File indexing completed on 2024-05-12 11:41:17

0001 /*
0002     File                 : GuiObserver.cpp
0003     Project              : LabPlot
0004     Description          : GUI observer
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2010-2023 Alexander Semke <alexander.semke@web.de>
0007     SPDX-FileCopyrightText: 2015-2018 Stefan Gerlach <stefan.gerlach@uni.kn>
0008     SPDX-FileCopyrightText: 2016 Garvit Khatri <garvitdelhi@gmail.com>
0009 
0010     SPDX-License-Identifier: GPL-2.0-or-later
0011 */
0012 
0013 #include "kdefrontend/GuiObserver.h"
0014 #include "backend/core/AbstractAspect.h"
0015 #include "backend/core/AspectTreeModel.h"
0016 #include "backend/datasources/LiveDataSource.h"
0017 #include "backend/matrix/Matrix.h"
0018 #include "backend/spreadsheet/Spreadsheet.h"
0019 #include "backend/spreadsheet/StatisticsSpreadsheet.h"
0020 #include "backend/worksheet/Image.h"
0021 #include "backend/worksheet/InfoElement.h"
0022 #include "backend/worksheet/TextLabel.h"
0023 #include "backend/worksheet/Worksheet.h"
0024 #include "backend/worksheet/plots/cartesian/Axis.h"
0025 #include "backend/worksheet/plots/cartesian/BarPlot.h"
0026 #include "backend/worksheet/plots/cartesian/BoxPlot.h"
0027 #include "backend/worksheet/plots/cartesian/CartesianPlot.h"
0028 #include "backend/worksheet/plots/cartesian/CartesianPlotLegend.h"
0029 #include "backend/worksheet/plots/cartesian/CustomPoint.h"
0030 #include "backend/worksheet/plots/cartesian/Histogram.h"
0031 #include "backend/worksheet/plots/cartesian/KDEPlot.h"
0032 #include "backend/worksheet/plots/cartesian/QQPlot.h"
0033 #include "backend/worksheet/plots/cartesian/ReferenceLine.h"
0034 #include "backend/worksheet/plots/cartesian/XYCurve.h"
0035 #ifdef HAVE_CANTOR_LIBS
0036 #include "backend/cantorWorksheet/CantorWorksheet.h"
0037 #endif
0038 #ifdef HAVE_MQTT
0039 #include "backend/datasources/MQTTClient.h"
0040 #include "backend/datasources/MQTTSubscription.h"
0041 #include "backend/datasources/MQTTTopic.h"
0042 #endif
0043 #include "backend/core/Project.h"
0044 #include "backend/datapicker/Datapicker.h"
0045 #include "backend/datapicker/DatapickerCurve.h"
0046 #include "backend/datapicker/DatapickerImage.h"
0047 #include "commonfrontend/ProjectExplorer.h"
0048 #include "kdefrontend/MainWin.h"
0049 #include "kdefrontend/dockwidgets/AspectDock.h"
0050 #include "kdefrontend/dockwidgets/AxisDock.h"
0051 #include "kdefrontend/dockwidgets/BarPlotDock.h"
0052 #include "kdefrontend/dockwidgets/BoxPlotDock.h"
0053 #include "kdefrontend/dockwidgets/CartesianPlotDock.h"
0054 #include "kdefrontend/dockwidgets/CartesianPlotLegendDock.h"
0055 #include "kdefrontend/dockwidgets/ColumnDock.h"
0056 #include "kdefrontend/dockwidgets/CursorDock.h"
0057 #include "kdefrontend/dockwidgets/CustomPointDock.h"
0058 #include "kdefrontend/dockwidgets/HistogramDock.h"
0059 #include "kdefrontend/dockwidgets/ImageDock.h"
0060 #include "kdefrontend/dockwidgets/InfoElementDock.h"
0061 #include "kdefrontend/dockwidgets/KDEPlotDock.h"
0062 #include "kdefrontend/dockwidgets/LiveDataDock.h"
0063 #include "kdefrontend/dockwidgets/LollipopPlotDock.h"
0064 #include "kdefrontend/dockwidgets/MatrixDock.h"
0065 #include "kdefrontend/dockwidgets/NoteDock.h"
0066 #include "kdefrontend/dockwidgets/ProjectDock.h"
0067 #include "kdefrontend/dockwidgets/QQPlotDock.h"
0068 #include "kdefrontend/dockwidgets/ReferenceLineDock.h"
0069 #include "kdefrontend/dockwidgets/ReferenceRangeDock.h"
0070 #include "kdefrontend/dockwidgets/SpreadsheetDock.h"
0071 #include "kdefrontend/dockwidgets/StatisticsSpreadsheetDock.h"
0072 #include "kdefrontend/dockwidgets/WorksheetDock.h"
0073 #include "kdefrontend/dockwidgets/XYConvolutionCurveDock.h"
0074 #include "kdefrontend/dockwidgets/XYCorrelationCurveDock.h"
0075 #include "kdefrontend/dockwidgets/XYCurveDock.h"
0076 #include "kdefrontend/dockwidgets/XYDataReductionCurveDock.h"
0077 #include "kdefrontend/dockwidgets/XYDifferentiationCurveDock.h"
0078 #include "kdefrontend/dockwidgets/XYEquationCurveDock.h"
0079 #include "kdefrontend/dockwidgets/XYFitCurveDock.h"
0080 #include "kdefrontend/dockwidgets/XYFourierFilterCurveDock.h"
0081 #include "kdefrontend/dockwidgets/XYFourierTransformCurveDock.h"
0082 #include "kdefrontend/dockwidgets/XYHilbertTransformCurveDock.h"
0083 #include "kdefrontend/dockwidgets/XYIntegrationCurveDock.h"
0084 #include "kdefrontend/dockwidgets/XYInterpolationCurveDock.h"
0085 #include "kdefrontend/dockwidgets/XYSmoothCurveDock.h"
0086 #ifdef HAVE_CANTOR_LIBS
0087 #include "kdefrontend/dockwidgets/CantorWorksheetDock.h"
0088 #endif
0089 #include "kdefrontend/widgets/DatapickerCurveWidget.h"
0090 #include "kdefrontend/widgets/DatapickerImageWidget.h"
0091 #include "kdefrontend/widgets/LabelWidget.h"
0092 
0093 #include <DockWidget.h>
0094 #include <KLocalizedString>
0095 #include <QStackedWidget>
0096 #include <QStatusBar>
0097 #include <QToolBar>
0098 
0099 /*!
0100   \class GuiObserver
0101   \brief The GUI observer looks for the selection changes in the main window
0102   and shows/hides the correspondings dock widgets, toolbars etc.
0103   This class is intended to simplify (or not to overload) the code in MainWin.
0104 
0105   \ingroup kdefrontend
0106 */
0107 
0108 QVector<BaseDock*> initializedDocks;
0109 
0110 namespace GuiObserverHelper {
0111 
0112 template<class T>
0113 bool raiseDock(T*& dock, QStackedWidget* parent) {
0114     Q_ASSERT(parent);
0115     DEBUG(Q_FUNC_INFO << ", number of stacked widgets = " << parent->count())
0116 
0117     const bool generated = !dock;
0118     if (generated) {
0119         dock = new T(parent);
0120         initializedDocks << dock;
0121         parent->addWidget(dock);
0122     }
0123 
0124     // see https://wiki.qt.io/Technical_FAQ#How_can_I_get_a_QStackedWidget_to_automatically_switch_size_depending_on_the_content_of_the_page
0125     if (parent->currentWidget())
0126         parent->currentWidget()->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
0127     parent->setCurrentWidget(dock);
0128     parent->currentWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0129 
0130     // scroll the scroll area up to the top
0131     if (parent->parent() && parent->parent()->parent()) {
0132         auto* scrollArea = dynamic_cast<QScrollArea*>(parent->parent()->parent());
0133         if (scrollArea)
0134             scrollArea->ensureVisible(0, 0);
0135     }
0136     return generated;
0137 }
0138 
0139 template<class T>
0140 void raiseDockConnect(T*& dock, QStatusBar* statusBar, QStackedWidget* parent) {
0141     if (raiseDock(dock, parent))
0142         QObject::connect(dock, &T::info, [=](const QString& text) {
0143             statusBar->showMessage(text);
0144         });
0145 }
0146 
0147 template<class T>
0148 void raiseDockSetupConnect(T*& dock, QStatusBar* statusBar, QStackedWidget* parent) {
0149     if (raiseDock(dock, parent)) {
0150         dock->setupGeneral();
0151         QObject::connect(dock, &T::info, [=](const QString& text) {
0152             statusBar->showMessage(text);
0153         });
0154     }
0155 }
0156 
0157 template<class T>
0158 QList<T*> castList(const QList<AbstractAspect*>& selectedAspects) {
0159     QList<T*> list;
0160     for (auto* aspect : selectedAspects)
0161         list << static_cast<T*>(aspect);
0162     return list;
0163 }
0164 
0165 } // namespace GuiObserverHelper
0166 
0167 using namespace GuiObserverHelper;
0168 
0169 GuiObserver::GuiObserver(MainWin* mainWin)
0170     : m_mainWindow(mainWin) {
0171     connect(mainWin->m_projectExplorer, &ProjectExplorer::selectedAspectsChanged, this, &GuiObserver::selectedAspectsChanged);
0172     connect(mainWin->m_projectExplorer, &ProjectExplorer::hiddenAspectSelected, this, &GuiObserver::hiddenAspectSelected);
0173 }
0174 
0175 GuiObserver::~GuiObserver() {
0176     while (!initializedDocks.isEmpty())
0177         delete initializedDocks.takeLast();
0178 }
0179 
0180 /*!
0181   called on selection changes in the project explorer.
0182   Determines the type of the currently selected objects (aspects)
0183   and activates the corresponding dockwidgets, toolbars etc.
0184 */
0185 void GuiObserver::selectedAspectsChanged(const QList<AbstractAspect*>& selectedAspects) {
0186     auto clearDock = [&]() {
0187         if (m_mainWindow->stackedWidget->currentWidget())
0188             m_mainWindow->stackedWidget->currentWidget()->hide();
0189 
0190         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties"));
0191     };
0192 
0193     if (selectedAspects.isEmpty() || selectedAspects.front() == nullptr) {
0194         clearDock();
0195         return;
0196     }
0197 
0198     const AspectType type{selectedAspects.front()->type()};
0199     DEBUG(Q_FUNC_INFO << ", type: " << STDSTRING(AbstractAspect::typeName(type)))
0200 
0201     // update cursor dock
0202     if (m_mainWindow->cursorWidget) {
0203         if (type == AspectType::Worksheet) {
0204             auto* worksheet = static_cast<Worksheet*>(selectedAspects.front());
0205             m_mainWindow->cursorWidget->setWorksheet(worksheet);
0206         } else {
0207             auto* parent = selectedAspects.front()->parent(AspectType::Worksheet);
0208             if (parent) {
0209                 auto* worksheet = static_cast<Worksheet*>(parent);
0210                 m_mainWindow->cursorWidget->setWorksheet(worksheet);
0211             }
0212         }
0213     }
0214 
0215     // Check, whether objects of different types were selected.
0216     // Don't show any dock widgets in this case.
0217     for (const auto* aspect : selectedAspects) {
0218         if (aspect->type() != type) {
0219             clearDock();
0220             return;
0221         }
0222     }
0223 
0224     switch (type) {
0225     case AspectType::Spreadsheet:
0226         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Spreadsheet"));
0227         raiseDockConnect(m_spreadsheetDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0228         m_spreadsheetDock->setSpreadsheets(castList<Spreadsheet>(selectedAspects));
0229         break;
0230     case AspectType::StatisticsSpreadsheet:
0231         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Column Statistics"));
0232         raiseDockConnect(m_statisticsSpreadsheetDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0233         m_statisticsSpreadsheetDock->setSpreadsheets(castList<StatisticsSpreadsheet>(selectedAspects));
0234         break;
0235     case AspectType::Column: {
0236 #ifdef HAVE_CANTOR_LIBS
0237         auto* casParent = dynamic_cast<CantorWorksheet*>(selectedAspects.first()->parentAspect());
0238         if (casParent) {
0239             // a column from a CAS-worksheets was selected, show the dock widget for the CAS worksheet
0240             raiseDockConnect(m_cantorWorksheetDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0241             m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window %1 is a Cantor backend", "%1 Worksheet", casParent->backendName()));
0242             m_cantorWorksheetDock->setCantorWorksheets(QList<CantorWorksheet*>{casParent});
0243         } else
0244 #endif
0245         {
0246             m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Column"));
0247             raiseDockConnect(m_columnDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0248             m_columnDock->setColumns(castList<Column>(selectedAspects));
0249         }
0250         break;
0251     }
0252     case AspectType::Matrix:
0253         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Matrix"));
0254         raiseDockConnect(m_matrixDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0255         m_matrixDock->setMatrices(castList<Matrix>(selectedAspects));
0256         break;
0257     case AspectType::Worksheet: {
0258         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Worksheet"));
0259         raiseDockConnect(m_worksheetDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0260         m_worksheetDock->setWorksheets(castList<Worksheet>(selectedAspects));
0261         break;
0262     }
0263     case AspectType::CartesianPlot: {
0264         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Plot Area"));
0265         raiseDockConnect(m_cartesianPlotDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0266         m_cartesianPlotDock->setPlots(castList<CartesianPlot>(selectedAspects));
0267         break;
0268     }
0269     case AspectType::CartesianPlotLegend:
0270         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Legend"));
0271         raiseDockConnect(m_cartesianPlotLegendDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0272         m_cartesianPlotLegendDock->setLegends(castList<CartesianPlotLegend>(selectedAspects));
0273         break;
0274     case AspectType::Axis:
0275         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Axis"));
0276         raiseDockConnect(m_axisDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0277         m_axisDock->setAxes(castList<Axis>(selectedAspects));
0278         break;
0279     case AspectType::XYCurve:
0280         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: XY-Curve"));
0281         raiseDockSetupConnect(m_xyCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0282         m_xyCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0283         break;
0284     case AspectType::XYEquationCurve:
0285         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: XY-Equation"));
0286         raiseDockSetupConnect(m_xyEquationCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0287         m_xyEquationCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0288         break;
0289     case AspectType::XYDataReductionCurve:
0290         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Data Reduction"));
0291         if (!m_xyDataReductionCurveDock) {
0292             m_xyDataReductionCurveDock = new XYDataReductionCurveDock(m_mainWindow->stackedWidget, m_mainWindow->statusBar());
0293             m_xyDataReductionCurveDock->setupGeneral();
0294             connect(m_xyDataReductionCurveDock, &XYDataReductionCurveDock::info, [&](const QString& text) {
0295                 m_mainWindow->statusBar()->showMessage(text);
0296             });
0297             m_mainWindow->stackedWidget->addWidget(m_xyDataReductionCurveDock);
0298         }
0299 
0300         initializedDocks << m_xyDataReductionCurveDock;
0301         m_xyDataReductionCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0302 
0303         m_mainWindow->stackedWidget->setCurrentWidget(m_xyDataReductionCurveDock);
0304         break;
0305     case AspectType::XYDifferentiationCurve:
0306         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Differentiation"));
0307         raiseDockSetupConnect(m_xyDifferentiationCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0308         m_xyDifferentiationCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0309         break;
0310     case AspectType::XYIntegrationCurve:
0311         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Integration"));
0312         raiseDockSetupConnect(m_xyIntegrationCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0313         m_xyIntegrationCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0314         break;
0315     case AspectType::XYInterpolationCurve:
0316         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Interpolation"));
0317         raiseDockSetupConnect(m_xyInterpolationCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0318         m_xyInterpolationCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0319         break;
0320     case AspectType::XYSmoothCurve:
0321         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Smoothing"));
0322         raiseDockSetupConnect(m_xySmoothCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0323         m_xySmoothCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0324         break;
0325     case AspectType::XYFitCurve:
0326         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Fit"));
0327         raiseDockSetupConnect(m_xyFitCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0328         m_xyFitCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0329         break;
0330     case AspectType::XYFourierTransformCurve:
0331         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Fourier Transform"));
0332         raiseDockSetupConnect(m_xyFourierTransformCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0333         m_xyFourierTransformCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0334         break;
0335     case AspectType::XYHilbertTransformCurve:
0336         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Hilbert Transform"));
0337         raiseDockSetupConnect(m_xyHilbertTransformCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0338         m_xyHilbertTransformCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0339         break;
0340     case AspectType::XYFourierFilterCurve:
0341         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Fourier Filter"));
0342         raiseDockSetupConnect(m_xyFourierFilterCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0343         m_xyFourierFilterCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0344         break;
0345     case AspectType::XYConvolutionCurve:
0346         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Convolution/Deconvolution"));
0347         raiseDockSetupConnect(m_xyConvolutionCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0348         m_xyConvolutionCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0349         break;
0350     case AspectType::XYCorrelationCurve:
0351         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Auto-/Cross-Correlation"));
0352         raiseDockSetupConnect(m_xyCorrelationCurveDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0353         m_xyCorrelationCurveDock->setCurves(castList<XYCurve>(selectedAspects));
0354         break;
0355     case AspectType::Histogram:
0356         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Histogram"));
0357         raiseDockConnect(m_histogramDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0358         m_histogramDock->setCurves(castList<Histogram>(selectedAspects));
0359         break;
0360     case AspectType::BarPlot:
0361         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Bar Plot"));
0362         raiseDock(m_barPlotDock, m_mainWindow->stackedWidget);
0363         m_barPlotDock->setBarPlots(castList<BarPlot>(selectedAspects));
0364         break;
0365     case AspectType::LollipopPlot:
0366         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Lollipop Plot"));
0367         raiseDock(m_lollipopPlotDock, m_mainWindow->stackedWidget);
0368         m_lollipopPlotDock->setPlots(castList<LollipopPlot>(selectedAspects));
0369         break;
0370     case AspectType::BoxPlot:
0371         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Box Plot"));
0372         raiseDock(m_boxPlotDock, m_mainWindow->stackedWidget);
0373         m_boxPlotDock->setBoxPlots(castList<BoxPlot>(selectedAspects));
0374         break;
0375     case AspectType::KDEPlot:
0376         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "KDE Plot"));
0377         raiseDock(m_kdePlotDock, m_mainWindow->stackedWidget);
0378         m_kdePlotDock->setPlots(castList<KDEPlot>(selectedAspects));
0379         break;
0380     case AspectType::QQPlot:
0381         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Q-Q Plot"));
0382         raiseDock(m_qqPlotDock, m_mainWindow->stackedWidget);
0383         m_qqPlotDock->setPlots(castList<QQPlot>(selectedAspects));
0384         break;
0385     case AspectType::TextLabel:
0386         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Text Label"));
0387         raiseDock(m_textLabelDock, m_mainWindow->stackedWidget);
0388         m_textLabelDock->setLabels(castList<TextLabel>(selectedAspects));
0389         break;
0390     case AspectType::Image:
0391         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Image"));
0392         raiseDock(m_imageDock, m_mainWindow->stackedWidget);
0393         m_imageDock->setImages(castList<Image>(selectedAspects));
0394         break;
0395     case AspectType::CustomPoint:
0396         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Custom Point"));
0397         raiseDock(m_customPointDock, m_mainWindow->stackedWidget);
0398         m_customPointDock->setPoints(castList<CustomPoint>(selectedAspects));
0399         break;
0400     case AspectType::ReferenceLine:
0401         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Reference Line"));
0402         raiseDock(m_referenceLineDock, m_mainWindow->stackedWidget);
0403         m_referenceLineDock->setReferenceLines(castList<ReferenceLine>(selectedAspects));
0404         break;
0405     case AspectType::ReferenceRange:
0406         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Reference Range"));
0407         raiseDock(m_referenceRangeDock, m_mainWindow->stackedWidget);
0408         m_referenceRangeDock->setReferenceRanges(castList<ReferenceRange>(selectedAspects));
0409         break;
0410     case AspectType::DatapickerCurve:
0411         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Datapicker Curve"));
0412         raiseDock(m_datapickerCurveDock, m_mainWindow->stackedWidget);
0413         m_datapickerCurveDock->setCurves(castList<DatapickerCurve>(selectedAspects));
0414         break;
0415     case AspectType::Datapicker:
0416         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Data Extractor"));
0417         raiseDock(m_datapickerImageDock, m_mainWindow->stackedWidget);
0418         {
0419             QList<DatapickerImage*> list;
0420             for (auto* aspect : selectedAspects)
0421                 list << static_cast<Datapicker*>(aspect)->image();
0422             m_datapickerImageDock->setImages(list);
0423         }
0424         break;
0425     case AspectType::Project:
0426         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Project"));
0427         raiseDock(m_projectDock, m_mainWindow->stackedWidget);
0428         m_projectDock->setProject(m_mainWindow->m_project);
0429         break;
0430     case AspectType::CantorWorksheet:
0431 #ifdef HAVE_CANTOR_LIBS
0432         raiseDockConnect(m_cantorWorksheetDock, m_mainWindow->statusBar(), m_mainWindow->stackedWidget);
0433         {
0434             auto list = castList<CantorWorksheet>(selectedAspects);
0435             if (list.size() == 1)
0436                 m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window %1 is a Cantor backend", "%1 Notebook", list.first()->backendName()));
0437             else
0438                 m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Notebook"));
0439             m_cantorWorksheetDock->setCantorWorksheets(list);
0440         }
0441 #endif
0442         break;
0443     case AspectType::Note:
0444         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Notes"));
0445         raiseDock(m_notesDock, m_mainWindow->stackedWidget);
0446         m_notesDock->setNotesList(castList<Note>(selectedAspects));
0447         break;
0448     case AspectType::InfoElement: {
0449         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Info Element"));
0450         raiseDock(m_infoElementDock, m_mainWindow->stackedWidget);
0451         m_infoElementDock->setInfoElements(castList<InfoElement>(selectedAspects));
0452         break;
0453     }
0454     case AspectType::MQTTClient:
0455 #ifdef HAVE_MQTT
0456         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: MQTT Data Source"));
0457         raiseDock(m_liveDataDock, m_mainWindow->stackedWidget);
0458         m_liveDataDock->setMQTTClient(static_cast<MQTTClient*>(selectedAspects.first()));
0459 #endif
0460         break;
0461     case AspectType::MQTTSubscription:
0462 #ifdef HAVE_MQTT
0463         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: MQTT Data Source"));
0464         raiseDock(m_liveDataDock, m_mainWindow->stackedWidget);
0465         m_liveDataDock->setMQTTClient(static_cast<MQTTSubscription*>(selectedAspects.first())->mqttClient());
0466 #endif
0467         break;
0468     case AspectType::MQTTTopic:
0469 #ifdef HAVE_MQTT
0470         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: MQTT Data Source"));
0471         raiseDock(m_liveDataDock, m_mainWindow->stackedWidget);
0472         m_liveDataDock->setMQTTClient(static_cast<MQTTTopic*>(selectedAspects.first())->mqttClient());
0473 #endif
0474         break;
0475     case AspectType::LiveDataSource:
0476         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Live Data Source"));
0477         raiseDock(m_liveDataDock, m_mainWindow->stackedWidget);
0478         m_liveDataDock->setLiveDataSource(static_cast<LiveDataSource*>(selectedAspects.first()));
0479         break;
0480     case AspectType::AbstractAspect:
0481     case AspectType::AbstractColumn:
0482     case AspectType::AbstractDataSource:
0483     case AspectType::AbstractFilter:
0484     case AspectType::AbstractPart:
0485     case AspectType::AbstractPlot:
0486     case AspectType::ColumnStringIO:
0487     case AspectType::DatapickerImage:
0488     case AspectType::DatapickerPoint:
0489     case AspectType::Folder:
0490         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Folder"));
0491         raiseDock(m_aspectDock, m_mainWindow->stackedWidget);
0492         m_aspectDock->setAspects(selectedAspects);
0493         break;
0494     case AspectType::PlotArea:
0495     case AspectType::SimpleFilterColumn:
0496     case AspectType::Workbook:
0497         m_mainWindow->m_propertiesDock->setWindowTitle(i18nc("@title:window", "Properties: Workbook"));
0498         raiseDock(m_aspectDock, m_mainWindow->stackedWidget);
0499         m_aspectDock->setAspects(selectedAspects);
0500         break;
0501     case AspectType::WorksheetElement:
0502     case AspectType::WorksheetElementContainer:
0503     case AspectType::WorksheetElementGroup:
0504     case AspectType::XYAnalysisCurve:
0505         clearDock();
0506         return;
0507     }
0508 
0509     m_mainWindow->stackedWidget->currentWidget()->show();
0510 }
0511 
0512 /*!
0513     handles the selection of a hidden aspect \c aspect in the view (relevant for WorksheetView only at the moment).
0514     Currently, a hidden aspect can only be a plot title lable or an axis label.
0515     -> Activate the corresponding DockWidget and make the title tab current.
0516  */
0517 void GuiObserver::hiddenAspectSelected(const AbstractAspect* aspect) {
0518     const AbstractAspect* parent = aspect->parentAspect();
0519     if (!parent)
0520         return;
0521 
0522     switch (static_cast<quint64>(parent->type())) { // cast the enum to turn off warnings about unhandled cases
0523     case static_cast<quint64>(AspectType::Axis):
0524         if (!m_axisDock) {
0525             m_axisDock = new AxisDock(m_mainWindow->stackedWidget);
0526             initializedDocks << m_axisDock;
0527             m_mainWindow->stackedWidget->addWidget(m_axisDock);
0528         }
0529         m_axisDock->activateTitleTab();
0530         break;
0531     case static_cast<quint64>(AspectType::CartesianPlot):
0532         if (!m_cartesianPlotDock) {
0533             m_cartesianPlotDock = new CartesianPlotDock(m_mainWindow->stackedWidget);
0534             initializedDocks << m_cartesianPlotDock;
0535             m_mainWindow->stackedWidget->addWidget(m_cartesianPlotDock);
0536         }
0537         m_cartesianPlotDock->activateTitleTab();
0538         break;
0539     case static_cast<quint64>(AspectType::CartesianPlotLegend):
0540         if (!m_cartesianPlotLegendDock) {
0541             m_cartesianPlotLegendDock = new CartesianPlotLegendDock(m_mainWindow->stackedWidget);
0542             initializedDocks << m_cartesianPlotLegendDock;
0543             m_mainWindow->stackedWidget->addWidget(m_cartesianPlotLegendDock);
0544         }
0545         m_cartesianPlotLegendDock->activateTitleTab();
0546         break;
0547     default:
0548         break;
0549     }
0550 }