]> git.lyx.org Git - lyx.git/blob - src/BufferList.cpp
7026cd8ea55c7a9beb177fe91183ce3bd69d18cf
[lyx.git] / src / BufferList.cpp
1 /**
2  * \file BufferList.cpp
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 "Session.h"
19 #include "LyX.h"
20 #include "output_latex.h"
21 #include "ParagraphList.h"
22
23 #include "frontends/alert.h"
24
25 #include "support/ExceptionMessage.h"
26 #include "support/debug.h"
27 #include "support/filetools.h"
28 #include "support/FileName.h"
29 #include "support/gettext.h"
30 #include "support/lstrings.h"
31 #include "support/Package.h"
32
33 #include "support/lassert.h"
34 #include <boost/bind.hpp>
35
36 #include <algorithm>
37 #include <functional>
38
39 using boost::bind;
40
41 using namespace std;
42 using namespace lyx::support;
43
44 namespace lyx {
45
46 namespace Alert = lyx::frontend::Alert;
47
48
49 BufferList::BufferList()
50 {}
51
52
53 bool BufferList::empty() const
54 {
55         return bstore.empty();
56 }
57
58
59 BufferList::iterator BufferList::begin()
60 {
61         return bstore.begin();
62 }
63
64
65 BufferList::const_iterator BufferList::begin() const
66 {
67         return bstore.begin();
68 }
69
70
71 BufferList::iterator BufferList::end()
72 {
73         return bstore.end();
74 }
75
76
77 BufferList::const_iterator BufferList::end() const
78 {
79         return bstore.end();
80 }
81
82
83 void BufferList::release(Buffer * buf)
84 {
85         LASSERT(buf, /**/);
86         BufferStorage::iterator const it =
87                 find(bstore.begin(), bstore.end(), buf);
88         if (it != bstore.end()) {
89                 Buffer * tmp = (*it);
90                 LASSERT(tmp, /**/);
91                 bstore.erase(it);
92                 delete tmp;
93         }
94 }
95
96
97 Buffer * BufferList::newBuffer(string const & s, bool const ronly)
98 {
99         auto_ptr<Buffer> tmpbuf;
100         try {
101                 tmpbuf.reset(new Buffer(s, ronly));
102         } catch (ExceptionMessage const & message) {
103                 if (message.type_ == ErrorException) {
104                         Alert::error(message.title_, message.details_);
105                         exit(1);
106                 } else if (message.type_ == WarningException) {
107                         Alert::warning(message.title_, message.details_);
108                         return 0;
109                 }
110         }
111         tmpbuf->params().useClassDefaults();
112         LYXERR(Debug::INFO, "Assigning to buffer " << bstore.size());
113         bstore.push_back(tmpbuf.get());
114         return tmpbuf.release();
115 }
116
117
118 void BufferList::closeAll()
119 {
120         while (!bstore.empty())
121                 release(bstore.front());
122 }
123
124
125 vector<string> const BufferList::getFileNames() const
126 {
127         vector<string> nvec;
128         transform(bstore.begin(), bstore.end(),
129                   back_inserter(nvec),
130                   boost::bind(&Buffer::absFileName, _1));
131         return nvec;
132 }
133
134
135 Buffer * BufferList::first()
136 {
137         if (bstore.empty())
138                 return 0;
139         return bstore.front();
140 }
141
142
143 Buffer * BufferList::last()
144 {
145         if (bstore.empty())
146                 return 0;
147         return bstore.back();
148 }
149
150
151 Buffer * BufferList::getBuffer(unsigned int choice)
152 {
153         if (choice >= bstore.size())
154                 return 0;
155         return bstore[choice];
156 }
157
158
159 Buffer * BufferList::next(Buffer const * buf) const
160 {
161         LASSERT(buf, /**/);
162
163         if (bstore.empty())
164                 return 0;
165         BufferStorage::const_iterator it = find(bstore.begin(),
166                                                 bstore.end(), buf);
167         LASSERT(it != bstore.end(), /**/);
168         ++it;
169         if (it == bstore.end())
170                 return bstore.front();
171         else
172                 return *it;
173 }
174
175
176 Buffer * BufferList::previous(Buffer const * buf) const
177 {
178         LASSERT(buf, /**/);
179
180         if (bstore.empty())
181                 return 0;
182         BufferStorage::const_iterator it = find(bstore.begin(),
183                                                 bstore.end(), buf);
184         LASSERT(it != bstore.end(), /**/);
185         if (it == bstore.begin())
186                 return bstore.back();
187         else
188                 return *(it - 1);
189 }
190
191
192 void BufferList::updateIncludedTeXfiles(string const & masterTmpDir,
193                                         OutputParams const & runparams)
194 {
195         BufferStorage::iterator it = bstore.begin();
196         BufferStorage::iterator end = bstore.end();
197         for (; it != end; ++it) {
198                 if (!(*it)->isDepClean(masterTmpDir)) {
199                         string writefile = addName(masterTmpDir, (*it)->latexName());
200                         (*it)->makeLaTeXFile(FileName(writefile), masterTmpDir,
201                                              runparams, false);
202                         (*it)->markDepClean(masterTmpDir);
203                 }
204         }
205 }
206
207
208 void BufferList::emergencyWriteAll()
209 {
210         for_each(bstore.begin(), bstore.end(),
211                  bind(&BufferList::emergencyWrite, this, _1));
212 }
213
214
215 docstring BufferList::emergencyWrite(Buffer * buf)
216 {
217         // Use ::assert to avoid a loop, BOOST_ASSERT ends up calling ::assert
218         // compare with 0 to avoid pointer/interger comparison
219         // ::assert(buf != 0);
220         if (!buf)
221                 return _("No file open!");
222
223         // No need to save if the buffer has not changed.
224         if (buf->isClean())
225                 return docstring();
226
227         string const doc = buf->isUnnamed()
228                 ? onlyFilename(buf->absFileName()) : buf->absFileName();
229
230         docstring user_message = bformat(
231                 _("LyX: Attempting to save document %1$s\n"), from_utf8(doc));
232
233         // We try to save three places:
234         // 1) Same place as document. Unless it is an unnamed doc.
235         if (!buf->isUnnamed()) {
236                 string s = buf->absFileName();
237                 s += ".emergency";
238                 lyxerr << "  " << s << endl;
239                 if (buf->writeFile(FileName(s))) {
240                         buf->markClean();
241                         user_message += _("  Save seems successful. Phew.\n");
242                         return user_message;
243                 } else {
244                         user_message += _("  Save failed! Trying...\n");
245                 }
246         }
247
248         // 2) In HOME directory.
249         string s = addName(package().home_dir().absFilename(), buf->absFileName());
250         s += ".emergency";
251         lyxerr << ' ' << s << endl;
252         if (buf->writeFile(FileName(s))) {
253                 buf->markClean();
254                 user_message += _("  Save seems successful. Phew.\n");
255                 return user_message;
256         }
257
258         user_message += _("  Save failed! Trying...\n");
259
260         // 3) In "/tmp" directory.
261         // MakeAbsPath to prepend the current
262         // drive letter on OS/2
263         s = addName(package().temp_dir().absFilename(), buf->absFileName());
264         s += ".emergency";
265         lyxerr << ' ' << s << endl;
266         if (buf->writeFile(FileName(s))) {
267                 buf->markClean();
268                 user_message += _("  Save seems successful. Phew.\n");
269                 return user_message;
270         }
271
272         user_message += _("  Save failed! Bummer. Document is lost.");
273         return user_message;
274 }
275
276
277 bool BufferList::exists(FileName const & fname) const
278 {
279         //FIXME: use Buffer::fileName()!
280         string const s = fname.absFilename();
281         return find_if(bstore.begin(), bstore.end(),
282                        bind(equal_to<string>(),
283                             bind(&Buffer::absFileName, _1),
284                             s))
285                 != bstore.end();
286 }
287
288
289 bool BufferList::isLoaded(Buffer const * b) const
290 {
291         LASSERT(b, /**/);
292         BufferStorage::const_iterator cit =
293                 find(bstore.begin(), bstore.end(), b);
294         return cit != bstore.end();
295 }
296
297
298 Buffer * BufferList::getBuffer(string const & s)
299 {
300         BufferStorage::iterator it =
301                 find_if(bstore.begin(), bstore.end(),
302                         bind(equal_to<string>(),
303                              bind(&Buffer::absFileName, _1),
304                              s));
305
306         return it != bstore.end() ? (*it) : 0;
307 }
308
309
310 Buffer * BufferList::getBufferFromTmp(string const & s)
311 {
312         BufferStorage::iterator it = bstore.begin();
313         BufferStorage::iterator end = bstore.end();
314         for (; it < end; ++it)
315                 if (prefixIs(s, (*it)->temppath()))
316                         return *it;
317         return 0;
318 }
319
320
321 void BufferList::setCurrentAuthor(docstring const & name, docstring const & email)
322 {
323         BufferStorage::iterator it = bstore.begin();
324         BufferStorage::iterator end = bstore.end();
325         for (; it != end; ++it)
326                 (*it)->params().authors().record(0, Author(name, email));
327 }
328
329
330 int BufferList::bufferNum(string const & name) const
331 {
332         vector<string> buffers = getFileNames();
333         vector<string>::const_iterator cit =
334                 find(buffers.begin(), buffers.end(), name);
335         if (cit == buffers.end())
336                 return 0;
337         return int(cit - buffers.begin());
338 }
339
340
341 bool BufferList::releaseChild(Buffer * parent, Buffer * child)
342 {
343         LASSERT(parent, return false);
344         LASSERT(child, return false);
345         LASSERT(parent->isChild(child), return false);
346
347         // Child document has a different parent, don't close it.
348         if (child->parent() != parent)
349                 return false;
350
351         BufferStorage::iterator it = bstore.begin();
352         BufferStorage::iterator end = bstore.end();
353         for (; it != end; ++it) {
354                 Buffer * buf = *it;
355                 if (buf != parent && buf->isChild(child)) {
356                         child->setParent(0);
357                         return false;
358                 }
359         }
360         release(child);
361         return true;
362 }
363
364
365 } // namespace lyx