]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
Set svn:eol-style.
[lyx.git] / src / Buffer.cpp
index e121ce429f8470956cccc887f3a543dc53bc8792..117cfe0ca7e5ba5ec100d56e2670635a16f1fe11 100644 (file)
@@ -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<string, bool> DepClean;
 typedef map<docstring, pair<InsetLabel const *, Buffer::References> > 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
@@ -258,6 +257,10 @@ public:
        mutable bool bibfile_cache_valid_;
        /// Cache of timestamps of .bib files
        map<FileName, time_t> bibfile_status_;
+       /// Indicates whether the bibinfo has changed since the last time
+       /// we ran updateBuffer(), i.e., whether citation labels may need
+       /// to be updated.
+       mutable bool cite_labels_valid_;
 
        mutable RefCache ref_cache_;
 
@@ -330,8 +333,8 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
          read_only(readonly_), filename(file), file_fully_loaded(false),
          toc_backend(owner), macro_lock(false), timestamp_(0),
          checksum_(0), wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false),
-               bibfile_cache_valid_(false), cloned_buffer_(cloned_buffer), 
-               doing_export(false), parent_buffer(0)
+         bibfile_cache_valid_(false), cite_labels_valid_(false),
+         cloned_buffer_(cloned_buffer), doing_export(false), parent_buffer(0)
 {
        if (!cloned_buffer_) {
                temppath = createBufferTmpDir();
@@ -348,6 +351,7 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
        bibinfo_cache_valid_ = cloned_buffer_->d->bibinfo_cache_valid_;
        bibfile_cache_valid_ = cloned_buffer_->d->bibfile_cache_valid_;
        bibfile_status_ = cloned_buffer_->d->bibfile_status_;
+       cite_labels_valid_ = cloned_buffer_->d->cite_labels_valid_;
 }
 
 
@@ -414,9 +418,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;
 }
@@ -424,29 +427,50 @@ Buffer::~Buffer()
 
 Buffer * Buffer::clone() const
 {
+       BufferMap bufmap;
+       masterBuffer()->clone(bufmap);
+       BufferMap::iterator it = bufmap.find(this);
+       LASSERT(it != bufmap.end(), return 0);
+       return it->second;
+}
+
+
+void Buffer::clone(BufferMap & bufmap) const
+{
+       // have we already been cloned?
+       if (bufmap.find(this) != bufmap.end())
+               return;
+
        Buffer * buffer_clone = new Buffer(fileName().absFileName(), false, this);
+       bufmap[this] = buffer_clone;
        buffer_clone->d->macro_lock = true;
        buffer_clone->d->children_positions.clear();
        // FIXME (Abdel 09/01/2010): this is too complicated. The whole children_positions and
        // math macro caches need to be rethought and simplified.
        // I am not sure wether we should handle Buffer cloning here or in BufferList.
        // Right now BufferList knows nothing about buffer clones.
-       Impl::BufferPositionMap::iterator it = d->children_positions.begin();
-       Impl::BufferPositionMap::iterator end = d->children_positions.end();
+       Impl::PositionScopeBufferMap::iterator it = d->position_to_children.begin();
+       Impl::PositionScopeBufferMap::iterator end = d->position_to_children.end();
        for (; it != end; ++it) {
-               DocIterator dit = it->second.clone(buffer_clone);
+               DocIterator dit = it->first.clone(buffer_clone);
                dit.setBuffer(buffer_clone);
-               Buffer * child = const_cast<Buffer *>(it->first);
-               Buffer * child_clone = child->clone();
+               Buffer * child = const_cast<Buffer *>(it->second.second);
+
+               child->clone(bufmap);
+               BufferMap::iterator const bit = bufmap.find(child);
+               LASSERT(bit != bufmap.end(), continue);
+               Buffer * child_clone = bit->second;
+
                Inset * inset = dit.nextInset();
                LASSERT(inset && inset->lyxCode() == INCLUDE_CODE, continue);
                InsetInclude * inset_inc = static_cast<InsetInclude *>(inset);
                inset_inc->setChildBuffer(child_clone);
                child_clone->d->setParent(buffer_clone);
+               // FIXME Do we need to do this now, or can we wait until we run updateMacros()?
                buffer_clone->setChild(dit, child_clone);
        }
        buffer_clone->d->macro_lock = false;
-       return buffer_clone;
+       return;
 }
 
 
