Cutelee 6.1.0
lists.cpp
1/*
2 This file is part of the Cutelee template system.
3
4 Copyright (c) 2009,2010,2011 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 "lists.h"
22
23#include "metatype.h"
24#include "util.h"
25#include "variable.h"
26
27#include <QSequentialIterable>
28#include <QtCore/QDateTime>
29
30QVariant JoinFilter::doFilter(const QVariant &input, const QVariant &argument,
31 bool autoescape) const
32{
33 if (!input.canConvert<QVariantList>())
34 return QVariant();
35
36 auto iter = input.value<QSequentialIterable>();
37
38 QString ret;
39 for (auto it = iter.begin(); it != iter.end(); ++it) {
40 const auto var = *it;
41 auto s = getSafeString(var);
42 if (autoescape)
43 s = conditionalEscape(s);
44
45 ret.append(s);
46 if ((it + 1) != iter.end()) {
47 auto argString = getSafeString(argument);
48 ret.append(conditionalEscape(argString));
49 }
50 }
51 return markSafe(ret);
52}
53
54QVariant LengthFilter::doFilter(const QVariant &input, const QVariant &argument,
55 bool autoescape) const
56{
57 Q_UNUSED(autoescape)
58 Q_UNUSED(argument)
59 if (input.canConvert<QVariantList>())
60 return input.value<QSequentialIterable>().size();
61
62 if (input.userType() == qMetaTypeId<SafeString>()
63 || input.userType() == qMetaTypeId<QString>())
64 return getSafeString(input).get().size();
65
66 return QVariant();
67}
68
70 const QVariant &argument,
71 bool autoescape) const
72{
73 Q_UNUSED(autoescape)
74 if (!input.isValid() || (input.userType() == qMetaTypeId<int>())
75 || (input.userType() == qMetaTypeId<QDateTime>()))
76 return QVariant();
77
78 auto size = 0;
79 if (input.canConvert<QVariantList>())
80 size = input.value<QSequentialIterable>().size();
81 else if (input.userType() == qMetaTypeId<SafeString>()
82 || input.userType() == qMetaTypeId<QString>())
83 size = getSafeString(input).get().size();
84
85 bool ok;
86 auto argInt = getSafeString(argument).get().toInt(&ok);
87
88 if (!ok)
89 return QVariant();
90
91 return size == argInt;
92}
93
94QVariant FirstFilter::doFilter(const QVariant &input, const QVariant &argument,
95 bool autoescape) const
96{
97 Q_UNUSED(autoescape)
98 Q_UNUSED(argument)
99
100 if (!input.canConvert<QVariantList>())
101 return QVariant();
102
103 auto iter = input.value<QSequentialIterable>();
104
105 if (iter.size() == 0)
106 return QString();
107
108 return *iter.begin();
109}
110
111QVariant LastFilter::doFilter(const QVariant &input, const QVariant &argument,
112 bool autoescape) const
113{
114 Q_UNUSED(autoescape)
115 Q_UNUSED(argument)
116
117 if (!input.canConvert<QVariantList>())
118 return QVariant();
119
120 auto iter = input.value<QSequentialIterable>();
121
122 if (iter.size() == 0)
123 return QString();
124
125 return *(iter.end() - 1);
126}
127
128QVariant RandomFilter::doFilter(const QVariant &input, const QVariant &argument,
129 bool autoescape) const
130{
131 Q_UNUSED(autoescape)
132 Q_UNUSED(argument)
133
134 if (!input.canConvert<QVariantList>())
135 return QVariant();
136
137 auto varList = input.value<QVariantList>();
138
139 if (varList.isEmpty())
140 return QVariant();
141
142 srand(QDateTime::currentDateTimeUtc().toMSecsSinceEpoch());
143 auto rnd = rand() % varList.size();
144 return varList.at(rnd);
145}
146
147QVariant SliceFilter::doFilter(const QVariant &input, const QVariant &argument,
148 bool autoescape) const
149{
150 Q_UNUSED(autoescape)
151 auto argString = getSafeString(argument);
152 auto splitterIndex = argString.get().indexOf(QLatin1Char(':'));
153 QString inputString = getSafeString(input);
154 if (inputString.isEmpty())
155 return QVariant();
156
157 if (splitterIndex >= 0) {
158 auto left = argString.get().left(splitterIndex).get().toInt();
159 auto right = argString.get().right(splitterIndex).get().toInt();
160 if (right < 0) {
161 right = inputString.size() + right;
162 }
163 return inputString.mid(left, right);
164 } else {
165 return QString(inputString.at(argument.value<int>()));
166 }
167}
168
170 const QVariant &argument,
171 bool autoescape) const
172{
173 Q_UNUSED(autoescape)
174 Q_UNUSED(argument)
175 if (_input.userType() == qMetaTypeId<QVariantList>())
176 return _input;
177 if (_input.canConvert<QVariantList>())
178 return _input.value<QVariantList>();
179
180 auto input = _input;
181
182 if (input.userType() == qMetaTypeId<int>()) {
183#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
184 input.convert(QMetaType::QString);
185#else
186 input.convert(QMetaType(QMetaType::QString));
187#endif
188 }
189
190 if (input.userType() == qMetaTypeId<SafeString>()
191 || input.userType() == qMetaTypeId<QString>()) {
192 QVariantList list;
193#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
194 const auto parts = getSafeString(input).get().split(QString(), QString::SkipEmptyParts);
195#else
196 const auto parts = getSafeString(input).get().split(QString(), Qt::SkipEmptyParts);
197#endif
198 for (const auto &var : parts) {
199 list << var;
200 }
201 return list;
202 }
203 return QVariant();
204}
205
207 const QVariant &argument,
208 bool autoescape) const
209{
210 Q_UNUSED(argument)
211
212 if (!input.canConvert<QVariantList>())
213 return QVariant();
214
215 return markSafe(processList(input.value<QVariantList>(), 1, autoescape));
216}
217
218SafeString UnorderedListFilter::processList(const QVariantList &list, int tabs,
219 bool autoescape) const
220{
221 QString indent;
222 for (auto i = 0; i < tabs; ++i)
223 indent.append(QLatin1Char('\t'));
224 QStringList output;
225
226 auto i = 0;
227 auto listSize = list.size();
228 while (i < listSize) {
229 auto titleObject = list.at(i);
230 auto title = getSafeString(titleObject);
231 QString sublist;
232 QVariant sublistItem;
233
234 if (titleObject.userType() == qMetaTypeId<QVariantList>()) {
235 sublistItem = titleObject;
236 title.get().clear();
237 } else if (i < listSize - 1) {
238 auto nextItem = list.at(i + 1);
239 if (nextItem.userType() == qMetaTypeId<QVariantList>()) {
240 sublistItem = nextItem;
241 }
242 ++i;
243 }
244 if (sublistItem.isValid()) {
245 sublist = processList(sublistItem.value<QVariantList>(), tabs + 1,
246 autoescape);
247 sublist = QStringLiteral("\n%1<ul>\n%2\n%3</ul>\n%4")
248 .arg(indent, sublist, indent, indent);
249 }
250 output.append(QStringLiteral("%1<li>%2%3</li>")
251 .arg(indent,
252 autoescape ? conditionalEscape(title) : title,
253 sublist));
254 ++i;
255 }
256
257 // Should be QLatin1Char() ?
258 return output.join(QChar::fromLatin1('\n'));
259}
260
262 bool operator()(const std::pair<QVariant, QVariant> &lp,
263 const std::pair<QVariant, QVariant> &rp) const
264 {
265 const auto l = lp.first;
266 const auto r = rp.first;
267 switch (l.userType()) {
269 return (r.isValid());
270 case QMetaType::Int:
271 return l.value<int>() < r.value<int>();
272 case QMetaType::UInt:
273 return l.value<uint>() < r.value<uint>();
275 return l.value<long long>() < r.value<long long>();
277 return l.value<unsigned long long>() < r.value<unsigned long long>();
278 case QMetaType::Float:
279 return l.value<float>() < r.value<float>();
281 return l.value<double>() < r.value<double>();
282 case QMetaType::Char:
283 return l.toChar() < r.toChar();
284 case QMetaType::QDate:
285 return l.toDate() < r.toDate();
286 case QMetaType::QTime:
287 return l.toTime() < r.toTime();
289 return l.toDateTime() < r.toDateTime();
291 return l.value<QObject *>() < r.value<QObject *>();
292 }
293 if (l.userType() == qMetaTypeId<Cutelee::SafeString>()) {
294 if (r.userType() == qMetaTypeId<Cutelee::SafeString>()) {
295 return l.value<Cutelee::SafeString>().get()
296 < r.value<Cutelee::SafeString>().get();
297 } else if (r.userType() == qMetaTypeId<QString>()) {
298 return l.value<Cutelee::SafeString>().get() < r.toString();
299 }
300 } else if (r.userType() == qMetaTypeId<Cutelee::SafeString>()) {
301 if (l.userType() == qMetaTypeId<QString>()) {
302 return l.toString() < r.value<Cutelee::SafeString>().get();
303 }
304 } else if (l.userType() == qMetaTypeId<QString>()) {
305 if (r.userType() == qMetaTypeId<QString>()) {
306 return l.toString() < r.toString();
307 }
308 }
309 return false;
310 }
311};
312
314 const QVariant &argument,
315 bool autoescape) const
316{
317 Q_UNUSED(autoescape)
318
319 if (!input.canConvert<QVariantList>())
320 return QVariant();
321
323 const auto inList = input.value<QSequentialIterable>();
324 for (const QVariant &item : inList) {
325 auto var = item;
326
327 const Variable v(getSafeString(argument));
328
329 if (v.literal().isValid()) {
330 var = MetaType::lookup(var, v.literal().toString());
331 } else {
332 const auto lookups = v.lookups();
333 Q_FOREACH (const QString &lookup, lookups) {
334 var = MetaType::lookup(var, lookup);
335 }
336 }
337 keyList.push_back({var, item});
338 }
339
341 std::stable_sort(keyList.begin(), keyList.end(), lt);
342
343 QVariantList outList;
344 auto it = keyList.constBegin();
345 const auto end = keyList.constEnd();
346 for (; it != end; ++it) {
347 outList << it->second;
348 }
349 return outList;
350}
SafeString conditionalEscape(const SafeString &input) const
Definition filter.cpp:22
A QString wrapper class for containing whether a string is safe or needs to be escaped.
Definition safestring.h:92
const NestedString & get() const
Definition safestring.h:340
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 doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:313
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:94
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:30
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:111
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:54
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:69
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:169
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:128
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:147
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition lists.cpp:206
Cutelee::SafeString getSafeString(const QVariant &input)
Definition util.cpp:108
Cutelee::SafeString markSafe(const Cutelee::SafeString &input)
Definition util.cpp:90
QChar fromLatin1(char c)
QDateTime currentDateTimeUtc()
void append(const T &value)
iterator begin()
const_iterator constBegin() const const
const_iterator constEnd() const const
iterator end()
void push_back(const T &value)
int size() const const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString & append(QChar ch)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const QChar at(int position) const const
bool isEmpty() const const
QString mid(int position, int n) const const
int size() const const
int toInt(bool *ok, int base) const const
QString join(const QString &separator) const const
SkipEmptyParts
bool canConvert(int targetTypeId) const const
void clear()
bool isValid() const const
QString toString() const const
int userType() const const
T value() const const
Utility functions used throughout Cutelee.