[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdepimlibs] akonadi: Remove Akonadi::Entity and Akonadi::AttributeEntity
From:       Dan_Vrátil <dvratil () redhat ! com>
Date:       2015-09-22 19:41:53
Message-ID: E1ZeTRp-0000yq-8N () scm ! kde ! org
[Download RAW message or body]

Git commit eef83bc45c95aa3df11a3a3ff92e319b1bd04fe6 by Dan Vrátil.
Committed on 22/09/2015 at 19:41.
Pushed by dvratil into branch 'master'.

Remove Akonadi::Entity and Akonadi::AttributeEntity

Collection and Item now have each their own implementation of attribute handling
(which we can factor out into some shared code later), and by not having to deal
with the polymorphism of Entity, we can get rid of vtable in ItemPrivate and
CollectionPrivate and better re-order member variables. This saves us 16 bytes
per Item and 32 (!) bytes per Collection. Tag now requires 8 bytes more
of memory due to TagPrivate being QSharedData (but we save something on Tag now).

We could also remove the copy-d_ptr-via-temporary-assignment from from Item,
because the usecase only really affects Collections. This should make copying
Items a bit faster (the assignEntityPrivate() workaround was showing up in
callgrind quite high).

M  +1    -1    akonadi/autotests/collectionsynctest.cpp
M  +4    -4    akonadi/autotests/entitycachetest.cpp
M  +1    -1    akonadi/autotests/fakeakonadiservercommand.h
M  +6    -6    akonadi/autotests/fakeserverdata.cpp
M  +7    -7    akonadi/autotests/fakeserverdata.h
M  +1    -0    akonadi/autotests/protocolhelpertest.cpp
M  +4    -4    akonadi/autotests/tagtest.cpp
M  +0    -4    akonadi/src/core/CMakeLists.txt
D  +0    -124  akonadi/src/core/attributeentity.cpp
D  +0    -172  akonadi/src/core/attributeentity.h
M  +164  -17   akonadi/src/core/collection.cpp
M  +239  -4    akonadi/src/core/collection.h
M  +51   -31   akonadi/src/core/collection_p.h
D  +0    -198  akonadi/src/core/entity.cpp
D  +0    -297  akonadi/src/core/entity.h
M  +1    -71   akonadi/src/core/entity_p.h
M  +30   -31   akonadi/src/core/entitycache_p.h
M  +1    -1    akonadi/src/core/entityhiddenattribute.h
M  +142  -7    akonadi/src/core/item.cpp
M  +237  -7    akonadi/src/core/item.h
M  +45   -19   akonadi/src/core/item_p.h
M  +1    -1    akonadi/src/core/jobs/collectionfetchjob.cpp
M  +1    -1    akonadi/src/core/jobs/collectionmodifyjob.h
M  +0    -1    akonadi/src/core/jobs/itemmodifyjob.cpp
M  +1    -1    akonadi/src/core/jobs/itemmodifyjob_p.h
M  +3    -2    akonadi/src/core/jobs/tagmodifyjob.cpp
M  +1    -1    akonadi/src/core/jobs/trashjob.cpp
M  +6    -6    akonadi/src/core/models/entityorderproxymodel.cpp
M  +3    -3    akonadi/src/core/models/entitytreemodel.cpp
M  +21   -21   akonadi/src/core/models/entitytreemodel_p.cpp
M  +13   -10   akonadi/src/core/models/entitytreemodel_p.h
M  +2    -0    akonadi/src/core/models/tagmodel.h
M  +1    -0    akonadi/src/core/models/tagmodel_p.h
M  +2    -15   akonadi/src/core/models/trashfilterproxymodel.cpp
M  +4    -4    akonadi/src/core/monitor_p.cpp
M  +2    -2    akonadi/src/core/notificationsource_p.cpp
M  +4    -3    akonadi/src/core/notificationsource_p.h
M  +3    -1    akonadi/src/core/pastehelper.cpp
M  +72   -38   akonadi/src/core/protocolhelper.cpp
M  +25   -9    akonadi/src/core/protocolhelper_p.h
M  +87   -67   akonadi/src/core/tag.cpp
M  +147  -16   akonadi/src/core/tag.h
A  +69   -0    akonadi/src/core/tag_p.h     [License: LGPL (v2+)]
M  +3    -2    akonadi/src/core/tagsync.cpp
M  +1    -1    akonadi/src/core/trashsettings.cpp
M  +6    -6    akonadi/src/widgets/etmviewstatesaver.cpp
M  +13   -2    akonadi/src/xml/xmlreader.cpp
M  +8    -2    akonadi/src/xml/xmlreader.h
M  +16   -4    akonadi/src/xml/xmlwriter.cpp
M  +7    -3    akonadi/src/xml/xmlwriter.h

http://commits.kde.org/kdepimlibs/eef83bc45c95aa3df11a3a3ff92e319b1bd04fe6

diff --git a/akonadi/autotests/collectionsynctest.cpp \
b/akonadi/autotests/collectionsynctest.cpp index 1b9f591..1e498de 100644
--- a/akonadi/autotests/collectionsynctest.cpp
+++ b/akonadi/autotests/collectionsynctest.cpp
@@ -369,7 +369,7 @@ private Q_SLOTS:
         QFETCH(bool, keepLocalChanges);
         const QString resource(QStringLiteral("akonadi_knut_resource_0"));
         Collection col = fetchCollections(resource).first();
-        col.attribute<EntityDisplayAttribute>(Akonadi::Entity::AddIfMissing)->setDisplayName(QStringLiteral("foo"));
 +        col.attribute<EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing)->setDisplayName(QStringLiteral("foo"));
                
         col.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType() << \
QStringLiteral("foo"));  {
             CollectionModifyJob *job = new CollectionModifyJob(col);
diff --git a/akonadi/autotests/entitycachetest.cpp \
b/akonadi/autotests/entitycachetest.cpp index b4ebf00..55a77c4 100644
--- a/akonadi/autotests/entitycachetest.cpp
+++ b/akonadi/autotests/entitycachetest.cpp
@@ -156,13 +156,13 @@ private Q_SLOTS:
         QSignalSpy spy(&cache, SIGNAL(dataAvailable()));
         QVERIFY(spy.isValid());
 
-        cache.request(QList<Entity::Id>() << 1 << 2 << 3, scope);
+        cache.request(QList<Item::Id>() << 1 << 2 << 3, scope);
         QTRY_COMPARE(spy.count(), 1);
-        QVERIFY(cache.isCached(QList<Entity::Id>() << 1 << 2 << 3));
+        QVERIFY(cache.isCached(QList<Item::Id>() << 1 << 2 << 3));
 
-        cache.ensureCached(QList<Entity::Id>() << 1 << 2 << 3 << 4, scope);
+        cache.ensureCached(QList<Item::Id>() << 1 << 2 << 3 << 4, scope);
         QTRY_COMPARE(spy.count(), 2);
-        QVERIFY(cache.isCached(QList<Entity::Id>() << 1 << 2 << 3 << 4));
+        QVERIFY(cache.isCached(QList<Item::Id>() << 1 << 2 << 3 << 4));
     }
 };
 
diff --git a/akonadi/autotests/fakeakonadiservercommand.h \
b/akonadi/autotests/fakeakonadiservercommand.h index aa74a34..320d8c1 100644
--- a/akonadi/autotests/fakeakonadiservercommand.h
+++ b/akonadi/autotests/fakeakonadiservercommand.h
@@ -97,7 +97,7 @@ protected:
     Akonadi::Tag m_parentTag;
     QHash<Akonadi::Collection::Id, Akonadi::Collection> m_collections;
     QHash<Akonadi::Item::Id, Akonadi::Item> m_items;
-    QHash<Akonadi::Item::Id, QList<Akonadi::Entity::Id> > m_childElements;
+    QHash<Akonadi::Collection::Id, QList<Akonadi::Collection::Id> > m_childElements;
     QHash<Akonadi::Tag::Id, Akonadi::Tag> m_tags;
 
 private:
