X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=6c3841ba638ee1941effd418265a999564c4107f;hb=1f820d11a26a156fd26dced06ea5d8b7a07896e2;hp=d6bc6d579b3101b1faa78c24d969e0928a22f8d6;hpb=a2abadb9f39269cc56516e7216e938efdcabb1fa;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index d6bc6d579b..6c3841ba63 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -77,12 +77,12 @@ #include "mathed/MathMacroTemplate.h" #include "mathed/MathSupport.h" +#include "graphics/PreviewLoader.h" + #include "frontends/alert.h" #include "frontends/Delegates.h" #include "frontends/WorkAreaManager.h" -#include "graphics/Previews.h" - #include "support/lassert.h" #include "support/convert.h" #include "support/debug.h" @@ -117,6 +117,7 @@ using namespace std; using namespace lyx::support; +using namespace lyx::graphics; namespace lyx { @@ -150,6 +151,7 @@ public: ~Impl() { + delete preview_loader_; if (wa_) { wa_->closeAll(); delete wa_; @@ -257,12 +259,19 @@ public: mutable bool bibfile_cache_valid_; /// Cache of timestamps of .bib files map bibfile_status_; + /// Indicates whether the bibinfo has changed since the last time + /// we ran updateBuffer(), i.e., whether citation labels may need + /// to be updated. + mutable bool cite_labels_valid_; mutable RefCache ref_cache_; /// our Text that should be wrapped in an InsetText InsetText * inset; + /// + PreviewLoader * preview_loader_; + /// This is here to force the test to be done whenever parent_buffer /// is accessed. Buffer const * parent() const { @@ -327,10 +336,11 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_, Buffer const * cloned_buffer) : owner_(owner), lyx_clean(true), bak_clean(true), unnamed(false), read_only(readonly_), filename(file), file_fully_loaded(false), - toc_backend(owner), macro_lock(false), timestamp_(0), - checksum_(0), wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false), - bibfile_cache_valid_(false), cloned_buffer_(cloned_buffer), - doing_export(false), parent_buffer(0) + toc_backend(owner), macro_lock(false), timestamp_(0), checksum_(0), + wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false), + bibfile_cache_valid_(false), cite_labels_valid_(false), + preview_loader_(0), cloned_buffer_(cloned_buffer), + doing_export(false), parent_buffer(0) { if (!cloned_buffer_) { temppath = createBufferTmpDir(); @@ -347,6 +357,7 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_, bibinfo_cache_valid_ = cloned_buffer_->d->bibinfo_cache_valid_; bibfile_cache_valid_ = cloned_buffer_->d->bibfile_cache_valid_; bibfile_status_ = cloned_buffer_->d->bibfile_status_; + cite_labels_valid_ = cloned_buffer_->d->cite_labels_valid_; } @@ -422,29 +433,50 @@ Buffer::~Buffer() Buffer * Buffer::clone() const { + BufferMap bufmap; + masterBuffer()->clone(bufmap); + BufferMap::iterator it = bufmap.find(this); + LASSERT(it != bufmap.end(), return 0); + return it->second; +} + + +void Buffer::clone(BufferMap & bufmap) const +{ + // have we already been cloned? + if (bufmap.find(this) != bufmap.end()) + return; + Buffer * buffer_clone = new Buffer(fileName().absFileName(), false, this); + bufmap[this] = buffer_clone; buffer_clone->d->macro_lock = true; buffer_clone->d->children_positions.clear(); // FIXME (Abdel 09/01/2010): this is too complicated. The whole children_positions and // math macro caches need to be rethought and simplified. // I am not sure wether we should handle Buffer cloning here or in BufferList. // Right now BufferList knows nothing about buffer clones. - Impl::BufferPositionMap::iterator it = d->children_positions.begin(); - Impl::BufferPositionMap::iterator end = d->children_positions.end(); + Impl::PositionScopeBufferMap::iterator it = d->position_to_children.begin(); + Impl::PositionScopeBufferMap::iterator end = d->position_to_children.end(); for (; it != end; ++it) { - DocIterator dit = it->second.clone(buffer_clone); + DocIterator dit = it->first.clone(buffer_clone); dit.setBuffer(buffer_clone); - Buffer * child = const_cast(it->first); - Buffer * child_clone = child->clone(); + Buffer * child = const_cast(it->second.second); + + child->clone(bufmap); + BufferMap::iterator const bit = bufmap.find(child); + LASSERT(bit != bufmap.end(), continue); + Buffer * child_clone = bit->second; + Inset * inset = dit.nextInset(); LASSERT(inset && inset->lyxCode() == INCLUDE_CODE, continue); InsetInclude * inset_inc = static_cast(inset); inset_inc->setChildBuffer(child_clone); child_clone->d->setParent(buffer_clone); + // FIXME Do we need to do this now, or can we wait until we run updateMacros()? buffer_clone->setChild(dit, child_clone); } buffer_clone->d->macro_lock = false; - return buffer_clone; + return; } @@ -597,7 +629,7 @@ string Buffer::logName(LogType * type) const FileName const bname( addName(path, onlyFileName( changeExtension(filename, - formats.extension(bufferFormat()) + ".out")))); + formats.extension(params().bufferFormat()) + ".out")))); // Also consider the master buffer log file FileName masterfname = fname; @@ -830,7 +862,7 @@ bool Buffer::readDocument(Lexer & lex) } usermacros.clear(); updateMacros(); - updateMacroInstances(); + updateMacroInstances(InternalUpdate); return res; } @@ -868,7 +900,12 @@ Buffer::ReadStatus Buffer::readFile(FileName const & fn) { FileName fname(fn); Lexer lex; - lex.setFile(fname); + if (!lex.setFile(fname)) { + Alert::error(_("File Not Found"), + bformat(_("Unable to open file `%1$s'."), + from_utf8(fn.absFileName()))); + return ReadFileNotFound; + } int file_format; ReadStatus const ret_plf = parseLyXFormat(lex, fn, file_format); @@ -915,16 +952,35 @@ void Buffer::setFullyLoaded(bool value) } -void Buffer::updatePreviews() const +PreviewLoader * Buffer::loader() const { - if (graphics::Previews::status() != LyXRC::PREVIEW_OFF) - thePreviews().generateBufferPreviews(*this); + if (lyxrc.preview == LyXRC::PREVIEW_OFF) + return 0; + if (!d->preview_loader_) + d->preview_loader_ = new PreviewLoader(*this); + return d->preview_loader_; } void Buffer::removePreviews() const { - thePreviews().removeLoader(*this); + delete d->preview_loader_; + d->preview_loader_ = 0; +} + + +void Buffer::updatePreviews() const +{ + PreviewLoader * ploader = loader(); + if (!ploader) + return; + + InsetIterator it = inset_iterator_begin(*d->inset); + InsetIterator const end = inset_iterator_end(*d->inset); + for (; it != end; ++it) + it->addPreview(it, *ploader); + + ploader->startLoading(); } @@ -1086,6 +1142,11 @@ bool Buffer::save() const bool Buffer::writeFile(FileName const & fname) const { + // FIXME Do we need to do these here? I don't think writing + // the LyX file depends upon it. (RGH) + // updateBuffer(); + // updateMacroInstances(); + if (d->read_only && fname == d->filename) return false; @@ -1147,7 +1208,7 @@ docstring Buffer::emergencyWrite() } // 2) In HOME directory. - string s = addName(package().home_dir().absFileName(), absFileName()); + string s = addName(Package::get_home_dir().absFileName(), absFileName()); s += ".emergency"; lyxerr << ' ' << s << endl; if (writeFile(FileName(s))) { @@ -1270,6 +1331,14 @@ bool Buffer::makeLaTeXFile(FileName const & fname, errorList.clear(); bool failed_export = false; otexstream os(ofs, d->texrow); + + // make sure we are ready to export + // this needs to be done before we validate + // FIXME Do we need to do this all the time? I.e., in children + // of a master we are exporting? + updateBuffer(); + updateMacroInstances(OutputUpdate); + try { os.texrow().reset(); writeLaTeXSource(os, original_path, @@ -1343,15 +1412,6 @@ void Buffer::writeLaTeXSource(otexstream & os, } LYXERR(Debug::INFO, "lyx document header finished"); - // 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. - updateMacroInstances(); - // There are a few differences between nice LaTeX and usual files: // usual is \batchmode and has a // special input@path to allow the including of figures @@ -1477,24 +1537,6 @@ void Buffer::writeLaTeXSource(otexstream & os, } -bool Buffer::isLatex() const -{ - return params().documentClass().outputType() == LATEX; -} - - -bool Buffer::isLiterate() const -{ - return params().documentClass().outputType() == LITERATE; -} - - -bool Buffer::isDocBook() const -{ - return params().documentClass().outputType() == DOCBOOK; -} - - void Buffer::makeDocBookFile(FileName const & fname, OutputParams const & runparams, bool const body_only) const @@ -1505,6 +1547,11 @@ void Buffer::makeDocBookFile(FileName const & fname, if (!openFileWrite(ofs, fname)) return; + // make sure we are ready to export + // this needs to be done before we validate + updateBuffer(); + updateMacroInstances(OutputUpdate); + writeDocBookSource(ofs, fname.absFileName(), runparams, body_only); ofs.close(); @@ -1579,8 +1626,6 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, params().documentClass().counters().reset(); - updateMacros(); - sgml::openTag(os, top); os << '\n'; docbookParagraphs(text(), *this, os, runparams); @@ -1589,8 +1634,7 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, void Buffer::makeLyXHTMLFile(FileName const & fname, - OutputParams const & runparams, - bool const body_only) const + OutputParams const & runparams) const { LYXERR(Debug::LATEX, "makeLyXHTMLFile..."); @@ -1598,7 +1642,12 @@ void Buffer::makeLyXHTMLFile(FileName const & fname, if (!openFileWrite(ofs, fname)) return; - writeLyXHTMLSource(ofs, runparams, body_only); + // make sure we are ready to export + // this has to be done before we validate + updateBuffer(UpdateMaster, OutputUpdate); + updateMacroInstances(OutputUpdate); + + writeLyXHTMLSource(ofs, runparams); ofs.close(); if (ofs.fail()) @@ -1612,10 +1661,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os, { LaTeXFeatures features(*this, params(), runparams); validate(features); - updateBuffer(UpdateMaster, OutputUpdate); d->bibinfo_.makeCitationLabels(*this); - updateMacros(); - updateMacroInstances(); if (!only_body) { os << "\n" @@ -1701,8 +1747,6 @@ void Buffer::validate(LaTeXFeatures & features) const { params().validate(features); - updateMacros(); - for_each(paragraphs().begin(), paragraphs().end(), bind(&Paragraph::validate, _1, ref(features))); @@ -1764,12 +1808,14 @@ void Buffer::updateBibfilesCache(UpdateScope scope) const } d->bibfile_cache_valid_ = true; d->bibinfo_cache_valid_ = false; + d->cite_labels_valid_ = false; } void Buffer::invalidateBibinfoCache() const { d->bibinfo_cache_valid_ = false; + d->cite_labels_valid_ = false; // also invalidate the cache for the parent buffer Buffer const * const pbuf = d->parent(); if (pbuf) @@ -1781,6 +1827,7 @@ void Buffer::invalidateBibfileCache() const { d->bibfile_cache_valid_ = false; d->bibinfo_cache_valid_ = false; + d->cite_labels_valid_ = false; // also invalidate the cache for the parent buffer Buffer const * const pbuf = d->parent(); if (pbuf) @@ -1830,6 +1877,7 @@ void Buffer::checkIfBibInfoCacheIsValid() const time_t prevw = d->bibfile_status_[*ei]; if (lastw != prevw) { d->bibinfo_cache_valid_ = false; + d->cite_labels_valid_ = false; d->bibfile_status_[*ei] = lastw; } } @@ -1880,6 +1928,12 @@ void Buffer::addBibTeXInfo(docstring const & key, BibTeXInfo const & bi) const } +bool Buffer::citeLabelsValid() const +{ + return masterBuffer()->d->cite_labels_valid_; +} + + bool Buffer::isDepClean(string const & name) const { DepClean::const_iterator const it = d->dep_clean.find(name); @@ -1895,21 +1949,6 @@ void Buffer::markDepClean(string const & name) } -bool Buffer::isExportableFormat(string const & format) const -{ - typedef vector Formats; - Formats formats; - formats = exportableFormats(true); - Formats::const_iterator fit = formats.begin(); - Formats::const_iterator end = formats.end(); - for (; fit != end ; ++fit) { - if ((*fit)->name() == format) - return true; - } - return false; -} - - bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) { if (isInternal()) { @@ -1938,7 +1977,7 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_BUFFER_EXPORT: { docstring const arg = cmd.argument(); - enable = arg == "custom" || isExportable(to_utf8(arg)); + enable = arg == "custom" || params().isExportable(to_utf8(arg)); if (!enable) flag.message(bformat( _("Don't know how to export to format: %1$s"), arg)); @@ -1946,11 +1985,11 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) } case LFUN_BUFFER_CHKTEX: - enable = isLatex() && !lyxrc.chktex_command.empty(); + enable = params().isLatex() && !lyxrc.chktex_command.empty(); break; case LFUN_BUILD_PROGRAM: - enable = isExportable("program"); + enable = params().isExportable("program"); break; case LFUN_BRANCH_ACTIVATE: @@ -2061,7 +2100,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) // Execute the command in the background Systemcall call; - call.startscript(Systemcall::DontWait, command); + call.startscript(Systemcall::DontWait, command, filePath()); break; } @@ -2239,7 +2278,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) command2 += quoteName(psname); // First run dvips. // If successful, then spool command - res = one.startscript(Systemcall::Wait, command); + res = one.startscript(Systemcall::Wait, command, + filePath()); if (res == 0) { // If there's no GUI, we have to wait on this command. Otherwise, @@ -2247,7 +2287,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) // file, before it can be printed!! Systemcall::Starttype stype = use_gui ? Systemcall::DontWait : Systemcall::Wait; - res = one.startscript(stype, command2); + res = one.startscript(stype, command2, + filePath()); } } else { // case 2: print directly to a printer @@ -2256,7 +2297,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) // as above.... Systemcall::Starttype stype = use_gui ? Systemcall::DontWait : Systemcall::Wait; - res = one.startscript(stype, command + quoteName(dviname)); + res = one.startscript(stype, command + + quoteName(dviname), filePath()); } } else { @@ -2279,7 +2321,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) // as above.... Systemcall::Starttype stype = use_gui ? Systemcall::DontWait : Systemcall::Wait; - res = one.startscript(stype, command); + res = one.startscript(stype, command, filePath()); } if (res == 0) @@ -2598,6 +2640,12 @@ void Buffer::collectChildren(ListOfBuffers & clist, bool grand_children) const // there might be grandchildren child->collectChildren(clist, true); } + // Make sure we have not included ourselves. + ListOfBuffers::iterator bit = find(clist.begin(), clist.end(), this); + if (bit != clist.end()) { + LYXERR0("Recursive include detected in `" << fileName() << "'."); + clist.erase(bit); + } } @@ -2920,7 +2968,7 @@ void Buffer::getUsedBranches(std::list & result, bool const from_mast } -void Buffer::updateMacroInstances() const +void Buffer::updateMacroInstances(UpdateType utype) const { LYXERR(Debug::MACROS, "updateMacroInstances for " << d->filename.onlyFileName()); @@ -2938,7 +2986,7 @@ void Buffer::updateMacroInstances() const MacroContext mc = MacroContext(this, it); for (DocIterator::idx_type i = 0; i < n; ++i) { MathData & data = minset->cell(i); - data.updateMacros(0, mc); + data.updateMacros(0, mc, utype); } } } @@ -3084,7 +3132,7 @@ void Buffer::getSourceCode(odocstream & os, string const format, { OutputParams runparams(¶ms().encoding()); runparams.nice = true; - runparams.flavor = getOutputFlavor(format); + runparams.flavor = params().getOutputFlavor(format); runparams.linelen = lyxrc.plaintext_linelen; // No side effect of file copying and image conversion runparams.dryrun = true; @@ -3094,7 +3142,7 @@ void Buffer::getSourceCode(odocstream & os, string const format, d->texrow.reset(); d->texrow.newline(); d->texrow.newline(); - if (isDocBook()) + if (params().isDocBook()) writeDocBookSource(os, absFileName(), runparams, false); else if (runparams.flavor == OutputParams::HTML) writeLyXHTMLSource(os, runparams, false); @@ -3122,7 +3170,7 @@ void Buffer::getSourceCode(odocstream & os, string const format, texrow.newline(); texrow.newline(); // output paragraphs - if (isDocBook()) + if (params().isDocBook()) docbookParagraphs(text(), *this, os, runparams); else if (runparams.flavor == OutputParams::HTML) { XHTMLStream xs(os); @@ -3138,12 +3186,7 @@ void Buffer::getSourceCode(odocstream & os, string const format, ErrorList & Buffer::errorList(string const & type) const { - static ErrorList emptyErrorList; - map::iterator it = d->errorLists.find(type); - if (it == d->errorLists.end()) - return emptyErrorList; - - return it->second; + return d->errorLists[type]; } @@ -3367,74 +3410,6 @@ bool Buffer::autoSave() const } -string Buffer::bufferFormat() const -{ - string format = params().documentClass().outputFormat(); - if (format == "latex") { - if (params().useNonTeXFonts) - return "xetex"; - if (params().encoding().package() == Encoding::japanese) - return "platex"; - } - return format; -} - - -string Buffer::getDefaultOutputFormat() const -{ - if (!params().default_output_format.empty() - && params().default_output_format != "default") - return params().default_output_format; - if (isDocBook() - || params().useNonTeXFonts - || params().encoding().package() == Encoding::japanese) { - vector const formats = exportableFormats(true); - if (formats.empty()) - return string(); - // return the first we find - return formats.front()->name(); - } - return lyxrc.default_view_format; -} - - -OutputParams::FLAVOR Buffer::getOutputFlavor(string const format) const -{ - string const dformat = (format.empty() || format == "default") ? - getDefaultOutputFormat() : format; - DefaultFlavorCache::const_iterator it = - default_flavors_.find(dformat); - - if (it != default_flavors_.end()) - return it->second; - - OutputParams::FLAVOR result = OutputParams::LATEX; - - if (dformat == "xhtml") - result = OutputParams::HTML; - else { - // Try to determine flavor of default output format - vector backs = backends(); - if (find(backs.begin(), backs.end(), dformat) == backs.end()) { - // Get shortest path to format - Graph::EdgePath path; - for (vector::const_iterator it = backs.begin(); - it != backs.end(); ++it) { - Graph::EdgePath p = theConverters().getPath(*it, dformat); - if (!p.empty() && (path.empty() || p.size() < path.size())) { - path = p; - } - } - if (!path.empty()) - result = theConverters().getFlavor(path); - } - } - // cache this flavor - default_flavors_[dformat] = result; - return result; -} - - namespace { // helper class, to guarantee this gets reset properly class MarkAsExporting { @@ -3480,7 +3455,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, runparams.flavor = OutputParams::LATEX; runparams.linelen = lyxrc.plaintext_linelen; runparams.includeall = includeall; - vector backs = backends(); + vector backs = params().backends(); Converters converters = theConverters(); if (find(backs.begin(), backs.end(), format) == backs.end()) { // Get shortest path to format @@ -3522,9 +3497,6 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, filename = changeExtension(filename, formats.extension(backend_format)); - // fix macros - updateMacroInstances(); - // Plain text backend if (backend_format == "text") { runparams.flavor = OutputParams::TEXT; @@ -3551,7 +3523,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, } else if (backend_format == "lyx") writeFile(FileName(filename)); // Docbook backend - else if (isDocBook()) { + else if (params().isDocBook()) { runparams.nice = !put_in_tempdir; makeDocBookFile(FileName(filename), runparams); } @@ -3582,7 +3554,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, } string const error_type = (format == "program") - ? "Build" : bufferFormat(); + ? "Build" : params().bufferFormat(); ErrorList & error_list = d->errorLists[error_type]; string const ext = formats.extension(format); FileName const tmp_result_file(changeExtension(filename, ext)); @@ -3621,7 +3593,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, // FIXME: There is a possibility of concurrent access to texrow // here from the main GUI thread that should be securized. d->cloned_buffer_->d->texrow = d->texrow; - string const error_type = bufferFormat(); + string const error_type = params().bufferFormat(); d->cloned_buffer_->d->errorLists[error_type] = d->errorLists[error_type]; } @@ -3703,55 +3675,6 @@ bool Buffer::preview(string const & format, bool includeall) const } -bool Buffer::isExportable(string const & format) const -{ - vector backs = backends(); - for (vector::const_iterator it = backs.begin(); - it != backs.end(); ++it) - if (theConverters().isReachable(*it, format)) - return true; - return false; -} - - -vector Buffer::exportableFormats(bool only_viewable) const -{ - vector const backs = backends(); - set excludes; - if (params().useNonTeXFonts) { - excludes.insert("latex"); - excludes.insert("pdflatex"); - } - vector result = - theConverters().getReachable(backs[0], only_viewable, true, excludes); - for (vector::const_iterator it = backs.begin() + 1; - it != backs.end(); ++it) { - vector r = - theConverters().getReachable(*it, only_viewable, false, excludes); - result.insert(result.end(), r.begin(), r.end()); - } - return result; -} - - -vector Buffer::backends() const -{ - vector v; - v.push_back(bufferFormat()); - // FIXME: Don't hardcode format names here, but use a flag - if (v.back() == "latex") { - v.push_back("pdflatex"); - v.push_back("luatex"); - v.push_back("xetex"); - } else if (v.back() == "xetex") - v.push_back("luatex"); - v.push_back("xhtml"); - v.push_back("text"); - v.push_back("lyx"); - return v; -} - - Buffer::ReadStatus Buffer::extractFromVC() { bool const found = LyXVC::file_not_found_hook(d->filename); @@ -4011,6 +3934,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const return; d->bibinfo_cache_valid_ = true; + d->cite_labels_valid_ = true; cbuf.tocBackend().update(); if (scope == UpdateMaster) cbuf.structureChanged(); @@ -4106,10 +4030,12 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const // Compute the item depth of the paragraph par.itemdepth = getItemDepth(it); - if (layout.margintype == MARGIN_MANUAL - || layout.latextype == LATEX_BIB_ENVIRONMENT) { + if (layout.margintype == MARGIN_MANUAL) { if (par.params().labelWidthString().empty()) par.params().labelWidthString(par.expandLabel(layout, bp)); + } else if (layout.latextype == LATEX_BIB_ENVIRONMENT) { + // we do not need to do anything here, since the empty case is + // handled during export. } else { par.params().labelWidthString(docstring()); }