Messagelib

filter.cpp
1/******************************************************************************
2 *
3 * SPDX-FileCopyrightText: 2008 Szymon Tomasz Stefanek <pragma@kvirc.net>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 *
7 *******************************************************************************/
8
9#include "core/filter.h"
10#include "core/messageitem.h"
11#include <MessageCore/StringUtil>
12#include <TextUtils/ConvertText>
13
14#include <KRandom>
15#include <PIM/emailquery.h>
16#include <PIM/resultiterator.h>
17using namespace MessageList::Core;
18
19Filter::Filter(QObject *parent)
20 : QObject(parent)
21{
22 generateRandomIdentifier();
23}
24
25bool Filter::containString(const QString &searchInString) const
26{
27 bool found = false;
28 const QString searchInStringNormalize{TextUtils::ConvertText::normalize(searchInString)};
29 for (const QString &str : std::as_const(mSearchList)) {
30 if (searchInStringNormalize.contains(TextUtils::ConvertText::normalize(str), Qt::CaseInsensitive)) {
31 found = true;
32 } else {
33 found = false;
34 break;
35 }
36 }
37 return found;
38}
39
40const QString &Filter::iconName() const
41{
42 return mIconName;
43}
44
45void Filter::setIconName(const QString &newIconName)
46{
47 mIconName = newIconName;
48}
49
50void Filter::setOptions(QuickSearchLine::SearchOptions newOptions)
51{
52 mOptions = newOptions;
53}
54
55const QString &Filter::filterName() const
56{
57 return mFilterName;
58}
59
60void Filter::setFilterName(const QString &newFilterName)
61{
62 mFilterName = newFilterName;
63}
64
65void Filter::setIdentifier(const QString &newIdentifier)
66{
67 mIdentifier = newIdentifier;
68}
69
70bool Filter::match(const MessageItem *item) const
71{
72 if (!mStatus.isEmpty()) {
73 for (Akonadi::MessageStatus status : std::as_const(mStatus)) {
74 if (!(status & item->status())) {
75 return false;
76 }
77 }
78 }
79
80 if (!mSearchString.isEmpty()) {
81 if (mMatchingItemIds.contains(item->itemId())) {
82 return true;
83 }
84
85 bool searchMatches = false;
86 bool searchEveryWhere = (mOptions & QuickSearchLine::SearchEveryWhere);
87 if (containString(item->subject()) && ((mOptions & QuickSearchLine::SearchAgainstSubject) || searchEveryWhere)) {
88 searchMatches = true;
89 } else if (containString(item->sender()) && ((mOptions & QuickSearchLine::SearchAgainstFrom) || searchEveryWhere)) {
90 searchMatches = true;
91 } else if (containString(item->receiver()) && ((mOptions & QuickSearchLine::SearchAgainstTo) || searchEveryWhere)) {
92 searchMatches = true;
93 }
94 if (!searchMatches) {
95 return false;
96 }
97 }
98
99 if (!mTagId.isEmpty()) {
100 // mTagId is a Akonadi::Tag::url
101 const bool tagMatches = item->findTag(mTagId) != nullptr;
102 if (!tagMatches) {
103 return false;
104 }
105 }
106
107 return true;
108}
109
110QList<Akonadi::MessageStatus> Filter::status() const
111{
112 return mStatus;
113}
114
115void Filter::setStatus(const QList<Akonadi::MessageStatus> &lstStatus)
116{
117 mStatus = lstStatus;
118}
119
120bool Filter::isEmpty() const
121{
122 if (!mStatus.isEmpty()) {
123 return false;
124 }
125
126 if (!mSearchString.isEmpty()) {
127 return false;
128 }
129
130 if (!mTagId.isEmpty()) {
131 return false;
132 }
133
134 return true;
135}
136
137void Filter::clear()
138{
139 mStatus.clear();
140 mSearchString.clear();
141 mTagId.clear();
142 mMatchingItemIds.clear();
143 mSearchList.clear();
144}
145
146void Filter::setCurrentFolder(const Akonadi::Collection &folder)
147{
148 mCurrentFolder = folder;
149}
150
151const QString &Filter::searchString() const
152{
153 return mSearchString;
154}
155
156QuickSearchLine::SearchOptions Filter::currentOptions() const
157{
158 return mOptions;
159}
160
161void Filter::save(const KSharedConfig::Ptr &config, const QString &filtername, const QString &iconName, int numFilter)
162{
163 KConfigGroup grp(config, QStringLiteral("General"));
164 int numberFilter = (numFilter == -1) ? grp.readEntry("NumberFilter").toInt() : numFilter;
165 KConfigGroup newGroup(config, QStringLiteral("Filter_%1").arg(numberFilter++));
166 newGroup.writeEntry("name", filtername);
167 if (!iconName.isEmpty()) {
168 newGroup.writeEntry("iconName", iconName);
169 }
170 newGroup.writeEntry("searchString", mSearchString);
171 newGroup.writeEntry("searchOptions", static_cast<int>(mOptions));
172 newGroup.writeEntry("tagId", mTagId);
173 newGroup.writeEntry("identifier", mIdentifier);
174 QList<qint32> lst;
175 lst.reserve(mStatus.count());
176 for (const auto s : std::as_const(mStatus)) {
177 lst << s.toQInt32();
178 }
179 newGroup.writeEntry("status", lst);
180 newGroup.sync();
181 grp.writeEntry("NumberFilter", numberFilter);
182 grp.sync();
183 config->reparseConfiguration();
184}
185
186Filter *Filter::load(const KSharedConfig::Ptr &config, int filternumber)
187{
188 KConfigGroup grp(config, QStringLiteral("General"));
189 int numberFilter = grp.readEntry("NumberFilter").toInt();
191 KConfigGroup newGroup(config, QStringLiteral("Filter_%1").arg(filternumber));
192 return loadFromConfigGroup(newGroup);
193 }
194 return nullptr;
195}
196
197Filter *Filter::loadFromConfigGroup(const KConfigGroup &newGroup)
198{
199 auto filter = new Filter();
200 filter->setSearchString(newGroup.readEntry("searchString"), static_cast<QuickSearchLine::SearchOptions>(newGroup.readEntry("searchOptions").toInt()));
201 filter->setTagId(newGroup.readEntry("tagId"));
202 filter->setIdentifier(newGroup.readEntry("identifier"));
203 filter->setFilterName(newGroup.readEntry("name"));
204 filter->setIconName(newGroup.readEntry("iconName"));
205 const QList<qint32> lst = newGroup.readEntry("status", QList<qint32>());
207 messageStatusLst.reserve(lst.count());
208 for (const auto s : std::as_const(lst)) {
212 }
213 filter->setStatus(messageStatusLst);
214 filter->setOptions(static_cast<QuickSearchLine::SearchOptions>(newGroup.readEntry("searchOptions").toInt()));
215 return filter;
216}
217
218void Filter::setSearchString(const QString &search, QuickSearchLine::SearchOptions options)
219{
220 const QString trimStr = search.trimmed();
221 if ((mSearchString == trimStr) && (mOptions == options)) {
222 return;
223 }
224 mOptions = options;
225 mSearchString = trimStr;
226 mMatchingItemIds.clear();
227
228 if (mSearchString.isEmpty()) {
229 return;
230 }
231 bool needToSplitString = false;
232 QString newStr = mSearchString;
233 if (mSearchString.startsWith(QLatin1Char('"')) && mSearchString.startsWith(QLatin1Char('"'))) {
234 newStr.remove(0, 1);
235 newStr.remove(newStr.length() - 1, 1);
236 mSearchList = QStringList() << newStr;
237 } else {
238 const QStringList searchListTmp = mSearchString.split(QLatin1Char(' '), Qt::SkipEmptyParts);
239 mSearchList.clear();
240 newStr.clear();
241 for (const QString &text : searchListTmp) {
242 if (text.size() >= 3) {
243 mSearchList << text;
244 if (!newStr.isEmpty()) {
245 newStr += QLatin1Char(' ');
246 }
247 newStr += text;
248 }
249 }
250 needToSplitString = true;
251 }
252 if (!newStr.trimmed().isEmpty()) {
254 if (options & QuickSearchLine::SearchEveryWhere) {
255 query.matches(newStr);
256 query.setSplitSearchMatchString(needToSplitString);
257 } else if (options & QuickSearchLine::SearchAgainstSubject) {
258 query.subjectMatches(newStr);
259 } else if (options & QuickSearchLine::SearchAgainstBody) {
260 query.bodyMatches(newStr);
261 } else if (options & QuickSearchLine::SearchAgainstFrom) {
262 query.setFrom(newStr);
263 } else if (options & QuickSearchLine::SearchAgainstBcc) {
264 query.setBcc(QStringList() << newStr);
265 } else if (options & QuickSearchLine::SearchAgainstTo) {
266 query.setTo(QStringList() << newStr);
267 }
268
269 // If the collection is virtual we're probably trying to filter the search collection, so we just search globally
270 if (mCurrentFolder.isValid() && !mCurrentFolder.isVirtual()) {
271 query.addCollection(mCurrentFolder.id());
272 }
273
275 while (it.next()) {
276 mMatchingItemIds << it.id();
277 }
278 }
279 Q_EMIT finished();
280}
281
282const QString &Filter::tagId() const
283{
284 return mTagId;
285}
286
287void Filter::setTagId(const QString &tagId)
288{
289 mTagId = tagId;
290}
291
292void Filter::generateRandomIdentifier()
293{
294 mIdentifier = KRandom::randomString(16);
295}
296
297QString Filter::identifier() const
298{
299 return mIdentifier;
300}
301
302QDebug operator<<(QDebug d, const MessageList::Core::Filter &t)
303{
304 d << "filtername " << t.filterName();
305 d << "identifier " << t.identifier();
306 d << "search string " << t.searchString();
307 d << "search option " << t.currentOptions();
308 d << "status " << t.status();
309 return d;
310}
311
312#include "moc_filter.cpp"
void fromQInt32(qint32 status)
This class is responsible of matching messages that should be displayed in the View.
Definition filter.h:33
QList< Akonadi::MessageStatus > status() const
Returns the currently set status mask.
Definition filter.cpp:110
const QString & searchString() const
Returns the currently set search string.
Definition filter.cpp:151
const QString & receiver() const
Returns the receiver associated to this item.
Definition item.cpp:501
const Akonadi::MessageStatus & status() const
Returns the status associated to this Item.
Definition item.cpp:446
const QString & sender() const
Returns the sender associated to this item.
Definition item.cpp:486
const QString & subject() const
Returns the subject associated to this Item.
Definition item.cpp:531
The MessageItem class.
Definition messageitem.h:35
const Tag * findTag(const QString &szTagId) const
Returns Tag associated to this message that has the specified id or 0 if no such tag exists.
Q_SCRIPTABLE CaptureState status()
KCOREADDONS_EXPORT QString randomString(int length)
The implementation independent part of the MessageList library.
Definition aggregation.h:22
int count(const T &value) const const
void reserve(int alloc)
Q_EMITQ_EMIT
T qobject_cast(QObject *object)
bool isEmpty() const const
QString trimmed() const const
CaseInsensitive
SkipEmptyParts
QFuture< void > filter(Sequence &sequence, KeepFunctor filterFunction)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:37:31 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.