]> vaikene.ee Git - evaf/commitdiff
First implementation of the Plugin manager library.
authorEnar Väikene <enar.vaikene@mt.com>
Wed, 18 May 2011 10:38:53 +0000 (13:38 +0300)
committerEnar Väikene <enar.vaikene@mt.com>
Wed, 18 May 2011 10:38:53 +0000 (13:38 +0300)
etc/eVaf.xml [new file with mode: 0644]
src/libs/CMakeLists.txt
src/libs/Plugins/CMakeLists.txt
src/libs/Plugins/ipluginfactory.h [new file with mode: 0644]
src/libs/Plugins/pluginmanager.cpp [new file with mode: 0644]
src/libs/Plugins/pluginmanager.h
src/libs/Plugins/pluginmanager_p.h [new file with mode: 0644]
src/libs/Plugins/version.h [new file with mode: 0644]
src/libs/Plugins/version.rc [new file with mode: 0644]

diff --git a/etc/eVaf.xml b/etc/eVaf.xml
new file mode 100644 (file)
index 0000000..f10b14e
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE eVaf>
+<eVaf version="1.0">
+
+    <properties>
+
+    </properties>
+
+    <qtplugins>
+        <!--plugin filename="sqlite" /-->
+        <!--plugin filename="gif" /-->
+        <!--plugin filename="jpeg" /-->
+    </qtplugins>
+
+    <plugins>
+
+    </plugins>
+
+</octo>
index d20916f2a23302e966b555b358d8a14b111e1580..918e3ce9f4efad2fba72301144aeac3a56efcf98 100644 (file)
@@ -1,2 +1,2 @@
-#add_subdirectory(Plugins)
+add_subdirectory(Plugins)
 add_subdirectory(Common)
index f0b59ad7fc066483074e40645dafa1aaa258d1a6..0aadd65e8ecbbe13eb7cc8999582469732a0c187 100644 (file)
@@ -13,7 +13,7 @@ add_definitions(-DPLUGINS_LIBRARY)
 include_directories(${eVaf_INCLUDE})
 
 # Required eVaf libraries
