doc/src/examples/filetree.qdoc
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the documentation of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 */