23#include "../lib/exception.h"
24#include "metaenumvariable_p.h"
27#include <QSequentialIterable>
29ForNodeFactory::ForNodeFactory() =
default;
35 if (expr.size() < 4) {
38 QStringLiteral(
"'for' statements should have at least four words: %1")
44 int reversed = ForNode::IsNotReversed;
45 if (expr.last() == QStringLiteral(
"reversed")) {
46 reversed = ForNode::IsReversed;
50 if (expr.at(expr.size() - 2) != QStringLiteral(
"in")) {
53 QStringLiteral(
"'for' statements should use the form 'for x in y': %1")
58 const auto parts = expr.
mid(0, expr.size() - 2);
59 for (
const QString &arg : parts) {
61 for (
const QString &var : args) {
65 QStringLiteral(
"'for' tag received invalid argument"));
75 auto n =
new ForNode(vars, fe, reversed, p);
78 = p->
parse(n, {QStringLiteral(
"empty"), QStringLiteral(
"endfor")});
79 n->setLoopList(loopNodes);
83 emptyNodes = p->
parse(n, QStringLiteral(
"endfor"));
84 n->setEmptyList(emptyNodes);
94 :
Node(parent), m_loopVars(loopVars), m_filterExpression(fe),
95 m_isReversed(reversed)
99void ForNode::setLoopList(
const NodeList &loopNodeList)
101 m_loopNodeList = loopNodeList;
104void ForNode::setEmptyList(
const NodeList &emptyList)
106 m_emptyNodeList = emptyList;
109static const char forloop[] =
"forloop";
110static const char parentloop[] =
"parentloop";
112void ForNode::insertLoopVariables(
Context *c,
int listSize,
int i)
114 auto forloopHash = c->
lookup(QStringLiteral(
"forloop")).
value<QVariantHash>();
116 forloopHash.insert(QStringLiteral(
"counter0"), i);
117 forloopHash.insert(QStringLiteral(
"counter"), i + 1);
118 forloopHash.insert(QStringLiteral(
"revcounter"), listSize - i);
119 forloopHash.insert(QStringLiteral(
"revcounter0"), listSize - i - 1);
120 forloopHash.insert(QStringLiteral(
"first"), (i == 0));
121 forloopHash.insert(QStringLiteral(
"last"), (i == listSize - 1));
122 c->
insert(QLatin1String(forloop), forloopHash);
127 for (
auto j = 0; j < m_loopNodeList.size(); j++) {
128 m_loopNodeList[j]->render(stream, c);
134 QVariantHash forloopHash;
137 if (parentLoopVariant.isValid()) {
139 forloopHash = parentLoopVariant.value<QVariantHash>();
141 parentLoopVariant.value<QVariantHash>());
145 auto unpack = m_loopVars.size() > 1;
149 auto varFE = m_filterExpression.resolve(c);
151 if (varFE.userType() == qMetaTypeId<MetaEnumVariable>()) {
152 const auto mev = varFE.value<MetaEnumVariable>();
154 if (mev.value != -1) {
156 return m_emptyNodeList.render(stream, c);
160 for (
auto row = 0; row < mev.enumerator.keyCount(); ++row) {
166 if (!varFE.canConvert<QVariantList>()) {
168 return m_emptyNodeList.render(stream, c);
172 const auto listSize = iter.
size();
177 return m_emptyNodeList.render(stream, c);
181 for (
auto it = m_isReversed == IsReversed ? iter.end() - 1 : iter.begin();
182 m_isReversed == IsReversed ? it != iter.begin() - 1 : it != iter.end();
183 m_isReversed == IsReversed ? --it : ++it) {
185 insertLoopVariables(c, listSize, i);
188 if (v.userType() == qMetaTypeId<QVariantList>()) {
189 auto vList = v.value<QVariantList>();
190 auto varsSize = qMin(m_loopVars.size(), vList.size());
192 for (; j < varsSize; ++j) {
193 c->
insert(m_loopVars.at(j), vList.at(j));
197 for (; j < m_loopVars.size(); ++j) {
208 for (
const QString &loopVar : m_loopVars) {
210 c->
insert(QStringLiteral(
"var"), v);
218 c->
insert(m_loopVars[0], v);
220 renderLoop(stream, c);
Q_INVOKABLE QStringList smartSplit(const QString &str) const
The Context class holds the context to render a Template with.
void insert(const QString &name, QObject *object)
virtual QVariant lookup(const QString &str) const
An exception for use when implementing template tags.
A FilterExpression object represents a filter expression in a template.
QVariant resolve(OutputStream *stream, Context *c) const
A list of Nodes with some convenience API for rendering them.
Base class for all nodes.
The OutputStream class is used to render templates to a QTextStream.
The Parser class processes a string template into a tree of nodes.
NodeList parse(Node *parent, const QStringList &stopAt={})
Node * getNode(const QString &tagContent, Parser *p) const override
void render(OutputStream *stream, Context *c) const override
qsizetype size() const const
QList< T > mid(qsizetype pos, qsizetype length) const const
QVariant fromValue(T &&value)
QString content
The content of this Token.