]> git.lyx.org Git - lyx.git/blob - src/BufferList.cpp
Hide custom_language_package if custom is not selected
[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/FileName.h"
28 #include "support/FileNameList.h"
29 #include "support/filetools.h"
30 #include "support/gettext.h"
31 #include "support/lstrings.h"
32 #include "support/Package.h"
33
34 #include "support/lassert.h"
35
36 #include <algorithm>
37 #include <iterator>
38 #include <memory>
39
40 using namespace std;
41 using namespace lyx::support;
42
43 namespace lyx {
44
45 namespace Alert = lyx::frontend::Alert;
46
47
48 BufferList::BufferList()
49 {}
50
51
52 BufferList::~BufferList()
53 {
54         for (Buffer * buf : binternal)
55                 delete buf;
56 }
57
58
59 bool BufferList::empty() const
60 {
61         return bstore.empty();
62 }
63
64
65 BufferList::iterator BufferList::begin()
66 {
67         return bstore.begin();
68 }
69
70
71 BufferList::const_iterator BufferList::begin() const
72 {
73         return bstore.begin();
74 }
75
76
77 BufferList::iterator BufferList::end()
78 {
79         return bstore.end();
80 }
81
82
83 BufferList::const_iterator BufferList::end() const
84 {
85         return bstore.end();
86 }
87
88
89 void BufferList::release(Buffer * buf)
90 {
91         // We may leak here, but we probably do not need to
92         // shut down.
93         LASSERT(buf, return);
94         BufferStorage::iterator const it =
95                 find(bstore.begin(), bstore.end(), buf);
96         if (it != bstore.end()) {
97                 Buffer const * parent = buf->parent();
98                 Buffer * tmp = (*it);
99                 bstore.erase(it);
100                 LASSERT(tmp, return);
101                 delete tmp;
102                 if (parent)
103                         // If this was a child, update the parent's buffer
104                         // to avoid crashes due to dangling pointers (bug 9979)
105                         parent->updateBuffer();
106         }
107 }
108
109
110 Buffer * BufferList::newInternalBuffer(string const & s)
111 {
112         Buffer * const buf = createNewBuffer(s);
113         if (buf) {
114                 buf->setInternal(true);
115                 binternal.push_back(buf);
116         }
117         return buf;
118 }
119
120
121 Buffer * BufferList::newBuffer(string const & s)
122 {
123         Buffer * const buf = createNewBuffer(s);
124         if (buf) {
125                 LYXERR(Debug::INFO, "Assigning to buffer " << bstore.size());
126                 bstore.push_back(buf);
127         }
128         return buf;
129 }
130
131
132 Buffer * BufferList::createNewBuffer(string const & s)
133 {
134         unique_ptr<Buffer> tmpbuf;
135         try {
136                 tmpbuf = make_unique<Buffer>(s);
137         } catch (ExceptionMessage const & message) {
138                 if (message.type_ == ErrorException) {
139                         Alert::error(message.title_, message.details_);
140                         exit(1);
141                 } else if (message.type_ == WarningException) {
142                         Alert::warning(message.title_, message.details_);
143                         return 0;
144                 }
145         }
146         tmpbuf->params().useClassDefaults();
147         return tmpbuf.release();
148 }
149
150
151 void BufferList::closeAll()
152 {
153         while (!bstore.empty())
154                 release(bstore.front());
155 }
156
157
158 FileNameList BufferList::fileNames() const
159 {
160         FileNameList nvec;
161         for (Buffer const * buf : bstore)
162                 nvec.push_back(buf->fileName());
163         return nvec;
164 }
165
166
167 Buffer * BufferList::first()
168 {
169         if (bstore.empty())
170                 return 0;
171         return bstore.front();
172 }
173
174
175 Buffer * BufferList::last()
176 {
177         if (bstore.empty())
178                 return 0;
179         return bstore.back();
180 }
181
182
183 Buffer * BufferList::getBuffer(unsigned int choice)
184 {
185         if (choice >= bstore.size())
186                 return 0;
187         return bstore[choice];
188 }
189
190
191 Buffer * BufferList::next(Buffer const * buf) const
192 {
193         // Something is wrong, but we can probably survive it.
194         LASSERT(buf, return 0);
195
196         if (bstore.empty())
197                 return 0;
198         BufferStorage::const_iterator it =
199                         find(bstore.begin(), bstore.end(), buf);
200         LASSERT(it != bstore.end(), return 0);
201         ++it;
202         Buffer * nextbuf = (it == bstore.end()) ? bstore.front() : *it;
203         return nextbuf;
204 }
205
206
207 Buffer * BufferList::previous(Buffer const * buf) const
208 {
209         // Something is wrong, but we can probably survive it.
210         LASSERT(buf, return 0);
211
212         if (bstore.empty())
213                 return 0;
214         BufferStorage::const_iterator it =
215                         find(bstore.begin(), bstore.end(), buf);
216         LASSERT(it != bstore.end(), return 0);
217
218         Buffer * previousbuf = (it == bstore.begin()) ? bstore.back() : *(it - 1);
219         return previousbuf;
220 }
221
222
223 void BufferList::updateIncludedTeXfiles(string const & masterTmpDir,
224                                         OutputParams const & runparams_in)
225 {
226         OutputParams runparams = runparams_in;
227         runparams.is_child = true;
228         for (Buffer * buf : bstore) {
229                 if (!buf->isDepClean(masterTmpDir)) {
230                         string writefile = addName(masterTmpDir, buf->latexName());
231                         buf->makeLaTeXFile(FileName(writefile), masterTmpDir,
232                                              runparams, Buffer::OnlyBody);
233                         buf->markDepClean(masterTmpDir);
234                 }
235         }
236 }
237
238
239 void BufferList::emergencyWriteAll()
240 {
241         for (Buffer * buf : bstore)
242                  buf->emergencyWrite();
243 }
244
245
246 void BufferList::invalidateConverterCache() const
247 {
248         for (Buffer const * buf : bstore)
249                 buf->params().invalidateConverterCache();
250 }
251
252
253 bool BufferList::exists(FileName const & fname) const
254 {
255         return getBuffer(fname) != 0;
256 }
257
258
259 bool BufferList::isLoaded(Buffer const * b) const
260 {
261         if (!b)
262                 return false;
263         BufferStorage::const_iterator cit =
264                 find(bstore.begin(), bstore.end(), b);
265         return cit != bstore.end();
266 }
267
268
269 bool BufferList::isInternal(Buffer const * b) const
270 {
271         if (!b)
272                 return false;
273         BufferStorage::const_iterator cit =
274                 find(binternal.begin(), binternal.end(), b);
275         return cit != binternal.end();
276 }
277
278
279 bool BufferList::isOthersChild(Buffer * parent, Buffer * child) const
280 {
281         LASSERT(parent, return false);
282         LASSERT(child, return false);
283         LASSERT(parent->isChild(child), return false);
284
285         // Does child document have a different parent?
286         Buffer const * parent_ = child->parent();
287         if (parent_ && parent_ != parent)
288                 return true;
289
290         for(Buffer const * buf : bstore)
291                 if (buf != parent && buf->isChild(child))
292                         return true;
293         return false;
294 }
295
296
297 Buffer * BufferList::getBuffer(support::FileName const & fname, bool internal) const
298 {
299         // 1) cheap test, using string comparison of file names
300         for (Buffer * b : bstore)
301                 if (b->fileName() == fname)
302                         return b;
303         // 2) possibly expensive test, using equivalence test of file names
304         for (Buffer * b : bstore)
305                 if (equivalent(b->fileName(), fname))
306                         return b;
307         if (internal) {
308                 // 1) cheap test, using string comparison of file names
309                 for (Buffer * b : binternal)
310                         if (b->fileName() == fname)
311                                 return b;
312                 // 2) possibly expensive test, using equivalence test of file names
313                 for (Buffer * b : binternal)
314                         if (equivalent(b->fileName(), fname))
315                                 return b;
316         }
317         return 0;
318 }
319
320
321 Buffer * BufferList::getBufferFromTmp(string const & s)
322 {
323         for (Buffer * buf : bstore) {
324                 if (prefixIs(s, buf->temppath())) {
325                         // check whether the filename matches the master
326                         string const master_name = buf->latexName();
327                         if (suffixIs(s, master_name))
328                                 return buf;
329                         // if not, try with the children
330                         for (Buffer * child : buf->getDescendents()) {
331                                 string const mangled_child_name = DocFileName(
332                                         changeExtension(child->absFileName(),
333                                                 ".tex")).mangledFileName();
334                                 if (suffixIs(s, mangled_child_name))
335                                         return child;
336                         }
337                 }
338         }
339         return 0;
340 }
341
342
343 void BufferList::recordCurrentAuthor(Author const & author)
344 {
345         for (Buffer * buf : bstore)
346                 buf->params().authors().recordCurrentAuthor(author);
347 }
348
349
350 void BufferList::updatePreviews()
351 {
352         for (Buffer * buf : bstore)
353                 buf->updatePreviews();
354 }
355
356
357 int BufferList::bufferNum(FileName const & fname) const
358 {
359         FileNameList const buffers(fileNames());
360         FileNameList::const_iterator cit =
361                 find(buffers.begin(), buffers.end(), fname);
362         if (cit == buffers.end())
363                 return 0;
364         return int(cit - buffers.begin());
365 }
366
367
368 void BufferList::changed(bool update_metrics) const
369 {
370         for (Buffer const * buf : bstore)
371                 buf->changed(update_metrics);
372         for (Buffer const * buf : binternal)
373                 buf->changed(update_metrics);
374 }
375
376
377 } // namespace lyx