]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
* ExternalSupport.cpp:
[lyx.git] / src / Buffer.cpp
index 005a4603321f04a2efbb059809ede8ab0c1847a1..a068ecfe3a9c9e502cac0801395b4aaf56f09a83 100644 (file)
@@ -72,6 +72,7 @@
 #include "insets/InsetInclude.h"
 #include "insets/InsetText.h"
 
+#include "mathed/InsetMathHull.h"
 #include "mathed/MacroTable.h"
 #include "mathed/MathMacroTemplate.h"
 #include "mathed/MathSupport.h"
@@ -126,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 = 387; // rgh: XHTML math options
+int const LYX_FORMAT = 400; // uwestoehr: support for \rule
 
 typedef map<string, bool> DepClean;
 typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
@@ -156,7 +157,7 @@ public:
                }
                delete inset;
        }
-
+       
        /// search for macro in local (buffer) table or in children
        MacroData const * getBufferMacro(docstring const & name,
                DocIterator const & pos) const;
@@ -254,7 +255,9 @@ public:
        /// A cache for bibliography info
        mutable BiblioInfo bibinfo_;
        /// whether the bibinfo cache is valid
-       bool bibinfo_cache_valid_;
+       mutable bool bibinfo_cache_valid_;
+       /// whether the bibfile cache is valid
+       mutable bool bibfile_cache_valid_;
        /// Cache of timestamps of .bib files
        map<FileName, time_t> bibfile_status_;
 
@@ -276,18 +279,27 @@ public:
                        parent_buffer = 0;
                return parent_buffer; 
        }
+       
        ///
        void setParent(Buffer const * pb) {
-               if (!cloned_buffer_ 
-                   && parent_buffer && pb && parent_buffer != pb)
+               if (parent_buffer == pb)
+                       // nothing to do
+                       return;
+               if (!cloned_buffer_ && parent_buffer && pb)
                        LYXERR0("Warning: a buffer should not have two parents!");
                parent_buffer = pb;
+               if (!cloned_buffer_ && parent_buffer) {
+                       parent_buffer->invalidateBibfileCache();
+                       parent_buffer->invalidateBibinfoCache();
+               }
        }
 
        /// If non zero, this buffer is a clone of existing buffer \p cloned_buffer_
        /// This one is useful for preview detached in a thread.
        Buffer const * cloned_buffer_;
-
+       /// are we in the process of exporting this buffer?
+       mutable bool doing_export;
+       
 private:
        /// So we can force access via the accessors.
        mutable Buffer const * parent_buffer;
@@ -320,7 +332,8 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
          read_only(readonly_), filename(file), file_fully_loaded(false),
          toc_backend(owner), macro_lock(false), timestamp_(0),
          checksum_(0), wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false),
-         cloned_buffer_(cloned_buffer), parent_buffer(0)
+               bibfile_cache_valid_(false), cloned_buffer_(cloned_buffer), 
+               doing_export(false), parent_buffer(0)
 {
        if (!cloned_buffer_) {
                temppath = createBufferTmpDir();
@@ -335,6 +348,7 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
        bibfiles_cache_ = cloned_buffer_->d->bibfiles_cache_;
        bibinfo_ = cloned_buffer_->d->bibinfo_;
        bibinfo_cache_valid_ = cloned_buffer_->d->bibinfo_cache_valid_;
+       bibfile_cache_valid_ = cloned_buffer_->d->bibfile_cache_valid_;
        bibfile_status_ = cloned_buffer_->d->bibfile_status_;
 }
 
@@ -403,7 +417,8 @@ Buffer::~Buffer()
        }
 
        // Remove any previewed LaTeX snippets associated with this buffer.
-       thePreviews().removeLoader(*this);
+       if (!isClone())
+               thePreviews().removeLoader(*this);
 
        delete d;
 }
@@ -673,6 +688,10 @@ int Buffer::readHeader(Lexer & lex)
        params().isfontcolor = false;
        params().notefontcolor = lyx::rgbFromHexName("#cccccc");
        params().boxbgcolor = lyx::rgbFromHexName("#ff0000");
+       params().html_latex_start.clear();
+       params().html_latex_end.clear();
+       params().html_math_img_scale = 1.0;
+       params().output_sync_macro.erase();
 
        for (int i = 0; i < 4; ++i) {
                params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i];
