qobjectxmlmodel.cpp Example File | Qt WebKit Examples 5.9

Qt 5.9 | Qt WebKit Examples | QObject XML Model Example | qobjectxmlmodel.cpp Example File

Qt 5.9.2 Reference Documentation

# qobjectxmlmodel.cpp Example File

webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp

      /****************************************************************************
      **
      ** Copyright (C) 2015 The Qt Company Ltd.
      ** Contact: http://www.qt.io/licensing/
      **
      ** 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 The Qt Company Ltd 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;
          }
      }