X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=5e9972138cb09dce281f4ccf29087e79fadbfcc1;hb=e54ae72e5fac6f750c3f7972c74bb42b57f3a049;hp=d4f1f9d77d408ec75ac1eed3e57fa251cb7f853b;hpb=5e6391a04ad9a3949dbe0003160ce09b296940d9;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index d4f1f9d77d..5e9972138c 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -47,6 +47,7 @@ #include "ParIterator.h" #include "sgml.h" #include "TexRow.h" +#include "TexStream.h" #include "TocBackend.h" #include "Undo.h" #include "version.h" @@ -68,30 +69,38 @@ #include "support/lyxalgo.h" #include "support/filetools.h" #include "support/fs_extras.h" +#include "support/gzstream.h" #include "support/lyxlib.h" #include "support/os.h" #include "support/Path.h" #include "support/textutils.h" #include "support/convert.h" -#include -#include -#include #include #include #include -#if defined (HAVE_UTIME_H) -#include -#elif defined (HAVE_SYS_UTIME_H) -#include -#endif - +#include #include #include #include #include +using std::endl; +using std::for_each; +using std::make_pair; + +using std::ios; +using std::map; +using std::ostream; +using std::ostringstream; +using std::ofstream; +using std::pair; +using std::stack; +using std::vector; +using std::string; +using std::time_t; + namespace lyx { @@ -119,30 +128,15 @@ using support::split; using support::subst; using support::tempName; using support::trim; +using support::sum; namespace Alert = frontend::Alert; namespace os = support::os; namespace fs = boost::filesystem; -namespace io = boost::iostreams; - -using std::endl; -using std::for_each; -using std::make_pair; - -using std::ios; -using std::map; -using std::ostream; -using std::ostringstream; -using std::ofstream; -using std::pair; -using std::stack; -using std::vector; -using std::string; - namespace { -int const LYX_FORMAT = 271; +int const LYX_FORMAT = 278; } // namespace anon @@ -193,13 +187,21 @@ public: /// TocBackend toc_backend; + + /// Container for all sort of Buffer dependant errors. + map errorLists; + + /// timestamp and checksum used to test if the file has been externally + /// modified. (Used to properly enable 'File->Revert to saved', bug 4114). + time_t timestamp_; + unsigned long checksum_; }; Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_) : lyx_clean(true), bak_clean(true), unnamed(false), read_only(readonly_), filename(file), file_fully_loaded(false), inset(params), - toc_backend(&parent) + toc_backend(&parent), timestamp_(0), checksum_(0) { inset.setAutoBreakRows(true); lyxvc.buffer(&parent); @@ -433,7 +435,7 @@ int Buffer::readHeader(Lexer & lex) params().temp_bullet(i) = ITEMIZE_DEFAULTS[i]; } - ErrorList & errorList = errorLists_["Parse"]; + ErrorList & errorList = pimpl_->errorLists["Parse"]; while (lex.isOK()) { lex.next(); @@ -484,7 +486,7 @@ int Buffer::readHeader(Lexer & lex) // Returns false if "\end_document" is not read (Asger) bool Buffer::readDocument(Lexer & lex) { - ErrorList & errorList = errorLists_["Parse"]; + ErrorList & errorList = pimpl_->errorLists["Parse"]; errorList.clear(); lex.next(); @@ -510,20 +512,20 @@ bool Buffer::readDocument(Lexer & lex) if (params().outputChanges) { bool dvipost = LaTeXFeatures::isAvailable("dvipost"); bool xcolorsoul = LaTeXFeatures::isAvailable("soul") && - LaTeXFeatures::isAvailable("xcolor"); - + LaTeXFeatures::isAvailable("xcolor"); + if (!dvipost && !xcolorsoul) { Alert::warning(_("Changes not shown in LaTeX output"), - _("Changes will not be highlighted in LaTeX output, " - "because neither dvipost nor xcolor/soul are installed.\n" - "Please install these packages or redefine " - "\\lyxadded and \\lyxdeleted in the LaTeX preamble.")); + _("Changes will not be highlighted in LaTeX output, " + "because neither dvipost nor xcolor/soul are installed.\n" + "Please install these packages or redefine " + "\\lyxadded and \\lyxdeleted in the LaTeX preamble.")); } else if (!xcolorsoul) { Alert::warning(_("Changes not shown in LaTeX output"), - _("Changes will not be highlighted in LaTeX output " - "when using pdflatex, because xcolor and soul are not installed.\n" - "Please install both packages or redefine " - "\\lyxadded and \\lyxdeleted in the LaTeX preamble.")); + _("Changes will not be highlighted in LaTeX output " + "when using pdflatex, because xcolor and soul are not installed.\n" + "Please install both packages or redefine " + "\\lyxadded and \\lyxdeleted in the LaTeX preamble.")); } } @@ -718,10 +720,10 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename, } ostringstream command; command << os::python() - << ' ' << quoteName(lyx2lyx.toFilesystemEncoding()) - << " -t " << convert(LYX_FORMAT) - << " -o " << quoteName(tmpfile.toFilesystemEncoding()) - << ' ' << quoteName(filename.toFilesystemEncoding()); + << ' ' << quoteName(lyx2lyx.toFilesystemEncoding()) + << " -t " << convert(LYX_FORMAT) + << " -o " << quoteName(tmpfile.toFilesystemEncoding()) + << ' ' << quoteName(filename.toFilesystemEncoding()); string const command_str = command.str(); LYXERR(Debug::INFO) << "Running '" @@ -756,6 +758,9 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename, //MacroTable::localMacros().clear(); pimpl_->file_fully_loaded = true; + // save the timestamp and checksum of disk file + pimpl_->timestamp_ = fs::last_write_time(filename.toFilesystemEncoding()); + pimpl_->checksum_ = sum(filename); return success; } @@ -776,23 +781,36 @@ bool Buffer::save() const backupName = FileName(fileName() + '~'); if (!lyxrc.backupdir_path.empty()) backupName = FileName(addName(lyxrc.backupdir_path, - subst(os::internal_path(backupName.absFilename()), '/', '!'))); + subst(os::internal_path(backupName.absFilename()), '/', '!'))); try { fs::copy_file(encodedFilename, backupName.toFilesystemEncoding(), false); madeBackup = true; } catch (fs::filesystem_error const & fe) { Alert::error(_("Backup failure"), - bformat(_("Cannot create backup file %1$s.\n" - "Please check whether the directory exists and is writeable."), - from_utf8(backupName.absFilename()))); + bformat(_("Cannot create backup file %1$s.\n" + "Please check whether the directory exists and is writeable."), + from_utf8(backupName.absFilename()))); LYXERR(Debug::DEBUG) << "Fs error: " << fe.what() << endl; } } + // ask if the disk file has been externally modified (use checksum method) + if (fs::exists(encodedFilename) && isExternallyModified(checksum_method)) { + docstring const file = makeDisplayPath(fileName(), 20); + docstring text = bformat(_("Document %1$s has been externally modified. Are you sure " + "you want to overwrite this file?"), file); + int const ret = Alert::prompt(_("Overwrite modified file?"), + text, 1, 1, _("&Overwrite"), _("&Cancel")); + if (ret == 1) + return false; + } + if (writeFile(pimpl_->filename)) { markClean(); removeAutosaveFile(fileName()); + pimpl_->timestamp_ = fs::last_write_time(pimpl_->filename.toFilesystemEncoding()); + pimpl_->checksum_ = sum(pimpl_->filename); return true; } else { // Saving failed, so backup is not backup @@ -811,7 +829,7 @@ bool Buffer::writeFile(FileName const & fname) const bool retval = false; if (params().compressed) { - io::filtering_ostream ofs(io::gzip_compressor() | io::file_sink(fname.toFilesystemEncoding())); + gz::ogzstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc); if (!ofs) return false; @@ -843,6 +861,19 @@ 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(); + AuthorList::Authors::const_iterator a_end = params().authors().end(); + for (; a_it != a_end; ++a_it) + a_it->second.used(false); + + ParIterator const end = par_iterator_end(); + ParIterator it = par_iterator_begin(); + for ( ; it != end; ++it) + it->checkAuthors(params().authors()); + // now write out the buffer parameters. ofs << "\\begin_header\n"; params().writeFile(ofs); @@ -890,6 +921,8 @@ bool Buffer::makeLaTeXFile(FileName const & fname, if (!openFileWrite(ofs, fname)) return false; + //TexStream ts(ofs.rdbuf(), &texrow()); + bool failed_export = false; try { writeLaTeXSource(ofs, original_path, @@ -899,7 +932,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname, lyxerr << "Caught iconv exception: " << e.what() << endl; failed_export = true; } - catch (std::exception const & e) { + catch (std::exception const & e) { lyxerr << "Caught \"normal\" exception: " << e.what() << endl; failed_export = true; } @@ -1000,8 +1033,8 @@ void Buffer::writeLaTeXSource(odocstream & os, !params().language->babel().empty()) { // FIXME UNICODE os << from_utf8(subst(lyxrc.language_command_begin, - "$$lang", - params().language->babel())) + "$$lang", + params().language->babel())) << '\n'; texrow().newline(); } @@ -1047,8 +1080,8 @@ void Buffer::writeLaTeXSource(odocstream & os, if (!lyxrc.language_auto_end && !params().language->babel().empty()) { os << from_utf8(subst(lyxrc.language_command_end, - "$$lang", - params().language->babel())) + "$$lang", + params().language->babel())) << '\n'; texrow().newline(); } @@ -1098,7 +1131,7 @@ void Buffer::makeDocBookFile(FileName const & fname, LYXERR(Debug::LATEX) << "makeDocBookFile..." << endl; //ofstream ofs; - odocfstream ofs; + odocfstream ofs; if (!openFileWrite(ofs, fname)) return; @@ -1126,12 +1159,12 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, if (runparams.flavor == OutputParams::XML) os << "\n"; - // FIXME UNICODE + // FIXME UNICODE os << "\n\n"; } @@ -1211,7 +1244,7 @@ int Buffer::runChktex() Alert::error(_("chktex failure"), _("Could not run chktex successfully.")); } else if (res > 0) { - ErrorList & errorList = errorLists_["ChkTeX"]; + ErrorList & errorList = pimpl_->errorLists["ChkTeX"]; // Clear out old errors errorList.clear(); // Fill-in the error list with the TeX errors @@ -1233,9 +1266,9 @@ void Buffer::validate(LaTeXFeatures & features) const if (params().outputChanges) { bool dvipost = LaTeXFeatures::isAvailable("dvipost"); bool xcolorsoul = LaTeXFeatures::isAvailable("soul") && - LaTeXFeatures::isAvailable("xcolor"); - - if (features.runparams().flavor == OutputParams::LATEX) { + LaTeXFeatures::isAvailable("xcolor"); + + if (features.runparams().flavor == OutputParams::LATEX) { if (dvipost) { features.require("ct-dvipost"); features.require("dvipost"); @@ -1243,7 +1276,7 @@ void Buffer::validate(LaTeXFeatures & features) const features.require("ct-xcolor-soul"); features.require("soul"); features.require("xcolor"); - } else { + } else { features.require("ct-none"); } } else if (features.runparams().flavor == OutputParams::PDFLATEX ) { @@ -1255,7 +1288,7 @@ void Buffer::validate(LaTeXFeatures & features) const } else { features.require("ct-none"); } - } + } } // AMS Style is at document level @@ -1544,6 +1577,16 @@ bool Buffer::isBakClean() const } +bool Buffer::isExternallyModified(CheckMethod method) const +{ + BOOST_ASSERT(fs::exists(pimpl_->filename.toFilesystemEncoding())); + // if method == timestamp, check timestamp before checksum + return (method == checksum_method + || pimpl_->timestamp_ != fs::last_write_time(pimpl_->filename.toFilesystemEncoding())) + && pimpl_->checksum_ != sum(pimpl_->filename); +} + + void Buffer::markClean() const { if (!pimpl_->lyx_clean) { @@ -1574,9 +1617,7 @@ bool Buffer::isUnnamed() const } -#ifdef WITH_WARNINGS -#warning this function should be moved to buffer_pimpl.C -#endif +// FIXME: this function should be moved to buffer_pimpl.C void Buffer::markDirty() { if (pimpl_->lyx_clean) { @@ -1613,7 +1654,11 @@ bool Buffer::isReadonly() const void Buffer::setParentName(string const & name) { - params().parentname = name; + if (name == pimpl_->filename.absFilename()) + // Avoids recursive include. + params().parentname.clear(); + else + params().parentname = name; } @@ -1717,7 +1762,7 @@ void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to, } else getLabelList(labels); - if (lyx::count(labels.begin(), labels.end(), from) > 1) + if (std::count(labels.begin(), labels.end(), from) > 1) return; for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { @@ -1751,7 +1796,7 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, runparams.par_end = par_end; if (par_begin + 1 == par_end) os << "% " - << bformat(_("Preview source code for paragraph %1$s"), par_begin) + << bformat(_("Preview source code for paragraph %1$d"), par_begin) << "\n\n"; else os << "% " @@ -1774,8 +1819,8 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, ErrorList const & Buffer::errorList(string const & type) const { static ErrorList const emptyErrorList; - std::map::const_iterator I = errorLists_.find(type); - if (I == errorLists_.end()) + std::map::const_iterator I = pimpl_->errorLists.find(type); + if (I == pimpl_->errorLists.end()) return emptyErrorList; return I->second; @@ -1784,7 +1829,7 @@ ErrorList const & Buffer::errorList(string const & type) const ErrorList & Buffer::errorList(string const & type) { - return errorLists_[type]; + return pimpl_->errorLists[type]; }