Solid

predicate.cpp
1/*
2 SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "predicate.h"
8
9#include <QMetaEnum>
10#include <QSequentialIterable>
11#include <QStringList>
12#include <solid/device.h>
13
14namespace Solid
15{
16class Predicate::Private
17{
18public:
19 Private()
20 : isValid(false)
21 , type(PropertyCheck)
22 , compOperator(Predicate::Equals)
23 , operand1(nullptr)
24 , operand2(nullptr)
25 {
26 }
27
28 bool isValid;
29 Type type;
30
31 DeviceInterface::Type ifaceType;
32 QString property;
33 QVariant value;
35
36 Predicate *operand1;
37 Predicate *operand2;
38};
39}
40
42 : d(new Private())
43{
44}
45
47 : d(new Private())
48{
49 *this = other;
50}
51
52Solid::Predicate::Predicate(const DeviceInterface::Type &ifaceType, const QString &property, const QVariant &value, ComparisonOperator compOperator)
53 : d(new Private())
54{
55 d->isValid = true;
56 d->ifaceType = ifaceType;
57 d->property = property;
58 d->value = value;
59 d->compOperator = compOperator;
60}
61
62Solid::Predicate::Predicate(const QString &ifaceName, const QString &property, const QVariant &value, ComparisonOperator compOperator)
63 : d(new Private())
64{
66
67 if (((int)ifaceType) != -1) {
68 d->isValid = true;
69 d->ifaceType = ifaceType;
70 d->property = property;
71 d->value = value;
72 d->compOperator = compOperator;
73 }
74}
75
77 : d(new Private())
78{
79 d->isValid = true;
80 d->type = InterfaceCheck;
81 d->ifaceType = ifaceType;
82}
83
85 : d(new Private())
86{
88
89 if (((int)ifaceType) != -1) {
90 d->isValid = true;
91 d->type = InterfaceCheck;
92 d->ifaceType = ifaceType;
93 }
94}
95
97{
98 if (d->type != PropertyCheck && d->type != InterfaceCheck) {
99 delete d->operand1;
100 delete d->operand2;
101 }
102
103 delete d;
104}
105
107{
108 d->isValid = other.d->isValid;
109 d->type = other.d->type;
110
111 if (d->type != PropertyCheck && d->type != InterfaceCheck) {
112 Predicate *operand1 = new Predicate(*(other.d->operand1));
113 delete d->operand1;
114 d->operand1 = operand1;
115 Predicate *operand2 = new Predicate(*(other.d->operand2));
116 delete d->operand2;
117 d->operand2 = operand2;
118 } else {
119 d->ifaceType = other.d->ifaceType;
120 d->property = other.d->property;
121 d->value = other.d->value;
122 d->compOperator = other.d->compOperator;
123 }
124
125 return *this;
126}
127
129{
130 Predicate result;
131
132 result.d->isValid = true;
133 result.d->type = Conjunction;
134 result.d->operand1 = new Predicate(*this);
135 result.d->operand2 = new Predicate(other);
136
137 return result;
138}
139
141{
142 *this = *this & other;
143 return *this;
144}
145
147{
148 Predicate result;
149
150 result.d->isValid = true;
151 result.d->type = Disjunction;
152 result.d->operand1 = new Predicate(*this);
153 result.d->operand2 = new Predicate(other);
154
155 return result;
156}
157
159{
160 *this = *this | other;
161 return *this;
162}
163
165{
166 return d->isValid;
167}
168
169bool Solid::Predicate::matches(const Device &device) const
170{
171 if (!d->isValid) {
172 return false;
173 }
174
175 switch (d->type) {
176 case Disjunction:
177 return d->operand1->matches(device) || d->operand2->matches(device);
178 case Conjunction:
179 return d->operand1->matches(device) && d->operand2->matches(device);
180 case PropertyCheck: {
181 const DeviceInterface *iface = device.asDeviceInterface(d->ifaceType);
182
183 if (iface != nullptr) {
184 const int index = iface->metaObject()->indexOfProperty(d->property.toLatin1().constData());
185 QMetaProperty metaProp = iface->metaObject()->property(index);
186 QVariant value = metaProp.isReadable() ? metaProp.read(iface) : QVariant();
187 QVariant expected = d->value;
188
189 if (metaProp.isEnumType() && expected.userType() == QMetaType::QString) {
190 QMetaEnum metaEnum = metaProp.enumerator();
191 int value = metaEnum.keysToValue(d->value.toString().toLatin1().constData());
192 if (value >= 0) { // No value found for these keys, resetting expected to invalid
193 expected = QVariant(metaProp.metaType(), &value);
194 } else {
195 expected = QVariant();
196 }
197 } else if (metaProp.isEnumType() && expected.userType() == QMetaType::Int) {
198 int expectedValue = expected.toInt();
199 expected = QVariant(metaProp.metaType(), &expectedValue);
200 }
201
202 if (d->compOperator == Mask) {
203 bool v_ok;
204 int v = value.toInt(&v_ok);
205 bool e_ok;
206 int e = expected.toInt(&e_ok);
207
208 return (e_ok && v_ok && (v & e));
209 }
210
211 if (value == expected) {
212 return true;
213 }
214
215 // Make sure we can match single elements inside lists.
216 if (value.canConvert<QSequentialIterable>()) {
217 const auto iterable = value.value<QSequentialIterable>();
218 for (const auto &element : iterable) {
219 if (element == expected) {
220 return true;
221 }
222 }
223 }
224 }
225 break;
226 }
227 case InterfaceCheck:
228 return device.isDeviceInterface(d->ifaceType);
229 }
230
231 return false;
232}
233
235{
237
238 if (d->isValid) {
239 switch (d->type) {
240 case Disjunction:
241 case Conjunction:
242 res += d->operand1->usedTypes();
243 res += d->operand2->usedTypes();
244 break;
245 case PropertyCheck:
246 case InterfaceCheck:
247 res << d->ifaceType;
248 break;
249 }
250 }
251
252 return res;
253}
254
256{
257 if (!d->isValid) {
258 return QStringLiteral("False");
259 }
260
261 if (d->type != PropertyCheck && d->type != InterfaceCheck) {
262 QString op = QStringLiteral("AND");
263 if (d->type == Disjunction) {
264 op = QStringLiteral("OR");
265 }
266
267 return QStringLiteral("[%1 %2 %3]").arg(d->operand1->toString(), op, d->operand2->toString());
268 } else {
269 QString ifaceName = DeviceInterface::typeToString(d->ifaceType);
270
271 if (ifaceName.isEmpty()) {
272 ifaceName = QStringLiteral("Unknown");
273 }
274
275 if (d->type == InterfaceCheck) {
276 return QStringLiteral("IS ") + ifaceName;
277 }
278
279 QString value;
280
281 switch (d->value.userType()) {
283 const QStringList list = d->value.toStringList();
284 if (list.isEmpty()) {
285 value = QStringLiteral("{}");
286 } else {
287 value = QStringLiteral("{'") + list.join(QStringLiteral("', '")) + QStringLiteral("'}'");
288 }
289 break;
290 }
291 case QMetaType::Bool:
292 value = (d->value.toBool() ? QStringLiteral("true") : QStringLiteral("false"));
293 break;
294 case QMetaType::Int:
295 case QMetaType::UInt:
298 value = d->value.toString();
299 break;
300 default:
301 value = QStringLiteral("'%1'").arg(d->value.toString());
302 break;
303 }
304
305 QString str_operator = QStringLiteral("==");
306 if (d->compOperator != Equals) {
307 str_operator = QStringLiteral(" &");
308 }
309
310 return QStringLiteral("%1.%2 %3 %4").arg(ifaceName, d->property, str_operator, value);
311 }
312}
313
315{
316 return d->type;
317}
318
320{
321 return d->ifaceType;
322}
323
325{
326 return d->property;
327}
328
330{
331 return d->value;
332}
333
338
340{
341 if (d->operand1) {
342 return *d->operand1;
343 }
344 return Predicate();
345}
346
348{
349 if (d->operand2) {
350 return *d->operand2;
351 }
352 return Predicate();
353}
Base class of all the device interfaces.
static QString typeToString(Type type)
Type
This enum type defines the type of device interface that a Device can have.
static Type stringToType(const QString &type)
This class allows applications to deal with devices available in the underlying system.
bool isDeviceInterface(const DeviceInterface::Type &type) const
Tests if a device interface is available from the device.
DeviceInterface * asDeviceInterface(const DeviceInterface::Type &type)
Retrieves a specialized interface to interact with the device corresponding to a particular device in...
This class implements predicates for devices.
bool matches(const Device &device) const
Checks if a device matches the predicate.
ComparisonOperator comparisonOperator() const
Retrieves the comparison operator used to compare a property's value.
Predicate()
Constructs an invalid predicate.
Definition predicate.cpp:41
Predicate operator|(const Predicate &other)
'Or' operator.
QString toString() const
Converts the predicate to its string form.
bool isValid() const
Indicates if the predicate is valid.
Predicate operator&(const Predicate &other)
'And' operator.
Predicate secondOperand() const
A smaller, inner predicate which is the second to appear and is compared with the first one.
QString propertyName() const
Retrieves the property name used when retrieving the value to compare against.
ComparisonOperator
The comparison operator which can be used for matching within the predicate.
Definition predicate.h:75
Predicate & operator&=(const Predicate &other)
'AndEquals' operator.
QVariant matchingValue() const
Retrieves the value used when comparing a devices property to see if it matches the predicate.
Predicate firstOperand() const
A smaller, inner predicate which is the first to appear and is compared with the second one.
DeviceInterface::Type interfaceType() const
Retrieves the interface type.
Type
The predicate type which controls how the predicate is handled.
Definition predicate.h:85
Predicate & operator=(const Predicate &other)
Assignment operator.
Predicate & operator|=(const Predicate &other)
'OrEquals' operator.
~Predicate()
Destroys a Predicate object.
Definition predicate.cpp:96
QSet< DeviceInterface::Type > usedTypes() const
Retrieves the device interface types used in this predicate.
Type type() const
Retrieves the predicate type, used to determine how to handle the predicate.
bool isEmpty() const const
T value(qsizetype i) const const
int keysToValue(const char *keys, bool *ok) const const
int indexOfProperty(const char *name) const const
QMetaProperty property(int index) const const
QMetaEnum enumerator() const const
bool isEnumType() const const
bool isReadable() const const
QMetaType metaType() const const
QVariant read(const QObject *object) const const
virtual const QMetaObject * metaObject() const const
QString arg(Args &&... args) const const
bool isEmpty() const const
QString join(QChar separator) const const
bool canConvert() const const
int toInt(bool *ok) const const
int userType() const const
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:14:22 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.