@@ -1006,6 +1025,7 @@ bool Buffer::save() const
                        backupName = FileName(addName(lyxrc.backupdir_path,
                                                      mangledName));
                }
+               // do not copy because of #6587
                if (fileName().moveTo(backupName)) {
                        madeBackup = true;
                } else {
@@ -1564,7 +1584,6 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
        LaTeXFeatures features(*this, params(), runparams);
        validate(features);
        updateBuffer(UpdateMaster, OutputUpdate);
-       checkBibInfoCache();
        d->bibinfo_.makeCitationLabels(*this);
        updateMacros();
        updateMacroInstances();
@@ -1656,7 +1675,7 @@ void Buffer::validate(LaTeXFeatures & features) const
        updateMacros();
 
        for_each(paragraphs().begin(), paragraphs().end(),
-                bind(&Paragraph::validate, _1, boost::ref(features)));
+                bind(&Paragraph::validate, _1, ref(features)));
 
        if (lyxerr.debugging(Debug::LATEX)) {
                features.showStruct();
@@ -1686,6 +1705,7 @@ void Buffer::getLabelList(vector<docstring> & list) const
 
 void Buffer::updateBibfilesCache(UpdateScope scope) const
 {
+       // FIXME This is probably unnecssary, given where we call this.
        // If this is a child document, use the parent's cache instead.
        Buffer const * const pbuf = d->parent();
        if (pbuf && scope != UpdateChildOnly) {
@@ -1705,35 +1725,54 @@ void Buffer::updateBibfilesCache(UpdateScope scope) const
                } else if (it->lyxCode() == INCLUDE_CODE) {
                        InsetInclude & inset =
                                static_cast<InsetInclude &>(*it);
-                       inset.updateBibfilesCache();
+                       Buffer const * const incbuf = inset.getChildBuffer();
+                       if (!incbuf)
+                               continue;
                        support::FileNameList const & bibfiles =
-                                       inset.getBibfilesCache();
-                       d->bibfiles_cache_.insert(d->bibfiles_cache_.end(),
-                               bibfiles.begin(),
-                               bibfiles.end());
+                                       incbuf->getBibfilesCache(UpdateChildOnly);
+                       if (!bibfiles.empty()) {
+                               d->bibfiles_cache_.insert(d->bibfiles_cache_.end(),
+                                       bibfiles.begin(),
+                                       bibfiles.end());
+                       }
                }
        }
-       // the bibinfo cache is now invalid
+       d->bibfile_cache_valid_ = true;
        d->bibinfo_cache_valid_ = false;
 }
 
 
-void Buffer::invalidateBibinfoCache()
+void Buffer::invalidateBibinfoCache() const
 {
        d->bibinfo_cache_valid_ = false;
+       // also invalidate the cache for the parent buffer
+       Buffer const * const pbuf = d->parent();
+       if (pbuf)
+               pbuf->invalidateBibinfoCache();
 }
 
 
-support::FileNameList const & Buffer::getBibfilesCache(UpdateScope scope) const
+void Buffer::invalidateBibfileCache() const
 {
-       // If this is a child document, use the parent's cache instead.
+       d->bibfile_cache_valid_ = false;
+       d->bibinfo_cache_valid_ = false;
+       // also invalidate the cache for the parent buffer
        Buffer const * const pbuf = d->parent();
-       if (pbuf && scope != UpdateChildOnly)
+       if (pbuf)
+               pbuf->invalidateBibfileCache();
+}
+
+
+support::FileNameList const & Buffer::getBibfilesCache(UpdateScope scope) const
+{
+       // FIXME This is probably unnecessary, given where we call this.
+       // If this is a child document, use the master's cache instead.
+       Buffer const * const pbuf = masterBuffer();
+       if (pbuf != this && scope != UpdateChildOnly)
                return pbuf->getBibfilesCache();
 
-       // We update the cache when first used instead of at loading time.
-       if (d->bibfiles_cache_.empty())
-               const_cast<Buffer *>(this)->updateBibfilesCache(scope);
+       if (!d->bibfile_cache_valid_)
+               this->updateBibfilesCache(scope);
 
        return d->bibfiles_cache_;
 }