@@ -599,7 +623,7 @@ string Buffer::logName(LogType * type) const
        FileName const bname(
                addName(path, onlyFileName(
                        changeExtension(filename,
-                                       formats.extension(bufferFormat()) + ".out"))));
+                                       formats.extension(params().bufferFormat()) + ".out"))));
 
        // Also consider the master buffer log file
        FileName masterfname = fname;
@@ -643,10 +667,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 +698,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();
@@ -821,9 +846,17 @@ 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();
+       updateMacroInstances(InternalUpdate);
        return res;
 }
 
@@ -835,22 +868,24 @@ bool Buffer::readString(string const & s)
        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");
+
+       int file_format;
+       ReadStatus const ret_plf = parseLyXFormat(lex, fn, file_format);
+       if (ret_plf != ReadSuccess)
+               return ret_plf;
 
-       case ReadWrongVersion: {
+       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;
 }
 
@@ -859,16 +894,42 @@ Buffer::ReadStatus Buffer::readFile(FileName const & fn)
 {
        FileName fname(fn);
        Lexer lex;
-       lex.setFile(fname);
+       if (!lex.setFile(fname)) {
+               Alert::error(_("File Not Found"),
+                       bformat(_("Unable to open file `%1$s'."), 
+                               from_utf8(fn.absFileName())));
+               return ReadFileNotFound;
+       }
+
+       int file_format;
+       ReadStatus const ret_plf = parseLyXFormat(lex, fn, file_format);
+       if (ret_plf != ReadSuccess)
+               return ret_plf;
 
-       ReadStatus const ret_rf = readFile(lex, fname);
-       if (ret_rf != ReadSuccess)
-               return ret_rf;
+       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;
+       }
 
-       // InsetInfo needs to know if file is under VCS
-       lyxvc().file_found_hook(fn);
-       d->read_only = !fname.isWritable();
-       params().compressed = fname.isZippedFile();
+       d->file_fully_loaded = true;
+       d->read_only = !d->filename.isWritable();
+       params().compressed = d->filename.isZippedFile();
+       saveCheckSum();
        return ReadSuccess;
 }
 
@@ -885,110 +946,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<int>(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<int>(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<string>(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 {
-                       // Do stuff with tmpfile name and buffer name here.
-                       return readFile(tmpfile);
-               }
 
+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<string>(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;
 }
 
@@ -996,11 +1046,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)
@@ -1022,13 +1086,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());
                }
@@ -1048,6 +1117,11 @@ bool Buffer::save() const
 
 bool Buffer::writeFile(FileName const & fname) const
 {
+       // FIXME Do we need to do these here? I don't think writing
+       // the LyX file depends upon it. (RGH)
+       // updateBuffer();
+       // updateMacroInstances();
+
        if (d->read_only && fname == d->filename)
                return false;
 
@@ -1075,7 +1149,7 @@ bool Buffer::writeFile(FileName const & fname) const
        // see bug 6587
        // removeAutosaveFile();
 
-       saveCheckSum(d->filename);
+       saveCheckSum();
        message(str + _(" done."));
 
        return true;
@@ -1101,24 +1175,24 @@ 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");
                }
        }
 
        // 2) In HOME directory.
-       string s = addName(package().home_dir().absFileName(), absFileName());
+       string s = addName(Package::get_home_dir().absFileName(), absFileName());
        s += ".emergency";
        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
