/* * Copyright 2009 Ben Boeckel * * 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 * 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 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU 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 . */ // Header include #include "PluginLoader.h" #include "PluginLoader_p.h" // Sigencore plugin includes #include #include #include // Sigmod includes #include // KDE includes #include #include #include // Qt includes #include using namespace Sigmod; using namespace Sigscript; using namespace Sigencore; using namespace Sigencore::Plugins; using namespace Sigtools; K_GLOBAL_STATIC(PluginLoader::Private, loader) QStringList PluginLoader::availablePlugins(const QString& type, const bool forceLookup) { if (forceLookup) loader->refresh(type); return loader->services(type); } KService::Ptr PluginLoader::service(const QString& type, const QString& name) { return loader->service(type, name); } Game* PluginLoader::game(const QString& name) { return loader->game(name); } PluginBase* PluginLoader::plugin(const QString& type, const QString& name) { return loader->factory(type, name); } ArenaPlugin* PluginLoader::pluginForArena(const QString& arena) { return qobject_cast(loader->factory("Arena", arena)); } CanvasPlugin* PluginLoader::pluginForCanvas(const QString& canvas) { return qobject_cast(loader->factory("Canvas", canvas)); } Arena* PluginLoader::loadArena(const QString& name, GameWrapper* game, Config* parent) { ArenaPlugin* plugin = pluginForArena(name); if (plugin) return plugin->getArena(name, game, parent); return NULL; } Canvas* PluginLoader::loadCanvas(const QString& name, GameWrapper* game, Config* parent) { CanvasPlugin* plugin = pluginForCanvas(name); if (plugin) return plugin->getCanvas(name, game, parent); return NULL; } PluginLoader::Private::Private() { if (!KGlobal::dirs()->resourceDirs("sigmod").size()) KGlobal::dirs()->addResourceType("sigmod", "data", "sigmod/"); } PluginLoader::Private::~Private() { QStringList types = m_available.keys(); foreach (const QString& type, types) clean(type); } void PluginLoader::Private::refresh(const QString& type) { QList curServices = m_available[type].values(); foreach (const Service& service, curServices) delete service.second; m_available[type].clear(); if (type == "Sigmod") { QList games = m_games.values(); foreach (Game* game, games) delete game; m_games.clear(); } // TODO: Progress dialog? KService::List services = KServiceTypeTrader::self()->query(QString("Sigen/%1").arg(type), "[X-Sigen-MinVersion] <= 000101"); foreach (KService::Ptr service, services) { if (type == "Sigmod") { const QString name = service->property("X-Sigen-Sigmod-Name", QVariant::String).toString(); const QStringList version = service->property("X-Sigen-Sigmod-Version", QVariant::StringList).toStringList(); const QString variant = service->property("X-Sigen-Sigmod-Variant", QVariant::String).toString(); const QStringList variantVersion = service->property("X-Sigen-Sigmod-VariantVersion", QVariant::StringList).toStringList(); QString fullName; QString varPath; if (!variant.isEmpty()) varPath = QString("/%1/%2").arg(variant).arg(variantVersion.join("-")); fullName = QString("%1/%2%3").arg(name).arg(version.join("-")).arg(varPath); QString fileName = KStandardDirs::locate("sigmod", QString("%1.smod").arg(fullName)); if (!fileName.isEmpty()) { QFile file(fileName); Game* game = NULL; if (file.open(QIODevice::ReadOnly)) { QDomDocument xml; QString error; int line; int column; if (xml.setContent(&file, &error, &line, &column)) { if (xml.doctype().name() == "Sigmod") game = new Game(xml.documentElement()); else KMessageBox::error(NULL, "The file is not a Sigmod.", "Invalid Sigmod"); } else KMessageBox::error(NULL, QString("%1 at line %2, column %3").arg(error).arg(line).arg(column), "XML Error"); } file.close(); // TODO: validate if (game) { m_available[type][fullName] = Service(service, NULL); m_games[fullName] = game; } } } else { KPluginLoader loader(service->library()); KPluginFactory *factory = loader.factory(); if (factory) { PluginBase* plugin = NULL; if (type == "Arena") plugin = factory->create(this); else if (type == "Canvas") plugin = factory->create(this); else KMessageBox::information(NULL, QString("The plugin type \"Sigen/%1\" is not supported.").arg(type), "Unsupported plugin type"); if (plugin) { QStringList classes = plugin->classList(); foreach (const QString& className, classes) m_available[type][className] = Service(service, plugin); } } else KMessageBox::error(NULL, QString("The plugin of type \"Sigen/%1\" with name \"%2\" is not a valid Sigen plugin. The error was:\n%3").arg(type).arg(service->name()).arg(loader.errorString()), "Plugin loading error"); } } } QStringList PluginLoader::Private::services(const QString& type) { if (!m_available.contains(type)) refresh(type); if (m_available.contains(type)) return m_available[type].keys(); return QStringList(); } KService::Ptr PluginLoader::Private::service(const QString& type, const QString& name) { if (!m_available.contains(type)) refresh(type); if (m_available.contains(type) && m_available[type].contains(name)) return m_available[type][name].first; return KService::Ptr(); } PluginBase* PluginLoader::Private::factory(const QString& type, const QString& name) { if (!m_available.contains(type)) refresh(type); if (m_available.contains(type) && m_available[type].contains(name)) return m_available[type][name].second; return NULL; } Game* PluginLoader::Private::game(const QString& name) { if (!m_games.contains(name)) refresh("Sigmod"); if (m_games.contains(name)) return m_games[name]; return NULL; } void PluginLoader::Private::clean(const QString& type) { // TODO fix this QStringList curServices = m_available[type].keys(); foreach (const QString& service, curServices) { if (m_available[type][service].second && !m_available[type][service].second->classesUsedCount()) { delete m_available[type][service].second; m_available[type].remove(service); } } if (type == "Sigmod") { qDeleteAll(m_games.values()); m_games.clear(); } }