#include "Visualization/VisualizationTabWidget.h" #include "Visualization/IVisualizationWidgetVisitor.h" #include "ui_VisualizationTabWidget.h" #include "Visualization/VisualizationZoneWidget.h" #include "Visualization/VisualizationGraphWidget.h" #include "Variable/VariableController.h" #include "SqpApplication.h" #include "DragDropHelper.h" Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget") namespace { /// Generates a default name for a new zone, according to the number of zones already displayed in /// the tab QString defaultZoneName(const QLayout &layout) { auto count = 0; for (auto i = 0; i < layout.count(); ++i) { if (dynamic_cast(layout.itemAt(i)->widget())) { count++; } } return QObject::tr("Zone %1").arg(count + 1); } /** * Applies a function to all zones of the tab represented by its layout * @param layout the layout that contains zones * @param fun the function to apply to each zone */ template void processZones(QLayout &layout, Fun fun) { for (auto i = 0; i < layout.count(); ++i) { if (auto item = layout.itemAt(i)) { if (auto visualizationZoneWidget = dynamic_cast(item->widget())) { fun(*visualizationZoneWidget); } } } } } // namespace struct VisualizationTabWidget::VisualizationTabWidgetPrivate { explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {} QString m_Name; }; VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent) : QWidget{parent}, ui{new Ui::VisualizationTabWidget}, impl{spimpl::make_unique_impl(name)} { ui->setupUi(this); ui->dragDropContainer->setAcceptedMimeTypes({DragDropHelper::MIME_TYPE_GRAPH, DragDropHelper::MIME_TYPE_ZONE}); connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this, &VisualizationTabWidget::dropMimeData); sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea); // Widget is deleted when closed setAttribute(Qt::WA_DeleteOnClose); } VisualizationTabWidget::~VisualizationTabWidget() { sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea); delete ui; } void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget) { ui->dragDropContainer->addDragWidget(zoneWidget); } void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget) { ui->dragDropContainer->insertDragWidget(index, zoneWidget); } VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr variable) { return createZone({variable}, -1); } VisualizationZoneWidget *VisualizationTabWidget::createZone(const QList > &variables, int index) { auto zoneWidget = createEmptyZone(index); // Creates a new graph into the zone zoneWidget->createGraph(variables, index); return zoneWidget; } VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index) { auto zoneWidget = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this}; this->insertZone(index, zoneWidget); return zoneWidget; } void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor) { if (visitor) { visitor->visitEnter(this); // Apply visitor to zone children: widgets different from zones are not visited (no action) processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) { zoneWidget.accept(visitor); }); visitor->visitLeave(this); } else { qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null"); } } bool VisualizationTabWidget::canDrop(const Variable &variable) const { // A tab can always accomodate a variable Q_UNUSED(variable); return true; } bool VisualizationTabWidget::contains(const Variable &variable) const { Q_UNUSED(variable); return false; } QString VisualizationTabWidget::name() const { return impl->m_Name; } void VisualizationTabWidget::closeEvent(QCloseEvent *event) { // Closes zones in the tab processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); }); QWidget::closeEvent(event); } QLayout &VisualizationTabWidget::tabLayout() const noexcept { return *ui->dragDropContainer->layout(); } void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData) { auto& helper = sqpApp->dragDropHelper(); if (mimeData->hasFormat(DragDropHelper::MIME_TYPE_GRAPH)) { auto graphWidget = static_cast(helper.getCurrentDragWidget()); auto parentDragDropContainer = qobject_cast(graphWidget->parentWidget()); Q_ASSERT(parentDragDropContainer); auto nbGraph = parentDragDropContainer->countDragWidget(); const auto& variables = graphWidget->variables(); if (!variables.isEmpty()) { //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); //} if (nbGraph == 1) { //This is the only graph in the previous zone, close the zone graphWidget->parentZoneWidget()->close(); } else { //Close the graph graphWidget->close(); } createZone(variables, index); } else { //The graph is empty, create an empty zone and move the graph inside auto parentZoneWidget = graphWidget->parentZoneWidget(); parentDragDropContainer->layout()->removeWidget(graphWidget); auto zoneWidget = createEmptyZone(index); zoneWidget->addGraph(graphWidget); //Close the old zone if it was the only graph inside if (nbGraph == 1) parentZoneWidget->close(); } } else if (mimeData->hasFormat(DragDropHelper::MIME_TYPE_ZONE)) { //Simple move of the zone, no variable operation associated auto zoneWidget = static_cast(helper.getCurrentDragWidget()); auto parentDragDropContainer = zoneWidget->parentWidget(); parentDragDropContainer->layout()->removeWidget(zoneWidget); ui->dragDropContainer->insertDragWidget(index, zoneWidget); } }