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