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