]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
* ExternalSupport.cpp:
[lyx.git] / src / Buffer.cpp
index ec6aba54592cd2ff5eaab386b8c54cb6eacd977b..a068ecfe3a9c9e502cac0801395b4aaf56f09a83 100644 (file)
@@ -42,7 +42,6 @@
 #include "Lexer.h"
 #include "LyXAction.h"
 #include "LyX.h"
-#include "LyXFunc.h"
 #include "LyXRC.h"
 #include "LyXVC.h"
 #include "output_docbook.h"
@@ -73,6 +72,7 @@
 #include "insets/InsetInclude.h"
 #include "insets/InsetText.h"
 
+#include "mathed/InsetMathHull.h"
 #include "mathed/MacroTable.h"
 #include "mathed/MathMacroTemplate.h"
 #include "mathed/MathSupport.h"
 #include "support/textutils.h"
 #include "support/types.h"
 
-#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
+#include "support/bind.h"
+#include "support/shared_ptr.h"
 
 #include <algorithm>
 #include <fstream>
@@ -127,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 = 376; // jspitzm: support for unincluded file maintenance
+int const LYX_FORMAT = 400; // uwestoehr: support for \rule
 
 typedef map<string, bool> DepClean;
 typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
@@ -147,7 +147,7 @@ class BufferSet : public std::set<Buffer const *> {};
 class Buffer::Impl
 {
 public:
-       Impl(Buffer & parent, FileName const & file, bool readonly, Buffer const * cloned_buffer);
+       Impl(Buffer * owner, FileName const & file, bool readonly, Buffer const * cloned_buffer);
 
        ~Impl()
        {
@@ -157,6 +157,25 @@ public:
                }
                delete inset;
        }
+       
+       /// search for macro in local (buffer) table or in children
+       MacroData const * getBufferMacro(docstring const & name,
+               DocIterator const & pos) const;
+
+       /// Update macro table starting with position of it \param it in some
+       /// text inset.
+       void updateMacros(DocIterator & it, DocIterator & scope);
+       ///
+       void setLabel(ParIterator & it, UpdateType utype) const;
+       ///
+       void collectRelatives(BufferSet & bufs) const;
+
+       /** If we have branches that use the file suffix
+           feature, return the file name with suffix appended.
+       */
+       support::FileName exportFileName() const;
+
+       Buffer * owner_;
 
        BufferParams params;
        LyXVC lyxvc;
@@ -197,7 +216,8 @@ public:
        /// map from the macro name to the position map,
        /// which maps the macro definition position to the scope and the MacroData.
        NamePositionScopeMacroMap macros;
-       bool macro_lock;
+       /// This seem to change the way Buffer::getMacro() works
+       mutable bool macro_lock;
 
        /// positions of child buffers in the buffer
        typedef map<Buffer const * const, DocIterator> BufferPositionMap;
@@ -235,7 +255,9 @@ public:
        /// A cache for bibliography info
        mutable BiblioInfo bibinfo_;
        /// whether the bibinfo cache is valid
-       bool bibinfo_cache_valid_;
+       mutable bool bibinfo_cache_valid_;
+       /// whether the bibfile cache is valid
+       mutable bool bibfile_cache_valid_;
        /// Cache of timestamps of .bib files
        map<FileName, time_t> bibfile_status_;
 
@@ -257,17 +279,27 @@ public:
                        parent_buffer = 0;
                return parent_buffer; 
        }
+       
        ///
        void setParent(Buffer const * pb) {
-               if (parent_buffer && pb && parent_buffer != pb)
+               if (parent_buffer == pb)
+                       // nothing to do
+                       return;
+               if (!cloned_buffer_ && parent_buffer && pb)
                        LYXERR0("Warning: a buffer should not have two parents!");
                parent_buffer = pb;
+               if (!cloned_buffer_ && parent_buffer) {
+                       parent_buffer->invalidateBibfileCache();
+                       parent_buffer->invalidateBibinfoCache();
+               }
        }
 
        /// If non zero, this buffer is a clone of existing buffer \p cloned_buffer_
        /// This one is useful for preview detached in a thread.
        Buffer const * cloned_buffer_;
-
+       /// are we in the process of exporting this buffer?
+       mutable bool doing_export;
+       
 private:
        /// So we can force access via the accessors.
        mutable Buffer const * parent_buffer;
@@ -282,29 +314,30 @@ static FileName createBufferTmpDir()
        // We are in our own directory.  Why bother to mangle name?
        // In fact I wrote this code to circumvent a problematic behaviour
        // (bug?) of EMX mkstemp().
-       FileName tmpfl(package().temp_dir().absFilename() + "/lyx_tmpbuf" +
+       FileName tmpfl(package().temp_dir().absFileName() + "/lyx_tmpbuf" +
                convert<string>(count++));
 
        if (!tmpfl.createDirectory(0777)) {
                throw ExceptionMessage(WarningException, _("Disk Error: "), bformat(
                        _("LyX could not create the temporary directory '%1$s' (Disk is full maybe?)"),
-                       from_utf8(tmpfl.absFilename())));
+                       from_utf8(tmpfl.absFileName())));
        }
        return tmpfl;
 }
 
 
-Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_,
+Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
        Buffer const * cloned_buffer)
-       : lyx_clean(true), bak_clean(true), unnamed(false),
+       : owner_(owner), lyx_clean(true), bak_clean(true), unnamed(false),
          read_only(readonly_), filename(file), file_fully_loaded(false),
-         toc_backend(&parent), macro_lock(false), timestamp_(0),
-         checksum_(0), wa_(0), gui_(0), undo_(parent), bibinfo_cache_valid_(false),
-         cloned_buffer_(cloned_buffer), parent_buffer(0)
+         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)
 {
        if (!cloned_buffer_) {
                temppath = createBufferTmpDir();
-               lyxvc.setBuffer(&parent);
+               lyxvc.setBuffer(owner_);
                if (use_gui)
                        wa_ = new frontend::WorkAreaManager;
                return;
@@ -315,12 +348,13 @@ Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_,
        bibfiles_cache_ = cloned_buffer_->d->bibfiles_cache_;
        bibinfo_ = cloned_buffer_->d->bibinfo_;
        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_;
 }
 
 
 Buffer::Buffer(string const & file, bool readonly, Buffer const * cloned_buffer)
-       : d(new Impl(*this, FileName(file), readonly, cloned_buffer))
+       : d(new Impl(this, FileName(file), readonly, cloned_buffer))
 {
        LYXERR(Debug::INFO, "Buffer::Buffer()");
        if (cloned_buffer) {
@@ -379,11 +413,12 @@ Buffer::~Buffer()
        if (!d->cloned_buffer_ && !d->temppath.destroyDirectory()) {
                Alert::warning(_("Could not remove temporary directory"),
                        bformat(_("Could not remove the temporary directory %1$s"),
-                       from_utf8(d->temppath.absFilename())));
+                       from_utf8(d->temppath.absFileName())));
        }
 
        // Remove any previewed LaTeX snippets associated with this buffer.
-       thePreviews().removeLoader(*this);
+       if (!isClone())
+               thePreviews().removeLoader(*this);
 
        delete d;
 }
