21 #include "typepluginloader_p.h"
24 #include "itemserializer_p.h"
25 #include "itemserializerplugin.h"
29 #include <kmimetype.h>
32 #include <QtCore/QHash>
33 #include <QtCore/QString>
34 #include <QtCore/QByteArray>
35 #include <QtCore/QStringList>
37 #include <boost/graph/adjacency_list.hpp>
38 #include <boost/graph/topological_sort.hpp>
41 #include "pluginloader_p.h"
46 static const char LEGACY_NAME[] =
"legacy";
47 static const char DEFAULT_NAME[] =
"default";
48 static const char _APPLICATION_OCTETSTREAM[] =
"application/octet-stream";
52 K_GLOBAL_STATIC( DefaultItemSerializerPlugin, s_defaultItemSerializerPlugin )
62 explicit PluginEntry(
const QString &identifier, QObject *plugin = 0 )
63 : mIdentifier( identifier ), mPlugin( plugin )
67 QObject* plugin()
const
72 QObject *
object = PluginLoader::self()->createForName( mIdentifier );
74 kWarning() <<
"ItemSerializerPluginLoader: "
75 <<
"plugin" << mIdentifier <<
"is not valid!" << endl;
78 mPlugin = s_defaultItemSerializerPlugin;
82 if ( !qobject_cast<ItemSerializerPlugin*>( mPlugin ) ) {
83 kWarning() <<
"ItemSerializerPluginLoader: "
84 <<
"plugin" << mIdentifier <<
"doesn't provide interface ItemSerializerPlugin!" << endl;
87 mPlugin = s_defaultItemSerializerPlugin;
95 const char * pluginClassName()
const
97 return plugin()->metaObject()->className();
100 QString identifier()
const
105 bool operator<(
const PluginEntry &other )
const
107 return mIdentifier < other.mIdentifier;
110 bool operator<(
const QString &identifier )
const
112 return mIdentifier < identifier;
117 mutable QObject *mPlugin;
120 static bool operator<(
const QString &identifier,
const PluginEntry &entry )
122 return identifier < entry.identifier();
128 explicit MimeTypeEntry(
const QString & mimeType )
129 : m_mimeType( mimeType ), m_plugins(), m_pluginsByMetaTypeId() {}
131 QString type()
const {
return m_mimeType; }
133 void add(
const QByteArray & class_,
const PluginEntry & entry ) {
134 m_pluginsByMetaTypeId.clear();
135 m_plugins.insert( class_, entry );
138 const PluginEntry * plugin(
const QByteArray & class_ )
const {
139 const QHash<QByteArray,PluginEntry>::const_iterator it = m_plugins.find( class_ );
140 return it == m_plugins.end() ? 0 : it.operator->() ;
143 const PluginEntry * defaultPlugin()
const {
145 if (
const PluginEntry * pe = plugin( DEFAULT_NAME ) )
150 bool sawZero =
false;
151 for ( QMap<
int,QHash<QByteArray,PluginEntry>::const_iterator>::const_iterator it = m_pluginsByMetaTypeId.constBegin(), end = m_pluginsByMetaTypeId.constEnd() ; it != end ; ++it )
155 if ( *it != m_plugins.end() )
156 return it->operator->();
159 for ( QHash<QByteArray,PluginEntry>::const_iterator it = m_plugins.constBegin(), end = m_plugins.constEnd() ; it != end ; ++it )
160 if ( it.key() == LEGACY_NAME )
163 return it.operator->() ;
171 const PluginEntry * plugin(
int metaTypeId )
const {
172 const QMap<int,QHash<QByteArray,PluginEntry>::const_iterator> & c_pluginsByMetaTypeId = m_pluginsByMetaTypeId;
173 QMap<int,QHash<QByteArray,PluginEntry>::const_iterator>::const_iterator it = c_pluginsByMetaTypeId.find( metaTypeId );
174 if ( it == c_pluginsByMetaTypeId.end() )
175 it = QMap<
int,QHash<QByteArray,PluginEntry>::const_iterator>::const_iterator( m_pluginsByMetaTypeId.insert( metaTypeId, m_plugins.find( metaTypeId ? QMetaType::typeName( metaTypeId ) : LEGACY_NAME ) ) );
176 return *it == m_plugins.end() ? 0 : it->operator->() ;
179 const PluginEntry * plugin(
const QVector<int> & metaTypeIds,
int & chosen )
const {
180 bool sawZero =
false;
181 for ( QVector<int>::const_iterator it = metaTypeIds.begin(), end = metaTypeIds.end() ; it != end ; ++it )
184 }
else if (
const PluginEntry *
const entry = plugin( *it ) ) {
197 QHash< QByteArray, PluginEntry > m_plugins;
198 mutable QMap<int,QHash<QByteArray,PluginEntry>::const_iterator> m_pluginsByMetaTypeId;
201 static bool operator<(
const MimeTypeEntry & lhs,
const MimeTypeEntry & rhs )
203 return lhs.type() < rhs.type() ;
206 static bool operator<(
const MimeTypeEntry & lhs,
const QString & rhs )
208 return lhs.type() < rhs ;
211 static bool operator<(
const QString & lhs,
const MimeTypeEntry & rhs )
213 return lhs < rhs.type();
216 static QString format(
const QString & mimeType,
const QVector<int> & metaTypeIds ) {
217 if ( metaTypeIds.empty() )
218 return QLatin1String(
"default for " ) + mimeType;
219 QStringList classTypes;
220 Q_FOREACH(
int metaTypeId, metaTypeIds )
221 classTypes.push_back( QString::fromLatin1( metaTypeId ? QMetaType::typeName( metaTypeId ) : LEGACY_NAME ) );
222 return mimeType + QLatin1String("@{
") + classTypes.join(QLatin1String(",
")) + QLatin1Char('}');
229 : mDefaultPlugin( PluginEntry( QLatin1String( "application/octet-stream@QByteArray
" ), s_defaultItemSerializerPlugin ) )
231 const PluginLoader* pl = PluginLoader::self();
233 kWarning() << "Cannot instantiate plugin loader!
" << endl;
236 const QStringList names = pl->names();
237 kDebug() << "ItemSerializerPluginLoader:
"
238 << "found
" << names.size() << "plugins.
" << endl;
239 QMap<QString,MimeTypeEntry> map;
240 QRegExp rx( QLatin1String( "(.+)@(.+)
" ) );
241 Q_FOREACH ( const QString & name, names )
242 if ( rx.exactMatch( name ) ) {
243 KMimeType::Ptr mime = KMimeType::mimeType( rx.cap(1), KMimeType::ResolveAliases );
245 const QString mimeType = mime->name();
246 const QByteArray classType = rx.cap(2).toLatin1();
247 QMap<QString,MimeTypeEntry>::iterator it = map.find( mimeType );
248 if ( it == map.end() )
249 it = map.insert( mimeType, MimeTypeEntry( mimeType ) );
250 it->add( classType, PluginEntry( name ) );
253 kDebug() << "ItemSerializerPluginLoader:
"
254 << "name
" << name << "doesn
't look like mimetype@classtype" << endl;
256 const QString APPLICATION_OCTETSTREAM = QLatin1String( _APPLICATION_OCTETSTREAM );
257 QMap<QString,MimeTypeEntry>::iterator it = map.find( APPLICATION_OCTETSTREAM );
258 if ( it == map.end() )
259 it = map.insert( APPLICATION_OCTETSTREAM, MimeTypeEntry( APPLICATION_OCTETSTREAM ) );
260 it->add( "QByteArray", mDefaultPlugin );
261 it->add( LEGACY_NAME, mDefaultPlugin );
262 const int size = map.size();
263 allMimeTypes.reserve( size );
264 std::copy( map.begin(), map.end(),
265 std::back_inserter( allMimeTypes ) );
268 QObject * findBestMatch( const QString & type, const QVector<int> & metaTypeId, TypePluginLoader::Options opt ) {
269 if ( QObject * const plugin = findBestMatch( type, metaTypeId ) ) {
270 if ( ( opt & TypePluginLoader::NoDefault ) && plugin == mDefaultPlugin.plugin() )
277 QObject * findBestMatch( const QString & type, const QVector<int> & metaTypeIds ) {
278 if ( QObject * const plugin = cacheLookup( type, metaTypeIds ) )
279 // plugin cached, so let's take that one
282 QObject *
const plugin = findBestMatchImpl( type, metaTypeIds, chosen );
283 if ( metaTypeIds.empty() )
285 cachedDefaultPlugins[type] = plugin;
287 cachedPlugins[type][chosen] = plugin;
292 QObject * findBestMatchImpl(
const QString &type,
const QVector<int> & metaTypeIds,
int & chosen )
const
294 KMimeType::Ptr mimeType = KMimeType::mimeType( type, KMimeType::ResolveAliases );
295 if ( mimeType.isNull() )
296 return mDefaultPlugin.plugin();
299 QVector<int> matchingIndexes;
300 for (
int i = 0, end = allMimeTypes.size(); i < end; ++i ) {
301 if ( mimeType->is( allMimeTypes[i].type() ) )
302 matchingIndexes.append( i );
307 if ( matchingIndexes.size() <= 1 ) {
308 order.push_back( 0 );
310 boost::adjacency_list<> graph( matchingIndexes.size() );
311 for (
int i = 0, end = matchingIndexes.size() ; i != end ; ++i ) {
312 KMimeType::Ptr mimeType = KMimeType::mimeType( allMimeTypes[matchingIndexes[i]].type(), KMimeType::ResolveAliases );
313 if ( mimeType.isNull() )
315 for (
int j = 0; j != end; ++j ) {
316 if ( i != j && mimeType->is( allMimeTypes[matchingIndexes[j]].type() ) )
317 boost::add_edge( j, i, graph );
321 order.reserve( matchingIndexes.size() );
323 boost::topological_sort( graph, std::back_inserter( order ) );
324 }
catch ( boost::not_a_dag &e ) {
325 kWarning() <<
"Mimetype tree is not a DAG!";
326 return mDefaultPlugin.plugin();
332 for ( QVector<int>::const_iterator it = order.constBegin(), end = order.constEnd() ; it != end ; ++it ) {
335 const MimeTypeEntry & mt = allMimeTypes[matchingIndexes[*it]];
336 if ( metaTypeIds.empty() ) {
337 if (
const PluginEntry *
const entry = mt.defaultPlugin() ) {
339 return entry->plugin();
343 }
else if (
const PluginEntry *
const entry = mt.plugin( metaTypeIds, chosen ) ) {
345 return entry->plugin();
353 return mDefaultPlugin.plugin();
356 std::vector<MimeTypeEntry> allMimeTypes;
357 QHash<QString, QMap<int,QObject*> > cachedPlugins;
358 QHash<QString, QObject*> cachedDefaultPlugins;
361 QObject * cacheLookup(
const QString & mimeType,
const QVector<int> & metaTypeIds )
const {
362 if ( metaTypeIds.empty() ) {
363 const QHash<QString,QObject*>::const_iterator hit = cachedDefaultPlugins.find( mimeType );
364 if ( hit != cachedDefaultPlugins.end() )
368 const QHash<QString,QMap<int,QObject*> >::const_iterator hit = cachedPlugins.find( mimeType );
369 if ( hit == cachedPlugins.end() )
371 bool sawZero =
false;
372 for ( QVector<int>::const_iterator it = metaTypeIds.begin(), end = metaTypeIds.end() ; it != end ; ++it )
375 else if ( QObject *
const o = hit->value( *it ) )
378 return hit->value( 0 );
383 PluginEntry mDefaultPlugin;
386 K_GLOBAL_STATIC( PluginRegistry, s_pluginRegistry )
388 QObject* TypePluginLoader::objectForMimeTypeAndClass( const QString &mimetype, const QVector<
int> & metaTypeIds, Options opt )
390 return s_pluginRegistry->findBestMatch( mimetype, metaTypeIds, opt );
394 QObject* TypePluginLoader::legacyObjectForMimeType(
const QString &mimetype ) {
396 return objectForMimeTypeAndClass( mimetype, QVector<int>( 1, 0 ) );