Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / libs / extensionsystem / pluginspec.cpp
blob1cc6dd8f87df14f52ed1022852396855a257aae8
1 /**
2 ******************************************************************************
4 * @file pluginspec.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
7 * @brief
8 * @see The GNU Public License (GPL) Version 3
9 * @defgroup
10 * @{
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "pluginspec.h"
30 #include "pluginspec.h"
31 #include "pluginspec_p.h"
32 #include "iplugin.h"
33 #include "iplugin_p.h"
34 #include "pluginmanager.h"
36 #include <QtCore/QFile>
37 #include <QtCore/QFileInfo>
38 #include <QtCore/QXmlStreamReader>
39 #include <QtCore/QRegExp>
40 #include <QtCore/QCoreApplication>
41 #include <QtDebug>
43 #ifdef Q_OS_LINUX
44 // Using the patched version breaks on Fedora 10, KDE4.2.2/Qt4.5.
45 # define USE_UNPATCHED_QPLUGINLOADER 1
46 #else
47 # define USE_UNPATCHED_QPLUGINLOADER 1
48 #endif
50 #if USE_UNPATCHED_QPLUGINLOADER
52 # include <QtCore/QPluginLoader>
53 typedef QT_PREPEND_NAMESPACE (QPluginLoader) PluginLoader;
55 #else
57 # include "patchedpluginloader.cpp"
58 typedef PatchedPluginLoader PluginLoader;
60 #endif
62 /*!
63 \class ExtensionSystem::PluginDependency
64 \brief Struct that contains the name and required compatible version number of a plugin's dependency.
66 This reflects the data of a dependency tag in the plugin's xml description file.
67 The name and version are used to resolve the dependency, i.e. a plugin with the given name and
68 plugin \c {compatibility version <= dependency version <= plugin version} is searched for.
70 See also ExtensionSystem::IPlugin for more information about plugin dependencies and
71 version matching.
74 /*!
75 \variable ExtensionSystem::PluginDependency::name
76 String identifier of the plugin.
79 /*!
80 \variable ExtensionSystem::PluginDependency::version
81 Version string that a plugin must match to fill this dependency.
84 /*!
85 \class ExtensionSystem::PluginSpec
86 \brief Contains the information of the plugins xml description file and
87 information about the plugin's current state.
89 The plugin spec is also filled with more information as the plugin
90 goes through its loading process (see PluginSpec::State).
91 If an error occurs, the plugin spec is the place to look for the
92 error details.
95 /*!
96 \enum ExtensionSystem::PluginSpec::State
98 The plugin goes through several steps while being loaded.
99 The state gives a hint on what went wrong in case of an error.
101 \value Invalid
102 Starting point: Even the xml description file was not read.
103 \value Read
104 The xml description file has been successfully read, and its
105 information is available via the PluginSpec.
106 \value Resolved
107 The dependencies given in the description file have been
108 successfully found, and are available via the dependencySpecs() method.
109 \value Loaded
110 The plugin's library is loaded and the plugin instance created
111 (available through plugin()).
112 \value Initialized
113 The plugin instance's IPlugin::initialize() method has been called
114 and returned a success value.
115 \value Running
116 The plugin's dependencies are successfully initialized and
117 extensionsInitialized has been called. The loading process is
118 complete.
119 \value Stopped
120 The plugin has been shut down, i.e. the plugin's IPlugin::shutdown() method has been called.
121 \value Deleted
122 The plugin instance has been deleted.
124 using namespace ExtensionSystem;
125 using namespace ExtensionSystem::Internal;
128 \fn bool PluginDependency::operator==(const PluginDependency &other)
129 \internal
131 bool PluginDependency::operator==(const PluginDependency &other)
133 return name == other.name && version == other.version;
137 \fn PluginSpec::PluginSpec()
138 \internal
140 PluginSpec::PluginSpec()
141 : d(new PluginSpecPrivate(this))
145 \fn PluginSpec::~PluginSpec()
146 \internal
148 PluginSpec::~PluginSpec()
150 delete d;
151 d = 0;
155 \fn QString PluginSpec::name() const
156 The plugin name. This is valid after the PluginSpec::Read state is reached.
158 QString PluginSpec::name() const
160 return d->name;
164 \fn QString PluginSpec::version() const
165 The plugin version. This is valid after the PluginSpec::Read state is reached.
167 QString PluginSpec::version() const
169 return d->version;
173 \fn QString PluginSpec::compatVersion() const
174 The plugin compatibility version. This is valid after the PluginSpec::Read state is reached.
176 QString PluginSpec::compatVersion() const
178 return d->compatVersion;
182 \fn QString PluginSpec::vendor() const
183 The plugin vendor. This is valid after the PluginSpec::Read state is reached.
185 QString PluginSpec::vendor() const
187 return d->vendor;
191 \fn QString PluginSpec::copyright() const
192 The plugin copyright. This is valid after the PluginSpec::Read state is reached.
194 QString PluginSpec::copyright() const
196 return d->copyright;
200 \fn QString PluginSpec::license() const
201 The plugin license. This is valid after the PluginSpec::Read state is reached.
203 QString PluginSpec::license() const
205 return d->license;
209 \fn QString PluginSpec::description() const
210 The plugin description. This is valid after the PluginSpec::Read state is reached.
212 QString PluginSpec::description() const
214 return d->description;
218 \fn QString PluginSpec::url() const
219 The plugin url where you can find more information about the plugin. This is valid after the PluginSpec::Read state is reached.
221 QString PluginSpec::url() const
223 return d->url;
227 \fn QList<PluginDependency> PluginSpec::dependencies() const
228 The plugin dependencies. This is valid after the PluginSpec::Read state is reached.
230 QList<PluginDependency> PluginSpec::dependencies() const
232 return d->dependencies;
236 \fn PluginSpec::PluginArgumentDescriptions PluginSpec::argumentDescriptions() const
237 Returns a list of descriptions of command line arguments the plugin processes.
240 PluginSpec::PluginArgumentDescriptions PluginSpec::argumentDescriptions() const
242 return d->argumentDescriptions;
246 \fn QString PluginSpec::location() const
247 The absolute path to the directory containing the plugin xml description file
248 this PluginSpec corresponds to.
250 QString PluginSpec::location() const
252 return d->location;
256 \fn QString PluginSpec::filePath() const
257 The absolute path to the plugin xml description file (including the file name)
258 this PluginSpec corresponds to.
260 QString PluginSpec::filePath() const
262 return d->filePath;
266 \fn QStringList PluginSpec::arguments() const
267 Command line arguments specific to that plugin. Set at startup
270 QStringList PluginSpec::arguments() const
272 return d->arguments;
276 \fn void PluginSpec::setArguments(const QStringList &arguments)
277 Set the command line arguments specific to that plugin to \a arguments.
280 void PluginSpec::setArguments(const QStringList &arguments)
282 d->arguments = arguments;
286 \fn PluginSpec::addArgument(const QString &argument)
287 Adds \a argument to the command line arguments specific to that plugin.
290 void PluginSpec::addArgument(const QString &argument)
292 d->arguments.push_back(argument);
297 \fn PluginSpec::State PluginSpec::state() const
298 The state in which the plugin currently is.
299 See the description of the PluginSpec::State enum for details.
301 PluginSpec::State PluginSpec::state() const
303 return d->state;
307 \fn bool PluginSpec::hasError() const
308 Returns whether an error occurred while reading/starting the plugin.
310 bool PluginSpec::hasError() const
312 return d->hasError;
316 \fn QString PluginSpec::errorString() const
317 Detailed, possibly multi-line, error description in case of an error.
319 QString PluginSpec::errorString() const
321 return d->errorString;
325 \fn bool PluginSpec::provides(const QString &pluginName, const QString &version) const
326 Returns if this plugin can be used to fill in a dependency of the given
327 \a pluginName and \a version.
329 \sa PluginSpec::dependencies()
331 bool PluginSpec::provides(const QString &pluginName, const QString &version) const
333 return d->provides(pluginName, version);
337 \fn IPlugin *PluginSpec::plugin() const
338 The corresponding IPlugin instance, if the plugin library has already been successfully loaded,
339 i.e. the PluginSpec::Loaded state is reached.
341 IPlugin *PluginSpec::plugin() const
343 return d->plugin;
347 \fn QList<PluginSpec *> PluginSpec::dependencySpecs() const
348 Returns the list of dependencies, already resolved to existing plugin specs.
349 Valid if PluginSpec::Resolved state is reached.
351 \sa PluginSpec::dependencies()
353 QList<PluginSpec *> PluginSpec::dependencySpecs() const
355 return d->dependencySpecs;
358 // ==========PluginSpecPrivate==================
360 namespace {
361 const char *const PLUGIN = "plugin";
362 const char *const PLUGIN_NAME = "name";
363 const char *const PLUGIN_VERSION = "version";
364 const char *const PLUGIN_COMPATVERSION = "compatVersion";
365 const char *const VENDOR = "vendor";
366 const char *const COPYRIGHT = "copyright";
367 const char *const LICENSE = "license";
368 const char *const DESCRIPTION = "description";
369 const char *const URL = "url";
370 const char *const DEPENDENCYLIST = "dependencyList";
371 const char *const DEPENDENCY = "dependency";
372 const char *const DEPENDENCY_NAME = "name";
373 const char *const DEPENDENCY_VERSION = "version";
374 const char *const ARGUMENTLIST = "argumentList";
375 const char *const ARGUMENT = "argument";
376 const char *const ARGUMENT_NAME = "name";
377 const char *const ARGUMENT_PARAMETER = "parameter";
380 \fn PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec)
381 \internal
383 PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec)
384 : plugin(0),
385 state(PluginSpec::Invalid),
386 hasError(false),
387 q(spec)
391 \fn bool PluginSpecPrivate::read(const QString &fileName)
392 \internal
394 bool PluginSpecPrivate::read(const QString &fileName)
396 name
397 = version
398 = compatVersion
399 = vendor
400 = copyright
401 = license
402 = description
403 = url
404 = location
405 = "";
406 state = PluginSpec::Invalid;
407 hasError = false;
408 errorString = "";
409 dependencies.clear();
410 QFile file(fileName);
411 if (!file.exists()) {
412 return reportError(tr("File does not exist: %1").arg(file.fileName()));
414 if (!file.open(QIODevice::ReadOnly)) {
415 return reportError(tr("Could not open file for read: %1").arg(file.fileName()));
417 QFileInfo fileInfo(file);
418 location = fileInfo.absolutePath();
419 filePath = fileInfo.absoluteFilePath();
420 QXmlStreamReader reader(&file);
421 while (!reader.atEnd()) {
422 reader.readNext();
423 switch (reader.tokenType()) {
424 case QXmlStreamReader::StartElement:
425 readPluginSpec(reader);
426 break;
427 default:
428 break;
431 if (reader.hasError()) {
432 return reportError(tr("Error parsing file %1: %2, at line %3, column %4")
433 .arg(file.fileName())
434 .arg(reader.errorString())
435 .arg(reader.lineNumber())
436 .arg(reader.columnNumber()));
438 state = PluginSpec::Read;
439 return true;
443 \fn bool PluginSpecPrivate::reportError(const QString &err)
444 \internal
446 bool PluginSpecPrivate::reportError(const QString &err)
448 errorString = err;
449 hasError = true;
450 return false;
453 static inline QString msgAttributeMissing(const char *elt, const char *attribute)
455 return QCoreApplication::translate("PluginSpec", "'%1' misses attribute '%2'").arg(QLatin1String(elt), QLatin1String(attribute));
458 static inline QString msgInvalidFormat(const char *content)
460 return QCoreApplication::translate("PluginSpec", "'%1' has invalid format").arg(content);
463 static inline QString msgInvalidElement(const QString &name)
465 return QCoreApplication::translate("PluginSpec", "Invalid element '%1'").arg(name);
468 static inline QString msgUnexpectedClosing(const QString &name)
470 return QCoreApplication::translate("PluginSpec", "Unexpected closing element '%1'").arg(name);
473 static inline QString msgUnexpectedToken()
475 return QCoreApplication::translate("PluginSpec", "Unexpected token");
479 \fn void PluginSpecPrivate::readPluginSpec(QXmlStreamReader &reader)
480 \internal
482 void PluginSpecPrivate::readPluginSpec(QXmlStreamReader &reader)
484 QString element = reader.name().toString();
486 if (element != QString(PLUGIN)) {
487 reader.raiseError(QCoreApplication::translate("PluginSpec", "Expected element '%1' as top level element").arg(PLUGIN));
488 return;
490 name = reader.attributes().value(PLUGIN_NAME).toString();
491 if (name.isEmpty()) {
492 reader.raiseError(msgAttributeMissing(PLUGIN, PLUGIN_NAME));
493 return;
495 version = reader.attributes().value(PLUGIN_VERSION).toString();
496 if (version.isEmpty()) {
497 reader.raiseError(msgAttributeMissing(PLUGIN, PLUGIN_VERSION));
498 return;
500 if (!isValidVersion(version)) {
501 reader.raiseError(msgInvalidFormat(PLUGIN_VERSION));
502 return;
504 compatVersion = reader.attributes().value(PLUGIN_COMPATVERSION).toString();
505 if (!compatVersion.isEmpty() && !isValidVersion(compatVersion)) {
506 reader.raiseError(msgInvalidFormat(PLUGIN_COMPATVERSION));
507 return;
508 } else if (compatVersion.isEmpty()) {
509 compatVersion = version;
511 while (!reader.atEnd()) {
512 reader.readNext();
513 switch (reader.tokenType()) {
514 case QXmlStreamReader::StartElement:
515 element = reader.name().toString();
516 if (element == VENDOR) {
517 vendor = reader.readElementText().trimmed();
518 } else if (element == COPYRIGHT) {
519 copyright = reader.readElementText().trimmed();
520 } else if (element == LICENSE) {
521 license = reader.readElementText().trimmed();
522 } else if (element == DESCRIPTION) {
523 description = reader.readElementText().trimmed();
524 } else if (element == URL) {
525 url = reader.readElementText().trimmed();
526 } else if (element == DEPENDENCYLIST) {
527 readDependencies(reader);
528 } else if (element == ARGUMENTLIST) {
529 readArgumentDescriptions(reader);
530 } else {
531 reader.raiseError(msgInvalidElement(name));
533 break;
534 case QXmlStreamReader::EndDocument:
535 case QXmlStreamReader::Comment:
536 case QXmlStreamReader::EndElement:
537 case QXmlStreamReader::Characters:
538 break;
539 default:
540 reader.raiseError(msgUnexpectedToken());
541 break;
547 \fn void PluginSpecPrivate::readArgumentDescriptions(QXmlStreamReader &reader)
548 \internal
551 void PluginSpecPrivate::readArgumentDescriptions(QXmlStreamReader &reader)
553 QString element;
555 while (!reader.atEnd()) {
556 reader.readNext();
557 switch (reader.tokenType()) {
558 case QXmlStreamReader::StartElement:
559 element = reader.name().toString();
560 if (element == ARGUMENT) {
561 readArgumentDescription(reader);
562 } else {
563 reader.raiseError(msgInvalidElement(name));
565 break;
566 case QXmlStreamReader::Comment:
567 case QXmlStreamReader::Characters:
568 break;
569 case QXmlStreamReader::EndElement:
570 element = reader.name().toString();
571 if (element == ARGUMENTLIST) {
572 return;
574 reader.raiseError(msgUnexpectedClosing(element));
575 break;
576 default:
577 reader.raiseError(msgUnexpectedToken());
578 break;
584 \fn void PluginSpecPrivate::readArgumentDescription(QXmlStreamReader &reader)
585 \internal
587 void PluginSpecPrivate::readArgumentDescription(QXmlStreamReader &reader)
589 PluginArgumentDescription arg;
591 arg.name = reader.attributes().value(ARGUMENT_NAME).toString();
592 if (arg.name.isEmpty()) {
593 reader.raiseError(msgAttributeMissing(ARGUMENT, ARGUMENT_NAME));
594 return;
596 arg.parameter = reader.attributes().value(ARGUMENT_PARAMETER).toString();
597 arg.description = reader.readElementText();
598 if (reader.tokenType() != QXmlStreamReader::EndElement) {
599 reader.raiseError(msgUnexpectedToken());
601 argumentDescriptions.push_back(arg);
605 \fn void PluginSpecPrivate::readDependencies(QXmlStreamReader &reader)
606 \internal
608 void PluginSpecPrivate::readDependencies(QXmlStreamReader &reader)
610 QString element;
612 while (!reader.atEnd()) {
613 reader.readNext();
614 switch (reader.tokenType()) {
615 case QXmlStreamReader::StartElement:
616 element = reader.name().toString();
617 if (element == DEPENDENCY) {
618 readDependencyEntry(reader);
619 } else {
620 reader.raiseError(msgInvalidElement(name));
622 break;
623 case QXmlStreamReader::Comment:
624 case QXmlStreamReader::Characters:
625 break;
626 case QXmlStreamReader::EndElement:
627 element = reader.name().toString();
628 if (element == DEPENDENCYLIST) {
629 return;
631 reader.raiseError(msgUnexpectedClosing(element));
632 break;
633 default:
634 reader.raiseError(msgUnexpectedToken());
635 break;
641 \fn void PluginSpecPrivate::readDependencyEntry(QXmlStreamReader &reader)
642 \internal
644 void PluginSpecPrivate::readDependencyEntry(QXmlStreamReader &reader)
646 PluginDependency dep;
648 dep.name = reader.attributes().value(DEPENDENCY_NAME).toString();
649 if (dep.name.isEmpty()) {
650 reader.raiseError(msgAttributeMissing(DEPENDENCY, DEPENDENCY_NAME));
651 return;
653 dep.version = reader.attributes().value(DEPENDENCY_VERSION).toString();
654 if (!dep.version.isEmpty() && !isValidVersion(dep.version)) {
655 reader.raiseError(msgInvalidFormat(DEPENDENCY_VERSION));
656 return;
658 dependencies.append(dep);
659 reader.readNext();
660 if (reader.tokenType() != QXmlStreamReader::EndElement) {
661 reader.raiseError(msgUnexpectedToken());
666 \fn bool PluginSpecPrivate::provides(const QString &pluginName, const QString &pluginVersion) const
667 \internal
669 bool PluginSpecPrivate::provides(const QString &pluginName, const QString &pluginVersion) const
671 if (QString::compare(pluginName, name, Qt::CaseInsensitive) != 0) {
672 return false;
674 return (versionCompare(version, pluginVersion) >= 0) && (versionCompare(compatVersion, pluginVersion) <= 0);
678 \fn QRegExp &PluginSpecPrivate::versionRegExp()
679 \internal
681 QRegExp &PluginSpecPrivate::versionRegExp()
683 static QRegExp reg("([0-9]+)(?:[.]([0-9]+))?(?:[.]([0-9]+))?(?:_([0-9]+))?");
685 return reg;
688 \fn bool PluginSpecPrivate::isValidVersion(const QString &version)
689 \internal
691 bool PluginSpecPrivate::isValidVersion(const QString &version)
693 return versionRegExp().exactMatch(version);
697 \fn int PluginSpecPrivate::versionCompare(const QString &version1, const QString &version2)
698 \internal
700 int PluginSpecPrivate::versionCompare(const QString &version1, const QString &version2)
702 QRegExp reg1 = versionRegExp();
703 QRegExp reg2 = versionRegExp();
705 if (!reg1.exactMatch(version1)) {
706 return 0;
708 if (!reg2.exactMatch(version2)) {
709 return 0;
711 int number1;
712 int number2;
713 for (int i = 0; i < 4; ++i) {
714 number1 = reg1.cap(i + 1).toInt();
715 number2 = reg2.cap(i + 1).toInt();
716 if (number1 < number2) {
717 return -1;
719 if (number1 > number2) {
720 return 1;
723 return 0;
727 \fn bool PluginSpecPrivate::resolveDependencies(const QList<PluginSpec *> &specs)
728 \internal
730 bool PluginSpecPrivate::resolveDependencies(const QList<PluginSpec *> &specs)
732 if (hasError) {
733 return false;
735 if (state == PluginSpec::Resolved) {
736 state = PluginSpec::Read; // Go back, so we just re-resolve the dependencies.
738 if (state != PluginSpec::Read) {
739 errorString = QCoreApplication::translate("PluginSpec", "Resolving dependencies failed because state != Read");
740 hasError = true;
741 return false;
743 QList<PluginSpec *> resolvedDependencies;
744 foreach(const PluginDependency &dependency, dependencies) {
745 PluginSpec *found = 0;
747 foreach(PluginSpec * spec, specs) {
748 if (spec->provides(dependency.name, dependency.version)) {
749 found = spec;
750 break;
753 if (!found) {
754 hasError = true;
755 if (!errorString.isEmpty()) {
756 errorString.append("\n");
758 errorString.append(QCoreApplication::translate("PluginSpec", "Could not resolve dependency '%1(%2)'")
759 .arg(dependency.name).arg(dependency.version));
760 continue;
762 resolvedDependencies.append(found);
764 if (hasError) {
765 return false;
767 dependencySpecs = resolvedDependencies;
768 state = PluginSpec::Resolved;
769 return true;
773 \fn bool PluginSpecPrivate::loadLibrary()
774 \internal
776 bool PluginSpecPrivate::loadLibrary()
778 if (hasError) {
779 return false;
781 if (state != PluginSpec::Resolved) {
782 if (state == PluginSpec::Loaded) {
783 return true;
785 errorString = QCoreApplication::translate("PluginSpec", "Loading the library failed because state != Resolved");
786 hasError = true;
787 return false;
789 #ifdef QT_NO_DEBUG
791 #ifdef Q_OS_WIN
792 QString libName = QString("%1/%2.dll").arg(location).arg(name);
793 #elif defined(Q_OS_MAC)
794 QString libName = QString("%1/lib%2.dylib").arg(location).arg(name);
795 #else
796 QString libName = QString("%1/lib%2.so").arg(location).arg(name);
797 #endif
799 #else // Q_NO_DEBUG
801 #ifdef Q_OS_WIN
802 QString libName = QString("%1/%2d.dll").arg(location).arg(name);
803 #elif defined(Q_OS_MAC)
804 QString libName = QString("%1/lib%2_debug.dylib").arg(location).arg(name);
805 #else
806 QString libName = QString("%1/lib%2.so").arg(location).arg(name);
807 #endif
809 #endif
811 PluginLoader loader(libName);
812 if (!loader.load()) {
813 hasError = true;
814 errorString = libName + QString::fromLatin1(": ") + loader.errorString();
815 return false;
817 IPlugin *pluginObject = qobject_cast<IPlugin *>(loader.instance());
818 if (!pluginObject) {
819 hasError = true;
820 errorString = QCoreApplication::translate("PluginSpec", "Plugin is not valid (does not derive from IPlugin)");
821 loader.unload();
822 return false;
824 state = PluginSpec::Loaded;
825 plugin = pluginObject;
826 plugin->d->pluginSpec = q;
827 return true;
831 \fn bool PluginSpecPrivate::initializePlugin()
832 \internal
834 bool PluginSpecPrivate::initializePlugin()
836 if (hasError) {
837 return false;
839 if (state != PluginSpec::Loaded) {
840 if (state == PluginSpec::Initialized) {
841 return true;
843 errorString = QCoreApplication::translate("PluginSpec", "Initializing the plugin failed because state != Loaded");
844 hasError = true;
845 return false;
847 if (!plugin) {
848 errorString = QCoreApplication::translate("PluginSpec", "Internal error: have no plugin instance to initialize");
849 hasError = true;
850 return false;
852 QString err;
853 if (!plugin->initialize(arguments, &err)) {
854 errorString = QCoreApplication::translate("PluginSpec", "Plugin initialization failed: %1").arg(err);
855 hasError = true;
856 return false;
858 state = PluginSpec::Initialized;
859 return true;
863 \fn bool PluginSpecPrivate::initializeExtensions()
864 \internal
866 bool PluginSpecPrivate::initializeExtensions()
868 if (hasError) {
869 return false;
871 if (state != PluginSpec::Initialized) {
872 if (state == PluginSpec::Running) {
873 return true;
875 errorString = QCoreApplication::translate("PluginSpec", "Cannot perform extensionsInitialized because state != Initialized");
876 hasError = true;
877 return false;
879 if (!plugin) {
880 errorString = QCoreApplication::translate("PluginSpec", "Internal error: have no plugin instance to perform extensionsInitialized");
881 hasError = true;
882 return false;
884 plugin->extensionsInitialized();
885 state = PluginSpec::Running;
886 return true;
890 \fn bool PluginSpecPrivate::stop()
891 \internal
893 void PluginSpecPrivate::stop()
895 if (!plugin) {
896 return;
898 plugin->shutdown();
899 state = PluginSpec::Stopped;
903 \fn bool PluginSpecPrivate::kill()
904 \internal
906 void PluginSpecPrivate::kill()
908 if (!plugin) {
909 return;
911 delete plugin;
912 plugin = 0;
913 state = PluginSpec::Deleted;