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