diff --git a/src/akonadi/CMakeLists.txt b/src/akonadi/CMakeLists.txt --- a/src/akonadi/CMakeLists.txt +++ b/src/akonadi/CMakeLists.txt @@ -1,6 +1,7 @@ set(akonadi_SRCS akonadiapplicationselectedattribute.cpp akonadiartifactqueries.cpp + akonadicacheinterface.cpp akonadicachingstorage.cpp akonadicollectionfetchjobinterface.cpp akonadicollectionsearchjobinterface.cpp diff --git a/src/akonadi/akonadicacheinterface.h b/src/akonadi/akonadicacheinterface.h new file mode 100644 --- /dev/null +++ b/src/akonadi/akonadicacheinterface.h @@ -0,0 +1,89 @@ +/* This file is part of Zanshin + + Copyright 2015 Mario Bensi + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 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 14 of version 3 of the license. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. +*/ + +#ifndef AKONADI_CACHEINTERFACE_H +#define AKONADI_CACHEINTERFACE_H + +#include + +#include +#include +#include + +namespace Akonadi { + +class CacheInterface: public QObject +{ + Q_OBJECT + +public: + CacheInterface(QObject *parent = Q_NULLPTR); + CacheInterface(const CacheInterface& other); + virtual ~CacheInterface(); + +public slots: + Akonadi::Collection::List collections() const; + Akonadi::Collection::List childCollections(Akonadi::Collection::Id parentId) const; + Akonadi::Collection collection(Akonadi::Collection::Id id) const; + virtual void createCollection(const Akonadi::Collection &collection); + virtual Akonadi::Collection modifyCollection(const Akonadi::Collection &collection); + virtual Akonadi::Collection removeCollection(const Akonadi::Collection &collection); + + Akonadi::Tag::List tags() const; + Akonadi::Tag tag(Akonadi::Tag::Id id) const; + virtual void createTag(const Akonadi::Tag &tag); + virtual Akonadi::Tag modifyTag(const Akonadi::Tag &tag); + virtual void removeTag(const Akonadi::Tag &tag); + + Akonadi::Item::List items() const; + Akonadi::Item::List childItems(Akonadi::Collection::Id parentId) const; + Akonadi::Item::List tagItems(Akonadi::Tag::Id tagId) const; + Akonadi::Item item(Akonadi::Item::Id id) const; + virtual void createItem(const Akonadi::Item &item); + virtual Akonadi::Item modifyItem(const Akonadi::Item &item); + virtual Akonadi::Item removeItem(const Akonadi::Item &item); + + Akonadi::Collection::Id maxCollectionId() const; + Akonadi::Item::Id maxItemId() const; + Akonadi::Tag::Id maxTagId() const; + + Akonadi::Collection reconstructAncestors(const Akonadi::Collection &collection, + const Akonadi::Collection &root = Akonadi::Collection::root()) const; + Akonadi::Item reconstructItemDependencies(const Akonadi::Item &item, + const Akonadi::Collection &root = Akonadi::Collection::root()) const; + +private: + QHash m_collections; + QHash> m_childCollections; + + QHash m_tags; + + QHash m_items; + QHash> m_childItems; + QHash> m_tagItems; + +}; + +} + +#endif // AKONADI_CACHEINTERFACE_H diff --git a/src/akonadi/akonadicacheinterface.cpp b/src/akonadi/akonadicacheinterface.cpp new file mode 100644 --- /dev/null +++ b/src/akonadi/akonadicacheinterface.cpp @@ -0,0 +1,368 @@ +/* This file is part of Zanshin + + Copyright 2015 Mario Bensi + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 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 14 of version 3 of the license. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. +*/ + +#include "akonadicacheinterface.h" + +#include +#include + +#include "akonadi/akonadiapplicationselectedattribute.h" +#include "akonadi/akonadimonitorimpl.h" + +#include + +using namespace Akonadi; + +template +static Akonadi::Collection::Id findParentId(const Entity &entity) +{ + const auto parent = entity.parentCollection(); + return parent.isValid() ? parent.id() + : Akonadi::Collection::root().id(); +} + +CacheInterface::CacheInterface(QObject *parent) + : QObject(parent) +{ +} + +CacheInterface::CacheInterface(const CacheInterface &other) + : QObject(other.parent()), + m_collections(other.m_collections), + m_childCollections(other.m_childCollections), + m_items(other.m_items), + m_childItems(other.m_childItems) +{ + +} + +CacheInterface::~CacheInterface() +{ +} + +Akonadi::Collection::List CacheInterface::collections() const +{ + return m_collections.values(); +} + +Akonadi::Collection::List CacheInterface::childCollections(Akonadi::Collection::Id parentId) const +{ + if (!m_childCollections.contains(parentId)) + return {}; + + const auto ids = m_childCollections.value(parentId); + auto result = Akonadi::Collection::List(); + std::transform(std::begin(ids), std::end(ids), + std::back_inserter(result), + [this] (Akonadi::Collection::Id id) { + Q_ASSERT(m_collections.contains(id)); + return m_collections.value(id); + }); + return result; +} + +Akonadi::Collection CacheInterface::collection(Akonadi::Collection::Id id) const +{ + if (!m_collections.contains(id)) + return Akonadi::Collection(); + + return m_collections.value(id); +} + +void CacheInterface::createCollection(const Akonadi::Collection &collection) +{ + Q_ASSERT(!m_collections.contains(collection.id())); + m_collections[collection.id()] = collection; + + const auto parentId = findParentId(collection); + m_childCollections[parentId] << collection.id(); +} + +Akonadi::Collection CacheInterface::modifyCollection(const Akonadi::Collection &collection) +{ + Q_ASSERT(m_collections.contains(collection.id())); + + const auto oldParentId = findParentId(m_collections[collection.id()]); + const auto oldCollection = m_collections.take(collection.id()); + auto newCollection = collection; + newCollection.setRemoteId(oldCollection.remoteId()); + if (!newCollection.parentCollection().isValid()) + newCollection.setParentCollection(oldCollection.parentCollection()); + if (newCollection.name().isEmpty()) + newCollection.setName(oldCollection.name()); + if (newCollection.contentMimeTypes().isEmpty()) + newCollection.setContentMimeTypes(oldCollection.contentMimeTypes()); + + m_collections[newCollection.id()] = newCollection; + const auto parentId = findParentId(newCollection); + + if (oldParentId != parentId) { + m_childCollections[oldParentId].removeAll(newCollection.id()); + m_childCollections[parentId] << newCollection.id(); + } + + return newCollection; +} + +Akonadi::Collection CacheInterface::removeCollection(const Akonadi::Collection &collection) +{ + Q_ASSERT(m_collections.contains(collection.id())); + + const auto childCollections = m_childCollections[collection.id()]; + foreach (const auto &childId, childCollections) { + removeCollection(Akonadi::Collection(childId)); + } + m_childCollections.remove(collection.id()); + + const auto childItems = m_childItems[collection.id()]; + foreach (const auto &childId, childItems) { + removeItem(Akonadi::Item(childId)); + } + m_childItems.remove(collection.id()); + + const auto parentId = findParentId(m_collections[collection.id()]); + const auto col = m_collections.take(collection.id()); + m_childCollections[parentId].removeAll(collection.id()); + + return col; +} + +Akonadi::Tag::List CacheInterface::tags() const +{ + return m_tags.values(); +} + +Akonadi::Tag CacheInterface::tag(Akonadi::Tag::Id id) const +{ + if (!m_tags.contains(id)) + return Akonadi::Tag(); + + return m_tags.value(id); +} + +void CacheInterface::createTag(const Akonadi::Tag &tag) +{ + Q_ASSERT(!m_tags.contains(tag.id())); + m_tags[tag.id()] = tag; +} + +Akonadi::Tag CacheInterface::modifyTag(const Akonadi::Tag &tag) +{ + Q_ASSERT(m_tags.contains(tag.id())); + const auto oldTag = m_tags.take(tag.id()); + auto newTag = tag; + newTag.setGid(oldTag.gid()); + newTag.setRemoteId(oldTag.remoteId()); + m_tags[tag.id()] = newTag; + return newTag; +} + +void CacheInterface::removeTag(const Akonadi::Tag &tag) +{ + Q_ASSERT(m_tags.contains(tag.id())); + + const auto ids = m_tagItems[tag.id()]; + foreach (const auto &id, ids) { + Q_ASSERT(m_items.contains(id)); + auto item = m_items.value(id); + item.clearTag(tag); + m_items[id] = item; + } + m_tagItems.remove(tag.id()); + + m_tags.remove(tag.id()); +} + +Akonadi::Item::List CacheInterface::items() const +{ + return m_items.values(); +} + +Akonadi::Item::List CacheInterface::childItems(Akonadi::Collection::Id parentId) const +{ + if (!m_childItems.contains(parentId)) + return {}; + + const auto ids = m_childItems.value(parentId); + auto result = Akonadi::Item::List(); + std::transform(std::begin(ids), std::end(ids), + std::back_inserter(result), + [this] (Akonadi::Item::Id id) { + Q_ASSERT(m_items.contains(id)); + return m_items.value(id); + }); + return result; +} + +Akonadi::Item::List CacheInterface::tagItems(Akonadi::Tag::Id tagId) const +{ + if (!m_tagItems.contains(tagId)) + return {}; + + const auto ids = m_tagItems.value(tagId); + auto result = Akonadi::Item::List(); + std::transform(std::begin(ids), std::end(ids), + std::back_inserter(result), + [this] (Akonadi::Item::Id id) { + Q_ASSERT(m_items.contains(id)); + return m_items.value(id); + }); + return result; +} + +Akonadi::Item CacheInterface::item(Akonadi::Item::Id id) const +{ + if (!m_items.contains(id)) + return {}; + + return m_items.value(id); +} + +void CacheInterface::createItem(const Akonadi::Item &item) +{ + Q_ASSERT(!m_items.contains(item.id())); + m_items[item.id()] = item; + + const auto parentId = findParentId(item); + m_childItems[parentId] << item.id(); + + foreach (const auto &tag, item.tags()) { + Q_ASSERT(m_tags.contains(tag.id())); + m_tagItems[tag.id()] << item.id(); + } +} + +Akonadi::Item CacheInterface::modifyItem(const Akonadi::Item &item) +{ + Q_ASSERT(m_items.contains(item.id())); + + const auto oldTags = m_items[item.id()].tags(); + const auto oldParentId = findParentId(m_items[item.id()]); + const auto oldItem = m_items.take(item.id()); + auto newItem = item; + newItem.setRemoteId(oldItem.remoteId()); + if (!newItem.parentCollection().isValid()) + newItem.setParentCollection(oldItem.parentCollection()); + + m_items[newItem.id()] = newItem; + const auto parentId = findParentId(newItem); + + if (oldParentId != parentId) { + m_childItems[oldParentId].removeAll(newItem.id()); + m_childItems[parentId] << newItem.id(); + } + + foreach (const auto &tag, oldTags) { + m_tagItems[tag.id()].removeAll(newItem.id()); + } + + foreach (const auto &tag, newItem.tags()) { + Q_ASSERT(m_tags.contains(tag.id())); + m_tagItems[tag.id()] << newItem.id(); + } + + return newItem; +} + +Akonadi::Item CacheInterface::removeItem(const Akonadi::Item &item) +{ + Q_ASSERT(m_items.contains(item.id())); + const auto parentId = findParentId(m_items[item.id()]); + const auto i = m_items.take(item.id()); + m_childItems[parentId].removeAll(item.id()); + + foreach (const Akonadi::Tag &tag, item.tags()) { + m_tagItems[tag.id()].removeAll(item.id()); + } + + return i; +} + +template +bool idLessThan(const T &left, const T &right) +{ + return left.id() < right.id(); +} + +Akonadi::Entity::Id CacheInterface::maxCollectionId() const +{ + if (m_collections.isEmpty()) + return 0; + + auto it = std::max_element(m_collections.constBegin(), m_collections.constEnd(), + idLessThan); + return it.key(); +} + +Akonadi::Entity::Id CacheInterface::maxItemId() const +{ + if (m_items.isEmpty()) + return 0; + + auto it = std::max_element(m_items.constBegin(), m_items.constEnd(), + idLessThan); + return it.key(); +} + +Akonadi::Tag::Id CacheInterface::maxTagId() const +{ + if (m_tags.isEmpty()) + return 0; + + auto it = std::max_element(m_tags.constBegin(), m_tags.constEnd(), + idLessThan); + return it.key(); +} + +Akonadi::Collection CacheInterface::reconstructAncestors(const Akonadi::Collection &collection, + const Akonadi::Collection &root) const +{ + if (!collection.isValid()) + return Akonadi::Collection::root(); + + if (collection == root) + return collection; + + auto parent = collection.parentCollection(); + auto reconstructedParent = reconstructAncestors(m_collections.value(parent.id()), root); + + auto result = collection; + result.setParentCollection(reconstructedParent); + return result; +} + +Akonadi::Item CacheInterface::reconstructItemDependencies(const Akonadi::Item &item, const Akonadi::Collection &root) const +{ + auto result = item; + result.setParentCollection(reconstructAncestors(item.parentCollection(), root)); + + auto tags = item.tags(); + std::transform(tags.constBegin(), tags.constEnd(), + tags.begin(), + [=] (const Akonadi::Tag &t) { + return tag(t.id()); + }); + result.setTags(tags); + + return result; +} diff --git a/tests/testlib/akonadifakedata.h b/tests/testlib/akonadifakedata.h --- a/tests/testlib/akonadifakedata.h +++ b/tests/testlib/akonadifakedata.h @@ -24,12 +24,7 @@ #ifndef TESTLIB_AKONADIFAKEDATA_H #define TESTLIB_AKONADIFAKEDATA_H -#include - -#include -#include -#include - +#include "akonadi/akonadicacheinterface.h" #include "testlib/akonadifakestoragebehavior.h" namespace Akonadi { @@ -41,59 +36,33 @@ class AkonadiFakeMonitor; -class AkonadiFakeData +class AkonadiFakeData : public Akonadi::CacheInterface { public: AkonadiFakeData(); AkonadiFakeData(const AkonadiFakeData &other); - ~AkonadiFakeData(); - - Akonadi::Collection::List collections() const; - Akonadi::Collection::List childCollections(Akonadi::Collection::Id parentId) const; - Akonadi::Collection collection(Akonadi::Collection::Id id) const; - void createCollection(const Akonadi::Collection &collection); - void modifyCollection(const Akonadi::Collection &collection); - void removeCollection(const Akonadi::Collection &collection); - - Akonadi::Tag::List tags() const; - Akonadi::Tag tag(Akonadi::Tag::Id id) const; - void createTag(const Akonadi::Tag &tag); - void modifyTag(const Akonadi::Tag &tag); - void removeTag(const Akonadi::Tag &tag); - - Akonadi::Item::List items() const; - Akonadi::Item::List childItems(Akonadi::Collection::Id parentId) const; - Akonadi::Item::List tagItems(Akonadi::Tag::Id tagId) const; - Akonadi::Item item(Akonadi::Item::Id id) const; - void createItem(const Akonadi::Item &item); - void modifyItem(const Akonadi::Item &item); - void removeItem(const Akonadi::Item &item); + virtual ~AkonadiFakeData(); - Akonadi::MonitorInterface *createMonitor(); - Akonadi::StorageInterface *createStorage(); +public slots: + void createCollection(const Akonadi::Collection &collection) Q_DECL_OVERRIDE; + Akonadi::Collection modifyCollection(const Akonadi::Collection &collection) Q_DECL_OVERRIDE; + Akonadi::Collection removeCollection(const Akonadi::Collection &collection) Q_DECL_OVERRIDE; + + void createTag(const Akonadi::Tag &tag) Q_DECL_OVERRIDE; + Akonadi::Tag modifyTag(const Akonadi::Tag &tag) Q_DECL_OVERRIDE; + void removeTag(const Akonadi::Tag &tag) Q_DECL_OVERRIDE; - Akonadi::Collection::Id maxCollectionId() const; - Akonadi::Item::Id maxItemId() const; - Akonadi::Tag::Id maxTagId() const; + void createItem(const Akonadi::Item &item) Q_DECL_OVERRIDE; + Akonadi::Item modifyItem(const Akonadi::Item &item) Q_DECL_OVERRIDE; + Akonadi::Item removeItem(const Akonadi::Item &item) Q_DECL_OVERRIDE; - Akonadi::Collection reconstructAncestors(const Akonadi::Collection &collection, - const Akonadi::Collection &root = Akonadi::Collection::root()) const; - Akonadi::Item reconstructItemDependencies(const Akonadi::Item &item, - const Akonadi::Collection &root = Akonadi::Collection::root()) const; + Akonadi::MonitorInterface *createMonitor(); + Akonadi::StorageInterface *createStorage(); const AkonadiFakeStorageBehavior &storageBehavior() const; AkonadiFakeStorageBehavior &storageBehavior(); private: - QHash m_collections; - QHash> m_childCollections; - - QHash m_tags; - - QHash m_items; - QHash> m_childItems; - QHash> m_tagItems; - QScopedPointer m_monitor; AkonadiFakeStorageBehavior m_storageBehavior; diff --git a/tests/testlib/akonadifakedata.cpp b/tests/testlib/akonadifakedata.cpp --- a/tests/testlib/akonadifakedata.cpp +++ b/tests/testlib/akonadifakedata.cpp @@ -30,8 +30,6 @@ #include "akonadi/akonadiapplicationselectedattribute.h" -#include - using namespace Testlib; template @@ -48,10 +46,7 @@ } AkonadiFakeData::AkonadiFakeData(const AkonadiFakeData &other) - : m_collections(other.m_collections), - m_childCollections(other.m_childCollections), - m_items(other.m_items), - m_childItems(other.m_childItems), + : CacheInterface(other), m_monitor(new AkonadiFakeMonitor) { @@ -61,67 +56,16 @@ { } -Akonadi::Collection::List AkonadiFakeData::collections() const -{ - return m_collections.values(); -} - -Akonadi::Collection::List AkonadiFakeData::childCollections(Akonadi::Collection::Id parentId) const -{ - if (!m_childCollections.contains(parentId)) - return {}; - - const auto ids = m_childCollections.value(parentId); - auto result = Akonadi::Collection::List(); - std::transform(std::begin(ids), std::end(ids), - std::back_inserter(result), - [this] (Akonadi::Collection::Id id) { - Q_ASSERT(m_collections.contains(id)); - return m_collections.value(id); - }); - return result; -} - -Akonadi::Collection AkonadiFakeData::collection(Akonadi::Collection::Id id) const -{ - if (!m_collections.contains(id)) - return Akonadi::Collection(); - - return m_collections.value(id); -} - void AkonadiFakeData::createCollection(const Akonadi::Collection &collection) { - Q_ASSERT(!m_collections.contains(collection.id())); - m_collections[collection.id()] = collection; - - const auto parentId = findParentId(collection); - m_childCollections[parentId] << collection.id(); + CacheInterface::createCollection(collection); m_monitor->addCollection(reconstructAncestors(collection)); } -void AkonadiFakeData::modifyCollection(const Akonadi::Collection &collection) +Akonadi::Collection AkonadiFakeData::modifyCollection(const Akonadi::Collection &collection) { - Q_ASSERT(m_collections.contains(collection.id())); - - const auto oldParentId = findParentId(m_collections[collection.id()]); - const auto oldCollection = m_collections.take(collection.id()); - auto newCollection = collection; - newCollection.setRemoteId(oldCollection.remoteId()); - if (!newCollection.parentCollection().isValid()) - newCollection.setParentCollection(oldCollection.parentCollection()); - if (newCollection.name().isEmpty()) - newCollection.setName(oldCollection.name()); - if (newCollection.contentMimeTypes().isEmpty()) - newCollection.setContentMimeTypes(oldCollection.contentMimeTypes()); - - m_collections[newCollection.id()] = newCollection; - const auto parentId = findParentId(newCollection); - - if (oldParentId != parentId) { - m_childCollections[oldParentId].removeAll(newCollection.id()); - m_childCollections[parentId] << newCollection.id(); - } + const auto oldCollection = this->collection(collection.id()); + auto newCollection = CacheInterface::modifyCollection(collection); auto notifiedCollection = reconstructAncestors(newCollection); m_monitor->changeCollection(notifiedCollection); @@ -138,186 +82,73 @@ m_monitor->changeCollectionSelection(notifiedCollection); } } + return newCollection; } -void AkonadiFakeData::removeCollection(const Akonadi::Collection &collection) +Akonadi::Collection AkonadiFakeData::removeCollection(const Akonadi::Collection &collection) { - Q_ASSERT(m_collections.contains(collection.id())); - - const auto childCollections = m_childCollections[collection.id()]; - foreach (const auto &childId, childCollections) { - removeCollection(Akonadi::Collection(childId)); - } - m_childCollections.remove(collection.id()); - - const auto childItems = m_childItems[collection.id()]; - foreach (const auto &childId, childItems) { - removeItem(Akonadi::Item(childId)); - } - m_childItems.remove(collection.id()); - - const auto parentId = findParentId(m_collections[collection.id()]); - const auto col = m_collections.take(collection.id()); - m_childCollections[parentId].removeAll(collection.id()); + auto col = CacheInterface::removeCollection(collection); m_monitor->removeCollection(col); -} - -Akonadi::Tag::List AkonadiFakeData::tags() const -{ - return m_tags.values(); -} - -Akonadi::Tag AkonadiFakeData::tag(Akonadi::Tag::Id id) const -{ - if (!m_tags.contains(id)) - return Akonadi::Tag(); - - return m_tags.value(id); + return col; } void AkonadiFakeData::createTag(const Akonadi::Tag &tag) { - Q_ASSERT(!m_tags.contains(tag.id())); - m_tags[tag.id()] = tag; + CacheInterface::createTag(tag); m_monitor->addTag(tag); } -void AkonadiFakeData::modifyTag(const Akonadi::Tag &tag) +Akonadi::Tag AkonadiFakeData::modifyTag(const Akonadi::Tag &tag) { - Q_ASSERT(m_tags.contains(tag.id())); - const auto oldTag = m_tags.take(tag.id()); - auto newTag = tag; - newTag.setGid(oldTag.gid()); - newTag.setRemoteId(oldTag.remoteId()); - m_tags[tag.id()] = newTag; + auto newTag = CacheInterface::modifyTag(tag); m_monitor->changeTag(newTag); + return newTag; } void AkonadiFakeData::removeTag(const Akonadi::Tag &tag) { - Q_ASSERT(m_tags.contains(tag.id())); + auto items = tagItems(tag.id()); - const auto ids = m_tagItems[tag.id()]; - foreach (const auto &id, ids) { - Q_ASSERT(m_items.contains(id)); - auto item = m_items.value(id); + CacheInterface::removeTag(tag); + + foreach(auto item, items) { item.clearTag(tag); - m_items[id] = item; m_monitor->changeItem(item); } - m_tagItems.remove(tag.id()); - m_tags.remove(tag.id()); m_monitor->removeTag(tag); } -Akonadi::Item::List AkonadiFakeData::items() const -{ - return m_items.values(); -} - -Akonadi::Item::List AkonadiFakeData::childItems(Akonadi::Collection::Id parentId) const -{ - if (!m_childItems.contains(parentId)) - return {}; - - const auto ids = m_childItems.value(parentId); - auto result = Akonadi::Item::List(); - std::transform(std::begin(ids), std::end(ids), - std::back_inserter(result), - [this] (Akonadi::Item::Id id) { - Q_ASSERT(m_items.contains(id)); - return m_items.value(id); - }); - return result; -} - -Akonadi::Item::List AkonadiFakeData::tagItems(Akonadi::Tag::Id tagId) const -{ - if (!m_tagItems.contains(tagId)) - return {}; - - const auto ids = m_tagItems.value(tagId); - auto result = Akonadi::Item::List(); - std::transform(std::begin(ids), std::end(ids), - std::back_inserter(result), - [this] (Akonadi::Item::Id id) { - Q_ASSERT(m_items.contains(id)); - return m_items.value(id); - }); - return result; -} - -Akonadi::Item AkonadiFakeData::item(Akonadi::Item::Id id) const -{ - if (!m_items.contains(id)) - return {}; - - return m_items.value(id); -} - void AkonadiFakeData::createItem(const Akonadi::Item &item) { - Q_ASSERT(!m_items.contains(item.id())); - m_items[item.id()] = item; - - const auto parentId = findParentId(item); - m_childItems[parentId] << item.id(); - - foreach (const auto &tag, item.tags()) { - Q_ASSERT(m_tags.contains(tag.id())); - m_tagItems[tag.id()] << item.id(); - } + CacheInterface::createItem(item); m_monitor->addItem(reconstructItemDependencies(item)); } -void AkonadiFakeData::modifyItem(const Akonadi::Item &item) +Akonadi::Item AkonadiFakeData::modifyItem(const Akonadi::Item &item) { - Q_ASSERT(m_items.contains(item.id())); + const auto i = this->item(item.id()); + const auto oldParentId = findParentId(i); - const auto oldTags = m_items[item.id()].tags(); - const auto oldParentId = findParentId(m_items[item.id()]); - const auto oldItem = m_items.take(item.id()); - auto newItem = item; - newItem.setRemoteId(oldItem.remoteId()); - if (!newItem.parentCollection().isValid()) - newItem.setParentCollection(oldItem.parentCollection()); + auto newItem = CacheInterface::modifyItem(item); - m_items[newItem.id()] = newItem; const auto parentId = findParentId(newItem); - if (oldParentId != parentId) { - m_childItems[oldParentId].removeAll(newItem.id()); - m_childItems[parentId] << newItem.id(); m_monitor->moveItem(reconstructItemDependencies(newItem)); } - foreach (const auto &tag, oldTags) { - m_tagItems[tag.id()].removeAll(newItem.id()); - } - - foreach (const auto &tag, newItem.tags()) { - Q_ASSERT(m_tags.contains(tag.id())); - m_tagItems[tag.id()] << newItem.id(); - } - m_monitor->changeItem(reconstructItemDependencies(newItem)); + return newItem; } -void AkonadiFakeData::removeItem(const Akonadi::Item &item) +Akonadi::Item AkonadiFakeData::removeItem(const Akonadi::Item &item) { - Q_ASSERT(m_items.contains(item.id())); - const auto parentId = findParentId(m_items[item.id()]); - const auto i = m_items.take(item.id()); - m_childItems[parentId].removeAll(item.id()); - - foreach (const Akonadi::Tag &tag, item.tags()) { - m_tagItems[tag.id()].removeAll(item.id()); - } + auto i = CacheInterface::removeItem(item); m_monitor->removeItem(reconstructItemDependencies(i)); + return i; } Akonadi::MonitorInterface *AkonadiFakeData::createMonitor() @@ -353,75 +184,6 @@ return new AkonadiFakeStorage(this); } -template -bool idLessThan(const T &left, const T &right) -{ - return left.id() < right.id(); -} - -Akonadi::Entity::Id AkonadiFakeData::maxCollectionId() const -{ - if (m_collections.isEmpty()) - return 0; - - auto it = std::max_element(m_collections.constBegin(), m_collections.constEnd(), - idLessThan); - return it.key(); -} - -Akonadi::Entity::Id AkonadiFakeData::maxItemId() const -{ - if (m_items.isEmpty()) - return 0; - - auto it = std::max_element(m_items.constBegin(), m_items.constEnd(), - idLessThan); - return it.key(); -} - -Akonadi::Tag::Id AkonadiFakeData::maxTagId() const -{ - if (m_tags.isEmpty()) - return 0; - - auto it = std::max_element(m_tags.constBegin(), m_tags.constEnd(), - idLessThan); - return it.key(); -} - -Akonadi::Collection AkonadiFakeData::reconstructAncestors(const Akonadi::Collection &collection, - const Akonadi::Collection &root) const -{ - if (!collection.isValid()) - return Akonadi::Collection::root(); - - if (collection == root) - return collection; - - auto parent = collection.parentCollection(); - auto reconstructedParent = reconstructAncestors(m_collections.value(parent.id()), root); - - auto result = collection; - result.setParentCollection(reconstructedParent); - return result; -} - -Akonadi::Item AkonadiFakeData::reconstructItemDependencies(const Akonadi::Item &item, const Akonadi::Collection &root) const -{ - auto result = item; - result.setParentCollection(reconstructAncestors(item.parentCollection(), root)); - - auto tags = item.tags(); - std::transform(tags.constBegin(), tags.constEnd(), - tags.begin(), - [=] (const Akonadi::Tag &t) { - return tag(t.id()); - }); - result.setTags(tags); - - return result; -} - const AkonadiFakeStorageBehavior &AkonadiFakeData::storageBehavior() const { return m_storageBehavior;