##// END OF EJS Templates
New event filter class to manage the tab switching of a tabBar during a drag&drop
trabillard -
r892:28af007d2663
parent child
Show More
@@ -0,0 +1,29
1 #ifndef SCIQLOP_DRAGDROPTABSWITCHER_H
2 #define SCIQLOP_DRAGDROPTABSWITCHER_H
3
4 #include <Common/spimpl.h>
5
6 #include <QLoggingCategory>
7 #include <QTabBar>
8
9 Q_DECLARE_LOGGING_CATEGORY(LOG_DragDropTabSwitcher)
10
11 class DragDropTabSwitcher : public QObject {
12 Q_OBJECT
13
14 public:
15 DragDropTabSwitcher(QObject *parent = nullptr);
16
17 void addTabBar(QTabBar *tabBar);
18 void removeTabBar(QTabBar *tabBar);
19
20 protected:
21 bool eventFilter(QObject *obj, QEvent *event);
22
23 private:
24 class DragDropTabSwitcherPrivate;
25 spimpl::unique_impl_ptr<DragDropTabSwitcherPrivate> impl;
26 };
27
28
29 #endif // SCIQLOP_DRAGDROPTABSWITCHER_H
@@ -0,0 +1,180
1 #include "DragAndDrop/DragDropTabSwitcher.h"
2
3 #include <QAbstractButton>
4 #include <QDragEnterEvent>
5 #include <QDragMoveEvent>
6 #include <QTimer>
7
8 #include "SqpApplication.h"
9
10 Q_LOGGING_CATEGORY(LOG_DragDropTabSwitcher, "DragDropTabSwitcher")
11
12 const int CHANGE_TAB_INTERVAL = 400; // time necessary over a tab to accept the switch
13 const int SCROLL_BUTTON_AUTO_CLICK_INTERVAL
14 = 500; // time between 2 auto clicks on a scroll button of the tab bar
15
16 struct DragDropTabSwitcher::DragDropTabSwitcherPrivate {
17
18 QList<QTabBar *> m_TabBarList;
19 QTabBar *m_CurrentTabBar = nullptr;
20
21 int m_HoveredTabIndex = -1;
22 std::unique_ptr<QTimer> m_TabSwitchTimer = nullptr;
23
24 QAbstractButton *m_HoveredScrollButton = nullptr;
25 std::unique_ptr<QTimer> m_ScrollButtonsTimer = nullptr;
26
27 explicit DragDropTabSwitcherPrivate()
28 : m_TabSwitchTimer{std::make_unique<QTimer>()},
29 m_ScrollButtonsTimer{std::make_unique<QTimer>()}
30 {
31 m_TabSwitchTimer->setSingleShot(true);
32 m_TabSwitchTimer->setInterval(CHANGE_TAB_INTERVAL);
33 QObject::connect(m_TabSwitchTimer.get(), &QTimer::timeout, [this]() {
34 if (m_CurrentTabBar) {
35 m_CurrentTabBar->setCurrentIndex(m_HoveredTabIndex);
36 }
37 else {
38 qCWarning(LOG_DragDropTabSwitcher()) << "DragDropTabSwitcherPrivate::timeout: "
39 "Cannot select a new tab: unknown current "
40 "tab bar.";
41 }
42 });
43
44 m_ScrollButtonsTimer->setInterval(SCROLL_BUTTON_AUTO_CLICK_INTERVAL);
45 QObject::connect(m_ScrollButtonsTimer.get(), &QTimer::timeout, [this]() {
46 if (m_HoveredScrollButton) {
47 m_HoveredScrollButton->animateClick();
48 }
49 else {
50 qCWarning(LOG_DragDropTabSwitcher())
51 << "DragDropTabSwitcherPrivate::timeoutScroll: "
52 "Unknown scroll button";
53 }
54 });
55 }
56
57 bool isScrollTabButton(QAbstractButton *button, QTabBar *tabBar)
58 {
59 auto isNextOrPreviousTabButton = true;
60
61 if (tabBar->isAncestorOf(button)) {
62 for (auto i = 0; i < tabBar->count(); ++i) {
63 if (tabBar->tabButton(i, QTabBar::RightSide) == button
64 || tabBar->tabButton(i, QTabBar::LeftSide) == button) {
65 isNextOrPreviousTabButton = false;
66 break;
67 }
68 }
69 }
70 else {
71 isNextOrPreviousTabButton = false;
72 }
73
74 return isNextOrPreviousTabButton;
75 }
76
77 QAbstractButton *tabScrollButtonAt(const QPoint &pos, QTabBar *tabBar)
78 {
79
80 auto globalPos = tabBar->mapToGlobal(pos);
81
82 auto widgetUnderMouse = sqpApp->widgetAt(globalPos);
83 if (auto btn = qobject_cast<QAbstractButton *>(widgetUnderMouse)) {
84
85 if (isScrollTabButton(btn, tabBar)) {
86 return btn;
87 }
88 }
89
90 return nullptr;
91 }
92 };
93
94 DragDropTabSwitcher::DragDropTabSwitcher(QObject *parent)
95 : QObject(parent), impl{spimpl::make_unique_impl<DragDropTabSwitcherPrivate>()}
96 {
97 }
98
99 void DragDropTabSwitcher::addTabBar(QTabBar *tabBar)
100 {
101 impl->m_TabBarList << tabBar;
102 tabBar->setAcceptDrops(true);
103 }
104
105 void DragDropTabSwitcher::removeTabBar(QTabBar *tabBar)
106 {
107 impl->m_TabBarList.removeAll(tabBar);
108 tabBar->setAcceptDrops(false);
109 }
110
111 bool DragDropTabSwitcher::eventFilter(QObject *obj, QEvent *event)
112 {
113 if (event->type() == QEvent::DragMove) {
114
115 if (impl->m_CurrentTabBar) {
116
117 QWidget *w = static_cast<QWidget *>(obj);
118 if (!impl->m_CurrentTabBar->isAncestorOf(w)) {
119 return false;
120 }
121
122 auto moveEvent = static_cast<QDragMoveEvent *>(event);
123
124 auto scrollButton = impl->tabScrollButtonAt(moveEvent->pos(), impl->m_CurrentTabBar);
125
126 if (!scrollButton) {
127
128 auto tabIndex = impl->m_CurrentTabBar->tabAt(moveEvent->pos());
129 if (tabIndex >= 0 && tabIndex != impl->m_CurrentTabBar->currentIndex()) {
130 // The mouse is over an unselected tab
131 if (!impl->m_TabSwitchTimer->isActive()
132 || tabIndex != impl->m_HoveredTabIndex) {
133 impl->m_HoveredTabIndex = tabIndex;
134 impl->m_TabSwitchTimer->start();
135 }
136 else {
137 // do nothing, timer already running
138 }
139 }
140 else {
141 impl->m_TabSwitchTimer->stop();
142 }
143
144 impl->m_ScrollButtonsTimer->stop();
145 }
146 else {
147 // The mouse is over a scroll button
148 // click it in a loop with a timer
149 if (!impl->m_ScrollButtonsTimer->isActive()
150 || impl->m_HoveredScrollButton != scrollButton) {
151 impl->m_HoveredScrollButton = scrollButton;
152 impl->m_ScrollButtonsTimer->start();
153 }
154 }
155 }
156 }
157 else if (event->type() == QEvent::DragEnter) {
158 QWidget *w = static_cast<QWidget *>(obj);
159
160 for (auto tabBar : impl->m_TabBarList) {
161 if (w == tabBar) {
162 auto enterEvent = static_cast<QDragEnterEvent *>(event);
163 enterEvent->acceptProposedAction();
164 enterEvent->setDropAction(Qt::IgnoreAction);
165 impl->m_CurrentTabBar = tabBar;
166 break;
167 }
168 }
169 }
170 else if (event->type() == QEvent::DragLeave || event->type() == QEvent::Drop) {
171 if (impl->m_CurrentTabBar) {
172 impl->m_HoveredTabIndex = -1;
173 impl->m_TabSwitchTimer->stop();
174 impl->m_CurrentTabBar = nullptr;
175 impl->m_ScrollButtonsTimer->stop();
176 }
177 }
178
179 return false;
180 }
@@ -1,67 +1,71
1 1 #ifndef SCIQLOP_DRAGDROPHELPER_H
2 2 #define SCIQLOP_DRAGDROPHELPER_H
3 3
4 4 #include <Common/spimpl.h>
5 5 #include <QLoggingCategory>
6 6 #include <QWidget>
7 7
8 8 class QVBoxLayout;
9 9 class QScrollArea;
10 class QTabBar;
10 11 class VisualizationDragWidget;
11 12 class VisualizationDragDropContainer;
12 13 class QMimeData;
13 14
14 15 Q_DECLARE_LOGGING_CATEGORY(LOG_DragDropHelper)
15 16
16 17 /**
17 18 * @brief Helper class for drag&drop operations.
18 19 * @note The helper is accessible from the sqpApp singleton and has the same life as the whole
19 20 * application (like a controller). But contrary to a controller, it doesn't live in a thread and
20 21 * can interect with the gui.
21 22 * @see SqpApplication
22 23 */
23 24 class DragDropHelper {
24 25 public:
25 26 static const QString MIME_TYPE_GRAPH;
26 27 static const QString MIME_TYPE_ZONE;
27 28
28 29 enum class PlaceHolderType { Default, Graph, Zone };
29 30
30 31 DragDropHelper();
31 32 virtual ~DragDropHelper();
32 33
33 34 /// Resets some internal variables. Must be called before any new drag&drop operation.
34 35 void resetDragAndDrop();
35 36
36 37 /// Sets the visualization widget currently being drag on the visualization.
37 38 void setCurrentDragWidget(VisualizationDragWidget *dragWidget);
38 39
39 40 /// Returns the visualization widget currently being drag on the visualization.
40 41 /// Can be null if a new visualization widget is intended to be created by the drag&drop
41 42 /// operation.
42 43 VisualizationDragWidget *getCurrentDragWidget() const;
43 44
44 45 QWidget &placeHolder() const;
45 46 void insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
46 47 const QString &topLabelText);
47 48 void removePlaceHolder();
48 49 bool isPlaceHolderSet() const;
49 50
50 51 /// Checks if the specified mime data is valid for a drop in the visualization
51 52 bool checkMimeDataForVisualization(const QMimeData *mimeData,
52 53 VisualizationDragDropContainer *dropContainer);
53 54
54 55 void addDragDropScrollArea(QScrollArea *scrollArea);
55 56 void removeDragDropScrollArea(QScrollArea *scrollArea);
56 57
58 void addDragDropTabBar(QTabBar *tabBar);
59 void removeDragDropTabBar(QTabBar *tabBar);
60
57 61 QUrl imageTemporaryUrl(const QImage &image) const;
58 62
59 63 void setHightlightedDragWidget(VisualizationDragWidget *dragWidget);
60 64 VisualizationDragWidget *getHightlightedDragWidget() const;
61 65
62 66 private:
63 67 class DragDropHelperPrivate;
64 68 spimpl::unique_impl_ptr<DragDropHelperPrivate> impl;
65 69 };
66 70
67 71 #endif // SCIQLOP_DRAGDROPHELPER_H
@@ -1,93 +1,95
1 1
2 2 gui_moc_headers = [
3 3 'include/DataSource/DataSourceWidget.h',
4 4 'include/DataSource/DataSourceTreeWidget.h',
5 5 'include/Settings/SqpSettingsDialog.h',
6 6 'include/Settings/SqpSettingsGeneralWidget.h',
7 7 'include/SidePane/SqpSidePane.h',
8 8 'include/SqpApplication.h',
9 9 'include/DragAndDrop/DragDropHelper.h',
10 10 'include/DragAndDrop/DragDropScroller.h',
11 'include/DragAndDrop/DragDropTabSwitcher.h',
11 12 'include/TimeWidget/TimeWidget.h',
12 13 'include/Variable/VariableInspectorWidget.h',
13 14 'include/Variable/VariableInspectorTableView.h',
14 15 'include/Variable/RenameVariableDialog.h',
15 16 'include/Visualization/qcustomplot.h',
16 17 'include/Visualization/VisualizationGraphWidget.h',
17 18 'include/Visualization/VisualizationTabWidget.h',
18 19 'include/Visualization/VisualizationWidget.h',
19 20 'include/Visualization/VisualizationZoneWidget.h',
20 21 'include/Visualization/VisualizationDragDropContainer.h',
21 22 'include/Visualization/VisualizationDragWidget.h'
22 23 ]
23 24
24 25 gui_ui_files = [
25 26 'ui/DataSource/DataSourceWidget.ui',
26 27 'ui/Settings/SqpSettingsDialog.ui',
27 28 'ui/Settings/SqpSettingsGeneralWidget.ui',
28 29 'ui/SidePane/SqpSidePane.ui',
29 30 'ui/TimeWidget/TimeWidget.ui',
30 31 'ui/Variable/VariableInspectorWidget.ui',
31 32 'ui/Variable/RenameVariableDialog.ui',
32 33 'ui/Variable/VariableMenuHeaderWidget.ui',
33 34 'ui/Visualization/VisualizationGraphWidget.ui',
34 35 'ui/Visualization/VisualizationTabWidget.ui',
35 36 'ui/Visualization/VisualizationWidget.ui',
36 37 'ui/Visualization/VisualizationZoneWidget.ui'
37 38 ]
38 39
39 40 gui_qresources = ['resources/sqpguiresources.qrc']
40 41
41 42 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
42 43 ui_files : gui_ui_files,
43 44 qresources : gui_qresources)
44 45
45 46 gui_sources = [
46 47 'src/SqpApplication.cpp',
47 48 'src/DragAndDrop/DragDropHelper.cpp',
48 49 'src/DragAndDrop/DragDropScroller.cpp',
50 'src/DragAndDrop/DragDropTabSwitcher.cpp',
49 51 'src/Common/ColorUtils.cpp',
50 52 'src/Common/VisualizationDef.cpp',
51 53 'src/DataSource/DataSourceTreeWidgetItem.cpp',
52 54 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
53 55 'src/DataSource/DataSourceWidget.cpp',
54 56 'src/DataSource/DataSourceTreeWidget.cpp',
55 57 'src/Settings/SqpSettingsDialog.cpp',
56 58 'src/Settings/SqpSettingsGeneralWidget.cpp',
57 59 'src/SidePane/SqpSidePane.cpp',
58 60 'src/TimeWidget/TimeWidget.cpp',
59 61 'src/Variable/VariableInspectorWidget.cpp',
60 62 'src/Variable/VariableInspectorTableView.cpp',
61 63 'src/Variable/VariableMenuHeaderWidget.cpp',
62 64 'src/Variable/RenameVariableDialog.cpp',
63 65 'src/Visualization/VisualizationGraphHelper.cpp',
64 66 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
65 67 'src/Visualization/VisualizationGraphWidget.cpp',
66 68 'src/Visualization/VisualizationTabWidget.cpp',
67 69 'src/Visualization/VisualizationWidget.cpp',
68 70 'src/Visualization/VisualizationZoneWidget.cpp',
69 71 'src/Visualization/qcustomplot.cpp',
70 72 'src/Visualization/QCustomPlotSynchronizer.cpp',
71 73 'src/Visualization/operations/FindVariableOperation.cpp',
72 74 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
73 75 'src/Visualization/operations/MenuBuilder.cpp',
74 76 'src/Visualization/operations/RemoveVariableOperation.cpp',
75 77 'src/Visualization/operations/RescaleAxeOperation.cpp',
76 78 'src/Visualization/VisualizationDragDropContainer.cpp',
77 79 'src/Visualization/VisualizationDragWidget.cpp'
78 80 ]
79 81
80 82 gui_inc = include_directories(['include'])
81 83
82 84 sciqlop_gui_lib = library('sciqlopgui',
83 85 gui_sources,
84 86 gui_moc_files,
85 87 include_directories : [gui_inc],
86 88 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
87 89 install : true
88 90 )
89 91
90 92 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
91 93 include_directories : gui_inc,
92 94 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
93 95
@@ -1,261 +1,275
1 1 #include "DragAndDrop/DragDropHelper.h"
2 2 #include "DragAndDrop/DragDropScroller.h"
3 #include "DragAndDrop/DragDropTabSwitcher.h"
3 4 #include "SqpApplication.h"
4 5 #include "Visualization/VisualizationDragDropContainer.h"
5 6 #include "Visualization/VisualizationDragWidget.h"
6 7 #include "Visualization/VisualizationWidget.h"
7 8 #include "Visualization/operations/FindVariableOperation.h"
8 9
9 10 #include "Variable/Variable.h"
10 11 #include "Variable/VariableController.h"
11 12
12 13 #include "Common/MimeTypesDef.h"
13 14 #include "Common/VisualizationDef.h"
14 15
15 16 #include <QDir>
16 17 #include <QLabel>
17 18 #include <QUrl>
18 19 #include <QVBoxLayout>
19 20
20 21
21 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
22 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDropHelper")
22 23
23 24
24 25 struct DragDropHelper::DragDropHelperPrivate {
25 26
26 27 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
27 28 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
28 29 QLabel *m_PlaceHolderLabel;
29 30 QWidget *m_PlaceBackground;
30 31 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
32 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
31 33 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
32 34 // QTemporaryFile to have a name which is not generated.
33 35
34 36 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
35 37
36 38 QMetaObject::Connection m_DragWidgetDestroyedConnection;
37 39 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
38 40
39 41 explicit DragDropHelperPrivate()
40 42 : m_PlaceHolder{std::make_unique<QWidget>()},
41 m_DragDropScroller{std::make_unique<DragDropScroller>()}
43 m_DragDropScroller{std::make_unique<DragDropScroller>()},
44 m_DragDropTabSwitcher{std::make_unique<DragDropTabSwitcher>()}
42 45 {
43 46
44 47 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
45 48 layout->setSpacing(0);
46 49 layout->setContentsMargins(0, 0, 0, 0);
47 50
48 51 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
49 52 m_PlaceHolderLabel->setMinimumHeight(25);
50 53 layout->addWidget(m_PlaceHolderLabel);
51 54
52 55 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
53 56 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
54 57 layout->addWidget(m_PlaceBackground);
55 58
56 59 sqpApp->installEventFilter(m_DragDropScroller.get());
60 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
57 61
58 62 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
59 63 }
60 64
61 65 void preparePlaceHolder(DragDropHelper::PlaceHolderType type, const QString &topLabelText) const
62 66 {
63 67 if (m_CurrentDragWidget) {
64 68 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
65 69 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
66 70 }
67 71 else {
68 72 // Configuration of the placeHolder when there is no dragWidget
69 73 // (for instance with a drag from a variable)
70 74
71 75 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
72 76 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
73 77 }
74 78
75 79 switch (type) {
76 80 case DragDropHelper::PlaceHolderType::Graph:
77 81 m_PlaceBackground->setStyleSheet(
78 82 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
79 83 break;
80 84 case DragDropHelper::PlaceHolderType::Zone:
81 85 case DragDropHelper::PlaceHolderType::Default:
82 86 m_PlaceBackground->setStyleSheet(
83 87 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
84 88 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
85 89 break;
86 90 }
87 91
88 92 m_PlaceHolderLabel->setText(topLabelText);
89 93 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
90 94 }
91 95 };
92 96
93 97
94 98 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()} {}
95 99
96 100 DragDropHelper::~DragDropHelper()
97 101 {
98 102 QFile::remove(impl->m_ImageTempUrl);
99 103 }
100 104
101 105 void DragDropHelper::resetDragAndDrop()
102 106 {
103 107 setCurrentDragWidget(nullptr);
104 108 impl->m_HighlightedDragWidget = nullptr;
105 109 }
106 110
107 111 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
108 112 {
109 113 if (impl->m_CurrentDragWidget) {
110 114
111 115 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
112 116 }
113 117
114 118 if (dragWidget) {
115 119 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
116 120 impl->m_DragWidgetDestroyedConnection
117 121 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
118 122 [this]() { impl->m_CurrentDragWidget = nullptr; });
119 123 }
120 124
121 125 impl->m_CurrentDragWidget = dragWidget;
122 126 }
123 127
124 128 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
125 129 {
126 130 return impl->m_CurrentDragWidget;
127 131 }
128 132
129 133 QWidget &DragDropHelper::placeHolder() const
130 134 {
131 135 return *impl->m_PlaceHolder;
132 136 }
133 137
134 138 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
135 139 const QString &topLabelText)
136 140 {
137 141 removePlaceHolder();
138 142 impl->preparePlaceHolder(type, topLabelText);
139 143 layout->insertWidget(index, impl->m_PlaceHolder.get());
140 144 impl->m_PlaceHolder->show();
141 145 }
142 146
143 147 void DragDropHelper::removePlaceHolder()
144 148 {
145 149 auto parentWidget = impl->m_PlaceHolder->parentWidget();
146 150 if (parentWidget) {
147 151 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
148 152 impl->m_PlaceHolder->setParent(nullptr);
149 153 impl->m_PlaceHolder->hide();
150 154 }
151 155 }
152 156
153 157 bool DragDropHelper::isPlaceHolderSet() const
154 158 {
155 159 return impl->m_PlaceHolder->parentWidget();
156 160 }
157 161
158 162 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
159 163 {
160 164 impl->m_DragDropScroller->addScrollArea(scrollArea);
161 165 }
162 166
163 167 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
164 168 {
165 169 impl->m_DragDropScroller->removeScrollArea(scrollArea);
166 170 }
167 171
172 void DragDropHelper::addDragDropTabBar(QTabBar *tabBar)
173 {
174 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
175 }
176
177 void DragDropHelper::removeDragDropTabBar(QTabBar *tabBar)
178 {
179 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
180 }
181
168 182 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
169 183 {
170 184 image.save(impl->m_ImageTempUrl);
171 185 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
172 186 }
173 187
174 188 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
175 189 {
176 190 if (impl->m_HighlightedDragWidget) {
177 191 impl->m_HighlightedDragWidget->highlightForMerge(false);
178 192 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
179 193 }
180 194
181 195 if (dragWidget) {
182 196 dragWidget->highlightForMerge(true);
183 197
184 198 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
185 199 impl->m_DragWidgetDestroyedConnection
186 200 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
187 201 [this]() { impl->m_HighlightedDragWidget = nullptr; });
188 202 }
189 203
190 204 impl->m_HighlightedDragWidget = dragWidget;
191 205 }
192 206
193 207 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
194 208 {
195 209 return impl->m_HighlightedDragWidget;
196 210 }
197 211
198 212 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
199 213 VisualizationDragDropContainer *dropContainer)
200 214 {
201 215 if (!mimeData || !dropContainer) {
202 216 qCWarning(LOG_DragDropHelper()) << QObject::tr(
203 217 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
204 218 Q_ASSERT(false);
205 219 return false;
206 220 }
207 221
208 222 auto result = false;
209 223
210 224 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
211 225 auto variables = sqpApp->variableController().variablesForMimeData(
212 226 mimeData->data(MIME_TYPE_VARIABLE_LIST));
213 227
214 228 if (variables.count() == 1) {
215 229
216 230 auto variable = variables.first();
217 231 if (variable->dataSeries() != nullptr) {
218 232
219 233 // Check that the variable is not already in a graph
220 234
221 235 auto parent = dropContainer->parentWidget();
222 236 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
223 237 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
224 238 }
225 239
226 240 if (parent) {
227 241 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
228 242
229 243 FindVariableOperation findVariableOperation{variable};
230 244 visualizationWidget->accept(&findVariableOperation);
231 245 auto variableContainers = findVariableOperation.result();
232 246 if (variableContainers.empty()) {
233 247 result = true;
234 248 }
235 249 else {
236 250 // result = false: the variable already exist in the visualisation
237 251 }
238 252 }
239 253 else {
240 254 qCWarning(LOG_DragDropHelper()) << QObject::tr(
241 255 "DragDropHelper::checkMimeDataForVisualization, the parent "
242 256 "VisualizationWidget cannot be found. Cannot check if the variable is "
243 257 "already used or not.");
244 258 }
245 259 }
246 260 else {
247 261 // result = false: the variable is not fully loaded
248 262 }
249 263 }
250 264 else {
251 265 // result = false: cannot drop multiple variables in the visualisation
252 266 }
253 267 }
254 268 else {
255 269 // Other MIME data
256 270 // no special rules, accepted by default
257 271 result = true;
258 272 }
259 273
260 274 return result;
261 275 }
@@ -1,172 +1,178
1 1 #include "Visualization/VisualizationWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphWidget.h"
4 4 #include "Visualization/VisualizationTabWidget.h"
5 5 #include "Visualization/VisualizationZoneWidget.h"
6 6 #include "Visualization/operations/FindVariableOperation.h"
7 7 #include "Visualization/operations/GenerateVariableMenuOperation.h"
8 8 #include "Visualization/operations/RemoveVariableOperation.h"
9 9 #include "Visualization/operations/RescaleAxeOperation.h"
10 10 #include "Visualization/qcustomplot.h"
11 11
12 12 #include "ui_VisualizationWidget.h"
13 13
14 #include "DragAndDrop/DragDropHelper.h"
15 #include "SqpApplication.h"
16
14 17 #include <QToolButton>
15 18
16 19 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
17 20
18 21 VisualizationWidget::VisualizationWidget(QWidget *parent)
19 22 : QWidget{parent}, ui{new Ui::VisualizationWidget}
20 23 {
21 24 ui->setupUi(this);
22 25
23 26 auto addTabViewButton = new QToolButton{ui->tabWidget};
24 27 addTabViewButton->setText(tr("Add View"));
25 28 addTabViewButton->setCursor(Qt::ArrowCursor);
26 29 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
27 30
28 31 auto enableMinimumCornerWidgetSize = [this](bool enable) {
29 32
30 33 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
31 34 auto width = enable ? tabViewCornerWidget->width() : 0;
32 35 auto height = enable ? tabViewCornerWidget->height() : 0;
33 36 tabViewCornerWidget->setMinimumHeight(height);
34 37 tabViewCornerWidget->setMinimumWidth(width);
35 38 ui->tabWidget->setMinimumHeight(height);
36 39 ui->tabWidget->setMinimumWidth(width);
37 40 };
38 41
39 42 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
40 43 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
41 44 ui->tabWidget};
42 45 auto index = ui->tabWidget->addTab(widget, widget->name());
43 46 if (ui->tabWidget->count() > 0) {
44 47 enableMinimumCornerWidgetSize(false);
45 48 }
46 49 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
47 50 };
48 51
49 52 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
50 53 if (ui->tabWidget->count() == 1) {
51 54 enableMinimumCornerWidgetSize(true);
52 55 }
53 56
54 57 // Removes widget from tab and closes it
55 58 auto widget = ui->tabWidget->widget(index);
56 59 ui->tabWidget->removeTab(index);
57 60 if (widget) {
58 61 widget->close();
59 62 }
60 63
61 64 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
62 65
63 66 };
64 67
65 68 ui->tabWidget->setTabsClosable(true);
66 69
67 70 connect(addTabViewButton, &QToolButton::clicked, addTabView);
68 71 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
69 72
73 sqpApp->dragDropHelper().addDragDropTabBar(ui->tabWidget->tabBar());
74
70 75 // Adds default tab
71 76 addTabView();
72 77 }
73 78
74 79 VisualizationWidget::~VisualizationWidget()
75 80 {
81 sqpApp->dragDropHelper().removeDragDropTabBar(ui->tabWidget->tabBar());
76 82 delete ui;
77 83 }
78 84
79 85 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
80 86 {
81 87 if (visitor) {
82 88 visitor->visitEnter(this);
83 89
84 90 // Apply visitor for tab children
85 91 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
86 92 // Widgets different from tabs are not visited (no action)
87 93 if (auto visualizationTabWidget
88 94 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
89 95 visualizationTabWidget->accept(visitor);
90 96 }
91 97 }
92 98
93 99 visitor->visitLeave(this);
94 100 }
95 101 else {
96 102 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
97 103 }
98 104 }
99 105
100 106 bool VisualizationWidget::canDrop(const Variable &variable) const
101 107 {
102 108 // The main widget can never accomodate a variable
103 109 Q_UNUSED(variable);
104 110 return false;
105 111 }
106 112
107 113 bool VisualizationWidget::contains(const Variable &variable) const
108 114 {
109 115 Q_UNUSED(variable);
110 116 return false;
111 117 }
112 118
113 119 QString VisualizationWidget::name() const
114 120 {
115 121 return QStringLiteral("MainView");
116 122 }
117 123
118 124 void VisualizationWidget::attachVariableMenu(
119 125 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
120 126 {
121 127 // Menu is generated only if there is a single variable
122 128 if (variables.size() == 1) {
123 129 if (auto variable = variables.first()) {
124 130 // Gets the containers of the variable
125 131 FindVariableOperation findVariableOperation{variable};
126 132 accept(&findVariableOperation);
127 133 auto variableContainers = findVariableOperation.result();
128 134
129 135 // Generates the actions that make it possible to visualize the variable
130 136 GenerateVariableMenuOperation generateVariableMenuOperation{
131 137 menu, variable, std::move(variableContainers)};
132 138 accept(&generateVariableMenuOperation);
133 139 }
134 140 else {
135 141 qCCritical(LOG_VisualizationWidget()) << tr(
136 142 "Can't generate the menu relative to the visualization: the variable is null");
137 143 }
138 144 }
139 145 else {
140 146 qCDebug(LOG_VisualizationWidget())
141 147 << tr("No generation of the menu related to the visualization: several variables are "
142 148 "selected");
143 149 }
144 150 }
145 151
146 152 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
147 153 {
148 154 // Calls the operation of removing all references to the variable in the visualization
149 155 auto removeVariableOperation = RemoveVariableOperation{variable};
150 156 accept(&removeVariableOperation);
151 157 }
152 158
153 159 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
154 160 const SqpRange &range) noexcept
155 161 {
156 162 // Calls the operation of rescaling all graph that contrains variable in the visualization
157 163 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
158 164 accept(&rescaleVariableOperation);
159 165 }
160 166
161 167 void VisualizationWidget::closeEvent(QCloseEvent *event)
162 168 {
163 169 // Closes tabs in the widget
164 170 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
165 171 if (auto visualizationTabWidget
166 172 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
167 173 visualizationTabWidget->close();
168 174 }
169 175 }
170 176
171 177 QWidget::closeEvent(event);
172 178 }
General Comments 3
Under Review
author

Pull request updated. Auto status change to "Under Review"

Changed commits:
  * 1 added
  * 0 removed

Changed files:
  * A core/tests/meson.build
You need to be logged in to leave comments. Login now