KNewStuff

tagsfilterchecker.cpp
1 /*
2  SPDX-FileCopyrightText: 2018 Dan Leinir Turthra Jensen <[email protected]>
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 
13 namespace KNSCore
14 {
15 class TagsFilterChecker::Private
16 {
17 public:
18  Private()
19  {
20  }
21  ~Private()
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...
28  QMap<QString, Validator *> validators;
29 
30  class Validator
31  {
32  public:
33  Validator(const QString &tag, const QString &value)
34  {
35  m_tag = tag;
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 TagsFilterChecker::Private;
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 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
151  << "which is not in the format \"key=value\" or \"key\".";
152  return false;
153  } else if (current.length() == 1) {
154  // If the tag is defined simply as a key, we give it the value "1", just to make our filtering work simpler
155  current << QStringLiteral("1");
156  }
158  while (i != d->validators.constEnd()) {
159  if (!i.value()->filterAccepts(current.at(0), current.at(1))) {
160  return false;
161  }
162  ++i;
163  }
164  }
165  // If we have arrived here, nothing has filtered the entry
166  // out (by being either incorrectly tagged or a filter rejecting
167  // it), and consequently it is an acceptable entry.
168  return true;
169 }
170 
171 }
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-2021 The KDE developers.
Generated on Tue Nov 30 2021 22:38:13 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.