##// END OF EJS Templates
Move Common MIME types constants in a Definition file in core module.
trabillard -
r850:3715d1ed451c
parent child
Show More
@@ -0,0 +1,18
1 #ifndef SCIQLOP_MIMETYPESDEF_H
2 #define SCIQLOP_MIMETYPESDEF_H
3
4 #include "CoreGlobal.h"
5
6 #include <QString>
7
8 // ////////////////// //
9 // SciQlop Mime Types //
10 // ////////////////// //
11
12 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH;
13 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
16
17
18 #endif // SCIQLOP_MIMETYPESDEF_H
@@ -0,0 +1,6
1 #include "Common/MimeTypesDef.h"
2
3 const QString MIME_TYPE_GRAPH = QStringLiteral("scqlop/graph");
4 const QString MIME_TYPE_ZONE = QStringLiteral("scqlop/zone");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("scqlop/var-list");
6 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("scqlop/time-range");
@@ -1,230 +1,227
1 1 #include "DragDropHelper.h"
2 2 #include "SqpApplication.h"
3 3 #include "Visualization/VisualizationDragWidget.h"
4 4
5 5 #include <QDir>
6 6 #include <QDragEnterEvent>
7 7 #include <QDragMoveEvent>
8 8 #include <QScrollArea>
9 9 #include <QScrollBar>
10 10 #include <QTimer>
11 11 #include <QVBoxLayout>
12 12
13 const QString DragDropHelper::MIME_TYPE_GRAPH = "scqlop/graph";
14 const QString DragDropHelper::MIME_TYPE_ZONE = "scqlop/zone";
15
16 13 const int SCROLL_SPEED = 5;
17 14 const int SCROLL_ZONE_SIZE = 50;
18 15
19 16 struct DragDropScroller::DragDropScrollerPrivate {
20 17
21 18 QList<QScrollArea *> m_ScrollAreas;
22 19 QScrollArea *m_CurrentScrollArea = nullptr;
23 20 std::unique_ptr<QTimer> m_Timer = nullptr;
24 21
25 22
26 23 enum class ScrollDirection { up, down, unknown };
27 24 ScrollDirection m_Direction = ScrollDirection::unknown;
28 25
29 26 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
30 27 {
31 28 m_Timer->setInterval(0);
32 29 }
33 30 };
34 31
35 32 DragDropScroller::DragDropScroller(QObject *parent)
36 33 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
37 34 {
38 35 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
39 36 }
40 37
41 38 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
42 39 {
43 40 impl->m_ScrollAreas << scrollArea;
44 41 scrollArea->viewport()->setAcceptDrops(true);
45 42 }
46 43
47 44 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
48 45 {
49 46 impl->m_ScrollAreas.removeAll(scrollArea);
50 47 scrollArea->viewport()->setAcceptDrops(false);
51 48 }
52 49
53 50 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
54 51 {
55 52 if (event->type() == QEvent::DragMove) {
56 53 auto w = static_cast<QWidget *>(obj);
57 54
58 55 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
59 56 auto moveEvent = static_cast<QDragMoveEvent *>(event);
60 57
61 58 auto pos = moveEvent->pos();
62 59 if (impl->m_CurrentScrollArea->viewport() != w) {
63 60 auto globalPos = w->mapToGlobal(moveEvent->pos());
64 61 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
65 62 }
66 63
67 64 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
68 65 - SCROLL_ZONE_SIZE;
69 66 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
70 67
71 68 if (!isInTopZone && !isInBottomZone) {
72 69 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
73 70 impl->m_Timer->stop();
74 71 }
75 72 else if (!impl->m_Timer->isActive()) {
76 73 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
77 74 : DragDropScrollerPrivate::ScrollDirection::down;
78 75 impl->m_Timer->start();
79 76 }
80 77 }
81 78 }
82 79 else if (event->type() == QEvent::DragEnter) {
83 80 auto w = static_cast<QWidget *>(obj);
84 81
85 82 for (auto scrollArea : impl->m_ScrollAreas) {
86 83 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
87 84 auto enterEvent = static_cast<QDragEnterEvent *>(event);
88 85 enterEvent->acceptProposedAction();
89 86 enterEvent->setDropAction(Qt::IgnoreAction);
90 87 impl->m_CurrentScrollArea = scrollArea;
91 88 break;
92 89 }
93 90 }
94 91 }
95 92 else if (event->type() == QEvent::DragLeave) {
96 93 if (impl->m_CurrentScrollArea) {
97 94 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
98 95 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
99 96 impl->m_CurrentScrollArea = nullptr;
100 97 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
101 98 impl->m_Timer->stop();
102 99 }
103 100 }
104 101 }
105 102 else if (event->type() == QEvent::Drop) {
106 103 if (impl->m_CurrentScrollArea) {
107 104 impl->m_CurrentScrollArea = nullptr;
108 105 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
109 106 impl->m_Timer->stop();
110 107 }
111 108 }
112 109
113 110 return false;
114 111 }
115 112
116 113 void DragDropScroller::onTimer()
117 114 {
118 115 if (impl->m_CurrentScrollArea) {
119 116 auto mvt = 0;
120 117 switch (impl->m_Direction) {
121 118 case DragDropScrollerPrivate::ScrollDirection::up:
122 119 mvt = SCROLL_SPEED;
123 120 break;
124 121 case DragDropScrollerPrivate::ScrollDirection::down:
125 122 mvt = -SCROLL_SPEED;
126 123 break;
127 124 default:
128 125 break;
129 126 }
130 127
131 128 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
132 129 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
133 130 }
134 131 }
135 132
136 133 struct DragDropHelper::DragDropHelperPrivate {
137 134
138 135 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
139 136 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
140 137 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
141 138 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
142 139 // QTemporaryFile to have a name which is not generated.
143 140
144 141 explicit DragDropHelperPrivate()
145 142 : m_PlaceHolder{std::make_unique<QWidget>()},
146 143 m_DragDropScroller{std::make_unique<DragDropScroller>()}
147 144 {
148 145 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
149 146 sqpApp->installEventFilter(m_DragDropScroller.get());
150 147
151 148
152 149 m_ImageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png");
153 150 }
154 151
155 152 void preparePlaceHolder() const
156 153 {
157 154 if (m_CurrentDragWidget) {
158 155 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
159 156 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
160 157 }
161 158 else {
162 159 m_PlaceHolder->setMinimumSize(200, 200);
163 160 }
164 161 }
165 162 };
166 163
167 164
168 165 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
169 166 {
170 167 }
171 168
172 169 DragDropHelper::~DragDropHelper()
173 170 {
174 171 QFile::remove(impl->m_ImageTempUrl);
175 172 }
176 173
177 174 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
178 175 {
179 176 impl->m_CurrentDragWidget = dragWidget;
180 177 }
181 178
182 179 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
183 180 {
184 181 return impl->m_CurrentDragWidget;
185 182 }
186 183
187 184
188 185 QWidget &DragDropHelper::placeHolder() const
189 186 {
190 187 return *impl->m_PlaceHolder;
191 188 }
192 189
193 190 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
194 191 {
195 192 removePlaceHolder();
196 193 impl->preparePlaceHolder();
197 194 layout->insertWidget(index, impl->m_PlaceHolder.get());
198 195 impl->m_PlaceHolder->show();
199 196 }
200 197
201 198 void DragDropHelper::removePlaceHolder()
202 199 {
203 200 auto parentWidget = impl->m_PlaceHolder->parentWidget();
204 201 if (parentWidget) {
205 202 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
206 203 impl->m_PlaceHolder->setParent(nullptr);
207 204 impl->m_PlaceHolder->hide();
208 205 }
209 206 }
210 207
211 208 bool DragDropHelper::isPlaceHolderSet() const
212 209 {
213 210 return impl->m_PlaceHolder->parentWidget();
214 211 }
215 212
216 213 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
217 214 {
218 215 impl->m_DragDropScroller->addScrollArea(scrollArea);
219 216 }
220 217
221 218 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
222 219 {
223 220 impl->m_DragDropScroller->removeScrollArea(scrollArea);
224 221 }
225 222
226 223 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
227 224 {
228 225 image.save(impl->m_ImageTempUrl);
229 226 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
230 227 }
@@ -1,384 +1,385
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 #include <Common/MimeTypesDef.h>
9 10 #include <Data/ArrayData.h>
10 11 #include <Data/IDataSeries.h>
11 12 #include <DragDropHelper.h>
12 13 #include <Settings/SqpSettingsDefs.h>
13 14 #include <SqpApplication.h>
14 15 #include <Variable/Variable.h>
15 16 #include <Variable/VariableController.h>
16 17
17 18 #include <unordered_map>
18 19
19 20 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
20 21
21 22 namespace {
22 23
23 24 /// Key pressed to enable zoom on horizontal axis
24 25 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
25 26
26 27 /// Key pressed to enable zoom on vertical axis
27 28 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
28 29
29 30 } // namespace
30 31
31 32 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
32 33
33 34 explicit VisualizationGraphWidgetPrivate(const QString &name)
34 35 : m_Name{name},
35 36 m_DoAcquisition{true},
36 37 m_IsCalibration{false},
37 38 m_RenderingDelegate{nullptr}
38 39 {
39 40 }
40 41
41 42 QString m_Name;
42 43 // 1 variable -> n qcpplot
43 44 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
44 45 bool m_DoAcquisition;
45 46 bool m_IsCalibration;
46 47 QCPItemTracer *m_TextTracer;
47 48 /// Delegate used to attach rendering features to the plot
48 49 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
49 50 };
50 51
51 52 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
52 53 : VisualizationDragWidget{parent},
53 54 ui{new Ui::VisualizationGraphWidget},
54 55 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
55 56 {
56 57 ui->setupUi(this);
57 58
58 59 // 'Close' options : widget is deleted when closed
59 60 setAttribute(Qt::WA_DeleteOnClose);
60 61
61 62 // Set qcpplot properties :
62 63 // - Drag (on x-axis) and zoom are enabled
63 64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
64 65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
65 66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
66 67
67 68 // The delegate must be initialized after the ui as it uses the plot
68 69 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
69 70
70 71 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
71 72 connect(ui->widget, &QCustomPlot::mouseRelease, this,
72 73 &VisualizationGraphWidget::onMouseRelease);
73 74 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
74 75 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
75 76 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
76 77 &QCPAxis::rangeChanged),
77 78 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
78 79
79 80 // Activates menu when right clicking on the graph
80 81 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
81 82 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
82 83 &VisualizationGraphWidget::onGraphMenuRequested);
83 84
84 85 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
85 86 &VariableController::onRequestDataLoading);
86 87
87 88 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
88 89 &VisualizationGraphWidget::onUpdateVarDisplaying);
89 90 }
90 91
91 92
92 93 VisualizationGraphWidget::~VisualizationGraphWidget()
93 94 {
94 95 delete ui;
95 96 }
96 97
97 98 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
98 99 {
99 100 auto parent = parentWidget();
100 101 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
101 102 parent = parent->parentWidget();
102 103 }
103 104
104 105 return qobject_cast<VisualizationZoneWidget *>(parent);
105 106 }
106 107
107 108 void VisualizationGraphWidget::enableAcquisition(bool enable)
108 109 {
109 110 impl->m_DoAcquisition = enable;
110 111 }
111 112
112 113 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
113 114 {
114 115 // Uses delegate to create the qcpplot components according to the variable
115 116 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
116 117 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
117 118
118 119 // Set axes properties according to the units of the data series
119 120 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
120 121 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
121 122 auto xAxisUnit = Unit{};
122 123 auto valuesUnit = Unit{};
123 124
124 125 if (auto dataSeries = variable->dataSeries()) {
125 126 dataSeries->lockRead();
126 127 xAxisUnit = dataSeries->xAxisUnit();
127 128 valuesUnit = dataSeries->valuesUnit();
128 129 dataSeries->unlock();
129 130 }
130 131 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
131 132
132 133 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
133 134
134 135 this->enableAcquisition(false);
135 136 this->setGraphRange(range);
136 137 this->enableAcquisition(true);
137 138
138 139 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
139 140
140 141 emit variableAdded(variable);
141 142 }
142 143
143 144 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
144 145 {
145 146 // Each component associated to the variable :
146 147 // - is removed from qcpplot (which deletes it)
147 148 // - is no longer referenced in the map
148 149 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
149 150 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
150 151 emit variableAboutToBeRemoved(variable);
151 152
152 153 auto &plottablesMap = variableIt->second;
153 154
154 155 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
155 156 plottableIt != plottableEnd;) {
156 157 ui->widget->removePlottable(plottableIt->second);
157 158 plottableIt = plottablesMap.erase(plottableIt);
158 159 }
159 160
160 161 impl->m_VariableToPlotMultiMap.erase(variableIt);
161 162 }
162 163
163 164 // Updates graph
164 165 ui->widget->replot();
165 166 }
166 167
167 168 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
168 169 {
169 170 auto variables = QList<std::shared_ptr<Variable> >{};
170 171 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
171 172 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
172 173 variables << it->first;
173 174 }
174 175
175 176 return variables;
176 177 }
177 178
178 179 void VisualizationGraphWidget::setYRange(const SqpRange &range)
179 180 {
180 181 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
181 182 }
182 183
183 184 SqpRange VisualizationGraphWidget::graphRange() const noexcept
184 185 {
185 186 auto graphRange = ui->widget->xAxis->range();
186 187 return SqpRange{graphRange.lower, graphRange.upper};
187 188 }
188 189
189 190 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
190 191 {
191 192 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
192 193 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
193 194 ui->widget->replot();
194 195 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
195 196 }
196 197
197 198 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
198 199 {
199 200 if (visitor) {
200 201 visitor->visit(this);
201 202 }
202 203 else {
203 204 qCCritical(LOG_VisualizationGraphWidget())
204 205 << tr("Can't visit widget : the visitor is null");
205 206 }
206 207 }
207 208
208 209 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
209 210 {
210 211 /// @todo : for the moment, a graph can always accomodate a variable
211 212 Q_UNUSED(variable);
212 213 return true;
213 214 }
214 215
215 216 bool VisualizationGraphWidget::contains(const Variable &variable) const
216 217 {
217 218 // Finds the variable among the keys of the map
218 219 auto variablePtr = &variable;
219 220 auto findVariable
220 221 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
221 222
222 223 auto end = impl->m_VariableToPlotMultiMap.cend();
223 224 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
224 225 return it != end;
225 226 }
226 227
227 228 QString VisualizationGraphWidget::name() const
228 229 {
229 230 return impl->m_Name;
230 231 }
231 232
232 233 QMimeData *VisualizationGraphWidget::mimeData() const
233 234 {
234 235 auto mimeData = new QMimeData;
235 mimeData->setData(DragDropHelper::MIME_TYPE_GRAPH, QByteArray());
236 mimeData->setData(MIME_TYPE_GRAPH, QByteArray());
236 237
237 238 return mimeData;
238 239 }
239 240
240 241 bool VisualizationGraphWidget::isDragAllowed() const
241 242 {
242 243 return true;
243 244 }
244 245
245 246 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
246 247 {
247 248 Q_UNUSED(event);
248 249
249 250 // Prevents that all variables will be removed from graph when it will be closed
250 251 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
251 252 emit variableAboutToBeRemoved(variableEntry.first);
252 253 }
253 254 }
254 255
255 256 void VisualizationGraphWidget::enterEvent(QEvent *event)
256 257 {
257 258 Q_UNUSED(event);
258 259 impl->m_RenderingDelegate->showGraphOverlay(true);
259 260 }
260 261
261 262 void VisualizationGraphWidget::leaveEvent(QEvent *event)
262 263 {
263 264 Q_UNUSED(event);
264 265 impl->m_RenderingDelegate->showGraphOverlay(false);
265 266 }
266 267
267 268 QCustomPlot &VisualizationGraphWidget::plot() noexcept
268 269 {
269 270 return *ui->widget;
270 271 }
271 272
272 273 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
273 274 {
274 275 QMenu graphMenu{};
275 276
276 277 // Iterates on variables (unique keys)
277 278 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
278 279 end = impl->m_VariableToPlotMultiMap.cend();
279 280 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
280 281 // 'Remove variable' action
281 282 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
282 283 [ this, var = it->first ]() { removeVariable(var); });
283 284 }
284 285
285 286 if (!graphMenu.isEmpty()) {
286 287 graphMenu.exec(QCursor::pos());
287 288 }
288 289 }
289 290
290 291 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
291 292 {
292 293 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
293 294 << QThread::currentThread()->objectName() << "DoAcqui"
294 295 << impl->m_DoAcquisition;
295 296
296 297 auto graphRange = SqpRange{t1.lower, t1.upper};
297 298 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
298 299
299 300 if (impl->m_DoAcquisition) {
300 301 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
301 302
302 303 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
303 304 end = impl->m_VariableToPlotMultiMap.end();
304 305 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
305 306 variableUnderGraphVector.push_back(it->first);
306 307 }
307 308 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
308 309 !impl->m_IsCalibration);
309 310
310 311 if (!impl->m_IsCalibration) {
311 312 qCDebug(LOG_VisualizationGraphWidget())
312 313 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
313 314 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
314 315 emit synchronize(graphRange, oldGraphRange);
315 316 }
316 317 }
317 318 }
318 319
319 320 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
320 321 {
321 322 // Handles plot rendering when mouse is moving
322 323 impl->m_RenderingDelegate->onMouseMove(event);
323 324
324 325 VisualizationDragWidget::mouseMoveEvent(event);
325 326 }
326 327
327 328 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
328 329 {
329 330 auto zoomOrientations = QFlags<Qt::Orientation>{};
330 331
331 332 // Lambda that enables a zoom orientation if the key modifier related to this orientation
332 333 // has
333 334 // been pressed
334 335 auto enableOrientation
335 336 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
336 337 auto orientationEnabled = event->modifiers().testFlag(modifier);
337 338 zoomOrientations.setFlag(orientation, orientationEnabled);
338 339 };
339 340 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
340 341 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
341 342
342 343 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
343 344 }
344 345
345 346 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
346 347 {
347 348 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
348 349
349 350 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
350 351
351 352 VisualizationDragWidget::mousePressEvent(event);
352 353 }
353 354
354 355 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
355 356 {
356 357 impl->m_IsCalibration = false;
357 358 }
358 359
359 360 void VisualizationGraphWidget::onDataCacheVariableUpdated()
360 361 {
361 362 auto graphRange = ui->widget->xAxis->range();
362 363 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
363 364
364 365 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
365 366 auto variable = variableEntry.first;
366 367 qCDebug(LOG_VisualizationGraphWidget())
367 368 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
368 369 qCDebug(LOG_VisualizationGraphWidget())
369 370 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
370 371 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
371 372 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
372 373 variable->range());
373 374 }
374 375 }
375 376 }
376 377
377 378 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
378 379 const SqpRange &range)
379 380 {
380 381 auto it = impl->m_VariableToPlotMultiMap.find(variable);
381 382 if (it != impl->m_VariableToPlotMultiMap.end()) {
382 383 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
383 384 }
384 385 }
@@ -1,219 +1,220
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 #include "Common/MimeTypesDef.h"
11
10 12 #include "DragDropHelper.h"
11 13 #include "SqpApplication.h"
12 14
13 15 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
14 16
15 17 namespace {
16 18
17 19 /// Generates a default name for a new zone, according to the number of zones already displayed in
18 20 /// the tab
19 21 QString defaultZoneName(const QLayout &layout)
20 22 {
21 23 auto count = 0;
22 24 for (auto i = 0; i < layout.count(); ++i) {
23 25 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
24 26 count++;
25 27 }
26 28 }
27 29
28 30 return QObject::tr("Zone %1").arg(count + 1);
29 31 }
30 32
31 33 /**
32 34 * Applies a function to all zones of the tab represented by its layout
33 35 * @param layout the layout that contains zones
34 36 * @param fun the function to apply to each zone
35 37 */
36 38 template <typename Fun>
37 39 void processZones(QLayout &layout, Fun fun)
38 40 {
39 41 for (auto i = 0; i < layout.count(); ++i) {
40 42 if (auto item = layout.itemAt(i)) {
41 43 if (auto visualizationZoneWidget
42 44 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
43 45 fun(*visualizationZoneWidget);
44 46 }
45 47 }
46 48 }
47 49 }
48 50
49 51 } // namespace
50 52
51 53 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
52 54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
53 55
54 56 QString m_Name;
55 57 };
56 58
57 59 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
58 60 : QWidget{parent},
59 61 ui{new Ui::VisualizationTabWidget},
60 62 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
61 63 {
62 64 ui->setupUi(this);
63 65
64 ui->dragDropContainer->setAcceptedMimeTypes(
65 {DragDropHelper::MIME_TYPE_GRAPH, DragDropHelper::MIME_TYPE_ZONE});
66 ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH, MIME_TYPE_ZONE});
66 67 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
67 68 &VisualizationTabWidget::dropMimeData);
68 69 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
69 70
70 71 // Widget is deleted when closed
71 72 setAttribute(Qt::WA_DeleteOnClose);
72 73 }
73 74
74 75 VisualizationTabWidget::~VisualizationTabWidget()
75 76 {
76 77 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
77 78 delete ui;
78 79 }
79 80
80 81 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
81 82 {
82 83 ui->dragDropContainer->addDragWidget(zoneWidget);
83 84 }
84 85
85 86 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
86 87 {
87 88 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
88 89 }
89 90
90 91 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
91 92 {
92 93 return createZone({variable}, -1);
93 94 }
94 95
95 96 VisualizationZoneWidget *
96 97 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
97 98 {
98 99 auto zoneWidget = createEmptyZone(index);
99 100
100 101 // Creates a new graph into the zone
101 102 zoneWidget->createGraph(variables, index);
102 103
103 104 return zoneWidget;
104 105 }
105 106
106 107 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
107 108 {
108 109 auto zoneWidget
109 110 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
110 111 this->insertZone(index, zoneWidget);
111 112
112 113 return zoneWidget;
113 114 }
114 115
115 116 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
116 117 {
117 118 if (visitor) {
118 119 visitor->visitEnter(this);
119 120
120 121 // Apply visitor to zone children: widgets different from zones are not visited (no action)
121 122 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
122 123 zoneWidget.accept(visitor);
123 124 });
124 125
125 126 visitor->visitLeave(this);
126 127 }
127 128 else {
128 129 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
129 130 }
130 131 }
131 132
132 133 bool VisualizationTabWidget::canDrop(const Variable &variable) const
133 134 {
134 135 // A tab can always accomodate a variable
135 136 Q_UNUSED(variable);
136 137 return true;
137 138 }
138 139
139 140 bool VisualizationTabWidget::contains(const Variable &variable) const
140 141 {
141 142 Q_UNUSED(variable);
142 143 return false;
143 144 }
144 145
145 146 QString VisualizationTabWidget::name() const
146 147 {
147 148 return impl->m_Name;
148 149 }
149 150
150 151 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
151 152 {
152 153 // Closes zones in the tab
153 154 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
154 155
155 156 QWidget::closeEvent(event);
156 157 }
157 158
158 159 QLayout &VisualizationTabWidget::tabLayout() const noexcept
159 160 {
160 161 return *ui->dragDropContainer->layout();
161 162 }
162 163
163 164 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
164 165 {
165 166 auto &helper = sqpApp->dragDropHelper();
166 if (mimeData->hasFormat(DragDropHelper::MIME_TYPE_GRAPH)) {
167 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
167 168 auto graphWidget = static_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
168 169 auto parentDragDropContainer
169 170 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
170 171 Q_ASSERT(parentDragDropContainer);
171 172
172 173 auto nbGraph = parentDragDropContainer->countDragWidget();
173 174
174 175 const auto &variables = graphWidget->variables();
175 176
176 177 if (!variables.isEmpty()) {
177 178 // Abort the requests for the variables (if any)
178 179 // Commented, because it's not sure if it's needed or not
179 180 // for (const auto& var : variables)
180 181 //{
181 182 // sqpApp->variableController().onAbortProgressRequested(var);
182 183 //}
183 184
184 185 if (nbGraph == 1) {
185 186 // This is the only graph in the previous zone, close the zone
186 187 graphWidget->parentZoneWidget()->close();
187 188 }
188 189 else {
189 190 // Close the graph
190 191 graphWidget->close();
191 192 }
192 193
193 194 createZone(variables, index);
194 195 }
195 196 else {
196 197 // The graph is empty, create an empty zone and move the graph inside
197 198
198 199 auto parentZoneWidget = graphWidget->parentZoneWidget();
199 200
200 201 parentDragDropContainer->layout()->removeWidget(graphWidget);
201 202
202 203 auto zoneWidget = createEmptyZone(index);
203 204 zoneWidget->addGraph(graphWidget);
204 205
205 206 // Close the old zone if it was the only graph inside
206 207 if (nbGraph == 1) {
207 208 parentZoneWidget->close();
208 209 }
209 210 }
210 211 }
211 else if (mimeData->hasFormat(DragDropHelper::MIME_TYPE_ZONE)) {
212 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
212 213 // Simple move of the zone, no variable operation associated
213 214 auto zoneWidget = static_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
214 215 auto parentDragDropContainer = zoneWidget->parentWidget();
215 216 parentDragDropContainer->layout()->removeWidget(zoneWidget);
216 217
217 218 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
218 219 }
219 220 }
@@ -1,410 +1,411
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 "ui_VisualizationZoneWidget.h"
7 7
8 #include "Common/MimeTypesDef.h"
8 9 #include <Data/SqpRange.h>
9 10 #include <Variable/Variable.h>
10 11 #include <Variable/VariableController.h>
11 12
12 13 #include <DragDropHelper.h>
13 14 #include <QUuid>
14 15 #include <SqpApplication.h>
15 16 #include <cmath>
16 17
17 18 #include <QLayout>
18 19
19 20 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
20 21
21 22 namespace {
22 23
23 24 /// Minimum height for graph added in zones (in pixels)
24 25 const auto GRAPH_MINIMUM_HEIGHT = 300;
25 26
26 27 /// Generates a default name for a new graph, according to the number of graphs already displayed in
27 28 /// the zone
28 29 QString defaultGraphName(const QLayout &layout)
29 30 {
30 31 auto count = 0;
31 32 for (auto i = 0; i < layout.count(); ++i) {
32 33 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
33 34 count++;
34 35 }
35 36 }
36 37
37 38 return QObject::tr("Graph %1").arg(count + 1);
38 39 }
39 40
40 41 /**
41 42 * Applies a function to all graphs of the zone represented by its layout
42 43 * @param layout the layout that contains graphs
43 44 * @param fun the function to apply to each graph
44 45 */
45 46 template <typename Fun>
46 47 void processGraphs(QLayout &layout, Fun fun)
47 48 {
48 49 for (auto i = 0; i < layout.count(); ++i) {
49 50 if (auto item = layout.itemAt(i)) {
50 51 if (auto visualizationGraphWidget
51 52 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
52 53 fun(*visualizationGraphWidget);
53 54 }
54 55 }
55 56 }
56 57 }
57 58
58 59 } // namespace
59 60
60 61 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
61 62
62 63 explicit VisualizationZoneWidgetPrivate()
63 64 : m_SynchronisationGroupId{QUuid::createUuid()},
64 65 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
65 66 {
66 67 }
67 68 QUuid m_SynchronisationGroupId;
68 69 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
69 70 };
70 71
71 72 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
72 73 : VisualizationDragWidget{parent},
73 74 ui{new Ui::VisualizationZoneWidget},
74 75 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
75 76 {
76 77 ui->setupUi(this);
77 78
78 79 ui->zoneNameLabel->setText(name);
79 80
80 ui->dragDropContainer->setAcceptedMimeTypes({DragDropHelper::MIME_TYPE_GRAPH});
81 ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH});
81 82 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
82 83 &VisualizationZoneWidget::dropMimeData);
83 84
84 85 // 'Close' options : widget is deleted when closed
85 86 setAttribute(Qt::WA_DeleteOnClose);
86 87 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
87 88 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
88 89
89 90 // Synchronisation id
90 91 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
91 92 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
92 93 }
93 94
94 95 VisualizationZoneWidget::~VisualizationZoneWidget()
95 96 {
96 97 delete ui;
97 98 }
98 99
99 100 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
100 101 {
101 102 // Synchronize new graph with others in the zone
102 103 impl->m_Synchronizer->addGraph(*graphWidget);
103 104
104 105 ui->dragDropContainer->addDragWidget(graphWidget);
105 106 }
106 107
107 108 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
108 109 {
109 110 // Synchronize new graph with others in the zone
110 111 impl->m_Synchronizer->addGraph(*graphWidget);
111 112
112 113 ui->dragDropContainer->insertDragWidget(index, graphWidget);
113 114 }
114 115
115 116 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
116 117 {
117 118 return createGraph(variable, -1);
118 119 }
119 120
120 121 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
121 122 int index)
122 123 {
123 124 auto graphWidget
124 125 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
125 126
126 127
127 128 // Set graph properties
128 129 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
129 130 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
130 131
131 132
132 133 // Lambda to synchronize zone widget
133 134 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
134 135 const SqpRange &oldGraphRange) {
135 136
136 137 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
137 138 auto frameLayout = ui->dragDropContainer->layout();
138 139 for (auto i = 0; i < frameLayout->count(); ++i) {
139 140 auto graphChild
140 141 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
141 142 if (graphChild && (graphChild != graphWidget)) {
142 143
143 144 auto graphChildRange = graphChild->graphRange();
144 145 switch (zoomType) {
145 146 case AcquisitionZoomType::ZoomIn: {
146 147 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
147 148 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
148 149 graphChildRange.m_TStart += deltaLeft;
149 150 graphChildRange.m_TEnd -= deltaRight;
150 151 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
151 152 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
152 153 << deltaLeft;
153 154 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
154 155 << deltaRight;
155 156 qCDebug(LOG_VisualizationZoneWidget())
156 157 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
157 158
158 159 break;
159 160 }
160 161
161 162 case AcquisitionZoomType::ZoomOut: {
162 163 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
163 164 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
164 165 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
165 166 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
166 167 << deltaLeft;
167 168 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
168 169 << deltaRight;
169 170 qCDebug(LOG_VisualizationZoneWidget())
170 171 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
171 172 graphChildRange.m_TStart -= deltaLeft;
172 173 graphChildRange.m_TEnd += deltaRight;
173 174 break;
174 175 }
175 176 case AcquisitionZoomType::PanRight: {
176 177 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
177 178 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
178 179 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
179 180 graphChildRange.m_TStart += deltaLeft;
180 181 graphChildRange.m_TEnd += deltaRight;
181 182 qCDebug(LOG_VisualizationZoneWidget())
182 183 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
183 184 break;
184 185 }
185 186 case AcquisitionZoomType::PanLeft: {
186 187 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
187 188 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
188 189 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
189 190 graphChildRange.m_TStart -= deltaLeft;
190 191 graphChildRange.m_TEnd -= deltaRight;
191 192 break;
192 193 }
193 194 case AcquisitionZoomType::Unknown: {
194 195 qCDebug(LOG_VisualizationZoneWidget())
195 196 << tr("Impossible to synchronize: zoom type unknown");
196 197 break;
197 198 }
198 199 default:
199 200 qCCritical(LOG_VisualizationZoneWidget())
200 201 << tr("Impossible to synchronize: zoom type not take into account");
201 202 // No action
202 203 break;
203 204 }
204 205 graphChild->enableAcquisition(false);
205 206 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
206 207 << graphChild->graphRange();
207 208 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
208 209 << graphChildRange;
209 210 qCDebug(LOG_VisualizationZoneWidget())
210 211 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
211 212 graphChild->setGraphRange(graphChildRange);
212 213 graphChild->enableAcquisition(true);
213 214 }
214 215 }
215 216 };
216 217
217 218 // connection for synchronization
218 219 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
219 220 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
220 221 &VisualizationZoneWidget::onVariableAdded);
221 222 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
222 223 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
223 224
224 225 auto range = SqpRange{};
225 226
226 227 // Apply visitor to graph children
227 228 auto layout = ui->dragDropContainer->layout();
228 229 if (layout->count() > 0) {
229 230 // Case of a new graph in a existant zone
230 231 if (auto visualizationGraphWidget
231 232 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
232 233 range = visualizationGraphWidget->graphRange();
233 234 }
234 235 }
235 236 else {
236 237 // Case of a new graph as the first of the zone
237 238 range = variable->range();
238 239 }
239 240
240 241 this->insertGraph(index, graphWidget);
241 242
242 243 graphWidget->addVariable(variable, range);
243 244
244 245 // get y using variable range
245 246 if (auto dataSeries = variable->dataSeries()) {
246 247 dataSeries->lockRead();
247 248 auto valuesBounds
248 249 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
249 250 auto end = dataSeries->cend();
250 251 if (valuesBounds.first != end && valuesBounds.second != end) {
251 252 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
252 253
253 254 auto minValue = rangeValue(valuesBounds.first->minValue());
254 255 auto maxValue = rangeValue(valuesBounds.second->maxValue());
255 256
256 257 graphWidget->setYRange(SqpRange{minValue, maxValue});
257 258 }
258 259 dataSeries->unlock();
259 260 }
260 261
261 262 return graphWidget;
262 263 }
263 264
264 265 VisualizationGraphWidget *
265 266 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
266 267 {
267 268 if (variables.isEmpty()) {
268 269 return nullptr;
269 270 }
270 271
271 272 auto graphWidget = createGraph(variables.first(), index);
272 273 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
273 274 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
274 275 }
275 276
276 277 return graphWidget;
277 278 }
278 279
279 280 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
280 281 {
281 282 if (visitor) {
282 283 visitor->visitEnter(this);
283 284
284 285 // Apply visitor to graph children: widgets different from graphs are not visited (no
285 286 // action)
286 287 processGraphs(
287 288 *ui->dragDropContainer->layout(),
288 289 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
289 290
290 291 visitor->visitLeave(this);
291 292 }
292 293 else {
293 294 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
294 295 }
295 296 }
296 297
297 298 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
298 299 {
299 300 // A tab can always accomodate a variable
300 301 Q_UNUSED(variable);
301 302 return true;
302 303 }
303 304
304 305 bool VisualizationZoneWidget::contains(const Variable &variable) const
305 306 {
306 307 Q_UNUSED(variable);
307 308 return false;
308 309 }
309 310
310 311 QString VisualizationZoneWidget::name() const
311 312 {
312 313 return ui->zoneNameLabel->text();
313 314 }
314 315
315 316 QMimeData *VisualizationZoneWidget::mimeData() const
316 317 {
317 318 auto mimeData = new QMimeData;
318 mimeData->setData(DragDropHelper::MIME_TYPE_ZONE, QByteArray());
319 mimeData->setData(MIME_TYPE_ZONE, QByteArray());
319 320
320 321 return mimeData;
321 322 }
322 323
323 324 bool VisualizationZoneWidget::isDragAllowed() const
324 325 {
325 326 return true;
326 327 }
327 328
328 329 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
329 330 {
330 331 // Closes graphs in the zone
331 332 processGraphs(*ui->dragDropContainer->layout(),
332 333 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
333 334
334 335 // Delete synchronization group from variable controller
335 336 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
336 337 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
337 338
338 339 QWidget::closeEvent(event);
339 340 }
340 341
341 342 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
342 343 {
343 344 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
344 345 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
345 346 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
346 347 }
347 348
348 349 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
349 350 {
350 351 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
351 352 Q_ARG(std::shared_ptr<Variable>, variable),
352 353 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
353 354 }
354 355
355 356 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
356 357 {
357 358 auto &helper = sqpApp->dragDropHelper();
358 if (mimeData->hasFormat(DragDropHelper::MIME_TYPE_GRAPH)) {
359 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
359 360 auto graphWidget = static_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
360 361 auto parentDragDropContainer
361 362 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
362 363 Q_ASSERT(parentDragDropContainer);
363 364
364 365 const auto &variables = graphWidget->variables();
365 366
366 367 if (parentDragDropContainer != ui->dragDropContainer && !variables.isEmpty()) {
367 368 // The drop didn't occur in the same zone
368 369
369 370 // Abort the requests for the variables (if any)
370 371 // Commented, because it's not sure if it's needed or not
371 372 // for (const auto& var : variables)
372 373 //{
373 374 // sqpApp->variableController().onAbortProgressRequested(var);
374 375 //}
375 376
376 377 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
377 378 auto nbGraph = parentDragDropContainer->countDragWidget();
378 379 if (nbGraph == 1) {
379 380 // This is the only graph in the previous zone, close the zone
380 381 previousParentZoneWidget->close();
381 382 }
382 383 else {
383 384 // Close the graph
384 385 graphWidget->close();
385 386 }
386 387
387 388 // Creates the new graph in the zone
388 389 createGraph(variables, index);
389 390 }
390 391 else {
391 392 // The drop occurred in the same zone or the graph is empty
392 393 // Simple move of the graph, no variable operation associated
393 394 parentDragDropContainer->layout()->removeWidget(graphWidget);
394 395
395 396 if (variables.isEmpty() && parentDragDropContainer != ui->dragDropContainer) {
396 397 // The graph is empty and dropped in a different zone.
397 398 // Take the range of the first graph in the zone (if existing).
398 399 auto layout = ui->dragDropContainer->layout();
399 400 if (layout->count() > 0) {
400 401 if (auto visualizationGraphWidget
401 402 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
402 403 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
403 404 }
404 405 }
405 406 }
406 407
407 408 ui->dragDropContainer->insertDragWidget(index, graphWidget);
408 409 }
409 410 }
410 411 }
General Comments 1
Under Review
author

Auto status change to "Under Review"

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