##// END OF EJS Templates
Ensures graph and zone names are not duplicated in the visualization
trabillard -
r1137:030ee50565df
parent child
Show More
@@ -1,338 +1,342
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 "Visualization/MacScrollBarStyle.h"
9 9
10 10 #include "Variable/VariableController.h"
11 11
12 12 #include "Common/MimeTypesDef.h"
13 13
14 14 #include "DragAndDrop/DragDropGuiController.h"
15 15 #include "SqpApplication.h"
16 16
17 17 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
18 18
19 19 namespace {
20 20
21 /// Generates a default name for a new zone, according to the number of zones already displayed in
22 /// the tab
23 QString defaultZoneName(const QLayout &layout)
24 {
25 auto count = 0;
26 for (auto i = 0; i < layout.count(); ++i) {
27 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
28 count++;
29 }
30 }
31
32 return QObject::tr("Zone %1").arg(count + 1);
33 }
34
35 21 /**
36 22 * Applies a function to all zones of the tab represented by its layout
37 23 * @param layout the layout that contains zones
38 24 * @param fun the function to apply to each zone
39 25 */
40 26 template <typename Fun>
41 27 void processZones(QLayout &layout, Fun fun)
42 28 {
43 29 for (auto i = 0; i < layout.count(); ++i) {
44 30 if (auto item = layout.itemAt(i)) {
45 31 if (auto visualizationZoneWidget
46 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
32 = qobject_cast<VisualizationZoneWidget *>(item->widget())) {
47 33 fun(*visualizationZoneWidget);
48 34 }
49 35 }
50 36 }
51 37 }
52 38
39 /// Generates a default name for a new zone, according to the number of zones already displayed in
40 /// the tab
41 QString defaultZoneName(QLayout &layout)
42 {
43 QSet<QString> existingNames;
44 processZones(layout,
45 [&existingNames](auto &zoneWidget) { existingNames.insert(zoneWidget.name()); });
46
47 int zoneNum = 1;
48 QString name;
49 do {
50 name = QObject::tr("Zone ").append(QString::number(zoneNum));
51 ++zoneNum;
52 } while (existingNames.contains(name));
53
54 return name;
55 }
56
53 57 } // namespace
54 58
55 59 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
56 60 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
57 61
58 62 QString m_Name;
59 63
60 64 #ifdef Q_OS_MAC
61 65 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
62 66 #endif
63 67
64 68 void dropGraph(int index, VisualizationTabWidget *tabWidget);
65 69 void dropZone(int index, VisualizationTabWidget *tabWidget);
66 70 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
67 71 VisualizationTabWidget *tabWidget);
68 72 };
69 73
70 74 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
71 75 : QWidget{parent},
72 76 ui{new Ui::VisualizationTabWidget},
73 77 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
74 78 {
75 79 ui->setupUi(this);
76 80
77 81 #ifdef Q_OS_MAC
78 82 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
79 83 #endif
80 84
81 85 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Zone, "Zone");
82 86 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
83 87 ui->dragDropContainer->layout()->setSpacing(0);
84 88 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
85 89 VisualizationDragDropContainer::DropBehavior::Inserted);
86 90 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
87 91 VisualizationDragDropContainer::DropBehavior::Inserted);
88 92 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
89 93 VisualizationDragDropContainer::DropBehavior::Inserted);
90 94
91 95 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
92 96 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
93 97 ui->dragDropContainer);
94 98 });
95 99
96 100 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
97 101 &VisualizationTabWidget::dropMimeData);
98 102
99 103 sqpApp->dragDropGuiController().addDragDropScrollArea(ui->scrollArea);
100 104
101 105 // Widget is deleted when closed
102 106 setAttribute(Qt::WA_DeleteOnClose);
103 107 }
104 108
105 109 VisualizationTabWidget::~VisualizationTabWidget()
106 110 {
107 111 sqpApp->dragDropGuiController().removeDragDropScrollArea(ui->scrollArea);
108 112 delete ui;
109 113 }
110 114
111 115 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
112 116 {
113 117 ui->dragDropContainer->addDragWidget(zoneWidget);
114 118 }
115 119
116 120 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
117 121 {
118 122 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
119 123 }
120 124
121 125 QStringList VisualizationTabWidget::availableZoneWidgets() const
122 126 {
123 127 QStringList zones;
124 128 processZones(tabLayout(),
125 129 [&zones](VisualizationZoneWidget &zoneWidget) { zones << zoneWidget.name(); });
126 130
127 131 return zones;
128 132 }
129 133
130 134 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
131 135 {
132 136 return createZone({variable}, -1);
133 137 }
134 138
135 139 VisualizationZoneWidget *
136 140 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
137 141 {
138 142 auto zoneWidget = createEmptyZone(index);
139 143
140 144 // Creates a new graph into the zone
141 145 zoneWidget->createGraph(variables, index);
142 146
143 147 return zoneWidget;
144 148 }
145 149
146 150 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
147 151 {
148 152 auto zoneWidget
149 153 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
150 154 this->insertZone(index, zoneWidget);
151 155
152 156 return zoneWidget;
153 157 }
154 158
155 159 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
156 160 {
157 161 if (visitor) {
158 162 visitor->visitEnter(this);
159 163
160 164 // Apply visitor to zone children: widgets different from zones are not visited (no action)
161 165 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
162 166 zoneWidget.accept(visitor);
163 167 });
164 168
165 169 visitor->visitLeave(this);
166 170 }
167 171 else {
168 172 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
169 173 }
170 174 }
171 175
172 176 bool VisualizationTabWidget::canDrop(const Variable &variable) const
173 177 {
174 178 // A tab can always accomodate a variable
175 179 Q_UNUSED(variable);
176 180 return true;
177 181 }
178 182
179 183 bool VisualizationTabWidget::contains(const Variable &variable) const
180 184 {
181 185 Q_UNUSED(variable);
182 186 return false;
183 187 }
184 188
185 189 QString VisualizationTabWidget::name() const
186 190 {
187 191 return impl->m_Name;
188 192 }
189 193
190 194 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
191 195 {
192 196 // Closes zones in the tab
193 197 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
194 198
195 199 QWidget::closeEvent(event);
196 200 }
197 201
198 202 QLayout &VisualizationTabWidget::tabLayout() const noexcept
199 203 {
200 204 return *ui->dragDropContainer->layout();
201 205 }
202 206
203 207 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
204 208 {
205 209 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
206 210 impl->dropGraph(index, this);
207 211 }
208 212 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
209 213 impl->dropZone(index, this);
210 214 }
211 215 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
212 216 auto variables = sqpApp->variableController().variablesForMimeData(
213 217 mimeData->data(MIME_TYPE_VARIABLE_LIST));
214 218 impl->dropVariables(variables, index, this);
215 219 }
216 220 else {
217 221 qCWarning(LOG_VisualizationZoneWidget())
218 222 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
219 223 }
220 224 }
221 225
222 226 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
223 227 int index, VisualizationTabWidget *tabWidget)
224 228 {
225 229 auto &helper = sqpApp->dragDropGuiController();
226 230
227 231 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
228 232 if (!graphWidget) {
229 233 qCWarning(LOG_VisualizationZoneWidget())
230 234 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
231 235 "found or invalid.");
232 236 Q_ASSERT(false);
233 237 return;
234 238 }
235 239
236 240 auto parentDragDropContainer
237 241 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
238 242 if (!parentDragDropContainer) {
239 243 qCWarning(LOG_VisualizationZoneWidget())
240 244 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
241 245 "the dropped graph is not found.");
242 246 Q_ASSERT(false);
243 247 return;
244 248 }
245 249
246 250 auto nbGraph = parentDragDropContainer->countDragWidget();
247 251
248 252 const auto &variables = graphWidget->variables();
249 253
250 254 if (!variables.isEmpty()) {
251 255 // Abort the requests for the variables (if any)
252 256 // Commented, because it's not sure if it's needed or not
253 257 // for (const auto& var : variables)
254 258 //{
255 259 // sqpApp->variableController().onAbortProgressRequested(var);
256 260 //}
257 261
258 262 if (nbGraph == 1) {
259 263 // This is the only graph in the previous zone, close the zone
260 264 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
261 265 }
262 266 else {
263 267 // Close the graph
264 268 helper.delayedCloseWidget(graphWidget);
265 269 }
266 270
267 271 auto zoneWidget = tabWidget->createZone(variables, index);
268 272 auto firstGraph = zoneWidget->firstGraph();
269 273 if (firstGraph) {
270 274 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
271 275 }
272 276 else {
273 277 qCWarning(LOG_VisualizationZoneWidget())
274 278 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
275 279 Q_ASSERT(false);
276 280 }
277 281 }
278 282 else {
279 283 // The graph is empty, create an empty zone and move the graph inside
280 284
281 285 auto parentZoneWidget = graphWidget->parentZoneWidget();
282 286
283 287 parentDragDropContainer->layout()->removeWidget(graphWidget);
284 288
285 289 auto zoneWidget = tabWidget->createEmptyZone(index);
286 290 zoneWidget->addGraph(graphWidget);
287 291
288 292 // Close the old zone if it was the only graph inside
289 293 if (nbGraph == 1) {
290 294 helper.delayedCloseWidget(parentZoneWidget);
291 295 }
292 296 }
293 297 }
294 298
295 299 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
296 300 int index, VisualizationTabWidget *tabWidget)
297 301 {
298 302 auto &helper = sqpApp->dragDropGuiController();
299 303
300 304 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
301 305 if (!zoneWidget) {
302 306 qCWarning(LOG_VisualizationZoneWidget())
303 307 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
304 308 "found or invalid.");
305 309 Q_ASSERT(false);
306 310 return;
307 311 }
308 312
309 313 auto parentDragDropContainer
310 314 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
311 315 if (!parentDragDropContainer) {
312 316 qCWarning(LOG_VisualizationZoneWidget())
313 317 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
314 318 "the dropped zone is not found.");
315 319 Q_ASSERT(false);
316 320 return;
317 321 }
318 322
319 323 // Simple move of the zone, no variable operation associated
320 324 parentDragDropContainer->layout()->removeWidget(zoneWidget);
321 325 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
322 326 }
323 327
324 328 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
325 329 const QList<std::shared_ptr<Variable> > &variables, int index,
326 330 VisualizationTabWidget *tabWidget)
327 331 {
328 332 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
329 333 // compatible variable here
330 334 if (variables.count() > 1) {
331 335 qCWarning(LOG_VisualizationZoneWidget())
332 336 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
333 337 "aborted.");
334 338 return;
335 339 }
336 340
337 341 tabWidget->createZone(variables, index);
338 342 }
@@ -1,587 +1,590
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 19 #include <DragAndDrop/DragDropGuiController.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
31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
32 /// the zone
33 QString defaultGraphName(const QLayout &layout)
34 {
35 auto count = 0;
36 for (auto i = 0; i < layout.count(); ++i) {
37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
38 count++;
39 }
40 }
41
42 return QObject::tr("Graph %1").arg(count + 1);
43 }
44
45 30 /**
46 31 * Applies a function to all graphs of the zone represented by its layout
47 32 * @param layout the layout that contains graphs
48 33 * @param fun the function to apply to each graph
49 34 */
50 35 template <typename Fun>
51 36 void processGraphs(QLayout &layout, Fun fun)
52 37 {
53 38 for (auto i = 0; i < layout.count(); ++i) {
54 39 if (auto item = layout.itemAt(i)) {
55 40 if (auto visualizationGraphWidget
56 41 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
57 42 fun(*visualizationGraphWidget);
58 43 }
59 44 }
60 45 }
61 46 }
62 47
48 /// Generates a default name for a new graph, according to the number of graphs already displayed in
49 /// the zone
50 QString defaultGraphName(QLayout &layout)
51 {
52 QSet<QString> existingNames;
53 processGraphs(
54 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
55
56 int zoneNum = 1;
57 QString name;
58 do {
59 name = QObject::tr("Graph ").append(QString::number(zoneNum));
60 ++zoneNum;
61 } while (existingNames.contains(name));
62
63 return name;
64 }
65
63 66 } // namespace
64 67
65 68 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
66 69
67 70 explicit VisualizationZoneWidgetPrivate()
68 71 : m_SynchronisationGroupId{QUuid::createUuid()},
69 72 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
70 73 {
71 74 }
72 75 QUuid m_SynchronisationGroupId;
73 76 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
74 77
75 78 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
76 79 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
77 80 VisualizationZoneWidget *zoneWidget);
78 81 };
79 82
80 83 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
81 84 : VisualizationDragWidget{parent},
82 85 ui{new Ui::VisualizationZoneWidget},
83 86 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
84 87 {
85 88 ui->setupUi(this);
86 89
87 90 ui->zoneNameLabel->setText(name);
88 91
89 92 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
90 93 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
91 94 VisualizationDragDropContainer::DropBehavior::Inserted);
92 95 ui->dragDropContainer->setMimeType(
93 96 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
94 97 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
95 98 VisualizationDragDropContainer::DropBehavior::Merged);
96 99 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
97 100 VisualizationDragDropContainer::DropBehavior::Forbidden);
98 101 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
99 102 VisualizationDragDropContainer::DropBehavior::Forbidden);
100 103 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
101 104 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
102 105 ui->dragDropContainer);
103 106 });
104 107
105 108 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
106 109 if (!mimeData) {
107 110 return false;
108 111 }
109 112
110 113 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
111 114 auto variables = sqpApp->variableController().variablesForMimeData(
112 115 mimeData->data(MIME_TYPE_VARIABLE_LIST));
113 116
114 117 if (variables.count() != 1) {
115 118 return false;
116 119 }
117 120 auto variable = variables.first();
118 121
119 122 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
120 123 return graphWidget->canDrop(*variable);
121 124 }
122 125 }
123 126
124 127 return true;
125 128 };
126 129 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
127 130
128 131 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
129 132 &VisualizationZoneWidget::dropMimeData);
130 133 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
131 134 &VisualizationZoneWidget::dropMimeDataOnGraph);
132 135
133 136 // 'Close' options : widget is deleted when closed
134 137 setAttribute(Qt::WA_DeleteOnClose);
135 138 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
136 139 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
137 140
138 141 // Synchronisation id
139 142 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
140 143 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
141 144 }
142 145
143 146 VisualizationZoneWidget::~VisualizationZoneWidget()
144 147 {
145 148 delete ui;
146 149 }
147 150
148 151 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
149 152 {
150 153 // Synchronize new graph with others in the zone
151 154 impl->m_Synchronizer->addGraph(*graphWidget);
152 155
153 156 ui->dragDropContainer->addDragWidget(graphWidget);
154 157 }
155 158
156 159 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
157 160 {
158 161 // Synchronize new graph with others in the zone
159 162 impl->m_Synchronizer->addGraph(*graphWidget);
160 163
161 164 ui->dragDropContainer->insertDragWidget(index, graphWidget);
162 165 }
163 166
164 167 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
165 168 {
166 169 return createGraph(variable, -1);
167 170 }
168 171
169 172 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
170 173 int index)
171 174 {
172 175 auto graphWidget
173 176 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
174 177
175 178
176 179 // Set graph properties
177 180 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
178 181 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
179 182
180 183
181 184 // Lambda to synchronize zone widget
182 185 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
183 186 const SqpRange &oldGraphRange) {
184 187
185 188 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
186 189 auto frameLayout = ui->dragDropContainer->layout();
187 190 for (auto i = 0; i < frameLayout->count(); ++i) {
188 191 auto graphChild
189 192 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
190 193 if (graphChild && (graphChild != graphWidget)) {
191 194
192 195 auto graphChildRange = graphChild->graphRange();
193 196 switch (zoomType) {
194 197 case AcquisitionZoomType::ZoomIn: {
195 198 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
196 199 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
197 200 graphChildRange.m_TStart += deltaLeft;
198 201 graphChildRange.m_TEnd -= deltaRight;
199 202 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
200 203 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
201 204 << deltaLeft;
202 205 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
203 206 << deltaRight;
204 207 qCDebug(LOG_VisualizationZoneWidget())
205 208 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
206 209
207 210 break;
208 211 }
209 212
210 213 case AcquisitionZoomType::ZoomOut: {
211 214 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
212 215 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
213 216 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
214 217 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
215 218 << deltaLeft;
216 219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
217 220 << deltaRight;
218 221 qCDebug(LOG_VisualizationZoneWidget())
219 222 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
220 223 graphChildRange.m_TStart -= deltaLeft;
221 224 graphChildRange.m_TEnd += deltaRight;
222 225 break;
223 226 }
224 227 case AcquisitionZoomType::PanRight: {
225 228 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
226 229 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
227 230 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
228 231 graphChildRange.m_TStart += deltaLeft;
229 232 graphChildRange.m_TEnd += deltaRight;
230 233 qCDebug(LOG_VisualizationZoneWidget())
231 234 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
232 235 break;
233 236 }
234 237 case AcquisitionZoomType::PanLeft: {
235 238 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
236 239 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
237 240 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
238 241 graphChildRange.m_TStart -= deltaLeft;
239 242 graphChildRange.m_TEnd -= deltaRight;
240 243 break;
241 244 }
242 245 case AcquisitionZoomType::Unknown: {
243 246 qCDebug(LOG_VisualizationZoneWidget())
244 247 << tr("Impossible to synchronize: zoom type unknown");
245 248 break;
246 249 }
247 250 default:
248 251 qCCritical(LOG_VisualizationZoneWidget())
249 252 << tr("Impossible to synchronize: zoom type not take into account");
250 253 // No action
251 254 break;
252 255 }
253 256 graphChild->enableAcquisition(false);
254 257 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
255 258 << graphChild->graphRange();
256 259 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
257 260 << graphChildRange;
258 261 qCDebug(LOG_VisualizationZoneWidget())
259 262 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
260 263 graphChild->setGraphRange(graphChildRange);
261 264 graphChild->enableAcquisition(true);
262 265 }
263 266 }
264 267 };
265 268
266 269 // connection for synchronization
267 270 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
268 271 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
269 272 &VisualizationZoneWidget::onVariableAdded);
270 273 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
271 274 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
272 275
273 276 auto range = SqpRange{};
274 277 if (auto firstGraph = this->firstGraph()) {
275 278 // Case of a new graph in a existant zone
276 279 range = firstGraph->graphRange();
277 280 }
278 281 else {
279 282 // Case of a new graph as the first of the zone
280 283 range = variable->range();
281 284 }
282 285
283 286 this->insertGraph(index, graphWidget);
284 287
285 288 graphWidget->addVariable(variable, range);
286 289 graphWidget->setYRange(variable);
287 290
288 291 return graphWidget;
289 292 }
290 293
291 294 VisualizationGraphWidget *
292 295 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
293 296 {
294 297 if (variables.isEmpty()) {
295 298 return nullptr;
296 299 }
297 300
298 301 auto graphWidget = createGraph(variables.first(), index);
299 302 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
300 303 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
301 304 }
302 305
303 306 return graphWidget;
304 307 }
305 308
306 309 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
307 310 {
308 311 VisualizationGraphWidget *firstGraph = nullptr;
309 312 auto layout = ui->dragDropContainer->layout();
310 313 if (layout->count() > 0) {
311 314 if (auto visualizationGraphWidget
312 315 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
313 316 firstGraph = visualizationGraphWidget;
314 317 }
315 318 }
316 319
317 320 return firstGraph;
318 321 }
319 322
320 323 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
321 324 {
322 325 if (visitor) {
323 326 visitor->visitEnter(this);
324 327
325 328 // Apply visitor to graph children: widgets different from graphs are not visited (no
326 329 // action)
327 330 processGraphs(
328 331 *ui->dragDropContainer->layout(),
329 332 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
330 333
331 334 visitor->visitLeave(this);
332 335 }
333 336 else {
334 337 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
335 338 }
336 339 }
337 340
338 341 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
339 342 {
340 343 // A tab can always accomodate a variable
341 344 Q_UNUSED(variable);
342 345 return true;
343 346 }
344 347
345 348 bool VisualizationZoneWidget::contains(const Variable &variable) const
346 349 {
347 350 Q_UNUSED(variable);
348 351 return false;
349 352 }
350 353
351 354 QString VisualizationZoneWidget::name() const
352 355 {
353 356 return ui->zoneNameLabel->text();
354 357 }
355 358
356 359 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
357 360 {
358 361 Q_UNUSED(position);
359 362
360 363 auto mimeData = new QMimeData;
361 364 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
362 365
363 366 if (auto firstGraph = this->firstGraph()) {
364 367 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
365 368 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
366 369 }
367 370
368 371 return mimeData;
369 372 }
370 373
371 374 bool VisualizationZoneWidget::isDragAllowed() const
372 375 {
373 376 return true;
374 377 }
375 378
376 379 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
377 380 const QPointF &plotPosition,
378 381 VisualizationGraphWidget *graphWidget)
379 382 {
380 383 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
381 384 VisualizationGraphWidget &processedGraph) {
382 385
383 386 switch (sqpApp->plotsCursorMode()) {
384 387 case SqpApplication::PlotsCursorMode::Vertical:
385 388 processedGraph.removeHorizontalCursor();
386 389 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
387 390 break;
388 391 case SqpApplication::PlotsCursorMode::Temporal:
389 392 processedGraph.addVerticalCursor(plotPosition.x());
390 393 processedGraph.removeHorizontalCursor();
391 394 break;
392 395 case SqpApplication::PlotsCursorMode::Horizontal:
393 396 processedGraph.removeVerticalCursor();
394 397 if (&processedGraph == graphWidget) {
395 398 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
396 399 }
397 400 else {
398 401 processedGraph.removeHorizontalCursor();
399 402 }
400 403 break;
401 404 case SqpApplication::PlotsCursorMode::Cross:
402 405 if (&processedGraph == graphWidget) {
403 406 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
404 407 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
405 408 }
406 409 else {
407 410 processedGraph.removeHorizontalCursor();
408 411 processedGraph.removeVerticalCursor();
409 412 }
410 413 break;
411 414 case SqpApplication::PlotsCursorMode::NoCursor:
412 415 processedGraph.removeHorizontalCursor();
413 416 processedGraph.removeVerticalCursor();
414 417 break;
415 418 }
416 419
417 420
418 421 });
419 422 }
420 423
421 424 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
422 425 {
423 426 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
424 427 processedGraph.removeHorizontalCursor();
425 428 processedGraph.removeVerticalCursor();
426 429 });
427 430 }
428 431
429 432 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
430 433 {
431 434 // Closes graphs in the zone
432 435 processGraphs(*ui->dragDropContainer->layout(),
433 436 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
434 437
435 438 // Delete synchronization group from variable controller
436 439 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
437 440 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
438 441
439 442 QWidget::closeEvent(event);
440 443 }
441 444
442 445 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
443 446 {
444 447 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
445 448 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
446 449 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
447 450 }
448 451
449 452 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
450 453 {
451 454 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
452 455 Q_ARG(std::shared_ptr<Variable>, variable),
453 456 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
454 457 }
455 458
456 459 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
457 460 {
458 461 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
459 462 impl->dropGraph(index, this);
460 463 }
461 464 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
462 465 auto variables = sqpApp->variableController().variablesForMimeData(
463 466 mimeData->data(MIME_TYPE_VARIABLE_LIST));
464 467 impl->dropVariables(variables, index, this);
465 468 }
466 469 else {
467 470 qCWarning(LOG_VisualizationZoneWidget())
468 471 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
469 472 }
470 473 }
471 474
472 475 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
473 476 const QMimeData *mimeData)
474 477 {
475 478 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
476 479 if (!graphWidget) {
477 480 qCWarning(LOG_VisualizationZoneWidget())
478 481 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
479 482 "drop aborted");
480 483 Q_ASSERT(false);
481 484 return;
482 485 }
483 486
484 487 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
485 488 auto variables = sqpApp->variableController().variablesForMimeData(
486 489 mimeData->data(MIME_TYPE_VARIABLE_LIST));
487 490 for (const auto &var : variables) {
488 491 graphWidget->addVariable(var, graphWidget->graphRange());
489 492 }
490 493 }
491 494 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
492 495 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
493 496 graphWidget->setGraphRange(range);
494 497 }
495 498 else {
496 499 qCWarning(LOG_VisualizationZoneWidget())
497 500 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
498 501 }
499 502 }
500 503
501 504 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
502 505 int index, VisualizationZoneWidget *zoneWidget)
503 506 {
504 507 auto &helper = sqpApp->dragDropGuiController();
505 508
506 509 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
507 510 if (!graphWidget) {
508 511 qCWarning(LOG_VisualizationZoneWidget())
509 512 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
510 513 "found or invalid.");
511 514 Q_ASSERT(false);
512 515 return;
513 516 }
514 517
515 518 auto parentDragDropContainer
516 519 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
517 520 if (!parentDragDropContainer) {
518 521 qCWarning(LOG_VisualizationZoneWidget())
519 522 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
520 523 "the dropped graph is not found.");
521 524 Q_ASSERT(false);
522 525 return;
523 526 }
524 527
525 528 const auto &variables = graphWidget->variables();
526 529
527 530 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
528 531 // The drop didn't occur in the same zone
529 532
530 533 // Abort the requests for the variables (if any)
531 534 // Commented, because it's not sure if it's needed or not
532 535 // for (const auto& var : variables)
533 536 //{
534 537 // sqpApp->variableController().onAbortProgressRequested(var);
535 538 //}
536 539
537 540 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
538 541 auto nbGraph = parentDragDropContainer->countDragWidget();
539 542 if (nbGraph == 1) {
540 543 // This is the only graph in the previous zone, close the zone
541 544 helper.delayedCloseWidget(previousParentZoneWidget);
542 545 }
543 546 else {
544 547 // Close the graph
545 548 helper.delayedCloseWidget(graphWidget);
546 549 }
547 550
548 551 // Creates the new graph in the zone
549 552 auto newGraphWidget = zoneWidget->createGraph(variables, index);
550 553 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
551 554 }
552 555 else {
553 556 // The drop occurred in the same zone or the graph is empty
554 557 // Simple move of the graph, no variable operation associated
555 558 parentDragDropContainer->layout()->removeWidget(graphWidget);
556 559
557 560 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
558 561 // The graph is empty and dropped in a different zone.
559 562 // Take the range of the first graph in the zone (if existing).
560 563 auto layout = zoneWidget->ui->dragDropContainer->layout();
561 564 if (layout->count() > 0) {
562 565 if (auto visualizationGraphWidget
563 566 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
564 567 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
565 568 }
566 569 }
567 570 }
568 571
569 572 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
570 573 }
571 574 }
572 575
573 576 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
574 577 const QList<std::shared_ptr<Variable> > &variables, int index,
575 578 VisualizationZoneWidget *zoneWidget)
576 579 {
577 580 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
578 581 // compatible variable here
579 582 if (variables.count() > 1) {
580 583 qCWarning(LOG_VisualizationZoneWidget())
581 584 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
582 585 "aborted.");
583 586 return;
584 587 }
585 588
586 589 zoneWidget->createGraph(variables, index);
587 590 }
General Comments 0
You need to be logged in to leave comments. Login now