Framework for looking up contacts directly in nepomuk in addition to going through...
[kdepim.git] / mailcommon / searchpattern.h
blobdcda954ca5109333926ad3897a2b8bd8ce5642db
1 /* -*- mode: C++; c-file-style: "gnu" -*-
3 Author: Marc Mutz <mutz@kde.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #ifndef MAILCOMMON_SEARCHPATTERN_H
21 #define MAILCOMMON_SEARCHPATTERN_H
23 #include "mailcommon_export.h"
25 #include <Akonadi/KMime/MessageStatus>
27 #ifndef KDEPIM_NO_NEPOMUK
28 #include <Nepomuk/Query/GroupTerm>
29 #include <Nepomuk/Query/ComparisonTerm>
30 #endif
32 #include <KLocale>
33 #include <KUrl>
35 #include <QList>
36 #include <QString>
38 #include <boost/shared_ptr.hpp>
40 using Akonadi::MessageStatus;
42 class QXmlStreamWriter;
44 namespace Akonadi {
45 class Item;
48 namespace KMime {
49 class Message;
52 class KConfigGroup;
54 namespace MailCommon {
56 // maximum number of filter rules per filter
57 const int FILTER_MAX_RULES = 8;
59 /**
60 * @short This class represents one search pattern rule.
61 * Incoming mail is sent through the list of mail filter
62 * rules before it is placed in the associated mail folder (usually "inbox").
63 * This class represents one mail filter rule. It is also used to represent
64 * a search rule as used by the search dialog and folders.
66 class MAILCOMMON_EXPORT SearchRule
68 public:
69 /**
70 * Defines a pointer to a search rule.
72 typedef boost::shared_ptr<SearchRule> Ptr;
74 /**
75 * Describes operators for comparison of field and contents.
77 * If you change the order or contents of the enum: do not forget
78 * to change funcConfigNames[], sFilterFuncList and matches()
79 * in SearchRule, too.
80 * Also, it is assumed that these functions come in pairs of logical
81 * opposites (ie. "=" <-> "!=", ">" <-> "<=", etc.).
83 enum Function {
84 FuncNone = -1,
85 FuncContains = 0,
86 FuncContainsNot,
87 FuncEquals,
88 FuncNotEqual,
89 FuncRegExp,
90 FuncNotRegExp,
91 FuncIsGreater,
92 FuncIsLessOrEqual,
93 FuncIsLess,
94 FuncIsGreaterOrEqual,
95 FuncIsInAddressbook,
96 FuncIsNotInAddressbook,
97 FuncIsInCategory,
98 FuncIsNotInCategory,
99 FuncHasAttachment,
100 FuncHasNoAttachment,
101 FuncStartWith,
102 FuncNotStartWith,
103 FuncEndWith,
104 FuncNotEndWith
108 * Creates new new search rule.
110 * @param field The field to search in.
111 * @param function The function to use for searching.
112 * @param contents The contents to search for.
114 explicit SearchRule ( const QByteArray &field = 0, Function function = FuncContains,
115 const QString &contents = QString() );
118 * Creates a new search rule from an @p other rule.
120 SearchRule( const SearchRule &other );
123 * Initializes this rule with an @p other rule.
125 const SearchRule &operator=( const SearchRule &other );
128 * Creates a new search rule of a certain type by instantiating the
129 * appropriate subclass depending on the @p field.
131 * @param field The field to search in.
132 * @param function The function to use for searching.
133 * @param contents The contents to search for.
135 static SearchRule::Ptr createInstance( const QByteArray &field = 0,
136 Function function = FuncContains,
137 const QString &contents = QString() );
140 * Creates a new search rule of a certain type by instantiating the
141 * appropriate subclass depending on the @p field.
143 * @param field The field to search in.
144 * @param function The name of the function to use for searching.
145 * @param contents The contents to search for.
147 static SearchRule::Ptr createInstance( const QByteArray &field,
148 const char *function,
149 const QString &contents );
152 * Creates a new search rule by cloning an @p other rule.
154 static SearchRule::Ptr createInstance( const SearchRule &other );
157 * Creates a new search rule by deseralizing its structure from a data @p stream.
159 static SearchRule::Ptr createInstance( QDataStream &stream );
162 * Creates a new search rule from a given config @p group.
164 * @param group The config group to read the structure from.
165 * @param index The identifier that is used to distinguish
166 * rules within a single config group.
168 * @note This function does no validation of the data obtained
169 * from the config file. You should call isEmpty yourself
170 * if you need valid rules.
172 static SearchRule::Ptr createInstanceFromConfig( const KConfigGroup &group, int index );
175 * Destroys the search rule.
177 virtual ~SearchRule();
180 * Tries to match the rule against the KMime::Message in the
181 * given @p item.
183 * @return true if the rule matched, false otherwise.
185 * @note Must be implemented by subclasses.
187 virtual bool matches( const Akonadi::Item &item ) const = 0;
190 * Determines whether the rule is worth considering.
191 * It isn't if either the field is not set or the contents is empty.
192 * The calling code should make sure that it's rule list contains
193 * only non-empty rules, as matches doesn't check this.
195 virtual bool isEmpty() const = 0;
198 * Returns true if the rule depends on a complete message,
199 * otherwise returns false.
201 virtual bool requiresBody() const;
204 * Saves the object into a given config @p group.
206 * @param index The identifier that is used to distinguish
207 * rules within a single config group.
209 * @note This function will happily write itself even when it's
210 * not valid, assuming higher layers to Do The Right Thing(TM).
212 void writeConfig( KConfigGroup &group, int index ) const;
215 * Sets the filter @p function of the rule.
217 void setFunction( Function function );
220 * Returns the filter function of the rule.
222 Function function() const;
225 * Sets the message header field @p name.
227 * @note Make sure the name contains no trailing ':'.
229 void setField( const QByteArray &name );
232 * Returns the message header field name (without the trailing ':').
234 * There are also six pseudo-headers:
235 * @li \<message\>: Try to match against the whole message.
236 * @li \<body\>: Try to match against the body of the message.
237 * @li \<any header\>: Try to match against any header field.
238 * @li \<recipients\>: Try to match against both To: and Cc: header fields.
239 * @li \<size\>: Try to match against size of message (numerical).
240 * @li \<age in days\>: Try to match against age of message (numerical).
241 * @li \<status\>: Try to match against status of message (status).
242 * @li \<tag\>: Try to match against message tags.
244 QByteArray field() const;
247 * Set the @p contents of the rule.
249 * This can be either a substring to search for in
250 * or a regexp pattern to match against the header.
252 void setContents( const QString &contents );
255 * Returns the contents of the rule.
257 QString contents() const;
260 * Returns the rule as string for debugging purpose
262 const QString asString() const;
264 #ifndef KDEPIM_NO_NEPOMUK
266 * Adds query terms to the given term group.
268 virtual void addQueryTerms( Nepomuk::Query::GroupTerm &groupTerm ) const = 0;
269 #endif
272 * Adds a serialization of the rule in XESAM format into the stream.
274 virtual void addXesamClause( QXmlStreamWriter &stream ) const = 0;
276 QDataStream &operator>>( QDataStream & ) const;
278 protected:
280 * Helper that returns whether the rule has a negated function.
282 bool isNegated() const;
284 #ifndef KDEPIM_NO_NEPOMUK
286 * Converts the rule function into the corresponding Nepomuk query operator.
288 Nepomuk::Query::ComparisonTerm::Comparator nepomukComparator() const;
291 * Adds @p term to @p termGroup and adds a negation term inbetween if needed.
293 void addAndNegateTerm( const Nepomuk::Query::Term &term,
294 Nepomuk::Query::GroupTerm &termGroup ) const;
295 #endif
297 * Converts the rule function into the corresponding Xesam query operator.
299 QString xesamComparator() const;
301 protected:
302 QString quote( const QString &content ) const;
303 private:
304 static Function configValueToFunc( const char * );
305 static QString functionToString( Function );
307 QByteArray mField;
308 Function mFunction;
309 QString mContents;
312 // Needed for MSVC 2010, as it seems to not implicit cast for a pointer anymore
313 #ifdef _MSC_VER
314 uint qHash( SearchRule::Ptr sr );
315 #endif
318 * @short This class represents a search pattern rule operating on a string.
320 * This class represents a search to be performed against a string.
321 * The string can be either a message header, or a pseudo header, such
322 * as \<body\>
324 class SearchRuleString : public SearchRule
326 public:
328 * Creates new new string search rule.
330 * @param field The field to search in.
331 * @param function The function to use for searching.
332 * @param contents The contents to search for.
334 explicit SearchRuleString( const QByteArray &field = 0,
335 Function function = FuncContains,
336 const QString &contents = QString() );
339 * Creates a new string search rule from an @p other rule.
341 SearchRuleString( const SearchRuleString &other );
344 * Initializes this rule with an @p other rule.
346 const SearchRuleString &operator=( const SearchRuleString &other );
349 * Destroys the string search rule.
351 virtual ~SearchRuleString();
354 * @copydoc SearchRule::isEmpty()
356 virtual bool isEmpty() const ;
359 * @copydoc SearchRule::requiresBody()
361 virtual bool requiresBody() const;
364 * @copydoc SearchRule::matches()
366 virtual bool matches( const Akonadi::Item &item ) const;
369 * A helper method for the main matches() method.
370 * Does the actual comparing.
372 bool matchesInternal( const QString &contents ) const;
374 #ifndef KDEPIM_NO_NEPOMUK
376 * @copydoc SearchRule::addQueryTerms()
378 virtual void addQueryTerms( Nepomuk::Query::GroupTerm &groupTerm ) const;
379 #endif
382 * @copydoc SearchRule::addXesamClause( QXmlStreamWriter &stream )
384 virtual void addXesamClause( QXmlStreamWriter &stream ) const;
386 private:
387 #ifndef KDEPIM_NO_NEPOMUK
389 * @copydoc SearchRule::addPersonTerms()
391 void addPersonTerm( Nepomuk::Query::GroupTerm &groupTerm, const QUrl &field ) const;
392 void addHeaderTerm( Nepomuk::Query::GroupTerm &groupTerm,
393 const Nepomuk::Query::Term &field ) const;
394 #endif
398 * @short This class represents a search pattern rule operating on numerical values.
400 * This class represents a search to be performed against a numerical value,
401 * such as the age of the message in days or its size.
403 class SearchRuleNumerical : public SearchRule
405 public:
407 * Creates new numerical search rule.
409 * @param field The field to search in.
410 * @param function The function to use for searching.
411 * @param contents The contents to search for.
413 explicit SearchRuleNumerical( const QByteArray &field = 0,
414 Function function = FuncContains,
415 const QString &contents = QString() );
418 * @copydoc SearchRule::isEmpty()
420 virtual bool isEmpty() const ;
423 * @copydoc SearchRule::matches()
425 virtual bool matches( const Akonadi::Item &item ) const;
427 // Optimized matching not implemented, will use the unoptimized matching
428 // from SearchRule
429 using SearchRule::matches;
432 * A helper method for the main matches() method.
433 * Does the actual comparing.
435 bool matchesInternal( long numericalValue, long numericalContents,
436 const QString &contents ) const;
438 #ifndef KDEPIM_NO_NEPOMUK
440 * @copydoc SearchRule::addQueryTerms()
442 virtual void addQueryTerms( Nepomuk::Query::GroupTerm &groupTerm ) const;
443 #endif
446 * @copydoc SearchRule::addXesamClause( QXmlStreamWriter &stream )
448 virtual void addXesamClause( QXmlStreamWriter &stream ) const;
452 class SearchRuleDate : public SearchRule
454 public:
456 * Creates new date search rule.
458 * @param field The field to search in.
459 * @param function The function to use for searching.
460 * @param contents The contents to search for.
462 explicit SearchRuleDate( const QByteArray &field = 0,
463 Function function = FuncContains,
464 const QString &contents = QString() );
467 * @copydoc SearchRule::isEmpty()
469 virtual bool isEmpty() const ;
472 * @copydoc SearchRule::matches()
474 virtual bool matches( const Akonadi::Item &item ) const;
476 // Optimized matching not implemented, will use the unoptimized matching
477 // from SearchRule
478 using SearchRule::matches;
481 * A helper method for the main matches() method.
482 * Does the actual comparing.
484 bool matchesInternal( const QDate& dateValue, const QDate& msgDate ) const;
486 #ifndef KDEPIM_NO_NEPOMUK
488 * @copydoc SearchRule::addQueryTerms()
490 virtual void addQueryTerms( Nepomuk::Query::GroupTerm &groupTerm ) const;
491 #endif
494 * @copydoc SearchRule::addXesamClause( QXmlStreamWriter &stream )
496 virtual void addXesamClause( QXmlStreamWriter &stream ) const;
503 //TODO: Check if the below one is needed or not!
504 // The below are used in several places and here so they are accessible.
505 struct MessageStatusInfo {
506 const char *text;
507 const char *icon;
510 // If you change the ordering here; also do it in the enum below
511 static const MessageStatusInfo StatusValues[] =
513 { I18N_NOOP2( "message status", "Important" ), "emblem-important" },
514 { I18N_NOOP2( "message status", "Action Item" ), "mail-task" },
515 { I18N_NOOP2( "message status", "Unread" ), "mail-unread" },
516 { I18N_NOOP2( "message status", "Read" ), "mail-read" },
517 { I18N_NOOP2( "message status", "Deleted" ), "mail-deleted" },
518 { I18N_NOOP2( "message status", "Replied" ), "mail-replied" },
519 { I18N_NOOP2( "message status", "Forwarded" ), "mail-forwarded" },
520 { I18N_NOOP2( "message status", "Queued" ), "mail-queued" },
521 { I18N_NOOP2( "message status", "Sent" ), "mail-sent" },
522 { I18N_NOOP2( "message status", "Watched" ), "mail-thread-watch" },
523 { I18N_NOOP2( "message status", "Ignored" ), "mail-thread-ignored" },
524 { I18N_NOOP2( "message status", "Spam" ), "mail-mark-junk" },
525 { I18N_NOOP2( "message status", "Ham" ), "mail-mark-notjunk" },
526 { I18N_NOOP2( "message status", "Has Attachment"), "mail-attachment" } //must be last
529 // If you change the ordering here; also do it in the array above
530 enum StatusValueTypes {
531 StatusImportant = 0,
532 StatusToAct = 1,
533 StatusUnread = 2,
534 StatusRead = 3,
535 StatusDeleted = 4,
536 StatusReplied = 5,
537 StatusForwarded = 6,
538 StatusQueued = 7,
539 StatusSent = 8,
540 StatusWatched = 9,
541 StatusIgnored = 10,
542 StatusSpam = 11,
543 StatusHam = 12,
544 StatusHasAttachment = 13 //must be last
547 static const int StatusValueCount =
548 sizeof( StatusValues ) / sizeof( MessageStatusInfo );
549 // we want to show all status entries in the quick search bar, but only the
550 // ones up to attachment in the search/filter dialog, because there the
551 // attachment case is handled separately.
552 static const int StatusValueCountWithoutHidden = StatusValueCount - 1;
555 * This class represents a search to be performed against the status of a
556 * messsage. The status is represented by a bitfield.
558 * @short This class represents a search pattern rule operating on message
559 * status.
561 class MAILCOMMON_EXPORT SearchRuleStatus : public SearchRule
563 public:
564 explicit SearchRuleStatus( const QByteArray &field = 0,
565 Function function = FuncContains,
566 const QString &contents = QString() );
568 explicit SearchRuleStatus( Akonadi::MessageStatus status,
569 Function function = FuncContains );
571 virtual bool isEmpty() const ;
572 virtual bool matches( const Akonadi::Item &item ) const;
574 #ifndef KDEPIM_NO_NEPOMUK
575 virtual void addQueryTerms( Nepomuk::Query::GroupTerm &groupTerm ) const;
576 #endif
578 //Not possible to implement optimized form for status searching
579 using SearchRule::matches;
581 static Akonadi::MessageStatus statusFromEnglishName( const QString & );
583 * @copydoc SearchRule::addXesamClause( QXmlStreamWriter &stream )
585 virtual void addXesamClause( QXmlStreamWriter &stream ) const;
587 private:
588 #ifndef KDEPIM_NO_NEPOMUK
589 void addTagTerm( Nepomuk::Query::GroupTerm &groupTerm, const QString &tagId ) const;
590 #endif
592 private:
593 Akonadi::MessageStatus mStatus;
596 // ------------------------------------------------------------------------
598 /** This class is an abstraction of a search over messages. It is
599 intended to be used inside a KFilter (which adds KFilterAction's),
600 as well as in KMSearch. It can read and write itself into a
601 KConfig group and there is a constructor, mainly used by KMFilter
602 to initialize from a preset KConfig-Group.
604 From a class hierarchy point of view, it is a QPtrList of
605 SearchRule's that adds the boolean operators (see Operator)
606 'and' and 'or' that connect the rules logically, and has a name
607 under which it could be stored in the config file.
609 As a QPtrList with autoDelete enabled, it assumes that it is the
610 central repository for the rules it contains. So if you want to
611 reuse a rule in another pattern, make a deep copy of that rule.
613 @short An abstraction of a search over messages.
614 @author Marc Mutz <mutz@kde.org>
616 class MAILCOMMON_EXPORT SearchPattern : public QList<SearchRule::Ptr>
619 public:
621 * Boolean operators that connect the return values of the
622 * individual rules. A pattern with @p OpAnd will match iff all
623 * it's rules match, whereas a pattern with @p OpOr will match if
624 * any of it's rules matches.
626 enum Operator {
627 OpAnd,
628 OpOr,
629 OpAll
633 * Constructor which provides a pattern with minimal, but
634 * sufficient initialization. Unmodified, such a pattern will fail
635 * to match any KMime::Message. You can query for such an empty
636 * rule by using isEmpty, which is inherited from QPtrList.
638 SearchPattern();
641 * Constructor that initializes from a given KConfig group, if
642 * given. This feature is mainly (solely?) used in KMFilter,
643 * as we don't allow to store search patterns in the config (yet).
645 SearchPattern( const KConfigGroup &config );
647 /** Destructor. Deletes all stored rules! */
648 ~SearchPattern();
651 * The central function of this class. Tries to match the set of
652 * rules against a KMime::Message. It's virtual to allow derived
653 * classes with added rules to reimplement it, yet reimplemented
654 * methods should and (&&) the result of this function with their
655 * own result or else most functionality is lacking, or has to be
656 * reimplemented, since the rules are private to this class.
658 * @return true if the match was successful, false otherwise.
660 bool matches( const Akonadi::Item &item, bool ignoreBody = false ) const;
663 * Returns true if the pattern only depends the DwString that backs a message.
665 bool requiresBody() const;
668 * Removes all empty rules from the list. You should call this
669 * method whenever the user had had control of the rules outside of
670 * this class. (e.g. after editing it with SearchPatternEdit).
672 void purify();
675 * Reads a search pattern from a KConfigGroup. If it does not find
676 * a valid saerch pattern in the preset group, initializes the pattern
677 * as if it were constructed using the default constructor.
679 * For backwards compatibility with previous versions of KMail, it
680 * checks for old-style filter rules (e.g. using @p OpIgnore)
681 * in @p config und converts them to the new format on writeConfig.
683 * Derived classes reimplementing readConfig() should also call this
684 * method, or else the rules will not be loaded.
686 void readConfig( const KConfigGroup &config );
689 * Writes itself into @p config. Tries to delete old-style keys by
690 * overwriting them with QString().
692 * Derived classes reimplementing writeConfig() should also call this
693 * method, or else the rules will not be stored.
695 void writeConfig( KConfigGroup &config ) const;
698 * Returns the name of the search pattern.
700 QString name() const
702 return mName;
706 * Sets the name of the search pattern. KMFilter uses this to
707 * store it's own name, too.
709 void setName( const QString &newName )
711 mName = newName;
715 * Returns the filter operator.
717 SearchPattern::Operator op() const
719 return mOperator;
723 * Sets the filter operator.
725 void setOp( SearchPattern::Operator aOp )
727 mOperator = aOp;
731 * Returns the pattern as string. For debugging.
733 QString asString() const;
736 * Returns the pattern as a SPARQL query.
738 QString asSparqlQuery(const KUrl::List& url = KUrl::List()) const;
741 * Returns the pattern as a XESAM query.
743 QString asXesamQuery() const;
746 * Overloaded assignment operator. Makes a deep copy.
748 const SearchPattern &operator=( const SearchPattern &aPattern );
751 * Writes the pattern into a byte array for persistance purposes.
753 QByteArray serialize() const;
756 * Constructs the pattern from a byte array serialization.
758 void deserialize( const QByteArray & );
760 QDataStream &operator>>( QDataStream &s ) const;
761 QDataStream &operator<<( QDataStream &s );
763 private:
765 * Tries to import a legacy search pattern, ie. one that still has
766 * e.g. the @p unless or @p ignore operator which were useful as long as
767 * the number of rules was restricted to two. This method is called from
768 * readConfig, which detects legacy configurations and also makes sure
769 * that this method is called from an initialized object.
771 void importLegacyConfig( const KConfigGroup &config );
774 * Initializes the object. Clears the list of rules, sets the name
775 * to "<i18n("unnamed")>", and the boolean operator to @p OpAnd.
777 void init();
778 Nepomuk::Query::ComparisonTerm createChildTerm( const KUrl& url, bool& empty ) const;
779 QString mName;
780 Operator mOperator;
784 #endif /* MAILCOMMON_SEARCHPATTERN_H_ */