File indexing completed on 2025-01-26 03:44:29
0001 /* 0002 SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #include "surveytargetexpressionevaluator.h" 0008 #include "surveytargetexpression.h" 0009 0010 using namespace KUserFeedback; 0011 0012 SurveyTargetExpressionDataProvider::SurveyTargetExpressionDataProvider() 0013 { 0014 } 0015 0016 SurveyTargetExpressionDataProvider::~SurveyTargetExpressionDataProvider() 0017 { 0018 } 0019 0020 SurveyTargetExpressionEvaluator::SurveyTargetExpressionEvaluator() 0021 : m_provider(nullptr) 0022 { 0023 } 0024 0025 SurveyTargetExpressionEvaluator::~SurveyTargetExpressionEvaluator() 0026 { 0027 } 0028 0029 void SurveyTargetExpressionEvaluator::setDataProvider(const SurveyTargetExpressionDataProvider* provider) 0030 { 0031 m_provider = provider; 0032 } 0033 0034 static bool variantLess(const QVariant &lhs, const QVariant &rhs) 0035 { 0036 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0037 return QVariant::compare(lhs, rhs) == QPartialOrdering::Less; 0038 #else 0039 return lhs < rhs; 0040 #endif 0041 } 0042 0043 static bool variantLessOrEqual(const QVariant &lhs, const QVariant &rhs) 0044 { 0045 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0046 const auto order = QVariant::compare(lhs, rhs); 0047 return order == QPartialOrdering::Less || order == QPartialOrdering::Equivalent; 0048 #else 0049 return lhs <= rhs; 0050 #endif 0051 } 0052 0053 bool SurveyTargetExpressionEvaluator::evaluate(SurveyTargetExpression* expression) 0054 { 0055 // logical operations 0056 switch (expression->type()) { 0057 case SurveyTargetExpression::OpLogicAnd: 0058 return evaluate(expression->left()) && evaluate(expression->right()); 0059 case SurveyTargetExpression::OpLogicOr: 0060 return evaluate(expression->left()) || evaluate(expression->right()); 0061 default: 0062 break; 0063 } 0064 0065 // comparison operations: 0066 const auto lhs = value(expression->left()); 0067 const auto rhs = value(expression->right()); 0068 if (lhs.type() == QVariant::Invalid || rhs.type() == QVariant::Invalid) // invalid element access can never succeed 0069 return false; 0070 if ((lhs.type() == QVariant::String && rhs.type() != QVariant::String) 0071 || (lhs.type() != QVariant::String && rhs.type() == QVariant::String)) 0072 return false; // strings can only be compared to strings 0073 0074 switch (expression->type()) { 0075 case SurveyTargetExpression::OpEqual: 0076 return lhs == rhs; 0077 case SurveyTargetExpression::OpNotEqual: 0078 return lhs != rhs; 0079 case SurveyTargetExpression::OpGreater: 0080 return variantLess(rhs, lhs); 0081 case SurveyTargetExpression::OpGreaterEqual: 0082 return variantLessOrEqual(rhs, lhs); 0083 case SurveyTargetExpression::OpLess: 0084 return variantLess(lhs, rhs); 0085 case SurveyTargetExpression::OpLessEqual: 0086 return variantLessOrEqual(lhs, rhs); 0087 default: 0088 break; 0089 } 0090 0091 return false; 0092 } 0093 0094 QVariant SurveyTargetExpressionEvaluator::value(SurveyTargetExpression* expression) 0095 { 0096 switch (expression->type()) { 0097 case SurveyTargetExpression::Value: 0098 return expression->value(); 0099 case SurveyTargetExpression::ScalarElement: 0100 { 0101 const auto v = value(expression->source()); 0102 if (v.canConvert<QVariantList>() && expression->sourceElement() == QLatin1String("size")) 0103 return v.value<QVariantList>().size(); 0104 const auto m = v.toMap(); 0105 const auto it = m.find(expression->sourceElement()); 0106 if (it != m.end() && !it.value().canConvert<QVariantMap>()) 0107 return it.value(); 0108 if (expression->sourceElement() == QLatin1String("size")) 0109 return m.size(); 0110 return QVariant(); 0111 } 0112 case SurveyTargetExpression::ListElement: 0113 { 0114 const auto v = value(expression->source()).value<QVariantList>().value(expression->value().toInt()); 0115 return v.toMap().value(expression->sourceElement()); 0116 } 0117 case SurveyTargetExpression::MapElement: 0118 { 0119 const auto v = value(expression->source()).toMap().value(expression->value().toString()); 0120 qDebug() << v << value(expression->source()).toMap() << expression->value().toString(); 0121 return v.toMap().value(expression->sourceElement()); 0122 } 0123 default: 0124 break; 0125 } 0126 0127 Q_ASSERT(false); 0128 return QVariant(); 0129 } 0130 0131 QVariant SurveyTargetExpressionEvaluator::value(const QString& source) 0132 { 0133 Q_ASSERT(m_provider); 0134 const auto it = m_dataCache.constFind(source); 0135 if (it != m_dataCache.constEnd()) 0136 return it.value(); 0137 0138 const auto v = m_provider->sourceData(source); 0139 m_dataCache.insert(source, v); 0140 return v; 0141 }