3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * Full author contact details are available in file CREDITS.
13 #include "BufferList.h"
17 #include "BufferParams.h"
18 #include "OutputParams.h"
20 #include "frontends/alert.h"
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"
29 #include "support/lassert.h"
32 #include <cstdlib> // exit()
37 using namespace lyx::support;
41 namespace Alert = lyx::frontend::Alert;
44 BufferList::BufferList()
48 BufferList::~BufferList()
50 for (Buffer * buf : binternal)
55 bool BufferList::empty() const
57 return bstore.empty();
61 BufferList::iterator BufferList::begin()
63 return bstore.begin();
67 BufferList::const_iterator BufferList::begin() const
69 return bstore.begin();
73 BufferList::iterator BufferList::end()
79 BufferList::const_iterator BufferList::end() const
85 void BufferList::release(Buffer * buf)
87 // We may leak here, but we probably do not need to
90 BufferStorage::iterator const it =
91 find(bstore.begin(), bstore.end(), buf);
92 if (it != bstore.end()) {
93 Buffer const * parent = buf->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();
106 Buffer * BufferList::newInternalBuffer(string const & s)
108 Buffer * const buf = createNewBuffer(s);
110 buf->setInternal(true);
111 binternal.push_back(buf);
117 Buffer * BufferList::newBuffer(string const & s)
119 Buffer * const buf = createNewBuffer(s);
121 LYXERR(Debug::INFO, "Assigning to buffer " << bstore.size());
122 bstore.push_back(buf);
128 Buffer * BufferList::createNewBuffer(string const & s)
130 unique_ptr<Buffer> tmpbuf;
132 tmpbuf = lyx::make_unique<Buffer>(s);
133 } catch (ExceptionMessage const & message) {
134 if (message.type_ == ErrorException) {
135 Alert::error(message.title_, message.details_);
137 } else if (message.type_ == WarningException) {
138 Alert::warning(message.title_, message.details_);
142 tmpbuf->params().useClassDefaults();
143 return tmpbuf.release();
147 void BufferList::closeAll()
149 while (!bstore.empty())
150 release(bstore.front());
154 FileNameList BufferList::fileNames() const
157 for (Buffer const * buf : bstore)
158 nvec.push_back(buf->fileName());
163 Buffer * BufferList::first()
167 return bstore.front();
171 Buffer * BufferList::last()
175 return bstore.back();
179 Buffer * BufferList::getBuffer(unsigned int choice)
181 if (choice >= bstore.size())
183 return bstore[choice];
187 Buffer * BufferList::next(Buffer const * buf) const
189 // Something is wrong, but we can probably survive it.
190 LASSERT(buf, return nullptr);
194 BufferStorage::const_iterator it =
195 find(bstore.begin(), bstore.end(), buf);
196 LASSERT(it != bstore.end(), return nullptr);
198 Buffer * nextbuf = (it == bstore.end()) ? bstore.front() : *it;
203 Buffer * BufferList::previous(Buffer const * buf) const
205 // Something is wrong, but we can probably survive it.
206 LASSERT(buf, return nullptr);
210 BufferStorage::const_iterator it =
211 find(bstore.begin(), bstore.end(), buf);
212 LASSERT(it != bstore.end(), return nullptr);
214 Buffer * previousbuf = (it == bstore.begin()) ? bstore.back() : *(it - 1);
219 void BufferList::updateIncludedTeXfiles(string const & masterTmpDir,
220 OutputParams const & runparams_in)
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);
235 void BufferList::emergencyWriteAll()
237 for (Buffer * buf : bstore)
238 buf->emergencyWrite();
242 void BufferList::invalidateConverterCache() const
244 for (Buffer const * buf : bstore)
245 buf->params().invalidateConverterCache();
249 bool BufferList::exists(FileName const & fname) const
251 return getBuffer(fname) != nullptr;
255 bool BufferList::isLoaded(Buffer const * b) const
259 BufferStorage::const_iterator cit =
260 find(bstore.begin(), bstore.end(), b);
261 return cit != bstore.end();
265 bool BufferList::isInternal(Buffer const * b) const
269 BufferStorage::const_iterator cit =
270 find(binternal.begin(), binternal.end(), b);
271 return cit != binternal.end();
275 bool BufferList::isOthersChild(Buffer * parent, Buffer * child) const
277 LASSERT(parent, return false);
278 LASSERT(child, return false);
279 LASSERT(parent->isChild(child), return false);
281 // Does child document have a different parent?
282 Buffer const * parent_ = child->parent();
283 if (parent_ && parent_ != parent)
286 for(Buffer const * buf : bstore)
287 if (buf != parent && buf->isChild(child))
293 Buffer * BufferList::getBuffer(support::FileName const & fname, bool internal) const
295 // 1) cheap test, using string comparison of file names
296 for (Buffer * b : bstore)
297 if (b->fileName() == fname)
299 // 2) possibly expensive test, using equivalence test of file names
300 for (Buffer * b : bstore)
301 if (equivalent(b->fileName(), fname))
304 // 1) cheap test, using string comparison of file names
305 for (Buffer * b : binternal)
306 if (b->fileName() == fname)
308 // 2) possibly expensive test, using equivalence test of file names
309 for (Buffer * b : binternal)
310 if (equivalent(b->fileName(), fname))
317 Buffer * BufferList::getBufferFromTmp(string const & path, bool realpath)
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))
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))
340 void BufferList::recordCurrentAuthor(Author const & author)
342 for (Buffer * buf : bstore)
343 buf->params().authors().recordCurrentAuthor(author);
347 void BufferList::updatePreviews()
349 for (Buffer * buf : bstore)
350 buf->updatePreviews();
354 int BufferList::bufferNum(FileName const & fname) const
356 FileNameList const buffers(fileNames());
357 FileNameList::const_iterator cit =
358 find(buffers.begin(), buffers.end(), fname);
359 if (cit == buffers.end())
361 return int(cit - buffers.begin());
365 void BufferList::changed(bool update_metrics) const
367 for (Buffer const * buf : bstore)
368 buf->changed(update_metrics);
369 for (Buffer const * buf : binternal)
370 buf->changed(update_metrics);