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