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
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#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;
234 var = jsonVal.toDouble();
235 break;
237 var = jsonVal.toString();
238 break;
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
QVariantList toVariantList() const const
QVariantHash toVariantHash() const const
QLocale c()
double toDouble(const QString &s, bool *ok) const const
int toInt(const QString &s, bool *ok) const const
QObject(QObject *parent)
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString mid(int position, int n) const const
int size() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QVariant fromValue(const 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.