KNewStuff

tagsfilterchecker.cpp
1 /*
2  Copyright (c) 2018 Dan Leinir Turthra Jensen <[email protected]>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "tagsfilterchecker.h"
19 
20 #include <knewstuffcore_debug.h>
21 
22 #include <QMap>
23 
24 namespace KNSCore
25 {
26 
27 class TagsFilterChecker::Private
28 {
29 public:
30  Private() {}
31  ~Private()
32  {
33  qDeleteAll(validators);
34  }
35  class Validator;
36  // If people start using a LOT of validators (>20ish), we can always change it, but
37  // for now it seems reasonable that QMap is better than QHash here...
38  QMap<QString, Validator*> validators;
39 
40  class Validator
41  {
42  public:
43  Validator(const QString &tag, const QString &value)
44  {
45  m_tag = tag;
46  if (!value.isNull()) {
47  m_acceptedValues << value;
48  }
49  }
50  virtual ~Validator() {};
51  virtual bool filterAccepts(const QString &tag, const QString &value) = 0;
52  protected:
53  friend class TagsFilterChecker::Private;
54  QString m_tag;
55  QStringList m_acceptedValues;
56  };
57 
58  // Will only accept entries which have one of the accepted values set for the tag key
59  class EqualityValidator : public Validator
60  {
61  public:
62  EqualityValidator(const QString &tag, const QString &value)
63  : Validator(tag, value)
64  {}
65  ~EqualityValidator() override {}
66  bool filterAccepts(const QString &tag, const QString &value) override
67  {
68  bool result = true;
69  if (tag == m_tag && !m_acceptedValues.contains(value)) {
70  qCDebug(KNEWSTUFFCORE) << "Item excluded by filter on" << m_tag << "because" << value << "was not included in" << m_acceptedValues;
71  result = false;
72  }
73  return result;
74  }
75  };
76 
77  // Will only accept entries which have none of the values set for the tag key
78  class InequalityValidator : public Validator
79  {
80  public:
81  InequalityValidator(const QString &tag, const QString &value)
82  : Validator(tag, value)
83  {}
84  ~InequalityValidator() override {}
85  bool filterAccepts(const QString &tag, const QString &value) override
86  {
87  bool result = true;
88  if (tag == m_tag && m_acceptedValues.contains(value)) {
89  qCDebug(KNEWSTUFFCORE) << "Item excluded by filter on" << m_tag << "because" << value << "was included in" << m_acceptedValues;
90  result = false;
91  }
92  return result;
93  }
94  };
95 
96  void addValidator(const QString &filter)
97  {
98  int pos = 0;
99  if ((pos = filter.indexOf(QLatin1String("=="))) > -1) {
100  QString tag = filter.left(pos);
101  QString value = filter.mid(tag.length() + 2);
102  Validator *val = validators.value(tag, nullptr);
103  if (!val) {
104  val = new EqualityValidator(tag, QString());
105  validators.insert(tag, val);
106  }
107  val->m_acceptedValues << value;
108  qCDebug(KNEWSTUFFCORE) << "Created EqualityValidator for tag" << tag << "with value" << value;
109  } else if ((pos = filter.indexOf(QLatin1String("!="))) > -1) {
110  QString tag = filter.left(pos);
111  QString value = filter.mid(tag.length() + 2);
112  Validator *val = validators.value(tag, nullptr);
113  if (!val) {
114  val = new InequalityValidator(tag, QString());
115  validators.insert(tag, val);
116  }
117  val->m_acceptedValues << value;
118  qCDebug(KNEWSTUFFCORE) << "Created InequalityValidator for tag" << tag << "with value" << value;
119  } else {
120  qCDebug(KNEWSTUFFCORE) << "Critical error attempting to create tag filter validators. The filter is defined as" << filter << "which is not in the accepted formats key==value or key!=value";
121  }
122  }
123 };
124 
126  : d(new TagsFilterChecker::Private)
127 {
128  for (const QString &filter : tagFilter) {
129  d->addValidator(filter);
130  }
131 }
132 
133 TagsFilterChecker::~TagsFilterChecker()
134 {
135  delete d;
136 }
137 
139 {
140  // if any tag in the content matches any of the tag filters, skip this entry
141  qCDebug(KNEWSTUFFCORE) << "Checking tags list" << tags << "against validators with keys" << d->validators.keys();
142  for (const QString &tag : tags) {
143  if (tag.isEmpty()) {
144  // This happens when you do a split on an empty string (not an empty list, a list with one empty element... because reasons).
145  // Also handy for other things, i guess, though, so let's just catch it here.
146  continue;
147  }
148  QStringList current = tag.split(QLatin1Char('='));
149  if (current.length() > 2) {
150  qCDebug(KNEWSTUFFCORE) << "Critical error attempting to filter tags. Entry has tag defined as" << tag << "which is not in the format \"key=value\" or \"key\".";
151  return false;
152  } else if (current.length() == 1) {
153  // If the tag is defined simply as a key, we give it the value "1", just to make our filtering work simpler
154  current << QStringLiteral("1");
155  }
157  while (i != d->validators.constEnd()) {
158  if (!i.value()->filterAccepts(current.at(0), current.at(1))) {
159  return false;
160  }
161  ++i;
162  }
163  }
164  // If we have arrived here, nothing has filtered the entry
165  // out (by being either incorrectly tagged or a filter rejecting
166  // it), and consequently it is an acceptable entry.
167  return true;
168 }
169 
170 }
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
int length() const const
const T & at(int i) const const
Contains the core functionality for handling interaction with NewStuff providers. ...
bool isNull() const const
bool isEmpty() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
Apply simple filtering logic to a list of tags.
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString mid(int position, int n) const const
bool filterAccepts(const QStringList &tags)
Check whether the filter list accepts the passed list of tags.
int length() const const
QString left(int n) const const
QMap::iterator insert(const Key &key, const T &value)
TagsFilterChecker(const QStringList &tagFilter)
Constructs an instance of the tags filter checker, prepopulated with the list of tag filters in the t...
const T value(const Key &key, const T &defaultValue) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sun Aug 9 2020 22:43:40 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.