d974d4a4079cd8510328f9592d1bb76f6e23138f
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / api / qvariableloader.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QVariant>
43 #include <QStringList>
44
45 #include "qanyuri_p.h"
46 #include "qatomicstring_p.h"
47 #include "qbuiltintypes_p.h"
48 #include "qcommonsequencetypes_p.h"
49 #include "qgenericsequencetype_p.h"
50 #include "qinteger_p.h"
51 #include "qitem_p.h"
52 #include "qsequencetype_p.h"
53 #include "qvariableloader_p.h"
54 #include "qxmlquery_p.h"
55
56 QT_BEGIN_NAMESPACE
57
58 namespace QPatternist
59 {
60
61     class VariantListIterator : public ListIteratorPlatform<QVariant, Item, VariantListIterator>
62     {
63     public:
64         inline VariantListIterator(const QVariantList &list) : ListIteratorPlatform<QVariant, Item, VariantListIterator>(list)
65         {
66         }
67
68     private:
69         friend class ListIteratorPlatform<QVariant, Item, VariantListIterator>;
70
71         inline Item inputToOutputItem(const QVariant &inputType) const
72         {
73             return AtomicValue::toXDM(inputType);
74         }
75     };
76
77     class StringListIterator : public ListIteratorPlatform<QString, Item, StringListIterator>
78     {
79     public:
80         inline StringListIterator(const QStringList &list) : ListIteratorPlatform<QString, Item, StringListIterator>(list)
81         {
82         }
83
84     private:
85         friend class ListIteratorPlatform<QString, Item, StringListIterator>;
86
87         static inline Item inputToOutputItem(const QString &inputType)
88         {
89             return AtomicString::fromValue(inputType);
90         }
91     };
92
93     /**
94      * Takes two DynamicContext instances, and redirects the storage of temporary trees
95      * to one of them.
96      *
97      * @since 4.5
98      */
99     class TemporaryTreesRedirectingContext : public DelegatingDynamicContext
100     {
101     public:
102         TemporaryTreesRedirectingContext(const DynamicContext::Ptr &other,
103                                          const DynamicContext::Ptr &modelStorage) : DelegatingDynamicContext(other)
104                                                                                   , m_modelStorage(modelStorage)
105         {
106             Q_ASSERT(m_modelStorage);
107         }
108
109         virtual void addNodeModel(const QAbstractXmlNodeModel::Ptr &nodeModel)
110         {
111             m_modelStorage->addNodeModel(nodeModel);
112         }
113
114     private:
115         const DynamicContext::Ptr m_modelStorage;
116     };
117 }
118
119 using namespace QPatternist;
120
121 SequenceType::Ptr VariableLoader::announceExternalVariable(const QXmlName name,
122                                                            const SequenceType::Ptr &declaredType)
123 {
124     Q_UNUSED(declaredType);
125     const QVariant &variant = m_bindingHash.value(name);
126
127
128     if(variant.isNull())
129         return SequenceType::Ptr();
130     else if(variant.userType() == qMetaTypeId<QIODevice *>())
131         return CommonSequenceTypes::ExactlyOneAnyURI;
132     else if(variant.userType() == qMetaTypeId<QXmlQuery>())
133     {
134         const QXmlQuery variableQuery(qvariant_cast<QXmlQuery>(variant));
135         return variableQuery.d->expression()->staticType();
136     }
137     else
138     {
139         return makeGenericSequenceType(AtomicValue::qtToXDMType(qvariant_cast<QXmlItem>(variant)),
140                                        Cardinality::exactlyOne());
141     }
142 }
143
144 Item::Iterator::Ptr VariableLoader::evaluateSequence(const QXmlName name,
145                                                      const DynamicContext::Ptr &context)
146 {
147
148     const QVariant &variant = m_bindingHash.value(name);
149     Q_ASSERT_X(!variant.isNull(), Q_FUNC_INFO,
150                "We assume that we have a binding.");
151
152     /* Same code as in the default clause below. */
153     if(variant.userType() == qMetaTypeId<QIODevice *>())
154         return makeSingletonIterator(itemForName(name));
155     else if(variant.userType() == qMetaTypeId<QXmlQuery>())
156     {
157         const QXmlQuery variableQuery(qvariant_cast<QXmlQuery>(variant));
158
159         return variableQuery.d->expression()->evaluateSequence(DynamicContext::Ptr(new TemporaryTreesRedirectingContext(variableQuery.d->dynamicContext(), context)));
160     }
161
162     const QVariant v(qvariant_cast<QXmlItem>(variant).toAtomicValue());
163
164     switch(v.type())
165     {
166         case QVariant::StringList:
167             return Item::Iterator::Ptr(new StringListIterator(v.toStringList()));
168         case QVariant::List:
169             return Item::Iterator::Ptr(new VariantListIterator(v.toList()));
170         default:
171             return makeSingletonIterator(itemForName(name));
172     }
173 }
174
175 Item VariableLoader::itemForName(const QXmlName &name) const
176 {
177     const QVariant &variant = m_bindingHash.value(name);
178
179     if(variant.userType() == qMetaTypeId<QIODevice *>())
180         return Item(AnyURI::fromValue(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:") + m_namePool->stringForLocalName(name.localName())));
181
182     const QXmlItem item(qvariant_cast<QXmlItem>(variant));
183
184     if(item.isNode())
185         return Item::fromPublic(item);
186     else
187     {
188         const QVariant atomicValue(item.toAtomicValue());
189         /* If the atomicValue is null it means it doesn't exist in m_bindingHash, and therefore it must
190          * be a QIODevice, since Patternist guarantees to only ask for variables that announceExternalVariable()
191          * has accepted. */
192         if(atomicValue.isNull())
193             return Item(AnyURI::fromValue(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:") + m_namePool->stringForLocalName(name.localName())));
194         else
195             return AtomicValue::toXDM(atomicValue);
196     }
197 }
198
199 Item VariableLoader::evaluateSingleton(const QXmlName name,
200                                        const DynamicContext::Ptr &)
201 {
202     return itemForName(name);
203 }
204
205 bool VariableLoader::isSameType(const QVariant &v1,
206                                 const QVariant &v2) const
207 {
208     /* Are both of type QIODevice *? */
209     if(v1.userType() == qMetaTypeId<QIODevice *>() && v1.userType() == v2.userType())
210         return true;
211
212     /* Ok, we have two QXmlItems. */
213     const QXmlItem i1(qvariant_cast<QXmlItem>(v1));
214     const QXmlItem i2(qvariant_cast<QXmlItem>(v2));
215
216     if(i1.isNode())
217     {
218         Q_ASSERT(false);
219         return false;
220     }
221     else if(i2.isAtomicValue())
222         return i1.toAtomicValue().type() == i2.toAtomicValue().type();
223     else
224     {
225         /* One is an atomic, the other is a node or they are null. */
226         return false;
227     }
228 }
229
230 void VariableLoader::removeBinding(const QXmlName &name)
231 {
232     m_bindingHash.remove(name);
233 }
234
235 bool VariableLoader::hasBinding(const QXmlName &name) const
236 {
237     return m_bindingHash.contains(name)
238         || (m_previousLoader && m_previousLoader->hasBinding(name));
239 }
240
241 QVariant VariableLoader::valueFor(const QXmlName &name) const
242 {
243     if(m_bindingHash.contains(name))
244         return m_bindingHash.value(name);
245     else if(m_previousLoader)
246         return m_previousLoader->valueFor(name);
247     else
248         return QVariant();
249 }
250
251 void VariableLoader::addBinding(const QXmlName &name,
252                                 const QVariant &value)
253 {
254     m_bindingHash.insert(name, value);
255 }
256
257 bool VariableLoader::invalidationRequired(const QXmlName &name,
258                                           const QVariant &variant) const
259 {
260     return hasBinding(name) && !isSameType(valueFor(name), variant);
261 }
262
263 QT_END_NAMESPACE
264