File indexing completed on 2025-02-09 04:28:38

0001 /*
0002   This file is part of the KTextTemplate library
0003 
0004   SPDX-FileCopyrightText: 2009, 2010 Stephen Kelly <steveire@gmail.com>
0005 
0006   SPDX-License-Identifier: LGPL-2.1-or-later
0007 
0008 */
0009 
0010 #ifndef KTEXTTEMPLATE_NODE_H
0011 #define KTEXTTEMPLATE_NODE_H
0012 
0013 // krazy:excludeall=dpointer
0014 
0015 #include "context.h"
0016 #include "filterexpression.h"
0017 #include "ktexttemplate_export.h"
0018 #include "outputstream.h"
0019 #include "safestring.h"
0020 
0021 #include <QStringList>
0022 
0023 // Need these for inheriting from QList<T> to work
0024 // http://lists.trolltech.com/qt-interest/2008-01/thread00578-0.html
0025 #include <QList>
0026 #include <QSet>
0027 
0028 namespace KTextTemplate
0029 {
0030 
0031 class Engine;
0032 class NodeList;
0033 class TemplateImpl;
0034 
0035 class NodePrivate;
0036 
0037 /// @headerfile node.h <KTextTemplate/Node>
0038 
0039 /**
0040   @brief Base class for all nodes.
0041 
0042   The **%Node** class can be implemented to make additional functionality
0043   available to Templates.
0044 
0045   A node is represented in template markup as content surrounded by percent
0046   signed tokens.
0047 
0048   @code
0049     text content
0050     {% some_tag arg1 arg2 %}
0051       text content
0052     {% some_other_tag arg1 arg2 %}
0053       text content
0054     {% end_some_other_tag %}
0055     text content
0056   @endcode
0057 
0058   This is parsed into a tree of **%Node** objects by an implementation of
0059   AbstractNodeFactory. The **%Node** objects can then later be rendered by their
0060   @ref render method.
0061 
0062   Rendering a **%Node** will usually mean writing some output to the stream. The
0063   content written to the stream could be determined by the arguments to the tag,
0064   or by the content of child nodes between a start and end tag, or both.
0065 
0066   @see FilterExpression
0067   @see @ref tags
0068 
0069   @author Stephen Kelly <steveire@gmail.com>
0070 */
0071 class KTEXTTEMPLATE_EXPORT Node : public QObject
0072 {
0073     Q_OBJECT
0074 public:
0075     /**
0076       Constructor.
0077 
0078       @param parent The parent QObject
0079     */
0080     explicit Node(QObject *parent = {});
0081 
0082     /**
0083       Destructor.
0084     */
0085     ~Node() override;
0086 
0087     /**
0088       Reimplement this to render the template in the Context @p c.
0089 
0090       This will also involve calling render on and child nodes.
0091     */
0092     virtual void render(OutputStream *stream, Context *c) const = 0;
0093 
0094 #ifndef K_DOXYGEN
0095     /**
0096       @internal
0097     */
0098     virtual bool mustBeFirst()
0099     { // krazy:exclude:inline
0100         return false;
0101     }
0102 #endif
0103 
0104 protected:
0105     /**
0106       Renders the value @p input in the Context @p c. This will involve escaping
0107       @p input if necessary.
0108 
0109       This is only relevant to developing template tags.
0110     */
0111     void streamValueInContext(OutputStream *stream, const QVariant &input, KTextTemplate::Context *c) const;
0112 
0113     /**
0114       Returns a raw pointer to the Template this **%Node** is in.
0115     */
0116     TemplateImpl *containerTemplate() const;
0117 
0118 private:
0119     Q_DECLARE_PRIVATE(Node)
0120     NodePrivate *const d_ptr;
0121 };
0122 
0123 /// @headerfile node.h KTextTemplate/node.h
0124 
0125 /**
0126   @brief A list of Nodes with some convenience API for rendering them.
0127 
0128   Typically, tags which have an end tag will create and later render a list of
0129   child nodes.
0130 
0131   This class contains API such as @ref append and @ref render to make creating
0132   such list easily.
0133 
0134   The @ref findChildren method behaves similarly to the QObject::findChildren
0135   method, returning a list of nodes of a particular type from the Node objects
0136   contained in the list (and their children).
0137 
0138   @see @ref tags_with_end_tags
0139 */
0140 class KTEXTTEMPLATE_EXPORT NodeList : public QList<KTextTemplate::Node *>
0141 {
0142 public:
0143     /**
0144       Creates an empty **%NodeList**.
0145     */
0146     NodeList();
0147 
0148     /**
0149       Copy constructor.
0150     */
0151     NodeList(const NodeList &list);
0152 
0153     NodeList &operator=(const NodeList &list);
0154 
0155     /**
0156       Convenience constructor
0157     */
0158     /* implicit */ NodeList(const QList<KTextTemplate::Node *> &list);
0159 
0160     /**
0161       Destructor.
0162     */
0163     ~NodeList();
0164 
0165     /**
0166       Appends @p node to the end of this **%NodeList**.
0167     */
0168     void append(KTextTemplate::Node *node);
0169 
0170     /**
0171       Appends @p nodeList to the end of this **%NodeList**.
0172     */
0173     void append(const QList<KTextTemplate::Node *> &nodeList);
0174 
0175     /**
0176       Returns true if this **%NodeList** contains non-text nodes.
0177     */
0178     bool containsNonText() const;
0179 
0180     /**
0181       A recursive listing of nodes in this tree of type @p T.
0182     */
0183     template<typename T>
0184     QList<T> findChildren()
0185     {
0186         QList<T> children;
0187         QList<KTextTemplate::Node *>::const_iterator it;
0188         const QList<KTextTemplate::Node *>::const_iterator first = constBegin();
0189         const QList<KTextTemplate::Node *>::const_iterator last = constEnd();
0190         for (it = first; it != last; ++it) {
0191             T object = qobject_cast<T>(*it);
0192             if (object) {
0193                 children << object;
0194             }
0195             children << (*it)->findChildren<T>();
0196         }
0197         return children;
0198     }
0199 
0200     /**
0201       Renders the list of Nodes in the Context @p c.
0202     */
0203     void render(OutputStream *stream, Context *c) const;
0204 
0205 private:
0206     bool m_containsNonText;
0207 };
0208 
0209 class AbstractNodeFactoryPrivate;
0210 
0211 /// @headerfile node.h KTextTemplate/node.h
0212 
0213 /**
0214   @brief Base class for all NodeFactories
0215 
0216   This class can be used to make custom tags available to templates.
0217   The getNode method should be implemented to return a Node to be rendered.
0218 
0219   A node is represented in template markup as content surrounded by percent
0220   signed tokens.
0221 
0222   @code
0223     text content
0224     {% some_tag arg1 arg2 %}
0225       text content
0226     {% some_other_tag arg1 arg2 %}
0227       text content
0228     {% end_some_other_tag %}
0229     text content
0230   @endcode
0231 
0232   It is the responsibility of an **%AbstractNodeFactory** implementation to
0233   process the contents of a tag and return a Node implementation from its
0234   getNode method.
0235 
0236   The @ref getNode method would for example be called with the tagContent
0237   \"<tt>some_tag arg1 arg2</tt>\". That content could then be split up, the
0238   arguments processed and a Node created
0239 
0240   @code
0241     Node* SomeTagFactory::getNode(const QString &tagContent, Parser *p) {
0242       QStringList parts = smartSplit( tagContent );
0243 
0244       parts.removeFirst(); // Remove the "some_tag" part.
0245 
0246       FilterExpression arg1( parts.first(), p );
0247       FilterExpression arg2( parts.at( 1 ), p );
0248 
0249       return new SomeTagNode( arg1, arg2, p );
0250     }
0251   @endcode
0252 
0253   The @ref getNode implementation might also advance the parser. For example if
0254   we had a @gr_tag{times} tag which rendered content the amount of times it was
0255   given in its argument, it could be used like this:
0256 
0257   @code
0258     Some text content.
0259     {% times 5 %}
0260       the bit to be repeated
0261     {% end_times %}
0262     End text content
0263   @endcode
0264 
0265   The argument to @gr_tag{times} might not be a simple number, but could be a
0266   FilterExpression such as \"<tt>someobject.some_property|getDigit:1</tt>\".
0267 
0268   The implementation could look like
0269 
0270   @code
0271     Node* SomeOtherTagFactory::getNode(const QString &tagContent, Parser *p) {
0272       QStringList parts = smartSplit( tagContent );
0273 
0274       parts.removeFirst(); // Remove the "times" part.
0275 
0276       FilterExpression arg( parts.first(), p );
0277 
0278       auto node = new SomeTagNode( arg, p );
0279       auto childNodes = p->parse( node, "end_times" );
0280       node->setChildNodes( childNodes );
0281       p->removeNextToken();
0282 
0283       return node;
0284     }
0285   @endcode
0286 
0287   Note that it is necessary to invoke the parser to create the child nodes only
0288   after creating the Node to return. That node must be passed to the Parser to
0289   perform as the parent QObject to the child nodes.
0290 
0291   @see Parser::parse
0292 */
0293 class KTEXTTEMPLATE_EXPORT AbstractNodeFactory : public QObject
0294 {
0295     Q_OBJECT
0296 public:
0297     /**
0298       Constructor.
0299 
0300       @param parent The parent QObject
0301     */
0302     explicit AbstractNodeFactory(QObject *parent = {});
0303 
0304     /**
0305       Destructor.
0306     */
0307     ~AbstractNodeFactory() override;
0308 
0309     /**
0310       This method should be reimplemented to return a Node which can be
0311       rendered.
0312 
0313       The @p tagContent is the content of the tag including the tag name and
0314       arguments. For example, if the template content is @gr_tag{my_tag arg1
0315       arg2}, the tagContent will be &quot;my_tag arg1 arg2&quot;.
0316 
0317       The Parser @p p is available and can be advanced if appropriate. For
0318       example, if the tag has an end tag, the parser can be advanced to the end
0319       tag.
0320 
0321       @see tags
0322     */
0323     virtual Node *getNode(const QString &tagContent, Parser *p) const = 0;
0324 
0325 #ifndef K_DOXYGEN
0326     /**
0327       @internal
0328 
0329       Sets the Engine which created this NodeFactory. Used by the
0330       ScriptableNodeFactory.
0331     */
0332     virtual void setEngine(Engine *)
0333     {
0334     }
0335 #endif
0336 
0337 protected:
0338     /**
0339       Splits @p str into a list, taking quote marks into account.
0340 
0341       This is typically used in the implementation of getNode with the
0342       tagContent.
0343 
0344       If @p str is 'one &quot;two three&quot; four 'five &quot; six' seven', the
0345       returned list will contain the following strings:
0346 
0347       - one
0348       - &quot;two three&quot;
0349       - four
0350       - five &quot; six
0351       - seven
0352     */
0353     Q_INVOKABLE QStringList smartSplit(const QString &str) const;
0354 
0355 protected:
0356     /**
0357       Returns a list of FilterExpression objects created with Parser @p p as
0358       described by the content of @p list.
0359 
0360       This is used for convenience when handling the arguments to a tag.
0361     */
0362     QList<FilterExpression> getFilterExpressionList(const QStringList &list, Parser *p) const;
0363 
0364 private:
0365     Q_DECLARE_PRIVATE(AbstractNodeFactory)
0366     AbstractNodeFactoryPrivate *const d_ptr;
0367 };
0368 }
0369 
0370 #endif