X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=9ec20e0fbbcb09b24277260cb8e453a4767dd89c;hb=3561caa3a171a5984ee7a10b7ea82f7f4b7226e8;hp=84b5e6ced529dd6d6d1c87379490d9eb4664bac2;hpb=3db74fa92d9acd784b271b01c473f69c36311777;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 84b5e6ced5..9ec20e0fbb 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -55,6 +55,7 @@ #include "ParagraphParameters.h" #include "ParIterator.h" #include "PDFOptions.h" +#include "Session.h" #include "SpellChecker.h" #include "sgml.h" #include "texstream.h" @@ -76,7 +77,7 @@ #include "mathed/InsetMathHull.h" #include "mathed/MacroTable.h" -#include "mathed/MathMacroTemplate.h" +#include "mathed/InsetMathMacroTemplate.h" #include "mathed/MathSupport.h" #include "graphics/GraphicsCache.h" @@ -136,7 +137,7 @@ int const LYX_FORMAT = LYX_FORMAT_LYX; typedef map DepClean; typedef map > RefCache; -} // namespace anon +} // namespace // A storehouse for the cloned buffers. @@ -379,14 +380,11 @@ public: // Make sure the file monitor monitors the good file. void refreshFileMonitor(); - /// has it been notified of an external modification? - bool isExternallyModified() const { return externally_modified_; } - /// Notify or clear of external modification - void fileExternallyModified(bool modified) const; + void fileExternallyModified(bool exists); - /// Block notifications of external modifications - FileMonitorBlocker blockFileMonitor() { return file_monitor_->block(10); } + /// has been externally modified? Can be reset by the user. + mutable bool externally_modified_; private: /// So we can force access via the accessors. @@ -396,9 +394,6 @@ private: int char_count_; int blank_count_; - /// has been externally modified? Can be reset by the user. - mutable bool externally_modified_; - FileMonitorPtr file_monitor_; }; @@ -440,9 +435,8 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_, bibfile_cache_valid_(false), cite_labels_valid_(false), preview_error_(false), inset(0), preview_loader_(0), cloned_buffer_(cloned_buffer), clone_list_(0), doing_export(false), - tracked_changes_present_(0), parent_buffer(0), - word_count_(0), char_count_(0), blank_count_(0), - externally_modified_(false) + tracked_changes_present_(0), externally_modified_(false), parent_buffer(0), + word_count_(0), char_count_(0), blank_count_(0) { refreshFileMonitor(); if (!cloned_buffer_) { @@ -543,17 +537,21 @@ Buffer::~Buffer() Impl::BufferPositionMap::iterator end = d->children_positions.end(); for (; it != end; ++it) { Buffer * child = const_cast(it->first); - if (theBufferList().isLoaded(child)) { - if (theBufferList().isOthersChild(this, child)) - child->setParent(0); - else - theBufferList().release(child); + if (theBufferList().isLoaded(child)) { + if (theBufferList().isOthersChild(this, child)) + child->setParent(0); + else + theBufferList().release(child); } } if (!isClean()) { docstring msg = _("LyX attempted to close a document that had unsaved changes!\n"); - msg += emergencyWrite(); + try { + msg += emergencyWrite(); + } catch (...) { + msg += " " + _("Save failed! Document is lost."); + } Alert::warning(_("Attempting to close changed document!"), msg); } @@ -725,7 +723,7 @@ BufferParams const & Buffer::masterParams() const double Buffer::fontScalingFactor() const { return isExporting() ? 75.0 * params().html_math_img_scale - : 0.01 * lyxrc.dpi * lyxrc.zoom * lyxrc.preview_scale_factor * params().display_pixel_ratio; + : 0.01 * lyxrc.dpi * lyxrc.currentZoom * lyxrc.preview_scale_factor * params().display_pixel_ratio; } @@ -834,7 +832,7 @@ string Buffer::logName(LogType * type) const FileName const bname( addName(path, onlyFileName( changeExtension(filename, - formats.extension(params().bufferFormat()) + ".out")))); + theFormats().extension(params().bufferFormat()) + ".out")))); // Also consider the master buffer log file FileName masterfname = fname; @@ -983,6 +981,8 @@ int Buffer::readHeader(Lexer & lex) errorList.push_back(ErrorItem(_("Document header error"), s)); } + params().shell_escape = theSession().shellescapeFiles().find(absFileName()); + params().makeDocumentClass(); return unknown_tokens; @@ -1085,7 +1085,7 @@ bool Buffer::readDocument(Lexer & lex) bool Buffer::importString(string const & format, docstring const & contents, ErrorList & errorList) { - Format const * fmt = formats.getFormat(format); + Format const * fmt = theFormats().getFormat(format); if (!fmt) return false; // It is important to use the correct extension here, since some @@ -1199,7 +1199,7 @@ Buffer::ReadStatus Buffer::readFile(FileName const & fn) d->file_fully_loaded = true; d->read_only = !d->filename.isWritable(); - params().compressed = formats.isZippedFile(d->filename); + params().compressed = theFormats().isZippedFile(d->filename); saveCheckSum(); return ReadSuccess; } @@ -1313,7 +1313,7 @@ Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn, command << os::python() << ' ' << quoteName(lyx2lyx.toFilesystemEncoding()) << " -t " << convert(LYX_FORMAT) - << " -o " << quoteName(tmpfile.toFilesystemEncoding()) + << " -o " << quoteName(tmpfile.toSafeFilesystemEncoding()) << ' ' << quoteName(fn.toSafeFilesystemEncoding()); string const command_str = command.str(); @@ -1379,7 +1379,6 @@ FileName Buffer::getBackupName() const { // Should probably be moved to somewhere else: BufferView? GuiView? bool Buffer::save() const { - FileMonitorBlocker block = d->blockFileMonitor(); docstring const file = makeDisplayPath(absFileName(), 20); d->filename.refresh(); @@ -1606,7 +1605,7 @@ docstring Buffer::emergencyWrite() return user_message; } - user_message += " " + _("Save failed! Bummer. Document is lost."); + user_message += " " + _("Save failed! Document is lost."); // Don't try again. markClean(); return user_message; @@ -1938,7 +1937,7 @@ void Buffer::writeLaTeXSource(otexstream & os, support::bformat(_("The languages %1$s are only supported by Polyglossia."), langs) : support::bformat(_("The language %1$s is only supported by Polyglossia."), langs); if (!blangs.empty()) - plangs += "\n"; + plangs += "\n"; } frontend::Alert::warning( @@ -2447,15 +2446,16 @@ void Buffer::reloadBibInfoCache() const return; d->bibinfo_.clear(); - collectBibKeys(); + FileNameList checkedFiles; + collectBibKeys(checkedFiles); d->bibinfo_cache_valid_ = true; } -void Buffer::collectBibKeys() const +void Buffer::collectBibKeys(FileNameList & checkedFiles) const { for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) - it->collectBibKeys(it); + it->collectBibKeys(it, checkedFiles); } @@ -2689,7 +2689,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) case LFUN_BUFFER_EXPORT_CUSTOM: { string format_name; string command = split(argument, format_name, ' '); - Format const * format = formats.getFormat(format_name); + Format const * format = theFormats().getFormat(format_name); if (!format) { lyxerr << "Format \"" << format_name << "\" not recognized!" @@ -2848,7 +2848,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) } case LFUN_BUFFER_VIEW_CACHE: - if (!formats.view(*this, d->preview_file_, + if (!theFormats().view(*this, d->preview_file_, d->preview_format_)) dr.setMessage(_("Error viewing the output file.")); break; @@ -3602,7 +3602,7 @@ void Buffer::Impl::updateMacros(DocIterator & it, DocIterator & scope) continue; // get macro data - MathMacroTemplate & macroTemplate = + InsetMathMacroTemplate & macroTemplate = *iit->inset->asInsetMath()->asMacroTemplate(); MacroContext mc(owner_, it); macroTemplate.updateToContext(mc); @@ -3721,8 +3721,12 @@ void Buffer::listMacroNames(MacroNameSet & macros) const // loop over children Impl::BufferPositionMap::iterator it = d->children_positions.begin(); Impl::BufferPositionMap::iterator end = d->children_positions.end(); - for (; it != end; ++it) - it->first->listMacroNames(macros); + for (; it != end; ++it) { + Buffer * child = const_cast(it->first); + // The buffer might have been closed (see #10766). + if (theBufferList().isLoaded(child)) + child->listMacroNames(macros); + } // call parent Buffer const * const pbuf = d->parent(); @@ -3752,7 +3756,7 @@ void Buffer::listParentMacros(MacroSet & macros, LaTeXFeatures & features) const if (data) { macros.insert(data); - // we cannot access the original MathMacroTemplate anymore + // we cannot access the original InsetMathMacroTemplate anymore // here to calls validate method. So we do its work here manually. // FIXME: somehow make the template accessible here. if (data->optionals() > 0) @@ -3945,6 +3949,7 @@ unique_ptr Buffer::getSourceCode(odocstream & os, string const & format, ots.texrow().newlines(2); if (master) runparams.is_child = true; + updateBuffer(); writeLaTeXSource(ots, string(), runparams, output); texrow = ots.releaseTexRow(); } @@ -4103,7 +4108,7 @@ int AutoSaveBuffer::generateChild() return pid; } -} // namespace anon +} // namespace FileName Buffer::getEmergencyFileName() const @@ -4281,7 +4286,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir // file (not for previewing). Alert::error(_("Couldn't export file"), bformat( _("No information for exporting the format %1$s."), - formats.prettyName(format))); + theFormats().prettyName(format))); } return ExportNoPathToFormat; } @@ -4311,7 +4316,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir string filename = latexName(false); filename = addName(temppath(), filename); filename = changeExtension(filename, - formats.extension(backend_format)); + theFormats().extension(backend_format)); LYXERR(Debug::FILES, "filename=" << filename); // Plain text backend @@ -4357,7 +4362,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir string const error_type = (format == "program") ? "Build" : params().bufferFormat(); ErrorList & error_list = d->errorLists[error_type]; - string const ext = formats.extension(format); + string const ext = theFormats().extension(format); FileName const tmp_result_file(changeExtension(filename, ext)); bool const success = converters.convert(this, FileName(filename), tmp_result_file, FileName(absFileName()), backend_format, format, @@ -4425,7 +4430,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir vector::const_iterator it = files.begin(); vector::const_iterator const en = files.end(); for (; it != en && status != CANCEL; ++it) { - string const fmt = formats.getFormatFromFile(it->sourceName); + string const fmt = theFormats().getFormatFromFile(it->sourceName); string fixedName = it->exportName; if (!runparams.export_folder.empty()) { // Relative pathnames starting with ../ will be sanitized @@ -4461,13 +4466,13 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir } else { message(bformat(_("Document exported as %1$s " "to file `%2$s'"), - formats.prettyName(format), + theFormats().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))); + theFormats().prettyName(format))); } return success ? ExportSuccess : ExportConverterError; @@ -4506,7 +4511,7 @@ Buffer::ExportStatus Buffer::preview(string const & format, bool includeall) con return status; if (previewFile.exists()) - return formats.view(*this, previewFile, format) ? + return theFormats().view(*this, previewFile, format) ? PreviewSuccess : PreviewError; // Successful export but no output file? @@ -4758,16 +4763,17 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const ParIterator parit = cbuf.par_iterator_begin(); updateBuffer(parit, utype); - /// FIXME: Perf - /// Update the tocBackend for any buffer. The outliner uses the master's, - /// and the navigation menu uses the child's. - cbuf.tocBackend().update(true, utype); - if (master != this) + // If this document has siblings, then update the TocBackend later. The + // reason is to ensure that later siblings are up to date when e.g. the + // broken or not status of references is computed. The update is called + // in InsetInclude::addToToc. return; d->bibinfo_cache_valid_ = true; d->cite_labels_valid_ = true; + /// FIXME: Perf + cbuf.tocBackend().update(true, utype); if (scope == UpdateMaster) cbuf.structureChanged(); } @@ -4911,8 +4917,10 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const switch (par.itemdepth) { case 2: enumcounter += 'i'; + // fall through case 1: enumcounter += 'i'; + // fall through case 0: enumcounter += 'i'; break; @@ -5025,7 +5033,7 @@ void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const // set the counter for this paragraph d->setLabel(parit, utype); - // update change-tracking flag + // update change-tracking flag parit->addChangesToBuffer(*this); // now the insets @@ -5318,38 +5326,57 @@ void Buffer::updateChangesPresent() const void Buffer::Impl::refreshFileMonitor() { - if (file_monitor_ && file_monitor_->filename() == filename.absFileName()) - return file_monitor_->refresh(); + if (file_monitor_ && file_monitor_->filename() == filename.absFileName()) { + file_monitor_->refresh(); + return; + } // The previous file monitor is invalid // This also destroys the previous file monitor and all its connections file_monitor_ = FileSystemWatcher::monitor(filename); - fileExternallyModified(false); // file_monitor_ will be destroyed with *this, so it is not going to call a // destroyed object method. - file_monitor_->connect([this](){ fileExternallyModified(true); }); + file_monitor_->connect([this](bool exists) { + fileExternallyModified(exists); + }); } -void Buffer::Impl::fileExternallyModified(bool modified) const +void Buffer::Impl::fileExternallyModified(bool const exists) { - if (modified) - lyx_clean = bak_clean = false; - externally_modified_ = modified; - if (wa_) + // ignore notifications after our own saving operations + if (checksum_ == filename.checksum()) { + LYXERR(Debug::FILES, "External modification but " + "checksum unchanged: " << filename); + return; + } + lyx_clean = bak_clean = false; + // If the file has been deleted, only mark the file as dirty since it is + // pointless to prompt for reloading. If later a file is moved into this + // location, then the externally modified warning will appear then. + if (exists) + externally_modified_ = true; + // Update external modification notification. + // Dirty buffers must be visible at all times. + if (wa_ && wa_->unhide(owner_)) wa_->updateTitles(); + else + // Unable to unhide the buffer (e.g. no GUI or not current View) + lyx_clean = true; } bool Buffer::notifiesExternalModification() const { - return d->isExternallyModified(); + return d->externally_modified_; } void Buffer::clearExternalModification() const { - d->fileExternallyModified(false); + d->externally_modified_ = false; + if (d->wa_) + d->wa_->updateTitles(); }