@@ -391,7 +426,7 @@ Buffer::~Buffer()
 
 Buffer * Buffer::clone() const
 {
-       Buffer * buffer_clone = new Buffer(fileName().absFilename(), false, this);
+       Buffer * buffer_clone = new Buffer(fileName().absFileName(), false, this);
        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
@@ -487,7 +522,7 @@ LyXVC const & Buffer::lyxvc() const
 
 string const Buffer::temppath() const
 {
-       return d->temppath.absFilename();
+       return d->temppath.absFileName();
 }
 
 
@@ -524,23 +559,23 @@ void Buffer::setChild(DocIterator const & dit, Buffer * child)
 string Buffer::latexName(bool const no_path) const
 {
        FileName latex_name =
-               makeLatexName(exportFileName());
+               makeLatexName(d->exportFileName());
        return no_path ? latex_name.onlyFileName()
-               : latex_name.absFilename();
+               : latex_name.absFileName();
 }
 
 
-FileName Buffer::exportFileName() const
+FileName Buffer::Impl::exportFileName() const
 {
        docstring const branch_suffix =
-               params().branchlist().getFilenameSuffix();
+               params.branchlist().getFileNameSuffix();
        if (branch_suffix.empty())
-               return fileName();
+               return filename;
 
-       string const name = fileName().onlyFileNameWithoutExt()
+       string const name = filename.onlyFileNameWithoutExt()
                + to_utf8(branch_suffix);
-       FileName res(fileName().onlyPath().absFilename() + "/" + name);
-       res.changeExtension(fileName().extension());
+       FileName res(filename.onlyPath().absFileName() + "/" + name);
+       res.changeExtension(filename.extension());
 
        return res;
 }
@@ -559,12 +594,12 @@ string Buffer::logName(LogType * type) const
        string const path = temppath();
 
        FileName const fname(addName(temppath(),
-                                    onlyFilename(changeExtension(filename,
+                                    onlyFileName(changeExtension(filename,
                                                                  ".log"))));
 
        // FIXME: how do we know this is the name of the build log?
        FileName const bname(
-               addName(path, onlyFilename(
+               addName(path, onlyFileName(
                        changeExtension(filename,
                                        formats.extension(bufferFormat()) + ".out"))));
 
@@ -584,7 +619,7 @@ string Buffer::logName(LogType * type) const
                LYXERR(Debug::FILES, "Log name calculated as: " << bname);
                if (type)
                        *type = buildlog;
-               return bname.absFilename();
+               return bname.absFileName();
        // If we have a newer master file log or only a master log, show this
        } else if (fname != masterfname
                   && (!fname.exists() && (masterfname.exists()
@@ -592,12 +627,12 @@ string Buffer::logName(LogType * type) const
                LYXERR(Debug::FILES, "Log name calculated as: " << masterfname);
                if (type)
                        *type = mtype;
-               return masterfname.absFilename();
+               return masterfname.absFileName();
        }
        LYXERR(Debug::FILES, "Log name calculated as: " << fname);
        if (type)
                        *type = latexlog;
-       return fname.absFilename();
+       return fname.absFileName();
 }
 
 
@@ -648,6 +683,15 @@ int Buffer::readHeader(Lexer & lex)
        params().pdfoptions().clear();
        params().indiceslist().clear();
        params().backgroundcolor = lyx::rgbFromHexName("#ffffff");
+       params().isbackgroundcolor = false;
+       params().fontcolor = lyx::rgbFromHexName("#000000");
+       params().isfontcolor = false;
+       params().notefontcolor = lyx::rgbFromHexName("#cccccc");
+       params().boxbgcolor = lyx::rgbFromHexName("#ff0000");
+       params().html_latex_start.clear();
+       params().html_latex_end.clear();
+       params().html_math_img_scale = 1.0;
+       params().output_sync_macro.erase();
 
        for (int i = 0; i < 4; ++i) {
                params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i];
@@ -746,7 +790,7 @@ bool Buffer::readDocument(Lexer & lex)
        if (!params().master.empty()) {
                FileName const master_file = makeAbsPath(params().master,
                           onlyPath(absFileName()));
-               if (isLyXFilename(master_file.absFilename())) {
+               if (isLyXFileName(master_file.absFileName())) {
                        Buffer * master = 
                                checkAndLoadLyXFile(master_file, true);
                        if (master) {
@@ -852,7 +896,7 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
        if (!lex.checkFor("\\lyxformat")) {
                Alert::error(_("Document format failure"),
                             bformat(_("%1$s is not a readable LyX document."),
-                                      from_utf8(filename.absFilename())));
+                                      from_utf8(filename.absFileName())));
                return failure;
        }
 
@@ -874,7 +918,7 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
                // 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();
+               string diskfile = filename.absFileName();
                if (suffixIs(diskfile, ".emergency"))
                        diskfile = diskfile.substr(0, diskfile.size() - 10);
                saveCheckSum(FileName(diskfile));
@@ -893,7 +937,7 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
                                              " version of LyX, but a temporary"
                                              " file for converting it could"
                                              " not be created."),
-                                             from_utf8(filename.absFilename())));
+                                             from_utf8(filename.absFileName())));
                        return failure;
                }
                FileName const lyx2lyx = libFileSearch("lyx2lyx", "lyx2lyx");
@@ -903,7 +947,7 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
                                               " version of LyX, but the"
                                               " conversion script lyx2lyx"
                                               " could not be found."),
-                                              from_utf8(filename.absFilename())));
+                                              from_utf8(filename.absFileName())));
                        return failure;
                }
                ostringstream command;
@@ -911,7 +955,7 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
                        << ' ' << quoteName(lyx2lyx.toFilesystemEncoding())
                        << " -t " << convert<string>(LYX_FORMAT)
                        << " -o " << quoteName(tmpfile.toFilesystemEncoding())
-                       << ' ' << quoteName(filename.toFilesystemEncoding());
+                       << ' ' << quoteName(filename.toSafeFilesystemEncoding());
                string const command_str = command.str();
 
                LYXERR(Debug::INFO, "Running '" << command_str << '\'');
@@ -923,13 +967,13 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
                                     bformat(_("%1$s is from an older version"
                                              " of LyX, but the lyx2lyx script"
                                              " failed to convert it."),
-                                             from_utf8(filename.absFilename())));
+                                             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())));
+                                             from_utf8(filename.absFileName())));
                        return failure;
                } else {
                        bool const ret = readFile(tmpfile);
@@ -943,7 +987,8 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
                Alert::error(_("Document format failure"),
                             bformat(_("%1$s ended unexpectedly, which means"
                                                    " that it is probably corrupted."),
-                                      from_utf8(filename.absFilename())));
+                                      from_utf8(filename.absFileName())));
+               return failure;
        }
 
        d->file_fully_loaded = true;
@@ -951,14 +996,23 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
 }
 
 
-// Should probably be moved to somewhere else: BufferView? LyXView?
+// Should probably be moved to somewhere else: BufferView? GuiView?
 bool Buffer::save() const
 {
+       // 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);
+               int const ret = Alert::prompt(_("Overwrite modified file?"),
+                       text, 1, 1, _("&Overwrite"), _("&Cancel"));
+               if (ret == 1)
+                       return false;
+       }
+
        // We don't need autosaves in the immediate future. (Asger)
        resetAutosaveTimers();
 
-       string const encodedFilename = d->filename.toFilesystemEncoding();
-
        FileName backupName;
        bool madeBackup = false;
 
@@ -967,32 +1021,22 @@ bool Buffer::save() const
                backupName = FileName(absFileName() + '~');
                if (!lyxrc.backupdir_path.empty()) {
                        string const mangledName =
-                               subst(subst(backupName.absFilename(), '/', '!'), ':', '!');
+                               subst(subst(backupName.absFileName(), '/', '!'), ':', '!');
                        backupName = FileName(addName(lyxrc.backupdir_path,
                                                      mangledName));
                }
