Cutelee 6.1.0
ifchanged.cpp
1/*
2 This file is part of the Cutelee template system.
3
4 Copyright (c) 2009,2010 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 "ifchanged.h"
22
23#include "parser.h"
24
25#include <QtCore/QDateTime>
26
27IfChangedNodeFactory::IfChangedNodeFactory() {}
28
29Node *IfChangedNodeFactory::getNode(const QString &tagContent, Parser *p) const
30{
31#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
32 auto expr = tagContent.split(QLatin1Char(' '), QString::SkipEmptyParts);
33#else
34 auto expr = tagContent.split(QLatin1Char(' '), Qt::SkipEmptyParts);
35#endif
36
37 expr.takeAt(0);
38 auto n = new IfChangedNode(getFilterExpressionList(expr, p), p);
39
40 auto trueList
41 = p->parse(n, {QStringLiteral("else"), QStringLiteral("endifchanged")});
42 n->setTrueList(trueList);
43 NodeList falseList;
44
45 if (p->takeNextToken().content == QStringLiteral("else")) {
46 falseList = p->parse(n, QStringLiteral("endifchanged"));
47 n->setFalseList(falseList);
48 p->removeNextToken();
49 }
50
51 return n;
52}
53
54IfChangedNode::IfChangedNode(const QList<FilterExpression> &feList,
55 QObject *parent)
56 : Node(parent), m_filterExpressions(feList)
57{
58 m_lastSeen = QVariant();
59 m_id = QString::number(reinterpret_cast<qint64>(this));
60}
61
62void IfChangedNode::setTrueList(const NodeList &trueList)
63{
64 m_trueList = trueList;
65}
66
67void IfChangedNode::setFalseList(const NodeList &falseList)
68{
69 m_falseList = falseList;
70}
71
73{
74 if (c->lookup(QStringLiteral("forloop")).isValid()
75 && (!c->lookup(QStringLiteral("forloop"))
76 .value<QVariantHash>()
77 .contains(m_id))) {
78 m_lastSeen = QVariant();
79 auto hash = c->lookup(QStringLiteral("forloop")).value<QVariantHash>();
80 hash.insert(m_id, 1);
81 c->insert(QStringLiteral("forloop"), hash);
82 }
83
84 QString watchedString;
85 QTextStream watchedTextStream(&watchedString);
86 auto watchedStream = stream->clone(&watchedTextStream);
87 if (m_filterExpressions.isEmpty()) {
88 m_trueList.render(watchedStream.get(), c);
89 }
90 QVariantList watchedVars;
91 for (auto &i : m_filterExpressions) {
92 auto var = i.resolve(c);
93 if (!var.isValid()) {
94 // silent error
95 return;
96 }
97 watchedVars.append(var);
98 }
99
100 // In Qt6, QVariant::value<QVariantList>() converts a QString
101 // to a QList(QVariant(QChar, c)...).
102 // Avoid that conversion
103 QVariantList lastSeenVarList;
104 if (m_lastSeen.userType() != qMetaTypeId<QString>()) {
105 lastSeenVarList = m_lastSeen.value<QVariantList>();
106 }
107
108 // At first glance it looks like m_last_seen will always be invalid,
109 // But it will change because render is called multiple times by the parent
110 // {% for %} loop in the template.
111 if ((watchedVars != lastSeenVarList)
112 || (!watchedString.isEmpty()
113 && (watchedString != m_lastSeen.value<QString>()))) {
114 auto firstLoop = !m_lastSeen.isValid();
115 if (!watchedString.isEmpty())
116 m_lastSeen = watchedString;
117 else
118 m_lastSeen = watchedVars;
119 c->push();
120 QVariantHash hash;
121 // TODO: Document this.
122 hash.insert(QStringLiteral("firstloop"), firstLoop);
123 c->insert(QStringLiteral("ifchanged"), hash);
124 m_trueList.render(stream, c);
125 c->pop();
126 } else if (!m_falseList.isEmpty()) {
127 m_falseList.render(stream, c);
128 }
129}
QList< FilterExpression > getFilterExpressionList(const QStringList &list, Parser *p) const
Definition node.cpp:192
The Context class holds the context to render a Template with.
Definition context.h:119
void insert(const QString &name, QObject *object)
Definition context.cpp:145
virtual QVariant lookup(const QString &str) const
Definition context.cpp:100
A list of Nodes with some convenience API for rendering them.
Definition node.h:148
void render(OutputStream *stream, Context *c) const
Definition node.cpp:177
Base class for all nodes.
Definition node.h:78
The OutputStream class is used to render templates to a QTextStream.
virtual std::shared_ptr< OutputStream > clone(QTextStream *stream) const
The Parser class processes a string template into a tree of nodes.
Definition parser.h:49
Token takeNextToken()
Definition parser.cpp:291
NodeList parse(Node *parent, const QStringList &stopAt={})
Definition parser.cpp:180
void removeNextToken()
Definition parser.cpp:297
Node * getNode(const QString &tagContent, Parser *p) const override
Definition ifchanged.cpp:29
void render(OutputStream *stream, Context *c) const override
Definition ifchanged.cpp:72
QString content
The content of this Token.
Definition token.h:51