From 10d19014fe2c9c02f2bc3e19732cbe340e316076 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 10 Nov 2015 12:05:39 +0100 Subject: A result model The result model drives the data retrieval and provides the interace for consumers --- common/modelresult.h | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 common/modelresult.h (limited to 'common') diff --git a/common/modelresult.h b/common/modelresult.h new file mode 100644 index 0000000..c23c41e --- /dev/null +++ b/common/modelresult.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2014 Christian Mollekopf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#pragma once + +#include +#include +#include +#include "query.h" +#include "clientapi.h" + +#include "resultprovider.h" + +template +class ModelResult : public QAbstractItemModel +{ +public: + + enum Roles { + DomainObjectRole = Qt::UserRole + 1 + }; + + ModelResult(const Akonadi2::Query &query, const QList &propertyColumns) + :QAbstractItemModel(), + mPropertyColumns(propertyColumns) + { + } + + static qint64 getIdentifier(const QModelIndex &idx) + { + if (!idx.isValid()) { + return 0; + } + return idx.internalId(); + } + + int rowCount(const QModelIndex &parent = QModelIndex()) const + { + return mTree[getIdentifier(parent)].size(); + } + + int columnCount(const QModelIndex &parent = QModelIndex()) const + { + return mPropertyColumns.size(); + } + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const + { + if (role == DomainObjectRole) { + qWarning() << "trying to get entity " << index.internalId(); + Q_ASSERT(mEntities.contains(index.internalId())); + return QVariant::fromValue(mEntities.value(index.internalId())); + } + qDebug() << "Invalid role"; + return QVariant(); + } + + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const + { + auto id = getIdentifier(parent); + auto childId = mTree.value(id).at(row); + return createIndex(row, column, childId); + } + + QModelIndex parent(const QModelIndex &index) const + { + auto id = getIdentifier(index); + auto parentId = mParents.value(id); + auto grandParentId = mParents.value(parentId, 0); + auto row = mTree.value(grandParentId).indexOf(parentId); + return createIndex(row, 0, parentId); + } + + bool canFetchMore(const QModelIndex &parent) const + { + return mEntityChildrenFetched.value(parent.internalId()); + } + + void fetchMore(const QModelIndex &parent) + { + fetchEntities(parent); + } + + void fetchEntities(const QModelIndex &parent) + { + qDebug() << "Fetching entities"; + const auto id = getIdentifier(parent); + // beginResetModel(); + // mEntities.remove(id); + mEntityChildrenFetched[id] = true; + auto query = mQuery; + if (!parent.isValid()) { + qDebug() << "no parent"; + query.propertyFilter.insert("parent", QByteArray()); + } else { + qDebug() << "parent is valid"; + auto object = parent.data(DomainObjectRole).template value(); + Q_ASSERT(object); + query.propertyFilter.insert("parent", object->identifier()); + } + auto emitter = Akonadi2::Store::load(query); + emitter->onAdded([this, id, parent](const typename T::Ptr &value) { + auto childId = qHash(value->identifier()); + qDebug() << "Added entity " << childId; + const auto keys = mTree[id]; + int index = 0; + for (; index < keys.size(); index++) { + if (childId < keys.at(index)) { + break; + } + } + beginInsertRows(parent, index, index); + mEntities.insert(childId, value); + mTree[id].insert(index, childId); + mParents.insert(childId, id); + endInsertRows(); + }); + emitter->onModified([this, id, parent](const typename T::Ptr &value) { + auto childId = qHash(value->identifier()); + qDebug() << "Modified entity" << childId; + auto i = mTree[id].indexOf(childId); + mEntities.remove(childId); + mEntities.insert(childId, value); + //TODO check for change of parents + auto idx = index(i, 0, parent); + emit dataChanged(idx, idx); + }); + emitter->onRemoved([this, id, parent](const typename T::Ptr &value) { + auto childId = qHash(value->identifier()); + qDebug() << "Removed entity" << childId; + auto index = mTree[id].indexOf(qHash(value->identifier())); + beginRemoveRows(parent, index, index); + mEntities.remove(childId); + mTree[id].removeAll(childId); + mParents.remove(childId); + //TODO remove children + endRemoveRows(); + }); + emitter->onInitialResultSetComplete([this]() { + }); + emitter->onComplete([this, id]() { + mEmitter[id].clear(); + }); + emitter->onClear([this]() { + // beginResetModel(); + // mEntities.clear(); + // endResetModel(); + }); + mEmitter.insert(id, emitter); + // endResetModel(); + } + +private: + QMap >> mEmitter; + //TODO we should be able to directly use T as index, with an appropriate hash function, and thus have a QMap and QList + QMap mEntities; + QMap /* child entity id*/> mTree; + QMap mParents; + QMap mEntityChildrenFetched; + QList mPropertyColumns; + Akonadi2::Query mQuery; +}; + -- cgit v1.2.3