-set(eVaf_LIBRARIES)
+set(eVaf_LIBRARIES CommonLib)
 
 # Source files
 set(SRCS
diff --git a/src/libs/Plugins/ipluginfactory.h b/src/libs/Plugins/ipluginfactory.h
new file mode 100644 (file)
index 0000000..637aa6b
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * @file Plugins/ipluginfactory.h
+ * @brief Common plugin factory interface for all the eVaf modules
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#ifndef __PLUGINS_IPLUGINFACTORY_H
+#define __PLUGINS_IPLUGINFACTORY_H
+
+#include "libplugins.h"
+
+#include <QObject>
+#include <QString>
+
+namespace eVaf {
+namespace Plugins {
+
+/**
+ * Common plugin factory interface for eVaf modules.
+ * @code#include <Plugins/iPluginFactory>
+ *
+ * The iPluginFactory interface is implemented by modules that export more than one
+ * iPlugin interface.
+ *
+ * Modules that implement only one iPlugin interface, use the iPlugin interface object
+ * directly.
+ */
+class PLUGINS_EXPORT iPluginFactory : public QObject
+{
+    Q_OBJECT
+
+public:
+
+    /// Empty constructor
+    iPluginFactory() : QObject() {}
+
+    /// Empty virtual destructor
+    virtual ~iPluginFactory() {}
+
+    /**
+     * Creates the requested iPlugin interface object
+     * @param name Name of the interface
+     * @return The requested iPlugin interface object or 0 if failed
+     *
+     * This function creates the requested iPlugin interface object. Modules can implement more than
+     * one iPlugin interface objects and use names to identify them.
+     *
+     * If the requested interface object cannot be created, this function returns 0.
+     *
+     * The module implementing the iPluginFactory interface is responsible for destroying all the
+     * created iPlugin interface objects.
+     */
+    virtual QObject * create(const QString & name) = 0;
+
+};
+
+} // namespace eVaf::Plugins
+} // namespace eVaf
+
+#endif // ipluginfactory.h
diff --git a/src/libs/Plugins/pluginmanager.cpp b/src/libs/Plugins/pluginmanager.cpp
new file mode 100644 (file)
index 0000000..c357d11
--- /dev/null
@@ -0,0 +1,543 @@
+/**
+ * @file plugins/pluginmanager.cpp
+ * @brief Implementation of the plugin manager
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#include "pluginmanager.h"
+#include "pluginmanager_p.h"
+#include "iplugin.h"
+#include "ipluginfactory.h"
+#include "version.h"
+
+#include <Common/Globals>
+#include <Common/Util>
+#include <Common/iLogger>
+#include <Common/iEnv>
+#include <Common/iApp>
+
+#include <QtCore>
+
+
+namespace eVaf {
+namespace Plugins {
+namespace Internal {
+
+    // Plugin manager interface implementation
+    static eVaf::Plugins::PluginManager * mPluginManager = 0;
+
+} // namespace eVaf::Plugins::Internal
+} // namespace eVaf::Plugins
+} // namespace eVaf
+
+
+//-------------------------------------------------------------------
+
+using namespace eVaf;
+using namespace eVaf::Plugins;
+
+PluginManager::PluginManager()
+    : QObject()
+{
+    setObjectName(QString("%1-PluginManager").arg(VER_MODULE_NAME_STR));
+
+    Internal::mPluginManager = this;
+
+    d = new Internal::PluginManagerPrivate;
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+PluginManager::~PluginManager()
+{
+    delete d;
+
+    Internal::mPluginManager = 0;
+
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+PluginManager * PluginManager::instance()
+{
+    return Internal::mPluginManager;
+}
+
+bool PluginManager::init()
+{
+    // Initialize the internal implementation
+    if (!d->init())
+        return false;
+
+    EVAF_INFO("Loading plugins");
+
+    // Load and initialize plugins
+    if (!d->loadPlugins())
+        return false;
+
+    EVAF_INFO("Plugins loaded");
+
+    emit pluginsLoaded();
+
+    EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+    return true;
+}
+
+void PluginManager::done()
+{
+    EVAF_INFO("Unloading plugins");
+
+    // Finalize and unload plugins
+    d->unloadPlugins();
+
+    emit pluginsUnloaded();
+
+    EVAF_INFO("Plugins unloaded");
+
+    // Finalize the internal implementation
+    d->done();
+
+    EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
+
+
+//-------------------------------------------------------------------
+
+using namespace eVaf::Plugins::Internal;
+
+PluginManagerPrivate::PluginManagerPrivate()
+    : QObject()
+{
+    setObjectName(QString("%1-PluginManagerPrivate").arg(VER_MODULE_NAME_STR));
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+PluginManagerPrivate::~PluginManagerPrivate()
+{
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+bool PluginManagerPrivate::init()
+{
+    EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+    return true;
+}
+
+void PluginManagerPrivate::done()
+{
+    EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
+
+bool PluginManagerPrivate::loadPlugins()
+{
+    // Get the name of the application's XML file
+    QString xmlFileName = Common::iEnv::instance()->etcDir() + Common::iApp::instance()->xmlFileName();
+
+    // Open the XML file
+    QFile xmlFile(xmlFileName);
+    if (!xmlFile.open(QFile::ReadOnly)) {
+        EVAF_FATAL_ERROR("Failed to open '%s' : %s", qPrintable(xmlFileName), qPrintable(xmlFile.errorString()));
+        return false;
+    }
+
+    // Process the XML file
+    QXmlStreamReader xml(&xmlFile);
+    bool isValid = false;
+    bool isPlugins = false;
+    bool isQtPlugins = false;
+    bool isPlugin = false;
+    QString moduleName;
+    QString pluginName;
+    QString args;
+    QStringList qtPlugins;
+
+    while (!xml.atEnd()) {
+        xml.readNext();
+
+        // Start element?
+        if (xml.isStartElement()) {
+
+            // Not a valid XML file yet?
+            if (!isValid) {
+                if (xml.name() == "eVaf") {
+                    isValid = true;
+                }
+                else {
+                    EVAF_FATAL_ERROR("'%s' is not a valid XML file for eVaf applications", qPrintable(xmlFileName));
+                    return false;
+                }
+            }
+
+            // This is a valid XML file
+            else {
+
+                // No plugins or qtplugins sections yet?
+                if (!isPlugins && !isQtPlugins) {
+                    if (xml.name() == "plugins") {
+                        // Check for windows and linux only sections
+#ifdef Q_OS_LINUX
+                        if (Common::isTrue(xml.attributes().value("windowsonly").toString()))
+                            continue;
+#endif
+#ifdef Q_OS_WIN32
+                        if (Common::isTrue(xml.attributes().value("linuxonly").toString()))
+                            continue;
+#endif
+                        isPlugins = true;
+                    }
+
+                    else if (xml.name() == "qtplugins") {
+                        // Check for windows and linux only sections
+#ifdef Q_OS_LINUX
+                        if (Common::isTrue(xml.attributes().value("windowsonly").toString()))
+                            continue;
+#endif
+#ifdef Q_OS_WIN32
+                        if (Common::isTrue(xml.attributes().value("linuxonly").toString()))
+                            continue;
+#endif
+                        isQtPlugins = true;
+                        qtPlugins.clear();
+                    }
+                }
+
+                // An individual plugin?
+                else if (isPlugins && xml.name() == "plugin") {
+                    // Check for windows and linux only plugins
+#ifdef Q_OS_LINUX
+                    if (Common::isTrue(xml.attributes().value("windowsonly").toString())) {
+                        EVAF_INFO("Plugin '%s' is for Windows only", qPrintable(xml.attributes().value("name").toString()));
+                        continue;
+                    }
+#endif
+#ifdef Q_OS_WIN32
+                    if (Common::isTrue(xml.attributes().value("linuxonly").toString())) {
+                        EVAF_INFO("Plugin '%s' is for Linux only", qPrintable(xml.attributes().value("name").toString()));
+                        continue;
+                    }
+#endif
+
+                    pluginName = xml.attributes().value("name").toString();
+                    moduleName = xml.attributes().value("filename").toString();
+
+                    /// @TODO: If the file name attribute is empty, loog for the config attribute
+                    if (moduleName.isEmpty())
+                        continue;
+
+                    isPlugin = true;
+                    args.clear();
+                }
+
+                // Plugin arguments?
+                else if (isPlugin) {
+                    args.append("<" + xml.name().toString());
+                    for (int i = 0; i < xml.attributes().size(); ++i)
+                        args.append(" " + xml.attributes().at(i).name().toString() + "=\"" + xml.attributes().at(i).value().toString() + "\"");
+                    args.append(">");
+                }
+
+                // An individual Qt plugin?
+                else if (isQtPlugins && xml.name() == "plugin") {
+                    // Check for windows and linux only plugins
+#ifdef Q_OS_LINUX
+                    if (Common::isTrue(xml.attributes().value("windowsonly").toString())) {
+                        EVAF_INFO("Qt plugin '%s' is for Windows only", qPrintable(xml.attributes().value("name").toString()));
+                        continue;
+                    }
+#endif
+#ifdef Q_OS_WIN32
+                    if (Common::isTrue(xml.attributes().value("linuxonly").toString())) {
+                        EVAF_INFO("Qt plugin '%s' is for Linux only", qPrintable(xml.attributes().value("name").toString()));
+                        continue;
+                    }
+#endif
+                    QString name = xml.attributes().value("filename").toString();
+                    if (!name.isEmpty() && !qtPlugins.contains(name))
+                        qtPlugins.append(name);
+                }
+            }
+        } // Start element?
+
+        // End element?
+        else if (xml.isEndElement()) {
+            if (isPlugin && xml.name() == "plugin") {
+                isPlugin = false;
+                Module * m = moduleByName(moduleName);
+                if (!m)
+                    mModules.append(QExplicitlySharedDataPointer<Module>(m = new Module(moduleName)));
+                mPlugins.append(QExplicitlySharedDataPointer<Plugin>(new Plugin(m, pluginName, args)));
+            }
+            else if (isPlugin)
+                args.append("</" + xml.name().toString() + ">");
+            else if (xml.name() == "plugins")
+                isPlugins = false;
+            else if (xml.name() == "qtplugins")
+                isQtPlugins = false;
+            else if (xml.name() == "eVaf")
+                isValid = false;
+        } // End element?
+    }
+
+    // Load Qt plugins
+    int i;
+    for (i = 0; i < qtPlugins.size(); ++i) {
+        loadQtPlugin(qtPlugins.at(i));
+    }
+
+    // Load eVaf plugins
+    i = 0;
+    while (i < mPlugins.size()) {
+        if (!mPlugins.at(i)->load()) {
+            EVAF_ERROR("Failed to load module '%s'", qPrintable(mPlugins.at(i)->name()));
+            mPlugins.removeAt(i);
+        }
+        else
+            ++i;
+    }
+
+    // Initialize eVaf plugins
+    i = 0;
+    while (i < mPlugins.size()) {
+        if (mPlugins.at(i)->init()) {
+            EVAF_ERROR("Failed to initialize module '%s'", qPrintable(mPlugins.at(i)->name()));
+            mPlugins.removeAt(i);
+        }
+        else
+            ++i;
+    }
+
+    return true;
+}
+
+void PluginManagerPrivate::unloadPlugins()
+{
+    // Finalize all the plugins
+    for (int i = 0; i < mPlugins.size(); ++i)
+        mPlugins.at(i)->done();
+    while (!mPlugins.isEmpty()) {
+        QExplicitlySharedDataPointer<Plugin> p = mPlugins.takeLast();
+        p->unload();
+    }
+
+    // Unload all the modules
+    while (!mModules.isEmpty()) {
+        QExplicitlySharedDataPointer<Module> m = mModules.takeLast();
+        m->unload();
+    }
+}
+
+Module * PluginManagerPrivate::moduleByName(QString const & name) const
+{
+    for (int i = 0; i < mModules.size(); ++i) {
+        if (mModules.at(i)->name() == name)
+            return mModules.at(i).data();
+    }
+    return 0;
+}
+
+bool PluginManagerPrivate::loadQtPlugin(QString const & name) const
+{
+    // Get the Qt plugin file name with the full path
+    QString fileName;
+
+#ifdef Q_OS_LINUX
+    fileName = QString("%1libq%2.so").arg(Common::iEnv::instance()->qtPluginsDir()).arg(name);
+#  ifndef QT_NO_DEBUG
+    QString t = QString("%1libq%2.so.debug").arg(Common::iEnv::instance()->qtPluginsDir()).arg(name);
+    if (QFile::exists(t))
+        fileName = t;
+#  endif
+#endif
+
+#ifdef Q_OS_WIN32
+    fileName = QString("%2q%2%3").arg(Common::iEnv::instance()->qtPluginsDir()).arg(name).arg("4.dll");
+#  ifndef QT_NO_DEBUG
+    QString t = QString(%1q%2%3).arg(Common::iEnv::instance()->qtPluginsDir()).arg(name).arg(d4.dll);
+    if (!QFile::exists(t))
+        fileName = t;
+#  endif
+#endif
+
+    if (fileName.isEmpty()) {
+        EVAF_ERROR("Don\'t know how to load Qt plugin '%s'", qPrintable(name));
+        return false;
+    }
+
+    EVAF_INFO("Loading Qt plugin '%s'", qPrintable(fileName));
+
+    QLibrary lib(fileName);
+    void * fn = lib.resolve("qt_plugin_instance");
+    if (fn) {
+        qRegisterStaticPluginInstanceFunction(QtPluginInstanceFunction(fn));
+        return true;
+    }
+    else {
+        EVAF_ERROR("Failed to load Qt plugin '%s' : %s", qPrintable(fileName), qPrintable(lib.errorString()));
+        return false;
+    }
+}
+
+
+//-------------------------------------------------------------------
+
+Module::Module(QString const & name)
+    : QSharedData()
+    , mName(name)
+    , mLoader(0)
+    , mRoot(0)
+    , mPlugin(0)
+    , mPluginFactory(0)
+{}
+
+Module::~Module()
+{
+    if (mPluginFactory)
+        delete mPluginFactory;
+    if (mLoader)
+        delete mLoader;
+}
+
+bool Module::load()
+{
+    // The real file name with path
+    QString fileName = Common::iEnv::instance()->binDir() + expandPluginName(mName);
+
+    // Try to load the module
+    QScopedPointer<QPluginLoader> p(new QPluginLoader(fileName));
+    if (!p->load()) {
+        EVAF_FATAL_ERROR("Failed to load '%s' : %s", qPrintable(mName), qPrintable(p->errorString()));
+        return false;
+    }
+
+    // Get the root component
+    QObject * root = p->instance();
+
+    // Does the module implement the iPluginFactory interface?
+    if ((mPluginFactory = qobject_cast<iPluginFactory *>(root)) == 0) {
+
+        // If not, then it has to implement the iPlugin interface
+        if ((mPlugin = qobject_cast<iPlugin *>(root)) == 0) {
+            EVAF_FATAL_ERROR("Module '%s' is not a valid eVaf module", qPrintable(mName));
+            return false;
+        }
+    }
+
+    mRoot = root;
+    mLoader = p.take();
+    return true;
+}
+
+void Module::unload()
+{
+    mRoot = 0;
+
+    if (mPluginFactory) {
+        delete mPluginFactory;
+        mPluginFactory = 0;
+    }
+    mPlugin = 0;
+    if (mLoader) {
+        delete mLoader;
+        mLoader = 0;
+    }
+}
+
+iPlugin * Module::create(QString const & name)
+{
+    // If the module is not loaded, load it now
+    if (!mLoader) {
+        if (!load())
+            return false;
+    }
+
+    iPlugin * i = 0;
+
+    // Does the module implement the iPluginFactory interface?
+    if (mPluginFactory) {
+        // Use the iPluginFactory interface to create the requested interface
+        i = qobject_cast<iPlugin *>(mPluginFactory->create(name));
+        if (i == 0) {
+            EVAF_FATAL_ERROR("Module '%s' failed to create the iPlugin interface with name '%s'", qPrintable(mName), qPrintable(name));
+            return 0;
+        }
+    }
+
+    // Otherwise use the root component, but only once
+    else {
+        if (mPlugin) {
+            EVAF_FATAL_ERROR("Module '%s' can implement only one iPlugin interface and one with the name '%s' is already created",
+                             qPrintable(mName), qPrintable(mPlugin->objectName()));
+            return 0;
+        }
+
+        i = qobject_cast<iPlugin *>(mRoot);
+        if (i == 0) {
+            EVAF_FATAL_ERROR("Module '%s' does not implement the iPlugin interface", qPrintable(mName));
+            return 0;
+        }
+
+        mPlugin = i;
+    }
+
+    return i;
+}
+
+
+//-------------------------------------------------------------------
+
+Plugin::Plugin(Module * module, QString const & name, QString const & args)
+    : QSharedData()
+    , mModule(module)
+    , mName(name)
+    , mArgs(args)
+    , mPlugin(0)
+{}
+
+Plugin::~Plugin()
+{
+    if (mPlugin)
+        delete mPlugin;
+}
+
+bool Plugin::load()
+{
+    mPlugin = mModule->create(mName);
+    if (mPlugin && !mPlugin->objectName().isEmpty())
+        mName = mPlugin->objectName();
+    return mPlugin != 0;
+}
+
+void Plugin::unload()
+{
+    if (mPlugin) {
+        delete mPlugin;
+        mPlugin = 0;
+    }
+}
+
+bool Plugin::init()
+{
+    if (!mPlugin)
+        return false;
+    return mPlugin->init(mArgs);
+}
+
+void Plugin::done()
+{
+    if (mPlugin)
+        mPlugin->done();
+}
index 2f320f97b54d0eab2ce57ccae5256976686e8846..f79193c1ab89034575fea35550a4d63456be0884 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * @file plugins/pluginmanager.h
+ * @file Plugins/pluginmanager.h
  * @brief Manager for loadable modules (plugins)
  *
  * Copyright (c) 2011 Enar Vaikene
@@ -24,6 +24,9 @@
 #include <version_rc.h>
 
 #include <QObject>
+#include <QString>
+
+namespace eVaf {
 
 /**
  * Library for managing loadable modules (plugins).
@@ -44,6 +47,25 @@ namespace Internal {
     class PluginManagerPrivate;
 }
 
+/**
+ * Expands plugin names for the selected platform.
+ * @param name Name of the plugin
+ * @return Expanded plugin name
+ *
+ * This function expands the plugin name so that it becomes valid for the selected platform.
+ * For example, on Linux it adds the prefix "lib" to the beginning and extension ".so" to the end.
+ */
+inline QString expandPluginName(QString const & name)
+{
+#ifdef Q_OS_WIN32
+    return name + ".dll";
+#elif defined Q_OS_LINUX
+    return "lib" + name + ".so";
+#else
+    return name;
+#endif
+}
+
 /**
  * Plugin manager for eVaf applications.
  */
@@ -101,11 +123,11 @@ signals:
 
 private:
 
-    Internal::PluginManagerPrivate * dl;
+    Internal::PluginManagerPrivate * d;
 
 };
 
