VisualizationTabWidget.cpp
309 lines
| 9.9 KiB
| text/x-c
|
CppLexer
r95 | #include "Visualization/VisualizationTabWidget.h" | |||
Alexandre Leroux
|
r207 | #include "Visualization/IVisualizationWidgetVisitor.h" | ||
r58 | #include "ui_VisualizationTabWidget.h" | |||
r842 | #include "Visualization/VisualizationGraphWidget.h" | |||
r847 | #include "Visualization/VisualizationZoneWidget.h" | |||
r842 | ||||
r844 | #include "Variable/VariableController.h" | |||
r850 | #include "Common/MimeTypesDef.h" | |||
r890 | #include "DragAndDrop/DragDropHelper.h" | |||
r847 | #include "SqpApplication.h" | |||
r118 | ||||
Alexandre Leroux
|
r219 | Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget") | ||
Alexandre Leroux
|
r201 | 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<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) { | ||||
count++; | ||||
} | ||||
} | ||||
return QObject::tr("Zone %1").arg(count + 1); | ||||
} | ||||
Alexandre Leroux
|
r738 | /** | ||
* 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 <typename Fun> | ||||
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<VisualizationZoneWidget *>(item->widget())) { | ||||
fun(*visualizationZoneWidget); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
Alexandre Leroux
|
r201 | } // namespace | ||
Alexandre Leroux
|
r198 | struct VisualizationTabWidget::VisualizationTabWidgetPrivate { | ||
explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {} | ||||
r118 | ||||
Alexandre Leroux
|
r198 | QString m_Name; | ||
r852 | ||||
void dropGraph(int index, VisualizationTabWidget *tabWidget); | ||||
void dropZone(int index, VisualizationTabWidget *tabWidget); | ||||
void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index, | ||||
VisualizationTabWidget *tabWidget); | ||||
Alexandre Leroux
|
r198 | }; | ||
VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent) | ||||
: QWidget{parent}, | ||||
ui{new Ui::VisualizationTabWidget}, | ||||
impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)} | ||||
r58 | { | |||
ui->setupUi(this); | ||||
Alexandre Leroux
|
r267 | |||
r887 | ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Zone, "Zone"); | |||
ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 5); | ||||
r885 | ui->dragDropContainer->addAcceptedMimeType( | |||
MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted); | ||||
ui->dragDropContainer->addAcceptedMimeType( | ||||
MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted); | ||||
ui->dragDropContainer->addAcceptedMimeType( | ||||
MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted); | ||||
r852 | ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) { | |||
return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData, | ||||
ui->dragDropContainer); | ||||
}); | ||||
r885 | ||||
connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this, | ||||
&VisualizationTabWidget::dropMimeData); | ||||
r843 | sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea); | |||
r842 | ||||
Alexandre Leroux
|
r267 | // Widget is deleted when closed | ||
setAttribute(Qt::WA_DeleteOnClose); | ||||
r58 | } | |||
VisualizationTabWidget::~VisualizationTabWidget() | ||||
{ | ||||
r843 | sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea); | |||
r58 | delete ui; | |||
} | ||||
r118 | ||||
void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget) | ||||
{ | ||||
r842 | ui->dragDropContainer->addDragWidget(zoneWidget); | |||
} | ||||
void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget) | ||||
{ | ||||
r847 | ui->dragDropContainer->insertDragWidget(index, zoneWidget); | |||
r118 | } | |||
Alexandre Leroux
|
r201 | VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable) | ||
r118 | { | |||
r842 | return createZone({variable}, -1); | |||
} | ||||
r847 | VisualizationZoneWidget * | |||
VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index) | ||||
r842 | { | |||
r844 | auto zoneWidget = createEmptyZone(index); | |||
r118 | ||||
Alexandre Leroux
|
r201 | // Creates a new graph into the zone | ||
r842 | zoneWidget->createGraph(variables, index); | |||
Alexandre Leroux
|
r201 | |||
r118 | return zoneWidget; | |||
} | ||||
r844 | VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index) | |||
{ | ||||
r847 | auto zoneWidget | |||
= new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this}; | ||||
r844 | this->insertZone(index, zoneWidget); | |||
return zoneWidget; | ||||
} | ||||
Alexandre Leroux
|
r207 | void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor) | ||
r118 | { | |||
Alexandre Leroux
|
r208 | if (visitor) { | ||
visitor->visitEnter(this); | ||||
Alexandre Leroux
|
r738 | // Apply visitor to zone children: widgets different from zones are not visited (no action) | ||
processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) { | ||||
zoneWidget.accept(visitor); | ||||
}); | ||||
Alexandre Leroux
|
r208 | |||
visitor->visitLeave(this); | ||||
} | ||||
Alexandre Leroux
|
r219 | else { | ||
qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null"); | ||||
} | ||||
r118 | } | |||
Alexandre Leroux
|
r209 | bool VisualizationTabWidget::canDrop(const Variable &variable) const | ||
{ | ||||
// A tab can always accomodate a variable | ||||
Q_UNUSED(variable); | ||||
return true; | ||||
} | ||||
Alexandre Leroux
|
r327 | bool VisualizationTabWidget::contains(const Variable &variable) const | ||
{ | ||||
Q_UNUSED(variable); | ||||
return false; | ||||
} | ||||
r119 | QString VisualizationTabWidget::name() const | |||
r118 | { | |||
Alexandre Leroux
|
r198 | return impl->m_Name; | ||
r118 | } | |||
Alexandre Leroux
|
r307 | |||
Alexandre Leroux
|
r738 | void VisualizationTabWidget::closeEvent(QCloseEvent *event) | ||
{ | ||||
// Closes zones in the tab | ||||
processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); }); | ||||
QWidget::closeEvent(event); | ||||
} | ||||
Alexandre Leroux
|
r307 | QLayout &VisualizationTabWidget::tabLayout() const noexcept | ||
{ | ||||
r842 | return *ui->dragDropContainer->layout(); | |||
} | ||||
void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData) | ||||
{ | ||||
r850 | if (mimeData->hasFormat(MIME_TYPE_GRAPH)) { | |||
r852 | impl->dropGraph(index, this); | |||
} | ||||
else if (mimeData->hasFormat(MIME_TYPE_ZONE)) { | ||||
impl->dropZone(index, this); | ||||
} | ||||
else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) { | ||||
auto variables = sqpApp->variableController().variablesForMimeData( | ||||
mimeData->data(MIME_TYPE_VARIABLE_LIST)); | ||||
impl->dropVariables(variables, index, this); | ||||
} | ||||
else { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationTabWidget::dropMimeData, unknown MIME data received."); | ||||
} | ||||
} | ||||
void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph( | ||||
int index, VisualizationTabWidget *tabWidget) | ||||
{ | ||||
auto &helper = sqpApp->dragDropHelper(); | ||||
auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget()); | ||||
if (!graphWidget) { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationTabWidget::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("VisualizationTabWidget::dropGraph, drop aborted, the parent container of " | ||||
"the dropped graph is not found."); | ||||
Q_ASSERT(false); | ||||
return; | ||||
} | ||||
auto nbGraph = parentDragDropContainer->countDragWidget(); | ||||
r844 | ||||
r852 | 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 | ||||
Thibaud Rabillard
|
r912 | helper.delayedCloseWidget(graphWidget->parentZoneWidget()); | ||
r842 | } | |||
r847 | else { | |||
r852 | // Close the graph | |||
Thibaud Rabillard
|
r912 | helper.delayedCloseWidget(graphWidget); | ||
r852 | } | |||
r842 | ||||
r852 | tabWidget->createZone(variables, index); | |||
} | ||||
else { | ||||
// The graph is empty, create an empty zone and move the graph inside | ||||
r844 | ||||
r852 | auto parentZoneWidget = graphWidget->parentZoneWidget(); | |||
r844 | ||||
r852 | parentDragDropContainer->layout()->removeWidget(graphWidget); | |||
r844 | ||||
r852 | auto zoneWidget = tabWidget->createEmptyZone(index); | |||
zoneWidget->addGraph(graphWidget); | ||||
// Close the old zone if it was the only graph inside | ||||
if (nbGraph == 1) { | ||||
Thibaud Rabillard
|
r912 | helper.delayedCloseWidget(parentZoneWidget); | ||
r844 | } | |||
r842 | } | |||
r852 | } | |||
r842 | ||||
r852 | void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone( | |||
int index, VisualizationTabWidget *tabWidget) | ||||
{ | ||||
auto &helper = sqpApp->dragDropHelper(); | ||||
auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget()); | ||||
if (!zoneWidget) { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not " | ||||
"found or invalid."); | ||||
Q_ASSERT(false); | ||||
return; | ||||
} | ||||
auto parentDragDropContainer | ||||
= qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget()); | ||||
if (!parentDragDropContainer) { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of " | ||||
"the dropped zone is not found."); | ||||
Q_ASSERT(false); | ||||
return; | ||||
r842 | } | |||
r852 | ||||
// Simple move of the zone, no variable operation associated | ||||
parentDragDropContainer->layout()->removeWidget(zoneWidget); | ||||
tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget); | ||||
} | ||||
void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables( | ||||
const QList<std::shared_ptr<Variable> > &variables, int index, | ||||
VisualizationTabWidget *tabWidget) | ||||
{ | ||||
r876 | // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and | |||
// compatible variable here | ||||
if (variables.count() > 1) { | ||||
qCWarning(LOG_VisualizationZoneWidget()) | ||||
<< tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation " | ||||
"aborted."); | ||||
return; | ||||
r877 | } | |||
r876 | ||||
r852 | tabWidget->createZone(variables, index); | |||
Alexandre Leroux
|
r307 | } | ||