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

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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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