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