File indexing completed on 2024-05-12 04:01:51
0001 /* 0002 SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "predicate.h" 0008 0009 #include <QMetaEnum> 0010 #include <QSequentialIterable> 0011 #include <QStringList> 0012 #include <solid/device.h> 0013 0014 namespace Solid 0015 { 0016 class Predicate::Private 0017 { 0018 public: 0019 Private() 0020 : isValid(false) 0021 , type(PropertyCheck) 0022 , compOperator(Predicate::Equals) 0023 , operand1(nullptr) 0024 , operand2(nullptr) 0025 { 0026 } 0027 0028 bool isValid; 0029 Type type; 0030 0031 DeviceInterface::Type ifaceType; 0032 QString property; 0033 QVariant value; 0034 Predicate::ComparisonOperator compOperator; 0035 0036 Predicate *operand1; 0037 Predicate *operand2; 0038 }; 0039 } 0040 0041 Solid::Predicate::Predicate() 0042 : d(new Private()) 0043 { 0044 } 0045 0046 Solid::Predicate::Predicate(const Predicate &other) 0047 : d(new Private()) 0048 { 0049 *this = other; 0050 } 0051 0052 Solid::Predicate::Predicate(const DeviceInterface::Type &ifaceType, const QString &property, const QVariant &value, ComparisonOperator compOperator) 0053 : d(new Private()) 0054 { 0055 d->isValid = true; 0056 d->ifaceType = ifaceType; 0057 d->property = property; 0058 d->value = value; 0059 d->compOperator = compOperator; 0060 } 0061 0062 Solid::Predicate::Predicate(const QString &ifaceName, const QString &property, const QVariant &value, ComparisonOperator compOperator) 0063 : d(new Private()) 0064 { 0065 DeviceInterface::Type ifaceType = DeviceInterface::stringToType(ifaceName); 0066 0067 if (((int)ifaceType) != -1) { 0068 d->isValid = true; 0069 d->ifaceType = ifaceType; 0070 d->property = property; 0071 d->value = value; 0072 d->compOperator = compOperator; 0073 } 0074 } 0075 0076 Solid::Predicate::Predicate(const DeviceInterface::Type &ifaceType) 0077 : d(new Private()) 0078 { 0079 d->isValid = true; 0080 d->type = InterfaceCheck; 0081 d->ifaceType = ifaceType; 0082 } 0083 0084 Solid::Predicate::Predicate(const QString &ifaceName) 0085 : d(new Private()) 0086 { 0087 DeviceInterface::Type ifaceType = DeviceInterface::stringToType(ifaceName); 0088 0089 if (((int)ifaceType) != -1) { 0090 d->isValid = true; 0091 d->type = InterfaceCheck; 0092 d->ifaceType = ifaceType; 0093 } 0094 } 0095 0096 Solid::Predicate::~Predicate() 0097 { 0098 if (d->type != PropertyCheck && d->type != InterfaceCheck) { 0099 delete d->operand1; 0100 delete d->operand2; 0101 } 0102 0103 delete d; 0104 } 0105 0106 Solid::Predicate &Solid::Predicate::operator=(const Predicate &other) 0107 { 0108 d->isValid = other.d->isValid; 0109 d->type = other.d->type; 0110 0111 if (d->type != PropertyCheck && d->type != InterfaceCheck) { 0112 Predicate *operand1 = new Predicate(*(other.d->operand1)); 0113 delete d->operand1; 0114 d->operand1 = operand1; 0115 Predicate *operand2 = new Predicate(*(other.d->operand2)); 0116 delete d->operand2; 0117 d->operand2 = operand2; 0118 } else { 0119 d->ifaceType = other.d->ifaceType; 0120 d->property = other.d->property; 0121 d->value = other.d->value; 0122 d->compOperator = other.d->compOperator; 0123 } 0124 0125 return *this; 0126 } 0127 0128 Solid::Predicate Solid::Predicate::operator&(const Predicate &other) 0129 { 0130 Predicate result; 0131 0132 result.d->isValid = true; 0133 result.d->type = Conjunction; 0134 result.d->operand1 = new Predicate(*this); 0135 result.d->operand2 = new Predicate(other); 0136 0137 return result; 0138 } 0139 0140 Solid::Predicate &Solid::Predicate::operator&=(const Predicate &other) 0141 { 0142 *this = *this & other; 0143 return *this; 0144 } 0145 0146 Solid::Predicate Solid::Predicate::operator|(const Predicate &other) 0147 { 0148 Predicate result; 0149 0150 result.d->isValid = true; 0151 result.d->type = Disjunction; 0152 result.d->operand1 = new Predicate(*this); 0153 result.d->operand2 = new Predicate(other); 0154 0155 return result; 0156 } 0157 0158 Solid::Predicate &Solid::Predicate::operator|=(const Predicate &other) 0159 { 0160 *this = *this | other; 0161 return *this; 0162 } 0163 0164 bool Solid::Predicate::isValid() const 0165 { 0166 return d->isValid; 0167 } 0168 0169 bool Solid::Predicate::matches(const Device &device) const 0170 { 0171 if (!d->isValid) { 0172 return false; 0173 } 0174 0175 switch (d->type) { 0176 case Disjunction: 0177 return d->operand1->matches(device) || d->operand2->matches(device); 0178 case Conjunction: 0179 return d->operand1->matches(device) && d->operand2->matches(device); 0180 case PropertyCheck: { 0181 const DeviceInterface *iface = device.asDeviceInterface(d->ifaceType); 0182 0183 if (iface != nullptr) { 0184 const int index = iface->metaObject()->indexOfProperty(d->property.toLatin1()); 0185 QMetaProperty metaProp = iface->metaObject()->property(index); 0186 QVariant value = metaProp.isReadable() ? metaProp.read(iface) : QVariant(); 0187 QVariant expected = d->value; 0188 0189 if (metaProp.isEnumType() && expected.userType() == QMetaType::QString) { 0190 QMetaEnum metaEnum = metaProp.enumerator(); 0191 int value = metaEnum.keysToValue(d->value.toString().toLatin1()); 0192 if (value >= 0) { // No value found for these keys, resetting expected to invalid 0193 expected = QVariant(metaProp.metaType(), &value); 0194 } else { 0195 expected = QVariant(); 0196 } 0197 } else if (metaProp.isEnumType() && expected.userType() == QMetaType::Int) { 0198 int expectedValue = expected.toInt(); 0199 expected = QVariant(metaProp.metaType(), &expectedValue); 0200 } 0201 0202 if (d->compOperator == Mask) { 0203 bool v_ok; 0204 int v = value.toInt(&v_ok); 0205 bool e_ok; 0206 int e = expected.toInt(&e_ok); 0207 0208 return (e_ok && v_ok && (v & e)); 0209 } 0210 0211 if (value == expected) { 0212 return true; 0213 } 0214 0215 // Make sure we can match single elements inside lists. 0216 if (value.canConvert<QSequentialIterable>()) { 0217 const auto iterable = value.value<QSequentialIterable>(); 0218 for (const auto &element : iterable) { 0219 if (element == expected) { 0220 return true; 0221 } 0222 } 0223 } 0224 } 0225 break; 0226 } 0227 case InterfaceCheck: 0228 return device.isDeviceInterface(d->ifaceType); 0229 } 0230 0231 return false; 0232 } 0233 0234 QSet<Solid::DeviceInterface::Type> Solid::Predicate::usedTypes() const 0235 { 0236 QSet<DeviceInterface::Type> res; 0237 0238 if (d->isValid) { 0239 switch (d->type) { 0240 case Disjunction: 0241 case Conjunction: 0242 res += d->operand1->usedTypes(); 0243 res += d->operand2->usedTypes(); 0244 break; 0245 case PropertyCheck: 0246 case InterfaceCheck: 0247 res << d->ifaceType; 0248 break; 0249 } 0250 } 0251 0252 return res; 0253 } 0254 0255 QString Solid::Predicate::toString() const 0256 { 0257 if (!d->isValid) { 0258 return "False"; 0259 } 0260 0261 if (d->type != PropertyCheck && d->type != InterfaceCheck) { 0262 QString op = " AND "; 0263 if (d->type == Disjunction) { 0264 op = " OR "; 0265 } 0266 0267 return '[' + d->operand1->toString() + op + d->operand2->toString() + ']'; 0268 } else { 0269 QString ifaceName = DeviceInterface::typeToString(d->ifaceType); 0270 0271 if (ifaceName.isEmpty()) { 0272 ifaceName = "Unknown"; 0273 } 0274 0275 if (d->type == InterfaceCheck) { 0276 return "IS " + ifaceName; 0277 } 0278 0279 QString value; 0280 0281 switch (d->value.userType()) { 0282 case QMetaType::QStringList: { 0283 value = '{'; 0284 0285 const QStringList list = d->value.toStringList(); 0286 0287 QStringList::ConstIterator it = list.begin(); 0288 QStringList::ConstIterator end = list.end(); 0289 0290 for (; it != end; ++it) { 0291 value += '\'' + *it + '\''; 0292 0293 if (it + 1 != end) { 0294 value += ", "; 0295 } 0296 } 0297 0298 value += '}'; 0299 break; 0300 } 0301 case QMetaType::Bool: 0302 value = (d->value.toBool() ? "true" : "false"); 0303 break; 0304 case QMetaType::Int: 0305 case QMetaType::UInt: 0306 case QMetaType::LongLong: 0307 case QMetaType::ULongLong: 0308 value = d->value.toString(); 0309 break; 0310 default: 0311 value = '\'' + d->value.toString() + '\''; 0312 break; 0313 } 0314 0315 QString str_operator = "=="; 0316 if (d->compOperator != Equals) { 0317 str_operator = " &"; 0318 } 0319 0320 return ifaceName + '.' + d->property + ' ' + str_operator + ' ' + value; 0321 } 0322 } 0323 0324 Solid::Predicate::Type Solid::Predicate::type() const 0325 { 0326 return d->type; 0327 } 0328 0329 Solid::DeviceInterface::Type Solid::Predicate::interfaceType() const 0330 { 0331 return d->ifaceType; 0332 } 0333 0334 QString Solid::Predicate::propertyName() const 0335 { 0336 return d->property; 0337 } 0338 0339 QVariant Solid::Predicate::matchingValue() const 0340 { 0341 return d->value; 0342 } 0343 0344 Solid::Predicate::ComparisonOperator Solid::Predicate::comparisonOperator() const 0345 { 0346 return d->compOperator; 0347 } 0348 0349 Solid::Predicate Solid::Predicate::firstOperand() const 0350 { 0351 if (d->operand1) { 0352 return *d->operand1; 0353 } 0354 return Predicate(); 0355 } 0356 0357 Solid::Predicate Solid::Predicate::secondOperand() const 0358 { 0359 if (d->operand2) { 0360 return *d->operand2; 0361 } 0362 return Predicate(); 0363 }