Qt Reference Documentation

# qobjectxmlmodel.cpp Example File

xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp

     /****************************************************************************
     **
     ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
     ** All rights reserved.
     ** Contact: Nokia Corporation (qt-info@nokia.com)
     **
     ** This file is part of the examples of the Qt Toolkit.
     **
     ** $QT_BEGIN_LICENSE:BSD$
     ** You may use this file under the terms of the BSD license as follows:
     **
     ** "Redistribution and use in source and binary forms, with or without
     ** modification, are permitted provided that the following conditions are
     ** met:
     **   * Redistributions of source code must retain the above copyright
     **     notice, this list of conditions and the following disclaimer.
     **   * Redistributions in binary form must reproduce the above copyright
     **     notice, this list of conditions and the following disclaimer in
     **     the documentation and/or other materials provided with the
     **     distribution.
     **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
     **     the names of its contributors may be used to endorse or promote
     **     products derived from this software without specific prior written
     **     permission.
     **
     ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
     ** $QT_END_LICENSE$
     **
     ****************************************************************************/

     #include <QVector>
     #include <QtDebug>

     #include <QCoreApplication>
     #include <QMetaProperty>
     #include <QXmlQuery>
     #include <QXmlResultItems>

     #include "qobjectxmlmodel.h"

     /*
     <metaObjects>
         <metaObject className="QObject"/>
         <metaObject className="QWidget" superClass="QObject">
         </metaObject>
         ...
     </metaObjects>
     <QObject objectName="MyWidget" property1="..." property2="..."> <!-- This is root() -->
         <QObject objectName="MyFOO" property1="..."/>
         ....
     </QObject>
     */

     QObjectXmlModel::QObjectXmlModel(QObject *const object, const QXmlNamePool &np)
         : QSimpleXmlNodeModel(np),
           m_baseURI(QUrl::fromLocalFile(QCoreApplication::applicationFilePath())),
           m_root(object),
           m_allMetaObjects(allMetaObjects())
     {
         Q_ASSERT(m_baseURI.isValid());
     }

     QXmlNodeModelIndex QObjectXmlModel::qObjectSibling(const int pos, const QXmlNodeModelIndex &n) const
     {
         Q_ASSERT(pos == 1 || pos == -1);
         Q_ASSERT(asQObject(n));

         const QObject *parent = asQObject(n)->parent();
         if (parent) {
             const QList<QObject *> &children = parent->children();
             const int siblingPos = children.indexOf(asQObject(n)) + pos;

             if (siblingPos >= 0 && siblingPos < children.count())
                 return createIndex(children.at(siblingPos));
             else
                 return QXmlNodeModelIndex();
         }
         else
             return QXmlNodeModelIndex();
     }

     QObjectXmlModel::QObjectNodeType QObjectXmlModel::toNodeType(const QXmlNodeModelIndex &n)
     {
         return QObjectNodeType(n.additionalData() & (15 << 26));
     }

     QObjectXmlModel::AllMetaObjects QObjectXmlModel::allMetaObjects() const
     {
         QXmlQuery query(namePool());
         query.bindVariable("root", root());
         query.setQuery("declare variable $root external;"
                        "$root/descendant-or-self::QObject");
         Q_ASSERT(query.isValid());

         QXmlResultItems result;
         query.evaluateTo(&result);
         QXmlItem i(result.next());

         AllMetaObjects objects;
         while (!i.isNull()) {
             const QMetaObject *moo = asQObject(i.toNodeModelIndex())->metaObject();
             while (moo) {
                 if (!objects.contains(moo))
                     objects.append(moo);
                 moo = moo->superClass();
             }
             i = result.next();
         }

         Q_ASSERT(!objects.contains(0));
         return objects;
     }

     QXmlNodeModelIndex QObjectXmlModel::metaObjectSibling(const int pos, const QXmlNodeModelIndex &n) const
     {
         Q_ASSERT(pos == 1 || pos == -1);
         Q_ASSERT(!n.isNull());

         const int indexOf = m_allMetaObjects.indexOf(static_cast<const QMetaObject *>(n.internalPointer())) + pos;

         if (indexOf >= 0 && indexOf < m_allMetaObjects.count())
             return createIndex(const_cast<QMetaObject *>(m_allMetaObjects.at(indexOf)), MetaObject);
         else
             return QXmlNodeModelIndex();
     }

     QXmlNodeModelIndex QObjectXmlModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &n) const
     {
         switch (toNodeType(n))
         {
             case IsQObject:
             {
                 switch (axis)
                 {
                     case Parent:
                         return createIndex(asQObject(n)->parent());

                     case FirstChild:
                     {
                         if (!asQObject(n) || asQObject(n)->children().isEmpty())
                             return QXmlNodeModelIndex();
                         else
                             return createIndex(asQObject(n)->children().first());
                     }

                     case NextSibling:
                         return qObjectSibling(1, n);

                     case PreviousSibling:
                     {
                         if (asQObject(n) == m_root)
                             return createIndex(qint64(0), MetaObjects);
                         else
                             return qObjectSibling(-1, n);
                     }
                 }
                 Q_ASSERT(false);
             }

             case QObjectClassName:
             case QObjectProperty:
             {
                 Q_ASSERT(axis == Parent);
                 return createIndex(asQObject(n));
             }

             case MetaObjects:
             {
                 switch (axis)
                 {
                     case Parent:
                         return QXmlNodeModelIndex();
                     case PreviousSibling:
                         return QXmlNodeModelIndex();
                     case NextSibling:
                         return root();
                     case FirstChild:
                     {
                         return createIndex(const_cast<QMetaObject*>(m_allMetaObjects.first()),MetaObject);
                     }
                 }
                 Q_ASSERT(false);
             }

             case MetaObject:
             {
                 switch (axis)
                 {
                     case FirstChild:
                         return QXmlNodeModelIndex();
                     case Parent:
                         return createIndex(qint64(0), MetaObjects);
                     case PreviousSibling:
                         return metaObjectSibling(-1, n);
                     case NextSibling:
                         return metaObjectSibling(1, n);
                 }
             }

             case MetaObjectClassName:
             case MetaObjectSuperClass:
             {
                 Q_ASSERT(axis == Parent);
                 return createIndex(asQObject(n), MetaObject);
             }
         }

         Q_ASSERT(false);
         return QXmlNodeModelIndex();
     }

     QVector<QXmlNodeModelIndex> QObjectXmlModel::attributes(const QXmlNodeModelIndex& n) const
     {
          QVector<QXmlNodeModelIndex> result;
          QObject *const object = asQObject(n);

          switch(toNodeType(n))
          {
             case IsQObject:
             {
                 const QMetaObject *const metaObject = object->metaObject();
                 const int count = metaObject->propertyCount();
                 result.append(createIndex(object, QObjectClassName));

                 for (int i = 0; i < count; ++i) {
                     const QMetaProperty qmp(metaObject->property(i));
                     const int ii = metaObject->indexOfProperty(qmp.name());
                     if (i == ii)
                         result.append(createIndex(object, QObjectProperty | i));
                 }
                 return result;
             }

             case MetaObject:
             {
                 result.append(createIndex(object, MetaObjectClassName));
                 result.append(createIndex(object, MetaObjectSuperClass));
                 return result;
             }
             default:
                 return QVector<QXmlNodeModelIndex>();
          }
     }

     QObject *QObjectXmlModel::asQObject(const QXmlNodeModelIndex &n)
     {
         return static_cast<QObject *>(n.internalPointer());
     }

     bool QObjectXmlModel::isProperty(const QXmlNodeModelIndex n)
     {
         return n.additionalData() & QObjectProperty;
     }

     QUrl QObjectXmlModel::documentUri(const QXmlNodeModelIndex& ) const
     {
         return m_baseURI;
     }

     QXmlNodeModelIndex::NodeKind QObjectXmlModel::kind(const QXmlNodeModelIndex& n) const
     {
         switch (toNodeType(n))
         {
             case IsQObject:
             case MetaObject:
             case MetaObjects:
                 return QXmlNodeModelIndex::Element;

             case QObjectProperty:
             case MetaObjectClassName:
             case MetaObjectSuperClass:
             case QObjectClassName:
                 return QXmlNodeModelIndex::Attribute;
         }

         Q_ASSERT(false);
         return QXmlNodeModelIndex::Element;
     }

     QXmlNodeModelIndex::DocumentOrder QObjectXmlModel::compareOrder(const QXmlNodeModelIndex& , const QXmlNodeModelIndex& ) const
     {
         return QXmlNodeModelIndex::Follows; // TODO
     }

     QXmlNodeModelIndex QObjectXmlModel::root() const
     {
         return createIndex(m_root);
     }

     QXmlNodeModelIndex QObjectXmlModel::root(const QXmlNodeModelIndex& n) const
     {
         QObject *p = asQObject(n);
         Q_ASSERT(p);

         do {
             QObject *const candidate = p->parent();
             if (candidate)
                 p = candidate;
             else
                 break;
         }
         while (true);

         return createIndex(p);
     }

     /*!
       We simply throw all of them into a QList and
       return an iterator over it.
      */
     QXmlNodeModelIndex::List QObjectXmlModel::ancestors(const QXmlNodeModelIndex n) const
     {
         const QObject *p = asQObject(n);
         Q_ASSERT(p);

         QXmlNodeModelIndex::List result;
         do {
             QObject *const candidate = p->parent();
             if (candidate) {
                 result.append(createIndex(candidate, 0));
                 p = candidate;
             }
             else
                 break;
         }
         while (true);

         return result;
     }

     QMetaProperty QObjectXmlModel::toMetaProperty(const QXmlNodeModelIndex &n)
     {
         const int propertyOffset = n.additionalData() & (~QObjectProperty);
         const QObject *const qo = asQObject(n);
         return qo->metaObject()->property(propertyOffset);
     }

     QXmlName QObjectXmlModel::name(const QXmlNodeModelIndex &n) const
     {
         switch (toNodeType(n))
         {
             case IsQObject:
                 return QXmlName(namePool(), QLatin1String("QObject"));
             case MetaObject:
                 return QXmlName(namePool(), QLatin1String("metaObject"));
             case QObjectClassName:
             case MetaObjectClassName:
                 return QXmlName(namePool(), QLatin1String("className"));
             case QObjectProperty:
                 return QXmlName(namePool(), toMetaProperty(n).name());
             case MetaObjects:
                 return QXmlName(namePool(), QLatin1String("metaObjects"));
             case MetaObjectSuperClass:
                 return QXmlName(namePool(), QLatin1String("superClass"));
         }

         Q_ASSERT(false);
         return QXmlName();
     }

     QVariant QObjectXmlModel::typedValue(const QXmlNodeModelIndex &n) const
     {
         switch (toNodeType(n))
         {
             case QObjectProperty:
             {
                const QVariant &candidate = toMetaProperty(n).read(asQObject(n));
                if (isTypeSupported(candidate.type()))
                    return candidate;
                else
                    return QVariant();
             }

             case MetaObjectClassName:
                 return QVariant(static_cast<QMetaObject*>(n.internalPointer())->className());

             case MetaObjectSuperClass:
             {
                 const QMetaObject *const superClass = static_cast<QMetaObject*>(n.internalPointer())->superClass();
                 if (superClass)
                     return QVariant(superClass->className());
                 else
                     return QVariant();
             }

             case QObjectClassName:
                 return QVariant(asQObject(n)->metaObject()->className());

             default:
                 return QVariant();
         }
     }

     /*!
      Returns \c true if QVariants of type \a type can be used
      in QtXmlPatterns, otherwise \c false.
      */
     bool QObjectXmlModel::isTypeSupported(QVariant::Type type)
     {
         /* See data/qatomicvalue.cpp too. */
         switch (type)
         {
             /* Fallthrough all these. */
             case QVariant::Char:
             case QVariant::String:
             case QVariant::Url:
             case QVariant::Bool:
             case QVariant::ByteArray:
             case QVariant::Int:
             case QVariant::LongLong:
             case QVariant::ULongLong:
             case QVariant::Date:
             case QVariant::DateTime:
             case QVariant::Time:
             case QVariant::Double:
                 return true;
             default:
                 return false;
         }
     }