Cutelee  6.1.0
extends.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 "extends.h"
22 
23 #include "block.h"
24 #include "blockcontext.h"
25 #include "engine.h"
26 #include "exception.h"
27 #include "nodebuiltins_p.h"
28 #include "parser.h"
29 #include "rendercontext.h"
30 #include "template.h"
31 #include "util.h"
32 
33 using namespace Cutelee;
34 
35 ExtendsNodeFactory::ExtendsNodeFactory(QObject *parent)
36  : AbstractNodeFactory(parent)
37 {
38 }
39 
40 Node *ExtendsNodeFactory::getNode(const QString &tagContent, Parser *p) const
41 {
42  const auto expr = smartSplit(tagContent);
43 
44  if (expr.size() != 2)
45  throw Cutelee::Exception(
46  TagSyntaxError,
47  QStringLiteral("Error: Include tag takes only one argument"));
48 
49  FilterExpression fe(expr.at(1), p);
50 
51  auto n = new ExtendsNode(fe, p);
52 
53  auto t = qobject_cast<TemplateImpl *>(p->parent());
54 
55  if (!t)
56  throw Cutelee::Exception(
57  TagSyntaxError, QStringLiteral("Extends tag is not in a template."));
58 
59  const auto nodeList = p->parse(t);
60  n->setNodeList(nodeList);
61 
62  if (t->findChildren<ExtendsNode *>().size() > 1) {
63  throw Cutelee::Exception(
64  TagSyntaxError,
65  QStringLiteral("Extends tag may only appear once in a template."));
66  }
67 
68  return n;
69 }
70 
71 ExtendsNode::ExtendsNode(const FilterExpression &fe, QObject *parent)
72  : Node(parent), m_filterExpression(fe)
73 {
74 }
75 
76 ExtendsNode::~ExtendsNode() {}
77 
78 static QHash<QString, BlockNode *> createNodeMap(const QList<BlockNode *> &list)
79 {
80  QHash<QString, BlockNode *> map;
81 
82  auto it = list.constBegin();
83  const auto end = list.constEnd();
84 
85  for (; it != end; ++it) {
86  map.insert((*it)->name(), *it);
87  }
88 
89  return map;
90 }
91 
92 void ExtendsNode::setNodeList(const NodeList &list)
93 {
94  m_list = list;
95 
96  const auto blockList = m_list.findChildren<BlockNode *>();
97  m_blocks = createNodeMap(blockList);
98 }
99 
100 Template ExtendsNode::getParent(Context *c) const
101 {
102  const auto parentVar = m_filterExpression.resolve(c);
103  if (parentVar.userType() == qMetaTypeId<Cutelee::Template>()) {
104  return parentVar.value<Template>();
105  }
106 
107  QString parentName = getSafeString(parentVar);
108 
109  auto ti = containerTemplate();
110 
111  const auto t = ti->engine()->loadByName(parentName);
112 
113  if (!t)
114  throw Cutelee::Exception(
115  TagSyntaxError,
116  QStringLiteral("Template not found %1").arg(parentName));
117 
118  if (t->error())
119  throw Cutelee::Exception(t->error(), t->errorString());
120 
121  return t;
122 }
123 
124 void ExtendsNode::render(OutputStream *stream, Context *c) const
125 {
126  const auto parentTemplate = getParent(c);
127 
128  if (!parentTemplate) {
129  throw Cutelee::Exception(TagSyntaxError,
130  QStringLiteral("Cannot load template."));
131  }
132 
133  QVariant &variant = c->renderContext()->data(0);
134  auto blockContext = variant.value<BlockContext>();
135  blockContext.addBlocks(m_blocks);
136  variant.setValue(blockContext);
137 
138  const auto nodeList = parentTemplate->nodeList();
139 
140  const auto parentBlocks
141  = createNodeMap(parentTemplate->findChildren<BlockNode *>());
142 
143  for (auto n : nodeList) {
144  auto tn = qobject_cast<TextNode *>(n);
145  if (!tn) {
146  auto en = qobject_cast<ExtendsNode *>(n);
147  if (!en) {
148  blockContext.addBlocks(parentBlocks);
149  variant.setValue(blockContext);
150  }
151  break;
152  }
153  }
154  variant.setValue(blockContext);
155  parentTemplate->nodeList().render(stream, c);
156 
157  auto nodes = parentTemplate->findChildren<BlockNode *>();
158  blockContext.remove(nodes);
159  variant.setValue(blockContext);
160 }
161 
162 void ExtendsNode::appendNode(Node *node)
163 {
164  m_list.append(node);
165  node->setParent(parent());
166 }
Base class for all NodeFactories.
Definition: node.h:300
Q_INVOKABLE QStringList smartSplit(const QString &str) const
Definition: node.cpp:202
The Context class holds the context to render a Template with.
Definition: context.h:119
RenderContext * renderContext() const
Definition: context.cpp:214
An exception for use when implementing template tags.
Definition: exception.h:85
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.
Definition: node.h:148
QList< T > findChildren()
Definition: node.h:190
void append(Cutelee::Node *node)
Definition: node.cpp:149
Base class for all nodes.
Definition: node.h:78
TemplateImpl * containerTemplate() const
Definition: node.cpp:107
The OutputStream class is used to render templates to a QTextStream.
Definition: outputstream.h:81
The Parser class processes a string template into a tree of nodes.
Definition: parser.h:49
NodeList parse(Node *parent, const QStringList &stopAt={})
Definition: parser.cpp:180
QVariant & data(const Node *const scopeNode)
The Template class is a tree of nodes which may be rendered.
Definition: template.h:95
Node * getNode(const QString &tagContent, Parser *p) const override
Definition: extends.cpp:40
void render(OutputStream *stream, Context *c) const override
Definition: extends.cpp:124
The Cutelee namespace holds all public Cutelee API.
Definition: Mainpage.dox:8
Cutelee::SafeString getSafeString(const QVariant &input)
Definition: util.cpp:108
Utility functions used throughout Cutelee.