21 #include "typepluginloader_p.h"
24 #include "itemserializer_p.h"
25 #include "itemserializerplugin.h"
29 #include <kmimetype.h>
33 #include <QtCore/QHash>
34 #include <QtCore/QString>
35 #include <QtCore/QByteArray>
36 #include <QtCore/QStringList>
38 #include <boost/graph/adjacency_list.hpp>
39 #include <boost/graph/topological_sort.hpp>
42 #include "pluginloader_p.h"
47 static const char LEGACY_NAME[] =
"legacy";
48 static const char DEFAULT_NAME[] =
"default";
49 static const char _APPLICATION_OCTETSTREAM[] =
"application/octet-stream";
53 K_GLOBAL_STATIC( DefaultItemSerializerPlugin, s_defaultItemSerializerPlugin )
63 explicit PluginEntry(
const QString &identifier, QObject *plugin = 0 )
64 : mIdentifier( identifier ), mPlugin( plugin )
68 QObject* plugin()
const
73 QObject *
object = PluginLoader::self()->createForName( mIdentifier );
75 kWarning() <<
"ItemSerializerPluginLoader: "
76 <<
"plugin" << mIdentifier <<
"is not valid!" << endl;
79 mPlugin = s_defaultItemSerializerPlugin;
83 if ( !qobject_cast<ItemSerializerPlugin*>( mPlugin ) ) {
84 kWarning() <<
"ItemSerializerPluginLoader: "
85 <<
"plugin" << mIdentifier <<
"doesn't provide interface ItemSerializerPlugin!" << endl;
88 mPlugin = s_defaultItemSerializerPlugin;
96 const char * pluginClassName()
const
98 return plugin()->metaObject()->className();
101 QString identifier()
const
106 bool operator<(
const PluginEntry &other )
const
108 return mIdentifier < other.mIdentifier;
111 bool operator<(
const QString &identifier )
const
113 return mIdentifier < identifier;
118 mutable QObject *mPlugin;
121 static bool operator<(
const QString &identifier,
const PluginEntry &entry )
123 return identifier < entry.identifier();
129 explicit MimeTypeEntry(
const QString & mimeType )
130 : m_mimeType( mimeType ), m_plugins(), m_pluginsByMetaTypeId() {}
132 QString type()
const {
return m_mimeType; }
134 void add(
const QByteArray & class_,
const PluginEntry & entry ) {
135 m_pluginsByMetaTypeId.clear();
136 m_plugins.insert( class_, entry );
139 const PluginEntry * plugin(
const QByteArray & class_ )
const {
140 const QHash<QByteArray,PluginEntry>::const_iterator it = m_plugins.find( class_ );
141 return it == m_plugins.end() ? 0 : it.operator->() ;
144 const PluginEntry * defaultPlugin()
const {
146 if (
const PluginEntry * pe = plugin( DEFAULT_NAME ) )
151 bool sawZero =
false;
152 for ( QMap<
int,QHash<QByteArray,PluginEntry>::const_iterator>::const_iterator it = m_pluginsByMetaTypeId.constBegin(), end = m_pluginsByMetaTypeId.constEnd() ; it != end ; ++it )
156 if ( *it != m_plugins.end() )
157 return it->operator->();
160 for ( QHash<QByteArray,PluginEntry>::const_iterator it = m_plugins.constBegin(), end = m_plugins.constEnd() ; it != end ; ++it )
161 if ( it.key() == LEGACY_NAME )
164 return it.operator->() ;
172 const PluginEntry * plugin(
int metaTypeId )
const {
173 const QMap<int,QHash<QByteArray,PluginEntry>::const_iterator> & c_pluginsByMetaTypeId = m_pluginsByMetaTypeId;
174 QMap<int,QHash<QByteArray,PluginEntry>::const_iterator>::const_iterator it = c_pluginsByMetaTypeId.find( metaTypeId );
175 if ( it == c_pluginsByMetaTypeId.end() )
176 it = QMap<
int,QHash<QByteArray,PluginEntry>::const_iterator>::const_iterator( m_pluginsByMetaTypeId.insert( metaTypeId, m_plugins.find( metaTypeId ? QMetaType::typeName( metaTypeId ) : LEGACY_NAME ) ) );
177 return *it == m_plugins.end() ? 0 : it->operator->() ;
180 const PluginEntry * plugin(
const QVector<int> & metaTypeIds,
int & chosen )
const {
181 bool sawZero =
false;
182 for ( QVector<int>::const_iterator it = metaTypeIds.begin(), end = metaTypeIds.end() ; it != end ; ++it )
185 }
else if (
const PluginEntry *
const entry = plugin( *it ) ) {
198 QHash< QByteArray, PluginEntry > m_plugins;
199 mutable QMap<int,QHash<QByteArray,PluginEntry>::const_iterator> m_pluginsByMetaTypeId;
202 static bool operator<(
const MimeTypeEntry & lhs,
const MimeTypeEntry & rhs )
204 return lhs.type() < rhs.type() ;
207 static bool operator<(
const MimeTypeEntry & lhs,
const QString & rhs )
209 return lhs.type() < rhs ;
212 static bool operator<(
const QString & lhs,
const MimeTypeEntry & rhs )
214 return lhs < rhs.type();
217 static QString format(
const QString & mimeType,
const QVector<int> & metaTypeIds ) {
218 if ( metaTypeIds.empty() )
219 return QLatin1String(
"default for " ) + mimeType;
220 QStringList classTypes;
221 Q_FOREACH(
int metaTypeId, metaTypeIds )
222 classTypes.push_back( QString::fromLatin1( metaTypeId ? QMetaType::typeName( metaTypeId ) : LEGACY_NAME ) );
223 return mimeType + QLatin1String("@{
") + classTypes.join(QLatin1String(",
")) + QLatin1Char('}');
230 : mDefaultPlugin( PluginEntry( QLatin1String( "application/octet-stream@QByteArray
" ), s_defaultItemSerializerPlugin ) ),
233 const PluginLoader* pl = PluginLoader::self();
235 kWarning() << "Cannot instantiate plugin loader!
" << endl;
238 const QStringList names = pl->names();
239 kDebug() << "ItemSerializerPluginLoader:
"
240 << "found
" << names.size() << "plugins.
" << endl;
241 QMap<QString,MimeTypeEntry> map;
242 QRegExp rx( QLatin1String( "(.+)@(.+)
" ) );
243 Q_FOREACH ( const QString & name, names )
244 if ( rx.exactMatch( name ) ) {
245 KMimeType::Ptr mime = KMimeType::mimeType( rx.cap(1), KMimeType::ResolveAliases );
247 const QString mimeType = mime->name();
248 const QByteArray classType = rx.cap(2).toLatin1();
249 QMap<QString,MimeTypeEntry>::iterator it = map.find( mimeType );
250 if ( it == map.end() )
251 it = map.insert( mimeType, MimeTypeEntry( mimeType ) );
252 it->add( classType, PluginEntry( name ) );
255 kDebug() << "ItemSerializerPluginLoader:
"
256 << "name
" << name << "doesn
't look like mimetype@classtype" << endl;
258 const QString APPLICATION_OCTETSTREAM = QLatin1String( _APPLICATION_OCTETSTREAM );
259 QMap<QString,MimeTypeEntry>::iterator it = map.find( APPLICATION_OCTETSTREAM );
260 if ( it == map.end() )
261 it = map.insert( APPLICATION_OCTETSTREAM, MimeTypeEntry( APPLICATION_OCTETSTREAM ) );
262 it->add( "QByteArray", mDefaultPlugin );
263 it->add( LEGACY_NAME, mDefaultPlugin );
264 const int size = map.size();
265 allMimeTypes.reserve( size );
266 std::copy( map.begin(), map.end(),
267 std::back_inserter( allMimeTypes ) );
270 QObject * findBestMatch( const QString & type, const QVector<int> & metaTypeId, TypePluginLoader::Options opt ) {
271 if ( QObject * const plugin = findBestMatch( type, metaTypeId ) ) {
272 if ( ( opt & TypePluginLoader::NoDefault ) && plugin == mDefaultPlugin.plugin() )
279 QObject * findBestMatch( const QString & type, const QVector<int> & metaTypeIds ) {
280 if ( mOverridePlugin ) {
281 return mOverridePlugin;
283 if ( QObject * const plugin = cacheLookup( type, metaTypeIds ) )
284 // plugin cached, so let's take that one
287 QObject *
const plugin = findBestMatchImpl( type, metaTypeIds, chosen );
288 if ( metaTypeIds.empty() )
290 cachedDefaultPlugins[type] = plugin;
292 cachedPlugins[type][chosen] = plugin;
296 void overrideDefaultPlugin( QObject *p ) {
301 QObject * findBestMatchImpl(
const QString &type,
const QVector<int> & metaTypeIds,
int & chosen )
const
303 KMimeType::Ptr mimeType = KMimeType::mimeType( type, KMimeType::ResolveAliases );
304 if ( mimeType.isNull() )
305 return mDefaultPlugin.plugin();
308 QVector<int> matchingIndexes;
309 for (
int i = 0, end = allMimeTypes.size(); i < end; ++i ) {
310 if ( mimeType->is( allMimeTypes[i].type() ) )
311 matchingIndexes.append( i );
316 if ( matchingIndexes.size() <= 1 ) {
317 order.push_back( 0 );
319 boost::adjacency_list<> graph( matchingIndexes.size() );
320 for (
int i = 0, end = matchingIndexes.size() ; i != end ; ++i ) {
321 KMimeType::Ptr mimeType = KMimeType::mimeType( allMimeTypes[matchingIndexes[i]].type(), KMimeType::ResolveAliases );
322 if ( mimeType.isNull() )
324 for (
int j = 0; j != end; ++j ) {
325 if ( i != j && mimeType->is( allMimeTypes[matchingIndexes[j]].type() ) )
326 boost::add_edge( j, i, graph );
330 order.reserve( matchingIndexes.size() );
332 boost::topological_sort( graph, std::back_inserter( order ) );
333 }
catch ( boost::not_a_dag &e ) {
334 kWarning() <<
"Mimetype tree is not a DAG!";
335 return mDefaultPlugin.plugin();
341 for ( QVector<int>::const_iterator it = order.constBegin(), end = order.constEnd() ; it != end ; ++it ) {
344 const MimeTypeEntry & mt = allMimeTypes[matchingIndexes[*it]];
345 if ( metaTypeIds.empty() ) {
346 if (
const PluginEntry *
const entry = mt.defaultPlugin() ) {
348 return entry->plugin();
352 }
else if (
const PluginEntry *
const entry = mt.plugin( metaTypeIds, chosen ) ) {
354 return entry->plugin();
362 return mDefaultPlugin.plugin();
365 std::vector<MimeTypeEntry> allMimeTypes;
366 QHash<QString, QMap<int,QObject*> > cachedPlugins;
367 QHash<QString, QObject*> cachedDefaultPlugins;
370 QObject * cacheLookup(
const QString & mimeType,
const QVector<int> & metaTypeIds )
const {
371 if ( metaTypeIds.empty() ) {
372 const QHash<QString,QObject*>::const_iterator hit = cachedDefaultPlugins.find( mimeType );
373 if ( hit != cachedDefaultPlugins.end() )
377 const QHash<QString,QMap<int,QObject*> >::const_iterator hit = cachedPlugins.find( mimeType );
378 if ( hit == cachedPlugins.end() )
380 bool sawZero =
false;
381 for ( QVector<int>::const_iterator it = metaTypeIds.begin(), end = metaTypeIds.end() ; it != end ; ++it )
384 else if ( QObject *
const o = hit->value( *it ) )
387 return hit->value( 0 );
392 PluginEntry mDefaultPlugin;
393 QObject *mOverridePlugin;
396 K_GLOBAL_STATIC( PluginRegistry, s_pluginRegistry )
398 QObject* TypePluginLoader::objectForMimeTypeAndClass( const QString &mimetype, const QVector<
int> & metaTypeIds, Options opt )
400 return s_pluginRegistry->findBestMatch( mimetype, metaTypeIds, opt );
404 QObject* TypePluginLoader::legacyObjectForMimeType(
const QString &mimetype ) {
406 return objectForMimeTypeAndClass( mimetype, QVector<int>( 1, 0 ) );
434 s_pluginRegistry->overrideDefaultPlugin( p );
void overridePluginLookup(QObject *plugin)
Override the plugin-lookup with plugin.
ItemSerializerPlugin * pluginForMimeTypeAndClass(const QString &mimetype, const QVector< int > &metaTypeIds, Options options=NoOptions)
Returns the item serializer plugin that matches the given mimetype, and any of the classes described ...
ItemSerializerPlugin * defaultPluginForMimeType(const QString &mimetype)
Returns the default item serializer plugin that matches the given mimetype.
QObject * objectForMimeTypeAndClass(const QString &mimetype, const QVector< int > &metaTypeIds, Options options=NoOptions)
Returns the type plugin object that matches the given mimetype, and any of the classes described by m...
QObject * defaultObjectForMimeType(const QString &mimetype)
Returns the default type plugin object that matches the given mimetype.
The base class for item type serializer plugins.