]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
Fix unwanted curly braces in formula (bug #8679)
[lyx.git] / src / Buffer.cpp
index 2c4e9a4788392b8e77413adddce0c76820768349..c525ec2f21459a966326c5cdeafaf89c87544cc4 100644 (file)
 #include "Chktex.h"
 #include "Converter.h"
 #include "Counters.h"
+#include "Cursor.h"
+#include "CutAndPaste.h"
 #include "DispatchResult.h"
 #include "DocIterator.h"
-#include "Encoding.h"
+#include "BufferEncodings.h"
 #include "ErrorList.h"
 #include "Exporter.h"
 #include "Format.h"
@@ -56,7 +58,6 @@
 #include "SpellChecker.h"
 #include "sgml.h"
 #include "TexRow.h"
-#include "TexStream.h"
 #include "Text.h"
 #include "TextClass.h"
 #include "TocBackend.h"
 #include "support/gzstream.h"
 #include "support/lstrings.h"
 #include "support/lyxalgo.h"
+#include "support/mutex.h"
 #include "support/os.h"
 #include "support/Package.h"
-#include "support/Path.h"
+#include "support/PathChanger.h"
 #include "support/Systemcall.h"
+#include "support/TempFile.h"
 #include "support/textutils.h"
 #include "support/types.h"
 
 #include <map>
 #include <set>
 #include <sstream>
-#include <stack>
 #include <vector>
 
 using namespace std;
@@ -195,6 +197,9 @@ public:
        /// is this an unnamed file (New...)?
        bool unnamed;
 
+       /// is this an internal bufffer?
+       bool internal_buffer;
+
        /// buffer is r/o
        bool read_only;
 
@@ -207,6 +212,9 @@ public:
         */
        bool file_fully_loaded;
 
+       /// Ignore the parent (e.g. when exporting a child standalone)?
+       bool ignore_parent;
+
        ///
        mutable TocBackend toc_backend;
 
@@ -276,7 +284,12 @@ public:
 
        /// This is here to force the test to be done whenever parent_buffer
        /// is accessed.
-       Buffer const * parent() const {
+       Buffer const * parent() const
+       {
+               // ignore_parent temporarily "orphans" a buffer
+               // (e.g. if a child is compiled standalone)
+               if (ignore_parent)
+                       return 0;
                // if parent_buffer is not loaded, then it has been unloaded,
                // which means that parent_buffer is an invalid pointer. So we
                // set it to null in that case.
@@ -289,7 +302,8 @@ public:
        }
 
        ///
-       void setParent(Buffer const * pb) {
+       void setParent(Buffer const * pb)
+       {
                if (parent_buffer == pb)
                        // nothing to do
                        return;
@@ -309,15 +323,19 @@ public:
        CloneList * clone_list_;
        /// are we in the process of exporting this buffer?
        mutable bool doing_export;
+
        /// compute statistics
        /// \p from initial position
        /// \p to points to the end position
        void updateStatistics(DocIterator & from, DocIterator & to,
-                                                 bool skipNoOutput = true);
+                             bool skipNoOutput = true);
        /// statistics accessor functions
-       int wordCount() const { return word_count_; }
-       int charCount(bool with_blanks) const {
+       int wordCount() const
+       {
+               return word_count_;
+       }
+       int charCount(bool with_blanks) const
+       {
                return char_count_
                + (with_blanks ? blank_count_ : 0);
        }
@@ -336,12 +354,20 @@ private:
 /// Creates the per buffer temporary directory
 static FileName createBufferTmpDir()
 {
-       static int count;
+       // FIXME This would be the ideal application for a TempDir class (like
+       //       TempFile but for directories) 
+       string counter;
+       {
+               static int count;
+               static Mutex mutex;
+               Mutex::Locker locker(&mutex);
+               counter = convert<string>(count++);
+       }
        // 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" +
-               convert<string>(count++));
+               counter);
 
        if (!tmpfl.createDirectory(0777)) {
                throw ExceptionMessage(WarningException, _("Disk Error: "), bformat(
@@ -355,11 +381,12 @@ static FileName createBufferTmpDir()
 Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
        Buffer const * cloned_buffer)
        : owner_(owner), lyx_clean(true), bak_clean(true), unnamed(false),
-         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), cite_labels_valid_(false),
-         preview_loader_(0), cloned_buffer_(cloned_buffer), clone_list_(0),
+         internal_buffer(false), read_only(readonly_), filename(file),
+         file_fully_loaded(false), ignore_parent(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),
+         cite_labels_valid_(false), preview_loader_(0),
+         cloned_buffer_(cloned_buffer), clone_list_(0),
          doing_export(false), parent_buffer(0)
 {
        if (!cloned_buffer_) {
@@ -379,6 +406,7 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
        bibfile_status_ = cloned_buffer_->d->bibfile_status_;
        cite_labels_valid_ = cloned_buffer_->d->cite_labels_valid_;
        unnamed = cloned_buffer_->d->unnamed;
+       internal_buffer = cloned_buffer_->d->internal_buffer;
 }
 
 
@@ -432,13 +460,17 @@ Buffer::~Buffer()
                // if we're the master buffer, then we should get rid of the list
                // of clones
                if (!parent()) {
-                       // if this is not empty, we have leaked something. worse, one of the
-                       // children still has a reference to this list.
-                       LASSERT(d->clone_list_->empty(), /* */);
+                       // If this is not empty, we have leaked something. Worse, one of the
+                       // children still has a reference to this list. But we will try to
+                       // continue, rather than shut down.
+                       LATTEST(d->clone_list_->empty());
                        list<CloneList *>::iterator it =
                                find(cloned_buffers.begin(), cloned_buffers.end(), d->clone_list_);
-                       LASSERT(it != cloned_buffers.end(), /* */);
-                       cloned_buffers.erase(it);
+                       if (it == cloned_buffers.end()) {
+                               // We will leak in this case, but it is safe to continue.
+                               LATTEST(false);
+                       } else
+                               cloned_buffers.erase(it);
                        delete d->clone_list_;
                }
                // FIXME Do we really need to do this right before we delete d?
@@ -481,7 +513,7 @@ Buffer::~Buffer()
 Buffer * Buffer::cloneFromMaster() const
 {
        BufferMap bufmap;
-       cloned_buffers.push_back(new CloneList());
+       cloned_buffers.push_back(new CloneList);
        CloneList * clones = cloned_buffers.back();
 
        masterBuffer()->cloneWithChildren(bufmap, clones);
@@ -502,11 +534,21 @@ void Buffer::cloneWithChildren(BufferMap & bufmap, CloneList * clones) const
                return;
 
        Buffer * buffer_clone = new Buffer(fileName().absFileName(), false, this);
+
+       // The clone needs its own DocumentClass, since running updateBuffer() will
+       // modify it, and we would otherwise be sharing it with the original Buffer.
+       buffer_clone->params().makeDocumentClass(true);
+       ErrorList el;
+       cap::switchBetweenClasses(
+                       params().documentClassPtr(), buffer_clone->params().documentClassPtr(),
+                       static_cast<InsetText &>(buffer_clone->inset()), el);
+
        bufmap[this] = buffer_clone;
        clones->insert(buffer_clone);
        buffer_clone->d->clone_list_ = clones;
        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.
@@ -537,11 +579,21 @@ void Buffer::cloneWithChildren(BufferMap & bufmap, CloneList * clones) const
 
 
 Buffer * Buffer::cloneBufferOnly() const {
-       cloned_buffers.push_back(new CloneList());
+       cloned_buffers.push_back(new CloneList);
        CloneList * clones = cloned_buffers.back();
        Buffer * buffer_clone = new Buffer(fileName().absFileName(), false, this);
+
+       // The clone needs its own DocumentClass, since running updateBuffer() will
+       // modify it, and we would otherwise be sharing it with the original Buffer.
+       buffer_clone->params().makeDocumentClass(true);
+       ErrorList el;
+       cap::switchBetweenClasses(
+                       params().documentClassPtr(), buffer_clone->params().documentClassPtr(),
+                       static_cast<InsetText &>(buffer_clone->inset()), el);
+
        clones->insert(buffer_clone);
        buffer_clone->d->clone_list_ = clones;
+
        // we won't be cloning the children
        buffer_clone->d->children_positions.clear();
        return buffer_clone;
@@ -563,7 +615,7 @@ void Buffer::changed(bool update_metrics) const
 
 frontend::WorkAreaManager & Buffer::workAreaManager() const
 {
-       LASSERT(d->wa_, /**/);
+       LBUFERR(d->wa_);
        return *d->wa_;
 }
 
@@ -592,6 +644,28 @@ BufferParams const & Buffer::params() const
 }
 
 
+BufferParams const & Buffer::masterParams() const
+{
+       if (masterBuffer() == this)
+               return params();
+
+       BufferParams & mparams = const_cast<Buffer *>(masterBuffer())->params();
+       // Copy child authors to the params. We need those pointers.
+       AuthorList const & child_authors = params().authors();
+       AuthorList::Authors::const_iterator it = child_authors.begin();
+       for (; it != child_authors.end(); ++it)
+               mparams.authors().record(*it);
+       return mparams;
+}
+
+
+double Buffer::fontScalingFactor() const
+{
+       return isExporting() ? 75.0 * params().html_math_img_scale
+               : 0.01 * lyxrc.dpi * lyxrc.zoom * lyxrc.preview_scale_factor * params().display_pixel_ratio;
+}
+
+
 ParagraphList & Buffer::paragraphs()
 {
        return text().paragraphs();
@@ -743,7 +817,10 @@ void Buffer::setReadonly(bool const flag)
 
 void Buffer::setFileName(FileName const & fname)
 {
+       bool const changed = fname != d->filename;
        d->filename = fname;
+       if (changed)
+               lyxvc().file_found_hook(fname);
        setReadonly(d->filename.isReadOnly());
        saveCheckSum();
        updateTitles();
@@ -789,7 +866,8 @@ int Buffer::readHeader(Lexer & lex)
        params().html_latex_end.clear();
        params().html_math_img_scale = 1.0;
        params().output_sync_macro.erase();
-       params().local_layout.clear();
+       params().setLocalLayout(string(), false);
+       params().setLocalLayout(string(), true);
 
        for (int i = 0; i < 4; ++i) {
                params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i];
@@ -865,7 +943,7 @@ bool Buffer::readDocument(Lexer & lex)
 
        readHeader(lex);
 
-       if (params().outputChanges) {
+       if (params().output_changes) {
                bool dvipost    = LaTeXFeatures::isAvailable("dvipost");
                bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
                                  LaTeXFeatures::isAvailable("xcolor");
@@ -885,7 +963,7 @@ bool Buffer::readDocument(Lexer & lex)
                }
        }
 
-       if (!params().master.empty()) {
+       if (!parent() && !params().master.empty()) {
                FileName const master_file = makeAbsPath(params().master,
                           onlyPath(absFileName()));
                if (isLyXFileName(master_file.absFileName())) {
@@ -936,6 +1014,50 @@ bool Buffer::readDocument(Lexer & lex)
 }
 
 
+bool Buffer::importString(string const & format, docstring const & contents, ErrorList & errorList)
+{
+       Format const * fmt = formats.getFormat(format);
+       if (!fmt)
+               return false;
+       // It is important to use the correct extension here, since some
+       // converters create a wrong output file otherwise (e.g. html2latex)
+       TempFile const tempfile("Buffer_importStringXXXXXX." + fmt->extension());
+       FileName const name(tempfile.name());
+       ofdocstream os(name.toFilesystemEncoding().c_str());
+       // Do not convert os implicitly to bool, since that is forbidden in C++11.
+       bool const success = !(os << contents).fail();
+       os.close();
+
+       bool converted = false;
+       if (success) {
+               params().compressed = false;
+
+               // remove dummy empty par
+               paragraphs().clear();
+
+               converted = importFile(format, name, errorList);
+       }
+
+       if (name.exists())
+               name.removeFile();
+       return converted;
+}
+
+
+bool Buffer::importFile(string const & format, FileName const & name, ErrorList & errorList)
+{
+       if (!theConverters().isReachable(format, "lyx"))
+               return false;
+
+       TempFile const tempfile("Buffer_importFileXXXXXX.lyx");
+       FileName const lyx(tempfile.name());
+       if (theConverters().convert(0, name, lyx, name, format, "lyx", errorList))
+               return readFile(lyx) == ReadSuccess;
+
+       return false;
+}
+
+
 bool Buffer::readString(string const & s)
 {
        params().compressed = false;
@@ -943,25 +1065,25 @@ bool Buffer::readString(string const & s)
        Lexer lex;
        istringstream is(s);
        lex.setStream(is);
-       FileName const fn = FileName::tempName("Buffer_readString");
+       TempFile tempfile("Buffer_readStringXXXXXX.lyx");
+       FileName const fn = tempfile.name();
 
        int file_format;
-       ReadStatus const ret_plf = parseLyXFormat(lex, fn, file_format);
-       if (ret_plf != ReadSuccess)
-               return ret_plf;
+       bool success = parseLyXFormat(lex, fn, file_format) == ReadSuccess;
 
-       if (file_format != LYX_FORMAT) {
+       if (success && file_format != LYX_FORMAT) {
                // We need to call lyx2lyx, so write the input to a file
                ofstream os(fn.toFilesystemEncoding().c_str());
                os << s;
                os.close();
                // lyxvc in readFile
-               return readFile(fn) == ReadSuccess;
+               if (readFile(fn) != ReadSuccess)
+                       success = false;
        }
-
-       if (readDocument(lex))
-               return false;
-       return true;
+       else if (success)
+               if (readDocument(lex))
+                       success = false;
+       return success;
 }
 
 
@@ -1081,7 +1203,9 @@ Buffer::ReadStatus Buffer::parseLyXFormat(Lexer & lex,
 Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn,
        FileName & tmpfile, int from_format)
 {
-       tmpfile = FileName::tempName("Buffer_convertLyXFormat");
+       TempFile tempfile("Buffer_convertLyXFormatXXXXXX.lyx");
+       tempfile.setAutoRemove(false);
+       tmpfile = tempfile.name();
        if(tmpfile.empty()) {
                Alert::error(_("Conversion failed"),
                        bformat(_("%1$s is from a different"
@@ -1168,12 +1292,32 @@ bool Buffer::save() const
        // We don't need autosaves in the immediate future. (Asger)
        resetAutosaveTimers();
 
-       FileName backupName;
-       bool madeBackup = false;
+       // if the file does not yet exist, none of the backup activity
+       // that follows is necessary
+       if (!fileName().exists())
+               return writeFile(fileName());
+
+       // we first write the file to a new name, then move it to its
+       // proper location once that has been done successfully. that
+       // way we preserve the original file if something goes wrong.
+       string const justname = fileName().onlyFileNameWithoutExt();
+       boost::scoped_ptr<TempFile>
+               tempfile(new TempFile(fileName().onlyPath(),
+                  justname + "-XXXXXX.lyx"));
+       bool const symlink = fileName().isSymLink();
+       if (!symlink)
+               tempfile->setAutoRemove(false);
+
+       FileName savefile(tempfile->name());
+       LYXERR(Debug::FILES, "Saving to " << savefile.absFileName());
+       if (!writeFile(savefile))
+               return false;
+
+       // we will set this to false if we fail
+       bool made_backup = true;
 
-       // make a backup if the file already exists
-       if (lyxrc.make_backup && fileName().exists()) {
-               backupName = FileName(absFileName() + '~');
+       FileName backupName(absFileName() + '~');
+       if (lyxrc.make_backup) {
                if (!lyxrc.backupdir_path.empty()) {
                        string const mangledName =
                                subst(subst(backupName.absFileName(), '/', '!'), ':', '!');
@@ -1181,14 +1325,15 @@ bool Buffer::save() const
                                                      mangledName));
                }
 
+               LYXERR(Debug::FILES, "Backing up original file to " <<
+                               backupName.absFileName());
                // 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);
+               made_backup = symlink ?
+                       fileName().copyTo(backupName):
+                       fileName().moveTo(backupName);
 
-               if (!madeBackup) {
+               if (!made_backup) {
                        Alert::error(_("Backup failure"),
                                     bformat(_("Cannot create backup file %1$s.\n"
                                               "Please check whether the directory exists and is writable."),
@@ -1197,25 +1342,51 @@ bool Buffer::save() const
                }
        }
 
-       if (writeFile(d->filename)) {
+       // Destroy tempfile since it keeps the file locked on windows (bug 9234)
+       // Only do this if tempfile is not in autoremove mode
+       if (!symlink)
+               tempfile.reset();
+       // If we have no symlink, we can simply rename the temp file.
+       // Otherwise, we need to copy it so the symlink stays intact.
+       if (made_backup && symlink ? savefile.copyTo(fileName(), true) :
+                                          savefile.moveTo(fileName()))
+       {
+               // saveCheckSum() was already called by writeFile(), but the
+               // time stamp is invalidated by copying/moving
+               saveCheckSum();
                markClean();
                return true;
+       }
+       // else we saved the file, but failed to move it to the right location.
+
+       if (lyxrc.make_backup && made_backup && !symlink) {
+               // the original file was moved to filename.lyx~, so it will look
+               // to the user as if it was deleted. (see bug #9234.) we could try
+               // to restore it, but that would basically mean trying to do again
+               // what we just failed to do. better to leave things as they are.
+               Alert::error(_("Write failure"),
+                            bformat(_("The file has successfully been saved as:\n  %1$s.\n"
+                          "But LyX could not move it to:\n  %2$s.\n"
+                                                        "Your original file has been backed up to:\n  %3$s"),
+                                    from_utf8(savefile.absFileName()),
+             from_utf8(fileName().absFileName()),
+                        from_utf8(backupName.absFileName())));
        } else {
-               // Saving failed, so backup is not backup
-               if (madeBackup)
-                       backupName.moveTo(d->filename);
-               return false;
+               // either we did not try to make a backup, or else we tried and failed,
+               // or else the original file was a symlink, in which case it was copied,
+               // not moved. so the original file is intact.
+               Alert::error(_("Write failure"),
+                            bformat(_("Cannot move saved file to:\n  %1$s.\n"
+                                      "But the file has successfully been saved as:\n  %2$s."),
+                                    from_utf8(fileName().absFileName()),
+                        from_utf8(savefile.absFileName())));
        }
+       return false;
 }
 
 
 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;
 
@@ -1317,6 +1488,8 @@ 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
+       // Important: Keep the version formatting in sync with lyx2lyx and
+       //            tex2lyx (bug 7951)
        ofs << "#LyX " << lyx_version_major << "." << lyx_version_minor
            << " created this file. For more info see http://www.lyx.org/\n"
            << "\\lyxformat " << LYX_FORMAT << "\n"
@@ -1385,7 +1558,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
 
        ofdocstream ofs;
        try { ofs.reset(encoding); }
-       catch (iconv_codecvt_facet_exception & e) {
+       catch (iconv_codecvt_facet_exception const & e) {
                lyxerr << "Caught iconv exception: " << e.what() << endl;
                Alert::error(_("Iconv software exception Detected"), bformat(_("Please "
                        "verify that the support software for your encoding (%1$s) is "
@@ -1395,7 +1568,6 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
        if (!openFileWrite(ofs, fname))
                return false;
 
-       //TexStream ts(ofs.rdbuf(), &texrow());
        ErrorList & errorList = d->errorLists["Export"];
        errorList.clear();
        bool failed_export = false;
@@ -1412,7 +1584,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
                os.texrow().reset();
                writeLaTeXSource(os, original_path, runparams, output);
        }
-       catch (EncodingException & e) {
+       catch (EncodingException const & e) {
                odocstringstream ods;
                ods.put(e.failed_char);
                ostringstream oss;
@@ -1426,7 +1598,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
                                e.par_id, e.pos, e.pos + 1));
                failed_export = true;
        }
-       catch (iconv_codecvt_facet_exception & e) {
+       catch (iconv_codecvt_facet_exception const & e) {
                errorList.push_back(ErrorItem(_("iconv conversion failed"),
                        _(e.what()), -1, 0, 0));
                failed_export = true;
@@ -1447,7 +1619,10 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
                lyxerr << "File '" << fname << "' was not closed properly." << endl;
        }
 
-       errors("Export");
+       if (runparams_in.silent)
+               errorList.clear();
+       else
+               errors("Export");
        return !failed_export;
 }
 
@@ -1455,25 +1630,35 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
 void Buffer::writeLaTeXSource(otexstream & os,
                           string const & original_path,
                           OutputParams const & runparams_in,
-         OutputWhat output) const
+                          OutputWhat output) const
 {
        // The child documents, if any, shall be already loaded at this point.
 
        OutputParams runparams = runparams_in;
 
+       // If we are compiling a file standalone, even if this is the
+       // child of some other buffer, let's cut the link here, so the
+       // file is really independent and no concurring settings from
+       // the master (e.g. branch state) interfere (see #8100).
+       if (!runparams.is_child)
+               d->ignore_parent = true;
+
        // Classify the unicode characters appearing in math insets
-       Encodings::initUnicodeMath(*this);
+       BufferEncodings::initUnicodeMath(*this);
 
        // validate the buffer.
        LYXERR(Debug::LATEX, "  Validating buffer...");
        LaTeXFeatures features(*this, params(), runparams);
        validate(features);
+       // This is only set once per document (in master)
+       if (!runparams.is_child)
+               runparams.use_polyglossia = features.usePolyglossia();
        LYXERR(Debug::LATEX, "  Buffer validation done.");
 
        bool const output_preamble =
                output == FullSource || output == OnlyPreamble;
        bool const output_body =
-         output == FullSource || output == OnlyBody;
+               output == FullSource || output == OnlyBody;
 
        // The starting paragraph of the coming rows is the
        // first paragraph of the document. (Asger)
@@ -1565,15 +1750,20 @@ void Buffer::writeLaTeXSource(otexstream & os,
                MacroSet parentMacros;
                listParentMacros(parentMacros, features);
 
-               runparams.use_polyglossia = features.usePolyglossia();
                // Write the preamble
                runparams.use_babel = params().writeLaTeX(os, features,
                                                          d->filename.onlyPath());
 
-               runparams.use_japanese = features.isRequired("japanese");
+               // Japanese might be required only in some children of a document,
+               // but once required, we must keep use_japanese true.
+               runparams.use_japanese |= features.isRequired("japanese");
 
-               if (!output_body)
+               if (!output_body) {
+                       // Restore the parenthood if needed
+                       if (!runparams.is_child)
+                               d->ignore_parent = false;
                        return;
+               }
 
                // make the body.
                os << "\\begin{document}\n";
@@ -1592,21 +1782,12 @@ void Buffer::writeLaTeXSource(otexstream & os,
 
        LYXERR(Debug::INFO, "preamble finished, now the body.");
 
-       // if we are doing a real file with body, even if this is the
-       // child of some other buffer, let's cut the link here.
-       // This happens for example if only a child document is printed.
-       Buffer const * save_parent = 0;
-       if (output_preamble) {
-               save_parent = d->parent();
-               d->setParent(0);
-       }
-
        // the real stuff
        latexParagraphs(*this, text(), os, runparams);
 
        // Restore the parenthood if needed
-       if (output_preamble)
-               d->setParent(save_parent);
+       if (!runparams.is_child)
+               d->ignore_parent = false;
 
        // add this just in case after all the paragraphs
        os << endl;
@@ -1773,7 +1954,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
 
        if (output_preamble) {
                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"
+                  << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\" \"http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd\">\n"
                   // FIXME Language should be set properly.
                   << "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
                   << "<head>\n"
@@ -1821,7 +2002,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
                                            << ";\n";
                                css << "}\n";
                }
-               
+
                docstring const dstyles = css.str();
                if (!dstyles.empty()) {
                        bool written = false;
@@ -1856,7 +2037,9 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
                if (output_body_tag)
                        os << "<body>\n";
                XHTMLStream xs(os);
-               params().documentClass().counters().reset();
+               if (output != IncludedFile)
+                       // if we're an included file, the counters are in the master.
+                       params().documentClass().counters().reset();
                xhtmlParagraphs(text(), *this, xs, runparams);
                if (output_body_tag)
                        os << "</body>\n";
@@ -1895,7 +2078,7 @@ int Buffer::runChktex()
        if (res == -1) {
                Alert::error(_("chktex failure"),
                             _("Could not run chktex successfully."));
-       } else if (res > 0) {
+       } else {
                ErrorList & errlist = d->errorLists["ChkTeX"];
                errlist.clear();
                bufferErrors(terr, errlist);
@@ -1903,7 +2086,10 @@ int Buffer::runChktex()
 
        setBusy(false);
 
-       errors("ChkTeX");
+       if (runparams.silent)
+               d->errorLists["ChkTeX"].clear();
+       else
+               errors("ChkTeX");
 
        return res;
 }
@@ -1911,7 +2097,11 @@ int Buffer::runChktex()
 
 void Buffer::validate(LaTeXFeatures & features) const
 {
-       params().validate(features);
+       // Validate the buffer params, but not for included
+       // files, since they also use the parent buffer's
+       // params (# 5941)
+       if (!features.runparams().is_child)
+               params().validate(features);
 
        for_each(paragraphs().begin(), paragraphs().end(),
                 bind(&Paragraph::validate, _1, ref(features)));
@@ -2094,6 +2284,13 @@ void Buffer::addBibTeXInfo(docstring const & key, BibTeXInfo const & bi) const
 }
 
 
+void Buffer::makeCitationLabels() const
+{
+       Buffer const * const master = masterBuffer();
+       return d->bibinfo_.makeCitationLabels(*master);
+}
+
+
 bool Buffer::citeLabelsValid() const
 {
        return masterBuffer()->d->cite_labels_valid_;
@@ -2145,57 +2342,70 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 
        switch (cmd.action()) {
 
-               case LFUN_BUFFER_TOGGLE_READ_ONLY:
-                       flag.setOnOff(isReadonly());
-                       break;
+       case LFUN_BUFFER_TOGGLE_READ_ONLY:
+               flag.setOnOff(isReadonly());
+               break;
 
                // FIXME: There is need for a command-line import.
                //case LFUN_BUFFER_IMPORT:
 
-               case LFUN_BUFFER_AUTO_SAVE:
-                       break;
+       case LFUN_BUFFER_AUTO_SAVE:
+               break;
 
-               case LFUN_BUFFER_EXPORT_CUSTOM:
-                       // FIXME: Nothing to check here?
-                       break;
+       case LFUN_BUFFER_EXPORT_CUSTOM:
+               // FIXME: Nothing to check here?
+               break;
 
-               case LFUN_BUFFER_EXPORT: {
-                       docstring const arg = cmd.argument();
-                       if (arg == "custom") {
-                               enable = true;
-                               break;
-                       }
-                       string format = to_utf8(arg);
-                       size_t pos = format.find(' ');
-                       if (pos != string::npos)
-                               format = format.substr(0, pos);
-                       enable = params().isExportable(format);
-                       if (!enable)
-                               flag.message(bformat(
-                                       _("Don't know how to export to format: %1$s"), arg));
+       case LFUN_BUFFER_EXPORT: {
+               docstring const arg = cmd.argument();
+               if (arg == "custom") {
+                       enable = true;
                        break;
                }
+               string format = to_utf8(arg);
+               size_t pos = format.find(' ');
+               if (pos != string::npos)
+                       format = format.substr(0, pos);
+               enable = params().isExportable(format);
+               if (!enable)
+                       flag.message(bformat(
+                                            _("Don't know how to export to format: %1$s"), arg));
+               break;
+       }
 
-               case LFUN_BUFFER_CHKTEX:
-                       enable = params().isLatex() && !lyxrc.chktex_command.empty();
-                       break;
+       case LFUN_BUFFER_CHKTEX:
+               enable = params().isLatex() && !lyxrc.chktex_command.empty();
+               break;
 
-               case LFUN_BUILD_PROGRAM:
-                       enable = params().isExportable("program");
-                       break;
+       case LFUN_BUILD_PROGRAM:
+               enable = params().isExportable("program");
+               break;
 
-               case LFUN_BRANCH_ADD:
-               case LFUN_BRANCHES_RENAME:
-               case LFUN_BUFFER_PRINT:
-                       // if no Buffer is present, then of course we won't be called!
-                       break;
+       case LFUN_BRANCH_ACTIVATE:
+       case LFUN_BRANCH_DEACTIVATE:
+       case LFUN_BRANCH_MASTER_ACTIVATE:
+       case LFUN_BRANCH_MASTER_DEACTIVATE: {
+               bool const master = (cmd.action() == LFUN_BRANCH_MASTER_ACTIVATE
+                                    || cmd.action() == LFUN_BRANCH_MASTER_DEACTIVATE);
+               BranchList const & branchList = master ? masterBuffer()->params().branchlist()
+                       : params().branchlist();
+               docstring const branchName = cmd.argument();
+               flag.setEnabled(!branchName.empty() && branchList.find(branchName));
+               break;
+       }
 
-               case LFUN_BUFFER_LANGUAGE:
-                       enable = !isReadonly();
-                       break;
+       case LFUN_BRANCH_ADD:
+       case LFUN_BRANCHES_RENAME:
+       case LFUN_BUFFER_PRINT:
+               // if no Buffer is present, then of course we won't be called!
+               break;
 
-               default:
-                       return false;
+       case LFUN_BUFFER_LANGUAGE:
+               enable = !isReadonly();
+               break;
+
+       default:
+               return false;
        }
        flag.setEnabled(enable);
        return true;
@@ -2226,8 +2436,11 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
 
        switch (func.action()) {
        case LFUN_BUFFER_TOGGLE_READ_ONLY:
-               if (lyxvc().inUse())
-                       lyxvc().toggleReadOnly();
+               if (lyxvc().inUse()) {
+                       string log = lyxvc().toggleReadOnly();
+                       if (!log.empty())
+                               dr.setMessage(log);
+               }
                else
                        setReadonly(!isReadonly());
                break;
@@ -2241,9 +2454,13 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
        }
 
-       case LFUN_BUILD_PROGRAM:
-               doExport("program", true);
+       case LFUN_BUILD_PROGRAM: {
+               ExportStatus const status = doExport("program", true);
+               dr.setError(status != ExportSuccess);
+               if (status != ExportSuccess)
+                       dr.setMessage(_("Error generating literate programming code."));
                break;
+       }
 
        case LFUN_BUFFER_CHKTEX:
                runChktex();
@@ -2300,6 +2517,42 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                resetAutosaveTimers();
                break;
 
+       case LFUN_BRANCH_ACTIVATE:
+       case LFUN_BRANCH_DEACTIVATE:
+       case LFUN_BRANCH_MASTER_ACTIVATE:
+       case LFUN_BRANCH_MASTER_DEACTIVATE: {
+               bool const master = (func.action() == LFUN_BRANCH_MASTER_ACTIVATE
+                                    || func.action() == LFUN_BRANCH_MASTER_DEACTIVATE);
+               Buffer * buf = master ? const_cast<Buffer *>(masterBuffer())
+                                     : this;
+
+               docstring const branch_name = func.argument();
+               // the case without a branch name is handled elsewhere
+               if (branch_name.empty()) {
+                       dispatched = false;
+                       break;
+               }
+               Branch * branch = buf->params().branchlist().find(branch_name);
+               if (!branch) {
+                       LYXERR0("Branch " << branch_name << " does not exist.");
+                       dr.setError(true);
+                       docstring const msg =
+                               bformat(_("Branch \"%1$s\" does not exist."), branch_name);
+                       dr.setMessage(msg);
+                       break;
+               }
+               bool const activate = (func.action() == LFUN_BRANCH_ACTIVATE
+                                      || func.action() == LFUN_BRANCH_MASTER_ACTIVATE);
+               if (branch->isSelected() != activate) {
+                       buf->undo().recordUndoFullDocument(CursorData());
+                       branch->setSelected(activate);
+                       dr.setError(false);
+                       dr.screenUpdate(Update::Force);
+                       dr.forceBufferUpdate();
+               }
+               break;
+       }
+
        case LFUN_BRANCH_ADD: {
                docstring branch_name = func.argument();
                if (branch_name.empty()) {
@@ -2321,6 +2574,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                        msg += ("\n");
                                msg += bformat(_("Branch \"%1$s\" already exists."), branch_name);
                        } else {
+                               undo().recordUndoFullDocument(CursorData());
                                branch_list.add(branch_name);
                                branch = branch_list.find(branch_name);
                                string const x11hexname = X11hexname(branch->color());
@@ -2348,7 +2602,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                        if (it->lyxCode() == BRANCH_CODE) {
                                InsetBranch & ins = static_cast<InsetBranch &>(*it);
                                if (ins.branch() == oldname) {
-                                       undo().recordUndo(it);
+                                       undo().recordUndo(CursorData(it));
                                        ins.rename(newname);
                                        success = true;
                                        continue;
@@ -2396,7 +2650,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                        break;
                }
 
-               if (!doExport("dvi", true)) {
+               if (doExport("dvi", true) != ExportSuccess) {
                        showPrintError(absFileName());
                        dr.setMessage(_("Error exporting to DVI."));
                        break;
@@ -2500,8 +2754,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
 
 void Buffer::changeLanguage(Language const * from, Language const * to)
 {
-       LASSERT(from, /**/);
-       LASSERT(to, /**/);
+       LASSERT(from, return);
+       LASSERT(to, return);
 
        for_each(par_iterator_begin(),
                 par_iterator_end(),
@@ -2612,7 +2866,7 @@ bool Buffer::isClean() const
 
 bool Buffer::isExternallyModified(CheckMethod method) const
 {
-       LASSERT(d->filename.exists(), /**/);
+       LASSERT(d->filename.exists(), return false);
        // if method == timestamp, check timestamp before checksum
        return (method == checksum_method
                || d->timestamp_ != d->filename.lastModified())
@@ -2668,7 +2922,13 @@ bool Buffer::isUnnamed() const
 /// retrieving fileName() nor for checking if it is unnamed or not.
 bool Buffer::isInternal() const
 {
-       return fileName().extension() == "internal";
+       return d->internal_buffer;
+}
+
+
+void Buffer::setInternal(bool flag)
+{
+       d->internal_buffer = flag;
 }
 
 
@@ -2702,7 +2962,12 @@ string Buffer::absFileName() const
 
 string Buffer::filePath() const
 {
-       return d->filename.onlyPath().absFileName() + "/";
+       string const abs = d->filename.onlyPath().absFileName();
+       if (abs.empty())
+               return abs;
+       int last = abs.length() - 1;
+
+       return abs[last] == '/' ? abs : abs + '/';
 }
 
 
@@ -2864,7 +3129,7 @@ MacroData const * Buffer::Impl::getBufferMacro(docstring const & name,
                                // try previous macro if there is one
                                if (it == nameIt->second.begin())
                                        break;
-                               it--;
+                               --it;
                        }
                }
        }
@@ -3199,10 +3464,10 @@ void Buffer::listParentMacros(MacroSet & macros, LaTeXFeatures & features) const
 }
 
 
-Buffer::References & Buffer::references(docstring const & label)
+Buffer::References & Buffer::getReferenceCache(docstring const & label)
 {
        if (d->parent())
-               return const_cast<Buffer *>(masterBuffer())->references(label);
+               return const_cast<Buffer *>(masterBuffer())->getReferenceCache(label);
 
        RefCache::iterator it = d->ref_cache_.find(label);
        if (it != d->ref_cache_.end())
@@ -3218,7 +3483,14 @@ Buffer::References & Buffer::references(docstring const & label)
 
 Buffer::References const & Buffer::references(docstring const & label) const
 {
-       return const_cast<Buffer *>(this)->references(label);
+       return const_cast<Buffer *>(this)->getReferenceCache(label);
+}
+
+
+void Buffer::addReference(docstring const & label, Inset * inset, ParIterator it)
+{
+       References & refs = getReferenceCache(label);
+       refs.push_back(make_pair(inset, it));
 }
 
 
@@ -3241,12 +3513,9 @@ void Buffer::clearReferenceCache() const
 }
 
 
-void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to,
-       InsetCode code)
+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
@@ -3264,21 +3533,19 @@ void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to,
 
        string const paramName = "key";
        for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) {
-               if (it->lyxCode() == code) {
-                       InsetCommand * inset = it->asInsetCommand();
-                       if (!inset)
-                               continue;
-                       docstring const oldValue = inset->getParam(paramName);
-                       if (oldValue == from)
-                               inset->setParam(paramName, to);
-               }
+               if (it->lyxCode() != CITE_CODE)
+                       continue;
+               InsetCommand * inset = it->asInsetCommand();
+               docstring const oldValue = inset->getParam(paramName);
+               if (oldValue == from)
+                       inset->setParam(paramName, to);
        }
 }
 
 
-void Buffer::getSourceCode(odocstream & os, string const format,
+void Buffer::getSourceCode(odocstream & os, string const format,
                           pit_type par_begin, pit_type par_end,
-                          OutputWhat output) const
+                          OutputWhat output, bool master) const
 {
        OutputParams runparams(&params().encoding());
        runparams.nice = true;
@@ -3301,14 +3568,14 @@ void Buffer::getSourceCode(odocstream & os, string const format,
                                        convert<docstring>(par_end - 1))
                           << "\n\n";
                }
-               TexRow texrow;
-               texrow.reset();
-               texrow.newline();
-               texrow.newline();
                // output paragraphs
-               if (params().isDocBook())
-                       docbookParagraphs(text(), *this, os, runparams);
-               else if (runparams.flavor == OutputParams::HTML) {
+               if (runparams.flavor == OutputParams::LYX) {
+                       Paragraph const & par = text().paragraphs()[par_begin];
+                       ostringstream ods;
+                       depth_type dt = par.getDepth();
+                       par.write(ods, params(), dt);
+                       os << from_utf8(ods.str());
+               } else if (runparams.flavor == OutputParams::HTML) {
                        XHTMLStream xs(os);
                        setMathFlavor(runparams);
                        xhtmlParagraphs(text(), *this, xs, runparams);
@@ -3318,10 +3585,34 @@ void Buffer::getSourceCode(odocstream & os, string const format,
                        // Probably should have some routine with a signature like them.
                        writePlaintextParagraph(*this,
                                text().paragraphs()[par_begin], os, runparams, dummy);
+               } else if (params().isDocBook()) {
+                       docbookParagraphs(text(), *this, os, runparams);
                } else {
+                       // If we are previewing a paragraph, even if this is the
+                       // child of some other buffer, let's cut the link here,
+                       // so that no concurring settings from the master
+                       // (e.g. branch state) interfere (see #8101).
+                       if (!master)
+                               d->ignore_parent = true;
+                       // We need to validate the Buffer params' features here
+                       // in order to know if we should output polyglossia
+                       // macros (instead of babel macros)
+                       LaTeXFeatures features(*this, params(), runparams);
+                       params().validate(features);
+                       runparams.use_polyglossia = features.usePolyglossia();
+                       TexRow texrow;
+                       texrow.reset();
+                       texrow.newline();
+                       texrow.newline();
                        // latex or literate
                        otexstream ots(os, texrow);
+
+                       // the real stuff
                        latexParagraphs(*this, text(), ots, runparams);
+
+                       // Restore the parenthood
+                       if (!master)
+                               d->ignore_parent = false;
                }
        } else {
                os << "% ";
@@ -3332,16 +3623,32 @@ void Buffer::getSourceCode(odocstream & os, string const format,
                else if (output == OnlyBody)
                        os << _("Preview body");
                os << "\n\n";
-               d->texrow.reset();
-               d->texrow.newline();
-               d->texrow.newline();
-               if (params().isDocBook())
-                       writeDocBookSource(os, absFileName(), runparams, output);
-               else if (runparams.flavor == OutputParams::HTML)
+               if (runparams.flavor == OutputParams::LYX) {
+                       ostringstream ods;
+                       if (output == FullSource)
+                               write(ods);
+                       else if (output == OnlyPreamble)
+                               params().writeFile(ods);
+                       else if (output == OnlyBody)
+                               text().write(ods);
+                       os << from_utf8(ods.str());
+               } else if (runparams.flavor == OutputParams::HTML) {
                        writeLyXHTMLSource(os, runparams, output);
-               else {
+               } else if (runparams.flavor == OutputParams::TEXT) {
+                       if (output == OnlyPreamble) {
+                               os << "% "<< _("Plain text does not have a preamble.");
+                       } else
+                               writePlaintextFile(*this, os, runparams);
+               } else if (params().isDocBook()) {
+                               writeDocBookSource(os, absFileName(), runparams, output);
+               } else {
                        // latex or literate
+                       d->texrow.reset();
+                       d->texrow.newline();
+                       d->texrow.newline();
                        otexstream ots(os, d->texrow);
+                       if (master)
+                               runparams.is_child = true;
                        writeLaTeXSource(ots, string(), runparams, output);
                }
        }
@@ -3471,11 +3778,13 @@ int AutoSaveBuffer::generateChild()
        // to fork. But we will do the save
        // anyway.
        bool failed = false;
-       FileName const tmp_ret = FileName::tempName("lyxauto");
+       TempFile tempfile("lyxautoXXXXXX.lyx");
+       tempfile.setAutoRemove(false);
+       FileName const tmp_ret = tempfile.name();
        if (!tmp_ret.empty()) {
-               buffer_.writeFile(tmp_ret);
-               // assume successful write of tmp_ret
-               if (!tmp_ret.moveTo(fname_))
+               if (!buffer_.writeFile(tmp_ret))
+                       failed = true;
+               else if (!tmp_ret.moveTo(fname_))
                        failed = true;
        } else
                failed = true;
@@ -3551,45 +3860,22 @@ bool Buffer::autoSave() const
        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;
-       }
-}
-
+       LASSERT(d->cloned_buffer_, return false);
 
-// helper class, to guarantee this gets reset properly
-class Buffer::MarkAsExporting {
-public:
-       MarkAsExporting(Buffer const * buf) : buf_(buf)
-       {
-               LASSERT(buf_, /* */);
-               buf_->setExportStatus(true);
-       }
-       ~MarkAsExporting()
-       {
-               buf_->setExportStatus(false);
+       // If this buffer is cloned, we assume that
+       // we are running in a separate thread already.
+       TempFile tempfile("lyxautoXXXXXX.lyx");
+       tempfile.setAutoRemove(false);
+       FileName const tmp_ret = tempfile.name();
+       if (!tmp_ret.empty()) {
+               writeFile(tmp_ret);
+               // assume successful write of tmp_ret
+               if (tmp_ret.moveTo(fname))
+                       return true;
        }
-private:
-       Buffer const * const buf_;
-};
-
+       // failed to write/rename tmp_ret so try writing direct
+       return writeFile(fname);
+}
 
 
 void Buffer::setExportStatus(bool e) const
@@ -3676,6 +3962,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
        runparams.includeall = includeall;
        vector<string> backs = params().backends();
        Converters converters = theConverters();
+       bool need_nice_file = false;
        if (find(backs.begin(), backs.end(), format) == backs.end()) {
                // Get shortest path to format
                converters.buildGraph();
@@ -3699,6 +3986,13 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
                        return ExportNoPathToFormat;
                }
                runparams.flavor = converters.getFlavor(path, this);
+               Graph::EdgePath::const_iterator it = path.begin();
+               Graph::EdgePath::const_iterator en = path.end();
+               for (; it != en; ++it)
+                       if (theConverters().get(*it).nice) {
+                               need_nice_file = true;
+                               break;
+                       }
 
        } else {
                backend_format = format;
@@ -3738,7 +4032,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
                makeDocBookFile(FileName(filename), runparams);
        }
        // LaTeX backend
-       else if (backend_format == format) {
+       else if (backend_format == format || need_nice_file) {
                runparams.nice = true;
                bool const success = makeLaTeXFile(FileName(filename), string(), runparams);
                if (d->cloned_buffer_)
@@ -3772,17 +4066,21 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
        // Emit the signal to show the error list or copy it back to the
        // cloned Buffer so that it can be emitted afterwards.
        if (format != backend_format) {
-               if (d->cloned_buffer_) {
+               if (runparams.silent)
+                       error_list.clear();
+               else if (d->cloned_buffer_)
                        d->cloned_buffer_->d->errorLists[error_type] =
                                d->errorLists[error_type];
-               else
+               else
                        errors(error_type);
                // also to the children, in case of master-buffer-view
                ListOfBuffers clist = getDescendents();
                ListOfBuffers::const_iterator cit = clist.begin();
                ListOfBuffers::const_iterator const cen = clist.end();
                for (; cit != cen; ++cit) {
-                       if (d->cloned_buffer_) {
+                       if (runparams.silent)
+                               (*cit)->d->errorLists[error_type].clear();
+                       else if (d->cloned_buffer_) {
                                // Enable reverse search by copying back the
                                // texrow object to the cloned buffer.
                                // FIXME: this is not thread safe.
@@ -3886,6 +4184,7 @@ Buffer::ExportStatus Buffer::preview(string const & format) const
        return preview(format, update_unincluded);
 }
 
+
 Buffer::ExportStatus Buffer::preview(string const & format, bool includeall) const
 {
        MarkAsExporting exporting(this);
@@ -3946,6 +4245,7 @@ Buffer::ReadStatus Buffer::loadEmergency()
                                        "file."), from_utf8(d->filename.absFileName())));
                        }
                        markDirty();
+                       lyxvc().file_found_hook(d->filename);
                        str = _("Document was successfully recovered.");
                } else
                        str = _("Document was NOT successfully recovered.");
@@ -4009,6 +4309,7 @@ Buffer::ReadStatus Buffer::loadAutosave()
                                        from_utf8(d->filename.absFileName())));
                        }
                        markDirty();
+                       lyxvc().file_found_hook(d->filename);
                        return ReadSuccess;
                }
                return ReadAutosaveFailure;
@@ -4114,13 +4415,17 @@ void Buffer::setBuffersForInsets() const
 
 void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
 {
+       LBUFERR(!text().paragraphs().empty());
+
        // 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 (master == this)
+       if (master == this) {
+               textclass.counters().reset(from_ascii("bibitem"));
                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.
@@ -4131,9 +4436,15 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
                if (master != this) {
                        bufToUpdate.insert(this);
                        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_)
+                       // If the master buffer has no gui associated with it, then the TocModel is 
+                       // not updated during the updateBuffer call and TocModel::toc_ is invalid 
+                       // (bug 5699). The same happens if the master buffer is open in a different 
+                       // window. This test catches both possibilities.
+                       // See: http://marc.info/?l=lyx-devel&m=138590578911716&w=2
+                       // There remains a problem here: If there is another child open in yet a third
+                       // window, that TOC is not updated. So some more general solution is needed at
+                       // some point.
+                       if (master->d->gui_ != d->gui_)
                                structureChanged();
 
                        // was buf referenced from the master (i.e. not in bufToUpdate anymore)?
@@ -4154,8 +4465,6 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
 
        Buffer & cbuf = const_cast<Buffer &>(*this);
 
-       LASSERT(!text().paragraphs().empty(), /**/);
-
        // do the real work
        ParIterator parit = cbuf.par_iterator_begin();
        updateBuffer(parit, utype);
@@ -4166,7 +4475,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
 
        d->bibinfo_cache_valid_ = true;
        d->cite_labels_valid_ = true;
-       cbuf.tocBackend().update();
+       cbuf.tocBackend().update(utype == OutputUpdate);
        if (scope == UpdateMaster)
                cbuf.structureChanged();
 }
@@ -4227,7 +4536,7 @@ static depth_type getItemDepth(ParIterator const & it)
 static bool needEnumCounterReset(ParIterator const & it)
 {
        Paragraph const & par = *it;
-       LASSERT(par.layout().labeltype == LABEL_ENUMERATE, /**/);
+       LASSERT(par.layout().labeltype == LABEL_ENUMERATE, return false);
        depth_type const cur_depth = par.getDepth();
        ParIterator prev_it = it;
        while (prev_it.pit()) {
@@ -4251,9 +4560,11 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const
        Counters & counters = textclass.counters();
 
        if (par.params().startOfAppendix()) {
-               // FIXME: only the counter corresponding to toplevel
-               // sectioning should be reset
-               counters.reset();
+               // We want to reset the counter corresponding to toplevel sectioning
+               Layout const & lay = textclass.getTOCLayout();
+               docstring const cnt = lay.counter;
+               if (!cnt.empty())
+                       counters.reset(cnt);
                counters.appendix(true);
        }
        par.params().appendix(counters.appendix());
@@ -4272,17 +4583,6 @@ 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()))) {
-                       if (counters.hasCounter(layout.counter))
-                               counters.step(layout.counter, utype);
-                       par.params().labelString(par.expandLabel(layout, bp));
-               } else
-                       par.params().labelString(docstring());
-               break;
-
        case LABEL_ITEMIZE: {
                // At some point of time we should do something more
                // clever here, like:
@@ -4362,19 +4662,34 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const
                par.params().labelString(docstring());
                break;
 
+       case LABEL_ABOVE:
+       case LABEL_CENTERED:
+       case LABEL_STATIC: {
+               docstring const & lcounter = layout.counter;
+               if (!lcounter.empty()) {
+                       if (layout.toclevel <= bp.secnumdepth
+                                               && (layout.latextype != LATEX_ENVIRONMENT
+                                       || it.text()->isFirstInSequence(it.pit()))) {
+                               if (counters.hasCounter(lcounter))
+                                       counters.step(lcounter, utype);
+                               par.params().labelString(par.expandLabel(layout, bp));
+                       } else
+                               par.params().labelString(docstring());
+               } else
+                       par.params().labelString(par.expandLabel(layout, bp));
+               break;
+       }
+
        case LABEL_MANUAL:
-       case LABEL_TOP_ENVIRONMENT:
-       case LABEL_CENTERED_TOP_ENVIRONMENT:
-       case LABEL_STATIC:
        case LABEL_BIBLIO:
                par.params().labelString(par.expandLabel(layout, bp));
-               break;
        }
 }
 
 
 void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const
 {
+       // LASSERT: Is it safe to continue here, or should we just return?
        LASSERT(parit.pit() == 0, /**/);
 
        // Set the position of the text in the buffer to be able
@@ -4385,7 +4700,17 @@ void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const
        pit_type const lastpit = parit.lastpit();
        for ( ; parit.pit() <= lastpit ; ++parit.pit()) {
                // reduce depth if necessary
-               parit->params().depth(min(parit->params().depth(), maxdepth));
+               if (parit->params().depth() > maxdepth) {
+                       /** FIXME: this function is const, but
+                        * nevertheless it modifies the buffer. To be
+                        * cleaner, one should modify the buffer in
+                        * another function, which is actually
+                        * non-const. This would however be costly in
+                        * terms of code duplication.
+                        */
+                       const_cast<Buffer *>(this)->undo().recordUndo(CursorData(parit));
+                       parit->params().depth(maxdepth);
+               }
                maxdepth = parit->getMaxDepthAfter();
 
                if (utype == OutputUpdate) {
@@ -4455,16 +4780,16 @@ void Buffer::Impl::updateStatistics(DocIterator & from, DocIterator & to, bool s
        word_count_ = 0;
        char_count_ = 0;
        blank_count_ = 0;
+
        for (DocIterator dit = from ; dit != to && !dit.atEnd(); ) {
                if (!dit.inTexted()) {
                        dit.forwardPos();
                        continue;
                }
-               
+
                Paragraph const & par = dit.paragraph();
                pos_type const pos = dit.pos();
-               
+
                // Copied and adapted from isWordSeparator() in Paragraph
                if (pos == dit.lastpos()) {
                        inword = false;
@@ -4478,7 +4803,7 @@ void Buffer::Impl::updateStatistics(DocIterator & from, DocIterator & to, bool s
                                        break;
                                continue;
                        } else if (!par.isDeleted(pos)) {
-                               if (par.isWordSeparator(pos)) 
+                               if (par.isWordSeparator(pos))
                                        inword = false;
                                else if (!inword) {
                                        ++word_count_;
@@ -4571,6 +4896,7 @@ bool Buffer::saveAs(FileName const & fn)
                // we need to check that the locations of child buffers
                // are still valid.
                checkChildBuffers();
+               checkMasterBuffer();
                return true;
        } else {
                // save failed
@@ -4619,4 +4945,25 @@ void Buffer::checkChildBuffers()
        d->position_to_children.clear();
 }
 
+
+// If a child has been saved under a different name/path, it might have been
+// orphaned. Therefore the master needs to be reset (bug 8161).
+void Buffer::checkMasterBuffer()
+{
+       Buffer const * const master = masterBuffer();
+       if (master == this)
+               return;
+
+       // necessary to re-register the child (bug 5873)
+       // FIXME: clean up updateMacros (here, only
+       // child registering is needed).
+       master->updateMacros();
+       // (re)set master as master buffer, but only
+       // if we are a real child
+       if (master->isChild(this))
+               setParent(master);
+       else
+               setParent(0);
+}
+
 } // namespace lyx