KCoreAddons

kpluginfactory.cpp
1 /*
2  This file is part of the KDE project
3 
4  SPDX-FileCopyrightText: 2007 Matthias Kretz <[email protected]>
5  SPDX-FileCopyrightText: 2007 Bernhard Loos <[email protected]>
6  SPDX-FileCopyrightText: 2021 Alexander Lohnau <[email protected]>
7 
8  SPDX-License-Identifier: LGPL-2.0-or-later
9 */
10 
11 #include "kpluginfactory.h"
12 #include "kpluginfactory_p.h"
13 
14 #include "kcoreaddons_debug.h"
15 #include <QObjectCleanupHandler>
16 
18 
20  : d_ptr(new KPluginFactoryPrivate)
21 {
22  factorycleanup()->add(this);
23 }
24 
25 KPluginFactory::KPluginFactory(KPluginFactoryPrivate &d)
26  : d_ptr(&d)
27 {
28  factorycleanup()->add(this);
29 }
30 
32 
34 {
36  QObject *obj = nullptr;
37  if (data.isStaticPlugin()) {
38  obj = data.staticPlugin().instance();
39  } else {
40  if (data.fileName().isEmpty()) {
41  result.errorString = tr("Could not find plugin %1").arg(data.requestedFileName());
42  result.errorText = QStringLiteral("Could not find plugin %1").arg(data.requestedFileName());
43  result.errorReason = INVALID_PLUGIN;
44  qCWarning(KCOREADDONS_DEBUG) << result.errorText;
45  return result;
46  }
47  QPluginLoader loader(data.fileName());
48  obj = loader.instance();
49  if (!obj) {
50  result.errorString = tr("Could not load plugin from %1: %2").arg(data.fileName(), loader.errorString());
51  result.errorText = QStringLiteral("Could not load plugin from %1: %2").arg(data.fileName(), loader.errorString());
52  result.errorReason = INVALID_PLUGIN;
53  qCWarning(KCOREADDONS_DEBUG) << result.errorText;
54  return result;
55  }
56  }
57 
58  KPluginFactory *factory = qobject_cast<KPluginFactory *>(obj);
59 
60  if (factory == nullptr) {
61  result.errorString = tr("The library %1 does not offer a KPluginFactory.").arg(data.fileName());
62  result.errorReason = INVALID_FACTORY;
63  qCWarning(KCOREADDONS_DEBUG) << "Expected a KPluginFactory, got a" << obj->metaObject()->className();
64  delete obj;
65  return result;
66  }
67 
68  factory->setMetaData(data);
69  result.plugin = factory;
70  return result;
71 }
72 
74 {
75  Q_D(const KPluginFactory);
76 
77  return d->metaData;
78 }
79 
81 {
83  d->metaData = metaData;
84 }
85 
86 void KPluginFactory::registerPlugin(const QString &keyword, const QMetaObject *metaObject, CreateInstanceFunction instanceFunction)
87 {
89 
90  Q_ASSERT(metaObject);
91 
92  // we allow different interfaces to be registered without keyword
93  if (!keyword.isEmpty()) {
94  if (d->createInstanceHash.contains(keyword)) {
95  qCWarning(KCOREADDONS_DEBUG) << "A plugin with the keyword" << keyword << "was already registered. A keyword must be unique!";
96  }
97  d->createInstanceHash.insert(keyword, KPluginFactoryPrivate::Plugin(metaObject, instanceFunction));
98  } else {
99  const QList<KPluginFactoryPrivate::Plugin> clashes(d->createInstanceHash.values(keyword));
100  const QMetaObject *superClass = metaObject->superClass();
101 
102  // check hierarchy of all registered with the same keyword registered classes
103  if (superClass) {
104  for (const KPluginFactoryPrivate::Plugin &plugin : clashes) {
105  for (const QMetaObject *otherSuper = plugin.first->superClass(); otherSuper; otherSuper = otherSuper->superClass()) {
106  if (superClass == otherSuper) {
107  qCWarning(KCOREADDONS_DEBUG).nospace() << "Two plugins with the same interface (" << superClass->className()
108  << ") were registered in the KPluginFactory " << this->metaObject()->className() << ". "
109  << "This might be due to a missing Q_OBJECT macro in one of the registered classes";
110  }
111  }
112  }
113  }
114  // check hierarchy of newly newly registered plugin against all registered classes with the same keyword
115  for (const KPluginFactoryPrivate::Plugin &plugin : clashes) {
116  superClass = plugin.first->superClass();
117  if (superClass) {
118  for (const QMetaObject *otherSuper = metaObject->superClass(); otherSuper; otherSuper = otherSuper->superClass()) {
119  if (superClass == otherSuper) {
120  qCWarning(KCOREADDONS_DEBUG).nospace() << "Two plugins with the same interface (" << superClass->className()
121  << ") were registered in the KPluginFactory " << this->metaObject()->className() << ". "
122  << "This might be due to a missing Q_OBJECT macro in one of the registered classes";
123  }
124  }
125  }
126  }
127  d->createInstanceHash.insert(keyword, KPluginFactoryPrivate::Plugin(metaObject, instanceFunction));
128  }
129 }
130 
131 void KPluginFactory::registerPlugin(const QString &keyword, const QMetaObject *metaObject, CreateInstanceWithMetaDataFunction instanceFunction)
132 {
134 
135  Q_ASSERT(metaObject);
136 
137  // we allow different interfaces to be registered without keyword
138  if (!keyword.isEmpty()) {
139  if (d->createInstanceWithMetaDataHash.contains(keyword)) {
140  qCWarning(KCOREADDONS_DEBUG) << "A plugin with the keyword" << keyword << "was already registered. A keyword must be unique!";
141  }
142  d->createInstanceWithMetaDataHash.insert(keyword, {metaObject, instanceFunction});
143  } else {
144  const QList<KPluginFactoryPrivate::PluginWithMetadata> clashes(d->createInstanceWithMetaDataHash.values(keyword));
145  const QMetaObject *superClass = metaObject->superClass();
146  // check hierarchy of all registered with the same keyword registered classes
147  if (superClass) {
148  for (const KPluginFactoryPrivate::PluginWithMetadata &plugin : clashes) {
149  for (const QMetaObject *otherSuper = plugin.first->superClass(); otherSuper; otherSuper = otherSuper->superClass()) {
150  if (superClass == otherSuper) {
151  qCWarning(KCOREADDONS_DEBUG).nospace() << "Two plugins with the same interface (" << superClass->className()
152  << ") were registered in the KPluginFactory " << this->metaObject()->className() << ". "
153  << "This might be due to a missing Q_OBJECT macro in one of the registered classes";
154  }
155  }
156  }
157  }
158  // check hierarchy of newly newly registered plugin against all registered classes with the same keyword
159  for (const KPluginFactoryPrivate::PluginWithMetadata &plugin : clashes) {
160  superClass = plugin.first->superClass();
161  if (superClass) {
162  for (const QMetaObject *otherSuper = metaObject->superClass(); otherSuper; otherSuper = otherSuper->superClass()) {
163  if (superClass == otherSuper) {
164  qCWarning(KCOREADDONS_DEBUG).nospace() << "Two plugins with the same interface (" << superClass->className()
165  << ") were registered in the KPluginFactory " << this->metaObject()->className() << ". "
166  << "This might be due to a missing Q_OBJECT macro in one of the registered classes";
167  }
168  }
169  }
170  }
171  d->createInstanceWithMetaDataHash.insert(keyword, {metaObject, instanceFunction});
172  }
173 }
174 
175 void KPluginFactory::logFailedInstantiationMessage(KPluginMetaData data)
176 {
177  qCWarning(KCOREADDONS_DEBUG) << "KPluginFactory could not load the plugin" << data.fileName();
178 }
179 void KPluginFactory::logFailedInstantiationMessage(const char *className, KPluginMetaData data)
180 {
181  qCWarning(KCOREADDONS_DEBUG) << "KPluginFactory could not create a" << className << "instance from" << data.fileName();
182 }
183 
184 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(4, 0)
185 QObject *KPluginFactory::createObject(QObject *parent, const char *className, const QStringList &args)
186 {
187  Q_UNUSED(parent);
188  Q_UNUSED(className);
189  Q_UNUSED(args);
190  return nullptr;
191 }
192 #endif
193 
194 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(4, 0)
195 KParts::Part *KPluginFactory::createPartObject(QWidget *parentWidget, QObject *parent, const char *classname, const QStringList &args)
196 {
197  Q_UNUSED(parent);
198  Q_UNUSED(parentWidget);
199  Q_UNUSED(classname);
200  Q_UNUSED(args);
201  return nullptr;
202 }
203 #endif
204 
205 QObject *KPluginFactory::create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args, const QString &keyword)
206 {
208 
209  QObject *obj = nullptr;
210 
211 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(4, 0)
212  if (keyword.isEmpty()) {
213  const QStringList argsStringList = variantListToStringList(args);
214 
215  if ((obj = reinterpret_cast<QObject *>(createPartObject(parentWidget, parent, iface, argsStringList)))) {
216  Q_EMIT objectCreated(obj);
217  return obj;
218  }
219 
220  if ((obj = createObject(parent, iface, argsStringList))) {
221  Q_EMIT objectCreated(obj);
222  return obj;
223  }
224  }
225 #endif
226 
227  const QList<KPluginFactoryPrivate::Plugin> candidates(d->createInstanceHash.values(keyword));
228  // for !keyword.isEmpty() candidates.count() is 0 or 1
229 
230  for (const KPluginFactoryPrivate::Plugin &plugin : candidates) {
231  for (const QMetaObject *current = plugin.first; current; current = current->superClass()) {
232  if (0 == qstrcmp(iface, current->className())) {
233  if (obj) {
234  qCWarning(KCOREADDONS_DEBUG) << "ambiguous interface requested from a DSO containing more than one plugin";
235  }
236  obj = plugin.second(parentWidget, parent, args);
237  break;
238  }
239  }
240  }
241 
242  if (!obj) {
243  const QList<KPluginFactoryPrivate::PluginWithMetadata> candidates = (d->createInstanceWithMetaDataHash.values(keyword));
244  // for !keyword.isEmpty() candidates.count() is 0 or 1
245 
246  for (const KPluginFactoryPrivate::PluginWithMetadata &plugin : candidates) {
247  for (const QMetaObject *current = plugin.first; current; current = current->superClass()) {
248  if (0 == qstrcmp(iface, current->className())) {
249  if (obj) {
250  qCWarning(KCOREADDONS_DEBUG) << "ambiguous interface requested from a DSO containing more than one plugin";
251  }
252  obj = plugin.second(parentWidget, parent, d->metaData, args);
253  break;
254  }
255  }
256  }
257  }
258 
259  if (obj) {
260  Q_EMIT objectCreated(obj);
261  }
262  return obj;
263 }
264 
266 {
267  QStringList stringlist;
268  for (const QVariant &var : list) {
269  stringlist << var.toString();
270  }
271  return stringlist;
272 }
273 
275 {
276  QVariantList variantlist;
277  for (const QString &str : list) {
278  variantlist << QVariant(str);
279  }
280  return variantlist;
281 }
282 
283 #include "moc_kpluginfactory.cpp"
Q_EMITQ_EMIT
void registerPlugin()
Overload for registerPlugin<T>(const QString &keyword, CreateInstanceFunction instanceFunction)
static QStringList variantListToStringList(const QVariantList &list)
virtual KParts::Part * createPartObject(QWidget *parentWidget, QObject *parent, const char *classname, const QStringList &args)
void setMetaData(const KPluginMetaData &metaData)
Set the metadata about the plugin this factory generates.
Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) class ControlPrivate
virtual QObject * createObject(QObject *parent, const char *className, const QStringList &args)
bool isEmpty() const const
bool isStaticPlugin() const
QString errorString
translated, user-visible error string
const QMetaObject * superClass() const const
T * create(QObject *parent=nullptr, const QVariantList &args=QVariantList())
Use this method to create an object.
KPluginMetaData metaData() const
static QVariantList stringListToVariantList(const QStringList &list)
static Result< KPluginFactory > loadFactory(const KPluginMetaData &data)
Attempts to load the KPluginFactory from the given metadata.
virtual const QMetaObject * metaObject() const const
KPluginFactory()
This constructor creates a factory for a plugin.
const char * className() const const
QString errorText
untranslated error text
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString & insert(int position, QChar ch)
~KPluginFactory() override
This destroys the PluginFactory.
QObject * instance()
QObject * instance()
Holds the result of a plugin load operation, i.e.
QString tr(const char *sourceText, const char *disambiguation, int n)
QObject * parent() const const
Q_D(Todo)
QString errorString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sat Dec 9 2023 04:03:07 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.