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

akonadi

item.cpp
00001 /*
00002     Copyright (c) 2006 Volker Krause <vkrause@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 #include "item.h"
00021 #include "item_p.h"
00022 #include "itemserializer_p.h"
00023 #include "protocol_p.h"
00024 
00025 #include <kurl.h>
00026 #include <kdebug.h>
00027 
00028 #include <QtCore/QStringList>
00029 #include <QtCore/QReadWriteLock>
00030 
00031 #include <algorithm>
00032 #include <map>
00033 #include <utility>
00034 
00035 using namespace Akonadi;
00036 using namespace boost;
00037 
00038 namespace {
00039 
00040 struct nodelete {
00041     template <typename T>
00042     void operator()( T * ) {}
00043 };
00044 
00045 struct ByTypeId {
00046     typedef bool result_type;
00047     bool operator()( const boost::shared_ptr<PayloadBase> & lhs, const boost::shared_ptr<PayloadBase> & rhs ) const {
00048         return strcmp( lhs->typeName(), rhs->typeName() ) < 0 ;
00049     }
00050 };
00051 
00052 } // anon namespace
00053 
00054 typedef QHash< QString, std::map< boost::shared_ptr<PayloadBase>, std::pair<int,int>, ByTypeId > > LegacyMap;
00055 Q_GLOBAL_STATIC( LegacyMap, typeInfoToMetaTypeIdMap )
00056 Q_GLOBAL_STATIC_WITH_ARGS( QReadWriteLock, legacyMapLock, ( QReadWriteLock::Recursive ) )
00057 
00058 void Item::addToLegacyMappingImpl( const QString & mimeType, int spid, int mtid, std::auto_ptr<PayloadBase> p ) {
00059     if ( !p.get() )
00060         return;
00061     const boost::shared_ptr<PayloadBase> sp( p );
00062     const QWriteLocker locker( legacyMapLock() );
00063     std::pair<int,int> & item = (*typeInfoToMetaTypeIdMap())[mimeType][sp];
00064     item.first = spid;
00065     item.second = mtid;
00066 }
00067 
00068 namespace {
00069     class MyReadLocker {
00070     public:
00071         explicit MyReadLocker( QReadWriteLock * rwl ) : rwl( rwl ), locked( false ) { if ( rwl ) rwl->lockForRead(); locked = true; }
00072         ~MyReadLocker() { if ( rwl && locked ) rwl->unlock(); }
00073 
00074         template <typename T>
00075         shared_ptr<T> makeUnlockingPointer( T * t ) {
00076             if ( t ) {
00077                 // the bind() doesn't throw, so if shared_ptr
00078                 // construction line below, or anything else after it,
00079                 // throws, we're unlocked. Mark us as such:
00080                 locked = false;
00081                 const shared_ptr<T> result( t, bind( &QReadWriteLock::unlock, rwl ) );
00082                 // from now on, the shared_ptr is responsible for unlocking
00083                 return result;
00084             } else {
00085                 return shared_ptr<T>();
00086             }
00087         }
00088     private:
00089         QReadWriteLock * const rwl;
00090         bool locked;
00091     };
00092 }
00093 
00094 static shared_ptr<const std::pair<int,int> > lookupLegacyMapping( const QString & mimeType, PayloadBase * p ) {
00095     MyReadLocker locker( legacyMapLock() );
00096     const LegacyMap::const_iterator hit = typeInfoToMetaTypeIdMap()->constFind( mimeType );
00097     if ( hit == typeInfoToMetaTypeIdMap()->constEnd() )
00098         return shared_ptr<const std::pair<int,int> >();
00099     const boost::shared_ptr<PayloadBase> sp( p, nodelete() );
00100     const LegacyMap::mapped_type::const_iterator it = hit->find( sp );
00101     if ( it == hit->end() )
00102         return shared_ptr<const std::pair<int,int> >();
00103     
00104     return locker.makeUnlockingPointer( &it->second );
00105 }
00106 
00107 // Change to something != RFC822 as soon as the server supports it
00108 const char* Item::FullPayload = "RFC822";
00109 
00110 Item::Item()
00111   : Entity( new ItemPrivate )
00112 {
00113 }
00114 
00115 Item::Item( Id id )
00116   : Entity( new ItemPrivate( id ) )
00117 {
00118 }
00119 
00120 Item::Item( const QString & mimeType )
00121   : Entity( new ItemPrivate )
00122 {
00123   d_func()->mMimeType = mimeType;
00124 }
00125 
00126 Item::Item( const Item &other )
00127   : Entity( other )
00128 {
00129 }
00130 
00131 Item::~Item()
00132 {
00133 }
00134 
00135 Item::Flags Item::flags() const
00136 {
00137   return d_func()->mFlags;
00138 }
00139 
00140 void Item::setFlag( const QByteArray & name )
00141 {
00142   Q_D( Item );
00143   d->mFlags.insert( name );
00144   if ( !d->mFlagsOverwritten ) {
00145     if ( d->mDeletedFlags.contains( name ) )
00146       d->mDeletedFlags.remove( name );
00147     else
00148       d->mAddedFlags.insert( name );
00149   }
00150 }
00151 
00152 void Item::clearFlag( const QByteArray & name )
00153 {
00154   Q_D( Item );
00155   d->mFlags.remove( name );
00156   if ( !d->mFlagsOverwritten ) {
00157     if ( d->mAddedFlags.contains( name ) )
00158       d->mAddedFlags.remove( name );
00159     else
00160       d->mDeletedFlags.insert( name );
00161   }
00162 }
00163 
00164 void Item::setFlags( const Flags &flags )
00165 {
00166   Q_D( Item );
00167   d->mFlags = flags;
00168   d->mFlagsOverwritten = true;
00169 }
00170 
00171 void Item::clearFlags()
00172 {
00173   Q_D( Item );
00174   d->mFlags.clear();
00175   d->mFlagsOverwritten = true;
00176 }
00177 
00178 QDateTime Item::modificationTime() const
00179 {
00180   return d_func()->mModificationTime;
00181 }
00182 
00183 void Item::setModificationTime( const QDateTime &datetime )
00184 {
00185   d_func()->mModificationTime = datetime;
00186 }
00187 
00188 bool Item::hasFlag( const QByteArray & name ) const
00189 {
00190   return d_func()->mFlags.contains( name );
00191 }
00192 
00193 QSet<QByteArray> Item::loadedPayloadParts() const
00194 {
00195   return ItemSerializer::parts( *this );
00196 }
00197 
00198 QByteArray Item::payloadData() const
00199 {
00200   int version = 0;
00201   QByteArray data;
00202   ItemSerializer::serialize( *this, FullPayload, data, version );
00203   return data;
00204 }
00205 
00206 void Item::setPayloadFromData( const QByteArray &data )
00207 {
00208   ItemSerializer::deserialize( *this, FullPayload, data, 0, false );
00209 }
00210 
00211 void Item::clearPayload()
00212 {
00213   d_func()->mClearPayload = true;
00214 }
00215 
00216 int Item::revision() const
00217 {
00218   return d_func()->mRevision;
00219 }
00220 
00221 void Item::setRevision( int rev )
00222 {
00223   d_func()->mRevision = rev;
00224 }
00225 
00226 Entity::Id Item::storageCollectionId() const
00227 {
00228   return d_func()->mCollectionId;
00229 }
00230 
00231 void Item::setStorageCollectionId( Entity::Id collectionId )
00232 {
00233   d_func()->mCollectionId = collectionId;
00234 }
00235 
00236 QString Item::mimeType() const
00237 {
00238   return d_func()->mMimeType;
00239 }
00240 
00241 void Item::setSize( qint64 size )
00242 {
00243   Q_D( Item );
00244   d->mSize = size;
00245   d->mSizeChanged = true;
00246 }
00247 
00248 qint64 Item::size() const
00249 {
00250   return d_func()->mSize;
00251 }
00252 
00253 void Item::setMimeType( const QString & mimeType )
00254 {
00255   d_func()->mMimeType = mimeType;
00256 }
00257 
00258 bool Item::hasPayload() const
00259 {
00260   return d_func()->hasMetaTypeId( -1 );
00261 }
00262 
00263 KUrl Item::url( UrlType type ) const
00264 {
00265   KUrl url;
00266   url.setProtocol( QString::fromLatin1( "akonadi" ) );
00267   url.addQueryItem( QLatin1String( "item" ), QString::number( id() ) );
00268 
00269   if ( type == UrlWithMimeType )
00270     url.addQueryItem( QLatin1String( "type" ), mimeType() );
00271 
00272   return url;
00273 }
00274 
00275 Item Item::fromUrl( const KUrl &url )
00276 {
00277   if ( url.protocol() != QLatin1String( "akonadi" ) )
00278     return Item();
00279 
00280   const QString itemStr = url.queryItem( QLatin1String( "item" ) );
00281   bool ok = false;
00282   Item::Id itemId = itemStr.toLongLong( &ok );
00283   if ( !ok )
00284     return Item();
00285 
00286   return Item( itemId );
00287 }
00288 
00289 namespace {
00290     class Dummy {};
00291 }
00292 
00293 Q_GLOBAL_STATIC( Payload<Dummy>, dummyPayload )
00294 
00295 PayloadBase* Item::payloadBase() const
00296 {
00297   Q_D( const Item );
00298   d->tryEnsureLegacyPayload();
00299   if ( d->mLegacyPayload )
00300     return d->mLegacyPayload.get();
00301   else
00302     return dummyPayload();
00303 }
00304 
00305 void ItemPrivate::tryEnsureLegacyPayload() const
00306 {
00307   if ( !mLegacyPayload )
00308     for ( PayloadContainer::const_iterator it = mPayloads.begin(), end = mPayloads.end() ; it != end ; ++it )
00309       if ( lookupLegacyMapping( mMimeType, it->payload.get() ) )
00310           mLegacyPayload = it->payload; // clones
00311 }
00312 
00313 PayloadBase* Item::payloadBaseV2( int spid, int mtid ) const
00314 {
00315   return d_func()->payloadBaseImpl( spid, mtid );
00316 }
00317 
00318 namespace {
00319     class ConversionGuard {
00320         const bool old;
00321         bool & b;
00322     public:
00323         explicit ConversionGuard( bool & b )
00324             : old( b ), b( b )
00325         {
00326             b = true;
00327         }
00328         ~ConversionGuard() {
00329             b = old;
00330         }
00331     };
00332 }
00333             
00334 
00335 bool Item::ensureMetaTypeId( int mtid ) const
00336 {
00337   Q_D( const Item );
00338   // 0. Nothing there - nothing to convert from, either
00339   if ( d->mPayloads.empty() )
00340     return false;
00341 
00342   // 1. Look whether we already have one:
00343   if ( d->hasMetaTypeId( mtid ) )
00344     return true;
00345 
00346   // recursion detection (shouldn't trigger, but does if the
00347   // serialiser plugins are acting funky):
00348   if ( d->mConversionInProgress )
00349       return false;
00350 
00351   // 2. Try to create one by conversion from a different representation:
00352   try {
00353     const ConversionGuard guard( d->mConversionInProgress );
00354     Item converted = ItemSerializer::convert( *this, mtid );
00355     return d->movePayloadFrom( converted.d_func(), mtid );
00356   } catch ( const std::exception & e ) {
00357     kDebug() << "conversion threw:" << e.what();
00358     return false;
00359   } catch ( ... ) {
00360     kDebug() << "conversion threw something not derived from std::exception: fix the program!";
00361     return false;
00362   }
00363 }
00364 
00365 static QString format_type( int spid, int mtid ) {
00366   return QString::fromLatin1( "sp(%1)<%2>" )
00367       .arg( spid ).arg( QLatin1String( QMetaType::typeName( mtid ) ) );
00368 }
00369 
00370 static QString format_types( const PayloadContainer & c ) {
00371   QStringList result;
00372   for ( PayloadContainer::const_iterator it = c.begin(), end = c.end() ; it != end ; ++it )
00373     result.push_back( format_type( it->sharedPointerId, it->metaTypeId ) );
00374   return result.join( QLatin1String(", ") );
00375 }
00376 
00377 #if 0
00378 QString Item::payloadExceptionText( int spid, int mtid ) const
00379 {
00380   Q_D( const Item );
00381   if ( d->mPayloads.empty() )
00382     return QLatin1String( "No payload set" );
00383   else
00384     return QString::fromLatin1( "Wrong payload type (requested: %1; present: %2" )
00385         .arg( format_type( spid, mtid ), format_types( d->mPayloads ) );
00386 }
00387 #else
00388 void Item::throwPayloadException( int spid, int mtid ) const
00389 {
00390   Q_D( const Item );
00391   if ( d->mPayloads.empty() )
00392     throw PayloadException( "No payload set" );
00393   else
00394     throw PayloadException( QString::fromLatin1( "Wrong payload type (requested: %1; present: %2" )
00395                             .arg( format_type( spid, mtid ), format_types( d->mPayloads ) ) );
00396 }
00397 #endif
00398 
00399 void Item::setPayloadBase( PayloadBase* p )
00400 {
00401   d_func()->setLegacyPayloadBaseImpl( std::auto_ptr<PayloadBase>( p ) );
00402 }
00403 
00404 void ItemPrivate::setLegacyPayloadBaseImpl( std::auto_ptr<PayloadBase> p )
00405 {
00406   if ( const shared_ptr<const std::pair<int,int> > pair = lookupLegacyMapping( mMimeType, p.get() ) ) {
00407     std::auto_ptr<PayloadBase> clone;
00408     if ( p.get() )
00409       clone.reset( p->clone() );
00410     setPayloadBaseImpl( pair->first, pair->second, p, false );
00411     mLegacyPayload.reset( clone.release() );
00412   } else {
00413     mPayloads.clear();
00414     mLegacyPayload.reset( p.release() );
00415   }
00416 }
00417 
00418 void Item::setPayloadBaseV2( int spid, int mtid, std::auto_ptr<PayloadBase> p )
00419 {
00420   d_func()->setPayloadBaseImpl( spid, mtid, p, false );
00421 }
00422 
00423 void Item::addPayloadBaseVariant( int spid, int mtid, std::auto_ptr<PayloadBase> p ) const
00424 {
00425   d_func()->setPayloadBaseImpl( spid, mtid, p, true );
00426 }
00427 
00428 QSet<QByteArray> Item::availablePayloadParts() const
00429 {
00430   return ItemSerializer::availableParts( *this );
00431 }
00432 
00433 QVector<int> Item::availablePayloadMetaTypeIds() const
00434 {
00435   QVector<int> result;
00436   Q_D( const Item );
00437   result.reserve( d->mPayloads.size() );
00438   // Stable Insertion Sort - N is typically _very_ low (1 or 2).
00439   for ( PayloadContainer::const_iterator it = d->mPayloads.begin(), end = d->mPayloads.end() ; it != end ; ++it )
00440       result.insert( std::upper_bound( result.begin(), result.end(), it->metaTypeId ), it->metaTypeId );
00441   return result;
00442 }
00443 
00444 void Item::apply( const Item &other )
00445 {
00446   if ( mimeType() != other.mimeType() || id() != other.id() ) {
00447     kDebug() << "mimeType() = " << mimeType() << "; other.mimeType() = " << other.mimeType();
00448     kDebug() << "id() = " << id() << "; other.id() = " << other.id();
00449     Q_ASSERT_X( false, "Item::apply", "mimetype or id missmatch" );
00450   }
00451 
00452   setRemoteId( other.remoteId() );
00453   setRevision( other.revision() );
00454   setFlags( other.flags() );
00455   setModificationTime( other.modificationTime() );
00456   setSize( other.size() );
00457   setParentCollection( other.parentCollection() );
00458   setStorageCollectionId( other.storageCollectionId() );
00459   setRemoteId( other.remoteId() );
00460 
00461   QList<QByteArray> attrs;
00462   foreach ( Attribute *attribute, other.attributes() )
00463   {
00464     addAttribute( attribute->clone() );
00465     attrs.append( attribute->type() );
00466   }
00467 
00468   QMutableHashIterator<QByteArray, Attribute*> it( d_ptr->mAttributes );
00469   while ( it.hasNext() ) {
00470     it.next();
00471     if ( !attrs.contains( it.key() ) ) {
00472       delete it.value();
00473       it.remove();
00474     }
00475   }
00476 
00477   ItemSerializer::apply( *this, other );
00478   d_func()->resetChangeLog();
00479 }
00480 
00481 AKONADI_DEFINE_PRIVATE( Item )
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu Aug 2 2012 15:25:18 by doxygen 1.7.5 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.8.5 API Reference

Skip menu "kdepimlibs-4.8.5 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