##// END OF EJS Templates
Merge branch 'feature/DragVariables' into develop
trabillard -
r854:552d1389af00 merge
parent child
Show More
@@ -0,0 +1,18
1 #ifndef SCIQLOP_MIMETYPESDEF_H
2 #define SCIQLOP_MIMETYPESDEF_H
3
4 #include "CoreGlobal.h"
5
6 #include <QString>
7
8 // ////////////////// //
9 // SciQlop Mime Types //
10 // ////////////////// //
11
12 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH;
13 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
16
17
18 #endif // SCIQLOP_MIMETYPESDEF_H
@@ -0,0 +1,6
1 #include "Common/MimeTypesDef.h"
2
3 const QString MIME_TYPE_GRAPH = QStringLiteral("scqlop/graph");
4 const QString MIME_TYPE_ZONE = QStringLiteral("scqlop/zone");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("scqlop/var-list");
6 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("scqlop/time-range");
@@ -0,0 +1,7
1 #ifndef SCIQLOP_VISUALIZATIONDEF_H
2 #define SCIQLOP_VISUALIZATIONDEF_H
3
4 /// Minimum height for graph added in zones (in pixels)
5 extern const int GRAPH_MINIMUM_HEIGHT;
6
7 #endif // SCIQLOP_VISUALIZATIONDEF_H
@@ -0,0 +1,3
1 #include "Common/VisualizationDef.h"
2
3 const int GRAPH_MINIMUM_HEIGHT = 300;
@@ -68,6 +68,8 public:
68 68 */
69 69 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
70 70
71 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
72 QList<std::shared_ptr<Variable> > variablesForMimeData(const QByteArray &mimeData) const;
71 73
72 74 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
73 75 signals:
@@ -18,6 +18,7 enum VariableRoles { ProgressRole = Qt::UserRole };
18 18
19 19 class IDataSeries;
20 20 class Variable;
21 class VariableController;
21 22
22 23 /**
23 24 * @brief The VariableModel class aims to hold the variables that have been created in SciQlop
@@ -25,7 +26,7 class Variable;
25 26 class SCIQLOP_CORE_EXPORT VariableModel : public QAbstractTableModel {
26 27 Q_OBJECT
27 28 public:
28 explicit VariableModel(QObject *parent = nullptr);
29 explicit VariableModel(VariableController *parent = nullptr);
29 30
30 31 /**
31 32 * Adds an existing variable in the model.
@@ -73,7 +74,20 public:
73 74 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
74 75 virtual QVariant headerData(int section, Qt::Orientation orientation,
75 76 int role = Qt::DisplayRole) const override;
76
77 virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
78
79 // ///////////////// //
80 // Drag&Drop methods //
81 // ///////////////// //
82
83 virtual Qt::DropActions supportedDropActions() const override;
84 virtual Qt::DropActions supportedDragActions() const override;
85 virtual QStringList mimeTypes() const override;
86 virtual QMimeData *mimeData(const QModelIndexList &indexes) const override;
87 virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
88 const QModelIndex &parent) const override;
89 virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
90 const QModelIndex &parent) override;
77 91
78 92 void abortProgress(const QModelIndex &index);
79 93
@@ -12,6 +12,7
12 12 #include <Data/VariableRequest.h>
13 13 #include <Time/TimeController.h>
14 14
15 #include <QDataStream>
15 16 #include <QMutex>
16 17 #include <QThread>
17 18 #include <QUuid>
@@ -277,6 +278,46 void VariableController::deleteVariables(
277 278 }
278 279 }
279 280
281 QByteArray
282 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
283 {
284 auto encodedData = QByteArray{};
285
286 QVariantList ids;
287 for (auto &var : variables) {
288 auto itVar = impl->m_VariableToIdentifierMap.find(var);
289 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
290 qCCritical(LOG_VariableController())
291 << tr("Impossible to find the data for an unknown variable.");
292 }
293
294 ids << itVar->second.toByteArray();
295 }
296
297 QDataStream stream{&encodedData, QIODevice::WriteOnly};
298 stream << ids;
299
300 return encodedData;
301 }
302
303 QList<std::shared_ptr<Variable> >
304 VariableController::variablesForMimeData(const QByteArray &mimeData) const
305 {
306 auto variables = QList<std::shared_ptr<Variable> >{};
307 QDataStream stream{mimeData};
308
309 QVariantList ids;
310 stream >> ids;
311
312 for (auto id : ids) {
313 auto uuid = QUuid(id.toByteArray());
314 auto var = impl->findVariable(uuid);
315 variables << var;
316 }
317
318 return variables;
319 }
320
280 321 std::shared_ptr<Variable>
281 322 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
282 323 std::shared_ptr<IDataProvider> provider) noexcept
@@ -1,11 +1,14
1 1 #include <Variable/Variable.h>
2 #include <Variable/VariableController.h>
2 3 #include <Variable/VariableModel.h>
3 4
4 5 #include <Common/DateUtils.h>
6 #include <Common/MimeTypesDef.h>
5 7 #include <Common/StringUtils.h>
6 8
7 9 #include <Data/IDataSeries.h>
8 10
11 #include <QMimeData>
9 12 #include <QSize>
10 13 #include <unordered_map>
11 14
@@ -66,14 +69,16 struct VariableModel::VariableModelPrivate {
66 69 /// Variables created in SciQlop
67 70 std::vector<std::shared_ptr<Variable> > m_Variables;
68 71 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
72 VariableController *m_VariableController;
69 73
70 74 /// Return the row index of the variable. -1 if it's not found
71 75 int indexOfVariable(Variable *variable) const noexcept;
72 76 };
73 77
74 VariableModel::VariableModel(QObject *parent)
78 VariableModel::VariableModel(VariableController *parent)
75 79 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
76 80 {
81 impl->m_VariableController = parent;
77 82 }
78 83
79 84 void VariableModel::addVariable(std::shared_ptr<Variable> variable) noexcept
@@ -255,6 +260,59 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int
255 260 return QVariant{};
256 261 }
257 262
263 Qt::ItemFlags VariableModel::flags(const QModelIndex &index) const
264 {
265 return QAbstractTableModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
266 }
267
268 Qt::DropActions VariableModel::supportedDropActions() const
269 {
270 return Qt::MoveAction;
271 }
272
273 Qt::DropActions VariableModel::supportedDragActions() const
274 {
275 return Qt::CopyAction | Qt::MoveAction;
276 }
277
278 QStringList VariableModel::mimeTypes() const
279 {
280 return {MIME_TYPE_VARIABLE_LIST};
281 }
282
283 QMimeData *VariableModel::mimeData(const QModelIndexList &indexes) const
284 {
285 auto mimeData = new QMimeData;
286
287 QList<std::shared_ptr<Variable> > variableList;
288
289 for (const auto &index : indexes) {
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 }
295 }
296 }
297
298 auto encodedData = impl->m_VariableController->mimeDataForVariables(variableList);
299 mimeData->setData(MIME_TYPE_VARIABLE_LIST, encodedData);
300
301 return mimeData;
302 }
303
304 bool VariableModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
305 int column, const QModelIndex &parent) const
306 {
307 return false;
308 }
309
310 bool VariableModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
311 const QModelIndex &parent)
312 {
313 return false;
314 }
315
258 316 void VariableModel::abortProgress(const QModelIndex &index)
259 317 {
260 318 if (auto variable = impl->m_Variables.at(index.row())) {
@@ -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>
@@ -10,12 +18,11
10 18 #include <QTimer>
11 19 #include <QVBoxLayout>
12 20
13 const QString DragDropHelper::MIME_TYPE_GRAPH = "scqlop/graph";
14 const QString DragDropHelper::MIME_TYPE_ZONE = "scqlop/zone";
15
16 21 const int SCROLL_SPEED = 5;
17 22 const int SCROLL_ZONE_SIZE = 50;
18 23
24 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
25
19 26 struct DragDropScroller::DragDropScrollerPrivate {
20 27
21 28 QList<QScrollArea *> m_ScrollAreas;
@@ -159,7 +166,11 struct DragDropHelper::DragDropHelperPrivate {
159 166 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
160 167 }
161 168 else {
162 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(0, GRAPH_MINIMUM_HEIGHT);
173 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
163 174 }
164 175 }
165 176 };
@@ -174,6 +185,11 DragDropHelper::~DragDropHelper()
174 185 QFile::remove(impl->m_ImageTempUrl);
175 186 }
176 187
188 void DragDropHelper::resetDragAndDrop()
189 {
190 setCurrentDragWidget(nullptr);
191 }
192
177 193 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
178 194 {
179 195 impl->m_CurrentDragWidget = dragWidget;
@@ -228,3 +244,46 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
228 244 image.save(impl->m_ImageTempUrl);
229 245 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
230 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()
@@ -3,6 +3,8
3 3 #include "SqpApplication.h"
4 4 #include "Visualization/VisualizationDragWidget.h"
5 5
6 #include "Common/VisualizationDef.h"
7
6 8 #include <QDrag>
7 9 #include <QDragEnterEvent>
8 10 #include <QVBoxLayout>
@@ -10,11 +12,15
10 12 #include <cmath>
11 13 #include <memory>
12 14
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
16
13 17 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
14 18
15 19 QVBoxLayout *m_Layout;
16 20 QStringList m_AcceptedMimeTypes;
17 21 QStringList m_MergeAllowedMimeTypes;
22 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
23 = [](auto mimeData) { return true; };
18 24
19 25 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
20 26 {
@@ -25,7 +31,7 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
25 31 bool acceptMimeData(const QMimeData *data) const
26 32 {
27 33 for (const auto &type : m_AcceptedMimeTypes) {
28 if (data->hasFormat(type)) {
34 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
29 35 return true;
30 36 }
31 37 }
@@ -121,10 +127,17 int VisualizationDragDropContainer::countDragWidget() const
121 127 return nbGraph;
122 128 }
123 129
130 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
131 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
132 {
133 impl->m_AcceptMimeDataFun = fun;
134 }
135
124 136 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
125 137 const QPoint &dragPosition)
126 138 {
127 139 auto &helper = sqpApp->dragDropHelper();
140 helper.resetDragAndDrop();
128 141
129 142 // Note: The management of the drag object is done by Qt
130 143 auto drag = new QDrag{dragWidget};
@@ -149,10 +162,15 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidg
149 162 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex);
150 163 dragWidget->setVisible(false);
151 164 }
152 }
153 165
154 // Note: The exec() is blocking on windows but not on linux and macOS
155 drag->exec(Qt::MoveAction | Qt::CopyAction);
166 // Note: The exec() is blocking on windows but not on linux and macOS
167 drag->exec(Qt::MoveAction | Qt::CopyAction);
168 }
169 else {
170 qCWarning(LOG_VisualizationDragDropContainer())
171 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
172 "VisualizationDragWidget is not found in this container.");
173 }
156 174 }
157 175
158 176 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
@@ -164,20 +182,30 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
164 182
165 183 if (!impl->hasPlaceHolder()) {
166 184 auto dragWidget = helper.getCurrentDragWidget();
167 auto parentWidget
168 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
169 if (parentWidget) {
170 dragWidget->setVisible(false);
185
186 if (dragWidget) {
187 // If the drag&drop is internal to the visualization, entering the container hide
188 // the dragWidget which was hidden by the dragLeaveEvent
189 auto parentWidget
190 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
191 if (parentWidget) {
192 dragWidget->setVisible(false);
193 }
171 194 }
172 195
173 196 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
174 197
175 198 if (dragWidgetHovered) {
176 199 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
200
201 if (dragWidget) {
202 auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
203 if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex) {
204 // Correction of the index if the drop occurs in the same container
205 // and if the drag is started from the visualization (in that case, the
206 // dragWidget is hidden)
207 hoveredWidgetIndex += 1;
208 }
181 209 }
182 210
183 211 helper.insertPlaceHolder(impl->m_Layout, hoveredWidgetIndex);
@@ -186,6 +214,9 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
186 214 helper.insertPlaceHolder(impl->m_Layout, 0);
187 215 }
188 216 }
217 else {
218 // do nothing
219 }
189 220 }
190 221 else {
191 222 event->ignore();
@@ -203,19 +234,23 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
203 234 if (!impl->cursorIsInContainer(this)) {
204 235 helper.removePlaceHolder();
205 236
206 bool isInternal = true;
207 if (isInternal) {
208 // Only if the drag is started from the visualization
209 // Show the drag widget at its original place
237 auto dragWidget = helper.getCurrentDragWidget();
238 if (dragWidget) {
239 // dragWidget has a value only if the drag is started from the visualization
240 // In that case, shows the drag widget at its original place
210 241 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
211 242 // drop zone (It is not possible to catch a drop event outside of the application)
212 243
213 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
214 244 if (dragWidget) {
215 245 dragWidget->setVisible(true);
216 246 }
217 247 }
218 248 }
249 else {
250 // Leave event probably received for a child widget.
251 // Do nothing.
252 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
253 }
219 254
220 255 QWidget::dragLeaveEvent(event);
221 256 }
@@ -229,7 +264,8 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
229 264
230 265 auto nbDragWidget = countDragWidget();
231 266 if (nbDragWidget > 0) {
232 auto graphHeight = size().height() / nbDragWidget;
267 auto graphHeight = qMax(size().height() / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
268
233 269 auto dropIndex = floor(event->pos().y() / graphHeight);
234 270 auto zoneSize = qMin(graphHeight / 3.0, 150.0);
235 271
@@ -244,10 +280,15 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
244 280 dropIndex += 1;
245 281 }
246 282
247 auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
248 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
249 dropIndex += 1; // Correction of the index if the drop occurs in the same
250 // container
283 if (helper.getCurrentDragWidget()) {
284 auto dragWidgetIndex
285 = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
286 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
287 // Correction of the index if the drop occurs in the same container
288 // and if the drag is started from the visualization (in that case, the
289 // dragWidget is hidden)
290 dropIndex += 1;
291 }
251 292 }
252 293
253 294 if (dropIndex != placeHolderIndex) {
@@ -261,6 +302,15 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
261 302 }
262 303 }
263 304 }
305 else {
306 qCWarning(LOG_VisualizationDragDropContainer())
307 << tr("VisualizationDragDropContainer::dragMoveEvent, no widget found in the "
308 "container");
309 }
310 }
311 else {
312 // No hovered drag widget, the mouse is probably hover the placeHolder
313 // Do nothing
264 314 }
265 315 }
266 316 else {
@@ -274,18 +324,22 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
274 324 {
275 325 if (impl->acceptMimeData(event->mimeData())) {
276 326 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
277 if (impl->hasPlaceHolder() && dragWidget) {
327 if (impl->hasPlaceHolder()) {
278 328 auto &helper = sqpApp->dragDropHelper();
279 329
280 330 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
281 331
282 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
283 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
284 droppedIndex
285 -= 1; // Correction of the index if the drop occurs in the same container
286 }
332 if (dragWidget) {
333 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
334 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
335 // Correction of the index if the drop occurs in the same container
336 // and if the drag is started from the visualization (in that case, the
337 // dragWidget is hidden)
338 droppedIndex -= 1;
339 }
287 340
288 dragWidget->setVisible(true);
341 dragWidget->setVisible(true);
342 }
289 343
290 344 event->acceptProposedAction();
291 345
@@ -293,6 +347,12 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
293 347
294 348 emit dropOccured(droppedIndex, event->mimeData());
295 349 }
350 else {
351 qCWarning(LOG_VisualizationDragDropContainer())
352 << tr("VisualizationDragDropContainer::dropEvent, couldn't drop because the "
353 "placeHolder is not found.");
354 Q_ASSERT(false);
355 }
296 356 }
297 357 else {
298 358 event->ignore();
@@ -6,6 +6,7
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7 #include "ui_VisualizationGraphWidget.h"
8 8
9 #include <Common/MimeTypesDef.h>
9 10 #include <Data/ArrayData.h>
10 11 #include <Data/IDataSeries.h>
11 12 #include <DragDropHelper.h>
@@ -232,7 +233,7 QString VisualizationGraphWidget::name() const
232 233 QMimeData *VisualizationGraphWidget::mimeData() const
233 234 {
234 235 auto mimeData = new QMimeData;
235 mimeData->setData(DragDropHelper::MIME_TYPE_GRAPH, QByteArray());
236 mimeData->setData(MIME_TYPE_GRAPH, QByteArray());
236 237
237 238 return mimeData;
238 239 }
@@ -7,6 +7,8
7 7
8 8 #include "Variable/VariableController.h"
9 9
10 #include "Common/MimeTypesDef.h"
11
10 12 #include "DragDropHelper.h"
11 13 #include "SqpApplication.h"
12 14
@@ -52,6 +54,11 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
52 54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
53 55
54 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);
55 62 };
56 63
57 64 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
@@ -62,9 +69,13 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *par
62 69 ui->setupUi(this);
63 70
64 71 ui->dragDropContainer->setAcceptedMimeTypes(
65 {DragDropHelper::MIME_TYPE_GRAPH, DragDropHelper::MIME_TYPE_ZONE});
72 {MIME_TYPE_GRAPH, MIME_TYPE_ZONE, MIME_TYPE_VARIABLE_LIST});
66 73 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
67 74 &VisualizationTabWidget::dropMimeData);
75 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
76 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
77 ui->dragDropContainer);
78 });
68 79 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
69 80
70 81 // Widget is deleted when closed
@@ -162,58 +173,122 QLayout &VisualizationTabWidget::tabLayout() const noexcept
162 173
163 174 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
164 175 {
176 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
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 {
165 196 auto &helper = sqpApp->dragDropHelper();
166 if (mimeData->hasFormat(DragDropHelper::MIME_TYPE_GRAPH)) {
167 auto graphWidget = static_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
168 auto parentDragDropContainer
169 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
170 Q_ASSERT(parentDragDropContainer);
171
172 auto nbGraph = parentDragDropContainer->countDragWidget();
173
174 const auto &variables = graphWidget->variables();
175
176 if (!variables.isEmpty()) {
177 // Abort the requests for the variables (if any)
178 // Commented, because it's not sure if it's needed or not
179 // for (const auto& var : variables)
180 //{
181 // sqpApp->variableController().onAbortProgressRequested(var);
182 //}
183
184 if (nbGraph == 1) {
185 // This is the only graph in the previous zone, close the zone
186 graphWidget->parentZoneWidget()->close();
187 }
188 else {
189 // Close the graph
190 graphWidget->close();
191 }
192 197
193 createZone(variables, index);
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();
218
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();
194 232 }
195 233 else {
196 // The graph is empty, create an empty zone and move the graph inside
234 // Close the graph
235 graphWidget->close();
236 }
197 237
198 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
199 242
200 parentDragDropContainer->layout()->removeWidget(graphWidget);
243 auto parentZoneWidget = graphWidget->parentZoneWidget();
201 244
202 auto zoneWidget = createEmptyZone(index);
203 zoneWidget->addGraph(graphWidget);
245 parentDragDropContainer->layout()->removeWidget(graphWidget);
204 246
205 // Close the old zone if it was the only graph inside
206 if (nbGraph == 1) {
207 parentZoneWidget->close();
208 }
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();
209 253 }
210 254 }
211 else if (mimeData->hasFormat(DragDropHelper::MIME_TYPE_ZONE)) {
212 // Simple move of the zone, no variable operation associated
213 auto zoneWidget = static_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
214 auto parentDragDropContainer = zoneWidget->parentWidget();
215 parentDragDropContainer->layout()->removeWidget(zoneWidget);
255 }
216 256
217 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;
218 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);
219 294 }
@@ -3,12 +3,18
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
9 #include "Common/MimeTypesDef.h"
10 #include "Common/VisualizationDef.h"
11
8 12 #include <Data/SqpRange.h>
9 13 #include <Variable/Variable.h>
10 14 #include <Variable/VariableController.h>
11 15
16 #include <Visualization/operations/FindVariableOperation.h>
17
12 18 #include <DragDropHelper.h>
13 19 #include <QUuid>
14 20 #include <SqpApplication.h>
@@ -20,8 +26,6 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
20 26
21 27 namespace {
22 28
23 /// Minimum height for graph added in zones (in pixels)
24 const auto GRAPH_MINIMUM_HEIGHT = 300;
25 29
26 30 /// Generates a default name for a new graph, according to the number of graphs already displayed in
27 31 /// the zone
@@ -66,6 +70,10 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
66 70 }
67 71 QUuid m_SynchronisationGroupId;
68 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);
69 77 };
70 78
71 79 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
@@ -77,7 +85,11 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *p
77 85
78 86 ui->zoneNameLabel->setText(name);
79 87
80 ui->dragDropContainer->setAcceptedMimeTypes({DragDropHelper::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 });
81 93 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
82 94 &VisualizationZoneWidget::dropMimeData);
83 95
@@ -315,7 +327,7 QString VisualizationZoneWidget::name() const
315 327 QMimeData *VisualizationZoneWidget::mimeData() const
316 328 {
317 329 auto mimeData = new QMimeData;
318 mimeData->setData(DragDropHelper::MIME_TYPE_ZONE, QByteArray());
330 mimeData->setData(MIME_TYPE_ZONE, QByteArray());
319 331
320 332 return mimeData;
321 333 }
@@ -354,57 +366,119 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variabl
354 366
355 367 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
356 368 {
369 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
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 {
357 386 auto &helper = sqpApp->dragDropHelper();
358 if (mimeData->hasFormat(DragDropHelper::MIME_TYPE_GRAPH)) {
359 auto graphWidget = static_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
360 auto parentDragDropContainer
361 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
362 Q_ASSERT(parentDragDropContainer);
363
364 const auto &variables = graphWidget->variables();
365
366 if (parentDragDropContainer != ui->dragDropContainer && !variables.isEmpty()) {
367 // The drop didn't occur in the same zone
368
369 // Abort the requests for the variables (if any)
370 // Commented, because it's not sure if it's needed or not
371 // for (const auto& var : variables)
372 //{
373 // sqpApp->variableController().onAbortProgressRequested(var);
374 //}
375
376 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
377 auto nbGraph = parentDragDropContainer->countDragWidget();
378 if (nbGraph == 1) {
379 // This is the only graph in the previous zone, close the zone
380 previousParentZoneWidget->close();
381 }
382 else {
383 // Close the graph
384 graphWidget->close();
385 }
386 387
387 // Creates the new graph in the zone
388 createGraph(variables, index);
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();
408
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();
389 424 }
390 425 else {
391 // The drop occurred in the same zone or the graph is empty
392 // Simple move of the graph, no variable operation associated
393 parentDragDropContainer->layout()->removeWidget(graphWidget);
394
395 if (variables.isEmpty() && parentDragDropContainer != ui->dragDropContainer) {
396 // The graph is empty and dropped in a different zone.
397 // Take the range of the first graph in the zone (if existing).
398 auto layout = ui->dragDropContainer->layout();
399 if (layout->count() > 0) {
400 if (auto visualizationGraphWidget
401 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
402 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
403 }
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());
404 446 }
405 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);
406 473
407 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;
408 482 }
409 483 }
410 484 }
General Comments 1
Under Review
author

Auto status change to "Under Review"

You need to be logged in to leave comments. Login now