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:

 1project(SamplePlugin)
 2
 3# Add the plugin
 4
 5add_plugin(Sample
 6    SOURCES
 7        ../../plugininfo.cpp
 8
 9        src/sampleplugin.cpp
10        src/sampleutilities.cpp
11    QT_MODULES
12        Core
13)

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 and QT_MODULES at lines 6 and 11, 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 (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.) Finally, OpenCOR uses the Qt framework, so even though our Sample plugin is very minimal, we must still reference the Core module (line 12).

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#include "plugininfo.h"
29
30//==============================================================================
31
32namespace OpenCOR {
33namespace Sample {
34
35//==============================================================================
36
37PLUGININFO_FUNC SamplePluginInfo();
38
39//==============================================================================
40
41class SamplePlugin : public QObject
42{
43    Q_OBJECT
44
45    Q_PLUGIN_METADATA(IID "OpenCOR.SamplePlugin" FILE "sampleplugin.json")
46};
47
48//==============================================================================
49
50} // namespace Sample
51} // 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    "Keys": [ "SamplePlugin" ]
3}

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

24#include "sampleplugin.h"
25
26//==============================================================================
27
28namespace OpenCOR {
29namespace Sample {
30
31//==============================================================================
32
33PLUGININFO_FUNC SamplePluginInfo()
34{
35    static const Descriptions descriptions = {
36                                                 { "en", QString::fromUtf8("a plugin that provides an addition function.") },
37                                                 { "fr", QString::fromUtf8("une extension qui fournit une fonction d'addition.") }
38                                             };
39
40    return new PluginInfo(PluginInfo::Category::Sample, false, false,
41                          {},
42                          descriptions);
43}
44
45//==============================================================================
46
47} // namespace Sample
48} // 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 36 and 37). 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::Category::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 {}; 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#include <QtGlobal>
29
30//==============================================================================
31
32#include "sampleglobal.h"
33
34//==============================================================================
35
36namespace OpenCOR {
37namespace Sample {
38
39//==============================================================================
40
41double SAMPLE_EXPORT add(double pNb1, double pNb2);
42
43//==============================================================================
44
45} // namespace Sample
46} // namespace OpenCOR

We start by including sampleglobal.h (line 32). 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 41).

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

24#include "sampleutilities.h"
25
26//==============================================================================
27
28namespace OpenCOR {
29namespace Sample {
30
31//==============================================================================
32
33double add(double pNb1, double pNb2)
34{
35    // Return the sum of the two given numbers
36
37    return pNb1+pNb2;
38}
39
40//==============================================================================
41
42} // namespace Sample
43} // 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).