##// END OF EJS Templates
Merge branch 'feature/VariableDeletion' into develop
Alexandre Leroux -
r311:c155354de1ae merge
parent child
Show More
@@ -0,0 +1,41
1 #ifndef SCIQLOP_REMOVEVARIABLEOPERATION_H
2 #define SCIQLOP_REMOVEVARIABLEOPERATION_H
3
4 #include "Visualization/IVisualizationWidgetVisitor.h"
5
6 #include <Common/spimpl.h>
7
8 #include <QLoggingCategory>
9
10 #include <memory>
11
12 class Variable;
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_RemoveVariableOperation)
15
16 /**
17 * @brief The RemoveVariableOperation class defines an operation that traverses all of visualization
18 * widgets to remove a variable if they contain it
19 */
20 class RemoveVariableOperation : public IVisualizationWidgetVisitor {
21 public:
22 /**
23 * Ctor
24 * @param variable the variable to remove from widgets
25 */
26 explicit RemoveVariableOperation(std::shared_ptr<Variable> variable);
27
28 void visitEnter(VisualizationWidget *widget) override final;
29 void visitLeave(VisualizationWidget *widget) override final;
30 void visitEnter(VisualizationTabWidget *tabWidget) override final;
31 void visitLeave(VisualizationTabWidget *tabWidget) override final;
32 void visitEnter(VisualizationZoneWidget *zoneWidget) override final;
33 void visitLeave(VisualizationZoneWidget *zoneWidget) override final;
34 void visit(VisualizationGraphWidget *graphWidget) override final;
35
36 private:
37 class RemoveVariableOperationPrivate;
38 spimpl::unique_impl_ptr<RemoveVariableOperationPrivate> impl;
39 };
40
41 #endif // SCIQLOP_REMOVEVARIABLEOPERATION_H
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,70
1 #include "Visualization/operations/RemoveVariableOperation.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3
4 #include <Variable/Variable.h>
5
6 Q_LOGGING_CATEGORY(LOG_RemoveVariableOperation, "RemoveVariableOperation")
7
8 struct RemoveVariableOperation::RemoveVariableOperationPrivate {
9 explicit RemoveVariableOperationPrivate(std::shared_ptr<Variable> variable)
10 : m_Variable(variable)
11 {
12 }
13
14 std::shared_ptr<Variable> m_Variable;
15 };
16
17 RemoveVariableOperation::RemoveVariableOperation(std::shared_ptr<Variable> variable)
18 : impl{spimpl::make_unique_impl<RemoveVariableOperationPrivate>(variable)}
19 {
20 }
21
22 void RemoveVariableOperation::visitEnter(VisualizationWidget *widget)
23 {
24 // VisualizationWidget is not intended to contain a variable
25 Q_UNUSED(widget)
26 }
27
28 void RemoveVariableOperation::visitLeave(VisualizationWidget *widget)
29 {
30 // VisualizationWidget is not intended to contain a variable
31 Q_UNUSED(widget)
32 }
33
34 void RemoveVariableOperation::visitEnter(VisualizationTabWidget *tabWidget)
35 {
36 // VisualizationTabWidget is not intended to contain a variable
37 Q_UNUSED(tabWidget)
38 }
39
40 void RemoveVariableOperation::visitLeave(VisualizationTabWidget *tabWidget)
41 {
42 // VisualizationTabWidget is not intended to contain a variable
43 Q_UNUSED(tabWidget)
44 }
45
46 void RemoveVariableOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
47 {
48 // VisualizationZoneWidget is not intended to contain a variable
49 Q_UNUSED(zoneWidget)
50 }
51
52 void RemoveVariableOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
53 {
54 // VisualizationZoneWidget is not intended to contain a variable
55 Q_UNUSED(zoneWidget)
56 }
57
58 void RemoveVariableOperation::visit(VisualizationGraphWidget *graphWidget)
59 {
60 if (graphWidget) {
61 // If the widget contains the variable, removes it
62 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
63 graphWidget->removeVariable(impl->m_Variable);
64 }
65 }
66 else {
67 qCCritical(LOG_RemoveVariableOperation(),
68 "Can't visit VisualizationGraphWidget : the widget is null");
69 }
70 }
@@ -1,259 +1,265
1 1 /*------------------------------------------------------------------------------
2 2 -- This file is a part of the SciQLop Software
3 3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
4 4 --
5 5 -- This program is free software; you can redistribute it and/or modify
6 6 -- it under the terms of the GNU General Public License as published by
7 7 -- the Free Software Foundation; either version 2 of the License, or
8 8 -- (at your option) any later version.
9 9 --
10 10 -- This program is distributed in the hope that it will be useful,
11 11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 -- GNU General Public License for more details.
14 14 --
15 15 -- You should have received a copy of the GNU General Public License
16 16 -- along with this program; if not, write to the Free Software
17 17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 18 -------------------------------------------------------------------------------*/
19 19 /*-- Author : Alexis Jeandet
20 20 -- Mail : alexis.jeandet@member.fsf.org
21 21 ----------------------------------------------------------------------------*/
22 22 #include "MainWindow.h"
23 23 #include "ui_MainWindow.h"
24 24
25 25 #include <DataSource/DataSourceController.h>
26 26 #include <DataSource/DataSourceWidget.h>
27 27 #include <SidePane/SqpSidePane.h>
28 28 #include <SqpApplication.h>
29 29 #include <Time/TimeController.h>
30 30 #include <TimeWidget/TimeWidget.h>
31 31 #include <Variable/Variable.h>
32 32 #include <Variable/VariableController.h>
33 33 #include <Visualization/VisualizationController.h>
34 34
35 35 #include <QAction>
36 36 #include <QDate>
37 37 #include <QDateTime>
38 38 #include <QDir>
39 39 #include <QFileDialog>
40 40 #include <QToolBar>
41 41 #include <QToolButton>
42 42 #include <memory.h>
43 43
44 44 //#include <omp.h>
45 45 //#include <network/filedownloader.h>
46 46 //#include <qlopdatabase.h>
47 47 //#include <qlopsettings.h>
48 48 //#include <qlopgui.h>
49 49 //#include <spacedata.h>
50 50 //#include "qlopcore.h"
51 51 //#include "qlopcodecmanager.h"
52 52 //#include "cdfcodec.h"
53 53 //#include "amdatxtcodec.h"
54 54 //#include <qlopplotmanager.h>
55 55
56 56 #include "iostream"
57 57
58 58 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
59 59
60 60 namespace {
61 61 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
62 62 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
63 63 const auto VIEWPLITTERINDEX = 2;
64 64 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
65 65 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
66 66 }
67 67
68 68 class MainWindow::MainWindowPrivate {
69 69 public:
70 70 QSize m_LastOpenLeftInspectorSize;
71 71 QSize m_LastOpenRightInspectorSize;
72 72 };
73 73
74 74 MainWindow::MainWindow(QWidget *parent)
75 75 : QMainWindow{parent},
76 76 m_Ui{new Ui::MainWindow},
77 77 impl{spimpl::make_unique_impl<MainWindowPrivate>()}
78 78 {
79 79 m_Ui->setupUi(this);
80 80
81 81 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
82 82 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
83 83
84 84
85 85 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
86 86 auto openLeftInspectorAction = new QAction{QIcon{
87 87 ":/icones/previous.png",
88 88 },
89 89 tr("Show/hide the left inspector"), this};
90 90
91 91
92 92 auto spacerLeftTop = new QWidget{};
93 93 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
94 94
95 95 auto spacerLeftBottom = new QWidget{};
96 96 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
97 97
98 98 leftSidePane->addWidget(spacerLeftTop);
99 99 leftSidePane->addAction(openLeftInspectorAction);
100 100 leftSidePane->addWidget(spacerLeftBottom);
101 101
102 102
103 103 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
104 104 auto openRightInspectorAction = new QAction{QIcon{
105 105 ":/icones/next.png",
106 106 },
107 107 tr("Show/hide the right inspector"), this};
108 108
109 109 auto spacerRightTop = new QWidget{};
110 110 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
111 111
112 112 auto spacerRightBottom = new QWidget{};
113 113 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
114 114
115 115 rightSidePane->addWidget(spacerRightTop);
116 116 rightSidePane->addAction(openRightInspectorAction);
117 117 rightSidePane->addWidget(spacerRightBottom);
118 118
119 119 openLeftInspectorAction->setCheckable(true);
120 120 openRightInspectorAction->setCheckable(true);
121 121
122 122 auto openInspector = [this](bool checked, bool right, auto action) {
123 123
124 124 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
125 125
126 126 auto &lastInspectorSize
127 127 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
128 128
129 129 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
130 130 : m_Ui->leftMainInspectorWidget->size();
131 131
132 132 // Update of the last opened geometry
133 133 if (checked) {
134 134 lastInspectorSize = nextInspectorSize;
135 135 }
136 136
137 137 auto startSize = lastInspectorSize;
138 138 auto endSize = startSize;
139 139 endSize.setWidth(0);
140 140
141 141 auto splitterInspectorIndex
142 142 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
143 143
144 144 auto currentSizes = m_Ui->splitter->sizes();
145 145 if (checked) {
146 146 // adjust sizes individually here, e.g.
147 147 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
148 148 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
149 149 m_Ui->splitter->setSizes(currentSizes);
150 150 }
151 151 else {
152 152 // adjust sizes individually here, e.g.
153 153 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
154 154 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
155 155 m_Ui->splitter->setSizes(currentSizes);
156 156 }
157 157
158 158 };
159 159
160 160
161 161 connect(openLeftInspectorAction, &QAction::triggered,
162 162 [openInspector, openLeftInspectorAction](bool checked) {
163 163 openInspector(checked, false, openLeftInspectorAction);
164 164 });
165 165 connect(openRightInspectorAction, &QAction::triggered,
166 166 [openInspector, openRightInspectorAction](bool checked) {
167 167 openInspector(checked, true, openRightInspectorAction);
168 168 });
169 169
170 170 this->menuBar()->addAction(tr("File"));
171 171 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
172 172
173 173 auto timeWidget = new TimeWidget{};
174 174 mainToolBar->addWidget(timeWidget);
175 175
176 // Controllers / controllers connections
177 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpDateTime)),
178 &sqpApp->variableController(), SLOT(onDateTimeOnSelection(SqpDateTime)));
179
176 180 // Widgets / controllers connections
177 181
178 182 // DataSource
179 183 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
180 184 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
181 185
182 186 // Time
183 187 connect(timeWidget, SIGNAL(timeUpdated(SqpDateTime)), &sqpApp->timeController(),
184 188 SLOT(onTimeToUpdate(SqpDateTime)));
185 189
186 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpDateTime)),
187 &sqpApp->variableController(), SLOT(onDateTimeOnSelection(SqpDateTime)));
190 // Visualization
191 connect(&sqpApp->visualizationController(),
192 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
193 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
188 194
189 195 // Widgets / widgets connections
190 196
191 197 // For the following connections, we use DirectConnection to allow each widget that can
192 198 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
193 199 // The order of connections is also important, since it determines the order in which each
194 200 // widget will attach its menu
195 201 connect(
196 202 m_Ui->variableInspectorWidget,
197 203 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
198 204 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
199 205 Qt::DirectConnection);
200 206
201 207 /* QLopGUI::registerMenuBar(menuBar());
202 208 this->setWindowIcon(QIcon(":/sciqlopLOGO.svg"));
203 209 this->m_progressWidget = new QWidget();
204 210 this->m_progressLayout = new QVBoxLayout(this->m_progressWidget);
205 211 this->m_progressWidget->setLayout(this->m_progressLayout);
206 212 this->m_progressWidget->setWindowModality(Qt::WindowModal);
207 213 m_progressThreadIds = (int*) malloc(OMP_THREADS*sizeof(int));
208 214 for(int i=0;i<OMP_THREADS;i++)
209 215 {
210 216 this->m_progress.append(new QProgressBar(this->m_progressWidget));
211 217 this->m_progress.last()->setMinimum(0);
212 218 this->m_progress.last()->setMaximum(100);
213 219 this->m_progressLayout->addWidget(this->m_progress.last());
214 220 this->m_progressWidget->hide();
215 221 this->m_progressThreadIds[i] = -1;
216 222 }
217 223 this->m_progressWidget->setWindowTitle("Loading File");
218 224 const QList<QLopService*>ServicesToLoad=QList<QLopService*>()
219 225 << QLopCore::self()
220 226 << QLopPlotManager::self()
221 227 << QLopCodecManager::self()
222 228 << FileDownloader::self()
223 229 << QLopDataBase::self()
224 230 << SpaceData::self();
225 231
226 232 CDFCodec::registerToManager();
227 233 AMDATXTCodec::registerToManager();
228 234
229 235
230 236 for(int i=0;i<ServicesToLoad.count();i++)
231 237 {
232 238 qDebug()<<ServicesToLoad.at(i)->serviceName();
233 239 ServicesToLoad.at(i)->initialize(); //must be called before getGUI
234 240 QDockWidget* wdgt=ServicesToLoad.at(i)->getGUI();
235 241 if(wdgt)
236 242 {
237 243 wdgt->setAllowedAreas(Qt::AllDockWidgetAreas);
238 244 this->addDockWidget(Qt::TopDockWidgetArea,wdgt);
239 245 }
240 246 PythonQt::self()->getMainModule().addObject(ServicesToLoad.at(i)->serviceName(),(QObject*)ServicesToLoad.at(i));
241 247 }*/
242 248 }
243 249
244 250 MainWindow::~MainWindow()
245 251 {
246 252 }
247 253
248 254
249 255 void MainWindow::changeEvent(QEvent *e)
250 256 {
251 257 QMainWindow::changeEvent(e);
252 258 switch (e->type()) {
253 259 case QEvent::LanguageChange:
254 260 m_Ui->retranslateUi(this);
255 261 break;
256 262 default:
257 263 break;
258 264 }
259 265 }
@@ -1,40 +1,46
1 1 #ifndef SCIQLOP_VARIABLECACHECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECACHECONTROLLER_H
3 3
4 #include <QLoggingCategory>
4 5 #include <QObject>
5 6
6 7 #include <Data/SqpDateTime.h>
7 8
8 9 #include <QLoggingCategory>
9 10
10 11 #include <Common/spimpl.h>
11 12
13 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableCacheController)
14
12 15 class Variable;
13 16
14 17 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableCacheController)
15 18
16 19
17 20 /// This class aims to store in the cache all of the dateTime already requested to the variable.
18 21 class VariableCacheController : public QObject {
19 22 Q_OBJECT
20 23 public:
21 24 explicit VariableCacheController(QObject *parent = 0);
22 25
23 26
24 27 void addDateTime(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
25 28
29 /// Clears cache concerning a variable
30 void clear(std::shared_ptr<Variable> variable) noexcept;
31
26 32 /// Return all of the SqpDataTime part of the dateTime whose are not in the cache
27 33 QVector<SqpDateTime> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
28 34 const SqpDateTime &dateTime);
29 35
30 36
31 37 QVector<SqpDateTime> dateCacheList(std::shared_ptr<Variable> variable) const noexcept;
32 38
33 39 void displayCache(std::shared_ptr<Variable> variable) const;
34 40
35 41 private:
36 42 class VariableCacheControllerPrivate;
37 43 spimpl::unique_impl_ptr<VariableCacheControllerPrivate> impl;
38 44 };
39 45
40 46 #endif // SCIQLOP_VARIABLECACHECONTROLLER_H
@@ -1,61 +1,82
1 1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECONTROLLER_H
3 3
4 4 #include <Data/SqpDateTime.h>
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8
9 9 #include <Common/spimpl.h>
10 10
11 11 class IDataProvider;
12 12 class QItemSelectionModel;
13 13 class TimeController;
14 14 class Variable;
15 15 class VariableModel;
16 16
17 17 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
18 18
19 19 /**
20 20 * @brief The VariableController class aims to handle the variables in SciQlop.
21 21 */
22 22 class VariableController : public QObject {
23 23 Q_OBJECT
24 24 public:
25 25 explicit VariableController(QObject *parent = 0);
26 26 virtual ~VariableController();
27 27
28 28 VariableModel *variableModel() noexcept;
29 29 QItemSelectionModel *variableSelectionModel() noexcept;
30 30
31 31 void setTimeController(TimeController *timeController) noexcept;
32 32
33 /**
34 * Deletes from the controller the variable passed in parameter.
35 *
36 * Delete a variable includes:
37 * - the deletion of the various references to the variable in SciQlop
38 * - the deletion of the model variable
39 * - the deletion of the provider associated with the variable
40 * - removing the cache associated with the variable
41 *
42 * @param variable the variable to delete from the controller.
43 */
44 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
45
46 /**
47 * Deletes from the controller the variables passed in parameter.
48 * @param variables the variables to delete from the controller.
49 * @sa deleteVariable()
50 */
51 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
33 52
34 53 signals:
54 /// Signal emitted when a variable is about to be deleted from the controller
55 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
35 56 /// Signal emitted when a variable has been created
36 57 void variableCreated(std::shared_ptr<Variable> variable);
37 58
38 59 public slots:
39 60 /// Request the data loading of the variable whithin dateTime
40 61 void onRequestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
41 62 /**
42 63 * Creates a new variable and adds it to the model
43 64 * @param name the name of the new variable
44 65 * @param provider the data provider for the new variable
45 66 */
46 67 void createVariable(const QString &name, std::shared_ptr<IDataProvider> provider) noexcept;
47 68
48 69 /// Update the temporal parameters of every selected variable to dateTime
49 70 void onDateTimeOnSelection(const SqpDateTime &dateTime);
50 71
51 72 void initialize();
52 73 void finalize();
53 74
54 75 private:
55 76 void waitForFinish();
56 77
57 78 class VariableControllerPrivate;
58 79 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
59 80 };
60 81
61 82 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,49 +1,55
1 1 #ifndef SCIQLOP_VARIABLEMODEL_H
2 2 #define SCIQLOP_VARIABLEMODEL_H
3 3
4 4
5 5 #include <Data/SqpDateTime.h>
6 6
7 7 #include <QAbstractTableModel>
8 8 #include <QLoggingCategory>
9 9
10 10 #include <Common/spimpl.h>
11 11
12 12 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel)
13 13
14 14 class IDataSeries;
15 15 class Variable;
16 16
17 17 /**
18 18 * @brief The VariableModel class aims to hold the variables that have been created in SciQlop
19 19 */
20 20 class VariableModel : public QAbstractTableModel {
21 21 public:
22 22 explicit VariableModel(QObject *parent = nullptr);
23 23
24 24 /**
25 25 * Creates a new variable in the model
26 26 * @param name the name of the new variable
27 27 * @param dateTime the dateTime of the new variable
28 28 * @return the pointer to the new variable
29 29 */
30 30 std::shared_ptr<Variable> createVariable(const QString &name,
31 31 const SqpDateTime &dateTime) noexcept;
32 32
33 /**
34 * Deletes a variable from the model, if it exists
35 * @param variable the variable to delete
36 */
37 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
38
33 39 std::shared_ptr<Variable> variable(int index) const;
34 40
35 41 // /////////////////////////// //
36 42 // QAbstractTableModel methods //
37 43 // /////////////////////////// //
38 44 virtual int columnCount(const QModelIndex &parent = QModelIndex{}) const override;
39 45 virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const override;
40 46 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
41 47 virtual QVariant headerData(int section, Qt::Orientation orientation,
42 48 int role = Qt::DisplayRole) const override;
43 49
44 50 private:
45 51 class VariableModelPrivate;
46 52 spimpl::unique_impl_ptr<VariableModelPrivate> impl;
47 53 };
48 54
49 55 #endif // SCIQLOP_VARIABLEMODEL_H
@@ -1,44 +1,46
1 1 #ifndef SCIQLOP_VISUALIZATIONCONTROLLER_H
2 2 #define SCIQLOP_VISUALIZATIONCONTROLLER_H
3 3
4 4 #include <QLoggingCategory>
5 5 #include <QObject>
6 6 #include <QUuid>
7 7
8 8 #include <Common/spimpl.h>
9 9
10 10 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationController)
11 11
12 12 class DataSourceItem;
13 13 class Variable;
14 14
15 15 /**
16 16 * @brief The VisualizationController class aims to make the link between SciQlop and its plugins.
17 17 * This is the intermediate class that SciQlop has to use in the way to connect a data source.
18 18 * Please first use register method to initialize a plugin specified by its metadata name (JSON
19 19 * plugin source) then others specifics method will be able to access it. You can load a data source
20 20 * driver plugin then create a data source.
21 21 */
22 22 class VisualizationController : public QObject {
23 23 Q_OBJECT
24 24 public:
25 25 explicit VisualizationController(QObject *parent = 0);
26 26 virtual ~VisualizationController();
27 27
28 28 signals:
29 /// Signal emitted when a variable is about to be deleted from SciQlop
30 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
29 31 /// Signal emitted when a variable has been created in SciQlop
30 32 void variableCreated(std::shared_ptr<Variable> variable);
31 33
32 34 public slots:
33 35 /// Manage init/end of the controller
34 36 void initialize();
35 37 void finalize();
36 38
37 39 private:
38 40 void waitForFinish();
39 41
40 42 class VisualizationControllerPrivate;
41 43 spimpl::unique_impl_ptr<VisualizationControllerPrivate> impl;
42 44 };
43 45
44 46 #endif // SCIQLOP_VISUALIZATIONCONTROLLER_H
@@ -1,204 +1,220
1 1 #include "Variable/VariableCacheController.h"
2 2
3 3 #include "Variable/Variable.h"
4 4 #include <unordered_map>
5 5
6 6 Q_LOGGING_CATEGORY(LOG_VariableCacheController, "VariableCacheController")
7 7
8 8 struct VariableCacheController::VariableCacheControllerPrivate {
9 9
10 10 std::unordered_map<std::shared_ptr<Variable>, QVector<SqpDateTime> >
11 11 m_VariableToSqpDateTimeListMap;
12 12
13 13 void addInCacheDataByEnd(const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
14 14 QVector<SqpDateTime> &notInCache, int cacheIndex,
15 15 double currentTStart);
16 16
17 17 void addInCacheDataByStart(const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
18 18 QVector<SqpDateTime> &notInCache, int cacheIndex,
19 19 double currentTStart);
20 20
21 21
22 22 void addDateTimeRecurse(const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
23 23 int cacheIndex);
24 24 };
25 25
26 26
27 27 VariableCacheController::VariableCacheController(QObject *parent)
28 28 : QObject{parent}, impl{spimpl::make_unique_impl<VariableCacheControllerPrivate>()}
29 29 {
30 30 }
31 31
32 32 void VariableCacheController::addDateTime(std::shared_ptr<Variable> variable,
33 33 const SqpDateTime &dateTime)
34 34 {
35 35 if (variable) {
36 36 auto findVariableIte = impl->m_VariableToSqpDateTimeListMap.find(variable);
37 37 if (findVariableIte == impl->m_VariableToSqpDateTimeListMap.end()) {
38 38 impl->m_VariableToSqpDateTimeListMap[variable].push_back(dateTime);
39 39 }
40 40 else {
41 41
42 42 // addDateTime modify the list<SqpDateTime> of the variable in a way to ensure
43 43 // that the list is ordered : l(0) < l(1). We assume also a < b
44 44 // (with a & b of type SqpDateTime) means ts(b) > te(a)
45 45
46 46 // The algorithm will try the merge of two interval:
47 47 // - dateTime will be compare with the first interval of the list:
48 48 // A: if it is inferior, it will be inserted and it's finished.
49 49 // B: if it is in intersection, it will be merge then the merged one
50 50 // will be compared to the next interval. The old one is remove from the list
51 51 // C: if it is superior, we do the same with the next interval of the list
52 52
53 53 try {
54 54 impl->addDateTimeRecurse(dateTime,
55 55 impl->m_VariableToSqpDateTimeListMap.at(variable), 0);
56 56 }
57 57 catch (const std::out_of_range &e) {
58 58 qCWarning(LOG_VariableCacheController()) << "addDateTime" << e.what();
59 59 }
60 60 }
61 61 }
62 62 }
63 63
64 void VariableCacheController::clear(std::shared_ptr<Variable> variable) noexcept
65 {
66 if (!variable) {
67 qCCritical(LOG_VariableCacheController()) << "Can't clear variable cache: variable is null";
68 return;
69 }
70
71 auto nbEntries = impl->m_VariableToSqpDateTimeListMap.erase(variable);
72
73 auto clearCacheMessage
74 = (nbEntries != 0)
75 ? tr("Variable cache cleared for variable %1").arg(variable->name())
76 : tr("No deletion of variable cache: no cache was associated with the variable");
77 qCDebug(LOG_VariableCacheController()) << clearCacheMessage;
78 }
79
64 80 QVector<SqpDateTime>
65 81 VariableCacheController::provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
66 82 const SqpDateTime &dateTime)
67 83 {
68 84 auto notInCache = QVector<SqpDateTime>{};
69 85
70 86 // This algorithm is recursif. The idea is to localise the start time then the end time in the
71 87 // list of date time request associated to the variable
72 88 // We assume that the list is ordered in a way that l(0) < l(1). We assume also a < b
73 89 // (with a & b of type SqpDateTime) means ts(b) > te(a)
74 90 auto it = impl->m_VariableToSqpDateTimeListMap.find(variable);
75 91 if (it != impl->m_VariableToSqpDateTimeListMap.end()) {
76 92 impl->addInCacheDataByStart(dateTime, it->second, notInCache, 0, dateTime.m_TStart);
77 93 }
78 94 else {
79 95 notInCache << dateTime;
80 96 }
81 97
82 98 return notInCache;
83 99 }
84 100
85 101 QVector<SqpDateTime>
86 102 VariableCacheController::dateCacheList(std::shared_ptr<Variable> variable) const noexcept
87 103 {
88 104 try {
89 105 return impl->m_VariableToSqpDateTimeListMap.at(variable);
90 106 }
91 107 catch (const std::out_of_range &e) {
92 108 qCWarning(LOG_VariableCacheController()) << e.what();
93 109 return QVector<SqpDateTime>{};
94 110 }
95 111 }
96 112
97 113 void VariableCacheController::VariableCacheControllerPrivate::addDateTimeRecurse(
98 114 const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList, int cacheIndex)
99 115 {
100 116 const auto dateTimeListSize = dateTimeList.count();
101 117 if (cacheIndex >= dateTimeListSize) {
102 118 dateTimeList.push_back(dateTime);
103 119 // there is no anymore interval to compore, we can just push_back it
104 120 return;
105 121 }
106 122
107 123 auto currentDateTime = dateTimeList[cacheIndex];
108 124
109 125 if (dateTime.m_TEnd < currentDateTime.m_TStart) {
110 126 // The compared one is < to current one compared, we can insert it
111 127 dateTimeList.insert(cacheIndex, dateTime);
112 128 }
113 129 else if (dateTime.m_TStart > currentDateTime.m_TEnd) {
114 130 // The compared one is > to current one compared we can comparet if to the next one
115 131 addDateTimeRecurse(dateTime, dateTimeList, ++cacheIndex);
116 132 }
117 133 else {
118 134 // Merge cases: we need to merge the two interval, remove the old one from the list then
119 135 // rerun the algo from this index with the merged interval
120 136 auto mTStart = std::min(dateTime.m_TStart, currentDateTime.m_TStart);
121 137 auto mTEnd = std::max(dateTime.m_TEnd, currentDateTime.m_TEnd);
122 138 auto mergeDateTime = SqpDateTime{mTStart, mTEnd};
123 139
124 140 dateTimeList.remove(cacheIndex);
125 141 addDateTimeRecurse(mergeDateTime, dateTimeList, cacheIndex);
126 142 }
127 143 }
128 144
129 145
130 146 void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByEnd(
131 147 const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
132 148 QVector<SqpDateTime> &notInCache, int cacheIndex, double currentTStart)
133 149 {
134 150 const auto dateTimeListSize = dateTimeList.count();
135 151 if (cacheIndex >= dateTimeListSize) {
136 152 if (currentTStart < dateTime.m_TEnd) {
137 153
138 154 // te localised after all other interval: The last interval is [currentTsart, te]
139 155 notInCache.push_back(SqpDateTime{currentTStart, dateTime.m_TEnd});
140 156 }
141 157 return;
142 158 }
143 159
144 160 auto currentDateTimeJ = dateTimeList[cacheIndex];
145 161 if (dateTime.m_TEnd <= currentDateTimeJ.m_TStart) {
146 162 // te localised between to interval: The last interval is [currentTsart, te]
147 163 notInCache.push_back(SqpDateTime{currentTStart, dateTime.m_TEnd});
148 164 }
149 165 else {
150 166 notInCache.push_back(SqpDateTime{currentTStart, currentDateTimeJ.m_TStart});
151 167 if (dateTime.m_TEnd > currentDateTimeJ.m_TEnd) {
152 168 // te not localised before the current interval: we need to look at the next interval
153 169 addInCacheDataByEnd(dateTime, dateTimeList, notInCache, ++cacheIndex,
154 170 currentDateTimeJ.m_TEnd);
155 171 }
156 172 }
157 173 }
158 174
159 175 void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByStart(
160 176 const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
161 177 QVector<SqpDateTime> &notInCache, int cacheIndex, double currentTStart)
162 178 {
163 179 const auto dateTimeListSize = dateTimeList.count();
164 180 if (cacheIndex >= dateTimeListSize) {
165 181 // ts localised after all other interval: The last interval is [ts, te]
166 182 notInCache.push_back(SqpDateTime{currentTStart, dateTime.m_TEnd});
167 183 return;
168 184 }
169 185
170 186 auto currentDateTimeI = dateTimeList[cacheIndex];
171 187 if (currentTStart < currentDateTimeI.m_TStart) {
172 188
173 189 // ts localised between to interval: let's localized te
174 190 addInCacheDataByEnd(dateTime, dateTimeList, notInCache, cacheIndex, currentTStart);
175 191 }
176 192 else if (currentTStart < currentDateTimeI.m_TEnd) {
177 193 if (dateTime.m_TEnd > currentDateTimeI.m_TEnd) {
178 194 // ts not localised before the current interval: we need to look at the next interval
179 195 // We can assume now current tstart is the last interval tend, because data between them
180 196 // are
181 197 // in the cache
182 198 addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex,
183 199 currentDateTimeI.m_TEnd);
184 200 }
185 201 }
186 202 else {
187 203 // ts not localised before the current interval: we need to look at the next interval
188 204 addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex, currentTStart);
189 205 }
190 206 }
191 207
192 208
193 209 void VariableCacheController::displayCache(std::shared_ptr<Variable> variable) const
194 210 {
195 211 auto variableDateTimeList = impl->m_VariableToSqpDateTimeListMap.find(variable);
196 212 if (variableDateTimeList != impl->m_VariableToSqpDateTimeListMap.end()) {
197 213 qCInfo(LOG_VariableCacheController()) << tr("VariableCacheController::displayCache")
198 214 << variableDateTimeList->second;
199 215 }
200 216 else {
201 217 qCWarning(LOG_VariableCacheController())
202 218 << tr("Cannot display a variable that is not in the cache");
203 219 }
204 220 }
@@ -1,177 +1,209
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableCacheController.h>
3 3 #include <Variable/VariableController.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Data/IDataProvider.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Time/TimeController.h>
10 10
11 11 #include <QDateTime>
12 12 #include <QMutex>
13 13 #include <QThread>
14 14 #include <QtCore/QItemSelectionModel>
15 15
16 16 #include <unordered_map>
17 17
18 18 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
19 19
20 20 namespace {
21 21
22 22 /// @todo Generates default dataseries, according to the provider passed in parameter. This method
23 23 /// will be deleted when the timerange is recovered from SciQlop
24 24 std::shared_ptr<IDataSeries> generateDefaultDataSeries(const IDataProvider &provider,
25 25 const SqpDateTime &dateTime) noexcept
26 26 {
27 27 auto parameters = DataProviderParameters{dateTime};
28 28
29 29 return provider.retrieveData(parameters);
30 30 }
31 31
32 32 } // namespace
33 33
34 34 struct VariableController::VariableControllerPrivate {
35 35 explicit VariableControllerPrivate(VariableController *parent)
36 36 : m_WorkingMutex{},
37 37 m_VariableModel{new VariableModel{parent}},
38 38 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
39 39 m_VariableCacheController{std::make_unique<VariableCacheController>()}
40 40 {
41 41 }
42 42
43 43 QMutex m_WorkingMutex;
44 44 /// Variable model. The VariableController has the ownership
45 45 VariableModel *m_VariableModel;
46 46 QItemSelectionModel *m_VariableSelectionModel;
47 47
48 48
49 49 TimeController *m_TimeController{nullptr};
50 50 std::unique_ptr<VariableCacheController> m_VariableCacheController;
51 51
52 52 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
53 53 m_VariableToProviderMap;
54 54 };
55 55
56 56 VariableController::VariableController(QObject *parent)
57 57 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
58 58 {
59 59 qCDebug(LOG_VariableController()) << tr("VariableController construction")
60 60 << QThread::currentThread();
61 61 }
62 62
63 63 VariableController::~VariableController()
64 64 {
65 65 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
66 66 << QThread::currentThread();
67 67 this->waitForFinish();
68 68 }
69 69
70 70 VariableModel *VariableController::variableModel() noexcept
71 71 {
72 72 return impl->m_VariableModel;
73 73 }
74 74
75 75 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
76 76 {
77 77 return impl->m_VariableSelectionModel;
78 78 }
79 79
80 80 void VariableController::setTimeController(TimeController *timeController) noexcept
81 81 {
82 82 impl->m_TimeController = timeController;
83 83 }
84 84
85 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
86 {
87 if (!variable) {
88 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
89 return;
90 }
91
92 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
93 // make some treatments before the deletion
94 emit variableAboutToBeDeleted(variable);
95
96 // Deletes provider
97 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
98 qCDebug(LOG_VariableController())
99 << tr("Number of providers deleted for variable %1: %2")
100 .arg(variable->name(), QString::number(nbProvidersDeleted));
101
102 // Clears cache
103 impl->m_VariableCacheController->clear(variable);
104
105 // Deletes from model
106 impl->m_VariableModel->deleteVariable(variable);
107 }
108
109 void VariableController::deleteVariables(
110 const QVector<std::shared_ptr<Variable> > &variables) noexcept
111 {
112 for (auto variable : qAsConst(variables)) {
113 deleteVariable(variable);
114 }
115 }
116
85 117 void VariableController::createVariable(const QString &name,
86 118 std::shared_ptr<IDataProvider> provider) noexcept
87 119 {
88 120
89 121 if (!impl->m_TimeController) {
90 122 qCCritical(LOG_VariableController())
91 123 << tr("Impossible to create variable: The time controller is null");
92 124 return;
93 125 }
94 126
95 127
96 128 /// @todo : for the moment :
97 129 /// - the provider is only used to retrieve data from the variable for its initialization, but
98 130 /// it will be retained later
99 131 /// - default data are generated for the variable, without taking into account the timerange set
100 132 /// in sciqlop
101 133 auto dateTime = impl->m_TimeController->dateTime();
102 134 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime)) {
103 135
104 136 // store the provider
105 137 impl->m_VariableToProviderMap[newVariable] = provider;
106 138
107 139 auto addDateTimeAcquired
108 140 = [this, newVariable](auto dataSeriesAcquired, auto dateTimeToPutInCache) {
109 141
110 142 impl->m_VariableCacheController->addDateTime(newVariable, dateTimeToPutInCache);
111 143 newVariable->setDataSeries(dataSeriesAcquired);
112 144
113 145 };
114 146
115 147 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
116 148 this->onRequestDataLoading(newVariable, dateTime);
117 149
118 150 // notify the creation
119 151 emit variableCreated(newVariable);
120 152 }
121 153 }
122 154
123 155 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
124 156 {
125 157 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
126 158
127 159 for (const auto &selectedRow : qAsConst(selectedRows)) {
128 160 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
129 161 selectedVariable->setDateTime(dateTime);
130 162 this->onRequestDataLoading(selectedVariable, dateTime);
131 163 }
132 164 }
133 165 }
134 166
135 167
136 168 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
137 169 const SqpDateTime &dateTime)
138 170 {
139 171 // we want to load data of the variable for the dateTime.
140 172 // First we check if the cache contains some of them.
141 173 // For the other, we ask the provider to give them.
142 174 if (variable) {
143 175
144 176 auto dateTimeListNotInCache
145 177 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
146 178
147 179 if (!dateTimeListNotInCache.empty()) {
148 180 // Ask the provider for each data on the dateTimeListNotInCache
149 181 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
150 182 std::move(dateTimeListNotInCache));
151 183 }
152 184 else {
153 185 emit variable->updated();
154 186 }
155 187 }
156 188 else {
157 189 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
158 190 }
159 191 }
160 192
161 193
162 194 void VariableController::initialize()
163 195 {
164 196 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
165 197 impl->m_WorkingMutex.lock();
166 198 qCDebug(LOG_VariableController()) << tr("VariableController init END");
167 199 }
168 200
169 201 void VariableController::finalize()
170 202 {
171 203 impl->m_WorkingMutex.unlock();
172 204 }
173 205
174 206 void VariableController::waitForFinish()
175 207 {
176 208 QMutexLocker locker{&impl->m_WorkingMutex};
177 209 }
@@ -1,153 +1,179
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableModel.h>
3 3
4 4 #include <Data/IDataSeries.h>
5 5
6 6 #include <QDateTime>
7 7 #include <QSize>
8 8
9 9 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
10 10
11 11 namespace {
12 12
13 13 // Column indexes
14 14 const auto NAME_COLUMN = 0;
15 15 const auto TSTART_COLUMN = 1;
16 16 const auto TEND_COLUMN = 2;
17 17 const auto NB_COLUMNS = 3;
18 18
19 19 // Column properties
20 20 const auto DEFAULT_HEIGHT = 25;
21 21 const auto DEFAULT_WIDTH = 100;
22 22
23 23 struct ColumnProperties {
24 24 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
25 25 int height = DEFAULT_HEIGHT)
26 26 : m_Name{name}, m_Width{width}, m_Height{height}
27 27 {
28 28 }
29 29
30 30 QString m_Name;
31 31 int m_Width;
32 32 int m_Height;
33 33 };
34 34
35 35 const auto COLUMN_PROPERTIES
36 36 = QHash<int, ColumnProperties>{{NAME_COLUMN, {QObject::tr("Name")}},
37 37 {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
38 38 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}};
39 39
40 40 /// Format for datetimes
41 41 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
42 42
43 43 } // namespace
44 44
45 45 struct VariableModel::VariableModelPrivate {
46 46 /// Variables created in SciQlop
47 47 std::vector<std::shared_ptr<Variable> > m_Variables;
48 48 };
49 49
50 50 VariableModel::VariableModel(QObject *parent)
51 51 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
52 52 {
53 53 }
54 54
55 55 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
56 56 const SqpDateTime &dateTime) noexcept
57 57 {
58 58 auto insertIndex = rowCount();
59 59 beginInsertRows({}, insertIndex, insertIndex);
60 60
61 61 /// @todo For the moment, the other data of the variable is initialized with default values
62 62 auto variable = std::make_shared<Variable>(name, QStringLiteral("unit"),
63 63 QStringLiteral("mission"), dateTime);
64 64
65 65 impl->m_Variables.push_back(variable);
66 66
67 67 endInsertRows();
68 68
69 69 return variable;
70 70 }
71 71
72 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
73 {
74 if (!variable) {
75 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
76 return;
77 }
78
79 // Finds variable in the model
80 auto begin = impl->m_Variables.cbegin();
81 auto end = impl->m_Variables.cend();
82 auto it = std::find(begin, end, variable);
83 if (it != end) {
84 auto removeIndex = std::distance(begin, it);
85
86 // Deletes variable
87 beginRemoveRows({}, removeIndex, removeIndex);
88 impl->m_Variables.erase(it);
89 endRemoveRows();
90 }
91 else {
92 qCritical(LOG_VariableModel())
93 << tr("Can't delete variable %1 from the model: the variable is not in the model")
94 .arg(variable->name());
95 }
96 }
97
72 98 std::shared_ptr<Variable> VariableModel::variable(int index) const
73 99 {
74 100 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
75 101 }
76 102
77 103 int VariableModel::columnCount(const QModelIndex &parent) const
78 104 {
79 105 Q_UNUSED(parent);
80 106
81 107 return NB_COLUMNS;
82 108 }
83 109
84 110 int VariableModel::rowCount(const QModelIndex &parent) const
85 111 {
86 112 Q_UNUSED(parent);
87 113
88 114 return impl->m_Variables.size();
89 115 }
90 116
91 117 QVariant VariableModel::data(const QModelIndex &index, int role) const
92 118 {
93 119 if (!index.isValid()) {
94 120 return QVariant{};
95 121 }
96 122
97 123 if (index.row() < 0 || index.row() >= rowCount()) {
98 124 return QVariant{};
99 125 }
100 126
101 127 if (role == Qt::DisplayRole) {
102 128 if (auto variable = impl->m_Variables.at(index.row()).get()) {
103 129 /// Lambda function that builds the variant to return for a time value
104 130 auto dateTimeVariant = [](double time) {
105 131 auto dateTime = QDateTime::fromMSecsSinceEpoch(time * 1000.);
106 132 return dateTime.toString(DATETIME_FORMAT);
107 133 };
108 134
109 135 switch (index.column()) {
110 136 case NAME_COLUMN:
111 137 return variable->name();
112 138 case TSTART_COLUMN:
113 139 return dateTimeVariant(variable->dateTime().m_TStart);
114 140 case TEND_COLUMN:
115 141 return dateTimeVariant(variable->dateTime().m_TEnd);
116 142 default:
117 143 // No action
118 144 break;
119 145 }
120 146
121 147 qWarning(LOG_VariableModel())
122 148 << tr("Can't get data (unknown column %1)").arg(index.column());
123 149 }
124 150 else {
125 151 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
126 152 }
127 153 }
128 154
129 155 return QVariant{};
130 156 }
131 157
132 158 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
133 159 {
134 160 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
135 161 return QVariant{};
136 162 }
137 163
138 164 if (orientation == Qt::Horizontal) {
139 165 auto propertiesIt = COLUMN_PROPERTIES.find(section);
140 166 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
141 167 // Role is either DisplayRole or SizeHintRole
142 168 return (role == Qt::DisplayRole)
143 169 ? QVariant{propertiesIt->m_Name}
144 170 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
145 171 }
146 172 else {
147 173 qWarning(LOG_VariableModel())
148 174 << tr("Can't get header data (unknown column %1)").arg(section);
149 175 }
150 176 }
151 177
152 178 return QVariant{};
153 179 }
@@ -1,19 +1,22
1 1 #ifndef SCIQLOP_IVARIABLECONTAINER_H
2 2 #define SCIQLOP_IVARIABLECONTAINER_H
3 3
4 4 class Variable;
5 5
6 6 /**
7 7 * @brief The IVariableContainer interface represents an UI object that can accommodate a variable
8 8 */
9 9 class IVariableContainer {
10 10
11 11 public:
12 12 virtual ~IVariableContainer() = default;
13 13
14 14 /// Checks if the container can handle the variable passed in parameter
15 15 virtual bool canDrop(const Variable &variable) const = 0;
16
17 /// Checks if the container contains the variable passed in parameter
18 virtual bool contains(const Variable &variable) const = 0;
16 19 };
17 20
18 21
19 22 #endif // SCIQLOP_IVARIABLECONTAINER_H
@@ -1,64 +1,65
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 14
15 15 class QCPRange;
16 16 class SqpDateTime;
17 17 class Variable;
18 18
19 19 namespace Ui {
20 20 class VisualizationGraphWidget;
21 21 } // namespace Ui
22 22
23 23 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
24 24 Q_OBJECT
25 25
26 26 public:
27 27 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
28 28 virtual ~VisualizationGraphWidget();
29 29
30 30 void addVariable(std::shared_ptr<Variable> variable);
31 31 void addVariableUsingGraph(std::shared_ptr<Variable> variable);
32 32 /// Removes a variable from the graph
33 33 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
34 34
35 35 // IVisualizationWidget interface
36 36 void accept(IVisualizationWidgetVisitor *visitor) override;
37 37 bool canDrop(const Variable &variable) const override;
38 bool contains(const Variable &variable) const override;
38 39 QString name() const override;
39 40
40 41 void updateDisplay(std::shared_ptr<Variable> variable);
41 42
42 43 signals:
43 44 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
44 45
45 46
46 47 private:
47 48 Ui::VisualizationGraphWidget *ui;
48 49
49 50 class VisualizationGraphWidgetPrivate;
50 51 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
51 52
52 53 private slots:
53 54 /// Slot called when right clicking on the graph (displays a menu)
54 55 void onGraphMenuRequested(const QPoint &pos) noexcept;
55 56
56 57 void onRangeChanged(const QCPRange &t1);
57 58
58 59 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
59 60 void onMouseWheel(QWheelEvent *event) noexcept;
60 61
61 62 void onDataCacheVariableUpdated();
62 63 };
63 64
64 65 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,53 +1,54
1 1 #ifndef SCIQLOP_VISUALIZATIONTABWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONTABWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <Common/spimpl.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QWidget>
10 10
11 11 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationTabWidget)
12 12
13 13 class Variable;
14 14 class VisualizationZoneWidget;
15 15
16 16 namespace Ui {
17 17 class VisualizationTabWidget;
18 18 } // namespace Ui
19 19
20 20 class VisualizationTabWidget : public QWidget, public IVisualizationWidget {
21 21 Q_OBJECT
22 22
23 23 public:
24 24 explicit VisualizationTabWidget(const QString &name = {}, QWidget *parent = 0);
25 25 virtual ~VisualizationTabWidget();
26 26
27 27 /// Add a zone widget
28 28 void addZone(VisualizationZoneWidget *zoneWidget);
29 29
30 30 /**
31 31 * Creates a zone using a variable. The variable will be displayed in a new graph of the new
32 32 * zone.
33 33 * @param variable the variable for which to create the zone
34 34 * @return the pointer to the created zone
35 35 */
36 36 VisualizationZoneWidget *createZone(std::shared_ptr<Variable> variable);
37 37
38 38 // IVisualizationWidget interface
39 39 void accept(IVisualizationWidgetVisitor *visitor) override;
40 40 bool canDrop(const Variable &variable) const override;
41 bool contains(const Variable &variable) const override;
41 42 QString name() const override;
42 43
43 44 private:
44 45 /// @return the layout of tab in which zones are added
45 46 QLayout &tabLayout() const noexcept;
46 47
47 48 Ui::VisualizationTabWidget *ui;
48 49
49 50 class VisualizationTabWidgetPrivate;
50 51 spimpl::unique_impl_ptr<VisualizationTabWidgetPrivate> impl;
51 52 };
52 53
53 54 #endif // SCIQLOP_VISUALIZATIONTABWIDGET_H
@@ -1,44 +1,48
1 1 #ifndef SCIQLOP_VISUALIZATIONWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
10 10
11 11 class QMenu;
12 12 class Variable;
13 13 class VisualizationTabWidget;
14 14
15 15 namespace Ui {
16 16 class VisualizationWidget;
17 17 } // namespace Ui
18 18
19 19 class VisualizationWidget : public QWidget, public IVisualizationWidget {
20 20 Q_OBJECT
21 21
22 22 public:
23 23 explicit VisualizationWidget(QWidget *parent = 0);
24 24 virtual ~VisualizationWidget();
25 25
26 26 // IVisualizationWidget interface
27 27 void accept(IVisualizationWidgetVisitor *visitor) override;
28 28 bool canDrop(const Variable &variable) const override;
29 bool contains(const Variable &variable) const override;
29 30 QString name() const override;
30 31
31 32 public slots:
32 33 /**
33 34 * Attaches to a menu the menu relative to the visualization of variables
34 35 * @param menu the parent menu of the generated menu
35 36 * @param variables the variables for which to generate the menu
36 37 */
37 38 void attachVariableMenu(QMenu *menu,
38 39 const QVector<std::shared_ptr<Variable> > &variables) noexcept;
39 40
41 /// Slot called when a variable is about to be deleted from SciQlop
42 void onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept;
43
40 44 private:
41 45 Ui::VisualizationWidget *ui;
42 46 };
43 47
44 48 #endif // VISUALIZATIONWIDGET_H
@@ -1,44 +1,45
1 1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
10 10
11 11 namespace Ui {
12 12 class VisualizationZoneWidget;
13 13 } // Ui
14 14
15 15 class Variable;
16 16 class VisualizationGraphWidget;
17 17
18 18 class VisualizationZoneWidget : public QWidget, public IVisualizationWidget {
19 19 Q_OBJECT
20 20
21 21 public:
22 22 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
23 23 virtual ~VisualizationZoneWidget();
24 24
25 25 /// Add a graph widget
26 26 void addGraph(VisualizationGraphWidget *graphWidget);
27 27
28 28 /**
29 29 * Creates a graph using a variable. The variable will be displayed in the new graph.
30 30 * @param variable the variable for which to create the graph
31 31 * @return the pointer to the created graph
32 32 */
33 33 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
34 34
35 35 // IVisualizationWidget interface
36 36 void accept(IVisualizationWidgetVisitor *visitor) override;
37 37 bool canDrop(const Variable &variable) const override;
38 bool contains(const Variable &variable) const override;
38 39 QString name() const override;
39 40
40 41 private:
41 42 Ui::VisualizationZoneWidget *ui;
42 43 };
43 44
44 45 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,59 +1,60
1 1 #ifndef SCIQLOP_MENUBUILDER_H
2 2 #define SCIQLOP_MENUBUILDER_H
3 3
4 4 #include <QLoggingCategory>
5 5 #include <QMenu>
6 6 #include <QStack>
7 7
8 8 Q_DECLARE_LOGGING_CATEGORY(LOG_MenuBuilder)
9 9
10 10 /// Helper assigned to build a hierarchical menu
11 11 class MenuBuilder {
12 12 public:
13 13 /**
14 14 * Ctor
15 15 * @param menu the parent menu
16 16 */
17 17 explicit MenuBuilder(QMenu *menu);
18 18
19 19 /**
20 20 * Adds action to the current menu
21 21 * @param actionName the name of the action
22 22 * @param actionFunction the function that will be executed when the action is triggered
23 23 */
24 24 template <typename ActionFun>
25 25 void addAction(const QString &actionName, ActionFun actionFunction);
26 26
27 27 /**
28 28 * Adds a new menu to the current menu
29 29 * @param name the name of the menu
30 * @param icon the icon of the menu (can be null)
30 31 */
31 void addMenu(const QString &name);
32 void addMenu(const QString &name, const QIcon &icon = {});
32 33
33 34 /// Adds a separator to the current menu. The separator is added only if the menu already
34 35 /// contains entries
35 36 void addSeparator();
36 37
37 38 /// Closes the current menu
38 39 void closeMenu();
39 40
40 41 private:
41 42 /// @return the current menu (i.e. the top menu of the stack), nullptr if there is no menu
42 43 QMenu *currentMenu() const;
43 44
44 45 /// Stack of all menus currently opened
45 46 QStack<QMenu *> m_Menus{};
46 47 };
47 48
48 49 template <typename ActionFun>
49 50 void MenuBuilder::addAction(const QString &actionName, ActionFun actionFunction)
50 51 {
51 52 if (auto currMenu = currentMenu()) {
52 53 currMenu->addAction(actionName, actionFunction);
53 54 }
54 55 else {
55 56 qCCritical(LOG_MenuBuilder()) << QObject::tr("No current menu to attach the action");
56 57 }
57 58 }
58 59
59 60 #endif // SCIQLOP_MENUBUILDER_H
@@ -1,8 +1,10
1 1 <RCC>
2 2 <qresource prefix="/">
3 3 <file>icones/delete.png</file>
4 4 <file>icones/openInspector.png</file>
5 5 <file>icones/next.png</file>
6 <file>icones/plot.png</file>
6 7 <file>icones/previous.png</file>
8 <file>icones/unplot.png</file>
7 9 </qresource>
8 10 </RCC>
@@ -1,118 +1,122
1 1 #include "SqpApplication.h"
2 2
3 3 #include <Data/IDataProvider.h>
4 4 #include <DataSource/DataSourceController.h>
5 5 #include <QThread>
6 6 #include <Time/TimeController.h>
7 7 #include <Variable/Variable.h>
8 8 #include <Variable/VariableController.h>
9 9 #include <Visualization/VisualizationController.h>
10 10
11 11 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
12 12
13 13 class SqpApplication::SqpApplicationPrivate {
14 14 public:
15 15 SqpApplicationPrivate()
16 16 : m_DataSourceController{std::make_unique<DataSourceController>()},
17 17 m_TimeController{std::make_unique<TimeController>()},
18 18 m_VariableController{std::make_unique<VariableController>()},
19 19 m_VisualizationController{std::make_unique<VisualizationController>()}
20 20 {
21 21 // /////////////////////////////// //
22 22 // Connections between controllers //
23 23 // /////////////////////////////// //
24 24
25 25 // VariableController <-> DataSourceController
26 26 connect(m_DataSourceController.get(),
27 27 SIGNAL(variableCreationRequested(const QString &, std::shared_ptr<IDataProvider>)),
28 28 m_VariableController.get(),
29 29 SLOT(createVariable(const QString &, std::shared_ptr<IDataProvider>)));
30 30
31 31 // VariableController <-> VisualizationController
32 32 connect(m_VariableController.get(), SIGNAL(variableCreated(std::shared_ptr<Variable>)),
33 33 m_VisualizationController.get(),
34 34 SIGNAL(variableCreated(std::shared_ptr<Variable>)));
35 connect(m_VariableController.get(),
36 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
37 m_VisualizationController.get(),
38 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
35 39
36 40 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
37 41 m_VariableController->moveToThread(&m_VariableControllerThread);
38 42 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
39 43
40 44 // Additionnal init
41 45 m_VariableController->setTimeController(m_TimeController.get());
42 46 }
43 47
44 48 virtual ~SqpApplicationPrivate()
45 49 {
46 50 qCInfo(LOG_SqpApplication()) << tr("SqpApplicationPrivate destruction");
47 51 m_DataSourceControllerThread.quit();
48 52 m_DataSourceControllerThread.wait();
49 53
50 54 m_VariableControllerThread.quit();
51 55 m_VariableControllerThread.wait();
52 56
53 57 m_VisualizationControllerThread.quit();
54 58 m_VisualizationControllerThread.wait();
55 59 }
56 60
57 61 std::unique_ptr<DataSourceController> m_DataSourceController;
58 62 std::unique_ptr<VariableController> m_VariableController;
59 63 std::unique_ptr<TimeController> m_TimeController;
60 64 std::unique_ptr<VisualizationController> m_VisualizationController;
61 65 QThread m_DataSourceControllerThread;
62 66 QThread m_VariableControllerThread;
63 67 QThread m_VisualizationControllerThread;
64 68 };
65 69
66 70
67 71 SqpApplication::SqpApplication(int &argc, char **argv)
68 72 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
69 73 {
70 74 qCInfo(LOG_SqpApplication()) << tr("SqpApplication construction");
71 75
72 76 connect(&impl->m_DataSourceControllerThread, &QThread::started,
73 77 impl->m_DataSourceController.get(), &DataSourceController::initialize);
74 78 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
75 79 impl->m_DataSourceController.get(), &DataSourceController::finalize);
76 80
77 81 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
78 82 &VariableController::initialize);
79 83 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
80 84 &VariableController::finalize);
81 85
82 86 connect(&impl->m_VisualizationControllerThread, &QThread::started,
83 87 impl->m_VisualizationController.get(), &VisualizationController::initialize);
84 88 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
85 89 impl->m_VisualizationController.get(), &VisualizationController::finalize);
86 90
87 91 impl->m_DataSourceControllerThread.start();
88 92 impl->m_VariableControllerThread.start();
89 93 impl->m_VisualizationControllerThread.start();
90 94 }
91 95
92 96 SqpApplication::~SqpApplication()
93 97 {
94 98 }
95 99
96 100 void SqpApplication::initialize()
97 101 {
98 102 }
99 103
100 104 DataSourceController &SqpApplication::dataSourceController() noexcept
101 105 {
102 106 return *impl->m_DataSourceController;
103 107 }
104 108
105 109 TimeController &SqpApplication::timeController() noexcept
106 110 {
107 111 return *impl->m_TimeController;
108 112 }
109 113
110 114 VariableController &SqpApplication::variableController() noexcept
111 115 {
112 116 return *impl->m_VariableController;
113 117 }
114 118
115 119 VisualizationController &SqpApplication::visualizationController() noexcept
116 120 {
117 121 return *impl->m_VisualizationController;
118 122 }
@@ -1,89 +1,89
1 1 #include <Variable/VariableController.h>
2 2 #include <Variable/VariableInspectorWidget.h>
3 3 #include <Variable/VariableMenuHeaderWidget.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <ui_VariableInspectorWidget.h>
7 7
8 8 #include <QSortFilterProxyModel>
9 9 #include <QWidgetAction>
10 10
11 11 #include <SqpApplication.h>
12 12
13 13 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
14 14
15 15 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
16 16 : QWidget{parent}, ui{new Ui::VariableInspectorWidget}
17 17 {
18 18 ui->setupUi(this);
19 19
20 20 // Sets model for table
21 21 // auto sortFilterModel = new QSortFilterProxyModel{this};
22 22 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
23 23
24 24 ui->tableView->setModel(sqpApp->variableController().variableModel());
25 25 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
26 26
27 27 // Fixes column sizes
28 28 auto model = ui->tableView->model();
29 29 const auto count = model->columnCount();
30 30 for (auto i = 0; i < count; ++i) {
31 31 ui->tableView->setColumnWidth(
32 32 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
33 33 }
34 34
35 35 // Sets selection options
36 36 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
37 37 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
38 38
39 39 // Connection to show a menu when right clicking on the tree
40 40 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
41 41 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
42 42 &VariableInspectorWidget::onTableMenuRequested);
43 43 }
44 44
45 45 VariableInspectorWidget::~VariableInspectorWidget()
46 46 {
47 47 delete ui;
48 48 }
49 49
50 50 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
51 51 {
52 52 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
53 53
54 54 // Gets the model to retrieve the underlying selected variables
55 55 auto model = sqpApp->variableController().variableModel();
56 56 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
57 57 for (const auto &selectedRow : qAsConst(selectedRows)) {
58 58 if (auto selectedVariable = model->variable(selectedRow.row())) {
59 59 selectedVariables.push_back(selectedVariable);
60 60 }
61 61 }
62 62
63 63 QMenu tableMenu{};
64 64
65 65 // Emits a signal so that potential receivers can populate the menu before displaying it
66 66 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
67 67
68 68 // Adds menu-specific actions
69 69 if (!selectedVariables.isEmpty()) {
70 70 // 'Delete' action
71 auto deleteFun = []() {
72 /// @todo ALX : call variable deletion
71 auto deleteFun = [&selectedVariables]() {
72 sqpApp->variableController().deleteVariables(selectedVariables);
73 73 };
74 74
75 75 tableMenu.addSeparator();
76 76 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
77 77 }
78 78
79 79 if (!tableMenu.isEmpty()) {
80 80 // Generates menu header (inserted before first action)
81 81 auto firstAction = tableMenu.actions().first();
82 82 auto headerAction = new QWidgetAction{&tableMenu};
83 83 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
84 84 tableMenu.insertAction(firstAction, headerAction);
85 85
86 86 // Displays menu
87 87 tableMenu.exec(mapToGlobal(pos));
88 88 }
89 89 }
@@ -1,273 +1,285
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphHelper.h"
4 4 #include "ui_VisualizationGraphWidget.h"
5 5
6 6 #include <Data/ArrayData.h>
7 7 #include <Data/IDataSeries.h>
8 8 #include <SqpApplication.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <unordered_map>
13 13
14 14 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
15 15
16 16 namespace {
17 17
18 18 /// Key pressed to enable zoom on horizontal axis
19 19 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
20 20
21 21 /// Key pressed to enable zoom on vertical axis
22 22 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
23 23
24 24 } // namespace
25 25
26 26 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
27 27
28 28 // 1 variable -> n qcpplot
29 29 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
30 30 };
31 31
32 32 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
33 33 : QWidget{parent},
34 34 ui{new Ui::VisualizationGraphWidget},
35 35 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
36 36 {
37 37 ui->setupUi(this);
38 38
39 39 ui->graphNameLabel->setText(name);
40 40
41 41 // 'Close' options : widget is deleted when closed
42 42 setAttribute(Qt::WA_DeleteOnClose);
43 43 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
44 44 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
45 45
46 46 // Set qcpplot properties :
47 47 // - Drag (on x-axis) and zoom are enabled
48 48 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
49 49 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
50 50 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
51 51 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
52 52 connect(ui->widget->xAxis,
53 53 static_cast<void (QCPAxis::*)(const QCPRange &)>(&QCPAxis::rangeChanged), this,
54 54 &VisualizationGraphWidget::onRangeChanged);
55 55
56 56 // Activates menu when right clicking on the graph
57 57 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
58 58 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
59 59 &VisualizationGraphWidget::onGraphMenuRequested);
60 60
61 61 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
62 62 &VariableController::onRequestDataLoading);
63 63 }
64 64
65 65
66 66 VisualizationGraphWidget::~VisualizationGraphWidget()
67 67 {
68 68 delete ui;
69 69 }
70 70
71 71 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
72 72 {
73 73 // Uses delegate to create the qcpplot components according to the variable
74 74 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
75 75
76 76 for (auto createdPlottable : qAsConst(createdPlottables)) {
77 77 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
78 78 }
79 79
80 80 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
81 81 }
82 82
83 83 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
84 84 {
85 85
86 86 // when adding a variable, we need to set its time range to the current graph range
87 87 auto grapheRange = ui->widget->xAxis->range();
88 88 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
89 89 variable->setDateTime(dateTime);
90 90
91 91 auto variableDateTimeWithTolerance = dateTime;
92 92
93 93 // add 10% tolerance for each side
94 94 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
95 95 variableDateTimeWithTolerance.m_TStart -= tolerance;
96 96 variableDateTimeWithTolerance.m_TEnd += tolerance;
97 97
98 98 // Uses delegate to create the qcpplot components according to the variable
99 99 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
100 100
101 101 for (auto createdPlottable : qAsConst(createdPlottables)) {
102 102 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
103 103 }
104 104
105 105 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
106 106
107 107 // CHangement detected, we need to ask controller to request data loading
108 108 emit requestDataLoading(variable, variableDateTimeWithTolerance);
109 109 }
110 110
111 111 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
112 112 {
113 113 // Each component associated to the variable :
114 114 // - is removed from qcpplot (which deletes it)
115 115 // - is no longer referenced in the map
116 116 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
117 117 for (auto it = componentsIt.first; it != componentsIt.second;) {
118 118 ui->widget->removePlottable(it->second);
119 119 it = impl->m_VariableToPlotMultiMap.erase(it);
120 120 }
121 121
122 122 // Updates graph
123 123 ui->widget->replot();
124 124 }
125 125
126 126 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
127 127 {
128 128 if (visitor) {
129 129 visitor->visit(this);
130 130 }
131 131 else {
132 132 qCCritical(LOG_VisualizationGraphWidget())
133 133 << tr("Can't visit widget : the visitor is null");
134 134 }
135 135 }
136 136
137 137 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
138 138 {
139 139 /// @todo : for the moment, a graph can always accomodate a variable
140 140 Q_UNUSED(variable);
141 141 return true;
142 142 }
143 143
144 bool VisualizationGraphWidget::contains(const Variable &variable) const
145 {
146 // Finds the variable among the keys of the map
147 auto variablePtr = &variable;
148 auto findVariable
149 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
150
151 auto end = impl->m_VariableToPlotMultiMap.cend();
152 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
153 return it != end;
154 }
155
144 156 QString VisualizationGraphWidget::name() const
145 157 {
146 158 return ui->graphNameLabel->text();
147 159 }
148 160
149 161 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
150 162 {
151 163 QMenu graphMenu{};
152 164
153 165 // Iterates on variables (unique keys)
154 166 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
155 167 end = impl->m_VariableToPlotMultiMap.cend();
156 168 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
157 169 // 'Remove variable' action
158 170 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
159 171 [ this, var = it->first ]() { removeVariable(var); });
160 172 }
161 173
162 174 if (!graphMenu.isEmpty()) {
163 175 graphMenu.exec(mapToGlobal(pos));
164 176 }
165 177 }
166 178
167 179 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1)
168 180 {
169 181 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged");
170 182
171 183 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
172 184 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
173 185
174 186 auto variable = it->first;
175 187 auto dateTime = SqpDateTime{t1.lower, t1.upper};
176 188
177 189 if (!variable->contains(dateTime)) {
178 190
179 191 auto variableDateTimeWithTolerance = dateTime;
180 192 if (!variable->isInside(dateTime)) {
181 193 auto variableDateTime = variable->dateTime();
182 194 if (variableDateTime.m_TStart < dateTime.m_TStart) {
183 195 qCDebug(LOG_VisualizationGraphWidget()) << tr("TDetection pan to right:");
184 196
185 197 auto diffEndToKeepDelta = dateTime.m_TEnd - variableDateTime.m_TEnd;
186 198 dateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
187 199 // Tolerance have to be added to the right
188 200 // add 10% tolerance for right (end) side
189 201 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
190 202 variableDateTimeWithTolerance.m_TEnd += tolerance;
191 203 }
192 204 else if (variableDateTime.m_TEnd > dateTime.m_TEnd) {
193 205 qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection pan to left: ");
194 206 auto diffStartToKeepDelta = variableDateTime.m_TStart - dateTime.m_TStart;
195 207 dateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
196 208 // Tolerance have to be added to the left
197 209 // add 10% tolerance for left (start) side
198 210 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
199 211 variableDateTimeWithTolerance.m_TStart -= tolerance;
200 212 }
201 213 else {
202 214 qCWarning(LOG_VisualizationGraphWidget())
203 215 << tr("Detection anormal zoom detection: ");
204 216 }
205 217 }
206 218 else {
207 219 qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection zoom out: ");
208 220 // add 10% tolerance for each side
209 221 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
210 222 variableDateTimeWithTolerance.m_TStart -= tolerance;
211 223 variableDateTimeWithTolerance.m_TEnd += tolerance;
212 224 }
213 225 variable->setDateTime(dateTime);
214 226
215 227 // CHangement detected, we need to ask controller to request data loading
216 228 emit requestDataLoading(variable, variableDateTimeWithTolerance);
217 229 }
218 230 else {
219 231 qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection zoom in: ");
220 232 }
221 233 }
222 234 }
223 235
224 236 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
225 237 {
226 238 auto zoomOrientations = QFlags<Qt::Orientation>{};
227 239
228 240 // Lambda that enables a zoom orientation if the key modifier related to this orientation
229 241 // has
230 242 // been pressed
231 243 auto enableOrientation
232 244 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
233 245 auto orientationEnabled = event->modifiers().testFlag(modifier);
234 246 zoomOrientations.setFlag(orientation, orientationEnabled);
235 247 };
236 248 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
237 249 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
238 250
239 251 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
240 252 }
241 253
242 254 void VisualizationGraphWidget::onDataCacheVariableUpdated()
243 255 {
244 256 // NOTE:
245 257 // We don't want to call the method for each component of a variable unitarily, but for
246 258 // all
247 259 // its components at once (eg its three components in the case of a vector).
248 260
249 261 // The unordered_multimap does not do this easily, so the question is whether to:
250 262 // - use an ordered_multimap and the algos of std to group the values by key
251 263 // - use a map (unique keys) and store as values directly the list of components
252 264
253 265 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
254 266 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
255 267 auto variable = it->first;
256 268 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
257 269 variable->dataSeries(), variable->dateTime());
258 270 }
259 271 }
260 272
261 273 void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable)
262 274 {
263 275 auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable);
264 276
265 277 auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{};
266 278
267 279 for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) {
268 280 abstractPlotableVect.push_back(it->second);
269 281 }
270 282
271 283 VisualizationGraphHelper::updateData(abstractPlotableVect, variable->dataSeries(),
272 284 variable->dateTime());
273 285 }
@@ -1,104 +1,110
1 1 #include "Visualization/VisualizationTabWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "ui_VisualizationTabWidget.h"
4 4
5 5 #include "Visualization/VisualizationZoneWidget.h"
6 6
7 7 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
8 8
9 9 namespace {
10 10
11 11 /// Generates a default name for a new zone, according to the number of zones already displayed in
12 12 /// the tab
13 13 QString defaultZoneName(const QLayout &layout)
14 14 {
15 15 auto count = 0;
16 16 for (auto i = 0; i < layout.count(); ++i) {
17 17 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
18 18 count++;
19 19 }
20 20 }
21 21
22 22 return QObject::tr("Zone %1").arg(count + 1);
23 23 }
24 24
25 25 } // namespace
26 26
27 27 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
28 28 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
29 29
30 30 QString m_Name;
31 31 };
32 32
33 33 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
34 34 : QWidget{parent},
35 35 ui{new Ui::VisualizationTabWidget},
36 36 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
37 37 {
38 38 ui->setupUi(this);
39 39
40 40 // Widget is deleted when closed
41 41 setAttribute(Qt::WA_DeleteOnClose);
42 42 }
43 43
44 44 VisualizationTabWidget::~VisualizationTabWidget()
45 45 {
46 46 delete ui;
47 47 }
48 48
49 49 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
50 50 {
51 51 tabLayout().addWidget(zoneWidget);
52 52 }
53 53
54 54 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
55 55 {
56 56 auto zoneWidget = new VisualizationZoneWidget{defaultZoneName(tabLayout()), this};
57 57 this->addZone(zoneWidget);
58 58
59 59 // Creates a new graph into the zone
60 60 zoneWidget->createGraph(variable);
61 61
62 62 return zoneWidget;
63 63 }
64 64
65 65 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
66 66 {
67 67 if (visitor) {
68 68 visitor->visitEnter(this);
69 69
70 70 // Apply visitor to zone children
71 71 auto &layout = tabLayout();
72 72 for (auto i = 0; i < layout.count(); ++i) {
73 73 if (auto item = layout.itemAt(i)) {
74 74 // Widgets different from zones are not visited (no action)
75 75 if (auto visualizationZoneWidget
76 76 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
77 77 visualizationZoneWidget->accept(visitor);
78 78 }
79 79 }
80 80 }
81 81
82 82 visitor->visitLeave(this);
83 83 }
84 84 else {
85 85 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
86 86 }
87 87 }
88 88
89 89 bool VisualizationTabWidget::canDrop(const Variable &variable) const
90 90 {
91 91 // A tab can always accomodate a variable
92 92 Q_UNUSED(variable);
93 93 return true;
94 94 }
95 95
96 bool VisualizationTabWidget::contains(const Variable &variable) const
97 {
98 Q_UNUSED(variable);
99 return false;
100 }
101
96 102 QString VisualizationTabWidget::name() const
97 103 {
98 104 return impl->m_Name;
99 105 }
100 106
101 107 QLayout &VisualizationTabWidget::tabLayout() const noexcept
102 108 {
103 109 return *ui->scrollAreaWidgetContents->layout();
104 110 }
@@ -1,129 +1,143
1 1 #include "Visualization/VisualizationWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphWidget.h"
4 4 #include "Visualization/VisualizationTabWidget.h"
5 5 #include "Visualization/VisualizationZoneWidget.h"
6 6 #include "Visualization/operations/GenerateVariableMenuOperation.h"
7 #include "Visualization/operations/RemoveVariableOperation.h"
7 8 #include "Visualization/qcustomplot.h"
8 9
9 10 #include "ui_VisualizationWidget.h"
10 11
11 12 #include <QToolButton>
12 13
13 14 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
14 15
15 16 VisualizationWidget::VisualizationWidget(QWidget *parent)
16 17 : QWidget{parent}, ui{new Ui::VisualizationWidget}
17 18 {
18 19 ui->setupUi(this);
19 20
20 21 auto addTabViewButton = new QToolButton{ui->tabWidget};
21 22 addTabViewButton->setText(tr("Add View"));
22 23 addTabViewButton->setCursor(Qt::ArrowCursor);
23 24 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
24 25
25 26 auto enableMinimumCornerWidgetSize = [this](bool enable) {
26 27
27 28 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
28 29 auto width = enable ? tabViewCornerWidget->width() : 0;
29 30 auto height = enable ? tabViewCornerWidget->height() : 0;
30 31 tabViewCornerWidget->setMinimumHeight(height);
31 32 tabViewCornerWidget->setMinimumWidth(width);
32 33 ui->tabWidget->setMinimumHeight(height);
33 34 ui->tabWidget->setMinimumWidth(width);
34 35 };
35 36
36 37 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
37 38 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
38 39 ui->tabWidget};
39 40 auto index = ui->tabWidget->addTab(widget, widget->name());
40 41 if (ui->tabWidget->count() > 0) {
41 42 enableMinimumCornerWidgetSize(false);
42 43 }
43 44 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
44 45 };
45 46
46 47 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
47 48 if (ui->tabWidget->count() == 1) {
48 49 enableMinimumCornerWidgetSize(true);
49 50 }
50 51
51 52 // Removes widget from tab and closes it
52 53 auto widget = ui->tabWidget->widget(index);
53 54 ui->tabWidget->removeTab(index);
54 55 if (widget) {
55 56 widget->close();
56 57 }
57 58
58 59 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
59 60
60 61 };
61 62
62 63 ui->tabWidget->setTabsClosable(true);
63 64
64 65 connect(addTabViewButton, &QToolButton::clicked, addTabView);
65 66 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
66 67
67 68 // Adds default tab
68 69 addTabView();
69 70 }
70 71
71 72 VisualizationWidget::~VisualizationWidget()
72 73 {
73 74 delete ui;
74 75 }
75 76
76 77 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
77 78 {
78 79 if (visitor) {
79 80 visitor->visitEnter(this);
80 81
81 82 // Apply visitor for tab children
82 83 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
83 84 // Widgets different from tabs are not visited (no action)
84 85 if (auto visualizationTabWidget
85 86 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
86 87 visualizationTabWidget->accept(visitor);
87 88 }
88 89 }
89 90
90 91 visitor->visitLeave(this);
91 92 }
92 93 else {
93 94 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
94 95 }
95 96 }
96 97
97 98 bool VisualizationWidget::canDrop(const Variable &variable) const
98 99 {
99 100 // The main widget can never accomodate a variable
100 101 Q_UNUSED(variable);
101 102 return false;
102 103 }
103 104
105 bool VisualizationWidget::contains(const Variable &variable) const
106 {
107 Q_UNUSED(variable);
108 return false;
109 }
110
104 111 QString VisualizationWidget::name() const
105 112 {
106 113 return QStringLiteral("MainView");
107 114 }
108 115
109 116 void VisualizationWidget::attachVariableMenu(
110 117 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
111 118 {
112 119 // Menu is generated only if there is a single variable
113 120 if (variables.size() == 1) {
114 121 if (auto variable = variables.first()) {
115 122 // Generates the actions that make it possible to visualize the variable
116 123 auto generateVariableMenuOperation = GenerateVariableMenuOperation{menu, variable};
117 124 accept(&generateVariableMenuOperation);
118 125 }
119 126 else {
120 127 qCCritical(LOG_VisualizationWidget()) << tr(
121 128 "Can't generate the menu relative to the visualization: the variable is null");
122 129 }
123 130 }
124 131 else {
125 132 qCDebug(LOG_VisualizationWidget())
126 133 << tr("No generation of the menu related to the visualization: several variables are "
127 134 "selected");
128 135 }
129 136 }
137
138 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
139 {
140 // Calls the operation of removing all references to the variable in the visualization
141 auto removeVariableOperation = RemoveVariableOperation{variable};
142 accept(&removeVariableOperation);
143 }
@@ -1,105 +1,111
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "ui_VisualizationZoneWidget.h"
4 4
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6
7 7 #include <SqpApplication.h>
8 8
9 9 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
10 10
11 11 namespace {
12 12
13 13 /// Minimum height for graph added in zones (in pixels)
14 14 const auto GRAPH_MINIMUM_HEIGHT = 300;
15 15
16 16 /// Generates a default name for a new graph, according to the number of graphs already displayed in
17 17 /// the zone
18 18 QString defaultGraphName(const QLayout &layout)
19 19 {
20 20 auto count = 0;
21 21 for (auto i = 0; i < layout.count(); ++i) {
22 22 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
23 23 count++;
24 24 }
25 25 }
26 26
27 27 return QObject::tr("Graph %1").arg(count + 1);
28 28 }
29 29
30 30 } // namespace
31 31
32 32 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
33 33 : QWidget{parent}, ui{new Ui::VisualizationZoneWidget}
34 34 {
35 35 ui->setupUi(this);
36 36
37 37 ui->zoneNameLabel->setText(name);
38 38
39 39 // 'Close' options : widget is deleted when closed
40 40 setAttribute(Qt::WA_DeleteOnClose);
41 41 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
42 42 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
43 43 }
44 44
45 45 VisualizationZoneWidget::~VisualizationZoneWidget()
46 46 {
47 47 delete ui;
48 48 }
49 49
50 50 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
51 51 {
52 52 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
53 53 }
54 54
55 55 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
56 56 {
57 57 auto graphWidget = new VisualizationGraphWidget{
58 58 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
59 59
60 60 // Set graph properties
61 61 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
62 62 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
63 63
64 64 this->addGraph(graphWidget);
65 65
66 66 graphWidget->addVariable(variable);
67 67
68 68 return graphWidget;
69 69 }
70 70
71 71 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
72 72 {
73 73 if (visitor) {
74 74 visitor->visitEnter(this);
75 75
76 76 // Apply visitor to graph children
77 77 auto layout = ui->visualizationZoneFrame->layout();
78 78 for (auto i = 0; i < layout->count(); ++i) {
79 79 if (auto item = layout->itemAt(i)) {
80 80 // Widgets different from graphs are not visited (no action)
81 81 if (auto visualizationGraphWidget
82 82 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
83 83 visualizationGraphWidget->accept(visitor);
84 84 }
85 85 }
86 86 }
87 87
88 88 visitor->visitLeave(this);
89 89 }
90 90 else {
91 91 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
92 92 }
93 93 }
94 94
95 95 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
96 96 {
97 97 // A tab can always accomodate a variable
98 98 Q_UNUSED(variable);
99 99 return true;
100 100 }
101 101
102 bool VisualizationZoneWidget::contains(const Variable &variable) const
103 {
104 Q_UNUSED(variable);
105 return false;
106 }
107
102 108 QString VisualizationZoneWidget::name() const
103 109 {
104 110 return ui->zoneNameLabel->text();
105 111 }
@@ -1,146 +1,183
1 1 #include "Visualization/operations/GenerateVariableMenuOperation.h"
2 2 #include "Visualization/operations/MenuBuilder.h"
3 3
4 4 #include "Visualization/VisualizationGraphWidget.h"
5 5 #include "Visualization/VisualizationTabWidget.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7
8 8 #include <Variable/Variable.h>
9 9
10 10 #include <QMenu>
11 11 #include <QStack>
12 12
13 13 Q_LOGGING_CATEGORY(LOG_GenerateVariableMenuOperation, "GenerateVariableMenuOperation")
14 14
15 15 struct GenerateVariableMenuOperation::GenerateVariableMenuOperationPrivate {
16 16 explicit GenerateVariableMenuOperationPrivate(QMenu *menu, std::shared_ptr<Variable> variable)
17 : m_Variable{variable}, m_MenuBuilder{menu}
17 : m_Variable{variable}, m_PlotMenuBuilder{menu}, m_UnplotMenuBuilder{menu}
18 18 {
19 19 }
20 20
21 21 void visitRootEnter()
22 22 {
23 23 // Creates the root menu
24 m_MenuBuilder.addMenu(QObject::tr("Plot"));
24 m_PlotMenuBuilder.addMenu(QObject::tr("Plot"), QIcon{":/icones/plot.png"});
25 m_UnplotMenuBuilder.addMenu(QObject::tr("Unplot"), QIcon{":/icones/unplot.png"});
25 26 }
26 27
27 28 void visitRootLeave()
28 29 {
29 30 // Closes the root menu
30 m_MenuBuilder.closeMenu();
31 m_PlotMenuBuilder.closeMenu();
32 m_UnplotMenuBuilder.closeMenu();
31 33 }
32 34
33 35 void visitNodeEnter(const IVisualizationWidget &container)
34 36 {
35 37 // Opens a new menu associated to the node
36 m_MenuBuilder.addMenu(container.name());
38 m_PlotMenuBuilder.addMenu(container.name());
39 m_UnplotMenuBuilder.addMenu(container.name());
37 40 }
38 41
39 42 template <typename ActionFun>
40 void visitNodeLeave(const IVisualizationWidget &container, const QString &actionName,
41 ActionFun actionFunction)
43 void visitNodeLeavePlot(const IVisualizationWidget &container, const QString &actionName,
44 ActionFun actionFunction)
42 45 {
43 46 if (m_Variable && container.canDrop(*m_Variable)) {
44 m_MenuBuilder.addSeparator();
45 m_MenuBuilder.addAction(actionName, actionFunction);
47 m_PlotMenuBuilder.addSeparator();
48 m_PlotMenuBuilder.addAction(actionName, actionFunction);
46 49 }
47 50
48 51 // Closes the menu associated to the node
49 m_MenuBuilder.closeMenu();
52 m_PlotMenuBuilder.closeMenu();
53 }
54
55 void visitNodeLeaveUnplot()
56 {
57 // Closes the menu associated to the node
58 m_UnplotMenuBuilder.closeMenu();
50 59 }
51 60
52 61 template <typename ActionFun>
53 void visitLeaf(const IVisualizationWidget &container, const QString &actionName,
54 ActionFun actionFunction)
62 void visitLeafPlot(const IVisualizationWidget &container, const QString &actionName,
63 ActionFun actionFunction)
55 64 {
56 65 if (m_Variable && container.canDrop(*m_Variable)) {
57 m_MenuBuilder.addAction(actionName, actionFunction);
66 m_PlotMenuBuilder.addAction(actionName, actionFunction);
67 }
68 }
69
70 template <typename ActionFun>
71 void visitLeafUnplot(const IVisualizationWidget &container, const QString &actionName,
72 ActionFun actionFunction)
73 {
74 if (m_Variable && container.contains(*m_Variable)) {
75 m_UnplotMenuBuilder.addAction(actionName, actionFunction);
58 76 }
59 77 }
60 78
61 79 std::shared_ptr<Variable> m_Variable;
62 MenuBuilder m_MenuBuilder;
80 MenuBuilder m_PlotMenuBuilder; ///< Builder for the 'Plot' menu
81 MenuBuilder m_UnplotMenuBuilder; ///< Builder for the 'Unplot' menu
63 82 };
64 83
65 84 GenerateVariableMenuOperation::GenerateVariableMenuOperation(QMenu *menu,
66 85 std::shared_ptr<Variable> variable)
67 86 : impl{spimpl::make_unique_impl<GenerateVariableMenuOperationPrivate>(menu, variable)}
68 87 {
69 88 }
70 89
71 90 void GenerateVariableMenuOperation::visitEnter(VisualizationWidget *widget)
72 91 {
73 92 // VisualizationWidget is not intended to accommodate a variable
74 93 Q_UNUSED(widget)
75 94
95 // 'Plot' and 'Unplot' menus
76 96 impl->visitRootEnter();
77 97 }
78 98
79 99 void GenerateVariableMenuOperation::visitLeave(VisualizationWidget *widget)
80 100 {
81 101 // VisualizationWidget is not intended to accommodate a variable
82 102 Q_UNUSED(widget)
83 103
104 // 'Plot' and 'Unplot' menus
84 105 impl->visitRootLeave();
85 106 }
86 107
87 108 void GenerateVariableMenuOperation::visitEnter(VisualizationTabWidget *tabWidget)
88 109 {
89 110 if (tabWidget) {
111 // 'Plot' and 'Unplot' menus
90 112 impl->visitNodeEnter(*tabWidget);
91 113 }
92 114 else {
93 115 qCCritical(LOG_GenerateVariableMenuOperation(),
94 116 "Can't visit enter VisualizationTabWidget : the widget is null");
95 117 }
96 118 }
97 119
98 120 void GenerateVariableMenuOperation::visitLeave(VisualizationTabWidget *tabWidget)
99 121 {
100 122 if (tabWidget) {
101 impl->visitNodeLeave(
123 // 'Plot' menu
124 impl->visitNodeLeavePlot(
102 125 *tabWidget, QObject::tr("Open in a new zone"),
103 126 [ var = impl->m_Variable, tabWidget ]() { tabWidget->createZone(var); });
127
128 // 'Unplot' menu
129 impl->visitNodeLeaveUnplot();
104 130 }
105 131 else {
106 132 qCCritical(LOG_GenerateVariableMenuOperation(),
107 133 "Can't visit leave VisualizationTabWidget : the widget is null");
108 134 }
109 135 }
110 136
111 137 void GenerateVariableMenuOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
112 138 {
113 139 if (zoneWidget) {
140 // 'Plot' and 'Unplot' menus
114 141 impl->visitNodeEnter(*zoneWidget);
115 142 }
116 143 else {
117 144 qCCritical(LOG_GenerateVariableMenuOperation(),
118 145 "Can't visit enter VisualizationZoneWidget : the widget is null");
119 146 }
120 147 }
121 148
122 149 void GenerateVariableMenuOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
123 150 {
124 151 if (zoneWidget) {
125 impl->visitNodeLeave(
152 // 'Plot' menu
153 impl->visitNodeLeavePlot(
126 154 *zoneWidget, QObject::tr("Open in a new graph"),
127 155 [ var = impl->m_Variable, zoneWidget ]() { zoneWidget->createGraph(var); });
156
157 // 'Unplot' menu
158 impl->visitNodeLeaveUnplot();
128 159 }
129 160 else {
130 161 qCCritical(LOG_GenerateVariableMenuOperation(),
131 162 "Can't visit leave VisualizationZoneWidget : the widget is null");
132 163 }
133 164 }
134 165
135 166 void GenerateVariableMenuOperation::visit(VisualizationGraphWidget *graphWidget)
136 167 {
137 168 if (graphWidget) {
138 impl->visitLeaf(
169 // 'Plot' menu
170 impl->visitLeafPlot(
139 171 *graphWidget, QObject::tr("Open in %1").arg(graphWidget->name()),
140 172 [ var = impl->m_Variable, graphWidget ]() { graphWidget->addVariableUsingGraph(var); });
173
174 // 'Unplot' menu
175 impl->visitLeafUnplot(
176 *graphWidget, QObject::tr("Remove from %1").arg(graphWidget->name()),
177 [ var = impl->m_Variable, graphWidget ]() { graphWidget->removeVariable(var); });
141 178 }
142 179 else {
143 180 qCCritical(LOG_GenerateVariableMenuOperation(),
144 181 "Can't visit VisualizationGraphWidget : the widget is null");
145 182 }
146 183 }
@@ -1,55 +1,55
1 1 #include "Visualization/operations/MenuBuilder.h"
2 2
3 3 Q_LOGGING_CATEGORY(LOG_MenuBuilder, "MenuBuilder")
4 4
5 5 MenuBuilder::MenuBuilder(QMenu *menu)
6 6 {
7 7 if (menu) {
8 8 m_Menus.push(menu);
9 9 }
10 10 else {
11 11 qCCritical(LOG_MenuBuilder()) << QObject::tr("No parent menu has been defined");
12 12 }
13 13 }
14 14
15 void MenuBuilder::addMenu(const QString &name)
15 void MenuBuilder::addMenu(const QString &name, const QIcon &icon)
16 16 {
17 17 if (auto currMenu = currentMenu()) {
18 m_Menus.push(currMenu->addMenu(name));
18 m_Menus.push(currMenu->addMenu(icon, name));
19 19 }
20 20 else {
21 21 qCCritical(LOG_MenuBuilder()) << QObject::tr("No current menu to attach the new menu");
22 22 }
23 23 }
24 24
25 25 void MenuBuilder::addSeparator()
26 26 {
27 27 if (auto currMenu = currentMenu()) {
28 28 if (!currMenu->isEmpty()) {
29 29 currMenu->addSeparator();
30 30 }
31 31 }
32 32 else {
33 33 qCCritical(LOG_MenuBuilder()) << QObject::tr("No current menu to attach the separator");
34 34 }
35 35 }
36 36
37 37 void MenuBuilder::closeMenu()
38 38 {
39 39 if (!m_Menus.isEmpty()) {
40 40 if (auto closedMenu = m_Menus.pop()) {
41 41 // Purge menu : if the closed menu has no entries, we remove it from its parent (the
42 42 // current menu)
43 43 if (auto currMenu = currentMenu()) {
44 44 if (closedMenu->isEmpty()) {
45 45 currMenu->removeAction(closedMenu->menuAction());
46 46 }
47 47 }
48 48 }
49 49 }
50 50 }
51 51
52 52 QMenu *MenuBuilder::currentMenu() const
53 53 {
54 54 return !m_Menus.isEmpty() ? m_Menus.top() : nullptr;
55 55 }
General Comments 0
You need to be logged in to leave comments. Login now