]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
Initializing the gui_ member of the cloned buffer has strange side effects
[lyx.git] / src / Buffer.cpp
index 01277217613fac95f25e9ddee92ecb54aab01696..ce174381f700ca625a80fc78cbbceda73e791d75 100644 (file)
@@ -66,7 +66,6 @@
 #include "WordLangTuple.h"
 #include "WordList.h"
 
-#include "insets/InsetBibitem.h"
 #include "insets/InsetBibtex.h"
 #include "insets/InsetBranch.h"
 #include "insets/InsetInclude.h"
@@ -128,7 +127,7 @@ namespace {
 
 // Do not remove the comment below, so we get merge conflict in
 // independent branches. Instead add your own.
-int const LYX_FORMAT = 407; // uwestoehr: support for multirow offset
+int const LYX_FORMAT = 413; // rgh: html_css_as_file
 
 typedef map<string, bool> DepClean;
 typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
@@ -646,6 +645,7 @@ void Buffer::setFileName(FileName const & fname)
 {
        d->filename = fname;
        setReadonly(d->filename.isReadOnly());
+       saveCheckSum();
        updateTitles();
 }
 
@@ -672,7 +672,7 @@ int Buffer::readHeader(Lexer & lex)
        params().headsep.erase();
        params().footskip.erase();
        params().columnsep.erase();
-       params().fontsCJK.erase();
+       params().fonts_cjk.erase();
        params().listings_params.clear();
        params().clearLayoutModules();
        params().clearRemovedModules();
@@ -820,6 +820,14 @@ bool Buffer::readDocument(Lexer & lex)
        // read main text
        bool const res = text().read(lex, errorList, d->inset);
 
+       // inform parent buffer about local macros
+       if (parent()) {
+               Buffer const * pbuf = parent();
+               UserMacroSet::const_iterator cit = usermacros.begin();
+               UserMacroSet::const_iterator end = usermacros.end();
+               for (; cit != end; ++cit)
+                       pbuf->usermacros.insert(*cit);
+       }
        usermacros.clear();
        updateMacros();
        updateMacroInstances();
@@ -888,8 +896,8 @@ Buffer::ReadStatus Buffer::readFile(FileName const & fn)
        }
 
        d->file_fully_loaded = true;
-       d->read_only = !fname.isWritable();
-       params().compressed = fname.isZippedFile();
+       d->read_only = !d->filename.isWritable();
+       params().compressed = d->filename.isZippedFile();
        saveCheckSum();
        return ReadSuccess;
 }
