Changed: #1206 Update plugin system. Now plugin manager takes into account dependencies between plug-ins. Update core, object viewer and example plugin.

This commit is contained in:
dnk-88 2011-02-28 21:01:35 +02:00
parent b1535e1981
commit b9df3fb0f5
16 changed files with 457 additions and 263 deletions

View file

@ -1,27 +1,27 @@
/* // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
Object Viewer Qt // Copyright (C) 2010 Winch Gate Property Limited
Copyright (C) 2010 Dzmitry Kamiahin <dnk-88@tut.by> // Copyright (C) 2011 Dzmitry Kamiahin <dnk-88@tut.by>
// Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
This program is free software: you can redistribute it and/or modify //
it under the terms of the GNU General Public License as published by // This program is free software: you can redistribute it and/or modify
the Free Software Foundation, either version 3 of the License, or // it under the terms of the GNU Affero General Public License as
(at your option) any later version. // published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, //
but WITHOUT ANY WARRANTY; without even the implied warranty of // This program is distributed in the hope that it will be useful,
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License //
along with this program. If not, see <http://www.gnu.org/licenses/>. // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IPLUGIN_H #ifndef IPLUGIN_H
#define IPLUGIN_H #define IPLUGIN_H
#include <QtCore/QtPlugin> #include <QtCore/QtPlugin>
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QStringList>
#include "iplugin_manager.h" #include "iplugin_manager.h"
@ -46,17 +46,61 @@ class IPlugin
public: public:
virtual ~IPlugin() {} virtual ~IPlugin() {}
/**
@brief Called after the plugin has been loaded and the IPlugin instance has been created.
@details The initialize methods of plugins that depend
on this plugin are called after the initialize method of this plugin
has been called. Plugins should initialize their internal state in this
method. Returns if initialization of successful. If it wasn't successful,
the \a errorString should be set to a user-readable message
describing the reason.
*/
virtual bool initialize(IPluginManager *pluginManager, QString *errorString) = 0; virtual bool initialize(IPluginManager *pluginManager, QString *errorString) = 0;
/**
@brief Called after the IPlugin::initialize() method has been called,
and after both the IPlugin::initialize() and IPlugin::extensionsInitialized()
methods of plugins that depend on this plugin have been called.
@details In this method, the plugin can assume that plugins that depend on
this plugin are fully 'up and running'. It is a good place to
look in the plugin manager's object pool for objects that have
been provided by dependent plugins.
*/
virtual void extensionsInitialized() = 0; virtual void extensionsInitialized() = 0;
/**
@\brief Called during a shutdown sequence in the same order as initialization
before the plugins get deleted in reverse order.
@details This method should be used to disconnect from other plugins,
hide all UI, and optimize shutdown in general.
*/
virtual void shutdown() { } virtual void shutdown() { }
/**
@\brief This method should be implemented to work properly NeL singletons.
Called immediately after loading the plugin.
@code
void Plugin::setNelContext(NLMISC::INelContext *nelContext)
{
#ifdef NL_OS_WINDOWS
// Ensure that a context doesn't exist yet.
// This only applies to platforms without PIC, e.g. Windows.
nlassert(!NLMISC::INelContext::isContextInitialised());
#endif // NL_OS_WINDOWS
_LibContext = new NLMISC::CLibraryContext(*nelContext);
}
@endcode
*/
virtual void setNelContext(NLMISC::INelContext *nelContext) = 0; virtual void setNelContext(NLMISC::INelContext *nelContext) = 0;
virtual QString name() const = 0; virtual QString name() const = 0;
virtual QString version() const = 0; virtual QString version() const = 0;
virtual QString vendor() const = 0; virtual QString vendor() const = 0;
virtual QString description() const = 0; virtual QString description() const = 0;
virtual QList<QString> dependencies() const = 0; virtual QStringList dependencies() const = 0;
}; };
}; //namespace ExtensionSystem }; //namespace ExtensionSystem

View file

