@@ -287,9 +287,11 QMimeData *VariableModel::mimeData(const QModelIndexList &indexes) const | |||
|
287 | 287 | QList<std::shared_ptr<Variable> > variableList; |
|
288 | 288 | |
|
289 | 289 | for (const auto &index : indexes) { |
|
290 | auto variable = impl->m_Variables.at(index.row()); | |
|
291 | if (variable.get() && index.isValid()) { | |
|
292 | variableList << variable; | |
|
290 | if (index.column() == 0) { // only the first column | |
|
291 | auto variable = impl->m_Variables.at(index.row()); | |
|
292 | if (variable.get() && index.isValid()) { | |
|
293 | variableList << variable; | |
|
294 | } | |
|
293 | 295 | } |
|
294 | 296 | } |
|
295 | 297 |
@@ -2,39 +2,23 | |||
|
2 | 2 | #define SCIQLOP_DRAGDROPHELPER_H |
|
3 | 3 | |
|
4 | 4 | #include <Common/spimpl.h> |
|
5 | #include <QLoggingCategory> | |
|
5 | 6 | #include <QWidget> |
|
6 | 7 | |
|
7 | 8 | class QVBoxLayout; |
|
8 | 9 | class QScrollArea; |
|
9 | 10 | class VisualizationDragWidget; |
|
11 | class VisualizationDragDropContainer; | |
|
10 | 12 | class QMimeData; |
|
11 | 13 | |
|
12 | /** | |
|
13 | * @brief Event filter class which manage the scroll of QScrollArea during a drag&drop operation. | |
|
14 | * @note A QScrollArea inside an other QScrollArea is not fully supported. | |
|
15 | */ | |
|
16 | class DragDropScroller : public QObject { | |
|
17 | Q_OBJECT | |
|
18 | ||
|
19 | public: | |
|
20 | DragDropScroller(QObject *parent = nullptr); | |
|
21 | ||
|
22 | void addScrollArea(QScrollArea *scrollArea); | |
|
23 | void removeScrollArea(QScrollArea *scrollArea); | |
|
24 | ||
|
25 | protected: | |
|
26 | bool eventFilter(QObject *obj, QEvent *event); | |
|
27 | ||
|
28 | private: | |
|
29 | class DragDropScrollerPrivate; | |
|
30 | spimpl::unique_impl_ptr<DragDropScrollerPrivate> impl; | |
|
31 | ||
|
32 | private slots: | |
|
33 | void onTimer(); | |
|
34 | }; | |
|
14 | Q_DECLARE_LOGGING_CATEGORY(LOG_DragDropHelper) | |
|
35 | 15 | |
|
36 | 16 | /** |
|
37 | 17 | * @brief Helper class for drag&drop operations. |
|
18 | * @note The helper is accessible from the sqpApp singleton and has the same life as the whole | |
|
19 | * application (like a controller). But contrary to a controller, it doesn't live in a thread and | |
|
20 | * can interect with the gui. | |
|
21 | * @see SqpApplication | |
|
38 | 22 | */ |
|
39 | 23 | class DragDropHelper { |
|
40 | 24 | public: |
@@ -44,7 +28,15 public: | |||
|
44 | 28 | DragDropHelper(); |
|
45 | 29 | virtual ~DragDropHelper(); |
|
46 | 30 | |
|
31 | /// Resets some internal variables. Must be called before any new drag&drop operation. | |
|
32 | void resetDragAndDrop(); | |
|
33 | ||
|
34 | /// Sets the visualization widget currently being drag on the visualization. | |
|
47 | 35 | void setCurrentDragWidget(VisualizationDragWidget *dragWidget); |
|
36 | ||
|
37 | /// Returns the visualization widget currently being drag on the visualization. | |
|
38 | /// Can be null if a new visualization widget is intended to be created by the drag&drop | |
|
39 | /// operation. | |
|
48 | 40 | VisualizationDragWidget *getCurrentDragWidget() const; |
|
49 | 41 | |
|
50 | 42 | QWidget &placeHolder() const; |
@@ -52,6 +44,10 public: | |||
|
52 | 44 | void removePlaceHolder(); |
|
53 | 45 | bool isPlaceHolderSet() const; |
|
54 | 46 | |
|
47 | /// Checks if the specified mime data is valid for a drop in the visualization | |
|
48 | bool checkMimeDataForVisualization(const QMimeData *mimeData, | |
|
49 | VisualizationDragDropContainer *dropContainer); | |
|
50 | ||
|
55 | 51 | void addDragDropScrollArea(QScrollArea *scrollArea); |
|
56 | 52 | void removeDragDropScrollArea(QScrollArea *scrollArea); |
|
57 | 53 | |
@@ -62,4 +58,28 private: | |||
|
62 | 58 | spimpl::unique_impl_ptr<DragDropHelperPrivate> impl; |
|
63 | 59 | }; |
|
64 | 60 | |
|
61 | /** | |
|
62 | * @brief Event filter class which manage the scroll of QScrollArea during a drag&drop operation. | |
|
63 | * @note A QScrollArea inside an other QScrollArea is not fully supported. | |
|
64 | */ | |
|
65 | class DragDropScroller : public QObject { | |
|
66 | Q_OBJECT | |
|
67 | ||
|
68 | public: | |
|
69 | DragDropScroller(QObject *parent = nullptr); | |
|
70 | ||
|
71 | void addScrollArea(QScrollArea *scrollArea); | |
|
72 | void removeScrollArea(QScrollArea *scrollArea); | |
|
73 | ||
|
74 | protected: | |
|
75 | bool eventFilter(QObject *obj, QEvent *event); | |
|
76 | ||
|
77 | private: | |
|
78 | class DragDropScrollerPrivate; | |
|
79 | spimpl::unique_impl_ptr<DragDropScrollerPrivate> impl; | |
|
80 | ||
|
81 | private slots: | |
|
82 | void onTimer(); | |
|
83 | }; | |
|
84 | ||
|
65 | 85 | #endif // SCIQLOP_DRAGDROPHELPER_H |
@@ -45,7 +45,8 public: | |||
|
45 | 45 | VariableController &variableController() noexcept; |
|
46 | 46 | VisualizationController &visualizationController() noexcept; |
|
47 | 47 | |
|
48 | /// Accessors for the differents sciqlop helpers | |
|
48 | /// Accessors for the differents sciqlop helpers, these helpers classes are like controllers but | |
|
49 | /// doesn't live in a thread and access gui | |
|
49 | 50 | DragDropHelper &dragDropHelper() noexcept; |
|
50 | 51 | |
|
51 | 52 | private: |
@@ -2,10 +2,15 | |||
|
2 | 2 | #define SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H |
|
3 | 3 | |
|
4 | 4 | #include <Common/spimpl.h> |
|
5 | #include <QLoggingCategory> | |
|
5 | 6 | #include <QMimeData> |
|
6 | 7 | #include <QVBoxLayout> |
|
7 | 8 | #include <QWidget> |
|
8 | 9 | |
|
10 | #include <functional> | |
|
11 | ||
|
12 | Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer) | |
|
13 | ||
|
9 | 14 | class VisualizationDragWidget; |
|
10 | 15 | |
|
11 | 16 | class VisualizationDragDropContainer : public QWidget { |
@@ -15,6 +20,8 signals: | |||
|
15 | 20 | void dropOccured(int dropIndex, const QMimeData *mimeData); |
|
16 | 21 | |
|
17 | 22 | public: |
|
23 | using AcceptMimeDataFunction = std::function<bool(const QMimeData *mimeData)>; | |
|
24 | ||
|
18 | 25 | VisualizationDragDropContainer(QWidget *parent = nullptr); |
|
19 | 26 | |
|
20 | 27 | void addDragWidget(VisualizationDragWidget *dragWidget); |
@@ -25,6 +32,8 public: | |||
|
25 | 32 | |
|
26 | 33 | int countDragWidget() const; |
|
27 | 34 | |
|
35 | void setAcceptMimeDataFunction(AcceptMimeDataFunction fun); | |
|
36 | ||
|
28 | 37 | protected: |
|
29 | 38 | void dragEnterEvent(QDragEnterEvent *event); |
|
30 | 39 | void dragLeaveEvent(QDragLeaveEvent *event); |
@@ -1,6 +1,14 | |||
|
1 | 1 | #include "DragDropHelper.h" |
|
2 | 2 | #include "SqpApplication.h" |
|
3 | #include "Visualization/VisualizationDragDropContainer.h" | |
|
3 | 4 | #include "Visualization/VisualizationDragWidget.h" |
|
5 | #include "Visualization/VisualizationWidget.h" | |
|
6 | #include "Visualization/operations/FindVariableOperation.h" | |
|
7 | ||
|
8 | #include "Variable/VariableController.h" | |
|
9 | ||
|
10 | #include "Common/MimeTypesDef.h" | |
|
11 | #include "Common/VisualizationDef.h" | |
|
4 | 12 | |
|
5 | 13 | #include <QDir> |
|
6 | 14 | #include <QDragEnterEvent> |
@@ -13,6 +21,8 | |||
|
13 | 21 | const int SCROLL_SPEED = 5; |
|
14 | 22 | const int SCROLL_ZONE_SIZE = 50; |
|
15 | 23 | |
|
24 | Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper") | |
|
25 | ||
|
16 | 26 | struct DragDropScroller::DragDropScrollerPrivate { |
|
17 | 27 | |
|
18 | 28 | QList<QScrollArea *> m_ScrollAreas; |
@@ -156,7 +166,11 struct DragDropHelper::DragDropHelperPrivate { | |||
|
156 | 166 | m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy()); |
|
157 | 167 | } |
|
158 | 168 | else { |
|
159 | m_PlaceHolder->setMinimumSize(200, 200); | |
|
169 | // Configuration of the placeHolder when there is no dragWidget | |
|
170 | // (for instance with a drag from a variable) | |
|
171 | ||
|
172 | m_PlaceHolder->setMinimumSize(400, 300); | |
|
173 | m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | |
|
160 | 174 | } |
|
161 | 175 | } |
|
162 | 176 | }; |
@@ -171,6 +185,11 DragDropHelper::~DragDropHelper() | |||
|
171 | 185 | QFile::remove(impl->m_ImageTempUrl); |
|
172 | 186 | } |
|
173 | 187 | |
|
188 | void DragDropHelper::resetDragAndDrop() | |
|
189 | { | |
|
190 | setCurrentDragWidget(nullptr); | |
|
191 | } | |
|
192 | ||
|
174 | 193 | void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget) |
|
175 | 194 | { |
|
176 | 195 | impl->m_CurrentDragWidget = dragWidget; |
@@ -225,3 +244,46 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const | |||
|
225 | 244 | image.save(impl->m_ImageTempUrl); |
|
226 | 245 | return QUrl::fromLocalFile(impl->m_ImageTempUrl); |
|
227 | 246 | } |
|
247 | ||
|
248 | bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData, | |
|
249 | VisualizationDragDropContainer *dropContainer) | |
|
250 | { | |
|
251 | auto result = true; | |
|
252 | ||
|
253 | if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) { | |
|
254 | auto variables = sqpApp->variableController().variablesForMimeData( | |
|
255 | mimeData->data(MIME_TYPE_VARIABLE_LIST)); | |
|
256 | ||
|
257 | if (variables.count() == 1) { | |
|
258 | // Check that the viariable is not already in a graph | |
|
259 | ||
|
260 | // Search for the top level VisualizationWidget | |
|
261 | auto parent = dropContainer->parentWidget(); | |
|
262 | while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) { | |
|
263 | parent = parent->parentWidget(); | |
|
264 | } | |
|
265 | ||
|
266 | if (parent) { | |
|
267 | auto visualizationWidget = static_cast<VisualizationWidget *>(parent); | |
|
268 | ||
|
269 | FindVariableOperation findVariableOperation{variables.first()}; | |
|
270 | visualizationWidget->accept(&findVariableOperation); | |
|
271 | auto variableContainers = findVariableOperation.result(); | |
|
272 | if (!variableContainers.empty()) { | |
|
273 | result = false; | |
|
274 | } | |
|
275 | } | |
|
276 | else { | |
|
277 | qCWarning(LOG_DragDropHelper()) << QObject::tr( | |
|
278 | "DragDropHelper::checkMimeDataForVisualization, the parent " | |
|
279 | "VisualizationWidget cannot be found."); | |
|
280 | result = false; | |
|
281 | } | |
|
282 | } | |
|
283 | else { | |
|
284 | result = false; | |
|
285 | } | |
|
286 | } | |
|
287 | ||
|
288 | return result; | |
|
289 | } |
@@ -12,6 +12,7 | |||
|
12 | 12 | #include <QStyledItemDelegate> |
|
13 | 13 | #include <QWidgetAction> |
|
14 | 14 | |
|
15 | #include <DragDropHelper.h> | |
|
15 | 16 | #include <SqpApplication.h> |
|
16 | 17 | |
|
17 | 18 | Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget") |
@@ -151,6 +152,11 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent) | |||
|
151 | 152 | ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); |
|
152 | 153 | connect(ui->tableView, &QTableView::customContextMenuRequested, this, |
|
153 | 154 | &VariableInspectorWidget::onTableMenuRequested); |
|
155 | ||
|
156 | // Resets the drag&drop operation on a left-click (the drag&drop is also started by a left | |
|
157 | // click). | |
|
158 | connect(ui->tableView, &QTableView::clicked, | |
|
159 | [](const auto &modelIndex) { sqpApp->dragDropHelper().resetDragAndDrop(); }); | |
|
154 | 160 | } |
|
155 | 161 | |
|
156 | 162 | VariableInspectorWidget::~VariableInspectorWidget() |
@@ -10,11 +10,15 | |||
|
10 | 10 | #include <cmath> |
|
11 | 11 | #include <memory> |
|
12 | 12 | |
|
13 | Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer") | |
|
14 | ||
|
13 | 15 | struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate { |
|
14 | 16 | |
|
15 | 17 | QVBoxLayout *m_Layout; |
|
16 | 18 | QStringList m_AcceptedMimeTypes; |
|
17 | 19 | QStringList m_MergeAllowedMimeTypes; |
|
20 | VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun | |
|
21 | = [](auto mimeData) { return true; }; | |
|
18 | 22 | |
|
19 | 23 | explicit VisualizationDragDropContainerPrivate(QWidget *widget) |
|
20 | 24 | { |
@@ -25,7 +29,7 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate { | |||
|
25 | 29 | bool acceptMimeData(const QMimeData *data) const |
|
26 | 30 | { |
|
27 | 31 | for (const auto &type : m_AcceptedMimeTypes) { |
|
28 | if (data->hasFormat(type)) { | |
|
32 | if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) { | |
|
29 | 33 | return true; |
|
30 | 34 | } |
|
31 | 35 | } |
@@ -121,10 +125,17 int VisualizationDragDropContainer::countDragWidget() const | |||
|
121 | 125 | return nbGraph; |
|
122 | 126 | } |
|
123 | 127 | |
|
128 | void VisualizationDragDropContainer::setAcceptMimeDataFunction( | |
|
129 | VisualizationDragDropContainer::AcceptMimeDataFunction fun) | |
|
130 | { | |
|
131 | impl->m_AcceptMimeDataFun = fun; | |
|
132 | } | |
|
133 | ||
|
124 | 134 | void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget, |
|
125 | 135 | const QPoint &dragPosition) |
|
126 | 136 | { |
|
127 | 137 | auto &helper = sqpApp->dragDropHelper(); |
|
138 | helper.resetDragAndDrop(); | |
|
128 | 139 | |
|
129 | 140 | // Note: The management of the drag object is done by Qt |
|
130 | 141 | auto drag = new QDrag{dragWidget}; |
@@ -149,10 +160,15 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidg | |||
|
149 | 160 | helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex); |
|
150 | 161 | dragWidget->setVisible(false); |
|
151 | 162 | } |
|
152 | } | |
|
153 | 163 | |
|
154 | // Note: The exec() is blocking on windows but not on linux and macOS | |
|
155 | drag->exec(Qt::MoveAction | Qt::CopyAction); | |
|
164 | // Note: The exec() is blocking on windows but not on linux and macOS | |
|
165 | drag->exec(Qt::MoveAction | Qt::CopyAction); | |
|
166 | } | |
|
167 | else { | |
|
168 | qCWarning(LOG_VisualizationDragDropContainer()) | |
|
169 | << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified " | |
|
170 | "VisualizationDragWidget is not found in this container."); | |
|
171 | } | |
|
156 | 172 | } |
|
157 | 173 | |
|
158 | 174 | void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event) |
@@ -164,20 +180,30 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event) | |||
|
164 | 180 | |
|
165 | 181 | if (!impl->hasPlaceHolder()) { |
|
166 | 182 | auto dragWidget = helper.getCurrentDragWidget(); |
|
167 | auto parentWidget | |
|
168 | = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget()); | |
|
169 | if (parentWidget) { | |
|
170 | dragWidget->setVisible(false); | |
|
183 | ||
|
184 | if (dragWidget) { | |
|
185 | // If the drag&drop is internal to the visualization, entering the container hide | |
|
186 | // the dragWidget which was hidden by the dragLeaveEvent | |
|
187 | auto parentWidget | |
|
188 | = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget()); | |
|
189 | if (parentWidget) { | |
|
190 | dragWidget->setVisible(false); | |
|
191 | } | |
|
171 | 192 | } |
|
172 | 193 | |
|
173 | 194 | auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos()); |
|
174 | 195 | |
|
175 | 196 | if (dragWidgetHovered) { |
|
176 | 197 | auto hoveredWidgetIndex = impl->m_Layout->indexOf(dragWidgetHovered); |
|
177 | auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget()); | |
|
178 | if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex) { | |
|
179 | hoveredWidgetIndex | |
|
180 | += 1; // Correction of the index if the drop occurs in the same container | |
|
198 | ||
|
199 | if (dragWidget) { | |
|
200 | auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget()); | |
|
201 | if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex) { | |
|
202 | // Correction of the index if the drop occurs in the same container | |
|
203 | // and if the drag is started from the visualization (in that case, the | |
|
204 | // dragWidget is hidden) | |
|
205 | hoveredWidgetIndex += 1; | |
|
206 | } | |
|
181 | 207 | } |
|
182 | 208 | |
|
183 | 209 | helper.insertPlaceHolder(impl->m_Layout, hoveredWidgetIndex); |
@@ -186,6 +212,9 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event) | |||
|
186 | 212 | helper.insertPlaceHolder(impl->m_Layout, 0); |
|
187 | 213 | } |
|
188 | 214 | } |
|
215 | else { | |
|
216 | // do nothing | |
|
217 | } | |
|
189 | 218 | } |
|
190 | 219 | else { |
|
191 | 220 | event->ignore(); |
@@ -203,19 +232,23 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event) | |||
|
203 | 232 | if (!impl->cursorIsInContainer(this)) { |
|
204 | 233 | helper.removePlaceHolder(); |
|
205 | 234 | |
|
206 | bool isInternal = true; | |
|
207 |
if ( |
|
|
208 |
// |
|
|
209 |
// |
|
|
235 | auto dragWidget = helper.getCurrentDragWidget(); | |
|
236 | if (dragWidget) { | |
|
237 | // dragWidget has a value only if the drag is started from the visualization | |
|
238 | // In that case, shows the drag widget at its original place | |
|
210 | 239 | // So the drag widget doesn't stay hidden if the drop occurs outside the visualization |
|
211 | 240 | // drop zone (It is not possible to catch a drop event outside of the application) |
|
212 | 241 | |
|
213 | auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget(); | |
|
214 | 242 | if (dragWidget) { |
|
215 | 243 | dragWidget->setVisible(true); |
|
216 | 244 | } |
|
217 | 245 | } |
|
218 | 246 | } |
|
247 | else { | |
|
248 | // Leave event probably received for a child widget. | |
|
249 | // Do nothing. | |
|
250 | // Note: The DragLeave event, doesn't have any mean to determine who sent it. | |
|
251 | } | |
|
219 | 252 | |
|
220 | 253 | QWidget::dragLeaveEvent(event); |
|
221 | 254 | } |
@@ -244,10 +277,15 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event) | |||
|
244 | 277 | dropIndex += 1; |
|
245 | 278 | } |
|
246 | 279 | |
|
247 |
|
|
|
248 |
|
|
|
249 | dropIndex += 1; // Correction of the index if the drop occurs in the same | |
|
250 | // container | |
|
280 | if (helper.getCurrentDragWidget()) { | |
|
281 | auto dragWidgetIndex | |
|
282 | = impl->m_Layout->indexOf(helper.getCurrentDragWidget()); | |
|
283 | if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) { | |
|
284 | // Correction of the index if the drop occurs in the same container | |
|
285 | // and if the drag is started from the visualization (in that case, the | |
|
286 | // dragWidget is hidden) | |
|
287 | dropIndex += 1; | |
|
288 | } | |
|
251 | 289 | } |
|
252 | 290 | |
|
253 | 291 | if (dropIndex != placeHolderIndex) { |
@@ -261,6 +299,15 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event) | |||
|
261 | 299 | } |
|
262 | 300 | } |
|
263 | 301 | } |
|
302 | else { | |
|
303 | qCWarning(LOG_VisualizationDragDropContainer()) | |
|
304 | << tr("VisualizationDragDropContainer::dragMoveEvent, no widget found in the " | |
|
305 | "container"); | |
|
306 | } | |
|
307 | } | |
|
308 | else { | |
|
309 | // No hovered drag widget, the mouse is probably hover the placeHolder | |
|
310 | // Do nothing | |
|
264 | 311 | } |
|
265 | 312 | } |
|
266 | 313 | else { |
@@ -274,18 +321,22 void VisualizationDragDropContainer::dropEvent(QDropEvent *event) | |||
|
274 | 321 | { |
|
275 | 322 | if (impl->acceptMimeData(event->mimeData())) { |
|
276 | 323 | auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget(); |
|
277 |
if (impl->hasPlaceHolder() |
|
|
324 | if (impl->hasPlaceHolder()) { | |
|
278 | 325 | auto &helper = sqpApp->dragDropHelper(); |
|
279 | 326 | |
|
280 | 327 | auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder()); |
|
281 | 328 | |
|
282 | auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget); | |
|
283 | if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) { | |
|
284 | droppedIndex | |
|
285 |
|
|
|
286 | } | |
|
329 | if (dragWidget) { | |
|
330 | auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget); | |
|
331 | if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) { | |
|
332 | // Correction of the index if the drop occurs in the same container | |
|
333 | // and if the drag is started from the visualization (in that case, the | |
|
334 | // dragWidget is hidden) | |
|
335 | droppedIndex -= 1; | |
|
336 | } | |
|
287 | 337 | |
|
288 | dragWidget->setVisible(true); | |
|
338 | dragWidget->setVisible(true); | |
|
339 | } | |
|
289 | 340 | |
|
290 | 341 | event->acceptProposedAction(); |
|
291 | 342 | |
@@ -293,6 +344,12 void VisualizationDragDropContainer::dropEvent(QDropEvent *event) | |||
|
293 | 344 | |
|
294 | 345 | emit dropOccured(droppedIndex, event->mimeData()); |
|
295 | 346 | } |
|
347 | else { | |
|
348 | qCWarning(LOG_VisualizationDragDropContainer()) | |
|
349 | << tr("VisualizationDragDropContainer::dropEvent, couldn't drop because the " | |
|
350 | "placeHolder is not found."); | |
|
351 | Q_ASSERT(false); | |
|
352 | } | |
|
296 | 353 | } |
|
297 | 354 | else { |
|
298 | 355 | event->ignore(); |
@@ -54,6 +54,11 struct VisualizationTabWidget::VisualizationTabWidgetPrivate { | |||
|
54 | 54 | explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {} |
|
55 | 55 | |
|
56 | 56 | QString m_Name; |
|
57 | ||
|
58 | void dropGraph(int index, VisualizationTabWidget *tabWidget); | |
|
59 | void dropZone(int index, VisualizationTabWidget *tabWidget); | |
|
60 | void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index, | |
|
61 | VisualizationTabWidget *tabWidget); | |
|
57 | 62 | }; |
|
58 | 63 | |
|
59 | 64 | VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent) |
@@ -63,9 +68,14 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *par | |||
|
63 | 68 | { |
|
64 | 69 | ui->setupUi(this); |
|
65 | 70 | |
|
66 |
ui->dragDropContainer->setAcceptedMimeTypes( |
|
|
71 | ui->dragDropContainer->setAcceptedMimeTypes( | |
|
72 | {MIME_TYPE_GRAPH, MIME_TYPE_ZONE, MIME_TYPE_VARIABLE_LIST}); | |
|
67 | 73 | connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this, |
|
68 | 74 | &VisualizationTabWidget::dropMimeData); |
|
75 | ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) { | |
|
76 | return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData, | |
|
77 | ui->dragDropContainer); | |
|
78 | }); | |
|
69 | 79 | sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea); |
|
70 | 80 | |
|
71 | 81 | // Widget is deleted when closed |
@@ -163,58 +173,122 QLayout &VisualizationTabWidget::tabLayout() const noexcept | |||
|
163 | 173 | |
|
164 | 174 | void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData) |
|
165 | 175 | { |
|
166 | auto &helper = sqpApp->dragDropHelper(); | |
|
167 | 176 | if (mimeData->hasFormat(MIME_TYPE_GRAPH)) { |
|
168 | auto graphWidget = static_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget()); | |
|
169 | auto parentDragDropContainer | |
|
170 | = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget()); | |
|
171 | Q_ASSERT(parentDragDropContainer); | |
|
172 | ||
|
173 | auto nbGraph = parentDragDropContainer->countDragWidget(); | |
|
174 | ||
|
175 | const auto &variables = graphWidget->variables(); | |
|
176 | ||
|
177 | if (!variables.isEmpty()) { | |
|
178 | // Abort the requests for the variables (if any) | |
|
179 | // Commented, because it's not sure if it's needed or not | |
|
180 | // for (const auto& var : variables) | |
|
181 | //{ | |
|
182 | // sqpApp->variableController().onAbortProgressRequested(var); | |
|
183 | //} | |
|
184 | ||
|
185 | if (nbGraph == 1) { | |
|
186 | // This is the only graph in the previous zone, close the zone | |
|
187 | graphWidget->parentZoneWidget()->close(); | |
|
188 | } | |
|
189 | else { | |
|
190 | // Close the graph | |
|
191 | graphWidget->close(); | |
|
192 | } | |
|
177 | impl->dropGraph(index, this); | |
|
178 | } | |
|
179 | else if (mimeData->hasFormat(MIME_TYPE_ZONE)) { | |
|
180 | impl->dropZone(index, this); | |
|
181 | } | |
|
182 | else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) { | |
|
183 | auto variables = sqpApp->variableController().variablesForMimeData( | |
|
184 | mimeData->data(MIME_TYPE_VARIABLE_LIST)); | |
|
185 | impl->dropVariables(variables, index, this); | |
|
186 | } | |
|
187 | else { | |
|
188 | qCWarning(LOG_VisualizationZoneWidget()) | |
|
189 | << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received."); | |
|
190 | } | |
|
191 | } | |
|
192 | ||
|
193 | void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph( | |
|
194 | int index, VisualizationTabWidget *tabWidget) | |
|
195 | { | |
|
196 | auto &helper = sqpApp->dragDropHelper(); | |
|
197 | ||
|
198 | auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget()); | |
|
199 | if (!graphWidget) { | |
|
200 | qCWarning(LOG_VisualizationZoneWidget()) | |
|
201 | << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not " | |
|
202 | "found or invalid."); | |
|
203 | Q_ASSERT(false); | |
|
204 | return; | |
|
205 | } | |
|
206 | ||
|
207 | auto parentDragDropContainer | |
|
208 | = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget()); | |
|
209 | if (!parentDragDropContainer) { | |
|
210 | qCWarning(LOG_VisualizationZoneWidget()) | |
|
211 | << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of " | |
|
212 | "the dropped graph is not found."); | |
|
213 | Q_ASSERT(false); | |
|
214 | return; | |
|
215 | } | |
|
216 | ||
|
217 | auto nbGraph = parentDragDropContainer->countDragWidget(); | |
|
193 | 218 | |
|
194 | createZone(variables, index); | |
|
219 | const auto &variables = graphWidget->variables(); | |
|
220 | ||
|
221 | if (!variables.isEmpty()) { | |
|
222 | // Abort the requests for the variables (if any) | |
|
223 | // Commented, because it's not sure if it's needed or not | |
|
224 | // for (const auto& var : variables) | |
|
225 | //{ | |
|
226 | // sqpApp->variableController().onAbortProgressRequested(var); | |
|
227 | //} | |
|
228 | ||
|
229 | if (nbGraph == 1) { | |
|
230 | // This is the only graph in the previous zone, close the zone | |
|
231 | graphWidget->parentZoneWidget()->close(); | |
|
195 | 232 | } |
|
196 | 233 | else { |
|
197 | // The graph is empty, create an empty zone and move the graph inside | |
|
234 | // Close the graph | |
|
235 | graphWidget->close(); | |
|
236 | } | |
|
198 | 237 | |
|
199 | auto parentZoneWidget = graphWidget->parentZoneWidget(); | |
|
238 | tabWidget->createZone(variables, index); | |
|
239 | } | |
|
240 | else { | |
|
241 | // The graph is empty, create an empty zone and move the graph inside | |
|
200 | 242 | |
|
201 | parentDragDropContainer->layout()->removeWidget(graphWidget); | |
|
243 | auto parentZoneWidget = graphWidget->parentZoneWidget(); | |
|
202 | 244 | |
|
203 | auto zoneWidget = createEmptyZone(index); | |
|
204 | zoneWidget->addGraph(graphWidget); | |
|
245 | parentDragDropContainer->layout()->removeWidget(graphWidget); | |
|
205 | 246 | |
|
206 | // Close the old zone if it was the only graph inside | |
|
207 | if (nbGraph == 1) { | |
|
208 | parentZoneWidget->close(); | |
|
209 | } | |
|
247 | auto zoneWidget = tabWidget->createEmptyZone(index); | |
|
248 | zoneWidget->addGraph(graphWidget); | |
|
249 | ||
|
250 | // Close the old zone if it was the only graph inside | |
|
251 | if (nbGraph == 1) { | |
|
252 | parentZoneWidget->close(); | |
|
210 | 253 | } |
|
211 | 254 | } |
|
212 | else if (mimeData->hasFormat(MIME_TYPE_ZONE)) { | |
|
213 | // Simple move of the zone, no variable operation associated | |
|
214 | auto zoneWidget = static_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget()); | |
|
215 | auto parentDragDropContainer = zoneWidget->parentWidget(); | |
|
216 | parentDragDropContainer->layout()->removeWidget(zoneWidget); | |
|
255 | } | |
|
217 | 256 | |
|
218 | ui->dragDropContainer->insertDragWidget(index, zoneWidget); | |
|
257 | void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone( | |
|
258 | int index, VisualizationTabWidget *tabWidget) | |
|
259 | { | |
|
260 | auto &helper = sqpApp->dragDropHelper(); | |
|
261 | ||
|
262 | auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget()); | |
|
263 | if (!zoneWidget) { | |
|
264 | qCWarning(LOG_VisualizationZoneWidget()) | |
|
265 | << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not " | |
|
266 | "found or invalid."); | |
|
267 | Q_ASSERT(false); | |
|
268 | return; | |
|
269 | } | |
|
270 | ||
|
271 | auto parentDragDropContainer | |
|
272 | = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget()); | |
|
273 | if (!parentDragDropContainer) { | |
|
274 | qCWarning(LOG_VisualizationZoneWidget()) | |
|
275 | << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of " | |
|
276 | "the dropped zone is not found."); | |
|
277 | Q_ASSERT(false); | |
|
278 | return; | |
|
219 | 279 | } |
|
280 | ||
|
281 | // Simple move of the zone, no variable operation associated | |
|
282 | parentDragDropContainer->layout()->removeWidget(zoneWidget); | |
|
283 | tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget); | |
|
284 | } | |
|
285 | ||
|
286 | void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables( | |
|
287 | const QList<std::shared_ptr<Variable> > &variables, int index, | |
|
288 | VisualizationTabWidget *tabWidget) | |
|
289 | { | |
|
290 | // Note: we are sure that there is a single and compatible variable here | |
|
291 | // because the AcceptMimeDataFunction, set on the drop container, makes the check before the | |
|
292 | // drop can occur. | |
|
293 | tabWidget->createZone(variables, index); | |
|
220 | 294 | } |
@@ -3,6 +3,7 | |||
|
3 | 3 | #include "Visualization/IVisualizationWidgetVisitor.h" |
|
4 | 4 | #include "Visualization/QCustomPlotSynchronizer.h" |
|
5 | 5 | #include "Visualization/VisualizationGraphWidget.h" |
|
6 | #include "Visualization/VisualizationWidget.h" | |
|
6 | 7 | #include "ui_VisualizationZoneWidget.h" |
|
7 | 8 | |
|
8 | 9 | #include "Common/MimeTypesDef.h" |
@@ -10,6 +11,8 | |||
|
10 | 11 | #include <Variable/Variable.h> |
|
11 | 12 | #include <Variable/VariableController.h> |
|
12 | 13 | |
|
14 | #include <Visualization/operations/FindVariableOperation.h> | |
|
15 | ||
|
13 | 16 | #include <DragDropHelper.h> |
|
14 | 17 | #include <QUuid> |
|
15 | 18 | #include <SqpApplication.h> |
@@ -67,6 +70,10 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate { | |||
|
67 | 70 | } |
|
68 | 71 | QUuid m_SynchronisationGroupId; |
|
69 | 72 | std::unique_ptr<IGraphSynchronizer> m_Synchronizer; |
|
73 | ||
|
74 | void dropGraph(int index, VisualizationZoneWidget *zoneWidget); | |
|
75 | void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index, | |
|
76 | VisualizationZoneWidget *zoneWidget); | |
|
70 | 77 | }; |
|
71 | 78 | |
|
72 | 79 | VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent) |
@@ -78,7 +85,11 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *p | |||
|
78 | 85 | |
|
79 | 86 | ui->zoneNameLabel->setText(name); |
|
80 | 87 | |
|
81 | ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH}); | |
|
88 | ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH, MIME_TYPE_VARIABLE_LIST}); | |
|
89 | ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) { | |
|
90 | return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData, | |
|
91 | ui->dragDropContainer); | |
|
92 | }); | |
|
82 | 93 | connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this, |
|
83 | 94 | &VisualizationZoneWidget::dropMimeData); |
|
84 | 95 | |
@@ -355,57 +366,119 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variabl | |||
|
355 | 366 | |
|
356 | 367 | void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData) |
|
357 | 368 | { |
|
358 | auto &helper = sqpApp->dragDropHelper(); | |
|
359 | 369 | if (mimeData->hasFormat(MIME_TYPE_GRAPH)) { |
|
360 | auto graphWidget = static_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget()); | |
|
361 | auto parentDragDropContainer | |
|
362 | = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget()); | |
|
363 | Q_ASSERT(parentDragDropContainer); | |
|
364 | ||
|
365 | const auto &variables = graphWidget->variables(); | |
|
366 | ||
|
367 | if (parentDragDropContainer != ui->dragDropContainer && !variables.isEmpty()) { | |
|
368 | // The drop didn't occur in the same zone | |
|
369 | ||
|
370 | // Abort the requests for the variables (if any) | |
|
371 | // Commented, because it's not sure if it's needed or not | |
|
372 | // for (const auto& var : variables) | |
|
373 | //{ | |
|
374 | // sqpApp->variableController().onAbortProgressRequested(var); | |
|
375 | //} | |
|
376 | ||
|
377 | auto previousParentZoneWidget = graphWidget->parentZoneWidget(); | |
|
378 | auto nbGraph = parentDragDropContainer->countDragWidget(); | |
|
379 | if (nbGraph == 1) { | |
|
380 | // This is the only graph in the previous zone, close the zone | |
|
381 | previousParentZoneWidget->close(); | |
|
382 | } | |
|
383 | else { | |
|
384 | // Close the graph | |
|
385 | graphWidget->close(); | |
|
386 | } | |
|
370 | impl->dropGraph(index, this); | |
|
371 | } | |
|
372 | else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) { | |
|
373 | auto variables = sqpApp->variableController().variablesForMimeData( | |
|
374 | mimeData->data(MIME_TYPE_VARIABLE_LIST)); | |
|
375 | impl->dropVariables(variables, index, this); | |
|
376 | } | |
|
377 | else { | |
|
378 | qCWarning(LOG_VisualizationZoneWidget()) | |
|
379 | << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received."); | |
|
380 | } | |
|
381 | } | |
|
382 | ||
|
383 | void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph( | |
|
384 | int index, VisualizationZoneWidget *zoneWidget) | |
|
385 | { | |
|
386 | auto &helper = sqpApp->dragDropHelper(); | |
|
387 | ||
|
388 | auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget()); | |
|
389 | if (!graphWidget) { | |
|
390 | qCWarning(LOG_VisualizationZoneWidget()) | |
|
391 | << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not " | |
|
392 | "found or invalid."); | |
|
393 | Q_ASSERT(false); | |
|
394 | return; | |
|
395 | } | |
|
396 | ||
|
397 | auto parentDragDropContainer | |
|
398 | = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget()); | |
|
399 | if (!parentDragDropContainer) { | |
|
400 | qCWarning(LOG_VisualizationZoneWidget()) | |
|
401 | << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of " | |
|
402 | "the dropped graph is not found."); | |
|
403 | Q_ASSERT(false); | |
|
404 | return; | |
|
405 | } | |
|
406 | ||
|
407 | const auto &variables = graphWidget->variables(); | |
|
387 | 408 | |
|
388 | // Creates the new graph in the zone | |
|
389 | createGraph(variables, index); | |
|
409 | if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) { | |
|
410 | // The drop didn't occur in the same zone | |
|
411 | ||
|
412 | // Abort the requests for the variables (if any) | |
|
413 | // Commented, because it's not sure if it's needed or not | |
|
414 | // for (const auto& var : variables) | |
|
415 | //{ | |
|
416 | // sqpApp->variableController().onAbortProgressRequested(var); | |
|
417 | //} | |
|
418 | ||
|
419 | auto previousParentZoneWidget = graphWidget->parentZoneWidget(); | |
|
420 | auto nbGraph = parentDragDropContainer->countDragWidget(); | |
|
421 | if (nbGraph == 1) { | |
|
422 | // This is the only graph in the previous zone, close the zone | |
|
423 | previousParentZoneWidget->close(); | |
|
390 | 424 | } |
|
391 | 425 | else { |
|
392 | // The drop occurred in the same zone or the graph is empty | |
|
393 | // Simple move of the graph, no variable operation associated | |
|
394 | parentDragDropContainer->layout()->removeWidget(graphWidget); | |
|
395 | ||
|
396 | if (variables.isEmpty() && parentDragDropContainer != ui->dragDropContainer) { | |
|
397 | // The graph is empty and dropped in a different zone. | |
|
398 | // Take the range of the first graph in the zone (if existing). | |
|
399 | auto layout = ui->dragDropContainer->layout(); | |
|
400 | if (layout->count() > 0) { | |
|
401 | if (auto visualizationGraphWidget | |
|
402 | = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) { | |
|
403 | graphWidget->setGraphRange(visualizationGraphWidget->graphRange()); | |
|
404 | } | |
|
426 | // Close the graph | |
|
427 | graphWidget->close(); | |
|
428 | } | |
|
429 | ||
|
430 | // Creates the new graph in the zone | |
|
431 | zoneWidget->createGraph(variables, index); | |
|
432 | } | |
|
433 | else { | |
|
434 | // The drop occurred in the same zone or the graph is empty | |
|
435 | // Simple move of the graph, no variable operation associated | |
|
436 | parentDragDropContainer->layout()->removeWidget(graphWidget); | |
|
437 | ||
|
438 | if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) { | |
|
439 | // The graph is empty and dropped in a different zone. | |
|
440 | // Take the range of the first graph in the zone (if existing). | |
|
441 | auto layout = zoneWidget->ui->dragDropContainer->layout(); | |
|
442 | if (layout->count() > 0) { | |
|
443 | if (auto visualizationGraphWidget | |
|
444 | = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) { | |
|
445 | graphWidget->setGraphRange(visualizationGraphWidget->graphRange()); | |
|
405 | 446 | } |
|
406 | 447 | } |
|
448 | } | |
|
449 | ||
|
450 | zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget); | |
|
451 | } | |
|
452 | } | |
|
453 | ||
|
454 | void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables( | |
|
455 | const QList<std::shared_ptr<Variable> > &variables, int index, | |
|
456 | VisualizationZoneWidget *zoneWidget) | |
|
457 | { | |
|
458 | // Search for the top level VisualizationWidget | |
|
459 | auto parent = zoneWidget->parentWidget(); | |
|
460 | while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) { | |
|
461 | parent = parent->parentWidget(); | |
|
462 | } | |
|
463 | ||
|
464 | if (!parent) { | |
|
465 | qCWarning(LOG_VisualizationZoneWidget()) | |
|
466 | << tr("VisualizationZoneWidget::dropVariables, drop aborted, the parent " | |
|
467 | "VisualizationWidget cannot be found."); | |
|
468 | Q_ASSERT(false); | |
|
469 | return; | |
|
470 | } | |
|
471 | ||
|
472 | auto visualizationWidget = static_cast<VisualizationWidget *>(parent); | |
|
407 | 473 | |
|
408 | ui->dragDropContainer->insertDragWidget(index, graphWidget); | |
|
474 | // Search for the first variable which can be dropped | |
|
475 | for (auto variable : variables) { | |
|
476 | FindVariableOperation findVariableOperation{variable}; | |
|
477 | visualizationWidget->accept(&findVariableOperation); | |
|
478 | auto variableContainers = findVariableOperation.result(); | |
|
479 | if (variableContainers.empty()) { | |
|
480 | zoneWidget->createGraph(variable, index); | |
|
481 | break; | |
|
409 | 482 | } |
|
410 | 483 | } |
|
411 | 484 | } |
General Comments 0
You need to be logged in to leave comments.
Login now