summaryrefslogtreecommitdiffstats
path: root/tdespell2/filter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdespell2/filter.cpp')
-rw-r--r--tdespell2/filter.cpp309
1 files changed, 309 insertions, 0 deletions
diff --git a/tdespell2/filter.cpp b/tdespell2/filter.cpp
new file mode 100644
index 000000000..1604bcae1
--- /dev/null
+++ b/tdespell2/filter.cpp
@@ -0,0 +1,309 @@
+// -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+/*
+ * filter.cpp
+ *
+ * Copyright (C) 2004 Zack Rusin <zack@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include "filter.h"
+
+#include "settings.h"
+
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+
+#include <tqstring.h>
+
+namespace KSpell2
+{
+
+static Word endWord;
+static KStaticDeleter<Filter> sd;
+static Filter* defFilter = 0;
+
+class Filter::Private
+{
+public:
+ // The reason it's not in the class directly is that
+ // i'm not 100% sure that having the settings() here is
+ // the way i want to be doing this.
+ Settings *settings;
+};
+
+Filter* Filter::defaultFilter()
+{
+ if ( !defFilter )
+ sd.setObject( defFilter, new Filter() );
+ return defFilter;
+}
+
+Word Filter::end()
+{
+ return endWord;
+}
+
+Filter::Filter()
+ : m_currentPosition( 0 )
+{
+ d = new Private;
+ d->settings = 0;
+}
+
+Filter::~Filter()
+{
+ delete d; d = 0;
+}
+
+void Filter::setSettings( Settings *conf )
+{
+ d->settings = conf;
+}
+
+Settings *Filter::settings() const
+{
+ return d->settings;
+}
+
+void Filter::restart()
+{
+ m_currentPosition = 0;
+}
+
+void Filter::setBuffer( const TQString& buffer )
+{
+ m_buffer = buffer;
+ m_currentPosition = 0;
+}
+
+TQString Filter::buffer() const
+{
+ return m_buffer;
+}
+
+bool Filter::atEnd() const
+{
+ if ( m_currentPosition >= m_buffer.length() ) {
+ return true;
+ } else
+ return false;
+}
+
+Word Filter::nextWord() const
+{
+ TQChar currentChar = skipToLetter( m_currentPosition );
+
+ if ( m_currentPosition >= m_buffer.length() ) {
+ return Filter::end();
+ }
+
+ bool allUppercase = currentChar.category() & TQChar::Letter_Uppercase;
+ bool runTogether = false;
+
+ TQString foundWord;
+ int start = m_currentPosition;
+ while ( currentChar.isLetter() ) {
+ if ( currentChar.category() & TQChar::Letter_Lowercase )
+ allUppercase = false;
+
+ /* FIXME: this does not work for Hebrew for example
+ //we consider run-together words as mixed-case words
+ if ( !allUppercase &&
+ currentChar.category() & TQChar::Letter_Uppercase )
+ runTogether = true;
+ */
+
+ foundWord += currentChar;
+ ++m_currentPosition;
+ currentChar = m_buffer[ m_currentPosition ];
+ }
+
+ if ( shouldBeSkipped( allUppercase, runTogether, foundWord ) )
+ return nextWord();
+
+ return Word( foundWord, start );
+}
+
+Word Filter::previousWord() const
+{
+ while ( !m_buffer[ m_currentPosition ].isLetter() &&
+ m_currentPosition != 0) {
+ --m_currentPosition;
+ }
+
+ if ( m_currentPosition == 0 ) {
+ return Filter::end();
+ }
+
+ TQString foundWord;
+ int start = m_currentPosition;
+ while ( m_buffer[ start ].isLetter() ) {
+ foundWord.prepend( m_buffer[ m_currentPosition ] );
+ --start;
+ }
+
+ return Word( foundWord, start );
+}
+
+Word Filter::wordAtPosition( unsigned int pos ) const
+{
+ if ( pos > m_buffer.length() )
+ return Filter::end();
+
+ int currentPosition = pos - 1;
+ TQString foundWord;
+ while ( currentPosition >= 0 &&
+ m_buffer[ currentPosition ].isLetter() ) {
+ foundWord.prepend( m_buffer[ currentPosition ] );
+ --currentPosition;
+ }
+
+ // currentPosition == 0 means the first char is not letter
+ // currentPosition == -1 means we reached the beginning
+ int start = (currentPosition < 0) ? 0 : ++currentPosition;
+ currentPosition = pos ;
+ if ( m_buffer[ currentPosition ].isLetter() ) {
+ while ( m_buffer[ currentPosition ].isLetter() ) {
+ foundWord.append( m_buffer[ currentPosition ] );
+ ++currentPosition;
+ }
+ }
+
+ return Word( foundWord, start );
+}
+
+
+void Filter::setCurrentPosition( int i )
+{
+ m_currentPosition = i;
+
+ //go back to the last word so that next word returns something
+ //useful
+ while ( m_buffer[m_currentPosition].isLetter() && m_currentPosition > 0 )
+ --m_currentPosition;
+}
+
+int Filter::currentPosition() const
+{
+ return m_currentPosition;
+}
+
+void Filter::replace( const Word& w, const TQString& newWord)
+{
+ int oldLen = w.word.length();
+ int newLen = newWord.length();
+
+ if ( oldLen != newLen && m_currentPosition > w.start ) {
+ if ( m_currentPosition > w.start ) {
+ int len = newLen - oldLen;
+ m_currentPosition += len;
+ }
+ }
+ m_buffer = m_buffer.replace( w.start, oldLen, newWord );
+}
+
+TQString Filter::context() const
+{
+ int len = 60;
+ //we don't want the expression underneath casted to an unsigned int
+ //which would cause it to always evaluate to false
+ int signedPosition = m_currentPosition;
+ bool begin = ( (signedPosition - len/2)<=0 ) ? true : false;
+
+
+ TQString buffer = m_buffer;
+ Word word = wordAtPosition( m_currentPosition );
+ buffer = buffer.replace( word.start, word.word.length(),
+ TQString( "<b>%1</b>" ).arg( word.word ) );
+
+ TQString context;
+ if ( begin )
+ context = TQString( "%1...")
+ .arg( buffer.mid( 0, len ) );
+ else
+ context = TQString( "...%1..." )
+ .arg( buffer.mid( m_currentPosition - 20, len ) );
+
+ context = context.replace( '\n', ' ' );
+
+ return context;
+}
+
+bool Filter::trySkipLinks() const
+{
+ TQChar currentChar = m_buffer[ m_currentPosition ];
+
+ uint length = m_buffer.length();
+ //URL - if so skip
+ if ( currentChar == ':' &&
+ ( m_buffer[ ++m_currentPosition] == '/' || ( m_currentPosition + 1 ) >= length ) ) {
+ //in both cases url is considered finished at the first whitespace occurence
+ while ( !m_buffer[ m_currentPosition++ ].isSpace() && m_currentPosition < length )
+ ;
+ return true;
+ }
+
+ //Email - if so skip
+ if ( currentChar == '@' ) {
+ while ( !m_buffer[ ++m_currentPosition ].isSpace() && m_currentPosition < length )
+ ;
+ return true;
+ }
+
+ return false;
+}
+
+bool Filter::ignore( const TQString& word ) const
+{
+ if ( d->settings ) {
+ return d->settings->ignore( word );
+ }
+ return false;
+}
+
+TQChar Filter::skipToLetter( uint &fromPosition ) const
+{
+
+ TQChar currentChar = m_buffer[ fromPosition ];
+ while ( !currentChar.isLetter() &&
+ ++fromPosition < m_buffer.length() ) {
+ currentChar = m_buffer[ fromPosition ];
+ }
+ return currentChar;
+}
+
+bool Filter::shouldBeSkipped( bool wordWasUppercase, bool wordWasRunTogether,
+ const TQString& foundWord ) const
+{
+ bool checkUpper = ( d->settings ) ?
+ d->settings->checkUppercase () : true;
+ bool skipRunTogether = ( d->settings ) ?
+ d->settings->skipRunTogether() : true;
+
+ if ( trySkipLinks() )
+ return true;
+
+ if ( wordWasUppercase && !checkUpper )
+ return true;
+
+ if ( wordWasRunTogether && skipRunTogether )
+ return true;
+
+ return ignore( foundWord );
+}
+
+}