From 1aa82ab9cfacca1ee9af9f9137caeede55f89230 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 13 Dec 2015 19:21:52 +0100 Subject: Load entities from multiple resources --- common/clientapi.cpp | 14 +++++++------ common/modelresult.cpp | 27 +++++++++++++++--------- common/resultprovider.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 79 insertions(+), 17 deletions(-) (limited to 'common') diff --git a/common/clientapi.cpp b/common/clientapi.cpp index 644d60c..46f7534 100644 --- a/common/clientapi.cpp +++ b/common/clientapi.cpp @@ -98,22 +98,24 @@ QSharedPointer Store::loadModel(Query query) resultProvider->initialResultSetComplete(typename DomainType::Ptr()); return model; } + auto aggregatingEmitter = AggregatingResultEmitter::Ptr::create(); + model->setEmitter(aggregatingEmitter); KAsync::iterate(resources) - .template each([query, model](const QByteArray &resource, KAsync::Future &future) { + .template each([query, aggregatingEmitter](const QByteArray &resource, KAsync::Future &future) { auto facade = FacadeFactory::instance().getFacade(resourceName(resource), resource); if (facade) { - Trace() << "Trying to fetch from resource"; + Trace() << "Trying to fetch from resource " << resource; auto result = facade->load(query); - auto emitter = result.second; - //TODO use aggregating emitter instead - model->setEmitter(emitter); - model->fetchMore(QModelIndex()); + aggregatingEmitter->addEmitter(result.second); result.first.template then([&future](){future.setFinished();}).exec(); } else { + Trace() << "Couldn' find a facade for " << resource; //Ignore the error and carry on future.setFinished(); } }).exec(); + //TODO if the aggregatingEmitter is still empty we're done + model->fetchMore(QModelIndex()); return model; } diff --git a/common/modelresult.cpp b/common/modelresult.cpp index d18dba1..690a17e 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -24,6 +24,13 @@ #include "domain/folder.h" #include "log.h" +static uint qHash(const Akonadi2::ApplicationDomain::ApplicationDomainType &type) +{ + Q_ASSERT(!type.resourceInstanceIdentifier().isEmpty()); + Q_ASSERT(!type.identifier().isEmpty()); + return qHash(type.resourceInstanceIdentifier() + type.identifier()); +} + template ModelResult::ModelResult(const Akonadi2::Query &query, const QList &propertyColumns) :QAbstractItemModel(), @@ -44,9 +51,9 @@ template qint64 ModelResult::parentId(const Ptr &value) { if (!mQuery.parentProperty.isEmpty()) { - const auto property = value->getProperty(mQuery.parentProperty).toByteArray(); - if (!property.isEmpty()) { - return qHash(property); + const auto identifier = value->getProperty(mQuery.parentProperty).toByteArray(); + if (!identifier.isEmpty()) { + return qHash(T(value->resourceInstanceIdentifier(), identifier, 0, QSharedPointer())); } } return 0; @@ -152,7 +159,7 @@ void ModelResult::fetchMore(const QModelIndex &parent) template void ModelResult::add(const Ptr &value) { - const auto childId = qHash(value->identifier()); + const auto childId = qHash(*value); const auto id = parentId(value); //Ignore updates we get before the initial fetch is done if (!mEntityChildrenFetched.contains(id)) { @@ -184,11 +191,11 @@ void ModelResult::add(const Ptr &value) template void ModelResult::remove(const Ptr &value) { - auto childId = qHash(value->identifier()); + auto childId = qHash(*value); auto id = parentId(value); auto parent = createIndexFromId(id); // qDebug() << "Removed entity" << childId; - auto index = mTree[id].indexOf(qHash(value->identifier())); + auto index = mTree[id].indexOf(childId); beginRemoveRows(parent, index, index); mEntities.remove(childId); mTree[id].removeAll(childId); @@ -202,7 +209,7 @@ void ModelResult::fetchEntities(const QModelIndex &parent) { const auto id = getIdentifier(parent); mEntityChildrenFetched.insert(id); - Trace() << "Loading child entities"; + Trace() << "Loading child entities of parent " << id; if (loadEntities) { loadEntities(parent.data(DomainObjectRole).template value()); } else { @@ -220,7 +227,7 @@ void ModelResult::setFetcher(const std::function void ModelResult::setEmitter(const typename Akonadi2::ResultEmitter::Ptr &emitter) { - setFetcher(emitter->mFetcher); + setFetcher([this](const Ptr &parent) {mEmitter->fetch(parent);}); emitter->onAdded([this](const Ptr &value) { this->add(value); }); @@ -231,7 +238,7 @@ void ModelResult::setEmitter(const typename Akonadi2::ResultEmitter this->remove(value); }); emitter->onInitialResultSetComplete([this](const Ptr &parent) { - const qint64 parentId = parent ? qHash(parent->identifier()) : 0; + const qint64 parentId = parent ? qHash(*parent) : 0; const auto parentIndex = createIndexFromId(parentId); mEntityChildrenFetchComplete.insert(parentId); emit dataChanged(parentIndex, parentIndex, QVector() << ChildrenFetchedRole); @@ -248,7 +255,7 @@ bool ModelResult::childrenFetched(const QModelIndex &index) const template void ModelResult::modify(const Ptr &value) { - auto childId = qHash(value->identifier()); + auto childId = qHash(*value); auto id = parentId(value); //Ignore updates we get before the initial fetch is done if (!mEntityChildrenFetched.contains(id)) { diff --git a/common/resultprovider.h b/common/resultprovider.h index d50f3f6..d94ad44 100644 --- a/common/resultprovider.h +++ b/common/resultprovider.h @@ -235,6 +235,11 @@ class ResultEmitter { public: typedef QSharedPointer > Ptr; + virtual ~ResultEmitter() + { + + } + void onAdded(const std::function &handler) { addHandler = handler; @@ -306,7 +311,12 @@ public: mFetcher = fetcher; } - std::function mFetcher; + virtual void fetch(const DomainType &parent) + { + if (mFetcher) { + mFetcher(parent); + } + } private: friend class ResultProvider; @@ -317,8 +327,51 @@ private: std::function initialResultSetCompleteHandler; std::function completeHandler; std::function clearHandler; + + std::function mFetcher; ThreadBoundary mThreadBoundary; }; +template +class AggregatingResultEmitter : public ResultEmitter { +public: + typedef QSharedPointer > Ptr; + + void addEmitter(const typename ResultEmitter::Ptr &emitter) + { + emitter->onAdded([this](const DomainType &value) { + this->add(value); + }); + emitter->onModified([this](const DomainType &value) { + this->modify(value); + }); + emitter->onRemoved([this](const DomainType &value) { + this->remove(value); + }); + emitter->onInitialResultSetComplete([this](const DomainType &value) { + this->initialResultSetComplete(value); + }); + emitter->onComplete([this]() { + this->complete(); + }); + emitter->onClear([this]() { + this->clear(); + }); + mEmitter << emitter; + } + + void fetch(const DomainType &parent) Q_DECL_OVERRIDE + { + for (const auto &emitter : mEmitter) { + emitter->fetch(parent); + } + } + +private: + QList::Ptr> mEmitter; +}; + + + } -- cgit v1.2.3