commit 07396ab2445720b21dc8195816eb1aee1f2ae3a7
Author: Juergen Spitzmueller <[email protected]>
Date:   Sat Mar 6 16:53:33 2021 +0100

    Meet per-document spelling dictionaries (fixes #86 [sic!])
    
    Now who can beat that? ;-)
---
 lib/RELEASE-NOTES                     |    3 +
 lib/lyx2lyx/lyx_2_4.py                |   15 +++-
 src/AppleSpellChecker.cpp             |   12 +++-
 src/AppleSpellChecker.h               |    3 +-
 src/AspellChecker.cpp                 |   10 ++-
 src/AspellChecker.h                   |    3 +-
 src/Buffer.cpp                        |    1 +
 src/BufferParams.cpp                  |   30 ++++++++
 src/BufferParams.h                    |    6 ++
 src/EnchantChecker.cpp                |   11 +++-
 src/EnchantChecker.h                  |    6 +-
 src/FuncCode.h                        |    2 +
 src/HunspellChecker.cpp               |   18 ++++-
 src/HunspellChecker.h                 |    3 +-
 src/LyXAction.cpp                     |   13 +++
 src/Paragraph.cpp                     |   11 ++-
 src/SpellChecker.h                    |    4 +-
 src/Text3.cpp                         |   43 +++++++++++
 src/frontends/qt/GuiSpellchecker.cpp  |   30 +++++++-
 src/frontends/qt/GuiSpellchecker.h    |    2 +
 src/frontends/qt/Menus.cpp            |    6 +-
 src/frontends/qt/ui/SpellcheckerUi.ui |  130 +++++++++++++++++++--------------
 src/version.h                         |    4 +-
 23 files changed, 287 insertions(+), 79 deletions(-)

diff --git a/lib/RELEASE-NOTES b/lib/RELEASE-NOTES
index 3496575..638d5a9 100644
--- a/lib/RELEASE-NOTES
+++ b/lib/RELEASE-NOTES
@@ -116,6 +116,9 @@
   cursor in the search cache that is used by word-find[-backward|-forward] if 
no argument
   is given to those.
 
+* spelling-add-local adds words for a given language to the document's local 
spelling
+  dictionary.
+
 * inset-split is a new convenience function that splits an inset into two at 
the given
   cursor position. This is only implemented for text insets currently.
 
diff --git a/lib/lyx2lyx/lyx_2_4.py b/lib/lyx2lyx/lyx_2_4.py
index 2ea050e..8d1c4d6 100644
--- a/lib/lyx2lyx/lyx_2_4.py
+++ b/lib/lyx2lyx/lyx_2_4.py
@@ -4396,6 +4396,15 @@ def revert_koma_frontispiece(document):
         document.append_local_layout(frontispiece_def)
 
 
+def revert_spellchecker_ignore(document):
+    """Revert document spellchecker disctionary"""
+    i = 0
+    while True:
+        i = find_token(document.header, "\\spellchecker_ignore")
+        if i == -1:
+            return
+        del document.header[i]
+
 ##
 # Conversion hub
 #
@@ -4463,10 +4472,12 @@ convert = [
            [603, []],
            [604, []],
            [605, [convert_vcolumns2]],
-           [606, [convert_koma_frontispiece]]
+           [606, [convert_koma_frontispiece]],
+           [607, []]
           ]
 
-revert =  [[605, [revert_koma_frontispiece]],
+revert =  [[606, [revert_spellchecker_ignore]],
+           [605, [revert_koma_frontispiece]],
            [604, [revert_vcolumns2]],
            [603, [revert_branch_darkcols]],
            [602, [revert_darkmode_graphics]],
diff --git a/src/AppleSpellChecker.cpp b/src/AppleSpellChecker.cpp
index 3ba1250..1975121 100644
--- a/src/AppleSpellChecker.cpp
+++ b/src/AppleSpellChecker.cpp
@@ -78,13 +78,23 @@ string 
AppleSpellChecker::Private::toString(SpellCheckResult status)
 }
 
 
-SpellChecker::Result AppleSpellChecker::check(WordLangTuple const & word)
+SpellChecker::Result AppleSpellChecker::check(WordLangTuple const & word,
+        std::vector<WordLangTuple> docdict)
 {
        if (!hasDictionary(word.lang()))
                return NO_DICTIONARY;
 
        string const word_str = to_utf8(word.word());
        string const lang = d->languageMap[word.lang()->lang()];
+
+       vector<WordLangTuple>::const_iterator it = docdict.begin();
+       for (; it != docdict.end(); ++it) {
+               if (it->lang()->code() != word.lang()->code())
+                       continue;
+               if (it->word() == word.word())
+                       return LEARNED_WORD;
+       }
+
        SpellCheckResult result =
                AppleSpeller_check(d->speller,
                        word_str.c_str(), lang.c_str());
diff --git a/src/AppleSpellChecker.h b/src/AppleSpellChecker.h
index d779777..8921fbe 100644
--- a/src/AppleSpellChecker.h
+++ b/src/AppleSpellChecker.h
@@ -24,7 +24,8 @@ public:
 
        /// \name SpellChecker inherited methods
        //@{
-       enum Result check(WordLangTuple const &) override;
+       enum Result check(WordLangTuple const &,
+                         std::vector<WordLangTuple> const &) override;
        void suggest(WordLangTuple const &, docstring_list &) override;
        void stem(WordLangTuple const &, docstring_list &) override {}
        void insert(WordLangTuple const &) override;
diff --git a/src/AspellChecker.cpp b/src/AspellChecker.cpp
index 8e41765..d7392d2 100644
--- a/src/AspellChecker.cpp
+++ b/src/AspellChecker.cpp
@@ -428,7 +428,8 @@ AspellChecker::~AspellChecker()
 }
 
 
-SpellChecker::Result AspellChecker::check(WordLangTuple const & word)
+SpellChecker::Result AspellChecker::check(WordLangTuple const & word,
+                                         vector<WordLangTuple> const & docdict)
 {
        AspellSpeller * m = d->speller(word.lang());
 
@@ -439,6 +440,13 @@ SpellChecker::Result AspellChecker::check(WordLangTuple 
const & word)
                // MSVC compiled Aspell doesn't like it.
                return WORD_OK;
 
+       vector<WordLangTuple>::const_iterator it = docdict.begin();
+       for (; it != docdict.end(); ++it) {
+               if (it->lang()->code() != word.lang()->code())
+                       continue;
+               if (it->word() == word.word())
+                       return LEARNED_WORD;
+       }
        SpellChecker::Result rc = d->check(m, word);
        return (rc == WORD_OK && d->learned(word)) ? LEARNED_WORD : rc;
 }
diff --git a/src/AspellChecker.h b/src/AspellChecker.h
index d3d744f..18aafed 100644
--- a/src/AspellChecker.h
+++ b/src/AspellChecker.h
@@ -25,7 +25,8 @@ public:
 
        /// \name SpellChecker inherited methods
        //@{
-       enum Result check(WordLangTuple const &) override;
+       enum Result check(WordLangTuple const &,
+                         std::vector<WordLangTuple> const &) override;
        void suggest(WordLangTuple const &, docstring_list &) override;
        void stem(WordLangTuple const &, docstring_list &) override {}
        void insert(WordLangTuple const &) override;
diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index d87578d..fdce444 100644
--- a/src/Buffer.cpp
+++ b/src/Buffer.cpp
@@ -961,6 +961,7 @@ int Buffer::readHeader(Lexer & lex)
        params().biblatex_citestyle.erase();
        params().multibib.erase();
        params().lineno_opts.clear();
+       params().spellignore().clear();
 
        for (int i = 0; i < 4; ++i) {
                params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i];
diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp
index 7004a92..4927741 100644
--- a/src/BufferParams.cpp
+++ b/src/BufferParams.cpp
@@ -341,6 +341,7 @@ public:
 
        AuthorList authorlist;
        BranchList branchlist;
+       IgnoreList spellignore;
        Bullet temp_bullets[4];
        Bullet user_defined_bullets[4];
        IndicesList indiceslist;
@@ -600,6 +601,21 @@ IndicesList const & BufferParams::indiceslist() const
 }
 
 
