src/xmlpatterns/api/qvariableloader.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    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(qVariantValue<QXmlQuery>(variant));
       
   135         return variableQuery.d->expression()->staticType();
       
   136     }
       
   137     else
       
   138     {
       
   139         return makeGenericSequenceType(AtomicValue::qtToXDMType(qVariantValue<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(qVariantValue<QXmlQuery>(variant));
       
   158 
       
   159         return variableQuery.d->expression()->evaluateSequence(DynamicContext::Ptr(new TemporaryTreesRedirectingContext(variableQuery.d->dynamicContext(), context)));
       
   160     }
       
   161 
       
   162     const QVariant v(qVariantValue<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(qVariantValue<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(qVariantValue<QXmlItem>(v1));
       
   214     const QXmlItem i2(qVariantValue<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