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 
37 using namespace Cutelee;
38 
39 namespace Cutelee
40 {
41 
43 {
44 public:
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 
57 Variable::Variable(const Variable &other) : d_ptr(new VariablePrivate(this))
58 {
59  *this = other;
60 }
61 
62 Variable::Variable() : d_ptr(new VariablePrivate(this)) {}
63 
64 Variable::~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 
77 Variable::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;
91  throw Cutelee::Exception(
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 
133 bool Variable::isValid() const
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 
145 bool 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 
159 QStringList Variable::lookups() const
160 {
161  Q_D(const Variable);
162  return d->m_lookups;
163 }
164 
165 class StaticQtMetaObject : public QObject
166 {
167 public:
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.