Cutelee 6.2.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
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 input.convert(QMetaType(QMetaType::QString));
184 }
185
186 if (input.userType() == qMetaTypeId<SafeString>()
187 || input.userType() == qMetaTypeId<QString>()) {
188 QVariantList list;
189 const auto parts = getSafeString(input).get().split(QString(), Qt::SkipEmptyParts);
190 for (const auto &var : parts) {
191 list << var;
192 }
193 return list;
194 }
195 return QVariant();
196}
197
199 const QVariant &argument,
200 bool autoescape) const
201{
202 Q_UNUSED(argument)
203
204 if (!input.canConvert<QVariantList>())
205 return QVariant();
206
207 return markSafe(processList(input.value<QVariantList>(), 1, autoescape));
208}
209
210SafeString UnorderedListFilter::processList(const QVariantList &list, int tabs,
211 bool autoescape) const
212{
213 QString indent;
214 for (auto i = 0; i < tabs; ++i)
215 indent.append(QLatin1Char('\t'));
216 QStringList output;
217
218 auto i = 0;
219 auto listSize = list.size();
220 while (i < listSize) {
221 auto titleObject = list.at(i);
222 auto title = getSafeString(titleObject);
223 QString sublist;
224 QVariant sublistItem;
225
226 if (titleObject.userType() == qMetaTypeId<QVariantList>()) {
227 sublistItem = titleObject;
228 title.get().clear();
229 } else if (i < listSize - 1) {
230 auto nextItem = list.at(i + 1);
231 if (nextItem.userType() == qMetaTypeId<QVariantList>()) {
232 sublistItem = nextItem;
233 }
234 ++i;
235 }
236 if (sublistItem.isValid()) {
237 sublist = processList(sublistItem.value<QVariantList>(), tabs + 1,
238 autoescape);
239 sublist = QStringLiteral("\n%1<ul>\n%2\n%3</ul>\n%4")
240 .arg(indent, sublist, indent, indent);
241 }
242 output.append(QStringLiteral("%1<li>%2%3</li>")
243 .arg(indent,
244 autoescape ? conditionalEscape(title) : title,
245 sublist));
246 ++i;
247 }
248
249 // Should be QLatin1Char() ?
250 return output.join(QChar::fromLatin1('\n'));
251}
252
254 bool operator()(const std::pair<QVariant, QVariant> &lp,
255 const std::pair<QVariant, QVariant> &rp) const
256 {
257 const auto l = lp.first;
258 const auto r = rp.first;
259 switch (l.userType()) {
261 return (r.isValid());
262 case QMetaType::Int:
263 return l.value<int>() < r.value<int>();
264 case QMetaType::UInt:
265 return l.value<uint>() < r.value<uint>();
267 return l.value<long long>() < r.value<long long>();
269 return l.value<unsigned long long>() < r.value<unsigned long long>();
270 case QMetaType::Float:
271 return l.value<float>() < r.value<float>();
273 return l.value<double>() < r.value<double>();
274 case QMetaType::Char:
275 return l.toChar() < r.toChar();
276 case QMetaType::QDate:
277 return l.toDate() < r.toDate();
278 case QMetaType::QTime:
279 return l.toTime() < r.toTime();
281 return l.toDateTime() < r.toDateTime();
283 return l.value<QObject *>() < r.value<QObject *>();
284 }
285 if (l.userType() == qMetaTypeId<Cutelee::SafeString>()) {
286 if (r.userType() == qMetaTypeId<Cutelee::SafeString>()) {
287 return l.value<Cutelee::SafeString>().get()
288 < r.value<Cutelee::SafeString>().get();
289 } else if (r.userType() == qMetaTypeId<QString>()) {
290 return l.value<Cutelee::SafeString>().get() < r.toString();
291 }
292 } else if (r.userType() == qMetaTypeId<Cutelee::SafeString>()) {
293 if (l.userType() == qMetaTypeId<QString>()) {
294 return l.toString() < r.value<Cutelee::SafeString>().get();
295 }
296 } else if (l.userType() == qMetaTypeId<QString>()) {
297 if (r.userType() == qMetaTypeId<QString>()) {
298 return l.toString() < r.toString();
299 }
300 }
301 return false;
302 }
303};
304
306 const QVariant &argument,
307 bool autoescape) const
308{
309 Q_UNUSED(autoescape)
310
311 if (!input.canConvert<QVariantList>())
312 return QVariant();
313
315 const auto inList = input.value<QSequentialIterable>();
316 for (const QVariant &item : inList) {
317 auto var = item;
318
319 const Variable v(getSafeString(argument));
320
321 if (v.literal().isValid()) {
322 var = MetaType::lookup(var, v.literal().toString());
323 } else {
324 const auto lookups = v.lookups();
325 Q_FOREACH (const QString &lookup, lookups) {
326 var = MetaType::lookup(var, lookup);
327 }
328 }
329 keyList.push_back({var, item});
330 }
331
333 std::stable_sort(keyList.begin(), keyList.end(), lt);
334
335 QVariantList outList;
336 auto it = keyList.constBegin();
337 const auto end = keyList.constEnd();
338 for (; it != end; ++it) {
339 outList << it->second;
340 }
341 return outList;
342}
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:325
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:305
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:198
Cutelee::SafeString getSafeString(const QVariant &input)
Definition util.cpp:111
Cutelee::SafeString markSafe(const Cutelee::SafeString &input)
Definition util.cpp:93
QChar fromLatin1(char c)
qint64 currentMSecsSinceEpoch()
void append(QList< T > &&value)
QList< T >::iterator begin()
QList< T >::const_iterator constBegin() const const
QList< T >::const_iterator constEnd() const const
QList< T >::iterator end()
void push_back(QList< T >::parameter_type value)
qsizetype size() const const
QString & append(QChar ch)
QString arg(Args &&... args) const const
const QChar at(qsizetype position) const const
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) &&
qsizetype size() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
QString join(QChar separator) const const
SkipEmptyParts
bool canConvert() const const
T & get(QVariant &v)
bool isValid() const const
QString toString() const const
int userType() const const
T value() const &const
Utility functions used throughout Cutelee.