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 #include "node.h" 0011 0012 #include "metaenumvariable_p.h" 0013 #include "nodebuiltins_p.h" 0014 #include "template.h" 0015 #include "util.h" 0016 0017 #include <QRegularExpressionMatchIterator> 0018 0019 using namespace KTextTemplate; 0020 0021 namespace KTextTemplate 0022 { 0023 0024 class NodePrivate 0025 { 0026 NodePrivate(Node *node) 0027 : q_ptr(node) 0028 { 0029 } 0030 Q_DECLARE_PUBLIC(Node) 0031 Node *const q_ptr; 0032 }; 0033 0034 class AbstractNodeFactoryPrivate 0035 { 0036 AbstractNodeFactoryPrivate(AbstractNodeFactory *factory) 0037 : q_ptr(factory) 0038 { 0039 #if defined(Q_CC_MSVC) 0040 // MSVC doesn't like static string concatenations like L"foo" "bar", as 0041 // results from QStringLiteral, so use QLatin1String here instead. 0042 #define STRING_LITERAL QLatin1String 0043 #else 0044 #define STRING_LITERAL QStringLiteral 0045 #endif 0046 smartSplitRe = 0047 QRegularExpression(STRING_LITERAL("(" // match 0048 "(?:[^\\s\\\'\\\"]*" // things that are not whitespace or 0049 // escaped quote chars 0050 "(?:" // followed by 0051 "(?:\"" // Either a quote starting with " 0052 "(?:[^\"\\\\]|\\\\.)*\"" // followed by anything that is 0053 // not the end of the quote 0054 "|\'" // Or a quote starting with ' 0055 "(?:[^\'\\\\]|\\\\.)*\'" // followed by anything that is 0056 // not the end of the quote 0057 ")" // (End either) 0058 "[^\\s\'\"]*" // To the start of the next such fragment 0059 ")+" // Perform multiple matches of the above. 0060 ")" // End of quoted string handling. 0061 "|\\S+" // Apart from quoted strings, match 0062 // non-whitespace fragments also 0063 ")" // End match 0064 )); 0065 0066 #undef STRING_LITERAL 0067 } 0068 0069 Q_DECLARE_PUBLIC(AbstractNodeFactory) 0070 AbstractNodeFactory *const q_ptr; 0071 0072 public: 0073 QRegularExpression smartSplitRe; 0074 }; 0075 } 0076 0077 Node::Node(QObject *parent) 0078 : QObject(parent) 0079 , d_ptr(new NodePrivate(this)) 0080 { 0081 } 0082 0083 Node::~Node() 0084 { 0085 delete d_ptr; 0086 } 0087 0088 void Node::streamValueInContext(OutputStream *stream, const QVariant &input, Context *c) const 0089 { 0090 KTextTemplate::SafeString inputString; 0091 if (input.userType() == qMetaTypeId<QVariantList>()) { 0092 inputString = toString(input.value<QVariantList>()); 0093 } else if (input.userType() == qMetaTypeId<MetaEnumVariable>()) { 0094 const auto mev = input.value<MetaEnumVariable>(); 0095 if (mev.value >= 0) 0096 (*stream) << QString::number(mev.value); 0097 } else { 0098 inputString = getSafeString(input); 0099 } 0100 if (c->autoEscape() && !inputString.isSafe()) 0101 inputString.setNeedsEscape(true); 0102 0103 (*stream) << inputString; 0104 } 0105 0106 TemplateImpl *Node::containerTemplate() const 0107 { 0108 auto _parent = parent(); 0109 auto ti = qobject_cast<TemplateImpl *>(_parent); 0110 while (_parent && !ti) { 0111 _parent = _parent->parent(); 0112 ti = qobject_cast<TemplateImpl *>(_parent); 0113 } 0114 Q_ASSERT(ti); 0115 return ti; 0116 } 0117 0118 NodeList::NodeList() 0119 : m_containsNonText(false) 0120 { 0121 } 0122 0123 NodeList::NodeList(const NodeList &list) = default; 0124 0125 NodeList &NodeList::operator=(const NodeList &list) 0126 { 0127 if (&list == this) { 0128 return *this; 0129 } 0130 static_cast<QList<KTextTemplate::Node *> &>(*this) = static_cast<QList<KTextTemplate::Node *>>(list); 0131 m_containsNonText = list.m_containsNonText; 0132 return *this; 0133 } 0134 0135 NodeList::NodeList(const QList<KTextTemplate::Node *> &list) 0136 : QList<KTextTemplate::Node *>(list) 0137 , m_containsNonText(false) 0138 { 0139 for (KTextTemplate::Node *node : list) { 0140 auto textNode = qobject_cast<TextNode *>(node); 0141 if (!textNode) { 0142 m_containsNonText = true; 0143 return; 0144 } 0145 } 0146 } 0147 0148 NodeList::~NodeList() = default; 0149 0150 void NodeList::append(KTextTemplate::Node *node) 0151 { 0152 if (!m_containsNonText) { 0153 auto textNode = qobject_cast<TextNode *>(node); 0154 if (!textNode) 0155 m_containsNonText = true; 0156 } 0157 0158 QList<KTextTemplate::Node *>::append(node); 0159 } 0160 0161 void NodeList::append(const QList<KTextTemplate::Node *> &nodeList) 0162 { 0163 if (!m_containsNonText) { 0164 for (KTextTemplate::Node *node : nodeList) { 0165 auto textNode = qobject_cast<TextNode *>(node); 0166 if (!textNode) { 0167 m_containsNonText = true; 0168 break; 0169 } 0170 } 0171 } 0172 0173 QList<KTextTemplate::Node *>::append(nodeList); 0174 } 0175 0176 bool NodeList::containsNonText() const 0177 { 0178 return m_containsNonText; 0179 } 0180 0181 void NodeList::render(OutputStream *stream, Context *c) const 0182 { 0183 for (auto i = 0; i < this->size(); ++i) { 0184 this->at(i)->render(stream, c); 0185 } 0186 } 0187 0188 AbstractNodeFactory::AbstractNodeFactory(QObject *parent) 0189 : QObject(parent) 0190 , d_ptr(new AbstractNodeFactoryPrivate(this)) 0191 { 0192 } 0193 0194 AbstractNodeFactory::~AbstractNodeFactory() 0195 { 0196 delete d_ptr; 0197 } 0198 0199 QList<FilterExpression> AbstractNodeFactory::getFilterExpressionList(const QStringList &list, Parser *p) const 0200 { 0201 QList<FilterExpression> fes; 0202 for (auto &varString : list) { 0203 fes << FilterExpression(varString, p); 0204 } 0205 return fes; 0206 } 0207 0208 QStringList AbstractNodeFactory::smartSplit(const QString &str) const 0209 { 0210 Q_D(const AbstractNodeFactory); 0211 QStringList l; 0212 0213 auto i = d->smartSplitRe.globalMatch(str); 0214 while (i.hasNext()) { 0215 auto match = i.next(); 0216 l.append(match.captured()); 0217 } 0218 0219 return l; 0220 } 0221 0222 #include "moc_node.cpp"