35 #include <QtCore/QFile>
36 #include <QtCore/QFileInfo>
37 #include <QtCore/QXmlStreamReader>
38 #include <QtCore/QRegExp>
39 #include <QtCore/QCoreApplication>
44 # define USE_UNPATCHED_QPLUGINLOADER 1
46 # define USE_UNPATCHED_QPLUGINLOADER 1
49 #if USE_UNPATCHED_QPLUGINLOADER
51 # include <QtCore/QPluginLoader>
56 # include "patchedpluginloader.cpp"
123 using namespace ExtensionSystem;
124 using namespace ExtensionSystem::Internal;
132 return name == other.
name && version == other.
version;
139 PluginSpec::PluginSpec()
333 return d->
provides(pluginName, version);
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";
411 QFile
file(fileName);
413 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()));
416 QFileInfo fileInfo(file);
418 filePath = fileInfo.absoluteFilePath();
419 QXmlStreamReader reader(&file);
420 while (!reader.atEnd()) {
422 switch (reader.tokenType()) {
423 case QXmlStreamReader::StartElement:
424 readPluginSpec(reader);
430 if (reader.hasError())
431 return reportError(tr(
"Error parsing file %1: %2, at line %3, column %4")
432 .arg(file.fileName())
433 .arg(reader.errorString())
434 .arg(reader.lineNumber())
435 .arg(reader.columnNumber()));
444 bool PluginSpecPrivate::reportError(
const QString &err)
451 static inline QString msgAttributeMissing(
const char *elt,
const char *attribute)
453 return QCoreApplication::translate(
"PluginSpec",
"'%1' misses attribute '%2'").arg(QLatin1String(elt), QLatin1String(attribute));
456 static inline QString msgInvalidFormat(
const char *content)
458 return QCoreApplication::translate(
"PluginSpec",
"'%1' has invalid format").arg(content);
461 static inline QString msgInvalidElement(
const QString &name)
463 return QCoreApplication::translate(
"PluginSpec",
"Invalid element '%1'").arg(name);
466 static inline QString msgUnexpectedClosing(
const QString &name)
468 return QCoreApplication::translate(
"PluginSpec",
"Unexpected closing element '%1'").arg(name);
471 static inline QString msgUnexpectedToken()
473 return QCoreApplication::translate(
"PluginSpec",
"Unexpected token");
480 void PluginSpecPrivate::readPluginSpec(QXmlStreamReader &reader)
482 QString element = reader.name().toString();
483 if (element != QString(PLUGIN)) {
484 reader.raiseError(QCoreApplication::translate(
"PluginSpec",
"Expected element '%1' as top level element").arg(PLUGIN));
487 name = reader.attributes().value(PLUGIN_NAME).toString();
488 if (name.isEmpty()) {
489 reader.raiseError(msgAttributeMissing(PLUGIN, PLUGIN_NAME));
492 version = reader.attributes().value(PLUGIN_VERSION).toString();
494 reader.raiseError(msgAttributeMissing(PLUGIN, PLUGIN_VERSION));
498 reader.raiseError(msgInvalidFormat(PLUGIN_VERSION));
501 compatVersion = reader.attributes().value(PLUGIN_COMPATVERSION).toString();
503 reader.raiseError(msgInvalidFormat(PLUGIN_COMPATVERSION));
508 while (!reader.atEnd()) {
510 switch (reader.tokenType()) {
511 case QXmlStreamReader::StartElement:
512 element = reader.name().toString();
513 if (element == VENDOR)
514 vendor = reader.readElementText().trimmed();
515 else if (element == COPYRIGHT)
516 copyright = reader.readElementText().trimmed();
517 else if (element == LICENSE)
518 license = reader.readElementText().trimmed();
519 else if (element == DESCRIPTION)
521 else if (element == URL)
522 url = reader.readElementText().trimmed();
523 else if (element == DEPENDENCYLIST)
524 readDependencies(reader);
525 else if (element == ARGUMENTLIST)
526 readArgumentDescriptions(reader);
528 reader.raiseError(msgInvalidElement(name));
530 case QXmlStreamReader::EndDocument:
531 case QXmlStreamReader::Comment:
532 case QXmlStreamReader::EndElement:
533 case QXmlStreamReader::Characters:
536 reader.raiseError(msgUnexpectedToken());
547 void PluginSpecPrivate::readArgumentDescriptions(QXmlStreamReader &reader)
550 while (!reader.atEnd()) {
552 switch (reader.tokenType()) {
553 case QXmlStreamReader::StartElement:
554 element = reader.name().toString();
555 if (element == ARGUMENT) {
556 readArgumentDescription(reader);
558 reader.raiseError(msgInvalidElement(name));
561 case QXmlStreamReader::Comment:
562 case QXmlStreamReader::Characters:
564 case QXmlStreamReader::EndElement:
565 element = reader.name().toString();
566 if (element == ARGUMENTLIST)
568 reader.raiseError(msgUnexpectedClosing(element));
571 reader.raiseError(msgUnexpectedToken());
581 void PluginSpecPrivate::readArgumentDescription(QXmlStreamReader &reader)
584 arg.
name = reader.attributes().value(ARGUMENT_NAME).toString();
585 if (arg.
name.isEmpty()) {
586 reader.raiseError(msgAttributeMissing(ARGUMENT, ARGUMENT_NAME));
589 arg.
parameter = reader.attributes().value(ARGUMENT_PARAMETER).toString();
591 if (reader.tokenType() != QXmlStreamReader::EndElement)
592 reader.raiseError(msgUnexpectedToken());
600 void PluginSpecPrivate::readDependencies(QXmlStreamReader &reader)
603 while (!reader.atEnd()) {
605 switch (reader.tokenType()) {
606 case QXmlStreamReader::StartElement:
607 element = reader.name().toString();
608 if (element == DEPENDENCY) {
609 readDependencyEntry(reader);
611 reader.raiseError(msgInvalidElement(name));
614 case QXmlStreamReader::Comment:
615 case QXmlStreamReader::Characters:
617 case QXmlStreamReader::EndElement:
618 element = reader.name().toString();
619 if (element == DEPENDENCYLIST)
621 reader.raiseError(msgUnexpectedClosing(element));
624 reader.raiseError(msgUnexpectedToken());
634 void PluginSpecPrivate::readDependencyEntry(QXmlStreamReader &reader)
637 dep.
name = reader.attributes().value(DEPENDENCY_NAME).toString();
638 if (dep.
name.isEmpty()) {
639 reader.raiseError(msgAttributeMissing(DEPENDENCY, DEPENDENCY_NAME));
642 dep.
version = reader.attributes().value(DEPENDENCY_VERSION).toString();
644 reader.raiseError(msgInvalidFormat(DEPENDENCY_VERSION));
649 if (reader.tokenType() != QXmlStreamReader::EndElement)
650 reader.raiseError(msgUnexpectedToken());
659 if (QString::compare(pluginName, name, Qt::CaseInsensitive) != 0)
668 QRegExp &PluginSpecPrivate::versionRegExp()
670 static QRegExp reg(
"([0-9]+)(?:[.]([0-9]+))?(?:[.]([0-9]+))?(?:_([0-9]+))?");
679 return versionRegExp().exactMatch(version);
688 QRegExp reg1 = versionRegExp();
689 QRegExp reg2 = versionRegExp();
690 if (!reg1.exactMatch(version1))
692 if (!reg2.exactMatch(version2))
696 for (
int i = 0;
i < 4; ++
i) {
697 number1 = reg1.cap(
i+1).toInt();
698 number2 = reg2.cap(
i+1).toInt();
699 if (number1 < number2)
701 if (number1 > number2)
718 errorString = QCoreApplication::translate(
"PluginSpec",
"Resolving dependencies failed because state != Read");
735 errorString.append(QCoreApplication::translate(
"PluginSpec",
"Could not resolve dependency '%1(%2)'")
739 resolvedDependencies.append(found);
759 errorString = QCoreApplication::translate(
"PluginSpec",
"Loading the library failed because state != Resolved");
766 QString libName = QString(
"%1/%2.dll").arg(
location).arg(name);
767 #elif defined(Q_OS_MAC)
768 QString libName = QString(
"%1/lib%2.dylib").arg(
location).arg(name);
770 QString libName = QString(
"%1/lib%2.so").arg(
location).arg(name);
776 QString libName = QString(
"%1/%2d.dll").arg(
location).arg(name);
777 #elif defined(Q_OS_MAC)
778 QString libName = QString(
"%1/lib%2_debug.dylib").arg(
location).arg(name);
780 QString libName = QString(
"%1/lib%2.so").arg(
location).arg(name);
785 PluginLoader loader(libName);
786 if (!loader.load()) {
788 errorString = libName + QString::fromLatin1(
": ") + loader.errorString();
791 IPlugin *pluginObject = qobject_cast<
IPlugin*>(loader.instance());
794 errorString = QCoreApplication::translate(
"PluginSpec",
"Plugin is not valid (does not derive from IPlugin)");
815 errorString = QCoreApplication::translate(
"PluginSpec",
"Initializing the plugin failed because state != Loaded");
820 errorString = QCoreApplication::translate(
"PluginSpec",
"Internal error: have no plugin instance to initialize");
826 errorString = QCoreApplication::translate(
"PluginSpec",
"Plugin initialization failed: %1").arg(err);
845 errorString = QCoreApplication::translate(
"PluginSpec",
"Cannot perform extensionsInitialized because state != Initialized");
850 errorString = QCoreApplication::translate(
"PluginSpec",
"Internal error: have no plugin instance to perform extensionsInitialized");
virtual void extensionsInitialized()=0
bool initializeExtensions()
QString copyright() const
PatchedPluginLoader PluginLoader
typedef QT_PREPEND_NAMESPACE(QPluginLoader) PluginLoader
PluginSpec::PluginArgumentDescriptions argumentDescriptions
bool provides(const QString &pluginName, const QString &version) const
void setArguments(const QStringList &arguments)
static bool isValidVersion(const QString &version)
QString errorString() const
QList< PluginDependency > dependencies
bool read(const QString &fileName)
bool operator==(const PluginDependency &other)
QList< PluginDependency > dependencies() const
bool provides(const QString &pluginName, const QString &version) const
static int versionCompare(const QString &version1, const QString &version2)
QStringList arguments() const
QString compatVersion() const
QList< PluginSpec * > dependencySpecs
virtual bool initialize(const QStringList &arguments, QString *errorString)=0
void addArgument(const QString &argument)
bool resolveDependencies(const QList< PluginSpec * > &specs)
PluginArgumentDescriptions argumentDescriptions() const
Contains the information of the plugins xml description file and information about the plugin's curre...
Struct that contains the name and required compatible version number of a plugin's dependency...
QList< PluginSpec * > dependencySpecs() const
QString description() const
Base class for all plugins.