]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
Connect to InsetInfo
[lyx.git] / src / Buffer.cpp
index b42f14d028ff642e155f6bdc1feb7148a16b599b..7aa037a580107408d659cd31f0c7745c8bdc2ffb 100644 (file)
@@ -42,7 +42,6 @@
 #include "Lexer.h"
 #include "LyXAction.h"
 #include "LyX.h"
-#include "LyXFunc.h"
 #include "LyXRC.h"
 #include "LyXVC.h"
 #include "output_docbook.h"
@@ -127,7 +126,7 @@ namespace {
 
 // Do not remove the comment below, so we get merge conflict in
 // independent branches. Instead add your own.
-int const LYX_FORMAT = 370; // uwestoehr: option to suppress default date
+int const LYX_FORMAT = 377; // uwestoehr: support for multirows
 
 typedef map<string, bool> DepClean;
 typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
@@ -147,7 +146,7 @@ class BufferSet : public std::set<Buffer const *> {};
 class Buffer::Impl
 {
 public:
-       Impl(Buffer & parent, FileName const & file, bool readonly);
+       Impl(Buffer * owner, FileName const & file, bool readonly, Buffer const * cloned_buffer);
 
        ~Impl()
        {
@@ -158,6 +157,25 @@ public:
                delete inset;
        }
 
+       /// search for macro in local (buffer) table or in children
+       MacroData const * getBufferMacro(docstring const & name,
+               DocIterator const & pos) const;
+
+       /// Update macro table starting with position of it \param it in some
+       /// text inset.
+       void updateMacros(DocIterator & it, DocIterator & scope);
+       ///
+       void setLabel(ParIterator & it, UpdateType utype) const;
+       ///
+       void collectRelatives(BufferSet & bufs) const;
+
+       /** If we have branches that use the file suffix
+           feature, return the file name with suffix appended.
+       */
+       support::FileName exportFileName() const;
+
+       Buffer * owner_;
+
        BufferParams params;
        LyXVC lyxvc;
        FileName temppath;
@@ -197,7 +215,8 @@ public:
        /// map from the macro name to the position map,
        /// which maps the macro definition position to the scope and the MacroData.
        NamePositionScopeMacroMap macros;
-       bool macro_lock;
+       /// This seem to change the way Buffer::getMacro() works
+       mutable bool macro_lock;
 
        /// positions of child buffers in the buffer
        typedef map<Buffer const * const, DocIterator> BufferPositionMap;
@@ -218,13 +237,15 @@ public:
 
        ///
        frontend::WorkAreaManager * wa_;
+       ///
+       frontend::GuiBufferDelegate * gui_;
 
        ///
        Undo undo_;
 
        /// A cache for the bibfiles (including bibfiles of loaded child
        /// documents), needed for appropriate update of natbib labels.
-       mutable support::FileNameList bibfilesCache_;
+       mutable support::FileNameList bibfiles_cache_;
 
        // FIXME The caching mechanism could be improved. At present, we have a
        // cache for each Buffer, that caches all the bibliography info for that
@@ -233,9 +254,9 @@ public:
        /// A cache for bibliography info
        mutable BiblioInfo bibinfo_;
        /// whether the bibinfo cache is valid
-       bool bibinfoCacheValid_;
+       bool bibinfo_cache_valid_;
        /// Cache of timestamps of .bib files
-       map<FileName, time_t> bibfileStatus_;
+       map<FileName, time_t> bibfile_status_;
 
        mutable RefCache ref_cache_;
 
@@ -248,15 +269,28 @@ public:
                // 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.
-               if (!theBufferList().isLoaded(parent_buffer))
+               // however, the BufferList doesn't know about cloned buffers, so
+               // they will always be regarded as unloaded. in that case, we hope
+               // for the best.
+               if (!cloned_buffer_ && !theBufferList().isLoaded(parent_buffer))
                        parent_buffer = 0;
                return parent_buffer; 
        }
        ///
-       void setParent(Buffer const * pb) { parent_buffer = pb; }
+       void setParent(Buffer const * pb) {
+               if (parent_buffer && pb && parent_buffer != pb)
+                       LYXERR0("Warning: a buffer should not have two parents!");
+               parent_buffer = pb;
+       }
+
+       /// If non zero, this buffer is a clone of existing buffer \p cloned_buffer_
+       /// This one is useful for preview detached in a thread.
+       Buffer const * cloned_buffer_;
+
 private:
        /// So we can force access via the accessors.
        mutable Buffer const * parent_buffer;
+
 };
 
 
@@ -279,26 +313,46 @@ static FileName createBufferTmpDir()
 }
 
 
-Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_)
-       : lyx_clean(true), bak_clean(true), unnamed(false),
+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(&parent), macro_lock(false), timestamp_(0),
-         checksum_(0), wa_(0), undo_(parent), bibinfoCacheValid_(false),
-         parent_buffer(0)
-{
-       temppath = createBufferTmpDir();
-       lyxvc.setBuffer(&parent);
-       if (use_gui)
-               wa_ = new frontend::WorkAreaManager;
+         toc_backend(owner), macro_lock(false), timestamp_(0),
+         checksum_(0), wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false),
+         cloned_buffer_(cloned_buffer), parent_buffer(0)
+{
+       if (!cloned_buffer_) {
+               temppath = createBufferTmpDir();
+               lyxvc.setBuffer(owner_);
+               if (use_gui)
+                       wa_ = new frontend::WorkAreaManager;
+               return;
+       }
+       temppath = cloned_buffer_->d->temppath;
+       file_fully_loaded = true;
+       params = cloned_buffer_->d->params;
+       bibfiles_cache_ = cloned_buffer_->d->bibfiles_cache_;
+       bibinfo_ = cloned_buffer_->d->bibinfo_;
+       bibinfo_cache_valid_ = cloned_buffer_->d->bibinfo_cache_valid_;
+       bibfile_status_ = cloned_buffer_->d->bibfile_status_;
 }
 
 
-Buffer::Buffer(string const & file, bool readonly)
-       : d(new Impl(*this, FileName(file), readonly)), gui_(0)
+Buffer::Buffer(string const & file, bool readonly, Buffer const * cloned_buffer)
+       : d(new Impl(this, FileName(file), readonly, cloned_buffer))
 {
        LYXERR(Debug::INFO, "Buffer::Buffer()");
-
-       d->inset = new InsetText(*this);
+       if (cloned_buffer) {
+               d->inset = new InsetText(*cloned_buffer->d->inset);
+               d->inset->setBuffer(*this);
+               // FIXME: optimize this loop somewhat, maybe by creating a new
+               // general recursive Inset::setId().
+               DocIterator it = doc_iterator_begin(this);
+               DocIterator cloned_it = doc_iterator_begin(cloned_buffer);
+               for (; !it.atEnd(); it.forwardPar(), cloned_it.forwardPar())
+                       it.paragraph().setId(cloned_it.paragraph().id());
+       } else
+               d->inset = new InsetText(this);
        d->inset->setAutoBreakRows(true);
        d->inset->getText(0)->setMacrocontextPosition(par_iterator_begin());
 }
