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.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 17 09:52:22 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003