/* * Stellarium * Copyright (C) 2006 Fabien Chereau * * 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 2 * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "StelModuleMgr.hpp" #include "StelApp.hpp" #include "StelModule.hpp" #include "StelFileMgr.hpp" #include "StelPluginInterface.hpp" #include "StelIniParser.hpp" StelModuleMgr::StelModuleMgr() : callingListsToRegenerate(true), pluginDescriptorListLoaded(false) { // Initialize empty call lists for each possible actions callOrders[StelModule::ActionDraw]=QList(); callOrders[StelModule::ActionUpdate]=QList(); callOrders[StelModule::ActionHandleMouseClicks]=QList(); callOrders[StelModule::ActionHandleMouseMoves]=QList(); callOrders[StelModule::ActionHandleKeys]=QList(); } StelModuleMgr::~StelModuleMgr() { } // Regenerate calling lists if necessary void StelModuleMgr::update() { if (callingListsToRegenerate) generateCallingLists(); callingListsToRegenerate = false; } /************************************************************************* Register a new StelModule to the list *************************************************************************/ void StelModuleMgr::registerModule(StelModule* m, bool fgenerateCallingLists) { QString name = m->objectName(); if (modules.find(name) != modules.end()) { qWarning() << "Module \"" << name << "\" is already loaded."; return; } modules.insert(name, m); m->setParent(this); if (fgenerateCallingLists) generateCallingLists(); } /************************************************************************* Unregister and delete a StelModule. *************************************************************************/ void StelModuleMgr::unloadModule(const QString& moduleID, bool alsoDelete) { StelModule* m = getModule(moduleID); if (!m) { qWarning() << "Module \"" << moduleID << "\" is not loaded."; return; } modules.remove(moduleID); m->setParent(NULL); callingListsToRegenerate = true; if (alsoDelete) { m->deinit(); delete m; } } /************************************************************************* Get the corresponding module or NULL if can't find it. *************************************************************************/ StelModule* StelModuleMgr::getModule(const QString& moduleID, bool noWarning) { QMap::ConstIterator iter = modules.find(moduleID); if (iter==modules.constEnd()) { if (noWarning==false) qWarning() << "Warning can't find module called " << moduleID << "."; return NULL; } return iter.value(); } /************************************************************************* Load an external plugin *************************************************************************/ StelModule* StelModuleMgr::loadPlugin(const QString& moduleID) { foreach (const PluginDescriptor& desc, getPluginsList()) { if (desc.info.id==moduleID) { Q_ASSERT(desc.pluginInterface); StelModule* sMod = desc.pluginInterface->getStelModule(); qDebug() << "Loaded plugin " << moduleID << "."; pluginDescriptorList[moduleID].loaded=true; return sMod; } } qWarning() << "Can't find plugin called " << moduleID; return NULL; } struct StelModuleOrderComparator { StelModuleOrderComparator(StelModule::StelModuleActionName aaction) : action(aaction) {;} bool operator()(StelModule* x, StelModule* y) {return x->getCallOrder(action)getCallOrder(action);} private: StelModule::StelModuleActionName action; }; // Unload all plugins void StelModuleMgr::unloadAllPlugins() { QListIterator i(getPluginsList()); i.toBack(); while (i.hasPrevious()) { const PluginDescriptor& d = i.previous(); if (d.loaded==false) continue; unloadModule(d.info.id, true); qDebug() << "Unloaded plugin " << d.info.id << "."; } // Call update now to make sure that all references to the now deleted plugins modules // are removed (fix crashes at application shutdown). update(); } void StelModuleMgr::setPluginLoadAtStartup(const QString& key, bool b) { QSettings* conf = StelApp::getInstance().getSettings(); conf->setValue("plugins_load_at_startup/"+key, b); if (pluginDescriptorList.contains(key)) { pluginDescriptorList[key].loadAtStartup=b; } } /************************************************************************* Generate properly sorted calling lists for each action (e,g, draw, update) according to modules orders dependencies *************************************************************************/ void StelModuleMgr::generateCallingLists() { QMap >::iterator mc; // For each actions (e.g. "draw", "update", etc..) for(mc=callOrders.begin();mc!=callOrders.end();++mc) { // Flush previous call orders mc.value().clear(); // and init them with modules in creation order foreach (StelModule* m, getAllModules()) { mc.value().push_back(m); } qSort(mc.value().begin(), mc.value().end(), StelModuleOrderComparator(mc.key())); } } /************************************************************************* Return the list of all the external module found in the modules/ directories *************************************************************************/ QList StelModuleMgr::getPluginsList() { if (pluginDescriptorListLoaded) { return pluginDescriptorList.values(); } // First list all static plugins. // If a dynamic plugin with the same ID exists, it will take precedence on the static one. foreach (QObject *plugin, QPluginLoader::staticInstances()) { StelPluginInterface* pluginInterface = qobject_cast(plugin); if (pluginInterface) { StelModuleMgr::PluginDescriptor mDesc; mDesc.info = pluginInterface->getPluginInfo(); mDesc.pluginInterface = pluginInterface; pluginDescriptorList.insert(mDesc.info.id, mDesc); } } // Then list dynamic libraries from the modules/ directory QSet moduleDirs; try { moduleDirs = StelFileMgr::listContents("modules",StelFileMgr::Directory); } catch(std::runtime_error& e) { qWarning() << "ERROR while trying list list modules:" << e.what(); } foreach (QString dir, moduleDirs) { QString moduleFullPath = QString("modules/") + dir + "/lib" + dir; #ifdef Q_OS_WIN moduleFullPath += ".dll"; #else #ifdef Q_OS_MAC moduleFullPath += ".dylib"; #else moduleFullPath += ".so"; #endif #endif try { moduleFullPath = StelFileMgr::findFile(moduleFullPath, StelFileMgr::File); } catch (std::runtime_error& e) { continue; } QPluginLoader loader(moduleFullPath); if (!loader.load()) { qWarning() << "Couldn't load the dynamic library: " << moduleFullPath << ": " << loader.errorString(); qWarning() << "Plugin " << dir << " will not be loaded."; continue; } QObject* obj = loader.instance(); if (!obj) { qWarning() << "Couldn't open the dynamic library: " << moduleFullPath << ": " << loader.errorString(); qWarning() << "Plugin " << dir << " will not be open."; continue; } StelPluginInterface* pluginInterface = qobject_cast(obj); if (pluginInterface) { StelModuleMgr::PluginDescriptor mDesc; mDesc.info = pluginInterface->getPluginInfo(); mDesc.pluginInterface = pluginInterface; pluginDescriptorList.insert(mDesc.info.id, mDesc); } } // Load for each plugin if it should be loaded at startup QSettings* conf = StelApp::getInstance().getSettings(); for (QMap::Iterator iter=pluginDescriptorList.begin();iter!=pluginDescriptorList.end();++iter) { if (!conf->contains("plugins_load_at_startup/"+iter.key())) conf->setValue("plugins_load_at_startup/"+iter.key(), false); iter->loadAtStartup = conf->value("plugins_load_at_startup/"+iter.key()).toBool(); } pluginDescriptorListLoaded = true; return pluginDescriptorList.values(); }