Make the Grantlee::Node::render method const.
[grantlee:grantlee.git] / templates / defaulttags / regroup.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 "regroup.h"
22
23 #include "../lib/exception.h"
24 #include "parser.h"
25 #include "util.h"
26
27 RegroupNodeFactory::RegroupNodeFactory()
28 {
29
30 }
31
32 Node* RegroupNodeFactory::getNode( const QString &tagContent, Parser *p ) const
33 {
34   QStringList expr = tagContent.split( QLatin1Char( ' ' ) );
35
36   if ( expr.size() != 6 ) {
37     throw Grantlee::Exception( TagSyntaxError, QLatin1String( "widthratio takes five arguments" ) );
38   }
39   FilterExpression target( expr.at( 1 ), p );
40   if ( expr.at( 2 ) != QLatin1String( "by" ) ) {
41     throw Grantlee::Exception( TagSyntaxError, QLatin1String( "second argument must be 'by'" ) );
42   }
43
44   if ( expr.at( 4 ) != QLatin1String( "as" ) ) {
45     throw Grantlee::Exception( TagSyntaxError, QLatin1String( "fourth argument must be 'as'" ) );
46   }
47
48   FilterExpression expression( QLatin1String( "\"" ) + expr.at( 3 ) + QLatin1String( "\"" ), p );
49
50   QString name = expr.at( 5 );
51
52   return new RegroupNode( target, expression, name, p );
53 }
54
55 RegroupNode::RegroupNode( FilterExpression target, FilterExpression expression, const QString &varName, QObject *parent )
56     : Node( parent ), m_target( target ), m_expression( expression ), m_varName( varName )
57 {
58
59 }
60
61 void RegroupNode::render( OutputStream *stream, Context *c ) const
62 {
63   Q_UNUSED( stream )
64   QVariantList objList = m_target.toList( c );
65   if ( objList.isEmpty() ) {
66     c->insert( m_varName, QVariantHash() );
67     return;
68   }
69
70   // What's going on?
71   //
72   // objList is a flat list of objects with a common parameter. For example, Person objects with
73   // a name parameter. The list is already sorted.
74   // Say the objList contains ["David Beckham", "David Blain", "Keira Nightly"] etc.
75   // We want to regroup the list into separate lists of people with the same first name.
76   // ie objHash should be: {"David": ["David Beckham", "David Blain"], "Keira": ["Keira Nightly"]}
77   //
78   // We then insert the objHash into the Context ready for rendering later in a for loop.
79
80   QVariantList contextList;
81   const QString keyName = getSafeString( m_expression.resolve( c ) );
82   QListIterator<QVariant> i( objList );
83   while ( i.hasNext() ) {
84     const QVariant var = i.next();
85     c->push();
86     c->insert( QLatin1String( "var" ), var );
87     const QString key = getSafeString( FilterExpression( QLatin1String( "var." ) + keyName, 0 ).resolve( c ) );
88     c->pop();
89     QVariantHash hash;
90     if ( contextList.size() > 0 ) {
91       QVariant hashVar = contextList.last();
92       hash = hashVar.toHash();
93     }
94     if ( !hash.contains( QLatin1String( "grouper" ) ) || hash.value( QLatin1String( "grouper" ) ) != key ) {
95       QVariantHash newHash;
96       hash.insert( QLatin1String( "grouper" ), key );
97       hash.insert( QLatin1String( "list" ), QVariantList() );
98       contextList.append( newHash );
99     }
100
101     QVariantList list = hash.value( QLatin1String( "list" ) ).toList();
102     list.append( var );
103     hash.insert( QLatin1String( "list" ), list );
104     contextList[contextList.size() - 1] = hash;
105   }
106   c->insert( m_varName, contextList );
107 }
108