* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
- * \author Lars Gullik Bjønnes
+ * \author Lars Gullik Bjønnes
*
* Full author contact details are available in file CREDITS.
*/
#include "Author.h"
#include "Buffer.h"
#include "BufferParams.h"
-#include "debug.h"
-#include "gettext.h"
#include "Session.h"
#include "LyX.h"
#include "output_latex.h"
#include "frontends/alert.h"
+#include "support/ExceptionMessage.h"
+#include "support/debug.h"
+#include "support/FileName.h"
+#include "support/FileNameList.h"
#include "support/filetools.h"
+#include "support/gettext.h"
#include "support/lstrings.h"
#include "support/Package.h"
-#include <boost/bind.hpp>
+#include "support/lassert.h"
+#include "support/bind.h"
#include <algorithm>
#include <functional>
+#include <iterator>
+#include <memory>
-using boost::bind;
-
-using std::auto_ptr;
-using std::endl;
-using std::equal_to;
-using std::find;
-using std::find_if;
-using std::for_each;
-using std::string;
-using std::vector;
-using std::back_inserter;
-using std::transform;
-
+using namespace std;
+using namespace lyx::support;
namespace lyx {
-using support::addName;
-using support::bformat;
-using support::FileName;
-using support::makeDisplayPath;
-using support::onlyFilename;
-using support::removeAutosaveFile;
-using support::package;
-using support::prefixIs;
-
namespace Alert = lyx::frontend::Alert;
{}
+BufferList::~BufferList()
+{
+ BufferStorage::iterator it = binternal.begin();
+ BufferStorage::iterator end = binternal.end();
+ for (; it != end; ++it)
+ delete (*it);
+}
+
+
bool BufferList::empty() const
{
return bstore.empty();
}
-bool BufferList::quitWriteBuffer(Buffer * buf)
-{
- BOOST_ASSERT(buf);
-
- docstring file;
-
- // FIXME: Unicode?
- if (buf->isUnnamed())
- file = from_utf8(buf->fileName().onlyFileName());
- else
- file = buf->fileName().displayName(30);
-
- docstring const text =
- bformat(_("The document %1$s has unsaved changes.\n\n"
- "Do you want to save the document or discard the changes?"),
- file);
- int const ret = Alert::prompt(_("Save changed document?"),
- text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
-
- if (ret == 0) {
- // FIXME: WriteAs can be asynch !
- // but not right now...maybe we should remove that
-
- bool succeeded;
-
- if (buf->isUnnamed())
- succeeded = buf->writeAs();
- else
- succeeded = buf->menuWrite();
-
- if (!succeeded)
- return false;
- } else if (ret == 1) {
- // if we crash after this we could
- // have no autosave file but I guess
- // this is really inprobable (Jug)
- if (buf->isUnnamed())
- removeAutosaveFile(buf->absFileName());
-
- } else {
- return false;
- }
-
- return true;
-}
-
-
-bool BufferList::quitWriteAll()
-{
- BufferStorage::iterator it = bstore.begin();
- BufferStorage::iterator end = bstore.end();
- for (; it != end; ++it) {
- if ((*it)->isClean())
- continue;
-
- if (!quitWriteBuffer(*it))
- return false;
- }
- // now, all buffers have been written sucessfully
- // save file names to .lyx/session
- it = bstore.begin();
- for (; it != end; ++it) {
- // if master/slave are both open, do not save slave since it
- // will be automatically loaded when the master is loaded
- if ((*it)->masterBuffer() == (*it))
- LyX::ref().session().lastOpened().add(FileName((*it)->absFileName()));
- }
-
- return true;
-}
-
-
void BufferList::release(Buffer * buf)
{
- BOOST_ASSERT(buf);
+ // We may leak here, but we probably do not need to
+ // shut down.
+ LASSERT(buf, return);
BufferStorage::iterator const it =
find(bstore.begin(), bstore.end(), buf);
if (it != bstore.end()) {
Buffer * tmp = (*it);
- BOOST_ASSERT(tmp);
bstore.erase(it);
+ LASSERT(tmp, return);
delete tmp;
}
}
-Buffer * BufferList::newBuffer(string const & s, bool const ronly)
+Buffer * BufferList::newInternalBuffer(string const & s)
{
- auto_ptr<Buffer> tmpbuf(new Buffer(s, ronly));
- tmpbuf->params().useClassDefaults();
- LYXERR(Debug::INFO, "Assigning to buffer " << bstore.size());
- bstore.push_back(tmpbuf.get());
- return tmpbuf.release();
+ Buffer * const buf = createNewBuffer(s);
+ if (buf) {
+ buf->setInternal(true);
+ binternal.push_back(buf);
+ }
+ return buf;
}
-void BufferList::closeAll()
+Buffer * BufferList::newBuffer(string const & s)
{
- while (!bstore.empty()) {
- close(bstore.front(), false);
+ Buffer * const buf = createNewBuffer(s);
+ if (buf) {
+ LYXERR(Debug::INFO, "Assigning to buffer " << bstore.size());
+ bstore.push_back(buf);
}
+ return buf;
}
-bool BufferList::close(Buffer * buf, bool const ask)
+Buffer * BufferList::createNewBuffer(string const & s)
{
- BOOST_ASSERT(buf);
-
- if (!ask || buf->isClean() || buf->paragraphs().empty()) {
- release(buf);
- return true;
+ unique_ptr<Buffer> tmpbuf;
+ try {
+ tmpbuf = make_unique<Buffer>(s);
+ } catch (ExceptionMessage const & message) {
+ if (message.type_ == ErrorException) {
+ Alert::error(message.title_, message.details_);
+ exit(1);
+ } else if (message.type_ == WarningException) {
+ Alert::warning(message.title_, message.details_);
+ return 0;
+ }
}
+ tmpbuf->params().useClassDefaults();
+ return tmpbuf.release();
+}
- docstring fname;
- if (buf->isUnnamed())
- fname = from_utf8(onlyFilename(buf->absFileName()));
- else
- fname = makeDisplayPath(buf->absFileName(), 30);
-
- docstring const text =
- bformat(_("The document %1$s has unsaved changes.\n\n"
- "Do you want to save the document or discard the changes?"),
- fname);
- int const ret = Alert::prompt(_("Save changed document?"),
- text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
-
- if (ret == 0) {
- if (buf->isUnnamed()) {
- if (!buf->writeAs())
- return false;
- } else if (!buf->menuWrite())
- return false;
- } else if (ret == 2)
- return false;
-
- removeAutosaveFile(buf->absFileName());
- release(buf);
- return true;
+void BufferList::closeAll()
+{
+ while (!bstore.empty())
+ release(bstore.front());
}
-vector<string> const BufferList::getFileNames() const
+FileNameList BufferList::fileNames() const
{
- vector<string> nvec;
- transform(bstore.begin(), bstore.end(),
- back_inserter(nvec),
- boost::bind(&Buffer::absFileName, _1));
+ FileNameList nvec;
+ BufferStorage::const_iterator it = bstore.begin();
+ BufferStorage::const_iterator end = bstore.end();
+ for (; it != end; ++it) {
+ Buffer * buf = *it;
+ nvec.push_back(buf->fileName());
+ }
return nvec;
}
Buffer * BufferList::next(Buffer const * buf) const
{
- BOOST_ASSERT(buf);
+ // Something is wrong, but we can probably survive it.
+ LASSERT(buf, return 0);
if (bstore.empty())
return 0;
- BufferStorage::const_iterator it = find(bstore.begin(),
- bstore.end(), buf);
- BOOST_ASSERT(it != bstore.end());
+ BufferStorage::const_iterator it =
+ find(bstore.begin(), bstore.end(), buf);
+ LASSERT(it != bstore.end(), return 0);
++it;
- if (it == bstore.end())
- return bstore.front();
- else
- return *it;
+ Buffer * nextbuf = (it == bstore.end()) ? bstore.front() : *it;
+ return nextbuf;
}
Buffer * BufferList::previous(Buffer const * buf) const
{
- BOOST_ASSERT(buf);
+ // Something is wrong, but we can probably survive it.
+ LASSERT(buf, return 0);
if (bstore.empty())
return 0;
- BufferStorage::const_iterator it = find(bstore.begin(),
- bstore.end(), buf);
- BOOST_ASSERT(it != bstore.end());
- if (it == bstore.begin())
- return bstore.back();
- else
- return *(it - 1);
+ BufferStorage::const_iterator it =
+ find(bstore.begin(), bstore.end(), buf);
+ LASSERT(it != bstore.end(), return 0);
+
+ Buffer * previousbuf = (it == bstore.begin()) ? bstore.back() : *(it - 1);
+ return previousbuf;
}
void BufferList::updateIncludedTeXfiles(string const & masterTmpDir,
- OutputParams const & runparams)
+ OutputParams const & runparams_in)
{
+ OutputParams runparams = runparams_in;
+ runparams.is_child = true;
BufferStorage::iterator it = bstore.begin();
BufferStorage::iterator end = bstore.end();
for (; it != end; ++it) {
if (!(*it)->isDepClean(masterTmpDir)) {
string writefile = addName(masterTmpDir, (*it)->latexName());
(*it)->makeLaTeXFile(FileName(writefile), masterTmpDir,
- runparams, false);
+ runparams, Buffer::OnlyBody);
(*it)->markDepClean(masterTmpDir);
}
}
+ runparams.is_child = false;
}
void BufferList::emergencyWriteAll()
{
- for_each(bstore.begin(), bstore.end(),
- bind(&BufferList::emergencyWrite, this, _1));
+ BufferStorage::const_iterator it = bstore.begin();
+ BufferStorage::const_iterator const en = bstore.end();
+ for (; it != en; ++it)
+ (*it)->emergencyWrite();
}
-void BufferList::emergencyWrite(Buffer * buf)
+bool BufferList::exists(FileName const & fname) const
{
- // Use ::assert to avoid a loop, BOOST_ASSERT ends up calling ::assert
- // compare with 0 to avoid pointer/interger comparison
- // ::assert(buf != 0);
- if (!buf)
- return;
-
- // No need to save if the buffer has not changed.
- if (buf->isClean())
- return;
-
- string const doc = buf->isUnnamed()
- ? onlyFilename(buf->absFileName()) : buf->absFileName();
-
- lyxerr << to_utf8(
- bformat(_("LyX: Attempting to save document %1$s"), from_utf8(doc)))
- << endl;
-
- // We try to save three places:
- // 1) Same place as document. Unless it is an unnamed doc.
- if (!buf->isUnnamed()) {
- string s = buf->absFileName();
- s += ".emergency";
- lyxerr << " " << s << endl;
- if (buf->writeFile(FileName(s))) {
- buf->markClean();
- lyxerr << to_utf8(_(" Save seems successful. Phew.")) << endl;
- return;
- } else {
- lyxerr << to_utf8(_(" Save failed! Trying...")) << endl;
- }
- }
+ return getBuffer(fname) != 0;
+}
- // 2) In HOME directory.
- string s = addName(package().home_dir().absFilename(), buf->absFileName());
- s += ".emergency";
- lyxerr << ' ' << s << endl;
- if (buf->writeFile(FileName(s))) {
- buf->markClean();
- lyxerr << to_utf8(_(" Save seems successful. Phew.")) << endl;
- return;
- }
- lyxerr << to_utf8(_(" Save failed! Trying...")) << endl;
-
- // 3) In "/tmp" directory.
- // MakeAbsPath to prepend the current
- // drive letter on OS/2
- s = addName(package().temp_dir().absFilename(), buf->absFileName());
- s += ".emergency";
- lyxerr << ' ' << s << endl;
- if (buf->writeFile(FileName(s))) {
- buf->markClean();
- lyxerr << to_utf8(_(" Save seems successful. Phew.")) << endl;
- return;
- }
- lyxerr << to_utf8(_(" Save failed! Bummer. Document is lost.")) << endl;
+ bool BufferList::isLoaded(Buffer const * b) const
+{
+ if (!b)
+ return false;
+ BufferStorage::const_iterator cit =
+ find(bstore.begin(), bstore.end(), b);
+ return cit != bstore.end();
}
-bool BufferList::exists(string const & s) const
+bool BufferList::isOthersChild(Buffer * parent, Buffer * child)
{
- return find_if(bstore.begin(), bstore.end(),
- bind(equal_to<string>(),
- bind(&Buffer::absFileName, _1),
- s))
- != bstore.end();
+ LASSERT(parent, return false);
+ LASSERT(child, return false);
+ LASSERT(parent->isChild(child), return false);
+
+ // Does child document have a different parent?
+ Buffer const * parent_ = child->parent();
+ if (parent_ && parent_ != parent)
+ return true;
+
+ BufferStorage::iterator it = bstore.begin();
+ BufferStorage::iterator end = bstore.end();
+ for (; it != end; ++it) {
+ Buffer * buf = *it;
+ if (buf != parent && buf->isChild(child))
+ return true;
+ }
+ return false;
}
-bool BufferList::isLoaded(Buffer const * b) const
+namespace {
+
+struct equivalent_to : public binary_function<FileName, FileName, bool>
{
- BOOST_ASSERT(b);
- BufferStorage::const_iterator cit =
- find(bstore.begin(), bstore.end(), b);
- return cit != bstore.end();
+ bool operator()(FileName const & x, FileName const & y) const
+ { return equivalent(x, y); }
+};
+
}
-Buffer * BufferList::getBuffer(string const & s)
+Buffer * BufferList::getBuffer(support::FileName const & fname, bool internal) const
{
- BufferStorage::iterator it =
- find_if(bstore.begin(), bstore.end(),
- bind(equal_to<string>(),
- bind(&Buffer::absFileName, _1),
- s));
+ // 1) cheap test, using string comparison of file names
+ BufferStorage::const_iterator it = find_if(bstore.begin(), bstore.end(),
+ lyx::bind(equal_to<FileName>(), lyx::bind(&Buffer::fileName, _1), fname));
+ if (it != bstore.end())
+ return *it;
+ // 2) possibly expensive test, using equivalence test of file names
+ it = find_if(bstore.begin(), bstore.end(),
+ lyx::bind(equivalent_to(), lyx::bind(&Buffer::fileName, _1), fname));
+ if (it != bstore.end())
+ return *it;
- return it != bstore.end() ? (*it) : 0;
+ if (internal) {
+ // 1) cheap test, using string comparison of file names
+ BufferStorage::const_iterator it = find_if(binternal.begin(), binternal.end(),
+ lyx::bind(equal_to<FileName>(), lyx::bind(&Buffer::fileName, _1), fname));
+ if (it != binternal.end())
+ return *it;
+ // 2) possibly expensive test, using equivalence test of file names
+ it = find_if(binternal.begin(), binternal.end(),
+ lyx::bind(equivalent_to(), lyx::bind(&Buffer::fileName, _1), fname));
+ if (it != binternal.end())
+ return *it;
+ }
+
+ return 0;
}
{
BufferStorage::iterator it = bstore.begin();
BufferStorage::iterator end = bstore.end();
- for (; it < end; ++it)
- if (prefixIs(s, (*it)->temppath()))
- return *it;
+ for (; it < end; ++it) {
+ if (prefixIs(s, (*it)->temppath())) {
+ // check whether the filename matches the master
+ string const master_name = (*it)->latexName();
+ if (suffixIs(s, master_name))
+ return *it;
+ // if not, try with the children
+ ListOfBuffers clist = (*it)->getDescendents();
+ ListOfBuffers::const_iterator cit = clist.begin();
+ ListOfBuffers::const_iterator cend = clist.end();
+ for (; cit != cend; ++cit) {
+ string const mangled_child_name = DocFileName(
+ changeExtension((*cit)->absFileName(),
+ ".tex")).mangledFileName();
+ if (suffixIs(s, mangled_child_name))
+ return *cit;
+ }
+ }
+ }
return 0;
}
-void BufferList::setCurrentAuthor(docstring const & name, docstring const & email)
+void BufferList::recordCurrentAuthor(Author const & author)
{
BufferStorage::iterator it = bstore.begin();
BufferStorage::iterator end = bstore.end();
for (; it != end; ++it)
- (*it)->params().authors().record(0, Author(name, email));
+ (*it)->params().authors().recordCurrentAuthor(author);
}
-int BufferList::bufferNum(std::string const & name) const
+void BufferList::updatePreviews()
{
- vector<string> buffers = getFileNames();
- vector<string>::const_iterator cit =
- std::find(buffers.begin(), buffers.end(), name);
+ BufferStorage::iterator it = bstore.begin();
+ BufferStorage::iterator end = bstore.end();
+ for (; it != end; ++it)
+ (*it)->updatePreviews();
+}
+
+
+int BufferList::bufferNum(FileName const & fname) const
+{
+ FileNameList const buffers(fileNames());
+ FileNameList::const_iterator cit =
+ find(buffers.begin(), buffers.end(), fname);
if (cit == buffers.end())
return 0;
return int(cit - buffers.begin());
}
+void BufferList::changed(bool update_metrics) const
+{
+ BufferStorage::const_iterator it = bstore.begin();
+ BufferStorage::const_iterator end = bstore.end();
+ for (; it != end; ++it)
+ (*it)->changed(update_metrics);
+ it = binternal.begin();
+ end = binternal.end();
+ for (; it != end; ++it)
+ (*it)->changed(update_metrics);
+}
+
+
} // namespace lyx