| 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 | */
|
|---|