commit 4543bf288d0839f5a9bb93e76928d5cb061ea7dd
Author: Enrico Forestieri <[email protected]>
Date:   Mon May 4 03:11:30 2015 +0200

    Update paths of included files when saving to a different folder.
    
    Fixes #9528 and #5115.

diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index d47abd9..52212e8 100644
--- a/src/Buffer.cpp
+++ b/src/Buffer.cpp
@@ -237,6 +237,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<string, ErrorList> errorLists;
 
@@ -4866,6 +4869,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();
@@ -4883,22 +4888,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();
@@ -4918,11 +4920,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);
        }
@@ -4952,4 +4949,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 fe0294b..e855c20 100644
--- a/src/Buffer.h
+++ b/src/Buffer.h
@@ -707,6 +707,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 c925bfe..eb0cf8f 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 8c4fa18..a4310ad 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 af04f83..519e937 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"
@@ -321,6 +322,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';
        if (preview_)
@@ -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 a5d4678..52f79ba 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 e3960c4..5f99944 100644
--- a/src/insets/InsetInclude.cpp
+++ b/src/insets/InsetInclude.cpp
@@ -1030,6 +1030,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 3e28346..bee2089 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
        //@{
diff --git a/status.21x b/status.21x
index 1f13747..6688024 100644
--- a/status.21x
+++ b/status.21x
@@ -82,6 +82,9 @@ What's new
 
 * DOCUMENT INPUT/OUTPUT
 
+- Update path of included files when saving a document to a different
+  location (bugs 9528, 5115).
+
 - Fix LaTeX errors caused by too late loading of fixltx2e package
   (bugs 9452, 9361).
 

Reply via email to