Description

The Filtered DataModel example allows the user to expand and collaps the header items in a ListView.

Overview

In this example we'll learn how to modify the structural appearance of a DataModel in a ListView by placing a filter model inbetween them. We will use the VegetablesDataModel from the vegetablesdatamodel example as source model and put a custom model FilteredDataModel on top of it to show all the top-level items but only the child items of the currently selected top-level item.

The UI

The UI of this sample application consists of a ListView that simply shows the content of our custom model.

We create the filter model in C++ and keep an object of it inside the App class.

Since the standard Header control, that is used by the ListView for header items, is too small, we declare our own ListItemComponent for it. The text inside the header is prefixed with a right or down arrow (used the Unicode symbols here), depending on the 'expanded' property of this header item. The 'expanded' property does not come from the source model but is injected by the FilteredDataModel.

The App class

App is the central class of the application that creates the UI and provides a public slot to mark one of the top-level items as selected.

Inside the constructor of App we create an instance of VegetablesDataModel, which acts as the source model, and an instance of FilteredDataModel, which takes the source model as parameter in its constructor.

Afterwards we load the UI from the main.qml file and export the FilteredDataModel object under the name '_model' to QML and the App object as '_app'. The latter is needed to be able to invoke the selectionChanged() slot from within the QML document.

Whenever the user selects a top-level item in the ListView, the selectionChanged() slot of the App object is invoked. Inside this slot we first check that the input parameters are valid. In the following steps we extract the index of the selected item and call the expandHeader() method on the FilteredDataModel object to toggle the expansion state of the item.

It reimplements all the abstract methods and additionally provides methods to toggle the expansion state of header items. It contains two member variables, one is the pointer to its source model and the other the index of the currently expanded header item.

Inside the childCount() method we test whether the passed 'indexPath' belongs to a header item that is not expanded. If that's the case we return '0', so the ListView won't show any child items underneath this header item. In all other cases, we simply forward the call to the source model.

Inside the hasChildren() method we test again whether the passed 'indexPath' belongs to a header item that is not expanded. If that's the case we return 'false', so the ListView won't show any child items underneath this header item. In all other cases, we simply forward the call to the source model.

Inside the data() method we test again whether the data for a header item or a normal item are requested. For a header item we want to enrich the original data (the color of the vegetables as string) with the current expansion state. We use a QVariantMap for this purpose, add an "data" entry with the original data from the source model and an "expanded" entry with a boolean value.

If the data of a normal item have been requested, we simply forward the call to the source model.

The expandHeader() method is called whenever the user selects a top-level item in the ListView. We first check whether the selected item should be expanded or collapsed. If it should be collapsed and the currently expanded item is the current one, we change set the index to '-1', which means none of the top-level items is expanded. In all other cases we set the passed index as the new expanded header.

The setExpandedHeader() method changes the member variable to new expanded index and emits the itemsChanged() signal that is defined in the bb::cascades::DataModel class. Whenever this signal is emitted, the ListView will reread all the structural information from the model and adapt its UI.