##// END OF EJS Templates
Merge branch 'feature/SelectionZones' into develop
trabillard -
r1095:ca242dcb639e merge
parent child
Show More
@@ -0,0 +1,47
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
3
4 #include <Common/spimpl.h>
5 #include <Data/SqpRange.h>
6 #include <Visualization/qcustomplot.h>
7
8 class VisualizationSelectionZoneItem : public QCPItemRect {
9
10 public:
11 VisualizationSelectionZoneItem(QCustomPlot *plot);
12 virtual ~VisualizationSelectionZoneItem();
13
14 void setName(const QString &name);
15 QString name() const;
16
17 SqpRange range() const;
18 void setRange(double tstart, double tend);
19 void setStart(double tstart);
20 void setEnd(double tend);
21
22 void setColor(const QColor &color);
23
24 void setEditionEnabled(bool value);
25 bool isEditionEnabled() const;
26
27 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
28 void setHovered(bool value);
29
30 void setAssociatedEditedZones(const QVector<VisualizationSelectionZoneItem *> &associatedZones);
31
32 protected:
33 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
34 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
35 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
36
37 void resizeLeft(double pixelDiff);
38 void resizeRight(double pixelDiff);
39 void move(double pixelDiff);
40
41
42 private:
43 class VisualizationSelectionZoneItemPrivate;
44 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
45 };
46
47 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
@@ -0,0 +1,26
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEMANAGER_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEMANAGER_H
3
4 #include <Common/spimpl.h>
5
6 #include <QVector>
7
8 class VisualizationSelectionZoneItem;
9
10 class VisualizationSelectionZoneManager {
11 public:
12 VisualizationSelectionZoneManager();
13
14 void select(const QVector<VisualizationSelectionZoneItem *> &items);
15 void setSelected(VisualizationSelectionZoneItem *item, bool value);
16
17 void clearSelection();
18
19 QVector<VisualizationSelectionZoneItem *> selectedItems() const;
20
21 private:
22 class VisualizationSelectionZoneManagerPrivate;
23 spimpl::unique_impl_ptr<VisualizationSelectionZoneManagerPrivate> impl;
24 };
25
26 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEMANAGER_H
@@ -0,0 +1,343
1 #include "Visualization/VisualizationSelectionZoneItem.h"
2
3 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
4
5 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
6
7 QCustomPlot *m_Plot;
8 double m_T1 = 0;
9 double m_T2 = 0;
10 QColor m_Color;
11
12 bool m_IsEditionEnabled = true;
13 double m_MovedOrinalT1 = 0;
14 double m_MovedOrinalT2 = 0;
15
16 QCPItemStraightLine *m_LeftLine;
17 QCPItemStraightLine *m_RightLine;
18 QCPItemText *m_NameLabelItem = nullptr;
19
20 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
21 EditionMode m_CurrentEditionMode;
22
23 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
24
25 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
26 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
27 {
28 }
29
30 void updatePosition(VisualizationSelectionZoneItem *item)
31 {
32 item->topLeft->setCoords(m_T1, 0);
33 item->bottomRight->setCoords(m_T2, 1);
34 }
35
36 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
37 {
38 auto distanceLeft = m_LeftLine->selectTest(pos, false);
39 auto distanceRight = m_RightLine->selectTest(pos, false);
40 auto distance = zoneItem->selectTest(pos, false);
41
42 if (distanceRight <= distance) {
43 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
44 }
45 else if (distanceLeft <= distance) {
46 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
47 }
48
49 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
50 }
51
52 double pixelSizeToAxisXSize(double pixels)
53 {
54 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
55 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
56 }
57 };
58
59 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
60 : QCPItemRect(plot),
61 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
62 {
63 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
64 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
65 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
66 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
67 setSelectable(false);
68
69 impl->m_RightLine = new QCPItemStraightLine(plot);
70 impl->m_RightLine->point1->setParentAnchor(topRight);
71 impl->m_RightLine->point2->setParentAnchor(bottomRight);
72 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
73 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
74 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
75 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
76 impl->m_RightLine->setSelectable(false);
77
78 impl->m_LeftLine = new QCPItemStraightLine(plot);
79 impl->m_LeftLine->point1->setParentAnchor(topLeft);
80 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
81 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
82 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
83 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
84 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
85 impl->m_LeftLine->setSelectable(false);
86
87 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
88 &QCPItemStraightLine::setSelected);
89 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
90 &QCPItemStraightLine::setSelected);
91
92 setColor(QColor(DEFAULT_COLOR));
93 }
94
95 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
96 {
97 impl->m_Plot->removeItem(impl->m_RightLine);
98 impl->m_Plot->removeItem(impl->m_LeftLine);
99 }
100
101 void VisualizationSelectionZoneItem::setName(const QString &name)
102 {
103 if (name.isEmpty() && impl->m_NameLabelItem) {
104 impl->m_Plot->removeItem(impl->m_NameLabelItem);
105 impl->m_NameLabelItem = nullptr;
106 }
107 else if (!impl->m_NameLabelItem) {
108 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
109 impl->m_NameLabelItem->setText(name);
110 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
111 impl->m_NameLabelItem->setColor(impl->m_Color);
112 impl->m_NameLabelItem->position->setParentAnchor(top);
113 }
114 }
115
116 QString VisualizationSelectionZoneItem::name() const
117 {
118 if (!impl->m_NameLabelItem) {
119 return QString();
120 }
121
122 return impl->m_NameLabelItem->text();
123 }
124
125 SqpRange VisualizationSelectionZoneItem::range() const
126 {
127 SqpRange range;
128 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
129 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
130 return range;
131 }
132
133 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
134 {
135 impl->m_T1 = tstart;
136 impl->m_T2 = tend;
137 impl->updatePosition(this);
138 }
139
140 void VisualizationSelectionZoneItem::setStart(double tstart)
141 {
142 impl->m_T1 = tstart;
143 impl->updatePosition(this);
144 }
145
146 void VisualizationSelectionZoneItem::setEnd(double tend)
147 {
148 impl->m_T2 = tend;
149 impl->updatePosition(this);
150 }
151
152 void VisualizationSelectionZoneItem::setColor(const QColor &color)
153 {
154 impl->m_Color = color;
155
156 auto brushColor = color;
157 brushColor.setAlpha(80);
158 setBrush(QBrush(brushColor));
159 setPen(QPen(Qt::NoPen));
160
161 auto selectedBrushColor = brushColor;
162 selectedBrushColor.setAlpha(150);
163 setSelectedBrush(QBrush(selectedBrushColor));
164 setSelectedPen(QPen(Qt::NoPen));
165
166 auto linePen = QPen(color);
167 linePen.setStyle(Qt::SolidLine);
168 linePen.setWidth(4);
169
170 auto selectedLinePen = linePen;
171 selectedLinePen.setColor(color.darker(120));
172 selectedLinePen.setWidth(4);
173
174 impl->m_LeftLine->setPen(linePen);
175 impl->m_RightLine->setPen(linePen);
176
177 impl->m_LeftLine->setSelectedPen(selectedLinePen);
178 impl->m_RightLine->setSelectedPen(selectedLinePen);
179 }
180
181 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
182 {
183 impl->m_IsEditionEnabled = value;
184 setSelectable(value);
185 if (!value) {
186 setSelected(false);
187 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
188 }
189 }
190
191 bool VisualizationSelectionZoneItem::isEditionEnabled() const
192 {
193 return impl->m_IsEditionEnabled;
194 }
195
196 Qt::CursorShape
197 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
198 {
199 auto mode = impl->m_CurrentEditionMode
200 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
201 ? impl->getEditionMode(position, this)
202 : impl->m_CurrentEditionMode;
203 switch (mode) {
204 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
205 return Qt::SizeAllCursor;
206 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
207 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
208 return Qt::SizeHorCursor;
209 default:
210 return Qt::ArrowCursor;
211 }
212 }
213
214 void VisualizationSelectionZoneItem::setHovered(bool value)
215 {
216 if (value) {
217 auto linePen = impl->m_LeftLine->pen();
218 linePen.setStyle(Qt::DotLine);
219 linePen.setWidth(3);
220
221 auto selectedLinePen = impl->m_LeftLine->selectedPen();
222 ;
223 selectedLinePen.setStyle(Qt::DotLine);
224 selectedLinePen.setWidth(3);
225
226 impl->m_LeftLine->setPen(linePen);
227 impl->m_RightLine->setPen(linePen);
228
229 impl->m_LeftLine->setSelectedPen(selectedLinePen);
230 impl->m_RightLine->setSelectedPen(selectedLinePen);
231 }
232 else {
233 setColor(impl->m_Color);
234 }
235 }
236
237 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
238 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
239 {
240 impl->m_AssociatedEditedZones = associatedZones;
241 impl->m_AssociatedEditedZones.removeAll(this);
242 }
243
244 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
245 {
246 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
247 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
248
249 impl->m_MovedOrinalT1 = impl->m_T1;
250 impl->m_MovedOrinalT2 = impl->m_T2;
251 for (auto associatedZone : impl->m_AssociatedEditedZones) {
252 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
253 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
254 }
255 }
256 else {
257 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
258 event->ignore();
259 }
260 }
261
262 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
263 {
264 if (isEditionEnabled()) {
265 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
266 auto pixelDiff = event->pos().x() - startPos.x();
267 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
268
269 switch (impl->m_CurrentEditionMode) {
270 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
271 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
272 for (auto associatedZone : impl->m_AssociatedEditedZones) {
273 associatedZone->move(pixelDiff);
274 }
275 break;
276 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
277 setStart(impl->m_MovedOrinalT1 + diff);
278 for (auto associatedZone : impl->m_AssociatedEditedZones) {
279 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
280 ? associatedZone->resizeLeft(pixelDiff)
281 : associatedZone->resizeRight(pixelDiff);
282 }
283 break;
284 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
285 setEnd(impl->m_MovedOrinalT2 + diff);
286 for (auto associatedZone : impl->m_AssociatedEditedZones) {
287 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
288 ? associatedZone->resizeRight(pixelDiff)
289 : associatedZone->resizeLeft(pixelDiff);
290 }
291 break;
292 default:
293 break;
294 }
295
296 for (auto associatedZone : impl->m_AssociatedEditedZones) {
297 associatedZone->parentPlot()->replot();
298 }
299 }
300 else {
301 event->ignore();
302 }
303 }
304
305 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
306 {
307 if (isEditionEnabled()) {
308 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
309 }
310 else {
311 event->ignore();
312 }
313
314 impl->m_AssociatedEditedZones.clear();
315 }
316
317 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
318 {
319 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
320 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
321 setStart(impl->m_MovedOrinalT1 + diff);
322 }
323 else {
324 setEnd(impl->m_MovedOrinalT2 + diff);
325 }
326 }
327
328 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
329 {
330 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
331 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
332 setStart(impl->m_MovedOrinalT1 + diff);
333 }
334 else {
335 setEnd(impl->m_MovedOrinalT2 + diff);
336 }
337 }
338
339 void VisualizationSelectionZoneItem::move(double pixelDiff)
340 {
341 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
342 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
343 }
@@ -0,0 +1,51
1 #include "Visualization/VisualizationSelectionZoneManager.h"
2 #include "Visualization/VisualizationSelectionZoneItem.h"
3
4 struct VisualizationSelectionZoneManager::VisualizationSelectionZoneManagerPrivate {
5 QVector<VisualizationSelectionZoneItem *> m_SelectedItems;
6 };
7
8 VisualizationSelectionZoneManager::VisualizationSelectionZoneManager()
9 : impl{spimpl::make_unique_impl<VisualizationSelectionZoneManagerPrivate>()}
10 {
11 }
12
13 void VisualizationSelectionZoneManager::select(
14 const QVector<VisualizationSelectionZoneItem *> &items)
15 {
16 clearSelection();
17 for (auto item : items) {
18 setSelected(item, true);
19 }
20 }
21
22 void VisualizationSelectionZoneManager::setSelected(VisualizationSelectionZoneItem *item,
23 bool value)
24 {
25 if (value != item->selected()) {
26 item->setSelected(value);
27 item->parentPlot()->replot();
28 }
29
30 if (!value && impl->m_SelectedItems.contains(item)) {
31 impl->m_SelectedItems.removeAll(item);
32 }
33 else if (value) {
34 impl->m_SelectedItems << item;
35 }
36 }
37
38 void VisualizationSelectionZoneManager::clearSelection()
39 {
40 for (auto item : impl->m_SelectedItems) {
41 item->setSelected(false);
42 item->parentPlot()->replot();
43 }
44
45 impl->m_SelectedItems.clear();
46 }
47
48 QVector<VisualizationSelectionZoneItem *> VisualizationSelectionZoneManager::selectedItems() const
49 {
50 return impl->m_SelectedItems;
51 }
@@ -1,353 +1,353
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 -- This file is a part of the SciQLop Software
2 -- This file is a part of the SciQLop Software
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
4 --
4 --
5 -- This program is free software; you can redistribute it and/or modify
5 -- This program is free software; you can redistribute it and/or modify
6 -- it under the terms of the GNU General Public License as published by
6 -- it under the terms of the GNU General Public License as published by
7 -- the Free Software Foundation; either version 2 of the License, or
7 -- the Free Software Foundation; either version 2 of the License, or
8 -- (at your option) any later version.
8 -- (at your option) any later version.
9 --
9 --
10 -- This program is distributed in the hope that it will be useful,
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 -- GNU General Public License for more details.
13 -- GNU General Public License for more details.
14 --
14 --
15 -- You should have received a copy of the GNU General Public License
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 -------------------------------------------------------------------------------*/
18 -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 -- Mail : alexis.jeandet@member.fsf.org
20 -- Mail : alexis.jeandet@member.fsf.org
21 ----------------------------------------------------------------------------*/
21 ----------------------------------------------------------------------------*/
22 #include "MainWindow.h"
22 #include "MainWindow.h"
23 #include "ui_MainWindow.h"
23 #include "ui_MainWindow.h"
24
24
25 #include <DataSource/DataSourceController.h>
25 #include <DataSource/DataSourceController.h>
26 #include <DataSource/DataSourceWidget.h>
26 #include <DataSource/DataSourceWidget.h>
27 #include <Settings/SqpSettingsDialog.h>
27 #include <Settings/SqpSettingsDialog.h>
28 #include <Settings/SqpSettingsGeneralWidget.h>
28 #include <Settings/SqpSettingsGeneralWidget.h>
29 #include <SidePane/SqpSidePane.h>
29 #include <SidePane/SqpSidePane.h>
30 #include <SqpApplication.h>
30 #include <SqpApplication.h>
31 #include <Time/TimeController.h>
31 #include <Time/TimeController.h>
32 #include <TimeWidget/TimeWidget.h>
32 #include <TimeWidget/TimeWidget.h>
33 #include <Variable/Variable.h>
33 #include <Variable/Variable.h>
34 #include <Variable/VariableController.h>
34 #include <Variable/VariableController.h>
35 #include <Visualization/VisualizationController.h>
35 #include <Visualization/VisualizationController.h>
36
36
37 #include <QAction>
37 #include <QAction>
38 #include <QDate>
38 #include <QDate>
39 #include <QDir>
39 #include <QDir>
40 #include <QFileDialog>
40 #include <QFileDialog>
41 #include <QToolBar>
41 #include <QToolBar>
42 #include <QToolButton>
42 #include <QToolButton>
43 #include <memory.h>
43 #include <memory.h>
44
44
45 #include "iostream"
45 #include "iostream"
46
46
47 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
47 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
48
48
49 namespace {
49 namespace {
50 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
50 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
51 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
51 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
52 const auto VIEWPLITTERINDEX = 2;
52 const auto VIEWPLITTERINDEX = 2;
53 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
53 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
54 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
54 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
55 }
55 }
56
56
57 class MainWindow::MainWindowPrivate {
57 class MainWindow::MainWindowPrivate {
58 public:
58 public:
59 explicit MainWindowPrivate(MainWindow *mainWindow)
59 explicit MainWindowPrivate(MainWindow *mainWindow)
60 : m_LastOpenLeftInspectorSize{},
60 : m_LastOpenLeftInspectorSize{},
61 m_LastOpenRightInspectorSize{},
61 m_LastOpenRightInspectorSize{},
62 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
62 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
63 m_SettingsDialog{new SqpSettingsDialog{mainWindow}}
63 m_SettingsDialog{new SqpSettingsDialog{mainWindow}}
64 {
64 {
65 }
65 }
66
66
67 QSize m_LastOpenLeftInspectorSize;
67 QSize m_LastOpenLeftInspectorSize;
68 QSize m_LastOpenRightInspectorSize;
68 QSize m_LastOpenRightInspectorSize;
69 /// General settings widget. MainWindow has the ownership
69 /// General settings widget. MainWindow has the ownership
70 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
70 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
71 /// Settings dialog. MainWindow has the ownership
71 /// Settings dialog. MainWindow has the ownership
72 SqpSettingsDialog *m_SettingsDialog;
72 SqpSettingsDialog *m_SettingsDialog;
73 };
73 };
74
74
75 MainWindow::MainWindow(QWidget *parent)
75 MainWindow::MainWindow(QWidget *parent)
76 : QMainWindow{parent},
76 : QMainWindow{parent},
77 m_Ui{new Ui::MainWindow},
77 m_Ui{new Ui::MainWindow},
78 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
78 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
79 {
79 {
80 m_Ui->setupUi(this);
80 m_Ui->setupUi(this);
81
81
82 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
82 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
83 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
83 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
84
84
85
85
86 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
86 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
87 auto openLeftInspectorAction = new QAction{QIcon{
87 auto openLeftInspectorAction = new QAction{QIcon{
88 ":/icones/previous.png",
88 ":/icones/previous.png",
89 },
89 },
90 tr("Show/hide the left inspector"), this};
90 tr("Show/hide the left inspector"), this};
91
91
92
92
93 auto spacerLeftTop = new QWidget{};
93 auto spacerLeftTop = new QWidget{};
94 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
94 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
95
95
96 auto spacerLeftBottom = new QWidget{};
96 auto spacerLeftBottom = new QWidget{};
97 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
97 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
98
98
99 leftSidePane->addWidget(spacerLeftTop);
99 leftSidePane->addWidget(spacerLeftTop);
100 leftSidePane->addAction(openLeftInspectorAction);
100 leftSidePane->addAction(openLeftInspectorAction);
101 leftSidePane->addWidget(spacerLeftBottom);
101 leftSidePane->addWidget(spacerLeftBottom);
102
102
103
103
104 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
104 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
105 auto openRightInspectorAction = new QAction{QIcon{
105 auto openRightInspectorAction = new QAction{QIcon{
106 ":/icones/next.png",
106 ":/icones/next.png",
107 },
107 },
108 tr("Show/hide the right inspector"), this};
108 tr("Show/hide the right inspector"), this};
109
109
110 auto spacerRightTop = new QWidget{};
110 auto spacerRightTop = new QWidget{};
111 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
111 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
112
112
113 auto spacerRightBottom = new QWidget{};
113 auto spacerRightBottom = new QWidget{};
114 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
114 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
115
115
116 rightSidePane->addWidget(spacerRightTop);
116 rightSidePane->addWidget(spacerRightTop);
117 rightSidePane->addAction(openRightInspectorAction);
117 rightSidePane->addAction(openRightInspectorAction);
118 rightSidePane->addWidget(spacerRightBottom);
118 rightSidePane->addWidget(spacerRightBottom);
119
119
120 openLeftInspectorAction->setCheckable(true);
120 openLeftInspectorAction->setCheckable(true);
121 openRightInspectorAction->setCheckable(true);
121 openRightInspectorAction->setCheckable(true);
122
122
123 auto openInspector = [this](bool checked, bool right, auto action) {
123 auto openInspector = [this](bool checked, bool right, auto action) {
124
124
125 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
125 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
126
126
127 auto &lastInspectorSize
127 auto &lastInspectorSize
128 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
128 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
129
129
130 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
130 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
131 : m_Ui->leftMainInspectorWidget->size();
131 : m_Ui->leftMainInspectorWidget->size();
132
132
133 // Update of the last opened geometry
133 // Update of the last opened geometry
134 if (checked) {
134 if (checked) {
135 lastInspectorSize = nextInspectorSize;
135 lastInspectorSize = nextInspectorSize;
136 }
136 }
137
137
138 auto startSize = lastInspectorSize;
138 auto startSize = lastInspectorSize;
139 auto endSize = startSize;
139 auto endSize = startSize;
140 endSize.setWidth(0);
140 endSize.setWidth(0);
141
141
142 auto splitterInspectorIndex
142 auto splitterInspectorIndex
143 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
143 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
144
144
145 auto currentSizes = m_Ui->splitter->sizes();
145 auto currentSizes = m_Ui->splitter->sizes();
146 if (checked) {
146 if (checked) {
147 // adjust sizes individually here, e.g.
147 // adjust sizes individually here, e.g.
148 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
148 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
149 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
149 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
150 m_Ui->splitter->setSizes(currentSizes);
150 m_Ui->splitter->setSizes(currentSizes);
151 }
151 }
152 else {
152 else {
153 // adjust sizes individually here, e.g.
153 // adjust sizes individually here, e.g.
154 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
154 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
155 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
155 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
156 m_Ui->splitter->setSizes(currentSizes);
156 m_Ui->splitter->setSizes(currentSizes);
157 }
157 }
158
158
159 };
159 };
160
160
161
161
162 connect(openLeftInspectorAction, &QAction::triggered,
162 connect(openLeftInspectorAction, &QAction::triggered,
163 [openInspector, openLeftInspectorAction](bool checked) {
163 [openInspector, openLeftInspectorAction](bool checked) {
164 openInspector(checked, false, openLeftInspectorAction);
164 openInspector(checked, false, openLeftInspectorAction);
165 });
165 });
166 connect(openRightInspectorAction, &QAction::triggered,
166 connect(openRightInspectorAction, &QAction::triggered,
167 [openInspector, openRightInspectorAction](bool checked) {
167 [openInspector, openRightInspectorAction](bool checked) {
168 openInspector(checked, true, openRightInspectorAction);
168 openInspector(checked, true, openRightInspectorAction);
169 });
169 });
170
170
171 // //////////////// //
171 // //////////////// //
172 // Menu and Toolbar //
172 // Menu and Toolbar //
173 // //////////////// //
173 // //////////////// //
174 this->menuBar()->addAction(tr("File"));
174 this->menuBar()->addAction(tr("File"));
175 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
175 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
176 toolsMenu->addAction(tr("Settings..."), [this]() {
176 toolsMenu->addAction(tr("Settings..."), [this]() {
177 // Loads settings
177 // Loads settings
178 impl->m_SettingsDialog->loadSettings();
178 impl->m_SettingsDialog->loadSettings();
179
179
180 // Open settings dialog and save settings if the dialog is accepted
180 // Open settings dialog and save settings if the dialog is accepted
181 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
181 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
182 impl->m_SettingsDialog->saveSettings();
182 impl->m_SettingsDialog->saveSettings();
183 }
183 }
184
184
185 });
185 });
186
186
187 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
187 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
188
188
189 auto timeWidget = new TimeWidget{};
189 auto timeWidget = new TimeWidget{};
190 mainToolBar->addWidget(timeWidget);
190 mainToolBar->addWidget(timeWidget);
191
191
192 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Pointer", this};
192 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
193 actionPointerMode->setCheckable(true);
193 actionPointerMode->setCheckable(true);
194 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
194 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
195 == SqpApplication::PlotsInteractionMode::None);
195 == SqpApplication::PlotsInteractionMode::None);
196 connect(actionPointerMode, &QAction::triggered,
196 connect(actionPointerMode, &QAction::triggered,
197 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
197 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
198
198
199 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
199 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
200 actionZoomMode->setCheckable(true);
200 actionZoomMode->setCheckable(true);
201 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
201 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
202 == SqpApplication::PlotsInteractionMode::ZoomBox);
202 == SqpApplication::PlotsInteractionMode::ZoomBox);
203 connect(actionZoomMode, &QAction::triggered, []() {
203 connect(actionZoomMode, &QAction::triggered, []() {
204 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
204 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
205 });
205 });
206
206
207 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
207 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
208 actionOrganisationMode->setCheckable(true);
208 actionOrganisationMode->setCheckable(true);
209 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
209 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
210 == SqpApplication::PlotsInteractionMode::DragAndDrop);
210 == SqpApplication::PlotsInteractionMode::DragAndDrop);
211 connect(actionOrganisationMode, &QAction::triggered, []() {
211 connect(actionOrganisationMode, &QAction::triggered, []() {
212 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
212 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
213 });
213 });
214
214
215 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
215 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
216 actionZonesMode->setCheckable(true);
216 actionZonesMode->setCheckable(true);
217 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
217 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
218 == SqpApplication::PlotsInteractionMode::SelectionZones);
218 == SqpApplication::PlotsInteractionMode::SelectionZones);
219 connect(actionZonesMode, &QAction::triggered, []() {
219 connect(actionZonesMode, &QAction::triggered, []() {
220 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
220 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
221 });
221 });
222
222
223 auto modeActionGroup = new QActionGroup{this};
223 auto modeActionGroup = new QActionGroup{this};
224 modeActionGroup->addAction(actionZoomMode);
224 modeActionGroup->addAction(actionZoomMode);
225 modeActionGroup->addAction(actionZonesMode);
225 modeActionGroup->addAction(actionZonesMode);
226 modeActionGroup->addAction(actionOrganisationMode);
226 modeActionGroup->addAction(actionOrganisationMode);
227 modeActionGroup->addAction(actionPointerMode);
227 modeActionGroup->addAction(actionPointerMode);
228 modeActionGroup->setExclusive(true);
228 modeActionGroup->setExclusive(true);
229
229
230 mainToolBar->addSeparator();
230 mainToolBar->addSeparator();
231 mainToolBar->addAction(actionPointerMode);
231 mainToolBar->addAction(actionPointerMode);
232 mainToolBar->addAction(actionZoomMode);
232 mainToolBar->addAction(actionZoomMode);
233 mainToolBar->addAction(actionOrganisationMode);
233 mainToolBar->addAction(actionOrganisationMode);
234 mainToolBar->addAction(actionZonesMode);
234 mainToolBar->addAction(actionZonesMode);
235 mainToolBar->addSeparator();
235 mainToolBar->addSeparator();
236
236
237 auto btnCursor = new QToolButton{this};
237 auto btnCursor = new QToolButton{this};
238 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
238 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
239 btnCursor->setText("Cursor");
239 btnCursor->setText("Cursor");
240 btnCursor->setToolTip("Cursor");
240 btnCursor->setToolTip("Cursor");
241 btnCursor->setPopupMode(QToolButton::InstantPopup);
241 btnCursor->setPopupMode(QToolButton::InstantPopup);
242 auto cursorMenu = new QMenu("CursorMenu", this);
242 auto cursorMenu = new QMenu("CursorMenu", this);
243 btnCursor->setMenu(cursorMenu);
243 btnCursor->setMenu(cursorMenu);
244
244
245 auto noCursorAction = cursorMenu->addAction("No Cursor");
245 auto noCursorAction = cursorMenu->addAction("No Cursor");
246 noCursorAction->setCheckable(true);
246 noCursorAction->setCheckable(true);
247 noCursorAction->setChecked(sqpApp->plotsCursorMode()
247 noCursorAction->setChecked(sqpApp->plotsCursorMode()
248 == SqpApplication::PlotsCursorMode::NoCursor);
248 == SqpApplication::PlotsCursorMode::NoCursor);
249 connect(noCursorAction, &QAction::triggered,
249 connect(noCursorAction, &QAction::triggered,
250 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
250 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
251
251
252 cursorMenu->addSeparator();
252 cursorMenu->addSeparator();
253 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
253 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
254 verticalCursorAction->setCheckable(true);
254 verticalCursorAction->setCheckable(true);
255 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
255 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
256 == SqpApplication::PlotsCursorMode::Vertical);
256 == SqpApplication::PlotsCursorMode::Vertical);
257 connect(verticalCursorAction, &QAction::triggered,
257 connect(verticalCursorAction, &QAction::triggered,
258 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
258 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
259
259
260 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
260 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
261 temporalCursorAction->setCheckable(true);
261 temporalCursorAction->setCheckable(true);
262 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
262 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
263 == SqpApplication::PlotsCursorMode::Temporal);
263 == SqpApplication::PlotsCursorMode::Temporal);
264 connect(temporalCursorAction, &QAction::triggered,
264 connect(temporalCursorAction, &QAction::triggered,
265 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
265 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
266
266
267 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
267 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
268 horizontalCursorAction->setCheckable(true);
268 horizontalCursorAction->setCheckable(true);
269 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
269 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
270 == SqpApplication::PlotsCursorMode::Horizontal);
270 == SqpApplication::PlotsCursorMode::Horizontal);
271 connect(horizontalCursorAction, &QAction::triggered,
271 connect(horizontalCursorAction, &QAction::triggered,
272 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
272 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
273
273
274 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
274 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
275 crossCursorAction->setCheckable(true);
275 crossCursorAction->setCheckable(true);
276 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
276 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
277 == SqpApplication::PlotsCursorMode::Cross);
277 == SqpApplication::PlotsCursorMode::Cross);
278 connect(crossCursorAction, &QAction::triggered,
278 connect(crossCursorAction, &QAction::triggered,
279 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
279 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
280
280
281 mainToolBar->addWidget(btnCursor);
281 mainToolBar->addWidget(btnCursor);
282
282
283 auto cursorModeActionGroup = new QActionGroup{this};
283 auto cursorModeActionGroup = new QActionGroup{this};
284 cursorModeActionGroup->setExclusive(true);
284 cursorModeActionGroup->setExclusive(true);
285 cursorModeActionGroup->addAction(noCursorAction);
285 cursorModeActionGroup->addAction(noCursorAction);
286 cursorModeActionGroup->addAction(verticalCursorAction);
286 cursorModeActionGroup->addAction(verticalCursorAction);
287 cursorModeActionGroup->addAction(temporalCursorAction);
287 cursorModeActionGroup->addAction(temporalCursorAction);
288 cursorModeActionGroup->addAction(horizontalCursorAction);
288 cursorModeActionGroup->addAction(horizontalCursorAction);
289 cursorModeActionGroup->addAction(crossCursorAction);
289 cursorModeActionGroup->addAction(crossCursorAction);
290
290
291 // //////// //
291 // //////// //
292 // Settings //
292 // Settings //
293 // //////// //
293 // //////// //
294
294
295 // Registers "general settings" widget to the settings dialog
295 // Registers "general settings" widget to the settings dialog
296 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
296 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
297 impl->m_GeneralSettingsWidget);
297 impl->m_GeneralSettingsWidget);
298
298
299 // /////////// //
299 // /////////// //
300 // Connections //
300 // Connections //
301 // /////////// //
301 // /////////// //
302
302
303 // Controllers / controllers connections
303 // Controllers / controllers connections
304 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpRange)), &sqpApp->variableController(),
304 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpRange)), &sqpApp->variableController(),
305 SLOT(onDateTimeOnSelection(SqpRange)));
305 SLOT(onDateTimeOnSelection(SqpRange)));
306
306
307 // Widgets / controllers connections
307 // Widgets / controllers connections
308
308
309 // DataSource
309 // DataSource
310 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
310 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
311 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
311 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
312
312
313 // Time
313 // Time
314 connect(timeWidget, SIGNAL(timeUpdated(SqpRange)), &sqpApp->timeController(),
314 connect(timeWidget, SIGNAL(timeUpdated(SqpRange)), &sqpApp->timeController(),
315 SLOT(onTimeToUpdate(SqpRange)));
315 SLOT(onTimeToUpdate(SqpRange)));
316
316
317 // Visualization
317 // Visualization
318 connect(&sqpApp->visualizationController(),
318 connect(&sqpApp->visualizationController(),
319 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
319 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
320 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
320 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
321
321
322 connect(&sqpApp->visualizationController(),
322 connect(&sqpApp->visualizationController(),
323 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)), m_Ui->view,
323 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)), m_Ui->view,
324 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
324 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
325
325
326 // Widgets / widgets connections
326 // Widgets / widgets connections
327
327
328 // For the following connections, we use DirectConnection to allow each widget that can
328 // For the following connections, we use DirectConnection to allow each widget that can
329 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
329 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
330 // The order of connections is also important, since it determines the order in which each
330 // The order of connections is also important, since it determines the order in which each
331 // widget will attach its menu
331 // widget will attach its menu
332 connect(
332 connect(
333 m_Ui->variableInspectorWidget,
333 m_Ui->variableInspectorWidget,
334 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
334 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
335 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
335 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
336 Qt::DirectConnection);
336 Qt::DirectConnection);
337 }
337 }
338
338
339 MainWindow::~MainWindow()
339 MainWindow::~MainWindow()
340 {
340 {
341 }
341 }
342
342
343 void MainWindow::changeEvent(QEvent *e)
343 void MainWindow::changeEvent(QEvent *e)
344 {
344 {
345 QMainWindow::changeEvent(e);
345 QMainWindow::changeEvent(e);
346 switch (e->type()) {
346 switch (e->type()) {
347 case QEvent::LanguageChange:
347 case QEvent::LanguageChange:
348 m_Ui->retranslateUi(this);
348 m_Ui->retranslateUi(this);
349 break;
349 break;
350 default:
350 default:
351 break;
351 break;
352 }
352 }
353 }
353 }
@@ -1,19 +1,20
1 #ifndef SCIQLOP_MIMETYPESDEF_H
1 #ifndef SCIQLOP_MIMETYPESDEF_H
2 #define SCIQLOP_MIMETYPESDEF_H
2 #define SCIQLOP_MIMETYPESDEF_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <QString>
6 #include <QString>
7
7
8 // ////////////////// //
8 // ////////////////// //
9 // SciQlop Mime Types //
9 // SciQlop Mime Types //
10 // ////////////////// //
10 // ////////////////// //
11
11
12 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH;
12 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH;
13 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
13 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
17 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_SELECTION_ZONE;
17
18
18
19
19 #endif // SCIQLOP_MIMETYPESDEF_H
20 #endif // SCIQLOP_MIMETYPESDEF_H
@@ -1,7 +1,8
1 #include "Common/MimeTypesDef.h"
1 #include "Common/MimeTypesDef.h"
2
2
3 const QString MIME_TYPE_GRAPH = QStringLiteral("sciqlop/graph");
3 const QString MIME_TYPE_GRAPH = QStringLiteral("sciqlop/graph");
4 const QString MIME_TYPE_ZONE = QStringLiteral("sciqlop/zone");
4 const QString MIME_TYPE_ZONE = QStringLiteral("sciqlop/zone");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list");
6 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
6 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
8 const QString MIME_TYPE_SELECTION_ZONE = QStringLiteral("sciqlop/selection-zone");
@@ -1,30 +1,34
1 #ifndef SCIQLOP_VISUALIZATIONDRAGWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONDRAGWIDGET_H
2 #define SCIQLOP_VISUALIZATIONDRAGWIDGET_H
2 #define SCIQLOP_VISUALIZATIONDRAGWIDGET_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QMimeData>
5 #include <QMimeData>
6 #include <QWidget>
6 #include <QWidget>
7
7
8 class VisualizationDragWidget : public QWidget {
8 class VisualizationDragWidget : public QWidget {
9 Q_OBJECT
9 Q_OBJECT
10
10
11 public:
11 public:
12 VisualizationDragWidget(QWidget *parent = nullptr);
12 VisualizationDragWidget(QWidget *parent = nullptr);
13
13
14 virtual QMimeData *mimeData() const = 0;
14 virtual QMimeData *mimeData(const QPoint &position) const = 0;
15 virtual bool isDragAllowed() const = 0;
15 virtual bool isDragAllowed() const = 0;
16 virtual void highlightForMerge(bool highlighted) { Q_UNUSED(highlighted); };
16 virtual void highlightForMerge(bool highlighted) { Q_UNUSED(highlighted); }
17
18 /// Custom pixmap to display during a drag operation.
19 /// If the provided pixmap is null, a pixmap of the entire widget is used.
20 virtual QPixmap customDragPixmap(const QPoint &dragPosition);
17
21
18 protected:
22 protected:
19 virtual void mousePressEvent(QMouseEvent *event) override;
23 virtual void mousePressEvent(QMouseEvent *event) override;
20 virtual void mouseMoveEvent(QMouseEvent *event) override;
24 virtual void mouseMoveEvent(QMouseEvent *event) override;
21
25
22 private:
26 private:
23 class VisualizationDragWidgetPrivate;
27 class VisualizationDragWidgetPrivate;
24 spimpl::unique_impl_ptr<VisualizationDragWidgetPrivate> impl;
28 spimpl::unique_impl_ptr<VisualizationDragWidgetPrivate> impl;
25
29
26 signals:
30 signals:
27 void dragDetected(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
31 void dragDetected(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
28 };
32 };
29
33
30 #endif // SCIQLOP_VISUALIZATIONDRAGWIDGET_H
34 #endif // SCIQLOP_VISUALIZATIONDRAGWIDGET_H
@@ -1,123 +1,138
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15
15
16 class QCPRange;
16 class QCPRange;
17 class QCustomPlot;
17 class QCustomPlot;
18 class SqpRange;
18 class SqpRange;
19 class Variable;
19 class Variable;
20 class VisualizationWidget;
20 class VisualizationZoneWidget;
21 class VisualizationZoneWidget;
21
22
22 namespace Ui {
23 namespace Ui {
23 class VisualizationGraphWidget;
24 class VisualizationGraphWidget;
24 } // namespace Ui
25 } // namespace Ui
25
26
26 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
27 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
27 Q_OBJECT
28 Q_OBJECT
28
29
29 friend class QCustomPlotSynchronizer;
30 friend class QCustomPlotSynchronizer;
30 friend class VisualizationGraphRenderingDelegate;
31 friend class VisualizationGraphRenderingDelegate;
31
32
32 public:
33 public:
33 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
34 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
34 virtual ~VisualizationGraphWidget();
35 virtual ~VisualizationGraphWidget();
35
36
37 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
36 VisualizationZoneWidget *parentZoneWidget() const noexcept;
38 VisualizationZoneWidget *parentZoneWidget() const noexcept;
37
39
40 /// Returns the main VisualizationWidget which contains the graph or nullptr
41 VisualizationWidget *parentVisualizationWidget() const;
42
38 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
43 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
39 void enableAcquisition(bool enable);
44 void enableAcquisition(bool enable);
40
45
41 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
46 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
42
47
43 /// Removes a variable from the graph
48 /// Removes a variable from the graph
44 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
49 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
45
50
46 /// Returns the list of all variables used in the graph
51 /// Returns the list of all variables used in the graph
47 QList<std::shared_ptr<Variable> > variables() const;
52 QList<std::shared_ptr<Variable> > variables() const;
48
53
49 /// Sets the y-axis range based on the data of a variable
54 /// Sets the y-axis range based on the data of a variable
50 void setYRange(std::shared_ptr<Variable> variable);
55 void setYRange(std::shared_ptr<Variable> variable);
51 SqpRange graphRange() const noexcept;
56 SqpRange graphRange() const noexcept;
52 void setGraphRange(const SqpRange &range);
57 void setGraphRange(const SqpRange &range);
53
58
59 /// Returns the ranges of all the selection zones on the graph
60 QVector<SqpRange> selectionZoneRanges() const;
61
62 /// Adds new selection zones in the graph
63 void addSelectionZones(const QVector<SqpRange> &ranges);
64
65 /// Undo the last zoom done with a zoom box
66 void undoZoom();
67
54 // IVisualizationWidget interface
68 // IVisualizationWidget interface
55 void accept(IVisualizationWidgetVisitor *visitor) override;
69 void accept(IVisualizationWidgetVisitor *visitor) override;
56 bool canDrop(const Variable &variable) const override;
70 bool canDrop(const Variable &variable) const override;
57 bool contains(const Variable &variable) const override;
71 bool contains(const Variable &variable) const override;
58 QString name() const override;
72 QString name() const override;
59
73
60 // VisualisationDragWidget
74 // VisualisationDragWidget
61 QMimeData *mimeData() const override;
75 QMimeData *mimeData(const QPoint &position) const override;
76 QPixmap customDragPixmap(const QPoint &dragPosition) override;
62 bool isDragAllowed() const override;
77 bool isDragAllowed() const override;
63 void highlightForMerge(bool highlighted) override;
78 void highlightForMerge(bool highlighted) override;
64
79
65 // Cursors
80 // Cursors
66 /// Adds or moves the vertical cursor at the specified value on the x-axis
81 /// Adds or moves the vertical cursor at the specified value on the x-axis
67 void addVerticalCursor(double time);
82 void addVerticalCursor(double time);
68 /// Adds or moves the vertical cursor at the specified value on the x-axis
83 /// Adds or moves the vertical cursor at the specified value on the x-axis
69 void addVerticalCursorAtViewportPosition(double position);
84 void addVerticalCursorAtViewportPosition(double position);
70 void removeVerticalCursor();
85 void removeVerticalCursor();
71 /// Adds or moves the vertical cursor at the specified value on the y-axis
86 /// Adds or moves the vertical cursor at the specified value on the y-axis
72 void addHorizontalCursor(double value);
87 void addHorizontalCursor(double value);
73 /// Adds or moves the vertical cursor at the specified value on the y-axis
88 /// Adds or moves the vertical cursor at the specified value on the y-axis
74 void addHorizontalCursorAtViewportPosition(double position);
89 void addHorizontalCursorAtViewportPosition(double position);
75 void removeHorizontalCursor();
90 void removeHorizontalCursor();
76
91
77 signals:
92 signals:
78 void synchronize(const SqpRange &range, const SqpRange &oldRange);
93 void synchronize(const SqpRange &range, const SqpRange &oldRange);
79 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
94 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
80 bool synchronise);
95 bool synchronise);
81
96
82 /// Signal emitted when the variable is about to be removed from the graph
97 /// Signal emitted when the variable is about to be removed from the graph
83 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
98 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
84 /// Signal emitted when the variable has been added to the graph
99 /// Signal emitted when the variable has been added to the graph
85 void variableAdded(std::shared_ptr<Variable> var);
100 void variableAdded(std::shared_ptr<Variable> var);
86
101
87 protected:
102 protected:
88 void closeEvent(QCloseEvent *event) override;
103 void closeEvent(QCloseEvent *event) override;
89 void enterEvent(QEvent *event) override;
104 void enterEvent(QEvent *event) override;
90 void leaveEvent(QEvent *event) override;
105 void leaveEvent(QEvent *event) override;
91
106
92 QCustomPlot &plot() noexcept;
107 QCustomPlot &plot() const noexcept;
93
108
94 private:
109 private:
95 Ui::VisualizationGraphWidget *ui;
110 Ui::VisualizationGraphWidget *ui;
96
111
97 class VisualizationGraphWidgetPrivate;
112 class VisualizationGraphWidgetPrivate;
98 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
113 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
99
114
100 private slots:
115 private slots:
101 /// Slot called when right clicking on the graph (displays a menu)
116 /// Slot called when right clicking on the graph (displays a menu)
102 void onGraphMenuRequested(const QPoint &pos) noexcept;
117 void onGraphMenuRequested(const QPoint &pos) noexcept;
103
118
104 /// Rescale the X axe to range parameter
119 /// Rescale the X axe to range parameter
105 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
120 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
106
121
107 /// Slot called when a mouse double click was made
122 /// Slot called when a mouse double click was made
108 void onMouseDoubleClick(QMouseEvent *event) noexcept;
123 void onMouseDoubleClick(QMouseEvent *event) noexcept;
109 /// Slot called when a mouse move was made
124 /// Slot called when a mouse move was made
110 void onMouseMove(QMouseEvent *event) noexcept;
125 void onMouseMove(QMouseEvent *event) noexcept;
111 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
126 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
112 void onMouseWheel(QWheelEvent *event) noexcept;
127 void onMouseWheel(QWheelEvent *event) noexcept;
113 /// Slot called when a mouse press was made, to activate the calibration of a graph
128 /// Slot called when a mouse press was made, to activate the calibration of a graph
114 void onMousePress(QMouseEvent *event) noexcept;
129 void onMousePress(QMouseEvent *event) noexcept;
115 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
130 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
116 void onMouseRelease(QMouseEvent *event) noexcept;
131 void onMouseRelease(QMouseEvent *event) noexcept;
117
132
118 void onDataCacheVariableUpdated();
133 void onDataCacheVariableUpdated();
119
134
120 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
135 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
121 };
136 };
122
137
123 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
138 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,54 +1,63
1 #ifndef SCIQLOP_VISUALIZATIONWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONWIDGET_H
2 #define SCIQLOP_VISUALIZATIONWIDGET_H
2 #define SCIQLOP_VISUALIZATIONWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include <Data/SqpRange.h>
5 #include <Data/SqpRange.h>
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <Common/spimpl.h>
11
10 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
11
13
12 class QMenu;
14 class QMenu;
13 class Variable;
15 class Variable;
14 class VisualizationTabWidget;
16 class VisualizationTabWidget;
17 class VisualizationSelectionZoneManager;
15
18
16 namespace Ui {
19 namespace Ui {
17 class VisualizationWidget;
20 class VisualizationWidget;
18 } // namespace Ui
21 } // namespace Ui
19
22
20 class VisualizationWidget : public QWidget, public IVisualizationWidget {
23 class VisualizationWidget : public QWidget, public IVisualizationWidget {
21 Q_OBJECT
24 Q_OBJECT
22
25
23 public:
26 public:
24 explicit VisualizationWidget(QWidget *parent = 0);
27 explicit VisualizationWidget(QWidget *parent = 0);
25 virtual ~VisualizationWidget();
28 virtual ~VisualizationWidget();
26
29
30 /// Returns the class which manage the selection of selection zone across the visualization
31 VisualizationSelectionZoneManager &selectionZoneManager() const;
32
27 // IVisualizationWidget interface
33 // IVisualizationWidget interface
28 void accept(IVisualizationWidgetVisitor *visitor) override;
34 void accept(IVisualizationWidgetVisitor *visitor) override;
29 bool canDrop(const Variable &variable) const override;
35 bool canDrop(const Variable &variable) const override;
30 bool contains(const Variable &variable) const override;
36 bool contains(const Variable &variable) const override;
31 QString name() const override;
37 QString name() const override;
32
38
33 public slots:
39 public slots:
34 /**
40 /**
35 * Attaches to a menu the menu relative to the visualization of variables
41 * Attaches to a menu the menu relative to the visualization of variables
36 * @param menu the parent menu of the generated menu
42 * @param menu the parent menu of the generated menu
37 * @param variables the variables for which to generate the menu
43 * @param variables the variables for which to generate the menu
38 */
44 */
39 void attachVariableMenu(QMenu *menu,
45 void attachVariableMenu(QMenu *menu,
40 const QVector<std::shared_ptr<Variable> > &variables) noexcept;
46 const QVector<std::shared_ptr<Variable> > &variables) noexcept;
41
47
42 /// Slot called when a variable is about to be deleted from SciQlop
48 /// Slot called when a variable is about to be deleted from SciQlop
43 void onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept;
49 void onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept;
44
50
45 void onRangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range) noexcept;
51 void onRangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range) noexcept;
46
52
47 protected:
53 protected:
48 void closeEvent(QCloseEvent *event) override;
54 void closeEvent(QCloseEvent *event) override;
49
55
50 private:
56 private:
51 Ui::VisualizationWidget *ui;
57 Ui::VisualizationWidget *ui;
58
59 class VisualizationWidgetPrivate;
60 spimpl::unique_impl_ptr<VisualizationWidgetPrivate> impl;
52 };
61 };
53
62
54 #endif // VISUALIZATIONWIDGET_H
63 #endif // VISUALIZATIONWIDGET_H
@@ -1,95 +1,98
1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
15
15
16 namespace Ui {
16 namespace Ui {
17 class VisualizationZoneWidget;
17 class VisualizationZoneWidget;
18 } // namespace Ui
18 } // namespace Ui
19
19
20 class Variable;
20 class Variable;
21 class VisualizationGraphWidget;
21 class VisualizationGraphWidget;
22
22
23 class VisualizationZoneWidget : public VisualizationDragWidget, public IVisualizationWidget {
23 class VisualizationZoneWidget : public VisualizationDragWidget, public IVisualizationWidget {
24 Q_OBJECT
24 Q_OBJECT
25
25
26 public:
26 public:
27 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
27 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
28 virtual ~VisualizationZoneWidget();
28 virtual ~VisualizationZoneWidget();
29
29
30 /// Adds a graph widget
30 /// Adds a graph widget
31 void addGraph(VisualizationGraphWidget *graphWidget);
31 void addGraph(VisualizationGraphWidget *graphWidget);
32
32
33 /// Inserts a graph widget
33 /// Inserts a graph widget
34 void insertGraph(int index, VisualizationGraphWidget *graphWidget);
34 void insertGraph(int index, VisualizationGraphWidget *graphWidget);
35
35
36 /**
36 /**
37 * Creates a graph using a variable. The variable will be displayed in the new graph.
37 * Creates a graph using a variable. The variable will be displayed in the new graph.
38 * The graph is added at the end.
38 * The graph is added at the end.
39 * @param variable the variable for which to create the graph
39 * @param variable the variable for which to create the graph
40 * @return the pointer to the created graph
40 * @return the pointer to the created graph
41 */
41 */
42 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
42 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
43
43
44 /**
44 /**
45 * Creates a graph using a variable. The variable will be displayed in the new graph.
45 * Creates a graph using a variable. The variable will be displayed in the new graph.
46 * The graph is inserted at the specified index.
46 * The graph is inserted at the specified index.
47 * @param variable the variable for which to create the graph
47 * @param variable the variable for which to create the graph
48 * @param index The index where the graph should be inserted in the layout
48 * @param index The index where the graph should be inserted in the layout
49 * @return the pointer to the created graph
49 * @return the pointer to the created graph
50 */
50 */
51 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable, int index);
51 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable, int index);
52
52
53 /**
53 /**
54 * Creates a graph using a list of variables. The variables will be displayed in the new graph.
54 * Creates a graph using a list of variables. The variables will be displayed in the new graph.
55 * The graph is inserted at the specified index.
55 * The graph is inserted at the specified index.
56 * @param variables List of variables to be added to the graph
56 * @param variables List of variables to be added to the graph
57 * @param index The index where the graph should be inserted in the layout
57 * @param index The index where the graph should be inserted in the layout
58 * @return the pointer to the created graph
58 * @return the pointer to the created graph
59 */
59 */
60 VisualizationGraphWidget *createGraph(const QList<std::shared_ptr<Variable> > variables,
60 VisualizationGraphWidget *createGraph(const QList<std::shared_ptr<Variable> > variables,
61 int index);
61 int index);
62
62
63 /// Returns the first graph in the zone or nullptr if there is no graph inside
64 VisualizationGraphWidget *firstGraph() const;
65
63 // IVisualizationWidget interface
66 // IVisualizationWidget interface
64 void accept(IVisualizationWidgetVisitor *visitor) override;
67 void accept(IVisualizationWidgetVisitor *visitor) override;
65 bool canDrop(const Variable &variable) const override;
68 bool canDrop(const Variable &variable) const override;
66 bool contains(const Variable &variable) const override;
69 bool contains(const Variable &variable) const override;
67 QString name() const override;
70 QString name() const override;
68
71
69 // VisualisationDragWidget
72 // VisualisationDragWidget
70 QMimeData *mimeData() const override;
73 QMimeData *mimeData(const QPoint &position) const override;
71 bool isDragAllowed() const override;
74 bool isDragAllowed() const override;
72
75
73 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
76 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
74 VisualizationGraphWidget *graphWidget);
77 VisualizationGraphWidget *graphWidget);
75 void notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget);
78 void notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget);
76
79
77 protected:
80 protected:
78 void closeEvent(QCloseEvent *event) override;
81 void closeEvent(QCloseEvent *event) override;
79
82
80 private:
83 private:
81 Ui::VisualizationZoneWidget *ui;
84 Ui::VisualizationZoneWidget *ui;
82
85
83 class VisualizationZoneWidgetPrivate;
86 class VisualizationZoneWidgetPrivate;
84 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
87 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
85
88
86 private slots:
89 private slots:
87 void onVariableAdded(std::shared_ptr<Variable> variable);
90 void onVariableAdded(std::shared_ptr<Variable> variable);
88 /// Slot called when a variable is about to be removed from a graph contained in the zone
91 /// Slot called when a variable is about to be removed from a graph contained in the zone
89 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
92 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
90
93
91 void dropMimeData(int index, const QMimeData *mimeData);
94 void dropMimeData(int index, const QMimeData *mimeData);
92 void dropMimeDataOnGraph(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
95 void dropMimeDataOnGraph(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
93 };
96 };
94
97
95 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
98 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,101 +1,103
1
1
2 gui_moc_headers = [
2 gui_moc_headers = [
3 'include/DataSource/DataSourceWidget.h',
3 'include/DataSource/DataSourceWidget.h',
4 'include/Settings/SqpSettingsDialog.h',
4 'include/Settings/SqpSettingsDialog.h',
5 'include/Settings/SqpSettingsGeneralWidget.h',
5 'include/Settings/SqpSettingsGeneralWidget.h',
6 'include/SidePane/SqpSidePane.h',
6 'include/SidePane/SqpSidePane.h',
7 'include/SqpApplication.h',
7 'include/SqpApplication.h',
8 'include/DragAndDrop/DragDropScroller.h',
8 'include/DragAndDrop/DragDropScroller.h',
9 'include/DragAndDrop/DragDropTabSwitcher.h',
9 'include/DragAndDrop/DragDropTabSwitcher.h',
10 'include/TimeWidget/TimeWidget.h',
10 'include/TimeWidget/TimeWidget.h',
11 'include/Variable/VariableInspectorWidget.h',
11 'include/Variable/VariableInspectorWidget.h',
12 'include/Variable/RenameVariableDialog.h',
12 'include/Variable/RenameVariableDialog.h',
13 'include/Visualization/qcustomplot.h',
13 'include/Visualization/qcustomplot.h',
14 'include/Visualization/VisualizationGraphWidget.h',
14 'include/Visualization/VisualizationGraphWidget.h',
15 'include/Visualization/VisualizationTabWidget.h',
15 'include/Visualization/VisualizationTabWidget.h',
16 'include/Visualization/VisualizationWidget.h',
16 'include/Visualization/VisualizationWidget.h',
17 'include/Visualization/VisualizationZoneWidget.h',
17 'include/Visualization/VisualizationZoneWidget.h',
18 'include/Visualization/VisualizationDragDropContainer.h',
18 'include/Visualization/VisualizationDragDropContainer.h',
19 'include/Visualization/VisualizationDragWidget.h',
19 'include/Visualization/VisualizationDragWidget.h',
20 'include/Visualization/ColorScaleEditor.h'
20 'include/Visualization/ColorScaleEditor.h'
21 ]
21 ]
22
22
23 gui_ui_files = [
23 gui_ui_files = [
24 'ui/DataSource/DataSourceWidget.ui',
24 'ui/DataSource/DataSourceWidget.ui',
25 'ui/Settings/SqpSettingsDialog.ui',
25 'ui/Settings/SqpSettingsDialog.ui',
26 'ui/Settings/SqpSettingsGeneralWidget.ui',
26 'ui/Settings/SqpSettingsGeneralWidget.ui',
27 'ui/SidePane/SqpSidePane.ui',
27 'ui/SidePane/SqpSidePane.ui',
28 'ui/TimeWidget/TimeWidget.ui',
28 'ui/TimeWidget/TimeWidget.ui',
29 'ui/Variable/VariableInspectorWidget.ui',
29 'ui/Variable/VariableInspectorWidget.ui',
30 'ui/Variable/RenameVariableDialog.ui',
30 'ui/Variable/RenameVariableDialog.ui',
31 'ui/Variable/VariableMenuHeaderWidget.ui',
31 'ui/Variable/VariableMenuHeaderWidget.ui',
32 'ui/Visualization/VisualizationGraphWidget.ui',
32 'ui/Visualization/VisualizationGraphWidget.ui',
33 'ui/Visualization/VisualizationTabWidget.ui',
33 'ui/Visualization/VisualizationTabWidget.ui',
34 'ui/Visualization/VisualizationWidget.ui',
34 'ui/Visualization/VisualizationWidget.ui',
35 'ui/Visualization/VisualizationZoneWidget.ui',
35 'ui/Visualization/VisualizationZoneWidget.ui',
36 'ui/Visualization/ColorScaleEditor.ui'
36 'ui/Visualization/ColorScaleEditor.ui'
37 ]
37 ]
38
38
39 gui_qresources = ['resources/sqpguiresources.qrc']
39 gui_qresources = ['resources/sqpguiresources.qrc']
40
40
41 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
41 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
42 ui_files : gui_ui_files,
42 ui_files : gui_ui_files,
43 qresources : gui_qresources)
43 qresources : gui_qresources)
44
44
45 gui_sources = [
45 gui_sources = [
46 'src/SqpApplication.cpp',
46 'src/SqpApplication.cpp',
47 'src/DragAndDrop/DragDropHelper.cpp',
47 'src/DragAndDrop/DragDropHelper.cpp',
48 'src/DragAndDrop/DragDropScroller.cpp',
48 'src/DragAndDrop/DragDropScroller.cpp',
49 'src/DragAndDrop/DragDropTabSwitcher.cpp',
49 'src/DragAndDrop/DragDropTabSwitcher.cpp',
50 'src/Common/ColorUtils.cpp',
50 'src/Common/ColorUtils.cpp',
51 'src/Common/VisualizationDef.cpp',
51 'src/Common/VisualizationDef.cpp',
52 'src/DataSource/DataSourceTreeWidgetItem.cpp',
52 'src/DataSource/DataSourceTreeWidgetItem.cpp',
53 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
53 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
54 'src/DataSource/DataSourceWidget.cpp',
54 'src/DataSource/DataSourceWidget.cpp',
55 'src/DataSource/DataSourceTreeWidget.cpp',
55 'src/DataSource/DataSourceTreeWidget.cpp',
56 'src/Settings/SqpSettingsDialog.cpp',
56 'src/Settings/SqpSettingsDialog.cpp',
57 'src/Settings/SqpSettingsGeneralWidget.cpp',
57 'src/Settings/SqpSettingsGeneralWidget.cpp',
58 'src/SidePane/SqpSidePane.cpp',
58 'src/SidePane/SqpSidePane.cpp',
59 'src/TimeWidget/TimeWidget.cpp',
59 'src/TimeWidget/TimeWidget.cpp',
60 'src/Variable/VariableInspectorWidget.cpp',
60 'src/Variable/VariableInspectorWidget.cpp',
61 'src/Variable/VariableInspectorTableView.cpp',
61 'src/Variable/VariableInspectorTableView.cpp',
62 'src/Variable/VariableMenuHeaderWidget.cpp',
62 'src/Variable/VariableMenuHeaderWidget.cpp',
63 'src/Variable/RenameVariableDialog.cpp',
63 'src/Variable/RenameVariableDialog.cpp',
64 'src/Visualization/VisualizationGraphHelper.cpp',
64 'src/Visualization/VisualizationGraphHelper.cpp',
65 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
65 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
66 'src/Visualization/VisualizationGraphWidget.cpp',
66 'src/Visualization/VisualizationGraphWidget.cpp',
67 'src/Visualization/VisualizationTabWidget.cpp',
67 'src/Visualization/VisualizationTabWidget.cpp',
68 'src/Visualization/VisualizationWidget.cpp',
68 'src/Visualization/VisualizationWidget.cpp',
69 'src/Visualization/VisualizationZoneWidget.cpp',
69 'src/Visualization/VisualizationZoneWidget.cpp',
70 'src/Visualization/qcustomplot.cpp',
70 'src/Visualization/qcustomplot.cpp',
71 'src/Visualization/QCustomPlotSynchronizer.cpp',
71 'src/Visualization/QCustomPlotSynchronizer.cpp',
72 'src/Visualization/operations/FindVariableOperation.cpp',
72 'src/Visualization/operations/FindVariableOperation.cpp',
73 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
73 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
74 'src/Visualization/operations/MenuBuilder.cpp',
74 'src/Visualization/operations/MenuBuilder.cpp',
75 'src/Visualization/operations/RemoveVariableOperation.cpp',
75 'src/Visualization/operations/RemoveVariableOperation.cpp',
76 'src/Visualization/operations/RescaleAxeOperation.cpp',
76 'src/Visualization/operations/RescaleAxeOperation.cpp',
77 'src/Visualization/VisualizationDragDropContainer.cpp',
77 'src/Visualization/VisualizationDragDropContainer.cpp',
78 'src/Visualization/VisualizationDragWidget.cpp',
78 'src/Visualization/VisualizationDragWidget.cpp',
79 'src/Visualization/AxisRenderingUtils.cpp',
79 'src/Visualization/AxisRenderingUtils.cpp',
80 'src/Visualization/PlottablesRenderingUtils.cpp',
80 'src/Visualization/PlottablesRenderingUtils.cpp',
81 'src/Visualization/MacScrollBarStyle.cpp',
81 'src/Visualization/MacScrollBarStyle.cpp',
82 'src/Visualization/VisualizationCursorItem.cpp',
82 'src/Visualization/VisualizationCursorItem.cpp',
83 'src/Visualization/ColorScaleEditor.cpp',
83 'src/Visualization/ColorScaleEditor.cpp',
84 'src/Visualization/SqpColorScale.cpp',
84 'src/Visualization/SqpColorScale.cpp',
85 'src/Visualization/QCPColorMapIterator.cpp'
85 'src/Visualization/QCPColorMapIterator.cpp',
86 'src/Visualization/VisualizationSelectionZoneItem.cpp',
87 'src/Visualization/VisualizationSelectionZoneManager.cpp'
86 ]
88 ]
87
89
88 gui_inc = include_directories(['include'])
90 gui_inc = include_directories(['include'])
89
91
90 sciqlop_gui_lib = library('sciqlopgui',
92 sciqlop_gui_lib = library('sciqlopgui',
91 gui_sources,
93 gui_sources,
92 gui_moc_files,
94 gui_moc_files,
93 include_directories : [gui_inc],
95 include_directories : [gui_inc],
94 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
96 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
95 install : true
97 install : true
96 )
98 )
97
99
98 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
100 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
99 include_directories : gui_inc,
101 include_directories : gui_inc,
100 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
102 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
101
103
@@ -1,492 +1,499
1 #include "Visualization/VisualizationDragDropContainer.h"
1 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "DragAndDrop/DragDropHelper.h"
2 #include "DragAndDrop/DragDropHelper.h"
3 #include "SqpApplication.h"
3 #include "SqpApplication.h"
4 #include "Visualization/VisualizationDragWidget.h"
4 #include "Visualization/VisualizationDragWidget.h"
5
5
6 #include "Common/VisualizationDef.h"
6 #include "Common/VisualizationDef.h"
7
7
8 #include <QDrag>
8 #include <QDrag>
9 #include <QDragEnterEvent>
9 #include <QDragEnterEvent>
10 #include <QVBoxLayout>
10 #include <QVBoxLayout>
11
11
12 #include <cmath>
12 #include <cmath>
13 #include <memory>
13 #include <memory>
14
14
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
16
16
17 auto DRAGGED_MINIATURE_WIDTH = 200; // in pixels
17 auto DRAGGED_MINIATURE_WIDTH = 200; // in pixels
18
18
19 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
19 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
20
20
21 QVBoxLayout *m_Layout;
21 QVBoxLayout *m_Layout;
22 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
22 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
23 QString m_PlaceHolderText;
23 QString m_PlaceHolderText;
24 DragDropHelper::PlaceHolderType m_PlaceHolderType;
24 DragDropHelper::PlaceHolderType m_PlaceHolderType;
25
25
26 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
26 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
27 = [](auto mimeData) { return true; };
27 = [](auto mimeData) { return true; };
28 VisualizationDragDropContainer::AcceptDragWidgetFunction m_AcceptDragWidgetFun
28 VisualizationDragDropContainer::AcceptDragWidgetFunction m_AcceptDragWidgetFun
29 = [](auto dragWidget, auto mimeData) { return true; };
29 = [](auto dragWidget, auto mimeData) { return true; };
30
30
31 int m_MinContainerHeight = 0;
31 int m_MinContainerHeight = 0;
32
32
33 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
33 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
34 : m_PlaceHolderType(DragDropHelper::PlaceHolderType::Graph)
34 : m_PlaceHolderType(DragDropHelper::PlaceHolderType::Graph)
35 {
35 {
36 m_Layout = new QVBoxLayout(widget);
36 m_Layout = new QVBoxLayout(widget);
37 m_Layout->setContentsMargins(0, 0, 0, 0);
37 m_Layout->setContentsMargins(0, 0, 0, 0);
38 }
38 }
39
39
40 bool acceptMimeData(const QMimeData *data) const
40 bool acceptMimeData(const QMimeData *data) const
41 {
41 {
42 auto accepted = false;
42 auto accepted = false;
43 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
43 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
44 ++it) {
44 ++it) {
45 const auto &type = it.key();
45 const auto &type = it.key();
46 const auto &behavior = it.value();
46 const auto &behavior = it.value();
47
47
48 if (data->hasFormat(type)) {
48 if (data->hasFormat(type)) {
49 if (behavior != DropBehavior::Forbidden) {
49 if (behavior != DropBehavior::Forbidden) {
50 accepted = true;
50 accepted = true;
51 }
51 }
52 else {
52 else {
53 accepted = false;
53 accepted = false;
54 break;
54 break;
55 }
55 }
56 }
56 }
57 }
57 }
58
58
59 if (accepted) {
59 if (accepted) {
60 accepted = m_AcceptMimeDataFun(data);
60 accepted = m_AcceptMimeDataFun(data);
61 }
61 }
62
62
63 return accepted;
63 return accepted;
64 }
64 }
65
65
66 bool allowMergeForMimeData(const QMimeData *data) const
66 bool allowMergeForMimeData(const QMimeData *data) const
67 {
67 {
68 auto result = false;
68 auto result = false;
69 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
69 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
70 ++it) {
70 ++it) {
71
71
72 if (data->hasFormat(it.key())
72 if (data->hasFormat(it.key())
73 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
73 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
74 || it.value()
74 || it.value()
75 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
75 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
76 result = true;
76 result = true;
77 }
77 }
78 else if (data->hasFormat(it.key())
78 else if (data->hasFormat(it.key())
79 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
79 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
80 // Merge is forbidden if the mime data contain an acceptable type which cannot be
80 // Merge is forbidden if the mime data contain an acceptable type which cannot be
81 // merged
81 // merged
82 result = false;
82 result = false;
83 break;
83 break;
84 }
84 }
85 }
85 }
86
86
87 return result;
87 return result;
88 }
88 }
89
89
90 bool allowInsertForMimeData(const QMimeData *data) const
90 bool allowInsertForMimeData(const QMimeData *data) const
91 {
91 {
92 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
92 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
93 ++it) {
93 ++it) {
94 if (data->hasFormat(it.key())
94 if (data->hasFormat(it.key())
95 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
95 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
96 || it.value()
96 || it.value()
97 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
97 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
98 return true;
98 return true;
99 }
99 }
100 }
100 }
101
101
102 return false;
102 return false;
103 }
103 }
104
104
105 bool hasPlaceHolder() const
105 bool hasPlaceHolder() const
106 {
106 {
107 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
107 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
108 }
108 }
109
109
110 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
110 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
111 {
111 {
112 VisualizationDragWidget *dragWidget = nullptr;
112 VisualizationDragWidget *dragWidget = nullptr;
113
113
114 for (auto child : parent->children()) {
114 for (auto child : parent->children()) {
115 auto widget = qobject_cast<VisualizationDragWidget *>(child);
115 auto widget = qobject_cast<VisualizationDragWidget *>(child);
116 if (widget && widget->isVisible()) {
116 if (widget && widget->isVisible()) {
117 if (widget->frameGeometry().contains(pos)) {
117 if (widget->frameGeometry().contains(pos)) {
118 dragWidget = widget;
118 dragWidget = widget;
119 break;
119 break;
120 }
120 }
121 }
121 }
122 }
122 }
123
123
124 return dragWidget;
124 return dragWidget;
125 }
125 }
126
126
127 bool cursorIsInContainer(QWidget *container) const
127 bool cursorIsInContainer(QWidget *container) const
128 {
128 {
129 auto widgetUnderMouse = sqpApp->widgetAt(QCursor::pos());
129 auto widgetUnderMouse = sqpApp->widgetAt(QCursor::pos());
130 return container->isAncestorOf(widgetUnderMouse) && widgetUnderMouse != container
130 return container->isAncestorOf(widgetUnderMouse) && widgetUnderMouse != container
131 && sqpApp->dragDropHelper().placeHolder().isAncestorOf(widgetUnderMouse);
131 && sqpApp->dragDropHelper().placeHolder().isAncestorOf(widgetUnderMouse);
132 }
132 }
133
133
134 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
134 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
135 {
135 {
136 auto nbGraph = 0;
136 auto nbGraph = 0;
137 for (auto child : parent->children()) {
137 for (auto child : parent->children()) {
138 if (qobject_cast<VisualizationDragWidget *>(child)) {
138 if (qobject_cast<VisualizationDragWidget *>(child)) {
139 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
139 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
140 nbGraph += 1;
140 nbGraph += 1;
141 }
141 }
142 }
142 }
143 }
143 }
144
144
145 return nbGraph;
145 return nbGraph;
146 }
146 }
147
147
148 bool findPlaceHolderPosition(const QPoint &pos, const QMimeData *mimeData, bool canInsert,
148 bool findPlaceHolderPosition(const QPoint &pos, const QMimeData *mimeData, bool canInsert,
149 bool canMerge, const VisualizationDragDropContainer *container);
149 bool canMerge, const VisualizationDragDropContainer *container);
150 };
150 };
151
151
152 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
152 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
153 : QFrame{parent},
153 : QFrame{parent},
154 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
154 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
155 {
155 {
156 setAcceptDrops(true);
156 setAcceptDrops(true);
157 }
157 }
158
158
159 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
159 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
160 {
160 {
161 impl->m_Layout->addWidget(dragWidget);
161 impl->m_Layout->addWidget(dragWidget);
162 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
162 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
163 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
163 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
164 &VisualizationDragDropContainer::startDrag);
164 &VisualizationDragDropContainer::startDrag);
165 }
165 }
166
166
167 void VisualizationDragDropContainer::insertDragWidget(int index,
167 void VisualizationDragDropContainer::insertDragWidget(int index,
168 VisualizationDragWidget *dragWidget)
168 VisualizationDragWidget *dragWidget)
169 {
169 {
170 impl->m_Layout->insertWidget(index, dragWidget);
170 impl->m_Layout->insertWidget(index, dragWidget);
171 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
171 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
172 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
172 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
173 &VisualizationDragDropContainer::startDrag);
173 &VisualizationDragDropContainer::startDrag);
174 }
174 }
175
175
176 void VisualizationDragDropContainer::setMimeType(
176 void VisualizationDragDropContainer::setMimeType(
177 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
177 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
178 {
178 {
179 impl->m_AcceptedMimeTypes[mimeType] = behavior;
179 impl->m_AcceptedMimeTypes[mimeType] = behavior;
180 }
180 }
181
181
182 int VisualizationDragDropContainer::countDragWidget() const
182 int VisualizationDragDropContainer::countDragWidget() const
183 {
183 {
184 return impl->countDragWidget(this);
184 return impl->countDragWidget(this);
185 }
185 }
186
186
187 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
187 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
188 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
188 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
189 {
189 {
190 impl->m_AcceptMimeDataFun = fun;
190 impl->m_AcceptMimeDataFun = fun;
191 }
191 }
192
192
193 void VisualizationDragDropContainer::setAcceptDragWidgetFunction(
193 void VisualizationDragDropContainer::setAcceptDragWidgetFunction(
194 VisualizationDragDropContainer::AcceptDragWidgetFunction fun)
194 VisualizationDragDropContainer::AcceptDragWidgetFunction fun)
195 {
195 {
196 impl->m_AcceptDragWidgetFun = fun;
196 impl->m_AcceptDragWidgetFun = fun;
197 }
197 }
198
198
199 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
199 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
200 const QString &placeHolderText)
200 const QString &placeHolderText)
201 {
201 {
202 impl->m_PlaceHolderType = type;
202 impl->m_PlaceHolderType = type;
203 impl->m_PlaceHolderText = placeHolderText;
203 impl->m_PlaceHolderText = placeHolderText;
204 }
204 }
205
205
206 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
206 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
207 const QPoint &dragPosition)
207 const QPoint &dragPosition)
208 {
208 {
209 auto &helper = sqpApp->dragDropHelper();
209 auto &helper = sqpApp->dragDropHelper();
210 helper.resetDragAndDrop();
210 helper.resetDragAndDrop();
211
211
212 // Note: The management of the drag object is done by Qt
212 // Note: The management of the drag object is done by Qt
213 auto drag = new QDrag{dragWidget};
213 auto drag = new QDrag{dragWidget};
214
214
215 auto mimeData = dragWidget->mimeData();
215 auto mimeData = dragWidget->mimeData(dragPosition);
216 drag->setMimeData(mimeData);
216 drag->setMimeData(mimeData);
217
217
218 auto pixmap = QPixmap(dragWidget->size());
218 auto pixmap = dragWidget->customDragPixmap(dragPosition);
219 if (pixmap.isNull()) {
220 pixmap = QPixmap{dragWidget->size()};
219 dragWidget->render(&pixmap);
221 dragWidget->render(&pixmap);
222 }
223
220 drag->setPixmap(pixmap.scaled(DRAGGED_MINIATURE_WIDTH, DRAGGED_MINIATURE_WIDTH,
224 drag->setPixmap(pixmap.scaled(DRAGGED_MINIATURE_WIDTH, DRAGGED_MINIATURE_WIDTH,
221 Qt::KeepAspectRatio, Qt::SmoothTransformation));
225 Qt::KeepAspectRatio, Qt::SmoothTransformation));
222
226
223 auto image = pixmap.toImage();
227 auto image = pixmap.toImage();
224 mimeData->setImageData(image);
228 mimeData->setImageData(image);
225 mimeData->setUrls({helper.imageTemporaryUrl(image)});
229 mimeData->setUrls({helper.imageTemporaryUrl(image)});
226
230
227 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
231 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
232
233 if (impl->acceptMimeData(mimeData) && impl->allowInsertForMimeData(mimeData)) {
228 helper.setCurrentDragWidget(dragWidget);
234 helper.setCurrentDragWidget(dragWidget);
229
235
230 if (impl->cursorIsInContainer(this)) {
236 if (impl->cursorIsInContainer(this)) {
231 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
237 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
232 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
238 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
233 impl->m_PlaceHolderText);
239 impl->m_PlaceHolderText);
234 dragWidget->setVisible(false);
240 dragWidget->setVisible(false);
235 }
241 }
236 else {
242 else {
237 // The drag starts directly outside the drop zone
243 // The drag starts directly outside the drop zone
238 // do not add the placeHolder
244 // do not add the placeHolder
239 }
245 }
246 }
240
247
241 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
248 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
242
249
243 helper.doCloseWidgets();
250 helper.doCloseWidgets();
244 }
251 }
245 else {
252 else {
246 qCWarning(LOG_VisualizationDragDropContainer())
253 qCWarning(LOG_VisualizationDragDropContainer())
247 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
254 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
248 "VisualizationDragWidget is not found in this container.");
255 "VisualizationDragWidget is not found in this container.");
249 }
256 }
250 }
257 }
251
258
252 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
259 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
253 {
260 {
254 if (impl->acceptMimeData(event->mimeData())) {
261 if (impl->acceptMimeData(event->mimeData())) {
255 event->acceptProposedAction();
262 event->acceptProposedAction();
256
263
257 auto &helper = sqpApp->dragDropHelper();
264 auto &helper = sqpApp->dragDropHelper();
258
265
259 if (!impl->hasPlaceHolder()) {
266 if (!impl->hasPlaceHolder()) {
260 auto dragWidget = helper.getCurrentDragWidget();
267 auto dragWidget = helper.getCurrentDragWidget();
261
268
262 if (dragWidget) {
269 if (dragWidget) {
263 // If the drag&drop is internal to the visualization, entering the container hide
270 // If the drag&drop is internal to the visualization, entering the container hide
264 // the dragWidget which was made visible by the dragLeaveEvent
271 // the dragWidget which was made visible by the dragLeaveEvent
265 auto parentWidget
272 auto parentWidget
266 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
273 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
267 if (parentWidget) {
274 if (parentWidget) {
268 dragWidget->setVisible(false);
275 dragWidget->setVisible(false);
269 }
276 }
270 }
277 }
271
278
272 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
279 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
273 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
280 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
274 if (!impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge,
281 if (!impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge,
275 this)) {
282 this)) {
276 event->ignore();
283 event->ignore();
277 }
284 }
278 }
285 }
279 else {
286 else {
280 // do nothing
287 // do nothing
281 }
288 }
282 }
289 }
283 else {
290 else {
284 event->ignore();
291 event->ignore();
285 }
292 }
286
293
287 QWidget::dragEnterEvent(event);
294 QWidget::dragEnterEvent(event);
288 }
295 }
289
296
290 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
297 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
291 {
298 {
292 Q_UNUSED(event);
299 Q_UNUSED(event);
293
300
294 auto &helper = sqpApp->dragDropHelper();
301 auto &helper = sqpApp->dragDropHelper();
295
302
296 if (!impl->cursorIsInContainer(this)) {
303 if (!impl->cursorIsInContainer(this)) {
297 helper.removePlaceHolder();
304 helper.removePlaceHolder();
298 helper.setHightlightedDragWidget(nullptr);
305 helper.setHightlightedDragWidget(nullptr);
299 impl->m_MinContainerHeight = 0;
306 impl->m_MinContainerHeight = 0;
300
307
301 auto dragWidget = helper.getCurrentDragWidget();
308 auto dragWidget = helper.getCurrentDragWidget();
302 if (dragWidget) {
309 if (dragWidget) {
303 // dragWidget has a value only if the drag is started from the visualization
310 // dragWidget has a value only if the drag is started from the visualization
304 // In that case, shows the drag widget at its original place
311 // In that case, shows the drag widget at its original place
305 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
312 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
306 // drop zone (It is not possible to catch a drop event outside of the application)
313 // drop zone (It is not possible to catch a drop event outside of the application)
307
314
308 if (dragWidget) {
315 if (dragWidget) {
309 dragWidget->setVisible(true);
316 dragWidget->setVisible(true);
310 }
317 }
311 }
318 }
312 }
319 }
313 else {
320 else {
314 // Leave event probably received for a child widget.
321 // Leave event probably received for a child widget.
315 // Do nothing.
322 // Do nothing.
316 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
323 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
317 }
324 }
318
325
319 QWidget::dragLeaveEvent(event);
326 QWidget::dragLeaveEvent(event);
320 }
327 }
321
328
322 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
329 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
323 {
330 {
324 if (impl->acceptMimeData(event->mimeData())) {
331 if (impl->acceptMimeData(event->mimeData())) {
325 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
332 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
326 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
333 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
327 impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge, this);
334 impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge, this);
328 }
335 }
329 else {
336 else {
330 event->ignore();
337 event->ignore();
331 }
338 }
332
339
333 QWidget::dragMoveEvent(event);
340 QWidget::dragMoveEvent(event);
334 }
341 }
335
342
336 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
343 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
337 {
344 {
338 auto &helper = sqpApp->dragDropHelper();
345 auto &helper = sqpApp->dragDropHelper();
339
346
340 if (impl->acceptMimeData(event->mimeData())) {
347 if (impl->acceptMimeData(event->mimeData())) {
341 auto dragWidget = helper.getCurrentDragWidget();
348 auto dragWidget = helper.getCurrentDragWidget();
342 if (impl->hasPlaceHolder()) {
349 if (impl->hasPlaceHolder()) {
343 // drop where the placeHolder is located
350 // drop where the placeHolder is located
344
351
345 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
352 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
346 if (canInsert) {
353 if (canInsert) {
347 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
354 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
348
355
349 if (dragWidget) {
356 if (dragWidget) {
350 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
357 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
351 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
358 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
352 // Correction of the index if the drop occurs in the same container
359 // Correction of the index if the drop occurs in the same container
353 // and if the drag is started from the visualization (in that case, the
360 // and if the drag is started from the visualization (in that case, the
354 // dragWidget is hidden)
361 // dragWidget is hidden)
355 droppedIndex -= 1;
362 droppedIndex -= 1;
356 }
363 }
357
364
358 dragWidget->setVisible(true);
365 dragWidget->setVisible(true);
359 }
366 }
360
367
361 event->acceptProposedAction();
368 event->acceptProposedAction();
362
369
363 helper.removePlaceHolder();
370 helper.removePlaceHolder();
364
371
365 emit dropOccuredInContainer(droppedIndex, event->mimeData());
372 emit dropOccuredInContainer(droppedIndex, event->mimeData());
366 }
373 }
367 else {
374 else {
368 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
375 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
369 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
376 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
370 "the insertion is forbidden.");
377 "the insertion is forbidden.");
371 Q_ASSERT(false);
378 Q_ASSERT(false);
372 }
379 }
373 }
380 }
374 else if (helper.getHightlightedDragWidget()) {
381 else if (helper.getHightlightedDragWidget()) {
375 // drop on the highlighted widget
382 // drop on the highlighted widget
376
383
377 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
384 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
378 if (canMerge) {
385 if (canMerge) {
379 event->acceptProposedAction();
386 event->acceptProposedAction();
380 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
387 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
381 }
388 }
382 else {
389 else {
383 qCWarning(LOG_VisualizationDragDropContainer())
390 qCWarning(LOG_VisualizationDragDropContainer())
384 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
391 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
385 "the merge is forbidden.");
392 "the merge is forbidden.");
386 Q_ASSERT(false);
393 Q_ASSERT(false);
387 }
394 }
388 }
395 }
389 }
396 }
390 else {
397 else {
391 event->ignore();
398 event->ignore();
392 }
399 }
393
400
394 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
401 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
395 impl->m_MinContainerHeight = 0;
402 impl->m_MinContainerHeight = 0;
396
403
397 QWidget::dropEvent(event);
404 QWidget::dropEvent(event);
398 }
405 }
399
406
400
407
401 bool VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
408 bool VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
402 const QPoint &pos, const QMimeData *mimeData, bool canInsert, bool canMerge,
409 const QPoint &pos, const QMimeData *mimeData, bool canInsert, bool canMerge,
403 const VisualizationDragDropContainer *container)
410 const VisualizationDragDropContainer *container)
404 {
411 {
405 auto &helper = sqpApp->dragDropHelper();
412 auto &helper = sqpApp->dragDropHelper();
406
413
407 auto absPos = container->mapToGlobal(pos);
414 auto absPos = container->mapToGlobal(pos);
408 auto isOnPlaceHolder = helper.placeHolder().isAncestorOf(sqpApp->widgetAt(absPos));
415 auto isOnPlaceHolder = helper.placeHolder().isAncestorOf(sqpApp->widgetAt(absPos));
409
416
410 if (countDragWidget(container, true) == 0) {
417 if (countDragWidget(container, true) == 0) {
411 // Drop on an empty container, just add the placeHolder at the top
418 // Drop on an empty container, just add the placeHolder at the top
412 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
419 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
413 }
420 }
414 else if (!isOnPlaceHolder) {
421 else if (!isOnPlaceHolder) {
415 auto nbDragWidget = countDragWidget(container);
422 auto nbDragWidget = countDragWidget(container);
416 if (nbDragWidget > 0) {
423 if (nbDragWidget > 0) {
417
424
418 if (m_MinContainerHeight == 0) {
425 if (m_MinContainerHeight == 0) {
419 m_MinContainerHeight = container->size().height();
426 m_MinContainerHeight = container->size().height();
420 }
427 }
421
428
422 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
429 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
423 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
430 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
424
431
425 auto posY = pos.y();
432 auto posY = pos.y();
426 auto dropIndex = floor(posY / graphHeight);
433 auto dropIndex = floor(posY / graphHeight);
427 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
434 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
428
435
429
436
430 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
437 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
431 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
438 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
432
439
433 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
440 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
434
441
435 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
442 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
436
443
437 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
444 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
438 if (isOnBottom) {
445 if (isOnBottom) {
439 dropIndex += 1;
446 dropIndex += 1;
440 }
447 }
441
448
442 if (helper.getCurrentDragWidget()) {
449 if (helper.getCurrentDragWidget()) {
443 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
450 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
444 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
451 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
445 // Correction of the index if the drop occurs in the same container
452 // Correction of the index if the drop occurs in the same container
446 // and if the drag is started from the visualization (in that case, the
453 // and if the drag is started from the visualization (in that case, the
447 // dragWidget is hidden)
454 // dragWidget is hidden)
448 dropIndex += 1;
455 dropIndex += 1;
449 }
456 }
450 }
457 }
451
458
452 if (dropIndex != placeHolderIndex) {
459 if (dropIndex != placeHolderIndex) {
453 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
460 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
454 m_PlaceHolderText);
461 m_PlaceHolderText);
455 }
462 }
456
463
457 helper.setHightlightedDragWidget(nullptr);
464 helper.setHightlightedDragWidget(nullptr);
458 }
465 }
459 else if (canMerge && dragWidgetHovered) {
466 else if (canMerge && dragWidgetHovered) {
460 // drop on the middle -> merge
467 // drop on the middle -> merge
461 if (hasPlaceHolder()) {
468 if (hasPlaceHolder()) {
462 helper.removePlaceHolder();
469 helper.removePlaceHolder();
463 }
470 }
464
471
465 if (m_AcceptDragWidgetFun(dragWidgetHovered, mimeData)) {
472 if (m_AcceptDragWidgetFun(dragWidgetHovered, mimeData)) {
466 helper.setHightlightedDragWidget(dragWidgetHovered);
473 helper.setHightlightedDragWidget(dragWidgetHovered);
467 return true;
474 return true;
468 }
475 }
469 else {
476 else {
470 return false;
477 return false;
471 }
478 }
472 }
479 }
473 else {
480 else {
474 qCWarning(LOG_VisualizationDragDropContainer())
481 qCWarning(LOG_VisualizationDragDropContainer())
475 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
482 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
476 "action.");
483 "action.");
477 }
484 }
478 }
485 }
479 else {
486 else {
480 qCWarning(LOG_VisualizationDragDropContainer())
487 qCWarning(LOG_VisualizationDragDropContainer())
481 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
488 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
482 "found in the "
489 "found in the "
483 "container");
490 "container");
484 }
491 }
485 }
492 }
486 else {
493 else {
487 // the mouse is hover the placeHolder
494 // the mouse is hover the placeHolder
488 // Do nothing
495 // Do nothing
489 }
496 }
490
497
491 return true;
498 return true;
492 }
499 }
@@ -1,55 +1,61
1 #include "Visualization/VisualizationDragWidget.h"
1 #include "Visualization/VisualizationDragWidget.h"
2 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "Visualization/VisualizationDragDropContainer.h"
3
3
4 #include <QApplication>
4 #include <QApplication>
5 #include <QMouseEvent>
5 #include <QMouseEvent>
6
6
7 #include <SqpApplication.h>
7 #include <SqpApplication.h>
8
8
9 struct VisualizationDragWidget::VisualizationDragWidgetPrivate {
9 struct VisualizationDragWidget::VisualizationDragWidgetPrivate {
10
10
11 QPoint m_DragStartPosition;
11 QPoint m_DragStartPosition;
12 bool m_DragStartPositionValid = false;
12 bool m_DragStartPositionValid = false;
13
13
14 explicit VisualizationDragWidgetPrivate() {}
14 explicit VisualizationDragWidgetPrivate() {}
15 };
15 };
16
16
17 VisualizationDragWidget::VisualizationDragWidget(QWidget *parent)
17 VisualizationDragWidget::VisualizationDragWidget(QWidget *parent)
18 : QWidget{parent}, impl{spimpl::make_unique_impl<VisualizationDragWidgetPrivate>()}
18 : QWidget{parent}, impl{spimpl::make_unique_impl<VisualizationDragWidgetPrivate>()}
19 {
19 {
20 }
20 }
21
21
22 QPixmap VisualizationDragWidget::customDragPixmap(const QPoint &dragPosition)
23 {
24 Q_UNUSED(dragPosition);
25 return QPixmap();
26 }
27
22 void VisualizationDragWidget::mousePressEvent(QMouseEvent *event)
28 void VisualizationDragWidget::mousePressEvent(QMouseEvent *event)
23 {
29 {
24 if (event->button() == Qt::LeftButton) {
30 if (event->button() == Qt::LeftButton) {
25 impl->m_DragStartPosition = event->pos();
31 impl->m_DragStartPosition = event->pos();
26 }
32 }
27
33
28 impl->m_DragStartPositionValid = isDragAllowed();
34 impl->m_DragStartPositionValid = isDragAllowed();
29
35
30 QWidget::mousePressEvent(event);
36 QWidget::mousePressEvent(event);
31 }
37 }
32
38
33 void VisualizationDragWidget::mouseMoveEvent(QMouseEvent *event)
39 void VisualizationDragWidget::mouseMoveEvent(QMouseEvent *event)
34 {
40 {
35 if (!impl->m_DragStartPositionValid || !isDragAllowed()) {
41 if (!impl->m_DragStartPositionValid || !isDragAllowed()) {
36 return;
42 return;
37 }
43 }
38
44
39 if (!(event->buttons() & Qt::LeftButton)) {
45 if (!(event->buttons() & Qt::LeftButton)) {
40 return;
46 return;
41 }
47 }
42
48
43 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::DragAndDrop
49 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::DragAndDrop
44 || event->modifiers().testFlag(Qt::AltModifier)) {
50 || event->modifiers().testFlag(Qt::AltModifier)) {
45
51
46 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
52 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
47 < QApplication::startDragDistance()) {
53 < QApplication::startDragDistance()) {
48 return;
54 return;
49 }
55 }
50
56
51 emit dragDetected(this, impl->m_DragStartPosition);
57 emit dragDetected(this, impl->m_DragStartPosition);
52 }
58 }
53
59
54 QWidget::mouseMoveEvent(event);
60 QWidget::mouseMoveEvent(event);
55 }
61 }
@@ -1,331 +1,332
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/AxisRenderingUtils.h"
2 #include "Visualization/AxisRenderingUtils.h"
3 #include "Visualization/ColorScaleEditor.h"
3 #include "Visualization/ColorScaleEditor.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
5 #include "Visualization/SqpColorScale.h"
5 #include "Visualization/SqpColorScale.h"
6 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationGraphWidget.h"
7 #include "Visualization/qcustomplot.h"
7 #include "Visualization/qcustomplot.h"
8
8
9 #include <Common/DateUtils.h>
9 #include <Common/DateUtils.h>
10
10
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12
12
13 #include <SqpApplication.h>
13 #include <SqpApplication.h>
14
14
15 namespace {
15 namespace {
16
16
17 /// Name of the axes layer in QCustomPlot
17 /// Name of the axes layer in QCustomPlot
18 const auto AXES_LAYER = QStringLiteral("axes");
18 const auto AXES_LAYER = QStringLiteral("axes");
19
19
20 /// Icon used to show x-axis properties
20 /// Icon used to show x-axis properties
21 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
21 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
22
22
23 /// Name of the overlay layer in QCustomPlot
23 /// Name of the overlay layer in QCustomPlot
24 const auto OVERLAY_LAYER = QStringLiteral("overlay");
24 const auto OVERLAY_LAYER = QStringLiteral("overlay");
25
25
26 /// Pixmap used to show x-axis properties
26 /// Pixmap used to show x-axis properties
27 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
27 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
28
28
29 /// Tooltip format for graphs
29 /// Tooltip format for graphs
30 const auto GRAPH_TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
30 const auto GRAPH_TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
31
31
32 /// Tooltip format for colormaps
32 /// Tooltip format for colormaps
33 const auto COLORMAP_TOOLTIP_FORMAT = QStringLiteral("x: %1\ny: %2\nvalue: %3");
33 const auto COLORMAP_TOOLTIP_FORMAT = QStringLiteral("x: %1\ny: %2\nvalue: %3");
34
34
35 /// Offset used to shift the tooltip of the mouse
35 /// Offset used to shift the tooltip of the mouse
36 const auto TOOLTIP_OFFSET = QPoint{20, 20};
36 const auto TOOLTIP_OFFSET = QPoint{20, 20};
37
37
38 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
38 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
39 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
39 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
40
40
41 /// Timeout after which the tooltip is displayed
41 /// Timeout after which the tooltip is displayed
42 const auto TOOLTIP_TIMEOUT = 500;
42 const auto TOOLTIP_TIMEOUT = 500;
43
43
44 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
44 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
45 {
45 {
46 tracer.setInterpolating(false);
46 tracer.setInterpolating(false);
47 tracer.setStyle(QCPItemTracer::tsCircle);
47 tracer.setStyle(QCPItemTracer::tsCircle);
48 tracer.setSize(3);
48 tracer.setSize(3);
49 tracer.setPen(QPen(Qt::black));
49 tracer.setPen(QPen(Qt::black));
50 tracer.setBrush(Qt::black);
50 tracer.setBrush(Qt::black);
51 tracer.setSelectable(false);
51 }
52 }
52
53
53 QPixmap pixmap(const QString &iconPath) noexcept
54 QPixmap pixmap(const QString &iconPath) noexcept
54 {
55 {
55 return QIcon{iconPath}.pixmap(QSize{16, 16});
56 return QIcon{iconPath}.pixmap(QSize{16, 16});
56 }
57 }
57
58
58 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
59 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
59 {
60 {
60 // Icon
61 // Icon
61 pixmap.setPixmap(
62 pixmap.setPixmap(
62 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
63 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
63
64
64 // Position
65 // Position
65 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
66 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
66 pixmap.topLeft->setCoords(1, 0);
67 pixmap.topLeft->setCoords(1, 0);
67 pixmap.setClipToAxisRect(false);
68 pixmap.setClipToAxisRect(false);
68
69
69 // Can be selected
70 // Can be selected
70 pixmap.setSelectable(true);
71 pixmap.setSelectable(true);
71 }
72 }
72
73
73 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
74 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
74 {
75 {
75 // Icon
76 // Icon
76 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
77 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
77
78
78 // Position
79 // Position
79 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
80 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
80 itemPixmap.topLeft->setCoords(0, 1);
81 itemPixmap.topLeft->setCoords(0, 1);
81 itemPixmap.setClipToAxisRect(false);
82 itemPixmap.setClipToAxisRect(false);
82
83
83 // Can be selected
84 // Can be selected
84 itemPixmap.setSelectable(true);
85 itemPixmap.setSelectable(true);
85 }
86 }
86
87
87 void initTitleTextStyle(QCPItemText &text) noexcept
88 void initTitleTextStyle(QCPItemText &text) noexcept
88 {
89 {
89 // Font and background styles
90 // Font and background styles
90 text.setColor(Qt::gray);
91 text.setColor(Qt::gray);
91 text.setBrush(Qt::white);
92 text.setBrush(Qt::white);
92
93
93 // Position
94 // Position
94 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
95 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
95 text.position->setType(QCPItemPosition::ptAxisRectRatio);
96 text.position->setType(QCPItemPosition::ptAxisRectRatio);
96 text.position->setCoords(0.5, 0);
97 text.position->setCoords(0.5, 0);
98 text.setSelectable(false);
97 }
99 }
98
100
99 /**
101 /**
100 * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter.
102 * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter.
101 * This method handles the fact that a colormap axis can be logarithmic or linear.
103 * This method handles the fact that a colormap axis can be logarithmic or linear.
102 * @param colormap the colormap for which to calculate the index
104 * @param colormap the colormap for which to calculate the index
103 * @param coord the coord to convert to cell index
105 * @param coord the coord to convert to cell index
104 * @param xCoord calculates the x index if true, calculates y index if false
106 * @param xCoord calculates the x index if true, calculates y index if false
105 * @return the cell index
107 * @return the cell index
106 */
108 */
107 int colorMapCellIndex(const QCPColorMap &colormap, double coord, bool xCoord)
109 int colorMapCellIndex(const QCPColorMap &colormap, double coord, bool xCoord)
108 {
110 {
109 // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not
111 // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not
110 auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType()
112 auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType()
111 == QCPAxis::stLogarithmic;
113 == QCPAxis::stLogarithmic;
112
114
113 if (isLogarithmic) {
115 if (isLogarithmic) {
114 // For a logarithmic axis we can't use the conversion method of colormap, so we calculate
116 // For a logarithmic axis we can't use the conversion method of colormap, so we calculate
115 // the index manually based on the position of the coordinate on the axis
117 // the index manually based on the position of the coordinate on the axis
116
118
117 // Gets the axis range and the number of values between range bounds to calculate the step
119 // Gets the axis range and the number of values between range bounds to calculate the step
118 // between each value of the range
120 // between each value of the range
119 auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange();
121 auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange();
120 auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1;
122 auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1;
121 auto valueStep
123 auto valueStep
122 = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues);
124 = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues);
123
125
124 // According to the coord position, calculates the closest index in the range
126 // According to the coord position, calculates the closest index in the range
125 return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep);
127 return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep);
126 }
128 }
127 else {
129 else {
128 // For a linear axis, we use the conversion method of colormap
130 // For a linear axis, we use the conversion method of colormap
129 int index;
131 int index;
130 if (xCoord) {
132 if (xCoord) {
131 colormap.data()->coordToCell(coord, 0., &index, nullptr);
133 colormap.data()->coordToCell(coord, 0., &index, nullptr);
132 }
134 }
133 else {
135 else {
134 colormap.data()->coordToCell(0., coord, nullptr, &index);
136 colormap.data()->coordToCell(0., coord, nullptr, &index);
135 }
137 }
136
138
137 return index;
139 return index;
138 }
140 }
139 }
141 }
140
142
141 } // namespace
143 } // namespace
142
144
143 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
145 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
144 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
146 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
145 : m_Plot{graphWidget.plot()},
147 : m_Plot{graphWidget.plot()},
146 m_PointTracer{new QCPItemTracer{&m_Plot}},
148 m_PointTracer{new QCPItemTracer{&m_Plot}},
147 m_TracerTimer{},
149 m_TracerTimer{},
148 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
150 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
149 m_TitleText{new QCPItemText{&m_Plot}},
151 m_TitleText{new QCPItemText{&m_Plot}},
150 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
152 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
151 m_ShowXAxis{true},
153 m_ShowXAxis{true},
152 m_XAxisLabel{},
154 m_XAxisLabel{},
153 m_ColorScale{SqpColorScale{m_Plot}}
155 m_ColorScale{SqpColorScale{m_Plot}}
154 {
156 {
155 initPointTracerStyle(*m_PointTracer);
157 initPointTracerStyle(*m_PointTracer);
156
158
157 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
159 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
158 m_TracerTimer.setSingleShot(true);
160 m_TracerTimer.setSingleShot(true);
159
161
160 // Inits "close button" in plot overlay
162 // Inits "close button" in plot overlay
161 m_ClosePixmap->setLayer(OVERLAY_LAYER);
163 m_ClosePixmap->setLayer(OVERLAY_LAYER);
162 initClosePixmapStyle(*m_ClosePixmap);
164 initClosePixmapStyle(*m_ClosePixmap);
163
165
164 // Connects pixmap selection to graph widget closing
166 // Connects pixmap selection to graph widget closing
165 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
167 QObject::connect(&m_Plot, &QCustomPlot::itemClick,
166 [&graphWidget](bool selected) {
168 [&graphWidget, this](auto item, auto mouseEvent) {
167 if (selected) {
169 if (item == m_ClosePixmap) {
168 graphWidget.close();
170 graphWidget.close();
169 }
171 }
170 });
172 });
171
173
172 // Inits graph name in plot overlay
174 // Inits graph name in plot overlay
173 m_TitleText->setLayer(OVERLAY_LAYER);
175 m_TitleText->setLayer(OVERLAY_LAYER);
174 m_TitleText->setText(graphWidget.name());
176 m_TitleText->setText(graphWidget.name());
175 initTitleTextStyle(*m_TitleText);
177 initTitleTextStyle(*m_TitleText);
176
178
177 // Inits "show x-axis button" in plot overlay
179 // Inits "show x-axis button" in plot overlay
178 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
180 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
179 initXAxisPixmapStyle(*m_XAxisPixmap);
181 initXAxisPixmapStyle(*m_XAxisPixmap);
180
182
181 // Connects pixmap selection to graph x-axis showing/hiding
183 // Connects pixmap selection to graph x-axis showing/hiding
182 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
184 QObject::connect(&m_Plot, &QCustomPlot::itemClick, [this](auto item, auto mouseEvent) {
183 if (m_XAxisPixmap->selected()) {
185 if (m_XAxisPixmap == item) {
184 // Changes the selection state and refreshes the x-axis
186 // Changes the selection state and refreshes the x-axis
185 m_ShowXAxis = !m_ShowXAxis;
187 m_ShowXAxis = !m_ShowXAxis;
186 updateXAxisState();
188 this->updateXAxisState();
187 m_Plot.layer(AXES_LAYER)->replot();
189 m_Plot.layer(AXES_LAYER)->replot();
188
190
189 // Deselects the x-axis pixmap and updates icon
191 // Deselects the x-axis pixmap and updates icon
190 m_XAxisPixmap->setSelected(false);
191 m_XAxisPixmap->setPixmap(
192 m_XAxisPixmap->setPixmap(
192 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
193 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
193 m_Plot.layer(OVERLAY_LAYER)->replot();
194 m_Plot.layer(OVERLAY_LAYER)->replot();
194 }
195 }
195 });
196 });
196 }
197 }
197
198
198 /// Updates state of x-axis according to the current selection of x-axis pixmap
199 /// Updates state of x-axis according to the current selection of x-axis pixmap
199 /// @remarks the method doesn't call plot refresh
200 /// @remarks the method doesn't call plot refresh
200 void updateXAxisState() noexcept
201 void updateXAxisState() noexcept
201 {
202 {
202 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
203 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
203 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
204 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
204 }
205 }
205
206
206 QCustomPlot &m_Plot;
207 QCustomPlot &m_Plot;
207 QCPItemTracer *m_PointTracer;
208 QCPItemTracer *m_PointTracer;
208 QTimer m_TracerTimer;
209 QTimer m_TracerTimer;
209 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
210 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
210 QCPItemText *m_TitleText; /// Graph's title
211 QCPItemText *m_TitleText; /// Graph's title
211 QCPItemPixmap *m_XAxisPixmap;
212 QCPItemPixmap *m_XAxisPixmap;
212 bool m_ShowXAxis; /// X-axis properties are shown or hidden
213 bool m_ShowXAxis; /// X-axis properties are shown or hidden
213 QString m_XAxisLabel;
214 QString m_XAxisLabel;
214 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
215 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
215 };
216 };
216
217
217 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
218 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
218 VisualizationGraphWidget &graphWidget)
219 VisualizationGraphWidget &graphWidget)
219 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
220 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
220 {
221 {
221 }
222 }
222
223
223 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
224 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
224 {
225 {
225 // Opens color scale editor if color scale is double clicked
226 // Opens color scale editor if color scale is double clicked
226 auto colorScale = static_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
227 auto colorScale = static_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
227 if (impl->m_ColorScale.m_Scale == colorScale) {
228 if (impl->m_ColorScale.m_Scale == colorScale) {
228 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
229 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
229 impl->m_Plot.replot();
230 impl->m_Plot.replot();
230 }
231 }
231 }
232 }
232 }
233 }
233
234
234 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
235 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
235 {
236 {
236 // Cancels pending refresh
237 // Cancels pending refresh
237 impl->m_TracerTimer.disconnect();
238 impl->m_TracerTimer.disconnect();
238
239
239 // Reinits tracers
240 // Reinits tracers
240 impl->m_PointTracer->setGraph(nullptr);
241 impl->m_PointTracer->setGraph(nullptr);
241 impl->m_PointTracer->setVisible(false);
242 impl->m_PointTracer->setVisible(false);
242 impl->m_Plot.replot();
243 impl->m_Plot.replot();
243
244
244 QString tooltip{};
245 QString tooltip{};
245
246
246 // Gets the graph under the mouse position
247 // Gets the graph under the mouse position
247 auto eventPos = event->pos();
248 auto eventPos = event->pos();
248 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
249 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
249 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
250 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
250 auto graphData = graph->data();
251 auto graphData = graph->data();
251
252
252 // Gets the closest data point to the mouse
253 // Gets the closest data point to the mouse
253 auto graphDataIt = graphData->findBegin(mouseKey);
254 auto graphDataIt = graphData->findBegin(mouseKey);
254 if (graphDataIt != graphData->constEnd()) {
255 if (graphDataIt != graphData->constEnd()) {
255 // Sets tooltip
256 // Sets tooltip
256 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
257 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
257 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
258 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
258 tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value);
259 tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value);
259
260
260 // Displays point tracer
261 // Displays point tracer
261 impl->m_PointTracer->setGraph(graph);
262 impl->m_PointTracer->setGraph(graph);
262 impl->m_PointTracer->setGraphKey(graphDataIt->key);
263 impl->m_PointTracer->setGraphKey(graphDataIt->key);
263 impl->m_PointTracer->setLayer(
264 impl->m_PointTracer->setLayer(
264 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
265 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
265 impl->m_PointTracer->setVisible(true);
266 impl->m_PointTracer->setVisible(true);
266 impl->m_Plot.replot();
267 impl->m_Plot.replot();
267 }
268 }
268 }
269 }
269 else if (auto colorMap = qobject_cast<QCPColorMap *>(impl->m_Plot.plottableAt(eventPos))) {
270 else if (auto colorMap = qobject_cast<QCPColorMap *>(impl->m_Plot.plottableAt(eventPos))) {
270 // Gets x and y coords
271 // Gets x and y coords
271 auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x());
272 auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x());
272 auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y());
273 auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y());
273
274
274 // Calculates x and y cell indexes, and retrieves the underlying value
275 // Calculates x and y cell indexes, and retrieves the underlying value
275 auto xCellIndex = colorMapCellIndex(*colorMap, x, true);
276 auto xCellIndex = colorMapCellIndex(*colorMap, x, true);
276 auto yCellIndex = colorMapCellIndex(*colorMap, y, false);
277 auto yCellIndex = colorMapCellIndex(*colorMap, y, false);
277 auto value = colorMap->data()->cell(xCellIndex, yCellIndex);
278 auto value = colorMap->data()->cell(xCellIndex, yCellIndex);
278
279
279 // Sets tooltips
280 // Sets tooltips
280 tooltip = COLORMAP_TOOLTIP_FORMAT.arg(formatValue(x, *colorMap->keyAxis()),
281 tooltip = COLORMAP_TOOLTIP_FORMAT.arg(formatValue(x, *colorMap->keyAxis()),
281 formatValue(y, *colorMap->valueAxis()),
282 formatValue(y, *colorMap->valueAxis()),
282 formatValue(value, *colorMap->colorScale()->axis()));
283 formatValue(value, *colorMap->colorScale()->axis()));
283 }
284 }
284
285
285 if (!tooltip.isEmpty()) {
286 if (!tooltip.isEmpty()) {
286 // Starts timer to show tooltip after timeout
287 // Starts timer to show tooltip after timeout
287 auto showTooltip = [tooltip, eventPos, this]() {
288 auto showTooltip = [tooltip, eventPos, this]() {
288 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
289 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
289 &impl->m_Plot, TOOLTIP_RECT);
290 &impl->m_Plot, TOOLTIP_RECT);
290 };
291 };
291
292
292 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
293 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
293 impl->m_TracerTimer.start();
294 impl->m_TracerTimer.start();
294 }
295 }
295 }
296 }
296
297
297 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
298 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
298 {
299 {
299 // Updates color scale bounds
300 // Updates color scale bounds
300 impl->m_ColorScale.updateDataRange();
301 impl->m_ColorScale.updateDataRange();
301 impl->m_Plot.replot();
302 impl->m_Plot.replot();
302 }
303 }
303
304
304 void VisualizationGraphRenderingDelegate::setAxesProperties(
305 void VisualizationGraphRenderingDelegate::setAxesProperties(
305 std::shared_ptr<IDataSeries> dataSeries) noexcept
306 std::shared_ptr<IDataSeries> dataSeries) noexcept
306 {
307 {
307 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
308 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
308 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
309 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
309
310
310 auto axisHelper = IAxisHelperFactory::create(dataSeries);
311 auto axisHelper = IAxisHelperFactory::create(dataSeries);
311 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
312 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
312
313
313 // Updates x-axis state
314 // Updates x-axis state
314 impl->updateXAxisState();
315 impl->updateXAxisState();
315
316
316 impl->m_Plot.layer(AXES_LAYER)->replot();
317 impl->m_Plot.layer(AXES_LAYER)->replot();
317 }
318 }
318
319
319 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
320 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
320 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
321 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
321 {
322 {
322 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
323 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
323 plottablesHelper->setProperties(plottables);
324 plottablesHelper->setProperties(plottables);
324 }
325 }
325
326
326 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
327 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
327 {
328 {
328 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
329 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
329 overlay->setVisible(show);
330 overlay->setVisible(show);
330 overlay->replot();
331 overlay->replot();
331 }
332 }
@@ -1,621 +1,876
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationWidget.h"
7 #include "Visualization/VisualizationZoneWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
8 #include "ui_VisualizationGraphWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
9
12
10 #include <Common/MimeTypesDef.h>
13 #include <Common/MimeTypesDef.h>
11 #include <Data/ArrayData.h>
14 #include <Data/ArrayData.h>
12 #include <Data/IDataSeries.h>
15 #include <Data/IDataSeries.h>
13 #include <Data/SpectrogramSeries.h>
16 #include <Data/SpectrogramSeries.h>
14 #include <DragAndDrop/DragDropHelper.h>
17 #include <DragAndDrop/DragDropHelper.h>
15 #include <Settings/SqpSettingsDefs.h>
18 #include <Settings/SqpSettingsDefs.h>
16 #include <SqpApplication.h>
19 #include <SqpApplication.h>
17 #include <Time/TimeController.h>
20 #include <Time/TimeController.h>
18 #include <Variable/Variable.h>
21 #include <Variable/Variable.h>
19 #include <Variable/VariableController.h>
22 #include <Variable/VariableController.h>
20
23
21 #include <unordered_map>
24 #include <unordered_map>
22
25
23 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
26 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
24
27
25 namespace {
28 namespace {
26
29
30 /// Key pressed to enable drag&drop in all modes
31 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
32
27 /// Key pressed to enable zoom on horizontal axis
33 /// Key pressed to enable zoom on horizontal axis
28 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
34 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
29
35
30 /// Key pressed to enable zoom on vertical axis
36 /// Key pressed to enable zoom on vertical axis
31 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
37 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
32
38
33 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
39 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
34 const auto PAN_SPEED = 5;
40 const auto PAN_SPEED = 5;
35
41
36 /// Key pressed to enable a calibration pan
42 /// Key pressed to enable a calibration pan
37 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
43 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
38
44
45 /// Key pressed to enable multi selection of selection zones
46 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
47
39 /// Minimum size for the zoom box, in percentage of the axis range
48 /// Minimum size for the zoom box, in percentage of the axis range
40 const auto ZOOM_BOX_MIN_SIZE = 0.8;
49 const auto ZOOM_BOX_MIN_SIZE = 0.8;
41
50
42 /// Format of the dates appearing in the label of a cursor
51 /// Format of the dates appearing in the label of a cursor
43 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
52 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
44
53
45 } // namespace
54 } // namespace
46
55
47 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
56 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
48
57
49 explicit VisualizationGraphWidgetPrivate(const QString &name)
58 explicit VisualizationGraphWidgetPrivate(const QString &name)
50 : m_Name{name},
59 : m_Name{name},
51 m_DoAcquisition{true},
60 m_DoAcquisition{true},
52 m_IsCalibration{false},
61 m_IsCalibration{false},
53 m_RenderingDelegate{nullptr}
62 m_RenderingDelegate{nullptr}
54 {
63 {
55 }
64 }
56
65
57 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
66 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
58 const SqpRange &range)
67 const SqpRange &range)
59 {
68 {
60 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
69 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
61
70
62 // Prevents that data has changed to update rendering
71 // Prevents that data has changed to update rendering
63 m_RenderingDelegate->onPlotUpdated();
72 m_RenderingDelegate->onPlotUpdated();
64 }
73 }
65
74
66 QString m_Name;
75 QString m_Name;
67 // 1 variable -> n qcpplot
76 // 1 variable -> n qcpplot
68 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
77 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
69 bool m_DoAcquisition;
78 bool m_DoAcquisition;
70 bool m_IsCalibration;
79 bool m_IsCalibration;
71 /// Delegate used to attach rendering features to the plot
80 /// Delegate used to attach rendering features to the plot
72 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
81 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
73
82
74 QCPItemRect *m_DrawingRect = nullptr;
83 QCPItemRect *m_DrawingZoomRect = nullptr;
84 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
85
75 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
86 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
76 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
87 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
77
88
78 void configureDrawingRect()
89 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
79 {
90 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
80 if (m_DrawingRect) {
91 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
81 QPen p;
92
82 p.setWidth(2);
93 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
83 m_DrawingRect->setPen(p);
84 }
85 }
86
94
87 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
95 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
88 {
96 {
89 removeDrawingRect(plot);
97 removeDrawingRect(plot);
90
98
91 auto axisPos = posToAxisPos(pos, plot);
99 auto axisPos = posToAxisPos(pos, plot);
92
100
93 m_DrawingRect = new QCPItemRect{&plot};
101 m_DrawingZoomRect = new QCPItemRect{&plot};
94 configureDrawingRect();
102 QPen p;
103 p.setWidth(2);
104 m_DrawingZoomRect->setPen(p);
95
105
96 m_DrawingRect->topLeft->setCoords(axisPos);
106 m_DrawingZoomRect->topLeft->setCoords(axisPos);
97 m_DrawingRect->bottomRight->setCoords(axisPos);
107 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
98 }
108 }
99
109
100 void removeDrawingRect(QCustomPlot &plot)
110 void removeDrawingRect(QCustomPlot &plot)
101 {
111 {
102 if (m_DrawingRect) {
112 if (m_DrawingZoomRect) {
103 plot.removeItem(m_DrawingRect); // the item is deleted by QCustomPlot
113 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
104 m_DrawingRect = nullptr;
114 m_DrawingZoomRect = nullptr;
105 plot.replot(QCustomPlot::rpQueuedReplot);
115 plot.replot(QCustomPlot::rpQueuedReplot);
106 }
116 }
107 }
117 }
108
118
119 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
120 {
121 endDrawingZone(graph);
122
123 auto axisPos = posToAxisPos(pos, graph->plot());
124
125 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
126 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
127 m_DrawingZone->setEditionEnabled(false);
128 }
129
130 void endDrawingZone(VisualizationGraphWidget *graph)
131 {
132 if (m_DrawingZone) {
133 auto drawingZoneRange = m_DrawingZone->range();
134 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
135 m_DrawingZone->setEditionEnabled(true);
136 addSelectionZone(m_DrawingZone);
137 }
138 else {
139 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
140 }
141
142 graph->plot().replot(QCustomPlot::rpQueuedReplot);
143 m_DrawingZone = nullptr;
144 }
145 }
146
147 void setSelectionZonesEditionEnabled(bool value)
148 {
149 for (auto s : m_SelectionZones) {
150 s->setEditionEnabled(value);
151 }
152 }
153
154 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
155
156 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
157 const QCustomPlot &plot) const
158 {
159 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
160 auto minDistanceToZone = -1;
161 for (auto zone : m_SelectionZones) {
162 auto distanceToZone = zone->selectTest(pos, false);
163 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
164 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
165 selectionZoneItemUnderCursor = zone;
166 }
167 }
168
169 return selectionZoneItemUnderCursor;
170 }
171
109 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
172 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
110 {
173 {
111 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
174 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
112 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
175 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
113 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
176 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
114 }
177 }
115
178
116 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
179 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
117 {
180 {
118 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
181 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
119 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
182 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
120
121 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
183 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
122 }
184 }
123 };
185 };
124
186
125 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
187 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
126 : VisualizationDragWidget{parent},
188 : VisualizationDragWidget{parent},
127 ui{new Ui::VisualizationGraphWidget},
189 ui{new Ui::VisualizationGraphWidget},
128 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
190 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
129 {
191 {
130 ui->setupUi(this);
192 ui->setupUi(this);
131
193
132 // 'Close' options : widget is deleted when closed
194 // 'Close' options : widget is deleted when closed
133 setAttribute(Qt::WA_DeleteOnClose);
195 setAttribute(Qt::WA_DeleteOnClose);
134
196
135 // Set qcpplot properties :
197 // Set qcpplot properties :
136 // - Drag (on x-axis) and zoom are enabled
198 // - zoom is enabled
137 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
199 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
138 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
200 ui->widget->setInteractions(QCP::iRangeZoom);
201 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
139
202
140 // The delegate must be initialized after the ui as it uses the plot
203 // The delegate must be initialized after the ui as it uses the plot
141 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
204 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
142
205
143 // Init the cursors
206 // Init the cursors
144 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
207 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
145 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
208 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
146 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
209 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
147 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
210 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
148
211
149 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
212 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
150 connect(ui->widget, &QCustomPlot::mouseRelease, this,
213 connect(ui->widget, &QCustomPlot::mouseRelease, this,
151 &VisualizationGraphWidget::onMouseRelease);
214 &VisualizationGraphWidget::onMouseRelease);
152 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
215 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
153 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
216 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
154 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
217 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
155 &VisualizationGraphWidget::onMouseDoubleClick);
218 &VisualizationGraphWidget::onMouseDoubleClick);
156 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
219 connect(
157 &QCPAxis::rangeChanged),
220 ui->widget->xAxis,
221 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
158 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
222 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
159
223
160 // Activates menu when right clicking on the graph
224 // Activates menu when right clicking on the graph
161 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
225 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
162 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
226 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
163 &VisualizationGraphWidget::onGraphMenuRequested);
227 &VisualizationGraphWidget::onGraphMenuRequested);
164
228
165 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
229 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
166 &VariableController::onRequestDataLoading);
230 &VariableController::onRequestDataLoading);
167
231
168 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
232 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
169 &VisualizationGraphWidget::onUpdateVarDisplaying);
233 &VisualizationGraphWidget::onUpdateVarDisplaying);
170
234
171 #ifdef Q_OS_MAC
235 #ifdef Q_OS_MAC
172 plot().setPlottingHint(QCP::phFastPolylines, true);
236 plot().setPlottingHint(QCP::phFastPolylines, true);
173 #endif
237 #endif
174 }
238 }
175
239
176
240
177 VisualizationGraphWidget::~VisualizationGraphWidget()
241 VisualizationGraphWidget::~VisualizationGraphWidget()
178 {
242 {
179 delete ui;
243 delete ui;
180 }
244 }
181
245
182 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
246 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
183 {
247 {
184 auto parent = parentWidget();
248 auto parent = parentWidget();
185 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
249 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
186 parent = parent->parentWidget();
250 parent = parent->parentWidget();
187 }
251 }
188
252
189 return qobject_cast<VisualizationZoneWidget *>(parent);
253 return qobject_cast<VisualizationZoneWidget *>(parent);
190 }
254 }
191
255
256 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
257 {
258 auto parent = parentWidget();
259 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
260 parent = parent->parentWidget();
261 }
262
263 return qobject_cast<VisualizationWidget *>(parent);
264 }
265
192 void VisualizationGraphWidget::enableAcquisition(bool enable)
266 void VisualizationGraphWidget::enableAcquisition(bool enable)
193 {
267 {
194 impl->m_DoAcquisition = enable;
268 impl->m_DoAcquisition = enable;
195 }
269 }
196
270
197 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
271 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
198 {
272 {
199 // Uses delegate to create the qcpplot components according to the variable
273 // Uses delegate to create the qcpplot components according to the variable
200 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
274 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
201
275
202 if (auto dataSeries = variable->dataSeries()) {
276 if (auto dataSeries = variable->dataSeries()) {
203 // Set axes properties according to the units of the data series
277 // Set axes properties according to the units of the data series
204 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
278 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
205
279
206 // Sets rendering properties for the new plottables
280 // Sets rendering properties for the new plottables
207 // Warning: this method must be called after setAxesProperties(), as it can access to some
281 // Warning: this method must be called after setAxesProperties(), as it can access to some
208 // axes properties that have to be initialized
282 // axes properties that have to be initialized
209 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
283 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
210 }
284 }
211
285
212 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
286 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
213
287
214 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
288 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
215
289
216 this->enableAcquisition(false);
290 this->enableAcquisition(false);
217 this->setGraphRange(range);
291 this->setGraphRange(range);
218 this->enableAcquisition(true);
292 this->enableAcquisition(true);
219
293
220 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
294 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
221
295
222 emit variableAdded(variable);
296 emit variableAdded(variable);
223 }
297 }
224
298
225 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
299 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
226 {
300 {
227 // Each component associated to the variable :
301 // Each component associated to the variable :
228 // - is removed from qcpplot (which deletes it)
302 // - is removed from qcpplot (which deletes it)
229 // - is no longer referenced in the map
303 // - is no longer referenced in the map
230 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
304 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
231 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
305 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
232 emit variableAboutToBeRemoved(variable);
306 emit variableAboutToBeRemoved(variable);
233
307
234 auto &plottablesMap = variableIt->second;
308 auto &plottablesMap = variableIt->second;
235
309
236 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
310 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
237 plottableIt != plottableEnd;) {
311 plottableIt != plottableEnd;) {
238 ui->widget->removePlottable(plottableIt->second);
312 ui->widget->removePlottable(plottableIt->second);
239 plottableIt = plottablesMap.erase(plottableIt);
313 plottableIt = plottablesMap.erase(plottableIt);
240 }
314 }
241
315
242 impl->m_VariableToPlotMultiMap.erase(variableIt);
316 impl->m_VariableToPlotMultiMap.erase(variableIt);
243 }
317 }
244
318
245 // Updates graph
319 // Updates graph
246 ui->widget->replot();
320 ui->widget->replot();
247 }
321 }
248
322
249 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
323 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
250 {
324 {
251 auto variables = QList<std::shared_ptr<Variable> >{};
325 auto variables = QList<std::shared_ptr<Variable> >{};
252 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
326 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
253 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
327 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
254 variables << it->first;
328 variables << it->first;
255 }
329 }
256
330
257 return variables;
331 return variables;
258 }
332 }
259
333
260 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
334 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
261 {
335 {
262 if (!variable) {
336 if (!variable) {
263 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
337 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
264 return;
338 return;
265 }
339 }
266
340
267 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
341 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
268 }
342 }
269
343
270 SqpRange VisualizationGraphWidget::graphRange() const noexcept
344 SqpRange VisualizationGraphWidget::graphRange() const noexcept
271 {
345 {
272 auto graphRange = ui->widget->xAxis->range();
346 auto graphRange = ui->widget->xAxis->range();
273 return SqpRange{graphRange.lower, graphRange.upper};
347 return SqpRange{graphRange.lower, graphRange.upper};
274 }
348 }
275
349
276 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
350 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
277 {
351 {
278 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
352 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
279 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
353 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
280 ui->widget->replot();
354 ui->widget->replot();
281 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
355 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
282 }
356 }
283
357
358 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
359 {
360 QVector<SqpRange> ranges;
361 for (auto zone : impl->m_SelectionZones) {
362 ranges << zone->range();
363 }
364
365 return ranges;
366 }
367
368 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
369 {
370 for (const auto &range : ranges) {
371 // note: ownership is transfered to QCustomPlot
372 auto zone = new VisualizationSelectionZoneItem(&plot());
373 zone->setRange(range.m_TStart, range.m_TEnd);
374 impl->addSelectionZone(zone);
375 }
376
377 plot().replot(QCustomPlot::rpQueuedReplot);
378 }
379
380 void VisualizationGraphWidget::undoZoom()
381 {
382 auto zoom = impl->m_ZoomStack.pop();
383 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
384 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
385
386 axisX->setRange(zoom.first);
387 axisY->setRange(zoom.second);
388
389 plot().replot(QCustomPlot::rpQueuedReplot);
390 }
391
284 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
392 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
285 {
393 {
286 if (visitor) {
394 if (visitor) {
287 visitor->visit(this);
395 visitor->visit(this);
288 }
396 }
289 else {
397 else {
290 qCCritical(LOG_VisualizationGraphWidget())
398 qCCritical(LOG_VisualizationGraphWidget())
291 << tr("Can't visit widget : the visitor is null");
399 << tr("Can't visit widget : the visitor is null");
292 }
400 }
293 }
401 }
294
402
295 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
403 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
296 {
404 {
297 auto isSpectrogram = [](const auto &variable) {
405 auto isSpectrogram = [](const auto &variable) {
298 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
406 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
299 };
407 };
300
408
301 // - A spectrogram series can't be dropped on graph with existing plottables
409 // - A spectrogram series can't be dropped on graph with existing plottables
302 // - No data series can be dropped on graph with existing spectrogram series
410 // - No data series can be dropped on graph with existing spectrogram series
303 return isSpectrogram(variable)
411 return isSpectrogram(variable)
304 ? impl->m_VariableToPlotMultiMap.empty()
412 ? impl->m_VariableToPlotMultiMap.empty()
305 : std::none_of(
413 : std::none_of(
306 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
414 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
307 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
415 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
308 }
416 }
309
417
310 bool VisualizationGraphWidget::contains(const Variable &variable) const
418 bool VisualizationGraphWidget::contains(const Variable &variable) const
311 {
419 {
312 // Finds the variable among the keys of the map
420 // Finds the variable among the keys of the map
313 auto variablePtr = &variable;
421 auto variablePtr = &variable;
314 auto findVariable
422 auto findVariable
315 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
423 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
316
424
317 auto end = impl->m_VariableToPlotMultiMap.cend();
425 auto end = impl->m_VariableToPlotMultiMap.cend();
318 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
426 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
319 return it != end;
427 return it != end;
320 }
428 }
321
429
322 QString VisualizationGraphWidget::name() const
430 QString VisualizationGraphWidget::name() const
323 {
431 {
324 return impl->m_Name;
432 return impl->m_Name;
325 }
433 }
326
434
327 QMimeData *VisualizationGraphWidget::mimeData() const
435 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
328 {
436 {
329 auto mimeData = new QMimeData;
437 auto mimeData = new QMimeData;
438
439 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
440 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
441 && selectionZoneItemUnderCursor) {
442 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
443 selectionZoneItemUnderCursor->range()));
444 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
445 selectionZoneItemUnderCursor->range()));
446 }
447 else {
330 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
448 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
331
449
332 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
450 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
333 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
451 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
452 }
334
453
335 return mimeData;
454 return mimeData;
336 }
455 }
337
456
457 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
458 {
459 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
460 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
461 && selectionZoneItemUnderCursor) {
462
463 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
464 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
465
466 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
467 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
468 .toSize();
469
470 auto pixmap = QPixmap(zoneSize);
471 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
472
473 return pixmap;
474 }
475
476 return QPixmap();
477 }
478
338 bool VisualizationGraphWidget::isDragAllowed() const
479 bool VisualizationGraphWidget::isDragAllowed() const
339 {
480 {
340 return true;
481 return true;
341 }
482 }
342
483
343 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
484 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
344 {
485 {
345 if (highlighted) {
486 if (highlighted) {
346 plot().setBackground(QBrush(QColor("#BBD5EE")));
487 plot().setBackground(QBrush(QColor("#BBD5EE")));
347 }
488 }
348 else {
489 else {
349 plot().setBackground(QBrush(Qt::white));
490 plot().setBackground(QBrush(Qt::white));
350 }
491 }
351
492
352 plot().update();
493 plot().update();
353 }
494 }
354
495
355 void VisualizationGraphWidget::addVerticalCursor(double time)
496 void VisualizationGraphWidget::addVerticalCursor(double time)
356 {
497 {
357 impl->m_VerticalCursor->setPosition(time);
498 impl->m_VerticalCursor->setPosition(time);
358 impl->m_VerticalCursor->setVisible(true);
499 impl->m_VerticalCursor->setVisible(true);
359
500
360 auto text
501 auto text
361 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
502 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
362 impl->m_VerticalCursor->setLabelText(text);
503 impl->m_VerticalCursor->setLabelText(text);
363 }
504 }
364
505
365 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
506 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
366 {
507 {
367 impl->m_VerticalCursor->setAbsolutePosition(position);
508 impl->m_VerticalCursor->setAbsolutePosition(position);
368 impl->m_VerticalCursor->setVisible(true);
509 impl->m_VerticalCursor->setVisible(true);
369
510
370 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
511 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
371 auto text
512 auto text
372 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
513 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
373 impl->m_VerticalCursor->setLabelText(text);
514 impl->m_VerticalCursor->setLabelText(text);
374 }
515 }
375
516
376 void VisualizationGraphWidget::removeVerticalCursor()
517 void VisualizationGraphWidget::removeVerticalCursor()
377 {
518 {
378 impl->m_VerticalCursor->setVisible(false);
519 impl->m_VerticalCursor->setVisible(false);
379 plot().replot(QCustomPlot::rpQueuedReplot);
520 plot().replot(QCustomPlot::rpQueuedReplot);
380 }
521 }
381
522
382 void VisualizationGraphWidget::addHorizontalCursor(double value)
523 void VisualizationGraphWidget::addHorizontalCursor(double value)
383 {
524 {
384 impl->m_HorizontalCursor->setPosition(value);
525 impl->m_HorizontalCursor->setPosition(value);
385 impl->m_HorizontalCursor->setVisible(true);
526 impl->m_HorizontalCursor->setVisible(true);
386 impl->m_HorizontalCursor->setLabelText(QString::number(value));
527 impl->m_HorizontalCursor->setLabelText(QString::number(value));
387 }
528 }
388
529
389 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
530 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
390 {
531 {
391 impl->m_HorizontalCursor->setAbsolutePosition(position);
532 impl->m_HorizontalCursor->setAbsolutePosition(position);
392 impl->m_HorizontalCursor->setVisible(true);
533 impl->m_HorizontalCursor->setVisible(true);
393
534
394 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
535 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
395 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
536 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
396 }
537 }
397
538
398 void VisualizationGraphWidget::removeHorizontalCursor()
539 void VisualizationGraphWidget::removeHorizontalCursor()
399 {
540 {
400 impl->m_HorizontalCursor->setVisible(false);
541 impl->m_HorizontalCursor->setVisible(false);
401 plot().replot(QCustomPlot::rpQueuedReplot);
542 plot().replot(QCustomPlot::rpQueuedReplot);
402 }
543 }
403
544
404 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
545 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
405 {
546 {
406 Q_UNUSED(event);
547 Q_UNUSED(event);
407
548
408 // Prevents that all variables will be removed from graph when it will be closed
549 // Prevents that all variables will be removed from graph when it will be closed
409 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
550 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
410 emit variableAboutToBeRemoved(variableEntry.first);
551 emit variableAboutToBeRemoved(variableEntry.first);
411 }
552 }
412 }
553 }
413
554
414 void VisualizationGraphWidget::enterEvent(QEvent *event)
555 void VisualizationGraphWidget::enterEvent(QEvent *event)
415 {
556 {
416 Q_UNUSED(event);
557 Q_UNUSED(event);
417 impl->m_RenderingDelegate->showGraphOverlay(true);
558 impl->m_RenderingDelegate->showGraphOverlay(true);
418 }
559 }
419
560
420 void VisualizationGraphWidget::leaveEvent(QEvent *event)
561 void VisualizationGraphWidget::leaveEvent(QEvent *event)
421 {
562 {
422 Q_UNUSED(event);
563 Q_UNUSED(event);
423 impl->m_RenderingDelegate->showGraphOverlay(false);
564 impl->m_RenderingDelegate->showGraphOverlay(false);
424
565
425 if (auto parentZone = parentZoneWidget()) {
566 if (auto parentZone = parentZoneWidget()) {
426 parentZone->notifyMouseLeaveGraph(this);
567 parentZone->notifyMouseLeaveGraph(this);
427 }
568 }
428 else {
569 else {
429 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
570 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
430 }
571 }
572
573 if (impl->m_HoveredZone) {
574 impl->m_HoveredZone->setHovered(false);
575 impl->m_HoveredZone = nullptr;
576 }
431 }
577 }
432
578
433 QCustomPlot &VisualizationGraphWidget::plot() noexcept
579 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
434 {
580 {
435 return *ui->widget;
581 return *ui->widget;
436 }
582 }
437
583
438 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
584 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
439 {
585 {
440 QMenu graphMenu{};
586 QMenu graphMenu{};
441
587
442 // Iterates on variables (unique keys)
588 // Iterates on variables (unique keys)
443 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
589 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
444 end = impl->m_VariableToPlotMultiMap.cend();
590 end = impl->m_VariableToPlotMultiMap.cend();
445 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
591 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
446 // 'Remove variable' action
592 // 'Remove variable' action
447 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
593 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
448 [ this, var = it->first ]() { removeVariable(var); });
594 [ this, var = it->first ]() { removeVariable(var); });
449 }
595 }
450
596
597 if (!impl->m_ZoomStack.isEmpty()) {
598 if (!graphMenu.isEmpty()) {
599 graphMenu.addSeparator();
600 }
601
602 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
603 }
604
451 if (!graphMenu.isEmpty()) {
605 if (!graphMenu.isEmpty()) {
452 graphMenu.exec(QCursor::pos());
606 graphMenu.exec(QCursor::pos());
453 }
607 }
454 }
608 }
455
609
456 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
610 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
457 {
611 {
458 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
612 qCDebug(LOG_VisualizationGraphWidget())
459 << QThread::currentThread()->objectName() << "DoAcqui"
613 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
460 << impl->m_DoAcquisition;
614 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
461
615
462 auto graphRange = SqpRange{t1.lower, t1.upper};
616 auto graphRange = SqpRange{t1.lower, t1.upper};
463 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
617 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
464
618
465 if (impl->m_DoAcquisition) {
619 if (impl->m_DoAcquisition) {
466 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
620 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
467
621
468 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
622 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
469 end = impl->m_VariableToPlotMultiMap.end();
623 end = impl->m_VariableToPlotMultiMap.end();
470 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
624 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
471 variableUnderGraphVector.push_back(it->first);
625 variableUnderGraphVector.push_back(it->first);
472 }
626 }
473 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
627 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
474 !impl->m_IsCalibration);
628 !impl->m_IsCalibration);
475
629
476 if (!impl->m_IsCalibration) {
630 if (!impl->m_IsCalibration) {
477 qCDebug(LOG_VisualizationGraphWidget())
631 qCDebug(LOG_VisualizationGraphWidget())
478 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
632 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
479 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
633 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
480 emit synchronize(graphRange, oldGraphRange);
634 emit synchronize(graphRange, oldGraphRange);
481 }
635 }
482 }
636 }
483
637
484 auto pos = mapFromGlobal(QCursor::pos());
638 auto pos = mapFromGlobal(QCursor::pos());
485 auto axisPos = impl->posToAxisPos(pos, plot());
639 auto axisPos = impl->posToAxisPos(pos, plot());
486 if (auto parentZone = parentZoneWidget()) {
640 if (auto parentZone = parentZoneWidget()) {
487 if (impl->pointIsInAxisRect(axisPos, plot())) {
641 if (impl->pointIsInAxisRect(axisPos, plot())) {
488 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
642 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
489 }
643 }
490 else {
644 else {
491 parentZone->notifyMouseLeaveGraph(this);
645 parentZone->notifyMouseLeaveGraph(this);
492 }
646 }
493 }
647 }
494 else {
648 else {
495 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
649 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
496 }
650 }
497 }
651 }
498
652
499 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
653 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
500 {
654 {
501 impl->m_RenderingDelegate->onMouseDoubleClick(event);
655 impl->m_RenderingDelegate->onMouseDoubleClick(event);
502 }
656 }
503
657
504 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
658 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
505 {
659 {
506 // Handles plot rendering when mouse is moving
660 // Handles plot rendering when mouse is moving
507 impl->m_RenderingDelegate->onMouseMove(event);
661 impl->m_RenderingDelegate->onMouseMove(event);
508
662
509 auto axisPos = impl->posToAxisPos(event->pos(), plot());
663 auto axisPos = impl->posToAxisPos(event->pos(), plot());
510
664
511 if (impl->m_DrawingRect) {
665 // Zoom box and zone drawing
512 impl->m_DrawingRect->bottomRight->setCoords(axisPos);
666 if (impl->m_DrawingZoomRect) {
667 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
668 }
669 else if (impl->m_DrawingZone) {
670 impl->m_DrawingZone->setEnd(axisPos.x());
513 }
671 }
514
672
673 // Cursor
515 if (auto parentZone = parentZoneWidget()) {
674 if (auto parentZone = parentZoneWidget()) {
516 if (impl->pointIsInAxisRect(axisPos, plot())) {
675 if (impl->pointIsInAxisRect(axisPos, plot())) {
517 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
676 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
518 }
677 }
519 else {
678 else {
520 parentZone->notifyMouseLeaveGraph(this);
679 parentZone->notifyMouseLeaveGraph(this);
521 }
680 }
522 }
681 }
523 else {
682 else {
524 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
683 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
525 }
684 }
526
685
686 // Search for the selection zone under the mouse
687 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
688 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
689 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
690
691 // Sets the appropriate cursor shape
692 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
693 setCursor(cursorShape);
694
695 // Manages the hovered zone
696 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
697 if (impl->m_HoveredZone) {
698 impl->m_HoveredZone->setHovered(false);
699 }
700 selectionZoneItemUnderCursor->setHovered(true);
701 impl->m_HoveredZone = selectionZoneItemUnderCursor;
702 plot().replot(QCustomPlot::rpQueuedReplot);
703 }
704 }
705 else {
706 // There is no zone under the mouse or the interaction mode is not "selection zones"
707 if (impl->m_HoveredZone) {
708 impl->m_HoveredZone->setHovered(false);
709 impl->m_HoveredZone = nullptr;
710 }
711
712 setCursor(Qt::ArrowCursor);
713 }
714
715 impl->m_HasMovedMouse = true;
527 VisualizationDragWidget::mouseMoveEvent(event);
716 VisualizationDragWidget::mouseMoveEvent(event);
528 }
717 }
529
718
530 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
719 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
531 {
720 {
532 auto value = event->angleDelta().x() + event->angleDelta().y();
721 auto value = event->angleDelta().x() + event->angleDelta().y();
533 if (value != 0) {
722 if (value != 0) {
534
723
535 auto direction = value > 0 ? 1.0 : -1.0;
724 auto direction = value > 0 ? 1.0 : -1.0;
536 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
725 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
537 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
726 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
538 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
727 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
539
728
540 auto zoomOrientations = QFlags<Qt::Orientation>{};
729 auto zoomOrientations = QFlags<Qt::Orientation>{};
541 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
730 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
542 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
731 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
543
732
544 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
733 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
545
734
546 if (!isZoomX && !isZoomY) {
735 if (!isZoomX && !isZoomY) {
547 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
736 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
548 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
737 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
549
738
550 axis->setRange(axis->range() + diff);
739 axis->setRange(axis->range() + diff);
551
740
552 if (plot().noAntialiasingOnDrag()) {
741 if (plot().noAntialiasingOnDrag()) {
553 plot().setNotAntialiasedElements(QCP::aeAll);
742 plot().setNotAntialiasedElements(QCP::aeAll);
554 }
743 }
555
744
556 plot().replot(QCustomPlot::rpQueuedReplot);
745 plot().replot(QCustomPlot::rpQueuedReplot);
557 }
746 }
558 }
747 }
559 }
748 }
560
749
561 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
750 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
562 {
751 {
752 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
753 auto isSelectionZoneMode
754 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
755 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
756
757 if (!isDragDropClick && isLeftClick) {
563 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
758 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
759 // Starts a zoom box
564 impl->startDrawingRect(event->pos(), plot());
760 impl->startDrawingRect(event->pos(), plot());
565 }
761 }
762 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
763 // Starts a new selection zone
764 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
765 if (!zoneAtPos) {
766 impl->startDrawingZone(event->pos(), this);
767 }
768 }
769 }
566
770
771 // Allows mouse panning only in default mode
772 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
773 == SqpApplication::PlotsInteractionMode::None
774 && !isDragDropClick);
775
776 // Allows zone edition only in selection zone mode without drag&drop
777 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
778
779 // Selection / Deselection
780 if (isSelectionZoneMode) {
781 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
782 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
783 if (selectionZoneItemUnderCursor && isLeftClick) {
784 selectionZoneItemUnderCursor->setAssociatedEditedZones(
785 parentVisualizationWidget()->selectionZoneManager().selectedItems());
786 }
787 else if (!isMultiSelectionClick && isLeftClick) {
788 parentVisualizationWidget()->selectionZoneManager().clearSelection();
789 }
790 else {
791 // No selection change
792 }
793 }
794
795
796 impl->m_HasMovedMouse = false;
567 VisualizationDragWidget::mousePressEvent(event);
797 VisualizationDragWidget::mousePressEvent(event);
568 }
798 }
569
799
570 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
800 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
571 {
801 {
572 if (impl->m_DrawingRect) {
802 if (impl->m_DrawingZoomRect) {
573
803
574 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
804 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
575 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
805 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
576
806
577 auto newAxisXRange = QCPRange{impl->m_DrawingRect->topLeft->coords().x(),
807 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
578 impl->m_DrawingRect->bottomRight->coords().x()};
808 impl->m_DrawingZoomRect->bottomRight->coords().x()};
579
809
580 auto newAxisYRange = QCPRange{impl->m_DrawingRect->topLeft->coords().y(),
810 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
581 impl->m_DrawingRect->bottomRight->coords().y()};
811 impl->m_DrawingZoomRect->bottomRight->coords().y()};
582
812
583 impl->removeDrawingRect(plot());
813 impl->removeDrawingRect(plot());
584
814
585 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
815 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
586 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
816 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
817 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
587 axisX->setRange(newAxisXRange);
818 axisX->setRange(newAxisXRange);
588 axisY->setRange(newAxisYRange);
819 axisY->setRange(newAxisYRange);
589
820
590 plot().replot(QCustomPlot::rpQueuedReplot);
821 plot().replot(QCustomPlot::rpQueuedReplot);
591 }
822 }
592 }
823 }
593
824
825 impl->endDrawingZone(this);
826
594 impl->m_IsCalibration = false;
827 impl->m_IsCalibration = false;
828
829 // Selection / Deselection
830 auto isSelectionZoneMode
831 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
832 if (isSelectionZoneMode) {
833 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
834 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
835 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
836 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
837 parentVisualizationWidget()->selectionZoneManager().select(
838 {selectionZoneItemUnderCursor});
839 }
840 else if (!impl->m_HasMovedMouse) {
841 parentVisualizationWidget()->selectionZoneManager().setSelected(
842 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
843 || event->button() == Qt::RightButton);
844 }
845 }
846 else {
847 // No selection change
848 }
849 }
595 }
850 }
596
851
597 void VisualizationGraphWidget::onDataCacheVariableUpdated()
852 void VisualizationGraphWidget::onDataCacheVariableUpdated()
598 {
853 {
599 auto graphRange = ui->widget->xAxis->range();
854 auto graphRange = ui->widget->xAxis->range();
600 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
855 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
601
856
602 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
857 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
603 auto variable = variableEntry.first;
858 auto variable = variableEntry.first;
604 qCDebug(LOG_VisualizationGraphWidget())
859 qCDebug(LOG_VisualizationGraphWidget())
605 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
860 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
606 qCDebug(LOG_VisualizationGraphWidget())
861 qCDebug(LOG_VisualizationGraphWidget())
607 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
862 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
608 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
863 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
609 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
864 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
610 }
865 }
611 }
866 }
612 }
867 }
613
868
614 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
869 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
615 const SqpRange &range)
870 const SqpRange &range)
616 {
871 {
617 auto it = impl->m_VariableToPlotMultiMap.find(variable);
872 auto it = impl->m_VariableToPlotMultiMap.find(variable);
618 if (it != impl->m_VariableToPlotMultiMap.end()) {
873 if (it != impl->m_VariableToPlotMultiMap.end()) {
619 impl->updateData(it->second, variable->dataSeries(), range);
874 impl->updateData(it->second, variable->dataSeries(), range);
620 }
875 }
621 }
876 }
@@ -1,320 +1,329
1 #include "Visualization/VisualizationTabWidget.h"
1 #include "Visualization/VisualizationTabWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "ui_VisualizationTabWidget.h"
3 #include "ui_VisualizationTabWidget.h"
4
4
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7
7
8 #include "Visualization/MacScrollBarStyle.h"
8 #include "Visualization/MacScrollBarStyle.h"
9
9
10 #include "Variable/VariableController.h"
10 #include "Variable/VariableController.h"
11
11
12 #include "Common/MimeTypesDef.h"
12 #include "Common/MimeTypesDef.h"
13
13
14 #include "DragAndDrop/DragDropHelper.h"
14 #include "DragAndDrop/DragDropHelper.h"
15 #include "SqpApplication.h"
15 #include "SqpApplication.h"
16
16
17 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
17 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
18
18
19 namespace {
19 namespace {
20
20
21 /// Generates a default name for a new zone, according to the number of zones already displayed in
21 /// Generates a default name for a new zone, according to the number of zones already displayed in
22 /// the tab
22 /// the tab
23 QString defaultZoneName(const QLayout &layout)
23 QString defaultZoneName(const QLayout &layout)
24 {
24 {
25 auto count = 0;
25 auto count = 0;
26 for (auto i = 0; i < layout.count(); ++i) {
26 for (auto i = 0; i < layout.count(); ++i) {
27 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
27 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
28 count++;
28 count++;
29 }
29 }
30 }
30 }
31
31
32 return QObject::tr("Zone %1").arg(count + 1);
32 return QObject::tr("Zone %1").arg(count + 1);
33 }
33 }
34
34
35 /**
35 /**
36 * Applies a function to all zones of the tab represented by its layout
36 * Applies a function to all zones of the tab represented by its layout
37 * @param layout the layout that contains zones
37 * @param layout the layout that contains zones
38 * @param fun the function to apply to each zone
38 * @param fun the function to apply to each zone
39 */
39 */
40 template <typename Fun>
40 template <typename Fun>
41 void processZones(QLayout &layout, Fun fun)
41 void processZones(QLayout &layout, Fun fun)
42 {
42 {
43 for (auto i = 0; i < layout.count(); ++i) {
43 for (auto i = 0; i < layout.count(); ++i) {
44 if (auto item = layout.itemAt(i)) {
44 if (auto item = layout.itemAt(i)) {
45 if (auto visualizationZoneWidget
45 if (auto visualizationZoneWidget
46 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
46 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
47 fun(*visualizationZoneWidget);
47 fun(*visualizationZoneWidget);
48 }
48 }
49 }
49 }
50 }
50 }
51 }
51 }
52
52
53 } // namespace
53 } // namespace
54
54
55 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
55 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
56 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
56 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
57
57
58 QString m_Name;
58 QString m_Name;
59
59
60 #ifdef Q_OS_MAC
60 #ifdef Q_OS_MAC
61 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
61 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
62 #endif
62 #endif
63
63
64 void dropGraph(int index, VisualizationTabWidget *tabWidget);
64 void dropGraph(int index, VisualizationTabWidget *tabWidget);
65 void dropZone(int index, VisualizationTabWidget *tabWidget);
65 void dropZone(int index, VisualizationTabWidget *tabWidget);
66 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
66 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
67 VisualizationTabWidget *tabWidget);
67 VisualizationTabWidget *tabWidget);
68 };
68 };
69
69
70 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
70 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
71 : QWidget{parent},
71 : QWidget{parent},
72 ui{new Ui::VisualizationTabWidget},
72 ui{new Ui::VisualizationTabWidget},
73 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
73 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
74 {
74 {
75 ui->setupUi(this);
75 ui->setupUi(this);
76
76
77 #ifdef Q_OS_MAC
77 #ifdef Q_OS_MAC
78 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
78 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
79 #endif
79 #endif
80
80
81 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Zone, "Zone");
81 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Zone, "Zone");
82 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
82 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
83 ui->dragDropContainer->layout()->setSpacing(0);
83 ui->dragDropContainer->layout()->setSpacing(0);
84 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
84 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
85 VisualizationDragDropContainer::DropBehavior::Inserted);
85 VisualizationDragDropContainer::DropBehavior::Inserted);
86 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
86 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
87 VisualizationDragDropContainer::DropBehavior::Inserted);
87 VisualizationDragDropContainer::DropBehavior::Inserted);
88 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
88 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
89 VisualizationDragDropContainer::DropBehavior::Inserted);
89 VisualizationDragDropContainer::DropBehavior::Inserted);
90
90
91 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
91 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
92 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
92 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
93 ui->dragDropContainer);
93 ui->dragDropContainer);
94 });
94 });
95
95
96 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
96 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
97 &VisualizationTabWidget::dropMimeData);
97 &VisualizationTabWidget::dropMimeData);
98
98
99 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
99 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
100
100
101 // Widget is deleted when closed
101 // Widget is deleted when closed
102 setAttribute(Qt::WA_DeleteOnClose);
102 setAttribute(Qt::WA_DeleteOnClose);
103 }
103 }
104
104
105 VisualizationTabWidget::~VisualizationTabWidget()
105 VisualizationTabWidget::~VisualizationTabWidget()
106 {
106 {
107 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
107 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
108 delete ui;
108 delete ui;
109 }
109 }
110
110
111 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
111 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
112 {
112 {
113 ui->dragDropContainer->addDragWidget(zoneWidget);
113 ui->dragDropContainer->addDragWidget(zoneWidget);
114 }
114 }
115
115
116 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
116 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
117 {
117 {
118 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
118 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
119 }
119 }
120
120
121 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
121 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
122 {
122 {
123 return createZone({variable}, -1);
123 return createZone({variable}, -1);
124 }
124 }
125
125
126 VisualizationZoneWidget *
126 VisualizationZoneWidget *
127 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
127 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
128 {
128 {
129 auto zoneWidget = createEmptyZone(index);
129 auto zoneWidget = createEmptyZone(index);
130
130
131 // Creates a new graph into the zone
131 // Creates a new graph into the zone
132 zoneWidget->createGraph(variables, index);
132 zoneWidget->createGraph(variables, index);
133
133
134 return zoneWidget;
134 return zoneWidget;
135 }
135 }
136
136
137 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
137 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
138 {
138 {
139 auto zoneWidget
139 auto zoneWidget
140 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
140 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
141 this->insertZone(index, zoneWidget);
141 this->insertZone(index, zoneWidget);
142
142
143 return zoneWidget;
143 return zoneWidget;
144 }
144 }
145
145
146 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
146 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
147 {
147 {
148 if (visitor) {
148 if (visitor) {
149 visitor->visitEnter(this);
149 visitor->visitEnter(this);
150
150
151 // Apply visitor to zone children: widgets different from zones are not visited (no action)
151 // Apply visitor to zone children: widgets different from zones are not visited (no action)
152 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
152 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
153 zoneWidget.accept(visitor);
153 zoneWidget.accept(visitor);
154 });
154 });
155
155
156 visitor->visitLeave(this);
156 visitor->visitLeave(this);
157 }
157 }
158 else {
158 else {
159 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
159 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
160 }
160 }
161 }
161 }
162
162
163 bool VisualizationTabWidget::canDrop(const Variable &variable) const
163 bool VisualizationTabWidget::canDrop(const Variable &variable) const
164 {
164 {
165 // A tab can always accomodate a variable
165 // A tab can always accomodate a variable
166 Q_UNUSED(variable);
166 Q_UNUSED(variable);
167 return true;
167 return true;
168 }
168 }
169
169
170 bool VisualizationTabWidget::contains(const Variable &variable) const
170 bool VisualizationTabWidget::contains(const Variable &variable) const
171 {
171 {
172 Q_UNUSED(variable);
172 Q_UNUSED(variable);
173 return false;
173 return false;
174 }
174 }
175
175
176 QString VisualizationTabWidget::name() const
176 QString VisualizationTabWidget::name() const
177 {
177 {
178 return impl->m_Name;
178 return impl->m_Name;
179 }
179 }
180
180
181 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
181 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
182 {
182 {
183 // Closes zones in the tab
183 // Closes zones in the tab
184 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
184 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
185
185
186 QWidget::closeEvent(event);
186 QWidget::closeEvent(event);
187 }
187 }
188
188
189 QLayout &VisualizationTabWidget::tabLayout() const noexcept
189 QLayout &VisualizationTabWidget::tabLayout() const noexcept
190 {
190 {
191 return *ui->dragDropContainer->layout();
191 return *ui->dragDropContainer->layout();
192 }
192 }
193
193
194 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
194 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
195 {
195 {
196 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
196 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
197 impl->dropGraph(index, this);
197 impl->dropGraph(index, this);
198 }
198 }
199 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
199 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
200 impl->dropZone(index, this);
200 impl->dropZone(index, this);
201 }
201 }
202 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
202 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
203 auto variables = sqpApp->variableController().variablesForMimeData(
203 auto variables = sqpApp->variableController().variablesForMimeData(
204 mimeData->data(MIME_TYPE_VARIABLE_LIST));
204 mimeData->data(MIME_TYPE_VARIABLE_LIST));
205 impl->dropVariables(variables, index, this);
205 impl->dropVariables(variables, index, this);
206 }
206 }
207 else {
207 else {
208 qCWarning(LOG_VisualizationZoneWidget())
208 qCWarning(LOG_VisualizationZoneWidget())
209 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
209 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
210 }
210 }
211 }
211 }
212
212
213 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
213 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
214 int index, VisualizationTabWidget *tabWidget)
214 int index, VisualizationTabWidget *tabWidget)
215 {
215 {
216 auto &helper = sqpApp->dragDropHelper();
216 auto &helper = sqpApp->dragDropHelper();
217
217
218 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
218 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
219 if (!graphWidget) {
219 if (!graphWidget) {
220 qCWarning(LOG_VisualizationZoneWidget())
220 qCWarning(LOG_VisualizationZoneWidget())
221 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
221 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
222 "found or invalid.");
222 "found or invalid.");
223 Q_ASSERT(false);
223 Q_ASSERT(false);
224 return;
224 return;
225 }
225 }
226
226
227 auto parentDragDropContainer
227 auto parentDragDropContainer
228 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
228 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
229 if (!parentDragDropContainer) {
229 if (!parentDragDropContainer) {
230 qCWarning(LOG_VisualizationZoneWidget())
230 qCWarning(LOG_VisualizationZoneWidget())
231 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
231 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
232 "the dropped graph is not found.");
232 "the dropped graph is not found.");
233 Q_ASSERT(false);
233 Q_ASSERT(false);
234 return;
234 return;
235 }
235 }
236
236
237 auto nbGraph = parentDragDropContainer->countDragWidget();
237 auto nbGraph = parentDragDropContainer->countDragWidget();
238
238
239 const auto &variables = graphWidget->variables();
239 const auto &variables = graphWidget->variables();
240
240
241 if (!variables.isEmpty()) {
241 if (!variables.isEmpty()) {
242 // Abort the requests for the variables (if any)
242 // Abort the requests for the variables (if any)
243 // Commented, because it's not sure if it's needed or not
243 // Commented, because it's not sure if it's needed or not
244 // for (const auto& var : variables)
244 // for (const auto& var : variables)
245 //{
245 //{
246 // sqpApp->variableController().onAbortProgressRequested(var);
246 // sqpApp->variableController().onAbortProgressRequested(var);
247 //}
247 //}
248
248
249 if (nbGraph == 1) {
249 if (nbGraph == 1) {
250 // This is the only graph in the previous zone, close the zone
250 // This is the only graph in the previous zone, close the zone
251 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
251 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
252 }
252 }
253 else {
253 else {
254 // Close the graph
254 // Close the graph
255 helper.delayedCloseWidget(graphWidget);
255 helper.delayedCloseWidget(graphWidget);
256 }
256 }
257
257
258 tabWidget->createZone(variables, index);
258 auto zoneWidget = tabWidget->createZone(variables, index);
259 auto firstGraph = zoneWidget->firstGraph();
260 if (firstGraph) {
261 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
262 }
263 else {
264 qCWarning(LOG_VisualizationZoneWidget())
265 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
266 Q_ASSERT(false);
267 }
259 }
268 }
260 else {
269 else {
261 // The graph is empty, create an empty zone and move the graph inside
270 // The graph is empty, create an empty zone and move the graph inside
262
271
263 auto parentZoneWidget = graphWidget->parentZoneWidget();
272 auto parentZoneWidget = graphWidget->parentZoneWidget();
264
273
265 parentDragDropContainer->layout()->removeWidget(graphWidget);
274 parentDragDropContainer->layout()->removeWidget(graphWidget);
266
275
267 auto zoneWidget = tabWidget->createEmptyZone(index);
276 auto zoneWidget = tabWidget->createEmptyZone(index);
268 zoneWidget->addGraph(graphWidget);
277 zoneWidget->addGraph(graphWidget);
269
278
270 // Close the old zone if it was the only graph inside
279 // Close the old zone if it was the only graph inside
271 if (nbGraph == 1) {
280 if (nbGraph == 1) {
272 helper.delayedCloseWidget(parentZoneWidget);
281 helper.delayedCloseWidget(parentZoneWidget);
273 }
282 }
274 }
283 }
275 }
284 }
276
285
277 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
286 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
278 int index, VisualizationTabWidget *tabWidget)
287 int index, VisualizationTabWidget *tabWidget)
279 {
288 {
280 auto &helper = sqpApp->dragDropHelper();
289 auto &helper = sqpApp->dragDropHelper();
281
290
282 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
291 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
283 if (!zoneWidget) {
292 if (!zoneWidget) {
284 qCWarning(LOG_VisualizationZoneWidget())
293 qCWarning(LOG_VisualizationZoneWidget())
285 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
294 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
286 "found or invalid.");
295 "found or invalid.");
287 Q_ASSERT(false);
296 Q_ASSERT(false);
288 return;
297 return;
289 }
298 }
290
299
291 auto parentDragDropContainer
300 auto parentDragDropContainer
292 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
301 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
293 if (!parentDragDropContainer) {
302 if (!parentDragDropContainer) {
294 qCWarning(LOG_VisualizationZoneWidget())
303 qCWarning(LOG_VisualizationZoneWidget())
295 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
304 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
296 "the dropped zone is not found.");
305 "the dropped zone is not found.");
297 Q_ASSERT(false);
306 Q_ASSERT(false);
298 return;
307 return;
299 }
308 }
300
309
301 // Simple move of the zone, no variable operation associated
310 // Simple move of the zone, no variable operation associated
302 parentDragDropContainer->layout()->removeWidget(zoneWidget);
311 parentDragDropContainer->layout()->removeWidget(zoneWidget);
303 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
312 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
304 }
313 }
305
314
306 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
315 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
307 const QList<std::shared_ptr<Variable> > &variables, int index,
316 const QList<std::shared_ptr<Variable> > &variables, int index,
308 VisualizationTabWidget *tabWidget)
317 VisualizationTabWidget *tabWidget)
309 {
318 {
310 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
319 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
311 // compatible variable here
320 // compatible variable here
312 if (variables.count() > 1) {
321 if (variables.count() > 1) {
313 qCWarning(LOG_VisualizationZoneWidget())
322 qCWarning(LOG_VisualizationZoneWidget())
314 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
323 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
315 "aborted.");
324 "aborted.");
316 return;
325 return;
317 }
326 }
318
327
319 tabWidget->createZone(variables, index);
328 tabWidget->createZone(variables, index);
320 }
329 }
@@ -1,178 +1,197
1 #include "Visualization/VisualizationWidget.h"
1 #include "Visualization/VisualizationWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/VisualizationGraphWidget.h"
4 #include "Visualization/VisualizationSelectionZoneManager.h"
4 #include "Visualization/VisualizationTabWidget.h"
5 #include "Visualization/VisualizationTabWidget.h"
5 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/operations/FindVariableOperation.h"
7 #include "Visualization/operations/FindVariableOperation.h"
7 #include "Visualization/operations/GenerateVariableMenuOperation.h"
8 #include "Visualization/operations/GenerateVariableMenuOperation.h"
8 #include "Visualization/operations/RemoveVariableOperation.h"
9 #include "Visualization/operations/RemoveVariableOperation.h"
9 #include "Visualization/operations/RescaleAxeOperation.h"
10 #include "Visualization/operations/RescaleAxeOperation.h"
10 #include "Visualization/qcustomplot.h"
11 #include "Visualization/qcustomplot.h"
11
12
12 #include "ui_VisualizationWidget.h"
13 #include "ui_VisualizationWidget.h"
13
14
14 #include "DragAndDrop/DragDropHelper.h"
15 #include "DragAndDrop/DragDropHelper.h"
15 #include "SqpApplication.h"
16 #include "SqpApplication.h"
16
17
17 #include <QToolButton>
18 #include <QToolButton>
18
19
20 #include <memory>
21
19 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
22 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
20
23
24 struct VisualizationWidget::VisualizationWidgetPrivate {
25 std::unique_ptr<VisualizationSelectionZoneManager> m_ZoneSelectionManager = nullptr;
26
27 VisualizationWidgetPrivate()
28 : m_ZoneSelectionManager(std::make_unique<VisualizationSelectionZoneManager>())
29 {
30 }
31 };
32
21 VisualizationWidget::VisualizationWidget(QWidget *parent)
33 VisualizationWidget::VisualizationWidget(QWidget *parent)
22 : QWidget{parent}, ui{new Ui::VisualizationWidget}
34 : QWidget{parent},
35 ui{new Ui::VisualizationWidget},
36 impl{spimpl::make_unique_impl<VisualizationWidgetPrivate>()}
23 {
37 {
24 ui->setupUi(this);
38 ui->setupUi(this);
25
39
26 auto addTabViewButton = new QToolButton{ui->tabWidget};
40 auto addTabViewButton = new QToolButton{ui->tabWidget};
27 addTabViewButton->setText(tr("Add View"));
41 addTabViewButton->setText(tr("Add View"));
28 addTabViewButton->setCursor(Qt::ArrowCursor);
42 addTabViewButton->setCursor(Qt::ArrowCursor);
29 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
43 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
30
44
31 auto enableMinimumCornerWidgetSize = [this](bool enable) {
45 auto enableMinimumCornerWidgetSize = [this](bool enable) {
32
46
33 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
47 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
34 auto width = enable ? tabViewCornerWidget->width() : 0;
48 auto width = enable ? tabViewCornerWidget->width() : 0;
35 auto height = enable ? tabViewCornerWidget->height() : 0;
49 auto height = enable ? tabViewCornerWidget->height() : 0;
36 tabViewCornerWidget->setMinimumHeight(height);
50 tabViewCornerWidget->setMinimumHeight(height);
37 tabViewCornerWidget->setMinimumWidth(width);
51 tabViewCornerWidget->setMinimumWidth(width);
38 ui->tabWidget->setMinimumHeight(height);
52 ui->tabWidget->setMinimumHeight(height);
39 ui->tabWidget->setMinimumWidth(width);
53 ui->tabWidget->setMinimumWidth(width);
40 };
54 };
41
55
42 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
56 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
43 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
57 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
44 ui->tabWidget};
58 ui->tabWidget};
45 auto index = ui->tabWidget->addTab(widget, widget->name());
59 auto index = ui->tabWidget->addTab(widget, widget->name());
46 if (ui->tabWidget->count() > 0) {
60 if (ui->tabWidget->count() > 0) {
47 enableMinimumCornerWidgetSize(false);
61 enableMinimumCornerWidgetSize(false);
48 }
62 }
49 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
63 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
50 };
64 };
51
65
52 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
66 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
53 if (ui->tabWidget->count() == 1) {
67 if (ui->tabWidget->count() == 1) {
54 enableMinimumCornerWidgetSize(true);
68 enableMinimumCornerWidgetSize(true);
55 }
69 }
56
70
57 // Removes widget from tab and closes it
71 // Removes widget from tab and closes it
58 auto widget = ui->tabWidget->widget(index);
72 auto widget = ui->tabWidget->widget(index);
59 ui->tabWidget->removeTab(index);
73 ui->tabWidget->removeTab(index);
60 if (widget) {
74 if (widget) {
61 widget->close();
75 widget->close();
62 }
76 }
63
77
64 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
78 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
65
79
66 };
80 };
67
81
68 ui->tabWidget->setTabsClosable(true);
82 ui->tabWidget->setTabsClosable(true);
69
83
70 connect(addTabViewButton, &QToolButton::clicked, addTabView);
84 connect(addTabViewButton, &QToolButton::clicked, addTabView);
71 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
85 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
72
86
73 sqpApp->dragDropHelper().addDragDropTabBar(ui->tabWidget->tabBar());
87 sqpApp->dragDropHelper().addDragDropTabBar(ui->tabWidget->tabBar());
74
88
75 // Adds default tab
89 // Adds default tab
76 addTabView();
90 addTabView();
77 }
91 }
78
92
79 VisualizationWidget::~VisualizationWidget()
93 VisualizationWidget::~VisualizationWidget()
80 {
94 {
81 sqpApp->dragDropHelper().removeDragDropTabBar(ui->tabWidget->tabBar());
95 sqpApp->dragDropHelper().removeDragDropTabBar(ui->tabWidget->tabBar());
82 delete ui;
96 delete ui;
83 }
97 }
84
98
99 VisualizationSelectionZoneManager &VisualizationWidget::selectionZoneManager() const
100 {
101 return *impl->m_ZoneSelectionManager.get();
102 }
103
85 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
104 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
86 {
105 {
87 if (visitor) {
106 if (visitor) {
88 visitor->visitEnter(this);
107 visitor->visitEnter(this);
89
108
90 // Apply visitor for tab children
109 // Apply visitor for tab children
91 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
110 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
92 // Widgets different from tabs are not visited (no action)
111 // Widgets different from tabs are not visited (no action)
93 if (auto visualizationTabWidget
112 if (auto visualizationTabWidget
94 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
113 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
95 visualizationTabWidget->accept(visitor);
114 visualizationTabWidget->accept(visitor);
96 }
115 }
97 }
116 }
98
117
99 visitor->visitLeave(this);
118 visitor->visitLeave(this);
100 }
119 }
101 else {
120 else {
102 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
121 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
103 }
122 }
104 }
123 }
105
124
106 bool VisualizationWidget::canDrop(const Variable &variable) const
125 bool VisualizationWidget::canDrop(const Variable &variable) const
107 {
126 {
108 // The main widget can never accomodate a variable
127 // The main widget can never accomodate a variable
109 Q_UNUSED(variable);
128 Q_UNUSED(variable);
110 return false;
129 return false;
111 }
130 }
112
131
113 bool VisualizationWidget::contains(const Variable &variable) const
132 bool VisualizationWidget::contains(const Variable &variable) const
114 {
133 {
115 Q_UNUSED(variable);
134 Q_UNUSED(variable);
116 return false;
135 return false;
117 }
136 }
118
137
119 QString VisualizationWidget::name() const
138 QString VisualizationWidget::name() const
120 {
139 {
121 return QStringLiteral("MainView");
140 return QStringLiteral("MainView");
122 }
141 }
123
142
124 void VisualizationWidget::attachVariableMenu(
143 void VisualizationWidget::attachVariableMenu(
125 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
144 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
126 {
145 {
127 // Menu is generated only if there is a single variable
146 // Menu is generated only if there is a single variable
128 if (variables.size() == 1) {
147 if (variables.size() == 1) {
129 if (auto variable = variables.first()) {
148 if (auto variable = variables.first()) {
130 // Gets the containers of the variable
149 // Gets the containers of the variable
131 FindVariableOperation findVariableOperation{variable};
150 FindVariableOperation findVariableOperation{variable};
132 accept(&findVariableOperation);
151 accept(&findVariableOperation);
133 auto variableContainers = findVariableOperation.result();
152 auto variableContainers = findVariableOperation.result();
134
153
135 // Generates the actions that make it possible to visualize the variable
154 // Generates the actions that make it possible to visualize the variable
136 GenerateVariableMenuOperation generateVariableMenuOperation{
155 GenerateVariableMenuOperation generateVariableMenuOperation{
137 menu, variable, std::move(variableContainers)};
156 menu, variable, std::move(variableContainers)};
138 accept(&generateVariableMenuOperation);
157 accept(&generateVariableMenuOperation);
139 }
158 }
140 else {
159 else {
141 qCCritical(LOG_VisualizationWidget()) << tr(
160 qCCritical(LOG_VisualizationWidget()) << tr(
142 "Can't generate the menu relative to the visualization: the variable is null");
161 "Can't generate the menu relative to the visualization: the variable is null");
143 }
162 }
144 }
163 }
145 else {
164 else {
146 qCDebug(LOG_VisualizationWidget())
165 qCDebug(LOG_VisualizationWidget())
147 << tr("No generation of the menu related to the visualization: several variables are "
166 << tr("No generation of the menu related to the visualization: several variables are "
148 "selected");
167 "selected");
149 }
168 }
150 }
169 }
151
170
152 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
171 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
153 {
172 {
154 // Calls the operation of removing all references to the variable in the visualization
173 // Calls the operation of removing all references to the variable in the visualization
155 auto removeVariableOperation = RemoveVariableOperation{variable};
174 auto removeVariableOperation = RemoveVariableOperation{variable};
156 accept(&removeVariableOperation);
175 accept(&removeVariableOperation);
157 }
176 }
158
177
159 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
178 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
160 const SqpRange &range) noexcept
179 const SqpRange &range) noexcept
161 {
180 {
162 // Calls the operation of rescaling all graph that contrains variable in the visualization
181 // Calls the operation of rescaling all graph that contrains variable in the visualization
163 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
182 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
164 accept(&rescaleVariableOperation);
183 accept(&rescaleVariableOperation);
165 }
184 }
166
185
167 void VisualizationWidget::closeEvent(QCloseEvent *event)
186 void VisualizationWidget::closeEvent(QCloseEvent *event)
168 {
187 {
169 // Closes tabs in the widget
188 // Closes tabs in the widget
170 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
189 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
171 if (auto visualizationTabWidget
190 if (auto visualizationTabWidget
172 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
191 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
173 visualizationTabWidget->close();
192 visualizationTabWidget->close();
174 }
193 }
175 }
194 }
176
195
177 QWidget::closeEvent(event);
196 QWidget::closeEvent(event);
178 }
197 }
@@ -1,583 +1,587
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationWidget.h"
6 #include "Visualization/VisualizationWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
8
8
9 #include "Common/MimeTypesDef.h"
9 #include "Common/MimeTypesDef.h"
10 #include "Common/VisualizationDef.h"
10 #include "Common/VisualizationDef.h"
11
11
12 #include <Data/SqpRange.h>
12 #include <Data/SqpRange.h>
13 #include <Time/TimeController.h>
13 #include <Time/TimeController.h>
14 #include <Variable/Variable.h>
14 #include <Variable/Variable.h>
15 #include <Variable/VariableController.h>
15 #include <Variable/VariableController.h>
16
16
17 #include <Visualization/operations/FindVariableOperation.h>
17 #include <Visualization/operations/FindVariableOperation.h>
18
18
19 #include <DragAndDrop/DragDropHelper.h>
19 #include <DragAndDrop/DragDropHelper.h>
20 #include <QUuid>
20 #include <QUuid>
21 #include <SqpApplication.h>
21 #include <SqpApplication.h>
22 #include <cmath>
22 #include <cmath>
23
23
24 #include <QLayout>
24 #include <QLayout>
25
25
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27
27
28 namespace {
28 namespace {
29
29
30
30
31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
32 /// the zone
32 /// the zone
33 QString defaultGraphName(const QLayout &layout)
33 QString defaultGraphName(const QLayout &layout)
34 {
34 {
35 auto count = 0;
35 auto count = 0;
36 for (auto i = 0; i < layout.count(); ++i) {
36 for (auto i = 0; i < layout.count(); ++i) {
37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
38 count++;
38 count++;
39 }
39 }
40 }
40 }
41
41
42 return QObject::tr("Graph %1").arg(count + 1);
42 return QObject::tr("Graph %1").arg(count + 1);
43 }
43 }
44
44
45 /**
45 /**
46 * Applies a function to all graphs of the zone represented by its layout
46 * Applies a function to all graphs of the zone represented by its layout
47 * @param layout the layout that contains graphs
47 * @param layout the layout that contains graphs
48 * @param fun the function to apply to each graph
48 * @param fun the function to apply to each graph
49 */
49 */
50 template <typename Fun>
50 template <typename Fun>
51 void processGraphs(QLayout &layout, Fun fun)
51 void processGraphs(QLayout &layout, Fun fun)
52 {
52 {
53 for (auto i = 0; i < layout.count(); ++i) {
53 for (auto i = 0; i < layout.count(); ++i) {
54 if (auto item = layout.itemAt(i)) {
54 if (auto item = layout.itemAt(i)) {
55 if (auto visualizationGraphWidget
55 if (auto visualizationGraphWidget
56 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
56 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
57 fun(*visualizationGraphWidget);
57 fun(*visualizationGraphWidget);
58 }
58 }
59 }
59 }
60 }
60 }
61 }
61 }
62
62
63 } // namespace
63 } // namespace
64
64
65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
66
66
67 explicit VisualizationZoneWidgetPrivate()
67 explicit VisualizationZoneWidgetPrivate()
68 : m_SynchronisationGroupId{QUuid::createUuid()},
68 : m_SynchronisationGroupId{QUuid::createUuid()},
69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
70 {
70 {
71 }
71 }
72 QUuid m_SynchronisationGroupId;
72 QUuid m_SynchronisationGroupId;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
74
74
75 // Returns the first graph in the zone or nullptr if there is no graph inside
76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
77 {
78 VisualizationGraphWidget *firstGraph = nullptr;
79 auto layout = zoneWidget->ui->dragDropContainer->layout();
80 if (layout->count() > 0) {
81 if (auto visualizationGraphWidget
82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
83 firstGraph = visualizationGraphWidget;
84 }
85 }
86
87 return firstGraph;
88 }
89
90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
75 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
76 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
92 VisualizationZoneWidget *zoneWidget);
77 VisualizationZoneWidget *zoneWidget);
93 };
78 };
94
79
95 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
80 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
96 : VisualizationDragWidget{parent},
81 : VisualizationDragWidget{parent},
97 ui{new Ui::VisualizationZoneWidget},
82 ui{new Ui::VisualizationZoneWidget},
98 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
83 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
99 {
84 {
100 ui->setupUi(this);
85 ui->setupUi(this);
101
86
102 ui->zoneNameLabel->setText(name);
87 ui->zoneNameLabel->setText(name);
103
88
104 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
89 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
105 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
90 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
106 VisualizationDragDropContainer::DropBehavior::Inserted);
91 VisualizationDragDropContainer::DropBehavior::Inserted);
107 ui->dragDropContainer->setMimeType(
92 ui->dragDropContainer->setMimeType(
108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
93 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
109 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
94 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
110 VisualizationDragDropContainer::DropBehavior::Merged);
95 VisualizationDragDropContainer::DropBehavior::Merged);
111 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
96 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
112 VisualizationDragDropContainer::DropBehavior::Forbidden);
97 VisualizationDragDropContainer::DropBehavior::Forbidden);
98 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
99 VisualizationDragDropContainer::DropBehavior::Forbidden);
113 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
100 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
114 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
101 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
115 ui->dragDropContainer);
102 ui->dragDropContainer);
116 });
103 });
117
104
118 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
105 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
119 if (!mimeData) {
106 if (!mimeData) {
120 return false;
107 return false;
121 }
108 }
122
109
123 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
110 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
124 auto variables = sqpApp->variableController().variablesForMimeData(
111 auto variables = sqpApp->variableController().variablesForMimeData(
125 mimeData->data(MIME_TYPE_VARIABLE_LIST));
112 mimeData->data(MIME_TYPE_VARIABLE_LIST));
126
113
127 if (variables.count() != 1) {
114 if (variables.count() != 1) {
128 return false;
115 return false;
129 }
116 }
130 auto variable = variables.first();
117 auto variable = variables.first();
131
118
132 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
119 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
133 return graphWidget->canDrop(*variable);
120 return graphWidget->canDrop(*variable);
134 }
121 }
135 }
122 }
136
123
137 return true;
124 return true;
138 };
125 };
139 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
126 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
140
127
141 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
128 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
142 &VisualizationZoneWidget::dropMimeData);
129 &VisualizationZoneWidget::dropMimeData);
143 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
130 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
144 &VisualizationZoneWidget::dropMimeDataOnGraph);
131 &VisualizationZoneWidget::dropMimeDataOnGraph);
145
132
146 // 'Close' options : widget is deleted when closed
133 // 'Close' options : widget is deleted when closed
147 setAttribute(Qt::WA_DeleteOnClose);
134 setAttribute(Qt::WA_DeleteOnClose);
148 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
135 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
149 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
136 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
150
137
151 // Synchronisation id
138 // Synchronisation id
152 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
139 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
153 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
140 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
154 }
141 }
155
142
156 VisualizationZoneWidget::~VisualizationZoneWidget()
143 VisualizationZoneWidget::~VisualizationZoneWidget()
157 {
144 {
158 delete ui;
145 delete ui;
159 }
146 }
160
147
161 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
148 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
162 {
149 {
163 // Synchronize new graph with others in the zone
150 // Synchronize new graph with others in the zone
164 impl->m_Synchronizer->addGraph(*graphWidget);
151 impl->m_Synchronizer->addGraph(*graphWidget);
165
152
166 ui->dragDropContainer->addDragWidget(graphWidget);
153 ui->dragDropContainer->addDragWidget(graphWidget);
167 }
154 }
168
155
169 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
156 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
170 {
157 {
171 // Synchronize new graph with others in the zone
158 // Synchronize new graph with others in the zone
172 impl->m_Synchronizer->addGraph(*graphWidget);
159 impl->m_Synchronizer->addGraph(*graphWidget);
173
160
174 ui->dragDropContainer->insertDragWidget(index, graphWidget);
161 ui->dragDropContainer->insertDragWidget(index, graphWidget);
175 }
162 }
176
163
177 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
164 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
178 {
165 {
179 return createGraph(variable, -1);
166 return createGraph(variable, -1);
180 }
167 }
181
168
182 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
169 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
183 int index)
170 int index)
184 {
171 {
185 auto graphWidget
172 auto graphWidget
186 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
173 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
187
174
188
175
189 // Set graph properties
176 // Set graph properties
190 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
177 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
191 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
178 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
192
179
193
180
194 // Lambda to synchronize zone widget
181 // Lambda to synchronize zone widget
195 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
182 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
196 const SqpRange &oldGraphRange) {
183 const SqpRange &oldGraphRange) {
197
184
198 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
185 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
199 auto frameLayout = ui->dragDropContainer->layout();
186 auto frameLayout = ui->dragDropContainer->layout();
200 for (auto i = 0; i < frameLayout->count(); ++i) {
187 for (auto i = 0; i < frameLayout->count(); ++i) {
201 auto graphChild
188 auto graphChild
202 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
189 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
203 if (graphChild && (graphChild != graphWidget)) {
190 if (graphChild && (graphChild != graphWidget)) {
204
191
205 auto graphChildRange = graphChild->graphRange();
192 auto graphChildRange = graphChild->graphRange();
206 switch (zoomType) {
193 switch (zoomType) {
207 case AcquisitionZoomType::ZoomIn: {
194 case AcquisitionZoomType::ZoomIn: {
208 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
195 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
209 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
196 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
210 graphChildRange.m_TStart += deltaLeft;
197 graphChildRange.m_TStart += deltaLeft;
211 graphChildRange.m_TEnd -= deltaRight;
198 graphChildRange.m_TEnd -= deltaRight;
212 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
199 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
200 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
214 << deltaLeft;
201 << deltaLeft;
215 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
202 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
216 << deltaRight;
203 << deltaRight;
217 qCDebug(LOG_VisualizationZoneWidget())
204 qCDebug(LOG_VisualizationZoneWidget())
218 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
205 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
219
206
220 break;
207 break;
221 }
208 }
222
209
223 case AcquisitionZoomType::ZoomOut: {
210 case AcquisitionZoomType::ZoomOut: {
224 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
211 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
225 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
212 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
226 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
213 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
227 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
214 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
228 << deltaLeft;
215 << deltaLeft;
229 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
216 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
230 << deltaRight;
217 << deltaRight;
231 qCDebug(LOG_VisualizationZoneWidget())
218 qCDebug(LOG_VisualizationZoneWidget())
232 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
233 graphChildRange.m_TStart -= deltaLeft;
220 graphChildRange.m_TStart -= deltaLeft;
234 graphChildRange.m_TEnd += deltaRight;
221 graphChildRange.m_TEnd += deltaRight;
235 break;
222 break;
236 }
223 }
237 case AcquisitionZoomType::PanRight: {
224 case AcquisitionZoomType::PanRight: {
238 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
225 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
239 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
226 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
240 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
227 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
241 graphChildRange.m_TStart += deltaLeft;
228 graphChildRange.m_TStart += deltaLeft;
242 graphChildRange.m_TEnd += deltaRight;
229 graphChildRange.m_TEnd += deltaRight;
243 qCDebug(LOG_VisualizationZoneWidget())
230 qCDebug(LOG_VisualizationZoneWidget())
244 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
231 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
245 break;
232 break;
246 }
233 }
247 case AcquisitionZoomType::PanLeft: {
234 case AcquisitionZoomType::PanLeft: {
248 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
235 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
249 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
236 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
250 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
237 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
251 graphChildRange.m_TStart -= deltaLeft;
238 graphChildRange.m_TStart -= deltaLeft;
252 graphChildRange.m_TEnd -= deltaRight;
239 graphChildRange.m_TEnd -= deltaRight;
253 break;
240 break;
254 }
241 }
255 case AcquisitionZoomType::Unknown: {
242 case AcquisitionZoomType::Unknown: {
256 qCDebug(LOG_VisualizationZoneWidget())
243 qCDebug(LOG_VisualizationZoneWidget())
257 << tr("Impossible to synchronize: zoom type unknown");
244 << tr("Impossible to synchronize: zoom type unknown");
258 break;
245 break;
259 }
246 }
260 default:
247 default:
261 qCCritical(LOG_VisualizationZoneWidget())
248 qCCritical(LOG_VisualizationZoneWidget())
262 << tr("Impossible to synchronize: zoom type not take into account");
249 << tr("Impossible to synchronize: zoom type not take into account");
263 // No action
250 // No action
264 break;
251 break;
265 }
252 }
266 graphChild->enableAcquisition(false);
253 graphChild->enableAcquisition(false);
267 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
254 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
268 << graphChild->graphRange();
255 << graphChild->graphRange();
269 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
256 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
270 << graphChildRange;
257 << graphChildRange;
271 qCDebug(LOG_VisualizationZoneWidget())
258 qCDebug(LOG_VisualizationZoneWidget())
272 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
259 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
273 graphChild->setGraphRange(graphChildRange);
260 graphChild->setGraphRange(graphChildRange);
274 graphChild->enableAcquisition(true);
261 graphChild->enableAcquisition(true);
275 }
262 }
276 }
263 }
277 };
264 };
278
265
279 // connection for synchronization
266 // connection for synchronization
280 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
267 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
281 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
268 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
282 &VisualizationZoneWidget::onVariableAdded);
269 &VisualizationZoneWidget::onVariableAdded);
283 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
270 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
284 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
271 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
285
272
286 auto range = SqpRange{};
273 auto range = SqpRange{};
287 if (auto firstGraph = impl->firstGraph(this)) {
274 if (auto firstGraph = this->firstGraph()) {
288 // Case of a new graph in a existant zone
275 // Case of a new graph in a existant zone
289 range = firstGraph->graphRange();
276 range = firstGraph->graphRange();
290 }
277 }
291 else {
278 else {
292 // Case of a new graph as the first of the zone
279 // Case of a new graph as the first of the zone
293 range = variable->range();
280 range = variable->range();
294 }
281 }
295
282
296 this->insertGraph(index, graphWidget);
283 this->insertGraph(index, graphWidget);
297
284
298 graphWidget->addVariable(variable, range);
285 graphWidget->addVariable(variable, range);
299 graphWidget->setYRange(variable);
286 graphWidget->setYRange(variable);
300
287
301 return graphWidget;
288 return graphWidget;
302 }
289 }
303
290
304 VisualizationGraphWidget *
291 VisualizationGraphWidget *
305 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
292 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
306 {
293 {
307 if (variables.isEmpty()) {
294 if (variables.isEmpty()) {
308 return nullptr;
295 return nullptr;
309 }
296 }
310
297
311 auto graphWidget = createGraph(variables.first(), index);
298 auto graphWidget = createGraph(variables.first(), index);
312 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
299 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
313 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
300 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
314 }
301 }
315
302
316 return graphWidget;
303 return graphWidget;
317 }
304 }
318
305
306 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
307 {
308 VisualizationGraphWidget *firstGraph = nullptr;
309 auto layout = ui->dragDropContainer->layout();
310 if (layout->count() > 0) {
311 if (auto visualizationGraphWidget
312 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
313 firstGraph = visualizationGraphWidget;
314 }
315 }
316
317 return firstGraph;
318 }
319
319 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
320 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
320 {
321 {
321 if (visitor) {
322 if (visitor) {
322 visitor->visitEnter(this);
323 visitor->visitEnter(this);
323
324
324 // Apply visitor to graph children: widgets different from graphs are not visited (no
325 // Apply visitor to graph children: widgets different from graphs are not visited (no
325 // action)
326 // action)
326 processGraphs(
327 processGraphs(
327 *ui->dragDropContainer->layout(),
328 *ui->dragDropContainer->layout(),
328 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
329 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
329
330
330 visitor->visitLeave(this);
331 visitor->visitLeave(this);
331 }
332 }
332 else {
333 else {
333 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
334 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
334 }
335 }
335 }
336 }
336
337
337 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
338 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
338 {
339 {
339 // A tab can always accomodate a variable
340 // A tab can always accomodate a variable
340 Q_UNUSED(variable);
341 Q_UNUSED(variable);
341 return true;
342 return true;
342 }
343 }
343
344
344 bool VisualizationZoneWidget::contains(const Variable &variable) const
345 bool VisualizationZoneWidget::contains(const Variable &variable) const
345 {
346 {
346 Q_UNUSED(variable);
347 Q_UNUSED(variable);
347 return false;
348 return false;
348 }
349 }
349
350
350 QString VisualizationZoneWidget::name() const
351 QString VisualizationZoneWidget::name() const
351 {
352 {
352 return ui->zoneNameLabel->text();
353 return ui->zoneNameLabel->text();
353 }
354 }
354
355
355 QMimeData *VisualizationZoneWidget::mimeData() const
356 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
356 {
357 {
358 Q_UNUSED(position);
359
357 auto mimeData = new QMimeData;
360 auto mimeData = new QMimeData;
358 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
361 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
359
362
360 if (auto firstGraph = impl->firstGraph(this)) {
363 if (auto firstGraph = this->firstGraph()) {
361 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
364 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
362 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
365 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
363 }
366 }
364
367
365 return mimeData;
368 return mimeData;
366 }
369 }
367
370
368 bool VisualizationZoneWidget::isDragAllowed() const
371 bool VisualizationZoneWidget::isDragAllowed() const
369 {
372 {
370 return true;
373 return true;
371 }
374 }
372
375
373 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
376 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
374 const QPointF &plotPosition,
377 const QPointF &plotPosition,
375 VisualizationGraphWidget *graphWidget)
378 VisualizationGraphWidget *graphWidget)
376 {
379 {
377 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
380 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
378 VisualizationGraphWidget &processedGraph) {
381 VisualizationGraphWidget &processedGraph) {
379
382
380 switch (sqpApp->plotsCursorMode()) {
383 switch (sqpApp->plotsCursorMode()) {
381 case SqpApplication::PlotsCursorMode::Vertical:
384 case SqpApplication::PlotsCursorMode::Vertical:
382 processedGraph.removeHorizontalCursor();
385 processedGraph.removeHorizontalCursor();
383 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
386 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
384 break;
387 break;
385 case SqpApplication::PlotsCursorMode::Temporal:
388 case SqpApplication::PlotsCursorMode::Temporal:
386 processedGraph.addVerticalCursor(plotPosition.x());
389 processedGraph.addVerticalCursor(plotPosition.x());
387 processedGraph.removeHorizontalCursor();
390 processedGraph.removeHorizontalCursor();
388 break;
391 break;
389 case SqpApplication::PlotsCursorMode::Horizontal:
392 case SqpApplication::PlotsCursorMode::Horizontal:
390 processedGraph.removeVerticalCursor();
393 processedGraph.removeVerticalCursor();
391 if (&processedGraph == graphWidget) {
394 if (&processedGraph == graphWidget) {
392 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
395 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
393 }
396 }
394 else {
397 else {
395 processedGraph.removeHorizontalCursor();
398 processedGraph.removeHorizontalCursor();
396 }
399 }
397 break;
400 break;
398 case SqpApplication::PlotsCursorMode::Cross:
401 case SqpApplication::PlotsCursorMode::Cross:
399 if (&processedGraph == graphWidget) {
402 if (&processedGraph == graphWidget) {
400 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
403 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
401 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
404 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
402 }
405 }
403 else {
406 else {
404 processedGraph.removeHorizontalCursor();
407 processedGraph.removeHorizontalCursor();
405 processedGraph.removeVerticalCursor();
408 processedGraph.removeVerticalCursor();
406 }
409 }
407 break;
410 break;
408 case SqpApplication::PlotsCursorMode::NoCursor:
411 case SqpApplication::PlotsCursorMode::NoCursor:
409 processedGraph.removeHorizontalCursor();
412 processedGraph.removeHorizontalCursor();
410 processedGraph.removeVerticalCursor();
413 processedGraph.removeVerticalCursor();
411 break;
414 break;
412 }
415 }
413
416
414
417
415 });
418 });
416 }
419 }
417
420
418 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
421 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
419 {
422 {
420 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
423 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
421 processedGraph.removeHorizontalCursor();
424 processedGraph.removeHorizontalCursor();
422 processedGraph.removeVerticalCursor();
425 processedGraph.removeVerticalCursor();
423 });
426 });
424 }
427 }
425
428
426 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
429 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
427 {
430 {
428 // Closes graphs in the zone
431 // Closes graphs in the zone
429 processGraphs(*ui->dragDropContainer->layout(),
432 processGraphs(*ui->dragDropContainer->layout(),
430 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
433 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
431
434
432 // Delete synchronization group from variable controller
435 // Delete synchronization group from variable controller
433 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
436 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
434 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
437 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
435
438
436 QWidget::closeEvent(event);
439 QWidget::closeEvent(event);
437 }
440 }
438
441
439 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
442 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
440 {
443 {
441 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
444 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
442 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
445 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
443 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
446 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
444 }
447 }
445
448
446 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
449 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
447 {
450 {
448 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
451 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
449 Q_ARG(std::shared_ptr<Variable>, variable),
452 Q_ARG(std::shared_ptr<Variable>, variable),
450 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
453 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
451 }
454 }
452
455
453 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
456 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
454 {
457 {
455 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
458 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
456 impl->dropGraph(index, this);
459 impl->dropGraph(index, this);
457 }
460 }
458 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
461 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
459 auto variables = sqpApp->variableController().variablesForMimeData(
462 auto variables = sqpApp->variableController().variablesForMimeData(
460 mimeData->data(MIME_TYPE_VARIABLE_LIST));
463 mimeData->data(MIME_TYPE_VARIABLE_LIST));
461 impl->dropVariables(variables, index, this);
464 impl->dropVariables(variables, index, this);
462 }
465 }
463 else {
466 else {
464 qCWarning(LOG_VisualizationZoneWidget())
467 qCWarning(LOG_VisualizationZoneWidget())
465 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
468 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
466 }
469 }
467 }
470 }
468
471
469 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
472 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
470 const QMimeData *mimeData)
473 const QMimeData *mimeData)
471 {
474 {
472 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
475 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
473 if (!graphWidget) {
476 if (!graphWidget) {
474 qCWarning(LOG_VisualizationZoneWidget())
477 qCWarning(LOG_VisualizationZoneWidget())
475 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
478 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
476 "drop aborted");
479 "drop aborted");
477 Q_ASSERT(false);
480 Q_ASSERT(false);
478 return;
481 return;
479 }
482 }
480
483
481 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
484 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
482 auto variables = sqpApp->variableController().variablesForMimeData(
485 auto variables = sqpApp->variableController().variablesForMimeData(
483 mimeData->data(MIME_TYPE_VARIABLE_LIST));
486 mimeData->data(MIME_TYPE_VARIABLE_LIST));
484 for (const auto &var : variables) {
487 for (const auto &var : variables) {
485 graphWidget->addVariable(var, graphWidget->graphRange());
488 graphWidget->addVariable(var, graphWidget->graphRange());
486 }
489 }
487 }
490 }
488 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
491 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
489 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
492 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
490 graphWidget->setGraphRange(range);
493 graphWidget->setGraphRange(range);
491 }
494 }
492 else {
495 else {
493 qCWarning(LOG_VisualizationZoneWidget())
496 qCWarning(LOG_VisualizationZoneWidget())
494 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
497 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
495 }
498 }
496 }
499 }
497
500
498 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
501 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
499 int index, VisualizationZoneWidget *zoneWidget)
502 int index, VisualizationZoneWidget *zoneWidget)
500 {
503 {
501 auto &helper = sqpApp->dragDropHelper();
504 auto &helper = sqpApp->dragDropHelper();
502
505
503 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
506 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
504 if (!graphWidget) {
507 if (!graphWidget) {
505 qCWarning(LOG_VisualizationZoneWidget())
508 qCWarning(LOG_VisualizationZoneWidget())
506 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
509 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
507 "found or invalid.");
510 "found or invalid.");
508 Q_ASSERT(false);
511 Q_ASSERT(false);
509 return;
512 return;
510 }
513 }
511
514
512 auto parentDragDropContainer
515 auto parentDragDropContainer
513 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
516 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
514 if (!parentDragDropContainer) {
517 if (!parentDragDropContainer) {
515 qCWarning(LOG_VisualizationZoneWidget())
518 qCWarning(LOG_VisualizationZoneWidget())
516 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
519 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
517 "the dropped graph is not found.");
520 "the dropped graph is not found.");
518 Q_ASSERT(false);
521 Q_ASSERT(false);
519 return;
522 return;
520 }
523 }
521
524
522 const auto &variables = graphWidget->variables();
525 const auto &variables = graphWidget->variables();
523
526
524 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
527 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
525 // The drop didn't occur in the same zone
528 // The drop didn't occur in the same zone
526
529
527 // Abort the requests for the variables (if any)
530 // Abort the requests for the variables (if any)
528 // Commented, because it's not sure if it's needed or not
531 // Commented, because it's not sure if it's needed or not
529 // for (const auto& var : variables)
532 // for (const auto& var : variables)
530 //{
533 //{
531 // sqpApp->variableController().onAbortProgressRequested(var);
534 // sqpApp->variableController().onAbortProgressRequested(var);
532 //}
535 //}
533
536
534 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
537 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
535 auto nbGraph = parentDragDropContainer->countDragWidget();
538 auto nbGraph = parentDragDropContainer->countDragWidget();
536 if (nbGraph == 1) {
539 if (nbGraph == 1) {
537 // This is the only graph in the previous zone, close the zone
540 // This is the only graph in the previous zone, close the zone
538 helper.delayedCloseWidget(previousParentZoneWidget);
541 helper.delayedCloseWidget(previousParentZoneWidget);
539 }
542 }
540 else {
543 else {
541 // Close the graph
544 // Close the graph
542 helper.delayedCloseWidget(graphWidget);
545 helper.delayedCloseWidget(graphWidget);
543 }
546 }
544
547
545 // Creates the new graph in the zone
548 // Creates the new graph in the zone
546 zoneWidget->createGraph(variables, index);
549 auto newGraphWidget = zoneWidget->createGraph(variables, index);
550 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
547 }
551 }
548 else {
552 else {
549 // The drop occurred in the same zone or the graph is empty
553 // The drop occurred in the same zone or the graph is empty
550 // Simple move of the graph, no variable operation associated
554 // Simple move of the graph, no variable operation associated
551 parentDragDropContainer->layout()->removeWidget(graphWidget);
555 parentDragDropContainer->layout()->removeWidget(graphWidget);
552
556
553 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
557 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
554 // The graph is empty and dropped in a different zone.
558 // The graph is empty and dropped in a different zone.
555 // Take the range of the first graph in the zone (if existing).
559 // Take the range of the first graph in the zone (if existing).
556 auto layout = zoneWidget->ui->dragDropContainer->layout();
560 auto layout = zoneWidget->ui->dragDropContainer->layout();
557 if (layout->count() > 0) {
561 if (layout->count() > 0) {
558 if (auto visualizationGraphWidget
562 if (auto visualizationGraphWidget
559 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
563 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
560 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
564 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
561 }
565 }
562 }
566 }
563 }
567 }
564
568
565 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
569 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
566 }
570 }
567 }
571 }
568
572
569 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
573 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
570 const QList<std::shared_ptr<Variable> > &variables, int index,
574 const QList<std::shared_ptr<Variable> > &variables, int index,
571 VisualizationZoneWidget *zoneWidget)
575 VisualizationZoneWidget *zoneWidget)
572 {
576 {
573 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
577 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
574 // compatible variable here
578 // compatible variable here
575 if (variables.count() > 1) {
579 if (variables.count() > 1) {
576 qCWarning(LOG_VisualizationZoneWidget())
580 qCWarning(LOG_VisualizationZoneWidget())
577 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
581 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
578 "aborted.");
582 "aborted.");
579 return;
583 return;
580 }
584 }
581
585
582 zoneWidget->createGraph(variables, index);
586 zoneWidget->createGraph(variables, index);
583 }
587 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved

Status change > Approved

You need to be logged in to leave comments. Login now