source: trunk/doc/src/examples/qobjectxmlmodel.qdoc@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 16.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the documentation of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@nokia.com.
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 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*/
Note: See TracBrowser for help on using the repository browser.