Sample

The purpose of this plugin is to give other plugins access to a simple add() function, which can be used as follows:

...
#include "sampleutilities.h"
...
double addResult = Sample::add(3.0, 5.0);
...

File structure

src
 ├─ sampleglobal.h
 ├─ sampleplugin.cpp
 ├─ sampleplugin.h
 ├─ sampleplugin.json
 ├─ sampleutilities.cpp
 └─ sampleutilities.h
CMakeLists.txt

Category

The first thing we need to do is to decide on the category of our plugin. Our plugin is aimed at helping people who want to learn how to write plugins for OpenCOR. So, it should be in the Sample category. This means that its code can be found under [OpenCOR]/src/plugins/sample/Sample/.

Interfaces

All our plugin does is make its add() function available to other plugins, so there is no need for our plugin to interact with OpenCOR and, therefore, no need to implement any interface.

CMake project

To build our plugin, we need a CMakeLists.txt file (some information on CMake and plugins in OpenCOR can be found here), which contents is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
project(SamplePlugin)

# Add the plugin

add_plugin(Sample
    SOURCES
        ../../plugininfo.cpp

        src/sampleplugin.cpp
        src/sampleutilities.cpp
    HEADERS_MOC
        src/sampleplugin.h
    QT_MODULES
        Core
)

The first line specifies the name of the CMake project for our Sample plugin, i.e. SamplePlugin. Then, we have a call to the add_plugin() macro (line 5), which is defined in [OpenCOR]/cmake/common.cmake. Different types of parameters are passed to it (SOURCES, HEADERS_MOC and QT_MODULES at lines 6, 11 and 13, respectively), followed by the parameters themselves.

As for any plugin, our Sample plugin must reference [OpenCOR]/src/plugins/plugininfo.cpp (line 7), so that it can provide some basic information about itself (see below). .cpp files that contain the plugin’s implementation code must also be referenced (lines 9 and 10). (Note that they start with sample, i.e. the name of the plugin in lower case. This convention is used throughout OpenCOR’s code to ensure that there are no name clashes between plugins’ files.) All header files that define at least one class that uses the Q_OBJECT macro must also be referenced. sampleplugin.h is one such file (see below) and is therefore referenced (line 12). Finally, OpenCOR uses the Qt framework, so even though our Sample plugin is very minimal, we must still reference the Core module (line 14).

Plugin information

We want our plugin to be recognisable by OpenCOR, which means that it must provide some plugin information. sampleplugin.cpp therefore contains a C function that is called by OpenCOR to retrieve some basic information about our plugin. That function is declared in sampleplugin.h, which is also where our plugin class is defined:

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "plugininfo.h"

//==============================================================================

namespace OpenCOR {
namespace Sample {

//==============================================================================

PLUGININFO_FUNC SamplePluginInfo();

//==============================================================================

class SamplePlugin : public QObject
{
    Q_OBJECT

    Q_PLUGIN_METADATA(IID "OpenCOR.SamplePlugin" FILE "sampleplugin.json")
};

//==============================================================================

}   // namespace Sample
}   // namespace OpenCOR

We need to know about the data structure of our basic information, so we must include plugininfo.h (line 28). Then, we must declare our C function (line 37). Finally, we have the definition of our plugin class (lines 41-46). The call to the Q_PLUGIN_METADATA() macro (line 45) requires to pass both an IID (OpenCOR.SamplePlugin) and the name of a JSON file (sampleplugin.json). As mentioned here, the JSON file simply references the name of our plugin class (SamplePlugin):

1
2
3
{
    "Keys": [ "SamplePlugin" ]
}

Next, we have our sampleplugin.cpp file, which contents is:

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "sampleplugin.h"

//==============================================================================

namespace OpenCOR {
namespace Sample {

//==============================================================================

PLUGININFO_FUNC SamplePluginInfo()
{
    Descriptions descriptions;

    descriptions.insert("en", QString::fromUtf8("a plugin that provides an addition function."));
    descriptions.insert("fr", QString::fromUtf8("une extension qui fournit une fonction d'addition."));

    return new PluginInfo(PluginInfo::Sample, false, false,
                          QStringList(),
                          descriptions);
}

//==============================================================================

}   // namespace Sample
}   // namespace OpenCOR

We start by including our header file (line 24). Then, lines 33-43 contain the body of our C function. The first thing it does is create an instance of Descriptions on the stack (line 35). This instance is used to provide a multilingual description of our plugin (here, both in English and in French; lines 37 and 38). Then, it creates and returns an instance of PluginInfo on the heap (lines 40-42), which contains the basic information needed by OpenCOR to identify our plugin. This includes our plugin’s category (PluginInfo::Sample; line 40), whether it is selectable (false; line 40), whether it offers direct CLI support (false; line 40), our plugin’s direct dependencies (none, hence QStringList(); line 41) and its multilingual description (descriptions; line 42).

Note: the returned PluginInfo object gets deleted by OpenCOR. So, no need to worry about it.

Plugin specific

Finally, we need to deal with our plugin’s add() function. It is declared in sampleutilities.h:

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "sampleglobal.h"

//==============================================================================

namespace OpenCOR {
namespace Sample {

//==============================================================================

double SAMPLE_EXPORT add(double pNb1, double pNb2);

//==============================================================================

}   // namespace Sample
}   // namespace OpenCOR

We start by including sampleglobal.h (line 28). This header file defines the SAMPLE_EXPORT macro (click here for some information on plugins’ global header file in OpenCOR), which we use to declare our plugin’s add() function (line 37).

The implementation of our plugin’s add() function can be found in sampleutilities.cpp:

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "sampleutilities.h"

//==============================================================================

namespace OpenCOR {
namespace Sample {

//==============================================================================

double add(double pNb1, double pNb2)
{
    // Return the sum of the two given numbers

    return pNb1+pNb2;
}

//==============================================================================

}   // namespace Sample
}   // namespace OpenCOR

We start by including sampleutilities.h (line 24). Then, we have a straightforward implementation of our plugin’s add() function (lines 33-38).