source: trunk/doc/src/examples/filetree.qdoc@ 1168

Last change on this file since 1168 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 18.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the documentation of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:FDL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in a
14** written agreement between you and Nokia.
15**
16** GNU Free Documentation License
17** Alternatively, this file may be used under the terms of the GNU Free
18** Documentation License version 1.3 as published by the Free Software
19** Foundation and appearing in the file included in the packaging of this
20** file.
21**
22** If you have questions regarding the use of this file, please contact
23** Nokia at [email protected].
24** $QT_END_LICENSE$
25**
26****************************************************************************/
27
28/*!
29 \example xmlpatterns/filetree
30 \title File System Example
31
32 This example shows how to use QtXmlPatterns for querying non-XML
33 data that is modeled to look like XML.
34
35 \tableofcontents
36
37 \section1 Introduction
38
39 The example models your computer's file system to look like XML and
40 allows you to query the file system with XQuery. Suppose we want to
41 find all the \c{cpp} files in the subtree beginning at
42 \c{/filetree}:
43
44 \image filetree_1-example.png
45
46 \section2 The User Inteface
47
48 The example is shown below. First, we use \c{File->Open Directory}
49 (not shown) to select the \c{/filetree} directory. Then we use the
50 combobox on the right to select the XQuery that searches for \c{cpp}
51 files (\c{listCPPFiles.xq}). Selecting an XQuery runs the query,
52 which in this case traverses the model looking for all the \c{cpp}
53 files. The XQuery text and the query results are shown on the right:
54
55 \image filetree_2-example.png
56
57 Don't be mislead by the XML representation of the \c{/filetree}
58 directory shown on the left. This is not the node model itself but
59 the XML obtained by traversing the node model and outputting it as
60 XML. Constructing and using the custom node model is explained in
61 the code walk-through.
62
63 \section2 Running your own XQueries
64
65 You can write your own XQuery files and run them in the example
66 program. The file \c{xmlpatterns/filetree/queries.qrc} is the \l{The
67 Qt Resource System} {resource file} for this example. It is used in
68 \c{main.cpp} (\c{Q_INIT_RESOURCE(queries);}). It lists the XQuery
69 files (\c{.xq}) that can be selected in the combobox.
70
71 \quotefromfile examples/xmlpatterns/filetree/queries.qrc
72 \printuntil
73
74 To add your own queries to the example's combobox, store your
75 \c{.xq} files in the \c{examples/xmlpatterns/filetree/queries}
76 directory and add them to \c{queries.qrc} as shown above.
77
78 \section1 Code Walk-Through
79
80 The strategy is to create a custom node model that represents the
81 directory tree of the computer's file system. That tree structure is
82 non-XML data. The custom node model must have the same callback
83 interface as the XML node models that the QtXmlPatterns query engine
84 uses to execute queries. The query engine can then traverse the
85 custom node model as if it were traversing the node model built from
86 an XML document.
87
88 The required callback interface is in QAbstractXmlNodeModel, so we
89 create a custom node model by subclassing QAbstractXmlNodeModel and
90 providing implementations for its pure virtual functions. For many
91 cases, the implementations of several of the virtual functions are
92 always the same, so QtXmlPatterns also provides QSimpleXmlNodeModel,
93 which subclasses QAbstractXmlNodeModel and provides implementations
94 for the callback functions that you can ignore. By subclassing
95 QSimpleXmlNodeModel instead of QAbstractXmlNodeModel, you can reduce
96 development time.
97
98 \section2 The Custom Node Model Class: FileTree
99
100 The custom node model for this example is class \c{FileTree}, which
101 is derived from QSimpleXmlNodeModel. \c{FileTree} implements all the
102 callback functions that don't have standard implementations in
103 QSimpleXmlNodeModel. When you implement your own custom node model,
104 you must provide implementations for these callback functions:
105
106 \snippet examples/xmlpatterns/filetree/filetree.h 0
107 \snippet examples/xmlpatterns/filetree/filetree.h 1
108
109 The \c{FileTree} class declares four data members:
110
111 \snippet examples/xmlpatterns/filetree/filetree.h 2
112
113 The QVector \c{m_fileInfos} will contain the node model. Each
114 QFileInfo in the vector will represent a file or a directory in the
115 file system. At this point it is instructive to note that although
116 the node model class for this example (\c{FileTree}) actually builds
117 and contains the custom node model, building the custom node model
118 isn't always required. The node model class for the \l{QObject XML
119 Model Example} {QObject node model example} does not build its node
120 model but instead uses an already existing QObject tree as its node
121 model and just implements the callback interface for that already
122 existing data structure. In this file system example, however,
123 although we have an already existing data structure, i.e. the file
124 system, that data structure is not in memory and is not in a form we
125 can use. So we must build an analog of the file system in memory
126 from instances of QFileInfo, and we use that analog as the custom
127 node model.
128
129 The two sets of flags, \c{m_filterAllowAll} and \c{m_sortFlags},
130 contain OR'ed flags from QDir::Filters and QDir::SortFlags
131 respectively. They are set by the \c{FileTree} constructor and used
132 in calls to QDir::entryInfoList() for getting the child list for a
133 directory node, i.e. a QFileInfoList containing the file and
134 directory nodes for all the immediate children of a directory.
135
136 The QVector \c{m_names} is an auxiliary component of the node
137 model. It holds the XML element and attribute names (QXmlName) for
138 all the node types that will be found in the node model. \c{m_names}
139 is indexed by the enum \c{FileTree::Type}, which specifies the node
140 types:
141
142 \target Node_Type
143 \snippet examples/xmlpatterns/filetree/filetree.h 4
144
145 \c{Directory} and \c{File} will represent the XML element nodes for
146 directories and files respectively, and the other enum values will
147 represent the XML attribute nodes for a file's path, name, suffix,
148 its size in bytes, and its mime type. The \c{FileTree} constructor
149 initializes \c{m_names} with an appropriate QXmlName for each
150 element and attribute type:
151
152 \snippet examples/xmlpatterns/filetree/filetree.cpp 2
153
154 Note that the constructor does \e{not} pre-build the entire node
155 model. Instead, the node model is built \e{incrementally} as the
156 query engine evaluates a query. To see how the query engine causes
157 the node model to be built incrementally, see \l{Building And
158 Traversing The Node Model}. To see how the query engine accesses the
159 node model, see \l{Accessing the node model}. See also: \l{Node
160 Model Building Strategy}.
161
162 \section3 Accessing The Node Model
163
164 Since the node model is stored outside the query engine in the
165 \c{FileTree} class, the query engine knows nothing about it and can
166 only access it by calling functions in the callback interface. When
167 the query engine calls any callback function to access data in the
168 node model, it passes a QXmlNodeModelIndex to identify the node in
169 the node model that it wants to access. Hence all the virtual
170 functions in the callback interface use a QXmlNodeModelIndex to
171 uniquely identify a node in the model.
172
173 We use the index of a QFileInfo in \c{m_fileInfos} to uniquely
174 identify a node in the node model. To get the QXmlNodeModelIndex for
175 a QFileInfo, the class uses the private function \c{toNodeIndex()}:
176
177 \target main toNodeIndex
178 \snippet examples/xmlpatterns/filetree/filetree.cpp 1
179
180 It searches the \c{m_fileInfos} vector for a QFileInfo that matches
181 \c{fileInfo}. If a match is found, its array index is passed to
182 QAbstractXmlNodeModel::createIndex() as the \c data value for the
183 QXmlNodeIndex. If no match is found, the unmatched QFileInfo is
184 appended to the vector, so this function is also doing the actual
185 incremental model building (see \l{Building And Traversing The Node
186 Model}).
187
188 Note that \c{toNodeIndex()} gets a \l{Node_Type} {node type} as the
189 second parameter, which it just passes on to
190 \l{QAbstractXmlNodeModel::createIndex()} {createIndex()} as the
191 \c{additionalData} value. Logically, this second parameter
192 represents a second dimension in the node model, where the first
193 dimension represents the \e element nodes, and the second dimension
194 represents each element's attribute nodes. The meaning is that each
195 QFileInfo in the \c{m_fileInfos} vector can represent an \e{element}
196 node \e{and} one or more \e{attribute} nodes. In particular, the
197 QFileInfo for a file will contain the values for the attribute nodes
198 path, name, suffix, size, and mime type (see
199 \c{FileTree::attributes()}). Since the attributes are contained in
200 the QFileInfo of the file element, there aren't actually any
201 attribute nodes in the node model. Hence, we can use a QVector for
202 \c{m_fileInfos}.
203
204 A convenience overloading of \l{toNodeIndex of convenience}
205 {toNodeIndex()} is also called in several places, wherever it is
206 known that the QXmlNodeModelIndex being requested is for a directory
207 or a file and not for an attribute. The convenience function takes
208 only the QFileInfo parameter and calls the other \l{main toNodeIndex}
209 {toNodeIndex()}, after obtaining either the Directory or File node
210 type directly from the QFileInfo:
211
212 \target toNodeIndex of convenience
213 \snippet examples/xmlpatterns/filetree/filetree.cpp 0
214
215 Note that the auxiliary vector \c{m_names} is accessed using the
216 \l{Node_Type} {node type}, for example:
217
218 \snippet examples/xmlpatterns/filetree/filetree.cpp 3
219
220 Most of the virtual functions in the callback interface are as
221 simple as the ones described so far, but the callback function used
222 for traversing (and building) the node model is more complex.
223
224 \section3 Building And Traversing The Node Model
225
226 The node model in \c{FileTree} is not fully built before the query
227 engine begins evaluating the query. In fact, when the query engine
228 begins evaluating its first query, the only node in the node model
229 is the one representing the root directory for the selected part of
230 the file system. See \l{The UI Class: MainWindow} below for details
231 about how the UI triggers creation of the model.
232
233 The query engine builds the node model incrementally each time it
234 calls the \l{next node on axis} {nextFromSimpleAxis()} callback
235 function, as it traverses the node model to evaluate a query. Thus
236 the query engine only builds the region of the node model that it
237 needs for evaluating the query.
238
239 \l{next node on axis} {nextFromSimpleAxis()} takes an
240 \l{QAbstractXmlNodeModel::SimpleAxis} {axis identifier} and a
241 \l{QXmlNodeModelIndex} {node identifier} as parameters. The
242 \l{QXmlNodeModelIndex} {node identifier} represents the \e{context
243 node} (i.e. the query engine's current location in the model), and
244 the \l{QAbstractXmlNodeModel::SimpleAxis} {axis identifier}
245 represents the direction we want to move from the context node. The
246 function finds the appropriate next node and returns its
247 QXmlNodeModelIndex.
248
249 \l{next node on axis} {nextFromSimpleAxis()} is where most of the
250 work of implementing a custom node model will be required. The
251 obvious way to do it is to use a switch statement with a case for
252 each \l{QAbstractXmlNodeModel::SimpleAxis} {axis}.
253
254 \target next node on axis
255 \snippet examples/xmlpatterns/filetree/filetree.cpp 4
256
257 The first thing this function does is call \l{to file info}
258 {toFileInfo()} to get the QFileInfo of the context node. The use of
259 QVector::at() here is guaranteed to succeed because the context node
260 must already be in the node model, and hence must have a QFileInfo
261 in \c{m_fileInfos}.
262
263 \target to file info
264 \snippet examples/xmlpatterns/filetree/filetree.cpp 6
265
266 The \l{QAbstractXmlNodeModel::Parent} {Parent} case looks up the
267 context node's parent by constructing a QFileInfo from the context
268 node's \l{QFileInfo::absoluteFilePath()} {path} and passing it to
269 \l{main toNodeIndex} {toNodeIndex()} to find the QFileInfo in
270 \c{m_fileInfos}.
271
272 The \l{QAbstractXmlNodeModel::FirstChild} {FirstChild} case requires
273 that the context node must be a directory, because a file doesn't
274 have children. If the context node is not a directory, a default
275 constructed QXmlNodeModelIndex is returned. Otherwise,
276 QDir::entryInfoList() constructs a QFileInfoList of the context
277 node's children. The first QFileInfo in the list is passed to
278 \l{toNodeIndex of convenience} {toNodeIndex()} to get its
279 QXmlNodeModelIndex. Note that this will add the child to the node
280 model, if it isn't in the model yet.
281
282 The \l{QAbstractXmlNodeModel::PreviousSibling} {PreviousSibling} and
283 \l{QAbstractXmlNodeModel::NextSibling} {NextSibling} cases call the
284 \l{nextSibling helper} {nextSibling() helper function}. It takes the
285 QXmlNodeModelIndex of the context node, the QFileInfo of the context
286 node, and an offest of +1 or -1. The context node is a child of some
287 parent, so the function gets the parent and then gets the child list
288 for the parent. The child list is searched to find the QFileInfo of
289 the context node. It must be there. Then the offset is applied, -1
290 for the previous sibling and +1 for the next sibling. The resulting
291 index is passed to \l{toNodeIndex of convenience} {toNodeIndex()} to
292 get its QXmlNodeModelIndex. Note again that this will add the
293 sibling to the node model, if it isn't in the model yet.
294
295 \target nextSibling helper
296 \snippet examples/xmlpatterns/filetree/filetree.cpp 5
297
298 \section2 The UI Class: MainWindow
299
300 The example's UI is a conventional Qt GUI application inheriting
301 QMainWindow and the Ui_MainWindow base class generated by
302 \l{Qt Designer Manual} {Qt Designer}.
303
304 \snippet examples/xmlpatterns/filetree/mainwindow.h 0
305
306 It contains the custom node model (\c{m_fileTree}) and an instance
307 of QXmlNodeModelIndex (\c{m_fileNode}) used for holding the node
308 index for the root of the file system subtree. \c{m_fileNode} will
309 be bound to a $variable in the XQuery to be evaluated.
310
311 Two actions of interest are handled by slot functions: \l{Selecting
312 A Directory To Model} and \l{Selecting And Running An XQuery}.
313
314 \section3 Selecting A Directory To Model
315
316 The user selects \c{File->Open Directory} to choose a directory to
317 be loaded into the custom node model. Choosing a directory signals
318 the \c{on_actionOpenDirectory_triggered()} slot:
319
320 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 1
321
322 The slot function simply calls the private function
323 \c{loadDirectory()} with the path of the chosen directory:
324
325 \target the standard code pattern
326 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 4
327
328 \c{loadDirectory()} demonstrates a standard code pattern for using
329 QtXmlPatterns programatically. First it gets the node model index
330 for the root of the selected directory. Then it creates an instance
331 of QXmlQuery and calls QXmlQuery::bindVariable() to bind the node
332 index to the XQuery variable \c{$fileTree}. It then calls
333 QXmlQuery::setQuery() to load the XQuery text.
334
335 \note QXmlQuery::bindVariable() must be called \e before calling
336 QXmlQuery::setQuery(), which loads and parses the XQuery text and
337 must have access to the variable binding as the text is parsed.
338
339 The next lines create an output device for outputting the query
340 result, which is then used to create a QXmlFormatter to format the
341 query result as XML. QXmlQuery::evaluateTo() is called to run the
342 query, and the formatted XML output is displayed in the left panel
343 of the UI window.
344
345 Finally, the private function \l{Selecting And Running An XQuery}
346 {evaluateResult()} is called to run the currently selected XQuery
347 over the custom node model.
348
349 \note As described in \l{Building And Traversing The Node Model},
350 the \c FileTree class wants to build the custom node model
351 incrementally as it evaluates the XQuery. But, because the
352 \c{loadDirectory()} function runs the \c{wholeTree.xq} XQuery, it
353 actually builds the entire node model anyway. See \l{Node Model
354 Building Strategy} for a discussion about building your custom node
355 model.
356
357 \section3 Selecting And Running An XQuery
358
359 The user chooses an XQuery from the menu in the combobox on the
360 right. Choosing an XQuery signals the
361 \c{on_queryBox_currentIndexChanged()} slot:
362
363 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 2
364
365 The slot function opens and loads the query file and then calls the
366 private function \c{evaluateResult()} to run the query:
367
368 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 3
369
370 \c{evaluateResult()} is a second example of the same code pattern
371 shown in \l{the standard code pattern} {loadDirectory()}. In this
372 case, it runs the XQuery currently selected in the combobox instead
373 of \c{qrc:/queries/wholeTree.xq}, and it outputs the query result to
374 the panel on the lower right of the UI window.
375
376 \section2 Node Model Building Strategy
377
378 We saw that the \l{The Custom Node Model Class: FileTree} {FileTree}
379 tries to build its custom node model incrementally, but we also saw
380 that the \l{the standard code pattern} {MainWindow::loadDirectory()}
381 function in the UI class immediately subverts the incremental build
382 by running the \c{wholeTree.xq} XQuery, which traverses the entire
383 selected directory, thereby causing the entire node model to be
384 built.
385
386 If we want to preserve the incremental build capability of the
387 \c{FileTree} class, we can strip the running of \c{wholeTree.xq} out
388 of \l{the standard code pattern} {MainWindow::loadDirectory()}:
389
390 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 5
391 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 6
392
393 Note, however, that \c{FileTree} doesn't have the capability of
394 deleting all or part of the node model. The node model, once built,
395 is only deleted when the \c{FileTree} instance goes out of scope.
396
397 In this example, each element node in the node model represents a
398 directory or a file in the computer's file system, and each node is
399 represented by an instance of QFileInfo. An instance of QFileInfo is
400 not costly to produce, but you might imagine a node model where
401 building new nodes is very costly. In such cases, the capability to
402 build the node model incrementally is important, because it allows
403 us to only build the region of the model we need for evaluating the
404 query. In other cases, it will be simpler to just build the entire
405 node model.
406
407*/
Note: See TracBrowser for help on using the repository browser.