---
title: Event System
sidebar_label: Event System
---

# 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](https://doc.qt.io/qt-6/qvariant.html). Below is a code snippet of the Filtering plugin broadcasting an event with data:

```cpp
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:

```cpp
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:

```cpp
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 receive `SELECTED_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 in `types.h` describing 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 |
