[SailfishDevel] One ListModel for multiple SilicaGridViews

Tomek discuss at tdress.de
Wed Apr 16 18:59:43 UTC 2014


Hi, 
I just wanted to share my general filter model (implemented in c++, supports flat list only) with the audience.
It might be a start for someone else’s work.

Here is how its used in QML:

FilterModel {
  id: filterModel
  roleNames: ["caption", "isActive"];

  Component.onCompleted: {
    filterModel.append({"caption": "A", "isActive" : true});
    filterModel.append({"caption": "A", "isActive" : true});
    filterModel.append({"caption": "B", "isActive" : true});
    filterModel.append({"caption": "B", "isActive" : true});
  }
}

ViewXYZ {
  model: filterModel
  delegate: Text { text: caption + " (" + isActive  + ")"}
}

Button {
  caption: "Add one"
  onButtonClicked: { filterModel.append({"caption": "A", "isActive" : false}); }
}
Button {
  caption: "Remove last"
  onButtonClicked: { filterModel.remove(filterModel.rowCountSource - 1); }
}
Button {
  caption: "Modify last"
  onButtonClicked: { filterModel.setProperty(filterModel.rowCountSource - 1, "caption", "C“); }
}
Button {
  caption: "Add filter"
  onButtonClicked: { filterModel.setFilter("caption", "A“); }
}
Button {
  caption: "Clear filter"
  onButtonClicked: { filterModel.clearFilter(); }
}


// --------------------------------------------------------------------------------------------------------------------
// filtermodel.h
// --------------------------------------------------------------------------------------------------------------------
#ifndef FILTERMODEL_H
#define FILTERMODEL_H
#include <QSortFilterProxyModel>
#include <QAbstractItemModel>
#include <QModelIndex>

#include <QHash>
#include <QByteArray>
#include <QString>

#include <QVariant>
#include <QVariantList>
#include <QVariantMap>


class ListModelPrivate: public QAbstractItemModel
{
    Q_OBJECT

public:
    explicit ListModelPrivate(QObject *parent = 0);
    ~ListModelPrivate();

    void setRoleNameList(QVariantList variantList);
    QHash<int,QByteArray> roleNames() const;

    QModelIndex parent(const QModelIndex &child) const;
    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    int columnCount(const QModelIndex &parent  = QModelIndex()) const;

    void append(QVariantMap variantMap);
    void remove(int i);
    void setProperty(int i, QString roleName, QVariant data);

    QVariant data(const QModelIndex &index, int role) const;

    int roleFromRoleName(QString roleName) const;

private:
    QHash<int, QByteArray> m_roleNames;
    QHash<QByteArray, int> m_roleNamesReverse;
    QList<QMap<QByteArray, QVariant> >* m_dataList;

};

class FilterModel: public QSortFilterProxyModel
{
    Q_OBJECT
    Q_PROPERTY(QVariantList roleNames READ roleNameList WRITE setRoleNameList NOTIFY roleNameListChanged)
    Q_PROPERTY(int rowCountSource READ rowCountSource)

public:
    FilterModel(QObject *parent = 0);
    ~FilterModel();

    QHash<int,QByteArray> roleNames() const;

    void setRoleNameList(QVariantList roleNameList);
    QVariantList roleNameList() const;

    Q_INVOKABLE int rowCountSource() const;
    Q_INVOKABLE void append(QVariantMap variantMap);
    Q_INVOKABLE void remove(int i);
    Q_INVOKABLE void setProperty(int i, QString roleName, QVariant data);

    Q_INVOKABLE void setFilter(QString filterRole, QString filterText);
    Q_INVOKABLE void clearFilter();

signals:
    void roleNameListChanged(QVariantList roleNames);

protected:
    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;

private:
    ListModelPrivate *m_sourceModel;
    QVariantList m_roleNameList;

};

#endif // FILTERMODEL_H



// --------------------------------------------------------------------------------------------------------------------
// filtermodel.cpp
// --------------------------------------------------------------------------------------------------------------------

#include "filtermodel.h"


ListModelPrivate::ListModelPrivate(QObject *parent)
    : QAbstractItemModel(parent)
{
    m_dataList = new QList<QMap<QByteArray, QVariant> >;
}

ListModelPrivate::~ListModelPrivate()
{
    delete m_dataList;
}

void ListModelPrivate::setRoleNameList(QVariantList roleNameList)
{
    for(int i = 0; i < roleNameList.size(); i++){
        QVariant variant = roleNameList.at(i);

        QString roleName = variant.toString();
        m_roleNames.insert(i,roleName.toUtf8());
        m_roleNamesReverse.insert(roleName.toUtf8(), i);
    }
}

QHash<int, QByteArray> ListModelPrivate::roleNames() const
{
    return m_roleNames;
}

QModelIndex ListModelPrivate::parent(const QModelIndex &child) const
{
    Q_UNUSED(child)
    return QModelIndex();
}

QModelIndex ListModelPrivate::index(int row, int column, const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    if (row < 0 || column < 0 || row >= m_dataList->size() || column >= m_roleNames.size())
    {
        return QModelIndex();
    }
    return createIndex(row, column, m_dataList);
}

int ListModelPrivate::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_dataList->size();
}

int ListModelPrivate::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_roleNames.size();
}

void ListModelPrivate::append(QVariantMap variantMap)
{
    if (variantMap.size() > 0)
    {
        beginInsertRows(QModelIndex(), rowCount(), rowCount());

        QList<QByteArray> keys = m_roleNamesReverse.keys();

        QMap<QByteArray, QVariant> map;
        QByteArray key;
        foreach (key, keys) {
            if (variantMap.contains(key))
            {
                map.insert(key, variantMap.value(key));
            }
            else
            {
                map.insert(key, QVariant());
            }
        }

        m_dataList->append(map);
        endInsertRows();
    }
}

void ListModelPrivate::remove(int i)
{
    if (i >= 0 && i < m_dataList->count())
    {
        beginRemoveRows(QModelIndex(), i, i);
        m_dataList->removeAt(i);
        endRemoveRows();
    }
}

QVariant ListModelPrivate::data(const QModelIndex &index, int role) const
{
    QVariant value;
    QByteArray roleName = m_roleNames.value(role, "");

    if (!roleName.isEmpty() && index.isValid() && index.row() < m_dataList->size())
    {
        QMap<QByteArray, QVariant> map = m_dataList->at(index.row());
        value = map.value(roleName);
    }
    return value;
}

void ListModelPrivate::setProperty(int i, QString roleName, QVariant data)
{

    if (i >= 0 && i < m_dataList->count())
    {
        int role = roleFromRoleName(roleName);
        if (role >= 0)
        {
            QMap<QByteArray, QVariant> map = m_dataList->at(i);

            map.insert(roleName.toUtf8(), data);
            (*m_dataList)[i] = map;

            QModelIndex index = createIndex(i,role);
            emit dataChanged(index, index);
        }
    }
}

int ListModelPrivate::roleFromRoleName(QString roleName) const
{
    return m_roleNamesReverse.value(roleName.toUtf8(), -1);
}

FilterModel::FilterModel(QObject *parent)
    : QSortFilterProxyModel(parent)
{
    m_sourceModel = new ListModelPrivate(parent);
    setSourceModel(m_sourceModel);
}

FilterModel::~FilterModel()
{
    delete m_sourceModel;
}

QHash<int,QByteArray> FilterModel::roleNames() const
{
    return m_sourceModel->roleNames();
}

void FilterModel::setRoleNameList(QVariantList roleNameList)
{
    if (m_roleNameList != roleNameList) {
        m_roleNameList = roleNameList;
        m_sourceModel->setRoleNameList(roleNameList);
        emit roleNameListChanged(roleNameList);
    }
}

QVariantList FilterModel::roleNameList() const
{
    return m_roleNameList;
}

int FilterModel::rowCountSource() const
{
    return m_sourceModel->rowCount();
}

void FilterModel::append(QVariantMap variantMap)
{
    m_sourceModel->append(variantMap);
}

void FilterModel::remove(int i)
{
    m_sourceModel->remove(i);
}

void FilterModel::setProperty(int i, QString roleName, QVariant data)
{
   m_sourceModel->setProperty(i, roleName, data);
}

bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
    if (filterRole() >= 0)
    {
        QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
        return (sourceModel()->data(index, filterRole()).toString().contains(filterRegExp()));
    }
    else
    {
        return true;
    }
}

void FilterModel::setFilter(QString filterRole, QString filterText)
{
    int role =  m_sourceModel->roleFromRoleName(filterRole);

    if (role >= 0)
    {
        setFilterRole(role);
        QRegExp rx(filterText, Qt::CaseSensitive, QRegExp::FixedString);
        setFilterRegExp(rx);
    }
    else
    {
       setFilterRole(-1);
    }
}

void FilterModel::clearFilter()
{
     setFilterRole(-1);
}





Am 16.03.2014 um 18:59 schrieb Andrey Kozhevnikov <coderusinbox at gmail.com>:

> well, its not trivial with GridView. You might need to use model to filteredmodel sorting manually, or implement  model in C++ with methods you need
> 
> On 16.03.2014 22:56, Tomek wrote:
>> Andrey, makes sense.
>> It is an model which is not related to the file system. 
>> Instead, it contains strings like caption and url and few booleans such as isFavourite and isActive.
>> I would like to use the mentioned booleans, to filter out elements is a SilicaGridView.
>> 
>> /Tomek
>> 
>> Am 16.03.2014 um 10:03 schrieb Andrey Kozhevnikov <coderusinbox at gmail.com>:
>> 
>>> what kind of model you implementing? files model and abstract data model solutions can be differ
>>> 
>>> On 16.03.2014 11:37, Tomek wrote:
>>>> I am wondering how I could display a single ListModel in multiple SilicaGridViews (filtered)?
>>>> Simply making an item invisible in a specific view does not work, because it still consumes (cellWidth x  cellHeight) the space.
>>>> I know, I could also implement my own model in c++. Probably something like this was done my someone already? 
>>>> 
>>>> 
>>>> Currently, I am experimenting with multiple models which I need to keep in sync (implementation is far from ready ;)).
>>>> [FilteredListModel.qml]
>>>> import QtQuick 2.0
>>>> import Sailfish.Silica 1.0
>>>> 
>>>> Item {
>>>>     property ListModel filteredModel: _filteredModel
>>>>     property ListModel model: _model
>>>>     property string filterRoleName
>>>>     property var filterValue
>>>>     ListModel {
>>>>         id: _filteredModel
>>>>     }
>>>>     ListModel {
>>>>         id: _model
>>>>         onRowsInserted: {
>>>>             for (var i = first; i <= last; i++) {
>>>>                 var entry = model.get(i);
>>>>                 if (entry[filterRoleName] === filterValue)
>>>>                 {
>>>>                   _filteredModel.append(entry);
>>>>                 }
>>>>             }
>>>>         }
>>>>         onRowsRemoved: {
>>>>              for (var i = first; i <= last; i++) {
>>>>                 _filteredModel.remove(i);
>>>>              }
>>>>         }
>>>>     }
>>>>     function append(sobject)
>>>>     {
>>>>         model.append(sobject);
>>>>     }
>>>>     function setProperty(index, key, value )
>>>>     {
>>>>         model.setProperty(index, key, value);
>>>>         var entry = model.get(index);
>>>>         if (entry[filterRoleName] === filterValue)
>>>>         {
>>>>             _filteredModel.set(index, model.get(index))
>>>>         }
>>>>         else
>>>>         {
>>>>             _filteredModel.remove(index);
>>>>         }
>>>>     }
>>>>     function remove(index)
>>>>     {
>>>>         model.remove(index);
>>>>     }
>>>>     Component.onCompleted: {
>>>>         model.append({"name": "Apple","cost": 0.25,active: false});
>>>>         model.append({"name": "Orange","cost": 0.90,active: true});
>>>>         model.append({"name": "Bannana","cost": 0.30,active: true});
>>>>         model.append({"name": "Ananas","cost": 3.10,active: true});
>>>>     }
>>>> }
>>>> 
>>>> 
>>>> 
>>>> _______________________________________________
>>>> SailfishOS.org Devel mailing list
>>> 
>>> _______________________________________________
>>> SailfishOS.org Devel mailing list
>> 
>> 
>> 
>> _______________________________________________
>> SailfishOS.org Devel mailing list
> 
> _______________________________________________
> SailfishOS.org Devel mailing list

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.sailfishos.org/pipermail/devel/attachments/20140416/54ac119a/attachment.html>


More information about the Devel mailing list