Make the Grantlee::Node::render method const.
[grantlee:grantlee.git] / templates / defaulttags / cycle.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 "cycle.h"
22
23 #include "../lib/exception.h"
24 #include "parser.h"
25 #include "rendercontext.h"
26 #include "util.h"
27
28 static const char _namedCycleNodes[] = "_namedCycleNodes";
29
30 CycleNodeFactory::CycleNodeFactory()
31 {
32
33 }
34
35 Node* CycleNodeFactory::getNode( const QString &tagContent, Parser *p ) const
36 {
37   QStringList expr = smartSplit( tagContent );
38
39   if ( expr.size() < 2 ) {
40     throw Grantlee::Exception( TagSyntaxError, QString::fromLatin1( "%1 expects at least one argument" ).arg( expr.first() ) );
41   }
42
43   if ( expr.at( 1 ).contains( QLatin1Char( ',' ) ) ) {
44     QStringList csvlist = expr.at( 1 ).split( QLatin1Char( ',' ) );
45     expr.removeAt( 1 );
46     for ( int i = 0; i < csvlist.size() ; ++i ) {
47       expr.insert( i + 1, QChar::fromLatin1( '"' ) + csvlist.at( i ) + QChar::fromLatin1( '"' ) );
48     }
49   }
50
51   if ( expr.size() == 2 ) {
52     // {% cycle var %}
53     QString name = expr.at( 1 );
54     QVariant cycleNodes = p->property( _namedCycleNodes );
55     if ( cycleNodes.type() != QVariant::Hash ) {
56       throw Grantlee::Exception( TagSyntaxError, QString::fromLatin1( "No named cycles in template. '%1' is not defined" ).arg( name ) );
57     }
58     QVariantHash hash = cycleNodes.toHash();
59     if ( !hash.contains( name ) ) {
60       throw Grantlee::Exception( TagSyntaxError, QString::fromLatin1( "Node not found: %1" ).arg( name ) );
61     }
62     QVariant nodeVariant = hash.value( name );
63     Q_ASSERT( nodeVariant.userType() == QMetaType::QObjectStar );
64     QObject *obj = nodeVariant.value<QObject*>();
65     Node *node = qobject_cast<Node*>( obj );
66     Q_ASSERT( node );
67     return node;
68   }
69
70   int exprSize = expr.size();
71   if ( exprSize > 4 && expr.at( exprSize - 2 ) == QLatin1String( "as" ) ) {
72     // {% cycle "foo" "bar" "bat" as var %}
73     QString name = expr.at( exprSize - 1 );
74     QStringList list = expr.mid( 1, exprSize - 3 );
75     Node *node = new CycleNode( getFilterExpressionList( list, p ), name, p );
76     QVariant hashVariant = p->property( _namedCycleNodes );
77     QVariantHash hash;
78     if ( hashVariant.type() == QVariant::Hash ) {
79       hash = hashVariant.toHash();
80     }
81     QObject *nodeObject = node;
82     QVariant nodeVariant = QVariant::fromValue( nodeObject );
83     hash.insert( name, nodeVariant );
84     p->setProperty( _namedCycleNodes, QVariant( hash ) );
85     return node;
86   } else {
87     QStringList list = expr.mid( 1, exprSize - 1 );
88     return new CycleNode( getFilterExpressionList( list, p ), QString(), p );
89   }
90 }
91
92 CycleNode::CycleNode( const QList<FilterExpression> &list, const QString &name, QObject *parent )
93     : Node( parent ), m_list( list ), m_variableIterator( list ), m_name( name )
94 {
95 }
96
97 void CycleNode::render( OutputStream *stream, Context *c ) const
98 {
99   QVariant &variant = c->renderContext()->data( this );
100
101   FilterExpressionRotator rotator;
102
103   if ( variant.isValid() )
104     rotator = variant.value<FilterExpressionRotator>();
105   else
106     rotator = FilterExpressionRotator( m_list );
107
108   QString value;
109   QTextStream textStream( &value );
110   QSharedPointer<OutputStream> temp = stream->clone( &textStream );
111
112   rotator.next().resolve( temp.data(), c ).toString();
113
114   variant.setValue( rotator );
115
116   if ( !m_name.isEmpty() ) {
117     c->insert( m_name, value );
118   }
119   ( *stream ) << value;
120 }
121