commit 62d36bf04d436c83ddace8aeaf4dbd493d674cdf
Author: Enrico Forestieri <[email protected]>
Date:   Sat May 16 19:51:53 2015 +0200

    Correctly load documents moved elsewhere after save.
    
    It is now possible opening documents that where manually moved to a
    different location after they were saved and still produce an output.
    Indeed, (hopefully) all needed included files are now still found.
    When the moved document is saved again, all paths are accordingly updated.
    Of course, for this to work, a document has to be saved in Format 490,
    at least.
    
    As an example, after converting the user guide to the last format, it can
    be copied anywhere and opened without the need of adapting the paths of
    included files or moving them to a proper place.
    
    There is one glitch I am aware of. When moving a child document (but not
    the master) the path to the master is correctly updated but it won't be
    recognized as such. This is because LyX checks that the parent actually
    includes this document but, of course, being the parent document not
    touched, it appears not including this child. Anyway, it will also occur
    when saving the child to a different location and the user is warned
    on the terminal about this fact when the moved child is loaded.
    However, there is no problem when it is the master that has been moved.

diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index bd063a7..ed449b3 100644
--- a/src/Buffer.cpp
+++ b/src/Buffer.cpp
@@ -249,7 +249,8 @@ 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
+       /// Contains the old buffer filePath() while saving-as, or the
+       /// directory where the document was last saved while loading.
        string old_position;
 
        /** Keeps track of the path of local layout files.
@@ -1030,7 +1031,9 @@ bool Buffer::readDocument(Lexer & lex)
        params().indiceslist().addDefault(B_("Index"));
 
        // read main text
+       d->old_position = originFilePath();
        bool const res = text().read(lex, errorList, d->inset);
+       d->old_position.clear();
 
        // inform parent buffer about local macros
        if (parent()) {
@@ -3027,6 +3030,15 @@ string Buffer::filePath() const
 }
 
 
+string Buffer::originFilePath() const
+{
+       if (FileName::isAbsolute(params().origin))
+               return params().origin;
+
+       return filePath();
+}
+
+
 string Buffer::layoutPos() const
 {
        return d->layout_position;
diff --git a/src/Buffer.h b/src/Buffer.h
index 50b2733..b50d5f4 100644
--- a/src/Buffer.h
+++ b/src/Buffer.h
@@ -403,6 +403,13 @@ public:
        /// It is always an absolute path.
        std::string filePath() const;
 
+       /** Returns the path where the document was last saved.
+        *  It may be different from filePath() if the document was later
+        *  manually moved to a different location.
+        *  It is always an absolute path.
+        */
+       std::string originFilePath() const;
+
        /** Returns the path where a local layout file lives.
         *  An empty string is returned for standard system and user layouts.
         *  If possible, it is always relative to the buffer path.
@@ -731,6 +738,9 @@ public:
        /// In all other cases, this is a no-op and name is returned unchanged.
        /// If a non-empty ext is given, the existence of name.ext is checked
        /// but the returned path will not contain this extension.
+       /// Similarly, when loading a document that was moved from the location
+       /// where it was saved, return the correct path relative to the new
+       /// location.
        std::string includedFilePath(std::string const & name,
                                std::string const & ext = empty_string()) const;
 
diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp
index 451736e..f6e9649 100644
--- a/src/BufferParams.cpp
+++ b/src/BufferParams.cpp
@@ -682,6 +682,19 @@ string BufferParams::readToken(Lexer & lex, string const & 
token,
        } else if (token == "\\master") {
                lex.eatLine();
                master = lex.getString();
+               if (!filepath.empty() && FileName::isAbsolute(origin)) {
+                       bool const isabs = FileName::isAbsolute(master);
+                       FileName const abspath(isabs ? master : origin + 
master);
+                       bool const moved = filepath != FileName(origin);
+                       if (moved && abspath.exists()) {
+                               docstring const path = isabs
+                                       ? from_utf8(master)
+                                       : from_utf8(abspath.realPath());
+                               docstring const refpath =
+                                       from_utf8(filepath.absFileName());
+                               master = to_utf8(makeRelPath(path, refpath));
+                       }
+               }
        } else if (token == "\\suppress_date") {
                lex >> suppress_date;
        } else if (token == "\\justification") {
diff --git a/src/factory.cpp b/src/factory.cpp
index 9ef881d..bf25fbd 100644
--- a/src/factory.cpp
+++ b/src/factory.cpp
@@ -538,7 +538,7 @@ Inset * readInset(Lexer & lex, Buffer * buf)
                //Worst case, we could put it in each case below. Better, we 
could
                //pass the lexer to the constructor and let the params be built 
there.
                InsetCommandParams inscmd(code);
-               inscmd.read(lex);
+               inscmd.read(lex, buf);
 
                switch (code) {
                        case BIBITEM_CODE:
diff --git a/src/insets/InsetBibitem.cpp b/src/insets/InsetBibitem.cpp
index d0a28e7..a8dfd11 100644
--- a/src/insets/InsetBibitem.cpp
+++ b/src/insets/InsetBibitem.cpp
@@ -195,7 +195,7 @@ void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & 
cmd)
 
 void InsetBibitem::read(Lexer & lex)
 {
-       InsetCommand::read(lex);
+       InsetCommand::read(lex, &buffer());
 
        if (prefixIs(getParam("key"), key_prefix)) {
                int const key = 
convert<int>(getParam("key").substr(key_prefix.length()));
diff --git a/src/insets/InsetCommand.cpp b/src/insets/InsetCommand.cpp
index 3cc8f70..4541190 100644
--- a/src/insets/InsetCommand.cpp
+++ b/src/insets/InsetCommand.cpp
@@ -244,7 +244,7 @@ bool InsetCommand::string2params(string const & data,
        lex.setContext("InsetCommand::string2params");
        lex >> name.c_str(); // check for name
        lex >> "CommandInset";
-       params.read(lex);
+       params.read(lex, 0);
        return true;
 }
 
diff --git a/src/insets/InsetCommand.h b/src/insets/InsetCommand.h
index 131beff..c3b5005 100644
--- a/src/insets/InsetCommand.h
+++ b/src/insets/InsetCommand.h
@@ -66,7 +66,7 @@ public:
        ///
        void write(std::ostream & os) const { p_.write(os); }
        ///
-       void read(Lexer & lex) { p_.read(lex); }
+       void read(Lexer & lex, Buffer const * buf) { p_.read(lex, buf); }
        ///
        void doDispatch(Cursor & cur, FuncRequest & cmd);
        ///
diff --git a/src/insets/InsetCommandParams.cpp 
b/src/insets/InsetCommandParams.cpp
index 074bd3a..e291053 100644
--- a/src/insets/InsetCommandParams.cpp
+++ b/src/insets/InsetCommandParams.cpp
@@ -275,7 +275,7 @@ void InsetCommandParams::setCmdName(string const & name)
 }
 
 
-void InsetCommandParams::read(Lexer & lex)
+void InsetCommandParams::read(Lexer & lex, Buffer const * buffer)
 {
        lex.setContext("InsetCommandParams::read");
        lex >> insetName(insetCode_).c_str();
@@ -302,7 +302,25 @@ void InsetCommandParams::read(Lexer & lex)
                }
                if (info_.hasParam(token)) {
                        lex.next(true);
-                       params_[token] = lex.getDocString();
+                       docstring data = lex.getDocString();
+                       if (buffer && token == "filename") {
+                               data = 
from_utf8(buffer->includedFilePath(to_utf8(data)));
+                       } else if (buffer && token == "bibfiles") {
+                               int i = 0;
+                               docstring newdata;
+                               docstring bib = support::token(data, ',', i);
+                               while (!bib.empty()) {
+                                       bib = 
from_utf8(buffer->includedFilePath(to_utf8(bib), "bib"));
+                                       if (!newdata.empty())
+                                               newdata.append(1, ',');
+                                       newdata.append(bib);
+                                       bib = support::token(data, ',', ++i);
+                               }
+                               data = newdata;
+                       } else if (buffer && token == "options") {
+                               data = 
from_utf8(buffer->includedFilePath(to_utf8(data), "bst"));
+                       }
+                       params_[token] = data;
                } else {
                        lex.printError("Unknown parameter name `$$Token' for 
command " + cmdName_);
                        throw ExceptionMessage(WarningException,
@@ -353,6 +371,8 @@ void InsetCommandParams::Write(ostream & os, Buffer const * 
buffer) const
                                        bib = token(data, ',', ++i);
                                }
                                data = newdata;
+                       } else if (buffer && name == "options") {
+                               data = buffer->includedFilePath(data, "bst");
                        }
                        os << name << ' '
                           << Lexer::quoteString(data)
diff --git a/src/insets/InsetCommandParams.h b/src/insets/InsetCommandParams.h
index 52f79ba..c983c33 100644
--- a/src/insets/InsetCommandParams.h
+++ b/src/insets/InsetCommandParams.h
@@ -114,7 +114,7 @@ public:
        ///
        InsetCode code() const { return insetCode_; }
        ///
-       void read(Lexer &);
+       void read(Lexer &, Buffer const *);
        /// Parse the command
        ///
        void write(std::ostream &) const;
diff --git a/src/insets/InsetGraphics.cpp b/src/insets/InsetGraphics.cpp
index 3055be9..7e18ec6 100644
--- a/src/insets/InsetGraphics.cpp
+++ b/src/insets/InsetGraphics.cpp
@@ -293,7 +293,7 @@ void InsetGraphics::read(Lexer & lex)
 {
        lex.setContext("InsetGraphics::read");
        //lex >> "Graphics";
-       readInsetGraphics(lex, buffer().filePath(), params_);
+       readInsetGraphics(lex, buffer().originFilePath(), params_);
        graphic_->update(params().as_grfxParams());
 }
 

Reply via email to