Cutelee 6.2.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
42class VariablePrivate
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);
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
160{
161 Q_D(const Variable);
162 return d->m_lookups;
163}
164
166{
167public:
168 static const QMetaObject *_smo() { return &QObject::staticMetaObject; }
169};
170
172{
173 Q_D(const Variable);
174 QVariant var;
175 if (!d->m_lookups.isEmpty()) {
176 auto i = 0;
177 if (d->m_lookups.at(i) == QStringLiteral("Qt")) {
178 ++i;
179 if (d->m_lookups.size() <= i)
180 return QVariant();
181
182 const auto nextPart = d->m_lookups.at(i);
183 ++i;
184
185 static auto globalMetaObject = StaticQtMetaObject::_smo();
186
187 auto breakout = false;
188 for (auto j = 0; j < globalMetaObject->enumeratorCount(); ++j) {
189 const auto me = globalMetaObject->enumerator(j);
190
191 if (QLatin1String(me.name()) == nextPart) {
192 const MetaEnumVariable mev(me);
193 var = QVariant::fromValue(mev);
194 break;
195 }
196
197 for (auto k = 0; k < me.keyCount(); ++k) {
198 if (QLatin1String(me.key(k)) == nextPart) {
199 const MetaEnumVariable mev(me, k);
200 var = QVariant::fromValue(mev);
201 breakout = true;
202 break;
203 }
204 }
205 if (breakout)
206 break;
207 }
208 if (!var.isValid())
209 return QVariant();
210
211 } else {
212 var = c->lookup(d->m_lookups.at(i++));
213 if (var.userType() == QMetaType::QJsonDocument) {
214 const auto jsonDoc = var.toJsonDocument();
215 if (jsonDoc.isArray()) {
216 var = jsonDoc.array().toVariantList();
217 } else if (jsonDoc.isObject()) {
218 var = jsonDoc.object().toVariantHash();
219 } else {
220 // JSON document is eather empty or null
221 return QVariant();
222 }
223 } else if (var.userType() == QMetaType::QJsonValue) {
224 const auto jsonVal = var.toJsonValue();
225 switch(jsonVal.type()) {
226 case QJsonValue::Bool:
227 var = jsonVal.toBool();
228 break;
230 var = jsonVal.toDouble();
231 break;
233 var = jsonVal.toString();
234 break;
237 var = jsonVal.toVariant();
238 break;
239 default:
240 return QVariant();
241 }
242 } else if (var.userType() == QMetaType::QJsonArray) {
243 var = var.toJsonArray().toVariantList();
244 } else if (var.userType() == QMetaType::QJsonObject) {
245 var = var.toJsonObject().toVariantHash();
246 }
247 }
248 while (i < d->m_lookups.size()) {
249 var = MetaType::lookup(var, d->m_lookups.at(i++));
250 if (!var.isValid())
251 return QVariant();
252 }
253 } else {
254 if (isSafeString(d->m_literal))
255 var = QVariant::fromValue(getSafeString(d->m_literal));
256 else
257 var = d->m_literal;
258 }
259
260 if (d->m_localize) {
261 return c->localizer()->localize(var);
262 }
263 return var;
264}
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:171
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:120
Cutelee::SafeString getSafeString(const QVariant &input)
Definition util.cpp:111
Cutelee::SafeString markSafe(const Cutelee::SafeString &input)
Definition util.cpp:93
bool variantIsTrue(const QVariant &variant)
Definition util.cpp:39
QVariantList toVariantList() const const
QVariantHash toVariantHash() const const
QLocale c()
double toDouble(QStringView s, bool *ok) const const
int toInt(QStringView s, bool *ok) const const
QObject(QObject *parent)
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString mid(qsizetype position, qsizetype n) &&
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QVariant fromValue(T &&value)
bool isValid() const const
bool toBool() const const
double toDouble(bool *ok) const const
QJsonArray toJsonArray() const const
QJsonDocument toJsonDocument() const const
QJsonObject toJsonObject() const const
QJsonValue toJsonValue() const const
QString toString() const const
int userType() const const
Utility functions used throughout Cutelee.