doc/src/examples/simpledommodel.qdoc
branchRCL_3
changeset 7 3f74d0d4af4c
equal deleted inserted replaced
6:dee5afe5301f 7:3f74d0d4af4c
       
     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 itemviews/simpledommodel
       
    44     \title Simple DOM Model Example
       
    45 
       
    46     The Simple DOM Model example shows how an existing class can be adapted for use with
       
    47     the model/view framework.
       
    48 
       
    49     \image simpledommodel-example.png
       
    50 
       
    51     Qt provides two complementary sets of classes for reading XML files: The classes based
       
    52     around QXmlReader provide a SAX-style API for incremental reading of large files, and
       
    53     the classes based around QDomDocument enable developers to access the contents of XML
       
    54     files using a Document Object Model (DOM) API.
       
    55 
       
    56     In this example, we create a model that uses the DOM API to expose the structure and
       
    57     contents of XML documents to views via the standard QAbstractModel interface.
       
    58 
       
    59     \section1 Design and Concepts
       
    60 
       
    61     Reading an XML document with Qt's DOM classes is a straightforward process. Typically,
       
    62     the contents of a file are supplied to QDomDocument, and nodes are accessed using the
       
    63     functions provided by QDomNode and its subclasses.
       
    64 
       
    65     \omit
       
    66     For example, the following code
       
    67     snippet reads the contents of a file into a QDomDocument object and traverses the
       
    68     document, reading all the plain text that can be found:
       
    69 
       
    70     \snippet doc/src/snippets/code/doc_src_examples_simpledommodel.qdoc 0
       
    71 
       
    72     In principle, the functions provided by QDomNode can be used to navigate from any
       
    73     given starting point in a document to the piece of data requested by another component.
       
    74     Since QDomDocument maintains information about the structure of a document, we can
       
    75     use this to implement the required virtual functions in a QAbstractItemModel subclass.
       
    76     \endomit
       
    77 
       
    78     The aim is to use the structure provided by QDomDocument by wrapping QDomNode objects
       
    79     in item objects similar to the \c TreeItem objects used in the
       
    80     \l{Simple Tree Model Example}{Simple Tree Model} example.
       
    81 
       
    82     \section1 DomModel Class Definition
       
    83 
       
    84     Let us begin by examining the \c DomModel class:
       
    85 
       
    86     \snippet examples/itemviews/simpledommodel/dommodel.h 0
       
    87 
       
    88     The class definition contains all the basic functions that are needed for a
       
    89     read-only model. Only the constructor and \c document() function are specific to
       
    90     this model. The private \c domDocument variable is used to hold the document
       
    91     that is exposed by the model; the \c rootItem variable contains a pointer to
       
    92     the root item in the model.
       
    93 
       
    94     \section1 DomItem Class Definition
       
    95 
       
    96     The \c DomItem class is used to hold information about a specific QDomNode in
       
    97     the document:
       
    98 
       
    99     \snippet examples/itemviews/simpledommodel/domitem.h 0
       
   100 
       
   101     Each \c DomItem provides a wrapper for a QDomNode obtained from the underlying
       
   102     document which contains a reference to the node, it's location in the parent node's
       
   103     list of child nodes, and a pointer to a parent wrapper item.
       
   104 
       
   105     The \c parent(), \c child(), and \c row() functions are convenience functions for
       
   106     the \c DomModel to use that provide basic information about the item to be discovered
       
   107     quickly. The node() function provides access to the underlying QDomNode object.
       
   108 
       
   109     As well as the information supplied in the constructor, the class maintains a cache
       
   110     of information about any child items. This is used to provide a collection of
       
   111     persistent item objects that the model can identify consistently and improve the
       
   112     performance of the model when accessing child items.
       
   113 
       
   114     \section1 DomItem Class Implementation
       
   115 
       
   116     Since the \c DomItem class is only a thin wrapper around QDomNode objects, with a
       
   117     few additional features to help improve performance and memory usage, we can provide
       
   118     a brief outline of the class before discussing the model itself.
       
   119 
       
   120     The constructor simply records details of the QDomNode that needs to be wrapped:
       
   121 
       
   122     \snippet examples/itemviews/simpledommodel/domitem.cpp 0
       
   123     \snippet examples/itemviews/simpledommodel/domitem.cpp 1
       
   124 
       
   125     As a result, functions to provide the parent wrapper, the row number occupied by
       
   126     the item in its parent's list of children, and the underlying QDomNode for each item
       
   127     are straightforward to write:
       
   128 
       
   129     \snippet examples/itemviews/simpledommodel/domitem.cpp 4
       
   130     \codeline
       
   131     \snippet examples/itemviews/simpledommodel/domitem.cpp 6
       
   132     \codeline
       
   133     \snippet examples/itemviews/simpledommodel/domitem.cpp 3
       
   134 
       
   135     It is necessary to maintain a collection of items which can be consistently identified
       
   136     by the model. For that reason, we maintain a hash of child wrapper items that, to
       
   137     minimize memory usage, is initially empty. The model uses the item's \c child()
       
   138     function to help create model indexes, and this constructs wrappers for the children
       
   139     of the item's QDomNode, relating the row number of each child to the newly-constructed
       
   140     wrapper:
       
   141 
       
   142     \snippet examples/itemviews/simpledommodel/domitem.cpp 5
       
   143 
       
   144     If a QDomNode was previously wrapped, the cached wrapper is returned; otherwise, a
       
   145     new wrapper is constructed and stored for valid children, and zero is returned for
       
   146     invalid ones.
       
   147 
       
   148     The class's destructor deletes all the child items of the wrapper:
       
   149 
       
   150     \snippet examples/itemviews/simpledommodel/domitem.cpp 2
       
   151 
       
   152     These, in turn, will delete their children and free any QDomNode objects in use.
       
   153 
       
   154     \section1 DomModel Class Implementation
       
   155 
       
   156     The structure provided by the \c DomItem class makes the implementation of \c DomModel
       
   157     similar to the \c TreeModel shown in the
       
   158     \l{Simple Tree Model Example}{Simple Tree Model} example.
       
   159 
       
   160     The constructor accepts an existing document and a parent object for the model:
       
   161 
       
   162     \snippet examples/itemviews/simpledommodel/dommodel.cpp 0
       
   163 
       
   164     A shallow copy of the document is stored for future reference, and a root item is
       
   165     created to provide a wrapper around the document. We assign the root item a row
       
   166     number of zero only to be consistent since the root item will have no siblings.
       
   167 
       
   168     Since the model only contains information about the root item, the destructor only
       
   169     needs to delete this one item:
       
   170 
       
   171     \snippet examples/itemviews/simpledommodel/dommodel.cpp 1
       
   172 
       
   173     All of the child items in the tree will be deleted by the \c DomItem destructor as
       
   174     their parent items are deleted.
       
   175 
       
   176     \section2 Basic Properties of The Model
       
   177 
       
   178     Some aspects of the model do not depend on the structure of the underlying document,
       
   179     and these are simple to implement.
       
   180 
       
   181     The number of columns exposed by the model is returned by the \c columnCount()
       
   182     function:
       
   183 
       
   184     \snippet examples/itemviews/simpledommodel/dommodel.cpp 2
       
   185 
       
   186     This value is fixed, and does not depend on the location or type of the underlying
       
   187     node in the document. We will use these three columns to display different kinds of
       
   188     data from the underlying document.
       
   189 
       
   190     Since we only implement a read-only model, the \c flags() function is straightforward
       
   191     to write:
       
   192 
       
   193     \snippet examples/itemviews/simpledommodel/dommodel.cpp 5
       
   194 
       
   195     Since the model is intended for use in a tree view, the \c headerData() function only
       
   196     provides a horizontal header:
       
   197 
       
   198     \snippet examples/itemviews/simpledommodel/dommodel.cpp 6
       
   199 
       
   200     The model presents the names of nodes in the first column, element attributes in the
       
   201     second, and any node values in the third.
       
   202 
       
   203     \section2 Navigating The Document
       
   204 
       
   205     The index() function creates a model index for the item with the given row, column,
       
   206     and parent in the model:
       
   207 
       
   208     \snippet examples/itemviews/simpledommodel/dommodel.cpp 7
       
   209 
       
   210     The function first has to relate the parent index to an item that contains a node
       
   211     from the underlying document. If the parent index is invalid, it refers to the root
       
   212     node in the document, so we retrieve the root item that wraps it; otherwise, we
       
   213     obtain a pointer to the relevant item using the QModelIndex::internalPointer()
       
   214     function. We are able to extract a pointer in this way because any valid model index
       
   215     will have been created by this function, and we store pointers to item objects in
       
   216     any new indexes that we create with QAbstractItemModel::createIndex():
       
   217 
       
   218     \snippet examples/itemviews/simpledommodel/dommodel.cpp 8
       
   219 
       
   220     A child item for the given row is provided by the parent item's \c child() function.
       
   221     If a suitable child item was found then we call
       
   222     \l{QAbstractItemModel::createIndex()}{createIndex()} to produce a model index for the
       
   223     requested row and column, passing a pointer to the child item for it to store
       
   224     internally. If no suitable child item is found, an invalid model index is returned.
       
   225 
       
   226     Note that the items themselves maintain ownership of their child items. This means
       
   227     that the model does not need to keep track of the child items that have been created,
       
   228     and can let the items themselves tidy up when they are deleted.
       
   229 
       
   230     The number of rows beneath a given item in the model is returned by the \c rowCount()
       
   231     function, and is the number of child nodes contained by the node that corresponds to
       
   232     the specified model index:
       
   233 
       
   234     \snippet examples/itemviews/simpledommodel/dommodel.cpp 10
       
   235 
       
   236     To obtain the relevant node in the underlying document, we access the item via the
       
   237     internal pointer stored in the model index. If an invalid index is supplied, the
       
   238     root item is used instead. We use the item's \c node() function to access the node
       
   239     itself, and simply count the number of child nodes it contains.
       
   240 
       
   241     Since the model is used to represent a hierarchical data structure, it needs to
       
   242     provide an implementation for the \c parent() function. This returns a model index
       
   243     that corresponds to the parent of a child model index supplied as its argument:
       
   244 
       
   245     \snippet examples/itemviews/simpledommodel/dommodel.cpp 9
       
   246 
       
   247     For valid indexes other than the index corresponding to the root item, we obtain
       
   248     a pointer to the relevant item using the method described in the \c index() function,
       
   249     and use the item's \c parent() function to obtain a pointer to the parent item.
       
   250 
       
   251     If no valid parent item exists, or if the parent item is the root item, we can simply
       
   252     follow convention and return an invalid model index. For all other parent items, we
       
   253     create a model index containing the appropriate row and column numbers, and a pointer
       
   254     to the parent item we just obtained.
       
   255 
       
   256     Data is provided by the \c data() function. For simplicity, we only provide data for
       
   257     the \l{Qt::DisplayRole}{display role}, returning an invalid variant for all other
       
   258     requests:
       
   259 
       
   260     \snippet examples/itemviews/simpledommodel/dommodel.cpp 3
       
   261 
       
   262     As before, we obtain an item pointer for the index supplied, and use it to obtain
       
   263     the underlying document node. Depending on the column specified, the data we return
       
   264     is obtained in different ways:
       
   265 
       
   266     \snippet examples/itemviews/simpledommodel/dommodel.cpp 4
       
   267 
       
   268     For the first column, we return the node's name. For the second column, we read any
       
   269     attributes that the node may have, and return a string that contains a space-separated
       
   270     list of attribute-value assignments. For the third column, we return any value that
       
   271     the node may have; this allows the contents of text nodes to be displayed in a view.
       
   272 
       
   273     If data from any other column is requested, an invalid variant is returned.
       
   274 
       
   275     \section1 Implementation Notes
       
   276 
       
   277     Ideally, we would rely on the structure provided by QDomDocument to help us write
       
   278     the \l{QAbstractItemModel::parent()}{parent()} and
       
   279     \l{QAbstractItemModel::index()}{index()} functions that are required when subclassing
       
   280     QAbstractItemModel. However, since Qt's DOM classes use their own system for
       
   281     dynamically allocating memory for DOM nodes, we cannot guarantee that the QDomNode
       
   282     objects returned for a given piece of information will be the same for subsequent
       
   283     accesses to the document.
       
   284 
       
   285     We use item wrappers for each QDomNode to provide consistent pointers that the model
       
   286     can use to navigate the document structure.
       
   287     \omit
       
   288     Since these items contain value references to the QDomNode objects themselves, this
       
   289     has the side effect that the DOM nodes themselves can be used to reliably navigate
       
   290     the document [not sure about this - QDom* may return different QDomNode objects for
       
   291     the same piece of information]. However, this advantage is redundant since we need to
       
   292     use wrapper items to obtain it. [Possible use of QDomNode cache in the model itself.]
       
   293     \endomit
       
   294 */