A common data model involves lists, tables and trees of more or less uniform items. Several standard widgets provided by the library use such a model. The abstract WAbstractItemModel base class provides the interface which is used by these view classes.
Not only Table Views and Tree Views display (and interact with) data from an item model, but so do also the list-oriented widgets such as Combo box, Selection box, Auto complete, and charting widgets such as Cartesian Chart, Scatter Plot and Pie Chart.
An item model is essentially a table of items, where each item can be a parent to a nested table of items.
Since recursive statements like the one above can confuse even a seasoned programmer, let's start from a simple model, and extend it to more complex instances.
In its most simple and perhaps most common form, an item model simply stores a list of items. Such a model has only one column.
Each item may holds different facets of the data, stored as different Item Data Roles. If a table has two dimensions (rows an columns), then data roles could be considered as a third dimension.
The common use-case for item data roles is that for a single item, there may be a textual representation, but also an icon, a customized style class, a link, etc...
The built-in views will thus interpret subsets of this data to render a single item. In particular, the following data roles are commonly supported:
A tree model is - like a list - a model with a single column. In addition each item may be parent to another list.
At this point it becomes necessary to introduce the concept of a WModelIndex to uniquely identify an item. A model index is a data structucre containing:
The recursion is thus achieved by associating a parent index with each item index. By convention, top-level items have an Invalid index (which is a default constructed WModelIndex). To make the recursive definition consistent, one can also imagine an invisible root item (corresponding to the "invalid" index) which is the parent of the top-level items.
Finally, a tree table extends the list model by allow additional columns of data to be associated with each item row.
None of the standard Views render hierarchical data that is not present in the first column ! While such data structures can indeed be defined by item models, this will effectively be ignored by the standard View classes.
To get you going, and more than sufficient for simple needs, the library provides a number of standard and generic models, which store the data in memory.
Separating models from views would be not very useful, if it were not of the ablity to implement customized models. These could be models that compute some or all data on the fly, or fetch this information from a underlying database or file system, or simply display information from an existing data structure in a tabular/tree-like way.
As a minimum, a custom table model should reimplement the following methods from WAbstractTableModel:
As an example of a custom table model, consider the following (non-sensical) model that simply displays row/column information for each item.
A custom tree model involves considerably more work. Each internal item (in the first column) which has children, needs to be identified by a unique 64-bit value (which may thus be a long long or a void * pointer). Depending on the source data, a suitable choice must be made for this data.
The following methods must be implemented for a minimally compliant hierarchical model:
As an example of a tree table model, consider the following model that loads information from a git repository (in this case, Wt's git). Only a minimum of information is kept in memory: we allocate a data structure only for folders that are being expanded, for use as internal pointer data in model indexes.
A model may support sorting by one of its columns. This sorting can be implemented within the model itself.
Sorting may be bolted onto a source model using the WSortFilterProxyModel, which is one of the standard proxy models.
A model does not necessarily need to be a static data source, but its data can also change, and data (rows/columns) can be added or removed. A model needs to generate events to inform Views of these modifications (for the events to which a View is subscribed). When implementing a custom model which is dynamic in nature, it is therefore important to emit these signals when making the modifications.
The model API also provides a standard interface to perform editing of the data, and some Views (such as the Tree View and Table Views) can be configured to allow editing of the data.
If a custom wants to support this editing API, it needs to reimplement the following methods from WAbstractTableModel: