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