KNewStuff

tagsfilterchecker.cpp
1/*
2 SPDX-FileCopyrightText: 2018 Dan Leinir Turthra Jensen <admin@leinir.dk>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#include "tagsfilterchecker.h"
8
9#include <knewstuffcore_debug.h>
10
11#include <QMap>
12
13namespace KNSCore
14{
15class TagsFilterCheckerPrivate
16{
17public:
18 TagsFilterCheckerPrivate()
19 {
20 }
21 ~TagsFilterCheckerPrivate()
22 {
23 qDeleteAll(validators);
24 }
25 class Validator;
26 // If people start using a LOT of validators (>20ish), we can always change it, but
27 // for now it seems reasonable that QMap is better than QHash here...
29
30 class Validator
31 {
32 public:
33 Validator(const QString &tag, const QString &value)
34 : m_tag(tag)
35 {
36 if (!value.isNull()) {
37 m_acceptedValues << value;
38 }
39 }
40 virtual ~Validator()
41 {
42 }
43 virtual bool filterAccepts(const QString &tag, const QString &value) = 0;
44
45 protected:
46 friend class TagsFilterCheckerPrivate;
47 QString m_tag;
48 QStringList m_acceptedValues;
49 };
50
51 // Will only accept entries which have one of the accepted values set for the tag key
52 class EqualityValidator : public Validator
53 {
54 public:
55 EqualityValidator(const QString &tag, const QString &value)
56 : Validator(tag, value)
57 {
58 }
59 ~EqualityValidator() override
60 {
61 }
62 bool filterAccepts(const QString &tag, const QString &value) override
63 {
64 bool result = true;
65 if (tag == m_tag && !m_acceptedValues.contains(value)) {
66 qCDebug(KNEWSTUFFCORE) << "Item excluded by filter on" << m_tag << "because" << value << "was not included in" << m_acceptedValues;
67 result = false;
68 }
69 return result;
70 }
71 };
72
73 // Will only accept entries which have none of the values set for the tag key
74 class InequalityValidator : public Validator
75 {
76 public:
77 InequalityValidator(const QString &tag, const QString &value)
78 : Validator(tag, value)
79 {
80 }
81 ~InequalityValidator() override
82 {
83 }
84 bool filterAccepts(const QString &tag, const QString &value) override
85 {
86 bool result = true;
87 if (tag == m_tag && m_acceptedValues.contains(value)) {
88 qCDebug(KNEWSTUFFCORE) << "Item excluded by filter on" << m_tag << "because" << value << "was included in" << m_acceptedValues;
89 result = false;
90 }
91 return result;
92 }
93 };
94
95 void addValidator(const QString &filter)
96 {
97 int pos = 0;
98 if ((pos = filter.indexOf(QLatin1String("=="))) > -1) {
99 QString tag = filter.left(pos);
100 QString value = filter.mid(tag.length() + 2);
101 Validator *val = validators.value(tag, nullptr);
102 if (!val) {
103 val = new EqualityValidator(tag, QString());
104 validators.insert(tag, val);
105 }
106 val->m_acceptedValues << value;
107 qCDebug(KNEWSTUFFCORE) << "Created EqualityValidator for tag" << tag << "with value" << value;
108 } else if ((pos = filter.indexOf(QLatin1String("!="))) > -1) {
109 QString tag = filter.left(pos);
110 QString value = filter.mid(tag.length() + 2);
111 Validator *val = validators.value(tag, nullptr);
112 if (!val) {
113 val = new InequalityValidator(tag, QString());
114 validators.insert(tag, val);
115 }
116 val->m_acceptedValues << value;
117 qCDebug(KNEWSTUFFCORE) << "Created InequalityValidator for tag" << tag << "with value" << value;
118 } else {
119 qCDebug(KNEWSTUFFCORE) << "Critical error attempting to create tag filter validators. The filter is defined as" << filter
120 << "which is not in the accepted formats key==value or key!=value";
121 }
122 }
123};
124
126 : d(new TagsFilterCheckerPrivate)
127{
128 for (const QString &filter : tagFilter) {
129 d->addValidator(filter);
130 }
131}
132
133TagsFilterChecker::~TagsFilterChecker() = default;
134
136{
137 // if any tag in the content matches any of the tag filters, skip this entry
138 qCDebug(KNEWSTUFFCORE) << "Checking tags list" << tags << "against validators with keys" << d->validators.keys();
139 for (const QString &tag : tags) {
140 if (tag.isEmpty()) {
141 // This happens when you do a split on an empty string (not an empty list, a list with one empty element... because reasons).
142 // Also handy for other things, i guess, though, so let's just catch it here.
143 continue;
144 }
145 QStringList current = tag.split(QLatin1Char('='));
146 if (current.length() > 2) {
147 qCDebug(KNEWSTUFFCORE) << "Critical error attempting to filter tags. Entry has tag defined as" << tag
148 << "which is not in the format \"key=value\" or \"key\".";
149 return false;
150 } else if (current.length() == 1) {
151 // If the tag is defined simply as a key, we give it the value "1", just to make our filtering work simpler
152 current << QStringLiteral("1");
153 }
155 while (i != d->validators.constEnd()) {
156 if (!i.value()->filterAccepts(current.at(0), current.at(1))) {
157 return false;
158 }
159 ++i;
160 }
161 }
162 // If we have arrived here, nothing has filtered the entry
163 // out (by being either incorrectly tagged or a filter rejecting
164 // it), and consequently it is an acceptable entry.
165 return true;
166}
167
168}
TagsFilterChecker(const QStringList &tagFilter)
Constructs an instance of the tags filter checker, prepopulated with the list of tag filters in the t...
bool filterAccepts(const QStringList &tags)
Check whether the filter list accepts the passed list of tags.
const_reference at(qsizetype i) const const
qsizetype length() const const
iterator insert(const Key &key, const T &value)
T value(const Key &key, const T &defaultValue) const const
bool isEmpty() const const
bool isNull() const const
qsizetype length() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 6 2024 12:13:34 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.