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