@ -1,26 +1,25 @@
/* // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
Object Viewer Qt // Copyright (C) 2010 Winch Gate Property Limited
Copyright (C) 2010 Dzmitry Kamiahin <dnk-88@tut.by> // Copyright (C) 2011 Dzmitry Kamiahin <dnk-88@tut.by>
// Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
This program is free software: you can redistribute it and/or modify //
it under the terms of the GNU General Public License as published by // This program is free software: you can redistribute it and/or modify
the Free Software Foundation, either version 3 of the License, or // it under the terms of the GNU Affero General Public License as
(at your option) any later version. // published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, //
but WITHOUT ANY WARRANTY; without even the implied warranty of // This program is distributed in the hope that it will be useful,
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License //
along with this program. If not, see <http://www.gnu.org/licenses/>. // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IPLUGINMANAGER_H #ifndef IPLUGINMANAGER_H
#define IPLUGINMANAGER_H #define IPLUGINMANAGER_H
#include "plugin_spec.h" #include "iplugin_spec.h"
#include <QtCore/QList> #include <QtCore/QList>
#include <QtCore/QObject> #include <QtCore/QObject>
@ -62,6 +61,8 @@ public:
virtual QSettings *settings() const = 0; virtual QSettings *settings() const = 0;
// Auxiliary operations // Auxiliary operations
/// Retrieve all objects of a given type from the object pool.
template <typename T> template <typename T>
QList<T *> getObjects() const QList<T *> getObjects() const
{ {
@ -76,6 +77,7 @@ public:
return objects; return objects;
} }
/// Retrieve the object of a given type from the object pool.
template <typename T> template <typename T>
T *getObject() const T *getObject() const
{ {
@ -124,9 +126,13 @@ public:
} }
Q_SIGNALS: Q_SIGNALS:
/// Signal that \a obj has been added to the object pool.
void objectAdded(QObject *obj); void objectAdded(QObject *obj);
/// Signal that \a obj will be removed from the object pool.
void aboutToRemoveObject(QObject *obj); void aboutToRemoveObject(QObject *obj);
/// Signal that the list of available plugins has changed.
void pluginsChanged(); void pluginsChanged();
}; };

View file

@ -1,21 +1,20 @@
/* // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
Object Viewer Qt // Copyright (C) 2010 Winch Gate Property Limited
Copyright (C) 2010 Dzmitry Kamiahin <dnk-88@tut.by> // Copyright (C) 2011 Dzmitry Kamiahin <dnk-88@tut.by>
// Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
This program is free software: you can redistribute it and/or modify //
it under the terms of the GNU General Public License as published by // This program is free software: you can redistribute it and/or modify
the Free Software Foundation, either version 3 of the License, or // it under the terms of the GNU Affero General Public License as
(at your option) any later version. // published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, //
but WITHOUT ANY WARRANTY; without even the implied warranty of // This program is distributed in the hope that it will be useful,
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License //
along with this program. If not, see <http://www.gnu.org/licenses/>. // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IPLUGINSPEC_H #ifndef IPLUGINSPEC_H
#define IPLUGINSPEC_H #define IPLUGINSPEC_H
@ -39,6 +38,7 @@ struct State
Invalid = 1, Invalid = 1,
Read, Read,
Loaded, Loaded,
Resolved,
Initialized, Initialized,
Running, Running,
Stopped, Stopped,

View file

@ -1,23 +1,23 @@
/* // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
Object Viewer Qt // Copyright (C) 2010 Winch Gate Property Limited
Copyright (C) 2010 Dzmitry Kamiahin <dnk-88@tut.by> // Copyright (C) 2011 Dzmitry Kamiahin <dnk-88@tut.by>
// Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
This program is free software: you can redistribute it and/or modify //
it under the terms of the GNU General Public License as published by // This program is free software: you can redistribute it and/or modify
the Free Software Foundation, either version 3 of the License, or // it under the terms of the GNU Affero General Public License as
(at your option) any later version. // published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, //
but WITHOUT ANY WARRANTY; without even the implied warranty of // This program is distributed in the hope that it will be useful,
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License //
along with this program. If not, see <http://www.gnu.org/licenses/>. // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "plugin_manager.h" #include "plugin_manager.h"
#include "plugin_spec.h"
#include <QtCore/QDir> #include <QtCore/QDir>
@ -28,7 +28,7 @@ namespace ExtensionSystem
CPluginManager::CPluginManager(QObject *parent) CPluginManager::CPluginManager(QObject *parent)
:IPluginManager(parent), :IPluginManager(parent),
_settings(0) m_settings(0)
{ {
} }
@ -36,25 +36,25 @@ CPluginManager::~CPluginManager()
{ {
stopAll(); stopAll();
deleteAll(); deleteAll();
qDeleteAll(_pluginSpecs); qDeleteAll(m_pluginSpecs);
} }
void CPluginManager::addObject(QObject *obj) void CPluginManager::addObject(QObject *obj)
{ {
QWriteLocker lock(&_lock); QWriteLocker lock(&m_lock);
if (obj == 0) if (obj == 0)
{ {
nlwarning("trying to add null object"); nlwarning("trying to add null object");
return; return;
} }
if (_allObjects.contains(obj)) if (m_allObjects.contains(obj))
{ {
nlwarning("trying to add duplicate object"); nlwarning("trying to add duplicate object");
return; return;
} }
nlinfo(QString("addObject: " + obj->objectName()).toStdString().c_str()); nlinfo(QString("addObject: " + obj->objectName()).toStdString().c_str());
_allObjects.append(obj); m_allObjects.append(obj);
Q_EMIT objectAdded(obj); Q_EMIT objectAdded(obj);
} }
@ -67,7 +67,7 @@ void CPluginManager::removeObject(QObject *obj)
return; return;
} }
if (!_allObjects.contains(obj)) if (!m_allObjects.contains(obj))
{ {
nlinfo(QString("object not in list: " + obj->objectName()).toStdString().c_str()); nlinfo(QString("object not in list: " + obj->objectName()).toStdString().c_str());
return; return;
@ -75,24 +75,29 @@ void CPluginManager::removeObject(QObject *obj)
nlinfo(QString("removeObject: " + obj->objectName()).toStdString().c_str()); nlinfo(QString("removeObject: " + obj->objectName()).toStdString().c_str());
Q_EMIT aboutToRemoveObject(obj); Q_EMIT aboutToRemoveObject(obj);
QWriteLocker lock(&_lock); QWriteLocker lock(&m_lock);
_allObjects.removeAll(obj); m_allObjects.removeAll(obj);
} }
QList<QObject *> CPluginManager::allObjects() const QList<QObject *> CPluginManager::allObjects() const
{ {
return _allObjects; return m_allObjects;
} }
void CPluginManager::loadPlugins() void CPluginManager::loadPlugins()
{ {
Q_FOREACH (CPluginSpec *spec, _pluginSpecs) Q_FOREACH (CPluginSpec *spec, m_pluginSpecs)
setPluginState(spec, State::Loaded); setPluginState(spec, State::Loaded);
Q_FOREACH (CPluginSpec *spec, _pluginSpecs) Q_FOREACH (CPluginSpec *spec, m_pluginSpecs)
setPluginState(spec, State::Resolved);
QList<CPluginSpec *> queue = loadQueue();
Q_FOREACH (CPluginSpec *spec, queue)
setPluginState(spec, State::Initialized); setPluginState(spec, State::Initialized);
QListIterator<CPluginSpec *> it(_pluginSpecs); QListIterator<CPluginSpec *> it(queue);
it.toBack(); it.toBack();
while (it.hasPrevious()) while (it.hasPrevious())
setPluginState(it.previous(), State::Running); setPluginState(it.previous(), State::Running);
@ -102,28 +107,28 @@ void CPluginManager::loadPlugins()
QStringList CPluginManager::getPluginPaths() const QStringList CPluginManager::getPluginPaths() const
{ {
return _pluginPaths; return m_pluginPaths;
} }
void CPluginManager::setPluginPaths(const QStringList &paths) void CPluginManager::setPluginPaths(const QStringList &paths)
{ {
_pluginPaths = paths; m_pluginPaths = paths;
readPluginPaths(); readPluginPaths();
} }
QList<IPluginSpec *> CPluginManager::plugins() const QList<IPluginSpec *> CPluginManager::plugins() const
{ {
return _ipluginSpecs; return m_ipluginSpecs;
} }
void CPluginManager::setSettings(QSettings *settings) void CPluginManager::setSettings(QSettings *settings)
{ {
_settings = settings; m_settings = settings;
} }
QSettings *CPluginManager::settings() const QSettings *CPluginManager::settings() const
{ {
return _settings; return m_settings;
} }
void CPluginManager::readSettings() void CPluginManager::readSettings()
@ -136,12 +141,12 @@ void CPluginManager::writeSettings()
void CPluginManager::readPluginPaths() void CPluginManager::readPluginPaths()
{ {
qDeleteAll(_pluginSpecs); qDeleteAll(m_pluginSpecs);
_pluginSpecs.clear(); m_pluginSpecs.clear();
_ipluginSpecs.clear(); m_ipluginSpecs.clear();
QStringList pluginsList; QStringList pluginsList;
QStringList searchPaths = _pluginPaths; QStringList searchPaths = m_pluginPaths;
while (!searchPaths.isEmpty()) while (!searchPaths.isEmpty())
{ {
const QDir dir(searchPaths.takeFirst()); const QDir dir(searchPaths.takeFirst());
@ -161,9 +166,9 @@ void CPluginManager::readPluginPaths()
{ {
CPluginSpec *spec = new CPluginSpec; CPluginSpec *spec = new CPluginSpec;
spec->setFileName(pluginFile); spec->setFileName(pluginFile);
spec->_pluginManager = this; spec->m_pluginManager = this;
_pluginSpecs.append(spec); m_pluginSpecs.append(spec);
_ipluginSpecs.append(spec); m_ipluginSpecs.append(spec);
} }
Q_EMIT pluginsChanged(); Q_EMIT pluginsChanged();
@ -171,36 +176,115 @@ void CPluginManager::readPluginPaths()
void CPluginManager::setPluginState(CPluginSpec *spec, int destState) void CPluginManager::setPluginState(CPluginSpec *spec, int destState)
{ {
if (spec->hasError()) if (spec->hasError() || spec->getState() != destState-1)
return; return;
if (destState == State::Running)
switch (destState)
{ {
case State::Loaded:
spec->loadLibrary();
return;
case State::Resolved:
spec->resolveDependencies(m_pluginSpecs);
return;
case State::Running:
spec->initializeExtensions(); spec->initializeExtensions();
return; return;
} case State::Deleted:
else if (destState == State::Deleted)
{
spec->kill(); spec->kill();
return; return;
default:
break;
}
Q_FOREACH (const CPluginSpec *depSpec, spec->dependencySpecs())
{
if (depSpec->getState() != destState)
{
spec->m_hasError = true;
spec->m_errorString = tr("Cannot initializing plugin because dependency failed to load: %1\nReason: %2")
.arg(depSpec->name()).arg(depSpec->errorString());
return;
}
}
switch (destState)
{
case State::Initialized:
spec->initializePlugin();
break;
case State::Stopped:
spec->stop();
break;
default:
break;
}
} }
if (destState == State::Loaded) QList<CPluginSpec *> CPluginManager::loadQueue()
spec->loadLibrary(); {
else if (destState == State::Initialized) QList<CPluginSpec *> queue;
spec->initializePlugin(); Q_FOREACH(CPluginSpec *spec, m_pluginSpecs)
else if (destState == State::Stopped) {
spec->stop(); QList<CPluginSpec *> circularityCheckQueue;
loadQueue(spec, queue, circularityCheckQueue);
}
return queue;
}
bool CPluginManager::loadQueue(CPluginSpec *spec, QList<CPluginSpec *> &queue,
QList<CPluginSpec *> &circularityCheckQueue)
{
if (queue.contains(spec))
return true;
// check for circular dependencies
if (circularityCheckQueue.contains(spec))
{
spec->m_hasError = true;
spec->m_errorString = tr("Circular dependency detected:\n");
int index = circularityCheckQueue.indexOf(spec);
for (int i = index; i < circularityCheckQueue.size(); ++i)
{
spec->m_errorString.append(tr("%1(%2) depends on\n")
.arg(circularityCheckQueue.at(i)->name()).arg(circularityCheckQueue.at(i)->version()));
}
spec->m_errorString.append(tr("%1(%2)").arg(spec->name()).arg(spec->version()));
return false;
}
circularityCheckQueue.append(spec);
// check if we have the dependencies
if (spec->getState() == State::Invalid || spec->getState() == State::Read)
{
queue.append(spec);
return false;
}
// add dependencies
Q_FOREACH (CPluginSpec *depSpec, spec->dependencySpecs())
{
if (!loadQueue(depSpec, queue, circularityCheckQueue))
{
spec->m_hasError = true;
spec->m_errorString =
tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
.arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString());
return false;
}
}
// add self
queue.append(spec);
return true;
} }
void CPluginManager::stopAll() void CPluginManager::stopAll()
{ {
Q_FOREACH (CPluginSpec *spec, _pluginSpecs) QList<CPluginSpec *> queue = loadQueue();
Q_FOREACH (CPluginSpec *spec, queue)
setPluginState(spec, State::Stopped); setPluginState(spec, State::Stopped);
} }
void CPluginManager::deleteAll() void CPluginManager::deleteAll()
{ {
QListIterator<CPluginSpec *> it(_pluginSpecs); QList<CPluginSpec *> queue = loadQueue();
QListIterator<CPluginSpec *> it(queue);
it.toBack(); it.toBack();
while (it.hasPrevious()) while (it.hasPrevious())
{ {

View file

@ -1,21 +1,20 @@
/* // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
Object Viewer Qt // Copyright (C) 2010 Winch Gate Property Limited
Copyright (C) 2010 Dzmitry Kamiahin <dnk-88@tut.by> // Copyright (C) 2011 Dzmitry Kamiahin <dnk-88@tut.by>
// Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
This program is free software: you can redistribute it and/or modify //
it under the terms of the GNU General Public License as published by // This program is free software: you can redistribute it and/or modify
the Free Software Foundation, either version 3 of the License, or // it under the terms of the GNU Affero General Public License as
(at your option) any later version. // published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, //
but WITHOUT ANY WARRANTY; without even the implied warranty of // This program is distributed in the hope that it will be useful,
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License //
along with this program. If not, see <http://www.gnu.org/licenses/>. // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLUGINMANAGER_H #ifndef PLUGINMANAGER_H
#define PLUGINMANAGER_H #define PLUGINMANAGER_H
@ -50,6 +49,7 @@ public:
virtual QStringList getPluginPaths() const; virtual QStringList getPluginPaths() const;
virtual void setPluginPaths(const QStringList &paths); virtual void setPluginPaths(const QStringList &paths);
virtual QList<IPluginSpec *> plugins() const; virtual QList<IPluginSpec *> plugins() const;
QList<CPluginSpec *> loadQueue();
// Settings // Settings
virtual void setSettings(QSettings *settings); virtual void setSettings(QSettings *settings);
@ -60,16 +60,17 @@ public:
private: private:
void setPluginState(CPluginSpec *spec, int destState); void setPluginState(CPluginSpec *spec, int destState);
void readPluginPaths(); void readPluginPaths();
bool loadQueue(CPluginSpec *spec, QList<CPluginSpec *> &queue, QList<CPluginSpec *> &circularityCheckQueue);
void stopAll(); void stopAll();
void deleteAll(); void deleteAll();
mutable QReadWriteLock _lock; mutable QReadWriteLock m_lock;
QSettings *_settings; QSettings *m_settings;
QList<CPluginSpec *> _pluginSpecs; QList<CPluginSpec *> m_pluginSpecs;
QList<IPluginSpec *> _ipluginSpecs; QList<IPluginSpec *> m_ipluginSpecs;
QStringList _pluginPaths; QStringList m_pluginPaths;
QList<QObject *> _allObjects; QList<QObject *> m_allObjects;
}; // class CPluginManager }; // class CPluginManager

View file

@ -1,22 +1,20 @@
/* // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
Object Viewer Qt // Copyright (C) 2010 Winch Gate Property Limited
Copyright (C) 2010 Dzmitry Kamiahin <dnk-88@tut.by> // Copyright (C) 2011 Dzmitry Kamiahin <dnk-88@tut.by>
// Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
This program is free software: you can redistribute it and/or modify //
it under the terms of the GNU General Public License as published by // This program is free software: you can redistribute it and/or modify
the Free Software Foundation, either version 3 of the License, or // it under the terms of the GNU Affero General Public License as
(at your option) any later version. // published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, //
but WITHOUT ANY WARRANTY; without even the implied warranty of // This program is distributed in the hope that it will be useful,
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License //
along with this program. If not, see <http://www.gnu.org/licenses/>. // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "plugin_spec.h" #include "plugin_spec.h"
#include <QtCore/QList> #include <QtCore/QList>
@ -34,74 +32,79 @@ namespace ExtensionSystem
{ {
CPluginSpec::CPluginSpec() CPluginSpec::CPluginSpec()
: _location(""), : m_location(""),
_filePath(""), m_filePath(""),
_fileName(""), m_fileName(""),
_name(""), m_name(""),
_version(""), m_version(""),
_vendor(""), m_vendor(""),
_description(""), m_description(""),
_state(State::Invalid), m_state(State::Invalid),
_hasError(false), m_hasError(false),
_errorString(""), m_errorString(""),
_plugin(0), m_plugin(0),
_pluginManager(0) m_pluginManager(0)
{ {
} }
QString CPluginSpec::name() const QString CPluginSpec::name() const
{ {
return _name; return m_name;
} }
QString CPluginSpec::version() const QString CPluginSpec::version() const
{ {
return _version; return m_version;
} }
QString CPluginSpec::vendor() const QString CPluginSpec::vendor() const
{ {
return _vendor; return m_vendor;
} }
QString CPluginSpec::description() const QString CPluginSpec::description() const
{ {
return _description; return m_description;
} }
QString CPluginSpec::location() const QString CPluginSpec::location() const
{ {
return _location; return m_location;
} }
QString CPluginSpec::filePath() const QString CPluginSpec::filePath() const
{ {
return _filePath; return m_filePath;
} }
QString CPluginSpec::fileName() const QString CPluginSpec::fileName() const
{ {
return _fileName; return m_fileName;
} }
IPlugin* CPluginSpec::plugin() const IPlugin* CPluginSpec::plugin() const
{ {
return _plugin; return m_plugin;
} }
int CPluginSpec::getState() const int CPluginSpec::getState() const
{ {
return _state; return m_state;
} }
bool CPluginSpec::hasError() const bool CPluginSpec::hasError() const
{ {
return _hasError; return m_hasError;
} }
QString CPluginSpec::errorString() const QString CPluginSpec::errorString() const
{ {
return _errorString; return m_errorString;
}
QList<CPluginSpec *> CPluginSpec::dependencySpecs() const
{
return m_dependencySpecs;
} }
bool CPluginSpec::setFileName(const QString &fileName) bool CPluginSpec::setFileName(const QString &fileName)
@ -113,26 +116,26 @@ bool CPluginSpec::setFileName(const QString &fileName)
return reportError(QCoreApplication::translate("CPluginSpec", "Could not open file for read: %1").arg(file.fileName())); return reportError(QCoreApplication::translate("CPluginSpec", "Could not open file for read: %1").arg(file.fileName()));
QFileInfo fileInfo(file); QFileInfo fileInfo(file);
_location = fileInfo.absolutePath(); m_location = fileInfo.absolutePath();
_filePath = fileInfo.absoluteFilePath(); m_filePath = fileInfo.absoluteFilePath();
_fileName = fileInfo.fileName(); m_fileName = fileInfo.fileName();
_state = State::Read; m_state = State::Read;
return true; return true;
} }
bool CPluginSpec::loadLibrary() bool CPluginSpec::loadLibrary()
{ {
if (_hasError) if (m_hasError)
return false; return false;
if (_state != State::Read) if (m_state != State::Read)
{ {
if (_state == State::Loaded) if (m_state == State::Loaded)
return true; return true;
return reportError(QCoreApplication::translate("CPluginSpec", "Loading the library failed because state != Resolved")); return reportError(QCoreApplication::translate("CPluginSpec", "Loading the library failed because state != Resolved"));
} }
QPluginLoader loader(_filePath); QPluginLoader loader(m_filePath);
if (!loader.load()) if (!loader.load())
return reportError(loader.errorString()); return reportError(loader.errorString());
@ -145,76 +148,121 @@ bool CPluginSpec::loadLibrary()
pluginObject->setNelContext(&NLMISC::INelContext::getInstance()); pluginObject->setNelContext(&NLMISC::INelContext::getInstance());
_name = pluginObject->name(); m_name = pluginObject->name();
_version = pluginObject->version(); m_version = pluginObject->version();
_vendor = pluginObject->vendor(); m_vendor = pluginObject->vendor();
_description = pluginObject->description(); m_description = pluginObject->description();
m_state = State::Loaded;
m_plugin = pluginObject;
return true;
}
bool CPluginSpec::resolveDependencies(const QList<CPluginSpec *> &specs)
{
if (m_hasError)
return false;
if (m_state != State::Loaded)
{
m_errorString = QCoreApplication::translate("CPluginSpec", "Resolving dependencies failed because state != Read");
m_hasError = true;
return false;
}
QList<CPluginSpec *> resolvedDependencies;
QStringList dependencies = m_plugin->dependencies();
Q_FOREACH(const QString &dependency, dependencies)
{
CPluginSpec *found = 0;
Q_FOREACH(CPluginSpec *spec, specs)
{
if (QString::compare(dependency, spec->name(), Qt::CaseInsensitive) == 0)
{
found = spec;
break;
}
}
if (!found)
{
m_hasError = true;
if (!m_errorString.isEmpty())
m_errorString.append(QLatin1Char('\n'));
m_errorString.append(QCoreApplication::translate("CPluginSpec", "Could not resolve dependency '%1'")
.arg(dependency));
continue;
}
resolvedDependencies.append(found);
}
if (m_hasError)
return false;
m_dependencySpecs = resolvedDependencies;
m_state = State::Resolved;
_state = State::Loaded;
_plugin = pluginObject;
return true; return true;
} }
bool CPluginSpec::initializePlugin() bool CPluginSpec::initializePlugin()
{ {
if (_hasError) if (m_hasError)
return false; return false;
if (_state != State::Loaded) if (m_state != State::Resolved)
{ {
if (_state == State::Initialized) if (m_state == State::Initialized)
return true; return true;
return reportError(QCoreApplication::translate("CPluginSpec", "Initializing the plugin failed because state != Loaded)")); return reportError(QCoreApplication::translate("CPluginSpec", "Initializing the plugin failed because state != Resolved)"));
} }
if (!_plugin) if (!m_plugin)
return reportError(QCoreApplication::translate("CPluginSpec", "Internal error: have no plugin instance to initialize")); return reportError(QCoreApplication::translate("CPluginSpec", "Internal error: have no plugin instance to initialize"));
QString err; QString err;
if (!_plugin->initialize(_pluginManager, &err)) if (!m_plugin->initialize(m_pluginManager, &err))
return reportError(QCoreApplication::translate("CPluginSpec", "Plugin initialization failed: %1").arg(err)); return reportError(QCoreApplication::translate("CPluginSpec", "Plugin initialization failed: %1").arg(err));
_state = State::Initialized; m_state = State::Initialized;
return true; return true;
} }
bool CPluginSpec::initializeExtensions() bool CPluginSpec::initializeExtensions()
{ {
if (_hasError) if (m_hasError)
return false; return false;
if (_state != State::Initialized) if (m_state != State::Initialized)
{ {
if (_state == State::Running) if (m_state == State::Running)
return true; return true;
return reportError(QCoreApplication::translate("CPluginSpec", "Cannot perform extensionsInitialized because state != Initialized")); return reportError(QCoreApplication::translate("CPluginSpec", "Cannot perform extensionsInitialized because state != Initialized"));
} }
if (!_plugin) if (!m_plugin)
return reportError(QCoreApplication::translate("CPluginSpec", "Internal error: have no plugin instance to perform extensionsInitialized")); return reportError(QCoreApplication::translate("CPluginSpec", "Internal error: have no plugin instance to perform extensionsInitialized"));
_plugin->extensionsInitialized(); m_plugin->extensionsInitialized();
_state = State::Running; m_state = State::Running;
return true; return true;
} }
void CPluginSpec::stop() void CPluginSpec::stop()
{ {
if (!_plugin) if (!m_plugin)
return; return;
_plugin->shutdown(); m_plugin->shutdown();
_state = State::Stopped; m_state = State::Stopped;
} }
void CPluginSpec::kill() void CPluginSpec::kill()
{ {
if (!_plugin) if (!m_plugin)
return; return;
delete _plugin; delete m_plugin;
_plugin = 0; m_plugin = 0;
_state = State::Deleted; m_state = State::Deleted;
} }
bool CPluginSpec::reportError(const QString &err) bool CPluginSpec::reportError(const QString &err)
{ {
_errorString = err; m_errorString = err;
_hasError = true; m_hasError = true;
return false; return false;
} }

View file

@ -1,27 +1,28 @@
/* // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
Object Viewer Qt // Copyright (C) 2010 Winch Gate Property Limited
Copyright (C) 2010 Dzmitry Kamiahin <dnk-88@tut.by> // Copyright (C) 2011 Dzmitry Kamiahin <dnk-88@tut.by>
// Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
This program is free software: you can redistribute it and/or modify //
it under the terms of the GNU General Public License as published by // This program is free software: you can redistribute it and/or modify
the Free Software Foundation, either version 3 of the License, or // it under the terms of the GNU Affero General Public License as
(at your option) any later version. // published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, //
but WITHOUT ANY WARRANTY; without even the implied warranty of // This program is distributed in the hope that it will be useful,
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License //
along with this program. If not, see <http://www.gnu.org/licenses/>. // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLUGINSPEC_H #ifndef PLUGINSPEC_H
#define PLUGINSPEC_H #define PLUGINSPEC_H
#include "iplugin_spec.h" #include "iplugin_spec.h"
#include "QtCore/QList"
namespace ExtensionSystem namespace ExtensionSystem
{ {
@ -43,12 +44,14 @@ public:
virtual int getState() const; virtual int getState() const;
virtual bool hasError() const; virtual bool hasError() const;
virtual QString errorString() const; virtual QString errorString() const;
QList<CPluginSpec *> dependencySpecs() const;
private: private:
CPluginSpec(); CPluginSpec();
bool setFileName(const QString &fileName); bool setFileName(const QString &fileName);
bool loadLibrary(); bool loadLibrary();
bool resolveDependencies(const QList<CPluginSpec *> &specs);
bool initializePlugin(); bool initializePlugin();
bool initializeExtensions(); bool initializeExtensions();
void stop(); void stop();
@ -56,21 +59,22 @@ private:
bool reportError(const QString &err); bool reportError(const QString &err);
QString _location; QString m_location;
QString _filePath; QString m_filePath;
QString _fileName; QString m_fileName;
QString _name; QString m_name;
QString _version; QString m_version;
QString _vendor; QString m_vendor;
QString _description; QString m_description;
int _state; int m_state;
bool _hasError; bool m_hasError;
QString _errorString; QString m_errorString;
IPlugin *_plugin; IPlugin *m_plugin;
IPluginManager *_pluginManager; IPluginManager *m_pluginManager;
QList<CPluginSpec *> m_dependencySpecs;
friend class CPluginManager; friend class CPluginManager;
}; };

View file

@ -26,6 +26,7 @@ namespace Constants
const char * const OVQT_VERSION_LONG = "0.0.1"; const char * const OVQT_VERSION_LONG = "0.0.1";
const char * const OVQT_VENDOR = "Dzmitry Kamiahin"; const char * const OVQT_VENDOR = "Dzmitry Kamiahin";
const char * const OVQT_YEAR = "2010, 2011"; const char * const OVQT_YEAR = "2010, 2011";
const char * const OVQT_CORE_PLUGIN = "Core";
//mainwindow //mainwindow
const char * const MAIN_WINDOW = "ObjectViewerQt.MainWindow"; const char * const MAIN_WINDOW = "ObjectViewerQt.MainWindow";

View file

@ -63,7 +63,8 @@ bool CorePlugin::initialize(ExtensionSystem::IPluginManager *pluginManager, QStr
QtWin::extendFrameIntoClientArea(_mainWindow); QtWin::extendFrameIntoClientArea(_mainWindow);
_mainWindow->setContentsMargins(0, 0, 0, 0); _mainWindow->setContentsMargins(0, 0, 0, 0);
} }
*/ bool success = _mainWindow->initialize(errorString); */
bool success = _mainWindow->initialize(errorString);
CSearchPathsSettingsPage *serchPathPage = new CSearchPathsSettingsPage(this); CSearchPathsSettingsPage *serchPathPage = new CSearchPathsSettingsPage(this);
serchPathPage->applySearchPaths(); serchPathPage->applySearchPaths();
addAutoReleasedObject(serchPathPage); addAutoReleasedObject(serchPathPage);
@ -91,7 +92,7 @@ void CorePlugin::setNelContext(NLMISC::INelContext *nelContext)
QString CorePlugin::name() const QString CorePlugin::name() const
{ {
return QLatin1String("Core"); return QLatin1String(Constants::OVQT_CORE_PLUGIN);
} }
QString CorePlugin::version() const QString CorePlugin::version() const
@ -109,9 +110,9 @@ QString CorePlugin::description() const
return "Core plugin."; return "Core plugin.";
} }
QList<QString> CorePlugin::dependencies() const QStringList CorePlugin::dependencies() const
{ {
return QList<QString>(); return QStringList();
} }
void CorePlugin::addAutoReleasedObject(QObject *obj) void CorePlugin::addAutoReleasedObject(QObject *obj)