-               if (fileName().copyTo(backupName)) {
+               // do not copy because of #6587
+               if (fileName().moveTo(backupName)) {
                        madeBackup = true;
                } else {
                        Alert::error(_("Backup failure"),
                                     bformat(_("Cannot create backup file %1$s.\n"
                                               "Please check whether the directory exists and is writeable."),
-                                            from_utf8(backupName.absFilename())));
+                                            from_utf8(backupName.absFileName())));
                        //LYXERR(Debug::DEBUG, "Fs error: " << fe.what());
                }
        }
 
-       // 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);
-               int const ret = Alert::prompt(_("Overwrite modified file?"),
-                       text, 1, 1, _("&Overwrite"), _("&Cancel"));
-               if (ret == 1)
-                       return false;
-       }
-
        if (writeFile(d->filename)) {
                markClean();
                return true;
@@ -1013,14 +1057,16 @@ bool Buffer::writeFile(FileName const & fname) const
        bool retval = false;
 
        docstring const str = bformat(_("Saving document %1$s..."),
-               makeDisplayPath(fname.absFilename()));
+               makeDisplayPath(fname.absFileName()));
        message(str);
 
+       string const encoded_fname = fname.toSafeFilesystemEncoding(os::CREATE);
+
        if (params().compressed) {
-               gz::ogzstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
+               gz::ogzstream ofs(encoded_fname.c_str(), ios::out|ios::trunc);
                retval = ofs && write(ofs);
        } else {
-               ofstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
+               ofstream ofs(encoded_fname.c_str(), ios::out|ios::trunc);
                retval = ofs && write(ofs);
        }
 
@@ -1029,7 +1075,8 @@ bool Buffer::writeFile(FileName const & fname) const
                return false;
        }
 
-       removeAutosaveFile();
+       // see bug 6587
+       // removeAutosaveFile();
 
        saveCheckSum(d->filename);
        message(str + _(" done."));
@@ -1044,7 +1091,7 @@ docstring Buffer::emergencyWrite()
        if (isClean())
                return docstring();
 
-       string const doc = isUnnamed() ? onlyFilename(absFileName()) : absFileName();
+       string const doc = isUnnamed() ? onlyFileName(absFileName()) : absFileName();
 
        docstring user_message = bformat(
                _("LyX: Attempting to save document %1$s\n"), from_utf8(doc));
@@ -1065,7 +1112,7 @@ docstring Buffer::emergencyWrite()
        }
 
        // 2) In HOME directory.
