libkdenetwork Library API Documentation

kscoring.cpp

00001 /* 00002 kscoring.cpp 00003 00004 Copyright (c) 2001 Mathias Waack 00005 00006 Author: Mathias Waack <mathias@atoll-net.de> 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 You should have received a copy of the GNU General Public License 00013 along with this program; if not, write to the Free Software Foundation, 00014 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, US 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 // a small function to encode attribute values, code stolen from QDom 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, "&lt;"); 00050 len += 3; 00051 i += 4; 00052 } else if (tmp[(int)i] == '"') { 00053 tmp.replace(i, 1, "&quot;"); 00054 len += 5; 00055 i += 6; 00056 } else if (tmp[(int)i] == '&') { 00057 tmp.replace(i, 1, "&amp;"); 00058 len += 4; 00059 i += 5; 00060 } else if (tmp[(int)i] == '>') { 00061 tmp.replace(i, 1, "&gt;"); 00062 len += 3; 00063 i += 4; 00064 } else { 00065 ++i; 00066 } 00067 } 00068 00069 return tmp; 00070 } 00071 00072 00073 // small dialog to display the messages from NotifyAction 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 // the base class for all actions 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 // the set score action 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 // the color action 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 // the notify action 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 // first look thru the notes and create one string 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 //KMessageBox::information(p,collection(),i18n("Collected Notes")); 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 // static 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 // static 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 // static 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 // static 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 //kdDebug(5100) << "matching against header " << c_header << endl; 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 // kdDebug(5100) << "matching returns " << res << endl; 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 // kdDebug(5100) << "KScoringExpression::toString() starts" << endl; 00505 // kdDebug(5100) << "header is " << header << endl; 00506 // kdDebug(5100) << "expr is " << expr_str << endl; 00507 // kdDebug(5100) << "neg is " << neg << endl; 00508 // kdDebug(5100) << "type is " << getType() << endl; 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 // kdDebug(5100) << "KScoringExpression::toString() finished" << endl; 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 // copy expressions 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 // copy actions 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 // copy groups, servers, linkmode and expires 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 // the expressions is setAutoDelete(true) 00588 expressions.clear(); 00589 } 00590 00591 void KScoringRule::cleanActions() 00592 { 00593 // the actions is setAutoDelete(true) 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 // kdDebug(5100) << "checking rule " << name << endl; 00655 // kdDebug(5100) << " for article from " 00656 // << a->from()->asUnicodeString() 00657 // << endl; 00658 bool oper_and = (link == AND); 00659 bool res = true; 00660 QPtrListIterator<KScoringExpression> it(expressions); 00661 //kdDebug(5100) << "checking " << expressions.count() << " expressions" << endl; 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& s*/, const QString& g) const 00672 { 00673 // check if one of the groups match 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 //kdDebug(5100) << "KScoringRule::toString() starts" << endl; 00690 QString r; 00691 r += "<Rule name=\"" + toXml(name) + "\" linkmode=\"" + getLinkModeName(); 00692 r += "\" expires=\"" + getExpireDateString() + "\">"; 00693 //kdDebug(5100) << "building grouplist..." << endl; 00694 for(GroupList::ConstIterator i=groups.begin();i!=groups.end();++i) { 00695 r += "<Group name=\"" + toXml(*i) + "\" />"; 00696 } 00697 //kdDebug(5100) << "building expressionlist..." << endl; 00698 QPtrListIterator<KScoringExpression> eit(expressions); 00699 for (; eit.current(); ++eit) { 00700 r += eit.current()->toString(); 00701 } 00702 //kdDebug(5100) << "building actionlist..." << endl; 00703 QPtrListIterator<ActionBase> ait(actions); 00704 for (; ait.current(); ++ait) { 00705 r += ait.current()->toString(); 00706 } 00707 r += "</Rule>"; 00708 //kdDebug(5100) << "KScoringRule::toString() finished" << endl; 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)//, _s(0) 00741 { 00742 allRules.setAutoDelete(true); 00743 // determine filename of the scorefile 00744 if(appName.isEmpty()) 00745 mFilename = KGlobal::dirs()->saveLocation("appdata") + "/scorefile"; 00746 else 00747 mFilename = KGlobal::dirs()->saveLocation("data") + "/" + appName + "/scorefile"; 00748 // open the score file 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 // I was'nt able to create a QDomDocument in memory:( 00792 // so I write the content into a string, which is really stupid 00793 QDomDocument sdoc("Scorefile"); 00794 QString ss; // scorestring 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; // the currentRule 00827 // the XML file was parsed and now we simply traverse the resulting tree 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 // the document itself 00835 break; 00836 } 00837 case QDomNode::ElementNode: { 00838 // Server, Newsgroup, Rule, Expression, Action 00839 QDomElement e = n.toElement(); 00840 //kdDebug(5100) << "The name of the element is " 00841 //<< e.tagName().latin1() << endl; 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: // kdDebug(5100) << "unknown DomNode::type" << endl; 00867 ; 00868 } 00869 QDomNodeList nodelist = n.childNodes(); 00870 unsigned cnt = nodelist.count(); 00871 //kdDebug(5100) << "recursive checking " << cnt << " nodes" << endl; 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 // only add a rule we don't know 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 // if e was'nt previously added to the list of rules, we delete it 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"
KDE Logo
This file is part of the documentation for libkdenetwork Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Oct 21 19:46:17 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003