35 #include <QApplication> 36 #include <QStringList> 37 #include <QDirIterator> 41 #include "ctkPluginFrameworkFactory.h" 42 #include "ctkPluginFramework.h" 43 #include "ctkPluginContext.h" 44 #include "ctkPluginException.h" 46 #include <ctkConfig.h> 63 mSettingsBase =
"pluginFramework";
64 mSettingsSearchPaths = mSettingsBase +
"/searchPaths";
66 ctkProperties fwProps;
69 fwProps[ctkPluginConstants::FRAMEWORK_STORAGE] = storagePath;
73 fwProps[ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN] = ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT;
75 mFrameworkFactory.reset(
new ctkPluginFrameworkFactory(fwProps));
76 mPluginLibFilter <<
"*.dll" <<
"*.so" <<
"*.dylib";
81 if(mFramework->getState() == ctkPlugin::ACTIVE)
83 CX_LOG_CHANNEL_WARNING(
"plugin") <<
"This should not happen: PluginFrameworkManager destructor stopping plugin framework";
88 QString PluginFrameworkManager::convertToRelativePath(QString path)
const 90 QDir base = qApp->applicationDirPath();
91 return base.relativeFilePath(path);
94 QString PluginFrameworkManager::convertToAbsolutePath(QString path)
const 96 if (QDir(path).isAbsolute())
97 return QDir(path).absolutePath();
99 QDir base = qApp->applicationDirPath();
100 return QDir(base.path() +
"/" + path).absolutePath();
105 std::vector<PluginFrameworkManager::PluginLoadInfo> PluginFrameworkManager::getPluginLoadInfo(QStringList symbolicNames)
107 std::vector<PluginLoadInfo> retval;
109 for (
unsigned i=0; i<symbolicNames.size(); ++i)
112 info.symbolicName = symbolicNames[i];
113 info.storedState =
settings()->
value(mSettingsBase+
"/"+info.symbolicName).toString();
115 if (info.storedState.isEmpty())
127 retval.push_back(info);
135 QStringList paths =
settings()->
value(mSettingsSearchPaths, QStringList()).toStringList();
139 std::vector<PluginLoadInfo> info = this->getPluginLoadInfo(names);
143 for (
unsigned i=0; i< info.size(); ++i)
145 if (info[i].targetState != ctkPlugin::UNINSTALLED)
147 this->
install(info[i].symbolicName);
152 for (
unsigned i=0; i< info.size(); ++i)
154 if (info[i].targetState == ctkPlugin::ACTIVE)
157 CX_LOG_CHANNEL_INFO(
"plugin") << QString(
"Autostarting plugin %1").arg(info[i].symbolicName);
161 this->
start(info[i].symbolicName, ctkPlugin::START_TRANSIENT);
166 .arg(info[i].symbolicName)
167 .arg(info[i].storedState);
173 void PluginFrameworkManager::saveState()
175 QStringList relativePaths;
176 for (
int i=0; i<mPluginSearchPaths.size(); ++i)
177 relativePaths << this->convertToRelativePath(mPluginSearchPaths[i]);
181 for (
unsigned i=0; i<names.size(); ++i)
183 QString name = names[i];
191 ctkPlugin::State state = ctkPlugin::UNINSTALLED;
194 state = plugin->getState();
200 mPluginSearchPaths.clear();
202 for (
int i=0; i<searchPath.size(); ++i)
203 mPluginSearchPaths << this->convertToAbsolutePath(searchPath[i]);
206 for (
unsigned i=0; i<defPaths.size(); ++i)
208 QString defPath = this->convertToAbsolutePath(defPaths[i]);
209 if (!mPluginSearchPaths.count(defPath))
210 mPluginSearchPaths << defPath;
213 mPluginSearchPaths.removeDuplicates();
215 for (
int i=0; i<searchPath.size(); ++i)
217 QApplication::addLibraryPath(searchPath[i]);
225 return mPluginSearchPaths;
230 return mFramework->getPluginContext();
238 void PluginFrameworkManager::initializeFramework()
240 if (this->frameworkInitialized())
245 QSharedPointer<ctkPluginFramework> framework = mFrameworkFactory->getFramework();
250 }
catch (
const ctkException& exc)
252 this->handlePluginException(
"Failed to initialize the plug-in framework", exc);
254 mFramework = framework;
257 bool PluginFrameworkManager::frameworkInitialized()
const 259 return mFramework != 0;
262 bool PluginFrameworkManager::frameworkStarted()
const 264 return mFramework && (mFramework->getState() == ctkPlugin::ACTIVE);
267 void PluginFrameworkManager::startFramework()
269 if (!this->frameworkInitialized())
270 this->initializeFramework();
272 if (this->frameworkStarted())
279 catch (
const ctkException& exc)
281 this->handlePluginException(
"Failed to start the plug-in framework", exc);
287 this->initializeFramework();
288 if (!this->frameworkInitialized())
291 QString pluginPath = this->getPluginPath(symbolicName);
292 if (pluginPath.isEmpty())
298 pc->installPlugin(QUrl::fromLocalFile(pluginPath))->getPluginId();
300 catch (
const ctkException& exc)
302 this->handlePluginException(QString(
"Failed to install plugin %1").arg(symbolicName), exc);
308 this->startFramework();
309 return this->frameworkStarted();
324 for (
int i=0; i<plugins.size(); ++i)
326 this->
stop(plugins[i]);
333 ctkPluginFrameworkEvent fe = mFramework->waitForStop(5000);
342 if (fe.getType() == ctkPluginFrameworkEvent::FRAMEWORK_WAIT_TIMEDOUT)
348 catch (
const ctkException& exc)
350 this->handlePluginException(
"Failed to stop the plug-in framework", exc);
353 return !this->frameworkStarted();
358 QString pluginPath = getPluginPath(symbolicName);
359 if (pluginPath.isEmpty())
365 pc->installPlugin(QUrl::fromLocalFile(pluginPath))->uninstall();
367 catch (
const ctkException& exc)
369 this->handlePluginException(QString(
"Failed to uninstall plugin %1.").arg(symbolicName), exc);
378 this->startFramework();
380 QString pluginPath = getPluginPath(symbolicName);
381 if (pluginPath.isEmpty())
383 CX_LOG_CHANNEL_ERROR(
"plugin") << QString(
"Failed to find plugin %1 in search path.").arg(symbolicName);
390 QSharedPointer<ctkPlugin> plugin = pc->installPlugin(QUrl::fromLocalFile(pluginPath));
391 plugin->start(options);
393 catch (ctkException& exc)
395 this->handlePluginException(QString(
"Failed to stop plugin %1.").arg(symbolicName), exc);
402 void PluginFrameworkManager::handlePluginException(
const QString& message,
const ctkException& exc)
405 const ctkException* nest = &exc;
409 nest = nest->cause();
415 if (!this->frameworkStarted())
417 QString pluginPath = this->getPluginPath(symbolicName);
418 if (pluginPath.isEmpty())
431 plugin->stop(options);
433 catch (
const ctkException& exc)
435 this->handlePluginException(QString(
"Failed to stop plugin %1").arg(symbolicName), exc);
444 QSharedPointer<ctkPlugin> empty;
446 if (!this->frameworkInitialized())
449 QString pluginPath = this->getPluginPath(symbolicName);
450 if (pluginPath.isEmpty())
454 QList < QSharedPointer<ctkPlugin> > plugins = pc->getPlugins();
455 foreach(QSharedPointer<ctkPlugin> plugin, plugins)
457 if (plugin->getSymbolicName() == symbolicName)
467 QString PluginFrameworkManager::getPluginPath(
const QString& symbolicName)
469 QString pluginFileName(symbolicName);
470 pluginFileName.replace(
".",
"_");
471 foreach(QString searchPath, mPluginSearchPaths)
473 QDirIterator dirIter(searchPath, mPluginLibFilter, QDir::Files, QDirIterator::Subdirectories);
474 while(dirIter.hasNext())
477 QFileInfo fileInfo = dirIter.fileInfo();
478 QString fileBaseName = fileInfo.baseName();
479 if (fileBaseName.startsWith(
"lib")) fileBaseName = fileBaseName.mid(3);
481 if (fileBaseName == pluginFileName)
483 return fileInfo.canonicalFilePath();
494 foreach(QString searchPath, mPluginSearchPaths)
498 result.removeDuplicates();
505 QDirIterator dirIter(searchPath, mPluginLibFilter, QDir::Files, QDirIterator::Subdirectories);
506 while (dirIter.hasNext())
509 QFileInfo fileInfo = dirIter.fileInfo();
510 QString fileBaseName = fileInfo.baseName();
511 if (fileBaseName.startsWith(
"lib"))
512 fileBaseName = fileBaseName.mid(3);
513 QString name = fileBaseName.replace(
"_",
".");
514 if (this->nameIsProbablyPlugin(name))
521 bool PluginFrameworkManager::nameIsProbablyPlugin(QString name)
const 524 return name.startsWith(
"org.custusx");
#define CX_LOG_CHANNEL_INFO(channel)
~PluginFrameworkManager()
QStringList getPluginSymbolicNames()
ctkPlugin::State getStateFromSymbolicName(QString name)
#define CX_LOG_CHANNEL_WARNING(channel)
QStringList getSearchPaths() const
static ProfileManager * getInstance(QString defaultProfile=QString("Laboratory"))
returns the only instance of this class
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
QSharedPointer< ctkPluginFramework > getPluginFramework()
void uninstall(const QString &symbolicName)
void install(const QString &symbolicName)
QSharedPointer< ctkPlugin > getInstalledPluginFromSymbolicName(QString symbolicName)
void setValue(const QString &key, const QVariant &value)
ctkPluginContext * getPluginContext()
Settings * settings()
Shortcut for accessing the settings instance.
static QStringList getDefaultPluginsPath()
return the folder where plugins should be located, by default.
QString getStringForctkPluginState(const ctkPlugin::State state)
QString getSettingsPath()
ctkPlugin::State getctkPluginStateForString(QString text)
#define CX_LOG_CHANNEL_ERROR(channel)
void setSearchPaths(const QStringList &searchPath)
Namespace for all CustusX production code.