00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
#ifdef KDE_USE_FINAL
00017
#undef QT_NO_ASCII_CAST
00018
#endif
00019
00020
#undef QT_NO_COMPAT
00021
00022
#include <iostream>
00023
00024
#include <qfile.h>
00025
#include <qdom.h>
00026
#include <qlayout.h>
00027
#include <qlabel.h>
00028
#include <qcheckbox.h>
00029
#include <qtextview.h>
00030
00031
#include <klocale.h>
00032
#include <kstandarddirs.h>
00033
#include <kdebug.h>
00034
#include <kinputdialog.h>
00035
00036
#include "kscoring.h"
00037
#include "kscoringeditor.h"
00038
00039
00040
00041
00042
static QString toXml(
const QString& str)
00043 {
00044
QString tmp(str);
00045 uint len = tmp.length();
00046 uint i = 0;
00047
while ( i < len ) {
00048
if (tmp[(
int)i] ==
'<') {
00049 tmp.replace(i, 1,
"<");
00050 len += 3;
00051 i += 4;
00052 }
else if (tmp[(
int)i] ==
'"') {
00053 tmp.replace(i, 1,
""");
00054 len += 5;
00055 i += 6;
00056 }
else if (tmp[(
int)i] ==
'&') {
00057 tmp.replace(i, 1,
"&");
00058 len += 4;
00059 i += 5;
00060 }
else if (tmp[(
int)i] ==
'>') {
00061 tmp.replace(i, 1,
">");
00062 len += 3;
00063 i += 4;
00064 }
else {
00065 ++i;
00066 }
00067 }
00068
00069
return tmp;
00070 }
00071
00072
00073
00074 NotifyDialog* NotifyDialog::me = 0;
00075
NotifyDialog::NotesMap NotifyDialog::dict;
00076
00077 NotifyDialog::NotifyDialog(
QWidget* p)
00078 : KDialogBase(p,
"notify action dialog",true,
"Notify Message",Close,Close,true)
00079 {
00080
QFrame *f = makeMainWidget();
00081
QVBoxLayout *topL =
new QVBoxLayout(f);
00082 note =
new QLabel(f);
00083 note->setTextFormat(RichText);
00084 topL->addWidget(note);
00085
QCheckBox *check =
new QCheckBox(i18n(
"Do not show this message again"),f);
00086 check->setChecked(
true);
00087 topL->addWidget(check);
00088 connect(check,SIGNAL(toggled(
bool)),SLOT(slotShowAgainToggled(
bool)));
00089 }
00090
00091
void NotifyDialog::slotShowAgainToggled(
bool flag)
00092 {
00093 dict.replace(msg,!flag);
00094 kdDebug(5100) <<
"note \"" << note <<
"\" will popup again: " << flag << endl;
00095 }
00096
00097
void NotifyDialog::display(ScorableArticle& a,
const QString& s)
00098 {
00099 kdDebug(5100) <<
"displaying message" << endl;
00100
if (!me) me =
new NotifyDialog();
00101 me->msg = s;
00102
00103 NotesMap::Iterator i = dict.find(s);
00104
if (i == dict.end() || i.data()) {
00105
QString msg = i18n(
"Article\n<b>%1</b><br><b>%2</b><br>caused the following"
00106
" note to appear:<br>%3").
00107 arg(a.from()).
00108 arg(a.subject()).
00109 arg(s);
00110 me->note->setText(msg);
00111
if ( i == dict.end() ) i = dict.replace(s,
false);
00112 me->adjustSize();
00113 me->exec();
00114 }
00115 }
00116
00117
00118
00119 ScorableArticle::~ScorableArticle()
00120 {
00121 }
00122
00123
void ScorableArticle::displayMessage(
const QString& note)
00124 {
00125 NotifyDialog::display(*
this,note);
00126 }
00127
00128
00129 ScorableGroup::~ScorableGroup()
00130 {
00131 }
00132
00133
00134 ActionBase::ActionBase()
00135 {
00136 kdDebug(5100) <<
"new Action " <<
this << endl;
00137 }
00138
00139 ActionBase::~ActionBase()
00140 {
00141 kdDebug(5100) <<
"delete Action " <<
this << endl;
00142 }
00143
00144
00145
QStringList ActionBase::userNames()
00146 {
00147
QStringList l;
00148 l << userName(SETSCORE);
00149 l << userName(NOTIFY);
00150 l << userName(COLOR);
00151
return l;
00152 }
00153
00154
ActionBase* ActionBase::factory(
int type,
QString value)
00155 {
00156
switch (type) {
00157
case SETSCORE:
return new ActionSetScore(value);
00158
case NOTIFY:
return new ActionNotify(value);
00159
case COLOR:
return new ActionColor(value);
00160
default:
00161 kdWarning(5100) <<
"unknown type " << type <<
" in ActionBase::factory()" << endl;
00162
return 0;
00163 }
00164 }
00165
00166
QString ActionBase::userName(
int type)
00167 {
00168
switch (type) {
00169
case SETSCORE:
return i18n(
"Adjust Score");
00170
case NOTIFY:
return i18n(
"Display Message");
00171
case COLOR:
return i18n(
"Colorize Header");
00172
default:
00173 kdWarning(5100) <<
"unknown type " << type <<
" in ActionBase::userName()" << endl;
00174
return 0;
00175 }
00176 }
00177
00178
int ActionBase::getTypeForName(
const QString& name)
00179 {
00180
if (name ==
"SETSCORE")
return SETSCORE;
00181
else if (name ==
"NOTIFY")
return NOTIFY;
00182
else if (name ==
"COLOR")
return COLOR;
00183
else {
00184 kdWarning(5100) <<
"unknown type string " << name
00185 <<
" in ActionBase::getTypeForName()" << endl;
00186
return -1;
00187 }
00188 }
00189
00190
int ActionBase::getTypeForUserName(
const QString& name)
00191 {
00192
if (name == userName(SETSCORE))
return SETSCORE;
00193
else if (name == userName(NOTIFY))
return NOTIFY;
00194
else if (name == userName(COLOR))
return COLOR;
00195
else {
00196 kdWarning(5100) <<
"unknown type string " << name
00197 <<
" in ActionBase::getTypeForUserName()" << endl;
00198
return -1;
00199 }
00200 }
00201
00202
00203 ActionSetScore::ActionSetScore(
short v)
00204 : val(v)
00205 {
00206 }
00207
00208 ActionSetScore::ActionSetScore(
const QString& s)
00209 {
00210 val = s.toShort();
00211 }
00212
00213 ActionSetScore::ActionSetScore(
const ActionSetScore& as)
00214 :
ActionBase(),
00215 val(as.val)
00216 {
00217 }
00218
00219 ActionSetScore::~ActionSetScore()
00220 {
00221 }
00222
00223
QString ActionSetScore::toString()
const
00224
{
00225
QString a;
00226 a +=
"<Action type=\"SETSCORE\" value=\"" + QString::number(val) +
"\" />";
00227
return a;
00228 }
00229
00230
void ActionSetScore::apply(ScorableArticle& a)
const
00231
{
00232 a.addScore(val);
00233 }
00234
00235 ActionSetScore* ActionSetScore::clone()
const
00236
{
00237
return new ActionSetScore(*
this);
00238 }
00239
00240
00241 ActionColor::ActionColor(
const QColor& c)
00242 :
ActionBase(), color(c)
00243 {
00244 }
00245
00246 ActionColor::ActionColor(
const QString& s)
00247 :
ActionBase()
00248 {
00249 setValue(s);
00250 }
00251
00252 ActionColor::ActionColor(
const ActionColor& a)
00253 :
ActionBase(), color(a.color)
00254 {
00255 }
00256
00257 ActionColor::~ActionColor()
00258 {}
00259
00260
QString ActionColor::toString()
const
00261
{
00262
QString a;
00263 a +=
"<Action type=\"COLOR\" value=\"" + toXml(color.name()) +
"\" />";
00264
return a;
00265 }
00266
00267
void ActionColor::apply(ScorableArticle& a)
const
00268
{
00269 a.changeColor(color);
00270 }
00271
00272 ActionColor* ActionColor::clone()
const
00273
{
00274
return new ActionColor(*
this);
00275 }
00276
00277
00278
00279 ActionNotify::ActionNotify(
const QString& s)
00280 {
00281 note = s;
00282 }
00283
00284 ActionNotify::ActionNotify(
const ActionNotify& an)
00285 :
ActionBase()
00286 {
00287 note = an.note;
00288 }
00289
00290
QString ActionNotify::toString()
const
00291
{
00292
return "<Action type=\"NOTIFY\" value=\"" + toXml(note) +
"\" />";
00293 }
00294
00295
void ActionNotify::apply(ScorableArticle& a)
const
00296
{
00297 a.displayMessage(note);
00298 }
00299
00300 ActionNotify* ActionNotify::clone()
const
00301
{
00302
return new ActionNotify(*
this);
00303 }
00304
00305
00306
00307 NotifyCollection::NotifyCollection()
00308 {
00309 notifyList.setAutoDelete(
true);
00310 }
00311
00312 NotifyCollection::~NotifyCollection()
00313 {
00314 }
00315
00316
void NotifyCollection::addNote(
const ScorableArticle& a,
const QString& note)
00317 {
00318 article_list *l = notifyList.find(note);
00319
if (!l) {
00320 notifyList.insert(note,
new article_list);
00321 l = notifyList.find(note);
00322 }
00323 article_info i;
00324 i.from = a.from();
00325 i.subject = a.subject();
00326 l->append(i);
00327 }
00328
00329
QString NotifyCollection::collection()
const
00330
{
00331
QString notifyCollection = i18n(
"<h1>List of collected notes</h1>");
00332 notifyCollection +=
"<p><ul>";
00333
00334
QDictIterator<article_list> it(notifyList);
00335
for(;it.current();++it) {
00336
const QString& note = it.currentKey();
00337 notifyCollection +=
"<li>" + note +
"<ul>";
00338 article_list* alist = it.current();
00339 article_list::Iterator ait;
00340
for(ait = alist->begin(); ait != alist->end(); ++ait) {
00341 notifyCollection +=
"<li><b>From: </b>" + (*ait).from +
"<br>";
00342 notifyCollection +=
"<b>Subject: </b>" + (*ait).subject;
00343 }
00344 notifyCollection +=
"</ul>";
00345 }
00346 notifyCollection +=
"</ul>";
00347
00348
return notifyCollection;
00349 }
00350
00351
void NotifyCollection::displayCollection(
QWidget *p)
const
00352
{
00353
00354 KDialogBase *dlg =
new KDialogBase(p,0,
true,i18n(
"Collected Notes"),
00355 KDialogBase::Close, KDialogBase::Close);
00356
QTextView *text =
new QTextView(dlg);
00357 text->setText(collection());
00358 dlg->setMainWidget(text);
00359 dlg->setMinimumWidth(300);
00360 dlg->setMinimumHeight(300);
00361 dlg->exec();
00362 }
00363
00364
00365 KScoringExpression::KScoringExpression(
const QString& h,
const QString& t,
const QString& n,
const QString& ng)
00366 : header(h), expr_str(n)
00367 {
00368
if (t ==
"MATCH" ) {
00369 cond = MATCH;
00370 expr.setPattern(expr_str);
00371 expr.setCaseSensitive(
false);
00372 }
00373
else if (t ==
"CONTAINS" ) cond = CONTAINS;
00374
else if (t ==
"EQUALS" ) cond = EQUALS;
00375
else if (t ==
"GREATER") {
00376 cond = GREATER;
00377 expr_int = expr_str.toInt();
00378 }
00379
else if (t ==
"SMALLER") {
00380 cond = SMALLER;
00381 expr_int = expr_str.toInt();
00382 }
00383
else {
00384 kdDebug(5100) <<
"unknown match type in new expression" << endl;
00385 }
00386
00387 neg = ng.toInt();
00388 c_header = header.latin1();
00389
00390 kdDebug(5100) <<
"new expr: " << c_header <<
" " << t <<
" "
00391 << expr_str <<
" " << neg << endl;
00392 }
00393
00394
00395
int KScoringExpression::getConditionForName(
const QString& s)
00396 {
00397
if (s == getNameForCondition(CONTAINS))
return CONTAINS;
00398
else if (s == getNameForCondition(MATCH))
return MATCH;
00399
else if (s == getNameForCondition(EQUALS))
return EQUALS;
00400
else if (s == getNameForCondition(SMALLER))
return SMALLER;
00401
else if (s == getNameForCondition(GREATER))
return GREATER;
00402
else {
00403 kdWarning(5100) <<
"unknown condition name " << s
00404 <<
" in KScoringExpression::getConditionForName()" << endl;
00405
return -1;
00406 }
00407 }
00408
00409
00410
QString KScoringExpression::getNameForCondition(
int cond)
00411 {
00412
switch (cond) {
00413
case CONTAINS:
return i18n(
"Contains Substring");
00414
case MATCH:
return i18n(
"Matches Regular Expression");
00415
case EQUALS:
return i18n(
"Is Exactly the Same As");
00416
case SMALLER:
return i18n(
"Less Than");
00417
case GREATER:
return i18n(
"Greater Than");
00418
default:
00419 kdWarning(5100) <<
"unknown condition " << cond
00420 <<
" in KScoringExpression::getNameForCondition()" << endl;
00421
return "";
00422 }
00423 }
00424
00425
00426
QStringList KScoringExpression::conditionNames()
00427 {
00428
QStringList l;
00429 l << getNameForCondition(CONTAINS);
00430 l << getNameForCondition(MATCH);
00431 l << getNameForCondition(EQUALS);
00432 l << getNameForCondition(SMALLER);
00433 l << getNameForCondition(GREATER);
00434
return l;
00435 }
00436
00437
00438
QStringList KScoringExpression::headerNames()
00439 {
00440
QStringList l;
00441 l.append(
"From");
00442 l.append(
"Message-ID");
00443 l.append(
"Subject");
00444 l.append(
"Date");
00445 l.append(
"References");
00446 l.append(
"NNTP-Posting-Host");
00447 l.append(
"Bytes");
00448 l.append(
"Lines");
00449 l.append(
"Xref");
00450
return l;
00451 }
00452
00453 KScoringExpression::~KScoringExpression()
00454 {
00455 }
00456
00457
bool KScoringExpression::match(ScorableArticle& a)
const
00458
{
00459
00460
bool res =
true;
00461
QString head;
00462
00463
if (header ==
"From")
00464 head = a.from();
00465
else if (header ==
"Subject")
00466 head = a.subject();
00467
else
00468 head = a.getHeaderByType(c_header);
00469
00470
if (!head.isEmpty()) {
00471
switch (cond) {
00472
case EQUALS:
00473 res = (head.lower() == expr_str.lower());
00474
break;
00475
case CONTAINS:
00476 res = (head.lower().find(expr_str.lower()) >= 0);
00477
break;
00478
case MATCH:
00479 res = (expr.search(head)!=-1);
00480
break;
00481
case GREATER:
00482 res = (head.toInt() > expr_int);
00483
break;
00484
case SMALLER:
00485 res = (head.toInt() < expr_int);
00486
break;
00487
default:
00488 kdDebug(5100) <<
"unknown match" << endl;
00489 res =
false;
00490 }
00491 }
00492
else res =
false;
00493
00494
return (neg)?!res:res;
00495 }
00496
00497
void KScoringExpression::write(
QTextStream& st)
const
00498
{
00499 st << toString();
00500 }
00501
00502
QString KScoringExpression::toString()
const
00503
{
00504
00505
00506
00507
00508
00509
QString e;
00510 e +=
"<Expression neg=\"" + QString::number(neg?1:0)
00511 +
"\" header=\"" + header
00512 +
"\" type=\"" + getTypeString()
00513 +
"\" expr=\"" + toXml(expr_str)
00514 +
"\" />";
00515
00516
return e;
00517 }
00518
00519
QString KScoringExpression::getTypeString()
const
00520
{
00521
return KScoringExpression::getTypeString(cond);
00522 }
00523
00524
QString KScoringExpression::getTypeString(
int cond)
00525 {
00526
switch (cond) {
00527
case CONTAINS:
return "CONTAINS";
00528
case MATCH:
return "MATCH";
00529
case EQUALS:
return "EQUALS";
00530
case SMALLER:
return "SMALLER";
00531
case GREATER:
return "GREATER";
00532
default:
00533 kdWarning(5100) <<
"unknown cond " << cond <<
" in KScoringExpression::getTypeString()" << endl;
00534
return "";
00535 }
00536 }
00537
00538
int KScoringExpression::getType()
const
00539
{
00540
return cond;
00541 }
00542
00543
00544 KScoringRule::KScoringRule(
const QString& n )
00545 : name(n), link(AND)
00546 {
00547 expressions.setAutoDelete(
true);
00548 actions.setAutoDelete(
true);
00549 }
00550
00551 KScoringRule::KScoringRule(
const KScoringRule& r)
00552 {
00553 kdDebug(5100) <<
"copying rule " << r.getName() << endl;
00554 name = r.getName();
00555 expressions.setAutoDelete(
true);
00556 actions.setAutoDelete(
true);
00557
00558 expressions.clear();
00559
const ScoreExprList& rexpr = r.expressions;
00560
QPtrListIterator<KScoringExpression> it(rexpr);
00561
for ( ; it.current(); ++it ) {
00562 KScoringExpression *t =
new KScoringExpression(**it);
00563 expressions.append(t);
00564 }
00565
00566 actions.clear();
00567
const ActionList& ract = r.actions;
00568
QPtrListIterator<ActionBase> ait(ract);
00569
for ( ; ait.current(); ++ait ) {
00570
ActionBase *t = *ait;
00571 actions.append(t->
clone());
00572 }
00573
00574 groups = r.groups;
00575 expires = r.expires;
00576 link = r.link;
00577 }
00578
00579 KScoringRule::~KScoringRule()
00580 {
00581 cleanExpressions();
00582 cleanActions();
00583 }
00584
00585
void KScoringRule::cleanExpressions()
00586 {
00587
00588 expressions.clear();
00589 }
00590
00591
void KScoringRule::cleanActions()
00592 {
00593
00594 actions.clear();
00595 }
00596
00597
void KScoringRule::addExpression( KScoringExpression* expr)
00598 {
00599 kdDebug(5100) <<
"KScoringRule::addExpression" << endl;
00600 expressions.append(expr);
00601 }
00602
00603
void KScoringRule::addAction(
int type,
const QString& val)
00604 {
00605
ActionBase *action = ActionBase::factory(type,val);
00606 addAction(action);
00607 }
00608
00609
void KScoringRule::addAction(
ActionBase* a)
00610 {
00611 kdDebug(5100) <<
"KScoringRule::addAction() " << a->
toString() << endl;
00612 actions.append(a);
00613 }
00614
00615
void KScoringRule::setLinkMode(
const QString& l)
00616 {
00617
if (l ==
"OR") link = OR;
00618
else link = AND;
00619 }
00620
00621
void KScoringRule::setExpire(
const QString& e)
00622 {
00623
if (e !=
"never") {
00624
QStringList l = QStringList::split(
"-",e);
00625 Q_ASSERT( l.count() == 3 );
00626 expires.setYMD( (*(l.at(0))).toInt(),
00627 (*(l.at(1))).toInt(),
00628 (*(l.at(2))).toInt());
00629 }
00630 kdDebug(5100) <<
"Rule " << getName() <<
" expires at " << getExpireDateString() << endl;
00631 }
00632
00633
bool KScoringRule::matchGroup(
const QString& group)
const
00634
{
00635
for(GroupList::ConstIterator i=groups.begin(); i!=groups.end();++i) {
00636
QRegExp e(*i);
00637
if (e.search(group, 0) != -1 &&
00638 (uint)e.matchedLength() == group.length())
00639
return true;
00640 }
00641
return false;
00642 }
00643
00644
void KScoringRule::applyAction(ScorableArticle& a)
const
00645
{
00646
QPtrListIterator<ActionBase> it(actions);
00647
for(; it.current(); ++it) {
00648 it.current()->apply(a);
00649 }
00650 }
00651
00652
void KScoringRule::applyRule(ScorableArticle& a)
const
00653
{
00654
00655
00656
00657
00658
bool oper_and = (link == AND);
00659
bool res =
true;
00660
QPtrListIterator<KScoringExpression> it(expressions);
00661
00662
for (; it.current(); ++it) {
00663 Q_ASSERT( it.current() );
00664 res = it.current()->match(a);
00665
if (!res && oper_and)
return;
00666
else if (res && !oper_and)
break;
00667 }
00668
if (res) applyAction(a);
00669 }
00670
00671
void KScoringRule::applyRule(ScorableArticle& a ,
const QString& g)
const
00672
{
00673
00674
for (QStringList::ConstIterator i = groups.begin(); i != groups.end(); ++i) {
00675
if (
QRegExp(*i).search(g) != -1) {
00676 applyRule(a);
00677
return;
00678 }
00679 }
00680 }
00681
00682
void KScoringRule::write(
QTextStream& s)
const
00683
{
00684 s << toString();
00685 }
00686
00687
QString KScoringRule::toString()
const
00688
{
00689
00690
QString r;
00691 r +=
"<Rule name=\"" + toXml(name) +
"\" linkmode=\"" + getLinkModeName();
00692 r +=
"\" expires=\"" + getExpireDateString() +
"\">";
00693
00694
for(GroupList::ConstIterator i=groups.begin();i!=groups.end();++i) {
00695 r +=
"<Group name=\"" + toXml(*i) +
"\" />";
00696 }
00697
00698
QPtrListIterator<KScoringExpression> eit(expressions);
00699
for (; eit.current(); ++eit) {
00700 r += eit.current()->toString();
00701 }
00702
00703
QPtrListIterator<ActionBase> ait(actions);
00704
for (; ait.current(); ++ait) {
00705 r += ait.current()->toString();
00706 }
00707 r +=
"</Rule>";
00708
00709
return r;
00710 }
00711
00712
QString KScoringRule::getLinkModeName()
const
00713
{
00714
switch (link) {
00715
case AND:
return "AND";
00716
case OR:
return "OR";
00717
default:
return "AND";
00718 }
00719 }
00720
00721
QString KScoringRule::getExpireDateString()
const
00722
{
00723
if (expires.isNull())
return "never";
00724
else {
00725
return QString::number(expires.year()) +
QString(
"-")
00726 + QString::number(expires.month()) +
QString(
"-")
00727 + QString::number(expires.day());
00728 }
00729 }
00730
00731
bool KScoringRule::isExpired()
const
00732
{
00733
return (expires.isValid() && (expires < QDate::currentDate()));
00734 }
00735
00736
00737
00738
00739 KScoringManager::KScoringManager(
const QString& appName)
00740 : cacheValid(false)
00741 {
00742 allRules.setAutoDelete(
true);
00743
00744
if(appName.isEmpty())
00745 mFilename = KGlobal::dirs()->saveLocation(
"appdata") +
"/scorefile";
00746
else
00747 mFilename = KGlobal::dirs()->saveLocation(
"data") +
"/" + appName +
"/scorefile";
00748
00749 load();
00750 }
00751
00752
00753 KScoringManager::~KScoringManager()
00754 {
00755 }
00756
00757
void KScoringManager::load()
00758 {
00759
QDomDocument sdoc(
"Scorefile");
00760
QFile f( mFilename );
00761
if ( !f.open( IO_ReadOnly ) )
00762
return;
00763
if ( !sdoc.setContent( &f ) ) {
00764 f.close();
00765 kdDebug(5100) <<
"loading the scorefile failed" << endl;
00766
return;
00767 }
00768 f.close();
00769 kdDebug(5100) <<
"loaded the scorefile, creating internal representation" << endl;
00770 allRules.clear();
00771 createInternalFromXML(sdoc);
00772 expireRules();
00773 kdDebug(5100) <<
"ready, got " << allRules.count() <<
" rules" << endl;
00774 }
00775
00776
void KScoringManager::save()
00777 {
00778 kdDebug(5100) <<
"KScoringManager::save() starts" << endl;
00779
QFile f( mFilename );
00780
if ( !f.open( IO_WriteOnly ) )
00781
return;
00782
QTextStream stream(&f);
00783 stream.setEncoding(QTextStream::Unicode);
00784 kdDebug(5100) <<
"KScoringManager::save() creating xml" << endl;
00785 createXMLfromInternal().save(stream,2);
00786 kdDebug(5100) <<
"KScoringManager::save() finished" << endl;
00787 }
00788
00789
QDomDocument KScoringManager::createXMLfromInternal()
00790 {
00791
00792
00793
QDomDocument sdoc(
"Scorefile");
00794
QString ss;
00795 ss +=
"<?xml version = '1.0'?><!DOCTYPE Scorefile >";
00796 ss += toString();
00797 ss +=
"</Scorefile>\n";
00798 kdDebug(5100) <<
"KScoringManager::createXMLfromInternal():" << endl << ss << endl;
00799 sdoc.setContent(ss);
00800
return sdoc;
00801 }
00802
00803
QString KScoringManager::toString()
const
00804
{
00805
QString s;
00806 s +=
"<Scorefile>\n";
00807
QPtrListIterator<KScoringRule> it(allRules);
00808
for( ; it.current(); ++it) {
00809 s += it.current()->toString();
00810 }
00811
return s;
00812 }
00813
00814
void KScoringManager::expireRules()
00815 {
00816
for ( KScoringRule *cR = allRules.first(); cR; cR=allRules.next()) {
00817
if (cR->isExpired()) {
00818 kdDebug(5100) <<
"Rule " << cR->getName() <<
" is expired, deleting it" << endl;
00819 allRules.remove();
00820 }
00821 }
00822 }
00823
00824
void KScoringManager::createInternalFromXML(
QDomNode n)
00825 {
00826
static KScoringRule *cR = 0;
00827
00828
if ( !n.isNull() ) {
00829 kdDebug(5100) <<
"inspecting node of type " << n.nodeType()
00830 <<
" named " << n.toElement().tagName() << endl;
00831
00832
switch (n.nodeType()) {
00833
case QDomNode::DocumentNode: {
00834
00835
break;
00836 }
00837
case QDomNode::ElementNode: {
00838
00839
QDomElement e = n.toElement();
00840
00841
00842
QString s = e.tagName();
00843
if (s ==
"Rule") {
00844 cR =
new KScoringRule(e.attribute(
"name"));
00845 cR->setLinkMode(e.attribute(
"linkmode"));
00846 cR->setExpire(e.attribute(
"expires"));
00847 addRuleInternal(cR);
00848 }
00849
else if (s ==
"Group") {
00850 Q_CHECK_PTR(cR);
00851 cR->addGroup( e.attribute(
"name") );
00852 }
00853
else if (s ==
"Expression") {
00854 cR->addExpression(
new KScoringExpression(e.attribute(
"header"),
00855 e.attribute(
"type"),
00856 e.attribute(
"expr"),
00857 e.attribute(
"neg")));
00858 }
00859
else if (s ==
"Action") {
00860 Q_CHECK_PTR(cR);
00861 cR->addAction(ActionBase::getTypeForName(e.attribute(
"type")),
00862 e.attribute(
"value"));
00863 }
00864
break;
00865 }
00866
default:
00867 ;
00868 }
00869
QDomNodeList nodelist = n.childNodes();
00870
unsigned cnt = nodelist.count();
00871
00872
for (
unsigned i=0;i<cnt;++i)
00873 createInternalFromXML(nodelist.item(i));
00874 }
00875 }
00876
00877 KScoringRule* KScoringManager::addRule(
const ScorableArticle& a,
QString group,
short score)
00878 {
00879 KScoringRule *rule =
new KScoringRule(findUniqueName());
00880 rule->addGroup( group );
00881 rule->addExpression(
00882
new KScoringExpression(
"From",
"CONTAINS",
00883 a.from(),
"0"));
00884
if (score) rule->addAction(
new ActionSetScore(score));
00885 rule->setExpireDate(QDate::currentDate().addDays(30));
00886 addRule(rule);
00887 KScoringEditor *edit = KScoringEditor::createEditor(
this);
00888 edit->setRule(rule);
00889 edit->show();
00890 setCacheValid(
false);
00891
return rule;
00892 }
00893
00894 KScoringRule* KScoringManager::addRule(KScoringRule* expr)
00895 {
00896
int i = allRules.findRef(expr);
00897
if (i == -1) {
00898
00899 addRuleInternal(expr);
00900 }
00901
else {
00902 emit changedRules();
00903 }
00904
return expr;
00905 }
00906
00907 KScoringRule* KScoringManager::addRule()
00908 {
00909 KScoringRule *rule =
new KScoringRule(findUniqueName());
00910 addRule(rule);
00911
return rule;
00912 }
00913
00914
void KScoringManager::addRuleInternal(KScoringRule *e)
00915 {
00916 allRules.append(e);
00917 setCacheValid(
false);
00918 emit changedRules();
00919 kdDebug(5100) <<
"KScoringManager::addRuleInternal " << e->getName() << endl;
00920 }
00921
00922
void KScoringManager::cancelNewRule(KScoringRule *r)
00923 {
00924
00925
int i = allRules.findRef(r);
00926
if (i == -1) {
00927 kdDebug(5100) <<
"deleting rule " << r->getName() << endl;
00928 deleteRule(r);
00929 }
00930
else {
00931 kdDebug(5100) <<
"rule " << r->getName() <<
" not deleted" << endl;
00932 }
00933 }
00934
00935
void KScoringManager::setRuleName(KScoringRule *r,
const QString& s)
00936 {
00937
bool cont =
true;
00938
QString text = s;
00939
QString oldName = r->getName();
00940
while (cont) {
00941 cont =
false;
00942
QPtrListIterator<KScoringRule> it(allRules);
00943
for (; it.current(); ++it) {
00944
if ( it.current() != r && it.current()->getName() == text ) {
00945 kdDebug(5100) <<
"rule name " << text <<
" is not unique" << endl;
00946 text = KInputDialog::getText(i18n(
"Choose Another Rule Name"),
00947 i18n(
"The rule name is already assigned, please choose another name:"),
00948 text);
00949 cont =
true;
00950
break;
00951 }
00952 }
00953 }
00954
if (text != oldName) {
00955 r->setName(text);
00956 emit changedRuleName(oldName,text);
00957 }
00958 }
00959
00960
void KScoringManager::deleteRule(KScoringRule *r)
00961 {
00962
int i = allRules.findRef(r);
00963
if (i != -1) {
00964 allRules.remove();
00965 emit changedRules();
00966 }
00967 }
00968
00969
void KScoringManager::editRule(KScoringRule *e,
QWidget *w)
00970 {
00971 KScoringEditor *edit = KScoringEditor::createEditor(
this, w);
00972 edit->setRule(e);
00973 edit->show();
00974
delete edit;
00975 }
00976
00977
void KScoringManager::editorReady()
00978 {
00979 kdDebug(5100) <<
"emitting signal finishedEditing" << endl;
00980 save();
00981 emit finishedEditing();
00982 }
00983
00984 KScoringRule* KScoringManager::copyRule(KScoringRule *r)
00985 {
00986 KScoringRule *rule =
new KScoringRule(*r);
00987 rule->setName(findUniqueName());
00988 addRuleInternal(rule);
00989
return rule;
00990 }
00991
00992
void KScoringManager::applyRules(
ScorableGroup* )
00993 {
00994 kdWarning(5100) <<
"KScoringManager::applyRules(ScorableGroup* ) isn't implemented" << endl;
00995 }
00996
00997
void KScoringManager::applyRules(ScorableArticle& article,
const QString& group)
00998 {
00999 setGroup(group);
01000 applyRules(article);
01001 }
01002
01003
void KScoringManager::applyRules(ScorableArticle& a)
01004 {
01005
QPtrListIterator<KScoringRule> it(isCacheValid()? ruleList : allRules);
01006
for( ; it.current(); ++it) {
01007 it.current()->applyRule(a);
01008 }
01009 }
01010
01011
void KScoringManager::initCache(
const QString& g)
01012 {
01013 group = g;
01014 ruleList.clear();
01015
QPtrListIterator<KScoringRule> it(allRules);
01016
for (; it.current(); ++it) {
01017
if ( it.current()->matchGroup(group) ) {
01018 ruleList.append(it.current());
01019 }
01020 }
01021 kdDebug(5100) <<
"created cache for group " << group
01022 <<
" with " << ruleList.count() <<
" rules" << endl;
01023 setCacheValid(
true);
01024 }
01025
01026
void KScoringManager::setGroup(
const QString& g)
01027 {
01028
if (group != g) initCache(g);
01029 }
01030
01031
bool KScoringManager::hasRulesForCurrentGroup()
01032 {
01033
return ruleList.count() != 0;
01034 }
01035
01036
01037
QStringList KScoringManager::getRuleNames()
01038 {
01039
QStringList l;
01040
QPtrListIterator<KScoringRule> it(allRules);
01041
for( ; it.current(); ++it) {
01042 l << it.current()->getName();
01043 }
01044
return l;
01045 }
01046
01047 KScoringRule* KScoringManager::findRule(
const QString& ruleName)
01048 {
01049
QPtrListIterator<KScoringRule> it(allRules);
01050
for (; it.current(); ++it) {
01051
if ( it.current()->getName() == ruleName ) {
01052
return it;
01053 }
01054 }
01055
return 0;
01056 }
01057
01058
bool KScoringManager::setCacheValid(
bool v)
01059 {
01060
bool res = cacheValid;
01061 cacheValid = v;
01062
return res;
01063 }
01064
01065
QString KScoringManager::findUniqueName()
const
01066
{
01067
int nr = 0;
01068
QString ret;
01069
bool duplicated=
false;
01070
01071
while (nr < 99999999) {
01072 nr++;
01073 ret = i18n(
"rule %1").arg(nr);
01074
01075 duplicated=
false;
01076
QPtrListIterator<KScoringRule> it(allRules);
01077
for( ; it.current(); ++it) {
01078
if (it.current()->getName() == ret) {
01079 duplicated =
true;
01080
break;
01081 }
01082 }
01083
01084
if (!duplicated)
01085
return ret;
01086 }
01087
01088
return ret;
01089 }
01090
01091
bool KScoringManager::hasFeature(
int p)
01092 {
01093
switch (p) {
01094
case ActionBase::SETSCORE:
return canScores();
01095
case ActionBase::NOTIFY:
return canNotes();
01096
case ActionBase::COLOR:
return canColors();
01097
default:
return false;
01098 }
01099 }
01100
01101
QStringList KScoringManager::getDefaultHeaders()
const
01102
{
01103
QStringList l;
01104 l.append(
"Subject");
01105 l.append(
"From");
01106 l.append(
"Date");
01107 l.append(
"Message-ID");
01108
return l;
01109 }
01110
01111
void KScoringManager::pushRuleList()
01112 {
01113 stack.push(allRules);
01114 }
01115
01116
void KScoringManager::popRuleList()
01117 {
01118 stack.pop(allRules);
01119 emit changedRules();
01120 }
01121
01122
void KScoringManager::removeTOS()
01123 {
01124 stack.drop();
01125 }
01126
01127 RuleStack::RuleStack()
01128 {
01129 }
01130
01131 RuleStack::~RuleStack()
01132 {}
01133
01134 void RuleStack::push(
QPtrList<KScoringRule>& l)
01135 {
01136 kdDebug(5100) <<
"RuleStack::push pushing list with " << l.count() <<
" rules" << endl;
01137
KScoringManager::ScoringRuleList *l1 =
new KScoringManager::ScoringRuleList;
01138
for ( KScoringRule *r=l.first(); r != 0; r=l.next() ) {
01139 l1->append(
new KScoringRule(*r));
01140 }
01141 stack.push(l1);
01142 kdDebug(5100) <<
"now there are " << stack.count() <<
" lists on the stack" << endl;
01143 }
01144
01145 void RuleStack::pop(
QPtrList<KScoringRule>& l)
01146 {
01147
top(l);
01148
drop();
01149 kdDebug(5100) <<
"RuleStack::pop pops list with " << l.count() <<
" rules" << endl;
01150 kdDebug(5100) <<
"now there are " << stack.count() <<
" lists on the stack" << endl;
01151 }
01152
01153 void RuleStack::top(
QPtrList<KScoringRule>& l)
01154 {
01155 l.clear();
01156
KScoringManager::ScoringRuleList *l1 = stack.top();
01157 l = *l1;
01158 }
01159
01160 void RuleStack::drop()
01161 {
01162 kdDebug(5100) <<
"drop: now there are " << stack.count() <<
" lists on the stack" << endl;
01163 stack.remove();
01164 }
01165
01166
01167
#include "kscoring.moc"