Skip to content

Event Handling (communication between plugins)

Alexander Vieth edited this page May 28, 2024 · 7 revisions

ManiVault facilitates communication between plugins (which do not need to know of each other during build time) through the means of events. These events are mainly used to inform plugins about dataset related changes.

Plugins may listen to data changes by registering:

Registering data events on a specific dataset

Changes to datasets are made public via signals. A plugin may listen to these signals and react to them:

// Request a dataset with given GUID from the core
Dataset<Points> pointDataset = mv::data().getDataset(datasetGuid); 

// Listen to changes in the data of dataset 'pointDataset', when its data changes, call onDataChange().
connect(&pointDataset, &Dataset<Points>::dataChanged, this, &ExamplePlugin::onDataChange);

A list of all signals a dataset can emit can be found below.

Registering data event for any dataset

Every plugin class has access to a member variable called _eventListener which is defined in its base class. This EventListener can be used to register for any dataset events.

The general syntax of these functions is as follows:

registerDataEvent(DataEventHandler callback);
registerDataEventByType(DataType dataType, DataEventHandler callback);

where DataEventHandler is a generic C++ function object and DataType is a ManiVault data type, e.g. PointType, ImageType or ClusterType.

Additionally, a plugin needs to specify which mv::EventType it wants to listen to:

addSupportedEventType(std::uint32_t eventType);
setSupportedEventTypes(const QSet<std::uint32_t>& eventTypes);

An example function call could look similar to this:

// Add DatasetDataChanged to the list of events this plugin listens to
addSupportedEventType(static_cast<std::uint32_t>(EventType::DatasetDataChanged));

// Register events involving only point data, events are sent to custom onDataEvent callback function with one argument
registerDataEventByType(PointType, std::bind(&YourOwnPlugin::onDataEvent, this, std::placeholders::_1));

We either bind a function (here onDataEvent) or pass a lambda to the callback.

Registering all data events

The EventListener can be used to register dataset events from all data with registerDataEvent:

// [[ExamplePlugin.h]]
using namespace mv::plugin;

class ExamplePlugin : public ViewPlugin
{
    ...
    void onDatasetEvent(mv::DatasetEvent* datasetEvent);
    ...
}

// [[ExamplePlugin.cpp]]
#include <event/Event.h>

using namespace mv;

void ExamplePlugin::init()
{
    _eventListener.addSupportedEventType(static_cast<std::uint32_t>(EventType::DatasetDataChanged));
    _eventListener.addSupportedEventType(static_cast<std::uint32_t>(EventType::DatasetDataSelectionChanged);

    // React to dataset events from all data types, providing the callback function 'onDatasetEvent'
    _eventListener.registerDataEvent(std::bind(&ExamplePlugin::onDatasetEvent, this, std::placeholders::_1));

    // React to events from all data types
    _eventListener.registerDataEvent([this](DatasetEvent* dataEvent) {
        const auto& dataset = dataEvent->getDataset();
			
        if(dataset->getDataType() != PointType)
            return;

        switch (dataEvent->getType()) {
            case EventType::DatasetDataChanged:            [[fallthrough]];
            case EventType::DatasetDataSelectionChanged:   [[fallthrough]];
            break;
        }
    });

}

void onDatasetEvent(mv::DatasetEvent* datasetEvent)
{
    if (dataEvent->getType() == EventType::DatasetDataChanged)
    {
         // Handle data changed event
    }
    else if (dataEvent->getType() == EventType::DatasetDataSelectionChanged)
    {
         // Handle data selection changed event
    }
}

Registering data events by data type

The EventListener can also be used to register dataset events from a particular type of data (such as point data) with registerDataEventByType:

// [[ExamplePlugin.h]]
using namespace mv::plugin;

class ExamplePlugin : public ViewPlugin
{
    ...
    void onDatasetEvent(mv::DatasetEvent* datasetEvent);
    ...
}

// [[ExamplePlugin.cpp]]
#include <event/Event.h>

using namespace mv;

void ExamplePlugin::init()
{
    _eventListener.addSupportedEventType(static_cast<std::uint32_t>(EventType::DatasetDataChanged));
    _eventListener.addSupportedEventType(static_cast<std::uint32_t>(EventType::DatasetDataSelectionChanged);

    // React to dataset events from all point data, providing the callback function 'onDatasetEvent'
    _eventListener.registerDataEventByType(PointType, std::bind(&ExamplePlugin::onDatasetEvent, this, std::placeholders::_1));
}

void onDatasetEvent(mv::DatasetEvent* datasetEvent)
{
    switch (dataEvent->getType()) {
        case EventType::DatasetDataChanged:            [[fallthrough]];
        case EventType::DatasetDataSelectionChanged:   [[fallthrough]];
        break;
    }
}

Event and signal overview

Some operations of data set automatically emit signals. Most data operations leave the timing of notifying other plugins about data changes to the developer. Plugins emit these notifications via ManiVault's events() manager.

Most notifications follow the syntax events().notify*(dataset) where * is the name of the event to be emitted:

events().notifyDatasetDataChanged(dataset);                             // standard syntax for most events
events().notifyDatasetRemoved(datasetGuid, dataType);                   // exception: need to provide data type during removal
events().notifyDatasetDataSelectionChanged(dataset, ignoreDatasets);    // exception: optionally add datasets that should be ignored during notification

As defined in Event.h and DatasetPrivate.h, these are all dataset related events:

Event Dataset signal Description
N/A Dataset<DatasetImpl>::changed The pointer to the dataset changed
DatasetDataChanged Dataset<DatasetImpl>::dataChanged The/A dataset data changed
DatasetDataDimensionsChanged Dataset<DatasetImpl>::dataDimensionsChanged A dataset dimensions changed
DatasetDataSelectionChanged Dataset<DatasetImpl>::dataSelectionChanged The/A dataset selection changed
DatasetAboutToBeRemoved Dataset<DatasetImpl>::aboutToBeRemoved The/A dataset is about to be removed
DatasetRemoved Dataset<DatasetImpl>::removed The/A dataset has been removed
N/A Dataset<DatasetImpl>::guiNameChanged The dataset GUI name changed
DatasetChildAdded Dataset<DatasetImpl>::childAdded A dataset child is added
DatasetChildRemoved Dataset<DatasetImpl>::childRemoved A dataset child was removed
DatasetLocked N/A A dataset is now locked
DatasetUnlocked N/A A dataset is now unlocked
Clone this wiki locally