File indexing completed on 2024-05-26 05:14:09

0001 /*
0002     SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "collection.h"
0008 #include "collection_p.h"
0009 
0010 #include "attributefactory.h"
0011 #include "cachepolicy.h"
0012 #include "collectionrightsattribute_p.h"
0013 #include "collectionstatistics.h"
0014 #include "entitydisplayattribute.h"
0015 
0016 #include <QHash>
0017 #include <QString>
0018 #include <QStringList>
0019 
0020 #include <QUrl>
0021 #include <QUrlQuery>
0022 
0023 using namespace Akonadi;
0024 
0025 Q_GLOBAL_STATIC(Akonadi::Collection, s_defaultParentCollection) // NOLINT(readability-redundant-member-init)
0026 
0027 size_t Akonadi::qHash(const Akonadi::Collection &collection, size_t seed) noexcept
0028 {
0029     return ::qHash(collection.id(), seed);
0030 }
0031 
0032 /**
0033  * Helper method for assignment operator and copy constructor.
0034  */
0035 static void assignCollectionPrivate(QSharedDataPointer<CollectionPrivate> &one, const QSharedDataPointer<CollectionPrivate> &other)
0036 {
0037     // We can't simply do one = other here, we have to use a temp.
0038     // Otherwise ProtocolHelperTest::testParentCollectionAfterCollectionParsing()
0039     // will break.
0040     //
0041     // The reason are assignments like
0042     //   col = col.parentCollection()
0043     //
0044     // Here, parentCollection() actually returns a reference to a pointer owned
0045     // by col. So when col (or rather, it's private class) is deleted, the pointer
0046     // to the parent collection and therefore the reference becomes invalid.
0047     //
0048     // With a single-line assignment here, the parent collection would be deleted
0049     // before it is assigned, and therefore the resulting object would point to
0050     // uninitialized memory.
0051     const QSharedDataPointer<CollectionPrivate> temp = other; // NOLINT(performance-unnecessary-copy-initialization): see above
0052     one = temp;
0053 }
0054 
0055 class CollectionRoot : public Collection
0056 {
0057 public:
0058     CollectionRoot()
0059         : Collection(0)
0060     {
0061         setContentMimeTypes({Collection::mimeType()});
0062 
0063         // The root collection is read-only for the users
0064         setRights(Collection::ReadOnly);
0065     }
0066 };
0067 
0068 Q_GLOBAL_STATIC(CollectionRoot, s_root) // NOLINT(readability-redundant-member-init)
0069 
0070 Collection::Collection()
0071     : d_ptr(new CollectionPrivate)
0072 {
0073     static int lastId = -1;
0074     d_ptr->mId = lastId--;
0075 }
0076 
0077 Collection::Collection(Id id)
0078     : d_ptr(new CollectionPrivate(id))
0079 {
0080 }
0081 
0082 Collection::Collection(const Collection &other)
0083 {
0084     assignCollectionPrivate(d_ptr, other.d_ptr);
0085 }
0086 
0087 Collection::Collection(Collection &&) noexcept = default;
0088 
0089 Collection::~Collection() = default;
0090 
0091 void Collection::setId(Collection::Id identifier)
0092 {
0093     d_ptr->mId = identifier;
0094 }
0095 
0096 Collection::Id Collection::id() const
0097 {
0098     return d_ptr->mId;
0099 }
0100 
0101 void Collection::setRemoteId(const QString &id)
0102 {
0103     d_ptr->mRemoteId = id;
0104 }
0105 
0106 QString Collection::remoteId() const
0107 {
0108     return d_ptr->mRemoteId;
0109 }
0110 
0111 void Collection::setRemoteRevision(const QString &revision)
0112 {
0113     d_ptr->mRemoteRevision = revision;
0114 }
0115 
0116 QString Collection::remoteRevision() const
0117 {
0118     return d_ptr->mRemoteRevision;
0119 }
0120 
0121 bool Collection::isValid() const
0122 {
0123     return (d_ptr->mId >= 0);
0124 }
0125 
0126 bool Collection::operator==(const Collection &other) const
0127 {
0128     // Invalid collections are the same, no matter what their internal ID is
0129     return (!isValid() && !other.isValid()) || (d_ptr->mId == other.d_ptr->mId);
0130 }
0131 
0132 bool Akonadi::Collection::operator!=(const Collection &other) const
0133 {
0134     return (isValid() || other.isValid()) && (d_ptr->mId != other.d_ptr->mId);
0135 }
0136 
0137 Collection &Collection ::operator=(const Collection &other)
0138 {
0139     if (this != &other) {
0140         assignCollectionPrivate(d_ptr, other.d_ptr);
0141     }
0142 
0143     return *this;
0144 }
0145 
0146 bool Akonadi::Collection::operator<(const Collection &other) const
0147 {
0148     return d_ptr->mId < other.d_ptr->mId;
0149 }
0150 
0151 void Collection::addAttribute(Attribute *attr)
0152 {
0153     d_ptr->mAttributeStorage.addAttribute(attr);
0154 }
0155 
0156 void Collection::removeAttribute(const QByteArray &type)
0157 {
0158     d_ptr->mAttributeStorage.removeAttribute(type);
0159 }
0160 
0161 bool Collection::hasAttribute(const QByteArray &type) const
0162 {
0163     return d_ptr->mAttributeStorage.hasAttribute(type);
0164 }
0165 
0166 Attribute::List Collection::attributes() const
0167 {
0168     return d_ptr->mAttributeStorage.attributes();
0169 }
0170 
0171 void Akonadi::Collection::clearAttributes()
0172 {
0173     d_ptr->mAttributeStorage.clearAttributes();
0174 }
0175 
0176 Attribute *Collection::attribute(const QByteArray &type)
0177 {
0178     markAttributeModified(type);
0179     return d_ptr->mAttributeStorage.attribute(type);
0180 }
0181 
0182 const Attribute *Collection::attribute(const QByteArray &type) const
0183 {
0184     return d_ptr->mAttributeStorage.attribute(type);
0185 }
0186 
0187 Collection &Collection::parentCollection()
0188 {
0189     if (!d_ptr->mParent) {
0190         d_ptr->mParent.reset(new Collection());
0191     }
0192     return *d_ptr->mParent;
0193 }
0194 
0195 Collection Collection::parentCollection() const
0196 {
0197     if (!d_ptr->mParent) {
0198         return *(s_defaultParentCollection);
0199     } else {
0200         return *d_ptr->mParent;
0201     }
0202 }
0203 
0204 void Collection::setParentCollection(const Collection &parent)
0205 {
0206     d_ptr->mParent.reset(new Collection(parent));
0207 }
0208 
0209 QString Collection::name() const
0210 {
0211     return d_ptr->name;
0212 }
0213 
0214 QString Collection::displayName() const
0215 {
0216     const auto *const attr = attribute<EntityDisplayAttribute>();
0217     const QString displayName = attr ? attr->displayName() : QString();
0218     return !displayName.isEmpty() ? displayName : d_ptr->name;
0219 }
0220 
0221 void Collection::setName(const QString &name)
0222 {
0223     d_ptr->name = name;
0224 }
0225 
0226 Collection::Rights Collection::rights() const
0227 {
0228     if (const auto *const attr = attribute<CollectionRightsAttribute>()) {
0229         return attr->rights();
0230     } else {
0231         return AllRights;
0232     }
0233 }
0234 
0235 void Collection::setRights(Rights rights)
0236 {
0237     attribute<CollectionRightsAttribute>(AddIfMissing)->setRights(rights);
0238 }
0239 
0240 QStringList Collection::contentMimeTypes() const
0241 {
0242     return d_ptr->contentTypes;
0243 }
0244 
0245 void Collection::setContentMimeTypes(const QStringList &types)
0246 {
0247     if (d_ptr->contentTypes != types) {
0248         d_ptr->contentTypes = types;
0249         d_ptr->contentTypesChanged = true;
0250     }
0251 }
0252 
0253 QUrl Collection::url(UrlType type) const
0254 {
0255     QUrlQuery query;
0256     query.addQueryItem(QStringLiteral("collection"), QString::number(id()));
0257     if (type == UrlWithName) {
0258         query.addQueryItem(QStringLiteral("name"), name());
0259     }
0260 
0261     QUrl url;
0262     url.setScheme(QStringLiteral("akonadi"));
0263     url.setQuery(query);
0264     return url;
0265 }
0266 
0267 Collection Collection::fromUrl(const QUrl &url)
0268 {
0269     if (url.scheme() != QLatin1StringView("akonadi")) {
0270         return Collection();
0271     }
0272 
0273     const QString colStr = QUrlQuery(url).queryItemValue(QStringLiteral("collection"));
0274     bool ok = false;
0275     Collection::Id colId = colStr.toLongLong(&ok);
0276     if (!ok) {
0277         return Collection();
0278     }
0279 
0280     if (colId == 0) {
0281         return Collection::root();
0282     }
0283 
0284     return Collection(colId);
0285 }
0286 
0287 Collection Collection::root()
0288 {
0289     return *s_root;
0290 }
0291 
0292 QString Collection::mimeType()
0293 {
0294     return QStringLiteral("inode/directory");
0295 }
0296 
0297 QString Akonadi::Collection::virtualMimeType()
0298 {
0299     return QStringLiteral("application/x-vnd.akonadi.collection.virtual");
0300 }
0301 
0302 QString Collection::resource() const
0303 {
0304     return d_ptr->resource;
0305 }
0306 
0307 void Collection::setResource(const QString &resource)
0308 {
0309     d_ptr->resource = resource;
0310 }
0311 
0312 QDebug operator<<(QDebug d, const Akonadi::Collection &collection)
0313 {
0314     return d << "Collection ID:" << collection.id() << "   remote ID:" << collection.remoteId() << '\n'
0315              << "   name:" << collection.name() << '\n'
0316              << "   url:" << collection.url() << '\n'
0317              << "   parent:" << collection.parentCollection().id() << collection.parentCollection().remoteId() << '\n'
0318              << "   resource:" << collection.resource() << '\n'
0319              << "   rights:" << collection.rights() << '\n'
0320              << "   contents mime type:" << collection.contentMimeTypes() << '\n'
0321              << "   isVirtual:" << collection.isVirtual() << '\n'
0322              << "   " << collection.cachePolicy() << '\n'
0323              << "   " << collection.statistics();
0324 }
0325 
0326 CollectionStatistics Collection::statistics() const
0327 {
0328     return d_ptr->statistics;
0329 }
0330 
0331 void Collection::setStatistics(const CollectionStatistics &statistics)
0332 {
0333     d_ptr->statistics = statistics;
0334 }
0335 
0336 CachePolicy Collection::cachePolicy() const
0337 {
0338     return d_ptr->cachePolicy;
0339 }
0340 
0341 void Collection::setCachePolicy(const CachePolicy &cachePolicy)
0342 {
0343     d_ptr->cachePolicy = cachePolicy;
0344     d_ptr->cachePolicyChanged = true;
0345 }
0346 
0347 bool Collection::isVirtual() const
0348 {
0349     return d_ptr->isVirtual;
0350 }
0351 
0352 void Akonadi::Collection::setVirtual(bool isVirtual)
0353 {
0354     d_ptr->isVirtual = isVirtual;
0355 }
0356 
0357 void Collection::setEnabled(bool enabled)
0358 {
0359     d_ptr->enabledChanged = true;
0360     d_ptr->enabled = enabled;
0361 }
0362 
0363 bool Collection::enabled() const
0364 {
0365     return d_ptr->enabled;
0366 }
0367 
0368 void Collection::setLocalListPreference(Collection::ListPurpose purpose, Collection::ListPreference preference)
0369 {
0370     switch (purpose) {
0371     case ListDisplay:
0372         d_ptr->displayPreference = preference;
0373         break;
0374     case ListSync:
0375         d_ptr->syncPreference = preference;
0376         break;
0377     case ListIndex:
0378         d_ptr->indexPreference = preference;
0379         break;
0380     }
0381     d_ptr->listPreferenceChanged = true;
0382 }
0383 
0384 Collection::ListPreference Collection::localListPreference(Collection::ListPurpose purpose) const
0385 {
0386     switch (purpose) {
0387     case ListDisplay:
0388         return d_ptr->displayPreference;
0389     case ListSync:
0390         return d_ptr->syncPreference;
0391     case ListIndex:
0392         return d_ptr->indexPreference;
0393     }
0394     return ListDefault;
0395 }
0396 
0397 bool Collection::shouldList(Collection::ListPurpose purpose) const
0398 {
0399     if (localListPreference(purpose) == ListDefault) {
0400         return enabled();
0401     }
0402     return (localListPreference(purpose) == ListEnabled);
0403 }
0404 
0405 void Collection::setShouldList(ListPurpose purpose, bool list)
0406 {
0407     if (localListPreference(purpose) == ListDefault) {
0408         setEnabled(list);
0409     } else {
0410         setLocalListPreference(purpose, list ? ListEnabled : ListDisabled);
0411     }
0412 }
0413 
0414 void Collection::setKeepLocalChanges(const QSet<QByteArray> &parts)
0415 {
0416     d_ptr->keepLocalChanges = parts;
0417 }
0418 
0419 QSet<QByteArray> Collection::keepLocalChanges() const
0420 {
0421     return d_ptr->keepLocalChanges;
0422 }
0423 
0424 void Collection::markAttributeModified(const QByteArray &type)
0425 {
0426     d_ptr->mAttributeStorage.markAttributeModified(type);
0427 }
0428 
0429 #include "moc_collection.cpp"