@@ -311,7 +365,7 @@ Buffer::~Buffer()
        // saved properly, before it goes into the void.
 
        // GuiView already destroyed
-       gui_ = 0;
+       d->gui_ = 0;
 
        if (isInternal()) {
                // No need to do additional cleanups for internal buffer.
@@ -324,22 +378,24 @@ Buffer::~Buffer()
        Impl::BufferPositionMap::iterator end = d->children_positions.end();
        for (; it != end; ++it) {
                Buffer * child = const_cast<Buffer *>(it->first);
+               if (d->cloned_buffer_)
+                       delete child;
                // The child buffer might have been closed already.
-               if (theBufferList().isLoaded(child))
+               else if (theBufferList().isLoaded(child))
                        theBufferList().releaseChild(this, child);
        }
 
        if (!isClean()) {
                docstring msg = _("LyX attempted to close a document that had unsaved changes!\n");
                msg += emergencyWrite();
-               frontend::Alert::warning(_("Attempting to close changed document!"), msg);
+               Alert::warning(_("Attempting to close changed document!"), msg);
        }
                
        // clear references to children in macro tables
        d->children_positions.clear();
        d->position_to_children.clear();
 
-       if (!d->temppath.destroyDirectory()) {
+       if (!d->cloned_buffer_ && !d->temppath.destroyDirectory()) {
                Alert::warning(_("Could not remove temporary directory"),
                        bformat(_("Could not remove the temporary directory %1$s"),
                        from_utf8(d->temppath.absFilename())));
@@ -352,10 +408,44 @@ Buffer::~Buffer()
 }
 
 
-void Buffer::changed() const
+Buffer * Buffer::clone() const
+{
+       Buffer * buffer_clone = new Buffer(fileName().absFilename(), false, this);
+       buffer_clone->d->macro_lock = true;
+       buffer_clone->d->children_positions.clear();
+       // FIXME (Abdel 09/01/2010): this is too complicated. The whole children_positions and
+       // math macro caches need to be rethought and simplified.
+       // I am not sure wether we should handle Buffer cloning here or in BufferList.
+       // Right now BufferList knows nothing about buffer clones.
+       Impl::BufferPositionMap::iterator it = d->children_positions.begin();
+       Impl::BufferPositionMap::iterator end = d->children_positions.end();
+       for (; it != end; ++it) {
+               DocIterator dit = it->second.clone(buffer_clone);
+               dit.setBuffer(buffer_clone);
+               Buffer * child = const_cast<Buffer *>(it->first);
+               Buffer * child_clone = child->clone();
+               Inset * inset = dit.nextInset();
+               LASSERT(inset && inset->lyxCode() == INCLUDE_CODE, continue);
+               InsetInclude * inset_inc = static_cast<InsetInclude *>(inset);
+               inset_inc->setChildBuffer(child_clone);
+               child_clone->d->setParent(buffer_clone);
+               buffer_clone->setChild(dit, child_clone);
+       }
+       buffer_clone->d->macro_lock = false;
+       return buffer_clone;
+}
+
+
+bool Buffer::isClone() const
+{
+       return d->cloned_buffer_;
+}
+
+
+void Buffer::changed(bool update_metrics) const
 {
        if (d->wa_)
-               d->wa_->redrawAll();
+               d->wa_->redrawAll(update_metrics);
 }
 
 
@@ -444,26 +534,32 @@ Undo & Buffer::undo()
 }
 
 
+void Buffer::setChild(DocIterator const & dit, Buffer * child)
+{
+       d->children_positions[child] = dit;
+}
+
+
 string Buffer::latexName(bool const no_path) const
 {
        FileName latex_name =
-               makeLatexName(exportFileName());
+               makeLatexName(d->exportFileName());
        return no_path ? latex_name.onlyFileName()
                : latex_name.absFilename();
 }
 
 
-FileName Buffer::exportFileName() const
+FileName Buffer::Impl::exportFileName() const
 {
        docstring const branch_suffix =
-               params().branchlist().getFilenameSuffix();
+               params.branchlist().getFilenameSuffix();
        if (branch_suffix.empty())
-               return fileName();
+               return filename;
 
-       string const name = fileName().onlyFileNameWithoutExt()
+       string const name = filename.onlyFileNameWithoutExt()
                + to_utf8(branch_suffix);
-       FileName res(fileName().onlyPath().absFilename() + "/" + name);
-       res.changeExtension(fileName().extension());
+       FileName res(filename.onlyPath().absFilename() + "/" + name);
+       res.changeExtension(filename.extension());
 
        return res;
 }
@@ -528,7 +624,7 @@ void Buffer::setReadonly(bool const flag)
 {
        if (d->read_only != flag) {
                d->read_only = flag;
-               setReadOnly(flag);
+               changed(false);
        }
 }
 
@@ -567,6 +663,7 @@ int Buffer::readHeader(Lexer & lex)
        params().listings_params.clear();
        params().clearLayoutModules();
        params().clearRemovedModules();
+       params().clearIncludedChildren();
        params().pdfoptions().clear();
        params().indiceslist().clear();
        params().backgroundcolor = lyx::rgbFromHexName("#ffffff");
@@ -701,6 +798,7 @@ bool Buffer::readDocument(Lexer & lex)
        // read main text
        bool const res = text().read(lex, errorList, d->inset);
 
+       usermacros.clear();
        updateMacros();
        updateMacroInstances();
        return res;
@@ -839,11 +937,18 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
 
                cmd_ret const ret = runCommand(command_str);
                if (ret.first != 0) {
-                       Alert::error(_("Conversion script failed"),
-                                    bformat(_("%1$s is from a different version"
+                       if (file_format < LYX_FORMAT)
+                               Alert::error(_("Conversion script failed"),
+                                    bformat(_("%1$s is from an older version"
                                              " of LyX, but the lyx2lyx script"
                                              " failed to convert it."),
                                              from_utf8(filename.absFilename())));
+                       else
+                               Alert::error(_("Conversion script failed"),
+                                    bformat(_("%1$s is from a newer version"
+                                             " of LyX and cannot be converted by the"
+                                                               " lyx2lyx script."),
+                                             from_utf8(filename.absFilename())));
                        return failure;
                } else {
                        bool const ret = readFile(tmpfile);
@@ -858,6 +963,7 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
                             bformat(_("%1$s ended unexpectedly, which means"
                                                    " that it is probably corrupted."),
                                       from_utf8(filename.absFilename())));
+               return failure;
        }
 
        d->file_fully_loaded = true;
@@ -865,7 +971,7 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
 }
 
 
-// Should probably be moved to somewhere else: BufferView? LyXView?
+// Should probably be moved to somewhere else: BufferView? GuiView?
 bool Buffer::save() const
 {
        // We don't need autosaves in the immediate future. (Asger)
@@ -1218,7 +1324,9 @@ void Buffer::writeLaTeXSource(odocstream & os,
                listParentMacros(parentMacros, features);
 
                // Write the preamble
-               runparams.use_babel = params().writeLaTeX(os, features, d->texrow);
+               runparams.use_babel = params().writeLaTeX(os, features,
+                                                         d->texrow,
+                                                         d->filename.onlyPath());
 
                runparams.use_japanese = features.isRequired("japanese");
 
@@ -1232,8 +1340,11 @@ void Buffer::writeLaTeXSource(odocstream & os,
                // output the parent macros
                MacroSet::iterator it = parentMacros.begin();
                MacroSet::iterator end = parentMacros.end();
-               for (; it != end; ++it)
-                       (*it)->write(os, true);
+               for (; it != end; ++it) {
+                       int num_lines = (*it)->write(os, true);
+                       d->texrow.newlines(num_lines);
+               }
+               
        } // output_preamble
 
        d->texrow.start(paragraphs().begin()->id(), 0);
@@ -1412,36 +1523,40 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
 {
        LaTeXFeatures features(*this, params(), runparams);
        validate(features);
-
-       d->texrow.reset();
+       updateLabels(UpdateMaster, OutputUpdate);
+       checkBibInfoCache();
+       d->bibinfo_.makeCitationLabels(*this);
+       updateMacros();
+       updateMacroInstances();
 
        if (!only_body) {
-               os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" <<
-                       " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
+               os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+               os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\" \"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd\">\n";
                // FIXME Language should be set properly.
-               os << "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n";
-               // FIXME Header
+               os << "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
                os << "<head>\n";
                // FIXME Presumably need to set this right
                os << "<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n";
-               // FIXME Get this during validation? What about other meta-data?
-               os << "<title>TBA</title>\n";
+               os << "<title>" << features.htmlTitle() << "</title>\n";
 
-               os << features.getTClassHTMLPreamble();
-
-               os << '\n';
+               os << "\n<!-- Text Class Preamble -->\n"
+                       << features.getTClassHTMLPreamble()
+                       << "\n<!-- Premable Snippets -->\n"
+                       << from_utf8(features.getPreambleSnippets());
 
+               os << "\n<!-- Layout-provided Styles -->\n";
                docstring const styleinfo = features.getTClassHTMLStyles();
                if (!styleinfo.empty()) {
-                       os << "<style type='text/css'>\n";
-                       os << styleinfo;
-                       os << "</style>\n";
+                       os << "<style type='text/css'>\n"
+                               << styleinfo
+                               << "</style>\n";
                }
                os << "</head>\n<body>\n";
        }
 
+       XHTMLStream xs(os);
        params().documentClass().counters().reset();
-       xhtmlParagraphs(text(), *this, os, runparams);
+       xhtmlParagraphs(text(), *this, xs, runparams);
        if (!only_body)
                os << "</body>\n</html>\n";
 }
@@ -1532,13 +1647,13 @@ void Buffer::updateBibfilesCache(UpdateScope scope) const
                return;
        }
 
-       d->bibfilesCache_.clear();
+       d->bibfiles_cache_.clear();
        for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) {
                if (it->lyxCode() == BIBTEX_CODE) {
                        InsetBibtex const & inset =
                                static_cast<InsetBibtex const &>(*it);
                        support::FileNameList const bibfiles = inset.getBibFiles();
-                       d->bibfilesCache_.insert(d->bibfilesCache_.end(),
+                       d->bibfiles_cache_.insert(d->bibfiles_cache_.end(),
                                bibfiles.begin(),
                                bibfiles.end());
                } else if (it->lyxCode() == INCLUDE_CODE) {
@@ -1547,19 +1662,19 @@ void Buffer::updateBibfilesCache(UpdateScope scope) const
                        inset.updateBibfilesCache();
                        support::FileNameList const & bibfiles =
                                        inset.getBibfilesCache();
-                       d->bibfilesCache_.insert(d->bibfilesCache_.end(),
+                       d->bibfiles_cache_.insert(d->bibfiles_cache_.end(),
                                bibfiles.begin(),
                                bibfiles.end());
                }
        }
        // the bibinfo cache is now invalid
-       d->bibinfoCacheValid_ = false;
+       d->bibinfo_cache_valid_ = false;
 }
 
 
 void Buffer::invalidateBibinfoCache()
 {
-       d->bibinfoCacheValid_ = false;
+       d->bibinfo_cache_valid_ = false;
 }
 
 
@@ -1571,10 +1686,10 @@ support::FileNameList const & Buffer::getBibfilesCache(UpdateScope scope) const
                return pbuf->getBibfilesCache();
 
        // We update the cache when first used instead of at loading time.
-       if (d->bibfilesCache_.empty())
+       if (d->bibfiles_cache_.empty())
                const_cast<Buffer *>(this)->updateBibfilesCache(scope);
 
-       return d->bibfilesCache_;
+       return d->bibfiles_cache_;
 }
 
 
@@ -1592,28 +1707,31 @@ BiblioInfo const & Buffer::masterBibInfo() const
 
 BiblioInfo const & Buffer::localBibInfo() const
 {
-       if (d->bibinfoCacheValid_) {
-               support::FileNameList const & bibfilesCache = getBibfilesCache();
-               // compare the cached timestamps with the actual ones.
-               support::FileNameList::const_iterator ei = bibfilesCache.begin();
-               support::FileNameList::const_iterator en = bibfilesCache.end();
-               for (; ei != en; ++ ei) {
-                       time_t lastw = ei->lastModified();
-                       if (lastw != d->bibfileStatus_[*ei]) {
-                               d->bibinfoCacheValid_ = false;
-                               d->bibfileStatus_[*ei] = lastw;
-                               break;
-                       }
+       return d->bibinfo_;
+}
+
+
+void Buffer::checkBibInfoCache() const 
+{
+       support::FileNameList const & bibfilesCache = getBibfilesCache();
+       // compare the cached timestamps with the actual ones.
+       support::FileNameList::const_iterator ei = bibfilesCache.begin();
+       support::FileNameList::const_iterator en = bibfilesCache.end();
+       for (; ei != en; ++ ei) {
+               time_t lastw = ei->lastModified();
+               time_t prevw = d->bibfile_status_[*ei];
+               if (lastw != prevw) {
+                       d->bibinfo_cache_valid_ = false;
+                       d->bibfile_status_[*ei] = lastw;
                }
        }
 
-       if (!d->bibinfoCacheValid_) {
+       if (!d->bibinfo_cache_valid_) {
                d->bibinfo_.clear();
                for (InsetIterator it = inset_iterator_begin(inset()); it; ++it)
                        it->fillWithBibKeys(d->bibinfo_, it);
-               d->bibinfoCacheValid_ = true;
-       }
-       return d->bibinfo_;
+               d->bibinfo_cache_valid_ = true;
+       }       
 }
 
 
@@ -1632,6 +1750,21 @@ void Buffer::markDepClean(string const & name)
 }
 
 
+bool Buffer::isExportableFormat(string const & format) const
+{
+               typedef vector<Format const *> Formats;
+               Formats formats;
+               formats = exportableFormats(true);
+               Formats::const_iterator fit = formats.begin();
+               Formats::const_iterator end = formats.end();
+               for (; fit != end ; ++fit) {
+                       if ((*fit)->name() == format)
+                               return true;
+               }
+               return false;
+}
+
+
 bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 {
        if (isInternal()) {
@@ -1667,27 +1800,6 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                        break;
                }
 
-               case LFUN_MASTER_BUFFER_UPDATE:
-               case LFUN_MASTER_BUFFER_VIEW: 
-                       enable = parent() != 0;
-                       break;
-               case LFUN_BUFFER_UPDATE:
-               case LFUN_BUFFER_VIEW: {
-                       string format = to_utf8(cmd.argument());
-                       if (cmd.argument().empty())
-                               format = getDefaultOutputFormat();
-                       typedef vector<Format const *> Formats;
-                       Formats formats;
-                       formats = exportableFormats(true);
-                       Formats::const_iterator fit = formats.begin();
-                       Formats::const_iterator end = formats.end();
-                       enable = false;
-                       for (; fit != end ; ++fit) {
-                               if ((*fit)->name() == format)
-                                       enable = true;
-                       }
-                       break;
-               }
                case LFUN_BUFFER_CHKTEX:
                        enable = isLatex() && !lyxrc.chktex_command.empty();
                        break;
@@ -1753,12 +1865,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
 
        case LFUN_BUFFER_EXPORT: {
-               if (argument == "custom") {
-                       lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
-                       break;
-               }
-               doExport(argument, false);
-               bool success = doExport(argument, false);
+               bool success = doExport(argument, false, false);
                dr.setError(success);
                if (!success)
                        dr.setMessage(bformat(_("Error exporting to format: %1$s."), 
@@ -1766,40 +1873,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
        }
 
-       case LFUN_BUFFER_UPDATE: {
-               string format = argument;
-               if (argument.empty())
-                       format = getDefaultOutputFormat();
-               doExport(format, true);
-               break;
-       }
-
-       case LFUN_BUFFER_VIEW: {
-               string format = argument;
-               if (argument.empty())
-                       format = getDefaultOutputFormat();
-               preview(format);
-               break;
-       }
-
-       case LFUN_MASTER_BUFFER_UPDATE: {
-               string format = argument;
-               if (argument.empty())
-                       format = masterBuffer()->getDefaultOutputFormat();
-               masterBuffer()->doExport(format, true);
-               break;
-       }
-
-       case LFUN_MASTER_BUFFER_VIEW: {
-               string format = argument;
-               if (argument.empty())
-                       format = masterBuffer()->getDefaultOutputFormat();
-               masterBuffer()->preview(format);
-               break;
-       }
-
        case LFUN_BUILD_PROGRAM:
-               doExport("program", true);
+               doExport("program", true, false);
                break;
 
        case LFUN_BUFFER_CHKTEX:
@@ -1831,7 +1906,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                break;
 
                } else {
-                       doExport(format_name, true, filename);
+                       doExport(format_name, true, false, filename);
                }
 
                // Substitute $$FName for filename
@@ -1965,7 +2040,10 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                        break;
                }
 
-               if (!doExport("dvi", true)) {
+               bool const update_unincluded =
+                               params().maintain_unincluded_children
+                               && !params().getIncludedChildren().empty();
+               if (!doExport("dvi", true, update_unincluded)) {
                        showPrintError(absFileName());
                        dr.setMessage(_("Error exporting to DVI."));
                        break;
@@ -2096,6 +2174,27 @@ bool Buffer::isMultiLingual() const
 }
 
 
+std::set<Language const *> Buffer::getLanguages() const
+{
+       std::set<Language const *> languages;
+       getLanguages(languages);
+       return languages;
+}
+
+
+void Buffer::getLanguages(std::set<Language const *> & languages) const
+{
+       ParConstIterator end = par_iterator_end();
+       for (ParConstIterator it = par_iterator_begin(); it != end; ++it)
+               it->getLanguages(languages);
+       // also children
+       std::vector<Buffer *> clist = getChildren();
+       for (vector<Buffer *>::const_iterator cit = clist.begin();
+            cit != clist.end(); ++cit)
+               (*cit)->getLanguages(languages);
+}
+
+
 DocIterator Buffer::getParFromID(int const id) const
 {
        Buffer * buf = const_cast<Buffer *>(this);
@@ -2161,12 +2260,6 @@ bool Buffer::isClean() const
 }
 
 
-bool Buffer::isBakClean() const
-{
-       return d->bak_clean;
-}
-
-
 bool Buffer::isExternallyModified(CheckMethod method) const
 {
        LASSERT(d->filename.exists(), /**/);
@@ -2202,12 +2295,6 @@ void Buffer::markClean() const
 }
 
 
-void Buffer::markBakClean() const
-{
-       d->bak_clean = true;
-}
-
-
 void Buffer::setUnnamed(bool flag)
 {
        d->unnamed = flag;
@@ -2285,15 +2372,15 @@ Buffer const * Buffer::parent() const
 }
 
 
-void Buffer::collectRelatives(BufferSet & bufs) const
+void Buffer::Impl::collectRelatives(BufferSet & bufs) const
 {
-       bufs.insert(this);
+       bufs.insert(owner_);
        if (parent())
-               parent()->collectRelatives(bufs);
+               parent()->d->collectRelatives(bufs);
 
        // loop over children
-       Impl::BufferPositionMap::iterator it = d->children_positions.begin();
-       Impl::BufferPositionMap::iterator end = d->children_positions.end();
+       BufferPositionMap::const_iterator it = children_positions.begin();
+       BufferPositionMap::const_iterator end = children_positions.end();
        for (; it != end; ++it)
                bufs.insert(const_cast<Buffer *>(it->first));
 }
@@ -2302,7 +2389,7 @@ void Buffer::collectRelatives(BufferSet & bufs) const
 std::vector<Buffer const *> Buffer::allRelatives() const
 {
        BufferSet bufs;
-       collectRelatives(bufs);
+       d->collectRelatives(bufs);
        BufferSet::iterator it = bufs.begin();
        std::vector<Buffer const *> ret;
        for (; it != bufs.end(); ++it)
@@ -2337,32 +2424,40 @@ DocIterator Buffer::firstChildPosition(Buffer const * child)
 }
 
 
-std::vector<Buffer *> Buffer::getChildren() const
+void Buffer::getChildren(std::vector<Buffer *> & clist, bool grand_children) const
 {
-       std::vector<Buffer *> clist;
        // loop over children
        Impl::BufferPositionMap::iterator it = d->children_positions.begin();
        Impl::BufferPositionMap::iterator end = d->children_positions.end();
        for (; it != end; ++it) {
                Buffer * child = const_cast<Buffer *>(it->first);
                clist.push_back(child);
-               // there might be grandchildren
-               std::vector<Buffer *> glist = child->getChildren();
-               for (vector<Buffer *>::const_iterator git = glist.begin();
-                    git != glist.end(); ++git)
-                       clist.push_back(*git);
+               if (grand_children) {
+                       // there might be grandchildren
+                       std::vector<Buffer *> glist = child->getChildren();
+                       for (vector<Buffer *>::const_iterator git = glist.begin();
+                                git != glist.end(); ++git)
+                               clist.push_back(*git);
+               }
        }
-       return clist;
+}
+
+
+std::vector<Buffer *> Buffer::getChildren(bool grand_children) const
+{
+       std::vector<Buffer *> v;
+       getChildren(v, grand_children);
+       return v;
 }
 
 
 template<typename M>
-typename M::iterator greatest_below(M & m, typename M::key_type const & x)
+typename M::const_iterator greatest_below(M & m, typename M::key_type const & x)
 {
        if (m.empty())
                return m.end();
 
-       typename M::iterator it = m.lower_bound(x);
+       typename M::const_iterator it = m.lower_bound(x);
        if (it == m.begin())
                return m.end();
 
@@ -2371,7 +2466,7 @@ typename M::iterator greatest_below(M & m, typename M::key_type const & x)
 }
 
 
-MacroData const * Buffer::getBufferMacro(docstring const & name,
+MacroData const * Buffer::Impl::getBufferMacro(docstring const & name,
                                         DocIterator const & pos) const
 {
        LYXERR(Debug::MACROS, "Searching for " << to_ascii(name) << " at " << pos);
@@ -2381,15 +2476,14 @@ MacroData const * Buffer::getBufferMacro(docstring const & name,
                return 0;
 
        // we haven't found anything yet
-       DocIterator bestPos = par_iterator_begin();
+       DocIterator bestPos = owner_->par_iterator_begin();
        MacroData const * bestData = 0;
 
        // find macro definitions for name
-       Impl::NamePositionScopeMacroMap::iterator nameIt
-               = d->macros.find(name);
-       if (nameIt != d->macros.end()) {
+       NamePositionScopeMacroMap::const_iterator nameIt = macros.find(name);
+       if (nameIt != macros.end()) {
                // find last definition in front of pos or at pos itself
-               Impl::PositionScopeMacroMap::const_iterator it
+               PositionScopeMacroMap::const_iterator it
                        = greatest_below(nameIt->second, pos);
                if (it != nameIt->second.end()) {
                        while (true) {
@@ -2412,9 +2506,9 @@ MacroData const * Buffer::getBufferMacro(docstring const & name,
        }
 
        // find macros in included files
-       Impl::PositionScopeBufferMap::const_iterator it
-               = greatest_below(d->position_to_children, pos);
-       if (it == d->position_to_children.end())
+       PositionScopeBufferMap::const_iterator it
+               = greatest_below(position_to_children, pos);
+       if (it == position_to_children.end())
                // no children before
                return bestData;
 
@@ -2426,10 +2520,10 @@ MacroData const * Buffer::getBufferMacro(docstring const & name,
                // scope ends behind pos?
                if (pos < it->second.first) {
                        // look for macro in external file
-                       d->macro_lock = true;
+                       macro_lock = true;
                        MacroData const * data
-                       = it->second.second->getMacro(name, false);
-                       d->macro_lock = false;
+                               = it->second.second->getMacro(name, false);
+                       macro_lock = false;
                        if (data) {
                                bestPos = it->first;
                                bestData = data;
@@ -2438,7 +2532,7 @@ MacroData const * Buffer::getBufferMacro(docstring const & name,
                }
 
                // try previous file if there is one
-               if (it == d->position_to_children.begin())
+               if (it == position_to_children.begin())
                        break;
                --it;
        }
@@ -2455,7 +2549,7 @@ MacroData const * Buffer::getMacro(docstring const & name,
                return 0;
 
        // query buffer macros
-       MacroData const * data = getBufferMacro(name, pos);
+       MacroData const * data = d->getBufferMacro(name, pos);
        if (data != 0)
                return data;
 
@@ -2503,9 +2597,9 @@ MacroData const * Buffer::getMacro(docstring const & name,
 }
 
 
-void Buffer::updateMacros(DocIterator & it, DocIterator & scope) const
+void Buffer::Impl::updateMacros(DocIterator & it, DocIterator & scope)
 {
-       pit_type lastpit = it.lastpit();
+       pit_type const lastpit = it.lastpit();
 
        // look for macros in each paragraph
        while (it.pit() <= lastpit) {
@@ -2540,20 +2634,20 @@ void Buffer::updateMacros(DocIterator & it, DocIterator & scope) const
                                // get buffer of external file
                                InsetInclude const & inset =
                                        static_cast<InsetInclude const &>(*iit->inset);
-                               d->macro_lock = true;
+                               macro_lock = true;
                                Buffer * child = inset.getChildBuffer();
-                               d->macro_lock = false;
+                               macro_lock = false;
                                if (!child)
                                        continue;
 
                                // register its position, but only when it is
                                // included first in the buffer
-                               if (d->children_positions.find(child) ==
-                                       d->children_positions.end())
-                                               d->children_positions[child] = it;
+                               if (children_positions.find(child) ==
+                                       children_positions.end())
+                                               children_positions[child] = it;
 
                                // register child with its scope
-                               d->position_to_children[it] = Impl::ScopeBuffer(scope, child);
+                               position_to_children[it] = Impl::ScopeBuffer(scope, child);
                                continue;
                        }
 
@@ -2563,7 +2657,7 @@ void Buffer::updateMacros(DocIterator & it, DocIterator & scope) const
                        // get macro data
                        MathMacroTemplate & macroTemplate =
                                static_cast<MathMacroTemplate &>(*iit->inset);
-                       MacroContext mc(*this, it);
+                       MacroContext mc(owner_, it);
                        macroTemplate.updateToContext(mc);
 
                        // valid?
@@ -2575,8 +2669,10 @@ void Buffer::updateMacros(DocIterator & it, DocIterator & scope) const
                                continue;
 
                        // register macro
-                       d->macros[macroTemplate.name()][it] =
-                               Impl::ScopeMacro(scope, MacroData(*this, it));
+                       // FIXME (Abdel), I don't understandt why we pass 'it' here
+                       // instead of 'macroTemplate' defined above... is this correct?
+                       macros[macroTemplate.name()][it] =
+                               Impl::ScopeMacro(scope, MacroData(const_cast<Buffer *>(owner_), it));
                }
 
                // next paragraph
@@ -2605,7 +2701,7 @@ void Buffer::updateMacros() const
        DocIterator it = par_iterator_begin();
        DocIterator outerScope = it;
        outerScope.pit() = outerScope.lastpit() + 2;
-       updateMacros(it, outerScope);
+       d->updateMacros(it, outerScope);
 }
 
 
@@ -2643,20 +2739,17 @@ void Buffer::updateMacroInstances() const
        LYXERR(Debug::MACROS, "updateMacroInstances for "
                << d->filename.onlyFileName());
        DocIterator it = doc_iterator_begin(this);
-       DocIterator end = doc_iterator_end(this);
-       for (; it != end; it.forwardPos()) {
-               // look for MathData cells in InsetMathNest insets
-               Inset * inset = it.nextInset();
-               if (!inset)
-                       continue;
-
-               InsetMath * minset = inset->asInsetMath();
+       it.forwardInset();
+       DocIterator const end = doc_iterator_end(this);
+       for (; it != end; it.forwardInset()) {
+               // look for MathData cells in InsetMathNest insets
+               InsetMath * minset = it.nextInset()->asInsetMath();
                if (!minset)
                        continue;
 
                // update macro in all cells of the InsetMathNest
                DocIterator::idx_type n = minset->nargs();
-               MacroContext mc = MacroContext(*this, it);
+               MacroContext mc = MacroContext(this, it);
                for (DocIterator::idx_type i = 0; i < n; ++i) {
                        MathData & data = minset->cell(i);
                        data.updateMacros(0, mc);
@@ -2772,6 +2865,7 @@ void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to,
        // 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();
@@ -2858,43 +2952,36 @@ ErrorList & Buffer::errorList(string const & type) const
 void Buffer::updateTocItem(std::string const & type,
        DocIterator const & dit) const
 {
-       if (gui_)
-               gui_->updateTocItem(type, dit);
+       if (d->gui_)
+               d->gui_->updateTocItem(type, dit);
 }
 
 
 void Buffer::structureChanged() const
 {
-       if (gui_)
-               gui_->structureChanged();
+       if (d->gui_)
+               d->gui_->structureChanged();
 }
 
 
 void Buffer::errors(string const & err, bool from_master) const
 {
-       if (gui_)
-               gui_->errors(err, from_master);
+       if (d->gui_)
+               d->gui_->errors(err, from_master);
 }
 
 
 void Buffer::message(docstring const & msg) const
 {
-       if (gui_)
-               gui_->message(msg);
+       if (d->gui_)
+               d->gui_->message(msg);
 }
 
 
 void Buffer::setBusy(bool on) const
 {
-       if (gui_)
-               gui_->setBusy(on);
-}
-
-
-void Buffer::setReadOnly(bool on) const
-{
-       if (d->wa_)
-               d->wa_->setReadOnly(on);
+       if (d->gui_)
+               d->gui_->setBusy(on);
 }
 
 
@@ -2907,20 +2994,20 @@ void Buffer::updateTitles() const
 
 void Buffer::resetAutosaveTimers() const
 {
-       if (gui_)
-               gui_->resetAutosaveTimers();
+       if (d->gui_)
+               d->gui_->resetAutosaveTimers();
 }
 
 
 bool Buffer::hasGuiDelegate() const
 {
-       return gui_;
+       return d->gui_;
 }
 
 
 void Buffer::setGuiDelegate(frontend::GuiBufferDelegate * gui)
 {
-       gui_ = gui;
+       d->gui_ = gui;
 }
 
 
@@ -2955,6 +3042,15 @@ private:
 
 int AutoSaveBuffer::generateChild()
 {
+#if defined(__APPLE__)
+       /* FIXME fork() is not usable for autosave on Mac OS X 10.6 (snow leopard) 
+        *   We should use something else like threads.
+        *
+        * Since I do not know how to determine at run time what is the OS X
+        * version, I just disable forking altogether for now (JMarc)
+        */
+       pid_t const pid = -1;
+#else
        // tmp_ret will be located (usually) in /tmp
        // will that be a problem?
        // Note that this calls ForkedCalls::fork(), so it's
@@ -2964,6 +3060,7 @@ int AutoSaveBuffer::generateChild()
        // you should set pid to -1, and comment out the fork.
        if (pid != 0 && pid != -1)
                return pid;
+#endif
 
        // pid = -1 signifies that lyx was unable
        // to fork. But we will do the save
@@ -3033,7 +3130,7 @@ void Buffer::moveAutosaveFile(support::FileName const & oldauto) const
 // Perfect target for a thread...
 void Buffer::autoSave() const
 {
-       if (isBakClean() || isReadonly()) {
+       if (d->bak_clean || isReadonly()) {
                // We don't save now, but we'll try again later
                resetAutosaveTimers();
                return;
@@ -3044,7 +3141,8 @@ void Buffer::autoSave() const
        AutoSaveBuffer autosave(*this, getAutosaveFilename());
        autosave.start();
 
-       markBakClean();
+       d->bak_clean = true;
+
        resetAutosaveTimers();
 }
 
@@ -3084,12 +3182,13 @@ string Buffer::getDefaultOutputFormat() const
 
 
 bool Buffer::doExport(string const & format, bool put_in_tempdir,
-       string & result_file) const
+       bool includeall, string & result_file) const
 {
        string backend_format;
        OutputParams runparams(&params().encoding());
        runparams.flavor = OutputParams::LATEX;
        runparams.linelen = lyxrc.plaintext_linelen;
+       runparams.includeall = includeall;
        vector<string> backs = backends();
        if (find(backs.begin(), backs.end(), format) == backs.end()) {
                // Get shortest path to format
@@ -3102,14 +3201,18 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                                path = p;
                        }
                }
-               if (!path.empty())
-                       runparams.flavor = theConverters().getFlavor(path);
-               else {
-                       Alert::error(_("Couldn't export file"),
-                               bformat(_("No information for exporting the format %1$s."),
-                                  formats.prettyName(format)));
+               if (path.empty()) {
+                       if (!put_in_tempdir) {
+                               // Only show this alert if this is an export to a non-temporary
+                               // file (not for previewing).
+                               Alert::error(_("Couldn't export file"), bformat(
+                                       _("No information for exporting the format %1$s."),
+                                       formats.prettyName(format)));
+                       }
                        return false;
                }
+               runparams.flavor = theConverters().getFlavor(path);
+
        } else {
                backend_format = format;
                // FIXME: Don't hardcode format names here, but use a flag
@@ -3126,8 +3229,10 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        updateMacroInstances();
 
        // Plain text backend
-       if (backend_format == "text")
+       if (backend_format == "text") {
+               runparams.flavor = OutputParams::TEXT;
                writePlaintextFile(*this, FileName(filename), runparams);
+       }
        // HTML backend
        else if (backend_format == "xhtml") {
                runparams.flavor = OutputParams::HTML;
@@ -3175,25 +3280,36 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        if (!success)
                return false;
 
+       if (d->cloned_buffer_) {
+               // Enable reverse dvi or pdf to work by copying back the texrow
+               // object to the cloned buffer.
+               // FIXME: There is a possibility of concurrent access to texrow
+               // here from the main GUI thread that should be securized.
+               d->cloned_buffer_->d->texrow = d->texrow;
+       }
+
        if (put_in_tempdir) {
                result_file = tmp_result_file.absFilename();
                return true;
        }
 
-       result_file = changeExtension(exportFileName().absFilename(), ext);
+       result_file = changeExtension(d->exportFileName().absFilename(), ext);
        // We need to copy referenced files (e. g. included graphics
        // if format == "dvi") to the result dir.
        vector<ExportedFile> const files =
                runparams.exportdata->externalFiles(format);
        string const dest = onlyPath(result_file);
        CopyStatus status = SUCCESS;
-       for (vector<ExportedFile>::const_iterator it = files.begin();
-               it != files.end() && status != CANCEL; ++it) {
+       
+       vector<ExportedFile>::const_iterator it = files.begin();
+       vector<ExportedFile>::const_iterator const en = files.end();
+       for (; it != en && status != CANCEL; ++it) {
                string const fmt = formats.getFormatFromFile(it->sourceName);
                status = copyFile(fmt, it->sourceName,
                        makeAbsPath(it->exportName, dest),
                        it->exportName, status == FORCE);
        }
+
        if (status == CANCEL) {
                message(_("Document export cancelled."));
        } else if (tmp_result_file.exists()) {
@@ -3215,17 +3331,26 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
 }
 
 
-bool Buffer::doExport(string const & format, bool put_in_tempdir) const
+bool Buffer::doExport(string const & format, bool put_in_tempdir,
+                     bool includeall) const
 {
        string result_file;
-       return doExport(format, put_in_tempdir, result_file);
+       // (1) export with all included children (omit \includeonly)
+       if (includeall && !doExport(format, put_in_tempdir, true, result_file))
+               return false;
+       // (2) export with included children only
+       return doExport(format, put_in_tempdir, false, result_file);
 }
 
 
-bool Buffer::preview(string const & format) const
+bool Buffer::preview(string const & format, bool includeall) const
 {
        string result_file;
-       if (!doExport(format, true, result_file))
+       // (1) export with all included children (omit \includeonly)
+       if (includeall && !doExport(format, true, true))
+               return false;
+       // (2) export with included children only
+       if (!doExport(format, true, false, result_file))
                return false;
        return formats.view(*this, FileName(result_file), format);
 }
@@ -3244,7 +3369,7 @@ bool Buffer::isExportable(string const & format) const
 
 vector<Format const *> Buffer::exportableFormats(bool only_viewable) const
 {
-       vector<string> backs = backends();
+       vector<string> const backs = backends();
        vector<Format const *> result =
                theConverters().getReachable(backs[0], only_viewable, true);
        for (vector<string>::const_iterator it = backs.begin() + 1;
@@ -3260,14 +3385,12 @@ vector<Format const *> Buffer::exportableFormats(bool only_viewable) const
 vector<string> Buffer::backends() const
 {
        vector<string> v;
-       if (params().baseClass()->isTeXClassAvailable()) {
-               v.push_back(bufferFormat());
-               // FIXME: Don't hardcode format names here, but use a flag
-               if (v.back() == "latex")
-                       v.push_back("pdflatex");
-       }
-       v.push_back("text");
+       v.push_back(bufferFormat());
+       // FIXME: Don't hardcode format names here, but use a flag
+       if (v.back() == "latex")
+               v.push_back("pdflatex");
        v.push_back("xhtml");
+       v.push_back("text");
        v.push_back("lyx");
        return v;
 }
@@ -3361,31 +3484,19 @@ bool Buffer::readFileHelper(FileName const & s)
 
 bool Buffer::loadLyXFile(FileName const & s)
 {
-       if (s.isReadableFile()) {
+       // If the file is not readable, we try to
+       // retrieve the file from version control.
+       if (!s.isReadableFile()
+                 && !LyXVC::file_not_found_hook(s))
+               return false;
+       
+       if (s.isReadableFile()){
+               // InsetInfo needs to know if file is under VCS
+               lyxvc().file_found_hook(s);
                if (readFileHelper(s)) {
-                       lyxvc().file_found_hook(s);
-                       if (!s.isWritable())
-                               setReadonly(true);
+                       setReadonly(!s.isWritable());
                        return true;
                }
-       } else {
-               docstring const file = makeDisplayPath(s.absFilename(), 20);
-               // Here we probably should run
-               if (LyXVC::file_not_found_hook(s)) {
-                       docstring const text =
-                               bformat(_("Do you want to retrieve the document"
-                                                      " %1$s from version control?"), file);
-                       int const ret = Alert::prompt(_("Retrieve from version control?"),
-                               text, 0, 1, _("&Retrieve"), _("&Cancel"));
-
-                       if (ret == 0) {
-                               // How can we know _how_ to do the checkout?
-                               // With the current VC support it has to be,
-                               // a RCS file since CVS do not have special ,v files.
-                               RCS::retrieve(s);
-                               return loadLyXFile(s);
-                       }
-               }
        }
        return false;
 }
@@ -3421,11 +3532,15 @@ void Buffer::setBuffersForInsets() const
 }
 
 
-void Buffer::updateLabels(UpdateScope scope) const
+void Buffer::updateLabels(UpdateScope scope, UpdateType utype) const
 {
        // Use the master text class also for child documents
        Buffer const * const master = masterBuffer();
        DocumentClass const & textclass = master->params().documentClass();
+       
+       // do this only if we are the top-level Buffer
+       if (scope != UpdateMaster || master == this)
+               checkBibInfoCache();
 
        // 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.
@@ -3435,10 +3550,10 @@ void Buffer::updateLabels(UpdateScope scope) const
                // If this is a child document start with the master
                if (master != this) {
                        bufToUpdate.insert(this);
-                       master->updateLabels();
+                       master->updateLabels(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->gui_)
+                       if (!master->d->gui_)
                                structureChanged();
 
                        // was buf referenced from the master (i.e. not in bufToUpdate anymore)?
@@ -3463,7 +3578,7 @@ void Buffer::updateLabels(UpdateScope scope) const
 
        // do the real work
        ParIterator parit = cbuf.par_iterator_begin();
-       updateLabels(parit);
+       updateLabels(parit, utype);
 
        if (master != this)
                // TocBackend update will be done later.
@@ -3545,9 +3660,9 @@ static bool needEnumCounterReset(ParIterator const & it)
 
 
 // set the label of a paragraph. This includes the counters.
-static void setLabel(Buffer const & buf, ParIterator & it)
+void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const
 {
-       BufferParams const & bp = buf.masterBuffer()->params();
+       BufferParams const & bp = owner_->masterBuffer()->params();
        DocumentClass const & textclass = bp.documentClass();
        Paragraph & par = it.paragraph();
        Layout const & layout = par.layout();
@@ -3555,7 +3670,7 @@ static void setLabel(Buffer const & buf, ParIterator & it)
 
        if (par.params().startOfAppendix()) {
                // FIXME: only the counter corresponding to toplevel
-               // sectionning should be reset
+               // sectioning should be reset
                counters.reset();
                counters.appendix(true);
        }
@@ -3577,7 +3692,7 @@ static void setLabel(Buffer const & buf, ParIterator & it)
                if (layout.toclevel <= bp.secnumdepth
                    && (layout.latextype != LATEX_ENVIRONMENT
                        || it.text()->isFirstInSequence(it.pit()))) {
-                       counters.step(layout.counter);
+                       counters.step(layout.counter, utype);
                        par.params().labelString(
                                par.expandLabel(layout, bp));
                } else
@@ -3631,7 +3746,7 @@ static void setLabel(Buffer const & buf, ParIterator & it)
                // Maybe we have to reset the enumeration counter.
                if (needEnumCounterReset(it))
                        counters.reset(enumcounter);
-               counters.step(enumcounter);
+               counters.step(enumcounter, utype);
 
                string const & lang = par.getParLanguage(bp)->code();
                par.params().labelString(counters.theCounter(enumcounter, lang));
@@ -3643,12 +3758,12 @@ static void setLabel(Buffer const & buf, ParIterator & it)
                string const & type = counters.current_float();
                docstring full_label;
                if (type.empty())
-                       full_label = buf.B_("Senseless!!! ");
+                       full_label = owner_->B_("Senseless!!! ");
                else {
-                       docstring name = buf.B_(textclass.floats().getType(type).name());
+                       docstring name = owner_->B_(textclass.floats().getType(type).name());
                        if (counters.hasCounter(from_utf8(type))) {
                                string const & lang = par.getParLanguage(bp)->code();
-                               counters.step(from_utf8(type));
+                               counters.step(from_utf8(type), utype);
                                full_label = bformat(from_ascii("%1$s %2$s:"), 
                                                     name, 
                                                     counters.theCounter(from_utf8(type), lang));
@@ -3674,7 +3789,7 @@ static void setLabel(Buffer const & buf, ParIterator & it)
 }
 
 
-void Buffer::updateLabels(ParIterator & parit) const
+void Buffer::updateLabels(ParIterator & parit, UpdateType utype) const
 {
        LASSERT(parit.pit() == 0, /**/);
 
@@ -3691,15 +3806,23 @@ void Buffer::updateLabels(ParIterator & parit) const
                parit->params().depth(min(parit->params().depth(), maxdepth));
                maxdepth = parit->getMaxDepthAfter();
 
+               if (utype == OutputUpdate) {
+                       // track the active counters
+                       // we have to do this for the master buffer, since the local
+                       // buffer isn't tracking anything.
+                       masterBuffer()->params().documentClass().counters().
+                                       setActiveLayout(parit->layout());
+               }
+               
                // set the counter for this paragraph
-               setLabel(*this, parit);
+               d->setLabel(parit, utype);
 
-               // Now the insets
+               // now the insets
                InsetList::const_iterator iit = parit->insetList().begin();
                InsetList::const_iterator end = parit->insetList().end();
                for (; iit != end; ++iit) {
                        parit.pos() = iit->pos;
-                       iit->inset->updateLabels(parit);
+                       iit->inset->updateLabels(parit, utype);
                }
        }
 }
@@ -3716,17 +3839,51 @@ int Buffer::spellCheck(DocIterator & from, DocIterator & to,
        DocIterator const end = doc_iterator_end(this);
        for (; from != end; from.forwardPos()) {
                // We are only interested in text so remove the math CursorSlice.
-               while (from.inMathed())
-                       from.forwardInset();
+               while (from.inMathed()) {
+                       from.pop_back();
+                       from.pos()++;
+               }
+               // If from is at the end of the document (which is possible
+               // when leaving the mathed) LyX will crash later.
+               if (from == end)
+                       break;
                to = from;
                if (from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions)) {
                        word_lang = wl;
                        break;
                }
-               from = to;
-               ++progress;
+
+               // Do not increase progress when from == to, otherwise the word
+               // count will be wrong.
+               if (from != to) {
+                       from = to;
+                       ++progress;
+               }
        }
        return progress;
 }
 
+
+bool Buffer::reload()
+{
+       setBusy(true);
+       // e.g., read-only status could have changed due to version control
+       d->filename.refresh();
+       docstring const disp_fn = makeDisplayPath(d->filename.absFilename());
+
+       bool const success = loadLyXFile(d->filename);
+       if (success) {
+               updateLabels();
+               changed(true);
+               markClean();
+               message(bformat(_("Document %1$s reloaded."), disp_fn));
+       } else {
+               message(bformat(_("Could not reload document %1$s."), disp_fn));
+       }       
+       setBusy(false);
+       errors("Parse");
+       return success;
+}
+
+
 } // namespace lyx