1 /*
2  * This file is part of Licq, an instant messaging client for UNIX.
3  * Copyright (C) 2009 Licq developers
4  *
5  * Licq is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Licq is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Licq; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include "spellchecker.h"
21 
22 #include <QFileInfo>
23 #include <QRegExp>
24 #include <QSyntaxHighlighter>
25 #include <QTextCodec>
26 
27 #include <hunspell/hunspell.hxx>
28 
29 
30 using namespace LicqQtGui;
31 /* TRANSLATOR LicqQtGui::SpellChecker */
32 
SpellChecker(QTextDocument * parent,const QString & dicFile)33 SpellChecker::SpellChecker(QTextDocument* parent, const QString& dicFile)
34   : QSyntaxHighlighter(parent),
35     mySpeller(NULL)
36 {
37   setDictionary(dicFile);
38 }
39 
~SpellChecker()40 SpellChecker::~SpellChecker()
41 {
42   if (mySpeller != NULL)
43     delete mySpeller;
44 }
45 
setDictionary(const QString & dicFile)46 void SpellChecker::setDictionary(const QString& dicFile)
47 {
48   if (dicFile == myDicFile)
49     return;
50   myDicFile = dicFile;
51 
52   if (mySpeller != NULL)
53   {
54     delete mySpeller;
55     mySpeller = NULL;
56   }
57 
58   // If dicFile is empty or refers to a non-existent file, disable spell checking
59   if (dicFile.isEmpty() || !QFileInfo(dicFile).isReadable())
60     return;
61 
62   QString affFile = dicFile.left(dicFile.lastIndexOf('.')) + ".aff";
63   mySpeller = new Hunspell(affFile.toLatin1(), dicFile.toLatin1());
64   mySpellerCodec = QTextCodec::codecForName(mySpeller->get_dic_encoding());
65 }
66 
highlightBlock(const QString & text)67 void SpellChecker::highlightBlock(const QString& text)
68 {
69   if (mySpeller == NULL)
70     return;
71 
72   QTextCharFormat myBadSpelling;
73   myBadSpelling.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
74   myBadSpelling.setUnderlineColor(Qt::red);
75 
76   QRegExp wordSplit("\\b\\w+\\b");
77   int pos = 0;
78   while ((pos = wordSplit.indexIn(text, pos)) != -1)
79   {
80     int len = wordSplit.matchedLength();
81     if (!checkWord(wordSplit.cap()))
82       setFormat(pos, len, myBadSpelling);
83     pos += len;
84   }
85 }
86 
getSuggestions(const QString & word)87 QStringList SpellChecker::getSuggestions(const QString& word)
88 {
89   if (mySpeller == NULL || checkWord(word))
90     return QStringList();
91 
92   char** wordList;
93   int count = mySpeller->suggest(&wordList, mySpellerCodec->fromUnicode(word).data());
94   if (count <= 0)
95     return QStringList();
96 
97   QStringList ret;
98   for (int i = 0; i < count; ++i)
99     ret.append(mySpellerCodec->toUnicode(wordList[i]));
100   mySpeller->free_list(&wordList, count);
101 
102   return ret;
103 }
104 
checkWord(const QString & word)105 bool SpellChecker::checkWord(const QString& word)
106 {
107   if (mySpeller == NULL)
108     return true;
109 
110   return (mySpeller->spell(mySpellerCodec->fromUnicode(word).data()) != 0);
111 }
112