diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 10:18:55 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 10:18:55 +0100 |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /doc/src/examples/editabletreemodel.qdoc | |
download | qt4-tools-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz |
Long live Qt 4.5!
Diffstat (limited to 'doc/src/examples/editabletreemodel.qdoc')
-rw-r--r-- | doc/src/examples/editabletreemodel.qdoc | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/doc/src/examples/editabletreemodel.qdoc b/doc/src/examples/editabletreemodel.qdoc new file mode 100644 index 0000000000..da018308e8 --- /dev/null +++ b/doc/src/examples/editabletreemodel.qdoc @@ -0,0 +1,459 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 + +*/ |