File indexing completed on 2025-02-09 04:28:41
0001 /* 0002 This file is part of the KTextTemplate library 0003 0004 SPDX-FileCopyrightText: 2009, 2010 Stephen Kelly <steveire@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.1-or-later 0007 0008 */ 0009 0010 #include "variable.h" 0011 0012 #include "abstractlocalizer.h" 0013 #include "context.h" 0014 #include "exception.h" 0015 #include "metaenumvariable_p.h" 0016 #include "metatype.h" 0017 #include "util.h" 0018 0019 #include <QMetaEnum> 0020 #include <QStringList> 0021 0022 using namespace KTextTemplate; 0023 0024 namespace KTextTemplate 0025 { 0026 0027 class VariablePrivate 0028 { 0029 public: 0030 VariablePrivate(Variable *variable) 0031 : q_ptr(variable) 0032 { 0033 } 0034 0035 Q_DECLARE_PUBLIC(Variable) 0036 Variable *const q_ptr; 0037 0038 QString m_varString; 0039 QVariant m_literal; 0040 QStringList m_lookups; 0041 bool m_localize = false; 0042 }; 0043 } 0044 0045 Variable::Variable(const Variable &other) 0046 : d_ptr(new VariablePrivate(this)) 0047 { 0048 *this = other; 0049 } 0050 0051 Variable::Variable() 0052 : d_ptr(new VariablePrivate(this)) 0053 { 0054 } 0055 0056 Variable::~Variable() 0057 { 0058 delete d_ptr; 0059 } 0060 0061 Variable &Variable::operator=(const Variable &other) 0062 { 0063 if (&other == this) 0064 return *this; 0065 d_ptr->m_varString = other.d_ptr->m_varString; 0066 d_ptr->m_literal = other.d_ptr->m_literal; 0067 d_ptr->m_lookups = other.d_ptr->m_lookups; 0068 d_ptr->m_localize = other.d_ptr->m_localize; 0069 return *this; 0070 } 0071 0072 Variable::Variable(const QString &var) 0073 : d_ptr(new VariablePrivate(this)) 0074 { 0075 Q_D(Variable); 0076 d->m_varString = var; 0077 0078 auto localVar = var; 0079 if (var.startsWith(QStringLiteral("_("))) { 0080 // The FilterExpression parser ensures this: 0081 Q_ASSERT(var.endsWith(QLatin1Char(')'))); 0082 d->m_localize = true; 0083 localVar = var.mid(2, var.size() - 3); 0084 } 0085 if (localVar.endsWith(QLatin1Char('.'))) { 0086 delete d_ptr; 0087 throw KTextTemplate::Exception(TagSyntaxError, QStringLiteral("Variable may not end with a dot: %1").arg(localVar)); 0088 } 0089 0090 auto processedNumber = false; 0091 { 0092 const auto intResult = QLocale::c().toInt(localVar, &processedNumber); 0093 if (processedNumber) { 0094 d->m_literal = intResult; 0095 } else { 0096 const auto doubleResult = QLocale::c().toDouble(localVar, &processedNumber); 0097 if (processedNumber) { 0098 d->m_literal = doubleResult; 0099 } 0100 } 0101 } 0102 if (!processedNumber) { 0103 if (localVar.startsWith(QLatin1Char('"')) || localVar.startsWith(QLatin1Char('\''))) { 0104 // The FilterExpression parser ensures this: 0105 Q_ASSERT(localVar.endsWith(QLatin1Char('\'')) || localVar.endsWith(QLatin1Char('"'))); 0106 const auto unesc = unescapeStringLiteral(localVar); 0107 const auto ss = markSafe(unesc); 0108 d->m_literal = QVariant::fromValue<KTextTemplate::SafeString>(ss); 0109 } else { 0110 if (localVar.contains(QStringLiteral("._")) || (localVar.startsWith(QLatin1Char('_')))) { 0111 delete d_ptr; 0112 throw KTextTemplate::Exception(TagSyntaxError, QStringLiteral("Variables and attributes may not begin with underscores: %1").arg(localVar)); 0113 } 0114 d->m_lookups = localVar.split(QLatin1Char('.')); 0115 } 0116 } 0117 } 0118 0119 bool Variable::isValid() const 0120 { 0121 Q_D(const Variable); 0122 return !d->m_varString.isEmpty(); 0123 } 0124 0125 bool Variable::isConstant() const 0126 { 0127 Q_D(const Variable); 0128 return !d->m_literal.isNull(); 0129 } 0130 0131 bool Variable::isTrue(Context *c) const 0132 { 0133 return variantIsTrue(resolve(c)); 0134 } 0135 0136 bool Variable::isLocalized() const 0137 { 0138 Q_D(const Variable); 0139 return d->m_localize; 0140 } 0141 0142 QVariant Variable::literal() const 0143 { 0144 Q_D(const Variable); 0145 return d->m_literal; 0146 } 0147 0148 QStringList Variable::lookups() const 0149 { 0150 Q_D(const Variable); 0151 return d->m_lookups; 0152 } 0153 0154 class StaticQtMetaObject : public QObject 0155 { 0156 public: 0157 static const QMetaObject *_smo() 0158 { 0159 return &Qt::staticMetaObject; 0160 } 0161 }; 0162 0163 QVariant Variable::resolve(Context *c) const 0164 { 0165 Q_D(const Variable); 0166 QVariant var; 0167 if (!d->m_lookups.isEmpty()) { 0168 auto i = 0; 0169 if (d->m_lookups.at(i) == QStringLiteral("Qt")) { 0170 ++i; 0171 if (d->m_lookups.size() <= i) 0172 return {}; 0173 0174 const auto nextPart = d->m_lookups.at(i); 0175 ++i; 0176 0177 static auto globalMetaObject = StaticQtMetaObject::_smo(); 0178 0179 auto breakout = false; 0180 for (auto j = 0; j < globalMetaObject->enumeratorCount(); ++j) { 0181 const auto me = globalMetaObject->enumerator(j); 0182 0183 if (QLatin1String(me.name()) == nextPart) { 0184 const MetaEnumVariable mev(me); 0185 var = QVariant::fromValue(mev); 0186 break; 0187 } 0188 0189 for (auto k = 0; k < me.keyCount(); ++k) { 0190 if (QLatin1String(me.key(k)) == nextPart) { 0191 const MetaEnumVariable mev(me, k); 0192 var = QVariant::fromValue(mev); 0193 breakout = true; 0194 break; 0195 } 0196 } 0197 if (breakout) 0198 break; 0199 } 0200 if (!var.isValid()) 0201 return {}; 0202 0203 } else { 0204 var = c->lookup(d->m_lookups.at(i++)); 0205 } 0206 while (i < d->m_lookups.size()) { 0207 var = MetaType::lookup(var, d->m_lookups.at(i++)); 0208 if (!var.isValid()) 0209 return {}; 0210 } 0211 } else { 0212 if (isSafeString(d->m_literal)) 0213 var = QVariant::fromValue(getSafeString(d->m_literal)); 0214 else 0215 var = d->m_literal; 0216 } 0217 0218 if (d->m_localize) { 0219 return c->localizer()->localize(var); 0220 } 0221 return var; 0222 }