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