From 94a2cd6ec21bf0466a9a50d6e4a0a956ed47bc82 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 19 Nov 2015 23:23:56 +0100 Subject: Move implementations to the cpp file. I finally figured out how to do that with cpp files. It requires instantiating the code with all expected classes, but that's not a big problem since we know all types. This will hopefully greatly reduce the compiletimes... --- common/modelresult.cpp | 203 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 common/modelresult.cpp (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp new file mode 100644 index 0000000..1abcc62 --- /dev/null +++ b/common/modelresult.cpp @@ -0,0 +1,203 @@ +/* + * 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 . + */ +#include "modelresult.h" + +#include + +#include "domain/folder.h" +#include "log.h" + +template +ModelResult::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(); +} + +template +qint64 ModelResult::parentId(const Ptr &value) +{ + return qHash(value->getProperty("parent").toByteArray()); +} + +template +int ModelResult::rowCount(const QModelIndex &parent) const +{ + return mTree[getIdentifier(parent)].size(); +} + +template +int ModelResult::columnCount(const QModelIndex &parent) const +{ + return mPropertyColumns.size(); +} + +template +QVariant ModelResult::data(const QModelIndex &index, int role) const +{ + if (role == DomainObjectRole) { + Q_ASSERT(mEntities.contains(index.internalId())); + return QVariant::fromValue(mEntities.value(index.internalId())); + } + if (role == Qt::DisplayRole) { + if (index.column() < mPropertyColumns.size()) { + Q_ASSERT(mEntities.contains(index.internalId())); + auto entity = mEntities.value(index.internalId()); + return entity->getProperty(mPropertyColumns.at(index.column())).toString(); + } else { + return "No data available"; + } + } + return QVariant(); +} + +template +QModelIndex ModelResult::index(int row, int column, const QModelIndex &parent) const +{ + auto id = getIdentifier(parent); + auto childId = mTree.value(id).at(row); + return createIndex(row, column, childId); +} + +template +QModelIndex ModelResult::createIndexFromId(const qint64 &id) const +{ + auto grandParentId = mParents.value(id, 0); + auto row = mTree.value(grandParentId).indexOf(id); + return createIndex(row, 0, id); +} + +template +QModelIndex ModelResult::parent(const QModelIndex &index) const +{ + auto id = getIdentifier(index); + auto parentId = mParents.value(id); + return createIndexFromId(parentId); +} + +template +bool ModelResult::canFetchMore(const QModelIndex &parent) const +{ + qDebug() << "Can fetch more: " << parent << mEntityChildrenFetched.value(parent.internalId()); + return mEntityChildrenFetched.value(parent.internalId()); +} + +template +void ModelResult::fetchMore(const QModelIndex &parent) +{ + qDebug() << "Fetch more: " << parent; + fetchEntities(parent); +} + +template +void ModelResult::add(const Ptr &value) +{ + auto childId = qHash(value->identifier()); + auto id = parentId(value); + //Ignore updates we get before the initial fetch is done + if (!mEntityChildrenFetched[id]) { + return; + } + auto parent = createIndexFromId(id); + qDebug() << "Added entity " << childId << value->identifier() << id; + const auto keys = mTree[id]; + int index = 0; + for (; index < keys.size(); index++) { + if (childId < keys.at(index)) { + break; + } + } + if (mEntities.contains(childId)) { + qWarning() << "Entity already in model " << value->identifier(); + return; + } + qDebug() << "Inserting rows " << index << parent; + beginInsertRows(QModelIndex(), index, index); + mEntities.insert(childId, value); + mTree[id].insert(index, childId); + mParents.insert(childId, id); + endInsertRows(); + qDebug() << "Inserted rows " << mTree[id].size(); +} + + +template +void ModelResult::remove(const Ptr &value) +{ + auto childId = qHash(value->identifier()); + auto id = parentId(value); + auto parent = createIndexFromId(id); + 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(); +} + +template +void ModelResult::fetchEntities(const QModelIndex &parent) +{ + const auto id = getIdentifier(parent); + mEntityChildrenFetched[id] = true; + Trace() << "Loading child entities"; + loadEntities(parent.data(DomainObjectRole).template value()); +} + +template +void ModelResult::setFetcher(const std::function &fetcher) +{ + Trace() << "Setting fetcher"; + loadEntities = fetcher; +} + +template +void ModelResult::modify(const Ptr &value) +{ + auto childId = qHash(value->identifier()); + auto id = parentId(value); + //Ignore updates we get before the initial fetch is done + if (!mEntityChildrenFetched[id]) { + return; + } + auto parent = createIndexFromId(id); + 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); +} + +template class ModelResult; +template class ModelResult; +template class ModelResult; +template class ModelResult; -- cgit v1.2.3 From ec92f856854a35bd888b883802a1ef618cc9f69c Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sat, 21 Nov 2015 02:29:57 +0100 Subject: Don't try to fetch more once the parent is fetched. We're not doing partial fetches yet --- common/modelresult.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp index 1abcc62..5b9e24f 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -104,7 +104,7 @@ template bool ModelResult::canFetchMore(const QModelIndex &parent) const { qDebug() << "Can fetch more: " << parent << mEntityChildrenFetched.value(parent.internalId()); - return mEntityChildrenFetched.value(parent.internalId()); + return !mEntityChildrenFetched.value(parent.internalId(), false); } template @@ -133,7 +133,7 @@ void ModelResult::add(const Ptr &value) } } if (mEntities.contains(childId)) { - qWarning() << "Entity already in model " << value->identifier(); + Warning() << "Entity already in model " << value->identifier(); return; } qDebug() << "Inserting rows " << index << parent; -- cgit v1.2.3 From 00e6b843e9f2881faccb312594a0e91c42df0096 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 25 Nov 2015 09:22:03 +0100 Subject: Less noise --- common/modelresult.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp index 5b9e24f..4102cda 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -124,7 +124,7 @@ void ModelResult::add(const Ptr &value) return; } auto parent = createIndexFromId(id); - qDebug() << "Added entity " << childId << value->identifier() << id; + // qDebug() << "Added entity " << childId << value->identifier() << id; const auto keys = mTree[id]; int index = 0; for (; index < keys.size(); index++) { @@ -136,13 +136,13 @@ void ModelResult::add(const Ptr &value) Warning() << "Entity already in model " << value->identifier(); return; } - qDebug() << "Inserting rows " << index << parent; + // qDebug() << "Inserting rows " << index << parent; beginInsertRows(QModelIndex(), index, index); mEntities.insert(childId, value); mTree[id].insert(index, childId); mParents.insert(childId, id); endInsertRows(); - qDebug() << "Inserted rows " << mTree[id].size(); + // qDebug() << "Inserted rows " << mTree[id].size(); } -- cgit v1.2.3 From a4acb7e251cba5ba6d66bf6235736202255c4eac Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 25 Nov 2015 09:37:59 +0100 Subject: Only use the parent index when it's available --- common/modelresult.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp index 4102cda..935e2e8 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -27,7 +27,8 @@ template ModelResult::ModelResult(const Akonadi2::Query &query, const QList &propertyColumns) :QAbstractItemModel(), - mPropertyColumns(propertyColumns) + mPropertyColumns(propertyColumns), + mQuery(query) { } @@ -42,7 +43,10 @@ static qint64 getIdentifier(const QModelIndex &idx) template qint64 ModelResult::parentId(const Ptr &value) { - return qHash(value->getProperty("parent").toByteArray()); + if (!mQuery.parentProperty.isEmpty()) { + return qHash(value->getProperty(mQuery.parentProperty).toByteArray()); + } + return qHash(QByteArray()); } template -- cgit v1.2.3 From 5b41b26a349967acf2197f9f9228526193fd826e Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 27 Nov 2015 17:30:04 +0100 Subject: Introduced a QueryRunner object The QueryRunner object lives for the duration of the query (so just for the initial query for non-live queries, and for the lifetime of the result model for live queries). It's supposed to handle all the threading internally and decouple the lifetime of the facade. --- common/modelresult.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp index 935e2e8..65eaba9 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -182,6 +182,28 @@ void ModelResult::setFetcher(const std::function +void ModelResult::setEmitter(const typename Akonadi2::ResultEmitter::Ptr &emitter) +{ + setFetcher(emitter->mFetcher); + emitter->onAdded([this](const Ptr &value) { + this->add(value); + }); + emitter->onModified([this](const Ptr &value) { + this->modify(value); + }); + emitter->onRemoved([this](const Ptr &value) { + this->remove(value); + }); + emitter->onInitialResultSetComplete([this]() { + }); + emitter->onComplete([this]() { + }); + emitter->onClear([this]() { + }); + mEmitter = emitter; +} + template void ModelResult::modify(const Ptr &value) { -- cgit v1.2.3 From 4926e7f613ea3e03a2865eec66c6a8c1ec0b6516 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sat, 28 Nov 2015 16:07:15 +0100 Subject: Cleanup --- common/modelresult.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp index 65eaba9..930048f 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -141,7 +141,7 @@ void ModelResult::add(const Ptr &value) return; } // qDebug() << "Inserting rows " << index << parent; - beginInsertRows(QModelIndex(), index, index); + beginInsertRows(parent, index, index); mEntities.insert(childId, value); mTree[id].insert(index, childId); mParents.insert(childId, id); -- cgit v1.2.3 From 67d573d98da247d2cd16ce65fdd37457c5ee74ec Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 30 Nov 2015 10:30:31 +0100 Subject: ModelResult hasChildren, cleanup --- common/modelresult.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp index 930048f..582f8ff 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -44,26 +44,32 @@ template qint64 ModelResult::parentId(const Ptr &value) { if (!mQuery.parentProperty.isEmpty()) { - return qHash(value->getProperty(mQuery.parentProperty).toByteArray()); + const auto property = value->getProperty(mQuery.parentProperty).toByteArray(); + if (!property.isEmpty()) { + return qHash(property); + } } - return qHash(QByteArray()); + return 0; } template int ModelResult::rowCount(const QModelIndex &parent) const { + qDebug() << "row count " << mTree[getIdentifier(parent)].size(); return mTree[getIdentifier(parent)].size(); } template int ModelResult::columnCount(const QModelIndex &parent) const { + qDebug() << "porperty count " << mPropertyColumns.size(); return mPropertyColumns.size(); } template QVariant ModelResult::data(const QModelIndex &index, int role) const { + qDebug() << index; if (role == DomainObjectRole) { Q_ASSERT(mEntities.contains(index.internalId())); return QVariant::fromValue(mEntities.value(index.internalId())); @@ -83,8 +89,8 @@ QVariant ModelResult::data(const QModelIndex &index, int role) const template QModelIndex ModelResult::index(int row, int column, const QModelIndex &parent) const { - auto id = getIdentifier(parent); - auto childId = mTree.value(id).at(row); + const auto id = getIdentifier(parent); + const auto childId = mTree.value(id).at(row); return createIndex(row, column, childId); } @@ -104,6 +110,15 @@ QModelIndex ModelResult::parent(const QModelIndex &index) const return createIndexFromId(parentId); } +template +bool ModelResult::hasChildren(const QModelIndex &parent) const +{ + if (mQuery.parentProperty.isEmpty() && parent.isValid()) { + return false; + } + return QAbstractItemModel::hasChildren(parent); +} + template bool ModelResult::canFetchMore(const QModelIndex &parent) const { @@ -121,8 +136,8 @@ void ModelResult::fetchMore(const QModelIndex &parent) template void ModelResult::add(const Ptr &value) { - auto childId = qHash(value->identifier()); - auto id = parentId(value); + const auto childId = qHash(value->identifier()); + const auto id = parentId(value); //Ignore updates we get before the initial fetch is done if (!mEntityChildrenFetched[id]) { return; -- cgit v1.2.3 From b5648af02ea7246b41d24e242c5f94e43e43980e Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 30 Nov 2015 11:09:31 +0100 Subject: Provide status information about children fetch state The fetch state is per parent. --- common/modelresult.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp index 582f8ff..4def20f 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -74,6 +74,9 @@ QVariant ModelResult::data(const QModelIndex &index, int role) const Q_ASSERT(mEntities.contains(index.internalId())); return QVariant::fromValue(mEntities.value(index.internalId())); } + if (role == ChildrenFetchedRole) { + return childrenFetched(index); + } if (role == Qt::DisplayRole) { if (index.column() < mPropertyColumns.size()) { Q_ASSERT(mEntities.contains(index.internalId())); @@ -122,8 +125,8 @@ bool ModelResult::hasChildren(const QModelIndex &parent) const template bool ModelResult::canFetchMore(const QModelIndex &parent) const { - qDebug() << "Can fetch more: " << parent << mEntityChildrenFetched.value(parent.internalId()); - return !mEntityChildrenFetched.value(parent.internalId(), false); + qDebug() << "Can fetch more: " << parent << mEntityChildrenFetched.contains(parent.internalId()); + return !mEntityChildrenFetched.contains(parent.internalId()); } template @@ -139,7 +142,8 @@ void ModelResult::add(const Ptr &value) const auto childId = qHash(value->identifier()); const auto id = parentId(value); //Ignore updates we get before the initial fetch is done - if (!mEntityChildrenFetched[id]) { + if (!mEntityChildrenFetched.contains(id)) { + qDebug() << "Children not yet fetched"; return; } auto parent = createIndexFromId(id); @@ -185,7 +189,7 @@ template void ModelResult::fetchEntities(const QModelIndex &parent) { const auto id = getIdentifier(parent); - mEntityChildrenFetched[id] = true; + mEntityChildrenFetched.insert(id); Trace() << "Loading child entities"; loadEntities(parent.data(DomainObjectRole).template value()); } @@ -210,22 +214,28 @@ void ModelResult::setEmitter(const typename Akonadi2::ResultEmitter emitter->onRemoved([this](const Ptr &value) { this->remove(value); }); - emitter->onInitialResultSetComplete([this]() { - }); - emitter->onComplete([this]() { - }); - emitter->onClear([this]() { + emitter->onInitialResultSetComplete([this](const Ptr &parent) { + qint64 parentId = parent ? qHash(parent->identifier()) : 0; + const auto parentIndex = createIndexFromId(parentId); + mEntityChildrenFetchComplete.insert(parentId); + emit dataChanged(parentIndex, parentIndex, QVector() << ChildrenFetchedRole); }); mEmitter = emitter; } +template +bool ModelResult::childrenFetched(const QModelIndex &index) const +{ + return mEntityChildrenFetchComplete.contains(getIdentifier(index)); +} + template void ModelResult::modify(const Ptr &value) { auto childId = qHash(value->identifier()); auto id = parentId(value); //Ignore updates we get before the initial fetch is done - if (!mEntityChildrenFetched[id]) { + if (!mEntityChildrenFetched.contains(id)) { return; } auto parent = createIndexFromId(id); -- cgit v1.2.3 From bf28c2e3f43038165dc83c10267d103e779b245e Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 30 Nov 2015 13:45:51 +0100 Subject: ModelResult: return an invalid QModelIndex for the toplevel parent --- common/modelresult.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp index 4def20f..e2a05f8 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -100,6 +100,9 @@ QModelIndex ModelResult::index(int row, int column, const QModelIndex &p template QModelIndex ModelResult::createIndexFromId(const qint64 &id) const { + if (id == 0) { + return QModelIndex(); + } auto grandParentId = mParents.value(id, 0); auto row = mTree.value(grandParentId).indexOf(id); return createIndex(row, 0, id); -- cgit v1.2.3 From 0b8850f85f420fcb08643463afe01b026e58dde5 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 30 Nov 2015 15:58:23 +0100 Subject: Less debug output --- common/modelresult.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'common/modelresult.cpp') diff --git a/common/modelresult.cpp b/common/modelresult.cpp index e2a05f8..c7fcd49 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -55,21 +55,18 @@ qint64 ModelResult::parentId(const Ptr &value) template int ModelResult::rowCount(const QModelIndex &parent) const { - qDebug() << "row count " << mTree[getIdentifier(parent)].size(); return mTree[getIdentifier(parent)].size(); } template int ModelResult::columnCount(const QModelIndex &parent) const { - qDebug() << "porperty count " << mPropertyColumns.size(); return mPropertyColumns.size(); } template QVariant ModelResult::data(const QModelIndex &index, int role) const { - qDebug() << index; if (role == DomainObjectRole) { Q_ASSERT(mEntities.contains(index.internalId())); return QVariant::fromValue(mEntities.value(index.internalId())); @@ -128,14 +125,12 @@ bool ModelResult::hasChildren(const QModelIndex &parent) const template bool ModelResult::canFetchMore(const QModelIndex &parent) const { - qDebug() << "Can fetch more: " << parent << mEntityChildrenFetched.contains(parent.internalId()); return !mEntityChildrenFetched.contains(parent.internalId()); } template void ModelResult::fetchMore(const QModelIndex &parent) { - qDebug() << "Fetch more: " << parent; fetchEntities(parent); } @@ -146,7 +141,6 @@ void ModelResult::add(const Ptr &value) const auto id = parentId(value); //Ignore updates we get before the initial fetch is done if (!mEntityChildrenFetched.contains(id)) { - qDebug() << "Children not yet fetched"; return; } auto parent = createIndexFromId(id); @@ -178,7 +172,7 @@ void ModelResult::remove(const Ptr &value) auto childId = qHash(value->identifier()); auto id = parentId(value); auto parent = createIndexFromId(id); - qDebug() << "Removed entity" << childId; + // qDebug() << "Removed entity" << childId; auto index = mTree[id].indexOf(qHash(value->identifier())); beginRemoveRows(parent, index, index); mEntities.remove(childId); @@ -218,7 +212,7 @@ void ModelResult::setEmitter(const typename Akonadi2::ResultEmitter this->remove(value); }); emitter->onInitialResultSetComplete([this](const Ptr &parent) { - qint64 parentId = parent ? qHash(parent->identifier()) : 0; + const qint64 parentId = parent ? qHash(parent->identifier()) : 0; const auto parentIndex = createIndexFromId(parentId); mEntityChildrenFetchComplete.insert(parentId); emit dataChanged(parentIndex, parentIndex, QVector() << ChildrenFetchedRole); @@ -242,7 +236,7 @@ void ModelResult::modify(const Ptr &value) return; } auto parent = createIndexFromId(id); - qDebug() << "Modified entity" << childId; + // qDebug() << "Modified entity" << childId; auto i = mTree[id].indexOf(childId); mEntities.remove(childId); mEntities.insert(childId, value); -- cgit v1.2.3