Cutelee 6.1.0
variable.cpp
1/*
2 This file is part of the Cutelee template system.
3
4 Copyright (c) 2009,2010 Stephen Kelly <steveire@gmail.com>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either version
9 2.1 of the Licence, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library. If not, see <http://www.gnu.org/licenses/>.
18
19*/
20
21#include "variable.h"
22
23#include "abstractlocalizer.h"
24#include "context.h"
25#include "exception.h"
26#include "metaenumvariable_p.h"
27#include "metatype.h"
28#include "util.h"
29
30#include <QtCore/QMetaEnum>
31#include <QtCore/QStringList>
32#include <QJsonArray>
33#include <QJsonDocument>
34#include <QJsonObject>
35#include <QJsonValue>
36
37using namespace Cutelee;
38
39namespace Cutelee
40{
41
43{
44public:
45 VariablePrivate(Variable *variable) : q_ptr(variable), m_localize(false) {}
46
47 Q_DECLARE_PUBLIC(Variable)
48 Variable *const q_ptr;
49
50 QString m_varString;
51 QVariant m_literal;
52 QStringList m_lookups;
53 bool m_localize;
54};
55}
56
57Variable::Variable(const Variable &other) : d_ptr(new VariablePrivate(this))
58{
59 *this = other;
60}
61
62Variable::Variable() : d_ptr(new VariablePrivate(this)) {}
63
64Variable::~Variable() { delete d_ptr; }
65
67{
68 if (&other == this)
69 return *this;
70 d_ptr->m_varString = other.d_ptr->m_varString;
71 d_ptr->m_literal = other.d_ptr->m_literal;
72 d_ptr->m_lookups = other.d_ptr->m_lookups;
73 d_ptr->m_localize = other.d_ptr->m_localize;
74 return *this;
75}
76
77Variable::Variable(const QString &var) : d_ptr(new VariablePrivate(this))
78{
79 Q_D(Variable);
80 d->m_varString = var;
81
82 auto localVar = var;
83 if (var.startsWith(QStringLiteral("_("))) {
84 // The FilterExpression parser ensures this:
85 Q_ASSERT(var.endsWith(QLatin1Char(')')));
86 d->m_localize = true;
87 localVar = var.mid(2, var.size() - 3);
88 }
89 if (localVar.endsWith(QLatin1Char('.'))) {
90 delete d_ptr;
92 TagSyntaxError,
93 QStringLiteral("Variable may not end with a dot: %1").arg(localVar));
94 }
95
96 auto processedNumber = false;
97 {
98 const auto intResult = QLocale::c().toInt(localVar, &processedNumber);
99 if (processedNumber) {
100 d->m_literal = intResult;
101 } else {
102 const auto doubleResult
103 = QLocale::c().toDouble(localVar, &processedNumber);
104 if (processedNumber) {
105 d->m_literal = doubleResult;
106 }
107 }
108 }
109 if (!processedNumber) {
110 if (localVar.startsWith(QLatin1Char('"'))
111 || localVar.startsWith(QLatin1Char('\''))) {
112 // The FilterExpression parser ensures this:
113 Q_ASSERT(localVar.endsWith(QLatin1Char('\''))
114 || localVar.endsWith(QLatin1Char('"')));
115 const auto unesc = unescapeStringLiteral(localVar);
116 const auto ss = markSafe(unesc);
117 d->m_literal = QVariant::fromValue<Cutelee::SafeString>(ss);
118 } else {
119 if (localVar.contains(QStringLiteral("._"))
120 || (localVar.startsWith(QLatin1Char('_')))) {
121 delete d_ptr;
122 throw Cutelee::Exception(
123 TagSyntaxError,
124 QStringLiteral(
125 "Variables and attributes may not begin with underscores: %1")
126 .arg(localVar));
127 }
128 d->m_lookups = localVar.split(QLatin1Char('.'));
129 }
130 }
131}
132
134{
135 Q_D(const Variable);
136 return !d->m_varString.isEmpty();
137}
138
140{
141 Q_D(const Variable);
142 return !d->m_literal.isNull();
143}
144
145bool Variable::isTrue(Context *c) const { return variantIsTrue(resolve(c)); }
146
148{
149 Q_D(const Variable);
150 return d->m_localize;
151}
152
154{
155 Q_D(const Variable);
156 return d->m_literal;
157}
158
159QStringList Variable::lookups() const
160{
161 Q_D(const Variable);
162 return d->m_lookups;
163}
164
165class StaticQtMetaObject : public QObject
166{
167public:
168#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
169 static const QMetaObject *_smo() { return &QObject::staticQtMetaObject; }
170#else
171 static const QMetaObject *_smo() { return &QObject::staticMetaObject; }
172#endif
173};
174
176{
177 Q_D(const Variable);
178 QVariant var;
179 if (!d->m_lookups.isEmpty()) {
180 auto i = 0;
181 if (d->m_lookups.at(i) == QStringLiteral("Qt")) {
182 ++i;
183 if (d->m_lookups.size() <= i)
184 return QVariant();
185
186 const auto nextPart = d->m_lookups.at(i);
187 ++i;
188
189 static auto globalMetaObject = StaticQtMetaObject::_smo();
190
191 auto breakout = false;
192 for (auto j = 0; j < globalMetaObject->enumeratorCount(); ++j) {
193 const auto me = globalMetaObject->enumerator(j);
194
195 if (QLatin1String(me.name()) == nextPart) {
196 const MetaEnumVariable mev(me);
197 var = QVariant::fromValue(mev);
198 break;
199 }
200
201 for (auto k = 0; k < me.keyCount(); ++k) {
202 if (QLatin1String(me.key(k)) == nextPart) {
203 const MetaEnumVariable mev(me, k);
204 var = QVariant::fromValue(mev);
205 breakout = true;
206 break;
207 }
208 }
209 if (breakout)
210 break;
211 }
212 if (!var.isValid())
213 return QVariant();
214
215 } else {
216 var = c->lookup(d->m_lookups.at(i++));
217 if (var.userType() == QMetaType::QJsonDocument) {
218 const auto jsonDoc = var.toJsonDocument();
219 if (jsonDoc.isArray()) {
220 var = jsonDoc.array().toVariantList();
221 } else if (jsonDoc.isObject()) {
222 var = jsonDoc.object().toVariantHash();
223 } else {
224 // JSON document is eather empty or null
225 return QVariant();
226 }
227 } else if (var.userType() == QMetaType::QJsonValue) {
228 const auto jsonVal = var.toJsonValue();
229 switch(jsonVal.type()) {
230 case QJsonValue::Bool:
231 var = jsonVal.toBool();
232 break;
233 case QJsonValue::Double:
234 var = jsonVal.toDouble();
235 break;
236 case QJsonValue::String:
237 var = jsonVal.toString();
238 break;
239 case QJsonValue::Array:
240 case QJsonValue::Object:
241 var = jsonVal.toVariant();
242 break;
243 default:
244 return QVariant();
245 }
246 } else if (var.userType() == QMetaType::QJsonArray) {
247 var = var.toJsonArray().toVariantList();
248 } else if (var.userType() == QMetaType::QJsonObject) {
249 var = var.toJsonObject().toVariantHash();
250 }
251 }
252 while (i < d->m_lookups.size()) {
253 var = MetaType::lookup(var, d->m_lookups.at(i++));
254 if (!var.isValid())
255 return QVariant();
256 }
257 } else {
258 if (isSafeString(d->m_literal))
259 var = QVariant::fromValue(getSafeString(d->m_literal));
260 else
261 var = d->m_literal;
262 }
263
264 if (d->m_localize) {
265 return c->localizer()->localize(var);
266 }
267 return var;
268}
The Context class holds the context to render a Template with.
Definition context.h:119
std::shared_ptr< AbstractLocalizer > localizer() const
Definition context.cpp:230
virtual QVariant lookup(const QString &str) const
Definition context.cpp:100
An exception for use when implementing template tags.
Definition exception.h:85
A container for static variables defined in Templates.
Definition variable.h:53
QStringList lookups() const
Definition variable.cpp:159
QVariant literal() const
Definition variable.cpp:153
QVariant resolve(Context *c) const
Definition variable.cpp:175
bool isTrue(Context *c) const
Definition variable.cpp:145
bool isConstant() const
Definition variable.cpp:139
Variable & operator=(const Variable &other)
Definition variable.cpp:66
bool isLocalized() const
Definition variable.cpp:147
bool isValid() const
Definition variable.cpp:133
The Cutelee namespace holds all public Cutelee API.
Definition Mainpage.dox:8
QString unescapeStringLiteral(const QString &input)
Definition util.cpp:31
bool isSafeString(const QVariant &input)
Definition util.cpp:117
Cutelee::SafeString getSafeString(const QVariant &input)
Definition util.cpp:108
Cutelee::SafeString markSafe(const Cutelee::SafeString &input)
Definition util.cpp:90
bool variantIsTrue(const QVariant &variant)
Definition util.cpp:39
Utility functions used throughout Cutelee.