diff --git a/src/ColoringAction.cpp b/src/ColoringAction.cpp index c3fca1f..88b693d 100644 --- a/src/ColoringAction.cpp +++ b/src/ColoringAction.cpp @@ -164,6 +164,29 @@ ColoringAction::ColoringAction(QObject* parent, const QString& title) : _scatterplotPlugin->getScatterplotWidget().setColoringMode(ScatterplotWidget::ColoringMode::Constant); } +ColoringAction::~ColoringAction() +{ + // Disconnect all connections to prevent accessing freed memory during destruction + if (_scatterplotPlugin) { + disconnect(&_scatterplotPlugin->getPositionDataset(), nullptr, this, nullptr); + disconnect(&_scatterplotPlugin->getPositionSourceDataset(), nullptr, this, nullptr); + disconnect(&_scatterplotPlugin->getScatterplotWidget(), nullptr, this, nullptr); + } + + // Disconnect child action connections + disconnect(&_colorByAction, nullptr, this, nullptr); + disconnect(&_colorByModel, nullptr, this, nullptr); + disconnect(&_dimensionAction, nullptr, this, nullptr); + disconnect(&_constantColorAction, nullptr, this, nullptr); + disconnect(&_colorMap1DAction, nullptr, this, nullptr); + disconnect(&_colorMap2DAction, nullptr, this, nullptr); + + // Disconnect current dataset if valid + if (_currentColorPointsDataset.isValid()) { + disconnect(&_currentColorPointsDataset, nullptr, this, nullptr); + } +} + QMenu* ColoringAction::getContextMenu(QWidget* parent /*= nullptr*/) { auto menu = new QMenu("Color", parent); diff --git a/src/ColoringAction.h b/src/ColoringAction.h index 4a1d480..6f5eacf 100644 --- a/src/ColoringAction.h +++ b/src/ColoringAction.h @@ -35,6 +35,11 @@ class ColoringAction : public VerticalGroupAction * @param title Title */ Q_INVOKABLE ColoringAction(QObject* parent, const QString& title); + + /** + * Destructor - ensures proper cleanup of Qt connections + */ + ~ColoringAction(); /** * Get the context menu for the action diff --git a/src/ScatterplotPlugin.cpp b/src/ScatterplotPlugin.cpp index 1e35b7c..a9f67b0 100644 --- a/src/ScatterplotPlugin.cpp +++ b/src/ScatterplotPlugin.cpp @@ -292,6 +292,27 @@ ScatterplotPlugin::ScatterplotPlugin(const PluginFactory* factory) : ScatterplotPlugin::~ScatterplotPlugin() { + disconnect(this); + if (_positionDataset.isValid()) { + disconnect(&_positionDataset, nullptr, this, nullptr); + } + + if (_scatterPlotWidget) { + disconnect(_scatterPlotWidget, nullptr, this, nullptr); + disconnect(&_scatterPlotWidget->getPixelSelectionTool(), nullptr, this, nullptr); + disconnect(&_scatterPlotWidget->getPointRendererNavigator().getNavigationAction().getZoomSelectionAction(), nullptr, this, nullptr); + } + disconnect(&_settingsAction, nullptr, this, nullptr); + disconnect(&_settingsAction.getColoringAction(), nullptr, this, nullptr); + disconnect(&_settingsAction.getColoringAction().getColorByAction(), nullptr, this, nullptr); + disconnect(&_settingsAction.getPlotAction().getPointPlotAction().getFocusSelection(), nullptr, this, nullptr); + disconnect(&_settingsAction.getPlotAction().getPointPlotAction().getSizeAction(), nullptr, this, nullptr); + disconnect(&_settingsAction.getPlotAction().getPointPlotAction().getOpacityAction(), nullptr, this, nullptr); + disconnect(&_settingsAction.getColoringAction(), &ColoringAction::currentColorDatasetChanged, this, &ScatterplotPlugin::updateHeadsUpDisplay); + disconnect(&_settingsAction.getColoringAction().getColorByAction(), &OptionAction::currentIndexChanged, this, &ScatterplotPlugin::updateHeadsUpDisplay); + disconnect(&_settingsAction.getPlotAction().getPointPlotAction().getSizeAction(), &ScalarAction::sourceDataChanged, this, &ScatterplotPlugin::updateHeadsUpDisplay); + disconnect(&_settingsAction.getPlotAction().getPointPlotAction().getOpacityAction(), &ScalarAction::sourceDataChanged, this, &ScatterplotPlugin::updateHeadsUpDisplay); + disconnect(&getSamplerAction(), nullptr, this, nullptr); } void ScatterplotPlugin::init() @@ -1017,6 +1038,9 @@ void ScatterplotPlugin::updateSelection() void ScatterplotPlugin::updateHeadsUpDisplay() { +#ifdef __APPLE__ + return; +#endif getHeadsUpDisplayAction().removeAllHeadsUpDisplayItems(); if (_positionDataset.isValid()) { diff --git a/src/SettingsAction.cpp b/src/SettingsAction.cpp index 03d0f82..8b63e66 100644 --- a/src/SettingsAction.cpp +++ b/src/SettingsAction.cpp @@ -45,6 +45,28 @@ SettingsAction::SettingsAction(QObject* parent, const QString& title) : connect(&_scatterplotPlugin->getPositionDataset(), &Dataset::changed, this, updateEnabled); } +SettingsAction::~SettingsAction() +{ + // Disconnect all connections to prevent accessing freed memory during destruction + if (_scatterplotPlugin) { + disconnect(&_scatterplotPlugin->getPositionDataset(), nullptr, this, nullptr); + disconnect(&_scatterplotPlugin->getPositionSourceDataset(), nullptr, this, nullptr); + disconnect(&_scatterplotPlugin->getScatterplotWidget(), nullptr, this, nullptr); + } + + // Disconnect all child actions to prevent cross-references during destruction + disconnect(&_coloringAction, nullptr, this, nullptr); + disconnect(&_plotAction, nullptr, this, nullptr); + disconnect(&_positionAction, nullptr, this, nullptr); + disconnect(&_renderModeAction, nullptr, this, nullptr); + disconnect(&_selectionAction, nullptr, this, nullptr); + disconnect(&_subsetAction, nullptr, this, nullptr); + disconnect(&_clusteringAction, nullptr, this, nullptr); + disconnect(&_exportAction, nullptr, this, nullptr); + disconnect(&_miscellaneousAction, nullptr, this, nullptr); + disconnect(&_datasetsAction, nullptr, this, nullptr); +} + QMenu* SettingsAction::getContextMenu() { auto menu = new QMenu(); diff --git a/src/SettingsAction.h b/src/SettingsAction.h index a6b0ba9..726b23e 100644 --- a/src/SettingsAction.h +++ b/src/SettingsAction.h @@ -34,6 +34,11 @@ class SettingsAction : public GroupAction * @param title Title */ Q_INVOKABLE SettingsAction(QObject* parent, const QString& title); + + /** + * Destructor - ensures proper cleanup of Qt connections + */ + ~SettingsAction(); /** * Get action context menu