Cutelee  6.1.0
node.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 "node.h"
22 
23 #include "metaenumvariable_p.h"
24 #include "nodebuiltins_p.h"
25 #include "template.h"
26 #include "util.h"
27 
28 #include <QtCore/QRegularExpressionMatchIterator>
29 
30 using namespace Cutelee;
31 
32 namespace Cutelee
33 {
34 
36 {
37  NodePrivate(Node *node) : q_ptr(node) {}
38  Q_DECLARE_PUBLIC(Node)
39  Node *const q_ptr;
40 };
41 
43 {
44  AbstractNodeFactoryPrivate(AbstractNodeFactory *factory) : q_ptr(factory)
45  {
46 #if defined(Q_CC_MSVC)
47 // MSVC doesn't like static string concatenations like L"foo" "bar", as
48 // results from QStringLiteral, so use QLatin1String here instead.
49 #define STRING_LITERAL QLatin1String
50 #else
51 #define STRING_LITERAL QStringLiteral
52 #endif
53  smartSplitRe = QRegularExpression(
54  STRING_LITERAL("(" // match
55  "(?:[^\\s\\\'\\\"]*" // things that are not whitespace or
56  // escaped quote chars
57  "(?:" // followed by
58  "(?:\"" // Either a quote starting with "
59  "(?:[^\"\\\\]|\\\\.)*\"" // followed by anything that is
60  // not the end of the quote
61  "|\'" // Or a quote starting with '
62  "(?:[^\'\\\\]|\\\\.)*\'" // followed by anything that is
63  // not the end of the quote
64  ")" // (End either)
65  "[^\\s\'\"]*" // To the start of the next such fragment
66  ")+" // Perform multiple matches of the above.
67  ")" // End of quoted string handling.
68  "|\\S+" // Apart from quoted strings, match
69  // non-whitespace fragments also
70  ")" // End match
71  ));
72 
73 #undef STRING_LITERAL
74  }
75 
76  Q_DECLARE_PUBLIC(AbstractNodeFactory)
77  AbstractNodeFactory *const q_ptr;
78 
79 public:
80  QRegularExpression smartSplitRe;
81 };
82 }
83 
84 Node::Node(QObject *parent) : QObject(parent), d_ptr(new NodePrivate(this)) {}
85 
86 Node::~Node() { delete d_ptr; }
87 
89  Context *c) const
90 {
91  Cutelee::SafeString inputString;
92  if (input.userType() == qMetaTypeId<QVariantList>()) {
93  inputString = toString(input.value<QVariantList>());
94  } else if (input.userType() == qMetaTypeId<MetaEnumVariable>()) {
95  const auto mev = input.value<MetaEnumVariable>();
96  if (mev.value >= 0)
97  (*stream) << QString::number(mev.value);
98  } else {
99  inputString = getSafeString(input);
100  }
101  if (c->autoEscape() && !inputString.isSafe())
102  inputString.setNeedsEscape(true);
103 
104  (*stream) << inputString;
105 }
106 
107 TemplateImpl *Node::containerTemplate() const
108 {
109  auto _parent = parent();
110  auto ti = qobject_cast<TemplateImpl *>(_parent);
111  while (_parent && !ti) {
112  _parent = _parent->parent();
113  ti = qobject_cast<TemplateImpl *>(_parent);
114  }
115  Q_ASSERT(ti);
116  return ti;
117 }
118 
119 NodeList::NodeList() : QList<Cutelee::Node *>(), m_containsNonText(false) {}
120 
121 NodeList::NodeList(const NodeList &list) : QList<Cutelee::Node *>(list)
122 {
123  m_containsNonText = list.m_containsNonText;
124 }
125 
126 NodeList &NodeList::operator=(const NodeList &list)
127 {
128  static_cast<QList<Cutelee::Node *> &>(*this)
129  = static_cast<QList<Cutelee::Node *>>(list);
130  m_containsNonText = list.m_containsNonText;
131  return *this;
132 }
133 
134 NodeList::NodeList(const QList<Cutelee::Node *> &list)
135  : QList<Cutelee::Node *>(list)
136 {
137  for (Cutelee::Node *node : list) {
138  auto textNode = qobject_cast<TextNode *>(node);
139  if (!textNode) {
140  m_containsNonText = true;
141  return;
142  }
143  }
144  m_containsNonText = false;
145 }
146 
148 
150 {
151  if (!m_containsNonText) {
152  auto textNode = qobject_cast<TextNode *>(node);
153  if (!textNode)
154  m_containsNonText = true;
155  }
156 
157  QList<Cutelee::Node *>::append(node);
158 }
159 
160 void NodeList::append(const QList<Cutelee::Node *> &nodeList)
161 {
162  if (!m_containsNonText) {
163  for (const Cutelee::Node *node : nodeList) {
164  auto textNode = qobject_cast<const TextNode *>(node);
165  if (!textNode) {
166  m_containsNonText = true;
167  break;
168  }
169  }
170  }
171 
172  QList<Cutelee::Node *>::append(nodeList);
173 }
174 
175 bool NodeList::containsNonText() const { return m_containsNonText; }
176 
177 void NodeList::render(OutputStream *stream, Context *c) const
178 {
179  for (auto i = 0; i < this->size(); ++i) {
180  this->at(i)->render(stream, c);
181  }
182 }
183 
185  : QObject(parent), d_ptr(new AbstractNodeFactoryPrivate(this))
186 {
187 }
188 
190 
191 QList<FilterExpression>
193  Parser *p) const
194 {
195  QList<FilterExpression> fes;
196  for (auto &varString : list) {
197  fes << FilterExpression(varString, p);
198  }
199  return fes;
200 }
201 
202 QStringList AbstractNodeFactory::smartSplit(const QString &str) const
203 {
204  Q_D(const AbstractNodeFactory);
205  QStringList l;
206 
207  auto i = d->smartSplitRe.globalMatch(str);
208  while (i.hasNext()) {
209  auto match = i.next();
210  l.append(match.captured());
211  }
212 
213  return l;
214 }
Base class for all NodeFactories.
Definition: node.h:300
~AbstractNodeFactory() override
Definition: node.cpp:189
AbstractNodeFactory(QObject *parent={})
Definition: node.cpp:184
QList< FilterExpression > getFilterExpressionList(const QStringList &list, Parser *p) const
Definition: node.cpp:192
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
A FilterExpression object represents a filter expression in a template.
A list of Nodes with some convenience API for rendering them.
Definition: node.h:148
bool containsNonText() const
Definition: node.cpp:175
void render(OutputStream *stream, Context *c) const
Definition: node.cpp:177
void append(Cutelee::Node *node)
Definition: node.cpp:149
Base class for all nodes.
Definition: node.h:78
void streamValueInContext(OutputStream *stream, const QVariant &input, Cutelee::Context *c) const
Definition: node.cpp:88
TemplateImpl * containerTemplate() const
Definition: node.cpp:107
~Node() override
Definition: node.cpp:86
Node(QObject *parent={})
Definition: node.cpp:84
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
A QString wrapper class for containing whether a string is safe or needs to be escaped.
Definition: safestring.h:92
bool isSafe() const
Definition: safestring.cpp:63
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.