]> git.lyx.org Git - lyx.git/blob - src/bufferlist.C
convert author names and status messages to docstring
[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 "session.h"
21 #include "lyx_cb.h"
22 #include "lyx_main.h"
23 #include "output_latex.h"
24 #include "paragraph.h"
25 #include "ParagraphList.h"
26
27 #include "frontends/Alert.h"
28
29 #include "support/filetools.h"
30 #include "support/package.h"
31
32 #include <boost/bind.hpp>
33
34 #include <algorithm>
35 #include <functional>
36
37
38 namespace lyx {
39
40 using support::addName;
41 using support::bformat;
42 using support::FileName;
43 using support::makeAbsPath;
44 using support::makeDisplayPath;
45 using support::onlyFilename;
46 using support::removeAutosaveFile;
47 using support::package;
48 using support::prefixIs;
49
50 using boost::bind;
51
52 using std::auto_ptr;
53 using std::endl;
54 using std::equal_to;
55 using std::find;
56 using std::find_if;
57 using std::for_each;
58 using std::string;
59 using std::vector;
60 using std::back_inserter;
61 using std::transform;
62
63 namespace Alert = lyx::frontend::Alert;
64
65
66 BufferList::BufferList()
67 {}
68
69
70 bool BufferList::empty() const
71 {
72         return bstore.empty();
73 }
74
75
76 BufferList::iterator BufferList::begin()
77 {
78         return bstore.begin();
79 }
80
81
82 BufferList::const_iterator BufferList::begin() const
83 {
84         return bstore.begin();
85 }
86
87
88 BufferList::iterator BufferList::end()
89 {
90         return bstore.end();
91 }
92
93
94 BufferList::const_iterator BufferList::end() const
95 {
96         return bstore.end();
97 }
98
99
100 bool BufferList::quitWriteBuffer(Buffer * buf)
101 {
102         BOOST_ASSERT(buf);
103
104         docstring file;
105         if (buf->isUnnamed())
106                 file = from_utf8(onlyFilename(buf->fileName()));
107         else
108                 file = makeDisplayPath(buf->fileName(), 30);
109
110         docstring const text =
111                 bformat(_("The document %1$s has unsaved changes.\n\n"
112                                        "Do you want to save the document or discard the changes?"),
113                                            file);
114         int const ret = Alert::prompt(_("Save changed document?"),
115                 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
116
117         if (ret == 0) {
118                 // FIXME: WriteAs can be asynch !
119                 // but not right now...maybe we should remove that
120
121                 bool succeeded;
122
123                 if (buf->isUnnamed())
124                         succeeded = writeAs(buf);
125                 else
126                         succeeded = menuWrite(buf);
127
128                 if (!succeeded)
129                         return false;
130         } else if (ret == 1) {
131                 // if we crash after this we could
132                 // have no autosave file but I guess
133                 // this is really inprobable (Jug)
134                 if (buf->isUnnamed())
135                         removeAutosaveFile(buf->fileName());
136
137         } else {
138                 return false;
139         }
140
141         return true;
142 }
143
144
145 bool BufferList::quitWriteAll()
146 {
147         BufferStorage::iterator it = bstore.begin();
148         BufferStorage::iterator end = bstore.end();
149         for (; it != end; ++it) {
150                 if ((*it)->isClean())
151                         continue;
152
153                 if (!quitWriteBuffer(*it))
154                         return false;
155         }
156         // now, all buffers have been written sucessfully
157         // save file names to .lyx/session
158         it = bstore.begin();
159         for (; it != end; ++it) {
160                 // if master/slave are both open, do not save slave since it
161                 // will be automatically loaded when the master is loaded
162                 if ((*it)->getMasterBuffer() == (*it))
163                         LyX::ref().session().lastOpened().add(FileName((*it)->fileName()));
164         }
165
166         return true;
167 }
168
169
170 void BufferList::release(Buffer * buf)
171 {
172         BOOST_ASSERT(buf);
173         BufferStorage::iterator const it =
174                 find(bstore.begin(), bstore.end(), buf);
175         if (it != bstore.end()) {
176                 Buffer * tmp = (*it);
177                 BOOST_ASSERT(tmp);
178                 bstore.erase(it);
179                 delete tmp;
180         }
181 }
182
183
184 Buffer * BufferList::newBuffer(string const & s, bool const ronly)
185 {
186         auto_ptr<Buffer> tmpbuf(new Buffer(s, ronly));
187         tmpbuf->params().useClassDefaults();
188         lyxerr[Debug::INFO] << "Assigning to buffer "
189                             << bstore.size() << endl;
190         bstore.push_back(tmpbuf.get());
191         return tmpbuf.release();
192 }
193
194
195 void BufferList::closeAll()
196 {
197         while (!bstore.empty()) {
198                 close(bstore.front(), false);
199         }
200 }
201
202
203 bool BufferList::close(Buffer * buf, bool const ask)
204 {
205         BOOST_ASSERT(buf);
206
207         if (!ask || buf->isClean() || buf->paragraphs().empty()) {
208                 release(buf);
209                 return true;
210         }
211
212         docstring fname;
213         if (buf->isUnnamed())
214                 fname = from_utf8(onlyFilename(buf->fileName()));
215         else
216                 fname = makeDisplayPath(buf->fileName(), 30);
217
218         docstring const text =
219                 bformat(_("The document %1$s has unsaved changes.\n\n"
220                                        "Do you want to save the document or discard the changes?"),
221                                            fname);
222         int const ret = Alert::prompt(_("Save changed document?"),
223                 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
224
225         if (ret == 0) {
226                 if (buf->isUnnamed()) {
227                         if (!writeAs(buf))
228                                 return false;
229                 } else if (!menuWrite(buf))
230                         return false;
231                 else
232                         return false;
233         } else if (ret == 2)
234                 return false;
235
236         if (buf->isUnnamed()) {
237                 removeAutosaveFile(buf->fileName());
238         }
239
240         release(buf);
241         return true;
242 }
243
244
245 vector<string> const BufferList::getFileNames() const
246 {
247         vector<string> nvec;
248         transform(bstore.begin(), bstore.end(),
249                   back_inserter(nvec),
250                   boost::bind(&Buffer::fileName, _1));
251         return nvec;
252 }
253
254
255 Buffer * BufferList::first()
256 {
257         if (bstore.empty())
258                 return 0;
259         return bstore.front();
260 }
261
262
263 Buffer * BufferList::last()
264 {
265         if (bstore.empty())
266                 return 0;
267         return bstore.back();
268 }
269
270
271 Buffer * BufferList::getBuffer(unsigned int const choice)
272 {
273         if (choice >= bstore.size())
274                 return 0;
275         return bstore[choice];
276 }
277
278
279 Buffer * BufferList::next(Buffer const * buf) const
280 {
281         BOOST_ASSERT(buf);
282
283         if (bstore.empty())
284                 return 0;
285         BufferStorage::const_iterator it = find(bstore.begin(),
286                                                 bstore.end(), buf);
287         BOOST_ASSERT(it != bstore.end());
288         ++it;
289         if (it == bstore.end())
290                 return bstore.front();
291         else
292                 return *it;
293 }
294
295
296 Buffer * BufferList::previous(Buffer const * buf) const
297 {
298         BOOST_ASSERT(buf);
299
300         if (bstore.empty())
301                 return 0;
302         BufferStorage::const_iterator it = find(bstore.begin(),
303                                                 bstore.end(), buf);
304         BOOST_ASSERT(it != bstore.end());
305         if (it == bstore.begin())
306                 return bstore.back();
307         else
308                 return *(it - 1);
309 }
310
311
312 void BufferList::updateIncludedTeXfiles(string const & mastertmpdir,
313                                         OutputParams const & runparams)
314 {
315         BufferStorage::iterator it = bstore.begin();
316         BufferStorage::iterator end = bstore.end();
317         for (; it != end; ++it) {
318                 if (!(*it)->isDepClean(mastertmpdir)) {
319                         string writefile = mastertmpdir;
320                         writefile += '/';
321                         writefile += (*it)->getLatexName();
322                         (*it)->makeLaTeXFile(FileName(writefile), mastertmpdir,
323                                              runparams, false);
324                         (*it)->markDepClean(mastertmpdir);
325                 }
326         }
327 }
328
329
330 void BufferList::emergencyWriteAll()
331 {
332         for_each(bstore.begin(), bstore.end(),
333                  bind(&BufferList::emergencyWrite, this, _1));
334 }
335
336
337 void BufferList::emergencyWrite(Buffer * buf)
338 {
339         // Use ::assert to avoid a loop, BOOST_ASSERT ends up calling ::assert
340         // compare with 0 to avoid pointer/interger comparison
341         assert(buf != 0);
342
343         // No need to save if the buffer has not changed.
344         if (buf->isClean())
345                 return;
346
347         string const doc = buf->isUnnamed()
348                 ? onlyFilename(buf->fileName()) : buf->fileName();
349
350         lyxerr << to_utf8(
351                 bformat(_("LyX: Attempting to save document %1$s"), from_utf8(doc)))
352                 << endl;
353
354         // We try to save three places:
355         // 1) Same place as document. Unless it is an unnamed doc.
356         if (!buf->isUnnamed()) {
357                 string s = buf->fileName();
358                 s += ".emergency";
359                 lyxerr << "  " << s << endl;
360                 if (buf->writeFile(FileName(s))) {
361                         buf->markClean();
362                         lyxerr << to_utf8(_("  Save seems successful. Phew.")) << endl;
363                         return;
364                 } else {
365                         lyxerr << to_utf8(_("  Save failed! Trying...")) << endl;
366                 }
367         }
368
369         // 2) In HOME directory.
370         string s = addName(package().home_dir(), buf->fileName());
371         s += ".emergency";
372         lyxerr << ' ' << s << endl;
373         if (buf->writeFile(FileName(s))) {
374                 buf->markClean();
375                 lyxerr << to_utf8(_("  Save seems successful. Phew.")) << endl;
376                 return;
377         }
378
379         lyxerr << to_utf8(_("  Save failed! Trying...")) << endl;
380
381         // 3) In "/tmp" directory.
382         // MakeAbsPath to prepend the current
383         // drive letter on OS/2
384         s = addName(package().temp_dir(), buf->fileName());
385         s += ".emergency";
386         lyxerr << ' ' << s << endl;
387         if (buf->writeFile(FileName(s))) {
388                 buf->markClean();
389                 lyxerr << to_utf8(_("  Save seems successful. Phew.")) << endl;
390                 return;
391         }
392         lyxerr << to_utf8(_("  Save failed! Bummer. Document is lost.")) << endl;
393 }
394
395
396 bool BufferList::exists(string const & s) const
397 {
398         return find_if(bstore.begin(), bstore.end(),
399                        bind(equal_to<string>(),
400                             bind(&Buffer::fileName, _1),
401                             s))
402                 != bstore.end();
403 }
404
405
406 bool BufferList::isLoaded(Buffer const * b) const
407 {
408         BOOST_ASSERT(b);
409         BufferStorage::const_iterator cit =
410                 find(bstore.begin(), bstore.end(), b);
411         return cit != bstore.end();
412 }
413
414
415 Buffer * BufferList::getBuffer(string const & s)
416 {
417         BufferStorage::iterator it =
418                 find_if(bstore.begin(), bstore.end(),
419                         bind(equal_to<string>(),
420                              bind(&Buffer::fileName, _1),
421                              s));
422
423         return it != bstore.end() ? (*it) : 0;
424 }
425
426
427 Buffer * BufferList::getBufferFromTmp(string const & s)
428 {
429         BufferStorage::iterator it = bstore.begin();
430         BufferStorage::iterator end = bstore.end();
431         for (; it < end; ++it)
432                 if (prefixIs(s, (*it)->temppath()))
433                         return *it;
434         return 0;
435 }
436
437
438 void BufferList::setCurrentAuthor(docstring const & name, docstring const & email)
439 {
440         BufferStorage::iterator it = bstore.begin();
441         BufferStorage::iterator end = bstore.end();
442         for (; it != end; ++it) {
443                 (*it)->params().authors().record(0, Author(name, email));
444         }
445 }
446
447
448 } // namespace lyx