##// END OF EJS Templates
Drop of variable, graph and zones on the time widget
Drop of variable, graph and zones on the time widget

File last commit:

r882:da9523540c62
r884:e439cb403ff9
Show More
DragDropHelper.cpp
353 lines | 11.9 KiB | text/x-c | CppLexer
/ gui / src / DragDropHelper.cpp
New helper class for the drag&drop
r840 #include "DragDropHelper.h"
#include "SqpApplication.h"
drop of variables in the visualization
r852 #include "Visualization/VisualizationDragDropContainer.h"
Format changes
r847 #include "Visualization/VisualizationDragWidget.h"
drop of variables in the visualization
r852 #include "Visualization/VisualizationWidget.h"
#include "Visualization/operations/FindVariableOperation.h"
prevent dropping an variable without data in the visu
r882 #include "Variable/Variable.h"
drop of variables in the visualization
r852 #include "Variable/VariableController.h"
#include "Common/MimeTypesDef.h"
#include "Common/VisualizationDef.h"
New helper class for the drag&drop
r840
Format changes
r847 #include <QDir>
New helper class for the drag&drop
r840 #include <QDragEnterEvent>
Format changes
r847 #include <QDragMoveEvent>
New helper class for the drag&drop
r840 #include <QScrollArea>
Format changes
r847 #include <QScrollBar>
New helper class for the drag&drop
r840 #include <QTimer>
Format changes
r847 #include <QVBoxLayout>
New helper class for the drag&drop
r840
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 const int SCROLL_SPEED = 5;
const int SCROLL_ZONE_SIZE = 50;
drop of variables in the visualization
r852 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 struct DragDropScroller::DragDropScrollerPrivate {
Format changes
r847 QList<QScrollArea *> m_ScrollAreas;
QScrollArea *m_CurrentScrollArea = nullptr;
std::unique_ptr<QTimer> m_Timer = nullptr;
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843
Format changes
r847 enum class ScrollDirection { up, down, unknown };
ScrollDirection m_Direction = ScrollDirection::unknown;
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843
Format changes
r847 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 {
Format changes
r847 m_Timer->setInterval(0);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
};
Format changes
r847 DragDropScroller::DragDropScroller(QObject *parent)
: QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 {
Format changes
r847 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
Format changes
r847 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 {
Format changes
r847 impl->m_ScrollAreas << scrollArea;
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 scrollArea->viewport()->setAcceptDrops(true);
}
Format changes
r847 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 {
Format changes
r847 impl->m_ScrollAreas.removeAll(scrollArea);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 scrollArea->viewport()->setAcceptDrops(false);
}
bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
{
Format changes
r847 if (event->type() == QEvent::DragMove) {
auto w = static_cast<QWidget *>(obj);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843
Format changes
r847 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
auto moveEvent = static_cast<QDragMoveEvent *>(event);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843
auto pos = moveEvent->pos();
Format changes
r847 if (impl->m_CurrentScrollArea->viewport() != w) {
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 auto globalPos = w->mapToGlobal(moveEvent->pos());
Format changes
r847 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
Format changes
r847 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
- SCROLL_ZONE_SIZE;
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
Format changes
r847 if (!isInTopZone && !isInBottomZone) {
impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
impl->m_Timer->stop();
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
Format changes
r847 else if (!impl->m_Timer->isActive()) {
impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
: DragDropScrollerPrivate::ScrollDirection::down;
impl->m_Timer->start();
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
}
}
Format changes
r847 else if (event->type() == QEvent::DragEnter) {
auto w = static_cast<QWidget *>(obj);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843
Format changes
r847 for (auto scrollArea : impl->m_ScrollAreas) {
if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
auto enterEvent = static_cast<QDragEnterEvent *>(event);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 enterEvent->acceptProposedAction();
enterEvent->setDropAction(Qt::IgnoreAction);
Format changes
r847 impl->m_CurrentScrollArea = scrollArea;
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 break;
}
}
}
Format changes
r847 else if (event->type() == QEvent::DragLeave) {
if (impl->m_CurrentScrollArea) {
if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
.contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
impl->m_CurrentScrollArea = nullptr;
impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
impl->m_Timer->stop();
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
}
}
Format changes
r847 else if (event->type() == QEvent::Drop) {
if (impl->m_CurrentScrollArea) {
impl->m_CurrentScrollArea = nullptr;
impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
impl->m_Timer->stop();
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
}
return false;
}
void DragDropScroller::onTimer()
{
Format changes
r847 if (impl->m_CurrentScrollArea) {
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 auto mvt = 0;
Format changes
r847 switch (impl->m_Direction) {
case DragDropScrollerPrivate::ScrollDirection::up:
mvt = SCROLL_SPEED;
break;
case DragDropScrollerPrivate::ScrollDirection::down:
mvt = -SCROLL_SPEED;
break;
default:
break;
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
Format changes
r847 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
}
New helper class for the drag&drop
r840
struct DragDropHelper::DragDropHelperPrivate {
Format changes
r847 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
// QTemporaryFile to have a name which is not generated.
New helper class for the drag&drop
r840
Improves visual effect of dropping a variable in a graph
r879 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
Improves reliability
r880 QMetaObject::Connection m_DragWidgetDestroyedConnection;
QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
New helper class for the drag&drop
r840 explicit DragDropHelperPrivate()
Format changes
r847 : m_PlaceHolder{std::make_unique<QWidget>()},
m_DragDropScroller{std::make_unique<DragDropScroller>()}
New helper class for the drag&drop
r840 {
Format changes
r847 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
sqpApp->installEventFilter(m_DragDropScroller.get());
New helper class for the drag&drop
r840
prevent dropping an variable without data in the visu
r882 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
New helper class for the drag&drop
r840 }
void preparePlaceHolder() const
{
Format changes
r847 if (m_CurrentDragWidget) {
m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
New helper class for the drag&drop
r840 }
Format changes
r847 else {
drop of variables in the visualization
r852 // Configuration of the placeHolder when there is no dragWidget
// (for instance with a drag from a variable)
Move the GRAPH_MINIMUM_HEIGHT constant in a place accessible everywhere and use it in the drag&drop
r853 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
drop of variables in the visualization
r852 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
New helper class for the drag&drop
r840 }
}
};
MR for linux compilation
r848 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
{
}
New helper class for the drag&drop
r840
DragDropHelper::~DragDropHelper()
{
Format changes
r847 QFile::remove(impl->m_ImageTempUrl);
New helper class for the drag&drop
r840 }
drop of variables in the visualization
r852 void DragDropHelper::resetDragAndDrop()
{
setCurrentDragWidget(nullptr);
Improves visual effect of dropping a variable in a graph
r879 impl->m_HighlightedDragWidget = nullptr;
drop of variables in the visualization
r852 }
New helper class for the drag&drop
r840 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
{
Improves reliability
r880 if (impl->m_CurrentDragWidget) {
QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
}
if (dragWidget) {
// ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
impl->m_DragWidgetDestroyedConnection
= QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
[this]() { impl->m_CurrentDragWidget = nullptr; });
}
Format changes
r847 impl->m_CurrentDragWidget = dragWidget;
New helper class for the drag&drop
r840 }
VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
{
Format changes
r847 return impl->m_CurrentDragWidget;
New helper class for the drag&drop
r840 }
Format changes
r847 QWidget &DragDropHelper::placeHolder() const
New helper class for the drag&drop
r840 {
Format changes
r847 return *impl->m_PlaceHolder;
New helper class for the drag&drop
r840 }
void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
{
removePlaceHolder();
impl->preparePlaceHolder();
Format changes
r847 layout->insertWidget(index, impl->m_PlaceHolder.get());
impl->m_PlaceHolder->show();
New helper class for the drag&drop
r840 }
void DragDropHelper::removePlaceHolder()
{
Format changes
r847 auto parentWidget = impl->m_PlaceHolder->parentWidget();
if (parentWidget) {
parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
impl->m_PlaceHolder->setParent(nullptr);
impl->m_PlaceHolder->hide();
New helper class for the drag&drop
r840 }
}
bool DragDropHelper::isPlaceHolderSet() const
{
Format changes
r847 return impl->m_PlaceHolder->parentWidget();
New helper class for the drag&drop
r840 }
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
{
Format changes
r847 impl->m_DragDropScroller->addScrollArea(scrollArea);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
{
Format changes
r847 impl->m_DragDropScroller->removeScrollArea(scrollArea);
Manage the scroll of the tab QScrollArea during a drag&drop operation
r843 }
Format changes
r847 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
New helper class for the drag&drop
r840 {
Format changes
r847 image.save(impl->m_ImageTempUrl);
return QUrl::fromLocalFile(impl->m_ImageTempUrl);
New helper class for the drag&drop
r840 }
drop of variables in the visualization
r852
Improves visual effect of dropping a variable in a graph
r879 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
{
if (impl->m_HighlightedDragWidget) {
impl->m_HighlightedDragWidget->highlightForMerge(false);
Improves reliability
r880 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
Improves visual effect of dropping a variable in a graph
r879 }
if (dragWidget) {
Improves reliability
r880 dragWidget->highlightForMerge(true);
// ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
impl->m_DragWidgetDestroyedConnection
= QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
[this]() { impl->m_HighlightedDragWidget = nullptr; });
Improves visual effect of dropping a variable in a graph
r879 }
Improves reliability
r880
impl->m_HighlightedDragWidget = dragWidget;
Improves visual effect of dropping a variable in a graph
r879 }
drop of variable inside an existing graph
r881 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
{
return impl->m_HighlightedDragWidget;
}
drop of variables in the visualization
r852 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
VisualizationDragDropContainer *dropContainer)
{
Drag of product
r876 if (!mimeData || !dropContainer) {
qCWarning(LOG_DragDropHelper()) << QObject::tr(
"DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
Q_ASSERT(false);
prevent dropping an variable without data in the visu
r882 return false;
Drag of product
r876 }
prevent dropping an variable without data in the visu
r882 auto result = false;
drop of variables in the visualization
r852
if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
auto variables = sqpApp->variableController().variablesForMimeData(
mimeData->data(MIME_TYPE_VARIABLE_LIST));
if (variables.count() == 1) {
prevent dropping an variable without data in the visu
r882 auto variable = variables.first();
if (variable->dataSeries() != nullptr) {
// Check that the variable is not already in a graph
drop of variables in the visualization
r852
prevent dropping an variable without data in the visu
r882 auto parent = dropContainer->parentWidget();
while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
parent = parent->parentWidget(); // Search for the top level VisualizationWidget
}
drop of variables in the visualization
r852
prevent dropping an variable without data in the visu
r882 if (parent) {
auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
FindVariableOperation findVariableOperation{variable};
visualizationWidget->accept(&findVariableOperation);
auto variableContainers = findVariableOperation.result();
if (variableContainers.empty()) {
result = true;
}
else {
// result = false: the variable already exist in the visualisation
}
}
else {
qCWarning(LOG_DragDropHelper()) << QObject::tr(
"DragDropHelper::checkMimeDataForVisualization, the parent "
"VisualizationWidget cannot be found. Cannot check if the variable is "
"already used or not.");
drop of variables in the visualization
r852 }
}
else {
prevent dropping an variable without data in the visu
r882 // result = false: the variable is not fully loaded
drop of variables in the visualization
r852 }
}
else {
prevent dropping an variable without data in the visu
r882 // result = false: cannot drop multiple variables in the visualisation
drop of variables in the visualization
r852 }
}
prevent dropping an variable without data in the visu
r882 else {
// Other MIME data
// no special rules, accepted by default
result = true;
}
drop of variables in the visualization
r852
return result;
}