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

akonadi

  • sources
  • kde-4.14
  • kdepimlibs
  • 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)
65  , mPlugin(plugin)
66  {
67  }
68 
69  QObject *plugin() const
70  {
71  if (mPlugin) {
72  return mPlugin;
73  }
74 
75  QObject *object = PluginLoader::self()->createForName(mIdentifier);
76  if (!object) {
77  kWarning() << "ItemSerializerPluginLoader: "
78  << "plugin" << mIdentifier << "is not valid!" << endl;
79 
80  // we try to use the default in that case
81  mPlugin = s_defaultItemSerializerPlugin;
82  }
83 
84  mPlugin = object;
85  if (!qobject_cast<ItemSerializerPlugin *>(mPlugin)) {
86  kWarning() << "ItemSerializerPluginLoader: "
87  << "plugin" << mIdentifier << "doesn't provide interface ItemSerializerPlugin!" << endl;
88 
89  // we try to use the default in that case
90  mPlugin = s_defaultItemSerializerPlugin;
91  }
92 
93  Q_ASSERT(mPlugin);
94 
95  return mPlugin;
96  }
97 
98  const char *pluginClassName() const
99  {
100  return plugin()->metaObject()->className();
101  }
102 
103  QString identifier() const
104  {
105  return mIdentifier;
106  }
107 
108  bool operator<(const PluginEntry &other) const
109  {
110  return mIdentifier < other.mIdentifier;
111  }
112 
113  bool operator<(const QString &identifier) const
114  {
115  return mIdentifier < identifier;
116  }
117 
118 private:
119  QString mIdentifier;
120  mutable QObject *mPlugin;
121 };
122 
123 static bool operator<(const QString &identifier, const PluginEntry &entry)
124 {
125  return identifier < entry.identifier();
126 }
127 
128 class MimeTypeEntry
129 {
130 public:
131  explicit MimeTypeEntry(const QString &mimeType)
132  : m_mimeType(mimeType)
133  , m_plugins()
134  , m_pluginsByMetaTypeId()
135  {
136  }
137 
138  QString type() const
139  {
140  return m_mimeType;
141  }
142 
143  void add(const QByteArray &class_, const PluginEntry &entry)
144  {
145  m_pluginsByMetaTypeId.clear(); // iterators will be invalidated by next line
146  m_plugins.insert(class_, entry);
147  }
148 
149  const PluginEntry *plugin(const QByteArray &class_) const
150  {
151  const QHash<QByteArray, PluginEntry>::const_iterator it = m_plugins.find(class_);
152  return it == m_plugins.end() ? 0 : it.operator->();
153  }
154 
155  const PluginEntry *defaultPlugin() const
156  {
157  // 1. If there's an explicit default plugin, use that one:
158  if (const PluginEntry *pe = plugin(DEFAULT_NAME)) {
159  return pe;
160  }
161 
162  // 2. Otherwise, look through the already instantiated plugins,
163  // and return one of them (preferably not the legacy one):
164  bool sawZero = false;
165  for (QMap<int, QHash<QByteArray, PluginEntry>::const_iterator>::const_iterator it = m_pluginsByMetaTypeId.constBegin(), end = m_pluginsByMetaTypeId.constEnd(); it != end; ++it) {
166  if (it.key() == 0) {
167  sawZero = true;
168  } else if (*it != m_plugins.end()) {
169  return it->operator->();
170  }
171  }
172 
173  // 3. Otherwise, look through the whole list (again, preferably not the legacy one):
174  for (QHash<QByteArray, PluginEntry>::const_iterator it = m_plugins.constBegin(), end = m_plugins.constEnd(); it != end; ++it) {
175  if (it.key() == LEGACY_NAME) {
176  sawZero = true;
177  } else {
178  return it.operator->();
179  }
180  }
181 
182  // 4. take the legacy one:
183  if (sawZero) {
184  return plugin(0);
185  }
186  return 0;
187  }
188 
189  const PluginEntry *plugin(int metaTypeId) const
190  {
191  const QMap<int, QHash<QByteArray, PluginEntry>::const_iterator> &c_pluginsByMetaTypeId = m_pluginsByMetaTypeId;
192  QMap<int, QHash<QByteArray, PluginEntry>::const_iterator>::const_iterator it = c_pluginsByMetaTypeId.find(metaTypeId);
193  if (it == c_pluginsByMetaTypeId.end()) {
194  it = QMap<int, QHash<QByteArray, PluginEntry>::const_iterator>::const_iterator(m_pluginsByMetaTypeId.insert(metaTypeId, m_plugins.find(metaTypeId ? QMetaType::typeName(metaTypeId) : LEGACY_NAME)));
195  }
196  return *it == m_plugins.end() ? 0 : it->operator->();
197  }
198 
199  const PluginEntry *plugin(const QVector<int> &metaTypeIds, int &chosen) const
200  {
201  bool sawZero = false;
202  for (QVector<int>::const_iterator it = metaTypeIds.begin(), end = metaTypeIds.end(); it != end; ++it) {
203  if (*it == 0) {
204  sawZero = true; // skip the legacy type and see if we can find something else first
205  } else if (const PluginEntry *const entry = plugin(*it)) {
206  chosen = *it;
207  return entry;
208  }
209  }
210  if (sawZero) {
211  chosen = 0;
212  return plugin(0);
213  }
214  return 0;
215  }
216 
217 private:
218  QString m_mimeType;
219  QHash<QByteArray/* class */, PluginEntry> m_plugins;
220  mutable QMap<int, QHash<QByteArray, PluginEntry>::const_iterator> m_pluginsByMetaTypeId;
221 };
222 
223 static bool operator<(const MimeTypeEntry &lhs, const MimeTypeEntry &rhs)
224 {
225  return lhs.type() < rhs.type();
226 }
227 
228 static bool operator<(const MimeTypeEntry &lhs, const QString &rhs)
229 {
230  return lhs.type() < rhs;
231 }
232 
233 static bool operator<(const QString &lhs, const MimeTypeEntry &rhs)
234 {
235  return lhs < rhs.type();
236 }
237 
238 static QString format(const QString &mimeType, const QVector<int> &metaTypeIds) {
239  if (metaTypeIds.empty()) {
240  return QLatin1String("default for ") + mimeType;
241  }
242  QStringList classTypes;
243  Q_FOREACH (int metaTypeId, metaTypeIds) {
244  classTypes.push_back(QString::fromLatin1(metaTypeId ? QMetaType::typeName(metaTypeId) : LEGACY_NAME));
245  }
246  return mimeType + QLatin1String("@{") + classTypes.join(QLatin1String(",")) + QLatin1Char('}');
247 }
248 
249 class PluginRegistry
250 {
251 public:
252  PluginRegistry()
253  : mDefaultPlugin(PluginEntry(QLatin1String("application/octet-stream@QByteArray"), s_defaultItemSerializerPlugin))
254  , mOverridePlugin(0)
255  {
256  const PluginLoader *pl = PluginLoader::self();
257  if (!pl) {
258  kWarning() << "Cannot instantiate plugin loader!" << endl;
259  return;
260  }
261  const QStringList names = pl->names();
262  kDebug() << "ItemSerializerPluginLoader: "
263  << "found" << names.size() << "plugins." << endl;
264  QMap<QString, MimeTypeEntry> map;
265  QRegExp rx(QLatin1String("(.+)@(.+)"));
266  Q_FOREACH (const QString &name, names) {
267  if (rx.exactMatch(name)) {
268  KMimeType::Ptr mime = KMimeType::mimeType(rx.cap(1), KMimeType::ResolveAliases);
269  if (mime) {
270  const QString mimeType = mime->name();
271  const QByteArray classType = rx.cap(2).toLatin1();
272  QMap<QString, MimeTypeEntry>::iterator it = map.find(mimeType);
273  if (it == map.end()) {
274  it = map.insert(mimeType, MimeTypeEntry(mimeType));
275  }
276  it->add(classType, PluginEntry(name));
277  }
278  } else {
279  kDebug() << "ItemSerializerPluginLoader: "
280  << "name" << name << "doesn't look like mimetype@classtype" << endl;
281  }
282  }
283  const QString APPLICATION_OCTETSTREAM = QLatin1String(_APPLICATION_OCTETSTREAM);
284  QMap<QString, MimeTypeEntry>::iterator it = map.find(APPLICATION_OCTETSTREAM);
285  if (it == map.end()) {
286  it = map.insert(APPLICATION_OCTETSTREAM, MimeTypeEntry(APPLICATION_OCTETSTREAM));
287  }
288  it->add("QByteArray", mDefaultPlugin);
289  it->add(LEGACY_NAME, mDefaultPlugin);
290  const int size = map.size();
291  allMimeTypes.reserve(size);
292  std::copy(map.begin(), map.end(), std::back_inserter(allMimeTypes));
293  }
294 
295  QObject *findBestMatch(const QString &type, const QVector<int> &metaTypeId, TypePluginLoader::Options opt)
296  {
297  if (QObject *const plugin = findBestMatch(type, metaTypeId)) { {
298  if ((opt &TypePluginLoader::NoDefault) && plugin == mDefaultPlugin.plugin()) {
299  return 0;
300  }
301  return plugin;
302  }
303  }
304  return 0;
305  }
306 
307  QObject *findBestMatch(const QString &type, const QVector<int> &metaTypeIds)
308  {
309  if (mOverridePlugin) {
310  return mOverridePlugin;
311  }
312  if (QObject *const plugin = cacheLookup(type, metaTypeIds)) {
313  // plugin cached, so let's take that one
314  return plugin;
315  }
316  int chosen = -1;
317  QObject *const plugin = findBestMatchImpl(type, metaTypeIds, chosen);
318  if (metaTypeIds.empty()) {
319  if (plugin) {
320  cachedDefaultPlugins[type] = plugin;
321  }
322  }
323  if (chosen >= 0) {
324  cachedPlugins[type][chosen] = plugin;
325  }
326  return plugin;
327  }
328 
329  void overrideDefaultPlugin(QObject *p)
330  {
331  mOverridePlugin = p;
332  }
333 
334 private:
335  QObject *findBestMatchImpl(const QString &type, const QVector<int> &metaTypeIds, int &chosen) const
336  {
337  KMimeType::Ptr mimeType = KMimeType::mimeType(type, KMimeType::ResolveAliases);
338  if (mimeType.isNull()) {
339  return mDefaultPlugin.plugin();
340  }
341 
342  // step 1: find all plugins that match at all
343  QVector<int> matchingIndexes;
344  for (int i = 0, end = allMimeTypes.size(); i < end; ++i) {
345  if (mimeType->is(allMimeTypes[i].type())) {
346  matchingIndexes.append(i);
347  }
348  }
349 
350  // step 2: if we have more than one match, find the most specific one using topological sort
351  QVector<int> order;
352  if (matchingIndexes.size() <= 1) {
353  order.push_back(0);
354  } else {
355  boost::adjacency_list<> graph(matchingIndexes.size());
356  for (int i = 0, end = matchingIndexes.size(); i != end; ++i) {
357  KMimeType::Ptr mimeType = KMimeType::mimeType(allMimeTypes[matchingIndexes[i]].type(), KMimeType::ResolveAliases);
358  if (mimeType.isNull()) {
359  continue;
360  }
361  for (int j = 0; j != end; ++j) {
362  if (i != j && mimeType->is(allMimeTypes[matchingIndexes[j]].type())) {
363  boost::add_edge(j, i, graph);
364  }
365  }
366  }
367 
368  order.reserve(matchingIndexes.size());
369  try {
370  boost::topological_sort(graph, std::back_inserter(order));
371  } catch (boost::not_a_dag &e) {
372  kWarning() << "Mimetype tree is not a DAG!";
373  return mDefaultPlugin.plugin();
374  }
375  }
376 
377  // step 3: ask each one in turn if it can handle any of the metaTypeIds:
378 // kDebug() << "Looking for " << format( type, metaTypeIds );
379  for (QVector<int>::const_iterator it = order.constBegin(), end = order.constEnd(); it != end; ++it) {
380 // kDebug() << " Considering serializer plugin for type" << allMimeTypes[matchingIndexes[*it]].type()
381 // // << "as the closest match";
382  const MimeTypeEntry &mt = allMimeTypes[matchingIndexes[*it]];
383  if (metaTypeIds.empty()) {
384  if (const PluginEntry *const entry = mt.defaultPlugin()) {
385 // kDebug() << " -> got " << entry->pluginClassName() << " and am happy with it.";
386  return entry->plugin();
387  } else {
388 // kDebug() << " -> no default plugin for this mime type, trying next";
389  }
390  } else if (const PluginEntry *const entry = mt.plugin(metaTypeIds, chosen)) {
391 // kDebug() << " -> got " << entry->pluginClassName() << " and am happy with it.";
392  return entry->plugin();
393  } else {
394 // kDebug() << " -> can't handle any of the types, trying next";
395  }
396  }
397 
398 // kDebug() << " No further candidates, using default plugin";
399  // no luck? Use the default plugin
400  return mDefaultPlugin.plugin();
401  }
402 
403  std::vector<MimeTypeEntry> allMimeTypes;
404  QHash<QString, QMap<int, QObject *> > cachedPlugins;
405  QHash<QString, QObject *> cachedDefaultPlugins;
406 
407  // ### cache NULLs, too
408  QObject *cacheLookup(const QString &mimeType, const QVector<int> &metaTypeIds) const {
409  if (metaTypeIds.empty()) {
410  const QHash<QString, QObject *>::const_iterator hit = cachedDefaultPlugins.find(mimeType);
411  if (hit != cachedDefaultPlugins.end()) {
412  return *hit;
413  }
414  }
415 
416  const QHash<QString, QMap<int, QObject *> >::const_iterator hit = cachedPlugins.find(mimeType);
417  if (hit == cachedPlugins.end()) {
418  return 0;
419  }
420  bool sawZero = false;
421  for (QVector<int>::const_iterator it = metaTypeIds.begin(), end = metaTypeIds.end(); it != end; ++it) {
422  if (*it == 0) {
423  sawZero = true; // skip the legacy type and see if we can find something else first
424  } else if (QObject *const o = hit->value(*it)) {
425  return o;
426  }
427  }
428  if (sawZero) {
429  return hit->value(0);
430  }
431  return 0;
432  }
433 
434 private:
435  PluginEntry mDefaultPlugin;
436  QObject *mOverridePlugin;
437 };
438 
439 K_GLOBAL_STATIC(PluginRegistry, s_pluginRegistry)
440 
441 QObject *TypePluginLoader::objectForMimeTypeAndClass(const QString &mimetype, const QVector<int> &metaTypeIds, Options opt)
442 {
443  return s_pluginRegistry->findBestMatch(mimetype, metaTypeIds, opt);
444 }
445 
446 #if 0
447 QObject *TypePluginLoader::legacyObjectForMimeType(const QString &mimetype) {
448  // ### impl specifically - only works b/c vector isn't used in impl ###
449  return objectForMimeTypeAndClass(mimetype, QVector<int>(1, 0));
450 }
451 #endif
452 
453 QObject *TypePluginLoader::defaultObjectForMimeType(const QString &mimetype) {
454  return objectForMimeTypeAndClass(mimetype, QVector<int>());
455 }
456 
457 ItemSerializerPlugin *TypePluginLoader::pluginForMimeTypeAndClass(const QString &mimetype, const QVector<int> &metaTypeIds, Options opt)
458 {
459  return qobject_cast<ItemSerializerPlugin *>(objectForMimeTypeAndClass(mimetype, metaTypeIds, opt));
460 }
461 
462 #if 0
463 ItemSerializerPlugin *TypePluginLoader::legacyPluginForMimeType(const QString &mimetype) {
464  ItemSerializerPlugin *plugin = qobject_cast<ItemSerializerPlugin *>(legacyObjectForMimeType(mimetype));
465  Q_ASSERT(plugin);
466  return plugin;
467 }
468 #endif
469 
470 ItemSerializerPlugin *TypePluginLoader::defaultPluginForMimeType(const QString &mimetype) {
471  ItemSerializerPlugin *plugin = qobject_cast<ItemSerializerPlugin *>(defaultObjectForMimeType(mimetype));
472  Q_ASSERT(plugin);
473  return plugin;
474 }
475 
476 void TypePluginLoader::overridePluginLookup(QObject *p) {
477  s_pluginRegistry->overrideDefaultPlugin(p);
478 }
479 
480 }
Akonadi::TypePluginLoader::overridePluginLookup
void overridePluginLookup(QObject *plugin)
Override the plugin-lookup with plugin.
Definition: typepluginloader.cpp:476
QHash::key
const Key key(const T &value) const
QVector::append
void append(const T &value)
QVector::begin
iterator begin()
QList::push_back
void push_back(const T &value)
QByteArray
QVector::constEnd
const_iterator constEnd() const
QMap
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:457
QStringList::join
QString join(const QString &separator) const
QList::size
int size() const
QString::clear
void clear()
QRegExp
QHash
QObject
QString
QtConcurrent::map
QFuture< void > map(Sequence &sequence, MapFunction function)
QMap::end
iterator end()
QMap::begin
iterator begin()
QStringList
QHash::value
const T value(const Key &key) const
QVector::reserve
void reserve(int size)
QHash::find
iterator find(const Key &key)
QLatin1Char
Akonadi::TypePluginLoader::defaultPluginForMimeType
ItemSerializerPlugin * defaultPluginForMimeType(const QString &mimetype)
Returns the default item serializer plugin that matches the given mimetype.
Definition: typepluginloader.cpp:470
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:441
QHash::constBegin
const_iterator constBegin() const
QVector::constBegin
const_iterator constBegin() const
QMetaType::typeName
const char * typeName(int type)
QVector< int >
QLatin1String
Akonadi::TypePluginLoader::defaultObjectForMimeType
QObject * defaultObjectForMimeType(const QString &mimetype)
Returns the default type plugin object that matches the given mimetype.
Definition: typepluginloader.cpp:453
QVector::push_back
void push_back(const T &value)
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QMap::insert
iterator insert(const Key &key, const T &value)
Akonadi::ItemSerializerPlugin
The base class for item type serializer plugins.
Definition: itemserializerplugin.h:119
QHash::end
iterator end()
QVector::size
int size() const
QVector::empty
bool empty() const
QVector::end
iterator end()
QMap::find
iterator find(const Key &key)
QMap::size
int size() const
QMap::iterator
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:38:03 by doxygen 1.8.7 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 API Reference

Skip menu "kdepimlibs 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

Search



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