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