• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepimlibs API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • sources
  • kde-4.14
  • kdepimlibs
  • akonadi
item.cpp
1 /*
2  Copyright (c) 2006 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "item.h"
21 #include "item_p.h"
22 #include "itemserializer_p.h"
23 #include "protocol_p.h"
24 
25 #include <kurl.h>
26 #include <kdebug.h>
27 
28 #include <QtCore/QStringList>
29 #include <QtCore/QReadWriteLock>
30 
31 #include <algorithm>
32 #include <map>
33 #include <utility>
34 
35 using namespace Akonadi;
36 using namespace boost;
37 
38 namespace {
39 
40 struct nodelete {
41  template <typename T>
42  void operator()(T *)
43  {
44  }
45 };
46 
47 struct ByTypeId {
48  typedef bool result_type;
49  bool operator()(const boost::shared_ptr<PayloadBase> &lhs, const boost::shared_ptr<PayloadBase> &rhs) const
50  {
51  return strcmp(lhs->typeName(), rhs->typeName()) < 0 ;
52  }
53 };
54 
55 } // anon namespace
56 
57 typedef QHash< QString, std::map< boost::shared_ptr<PayloadBase>, std::pair<int, int>, ByTypeId > > LegacyMap;
58 Q_GLOBAL_STATIC(LegacyMap, typeInfoToMetaTypeIdMap)
59 Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, legacyMapLock, (QReadWriteLock::Recursive))
60 
61 void Item::addToLegacyMappingImpl(const QString &mimeType, int spid, int mtid, std::auto_ptr<PayloadBase> p)
62 {
63  if (!p.get()) {
64  return;
65  }
66  const boost::shared_ptr<PayloadBase> sp(p);
67  const QWriteLocker locker(legacyMapLock());
68  std::pair<int, int> &item = (*typeInfoToMetaTypeIdMap())[mimeType][sp];
69  item.first = spid;
70  item.second = mtid;
71 }
72 
73 namespace {
74 class MyReadLocker {
75 public:
76  explicit MyReadLocker(QReadWriteLock *rwl)
77  : rwl(rwl)
78  , locked(false)
79  {
80  if (rwl) {
81  rwl->lockForRead();
82  }
83  locked = true;
84  }
85 
86  ~MyReadLocker()
87  {
88  if (rwl && locked) {
89  rwl->unlock();
90  }
91  }
92 
93  template <typename T>
94  shared_ptr<T> makeUnlockingPointer(T *t)
95  {
96  if (t) {
97  // the bind() doesn't throw, so if shared_ptr
98  // construction line below, or anything else after it,
99  // throws, we're unlocked. Mark us as such:
100  locked = false;
101  const shared_ptr<T> result(t, bind(&QReadWriteLock::unlock, rwl));
102  // from now on, the shared_ptr is responsible for unlocking
103  return result;
104  } else {
105  return shared_ptr<T>();
106  }
107  }
108 private:
109  QReadWriteLock *const rwl;
110  bool locked;
111 };
112 }
113 
114 static shared_ptr<const std::pair<int, int> > lookupLegacyMapping(const QString &mimeType, PayloadBase *p)
115 {
116  MyReadLocker locker(legacyMapLock());
117  const LegacyMap::const_iterator hit = typeInfoToMetaTypeIdMap()->constFind(mimeType);
118  if (hit == typeInfoToMetaTypeIdMap()->constEnd()) {
119  return shared_ptr<const std::pair<int, int> >();
120  }
121  const boost::shared_ptr<PayloadBase> sp(p, nodelete());
122  const LegacyMap::mapped_type::const_iterator it = hit->find(sp);
123  if (it == hit->end()) {
124  return shared_ptr<const std::pair<int, int> >();
125  }
126 
127  return locker.makeUnlockingPointer(&it->second);
128 }
129 
130 // Change to something != RFC822 as soon as the server supports it
131 const char *Item::FullPayload = "RFC822";
132 
133 Item::Item()
134  : Entity(new ItemPrivate)
135 {
136 }
137 
138 Item::Item(Id id)
139  : Entity(new ItemPrivate(id))
140 {
141 }
142 
143 Item::Item(const QString &mimeType)
144  : Entity(new ItemPrivate)
145 {
146  d_func()->mMimeType = mimeType;
147 }
148 
149 Item::Item(const Item &other)
150  : Entity(other)
151 {
152 }
153 
154 Item::~Item()
155 {
156 }
157 
158 Item::Flags Item::flags() const
159 {
160  return d_func()->mFlags;
161 }
162 
163 void Item::setFlag(const QByteArray &name)
164 {
165  Q_D(Item);
166  d->mFlags.insert(name);
167  if (!d->mFlagsOverwritten) {
168  if (d->mDeletedFlags.contains(name)) {
169  d->mDeletedFlags.remove(name);
170  } else {
171  d->mAddedFlags.insert(name);
172  }
173  }
174 }
175 
176 void Item::clearFlag(const QByteArray &name)
177 {
178  Q_D(Item);
179  d->mFlags.remove(name);
180  if (!d->mFlagsOverwritten) {
181  if (d->mAddedFlags.contains(name)) {
182  d->mAddedFlags.remove(name);
183  } else {
184  d->mDeletedFlags.insert(name);
185  }
186  }
187 }
188 
189 void Item::setFlags(const Flags &flags)
190 {
191  Q_D(Item);
192  d->mFlags = flags;
193  d->mFlagsOverwritten = true;
194 }
195 
196 void Item::clearFlags()
197 {
198  Q_D(Item);
199  d->mFlags.clear();
200  d->mFlagsOverwritten = true;
201 }
202 
203 QDateTime Item::modificationTime() const
204 {
205  return d_func()->mModificationTime;
206 }
207 
208 void Item::setModificationTime(const QDateTime &datetime)
209 {
210  d_func()->mModificationTime = datetime;
211 }
212 
213 bool Item::hasFlag(const QByteArray &name) const
214 {
215  return d_func()->mFlags.contains(name);
216 }
217 
218 void Item::setTags(const Tag::List &list)
219 {
220  Q_D(Item);
221  d->mTags = list;
222  d->mTagsOverwritten = true;
223 }
224 
225 void Item::setTag(const Tag &tag)
226 {
227  Q_D(Item);
228  d->mTags << tag;
229  if (!d->mTagsOverwritten) {
230  if (d->mDeletedTags.contains(tag)) {
231  d->mDeletedTags.removeOne(tag);
232  } else {
233  d->mAddedTags << tag ;
234  }
235  }
236 }
237 
238 void Item::clearTags()
239 {
240  Q_D(Item);
241  d->mTags.clear();
242  d->mTagsOverwritten = true;
243 }
244 
245 void Item::clearTag(const Tag &tag)
246 {
247  Q_D(Item);
248  d->mTags.removeOne(tag);
249  if (!d->mTagsOverwritten) {
250  if (d->mAddedTags.contains(tag)) {
251  d->mAddedTags.removeOne(tag);
252  } else {
253  d->mDeletedTags << tag;
254  }
255  }
256 }
257 
258 bool Item::hasTag(const Tag &tag) const
259 {
260  Q_D(const Item);
261  return d->mTags.contains(tag);
262 }
263 
264 Tag::List Item::tags() const
265 {
266  Q_D(const Item);
267  return d->mTags;
268 }
269 
270 QSet<QByteArray> Item::loadedPayloadParts() const
271 {
272  return ItemSerializer::parts(*this);
273 }
274 
275 QByteArray Item::payloadData() const
276 {
277  int version = 0;
278  QByteArray data;
279  ItemSerializer::serialize(*this, FullPayload, data, version);
280  return data;
281 }
282 
283 void Item::setPayloadFromData(const QByteArray &data)
284 {
285  ItemSerializer::deserialize(*this, FullPayload, data, 0, false);
286 }
287 
288 void Item::clearPayload()
289 {
290  d_func()->mClearPayload = true;
291 }
292 
293 int Item::revision() const
294 {
295  return d_func()->mRevision;
296 }
297 
298 void Item::setRevision(int rev)
299 {
300  d_func()->mRevision = rev;
301 }
302 
303 Entity::Id Item::storageCollectionId() const
304 {
305  return d_func()->mCollectionId;
306 }
307 
308 void Item::setStorageCollectionId(Entity::Id collectionId)
309 {
310  d_func()->mCollectionId = collectionId;
311 }
312 
313 QString Item::mimeType() const
314 {
315  return d_func()->mMimeType;
316 }
317 
318 void Item::setSize(qint64 size)
319 {
320  Q_D(Item);
321  d->mSize = size;
322  d->mSizeChanged = true;
323 }
324 
325 qint64 Item::size() const
326 {
327  return d_func()->mSize;
328 }
329 
330 void Item::setMimeType(const QString &mimeType)
331 {
332  d_func()->mMimeType = mimeType;
333 }
334 
335 void Item::setGid(const QString &id)
336 {
337  d_func()->mGid = id;
338 }
339 
340 QString Item::gid() const
341 {
342  return d_func()->mGid;
343 }
344 
345 void Item::setVirtualReferences(const Collection::List &collections)
346 {
347  d_func()->mVirtualReferences = collections;
348 }
349 
350 Collection::List Item::virtualReferences() const
351 {
352  return d_func()->mVirtualReferences;
353 }
354 
355 bool Item::hasPayload() const
356 {
357  return d_func()->hasMetaTypeId(-1);
358 }
359 
360 KUrl Item::url(UrlType type) const
361 {
362  KUrl url;
363  url.setProtocol(QString::fromLatin1("akonadi"));
364  url.addQueryItem(QLatin1String("item"), QString::number(id()));
365 
366  if (type == UrlWithMimeType) {
367  url.addQueryItem(QLatin1String("type"), mimeType());
368  }
369 
370  return url;
371 }
372 
373 Item Item::fromUrl(const KUrl &url)
374 {
375  if (url.protocol() != QLatin1String("akonadi")) {
376  return Item();
377  }
378 
379  const QString itemStr = url.queryItem(QLatin1String("item"));
380  bool ok = false;
381  Item::Id itemId = itemStr.toLongLong(&ok);
382  if (!ok) {
383  return Item();
384  }
385 
386  return Item(itemId);
387 }
388 
389 namespace {
390 class Dummy
391 {
392 };
393 }
394 
395 Q_GLOBAL_STATIC(Payload<Dummy>, dummyPayload)
396 
397 PayloadBase *Item::payloadBase() const
398 {
399  Q_D(const Item);
400  d->tryEnsureLegacyPayload();
401  if (d->mLegacyPayload) {
402  return d->mLegacyPayload.get();
403  } else {
404  return dummyPayload();
405  }
406 }
407 
408 void ItemPrivate::tryEnsureLegacyPayload() const
409 {
410  if (!mLegacyPayload) {
411  for (PayloadContainer::const_iterator it = mPayloads.begin(), end = mPayloads.end() ; it != end ; ++it) {
412  if (lookupLegacyMapping(mMimeType, it->payload.get())) {
413  mLegacyPayload = it->payload; // clones
414  }
415  }
416  }
417 }
418 
419 PayloadBase *Item::payloadBaseV2(int spid, int mtid) const
420 {
421  return d_func()->payloadBaseImpl(spid, mtid);
422 }
423 
424 namespace {
425 class ConversionGuard
426 {
427  const bool old;
428  bool &b;
429 public:
430  explicit ConversionGuard(bool &b)
431  : old(b)
432  , b(b)
433  {
434  b = true;
435  }
436  ~ConversionGuard() {
437  b = old;
438  }
439 };
440 }
441 
442 bool Item::ensureMetaTypeId(int mtid) const
443 {
444  Q_D(const Item);
445  // 0. Nothing there - nothing to convert from, either
446  if (d->mPayloads.empty()) {
447  return false;
448  }
449 
450  // 1. Look whether we already have one:
451  if (d->hasMetaTypeId(mtid)) {
452  return true;
453  }
454 
455  // recursion detection (shouldn't trigger, but does if the
456  // serialiser plugins are acting funky):
457  if (d->mConversionInProgress) {
458  return false;
459  }
460 
461  // 2. Try to create one by conversion from a different representation:
462  try {
463  const ConversionGuard guard(d->mConversionInProgress);
464  Item converted = ItemSerializer::convert(*this, mtid);
465  return d->movePayloadFrom(converted.d_func(), mtid);
466  } catch (const std::exception &e) {
467  kDebug() << "conversion threw:" << e.what();
468  return false;
469  } catch (...) {
470  kDebug() << "conversion threw something not derived from std::exception: fix the program!";
471  return false;
472  }
473 }
474 
475 static QString format_type(int spid, int mtid)
476 {
477  return QString::fromLatin1("sp(%1)<%2>")
478  .arg(spid).arg(QLatin1String(QMetaType::typeName(mtid)));
479 }
480 
481 static QString format_types(const PayloadContainer &c)
482 {
483  QStringList result;
484  for (PayloadContainer::const_iterator it = c.begin(), end = c.end() ; it != end ; ++it) {
485  result.push_back(format_type(it->sharedPointerId, it->metaTypeId));
486  }
487  return result.join(QLatin1String(", "));
488 }
489 
490 #if 0
491 QString Item::payloadExceptionText(int spid, int mtid) const
492 {
493  Q_D(const Item);
494  if (d->mPayloads.empty()) {
495  return QLatin1String("No payload set");
496  } else {
497  return QString::fromLatin1("Wrong payload type (requested: %1; present: %2")
498  .arg(format_type(spid, mtid), format_types(d->mPayloads));
499  }
500 }
501 #else
502 void Item::throwPayloadException(int spid, int mtid) const
503 {
504  Q_D(const Item);
505  if (d->mPayloads.empty()) {
506  throw PayloadException("No payload set");
507  } else {
508  throw PayloadException(QString::fromLatin1("Wrong payload type (requested: %1; present: %2")
509  .arg(format_type(spid, mtid), format_types(d->mPayloads)));
510  }
511 }
512 #endif
513 
514 void Item::setPayloadBase(PayloadBase *p)
515 {
516  d_func()->setLegacyPayloadBaseImpl(std::auto_ptr<PayloadBase>(p));
517 }
518 
519 void ItemPrivate::setLegacyPayloadBaseImpl(std::auto_ptr<PayloadBase> p)
520 {
521  if (const shared_ptr<const std::pair<int, int> > pair = lookupLegacyMapping(mMimeType, p.get())) {
522  std::auto_ptr<PayloadBase> clone;
523  if (p.get()) {
524  clone.reset(p->clone());
525  }
526  setPayloadBaseImpl(pair->first, pair->second, p, false);
527  mLegacyPayload.reset(clone.release());
528  } else {
529  mPayloads.clear();
530  mLegacyPayload.reset(p.release());
531  }
532 }
533 
534 void Item::setPayloadBaseV2(int spid, int mtid, std::auto_ptr<PayloadBase> p)
535 {
536  d_func()->setPayloadBaseImpl(spid, mtid, p, false);
537 }
538 
539 void Item::addPayloadBaseVariant(int spid, int mtid, std::auto_ptr<PayloadBase> p) const
540 {
541  d_func()->setPayloadBaseImpl(spid, mtid, p, true);
542 }
543 
544 QSet<QByteArray> Item::cachedPayloadParts() const
545 {
546  Q_D(const Item);
547  return d->mCachedPayloadParts;
548 }
549 
550 void Item::setCachedPayloadParts(const QSet< QByteArray > &cachedParts)
551 {
552  Q_D(Item);
553  d->mCachedPayloadParts = cachedParts;
554 }
555 
556 QSet<QByteArray> Item::availablePayloadParts() const
557 {
558  return ItemSerializer::availableParts(*this);
559 }
560 
561 QVector<int> Item::availablePayloadMetaTypeIds() const
562 {
563  QVector<int> result;
564  Q_D(const Item);
565  result.reserve(d->mPayloads.size());
566  // Stable Insertion Sort - N is typically _very_ low (1 or 2).
567  for (PayloadContainer::const_iterator it = d->mPayloads.begin(), end = d->mPayloads.end() ; it != end ; ++it) {
568  result.insert(std::upper_bound(result.begin(), result.end(), it->metaTypeId), it->metaTypeId);
569  }
570  return result;
571 }
572 
573 void Item::apply(const Item &other)
574 {
575  if (mimeType() != other.mimeType() || id() != other.id()) {
576  kDebug() << "mimeType() = " << mimeType() << "; other.mimeType() = " << other.mimeType();
577  kDebug() << "id() = " << id() << "; other.id() = " << other.id();
578  Q_ASSERT_X(false, "Item::apply", "mimetype or id missmatch");
579  }
580 
581  setRemoteId(other.remoteId());
582  setRevision(other.revision());
583  setRemoteRevision(other.remoteRevision());
584  setFlags(other.flags());
585  setTags(other.tags());
586  setModificationTime(other.modificationTime());
587  setSize(other.size());
588  setParentCollection(other.parentCollection());
589  setStorageCollectionId(other.storageCollectionId());
590 
591  QList<QByteArray> attrs;
592  foreach (Attribute *attribute, other.attributes()) {
593  addAttribute(attribute->clone());
594  attrs.append(attribute->type());
595  }
596 
597  QMutableHashIterator<QByteArray, Attribute *> it(d_ptr->mAttributes);
598  while (it.hasNext()) {
599  it.next();
600  if (!attrs.contains(it.key())) {
601  delete it.value();
602  it.remove();
603  }
604  }
605 
606  ItemSerializer::apply(*this, other);
607  d_func()->resetChangeLog();
608 }
609 
610 AKONADI_DEFINE_PRIVATE(Item)
QReadWriteLock
QReadWriteLock::lockForRead
void lockForRead()
QVector::begin
iterator begin()
QList::push_back
void push_back(const T &value)
QByteArray
QMutableHashIterator
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition: entity.h:65
QVector::insert
void insert(int i, const T &value)
QStringList::join
QString join(const QString &separator) const
Akonadi::Attribute
Provides interface for custom attributes for Entity.
Definition: attribute.h:138
QReadWriteLock::unlock
void unlock()
QString::number
QString number(int n, int base)
QList::append
void append(const T &value)
Akonadi::ItemSerializer::convert
static Item convert(const Item &item, int metaTypeId)
Tries to convert the payload in item into type with metatype-id metaTypeId.
Definition: itemserializer.cpp:191
Akonadi::ItemSerializer::parts
static QSet< QByteArray > parts(const Item &item)
Returns a list of parts available in the item payload.
Definition: itemserializer.cpp:164
Akonadi::ItemSerializer::apply
static void apply(Item &item, const Item &other)
Throws ItemSerializerException on failure.
Definition: itemserializer.cpp:136
QHash
QSet< QByteArray >
QString
QList
QWriteLocker
Akonadi::ItemSerializer::deserialize
static void deserialize(Item &item, const QByteArray &label, const QByteArray &data, int version, bool external)
throws ItemSerializerException on failure
Definition: itemserializer.cpp:84
QStringList
QVector::reserve
void reserve(int size)
Akonadi::Entity
The base class for Item and Collection.
Definition: entity.h:59
QHash::const_iterator
Akonadi::ItemPrivate
Definition: item_p.h:274
QMetaType::typeName
const char * typeName(int type)
QVector< int >
QLatin1String
Akonadi::Tag
An Akonadi Tag.
Definition: tag.h:43
QString::fromLatin1
QString fromLatin1(const char *str, int size)
Akonadi::ItemSerializer::serialize
static void serialize(const Item &item, const QByteArray &label, QByteArray &data, int &version)
throws ItemSerializerException on failure
Definition: itemserializer.cpp:116
Akonadi::Attribute::clone
virtual Attribute * clone() const =0
Creates a copy of this attribute.
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QVector::end
iterator end()
Akonadi::Attribute::type
virtual QByteArray type() const =0
Returns the type of the attribute.
QString::toLongLong
qlonglong toLongLong(bool *ok, int base) const
Akonadi::ItemSerializer::availableParts
static QSet< QByteArray > availableParts(const Item &item)
Returns a list of parts available remotely in the item payload.
Definition: itemserializer.cpp:172
QDateTime
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:38:03 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal