[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