From 8c351e32be92fca91e2dd1f9ec478d5cb1ce6c8c Mon Sep 17 00:00:00 2001 From: Enrico Forestieri Date: Sun, 3 May 2015 23:55:19 +0200 Subject: [PATCH] Update paths of included files when saving to a different folder. Fixes #9528 and #5115. --- src/Buffer.cpp | 35 ++++++++++++++++++++----------- src/Buffer.h | 6 ++++++ src/insets/InsetBibtex.cpp | 6 ++++++ src/insets/InsetBibtex.h | 2 ++ src/insets/InsetCommandParams.cpp | 30 ++++++++++++++++++++++---- src/insets/InsetCommandParams.h | 3 +++ src/insets/InsetInclude.cpp | 6 ++++++ src/insets/InsetInclude.h | 2 ++ 8 files changed, 74 insertions(+), 16 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 7022139daf..ed94503c14 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -249,6 +249,9 @@ public: /// map from children inclusion positions to their scope and their buffer PositionScopeBufferMap position_to_children; + /// Keeps track of old buffer filePath() for save-as operations + string old_position; + /// Container for all sort of Buffer dependant errors. map errorLists; @@ -4926,6 +4929,8 @@ bool Buffer::saveAs(FileName const & fn) FileName const old_name = fileName(); FileName const old_auto = getAutosaveFileName(); bool const old_unnamed = isUnnamed(); + bool success = true; + d->old_position = filePath(); setFileName(fn); markDirty(); @@ -4943,22 +4948,19 @@ bool Buffer::saveAs(FileName const & fn) // are still valid. checkChildBuffers(); checkMasterBuffer(); - return true; } else { // save failed // reset the old filename and unnamed state setFileName(old_name); setUnnamed(old_unnamed); - return false; + success = false; } + + d->old_position.clear(); + return success; } -// FIXME We could do better here, but it is complicated. What would be -// nice is to offer either (a) to save the child buffer to an appropriate -// location, so that it would "move with the master", or else (b) to update -// the InsetInclude so that it pointed to the same file. But (a) is a bit -// complicated, because the code for this lives in GuiView. void Buffer::checkChildBuffers() { Impl::BufferPositionMap::iterator it = d->children_positions.begin(); @@ -4978,11 +4980,6 @@ void Buffer::checkChildBuffers() if (oldloc == newloc) continue; // the location of the child file is incorrect. - Alert::warning(_("Included File Invalid"), - bformat(_("Saving this document to a new location has made the file:\n" - " %1$s\n" - "inaccessible. You will need to update the included filename."), - from_utf8(oldloc))); cbuf->setParent(0); inset_inc->setChildBuffer(0); } @@ -5012,4 +5009,18 @@ void Buffer::checkMasterBuffer() setParent(0); } + +string Buffer::includedFilePath(string const & name) const +{ + if (d->old_position.empty() || d->old_position == filePath()) + return name; + + if (FileName::isAbsolute(name)) + return to_utf8(makeRelPath(from_utf8(name), from_utf8(filePath()))); + + // old_position already contains a trailing path separator + string const cleanpath = FileName(d->old_position + name).realPath(); + return to_utf8(makeRelPath(from_utf8(cleanpath), from_utf8(filePath()))); +} + } // namespace lyx diff --git a/src/Buffer.h b/src/Buffer.h index 05cf8aac81..718fe1e2e1 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -710,6 +710,12 @@ public: /// void checkMasterBuffer(); + /// If the document is being saved to a new location, return the + /// updated path of an included file relative to the new buffer path + /// if possible, otherwise return its absolute path. + /// In all other cases, this is a no-op and name is returned unchanged. + std::string includedFilePath(std::string const & name) const; + /// compute statistics between \p from and \p to /// \p from initial position /// \p to points to the end position diff --git a/src/insets/InsetBibtex.cpp b/src/insets/InsetBibtex.cpp index c925bfe3cc..eb0cf8ff92 100644 --- a/src/insets/InsetBibtex.cpp +++ b/src/insets/InsetBibtex.cpp @@ -1025,6 +1025,12 @@ docstring InsetBibtex::xhtml(XHTMLStream & xs, OutputParams const &) const } +void InsetBibtex::write(ostream & os) const +{ + params().Write(os, &buffer()); +} + + string InsetBibtex::contextMenuName() const { return "context-bibtex"; diff --git a/src/insets/InsetBibtex.h b/src/insets/InsetBibtex.h index 8c4fa18d3d..a4310ad205 100644 --- a/src/insets/InsetBibtex.h +++ b/src/insets/InsetBibtex.h @@ -38,6 +38,8 @@ public: bool addDatabase(docstring const &); /// bool delDatabase(docstring const &); + /// + void write(std::ostream &) const; /// \name Public functions inherited from Inset class //@{ diff --git a/src/insets/InsetCommandParams.cpp b/src/insets/InsetCommandParams.cpp index af04f83f0c..519e93797d 100644 --- a/src/insets/InsetCommandParams.cpp +++ b/src/insets/InsetCommandParams.cpp @@ -28,6 +28,7 @@ #include "InsetRef.h" #include "InsetTOC.h" +#include "Buffer.h" #include "Encoding.h" #include "Lexer.h" #include "OutputParams.h" @@ -320,6 +321,12 @@ void InsetCommandParams::read(Lexer & lex) void InsetCommandParams::write(ostream & os) const +{ + Write(os, 0); +} + + +void InsetCommandParams::Write(ostream & os, Buffer const * buffer) const { os << "CommandInset " << insetType() << '\n'; os << "LatexCommand " << cmdName_ << '\n'; @@ -328,12 +335,27 @@ void InsetCommandParams::write(ostream & os) const ParamInfo::const_iterator it = info_.begin(); ParamInfo::const_iterator end = info_.end(); for (; it != end; ++it) { - std::string const & name = it->name(); - docstring const & data = (*this)[name]; + string const & name = it->name(); + string data = to_utf8((*this)[name]); if (!data.empty()) { - // FIXME UNICODE + // Adjust path of files if document was moved + if (buffer && name == "filename") { + data = buffer->includedFilePath(data); + } else if (buffer && name == "bibfiles") { + int i = 0; + string newdata; + string bib = token(data, ',', i); + while (!bib.empty()) { + bib = buffer->includedFilePath(bib); + if (!newdata.empty()) + newdata.append(1, ','); + newdata.append(bib); + bib = token(data, ',', ++i); + } + data = newdata; + } os << name << ' ' - << Lexer::quoteString(to_utf8(data)) + << Lexer::quoteString(data) << '\n'; } } diff --git a/src/insets/InsetCommandParams.h b/src/insets/InsetCommandParams.h index a5d46785b8..52f79baf4c 100644 --- a/src/insets/InsetCommandParams.h +++ b/src/insets/InsetCommandParams.h @@ -28,6 +28,7 @@ namespace lyx { class Lexer; +class Buffer; class ParamInfo { public: @@ -117,6 +118,8 @@ public: /// Parse the command /// void write(std::ostream &) const; + /// + void Write(std::ostream & os, Buffer const * buf) const; /// Build the complete LaTeX command docstring getCommand(OutputParams const &) const; /// Return the command name diff --git a/src/insets/InsetInclude.cpp b/src/insets/InsetInclude.cpp index 7494650443..a3a7441a39 100644 --- a/src/insets/InsetInclude.cpp +++ b/src/insets/InsetInclude.cpp @@ -1029,6 +1029,12 @@ void InsetInclude::draw(PainterInfo & pi, int x, int y) const } +void InsetInclude::write(ostream & os) const +{ + params().Write(os, &buffer()); +} + + string InsetInclude::contextMenuName() const { return "context-include"; diff --git a/src/insets/InsetInclude.h b/src/insets/InsetInclude.h index 3e28346269..bee2089d94 100644 --- a/src/insets/InsetInclude.h +++ b/src/insets/InsetInclude.h @@ -64,6 +64,8 @@ public: /// void updateCommand(); + /// + void write(std::ostream &) const; /// \name Public functions inherited from Inset class //@{