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

akonadi

  • sources
  • kde-4.12
  • 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 struct ByTypeId {
46  typedef bool result_type;
47  bool operator()( const boost::shared_ptr<PayloadBase> & lhs, const boost::shared_ptr<PayloadBase> & rhs ) const {
48  return strcmp( lhs->typeName(), rhs->typeName() ) < 0 ;
49  }
50 };
51 
52 } // anon namespace
53 
54 typedef QHash< QString, std::map< boost::shared_ptr<PayloadBase>, std::pair<int,int>, ByTypeId > > LegacyMap;
55 Q_GLOBAL_STATIC( LegacyMap, typeInfoToMetaTypeIdMap )
56 Q_GLOBAL_STATIC_WITH_ARGS( QReadWriteLock, legacyMapLock, ( QReadWriteLock::Recursive ) )
57 
58 void Item::addToLegacyMappingImpl( const QString & mimeType, int spid, int mtid, std::auto_ptr<PayloadBase> p ) {
59  if ( !p.get() ) {
60  return;
61  }
62  const boost::shared_ptr<PayloadBase> sp( p );
63  const QWriteLocker locker( legacyMapLock() );
64  std::pair<int,int> & item = ( *typeInfoToMetaTypeIdMap() )[mimeType][sp];
65  item.first = spid;
66  item.second = mtid;
67 }
68 
69 namespace {
70  class MyReadLocker {
71  public:
72  explicit MyReadLocker( QReadWriteLock * rwl ) : rwl( rwl ), locked( false ) { if ( rwl ) rwl->lockForRead(); locked = true; }
73  ~MyReadLocker() { if ( rwl && locked ) rwl->unlock(); }
74 
75  template <typename T>
76  shared_ptr<T> makeUnlockingPointer( T * t ) {
77  if ( t ) {
78  // the bind() doesn't throw, so if shared_ptr
79  // construction line below, or anything else after it,
80  // throws, we're unlocked. Mark us as such:
81  locked = false;
82  const shared_ptr<T> result( t, bind( &QReadWriteLock::unlock, rwl ) );
83  // from now on, the shared_ptr is responsible for unlocking
84  return result;
85  } else {
86  return shared_ptr<T>();
87  }
88  }
89  private:
90  QReadWriteLock * const rwl;
91  bool locked;
92  };
93 }
94 
95 static shared_ptr<const std::pair<int,int> > lookupLegacyMapping( const QString & mimeType, PayloadBase * p ) {
96  MyReadLocker locker( legacyMapLock() );
97  const LegacyMap::const_iterator hit = typeInfoToMetaTypeIdMap()->constFind( mimeType );
98  if ( hit == typeInfoToMetaTypeIdMap()->constEnd() ) {
99  return shared_ptr<const std::pair<int,int> >();
100  }
101  const boost::shared_ptr<PayloadBase> sp( p, nodelete() );
102  const LegacyMap::mapped_type::const_iterator it = hit->find( sp );
103  if ( it == hit->end() ) {
104  return shared_ptr<const std::pair<int,int> >();
105  }
106 
107  return locker.makeUnlockingPointer( &it->second );
108 }
109 
110 // Change to something != RFC822 as soon as the server supports it
111 const char* Item::FullPayload = "RFC822";
112 
113 Item::Item()
114  : Entity( new ItemPrivate )
115 {
116 }
117 
118 Item::Item( Id id )
119  : Entity( new ItemPrivate( id ) )
120 {
121 }
122 
123 Item::Item( const QString & mimeType )
124  : Entity( new ItemPrivate )
125 {
126  d_func()->mMimeType = mimeType;
127 }
128 
129 Item::Item( const Item &other )
130  : Entity( other )
131 {
132 }
133 
134 Item::~Item()
135 {
136 }
137 
138 Item::Flags Item::flags() const
139 {
140  return d_func()->mFlags;
141 }
142 
143 void Item::setFlag( const QByteArray & name )
144 {
145  Q_D( Item );
146  d->mFlags.insert( name );
147  if ( !d->mFlagsOverwritten ) {
148  if ( d->mDeletedFlags.contains( name ) ) {
149  d->mDeletedFlags.remove( name );
150  } else {
151  d->mAddedFlags.insert( name );
152  }
153  }
154 }
155 
156 void Item::clearFlag( const QByteArray & name )
157 {
158  Q_D( Item );
159  d->mFlags.remove( name );
160  if ( !d->mFlagsOverwritten ) {
161  if ( d->mAddedFlags.contains( name ) ) {
162  d->mAddedFlags.remove( name );
163  } else {
164  d->mDeletedFlags.insert( name );
165  }
166  }
167 }
168 
169 void Item::setFlags( const Flags &flags )
170 {
171  Q_D( Item );
172  d->mFlags = flags;
173  d->mFlagsOverwritten = true;
174 }
175 
176 void Item::clearFlags()
177 {
178  Q_D( Item );
179  d->mFlags.clear();
180  d->mFlagsOverwritten = true;
181 }
182 
183 QDateTime Item::modificationTime() const
184 {
185  return d_func()->mModificationTime;
186 }
187 
188 void Item::setModificationTime( const QDateTime &datetime )
189 {
190  d_func()->mModificationTime = datetime;
191 }
192 
193 bool Item::hasFlag( const QByteArray & name ) const
194 {
195  return d_func()->mFlags.contains( name );
196 }
197 
198 QSet<QByteArray> Item::loadedPayloadParts() const
199 {
200  return ItemSerializer::parts( *this );
201 }
202 
203 QByteArray Item::payloadData() const
204 {
205  int version = 0;
206  QByteArray data;
207  ItemSerializer::serialize( *this, FullPayload, data, version );
208  return data;
209 }
210 
211 void Item::setPayloadFromData( const QByteArray &data )
212 {
213  ItemSerializer::deserialize( *this, FullPayload, data, 0, false );
214 }
215 
216 void Item::clearPayload()
217 {
218  d_func()->mClearPayload = true;
219 }
220 
221 int Item::revision() const
222 {
223  return d_func()->mRevision;
224 }
225 
226 void Item::setRevision( int rev )
227 {
228  d_func()->mRevision = rev;
229 }
230 
231 Entity::Id Item::storageCollectionId() const
232 {
233  return d_func()->mCollectionId;
234 }
235 
236 void Item::setStorageCollectionId( Entity::Id collectionId )
237 {
238  d_func()->mCollectionId = collectionId;
239 }
240 
241 QString Item::mimeType() const
242 {
243  return d_func()->mMimeType;
244 }
245 
246 void Item::setSize( qint64 size )
247 {
248  Q_D( Item );
249  d->mSize = size;
250  d->mSizeChanged = true;
251 }
252 
253 qint64 Item::size() const
254 {
255  return d_func()->mSize;
256 }
257 
258 void Item::setMimeType( const QString & mimeType )
259 {
260  d_func()->mMimeType = mimeType;
261 }
262 
263 void Item::setGid( const QString &id )
264 {
265  d_func()->mGid = id;
266 }
267 
268 QString Item::gid() const
269 {
270  return d_func()->mGid;
271 }
272 
273 bool Item::hasPayload() const
274 {
275  return d_func()->hasMetaTypeId( -1 );
276 }
277 
278 KUrl Item::url( UrlType type ) const
279 {
280  KUrl url;
281  url.setProtocol( QString::fromLatin1( "akonadi" ) );
282  url.addQueryItem( QLatin1String( "item" ), QString::number( id() ) );
283 
284  if ( type == UrlWithMimeType ) {
285  url.addQueryItem( QLatin1String( "type" ), mimeType() );
286  }
287 
288  return url;
289 }
290 
291 Item Item::fromUrl( const KUrl &url )
292 {
293  if ( url.protocol() != QLatin1String( "akonadi" ) ) {
294  return Item();
295  }
296 
297  const QString itemStr = url.queryItem( QLatin1String( "item" ) );
298  bool ok = false;
299  Item::Id itemId = itemStr.toLongLong( &ok );
300  if ( !ok ) {
301  return Item();
302  }
303 
304  return Item( itemId );
305 }
306 
307 namespace {
308  class Dummy {};
309 }
310 
311 Q_GLOBAL_STATIC( Payload<Dummy>, dummyPayload )
312 
313 PayloadBase* Item::payloadBase() const
314 {
315  Q_D( const Item );
316  d->tryEnsureLegacyPayload();
317  if ( d->mLegacyPayload ) {
318  return d->mLegacyPayload.get();
319  } else {
320  return dummyPayload();
321  }
322 }
323 
324 void ItemPrivate::tryEnsureLegacyPayload() const
325 {
326  if ( !mLegacyPayload ) {
327  for ( PayloadContainer::const_iterator it = mPayloads.begin(), end = mPayloads.end() ; it != end ; ++it ) {
328  if ( lookupLegacyMapping( mMimeType, it->payload.get() ) ) {
329  mLegacyPayload = it->payload; // clones
330  }
331  }
332  }
333 }
334 
335 PayloadBase* Item::payloadBaseV2( int spid, int mtid ) const
336 {
337  return d_func()->payloadBaseImpl( spid, mtid );
338 }
339 
340 namespace {
341  class ConversionGuard {
342  const bool old;
343  bool & b;
344  public:
345  explicit ConversionGuard( bool & b )
346  : old( b ), b( b )
347  {
348  b = true;
349  }
350  ~ConversionGuard() {
351  b = old;
352  }
353  };
354 }
355 
356 bool Item::ensureMetaTypeId( int mtid ) const
357 {
358  Q_D( const Item );
359  // 0. Nothing there - nothing to convert from, either
360  if ( d->mPayloads.empty() ) {
361  return false;
362  }
363 
364  // 1. Look whether we already have one:
365  if ( d->hasMetaTypeId( mtid ) ) {
366  return true;
367  }
368 
369  // recursion detection (shouldn't trigger, but does if the
370  // serialiser plugins are acting funky):
371  if ( d->mConversionInProgress ) {
372  return false;
373  }
374 
375  // 2. Try to create one by conversion from a different representation:
376  try {
377  const ConversionGuard guard( d->mConversionInProgress );
378  Item converted = ItemSerializer::convert( *this, mtid );
379  return d->movePayloadFrom( converted.d_func(), mtid );
380  } catch ( const std::exception & e ) {
381  kDebug() << "conversion threw:" << e.what();
382  return false;
383  } catch ( ... ) {
384  kDebug() << "conversion threw something not derived from std::exception: fix the program!";
385  return false;
386  }
387 }
388 
389 static QString format_type( int spid, int mtid ) {
390  return QString::fromLatin1( "sp(%1)<%2>" )
391  .arg( spid ).arg( QLatin1String( QMetaType::typeName( mtid ) ) );
392 }
393 
394 static QString format_types( const PayloadContainer & c ) {
395  QStringList result;
396  for ( PayloadContainer::const_iterator it = c.begin(), end = c.end() ; it != end ; ++it ) {
397  result.push_back( format_type( it->sharedPointerId, it->metaTypeId ) );
398  }
399  return result.join( QLatin1String( ", " ) );
400 }
401 
402 #if 0
403 QString Item::payloadExceptionText( int spid, int mtid ) const
404 {
405  Q_D( const Item );
406  if ( d->mPayloads.empty() ) {
407  return QLatin1String( "No payload set" );
408  } else {
409  return QString::fromLatin1( "Wrong payload type (requested: %1; present: %2" )
410  .arg( format_type( spid, mtid ), format_types( d->mPayloads ) );
411  }
412 }
413 #else
414 void Item::throwPayloadException( int spid, int mtid ) const
415 {
416  Q_D( const Item );
417  if ( d->mPayloads.empty() ) {
418  throw PayloadException( "No payload set" );
419  } else {
420  throw PayloadException( QString::fromLatin1( "Wrong payload type (requested: %1; present: %2" )
421  .arg( format_type( spid, mtid ), format_types( d->mPayloads ) ) );
422  }
423 }
424 #endif
425 
426 void Item::setPayloadBase( PayloadBase* p )
427 {
428  d_func()->setLegacyPayloadBaseImpl( std::auto_ptr<PayloadBase>( p ) );
429 }
430 
431 void ItemPrivate::setLegacyPayloadBaseImpl( std::auto_ptr<PayloadBase> p )
432 {
433  if ( const shared_ptr<const std::pair<int,int> > pair = lookupLegacyMapping( mMimeType, p.get() ) ) {
434  std::auto_ptr<PayloadBase> clone;
435  if ( p.get() ) {
436  clone.reset( p->clone() );
437  }
438  setPayloadBaseImpl( pair->first, pair->second, p, false );
439  mLegacyPayload.reset( clone.release() );
440  } else {
441  mPayloads.clear();
442  mLegacyPayload.reset( p.release() );
443  }
444 }
445 
446 void Item::setPayloadBaseV2( int spid, int mtid, std::auto_ptr<PayloadBase> p )
447 {
448  d_func()->setPayloadBaseImpl( spid, mtid, p, false );
449 }
450 
451 void Item::addPayloadBaseVariant( int spid, int mtid, std::auto_ptr<PayloadBase> p ) const
452 {
453  d_func()->setPayloadBaseImpl( spid, mtid, p, true );
454 }
455 
456 QSet<QByteArray> Item::cachedPayloadParts() const
457 {
458  Q_D(const Item);
459  return d->mCachedPayloadParts;
460 }
461 
462 void Item::setCachedPayloadParts(const QSet< QByteArray > &cachedParts)
463 {
464  Q_D(Item);
465  d->mCachedPayloadParts = cachedParts;
466 }
467 
468 QSet<QByteArray> Item::availablePayloadParts() const
469 {
470  return ItemSerializer::availableParts( *this );
471 }
472 
473 QVector<int> Item::availablePayloadMetaTypeIds() const
474 {
475  QVector<int> result;
476  Q_D( const Item );
477  result.reserve( d->mPayloads.size() );
478  // Stable Insertion Sort - N is typically _very_ low (1 or 2).
479  for ( PayloadContainer::const_iterator it = d->mPayloads.begin(), end = d->mPayloads.end() ; it != end ; ++it ) {
480  result.insert( std::upper_bound( result.begin(), result.end(), it->metaTypeId ), it->metaTypeId );
481  }
482  return result;
483 }
484 
485 void Item::apply( const Item &other )
486 {
487  if ( mimeType() != other.mimeType() || id() != other.id() ) {
488  kDebug() << "mimeType() = " << mimeType() << "; other.mimeType() = " << other.mimeType();
489  kDebug() << "id() = " << id() << "; other.id() = " << other.id();
490  Q_ASSERT_X( false, "Item::apply", "mimetype or id missmatch" );
491  }
492 
493  setRemoteId( other.remoteId() );
494  setRevision( other.revision() );
495  setRemoteRevision( other.remoteRevision() );
496  setFlags( other.flags() );
497  setModificationTime( other.modificationTime() );
498  setSize( other.size() );
499  setParentCollection( other.parentCollection() );
500  setStorageCollectionId( other.storageCollectionId() );
501 
502  QList<QByteArray> attrs;
503  foreach ( Attribute *attribute, other.attributes() ) {
504  addAttribute( attribute->clone() );
505  attrs.append( attribute->type() );
506  }
507 
508  QMutableHashIterator<QByteArray, Attribute*> it( d_ptr->mAttributes );
509  while ( it.hasNext() ) {
510  it.next();
511  if ( !attrs.contains( it.key() ) ) {
512  delete it.value();
513  it.remove();
514  }
515  }
516 
517  ItemSerializer::apply( *this, other );
518  d_func()->resetChangeLog();
519 }
520 
521 AKONADI_DEFINE_PRIVATE( Item )
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition: entity.h:65
Akonadi::Attribute
Provides interface for custom attributes for Entity.
Definition: attribute.h:138
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:196
Akonadi::ItemSerializer::parts
static QSet< QByteArray > parts(const Item &item)
Returns a list of parts available in the item payload.
Definition: itemserializer.cpp:173
Akonadi::ItemSerializer::apply
static void apply(Item &item, const Item &other)
Throws ItemSerializerException on failure.
Definition: itemserializer.cpp:146
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
Akonadi::Entity
The base class for Item and Collection.
Definition: entity.h:59
Akonadi::ItemPrivate
Definition: item_p.h:162
Akonadi::ItemSerializer::serialize
static void serialize(const Item &item, const QByteArray &label, QByteArray &data, int &version)
throws ItemSerializerException on failure
Definition: itemserializer.cpp:127
Akonadi::Attribute::clone
virtual Attribute * clone() const =0
Creates a copy of this attribute.
Akonadi::Attribute::type
virtual QByteArray type() const =0
Returns the type of the attribute.
Akonadi::ItemSerializer::availableParts
static QSet< QByteArray > availableParts(const Item &item)
Returns a list of parts available remotely in the item payload.
Definition: itemserializer.cpp:180
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:00:27 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
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

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