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

akonadi

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

Skip menu "kdepimlibs-4.9.4 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
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