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 
30 QVariant 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 
54 QVariant 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 
94 QVariant 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 
111 QVariant 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 
128 QVariant 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 
147 QVariant 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>()) {
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 
210 SafeString 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>();
266  case QMetaType::LongLong:
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>();
272  case QMetaType::Double:
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 
332  DictSortLessThan lt;
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 }
T & get(QVariant &v)
QString & append(QChar ch)
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:305
void push_back(parameter_type value)
QStringList lookups() const
Definition: variable.cpp:159
Cutelee::SafeString markSafe(const Cutelee::SafeString &input)
Definition: util.cpp:93
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:111
qsizetype size() const const
A container for static variables defined in Templates.
Definition: variable.h:52
T value() const const
QString join(QChar separator) const const
qsizetype size() const const
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition: lists.cpp:147
qsizetype size() const const
SafeString conditionalEscape(const SafeString &input) const
Definition: filter.cpp:22
qint64 currentMSecsSinceEpoch()
bool canConvert() const const
QChar fromLatin1(char c)
int toInt(bool *ok, int base) const const
bool isEmpty() const const
Utility functions used throughout Cutelee.
A QString wrapper class for containing whether a string is safe or needs to be escaped.
Definition: safestring.h:91
int userType() const const
iterator end()
SkipEmptyParts
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition: lists.cpp:169
QString mid(qsizetype position, qsizetype n) const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QVariant literal() const
Definition: variable.cpp:153
void append(QList< T > &&value)
const QChar at(qsizetype position) const const
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition: lists.cpp:128
bool isValid() const const
const_iterator constEnd() const const
iterator begin()
const_iterator constBegin() const const
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition: lists.cpp:54
bool convert(QMetaType targetType)
QString arg(Args &&... args) const const
QString toString() const const
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
Definition: lists.cpp:69
iterator begin()
const NestedString & get() const
Definition: safestring.h:325
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