]> git.lyx.org Git - lyx.git/blob - src/bufferlist.C
d0597d6b42fa1f3106325fec304d448fd52e06ad
[lyx.git] / src / bufferlist.C
1 /**
2  * \file bufferlist.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "bufferlist.h"
14
15 #include "author.h"
16 #include "buffer.h"
17 #include "bufferparams.h"
18 #include "debug.h"
19 #include "gettext.h"
20 #include "lastfiles.h"
21 #include "lyx_cb.h"
22 #include "lyx_main.h"
23 #include "paragraph.h"
24 #include "TextCache.h"
25
26 #include "frontends/Alert.h"
27
28 #include "support/filetools.h"
29 #include "support/LAssert.h"
30 #include "support/lyxfunctional.h"
31
32 #include <boost/bind.hpp>
33
34 using namespace lyx::support;
35
36 using std::endl;
37 using std::find;
38 using std::find_if;
39 using std::for_each;
40
41 using std::vector;
42
43
44 BufferList::BufferList()
45 {}
46
47
48 bool BufferList::empty() const
49 {
50         return bstore.empty();
51 }
52
53
54 bool BufferList::quitWriteBuffer(Buffer * buf)
55 {
56         string file;
57         if (buf->isUnnamed())
58                 file = OnlyFilename(buf->fileName());
59         else
60                 file = MakeDisplayPath(buf->fileName(), 30);
61
62         string text = bformat(_("The document %1$s has unsaved changes.\n\n"
63                 "Do you want to save the document or discard the changes?"), file);
64         int const ret = Alert::prompt(_("Save changed document?"),
65                 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
66
67         if (ret == 0) {
68                 // FIXME: WriteAs can be asynch !
69                 // but not right now...maybe we should remove that
70
71                 bool succeeded;
72
73                 if (buf->isUnnamed())
74                         succeeded = WriteAs(buf);
75                 else
76                         succeeded = MenuWrite(buf);
77
78                 if (!succeeded)
79                         return false;
80         } else if (ret == 1) {
81                 // if we crash after this we could
82                 // have no autosave file but I guess
83                 // this is really inprobable (Jug)
84                 if (buf->isUnnamed())
85                         removeAutosaveFile(buf->fileName());
86
87         } else {
88                 return false;
89         }
90
91         return true;
92 }
93
94
95 bool BufferList::quitWriteAll()
96 {
97         BufferStorage::iterator it = bstore.begin();
98         BufferStorage::iterator end = bstore.end();
99         for (; it != end; ++it) {
100                 if ((*it)->isClean())
101                         continue;
102
103                 if (!quitWriteBuffer(*it))
104                         return false;
105         }
106
107         return true;
108 }
109
110
111 void BufferList::release(Buffer * buf)
112 {
113         Assert(buf);
114         BufferStorage::iterator it = find(bstore.begin(), bstore.end(), buf);
115         if (it != bstore.end()) {
116                 // Make sure that we don't store a LyXText in
117                 // the textcache that points to the buffer
118                 // we just deleted.
119                 Buffer * tmp = (*it);
120                 bstore.erase(it);
121                 textcache.removeAllWithBuffer(tmp);
122                 delete tmp;
123         }
124 }
125
126
127 Buffer * BufferList::newBuffer(string const & s, bool ronly)
128 {
129         Buffer * tmpbuf = new Buffer(s, ronly);
130         tmpbuf->params().useClassDefaults();
131         lyxerr[Debug::INFO] << "Assigning to buffer "
132                             << bstore.size() << endl;
133         bstore.push_back(tmpbuf);
134         return tmpbuf;
135 }
136
137
138 void BufferList::closeAll()
139 {
140         // Since we are closing we can just as well delete all
141         // in the textcache this will also speed the closing/quiting up a bit.
142         textcache.clear();
143
144         while (!bstore.empty()) {
145                 close(bstore.front(), false);
146         }
147 }
148
149
150 bool BufferList::close(Buffer * buf, bool ask)
151 {
152         Assert(buf);
153
154         // FIXME: is the quitting check still necessary ?
155         if (!ask || buf->isClean() || quitting || buf->paragraphs().empty()) {
156                 release(buf);
157                 return true;
158         }
159
160         string fname;
161         if (buf->isUnnamed())
162                 fname = OnlyFilename(buf->fileName());
163         else
164                 fname = MakeDisplayPath(buf->fileName(), 30);
165
166         string text = bformat(_("The document %1$s has unsaved changes.\n\n"
167                 "Do you want to save the document or discard the changes?"), fname);
168         int const ret = Alert::prompt(_("Save changed document?"),
169                 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
170
171         if (ret == 0) {
172                 if (buf->isUnnamed()) {
173                         if (!WriteAs(buf))
174                                 return false;
175                 } else if (buf->save()) {
176                         lastfiles->newFile(buf->fileName());
177                 } else {
178                         return false;
179                 }
180         } else if (ret == 2) {
181                 return false;
182         }
183
184         if (buf->isUnnamed()) {
185                 removeAutosaveFile(buf->fileName());
186         }
187
188         release(buf);
189         return true;
190 }
191
192
193 vector<string> const BufferList::getFileNames() const
194 {
195         vector<string> nvec;
196         std::copy(bstore.begin(), bstore.end(),
197                   lyx::back_inserter_fun(nvec, &Buffer::fileName));
198         return nvec;
199 }
200
201
202 Buffer * BufferList::first()
203 {
204         if (bstore.empty())
205                 return 0;
206         return bstore.front();
207 }
208
209
210 Buffer * BufferList::getBuffer(unsigned int choice)
211 {
212         if (choice >= bstore.size())
213                 return 0;
214         return bstore[choice];
215 }
216
217
218 void BufferList::updateIncludedTeXfiles(string const & mastertmpdir,
219                                         LatexRunParams const & runparams)
220 {
221         BufferStorage::iterator it = bstore.begin();
222         BufferStorage::iterator end = bstore.end();
223         for (; it != end; ++it) {
224                 if (!(*it)->isDepClean(mastertmpdir)) {
225                         string writefile = mastertmpdir;
226                         writefile += '/';
227                         writefile += (*it)->getLatexName();
228                         (*it)->makeLaTeXFile(writefile, mastertmpdir,
229                                              runparams, false);
230                         (*it)->markDepClean(mastertmpdir);
231                 }
232         }
233 }
234
235
236 void BufferList::emergencyWriteAll()
237 {
238         for_each(bstore.begin(), bstore.end(),
239                  boost::bind(&BufferList::emergencyWrite, this, _1));
240 }
241
242
243 void BufferList::emergencyWrite(Buffer * buf)
244 {
245         // assert(buf) // this is not good since C assert takes an int
246                        // and a pointer is a long (JMarc)
247         assert(buf != 0); // use c assert to avoid a loop
248
249
250         // No need to save if the buffer has not changed.
251         if (buf->isClean())
252                 return;
253
254         string const doc = buf->isUnnamed()
255                 ? OnlyFilename(buf->fileName()) : buf->fileName();
256
257         lyxerr << bformat(_("LyX: Attempting to save document %1$s"), doc) << endl;
258
259         // We try to save three places:
260         // 1) Same place as document. Unless it is an unnamed doc.
261         if (!buf->isUnnamed()) {
262                 string s = buf->fileName();
263                 s += ".emergency";
264                 lyxerr << "  " << s << endl;
265                 if (buf->writeFile(s)) {
266                         buf->markClean();
267                         lyxerr << _("  Save seems successful. Phew.") << endl;
268                         return;
269                 } else {
270                         lyxerr << _("  Save failed! Trying...") << endl;
271                 }
272         }
273
274         // 2) In HOME directory.
275         string s = AddName(GetEnvPath("HOME"), buf->fileName());
276         s += ".emergency";
277         lyxerr << ' ' << s << endl;
278         if (buf->writeFile(s)) {
279                 buf->markClean();
280                 lyxerr << _("  Save seems successful. Phew.") << endl;
281                 return;
282         }
283
284         lyxerr << _("  Save failed! Trying...") << endl;
285
286         // 3) In "/tmp" directory.
287         // MakeAbsPath to prepend the current
288         // drive letter on OS/2
289         s = AddName(MakeAbsPath("/tmp/"), buf->fileName());
290         s += ".emergency";
291         lyxerr << ' ' << s << endl;
292         if (buf->writeFile(s)) {
293                 buf->markClean();
294                 lyxerr << _("  Save seems successful. Phew.") << endl;
295                 return;
296         }
297         lyxerr << _("  Save failed! Bummer. Document is lost.") << endl;
298 }
299
300
301 bool BufferList::exists(string const & s) const
302 {
303         return find_if(bstore.begin(), bstore.end(),
304                        lyx::compare_memfun(&Buffer::fileName, s))
305                 != bstore.end();
306 }
307
308
309 bool BufferList::isLoaded(Buffer const * b) const
310 {
311         Assert(b);
312         
313         BufferStorage::const_iterator cit =
314                 find(bstore.begin(), bstore.end(), b);
315         return cit != bstore.end();
316 }
317
318
319 Buffer * BufferList::getBuffer(string const & s)
320 {
321         BufferStorage::iterator it =
322                 find_if(bstore.begin(), bstore.end(),
323                         lyx::compare_memfun(&Buffer::fileName, s));
324         return it != bstore.end() ? (*it) : 0;
325 }
326
327
328 void BufferList::setCurrentAuthor(string const & name, string const & email)
329 {
330         BufferStorage::iterator it = bstore.begin();
331         BufferStorage::iterator end = bstore.end();
332         for (; it != end; ++it) {
333                 (*it)->params().authors().record(0, Author(name, email));
334         }
335 }