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

KDECore

filter.cpp

Go to the documentation of this file.
00001 // -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*-
00024 #include "filter_p.h"
00025 
00026 #include "settings_p.h"
00027 
00028 #include <kglobal.h>
00029 #include <kdebug.h>
00030 
00031 namespace Sonnet
00032 {
00033 
00034 static Word endWord;
00035 
00036 class Filter::Private
00037 {
00038 public:
00039     // The reason it's not in the class directly is that
00040     // I'm not 100% sure that having the settings() here is
00041     // the way i want to be doing this.
00042     Settings *settings;
00043 };
00044 
00045 Filter* Filter::defaultFilter()
00046 {
00047     return new Filter();
00048 }
00049 
00050 Word Filter::end()
00051 {
00052     return endWord;
00053 }
00054 
00055 Filter::Filter()
00056     : d(new Private)
00057 {
00058     d->settings = 0;
00059 }
00060 
00061 Filter::~Filter()
00062 {
00063     delete d;
00064 }
00065 
00066 void Filter::setSettings( Settings *conf )
00067 {
00068     d->settings = conf;
00069 }
00070 
00071 Settings *Filter::settings() const
00072 {
00073     return d->settings;
00074 }
00075 
00076 void Filter::restart()
00077 {
00078     m_finder.toStart();
00079 }
00080 
00081 void Filter::setBuffer( const QString& buffer )
00082 {
00083     m_buffer = buffer;
00084     m_finder = QTextBoundaryFinder(QTextBoundaryFinder::Word, m_buffer);
00085 }
00086 
00087 QString Filter::buffer() const
00088 {
00089     return m_buffer;
00090 }
00091 
00092 bool Filter::atEnd() const
00093 {
00094     return m_finder.position() >= m_buffer.length() || m_finder.position() < 0;
00095 }
00096 
00097 // we don't want to spell check empty words, or single-char words of the form
00098 // '<', '=', etc.
00099 static bool
00100 isValidWord(const QString &str)
00101 {
00102     if(str.isEmpty() || (str.length() == 1 && !str[0].isLetter())) {
00103       return false;
00104     }
00105     const int length = str.length();
00106     for(int i = 0; i < length; ++i) {
00107       if(!str[i].isNumber()) {
00108         return true;
00109       }
00110     }
00111     // 'str' only contains numbers
00112     return false;
00113 }
00114 
00115 static bool
00116 finderNextWord(QTextBoundaryFinder &finder, QString &word, int &bufferStart)
00117 {
00118     QTextBoundaryFinder::BoundaryReasons boundary = finder.boundaryReasons();
00119     int start = finder.position(), end = finder.position();
00120     bool inWord = (boundary & QTextBoundaryFinder::StartWord) != 0;
00121     while (finder.toNextBoundary() > 0) {
00122         boundary = finder.boundaryReasons();
00123         if ((boundary & QTextBoundaryFinder::EndWord) && inWord) {
00124             end = finder.position();
00125             QString str = finder.string().mid(start, end - start);
00126             if (isValidWord(str)) {
00127                 word = str;
00128                 bufferStart = start;
00129 #if 0
00130                 kDebug() << "Word at " << start << " word = '"
00131                          <<  str << "', len = " << str.length();
00132 #endif
00133                 return true;
00134             }
00135             inWord = false;
00136         }
00137         if ((boundary & QTextBoundaryFinder::StartWord)) {
00138             start = finder.position();
00139             inWord = true;
00140         }
00141     }
00142     return false;
00143 }
00144 
00145 static bool finderWordAt(QTextBoundaryFinder &finder,
00146                          int at,
00147                          QString &word, int &bufferStart)
00148 {
00149     int oldPosition = finder.position();
00150 
00151     finder.setPosition(at);
00152     if (!finder.isAtBoundary() || (finder.boundaryReasons() & QTextBoundaryFinder::EndWord)) {
00153         if (finder.toPreviousBoundary() <= 0) {
00154             /* QTextBoundaryIterator doesn't consider start of the string
00155              * a boundary so we need to rewind to the beginning to catch
00156              * the first word */
00157             if (at > 0 && finder.string().length() > 0) {
00158                 finder.toStart();
00159             } else
00160                 return false;
00161         }
00162     }
00163     bool ret = finderNextWord(finder, word, bufferStart);
00164     finder.setPosition(oldPosition);
00165     return ret;
00166 }
00167 
00168 Word Filter::nextWord() const
00169 {
00170     QString foundWord;
00171     int start;
00172     bool allUppercase = false;
00173     bool runTogether = false;
00174 
00175     if (!finderNextWord(m_finder, foundWord, start))
00176         return Filter::end();
00177 
00178     allUppercase = ( foundWord == foundWord.toUpper() );
00179 
00180     //TODO implement runtogether correctly.
00181     //We must ask to sonnet plugins to do it and not directly here.
00182 
00183     if ( shouldBeSkipped( allUppercase, runTogether, foundWord ) )
00184         return nextWord();
00185     return Word( foundWord, start );
00186 }
00187 
00188 Word Filter::wordAtPosition( unsigned int pos ) const
00189 {
00190     QString foundWord;
00191     int start;
00192     if (!finderWordAt(m_finder, pos, foundWord, start))
00193         return Filter::end();
00194     return Word( foundWord, start );
00195 }
00196 
00197 
00198 void Filter::setCurrentPosition( int i )
00199 {
00200     QString word;
00201     int pos;
00202 
00203     //to make sure we're at an reasonable word boundary
00204     if (!finderWordAt(m_finder, i, word, pos)) {
00205         return;
00206     }
00207     m_finder.setPosition(pos);
00208 }
00209 
00210 int Filter::currentPosition() const
00211 {
00212     return m_finder.position();
00213 }
00214 
00215 void Filter::replace( const Word& w, const QString& newWord)
00216 {
00217     int oldLen = w.word.length();
00218 
00219     //start spell checkin from the just correct word
00220     m_buffer = m_buffer.replace( w.start, oldLen, newWord );
00221     m_finder = QTextBoundaryFinder(QTextBoundaryFinder::Word,
00222                                      m_buffer);
00223     m_finder.setPosition(w.start);
00224 }
00225 
00226 QString Filter::context() const
00227 {
00228     int len = 60;
00229     //we don't want the expression underneath casted to an unsigned int
00230     //which would cause it to always evaluate to false
00231     int signedPosition = m_finder.position();
00232     bool begin = (signedPosition - len/2)<=0;
00233 
00234 
00235     QString buffer = m_buffer;
00236     Word word = wordAtPosition( m_finder.position() );
00237     buffer = buffer.replace( word.start, word.word.length(),
00238                              QString::fromLatin1( "<b>%1</b>" ).arg( word.word ) );
00239 
00240     QString context;
00241     if ( begin )
00242         context = QString::fromLatin1("%1...")
00243                   .arg( buffer.mid(  0, len ) );
00244     else
00245         context = QString::fromLatin1("...%1...")
00246                   .arg( buffer.mid(  m_finder.position() - 20, len ) );
00247 
00248     context.replace( QLatin1Char('\n'), QLatin1Char(' ') );
00249 
00250     return context;
00251 }
00252 
00253 bool Filter::trySkipLinks() const
00254 {
00255     QChar currentChar;
00256     int currentPosition = m_finder.position();
00257 
00258     if (currentPosition < 0 || currentPosition >= m_buffer.length())
00259         return false;
00260     currentChar = m_buffer.at( currentPosition );
00261 
00262     int length = m_buffer.length();
00263     //URL - if so skip
00264     if ( currentChar == QLatin1Char(':')
00265          && (currentPosition+1 < length)
00266          && (m_buffer.at( ++currentPosition ) == QLatin1Char('/') || ( currentPosition + 1 ) >= length ) ) {
00267         //in both cases url is considered finished at the first whitespace occurrence
00268         //TODO hey, "http://en.wikipedia.org/wiki/Main Page" --Nick Shaforostoff
00269         while ( !m_buffer.at( currentPosition++ ).isSpace() && currentPosition < length )
00270             ;
00271         m_finder.setPosition(currentPosition);
00272         return true;
00273     }
00274 
00275     //Email - if so skip
00276     if ( currentChar == QLatin1Char('@')) {
00277         while ( ++currentPosition < length && !m_buffer.at( currentPosition ).isSpace() )
00278             ;
00279         m_finder.setPosition(currentPosition);
00280         return true;
00281     }
00282 
00283     return false;
00284 }
00285 
00286 bool Filter::ignore( const QString& word ) const
00287 {
00288     return d->settings && d->settings->ignore( word );
00289 }
00290 
00291 bool Filter::shouldBeSkipped( bool wordWasUppercase, bool wordWasRunTogether,
00292                              const QString& foundWord ) const
00293 {
00294     bool checkUpper = ( d->settings ) ?
00295                       d->settings->checkUppercase () : true;
00296 
00297     bool skipRunTogether = ( d->settings ) ?
00298                            d->settings->skipRunTogether() : true;
00299 
00300     if ( trySkipLinks() )
00301         return true;
00302 
00303     if ( wordWasUppercase && !checkUpper )
00304         return true;
00305 
00306     if ( wordWasRunTogether && skipRunTogether )
00307         return true;
00308 
00309     return ignore( foundWord );
00310 }
00311 
00312 }

KDECore

Skip menu "KDECore"
  • 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