diff --git a/akonadi/item.cpp b/akonadi/item.cpp index b459e3bc7..507f0308c 100644 --- a/akonadi/item.cpp +++ b/akonadi/item.cpp @@ -1,228 +1,225 @@ /* Copyright (c) 2006 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "item.h" #include "item_p.h" #include "itemserializer_p.h" #include "protocol_p.h" #include #include using namespace Akonadi; // Change to something != RFC822 as soon as the server supports it const char* Item::FullPayload = "RFC822"; Item::Item() : Entity( new ItemPrivate ) { } Item::Item( Id id ) : Entity( new ItemPrivate( id ) ) { } Item::Item( const QString & mimeType ) : Entity( new ItemPrivate ) { d_func()->mMimeType = mimeType; } Item::Item( const Item &other ) : Entity( other ) { } Item::~Item() { } Item::Flags Item::flags() const { return d_func()->mFlags; } void Item::setFlag( const QByteArray & name ) { Q_D( Item ); d->mFlags.insert( name ); if ( !d->mFlagsOverwritten ) d->mAddedFlags.insert( name ); } void Item::clearFlag( const QByteArray & name ) { Q_D( Item ); d->mFlags.remove( name ); if ( !d->mFlagsOverwritten ) d->mDeletedFlags.insert( name ); } void Item::setFlags( const Flags &flags ) { Q_D( Item ); d->mFlags = flags; d->mFlagsOverwritten = true; } void Item::clearFlags() { Q_D( Item ); d->mFlags.clear(); d->mFlagsOverwritten = true; } QDateTime Item::modificationTime() const { return d_func()->mModificationTime; } void Item::setModificationTime( const QDateTime &datetime ) { d_func()->mModificationTime = datetime; } bool Item::hasFlag( const QByteArray & name ) const { return d_func()->mFlags.contains( name ); } QSet Item::loadedPayloadParts() const { return ItemSerializer::parts( *this ); } QByteArray Item::payloadData() const { int version = 0; QByteArray data; ItemSerializer::serialize( *this, FullPayload, data, version ); return data; } void Item::setPayloadFromData( const QByteArray &data ) { ItemSerializer::deserialize( *this, FullPayload, data, 0, false ); } int Item::revision() const { return d_func()->mRevision; } void Item::setRevision( int rev ) { d_func()->mRevision = rev; } Entity::Id Item::storageCollectionId() const { return d_func()->mCollectionId; } void Item::setStorageCollectionId( Entity::Id collectionId ) { d_func()->mCollectionId = collectionId; } QString Item::mimeType() const { return d_func()->mMimeType; } void Item::setSize( qint64 size ) { Q_D( Item ); d->mSize = size; d->mSizeChanged = true; } qint64 Item::size() const { return d_func()->mSize; } void Item::setMimeType( const QString & mimeType ) { d_func()->mMimeType = mimeType; } bool Item::hasPayload() const { return d_func()->mPayload != 0; } KUrl Item::url( UrlType type ) const { KUrl url; url.setProtocol( QString::fromLatin1("akonadi") ); url.addQueryItem( QLatin1String( "item" ), QString::number( id() ) ); if ( type == UrlWithMimeType ) url.addQueryItem( QLatin1String( "type" ), mimeType() ); return url; } Item Item::fromUrl( const KUrl &url ) { if ( url.protocol() != QLatin1String( "akonadi" ) ) return Item(); const QString itemStr = url.queryItem( QLatin1String( "item" ) ); bool ok = false; Item::Id itemId = itemStr.toLongLong( &ok ); if ( !ok ) return Item(); return Item( itemId ); } PayloadBase* Item::payloadBase() const { return d_func()->mPayload; } void Item::setPayloadBase( PayloadBase* p ) { Q_D( Item ); delete d->mPayload; d->mPayload = p; } QSet Item::availablePayloadParts() const { return ItemSerializer::availableParts( *this ); } -void Item::merge(const Item &other) +void Item::merge( const Item &other ) { - foreach(Attribute *attribute, other.attributes()) - { - addAttribute(attribute->clone()); - } + foreach( Attribute *attribute, other.attributes() ) + addAttribute( attribute->clone() ); ItemSerializer::merge( *this, other ); } - AKONADI_DEFINE_PRIVATE( Item ) diff --git a/akonadi/item.h b/akonadi/item.h index d7d1e4a2b..f2fa81fc4 100644 --- a/akonadi/item.h +++ b/akonadi/item.h @@ -1,439 +1,439 @@ /* Copyright (c) 2006 Volker Krause 2007 Till Adam This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_ITEM_H #define AKONADI_ITEM_H #include "akonadi_export.h" #include #include #include "itempayloadinternals_p.h" #include #include #include #include #include #include class KUrl; namespace std { template class auto_ptr; } namespace Akonadi { class ItemPrivate; /** * @short Represents a PIM item stored in Akonadi storage. * * A PIM item consists of one or more parts, allowing a fine-grained access on its * content where needed (eg. mail envelope, mail body and attachments). * * There is also a namespace (prefix) for special parts which are local to Akonadi. * These parts, prefixed by "akonadi-" will never be fetched in the resource. * They are useful for local extensions like agents which might want to add meta data * to items in order to handle them but the meta data should not be stored back to the * resource. * * This class contains beside some type-agnostic information (flags, revision) * a single payload object representing its actual data. Which objects these actually * are depends on the mimetype of the item and the corresponding serializer plugin. * * This class is implicitly shared. * *

Payload

* * Technically the only restriction on payload objects is that they have to be copyable. * For safety reasons, pointer payloads are forbidden as well though, as the * ownership would not be clear. In this case, usage of a shared pointer is * recommended (such as boost::shared_ptr or QSharedPointer). * * Using a shared pointer is also recommended in case the payload uses polymorphic * types. For supported shared pointer types implicit casting is provided when possible. * * When using a value-based class as payload, it is recommended to use one that does * support implicit sharing as setting and retrieving a payload as well as copying * an Akonadi::Item object imply copying of the payload object. * * The availability of a payload of a specific type can be checked using hasPayload(), * payloads can be retrieved by using payload() and set by using setPayload(). Refer * to the documentation of those methods for more details. * * @author Volker Krause , Till Adam */ class AKONADI_EXPORT Item : public Entity { public: /** * Describes a list of items. */ typedef QList List; /** * Describes a flag name. */ typedef QByteArray Flag; /** * Describes a set of flag names. */ typedef QSet Flags; /** * Describes the part name that is used to fetch the * full payload of an item. */ static const char* FullPayload; /** * Creates a new item. */ Item(); /** * Creates a new item with the given unique @p id. */ explicit Item( Id id ); /** * Creates a new item with the given mime type. * * @param mimeType The mime type of the item. */ explicit Item( const QString &mimeType ); /** * Creates a new item from an @p other item. */ Item( const Item &other ); /** * Destroys the item. */ ~Item(); /** * Creates an item from the given @p url. */ static Item fromUrl( const KUrl &url ); /** * Returns all flags of this item. */ Flags flags() const; /** * Returns the timestamp of the last modification of this item. * @since 4.2 */ QDateTime modificationTime() const; /** * Sets the timestamp of the last modification of this item. * * @note Do not modify this value from within an application, * it is updated automatically by the revision checking functions. * @since 4.2 */ void setModificationTime( const QDateTime &datetime ); /** * Returns whether the flag with the given @p name is * set in the item. */ bool hasFlag( const QByteArray &name ) const; /** * Sets the flag with the given @p name in the item. */ void setFlag( const QByteArray &name ); /** * Removes the flag with the given @p name from the item. */ void clearFlag( const QByteArray &name ); /** * Overwrites all flags of the item by the given @p flags. */ void setFlags( const Flags &flags ); /** * Removes all flags from the item. */ void clearFlags(); /** * Sets the payload based on the canonical representation normally * used for data of this mime type. * * @param data The encoded data. * @see fullPayloadData */ void setPayloadFromData( const QByteArray &data ); /** * Returns the full payload in its canonical representation, e.g. the * binary or textual format usually used for data with this mime type. * This is useful when communicating with non-Akonadi application by * e.g. drag&drop, copy&paste or stored files. */ QByteArray payloadData() const; /** * Returns the list of loaded payload parts. This is not necessarily * identical to all parts in the cache or to all available parts on the backend. */ QSet loadedPayloadParts() const; /** * Sets the @p revision number of the item. * * @note Do not modify this value from within an application, * it is updated automatically by the revision checking functions. */ void setRevision( int revision ); /** * Returns the revision number of the item. */ int revision() const; /** * Returns the unique identifier of the collection this item is stored in. There is only * a single such collection, although the item can be linked into arbitrary many * virtual collections. * Calling this method makes sense only after running an ItemFetchJob on the item. * @returns the collection ID if it is know, -1 otherwise. * @since 4.3 */ Entity::Id storageCollectionId() const; /** * Set the size of the item in bytes. * * @since 4.2 */ void setSize( qint64 size ); /** * Returns the size of the items in bytes. * * @since 4.2 */ qint64 size() const; /** * Sets the mime type of the item to @p mimeType. */ void setMimeType( const QString &mimeType ); /** * Returns the mime type of the item. */ QString mimeType() const; /** * Sets the payload object of this PIM item. * * @param p The payload object. Must be copyable and must not be a pointer, * will cause a compilation failure otherwise. Using a type that can be copied * fast (such as implicitly shared classes) is recommended. * If the payload type is polymorphic and you intend to set and retrieve payload * objects with mismatching but castable types, make sure to use a supported * shared pointer implementation (currently boost::shared_ptr and QSharedPointer) * and make sure there is a specialization of Akonadi::super_trait for your class. */ template void setPayload( const T &p ); //@cond PRIVATE template void setPayload( T* p ); template void setPayload( std::auto_ptr p ); //@endcond /** * Returns the payload object of this PIM item. This method will only succeed if either * you requested the exact same payload type that was put in or the payload uses a * supported shared pointer type (currently boost::shared_ptr and QSharedPointer), and * is castable to the requested type. For this to work there needs to be a specialization * of Akonadi::super_trait of the used classes. * * If a mismatching or non-castable payload type is requested, an Akonadi::PayloadException * is thrown. Therefore it is generally recommended to guard calls to payload() with a * corresponding hasPayload() call. * * Trying to retrieve a pointer type will fail to compile. */ template T payload() const; /** * Returns whether the item has a payload object. */ bool hasPayload() const; /** * Returns whether the item has a payload of type @c T. * This method will only return @c true if either you requested the exact same payload type * that was put in or the payload uses a supported shared pointer type (currently boost::shared_ptr * and QSharedPointer), and is castable to the requested type. For this to work there needs * to be a specialization of Akonadi::super_trait of the used classes. * * Trying to retrieve a pointer type will fail to compile. */ template bool hasPayload() const; /** * Describes the type of url which is returned in url(). */ enum UrlType { UrlShort = 0, ///< A short url which contains the identifier only (default) UrlWithMimeType = 1 ///< A url with identifier and mimetype }; /** * Returns the url of the item. */ KUrl url( UrlType type = UrlShort ) const; /** * Returns the parts available for this item. * * @since 4.4 */ QSet availablePayloadParts() const; /** * Merges the Item @p other into this item. * Any parts or attributes available in other, will be merged into this item, * and the payload parts of other will be inserted into this item, overwriting * any existing parts with the same part name. * * If there is an ItemSerialzerPluginV2 for the type, the merge method in that plugin is * used to perform the merge. If only an ItemSerialzerPlugin class is found, or the merge * method of the -V2 plugin is not implemented, the merge is performed with multiple deserializations * of the payload. * * @since 4.4 */ - void merge(const Item &other); + void merge( const Item &other ); private: //@cond PRIVATE friend class ItemModifyJob; friend class ItemFetchJob; PayloadBase* payloadBase() const; void setPayloadBase( PayloadBase* ); /** * Set the collection ID to where the item is stored in. Should be set only by the ItemFetchJob. * @param collectionId the unique identifier of the the collection where this item is stored in. * @since 4.3 */ void setStorageCollectionId( Entity::Id collectionId); //@endcond AKONADI_DECLARE_PRIVATE( Item ) }; template T Item::payload() const { BOOST_STATIC_ASSERT( !boost::is_pointer::value ); if ( !payloadBase() ) throw PayloadException( "No payload set" ); typedef Internal::PayloadTrait PayloadType; if ( PayloadType::isPolymorphic ) { try { const typename PayloadType::SuperType sp = payload(); return PayloadType::castFrom( sp ); } catch ( const Akonadi::PayloadException& ) {} } Payload *p = Internal::payload_cast( payloadBase() ); if ( !p ) { throw PayloadException( QString::fromLatin1( "Wrong payload type (is '%1', requested '%2')" ) .arg( QLatin1String( payloadBase()->typeName() ) ) .arg( QLatin1String( typeid(p).name() ) ) ); } return p->payload; } template bool Item::hasPayload() const { BOOST_STATIC_ASSERT( !boost::is_pointer::value ); if ( !hasPayload() ) return false; typedef Internal::PayloadTrait PayloadType; if ( PayloadType::isPolymorphic ) { try { const typename PayloadType::SuperType sp = payload(); return PayloadType::canCastFrom( sp ); } catch ( const Akonadi::PayloadException& ) {} } return Internal::payload_cast( payloadBase() ); } template void Item::setPayload( const T &p ) { typedef Internal::PayloadTrait PayloadType; if ( PayloadType::isPolymorphic ) { const typename PayloadType::SuperType sp = PayloadType::template castTo( p ); if ( !Internal::PayloadTrait::isNull( sp ) || PayloadType::isNull( p ) ) { setPayload( sp ); return; } } setPayloadBase( new Payload( p ) ); } template void Item::setPayload( T* p ) { p.You_MUST_NOT_use_a_pointer_as_payload; } template void Item::setPayload( std::auto_ptr p ) { p.Nice_try_but_a_std_auto_ptr_is_not_allowed_as_payload_either; } } Q_DECLARE_METATYPE(Akonadi::Item) Q_DECLARE_METATYPE(Akonadi::Item::List) #endif diff --git a/akonadi/itemserializer.cpp b/akonadi/itemserializer.cpp index 7dff7d235..79293091b 100644 --- a/akonadi/itemserializer.cpp +++ b/akonadi/itemserializer.cpp @@ -1,339 +1,336 @@ /* Copyright (c) 2007 Till Adam Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "itemserializer_p.h" #include "item.h" #include "itemserializerplugin.h" #include "attributefactory.h" // KDE core #include #include #include // Qt #include #include #include #include #include #include #include #include // temporary #include "pluginloader_p.h" namespace Akonadi { class DefaultItemSerializerPlugin; class DefaultItemSerializerPlugin : public ItemSerializerPlugin { public: DefaultItemSerializerPlugin() { } bool deserialize( Item& item, const QByteArray& label, QIODevice& data, int ) { if ( label != Item::FullPayload ) return false; item.setPayload( data.readAll() ); return true; } void serialize( const Item& item, const QByteArray& label, QIODevice& data, int& ) { Q_ASSERT( label == Item::FullPayload ); if ( item.hasPayload() ) data.write( item.payload() ); } }; K_GLOBAL_STATIC( DefaultItemSerializerPlugin, s_defaultItemSerializerPlugin ) class PluginEntry { public: PluginEntry() : mPlugin( 0 ) { } explicit PluginEntry( const QString &identifier, ItemSerializerPlugin *plugin = 0 ) : mIdentifier( identifier ), mPlugin( plugin ) { } inline ItemSerializerPlugin* plugin() const { if ( mPlugin ) return mPlugin; QObject *object = PluginLoader::self()->createForName( mIdentifier ); if ( !object ) { kWarning() << "ItemSerializerPluginLoader: " << "plugin" << mIdentifier << "is not valid!" << endl; // we try to use the default in that case mPlugin = s_defaultItemSerializerPlugin; } mPlugin = qobject_cast( object ); if ( !mPlugin ) { kWarning() << "ItemSerializerPluginLoader: " << "plugin" << mIdentifier << "doesn't provide interface ItemSerializerPlugin!" << endl; // we try to use the default in that case mPlugin = s_defaultItemSerializerPlugin; } Q_ASSERT( mPlugin ); return mPlugin; } QString type() const { return mIdentifier; } bool operator<( const PluginEntry &other ) const { return mIdentifier < other.mIdentifier; } bool operator<( const QString &type ) const { return mIdentifier < type; } private: QString mIdentifier; mutable ItemSerializerPlugin *mPlugin; }; static bool operator<( const QString &type, const PluginEntry &entry ) { return type < entry.type(); } class PluginRegistry { public: PluginRegistry() : mDefaultPlugin( PluginEntry( QLatin1String("application/octet-stream"), s_defaultItemSerializerPlugin ) ) { const PluginLoader* pl = PluginLoader::self(); if ( !pl ) { kWarning() << "Cannot instantiate plugin loader!" << endl; return; } const QStringList types = pl->types(); kDebug() << "ItemSerializerPluginLoader: " << "found" << types.size() << "plugins." << endl; allPlugins.reserve( types.size() + 1 ); foreach ( const QString &type, types ) allPlugins.append( PluginEntry( type ) ); allPlugins.append( mDefaultPlugin ); std::sort( allPlugins.begin(), allPlugins.end() ); } const PluginEntry& findBestMatch( const QString &type ) { KMimeType::Ptr mimeType = KMimeType::mimeType( type, KMimeType::ResolveAliases ); if ( mimeType.isNull() ) return mDefaultPlugin; // step 1: find all plugins that match at all QVector matchingIndexes; for ( int i = 0, end = allPlugins.size(); i < end; ++i ) { if ( mimeType->is( allPlugins[i].type() ) ) matchingIndexes.append( i ); } // 0 matches: no luck (shouldn't happend though, as application/octet-stream matches everything) if ( matchingIndexes.isEmpty() ) return mDefaultPlugin; // 1 match: we are done if ( matchingIndexes.size() == 1 ) return allPlugins[matchingIndexes.first()]; // step 2: if we have more than one match, find the most specific one using topological sort boost::adjacency_list<> graph( matchingIndexes.size() ); for ( int i = 0, end = matchingIndexes.size() ; i != end ; ++i ) { KMimeType::Ptr mimeType = KMimeType::mimeType( allPlugins[matchingIndexes[i]].type(), KMimeType::ResolveAliases ); if ( mimeType.isNull() ) continue; for ( int j = 0; j != end; ++j ) { if ( i != j && mimeType->is( allPlugins[matchingIndexes[j]].type() ) ) boost::add_edge( j, i, graph ); } } QVector order; order.reserve( allPlugins.size() ); try { boost::topological_sort( graph, std::back_inserter( order ) ); } catch ( boost::not_a_dag &e ) { kWarning() << "Mimetype tree is not a DAG!"; return mDefaultPlugin; } return allPlugins[matchingIndexes[order.first()]]; } QVector allPlugins; QHash cachedPlugins; private: PluginEntry mDefaultPlugin; }; K_GLOBAL_STATIC( PluginRegistry, s_pluginRegistry ) /*static*/ void ItemSerializer::deserialize( Item& item, const QByteArray& label, const QByteArray& data, int version, bool external ) { if ( external ) { QFile file( QString::fromUtf8(data) ); if ( file.open( QIODevice:: ReadOnly ) ) { deserialize( item, label, file, version ); file.close(); } } else { QBuffer buffer; buffer.setData( data ); buffer.open( QIODevice::ReadOnly ); buffer.seek( 0 ); deserialize( item, label, buffer, version ); buffer.close(); } } /*static*/ void ItemSerializer::deserialize( Item& item, const QByteArray& label, QIODevice& data, int version ) { if ( !ItemSerializer::pluginForMimeType( item.mimeType() )->deserialize( item, label, data, version ) ) kWarning() << "Unable to deserialize payload part:" << label; } /*static*/ void ItemSerializer::serialize( const Item& item, const QByteArray& label, QByteArray& data, int &version ) { QBuffer buffer; buffer.setBuffer( &data ); buffer.open( QIODevice::WriteOnly ); buffer.seek( 0 ); serialize( item, label, buffer, version ); buffer.close(); } /*static*/ void ItemSerializer::serialize( const Item& item, const QByteArray& label, QIODevice& data, int &version ) { if ( !item.hasPayload() ) return; ItemSerializerPlugin *plugin = pluginForMimeType( item.mimeType() ); plugin->serialize( item, label, data, version ); } void ItemSerializer::merge( Item &item, const Item &other ) { if ( !other.hasPayload() ) return; + ItemSerializerPlugin *plugin = pluginForMimeType( item.mimeType() ); - ItemSerializerPluginV2 *pluginV2 = dynamic_cast(plugin); - if ( pluginV2 ) - { + ItemSerializerPluginV2 *pluginV2 = dynamic_cast( plugin ); + if ( pluginV2 ) { pluginV2->merge( item, other ); return; } // Old-school merge: QBuffer buffer; buffer.setBuffer( &other.payloadData() ); buffer.open( QIODevice::ReadOnly ); - foreach( const QByteArray &part, other.loadedPayloadParts() ) - { + foreach ( const QByteArray &part, other.loadedPayloadParts() ) { buffer.seek( 0 ); deserialize( item, part, buffer, 0 ); } - buffer.close(); + buffer.close(); } QSet ItemSerializer::parts( const Item & item ) { if ( !item.hasPayload() ) return QSet(); return pluginForMimeType( item.mimeType() )->parts( item ); } QSet ItemSerializer::availableParts( const Item & item ) { if ( !item.hasPayload() ) return QSet(); ItemSerializerPlugin *plugin = pluginForMimeType( item.mimeType() ); ItemSerializerPluginV2 *pluginV2 = dynamic_cast( plugin ); if ( pluginV2 ) - { return pluginV2->availableParts( item ); - } if (item.hasPayload()) return QSet(); - return QSet() << Item::FullPayload; + return QSet() << Item::FullPayload; } /*static*/ ItemSerializerPlugin* ItemSerializer::pluginForMimeType( const QString & mimetype ) { // plugin cached, so let's take that one if ( s_pluginRegistry->cachedPlugins.contains( mimetype ) ) return s_pluginRegistry->cachedPlugins.value( mimetype ); ItemSerializerPlugin *plugin = 0; // check if we have one that matches exactly const QVector::const_iterator it = qBinaryFind( s_pluginRegistry->allPlugins.constBegin(), s_pluginRegistry->allPlugins.constEnd(), mimetype ); if ( it != s_pluginRegistry->allPlugins.constEnd() ) { plugin = ( *it ).plugin(); } else { // check if we have a more generic plugin const PluginEntry &entry = s_pluginRegistry->findBestMatch( mimetype ); kDebug() << "Did not find exactly matching serializer plugin for type" << mimetype << ", taking" << entry.type() << "as the closest match"; plugin = entry.plugin(); } Q_ASSERT(plugin); s_pluginRegistry->cachedPlugins.insert( mimetype, plugin ); return plugin; } } diff --git a/akonadi/itemserializer_p.h b/akonadi/itemserializer_p.h index 321ef6fa9..7d4b42402 100644 --- a/akonadi/itemserializer_p.h +++ b/akonadi/itemserializer_p.h @@ -1,73 +1,77 @@ /* Copyright (c) 2007 Till Adam Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_ITEM_SERIALIZER_P_H #define AKONADI_ITEM_SERIALIZER_P_H #include #include #include "akonadiprivate_export.h" class QIODevice; namespace Akonadi { class Item; class ItemSerializerPlugin; /** @internal Serialization/Deserialization of item parts, serializer plugin management. */ class AKONADI_TESTS_EXPORT ItemSerializer { public: /** throws ItemSerializerException on failure */ static void deserialize( Item& item, const QByteArray& label, const QByteArray& data, int version, bool external ); /** throws ItemSerializerException on failure */ static void deserialize( Item& item, const QByteArray& label, QIODevice& data, int version ); /** throws ItemSerializerException on failure */ static void serialize( const Item& item, const QByteArray& label, QByteArray& data, int &version ); /** throws ItemSerializerException on failure */ static void serialize( const Item& item, const QByteArray& label, QIODevice& data, int &version ); - /** throws ItemSerializerException on failure + /** + * Throws ItemSerializerException on failure. * * @since 4.4 */ static void merge( Item& item, const Item &other ); - /** Returns a list of parts available in the item payload. */ + /** + * Returns a list of parts available in the item payload. + */ static QSet parts( const Item &item ); - /** Returns a list of parts available remotely in the item payload. + /** + * Returns a list of parts available remotely in the item payload. * * @since 4.4 */ static QSet availableParts( const Item &item ); private: static ItemSerializerPlugin* pluginForMimeType( const QString& mimetype ); }; } #endif diff --git a/akonadi/itemserializerplugin.cpp b/akonadi/itemserializerplugin.cpp index 7c3e0c1c4..4f84e937c 100644 --- a/akonadi/itemserializerplugin.cpp +++ b/akonadi/itemserializerplugin.cpp @@ -1,63 +1,65 @@ /* Copyright (c) 2007 Till Adam Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "itemserializerplugin.h" #include "item.h" -#include +#include using namespace Akonadi; ItemSerializerPlugin::~ItemSerializerPlugin() { } -QSet ItemSerializerPlugin::parts(const Item & item) const +QSet ItemSerializerPlugin::parts( const Item & item ) const { QSet set; if ( item.hasPayload() ) set.insert( Item::FullPayload ); + return set; } ItemSerializerPluginV2::~ItemSerializerPluginV2() { } -QSet ItemSerializerPluginV2::availableParts(const Item & item) const +QSet ItemSerializerPluginV2::availableParts( const Item & item ) const { if ( item.hasPayload() ) return QSet(); + return QSet() << Item::FullPayload; } -void ItemSerializerPluginV2::merge(Item &item, const Item &other ) +void ItemSerializerPluginV2::merge( Item &item, const Item &other ) { QBuffer buffer; buffer.setBuffer( &other.payloadData() ); buffer.open( QIODevice::ReadOnly ); - foreach( const QByteArray part, other.loadedPayloadParts() ) - { + foreach ( const QByteArray part, other.loadedPayloadParts() ) { buffer.seek( 0 ); deserialize( item, part, buffer, 0 ); } + buffer.close(); } diff --git a/akonadi/itemserializerplugin.h b/akonadi/itemserializerplugin.h index 021537a86..8a84389af 100644 --- a/akonadi/itemserializerplugin.h +++ b/akonadi/itemserializerplugin.h @@ -1,215 +1,214 @@ /* Copyright (c) 2007 Till Adam Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_ITEMSERIALIZERPLUGIN_H #define AKONADI_ITEMSERIALIZERPLUGIN_H #include #include #include "item.h" #include "akonadi_export.h" class QIODevice; namespace Akonadi { /** * @short The base class for item type serializer plugins. * * Serializer plugins convert between the payload of Akonadi::Item objects and * a textual or binary representation of the actual content data. * This allows to easily add support for new types to Akonadi. * * The following example shows how to implement a serializer plugin for * a new data type PimNote. * * The PimNote data structure: * @code * typedef struct { * QString author; * QDateTime dateTime; * QString text; * } PimNote; * @endcode * * The serializer plugin code: * @code * #include * * class SerializerPluginPimNote : public QObject, public Akonadi::ItemSerializerPlugin * { * Q_OBJECT * Q_INTERFACES( Akonadi::ItemSerializerPlugin ) * * public: * bool deserialize( Akonadi::Item& item, const QByteArray& label, QIODevice& data, int version ) * { * // we don't handle versions in this example * Q_UNUSED( version ); * * // we work only on full payload * if ( label != Akonadi::Item::FullPayload ) * return false; * * QDataStream stream( &data ); * * PimNote note; * stream >> note.author; * stream >> note.dateTime; * stream >> note.text; * * item.setPayload( note ); * * return true; * } * * void serialize( const Akonadi::Item& item, const QByteArray& label, QIODevice& data, int &version ) * { * // we don't handle versions in this example * Q_UNUSED( version ); * * if ( label != Akonadi::Item::FullPayload || !item.hasPayload() ) * return; * * QDataStream stream( &data ); * * PimNote note = item.payload(); * * stream << note.author; * stream << note.dateTime; * stream << note.text; * } * }; * * Q_EXPORT_PLUGIN2( akonadi_serializer_pimnote, SerializerPluginPimNote ) * * @endcode * * The desktop file: * @code * [Misc] * Name=Pim Note Serializer * Comment=An Akonadi serializer plugin for note objects * * [Plugin] * Type=application/x-pimnote * X-KDE-Library=akonadi_serializer_pimnote * @endcode * * @author Till Adam , Volker Krause */ class AKONADI_EXPORT ItemSerializerPlugin { -public: + public: /** * Destroys the item serializer plugin. */ virtual ~ItemSerializerPlugin(); /** * Converts serialized item data provided in @p data into payload for @p item. * * @param item The item to which the payload should be added. * It is guaranteed to have a mime type matching one of the supported * mime types of this plugin. * However it might contain a unsuited payload added manually * by the application developer. * Verifying the payload type in case a payload is already available * is recommended therefore. * @param label The part identifier of the part to deserialize. * @p label might be an unsupported item part, return @c false if this is the case. * @param data A QIODevice providing access to the serialized data. * The QIODevice is opened in read-only mode and positioned at the beginning. * The QIODevice is guaranteed to be valid. * @param version The version of the data format as set by the user in serialize() or @c 0 (default). * @return @c false if the specified part is not supported by this plugin, @c true if the part * could be de-serialized successfully. */ virtual bool deserialize( Item& item, const QByteArray& label, QIODevice& data, int version ) = 0; /** * Convert the payload object provided in @p item into its serialzed form into @p data. * * @param item The item which contains the payload. * It is guaranteed to have a mimetype matching one of the supported * mimetypes of this plugin as well as the existence of a payload object. * However it might contain an unsupported payload added manually by * the application developer. * Verifying the payload type is recommended therefore. * @param label The part identifier of the part to serialize. * @p label will be one of the item parts returned by parts(). * @param data The QIODevice where the serialized data should be written to. * The QIODevice is opened in write-only mode and positioned at the beginning. * The QIODevice is guaranteed to be valid. * @param version The version of the data format. Can be set by the user to handle different * versions. */ virtual void serialize( const Item& item, const QByteArray& label, QIODevice& data, int &version ) = 0; /** * Returns a list of available parts for the given item payload. * The default implementation returns Item::FullPayload if a payload is set. * * @param item The item. */ virtual QSet parts( const Item &item ) const; }; class AKONADI_EXPORT ItemSerializerPluginV2 : public ItemSerializerPlugin { -public: - /** - * Destroys the item serializer plugin. - */ - virtual ~ItemSerializerPluginV2(); - - /** - * Merges the payload parts in @p other into @p item. - * - * The default implementation is slow as it requires serializing @p other, and deserializing @p item multiple times. - * Reimplementing this is recommended if your type uses payload parts. - * - * @since 4.4 - */ - virtual void merge( Item &item, const Item &other ); - - - /** - * Returns the parts available in the item @p item. - * - * This should be reimplemented to return available parts. - * - * The default implementation returns an empty set if the item has a payload, - * and a set containing Item::FullPayload if the item has no payload. - * - * @since 4.4 - */ - virtual QSet availableParts( const Item &item ) const; + public: + /** + * Destroys the item serializer plugin. + */ + virtual ~ItemSerializerPluginV2(); + + /** + * Merges the payload parts in @p other into @p item. + * + * The default implementation is slow as it requires serializing @p other, and deserializing @p item multiple times. + * Reimplementing this is recommended if your type uses payload parts. + * + * @since 4.4 + */ + virtual void merge( Item &item, const Item &other ); + + /** + * Returns the parts available in the item @p item. + * + * This should be reimplemented to return available parts. + * + * The default implementation returns an empty set if the item has a payload, + * and a set containing Item::FullPayload if the item has no payload. + * + * @since 4.4 + */ + virtual QSet availableParts( const Item &item ) const; }; } Q_DECLARE_INTERFACE( Akonadi::ItemSerializerPlugin, "org.freedesktop.Akonadi.ItemSerializerPlugin/1.0" ) Q_DECLARE_INTERFACE( Akonadi::ItemSerializerPluginV2, "org.freedesktop.Akonadi.ItemSerializerPlugin/1.1" ) #endif diff --git a/akonadi/partfetcher.h b/akonadi/partfetcher.h index dc65725c3..e8ac4921c 100755 --- a/akonadi/partfetcher.h +++ b/akonadi/partfetcher.h @@ -1,71 +1,91 @@ /* Copyright (c) 2009 Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_PART_FETCHER_H #define AKONADI_PART_FETCHER_H -#include -#include +#include -#include "item.h" #include "akonadi_export.h" +class QModelIndex; + namespace Akonadi { +class Item; class PartFetcherPrivate; /** - A convenience class for getting individual payload parts from the model, and fetching asyncronously from - Akonadi if necessary. - - The requested part is emitted though the partFetched signal. - - @author Stephen Kelly - @since 4.4 -*/ + * @short Convenience class for getting payload parts from an Akonadi Model. + * + * This class can be used to retrieve individual payload parts from an EntityTreeModel, + * and fetch them asyncronously from the Akonadi storage if necessary. + * + * The requested part is emitted though the partFetched signal. + * + * @author Stephen Kelly + * @since 4.4 + */ class AKONADI_EXPORT PartFetcher : public QObject { Q_OBJECT -public: - explicit PartFetcher( QObject *parent = 0 ); - - /** - Fetch the part called @p partname from the item at index @p idx. - */ - bool fetchPart( const QModelIndex &idx, const QByteArray &partName ); - - void reset(); - -signals: - void partFetched( const QModelIndex &idx, const Item &item, const QByteArray &partName ); - void invalidated(); - -private: - Q_DECLARE_PRIVATE( Akonadi::PartFetcher ) - PartFetcherPrivate *d_ptr; - - Q_PRIVATE_SLOT( d_func(), void itemsFetched( const Akonadi::Item::List & ) ) - Q_PRIVATE_SLOT( d_func(), void fetchJobDone( KJob *job ) ) + public: + /** + * Creates a new part fetcher. + * + * @param parent The parent object. + */ + explicit PartFetcher( QObject *parent = 0 ); + + /** + * Fetches the part called @p partName from the item at @p index + */ + bool fetchPart( const QModelIndex &index, const QByteArray &partName ); + + /** + * @internal + * + * TODO: move to private class. + */ + void reset(); + + Q_SIGNALS: + /** + * This signal is emitted whenever the requested part has been fetched successfully. + * + * @param index The index of the item the part was fetched from. + * @param item The item the part was fetched from. + * @param partName The name of the part that has been fetched. + */ + void partFetched( const QModelIndex &index, const Item &item, const QByteArray &partName ); + void invalidated(); + + private: + Q_DECLARE_PRIVATE( Akonadi::PartFetcher ) + PartFetcherPrivate *d_ptr; + + Q_PRIVATE_SLOT( d_func(), void itemsFetched( const Akonadi::Item::List & ) ) + Q_PRIVATE_SLOT( d_func(), void fetchJobDone( KJob *job ) ) }; } #endif