+typedef std::vector<WordLangTuple> IgnoreList;
+
+
+IgnoreList & BufferParams::spellignore()
+{
+       return pimpl_->spellignore;
+}
+
+
+IgnoreList const & BufferParams::spellignore() const
+{
+       return pimpl_->spellignore;
+}
+
+
 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
 {
        LASSERT(index < 4, return pimpl_->temp_bullets[0]);
@@ -1032,6 +1048,14 @@ string BufferParams::readToken(Lexer & lex, string const 
& token,
                                        lcolor.setColor(to_utf8(shortcut)+ "@" 
+ filename.absFileName(), color);
                        }
                }
+       } else if (token == "\\spellchecker_ignore") {
+               lex.eatLine();
+               docstring wl = lex.getDocString();
+               docstring langcode;
+               docstring word = split(wl, langcode, ' ');
+               Language const * lang = 
languages.getFromCode(to_ascii(langcode));
+               if (lang)
+                       spellignore().push_back(WordLangTuple(word, lang));
        } else if (token == "\\author") {
                lex.eatLine();
                istringstream ss(lex.getString());
@@ -1408,6 +1432,12 @@ void BufferParams::writeFile(ostream & os, Buffer const 
* buf) const
                   << "\n";
        }
 
+       for (auto const & si : spellignore()) {
+               os << "\\spellchecker_ignore " << si.lang()->code()
+                  << " " << to_utf8(si.word())
+                  << "\n";
+       }
+
        if (!paperwidth.empty())
                os << "\\paperwidth "
                   << VSpace(paperwidth).asLyXCommand() << '\n';
diff --git a/src/BufferParams.h b/src/BufferParams.h
index ff5604e..10233e6 100644
--- a/src/BufferParams.h
+++ b/src/BufferParams.h
@@ -21,6 +21,7 @@
 #include "DocumentClassPtr.h"
 #include "LayoutModuleList.h"
 #include "paper.h"
+#include "WordLangTuple.h"
 
 #include "support/copied_ptr.h"
 #include "support/types.h"
@@ -335,6 +336,11 @@ public:
        /// IndicesList:
        IndicesList & indiceslist();
        IndicesList const & indiceslist() const;
