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