VisualizationZoneWidget.cpp
629 lines
| 24.0 KiB
| text/x-c
|
CppLexer
r95 | #include "Visualization/VisualizationZoneWidget.h" | |||
r444 | ||||
Alexandre Leroux
|
r207 | #include "Visualization/IVisualizationWidgetVisitor.h" | ||
Alexandre Leroux
|
r730 | #include "Visualization/QCustomPlotSynchronizer.h" | ||
r444 | #include "Visualization/VisualizationGraphWidget.h" | |||
r850 | #include "Visualization/VisualizationWidget.h" | |||
r58 | #include "ui_VisualizationZoneWidget.h" | |||
r848 | #include "Common/MimeTypesDef.h" | |||
r851 | #include "Common/VisualizationDef.h" | |||
r1347 | #include <Data/DateTimeRange.h> | |||
r1348 | #include <Data/DateTimeRangeHelper.h> | |||
r1287 | #include <DataSource/DataSourceController.h> | |||
r878 | #include <Time/TimeController.h> | |||
r548 | #include <Variable/Variable.h> | |||
r1348 | #include <Variable/VariableController2.h> | |||
r118 | ||||
r850 | #include <Visualization/operations/FindVariableOperation.h> | |||
r1075 | #include <DragAndDrop/DragDropGuiController.h> | |||
r539 | #include <QUuid> | |||
Alexandre Leroux
|
r265 | #include <SqpApplication.h> | ||
r621 | #include <cmath> | |||
Alexandre Leroux
|
r265 | |||
r839 | #include <QLayout> | |||
r1347 | #include <QStyle> | |||
r839 | ||||
Alexandre Leroux
|
r219 | Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget") | ||
Alexandre Leroux
|
r200 | namespace { | ||
Alexandre Leroux
|
r738 | /** | ||
* Applies a function to all graphs of the zone represented by its layout | ||||
* @param layout the layout that contains graphs | ||||
* @param fun the function to apply to each graph | ||||
*/ | ||||
template <typename Fun> | ||||
void processGraphs(QLayout &layout, Fun fun) | ||||
{ | ||||
for (auto i = 0; i < layout.count(); ++i) { | ||||
if (auto item = layout.itemAt(i)) { | ||||
if (auto visualizationGraphWidget | ||||
r960 | = qobject_cast<VisualizationGraphWidget *>(item->widget())) { | |||
Alexandre Leroux
|
r738 | fun(*visualizationGraphWidget); | ||
} | ||||
} | ||||
} | ||||
} | ||||
r1137 | /// Generates a default name for a new graph, according to the number of graphs already displayed in | |||
/// the zone | ||||
QString defaultGraphName(QLayout &layout) | ||||
{ | ||||
QSet<QString> existingNames; | ||||
processGraphs( | ||||
layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); }); | ||||
int zoneNum = 1; | ||||
QString name; | ||||
do { | ||||
name = QObject::tr("Graph ").append(QString::number(zoneNum)); | ||||
++zoneNum; | ||||
} while (existingNames.contains(name)); | ||||
return name; | ||||
} | ||||
Alexandre Leroux
|
r200 | } // namespace | ||
r539 | struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate { | |||
Alexandre Leroux
|
r730 | explicit VisualizationZoneWidgetPrivate() | ||
: m_SynchronisationGroupId{QUuid::createUuid()}, | ||||
m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()} | ||||
{ | ||||
} | ||||
r539 | QUuid m_SynchronisationGroupId; | |||
Alexandre Leroux
|
r730 | std::unique_ptr<IGraphSynchronizer> m_Synchronizer; | ||
r850 | ||||
void dropGraph(int index, VisualizationZoneWidget *zoneWidget); | ||||
r1348 | void dropVariables(const std::vector<std::shared_ptr<Variable> > &variables, int index, | |||
r850 | VisualizationZoneWidget *zoneWidget); | |||
r1287 | void dropProducts(const QVariantList &productsData, int index, | |||
VisualizationZoneWidget *zoneWidget); | ||||
r539 | }; | |||
Alexandre Leroux
|
r197 | VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent) | ||
r839 | : VisualizationDragWidget{parent}, | |||
r539 | ui{new Ui::VisualizationZoneWidget}, | |||
impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()} | ||||
r58 | { | |||
ui->setupUi(this); | ||||
Alexandre Leroux
|
r197 | |||
ui->zoneNameLabel->setText(name); | ||||
Alexandre Leroux
|
r265 | |||
r1075 | ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph); | |||
r936 | ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH, | |||
VisualizationDragDropContainer::DropBehavior::Inserted); | ||||
ui->dragDropContainer->setMimeType( | ||||
r879 | MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged); | |||
r1287 | ui->dragDropContainer->setMimeType( | |||
MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged); | ||||
r936 | ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE, | |||
VisualizationDragDropContainer::DropBehavior::Merged); | ||||
ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE, | ||||
VisualizationDragDropContainer::DropBehavior::Forbidden); | ||||
r1047 | ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE, | |||
VisualizationDragDropContainer::DropBehavior::Forbidden); | ||||
r850 | ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) { | |||
r1075 | return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData, | |||
ui->dragDropContainer); | ||||
r850 | }); | |||
r875 | ||||
Alexandre Leroux
|
r1023 | auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) { | ||
if (!mimeData) { | ||||
return false; | ||||
} | ||||
if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) { | ||||
r1348 | auto variables = sqpApp->variableController().variables( | |||
r1350 | Variable::variablesIDs(mimeData->data(MIME_TYPE_VARIABLE_LIST))); | |||
Alexandre Leroux
|
r1023 | |||
r1348 | if (variables.size() != 1) { | |||
Alexandre Leroux
|
r1023 | return false; | ||
} | ||||
r1348 | auto variable = variables.front(); | |||
Alexandre Leroux
|
r1023 | |||
if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) { | ||||
return graphWidget->canDrop(*variable); | ||||
} | ||||
} | ||||
return true; | ||||
}; | ||||
ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun); | ||||
r875 | connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this, | |||
r844 | &VisualizationZoneWidget::dropMimeData); | |||
r875 | connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this, | |||
&VisualizationZoneWidget::dropMimeDataOnGraph); | ||||
r839 | ||||
Alexandre Leroux
|
r265 | // 'Close' options : widget is deleted when closed | ||
setAttribute(Qt::WA_DeleteOnClose); | ||||
connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close); | ||||
ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton)); | ||||
r539 | ||||
// Synchronisation id | ||||
QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId", | ||||
Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId)); | ||||
r58 | } | |||
VisualizationZoneWidget::~VisualizationZoneWidget() | ||||
{ | ||||
delete ui; | ||||
} | ||||
r118 | ||||
r1346 | void VisualizationZoneWidget::setZoneRange(const DateTimeRange &range) | |||
r1138 | { | |||
if (auto graph = firstGraph()) { | ||||
graph->setGraphRange(range); | ||||
} | ||||
else { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("setZoneRange:Cannot set the range of an empty zone."); | ||||
} | ||||
} | ||||
r118 | void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget) | |||
{ | ||||
Alexandre Leroux
|
r730 | // Synchronize new graph with others in the zone | ||
impl->m_Synchronizer->addGraph(*graphWidget); | ||||
r839 | ui->dragDropContainer->addDragWidget(graphWidget); | |||
} | ||||
void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget) | ||||
{ | ||||
// Synchronize new graph with others in the zone | ||||
impl->m_Synchronizer->addGraph(*graphWidget); | ||||
ui->dragDropContainer->insertDragWidget(index, graphWidget); | ||||
r118 | } | |||
Alexandre Leroux
|
r200 | VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable) | ||
r839 | { | |||
return createGraph(variable, -1); | ||||
} | ||||
r844 | VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable, | |||
int index) | ||||
r118 | { | |||
r844 | auto graphWidget | |||
= new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this}; | ||||
Alexandre Leroux
|
r307 | |||
r444 | ||||
Alexandre Leroux
|
r307 | // Set graph properties | ||
graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); | ||||
graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT); | ||||
Alexandre Leroux
|
r200 | |||
r444 | // Lambda to synchronize zone widget | |||
r1346 | auto synchronizeZoneWidget = [this, graphWidget](const DateTimeRange &graphRange, | |||
const DateTimeRange &oldGraphRange) { | ||||
r539 | ||||
r1348 | auto zoomType = DateTimeRangeHelper::getTransformationType(oldGraphRange, graphRange); | |||
r839 | auto frameLayout = ui->dragDropContainer->layout(); | |||
r444 | for (auto i = 0; i < frameLayout->count(); ++i) { | |||
auto graphChild | ||||
= dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget()); | ||||
if (graphChild && (graphChild != graphWidget)) { | ||||
auto graphChildRange = graphChild->graphRange(); | ||||
switch (zoomType) { | ||||
r1348 | case TransformationType::ZoomIn: { | |||
r545 | auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart; | |||
auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd; | ||||
r444 | graphChildRange.m_TStart += deltaLeft; | |||
graphChildRange.m_TEnd -= deltaRight; | ||||
break; | ||||
} | ||||
r1348 | case TransformationType::ZoomOut: { | |||
r545 | auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart; | |||
auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd; | ||||
r444 | graphChildRange.m_TStart -= deltaLeft; | |||
graphChildRange.m_TEnd += deltaRight; | ||||
break; | ||||
} | ||||
r1348 | case TransformationType::PanRight: { | |||
r809 | auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart; | |||
r545 | auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd; | |||
r809 | graphChildRange.m_TStart += deltaLeft; | |||
r444 | graphChildRange.m_TEnd += deltaRight; | |||
break; | ||||
} | ||||
r1348 | case TransformationType::PanLeft: { | |||
r545 | auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart; | |||
r809 | auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd; | |||
r444 | graphChildRange.m_TStart -= deltaLeft; | |||
r809 | graphChildRange.m_TEnd -= deltaRight; | |||
r444 | break; | |||
} | ||||
r1348 | case TransformationType::Unknown: { | |||
r444 | break; | |||
} | ||||
default: | ||||
qCCritical(LOG_VisualizationZoneWidget()) | ||||
<< tr("Impossible to synchronize: zoom type not take into account"); | ||||
// No action | ||||
break; | ||||
} | ||||
Alexandre Leroux
|
r1271 | graphChild->setFlags(GraphFlag::DisableAll); | ||
r445 | graphChild->setGraphRange(graphChildRange); | |||
Alexandre Leroux
|
r1271 | graphChild->setFlags(GraphFlag::EnableAll); | ||
r444 | } | |||
} | ||||
}; | ||||
// connection for synchronization | ||||
connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget); | ||||
r540 | connect(graphWidget, &VisualizationGraphWidget::variableAdded, this, | |||
&VisualizationZoneWidget::onVariableAdded); | ||||
Alexandre Leroux
|
r737 | connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this, | ||
&VisualizationZoneWidget::onVariableAboutToBeRemoved); | ||||
r540 | ||||
r1346 | auto range = DateTimeRange{}; | |||
r1048 | if (auto firstGraph = this->firstGraph()) { | |||
r548 | // Case of a new graph in a existant zone | |||
r878 | range = firstGraph->graphRange(); | |||
r548 | } | |||
else { | ||||
// Case of a new graph as the first of the zone | ||||
range = variable->range(); | ||||
} | ||||
r839 | this->insertGraph(index, graphWidget); | |||
r540 | ||||
r548 | graphWidget->addVariable(variable, range); | |||
Alexandre Leroux
|
r900 | graphWidget->setYRange(variable); | ||
r444 | ||||
r118 | return graphWidget; | |||
} | ||||
r844 | VisualizationGraphWidget * | |||
r1348 | VisualizationZoneWidget::createGraph(const std::vector<std::shared_ptr<Variable> > variables, int index) | |||
r839 | { | |||
r1348 | if (variables.empty()) { | |||
r839 | return nullptr; | |||
r844 | } | |||
r839 | ||||
r1348 | auto graphWidget = createGraph(variables.front(), index); | |||
r844 | for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) { | |||
r839 | graphWidget->addVariable(*variableIt, graphWidget->graphRange()); | |||
} | ||||
return graphWidget; | ||||
} | ||||
r1048 | VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const | |||
{ | ||||
VisualizationGraphWidget *firstGraph = nullptr; | ||||
auto layout = ui->dragDropContainer->layout(); | ||||
if (layout->count() > 0) { | ||||
if (auto visualizationGraphWidget | ||||
= qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) { | ||||
firstGraph = visualizationGraphWidget; | ||||
} | ||||
} | ||||
return firstGraph; | ||||
} | ||||
r1307 | void VisualizationZoneWidget::closeAllGraphs() | |||
{ | ||||
processGraphs(*ui->dragDropContainer->layout(), | ||||
[](VisualizationGraphWidget &graphWidget) { graphWidget.close(); }); | ||||
} | ||||
Alexandre Leroux
|
r207 | void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor) | ||
r118 | { | |||
Alexandre Leroux
|
r208 | if (visitor) { | ||
visitor->visitEnter(this); | ||||
Alexandre Leroux
|
r738 | // Apply visitor to graph children: widgets different from graphs are not visited (no | ||
// action) | ||||
processGraphs( | ||||
r839 | *ui->dragDropContainer->layout(), | |||
Alexandre Leroux
|
r738 | [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); }); | ||
Alexandre Leroux
|
r208 | |||
visitor->visitLeave(this); | ||||
} | ||||
Alexandre Leroux
|
r219 | else { | ||
qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null"); | ||||
} | ||||
r118 | } | |||
Alexandre Leroux
|
r209 | bool VisualizationZoneWidget::canDrop(const Variable &variable) const | ||
{ | ||||
// A tab can always accomodate a variable | ||||
Q_UNUSED(variable); | ||||
return true; | ||||
} | ||||
Alexandre Leroux
|
r327 | bool VisualizationZoneWidget::contains(const Variable &variable) const | ||
{ | ||||
Q_UNUSED(variable); | ||||
return false; | ||||
} | ||||
r119 | QString VisualizationZoneWidget::name() const | |||
r118 | { | |||
Alexandre Leroux
|
r197 | return ui->zoneNameLabel->text(); | ||
r118 | } | |||
r540 | ||||
r1047 | QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const | |||
r839 | { | |||
r1047 | Q_UNUSED(position); | |||
r846 | auto mimeData = new QMimeData; | |||
r868 | mimeData->setData(MIME_TYPE_ZONE, QByteArray{}); | |||
r839 | ||||
r1048 | if (auto firstGraph = this->firstGraph()) { | |||
r936 | auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange()); | |||
mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData); | ||||
} | ||||
r839 | return mimeData; | |||
} | ||||
bool VisualizationZoneWidget::isDragAllowed() const | ||||
{ | ||||
return true; | ||||
} | ||||
r960 | void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition, | |||
const QPointF &plotPosition, | ||||
VisualizationGraphWidget *graphWidget) | ||||
{ | ||||
processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget]( | ||||
VisualizationGraphWidget &processedGraph) { | ||||
switch (sqpApp->plotsCursorMode()) { | ||||
case SqpApplication::PlotsCursorMode::Vertical: | ||||
processedGraph.removeHorizontalCursor(); | ||||
processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x()); | ||||
break; | ||||
case SqpApplication::PlotsCursorMode::Temporal: | ||||
processedGraph.addVerticalCursor(plotPosition.x()); | ||||
processedGraph.removeHorizontalCursor(); | ||||
break; | ||||
case SqpApplication::PlotsCursorMode::Horizontal: | ||||
processedGraph.removeVerticalCursor(); | ||||
if (&processedGraph == graphWidget) { | ||||
processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y()); | ||||
} | ||||
else { | ||||
processedGraph.removeHorizontalCursor(); | ||||
} | ||||
break; | ||||
case SqpApplication::PlotsCursorMode::Cross: | ||||
if (&processedGraph == graphWidget) { | ||||
processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x()); | ||||
processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y()); | ||||
} | ||||
else { | ||||
processedGraph.removeHorizontalCursor(); | ||||
processedGraph.removeVerticalCursor(); | ||||
} | ||||
break; | ||||
case SqpApplication::PlotsCursorMode::NoCursor: | ||||
processedGraph.removeHorizontalCursor(); | ||||
processedGraph.removeVerticalCursor(); | ||||
break; | ||||
} | ||||
}); | ||||
} | ||||
void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget) | ||||
{ | ||||
processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) { | ||||
processedGraph.removeHorizontalCursor(); | ||||
processedGraph.removeVerticalCursor(); | ||||
}); | ||||
} | ||||
Alexandre Leroux
|
r738 | void VisualizationZoneWidget::closeEvent(QCloseEvent *event) | ||
{ | ||||
// Closes graphs in the zone | ||||
r839 | processGraphs(*ui->dragDropContainer->layout(), | |||
Alexandre Leroux
|
r738 | [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); }); | ||
Alexandre Leroux
|
r739 | // Delete synchronization group from variable controller | ||
QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId", | ||||
Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId)); | ||||
Alexandre Leroux
|
r738 | QWidget::closeEvent(event); | ||
} | ||||
r540 | void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable) | |||
{ | ||||
QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized", | ||||
Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable), | ||||
Q_ARG(QUuid, impl->m_SynchronisationGroupId)); | ||||
} | ||||
Alexandre Leroux
|
r737 | |||
void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable) | ||||
{ | ||||
QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection, | ||||
Q_ARG(std::shared_ptr<Variable>, variable), | ||||
Q_ARG(QUuid, impl->m_SynchronisationGroupId)); | ||||
} | ||||
r839 | ||||
void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData) | ||||
{ | ||||
r848 | if (mimeData->hasFormat(MIME_TYPE_GRAPH)) { | |||
r850 | impl->dropGraph(index, this); | |||
} | ||||
else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) { | ||||
r1348 | auto variables = sqpApp->variableController().variables( | |||
r1350 | Variable::variablesIDs(mimeData->data(MIME_TYPE_VARIABLE_LIST))); | |||
r850 | impl->dropVariables(variables, index, this); | |||
} | ||||
r1287 | else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) { | |||
auto products = sqpApp->dataSourceController().productsDataForMimeData( | ||||
mimeData->data(MIME_TYPE_PRODUCT_LIST)); | ||||
impl->dropProducts(products, index, this); | ||||
} | ||||
r850 | else { | |||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received."); | ||||
} | ||||
} | ||||
r875 | void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget, | |||
const QMimeData *mimeData) | ||||
{ | ||||
auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget); | ||||
if (!graphWidget) { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, " | ||||
"drop aborted"); | ||||
Q_ASSERT(false); | ||||
return; | ||||
} | ||||
if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) { | ||||
r1348 | auto variables = sqpApp->variableController().variables( | |||
r1350 | Variable::variablesIDs(mimeData->data(MIME_TYPE_VARIABLE_LIST))); | |||
r875 | for (const auto &var : variables) { | |||
graphWidget->addVariable(var, graphWidget->graphRange()); | ||||
} | ||||
} | ||||
r1287 | else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) { | |||
auto products = sqpApp->dataSourceController().productsDataForMimeData( | ||||
mimeData->data(MIME_TYPE_PRODUCT_LIST)); | ||||
r1288 | auto context = new QObject{this}; | |||
r1348 | connect(&sqpApp->variableController(), &VariableController2::variableAdded, context, | |||
r1288 | [this, graphWidget, context](auto variable) { | |||
graphWidget->addVariable(variable, graphWidget->graphRange()); | ||||
delete context; // removes the connection | ||||
}, | ||||
Qt::QueuedConnection); | ||||
r1287 | auto productData = products.first().toHash(); | |||
QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable", | ||||
Qt::QueuedConnection, Q_ARG(QVariantHash, productData)); | ||||
} | ||||
r879 | else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) { | |||
auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE)); | ||||
graphWidget->setGraphRange(range); | ||||
} | ||||
r875 | else { | |||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received."); | ||||
} | ||||
} | ||||
r850 | void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph( | |||
int index, VisualizationZoneWidget *zoneWidget) | ||||
{ | ||||
r1075 | auto &helper = sqpApp->dragDropGuiController(); | |||
r850 | ||||
auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget()); | ||||
if (!graphWidget) { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not " | ||||
"found or invalid."); | ||||
Q_ASSERT(false); | ||||
return; | ||||
} | ||||
auto parentDragDropContainer | ||||
= qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget()); | ||||
if (!parentDragDropContainer) { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of " | ||||
"the dropped graph is not found."); | ||||
Q_ASSERT(false); | ||||
return; | ||||
} | ||||
const auto &variables = graphWidget->variables(); | ||||
r841 | ||||
r1348 | if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.empty()) { | |||
r850 | // The drop didn't occur in the same zone | |||
// Abort the requests for the variables (if any) | ||||
// Commented, because it's not sure if it's needed or not | ||||
// for (const auto& var : variables) | ||||
//{ | ||||
// sqpApp->variableController().onAbortProgressRequested(var); | ||||
//} | ||||
auto previousParentZoneWidget = graphWidget->parentZoneWidget(); | ||||
auto nbGraph = parentDragDropContainer->countDragWidget(); | ||||
if (nbGraph == 1) { | ||||
// This is the only graph in the previous zone, close the zone | ||||
Thibaud Rabillard
|
r911 | helper.delayedCloseWidget(previousParentZoneWidget); | ||
r841 | } | |||
r844 | else { | |||
r850 | // Close the graph | |||
Thibaud Rabillard
|
r911 | helper.delayedCloseWidget(graphWidget); | ||
r850 | } | |||
// Creates the new graph in the zone | ||||
r1048 | auto newGraphWidget = zoneWidget->createGraph(variables, index); | |||
newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges()); | ||||
r850 | } | |||
else { | ||||
// The drop occurred in the same zone or the graph is empty | ||||
// Simple move of the graph, no variable operation associated | ||||
parentDragDropContainer->layout()->removeWidget(graphWidget); | ||||
r1348 | if (variables.empty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) { | |||
r850 | // The graph is empty and dropped in a different zone. | |||
// Take the range of the first graph in the zone (if existing). | ||||
auto layout = zoneWidget->ui->dragDropContainer->layout(); | ||||
if (layout->count() > 0) { | ||||
if (auto visualizationGraphWidget | ||||
= qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) { | ||||
graphWidget->setGraphRange(visualizationGraphWidget->graphRange()); | ||||
r841 | } | |||
} | ||||
r850 | } | |||
zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget); | ||||
} | ||||
} | ||||
void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables( | ||||
r1348 | const std::vector<std::shared_ptr<Variable> > &variables, int index, | |||
r850 | VisualizationZoneWidget *zoneWidget) | |||
{ | ||||
r868 | // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and | |||
// compatible variable here | ||||
r1348 | if (variables.size() > 1) { | |||
r850 | return; | |||
} | ||||
r870 | zoneWidget->createGraph(variables, index); | |||
r839 | } | |||
r1287 | ||||
void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts( | ||||
const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget) | ||||
{ | ||||
// Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and | ||||
// compatible variable here | ||||
if (productsData.count() != 1) { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation " | ||||
"aborted."); | ||||
return; | ||||
} | ||||
r1288 | auto context = new QObject{zoneWidget}; | |||
r1348 | connect(&sqpApp->variableController(), &VariableController2::variableAdded, context, | |||
r1288 | [this, index, zoneWidget, context](auto variable) { | |||
zoneWidget->createGraph(variable, index); | ||||
delete context; // removes the connection | ||||
}, | ||||
Qt::QueuedConnection); | ||||
r1287 | auto productData = productsData.first().toHash(); | |||
QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable", | ||||
Qt::QueuedConnection, Q_ARG(QVariantHash, productData)); | ||||
} | ||||