00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "typepluginloader_p.h"
00022
00023 #include "item.h"
00024 #include "itemserializer_p.h"
00025 #include "itemserializerplugin.h"
00026
00027
00028 #include <kdebug.h>
00029 #include <kmimetype.h>
00030
00031
00032 #include <QtCore/QHash>
00033 #include <QtCore/QString>
00034 #include <QtCore/QStringList>
00035
00036 #include <boost/graph/adjacency_list.hpp>
00037 #include <boost/graph/topological_sort.hpp>
00038
00039
00040 #include "pluginloader_p.h"
00041
00042 namespace Akonadi {
00043
00044 K_GLOBAL_STATIC( DefaultItemSerializerPlugin, s_defaultItemSerializerPlugin )
00045
00046 class PluginEntry
00047 {
00048 public:
00049 PluginEntry()
00050 : mPlugin( 0 )
00051 {
00052 }
00053
00054 explicit PluginEntry( const QString &identifier, QObject *plugin = 0 )
00055 : mIdentifier( identifier ), mPlugin( plugin )
00056 {
00057 }
00058
00059 inline QObject* plugin() const
00060 {
00061 if ( mPlugin )
00062 return mPlugin;
00063
00064 QObject *object = PluginLoader::self()->createForName( mIdentifier );
00065 if ( !object ) {
00066 kWarning() << "ItemSerializerPluginLoader: "
00067 << "plugin" << mIdentifier << "is not valid!" << endl;
00068
00069
00070 mPlugin = s_defaultItemSerializerPlugin;
00071 }
00072
00073 mPlugin = object;
00074 if ( !qobject_cast<ItemSerializerPlugin*>( mPlugin ) ) {
00075 kWarning() << "ItemSerializerPluginLoader: "
00076 << "plugin" << mIdentifier << "doesn't provide interface ItemSerializerPlugin!" << endl;
00077
00078
00079 mPlugin = s_defaultItemSerializerPlugin;
00080 }
00081
00082 Q_ASSERT( mPlugin );
00083
00084 return mPlugin;
00085 }
00086
00087 QString type() const
00088 {
00089 return mIdentifier;
00090 }
00091
00092 bool operator<( const PluginEntry &other ) const
00093 {
00094 return mIdentifier < other.mIdentifier;
00095 }
00096
00097 bool operator<( const QString &type ) const
00098 {
00099 return mIdentifier < type;
00100 }
00101
00102 private:
00103 QString mIdentifier;
00104 mutable QObject *mPlugin;
00105 };
00106
00107 static bool operator<( const QString &type, const PluginEntry &entry )
00108 {
00109 return type < entry.type();
00110 }
00111
00112
00113 class PluginRegistry
00114 {
00115 public:
00116 PluginRegistry()
00117 : mDefaultPlugin( PluginEntry( QLatin1String( "application/octet-stream" ), s_defaultItemSerializerPlugin ) )
00118 {
00119 const PluginLoader* pl = PluginLoader::self();
00120 if ( !pl ) {
00121 kWarning() << "Cannot instantiate plugin loader!" << endl;
00122 return;
00123 }
00124 const QStringList types = pl->types();
00125 kDebug() << "ItemSerializerPluginLoader: "
00126 << "found" << types.size() << "plugins." << endl;
00127 allPlugins.reserve( types.size() + 1 );
00128 foreach ( const QString &type, types )
00129 allPlugins.append( PluginEntry( type ) );
00130 allPlugins.append( mDefaultPlugin );
00131 std::sort( allPlugins.begin(), allPlugins.end() );
00132 }
00133
00134 const PluginEntry& findBestMatch( const QString &type )
00135 {
00136 KMimeType::Ptr mimeType = KMimeType::mimeType( type, KMimeType::ResolveAliases );
00137 if ( mimeType.isNull() )
00138 return mDefaultPlugin;
00139
00140
00141 QVector<int> matchingIndexes;
00142 for ( int i = 0, end = allPlugins.size(); i < end; ++i ) {
00143 if ( mimeType->is( allPlugins[i].type() ) )
00144 matchingIndexes.append( i );
00145 }
00146
00147
00148 if ( matchingIndexes.isEmpty() )
00149 return mDefaultPlugin;
00150
00151 if ( matchingIndexes.size() == 1 )
00152 return allPlugins[matchingIndexes.first()];
00153
00154
00155 boost::adjacency_list<> graph( matchingIndexes.size() );
00156 for ( int i = 0, end = matchingIndexes.size() ; i != end ; ++i ) {
00157 KMimeType::Ptr mimeType = KMimeType::mimeType( allPlugins[matchingIndexes[i]].type(), KMimeType::ResolveAliases );
00158 if ( mimeType.isNull() )
00159 continue;
00160 for ( int j = 0; j != end; ++j ) {
00161 if ( i != j && mimeType->is( allPlugins[matchingIndexes[j]].type() ) )
00162 boost::add_edge( j, i, graph );
00163 }
00164 }
00165
00166 QVector<int> order;
00167 order.reserve( allPlugins.size() );
00168 try {
00169 boost::topological_sort( graph, std::back_inserter( order ) );
00170 } catch ( boost::not_a_dag &e ) {
00171 kWarning() << "Mimetype tree is not a DAG!";
00172 return mDefaultPlugin;
00173 }
00174
00175 return allPlugins[matchingIndexes[order.first()]];
00176 }
00177
00178 QVector<PluginEntry> allPlugins;
00179 QHash<QString, QObject*> cachedPlugins;
00180
00181 private:
00182 PluginEntry mDefaultPlugin;
00183 };
00184
00185 K_GLOBAL_STATIC( PluginRegistry, s_pluginRegistry )
00186
00187 QObject* TypePluginLoader::objectForMimeType( const QString &mimetype )
00188 {
00189
00190 if ( s_pluginRegistry->cachedPlugins.contains( mimetype ) )
00191 return s_pluginRegistry->cachedPlugins.value( mimetype );
00192
00193 QObject *plugin = 0;
00194
00195
00196 const QVector<PluginEntry>::const_iterator it
00197 = qBinaryFind( s_pluginRegistry->allPlugins.constBegin(), s_pluginRegistry->allPlugins.constEnd(), mimetype );
00198 if ( it != s_pluginRegistry->allPlugins.constEnd() ) {
00199 plugin = ( *it ).plugin();
00200 } else {
00201
00202 const PluginEntry &entry = s_pluginRegistry->findBestMatch( mimetype );
00203 kDebug() << "Did not find exactly matching serializer plugin for type" << mimetype
00204 << ", taking" << entry.type() << "as the closest match";
00205 plugin = entry.plugin();
00206 }
00207
00208 Q_ASSERT(plugin);
00209 s_pluginRegistry->cachedPlugins.insert( mimetype, plugin );
00210 return plugin;
00211 }
00212
00213 ItemSerializerPlugin* TypePluginLoader::pluginForMimeType( const QString &mimetype )
00214 {
00215 ItemSerializerPlugin* plugin = qobject_cast<ItemSerializerPlugin*>( objectForMimeType( mimetype ) );
00216 Q_ASSERT( plugin );
00217 return plugin;
00218 }
00219
00220 }