X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=d2eff530f835197ca76ef1481d0c3e2f9177c98c;hb=c20e885331c9bba720e386985d0e7bcdb5bf8b9c;hp=f008f3f90cbadff053ec92155009901a13e195b2;hpb=375db69d9919c1e4d46ab864518f516c787403ad;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index f008f3f90c..d2eff530f8 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -66,7 +66,6 @@ #include "WordLangTuple.h" #include "WordList.h" -#include "insets/InsetBibitem.h" #include "insets/InsetBibtex.h" #include "insets/InsetBranch.h" #include "insets/InsetInclude.h" @@ -128,7 +127,7 @@ namespace { // Do not remove the comment below, so we get merge conflict in // independent branches. Instead add your own. -int const LYX_FORMAT = 404; // rgh: refstyle +int const LYX_FORMAT = 413; // rgh: html_css_as_file typedef map DepClean; typedef map > RefCache; @@ -189,7 +188,7 @@ public: /// is autosave needed? mutable bool bak_clean; - /// is this a unnamed file (New...)? + /// is this an unnamed file (New...)? bool unnamed; /// buffer is r/o @@ -414,9 +413,8 @@ Buffer::~Buffer() from_utf8(d->temppath.absFileName()))); } - // Remove any previewed LaTeX snippets associated with this buffer. if (!isClone()) - thePreviews().removeLoader(*this); + removePreviews(); delete d; } @@ -643,10 +641,11 @@ void Buffer::setReadonly(bool const flag) } -void Buffer::setFileName(string const & newfile) +void Buffer::setFileName(FileName const & fname) { - d->filename = makeAbsPath(newfile); + d->filename = fname; setReadonly(d->filename.isReadOnly()); + saveCheckSum(); updateTitles(); } @@ -673,7 +672,7 @@ int Buffer::readHeader(Lexer & lex) params().headsep.erase(); params().footskip.erase(); params().columnsep.erase(); - params().fontsCJK.erase(); + params().fonts_cjk.erase(); params().listings_params.clear(); params().clearLayoutModules(); params().clearRemovedModules(); @@ -754,15 +753,15 @@ bool Buffer::readDocument(Lexer & lex) ErrorList & errorList = d->errorLists["Parse"]; errorList.clear(); + // remove dummy empty par + paragraphs().clear(); + if (!lex.checkFor("\\begin_document")) { docstring const s = _("\\begin_document is missing"); errorList.push_back(ErrorItem(_("Document header error"), s, -1, 0, 0)); } - // we are reading in a brand new document - LASSERT(paragraphs().empty(), /**/); - readHeader(lex); if (params().outputChanges) { @@ -821,6 +820,14 @@ bool Buffer::readDocument(Lexer & lex) // read main text bool const res = text().read(lex, errorList, d->inset); + // inform parent buffer about local macros + if (parent()) { + Buffer const * pbuf = parent(); + UserMacroSet::const_iterator cit = usermacros.begin(); + UserMacroSet::const_iterator end = usermacros.end(); + for (; cit != end; ++cit) + pbuf->usermacros.insert(*cit); + } usermacros.clear(); updateMacros(); updateMacroInstances(); @@ -832,46 +839,67 @@ bool Buffer::readString(string const & s) { params().compressed = false; - // remove dummy empty par - paragraphs().clear(); Lexer lex; istringstream is(s); lex.setStream(is); - FileName const name = FileName::tempName("Buffer_readString"); - switch (readFile(lex, name, true)) { - case ReadFailure: - return false; + FileName const fn = FileName::tempName("Buffer_readString"); - case ReadWrongVersion: { + int file_format; + ReadStatus const ret_plf = parseLyXFormat(lex, fn, file_format); + if (ret_plf != ReadSuccess) + return ret_plf; + + if (file_format != LYX_FORMAT) { // We need to call lyx2lyx, so write the input to a file - ofstream os(name.toFilesystemEncoding().c_str()); + ofstream os(fn.toFilesystemEncoding().c_str()); os << s; os.close(); - return readFile(name); - } - default: - break; + // lyxvc in readFile + return readFile(fn) == ReadSuccess; } + if (readDocument(lex)) + return false; return true; } -bool Buffer::readFile(FileName const & filename) +Buffer::ReadStatus Buffer::readFile(FileName const & fn) { - FileName fname(filename); - - params().compressed = fname.isZippedFile(); - - // remove dummy empty par - paragraphs().clear(); + FileName fname(fn); Lexer lex; lex.setFile(fname); - if (readFile(lex, fname) != ReadSuccess) - return false; - d->read_only = !fname.isWritable(); - return true; + int file_format; + ReadStatus const ret_plf = parseLyXFormat(lex, fn, file_format); + if (ret_plf != ReadSuccess) + return ret_plf; + + if (file_format != LYX_FORMAT) { + FileName tmpFile; + ReadStatus const ret_clf = convertLyXFormat(fn, tmpFile, file_format); + if (ret_clf != ReadSuccess) + return ret_clf; + return readFile(tmpFile); + } + + // FIXME: InsetInfo needs to know whether the file is under VCS + // during the parse process, so this has to be done before. + lyxvc().file_found_hook(d->filename); + + if (readDocument(lex)) { + Alert::error(_("Document format failure"), + bformat(_("%1$s ended unexpectedly, which means" + " that it is probably corrupted."), + from_utf8(fn.absFileName()))); + return ReadDocumentFailure; + } + + d->file_fully_loaded = true; + d->read_only = !d->filename.isWritable(); + params().compressed = d->filename.isZippedFile(); + saveCheckSum(); + return ReadSuccess; } @@ -887,111 +915,99 @@ void Buffer::setFullyLoaded(bool value) } -Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename, - bool fromstring) +void Buffer::updatePreviews() const +{ + if (graphics::Previews::status() != LyXRC::PREVIEW_OFF) + thePreviews().generateBufferPreviews(*this); +} + + +void Buffer::removePreviews() const { - LASSERT(!filename.empty(), /**/); + thePreviews().removeLoader(*this); +} + - // the first (non-comment) token _must_ be... - if (!lex.checkFor("\\lyxformat")) { +Buffer::ReadStatus Buffer::parseLyXFormat(Lexer & lex, + FileName const & fn, int & file_format) const +{ + if(!lex.checkFor("\\lyxformat")) { Alert::error(_("Document format failure"), - bformat(_("%1$s is not a readable LyX document."), - from_utf8(filename.absFileName()))); - return ReadFailure; - } + bformat(_("%1$s is not a readable LyX document."), + from_utf8(fn.absFileName()))); + return ReadNoLyXFormat; + } string tmp_format; lex >> tmp_format; - //lyxerr << "LyX Format: `" << tmp_format << '\'' << endl; - // if present remove ".," from string. + + // LyX formats 217 and earlier were written as 2.17. This corresponds + // to files from LyX versions < 1.1.6.3. We just remove the dot in + // these cases. See also: www.lyx.org/trac/changeset/1313. size_t dot = tmp_format.find_first_of(".,"); - //lyxerr << " dot found at " << dot << endl; if (dot != string::npos) - tmp_format.erase(dot, 1); - int const file_format = convert(tmp_format); - //lyxerr << "format: " << file_format << endl; - - // save timestamp and checksum of the original disk file, making sure - // to not overwrite them with those of the file created in the tempdir - // when it has to be converted to the current format. - if (!d->checksum_) { - // Save the timestamp and checksum of disk file. If filename is an - // emergency file, save the timestamp and checksum of the original lyx file - // because isExternallyModified will check for this file. (BUG4193) - string diskfile = filename.absFileName(); - if (suffixIs(diskfile, ".emergency")) - diskfile = diskfile.substr(0, diskfile.size() - 10); - saveCheckSum(FileName(diskfile)); - } + tmp_format.erase(dot, 1); - if (file_format != LYX_FORMAT) { + file_format = convert(tmp_format); + return ReadSuccess; +} - if (fromstring) - // lyx2lyx would fail - return ReadWrongVersion; - - FileName const tmpfile = FileName::tempName("Buffer_readFile"); - if (tmpfile.empty()) { - Alert::error(_("Conversion failed"), - bformat(_("%1$s is from a different" - " version of LyX, but a temporary" - " file for converting it could" - " not be created."), - from_utf8(filename.absFileName()))); - return ReadFailure; - } - FileName const lyx2lyx = libFileSearch("lyx2lyx", "lyx2lyx"); - if (lyx2lyx.empty()) { - Alert::error(_("Conversion script not found"), - bformat(_("%1$s is from a different" - " version of LyX, but the" - " conversion script lyx2lyx" - " could not be found."), - from_utf8(filename.absFileName()))); - return ReadFailure; - } - ostringstream command; - command << os::python() - << ' ' << quoteName(lyx2lyx.toFilesystemEncoding()) - << " -t " << convert(LYX_FORMAT) - << " -o " << quoteName(tmpfile.toFilesystemEncoding()) - << ' ' << quoteName(filename.toSafeFilesystemEncoding()); - string const command_str = command.str(); - - LYXERR(Debug::INFO, "Running '" << command_str << '\''); - - cmd_ret const ret = runCommand(command_str); - if (ret.first != 0) { - if (file_format < LYX_FORMAT) - Alert::error(_("Conversion script failed"), - bformat(_("%1$s is from an older version" - " of LyX, but the lyx2lyx script" - " failed to convert it."), - from_utf8(filename.absFileName()))); - else - Alert::error(_("Conversion script failed"), - bformat(_("%1$s is from a newer version" - " of LyX and cannot be converted by the" - " lyx2lyx script."), - from_utf8(filename.absFileName()))); - return ReadFailure; - } else { - bool const ret = readFile(tmpfile); - // Do stuff with tmpfile name and buffer name here. - return ret ? ReadSuccess : ReadFailure; - } +Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn, + FileName & tmpfile, int from_format) +{ + tmpfile = FileName::tempName("Buffer_convertLyXFormat"); + if(tmpfile.empty()) { + Alert::error(_("Conversion failed"), + bformat(_("%1$s is from a different" + " version of LyX, but a temporary" + " file for converting it could" + " not be created."), + from_utf8(fn.absFileName()))); + return LyX2LyXNoTempFile; } - if (readDocument(lex)) { - Alert::error(_("Document format failure"), - bformat(_("%1$s ended unexpectedly, which means" - " that it is probably corrupted."), - from_utf8(filename.absFileName()))); - return ReadFailure; + FileName const lyx2lyx = libFileSearch("lyx2lyx", "lyx2lyx"); + if (lyx2lyx.empty()) { + Alert::error(_("Conversion script not found"), + bformat(_("%1$s is from a different" + " version of LyX, but the" + " conversion script lyx2lyx" + " could not be found."), + from_utf8(fn.absFileName()))); + return LyX2LyXNotFound; } - d->file_fully_loaded = true; + // Run lyx2lyx: + // $python$ "$lyx2lyx$" -t $LYX_FORMAT$ -o "$tempfile$" "$filetoread$" + ostringstream command; + command << os::python() + << ' ' << quoteName(lyx2lyx.toFilesystemEncoding()) + << " -t " << convert(LYX_FORMAT) + << " -o " << quoteName(tmpfile.toFilesystemEncoding()) + << ' ' << quoteName(fn.toSafeFilesystemEncoding()); + string const command_str = command.str(); + + LYXERR(Debug::INFO, "Running '" << command_str << '\''); + + cmd_ret const ret = runCommand(command_str); + if (ret.first != 0) { + if (from_format < LYX_FORMAT) { + Alert::error(_("Conversion script failed"), + bformat(_("%1$s is from an older version" + " of LyX and the lyx2lyx script" + " failed to convert it."), + from_utf8(fn.absFileName()))); + return LyX2LyXOlderFormat; + } else { + Alert::error(_("Conversion script failed"), + bformat(_("%1$s is from a newer version" + " of LyX and the lyx2lyx script" + " failed to convert it."), + from_utf8(fn.absFileName()))); + return LyX2LyXNewerFormat; + } + } return ReadSuccess; } @@ -999,11 +1015,25 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename, // Should probably be moved to somewhere else: BufferView? GuiView? bool Buffer::save() const { + docstring const file = makeDisplayPath(absFileName(), 20); + d->filename.refresh(); + + // check the read-only status before moving the file as a backup + if (d->filename.exists()) { + bool const read_only = !d->filename.isWritable(); + if (read_only) { + Alert::warning(_("File is read-only"), + bformat(_("The file %1$s cannot be written because it " + "is marked as read-only."), file)); + return false; + } + } + // ask if the disk file has been externally modified (use checksum method) if (fileName().exists() && isExternallyModified(checksum_method)) { - docstring const file = makeDisplayPath(absFileName(), 20); - docstring text = bformat(_("Document %1$s has been externally modified. Are you sure " - "you want to overwrite this file?"), file); + 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) @@ -1025,13 +1055,18 @@ bool Buffer::save() const backupName = FileName(addName(lyxrc.backupdir_path, mangledName)); } - // do not copy because of #6587 - if (fileName().moveTo(backupName)) { - madeBackup = true; - } else { + + // Except file is symlink do not copy because of #6587. + // Hard links have bad luck. + if (fileName().isSymLink()) + madeBackup = fileName().copyTo(backupName); + else + madeBackup = fileName().moveTo(backupName); + + if (!madeBackup) { Alert::error(_("Backup failure"), bformat(_("Cannot create backup file %1$s.\n" - "Please check whether the directory exists and is writeable."), + "Please check whether the directory exists and is writable."), from_utf8(backupName.absFileName()))); //LYXERR(Debug::DEBUG, "Fs error: " << fe.what()); } @@ -1078,7 +1113,7 @@ bool Buffer::writeFile(FileName const & fname) const // see bug 6587 // removeAutosaveFile(); - saveCheckSum(d->filename); + saveCheckSum(); message(str + _(" done.")); return true; @@ -1104,10 +1139,10 @@ docstring Buffer::emergencyWrite() LYXERR0(" " << s); if (writeFile(FileName(s))) { markClean(); - user_message += bformat(_(" Saved to %1$s. Phew.\n"), from_utf8(s)); + user_message += " " + bformat(_("Saved to %1$s. Phew.\n"), from_utf8(s)); return user_message; } else { - user_message += _(" Save failed! Trying again...\n"); + user_message += " " + _("Save failed! Trying again...\n"); } } @@ -1117,11 +1152,11 @@ docstring Buffer::emergencyWrite() lyxerr << ' ' << s << endl; if (writeFile(FileName(s))) { markClean(); - user_message += bformat(_(" Saved to %1$s. Phew.\n"), from_utf8(s)); + user_message += " " + bformat(_("Saved to %1$s. Phew.\n"), from_utf8(s)); return user_message; } - user_message += _(" Save failed! Trying yet again...\n"); + user_message += " " + _("Save failed! Trying yet again...\n"); // 3) In "/tmp" directory. // MakeAbsPath to prepend the current @@ -1131,11 +1166,11 @@ docstring Buffer::emergencyWrite() lyxerr << ' ' << s << endl; if (writeFile(FileName(s))) { markClean(); - user_message += bformat(_(" Saved to %1$s. Phew.\n"), from_utf8(s)); + user_message += " " + bformat(_("Saved to %1$s. Phew.\n"), from_utf8(s)); return user_message; } - user_message += _(" Save failed! Bummer. Document is lost."); + user_message += " " + _("Save failed! Bummer. Document is lost."); // Don't try again. markClean(); return user_message; @@ -1152,7 +1187,7 @@ bool Buffer::write(ostream & ofs) const // The top of the file should not be written by params(). // write out a comment in the top of the file - ofs << "#LyX " << lyx_version + ofs << "#LyX " << lyx_version_major << "." << lyx_version_minor << " created this file. For more info see http://www.lyx.org/\n" << "\\lyxformat " << LYX_FORMAT << "\n" << "\\begin_document\n"; @@ -1209,8 +1244,11 @@ bool Buffer::makeLaTeXFile(FileName const & fname, bool output_preamble, bool output_body) const { OutputParams runparams = runparams_in; - if (params().useXetex) - runparams.flavor = OutputParams::XETEX; + + // This is necessary for LuaTeX/XeTeX with tex fonts. + // See FIXME in BufferParams::encoding() + if (runparams.isFullUnicode()) + runparams.encoding = encodings.fromLyXName("utf8-plain"); string const encoding = runparams.encoding->iconvName(); LYXERR(Debug::LATEX, "makeLaTeXFile encoding: " << encoding << "..."); @@ -1231,9 +1269,10 @@ bool Buffer::makeLaTeXFile(FileName const & fname, ErrorList & errorList = d->errorLists["Export"]; errorList.clear(); bool failed_export = false; + otexstream os(ofs, d->texrow); try { - d->texrow.reset(); - writeLaTeXSource(ofs, original_path, + os.texrow().reset(); + writeLaTeXSource(os, original_path, runparams, output_preamble, output_body); } catch (EncodingException & e) { @@ -1276,7 +1315,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname, } -void Buffer::writeLaTeXSource(odocstream & os, +void Buffer::writeLaTeXSource(otexstream & os, string const & original_path, OutputParams const & runparams_in, bool const output_preamble, bool const output_body) const @@ -1301,8 +1340,6 @@ void Buffer::writeLaTeXSource(odocstream & os, "For more info, see http://www.lyx.org/.\n" "%% Do not edit unless you really know what " "you are doing.\n"; - d->texrow.newline(); - d->texrow.newline(); } LYXERR(Debug::INFO, "lyx document header finished"); @@ -1328,9 +1365,7 @@ void Buffer::writeLaTeXSource(odocstream & os, if (output_preamble) { if (!runparams.nice) { // code for usual, NOT nice-latex-file - os << "\\batchmode\n"; // changed - // from \nonstopmode - d->texrow.newline(); + os << "\\batchmode\n"; // changed from \nonstopmode } if (!original_path.empty()) { // FIXME UNICODE @@ -1366,9 +1401,6 @@ void Buffer::writeLaTeXSource(odocstream & os, << "\\def\\input@path{{" << inputpath << "/}}\n" << "\\makeatother\n"; - d->texrow.newline(); - d->texrow.newline(); - d->texrow.newline(); } } @@ -1377,9 +1409,9 @@ void Buffer::writeLaTeXSource(odocstream & os, MacroSet parentMacros; listParentMacros(parentMacros, features); + runparams.use_polyglossia = features.usePolyglossia(); // Write the preamble runparams.use_babel = params().writeLaTeX(os, features, - d->texrow, d->filename.onlyPath()); runparams.use_japanese = features.isRequired("japanese"); @@ -1389,19 +1421,18 @@ void Buffer::writeLaTeXSource(odocstream & os, // make the body. os << "\\begin{document}\n"; - d->texrow.newline(); // output the parent macros MacroSet::iterator it = parentMacros.begin(); MacroSet::iterator end = parentMacros.end(); for (; it != end; ++it) { - int num_lines = (*it)->write(os, true); - d->texrow.newlines(num_lines); + int num_lines = (*it)->write(os.os(), true); + os.texrow().newlines(num_lines); } } // output_preamble - d->texrow.start(paragraphs().begin()->id(), 0); + os.texrow().start(paragraphs().begin()->id(), 0); LYXERR(Debug::INFO, "preamble finished, now the body."); @@ -1415,7 +1446,7 @@ void Buffer::writeLaTeXSource(odocstream & os, } // the real stuff - latexParagraphs(*this, text(), os, d->texrow, runparams); + latexParagraphs(*this, text(), os, runparams); // Restore the parenthood if needed if (output_preamble) @@ -1423,11 +1454,9 @@ void Buffer::writeLaTeXSource(odocstream & os, // add this just in case after all the paragraphs os << endl; - d->texrow.newline(); if (output_preamble) { os << "\\end{document}\n"; - d->texrow.newline(); LYXERR(Debug::LATEX, "makeLaTeXFile...done"); } else { LYXERR(Debug::LATEX, "LaTeXFile for inclusion made."); @@ -1435,7 +1464,7 @@ void Buffer::writeLaTeXSource(odocstream & os, runparams_in.encoding = runparams.encoding; // Just to be sure. (Asger) - d->texrow.newline(); + os.texrow().newline(); //for (int i = 0; itexrow.rows(); i++) { // int id,pos; @@ -1444,7 +1473,7 @@ void Buffer::writeLaTeXSource(odocstream & os, //} LYXERR(Debug::INFO, "Finished making LaTeX file."); - LYXERR(Debug::INFO, "Row count was " << d->texrow.rows() - 1 << '.'); + LYXERR(Debug::INFO, "Row count was " << os.texrow().rows() - 1 << '.'); } @@ -1605,7 +1634,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os, os << "\n\n" << features.getTClassHTMLPreamble() - << "\n\n" + << "\n\n" << from_utf8(features.getPreambleSnippets()); os << "\n\n"; @@ -1714,15 +1743,13 @@ void Buffer::updateBibfilesCache(UpdateScope scope) const d->bibfiles_cache_.clear(); for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { if (it->lyxCode() == BIBTEX_CODE) { - InsetBibtex const & inset = - static_cast(*it); + InsetBibtex const & inset = static_cast(*it); support::FileNameList const bibfiles = inset.getBibFiles(); d->bibfiles_cache_.insert(d->bibfiles_cache_.end(), bibfiles.begin(), bibfiles.end()); } else if (it->lyxCode() == INCLUDE_CODE) { - InsetInclude & inset = - static_cast(*it); + InsetInclude & inset = static_cast(*it); Buffer const * const incbuf = inset.getChildBuffer(); if (!incbuf) continue; @@ -1785,21 +1812,19 @@ BiblioInfo const & Buffer::masterBibInfo() const } -void Buffer::checkBibInfoCache() const +void Buffer::checkIfBibInfoCacheIsValid() const { // use the master's cache Buffer const * const tmp = masterBuffer(); if (tmp != this) { - tmp->checkBibInfoCache(); + tmp->checkIfBibInfoCacheIsValid(); return; } - // this will also reload the cache if it is invalid - support::FileNameList const & bibfiles_cache = getBibfilesCache(); - // compare the cached timestamps with the actual ones. - support::FileNameList::const_iterator ei = bibfiles_cache.begin(); - support::FileNameList::const_iterator en = bibfiles_cache.end(); + FileNameList const & bibfiles_cache = getBibfilesCache(); + FileNameList::const_iterator ei = bibfiles_cache.begin(); + FileNameList::const_iterator en = bibfiles_cache.end(); for (; ei != en; ++ ei) { time_t lastw = ei->lastModified(); time_t prevw = d->bibfile_status_[*ei]; @@ -1808,20 +1833,50 @@ void Buffer::checkBibInfoCache() const d->bibfile_status_[*ei] = lastw; } } - - // if not valid, then reload the info - if (!d->bibinfo_cache_valid_) { - d->bibinfo_.clear(); - fillWithBibKeys(d->bibinfo_); - d->bibinfo_cache_valid_ = true; +} + + +void Buffer::reloadBibInfoCache() const +{ + // use the master's cache + Buffer const * const tmp = masterBuffer(); + if (tmp != this) { + tmp->reloadBibInfoCache(); + return; } + + checkIfBibInfoCacheIsValid(); + if (d->bibinfo_cache_valid_) + return; + + d->bibinfo_.clear(); + collectBibKeys(); + d->bibinfo_cache_valid_ = true; } -void Buffer::fillWithBibKeys(BiblioInfo & keys) const +void Buffer::collectBibKeys() const { for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) - it->fillWithBibKeys(keys, it); + it->collectBibKeys(it); +} + + +void Buffer::addBiblioInfo(BiblioInfo const & bi) const +{ + Buffer const * tmp = masterBuffer(); + BiblioInfo & masterbi = (tmp == this) ? + d->bibinfo_ : tmp->d->bibinfo_; + masterbi.mergeBiblioInfo(bi); +} + + +void Buffer::addBibTeXInfo(docstring const & key, BibTeXInfo const & bi) const +{ + Buffer const * tmp = masterBuffer(); + BiblioInfo & masterbi = (tmp == this) ? + d->bibinfo_ : tmp->d->bibinfo_; + masterbi[key] = bi; } @@ -2019,6 +2074,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) case LFUN_BUFFER_AUTO_SAVE: autoSave(); + resetAutosaveTimers(); break; case LFUN_BRANCH_ADD: { @@ -2092,7 +2148,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) bool success = false; for (; it != end; ++it) { if (it->lyxCode() == BRANCH_CODE) { - InsetBranch & ins = dynamic_cast(*it); + InsetBranch & ins = static_cast(*it); if (ins.branch() == oldname) { undo().recordUndo(it); ins.rename(newname); @@ -2378,8 +2434,11 @@ bool Buffer::isExternallyModified(CheckMethod method) const } -void Buffer::saveCheckSum(FileName const & file) const +void Buffer::saveCheckSum() const { + FileName const & file = d->filename; + + file.refresh(); if (file.exists()) { d->timestamp_ = file.lastModified(); d->checksum_ = file.checksum(); @@ -2484,7 +2543,7 @@ Buffer const * Buffer::parent() const ListOfBuffers Buffer::allRelatives() const { ListOfBuffers lb = masterBuffer()->getDescendents(); - lb.push_front(const_cast(this)); + lb.push_front(const_cast(masterBuffer())); return lb; } @@ -2625,7 +2684,9 @@ MacroData const * Buffer::Impl::getBufferMacro(docstring const & name, break; // scope ends behind pos? - if (pos < it->second.first) { + if (pos < it->second.first + && (cloned_buffer_ || + theBufferList().isLoaded(it->second.second))) { // look for macro in external file macro_lock = true; MacroData const * data @@ -2769,12 +2830,11 @@ void Buffer::Impl::updateMacros(DocIterator & it, DocIterator & scope) continue; } - if (doing_export && iit->inset->asInsetMath()) { - InsetMath * im = static_cast(iit->inset); - if (im->asHullInset()) { - InsetMathHull * hull = static_cast(im); + InsetMath * im = iit->inset->asInsetMath(); + if (doing_export && im) { + InsetMathHull * hull = im->asHullInset(); + if (hull) hull->recordLocation(it); - } } if (iit->inset->lyxCode() != MATHMACRO_CODE) @@ -2782,7 +2842,7 @@ void Buffer::Impl::updateMacros(DocIterator & it, DocIterator & scope) // get macro data MathMacroTemplate & macroTemplate = - static_cast(*iit->inset); + *iit->inset->asInsetMath()->asMacroTemplate(); MacroContext mc(owner_, it); macroTemplate.updateToContext(mc); @@ -2837,7 +2897,7 @@ void Buffer::getUsedBranches(std::list & result, bool const from_mast InsetIterator const end = inset_iterator_end(inset()); for (; it != end; ++it) { if (it->lyxCode() == BRANCH_CODE) { - InsetBranch & br = dynamic_cast(*it); + InsetBranch & br = static_cast(*it); docstring const name = br.branch(); if (!from_master && !params().branchlist().find(name)) result.push_back(name); @@ -2988,40 +3048,43 @@ void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to, { //FIXME: This does not work for child documents yet. LASSERT(code == CITE_CODE, /**/); + + reloadBibInfoCache(); + // Check if the label 'from' appears more than once - vector labels; - string paramName; - checkBibInfoCache(); BiblioInfo const & keys = masterBibInfo(); BiblioInfo::const_iterator bit = keys.begin(); BiblioInfo::const_iterator bend = keys.end(); + vector labels; for (; bit != bend; ++bit) // FIXME UNICODE labels.push_back(bit->first); - paramName = "key"; if (count(labels.begin(), labels.end(), from) > 1) return; + string const paramName = "key"; for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { if (it->lyxCode() == code) { - InsetCommand & inset = static_cast(*it); - docstring const oldValue = inset.getParam(paramName); + InsetCommand * inset = it->asInsetCommand(); + if (!inset) + continue; + docstring const oldValue = inset->getParam(paramName); if (oldValue == from) - inset.setParam(paramName, to); + inset->setParam(paramName, to); } } } -void Buffer::getSourceCode(odocstream & os, pit_type par_begin, - pit_type par_end, bool full_source) const +void Buffer::getSourceCode(odocstream & os, string const format, + pit_type par_begin, pit_type par_end, + bool full_source) const { OutputParams runparams(¶ms().encoding()); runparams.nice = true; - runparams.flavor = params().useXetex ? - OutputParams::XETEX : OutputParams::LATEX; + runparams.flavor = getOutputFlavor(format); runparams.linelen = lyxrc.plaintext_linelen; // No side effect of file copying and image conversion runparams.dryrun = true; @@ -3033,9 +3096,13 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, d->texrow.newline(); if (isDocBook()) writeDocBookSource(os, absFileName(), runparams, false); - else + else if (runparams.flavor == OutputParams::HTML) + writeLyXHTMLSource(os, runparams, false); + else { // latex or literate - writeLaTeXSource(os, string(), runparams, true, true); + otexstream ots(os, d->texrow); + writeLaTeXSource(ots, string(), runparams, true, true); + } } else { runparams.par_begin = par_begin; runparams.par_end = par_end; @@ -3057,9 +3124,14 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, // output paragraphs if (isDocBook()) docbookParagraphs(text(), *this, os, runparams); - else + else if (runparams.flavor == OutputParams::HTML) { + XHTMLStream xs(os); + xhtmlParagraphs(text(), *this, xs, runparams); + } else { // latex or literate - latexParagraphs(*this, text(), os, texrow, runparams); + otexstream ots(os, texrow); + latexParagraphs(*this, text(), ots, runparams); + } } } @@ -3222,13 +3294,7 @@ int AutoSaveBuffer::generateChild() FileName Buffer::getEmergencyFileName() const { - return getEmergencyFileNameFor(d->filename); -} - - -FileName Buffer::getEmergencyFileNameFor(FileName const & fn) const -{ - return FileName(fn.absFileName() + ".emergency"); + return FileName(d->filename.absFileName() + ".emergency"); } @@ -3244,15 +3310,9 @@ FileName Buffer::getAutosaveFileName() const if (!isUnnamed() || fpath.empty() || !FileName(fpath).exists()) fpath = filePath(); - string const fname = d->filename.onlyFileName(); - return getAutosaveFileNameFor(makeAbsPath(fname, fpath)); -} - + string const fname = "#" + d->filename.onlyFileName() + "#"; -FileName Buffer::getAutosaveFileNameFor(FileName const & fn) const -{ - string const fname = "#" + onlyFileName(fn.absFileName()) + "#"; - return FileName(onlyPath(fn.absFileName()) + fname); + return makeAbsPath(fname, fpath); } @@ -3274,23 +3334,36 @@ void Buffer::moveAutosaveFile(support::FileName const & oldauto) const } -// Perfect target for a thread... -void Buffer::autoSave() const +bool Buffer::autoSave() const { - if (d->bak_clean || isReadonly()) { - // We don't save now, but we'll try again later - resetAutosaveTimers(); - return; - } + Buffer const * buf = d->cloned_buffer_ ? d->cloned_buffer_ : this; + if (buf->d->bak_clean || isReadonly()) + return true; - // emit message signal. message(_("Autosaving current document...")); - AutoSaveBuffer autosave(*this, getAutosaveFileName()); - autosave.start(); - - d->bak_clean = true; - - resetAutosaveTimers(); + buf->d->bak_clean = true; + + FileName const fname = getAutosaveFileName(); + if (d->cloned_buffer_) { + // If this buffer is cloned, we assume that + // we are running in a separate thread already. + FileName const tmp_ret = FileName::tempName("lyxauto"); + if (!tmp_ret.empty()) { + writeFile(tmp_ret); + // assume successful write of tmp_ret + if (tmp_ret.moveTo(fname)) + return true; + } + // failed to write/rename tmp_ret so try writing direct + return writeFile(fname); + } else { + /// This function is deprecated as the frontend needs to take care + /// of cloning the buffer and autosaving it in another thread. It + /// is still here to allow (QT_VERSION < 0x040400). + AutoSaveBuffer autosave(*this, fname); + autosave.start(); + return true; + } } @@ -3298,7 +3371,7 @@ string Buffer::bufferFormat() const { string format = params().documentClass().outputFormat(); if (format == "latex") { - if (params().useXetex) + if (params().useNonTeXFonts) return "xetex"; if (params().encoding().package() == Encoding::japanese) return "platex"; @@ -3309,15 +3382,13 @@ string Buffer::bufferFormat() const string Buffer::getDefaultOutputFormat() const { - if (!params().defaultOutputFormat.empty() - && params().defaultOutputFormat != "default") - return params().defaultOutputFormat; - typedef vector Formats; - Formats formats = exportableFormats(true); + if (!params().default_output_format.empty() + && params().default_output_format != "default") + return params().default_output_format; if (isDocBook() - || isLiterate() - || params().useXetex + || params().useNonTeXFonts || params().encoding().package() == Encoding::japanese) { + vector const formats = exportableFormats(true); if (formats.empty()) return string(); // return the first we find @@ -3327,6 +3398,43 @@ string Buffer::getDefaultOutputFormat() const } +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 { @@ -3368,12 +3476,14 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, runparams.linelen = lyxrc.plaintext_linelen; runparams.includeall = includeall; vector backs = backends(); + Converters converters = theConverters(); if (find(backs.begin(), backs.end(), format) == backs.end()) { // Get shortest path to format + converters.buildGraph(); Graph::EdgePath path; for (vector::const_iterator it = backs.begin(); it != backs.end(); ++it) { - Graph::EdgePath p = theConverters().getPath(*it, format); + Graph::EdgePath p = converters.getPath(*it, format); if (!p.empty() && (path.empty() || p.size() < path.size())) { backend_format = *it; path = p; @@ -3389,13 +3499,17 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, } return false; } - runparams.flavor = theConverters().getFlavor(path); + runparams.flavor = converters.getFlavor(path); } else { backend_format = format; // FIXME: Don't hardcode format names here, but use a flag if (backend_format == "pdflatex") runparams.flavor = OutputParams::PDFLATEX; + else if (backend_format == "luatex") + runparams.flavor = OutputParams::LUATEX; + else if (backend_format == "xetex") + runparams.flavor = OutputParams::XETEX; } string filename = latexName(false); @@ -3426,11 +3540,10 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, break; case BufferParams::LaTeX: runparams.math_flavor = OutputParams::MathAsLaTeX; - break; + break; } - makeLyXHTMLFile(FileName(filename), runparams); - } else if (backend_format == "lyx") + } else if (backend_format == "lyx") writeFile(FileName(filename)); // Docbook backend else if (isDocBook()) { @@ -3440,8 +3553,13 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, // LaTeX backend else if (backend_format == format) { runparams.nice = true; - if (!makeLaTeXFile(FileName(filename), string(), runparams)) + if (!makeLaTeXFile(FileName(filename), string(), runparams)) { + if (d->cloned_buffer_) { + d->cloned_buffer_->d->errorLists["Export"] = + d->errorLists["Export"]; + } return false; + } } else if (!lyxrc.tex_allows_spaces && contains(filePath(), ' ')) { Alert::error(_("File name error"), @@ -3449,8 +3567,13 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, return false; } else { runparams.nice = false; - if (!makeLaTeXFile(FileName(filename), filePath(), runparams)) + if (!makeLaTeXFile(FileName(filename), filePath(), runparams)) { + if (d->cloned_buffer_) { + d->cloned_buffer_->d->errorLists["Export"] = + d->errorLists["Export"]; + } return false; + } } string const error_type = (format == "program") @@ -3458,12 +3581,12 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, ErrorList & error_list = d->errorLists[error_type]; string const ext = formats.extension(format); FileName const tmp_result_file(changeExtension(filename, ext)); - bool const success = theConverters().convert(this, FileName(filename), + bool const success = converters.convert(this, FileName(filename), tmp_result_file, FileName(absFileName()), backend_format, format, error_list); // Emit the signal to show the error list or copy it back to the - // cloned Buffer so that it cab be emitted afterwards. + // cloned Buffer so that it can be emitted afterwards. if (format != backend_format) { if (d->cloned_buffer_) { d->cloned_buffer_->d->errorLists[error_type] = @@ -3476,6 +3599,10 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, ListOfBuffers::const_iterator const cen = clist.end(); for (; cit != cen; ++cit) { if (d->cloned_buffer_) { + // Enable reverse search by copying back the + // texrow object to the cloned buffer. + // FIXME: this is not thread safe. + (*cit)->d->cloned_buffer_->d->texrow = (*cit)->d->texrow; (*cit)->d->cloned_buffer_->d->errorLists[error_type] = (*cit)->d->errorLists[error_type]; } else @@ -3602,8 +3729,12 @@ 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") + 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"); @@ -3611,59 +3742,72 @@ vector Buffer::backends() const } -Buffer::ReadStatus Buffer::readFromVC(FileName const & fn) +Buffer::ReadStatus Buffer::extractFromVC() { - bool const found = LyXVC::file_not_found_hook(fn); + bool const found = LyXVC::file_not_found_hook(d->filename); if (!found) return ReadFileNotFound; - if (!fn.isReadableFile()) + if (!d->filename.isReadableFile()) return ReadVCError; return ReadSuccess; } -Buffer::ReadStatus Buffer::readEmergency(FileName const & fn) +Buffer::ReadStatus Buffer::loadEmergency() { - FileName const emergencyFile = getEmergencyFileNameFor(fn); + FileName const emergencyFile = getEmergencyFileName(); if (!emergencyFile.exists() - || emergencyFile.lastModified() <= fn.lastModified()) + || emergencyFile.lastModified() <= d->filename.lastModified()) return ReadFileNotFound; - docstring const file = makeDisplayPath(fn.absFileName(), 20); + docstring const file = makeDisplayPath(d->filename.absFileName(), 20); docstring const text = bformat(_("An emergency save of the document " "%1$s exists.\n\nRecover emergency save?"), file); - int const ret = Alert::prompt(_("Load emergency save?"), text, + + int const load_emerg = Alert::prompt(_("Load emergency save?"), text, 0, 2, _("&Recover"), _("&Load Original"), _("&Cancel")); - switch (ret) + switch (load_emerg) { case 0: { - // the file is not saved if we load the emergency file. - markDirty(); docstring str; - bool const res = readFile(emergencyFile); - if (res) + ReadStatus const ret_llf = loadThisLyXFile(emergencyFile); + bool const success = (ret_llf == ReadSuccess); + if (success) { + if (isReadonly()) { + Alert::warning(_("File is read-only"), + bformat(_("An emergency file is successfully loaded, " + "but the original file %1$s is marked read-only. " + "Please make sure to save the document as a different " + "file."), from_utf8(d->filename.absFileName()))); + } + markDirty(); str = _("Document was successfully recovered."); - else + } else str = _("Document was NOT successfully recovered."); str += "\n\n" + bformat(_("Remove emergency file now?\n(%1$s)"), - makeDisplayPath(emergencyFile.absFileName())); + makeDisplayPath(emergencyFile.absFileName())); - if (!Alert::prompt(_("Delete emergency file?"), str, 1, 1, - _("&Remove"), _("&Keep"))) { + int const del_emerg = + Alert::prompt(_("Delete emergency file?"), str, 1, 1, + _("&Remove"), _("&Keep")); + if (del_emerg == 0) { emergencyFile.removeFile(); - if (res) + if (success) Alert::warning(_("Emergency file deleted"), _("Do not forget to save your file now!"), true); } - return res ? ReadSuccess : ReadEmergencyFailure; + return success ? ReadSuccess : ReadEmergencyFailure; } - case 1: - if (!Alert::prompt(_("Delete emergency file?"), + case 1: { + int const del_emerg = + Alert::prompt(_("Delete emergency file?"), _("Remove emergency file now?"), 1, 1, - _("&Remove"), _("&Keep"))) + _("&Remove"), _("&Keep")); + if (del_emerg == 0) emergencyFile.removeFile(); return ReadOriginal; + } default: break; @@ -3672,16 +3816,16 @@ Buffer::ReadStatus Buffer::readEmergency(FileName const & fn) } -Buffer::ReadStatus Buffer::readAutosave(FileName const & fn) +Buffer::ReadStatus Buffer::loadAutosave() { // Now check if autosave file is newer. - FileName autosaveFile = getAutosaveFileNameFor(fn); + FileName const autosaveFile = getAutosaveFileName(); if (!autosaveFile.exists() - || autosaveFile.lastModified() <= fn.lastModified()) + || autosaveFile.lastModified() <= d->filename.lastModified()) return ReadFileNotFound; - docstring const file = makeDisplayPath(fn.absFileName(), 20); - docstring const text = bformat(_("The backup of the document %1$s + docstring const file = makeDisplayPath(d->filename.absFileName(), 20); + docstring const text = bformat(_("The backup of the document %1$s " "is newer.\n\nLoad the backup instead?"), file); int const ret = Alert::prompt(_("Load backup?"), text, 0, 2, _("&Load backup"), _("Load &original"), _("&Cancel")); @@ -3689,9 +3833,17 @@ Buffer::ReadStatus Buffer::readAutosave(FileName const & fn) switch (ret) { case 0: { - bool success = readFile(autosaveFile); + ReadStatus const ret_llf = loadThisLyXFile(autosaveFile); // the file is not saved if we load the autosave file. - if (success) { + if (ret_llf == ReadSuccess) { + if (isReadonly()) { + Alert::warning(_("File is read-only"), + bformat(_("A backup file is successfully loaded, " + "but the original file %1$s is marked read-only. " + "Please make sure to save the document as a " + "different file."), + from_utf8(d->filename.absFileName()))); + } markDirty(); return ReadSuccess; } @@ -3708,50 +3860,78 @@ Buffer::ReadStatus Buffer::readAutosave(FileName const & fn) } -Buffer::ReadStatus Buffer::loadLyXFile(FileName const & fn) +Buffer::ReadStatus Buffer::loadLyXFile() { - if (!fn.isReadableFile()) { - ReadStatus const ret_rvc = readFromVC(fn); + if (!d->filename.isReadableFile()) { + ReadStatus const ret_rvc = extractFromVC(); if (ret_rvc != ReadSuccess) return ret_rvc; } - // InsetInfo needs to know if file is under VCS - lyxvc().file_found_hook(fn); - ReadStatus const ret_re = readEmergency(fn); + ReadStatus const ret_re = loadEmergency(); if (ret_re == ReadSuccess || ret_re == ReadCancel) return ret_re; - ReadStatus const ret_ra = readAutosave(fn); + ReadStatus const ret_ra = loadAutosave(); if (ret_ra == ReadSuccess || ret_ra == ReadCancel) return ret_ra; - if (readFile(fn)) - return ReadSuccess; - return ReadFailure; + return loadThisLyXFile(d->filename); +} + + +Buffer::ReadStatus Buffer::loadThisLyXFile(FileName const & fn) +{ + return readFile(fn); } void Buffer::bufferErrors(TeXErrors const & terr, ErrorList & errorList) const { - TeXErrors::Errors::const_iterator cit = terr.begin(); + TeXErrors::Errors::const_iterator it = terr.begin(); TeXErrors::Errors::const_iterator end = terr.end(); + ListOfBuffers clist = getDescendents(); + ListOfBuffers::const_iterator cen = clist.end(); - for (; cit != end; ++cit) { + for (; it != end; ++it) { int id_start = -1; int pos_start = -1; - int errorRow = cit->error_in_line; - bool found = d->texrow.getIdFromRow(errorRow, id_start, - pos_start); + int errorRow = it->error_in_line; + Buffer const * buf = 0; + Impl const * p = d; + if (it->child_name.empty()) + p->texrow.getIdFromRow(errorRow, id_start, pos_start); + else { + // The error occurred in a child + ListOfBuffers::const_iterator cit = clist.begin(); + for (; cit != cen; ++cit) { + string const child_name = + DocFileName(changeExtension( + (*cit)->absFileName(), "tex")). + mangledFileName(); + if (it->child_name != child_name) + continue; + (*cit)->d->texrow.getIdFromRow(errorRow, + id_start, pos_start); + if (id_start != -1) { + buf = d->cloned_buffer_ + ? (*cit)->d->cloned_buffer_->d->owner_ + : (*cit)->d->owner_; + p = (*cit)->d; + break; + } + } + } int id_end = -1; int pos_end = -1; + bool found; do { ++errorRow; - found = d->texrow.getIdFromRow(errorRow, id_end, pos_end); + found = p->texrow.getIdFromRow(errorRow, id_end, pos_end); } while (found && id_start == id_end && pos_start == pos_end); - errorList.push_back(ErrorItem(cit->error_desc, - cit->error_text, id_start, pos_start, pos_end)); + errorList.push_back(ErrorItem(it->error_desc, + it->error_text, id_start, pos_start, pos_end, buf)); } } @@ -3770,7 +3950,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const // do this only if we are the top-level Buffer if (master == this) - checkBibInfoCache(); + reloadBibInfoCache(); // keep the buffers to be children in this set. If the call from the // master comes back we can see which of them were actually seen (i.e. @@ -3814,6 +3994,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const // TocBackend update will be done later. return; + d->bibinfo_cache_valid_ = true; cbuf.tocBackend().update(); if (scope == UpdateMaster) cbuf.structureChanged(); @@ -3920,11 +4101,11 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const switch(layout.labeltype) { case LABEL_COUNTER: if (layout.toclevel <= bp.secnumdepth - && (layout.latextype != LATEX_ENVIRONMENT - || it.text()->isFirstInSequence(it.pit()))) { - counters.step(layout.counter, utype); - par.params().labelString( - par.expandLabel(layout, bp)); + && (layout.latextype != LATEX_ENVIRONMENT + || it.text()->isFirstInSequence(it.pit()))) { + if (counters.hasCounter(layout.counter)) + counters.step(layout.counter, utype); + par.params().labelString(par.expandLabel(layout, bp)); } else par.params().labelString(docstring()); break; @@ -4094,32 +4275,63 @@ int Buffer::spellCheck(DocIterator & from, DocIterator & to, } -bool Buffer::reload() +Buffer::ReadStatus Buffer::reload() { setBusy(true); - // c.f. bug 6587 + // c.f. bug http://www.lyx.org/trac/ticket/6587 removeAutosaveFile(); // e.g., read-only status could have changed due to version control d->filename.refresh(); docstring const disp_fn = makeDisplayPath(d->filename.absFileName()); - bool const success = (loadLyXFile(d->filename) == ReadSuccess); - if (success) { + ReadStatus const status = loadLyXFile(); + if (status == ReadSuccess) { updateBuffer(); changed(true); updateTitles(); markClean(); - saveCheckSum(d->filename); message(bformat(_("Document %1$s reloaded."), disp_fn)); + d->undo_.clear(); } else { message(bformat(_("Could not reload document %1$s."), disp_fn)); } setBusy(false); - thePreviews().removeLoader(*this); - if (graphics::Previews::status() != LyXRC::PREVIEW_OFF) - thePreviews().generateBufferPreviews(*this); + removePreviews(); + updatePreviews(); errors("Parse"); - return success; + return status; +} + + +bool Buffer::saveAs(FileName const & fn) +{ + FileName const old_name = fileName(); + FileName const old_auto = getAutosaveFileName(); + bool const old_unnamed = isUnnamed(); + + setFileName(fn); + markDirty(); + setUnnamed(false); + + if (save()) { + // bring the autosave file with us, just in case. + moveAutosaveFile(old_auto); + // validate version control data and + // correct buffer title + lyxvc().file_found_hook(fileName()); + updateTitles(); + // the file has now been saved to the new location. + // we need to check that the locations of child buffers + // are still valid. + checkChildBuffers(); + return true; + } else { + // save failed + // reset the old filename and unnamed state + setFileName(old_name); + setUnnamed(old_unnamed); + return false; + } }