View file

@ -57,7 +57,7 @@ public:
QString version() const; QString version() const;
QString vendor() const; QString vendor() const;
QString description() const; QString description() const;
QList<QString> dependencies() const; QStringList dependencies() const;
void addAutoReleasedObject(QObject *obj); void addAutoReleasedObject(QObject *obj);

View file

@ -86,9 +86,12 @@ QString MyPlugin::description() const
return "Example ovqt plugin."; return "Example ovqt plugin.";
} }
QList<QString> MyPlugin::dependencies() const QStringList MyPlugin::dependencies() const
{ {
return QList<QString>(); QStringList list;
list.append(Core::Constants::OVQT_CORE_PLUGIN);
list.append("ObjectViewer");
return list;
} }
void MyPlugin::addAutoReleasedObject(QObject *obj) void MyPlugin::addAutoReleasedObject(QObject *obj)

View file

@ -43,7 +43,7 @@ public:
QString version() const; QString version() const;
QString vendor() const; QString vendor() const;
QString description() const; QString description() const;
QList<QString> dependencies() const; QStringList dependencies() const;
void addAutoReleasedObject(QObject *obj); void addAutoReleasedObject(QObject *obj);

View file

@ -65,9 +65,11 @@ QString ObjectViewerPlugin::description() const
return "Object Viewer plugin."; return "Object Viewer plugin.";
} }
QList<QString> ObjectViewerPlugin::dependencies() const QStringList ObjectViewerPlugin::dependencies() const
{ {
return QList<QString>(); QStringList list;
list.append(Core::Constants::OVQT_CORE_PLUGIN);
return list;
} }
void ObjectViewerPlugin::addAutoReleasedObject(QObject *obj) void ObjectViewerPlugin::addAutoReleasedObject(QObject *obj)

View file

@ -42,7 +42,7 @@ public:
QString version() const; QString version() const;
QString vendor() const; QString vendor() const;
QString description() const; QString description() const;
QList<QString> dependencies() const; QStringList dependencies() const;
void addAutoReleasedObject(QObject *obj); void addAutoReleasedObject(QObject *obj);