-       string s = addName(package().home_dir().absFilename(), absFileName());
+       string s = addName(package().home_dir().absFileName(), absFileName());
        s += ".emergency";
        lyxerr << ' ' << s << endl;
        if (writeFile(FileName(s))) {
@@ -1079,7 +1126,7 @@ docstring Buffer::emergencyWrite()
        // 3) In "/tmp" directory.
        // MakeAbsPath to prepend the current
        // drive letter on OS/2
-       s = addName(package().temp_dir().absFilename(), absFileName());
+       s = addName(package().temp_dir().absFileName(), absFileName());
        s += ".emergency";
        lyxerr << ' ' << s << endl;
        if (writeFile(FileName(s))) {
@@ -1288,14 +1335,41 @@ void Buffer::writeLaTeXSource(odocstream & os,
                if (!original_path.empty()) {
                        // FIXME UNICODE
                        // We don't know the encoding of inputpath
-                       docstring const inputpath = from_utf8(latex_path(original_path));
-                       os << "\\makeatletter\n"
-                          << "\\def\\input@path{{"
-                          << inputpath << "/}}\n"
-                          << "\\makeatother\n";
-                       d->texrow.newline();
-                       d->texrow.newline();
-                       d->texrow.newline();
+                       docstring const inputpath = from_utf8(support::latex_path(original_path));
+                       docstring uncodable_glyphs;
+                       Encoding const * const enc = runparams.encoding;
+                       if (enc) {
+                               for (size_t n = 0; n < inputpath.size(); ++n) {
+                                       docstring const glyph =
+                                               docstring(1, inputpath[n]);
+                                       if (enc->latexChar(inputpath[n], true) != glyph) {
+                                               LYXERR0("Uncodable character '"
+                                                       << glyph
+                                                       << "' in input path!");
+                                               uncodable_glyphs += glyph;
+                                       }
+                               }
+                       }
+
+                       // warn user if we found uncodable glyphs.
+                       if (!uncodable_glyphs.empty()) {
+                               frontend::Alert::warning(_("Uncodable character in file path"),
+                                               support::bformat(_("The path of your document\n"
+                                                 "(%1$s)\n"
+                                                 "contains glyphs that are unknown in the\n"
+                                                 "current document encoding (namely %2$s).\n"
+                                                 "This will likely result in incomplete output.\n\n"
+                                                 "Choose an appropriate document encoding (such as utf8)\n"
+                                                 "or change the file path name."), inputpath, uncodable_glyphs));
+                       } else {
+                               os << "\\makeatletter\n"
+                                  << "\\def\\input@path{{"
+                                  << inputpath << "/}}\n"
+                                  << "\\makeatother\n";
+                               d->texrow.newline();
+                               d->texrow.newline();
+                               d->texrow.newline();
+                       }
                }
 
                // get parent macros (if this buffer has a parent) which will be
@@ -1320,8 +1394,11 @@ void Buffer::writeLaTeXSource(odocstream & os,
                // output the parent macros
                MacroSet::iterator it = parentMacros.begin();
                MacroSet::iterator end = parentMacros.end();
-               for (; it != end; ++it)
-                       (*it)->write(os, true);
+               for (; it != end; ++it) {
+                       int num_lines = (*it)->write(os, true);
+                       d->texrow.newlines(num_lines);
+               }
+               
        } // output_preamble
 
        d->texrow.start(paragraphs().begin()->id(), 0);
@@ -1360,6 +1437,12 @@ void Buffer::writeLaTeXSource(odocstream & os,
        // Just to be sure. (Asger)
        d->texrow.newline();
 
+       //for (int i = 0; i<d->texrow.rows(); i++) {
+       // int id,pos;
+       // if (d->texrow.getIdFromRow(i+1,id,pos) && id>0)
+       //      lyxerr << i+1 << ":" << id << ":" << getParFromID(id).paragraph().asString()<<"\n";
+       //}
+
        LYXERR(Debug::INFO, "Finished making LaTeX file.");
        LYXERR(Debug::INFO, "Row count was " << d->texrow.rows() - 1 << '.');
 }
@@ -1393,7 +1476,7 @@ void Buffer::makeDocBookFile(FileName const & fname,
        if (!openFileWrite(ofs, fname))
                return;
 
-       writeDocBookSource(ofs, fname.absFilename(), runparams, body_only);
+       writeDocBookSource(ofs, fname.absFileName(), runparams, body_only);
 
        ofs.close();
        if (ofs.fail())
@@ -1500,26 +1583,30 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
 {
        LaTeXFeatures features(*this, params(), runparams);
        validate(features);
-       updateLabels(UpdateMaster, OutputUpdate);
-       checkBibInfoCache();
+       updateBuffer(UpdateMaster, OutputUpdate);
        d->bibinfo_.makeCitationLabels(*this);
        updateMacros();
        updateMacroInstances();
 
        if (!only_body) {
-               os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
-               os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\" \"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd\">\n";
-               // FIXME Language should be set properly.
-               os << "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
-               os << "<head>\n";
-               // FIXME Presumably need to set this right
-               os << "<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n";
-               os << "<title>" << features.htmlTitle() << "</title>\n";
+               os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                  << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\" \"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd\">\n"
+                  // FIXME Language should be set properly.
+                  << "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
+                  << "<head>\n"
+                  << "<meta name=\"GENERATOR\" content=\"" << PACKAGE_STRING << "\" />\n"
+                  // FIXME Presumably need to set this right
+                  << "<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n";
+
+               docstring const & doctitle = features.htmlTitle();
+               os << "<title>"
+                  << (doctitle.empty() ? from_ascii("LyX Document") : doctitle)
+                  << "</title>\n";
 
                os << "\n<!-- Text Class Preamble -->\n"
-                       << features.getTClassHTMLPreamble()
-                       << "\n<!-- Premable Snippets -->\n"
-                       << from_utf8(features.getPreambleSnippets());
+                  << features.getTClassHTMLPreamble()
+                  << "\n<!-- Premable Snippets -->\n"
+                  << from_utf8(features.getPreambleSnippets());
 
                os << "\n<!-- Layout-provided Styles -->\n";
                docstring const styleinfo = features.getTClassHTMLStyles();
@@ -1547,7 +1634,7 @@ int Buffer::runChktex()
 
        // get LaTeX-Filename
        FileName const path(temppath());
-       string const name = addName(path.absFilename(), latexName());
+       string const name = addName(path.absFileName(), latexName());
        string const org_path = filePath();
 
        PathChanger p(path); // path to LaTeX file
@@ -1557,10 +1644,11 @@ int Buffer::runChktex()
        OutputParams runparams(&params().encoding());
        runparams.flavor = OutputParams::LATEX;
        runparams.nice = false;
+       runparams.linelen = lyxrc.plaintext_linelen;
        makeLaTeXFile(FileName(name), org_path, runparams);
 
        TeXErrors terr;
-       Chktex chktex(lyxrc.chktex_command, onlyFilename(name), filePath());
+       Chktex chktex(lyxrc.chktex_command, onlyFileName(name), filePath());
        int const res = chktex.run(terr); // run chktex
 
        if (res == -1) {
@@ -1587,7 +1675,7 @@ void Buffer::validate(LaTeXFeatures & features) const
        updateMacros();
 
        for_each(paragraphs().begin(), paragraphs().end(),
-                boost::bind(&Paragraph::validate, _1, boost::ref(features)));
+                bind(&Paragraph::validate, _1, ref(features)));
 
        if (lyxerr.debugging(Debug::LATEX)) {
                features.showStruct();
@@ -1617,6 +1705,7 @@ void Buffer::getLabelList(vector<docstring> & list) const
 
 void Buffer::updateBibfilesCache(UpdateScope scope) const
 {
+       // FIXME This is probably unnecssary, given where we call this.
        // If this is a child document, use the parent's cache instead.
        Buffer const * const pbuf = d->parent();
        if (pbuf && scope != UpdateChildOnly) {
@@ -1636,35 +1725,54 @@ void Buffer::updateBibfilesCache(UpdateScope scope) const
                } else if (it->lyxCode() == INCLUDE_CODE) {
                        InsetInclude & inset =
                                static_cast<InsetInclude &>(*it);
-                       inset.updateBibfilesCache();
+                       Buffer const * const incbuf = inset.getChildBuffer();
+                       if (!incbuf)
+                               continue;
                        support::FileNameList const & bibfiles =
-                                       inset.getBibfilesCache();
-                       d->bibfiles_cache_.insert(d->bibfiles_cache_.end(),
-                               bibfiles.begin(),
-                               bibfiles.end());
+                                       incbuf->getBibfilesCache(UpdateChildOnly);
+                       if (!bibfiles.empty()) {
+                               d->bibfiles_cache_.insert(d->bibfiles_cache_.end(),
+                                       bibfiles.begin(),
+                                       bibfiles.end());
+                       }
                }
        }
-       // the bibinfo cache is now invalid
+       d->bibfile_cache_valid_ = true;
+       d->bibinfo_cache_valid_ = false;
+}
+
+
+void Buffer::invalidateBibinfoCache() const
+{
        d->bibinfo_cache_valid_ = false;
+       // also invalidate the cache for the parent buffer
+       Buffer const * const pbuf = d->parent();
+       if (pbuf)
+               pbuf->invalidateBibinfoCache();
 }
 
 
-void Buffer::invalidateBibinfoCache()
+void Buffer::invalidateBibfileCache() const
 {
+       d->bibfile_cache_valid_ = false;
        d->bibinfo_cache_valid_ = false;
+       // also invalidate the cache for the parent buffer
+       Buffer const * const pbuf = d->parent();
+       if (pbuf)
+               pbuf->invalidateBibfileCache();
 }
 
 
 support::FileNameList const & Buffer::getBibfilesCache(UpdateScope scope) const
 {
-       // If this is a child document, use the parent's cache instead.
-       Buffer const * const pbuf = d->parent();
-       if (pbuf && scope != UpdateChildOnly)
+       // FIXME This is probably unnecessary, given where we call this.
+       // If this is a child document, use the master's cache instead.
+       Buffer const * const pbuf = masterBuffer();
+       if (pbuf != this && scope != UpdateChildOnly)
                return pbuf->getBibfilesCache();
 
-       // We update the cache when first used instead of at loading time.
-       if (d->bibfiles_cache_.empty())
-               const_cast<Buffer *>(this)->updateBibfilesCache(scope);
+       if (!d->bibfile_cache_valid_)
+               this->updateBibfilesCache(scope);
 
        return d->bibfiles_cache_;
 }
@@ -1672,28 +1780,28 @@ support::FileNameList const & Buffer::getBibfilesCache(UpdateScope scope) const
 
 BiblioInfo const & Buffer::masterBibInfo() const
 {
-       // if this is a child document and the parent is already loaded
-       // use the parent's list instead  [ale990412]
        Buffer const * const tmp = masterBuffer();
-       LASSERT(tmp, /**/);
        if (tmp != this)
                return tmp->masterBibInfo();
-       return localBibInfo();
-}
-
-
-BiblioInfo const & Buffer::localBibInfo() const
-{
        return d->bibinfo_;
 }
 
 
 void Buffer::checkBibInfoCache() const 
 {
-       support::FileNameList const & bibfilesCache = getBibfilesCache();
+       // use the master's cache
+       Buffer const * const tmp = masterBuffer();
+       if (tmp != this) {
+               tmp->checkBibInfoCache();
+               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 = bibfilesCache.begin();
-       support::FileNameList::const_iterator en = bibfilesCache.end();
+       support::FileNameList::const_iterator ei = bibfiles_cache.begin();
+       support::FileNameList::const_iterator en = bibfiles_cache.end();
        for (; ei != en; ++ ei) {
                time_t lastw = ei->lastModified();
                time_t prevw = d->bibfile_status_[*ei];
@@ -1702,13 +1810,20 @@ void Buffer::checkBibInfoCache() const
                        d->bibfile_status_[*ei] = lastw;
                }
        }
-
+       
+       // if not valid, then reload the info
        if (!d->bibinfo_cache_valid_) {
                d->bibinfo_.clear();
-               for (InsetIterator it = inset_iterator_begin(inset()); it; ++it)
-                       it->fillWithBibKeys(d->bibinfo_, it);
+               fillWithBibKeys(d->bibinfo_);
                d->bibinfo_cache_valid_ = true;
-       }       
+       }
+}
+
+
+void Buffer::fillWithBibKeys(BiblioInfo & keys) const
+{
+       for (InsetIterator it = inset_iterator_begin(inset()); it; ++it)
+               it->fillWithBibKeys(keys, it);
 }
 
 
@@ -1752,7 +1867,7 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 
        bool enable = true;
 
-       switch (cmd.action) {
+       switch (cmd.action()) {
 
                case LFUN_BUFFER_TOGGLE_READ_ONLY:
                        flag.setOnOff(isReadonly());
@@ -1824,7 +1939,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
 {
        if (isInternal()) {
                // FIXME? if there is an Buffer LFUN that can be dispatched even
-               // if internal, put a switch '(cmd.action)' here.
+               // if internal, put a switch '(cmd.action())' here.
                dr.dispatched(false);
                return;
        }
@@ -1833,7 +1948,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
        bool dispatched = true;
        undo().beginUndoGroup();
 
-       switch (func.action) {
+       switch (func.action()) {
        case LFUN_BUFFER_TOGGLE_READ_ONLY:
                if (lyxvc().inUse())
                        lyxvc().toggleReadOnly();
@@ -1843,7 +1958,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
 
        case LFUN_BUFFER_EXPORT: {
                bool success = doExport(argument, false, false);
-               dr.setError(success);
+               dr.setError(!success);
                if (!success)
                        dr.setMessage(bformat(_("Error exporting to format: %1$s."), 
                                              func.argument()));
@@ -1909,28 +2024,37 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
 
        case LFUN_BRANCH_ADD: {
-               docstring const branch_name = func.argument();
+               docstring branch_name = func.argument();
                if (branch_name.empty()) {
                        dispatched = false;
                        break;
                }
                BranchList & branch_list = params().branchlist();
-               Branch * branch = branch_list.find(branch_name);
-               if (branch) {
-                       LYXERR0("Branch " << branch_name << " already exists.");
-                       dr.setError(true);
-                       docstring const msg = 
-                               bformat(_("Branch \"%1$s\" already exists."), branch_name);
-                       dr.setMessage(msg);
-               } else {
-                       branch_list.add(branch_name);
-                       branch = branch_list.find(branch_name);
-                       string const x11hexname = X11hexname(branch->color());
-                       docstring const str = branch_name + ' ' + from_ascii(x11hexname);
-                       lyx::dispatch(FuncRequest(LFUN_SET_COLOR, str));        
-                       dr.setError(false);
-                       dr.update(Update::Force);
+               vector<docstring> const branches =
+                       getVectorFromString(branch_name, branch_list.separator());
+               docstring msg;
+               for (vector<docstring>::const_iterator it = branches.begin();
+                    it != branches.end(); ++it) {
+                       branch_name = *it;
+                       Branch * branch = branch_list.find(branch_name);
+                       if (branch) {
+                               LYXERR0("Branch " << branch_name << " already exists.");
+                               dr.setError(true);
+                               if (!msg.empty())
+                                       msg += ("\n");
+                               msg += bformat(_("Branch \"%1$s\" already exists."), branch_name);
+                       } else {
+                               branch_list.add(branch_name);
+                               branch = branch_list.find(branch_name);
+                               string const x11hexname = X11hexname(branch->color());
+                               docstring const str = branch_name + ' ' + from_ascii(x11hexname);
+                               lyx::dispatch(FuncRequest(LFUN_SET_COLOR, str));
+                               dr.setError(false);
+                               dr.update(Update::Force);
+                       }
                }
+               if (!msg.empty())
+                       dr.setMessage(msg);
                break;
        }
 
@@ -1951,9 +2075,10 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                bformat(_("Branch \"%1$s\" does not exist."), branchName);
                        dr.setMessage(msg);
                } else {
-                       branch->setSelected(func.action == LFUN_BRANCH_ACTIVATE);
+                       branch->setSelected(func.action() == LFUN_BRANCH_ACTIVATE);
                        dr.setError(false);
                        dr.update(Update::Force);
+                       dr.forceBufferUpdate();
                }
                break;
        }
@@ -1988,8 +2113,10 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                        }
                }
 
-               if (success)
+               if (success) {
                        dr.update(Update::Force);
+                       dr.forceBufferUpdate();
+               }
                break;
        }
 
@@ -2086,7 +2213,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                docstring text = bformat(
                                        _("The file %1$s already exists.\n\n"
                                          "Do you want to overwrite that file?"),
-                                       makeDisplayPath(filename.absFilename()));
+                                       makeDisplayPath(filename.absFileName()));
                                if (Alert::prompt(_("Overwrite file?"),
                                                  text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
                                        break;
@@ -2115,8 +2242,10 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                Language const * newL = languages.getLanguage(argument);
                if (!newL || oldL == newL)
                        break;
-               if (oldL->rightToLeft() == newL->rightToLeft() && !isMultiLingual())
+               if (oldL->rightToLeft() == newL->rightToLeft() && !isMultiLingual()) {
                        changeLanguage(oldL, newL);
+                       dr.forceBufferUpdate();
+               }
                break;
        }
 
@@ -2151,6 +2280,30 @@ bool Buffer::isMultiLingual() const
 }
 
 
+std::set<Language const *> Buffer::getLanguages() const
+{
+       std::set<Language const *> languages;
+       getLanguages(languages);
+       return languages;
+}
+
+
+void Buffer::getLanguages(std::set<Language const *> & languages) const
+{
+       ParConstIterator end = par_iterator_end();
+       // add the buffer language, even if it's not actively used
+       languages.insert(language());
+       // iterate over the paragraphs
+       for (ParConstIterator it = par_iterator_begin(); it != end; ++it)
+               it->getLanguages(languages);
+       // also children
+       std::vector<Buffer *> clist = getChildren();
+       for (vector<Buffer *>::const_iterator cit = clist.begin();
+            cit != clist.end(); ++cit)
+               (*cit)->getLanguages(languages);
+}
+
+
 DocIterator Buffer::getParFromID(int const id) const
 {
        Buffer * buf = const_cast<Buffer *>(this);
@@ -2248,6 +2401,7 @@ void Buffer::markClean() const
        // if the .lyx file has been saved, we don't need an
        // autosave
        d->bak_clean = true;
+       d->undo_.markDirty();
 }
 
 
@@ -2298,13 +2452,13 @@ FileName Buffer::fileName() const
 
 string Buffer::absFileName() const
 {
-       return d->filename.absFilename();
+       return d->filename.absFileName();
 }
 
 
 string Buffer::filePath() const
 {
-       return d->filename.onlyPath().absFilename() + "/";
+       return d->filename.onlyPath().absFileName() + "/";
 }
 
 
@@ -2328,15 +2482,15 @@ Buffer const * Buffer::parent() const
 }
 
 
-void Buffer::collectRelatives(BufferSet & bufs) const
+void Buffer::Impl::collectRelatives(BufferSet & bufs) const
 {
-       bufs.insert(this);
+       bufs.insert(owner_);
        if (parent())
-               parent()->collectRelatives(bufs);
+               parent()->d->collectRelatives(bufs);
 
        // loop over children
-       Impl::BufferPositionMap::iterator it = d->children_positions.begin();
-       Impl::BufferPositionMap::iterator end = d->children_positions.end();
+       BufferPositionMap::const_iterator it = children_positions.begin();
+       BufferPositionMap::const_iterator end = children_positions.end();
        for (; it != end; ++it)
                bufs.insert(const_cast<Buffer *>(it->first));
 }
@@ -2345,7 +2499,7 @@ void Buffer::collectRelatives(BufferSet & bufs) const
 std::vector<Buffer const *> Buffer::allRelatives() const
 {
        BufferSet bufs;
-       collectRelatives(bufs);
+       d->collectRelatives(bufs);
        BufferSet::iterator it = bufs.begin();
        std::vector<Buffer const *> ret;
        for (; it != bufs.end(); ++it)
@@ -2390,30 +2544,28 @@ void Buffer::getChildren(std::vector<Buffer *> & clist, bool grand_children) con
                clist.push_back(child);
                if (grand_children) {
                        // there might be grandchildren
-                       std::vector<Buffer *> glist = child->getChildren();
-                       for (vector<Buffer *>::const_iterator git = glist.begin();
-                                git != glist.end(); ++git)
-                               clist.push_back(*git);
+                       vector<Buffer *> glist = child->getChildren();
+                       clist.insert(clist.end(), glist.begin(), glist.end());
                }
        }
 }
 
 
-std::vector<Buffer *> Buffer::getChildren(bool grand_children) const
+vector<Buffer *> Buffer::getChildren(bool grand_children) const
 {
-       std::vector<Buffer *> v;
+       vector<Buffer *> v;
        getChildren(v, grand_children);
        return v;
 }
 
 
 template<typename M>
-typename M::iterator greatest_below(M & m, typename M::key_type const & x)
+typename M::const_iterator greatest_below(M & m, typename M::key_type const & x)
 {
        if (m.empty())
                return m.end();
 
-       typename M::iterator it = m.lower_bound(x);
+       typename M::const_iterator it = m.lower_bound(x);
        if (it == m.begin())
                return m.end();
 
@@ -2422,7 +2574,7 @@ typename M::iterator greatest_below(M & m, typename M::key_type const & x)
 }
 
 
-MacroData const * Buffer::getBufferMacro(docstring const & name,
+MacroData const * Buffer::Impl::getBufferMacro(docstring const & name,
                                         DocIterator const & pos) const
 {
        LYXERR(Debug::MACROS, "Searching for " << to_ascii(name) << " at " << pos);
@@ -2432,15 +2584,14 @@ MacroData const * Buffer::getBufferMacro(docstring const & name,
                return 0;
 
        // we haven't found anything yet
-       DocIterator bestPos = par_iterator_begin();
+       DocIterator bestPos = owner_->par_iterator_begin();
        MacroData const * bestData = 0;
 
        // find macro definitions for name
-       Impl::NamePositionScopeMacroMap::iterator nameIt
-               = d->macros.find(name);
-       if (nameIt != d->macros.end()) {
+       NamePositionScopeMacroMap::const_iterator nameIt = macros.find(name);
+       if (nameIt != macros.end()) {
                // find last definition in front of pos or at pos itself
-               Impl::PositionScopeMacroMap::const_iterator it
+               PositionScopeMacroMap::const_iterator it
                        = greatest_below(nameIt->second, pos);
                if (it != nameIt->second.end()) {
                        while (true) {
@@ -2463,9 +2614,9 @@ MacroData const * Buffer::getBufferMacro(docstring const & name,
        }
 
        // find macros in included files
-       Impl::PositionScopeBufferMap::const_iterator it
-               = greatest_below(d->position_to_children, pos);
-       if (it == d->position_to_children.end())
+       PositionScopeBufferMap::const_iterator it
+               = greatest_below(position_to_children, pos);
+       if (it == position_to_children.end())
                // no children before
                return bestData;
 
@@ -2477,10 +2628,10 @@ MacroData const * Buffer::getBufferMacro(docstring const & name,
                // scope ends behind pos?
                if (pos < it->second.first) {
                        // look for macro in external file
-                       d->macro_lock = true;
+                       macro_lock = true;
                        MacroData const * data
-                       = it->second.second->getMacro(name, false);
-                       d->macro_lock = false;
+                               = it->second.second->getMacro(name, false);
+                       macro_lock = false;
                        if (data) {
                                bestPos = it->first;
                                bestData = data;
@@ -2489,7 +2640,7 @@ MacroData const * Buffer::getBufferMacro(docstring const & name,
                }
 
                // try previous file if there is one
-               if (it == d->position_to_children.begin())
+               if (it == position_to_children.begin())
                        break;
                --it;
        }
@@ -2506,7 +2657,7 @@ MacroData const * Buffer::getMacro(docstring const & name,
                return 0;
 
        // query buffer macros
-       MacroData const * data = getBufferMacro(name, pos);
+       MacroData const * data = d->getBufferMacro(name, pos);
        if (data != 0)
                return data;
 
@@ -2554,7 +2705,7 @@ MacroData const * Buffer::getMacro(docstring const & name,
 }
 
 
-void Buffer::updateMacros(DocIterator & it, DocIterator & scope) const
+void Buffer::Impl::updateMacros(DocIterator & it, DocIterator & scope)
 {
        pit_type const lastpit = it.lastpit();
 
@@ -2591,30 +2742,38 @@ void Buffer::updateMacros(DocIterator & it, DocIterator & scope) const
                                // get buffer of external file
                                InsetInclude const & inset =
                                        static_cast<InsetInclude const &>(*iit->inset);
-                               d->macro_lock = true;
+                               macro_lock = true;
                                Buffer * child = inset.getChildBuffer();
-                               d->macro_lock = false;
+                               macro_lock = false;
                                if (!child)
                                        continue;
 
                                // register its position, but only when it is
                                // included first in the buffer
-                               if (d->children_positions.find(child) ==
-                                       d->children_positions.end())
-                                               d->children_positions[child] = it;
+                               if (children_positions.find(child) ==
+                                       children_positions.end())
+                                               children_positions[child] = it;
 
                                // register child with its scope
-                               d->position_to_children[it] = Impl::ScopeBuffer(scope, child);
+                               position_to_children[it] = Impl::ScopeBuffer(scope, child);
                                continue;
                        }
 
+                       if (doing_export && iit->inset->asInsetMath()) {
+                               InsetMath * im = static_cast<InsetMath *>(iit->inset);
+                               if (im->asHullInset()) {
+                                       InsetMathHull * hull = static_cast<InsetMathHull *>(im);
+                                       hull->recordLocation(it);
+                               }
+                       }
+
                        if (iit->inset->lyxCode() != MATHMACRO_CODE)
                                continue;
 
                        // get macro data
                        MathMacroTemplate & macroTemplate =
                                static_cast<MathMacroTemplate &>(*iit->inset);
-                       MacroContext mc(this, it);
+                       MacroContext mc(owner_, it);
                        macroTemplate.updateToContext(mc);
 
                        // valid?
@@ -2628,8 +2787,8 @@ void Buffer::updateMacros(DocIterator & it, DocIterator & scope) const
                        // register macro
                        // FIXME (Abdel), I don't understandt why we pass 'it' here
                        // instead of 'macroTemplate' defined above... is this correct?
-                       d->macros[macroTemplate.name()][it] =
-                               Impl::ScopeMacro(scope, MacroData(const_cast<Buffer *>(this), it));
+                       macros[macroTemplate.name()][it] =
+                               Impl::ScopeMacro(scope, MacroData(const_cast<Buffer *>(owner_), it));
                }
 
                // next paragraph
@@ -2658,7 +2817,7 @@ void Buffer::updateMacros() const
        DocIterator it = par_iterator_begin();
        DocIterator outerScope = it;
        outerScope.pit() = outerScope.lastpit() + 2;
-       updateMacros(it, outerScope);
+       d->updateMacros(it, outerScope);
 }
 
 
@@ -2898,11 +3057,11 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin,
 ErrorList & Buffer::errorList(string const & type) const
 {
        static ErrorList emptyErrorList;
-       map<string, ErrorList>::iterator I = d->errorLists.find(type);
-       if (I == d->errorLists.end())
+       map<string, ErrorList>::iterator it = d->errorLists.find(type);
+       if (it == d->errorLists.end())
                return emptyErrorList;
 
-       return I->second;
+       return it->second;
 }
 
 
@@ -2977,15 +3136,15 @@ public:
        AutoSaveBuffer(Buffer const & buffer, FileName const & fname)
                : buffer_(buffer), fname_(fname) {}
        ///
-       virtual boost::shared_ptr<ForkedProcess> clone() const
+       virtual shared_ptr<ForkedProcess> clone() const
        {
-               return boost::shared_ptr<ForkedProcess>(new AutoSaveBuffer(*this));
+               return shared_ptr<ForkedProcess>(new AutoSaveBuffer(*this));
        }
        ///
        int start()
        {
                command_ = to_utf8(bformat(_("Auto-saving %1$s"),
-                                                from_utf8(fname_.absFilename())));
+                                                from_utf8(fname_.absFileName())));
                return run(DontWait);
        }
 private:
@@ -3051,7 +3210,7 @@ int AutoSaveBuffer::generateChild()
 } // namespace anon
 
 
-FileName Buffer::getAutosaveFilename() const
+FileName Buffer::getAutosaveFileName() const
 {
        // if the document is unnamed try to save in the backup dir, else
        // in the default document path, and as a last try in the filePath, 
@@ -3070,7 +3229,7 @@ FileName Buffer::getAutosaveFilename() const
 
 void Buffer::removeAutosaveFile() const
 {
-       FileName const f = getAutosaveFilename();
+       FileName const f = getAutosaveFileName();
        if (f.exists())
                f.removeFile();
 }
@@ -3078,9 +3237,11 @@ void Buffer::removeAutosaveFile() const
 
 void Buffer::moveAutosaveFile(support::FileName const & oldauto) const
 {
-       FileName const newauto = getAutosaveFilename();
-       if (!(oldauto == newauto || oldauto.moveTo(newauto)))
-               LYXERR0("Unable to remove autosave file `" << oldauto << "'!");
+       FileName const newauto = getAutosaveFileName();
+       oldauto.refresh();
+       if (newauto != oldauto && oldauto.exists())
+               if (!oldauto.moveTo(newauto))
+                       LYXERR0("Unable to move autosave file `" << oldauto << "'!");
 }
 
 
@@ -3095,7 +3256,7 @@ void Buffer::autoSave() const
 
        // emit message signal.
        message(_("Autosaving current document..."));
-       AutoSaveBuffer autosave(*this, getAutosaveFilename());
+       AutoSaveBuffer autosave(*this, getAutosaveFileName());
        autosave.start();
 
        d->bak_clean = true;
@@ -3137,10 +3298,41 @@ string Buffer::getDefaultOutputFormat() const
 }
 
 
+namespace {
+       // helper class, to guarantee this gets reset properly
+       class MarkAsExporting   {
+       public:
+               MarkAsExporting(Buffer const * buf) : buf_(buf) 
+               {
+                       LASSERT(buf_, /* */);
+                       buf_->setExportStatus(true);
+               }
+               ~MarkAsExporting() 
+               {
+                       buf_->setExportStatus(false);
+               }
+       private:
+               Buffer const * const buf_;
+       };
+}
+
+
+void Buffer::setExportStatus(bool e) const
+{
+       d->doing_export = e;    
+}
+
+
+bool Buffer::isExporting() const
+{
+       return d->doing_export;
+}
+
 
 bool Buffer::doExport(string const & format, bool put_in_tempdir,
        bool includeall, string & result_file) const
 {
+       MarkAsExporting exporting(this);
        string backend_format;
        OutputParams runparams(&params().encoding());
        runparams.flavor = OutputParams::LATEX;
@@ -3193,6 +3385,21 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        // HTML backend
        else if (backend_format == "xhtml") {
                runparams.flavor = OutputParams::HTML;
+               switch (params().html_math_output) {
+               case BufferParams::MathML: 
+                       runparams.math_flavor = OutputParams::MathAsMathML; 
+                       break;
+               case BufferParams::HTML: 
+                       runparams.math_flavor = OutputParams::MathAsHTML; 
+                       break;
+               case BufferParams::Images:
+                       runparams.math_flavor = OutputParams::MathAsImages; 
+                       break;
+               case BufferParams::LaTeX:
+                       runparams.math_flavor = OutputParams::MathAsLaTeX; 
+                       break;                                                                                  
+               }
+               
                makeLyXHTMLFile(FileName(filename), runparams);
        }       else if (backend_format == "lyx")
                writeFile(FileName(filename));
@@ -3225,17 +3432,26 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        bool const success = theConverters().convert(this, FileName(filename),
                tmp_result_file, FileName(absFileName()), backend_format, format,
                error_list);
-       // Emit the signal to show the 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.
        if (format != backend_format) {
-               errors(error_type);
+               if (d->cloned_buffer_) {
+                       d->cloned_buffer_->d->errorLists[error_type] = 
+                               d->errorLists[error_type];
+               } else 
+                       errors(error_type);
                // also to the children, in case of master-buffer-view
                std::vector<Buffer *> clist = getChildren();
                for (vector<Buffer *>::const_iterator cit = clist.begin();
-                    cit != clist.end(); ++cit)
-                       (*cit)->errors(error_type, true);
+                       cit != clist.end(); ++cit) {
+                       if (d->cloned_buffer_) {
+                               (*cit)->d->cloned_buffer_->d->errorLists[error_type] = 
+                                       (*cit)->d->errorLists[error_type];
+                       } else
+                               (*cit)->errors(error_type, true);
+               }
        }
-       if (!success)
-               return false;
 
        if (d->cloned_buffer_) {
                // Enable reverse dvi or pdf to work by copying back the texrow
@@ -3243,20 +3459,27 @@ 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();
+               d->cloned_buffer_->d->errorLists[error_type] = d->errorLists[error_type];
        }
 
+       if (!success)
+               return false;
+
        if (put_in_tempdir) {
-               result_file = tmp_result_file.absFilename();
+               result_file = tmp_result_file.absFileName();
                return true;
        }
 
-       result_file = changeExtension(exportFileName().absFilename(), ext);
+       result_file = changeExtension(d->exportFileName().absFileName(), ext);
        // We need to copy referenced files (e. g. included graphics
        // if format == "dvi") to the result dir.
        vector<ExportedFile> const files =
                runparams.exportdata->externalFiles(format);
        string const dest = onlyPath(result_file);
-       CopyStatus status = SUCCESS;
+       bool use_force = use_gui ? lyxrc.export_overwrite == ALL_FILES
+                                : force_overwrite == ALL_FILES;
+       CopyStatus status = use_force ? FORCE : SUCCESS;
        
        vector<ExportedFile>::const_iterator it = files.begin();
        vector<ExportedFile>::const_iterator const en = files.end();
@@ -3271,6 +3494,10 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                message(_("Document export cancelled."));
        } else if (tmp_result_file.exists()) {
                // Finally copy the main file
+               use_force = use_gui ? lyxrc.export_overwrite != NO_FILES
+                                   : force_overwrite != NO_FILES;
+               if (status == SUCCESS && use_force)
+                       status = FORCE;
                status = copyFile(format, tmp_result_file,
                        FileName(result_file), result_file,
                        status == FORCE);
@@ -3302,6 +3529,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
 
 bool Buffer::preview(string const & format, bool includeall) const
 {
+       MarkAsExporting exporting(this);
        string result_file;
        // (1) export with all included children (omit \includeonly)
        if (includeall && !doExport(format, true, true))
@@ -3357,7 +3585,7 @@ bool Buffer::readFileHelper(FileName const & s)
 {
        // File information about normal file
        if (!s.exists()) {
-               docstring const file = makeDisplayPath(s.absFilename(), 50);
+               docstring const file = makeDisplayPath(s.absFileName(), 50);
                docstring text = bformat(_("The specified document\n%1$s"
                                                     "\ncould not be read."), file);
                Alert::error(_("Could not read document"), text);
@@ -3365,10 +3593,10 @@ bool Buffer::readFileHelper(FileName const & s)
        }
 
        // Check if emergency save file exists and is newer.
-       FileName const e(s.absFilename() + ".emergency");
+       FileName const e(s.absFileName() + ".emergency");
 
        if (e.exists() && s.exists() && e.lastModified() > s.lastModified()) {
-               docstring const file = makeDisplayPath(s.absFilename(), 20);
+               docstring const file = makeDisplayPath(s.absFileName(), 20);
                docstring const text =
                        bformat(_("An emergency save of the document "
                                  "%1$s exists.\n\n"
@@ -3388,7 +3616,7 @@ bool Buffer::readFileHelper(FileName const & s)
                        else
                                str = _("Document was NOT successfully recovered.");
                        str += "\n\n" + bformat(_("Remove emergency file now?\n(%1$s)"),
-                                               from_utf8(e.absFilename()));
+                                               makeDisplayPath(e.absFileName()));
 
                        if (!Alert::prompt(_("Delete emergency file?"), str, 1, 1,
                                        _("&Remove"), _("&Keep it"))) {
@@ -3411,10 +3639,10 @@ bool Buffer::readFileHelper(FileName const & s)
        }
 
        // Now check if autosave file is newer.
-       FileName const a(onlyPath(s.absFilename()) + '#' + onlyFilename(s.absFilename()) + '#');
+       FileName const a(onlyPath(s.absFileName()) + '#' + onlyFileName(s.absFileName()) + '#');
 
        if (a.exists() && s.exists() && a.lastModified() > s.lastModified()) {
-               docstring const file = makeDisplayPath(s.absFilename(), 20);
+               docstring const file = makeDisplayPath(s.absFileName(), 20);
                docstring const text =
                        bformat(_("The backup of the document "
                                  "%1$s is newer.\n\nLoad the "
@@ -3447,11 +3675,13 @@ bool Buffer::loadLyXFile(FileName const & s)
                  && !LyXVC::file_not_found_hook(s))
                return false;
        
-       if (s.isReadableFile()
-                 && readFileHelper(s)) {
+       if (s.isReadableFile()){
+               // InsetInfo needs to know if file is under VCS
                lyxvc().file_found_hook(s);
-               setReadonly(!s.isWritable());
-               return true;
+               if (readFileHelper(s)) {
+                       d->read_only = !s.isWritable();
+                       return true;
+               }
        }
        return false;
 }
@@ -3487,14 +3717,14 @@ void Buffer::setBuffersForInsets() const
 }
 
 
-void Buffer::updateLabels(UpdateScope scope, UpdateType utype) const
+void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
 {
        // Use the master text class also for child documents
        Buffer const * const master = masterBuffer();
        DocumentClass const & textclass = master->params().documentClass();
        
        // do this only if we are the top-level Buffer
-       if (scope != UpdateMaster || master == this)
+       if (master == this)
                checkBibInfoCache();
 
        // keep the buffers to be children in this set. If the call from the
@@ -3505,7 +3735,7 @@ void Buffer::updateLabels(UpdateScope scope, UpdateType utype) const
                // If this is a child document start with the master
                if (master != this) {
                        bufToUpdate.insert(this);
-                       master->updateLabels(UpdateMaster, utype);
+                       master->updateBuffer(UpdateMaster, utype);
                        // Do this here in case the master has no gui associated with it. Then, 
                        // the TocModel is not updated and TocModel::toc_ is invalid (bug 5699).
                        if (!master->d->gui_)
@@ -3533,7 +3763,7 @@ void Buffer::updateLabels(UpdateScope scope, UpdateType utype) const
 
        // do the real work
        ParIterator parit = cbuf.par_iterator_begin();
-       updateLabels(parit, utype);
+       updateBuffer(parit, utype);
 
        if (master != this)
                // TocBackend update will be done later.
@@ -3615,9 +3845,9 @@ static bool needEnumCounterReset(ParIterator const & it)
 
 
 // set the label of a paragraph. This includes the counters.
-void Buffer::setLabel(ParIterator & it, UpdateType utype) const
+void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const
 {
-       BufferParams const & bp = this->masterBuffer()->params();
+       BufferParams const & bp = owner_->masterBuffer()->params();
        DocumentClass const & textclass = bp.documentClass();
        Paragraph & par = it.paragraph();
        Layout const & layout = par.layout();
@@ -3713,9 +3943,9 @@ void Buffer::setLabel(ParIterator & it, UpdateType utype) const
                string const & type = counters.current_float();
                docstring full_label;
                if (type.empty())
-                       full_label = this->B_("Senseless!!! ");
+                       full_label = owner_->B_("Senseless!!! ");
                else {
-                       docstring name = this->B_(textclass.floats().getType(type).name());
+                       docstring name = owner_->B_(textclass.floats().getType(type).name());
                        if (counters.hasCounter(from_utf8(type))) {
                                string const & lang = par.getParLanguage(bp)->code();
                                counters.step(from_utf8(type), utype);
@@ -3744,7 +3974,7 @@ void Buffer::setLabel(ParIterator & it, UpdateType utype) const
 }
 
 
-void Buffer::updateLabels(ParIterator & parit, UpdateType utype) const
+void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const
 {
        LASSERT(parit.pit() == 0, /**/);
 
@@ -3770,14 +4000,14 @@ void Buffer::updateLabels(ParIterator & parit, UpdateType utype) const
                }
                
                // set the counter for this paragraph
-               setLabel(parit, utype);
+               d->setLabel(parit, utype);
 
                // now the insets
                InsetList::const_iterator iit = parit->insetList().begin();
                InsetList::const_iterator end = parit->insetList().end();
                for (; iit != end; ++iit) {
                        parit.pos() = iit->pos;
-                       iit->inset->updateLabels(parit, utype);
+                       iit->inset->updateBuffer(parit, utype);
                }
        }
 }
@@ -3803,7 +4033,9 @@ int Buffer::spellCheck(DocIterator & from, DocIterator & to,
                if (from == end)
                        break;
                to = from;
-               if (from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions)) {
+               from.paragraph().spellCheck();
+               SpellChecker::Result res = from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions);
+               if (SpellChecker::misspelled(res)) {
                        word_lang = wl;
                        break;
                }
@@ -3822,23 +4054,66 @@ int Buffer::spellCheck(DocIterator & from, DocIterator & to,
 bool Buffer::reload()
 {
        setBusy(true);
+       // c.f. bug 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());
+       docstring const disp_fn = makeDisplayPath(d->filename.absFileName());
 
        bool const success = loadLyXFile(d->filename);
        if (success) {
-               updateLabels();
+               updateBuffer();
                changed(true);
+               updateTitles();
                markClean();
                message(bformat(_("Document %1$s reloaded."), disp_fn));
        } 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);
        errors("Parse");
        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();
+       Impl::BufferPositionMap::iterator const en = d->children_positions.end();
+       for (; it != en; ++it) {
+               DocIterator dit = it->second;
+               Buffer * cbuf = const_cast<Buffer *>(it->first);
+               if (!cbuf || !theBufferList().isLoaded(cbuf))
+                       continue;
+               Inset * inset = dit.nextInset();
+               LASSERT(inset && inset->lyxCode() == INCLUDE_CODE, continue);
+               InsetInclude * inset_inc = static_cast<InsetInclude *>(inset);
+               docstring const & incfile = inset_inc->getParam("filename");
+               string oldloc = cbuf->absFileName();
+               string newloc = makeAbsPath(to_utf8(incfile),
+                               onlyPath(absFileName())).absFileName();
+               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);
+       }
+       // invalidate cache of children
+       d->children_positions.clear();
+       d->position_to_children.clear();
+}
+
 } // namespace lyx