source: trunk/doc/src/examples/simpledommodel.qdoc@ 357

Last change on this file since 357 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 14.0 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 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*/
Note: See TracBrowser for help on using the repository browser.