22 #include "itemserializer_p.h"
23 #include "protocol_p.h"
28 #include <QtCore/QStringList>
29 #include <QtCore/QReadWriteLock>
35 using namespace Akonadi;
36 using namespace boost;
42 void operator()( T * ) {}
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 ;
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 ) )
58 void Item::addToLegacyMappingImpl( const QString & mimeType,
int spid,
int mtid, std::auto_ptr<PayloadBase> p ) {
61 const boost::shared_ptr<PayloadBase> sp( p );
62 const QWriteLocker locker( legacyMapLock() );
63 std::pair<int,int> & item = (*typeInfoToMetaTypeIdMap())[mimeType][sp];
71 explicit MyReadLocker( QReadWriteLock * rwl ) : rwl( rwl ), locked( false ) {
if ( rwl ) rwl->lockForRead(); locked =
true; }
72 ~MyReadLocker() {
if ( rwl && locked ) rwl->unlock(); }
75 shared_ptr<T> makeUnlockingPointer( T * t ) {
81 const shared_ptr<T> result( t, bind( &QReadWriteLock::unlock, rwl ) );
85 return shared_ptr<T>();
89 QReadWriteLock *
const rwl;
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> >();
104 return locker.makeUnlockingPointer( &it->second );
108 const char* Item::FullPayload =
"RFC822";
120 Item::Item(
const QString & mimeType )
123 d_func()->mMimeType = mimeType;
126 Item::Item(
const Item &other )
137 return d_func()->mFlags;
140 void Item::setFlag(
const QByteArray & name )
143 d->mFlags.insert( name );
144 if ( !d->mFlagsOverwritten ) {
145 if ( d->mDeletedFlags.contains( name ) )
146 d->mDeletedFlags.remove( name );
148 d->mAddedFlags.insert( name );
152 void Item::clearFlag(
const QByteArray & name )
155 d->mFlags.remove( name );
156 if ( !d->mFlagsOverwritten ) {
157 if ( d->mAddedFlags.contains( name ) )
158 d->mAddedFlags.remove( name );
160 d->mDeletedFlags.insert( name );
164 void Item::setFlags(
const Flags &flags )
168 d->mFlagsOverwritten =
true;
171 void Item::clearFlags()
175 d->mFlagsOverwritten =
true;
178 QDateTime Item::modificationTime()
const
180 return d_func()->mModificationTime;
183 void Item::setModificationTime(
const QDateTime &datetime )
185 d_func()->mModificationTime = datetime;
188 bool Item::hasFlag(
const QByteArray & name )
const
190 return d_func()->mFlags.contains( name );
193 QSet<QByteArray> Item::loadedPayloadParts()
const
195 return ItemSerializer::parts( *
this );
198 QByteArray Item::payloadData()
const
202 ItemSerializer::serialize( *
this, FullPayload, data, version );
206 void Item::setPayloadFromData(
const QByteArray &data )
208 ItemSerializer::deserialize( *
this, FullPayload, data, 0,
false );
211 void Item::clearPayload()
213 d_func()->mClearPayload =
true;
216 int Item::revision()
const
218 return d_func()->mRevision;
221 void Item::setRevision(
int rev )
223 d_func()->mRevision = rev;
228 return d_func()->mCollectionId;
231 void Item::setStorageCollectionId(
Entity::Id collectionId )
233 d_func()->mCollectionId = collectionId;
236 QString Item::mimeType()
const
238 return d_func()->mMimeType;
241 void Item::setSize( qint64 size )
245 d->mSizeChanged =
true;
248 qint64 Item::size()
const
250 return d_func()->mSize;
253 void Item::setMimeType(
const QString & mimeType )
255 d_func()->mMimeType = mimeType;
258 bool Item::hasPayload()
const
260 return d_func()->hasMetaTypeId( -1 );
266 url.setProtocol( QString::fromLatin1(
"akonadi" ) );
267 url.addQueryItem( QLatin1String(
"item" ), QString::number(
id() ) );
269 if ( type == UrlWithMimeType )
270 url.addQueryItem( QLatin1String(
"type" ), mimeType() );
275 Item Item::fromUrl(
const KUrl &url )
277 if ( url.protocol() != QLatin1String(
"akonadi" ) )
280 const QString itemStr = url.queryItem( QLatin1String(
"item" ) );
282 Item::Id itemId = itemStr.toLongLong( &ok );
286 return Item( itemId );
293 Q_GLOBAL_STATIC( Payload<Dummy>, dummyPayload )
295 PayloadBase* Item::payloadBase()
const
298 d->tryEnsureLegacyPayload();
299 if ( d->mLegacyPayload )
300 return d->mLegacyPayload.get();
302 return dummyPayload();
305 void ItemPrivate::tryEnsureLegacyPayload()
const
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;
313 PayloadBase* Item::payloadBaseV2(
int spid,
int mtid )
const
315 return d_func()->payloadBaseImpl( spid, mtid );
319 class ConversionGuard {
323 explicit ConversionGuard(
bool & b )
335 bool Item::ensureMetaTypeId(
int mtid )
const
339 if ( d->mPayloads.empty() )
343 if ( d->hasMetaTypeId( mtid ) )
348 if ( d->mConversionInProgress )
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();
360 kDebug() <<
"conversion threw something not derived from std::exception: fix the program!";
365 static QString format_type(
int spid,
int mtid ) {
366 return QString::fromLatin1(
"sp(%1)<%2>" )
367 .arg( spid ).arg( QLatin1String( QMetaType::typeName( mtid ) ) );
370 static QString format_types(
const PayloadContainer & c ) {
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(
", ") );
378 QString Item::payloadExceptionText(
int spid,
int mtid )
const
381 if ( d->mPayloads.empty() )
382 return QLatin1String(
"No payload set" );
384 return QString::fromLatin1(
"Wrong payload type (requested: %1; present: %2" )
385 .arg( format_type( spid, mtid ), format_types( d->mPayloads ) );
388 void Item::throwPayloadException(
int spid,
int mtid )
const
391 if ( d->mPayloads.empty() )
392 throw PayloadException(
"No payload set" );
394 throw PayloadException( QString::fromLatin1(
"Wrong payload type (requested: %1; present: %2" )
395 .arg( format_type( spid, mtid ), format_types( d->mPayloads ) ) );
399 void Item::setPayloadBase( PayloadBase* p )
401 d_func()->setLegacyPayloadBaseImpl( std::auto_ptr<PayloadBase>( p ) );
404 void ItemPrivate::setLegacyPayloadBaseImpl( std::auto_ptr<PayloadBase> p )
406 if (
const shared_ptr<
const std::pair<int,int> > pair = lookupLegacyMapping( mMimeType, p.get() ) ) {
407 std::auto_ptr<PayloadBase> clone;
409 clone.reset( p->clone() );
410 setPayloadBaseImpl( pair->first, pair->second, p,
false );
411 mLegacyPayload.reset( clone.release() );
414 mLegacyPayload.reset( p.release() );
418 void Item::setPayloadBaseV2(
int spid,
int mtid, std::auto_ptr<PayloadBase> p )
420 d_func()->setPayloadBaseImpl( spid, mtid, p,
false );
423 void Item::addPayloadBaseVariant(
int spid,
int mtid, std::auto_ptr<PayloadBase> p )
const
425 d_func()->setPayloadBaseImpl( spid, mtid, p,
true );
428 QSet<QByteArray> Item::availablePayloadParts()
const
430 return ItemSerializer::availableParts( *
this );
433 QVector<int> Item::availablePayloadMetaTypeIds()
const
437 result.reserve( d->mPayloads.size() );
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 );
444 void Item::apply(
const Item &other )
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" );
454 setFlags( other.
flags() );
456 setSize( other.
size() );
461 QList<QByteArray> attrs;
464 addAttribute( attribute->
clone() );
465 attrs.append( attribute->
type() );
468 QMutableHashIterator<QByteArray, Attribute*> it( d_ptr->mAttributes );
469 while ( it.hasNext() ) {
471 if ( !attrs.contains( it.key() ) ) {
477 ItemSerializer::apply( *
this, other );
478 d_func()->resetChangeLog();
481 AKONADI_DEFINE_PRIVATE(
Item )