Make the Grantlee::Node::render method const.
[grantlee:grantlee.git] / templates / loadertags / extends.cpp
1 /*
2   This file is part of the Grantlee 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 #include <QtCore/QListIterator>
34
35 using namespace Grantlee;
36
37 ExtendsNodeFactory::ExtendsNodeFactory( QObject *parent )
38     : AbstractNodeFactory( parent )
39 {
40
41 }
42
43 Node* ExtendsNodeFactory::getNode( const QString &tagContent, Parser *p ) const
44 {
45   const QStringList expr = smartSplit( tagContent );
46
47   if ( expr.size() != 2 )
48     throw Grantlee::Exception( TagSyntaxError, QLatin1String( "Error: Include tag takes only one argument" ) );
49
50   QString parentName = expr.at( 1 );
51   FilterExpression fe;
52   const int size = parentName.size();
53
54   if (( parentName.startsWith( QLatin1Char( '"' ) ) && parentName.endsWith( QLatin1Char( '\"' ) ) )
55       || ( parentName.startsWith( QLatin1Char( '\'' ) ) && parentName.endsWith( QLatin1Char( '\'' ) ) ) ) {
56     parentName = parentName.mid( 1, size - 2 );
57   } else {
58     fe = FilterExpression( parentName, p );
59     parentName.clear();
60   }
61
62   ExtendsNode *n = new ExtendsNode( parentName, fe, p );
63
64   TemplateImpl *t = qobject_cast<TemplateImpl *>( p->parent() );
65
66   if ( !t )
67     throw Grantlee::Exception( TagSyntaxError, QLatin1String( "Extends tag is not in a template." ) );
68
69   const NodeList nodeList = p->parse( t );
70   n->setNodeList( nodeList );
71
72   if ( t->findChildren<ExtendsNode *>().size() > 1 ) {
73     throw Grantlee::Exception( TagSyntaxError, QLatin1String( "Extends tag may only appear once in a template." ) );
74   }
75
76   return n;
77 }
78
79 ExtendsNode::ExtendsNode( const QString &name, FilterExpression fe, QObject *parent )
80     : Node( parent ),
81     m_filterExpression( fe ),
82     m_name( name )
83 {
84 }
85
86
87 ExtendsNode::~ExtendsNode()
88 {
89 }
90
91 static QHash<QString, BlockNode*> createNodeMap( QList<BlockNode*> list )
92 {
93   QHash<QString, BlockNode*> map;
94
95   QList<BlockNode*>::const_iterator it = list.constBegin();
96   const QList<BlockNode*>::const_iterator end = list.constEnd();
97
98   for ( ; it != end; ++it ) {
99     map.insert( ( *it )->name(), *it );
100   }
101
102   return map;
103 }
104
105 void ExtendsNode::setNodeList( const NodeList &list )
106 {
107   m_list = list;
108
109   const QList<BlockNode*> blockList = m_list.findChildren<BlockNode*>();
110   m_blocks = createNodeMap( blockList );
111 }
112
113 Template ExtendsNode::getParent( Context *c ) const
114 {
115   QString parentName;
116   if ( m_name.isEmpty() ) {
117     const QVariant parentVar = m_filterExpression.resolve( c );
118     if ( parentVar.userType() == qMetaTypeId<Grantlee::Template>() ) {
119       return parentVar.value<Template>();
120     }
121
122     parentName = getSafeString( parentVar );
123   } else {
124     parentName = m_name;
125   }
126
127   TemplateImpl *ti = containerTemplate();
128
129   const Template t = ti->engine()->loadByName( parentName );
130
131   if ( !t )
132     throw Grantlee::Exception( TagSyntaxError, QString::fromLatin1( "Template not found %1" ).arg( parentName ) );
133
134   if ( t->error() )
135     throw Grantlee::Exception( t->error(), t->errorString() );
136
137   return t;
138 }
139
140 void ExtendsNode::render( OutputStream *stream, Context *c ) const
141 {
142   const Template parentTemplate = getParent( c );
143
144   if ( !parentTemplate ) {
145     throw Grantlee::Exception( TagSyntaxError, QString::fromLatin1( "Cannot load template '%1'" ).arg( m_name ) );
146   }
147
148   QVariant &variant = c->renderContext()->data( 0 );
149   BlockContext blockContext = variant.value<BlockContext>();
150   blockContext.addBlocks( m_blocks );
151   variant.setValue( blockContext );
152
153   const NodeList nodeList = parentTemplate->nodeList();
154
155   const QHash<QString, BlockNode*> parentBlocks = createNodeMap( parentTemplate->findChildren<BlockNode*>() );
156   QListIterator<Node*> i( nodeList );
157
158   while ( i.hasNext() ) {
159     Node* n = i.next();
160     TextNode *tn = qobject_cast<TextNode*>( n );
161     if ( !tn ) {
162       ExtendsNode *en = qobject_cast<ExtendsNode*>( n );
163       if ( !en ) {
164         blockContext.addBlocks( parentBlocks );
165         variant.setValue( blockContext );
166       }
167       break;
168     }
169   }
170   variant.setValue( blockContext );
171   parentTemplate->nodeList().render( stream, c );
172 }
173
174 void ExtendsNode::appendNode( Node *node )
175 {
176   m_list.append( node );
177   node->setParent( parent() );
178 }
179