qobjectxmlmodel.cpp Example File | Qt WebKit Examples 5.4

- Qt 5.4
- Qt WebKit Examples
- QObject XML Model Example
- qobjectxmlmodel.cpp Example File
- Qt 5.4.2 Reference Documentation

# qobjectxmlmodel.cpp Example File

webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp

    /****************************************************************************
    **
    ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
    ** Contact: http://www.qt-project.org/legal
    **
    ** 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 Digia Plc 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;
        }
    }