• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

akonadi

itemserializer.cpp

00001 /*
00002     Copyright (c) 2007 Till Adam <adam@kde.org>
00003     Copyright (c) 2007 Volker Krause <vkrause@kde.org>
00004 
00005     This library is free software; you can redistribute it and/or modify it
00006     under the terms of the GNU Library General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or (at your
00008     option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful, but WITHOUT
00011     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013     License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to the
00017     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00018     02110-1301, USA.
00019 */
00020 
00021 #include "itemserializer_p.h"
00022 #include "item.h"
00023 #include "itemserializerplugin.h"
00024 #include "attributefactory.h"
00025 
00026 // KDE core
00027 #include <kdebug.h>
00028 #include <kmimetype.h>
00029 #include <kglobal.h>
00030 
00031 // Qt
00032 #include <QtCore/QBuffer>
00033 #include <QtCore/QFile>
00034 #include <QtCore/QIODevice>
00035 #include <QtCore/QHash>
00036 #include <QtCore/QString>
00037 #include <QtCore/QStringList>
00038 
00039 #include <boost/graph/adjacency_list.hpp>
00040 #include <boost/graph/topological_sort.hpp>
00041 
00042 // temporary
00043 #include "pluginloader_p.h"
00044 
00045 
00046 
00047 namespace Akonadi {
00048 
00049 class DefaultItemSerializerPlugin;
00050 
00051 class DefaultItemSerializerPlugin : public ItemSerializerPlugin
00052 {
00053 public:
00054     DefaultItemSerializerPlugin() { }
00055 
00056     bool deserialize( Item& item, const QByteArray& label, QIODevice& data, int )
00057     {
00058         if ( label != Item::FullPayload )
00059           return false;
00060         item.setPayload( data.readAll() );
00061         return true;
00062     }
00063 
00064     void serialize( const Item& item, const QByteArray& label, QIODevice& data, int& )
00065     {
00066         Q_ASSERT( label == Item::FullPayload );
00067         if ( item.hasPayload<QByteArray>() )
00068             data.write( item.payload<QByteArray>() );
00069     }
00070 
00071 };
00072 
00073 K_GLOBAL_STATIC( DefaultItemSerializerPlugin, s_defaultItemSerializerPlugin )
00074 
00075 }
00076 
00077 using namespace Akonadi;
00078 
00079 class PluginEntry
00080 {
00081   public:
00082     PluginEntry()
00083       : mPlugin( 0 )
00084     {
00085     }
00086 
00087     explicit PluginEntry( const QString &identifier, ItemSerializerPlugin *plugin = 0 )
00088       : mIdentifier( identifier ), mPlugin( plugin )
00089     {
00090     }
00091 
00092     inline ItemSerializerPlugin* plugin() const
00093     {
00094       if ( mPlugin )
00095         return mPlugin;
00096 
00097       QObject *object = PluginLoader::self()->createForName( mIdentifier );
00098       if ( !object ) {
00099         kWarning( 5250 ) << "ItemSerializerPluginLoader: "
00100                          << "plugin" << mIdentifier << "is not valid!" << endl;
00101 
00102         // we try to use the default in that case
00103         mPlugin = s_defaultItemSerializerPlugin;
00104       }
00105 
00106       mPlugin = qobject_cast<ItemSerializerPlugin*>( object );
00107       if ( !mPlugin ) {
00108         kWarning( 5250 ) << "ItemSerializerPluginLoader: "
00109                          << "plugin" << mIdentifier << "doesn't provide interface ItemSerializerPlugin!" << endl;
00110 
00111         // we try to use the default in that case
00112         mPlugin = s_defaultItemSerializerPlugin;
00113       }
00114 
00115       Q_ASSERT( mPlugin );
00116 
00117       return mPlugin;
00118     }
00119 
00120     QString type() const { return mIdentifier; }
00121 
00122     bool operator<( const PluginEntry &other ) const
00123     {
00124       return mIdentifier < other.mIdentifier;
00125     }
00126     bool operator<( const QString &type ) const
00127     {
00128       return mIdentifier < type;
00129     }
00130 
00131   private:
00132     QString mIdentifier;
00133     mutable ItemSerializerPlugin *mPlugin;
00134 };
00135 
00136 static bool operator<( const QString &type, const PluginEntry &entry )
00137 {
00138   return type < entry.type();
00139 }
00140 
00141 
00142 class PluginRegistry
00143 {
00144   public:
00145     PluginRegistry() :
00146       mDefaultPlugin( PluginEntry( QLatin1String("application/octet-stream"), s_defaultItemSerializerPlugin ) )
00147     {
00148       const PluginLoader* pl = PluginLoader::self();
00149       if ( !pl ) {
00150         kWarning( 5250 ) << "Cannot instantiate plugin loader!" << endl;
00151         return;
00152       }
00153       const QStringList types = pl->types();
00154       kDebug( 5250 ) << "ItemSerializerPluginLoader: "
00155                      << "found" << types.size() << "plugins." << endl;
00156       allPlugins.reserve( types.size() + 1 );
00157       foreach ( const QString &type, types )
00158         allPlugins.append( PluginEntry( type ) );
00159       allPlugins.append( mDefaultPlugin );
00160       std::sort( allPlugins.begin(), allPlugins.end() );
00161     }
00162 
00163     const PluginEntry& findBestMatch( const QString &type )
00164     {
00165       KMimeType::Ptr mimeType = KMimeType::mimeType( type, KMimeType::ResolveAliases );
00166       if ( mimeType.isNull() )
00167         return mDefaultPlugin;
00168 
00169       // step 1: find all plugins that match at all
00170       QVector<int> matchingIndexes;
00171       for ( int i = 0, end = allPlugins.size(); i < end; ++i ) {
00172         if ( mimeType->is( allPlugins[i].type() ) )
00173           matchingIndexes.append( i );
00174       }
00175 
00176       // 0 matches: no luck (shouldn't happend though, as application/octet-stream matches everything)
00177       if ( matchingIndexes.isEmpty() )
00178         return mDefaultPlugin;
00179       // 1 match: we are done
00180       if ( matchingIndexes.size() == 1 )
00181         return allPlugins[matchingIndexes.first()];
00182 
00183       // step 2: if we have more than one match, find the most specific one using topological sort
00184       boost::adjacency_list<> graph( matchingIndexes.size() );
00185       for ( int i = 0, end = matchingIndexes.size() ; i != end ; ++i ) {
00186         KMimeType::Ptr mimeType = KMimeType::mimeType( allPlugins[matchingIndexes[i]].type(), KMimeType::ResolveAliases );
00187         if ( mimeType.isNull() )
00188           continue;
00189         for ( int j = 0; j != end; ++j ) {
00190           if ( i != j && mimeType->is( allPlugins[matchingIndexes[j]].type() ) )
00191             boost::add_edge( j, i, graph );
00192         }
00193       }
00194 
00195       QVector<int> order;
00196       order.reserve( allPlugins.size() );
00197       try {
00198         boost::topological_sort( graph, std::back_inserter( order ) );
00199       } catch ( boost::not_a_dag &e ) {
00200         kWarning() << "Mimetype tree is not a DAG!";
00201         return mDefaultPlugin;
00202       }
00203 
00204       return allPlugins[matchingIndexes[order.first()]];
00205     }
00206 
00207     QVector<PluginEntry> allPlugins;
00208     QHash<QString, ItemSerializerPlugin*> cachedPlugins;
00209 
00210   private:
00211     PluginEntry mDefaultPlugin;
00212 };
00213 
00214 K_GLOBAL_STATIC( PluginRegistry, s_pluginRegistry )
00215 
00216 
00217 /*static*/
00218 void ItemSerializer::deserialize( Item& item, const QByteArray& label, const QByteArray& data, int version, bool external )
00219 {
00220 
00221     if ( external ) {
00222       QFile file( QString::fromUtf8(data) );
00223       if ( file.open( QIODevice:: ReadOnly ) ) {
00224         deserialize( item, label, file, version );
00225         file.close();
00226       }
00227     } else {
00228       QBuffer buffer;
00229       buffer.setData( data );
00230       buffer.open( QIODevice::ReadOnly );
00231       buffer.seek( 0 );
00232       deserialize( item, label, buffer, version );
00233       buffer.close();
00234     }
00235 }
00236 
00237 /*static*/
00238 void ItemSerializer::deserialize( Item& item, const QByteArray& label, QIODevice& data, int version )
00239 {
00240   if ( !ItemSerializer::pluginForMimeType( item.mimeType() ).deserialize( item, label, data, version ) )
00241     kWarning() << "Unable to deserialize payload part:" << label;
00242 }
00243 
00244 /*static*/
00245 void ItemSerializer::serialize( const Item& item, const QByteArray& label, QByteArray& data, int &version )
00246 {
00247     QBuffer buffer;
00248     buffer.setBuffer( &data );
00249     buffer.open( QIODevice::WriteOnly );
00250     buffer.seek( 0 );
00251     serialize( item, label, buffer, version );
00252     buffer.close();
00253 }
00254 
00255 /*static*/
00256 void ItemSerializer::serialize( const Item& item, const QByteArray& label, QIODevice& data, int &version )
00257 {
00258   if ( !item.hasPayload() )
00259     return;
00260   ItemSerializerPlugin& plugin = pluginForMimeType( item.mimeType() );
00261   plugin.serialize( item, label, data, version );
00262 }
00263 
00264 QSet<QByteArray> ItemSerializer::parts(const Item & item)
00265 {
00266   if ( !item.hasPayload() )
00267     return QSet<QByteArray>();
00268   return pluginForMimeType( item.mimeType() ).parts( item );
00269 }
00270 
00271 /*static*/
00272 ItemSerializerPlugin& ItemSerializer::pluginForMimeType( const QString & mimetype )
00273 {
00274   // plugin cached, so let's take that one
00275   if ( s_pluginRegistry->cachedPlugins.contains( mimetype ) )
00276     return *(s_pluginRegistry->cachedPlugins.value( mimetype ));
00277 
00278   ItemSerializerPlugin *plugin = 0;
00279 
00280   // check if we have one that matches exactly
00281   const QVector<PluginEntry>::const_iterator it
00282     = qBinaryFind( s_pluginRegistry->allPlugins.constBegin(), s_pluginRegistry->allPlugins.constEnd(), mimetype );
00283   if ( it != s_pluginRegistry->allPlugins.constEnd() ) {
00284     plugin = (*it).plugin();
00285   } else {
00286     // check if we have a more generic plugin
00287     const PluginEntry &entry = s_pluginRegistry->findBestMatch( mimetype );
00288     kDebug( 5250 ) << "Did not find exactly matching serializer plugin for type" << mimetype
00289                    << ", taking" << entry.type() << "as the closest match";
00290     plugin = entry.plugin();
00291   }
00292 
00293   Q_ASSERT(plugin);
00294   s_pluginRegistry->cachedPlugins.insert( mimetype, plugin );
00295   return *plugin;
00296 }

akonadi

Skip menu "akonadi"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal