Remove ugly widget factory to replace it by a more robust system
Goal
Enable plugins that have specific setters and getters to be handled in the composer through widget editors.
Summary of the new system
dtkCore
Modifications in In dtkCorePluginFactory
, add of method to record a widget_creator function and to create the widget using such a function.
As one only uses pointers to QWidget
, no link to neither inclusion of QtWidgets is required, thus avoiding spurious dependency.
dtkCore
Addition in -
dtkCorePluginWidgetManager
is a singleton that stores a map between concept objects encapsulated within aQVariant
and widgets that have to be provided by the plugins.
dtkComposer
Consequences for As a result, one is now able to factorize into dtkComposerNodeObject
the management of the editor widget. Code is as follows:
template <typename T> inline QWidget *dtkComposerNodeObject<T>::editor(void)
{
if (!m_factory) {
return nullptr;
}
QVariant v = dtkMetaType::variantFromValue(this->object());
QWidget *w = dtkCorePluginWidgetManager::instance().widget(v);
if (!w) {
w = m_factory->createWidget(m_implementation);
if (w) {
dtkCorePluginWidgetManager::instance().add(v, w);
}
}
return w;
}
First, one encapsulates the object into a QVariant
so that one can ask the dtkCorePluginWidgetManager
for a widget associated with the current object. If the widget exists, it is returned.
Else, one creates the widget using the factory and the name of the implementation of the current object.
When the creation is OK, the couple (QVariant, QWidget*)
is added to the dtkCorePluginWidgetManager
.
Connection with the plugins
When one adds the couple (QVariant, QWidget*)
in the dtkCorePluginWidgetManager
, a signal added(const QVariant&, QWidget*)
is emitted.
This signal can be connected to the widget provided by the plugin in order to get the instance of the object into the widget and makes connections between the specific setters and getters of the object and its dedicated widget.
For instance, let us consider the plugin dtkVtkMeshingFilterPlugin
that implement the concept dtkAbstractMeshingFilter
of dtkImagingFilters
layer. The implementation has the following specific setter method:
class dtkVtkMeshingFilter : public dtkAbstractMeshingFilter
{
...
public:
void setDecimate(bool decimate);
...
};
A widget has been created to handle this parameter through the composer editor:
#pragma once
#include <QtWidgets>
namespace Ui {
class dtkVtkMeshingFilterWidget;
}
class dtkVtkMeshingFilterWidget : public QWidget
{
public:
dtkVtkMeshingFilterWidget(QWidget *parent = 0);
~dtkVtkMeshingFilterWidget();
private:
Ui::dtkVtkMeshingFilterWidget *ui;
QMetaObject::Connection m_connection;
};
inline QWidget *dtkVtkMeshingFilterWidgetCreator(void)
{
return new dtkVtkMeshingFilterWidget();
}
In the constructor, one can now connect the signal emitted by the dtkCorePluginWidgetManager
to a lambda function that establish connection between the QCheckBox
in the widget and the setter method handling the decimate parameter of the object contained in the dtkComposerNodeObject
:
dtkVtkMeshingFilterWidget::dtkVtkMeshingFilterWidget(QWidget *parent) : QWidget(parent), ui(new Ui::dtkVtkMeshingFilterWidget)
{
ui->setupUi(this);
m_connection = connect(&dtkCorePluginWidgetManager::instance(),
&dtkCorePluginWidgetManager::added,
[=] (const QVariant& v, QWidget *w) {
if (w != this) {
dtkTrace() << Q_FUNC_INFO << "Mismatch widget";
return;
}
dtkAbstractMeshingFilter *f = v.value<dtkAbstractMeshingFilter *>();
if (!f) {
dtkTrace() << Q_FUNC_INFO << "Wrong concept";
return;
}
dtkVtkMeshingFilter *filter = dynamic_cast<dtkVtkMeshingFilter *>(f);
if (!filter) {
dtkTrace() << Q_FUNC_INFO << "Wrong implementation";
return;
}
connect(ui->m_decimate, &QCheckBox::toggled, [=] (bool b) {
filter->setDecimate(b);
});
dtkTrace() << Q_FUNC_INFO << "Connection done";
});
}
dtkVtkMeshingFilterWidget::~dtkVtkMeshingFilterWidget()
{
disconnect(m_connection);
delete ui;
}
Destructor disconnects the connection.
Less dependencies
The new system enables to remove dependencies to dtkWidgets
and, in the present case, dtkImagingWidgets
. We can even be able to compile the widget part of the plugin only when the composer is enabled.
Outline
The new system works as a charm on my ubuntu 16.04. It compiles on windows 7 for at least dtk and dtk-imaging. I have not yet tested it for dtk-plugins-imaging on windows.
If it is convincing enough, we can remove dtkWidgetFactory
from dtkWidgets
layer. It will imply to modify layers and plugins that uses it.