Difference between revisions of "Events:CTK-Hackfest-2010/SlicerQtPluginArchitecture"

From NAMIC Wiki
Jump to: navigation, search
 
(3 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
+
== 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
  
* The CTK layer
+
== The CTK layer ==
** Base class: qCTKAbstractFactory
+
* Base class: qCTKAbstractFactory
 
<pre>
 
<pre>
 
template<typename BaseClassType>
 
template<typename BaseClassType>
Line 60: Line 61:
 
</pre>
 
</pre>
  
** 3 kind of factory:  
+
* 3 kind of factory:  
*** qCTKAbstractLibraryFactory
+
** qCTKAbstractLibraryFactory
*** qCTKAbstractObjectFactory
+
** qCTKAbstractObjectFactory
*** qCTKAbstractPluginFactory
+
** qCTKAbstractPluginFactory
  
** A factory manage a collection of qCTKAbstractFactoryItem.
+
* A factory manage a collection of qCTKAbstractFactoryItem.
 
<pre>
 
<pre>
 
template<typename BaseClassType>
 
template<typename BaseClassType>
Line 87: Line 88:
 
</pre>
 
</pre>
  
* Concrete example(s)
+
== Concrete example(s) ==
All modules are based on qSlicerAbstractModule
+
* All modules are based on qSlicerAbstractModule which provides:
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
 
** 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:  
+
* qSlicerCoreModuleFactory:  
 
+
** registerItems -> registerCoreModule -> N * registerCoreModule -> extractName -> registerObject -> registerItem(moduleName)
*** registerItems -> registerCoreModule -> N * registerCoreModule -> extractName -> registerObject -> registerItem(moduleName)
 
 
<pre>
 
<pre>
 
void qSlicerCoreModuleFactory::registerItems()
 
void qSlicerCoreModuleFactory::registerItems()
Line 105: Line 104:
 
</pre>
 
</pre>
  
** qSlicerLoadableModuleFactory
+
* qSlicerLoadableModuleFactory
*** registerItems -> use QDirIterator -> extractName -> registerPlugin(path, moduleName)
+
** registerItems -> use QDirIterator -> extractName -> registerPlugin(path, moduleName)
 
<pre>
 
<pre>
 
template<typename BaseClassType>
 
template<typename BaseClassType>
Line 138: Line 137:
 
</pre>
 
</pre>
  
** qSlicerCLILoadableModuleFactory
+
* qSlicerCLILoadableModuleFactory
*** registerItems -> use QDirIterator -> extractName -> registerLibrary(path, moduleName)
+
** 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 < SlicerQtPluginArchitecture

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;
    }
}