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