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

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