]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
* Add ability to rename branches (bug 4128).
[lyx.git] / src / Buffer.cpp
index b7b27c4073d6e5316dbe56d0a0e8126d454524d3..53ade6faf3683655839783effc631bc4f9a0f8f3 100644 (file)
@@ -69,6 +69,7 @@
 
 #include "insets/InsetBibitem.h"
 #include "insets/InsetBibtex.h"
+#include "insets/InsetBranch.h"
 #include "insets/InsetInclude.h"
 #include "insets/InsetText.h"
 
@@ -1621,6 +1622,8 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                        break;
                }
 
+               case LFUN_BRANCH_ADD:
+               case LFUN_BRANCHES_RENAME:
                case LFUN_BUFFER_PRINT:
                        // if no Buffer is present, then of course we won't be called!
                        flag.setEnabled(true);
@@ -1657,6 +1660,28 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
        }
 
+       case LFUN_BRANCH_ADD: {
+               BranchList & branchList = params().branchlist();
+               docstring const branchName = func.argument();
+               if (branchName.empty()) {
+                       dispatched = false;
+                       break;
+               }
+               Branch * branch = branchList.find(branchName);
+               if (branch) {
+                       LYXERR0("Branch " << branchName << " does already exist.");
+                       dr.setError(true);
+                       docstring const msg = 
+                               bformat(_("Branch \"%1$s\" does already exist."), branchName);
+                       dr.setMessage(msg);
+               } else {
+                       branchList.add(branchName);
+                       dr.setError(false);
+                       dr.update(Update::Force);
+               }
+               break;
+       }
+
        case LFUN_BRANCH_ACTIVATE:
        case LFUN_BRANCH_DEACTIVATE: {
                BranchList & branchList = params().branchlist();
@@ -1681,6 +1706,13 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
        }
 
+       case LFUN_BRANCHES_RENAME: {
+               docstring const oldname = from_utf8(func.getArg(0));
+               docstring const newname = from_utf8(func.getArg(1));
+               renameBranches(oldname, newname);
+               break;
+       }
+
        case LFUN_BUFFER_PRINT: {
                // we'll assume there's a problem until we succeed
                dr.setError(true); 
@@ -2328,6 +2360,107 @@ void Buffer::updateMacros() const
 }
 
 
+void Buffer::getUsedBranches(std::list<docstring> & result, bool const from_master) const
+{
+       // Iterate over buffer, starting with first paragraph
+       // The scope must be bigger than any lookup DocIterator
+       // later. For the global lookup, lastpit+1 is used, hence
+       // we use lastpit+2 here.
+       DocIterator it = par_iterator_begin();
+       DocIterator scope = it;
+       scope.pit() = scope.lastpit() + 2;
+       pit_type lastpit = it.lastpit();
+
+       while (it.pit() <= lastpit) {
+               Paragraph & par = it.paragraph();
+
+               // iterate over the insets of the current paragraph
+               InsetList const & insets = par.insetList();
+               InsetList::const_iterator iit = insets.begin();
+               InsetList::const_iterator end = insets.end();
+               for (; iit != end; ++iit) {
+                       it.pos() = iit->pos;
+
+                       if (iit->inset->lyxCode() == BRANCH_CODE) {
+                               // get buffer of external file
+                               InsetBranch const & br =
+                                       static_cast<InsetBranch const &>(*iit->inset);
+                               docstring const name = br.branch();
+                               if (!from_master && !params().branchlist().find(name))
+                                       result.push_back(name);
+                               else if (from_master && !masterBuffer()->params().branchlist().find(name))
+                                       result.push_back(name);
+                               continue;
+                       }
+
+                       // is it an external file?
+                       if (iit->inset->lyxCode() == INCLUDE_CODE) {
+                               // get buffer of external file
+                               InsetInclude const & inset =
+                                       static_cast<InsetInclude const &>(*iit->inset);
+                               Buffer * child = inset.getChildBuffer();
+                               if (!child)
+                                       continue;
+                               child->getUsedBranches(result, true);
+                       }
+               }
+               // next paragraph
+               it.pit()++;
+               it.pos() = 0;
+       }
+       // remove duplicates
+       result.unique();
+}
+
+
+void Buffer::renameBranches(docstring const & oldname, docstring const & newname)
+{
+       // Iterate over buffer, starting with first paragraph
+       // The scope must be bigger than any lookup DocIterator
+       // later. For the global lookup, lastpit+1 is used, hence
+       // we use lastpit+2 here.
+       DocIterator it = par_iterator_begin();
+       DocIterator scope = it;
+       scope.pit() = scope.lastpit() + 2;
+       pit_type lastpit = it.lastpit();
+
+       while (it.pit() <= lastpit) {
+               Paragraph & par = it.paragraph();
+
+               // iterate over the insets of the current paragraph
+               InsetList const & insets = par.insetList();
+               InsetList::const_iterator iit = insets.begin();
+               InsetList::const_iterator end = insets.end();
+               for (; iit != end; ++iit) {
+                       it.pos() = iit->pos;
+
+                       if (iit->inset->lyxCode() == BRANCH_CODE) {
+                               // get buffer of external file
+                               InsetBranch & br =
+                                       static_cast<InsetBranch &>(*iit->inset);
+                               if (br.branch() == oldname)
+                                       br.rename(newname);
+                               continue;
+                       }
+
+                       // is it an external file?
+                       if (iit->inset->lyxCode() == INCLUDE_CODE) {
+                               // get buffer of external file
+                               InsetInclude const & inset =
+                                       static_cast<InsetInclude const &>(*iit->inset);
+                               Buffer * child = inset.getChildBuffer();
+                               if (!child)
+                                       continue;
+                               child->renameBranches(oldname, newname);
+                       }
+               }
+               // next paragraph
+               it.pit()++;
+               it.pos() = 0;
+       }
+}
+
+
 void Buffer::updateMacroInstances() const
 {
        LYXERR(Debug::MACROS, "updateMacroInstances for "
@@ -2560,10 +2693,10 @@ void Buffer::structureChanged() const
 }
 
 
-void Buffer::errors(string const & err) const
+void Buffer::errors(string const & err, bool from_master) const
 {
        if (gui_)
-               gui_->errors(err);
+               gui_->errors(err, from_master);
 }
 
 
@@ -2853,8 +2986,14 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                tmp_result_file, FileName(absFileName()), backend_format, format,
                error_list);
        // Emit the signal to show the error list.
-       if (format != backend_format)
+       if (format != backend_format) {
                errors(error_type);
+               // also to the children, in case of master-buffer-view
+               std::vector<Buffer *> clist = getChildren();
+               for (vector<Buffer *>::const_iterator cit = clist.begin();
+                    cit != clist.end(); ++cit)
+                       (*cit)->errors(error_type, true);
+       }
        if (!success)
                return false;
 
@@ -3100,7 +3239,7 @@ void Buffer::updateLabels(UpdateScope scope) const
                        // 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_)
-                               structureChanged();     
+                               structureChanged();
 
                        // was buf referenced from the master (i.e. not in bufToUpdate anymore)?
                        if (bufToUpdate.find(this) == bufToUpdate.end())
@@ -3365,77 +3504,27 @@ void Buffer::updateLabels(ParIterator & parit) const
 }
 
 
-bool Buffer::nextWord(DocIterator & from, DocIterator & to,
-       docstring & word) const
-{
-       bool inword = false;
-       bool ignoreword = false;
-       string lang_code;
-       // Go backward a bit if needed in order to return the word currently
-       // pointed by 'from'.
-       while (from && from.pos() && isLetter(from))
-               from.backwardPos();
-       // OK, we start from here.
-       to = from;
-       while (to.depth()) {
-               if (isLetter(to)) {
-                       if (!inword) {
-                               inword = true;
-                               ignoreword = false;
-                               from = to;
-                               word.clear();
-                               lang_code = to.paragraph().getFontSettings(params(),
-                                       to.pos()).language()->code();
-                       }
-                       // Insets like optional hyphens and ligature
-                       // break are part of a word.
-                       if (!to.paragraph().isInset(to.pos())) {
-                               char_type const c = to.paragraph().getChar(to.pos());
-                               word += c;
-                               if (isDigit(c))
-                                       ignoreword = true;
-                       }
-               } else { // !isLetter(cur)
-                       if (inword && !word.empty() && !ignoreword)
-                               return true;
-                       inword = false;
-               }
-               to.forwardPos();
-       }
-       from = to;
-       word.clear();
-       return false;
-}
-
-
 int Buffer::spellCheck(DocIterator & from, DocIterator & to,
        WordLangTuple & word_lang, docstring_list & suggestions) const
 {
        int progress = 0;
-       SpellChecker::Result res = SpellChecker::OK;
-       SpellChecker * speller = theSpellChecker();
+       WordLangTuple wl;
        suggestions.clear();
-       docstring word;
-       while (nextWord(from, to, word)) {
-               ++progress;
-               string const lang_code = lyxrc.spellchecker_alt_lang.empty()
-                       ? from.paragraph().getFontSettings(params(), from.pos()).language()->code()
-                       : lyxrc.spellchecker_alt_lang;
-               WordLangTuple wl(word, lang_code);
-               res = speller->check(wl);
-               // ... just bail out if the spellchecker reports an error.
-               if (!speller->error().empty()) {
-                       throw ExceptionMessage(WarningException,
-                               _("The spellchecker has failed."), speller->error());
-               }
-               if (res != SpellChecker::OK && res != SpellChecker::IGNORED_WORD) {
+       word_lang = WordLangTuple();
+       // OK, we start from here.
+       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();
+               to = from;
+               if (from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions)) {
                        word_lang = wl;
                        break;
                }
                from = to;
+               ++progress;
        }
-       while (!(word = speller->nextMiss()).empty())
-               suggestions.push_back(word);
        return progress;
 }