X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=d68ef97c7a48c9eccce5515598ecdc983665eb51;hb=0011f47885e070cf36e92d3a2f11f29ce1d4fdf4;hp=44572501ea0b866aab72082101c52ef9bf0f5d39;hpb=9a7cd29f5ba8fdf17441dd5d87203fa8a181b556;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 44572501ea..d68ef97c7a 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -14,6 +14,7 @@ #include "Buffer.h" #include "Author.h" +#include "LayoutFile.h" #include "BiblioInfo.h" #include "BranchList.h" #include "buffer_funcs.h" @@ -50,16 +51,16 @@ #include "ParagraphParameters.h" #include "ParIterator.h" #include "PDFOptions.h" -#include "Session.h" #include "sgml.h" #include "TexRow.h" #include "TexStream.h" -#include "TextClassList.h" #include "Text.h" +#include "TextClass.h" #include "TocBackend.h" #include "Undo.h" #include "VCBackend.h" #include "version.h" +#include "WordList.h" #include "insets/InsetBibitem.h" #include "insets/InsetBibtex.h" @@ -79,7 +80,6 @@ #include "support/convert.h" #include "support/debug.h" #include "support/ExceptionMessage.h" -#include "support/FileFilterList.h" #include "support/FileName.h" #include "support/FileNameList.h" #include "support/filetools.h" @@ -95,18 +95,16 @@ #include "support/types.h" #include "support/FileZipListDir.h" -#if !defined (HAVE_FORK) -# define fork() -1 -#endif - #include #include #include +#include #include -#include +#include #include -#include +#include +#include using namespace std; using namespace lyx::support; @@ -118,12 +116,12 @@ namespace os = support::os; namespace { -int const LYX_FORMAT = 310; // Bernhard Reiter: support for \nocite{*} - -} // namespace anon - +int const LYX_FORMAT = 321; typedef map DepClean; +typedef map > RefCache; + +} // namespace anon class Buffer::Impl { @@ -168,9 +166,6 @@ public: */ bool file_fully_loaded; - /// our Text that should be wrapped in an InsetText - InsetText inset; - /// mutable TocBackend toc_backend; @@ -178,6 +173,8 @@ public: typedef pair ScopeMacro; typedef map PositionScopeMacroMap; typedef map NamePositionScopeMacroMap; + /// map from the macro name to the position map, + /// which maps the macro definition position to the scope and the MacroData. NamePositionScopeMacroMap macros; bool macro_lock; @@ -185,14 +182,16 @@ public: typedef map BufferPositionMap; typedef pair ScopeBuffer; typedef map PositionScopeBufferMap; + /// position of children buffers in this buffer BufferPositionMap children_positions; + /// map from children inclusion positions to their scope and their buffer PositionScopeBufferMap position_to_children; /// Container for all sort of Buffer dependant errors. map errorLists; /// all embedded files of this buffer - EmbeddedFiles embedded_files; + EmbeddedFileList embedded_files; /// timestamp and checksum used to test if the file has been externally /// modified. (Used to properly enable 'File->Revert to saved', bug 4114). @@ -207,7 +206,12 @@ public: /// A cache for the bibfiles (including bibfiles of loaded child /// documents), needed for appropriate update of natbib labels. - mutable FileNameList bibfilesCache_; + mutable EmbeddedFileList bibfilesCache_; + + mutable RefCache ref_cache_; + + /// our Text that should be wrapped in an InsetText + InsetText inset; }; /// Creates the per buffer temporary directory @@ -232,12 +236,11 @@ static FileName createBufferTmpDir() Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_) : parent_buffer(0), lyx_clean(true), bak_clean(true), unnamed(false), read_only(readonly_), filename(file), file_fully_loaded(false), - inset(params), toc_backend(&parent), macro_lock(false), - embedded_files(&parent), timestamp_(0), checksum_(0), wa_(0), + toc_backend(&parent), macro_lock(false), + embedded_files(), timestamp_(0), checksum_(0), wa_(0), undo_(parent) { temppath = createBufferTmpDir(); - inset.setAutoBreakRows(true); lyxvc.setBuffer(&parent); if (use_gui) wa_ = new frontend::WorkAreaManager; @@ -249,6 +252,9 @@ Buffer::Buffer(string const & file, bool readonly) { LYXERR(Debug::INFO, "Buffer::Buffer()"); + d->inset.setBuffer(*this); + d->inset.initParagraphs(*this); + d->inset.setAutoBreakRows(true); d->inset.getText(0)->setMacrocontextPosition(par_iterator_begin()); } @@ -262,16 +268,9 @@ Buffer::~Buffer() // GuiView already destroyed gui_ = 0; - Buffer const * master = masterBuffer(); - if (master != this && use_gui) { - // We are closing buf which was a child document so we - // must update the labels and section numbering of its master - // Buffer. - updateLabels(*master); - master->updateMacros(); - } - - resetChildDocuments(false); + // clear references to children in macro tables + d->children_positions.clear(); + d->position_to_children.clear(); if (!d->temppath.destroyDirectory()) { Alert::warning(_("Could not remove temporary directory"), @@ -366,18 +365,24 @@ TocBackend & Buffer::tocBackend() const } -EmbeddedFiles & Buffer::embeddedFiles() +EmbeddedFileList & Buffer::embeddedFiles() { return d->embedded_files; } -EmbeddedFiles const & Buffer::embeddedFiles() const +EmbeddedFileList const & Buffer::embeddedFiles() const { return d->embedded_files; } +bool Buffer::embedded() const +{ + return params().embedded; +} + + Undo & Buffer::undo() { return d->undo_; @@ -465,6 +470,7 @@ int Buffer::readHeader(Lexer & lex) params().headheight.erase(); params().headsep.erase(); params().footskip.erase(); + params().columnsep.erase(); params().listings_params.clear(); params().clearLayoutModules(); params().pdfoptions().clear(); @@ -495,7 +501,8 @@ int Buffer::readHeader(Lexer & lex) LYXERR(Debug::PARSER, "Handling document header token: `" << token << '\''); - string unknown = params().readToken(lex, token, d->filename.onlyPath()); + string unknown = params().readToken(lex, token, d->filename.onlyPath(), + d->temppath); if (!unknown.empty()) { if (unknown[0] != '\\' && token == "\\textclass") { Alert::warning(_("Unknown document class"), @@ -518,7 +525,7 @@ int Buffer::readHeader(Lexer & lex) s, -1, 0, 0)); } - params().makeTextClass(); + params().makeDocumentClass(); return unknown_tokens; } @@ -566,10 +573,23 @@ bool Buffer::readDocument(Lexer & lex) } // read main text - bool const res = text().read(*this, lex, errorList); - for_each(text().paragraphs().begin(), - text().paragraphs().end(), - bind(&Paragraph::setInsetOwner, _1, &inset())); + bool const res = text().read(*this, lex, errorList, &(d->inset)); + + // Enable embeded files, which will set temp path and move + // inconsistent inzip files if needed. + try { + embeddedFiles().validate(*this); + embeddedFiles().enable(params().embedded, *this, false); + } catch (ExceptionMessage const & message) { + Alert::error(message.title_, message.details_); + Alert::warning(_("Failed to read embedded files"), + _("Due to most likely a bug, LyX failed to locate all embedded " + "file. If you unzip the LyX file, you should be able to see and " + "open content.lyx which is your main text. You may also be able " + "to recover some embedded files. Please report this bug to the " + "lyx-devel mailing list.")); + return false; + } updateMacros(); updateMacroInstances(); @@ -592,7 +612,7 @@ void Buffer::insertStringAsLines(ParagraphList & pars, if (*cit == '\n') { if (autobreakrows && (!par.empty() || par.allowEmpty())) { breakParagraph(params(), pars, pit, pos, - par.layout()->isEnvironment()); + par.layout().isEnvironment()); ++pit; pos = 0; space_inserted = true; @@ -672,6 +692,8 @@ bool Buffer::readFile(FileName const & filename) FileName lyxfile(addName(temppath(), "content.lyx")); // if both manifest.txt and file.lyx exist, this is am embedded file if (lyxfile.exists()) { + // if in bundled format, save checksum of the compressed file, not content.lyx + saveCheckSum(filename); params().embedded = true; fname = lyxfile; } @@ -903,25 +925,24 @@ bool Buffer::writeFile(FileName const & fname) const } if (!retval) { - message(str + _(" could not write file!.")); + message(str + _(" could not write file!")); return false; } removeAutosaveFile(d->filename.absFilename()); + + if (params().embedded) { + message(str + _(" writing embedded files.")); + // if embedding is enabled, write file.lyx and all the embedded files + // to the zip file fname. + if (!d->embedded_files.writeFile(fname, *this)) { + message(str + _(" could not write embedded files!")); + return false; + } + } saveCheckSum(d->filename); message(str + _(" done.")); - if (!params().embedded) - return true; - - message(str + _(" writing embedded files!.")); - // if embedding is enabled, write file.lyx and all the embedded files - // to the zip file fname. - if (!d->embedded_files.writeFile(fname)) { - message(str + _(" could not write embedded files!.")); - return false; - } - message(str + _(" error while writing embedded files.")); return true; } @@ -941,7 +962,6 @@ bool Buffer::write(ostream & ofs) const << "\\lyxformat " << LYX_FORMAT << "\n" << "\\begin_document\n"; - /// For each author, set 'used' to true if there is a change /// by this author in the document; otherwise set it to 'false'. AuthorList::Authors::const_iterator a_it = params().authors().begin(); @@ -949,8 +969,8 @@ bool Buffer::write(ostream & ofs) const for (; a_it != a_end; ++a_it) a_it->second.setUsed(false); - ParIterator const end = par_iterator_end(); - ParIterator it = par_iterator_begin(); + ParIterator const end = const_cast(this)->par_iterator_end(); + ParIterator it = const_cast(this)->par_iterator_begin(); for ( ; it != end; ++it) it->checkAuthors(params().authors()); @@ -1062,6 +1082,8 @@ void Buffer::writeLaTeXSource(odocstream & os, OutputParams const & runparams_in, bool const output_preamble, bool const output_body) const { + // The child documents, if any, shall be already loaded at this point. + OutputParams runparams = runparams_in; // validate the buffer. @@ -1126,9 +1148,13 @@ void Buffer::writeLaTeXSource(odocstream & os, LYXERR(Debug::INFO, "preamble finished, now the body."); + // Don't move this behind the parent_buffer=0 code below, + // because then the macros will not get the right "redefinition" + // flag as they don't see the parent macros which are output before. + updateMacros(); + // fold macros if possible, still with parent buffer as the // macros will be put in the prefix anyway. - updateMacros(); updateMacroInstances(); // if we are doing a real file with body, even if this is the @@ -1143,10 +1169,8 @@ void Buffer::writeLaTeXSource(odocstream & os, d->parent_buffer = 0; } - loadChildDocuments(); - // the real stuff - latexParagraphs(*this, paragraphs(), os, d->texrow, runparams); + latexParagraphs(*this, text(), os, d->texrow, runparams); // Restore the parenthood if needed if (output_preamble) { @@ -1181,19 +1205,19 @@ void Buffer::writeLaTeXSource(odocstream & os, bool Buffer::isLatex() const { - return params().getTextClass().outputType() == LATEX; + return params().documentClass().outputType() == LATEX; } bool Buffer::isLiterate() const { - return params().getTextClass().outputType() == LITERATE; + return params().documentClass().outputType() == LITERATE; } bool Buffer::isDocBook() const { - return params().getTextClass().outputType() == DOCBOOK; + return params().documentClass().outputType() == DOCBOOK; } @@ -1224,7 +1248,7 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, d->texrow.reset(); - TextClass const & tclass = params().getTextClass(); + DocumentClass const & tclass = params().documentClass(); string const top_element = tclass.latexname(); if (!only_body) { @@ -1279,9 +1303,9 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, << " file was created by LyX " << lyx_version << "\n See http://www.lyx.org/ for more information -->\n"; - params().getTextClass().counters().reset(); + params().documentClass().counters().reset(); - loadChildDocuments(); + updateMacros(); sgml::openTag(os, top); os << '\n'; @@ -1335,7 +1359,7 @@ void Buffer::validate(LaTeXFeatures & features) const { params().validate(features); - loadChildDocuments(); + updateMacros(); for_each(paragraphs().begin(), paragraphs().end(), boost::bind(&Paragraph::validate, _1, boost::ref(features))); @@ -1348,33 +1372,28 @@ void Buffer::validate(LaTeXFeatures & features) const void Buffer::getLabelList(vector & list) const { - /// if this is a child document and the parent is already loaded - /// Use the parent's list instead [ale990407] - Buffer const * tmp = masterBuffer(); - if (!tmp) { - lyxerr << "masterBuffer() failed!" << endl; - BOOST_ASSERT(tmp); - } - if (tmp != this) { - tmp->getLabelList(list); + // If this is a child document, use the parent's list instead. + if (d->parent_buffer) { + d->parent_buffer->getLabelList(list); return; } - loadChildDocuments(); - - for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) - it.nextInset()->getLabelList(*this, list); + list.clear(); + Toc & toc = d->toc_backend.toc("label"); + TocIterator toc_it = toc.begin(); + TocIterator end = toc.end(); + for (; toc_it != end; ++toc_it) { + if (toc_it->depth() == 0) + list.push_back(toc_it->str()); + } } void Buffer::updateBibfilesCache() const { - // if this is a child document and the parent is already loaded - // update the parent's cache instead - Buffer const * tmp = masterBuffer(); - BOOST_ASSERT(tmp); - if (tmp != this) { - tmp->updateBibfilesCache(); + // If this is a child document, use the parent's cache instead. + if (d->parent_buffer) { + d->parent_buffer->updateBibfilesCache(); return; } @@ -1383,15 +1402,15 @@ void Buffer::updateBibfilesCache() const if (it->lyxCode() == BIBTEX_CODE) { InsetBibtex const & inset = static_cast(*it); - FileNameList const bibfiles = inset.getFiles(*this); + EmbeddedFileList const bibfiles = inset.embeddedFiles(); d->bibfilesCache_.insert(d->bibfilesCache_.end(), bibfiles.begin(), bibfiles.end()); } else if (it->lyxCode() == INCLUDE_CODE) { InsetInclude & inset = static_cast(*it); - inset.updateBibfilesCache(*this); - FileNameList const & bibfiles = + inset.updateBibfilesCache(); + EmbeddedFileList const & bibfiles = inset.getBibfilesCache(*this); d->bibfilesCache_.insert(d->bibfilesCache_.end(), bibfiles.begin(), @@ -1401,14 +1420,11 @@ void Buffer::updateBibfilesCache() const } -FileNameList const & Buffer::getBibfilesCache() const +EmbeddedFileList const & Buffer::getBibfilesCache() const { - // if this is a child document and the parent is already loaded - // use the parent's cache instead - Buffer const * tmp = masterBuffer(); - BOOST_ASSERT(tmp); - if (tmp != this) - return tmp->getBibfilesCache(); + // If this is a child document, use the parent's cache instead. + if (d->parent_buffer) + return d->parent_buffer->getBibfilesCache(); // We update the cache when first used instead of at loading time. if (d->bibfilesCache_.empty()) @@ -1480,41 +1496,37 @@ bool Buffer::isMultiLingual() const } -ParIterator Buffer::getParFromID(int const id) const +DocIterator Buffer::getParFromID(int const id) const { - ParConstIterator it = par_iterator_begin(); - ParConstIterator const end = par_iterator_end(); - if (id < 0) { // John says this is called with id == -1 from undo lyxerr << "getParFromID(), id: " << id << endl; - return end; + return doc_iterator_end(inset()); } - for (; it != end; ++it) - if (it->id() == id) + for (DocIterator it = doc_iterator_begin(inset()); !it.atEnd(); it.forwardPar()) + if (it.paragraph().id() == id) return it; - return end; + return doc_iterator_end(inset()); } bool Buffer::hasParWithID(int const id) const { - ParConstIterator const it = getParFromID(id); - return it != par_iterator_end(); + return !getParFromID(id).atEnd(); } ParIterator Buffer::par_iterator_begin() { - return lyx::par_iterator_begin(inset()); + return ParIterator(doc_iterator_begin(inset())); } ParIterator Buffer::par_iterator_end() { - return lyx::par_iterator_end(inset()); + return ParIterator(doc_iterator_end(inset())); } @@ -1729,31 +1741,33 @@ MacroData const * Buffer::getBufferMacro(docstring const & name, // find macros in included files Impl::PositionScopeBufferMap::const_iterator it = greatest_below(d->position_to_children, pos); - if (it != d->position_to_children.end()) { - while (true) { - // do we know something better (i.e. later) already? - if (it->first < bestPos ) - break; + if (it == d->position_to_children.end()) + // no children before + return bestData; - // scope ends behind pos? - if (pos < it->second.first) { - // look for macro in external file - d->macro_lock = true; - MacroData const * data - = it->second.second->getMacro(name, false); - d->macro_lock = false; - if (data) { - bestPos = it->first; - bestData = data; - break; - } - } - - // try previous file if there is one - if (it == d->position_to_children.begin()) + while (true) { + // do we know something better (i.e. later) already? + if (it->first < bestPos ) + break; + + // scope ends behind pos? + if (pos < it->second.first) { + // look for macro in external file + d->macro_lock = true; + MacroData const * data + = it->second.second->getMacro(name, false); + d->macro_lock = false; + if (data) { + bestPos = it->first; + bestData = data; break; - --it; + } } + + // try previous file if there is one + if (it == d->position_to_children.begin()) + break; + --it; } // return the best macro we have found @@ -1775,8 +1789,8 @@ MacroData const * Buffer::getMacro(docstring const & name, // If there is a master buffer, query that if (d->parent_buffer) { d->macro_lock = true; - MacroData const * macro - = d->parent_buffer->getMacro(name, *this, false); + MacroData const * macro = d->parent_buffer->getMacro( + name, *this, false); d->macro_lock = false; if (macro) return macro; @@ -1802,11 +1816,11 @@ MacroData const * Buffer::getMacro(docstring const & name, bool global) const } -MacroData const * Buffer::getMacro(docstring const & name, Buffer const & child, bool global) const +MacroData const * Buffer::getMacro(docstring const & name, + Buffer const & child, bool global) const { // look where the child buffer is included first - Impl::BufferPositionMap::iterator it - = d->children_positions.find(&child); + Impl::BufferPositionMap::iterator it = d->children_positions.find(&child); if (it == d->children_positions.end()) return 0; @@ -1815,28 +1829,14 @@ MacroData const * Buffer::getMacro(docstring const & name, Buffer const & child, } -void Buffer::updateEnvironmentMacros(DocIterator & it, - pit_type lastpit, - DocIterator & scope) const +void Buffer::updateMacros(DocIterator & it, DocIterator & scope) const { - Paragraph & par = it.paragraph(); - depth_type depth - = par.params().depth(); - Length const & leftIndent - = par.params().leftIndent(); + pit_type lastpit = it.lastpit(); // look for macros in each paragraph while (it.pit() <= lastpit) { Paragraph & par = it.paragraph(); - // increased depth? - if ((par.params().depth() > depth - || par.params().leftIndent() != leftIndent) - && par.layout()->isEnvironment()) { - updateBlockMacros(it, scope); - continue; - } - // iterate over the insets of the current paragraph InsetList const & insets = par.insetList(); InsetList::const_iterator iit = insets.begin(); @@ -1849,15 +1849,15 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, // Inset needs its own scope? InsetText const * itext = iit->inset->asInsetText(); - bool newScope = itext->isMacroScope(*this); + bool newScope = itext->isMacroScope(); - // scope which ends just behind die inset + // scope which ends just behind the inset DocIterator insetScope = it; - insetScope.pos()++; + ++insetScope.pos(); // collect macros in inset it.push_back(CursorSlice(*iit->inset)); - updateInsetMacros(it, newScope ? insetScope : scope); + updateMacros(it, newScope ? insetScope : scope); it.pop_back(); continue; } @@ -1866,7 +1866,7 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, if (iit->inset->lyxCode() == INCLUDE_CODE) { // get buffer of external file InsetCommand const & inset - = static_cast(*iit->inset); + = static_cast(*iit->inset); InsetCommandParams const & ip = inset.params(); d->macro_lock = true; Buffer * child = loadIfNeeded(*this, ip); @@ -1874,15 +1874,14 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, if (!child) continue; - // register it, but only when it is + // register its position, but only when it is // included first in the buffer if (d->children_positions.find(child) - == d->children_positions.end()) + == d->children_positions.end()) d->children_positions[child] = it; // register child with its scope d->position_to_children[it] = Impl::ScopeBuffer(scope, child); - continue; } @@ -1904,8 +1903,8 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, continue; // register macro - d->macros[macroTemplate.name()][it] - = Impl::ScopeMacro(scope, MacroData(*this, it)); + d->macros[macroTemplate.name()][it] = + Impl::ScopeMacro(scope, MacroData(*this, it)); } // next paragraph @@ -1915,48 +1914,6 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, } -void Buffer::updateBlockMacros(DocIterator & it, DocIterator & scope) const -{ - Paragraph & par = it.paragraph(); - - // set scope for macros in this paragraph: - // * either the "old" outer scope - // * or the scope ending after the environment - if (par.layout()->isEnvironment()) { - // find end of environment block, - DocIterator envEnd = it; - pit_type n = it.lastpit() + 1; - depth_type depth = par.params().depth(); - Length const & length = par.params().leftIndent(); - // looping through the paragraph, basically until - // the layout changes or the depth gets smaller. - // (the logic of output_latex.cpp's TeXEnvironment) - do { - envEnd.pit()++; - if (envEnd.pit() == n) - break; - } while (par.layout() == envEnd.paragraph().layout() - || depth < envEnd.paragraph().params().depth() - || length != envEnd.paragraph().params().leftIndent()); - - // collect macros from environment block - updateEnvironmentMacros(it, envEnd.pit() - 1, envEnd); - } else { - // collect macros from paragraph - updateEnvironmentMacros(it, it.pit(), scope); - } -} - - -void Buffer::updateInsetMacros(DocIterator & it, DocIterator & scope) const -{ - // look for macros in each paragraph - pit_type n = it.lastpit() + 1; - while (it.pit() < n) - updateBlockMacros(it, scope); -} - - void Buffer::updateMacros() const { if (d->macro_lock) @@ -1976,15 +1933,16 @@ void Buffer::updateMacros() const DocIterator it = par_iterator_begin(); DocIterator outerScope = it; outerScope.pit() = outerScope.lastpit() + 2; - updateInsetMacros(it, outerScope); + updateMacros(it, outerScope); } void Buffer::updateMacroInstances() const { - LYXERR(Debug::MACROS, "updateMacroInstances for " << d->filename.onlyFileName()); - ParIterator it = par_iterator_begin(); - ParIterator end = par_iterator_end(); + LYXERR(Debug::MACROS, "updateMacroInstances for " + << d->filename.onlyFileName()); + DocIterator it = doc_iterator_begin(inset()); + DocIterator end = doc_iterator_end(inset()); for (; it != end; it.forwardPos()) { // look for MathData cells in InsetMathNest insets Inset * inset = it.nextInset(); @@ -2014,18 +1972,14 @@ void Buffer::listMacroNames(MacroNameSet & macros) const d->macro_lock = true; // loop over macro names - Impl::NamePositionScopeMacroMap::iterator nameIt - = d->macros.begin(); - Impl::NamePositionScopeMacroMap::iterator nameEnd - = d->macros.end(); + Impl::NamePositionScopeMacroMap::iterator nameIt = d->macros.begin(); + Impl::NamePositionScopeMacroMap::iterator nameEnd = d->macros.end(); for (; nameIt != nameEnd; ++nameIt) macros.insert(nameIt->first); // loop over children - Impl::BufferPositionMap::iterator it - = d->children_positions.begin(); - Impl::BufferPositionMap::iterator end - = d->children_positions.end(); + Impl::BufferPositionMap::iterator it = d->children_positions.begin(); + Impl::BufferPositionMap::iterator end = d->children_positions.end(); for (; it != end; ++it) it->first->listMacroNames(macros); @@ -2054,34 +2008,70 @@ void Buffer::writeParentMacros(odocstream & os) const MacroData const * data = d->parent_buffer->getMacro(*it, *this, false); if (data) - data->write(os, true); + data->write(os, true); } } +Buffer::References & Buffer::references(docstring const & label) +{ + if (d->parent_buffer) + return const_cast(masterBuffer())->references(label); + + RefCache::iterator it = d->ref_cache_.find(label); + if (it != d->ref_cache_.end()) + return it->second.second; + + static InsetLabel const * dummy_il = 0; + static References const dummy_refs; + it = d->ref_cache_.insert( + make_pair(label, make_pair(dummy_il, dummy_refs))).first; + return it->second.second; +} + + +Buffer::References const & Buffer::references(docstring const & label) const +{ + return const_cast(this)->references(label); +} + + +void Buffer::setInsetLabel(docstring const & label, InsetLabel const * il) +{ + masterBuffer()->d->ref_cache_[label].first = il; +} + + +InsetLabel const * Buffer::insetLabel(docstring const & label) const +{ + return masterBuffer()->d->ref_cache_[label].first; +} + + +void Buffer::clearReferenceCache() const +{ + if (!d->parent_buffer) + d->ref_cache_.clear(); +} + + void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to, InsetCode code) { //FIXME: This does not work for child documents yet. - BOOST_ASSERT(code == CITE_CODE || code == REF_CODE); + BOOST_ASSERT(code == CITE_CODE); // Check if the label 'from' appears more than once vector labels; - string paramName; - if (code == CITE_CODE) { - BiblioInfo keys; - keys.fillWithBibKeys(this); - BiblioInfo::const_iterator bit = keys.begin(); - BiblioInfo::const_iterator bend = keys.end(); + BiblioInfo keys; + keys.fillWithBibKeys(this); + BiblioInfo::const_iterator bit = keys.begin(); + BiblioInfo::const_iterator bend = keys.end(); - for (; bit != bend; ++bit) - // FIXME UNICODE - labels.push_back(bit->first); - paramName = "key"; - } else { - getLabelList(labels); - paramName = "reference"; - } + for (; bit != bend; ++bit) + // FIXME UNICODE + labels.push_back(bit->first); + paramName = "key"; if (count(labels.begin(), labels.end(), from) > 1) return; @@ -2114,31 +2104,30 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, d->texrow.newline(); if (isLatex()) writeLaTeXSource(os, filePath(), runparams, true, true); - else { + else writeDocBookSource(os, absFileName(), runparams, false); - } } else { runparams.par_begin = par_begin; runparams.par_end = par_end; - if (par_begin + 1 == par_end) + if (par_begin + 1 == par_end) { os << "% " << bformat(_("Preview source code for paragraph %1$d"), par_begin) << "\n\n"; - else + } else { os << "% " << bformat(_("Preview source code from paragraph %1$s to %2$s"), convert(par_begin), convert(par_end - 1)) << "\n\n"; + } d->texrow.newline(); d->texrow.newline(); // output paragraphs - if (isLatex()) { - latexParagraphs(*this, paragraphs(), os, d->texrow, runparams); - } else { + if (isLatex()) + latexParagraphs(*this, text(), os, d->texrow, runparams); + else // DocBook docbookParagraphs(paragraphs(), *this, os, runparams); - } } } @@ -2238,52 +2227,44 @@ private: }; -#if !defined (HAVE_FORK) -# define fork() -1 -#endif - int AutoSaveBuffer::generateChild() { // tmp_ret will be located (usually) in /tmp // will that be a problem? + // Note that this calls ForkedCalls::fork(), so it's + // ok cross-platform. pid_t const pid = fork(); // If you want to debug the autosave // you should set pid to -1, and comment out the fork. - if (pid == 0 || pid == -1) { - // pid = -1 signifies that lyx was unable - // to fork. But we will do the save - // anyway. - bool failed = false; - - FileName const tmp_ret = FileName::tempName("lyxauto"); - if (!tmp_ret.empty()) { - buffer_.writeFile(tmp_ret); - // assume successful write of tmp_ret - if (!tmp_ret.moveTo(fname_)) { - failed = true; - // most likely couldn't move between - // filesystems unless write of tmp_ret - // failed so remove tmp file (if it - // exists) - tmp_ret.removeFile(); - } - } else { + if (pid != 0 && pid != -1) + return pid; + + // pid = -1 signifies that lyx was unable + // to fork. But we will do the save + // anyway. + bool failed = false; + FileName const tmp_ret = FileName::tempName("lyxauto"); + if (!tmp_ret.empty()) { + buffer_.writeFile(tmp_ret); + // assume successful write of tmp_ret + if (!tmp_ret.moveTo(fname_)) failed = true; - } - - if (failed) { - // failed to write/rename tmp_ret so try writing direct - if (!buffer_.writeFile(fname_)) { - // It is dangerous to do this in the child, - // but safe in the parent, so... - if (pid == -1) // emit message signal. - buffer_.message(_("Autosave failed!")); - } - } - if (pid == 0) { // we are the child so... - _exit(0); + } else + failed = true; + + if (failed) { + // failed to write/rename tmp_ret so try writing direct + if (!buffer_.writeFile(fname_)) { + // It is dangerous to do this in the child, + // but safe in the parent, so... + if (pid == -1) // emit message signal. + buffer_.message(_("Autosave failed!")); } } + + if (pid == 0) // we are the child so... + _exit(0); + return pid; } @@ -2316,49 +2297,6 @@ void Buffer::autoSave() const } -void Buffer::resetChildDocuments(bool close_them) const -{ - for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { - if (it->lyxCode() != INCLUDE_CODE) - continue; - InsetCommand const & inset = static_cast(*it); - InsetCommandParams const & ip = inset.params(); - - resetParentBuffer(this, ip, close_them); - } - - if (use_gui && masterBuffer() == this) - updateLabels(*this); - - // clear references to children in macro tables - d->children_positions.clear(); - d->position_to_children.clear(); -} - - -void Buffer::loadChildDocuments() const -{ - bool parse_error = false; - - for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { - if (it->lyxCode() != INCLUDE_CODE) - continue; - InsetCommand const & inset = static_cast(*it); - InsetCommandParams const & ip = inset.params(); - Buffer * child = loadIfNeeded(*this, ip); - if (!child) - continue; - parse_error |= !child->errorList("Parse").empty(); - child->loadChildDocuments(); - } - - if (use_gui && masterBuffer() == this) - updateLabels(*this); - - updateMacros(); -} - - string Buffer::bufferFormat() const { if (isDocBook()) @@ -2451,40 +2389,40 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, if (!success) return false; - if (put_in_tempdir) + if (put_in_tempdir) { result_file = tmp_result_file.absFilename(); - else { - result_file = changeExtension(absFileName(), ext); - // We need to copy referenced files (e. g. included graphics - // if format == "dvi") to the result dir. - vector const files = - runparams.exportdata->externalFiles(format); - string const dest = onlyPath(result_file); - CopyStatus status = SUCCESS; - for (vector::const_iterator it = files.begin(); - it != files.end() && status != CANCEL; ++it) { - string const fmt = - formats.getFormatFromFile(it->sourceName); - status = copyFile(fmt, it->sourceName, - makeAbsPath(it->exportName, dest), - it->exportName, status == FORCE); - } - if (status == CANCEL) { - message(_("Document export cancelled.")); - } else if (tmp_result_file.exists()) { - // Finally copy the main file - status = copyFile(format, tmp_result_file, - FileName(result_file), result_file, - status == FORCE); - message(bformat(_("Document exported as %1$s " - "to file `%2$s'"), - formats.prettyName(format), - makeDisplayPath(result_file))); - } else { - // This must be a dummy converter like fax (bug 1888) - message(bformat(_("Document exported as %1$s"), - formats.prettyName(format))); - } + return true; + } + + result_file = changeExtension(absFileName(), ext); + // We need to copy referenced files (e. g. included graphics + // if format == "dvi") to the result dir. + vector const files = + runparams.exportdata->externalFiles(format); + string const dest = onlyPath(result_file); + CopyStatus status = SUCCESS; + for (vector::const_iterator it = files.begin(); + it != files.end() && status != CANCEL; ++it) { + string const fmt = formats.getFormatFromFile(it->sourceName); + status = copyFile(fmt, it->sourceName, + makeAbsPath(it->exportName, dest), + it->exportName, status == FORCE); + } + if (status == CANCEL) { + message(_("Document export cancelled.")); + } else if (tmp_result_file.exists()) { + // Finally copy the main file + status = copyFile(format, tmp_result_file, + FileName(result_file), result_file, + status == FORCE); + message(bformat(_("Document exported as %1$s " + "to file `%2$s'"), + formats.prettyName(format), + makeDisplayPath(result_file))); + } else { + // This must be a dummy converter like fax (bug 1888) + message(bformat(_("Document exported as %1$s"), + formats.prettyName(format))); } return true; @@ -2536,7 +2474,7 @@ vector Buffer::exportableFormats(bool only_viewable) const vector Buffer::backends() const { vector v; - if (params().getTextClass().isTeXClassAvailable()) { + if (params().baseClass()->isTeXClassAvailable()) { v.push_back(bufferFormat()); // FIXME: Don't hardcode format names here, but use a flag if (v.back() == "latex")