doc/src/examples/qobjectxmlmodel.qdoc
changeset 0 1918ee327afb
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 documentation 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 /*!
       
    43   \example xmlpatterns/qobjectxmlmodel
       
    44   \title QObject XML Model Example
       
    45 
       
    46   This example shows how to use QtXmlPatterns to query QObject trees
       
    47   by modeling the non-XML data structure of a QObject tree to look
       
    48   like XML.
       
    49 
       
    50   \tableofcontents
       
    51 
       
    52   \section1 Introduction
       
    53 
       
    54   This example illustrates two important points about using XQuery to
       
    55   query non-XML data modeled to look like XML. The first point is that
       
    56   a custom node model class doesn't always have to actually build the
       
    57   node model. Sometimes the node model can be an already existing data
       
    58   structure, like the QObject tree used in this example. The second
       
    59   point is to explain what is required to make non-XML data look like
       
    60   XML.
       
    61 
       
    62   In this example, we want to model a QObject tree to look like
       
    63   XML. That is easy to do because a QObject tree maps to the XML tree
       
    64   structure in a staightforward way. Each QObject node is modeled as
       
    65   an XML element node. However, when we want to add the QMetaObject tree
       
    66   to the QObject tree node model, we are trying to add a second tree to
       
    67   the node model. The QMetaObject tree exists \e{behind} the QObject
       
    68   tree. Adding the QMetaObject tree to the node model changes the two
       
    69   dimensional tree into a three dimensional tree.
       
    70 
       
    71   The query engine can only traverse two dimensional trees, because an
       
    72   XML document is always a two dimensional tree. If we want to add the
       
    73   QMetaObject tree to the node model, we have to somehow flatten it
       
    74   into the same plane as the QObject tree. This requires that the
       
    75   node model class must build an auxiliary data structure and make it
       
    76   part of the two dimensional QObject node model. How to do this is
       
    77   explained in \l{Including The QMetaObject Tree}.
       
    78 
       
    79   \section2 The User Interface
       
    80 
       
    81   The UI for this example was created using Qt Designer:
       
    82 
       
    83   \image qobjectxmlmodel-example.png
       
    84 
       
    85   \section1 Code Walk-Through
       
    86 
       
    87   The strategy for this example is different from the strategy for the
       
    88   \l{File System Example}{file system example}. In the file system
       
    89   example, the node model class had to actually build a node model
       
    90   because the non-XML data to be traversed was the computer's file
       
    91   system, a structure stored on disk in a form that the query engine
       
    92   couldn't use. The node model class had to build an analog of the
       
    93   computer's file system in memory.
       
    94 
       
    95   For this example, the data structure to be traversed already exists
       
    96   in memory in a usable form. It is the QObject tree of the example
       
    97   application itself. All we need is the pointer to the root of the
       
    98   QObject tree.
       
    99 
       
   100   \note When we add the QMetaObject tree to the node model, the node
       
   101   model class will have to build an auxiliary data structure to move
       
   102   the QMetaObject tree into the same plane as the QObject tree. This
       
   103   is explained later in \l{Including The QMetaObject Tree}.
       
   104 
       
   105   \section2 The Custom Node Model Class: QObjextXmlModel
       
   106 
       
   107   The node model class for this example is QObjextXmlModel, which is
       
   108   derived from QSimpleXmlNodeModel. QObjextXmlModel implements the
       
   109   callback interface functions that don't have implementations in
       
   110   QSimpleXmlNodeModel: 
       
   111 
       
   112   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.h 0
       
   113 
       
   114   The node model class declares three data members:
       
   115 
       
   116   \target Three Data Members
       
   117   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.h 2
       
   118 
       
   119   The constructor sets \c m_baseURI to the QUrl constructed from the
       
   120   \l{QCoreApplication::applicationFilePath()}{file path} of the
       
   121   application executable.  This is the value returned by
       
   122   \l{QAbstractXmlNodeModel::documentUri()}{documentUri()}. The
       
   123   constructor sets \c{m_root} to point to the QObject tree for the
       
   124   example application. This is the node model that the query engine
       
   125   will use. And the constructor calls a local function to build the
       
   126   auxiliary data structure (\c{m_allMetaObjects}) for including the
       
   127   QMetaObject tree in the node model. How this auxiliary data
       
   128   structure is incorporated into the QObject node model is discussed
       
   129   in \l{Including The QMetaObject Tree}.
       
   130 
       
   131   \section3 Accessing The Node Model
       
   132 
       
   133   Since the query engine knows nothing about QObject trees, it can
       
   134   only access them by calling functions in the node model callback
       
   135   interface. The query engine passes a QXmlNodeModelIndex to uniquely
       
   136   identify a node in the node model. The QXmlNodeModelIndex is
       
   137   constructed from a pointer to the QObject that represents the node.
       
   138   \l{QAbstractXmlNodeModel::createIndex()}{createIndex()} creates the
       
   139   QXmlNodeModelIndex, as in the local \c{root()} function, for example:
       
   140 
       
   141   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 0
       
   142 
       
   143   A QObject represents an element node in the node model, but we also
       
   144   need to represent attribute nodes. For example, the class name of a
       
   145   QObject is an attribute of the QObject, so it should be an attribute
       
   146   node in the node model. A QObject's class name is obtained from the
       
   147   QObject. (Actually, it is in the QMetaObject, which is obtained from
       
   148   the QObject). This means that a single QObject logically represents
       
   149   multiple nodes in the node model: the element node and potentially
       
   150   many attribute nodes.
       
   151 
       
   152   To uniquely identify an attribute node, we need the pointer to the
       
   153   QObject containing the attribute, and an additional value that
       
   154   identifies the attribute in the QObject. For this \e{additional
       
   155   data} value, we use \c{enum QObjectNodeType}:
       
   156 
       
   157   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.h 3
       
   158 
       
   159   Ignore the \c{MetaObjectXXX} values for now. They will be explained
       
   160   in \l{Including The QMetaObject Tree}. Here we are interested in the
       
   161   three node types for QObject nodes: \c{IsQObject}, which represents
       
   162   the element node type for a QObject, and \c{QObjectProperty} and
       
   163   \c{QObjectClassName}, which represent the attribute node types for
       
   164   the attributes of a QObject.
       
   165 
       
   166   The \l{QAbstractXmlNodeModel::createIndex()}{createIndex()}
       
   167   function called in the \c{root()} snippet above is the overload that
       
   168   accepts a \c{void*} pointer and a second parameter,
       
   169   \c{additionalData}, with default value 0 (\c{IsQObject}). Wherever
       
   170   you see a call to \l{QAbstractXmlNodeModel::createIndex()}
       
   171   {createIndex()} that only passes the QObject pointer, it is creating
       
   172   the node index for a QObject element node. To create the node index
       
   173   for the class name attribute, for example, the \l{QObject
       
   174   attributes} {attributes()} function uses
       
   175   \c{createIndex(object,QObjectClassName)}.
       
   176 
       
   177   \target QObject attributes
       
   178   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 6
       
   179   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 8
       
   180 
       
   181   \l{QObject attributes} {attributes()} is one of the callback
       
   182   functions you have to implement in your custom node model class. It
       
   183   returns a QVector of \l{QXmlNodeModelIndex} {node indexes} for all
       
   184   the attribute nodes for QObject \c{n}. It calls
       
   185   \l{QAbstractXmlNodeModel::createIndex()} {createIndex()} in two places.
       
   186   Both calls use the QObject pointer from the current node \c{n} (the
       
   187   element node), and just add a different value for the \e{additional data}
       
   188   parameter. This makes sense because, in XML, the attributes of an
       
   189   element are part of that element. 
       
   190 
       
   191   \section3 Traversing The Node Model
       
   192 
       
   193   The query engine traverses the QObject tree by calling back to the
       
   194   node model class's implementation of \l{QObject nextFromSimpleAxis}
       
   195   {nextFromSimpleAxis()}. This function is the heart of the callback
       
   196   interface, and it will probably be the most complex to implement in
       
   197   your custom node model class. Below is a partial listing of the
       
   198   implementation for this example. The full listing will be shown in
       
   199   \l{Including The QMetaObject Tree}, where we discuss traversing the
       
   200   QMetaObject tree.
       
   201 
       
   202   \target QObject nextFromSimpleAxis
       
   203   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 2
       
   204   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 4
       
   205 
       
   206   The main switch uses \c toNodeType(), which obtains the node
       
   207   type from \l{QXmlNodeModelIndex::additionalData()}:
       
   208 
       
   209   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 1
       
   210 
       
   211   \c{case IsObject} case is the most interesting. It switches again on
       
   212   the value of the \c{axis} parameter, which specifies the direction
       
   213   the query engine wants to take from the current node. It is one of
       
   214   the four enum values of \l{QAbstractXmlNodeModel::SimpleAxis}.  The
       
   215   \l{QAbstractXmlNodeModel::Parent} {Parent} and
       
   216   \l{QAbstractXmlNodeModel::FirstChild} {FirstChild} cases reduce to
       
   217   calls to QObject::parent() and QObject::children()
       
   218   respectively. Note that a default constructed QXmlNodeModelIndex is
       
   219   returned in the \l{QAbstractXmlNodeModel::Parent} {Parent} case if
       
   220   the current node is the root, and in the
       
   221   \l{QAbstractXmlNodeModel::FirstChild} {FirstChild} case if the
       
   222   current node has no children.
       
   223 
       
   224   For the \l{QAbstractXmlNodeModel::NextSibling} {NextSibling} and
       
   225   \l{QAbstractXmlNodeModel::PreviousSibling} {PreviousSibling} axes,
       
   226   the helper function \c{qObjectSibling()} is called, with +1 to
       
   227   traverse to the \l{QAbstractXmlNodeModel::NextSibling} {NextSibling}
       
   228   and -1 to traverse to the
       
   229   \l{QAbstractXmlNodeModel::PreviousSibling} {PreviousSibling}.
       
   230 
       
   231   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 5
       
   232 
       
   233   \c{qObjectSibling()} determines whether or not the node has any
       
   234   siblings. It is called with \c{n}, the index of the current node.
       
   235   If the current node is a child, then it has a parent with children
       
   236   (the current node one of these).
       
   237   So, we get the \l{QObject::parent()}{parent}, obtain the parent's
       
   238   \l{QObject::children()} {child list}, find the current node in the
       
   239   list, and construct the node index for the next or previous child
       
   240   (sibling) and return it.
       
   241 
       
   242   \note In \l{QObject nextFromSimpleAxis} {nextFromSimpleAxis()}, the
       
   243   special case of asking for the
       
   244   \l{QAbstractXmlNodeModel::PreviousSibling} {PreviousSibling} of the
       
   245   root node is discussed in \l{Including The QMetaObject Tree}.
       
   246 
       
   247   Traversing away from a \c{QObjectClassName} attribute node or a
       
   248   \c{QObjectProperty} attribute node might seem a bit confusing at
       
   249   first glance. The only move allowed from an attribute node is to the
       
   250   \l{QAbstractXmlNodeModel::Parent} {Parent}, because attribute nodes
       
   251   don't have children. But these two cases simply return the 
       
   252   \l{QXmlNodeModelIndex} {node index} of the current node.
       
   253 
       
   254   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 7
       
   255 
       
   256   Since \c n is the QXmlNodeModelIndex of the current node, all this
       
   257   does is create another QXmlNodeModelIndex for the current node and
       
   258   return it. This was explained above in \l{Accessing The Node Model},
       
   259   where we saw that each QObject in the node model actually represents
       
   260   an element node and potentially many attribute nodes. Traversing to
       
   261   the parent node of an attribute simply creates a node index for the
       
   262   same QObject, but with an \e{additional data} value of 0
       
   263   (\c{IsQObject}).
       
   264 
       
   265   If we only wanted to traverse the QObject tree with XQuery, we could
       
   266   just implement the rest of the virtual callback functions listed
       
   267   earlier and we would be done. The implementations for the remaining
       
   268   functions are straightforward. But if we also want to use XQuery to
       
   269   traverse the QMetaObject tree, we must include the QMetaObject tree
       
   270   in the custom node model.
       
   271 
       
   272   \section3 Including The QMetaObject Tree
       
   273 
       
   274   The \l{Meta-Object System} {metaobject system} not only enables Qt's
       
   275   \l{Signals and Slots} {signals and slots}, it also provides type
       
   276   information that is useful at run-time; e.g., getting and setting
       
   277   properties without knowing the property names at compile time. Each
       
   278   QObject has an associated QMetaObject tree which contains all this
       
   279   useful type information. Given a QObject, its QMetaObject is
       
   280   obtained with QObject::metaObject(). Then QMetaObject::superClass()
       
   281   can be called repeatedly to get the QMetaObject for each class in the 
       
   282   class hierarchy for the original QObject.
       
   283 
       
   284   However, the QMetaObject hierarchy is a second tree in a plan that
       
   285   exists logically behind the plane of the QObject tree. The QtXmlPatterns
       
   286   query engine can only traverse a two dimensional node model that
       
   287   represents an XML tree. If we want to include the QMetaObject in the
       
   288   same node model that represents the QObject tree, we must find a way
       
   289   to flatten the QMetaObject tree into the same plane as the QObject
       
   290   tree.
       
   291 
       
   292   The node model class declares \l{All MetaObjects}{m_allMetaObjects}
       
   293   as a vector of pointers to QMetaObject:
       
   294 
       
   295   \target All MetaObjects
       
   296   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.h 1
       
   297   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.h 4
       
   298 
       
   299   This vector gets populated by the QObjectXmlModel constructor by
       
   300   calling the private allMetaObjects() function:
       
   301 
       
   302   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 9
       
   303 
       
   304   The first half of the function is an example of the standard code
       
   305   pattern for using QtXmlPatterns to run an XQuery. First it creates an
       
   306   instance of QXmlQuery. Then it \l{QXmlQuery::bindVariable()}{binds}
       
   307   the XQuery variable \c{$root} to the root node of the of the node
       
   308   model; i.e., the root of the QObject tree. Then it
       
   309   \l{QXmlQuery::setQuery()} {sets the query} to be an XQuery that
       
   310   returns all the QObjects in the node model. Finally, the query is
       
   311   evaluated into a \l{QXmlResultItems} {result item list}.
       
   312 
       
   313   \note \l{QXmlQuery::bindVariable()} must be called before
       
   314   \l{QXmlQuery::setQuery()}, because setting the query causes
       
   315   QtXmlPatterns to \e compile the XQuery, which requires knowledge of
       
   316   the variable bindings.
       
   317 
       
   318   The second half of the function traverses the \l{QXmlResultItems}
       
   319   {result item list}, getting the QMetaObject hierarchy for each
       
   320   QObject and appending it to \l{All MetaObjects} {m_allMetaObjects},
       
   321   if it isn't already there. But how do we include this vector of
       
   322   pointers to QMetaObjects in the node model? The key insight is
       
   323   shown in the full listing of \l{Full Listing of nextFromSimpleAxis}
       
   324   {nextFromSimpleAxis()}, where we are interested now in the 
       
   325   \c{MetaObjectXXX} cases:
       
   326 
       
   327   \target Full Listing of nextFromSimpleAxis
       
   328   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 2
       
   329   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 3
       
   330   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 4
       
   331 
       
   332   But first, revisit the \c{PreviousSibling} case for the
       
   333   \c{IsQObject} case:
       
   334 
       
   335   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 10
       
   336 
       
   337   When asking for the previous sibling of the root of the QObject
       
   338   tree, it creates a node model index with a null QObject pointer and
       
   339   an \c{additionalData} value of \c{MetaObjects}. This effectively
       
   340   allows the query engine to jump from the QObject tree to the
       
   341   QMetaObject tree.
       
   342 
       
   343   The query engine can jump from the QMetaObject tree back to the
       
   344   QObject tree in the \c{NextSibling} case of case \c{MetaObjects},
       
   345   where the \c{root()} function is called:
       
   346 
       
   347   \snippet examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp 11
       
   348 
       
   349   Having jumped from the QObject tree to the QMetaObject tree, the
       
   350   query engine will use the \c{MetaObject}, \c{MetaObjectClassName},
       
   351   and \c{MetaObjectSuperClass} cases, which are similar to the cases
       
   352   for \c{IsQObject}, \c{QObjectProperty}, and \c{QObjectClassName}.  
       
   353 */