From 92672e17a52d0c86e693183627c8c6b8fa44fb86 Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Wed, 3 Dec 2014 00:54:24 +0100
Subject: Fix spell checking by using QSyntaxHighlighter.

This fixes spell checking not interfering with Qt's undo stack management anymore.

Test-Information:

Tested on OS X 10.9.5 with Qt 5.3.2.

Change-Id: Icc3aa9f7213856388e4da317525c75ac97da72e3

diff --git a/Swift/QtUI/QtSpellCheckHighlighter.cpp b/Swift/QtUI/QtSpellCheckHighlighter.cpp
new file mode 100644
index 0000000..dba6100
--- /dev/null
+++ b/Swift/QtUI/QtSpellCheckHighlighter.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/QtUI/QtSpellCheckHighlighter.h>
+
+#include <SwifTools/SpellChecker.h>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtSpellCheckHighlighter::QtSpellCheckHighlighter(QTextDocument* parent, SpellChecker* spellChecker) : QSyntaxHighlighter(parent), checker_(spellChecker) {
+
+}
+
+QtSpellCheckHighlighter::~QtSpellCheckHighlighter() {
+
+}
+
+void QtSpellCheckHighlighter::highlightBlock(const QString& text) {
+	misspelledPositions_.clear();
+	std::string fragment = Q2PSTRING(text);
+	checker_->checkFragment(fragment, misspelledPositions_);
+
+	QTextCharFormat spellingErrorFormat;
+	spellingErrorFormat.setUnderlineColor(QColor(Qt::red));
+	spellingErrorFormat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
+
+	foreach (PositionPair position, misspelledPositions_) {
+		setFormat(boost::get<0>(position), boost::get<1>(position) - boost::get<0>(position), spellingErrorFormat);
+	};
+}
+
+PositionPairList QtSpellCheckHighlighter::getMisspelledPositions() const {
+	return misspelledPositions_;
+}
+
+}
diff --git a/Swift/QtUI/QtSpellCheckHighlighter.h b/Swift/QtUI/QtSpellCheckHighlighter.h
new file mode 100644
index 0000000..c1cfc70
--- /dev/null
+++ b/Swift/QtUI/QtSpellCheckHighlighter.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <SwifTools/SpellParser.h>
+
+#include <QSyntaxHighlighter>
+
+class QString;
+class QTextDocument;
+
+namespace Swift {
+
+class SpellChecker;
+
+class QtSpellCheckHighlighter : public QSyntaxHighlighter {
+	Q_OBJECT
+
+public:
+	QtSpellCheckHighlighter(QTextDocument* parent, SpellChecker* spellChecker);
+	virtual ~QtSpellCheckHighlighter();
+
+	PositionPairList getMisspelledPositions() const;
+
+protected:
+	virtual void highlightBlock(const QString& text);
+
+private:
+	SpellChecker* checker_;
+	PositionPairList misspelledPositions_;
+};
+
+
+}
diff --git a/Swift/QtUI/QtTextEdit.cpp b/Swift/QtUI/QtTextEdit.cpp
index 8551f3d..98d735e 100644
--- a/Swift/QtUI/QtTextEdit.cpp
+++ b/Swift/QtUI/QtTextEdit.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -29,9 +29,8 @@
 
 namespace Swift {
 
-QtTextEdit::QtTextEdit(SettingsProvider* settings, QWidget* parent) : QTextEdit(parent) {
+QtTextEdit::QtTextEdit(SettingsProvider* settings, QWidget* parent) : QTextEdit(parent), checker_(NULL), highlighter_(NULL) {
 	connect(this, SIGNAL(textChanged()), this, SLOT(handleTextChanged()));
-	checker_ = NULL;
 	settings_ = settings;
 #ifdef HAVE_SPELLCHECKER
 	setUpSpellChecker();
@@ -73,35 +72,6 @@ void QtTextEdit::keyPressEvent(QKeyEvent* event) {
 	}
 	else {
 		QTextEdit::keyPressEvent(event);
-#ifdef HAVE_SPELLCHECKER
-		if (settings_->getSetting(SettingConstants::SPELL_CHECKER)) {
-			underlineMisspells();
-		}
-#endif
-	}
-}
-
-void QtTextEdit::underlineMisspells() {
-	QTextCursor cursor = textCursor();
-	misspelledPositions_.clear();
-	QTextCharFormat normalFormat;
-	cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1);
-	cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor, 1);
-	cursor.setCharFormat(normalFormat);
-	if (checker_ == NULL) {
-		return;
-	}
-	QTextCharFormat spellingErrorFormat;
-	spellingErrorFormat.setUnderlineColor(QColor(Qt::red));
-	spellingErrorFormat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
-	std::string fragment = Q2PSTRING(cursor.selectedText());
-	checker_->checkFragment(fragment, misspelledPositions_);
-	foreach (PositionPair position, misspelledPositions_) {
-		cursor.setPosition(boost::get<0>(position), QTextCursor::MoveAnchor);
-		cursor.setPosition(boost::get<1>(position), QTextCursor::KeepAnchor);
-		cursor.setCharFormat(spellingErrorFormat);
-		cursor.clearSelection();
-		cursor.setCharFormat(normalFormat);
 	}
 }
 
