##// END OF EJS Templates
Fix some glitches which occurred when dragging in the visualization something from the sides.
Fix some glitches which occurred when dragging in the visualization something from the sides.

File last commit:

r882:da9523540c62
r886:4ed691514436
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;
}