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

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
  •   WTF
  • KJSEmbed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  •   core
  • Phonon
  •   Backend
  • 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