kategorie:

menu:


Tree model with Silica components

22.12.2016   ::    topics: Programming, Sailfish OS

When you have Qt data model representing tree (QAbstractItemModel), you can use TreeView component when you are creating UI with QtQuick.

QtQuick TreeView

But what to do when there is no similar native component for your platform? It is the case of Silica, native components for Sailfish OS – great mobile OS from Finnish company Jolla. I face this problem some days ago when I was creating map downloader for OSM Scout. Model of available maps represents tree of continents, countries and regions. I found inspiration in native File Browser where every directory is opened as a new page – it perfectly fits to Sailfish look & feel. But how to implement this behavior just in QML? Answer is DelegateModel from QtQml.Models.

For list entries for specific tree root can be used standard SilicaListView. Here is AvailableMapsView.qml component:

SilicaListView {
    id: listView

    property AvailableMapsModel originModel
    property var rootIndex

    signal click(int row, variant item)

    model: DelegateModel {
        id: visualModel
        model: originModel
        rootIndex : listView.rootIndex
        delegate:  ListItem{
            property variant myData: model

            // ... shortened by entry visuals

            onClicked: {
                listView.click(index, myData)
            }
        }
    }
}

Downloads.qml page:

AvailableMapsModel{
    id: availableMapsModel
}

AvailableMapsView{
    id:availableMapListView

    originModel:availableMapsModel

    onClick: {
        var index=availableMapsModel.index(row, /*column*/ 0 /* root as parent */);
        if (item.dir){
            pageStack.push(Qt.resolvedUrl("MapList.qml"),
                            {
                             availableMapsModel: availableMapsModel,
                             rootDirectoryIndex: index,
                             rootName: item.name,
                             downloadsPage: downloadsPage
                            })
        }else{
            pageStack.push(Qt.resolvedUrl("MapDetail.qml"),
                            {
                             availableMapsModel: availableMapsModel,
                             mapIndex: index,
                             mapName: item.name,
                             mapItem: item,
                             downloadsPage: downloadsPage
                            })
        }
    }
}

And almost the same MapList.qml:

Page {
    id: mapListPage

    property AvailableMapsModel availableMapsModel
    property var rootDirectoryIndex
    property string rootName
    property var downloadsPage

    // ... example shortened by SilicaFlickable, Column, PageHeader ...

    AvailableMapsView {
        id: availableMapListView

        originModel: availableMapsModel
        rootIndex: rootDirectoryIndex

        onClick: {
            var index=availableMapsModel.index(row, /*column*/ 0, /* parent */ rootDirectoryIndex);
            if (item.dir){
                pageStack.push(Qt.resolvedUrl("MapList.qml"),
                                {
                                 availableMapsModel: availableMapsModel,
                                 rootDirectoryIndex: index,
                                 rootName: item.name,
                                 downloadsPage: downloadsPage
                                })
            }else{
                pageStack.push(Qt.resolvedUrl("MapDetail.qml"),
                                {
                                 availableMapsModel: availableMapsModel,
                                 mapIndex: index,
                                 mapName: item.name,
                                 mapItem: item,
                                 downloadsPage: downloadsPage
                                })
            }
        }
    }
}

You can find complete source codes on GitHub. Here is the result: