Difference between revisions of "Events:CTK-Hackfest-2010/SlicerQtPluginArchitecture"
From NAMIC Wiki
(Created page with '= Goal = * Provide a cross-platform plugin architecture * Modular and extensible = Big picture = * a Factory manages a collection of Factory items * Factory Item provides load()…') |
m (→Big picture) |
||
| (4 intermediate revisions by the same user not shown) | |||
| Line 6: | Line 6: | ||
* a Factory manages a collection of Factory items | * a Factory manages a collection of Factory items | ||
* Factory Item provides load() and instanciate() methods | * Factory Item provides load() and instanciate() methods | ||
| − | * Factory | + | * Factory provides registerItems() and load(key) methods |
| + | * Factory are templated | ||
= Under the hood = | = Under the hood = | ||
| − | + | == The Qt layer == | |
| − | + | * QPlugin [http://doc.trolltech.com/4.6-snapshot/qpluginloader.html] [http://doc.trolltech.com/4.6-snapshot/qtplugin.html] (from Qt docmentation ... ) | |
| − | + | ** QPluginLoader checks that a plugin is linked against the same version of Qt as the application. | |
| − | + | ** QPluginLoader provides direct access to a root component object (instance()), instead of forcing you to resolve a C function manually. | |
| − | + | ** In order to speed up loading and validation of plugins, some of the information that is collected during loading is cached in persistent memory (through QSettings). | |
| − | + | * QLibrary [http://doc.trolltech.com/4.6-snapshot/qlibrary.html] | |
| − | + | * QObject / Object | |
| − | + | == The CTK layer == | |
| − | + | * Base class: qCTKAbstractFactory | |
<pre> | <pre> | ||
template<typename BaseClassType> | template<typename BaseClassType> | ||
| Line 60: | Line 61: | ||
</pre> | </pre> | ||
| − | + | * 3 kind of factory: | |
| − | + | ** qCTKAbstractLibraryFactory | |
| − | + | ** qCTKAbstractObjectFactory | |
| − | + | ** qCTKAbstractPluginFactory | |
| − | + | * A factory manage a collection of qCTKAbstractFactoryItem. | |
<pre> | <pre> | ||
template<typename BaseClassType> | template<typename BaseClassType> | ||
| Line 87: | Line 88: | ||
</pre> | </pre> | ||
| − | + | == Concrete example(s) == | |
| − | All modules are based on qSlicerAbstractModule | + | * All modules are based on qSlicerAbstractModule which provides: |
| − | |||
** logic(): This method allows to get a pointer to the ModuleLogic. If no moduleLogic already exists, one will be created calling 'createLogic' method | ** logic(): This method allows to get a pointer to the ModuleLogic. If no moduleLogic already exists, one will be created calling 'createLogic' method | ||
** widgetRepresentation(): This method allows to get a pointer to the WidgetRepresentation. If no WidgetRepresentation already exists, one will be created calling 'createWidgetRepresentation' method. | ** widgetRepresentation(): This method allows to get a pointer to the WidgetRepresentation. If no WidgetRepresentation already exists, one will be created calling 'createWidgetRepresentation' method. | ||
| − | + | * qSlicerCoreModuleFactory: | |
| − | + | ** registerItems -> registerCoreModule -> N * registerCoreModule -> extractName -> registerObject -> registerItem(moduleName) | |
| − | |||
<pre> | <pre> | ||
void qSlicerCoreModuleFactory::registerItems() | void qSlicerCoreModuleFactory::registerItems() | ||
| Line 105: | Line 104: | ||
</pre> | </pre> | ||
| − | + | * qSlicerLoadableModuleFactory | |
| − | + | ** registerItems -> use QDirIterator -> extractName -> registerPlugin(path, moduleName) | |
<pre> | <pre> | ||
template<typename BaseClassType> | template<typename BaseClassType> | ||
| Line 138: | Line 137: | ||
</pre> | </pre> | ||
| − | + | * qSlicerCLILoadableModuleFactory | |
| − | + | ** registerItems -> use QDirIterator -> extractName -> registerLibrary(path, moduleName) | |
<pre> | <pre> | ||
void qCTKFactoryLibraryItem<BaseClassType>::resolve() | void qCTKFactoryLibraryItem<BaseClassType>::resolve() | ||
Latest revision as of 07:11, 8 March 2010
Home < Events:CTK-Hackfest-2010 < SlicerQtPluginArchitectureContents
Goal
- Provide a cross-platform plugin architecture
- Modular and extensible
Big picture
- a Factory manages a collection of Factory items
- Factory Item provides load() and instanciate() methods
- Factory provides registerItems() and load(key) methods
- Factory are templated
Under the hood
The Qt layer
- QPlugin [1] [2] (from Qt docmentation ... )
- QPluginLoader checks that a plugin is linked against the same version of Qt as the application.
- QPluginLoader provides direct access to a root component object (instance()), instead of forcing you to resolve a C function manually.
- In order to speed up loading and validation of plugins, some of the information that is collected during loading is cached in persistent memory (through QSettings).
- QLibrary [3]
- QObject / Object
The CTK layer
- Base class: qCTKAbstractFactory
template<typename BaseClassType>
class qCTKAbstractFactory
{
...
public:
explicit qCTKAbstractFactory();
virtual ~qCTKAbstractFactory();
virtual void printAdditionalInfo();
/// Return factory name
virtual QString name()const = 0;
/// Create an instance of the object
virtual BaseClassType * instantiate(const QString& itemKey);
/// Uninstanciate the object
void uninstantiate(const QString& itemKey);
/// Get list of all registered item names
QStringList names() const;
/// Register items with the factory
/// Method provided for convenience - Should be overloaded in subclasse
virtual void registerItems(){}
protected:
/// Call the load method associated with the item.
/// If succesfully loaded, add it to the internal map.
bool registerItem(const QSharedPointer<qCTKAbstractFactoryItem<BaseClassType> > & item);
/// Get a Factory item given its itemKey. Return 0 if any.
qCTKAbstractFactoryItem<BaseClassType> * item(const QString& itemKey)const;
private:
...
};
- 3 kind of factory:
- qCTKAbstractLibraryFactory
- qCTKAbstractObjectFactory
- qCTKAbstractPluginFactory
- A factory manage a collection of qCTKAbstractFactoryItem.
template<typename BaseClassType>
class qCTKAbstractFactoryItem
{
public:
explicit qCTKAbstractFactoryItem(const QString& key);
virtual QString loadErrorString()const;
virtual bool load() = 0;
BaseClassType* instantiate();
bool instantiated();
QString key();
virtual void uninstantiate();
protected:
virtual BaseClassType* instanciator() = 0;
BaseClassType* Instance;
private:
QString Key;
};
Concrete example(s)
- All modules are based on qSlicerAbstractModule which provides:
- logic(): This method allows to get a pointer to the ModuleLogic. If no moduleLogic already exists, one will be created calling 'createLogic' method
- widgetRepresentation(): This method allows to get a pointer to the WidgetRepresentation. If no WidgetRepresentation already exists, one will be created calling 'createWidgetRepresentation' method.
- qSlicerCoreModuleFactory:
- registerItems -> registerCoreModule -> N * registerCoreModule -> extractName -> registerObject -> registerItem(moduleName)
void qSlicerCoreModuleFactory::registerItems()
{
QCTK_D(qSlicerCoreModuleFactory);
d->registerCoreModule<qSlicerTransformsModule>();
d->registerCoreModule<qSlicerCamerasModule>();
}
- qSlicerLoadableModuleFactory
- registerItems -> use QDirIterator -> extractName -> registerPlugin(path, moduleName)
template<typename BaseClassType>
bool qCTKFactoryPluginItem<BaseClassType>::load()
{
this->Loader.setFileName(this->path());
return this->Loader.load();
}
template<typename BaseClassType>
BaseClassType* qCTKFactoryPluginItem<BaseClassType>::instanciator()
{
//qDebug() << "PluginItem::instantiate - name:" << this->path();
QObject * object = this->Loader.instance();
if (!object)
{
qWarning() << "Failed to instantiate plugin:" << this->path();
return 0;
}
BaseClassType* castedObject = qobject_cast<BaseClassType*>(object);
if (!castedObject)
{
qWarning() << "Failed to access interface [" << BaseClassType::staticMetaObject.className()
<< "] in plugin:" << this->path();
delete object; // Clean memory
return 0;
}
return castedObject;
}
- qSlicerCLILoadableModuleFactory
- registerItems -> use QDirIterator -> extractName -> registerLibrary(path, moduleName)
void qCTKFactoryLibraryItem<BaseClassType>::resolve()
{
foreach(const QString& symbol, this->Symbols)
{
// Sanity checks
if (symbol.isEmpty())
{
continue;
}
// Make sure the symbols haven't been registered
if (this->ResolvedSymbols.contains(symbol))
{
qWarning() << "Symbol '" << symbol << "' already resolved - Path:" << this->Path;
continue;
}
void * resolvedSymbol = this->Library.resolve(symbol.toLatin1());
if (!resolvedSymbol)
{
qWarning() << "Failed to resolve symbol '" << symbol << "' - Path:" << this->Path;
}
this->ResolvedSymbols[symbol] = resolvedSymbol;
}
}