-} // namespace Plugins
-
+} // namespace eVaf::Plugins
+} // namespace eVaf
 
 #endif // pluginmanager.h
diff --git a/src/libs/Plugins/pluginmanager_p.h b/src/libs/Plugins/pluginmanager_p.h
new file mode 100644 (file)
index 0000000..1fbdad0
--- /dev/null
@@ -0,0 +1,228 @@
+/**
+ * @file plugins/pluginmanager_p.h
+ * @brief Private implementation of the plugin manager
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#ifndef __PLUGINS_PLUGINMANAGER_P_H
+#define __PLUGINS_PLUGINMANAGER_P_H
+
+#include <QObject>
+#include <QSharedData>
+#include <QExplicitlySharedDataPointer>
+#include <QPluginLoader>
+
+namespace eVaf {
+namespace Plugins {
+
+class iPlugin;
+class iPluginFactory;
+
+namespace Internal {
+
+class Plugin;
+class Module;
+
+/**
+ * Internal implementation of the plugin manager
+ */
+class PluginManagerPrivate : public QObject
+{
+    Q_OBJECT
+
+public:
+
+    /// Ctr.
+    PluginManagerPrivate();
+
+    /// Dtr.
+    virtual ~PluginManagerPrivate();
+
+    /**
+     * Initializes the private plugin manager object
+     * @return True; false if failed
+     */
+    bool init();
+
+    /**
+     * Finalizes the private plugin manager object
+     */
+    void done();
+
+    /**
+     * Loads and initializes plugins
+     * @return True; false if failed
+     */
+    bool loadPlugins();
+
+    /**
+     * Finalizes and unloads plugins
+     */
+    void unloadPlugins();
+
+
+private: // Members
+
+    /// List of all the modules
+    QList<QExplicitlySharedDataPointer<Module> > mModules;
+
+    /// List of all the plugins
+    QList<QExplicitlySharedDataPointer<Plugin> > mPlugins;
+
+
+private: // Methods
+
+    /**
+     * Returns the module object by its name
+     * @param name Name of the module
+     * @return Module object or 0 if not found
+     */
+    Module * moduleByName(QString const & name) const;
+
+    /**
+     * Loads the Qt plugin
+     * @param Name of the Qt plugin
+     * @return True; false if failed
+     */
+    bool loadQtPlugin(QString const & name) const;
+
+};
+
+/**
+ * One external module implementing the iPluginFactory or the iPlugin interfaces.
+ *
+ * This class is a wrapper around the external module.
+ */
+class Module : public QSharedData
+{
+public:
+
+    /**
+     * Ctr.
+     * @param name Name of the module
+     */
+    Module(QString const & name);
+
+    /// Dtr.
+    ~Module();
+
+    /// Returns true if the module is loaded
+    bool isLoaded() const { return mLoader != 0; }
+
+    /// The name of the module
+    QString const & name() const { return mName; }
+
+    /**
+     * Loads the module
+     * @return True; false if failed
+     */
+    bool load();
+
+    /// Unloads the module
+    void unload();
+
+    /**
+     * Creates the requested iPlugin interface object
+     * @param name Name of the interface
+     * @return The iPlugin interface object or 0 if failed
+     */
+    iPlugin * create(QString const & name);
+
+
+private: // Members
+
+    /// Name of the module
+    QString mName;
+
+    /// Plugin loader
+    QPluginLoader * mLoader;
+
+    /// Plugin's root component
+    QObject * mRoot;
+
+    /// The iPlugin interface object if the module implements only one iPlugin interface
+    iPlugin * mPlugin;
+
+    /// The iPluginFactory interface object if the module implements more than one iPluginFactory interface
+    iPluginFactory * mPluginFactory;
+
+};
+
+/**
+ * One iPlugin interface object.
+ *
+ * This class is a wrapper around the plugin.
+ */
+class Plugin : public QSharedData
+{
+public:
+
+    /**
+     * Ctr.
+     * @param module The Module implementing this iPlugin interface
+     * @param name Name of the plugin
+     * @param args Arguments for the plugin initialization
+     */
+    Plugin(Module * module, QString const & name, QString const & args);
+
+    /// Dtr.
+    ~Plugin();
+
+    /// The iPlugin interface
+    iPlugin * plugin() const { return mPlugin; }
+
+    /// The name of the plugin
+    QString const & name() const { return mName; }
+
+    /**
+     * Loads the plugin
+     * @return True; false if failed
+     */
+    bool load();
+
+    /// Unloads the plugin
+    void unload();
+
+    /**
+     * Initializes the plugin
+     * @return True; false if failed
+     */
+    bool init();
+
+    /// Uninitializes the plugin
+    void done();
+
+
+private: // Members
+
+    /// Module implementing this iPlugin interface
+    Module * mModule;
+
+    /// Name of the plugin
+    QString mName;
+
+    /// Arguments for the initialization
+    QString mArgs;
+
+    /// The iPlugin interface object
+    iPlugin * mPlugin;
+
+};
+
+} // namespace eVaf::Plugins::Internal
+} // namespace eVaf::Plugins
+} // namespace eVaf
+
+#endif // pluginmanager_p.h
diff --git a/src/libs/Plugins/version.h b/src/libs/Plugins/version.h
new file mode 100644 (file)
index 0000000..f114e5a
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * @file Plugins/version.h
+ * @brief Version information for eVaf modules
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#ifndef __PLUGINS_VERSION_H
+#define __PLUGINS_VERSION_H
+
+#include <version_rc.h>
+
+/**
+ * Module/library version number in the form major,minor,release,build
+ */
+#define VER_FILE_VERSION                0,1,1,1
+
+/**
+ * Module/library version number in the string format (shall end with \0)
+ */
+#define VER_FILE_VERSION_STR            "0.1.1.1\0"
+
+/**
+ * Module/library name (shall end with \0)
+ */
+#define VER_MODULE_NAME_STR             "PluginsLib\0"
+
+/**
+ * Module type (see version_rc.h for all the types)
+ */
+#define VER_MODULE_TYPE                 MT_GENERIC
+
+/**
+ * Module type in the string format (see version_rc for all the types)
+ */
+#define VER_MODULE_TYPE_STR             MT_GENERIC
+
+/**
+ * Original file name for windows (shall end with \0)
+ */
+#define VER_ORIGINAL_FILE_NAME_STR      "PluginsLib.dll\0"
+
+/**
+ * Description of the module/library (shall end with \0)
+ */
+#define VER_FILE_DESCRIPTION_STR         "Library for eVaf applications that loads external modules into the application.\0"
+
+#endif // version.h
diff --git a/src/libs/Plugins/version.rc b/src/libs/Plugins/version.rc
new file mode 100644 (file)
index 0000000..04ed2f8
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * @file Common/version.rc
+ * @brief Windows resource file with module/library version information.
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#include "version.h"
+#include <version_rc.h>
+#include <winver.h>
+
+
+VS_VERSION_INFO VERSIONINFO
+        FILEVERSION VER_FILE_VERSION
+        PRODUCTVERSION VER_PRODUCT_VERSION
+        FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+        FILEFLAGS VS_FF_DEBUG
+#else
+        FILEFLAGS 0x0L
+#endif
+        FILEOS VOS__WINDOWS32
+        FILETYPE VFT_DLL
+        FILESUBTYPE 0x0L
+        BEGIN
+                BLOCK "StringFileInfo"
+                BEGIN
+                        BLOCK "040904B0"
+                        BEGIN
+                                VALUE "CompanyName", VER_COMPANY_NAME_STR
+                                VALUE "FileDescription", VER_FILE_DESCRIPTION_STR
+                                VALUE "FileVersion", VER_FILE_VERSION_STR
+                                VALUE "LegalCopyright", VER_LEGAL_COPYRIGHT_STR
+                                VALUE "OriginalFilename", VER_ORIGINAL_FILE_NAME_STR
+                                VALUE "ProductName", VER_PRODUCT_NAME_STR
+                                VALUE "ProductVersion", VER_PRODUCT_VERSION_STR
+                                VALUE "Build Date", VER_PRODUCT_DATE_STR
+                                VALUE "Module Name", VER_MODULE_NAME_STR
+                                VALUE "Module Type", VER_MODULE_TYPE_STR
+                        END
+                END
+        END