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 
16 class TagsFilterChecker::Private
17 {
18 public:
19  Private() {}
20  ~Private()
21  {
22  qDeleteAll(validators);
23  }
24  class Validator;
25  // If people start using a LOT of validators (>20ish), we can always change it, but
26  // for now it seems reasonable that QMap is better than QHash here...
27  QMap<QString, Validator*> validators;
28 
29  class Validator
30  {
31  public:
32  Validator(const QString &tag, const QString &value)
33  {
34  m_tag = tag;
35  if (!value.isNull()) {
36  m_acceptedValues << value;
37  }
38  }
39  virtual ~Validator() {}
40  virtual bool filterAccepts(const QString &tag, const QString &value) = 0;
41  protected:
42  friend class TagsFilterChecker::Private;
43  QString m_tag;
44  QStringList m_acceptedValues;
45  };
46 
47  // Will only accept entries which have one of the accepted values set for the tag key
48  class EqualityValidator : public Validator
49  {
50  public:
51  EqualityValidator(const QString &tag, const QString &value)
52  : Validator(tag, value)
53  {}
54  ~EqualityValidator() override {}
55  bool filterAccepts(const QString &tag, const QString &value) override
56  {
57  bool result = true;
58  if (tag == m_tag && !m_acceptedValues.contains(value)) {
59  qCDebug(KNEWSTUFFCORE) << "Item excluded by filter on" << m_tag << "because" << value << "was not included in" << m_acceptedValues;
60  result = false;
61  }
62  return result;
63  }
64  };
65 
66  // Will only accept entries which have none of the values set for the tag key
67  class InequalityValidator : public Validator
68  {
69  public:
70  InequalityValidator(const QString &tag, const QString &value)
71  : Validator(tag, value)
72  {}
73  ~InequalityValidator() override {}
74  bool filterAccepts(const QString &tag, const QString &value) override
75  {
76  bool result = true;
77  if (tag == m_tag && m_acceptedValues.contains(value)) {
78  qCDebug(KNEWSTUFFCORE) << "Item excluded by filter on" << m_tag << "because" << value << "was included in" << m_acceptedValues;
79  result = false;
80  }
81  return result;
82  }
83  };
84 
85  void addValidator(const QString &filter)
86  {
87  int pos = 0;
88  if ((pos = filter.indexOf(QLatin1String("=="))) > -1) {
89  QString tag = filter.left(pos);
90  QString value = filter.mid(tag.length() + 2);
91  Validator *val = validators.value(tag, nullptr);
92  if (!val) {
93  val = new EqualityValidator(tag, QString());
94  validators.insert(tag, val);
95  }
96  val->m_acceptedValues << value;
97  qCDebug(KNEWSTUFFCORE) << "Created EqualityValidator for tag" << tag << "with value" << value;
98  } else 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 InequalityValidator(tag, QString());
104  validators.insert(tag, val);
105  }
106  val->m_acceptedValues << value;
107  qCDebug(KNEWSTUFFCORE) << "Created InequalityValidator for tag" << tag << "with value" << value;
108  } else {
109  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";
110  }
111  }
112 };
113 
115  : d(new TagsFilterChecker::Private)
116 {
117  for (const QString &filter : tagFilter) {
118  d->addValidator(filter);
119  }
120 }
121 
122 TagsFilterChecker::~TagsFilterChecker()
123 {
124  delete d;
125 }
126 
128 {
129  // if any tag in the content matches any of the tag filters, skip this entry
130  qCDebug(KNEWSTUFFCORE) << "Checking tags list" << tags << "against validators with keys" << d->validators.keys();
131  for (const QString &tag : tags) {
132  if (tag.isEmpty()) {
133  // This happens when you do a split on an empty string (not an empty list, a list with one empty element... because reasons).
134  // Also handy for other things, i guess, though, so let's just catch it here.
135  continue;
136  }
137  QStringList current = tag.split(QLatin1Char('='));
138  if (current.length() > 2) {
139  qCDebug(KNEWSTUFFCORE) << "Critical error attempting to filter tags. Entry has tag defined as" << tag << "which is not in the format \"key=value\" or \"key\".";
140  return false;
141  } else if (current.length() == 1) {
142  // If the tag is defined simply as a key, we give it the value "1", just to make our filtering work simpler
143  current << QStringLiteral("1");
144  }
146  while (i != d->validators.constEnd()) {
147  if (!i.value()->filterAccepts(current.at(0), current.at(1))) {
148  return false;
149  }
150  ++i;
151  }
152  }
153  // If we have arrived here, nothing has filtered the entry
154  // out (by being either incorrectly tagged or a filter rejecting
155  // it), and consequently it is an acceptable entry.
156  return true;
157 }
158 
159 }
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 Mon Jan 18 2021 22:43:50 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.