/* kscoring.cpp Copyright (c) 2001 Mathias Waack Copyright (C) 2005 by Volker Krause Author: Mathias Waack This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #ifdef KDE_USE_FINAL #undef QT_NO_ASCII_CAST #endif #undef QT_NO_COMPAT #include "kscoring.h" #include "kscoringeditor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KPIM; //---------------------------------------------------------------------------- // a small function to encode attribute values, code stolen from QDom static QString toXml( const QString &str ) { QString tmp(str); uint len = tmp.length(); uint i = 0; while ( i < len ) { if ( tmp[(int)i] == '<' ) { tmp.replace( i, 1, "<" ); len += 3; i += 4; } else if ( tmp[(int)i] == '"' ) { tmp.replace( i, 1, """ ); len += 5; i += 6; } else if ( tmp[(int)i] == '&' ) { tmp.replace( i, 1, "&" ); len += 4; i += 5; } else if ( tmp[(int)i] == '>' ) { tmp.replace( i, 1, ">" ); len += 3; i += 4; } else { ++i; } } return tmp; } // small dialog to display the messages from NotifyAction NotifyDialog *NotifyDialog::me = 0; NotifyDialog::NotesMap NotifyDialog::dict; NotifyDialog::NotifyDialog( QWidget *parent ) : KDialog( parent ) { setCaption( i18n( "Notify Message" ) ); setButtons( Close ); setDefaultButton( Close ); setModal( true ); QFrame *f = new QFrame( this ); setMainWidget ( f ); QVBoxLayout *topL = new QVBoxLayout( f ); note = new QLabel( f ); note->setTextFormat( Qt::RichText ); topL->addWidget( note ); QCheckBox *check = new QCheckBox( i18n( "Do not show this message again" ), f ); check->setChecked( true ); topL->addWidget( check ); connect( check, SIGNAL(toggled(bool)), SLOT(slotShowAgainToggled(bool)) ); } void NotifyDialog::slotShowAgainToggled( bool flag ) { dict.remove( msg ); dict.insert( msg, !flag ); kDebug(5100) <<"note \"" << note <<"\" will popup again:" << flag; } void NotifyDialog::display( ScorableArticle &a, const QString &s ) { kDebug(5100) <<"displaying message"; if ( !me ) { me = new NotifyDialog(); } me->msg = s; NotesMap::Iterator i = dict.find( s ); if ( i == dict.end() || i.value() ) { QString msg = i18n( "Article\n%1
%2
caused the following note to appear:
%3", a.from(), a.subject(), s ); me->note->setText(msg); if ( i == dict.end() ) { dict.remove( s ); i = dict.insert( s, false ); } me->adjustSize(); me->exec(); } } //---------------------------------------------------------------------------- ScorableArticle::~ScorableArticle() { } void ScorableArticle::displayMessage( const QString ¬e ) { NotifyDialog::display( *this, note ); } //---------------------------------------------------------------------------- ScorableGroup::~ScorableGroup() { } // the base class for all actions ActionBase::ActionBase() { kDebug(5100) <<"new Action" << this; } ActionBase::~ActionBase() { kDebug(5100) <<"delete Action" << this; } QStringList ActionBase::userNames() { QStringList l; l << userName( SETSCORE ); l << userName( NOTIFY ); l << userName( COLOR ); l << userName( MARKASREAD ); return l; } ActionBase *ActionBase::factory( int type, const QString &value ) { switch( type ) { case SETSCORE: return new ActionSetScore( value ); case NOTIFY: return new ActionNotify( value ); case COLOR: return new ActionColor( value ); case MARKASREAD: return new ActionMarkAsRead(); default: kWarning(5100) <<"unknown type" << type <<" in ActionBase::factory()"; return 0; } } QString ActionBase::userName( int type ) { switch( type ) { case SETSCORE: return i18n( "Adjust Score" ); case NOTIFY: return i18n( "Display Message" ); case COLOR: return i18n( "Colorize Header" ); case MARKASREAD: return i18n( "Mark as Read" ); default: kWarning(5100) <<"unknown type" << type <<" in ActionBase::userName()"; return 0; } } int ActionBase::getTypeForName( const QString &name ) { if ( name == "SETSCORE" ) { return SETSCORE; } else if ( name == "NOTIFY" ) { return NOTIFY; } else if ( name == "COLOR" ) { return COLOR; } else if ( name == "MARKASREAD" ) { return MARKASREAD; } else { kWarning(5100) <<"unknown type string" << name << "in ActionBase::getTypeForName()"; return -1; } } int ActionBase::getTypeForUserName( const QString &name ) { if ( name == userName( SETSCORE ) ) { return SETSCORE; } else if ( name == userName( NOTIFY ) ) { return NOTIFY; } else if ( name == userName( COLOR ) ) { return COLOR; } else if ( name == userName( MARKASREAD ) ) { return MARKASREAD; } else { kWarning(5100) <<"unknown type string" << name << "in ActionBase::getTypeForUserName()"; return -1; } } // the set score action ActionSetScore::ActionSetScore( short v ) : val( v ) { } ActionSetScore::ActionSetScore( const QString &s ) { val = s.toShort(); } ActionSetScore::ActionSetScore( const ActionSetScore &as ) : ActionBase(), val( as.val ) { } ActionSetScore::~ActionSetScore() { } QString ActionSetScore::toString() const { QString a; a += ""; return a; } void ActionSetScore::apply( ScorableArticle &a ) const { a.addScore( val ); } ActionSetScore *ActionSetScore::clone() const { return new ActionSetScore( *this ); } // the color action ActionColor::ActionColor( const QColor &c ) : ActionBase(), color( c ) { } ActionColor::ActionColor( const QString &s ) : ActionBase() { setValue(s); } ActionColor::ActionColor( const ActionColor &a ) : ActionBase(), color( a.color ) { } ActionColor::~ActionColor() {} QString ActionColor::toString() const { QString a; a += ""; return a; } void ActionColor::apply( ScorableArticle &a ) const { a.changeColor( color ); } ActionColor *ActionColor::clone() const { return new ActionColor( *this ); } // the notify action ActionNotify::ActionNotify( const QString &s ) { note = s; } ActionNotify::ActionNotify( const ActionNotify &an ) : ActionBase() { note = an.note; } QString ActionNotify::toString() const { return ""; } void ActionNotify::apply( ScorableArticle &a ) const { a.displayMessage( note ); } ActionNotify *ActionNotify::clone() const { return new ActionNotify( *this ); } // mark as read action ActionMarkAsRead::ActionMarkAsRead() : ActionBase() { } ActionMarkAsRead::ActionMarkAsRead( const ActionMarkAsRead &action ) : ActionBase() { Q_UNUSED( action ); } QString ActionMarkAsRead::toString() const { return ""; } void ActionMarkAsRead::apply( ScorableArticle &article ) const { article.markAsRead(); } ActionMarkAsRead *ActionMarkAsRead::clone() const { return new ActionMarkAsRead( *this ); } //---------------------------------------------------------------------------- NotifyCollection::NotifyCollection() { notifyList.setAutoDelete( true ); } NotifyCollection::~NotifyCollection() { } void NotifyCollection::addNote( const ScorableArticle &a, const QString ¬e ) { article_list *l = notifyList.find( note ); if ( !l ) { notifyList.insert( note, new article_list ); l = notifyList.find( note ); } article_info i; i.from = a.from(); i.subject = a.subject(); l->append(i); } QString NotifyCollection::collection() const { QString notifyCollection = i18n( "

List of collected notes

" ); notifyCollection += "

    "; // first look thru the notes and create one string Q3DictIterator it(notifyList); for ( ; it.current(); ++it ) { const QString ¬e = it.currentKey(); notifyCollection += "
  • " + note + "
      "; article_list *alist = it.current(); article_list::Iterator ait; for ( ait = alist->begin(); ait != alist->end(); ++ait ) { notifyCollection += "
    • From: " + (*ait).from + "
      "; notifyCollection += "Subject: " + (*ait).subject; } notifyCollection += "
    "; } notifyCollection += "
"; return notifyCollection; } void NotifyCollection::displayCollection( QWidget *p ) const { //KMessageBox::information(p,collection(),i18n("Collected Notes")); KDialog *dlg = new KDialog( p ); dlg->setCaption( i18n( "Collected Notes" ) ); dlg->setButtons( KDialog::Close ); dlg->setDefaultButton( KDialog::Close ); dlg->setModal( false ); KTextEdit *text = new KTextEdit( dlg ); text->setReadOnly( true ); text->setText( collection() ); dlg->setMainWidget( text ); dlg->setMinimumWidth( 300 ); dlg->setMinimumHeight( 300 ); dlg->show(); } //---------------------------------------------------------------------------- KScoringExpression::KScoringExpression( const QString &h, const QString &t, const QString &n, const QString &ng ) : header( h ), expr_str( n ) { if ( t == "MATCH" ) { cond = MATCH; expr.setPattern( expr_str ); expr.setCaseSensitivity( Qt::CaseInsensitive ); } else if ( t == "MATCHCS" ) { cond = MATCHCS; expr.setPattern( expr_str ); expr.setCaseSensitivity( Qt::CaseSensitive ); } else if ( t == "CONTAINS" ) { cond = CONTAINS; } else if ( t == "EQUALS" ) { cond = EQUALS; } else if ( t == "GREATER" ) { cond = GREATER; expr_int = expr_str.toInt(); } else if ( t == "SMALLER" ) { cond = SMALLER; expr_int = expr_str.toInt(); } else { kDebug(5100) <<"unknown match type in new expression"; } neg = ng.toInt(); kDebug(5100) <<"new expr:" << header << t << expr_str << neg; } // static int KScoringExpression::getConditionForName( const QString &s ) { if ( s == getNameForCondition( CONTAINS ) ) { return CONTAINS; } else if ( s == getNameForCondition( MATCH ) ) { return MATCH; } else if ( s == getNameForCondition( MATCHCS ) ) { return MATCHCS; } else if ( s == getNameForCondition( EQUALS ) ) { return EQUALS; } else if ( s == getNameForCondition( SMALLER ) ) { return SMALLER; } else if ( s == getNameForCondition( GREATER ) ) { return GREATER; } else { kWarning(5100) <<"unknown condition name" << s << "in KScoringExpression::getConditionForName()"; return -1; } } // static QString KScoringExpression::getNameForCondition( int cond ) { switch ( cond ) { case CONTAINS: return i18n( "Contains Substring" ); case MATCH: return i18n( "Matches Regular Expression" ); case MATCHCS: return i18n( "Matches Regular Expression (Case Sensitive)" ); case EQUALS: return i18n( "Is Exactly the Same As" ); case SMALLER: return i18n( "Less Than" ); case GREATER: return i18n( "Greater Than" ); default: kWarning(5100) <<"unknown condition" << cond << "in KScoringExpression::getNameForCondition()"; return ""; } } // static QStringList KScoringExpression::conditionNames() { QStringList l; l << getNameForCondition( CONTAINS ); l << getNameForCondition( MATCH ); l << getNameForCondition( MATCHCS ); l << getNameForCondition( EQUALS ); l << getNameForCondition( SMALLER ); l << getNameForCondition( GREATER ); return l; } // static QStringList KScoringExpression::headerNames() { QStringList l; l.append( "From" ); l.append( "Message-ID" ); l.append( "Subject" ); l.append( "Date" ); l.append( "References" ); l.append( "NNTP-Posting-Host" ); l.append( "Bytes" ); l.append( "Lines" ); l.append( "Xref" ); return l; } KScoringExpression::~KScoringExpression() { } bool KScoringExpression::match( ScorableArticle &a ) const { bool res = true; QString head; if ( header == "From" ) { head = a.from(); } else if ( header == "Subject" ) { head = a.subject(); } else { head = a.getHeaderByType( header ); } if ( !head.isEmpty() ) { switch( cond ) { case EQUALS: res = ( head.toLower() == expr_str.toLower() ); break; case CONTAINS: res = ( head.toLower().indexOf( expr_str.toLower() ) >= 0 ); break; case MATCH: case MATCHCS: res = ( expr.indexIn( head ) != -1 ); break; case GREATER: res = ( head.toInt() > expr_int ); break; case SMALLER: res = ( head.toInt() < expr_int ); break; default: kDebug(5100) <<"unknown match"; res = false; } } else { res = false; } return neg ? !res : res; } void KScoringExpression::write( QTextStream &st ) const { st << toString(); } QString KScoringExpression::toString() const { QString e; e += ""; return e; } QString KScoringExpression::getTypeString() const { return KScoringExpression::getTypeString(cond); } QString KScoringExpression::getTypeString( int cond ) { switch( cond ) { case CONTAINS: return "CONTAINS"; case MATCH: return "MATCH"; case MATCHCS: return "MATCHCS"; case EQUALS: return "EQUALS"; case SMALLER: return "SMALLER"; case GREATER: return "GREATER"; default: kWarning(5100) <<"unknown cond" << cond <<" in KScoringExpression::getTypeString()"; return ""; } } int KScoringExpression::getType() const { return cond; } //---------------------------------------------------------------------------- KScoringRule::KScoringRule( const QString &n ) : name( n ), link( AND ) { expressions.setAutoDelete( true ); actions.setAutoDelete( true ); } KScoringRule::KScoringRule( const KScoringRule &r ) { kDebug(5100) <<"copying rule" << r.getName(); name = r.getName(); expressions.setAutoDelete( true ); actions.setAutoDelete( true ); // copy expressions expressions.clear(); const ScoreExprList &rexpr = r.expressions; Q3PtrListIterator it( rexpr ); for ( ; it.current(); ++it ) { KScoringExpression *t = new KScoringExpression( **it ); expressions.append( t ); } // copy actions actions.clear(); const ActionList &ract = r.actions; Q3PtrListIterator ait( ract ); for ( ; ait.current(); ++ait ) { ActionBase *t = *ait; actions.append( t->clone() ); } // copy groups, servers, linkmode and expires groups = r.groups; expires = r.expires; link = r.link; } KScoringRule::~KScoringRule() { cleanExpressions(); cleanActions(); } void KScoringRule::cleanExpressions() { // the expressions is setAutoDelete(true) expressions.clear(); } void KScoringRule::cleanActions() { // the actions is setAutoDelete(true) actions.clear(); } void KScoringRule::addExpression( KScoringExpression *expr ) { kDebug(5100) <<"KScoringRule::addExpression"; expressions.append(expr); } void KScoringRule::addAction( int type, const QString &val ) { ActionBase *action = ActionBase::factory( type, val ); addAction( action ); } void KScoringRule::addAction( ActionBase *a ) { kDebug(5100) <<"KScoringRule::addAction()" << a->toString(); actions.append(a); } void KScoringRule::setLinkMode( const QString &l ) { if ( l == "OR" ) { link = OR; } else { link = AND; } } void KScoringRule::setExpire( const QString &e ) { if ( e != "never" ) { QStringList l = e.split( '-', QString::SkipEmptyParts ); Q_ASSERT( l.count() == 3 ); expires.setYMD( l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt() ); } kDebug(5100) <<"Rule" << getName() <<" expires at" << getExpireDateString(); } bool KScoringRule::matchGroup( const QString &group ) const { for ( GroupList::ConstIterator i = groups.begin(); i != groups.end(); ++i ) { QRegExp e( *i ); if ( e.indexIn( group, 0 ) != -1 && e.matchedLength() == group.length() ) { return true; } } return false; } void KScoringRule::applyAction( ScorableArticle &a ) const { Q3PtrListIterator it( actions ); for ( ; it.current(); ++it ) { it.current()->apply( a ); } } void KScoringRule::applyRule( ScorableArticle &a ) const { bool oper_and = ( link == AND ); bool res = true; Q3PtrListIterator it( expressions ); for ( ; it.current(); ++it ) { Q_ASSERT( it.current() ); res = it.current()->match( a ); if ( !res && oper_and ) { return; } else if ( res && !oper_and ) { break; } } if ( res ) { applyAction( a ); } } void KScoringRule::applyRule( ScorableArticle &a, const QString &g ) const { // check if one of the groups match for ( QStringList::ConstIterator i = groups.begin(); i != groups.end(); ++i ) { if ( QRegExp( *i ).indexIn( g ) != -1 ) { applyRule( a ); return; } } } void KScoringRule::write( QTextStream &s ) const { s << toString(); } QString KScoringRule::toString() const { QString r; r += ""; for ( GroupList::ConstIterator i = groups.begin(); i != groups.end(); ++i ) { r += ""; } Q3PtrListIterator eit(expressions); for ( ; eit.current(); ++eit ) { r += eit.current()->toString(); } Q3PtrListIterator ait(actions); for ( ; ait.current(); ++ait ) { r += ait.current()->toString(); } r += ""; return r; } QString KScoringRule::getLinkModeName() const { switch( link ) { case AND: return "AND"; case OR: return "OR"; default: return "AND"; } } QString KScoringRule::getExpireDateString() const { if ( expires.isNull() ) { return "never"; } else { return QString::number( expires.year() ) + QString( '-' ) + QString::number( expires.month() ) + QString( '-' ) + QString::number( expires.day() ); } } bool KScoringRule::isExpired() const { return expires.isValid() && ( expires < QDate::currentDate() ); } //---------------------------------------------------------------------------- KScoringManager::KScoringManager( const QString &appName ) : cacheValid( false ) { allRules.setAutoDelete( true ); // determine filename of the scorefile if ( appName.isEmpty() ) { mFilename = KGlobal::dirs()->saveLocation( "appdata" ) + "/scorefile"; } else { mFilename = KGlobal::dirs()->saveLocation( "data" ) + '/' + appName + "/scorefile"; } // open the score file load(); } KScoringManager::~KScoringManager() { } void KScoringManager::load() { QDomDocument sdoc( "Scorefile" ); QFile f( mFilename ); if ( !f.open( QIODevice::ReadOnly ) ) { return; } if ( !sdoc.setContent( &f ) ) { f.close(); kDebug(5100) <<"loading the scorefile failed"; return; } f.close(); kDebug(5100) <<"loaded the scorefile, creating internal representation"; allRules.clear(); createInternalFromXML( sdoc ); expireRules(); kDebug(5100) <<"ready, got" << allRules.count() <<" rules"; } void KScoringManager::save() { kDebug(5100) <<"KScoringManager::save() starts"; QFile f( mFilename ); if ( !f.open( QIODevice::WriteOnly ) ) { return; } QTextStream stream( &f ); stream.setCodec( "UTF-8" ); kDebug(5100) <<"KScoringManager::save() creating xml"; createXMLfromInternal().save( stream, 2 ); kDebug(5100) <<"KScoringManager::save() finished"; } QDomDocument KScoringManager::createXMLfromInternal() { // I was'nt able to create a QDomDocument in memory:( // so I write the content into a string, which is really stupid QDomDocument sdoc( "Scorefile" ); QString ss; // scorestring ss += ""; ss += toString(); ss += "\n"; kDebug(5100) <<"KScoringManager::createXMLfromInternal():" << endl << ss; sdoc.setContent(ss); return sdoc; } QString KScoringManager::toString() const { QString s; s += "\n"; Q3PtrListIterator it( allRules ); for ( ; it.current(); ++it ) { s += it.current()->toString(); } return s; } void KScoringManager::expireRules() { for ( KScoringRule *cR = allRules.first(); cR; cR=allRules.next() ) { if ( cR->isExpired() ) { kDebug(5100) <<"Rule" << cR->getName() <<" is expired, deleting it"; allRules.remove(); } } } void KScoringManager::createInternalFromXML( QDomNode n ) { static KScoringRule *cR = 0; // the currentRule // the XML file was parsed and now we simply traverse the resulting tree if ( !n.isNull() ) { kDebug(5100) <<"inspecting node of type" << n.nodeType() << "named" << n.toElement().tagName(); switch ( n.nodeType() ) { case QDomNode::DocumentNode: { // the document itself break; } case QDomNode::ElementNode: { // Server, Newsgroup, Rule, Expression, Action QDomElement e = n.toElement(); QString s = e.tagName(); if ( s == "Rule" ) { cR = new KScoringRule( e.attribute( "name" ) ); cR->setLinkMode( e.attribute( "linkmode" ) ); cR->setExpire( e.attribute( "expires" ) ); addRuleInternal( cR ); } else if ( s == "Group" ) { Q_CHECK_PTR( cR ); cR->addGroup( e.attribute( "name" ) ); } else if ( s == "Expression" ) { cR->addExpression( new KScoringExpression( e.attribute( "header" ), e.attribute( "type" ), e.attribute( "expr" ), e.attribute( "neg" ) ) ); } else if ( s == "Action" ) { Q_CHECK_PTR( cR ); cR->addAction( ActionBase::getTypeForName( e.attribute( "type" ) ), e.attribute( "value" ) ); } break; } default: ; } QDomNodeList nodelist = n.childNodes(); int cnt = nodelist.count(); for ( int i=0; iaddGroup( group ); rule->addExpression( new KScoringExpression( "From","CONTAINS", a.from(), "0" ) ); if ( score ) { rule->addAction( new ActionSetScore( score ) ); } rule->setExpireDate( QDate::currentDate().addDays( 30 ) ); KScoringEditor *edit = KScoringEditor::createEditor( this ); // Note: the call to createEditor() call this->pushRuleList(). So addRule(KScoringRule) // must be place after it, otherwise the cancel button of the editor is not effective (bug #101092). addRule( rule ); edit->setRule( rule ); edit->show(); setCacheValid( false ); return rule; } KScoringRule *KScoringManager::addRule( KScoringRule *expr ) { int i = allRules.findRef( expr ); if ( i == -1 ) { // only add a rule we don't know addRuleInternal( expr ); } else { emit changedRules(); } return expr; } KScoringRule *KScoringManager::addRule() { KScoringRule *rule = new KScoringRule( findUniqueName() ); addRule( rule ); return rule; } void KScoringManager::addRuleInternal( KScoringRule *e ) { allRules.append( e ) ; setCacheValid( false ); emit changedRules(); kDebug(5100) <<"KScoringManager::addRuleInternal" << e->getName(); } void KScoringManager::cancelNewRule( KScoringRule *r ) { // if e was'nt previously added to the list of rules, we delete it int i = allRules.findRef( r ); if ( i == -1 ) { kDebug(5100) <<"deleting rule" << r->getName(); deleteRule( r ); } else { kDebug(5100) <<"rule" << r->getName() <<" not deleted"; } } void KScoringManager::setRuleName( KScoringRule *r, const QString &s ) { bool cont = true; QString text = s; QString oldName = r->getName(); while ( cont ) { cont = false; Q3PtrListIterator it( allRules ); for ( ; it.current(); ++it ) { if ( it.current() != r && it.current()->getName() == text ) { kDebug(5100) <<"rule name" << text <<" is not unique"; text = KInputDialog::getText( i18n( "Choose Another Rule Name" ), i18n( "The rule name is already assigned, please choose another name:" ), text ); cont = true; break; } } } if ( text != oldName ) { r->setName( text ); emit changedRuleName( oldName, text ); } } void KScoringManager::deleteRule( KScoringRule *r ) { int i = allRules.findRef( r ); if ( i != -1 ) { allRules.remove(); emit changedRules(); } } void KScoringManager::editRule( KScoringRule *e, QWidget *w ) { KScoringEditor *edit = KScoringEditor::createEditor( this, w ); edit->setRule( e ); edit->show(); delete edit; } void KScoringManager::moveRuleAbove( KScoringRule *above, KScoringRule *below ) { int aindex = allRules.findRef( above ); int bindex = allRules.findRef( below ); if ( aindex <= 0 || bindex < 0 ) { return; } if ( aindex < bindex ) { --bindex; } allRules.take( aindex ); allRules.insert( bindex, above ); } void KScoringManager::moveRuleBelow( KScoringRule *below, KScoringRule *above ) { int bindex = allRules.findRef( below ); int aindex = allRules.findRef( above ); if ( bindex < 0 || bindex >= (int)allRules.count() - 1 || aindex < 0 ) { return; } if ( bindex < aindex ) { --aindex; } allRules.take( bindex ); allRules.insert( aindex + 1, below ); } void KScoringManager::editorReady() { kDebug(5100) <<"emitting signal finishedEditing"; save(); emit finishedEditing(); } KScoringRule *KScoringManager::copyRule( KScoringRule *r ) { KScoringRule *rule = new KScoringRule( *r ); rule->setName( findUniqueName() ); addRuleInternal( rule ); return rule; } void KScoringManager::applyRules( ScorableGroup * ) { kWarning(5100) <<"KScoringManager::applyRules(ScorableGroup* ) isn't implemented"; } void KScoringManager::applyRules( ScorableArticle &article, const QString &group ) { setGroup( group ); applyRules( article ); } void KScoringManager::applyRules( ScorableArticle &a ) { Q3PtrListIterator it( isCacheValid() ? ruleList : allRules ); for ( ; it.current(); ++it ) { it.current()->applyRule( a ); } } void KScoringManager::initCache( const QString &g ) { group = g; ruleList.clear(); Q3PtrListIterator it(allRules); for ( ; it.current(); ++it ) { if ( it.current()->matchGroup( group ) ) { ruleList.append( it.current() ); } } kDebug(5100) <<"created cache for group" << group << "with" << ruleList.count() << "rules"; setCacheValid( true ); } void KScoringManager::setGroup( const QString &g ) { if ( group != g ) { initCache( g ); } } bool KScoringManager::hasRulesForCurrentGroup() { return ruleList.count() != 0; } QStringList KScoringManager::getRuleNames() { QStringList l; Q3PtrListIterator it( allRules ); for ( ; it.current(); ++it ) { l << it.current()->getName(); } return l; } KScoringRule *KScoringManager::findRule( const QString &ruleName ) { Q3PtrListIterator it( allRules ); for ( ; it.current(); ++it ) { if ( it.current()->getName() == ruleName ) { return it; } } return 0; } bool KScoringManager::setCacheValid( bool v ) { bool res = cacheValid; cacheValid = v; return res; } QString KScoringManager::findUniqueName() const { int nr = 0; QString ret; bool duplicated = false; while ( nr < 99999999 ) { nr++; ret = i18n( "rule %1", nr ); duplicated = false; Q3PtrListIterator it( allRules ); for ( ; it.current(); ++it ) { if ( it.current()->getName() == ret ) { duplicated = true; break; } } if ( !duplicated ) { return ret; } } return ret; } bool KScoringManager::hasFeature( int p ) { switch ( p ) { case ActionBase::SETSCORE: return canScores(); case ActionBase::NOTIFY: return canNotes(); case ActionBase::COLOR: return canColors(); case ActionBase::MARKASREAD: return canMarkAsRead(); default: return false; } } QStringList KScoringManager::getDefaultHeaders() const { QStringList l; l.append( "Subject" ); l.append( "From" ); l.append( "Date" ); l.append( "Message-ID" ); return l; } void KScoringManager::pushRuleList() { stack.push( allRules ); } void KScoringManager::popRuleList() { stack.pop( allRules ); } void KScoringManager::removeTOS() { stack.drop(); } RuleStack::RuleStack() { } RuleStack::~RuleStack() {} void RuleStack::push( Q3PtrList &l ) { kDebug(5100) <<"RuleStack::push pushing list with" << l.count() <<" rules"; KScoringManager::ScoringRuleList *l1 = new KScoringManager::ScoringRuleList; for ( KScoringRule *r=l.first(); r != 0; r=l.next() ) { l1->append( new KScoringRule( *r ) ); } stack.push( l1 ); kDebug(5100) <<"now there are" << stack.count() <<" lists on the stack"; } void RuleStack::pop( Q3PtrList &l ) { top( l ); drop(); kDebug(5100) <<"RuleStack::pop pops list with" << l.count() <<" rules"; kDebug(5100) <<"now there are" << stack.count() <<" lists on the stack"; } void RuleStack::top( Q3PtrList &l ) { l.clear(); KScoringManager::ScoringRuleList *l1 = stack.top(); l = *l1; } void RuleStack::drop() { kDebug(5100) <<"drop: now there are" << stack.count() <<" lists on the stack"; stack.remove(); }