@@ -1128,11 +1202,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;
@@ -1149,7 +1223,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";
@@ -1206,8 +1280,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 << "...");
@@ -1228,9 +1305,18 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
        ErrorList & errorList = d->errorLists["Export"];
        errorList.clear();
        bool failed_export = false;
+       otexstream os(ofs, d->texrow);
+
+       // make sure we are ready to export
+       // this needs to be done before we validate
+       // FIXME Do we need to do this all the time? I.e., in children
+       // of a master we are exporting?
+       updateBuffer();
+       updateMacroInstances(OutputUpdate);
+
        try {
-               d->texrow.reset();
-               writeLaTeXSource(ofs, original_path,
+               os.texrow().reset();
+               writeLaTeXSource(os, original_path,
                      runparams, output_preamble, output_body);
        }
        catch (EncodingException & e) {
@@ -1273,7 +1359,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
@@ -1298,20 +1384,9 @@ 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");
 
-       // Don't move this behind the parent_buffer=0 code below,
-       // because then the macros will not get the right "redefinition"
-       // flag as they don't see the parent macros which are output before.
-       updateMacros();
-
-       // fold macros if possible, still with parent buffer as the
-       // macros will be put in the prefix anyway.
-       updateMacroInstances();
-
        // There are a few differences between nice LaTeX and usual files:
        // usual is \batchmode and has a
        // special input@path to allow the including of figures
@@ -1325,9 +1400,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
@@ -1363,9 +1436,6 @@ void Buffer::writeLaTeXSource(odocstream & os,
                                   << "\\def\\input@path{{"
                                   << inputpath << "/}}\n"
                                   << "\\makeatother\n";
-                               d->texrow.newline();
-                               d->texrow.newline();
-                               d->texrow.newline();
                        }
                }
 
@@ -1374,9 +1444,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");
@@ -1386,19 +1456,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.");
 
@@ -1412,7 +1481,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)
@@ -1420,11 +1489,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.");
@@ -1432,7 +1499,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; i<d->texrow.rows(); i++) {
        // int id,pos;
@@ -1441,25 +1508,7 @@ void Buffer::writeLaTeXSource(odocstream & os,
        //}
 
        LYXERR(Debug::INFO, "Finished making LaTeX file.");
-       LYXERR(Debug::INFO, "Row count was " << d->texrow.rows() - 1 << '.');
-}
-
-
-bool Buffer::isLatex() const
-{
-       return params().documentClass().outputType() == LATEX;
-}
-
-
-bool Buffer::isLiterate() const
-{
-       return params().documentClass().outputType() == LITERATE;
-}
-
-
-bool Buffer::isDocBook() const
-{
-       return params().documentClass().outputType() == DOCBOOK;
+       LYXERR(Debug::INFO, "Row count was " << os.texrow().rows() - 1 << '.');
 }
 
 
@@ -1473,6 +1522,11 @@ void Buffer::makeDocBookFile(FileName const & fname,
        if (!openFileWrite(ofs, fname))
                return;
 
+       // make sure we are ready to export
+       // this needs to be done before we validate
+       updateBuffer();
+       updateMacroInstances(OutputUpdate);
+
        writeDocBookSource(ofs, fname.absFileName(), runparams, body_only);
 
        ofs.close();
@@ -1547,8 +1601,6 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname,
 
        params().documentClass().counters().reset();
 
-       updateMacros();
-
        sgml::openTag(os, top);
        os << '\n';
        docbookParagraphs(text(), *this, os, runparams);
@@ -1566,6 +1618,11 @@ void Buffer::makeLyXHTMLFile(FileName const & fname,
        if (!openFileWrite(ofs, fname))
                return;
 
+       // make sure we are ready to export
+       // this has to be done before we validate
+       updateBuffer(UpdateMaster, OutputUpdate);
+       updateMacroInstances(OutputUpdate);
+
        writeLyXHTMLSource(ofs, runparams, body_only);
 
        ofs.close();
@@ -1580,10 +1637,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
 {
        LaTeXFeatures features(*this, params(), runparams);
        validate(features);
-       updateBuffer(UpdateMaster, OutputUpdate);
        d->bibinfo_.makeCitationLabels(*this);
-       updateMacros();
-       updateMacroInstances();
 
        if (!only_body) {
                os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
@@ -1602,7 +1656,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
 
                os << "\n<!-- Text Class Preamble -->\n"
                   << features.getTClassHTMLPreamble()
-                  << "\n<!-- Premable Snippets -->\n"
+                  << "\n<!-- Preamble Snippets -->\n"
                   << from_utf8(features.getPreambleSnippets());
 
                os << "\n<!-- Layout-provided Styles -->\n";
@@ -1669,8 +1723,6 @@ void Buffer::validate(LaTeXFeatures & features) const
 {
        params().validate(features);
 
-       updateMacros();
-
        for_each(paragraphs().begin(), paragraphs().end(),
                 bind(&Paragraph::validate, _1, ref(features)));
 
@@ -1711,15 +1763,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<InsetBibtex const &>(*it);
+                       InsetBibtex const & inset = static_cast<InsetBibtex const &>(*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<InsetInclude &>(*it);
+                       InsetInclude & inset = static_cast<InsetInclude &>(*it);
                        Buffer const * const incbuf = inset.getChildBuffer();
                        if (!incbuf)
                                continue;
@@ -1734,12 +1784,14 @@ void Buffer::updateBibfilesCache(UpdateScope scope) const
        }
        d->bibfile_cache_valid_ = true;
        d->bibinfo_cache_valid_ = false;
+       d->cite_labels_valid_ = false;
 }
 
 
 void Buffer::invalidateBibinfoCache() const
 {
        d->bibinfo_cache_valid_ = false;
+       d->cite_labels_valid_ = false;
        // also invalidate the cache for the parent buffer
        Buffer const * const pbuf = d->parent();
        if (pbuf)
@@ -1751,6 +1803,7 @@ void Buffer::invalidateBibfileCache() const
 {
        d->bibfile_cache_valid_ = false;
        d->bibinfo_cache_valid_ = false;
+       d->cite_labels_valid_ = false;
        // also invalidate the cache for the parent buffer
        Buffer const * const pbuf = d->parent();
        if (pbuf)
@@ -1782,43 +1835,78 @@ 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];
                if (lastw != prevw) {
                        d->bibinfo_cache_valid_ = false;
+                       d->cite_labels_valid_ = false;
                        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;
+}
+
+
+bool Buffer::citeLabelsValid() const
+{
+       return masterBuffer()->d->cite_labels_valid_;
 }
 
 
@@ -1837,21 +1925,6 @@ void Buffer::markDepClean(string const & name)
 }
 
 
-bool Buffer::isExportableFormat(string const & format) const
-{
-               typedef vector<Format const *> Formats;
-               Formats formats;
-               formats = exportableFormats(true);
-               Formats::const_iterator fit = formats.begin();
-               Formats::const_iterator end = formats.end();
-               for (; fit != end ; ++fit) {
-                       if ((*fit)->name() == format)
-                               return true;
-               }
-               return false;
-}
-
-
 bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 {
        if (isInternal()) {
@@ -1880,7 +1953,7 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 
                case LFUN_BUFFER_EXPORT: {
                        docstring const arg = cmd.argument();
-                       enable = arg == "custom" || isExportable(to_utf8(arg));
+                       enable = arg == "custom" || params().isExportable(to_utf8(arg));
                        if (!enable)
                                flag.message(bformat(
                                        _("Don't know how to export to format: %1$s"), arg));
@@ -1888,11 +1961,11 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                }
 
                case LFUN_BUFFER_CHKTEX:
-                       enable = isLatex() && !lyxrc.chktex_command.empty();
+                       enable = params().isLatex() && !lyxrc.chktex_command.empty();
                        break;
 
                case LFUN_BUILD_PROGRAM:
-                       enable = isExportable("program");
+                       enable = params().isExportable("program");
                        break;
 
                case LFUN_BRANCH_ACTIVATE: 
@@ -2003,7 +2076,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
 
                // Execute the command in the background
                Systemcall call;
-               call.startscript(Systemcall::DontWait, command);
+               call.startscript(Systemcall::DontWait, command, filePath());
                break;
        }
 
@@ -2016,6 +2089,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
 
        case LFUN_BUFFER_AUTO_SAVE:
                autoSave();
+               resetAutosaveTimers();
                break;
 
        case LFUN_BRANCH_ADD: {
@@ -2089,7 +2163,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<InsetBranch &>(*it);
+                               InsetBranch & ins = static_cast<InsetBranch &>(*it);
                                if (ins.branch() == oldname) {
                                        undo().recordUndo(it);
                                        ins.rename(newname);
@@ -2180,7 +2254,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                command2 += quoteName(psname);
                                // First run dvips.
                                // If successful, then spool command
-                               res = one.startscript(Systemcall::Wait, command);
+                               res = one.startscript(Systemcall::Wait, command,
+                                                     filePath());
 
                                if (res == 0) {
                                        // If there's no GUI, we have to wait on this command. Otherwise,
@@ -2188,7 +2263,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                        // file, before it can be printed!!
                                        Systemcall::Starttype stype = use_gui ?
                                                Systemcall::DontWait : Systemcall::Wait;
-                                       res = one.startscript(stype, command2);
+                                       res = one.startscript(stype, command2,
+                                                             filePath());
                                }
                        } else {
                                // case 2: print directly to a printer
@@ -2197,7 +2273,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                // as above....
                                Systemcall::Starttype stype = use_gui ?
                                        Systemcall::DontWait : Systemcall::Wait;
-                               res = one.startscript(stype, command + quoteName(dviname));
+                               res = one.startscript(stype, command +
+                                               quoteName(dviname), filePath());
                        }
 
                } else {
@@ -2220,7 +2297,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                        // as above....
                        Systemcall::Starttype stype = use_gui ?
                                Systemcall::DontWait : Systemcall::Wait;
-                       res = one.startscript(stype, command);
+                       res = one.startscript(stype, command, filePath());
                }
 
                if (res == 0) 
@@ -2375,8 +2452,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();
@@ -2481,7 +2561,7 @@ Buffer const * Buffer::parent() const
 ListOfBuffers Buffer::allRelatives() const
 {
        ListOfBuffers lb = masterBuffer()->getDescendents();
-       lb.push_front(const_cast<Buffer *>(this));
+       lb.push_front(const_cast<Buffer *>(masterBuffer()));
        return lb;
 }
 
@@ -2622,7 +2702,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
@@ -2766,12 +2848,11 @@ void Buffer::Impl::updateMacros(DocIterator & it, DocIterator & scope)
                                continue;
                        }
 
-                       if (doing_export && iit->inset->asInsetMath()) {
-                               InsetMath * im = static_cast<InsetMath *>(iit->inset);
-                               if (im->asHullInset()) {
-                                       InsetMathHull * hull = static_cast<InsetMathHull *>(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)
@@ -2779,7 +2860,7 @@ void Buffer::Impl::updateMacros(DocIterator & it, DocIterator & scope)
 
                        // get macro data
                        MathMacroTemplate & macroTemplate =
-                               static_cast<MathMacroTemplate &>(*iit->inset);
+                               *iit->inset->asInsetMath()->asMacroTemplate();
                        MacroContext mc(owner_, it);
                        macroTemplate.updateToContext(mc);
 
@@ -2834,7 +2915,7 @@ void Buffer::getUsedBranches(std::list<docstring> & 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<InsetBranch &>(*it);
+                       InsetBranch & br = static_cast<InsetBranch &>(*it);
                        docstring const name = br.branch();
                        if (!from_master && !params().branchlist().find(name))
                                result.push_back(name);
@@ -2857,7 +2938,7 @@ void Buffer::getUsedBranches(std::list<docstring> & result, bool const from_mast
 }
 
 
-void Buffer::updateMacroInstances() const
+void Buffer::updateMacroInstances(UpdateType utype) const
 {
        LYXERR(Debug::MACROS, "updateMacroInstances for "
                << d->filename.onlyFileName());
@@ -2875,7 +2956,7 @@ void Buffer::updateMacroInstances() const
                MacroContext mc = MacroContext(this, it);
                for (DocIterator::idx_type i = 0; i < n; ++i) {
                        MathData & data = minset->cell(i);
-                       data.updateMacros(0, mc);
+                       data.updateMacros(0, mc, utype);
                }
        }
 }
@@ -2985,40 +3066,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<docstring> labels;
-       string paramName;
-       checkBibInfoCache();
        BiblioInfo const & keys = masterBibInfo();
        BiblioInfo::const_iterator bit  = keys.begin();
        BiblioInfo::const_iterator bend = keys.end();
+       vector<docstring> 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<InsetCommand &>(*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(&params().encoding());
        runparams.nice = true;
-       runparams.flavor = params().useXetex ? 
-               OutputParams::XETEX : OutputParams::LATEX;
+       runparams.flavor = params().getOutputFlavor(format);
        runparams.linelen = lyxrc.plaintext_linelen;
        // No side effect of file copying and image conversion
        runparams.dryrun = true;
@@ -3028,11 +3112,15 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin,
                d->texrow.reset();
                d->texrow.newline();
                d->texrow.newline();
-               if (isDocBook())
+               if (params().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;
@@ -3052,11 +3140,16 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin,
                texrow.newline();
                texrow.newline();
                // output paragraphs
-               if (isDocBook())
+               if (params().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);
+               }
        }
 }
 
@@ -3219,13 +3312,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");
 }
 
 
@@ -3241,15 +3328,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);
 }
 
 
@@ -3271,56 +3352,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();
-}
-
-
-string Buffer::bufferFormat() const
-{
-       string format = params().documentClass().outputFormat();
-       if (format == "latex") {
-               if (params().useXetex)
-                       return "xetex";
-               if (params().encoding().package() == Encoding::japanese)
-                       return "platex";
-       }
-       return format;
-}
-
-
-string Buffer::getDefaultOutputFormat() const
-{
-       if (!params().defaultOutputFormat.empty()
-           && params().defaultOutputFormat != "default")
-               return params().defaultOutputFormat;
-       typedef vector<Format const *> Formats;
-       Formats formats = exportableFormats(true);
-       if (isDocBook()
-           || isLiterate()
-           || params().useXetex
-           || params().encoding().package() == Encoding::japanese) {
-               if (formats.empty())
-                       return string();
-               // return the first we find
-               return formats.front()->name();
+       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;
        }
-       return lyxrc.default_view_format;
 }
 
 
@@ -3346,6 +3407,11 @@ namespace {
 void Buffer::setExportStatus(bool e) const
 {
        d->doing_export = e;    
+       ListOfBuffers clist = getDescendents();
+       ListOfBuffers::const_iterator cit = clist.begin();
+       ListOfBuffers::const_iterator const cen = clist.end();
+       for (; cit != cen; ++cit)
+               (*cit)->d->doing_export = e;
 }
 
 
@@ -3364,13 +3430,15 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        runparams.flavor = OutputParams::LATEX;
        runparams.linelen = lyxrc.plaintext_linelen;
        runparams.includeall = includeall;
-       vector<string> backs = backends();
+       vector<string> backs = params().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<string>::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;
@@ -3386,13 +3454,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);
@@ -3400,9 +3472,6 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        filename = changeExtension(filename,
                                   formats.extension(backend_format));
 
-       // fix macros
-       updateMacroInstances();
-
        // Plain text backend
        if (backend_format == "text") {
                runparams.flavor = OutputParams::TEXT;
@@ -3423,22 +3492,26 @@ 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()) {
+       else if (params().isDocBook()) {
                runparams.nice = !put_in_tempdir;
                makeDocBookFile(FileName(filename), runparams);
        }
        // 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"),
@@ -3446,21 +3519,26 @@ 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")
-               ? "Build" : bufferFormat();
+               ? "Build" : params().bufferFormat();
        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] = 
@@ -3473,6 +3551,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
@@ -3486,7 +3568,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                // FIXME: There is a possibility of concurrent access to texrow
                // here from the main GUI thread that should be securized.
                d->cloned_buffer_->d->texrow = d->texrow;
-               string const error_type = bufferFormat();
+               string const error_type = params().bufferFormat();
                d->cloned_buffer_->d->errorLists[error_type] = d->errorLists[error_type];
        }
 
@@ -3568,100 +3650,72 @@ bool Buffer::preview(string const & format, bool includeall) const
 }
 
 
