Event System
This guide covers the event system used in MNE Analyze for inter-plugin communication, not to be confused with the Event Manager plugin.
Overview
In addition to the Qt Framework's signal/slot system, MNE Analyze uses a dedicated event system for all communication between plugins. This event system is integrated into all plugins through the AbstractPlugin interface, allowing every plugin to send and receive events. The event manager runs on a separate thread, cycling through a buffer and delivering queued events to subscribed plugins.
Events
Events can be used to send data, trigger things, or both. As an example: SELECTED_MODEL_CHANGED, one of the most widely used event types, which is triggered by the selection of a new item in the Data Manager, contains a QSharedPointer<ANSHAREDLIB::AbstractModel>>, a pointer to the selected data item; while TRIGGER_REDRAW, used for making the Signal Viewer update, contains no data.
All event types are declared in applications/mne_analyze/libs/anShared/Utils/types.h in the EVENT_TYPE enum. To add a new event type, simply add an entry to this enum. Events should ideally serve a single purpose and always send and expect the same type of data, if any.
Sending Events
Events are sent using the Communicator class (applications/mne_analyze/libs/anShared/Management/communicator.h) via its publishEvent() method. When sending an event you pass an event type and, optionally, data wrapped in a QVariant. Below is a code snippet of the Filtering plugin broadcasting an event with data:
void Filtering::setFilterChannelType(const QString& sType)
{
QVariant data;
data.setValue(sType);
m_pCommu->publishEvent(EVENT_TYPE::FILTER_CHANNEL_TYPE_CHANGED, data);
}
The string sType is stored in the QVariant via setValue() before being passed along with the event.
Receiving Events
To receive events of a certain type, a plugin must subscribe to that type. This is done in the plugin's implementation of getEventSubscriptions() by returning a vector of all the event types the plugin is interested in. Below is a code snippet of the Averaging plugin subscribing to events:
QVector<EVENT_TYPE> Averaging::getEventSubscriptions(void) const
{
QVector<EVENT_TYPE> temp;
temp.push_back(SELECTED_MODEL_CHANGED);
temp.push_back(FILTER_ACTIVE_CHANGED);
temp.push_back(FILTER_DESIGN_CHANGED);
temp.push_back(EVENT_GROUPS_UPDATED);
temp.push_back(CHANNEL_SELECTION_ITEMS);
temp.push_back(SCALING_MAP_CHANGED);
temp.push_back(VIEW_SETTINGS_CHANGED);
return temp;
}
Once subscribed, plugins handle incoming events via handleEvent(). Below is how the AnnotationManager plugin handles its events:
void AnnotationManager::handleEvent(QSharedPointer<Event> e)
{
switch (e->getType()) {
case EVENT_TYPE::NEW_ANNOTATION_ADDED:
emit newAnnotationAvailable(e->getData().toInt());
onTriggerRedraw();
break;
case EVENT_TYPE::SELECTED_MODEL_CHANGED:
onModelChanged(e->getData().value<QSharedPointer<ANSHAREDLIB::AbstractModel> >());
break;
default:
qWarning() << "[AnnotationManager::handleEvent] Received an Event that is not handled by switch cases.";
}
}
Best Practices
- Delegate to helper functions. Unless the handling code is very short, move the logic into a dedicated method for readability. See the
onModelChanged()pattern used in plugins that receiveSELECTED_MODEL_CHANGED. - One purpose per event. Each event type should carry a consistent data payload and serve a single, well-defined purpose.
- Document your events. When introducing a new
EVENT_TYPE, add a brief comment intypes.hdescribing what data it carries and which plugins produce/consume it.
Common Event Types
| Event | Data Payload | Typical Use |
|---|---|---|
SELECTED_MODEL_CHANGED | QSharedPointer<AbstractModel> | A new item was selected in the Data Manager |
FILTER_ACTIVE_CHANGED | bool | Filter was toggled on/off |
FILTER_DESIGN_CHANGED | Filter parameters | Filter settings were modified |
TRIGGER_REDRAW | (none) | Request views to repaint |
SCALING_MAP_CHANGED | Scaling map | Channel scaling was updated |
NEW_ANNOTATION_ADDED | int (annotation index) | A new annotation was created |