Difference between revisions of "Events:CTK-Hackfest-2010/SlicerQtPluginArchitecture"
From NAMIC Wiki
m (→Big picture) |
m (→Under the hood) |
||
| Line 11: | Line 11: | ||
* The Qt layer | * The Qt layer | ||
| − | ** QPlugin (from Qt docmentation ... ) | + | ** 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 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. | *** 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). | *** 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 | + | ** QLibrary [http://doc.trolltech.com/4.6-snapshot/qlibrary.html] |
** QObject / Object | ** QObject / Object | ||
| Line 90: | Line 90: | ||
All modules are based on qSlicerAbstractModule | All modules are based on qSlicerAbstractModule | ||
qSlicerAbstractModule provided methods: | qSlicerAbstractModule provided methods: | ||
| − | + | * 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: | ** qSlicerCoreModuleFactory: | ||
Revision as of 07:07, 8 March 2010
Home < Events:CTK-Hackfest-2010 < SlicerQtPluginArchitectureGoal
- 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
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
- QPlugin [1] [2] (from Qt docmentation ... )
- 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
- 3 kind of factory:
- 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 qSlicerAbstractModule provided methods:
- 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)
- qSlicerLoadableModuleFactory
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)
- qSlicerCLILoadableModuleFactory
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;
}
}