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"
36 using namespace lyx::support;
40 namespace Alert = lyx::frontend::Alert;
43 BufferList::BufferList()
47 BufferList::~BufferList()
49 for (Buffer * buf : binternal)
54 bool BufferList::empty() const
56 return bstore.empty();
60 BufferList::iterator BufferList::begin()
62 return bstore.begin();
66 BufferList::const_iterator BufferList::begin() const
68 return bstore.begin();
72 BufferList::iterator BufferList::end()
78 BufferList::const_iterator BufferList::end() const
84 void BufferList::release(Buffer * buf)
86 // We may leak here, but we probably do not need to
89 BufferStorage::iterator const it =
90 find(bstore.begin(), bstore.end(), buf);
91 if (it != bstore.end()) {
92 Buffer const * parent = buf->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();
105 Buffer * BufferList::newInternalBuffer(string const & s)
107 Buffer * const buf = createNewBuffer(s);
109 buf->setInternal(true);
110 binternal.push_back(buf);
116 Buffer * BufferList::newBuffer(string const & s)
118 Buffer * const buf = createNewBuffer(s);
120 LYXERR(Debug::INFO, "Assigning to buffer " << bstore.size());
121 bstore.push_back(buf);
127 Buffer * BufferList::createNewBuffer(string const & s)
129 unique_ptr<Buffer> tmpbuf;
131 tmpbuf = make_unique<Buffer>(s);
132 } catch (ExceptionMessage const & message) {
133 if (message.type_ == ErrorException) {
134 Alert::error(message.title_, message.details_);
136 } else if (message.type_ == WarningException) {
137 Alert::warning(message.title_, message.details_);
141 tmpbuf->params().useClassDefaults();
142 return tmpbuf.release();
146 void BufferList::closeAll()
148 while (!bstore.empty())
149 release(bstore.front());
153 FileNameList BufferList::fileNames() const
156 for (Buffer const * buf : bstore)
157 nvec.push_back(buf->fileName());
162 Buffer * BufferList::first()
166 return bstore.front();
170 Buffer * BufferList::last()
174 return bstore.back();
178 Buffer * BufferList::getBuffer(unsigned int choice)
180 if (choice >= bstore.size())
182 return bstore[choice];
186 Buffer * BufferList::next(Buffer const * buf) const
188 // Something is wrong, but we can probably survive it.
189 LASSERT(buf, return nullptr);
193 BufferStorage::const_iterator it =
194 find(bstore.begin(), bstore.end(), buf);
195 LASSERT(it != bstore.end(), return nullptr);
197 Buffer * nextbuf = (it == bstore.end()) ? bstore.front() : *it;
202 Buffer * BufferList::previous(Buffer const * buf) const
204 // Something is wrong, but we can probably survive it.
205 LASSERT(buf, return nullptr);
209 BufferStorage::const_iterator it =
210 find(bstore.begin(), bstore.end(), buf);
211 LASSERT(it != bstore.end(), return nullptr);
213 Buffer * previousbuf = (it == bstore.begin()) ? bstore.back() : *(it - 1);
218 void BufferList::updateIncludedTeXfiles(string const & masterTmpDir,
219 OutputParams const & runparams_in)
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);
234 void BufferList::emergencyWriteAll()
236 for (Buffer * buf : bstore)
237 buf->emergencyWrite();
241 void BufferList::invalidateConverterCache() const
243 for (Buffer const * buf : bstore)
244 buf->params().invalidateConverterCache();
248 bool BufferList::exists(FileName const & fname) const
250 return getBuffer(fname) != nullptr;
254 bool BufferList::isLoaded(Buffer const * b) const
258 BufferStorage::const_iterator cit =
259 find(bstore.begin(), bstore.end(), b);
260 return cit != bstore.end();
264 bool BufferList::isInternal(Buffer const * b) const
268 BufferStorage::const_iterator cit =
269 find(binternal.begin(), binternal.end(), b);
270 return cit != binternal.end();
274 bool BufferList::isOthersChild(Buffer * parent, Buffer * child) const
276 LASSERT(parent, return false);
277 LASSERT(child, return false);
278 LASSERT(parent->isChild(child), return false);
280 // Does child document have a different parent?
281 Buffer const * parent_ = child->parent();
282 if (parent_ && parent_ != parent)
285 for(Buffer const * buf : bstore)
286 if (buf != parent && buf->isChild(child))
292 Buffer * BufferList::getBuffer(support::FileName const & fname, bool internal) const
294 // 1) cheap test, using string comparison of file names
295 for (Buffer * b : bstore)
296 if (b->fileName() == fname)
298 // 2) possibly expensive test, using equivalence test of file names
299 for (Buffer * b : bstore)
300 if (equivalent(b->fileName(), fname))
303 // 1) cheap test, using string comparison of file names
304 for (Buffer * b : binternal)
305 if (b->fileName() == fname)
307 // 2) possibly expensive test, using equivalence test of file names
308 for (Buffer * b : binternal)
309 if (equivalent(b->fileName(), fname))
316 Buffer * BufferList::getBufferFromTmp(string const & path, bool realpath)
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))
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))
339 void BufferList::recordCurrentAuthor(Author const & author)
341 for (Buffer * buf : bstore)
342 buf->params().authors().recordCurrentAuthor(author);
346 void BufferList::updatePreviews()
348 for (Buffer * buf : bstore)
349 buf->updatePreviews();
353 int BufferList::bufferNum(FileName const & fname) const
355 FileNameList const buffers(fileNames());
356 FileNameList::const_iterator cit =
357 find(buffers.begin(), buffers.end(), fname);
358 if (cit == buffers.end())
360 return int(cit - buffers.begin());
364 void BufferList::changed(bool update_metrics) const
366 for (Buffer const * buf : bstore)
367 buf->changed(update_metrics);
368 for (Buffer const * buf : binternal)
369 buf->changed(update_metrics);