• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.11.3 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
typepluginloader.cpp
1 /*
2  Copyright (c) 2007 Till Adam <adam@kde.org>
3  Copyright (c) 2007 Volker Krause <vkrause@kde.org>
4 
5  This library is free software; you can redistribute it and/or modify it
6  under the terms of the GNU Library General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or (at your
8  option) any later version.
9 
10  This library is distributed in the hope that it will be useful, but WITHOUT
11  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13  License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to the
17  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  02110-1301, USA.
19 */
20 
21 #include "typepluginloader_p.h"
22 
23 #include "item.h"
24 #include "itemserializer_p.h"
25 #include "itemserializerplugin.h"
26 
27 // KDE core
28 #include <kdebug.h>
29 #include <kmimetype.h>
30 #include <kglobal.h>
31 
32 // Qt
33 #include <QtCore/QHash>
34 #include <QtCore/QString>
35 #include <QtCore/QByteArray>
36 #include <QtCore/QStringList>
37 
38 #include <boost/graph/adjacency_list.hpp>
39 #include <boost/graph/topological_sort.hpp>
40 
41 // temporary
42 #include "pluginloader_p.h"
43 
44 #include <vector>
45 #include <cassert>
46 
47 static const char LEGACY_NAME[] = "legacy";
48 static const char DEFAULT_NAME[] = "default";
49 static const char _APPLICATION_OCTETSTREAM[] = "application/octet-stream";
50 
51 namespace Akonadi {
52 
53 K_GLOBAL_STATIC( DefaultItemSerializerPlugin, s_defaultItemSerializerPlugin )
54 
55 class PluginEntry
56 {
57  public:
58  PluginEntry()
59  : mPlugin( 0 )
60  {
61  }
62 
63  explicit PluginEntry( const QString &identifier, QObject *plugin = 0 )
64  : mIdentifier( identifier ), mPlugin( plugin )
65  {
66  }
67 
68  QObject* plugin() const
69  {
70  if ( mPlugin )
71  return mPlugin;
72 
73  QObject *object = PluginLoader::self()->createForName( mIdentifier );
74  if ( !object ) {
75  kWarning() << "ItemSerializerPluginLoader: "
76  << "plugin" << mIdentifier << "is not valid!" << endl;
77 
78  // we try to use the default in that case
79  mPlugin = s_defaultItemSerializerPlugin;
80  }
81 
82  mPlugin = object;
83  if ( !qobject_cast<ItemSerializerPlugin*>( mPlugin ) ) {
84  kWarning() << "ItemSerializerPluginLoader: "
85  << "plugin" << mIdentifier << "doesn't provide interface ItemSerializerPlugin!" << endl;
86 
87  // we try to use the default in that case
88  mPlugin = s_defaultItemSerializerPlugin;
89  }
90 
91  Q_ASSERT( mPlugin );
92 
93  return mPlugin;
94  }
95 
96  const char * pluginClassName() const
97  {
98  return plugin()->metaObject()->className();
99  }
100 
101  QString identifier() const
102  {
103  return mIdentifier;
104  }
105 
106  bool operator<( const PluginEntry &other ) const
107  {
108  return mIdentifier < other.mIdentifier;
109  }
110 
111  bool operator<( const QString &identifier ) const
112  {
113  return mIdentifier < identifier;
114  }
115 
116  private:
117  QString mIdentifier;
118  mutable QObject *mPlugin;
119 };
120 
121 static bool operator<( const QString &identifier, const PluginEntry &entry )
122 {
123  return identifier < entry.identifier();
124 }
125 
126 class MimeTypeEntry
127 {
128 public:
129  explicit MimeTypeEntry( const QString & mimeType )
130  : m_mimeType( mimeType ), m_plugins(), m_pluginsByMetaTypeId() {}
131 
132  QString type() const { return m_mimeType; }
133 
134  void add( const QByteArray & class_, const PluginEntry & entry ) {
135  m_pluginsByMetaTypeId.clear(); // iterators will be invalidated by next line
136  m_plugins.insert( class_, entry );
137  }
138 
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->() ;
142  }
143 
144  const PluginEntry * defaultPlugin() const {
145  // 1. If there's an explicit default plugin, use that one:
146  if ( const PluginEntry * pe = plugin( DEFAULT_NAME ) )
147  return pe;
148 
149  // 2. Otherwise, look through the already instantiated plugins,
150  // and return one of them (preferably not the legacy one):
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 )
153  if ( it.key() == 0 )
154  sawZero = true;
155  else
156  if ( *it != m_plugins.end() )
157  return it->operator->();
158 
159  // 3. Otherwise, look through the whole list (again, preferably not the legacy one):
160  for ( QHash<QByteArray,PluginEntry>::const_iterator it = m_plugins.constBegin(), end = m_plugins.constEnd() ; it != end ; ++it )
161  if ( it.key() == LEGACY_NAME )
162  sawZero = true;
163  else
164  return it.operator->() ;
165 
166  // 4. take the legacy one:
167  if ( sawZero )
168  return plugin( 0 );
169  return 0;
170  }
171 
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->() ;
178  }
179 
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 )
183  if ( *it == 0 ) {
184  sawZero = true; // skip the legacy type and see if we can find something else first
185  } else if ( const PluginEntry * const entry = plugin( *it ) ) {
186  chosen = *it;
187  return entry;
188  }
189  if ( sawZero ) {
190  chosen = 0;
191  return plugin( 0 );
192  }
193  return 0;
194  }
195 
196 private:
197  QString m_mimeType;
198  QHash< QByteArray/* class */, PluginEntry > m_plugins;
199  mutable QMap<int,QHash<QByteArray,PluginEntry>::const_iterator> m_pluginsByMetaTypeId;
200 };
201 
202 static bool operator<( const MimeTypeEntry & lhs, const MimeTypeEntry & rhs )
203 {
204  return lhs.type() < rhs.type() ;
205 }
206 
207 static bool operator<( const MimeTypeEntry & lhs, const QString & rhs )
208 {
209  return lhs.type() < rhs ;
210 }
211 
212 static bool operator<( const QString & lhs, const MimeTypeEntry & rhs )
213 {
214  return lhs < rhs.type();
215 }
216 
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('}');
224 }
225 
226 class PluginRegistry
227 {
228  public:
229  PluginRegistry()
230  : mDefaultPlugin( PluginEntry( QLatin1String( "application/octet-stream@QByteArray" ), s_defaultItemSerializerPlugin ) )
231  {
232  const PluginLoader* pl = PluginLoader::self();
233  if ( !pl ) {
234  kWarning() << "Cannot instantiate plugin loader!" << endl;
235  return;
236  }
237  const QStringList names = pl->names();
238  kDebug() << "ItemSerializerPluginLoader: "
239  << "found" << names.size() << "plugins." << endl;
240  QMap<QString,MimeTypeEntry> map;
241  QRegExp rx( QLatin1String( "(.+)@(.+)" ) );
242  Q_FOREACH ( const QString & name, names )
243  if ( rx.exactMatch( name ) ) {
244  KMimeType::Ptr mime = KMimeType::mimeType( rx.cap(1), KMimeType::ResolveAliases );
245  if ( mime ) {
246  const QString mimeType = mime->name();
247  const QByteArray classType = rx.cap(2).toLatin1();
248  QMap<QString,MimeTypeEntry>::iterator it = map.find( mimeType );
249  if ( it == map.end() )
250  it = map.insert( mimeType, MimeTypeEntry( mimeType ) );
251  it->add( classType, PluginEntry( name ) );
252  }
253  } else {
254  kDebug() << "ItemSerializerPluginLoader: "
255  << "name" << name << "doesn't look like mimetype@classtype" << endl;
256  }
257  const QString APPLICATION_OCTETSTREAM = QLatin1String( _APPLICATION_OCTETSTREAM );
258  QMap<QString,MimeTypeEntry>::iterator it = map.find( APPLICATION_OCTETSTREAM );
259  if ( it == map.end() )
260  it = map.insert( APPLICATION_OCTETSTREAM, MimeTypeEntry( APPLICATION_OCTETSTREAM ) );
261  it->add( "QByteArray", mDefaultPlugin );
262  it->add( LEGACY_NAME, mDefaultPlugin );
263  const int size = map.size();
264  allMimeTypes.reserve( size );
265  std::copy( map.begin(), map.end(),
266  std::back_inserter( allMimeTypes ) );
267  }
268 
269  QObject * findBestMatch( const QString & type, const QVector<int> & metaTypeId, TypePluginLoader::Options opt ) {
270  if ( QObject * const plugin = findBestMatch( type, metaTypeId ) ) {
271  if ( ( opt & TypePluginLoader::NoDefault ) && plugin == mDefaultPlugin.plugin() )
272  return 0;
273  return plugin;
274  }
275  return 0;
276  }
277 
278  QObject * findBestMatch( const QString & type, const QVector<int> & metaTypeIds ) {
279  if ( QObject * const plugin = cacheLookup( type, metaTypeIds ) )
280  // plugin cached, so let's take that one
281  return plugin;
282  int chosen = -1;
283  QObject * const plugin = findBestMatchImpl( type, metaTypeIds, chosen );
284  if ( metaTypeIds.empty() )
285  if ( plugin )
286  cachedDefaultPlugins[type] = plugin;
287  if ( chosen >= 0 )
288  cachedPlugins[type][chosen] = plugin;
289  return plugin;
290  }
291 
292 private:
293  QObject * findBestMatchImpl( const QString &type, const QVector<int> & metaTypeIds, int & chosen ) const
294  {
295  KMimeType::Ptr mimeType = KMimeType::mimeType( type, KMimeType::ResolveAliases );
296  if ( mimeType.isNull() )
297  return mDefaultPlugin.plugin();
298 
299  // step 1: find all plugins that match at all
300  QVector<int> matchingIndexes;
301  for ( int i = 0, end = allMimeTypes.size(); i < end; ++i ) {
302  if ( mimeType->is( allMimeTypes[i].type() ) )
303  matchingIndexes.append( i );
304  }
305 
306  // step 2: if we have more than one match, find the most specific one using topological sort
307  QVector<int> order;
308  if ( matchingIndexes.size() <= 1 ) {
309  order.push_back( 0 );
310  } else {
311  boost::adjacency_list<> graph( matchingIndexes.size() );
312  for ( int i = 0, end = matchingIndexes.size() ; i != end ; ++i ) {
313  KMimeType::Ptr mimeType = KMimeType::mimeType( allMimeTypes[matchingIndexes[i]].type(), KMimeType::ResolveAliases );
314  if ( mimeType.isNull() )
315  continue;
316  for ( int j = 0; j != end; ++j ) {
317  if ( i != j && mimeType->is( allMimeTypes[matchingIndexes[j]].type() ) )
318  boost::add_edge( j, i, graph );
319  }
320  }
321 
322  order.reserve( matchingIndexes.size() );
323  try {
324  boost::topological_sort( graph, std::back_inserter( order ) );
325  } catch ( boost::not_a_dag &e ) {
326  kWarning() << "Mimetype tree is not a DAG!";
327  return mDefaultPlugin.plugin();
328  }
329  }
330 
331  // step 3: ask each one in turn if it can handle any of the metaTypeIds:
332 // kDebug() << "Looking for " << format( type, metaTypeIds );
333  for ( QVector<int>::const_iterator it = order.constBegin(), end = order.constEnd() ; it != end ; ++it ) {
334 // kDebug() << " Considering serializer plugin for type" << allMimeTypes[matchingIndexes[*it]].type()
335 // // << "as the closest match";
336  const MimeTypeEntry & mt = allMimeTypes[matchingIndexes[*it]];
337  if ( metaTypeIds.empty() ) {
338  if ( const PluginEntry * const entry = mt.defaultPlugin() ) {
339 // kDebug() << " -> got " << entry->pluginClassName() << " and am happy with it.";
340  return entry->plugin();
341  } else {
342 // kDebug() << " -> no default plugin for this mime type, trying next";
343  }
344  } else if ( const PluginEntry * const entry = mt.plugin( metaTypeIds, chosen ) ) {
345 // kDebug() << " -> got " << entry->pluginClassName() << " and am happy with it.";
346  return entry->plugin();
347  } else {
348 // kDebug() << " -> can't handle any of the types, trying next";
349  }
350  }
351 
352 // kDebug() << " No further candidates, using default plugin";
353  // no luck? Use the default plugin
354  return mDefaultPlugin.plugin();
355  }
356 
357  std::vector<MimeTypeEntry> allMimeTypes;
358  QHash<QString, QMap<int,QObject*> > cachedPlugins;
359  QHash<QString, QObject*> cachedDefaultPlugins;
360 
361  // ### cache NULLs, too
362  QObject * cacheLookup( const QString & mimeType, const QVector<int> & metaTypeIds ) const {
363  if ( metaTypeIds.empty() ) {
364  const QHash<QString,QObject*>::const_iterator hit = cachedDefaultPlugins.find( mimeType );
365  if ( hit != cachedDefaultPlugins.end() )
366  return *hit;
367  }
368 
369  const QHash<QString,QMap<int,QObject*> >::const_iterator hit = cachedPlugins.find( mimeType );
370  if ( hit == cachedPlugins.end() )
371  return 0;
372  bool sawZero = false;
373  for ( QVector<int>::const_iterator it = metaTypeIds.begin(), end = metaTypeIds.end() ; it != end ; ++it )
374  if ( *it == 0 )
375  sawZero = true; // skip the legacy type and see if we can find something else first
376  else if ( QObject * const o = hit->value( *it ) )
377  return o;
378  if ( sawZero )
379  return hit->value( 0 );
380  return 0;
381  }
382 
383  private:
384  PluginEntry mDefaultPlugin;
385 };
386 
387 K_GLOBAL_STATIC( PluginRegistry, s_pluginRegistry )
388 
389 QObject* TypePluginLoader::objectForMimeTypeAndClass( const QString &mimetype, const QVector<int> & metaTypeIds, Options opt )
390 {
391  return s_pluginRegistry->findBestMatch( mimetype, metaTypeIds, opt );
392 }
393 
394 #if 0
395 QObject* TypePluginLoader::legacyObjectForMimeType( const QString &mimetype ) {
396  // ### impl specifically - only works b/c vector isn't used in impl ###
397  return objectForMimeTypeAndClass( mimetype, QVector<int>( 1, 0 ) );
398 }
399 #endif
400 
401 QObject* TypePluginLoader::defaultObjectForMimeType( const QString &mimetype ) {
402  return objectForMimeTypeAndClass( mimetype, QVector<int>() );
403 }
404 
405 ItemSerializerPlugin* TypePluginLoader::pluginForMimeTypeAndClass( const QString &mimetype, const QVector<int> &metaTypeIds, Options opt )
406 {
407  return qobject_cast<ItemSerializerPlugin*>( objectForMimeTypeAndClass( mimetype, metaTypeIds, opt ) );
408 }
409 
410 #if 0
411 ItemSerializerPlugin* TypePluginLoader::legacyPluginForMimeType( const QString &mimetype ) {
412  ItemSerializerPlugin* plugin = qobject_cast<ItemSerializerPlugin*>( legacyObjectForMimeType( mimetype ) );
413  Q_ASSERT( plugin );
414  return plugin;
415 }
416 #endif
417 
418 ItemSerializerPlugin* TypePluginLoader::defaultPluginForMimeType( const QString &mimetype ) {
419  ItemSerializerPlugin* plugin = qobject_cast<ItemSerializerPlugin*>( defaultObjectForMimeType( mimetype ) );
420  Q_ASSERT( plugin );
421  return plugin;
422 }
423 
424 
425 }
Akonadi::TypePluginLoader::pluginForMimeTypeAndClass
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 ...
Definition: typepluginloader.cpp:405
Akonadi::TypePluginLoader::defaultPluginForMimeType
ItemSerializerPlugin * defaultPluginForMimeType(const QString &mimetype)
Returns the default item serializer plugin that matches the given mimetype.
Definition: typepluginloader.cpp:418
Akonadi::TypePluginLoader::objectForMimeTypeAndClass
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...
Definition: typepluginloader.cpp:389
Akonadi::TypePluginLoader::defaultObjectForMimeType
QObject * defaultObjectForMimeType(const QString &mimetype)
Returns the default type plugin object that matches the given mimetype.
Definition: typepluginloader.cpp:401
Akonadi::ItemSerializerPlugin
The base class for item type serializer plugins.
Definition: itemserializerplugin.h:120
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Tue Nov 26 2013 09:03:19 by doxygen 1.8.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

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

kdepimlibs-4.11.3 API Reference

Skip menu "kdepimlibs-4.11.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal