diff --git a/gui/include/Visualization/VisualizationGraphWidget.h b/gui/include/Visualization/VisualizationGraphWidget.h index c38c375..2343da1 100644 --- a/gui/include/Visualization/VisualizationGraphWidget.h +++ b/gui/include/Visualization/VisualizationGraphWidget.h @@ -16,6 +16,11 @@ class QCPRange; class SqpDateTime; class Variable; +/** + * Possible types of zoom operation + */ +enum class VisualizationGraphWidgetZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown }; + namespace Ui { class VisualizationGraphWidget; } // namespace Ui @@ -27,13 +32,16 @@ public: explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0); virtual ~VisualizationGraphWidget(); + void enableSynchronize(bool enable); + void addVariable(std::shared_ptr variable); void addVariableUsingGraph(std::shared_ptr variable); /// Removes a variable from the graph void removeVariable(std::shared_ptr variable) noexcept; - /// Rescale the X axe to range parameter void setRange(std::shared_ptr variable, const SqpDateTime &range); + SqpDateTime graphRange(); + void setGraphRange(const SqpDateTime &range); // IVisualizationWidget interface void accept(IVisualizationWidgetVisitor *visitor) override; @@ -41,8 +49,11 @@ public: bool contains(const Variable &variable) const override; QString name() const override; + signals: void requestDataLoading(std::shared_ptr variable, const SqpDateTime &dateTime); + void synchronize(const SqpDateTime &dateTime, const SqpDateTime &oldDateTime, + VisualizationGraphWidgetZoomType zoomType); private: @@ -55,7 +66,8 @@ private slots: /// Slot called when right clicking on the graph (displays a menu) void onGraphMenuRequested(const QPoint &pos) noexcept; - void onRangeChanged(const QCPRange &t1); + /// Rescale the X axe to range parameter + void onRangeChanged(const QCPRange &t1, const QCPRange &t2); /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done void onMouseWheel(QWheelEvent *event) noexcept; diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index 490203f..1826ded 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -25,8 +25,12 @@ const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier; struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate { + explicit VisualizationGraphWidgetPrivate() : m_DoSynchronize(true) {} + // 1 variable -> n qcpplot std::multimap, QCPAbstractPlottable *> m_VariableToPlotMultiMap; + + bool m_DoSynchronize; }; VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent) @@ -49,9 +53,9 @@ VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); ui->widget->axisRect()->setRangeDrag(Qt::Horizontal); connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel); - connect(ui->widget->xAxis, - static_cast(&QCPAxis::rangeChanged), this, - &VisualizationGraphWidget::onRangeChanged); + connect(ui->widget->xAxis, static_cast( + &QCPAxis::rangeChanged), + this, &VisualizationGraphWidget::onRangeChanged); // Activates menu when right clicking on the graph ui->widget->setContextMenuPolicy(Qt::CustomContextMenu); @@ -68,6 +72,11 @@ VisualizationGraphWidget::~VisualizationGraphWidget() delete ui; } +void VisualizationGraphWidget::enableSynchronize(bool enable) +{ + impl->m_DoSynchronize = enable; +} + void VisualizationGraphWidget::addVariable(std::shared_ptr variable) { // Uses delegate to create the qcpplot components according to the variable @@ -129,6 +138,22 @@ void VisualizationGraphWidget::setRange(std::shared_ptr variable, // for (auto it = componentsIt.first; it != componentsIt.second;) { // } ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd); + ui->widget->replot(); +} + +SqpDateTime VisualizationGraphWidget::graphRange() +{ + auto grapheRange = ui->widget->xAxis->range(); + return SqpDateTime{grapheRange.lower, grapheRange.upper}; +} + +void VisualizationGraphWidget::setGraphRange(const SqpDateTime &range) +{ + qCDebug(LOG_VisualizationGraphWidget()) + << tr("VisualizationGraphWidget::setGraphRange START"); + ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd); + ui->widget->replot(); + qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END"); } void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor) @@ -184,78 +209,108 @@ void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept } } -void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1) +void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2) { - qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged") - << QThread::currentThread()->objectName(); + qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged") + << QThread::currentThread()->objectName(); + + auto dateTimeRange = SqpDateTime{t1.lower, t1.upper}; + auto zoomType = VisualizationGraphWidgetZoomType::ZoomOut; for (auto it = impl->m_VariableToPlotMultiMap.cbegin(); it != impl->m_VariableToPlotMultiMap.cend(); ++it) { auto variable = it->first; - auto dateTime = SqpDateTime{t1.lower, t1.upper}; - auto dateTimeRange = dateTime; + auto currentDateTime = dateTimeRange; auto toleranceFactor = 0.2; - auto tolerance = toleranceFactor * (dateTime.m_TEnd - dateTime.m_TStart); - auto variableDateTimeWithTolerance = dateTime; + auto tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart); + auto variableDateTimeWithTolerance = currentDateTime; variableDateTimeWithTolerance.m_TStart -= tolerance; variableDateTimeWithTolerance.m_TEnd += tolerance; - qCDebug(LOG_VisualizationGraphWidget()) << "v" << dateTime; - qCDebug(LOG_VisualizationGraphWidget()) << "vtol" << variableDateTimeWithTolerance; + qCDebug(LOG_VisualizationGraphWidget()) << "r" << currentDateTime; + qCDebug(LOG_VisualizationGraphWidget()) << "t" << variableDateTimeWithTolerance; + qCDebug(LOG_VisualizationGraphWidget()) << "v" << variable->dateTime(); // If new range with tol is upper than variable datetime parameters. we need to request new // data if (!variable->contains(variableDateTimeWithTolerance)) { - auto variableDateTimeWithTolerance = dateTime; - if (!variable->isInside(dateTime)) { + auto variableDateTimeWithTolerance = currentDateTime; + if (!variable->isInside(currentDateTime)) { auto variableDateTime = variable->dateTime(); - if (variableDateTime.m_TStart < dateTime.m_TStart) { - qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:"); + if (variable->contains(variableDateTimeWithTolerance)) { + qCInfo(LOG_VisualizationGraphWidget()) + << tr("TORM: Detection zoom in that need request:"); + // add 10% tolerance for each side + tolerance + = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart); + variableDateTimeWithTolerance.m_TStart -= tolerance; + variableDateTimeWithTolerance.m_TEnd += tolerance; + zoomType = VisualizationGraphWidgetZoomType::ZoomIn; + } + else if (variableDateTime.m_TStart < currentDateTime.m_TStart) { + qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:"); - auto diffEndToKeepDelta = dateTime.m_TEnd - variableDateTime.m_TEnd; - dateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta; + auto diffEndToKeepDelta = currentDateTime.m_TEnd - variableDateTime.m_TEnd; + currentDateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta; // Tolerance have to be added to the right // add tolerance for right (end) side - tolerance = toleranceFactor * (dateTime.m_TEnd - dateTime.m_TStart); + tolerance + = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart); variableDateTimeWithTolerance.m_TEnd += tolerance; + zoomType = VisualizationGraphWidgetZoomType::PanRight; } - else if (variableDateTime.m_TEnd > dateTime.m_TEnd) { - qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: "); - auto diffStartToKeepDelta = variableDateTime.m_TStart - dateTime.m_TStart; - dateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta; + else if (variableDateTime.m_TEnd > currentDateTime.m_TEnd) { + qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: "); + auto diffStartToKeepDelta + = variableDateTime.m_TStart - currentDateTime.m_TStart; + currentDateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta; // Tolerance have to be added to the left // add tolerance for left (start) side - tolerance = toleranceFactor * (dateTime.m_TEnd - dateTime.m_TStart); + tolerance + = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart); variableDateTimeWithTolerance.m_TStart -= tolerance; + zoomType = VisualizationGraphWidgetZoomType::PanLeft; } else { - qCDebug(LOG_VisualizationGraphWidget()) + qCInfo(LOG_VisualizationGraphWidget()) << tr("Detection anormal zoom detection: "); + zoomType = VisualizationGraphWidgetZoomType::Unknown; } } else { - qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection zoom out: "); + qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection zoom out: "); // add 10% tolerance for each side - tolerance = 0.2 * (dateTime.m_TEnd - dateTime.m_TStart); + tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart); variableDateTimeWithTolerance.m_TStart -= tolerance; variableDateTimeWithTolerance.m_TEnd += tolerance; + zoomType = VisualizationGraphWidgetZoomType::ZoomOut; } if (!variable->contains(dateTimeRange)) { - qCDebug(LOG_VisualizationGraphWidget()) - << "TORM: Modif on variable datetime detected" << dateTime; - variable->setDateTime(dateTime); + qCInfo(LOG_VisualizationGraphWidget()) + << "TORM: Modif on variable datetime detected" << currentDateTime; + variable->setDateTime(currentDateTime); } - qCDebug(LOG_VisualizationGraphWidget()) << tr("Request data detection: "); + qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Request data detection: "); // CHangement detected, we need to ask controller to request data loading emit requestDataLoading(variable, variableDateTimeWithTolerance); } else { - qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection zoom in: "); + qCInfo(LOG_VisualizationGraphWidget()) + << tr("TORM: Detection zoom in that doesn't need request: "); + zoomType = VisualizationGraphWidgetZoomType::ZoomIn; } } + + if (impl->m_DoSynchronize) { + auto oldDateTime = SqpDateTime{t2.lower, t2.upper}; + qCDebug(LOG_VisualizationGraphWidget()) + << tr("TORM: VisualizationGraphWidget::Synchronize notify !!") + << QThread::currentThread()->objectName(); + emit synchronize(dateTimeRange, oldDateTime, zoomType); + } } void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept diff --git a/gui/src/Visualization/VisualizationZoneWidget.cpp b/gui/src/Visualization/VisualizationZoneWidget.cpp index 355dbf4..5351a62 100644 --- a/gui/src/Visualization/VisualizationZoneWidget.cpp +++ b/gui/src/Visualization/VisualizationZoneWidget.cpp @@ -1,8 +1,11 @@ #include "Visualization/VisualizationZoneWidget.h" + +#include "Data/SqpDateTime.h" + #include "Visualization/IVisualizationWidgetVisitor.h" +#include "Visualization/VisualizationGraphWidget.h" #include "ui_VisualizationZoneWidget.h" -#include "Visualization/VisualizationGraphWidget.h" #include @@ -57,6 +60,7 @@ VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptrvisualizationZoneFrame->layout()), this}; + // Set graph properties graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT); @@ -65,6 +69,71 @@ VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptraddVariable(variable); + // Lambda to synchronize zone widget + auto synchronizeZoneWidget = [this, graphWidget](const SqpDateTime &dateTime, + const SqpDateTime &oldDateTime, + VisualizationGraphWidgetZoomType zoomType) { + auto frameLayout = ui->visualizationZoneFrame->layout(); + for (auto i = 0; i < frameLayout->count(); ++i) { + auto graphChild + = dynamic_cast(frameLayout->itemAt(i)->widget()); + if (graphChild && (graphChild != graphWidget)) { + + auto dateTimeThatKeepDelta = dateTime; + auto graphChildRange = graphChild->graphRange(); + switch (zoomType) { + case VisualizationGraphWidgetZoomType::ZoomIn: { + auto deltaLeft = dateTime.m_TStart - oldDateTime.m_TStart; + auto deltaRight = oldDateTime.m_TEnd - dateTime.m_TEnd; + graphChildRange.m_TStart += deltaLeft; + graphChildRange.m_TEnd -= deltaRight; + dateTimeThatKeepDelta = graphChildRange; + break; + } + + case VisualizationGraphWidgetZoomType::ZoomOut: { + auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart; + auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd; + graphChildRange.m_TStart -= deltaLeft; + graphChildRange.m_TEnd += deltaRight; + dateTimeThatKeepDelta = graphChildRange; + break; + } + case VisualizationGraphWidgetZoomType::PanRight: { + auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd; + graphChildRange.m_TStart += deltaRight; + graphChildRange.m_TEnd += deltaRight; + dateTimeThatKeepDelta = graphChildRange; + break; + } + case VisualizationGraphWidgetZoomType::PanLeft: { + auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart; + graphChildRange.m_TStart -= deltaLeft; + graphChildRange.m_TEnd -= deltaLeft; + dateTimeThatKeepDelta = graphChildRange; + break; + } + case VisualizationGraphWidgetZoomType::Unknown: { + qCCritical(LOG_VisualizationZoneWidget()) + << tr("Impossible to synchronize: zoom type unknown"); + break; + } + default: + qCCritical(LOG_VisualizationZoneWidget()) + << tr("Impossible to synchronize: zoom type not take into account"); + // No action + break; + } + graphChild->enableSynchronize(false); + graphChild->setGraphRange(dateTimeThatKeepDelta); + graphChild->enableSynchronize(true); + } + } + }; + + // connection for synchronization + connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget); + return graphWidget; }