• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEUI

highlighter.cpp

Go to the documentation of this file.
00001 
00023 #include "highlighter.h"
00024 #include "highlighter.moc"
00025 
00026 #include "speller.h"
00027 #include "loader_p.h"
00028 #include "filter_p.h"
00029 #include "settings_p.h"
00030 
00031 #include <kconfig.h>
00032 #include <kdebug.h>
00033 #include <klocale.h>
00034 #include <kmessagebox.h>
00035 
00036 #include <QTextEdit>
00037 #include <QTextCharFormat>
00038 #include <QTimer>
00039 #include <QColor>
00040 #include <QHash>
00041 #include <QTextCursor>
00042 #include <QEvent>
00043 #include <QKeyEvent>
00044 #include <QApplication>
00045 
00046 namespace Sonnet {
00047 
00048 class Highlighter::Private
00049 {
00050 public:
00051     ~Private();
00052     Filter     *filter;
00053     Loader     *loader;
00054     Speller    *dict;
00055     QHash<QString, Speller*> dictCache;
00056     QTextEdit *edit;
00057     bool active;
00058     bool automatic;
00059     bool completeRehighlightRequired;
00060     bool intraWordEditing;
00061     bool spellCheckerFound;
00062     int disablePercentage;
00063     int disableWordCount;
00064     int wordCount, errorCount;
00065     QTimer *rehighlightRequest;
00066     QColor spellColor;
00067     int suggestionListeners; // #of connections for the newSuggestions signal
00068 };
00069 
00070 Highlighter::Private::~Private()
00071 {
00072   qDeleteAll(dictCache);
00073   delete filter;
00074 }
00075 
00076 Highlighter::Highlighter(QTextEdit *textEdit,
00077                          const QString& configFile,
00078                          const QColor& _col)
00079     : QSyntaxHighlighter(textEdit),
00080       d(new Private)
00081 {
00082     d->filter = Filter::defaultFilter();
00083     d->edit = textEdit;
00084     d->active = true;
00085     d->automatic = true;
00086     d->wordCount = 0;
00087     d->errorCount = 0;
00088     d->intraWordEditing = false;
00089     d->completeRehighlightRequired = false;
00090     d->spellCheckerFound = true;
00091     d->spellColor = _col.isValid() ? _col : Qt::red;
00092     d->suggestionListeners = 0;
00093 
00094     textEdit->installEventFilter( this );
00095     textEdit->viewport()->installEventFilter( this );
00096 
00097     d->loader = Loader::openLoader();
00098 
00099     //Do not load an empty settings file as it will cause the spellchecker to fail
00100     //if the KGlobal::locale()->language() (default value) spellchecker is not installed,
00101     //and we have a global sonnetrc file with a spellcheck lang installed which could be used.
00102     if (!configFile.isEmpty()) {
00103         KConfig conf(configFile);
00104         if (conf.hasGroup("Spelling")) {
00105             d->loader->settings()->restore(&conf);
00106             d->filter->setSettings(d->loader->settings());
00107         }
00108     }
00109 
00110     d->dict   = new Sonnet::Speller();
00111     if(!d->dict->isValid()) {
00112     d->spellCheckerFound = false;
00113     } else {
00114         d->dictCache.insert(d->dict->language(),
00115                             d->dict);
00116 
00117         d->disablePercentage = d->loader->settings()->disablePercentageWordError();
00118 
00119         d->disableWordCount = d->loader->settings()->disableWordErrorCount();
00120 
00121         //Add kde personal word
00122         const QStringList l = Highlighter::personalWords();
00123         for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) {
00124             d->dict->addToSession( *it );
00125         }
00126         d->rehighlightRequest = new QTimer(this);
00127         connect( d->rehighlightRequest, SIGNAL( timeout() ),
00128                  this, SLOT( slotRehighlight() ));
00129         d->completeRehighlightRequired = true;
00130         d->rehighlightRequest->setInterval(0);
00131         d->rehighlightRequest->setSingleShot(true);
00132         d->rehighlightRequest->start();
00133     }
00134 }
00135 
00136 Highlighter::~Highlighter()
00137 {
00138     delete d;
00139 }
00140 
00141 bool Highlighter::spellCheckerFound() const
00142 {
00143     return d->spellCheckerFound;
00144 }
00145 
00146 // Since figuring out spell correction suggestions is extremely costly,
00147 // we keep track of whether the user actually wants some, and only offer them
00148 // in that case
00149 void Highlighter::connectNotify(const char* signal)
00150 {
00151     if (QLatin1String(signal) == SIGNAL(newSuggestions(QString,QStringList)))
00152         ++d->suggestionListeners;
00153     QSyntaxHighlighter::connectNotify(signal);
00154 }
00155 
00156 void Highlighter::disconnectNotify(const char* signal)
00157 {
00158     if (QLatin1String(signal) == SIGNAL(newSuggestions(QString,QStringList)))
00159         --d->suggestionListeners;
00160     QSyntaxHighlighter::disconnectNotify(signal);
00161 }
00162 
00163 void Highlighter::slotRehighlight()
00164 {
00165     kDebug(0) << "Highlighter::slotRehighlight()";
00166     if (d->completeRehighlightRequired) {
00167         d->wordCount  = 0;
00168         d->errorCount = 0;
00169         rehighlight();
00170 
00171     } else {
00172     //rehighlight the current para only (undo/redo safe)
00173         QTextCursor cursor = d->edit->textCursor();
00174         cursor.insertText( "" );
00175     }
00176     //if (d->checksDone == d->checksRequested)
00177     //d->completeRehighlightRequired = false;
00178     QTimer::singleShot( 0, this, SLOT( slotAutoDetection() ));
00179 }
00180 
00181 
00182 QStringList Highlighter::personalWords()
00183 {
00184     QStringList l;
00185     l.append( "KMail" );
00186     l.append( "KOrganizer" );
00187     l.append( "KAddressBook" );
00188     l.append( "KHTML" );
00189     l.append( "KIO" );
00190     l.append( "KJS" );
00191     l.append( "Konqueror" );
00192     l.append( "Sonnet" );
00193     l.append( "Kontact" );
00194     l.append( "Qt" );
00195     return l;
00196 }
00197 
00198 bool Highlighter::automatic() const
00199 {
00200     return d->automatic;
00201 }
00202 
00203 bool Highlighter::intraWordEditing() const
00204 {
00205     return d->intraWordEditing;
00206 }
00207 
00208 void Highlighter::setIntraWordEditing( bool editing )
00209 {
00210     d->intraWordEditing = editing;
00211 }
00212 
00213 
00214 void Highlighter::setAutomatic( bool automatic )
00215 {
00216     if ( automatic  == d->automatic )
00217         return;
00218 
00219     d->automatic = automatic;
00220     if ( d->automatic )
00221         slotAutoDetection();
00222 }
00223 
00224 void Highlighter::slotAutoDetection()
00225 {
00226     bool savedActive = d->active;
00227 
00228     //don't disable just because 1 of 4 is misspelled.
00229     if (d->automatic && d->wordCount >= 10) {
00230         // tme = Too many errors
00231         bool tme = (d->errorCount >= d->disableWordCount) && (
00232             d->errorCount * 100 >= d->disablePercentage * d->wordCount);
00233         if (d->active && tme) {
00234             d->active = false;
00235         } else if (!d->active && !tme) {
00236             d->active = true;
00237         }
00238     }
00239 
00240     if (d->active != savedActive) {
00241         if (d->active) {
00242             emit activeChanged(i18n("As-you-type spell checking enabled."));
00243         } else {
00244             emit activeChanged(i18n( "Too many misspelled words. "
00245                                "As-you-type spell checking disabled."));
00246         }
00247 
00248         d->completeRehighlightRequired = true;
00249         d->rehighlightRequest->setInterval(100);
00250         d->rehighlightRequest->setSingleShot(true);
00251         kDebug()<<" Highlighter::slotAutoDetection :"<<d->active;
00252     }
00253 
00254 }
00255 
00256 void Highlighter::setActive( bool active )
00257 {
00258     if ( active == d->active )
00259         return;
00260     d->active = active;
00261     rehighlight();
00262 
00263 
00264     if ( d->active )
00265         emit activeChanged( i18n("As-you-type spell checking enabled.") );
00266     else
00267         emit activeChanged( i18n("As-you-type spell checking disabled.") );
00268 }
00269 
00270 bool Highlighter::isActive() const
00271 {
00272     return d->active;
00273 }
00274 
00275 void Highlighter::highlightBlock(const QString &text)
00276 {
00277     if (text.isEmpty() || !d->active || !d->spellCheckerFound)
00278         return;
00279 
00280     d->filter->setBuffer( text );
00281     Word w = d->filter->nextWord();
00282     while ( !w.end ) {
00283         ++d->wordCount;
00284         if (d->dict->isMisspelled(w.word)) {
00285             ++d->errorCount;
00286             setMisspelled(w.start, w.word.length());
00287             if (d->suggestionListeners)
00288                 emit newSuggestions(w.word, d->dict->suggest(w.word));
00289         } else
00290             unsetMisspelled(w.start, w.word.length());
00291         w = d->filter->nextWord();
00292     }
00293     //QTimer::singleShot( 0, this, SLOT(checkWords()) );
00294     setCurrentBlockState(0);
00295 }
00296 
00297 QString Highlighter::currentLanguage() const
00298 {
00299     return d->dict->language();
00300 }
00301 
00302 void Highlighter::setCurrentLanguage(const QString &lang)
00303 {
00304     if (!d->dictCache.contains(lang)) {
00305         d->dict = new Speller(*d->dict);
00306         d->dict->setLanguage(lang);
00307         if (d->dict->isValid()) {
00308             d->dictCache.insert(lang, d->dict);
00309         } else {
00310             kDebug()<<"No dictionary for \""
00311                     <<lang
00312                     <<"\" staying with the current language."
00313                     <<endl;
00314             return;
00315         }
00316     }
00317     d->dict = d->dictCache[lang];
00318     d->wordCount = 0;
00319     d->errorCount = 0;
00320     if (d->automatic)
00321         slotAutoDetection();
00322 }
00323 
00324 void Highlighter::setMisspelled(int start, int count)
00325 {
00326     QTextCharFormat format;
00327     format.setFontUnderline(true);
00328     format.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
00329     format.setUnderlineColor(d->spellColor);
00330     setFormat(start, count, format);
00331 }
00332 
00333 void Highlighter::unsetMisspelled( int start, int count )
00334 {
00335     setFormat(start, count, QTextCharFormat());
00336 }
00337 
00338 bool Highlighter::eventFilter( QObject *o, QEvent *e)
00339 {
00340 #if 0
00341     if (o == textEdit() && (e->type() == QEvent::FocusIn)) {
00342         if ( d->globalConfig ) {
00343             QString skey = spellKey();
00344             if ( d->spell && d->spellKey != skey ) {
00345                 d->spellKey = skey;
00346                 KDictSpellingHighlighter::dictionaryChanged();
00347             }
00348         }
00349     }
00350 #endif
00351     if (!d->spellCheckerFound)
00352     return false;
00353     if (o == d->edit  && (e->type() == QEvent::KeyPress)) {
00354     QKeyEvent *k = static_cast<QKeyEvent *>(e);
00355     //d->autoReady = true;
00356     if (d->rehighlightRequest->isActive()) // try to stay out of the users way
00357         d->rehighlightRequest->start( 500 );
00358     if ( k->key() == Qt::Key_Enter ||
00359          k->key() == Qt::Key_Return ||
00360          k->key() == Qt::Key_Up ||
00361          k->key() == Qt::Key_Down ||
00362          k->key() == Qt::Key_Left ||
00363          k->key() == Qt::Key_Right ||
00364          k->key() == Qt::Key_PageUp ||
00365          k->key() == Qt::Key_PageDown ||
00366          k->key() == Qt::Key_Home ||
00367          k->key() == Qt::Key_End ||
00368          (( k->modifiers()== Qt::ControlModifier ) &&
00369           ((k->key() == Qt::Key_A) ||
00370            (k->key() == Qt::Key_B) ||
00371            (k->key() == Qt::Key_E) ||
00372            (k->key() == Qt::Key_N) ||
00373            (k->key() == Qt::Key_P))) ) {
00374         if ( intraWordEditing() ) {
00375         setIntraWordEditing( false );
00376         d->completeRehighlightRequired = true;
00377         d->rehighlightRequest->setInterval(500);
00378                 d->rehighlightRequest->setSingleShot(true);
00379                 d->rehighlightRequest->start();
00380         }
00381 #if 0
00382         if (d->checksDone != d->checksRequested) {
00383         // Handle possible change of paragraph while
00384         // words are pending spell checking
00385         d->completeRehighlightRequired = true;
00386         d->rehighlightRequest->start( 500, true );
00387         }
00388 #endif
00389     } else {
00390         setIntraWordEditing( true );
00391     }
00392     if ( k->key() == Qt::Key_Space ||
00393          k->key() == Qt::Key_Enter ||
00394          k->key() == Qt::Key_Return ) {
00395         QTimer::singleShot( 0, this, SLOT( slotAutoDetection() ));
00396     }
00397     }
00398 
00399     else if ( o == d->edit->viewport() &&
00400               ( e->type() == QEvent::MouseButtonPress )) {
00401     //d->autoReady = true;
00402     if ( intraWordEditing() ) {
00403         setIntraWordEditing( false );
00404         d->completeRehighlightRequired = true;
00405         d->rehighlightRequest->setInterval(0);
00406             d->rehighlightRequest->setSingleShot(true);
00407             d->rehighlightRequest->start();
00408     }
00409     }
00410     return false;
00411 }
00412 
00413 void Highlighter::addWordToDictionary(const QString &word)
00414 {
00415     d->dict->addToPersonal(word);
00416 }
00417 
00418 void Highlighter::ignoreWord(const QString &word)
00419 {
00420     d->dict->addToSession(word);
00421 }
00422 
00423 QStringList Highlighter::suggestionsForWord(const QString &word, int max)
00424 {
00425     QStringList suggestions = d->dict->suggest(word);
00426     if ( max != -1 ) {
00427         while ( suggestions.count() > max )
00428             suggestions.removeLast();
00429     }
00430     return suggestions;
00431 }
00432 
00433 bool Highlighter::isWordMisspelled(const QString &word)
00434 {
00435     return d->dict->isMisspelled(word);
00436 }
00437 
00438 void Highlighter::setMisspelledColor(const QColor &color)
00439 {
00440     d->spellColor = color;
00441 }
00442 
00443 bool Highlighter::checkerEnabledByDefault() const
00444 {
00445     return d->loader->settings()->checkerEnabledByDefault();
00446 }
00447 
00448 
00449 }

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal