summaryrefslogtreecommitdiffstats
path: root/common/modelresult.h
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2015-11-10 12:05:39 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2015-11-10 12:05:39 +0100
commit10d19014fe2c9c02f2bc3e19732cbe340e316076 (patch)
tree94d8bfee0c97e4496a439bf33b0eb91471468597 /common/modelresult.h
parentfa1f58e8a83c6dc524ee0540f450065014e1a825 (diff)
downloadsink-10d19014fe2c9c02f2bc3e19732cbe340e316076.tar.gz
sink-10d19014fe2c9c02f2bc3e19732cbe340e316076.zip
A result model
The result model drives the data retrieval and provides the interace for consumers
Diffstat (limited to 'common/modelresult.h')
-rw-r--r--common/modelresult.h180
1 files changed, 180 insertions, 0 deletions
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 @@
1/*
2 * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) version 3, or any
8 * later version accepted by the membership of KDE e.V. (or its
9 * successor approved by the membership of KDE e.V.), which shall
10 * act as a proxy defined in Section 6 of version 3 of the license.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#pragma once
22
23#include <QAbstractItemModel>
24#include <QModelIndex>
25#include <QDebug>
26#include "query.h"
27#include "clientapi.h"
28
29#include "resultprovider.h"
30
31template<class T>
32class ModelResult : public QAbstractItemModel
33{
34public:
35
36 enum Roles {
37 DomainObjectRole = Qt::UserRole + 1
38 };
39
40 ModelResult(const Akonadi2::Query &query, const QList<QByteArray> &propertyColumns)
41 :QAbstractItemModel(),
42 mPropertyColumns(propertyColumns)
43 {
44 }
45
46 static qint64 getIdentifier(const QModelIndex &idx)
47 {
48 if (!idx.isValid()) {
49 return 0;
50 }
51 return idx.internalId();
52 }
53
54 int rowCount(const QModelIndex &parent = QModelIndex()) const
55 {
56 return mTree[getIdentifier(parent)].size();
57 }
58
59 int columnCount(const QModelIndex &parent = QModelIndex()) const
60 {
61 return mPropertyColumns.size();
62 }
63
64 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
65 {
66 if (role == DomainObjectRole) {
67 qWarning() << "trying to get entity " << index.internalId();
68 Q_ASSERT(mEntities.contains(index.internalId()));
69 return QVariant::fromValue(mEntities.value(index.internalId()));
70 }
71 qDebug() << "Invalid role";
72 return QVariant();
73 }
74
75 QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const
76 {
77 auto id = getIdentifier(parent);
78 auto childId = mTree.value(id).at(row);
79 return createIndex(row, column, childId);
80 }
81
82 QModelIndex parent(const QModelIndex &index) const
83 {
84 auto id = getIdentifier(index);
85 auto parentId = mParents.value(id);
86 auto grandParentId = mParents.value(parentId, 0);
87 auto row = mTree.value(grandParentId).indexOf(parentId);
88 return createIndex(row, 0, parentId);
89 }
90
91 bool canFetchMore(const QModelIndex &parent) const
92 {
93 return mEntityChildrenFetched.value(parent.internalId());
94 }
95
96 void fetchMore(const QModelIndex &parent)
97 {
98 fetchEntities(parent);
99 }
100
101 void fetchEntities(const QModelIndex &parent)
102 {
103 qDebug() << "Fetching entities";
104 const auto id = getIdentifier(parent);
105 // beginResetModel();
106 // mEntities.remove(id);
107 mEntityChildrenFetched[id] = true;
108 auto query = mQuery;
109 if (!parent.isValid()) {
110 qDebug() << "no parent";
111 query.propertyFilter.insert("parent", QByteArray());
112 } else {
113 qDebug() << "parent is valid";
114 auto object = parent.data(DomainObjectRole).template value<typename T::Ptr>();
115 Q_ASSERT(object);
116 query.propertyFilter.insert("parent", object->identifier());
117 }
118 auto emitter = Akonadi2::Store::load<T>(query);
119 emitter->onAdded([this, id, parent](const typename T::Ptr &value) {
120 auto childId = qHash(value->identifier());
121 qDebug() << "Added entity " << childId;
122 const auto keys = mTree[id];
123 int index = 0;
124 for (; index < keys.size(); index++) {
125 if (childId < keys.at(index)) {
126 break;
127 }
128 }
129 beginInsertRows(parent, index, index);
130 mEntities.insert(childId, value);
131 mTree[id].insert(index, childId);
132 mParents.insert(childId, id);
133 endInsertRows();
134 });
135 emitter->onModified([this, id, parent](const typename T::Ptr &value) {
136 auto childId = qHash(value->identifier());
137 qDebug() << "Modified entity" << childId;
138 auto i = mTree[id].indexOf(childId);
139 mEntities.remove(childId);
140 mEntities.insert(childId, value);
141 //TODO check for change of parents
142 auto idx = index(i, 0, parent);
143 emit dataChanged(idx, idx);
144 });
145 emitter->onRemoved([this, id, parent](const typename T::Ptr &value) {
146 auto childId = qHash(value->identifier());
147 qDebug() << "Removed entity" << childId;
148 auto index = mTree[id].indexOf(qHash(value->identifier()));
149 beginRemoveRows(parent, index, index);
150 mEntities.remove(childId);
151 mTree[id].removeAll(childId);
152 mParents.remove(childId);
153 //TODO remove children
154 endRemoveRows();
155 });
156 emitter->onInitialResultSetComplete([this]() {
157 });
158 emitter->onComplete([this, id]() {
159 mEmitter[id].clear();
160 });
161 emitter->onClear([this]() {
162 // beginResetModel();
163 // mEntities.clear();
164 // endResetModel();
165 });
166 mEmitter.insert(id, emitter);
167 // endResetModel();
168 }
169
170private:
171 QMap<qint64 /* parent entity id */, QSharedPointer<Akonadi2::ResultEmitter<typename T::Ptr> >> mEmitter;
172 //TODO we should be able to directly use T as index, with an appropriate hash function, and thus have a QMap<T, T> and QList<T>
173 QMap<qint64 /* entity id */, typename T::Ptr> mEntities;
174 QMap<qint64 /* parent entity id */, QList<qint64> /* child entity id*/> mTree;
175 QMap<qint64 /* child entity id */, qint64 /* parent entity id*/> mParents;
176 QMap<qint64 /* entity id */, bool> mEntityChildrenFetched;
177 QList<QByteArray> mPropertyColumns;
178 Akonadi2::Query mQuery;
179};
180