diff --git a/akonadi/autotests/fakeserverdata.cpp \
b/akonadi/autotests/fakeserverdata.cpp index 486b172..b6f407e 100644
--- a/akonadi/autotests/fakeserverdata.cpp
+++ b/akonadi/autotests/fakeserverdata.cpp
@@ -37,7 +37,7 @@ FakeServerData::FakeServerData(EntityTreeModel *model, FakeSession \
*session, Fak  // the slot gets called
     connect(session, &FakeSession::jobAdded,
             [this](Akonadi::Job * job) {
-                Entity::Id fetchColId = \
job->property("FetchCollectionId").toULongLong(); +                Collection::Id \
fetchColId = job->property("FetchCollectionId").toULongLong();  QTimer::singleShot(0, \
[this, fetchColId]() {  jobAdded(fetchColId);
                 });
@@ -65,7 +65,7 @@ FakeServerData::FakeServerData(TagModel *model, FakeSession \
*session, FakeMonito  void FakeServerData::setCommands(QList< \
FakeAkonadiServerCommand * > list)  {
     m_communicationQueue.clear();
-    foreach (FakeAkonadiServerCommand *command, list) {
+    Q_FOREACH (FakeAkonadiServerCommand *command, list) {
         m_communicationQueue << command;
     }
 }
@@ -97,7 +97,7 @@ void FakeServerData::jobAdded()
     processNotifications();
 }
 
-void FakeServerData::returnEntities(Entity::Id fetchColId)
+void FakeServerData::returnEntities(Collection::Id fetchColId)
 {
     if (!returnCollections(fetchColId)) {
         while (!m_communicationQueue.isEmpty() && \
m_communicationQueue.head()->respondTo() == \
FakeAkonadiServerCommand::RespondToItemFetch) { @@ -108,7 +108,7 @@ void \
FakeServerData::returnEntities(Entity::Id fetchColId)  processNotifications();
 }
 
-bool FakeServerData::returnCollections(Entity::Id fetchColId)
+bool FakeServerData::returnCollections(Collection::Id fetchColId)
 {
     if (m_communicationQueue.isEmpty()) {
         return true;
@@ -129,7 +129,7 @@ bool FakeServerData::returnCollections(Entity::Id fetchColId)
     return false;
 }
 
-void FakeServerData::returnItems(Entity::Id fetchColId)
+void FakeServerData::returnItems(Item::Id fetchColId)
 {
     FakeAkonadiServerCommand::Type commType = \
m_communicationQueue.head()->respondTo();  
@@ -150,4 +150,4 @@ void FakeServerData::returnTags()
         FakeAkonadiServerCommand *command = m_communicationQueue.dequeue();
         command->doCommand();
     }
-}
\ No newline at end of file
+}
diff --git a/akonadi/autotests/fakeserverdata.h b/akonadi/autotests/fakeserverdata.h
index f2b0c59..103bec6 100644
--- a/akonadi/autotests/fakeserverdata.h
+++ b/akonadi/autotests/fakeserverdata.h
@@ -41,11 +41,11 @@ public:
 
     void setCommands(QList<FakeAkonadiServerCommand *> list);
 
-    Entity::Id nextCollectionId() const
+    Collection::Id nextCollectionId() const
     {
         return m_nextCollectionId++;
     }
-    Entity::Id nextItemId() const
+    Item::Id nextItemId() const
     {
         return m_nextItemId++;
     }
@@ -66,9 +66,9 @@ private Q_SLOTS:
     void jobAdded();
 
 private:
-    bool returnCollections(Entity::Id fetchColId);
-    void returnItems(Entity::Id fetchColId);
-    void returnEntities(Entity::Id fetchColId);
+    bool returnCollections(Collection::Id fetchColId);
+    void returnItems(Item::Id fetchColId);
+    void returnEntities(Collection::Id fetchColId);
     void returnTags();
 
 private:
@@ -79,8 +79,8 @@ private:
     QList<FakeAkonadiServerCommand *> m_commandList;
     QQueue<FakeAkonadiServerCommand *> m_communicationQueue;
 
-    mutable Entity::Id m_nextCollectionId;
-    mutable Entity::Id m_nextItemId;
+    mutable Collection::Id m_nextCollectionId;
+    mutable Item::Id m_nextItemId;
     mutable Tag::Id m_nextTagId;
 };
 
diff --git a/akonadi/autotests/protocolhelpertest.cpp \
b/akonadi/autotests/protocolhelpertest.cpp index 8bc5760..11da9b9 100644
--- a/akonadi/autotests/protocolhelpertest.cpp
+++ b/akonadi/autotests/protocolhelpertest.cpp
@@ -159,6 +159,7 @@ private Q_SLOTS:
             const Collection p2(collection.parentCollection());
             parsedCollection = p1;
             collection = p2;
+            qDebug() << p1.isValid() << p2.isValid();
         }
     }
 
diff --git a/akonadi/autotests/tagtest.cpp b/akonadi/autotests/tagtest.cpp
index 13648a1..4a6c335 100644
--- a/akonadi/autotests/tagtest.cpp
+++ b/akonadi/autotests/tagtest.cpp
@@ -349,7 +349,7 @@ void TagTest::testModify()
 
     //We can add an attribute
     {
-        Akonadi::TagAttribute *attr = \
tag.attribute<Akonadi::TagAttribute>(AttributeEntity::AddIfMissing); +        \
Akonadi::TagAttribute *attr = \
tag.attribute<Akonadi::TagAttribute>(Tag::AddIfMissing);  \
attr->setDisplayName(QStringLiteral("display name"));  tag.addAttribute(attr);
         tag.setParent(Tag(0));
@@ -365,7 +365,7 @@ void TagTest::testModify()
     }
     //We can update an attribute
     {
-        Akonadi::TagAttribute *attr = \
tag.attribute<Akonadi::TagAttribute>(AttributeEntity::AddIfMissing); +        \
Akonadi::TagAttribute *attr = \
tag.attribute<Akonadi::TagAttribute>(Tag::AddIfMissing);  \
attr->setDisplayName(QStringLiteral("display name2"));  TagModifyJob *modJob = new \
TagModifyJob(tag, this);  AKVERIFYEXEC(modJob);
@@ -451,7 +451,7 @@ void TagTest::testAttributes()
     Tag tag;
     {
         tag.setGid("gid2");
-        TagAttribute *attr = \
tag.attribute<TagAttribute>(AttributeEntity::AddIfMissing); +        TagAttribute \
*attr = tag.attribute<TagAttribute>(Tag::AddIfMissing);  \
attr->setDisplayName(QStringLiteral("name"));  attr->setInToolbar(true);
         tag.addAttribute(attr);
@@ -478,7 +478,7 @@ void TagTest::testAttributes()
     Tag tag2;
     {
         tag2.setGid("gid22");
-        TagAttribute *attr = \
tag.attribute<TagAttribute>(AttributeEntity::AddIfMissing); +        TagAttribute \
*attr = tag.attribute<TagAttribute>(Tag::AddIfMissing);  \
attr->setDisplayName(QStringLiteral("name2"));  attr->setInToolbar(true);
         tag2.addAttribute(attr);
diff --git a/akonadi/src/core/CMakeLists.txt b/akonadi/src/core/CMakeLists.txt
index 519cbc2..4eaa22d 100644
--- a/akonadi/src/core/CMakeLists.txt
+++ b/akonadi/src/core/CMakeLists.txt
@@ -5,7 +5,6 @@ set(akonadicore_base_SRCS
     agenttype.cpp
     asyncselectionhandler.cpp
     attribute.cpp
-    attributeentity.cpp
     attributefactory.cpp
     cachepolicy.cpp
     changemediator_p.cpp
@@ -24,7 +23,6 @@ set(akonadicore_base_SRCS
     conflicthandler.cpp
     collectionidentificationattribute.cpp
     control.cpp
-    entity.cpp
     entityannotationsattribute.cpp
     entitycache.cpp
     entitydeletedattribute.cpp
@@ -76,7 +74,6 @@ ecm_generate_headers(AkonadiCore_base_HEADERS
     AgentManager
     AgentType
     Attribute
-    AttributeEntity
     AttributeFactory
     CachePolicy
     ChangeRecorder
@@ -88,7 +85,6 @@ ecm_generate_headers(AkonadiCore_base_HEADERS
     CollectionIdentificationAttribute
     Control
     DifferencesAlgorithmInterface
-    Entity
     EntityAnnotationsAttribute
     EntityDeletedAttribute
     EntityDisplayAttribute
diff --git a/akonadi/src/core/attributeentity.cpp \
b/akonadi/src/core/attributeentity.cpp deleted file mode 100644
index c22b9d5..0000000
--- a/akonadi/src/core/attributeentity.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
-    Copyright (c) 2014 Christian Mollekopf <mollekopf@kolabsys.com>
-
-    This library is free software; you can redistribute it and/or modify it
-    under the terms of the GNU Library General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    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 Library General Public
-    License for more details.
-
-    You should have received a copy of the GNU Library General Public License
-    along with this library; see the file COPYING.LIB.  If not, write to the
-    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-    02110-1301, USA.
-*/
-#include "attributeentity.h"
-#include <QHash>
-#include <QSet>
-
-using namespace Akonadi;
-
-struct Akonadi::AttributeEntity::Private {
-    Private()
-    {
-    }
-
-    ~Private()
-    {
-        qDeleteAll(mAttributes);
-    }
-
-    Private(const Private &other)
-    {
-        Q_FOREACH (Attribute *attr, other.mAttributes) {
-            mAttributes.insert(attr->type(), attr->clone());
-        }
-        mDeletedAttributes = other.mDeletedAttributes;
-    }
-
-    QHash<QByteArray, Attribute *> mAttributes;
-    QSet<QByteArray> mDeletedAttributes;
-};
-
-AttributeEntity::AttributeEntity()
-    : d_ptr(new Private)
-{
-
-}
-
-AttributeEntity::AttributeEntity(const AttributeEntity &other)
-    : d_ptr(new Private)
-{
-    operator=(other);
-}
-
-AttributeEntity::~AttributeEntity()
-{
-
-}
-
-Akonadi::AttributeEntity &Akonadi::AttributeEntity::operator=(const \
                Akonadi::AttributeEntity &other)
-{
-    QHash<QByteArray, Attribute *>::const_iterator it = \
                other.d_ptr->mAttributes.constBegin();
-    for (; it != other.d_ptr->mAttributes.constEnd(); ++it) {
-        d_ptr->mAttributes.insert(it.key(), it.value()->clone());
-    }
-    d_ptr->mDeletedAttributes = other.d_ptr->mDeletedAttributes;
-    return *this;
-}
-
-void AttributeEntity::addAttribute(Attribute *attr)
-{
-    if (d_ptr->mAttributes.contains(attr->type())) {
-        Attribute *existing = d_ptr->mAttributes.value(attr->type());
-        if (attr == existing) {
-            return;
-        }
-        d_ptr->mAttributes.remove(attr->type());
-        delete existing;
-    }
-    d_ptr->mAttributes.insert(attr->type(), attr);
-    d_ptr->mDeletedAttributes.remove(attr->type());
-}
-
-void AttributeEntity::removeAttribute(const QByteArray &type)
-{
-    d_ptr->mDeletedAttributes.insert(type);
-    delete d_ptr->mAttributes.take(type);
-}
-
-bool AttributeEntity::hasAttribute(const QByteArray &type) const
-{
-    return d_ptr->mAttributes.contains(type);
-}
-
-Attribute::List AttributeEntity::attributes() const
-{
-    return d_ptr->mAttributes.values();
-}
-
-void Akonadi::AttributeEntity::clearAttributes()
-{
-    Q_FOREACH (Attribute *attr, d_ptr->mAttributes) {
-        d_ptr->mDeletedAttributes.insert(attr->type());
-        delete attr;
-    }
-    d_ptr->mAttributes.clear();
-}
-
-Attribute *AttributeEntity::attribute(const QByteArray &type) const
-{
-    if (d_ptr->mAttributes.contains(type)) {
-        return d_ptr->mAttributes.value(type);
-    }
-    return 0;
-}
-
-QSet<QByteArray> &AttributeEntity::removedAttributes() const
-{
-    return d_ptr->mDeletedAttributes;
-}
diff --git a/akonadi/src/core/attributeentity.h b/akonadi/src/core/attributeentity.h
deleted file mode 100644
index dbff9db..0000000
--- a/akonadi/src/core/attributeentity.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
-    Copyright (c) 2014 Christian Mollekopf <mollekopf@kolabsys.com>
-
-    This library is free software; you can redistribute it and/or modify it
-    under the terms of the GNU Library General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    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 Library General Public
-    License for more details.
-
-    You should have received a copy of the GNU Library General Public License
-    along with this library; see the file COPYING.LIB.  If not, write to the
-    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-    02110-1301, USA.
-*/
-
-#ifndef AKONADI_ATTRIBUTEENTITY_H
-#define AKONADI_ATTRIBUTEENTITY_H
-
-#include "akonadicore_export.h"
-
-#include "job.h"
-#include "attribute.h"
-
-#include <QSharedPointer>
-#include <QDebug>
-
-namespace Akonadi
-{
-
-/**
- * Parent class for entities that can have attributes.
- * This is supposed to eventually share the code between Akonadi::Tag and \
                Akonadi::Entity.
- *
- * In the current form using this in Akonadi::Entity would break the implicit \
                sharing of it's private class,
- * so AttributeEntity::Private would need to become a parent class of EntityPrivate \
                and use the same clone()
- * calls etc.
- * An even better solution is probably ot make AttributeEntity a private member of \
                Entity, with all Attribute related member functions forwarding to \
                this class.
- */
-class AKONADICORE_EXPORT AttributeEntity
-{
-public:
-    AttributeEntity();
-
-    AttributeEntity(const AttributeEntity &other);
-    virtual ~AttributeEntity();
-
-    //Each subclass must Q_DECL_OVERRIDE this to avoid slicing
-    virtual AttributeEntity &operator=(const AttributeEntity &other);
-
-    /**
-     * Adds an attribute to the entity.
-     *
-     * If an attribute of the same type name already exists, it is deleted and
-     * replaced with the new one.
-     *
-     * @param attribute The new attribute.
-     *
-     * @note The entity takes the ownership of the attribute.
-     */
-    void addAttribute(Attribute *attribute);
-
-    /**
-     * Removes and deletes the attribute of the given type @p name.
-     */
-    void removeAttribute(const QByteArray &name);
-
-    /**
-     * Returns @c true if the entity has an attribute of the given type @p name,
-     * false otherwise.
-     */
-    bool hasAttribute(const QByteArray &name) const;
-
-    /**
-     * Returns a list of all attributes of the entity.
-     */
-    Attribute::List attributes() const;
-
-    /**
-     * Removes and deletes all attributes of the entity.
-     */
-    void clearAttributes();
-
-    /**
-     * Returns the attribute of the given type @p name if available, 0 otherwise.
-     */
-    Attribute *attribute(const QByteArray &name) const;
-
-    /**
-     * Describes the options that can be passed to access attributes.
-     */
-    enum CreateOption {
-        AddIfMissing    ///< Creates the attribute if it is missing
-    };
-
-    /**
-     * Returns the attribute of the requested type.
-     * If the entity has no attribute of that type yet, a new one
-     * is created and added to the entity.
-     *
-     * @param option The create options.
-     */
-    template <typename T> inline T *attribute(CreateOption option)
-    {
-        Q_UNUSED(option);
-
-        const T dummy;
-        if (hasAttribute(dummy.type())) {
-            T *attr = dynamic_cast<T *>(attribute(dummy.type()));
-            if (attr) {
-                return attr;
-            }
-            //reuse 5250
-            qWarning() << "Found attribute of unknown type" << dummy.type()
-                       << ". Did you forget to call \
                AttributeFactory::registerAttribute()?";
-        }
-
-        T *attr = new T();
-        addAttribute(attr);
-        return attr;
-    }
-
-    /**
-     * Returns the attribute of the requested type or 0 if it is not available.
-     */
-    template <typename T> inline T *attribute() const
-    {
-        const T dummy;
-        if (hasAttribute(dummy.type())) {
-            T *attr = dynamic_cast<T *>(attribute(dummy.type()));
-            if (attr) {
-                return attr;
-            }
-            //Reuse 5250
-            qWarning() << "Found attribute of unknown type" << dummy.type()
-                       << ". Did you forget to call \
                AttributeFactory::registerAttribute()?";
-        }
-
-        return 0;
-    }
-
-    /**
-     * Removes and deletes the attribute of the requested type.
-     */
-    template <typename T> inline void removeAttribute()
-    {
-        const T dummy;
-        removeAttribute(dummy.type());
-    }
-
-    /**
-     * Returns whether the entity has an attribute of the requested type.
-     */
-    template <typename T> inline bool hasAttribute() const
-    {
-        const T dummy;
-        return hasAttribute(dummy.type());
-    }
-private:
-    friend class TagModifyJob;
-    QSet<QByteArray> &removedAttributes() const;
-
-    class Private;
-    QSharedPointer<Private> d_ptr;
-};
-
-}
-
-#endif
diff --git a/akonadi/src/core/collection.cpp b/akonadi/src/core/collection.cpp
index a093520..a78032a 100644
--- a/akonadi/src/core/collection.cpp
+++ b/akonadi/src/core/collection.cpp
@@ -19,12 +19,12 @@
 
 #include "collection.h"
 #include "collection_p.h"
+#include "entity_p.h"
 
 #include "attributefactory.h"
 #include "cachepolicy.h"
 #include "collectionrightsattribute_p.h"
 #include "collectionstatistics.h"
-#include "entity_p.h"
 #include "entitydisplayattribute.h"
 
 #include <QtCore/QDebug>
@@ -37,47 +37,199 @@
 
 using namespace Akonadi;
 
+uint Akonadi::qHash(const Akonadi::Collection &collection)
+{
+    return ::qHash(collection.id());
+}
+
+/**
+ * Helper method for assignment operator and copy constructor.
+ */
+static void assignCollectionPrivate(QSharedDataPointer<CollectionPrivate> &one,
+                                    const QSharedDataPointer<CollectionPrivate> \
&other) +{
+    // We can't simply do one = other here, we have to use a temp.
+    // Otherwise ProtocolHelperTest::testParentCollectionAfterCollectionParsing()
+    // will break.
+    //
+    // The reason are assignments like
+    //   col = col.parentCollection()
+    //
+    // Here, parentCollection() actually returns a reference to a pointer owned
+    // by col. So when col (or rather, it's private class) is deleted, the pointer
+    // to the parent collection and therefore the reference becomes invalid.
+    //
+    // With a single-line assignment here, the parent collection would be deleted
+    // before it is assigned, and therefore the resulting object would point to
+    // uninitalized memory.
+    QSharedDataPointer<CollectionPrivate> temp = other;
+    one = temp;
+}
+
 class CollectionRoot : public Collection
 {
 public:
     CollectionRoot()
         : Collection(0)
     {
-        QStringList types;
-        types << Collection::mimeType();
-        setContentMimeTypes(types);
+        setContentMimeTypes({ Collection::mimeType() });
 
         // The root collection is read-only for the users
-        Collection::Rights rights;
-        rights |= Collection::ReadOnly;
-        setRights(rights);
+        setRights(Collection::ReadOnly);
     }
 };
 
 Q_GLOBAL_STATIC(CollectionRoot, s_root)
 
 Collection::Collection()
-    : Entity(new CollectionPrivate)
+    : d_ptr(new CollectionPrivate)
 {
-    Q_D(Collection);
     static int lastId = -1;
-    d->mId = lastId--;
+    d_ptr->mId = lastId--;
 }
 
 Collection::Collection(Id id)
-    : Entity(new CollectionPrivate(id))
+    : d_ptr(new CollectionPrivate(id))
 {
 }
 
 Collection::Collection(const Collection &other)
-    : Entity(other)
 {
+    assignCollectionPrivate(d_ptr, other.d_ptr);
 }
 
 Collection::~Collection()
 {
 }
 
+void Collection::setId(Collection::Id identifier)
+{
+    d_ptr->mId = identifier;
+}
+
+Collection::Id Collection::id() const
+{
+    return d_func()->mId;
+}
+
+void Collection::setRemoteId(const QString &id)
+{
+    d_ptr->mRemoteId = id;
+}
+
+QString Collection::remoteId() const
+{
+    return d_ptr->mRemoteId;
+}
+
+void Collection::setRemoteRevision(const QString &revision)
+{
+    d_ptr->mRemoteRevision = revision;
+}
+
+QString Collection::remoteRevision() const
+{
+    return d_ptr->mRemoteRevision;
+}
+
+bool Collection::isValid() const
+{
+    return (d_ptr->mId >= 0);
+}
+
+bool Collection::operator==(const Collection &other) const
+{
+    // Invalid collections are the same, no matter what their internal ID is
+    return (!isValid() && !other.isValid()) || (d_ptr->mId == other.d_ptr->mId);
+}
+
+bool Akonadi::Collection::operator!=(const Collection &other) const
+{
+    return (isValid() || other.isValid()) && (d_ptr->mId != other.d_ptr->mId);
+}
+
+Collection &Collection ::operator=(const Collection &other)
+{
+    if (this != &other) {
+        assignCollectionPrivate(d_ptr, other.d_ptr);
+    }
+
+    return *this;
+}
+
+bool Akonadi::Collection::operator<(const Collection &other) const
+{
+    return d_ptr->mId < other.d_ptr->mId;
+}
+
+void Collection::addAttribute(Attribute *attr)
+{
+    Q_ASSERT(attr);
+    Attribute *existing = d_ptr->mAttributes.value(attr->type());
+    if (existing) {
+        if (attr == existing) {
+            return;
+        }
+        d_ptr->mAttributes.remove(attr->type());
+        delete existing;
+    }
+    d_ptr->mAttributes.insert(attr->type(), attr);
+    d_ptr->mDeletedAttributes.remove(attr->type());
+}
+
+void Collection::removeAttribute(const QByteArray &type)
+{
+    d_ptr->mDeletedAttributes.insert(type);
+    delete d_ptr->mAttributes.take(type);
+}
+
+bool Collection::hasAttribute(const QByteArray &type) const
+{
+    return d_ptr->mAttributes.contains(type);
+}
+
+Attribute::List Collection::attributes() const
+{
+    return d_ptr->mAttributes.values();
+}
+
+void Akonadi::Collection::clearAttributes()
+{
+    Q_FOREACH (Attribute *attr, d_ptr->mAttributes) {
+        d_ptr->mDeletedAttributes.insert(attr->type());
+        delete attr;
+    }
+    d_ptr->mAttributes.clear();
+}
+
+Attribute *Collection::attribute(const QByteArray &type) const
+{
+    return d_ptr->mAttributes.value(type);
+}
+
+Collection &Collection::parentCollection()
+{
+    if (!d_ptr->mParent) {
+        d_ptr->mParent = new Collection();
+    }
+    return *(d_ptr->mParent);
+}
+
+Collection Collection::parentCollection() const
+{
+    if (!d_ptr->mParent) {
+        return *(s_defaultParentCollection);
+    } else {
+        return *(d_ptr->mParent);
+    }
+}
+
+void Collection::setParentCollection(const Collection &parent)
+{
+    delete d_ptr->mParent;
+    d_ptr->mParent = new Collection(parent);
+}
+
 QString Collection::name() const
 {
     return d_func()->name;
@@ -186,11 +338,6 @@ void Collection::setResource(const QString &resource)
     d->resource = resource;
 }
 
-uint qHash(const Akonadi::Collection &collection)
-{
-    return qHash(collection.id());
-}
-
 QDebug operator <<(QDebug d, const Akonadi::Collection &collection)
 {
     return d << "Collection ID:" << collection.id()
diff --git a/akonadi/src/core/collection.h b/akonadi/src/core/collection.h
index 09de36e..4dfe733 100644
--- a/akonadi/src/core/collection.h
+++ b/akonadi/src/core/collection.h
@@ -21,10 +21,11 @@
 #define AKONADI_COLLECTION_H
 
 #include "akonadicore_export.h"
-#include "entity.h"
+#include "attribute.h"
 
 #include <QtCore/QMetaType>
 #include <QtCore/QSharedDataPointer>
+#include <QtCore/QDebug>
 
 class QUrl;
 
@@ -72,10 +73,15 @@ class CollectionStatistics;
  *
  * @author Volker Krause <vkrause@kde.org>
  */
-class AKONADICORE_EXPORT Collection : public Entity
+class AKONADICORE_EXPORT Collection
 {
 public:
     /**
+     * Describes the unique id type.
+     */
+    typedef qint64 Id;
+
+    /**
      * Describes a list of collections.
      */
     typedef QVector<Collection> List;
@@ -126,6 +132,176 @@ public:
     static Collection fromUrl(const QUrl &url);
 
     /**
+     * Sets the unique @p identifier of the collection.
+     */
+    void setId(Id identifier);
+
+    /**
+     * Returns the unique identifier of the collection.
+     */
+    Id id() const;
+
+    /**
+     * Sets the remote @p id of the collection.
+     */
+    void setRemoteId(const QString &id);
+
+    /**
+     * Returns the remote id of the collection.
+     */
+    QString remoteId() const;
+
+    /**
+     * Sets the remote @p revision of the collection.
+     * @param revision the collections's remote revision
+     * The remote revision can be used by resources to store some
+     * revision information of the backend to detect changes there.
+     *
+     * @note This method is supposed to be used by resources only.
+     * @since 4.5
+     */
+    void setRemoteRevision(const QString &revision);
+
+    /**
+     * Returns the remote revision of the collection.
+     *
+     * @note This method is supposed to be used by resources only.
+     * @since 4.5
+     */
+    QString remoteRevision() const;
+
+    /**
+     * Returns whether the collection is valid.
+     */
+    bool isValid() const;
+
+    /**
+     * Returns whether this collections's id equals the
+     * id of the @p other collection.
+     */
+    bool operator==(const Collection &other) const;
+
+    /**
+     * Returns whether the collection's id does not equal the id
+     * of the @p other collection.
+     */
+    bool operator!=(const Collection &other) const;
+
+    /**
+     * Assigns the @p other to this collection and returns a reference to this
+     * collection.
+     * @param other the collection to assign
+     */
+    Collection &operator=(const Collection &other);
+
+    /**
+     * @internal For use with containers only.
+     *
+     * @since 4.8
+     */
+    bool operator<(const Collection &other) const;
+
+    /**
+     * Returns the parent collection of this object.
+     * @note This will of course only return a useful value if it was explictly \
retrieved +     *       from the Akonadi server.
+     * @since 4.4
+     */
+    Collection parentCollection() const;
+
+    /**
+     * Returns a reference to the parent collection of this object.
+     * @note This will of course only return a useful value if it was explictly \
retrieved +     *       from the Akonadi server.
+     * @since 4.4
+     */
+    Collection &parentCollection();
+
+    /**
+     * Set the parent collection of this object.
+     * @note Calling this method has no immediate effect for the object itself,
+     *       such as being moved to another collection.
+     *       It is mainly relevant to provide a context for RID-based operations
+     *       inside resources.
+     * @param parent The parent collection.
+     * @since 4.4
+     */
+    void setParentCollection(const Collection &parent);
+
+    /**
+     * Adds an attribute to the collection.
+     *
+     * If an attribute of the same type name already exists, it is deleted and
+     * replaced with the new one.
+     *
+     * @param attribute The new attribute.
+     *
+     * @note The collection takes the ownership of the attribute.
+     */
+    void addAttribute(Attribute *attribute);
+
+    /**
+     * Removes and deletes the attribute of the given type @p name.
+     */
+    void removeAttribute(const QByteArray &name);
+
+    /**
+     * Returns @c true if the collection has an attribute of the given type @p name,
+     * false otherwise.
+     */
+    bool hasAttribute(const QByteArray &name) const;
+
+    /**
+     * Returns a list of all attributes of the collection.
+     */
+    Attribute::List attributes() const;
+
+    /**
+     * Removes and deletes all attributes of the collection.
+     */
+    void clearAttributes();
+
+    /**
+     * Returns the attribute of the given type @p name if available, 0 otherwise.
+     */
+    Attribute *attribute(const QByteArray &name) const;
+
+    /**
+     * Describes the options that can be passed to access attributes.
+     */
+    enum CreateOption {
+        AddIfMissing    ///< Creates the attribute if it is missing
+    };
+
+    /**
+     * Returns the attribute of the requested type.
+     * If the collection has no attribute of that type yet, a new one
+     * is created and added to the entity.
+     *
+     * @param option The create options.
+     */
+    template <typename T>
+    inline T *attribute(CreateOption option);
+
+    /**
+     * Returns the attribute of the requested type or 0 if it is not available.
+     */
+    template <typename T>
+    inline T *attribute() const;
+
+    /**
+     * Removes and deletes the attribute of the requested type.
+     */
+    template <typename T>
+    inline void removeAttribute();
+
+    /**
+     * Returns whether the collection has an attribute of the requested type.
+     */
+    template <typename T>
+    inline bool hasAttribute() const;
+
+    /**
      * Returns the i18n'ed name of the collection.
      */
     QString name() const;
@@ -368,16 +544,75 @@ public:
     QSet<QByteArray> keepLocalChanges() const;
 
 private:
-    AKONADI_DECLARE_PRIVATE(Collection)
     friend class CollectionCreateJob;
     friend class CollectionFetchJob;
     friend class CollectionModifyJob;
     friend class ProtocolHelper;
+
+    //@cond PRIVATE
+    QSharedDataPointer<CollectionPrivate> d_ptr;
+    CollectionPrivate *d_func();
+    const CollectionPrivate *d_func() const;
+    friend class CollectionPrivate;
+    //@endcond
 };
 
+AKONADICORE_EXPORT uint qHash(const Akonadi::Collection &collection);
+
+template <typename T>
+inline T *Akonadi::Collection::attribute(Collection::CreateOption option)
+{
+    Q_UNUSED(option);
+
+    const T dummy;
+    if (hasAttribute(dummy.type())) {
+        T *attr = dynamic_cast<T *>(attribute(dummy.type()));
+        if (attr) {
+            return attr;
+        }
+        //Reuse 5250
+        qWarning() << "Found attribute of unknown type" << dummy.type()
+                    << ". Did you forget to call \
AttributeFactory::registerAttribute()?"; +    }
+
+    T *attr = new T();
+    addAttribute(attr);
+    return attr;
 }
 
-AKONADICORE_EXPORT uint qHash(const Akonadi::Collection &collection);
+template <typename T>
+inline T *Akonadi::Collection::attribute() const
+{
+    const T dummy;
+    if (hasAttribute(dummy.type())) {
+        T *attr = dynamic_cast<T *>(attribute(dummy.type()));
+        if (attr) {
+            return attr;
+        }
+        //reuse 5250
+        qWarning() << "Found attribute of unknown type" << dummy.type()
+                    << ". Did you forget to call \
AttributeFactory::registerAttribute()?"; +    }
+
+    return 0;
+}
+
+template <typename T>
+inline void Akonadi::Collection::removeAttribute()
+{
+    const T dummy;
+    removeAttribute(dummy.type());
+}
+
+template <typename T>
+inline bool Akonadi::Collection::hasAttribute() const
+{
+    const T dummy;
+    return hasAttribute(dummy.type());
+}
+
+} // namespace Akonadi
+
 /**
  * Allows to output a collection for debugging purposes.
  */
diff --git a/akonadi/src/core/collection_p.h b/akonadi/src/core/collection_p.h
index 7e92762..716fb65 100644
--- a/akonadi/src/core/collection_p.h
+++ b/akonadi/src/core/collection_p.h
@@ -23,37 +23,51 @@
 #include "collection.h"
 #include "cachepolicy.h"
 #include "collectionstatistics.h"
-#include "entity_p.h"
 
 #include "qstringlist.h"
 
+#include <QSharedData>
+
 using namespace Akonadi;
 
 /**
  * @internal
  */
-class Akonadi::CollectionPrivate : public EntityPrivate
+class Akonadi::CollectionPrivate : public QSharedData
 {
 public:
     CollectionPrivate(Collection::Id id = -1)
-        : EntityPrivate(id)
-        , contentTypesChanged(false)
-        , cachePolicyChanged(false)
-        , isVirtual(false)
+        : QSharedData()
+        , displayPreference(Collection::ListDefault)
+        , syncPreference(Collection::ListDefault)
+        , indexPreference(Collection::ListDefault)
+        , listPreferenceChanged(false)
         , enabled(true)
         , enabledChanged(false)
-        , listPreferenceChanged(false)
         , referenced(false)
         , referencedChanged(false)
-        , displayPreference(Collection::ListDefault)
-        , syncPreference(Collection::ListDefault)
-        , indexPreference(Collection::ListDefault)
+        , contentTypesChanged(false)
+        , cachePolicyChanged(false)
+        , isVirtual(false)
+        , mId(id)
+        , mParent(Q_NULLPTR)
     {
     }
 
     CollectionPrivate(const CollectionPrivate &other)
-        : EntityPrivate(other)
+        : QSharedData(other)
+        , mParent(Q_NULLPTR)
     {
+        mId = other.mId;
+        mRemoteId = other.mRemoteId;
+        mRemoteRevision = other.mRemoteRevision;
+        Q_FOREACH (Attribute *attr, other.mAttributes) {
+            mAttributes.insert(attr->type(), attr->clone());
+        }
+        mDeletedAttributes = other.mDeletedAttributes;
+        if (other.mParent) {
+            mParent = new Collection(*(other.mParent));
+        }
         name = other.name;
         resource = other.resource;
         statistics = other.statistics;
@@ -75,49 +89,55 @@ public:
 
     ~CollectionPrivate()
     {
+        qDeleteAll(mAttributes);
+        delete mParent;
     }
 
-    CollectionPrivate *clone() const Q_DECL_OVERRIDE
+    void resetChangeLog()
     {
-        return new CollectionPrivate(*this);
-    }
-
-    void resetChangeLog() Q_DECL_OVERRIDE {
         contentTypesChanged = false;
         cachePolicyChanged = false;
         enabledChanged = false;
         listPreferenceChanged = false;
         referencedChanged = false;
-        EntityPrivate::resetChangeLog();
+        mDeletedAttributes.clear();
     }
 
     static Collection newRoot()
     {
         Collection rootCollection(0);
-        QStringList types;
-        types << Collection::mimeType();
-        rootCollection.setContentMimeTypes(types);
+        rootCollection.setContentMimeTypes({ Collection::mimeType() });
         return rootCollection;
     }
 
+    // Make use of the 4-bytes padding from QSharedData
+    Collection::ListPreference displayPreference: 2;
+    Collection::ListPreference syncPreference: 2;
+    Collection::ListPreference indexPreference: 2;
+    bool listPreferenceChanged: 1;
+    bool enabled: 1;
+    bool enabledChanged: 1;
+    bool referenced: 1;
+    bool referencedChanged: 1;
+    bool contentTypesChanged: 1;
+    bool cachePolicyChanged: 1;
+    bool isVirtual: 1;
+    // 2 bytes padding here
+
+    Collection::Id mId;
+    QString mRemoteId;
+    QString mRemoteRevision;
+    QHash<QByteArray, Attribute *> mAttributes;
+    QSet<QByteArray> mDeletedAttributes;
+    mutable Collection *mParent;
     QString name;
     QString resource;
     CollectionStatistics statistics;
     QStringList contentTypes;
     static const Collection root;
     CachePolicy cachePolicy;
-    bool contentTypesChanged: 1;
-    bool cachePolicyChanged: 1;
-    bool isVirtual: 1;
-    bool enabled: 1;
-    bool enabledChanged: 1;
-    bool listPreferenceChanged: 1;
-    bool referenced: 1;
-    bool referencedChanged: 1;
-    Collection::ListPreference displayPreference: 2;
-    Collection::ListPreference syncPreference: 2;
-    Collection::ListPreference indexPreference: 2;
     QSet<QByteArray> keepLocalChanges;
+
 };
 
 #endif
diff --git a/akonadi/src/core/entity.cpp b/akonadi/src/core/entity.cpp
deleted file mode 100644
index 078e4bc..0000000
--- a/akonadi/src/core/entity.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
-    Copyright (c) 2008 Tobias Koenig <tokoe@kde.org>
-
-    This library is free software; you can redistribute it and/or modify it
-    under the terms of the GNU Library General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    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 Library General Public
-    License for more details.
-
-    You should have received a copy of the GNU Library General Public License
-    along with this library; see the file COPYING.LIB.  If not, write to the
-    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-    02110-1301, USA.
-*/
-
-#include "entity.h"
-#include "entity_p.h"
-#include "collection.h"
-
-using namespace Akonadi;
-
-Q_GLOBAL_STATIC(Akonadi::Collection, s_defaultParentCollection)
-
-/**
- * Helper method for assignment operator and copy constructor.
- */
-static void assignEntityPrivate(QSharedDataPointer<EntityPrivate> &one, const \
                QSharedDataPointer<EntityPrivate> &other)
-{
-    // We can't simply do one = other here, we have to use a temp.
-    // Otherwise ProtocolHelperTest::testParentCollectionAfterCollectionParsing()
-    // will break.
-    //
-    // The reason are assignments like
-    //   col = col.parentCollection()
-    //
-    // Here, parentCollection() actually returns a reference to a pointer owned
-    // by col. So when col (or rather, it's private class) is deleted, the pointer
-    // to the parent collection and therefore the reference becomes invalid.
-    //
-    // With a single-line assignment here, the parent collection would be deleted
-    // before it is assigned, and therefore the resulting object would point to
-    // uninitalized memory.
-    QSharedDataPointer<EntityPrivate> temp = other;
-    one = temp;
-}
-
-Entity::Entity(const Entity &other)
-{
-    assignEntityPrivate(d_ptr, other.d_ptr);
-}
-
-Entity::Entity(EntityPrivate *dd)
-    : d_ptr(dd)
-{
-}
-
-Entity::~Entity()
-{
-}
-
-void Entity::setId(Id id)
-{
-    d_ptr->mId = id;
-}
-
-Entity::Id Entity::id() const
-{
-    return d_ptr->mId;
-}
-
-void Entity::setRemoteId(const QString &id)
-{
-    d_ptr->mRemoteId = id;
-}
-
-QString Entity::remoteId() const
-{
-    return d_ptr->mRemoteId;
-}
-
-void Entity::setRemoteRevision(const QString &revision)
-{
-    d_ptr->mRemoteRevision = revision;
-}
-
-QString Entity::remoteRevision() const
-{
-    return d_ptr->mRemoteRevision;
-}
-
-bool Entity::isValid() const
-{
-    return (d_ptr->mId >= 0);
-}
-
-bool Entity::operator==(const Entity &other) const
-{
-    // Invalid items are the same, no matter what their internal ID is
-    return (!isValid() && !other.isValid()) || (d_ptr->mId == other.d_ptr->mId);
-}
-
-bool Akonadi::Entity::operator!=(const Entity &other) const
-{
-    return (isValid() || other.isValid()) && (d_ptr->mId != other.d_ptr->mId);
-}
-
-Entity &Entity ::operator=(const Entity &other)
-{
-    if (this != &other) {
-        assignEntityPrivate(d_ptr, other.d_ptr);
-    }
-
-    return *this;
-}
-
-bool Akonadi::Entity::operator<(const Entity &other) const
-{
-    return d_ptr->mId < other.d_ptr->mId;
-}
-
-void Entity::addAttribute(Attribute *attr)
-{
-    Q_ASSERT(attr);
-    Attribute *existing = d_ptr->mAttributes.value(attr->type());
-    if (existing) {
-        if (attr == existing) {
-            return;
-        }
-        d_ptr->mAttributes.remove(attr->type());
-        delete existing;
-    }
-    d_ptr->mAttributes.insert(attr->type(), attr);
-    d_ptr->mDeletedAttributes.remove(attr->type());
-}
-
-void Entity::removeAttribute(const QByteArray &type)
-{
-    d_ptr->mDeletedAttributes.insert(type);
-    delete d_ptr->mAttributes.take(type);
-}
-
-bool Entity::hasAttribute(const QByteArray &type) const
-{
-    return d_ptr->mAttributes.contains(type);
-}
-
-Attribute::List Entity::attributes() const
-{
-    return d_ptr->mAttributes.values();
-}
-
-void Akonadi::Entity::clearAttributes()
-{
-    foreach (Attribute *attr, d_ptr->mAttributes) {
-        d_ptr->mDeletedAttributes.insert(attr->type());
-        delete attr;
-    }
-    d_ptr->mAttributes.clear();
-}
-
-Attribute *Entity::attribute(const QByteArray &type) const
-{
-    return d_ptr->mAttributes.value(type);
-}
-
-uint qHash(const Akonadi::Entity &entity)
-{
-    return qHash(entity.id());
-}
-
-Collection &Entity::parentCollection()
-{
-    if (!d_ptr->mParent) {
-        d_ptr->mParent = new Collection();
-    }
-    return *(d_ptr->mParent);
-}
-
-Collection Entity::parentCollection() const
-{
-    if (!d_ptr->mParent) {
-        return *(s_defaultParentCollection);
-    } else {
-        return *(d_ptr->mParent);
-    }
-}
-
-void Entity::setParentCollection(const Collection &parent)
-{
-    delete d_ptr->mParent;
-    d_ptr->mParent = new Collection(parent);
-}
-
-AKONADI_DEFINE_PRIVATE(Entity)
diff --git a/akonadi/src/core/entity.h b/akonadi/src/core/entity.h
deleted file mode 100644
index 58e20bc..0000000
--- a/akonadi/src/core/entity.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
-    Copyright (c) 2008 Tobias Koenig <tokoe@kde.org>
-
-    This library is free software; you can redistribute it and/or modify it
-    under the terms of the GNU Library General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    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 Library General Public
-    License for more details.
-
-    You should have received a copy of the GNU Library General Public License
-    along with this library; see the file COPYING.LIB.  If not, write to the
-    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-    02110-1301, USA.
-*/
-
-#ifndef AKONADI_ENTITY_H
-#define AKONADI_ENTITY_H
-
-#include "akonadicore_export.h"
-#include <QString>
-
-namespace Akonadi
-{
-class Entity;
-}
-
-AKONADICORE_EXPORT uint qHash(const Akonadi::Entity &);
-
-#include "attribute.h"
-
-#include <QDebug>
-
-#include <QtCore/QHash>
-#include <QtCore/QSharedDataPointer>
-
-#ifndef AKONADI_DECLARE_PRIVATE
-#define AKONADI_DECLARE_PRIVATE( Class ) \
-    Class##Private *d_func(); \
-    const Class##Private *d_func() const; \
-    friend class Class##Private;
-#endif
-
-namespace Akonadi
-{
-
-class Collection;
-class EntityPrivate;
-
-/**
- * @short The base class for Item and Collection.
- *
- * Entity is the common base class for Item and Collection that provides
- * unique IDs and attributes handling.
- *
- * This class is not meant to be used directly, use Item or Collection instead.
- *
- * @author Tobias Koenig <tokoe@kde.org>
- */
-class AKONADICORE_EXPORT Entity
-{
-public:
-    /**
-     * Describes the unique id type.
-     */
-    typedef qint64 Id;
-
-    /**
-     * Sets the unique @p identifier of the entity.
-     */
-    void setId(Id identifier);
-
-    /**
-     * Returns the unique identifier of the entity.
-     */
-    Id id() const;
-
-    /**
-     * Sets the remote @p id of the entity.
-     */
-    void setRemoteId(const QString &id);
-
-    /**
-     * Returns the remote id of the entity.
-     */
-    QString remoteId() const;
-
-    /**
-     * Sets the remote @p revision of the entity.
-     * @param revision the entity's remote revision
-     * The remote revision can be used by resources to store some
-     * revision information of the backend to detect changes there.
-     *
-     * @note This method is supposed to be used by resources only.
-     * @since 4.5
-     */
-    void setRemoteRevision(const QString &revision);
-
-    /**
-     * Returns the remote revision of the entity.
-     *
-     * @note This method is supposed to be used by resources only.
-     * @since 4.5
-     */
-    QString remoteRevision() const;
-
-    /**
-     * Returns whether the entity is valid.
-     */
-    bool isValid() const;
-
-    /**
-     * Returns whether the entity's id equals the
-     * id of the @p other entity.
-     */
-    bool operator==(const Entity &other) const;
-
-    /**
-     * Returns whether the entity's id does not equal the id
-     * of the @p other entity.
-     */
-    bool operator!=(const Entity &other) const;
-
-    /**
-     * Assigns the @p other to this entity and returns a reference to this entity.
-     * @param other the entity to assign
-     */
-    Entity &operator=(const Entity &other);
-
-    /**
-     * @internal For use with containers only.
-     *
-     * @since 4.8
-     */
-    bool operator<(const Entity &other) const;
-
-    /**
-     * Returns the parent collection of this object.
-     * @note This will of course only return a useful value if it was explictly \
                retrieved
-     *       from the Akonadi server.
-     * @since 4.4
-     */
-    Collection parentCollection() const;
-
-    /**
-     * Returns a reference to the parent collection of this object.
-     * @note This will of course only return a useful value if it was explictly \
                retrieved
-     *       from the Akonadi server.
-     * @since 4.4
-     */
-    Collection &parentCollection();
-
-    /**
-     * Set the parent collection of this object.
-     * @note Calling this method has no immediate effect for the object itself,
-     *       such as being moved to another collection.
-     *       It is mainly relevant to provide a context for RID-based operations
-     *       inside resources.
-     * @param parent The parent collection.
-     * @since 4.4
-     */
-    void setParentCollection(const Collection &parent);
-
-    /**
-     * Adds an attribute to the entity.
-     *
-     * If an attribute of the same type name already exists, it is deleted and
-     * replaced with the new one.
-     *
-     * @param attribute The new attribute.
-     *
-     * @note The entity takes the ownership of the attribute.
-     */
-    void addAttribute(Attribute *attribute);
-
-    /**
-     * Removes and deletes the attribute of the given type @p name.
-     */
-    void removeAttribute(const QByteArray &name);
-
-    /**
-     * Returns @c true if the entity has an attribute of the given type @p name,
-     * false otherwise.
-     */
-    bool hasAttribute(const QByteArray &name) const;
-
-    /**
-     * Returns a list of all attributes of the entity.
-     */
-    Attribute::List attributes() const;
-
-    /**
-     * Removes and deletes all attributes of the entity.
-     */
-    void clearAttributes();
-
-    /**
-     * Returns the attribute of the given type @p name if available, 0 otherwise.
-     */
-    Attribute *attribute(const QByteArray &name) const;
-
-    /**
-     * Describes the options that can be passed to access attributes.
-     */
-    enum CreateOption {
-        AddIfMissing    ///< Creates the attribute if it is missing
-    };
-
-    /**
-     * Returns the attribute of the requested type.
-     * If the entity has no attribute of that type yet, a new one
-     * is created and added to the entity.
-     *
-     * @param option The create options.
-     */
-    template <typename T> inline T *attribute(CreateOption option)
-    {
-        Q_UNUSED(option);
-
-        const T dummy;
-        if (hasAttribute(dummy.type())) {
-            T *attr = dynamic_cast<T *>(attribute(dummy.type()));
-            if (attr) {
-                return attr;
-            }
-            //Reuse 5250
-            qWarning() << "Found attribute of unknown type" << dummy.type()
-                       << ". Did you forget to call \
                AttributeFactory::registerAttribute()?";
-        }
-
-        T *attr = new T();
-        addAttribute(attr);
-        return attr;
-    }
-
-    /**
-     * Returns the attribute of the requested type or 0 if it is not available.
-     */
-    template <typename T> inline T *attribute() const
-    {
-        const T dummy;
-        if (hasAttribute(dummy.type())) {
-            T *attr = dynamic_cast<T *>(attribute(dummy.type()));
-            if (attr) {
-                return attr;
-            }
-            //reuse 5250
-            qWarning() << "Found attribute of unknown type" << dummy.type()
-                       << ". Did you forget to call \
                AttributeFactory::registerAttribute()?";
-        }
-
-        return 0;
-    }
-
-    /**
-     * Removes and deletes the attribute of the requested type.
-     */
-    template <typename T> inline void removeAttribute()
-    {
-        const T dummy;
-        removeAttribute(dummy.type());
-    }
-
-    /**
-     * Returns whether the entity has an attribute of the requested type.
-     */
-    template <typename T> inline bool hasAttribute() const
-    {
-        const T dummy;
-        return hasAttribute(dummy.type());
-    }
-
-protected:
-    /**
-     * Creates an entity from an @p other entity.
-     */
-    Entity(const Entity &other);
-
-    /**
-     * Destroys the entity.
-     */
-    ~Entity();
-
-    //@cond PRIVATE
-    Entity(EntityPrivate *dd);
-    QSharedDataPointer<EntityPrivate> d_ptr;
-    //@endcond
-
-    AKONADI_DECLARE_PRIVATE(Entity)
-};
-
-}
-
-#endif
diff --git a/akonadi/src/core/entity_p.h b/akonadi/src/core/entity_p.h
index 74d84fe..0c6d4ec 100644
--- a/akonadi/src/core/entity_p.h
+++ b/akonadi/src/core/entity_p.h
@@ -20,12 +20,9 @@
 #ifndef ENTITY_P_H
 #define ENTITY_P_H
 
-#include "entity.h"
 #include "collection.h"
 
-#include <QtCore/QSet>
-#include <QtCore/QSharedData>
-#include <QtCore/QString>
+Q_GLOBAL_STATIC(Akonadi::Collection, s_defaultParentCollection)
 
 #define AKONADI_DEFINE_PRIVATE( Class ) \
     Class##Private *Class ::d_func() \
@@ -37,71 +34,4 @@
         return reinterpret_cast<const Class##Private *>( d_ptr.data() );\
     }
 
-namespace Akonadi
-{
-
-/**
- * @internal
- */
-class EntityPrivate : public QSharedData
-{
-public:
-    explicit EntityPrivate(Entity::Id id = -1)
-        : mId(id)
-        , mParent(0)
-    {
-    }
-
-    virtual ~EntityPrivate()
-    {
-        qDeleteAll(mAttributes);
-        delete mParent;
-    }
-
-    EntityPrivate(const EntityPrivate &other)
-        : QSharedData(other)
-        , mParent(0)
-    {
-        mId = other.mId;
-        mRemoteId = other.mRemoteId;
-        mRemoteRevision = other.mRemoteRevision;
-        foreach (Attribute *attr, other.mAttributes) {
-            mAttributes.insert(attr->type(), attr->clone());
-        }
-        mDeletedAttributes = other.mDeletedAttributes;
-        if (other.mParent) {
-            mParent = new Collection(*(other.mParent));
-        }
-    }
-
-    virtual void resetChangeLog()
-    {
-        mDeletedAttributes.clear();
-    }
-
-    virtual EntityPrivate *clone() const = 0;
-
-    Entity::Id mId;
-    QString mRemoteId;
-    QString mRemoteRevision;
-    QHash<QByteArray, Attribute *> mAttributes;
-    QSet<QByteArray> mDeletedAttributes;
-    mutable Collection *mParent;
-};
-
-}
-
-/**
- * @internal
- *
- * This template specialization is used to change the detach
- * behaviour of QSharedDataPointer to allow 'virtual copy constructors',
- * so Akonadi::ItemPrivate and Akonadi::CollectionPrivate are copied correctly.
- */
-template <>
-Q_INLINE_TEMPLATE Akonadi::EntityPrivate \
                *QSharedDataPointer<Akonadi::EntityPrivate>::clone()
-{
-    return d->clone();
-}
-
 #endif
diff --git a/akonadi/src/core/entitycache_p.h b/akonadi/src/core/entitycache_p.h
index 308b388..170d9dc 100644
--- a/akonadi/src/core/entitycache_p.h
+++ b/akonadi/src/core/entitycache_p.h
@@ -41,8 +41,7 @@
 
 class KJob;
 
-typedef QList<Akonadi::Entity::Id> EntityIdList;
-Q_DECLARE_METATYPE(QList<Akonadi::Entity::Id>)
+Q_DECLARE_METATYPE(QList<qint64>)
 
 namespace Akonadi
 {
@@ -89,7 +88,7 @@ struct EntityCacheNode {
 
 /**
  * @internal
- * A in-memory FIFO cache for a small amount of Entity objects.
+ * A in-memory FIFO cache for a small amount of Item or Collection objects.
  */
 template<typename T, typename FetchJob, typename FetchScope_>
 class EntityCache : public EntityCacheBase
@@ -319,11 +318,11 @@ public:
     }
 
     /** Returns the cached object if available, an empty instance otherwise. */
-    typename T::List retrieve(const QList<Entity::Id> &ids) const
+    typename T::List retrieve(const QList<typename T::Id> &ids) const
     {
         typename T::List list;
 
-        foreach (Entity::Id id, ids) {
+        Q_FOREACH (typename T::Id id, ids) {
             EntityListCacheNode<T> *node = mCache.value(id);
             if (!node || node->pending || node->invalid) {
                 return typename T::List();
@@ -336,12 +335,12 @@ public:
     }
 
     /** Requests the object to be cached if it is not yet in the cache. @returns @c \
                true if it was in the cache already. */
-    bool ensureCached(const QList<Entity::Id> &ids, const FetchScope &scope)
+    bool ensureCached(const QList<typename T::Id> &ids, const FetchScope &scope)
     {
-        QList<Entity::Id> toRequest;
+        QList<typename T::Id> toRequest;
         bool result = true;
 
-        foreach (Entity::Id id, ids) {
+        Q_FOREACH (typename T::Id id, ids) {
             EntityListCacheNode<T> *node = mCache.value(id);
             if (!node) {
                 toRequest << id;
@@ -362,9 +361,9 @@ public:
     }
 
     /** Marks the cache entry as invalid, use in case the object has been deleted on \
                the server. */
-    void invalidate(const QList<Entity::Id> &ids)
+    void invalidate(const QList<typename T::Id> &ids)
     {
-        foreach (Entity::Id id, ids) {
+        Q_FOREACH (typename T::Id id, ids) {
             EntityListCacheNode<T> *node = mCache.value(id);
             if (node) {
                 node->invalid = true;
@@ -373,11 +372,11 @@ public:
     }
 
     /** Triggers a re-fetching of a cache entry, use if it has changed on the \
                server. */
-    void update(const QList<Entity::Id> &ids, const FetchScope &scope)
+    void update(const QList<typename T::Id> &ids, const FetchScope &scope)
     {
-        QList<Entity::Id> toRequest;
+        QList<typename T::Id> toRequest;
 
-        foreach (Entity::Id id, ids) {
+        Q_FOREACH (typename T::Id id, ids) {
             EntityListCacheNode<T> *node = mCache.value(id);
             if (node) {
                 mCache.remove(id);
@@ -398,22 +397,23 @@ public:
       a token to indicate which request has been finished in the
       dataAvailable() signal.
     */
-    void request(const QList<Entity::Id> &ids, const FetchScope &scope, const \
QList<Entity::Id> &preserveIds = QList<Entity::Id>()) +    void request(const \
QList<typename T::Id> &ids, const FetchScope &scope, +                 const \
QList<typename T::Id> &preserveIds = QList<typename T::Id>())  {
         Q_ASSERT(isNotRequested(ids));
         shrinkCache(preserveIds);
-        foreach (Entity::Id id, ids) {
+        Q_FOREACH (typename T::Id id, ids) {
             EntityListCacheNode<T> *node = new EntityListCacheNode<T>(id);
             mCache.insert(id, node);
         }
         FetchJob *job = createFetchJob(ids, scope);
-        job->setProperty("EntityListCacheIds", QVariant::fromValue< \
QList<Entity::Id> >(ids)); +        job->setProperty("EntityListCacheIds", \
                QVariant::fromValue<QList<typename T::Id>>(ids));
         connect(job, SIGNAL(result(KJob *)), SLOT(processResult(KJob *)));
     }
 
-    bool isNotRequested(const QList<Entity::Id> &ids) const
+    bool isNotRequested(const QList<typename T::Id> &ids) const
     {
-        foreach (Entity::Id id, ids) {
+        Q_FOREACH (typename T::Id id, ids) {
             if (mCache.contains(id)) {
                 return false;
             }
@@ -423,9 +423,9 @@ public:
     }
 
     /** Object is available in the cache and can be retrieved. */
-    bool isCached(const QList<Entity::Id> &ids) const
+    bool isCached(const QList<typename T::Id> &ids) const
     {
-        foreach (Entity::Id id, ids) {
+        Q_FOREACH (typename T::Id id, ids) {
             EntityListCacheNode<T> *node = mCache.value(id);
             if (!node || node->pending) {
                 return false;
@@ -436,10 +436,9 @@ public:
 
 private:
     /** Tries to reduce the cache size until at least one more object fits in. */
-    void shrinkCache(const QList<Entity::Id> &preserveIds)
+    void shrinkCache(const QList<typename T::Id> &preserveIds)
     {
-        typename
-        QHash< Entity::Id, EntityListCacheNode<T> *>::Iterator iter = \
mCache.begin(); +        typename QHash<typename T::Id, EntityListCacheNode<T> \
*>::Iterator iter = mCache.begin();  while (iter != mCache.end() && mCache.size() >= \
                mCapacity) {
             if (iter.value()->pending || preserveIds.contains(iter.key())) {
                 ++iter;
@@ -451,24 +450,24 @@ private:
         }
     }
 
-    inline FetchJob *createFetchJob(const QList<Entity::Id> &ids, const FetchScope \
&scope) +    inline FetchJob *createFetchJob(const QList<typename T::Id> &ids, const \
FetchScope &scope)  {
         FetchJob *job = new FetchJob(ids, session);
         job->setFetchScope(scope);
         return job;
     }
 
-    void processResult(KJob *job) Q_DECL_OVERRIDE {
-        if (job->error())
-        {
+    void processResult(KJob *job) Q_DECL_OVERRIDE
+    {
+        if (job->error()) {
             qWarning() << job->errorString();
         }
-        const QList<Entity::Id> ids = job->property("EntityListCacheIds").value< \
QList<Entity::Id> >(); +        const QList<typename T::Id> ids = \
job->property("EntityListCacheIds").value<QList<typename T::Id>>();  
         typename T::List entities;
         extractResults(job, entities);
 
-        foreach (Entity::Id id, ids)
+        Q_FOREACH (typename T::Id id, ids)
         {
             EntityListCacheNode<T> *node = mCache.value(id);
             if (!node) {
@@ -503,7 +502,7 @@ private:
     void extractResults(KJob *job, typename T::List &entities) const;
 
 private:
-    QHash< Entity::Id, EntityListCacheNode<T> *> mCache;
+    QHash<typename T::Id, EntityListCacheNode<T> *> mCache;
     int mCapacity;
 };
 
@@ -529,7 +528,7 @@ template<> inline void EntityListCache<Tag, TagFetchJob, \
TagFetchScope>::extract  }
 
 template<>
-inline CollectionFetchJob *EntityListCache<Collection, CollectionFetchJob, \
CollectionFetchScope>::createFetchJob(const QList<Entity::Id> &ids, const \
CollectionFetchScope &scope) +inline CollectionFetchJob *EntityListCache<Collection, \
CollectionFetchJob, CollectionFetchScope>::createFetchJob(const QList<Collection::Id> \
&ids, const CollectionFetchScope &scope)  {
     CollectionFetchJob *fetch = new CollectionFetchJob(ids, \
CollectionFetchJob::Base, session);  fetch->setFetchScope(scope);
diff --git a/akonadi/src/core/entityhiddenattribute.h \
b/akonadi/src/core/entityhiddenattribute.h index 85fad37..2534b8c 100644
--- a/akonadi/src/core/entityhiddenattribute.h
+++ b/akonadi/src/core/entityhiddenattribute.h
@@ -44,7 +44,7 @@ namespace Akonadi
  * ...
  * // hide a collection by setting the hidden attribute
  * Collection collection = collectionFetchJob->collections().at(0);
- * collection.attribute<EntityHiddenAttribute>( Entity::AddIfMissing );
+ * collection.attribute<EntityHiddenAttribute>( Collection::AddIfMissing );
  * new CollectionModifyJob( collection, this ); // save back to storage
  *
  * // check if the collection is hidden
diff --git a/akonadi/src/core/item.cpp b/akonadi/src/core/item.cpp
index e25d1b6..2d8b6d5 100644
--- a/akonadi/src/core/item.cpp
+++ b/akonadi/src/core/item.cpp
@@ -19,6 +19,8 @@
 
 #include "item.h"
 #include "item_p.h"
+#include "entity_p.h"
+
 #include "itemserializer_p.h"
 #include <akonadi/private/protocol_p.h>
 
@@ -35,6 +37,11 @@
 
 using namespace Akonadi;
 
+uint Akonadi::qHash(const Akonadi::Item &item)
+{
+    return ::qHash(item.id());
+}
+
 namespace
 {
 
@@ -131,23 +138,23 @@ static std::shared_ptr<const std::pair<int, int> > \
lookupLegacyMapping(const QSt  const char Item::FullPayload[] = "RFC822";
 
 Item::Item()
-    : Entity(new ItemPrivate)
+    : d_ptr(new ItemPrivate)
 {
 }
 
 Item::Item(Id id)
-    : Entity(new ItemPrivate(id))
+    : d_ptr(new ItemPrivate(id))
 {
 }
 
 Item::Item(const QString &mimeType)
-    : Entity(new ItemPrivate)
+    : d_ptr(new ItemPrivate)
 {
     d_func()->mMimeType = mimeType;
 }
 
 Item::Item(const Item &other)
-    : Entity(other)
+    : d_ptr(other.d_ptr)
 {
 }
 
@@ -155,6 +162,134 @@ Item::~Item()
 {
 }
 
+void Item::setId(Item::Id identifier)
+{
+    d_ptr->mId = identifier;
+}
+
+Item::Id Item::id() const
+{
+    return d_func()->mId;
+}
+
+void Item::setRemoteId(const QString &id)
+{
+    d_ptr->mRemoteId = id;
+}
+
+QString Item::remoteId() const
+{
+    return d_ptr->mRemoteId;
+}
+
+void Item::setRemoteRevision(const QString &revision)
+{
+    d_ptr->mRemoteRevision = revision;
+}
+
+QString Item::remoteRevision() const
+{
+    return d_ptr->mRemoteRevision;
+}
+
+bool Item::isValid() const
+{
+    return (d_ptr->mId >= 0);
+}
+
+bool Item::operator==(const Item &other) const
+{
+    // Invalid collections are the same, no matter what their internal ID is
+    return (!isValid() && !other.isValid()) || (d_ptr->mId == other.d_ptr->mId);
+}
+
+bool Akonadi::Item::operator!=(const Item &other) const
+{
+    return (isValid() || other.isValid()) && (d_ptr->mId != other.d_ptr->mId);
+}
+
+Item &Item ::operator=(const Item &other)
+{
+    if (this != &other) {
+        d_ptr = other.d_ptr;
+    }
+
+    return *this;
+}
+
+bool Akonadi::Item::operator<(const Item &other) const
+{
+    return d_ptr->mId < other.d_ptr->mId;
+}
+
+void Item::addAttribute(Attribute *attr)
+{
+    Q_ASSERT(attr);
+    Attribute *existing = d_ptr->mAttributes.value(attr->type());
+    if (existing) {
+        if (attr == existing) {
+            return;
+        }
+        d_ptr->mAttributes.remove(attr->type());
+        delete existing;
+    }
+    d_ptr->mAttributes.insert(attr->type(), attr);
+    d_ptr->mDeletedAttributes.remove(attr->type());
+}
+
+void Item::removeAttribute(const QByteArray &type)
+{
+    d_ptr->mDeletedAttributes.insert(type);
+    delete d_ptr->mAttributes.take(type);
+}
+
+bool Item::hasAttribute(const QByteArray &type) const
+{
+    return d_ptr->mAttributes.contains(type);
+}
+
+Attribute::List Item::attributes() const
+{
+    return d_ptr->mAttributes.values();
+}
+
+void Akonadi::Item::clearAttributes()
+{
+    Q_FOREACH (Attribute *attr, d_ptr->mAttributes) {
+        d_ptr->mDeletedAttributes.insert(attr->type());
+        delete attr;
+    }
+    d_ptr->mAttributes.clear();
+}
+
+Attribute *Item::attribute(const QByteArray &type) const
+{
+    return d_ptr->mAttributes.value(type);
+}
+
+Collection &Item::parentCollection()
+{
+    if (!d_ptr->mParent) {
+        d_ptr->mParent = new Collection();
+    }
+    return *(d_ptr->mParent);
+}
+
+Collection Item::parentCollection() const
+{
+    if (!d_ptr->mParent) {
+        return *(s_defaultParentCollection);
+    } else {
+        return *(d_ptr->mParent);
+    }
+}
+
+void Item::setParentCollection(const Collection &parent)
+{
+    delete d_ptr->mParent;
+    d_ptr->mParent = new Collection(parent);
+}
+
 Item::Flags Item::flags() const
 {
     return d_func()->mFlags;
@@ -306,12 +441,12 @@ void Item::setRevision(int rev)
     d_func()->mRevision = rev;
 }
 
-Entity::Id Item::storageCollectionId() const
+Collection::Id Item::storageCollectionId() const
 {
     return d_func()->mCollectionId;
 }
 
-void Item::setStorageCollectionId(Entity::Id collectionId)
+void Item::setStorageCollectionId(Collection::Id collectionId)
 {
     d_func()->mCollectionId = collectionId;
 }
@@ -601,7 +736,7 @@ void Item::apply(const Item &other)
 
     QList<QByteArray> attrs;
     attrs.reserve(other.attributes().count());
-    foreach (Attribute *attribute, other.attributes()) {
+    Q_FOREACH (Attribute *attribute, other.attributes()) {
         addAttribute(attribute->clone());
         attrs.append(attribute->type());
     }
diff --git a/akonadi/src/core/item.h b/akonadi/src/core/item.h
index 7e00756..a761fb7 100644
--- a/akonadi/src/core/item.h
+++ b/akonadi/src/core/item.h
@@ -22,12 +22,13 @@
 #define AKONADI_ITEM_H
 
 #include "akonadicore_export.h"
-#include "entity.h"
+#include "attribute.h"
 #include "exception.h"
 #include "tag.h"
 #include "collection.h"
 #include "relation.h"
 #include "itempayloadinternals_p.h"
+#include "job.h"
 
 #include <QtCore/QByteArray>
 #include <QtCore/QMetaType>
@@ -112,10 +113,15 @@ class ItemPrivate;
  *
  * @author Volker Krause <vkrause@kde.org>, Till Adam <adam@kde.org>, Marc Mutz \
                <mutz@kde.org>
  */
-class AKONADICORE_EXPORT Item : public Entity
+class AKONADICORE_EXPORT Item
 {
 public:
     /**
+     * Describes the unique id type.
+     */
+    typedef qint64 Id;
+
+    /**
      * Describes a list of items.
      */
     typedef QVector<Item> List;
@@ -169,6 +175,173 @@ public:
     static Item fromUrl(const QUrl &url);
 
     /**
+     * Sets the unique @p identifier of the item.
+     */
+    void setId(Id identifier);
+
+    /**
+     * Returns the unique identifier of the item.
+     */
+    Id id() const;
+
+    /**
+     * Sets the remote @p id of the item.
+     */
+    void setRemoteId(const QString &id);
+
+    /**
+     * Returns the remote id of the item.
+     */
+    QString remoteId() const;
+
+    /**
+     * Sets the remote @p revision of the item.
+     * @param revision the item's remote revision
+     * The remote revision can be used by resources to store some
+     * revision information of the backend to detect changes there.
+     *
+     * @note This method is supposed to be used by resources only.
+     * @since 4.5
+     */
+    void setRemoteRevision(const QString &revision);
+
+    /**
+     * Returns the remote revision of the item.
+     *
+     * @note This method is supposed to be used by resources only.
+     * @since 4.5
+     */
+    QString remoteRevision() const;
+
+    /**
+     * Returns whether the item is valid.
+     */
+    bool isValid() const;
+
+    /**
+     * Returns whether this item's id equals the id of the @p other item.
+     */
+    bool operator==(const Item &other) const;
+
+    /**
+     * Returns whether the item's id does not equal the id of the @p other item.
+     */
+    bool operator!=(const Item &other) const;
+
+    /**
+     * Assigns the @p other to this item and returns a reference to this item.
+     * @param other the item to assign
+     */
+    Item &operator=(const Item &other);
+
+    /**
+     * @internal For use with containers only.
+     *
+     * @since 4.8
+     */
+    bool operator<(const Item &other) const;
+
+    /**
+     * Returns the parent collection of this object.
+     * @note This will of course only return a useful value if it was explictly \
retrieved +     *       from the Akonadi server.
+     * @since 4.4
+     */
+    Collection parentCollection() const;
+
+    /**
+     * Returns a reference to the parent collection of this object.
+     * @note This will of course only return a useful value if it was explictly \
retrieved +     *       from the Akonadi server.
+     * @since 4.4
+     */
+    Collection &parentCollection();
+
+    /**
+     * Set the parent collection of this object.
+     * @note Calling this method has no immediate effect for the object itself,
+     *       such as being moved to another collection.
+     *       It is mainly relevant to provide a context for RID-based operations
+     *       inside resources.
+     * @param parent The parent collection.
+     * @since 4.4
+     */
+    void setParentCollection(const Collection &parent);
+
+    /**
+     * Adds an attribute to the item.
+     *
+     * If an attribute of the same type name already exists, it is deleted and
+     * replaced with the new one.
+     *
+     * @param attribute The new attribute.
+     *
+     * @note The collection takes the ownership of the attribute.
+     */
+    void addAttribute(Attribute *attribute);
+
+    /**
+     * Removes and deletes the attribute of the given type @p name.
+     */
+    void removeAttribute(const QByteArray &name);
+
+    /**
+     * Returns @c true if the item has an attribute of the given type @p name,
+     * false otherwise.
+     */
+    bool hasAttribute(const QByteArray &name) const;
+
+    /**
+     * Returns a list of all attributes of the item.
+     */
+    Attribute::List attributes() const;
+
+    /**
+     * Removes and deletes all attributes of the item.
+     */
+    void clearAttributes();
+
+    /**
+     * Returns the attribute of the given type @p name if available, 0 otherwise.
+     */
+    Attribute *attribute(const QByteArray &name) const;
+
+    /**
+     * Describes the options that can be passed to access attributes.
+     */
+    enum CreateOption {
+        AddIfMissing    ///< Creates the attribute if it is missing
+    };
+
+    /**
+     * Returns the attribute of the requested type.
+     * If the item has no attribute of that type yet, a new one
+     * is created and added to the entity.
+     *
+     * @param option The create options.
+     */
+    template <typename T>
+    inline T *attribute(CreateOption option);
+
+    /**
+     * Returns the attribute of the requested type or 0 if it is not available.
+     */
+    template <typename T>
+    inline T *attribute() const;
+
+    /**
+     * Removes and deletes the attribute of the requested type.
+     */
+    template <typename T>
+    inline void removeAttribute();
+
+    /**
+     * Returns whether the item has an attribute of the requested type.
+     */
+    template <typename T>
+    inline bool hasAttribute() const;
+
+    /**
      * Returns all flags of this item.
      */
     Flags flags() const;
@@ -288,7 +461,7 @@ public:
      * @returns the collection ID if it is known, -1 otherwise.
      * @since 4.3
      */
-    Entity::Id storageCollectionId() const;
+    Collection::Id storageCollectionId() const;
 
     /**
      * Set the size of the item in bytes.
@@ -550,7 +723,7 @@ private:
      * @param collectionId the unique identifier of the collection where this item \
                is stored in.
      * @since 4.3
      */
-    void setStorageCollectionId(Entity::Id collectionId);
+    void setStorageCollectionId(Collection::Id collectionId);
 
 #if 0
     /**
@@ -570,11 +743,68 @@ private:
 #else
     void throwPayloadException(int spid, int mtid) const;
 #endif
-    //@endcond
 
-    AKONADI_DECLARE_PRIVATE(Item)
+    QSharedDataPointer<ItemPrivate> d_ptr;
+    const ItemPrivate *d_func() const;
+    ItemPrivate *d_func();
+    friend class ItemPrivate;
+    //@endcond
 };
 
+AKONADICORE_EXPORT uint qHash(const Akonadi::Item &item);
+
+template <typename T>
+inline T *Item::attribute(Item::CreateOption option)
+{
+    Q_UNUSED(option);
+
+    const T dummy;
+    if (hasAttribute(dummy.type())) {
+        T *attr = dynamic_cast<T *>(attribute(dummy.type()));
+        if (attr) {
+            return attr;
+        }
+        //Reuse 5250
+        qWarning() << "Found attribute of unknown type" << dummy.type()
+                    << ". Did you forget to call \
AttributeFactory::registerAttribute()?"; +    }
+
+    T *attr = new T();
+    addAttribute(attr);
+    return attr;
+}
+
+template <typename T>
+inline T *Item::attribute() const
+{
+    const T dummy;
+    if (hasAttribute(dummy.type())) {
+        T *attr = dynamic_cast<T *>(attribute(dummy.type()));
+        if (attr) {
+            return attr;
+        }
+        //reuse 5250
+        qWarning() << "Found attribute of unknown type" << dummy.type()
+                    << ". Did you forget to call \
AttributeFactory::registerAttribute()?"; +    }
+
+    return 0;
+}
+
+template <typename T>
+inline void Item::removeAttribute()
+{
+    const T dummy;
+    removeAttribute(dummy.type());
+}
+
+template <typename T>
+inline bool Item::hasAttribute() const
+{
+    const T dummy;
+    return hasAttribute(dummy.type());
+}
+
 template <typename T>
 T Item::payload() const
 {
@@ -818,7 +1048,7 @@ void Item::addToLegacyMapping(const QString &mimeType)
     addToLegacyMappingImpl(mimeType, PayloadType::sharedPointerId, \
PayloadType::elementMetaTypeId(), p);  }
 
-}
+} // namespace Akonadi
 
 Q_DECLARE_METATYPE(Akonadi::Item)
 Q_DECLARE_METATYPE(Akonadi::Item::List)
diff --git a/akonadi/src/core/item_p.h b/akonadi/src/core/item_p.h
index 9bf5ddd..917a557 100644
--- a/akonadi/src/core/item_p.h
+++ b/akonadi/src/core/item_p.h
@@ -24,7 +24,6 @@
 #include <QtCore/QMap>
 #include <QtCore/QVarLengthArray>
 
-#include "entity_p.h"
 #include "itempayloadinternals_p.h"
 #include "tag.h"
 
@@ -277,15 +276,16 @@ namespace Akonadi
 /**
  * @internal
  */
-class ItemPrivate : public EntityPrivate
+class ItemPrivate : public QSharedData
 {
 public:
     explicit ItemPrivate(Item::Id id = -1)
-        : EntityPrivate(id)
+        : QSharedData()
+        , mRevision(-1)
+        , mId(id)
+        , mParent(Q_NULLPTR)
         , mLegacyPayload()
         , mPayloads()
-        , mConversionInProgress(false)
-        , mRevision(-1)
         , mCollectionId(-1)
         , mSize(0)
         , mModificationTime()
@@ -293,35 +293,56 @@ public:
         , mTagsOverwritten(false)
         , mSizeChanged(false)
         , mClearPayload(false)
+        , mConversionInProgress(false)
     {
     }
 
-#if 0
     ItemPrivate(const ItemPrivate &other)
-        : EntityPrivate(other)
-    {
+        : QSharedData(other)
+        , mParent(Q_NULLPTR)
+    {
+        mId = other.mId;
+        mRemoteId = other.mRemoteId;
+        mRemoteRevision = other.mRemoteRevision;
+        Q_FOREACH (Attribute *attr, other.mAttributes) {
+            mAttributes.insert(attr->type(), attr->clone());
+        }
+        mDeletedAttributes = other.mDeletedAttributes;
+        if (other.mParent) {
+            mParent = new Collection(*(other.mParent));
+        }
         mFlags = other.mFlags;
         mRevision = other.mRevision;
+        mTags = other.mTags;
+        mRelations = other.mRelations;
         mSize = other.mSize;
         mModificationTime = other.mModificationTime;
         mMimeType = other.mMimeType;
         mLegacyPayload = other.mLegacyPayload;
         mPayloads = other.mPayloads;
-        mConversionInProgress = false;
         mAddedFlags = other.mAddedFlags;
         mDeletedFlags = other.mDeletedFlags;
         mFlagsOverwritten = other.mFlagsOverwritten;
         mSizeChanged = other.mSizeChanged;
         mCollectionId = other.mCollectionId;
         mClearPayload = other.mClearPayload;
+        mVirtualReferences = other.mVirtualReferences;
+        mGid = other.mGid;
+        mAddedTags = other.mAddedTags;
+        mDeletedTags = other.mDeletedTags;
+        mCachedPayloadParts = other.mCachedPayloadParts;
+        mTagsOverwritten = other.mTagsOverwritten;
+        mConversionInProgress = false;
     }
-#endif
 
     ~ItemPrivate()
     {
+        qDeleteAll(mAttributes);
+        delete mParent;
     }
 
-    void resetChangeLog() Q_DECL_OVERRIDE {
+    void resetChangeLog()
+    {
         mFlagsOverwritten = false;
         mAddedFlags.clear();
         mDeletedFlags.clear();
@@ -329,11 +350,7 @@ public:
         mTagsOverwritten = false;
         mAddedTags.clear();
         mDeletedTags.clear();
-    }
-
-    EntityPrivate *clone() const Q_DECL_OVERRIDE
-    {
-        return new ItemPrivate(*this);
+        mDeletedAttributes.clear();
     }
 
     bool hasMetaTypeId(int mtid) const
@@ -413,15 +430,22 @@ public:
     void setLegacyPayloadBaseImpl(std::unique_ptr<PayloadBase> p);
     void tryEnsureLegacyPayload() const;
 
+    // Utilise the 4-bytes padding from QSharedData
+    int mRevision;
+    Item::Id mId;
+    QString mRemoteId;
+    QString mRemoteRevision;
+    QHash<QByteArray, Attribute *> mAttributes;
+    QSet<QByteArray> mDeletedAttributes;
+    mutable Collection *mParent;
     mutable _detail::clone_ptr<PayloadBase> mLegacyPayload;
     mutable PayloadContainer mPayloads;
-    mutable bool mConversionInProgress;
-    int mRevision;
     Item::Flags mFlags;
     Tag::List mTags;
     Relation::List mRelations;
-    Entity::Id mCollectionId;
+    Item::Id mCollectionId;
     Collection::List mVirtualReferences;
+    // TODO: Maybe just use uint? Would save us another 8 bytes after reordering
     qint64 mSize;
     QDateTime mModificationTime;
     QString mMimeType;
@@ -435,6 +459,8 @@ public:
     bool mTagsOverwritten : 1;
     bool mSizeChanged : 1;
     bool mClearPayload : 1;
+    mutable bool mConversionInProgress;
+    // 6 bytes padding here
 };
 
 }
diff --git a/akonadi/src/core/jobs/collectionfetchjob.cpp \
b/akonadi/src/core/jobs/collectionfetchjob.cpp index a2ae34a..4e7bb0f 100644
--- a/akonadi/src/core/jobs/collectionfetchjob.cpp
+++ b/akonadi/src/core/jobs/collectionfetchjob.cpp
@@ -21,7 +21,7 @@
 
 #include "job_p.h"
 #include "protocolhelper_p.h"
-#include "entity_p.h"
+#include "collection_p.h"
 #include "collectionfetchscope.h"
 #include "collectionutils.h"
 #include "protocolhelper_p.h"
diff --git a/akonadi/src/core/jobs/collectionmodifyjob.h \
b/akonadi/src/core/jobs/collectionmodifyjob.h index 6e7c277..cac860b 100644
--- a/akonadi/src/core/jobs/collectionmodifyjob.h
+++ b/akonadi/src/core/jobs/collectionmodifyjob.h
@@ -55,7 +55,7 @@ class CollectionModifyJobPrivate;
  *
  * // Update the 'MyAttribute' attribute of 'collection'.
  * Akonadi::Collection c( collection.id() );
- * MyAttribute *attribute = c.attribute<MyAttribute>( Entity::AddIfMissing );
+ * MyAttribute *attribute = c.attribute<MyAttribute>( Collection::AddIfMissing );
  * if ( collection.hasAttribute<MyAttribute>() ) {
  *     *attribute = *collection.attribute<MyAttribute>();
  * }
diff --git a/akonadi/src/core/jobs/itemmodifyjob.cpp \
b/akonadi/src/core/jobs/itemmodifyjob.cpp index 70fe577..cba6268 100644
--- a/akonadi/src/core/jobs/itemmodifyjob.cpp
+++ b/akonadi/src/core/jobs/itemmodifyjob.cpp
@@ -23,7 +23,6 @@
 #include "changemediator_p.h"
 #include "collection.h"
 #include "conflicthandler_p.h"
-#include "entity_p.h"
 #include "item_p.h"
 #include "itemserializer_p.h"
 #include "job_p.h"
diff --git a/akonadi/src/core/jobs/itemmodifyjob_p.h \
b/akonadi/src/core/jobs/itemmodifyjob_p.h index d95280c..9237a2d 100644
--- a/akonadi/src/core/jobs/itemmodifyjob_p.h
+++ b/akonadi/src/core/jobs/itemmodifyjob_p.h
@@ -53,7 +53,7 @@ public:
     void conflictResolved();
     void conflictResolveError(const QString &message);
 
-    void doUpdateItemRevision(Entity::Id, int oldRevision, int newRevision) \
Q_DECL_OVERRIDE; +    void doUpdateItemRevision(Item::Id id, int oldRevision, int \
newRevision) Q_DECL_OVERRIDE;  
     QString jobDebuggingString() const Q_DECL_OVERRIDE /*Q_DECL_OVERRIDE*/;
     Protocol::Command fullCommand() const;
diff --git a/akonadi/src/core/jobs/tagmodifyjob.cpp \
b/akonadi/src/core/jobs/tagmodifyjob.cpp index 9c3fd41..117308d8 100644
--- a/akonadi/src/core/jobs/tagmodifyjob.cpp
+++ b/akonadi/src/core/jobs/tagmodifyjob.cpp
@@ -20,6 +20,7 @@
 #include "tagmodifyjob.h"
 #include "job_p.h"
 #include "tag.h"
+#include "tag_p.h"
 #include "protocolhelper_p.h"
 #include "changemediator_p.h"
 
@@ -55,8 +56,8 @@ void TagModifyJob::doStart()
     if (d->mTag.parent().isValid() && !d->mTag.isImmutable()) {
         cmd.setParentId(d->mTag.parent().id());
     }
-    if (!d->mTag.removedAttributes().isEmpty()) {
-        cmd.setRemovedAttributes(d->mTag.removedAttributes());
+    if (!d->mTag.d_ptr->mDeletedAttributes.isEmpty()) {
+        cmd.setRemovedAttributes(d->mTag.d_ptr->mDeletedAttributes);
     }
 
     cmd.setAttributes(ProtocolHelper::attributesToProtocol(d->mTag));
diff --git a/akonadi/src/core/jobs/trashjob.cpp b/akonadi/src/core/jobs/trashjob.cpp
index 8a475bb..879e5c2 100644
--- a/akonadi/src/core/jobs/trashjob.cpp
+++ b/akonadi/src/core/jobs/trashjob.cpp
@@ -81,7 +81,7 @@ public:
     bool mSetRestoreCollection; //only set restore collection when moved to trash \
collection (not in place)  bool mDeleteIfInTrash;
     QHash<Collection, Item::List> mCollectionItems; //list of trashed items sorted \
                according to parent collection
-    QHash<Entity::Id, Collection> mParentCollections; //fetched parent collcetion of \
items (containing the resource name) +    QHash<Item::Id, Collection> \
mParentCollections; //fetched parent collection of items (containing the resource \
name)  
 };
 
diff --git a/akonadi/src/core/models/entityorderproxymodel.cpp \
b/akonadi/src/core/models/entityorderproxymodel.cpp index 5800816..793c97a 100644
--- a/akonadi/src/core/models/entityorderproxymodel.cpp
+++ b/akonadi/src/core/models/entityorderproxymodel.cpp
@@ -271,13 +271,13 @@ QString EntityOrderProxyModel::parentConfigString(const \
QModelIndex &index) cons  
 QString EntityOrderProxyModel::configString(const QModelIndex &index) const
 {
-    Entity::Id eId = index.data(EntityTreeModel::ItemIdRole).toLongLong();
-    if (eId != -1) {
-        return QLatin1String("i") + QString::number(eId);
+    Item::Id iId = index.data(EntityTreeModel::ItemIdRole).toLongLong();
+    if (iId != -1) {
+        return QLatin1String("i") + QString::number(iId);
     }
-    eId = index.data(EntityTreeModel::CollectionIdRole).toLongLong();
-    if (eId != -1) {
-        return QLatin1String("c") + QString::number(eId);
+    Collection::Id cId = index.data(EntityTreeModel::CollectionIdRole).toLongLong();
+    if (cId != -1) {
+        return QLatin1String("c") + QString::number(cId);
     }
     Q_ASSERT(!"Invalid entity");
     return QString();
diff --git a/akonadi/src/core/models/entitytreemodel.cpp \
b/akonadi/src/core/models/entitytreemodel.cpp index 889292d..f944162 100644
--- a/akonadi/src/core/models/entitytreemodel.cpp
+++ b/akonadi/src/core/models/entitytreemodel.cpp
@@ -847,7 +847,7 @@ bool EntityTreeModel::setData(const QModelIndex &index, const \
QVariant &value, i  return false;
                 }
 
-                EntityDisplayAttribute *eda = \
collection.attribute<EntityDisplayAttribute>(Entity::AddIfMissing); +                \
EntityDisplayAttribute *eda = \
collection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing);  \
eda->setBackgroundColor(color);  }
 
@@ -870,7 +870,7 @@ bool EntityTreeModel::setData(const QModelIndex &index, const \
QVariant &value, i  
             if (Qt::EditRole == role) {
                 if (item.hasAttribute<EntityDisplayAttribute>()) {
-                    EntityDisplayAttribute *displayAttribute = \
item.attribute<EntityDisplayAttribute>(Entity::AddIfMissing); +                    \
EntityDisplayAttribute *displayAttribute = \
item.attribute<EntityDisplayAttribute>(Item::AddIfMissing);  \
displayAttribute->setDisplayName(value.toString());  }
             }
@@ -882,7 +882,7 @@ bool EntityTreeModel::setData(const QModelIndex &index, const \
QVariant &value, i  return false;
                 }
 
-                EntityDisplayAttribute *eda = \
item.attribute<EntityDisplayAttribute>(Entity::AddIfMissing); +                \
EntityDisplayAttribute *eda = \
item.attribute<EntityDisplayAttribute>(Item::AddIfMissing);  \
eda->setBackgroundColor(color);  }
 
diff --git a/akonadi/src/core/models/entitytreemodel_p.cpp \
b/akonadi/src/core/models/entitytreemodel_p.cpp index 0f243ca..db97664 100644
--- a/akonadi/src/core/models/entitytreemodel_p.cpp
+++ b/akonadi/src/core/models/entitytreemodel_p.cpp
@@ -268,25 +268,11 @@ void EntityTreeModelPrivate::fetchCollections(const Collection \
&collection, Coll  fetchCollections(job);
 }
 
-// Specialization needs to be in the same namespace as the definition
 namespace Akonadi
 {
 
-template<>
-bool EntityTreeModelPrivate::isHidden<Akonadi::Collection>(const Akonadi::Collection \
                &entity) const
-{
-    return isHidden(entity, Node::Collection);
-}
-
-template<>
-bool EntityTreeModelPrivate::isHidden<Akonadi::Item>(const Akonadi::Item &entity) \
                const
-{
-    return isHidden(entity, Node::Item);
-}
-
-}
-
-bool EntityTreeModelPrivate::isHidden(const Entity &entity, Node::Type type) const
+template<typename T>
+inline bool EntityTreeModelPrivate::isHiddenImpl(const T &entity, Node::Type type) \
const  {
     if (m_showSystemEntities) {
         return false;
@@ -297,18 +283,32 @@ bool EntityTreeModelPrivate::isHidden(const Entity &entity, \
Node::Type type) con  return false;
     }
 
-    if (entity.hasAttribute<EntityHiddenAttribute>()) {
+    // entity.hasAttribute<EntityHiddenAttribute>() does not compile w/ GCC for
+    // some reason
+    if (entity.hasAttribute(EntityHiddenAttribute().type())) {
         return true;
     }
 
     const Collection parent = entity.parentCollection();
     if (parent.isValid()) {
-        return isHidden(parent, Node::Collection);
+        return isHiddenImpl(parent, Node::Collection);
     }
 
     return false;
 }
 
+}
+
+bool EntityTreeModelPrivate::isHidden(const Akonadi::Collection &collection) const
+{
+    return isHiddenImpl(collection, Node::Collection);
+}
+
+bool EntityTreeModelPrivate::isHidden(const Akonadi::Item &item) const
+{
+    return isHiddenImpl(item, Node::Item);
+}
+
 void EntityTreeModelPrivate::collectionListFetched(const Akonadi::Collection::List \
&collections)  {
     QVectorIterator<Akonadi::Collection> it(collections);
@@ -1732,8 +1732,8 @@ QModelIndex EntityTreeModelPrivate::indexForCollection(const \
Collection &collect  } else if (collection.parentCollection().isValid()) {
         parentId = collection.parentCollection().id();
     } else {
-        QHash<Entity::Id, QList<Node *> >::const_iterator it = \
                m_childEntities.constBegin();
-        const QHash<Entity::Id, QList<Node *> >::const_iterator end = \
m_childEntities.constEnd(); +        QHash<Node::Id, QList<Node *> >::const_iterator \
it = m_childEntities.constBegin(); +        const QHash<Node::Id, QList<Node *> \
>::const_iterator end = m_childEntities.constEnd();  for (; it != end; ++it) {
             const int row = indexOf<Node::Collection>(it.value(), collection.id());
             if (row < 0) {
@@ -1866,7 +1866,7 @@ void EntityTreeModelPrivate::fillModel()
 
         Item::List items;
         items.reserve(m_monitor->itemsMonitoredEx().size());
-        foreach (Entity::Id id, m_monitor->itemsMonitoredEx()) {
+        Q_FOREACH (Item::Id id, m_monitor->itemsMonitoredEx()) {
             items.append(Item(id));
         }
         ItemFetchJob *itemFetch = new ItemFetchJob(items, m_session);
diff --git a/akonadi/src/core/models/entitytreemodel_p.h \
b/akonadi/src/core/models/entitytreemodel_p.h index 840fd63..cab1ba4 100644
--- a/akonadi/src/core/models/entitytreemodel_p.h
+++ b/akonadi/src/core/models/entitytreemodel_p.h
@@ -43,8 +43,10 @@ class AgentInstance;
 }
 
 struct Node {
-    Akonadi::Entity::Id id;
-    Akonadi::Entity::Id parent;
+    typedef qint64 Id;
+
+    Id id;
+    Akonadi::Collection::Id parent;
 
     enum Type {
         Item,
@@ -133,13 +135,13 @@ public:
     QIcon iconForName(const QString &name) const;
 
     QHash<Collection::Id, Collection> m_collections;
-    QHash<Entity::Id, Item> m_items;
+    QHash<Item::Id, Item> m_items;
     QHash<Collection::Id, QList<Node *> > m_childEntities;
     QSet<Collection::Id> m_populatedCols;
     QSet<Collection::Id> m_collectionsWithoutItems;
 
-    QVector<Entity::Id> m_pendingCutItems;
-    QVector<Entity::Id> m_pendingCutCollections;
+    QVector<Item::Id> m_pendingCutItems;
+    QVector<Item::Id> m_pendingCutCollections;
     mutable QSet<Collection::Id> m_pendingCollectionRetrieveJobs;
     mutable QSet<KJob *> m_pendingCollectionFetchJobs;
 
@@ -185,10 +187,10 @@ public:
      * Returns the index of the node in @p list with the id @p id. Returns -1 if not \
                found.
      */
     template<Node::Type Type>
-    int indexOf(const QList<Node *> &nodes, Entity::Id id) const
+    int indexOf(const QList<Node *> &nodes, Node::Id id) const
     {
         int i = 0;
-        foreach (const Node *node, nodes) {
+        Q_FOREACH (const Node *node, nodes) {
             if (node->id == id && node->type == Type) {
                 return i;
             }
@@ -215,12 +217,13 @@ public:
     void topLevelCollectionsFetched(const Akonadi::Collection::List \
&collectionList);  
     /**
-      @returns True if @p entity or one of its descemdants is hidden.
+      @returns True if @p item or one of its descemdants is hidden.
     */
-    bool isHidden(const Entity &entity, Node::Type type) const;
+    bool isHidden(const Item &item) const;
+    bool isHidden(const Collection &collection) const;
 
     template<typename T>
-    bool isHidden(const T &entity) const;
+    bool isHiddenImpl(const T &entity, Node::Type type) const;
 
     bool m_showSystemEntities;
 
diff --git a/akonadi/src/core/models/tagmodel.h b/akonadi/src/core/models/tagmodel.h
index c0b2992..6e34b83 100644
--- a/akonadi/src/core/models/tagmodel.h
+++ b/akonadi/src/core/models/tagmodel.h
@@ -25,6 +25,8 @@
 #include "akonadicore_export.h"
 #include "tag.h"
 
+class KJob;
+
 namespace Akonadi
 {
 
diff --git a/akonadi/src/core/models/tagmodel_p.h \
b/akonadi/src/core/models/tagmodel_p.h index 78c7660..bd5f3f0 100644
--- a/akonadi/src/core/models/tagmodel_p.h
+++ b/akonadi/src/core/models/tagmodel_p.h
@@ -23,6 +23,7 @@
 #include "tag.h"
 
 class QModelIndex;
+class KJob;
 
 namespace Akonadi
 {
diff --git a/akonadi/src/core/models/trashfilterproxymodel.cpp \
b/akonadi/src/core/models/trashfilterproxymodel.cpp index 2161594..1bc4f8e 100644
--- a/akonadi/src/core/models/trashfilterproxymodel.cpp
+++ b/akonadi/src/core/models/trashfilterproxymodel.cpp
@@ -18,7 +18,6 @@
 */
 #include "trashfilterproxymodel.h"
 
-#include "entity.h"
 #include "entitydeletedattribute.h"
 #include "item.h"
 #include "entitytreemodel.h"
@@ -32,21 +31,9 @@ public:
         : mTrashIsShown(false)
     {
     };
-    bool showEntity(const Entity &) const;
     bool mTrashIsShown;
 };
 
-bool TrashFilterProxyModel::TrashFilterProxyModelPrivate::showEntity(const \
                Akonadi::Entity &entity) const
-{
-    if (entity.hasAttribute<EntityDeletedAttribute>()) {
-        return true;
-    }
-    if (entity.id() == Collection::root().id()) {
-        return false;
-    }
-    return showEntity(entity.parentCollection());
-}
-
 TrashFilterProxyModel::TrashFilterProxyModel(QObject *parent)
     : KRecursiveFilterProxyModel(parent)
     , d_ptr(new TrashFilterProxyModelPrivate())
@@ -79,13 +66,13 @@ bool TrashFilterProxyModel::acceptRow(int sourceRow, const \
                QModelIndex &sourcePa
     const Item &item = index.data(EntityTreeModel::ItemRole).value<Item>();
     //qDebug() << item.id();
     if (item.isValid()) {
-        if (item.hasAttribute<EntityDeletedAttribute>()/* d->showEntity(item)*/) {
+        if (item.hasAttribute<EntityDeletedAttribute>()) {
             return d->mTrashIsShown;
         }
     }
     const Collection &collection = \
index.data(EntityTreeModel::CollectionRole).value<Collection>();  if \
                (collection.isValid()) {
-        if (collection.hasAttribute<EntityDeletedAttribute>()/*d->showEntity(collection) \
*/) { +        if (collection.hasAttribute<EntityDeletedAttribute>()) {
             return d->mTrashIsShown;
         }
     }
diff --git a/akonadi/src/core/monitor_p.cpp b/akonadi/src/core/monitor_p.cpp
index 70bbb7c..af5fabd 100644
--- a/akonadi/src/core/monitor_p.cpp
+++ b/akonadi/src/core/monitor_p.cpp
@@ -123,7 +123,7 @@ void MonitorPrivate::serverStateChanged(ServerManager::State \
state)  Q_FOREACH (const Collection &col, collections) {
                 notificationSource->setMonitoredCollection(col.id(), true);
             }
-            Q_FOREACH (const Entity::Id id, items) {
+            Q_FOREACH (const Item::Id id, items) {
                 notificationSource->setMonitoredItem(id, true);
             }
             Q_FOREACH (const QByteArray &resource, resources) {
@@ -153,7 +153,7 @@ void MonitorPrivate::invalidateCollectionCache(qint64 id)
 
 void MonitorPrivate::invalidateItemCache(qint64 id)
 {
-    itemCache->update(QList<Entity::Id>() << id, mItemFetchScope);
+    itemCache->update(QList<Item::Id>() << id, mItemFetchScope);
 }
 
 void MonitorPrivate::invalidateTagCache(qint64 id)
@@ -1264,7 +1264,7 @@ int MonitorPrivate::PurgeBuffer::buffersize()
     return MAXBUFFERSIZE;
 }
 
-bool MonitorPrivate::isMonitored(Entity::Id colId) const
+bool MonitorPrivate::isMonitored(Collection::Id colId) const
 {
     if (!useRefCounting) {
         return true;
@@ -1272,7 +1272,7 @@ bool MonitorPrivate::isMonitored(Entity::Id colId) const
     return refCountMap.contains(colId) || m_buffer.isBuffered(colId);
 }
 
-void MonitorPrivate::notifyCollectionStatisticsWatchers(Entity::Id collection, const \
QByteArray &resource) +void \
MonitorPrivate::notifyCollectionStatisticsWatchers(Collection::Id collection, const \
QByteArray &resource)  {
     if (collection > 0 && (monitorAll || isCollectionMonitored(collection) || \
resources.contains(resource))) {  recentlyChangedCollections.insert(collection);
diff --git a/akonadi/src/core/notificationsource_p.cpp \
b/akonadi/src/core/notificationsource_p.cpp index f90bc34..d30e2cd 100644
--- a/akonadi/src/core/notificationsource_p.cpp
+++ b/akonadi/src/core/notificationsource_p.cpp
@@ -55,7 +55,7 @@ void NotificationSource::setExclusive(bool exclusive)
     Q_UNUSED(ok);
 }
 
-void NotificationSource::setMonitoredCollection(Entity::Id id, bool monitored)
+void NotificationSource::setMonitoredCollection(Collection::Id id, bool monitored)
 {
     const bool ok = QMetaObject::invokeMethod(parent(), "setMonitoredCollection",
                     Q_ARG(qlonglong, id),
@@ -64,7 +64,7 @@ void NotificationSource::setMonitoredCollection(Entity::Id id, bool \
monitored)  Q_UNUSED(ok);
 }
 
-void NotificationSource::setMonitoredItem(Entity::Id id, bool monitored)
+void NotificationSource::setMonitoredItem(Item::Id id, bool monitored)
 {
     const bool ok = QMetaObject::invokeMethod(parent(), "setMonitoredItem",
                     Q_ARG(qlonglong, id),
diff --git a/akonadi/src/core/notificationsource_p.h \
b/akonadi/src/core/notificationsource_p.h index 4b0133c..7ef0de4 100644
--- a/akonadi/src/core/notificationsource_p.h
+++ b/akonadi/src/core/notificationsource_p.h
@@ -24,8 +24,9 @@
 
 #include "akonadiprivate_export.h"
 
-#include "entity.h"
 #include "tag.h"
+#include "collection.h"
+#include "item.h"
 
 #include <akonadi/private/protocol_p.h>
 
@@ -44,8 +45,8 @@ public:
 
     void setAllMonitored(bool allMonitored);
     void setExclusive(bool exclusive);
-    void setMonitoredCollection(Entity::Id id, bool monitored);
-    void setMonitoredItem(Entity::Id id, bool monitored);
+    void setMonitoredCollection(Collection::Id id, bool monitored);
+    void setMonitoredItem(Item::Id id, bool monitored);
     void setMonitoredResource(const QByteArray &resource, bool monitored);
     void setMonitoredMimeType(const QString &mimeType, bool monitored);
     void setMonitoredTag(Tag::Id id, bool monitored);
diff --git a/akonadi/src/core/pastehelper.cpp b/akonadi/src/core/pastehelper.cpp
index 39ff3c9..3a5cd1e 100644
--- a/akonadi/src/core/pastehelper.cpp
+++ b/akonadi/src/core/pastehelper.cpp
@@ -91,7 +91,9 @@ PasteHelperJob::PasteHelperJob(Qt::DropAction action, const \
Item::List &items,  // Check if all items have the same parent collection ID
         const Collection parent = items.first().parentCollection();
         if (std::find_if(items.constBegin(), items.constEnd(),
-                         std::bind(&Entity::operator!=, \
std::bind(static_cast<Collection(Item::*)() const>(&Item::parentCollection), _1), \
parent)) +                         [parent](const Item &item) -> bool {
+                             return item.parentCollection() != parent;
+                         })
                 == items.constEnd()) {
             dragSourceCollection = parent;
         }
diff --git a/akonadi/src/core/protocolhelper.cpp \
b/akonadi/src/core/protocolhelper.cpp index 4166940..676683c 100644
--- a/akonadi/src/core/protocolhelper.cpp
+++ b/akonadi/src/core/protocolhelper.cpp
@@ -21,8 +21,8 @@
 
 #include "attributefactory.h"
 #include "collectionstatistics.h"
-#include "entity_p.h"
 #include "item_p.h"
+#include "collection_p.h"
 #include "exception.h"
 #include "itemserializer_p.h"
 #include "itemserializerplugin.h"
@@ -67,13 +67,29 @@ Protocol::CachePolicy ProtocolHelper::cachePolicyToProtocol(const \
CachePolicy &p  return proto;
 }
 
-void ProtocolHelper::parseAncestorsCached(const QVector<Protocol::Ancestor> \
                &ancestors, Entity *entity,
-        Collection::Id parentCollection,
-        ProtocolHelperValuePool *pool)
+
+template<typename T>
+inline static void parseAttributesImpl(const Protocol::Attributes &attributes, T \
*entity) +{
+    for (auto iter = attributes.cbegin(), end = attributes.cend(); iter != end; \
++iter) { +        Attribute *attribute = \
AttributeFactory::createAttribute(iter.key()); +        if (!attribute) {
+            qWarning() << "Warning: unknown attribute" << iter.key();
+            continue;
+        }
+        attribute->deserialize(iter.value());
+        entity->addAttribute(attribute);
+    }
+}
+
+template<typename T>
+inline static void parseAncestorsCachedImpl(const QVector<Protocol::Ancestor> \
&ancestors, T *entity, +                                            Collection::Id \
parentCollection, +                                            \
ProtocolHelperValuePool *pool)  {
     if (!pool || parentCollection == -1) {
         // if no pool or parent collection id is provided we can't cache anything, \
                so continue as usual
-        parseAncestors(ancestors, entity);
+        ProtocolHelper::parseAncestors(ancestors, entity);
         return;
     }
 
@@ -82,17 +98,50 @@ void ProtocolHelper::parseAncestorsCached(const \
                QVector<Protocol::Ancestor> &anc
         entity->setParentCollection(pool->ancestorCollections.value(parentCollection));
  } else {
         // not cached yet, parse the chain
-        parseAncestors(ancestors, entity);
+        ProtocolHelper::parseAncestors(ancestors, entity);
         pool->ancestorCollections.insert(parentCollection, \
entity->parentCollection());  }
 }
 
-void ProtocolHelper::parseAncestors(const QVector<Protocol::Ancestor> &ancestors, \
Entity *entity) +template<typename T>
+inline static Protocol::Attributes attributesToProtocolImpl(const T &entity, bool \
ns) +{
+    Protocol::Attributes attributes;
+    Q_FOREACH (const Attribute *attr, entity.attributes()) {
+        attributes.insert(ProtocolHelper::encodePartIdentifier(ns ? \
ProtocolHelper::PartAttribute : ProtocolHelper::PartGlobal, attr->type()), +          \
attr->serialized()); +    }
+    return attributes;
+}
+
+void ProtocolHelper::parseAncestorsCached(const QVector<Protocol::Ancestor> \
&ancestors, +                                          Item *item, Collection::Id \
parentCollection, +                                          ProtocolHelperValuePool \
*pool) +{
+    parseAncestorsCachedImpl(ancestors, item, parentCollection, pool);
+}
+
+void ProtocolHelper::parseAncestorsCached(const QVector<Protocol::Ancestor> \
&ancestors, +                                          Collection *collection, \
Collection::Id parentCollection, +                                          \
ProtocolHelperValuePool *pool) +{
+    parseAncestorsCachedImpl(ancestors, collection, parentCollection, pool);
+}
+
+void ProtocolHelper::parseAncestors(const QVector<Protocol::Ancestor> &ancestors, \
Item *item) +{
+    Collection fakeCollection;
+    parseAncestors(ancestors, &fakeCollection);
+
+    item->setParentCollection(fakeCollection.parentCollection());
+}
+
+void ProtocolHelper::parseAncestors(const QVector<Protocol::Ancestor> &ancestors, \
Collection *collection)  {
     static const Collection::Id rootCollectionId = Collection::root().id();
     QList<QByteArray> parentIds;
 
-    Entity *current = entity;
+    Collection *current = collection;
     Q_FOREACH (const Protocol::Ancestor &ancestor, ancestors) {
         if (ancestor.id() == rootCollectionId) {
             current->setParentCollection(Collection::root());
@@ -102,7 +151,7 @@ void ProtocolHelper::parseAncestors(const \
QVector<Protocol::Ancestor> &ancestors  Akonadi::Collection \
parentCollection(ancestor.id());  parentCollection.setName(ancestor.name());
         parentCollection.setRemoteId(ancestor.remoteId());
-        parseAttributes(ancestor.attributes(), &parentCollection);
+        parseAttributesImpl(ancestor.attributes(), &parentCollection);
         current->setParentCollection(parentCollection);
         current = &current->parentCollection();
     }
@@ -132,49 +181,34 @@ CollectionStatistics \
ProtocolHelper::parseCollectionStatistics(const Protocol::F  return cs;
 }
 
-template<typename T>
-inline static void parseAttributesImpl(const Protocol::Attributes &attributes, T \
*entity) +void ProtocolHelper::parseAttributes(const Protocol::Attributes \
&attributes, Item *item)  {
-    for (auto iter = attributes.cbegin(), end = attributes.cend(); iter != end; \
                ++iter) {
-        Attribute *attribute = AttributeFactory::createAttribute(iter.key());
-        if (!attribute) {
-            qWarning() << "Warning: unknown attribute" << iter.key();
-            continue;
-        }
-        attribute->deserialize(iter.value());
-        entity->addAttribute(attribute);
-    }
+    parseAttributesImpl(attributes, item);
 }
 
-void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Entity \
*entity) +void ProtocolHelper::parseAttributes(const Protocol::Attributes \
&attributes, Collection *collection)  {
-    parseAttributesImpl(attributes, entity);
+    parseAttributesImpl(attributes, collection);
 }
 
-void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, \
AttributeEntity *entity) +void ProtocolHelper::parseAttributes(const \
Protocol::Attributes &attributes, Tag *tag)  {
-    parseAttributesImpl(attributes, entity);
+    parseAttributesImpl(attributes, tag);
 }
 
-template<typename T>
-inline static Protocol::Attributes attributesToProtocolImpl(const T &entity, bool \
ns) +Protocol::Attributes ProtocolHelper::attributesToProtocol(const Item &item, bool \
ns)  {
-    Protocol::Attributes attributes;
-    Q_FOREACH (const Attribute *attr, entity.attributes()) {
-        attributes.insert(ProtocolHelper::encodePartIdentifier(ns ? \
                ProtocolHelper::PartAttribute : ProtocolHelper::PartGlobal, \
                attr->type()),
-                          attr->serialized());
-    }
-    return attributes;
+    return attributesToProtocolImpl(item, ns);
 }
 
-Protocol::Attributes ProtocolHelper::attributesToProtocol(const Entity &entity, bool \
ns) +Protocol::Attributes ProtocolHelper::attributesToProtocol(const Collection \
&collection, bool ns)  {
-    return attributesToProtocolImpl(entity, ns);
+    return attributesToProtocolImpl(collection, ns);
 }
 
-Protocol::Attributes ProtocolHelper::attributesToProtocol(const AttributeEntity \
&entity, bool ns) +Protocol::Attributes ProtocolHelper::attributesToProtocol(const \
Tag &tag, bool ns)  {
-    return attributesToProtocolImpl(entity, ns);
+    return attributesToProtocolImpl(tag, ns);
 }
 
 Collection ProtocolHelper::parseCollection(const Protocol::FetchCollectionsResponse \
&data, bool requireParent) @@ -201,7 +235,7 @@ Collection \
ProtocolHelper::parseCollection(const Protocol::FetchCollectionsRespo  \
collection.setReferenced(data.referenced());  
     if (!data.searchQuery().isEmpty()) {
-        auto attr = \
collection.attribute<PersistentSearchAttribute>(Entity::AddIfMissing); +        auto \
attr = collection.attribute<PersistentSearchAttribute>(Collection::AddIfMissing);  \
attr->setQueryString(data.searchQuery());  
         QVector<Collection> cols;
@@ -214,7 +248,7 @@ Collection ProtocolHelper::parseCollection(const \
Protocol::FetchCollectionsRespo  
     parseAttributes(data.attributes(), &collection);
 
-    collection.d_ptr->resetChangeLog();;
+    collection.d_ptr->resetChangeLog();
     return collection;
 }
 
diff --git a/akonadi/src/core/protocolhelper_p.h \
b/akonadi/src/core/protocolhelper_p.h index 3e8da16..7de21d9 100644
--- a/akonadi/src/core/protocolhelper_p.h
+++ b/akonadi/src/core/protocolhelper_p.h
@@ -26,7 +26,6 @@
 #include "item.h"
 #include "itemfetchscope.h"
 #include "sharedvaluepool_p.h"
-#include "attributeentity.h"
 #include "tag.h"
 
 #include <akonadi/private/imapparser_p.h>
@@ -84,22 +83,37 @@ public:
     static Protocol::CachePolicy cachePolicyToProtocol(const CachePolicy &policy);
 
     /**
-      Convert a ancestor chain from its protocol representation into an Entity \
object. +      Convert a ancestor chain from its protocol representation into an Item \
                object.
     */
-    static void parseAncestors(const QVector<Protocol::Ancestor> &ancestors, Entity \
*entity); +    static void parseAncestors(const QVector<Protocol::Ancestor> \
&ancestors, Item *item);  
     /**
-      Convert a ancestor chain from its protocol representation into an Entity \
object. +      Convert a ancestor chain from its protocol representation into a \
Collection object. +    */
+    static void parseAncestors(const QVector<Protocol::Ancestor> &ancestors, \
Collection *collection); +
+    /**
+      Convert a ancestor chain from its protocol representation into an Item object.
 
       This method allows to pass a @p valuePool which acts as cache, so ancestor \
paths for the  same @p parentCollection don't have to be parsed twice.
     */
     static void parseAncestorsCached(const QVector<Protocol::Ancestor> &ancestors,
-                                     Entity *entity,
+                                     Item *item,
                                      Collection::Id parentCollection,
                                      ProtocolHelperValuePool *valuePool = 0);
 
     /**
+      Convert a ancestor chain from its protocol representation into an Collection \
object. +
+      This method allows to pass a @p valuePool which acts as cache, so ancestor \
paths for the +      same @p parentCollection don't have to be parsed twice.
+    */
+    static void parseAncestorsCached(const QVector<Protocol::Ancestor> &ancestors,
+                                     Collection *collection,
+                                     Collection::Id parentCollection,
+                                     ProtocolHelperValuePool *valuePool = 0);
+    /**
       Parse a collection description.
       @param data The input data.
       @param requireParent Whether or not we require a parent as part of the data.
@@ -107,16 +121,18 @@ public:
     */
     static Collection parseCollection(const Protocol::FetchCollectionsResponse \
&data, bool requireParent = true);  
-    static void parseAttributes(const Protocol::Attributes &attributes, Entity \
                *entity);
-    static void parseAttributes(const Protocol::Attributes &attributes, \
AttributeEntity *entity); +    static void parseAttributes(const Protocol::Attributes \
&attributes, Item *item); +    static void parseAttributes(const Protocol::Attributes \
&attributes, Collection *collection); +    static void parseAttributes(const \
Protocol::Attributes &attributes, Tag *entity);  
     static CollectionStatistics parseCollectionStatistics(const \
Protocol::FetchCollectionStatsResponse &stats);  
     /**
       Convert attributes to their protocol representation.
     */
-    static Protocol::Attributes attributesToProtocol(const Entity &entity, bool ns = \
                false);
-    static Protocol::Attributes attributesToProtocol(const AttributeEntity &entity, \
bool ns = false); +    static Protocol::Attributes attributesToProtocol(const Item \
&item, bool ns = false); +    static Protocol::Attributes attributesToProtocol(const \
Collection &collection, bool ns = false); +    static Protocol::Attributes \
attributesToProtocol(const Tag &entity, bool ns = false);  
     /**
       Encodes part label and namespace.
diff --git a/akonadi/src/core/tag.cpp b/akonadi/src/core/tag.cpp
index 0b39721..b04ece5 100644
--- a/akonadi/src/core/tag.cpp
+++ b/akonadi/src/core/tag.cpp
@@ -18,7 +18,9 @@
 */
 
 #include "tag.h"
+#include "tag_p.h"
 #include "tagattribute.h"
+#include "entity_p.h"
 #include <QUuid>
 #include <QUrlQuery>
 
@@ -27,50 +29,34 @@ using namespace Akonadi;
 const char Akonadi::Tag::PLAIN[] = "PLAIN";
 const char Akonadi::Tag::GENERIC[] = "GENERIC";
 
-struct Akonadi::Tag::Private {
-    Private()
-        : id(-1)
-    {
-    }
-
-    ~Private()
-    {
-    }
+uint Akonadi::qHash(const Tag &tag)
+{
+    return ::qHash(tag.id());
+}
 
-    Id id;
-    QByteArray gid;
-    QByteArray remoteId;
-    QScopedPointer<Tag> parent;
-    QByteArray type;
-};
 
 Tag::Tag()
-    : AttributeEntity()
-    , d(new Private)
+    : d_ptr(new TagPrivate)
 {
 
 }
 
 Tag::Tag(Tag::Id id)
-    : AttributeEntity()
-    , d(new Private)
+    : d_ptr(new TagPrivate)
 {
-    d->id = id;
+    d_ptr->id = id;
 }
 
 Tag::Tag(const QString &name)
-    : AttributeEntity()
-    , d(new Private)
+    : d_ptr(new TagPrivate)
 {
-    d->gid = name.toUtf8();
-    d->type = PLAIN;
+    d_ptr->gid = name.toUtf8();
+    d_ptr->type = PLAIN;
 }
 
 Tag::Tag(const Tag &other)
-    : AttributeEntity()
-    , d(new Private)
+    : d_ptr(other.d_ptr)
 {
-    operator=(other);
 }
 
 Tag::~Tag()
@@ -79,32 +65,23 @@ Tag::~Tag()
 
 Tag &Tag::operator=(const Tag &other)
 {
-    d->id = other.d->id;
-    d->gid = other.d->gid;
-    d->remoteId = other.d->remoteId;
-    d->type = other.d->type;
-    if (other.d->parent) {
-        d->parent.reset(new Tag(*other.d->parent));
+    if (this != &other) {
+        d_ptr = other.d_ptr;
     }
-    AttributeEntity::operator=(other);
-    return *this;
-}
 
-AttributeEntity &Tag::operator=(const AttributeEntity &other)
-{
-    return operator=(*static_cast<const Tag *>(&other));
+    return *this;
 }
 
 bool Tag::operator==(const Tag &other) const
 {
     // Valid tags are equal if their IDs are equal
     if (isValid() && other.isValid()) {
-        return d->id == other.d->id;
+        return d_ptr->id == other.d_ptr->id;
     }
 
     // Invalid tags are equal if their GIDs are non empty but equal
-    if (!d->gid.isEmpty() || !other.d->gid.isEmpty()) {
-        return d->gid == other.d->gid;
+    if (!d_ptr->gid.isEmpty() || !other.d_ptr->gid.isEmpty()) {
+        return d_ptr->gid == other.d_ptr->gid;
     }
 
     // Invalid tags are equal if both are invalid
@@ -143,40 +120,87 @@ QUrl Tag::url() const
     return url;
 }
 
+void Tag::addAttribute(Attribute *attr)
+{
+    if (d_ptr->mAttributes.contains(attr->type())) {
+        Attribute *existing = d_ptr->mAttributes.value(attr->type());
+        if (attr == existing) {
+            return;
+        }
+        d_ptr->mAttributes.remove(attr->type());
+        delete existing;
+    }
+    d_ptr->mAttributes.insert(attr->type(), attr);
+    d_ptr->mDeletedAttributes.remove(attr->type());
+}
+
+void Tag::removeAttribute(const QByteArray &type)
+{
+    d_ptr->mDeletedAttributes.insert(type);
+    delete d_ptr->mAttributes.take(type);
+}
+
+bool Tag::hasAttribute(const QByteArray &type) const
+{
+    return d_ptr->mAttributes.contains(type);
+}
+
+Attribute::List Tag::attributes() const
+{
+    return d_ptr->mAttributes.values();
+}
+
+void Tag::clearAttributes()
+{
+    Q_FOREACH (Attribute *attr, d_ptr->mAttributes) {
+        d_ptr->mDeletedAttributes.insert(attr->type());
+        delete attr;
+    }
+    d_ptr->mAttributes.clear();
+}
+
+Attribute *Tag::attribute(const QByteArray &type) const
+{
+    if (d_ptr->mAttributes.contains(type)) {
+        return d_ptr->mAttributes.value(type);
+    }
+    return 0;
+}
+
 void Tag::setId(Tag::Id identifier)
 {
-    d->id = identifier;
+    d_ptr->id = identifier;
 }
 
 Tag::Id Tag::id() const
 {
-    return d->id;
+    return d_ptr->id;
 }
 
-void Tag::setGid(const QByteArray &gid) const
+void Tag::setGid(const QByteArray &gid)
 {
-    d->gid = gid;
+    d_ptr->gid = gid;
 }
 
 QByteArray Tag::gid() const
 {
-    return d->gid;
+    return d_ptr->gid;
 }
 
-void Tag::setRemoteId(const QByteArray &remoteId) const
+void Tag::setRemoteId(const QByteArray &remoteId)
 {
-    d->remoteId = remoteId;
+    d_ptr->remoteId = remoteId;
 }
 
 QByteArray Tag::remoteId() const
 {
-    return d->remoteId;
+    return d_ptr->remoteId;
 }
 
 void Tag::setName(const QString &name)
 {
     if (!name.isEmpty()) {
-        TagAttribute *const attr = \
attribute<TagAttribute>(AttributeEntity::AddIfMissing); +        TagAttribute *const \
attr = attribute<TagAttribute>(Tag::AddIfMissing);  attr->setDisplayName(name);
     }
 }
@@ -185,45 +209,40 @@ QString Tag::name() const
 {
     const TagAttribute *const attr = attribute<TagAttribute>();
     const QString displayName = attr ? attr->displayName() : QString();
-    return !displayName.isEmpty() ? displayName : QString::fromUtf8(d->gid);
+    return !displayName.isEmpty() ? displayName : QString::fromUtf8(d_ptr->gid);
 }
 
 void Tag::setParent(const Tag &parent)
 {
-    d->parent.reset(new Tag(parent));
+    d_ptr->parent.reset(new Tag(parent));
 }
 
 Tag Tag::parent() const
 {
-    if (!d->parent) {
+    if (!d_ptr->parent) {
         return Tag();
     }
-    return *d->parent;
+    return *d_ptr->parent;
 }
 
-void Tag::setType(const QByteArray &type) const
+void Tag::setType(const QByteArray &type)
 {
-    d->type = type;
+    d_ptr->type = type;
 }
 
 QByteArray Tag::type() const
 {
-    return d->type;
+    return d_ptr->type;
 }
 
 bool Tag::isValid() const
 {
-    return d->id >= 0;
+    return d_ptr->id >= 0;
 }
 
 bool Tag::isImmutable() const
 {
-    return (d->type.isEmpty() || d->type == PLAIN);
-}
-
-uint qHash(const Tag &tag)
-{
-    return qHash(tag.id());
+    return (d_ptr->type.isEmpty() || d_ptr->type == PLAIN);
 }
 
 QDebug &operator<<(QDebug &debug, const Tag &tag)
@@ -235,9 +254,10 @@ QDebug &operator<<(QDebug &debug, const Tag &tag)
 Tag Tag::genericTag(const QString &name)
 {
     Tag tag;
-    tag.d->type = GENERIC;
-    tag.d->gid = QUuid::createUuid().toByteArray().mid(1, 36);
+    tag.d_ptr->type = GENERIC;
+    tag.d_ptr->gid = QUuid::createUuid().toByteArray().mid(1, 36);
     tag.setName(name);
     return tag;
 }
 
+AKONADI_DEFINE_PRIVATE(Tag)
diff --git a/akonadi/src/core/tag.h b/akonadi/src/core/tag.h
index 5ae07ca..73393b8 100644
--- a/akonadi/src/core/tag.h
+++ b/akonadi/src/core/tag.h
@@ -21,27 +21,22 @@
 #define AKONADI_TAG_H
 
 #include "akonadicore_export.h"
-#include <QString>
-
-namespace Akonadi
-{
-class Tag;
-}
+#include "attribute.h"
 
-AKONADICORE_EXPORT uint qHash(const Akonadi::Tag &);
-
-#include "attributeentity.h"
+#include <QString>
 #include <QSharedPointer>
 #include <QUrl>
 #include <QDebug>
 
 namespace Akonadi
 {
+class TagModifyJob;
+class TagPrivate;
 
 /**
  * An Akonadi Tag.
  */
-class AKONADICORE_EXPORT Tag : public AttributeEntity
+class AKONADICORE_EXPORT Tag
 {
 public:
     typedef QVector<Tag> List;
@@ -80,13 +75,85 @@ public:
 
     Tag &operator=(const Tag &);
     //Avoid slicing
-    AttributeEntity &operator=(const AttributeEntity &) Q_DECL_OVERRIDE;
     bool operator==(const Tag &) const;
     bool operator!=(const Tag &) const;
 
     static Tag fromUrl(const QUrl &url);
 
     /**
+     * Adds an attribute to the entity.
+     *
+     * If an attribute of the same type name already exists, it is deleted and
+     * replaced with the new one.
+     *
+     * @param attribute The new attribute.
+     *
+     * @note The entity takes the ownership of the attribute.
+     */
+    void addAttribute(Attribute *attribute);
+
+    /**
+     * Removes and deletes the attribute of the given type @p name.
+     */
+    void removeAttribute(const QByteArray &name);
+
+    /**
+     * Returns @c true if the entity has an attribute of the given type @p name,
+     * false otherwise.
+     */
+    bool hasAttribute(const QByteArray &name) const;
+
+    /**
+     * Returns a list of all attributes of the entity.
+     */
+    Attribute::List attributes() const;
+
+    /**
+     * Removes and deletes all attributes of the entity.
+     */
+    void clearAttributes();
+
+    /**
+     * Returns the attribute of the given type @p name if available, 0 otherwise.
+     */
+    Attribute *attribute(const QByteArray &name) const;
+
+    /**
+     * Describes the options that can be passed to access attributes.
+     */
+    enum CreateOption {
+        AddIfMissing    ///< Creates the attribute if it is missing
+    };
+
+    /**
+     * Returns the attribute of the requested type.
+     * If the entity has no attribute of that type yet, a new one
+     * is created and added to the entity.
+     *
+     * @param option The create options.
+     */
+    template <typename T>
+    inline T *attribute(CreateOption option);
+
+    /**
+     * Returns the attribute of the requested type or 0 if it is not available.
+     */
+    template <typename T>
+    inline T *attribute() const;
+
+    /**
+     * Removes and deletes the attribute of the requested type.
+     */
+    template <typename T>
+    inline void removeAttribute();
+
+    /**
+     * Returns whether the entity has an attribute of the requested type.
+     */
+    template <typename T>
+    inline bool hasAttribute() const;
+
+    /**
      * Returns the url of the tag.
      */
     QUrl url() const;
@@ -101,13 +168,13 @@ public:
      */
     Id id() const;
 
-    void setGid(const QByteArray &gid) const;
+    void setGid(const QByteArray &gid);
     QByteArray gid() const;
 
-    void setRemoteId(const QByteArray &remoteId) const;
+    void setRemoteId(const QByteArray &remoteId);
     QByteArray remoteId() const;
 
-    void setType(const QByteArray &type) const;
+    void setType(const QByteArray &type);
     QByteArray type() const;
 
     void setName(const QString &name);
@@ -128,17 +195,81 @@ public:
      * Returns a GENERIC tag with the given name and a valid gid
      */
     static Tag genericTag(const QString &name);
+
 private:
-    class Private;
-    QSharedPointer<Private> d;
+    //@cond PRIVATE
+    friend class TagModifyJob;
+
+    QSharedDataPointer<TagPrivate> d_ptr;
+    const TagPrivate *d_func() const;
+    TagPrivate *d_func();
+    //@endcond
 };
 
+
+AKONADICORE_EXPORT uint qHash(const Akonadi::Tag &);
+
+
+template <typename T>
+inline T *Tag::attribute(CreateOption option)
+{
+    Q_UNUSED(option);
+
+    const T dummy;
+    if (hasAttribute(dummy.type())) {
+        T *attr = dynamic_cast<T *>(attribute(dummy.type()));
+        if (attr) {
+            return attr;
+        }
+        //reuse 5250
+        qWarning() << "Found attribute of unknown type" << dummy.type()
+                    << ". Did you forget to call \
AttributeFactory::registerAttribute()?"; +    }
+
+    T *attr = new T();
+    addAttribute(attr);
+    return attr;
+}
+
+template <typename T>
+inline T *Tag::attribute() const
+{
+    const T dummy;
+    if (hasAttribute(dummy.type())) {
+        T *attr = dynamic_cast<T *>(attribute(dummy.type()));
+        if (attr) {
+            return attr;
+        }
+        //Reuse 5250
+        qWarning() << "Found attribute of unknown type" << dummy.type()
+                    << ". Did you forget to call \
AttributeFactory::registerAttribute()?"; +    }
+
+    return 0;
+}
+
+template <typename T>
+inline void Tag::removeAttribute()
+{
+    const T dummy;
+    removeAttribute(dummy.type());
+}
+
+template <typename T>
+inline bool Tag::hasAttribute() const
+{
+    const T dummy;
+    return hasAttribute(dummy.type());
 }
 
+
+} // namespace Akonadi
+
 AKONADICORE_EXPORT QDebug &operator<<(QDebug &debug, const Akonadi::Tag &tag);
 
 Q_DECLARE_METATYPE(Akonadi::Tag)
 Q_DECLARE_METATYPE(Akonadi::Tag::List)
 Q_DECLARE_METATYPE(QSet<Akonadi::Tag>)
 Q_DECLARE_TYPEINFO(Akonadi::Tag, Q_MOVABLE_TYPE);
+
 #endif
diff --git a/akonadi/src/core/tag_p.h b/akonadi/src/core/tag_p.h
new file mode 100644
index 0000000..dac185c
--- /dev/null
+++ b/akonadi/src/core/tag_p.h
@@ -0,0 +1,69 @@
+/*
+    Copyright (c) 2014 Christian Mollekopf <mollekopf@kolabsys.com>
+    Copyright (c) 2015 Daniel Vrátil <dvratil@redhat.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    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 Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+#ifndef TAG_P_H
+#define TAG_P_H
+
+#include "tag.h"
+
+namespace Akonadi
+{
+
+class TagPrivate : public QSharedData
+{
+public:
+    TagPrivate()
+        : id(-1)
+    {
+    }
+
+    TagPrivate(const TagPrivate &other)
+        : QSharedData(other)
+    {
+        id = other.id;
+        gid = other.gid;
+        remoteId = other.remoteId;
+        parent.reset(new Tag(*other.parent));
+        type = other.type;
+        Q_FOREACH (Attribute *attr, other.mAttributes) {
+            mAttributes.insert(attr->type(), attr->clone());
+        }
+        mDeletedAttributes = other.mDeletedAttributes;
+    }
+
+    ~TagPrivate()
+    {
+        qDeleteAll(mAttributes);
+    }
+
+    // 4 bytes padding here (after QSharedData)
+
+    Tag::Id id;
+    QByteArray gid;
+    QByteArray remoteId;
+    QScopedPointer<Tag> parent;
+    QByteArray type;
+    QHash<QByteArray, Attribute *> mAttributes;
+    QSet<QByteArray> mDeletedAttributes;
+};
+
+}
+
+#endif
diff --git a/akonadi/src/core/tagsync.cpp b/akonadi/src/core/tagsync.cpp
index 5d66855..dafa863 100644
--- a/akonadi/src/core/tagsync.cpp
+++ b/akonadi/src/core/tagsync.cpp
@@ -141,8 +141,9 @@ void TagSync::diffTags()
     }
     Q_FOREACH (const Tag &tag, tagById) {
         //Removed remotely, unset rid
-        tag.setRemoteId(QByteArray(""));
-        TagModifyJob *modJob = new TagModifyJob(tag, this);
+        Tag copy(tag);
+        copy.setRemoteId(QByteArray(""));
+        TagModifyJob *modJob = new TagModifyJob(copy, this);
         connect(modJob, &KJob::result, this, &TagSync::onJobDone);
     }
     checkDone();
diff --git a/akonadi/src/core/trashsettings.cpp b/akonadi/src/core/trashsettings.cpp
index c536647..9946b6f 100644
--- a/akonadi/src/core/trashsettings.cpp
+++ b/akonadi/src/core/trashsettings.cpp
@@ -31,7 +31,7 @@ Akonadi::Collection TrashSettings::getTrashCollection(const QString \
&resource)  {
     KConfig config(QStringLiteral("akonaditrashrc"));
     KConfigGroup group(&config, resource);
-    const Akonadi::Entity::Id colId = group.readEntry<Akonadi::Entity::Id> \
("TrashCollection", -1); +    const Akonadi::Collection::Id colId = \
group.readEntry<Akonadi::Collection::Id> ("TrashCollection", -1);  qWarning() << \
resource << colId;  return Collection(colId);
 }
diff --git a/akonadi/src/widgets/etmviewstatesaver.cpp \
b/akonadi/src/widgets/etmviewstatesaver.cpp index 6449f70..1ea2729 100644
--- a/akonadi/src/widgets/etmviewstatesaver.cpp
+++ b/akonadi/src/widgets/etmviewstatesaver.cpp
@@ -38,7 +38,7 @@ QModelIndex ETMViewStateSaver::indexFromConfigString(const \
QAbstractItemModel *m  return QModelIndex();
     }
 
-    Entity::Id id = key.mid(1).toLongLong();
+    Item::Id id = key.mid(1).toLongLong();
     if (id < 0) {
         return QModelIndex();
     }
@@ -68,7 +68,7 @@ QString ETMViewStateSaver::indexToConfigString(const QModelIndex \
&index) const  if (c.isValid()) {
         return QStringLiteral("c%1").arg(c.id());
     }
-    Entity::Id id = index.data(EntityTreeModel::ItemIdRole).value<Entity::Id>();
+    Item::Id id = index.data(EntityTreeModel::ItemIdRole).value<Item::Id>();
     if (id >= 0) {
         return QStringLiteral("i%1").arg(id);
     }
@@ -79,7 +79,7 @@ void ETMViewStateSaver::selectCollections(const \
Akonadi::Collection::List &list)  {
     QStringList colStrings;
     colStrings.reserve(list.count());
-    foreach (const Collection &col, list) {
+    Q_FOREACH (const Collection &col, list) {
         colStrings << QStringLiteral("c%1").arg(col.id());
     }
     restoreSelection(colStrings);
@@ -89,7 +89,7 @@ void ETMViewStateSaver::selectCollections(const QList< \
Collection::Id > &list)  {
     QStringList colStrings;
     colStrings.reserve(list.count());
-    foreach (const Collection::Id &colId, list) {
+    Q_FOREACH (const Collection::Id &colId, list) {
         colStrings << QStringLiteral("c%1").arg(colId);
     }
     restoreSelection(colStrings);
@@ -99,7 +99,7 @@ void ETMViewStateSaver::selectItems(const Akonadi::Item::List \
&list)  {
     QStringList itemStrings;
     itemStrings.reserve(list.count());
-    foreach (const Item &item, list) {
+    Q_FOREACH (const Item &item, list) {
         itemStrings << QStringLiteral("i%1").arg(item.id());
     }
     restoreSelection(itemStrings);
@@ -109,7 +109,7 @@ void ETMViewStateSaver::selectItems(const QList< Item::Id > \
&list)  {
     QStringList itemStrings;
     itemStrings.reserve(list.count());
-    foreach (const Item::Id &itemId, list) {
+    Q_FOREACH (const Item::Id &itemId, list) {
         itemStrings << QStringLiteral("i%1").arg(itemId);
     }
     restoreSelection(itemStrings);
diff --git a/akonadi/src/xml/xmlreader.cpp b/akonadi/src/xml/xmlreader.cpp
index ca86d55..8ec060f 100644
--- a/akonadi/src/xml/xmlreader.cpp
+++ b/akonadi/src/xml/xmlreader.cpp
@@ -37,7 +37,8 @@ Attribute *XmlReader::elementToAttribute(const QDomElement &elem)
     return attr;
 }
 
-void XmlReader::readAttributes(const QDomElement &elem, Entity &entity)
+template<typename T>
+static void readAttributesImpl(const QDomElement &elem, T &entity)
 {
     if (elem.isNull()) {
         return;
@@ -45,13 +46,23 @@ void XmlReader::readAttributes(const QDomElement &elem, Entity \
&entity)  const QDomNodeList children = elem.childNodes();
     for (int i = 0; i < children.count(); ++i) {
         const QDomElement attrElem = children.at(i).toElement();
-        Attribute *attr = elementToAttribute(attrElem);
+        Attribute *attr = XmlReader::elementToAttribute(attrElem);
         if (attr) {
             entity.addAttribute(attr);
         }
     }
 }
 
+void XmlReader::readAttributes(const QDomElement &elem, Item &item)
+{
+    readAttributesImpl(elem, item);
+}
+
+void XmlReader::readAttributes(const QDomElement &elem, Collection &collection)
+{
+    readAttributesImpl(elem, collection);
+}
+
 Collection XmlReader::elementToCollection(const QDomElement &elem)
 {
     if (elem.isNull() || elem.tagName() != Format::Tag::collection()) {
diff --git a/akonadi/src/xml/xmlreader.h b/akonadi/src/xml/xmlreader.h
index 465a598..9b8c5e4 100644
--- a/akonadi/src/xml/xmlreader.h
+++ b/akonadi/src/xml/xmlreader.h
@@ -46,9 +46,15 @@ AKONADI_XML_EXPORT Attribute *elementToAttribute(const QDomElement \
&elem);  
 /**
   Reads all attributes that are immediate children of @p elem and adds them
-  to @p entity.
+  to @p item.
 */
-AKONADI_XML_EXPORT void readAttributes(const QDomElement &elem, Entity &entity);
+AKONADI_XML_EXPORT void readAttributes(const QDomElement &elem, Item &item);
+
+/**
+  Reads all attributes that are immediate children of @p elem and adds them
+  to @p collection.
+*/
+AKONADI_XML_EXPORT void readAttributes(const QDomElement &elem, Collection \
&collection);  
 /**
   Converts a collection element.
diff --git a/akonadi/src/xml/xmlwriter.cpp b/akonadi/src/xml/xmlwriter.cpp
index 9419ded..1eb7840 100644
--- a/akonadi/src/xml/xmlwriter.cpp
+++ b/akonadi/src/xml/xmlwriter.cpp
@@ -41,18 +41,30 @@ QDomElement XmlWriter::attributeToElement(Attribute *attr, \
QDomDocument &documen  return top;
 }
 
-void XmlWriter::writeAttributes(const Entity &entity, QDomElement &parentElem)
+template<typename T>
+static void writeAttributesImpl(const T &entity, QDomElement &parentElem)
 {
     if (parentElem.isNull()) {
         return;
     }
 
     QDomDocument doc = parentElem.ownerDocument();
-    foreach (Attribute *attr, entity.attributes()) {
-        parentElem.appendChild(attributeToElement(attr, doc));
+    Q_FOREACH (Attribute *attr, entity.attributes()) {
+        parentElem.appendChild(XmlWriter::attributeToElement(attr, doc));
     }
 }
 
+void XmlWriter::writeAttributes(const Item &item, QDomElement &parentElem)
+{
+    writeAttributesImpl(item, parentElem);
+}
+
+void XmlWriter::writeAttributes(const Collection &collection, QDomElement \
&parentElem) +{
+    writeAttributesImpl(collection, parentElem);
+}
+
+
 QDomElement XmlWriter::collectionToElement(const Akonadi::Collection &collection, \
QDomDocument &document)  {
     if (document.isNull()) {
@@ -99,7 +111,7 @@ QDomElement XmlWriter::itemToElement(const Akonadi::Item &item, \
QDomDocument &do  
     writeAttributes(item, top);
 
-    foreach (const Item::Flag &flag, item.flags()) {
+    Q_FOREACH (const Item::Flag &flag, item.flags()) {
         QDomElement flagElem = document.createElement(Format::Tag::flag());
         QDomText flagText = document.createTextNode(QString::fromUtf8(flag));
         flagElem.appendChild(flagText);
diff --git a/akonadi/src/xml/xmlwriter.h b/akonadi/src/xml/xmlwriter.h
index 41faa1a..99dcccc 100644
--- a/akonadi/src/xml/xmlwriter.h
+++ b/akonadi/src/xml/xmlwriter.h
@@ -30,7 +30,6 @@ namespace Akonadi
 
 class Attribute;
 class Collection;
-class Entity;
 class Item;
 
 /**
@@ -47,7 +46,12 @@ AKONADI_XML_EXPORT QDomElement attributeToElement(Attribute *attr, \
QDomDocument  /**
   Serializes all attributes of the given Akonadi object into the given parent \
                element.
 */
-AKONADI_XML_EXPORT void writeAttributes(const Entity &entity, QDomElement \
&parentElem); +AKONADI_XML_EXPORT void writeAttributes(const Item &entity, \
QDomElement &parentElem); +
+/**
+  Serializes all attributes of the given Akonadi object into the given parent \
element. +*/
+AKONADI_XML_EXPORT void writeAttributes(const Collection &entity, QDomElement \
&parentElem);  
 /**
   Creates a collection element for the given document, not yet attached to the DOM \
tree. @@ -67,7 +71,7 @@ AKONADI_XML_EXPORT QDomElement itemToElement(const Item \
&item, QDomDocument &doc  /**
   Serializes the given item into a DOM element and attaches it to the given item.
 */
-AKONADI_XML_EXPORT QDomElement writeItem(const Akonadi::Item &item, QDomElement \
&parentElem); +AKONADI_XML_EXPORT QDomElement writeItem(const Item &item, QDomElement \
&parentElem);  }
 
 }


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic