4.3.4. Plugin WAF Module

At this point, the project needs to be extended. The new widget-library/plugin module is added as shown in the following listing:

widget-library
├── plugin
│   ├── src
│   │   ├── include
│   │   │   └── cut
│   │   │       └── examples
│   │   │           └── widgets
│   │   │               └── plugin
│   │   │                   ├── QeExampleDmsLabelPlugin.hpp
│   │   │                   └── QeExamplesWidgetCollection.hpp
│   │   ├── QeExampleDmsLabelPlugin.cpp
│   │   └── QeExamplesWidgetCollection.cpp
│   └── wscript
├── widgets
│   ├── src
│   │   ├── include
│   │   │   ├── cut
│   │   │   │   └── examples
│   │   │   │       └── widgets
│   │   │   │           └── widgets
│   │   │   │               └── QeExampleDmsLabel.hpp
│   │   │   └── QeExamplesWidgets.h
│   │   └── QeExampleDmsLabel.cpp
│   └── wscript
└── wscript

The plugin/wscript file looks a bit different than the one in widgets WAF module:

../../../../examples/widget_library/plugin/wscript
 1from wtools.module import declare_qtcshlib
 2
 3# In the "use" parameter, if using modules from the same project,
 4#  you should use the name of the directory. It can be different from
 5#  the name of the target of that directory.
 6declare_qtcshlib(
 7    target='cutExamplesWidgetsPlugin',
 8    use='widgets',
 9    qt5_plugin=True
10)

This wscript file also uses the declare_qtcshlib wtools instruction. The main difference here is the additional keyword argument qt_plugin=True. This will indicate to the install command that the resulting library should be place into $INTROOT/lib64/designer. Then the QT_PLUGIN_PATH environment variable can be used by Qt Designer to find any widgets plugin. QT_PLUGIN_PATH shall be $INTROOT/lib64, as the designer expects a certain directory structure. One of these directories is designer, which is the one used to store any plugin intended for Qt Designer.

The second different is that the use argument for declare_qtcshlib command now include widgets. This indicates WAF that widgets module is a dependency, and therefore, must be compiled before this module. Also, when compiling this plugin module, its includes added to include paths, and its library added for linking instructions. widgets string must be the names of the directory structure, not the target names. If many directory levels are used in the project, then replace / with ..

Also, the installation instruction does not copy the includes from this module to the $INTROOT. As the plugins are not intended to be used for development, these files are not meant for further development.

4.3.4.1. Header files

Two classes, one for QeExampleDmsLabel plugin, and another for a Collection, are defined in this module.

The listing of the QeExampleDmsLabelPlugin.hpp is given below:

examples/widget_library/plugin/src/include/cut/examples/widgets/plugin/QeExampleDmsLabelPlugin.hpp
 1/**
 2 * @file
 3 * @ingroup widgets_plugin
 4 * @copyright ESO - European Southern Observatory
 5 * @author Arturo Hoffstadt Urrutia <ahoffsta@eso.org>
 6 *
 7 * @brief QeDmsLabel plugin for Qt Designer
 8 */
 9
10#ifndef QEEXAMPLEDMSLABELPLUGIN_HPP
11#define QEEXAMPLEDMSLABELPLUGIN_HPP
12
13#include <QtUiPlugin/QDesignerCustomWidgetInterface>
14
15/**
16 * @brief QeExampleDmsLabel Plugin for Qt Designer. Enables WYSIWYG design while using
17 * Qt Designer.
18 * @class QeExampleDmsLabelPlugin
19 * @ingroup widgets_plugin
20 *
21 * This class implements the QDesignerCustomWidgetInterface that enables
22 * Qt Designer to create new instances of the QeDmsLabel widget, and obtain
23 * information to present the widget, in the WYSIWYG view of the form, its
24 * toolbar, and properties view.
25 *
26 * @warning This class is not intended for developers, and is internal to CUT.
27 */
28class QeExampleDmsLabelPlugin : public QObject, public QDesignerCustomWidgetInterface
29{
30    Q_OBJECT
31    Q_INTERFACES(QDesignerCustomWidgetInterface)
32
33public:
34    QeExampleDmsLabelPlugin(QObject *parent = 0);
35
36    bool isContainer() const;
37    bool isInitialized() const;
38    QIcon icon() const;
39    QString domXml() const;
40    QString group() const;
41    QString includeFile() const;
42    QString name() const;
43    QString toolTip() const;
44    QString whatsThis() const;
45    QWidget *createWidget(QWidget *parent);
46    void initialize(QDesignerFormEditorInterface *core);
47
48private:
49    bool m_initialized;
50};
51
52#endif // QEEXAMPLEDMSLABELPLUGIN_HPP

This file does not change much from widget to widget. Only the name of the class does which is used for Class name, and constructor.

The contents of the Collection are also not very dynamic:

examples/widget_library/plugin/src/include/cut/examples/widgets/plugin/QeExamplesWidgetCollection.hpp
 1#ifndef QEEXAMPLEWIDGETCOLLECTION_HPP
 2#define QEEXAMPLEWIDGETCOLLECTION_HPP
 3
 4#include <QtUiPlugin/QDesignerCustomWidgetInterface>
 5#include <qplugin.h>
 6
 7class QeExamplesWidgetCollection : public QObject, public QDesignerCustomWidgetCollectionInterface
 8{
 9    Q_OBJECT
10    Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
11#if QT_VERSION >= 0x050000
12    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface")
13#endif // QT_VERSION >= 0x050000
14
15public:
16    explicit QeExamplesWidgetCollection(QObject *parent = 0);
17
18    virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const;
19
20private:
21    QList<QDesignerCustomWidgetInterface*> m_widgets;
22};
23
24#endif // QEEXAMPLEWIDGETCOLLECTION_HPP

The name of this class is tied to the name of the library instead of a particular widget. This Collection will provide access to all widgets in the plugin. The matter that we only provide only changes nothing. Qt Designer provides to us an interface ready to use to extend it with more widgets.

4.3.4.2. Implementation

The plugin implementation has more details. The Collection implementation needs to add the Plugin classes to a list during construction. And a specific method returns the list, informing Qt Designer of the widgets included in this Collection.

examples/widget_library/plugin/src/QeExamplesWidgetCollection.cpp
 1#include "include/cut/examples/widgets/plugin/QeExamplesWidgetCollection.hpp"
 2#include "include/cut/examples/widgets/plugin/QeExampleDmsLabelPlugin.hpp"
 3
 4#if WAF
 5#include "include/cut/examples/widgets/plugin/QeExamplesWidgetCollection.moc"
 6#endif
 7
 8
 9QeExamplesWidgetCollection::QeExamplesWidgetCollection(QObject *parent)
10    : QObject(parent)
11{
12    m_widgets.append(new QeExampleDmsLabelPlugin(this));
13}
14
15QList<QDesignerCustomWidgetInterface*> QeExamplesWidgetCollection::customWidgets() const
16{
17    return m_widgets;
18}

The Plugin implementation itself deals with necessary entries used during code generation. The UI files are themselves XML, and every time a widget is added to a UI file using the Qt Designer, it will query the different methods from this implementation.

examples/widget_library/plugin/src/QeExampleDmsLabelPlugin.cpp
  1#include "cut/examples/widgets/widgets/QeExampleDmsLabel.hpp"
  2#include "include/cut/examples/widgets/plugin/QeExampleDmsLabelPlugin.hpp"
  3
  4#include <QtPlugin>
  5
  6#if WAF
  7#include "include/cut/examples/widgets/plugin/QeExampleDmsLabelPlugin.moc"
  8#endif
  9
 10QeExampleDmsLabelPlugin::QeExampleDmsLabelPlugin(QObject *parent)
 11    : QObject(parent)
 12{
 13    m_initialized = false;
 14}
 15
 16void QeExampleDmsLabelPlugin::initialize(QDesignerFormEditorInterface * /* core */)
 17{
 18    if (m_initialized)
 19        return;
 20
 21    // Add extension registrations, etc. here
 22
 23    m_initialized = true;
 24}
 25
 26bool QeExampleDmsLabelPlugin::isInitialized() const
 27{
 28    return m_initialized;
 29}
 30
 31QWidget *QeExampleDmsLabelPlugin::createWidget(QWidget *parent)
 32{
 33    return new QeExampleDmsLabel(parent);
 34}
 35
 36QString QeExampleDmsLabelPlugin::name() const
 37{
 38    return QLatin1String("QeExampleDmsLabel");
 39}
 40
 41QString QeExampleDmsLabelPlugin::group() const
 42{
 43    return QLatin1String("Display Widgets");
 44}
 45
 46QIcon QeExampleDmsLabelPlugin::icon() const
 47{
 48    return QIcon();
 49}
 50
 51QString QeExampleDmsLabelPlugin::toolTip() const
 52{
 53    return QLatin1String("Displays as Degrees-Minutes-Seconds, or Hour-Minutes-Seconds, an angle in radians.");
 54}
 55
 56QString QeExampleDmsLabelPlugin::whatsThis() const
 57{
 58    return QLatin1String("");
 59}
 60
 61bool QeExampleDmsLabelPlugin::isContainer() const
 62{
 63    return false;
 64}
 65
 66QString QeExampleDmsLabelPlugin::domXml() const
 67{
 68    return QLatin1String("<widget class=\"QeExampleDmsLabel\" name=\"qeExampleDmsLabel\">\n"
 69                            "  <property name=\"radians\">\n"
 70                            "     <double>0.0</double>\n"
 71                            "  </property>\n"
 72                            "  <property name=\"precision\">\n"
 73                            "     <number>3</number>\n"
 74                            "  </property>\n"
 75                         "</widget>\n");
 76}
 77
 78/*
 79 * We use a small hack to allow compatibility between Python
 80 * and C++ resolution of classes on the UI compilers.
 81 * C++ UI compiler uses the includeFile() to construct its
 82 * include statement.
 83 *
 84 * #include QeWidgetExample.h
 85 * QeDartBoard* qeDartBoard = new QeDartBoard();
 86 *
 87 * Python UI compiler uses the includeFile() and the name()
 88 * to construct the import statement, but removes the '.h'
 89 * suffix.
 90 *
 91 * from QeWidgetExample import QeDartBoard
 92 *
 93 * Using an intermediary file allows us to use the same
 94 * includeFile() string under Python and C++.
 95 */
 96QString QeExampleDmsLabelPlugin::includeFile() const
 97{
 98    return QLatin1String("QeExamplesWidgets.h");
 99}
100
101////
  • createWidget() should return a new widget. This is used by the designer to place a widget in the view for the WYSIWYG editor.

  • name() returns the class name of the widget. It has to be the name of the class in C++/Python.

  • group() returns a name for the category the widget is placed in the Qt Designer Toolbox.

  • icon() returns a Pixmap that represents the widget in a concise manner. Used in the Toolbox along with the :samp`name`, and in the Object Inspector Docking Widget.

  • toolTip() contextual help shown as a tooltip on the Toolbox.

  • whatsThis() contextual help shown when the What’s This feature is activated. Usually is longer than the tooltip.

  • domXml() initial XML inserted into the UI file when the widget is added to the file.