akregator
articlematcher.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "articlematcher.h"
00028 #include "article.h"
00029 #include "types.h"
00030
00031 #include <kapplication.h>
00032 #include <kconfiggroup.h>
00033 #include <kdebug.h>
00034 #include <krandom.h>
00035 #include <kurl.h>
00036
00037 #include <QList>
00038 #include <QRegExp>
00039
00040
00041 namespace Akregator {
00042 namespace Filters {
00043
00044 AbstractMatcher::AbstractMatcher() {}
00045
00046 AbstractMatcher::~AbstractMatcher() {}
00047
00048 QString Criterion::subjectToString(Subject subj)
00049 {
00050 switch (subj)
00051 {
00052 case Title:
00053 return QString::fromLatin1("Title");
00054 case Link:
00055 return QString::fromLatin1("Link");
00056 case Description:
00057 return QString::fromLatin1("Description");
00058 case Status:
00059 return QString::fromLatin1("Status");
00060 case KeepFlag:
00061 return QString::fromLatin1("KeepFlag");
00062 default:
00063 return QString::fromLatin1("Description");
00064 }
00065 }
00066
00067 Criterion::Subject Criterion::stringToSubject(const QString& subjStr)
00068 {
00069 if (subjStr == QString::fromLatin1("Title"))
00070 return Title;
00071 else if (subjStr == QString::fromLatin1("Link"))
00072 return Link;
00073 else if (subjStr == QString::fromLatin1("Description"))
00074 return Description;
00075 else if (subjStr == QString::fromLatin1("Status"))
00076 return Status;
00077 else if (subjStr == QString::fromLatin1("KeepFlag"))
00078 return KeepFlag;
00079
00080
00081 return Description;
00082 }
00083
00084 QString Criterion::predicateToString(Predicate pred)
00085 {
00086 switch (pred)
00087 {
00088 case Contains:
00089 return QString::fromLatin1("Contains");
00090 case Equals:
00091 return QString::fromLatin1("Equals");
00092 case Matches:
00093 return QString::fromLatin1("Matches");
00094 case Negation:
00095 return QString::fromLatin1("Negation");
00096 default:
00097 return QString::fromLatin1("Contains");
00098 }
00099 }
00100
00101 Criterion::Predicate Criterion::stringToPredicate(const QString& predStr)
00102 {
00103 if (predStr == QString::fromLatin1("Contains"))
00104 return Contains;
00105 else if (predStr == QString::fromLatin1("Equals"))
00106 return Equals;
00107 else if (predStr == QString::fromLatin1("Matches"))
00108 return Matches;
00109 else if (predStr == QString::fromLatin1("Negation"))
00110 return Negation;
00111
00112
00113 return Contains;
00114 }
00115
00116 Criterion::Criterion()
00117 {
00118 }
00119
00120 Criterion::Criterion( Subject subject, Predicate predicate, const QVariant &object )
00121 : m_subject( subject )
00122 , m_predicate( predicate )
00123 , m_object( object )
00124 {
00125
00126 }
00127
00128 void Criterion::writeConfig(KConfigGroup* config) const
00129 {
00130 config->writeEntry(QString::fromLatin1("subject"), subjectToString(m_subject));
00131
00132 config->writeEntry(QString::fromLatin1("predicate"), predicateToString(m_predicate));
00133
00134 config->writeEntry(QString::fromLatin1("objectType"), QString(m_object.typeName()));
00135
00136 config->writeEntry(QString::fromLatin1("objectValue"), m_object);
00137 }
00138
00139 void Criterion::readConfig(KConfigGroup* config)
00140 {
00141 m_subject = stringToSubject(config->readEntry(QString::fromLatin1("subject"), QString()));
00142 m_predicate = stringToPredicate(config->readEntry(QString::fromLatin1("predicate"), QString()));
00143 QVariant::Type type = QVariant::nameToType(config->readEntry(QString::fromLatin1("objType"), QString()).toAscii());
00144
00145 if (type != QVariant::Invalid)
00146 {
00147 m_object = config->readEntry(QString::fromLatin1("objectValue"), QVariant(type) );
00148 }
00149 }
00150
00151 bool Criterion::satisfiedBy( const Article &article ) const
00152 {
00153 QVariant concreteSubject;
00154
00155 switch ( m_subject ) {
00156 case Title:
00157 concreteSubject = QVariant(article.title());
00158 break;
00159 case Description:
00160 concreteSubject = QVariant(article.description());
00161 break;
00162 case Link:
00163
00164 concreteSubject = QVariant(article.link().url());
00165 break;
00166 case Status:
00167 concreteSubject = QVariant(article.status());
00168 break;
00169 case KeepFlag:
00170 concreteSubject = QVariant(article.keep());
00171 default:
00172 break;
00173 }
00174
00175 bool satisfied = false;
00176
00177 const Predicate predicateType = static_cast<Predicate>( m_predicate & ~Negation );
00178 QString subjectType=concreteSubject.typeName();
00179
00180 switch ( predicateType ) {
00181 case Contains:
00182 satisfied = concreteSubject.toString().indexOf( m_object.toString(), 0, Qt::CaseInsensitive ) != -1;
00183 break;
00184 case Equals:
00185 if (subjectType=="int")
00186 satisfied = concreteSubject.toInt() == m_object.toInt();
00187 else
00188 satisfied = concreteSubject.toString() == m_object.toString();
00189 break;
00190 case Matches:
00191 satisfied = QRegExp( m_object.toString() ).indexIn( concreteSubject.toString() ) != -1;
00192 break;
00193 default:
00194 kDebug() <<"Internal inconsistency; predicateType should never be Negation";
00195 break;
00196 }
00197
00198 if ( m_predicate & Negation ) {
00199 satisfied = !satisfied;
00200 }
00201
00202 return satisfied;
00203 }
00204
00205 Criterion::Subject Criterion::subject() const
00206 {
00207 return m_subject;
00208 }
00209
00210 Criterion::Predicate Criterion::predicate() const
00211 {
00212 return m_predicate;
00213 }
00214
00215 QVariant Criterion::object() const
00216 {
00217 return m_object;
00218 }
00219
00220 ArticleMatcher::ArticleMatcher()
00221 : m_association( None )
00222 {
00223 }
00224
00225 ArticleMatcher::~ArticleMatcher()
00226 {
00227 }
00228
00229 ArticleMatcher::ArticleMatcher( const QList<Criterion> &criteria, Association assoc)
00230 : m_criteria( criteria )
00231 , m_association( assoc )
00232 {
00233 }
00234
00235 bool ArticleMatcher::matches( const Article &a ) const
00236 {
00237 switch ( m_association ) {
00238 case LogicalOr:
00239 return anyCriterionMatches( a );
00240 case LogicalAnd:
00241 return allCriteriaMatch( a );
00242 default:
00243 break;
00244 }
00245 return true;
00246 }
00247
00248 void ArticleMatcher::writeConfig(KConfigGroup* config) const
00249 {
00250 config->writeEntry(QString::fromLatin1("matcherAssociation"), associationToString(m_association));
00251
00252 config->writeEntry(QString::fromLatin1("matcherCriteriaCount"), m_criteria.count());
00253
00254 int index = 0;
00255
00256 QString criterionGroupPrefix = config->name() + QString::fromLatin1("_Criterion");
00257
00258 for (QList<Criterion>::ConstIterator it = m_criteria.begin(); it != m_criteria.end(); ++it)
00259 {
00260 config->changeGroup(criterionGroupPrefix + QString::number(index));
00261 (*it).writeConfig(config);
00262 ++index;
00263 }
00264 }
00265
00266 void ArticleMatcher::readConfig(KConfigGroup* config)
00267 {
00268 m_criteria.clear();
00269 m_association = stringToAssociation(config->readEntry(QString::fromLatin1("matcherAssociation"), QString()));
00270
00271 int count = config->readEntry(QString::fromLatin1("matcherCriteriaCount"), 0);
00272
00273 QString criterionGroupPrefix = config->name() + QString::fromLatin1("_Criterion");
00274
00275 for (int i = 0; i < count; ++i)
00276 {
00277 Criterion c;
00278 config->changeGroup(criterionGroupPrefix + QString::number(i));
00279 c.readConfig(config);
00280 m_criteria.append(c);
00281 }
00282 }
00283
00284 bool ArticleMatcher::operator==(const AbstractMatcher& other) const
00285 {
00286 AbstractMatcher* ptr = const_cast<AbstractMatcher*>(&other);
00287 ArticleMatcher* o = dynamic_cast<ArticleMatcher*>(ptr);
00288 if (!o)
00289 return false;
00290 else
00291 return m_association == o->m_association && m_criteria == o->m_criteria;
00292 }
00293 bool ArticleMatcher::operator!=(const AbstractMatcher& other) const
00294 {
00295 return !(*this == other);
00296 }
00297
00298 bool ArticleMatcher::anyCriterionMatches( const Article &a ) const
00299 {
00300 if (m_criteria.count()==0)
00301 return true;
00302 QList<Criterion>::ConstIterator it = m_criteria.begin();
00303 QList<Criterion>::ConstIterator end = m_criteria.end();
00304 for ( ; it != end; ++it ) {
00305 if ( ( *it ).satisfiedBy( a ) ) {
00306 return true;
00307 }
00308 }
00309 return false;
00310 }
00311
00312 bool ArticleMatcher::allCriteriaMatch( const Article &a ) const
00313 {
00314 if (m_criteria.count()==0)
00315 return true;
00316 QList<Criterion>::ConstIterator it = m_criteria.begin();
00317 QList<Criterion>::ConstIterator end = m_criteria.end();
00318 for ( ; it != end; ++it ) {
00319 if ( !( *it ).satisfiedBy( a ) ) {
00320 return false;
00321 }
00322 }
00323 return true;
00324 }
00325
00326 ArticleMatcher::Association ArticleMatcher::stringToAssociation(const QString& assocStr)
00327 {
00328 if (assocStr == QString::fromLatin1("LogicalAnd"))
00329 return LogicalAnd;
00330 else if (assocStr == QString::fromLatin1("LogicalOr"))
00331 return LogicalOr;
00332 else
00333 return None;
00334 }
00335
00336 QString ArticleMatcher::associationToString(Association association)
00337 {
00338 switch (association)
00339 {
00340 case LogicalAnd:
00341 return QString::fromLatin1("LogicalAnd");
00342 case LogicalOr:
00343 return QString::fromLatin1("LogicalOr");
00344 default:
00345 return QString::fromLatin1("None");
00346 }
00347 }
00348
00349
00350 }
00351 }