summaryrefslogtreecommitdiff
path: root/src/xmlpatterns/api/qvariableloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmlpatterns/api/qvariableloader.cpp')
-rw-r--r--src/xmlpatterns/api/qvariableloader.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/xmlpatterns/api/qvariableloader.cpp b/src/xmlpatterns/api/qvariableloader.cpp
new file mode 100644
index 0000000..9909508
--- /dev/null
+++ b/src/xmlpatterns/api/qvariableloader.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtXmlPatterns module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QVariant>
+#include <QStringList>
+
+#include "qanyuri_p.h"
+#include "qatomicstring_p.h"
+#include "qbuiltintypes_p.h"
+#include "qcommonsequencetypes_p.h"
+#include "qgenericsequencetype_p.h"
+#include "qinteger_p.h"
+#include "qitem_p.h"
+#include "qsequencetype_p.h"
+#include "qvariableloader_p.h"
+#include "qxmlquery_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QPatternist
+{
+
+ class VariantListIterator : public ListIteratorPlatform<QVariant, Item, VariantListIterator>
+ {
+ public:
+ inline VariantListIterator(const QVariantList &list) : ListIteratorPlatform<QVariant, Item, VariantListIterator>(list)
+ {
+ }
+
+ private:
+ friend class ListIteratorPlatform<QVariant, Item, VariantListIterator>;
+
+ inline Item inputToOutputItem(const QVariant &inputType) const
+ {
+ return AtomicValue::toXDM(inputType);
+ }
+ };
+
+ class StringListIterator : public ListIteratorPlatform<QString, Item, StringListIterator>
+ {
+ public:
+ inline StringListIterator(const QStringList &list) : ListIteratorPlatform<QString, Item, StringListIterator>(list)
+ {
+ }
+
+ private:
+ friend class ListIteratorPlatform<QString, Item, StringListIterator>;
+
+ static inline Item inputToOutputItem(const QString &inputType)
+ {
+ return AtomicString::fromValue(inputType);
+ }
+ };
+
+ /**
+ * Takes two DynamicContext instances, and redirects the storage of temporary trees
+ * to one of them.
+ *
+ * @since 4.5
+ */
+ class TemporaryTreesRedirectingContext : public DelegatingDynamicContext
+ {
+ public:
+ TemporaryTreesRedirectingContext(const DynamicContext::Ptr &other,
+ const DynamicContext::Ptr &modelStorage) : DelegatingDynamicContext(other)
+ , m_modelStorage(modelStorage)
+ {
+ Q_ASSERT(m_modelStorage);
+ }
+
+ virtual void addNodeModel(const QAbstractXmlNodeModel::Ptr &nodeModel)
+ {
+ m_modelStorage->addNodeModel(nodeModel);
+ }
+
+ private:
+ const DynamicContext::Ptr m_modelStorage;
+ };
+}
+
+using namespace QPatternist;
+
+SequenceType::Ptr VariableLoader::announceExternalVariable(const QXmlName name,
+ const SequenceType::Ptr &declaredType)
+{
+ Q_UNUSED(declaredType);
+ const QVariant &variant = m_bindingHash.value(name);
+
+
+ if(variant.isNull())
+ return SequenceType::Ptr();
+ else if(variant.userType() == qMetaTypeId<QIODevice *>())
+ return CommonSequenceTypes::ExactlyOneAnyURI;
+ else if(variant.userType() == qMetaTypeId<QXmlQuery>())
+ {
+ const QXmlQuery variableQuery(qvariant_cast<QXmlQuery>(variant));
+ return variableQuery.d->expression()->staticType();
+ }
+ else
+ {
+ return makeGenericSequenceType(AtomicValue::qtToXDMType(qvariant_cast<QXmlItem>(variant)),
+ Cardinality::exactlyOne());
+ }
+}
+
+Item::Iterator::Ptr VariableLoader::evaluateSequence(const QXmlName name,
+ const DynamicContext::Ptr &context)
+{
+
+ const QVariant &variant = m_bindingHash.value(name);
+ Q_ASSERT_X(!variant.isNull(), Q_FUNC_INFO,
+ "We assume that we have a binding.");
+
+ /* Same code as in the default clause below. */
+ if(variant.userType() == qMetaTypeId<QIODevice *>())
+ return makeSingletonIterator(itemForName(name));
+ else if(variant.userType() == qMetaTypeId<QXmlQuery>())
+ {
+ const QXmlQuery variableQuery(qvariant_cast<QXmlQuery>(variant));
+
+ return variableQuery.d->expression()->evaluateSequence(DynamicContext::Ptr(new TemporaryTreesRedirectingContext(variableQuery.d->dynamicContext(), context)));
+ }
+
+ const QVariant v(qvariant_cast<QXmlItem>(variant).toAtomicValue());
+
+ switch(v.type())
+ {
+ case QVariant::StringList:
+ return Item::Iterator::Ptr(new StringListIterator(v.toStringList()));
+ case QVariant::List:
+ return Item::Iterator::Ptr(new VariantListIterator(v.toList()));
+ default:
+ return makeSingletonIterator(itemForName(name));
+ }
+}
+
+Item VariableLoader::itemForName(const QXmlName &name) const
+{
+ const QVariant &variant = m_bindingHash.value(name);
+
+ if(variant.userType() == qMetaTypeId<QIODevice *>())
+ return Item(AnyURI::fromValue(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:") + m_namePool->stringForLocalName(name.localName())));
+
+ const QXmlItem item(qvariant_cast<QXmlItem>(variant));
+
+ if(item.isNode())
+ return Item::fromPublic(item);
+ else
+ {
+ const QVariant atomicValue(item.toAtomicValue());
+ /* If the atomicValue is null it means it doesn't exist in m_bindingHash, and therefore it must
+ * be a QIODevice, since Patternist guarantees to only ask for variables that announceExternalVariable()
+ * has accepted. */
+ if(atomicValue.isNull())
+ return Item(AnyURI::fromValue(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:") + m_namePool->stringForLocalName(name.localName())));
+ else
+ return AtomicValue::toXDM(atomicValue);
+ }
+}
+
+Item VariableLoader::evaluateSingleton(const QXmlName name,
+ const DynamicContext::Ptr &)
+{
+ return itemForName(name);
+}
+
+bool VariableLoader::isSameType(const QVariant &v1,
+ const QVariant &v2) const
+{
+ /* Are both of type QIODevice *? */
+ if(v1.userType() == qMetaTypeId<QIODevice *>() && v1.userType() == v2.userType())
+ return true;
+
+ /* Ok, we have two QXmlItems. */
+ const QXmlItem i1(qvariant_cast<QXmlItem>(v1));
+ const QXmlItem i2(qvariant_cast<QXmlItem>(v2));
+
+ if(i1.isNode())
+ {
+ Q_ASSERT(false);
+ return false;
+ }
+ else if(i2.isAtomicValue())
+ return i1.toAtomicValue().type() == i2.toAtomicValue().type();
+ else
+ {
+ /* One is an atomic, the other is a node or they are null. */
+ return false;
+ }
+}
+
+void VariableLoader::removeBinding(const QXmlName &name)
+{
+ m_bindingHash.remove(name);
+}
+
+bool VariableLoader::hasBinding(const QXmlName &name) const
+{
+ return m_bindingHash.contains(name)
+ || (m_previousLoader && m_previousLoader->hasBinding(name));
+}
+
+QVariant VariableLoader::valueFor(const QXmlName &name) const
+{
+ if(m_bindingHash.contains(name))
+ return m_bindingHash.value(name);
+ else if(m_previousLoader)
+ return m_previousLoader->valueFor(name);
+ else
+ return QVariant();
+}
+
+void VariableLoader::addBinding(const QXmlName &name,
+ const QVariant &value)
+{
+ m_bindingHash.insert(name, value);
+}
+
+bool VariableLoader::invalidationRequired(const QXmlName &name,
+ const QVariant &variant) const
+{
+ return hasBinding(name) && !isSameType(valueFor(name), variant);
+}
+
+QT_END_NAMESPACE
+