summaryrefslogtreecommitdiff
path: root/doc/src/examples/editabletreemodel.qdoc
blob: d925c4340ccd94ee0b9b6212488d2aae1ca5543e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \example itemviews/editabletreemodel
    \title Editable Tree Model Example

    This example shows how to implement a simple item-based tree model that can
    be used with other classes the model/view framework.

    \image itemviews-editabletreemodel.png

    The model supports editable items, custom headers, and the ability to
    insert and remove rows and columns. With these features, it is also
    possible to insert new child items, and this is shown in the supporting
    example code.

    \note The model only shows the basic principles used when creating an
    editable, hierarchical model. You may wish to use the \l{ModelTest}
    project to test production models.

    \section1 Overview

    As described in the \l{Model Subclassing Reference}, models must
    provide implementations for the standard set of model functions:
    \l{QAbstractItemModel::}{flags()}, \l{QAbstractItemModel::}{data()},
    \l{QAbstractItemModel::}{headerData()}, and
    \l{QAbstractItemModel::}{rowCount()}. In addition, hierarchical models,
    such as this one, need to provide implementations of
    \l{QAbstractItemModel::}{index()} and \l{QAbstractItemModel::}{parent()}.

    An editable model needs to provide implementations of
    \l{QAbstractItemModel::}{setData()} and
    \l{QAbstractItemModel::}{headerData()}, and must return a suitable
    combination of flags from its \l{QAbstractItemModel::}{flags()} function.

    Since this example allows the dimensions of the model to be changed,
    we must also implement \l{QAbstractItemModel::}{insertRows()},
    \l{QAbstractItemModel::}{insertColumns()},
    \l{QAbstractItemModel::}{removeRows()}, and
    \l{QAbstractItemModel::}{removeColumns()}.

    \section1 Design

    As with the \l{itemviews/simpletreemodel}{Simple Tree Model} example,
    the model simply acts as a wrapper around a collection
    of instances of a \c TreeItem class. Each \c TreeItem is designed to
    hold data for a row of items in a tree view, so it contains a list of
    values corresponding to the data shown in each column.

    Since QTreeView provides a row-oriented view onto a model, it is
    natural to choose a row-oriented design for data structures that
    will supply data via a model to this kind of view. Although this makes
    the tree model less flexible, and possibly less useful for use with
    more sophisticated views, it makes it less complex to design and easier
    to implement.

    \target Relations-between-internal-items
    \table
    \row \o \inlineimage itemviews-editabletreemodel-items.png
    \o \bold{Relations between internal items}

    When designing a data structure for use with a custom model, it is useful
    to expose each item's parent via a function like
    \l{TreeItem::parent}{TreeItem::parent()} because it will make
    writing the model's own \l{QAbstractItemModel::}{parent()} function easier.
    Similarly, a function like \l{TreeItem::child}{TreeItem::child()} is
    helpful when implementing the model's \l{QAbstractItemModel::}{index()}
    function. As a result, each \c TreeItem maintains information about
    its parent and children, making it possible for us to traverse the tree
    structure.

    The diagram shows how \c TreeItem instances are connected via their
    \l{TreeItem::parent}{parent()} and \l{TreeItem::child}{child()}
    functions.

    In the example shown, two top-level items, \bold{A} and
    \bold{B}, can be obtained from the root item by calling its child()
    function, and each of these items return the root node from their
    parent() functions, though this is only shown for item \bold{A}.
    \endtable

    Each \c TreeItem stores data for each column in the row it represents
    in its \c itemData private member (a list of QVariant objects).
    Since there is a one-to-one mapping between each column in the view
    and each entry in the list, we provide a simple
    \l{TreeItem::data}{data()} function to read entries in the \c itemData
    list and a \l{TreeItem::setData}{setData()} function to allow them to
    be modified.
    As with other functions in the item, this simplifies the implemention
    of the model's \l{QAbstractItemModel::}{data()} and
    \l{QAbstractItemModel::}{setData()} functions.

    We place an item at the root of the tree of items. This root item
    corresponds to the null model index, \l{QModelIndex::}{QModelIndex()},
    that is used to represent the parent of a top-level item when handling
    model indexes.
    Although the root item does not have a visible representation in any of
    the standard views, we use its internal list of QVariant objects to
    store a list of strings that will be passed to views for use as
    horizontal header titles.

    \table
    \row \o \inlineimage itemviews-editabletreemodel-model.png
    \o \bold{Accessing data via the model}

    In the case shown in the diagram, the piece of information represented
    by \bold{a} can be obtained using the standard model/view API:

    \snippet doc/src/snippets/code/doc_src_examples_editabletreemodel.qdoc 0

    Since each items holds pieces of data for each column in a given row,
    there can be many model indexes that map to the same \c TreeItem object.
    For example, the information represented by \bold{b} can be obtained
    using the following code:

    \snippet doc/src/snippets/code/doc_src_examples_editabletreemodel.qdoc 1

    The same underlying \c TreeItem would be accessed to obtain information
    for the other model indexes in the same row as \bold{b}.
    \endtable

    In the model class, \c TreeModel, we relate \c TreeItem objects to
    model indexes by passing a pointer for each item when we create its
    corresponding model index with QAbstractItemModel::createIndex() in
    our \l{TreeModel::index}{index()} and \l{TreeModel::parent}{parent()}
    implementations.
    We can retrieve pointers stored in this way by calling the
    \l{QModelIndex::}{internalPointer()} function on the relevant model
    index - we create our own \l{TreeModel::getItem}{getItem()} function to
    do this work for us, and call it from our \l{TreeModel::data}{data()}
    and \l{TreeModel::parent}{parent()} implementations.

    Storing pointers to items is convenient when we control how they are
    created and destroyed since we can assume that an address obtained from
    \l{QModelIndex::}{internalPointer()} is a valid pointer.
    However, some models need to handle items that are obtained from other
    components in a system, and in many cases it is not possible to fully
    control how items are created or destroyed. In such situations, a pure
    pointer-based approach needs to be supplemented by safeguards to ensure
    that the model does not attempt to access items that have been deleted.

    \table
    \row \o \bold{Storing information in the underlying data structure}

    Several pieces of data are stored as QVariant objects in the \c itemData
    member of each \c TreeItem instance

    The diagram shows how pieces of information,
    represented by the labels \bold{a}, \bold{b} and \bold{c} in the
    previous two diagrams, are stored in items \bold{A}, \bold{B} and
    \bold{C} in the underlying data structure. Note that pieces of
    information from the same row in the model are all obtained from the
    same item. Each element in a list corresponds to a piece of information
    exposed by each column in a given row in the model.

    \o \inlineimage itemviews-editabletreemodel-values.png
    \endtable

    Since the \c TreeModel implementation has been designed for use with
    QTreeView, we have added a restriction on the way it uses \c TreeItem
    instances: each item must expose the same number of columns of data.
    This makes viewing the model consistent, allowing us to use the root
    item to determine the number of columns for any given row, and only
    adds the requirement that we create items containing enough data for
    the total number of columns. As a result, inserting and removing
    columns are time-consuming operations because we need to traverse the
    entire tree to modify every item.

    An alternative approach would be to design the \c TreeModel class so
    that it truncates or expands the list of data in individual \c TreeItem
    instances as items of data are modified. However, this "lazy" resizing
    approach would only allow us to insert and remove columns at the end of
    each row and would not allow columns to be inserted or removed at
    arbitrary positions in each row.

    \target Relating-items-using-model-indexes
    \table
    \row
    \o \inlineimage itemviews-editabletreemodel-indexes.png
    \o \bold{Relating items using model indexes}

    As with the \l{itemviews/simpletreemodel}{Simple Tree Model} example,
    the \c TreeModel needs to be able to take a model index, find the
    corresponding \c TreeItem, and return model indexes that correspond to
    its parents and children. 

    In the diagram, we show how the model's \l{TreeModel::parent()}{parent()}
    implementation obtains the model index corresponding to the parent of
    an item supplied by the caller, using the items shown in a
    \l{Relations-between-internal-items}{previous diagram}.

    A pointer to item \bold{C} is obtained from the corresponding model index
    using the \l{QModelIndex::internalPointer()} function. The pointer was
    stored internally in the index when it was created. Since the child
    contains a pointer to its parent, we use its \l{TreeItem::parent}{parent()}
    function to obtain a pointer to item \bold{B}. The parent model index is
    created using the QAbstractItemModel::createIndex() function, passing
    the pointer to item \bold{B} as the internal pointer.
    \endtable

    \section1 TreeItem Class Definition

    The \c TreeItem class provides simple items that contain several
    pieces of data, and which can provide information about their parent
    and child items:

    \snippet examples/itemviews/editabletreemodel/treeitem.h 0

    We have designed the API to be similar to that provided by
    QAbstractItemModel by giving each item functions to return the number
    of columns of information, read and write data, and insert and remove
    columns. However, we make the relationship between items explicit by
    providing functions to deal with "children" rather than "rows".

    Each item contains a list of pointers to child items, a pointer to its
    parent item, and a list of QVariant objects that correspond to
    information held in columns in a given row in the model.

    \section1 TreeItem Class Implementation

    Each \c TreeItem is constructed with a list of data and an optional
    parent item:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 0

    Initially, each item has no children. These are added to the item's
    internal \c childItems member using the \c insertChildren() function
    described later.

    The destructor ensures that each child added to the item is deleted
    when the item itself is deleted:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 1

    \target TreeItem::parent
    Since each item stores a pointer to its parent, the \c parent() function
    is trivial:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 9

    \target TreeItem::child
    Three functions provide information about the children of an item.
    \c child() returns a specific child from the internal list of children:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 2

    The \c childCount() function returns the total number of children:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 3

    The \c childNumber() function is used to determine the index of the child
    in its parent's list of children. It accesses the parent's \c childItems
    member directly to obtain this information:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 4

    The root item has no parent item; for this item, we return zero to be
    consistent with the other items.

    The \c columnCount() function simply returns the number of elements in
    the internal \c itemData list of QVariant objects:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 5

    \target TreeItem::data
    Data is retrieved using the \c data() function, which accesses the
    appropriate element in the \c itemData list:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 6

    \target TreeItem::setData
    Data is set using the \c setData() function, which only stores values
    in the \c itemData list for valid list indexes, corresponding to column
    values in the model:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 11

    To make implementation of the model easier, we return true to indicate
    whether the data was set successfully, or false if an invalid column

    Editable models often need to be resizable, enabling rows and columns to
    be inserted and removed. The insertion of rows beneath a given model index
    in the model leads to the insertion of new child items in the corresponding
    item, handled by the \c insertChildren() function:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 7

    This ensures that new items are created with the required number of columns
    and inserted at a valid position in the internal \c childItems list.
    Items are removed with the \c removeChildren() function:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 10

    As discussed above, the functions for inserting and removing columns are
    used differently to those for inserting and removing child items because
    they are expected to be called on every item in the tree. We do this by
    recursively calling this function on each child of the item:

    \snippet examples/itemviews/editabletreemodel/treeitem.cpp 8

    \section1 TreeModel Class Definition

    The \c TreeModel class provides an implementation of the QAbstractItemModel
    class, exposing the necessary interface for a model that can be edited and
    resized.

    \snippet examples/itemviews/editabletreemodel/treemodel.h 0

    The constructor and destructor are specific to this model.

    \snippet examples/itemviews/editabletreemodel/treemodel.h 1

    Read-only tree models only need to provide the above functions. The
    following public functions provide support for editing and resizing:

    \snippet examples/itemviews/editabletreemodel/treemodel.h 2

    To simplify this example, the data exposed by the model is organized into
    a data structure by the model's \l{TreeModel::setupModelData}{setupModelData()}
    function. Many real world models will not process the raw data at all, but
    simply work with an existing data structure or library API.

    \section1 TreeModel Class Implementation

    The constructor creates a root item and initializes it with the header
    data supplied:

    \snippet examples/itemviews/editabletreemodel/treemodel.cpp 0

    We call the internal \l{TreeModel::setupModelData}{setupModelData()}
    function to convert the textual data supplied to a data structure we can
    use with the model. Other models may be initialized with a ready-made
    data structure, or use an API to a library that maintains its own data.

    The destructor only has to delete the root item; all child items will
    be recursively deleted by the \c TreeItem destructor.

    \snippet examples/itemviews/editabletreemodel/treemodel.cpp 1

    \target TreeModel::getItem
    Since the model's interface to the other model/view components is based
    on model indexes, and the internal data structure is item-based, many of
    the functions implemented by the model need to be able to convert any
    given model index to its corresponding item. For convenience and
    consistency, we have defined a \c getItem() function to perform this
    repetitive task:

    \snippet examples/itemviews/editabletreemodel/treemodel.cpp 4

    This function assumes that each model index it is passed corresponds to
    a valid item in memory. If the index is invalid, or its internal pointer
    does not refer to a valid item, the root item is returned instead.

    The model's \c rowCount() implementation is simple: it first uses the
    \c getItem() function to obtain the relevant item, then returns the
    number of children it contains:

    \snippet examples/itemviews/editabletreemodel/treemodel.cpp 8

    By contrast, the \c columnCount() implementation does not need to look
    for a particular item because all items are defined to have the same
    number of columns associated with them.

    \snippet examples/itemviews/editabletreemodel/treemodel.cpp 2

    As a result, the number of columns can be obtained directly from the root
    item.

    To enable items to be edited and selected, the \c flags() function needs
    to be implemented so that it returns a combination of flags that includes
    the Qt::ItemIsEditable and Qt::ItemIsSelectable flags as well as
    Qt::ItemIsEnabled:

    \snippet examples/itemviews/editabletreemodel/treemodel.cpp 3

    \target TreeModel::index
    The model needs to be able to generate model indexes to allow other
    components to request data and information about its structure. This task
    is performed by the \c index() function, which is used to obtain model
    indexes corresponding to children of a given parent item:

    \snippet examples/itemviews/editabletreemodel/treemodel.cpp 5

    In this model, we only return model indexes for child items if the parent
    index is invalid (corresponding to the root item) or if it has a zero
    column number.

    We use the custom \l{TreeModel::getItem}{getItem()} function to obtain
    a \c TreeItem instance that corresponds to the model index supplied, and
    request its child item that corresponds to the specified row.

    \snippet examples/itemviews/editabletreemodel/treemodel.cpp 6

    Since each item contains information for an entire row of data, we create
    a model index to uniquely identify it by calling
    \l{QAbstractItemModel::}{createIndex()} it with the row and column numbers
    and a pointer to the item. In the \l{TreeModel::data}{data()} function,
    we will use the item pointer and column number to access the data
    associated with the model index; in this model, the row number is not
    needed to identify data.

    \target TreeModel::parent
    The \c parent() function supplies model indexes for parents of items
    by finding the corresponding item for a given model index, using its
    \l{TreeItem::parent}{parent()} function to obtain its parent item,
    then creating a model index to represent the parent. (See
    \l{Relating-items-using-model-indexes}{the above diagram}).

    \snippet examples/itemviews/editabletreemodel/treemodel.cpp 7

    Items without parents, including the root item, are handled by returning
    a null model index. Otherwise, a model index is created and returned as
    in the \l{TreeModel::index}{index()} function, with a suitable row number,
    but with a zero column number to be consistent with the scheme used in
    the \l{TreeModel::index}{index()} implementation.

    \target TreeModel::data
    \target TreeModel::setupModelData

*/