-bool Buffer::isExportable(string const & format) const
-{
-       vector<string> backs = backends();
-       for (vector<string>::const_iterator it = backs.begin();
-            it != backs.end(); ++it)
-               if (theConverters().isReachable(*it, format))
-                       return true;
-       return false;
-}
-
-
-vector<Format const *> Buffer::exportableFormats(bool only_viewable) const
+Buffer::ReadStatus Buffer::extractFromVC()
 {
-       vector<string> const backs = backends();
-       vector<Format const *> result =
-               theConverters().getReachable(backs[0], only_viewable, true);
-       for (vector<string>::const_iterator it = backs.begin() + 1;
-            it != backs.end(); ++it) {
-               vector<Format const *>  r =
-                       theConverters().getReachable(*it, only_viewable, false);
-               result.insert(result.end(), r.begin(), r.end());
-       }
-       return result;
-}
-
-
-vector<string> Buffer::backends() const
-{
-       vector<string> v;
-       v.push_back(bufferFormat());
-       // FIXME: Don't hardcode format names here, but use a flag
-       if (v.back() == "latex")
-               v.push_back("pdflatex");
-       v.push_back("xhtml");
-       v.push_back("text");
-       v.push_back("lyx");
-       return v;
-}
-
-
-Buffer::ReadStatus Buffer::readFromVC(FileName const & fn)
-{
-       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 res;
-               ReadStatus const ret_rf = readFile(emergencyFile);
-               if (res = (ret_rf == ReadSuccess))
+               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;
@@ -3670,15 +3724,15 @@ 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 const 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 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,
@@ -3687,9 +3741,17 @@ Buffer::ReadStatus Buffer::readAutosave(FileName const & fn)
        switch (ret)
        {
        case 0: {
-               ReadStatus const ret_rf = readFile(autosaveFile);
+               ReadStatus const ret_llf = loadThisLyXFile(autosaveFile);
                // the file is not saved if we load the autosave file.
-               if (ret_rf == ReadSuccess) {
+               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;
                }
@@ -3706,46 +3768,84 @@ 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;
        }
 
-       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;
 
+       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));
+               if (id_start != id_end) {
+                       // Next registered position is outside the inset where
+                       // the error occurred, so signal end-of-paragraph
+                       pos_end = 0;
+               }
+
+               errorList.push_back(ErrorItem(it->error_desc,
+                       it->error_text, id_start, pos_start, pos_end, buf));
        }
 }
 
@@ -3764,7 +3864,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.
@@ -3808,6 +3908,8 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
                // TocBackend update will be done later.
                return;
 
+       d->bibinfo_cache_valid_ = true;
+       d->cite_labels_valid_ = true;
        cbuf.tocBackend().update();
        if (scope == UpdateMaster)
                cbuf.structureChanged();
@@ -3914,11 +4016,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;
@@ -4088,32 +4190,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;
+       }
 }