@@ -1741,28 +1780,28 @@ support::FileNameList const & Buffer::getBibfilesCache(UpdateScope scope) const
 
 BiblioInfo const & Buffer::masterBibInfo() const
 {
-       // if this is a child document and the parent is already loaded
-       // use the parent's list instead  [ale990412]
        Buffer const * const tmp = masterBuffer();
-       LASSERT(tmp, /**/);
        if (tmp != this)
                return tmp->masterBibInfo();
-       return localBibInfo();
-}
-
-
-BiblioInfo const & Buffer::localBibInfo() const
-{
        return d->bibinfo_;
 }
 
 
 void Buffer::checkBibInfoCache() const 
 {
-       support::FileNameList const & bibfilesCache = getBibfilesCache();
+       // use the master's cache
+       Buffer const * const tmp = masterBuffer();
+       if (tmp != this) {
+               tmp->checkBibInfoCache();
+               return;
+       }
+
+       // this will also reload the cache if it is invalid 
+       support::FileNameList const & bibfiles_cache = getBibfilesCache();
+       
        // compare the cached timestamps with the actual ones.
-       support::FileNameList::const_iterator ei = bibfilesCache.begin();
-       support::FileNameList::const_iterator en = bibfilesCache.end();
+       support::FileNameList::const_iterator ei = bibfiles_cache.begin();
+       support::FileNameList::const_iterator en = bibfiles_cache.end();
        for (; ei != en; ++ ei) {
                time_t lastw = ei->lastModified();
                time_t prevw = d->bibfile_status_[*ei];
@@ -1771,13 +1810,20 @@ void Buffer::checkBibInfoCache() const
                        d->bibfile_status_[*ei] = lastw;
                }
        }
-
+       
+       // if not valid, then reload the info
        if (!d->bibinfo_cache_valid_) {
                d->bibinfo_.clear();
-               for (InsetIterator it = inset_iterator_begin(inset()); it; ++it)
-                       it->fillWithBibKeys(d->bibinfo_, it);
+               fillWithBibKeys(d->bibinfo_);
                d->bibinfo_cache_valid_ = true;
-       }       
+       }
+}
+
+
+void Buffer::fillWithBibKeys(BiblioInfo & keys) const
+{
+       for (InsetIterator it = inset_iterator_begin(inset()); it; ++it)
+               it->fillWithBibKeys(keys, it);
 }
 
 
@@ -1978,28 +2024,37 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
 
        case LFUN_BRANCH_ADD: {
-               docstring const branch_name = func.argument();
+               docstring branch_name = func.argument();
                if (branch_name.empty()) {
                        dispatched = false;
                        break;
                }
                BranchList & branch_list = params().branchlist();
-               Branch * branch = branch_list.find(branch_name);
-               if (branch) {
-                       LYXERR0("Branch " << branch_name << " already exists.");
-                       dr.setError(true);
-                       docstring const msg = 
-                               bformat(_("Branch \"%1$s\" already exists."), branch_name);
-                       dr.setMessage(msg);
-               } else {
-                       branch_list.add(branch_name);
-                       branch = branch_list.find(branch_name);
-                       string const x11hexname = X11hexname(branch->color());
-                       docstring const str = branch_name + ' ' + from_ascii(x11hexname);
-                       lyx::dispatch(FuncRequest(LFUN_SET_COLOR, str));        
-                       dr.setError(false);
-                       dr.update(Update::Force);
+               vector<docstring> const branches =
+                       getVectorFromString(branch_name, branch_list.separator());
+               docstring msg;
+               for (vector<docstring>::const_iterator it = branches.begin();
+                    it != branches.end(); ++it) {
+                       branch_name = *it;
+                       Branch * branch = branch_list.find(branch_name);
+                       if (branch) {
+                               LYXERR0("Branch " << branch_name << " already exists.");
+                               dr.setError(true);
+                               if (!msg.empty())
+                                       msg += ("\n");
+                               msg += bformat(_("Branch \"%1$s\" already exists."), branch_name);
+                       } else {
+                               branch_list.add(branch_name);
+                               branch = branch_list.find(branch_name);
+                               string const x11hexname = X11hexname(branch->color());
+                               docstring const str = branch_name + ' ' + from_ascii(x11hexname);
+                               lyx::dispatch(FuncRequest(LFUN_SET_COLOR, str));
+                               dr.setError(false);
+                               dr.update(Update::Force);
+                       }
                }
+               if (!msg.empty())
+                       dr.setMessage(msg);
                break;
        }
 
@@ -2023,6 +2078,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                        branch->setSelected(func.action() == LFUN_BRANCH_ACTIVATE);
                        dr.setError(false);
                        dr.update(Update::Force);
+                       dr.forceBufferUpdate();
                }
                break;
        }