+       ///
+       typedef std::vector<WordLangTuple> IgnoreList;
+       ///
+       IgnoreList & spellignore();
+       IgnoreList const & spellignore() const;
        /**
         * The LyX name of the input encoding for LaTeX. This can be one of
         * - \c auto: find out the input encoding from the used languages
diff --git a/src/EnchantChecker.cpp b/src/EnchantChecker.cpp
index 66931fa..1dcae55 100644
--- a/src/EnchantChecker.cpp
+++ b/src/EnchantChecker.cpp
@@ -118,7 +118,8 @@ EnchantChecker::~EnchantChecker()
 }
 
 
-SpellChecker::Result EnchantChecker::check(WordLangTuple const & word)
+SpellChecker::Result EnchantChecker::check(WordLangTuple const & word,
+        std::vector<WordLangTuple> docdict)
 {
        enchant::Dict * m = d->speller(word.lang()->code());
 
@@ -133,6 +134,14 @@ SpellChecker::Result EnchantChecker::check(WordLangTuple 
const & word)
        if (m->check(utf8word))
                return WORD_OK;
 
+       vector<WordLangTuple>::const_iterator it = docdict.begin();
+       for (; it != docdict.end(); ++it) {
+               if (it->lang()->code() != word.lang()->code())
+                       continue;
+               if (it->word() == word.word())
+                       return LEARNED_WORD;
+       }
+
        return UNKNOWN_WORD;
 }
 
diff --git a/src/EnchantChecker.h b/src/EnchantChecker.h
index 22ec9bc..a79714e 100644
--- a/src/EnchantChecker.h
+++ b/src/EnchantChecker.h
@@ -15,8 +15,9 @@
 
 #include "SpellChecker.h"
 
+
 namespace enchant {
-    class Dict;
+       class Dict;
 }
 
 namespace lyx {
@@ -31,7 +32,8 @@ public:
 
        /// SpellChecker inherited methods.
        ///@{
-       enum Result check(WordLangTuple const &) override;
+       enum Result check(WordLangTuple const &,
+                         std::vector<WordLangTuple> const &) override;
        void suggest(WordLangTuple const &, docstring_list &) override;
        void stem(WordLangTuple const &, docstring_list &) override {}
        void insert(WordLangTuple const &) override;
diff --git a/src/FuncCode.h b/src/FuncCode.h
index 9976a1d..4fceed8 100644
--- a/src/FuncCode.h
+++ b/src/FuncCode.h
@@ -497,6 +497,8 @@ enum FuncCode
        LFUN_LYXFILES_OPEN,             // jspitzm 20210210
        LFUN_SEARCH_STRING_SET,         // stwitt/jspitzm 20210212
        LFUN_FONT_NO_SPELLCHECK,        // jspitzm 20210305
+       LFUN_SPELLING_ADD_LOCAL,        // jspitzm 20210306
+       // 390
        LFUN_LASTACTION                 // end of the table
 };
 
diff --git a/src/HunspellChecker.cpp b/src/HunspellChecker.cpp
index 918d4f8..06349c6 100644
--- a/src/HunspellChecker.cpp
+++ b/src/HunspellChecker.cpp
@@ -70,7 +70,8 @@ struct HunspellChecker::Private
        Hunspell * speller(Language const * lang);
        Hunspell * lookup(Language const * lang);
        /// ignored words
-       bool isIgnored(WordLangTuple const & wl) const;
+       bool isIgnored(WordLangTuple const & wl,
+                      std::vector<WordLangTuple> const & docdict) const;
        /// personal word list interface
        void remove(WordLangTuple const & wl);
        void insert(WordLangTuple const & wl);
@@ -281,7 +282,8 @@ int HunspellChecker::Private::numDictionaries() const
 }
 
 
-bool HunspellChecker::Private::isIgnored(WordLangTuple const & wl) const
+bool HunspellChecker::Private::isIgnored(WordLangTuple const & wl,
+                                        vector<WordLangTuple> const & docdict) 
const
 {
        IgnoreList::const_iterator it = ignored_.begin();
        for (; it != ignored_.end(); ++it) {
@@ -290,6 +292,13 @@ bool HunspellChecker::Private::isIgnored(WordLangTuple 
const & wl) const
                if (it->word() == wl.word())
                        return true;
        }
+       it = docdict.begin();
+       for (; it != docdict.end(); ++it) {
+               if (it->lang()->code() != wl.lang()->code())
+                       continue;
+               if (it->word() == wl.word())
+                       return true;
+       }
        return false;
 }
 
@@ -344,9 +353,10 @@ HunspellChecker::~HunspellChecker()
 }
 
 
-SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl)
+SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl,
+                                           vector<WordLangTuple> const & 
docdict)
 {
-       if (d->isIgnored(wl))
+       if (d->isIgnored(wl, docdict))
                return WORD_OK;
 
        Hunspell * h = d->speller(wl.lang());
diff --git a/src/HunspellChecker.h b/src/HunspellChecker.h
index a7225d9..e3299de 100644
--- a/src/HunspellChecker.h
+++ b/src/HunspellChecker.h
@@ -25,7 +25,8 @@ public:
 
        /// \name SpellChecker inherited methods.
        ///@{
-       enum Result check(WordLangTuple const &) override;
+       enum Result check(WordLangTuple const &,
+                         std::vector<WordLangTuple> const &) override;
        void suggest(WordLangTuple const &, docstring_list &) override;
        void stem(WordLangTuple const &, docstring_list &) override;
        void insert(WordLangTuple const &) override;
diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp
index efabfff..5badfc9 100644
--- a/src/LyXAction.cpp
+++ b/src/LyXAction.cpp
@@ -3794,6 +3794,19 @@ void LyXAction::init()
                { LFUN_SPELLING_ADD, "spelling-add", ReadOnly, Edit },
 
 /*!
+ * \var lyx::FuncCode lyx::LFUN_SPELLING_ADD_LOCAL
+ * \li Action: Add the word under the cursor to the document's local
+ *             spell checker dictionary.
+ *             The default for the language is retrieved from the cursor 
position.
+ * \li Syntax: spelling-add-local [<STRING>] [<LANG>]
+ * \li Params: <WORD>: word to add
+              <LANG>: language name (see file languages)
+ * \li Origin: spitz, 6 Mar 2021
+ * \endvar
+ */
+               { LFUN_SPELLING_ADD_LOCAL, "spelling-add-local", Noop, Edit },
+
+/*!
  * \var lyx::FuncCode lyx::LFUN_SPELLING_CONTINUOUSLY
  * \li Action: Toggle continuous spell checking.
  * \li Syntax: spelling-continuously
diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp
index cd61bb5..008ed0e 100644
--- a/src/Paragraph.cpp
+++ b/src/Paragraph.cpp
@@ -4860,7 +4860,9 @@ SpellChecker::Result Paragraph::spellCheck(pos_type & 
from, pos_type & to,
        docstring word = asString(from, to, AS_STR_INSETS | AS_STR_SKIPDELETE);
        Language * lang = d->getSpellLanguage(from);
 
-       if (getFontSettings(d->inset_owner_->buffer().params(), 
from).fontInfo().nospellcheck() == FONT_ON)
+       BufferParams const & bparams = d->inset_owner_->buffer().params();
+
+       if (getFontSettings(bparams, from).fontInfo().nospellcheck() == FONT_ON)
                return result;
 
        wl = WordLangTuple(word, lang);
@@ -4872,10 +4874,10 @@ SpellChecker::Result Paragraph::spellCheck(pos_type & 
from, pos_type & to,
                pos_type end = to;
                if (!d->ignoreWord(word)) {
                        bool const trailing_dot = to < size() && d->text_[to] 
== '.';
-                       result = speller->check(wl);
+                       result = speller->check(wl, bparams.spellignore());
                        if (SpellChecker::misspelled(result) && trailing_dot) {
                                wl = 
WordLangTuple(word.append(from_ascii(".")), lang);
-                               result = speller->check(wl);
+                               result = speller->check(wl, 
bparams.spellignore());
                                if (!SpellChecker::misspelled(result)) {
                                        LYXERR(Debug::GUI, "misspelled word is 
correct with dot: \"" <<
                                           word << "\" [" <<
@@ -4987,8 +4989,9 @@ void Paragraph::spellCheck() const
                        // start the spell checker on the unit of meaning
                        docstring word = asString(first, last, AS_STR_INSETS + 
AS_STR_SKIPDELETE);
                        WordLangTuple wl = WordLangTuple(word, lang);
+                       BufferParams const & bparams = 
d->inset_owner_->buffer().params();
                        SpellChecker::Result result = !word.empty() ?
-                               speller->check(wl) : SpellChecker::WORD_OK;
+                               speller->check(wl, bparams.spellignore()) : 
SpellChecker::WORD_OK;
                        d->markMisspelledWords(first, last, result, word, 
skips);
                        first = ++last;
                }
diff --git a/src/SpellChecker.h b/src/SpellChecker.h
index dd13a76..7a5dbac 100644
--- a/src/SpellChecker.h
+++ b/src/SpellChecker.h
@@ -14,6 +14,7 @@
 #define SPELL_BASE_H
 
 #include "support/strfwd.h"
+#include <vector>
 
 
 namespace lyx {
@@ -59,7 +60,8 @@ public:
                        && res != LEARNED_WORD; }
 
        /// check the given word of the given lang code and return the result
-       virtual enum Result check(WordLangTuple const &) = 0;
+       virtual enum Result check(WordLangTuple const &,
+                                 std::vector<WordLangTuple> const &) = 0;
 
        /// Gives suggestions.
        virtual void suggest(WordLangTuple const &, docstring_list & 
suggestions) = 0;
diff --git a/src/Text3.cpp b/src/Text3.cpp
index b34dbff..5c623fe 100644
--- a/src/Text3.cpp
+++ b/src/Text3.cpp
@@ -67,6 +67,7 @@
 
 #include "support/convert.h"
 #include "support/debug.h"
+#include "support/docstring_list.h"
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/lassert.h"
@@ -2730,6 +2731,47 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
+       case LFUN_SPELLING_ADD_LOCAL: {
+               Language const * language = getLanguage(cur, cmd.getArg(1));
+               docstring word = from_utf8(cmd.getArg(0));
+               if (word.empty()) {
+                       word = cur.selectionAsString(false);
+                       if (word.size() > 100)
+                               break;
+                       if (word.empty()) {
+                               // Get word or selection
+                               selectWordWhenUnderCursor(cur, WHOLE_WORD);
+                               word = cur.selectionAsString(false);
+                       }
+               }
+               WordLangTuple wl(word, language);
+               bool has_item = false;
+               vector<WordLangTuple> il = bv->buffer().params().spellignore();
+               vector<WordLangTuple>::const_iterator it = il.begin();
+               for (; it != il.end(); ++it) {
+                       if (it->lang()->code() != wl.lang()->code())
+                               continue;
+                       if (it->word() == wl.word()) {
+                               has_item = true;
+                               break;
+                       }
+               }
+               if (!has_item) {
+                       cur.recordUndoBufferParams();
+                       bv->buffer().params().spellignore().push_back(wl);
+                       cur.recordUndo();
+                       // trigger re-check
+                       WordLangTuple wl;
+                       docstring_list suggestions;
+                       Paragraph const & par = cur.paragraph();
+                       pos_type from = cur.pos();
+                       pos_type to = from;
+                       par.spellCheck(from, to, wl, suggestions, true, true);
+               }
+               break;
+       }
+       
+
        case LFUN_SPELLING_IGNORE: {
                Language const * language = getLanguage(cur, cmd.getArg(1));
                docstring word = from_utf8(cmd.getArg(0));
@@ -3459,6 +3501,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & 
cmd,
                break;
 
        case LFUN_SPELLING_ADD:
+       case LFUN_SPELLING_ADD_LOCAL:
        case LFUN_SPELLING_IGNORE:
        case LFUN_SPELLING_REMOVE:
                enable = theSpellChecker() != nullptr;
diff --git a/src/frontends/qt/GuiSpellchecker.cpp 
b/src/frontends/qt/GuiSpellchecker.cpp
index 684e7c7..7e4c3d7 100644
--- a/src/frontends/qt/GuiSpellchecker.cpp
+++ b/src/frontends/qt/GuiSpellchecker.cpp
@@ -428,7 +428,7 @@ bool SpellcheckerWidget::initialiseParams(std::string const 
&)
 }
 
 
-void SpellcheckerWidget::on_ignoreAllPB_clicked()
+void SpellcheckerWidget::on_skipAllPB_clicked()
 {
        /// ignore all occurrences of word
        if (d->disabled())
@@ -442,6 +442,21 @@ void SpellcheckerWidget::on_ignoreAllPB_clicked()
 }
 
 
+void SpellcheckerWidget::on_ignoreAllPB_clicked()
+{
+       /// ignore all occurrences of word
+       if (d->disabled())
+               return;
+       LYXERR(Debug::GUI, "Spellchecker: ignore all button");
+       if (d->word_.lang() && !d->word_.word().empty())
+               dispatch(FuncRequest(LFUN_SPELLING_ADD_LOCAL,
+                                    d->word_.word() + " " + 
from_ascii(d->word_.lang()->lang())));
+       d->forward();
+       d->check();
+       d->canCheck();
+}
+
+
 void SpellcheckerWidget::on_addPB_clicked()
 {
        /// insert word in personal dictionary
@@ -455,12 +470,25 @@ void SpellcheckerWidget::on_addPB_clicked()
 }
 
 
+void SpellcheckerWidget::on_skipPB_clicked()
+{
+       /// ignore this occurrence of word
+       if (d->disabled())
+               return;
+       LYXERR(Debug::GUI, "Spellchecker: skip button");
+       d->forward();
+       d->check();
+       d->canCheck();
+}
+
+
 void SpellcheckerWidget::on_ignorePB_clicked()
 {
        /// ignore this occurrence of word
        if (d->disabled())
                return;
        LYXERR(Debug::GUI, "Spellchecker: ignore button");
+       dispatch(FuncRequest(LFUN_FONT_NO_SPELLCHECK));
        d->forward();
        d->check();
        d->canCheck();
diff --git a/src/frontends/qt/GuiSpellchecker.h 
b/src/frontends/qt/GuiSpellchecker.h
index 237446d..dd60eed 100644
--- a/src/frontends/qt/GuiSpellchecker.h
+++ b/src/frontends/qt/GuiSpellchecker.h
@@ -42,7 +42,9 @@ private Q_SLOTS:
        void on_replaceCO_highlighted(const QString & str);
        void on_languageCO_activated(int index);
        void on_ignoreAllPB_clicked();
+       void on_skipAllPB_clicked();
        void on_addPB_clicked();
+       void on_skipPB_clicked();
        void on_ignorePB_clicked();
        void on_replacePB_clicked();
 
diff --git a/src/frontends/qt/Menus.cpp b/src/frontends/qt/Menus.cpp
index 8f5ae7c..df5586e 100644
--- a/src/frontends/qt/Menus.cpp
+++ b/src/frontends/qt/Menus.cpp
@@ -862,10 +862,12 @@ void MenuDefinition::expandSpellingSuggestions(BufferView 
const * bv)
                                docstring const arg = wl.word() + " " + 
from_ascii(wl.lang()->lang());
                                add(MenuItem(MenuItem::Command, qt_("Add to 
personal dictionary|n"),
                                                FuncRequest(LFUN_SPELLING_ADD, 
arg)));
-                               add(MenuItem(MenuItem::Command, qt_("Ignore|g"),
+                               add(MenuItem(MenuItem::Command, qt_("Ignore 
this occurrence|g"),
                                                
FuncRequest(LFUN_FONT_NO_SPELLCHECK, arg)));
-                               add(MenuItem(MenuItem::Command, qt_("Ignore 
all|I"),
+                               add(MenuItem(MenuItem::Command, qt_("Ignore all 
for this session|I"),
                                                
FuncRequest(LFUN_SPELLING_IGNORE, arg)));
+                               add(MenuItem(MenuItem::Command, qt_("Ignore all 
in this document|d"),
+                                               
FuncRequest(LFUN_SPELLING_ADD_LOCAL, arg)));
                        }
                }
                break;
diff --git a/src/frontends/qt/ui/SpellcheckerUi.ui 
b/src/frontends/qt/ui/SpellcheckerUi.ui
index c22ae0a..d51d3ee 100644
--- a/src/frontends/qt/ui/SpellcheckerUi.ui
+++ b/src/frontends/qt/ui/SpellcheckerUi.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>300</width>
-    <height>380</height>
+    <width>477</width>
+    <height>488</height>
    </rect>
   </property>
   <property name="minimumSize">
@@ -19,37 +19,8 @@
   <property name="windowTitle">
    <string>Spell Checker</string>
   </property>
-  <layout class="QGridLayout" name="gridLayout" columnstretch="1,0">
-   <item row="5" column="0">
-    <widget class="QComboBox" name="replaceCO">
-     <property name="focusPolicy">
-      <enum>Qt::StrongFocus</enum>
-     </property>
-     <property name="toolTip">
-      <string>Replace with selected word</string>
-     </property>
-     <property name="editable">
-      <bool>true</bool>
-     </property>
-     <property name="insertPolicy">
-      <enum>QComboBox::InsertAtTop</enum>
-     </property>
-     <property name="duplicatesEnabled">
-      <bool>false</bool>
-     </property>
-    </widget>
-   </item>
-   <item row="5" column="1">
-    <widget class="QPushButton" name="replacePB">
-     <property name="toolTip">
-      <string>Replace word with current choice</string>
-     </property>
-     <property name="text">
-      <string>&amp;Replace</string>
-     </property>
-    </widget>
-   </item>
-   <item row="0" column="0" colspan="2">
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
       <widget class="QLabel" name="languageLA">
@@ -76,6 +47,13 @@
      </item>
     </layout>
    </item>
+   <item row="1" column="0" colspan="2">
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
    <item row="2" column="0">
     <widget class="QLabel" name="TextLabel3">
      <property name="text">
@@ -93,6 +71,16 @@
      </property>
     </widget>
    </item>
+   <item row="3" column="1">
+    <widget class="QPushButton" name="skipPB">
+     <property name="toolTip">
+      <string>Skip this match and go to next misspelling</string>
+     </property>
+     <property name="text">
+      <string>S&amp;kip</string>
+     </property>
+    </widget>
+   </item>
    <item row="4" column="0">
     <widget class="QLabel" name="TextLabel1">
      <property name="text">
@@ -103,6 +91,35 @@
      </property>
     </widget>
    </item>
+   <item row="5" column="0">
+    <widget class="QComboBox" name="replaceCO">
+     <property name="focusPolicy">
+      <enum>Qt::StrongFocus</enum>
+     </property>
+     <property name="toolTip">
+      <string>Replace with selected word</string>
+     </property>
+     <property name="editable">
+      <bool>true</bool>
+     </property>
+     <property name="insertPolicy">
+      <enum>QComboBox::InsertAtTop</enum>
+     </property>
+     <property name="duplicatesEnabled">
+      <bool>false</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="1">
+    <widget class="QPushButton" name="replacePB">
+     <property name="toolTip">
+      <string>Replace word with current choice</string>
+     </property>
+     <property name="text">
+      <string>&amp;Replace</string>
+     </property>
+    </widget>
+   </item>
    <item row="6" column="0">
     <widget class="QLabel" name="TextLabel2">
      <property name="sizePolicy">
@@ -122,24 +139,37 @@
    <item row="6" column="1">
     <widget class="QPushButton" name="replaceAllPB">
      <property name="toolTip">
-      <string/>
+      <string>Replace all occurrences of the word in the document with current 
choice</string>
      </property>
      <property name="text">
       <string>Re&amp;place All</string>
      </property>
     </widget>
    </item>
-   <item row="1" column="0" colspan="2">
-    <widget class="Line" name="line">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
+   <item row="7" column="0" rowspan="5">
+    <widget class="QListWidget" name="suggestionsLW"/>
+   </item>
+   <item row="7" column="1">
+    <widget class="QPushButton" name="ignorePB">
+     <property name="toolTip">
+      <string>Ignore this occurrence of the word permanently</string>
+     </property>
+     <property name="text">
+      <string>Ign&amp;ore</string>
      </property>
     </widget>
    </item>
-   <item row="7" column="0" rowspan="4">
-    <widget class="QListWidget" name="suggestionsLW"/>
-   </item>
    <item row="9" column="1">
+    <widget class="QPushButton" name="ignoreAllPB">
+     <property name="toolTip">
+      <string>Ignore all occurrences of this word within this document. This 
is perdurant beyond the current session.</string>
+     </property>
+     <property name="text">
+      <string>I&amp;gnore All</string>
+     </property>
+    </widget>
+   </item>
+   <item row="10" column="1">
     <widget class="QPushButton" name="addPB">
      <property name="toolTip">
       <string>Add the word to your personal dictionary</string>
@@ -149,7 +179,7 @@
      </property>
     </widget>
    </item>
-   <item row="10" column="1">
+   <item row="11" column="1">
     <spacer>
      <property name="orientation">
       <enum>Qt::Vertical</enum>
@@ -165,23 +195,13 @@
      </property>
     </spacer>
    </item>
-   <item row="3" column="1">
-    <widget class="QPushButton" name="ignorePB">
-     <property name="toolTip">
-      <string>Ignore this word</string>
-     </property>
-     <property name="text">
-      <string>Ign&amp;ore</string>
-     </property>
-    </widget>
-   </item>
    <item row="4" column="1">
-    <widget class="QPushButton" name="ignoreAllPB">
+    <widget class="QPushButton" name="skipAllPB">
      <property name="toolTip">
-      <string>Ignore this word throughout this session</string>
+      <string>Skips all occurrences of this word within the current 
session.</string>
      </property>
      <property name="text">
-      <string>I&amp;gnore All</string>
+      <string>Skip A&amp;ll</string>
      </property>
     </widget>
    </item>
diff --git a/src/version.h b/src/version.h
index c8c3c49..cc1f2a2 100644
--- a/src/version.h
+++ b/src/version.h
@@ -32,8 +32,8 @@ extern char const * const lyx_version_info;
 
 // Do not remove the comment below, so we get merge conflict in
 // independent branches. Instead add your own.
-#define LYX_FORMAT_LYX 606 // spitz: frontispiece KOMA layout
-#define LYX_FORMAT_TEX2LYX 606
+#define LYX_FORMAT_LYX 607 // spitz: \\spellchecker_ignore buffer param
+#define LYX_FORMAT_TEX2LYX 607
 
 #if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
 #ifndef _MSC_VER
-- 
lyx-cvs mailing list
[email protected]
http://lists.lyx.org/mailman/listinfo/lyx-cvs

Reply via email to