@@ -123,7 +93,8 @@ void QtTextEdit::replaceMisspelledWord(const QString& word, int cursorPosition)
 }
 
 PositionPair QtTextEdit::getWordFromCursor(int cursorPosition) {
-	for (PositionPairList::iterator it = misspelledPositions_.begin(); it != misspelledPositions_.end(); ++it) {
+	PositionPairList misspelledPositions = highlighter_->getMisspelledPositions();
+	for (PositionPairList::iterator it = misspelledPositions.begin(); it != misspelledPositions.end(); ++it) {
 		if (cursorPosition >= boost::get<0>(*it) && cursorPosition <= boost::get<1>(*it)) {
 			return *it;
 		}
@@ -208,6 +179,9 @@ void QtTextEdit::setUpSpellChecker()
 		std::string dictPath = settings_->getSetting(SettingConstants::DICT_PATH);
 		std::string dictFile = settings_->getSetting(SettingConstants::DICT_FILE);
 		checker_ = SpellCheckerFactory().createSpellChecker(dictPath + dictFile);
+		delete highlighter_;
+		highlighter_ = NULL;
+		highlighter_ = new QtSpellCheckHighlighter(document(), checker_);
 	}
 }
 #endif
@@ -231,7 +205,7 @@ void QtTextEdit::handleSettingChanged(const std::string& settings) {
 		|| settings == SettingConstants::DICT_FILE.getKey()) {
 #ifdef HAVE_SPELLCHECKER
 		setUpSpellChecker();
-		underlineMisspells();
+		highlighter_->rehighlight();
 #endif
 	}
 }
diff --git a/Swift/QtUI/QtTextEdit.h b/Swift/QtUI/QtTextEdit.h
index a8df4d3..5f16453 100644
--- a/Swift/QtUI/QtTextEdit.h
+++ b/Swift/QtUI/QtTextEdit.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -11,40 +11,49 @@
 #include <Swift/Controllers/Settings/SettingsProvider.h>
 #include <Swift/Controllers/SettingConstants.h>
 
+#include <Swift/QtUI/QtSpellCheckHighlighter.h>
+
 #include <QTextEdit>
 #include <QPointer>
 
 namespace Swift {
 	class SpellChecker;
 	class QtSpellCheckerWindow;
+
 	class QtTextEdit : public QTextEdit {
 		Q_OBJECT
 	public:
 		QtTextEdit(SettingsProvider* settings, QWidget* parent = 0);
 		virtual ~QtTextEdit();
 		virtual QSize sizeHint() const;
+
 	signals:
 		void wordCorrected(QString& word);
 		void returnPressed();
 		void unhandledKeyPressEvent(QKeyEvent* event);
+
 	public slots:
 		void handleSettingChanged(const std::string& settings);
+
 	protected:
 		virtual void keyPressEvent(QKeyEvent* event);
 		virtual void contextMenuEvent(QContextMenuEvent* event);
+
 	private slots:
 		void handleTextChanged();
+
 	private:
-		SpellChecker *checker_;
-		std::vector<QAction*> replaceWordActions_;
-		PositionPairList misspelledPositions_;
-		SettingsProvider *settings_;
-		QPointer<QtSpellCheckerWindow> spellCheckerWindow_;
 		void addSuggestions(QMenu* menu, QContextMenuEvent* event);
 		void replaceMisspelledWord(const QString& word, int cursorPosition);
 		void setUpSpellChecker();
-		void underlineMisspells();
 		void spellCheckerSettingsWindow();
 		PositionPair getWordFromCursor(int cursorPosition);
+
+	private:
+		SpellChecker* checker_;
+		QtSpellCheckHighlighter* highlighter_;
+		std::vector<QAction*> replaceWordActions_;
+		SettingsProvider* settings_;
+		QPointer<QtSpellCheckerWindow> spellCheckerWindow_;
 	};
 }
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 26e738a..80daaea 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -192,7 +192,8 @@ sources = [
     "QtAffiliationEditor.cpp",
     "QtUISettingConstants.cpp",
     "QtURLValidator.cpp",
-    "QtResourceHelper.cpp"
+    "QtResourceHelper.cpp",
+    "QtSpellCheckHighlighter.cpp"
   ]
 
 # QtVCardWidget
-- 
cgit v0.10.2-6-g49f6