@@ -2057,8 +2113,10 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                        }
                }
 
-               if (success)
+               if (success) {
                        dr.update(Update::Force);
+                       dr.forceBufferUpdate();
+               }
                break;
        }
 
@@ -2184,8 +2242,10 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                Language const * newL = languages.getLanguage(argument);
                if (!newL || oldL == newL)
                        break;
-               if (oldL->rightToLeft() == newL->rightToLeft() && !isMultiLingual())
+               if (oldL->rightToLeft() == newL->rightToLeft() && !isMultiLingual()) {
                        changeLanguage(oldL, newL);
+                       dr.forceBufferUpdate();
+               }
                break;
        }
 
@@ -2341,6 +2401,7 @@ void Buffer::markClean() const
        // if the .lyx file has been saved, we don't need an
        // autosave
        d->bak_clean = true;
+       d->undo_.markDirty();
 }
 
 
@@ -2698,6 +2759,14 @@ void Buffer::Impl::updateMacros(DocIterator & it, DocIterator & scope)
                                continue;
                        }
 
+                       if (doing_export && iit->inset->asInsetMath()) {
+                               InsetMath * im = static_cast<InsetMath *>(iit->inset);
+                               if (im->asHullInset()) {
+                                       InsetMathHull * hull = static_cast<InsetMathHull *>(im);
+                                       hull->recordLocation(it);
+                               }
+                       }
+
                        if (iit->inset->lyxCode() != MATHMACRO_CODE)
                                continue;
 
@@ -3229,10 +3298,41 @@ string Buffer::getDefaultOutputFormat() const
 }
 
 
+namespace {
+       // helper class, to guarantee this gets reset properly
+       class MarkAsExporting   {
+       public:
+               MarkAsExporting(Buffer const * buf) : buf_(buf) 
+               {
+                       LASSERT(buf_, /* */);
+                       buf_->setExportStatus(true);
+               }
+               ~MarkAsExporting() 
+               {
+                       buf_->setExportStatus(false);
+               }
+       private:
+               Buffer const * const buf_;
+       };
+}
+
+
+void Buffer::setExportStatus(bool e) const
+{
+       d->doing_export = e;    
+}
+
+
+bool Buffer::isExporting() const
+{
+       return d->doing_export;
+}
+
 
 bool Buffer::doExport(string const & format, bool put_in_tempdir,
        bool includeall, string & result_file) const
 {
+       MarkAsExporting exporting(this);
        string backend_format;
        OutputParams runparams(&params().encoding());
        runparams.flavor = OutputParams::LATEX;
@@ -3429,6 +3529,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
 
 bool Buffer::preview(string const & format, bool includeall) const
 {
+       MarkAsExporting exporting(this);
        string result_file;
        // (1) export with all included children (omit \includeonly)
        if (includeall && !doExport(format, true, true))
@@ -3623,7 +3724,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
        DocumentClass const & textclass = master->params().documentClass();
        
        // do this only if we are the top-level Buffer
-       if (scope != UpdateMaster || master == this)
+       if (master == this)
                checkBibInfoCache();
 
        // keep the buffers to be children in this set. If the call from the
@@ -3932,7 +4033,9 @@ int Buffer::spellCheck(DocIterator & from, DocIterator & to,
                if (from == end)
                        break;
                to = from;
-               if (from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions)) {
+               from.paragraph().spellCheck();
+               SpellChecker::Result res = from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions);
+               if (SpellChecker::misspelled(res)) {
                        word_lang = wl;
                        break;
                }
@@ -3961,6 +4064,7 @@ bool Buffer::reload()
        if (success) {
                updateBuffer();
                changed(true);
+               updateTitles();
                markClean();
                message(bformat(_("Document %1$s reloaded."), disp_fn));
        } else {