File indexing completed on 2024-11-10 04:40:38
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"