libkdepim
kscoring.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef KDE_USE_FINAL
00018 #undef QT_NO_ASCII_CAST
00019 #endif
00020
00021 #undef QT_NO_COMPAT
00022
00023 #include "kscoring.h"
00024 #include "kscoringeditor.h"
00025
00026 #include <KDebug>
00027 #include <KLocale>
00028 #include <KInputDialog>
00029 #include <KStandardDirs>
00030 #include <KTextEdit>
00031
00032 #include <QCheckBox>
00033 #include <QDomElement>
00034 #include <QDomDocument>
00035 #include <QDomNode>
00036 #include <QDomNodeList>
00037 #include <QFile>
00038 #include <QLayout>
00039 #include <QLabel>
00040 #include <QTextStream>
00041 #include <QVBoxLayout>
00042 #include <Q3PtrList>
00043
00044 #include <iostream>
00045
00046 using namespace KPIM;
00047
00048
00049
00050 static QString toXml( const QString &str )
00051 {
00052 QString tmp(str);
00053 uint len = tmp.length();
00054 uint i = 0;
00055 while ( i < len ) {
00056 if ( tmp[(int)i] == '<' ) {
00057 tmp.replace( i, 1, "<" );
00058 len += 3;
00059 i += 4;
00060 } else if ( tmp[(int)i] == '"' ) {
00061 tmp.replace( i, 1, """ );
00062 len += 5;
00063 i += 6;
00064 } else if ( tmp[(int)i] == '&' ) {
00065 tmp.replace( i, 1, "&" );
00066 len += 4;
00067 i += 5;
00068 } else if ( tmp[(int)i] == '>' ) {
00069 tmp.replace( i, 1, ">" );
00070 len += 3;
00071 i += 4;
00072 } else {
00073 ++i;
00074 }
00075 }
00076
00077 return tmp;
00078 }
00079
00080
00081 NotifyDialog *NotifyDialog::me = 0;
00082 NotifyDialog::NotesMap NotifyDialog::dict;
00083
00084 NotifyDialog::NotifyDialog( QWidget *parent )
00085 : KDialog( parent )
00086 {
00087 setCaption( i18n( "Notify Message" ) );
00088 setButtons( Close );
00089 setDefaultButton( Close );
00090 setModal( true );
00091
00092 QFrame *f = new QFrame( this );
00093 setMainWidget ( f );
00094 QVBoxLayout *topL = new QVBoxLayout( f );
00095 note = new QLabel( f );
00096 note->setTextFormat( Qt::RichText );
00097 topL->addWidget( note );
00098 QCheckBox *check = new QCheckBox( i18n( "Do not show this message again" ), f );
00099 check->setChecked( true );
00100 topL->addWidget( check );
00101 connect( check, SIGNAL(toggled(bool)), SLOT(slotShowAgainToggled(bool)) );
00102 }
00103
00104 void NotifyDialog::slotShowAgainToggled( bool flag )
00105 {
00106 dict.remove( msg );
00107 dict.insert( msg, !flag );
00108 kDebug(5100) <<"note \"" << note <<"\" will popup again:" << flag;
00109 }
00110
00111 void NotifyDialog::display( ScorableArticle &a, const QString &s )
00112 {
00113 kDebug(5100) <<"displaying message";
00114 if ( !me ) {
00115 me = new NotifyDialog();
00116 }
00117 me->msg = s;
00118
00119 NotesMap::Iterator i = dict.find( s );
00120 if ( i == dict.end() || i.value() ) {
00121 QString msg =
00122 i18n( "Article\n<b>%1</b><br /><b>%2</b><br />caused the following note to appear:<br />%3",
00123 a.from(),
00124 a.subject(),
00125 s );
00126 me->note->setText(msg);
00127 if ( i == dict.end() ) {
00128 dict.remove( s );
00129 i = dict.insert( s, false );
00130 }
00131 me->adjustSize();
00132 me->exec();
00133 }
00134 }
00135
00136
00137 ScorableArticle::~ScorableArticle()
00138 {
00139 }
00140
00141 void ScorableArticle::displayMessage( const QString ¬e )
00142 {
00143 NotifyDialog::display( *this, note );
00144 }
00145
00146
00147 ScorableGroup::~ScorableGroup()
00148 {
00149 }
00150
00151
00152 ActionBase::ActionBase()
00153 {
00154 kDebug(5100) <<"new Action" << this;
00155 }
00156
00157 ActionBase::~ActionBase()
00158 {
00159 kDebug(5100) <<"delete Action" << this;
00160 }
00161
00162 QStringList ActionBase::userNames()
00163 {
00164 QStringList l;
00165 l << userName( SETSCORE );
00166 l << userName( NOTIFY );
00167 l << userName( COLOR );
00168 l << userName( MARKASREAD );
00169 return l;
00170 }
00171
00172 ActionBase *ActionBase::factory( int type, const QString &value )
00173 {
00174 switch( type ) {
00175 case SETSCORE:
00176 return new ActionSetScore( value );
00177 case NOTIFY:
00178 return new ActionNotify( value );
00179 case COLOR:
00180 return new ActionColor( value );
00181 case MARKASREAD:
00182 return new ActionMarkAsRead();
00183 default:
00184 kWarning(5100) <<"unknown type" << type <<" in ActionBase::factory()";
00185 return 0;
00186 }
00187 }
00188
00189 QString ActionBase::userName( int type )
00190 {
00191 switch( type ) {
00192 case SETSCORE:
00193 return i18n( "Adjust Score" );
00194 case NOTIFY:
00195 return i18n( "Display Message" );
00196 case COLOR:
00197 return i18n( "Colorize Header" );
00198 case MARKASREAD:
00199 return i18n( "Mark As Read" );
00200 default:
00201 kWarning(5100) <<"unknown type" << type <<" in ActionBase::userName()";
00202 return 0;
00203 }
00204 }
00205
00206 int ActionBase::getTypeForName( const QString &name )
00207 {
00208 if ( name == "SETSCORE" ) {
00209 return SETSCORE;
00210 } else if ( name == "NOTIFY" ) {
00211 return NOTIFY;
00212 } else if ( name == "COLOR" ) {
00213 return COLOR;
00214 } else if ( name == "MARKASREAD" ) {
00215 return MARKASREAD;
00216 } else {
00217 kWarning(5100) <<"unknown type string" << name
00218 << "in ActionBase::getTypeForName()";
00219 return -1;
00220 }
00221 }
00222
00223 int ActionBase::getTypeForUserName( const QString &name )
00224 {
00225 if ( name == userName( SETSCORE ) ) {
00226 return SETSCORE;
00227 } else if ( name == userName( NOTIFY ) ) {
00228 return NOTIFY;
00229 } else if ( name == userName( COLOR ) ) {
00230 return COLOR;
00231 } else if ( name == userName( MARKASREAD ) ) {
00232 return MARKASREAD;
00233 } else {
00234 kWarning(5100) <<"unknown type string" << name
00235 << "in ActionBase::getTypeForUserName()";
00236 return -1;
00237 }
00238 }
00239
00240
00241 ActionSetScore::ActionSetScore( short v )
00242 : val( v )
00243 {
00244 }
00245
00246 ActionSetScore::ActionSetScore( const QString &s )
00247 {
00248 val = s.toShort();
00249 }
00250
00251 ActionSetScore::ActionSetScore( const ActionSetScore &as )
00252 : ActionBase(),
00253 val( as.val )
00254 {
00255 }
00256
00257 ActionSetScore::~ActionSetScore()
00258 {
00259 }
00260
00261 QString ActionSetScore::toString() const
00262 {
00263 QString a;
00264 a += "<Action type=\"SETSCORE\" value=\"" + QString::number(val) + "\" />";
00265 return a;
00266 }
00267
00268 void ActionSetScore::apply( ScorableArticle &a ) const
00269 {
00270 a.addScore( val );
00271 }
00272
00273 ActionSetScore *ActionSetScore::clone() const
00274 {
00275 return new ActionSetScore( *this );
00276 }
00277
00278
00279 ActionColor::ActionColor( const QColor &c )
00280 : ActionBase(), color( c )
00281 {
00282 }
00283
00284 ActionColor::ActionColor( const QString &s )
00285 : ActionBase()
00286 {
00287 setValue(s);
00288 }
00289
00290 ActionColor::ActionColor( const ActionColor &a )
00291 : ActionBase(), color( a.color )
00292 {
00293 }
00294
00295 ActionColor::~ActionColor()
00296 {}
00297
00298 QString ActionColor::toString() const
00299 {
00300 QString a;
00301 a += "<Action type=\"COLOR\" value=\"" + toXml(color.name()) + "\" />";
00302 return a;
00303 }
00304
00305 void ActionColor::apply( ScorableArticle &a ) const
00306 {
00307 a.changeColor( color );
00308 }
00309
00310 ActionColor *ActionColor::clone() const
00311 {
00312 return new ActionColor( *this );
00313 }
00314
00315
00316 ActionNotify::ActionNotify( const QString &s )
00317 {
00318 note = s;
00319 }
00320
00321 ActionNotify::ActionNotify( const ActionNotify &an )
00322 : ActionBase()
00323 {
00324 note = an.note;
00325 }
00326
00327 QString ActionNotify::toString() const
00328 {
00329 return "<Action type=\"NOTIFY\" value=\"" + toXml(note) + "\" />";
00330 }
00331
00332 void ActionNotify::apply( ScorableArticle &a ) const
00333 {
00334 a.displayMessage( note );
00335 }
00336
00337 ActionNotify *ActionNotify::clone() const
00338 {
00339 return new ActionNotify( *this );
00340 }
00341
00342
00343 ActionMarkAsRead::ActionMarkAsRead() :
00344 ActionBase()
00345 {
00346 }
00347
00348 ActionMarkAsRead::ActionMarkAsRead( const ActionMarkAsRead &action ) :
00349 ActionBase()
00350 {
00351 Q_UNUSED( action );
00352 }
00353
00354 QString ActionMarkAsRead::toString() const
00355 {
00356 return "<Action type=\"MARKASREAD\"/>";
00357 }
00358
00359 void ActionMarkAsRead::apply( ScorableArticle &article ) const
00360 {
00361 article.markAsRead();
00362 }
00363
00364 ActionMarkAsRead *ActionMarkAsRead::clone() const
00365 {
00366 return new ActionMarkAsRead( *this );
00367 }
00368
00369
00370 NotifyCollection::NotifyCollection()
00371 {
00372 notifyList.setAutoDelete( true );
00373 }
00374
00375 NotifyCollection::~NotifyCollection()
00376 {
00377 }
00378
00379 void NotifyCollection::addNote( const ScorableArticle &a, const QString ¬e )
00380 {
00381 article_list *l = notifyList.find( note );
00382 if ( !l ) {
00383 notifyList.insert( note, new article_list );
00384 l = notifyList.find( note );
00385 }
00386 article_info i;
00387 i.from = a.from();
00388 i.subject = a.subject();
00389 l->append(i);
00390 }
00391
00392 QString NotifyCollection::collection() const
00393 {
00394 QString notifyCollection = i18n( "<h1>List of collected notes</h1>" );
00395 notifyCollection += "<p><ul>";
00396
00397 Q3DictIterator<article_list> it(notifyList);
00398 for ( ; it.current(); ++it ) {
00399 const QString ¬e = it.currentKey();
00400 notifyCollection += "<li>" + note + "<ul>";
00401 article_list *alist = it.current();
00402 article_list::Iterator ait;
00403 for ( ait = alist->begin(); ait != alist->end(); ++ait ) {
00404 notifyCollection += "<li><b>From: </b>" + (*ait).from + "<br>";
00405 notifyCollection += "<b>Subject: </b>" + (*ait).subject;
00406 }
00407 notifyCollection += "</ul>";
00408 }
00409 notifyCollection += "</ul>";
00410
00411 return notifyCollection;
00412 }
00413
00414 void NotifyCollection::displayCollection( QWidget *p ) const
00415 {
00416
00417 KDialog *dlg = new KDialog( p );
00418 dlg->setCaption( i18n( "Collected Notes" ) );
00419 dlg->setButtons( KDialog::Close );
00420 dlg->setDefaultButton( KDialog::Close );
00421 dlg->setModal( false );
00422 KTextEdit *text = new KTextEdit( dlg );
00423 text->setReadOnly( true );
00424 text->setText( collection() );
00425 dlg->setMainWidget( text );
00426 dlg->setMinimumWidth( 300 );
00427 dlg->setMinimumHeight( 300 );
00428 dlg->show();
00429 }
00430
00431
00432 KScoringExpression::KScoringExpression( const QString &h, const QString &t,
00433 const QString &n, const QString &ng )
00434 : header( h ), expr_str( n )
00435 {
00436 if ( t == "MATCH" ) {
00437 cond = MATCH;
00438 expr.setPattern( expr_str );
00439 expr.setCaseSensitivity( Qt::CaseInsensitive );
00440 } else if ( t == "MATCHCS" ) {
00441 cond = MATCHCS;
00442 expr.setPattern( expr_str );
00443 expr.setCaseSensitivity( Qt::CaseSensitive );
00444 } else if ( t == "CONTAINS" ) {
00445 cond = CONTAINS;
00446 } else if ( t == "EQUALS" ) {
00447 cond = EQUALS;
00448 } else if ( t == "GREATER" ) {
00449 cond = GREATER;
00450 expr_int = expr_str.toInt();
00451 } else if ( t == "SMALLER" ) {
00452 cond = SMALLER;
00453 expr_int = expr_str.toInt();
00454 } else {
00455 kDebug(5100) <<"unknown match type in new expression";
00456 }
00457
00458 neg = ng.toInt();
00459 c_header = header.toLatin1();
00460
00461 kDebug(5100) <<"new expr:" << c_header << t
00462 << expr_str << neg;
00463 }
00464
00465
00466 int KScoringExpression::getConditionForName( const QString &s )
00467 {
00468 if ( s == getNameForCondition( CONTAINS ) ) {
00469 return CONTAINS;
00470 } else if ( s == getNameForCondition( MATCH ) ) {
00471 return MATCH;
00472 } else if ( s == getNameForCondition( MATCHCS ) ) {
00473 return MATCHCS;
00474 } else if ( s == getNameForCondition( EQUALS ) ) {
00475 return EQUALS;
00476 } else if ( s == getNameForCondition( SMALLER ) ) {
00477 return SMALLER;
00478 } else if ( s == getNameForCondition( GREATER ) ) {
00479 return GREATER;
00480 } else {
00481 kWarning(5100) <<"unknown condition name" << s
00482 << "in KScoringExpression::getConditionForName()";
00483 return -1;
00484 }
00485 }
00486
00487
00488 QString KScoringExpression::getNameForCondition( int cond )
00489 {
00490 switch ( cond ) {
00491 case CONTAINS:
00492 return i18n( "Contains Substring" );
00493 case MATCH:
00494 return i18n( "Matches Regular Expression" );
00495 case MATCHCS:
00496 return i18n( "Matches Regular Expression (Case Sensitive)" );
00497 case EQUALS:
00498 return i18n( "Is Exactly the Same As" );
00499 case SMALLER:
00500 return i18n( "Less Than" );
00501 case GREATER:
00502 return i18n( "Greater Than" );
00503 default:
00504 kWarning(5100) <<"unknown condition" << cond
00505 << "in KScoringExpression::getNameForCondition()";
00506 return "";
00507 }
00508 }
00509
00510
00511 QStringList KScoringExpression::conditionNames()
00512 {
00513 QStringList l;
00514 l << getNameForCondition( CONTAINS );
00515 l << getNameForCondition( MATCH );
00516 l << getNameForCondition( MATCHCS );
00517 l << getNameForCondition( EQUALS );
00518 l << getNameForCondition( SMALLER );
00519 l << getNameForCondition( GREATER );
00520 return l;
00521 }
00522
00523
00524 QStringList KScoringExpression::headerNames()
00525 {
00526 QStringList l;
00527 l.append( "From" );
00528 l.append( "Message-ID" );
00529 l.append( "Subject" );
00530 l.append( "Date" );
00531 l.append( "References" );
00532 l.append( "NNTP-Posting-Host" );
00533 l.append( "Bytes" );
00534 l.append( "Lines" );
00535 l.append( "Xref" );
00536 return l;
00537 }
00538
00539 KScoringExpression::~KScoringExpression()
00540 {
00541 }
00542
00543 bool KScoringExpression::match( ScorableArticle &a ) const
00544 {
00545 bool res = true;
00546 QString head;
00547
00548 if ( header == "From" ) {
00549 head = a.from();
00550 } else if ( header == "Subject" ) {
00551 head = a.subject();
00552 } else {
00553 head = a.getHeaderByType(c_header);
00554 }
00555
00556 if ( !head.isEmpty() ) {
00557 switch( cond ) {
00558 case EQUALS:
00559 res = ( head.toLower() == expr_str.toLower() );
00560 break;
00561 case CONTAINS:
00562 res = ( head.toLower().indexOf( expr_str.toLower() ) >= 0 );
00563 break;
00564 case MATCH:
00565 case MATCHCS:
00566 res = ( expr.indexIn( head ) != -1 );
00567 break;
00568 case GREATER:
00569 res = ( head.toInt() > expr_int );
00570 break;
00571 case SMALLER:
00572 res = ( head.toInt() < expr_int );
00573 break;
00574 default:
00575 kDebug(5100) <<"unknown match";
00576 res = false;
00577 }
00578 } else {
00579 res = false;
00580 }
00581
00582 return neg ? !res : res;
00583 }
00584
00585 void KScoringExpression::write( QTextStream &st ) const
00586 {
00587 st << toString();
00588 }
00589
00590 QString KScoringExpression::toString() const
00591 {
00592 QString e;
00593 e += "<Expression neg=\"" + QString::number( neg ? 1 : 0 ) +
00594 "\" header=\"" + header +
00595 "\" type=\"" + getTypeString() +
00596 "\" expr=\"" + toXml(expr_str) +
00597 "\" />";
00598
00599 return e;
00600 }
00601
00602 QString KScoringExpression::getTypeString() const
00603 {
00604 return KScoringExpression::getTypeString(cond);
00605 }
00606
00607 QString KScoringExpression::getTypeString( int cond )
00608 {
00609 switch( cond ) {
00610 case CONTAINS:
00611 return "CONTAINS";
00612 case MATCH:
00613 return "MATCH";
00614 case MATCHCS:
00615 return "MATCHCS";
00616 case EQUALS:
00617 return "EQUALS";
00618 case SMALLER:
00619 return "SMALLER";
00620 case GREATER:
00621 return "GREATER";
00622 default:
00623 kWarning(5100) <<"unknown cond" << cond
00624 <<" in KScoringExpression::getTypeString()";
00625 return "";
00626 }
00627 }
00628
00629 int KScoringExpression::getType() const
00630 {
00631 return cond;
00632 }
00633
00634
00635 KScoringRule::KScoringRule( const QString &n )
00636 : name( n ), link( AND )
00637 {
00638 expressions.setAutoDelete( true );
00639 actions.setAutoDelete( true );
00640 }
00641
00642 KScoringRule::KScoringRule( const KScoringRule &r )
00643 {
00644 kDebug(5100) <<"copying rule" << r.getName();
00645 name = r.getName();
00646 expressions.setAutoDelete( true );
00647 actions.setAutoDelete( true );
00648
00649 expressions.clear();
00650 const ScoreExprList &rexpr = r.expressions;
00651 Q3PtrListIterator<KScoringExpression> it( rexpr );
00652 for ( ; it.current(); ++it ) {
00653 KScoringExpression *t = new KScoringExpression( **it );
00654 expressions.append( t );
00655 }
00656
00657 actions.clear();
00658 const ActionList &ract = r.actions;
00659 Q3PtrListIterator<ActionBase> ait( ract );
00660 for ( ; ait.current(); ++ait ) {
00661 ActionBase *t = *ait;
00662 actions.append( t->clone() );
00663 }
00664
00665 groups = r.groups;
00666 expires = r.expires;
00667 link = r.link;
00668 }
00669
00670 KScoringRule::~KScoringRule()
00671 {
00672 cleanExpressions();
00673 cleanActions();
00674 }
00675
00676 void KScoringRule::cleanExpressions()
00677 {
00678
00679 expressions.clear();
00680 }
00681
00682 void KScoringRule::cleanActions()
00683 {
00684
00685 actions.clear();
00686 }
00687
00688 void KScoringRule::addExpression( KScoringExpression *expr )
00689 {
00690 kDebug(5100) <<"KScoringRule::addExpression";
00691 expressions.append(expr);
00692 }
00693
00694 void KScoringRule::addAction( int type, const QString &val )
00695 {
00696 ActionBase *action = ActionBase::factory( type, val );
00697 addAction( action );
00698 }
00699
00700 void KScoringRule::addAction( ActionBase *a )
00701 {
00702 kDebug(5100) <<"KScoringRule::addAction()" << a->toString();
00703 actions.append(a);
00704 }
00705
00706 void KScoringRule::setLinkMode( const QString &l )
00707 {
00708 if ( l == "OR" ) {
00709 link = OR;
00710 } else {
00711 link = AND;
00712 }
00713 }
00714
00715 void KScoringRule::setExpire( const QString &e )
00716 {
00717 if ( e != "never" ) {
00718 QStringList l = e.split( '-', QString::SkipEmptyParts );
00719 Q_ASSERT( l.count() == 3 );
00720 expires.setYMD( l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt() );
00721 }
00722 kDebug(5100) <<"Rule" << getName() <<" expires at" << getExpireDateString();
00723 }
00724
00725 bool KScoringRule::matchGroup( const QString &group ) const
00726 {
00727 for ( GroupList::ConstIterator i = groups.begin(); i != groups.end(); ++i ) {
00728 QRegExp e( *i );
00729 if ( e.indexIn( group, 0 ) != -1 && e.matchedLength() == group.length() ) {
00730 return true;
00731 }
00732 }
00733 return false;
00734 }
00735
00736 void KScoringRule::applyAction( ScorableArticle &a ) const
00737 {
00738 Q3PtrListIterator<ActionBase> it( actions );
00739 for ( ; it.current(); ++it ) {
00740 it.current()->apply( a );
00741 }
00742 }
00743
00744 void KScoringRule::applyRule( ScorableArticle &a ) const
00745 {
00746 bool oper_and = ( link == AND );
00747 bool res = true;
00748 Q3PtrListIterator<KScoringExpression> it( expressions );
00749
00750 for ( ; it.current(); ++it ) {
00751 Q_ASSERT( it.current() );
00752 res = it.current()->match( a );
00753 if ( !res && oper_and ) {
00754 return;
00755 } else if ( res && !oper_and ) {
00756 break;
00757 }
00758 }
00759 if ( res ) {
00760 applyAction( a );
00761 }
00762 }
00763
00764 void KScoringRule::applyRule( ScorableArticle &a, const QString &g ) const
00765 {
00766
00767 for ( QStringList::ConstIterator i = groups.begin(); i != groups.end(); ++i ) {
00768 if ( QRegExp( *i ).indexIn( g ) != -1 ) {
00769 applyRule( a );
00770 return;
00771 }
00772 }
00773 }
00774
00775 void KScoringRule::write( QTextStream &s ) const
00776 {
00777 s << toString();
00778 }
00779
00780 QString KScoringRule::toString() const
00781 {
00782 QString r;
00783 r += "<Rule name=\"" + toXml(name) + "\" linkmode=\"" + getLinkModeName();
00784 r += "\" expires=\"" + getExpireDateString() + "\">";
00785
00786 for ( GroupList::ConstIterator i = groups.begin(); i != groups.end(); ++i ) {
00787 r += "<Group name=\"" + toXml(*i) + "\" />";
00788 }
00789
00790 Q3PtrListIterator<KScoringExpression> eit(expressions);
00791 for ( ; eit.current(); ++eit ) {
00792 r += eit.current()->toString();
00793 }
00794
00795 Q3PtrListIterator<ActionBase> ait(actions);
00796 for ( ; ait.current(); ++ait ) {
00797 r += ait.current()->toString();
00798 }
00799 r += "</Rule>";
00800 return r;
00801 }
00802
00803 QString KScoringRule::getLinkModeName() const
00804 {
00805 switch( link ) {
00806 case AND:
00807 return "AND";
00808 case OR:
00809 return "OR";
00810 default:
00811 return "AND";
00812 }
00813 }
00814
00815 QString KScoringRule::getExpireDateString() const
00816 {
00817 if ( expires.isNull() ) {
00818 return "never";
00819 } else {
00820 return
00821 QString::number( expires.year() ) + QString( '-' ) +
00822 QString::number( expires.month() ) + QString( '-' ) +
00823 QString::number( expires.day() );
00824 }
00825 }
00826
00827 bool KScoringRule::isExpired() const
00828 {
00829 return
00830 expires.isValid() &&
00831 ( expires < QDate::currentDate() );
00832 }
00833
00834
00835 KScoringManager::KScoringManager( const QString &appName )
00836 : cacheValid( false )
00837 {
00838 allRules.setAutoDelete( true );
00839
00840 if ( appName.isEmpty() ) {
00841 mFilename = KGlobal::dirs()->saveLocation( "appdata" ) + "/scorefile";
00842 } else {
00843 mFilename = KGlobal::dirs()->saveLocation( "data" ) + '/' + appName + "/scorefile";
00844 }
00845
00846 load();
00847 }
00848
00849 KScoringManager::~KScoringManager()
00850 {
00851 }
00852
00853 void KScoringManager::load()
00854 {
00855 QDomDocument sdoc( "Scorefile" );
00856 QFile f( mFilename );
00857 if ( !f.open( QIODevice::ReadOnly ) ) {
00858 return;
00859 }
00860 if ( !sdoc.setContent( &f ) ) {
00861 f.close();
00862 kDebug(5100) <<"loading the scorefile failed";
00863 return;
00864 }
00865 f.close();
00866 kDebug(5100) <<"loaded the scorefile, creating internal representation";
00867 allRules.clear();
00868 createInternalFromXML( sdoc );
00869 expireRules();
00870 kDebug(5100) <<"ready, got" << allRules.count() <<" rules";
00871 }
00872
00873 void KScoringManager::save()
00874 {
00875 kDebug(5100) <<"KScoringManager::save() starts";
00876 QFile f( mFilename );
00877 if ( !f.open( QIODevice::WriteOnly ) ) {
00878 return;
00879 }
00880 QTextStream stream( &f );
00881 stream.setCodec( "UTF-8" );
00882 kDebug(5100) <<"KScoringManager::save() creating xml";
00883 createXMLfromInternal().save( stream, 2 );
00884 kDebug(5100) <<"KScoringManager::save() finished";
00885 }
00886
00887 QDomDocument KScoringManager::createXMLfromInternal()
00888 {
00889
00890
00891 QDomDocument sdoc( "Scorefile" );
00892 QString ss;
00893 ss += "<?xml version = '1.0'?><!DOCTYPE Scorefile >";
00894 ss += toString();
00895 ss += "</Scorefile>\n";
00896 kDebug(5100) <<"KScoringManager::createXMLfromInternal():" << endl << ss;
00897 sdoc.setContent(ss);
00898 return sdoc;
00899 }
00900
00901 QString KScoringManager::toString() const
00902 {
00903 QString s;
00904 s += "<Scorefile>\n";
00905 Q3PtrListIterator<KScoringRule> it( allRules );
00906 for ( ; it.current(); ++it ) {
00907 s += it.current()->toString();
00908 }
00909 return s;
00910 }
00911
00912 void KScoringManager::expireRules()
00913 {
00914 for ( KScoringRule *cR = allRules.first(); cR; cR=allRules.next() ) {
00915 if ( cR->isExpired() ) {
00916 kDebug(5100) <<"Rule" << cR->getName() <<" is expired, deleting it";
00917 allRules.remove();
00918 }
00919 }
00920 }
00921
00922 void KScoringManager::createInternalFromXML( QDomNode n )
00923 {
00924 static KScoringRule *cR = 0;
00925
00926 if ( !n.isNull() ) {
00927 kDebug(5100) <<"inspecting node of type" << n.nodeType()
00928 << "named" << n.toElement().tagName();
00929
00930 switch ( n.nodeType() ) {
00931 case QDomNode::DocumentNode:
00932 {
00933
00934 break;
00935 }
00936 case QDomNode::ElementNode:
00937 {
00938
00939 QDomElement e = n.toElement();
00940 QString s = e.tagName();
00941 if ( s == "Rule" ) {
00942 cR = new KScoringRule( e.attribute( "name" ) );
00943 cR->setLinkMode( e.attribute( "linkmode" ) );
00944 cR->setExpire( e.attribute( "expires" ) );
00945 addRuleInternal( cR );
00946 } else if ( s == "Group" ) {
00947 Q_CHECK_PTR( cR );
00948 cR->addGroup( e.attribute( "name" ) );
00949 } else if ( s == "Expression" ) {
00950 cR->addExpression( new KScoringExpression( e.attribute( "header" ),
00951 e.attribute( "type" ),
00952 e.attribute( "expr" ),
00953 e.attribute( "neg" ) ) );
00954 } else if ( s == "Action" ) {