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

Last change on this file since 1147 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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