Difference between revisions of "Events:CTK-Hackfest-2010/SlicerQtPluginArchitecture"
From NAMIC Wiki
m (→Under the hood) |
m (→Big picture) |
||
(2 intermediate revisions by the same user not shown) | |||
Line 7: | Line 7: | ||
* Factory Item provides load() and instanciate() methods | * Factory Item provides load() and instanciate() methods | ||
* Factory provides registerItems() and load(key) methods | * 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; } }