diff --git a/libs/text/KoTextBlockData.cpp b/libs/text/KoTextBlockData.cpp --- a/libs/text/KoTextBlockData.cpp +++ b/libs/text/KoTextBlockData.cpp @@ -81,7 +81,15 @@ void KoTextBlockData::appendMarkup(MarkupType type, int firstChar, int lastChar) { - Q_ASSERT(d->markupRangesMap[type].isEmpty() || d->markupRangesMap[type].last().lastChar < firstChar); + if (type == KoTextBlockData::Grammar) { + Q_ASSERT(d->markupRangesMap[type].isEmpty() || d->markupRangesMap[type].last().lastChar < firstChar); + } else if (!d->markupRangesMap[type].isEmpty() && d->markupRangesMap[type].last().lastChar >= firstChar) { + // Character positions from spellchecker are not in sync with document. + // I have only seen this in connection with dropcaps, so could be caused by + // large amount to spellcheck combined with large changes to the document. + // Anyway, returning here just means markup will be incorrect/missing until next spellcheck is run. + return; + } MarkupRange range; range.firstChar = firstChar; diff --git a/plugins/textediting/spellcheck/SpellCheck.h b/plugins/textediting/spellcheck/SpellCheck.h --- a/plugins/textediting/spellcheck/SpellCheck.h +++ b/plugins/textediting/spellcheck/SpellCheck.h @@ -86,7 +86,7 @@ void configureSpellCheck(); void runQueue(); void setBackgroundSpellChecking(bool b); - void documentChanged(int from, int min, int plus); + void documentChanged(int from, int charsRemoved, int charsAdded); private: Sonnet::Speller m_speller; @@ -111,7 +111,8 @@ QTextStream stream; SpellCheckMenu *m_spellCheckMenu; SpellSections m_activeSection; // the section we are currently doing a run on; - bool m_simpleEdit; //set when user is doing a simple edit, meaning we should ignore documentCanged + bool m_simpleEdit; //set when user is doing a simple edit, meaning we should not start spellchecking + int m_cursorPosition; // simple edit cursor position }; #endif diff --git a/plugins/textediting/spellcheck/SpellCheck.cpp b/plugins/textediting/spellcheck/SpellCheck.cpp --- a/plugins/textediting/spellcheck/SpellCheck.cpp +++ b/plugins/textediting/spellcheck/SpellCheck.cpp @@ -52,6 +52,7 @@ , m_spellCheckMenu(0) , m_activeSection(0, 0, 0) , m_simpleEdit(false) + , m_cursorPosition(0) { /* setup actions for this plugin */ QAction *configureAction = new QAction(i18n("Configure &Spell Checking..."), this); @@ -102,8 +103,7 @@ { m_simpleEdit = true; setDocument(document); - Q_UNUSED(document); - Q_UNUSED(cursorPosition); + m_cursorPosition = cursorPosition; } void SpellCheck::checkSection(QTextDocument *document, int startPosition, int endPosition) @@ -241,8 +241,9 @@ blockData.appendMarkup(KoTextBlockData::Misspell, startPosition - block.position(), startPosition - block.position() + word.trimmed().length()); } -void SpellCheck::documentChanged(int from, int min, int plus) +void SpellCheck::documentChanged(int from, int charsRemoved, int charsAdded) { + Q_UNUSED(charsRemoved); QTextDocument *document = qobject_cast(sender()); if (document == 0) return; @@ -255,17 +256,21 @@ KoTextBlockData blockData(block); if (m_enableSpellCheck) { blockData.setMarkupsLayoutValidity(KoTextBlockData::Misspell, false); - if (m_simpleEdit) { - // if it's a simple edit we will wait until finishedWord - blockData.rebaseMarkups(KoTextBlockData::Misspell, from, plus - min); + // We cannot safely handle combined remove/add in case it spans words. + // This should probably never be defined as a simple edit anyway, + // but atm lines with dropcaps trigger this behaviour. See KoTextLayoutArea. + if (m_simpleEdit && (charsRemoved == 0 || charsAdded == 0)) { + // If it's a simple edit we will wait until finishedWord before spellchecking + // but we need to adjust all markups behind the added/removed character(s) + blockData.rebaseMarkups(KoTextBlockData::Misspell, from - block.position(), charsAdded - charsRemoved); } else { checkSection(document, block.position(), block.position() + block.length() - 1); } } else { blockData.clearMarkups(KoTextBlockData::Misspell); } block = block.next(); - } while(block.isValid() && block.position() <= from + plus); + } while(block.isValid() && block.position() <= from + charsAdded); m_simpleEdit = false; }