• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 API Reference
  • 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; //cached d->dict->isValid() value
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->spellColor = _col.isValid() ? _col : Qt::red;
00091     d->suggestionListeners = 0;
00092 
00093     textEdit->installEventFilter( this );
00094     textEdit->viewport()->installEventFilter( this );
00095 
00096     d->loader = Loader::openLoader();
00097 
00098     //Do not load an empty settings file as it will cause the spellchecker to fail
00099     //if the KGlobal::locale()->language() (default value) spellchecker is not installed,
00100     //and we have a global sonnetrc file with a spellcheck lang installed which could be used.
00101     if (!configFile.isEmpty()) {
00102         KConfig conf(configFile);
00103         if (conf.hasGroup("Spelling")) {
00104             d->loader->settings()->restore(&conf);
00105             d->filter->setSettings(d->loader->settings());
00106         }
00107     }
00108 
00109     d->dict = new Sonnet::Speller();
00110     d->spellCheckerFound = d->dict->isValid();
00111     d->rehighlightRequest = new QTimer(this);
00112     connect( d->rehighlightRequest, SIGNAL(timeout()),
00113              this, SLOT(slotRehighlight()));
00114 
00115     if(!d->spellCheckerFound)
00116         return;
00117 
00118     d->dictCache.insert(d->dict->language(), d->dict);
00119 
00120     d->disablePercentage = d->loader->settings()->disablePercentageWordError();
00121     d->disableWordCount = d->loader->settings()->disableWordErrorCount();
00122 
00123     //Add kde personal word
00124     const QStringList l = Highlighter::personalWords();
00125     for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) {
00126         d->dict->addToSession( *it );
00127     }
00128     d->completeRehighlightRequired = true;
00129     d->rehighlightRequest->setInterval(0);
00130     d->rehighlightRequest->setSingleShot(true);
00131     d->rehighlightRequest->start();
00132 }
00133 
00134 Highlighter::~Highlighter()
00135 {
00136     delete d;
00137 }
00138 
00139 bool Highlighter::spellCheckerFound() const
00140 {
00141     return d->spellCheckerFound;
00142 }
00143 
00144 // Since figuring out spell correction suggestions is extremely costly,
00145 // we keep track of whether the user actually wants some, and only offer them
00146 // in that case
00147 void Highlighter::connectNotify(const char* signal)
00148 {
00149     if (QLatin1String(signal) == SIGNAL(newSuggestions(QString,QStringList)))
00150         ++d->suggestionListeners;
00151     QSyntaxHighlighter::connectNotify(signal);
00152 }
00153 
00154 void Highlighter::disconnectNotify(const char* signal)
00155 {
00156     if (QLatin1String(signal) == SIGNAL(newSuggestions(QString,QStringList)))
00157         --d->suggestionListeners;
00158     QSyntaxHighlighter::disconnectNotify(signal);
00159 }
00160 
00161 void Highlighter::slotRehighlight()
00162 {
00163     kDebug(0) << "Highlighter::slotRehighlight()";
00164     if (d->completeRehighlightRequired) {
00165         d->wordCount  = 0;
00166         d->errorCount = 0;
00167         rehighlight();
00168 
00169     } else {
00170     //rehighlight the current para only (undo/redo safe)
00171         QTextCursor cursor = d->edit->textCursor();
00172         cursor.insertText( "" );
00173     }
00174     //if (d->checksDone == d->checksRequested)
00175     //d->completeRehighlightRequired = false;
00176     QTimer::singleShot( 0, this, SLOT(slotAutoDetection()));
00177 }
00178 
00179 
00180 QStringList Highlighter::personalWords()
00181 {
00182     QStringList l;
00183     l.append( "KMail" );
00184     l.append( "KOrganizer" );
00185     l.append( "KAddressBook" );
00186     l.append( "KHTML" );
00187     l.append( "KIO" );
00188     l.append( "KJS" );
00189     l.append( "Konqueror" );
00190     l.append( "Sonnet" );
00191     l.append( "Kontact" );
00192     l.append( "Qt" );
00193     return l;
00194 }
00195 
00196 bool Highlighter::automatic() const
00197 {
00198     return d->automatic;
00199 }
00200 
00201 bool Highlighter::intraWordEditing() const
00202 {
00203     return d->intraWordEditing;
00204 }
00205 
00206 void Highlighter::setIntraWordEditing( bool editing )
00207 {
00208     d->intraWordEditing = editing;
00209 }
00210 
00211 
00212 void Highlighter::setAutomatic( bool automatic )
00213 {
00214     if ( automatic  == d->automatic )
00215         return;
00216 
00217     d->automatic = automatic;
00218     if ( d->automatic )
00219         slotAutoDetection();
00220 }
00221 
00222 void Highlighter::slotAutoDetection()
00223 {
00224     bool savedActive = d->active;
00225 
00226     //don't disable just because 1 of 4 is misspelled.
00227     if (d->automatic && d->wordCount >= 10) {
00228         // tme = Too many errors
00229         bool tme = (d->errorCount >= d->disableWordCount) && (
00230             d->errorCount * 100 >= d->disablePercentage * d->wordCount);
00231         if (d->active && tme) {
00232             d->active = false;
00233         } else if (!d->active && !tme) {
00234             d->active = true;
00235         }
00236     }
00237 
00238     if (d->active != savedActive) {
00239         if (d->active) {
00240             emit activeChanged(i18n("As-you-type spell checking enabled."));
00241         } else {
00242             emit activeChanged(i18n( "Too many misspelled words. "
00243                                "As-you-type spell checking disabled."));
00244         }
00245 
00246         d->completeRehighlightRequired = true;
00247         d->rehighlightRequest->setInterval(100);
00248         d->rehighlightRequest->setSingleShot(true);
00249         kDebug()<<" Highlighter::slotAutoDetection :"<<d->active;
00250     }
00251 
00252 }
00253 
00254 void Highlighter::setActive( bool active )
00255 {
00256     if ( active == d->active )
00257         return;
00258     d->active = active;
00259     rehighlight();
00260 
00261 
00262     if ( d->active )
00263         emit activeChanged( i18n("As-you-type spell checking enabled.") );
00264     else
00265         emit activeChanged( i18n("As-you-type spell checking disabled.") );
00266 }
00267 
00268 bool Highlighter::isActive() const
00269 {
00270     return d->active;
00271 }
00272 
00273 void Highlighter::highlightBlock(const QString &text)
00274 {
00275     if (text.isEmpty() || !d->active || !d->spellCheckerFound)
00276         return;
00277 
00278     d->filter->setBuffer( text );
00279     Word w = d->filter->nextWord();
00280     while ( !w.end ) {
00281         ++d->wordCount;
00282         if (d->dict->isMisspelled(w.word)) {
00283             ++d->errorCount;
00284             setMisspelled(w.start, w.word.length());
00285             if (d->suggestionListeners)
00286                 emit newSuggestions(w.word, d->dict->suggest(w.word));
00287         } else
00288             unsetMisspelled(w.start, w.word.length());
00289         w = d->filter->nextWord();
00290     }
00291     //QTimer::singleShot( 0, this, SLOT(checkWords()) );
00292     setCurrentBlockState(0);
00293 }
00294 
00295 QString Highlighter::currentLanguage() const
00296 {
00297     return d->dict->language();
00298 }
00299 
00300 void Highlighter::setCurrentLanguage(const QString &lang)
00301 {
00302     if (!d->dictCache.contains(lang)) {
00303         d->dict = new Speller(*d->dict);
00304         d->dict->setLanguage(lang);
00305         if (d->dict->isValid()) {
00306             d->dictCache.insert(lang, d->dict);
00307         } else {
00308             d->spellCheckerFound = false;
00309             kDebug()<<"No dictionary for \""
00310                     <<lang
00311                     <<"\" staying with the current language."
00312                     <<endl;
00313             return;
00314         }
00315     }
00316     d->dict = d->dictCache[lang];
00317     d->spellCheckerFound = d->dict->isValid();
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 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed May 2 2012 17:56:39 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

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

kdelibs-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal