##// END OF EJS Templates
Moves the DragDropHelper file
trabillard -
r890:9b45c5936f92
parent child
Show More
1 NO CONTENT: file renamed from gui/include/DragDropHelper.h to gui/include/DragAndDrop/DragDropHelper.h
@@ -1,57 +1,57
1 1 #ifndef SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
2 2 #define SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
3 3
4 4 #include <Common/spimpl.h>
5 5 #include <QFrame>
6 6 #include <QLoggingCategory>
7 7 #include <QMimeData>
8 8 #include <QVBoxLayout>
9 9
10 10 #include <functional>
11 11
12 #include <DragDropHelper.h>
12 #include <DragAndDrop/DragDropHelper.h>
13 13
14 14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer)
15 15
16 16 class VisualizationDragWidget;
17 17
18 18 class VisualizationDragDropContainer : public QFrame {
19 19 Q_OBJECT
20 20
21 21 signals:
22 22 void dropOccuredInContainer(int dropIndex, const QMimeData *mimeData);
23 23 void dropOccuredOnWidget(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
24 24
25 25 public:
26 26 enum class DropBehavior { Inserted, Merged, InsertedAndMerged };
27 27 using AcceptMimeDataFunction = std::function<bool(const QMimeData *mimeData)>;
28 28
29 29 VisualizationDragDropContainer(QWidget *parent = nullptr);
30 30
31 31 void addDragWidget(VisualizationDragWidget *dragWidget);
32 32 void insertDragWidget(int index, VisualizationDragWidget *dragWidget);
33 33
34 34 void addAcceptedMimeType(const QString &mimeType, DropBehavior behavior);
35 35
36 36 int countDragWidget() const;
37 37
38 38 void setAcceptMimeDataFunction(AcceptMimeDataFunction fun);
39 39
40 40 void setPlaceHolderType(DragDropHelper::PlaceHolderType type,
41 41 const QString &placeHolderText = QString());
42 42
43 43 protected:
44 44 void dragEnterEvent(QDragEnterEvent *event);
45 45 void dragLeaveEvent(QDragLeaveEvent *event);
46 46 void dragMoveEvent(QDragMoveEvent *event);
47 47 void dropEvent(QDropEvent *event);
48 48
49 49 private:
50 50 class VisualizationDragDropContainerPrivate;
51 51 spimpl::unique_impl_ptr<VisualizationDragDropContainerPrivate> impl;
52 52
53 53 private slots:
54 54 void startDrag(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
55 55 };
56 56
57 57 #endif // SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
@@ -1,91 +1,91
1 1
2 2 gui_moc_headers = [
3 3 'include/DataSource/DataSourceWidget.h',
4 4 'include/DataSource/DataSourceTreeWidget.h',
5 5 'include/Settings/SqpSettingsDialog.h',
6 6 'include/Settings/SqpSettingsGeneralWidget.h',
7 7 'include/SidePane/SqpSidePane.h',
8 8 'include/SqpApplication.h',
9 'include/DragDropHelper.h',
9 'include/DragAndDrop/DragDropHelper.h',
10 10 'include/TimeWidget/TimeWidget.h',
11 11 'include/Variable/VariableInspectorWidget.h',
12 12 'include/Variable/VariableInspectorTableView.h',
13 13 'include/Variable/RenameVariableDialog.h',
14 14 'include/Visualization/qcustomplot.h',
15 15 'include/Visualization/VisualizationGraphWidget.h',
16 16 'include/Visualization/VisualizationTabWidget.h',
17 17 'include/Visualization/VisualizationWidget.h',
18 18 'include/Visualization/VisualizationZoneWidget.h',
19 19 'include/Visualization/VisualizationDragDropContainer.h',
20 20 'include/Visualization/VisualizationDragWidget.h'
21 21 ]
22 22
23 23 gui_ui_files = [
24 24 'ui/DataSource/DataSourceWidget.ui',
25 25 'ui/Settings/SqpSettingsDialog.ui',
26 26 'ui/Settings/SqpSettingsGeneralWidget.ui',
27 27 'ui/SidePane/SqpSidePane.ui',
28 28 'ui/TimeWidget/TimeWidget.ui',
29 29 'ui/Variable/VariableInspectorWidget.ui',
30 30 'ui/Variable/RenameVariableDialog.ui',
31 31 'ui/Variable/VariableMenuHeaderWidget.ui',
32 32 'ui/Visualization/VisualizationGraphWidget.ui',
33 33 'ui/Visualization/VisualizationTabWidget.ui',
34 34 'ui/Visualization/VisualizationWidget.ui',
35 35 'ui/Visualization/VisualizationZoneWidget.ui'
36 36 ]
37 37
38 38 gui_qresources = ['resources/sqpguiresources.qrc']
39 39
40 40 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
41 41 ui_files : gui_ui_files,
42 42 qresources : gui_qresources)
43 43
44 44 gui_sources = [
45 45 'src/SqpApplication.cpp',
46 'src/DragDropHelper.cpp',
46 'src/DragAndDrop/DragDropHelper.cpp',
47 47 'src/Common/ColorUtils.cpp',
48 48 'src/Common/VisualizationDef.cpp',
49 49 'src/DataSource/DataSourceTreeWidgetItem.cpp',
50 50 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
51 51 'src/DataSource/DataSourceWidget.cpp',
52 52 'src/DataSource/DataSourceTreeWidget.cpp',
53 53 'src/Settings/SqpSettingsDialog.cpp',
54 54 'src/Settings/SqpSettingsGeneralWidget.cpp',
55 55 'src/SidePane/SqpSidePane.cpp',
56 56 'src/TimeWidget/TimeWidget.cpp',
57 57 'src/Variable/VariableInspectorWidget.cpp',
58 58 'src/Variable/VariableInspectorTableView.cpp',
59 59 'src/Variable/VariableMenuHeaderWidget.cpp',
60 60 'src/Variable/RenameVariableDialog.cpp',
61 61 'src/Visualization/VisualizationGraphHelper.cpp',
62 62 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
63 63 'src/Visualization/VisualizationGraphWidget.cpp',
64 64 'src/Visualization/VisualizationTabWidget.cpp',
65 65 'src/Visualization/VisualizationWidget.cpp',
66 66 'src/Visualization/VisualizationZoneWidget.cpp',
67 67 'src/Visualization/qcustomplot.cpp',
68 68 'src/Visualization/QCustomPlotSynchronizer.cpp',
69 69 'src/Visualization/operations/FindVariableOperation.cpp',
70 70 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
71 71 'src/Visualization/operations/MenuBuilder.cpp',
72 72 'src/Visualization/operations/RemoveVariableOperation.cpp',
73 73 'src/Visualization/operations/RescaleAxeOperation.cpp',
74 74 'src/Visualization/VisualizationDragDropContainer.cpp',
75 75 'src/Visualization/VisualizationDragWidget.cpp'
76 76 ]
77 77
78 78 gui_inc = include_directories(['include'])
79 79
80 80 sciqlop_gui_lib = library('sciqlopgui',
81 81 gui_sources,
82 82 gui_moc_files,
83 83 include_directories : [gui_inc],
84 84 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
85 85 install : true
86 86 )
87 87
88 88 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
89 89 include_directories : gui_inc,
90 90 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
91 91
@@ -1,45 +1,45
1 1 #include "DataSource/DataSourceTreeWidget.h"
2 2 #include "Common/MimeTypesDef.h"
3 3 #include "DataSource/DataSourceController.h"
4 4 #include "DataSource/DataSourceItem.h"
5 5 #include "DataSource/DataSourceTreeWidgetItem.h"
6 6
7 #include "DragDropHelper.h"
7 #include "DragAndDrop/DragDropHelper.h"
8 8 #include "SqpApplication.h"
9 9
10 10 #include <QMimeData>
11 11
12 12 DataSourceTreeWidget::DataSourceTreeWidget(QWidget *parent) : QTreeWidget(parent) {}
13 13
14 14 QMimeData *DataSourceTreeWidget::mimeData(const QList<QTreeWidgetItem *> items) const
15 15 {
16 16 auto mimeData = new QMimeData;
17 17
18 18 // Basic check to ensure the item are correctly typed
19 19 Q_ASSERT(items.isEmpty() || dynamic_cast<DataSourceTreeWidgetItem *>(items.first()) != nullptr);
20 20
21 21 QVariantList productData;
22 22
23 23 for (auto item : items) {
24 24 auto dataSourceTreeItem = static_cast<DataSourceTreeWidgetItem *>(item);
25 25 auto dataSource = dataSourceTreeItem->data();
26 26
27 27 if (dataSource->type() == DataSourceItemType::COMPONENT
28 28 || dataSource->type() == DataSourceItemType::PRODUCT) {
29 29 auto metaData = dataSource->data();
30 30 productData << metaData;
31 31 }
32 32 }
33 33
34 34 auto encodedData = sqpApp->dataSourceController().mimeDataForProductsData(productData);
35 35 mimeData->setData(MIME_TYPE_PRODUCT_LIST, encodedData);
36 36
37 37 return mimeData;
38 38 }
39 39
40 40 void DataSourceTreeWidget::startDrag(Qt::DropActions supportedActions)
41 41 {
42 42 // Resets the drag&drop operations before it's starting
43 43 sqpApp->dragDropHelper().resetDragAndDrop();
44 44 QTreeWidget::startDrag(supportedActions);
45 45 }
@@ -1,383 +1,381
1 #include "DragDropHelper.h"
1 #include "DragAndDrop/DragDropHelper.h"
2 2 #include "SqpApplication.h"
3 3 #include "Visualization/VisualizationDragDropContainer.h"
4 4 #include "Visualization/VisualizationDragWidget.h"
5 5 #include "Visualization/VisualizationWidget.h"
6 6 #include "Visualization/operations/FindVariableOperation.h"
7 7
8 8 #include "Variable/Variable.h"
9 9 #include "Variable/VariableController.h"
10 10
11 11 #include "Common/MimeTypesDef.h"
12 12 #include "Common/VisualizationDef.h"
13 13
14 14 #include <QDir>
15 15 #include <QDragEnterEvent>
16 16 #include <QDragMoveEvent>
17 17 #include <QLabel>
18 18 #include <QScrollArea>
19 19 #include <QScrollBar>
20 20 #include <QTimer>
21 21 #include <QVBoxLayout>
22 22
23 23 const int SCROLL_SPEED = 5;
24 24 const int SCROLL_ZONE_SIZE = 50;
25 25
26 26 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
27 27
28 28 struct DragDropScroller::DragDropScrollerPrivate {
29 29
30 30 QList<QScrollArea *> m_ScrollAreas;
31 31 QScrollArea *m_CurrentScrollArea = nullptr;
32 32 std::unique_ptr<QTimer> m_Timer = nullptr;
33 33
34 34 enum class ScrollDirection { up, down, unknown };
35 35 ScrollDirection m_Direction = ScrollDirection::unknown;
36 36
37 37 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
38 38 {
39 39 m_Timer->setInterval(0);
40 40 }
41 41 };
42 42
43 43 DragDropScroller::DragDropScroller(QObject *parent)
44 44 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
45 45 {
46 46 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
47 47 }
48 48
49 49 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
50 50 {
51 51 impl->m_ScrollAreas << scrollArea;
52 52 scrollArea->viewport()->setAcceptDrops(true);
53 53 }
54 54
55 55 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
56 56 {
57 57 impl->m_ScrollAreas.removeAll(scrollArea);
58 58 scrollArea->viewport()->setAcceptDrops(false);
59 59 }
60 60
61 61 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
62 62 {
63 63 if (event->type() == QEvent::DragMove) {
64 64 auto w = static_cast<QWidget *>(obj);
65 65
66 66 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
67 67 auto moveEvent = static_cast<QDragMoveEvent *>(event);
68 68
69 69 auto pos = moveEvent->pos();
70 70 if (impl->m_CurrentScrollArea->viewport() != w) {
71 71 auto globalPos = w->mapToGlobal(moveEvent->pos());
72 72 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
73 73 }
74 74
75 75 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
76 76 - SCROLL_ZONE_SIZE;
77 77 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
78 78
79 79 if (!isInTopZone && !isInBottomZone) {
80 80 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
81 81 impl->m_Timer->stop();
82 82 }
83 83 else if (!impl->m_Timer->isActive()) {
84 84 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
85 85 : DragDropScrollerPrivate::ScrollDirection::down;
86 86 impl->m_Timer->start();
87 87 }
88 88 }
89 89 }
90 90 else if (event->type() == QEvent::DragEnter) {
91 91 auto w = static_cast<QWidget *>(obj);
92 92
93 93 for (auto scrollArea : impl->m_ScrollAreas) {
94 94 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
95 95 auto enterEvent = static_cast<QDragEnterEvent *>(event);
96 96 enterEvent->acceptProposedAction();
97 97 enterEvent->setDropAction(Qt::IgnoreAction);
98 98 impl->m_CurrentScrollArea = scrollArea;
99 99 break;
100 100 }
101 101 }
102 102 }
103 103 else if (event->type() == QEvent::DragLeave) {
104 104 if (impl->m_CurrentScrollArea) {
105 105 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
106 106 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
107 107 impl->m_CurrentScrollArea = nullptr;
108 108 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
109 109 impl->m_Timer->stop();
110 110 }
111 111 }
112 112 }
113 113 else if (event->type() == QEvent::Drop) {
114 114 if (impl->m_CurrentScrollArea) {
115 115 impl->m_CurrentScrollArea = nullptr;
116 116 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
117 117 impl->m_Timer->stop();
118 118 }
119 119 }
120 120
121 121 return false;
122 122 }
123 123
124 124 void DragDropScroller::onTimer()
125 125 {
126 126 if (impl->m_CurrentScrollArea) {
127 127 auto mvt = 0;
128 128 switch (impl->m_Direction) {
129 129 case DragDropScrollerPrivate::ScrollDirection::up:
130 130 mvt = SCROLL_SPEED;
131 131 break;
132 132 case DragDropScrollerPrivate::ScrollDirection::down:
133 133 mvt = -SCROLL_SPEED;
134 134 break;
135 135 default:
136 136 break;
137 137 }
138 138
139 139 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
140 140 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
141 141 }
142 142 }
143 143
144 144 struct DragDropHelper::DragDropHelperPrivate {
145 145
146 146 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
147 147 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
148 148 QLabel *m_PlaceHolderLabel;
149 149 QWidget *m_PlaceBackground;
150 150 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
151 151 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
152 152 // QTemporaryFile to have a name which is not generated.
153 153
154 154 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
155 155
156 156 QMetaObject::Connection m_DragWidgetDestroyedConnection;
157 157 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
158 158
159 159 explicit DragDropHelperPrivate()
160 160 : m_PlaceHolder{std::make_unique<QWidget>()},
161 161 m_DragDropScroller{std::make_unique<DragDropScroller>()}
162 162 {
163 163
164 164 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
165 165 layout->setSpacing(0);
166 166 layout->setContentsMargins(0, 0, 0, 0);
167 167
168 168 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
169 169 m_PlaceHolderLabel->setMinimumHeight(25);
170 170 layout->addWidget(m_PlaceHolderLabel);
171 171
172 172 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
173 173 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
174 174 layout->addWidget(m_PlaceBackground);
175 175
176 176 sqpApp->installEventFilter(m_DragDropScroller.get());
177 177
178 178 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
179 179 }
180 180
181 181 void preparePlaceHolder(DragDropHelper::PlaceHolderType type, const QString &topLabelText) const
182 182 {
183 183 if (m_CurrentDragWidget) {
184 184 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
185 185 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
186 186 }
187 187 else {
188 188 // Configuration of the placeHolder when there is no dragWidget
189 189 // (for instance with a drag from a variable)
190 190
191 191 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
192 192 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
193 193 }
194 194
195 195 switch (type) {
196 196 case DragDropHelper::PlaceHolderType::Graph:
197 197 m_PlaceBackground->setStyleSheet(
198 198 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
199 199 break;
200 200 case DragDropHelper::PlaceHolderType::Zone:
201 201 case DragDropHelper::PlaceHolderType::Default:
202 202 m_PlaceBackground->setStyleSheet(
203 203 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
204 204 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
205 205 break;
206 206 }
207 207
208 208 m_PlaceHolderLabel->setText(topLabelText);
209 209 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
210 210 }
211 211 };
212 212
213 213
214 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
215 {
216 }
214 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()} {}
217 215
218 216 DragDropHelper::~DragDropHelper()
219 217 {
220 218 QFile::remove(impl->m_ImageTempUrl);
221 219 }
222 220
223 221 void DragDropHelper::resetDragAndDrop()
224 222 {
225 223 setCurrentDragWidget(nullptr);
226 224 impl->m_HighlightedDragWidget = nullptr;
227 225 }
228 226
229 227 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
230 228 {
231 229 if (impl->m_CurrentDragWidget) {
232 230
233 231 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
234 232 }
235 233
236 234 if (dragWidget) {
237 235 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
238 236 impl->m_DragWidgetDestroyedConnection
239 237 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
240 238 [this]() { impl->m_CurrentDragWidget = nullptr; });
241 239 }
242 240
243 241 impl->m_CurrentDragWidget = dragWidget;
244 242 }
245 243
246 244 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
247 245 {
248 246 return impl->m_CurrentDragWidget;
249 247 }
250 248
251 249 QWidget &DragDropHelper::placeHolder() const
252 250 {
253 251 return *impl->m_PlaceHolder;
254 252 }
255 253
256 254 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
257 255 const QString &topLabelText)
258 256 {
259 257 removePlaceHolder();
260 258 impl->preparePlaceHolder(type, topLabelText);
261 259 layout->insertWidget(index, impl->m_PlaceHolder.get());
262 260 impl->m_PlaceHolder->show();
263 261 }
264 262
265 263 void DragDropHelper::removePlaceHolder()
266 264 {
267 265 auto parentWidget = impl->m_PlaceHolder->parentWidget();
268 266 if (parentWidget) {
269 267 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
270 268 impl->m_PlaceHolder->setParent(nullptr);
271 269 impl->m_PlaceHolder->hide();
272 270 }
273 271 }
274 272
275 273 bool DragDropHelper::isPlaceHolderSet() const
276 274 {
277 275 return impl->m_PlaceHolder->parentWidget();
278 276 }
279 277
280 278 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
281 279 {
282 280 impl->m_DragDropScroller->addScrollArea(scrollArea);
283 281 }
284 282
285 283 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
286 284 {
287 285 impl->m_DragDropScroller->removeScrollArea(scrollArea);
288 286 }
289 287
290 288 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
291 289 {
292 290 image.save(impl->m_ImageTempUrl);
293 291 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
294 292 }
295 293
296 294 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
297 295 {
298 296 if (impl->m_HighlightedDragWidget) {
299 297 impl->m_HighlightedDragWidget->highlightForMerge(false);
300 298 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
301 299 }
302 300
303 301 if (dragWidget) {
304 302 dragWidget->highlightForMerge(true);
305 303
306 304 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
307 305 impl->m_DragWidgetDestroyedConnection
308 306 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
309 307 [this]() { impl->m_HighlightedDragWidget = nullptr; });
310 308 }
311 309
312 310 impl->m_HighlightedDragWidget = dragWidget;
313 311 }
314 312
315 313 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
316 314 {
317 315 return impl->m_HighlightedDragWidget;
318 316 }
319 317
320 318 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
321 319 VisualizationDragDropContainer *dropContainer)
322 320 {
323 321 if (!mimeData || !dropContainer) {
324 322 qCWarning(LOG_DragDropHelper()) << QObject::tr(
325 323 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
326 324 Q_ASSERT(false);
327 325 return false;
328 326 }
329 327
330 328 auto result = false;
331 329
332 330 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
333 331 auto variables = sqpApp->variableController().variablesForMimeData(
334 332 mimeData->data(MIME_TYPE_VARIABLE_LIST));
335 333
336 334 if (variables.count() == 1) {
337 335
338 336 auto variable = variables.first();
339 337 if (variable->dataSeries() != nullptr) {
340 338
341 339 // Check that the variable is not already in a graph
342 340
343 341 auto parent = dropContainer->parentWidget();
344 342 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
345 343 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
346 344 }
347 345
348 346 if (parent) {
349 347 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
350 348
351 349 FindVariableOperation findVariableOperation{variable};
352 350 visualizationWidget->accept(&findVariableOperation);
353 351 auto variableContainers = findVariableOperation.result();
354 352 if (variableContainers.empty()) {
355 353 result = true;
356 354 }
357 355 else {
358 356 // result = false: the variable already exist in the visualisation
359 357 }
360 358 }
361 359 else {
362 360 qCWarning(LOG_DragDropHelper()) << QObject::tr(
363 361 "DragDropHelper::checkMimeDataForVisualization, the parent "
364 362 "VisualizationWidget cannot be found. Cannot check if the variable is "
365 363 "already used or not.");
366 364 }
367 365 }
368 366 else {
369 367 // result = false: the variable is not fully loaded
370 368 }
371 369 }
372 370 else {
373 371 // result = false: cannot drop multiple variables in the visualisation
374 372 }
375 373 }
376 374 else {
377 375 // Other MIME data
378 376 // no special rules, accepted by default
379 377 result = true;
380 378 }
381 379
382 380 return result;
383 381 }
@@ -1,163 +1,163
1 1 #include "SqpApplication.h"
2 2
3 3 #include <Data/IDataProvider.h>
4 4 #include <DataSource/DataSourceController.h>
5 #include <DragDropHelper.h>
5 #include <DragAndDrop/DragDropHelper.h>
6 6 #include <Network/NetworkController.h>
7 7 #include <QThread>
8 8 #include <Time/TimeController.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11 #include <Variable/VariableModel.h>
12 12 #include <Visualization/VisualizationController.h>
13 13
14 14 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
15 15
16 16 class SqpApplication::SqpApplicationPrivate {
17 17 public:
18 18 SqpApplicationPrivate()
19 19 : m_DataSourceController{std::make_unique<DataSourceController>()},
20 20 m_NetworkController{std::make_unique<NetworkController>()},
21 21 m_TimeController{std::make_unique<TimeController>()},
22 22 m_VariableController{std::make_unique<VariableController>()},
23 23 m_VisualizationController{std::make_unique<VisualizationController>()},
24 24 m_DragDropHelper{std::make_unique<DragDropHelper>()}
25 25 {
26 26 // /////////////////////////////// //
27 27 // Connections between controllers //
28 28 // /////////////////////////////// //
29 29
30 30 // VariableController <-> DataSourceController
31 31 connect(m_DataSourceController.get(),
32 32 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
33 33 std::shared_ptr<IDataProvider>)),
34 34 m_VariableController.get(),
35 35 SLOT(createVariable(const QString &, const QVariantHash &,
36 36 std::shared_ptr<IDataProvider>)));
37 37
38 38 connect(m_VariableController->variableModel(), &VariableModel::requestVariable,
39 39 m_DataSourceController.get(), &DataSourceController::requestVariable);
40 40
41 41 // VariableController <-> VisualizationController
42 42 connect(m_VariableController.get(),
43 43 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
44 44 m_VisualizationController.get(),
45 45 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
46 46
47 47 connect(m_VariableController.get(),
48 48 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)),
49 49 m_VisualizationController.get(),
50 50 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
51 51
52 52
53 53 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
54 54 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
55 55 m_NetworkController->moveToThread(&m_NetworkControllerThread);
56 56 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
57 57 m_VariableController->moveToThread(&m_VariableControllerThread);
58 58 m_VariableControllerThread.setObjectName("VariableControllerThread");
59 59 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
60 60 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
61 61
62 62
63 63 // Additionnal init
64 64 m_VariableController->setTimeController(m_TimeController.get());
65 65 }
66 66
67 67 virtual ~SqpApplicationPrivate()
68 68 {
69 69 m_DataSourceControllerThread.quit();
70 70 m_DataSourceControllerThread.wait();
71 71
72 72 m_NetworkControllerThread.quit();
73 73 m_NetworkControllerThread.wait();
74 74
75 75 m_VariableControllerThread.quit();
76 76 m_VariableControllerThread.wait();
77 77
78 78 m_VisualizationControllerThread.quit();
79 79 m_VisualizationControllerThread.wait();
80 80 }
81 81
82 82 std::unique_ptr<DataSourceController> m_DataSourceController;
83 83 std::unique_ptr<VariableController> m_VariableController;
84 84 std::unique_ptr<TimeController> m_TimeController;
85 85 std::unique_ptr<NetworkController> m_NetworkController;
86 86 std::unique_ptr<VisualizationController> m_VisualizationController;
87 87 QThread m_DataSourceControllerThread;
88 88 QThread m_NetworkControllerThread;
89 89 QThread m_VariableControllerThread;
90 90 QThread m_VisualizationControllerThread;
91 91
92 92 std::unique_ptr<DragDropHelper> m_DragDropHelper;
93 93 };
94 94
95 95
96 96 SqpApplication::SqpApplication(int &argc, char **argv)
97 97 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
98 98 {
99 99 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
100 100
101 101 connect(&impl->m_DataSourceControllerThread, &QThread::started,
102 102 impl->m_DataSourceController.get(), &DataSourceController::initialize);
103 103 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
104 104 impl->m_DataSourceController.get(), &DataSourceController::finalize);
105 105
106 106 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
107 107 &NetworkController::initialize);
108 108 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
109 109 &NetworkController::finalize);
110 110
111 111 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
112 112 &VariableController::initialize);
113 113 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
114 114 &VariableController::finalize);
115 115
116 116 connect(&impl->m_VisualizationControllerThread, &QThread::started,
117 117 impl->m_VisualizationController.get(), &VisualizationController::initialize);
118 118 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
119 119 impl->m_VisualizationController.get(), &VisualizationController::finalize);
120 120
121 121 impl->m_DataSourceControllerThread.start();
122 122 impl->m_NetworkControllerThread.start();
123 123 impl->m_VariableControllerThread.start();
124 124 impl->m_VisualizationControllerThread.start();
125 125 }
126 126
127 127 SqpApplication::~SqpApplication()
128 128 {
129 129 }
130 130
131 131 void SqpApplication::initialize()
132 132 {
133 133 }
134 134
135 135 DataSourceController &SqpApplication::dataSourceController() noexcept
136 136 {
137 137 return *impl->m_DataSourceController;
138 138 }
139 139
140 140 NetworkController &SqpApplication::networkController() noexcept
141 141 {
142 142 return *impl->m_NetworkController;
143 143 }
144 144
145 145 TimeController &SqpApplication::timeController() noexcept
146 146 {
147 147 return *impl->m_TimeController;
148 148 }
149 149
150 150 VariableController &SqpApplication::variableController() noexcept
151 151 {
152 152 return *impl->m_VariableController;
153 153 }
154 154
155 155 VisualizationController &SqpApplication::visualizationController() noexcept
156 156 {
157 157 return *impl->m_VisualizationController;
158 158 }
159 159
160 160 DragDropHelper &SqpApplication::dragDropHelper() noexcept
161 161 {
162 162 return *impl->m_DragDropHelper;
163 163 }
@@ -1,156 +1,156
1 1 #include "TimeWidget/TimeWidget.h"
2 2 #include "ui_TimeWidget.h"
3 3
4 4 #include <Common/DateUtils.h>
5 5 #include <Common/MimeTypesDef.h>
6 6
7 #include <DragDropHelper.h>
7 #include <DragAndDrop/DragDropHelper.h>
8 8 #include <SqpApplication.h>
9 9 #include <Time/TimeController.h>
10 10
11 11 #include <QDrag>
12 12 #include <QDragEnterEvent>
13 13 #include <QDropEvent>
14 14 #include <QMimeData>
15 15
16 16
17 17 struct TimeWidget::TimeWidgetPrivate {
18 18
19 19 explicit TimeWidgetPrivate() {}
20 20
21 21 QPoint m_DragStartPosition;
22 22 };
23 23
24 24 TimeWidget::TimeWidget(QWidget *parent)
25 25 : QWidget{parent},
26 26 ui{new Ui::TimeWidget},
27 27 impl{spimpl::make_unique_impl<TimeWidgetPrivate>()}
28 28 {
29 29 ui->setupUi(this);
30 30
31 31 ui->applyToolButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_DialogApplyButton));
32 32
33 33 // Connection
34 34 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
35 35 &TimeWidget::onTimeUpdateRequested);
36 36
37 37 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
38 38 &TimeWidget::onTimeUpdateRequested);
39 39
40 40
41 41 connect(ui->applyToolButton, &QToolButton::clicked, &sqpApp->timeController(),
42 42 &TimeController::onTimeNotify);
43 43
44 44 // Initialisation
45 45 auto endDateTime = QDateTime::currentDateTimeUtc();
46 46 auto startDateTime = endDateTime.addSecs(-3600); // one hour before
47 47
48 48 ui->startDateTimeEdit->setDateTime(startDateTime);
49 49 ui->endDateTimeEdit->setDateTime(endDateTime);
50 50
51 51 auto dateTime = SqpRange{DateUtils::secondsSinceEpoch(startDateTime),
52 52 DateUtils::secondsSinceEpoch(endDateTime)};
53 53
54 54 sqpApp->timeController().onTimeToUpdate(dateTime);
55 55 }
56 56
57 57
58 58 TimeWidget::~TimeWidget()
59 59 {
60 60 delete ui;
61 61 }
62 62
63 63 void TimeWidget::setTimeRange(SqpRange time)
64 64 {
65 65 auto startDateTime = DateUtils::dateTime(time.m_TStart);
66 66 auto endDateTime = DateUtils::dateTime(time.m_TEnd);
67 67
68 68 ui->startDateTimeEdit->setDateTime(startDateTime);
69 69 ui->endDateTimeEdit->setDateTime(endDateTime);
70 70 }
71 71
72 72 SqpRange TimeWidget::timeRange() const
73 73 {
74 74 return SqpRange{DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
75 75 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime())};
76 76 }
77 77
78 78 void TimeWidget::onTimeUpdateRequested()
79 79 {
80 80 auto dateTime = timeRange();
81 81 emit timeUpdated(std::move(dateTime));
82 82 }
83 83
84 84 void TimeWidget::dragEnterEvent(QDragEnterEvent *event)
85 85 {
86 86 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
87 87 event->acceptProposedAction();
88 88 setStyleSheet("QDateTimeEdit{background-color: #BBD5EE; border:2px solid #2A7FD4}");
89 89 }
90 90 else {
91 91 event->ignore();
92 92 }
93 93 }
94 94
95 95 void TimeWidget::dragLeaveEvent(QDragLeaveEvent *event)
96 96 {
97 97 setStyleSheet(QString());
98 98 }
99 99
100 100 void TimeWidget::dropEvent(QDropEvent *event)
101 101 {
102 102 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
103 103 auto mimeData = event->mimeData()->data(MIME_TYPE_TIME_RANGE);
104 104 auto timeRange = TimeController::timeRangeForMimeData(mimeData);
105 105
106 106 setTimeRange(timeRange);
107 107 }
108 108 else {
109 109 event->ignore();
110 110 }
111 111
112 112 setStyleSheet(QString());
113 113 }
114 114
115 115
116 116 void TimeWidget::mousePressEvent(QMouseEvent *event)
117 117 {
118 118 if (event->button() == Qt::LeftButton) {
119 119 impl->m_DragStartPosition = event->pos();
120 120 }
121 121
122 122 QWidget::mousePressEvent(event);
123 123 }
124 124
125 125 void TimeWidget::mouseMoveEvent(QMouseEvent *event)
126 126 {
127 127 if (!(event->buttons() & Qt::LeftButton)) {
128 128 return;
129 129 }
130 130
131 131 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
132 132 < QApplication::startDragDistance()) {
133 133 return;
134 134 }
135 135
136 136 // Note: The management of the drag object is done by Qt
137 137 auto drag = new QDrag{this};
138 138
139 139 auto mimeData = new QMimeData;
140 140 auto timeData = TimeController::mimeDataForTimeRange(timeRange());
141 141 mimeData->setData(MIME_TYPE_TIME_RANGE, timeData);
142 142
143 143 drag->setMimeData(mimeData);
144 144
145 145 auto pixmap = QPixmap(size());
146 146 render(&pixmap);
147 147 drag->setPixmap(pixmap);
148 148 drag->setHotSpot(impl->m_DragStartPosition);
149 149
150 150 sqpApp->dragDropHelper().resetDragAndDrop();
151 151
152 152 // Note: The exec() is blocking on windows but not on linux and macOS
153 153 drag->exec(Qt::MoveAction | Qt::CopyAction);
154 154
155 155 QWidget::mouseMoveEvent(event);
156 156 }
@@ -1,13 +1,13
1 1 #include "Variable/VariableInspectorTableView.h"
2 2
3 #include "DragDropHelper.h"
3 #include "DragAndDrop/DragDropHelper.h"
4 4 #include "SqpApplication.h"
5 5
6 6 VariableInspectorTableView::VariableInspectorTableView(QWidget *parent) : QTableView(parent) {}
7 7
8 8 void VariableInspectorTableView::startDrag(Qt::DropActions supportedActions)
9 9 {
10 10 // Resets the drag&drop operations before it's starting
11 11 sqpApp->dragDropHelper().resetDragAndDrop();
12 12 QTableView::startDrag(supportedActions);
13 13 }
@@ -1,240 +1,240
1 1 #include <Variable/RenameVariableDialog.h>
2 2 #include <Variable/Variable.h>
3 3 #include <Variable/VariableController.h>
4 4 #include <Variable/VariableInspectorWidget.h>
5 5 #include <Variable/VariableMenuHeaderWidget.h>
6 6 #include <Variable/VariableModel.h>
7 7
8 8 #include <ui_VariableInspectorWidget.h>
9 9
10 10 #include <QMouseEvent>
11 11 #include <QSortFilterProxyModel>
12 12 #include <QStyledItemDelegate>
13 13 #include <QWidgetAction>
14 14
15 #include <DragDropHelper.h>
15 #include <DragAndDrop/DragDropHelper.h>
16 16 #include <SqpApplication.h>
17 17
18 18 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
19 19
20 20
21 21 class QProgressBarItemDelegate : public QStyledItemDelegate {
22 22
23 23 public:
24 24 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
25 25
26 26 void paint(QPainter *painter, const QStyleOptionViewItem &option,
27 27 const QModelIndex &index) const
28 28 {
29 29 auto data = index.data(Qt::DisplayRole);
30 30 auto progressData = index.data(VariableRoles::ProgressRole);
31 31 if (data.isValid() && progressData.isValid()) {
32 32 auto name = data.value<QString>();
33 33 auto progress = progressData.value<double>();
34 34 if (progress > 0) {
35 35 auto cancelButtonWidth = 20;
36 36 auto progressBarOption = QStyleOptionProgressBar{};
37 37 auto progressRect = option.rect;
38 38 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
39 39 progressBarOption.rect = progressRect;
40 40 progressBarOption.minimum = 0;
41 41 progressBarOption.maximum = 100;
42 42 progressBarOption.progress = progress;
43 43 progressBarOption.text
44 44 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
45 45 progressBarOption.textVisible = true;
46 46 progressBarOption.textAlignment = Qt::AlignCenter;
47 47
48 48
49 49 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
50 50 painter);
51 51
52 52 // Cancel button
53 53 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
54 54 option.rect.height());
55 55 auto buttonOption = QStyleOptionButton{};
56 56 buttonOption.rect = buttonRect;
57 57 buttonOption.text = "X";
58 58
59 59 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
60 60 }
61 61 else {
62 62 QStyledItemDelegate::paint(painter, option, index);
63 63 }
64 64 }
65 65 else {
66 66 QStyledItemDelegate::paint(painter, option, index);
67 67 }
68 68 }
69 69
70 70 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
71 71 const QModelIndex &index)
72 72 {
73 73 if (event->type() == QEvent::MouseButtonRelease) {
74 74 auto data = index.data(Qt::DisplayRole);
75 75 auto progressData = index.data(VariableRoles::ProgressRole);
76 76 if (data.isValid() && progressData.isValid()) {
77 77 auto cancelButtonWidth = 20;
78 78 auto progressRect = option.rect;
79 79 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
80 80 // Cancel button
81 81 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
82 82 option.rect.height());
83 83
84 84 auto e = (QMouseEvent *)event;
85 85 auto clickX = e->x();
86 86 auto clickY = e->y();
87 87
88 88 auto x = buttonRect.left(); // the X coordinate
89 89 auto y = buttonRect.top(); // the Y coordinate
90 90 auto w = buttonRect.width(); // button width
91 91 auto h = buttonRect.height(); // button height
92 92
93 93 if (clickX > x && clickX < x + w) {
94 94 if (clickY > y && clickY < y + h) {
95 95 auto variableModel = sqpApp->variableController().variableModel();
96 96 variableModel->abortProgress(index);
97 97 }
98 98 return true;
99 99 }
100 100 else {
101 101 return QStyledItemDelegate::editorEvent(event, model, option, index);
102 102 }
103 103 }
104 104 else {
105 105 return QStyledItemDelegate::editorEvent(event, model, option, index);
106 106 }
107 107 }
108 108 else {
109 109 return QStyledItemDelegate::editorEvent(event, model, option, index);
110 110 }
111 111
112 112
113 113 return QStyledItemDelegate::editorEvent(event, model, option, index);
114 114 }
115 115 };
116 116
117 117 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
118 118 : QWidget{parent},
119 119 ui{new Ui::VariableInspectorWidget},
120 120 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
121 121 {
122 122 ui->setupUi(this);
123 123
124 124 // Sets model for table
125 125 // auto sortFilterModel = new QSortFilterProxyModel{this};
126 126 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
127 127
128 128 auto variableModel = sqpApp->variableController().variableModel();
129 129 ui->tableView->setModel(variableModel);
130 130
131 131 // Adds extra signal/slot between view and model, so the view can be updated instantly when
132 132 // there is a change of data in the model
133 133 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
134 134 SLOT(refresh()));
135 135
136 136 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
137 137 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
138 138
139 139 // Fixes column sizes
140 140 auto model = ui->tableView->model();
141 141 const auto count = model->columnCount();
142 142 for (auto i = 0; i < count; ++i) {
143 143 ui->tableView->setColumnWidth(
144 144 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
145 145 }
146 146
147 147 // Sets selection options
148 148 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
149 149 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
150 150
151 151 // Connection to show a menu when right clicking on the tree
152 152 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
153 153 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
154 154 &VariableInspectorWidget::onTableMenuRequested);
155 155 }
156 156
157 157 VariableInspectorWidget::~VariableInspectorWidget()
158 158 {
159 159 delete ui;
160 160 }
161 161
162 162 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
163 163 {
164 164 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
165 165
166 166 // Gets the model to retrieve the underlying selected variables
167 167 auto model = sqpApp->variableController().variableModel();
168 168 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
169 169 for (const auto &selectedRow : qAsConst(selectedRows)) {
170 170 if (auto selectedVariable = model->variable(selectedRow.row())) {
171 171 selectedVariables.push_back(selectedVariable);
172 172 }
173 173 }
174 174
175 175 QMenu tableMenu{};
176 176
177 177 // Emits a signal so that potential receivers can populate the menu before displaying it
178 178 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
179 179
180 180 // Adds menu-specific actions
181 181 if (!selectedVariables.isEmpty()) {
182 182 tableMenu.addSeparator();
183 183
184 184 // 'Rename' and 'Duplicate' actions (only if one variable selected)
185 185 if (selectedVariables.size() == 1) {
186 186 auto selectedVariable = selectedVariables.front();
187 187
188 188 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
189 189 {
190 190 if (auto var = varW.lock()) {
191 191 sqpApp->variableController().cloneVariable(var);
192 192 }
193 193 };
194 194
195 195 tableMenu.addAction(tr("Duplicate"), duplicateFun);
196 196
197 197 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), &model, this ]()
198 198 {
199 199 if (auto var = varW.lock()) {
200 200 // Generates forbidden names (names associated to existing variables)
201 201 auto allVariables = model->variables();
202 202 auto forbiddenNames = QVector<QString>(allVariables.size());
203 203 std::transform(allVariables.cbegin(), allVariables.cend(),
204 204 forbiddenNames.begin(),
205 205 [](const auto &variable) { return variable->name(); });
206 206
207 207 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
208 208 if (dialog.exec() == QDialog::Accepted) {
209 209 var->setName(dialog.name());
210 210 }
211 211 }
212 212 };
213 213
214 214 tableMenu.addAction(tr("Rename..."), renameFun);
215 215 }
216 216
217 217 // 'Delete' action
218 218 auto deleteFun = [&selectedVariables]() {
219 219 sqpApp->variableController().deleteVariables(selectedVariables);
220 220 };
221 221
222 222 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
223 223 }
224 224
225 225 if (!tableMenu.isEmpty()) {
226 226 // Generates menu header (inserted before first action)
227 227 auto firstAction = tableMenu.actions().first();
228 228 auto headerAction = new QWidgetAction{&tableMenu};
229 229 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
230 230 tableMenu.insertAction(firstAction, headerAction);
231 231
232 232 // Displays menu
233 233 tableMenu.exec(QCursor::pos());
234 234 }
235 235 }
236 236
237 237 void VariableInspectorWidget::refresh() noexcept
238 238 {
239 239 ui->tableView->viewport()->update();
240 240 }
@@ -1,453 +1,453
1 1 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "DragDropHelper.h"
2 #include "DragAndDrop/DragDropHelper.h"
3 3 #include "SqpApplication.h"
4 4 #include "Visualization/VisualizationDragWidget.h"
5 5
6 6 #include "Common/VisualizationDef.h"
7 7
8 8 #include <QDrag>
9 9 #include <QDragEnterEvent>
10 10 #include <QVBoxLayout>
11 11
12 12 #include <cmath>
13 13 #include <memory>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
16 16
17 17 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
18 18
19 19 QVBoxLayout *m_Layout;
20 20 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
21 21 QString m_PlaceHolderText;
22 22 DragDropHelper::PlaceHolderType m_PlaceHolderType = DragDropHelper::PlaceHolderType::Graph;
23 23
24 24 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
25 25 = [](auto mimeData) { return true; };
26 26
27 27 int m_MinContainerHeight = 0;
28 28
29 29 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
30 30 {
31 31 m_Layout = new QVBoxLayout(widget);
32 32 m_Layout->setContentsMargins(0, 0, 0, 0);
33 33 }
34 34
35 35 bool acceptMimeData(const QMimeData *data) const
36 36 {
37 37 for (const auto &type : m_AcceptedMimeTypes.keys()) {
38 38 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
39 39 return true;
40 40 }
41 41 }
42 42
43 43 return false;
44 44 }
45 45
46 46 bool allowMergeForMimeData(const QMimeData *data) const
47 47 {
48 48 bool result = false;
49 49 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
50 50 ++it) {
51 51
52 52 if (data->hasFormat(it.key())
53 53 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
54 54 || it.value()
55 55 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
56 56 result = true;
57 57 }
58 58 else if (data->hasFormat(it.key())
59 59 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
60 60 // Merge is forbidden if the mime data contain an acceptable type which cannot be
61 61 // merged
62 62 result = false;
63 63 break;
64 64 }
65 65 }
66 66
67 67 return result;
68 68 }
69 69
70 70 bool allowInsertForMimeData(const QMimeData *data) const
71 71 {
72 72 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
73 73 ++it) {
74 74 if (data->hasFormat(it.key())
75 75 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
76 76 || it.value()
77 77 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
78 78 return true;
79 79 }
80 80 }
81 81
82 82 return false;
83 83 }
84 84
85 85 bool hasPlaceHolder() const
86 86 {
87 87 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
88 88 }
89 89
90 90 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
91 91 {
92 92 VisualizationDragWidget *dragWidget = nullptr;
93 93
94 94 for (auto child : parent->children()) {
95 95 auto widget = qobject_cast<VisualizationDragWidget *>(child);
96 96 if (widget && widget->isVisible()) {
97 97 if (widget->frameGeometry().contains(pos)) {
98 98 dragWidget = widget;
99 99 break;
100 100 }
101 101 }
102 102 }
103 103
104 104 return dragWidget;
105 105 }
106 106
107 107 bool cursorIsInContainer(QWidget *container) const
108 108 {
109 109 return container->isAncestorOf(sqpApp->widgetAt(QCursor::pos()));
110 110 }
111 111
112 112 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
113 113 {
114 114 auto nbGraph = 0;
115 115 for (auto child : parent->children()) {
116 116 if (qobject_cast<VisualizationDragWidget *>(child)) {
117 117 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
118 118 nbGraph += 1;
119 119 }
120 120 }
121 121 }
122 122
123 123 return nbGraph;
124 124 }
125 125
126 126 void findPlaceHolderPosition(const QPoint &pos, bool canInsert, bool canMerge,
127 127 const VisualizationDragDropContainer *container);
128 128 };
129 129
130 130 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
131 131 : QFrame{parent},
132 132 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
133 133 {
134 134 setAcceptDrops(true);
135 135 }
136 136
137 137 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
138 138 {
139 139 impl->m_Layout->addWidget(dragWidget);
140 140 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
141 141 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
142 142 &VisualizationDragDropContainer::startDrag);
143 143 }
144 144
145 145 void VisualizationDragDropContainer::insertDragWidget(int index,
146 146 VisualizationDragWidget *dragWidget)
147 147 {
148 148 impl->m_Layout->insertWidget(index, dragWidget);
149 149 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
150 150 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
151 151 &VisualizationDragDropContainer::startDrag);
152 152 }
153 153
154 154 void VisualizationDragDropContainer::addAcceptedMimeType(
155 155 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
156 156 {
157 157 impl->m_AcceptedMimeTypes[mimeType] = behavior;
158 158 }
159 159
160 160 int VisualizationDragDropContainer::countDragWidget() const
161 161 {
162 162 return impl->countDragWidget(this);
163 163 }
164 164
165 165 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
166 166 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
167 167 {
168 168 impl->m_AcceptMimeDataFun = fun;
169 169 }
170 170
171 171 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
172 172 const QString &placeHolderText)
173 173 {
174 174 impl->m_PlaceHolderType = type;
175 175 impl->m_PlaceHolderText = placeHolderText;
176 176 }
177 177
178 178 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
179 179 const QPoint &dragPosition)
180 180 {
181 181 auto &helper = sqpApp->dragDropHelper();
182 182 helper.resetDragAndDrop();
183 183
184 184 // Note: The management of the drag object is done by Qt
185 185 auto drag = new QDrag{dragWidget};
186 186 drag->setHotSpot(dragPosition);
187 187
188 188 auto mimeData = dragWidget->mimeData();
189 189 drag->setMimeData(mimeData);
190 190
191 191 auto pixmap = QPixmap(dragWidget->size());
192 192 dragWidget->render(&pixmap);
193 193 drag->setPixmap(pixmap);
194 194
195 195 auto image = pixmap.toImage();
196 196 mimeData->setImageData(image);
197 197 mimeData->setUrls({helper.imageTemporaryUrl(image)});
198 198
199 199 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
200 200 helper.setCurrentDragWidget(dragWidget);
201 201
202 202 if (impl->cursorIsInContainer(this)) {
203 203 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
204 204 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
205 205 impl->m_PlaceHolderText);
206 206 dragWidget->setVisible(false);
207 207 }
208 208 else {
209 209 // The drag starts directly outside the drop zone
210 210 // do not add the placeHolder
211 211 }
212 212
213 213 // Note: The exec() is blocking on windows but not on linux and macOS
214 214 drag->exec(Qt::MoveAction | Qt::CopyAction);
215 215 }
216 216 else {
217 217 qCWarning(LOG_VisualizationDragDropContainer())
218 218 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
219 219 "VisualizationDragWidget is not found in this container.");
220 220 }
221 221 }
222 222
223 223 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
224 224 {
225 225 if (impl->acceptMimeData(event->mimeData())) {
226 226 event->acceptProposedAction();
227 227
228 228 auto &helper = sqpApp->dragDropHelper();
229 229
230 230 if (!impl->hasPlaceHolder()) {
231 231 auto dragWidget = helper.getCurrentDragWidget();
232 232
233 233 if (dragWidget) {
234 234 // If the drag&drop is internal to the visualization, entering the container hide
235 235 // the dragWidget which was made visible by the dragLeaveEvent
236 236 auto parentWidget
237 237 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
238 238 if (parentWidget) {
239 239 dragWidget->setVisible(false);
240 240 }
241 241 }
242 242
243 243 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
244 244 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
245 245 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
246 246 }
247 247 else {
248 248 // do nothing
249 249 }
250 250 }
251 251 else {
252 252 event->ignore();
253 253 }
254 254
255 255 QWidget::dragEnterEvent(event);
256 256 }
257 257
258 258 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
259 259 {
260 260 Q_UNUSED(event);
261 261
262 262 auto &helper = sqpApp->dragDropHelper();
263 263
264 264 if (!impl->cursorIsInContainer(this)) {
265 265 helper.removePlaceHolder();
266 266 helper.setHightlightedDragWidget(nullptr);
267 267 impl->m_MinContainerHeight = 0;
268 268
269 269 auto dragWidget = helper.getCurrentDragWidget();
270 270 if (dragWidget) {
271 271 // dragWidget has a value only if the drag is started from the visualization
272 272 // In that case, shows the drag widget at its original place
273 273 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
274 274 // drop zone (It is not possible to catch a drop event outside of the application)
275 275
276 276 if (dragWidget) {
277 277 dragWidget->setVisible(true);
278 278 }
279 279 }
280 280 }
281 281 else {
282 282 // Leave event probably received for a child widget.
283 283 // Do nothing.
284 284 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
285 285 }
286 286
287 287 QWidget::dragLeaveEvent(event);
288 288 }
289 289
290 290 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
291 291 {
292 292 if (impl->acceptMimeData(event->mimeData())) {
293 293 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
294 294 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
295 295 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
296 296 }
297 297 else {
298 298 event->ignore();
299 299 }
300 300
301 301 QWidget::dragMoveEvent(event);
302 302 }
303 303
304 304 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
305 305 {
306 306 auto &helper = sqpApp->dragDropHelper();
307 307
308 308 if (impl->acceptMimeData(event->mimeData())) {
309 309 auto dragWidget = helper.getCurrentDragWidget();
310 310 if (impl->hasPlaceHolder()) {
311 311 // drop where the placeHolder is located
312 312
313 313 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
314 314 if (canInsert) {
315 315 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
316 316
317 317 if (dragWidget) {
318 318 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
319 319 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
320 320 // Correction of the index if the drop occurs in the same container
321 321 // and if the drag is started from the visualization (in that case, the
322 322 // dragWidget is hidden)
323 323 droppedIndex -= 1;
324 324 }
325 325
326 326 dragWidget->setVisible(true);
327 327 }
328 328
329 329 event->acceptProposedAction();
330 330
331 331 helper.removePlaceHolder();
332 332
333 333 emit dropOccuredInContainer(droppedIndex, event->mimeData());
334 334 }
335 335 else {
336 336 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
337 337 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
338 338 "the insertion is forbidden.");
339 339 Q_ASSERT(false);
340 340 }
341 341 }
342 342 else if (helper.getHightlightedDragWidget()) {
343 343 // drop on the highlighted widget
344 344
345 345 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
346 346 if (canMerge) {
347 347 event->acceptProposedAction();
348 348 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
349 349 }
350 350 else {
351 351 qCWarning(LOG_VisualizationDragDropContainer())
352 352 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
353 353 "the merge is forbidden.");
354 354 Q_ASSERT(false);
355 355 }
356 356 }
357 357 }
358 358 else {
359 359 event->ignore();
360 360 }
361 361
362 362 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
363 363 impl->m_MinContainerHeight = 0;
364 364
365 365 QWidget::dropEvent(event);
366 366 }
367 367
368 368
369 369 void VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
370 370 const QPoint &pos, bool canInsert, bool canMerge,
371 371 const VisualizationDragDropContainer *container)
372 372 {
373 373 auto &helper = sqpApp->dragDropHelper();
374 374
375 375 auto absPos = container->mapToGlobal(pos);
376 376 auto isOnPlaceHolder = sqpApp->widgetAt(absPos) == &(helper.placeHolder());
377 377
378 378 if (countDragWidget(container, true) == 0) {
379 379 // Drop on an empty container, just add the placeHolder at the top
380 380 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
381 381 }
382 382 else if (!isOnPlaceHolder) {
383 383 auto nbDragWidget = countDragWidget(container);
384 384 if (nbDragWidget > 0) {
385 385
386 386 if (m_MinContainerHeight == 0) {
387 387 m_MinContainerHeight = container->size().height();
388 388 }
389 389
390 390 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
391 391 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
392 392
393 393 auto posY = pos.y();
394 394 auto dropIndex = floor(posY / graphHeight);
395 395 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
396 396
397 397
398 398 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
399 399 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
400 400
401 401 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
402 402
403 403 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
404 404
405 405 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
406 406 if (isOnBottom) {
407 407 dropIndex += 1;
408 408 }
409 409
410 410 if (helper.getCurrentDragWidget()) {
411 411 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
412 412 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
413 413 // Correction of the index if the drop occurs in the same container
414 414 // and if the drag is started from the visualization (in that case, the
415 415 // dragWidget is hidden)
416 416 dropIndex += 1;
417 417 }
418 418 }
419 419
420 420 if (dropIndex != placeHolderIndex) {
421 421 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
422 422 m_PlaceHolderText);
423 423 }
424 424
425 425 helper.setHightlightedDragWidget(nullptr);
426 426 }
427 427 else if (canMerge && dragWidgetHovered) {
428 428 // drop on the middle -> merge
429 429 if (hasPlaceHolder()) {
430 430 helper.removePlaceHolder();
431 431 }
432 432
433 433 helper.setHightlightedDragWidget(dragWidgetHovered);
434 434 }
435 435 else {
436 436 qCWarning(LOG_VisualizationDragDropContainer())
437 437 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
438 438 "action.");
439 439 Q_ASSERT(false);
440 440 }
441 441 }
442 442 else {
443 443 qCWarning(LOG_VisualizationDragDropContainer())
444 444 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
445 445 "found in the "
446 446 "container");
447 447 }
448 448 }
449 449 else {
450 450 // the mouse is hover the placeHolder
451 451 // Do nothing
452 452 }
453 453 }
@@ -1,401 +1,401
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationDefs.h"
4 4 #include "Visualization/VisualizationGraphHelper.h"
5 5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7 #include "ui_VisualizationGraphWidget.h"
8 8
9 9 #include <Common/MimeTypesDef.h>
10 10 #include <Data/ArrayData.h>
11 11 #include <Data/IDataSeries.h>
12 #include <DragDropHelper.h>
12 #include <DragAndDrop/DragDropHelper.h>
13 13 #include <Settings/SqpSettingsDefs.h>
14 14 #include <SqpApplication.h>
15 15 #include <Time/TimeController.h>
16 16 #include <Variable/Variable.h>
17 17 #include <Variable/VariableController.h>
18 18
19 19 #include <unordered_map>
20 20
21 21 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
22 22
23 23 namespace {
24 24
25 25 /// Key pressed to enable zoom on horizontal axis
26 26 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
27 27
28 28 /// Key pressed to enable zoom on vertical axis
29 29 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
30 30
31 31 } // namespace
32 32
33 33 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
34 34
35 35 explicit VisualizationGraphWidgetPrivate(const QString &name)
36 36 : m_Name{name},
37 37 m_DoAcquisition{true},
38 38 m_IsCalibration{false},
39 39 m_RenderingDelegate{nullptr}
40 40 {
41 41 }
42 42
43 43 QString m_Name;
44 44 // 1 variable -> n qcpplot
45 45 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
46 46 bool m_DoAcquisition;
47 47 bool m_IsCalibration;
48 48 QCPItemTracer *m_TextTracer;
49 49 /// Delegate used to attach rendering features to the plot
50 50 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
51 51 };
52 52
53 53 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
54 54 : VisualizationDragWidget{parent},
55 55 ui{new Ui::VisualizationGraphWidget},
56 56 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
57 57 {
58 58 ui->setupUi(this);
59 59
60 60 // 'Close' options : widget is deleted when closed
61 61 setAttribute(Qt::WA_DeleteOnClose);
62 62
63 63 // Set qcpplot properties :
64 64 // - Drag (on x-axis) and zoom are enabled
65 65 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
66 66 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
67 67 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
68 68
69 69 // The delegate must be initialized after the ui as it uses the plot
70 70 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
71 71
72 72 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
73 73 connect(ui->widget, &QCustomPlot::mouseRelease, this,
74 74 &VisualizationGraphWidget::onMouseRelease);
75 75 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
76 76 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
77 77 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
78 78 &QCPAxis::rangeChanged),
79 79 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
80 80
81 81 // Activates menu when right clicking on the graph
82 82 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
83 83 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
84 84 &VisualizationGraphWidget::onGraphMenuRequested);
85 85
86 86 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
87 87 &VariableController::onRequestDataLoading);
88 88
89 89 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
90 90 &VisualizationGraphWidget::onUpdateVarDisplaying);
91 91 }
92 92
93 93
94 94 VisualizationGraphWidget::~VisualizationGraphWidget()
95 95 {
96 96 delete ui;
97 97 }
98 98
99 99 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
100 100 {
101 101 auto parent = parentWidget();
102 102 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
103 103 parent = parent->parentWidget();
104 104 }
105 105
106 106 return qobject_cast<VisualizationZoneWidget *>(parent);
107 107 }
108 108
109 109 void VisualizationGraphWidget::enableAcquisition(bool enable)
110 110 {
111 111 impl->m_DoAcquisition = enable;
112 112 }
113 113
114 114 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
115 115 {
116 116 // Uses delegate to create the qcpplot components according to the variable
117 117 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
118 118 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
119 119
120 120 // Set axes properties according to the units of the data series
121 121 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
122 122 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
123 123 auto xAxisUnit = Unit{};
124 124 auto valuesUnit = Unit{};
125 125
126 126 if (auto dataSeries = variable->dataSeries()) {
127 127 dataSeries->lockRead();
128 128 xAxisUnit = dataSeries->xAxisUnit();
129 129 valuesUnit = dataSeries->valuesUnit();
130 130 dataSeries->unlock();
131 131 }
132 132 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
133 133
134 134 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
135 135
136 136 this->enableAcquisition(false);
137 137 this->setGraphRange(range);
138 138 this->enableAcquisition(true);
139 139
140 140 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
141 141
142 142 emit variableAdded(variable);
143 143 }
144 144
145 145 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
146 146 {
147 147 // Each component associated to the variable :
148 148 // - is removed from qcpplot (which deletes it)
149 149 // - is no longer referenced in the map
150 150 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
151 151 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
152 152 emit variableAboutToBeRemoved(variable);
153 153
154 154 auto &plottablesMap = variableIt->second;
155 155
156 156 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
157 157 plottableIt != plottableEnd;) {
158 158 ui->widget->removePlottable(plottableIt->second);
159 159 plottableIt = plottablesMap.erase(plottableIt);
160 160 }
161 161
162 162 impl->m_VariableToPlotMultiMap.erase(variableIt);
163 163 }
164 164
165 165 // Updates graph
166 166 ui->widget->replot();
167 167 }
168 168
169 169 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
170 170 {
171 171 auto variables = QList<std::shared_ptr<Variable> >{};
172 172 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
173 173 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
174 174 variables << it->first;
175 175 }
176 176
177 177 return variables;
178 178 }
179 179
180 180 void VisualizationGraphWidget::setYRange(const SqpRange &range)
181 181 {
182 182 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
183 183 }
184 184
185 185 SqpRange VisualizationGraphWidget::graphRange() const noexcept
186 186 {
187 187 auto graphRange = ui->widget->xAxis->range();
188 188 return SqpRange{graphRange.lower, graphRange.upper};
189 189 }
190 190
191 191 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
192 192 {
193 193 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
194 194 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
195 195 ui->widget->replot();
196 196 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
197 197 }
198 198
199 199 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
200 200 {
201 201 if (visitor) {
202 202 visitor->visit(this);
203 203 }
204 204 else {
205 205 qCCritical(LOG_VisualizationGraphWidget())
206 206 << tr("Can't visit widget : the visitor is null");
207 207 }
208 208 }
209 209
210 210 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
211 211 {
212 212 /// @todo : for the moment, a graph can always accomodate a variable
213 213 Q_UNUSED(variable);
214 214 return true;
215 215 }
216 216
217 217 bool VisualizationGraphWidget::contains(const Variable &variable) const
218 218 {
219 219 // Finds the variable among the keys of the map
220 220 auto variablePtr = &variable;
221 221 auto findVariable
222 222 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
223 223
224 224 auto end = impl->m_VariableToPlotMultiMap.cend();
225 225 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
226 226 return it != end;
227 227 }
228 228
229 229 QString VisualizationGraphWidget::name() const
230 230 {
231 231 return impl->m_Name;
232 232 }
233 233
234 234 QMimeData *VisualizationGraphWidget::mimeData() const
235 235 {
236 236 auto mimeData = new QMimeData;
237 237 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
238 238
239 239 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
240 240 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
241 241
242 242 return mimeData;
243 243 }
244 244
245 245 bool VisualizationGraphWidget::isDragAllowed() const
246 246 {
247 247 return true;
248 248 }
249 249
250 250 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
251 251 {
252 252 if (highlighted) {
253 253 plot().setBackground(QBrush(QColor("#BBD5EE")));
254 254 }
255 255 else {
256 256 plot().setBackground(QBrush(Qt::white));
257 257 }
258 258
259 259 plot().update();
260 260 }
261 261
262 262 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
263 263 {
264 264 Q_UNUSED(event);
265 265
266 266 // Prevents that all variables will be removed from graph when it will be closed
267 267 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
268 268 emit variableAboutToBeRemoved(variableEntry.first);
269 269 }
270 270 }
271 271
272 272 void VisualizationGraphWidget::enterEvent(QEvent *event)
273 273 {
274 274 Q_UNUSED(event);
275 275 impl->m_RenderingDelegate->showGraphOverlay(true);
276 276 }
277 277
278 278 void VisualizationGraphWidget::leaveEvent(QEvent *event)
279 279 {
280 280 Q_UNUSED(event);
281 281 impl->m_RenderingDelegate->showGraphOverlay(false);
282 282 }
283 283
284 284 QCustomPlot &VisualizationGraphWidget::plot() noexcept
285 285 {
286 286 return *ui->widget;
287 287 }
288 288
289 289 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
290 290 {
291 291 QMenu graphMenu{};
292 292
293 293 // Iterates on variables (unique keys)
294 294 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
295 295 end = impl->m_VariableToPlotMultiMap.cend();
296 296 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
297 297 // 'Remove variable' action
298 298 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
299 299 [ this, var = it->first ]() { removeVariable(var); });
300 300 }
301 301
302 302 if (!graphMenu.isEmpty()) {
303 303 graphMenu.exec(QCursor::pos());
304 304 }
305 305 }
306 306
307 307 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
308 308 {
309 309 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
310 310 << QThread::currentThread()->objectName() << "DoAcqui"
311 311 << impl->m_DoAcquisition;
312 312
313 313 auto graphRange = SqpRange{t1.lower, t1.upper};
314 314 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
315 315
316 316 if (impl->m_DoAcquisition) {
317 317 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
318 318
319 319 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
320 320 end = impl->m_VariableToPlotMultiMap.end();
321 321 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
322 322 variableUnderGraphVector.push_back(it->first);
323 323 }
324 324 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
325 325 !impl->m_IsCalibration);
326 326
327 327 if (!impl->m_IsCalibration) {
328 328 qCDebug(LOG_VisualizationGraphWidget())
329 329 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
330 330 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
331 331 emit synchronize(graphRange, oldGraphRange);
332 332 }
333 333 }
334 334 }
335 335
336 336 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
337 337 {
338 338 // Handles plot rendering when mouse is moving
339 339 impl->m_RenderingDelegate->onMouseMove(event);
340 340
341 341 VisualizationDragWidget::mouseMoveEvent(event);
342 342 }
343 343
344 344 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
345 345 {
346 346 auto zoomOrientations = QFlags<Qt::Orientation>{};
347 347
348 348 // Lambda that enables a zoom orientation if the key modifier related to this orientation
349 349 // has
350 350 // been pressed
351 351 auto enableOrientation
352 352 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
353 353 auto orientationEnabled = event->modifiers().testFlag(modifier);
354 354 zoomOrientations.setFlag(orientation, orientationEnabled);
355 355 };
356 356 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
357 357 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
358 358
359 359 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
360 360 }
361 361
362 362 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
363 363 {
364 364 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
365 365
366 366 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
367 367
368 368 VisualizationDragWidget::mousePressEvent(event);
369 369 }
370 370
371 371 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
372 372 {
373 373 impl->m_IsCalibration = false;
374 374 }
375 375
376 376 void VisualizationGraphWidget::onDataCacheVariableUpdated()
377 377 {
378 378 auto graphRange = ui->widget->xAxis->range();
379 379 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
380 380
381 381 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
382 382 auto variable = variableEntry.first;
383 383 qCDebug(LOG_VisualizationGraphWidget())
384 384 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
385 385 qCDebug(LOG_VisualizationGraphWidget())
386 386 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
387 387 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
388 388 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
389 389 variable->range());
390 390 }
391 391 }
392 392 }
393 393
394 394 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
395 395 const SqpRange &range)
396 396 {
397 397 auto it = impl->m_VariableToPlotMultiMap.find(variable);
398 398 if (it != impl->m_VariableToPlotMultiMap.end()) {
399 399 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
400 400 }
401 401 }
@@ -1,309 +1,309
1 1 #include "Visualization/VisualizationTabWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "ui_VisualizationTabWidget.h"
4 4
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7
8 8 #include "Variable/VariableController.h"
9 9
10 10 #include "Common/MimeTypesDef.h"
11 11
12 #include "DragDropHelper.h"
12 #include "DragAndDrop/DragDropHelper.h"
13 13 #include "SqpApplication.h"
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
16 16
17 17 namespace {
18 18
19 19 /// Generates a default name for a new zone, according to the number of zones already displayed in
20 20 /// the tab
21 21 QString defaultZoneName(const QLayout &layout)
22 22 {
23 23 auto count = 0;
24 24 for (auto i = 0; i < layout.count(); ++i) {
25 25 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
26 26 count++;
27 27 }
28 28 }
29 29
30 30 return QObject::tr("Zone %1").arg(count + 1);
31 31 }
32 32
33 33 /**
34 34 * Applies a function to all zones of the tab represented by its layout
35 35 * @param layout the layout that contains zones
36 36 * @param fun the function to apply to each zone
37 37 */
38 38 template <typename Fun>
39 39 void processZones(QLayout &layout, Fun fun)
40 40 {
41 41 for (auto i = 0; i < layout.count(); ++i) {
42 42 if (auto item = layout.itemAt(i)) {
43 43 if (auto visualizationZoneWidget
44 44 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
45 45 fun(*visualizationZoneWidget);
46 46 }
47 47 }
48 48 }
49 49 }
50 50
51 51 } // namespace
52 52
53 53 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
54 54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
55 55
56 56 QString m_Name;
57 57
58 58 void dropGraph(int index, VisualizationTabWidget *tabWidget);
59 59 void dropZone(int index, VisualizationTabWidget *tabWidget);
60 60 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
61 61 VisualizationTabWidget *tabWidget);
62 62 };
63 63
64 64 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
65 65 : QWidget{parent},
66 66 ui{new Ui::VisualizationTabWidget},
67 67 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
68 68 {
69 69 ui->setupUi(this);
70 70
71 71 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Zone, "Zone");
72 72 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 5);
73 73 ui->dragDropContainer->addAcceptedMimeType(
74 74 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
75 75 ui->dragDropContainer->addAcceptedMimeType(
76 76 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
77 77 ui->dragDropContainer->addAcceptedMimeType(
78 78 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
79 79
80 80 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
81 81 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
82 82 ui->dragDropContainer);
83 83 });
84 84
85 85 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
86 86 &VisualizationTabWidget::dropMimeData);
87 87
88 88 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
89 89
90 90 // Widget is deleted when closed
91 91 setAttribute(Qt::WA_DeleteOnClose);
92 92 }
93 93
94 94 VisualizationTabWidget::~VisualizationTabWidget()
95 95 {
96 96 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
97 97 delete ui;
98 98 }
99 99
100 100 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
101 101 {
102 102 ui->dragDropContainer->addDragWidget(zoneWidget);
103 103 }
104 104
105 105 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
106 106 {
107 107 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
108 108 }
109 109
110 110 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
111 111 {
112 112 return createZone({variable}, -1);
113 113 }
114 114
115 115 VisualizationZoneWidget *
116 116 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
117 117 {
118 118 auto zoneWidget = createEmptyZone(index);
119 119
120 120 // Creates a new graph into the zone
121 121 zoneWidget->createGraph(variables, index);
122 122
123 123 return zoneWidget;
124 124 }
125 125
126 126 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
127 127 {
128 128 auto zoneWidget
129 129 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
130 130 this->insertZone(index, zoneWidget);
131 131
132 132 return zoneWidget;
133 133 }
134 134
135 135 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
136 136 {
137 137 if (visitor) {
138 138 visitor->visitEnter(this);
139 139
140 140 // Apply visitor to zone children: widgets different from zones are not visited (no action)
141 141 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
142 142 zoneWidget.accept(visitor);
143 143 });
144 144
145 145 visitor->visitLeave(this);
146 146 }
147 147 else {
148 148 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
149 149 }
150 150 }
151 151
152 152 bool VisualizationTabWidget::canDrop(const Variable &variable) const
153 153 {
154 154 // A tab can always accomodate a variable
155 155 Q_UNUSED(variable);
156 156 return true;
157 157 }
158 158
159 159 bool VisualizationTabWidget::contains(const Variable &variable) const
160 160 {
161 161 Q_UNUSED(variable);
162 162 return false;
163 163 }
164 164
165 165 QString VisualizationTabWidget::name() const
166 166 {
167 167 return impl->m_Name;
168 168 }
169 169
170 170 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
171 171 {
172 172 // Closes zones in the tab
173 173 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
174 174
175 175 QWidget::closeEvent(event);
176 176 }
177 177
178 178 QLayout &VisualizationTabWidget::tabLayout() const noexcept
179 179 {
180 180 return *ui->dragDropContainer->layout();
181 181 }
182 182
183 183 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
184 184 {
185 185 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
186 186 impl->dropGraph(index, this);
187 187 }
188 188 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
189 189 impl->dropZone(index, this);
190 190 }
191 191 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
192 192 auto variables = sqpApp->variableController().variablesForMimeData(
193 193 mimeData->data(MIME_TYPE_VARIABLE_LIST));
194 194 impl->dropVariables(variables, index, this);
195 195 }
196 196 else {
197 197 qCWarning(LOG_VisualizationZoneWidget())
198 198 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
199 199 }
200 200 }
201 201
202 202 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
203 203 int index, VisualizationTabWidget *tabWidget)
204 204 {
205 205 auto &helper = sqpApp->dragDropHelper();
206 206
207 207 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
208 208 if (!graphWidget) {
209 209 qCWarning(LOG_VisualizationZoneWidget())
210 210 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
211 211 "found or invalid.");
212 212 Q_ASSERT(false);
213 213 return;
214 214 }
215 215
216 216 auto parentDragDropContainer
217 217 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
218 218 if (!parentDragDropContainer) {
219 219 qCWarning(LOG_VisualizationZoneWidget())
220 220 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
221 221 "the dropped graph is not found.");
222 222 Q_ASSERT(false);
223 223 return;
224 224 }
225 225
226 226 auto nbGraph = parentDragDropContainer->countDragWidget();
227 227
228 228 const auto &variables = graphWidget->variables();
229 229
230 230 if (!variables.isEmpty()) {
231 231 // Abort the requests for the variables (if any)
232 232 // Commented, because it's not sure if it's needed or not
233 233 // for (const auto& var : variables)
234 234 //{
235 235 // sqpApp->variableController().onAbortProgressRequested(var);
236 236 //}
237 237
238 238 if (nbGraph == 1) {
239 239 // This is the only graph in the previous zone, close the zone
240 240 graphWidget->parentZoneWidget()->close();
241 241 }
242 242 else {
243 243 // Close the graph
244 244 graphWidget->close();
245 245 }
246 246
247 247 tabWidget->createZone(variables, index);
248 248 }
249 249 else {
250 250 // The graph is empty, create an empty zone and move the graph inside
251 251
252 252 auto parentZoneWidget = graphWidget->parentZoneWidget();
253 253
254 254 parentDragDropContainer->layout()->removeWidget(graphWidget);
255 255
256 256 auto zoneWidget = tabWidget->createEmptyZone(index);
257 257 zoneWidget->addGraph(graphWidget);
258 258
259 259 // Close the old zone if it was the only graph inside
260 260 if (nbGraph == 1) {
261 261 parentZoneWidget->close();
262 262 }
263 263 }
264 264 }
265 265
266 266 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
267 267 int index, VisualizationTabWidget *tabWidget)
268 268 {
269 269 auto &helper = sqpApp->dragDropHelper();
270 270
271 271 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
272 272 if (!zoneWidget) {
273 273 qCWarning(LOG_VisualizationZoneWidget())
274 274 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
275 275 "found or invalid.");
276 276 Q_ASSERT(false);
277 277 return;
278 278 }
279 279
280 280 auto parentDragDropContainer
281 281 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
282 282 if (!parentDragDropContainer) {
283 283 qCWarning(LOG_VisualizationZoneWidget())
284 284 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
285 285 "the dropped zone is not found.");
286 286 Q_ASSERT(false);
287 287 return;
288 288 }
289 289
290 290 // Simple move of the zone, no variable operation associated
291 291 parentDragDropContainer->layout()->removeWidget(zoneWidget);
292 292 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
293 293 }
294 294
295 295 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
296 296 const QList<std::shared_ptr<Variable> > &variables, int index,
297 297 VisualizationTabWidget *tabWidget)
298 298 {
299 299 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
300 300 // compatible variable here
301 301 if (variables.count() > 1) {
302 302 qCWarning(LOG_VisualizationZoneWidget())
303 303 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
304 304 "aborted.");
305 305 return;
306 306 }
307 307
308 308 tabWidget->createZone(variables, index);
309 309 }
@@ -1,516 +1,516
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 4 #include "Visualization/QCustomPlotSynchronizer.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "Visualization/VisualizationWidget.h"
7 7 #include "ui_VisualizationZoneWidget.h"
8 8
9 9 #include "Common/MimeTypesDef.h"
10 10 #include "Common/VisualizationDef.h"
11 11
12 12 #include <Data/SqpRange.h>
13 13 #include <Time/TimeController.h>
14 14 #include <Variable/Variable.h>
15 15 #include <Variable/VariableController.h>
16 16
17 17 #include <Visualization/operations/FindVariableOperation.h>
18 18
19 #include <DragDropHelper.h>
19 #include <DragAndDrop/DragDropHelper.h>
20 20 #include <QUuid>
21 21 #include <SqpApplication.h>
22 22 #include <cmath>
23 23
24 24 #include <QLayout>
25 25
26 26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27 27
28 28 namespace {
29 29
30 30
31 31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
32 32 /// the zone
33 33 QString defaultGraphName(const QLayout &layout)
34 34 {
35 35 auto count = 0;
36 36 for (auto i = 0; i < layout.count(); ++i) {
37 37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
38 38 count++;
39 39 }
40 40 }
41 41
42 42 return QObject::tr("Graph %1").arg(count + 1);
43 43 }
44 44
45 45 /**
46 46 * Applies a function to all graphs of the zone represented by its layout
47 47 * @param layout the layout that contains graphs
48 48 * @param fun the function to apply to each graph
49 49 */
50 50 template <typename Fun>
51 51 void processGraphs(QLayout &layout, Fun fun)
52 52 {
53 53 for (auto i = 0; i < layout.count(); ++i) {
54 54 if (auto item = layout.itemAt(i)) {
55 55 if (auto visualizationGraphWidget
56 56 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
57 57 fun(*visualizationGraphWidget);
58 58 }
59 59 }
60 60 }
61 61 }
62 62
63 63 } // namespace
64 64
65 65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
66 66
67 67 explicit VisualizationZoneWidgetPrivate()
68 68 : m_SynchronisationGroupId{QUuid::createUuid()},
69 69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
70 70 {
71 71 }
72 72 QUuid m_SynchronisationGroupId;
73 73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
74 74
75 75 // Returns the first graph in the zone or nullptr if there is no graph inside
76 76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
77 77 {
78 78 VisualizationGraphWidget *firstGraph = nullptr;
79 79 auto layout = zoneWidget->ui->dragDropContainer->layout();
80 80 if (layout->count() > 0) {
81 81 if (auto visualizationGraphWidget
82 82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
83 83 firstGraph = visualizationGraphWidget;
84 84 }
85 85 }
86 86
87 87 return firstGraph;
88 88 }
89 89
90 90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
91 91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
92 92 VisualizationZoneWidget *zoneWidget);
93 93 };
94 94
95 95 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
96 96 : VisualizationDragWidget{parent},
97 97 ui{new Ui::VisualizationZoneWidget},
98 98 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
99 99 {
100 100 ui->setupUi(this);
101 101
102 102 ui->zoneNameLabel->setText(name);
103 103
104 104 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
105 105 ui->dragDropContainer->addAcceptedMimeType(
106 106 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
107 107 ui->dragDropContainer->addAcceptedMimeType(
108 108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
109 109 ui->dragDropContainer->addAcceptedMimeType(
110 110 MIME_TYPE_TIME_RANGE, VisualizationDragDropContainer::DropBehavior::Merged);
111 111 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
112 112 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
113 113 ui->dragDropContainer);
114 114 });
115 115
116 116 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
117 117 &VisualizationZoneWidget::dropMimeData);
118 118 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
119 119 &VisualizationZoneWidget::dropMimeDataOnGraph);
120 120
121 121 // 'Close' options : widget is deleted when closed
122 122 setAttribute(Qt::WA_DeleteOnClose);
123 123 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
124 124 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
125 125
126 126 // Synchronisation id
127 127 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
128 128 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
129 129 }
130 130
131 131 VisualizationZoneWidget::~VisualizationZoneWidget()
132 132 {
133 133 delete ui;
134 134 }
135 135
136 136 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
137 137 {
138 138 // Synchronize new graph with others in the zone
139 139 impl->m_Synchronizer->addGraph(*graphWidget);
140 140
141 141 ui->dragDropContainer->addDragWidget(graphWidget);
142 142 }
143 143
144 144 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
145 145 {
146 146 // Synchronize new graph with others in the zone
147 147 impl->m_Synchronizer->addGraph(*graphWidget);
148 148
149 149 ui->dragDropContainer->insertDragWidget(index, graphWidget);
150 150 }
151 151
152 152 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
153 153 {
154 154 return createGraph(variable, -1);
155 155 }
156 156
157 157 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
158 158 int index)
159 159 {
160 160 auto graphWidget
161 161 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
162 162
163 163
164 164 // Set graph properties
165 165 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
166 166 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
167 167
168 168
169 169 // Lambda to synchronize zone widget
170 170 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
171 171 const SqpRange &oldGraphRange) {
172 172
173 173 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
174 174 auto frameLayout = ui->dragDropContainer->layout();
175 175 for (auto i = 0; i < frameLayout->count(); ++i) {
176 176 auto graphChild
177 177 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
178 178 if (graphChild && (graphChild != graphWidget)) {
179 179
180 180 auto graphChildRange = graphChild->graphRange();
181 181 switch (zoomType) {
182 182 case AcquisitionZoomType::ZoomIn: {
183 183 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
184 184 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
185 185 graphChildRange.m_TStart += deltaLeft;
186 186 graphChildRange.m_TEnd -= deltaRight;
187 187 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
188 188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
189 189 << deltaLeft;
190 190 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
191 191 << deltaRight;
192 192 qCDebug(LOG_VisualizationZoneWidget())
193 193 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
194 194
195 195 break;
196 196 }
197 197
198 198 case AcquisitionZoomType::ZoomOut: {
199 199 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
200 200 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
201 201 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
202 202 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
203 203 << deltaLeft;
204 204 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
205 205 << deltaRight;
206 206 qCDebug(LOG_VisualizationZoneWidget())
207 207 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
208 208 graphChildRange.m_TStart -= deltaLeft;
209 209 graphChildRange.m_TEnd += deltaRight;
210 210 break;
211 211 }
212 212 case AcquisitionZoomType::PanRight: {
213 213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
214 214 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
215 215 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
216 216 graphChildRange.m_TStart += deltaLeft;
217 217 graphChildRange.m_TEnd += deltaRight;
218 218 qCDebug(LOG_VisualizationZoneWidget())
219 219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
220 220 break;
221 221 }
222 222 case AcquisitionZoomType::PanLeft: {
223 223 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
224 224 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
225 225 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
226 226 graphChildRange.m_TStart -= deltaLeft;
227 227 graphChildRange.m_TEnd -= deltaRight;
228 228 break;
229 229 }
230 230 case AcquisitionZoomType::Unknown: {
231 231 qCDebug(LOG_VisualizationZoneWidget())
232 232 << tr("Impossible to synchronize: zoom type unknown");
233 233 break;
234 234 }
235 235 default:
236 236 qCCritical(LOG_VisualizationZoneWidget())
237 237 << tr("Impossible to synchronize: zoom type not take into account");
238 238 // No action
239 239 break;
240 240 }
241 241 graphChild->enableAcquisition(false);
242 242 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
243 243 << graphChild->graphRange();
244 244 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
245 245 << graphChildRange;
246 246 qCDebug(LOG_VisualizationZoneWidget())
247 247 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
248 248 graphChild->setGraphRange(graphChildRange);
249 249 graphChild->enableAcquisition(true);
250 250 }
251 251 }
252 252 };
253 253
254 254 // connection for synchronization
255 255 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
256 256 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
257 257 &VisualizationZoneWidget::onVariableAdded);
258 258 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
259 259 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
260 260
261 261 auto range = SqpRange{};
262 262 if (auto firstGraph = impl->firstGraph(this)) {
263 263 // Case of a new graph in a existant zone
264 264 range = firstGraph->graphRange();
265 265 }
266 266 else {
267 267 // Case of a new graph as the first of the zone
268 268 range = variable->range();
269 269 }
270 270
271 271 this->insertGraph(index, graphWidget);
272 272
273 273 graphWidget->addVariable(variable, range);
274 274
275 275 // get y using variable range
276 276 if (auto dataSeries = variable->dataSeries()) {
277 277 dataSeries->lockRead();
278 278 auto valuesBounds
279 279 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
280 280 auto end = dataSeries->cend();
281 281 if (valuesBounds.first != end && valuesBounds.second != end) {
282 282 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
283 283
284 284 auto minValue = rangeValue(valuesBounds.first->minValue());
285 285 auto maxValue = rangeValue(valuesBounds.second->maxValue());
286 286
287 287 graphWidget->setYRange(SqpRange{minValue, maxValue});
288 288 }
289 289 dataSeries->unlock();
290 290 }
291 291
292 292 return graphWidget;
293 293 }
294 294
295 295 VisualizationGraphWidget *
296 296 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
297 297 {
298 298 if (variables.isEmpty()) {
299 299 return nullptr;
300 300 }
301 301
302 302 auto graphWidget = createGraph(variables.first(), index);
303 303 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
304 304 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
305 305 }
306 306
307 307 return graphWidget;
308 308 }
309 309
310 310 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
311 311 {
312 312 if (visitor) {
313 313 visitor->visitEnter(this);
314 314
315 315 // Apply visitor to graph children: widgets different from graphs are not visited (no
316 316 // action)
317 317 processGraphs(
318 318 *ui->dragDropContainer->layout(),
319 319 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
320 320
321 321 visitor->visitLeave(this);
322 322 }
323 323 else {
324 324 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
325 325 }
326 326 }
327 327
328 328 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
329 329 {
330 330 // A tab can always accomodate a variable
331 331 Q_UNUSED(variable);
332 332 return true;
333 333 }
334 334
335 335 bool VisualizationZoneWidget::contains(const Variable &variable) const
336 336 {
337 337 Q_UNUSED(variable);
338 338 return false;
339 339 }
340 340
341 341 QString VisualizationZoneWidget::name() const
342 342 {
343 343 return ui->zoneNameLabel->text();
344 344 }
345 345
346 346 QMimeData *VisualizationZoneWidget::mimeData() const
347 347 {
348 348 auto mimeData = new QMimeData;
349 349 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
350 350
351 351 return mimeData;
352 352 }
353 353
354 354 bool VisualizationZoneWidget::isDragAllowed() const
355 355 {
356 356 return true;
357 357 }
358 358
359 359 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
360 360 {
361 361 // Closes graphs in the zone
362 362 processGraphs(*ui->dragDropContainer->layout(),
363 363 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
364 364
365 365 // Delete synchronization group from variable controller
366 366 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
367 367 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
368 368
369 369 QWidget::closeEvent(event);
370 370 }
371 371
372 372 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
373 373 {
374 374 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
375 375 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
376 376 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
377 377 }
378 378
379 379 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
380 380 {
381 381 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
382 382 Q_ARG(std::shared_ptr<Variable>, variable),
383 383 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
384 384 }
385 385
386 386 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
387 387 {
388 388 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
389 389 impl->dropGraph(index, this);
390 390 }
391 391 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
392 392 auto variables = sqpApp->variableController().variablesForMimeData(
393 393 mimeData->data(MIME_TYPE_VARIABLE_LIST));
394 394 impl->dropVariables(variables, index, this);
395 395 }
396 396 else {
397 397 qCWarning(LOG_VisualizationZoneWidget())
398 398 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
399 399 }
400 400 }
401 401
402 402 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
403 403 const QMimeData *mimeData)
404 404 {
405 405 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
406 406 if (!graphWidget) {
407 407 qCWarning(LOG_VisualizationZoneWidget())
408 408 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
409 409 "drop aborted");
410 410 Q_ASSERT(false);
411 411 return;
412 412 }
413 413
414 414 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
415 415 auto variables = sqpApp->variableController().variablesForMimeData(
416 416 mimeData->data(MIME_TYPE_VARIABLE_LIST));
417 417 for (const auto &var : variables) {
418 418 graphWidget->addVariable(var, graphWidget->graphRange());
419 419 }
420 420 }
421 421 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
422 422 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
423 423 graphWidget->setGraphRange(range);
424 424 }
425 425 else {
426 426 qCWarning(LOG_VisualizationZoneWidget())
427 427 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
428 428 }
429 429 }
430 430
431 431 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
432 432 int index, VisualizationZoneWidget *zoneWidget)
433 433 {
434 434 auto &helper = sqpApp->dragDropHelper();
435 435
436 436 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
437 437 if (!graphWidget) {
438 438 qCWarning(LOG_VisualizationZoneWidget())
439 439 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
440 440 "found or invalid.");
441 441 Q_ASSERT(false);
442 442 return;
443 443 }
444 444
445 445 auto parentDragDropContainer
446 446 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
447 447 if (!parentDragDropContainer) {
448 448 qCWarning(LOG_VisualizationZoneWidget())
449 449 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
450 450 "the dropped graph is not found.");
451 451 Q_ASSERT(false);
452 452 return;
453 453 }
454 454
455 455 const auto &variables = graphWidget->variables();
456 456
457 457 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
458 458 // The drop didn't occur in the same zone
459 459
460 460 // Abort the requests for the variables (if any)
461 461 // Commented, because it's not sure if it's needed or not
462 462 // for (const auto& var : variables)
463 463 //{
464 464 // sqpApp->variableController().onAbortProgressRequested(var);
465 465 //}
466 466
467 467 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
468 468 auto nbGraph = parentDragDropContainer->countDragWidget();
469 469 if (nbGraph == 1) {
470 470 // This is the only graph in the previous zone, close the zone
471 471 previousParentZoneWidget->close();
472 472 }
473 473 else {
474 474 // Close the graph
475 475 graphWidget->close();
476 476 }
477 477
478 478 // Creates the new graph in the zone
479 479 zoneWidget->createGraph(variables, index);
480 480 }
481 481 else {
482 482 // The drop occurred in the same zone or the graph is empty
483 483 // Simple move of the graph, no variable operation associated
484 484 parentDragDropContainer->layout()->removeWidget(graphWidget);
485 485
486 486 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
487 487 // The graph is empty and dropped in a different zone.
488 488 // Take the range of the first graph in the zone (if existing).
489 489 auto layout = zoneWidget->ui->dragDropContainer->layout();
490 490 if (layout->count() > 0) {
491 491 if (auto visualizationGraphWidget
492 492 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
493 493 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
494 494 }
495 495 }
496 496 }
497 497
498 498 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
499 499 }
500 500 }
501 501
502 502 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
503 503 const QList<std::shared_ptr<Variable> > &variables, int index,
504 504 VisualizationZoneWidget *zoneWidget)
505 505 {
506 506 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
507 507 // compatible variable here
508 508 if (variables.count() > 1) {
509 509 qCWarning(LOG_VisualizationZoneWidget())
510 510 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
511 511 "aborted.");
512 512 return;
513 513 }
514 514
515 515 zoneWidget->createGraph(variables, index);
516 516 }
General Comments 3
Under Review
author

Pull request updated. Auto status change to "Under Review"

Changed commits:
  * 1 added
  * 0 removed

Changed files:
  * A core/tests/meson.build
You need to be logged in to leave comments. Login now