@@ -987,14 +995,14 @@ Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn,
                if (from_format < LYX_FORMAT) {
                        Alert::error(_("Conversion script failed"),
                                bformat(_("%1$s is from an older version"
-                                       " of LyX, but the lyx2lyx script"
+                                       " of LyX and the lyx2lyx script"
                                        " failed to convert it."),
                                        from_utf8(fn.absFileName())));
                        return LyX2LyXOlderFormat;
                } else {
                        Alert::error(_("Conversion script failed"),
-                               bformat(_("%1$s is from an newer version"
-                                       " of LyX, but the lyx2lyx script"
+                               bformat(_("%1$s is from a newer version"
+                                       " of LyX and the lyx2lyx script"
                                        " failed to convert it."),
                                        from_utf8(fn.absFileName())));
                        return LyX2LyXNewerFormat;
@@ -1007,11 +1015,25 @@ Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn,
 // Should probably be moved to somewhere else: BufferView? GuiView?
 bool Buffer::save() const
 {
+       docstring const file = makeDisplayPath(absFileName(), 20);
+       d->filename.refresh();
+
+       // check the read-only status before moving the file as a backup
+       if (d->filename.exists()) {
+               bool const read_only = !d->filename.isWritable();
+               if (read_only) {
+                       Alert::warning(_("File is read-only"),
+                               bformat(_("The file %1$s cannot be written because it "
+                               "is marked as read-only."), file));
+                       return false;
+               }
+       }
+
        // ask if the disk file has been externally modified (use checksum method)
        if (fileName().exists() && isExternallyModified(checksum_method)) {
-               docstring const file = makeDisplayPath(absFileName(), 20);
-               docstring text = bformat(_("Document %1$s has been externally modified. Are you sure "
-                                                            "you want to overwrite this file?"), file);
+               docstring text = 
+                       bformat(_("Document %1$s has been externally modified. "
+                               "Are you sure you want to overwrite this file?"), file);
                int const ret = Alert::prompt(_("Overwrite modified file?"),
                        text, 1, 1, _("&Overwrite"), _("&Cancel"));
                if (ret == 1)
@@ -1033,13 +1055,18 @@ bool Buffer::save() const
                        backupName = FileName(addName(lyxrc.backupdir_path,
                                                      mangledName));
                }
-               // do not copy because of #6587
-               if (fileName().moveTo(backupName)) {
-                       madeBackup = true;
-               } else {
+
+               // Except file is symlink do not copy because of #6587.
+               // Hard links have bad luck.
+               if (fileName().isSymLink())
+                       madeBackup = fileName().copyTo(backupName);
+               else
+                       madeBackup = fileName().moveTo(backupName);
+
+               if (!madeBackup) {
                        Alert::error(_("Backup failure"),
                                     bformat(_("Cannot create backup file %1$s.\n"
-                                              "Please check whether the directory exists and is writeable."),
+                                              "Please check whether the directory exists and is writable."),
                                             from_utf8(backupName.absFileName())));
                        //LYXERR(Debug::DEBUG, "Fs error: " << fe.what());
                }
@@ -1112,10 +1139,10 @@ docstring Buffer::emergencyWrite()
                LYXERR0("  " << s);
                if (writeFile(FileName(s))) {
                        markClean();
-                       user_message += bformat(_("  Saved to %1$s. Phew.\n"), from_utf8(s));
+                       user_message += "  " + bformat(_("Saved to %1$s. Phew.\n"), from_utf8(s));
                        return user_message;
                } else {
-                       user_message += _("  Save failed! Trying again...\n");
+                       user_message += "  " + _("Save failed! Trying again...\n");
                }
        }
 
@@ -1125,11 +1152,11 @@ docstring Buffer::emergencyWrite()
        lyxerr << ' ' << s << endl;
        if (writeFile(FileName(s))) {
                markClean();
-               user_message += bformat(_("  Saved to %1$s. Phew.\n"), from_utf8(s));
+               user_message += "  " + bformat(_("Saved to %1$s. Phew.\n"), from_utf8(s));
                return user_message;
        }
 
-       user_message += _("  Save failed! Trying yet again...\n");
+       user_message += "  " + _("Save failed! Trying yet again...\n");
 
        // 3) In "/tmp" directory.
        // MakeAbsPath to prepend the current
@@ -1139,11 +1166,11 @@ docstring Buffer::emergencyWrite()
        lyxerr << ' ' << s << endl;
        if (writeFile(FileName(s))) {
                markClean();
-               user_message += bformat(_("  Saved to %1$s. Phew.\n"), from_utf8(s));
+               user_message += "  " + bformat(_("Saved to %1$s. Phew.\n"), from_utf8(s));
                return user_message;
        }
 
-       user_message += _("  Save failed! Bummer. Document is lost.");
+       user_message += "  " + _("Save failed! Bummer. Document is lost.");
        // Don't try again.
        markClean();
        return user_message;
@@ -1160,7 +1187,7 @@ bool Buffer::write(ostream & ofs) const
        // The top of the file should not be written by params().
 
        // write out a comment in the top of the file
-       ofs << "#LyX " << lyx_version
+       ofs << "#LyX " << lyx_version_major << "." << lyx_version_minor
            << " created this file. For more info see http://www.lyx.org/\n"
            << "\\lyxformat " << LYX_FORMAT << "\n"
            << "\\begin_document\n";
@@ -1217,8 +1244,11 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
                           bool output_preamble, bool output_body) const
 {
        OutputParams runparams = runparams_in;
-       if (params().useXetex)
-               runparams.flavor = OutputParams::XETEX;
+
+       // This is necessary for LuaTeX/XeTeX with tex fonts.
+       // See FIXME in BufferParams::encoding()
+       if (runparams.isFullUnicode())
+               runparams.encoding = encodings.fromLyXName("utf8-plain");
 
        string const encoding = runparams.encoding->iconvName();
        LYXERR(Debug::LATEX, "makeLaTeXFile encoding: " << encoding << "...");
@@ -1239,9 +1269,10 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
        ErrorList & errorList = d->errorLists["Export"];
        errorList.clear();
        bool failed_export = false;
+       otexstream os(ofs, d->texrow);
        try {
-               d->texrow.reset();
-               writeLaTeXSource(ofs, original_path,
+               os.texrow().reset();
+               writeLaTeXSource(os, original_path,
                      runparams, output_preamble, output_body);
        }
        catch (EncodingException & e) {
@@ -1284,7 +1315,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
 }
 
 
-void Buffer::writeLaTeXSource(odocstream & os,
+void Buffer::writeLaTeXSource(otexstream & os,
                           string const & original_path,
                           OutputParams const & runparams_in,
                           bool const output_preamble, bool const output_body) const
@@ -1309,8 +1340,6 @@ void Buffer::writeLaTeXSource(odocstream & os,
                        "For more info, see http://www.lyx.org/.\n"
                        "%% Do not edit unless you really know what "
                        "you are doing.\n";
-               d->texrow.newline();
-               d->texrow.newline();
        }
        LYXERR(Debug::INFO, "lyx document header finished");
 
@@ -1336,9 +1365,7 @@ void Buffer::writeLaTeXSource(odocstream & os,
        if (output_preamble) {
                if (!runparams.nice) {
                        // code for usual, NOT nice-latex-file
-                       os << "\\batchmode\n"; // changed
-                       // from \nonstopmode
-                       d->texrow.newline();
+                       os << "\\batchmode\n"; // changed from \nonstopmode
                }
                if (!original_path.empty()) {
                        // FIXME UNICODE
@@ -1374,9 +1401,6 @@ void Buffer::writeLaTeXSource(odocstream & os,
                                   << "\\def\\input@path{{"
                                   << inputpath << "/}}\n"
                                   << "\\makeatother\n";
-                               d->texrow.newline();
-                               d->texrow.newline();
-                               d->texrow.newline();
                        }
                }
 
@@ -1385,9 +1409,9 @@ void Buffer::writeLaTeXSource(odocstream & os,
                MacroSet parentMacros;
                listParentMacros(parentMacros, features);
 
+               runparams.use_polyglossia = features.usePolyglossia();
                // Write the preamble
                runparams.use_babel = params().writeLaTeX(os, features,
-                                                         d->texrow,
                                                          d->filename.onlyPath());
 
                runparams.use_japanese = features.isRequired("japanese");
@@ -1397,19 +1421,18 @@ void Buffer::writeLaTeXSource(odocstream & os,
 
                // make the body.
                os << "\\begin{document}\n";
-               d->texrow.newline();
 
                // output the parent macros
                MacroSet::iterator it = parentMacros.begin();
                MacroSet::iterator end = parentMacros.end();
                for (; it != end; ++it) {
-                       int num_lines = (*it)->write(os, true);
-                       d->texrow.newlines(num_lines);
+                       int num_lines = (*it)->write(os.os(), true);
+                       os.texrow().newlines(num_lines);
                }
                
        } // output_preamble
 
-       d->texrow.start(paragraphs().begin()->id(), 0);
+       os.texrow().start(paragraphs().begin()->id(), 0);
 
        LYXERR(Debug::INFO, "preamble finished, now the body.");
 
@@ -1423,7 +1446,7 @@ void Buffer::writeLaTeXSource(odocstream & os,
        }
 
        // the real stuff
-       latexParagraphs(*this, text(), os, d->texrow, runparams);
+       latexParagraphs(*this, text(), os, runparams);
 
        // Restore the parenthood if needed
        if (output_preamble)
@@ -1431,11 +1454,9 @@ void Buffer::writeLaTeXSource(odocstream & os,
 
        // add this just in case after all the paragraphs
        os << endl;
-       d->texrow.newline();
 
        if (output_preamble) {
                os << "\\end{document}\n";
-               d->texrow.newline();
                LYXERR(Debug::LATEX, "makeLaTeXFile...done");
        } else {
                LYXERR(Debug::LATEX, "LaTeXFile for inclusion made.");
@@ -1443,7 +1464,7 @@ void Buffer::writeLaTeXSource(odocstream & os,
        runparams_in.encoding = runparams.encoding;
 
        // Just to be sure. (Asger)
-       d->texrow.newline();
+       os.texrow().newline();
 
        //for (int i = 0; i<d->texrow.rows(); i++) {
        // int id,pos;
@@ -1452,7 +1473,7 @@ void Buffer::writeLaTeXSource(odocstream & os,
        //}
 
        LYXERR(Debug::INFO, "Finished making LaTeX file.");
-       LYXERR(Debug::INFO, "Row count was " << d->texrow.rows() - 1 << '.');
+       LYXERR(Debug::INFO, "Row count was " << os.texrow().rows() - 1 << '.');
 }
 
 
@@ -1613,7 +1634,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
 
                os << "\n<!-- Text Class Preamble -->\n"
                   << features.getTClassHTMLPreamble()
-                  << "\n<!-- Premable Snippets -->\n"
+                  << "\n<!-- Preamble Snippets -->\n"
                   << from_utf8(features.getPreambleSnippets());
 
                os << "\n<!-- Layout-provided Styles -->\n";
@@ -1791,21 +1812,19 @@ BiblioInfo const & Buffer::masterBibInfo() const
 }
 
 
-void Buffer::checkBibInfoCache() const 
+void Buffer::checkIfBibInfoCacheIsValid() const
 {
        // use the master's cache
        Buffer const * const tmp = masterBuffer();
        if (tmp != this) {
-               tmp->checkBibInfoCache();
+               tmp->checkIfBibInfoCacheIsValid();
                return;
        }
 
-       // this will also reload the cache if it is invalid 
-       support::FileNameList const & bibfiles_cache = getBibfilesCache();
-       
        // compare the cached timestamps with the actual ones.
-       support::FileNameList::const_iterator ei = bibfiles_cache.begin();
-       support::FileNameList::const_iterator en = bibfiles_cache.end();
+       FileNameList const & bibfiles_cache = getBibfilesCache();
+       FileNameList::const_iterator ei = bibfiles_cache.begin();
+       FileNameList::const_iterator en = bibfiles_cache.end();
        for (; ei != en; ++ ei) {
                time_t lastw = ei->lastModified();
                time_t prevw = d->bibfile_status_[*ei];
@@ -1814,20 +1833,50 @@ void Buffer::checkBibInfoCache() const
                        d->bibfile_status_[*ei] = lastw;
                }
        }
-       
-       // if not valid, then reload the info
-       if (!d->bibinfo_cache_valid_) {
-               d->bibinfo_.clear();
-               fillWithBibKeys(d->bibinfo_);
-               d->bibinfo_cache_valid_ = true;
+}
+
+
+void Buffer::reloadBibInfoCache() const
+{
+       // use the master's cache
+       Buffer const * const tmp = masterBuffer();
+       if (tmp != this) {
+               tmp->reloadBibInfoCache();
+               return;
        }
+
+       checkIfBibInfoCacheIsValid();
+       if (d->bibinfo_cache_valid_)
+               return;
+
+       d->bibinfo_.clear();
+       collectBibKeys();
+       d->bibinfo_cache_valid_ = true;
 }
 
 
-void Buffer::fillWithBibKeys(BiblioInfo & keys) const
+void Buffer::collectBibKeys() const
 {
        for (InsetIterator it = inset_iterator_begin(inset()); it; ++it)
-               it->fillWithBibKeys(keys, it);
+               it->collectBibKeys(it);
+}
+
+
+void Buffer::addBiblioInfo(BiblioInfo const & bi) const
+{
+       Buffer const * tmp = masterBuffer();
+       BiblioInfo & masterbi = (tmp == this) ?
+               d->bibinfo_ : tmp->d->bibinfo_;
+       masterbi.mergeBiblioInfo(bi);
+}
+
+
+void Buffer::addBibTeXInfo(docstring const & key, BibTeXInfo const & bi) const
+{
+       Buffer const * tmp = masterBuffer();
+       BiblioInfo & masterbi = (tmp == this) ?
+               d->bibinfo_ : tmp->d->bibinfo_;
+       masterbi[key] = bi;
 }
 
 
@@ -2388,6 +2437,8 @@ bool Buffer::isExternallyModified(CheckMethod method) const
 void Buffer::saveCheckSum() const
 {
        FileName const & file = d->filename;
+
+       file.refresh();
        if (file.exists()) {
                d->timestamp_ = file.lastModified();
                d->checksum_ = file.checksum();
@@ -2633,7 +2684,9 @@ MacroData const * Buffer::Impl::getBufferMacro(docstring const & name,
                        break;
 
                // scope ends behind pos?
-               if (pos < it->second.first) {
+               if (pos < it->second.first
+                       && (cloned_buffer_ ||
+                           theBufferList().isLoaded(it->second.second))) {
                        // look for macro in external file
                        macro_lock = true;
                        MacroData const * data
@@ -2995,22 +3048,23 @@ void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to,
 {
        //FIXME: This does not work for child documents yet.
        LASSERT(code == CITE_CODE, /**/);
+
+       reloadBibInfoCache();
+
        // Check if the label 'from' appears more than once
-       vector<docstring> labels;
-       string paramName;
-       checkBibInfoCache();
        BiblioInfo const & keys = masterBibInfo();
        BiblioInfo::const_iterator bit  = keys.begin();
        BiblioInfo::const_iterator bend = keys.end();
+       vector<docstring> labels;
 
        for (; bit != bend; ++bit)
                // FIXME UNICODE
                labels.push_back(bit->first);
-       paramName = "key";
 
        if (count(labels.begin(), labels.end(), from) > 1)
                return;
 
+       string const paramName = "key";
        for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) {
                if (it->lyxCode() == code) {
                        InsetCommand * inset = it->asInsetCommand();
@@ -3024,13 +3078,13 @@ void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to,
 }
 
 
-void Buffer::getSourceCode(odocstream & os, pit_type par_begin,
-       pit_type par_end, bool full_source) const
+void Buffer::getSourceCode(odocstream & os, string const format,
+                          pit_type par_begin, pit_type par_end,
+                          bool full_source) const
 {
        OutputParams runparams(&params().encoding());
        runparams.nice = true;
-       runparams.flavor = params().useXetex ? 
-               OutputParams::XETEX : OutputParams::LATEX;
+       runparams.flavor = getOutputFlavor(format);
        runparams.linelen = lyxrc.plaintext_linelen;
        // No side effect of file copying and image conversion
        runparams.dryrun = true;
@@ -3042,9 +3096,13 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin,
                d->texrow.newline();
                if (isDocBook())
                        writeDocBookSource(os, absFileName(), runparams, false);
-               else
+               else if (runparams.flavor == OutputParams::HTML)
+                       writeLyXHTMLSource(os, runparams, false);
+               else {
                        // latex or literate
-                       writeLaTeXSource(os, string(), runparams, true, true);
+                       otexstream ots(os, d->texrow);
+                       writeLaTeXSource(ots, string(), runparams, true, true);
+               }
        } else {
                runparams.par_begin = par_begin;
                runparams.par_end = par_end;
@@ -3066,9 +3124,14 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin,
                // output paragraphs
                if (isDocBook())
                        docbookParagraphs(text(), *this, os, runparams);
-               else 
+               else if (runparams.flavor == OutputParams::HTML) {
+                       XHTMLStream xs(os);
+                       xhtmlParagraphs(text(), *this, xs, runparams);
+               } else {
                        // latex or literate
-                       latexParagraphs(*this, text(), os, texrow, runparams);
+                       otexstream ots(os, texrow);
+                       latexParagraphs(*this, text(), ots, runparams);
+               }
        }
 }
 
@@ -3308,7 +3371,7 @@ string Buffer::bufferFormat() const
 {
        string format = params().documentClass().outputFormat();
        if (format == "latex") {
-               if (params().useXetex)
+               if (params().useNonTeXFonts)
                        return "xetex";
                if (params().encoding().package() == Encoding::japanese)
                        return "platex";
@@ -3319,15 +3382,13 @@ string Buffer::bufferFormat() const
 
 string Buffer::getDefaultOutputFormat() const
 {
-       if (!params().defaultOutputFormat.empty()
-           && params().defaultOutputFormat != "default")
-               return params().defaultOutputFormat;
-       typedef vector<Format const *> Formats;
-       Formats formats = exportableFormats(true);
+       if (!params().default_output_format.empty()
+           && params().default_output_format != "default")
+               return params().default_output_format;
        if (isDocBook()
-           || isLiterate()
-           || params().useXetex
+           || params().useNonTeXFonts
            || params().encoding().package() == Encoding::japanese) {
+               vector<Format const *> const formats = exportableFormats(true);
                if (formats.empty())
                        return string();
                // return the first we find
@@ -3337,6 +3398,43 @@ string Buffer::getDefaultOutputFormat() const
 }
 
 
+OutputParams::FLAVOR Buffer::getOutputFlavor(string const format) const
+{
+       string const dformat = (format.empty() || format == "default") ?
+               getDefaultOutputFormat() : format;
+       DefaultFlavorCache::const_iterator it =
+               default_flavors_.find(dformat);
+
+       if (it != default_flavors_.end())
+               return it->second;
+
+       OutputParams::FLAVOR result = OutputParams::LATEX;
+       
+       if (dformat == "xhtml")
+               result = OutputParams::HTML;
+       else {
+               // Try to determine flavor of default output format
+               vector<string> backs = backends();
+               if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
+                       // Get shortest path to format
+                       Graph::EdgePath path;
+                       for (vector<string>::const_iterator it = backs.begin();
+                           it != backs.end(); ++it) {
+                               Graph::EdgePath p = theConverters().getPath(*it, dformat);
+                               if (!p.empty() && (path.empty() || p.size() < path.size())) {
+                                       path = p;
+                               }
+                       }
+                       if (!path.empty())
+                               result = theConverters().getFlavor(path);
+               }
+       }
+       // cache this flavor
+       default_flavors_[dformat] = result;
+       return result;
+}
+
+
 namespace {
        // helper class, to guarantee this gets reset properly
        class MarkAsExporting   {
@@ -3378,12 +3476,14 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        runparams.linelen = lyxrc.plaintext_linelen;
        runparams.includeall = includeall;
        vector<string> backs = backends();
+       Converters converters = theConverters();
        if (find(backs.begin(), backs.end(), format) == backs.end()) {
                // Get shortest path to format
+               converters.buildGraph();
                Graph::EdgePath path;
                for (vector<string>::const_iterator it = backs.begin();
                     it != backs.end(); ++it) {
-                       Graph::EdgePath p = theConverters().getPath(*it, format);
+                       Graph::EdgePath p = converters.getPath(*it, format);
                        if (!p.empty() && (path.empty() || p.size() < path.size())) {
                                backend_format = *it;
                                path = p;
@@ -3399,13 +3499,17 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                        }
                        return false;
                }
-               runparams.flavor = theConverters().getFlavor(path);
+               runparams.flavor = converters.getFlavor(path);
 
        } else {
                backend_format = format;
                // FIXME: Don't hardcode format names here, but use a flag
                if (backend_format == "pdflatex")
                        runparams.flavor = OutputParams::PDFLATEX;
+               else if (backend_format == "luatex")
+                       runparams.flavor = OutputParams::LUATEX;
+               else if (backend_format == "xetex")
+                       runparams.flavor = OutputParams::XETEX;
        }
 
        string filename = latexName(false);
@@ -3436,11 +3540,10 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                        break;
                case BufferParams::LaTeX:
                        runparams.math_flavor = OutputParams::MathAsLaTeX; 
-                       break;                                                                                  
+                       break;
                }
-               
                makeLyXHTMLFile(FileName(filename), runparams);
-       }       else if (backend_format == "lyx")
+       } else if (backend_format == "lyx")
                writeFile(FileName(filename));
        // Docbook backend
        else if (isDocBook()) {
@@ -3450,8 +3553,13 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        // LaTeX backend
        else if (backend_format == format) {
                runparams.nice = true;
-               if (!makeLaTeXFile(FileName(filename), string(), runparams))
+               if (!makeLaTeXFile(FileName(filename), string(), runparams)) {
+                       if (d->cloned_buffer_) {
+                               d->cloned_buffer_->d->errorLists["Export"] =
+                                       d->errorLists["Export"];
+                       }
                        return false;
+               }
        } else if (!lyxrc.tex_allows_spaces
                   && contains(filePath(), ' ')) {
                Alert::error(_("File name error"),
@@ -3459,8 +3567,13 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                return false;
        } else {
                runparams.nice = false;
-               if (!makeLaTeXFile(FileName(filename), filePath(), runparams))
+               if (!makeLaTeXFile(FileName(filename), filePath(), runparams)) {
+                       if (d->cloned_buffer_) {
+                               d->cloned_buffer_->d->errorLists["Export"] =
+                                       d->errorLists["Export"];
+                       }
                        return false;
+               }
        }
 
        string const error_type = (format == "program")
@@ -3468,12 +3581,12 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        ErrorList & error_list = d->errorLists[error_type];
        string const ext = formats.extension(format);
        FileName const tmp_result_file(changeExtension(filename, ext));
-       bool const success = theConverters().convert(this, FileName(filename),
+       bool const success = converters.convert(this, FileName(filename),
                tmp_result_file, FileName(absFileName()), backend_format, format,
                error_list);
 
        // Emit the signal to show the error list or copy it back to the
-       // cloned Buffer so that it cab be emitted afterwards.
+       // cloned Buffer so that it can be emitted afterwards.
        if (format != backend_format) {
                if (d->cloned_buffer_) {
                        d->cloned_buffer_->d->errorLists[error_type] = 
@@ -3486,6 +3599,10 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                ListOfBuffers::const_iterator const cen = clist.end();
                for (; cit != cen; ++cit) {
                        if (d->cloned_buffer_) {
+                               // Enable reverse search by copying back the
+                               // texrow object to the cloned buffer.
+                               // FIXME: this is not thread safe.
+                               (*cit)->d->cloned_buffer_->d->texrow = (*cit)->d->texrow;
                                (*cit)->d->cloned_buffer_->d->errorLists[error_type] = 
                                        (*cit)->d->errorLists[error_type];
                        } else
@@ -3612,8 +3729,12 @@ vector<string> Buffer::backends() const
        vector<string> v;
        v.push_back(bufferFormat());
        // FIXME: Don't hardcode format names here, but use a flag
-       if (v.back() == "latex")
+       if (v.back() == "latex") {
                v.push_back("pdflatex");
+               v.push_back("luatex");
+               v.push_back("xetex");
+       } else if (v.back() == "xetex")
+               v.push_back("luatex");
        v.push_back("xhtml");
        v.push_back("text");
        v.push_back("lyx");
@@ -3653,6 +3774,13 @@ Buffer::ReadStatus Buffer::loadEmergency()
                ReadStatus const ret_llf = loadThisLyXFile(emergencyFile);
                bool const success = (ret_llf == ReadSuccess);
                if (success) {
+                       if (isReadonly()) {
+                               Alert::warning(_("File is read-only"),
+                                       bformat(_("An emergency file is successfully loaded, "
+                                       "but the original file %1$s is marked read-only. "
+                                       "Please make sure to save the document as a different "
+                                       "file."), from_utf8(d->filename.absFileName())));
+                       }
                        markDirty();
                        str = _("Document was successfully recovered.");
                } else
@@ -3708,6 +3836,14 @@ Buffer::ReadStatus Buffer::loadAutosave()
                ReadStatus const ret_llf = loadThisLyXFile(autosaveFile);
                // the file is not saved if we load the autosave file.
                if (ret_llf == ReadSuccess) {
+                       if (isReadonly()) {
+                               Alert::warning(_("File is read-only"),
+                                       bformat(_("A backup file is successfully loaded, "
+                                       "but the original file %1$s is marked read-only. "
+                                       "Please make sure to save the document as a "
+                                       "different file."), 
+                                       from_utf8(d->filename.absFileName())));
+                       }
                        markDirty();
                        return ReadSuccess;
                }
@@ -3788,7 +3924,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
        
        // do this only if we are the top-level Buffer
        if (master == this)
-               checkBibInfoCache();
+               reloadBibInfoCache();
 
        // keep the buffers to be children in this set. If the call from the
        // master comes back we can see which of them were actually seen (i.e.
@@ -3832,6 +3968,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
                // TocBackend update will be done later.
                return;
 
+       d->bibinfo_cache_valid_ = true;
        cbuf.tocBackend().update();
        if (scope == UpdateMaster)
                cbuf.structureChanged();
@@ -3938,11 +4075,11 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const
        switch(layout.labeltype) {
        case LABEL_COUNTER:
                if (layout.toclevel <= bp.secnumdepth
-                   && (layout.latextype != LATEX_ENVIRONMENT
-                       || it.text()->isFirstInSequence(it.pit()))) {
-                       counters.step(layout.counter, utype);
-                       par.params().labelString(
-                               par.expandLabel(layout, bp));
+                     && (layout.latextype != LATEX_ENVIRONMENT
+                         || it.text()->isFirstInSequence(it.pit()))) {
+                       if (counters.hasCounter(layout.counter))
+                               counters.step(layout.counter, utype);
+                       par.params().labelString(par.expandLabel(layout, bp));
                } else
                        par.params().labelString(docstring());
                break;
@@ -4128,6 +4265,7 @@ Buffer::ReadStatus Buffer::reload()
                updateTitles();
                markClean();
                message(bformat(_("Document %1$s reloaded."), disp_fn));
+               d->undo_.clear();
        } else {
                message(bformat(_("Could not reload document %1$s."), disp_fn));
        }       
@@ -4166,7 +4304,6 @@ bool Buffer::saveAs(FileName const & fn)
                // reset the old filename and unnamed state
                setFileName(old_name);
                setUnnamed(old_unnamed);
-               saveCheckSum();
                return false;
        }
 }