diff --git a/src/core/attributestorage.cpp b/src/core/attributestorage.cpp --- a/src/core/attributestorage.cpp +++ b/src/core/attributestorage.cpp @@ -97,11 +97,17 @@ mModifiedAttributes.clear(); } -Attribute *AttributeStorage::attribute(const QByteArray &type) const +const Attribute *AttributeStorage::attribute(const QByteArray &type) const { return mAttributes.value(type); } +Attribute *AttributeStorage::attribute(const QByteArray &type) +{ + markAttributeModified(type); + return mAttributes.value(type); +} + void AttributeStorage::markAttributeModified(const QByteArray &type) { mDeletedAttributes.remove(type); diff --git a/src/core/attributestorage_p.h b/src/core/attributestorage_p.h --- a/src/core/attributestorage_p.h +++ b/src/core/attributestorage_p.h @@ -48,7 +48,8 @@ bool hasAttribute(const QByteArray &type) const; Attribute::List attributes() const; void clearAttributes(); - Attribute *attribute(const QByteArray &type) const; + const Attribute *attribute(const QByteArray &type) const; + Attribute *attribute(const QByteArray &type); void markAttributeModified(const QByteArray &type); void resetChangeLog(); diff --git a/src/core/collection.h b/src/core/collection.h --- a/src/core/collection.h +++ b/src/core/collection.h @@ -253,6 +253,10 @@ /** * Returns a list of all attributes of the collection. + * + * @warning Do not modify the attributes returned from this method, + * the change will not be reflected when updating the Collection + * through CollectionModifyJob. */ Q_REQUIRED_RESULT Attribute::List attributes() const; @@ -264,30 +268,32 @@ /** * Returns the attribute of the given type @p name if available, 0 otherwise. */ - Attribute *attribute(const QByteArray &name) const; + Attribute *attribute(const QByteArray &name); + const 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 + AddIfMissing, ///< Creates the attribute if it is missing + DontCreate ///< Default value }; /** * 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. + * If the collection has no attribute of that type yet, passing AddIfMissing + * as an argument will create and add it to the entity * * @param option The create options. */ template - inline T *attribute(CreateOption option); + inline T *attribute(CreateOption option = DontCreate); /** * Returns the attribute of the requested type or 0 if it is not available. */ template - inline T *attribute() const; + inline const T *attribute() const; /** * Removes and deletes the attribute of the requested type. @@ -562,40 +568,30 @@ template inline T *Akonadi::Collection::attribute(Collection::CreateOption option) { - Q_UNUSED(option); - const QByteArray type = T().type(); if (hasAttribute(type)) { - T *attr = dynamic_cast(attribute(type)); - if (attr) { - markAttributeModified(type); + if (T *attr = dynamic_cast(attribute(type))) { return attr; } - //Reuse 5250 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } else if (option == AddIfMissing) { + T *attr = new T(); + addAttribute(attr); + return attr; } - T *attr = new T(); - addAttribute(attr); - return attr; + return nullptr; } template -inline T *Akonadi::Collection::attribute() const +inline const T *Akonadi::Collection::attribute() const { const QByteArray type = T().type(); if (hasAttribute(type)) { - T *attr = dynamic_cast(attribute(type)); - if (attr) { - // FIXME: This method returns a non-const pointer, so callers may still modify the - // attribute. Unfortunately, just making this function return a const pointer and - // creating a non-const overload does not work, as many users of this function abuse the - // non-const pointer and modify the attribute even on a const object. - const_cast(this)->markAttributeModified(type); + if (const T *attr = dynamic_cast(attribute(type))) { return attr; } - //reuse 5250 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?"; } @@ -606,15 +602,13 @@ template inline void Akonadi::Collection::removeAttribute() { - const T dummy; - removeAttribute(dummy.type()); + removeAttribute(T().type()); } template inline bool Akonadi::Collection::hasAttribute() const { - const T dummy; - return hasAttribute(dummy.type()); + return hasAttribute(T().type()); } } // namespace Akonadi diff --git a/src/core/collection.cpp b/src/core/collection.cpp --- a/src/core/collection.cpp +++ b/src/core/collection.cpp @@ -189,7 +189,13 @@ return d_ptr->mAttributeStorage.clearAttributes(); } -Attribute *Collection::attribute(const QByteArray &type) const +Attribute *Collection::attribute(const QByteArray &type) +{ + markAttributeModified(type); + return d_ptr->mAttributeStorage.attribute(type); +} + +const Attribute *Collection::attribute(const QByteArray &type) const { return d_ptr->mAttributeStorage.attribute(type); } @@ -236,18 +242,16 @@ Collection::Rights Collection::rights() const { - CollectionRightsAttribute *attr = attribute(); - if (attr) { + if (const auto attr = attribute()) { return attr->rights(); } else { return AllRights; } } void Collection::setRights(Rights rights) { - CollectionRightsAttribute *attr = attribute(AddIfMissing); - attr->setRights(rights); + attribute(AddIfMissing)->setRights(rights); } QStringList Collection::contentMimeTypes() const diff --git a/src/core/collectionsync.cpp b/src/core/collectionsync.cpp --- a/src/core/collectionsync.cpp +++ b/src/core/collectionsync.cpp @@ -573,7 +573,7 @@ Q_FOREACH (Attribute *remoteAttr, upd.attributes()) { if (ignoreAttributeChanges(remote, remoteAttr->type()) && local.hasAttribute(remoteAttr->type())) { //We don't want to overwrite the attribute changes with the defaults provided by the resource. - Attribute *localAttr = local.attribute(remoteAttr->type()); + const Attribute *localAttr = local.attribute(remoteAttr->type()); upd.removeAttribute(localAttr->type()); upd.addAttribute(localAttr->clone()); } diff --git a/src/core/item.h b/src/core/item.h --- a/src/core/item.h +++ b/src/core/item.h @@ -293,6 +293,10 @@ /** * Returns a list of all attributes of the item. + * + * @warning Do not modify the attributes returned from this method, + * the change will not be reflected when updating the Item through + * ItemModifyJob. */ Attribute::List attributes() const; @@ -304,13 +308,15 @@ /** * Returns the attribute of the given type @p name if available, 0 otherwise. */ - Attribute *attribute(const QByteArray &name) const; + Attribute *attribute(const QByteArray &name); + const 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 + AddIfMissing, ///< Creates the attribute if it is missing + DontCreate ///< Do not create the attribute if it is missing (default) }; /** @@ -321,13 +327,13 @@ * @param option The create options. */ template - inline T *attribute(CreateOption option); + inline T *attribute(CreateOption option = DontCreate); /** * Returns the attribute of the requested type or 0 if it is not available. */ template - inline T *attribute() const; + inline const T *attribute() const; /** * Removes and deletes the attribute of the requested type. @@ -787,36 +793,31 @@ template inline T *Item::attribute(Item::CreateOption option) { - Q_UNUSED(option); - - const T dummy; - if (hasAttribute(dummy.type())) { - T *attr = dynamic_cast(attribute(dummy.type())); - if (attr) { + const QByteArray type = T().type(); + if (hasAttribute(type)) { + if (T *attr = dynamic_cast(attribute(type))) { return attr; } - //Reuse 5250 - qWarning() << "Found attribute of unknown type" << dummy.type() + qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } else if (option == AddIfMissing) { + T *attr = new T(); + addAttribute(attr); + return attr; } - T *attr = new T(); - addAttribute(attr); - return attr; + return nullptr; } template -inline T *Item::attribute() const +inline const T *Item::attribute() const { - const T dummy; - if (hasAttribute(dummy.type())) { - T *attr = dynamic_cast(attribute(dummy.type())); - if (attr) { - + const QByteArray type = T().type(); + if (hasAttribute(type)) { + if (const T *attr = dynamic_cast(attribute(type))) { return attr; } - //reuse 5250 - qWarning() << "Found attribute of unknown type" << dummy.type() + qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?"; } @@ -826,15 +827,13 @@ template inline void Item::removeAttribute() { - const T dummy; - removeAttribute(dummy.type()); + removeAttribute(T().type()); } template inline bool Item::hasAttribute() const { - const T dummy; - return hasAttribute(dummy.type()); + return hasAttribute(T().type()); } template diff --git a/src/core/item.cpp b/src/core/item.cpp --- a/src/core/item.cpp +++ b/src/core/item.cpp @@ -252,13 +252,14 @@ ItemChangeLog::instance()->attributeStorage(d_ptr).clearAttributes(); } -Attribute *Item::attribute(const QByteArray &type) const +Attribute *Item::attribute(const QByteArray &type) { - // FIXME: Createa a truly const and non-const overloads of this method - // so only non-const access marks the attribute as modified - auto &storage = ItemChangeLog::instance()->attributeStorage(d_ptr); - storage.markAttributeModified(type); - return attribute(type); + return ItemChangeLog::instance()->attributeStorage(d_ptr).attribute(type); +} + +const Attribute *Item::attribute(const QByteArray &type) const +{ + return ItemChangeLog::instance()->attributeStorage(d_ptr).attribute(type); } Collection &Item::parentCollection() diff --git a/src/core/itemchangelog.cpp b/src/core/itemchangelog.cpp --- a/src/core/itemchangelog.cpp +++ b/src/core/itemchangelog.cpp @@ -57,7 +57,12 @@ return m_deletedTags[const_cast(priv)]; } -AttributeStorage &ItemChangeLog::attributeStorage(const ItemPrivate *priv) +AttributeStorage &ItemChangeLog::attributeStorage(ItemPrivate *priv) +{ + return m_attributeStorage[priv]; +} + +const AttributeStorage &ItemChangeLog::attributeStorage(const ItemPrivate *priv) { return m_attributeStorage[const_cast(priv)]; } diff --git a/src/core/itemchangelog_p.h b/src/core/itemchangelog_p.h --- a/src/core/itemchangelog_p.h +++ b/src/core/itemchangelog_p.h @@ -41,7 +41,8 @@ Tag::List &addedTags(const ItemPrivate *priv); Tag::List &deletedTags(const ItemPrivate *priv); - AttributeStorage &attributeStorage(const ItemPrivate *priv); + const AttributeStorage &attributeStorage(const ItemPrivate *priv); + AttributeStorage &attributeStorage(ItemPrivate *priv); void removeItem(const ItemPrivate *priv); void clearItemChangelog(const ItemPrivate *priv); diff --git a/src/core/models/entitytreemodel.cpp b/src/core/models/entitytreemodel.cpp --- a/src/core/models/entitytreemodel.cpp +++ b/src/core/models/entitytreemodel.cpp @@ -317,7 +317,7 @@ return d->m_pendingCutCollections.contains(node->id); case Qt::BackgroundRole: { if (collection.hasAttribute()) { - EntityDisplayAttribute *eda = collection.attribute(); + const EntityDisplayAttribute *eda = collection.attribute(); QColor color = eda->backgroundColor(); if (color.isValid()) { return color; @@ -368,7 +368,7 @@ return d->m_pendingCutItems.contains(node->id); case Qt::BackgroundRole: { if (item.hasAttribute()) { - EntityDisplayAttribute *eda = item.attribute(); + const EntityDisplayAttribute *eda = item.attribute(); const QColor color = eda->backgroundColor(); if (color.isValid()) { return color; diff --git a/src/core/models/statisticsproxymodel.cpp b/src/core/models/statisticsproxymodel.cpp --- a/src/core/models/statisticsproxymodel.cpp +++ b/src/core/models/statisticsproxymodel.cpp @@ -103,7 +103,7 @@ .arg(i18n("Unread Messages")).arg(collection.statistics().unreadCount()); if (collection.hasAttribute()) { - CollectionQuotaAttribute *quota = collection.attribute(); + const CollectionQuotaAttribute *quota = collection.attribute(); if (quota->currentValue() > -1 && quota->maximumValue() > 0) { qreal percentage = (100.0 * quota->currentValue()) / quota->maximumValue(); diff --git a/src/core/models/tagmodel.cpp b/src/core/models/tagmodel.cpp --- a/src/core/models/tagmodel.cpp +++ b/src/core/models/tagmodel.cpp @@ -109,8 +109,7 @@ case TagRole: return QVariant::fromValue(tag); case Qt::DecorationRole: { - TagAttribute *attr = tag.attribute(); - if (attr) { + if (const TagAttribute *attr = tag.attribute()) { return QIcon::fromTheme(attr->iconName()); } else { return QVariant(); diff --git a/src/core/tag.h b/src/core/tag.h --- a/src/core/tag.h +++ b/src/core/tag.h @@ -116,13 +116,15 @@ /** * Returns the attribute of the given type @p name if available, 0 otherwise. */ - Attribute *attribute(const QByteArray &name) const; + const Attribute *attribute(const QByteArray &name) const; + Attribute *attribute(const QByteArray &name); /** * Describes the options that can be passed to access attributes. */ enum CreateOption { - AddIfMissing ///< Creates the attribute if it is missing + AddIfMissing, ///< Creates the attribute if it is missing + DontCreate ///< Does not create an attribute if it is missing (default) }; /** @@ -133,13 +135,13 @@ * @param option The create options. */ template - inline T *attribute(CreateOption option); + inline T *attribute(CreateOption option = DontCreate); /** * Returns the attribute of the requested type or 0 if it is not available. */ template - inline T *attribute() const; + inline const T *attribute() const; /** * Removes and deletes the attribute of the requested type. @@ -197,7 +199,7 @@ static Tag genericTag(const QString &name); private: - bool checkAttribute(Attribute *attr, const QByteArray &type) const; + bool checkAttribute(const Attribute *attr, const QByteArray &type) const; void markAttributeModified(const QByteArray &type); //@cond PRIVATE @@ -214,32 +216,28 @@ template inline T *Tag::attribute(CreateOption option) { - Q_UNUSED(option); - const QByteArray type = T().type(); if (hasAttribute(type)) { T *attr = dynamic_cast(attribute(type)); if (checkAttribute(attr, type)) { - markAttributeModified(type); return attr; } + } else if (option == AddIfMissing) { + T *attr = new T(); + addAttribute(attr); + return attr; } - T *attr = new T(); - addAttribute(attr); - return attr; + return nullptr; } template -inline T *Tag::attribute() const +inline const T *Tag::attribute() const { const QByteArray type = T().type(); if (hasAttribute(type)) { - T *attr = dynamic_cast(attribute(type)); + const T *attr = dynamic_cast(attribute(type)); if (checkAttribute(attr, type)) { - // FIXME: Make this a truly const method so that callers may not modify - // the attribute returned from here. - const_cast(this)->markAttributeModified(type); return attr; } } diff --git a/src/core/tag.cpp b/src/core/tag.cpp --- a/src/core/tag.cpp +++ b/src/core/tag.cpp @@ -145,11 +145,17 @@ d_ptr->mAttributeStorage.clearAttributes(); } -Attribute *Tag::attribute(const QByteArray &type) const +const Attribute *Tag::attribute(const QByteArray &type) const { return d_ptr->mAttributeStorage.attribute(type); } +Attribute *Tag::attribute(const QByteArray &type) +{ + markAttributeModified(type); + return d_ptr->mAttributeStorage.attribute(type); +} + void Tag::setId(Tag::Id identifier) { d_ptr->id = identifier; @@ -244,7 +250,7 @@ return tag; } -bool Tag::checkAttribute(Attribute *attr, const QByteArray &type) const +bool Tag::checkAttribute(const Attribute *attr, const QByteArray &type) const { if (attr) { return true; diff --git a/src/widgets/collectionmaintenancepage.cpp b/src/widgets/collectionmaintenancepage.cpp --- a/src/widgets/collectionmaintenancepage.cpp +++ b/src/widgets/collectionmaintenancepage.cpp @@ -129,7 +129,7 @@ init(col); if (col.isValid()) { d->updateLabel(col.statistics().count(), col.statistics().unreadCount(), col.statistics().size()); - Akonadi::IndexPolicyAttribute *attr = col.attribute(); + const Akonadi::IndexPolicyAttribute *attr = col.attribute(); const bool indexingWasEnabled(!attr || attr->indexingEnabled()); d->ui.enableIndexingChkBox->setChecked(indexingWasEnabled); if (indexingWasEnabled) { diff --git a/src/xml/autotests/collectiontest.cpp b/src/xml/autotests/collectiontest.cpp --- a/src/xml/autotests/collectiontest.cpp +++ b/src/xml/autotests/collectiontest.cpp @@ -76,7 +76,7 @@ verifyCollection(colist, 2, QStringLiteral("c112"), QStringLiteral("Akonadi"), mimeType); QVERIFY(colist.at(0).hasAttribute()); - EntityDisplayAttribute *attr = colist.at(0).attribute(); + const EntityDisplayAttribute *attr = colist.at(0).attribute(); QCOMPARE(attr->displayName(), QStringLiteral("Posteingang")); }