23 #include "../lib/exception.h" 24 #include "metaenumvariable_p.h" 27 #include <QSequentialIterable> 29 ForNodeFactory::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)
99 void ForNode::setLoopList(
const NodeList &loopNodeList)
101 m_loopNodeList = loopNodeList;
104 void ForNode::setEmptyList(
const NodeList &emptyList)
106 m_emptyNodeList = emptyList;
109 static const char forloop[] =
"forloop";
110 static const char parentloop[] =
"parentloop";
112 void 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));
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);
NodeList parse(Node *parent, const QStringList &stopAt={})
The Context class holds the context to render a Template with.
Node * getNode(const QString &tagContent, Parser *p) const override
QVariant fromValue(T &&value)
const_reference at(qsizetype i) const const
void render(OutputStream *stream, Context *c) const override
qsizetype size() const const
qsizetype size() const const
QString content
The content of this Token.
Base class for all nodes.
The OutputStream class is used to render templates to a QTextStream.
QVariant resolve(OutputStream *stream, Context *c) const
The Parser class processes a string template into a tree of nodes.
QList< T > mid(qsizetype pos, qsizetype length) const const
A list of Nodes with some convenience API for rendering them.
A FilterExpression object represents a filter expression in a template.
Q_INVOKABLE QStringList smartSplit(const QString &str) const
virtual QVariant lookup(const QString &str) const
void insert(const QString &name, QObject *object)
void render(OutputStream *stream, Context *c) const
An exception for use when implementing template tags.