##// END OF EJS Templates
drop of variables in the visualization
trabillard -
r850:2e038915a77e
parent child
Show More
@@ -1,349 +1,351
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableController.h>
2 #include <Variable/VariableController.h>
3 #include <Variable/VariableModel.h>
3 #include <Variable/VariableModel.h>
4
4
5 #include <Common/DateUtils.h>
5 #include <Common/DateUtils.h>
6 #include <Common/MimeTypesDef.h>
6 #include <Common/MimeTypesDef.h>
7 #include <Common/StringUtils.h>
7 #include <Common/StringUtils.h>
8
8
9 #include <Data/IDataSeries.h>
9 #include <Data/IDataSeries.h>
10
10
11 #include <QMimeData>
11 #include <QMimeData>
12 #include <QSize>
12 #include <QSize>
13 #include <unordered_map>
13 #include <unordered_map>
14
14
15 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
15 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
16
16
17 namespace {
17 namespace {
18
18
19 // Column indexes
19 // Column indexes
20 const auto NAME_COLUMN = 0;
20 const auto NAME_COLUMN = 0;
21 const auto TSTART_COLUMN = 1;
21 const auto TSTART_COLUMN = 1;
22 const auto TEND_COLUMN = 2;
22 const auto TEND_COLUMN = 2;
23 const auto NBPOINTS_COLUMN = 3;
23 const auto NBPOINTS_COLUMN = 3;
24 const auto UNIT_COLUMN = 4;
24 const auto UNIT_COLUMN = 4;
25 const auto MISSION_COLUMN = 5;
25 const auto MISSION_COLUMN = 5;
26 const auto PLUGIN_COLUMN = 6;
26 const auto PLUGIN_COLUMN = 6;
27 const auto NB_COLUMNS = 7;
27 const auto NB_COLUMNS = 7;
28
28
29 // Column properties
29 // Column properties
30 const auto DEFAULT_HEIGHT = 25;
30 const auto DEFAULT_HEIGHT = 25;
31 const auto DEFAULT_WIDTH = 100;
31 const auto DEFAULT_WIDTH = 100;
32
32
33 struct ColumnProperties {
33 struct ColumnProperties {
34 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
34 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
35 int height = DEFAULT_HEIGHT)
35 int height = DEFAULT_HEIGHT)
36 : m_Name{name}, m_Width{width}, m_Height{height}
36 : m_Name{name}, m_Width{width}, m_Height{height}
37 {
37 {
38 }
38 }
39
39
40 QString m_Name;
40 QString m_Name;
41 int m_Width;
41 int m_Width;
42 int m_Height;
42 int m_Height;
43 };
43 };
44
44
45 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
45 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
46 {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
46 {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
47 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {NBPOINTS_COLUMN, {QObject::tr("Nb points")}},
47 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {NBPOINTS_COLUMN, {QObject::tr("Nb points")}},
48 {UNIT_COLUMN, {QObject::tr("Unit")}}, {MISSION_COLUMN, {QObject::tr("Mission")}},
48 {UNIT_COLUMN, {QObject::tr("Unit")}}, {MISSION_COLUMN, {QObject::tr("Mission")}},
49 {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
49 {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
50
50
51 /// Format for datetimes
51 /// Format for datetimes
52 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
52 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
53
53
54 QString uniqueName(const QString &defaultName,
54 QString uniqueName(const QString &defaultName,
55 const std::vector<std::shared_ptr<Variable> > &variables)
55 const std::vector<std::shared_ptr<Variable> > &variables)
56 {
56 {
57 auto forbiddenNames = std::vector<QString>(variables.size());
57 auto forbiddenNames = std::vector<QString>(variables.size());
58 std::transform(variables.cbegin(), variables.cend(), forbiddenNames.begin(),
58 std::transform(variables.cbegin(), variables.cend(), forbiddenNames.begin(),
59 [](const auto &variable) { return variable->name(); });
59 [](const auto &variable) { return variable->name(); });
60 auto uniqueName = StringUtils::uniqueName(defaultName, forbiddenNames);
60 auto uniqueName = StringUtils::uniqueName(defaultName, forbiddenNames);
61 Q_ASSERT(!uniqueName.isEmpty());
61 Q_ASSERT(!uniqueName.isEmpty());
62
62
63 return uniqueName;
63 return uniqueName;
64 }
64 }
65
65
66 } // namespace
66 } // namespace
67
67
68 struct VariableModel::VariableModelPrivate {
68 struct VariableModel::VariableModelPrivate {
69 /// Variables created in SciQlop
69 /// Variables created in SciQlop
70 std::vector<std::shared_ptr<Variable> > m_Variables;
70 std::vector<std::shared_ptr<Variable> > m_Variables;
71 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
71 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
72 VariableController *m_VariableController;
72 VariableController *m_VariableController;
73
73
74 /// Return the row index of the variable. -1 if it's not found
74 /// Return the row index of the variable. -1 if it's not found
75 int indexOfVariable(Variable *variable) const noexcept;
75 int indexOfVariable(Variable *variable) const noexcept;
76 };
76 };
77
77
78 VariableModel::VariableModel(VariableController *parent)
78 VariableModel::VariableModel(VariableController *parent)
79 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
79 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
80 {
80 {
81 impl->m_VariableController = parent;
81 impl->m_VariableController = parent;
82 }
82 }
83
83
84 void VariableModel::addVariable(std::shared_ptr<Variable> variable) noexcept
84 void VariableModel::addVariable(std::shared_ptr<Variable> variable) noexcept
85 {
85 {
86 auto insertIndex = rowCount();
86 auto insertIndex = rowCount();
87 beginInsertRows({}, insertIndex, insertIndex);
87 beginInsertRows({}, insertIndex, insertIndex);
88
88
89 // Generates unique name for the variable
89 // Generates unique name for the variable
90 variable->setName(uniqueName(variable->name(), impl->m_Variables));
90 variable->setName(uniqueName(variable->name(), impl->m_Variables));
91
91
92 impl->m_Variables.push_back(variable);
92 impl->m_Variables.push_back(variable);
93 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
93 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
94
94
95 endInsertRows();
95 endInsertRows();
96 }
96 }
97
97
98 bool VariableModel::containsVariable(std::shared_ptr<Variable> variable) const noexcept
98 bool VariableModel::containsVariable(std::shared_ptr<Variable> variable) const noexcept
99 {
99 {
100 auto end = impl->m_Variables.cend();
100 auto end = impl->m_Variables.cend();
101 return std::find(impl->m_Variables.cbegin(), end, variable) != end;
101 return std::find(impl->m_Variables.cbegin(), end, variable) != end;
102 }
102 }
103
103
104 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
104 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
105 const QVariantHash &metadata) noexcept
105 const QVariantHash &metadata) noexcept
106 {
106 {
107 auto variable = std::make_shared<Variable>(name, metadata);
107 auto variable = std::make_shared<Variable>(name, metadata);
108 addVariable(variable);
108 addVariable(variable);
109
109
110 return variable;
110 return variable;
111 }
111 }
112
112
113 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
113 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
114 {
114 {
115 if (!variable) {
115 if (!variable) {
116 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
116 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
117 return;
117 return;
118 }
118 }
119
119
120 // Finds variable in the model
120 // Finds variable in the model
121 auto begin = impl->m_Variables.cbegin();
121 auto begin = impl->m_Variables.cbegin();
122 auto end = impl->m_Variables.cend();
122 auto end = impl->m_Variables.cend();
123 auto it = std::find(begin, end, variable);
123 auto it = std::find(begin, end, variable);
124 if (it != end) {
124 if (it != end) {
125 auto removeIndex = std::distance(begin, it);
125 auto removeIndex = std::distance(begin, it);
126
126
127 // Deletes variable
127 // Deletes variable
128 beginRemoveRows({}, removeIndex, removeIndex);
128 beginRemoveRows({}, removeIndex, removeIndex);
129 impl->m_Variables.erase(it);
129 impl->m_Variables.erase(it);
130 endRemoveRows();
130 endRemoveRows();
131 }
131 }
132 else {
132 else {
133 qCritical(LOG_VariableModel())
133 qCritical(LOG_VariableModel())
134 << tr("Can't delete variable %1 from the model: the variable is not in the model")
134 << tr("Can't delete variable %1 from the model: the variable is not in the model")
135 .arg(variable->name());
135 .arg(variable->name());
136 }
136 }
137
137
138 // Removes variable from progress map
138 // Removes variable from progress map
139 impl->m_VariableToProgress.erase(variable);
139 impl->m_VariableToProgress.erase(variable);
140 }
140 }
141
141
142
142
143 std::shared_ptr<Variable> VariableModel::variable(int index) const
143 std::shared_ptr<Variable> VariableModel::variable(int index) const
144 {
144 {
145 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
145 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
146 }
146 }
147
147
148 std::vector<std::shared_ptr<Variable> > VariableModel::variables() const
148 std::vector<std::shared_ptr<Variable> > VariableModel::variables() const
149 {
149 {
150 return impl->m_Variables;
150 return impl->m_Variables;
151 }
151 }
152
152
153 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
153 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
154 {
154 {
155 if (progress > 0.0) {
155 if (progress > 0.0) {
156 impl->m_VariableToProgress[variable] = progress;
156 impl->m_VariableToProgress[variable] = progress;
157 }
157 }
158 else {
158 else {
159 impl->m_VariableToProgress.erase(variable);
159 impl->m_VariableToProgress.erase(variable);
160 }
160 }
161 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
161 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
162
162
163 emit dataChanged(modelIndex, modelIndex);
163 emit dataChanged(modelIndex, modelIndex);
164 }
164 }
165
165
166 int VariableModel::columnCount(const QModelIndex &parent) const
166 int VariableModel::columnCount(const QModelIndex &parent) const
167 {
167 {
168 Q_UNUSED(parent);
168 Q_UNUSED(parent);
169
169
170 return NB_COLUMNS;
170 return NB_COLUMNS;
171 }
171 }
172
172
173 int VariableModel::rowCount(const QModelIndex &parent) const
173 int VariableModel::rowCount(const QModelIndex &parent) const
174 {
174 {
175 Q_UNUSED(parent);
175 Q_UNUSED(parent);
176
176
177 return impl->m_Variables.size();
177 return impl->m_Variables.size();
178 }
178 }
179
179
180 QVariant VariableModel::data(const QModelIndex &index, int role) const
180 QVariant VariableModel::data(const QModelIndex &index, int role) const
181 {
181 {
182 if (!index.isValid()) {
182 if (!index.isValid()) {
183 return QVariant{};
183 return QVariant{};
184 }
184 }
185
185
186 if (index.row() < 0 || index.row() >= rowCount()) {
186 if (index.row() < 0 || index.row() >= rowCount()) {
187 return QVariant{};
187 return QVariant{};
188 }
188 }
189
189
190 if (role == Qt::DisplayRole) {
190 if (role == Qt::DisplayRole) {
191 if (auto variable = impl->m_Variables.at(index.row()).get()) {
191 if (auto variable = impl->m_Variables.at(index.row()).get()) {
192 switch (index.column()) {
192 switch (index.column()) {
193 case NAME_COLUMN:
193 case NAME_COLUMN:
194 return variable->name();
194 return variable->name();
195 case TSTART_COLUMN: {
195 case TSTART_COLUMN: {
196 auto range = variable->realRange();
196 auto range = variable->realRange();
197 return range != INVALID_RANGE
197 return range != INVALID_RANGE
198 ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT)
198 ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT)
199 : QVariant{};
199 : QVariant{};
200 }
200 }
201 case TEND_COLUMN: {
201 case TEND_COLUMN: {
202 auto range = variable->realRange();
202 auto range = variable->realRange();
203 return range != INVALID_RANGE
203 return range != INVALID_RANGE
204 ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT)
204 ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT)
205 : QVariant{};
205 : QVariant{};
206 }
206 }
207 case NBPOINTS_COLUMN:
207 case NBPOINTS_COLUMN:
208 return variable->nbPoints();
208 return variable->nbPoints();
209 case UNIT_COLUMN:
209 case UNIT_COLUMN:
210 return variable->metadata().value(QStringLiteral("units"));
210 return variable->metadata().value(QStringLiteral("units"));
211 case MISSION_COLUMN:
211 case MISSION_COLUMN:
212 return variable->metadata().value(QStringLiteral("mission"));
212 return variable->metadata().value(QStringLiteral("mission"));
213 case PLUGIN_COLUMN:
213 case PLUGIN_COLUMN:
214 return variable->metadata().value(QStringLiteral("plugin"));
214 return variable->metadata().value(QStringLiteral("plugin"));
215 default:
215 default:
216 // No action
216 // No action
217 break;
217 break;
218 }
218 }
219
219
220 qWarning(LOG_VariableModel())
220 qWarning(LOG_VariableModel())
221 << tr("Can't get data (unknown column %1)").arg(index.column());
221 << tr("Can't get data (unknown column %1)").arg(index.column());
222 }
222 }
223 else {
223 else {
224 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
224 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
225 }
225 }
226 }
226 }
227 else if (role == VariableRoles::ProgressRole) {
227 else if (role == VariableRoles::ProgressRole) {
228 if (auto variable = impl->m_Variables.at(index.row())) {
228 if (auto variable = impl->m_Variables.at(index.row())) {
229
229
230 auto it = impl->m_VariableToProgress.find(variable);
230 auto it = impl->m_VariableToProgress.find(variable);
231 if (it != impl->m_VariableToProgress.cend()) {
231 if (it != impl->m_VariableToProgress.cend()) {
232 return it->second;
232 return it->second;
233 }
233 }
234 }
234 }
235 }
235 }
236
236
237 return QVariant{};
237 return QVariant{};
238 }
238 }
239
239
240 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
240 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
241 {
241 {
242 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
242 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
243 return QVariant{};
243 return QVariant{};
244 }
244 }
245
245
246 if (orientation == Qt::Horizontal) {
246 if (orientation == Qt::Horizontal) {
247 auto propertiesIt = COLUMN_PROPERTIES.find(section);
247 auto propertiesIt = COLUMN_PROPERTIES.find(section);
248 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
248 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
249 // Role is either DisplayRole or SizeHintRole
249 // Role is either DisplayRole or SizeHintRole
250 return (role == Qt::DisplayRole)
250 return (role == Qt::DisplayRole)
251 ? QVariant{propertiesIt->m_Name}
251 ? QVariant{propertiesIt->m_Name}
252 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
252 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
253 }
253 }
254 else {
254 else {
255 qWarning(LOG_VariableModel())
255 qWarning(LOG_VariableModel())
256 << tr("Can't get header data (unknown column %1)").arg(section);
256 << tr("Can't get header data (unknown column %1)").arg(section);
257 }
257 }
258 }
258 }
259
259
260 return QVariant{};
260 return QVariant{};
261 }
261 }
262
262
263 Qt::ItemFlags VariableModel::flags(const QModelIndex &index) const
263 Qt::ItemFlags VariableModel::flags(const QModelIndex &index) const
264 {
264 {
265 return QAbstractTableModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
265 return QAbstractTableModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
266 }
266 }
267
267
268 Qt::DropActions VariableModel::supportedDropActions() const
268 Qt::DropActions VariableModel::supportedDropActions() const
269 {
269 {
270 return Qt::MoveAction;
270 return Qt::MoveAction;
271 }
271 }
272
272
273 Qt::DropActions VariableModel::supportedDragActions() const
273 Qt::DropActions VariableModel::supportedDragActions() const
274 {
274 {
275 return Qt::CopyAction | Qt::MoveAction;
275 return Qt::CopyAction | Qt::MoveAction;
276 }
276 }
277
277
278 QStringList VariableModel::mimeTypes() const
278 QStringList VariableModel::mimeTypes() const
279 {
279 {
280 return {MIME_TYPE_VARIABLE_LIST};
280 return {MIME_TYPE_VARIABLE_LIST};
281 }
281 }
282
282
283 QMimeData *VariableModel::mimeData(const QModelIndexList &indexes) const
283 QMimeData *VariableModel::mimeData(const QModelIndexList &indexes) const
284 {
284 {
285 auto mimeData = new QMimeData;
285 auto mimeData = new QMimeData;
286
286
287 QList<std::shared_ptr<Variable> > variableList;
287 QList<std::shared_ptr<Variable> > variableList;
288
288
289 for (const auto &index : indexes) {
289 for (const auto &index : indexes) {
290 auto variable = impl->m_Variables.at(index.row());
290 if (index.column() == 0) { // only the first column
291 if (variable.get() && index.isValid()) {
291 auto variable = impl->m_Variables.at(index.row());
292 variableList << variable;
292 if (variable.get() && index.isValid()) {
293 variableList << variable;
294 }
293 }
295 }
294 }
296 }
295
297
296 auto encodedData = impl->m_VariableController->mimeDataForVariables(variableList);
298 auto encodedData = impl->m_VariableController->mimeDataForVariables(variableList);
297 mimeData->setData(MIME_TYPE_VARIABLE_LIST, encodedData);
299 mimeData->setData(MIME_TYPE_VARIABLE_LIST, encodedData);
298
300
299 return mimeData;
301 return mimeData;
300 }
302 }
301
303
302 bool VariableModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
304 bool VariableModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
303 int column, const QModelIndex &parent) const
305 int column, const QModelIndex &parent) const
304 {
306 {
305 return false;
307 return false;
306 }
308 }
307
309
308 bool VariableModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
310 bool VariableModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
309 const QModelIndex &parent)
311 const QModelIndex &parent)
310 {
312 {
311 return false;
313 return false;
312 }
314 }
313
315
314 void VariableModel::abortProgress(const QModelIndex &index)
316 void VariableModel::abortProgress(const QModelIndex &index)
315 {
317 {
316 if (auto variable = impl->m_Variables.at(index.row())) {
318 if (auto variable = impl->m_Variables.at(index.row())) {
317 emit abortProgessRequested(variable);
319 emit abortProgessRequested(variable);
318 }
320 }
319 }
321 }
320
322
321 void VariableModel::onVariableUpdated() noexcept
323 void VariableModel::onVariableUpdated() noexcept
322 {
324 {
323 // Finds variable that has been updated in the model
325 // Finds variable that has been updated in the model
324 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
326 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
325 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
327 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
326
328
327 if (updatedVariableIndex > -1) {
329 if (updatedVariableIndex > -1) {
328 emit dataChanged(createIndex(updatedVariableIndex, 0),
330 emit dataChanged(createIndex(updatedVariableIndex, 0),
329 createIndex(updatedVariableIndex, columnCount() - 1));
331 createIndex(updatedVariableIndex, columnCount() - 1));
330 }
332 }
331 }
333 }
332 }
334 }
333
335
334 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
336 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
335 {
337 {
336 auto begin = std::cbegin(m_Variables);
338 auto begin = std::cbegin(m_Variables);
337 auto end = std::cend(m_Variables);
339 auto end = std::cend(m_Variables);
338 auto it
340 auto it
339 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
341 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
340
342
341 if (it != end) {
343 if (it != end) {
342 // Gets the index of the variable in the model: we assume here that views have the same
344 // Gets the index of the variable in the model: we assume here that views have the same
343 // order as the model
345 // order as the model
344 return std::distance(begin, it);
346 return std::distance(begin, it);
345 }
347 }
346 else {
348 else {
347 return -1;
349 return -1;
348 }
350 }
349 }
351 }
@@ -1,65 +1,85
1 #ifndef SCIQLOP_DRAGDROPHELPER_H
1 #ifndef SCIQLOP_DRAGDROPHELPER_H
2 #define SCIQLOP_DRAGDROPHELPER_H
2 #define SCIQLOP_DRAGDROPHELPER_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QLoggingCategory>
5 #include <QWidget>
6 #include <QWidget>
6
7
7 class QVBoxLayout;
8 class QVBoxLayout;
8 class QScrollArea;
9 class QScrollArea;
9 class VisualizationDragWidget;
10 class VisualizationDragWidget;
11 class VisualizationDragDropContainer;
10 class QMimeData;
12 class QMimeData;
11
13
12 /**
14 Q_DECLARE_LOGGING_CATEGORY(LOG_DragDropHelper)
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 };
35
15
36 /**
16 /**
37 * @brief Helper class for drag&drop operations.
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 class DragDropHelper {
23 class DragDropHelper {
40 public:
24 public:
41 static const QString MIME_TYPE_GRAPH;
25 static const QString MIME_TYPE_GRAPH;
42 static const QString MIME_TYPE_ZONE;
26 static const QString MIME_TYPE_ZONE;
43
27
44 DragDropHelper();
28 DragDropHelper();
45 virtual ~DragDropHelper();
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 void setCurrentDragWidget(VisualizationDragWidget *dragWidget);
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 VisualizationDragWidget *getCurrentDragWidget() const;
40 VisualizationDragWidget *getCurrentDragWidget() const;
49
41
50 QWidget &placeHolder() const;
42 QWidget &placeHolder() const;
51 void insertPlaceHolder(QVBoxLayout *layout, int index);
43 void insertPlaceHolder(QVBoxLayout *layout, int index);
52 void removePlaceHolder();
44 void removePlaceHolder();
53 bool isPlaceHolderSet() const;
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 void addDragDropScrollArea(QScrollArea *scrollArea);
51 void addDragDropScrollArea(QScrollArea *scrollArea);
56 void removeDragDropScrollArea(QScrollArea *scrollArea);
52 void removeDragDropScrollArea(QScrollArea *scrollArea);
57
53
58 QUrl imageTemporaryUrl(const QImage &image) const;
54 QUrl imageTemporaryUrl(const QImage &image) const;
59
55
60 private:
56 private:
61 class DragDropHelperPrivate;
57 class DragDropHelperPrivate;
62 spimpl::unique_impl_ptr<DragDropHelperPrivate> impl;
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 #endif // SCIQLOP_DRAGDROPHELPER_H
85 #endif // SCIQLOP_DRAGDROPHELPER_H
@@ -1,56 +1,57
1 #ifndef SCIQLOP_SQPAPPLICATION_H
1 #ifndef SCIQLOP_SQPAPPLICATION_H
2 #define SCIQLOP_SQPAPPLICATION_H
2 #define SCIQLOP_SQPAPPLICATION_H
3
3
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5
5
6 #include <QApplication>
6 #include <QApplication>
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8
8
9 #include <Common/spimpl.h>
9 #include <Common/spimpl.h>
10
10
11 Q_DECLARE_LOGGING_CATEGORY(LOG_SqpApplication)
11 Q_DECLARE_LOGGING_CATEGORY(LOG_SqpApplication)
12
12
13 #if defined(sqpApp)
13 #if defined(sqpApp)
14 #undef sqpApp
14 #undef sqpApp
15 #endif
15 #endif
16 #define sqpApp (static_cast<SqpApplication *>(QCoreApplication::instance()))
16 #define sqpApp (static_cast<SqpApplication *>(QCoreApplication::instance()))
17
17
18 class DataSourceController;
18 class DataSourceController;
19 class NetworkController;
19 class NetworkController;
20 class TimeController;
20 class TimeController;
21 class VariableController;
21 class VariableController;
22 class VisualizationController;
22 class VisualizationController;
23 class DragDropHelper;
23 class DragDropHelper;
24
24
25 /**
25 /**
26 * @brief The SqpApplication class aims to make the link between SciQlop
26 * @brief The SqpApplication class aims to make the link between SciQlop
27 * and its plugins. This is the intermediate class that SciQlop has to use
27 * and its plugins. This is the intermediate class that SciQlop has to use
28 * in the way to connect a data source. Please first use load method to initialize
28 * in the way to connect a data source. Please first use load method to initialize
29 * a plugin specified by its metadata name (JSON plugin source) then others specifics
29 * a plugin specified by its metadata name (JSON plugin source) then others specifics
30 * method will be able to access it.
30 * method will be able to access it.
31 * You can load a data source driver plugin then create a data source.
31 * You can load a data source driver plugin then create a data source.
32 */
32 */
33
33
34 class SqpApplication : public QApplication {
34 class SqpApplication : public QApplication {
35 Q_OBJECT
35 Q_OBJECT
36 public:
36 public:
37 explicit SqpApplication(int &argc, char **argv);
37 explicit SqpApplication(int &argc, char **argv);
38 virtual ~SqpApplication();
38 virtual ~SqpApplication();
39 void initialize();
39 void initialize();
40
40
41 /// Accessors for the differents sciqlop controllers
41 /// Accessors for the differents sciqlop controllers
42 DataSourceController &dataSourceController() noexcept;
42 DataSourceController &dataSourceController() noexcept;
43 NetworkController &networkController() noexcept;
43 NetworkController &networkController() noexcept;
44 TimeController &timeController() noexcept;
44 TimeController &timeController() noexcept;
45 VariableController &variableController() noexcept;
45 VariableController &variableController() noexcept;
46 VisualizationController &visualizationController() noexcept;
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 DragDropHelper &dragDropHelper() noexcept;
50 DragDropHelper &dragDropHelper() noexcept;
50
51
51 private:
52 private:
52 class SqpApplicationPrivate;
53 class SqpApplicationPrivate;
53 spimpl::unique_impl_ptr<SqpApplicationPrivate> impl;
54 spimpl::unique_impl_ptr<SqpApplicationPrivate> impl;
54 };
55 };
55
56
56 #endif // SCIQLOP_SQPAPPLICATION_H
57 #endif // SCIQLOP_SQPAPPLICATION_H
@@ -1,42 +1,51
1 #ifndef SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
1 #ifndef SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
2 #define SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
2 #define SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QLoggingCategory>
5 #include <QMimeData>
6 #include <QMimeData>
6 #include <QVBoxLayout>
7 #include <QVBoxLayout>
7 #include <QWidget>
8 #include <QWidget>
8
9
10 #include <functional>
11
12 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer)
13
9 class VisualizationDragWidget;
14 class VisualizationDragWidget;
10
15
11 class VisualizationDragDropContainer : public QWidget {
16 class VisualizationDragDropContainer : public QWidget {
12 Q_OBJECT
17 Q_OBJECT
13
18
14 signals:
19 signals:
15 void dropOccured(int dropIndex, const QMimeData *mimeData);
20 void dropOccured(int dropIndex, const QMimeData *mimeData);
16
21
17 public:
22 public:
23 using AcceptMimeDataFunction = std::function<bool(const QMimeData *mimeData)>;
24
18 VisualizationDragDropContainer(QWidget *parent = nullptr);
25 VisualizationDragDropContainer(QWidget *parent = nullptr);
19
26
20 void addDragWidget(VisualizationDragWidget *dragWidget);
27 void addDragWidget(VisualizationDragWidget *dragWidget);
21 void insertDragWidget(int index, VisualizationDragWidget *dragWidget);
28 void insertDragWidget(int index, VisualizationDragWidget *dragWidget);
22
29
23 void setAcceptedMimeTypes(const QStringList &mimeTypes);
30 void setAcceptedMimeTypes(const QStringList &mimeTypes);
24 void setMergeAllowedMimeTypes(const QStringList &mimeTypes);
31 void setMergeAllowedMimeTypes(const QStringList &mimeTypes);
25
32
26 int countDragWidget() const;
33 int countDragWidget() const;
27
34
35 void setAcceptMimeDataFunction(AcceptMimeDataFunction fun);
36
28 protected:
37 protected:
29 void dragEnterEvent(QDragEnterEvent *event);
38 void dragEnterEvent(QDragEnterEvent *event);
30 void dragLeaveEvent(QDragLeaveEvent *event);
39 void dragLeaveEvent(QDragLeaveEvent *event);
31 void dragMoveEvent(QDragMoveEvent *event);
40 void dragMoveEvent(QDragMoveEvent *event);
32 void dropEvent(QDropEvent *event);
41 void dropEvent(QDropEvent *event);
33
42
34 private:
43 private:
35 class VisualizationDragDropContainerPrivate;
44 class VisualizationDragDropContainerPrivate;
36 spimpl::unique_impl_ptr<VisualizationDragDropContainerPrivate> impl;
45 spimpl::unique_impl_ptr<VisualizationDragDropContainerPrivate> impl;
37
46
38 private slots:
47 private slots:
39 void startDrag(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
48 void startDrag(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
40 };
49 };
41
50
42 #endif // SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
51 #endif // SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
@@ -1,227 +1,289
1 #include "DragDropHelper.h"
1 #include "DragDropHelper.h"
2 #include "SqpApplication.h"
2 #include "SqpApplication.h"
3 #include "Visualization/VisualizationDragDropContainer.h"
3 #include "Visualization/VisualizationDragWidget.h"
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 #include <QDir>
13 #include <QDir>
6 #include <QDragEnterEvent>
14 #include <QDragEnterEvent>
7 #include <QDragMoveEvent>
15 #include <QDragMoveEvent>
8 #include <QScrollArea>
16 #include <QScrollArea>
9 #include <QScrollBar>
17 #include <QScrollBar>
10 #include <QTimer>
18 #include <QTimer>
11 #include <QVBoxLayout>
19 #include <QVBoxLayout>
12
20
13 const int SCROLL_SPEED = 5;
21 const int SCROLL_SPEED = 5;
14 const int SCROLL_ZONE_SIZE = 50;
22 const int SCROLL_ZONE_SIZE = 50;
15
23
24 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
25
16 struct DragDropScroller::DragDropScrollerPrivate {
26 struct DragDropScroller::DragDropScrollerPrivate {
17
27
18 QList<QScrollArea *> m_ScrollAreas;
28 QList<QScrollArea *> m_ScrollAreas;
19 QScrollArea *m_CurrentScrollArea = nullptr;
29 QScrollArea *m_CurrentScrollArea = nullptr;
20 std::unique_ptr<QTimer> m_Timer = nullptr;
30 std::unique_ptr<QTimer> m_Timer = nullptr;
21
31
22
32
23 enum class ScrollDirection { up, down, unknown };
33 enum class ScrollDirection { up, down, unknown };
24 ScrollDirection m_Direction = ScrollDirection::unknown;
34 ScrollDirection m_Direction = ScrollDirection::unknown;
25
35
26 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
36 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
27 {
37 {
28 m_Timer->setInterval(0);
38 m_Timer->setInterval(0);
29 }
39 }
30 };
40 };
31
41
32 DragDropScroller::DragDropScroller(QObject *parent)
42 DragDropScroller::DragDropScroller(QObject *parent)
33 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
43 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
34 {
44 {
35 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
45 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
36 }
46 }
37
47
38 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
48 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
39 {
49 {
40 impl->m_ScrollAreas << scrollArea;
50 impl->m_ScrollAreas << scrollArea;
41 scrollArea->viewport()->setAcceptDrops(true);
51 scrollArea->viewport()->setAcceptDrops(true);
42 }
52 }
43
53
44 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
54 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
45 {
55 {
46 impl->m_ScrollAreas.removeAll(scrollArea);
56 impl->m_ScrollAreas.removeAll(scrollArea);
47 scrollArea->viewport()->setAcceptDrops(false);
57 scrollArea->viewport()->setAcceptDrops(false);
48 }
58 }
49
59
50 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
60 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
51 {
61 {
52 if (event->type() == QEvent::DragMove) {
62 if (event->type() == QEvent::DragMove) {
53 auto w = static_cast<QWidget *>(obj);
63 auto w = static_cast<QWidget *>(obj);
54
64
55 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
65 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
56 auto moveEvent = static_cast<QDragMoveEvent *>(event);
66 auto moveEvent = static_cast<QDragMoveEvent *>(event);
57
67
58 auto pos = moveEvent->pos();
68 auto pos = moveEvent->pos();
59 if (impl->m_CurrentScrollArea->viewport() != w) {
69 if (impl->m_CurrentScrollArea->viewport() != w) {
60 auto globalPos = w->mapToGlobal(moveEvent->pos());
70 auto globalPos = w->mapToGlobal(moveEvent->pos());
61 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
71 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
62 }
72 }
63
73
64 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
74 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
65 - SCROLL_ZONE_SIZE;
75 - SCROLL_ZONE_SIZE;
66 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
76 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
67
77
68 if (!isInTopZone && !isInBottomZone) {
78 if (!isInTopZone && !isInBottomZone) {
69 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
79 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
70 impl->m_Timer->stop();
80 impl->m_Timer->stop();
71 }
81 }
72 else if (!impl->m_Timer->isActive()) {
82 else if (!impl->m_Timer->isActive()) {
73 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
83 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
74 : DragDropScrollerPrivate::ScrollDirection::down;
84 : DragDropScrollerPrivate::ScrollDirection::down;
75 impl->m_Timer->start();
85 impl->m_Timer->start();
76 }
86 }
77 }
87 }
78 }
88 }
79 else if (event->type() == QEvent::DragEnter) {
89 else if (event->type() == QEvent::DragEnter) {
80 auto w = static_cast<QWidget *>(obj);
90 auto w = static_cast<QWidget *>(obj);
81
91
82 for (auto scrollArea : impl->m_ScrollAreas) {
92 for (auto scrollArea : impl->m_ScrollAreas) {
83 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
93 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
84 auto enterEvent = static_cast<QDragEnterEvent *>(event);
94 auto enterEvent = static_cast<QDragEnterEvent *>(event);
85 enterEvent->acceptProposedAction();
95 enterEvent->acceptProposedAction();
86 enterEvent->setDropAction(Qt::IgnoreAction);
96 enterEvent->setDropAction(Qt::IgnoreAction);
87 impl->m_CurrentScrollArea = scrollArea;
97 impl->m_CurrentScrollArea = scrollArea;
88 break;
98 break;
89 }
99 }
90 }
100 }
91 }
101 }
92 else if (event->type() == QEvent::DragLeave) {
102 else if (event->type() == QEvent::DragLeave) {
93 if (impl->m_CurrentScrollArea) {
103 if (impl->m_CurrentScrollArea) {
94 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
104 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
95 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
105 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
96 impl->m_CurrentScrollArea = nullptr;
106 impl->m_CurrentScrollArea = nullptr;
97 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
107 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
98 impl->m_Timer->stop();
108 impl->m_Timer->stop();
99 }
109 }
100 }
110 }
101 }
111 }
102 else if (event->type() == QEvent::Drop) {
112 else if (event->type() == QEvent::Drop) {
103 if (impl->m_CurrentScrollArea) {
113 if (impl->m_CurrentScrollArea) {
104 impl->m_CurrentScrollArea = nullptr;
114 impl->m_CurrentScrollArea = nullptr;
105 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
115 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
106 impl->m_Timer->stop();
116 impl->m_Timer->stop();
107 }
117 }
108 }
118 }
109
119
110 return false;
120 return false;
111 }
121 }
112
122
113 void DragDropScroller::onTimer()
123 void DragDropScroller::onTimer()
114 {
124 {
115 if (impl->m_CurrentScrollArea) {
125 if (impl->m_CurrentScrollArea) {
116 auto mvt = 0;
126 auto mvt = 0;
117 switch (impl->m_Direction) {
127 switch (impl->m_Direction) {
118 case DragDropScrollerPrivate::ScrollDirection::up:
128 case DragDropScrollerPrivate::ScrollDirection::up:
119 mvt = SCROLL_SPEED;
129 mvt = SCROLL_SPEED;
120 break;
130 break;
121 case DragDropScrollerPrivate::ScrollDirection::down:
131 case DragDropScrollerPrivate::ScrollDirection::down:
122 mvt = -SCROLL_SPEED;
132 mvt = -SCROLL_SPEED;
123 break;
133 break;
124 default:
134 default:
125 break;
135 break;
126 }
136 }
127
137
128 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
138 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
129 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
139 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
130 }
140 }
131 }
141 }
132
142
133 struct DragDropHelper::DragDropHelperPrivate {
143 struct DragDropHelper::DragDropHelperPrivate {
134
144
135 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
145 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
136 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
146 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
137 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
147 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
138 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
148 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
139 // QTemporaryFile to have a name which is not generated.
149 // QTemporaryFile to have a name which is not generated.
140
150
141 explicit DragDropHelperPrivate()
151 explicit DragDropHelperPrivate()
142 : m_PlaceHolder{std::make_unique<QWidget>()},
152 : m_PlaceHolder{std::make_unique<QWidget>()},
143 m_DragDropScroller{std::make_unique<DragDropScroller>()}
153 m_DragDropScroller{std::make_unique<DragDropScroller>()}
144 {
154 {
145 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
155 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
146 sqpApp->installEventFilter(m_DragDropScroller.get());
156 sqpApp->installEventFilter(m_DragDropScroller.get());
147
157
148
158
149 m_ImageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png");
159 m_ImageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png");
150 }
160 }
151
161
152 void preparePlaceHolder() const
162 void preparePlaceHolder() const
153 {
163 {
154 if (m_CurrentDragWidget) {
164 if (m_CurrentDragWidget) {
155 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
165 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
156 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
166 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
157 }
167 }
158 else {
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 };
163
177
164
178
165 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
179 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
166 {
180 {
167 }
181 }
168
182
169 DragDropHelper::~DragDropHelper()
183 DragDropHelper::~DragDropHelper()
170 {
184 {
171 QFile::remove(impl->m_ImageTempUrl);
185 QFile::remove(impl->m_ImageTempUrl);
172 }
186 }
173
187
188 void DragDropHelper::resetDragAndDrop()
189 {
190 setCurrentDragWidget(nullptr);
191 }
192
174 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
193 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
175 {
194 {
176 impl->m_CurrentDragWidget = dragWidget;
195 impl->m_CurrentDragWidget = dragWidget;
177 }
196 }
178
197
179 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
198 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
180 {
199 {
181 return impl->m_CurrentDragWidget;
200 return impl->m_CurrentDragWidget;
182 }
201 }
183
202
184
203
185 QWidget &DragDropHelper::placeHolder() const
204 QWidget &DragDropHelper::placeHolder() const
186 {
205 {
187 return *impl->m_PlaceHolder;
206 return *impl->m_PlaceHolder;
188 }
207 }
189
208
190 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
209 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
191 {
210 {
192 removePlaceHolder();
211 removePlaceHolder();
193 impl->preparePlaceHolder();
212 impl->preparePlaceHolder();
194 layout->insertWidget(index, impl->m_PlaceHolder.get());
213 layout->insertWidget(index, impl->m_PlaceHolder.get());
195 impl->m_PlaceHolder->show();
214 impl->m_PlaceHolder->show();
196 }
215 }
197
216
198 void DragDropHelper::removePlaceHolder()
217 void DragDropHelper::removePlaceHolder()
199 {
218 {
200 auto parentWidget = impl->m_PlaceHolder->parentWidget();
219 auto parentWidget = impl->m_PlaceHolder->parentWidget();
201 if (parentWidget) {
220 if (parentWidget) {
202 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
221 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
203 impl->m_PlaceHolder->setParent(nullptr);
222 impl->m_PlaceHolder->setParent(nullptr);
204 impl->m_PlaceHolder->hide();
223 impl->m_PlaceHolder->hide();
205 }
224 }
206 }
225 }
207
226
208 bool DragDropHelper::isPlaceHolderSet() const
227 bool DragDropHelper::isPlaceHolderSet() const
209 {
228 {
210 return impl->m_PlaceHolder->parentWidget();
229 return impl->m_PlaceHolder->parentWidget();
211 }
230 }
212
231
213 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
232 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
214 {
233 {
215 impl->m_DragDropScroller->addScrollArea(scrollArea);
234 impl->m_DragDropScroller->addScrollArea(scrollArea);
216 }
235 }
217
236
218 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
237 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
219 {
238 {
220 impl->m_DragDropScroller->removeScrollArea(scrollArea);
239 impl->m_DragDropScroller->removeScrollArea(scrollArea);
221 }
240 }
222
241
223 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
242 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
224 {
243 {
225 image.save(impl->m_ImageTempUrl);
244 image.save(impl->m_ImageTempUrl);
226 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
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 }
@@ -1,239 +1,245
1 #include <Variable/RenameVariableDialog.h>
1 #include <Variable/RenameVariableDialog.h>
2 #include <Variable/Variable.h>
2 #include <Variable/Variable.h>
3 #include <Variable/VariableController.h>
3 #include <Variable/VariableController.h>
4 #include <Variable/VariableInspectorWidget.h>
4 #include <Variable/VariableInspectorWidget.h>
5 #include <Variable/VariableMenuHeaderWidget.h>
5 #include <Variable/VariableMenuHeaderWidget.h>
6 #include <Variable/VariableModel.h>
6 #include <Variable/VariableModel.h>
7
7
8 #include <ui_VariableInspectorWidget.h>
8 #include <ui_VariableInspectorWidget.h>
9
9
10 #include <QMouseEvent>
10 #include <QMouseEvent>
11 #include <QSortFilterProxyModel>
11 #include <QSortFilterProxyModel>
12 #include <QStyledItemDelegate>
12 #include <QStyledItemDelegate>
13 #include <QWidgetAction>
13 #include <QWidgetAction>
14
14
15 #include <DragDropHelper.h>
15 #include <SqpApplication.h>
16 #include <SqpApplication.h>
16
17
17 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
18 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
18
19
19
20
20 class QProgressBarItemDelegate : public QStyledItemDelegate {
21 class QProgressBarItemDelegate : public QStyledItemDelegate {
21
22
22 public:
23 public:
23 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
24 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
24
25
25 void paint(QPainter *painter, const QStyleOptionViewItem &option,
26 void paint(QPainter *painter, const QStyleOptionViewItem &option,
26 const QModelIndex &index) const
27 const QModelIndex &index) const
27 {
28 {
28 auto data = index.data(Qt::DisplayRole);
29 auto data = index.data(Qt::DisplayRole);
29 auto progressData = index.data(VariableRoles::ProgressRole);
30 auto progressData = index.data(VariableRoles::ProgressRole);
30 if (data.isValid() && progressData.isValid()) {
31 if (data.isValid() && progressData.isValid()) {
31 auto name = data.value<QString>();
32 auto name = data.value<QString>();
32 auto progress = progressData.value<double>();
33 auto progress = progressData.value<double>();
33 if (progress > 0) {
34 if (progress > 0) {
34 auto cancelButtonWidth = 20;
35 auto cancelButtonWidth = 20;
35 auto progressBarOption = QStyleOptionProgressBar{};
36 auto progressBarOption = QStyleOptionProgressBar{};
36 auto progressRect = option.rect;
37 auto progressRect = option.rect;
37 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
38 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
38 progressBarOption.rect = progressRect;
39 progressBarOption.rect = progressRect;
39 progressBarOption.minimum = 0;
40 progressBarOption.minimum = 0;
40 progressBarOption.maximum = 100;
41 progressBarOption.maximum = 100;
41 progressBarOption.progress = progress;
42 progressBarOption.progress = progress;
42 progressBarOption.text
43 progressBarOption.text
43 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
44 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
44 progressBarOption.textVisible = true;
45 progressBarOption.textVisible = true;
45 progressBarOption.textAlignment = Qt::AlignCenter;
46 progressBarOption.textAlignment = Qt::AlignCenter;
46
47
47
48
48 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
49 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
49 painter);
50 painter);
50
51
51 // Cancel button
52 // Cancel button
52 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
53 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
53 option.rect.height());
54 option.rect.height());
54 auto buttonOption = QStyleOptionButton{};
55 auto buttonOption = QStyleOptionButton{};
55 buttonOption.rect = buttonRect;
56 buttonOption.rect = buttonRect;
56 buttonOption.text = "X";
57 buttonOption.text = "X";
57
58
58 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
59 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
59 }
60 }
60 else {
61 else {
61 QStyledItemDelegate::paint(painter, option, index);
62 QStyledItemDelegate::paint(painter, option, index);
62 }
63 }
63 }
64 }
64 else {
65 else {
65 QStyledItemDelegate::paint(painter, option, index);
66 QStyledItemDelegate::paint(painter, option, index);
66 }
67 }
67 }
68 }
68
69
69 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
70 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
70 const QModelIndex &index)
71 const QModelIndex &index)
71 {
72 {
72 if (event->type() == QEvent::MouseButtonRelease) {
73 if (event->type() == QEvent::MouseButtonRelease) {
73 auto data = index.data(Qt::DisplayRole);
74 auto data = index.data(Qt::DisplayRole);
74 auto progressData = index.data(VariableRoles::ProgressRole);
75 auto progressData = index.data(VariableRoles::ProgressRole);
75 if (data.isValid() && progressData.isValid()) {
76 if (data.isValid() && progressData.isValid()) {
76 auto cancelButtonWidth = 20;
77 auto cancelButtonWidth = 20;
77 auto progressRect = option.rect;
78 auto progressRect = option.rect;
78 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
79 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
79 // Cancel button
80 // Cancel button
80 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
81 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
81 option.rect.height());
82 option.rect.height());
82
83
83 auto e = (QMouseEvent *)event;
84 auto e = (QMouseEvent *)event;
84 auto clickX = e->x();
85 auto clickX = e->x();
85 auto clickY = e->y();
86 auto clickY = e->y();
86
87
87 auto x = buttonRect.left(); // the X coordinate
88 auto x = buttonRect.left(); // the X coordinate
88 auto y = buttonRect.top(); // the Y coordinate
89 auto y = buttonRect.top(); // the Y coordinate
89 auto w = buttonRect.width(); // button width
90 auto w = buttonRect.width(); // button width
90 auto h = buttonRect.height(); // button height
91 auto h = buttonRect.height(); // button height
91
92
92 if (clickX > x && clickX < x + w) {
93 if (clickX > x && clickX < x + w) {
93 if (clickY > y && clickY < y + h) {
94 if (clickY > y && clickY < y + h) {
94 auto variableModel = sqpApp->variableController().variableModel();
95 auto variableModel = sqpApp->variableController().variableModel();
95 variableModel->abortProgress(index);
96 variableModel->abortProgress(index);
96 }
97 }
97 return true;
98 return true;
98 }
99 }
99 else {
100 else {
100 return QStyledItemDelegate::editorEvent(event, model, option, index);
101 return QStyledItemDelegate::editorEvent(event, model, option, index);
101 }
102 }
102 }
103 }
103 else {
104 else {
104 return QStyledItemDelegate::editorEvent(event, model, option, index);
105 return QStyledItemDelegate::editorEvent(event, model, option, index);
105 }
106 }
106 }
107 }
107 else {
108 else {
108 return QStyledItemDelegate::editorEvent(event, model, option, index);
109 return QStyledItemDelegate::editorEvent(event, model, option, index);
109 }
110 }
110
111
111
112
112 return QStyledItemDelegate::editorEvent(event, model, option, index);
113 return QStyledItemDelegate::editorEvent(event, model, option, index);
113 }
114 }
114 };
115 };
115
116
116 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
117 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
117 : QWidget{parent},
118 : QWidget{parent},
118 ui{new Ui::VariableInspectorWidget},
119 ui{new Ui::VariableInspectorWidget},
119 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
120 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
120 {
121 {
121 ui->setupUi(this);
122 ui->setupUi(this);
122
123
123 // Sets model for table
124 // Sets model for table
124 // auto sortFilterModel = new QSortFilterProxyModel{this};
125 // auto sortFilterModel = new QSortFilterProxyModel{this};
125 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
126 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
126
127
127 auto variableModel = sqpApp->variableController().variableModel();
128 auto variableModel = sqpApp->variableController().variableModel();
128 ui->tableView->setModel(variableModel);
129 ui->tableView->setModel(variableModel);
129
130
130 // Adds extra signal/slot between view and model, so the view can be updated instantly when
131 // Adds extra signal/slot between view and model, so the view can be updated instantly when
131 // there is a change of data in the model
132 // there is a change of data in the model
132 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
133 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
133 SLOT(refresh()));
134 SLOT(refresh()));
134
135
135 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
136 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
136 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
137 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
137
138
138 // Fixes column sizes
139 // Fixes column sizes
139 auto model = ui->tableView->model();
140 auto model = ui->tableView->model();
140 const auto count = model->columnCount();
141 const auto count = model->columnCount();
141 for (auto i = 0; i < count; ++i) {
142 for (auto i = 0; i < count; ++i) {
142 ui->tableView->setColumnWidth(
143 ui->tableView->setColumnWidth(
143 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
144 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
144 }
145 }
145
146
146 // Sets selection options
147 // Sets selection options
147 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
148 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
148 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
149 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
149
150
150 // Connection to show a menu when right clicking on the tree
151 // Connection to show a menu when right clicking on the tree
151 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
152 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
152 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
153 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
153 &VariableInspectorWidget::onTableMenuRequested);
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 VariableInspectorWidget::~VariableInspectorWidget()
162 VariableInspectorWidget::~VariableInspectorWidget()
157 {
163 {
158 delete ui;
164 delete ui;
159 }
165 }
160
166
161 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
167 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
162 {
168 {
163 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
169 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
164
170
165 // Gets the model to retrieve the underlying selected variables
171 // Gets the model to retrieve the underlying selected variables
166 auto model = sqpApp->variableController().variableModel();
172 auto model = sqpApp->variableController().variableModel();
167 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
173 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
168 for (const auto &selectedRow : qAsConst(selectedRows)) {
174 for (const auto &selectedRow : qAsConst(selectedRows)) {
169 if (auto selectedVariable = model->variable(selectedRow.row())) {
175 if (auto selectedVariable = model->variable(selectedRow.row())) {
170 selectedVariables.push_back(selectedVariable);
176 selectedVariables.push_back(selectedVariable);
171 }
177 }
172 }
178 }
173
179
174 QMenu tableMenu{};
180 QMenu tableMenu{};
175
181
176 // Emits a signal so that potential receivers can populate the menu before displaying it
182 // Emits a signal so that potential receivers can populate the menu before displaying it
177 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
183 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
178
184
179 // Adds menu-specific actions
185 // Adds menu-specific actions
180 if (!selectedVariables.isEmpty()) {
186 if (!selectedVariables.isEmpty()) {
181 tableMenu.addSeparator();
187 tableMenu.addSeparator();
182
188
183 // 'Rename' and 'Duplicate' actions (only if one variable selected)
189 // 'Rename' and 'Duplicate' actions (only if one variable selected)
184 if (selectedVariables.size() == 1) {
190 if (selectedVariables.size() == 1) {
185 auto selectedVariable = selectedVariables.front();
191 auto selectedVariable = selectedVariables.front();
186
192
187 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
193 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
188 {
194 {
189 if (auto var = varW.lock()) {
195 if (auto var = varW.lock()) {
190 sqpApp->variableController().cloneVariable(var);
196 sqpApp->variableController().cloneVariable(var);
191 }
197 }
192 };
198 };
193
199
194 tableMenu.addAction(tr("Duplicate"), duplicateFun);
200 tableMenu.addAction(tr("Duplicate"), duplicateFun);
195
201
196 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), &model, this ]()
202 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), &model, this ]()
197 {
203 {
198 if (auto var = varW.lock()) {
204 if (auto var = varW.lock()) {
199 // Generates forbidden names (names associated to existing variables)
205 // Generates forbidden names (names associated to existing variables)
200 auto allVariables = model->variables();
206 auto allVariables = model->variables();
201 auto forbiddenNames = QVector<QString>(allVariables.size());
207 auto forbiddenNames = QVector<QString>(allVariables.size());
202 std::transform(allVariables.cbegin(), allVariables.cend(),
208 std::transform(allVariables.cbegin(), allVariables.cend(),
203 forbiddenNames.begin(),
209 forbiddenNames.begin(),
204 [](const auto &variable) { return variable->name(); });
210 [](const auto &variable) { return variable->name(); });
205
211
206 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
212 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
207 if (dialog.exec() == QDialog::Accepted) {
213 if (dialog.exec() == QDialog::Accepted) {
208 var->setName(dialog.name());
214 var->setName(dialog.name());
209 }
215 }
210 }
216 }
211 };
217 };
212
218
213 tableMenu.addAction(tr("Rename..."), renameFun);
219 tableMenu.addAction(tr("Rename..."), renameFun);
214 }
220 }
215
221
216 // 'Delete' action
222 // 'Delete' action
217 auto deleteFun = [&selectedVariables]() {
223 auto deleteFun = [&selectedVariables]() {
218 sqpApp->variableController().deleteVariables(selectedVariables);
224 sqpApp->variableController().deleteVariables(selectedVariables);
219 };
225 };
220
226
221 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
227 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
222 }
228 }
223
229
224 if (!tableMenu.isEmpty()) {
230 if (!tableMenu.isEmpty()) {
225 // Generates menu header (inserted before first action)
231 // Generates menu header (inserted before first action)
226 auto firstAction = tableMenu.actions().first();
232 auto firstAction = tableMenu.actions().first();
227 auto headerAction = new QWidgetAction{&tableMenu};
233 auto headerAction = new QWidgetAction{&tableMenu};
228 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
234 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
229 tableMenu.insertAction(firstAction, headerAction);
235 tableMenu.insertAction(firstAction, headerAction);
230
236
231 // Displays menu
237 // Displays menu
232 tableMenu.exec(QCursor::pos());
238 tableMenu.exec(QCursor::pos());
233 }
239 }
234 }
240 }
235
241
236 void VariableInspectorWidget::refresh() noexcept
242 void VariableInspectorWidget::refresh() noexcept
237 {
243 {
238 ui->tableView->viewport()->update();
244 ui->tableView->viewport()->update();
239 }
245 }
@@ -1,302 +1,359
1 #include "Visualization/VisualizationDragDropContainer.h"
1 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "DragDropHelper.h"
2 #include "DragDropHelper.h"
3 #include "SqpApplication.h"
3 #include "SqpApplication.h"
4 #include "Visualization/VisualizationDragWidget.h"
4 #include "Visualization/VisualizationDragWidget.h"
5
5
6 #include <QDrag>
6 #include <QDrag>
7 #include <QDragEnterEvent>
7 #include <QDragEnterEvent>
8 #include <QVBoxLayout>
8 #include <QVBoxLayout>
9
9
10 #include <cmath>
10 #include <cmath>
11 #include <memory>
11 #include <memory>
12
12
13 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
14
13 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
15 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
14
16
15 QVBoxLayout *m_Layout;
17 QVBoxLayout *m_Layout;
16 QStringList m_AcceptedMimeTypes;
18 QStringList m_AcceptedMimeTypes;
17 QStringList m_MergeAllowedMimeTypes;
19 QStringList m_MergeAllowedMimeTypes;
20 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
21 = [](auto mimeData) { return true; };
18
22
19 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
23 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
20 {
24 {
21 m_Layout = new QVBoxLayout(widget);
25 m_Layout = new QVBoxLayout(widget);
22 m_Layout->setContentsMargins(0, 0, 0, 0);
26 m_Layout->setContentsMargins(0, 0, 0, 0);
23 }
27 }
24
28
25 bool acceptMimeData(const QMimeData *data) const
29 bool acceptMimeData(const QMimeData *data) const
26 {
30 {
27 for (const auto &type : m_AcceptedMimeTypes) {
31 for (const auto &type : m_AcceptedMimeTypes) {
28 if (data->hasFormat(type)) {
32 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
29 return true;
33 return true;
30 }
34 }
31 }
35 }
32
36
33 return false;
37 return false;
34 }
38 }
35
39
36 bool allowMergeMimeData(const QMimeData *data) const
40 bool allowMergeMimeData(const QMimeData *data) const
37 {
41 {
38 for (const auto &type : m_MergeAllowedMimeTypes) {
42 for (const auto &type : m_MergeAllowedMimeTypes) {
39 if (data->hasFormat(type)) {
43 if (data->hasFormat(type)) {
40 return true;
44 return true;
41 }
45 }
42 }
46 }
43
47
44 return false;
48 return false;
45 }
49 }
46
50
47 bool hasPlaceHolder() const
51 bool hasPlaceHolder() const
48 {
52 {
49 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
53 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
50 }
54 }
51
55
52 VisualizationDragWidget *getChildDragWidgetAt(QWidget *parent, const QPoint &pos) const
56 VisualizationDragWidget *getChildDragWidgetAt(QWidget *parent, const QPoint &pos) const
53 {
57 {
54 VisualizationDragWidget *dragWidget = nullptr;
58 VisualizationDragWidget *dragWidget = nullptr;
55
59
56 for (auto child : parent->children()) {
60 for (auto child : parent->children()) {
57 auto widget = qobject_cast<VisualizationDragWidget *>(child);
61 auto widget = qobject_cast<VisualizationDragWidget *>(child);
58 if (widget && widget->isVisible()) {
62 if (widget && widget->isVisible()) {
59 if (widget->frameGeometry().contains(pos)) {
63 if (widget->frameGeometry().contains(pos)) {
60 dragWidget = widget;
64 dragWidget = widget;
61 break;
65 break;
62 }
66 }
63 }
67 }
64 }
68 }
65
69
66 return dragWidget;
70 return dragWidget;
67 }
71 }
68
72
69 bool cursorIsInContainer(QWidget *container) const
73 bool cursorIsInContainer(QWidget *container) const
70 {
74 {
71 auto adustNum = 18; // to be safe, in case of scrollbar on the side
75 auto adustNum = 18; // to be safe, in case of scrollbar on the side
72 auto containerRect = QRect(QPoint(), container->contentsRect().size())
76 auto containerRect = QRect(QPoint(), container->contentsRect().size())
73 .adjusted(adustNum, adustNum, -adustNum, -adustNum);
77 .adjusted(adustNum, adustNum, -adustNum, -adustNum);
74 return containerRect.contains(container->mapFromGlobal(QCursor::pos()));
78 return containerRect.contains(container->mapFromGlobal(QCursor::pos()));
75 }
79 }
76 };
80 };
77
81
78 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
82 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
79 : QWidget{parent},
83 : QWidget{parent},
80 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
84 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
81 {
85 {
82 setAcceptDrops(true);
86 setAcceptDrops(true);
83 }
87 }
84
88
85 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
89 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
86 {
90 {
87 impl->m_Layout->addWidget(dragWidget);
91 impl->m_Layout->addWidget(dragWidget);
88 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
92 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
89 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
93 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
90 &VisualizationDragDropContainer::startDrag);
94 &VisualizationDragDropContainer::startDrag);
91 }
95 }
92
96
93 void VisualizationDragDropContainer::insertDragWidget(int index,
97 void VisualizationDragDropContainer::insertDragWidget(int index,
94 VisualizationDragWidget *dragWidget)
98 VisualizationDragWidget *dragWidget)
95 {
99 {
96 impl->m_Layout->insertWidget(index, dragWidget);
100 impl->m_Layout->insertWidget(index, dragWidget);
97 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
101 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
98 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
102 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
99 &VisualizationDragDropContainer::startDrag);
103 &VisualizationDragDropContainer::startDrag);
100 }
104 }
101
105
102 void VisualizationDragDropContainer::setAcceptedMimeTypes(const QStringList &mimeTypes)
106 void VisualizationDragDropContainer::setAcceptedMimeTypes(const QStringList &mimeTypes)
103 {
107 {
104 impl->m_AcceptedMimeTypes = mimeTypes;
108 impl->m_AcceptedMimeTypes = mimeTypes;
105 }
109 }
106
110
107 void VisualizationDragDropContainer::setMergeAllowedMimeTypes(const QStringList &mimeTypes)
111 void VisualizationDragDropContainer::setMergeAllowedMimeTypes(const QStringList &mimeTypes)
108 {
112 {
109 impl->m_MergeAllowedMimeTypes = mimeTypes;
113 impl->m_MergeAllowedMimeTypes = mimeTypes;
110 }
114 }
111
115
112 int VisualizationDragDropContainer::countDragWidget() const
116 int VisualizationDragDropContainer::countDragWidget() const
113 {
117 {
114 auto nbGraph = 0;
118 auto nbGraph = 0;
115 for (auto child : children()) {
119 for (auto child : children()) {
116 if (qobject_cast<VisualizationDragWidget *>(child)) {
120 if (qobject_cast<VisualizationDragWidget *>(child)) {
117 nbGraph += 1;
121 nbGraph += 1;
118 }
122 }
119 }
123 }
120
124
121 return nbGraph;
125 return nbGraph;
122 }
126 }
123
127
128 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
129 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
130 {
131 impl->m_AcceptMimeDataFun = fun;
132 }
133
124 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
134 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
125 const QPoint &dragPosition)
135 const QPoint &dragPosition)
126 {
136 {
127 auto &helper = sqpApp->dragDropHelper();
137 auto &helper = sqpApp->dragDropHelper();
138 helper.resetDragAndDrop();
128
139
129 // Note: The management of the drag object is done by Qt
140 // Note: The management of the drag object is done by Qt
130 auto drag = new QDrag{dragWidget};
141 auto drag = new QDrag{dragWidget};
131 drag->setHotSpot(dragPosition);
142 drag->setHotSpot(dragPosition);
132
143
133 auto mimeData = dragWidget->mimeData();
144 auto mimeData = dragWidget->mimeData();
134 drag->setMimeData(mimeData);
145 drag->setMimeData(mimeData);
135
146
136 auto pixmap = QPixmap(dragWidget->size());
147 auto pixmap = QPixmap(dragWidget->size());
137 dragWidget->render(&pixmap);
148 dragWidget->render(&pixmap);
138 drag->setPixmap(pixmap);
149 drag->setPixmap(pixmap);
139
150
140 auto image = pixmap.toImage();
151 auto image = pixmap.toImage();
141 mimeData->setImageData(image);
152 mimeData->setImageData(image);
142 mimeData->setUrls({helper.imageTemporaryUrl(image)});
153 mimeData->setUrls({helper.imageTemporaryUrl(image)});
143
154
144 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
155 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
145 helper.setCurrentDragWidget(dragWidget);
156 helper.setCurrentDragWidget(dragWidget);
146
157
147 if (impl->cursorIsInContainer(this)) {
158 if (impl->cursorIsInContainer(this)) {
148 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
159 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
149 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex);
160 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex);
150 dragWidget->setVisible(false);
161 dragWidget->setVisible(false);
151 }
162 }
152 }
153
163
154 // Note: The exec() is blocking on windows but not on linux and macOS
164 // Note: The exec() is blocking on windows but not on linux and macOS
155 drag->exec(Qt::MoveAction | Qt::CopyAction);
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 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
174 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
159 {
175 {
160 if (impl->acceptMimeData(event->mimeData())) {
176 if (impl->acceptMimeData(event->mimeData())) {
161 event->acceptProposedAction();
177 event->acceptProposedAction();
162
178
163 auto &helper = sqpApp->dragDropHelper();
179 auto &helper = sqpApp->dragDropHelper();
164
180
165 if (!impl->hasPlaceHolder()) {
181 if (!impl->hasPlaceHolder()) {
166 auto dragWidget = helper.getCurrentDragWidget();
182 auto dragWidget = helper.getCurrentDragWidget();
167 auto parentWidget
183
168 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
184 if (dragWidget) {
169 if (parentWidget) {
185 // If the drag&drop is internal to the visualization, entering the container hide
170 dragWidget->setVisible(false);
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 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
194 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
174
195
175 if (dragWidgetHovered) {
196 if (dragWidgetHovered) {
176 auto hoveredWidgetIndex = impl->m_Layout->indexOf(dragWidgetHovered);
197 auto hoveredWidgetIndex = impl->m_Layout->indexOf(dragWidgetHovered);
177 auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
198
178 if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex) {
199 if (dragWidget) {
179 hoveredWidgetIndex
200 auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
180 += 1; // Correction of the index if the drop occurs in the same container
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 helper.insertPlaceHolder(impl->m_Layout, hoveredWidgetIndex);
209 helper.insertPlaceHolder(impl->m_Layout, hoveredWidgetIndex);
184 }
210 }
185 else {
211 else {
186 helper.insertPlaceHolder(impl->m_Layout, 0);
212 helper.insertPlaceHolder(impl->m_Layout, 0);
187 }
213 }
188 }
214 }
215 else {
216 // do nothing
217 }
189 }
218 }
190 else {
219 else {
191 event->ignore();
220 event->ignore();
192 }
221 }
193
222
194 QWidget::dragEnterEvent(event);
223 QWidget::dragEnterEvent(event);
195 }
224 }
196
225
197 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
226 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
198 {
227 {
199 Q_UNUSED(event);
228 Q_UNUSED(event);
200
229
201 auto &helper = sqpApp->dragDropHelper();
230 auto &helper = sqpApp->dragDropHelper();
202
231
203 if (!impl->cursorIsInContainer(this)) {
232 if (!impl->cursorIsInContainer(this)) {
204 helper.removePlaceHolder();
233 helper.removePlaceHolder();
205
234
206 bool isInternal = true;
235 auto dragWidget = helper.getCurrentDragWidget();
207 if (isInternal) {
236 if (dragWidget) {
208 // Only if the drag is started from the visualization
237 // dragWidget has a value only if the drag is started from the visualization
209 // Show the drag widget at its original place
238 // In that case, shows the drag widget at its original place
210 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
239 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
211 // drop zone (It is not possible to catch a drop event outside of the application)
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 if (dragWidget) {
242 if (dragWidget) {
215 dragWidget->setVisible(true);
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 QWidget::dragLeaveEvent(event);
253 QWidget::dragLeaveEvent(event);
221 }
254 }
222
255
223 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
256 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
224 {
257 {
225 if (impl->acceptMimeData(event->mimeData())) {
258 if (impl->acceptMimeData(event->mimeData())) {
226 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
259 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
227 if (dragWidgetHovered) {
260 if (dragWidgetHovered) {
228 auto canMerge = impl->allowMergeMimeData(event->mimeData());
261 auto canMerge = impl->allowMergeMimeData(event->mimeData());
229
262
230 auto nbDragWidget = countDragWidget();
263 auto nbDragWidget = countDragWidget();
231 if (nbDragWidget > 0) {
264 if (nbDragWidget > 0) {
232 auto graphHeight = size().height() / nbDragWidget;
265 auto graphHeight = size().height() / nbDragWidget;
233 auto dropIndex = floor(event->pos().y() / graphHeight);
266 auto dropIndex = floor(event->pos().y() / graphHeight);
234 auto zoneSize = qMin(graphHeight / 3.0, 150.0);
267 auto zoneSize = qMin(graphHeight / 3.0, 150.0);
235
268
236 auto isOnTop = event->pos().y() < dropIndex * graphHeight + zoneSize;
269 auto isOnTop = event->pos().y() < dropIndex * graphHeight + zoneSize;
237 auto isOnBottom = event->pos().y() > (dropIndex + 1) * graphHeight - zoneSize;
270 auto isOnBottom = event->pos().y() > (dropIndex + 1) * graphHeight - zoneSize;
238
271
239 auto &helper = sqpApp->dragDropHelper();
272 auto &helper = sqpApp->dragDropHelper();
240 auto placeHolderIndex = impl->m_Layout->indexOf(&(helper.placeHolder()));
273 auto placeHolderIndex = impl->m_Layout->indexOf(&(helper.placeHolder()));
241
274
242 if (isOnTop || isOnBottom) {
275 if (isOnTop || isOnBottom) {
243 if (isOnBottom) {
276 if (isOnBottom) {
244 dropIndex += 1;
277 dropIndex += 1;
245 }
278 }
246
279
247 auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
280 if (helper.getCurrentDragWidget()) {
248 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
281 auto dragWidgetIndex
249 dropIndex += 1; // Correction of the index if the drop occurs in the same
282 = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
250 // container
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 if (dropIndex != placeHolderIndex) {
291 if (dropIndex != placeHolderIndex) {
254 helper.insertPlaceHolder(impl->m_Layout, dropIndex);
292 helper.insertPlaceHolder(impl->m_Layout, dropIndex);
255 }
293 }
256 }
294 }
257 else if (canMerge) {
295 else if (canMerge) {
258 // drop on the middle -> merge
296 // drop on the middle -> merge
259 if (impl->hasPlaceHolder()) {
297 if (impl->hasPlaceHolder()) {
260 helper.removePlaceHolder();
298 helper.removePlaceHolder();
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 else {
313 else {
267 event->ignore();
314 event->ignore();
268 }
315 }
269
316
270 QWidget::dragMoveEvent(event);
317 QWidget::dragMoveEvent(event);
271 }
318 }
272
319
273 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
320 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
274 {
321 {
275 if (impl->acceptMimeData(event->mimeData())) {
322 if (impl->acceptMimeData(event->mimeData())) {
276 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
323 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
277 if (impl->hasPlaceHolder() && dragWidget) {
324 if (impl->hasPlaceHolder()) {
278 auto &helper = sqpApp->dragDropHelper();
325 auto &helper = sqpApp->dragDropHelper();
279
326
280 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
327 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
281
328
282 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
329 if (dragWidget) {
283 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
330 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
284 droppedIndex
331 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
285 -= 1; // Correction of the index if the drop occurs in the same container
332 // Correction of the index if the drop occurs in the same container
286 }
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 event->acceptProposedAction();
341 event->acceptProposedAction();
291
342
292 helper.removePlaceHolder();
343 helper.removePlaceHolder();
293
344
294 emit dropOccured(droppedIndex, event->mimeData());
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 else {
354 else {
298 event->ignore();
355 event->ignore();
299 }
356 }
300
357
301 QWidget::dropEvent(event);
358 QWidget::dropEvent(event);
302 }
359 }
@@ -1,220 +1,294
1 #include "Visualization/VisualizationTabWidget.h"
1 #include "Visualization/VisualizationTabWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "ui_VisualizationTabWidget.h"
3 #include "ui_VisualizationTabWidget.h"
4
4
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7
7
8 #include "Variable/VariableController.h"
8 #include "Variable/VariableController.h"
9
9
10 #include "Common/MimeTypesDef.h"
10 #include "Common/MimeTypesDef.h"
11
11
12 #include "DragDropHelper.h"
12 #include "DragDropHelper.h"
13 #include "SqpApplication.h"
13 #include "SqpApplication.h"
14
14
15 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
15 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
16
16
17 namespace {
17 namespace {
18
18
19 /// Generates a default name for a new zone, according to the number of zones already displayed in
19 /// Generates a default name for a new zone, according to the number of zones already displayed in
20 /// the tab
20 /// the tab
21 QString defaultZoneName(const QLayout &layout)
21 QString defaultZoneName(const QLayout &layout)
22 {
22 {
23 auto count = 0;
23 auto count = 0;
24 for (auto i = 0; i < layout.count(); ++i) {
24 for (auto i = 0; i < layout.count(); ++i) {
25 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
25 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
26 count++;
26 count++;
27 }
27 }
28 }
28 }
29
29
30 return QObject::tr("Zone %1").arg(count + 1);
30 return QObject::tr("Zone %1").arg(count + 1);
31 }
31 }
32
32
33 /**
33 /**
34 * Applies a function to all zones of the tab represented by its layout
34 * Applies a function to all zones of the tab represented by its layout
35 * @param layout the layout that contains zones
35 * @param layout the layout that contains zones
36 * @param fun the function to apply to each zone
36 * @param fun the function to apply to each zone
37 */
37 */
38 template <typename Fun>
38 template <typename Fun>
39 void processZones(QLayout &layout, Fun fun)
39 void processZones(QLayout &layout, Fun fun)
40 {
40 {
41 for (auto i = 0; i < layout.count(); ++i) {
41 for (auto i = 0; i < layout.count(); ++i) {
42 if (auto item = layout.itemAt(i)) {
42 if (auto item = layout.itemAt(i)) {
43 if (auto visualizationZoneWidget
43 if (auto visualizationZoneWidget
44 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
44 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
45 fun(*visualizationZoneWidget);
45 fun(*visualizationZoneWidget);
46 }
46 }
47 }
47 }
48 }
48 }
49 }
49 }
50
50
51 } // namespace
51 } // namespace
52
52
53 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
53 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
55
55
56 QString m_Name;
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 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
64 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
60 : QWidget{parent},
65 : QWidget{parent},
61 ui{new Ui::VisualizationTabWidget},
66 ui{new Ui::VisualizationTabWidget},
62 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
67 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
63 {
68 {
64 ui->setupUi(this);
69 ui->setupUi(this);
65
70
66 ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH, MIME_TYPE_ZONE});
71 ui->dragDropContainer->setAcceptedMimeTypes(
72 {MIME_TYPE_GRAPH, MIME_TYPE_ZONE, MIME_TYPE_VARIABLE_LIST});
67 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
73 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
68 &VisualizationTabWidget::dropMimeData);
74 &VisualizationTabWidget::dropMimeData);
75 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
76 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
77 ui->dragDropContainer);
78 });
69 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
79 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
70
80
71 // Widget is deleted when closed
81 // Widget is deleted when closed
72 setAttribute(Qt::WA_DeleteOnClose);
82 setAttribute(Qt::WA_DeleteOnClose);
73 }
83 }
74
84
75 VisualizationTabWidget::~VisualizationTabWidget()
85 VisualizationTabWidget::~VisualizationTabWidget()
76 {
86 {
77 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
87 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
78 delete ui;
88 delete ui;
79 }
89 }
80
90
81 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
91 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
82 {
92 {
83 ui->dragDropContainer->addDragWidget(zoneWidget);
93 ui->dragDropContainer->addDragWidget(zoneWidget);
84 }
94 }
85
95
86 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
96 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
87 {
97 {
88 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
98 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
89 }
99 }
90
100
91 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
101 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
92 {
102 {
93 return createZone({variable}, -1);
103 return createZone({variable}, -1);
94 }
104 }
95
105
96 VisualizationZoneWidget *
106 VisualizationZoneWidget *
97 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
107 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
98 {
108 {
99 auto zoneWidget = createEmptyZone(index);
109 auto zoneWidget = createEmptyZone(index);
100
110
101 // Creates a new graph into the zone
111 // Creates a new graph into the zone
102 zoneWidget->createGraph(variables, index);
112 zoneWidget->createGraph(variables, index);
103
113
104 return zoneWidget;
114 return zoneWidget;
105 }
115 }
106
116
107 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
117 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
108 {
118 {
109 auto zoneWidget
119 auto zoneWidget
110 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
120 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
111 this->insertZone(index, zoneWidget);
121 this->insertZone(index, zoneWidget);
112
122
113 return zoneWidget;
123 return zoneWidget;
114 }
124 }
115
125
116 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
126 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
117 {
127 {
118 if (visitor) {
128 if (visitor) {
119 visitor->visitEnter(this);
129 visitor->visitEnter(this);
120
130
121 // Apply visitor to zone children: widgets different from zones are not visited (no action)
131 // Apply visitor to zone children: widgets different from zones are not visited (no action)
122 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
132 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
123 zoneWidget.accept(visitor);
133 zoneWidget.accept(visitor);
124 });
134 });
125
135
126 visitor->visitLeave(this);
136 visitor->visitLeave(this);
127 }
137 }
128 else {
138 else {
129 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
139 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
130 }
140 }
131 }
141 }
132
142
133 bool VisualizationTabWidget::canDrop(const Variable &variable) const
143 bool VisualizationTabWidget::canDrop(const Variable &variable) const
134 {
144 {
135 // A tab can always accomodate a variable
145 // A tab can always accomodate a variable
136 Q_UNUSED(variable);
146 Q_UNUSED(variable);
137 return true;
147 return true;
138 }
148 }
139
149
140 bool VisualizationTabWidget::contains(const Variable &variable) const
150 bool VisualizationTabWidget::contains(const Variable &variable) const
141 {
151 {
142 Q_UNUSED(variable);
152 Q_UNUSED(variable);
143 return false;
153 return false;
144 }
154 }
145
155
146 QString VisualizationTabWidget::name() const
156 QString VisualizationTabWidget::name() const
147 {
157 {
148 return impl->m_Name;
158 return impl->m_Name;
149 }
159 }
150
160
151 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
161 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
152 {
162 {
153 // Closes zones in the tab
163 // Closes zones in the tab
154 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
164 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
155
165
156 QWidget::closeEvent(event);
166 QWidget::closeEvent(event);
157 }
167 }
158
168
159 QLayout &VisualizationTabWidget::tabLayout() const noexcept
169 QLayout &VisualizationTabWidget::tabLayout() const noexcept
160 {
170 {
161 return *ui->dragDropContainer->layout();
171 return *ui->dragDropContainer->layout();
162 }
172 }
163
173
164 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
174 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
165 {
175 {
166 auto &helper = sqpApp->dragDropHelper();
167 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
176 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
168 auto graphWidget = static_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
177 impl->dropGraph(index, this);
169 auto parentDragDropContainer
178 }
170 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
179 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
171 Q_ASSERT(parentDragDropContainer);
180 impl->dropZone(index, this);
172
181 }
173 auto nbGraph = parentDragDropContainer->countDragWidget();
182 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
174
183 auto variables = sqpApp->variableController().variablesForMimeData(
175 const auto &variables = graphWidget->variables();
184 mimeData->data(MIME_TYPE_VARIABLE_LIST));
176
185 impl->dropVariables(variables, index, this);
177 if (!variables.isEmpty()) {
186 }
178 // Abort the requests for the variables (if any)
187 else {
179 // Commented, because it's not sure if it's needed or not
188 qCWarning(LOG_VisualizationZoneWidget())
180 // for (const auto& var : variables)
189 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
181 //{
190 }
182 // sqpApp->variableController().onAbortProgressRequested(var);
191 }
183 //}
192
184
193 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
185 if (nbGraph == 1) {
194 int index, VisualizationTabWidget *tabWidget)
186 // This is the only graph in the previous zone, close the zone
195 {
187 graphWidget->parentZoneWidget()->close();
196 auto &helper = sqpApp->dragDropHelper();
188 }
197
189 else {
198 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
190 // Close the graph
199 if (!graphWidget) {
191 graphWidget->close();
200 qCWarning(LOG_VisualizationZoneWidget())
192 }
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 else {
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);
245 parentDragDropContainer->layout()->removeWidget(graphWidget);
204 zoneWidget->addGraph(graphWidget);
205
246
206 // Close the old zone if it was the only graph inside
247 auto zoneWidget = tabWidget->createEmptyZone(index);
207 if (nbGraph == 1) {
248 zoneWidget->addGraph(graphWidget);
208 parentZoneWidget->close();
249
209 }
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)) {
255 }
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);
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 }
@@ -1,411 +1,484
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationWidget.h"
6 #include "ui_VisualizationZoneWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
7
8
8 #include "Common/MimeTypesDef.h"
9 #include "Common/MimeTypesDef.h"
9 #include <Data/SqpRange.h>
10 #include <Data/SqpRange.h>
10 #include <Variable/Variable.h>
11 #include <Variable/Variable.h>
11 #include <Variable/VariableController.h>
12 #include <Variable/VariableController.h>
12
13
14 #include <Visualization/operations/FindVariableOperation.h>
15
13 #include <DragDropHelper.h>
16 #include <DragDropHelper.h>
14 #include <QUuid>
17 #include <QUuid>
15 #include <SqpApplication.h>
18 #include <SqpApplication.h>
16 #include <cmath>
19 #include <cmath>
17
20
18 #include <QLayout>
21 #include <QLayout>
19
22
20 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
23 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
21
24
22 namespace {
25 namespace {
23
26
24 /// Minimum height for graph added in zones (in pixels)
27 /// Minimum height for graph added in zones (in pixels)
25 const auto GRAPH_MINIMUM_HEIGHT = 300;
28 const auto GRAPH_MINIMUM_HEIGHT = 300;
26
29
27 /// Generates a default name for a new graph, according to the number of graphs already displayed in
30 /// Generates a default name for a new graph, according to the number of graphs already displayed in
28 /// the zone
31 /// the zone
29 QString defaultGraphName(const QLayout &layout)
32 QString defaultGraphName(const QLayout &layout)
30 {
33 {
31 auto count = 0;
34 auto count = 0;
32 for (auto i = 0; i < layout.count(); ++i) {
35 for (auto i = 0; i < layout.count(); ++i) {
33 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
36 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
34 count++;
37 count++;
35 }
38 }
36 }
39 }
37
40
38 return QObject::tr("Graph %1").arg(count + 1);
41 return QObject::tr("Graph %1").arg(count + 1);
39 }
42 }
40
43
41 /**
44 /**
42 * Applies a function to all graphs of the zone represented by its layout
45 * Applies a function to all graphs of the zone represented by its layout
43 * @param layout the layout that contains graphs
46 * @param layout the layout that contains graphs
44 * @param fun the function to apply to each graph
47 * @param fun the function to apply to each graph
45 */
48 */
46 template <typename Fun>
49 template <typename Fun>
47 void processGraphs(QLayout &layout, Fun fun)
50 void processGraphs(QLayout &layout, Fun fun)
48 {
51 {
49 for (auto i = 0; i < layout.count(); ++i) {
52 for (auto i = 0; i < layout.count(); ++i) {
50 if (auto item = layout.itemAt(i)) {
53 if (auto item = layout.itemAt(i)) {
51 if (auto visualizationGraphWidget
54 if (auto visualizationGraphWidget
52 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
55 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
53 fun(*visualizationGraphWidget);
56 fun(*visualizationGraphWidget);
54 }
57 }
55 }
58 }
56 }
59 }
57 }
60 }
58
61
59 } // namespace
62 } // namespace
60
63
61 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
64 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
62
65
63 explicit VisualizationZoneWidgetPrivate()
66 explicit VisualizationZoneWidgetPrivate()
64 : m_SynchronisationGroupId{QUuid::createUuid()},
67 : m_SynchronisationGroupId{QUuid::createUuid()},
65 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
68 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
66 {
69 {
67 }
70 }
68 QUuid m_SynchronisationGroupId;
71 QUuid m_SynchronisationGroupId;
69 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
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 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
79 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
73 : VisualizationDragWidget{parent},
80 : VisualizationDragWidget{parent},
74 ui{new Ui::VisualizationZoneWidget},
81 ui{new Ui::VisualizationZoneWidget},
75 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
82 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
76 {
83 {
77 ui->setupUi(this);
84 ui->setupUi(this);
78
85
79 ui->zoneNameLabel->setText(name);
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 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
93 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
83 &VisualizationZoneWidget::dropMimeData);
94 &VisualizationZoneWidget::dropMimeData);
84
95
85 // 'Close' options : widget is deleted when closed
96 // 'Close' options : widget is deleted when closed
86 setAttribute(Qt::WA_DeleteOnClose);
97 setAttribute(Qt::WA_DeleteOnClose);
87 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
98 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
88 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
99 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
89
100
90 // Synchronisation id
101 // Synchronisation id
91 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
102 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
92 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
103 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
93 }
104 }
94
105
95 VisualizationZoneWidget::~VisualizationZoneWidget()
106 VisualizationZoneWidget::~VisualizationZoneWidget()
96 {
107 {
97 delete ui;
108 delete ui;
98 }
109 }
99
110
100 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
111 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
101 {
112 {
102 // Synchronize new graph with others in the zone
113 // Synchronize new graph with others in the zone
103 impl->m_Synchronizer->addGraph(*graphWidget);
114 impl->m_Synchronizer->addGraph(*graphWidget);
104
115
105 ui->dragDropContainer->addDragWidget(graphWidget);
116 ui->dragDropContainer->addDragWidget(graphWidget);
106 }
117 }
107
118
108 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
119 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
109 {
120 {
110 // Synchronize new graph with others in the zone
121 // Synchronize new graph with others in the zone
111 impl->m_Synchronizer->addGraph(*graphWidget);
122 impl->m_Synchronizer->addGraph(*graphWidget);
112
123
113 ui->dragDropContainer->insertDragWidget(index, graphWidget);
124 ui->dragDropContainer->insertDragWidget(index, graphWidget);
114 }
125 }
115
126
116 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
127 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
117 {
128 {
118 return createGraph(variable, -1);
129 return createGraph(variable, -1);
119 }
130 }
120
131
121 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
132 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
122 int index)
133 int index)
123 {
134 {
124 auto graphWidget
135 auto graphWidget
125 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
136 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
126
137
127
138
128 // Set graph properties
139 // Set graph properties
129 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
140 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
130 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
141 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
131
142
132
143
133 // Lambda to synchronize zone widget
144 // Lambda to synchronize zone widget
134 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
145 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
135 const SqpRange &oldGraphRange) {
146 const SqpRange &oldGraphRange) {
136
147
137 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
148 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
138 auto frameLayout = ui->dragDropContainer->layout();
149 auto frameLayout = ui->dragDropContainer->layout();
139 for (auto i = 0; i < frameLayout->count(); ++i) {
150 for (auto i = 0; i < frameLayout->count(); ++i) {
140 auto graphChild
151 auto graphChild
141 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
152 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
142 if (graphChild && (graphChild != graphWidget)) {
153 if (graphChild && (graphChild != graphWidget)) {
143
154
144 auto graphChildRange = graphChild->graphRange();
155 auto graphChildRange = graphChild->graphRange();
145 switch (zoomType) {
156 switch (zoomType) {
146 case AcquisitionZoomType::ZoomIn: {
157 case AcquisitionZoomType::ZoomIn: {
147 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
158 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
148 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
159 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
149 graphChildRange.m_TStart += deltaLeft;
160 graphChildRange.m_TStart += deltaLeft;
150 graphChildRange.m_TEnd -= deltaRight;
161 graphChildRange.m_TEnd -= deltaRight;
151 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
162 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
152 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
163 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
153 << deltaLeft;
164 << deltaLeft;
154 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
165 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
155 << deltaRight;
166 << deltaRight;
156 qCDebug(LOG_VisualizationZoneWidget())
167 qCDebug(LOG_VisualizationZoneWidget())
157 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
168 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
158
169
159 break;
170 break;
160 }
171 }
161
172
162 case AcquisitionZoomType::ZoomOut: {
173 case AcquisitionZoomType::ZoomOut: {
163 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
174 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
164 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
175 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
165 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
176 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
166 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
177 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
167 << deltaLeft;
178 << deltaLeft;
168 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
179 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
169 << deltaRight;
180 << deltaRight;
170 qCDebug(LOG_VisualizationZoneWidget())
181 qCDebug(LOG_VisualizationZoneWidget())
171 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
182 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
172 graphChildRange.m_TStart -= deltaLeft;
183 graphChildRange.m_TStart -= deltaLeft;
173 graphChildRange.m_TEnd += deltaRight;
184 graphChildRange.m_TEnd += deltaRight;
174 break;
185 break;
175 }
186 }
176 case AcquisitionZoomType::PanRight: {
187 case AcquisitionZoomType::PanRight: {
177 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
178 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
189 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
179 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
190 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
180 graphChildRange.m_TStart += deltaLeft;
191 graphChildRange.m_TStart += deltaLeft;
181 graphChildRange.m_TEnd += deltaRight;
192 graphChildRange.m_TEnd += deltaRight;
182 qCDebug(LOG_VisualizationZoneWidget())
193 qCDebug(LOG_VisualizationZoneWidget())
183 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
194 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
184 break;
195 break;
185 }
196 }
186 case AcquisitionZoomType::PanLeft: {
197 case AcquisitionZoomType::PanLeft: {
187 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
198 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
188 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
199 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
189 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
200 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
190 graphChildRange.m_TStart -= deltaLeft;
201 graphChildRange.m_TStart -= deltaLeft;
191 graphChildRange.m_TEnd -= deltaRight;
202 graphChildRange.m_TEnd -= deltaRight;
192 break;
203 break;
193 }
204 }
194 case AcquisitionZoomType::Unknown: {
205 case AcquisitionZoomType::Unknown: {
195 qCDebug(LOG_VisualizationZoneWidget())
206 qCDebug(LOG_VisualizationZoneWidget())
196 << tr("Impossible to synchronize: zoom type unknown");
207 << tr("Impossible to synchronize: zoom type unknown");
197 break;
208 break;
198 }
209 }
199 default:
210 default:
200 qCCritical(LOG_VisualizationZoneWidget())
211 qCCritical(LOG_VisualizationZoneWidget())
201 << tr("Impossible to synchronize: zoom type not take into account");
212 << tr("Impossible to synchronize: zoom type not take into account");
202 // No action
213 // No action
203 break;
214 break;
204 }
215 }
205 graphChild->enableAcquisition(false);
216 graphChild->enableAcquisition(false);
206 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
217 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
207 << graphChild->graphRange();
218 << graphChild->graphRange();
208 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
209 << graphChildRange;
220 << graphChildRange;
210 qCDebug(LOG_VisualizationZoneWidget())
221 qCDebug(LOG_VisualizationZoneWidget())
211 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
222 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
212 graphChild->setGraphRange(graphChildRange);
223 graphChild->setGraphRange(graphChildRange);
213 graphChild->enableAcquisition(true);
224 graphChild->enableAcquisition(true);
214 }
225 }
215 }
226 }
216 };
227 };
217
228
218 // connection for synchronization
229 // connection for synchronization
219 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
230 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
220 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
231 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
221 &VisualizationZoneWidget::onVariableAdded);
232 &VisualizationZoneWidget::onVariableAdded);
222 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
233 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
223 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
234 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
224
235
225 auto range = SqpRange{};
236 auto range = SqpRange{};
226
237
227 // Apply visitor to graph children
238 // Apply visitor to graph children
228 auto layout = ui->dragDropContainer->layout();
239 auto layout = ui->dragDropContainer->layout();
229 if (layout->count() > 0) {
240 if (layout->count() > 0) {
230 // Case of a new graph in a existant zone
241 // Case of a new graph in a existant zone
231 if (auto visualizationGraphWidget
242 if (auto visualizationGraphWidget
232 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
243 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
233 range = visualizationGraphWidget->graphRange();
244 range = visualizationGraphWidget->graphRange();
234 }
245 }
235 }
246 }
236 else {
247 else {
237 // Case of a new graph as the first of the zone
248 // Case of a new graph as the first of the zone
238 range = variable->range();
249 range = variable->range();
239 }
250 }
240
251
241 this->insertGraph(index, graphWidget);
252 this->insertGraph(index, graphWidget);
242
253
243 graphWidget->addVariable(variable, range);
254 graphWidget->addVariable(variable, range);
244
255
245 // get y using variable range
256 // get y using variable range
246 if (auto dataSeries = variable->dataSeries()) {
257 if (auto dataSeries = variable->dataSeries()) {
247 dataSeries->lockRead();
258 dataSeries->lockRead();
248 auto valuesBounds
259 auto valuesBounds
249 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
260 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
250 auto end = dataSeries->cend();
261 auto end = dataSeries->cend();
251 if (valuesBounds.first != end && valuesBounds.second != end) {
262 if (valuesBounds.first != end && valuesBounds.second != end) {
252 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
263 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
253
264
254 auto minValue = rangeValue(valuesBounds.first->minValue());
265 auto minValue = rangeValue(valuesBounds.first->minValue());
255 auto maxValue = rangeValue(valuesBounds.second->maxValue());
266 auto maxValue = rangeValue(valuesBounds.second->maxValue());
256
267
257 graphWidget->setYRange(SqpRange{minValue, maxValue});
268 graphWidget->setYRange(SqpRange{minValue, maxValue});
258 }
269 }
259 dataSeries->unlock();
270 dataSeries->unlock();
260 }
271 }
261
272
262 return graphWidget;
273 return graphWidget;
263 }
274 }
264
275
265 VisualizationGraphWidget *
276 VisualizationGraphWidget *
266 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
277 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
267 {
278 {
268 if (variables.isEmpty()) {
279 if (variables.isEmpty()) {
269 return nullptr;
280 return nullptr;
270 }
281 }
271
282
272 auto graphWidget = createGraph(variables.first(), index);
283 auto graphWidget = createGraph(variables.first(), index);
273 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
284 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
274 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
285 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
275 }
286 }
276
287
277 return graphWidget;
288 return graphWidget;
278 }
289 }
279
290
280 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
291 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
281 {
292 {
282 if (visitor) {
293 if (visitor) {
283 visitor->visitEnter(this);
294 visitor->visitEnter(this);
284
295
285 // Apply visitor to graph children: widgets different from graphs are not visited (no
296 // Apply visitor to graph children: widgets different from graphs are not visited (no
286 // action)
297 // action)
287 processGraphs(
298 processGraphs(
288 *ui->dragDropContainer->layout(),
299 *ui->dragDropContainer->layout(),
289 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
300 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
290
301
291 visitor->visitLeave(this);
302 visitor->visitLeave(this);
292 }
303 }
293 else {
304 else {
294 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
305 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
295 }
306 }
296 }
307 }
297
308
298 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
309 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
299 {
310 {
300 // A tab can always accomodate a variable
311 // A tab can always accomodate a variable
301 Q_UNUSED(variable);
312 Q_UNUSED(variable);
302 return true;
313 return true;
303 }
314 }
304
315
305 bool VisualizationZoneWidget::contains(const Variable &variable) const
316 bool VisualizationZoneWidget::contains(const Variable &variable) const
306 {
317 {
307 Q_UNUSED(variable);
318 Q_UNUSED(variable);
308 return false;
319 return false;
309 }
320 }
310
321
311 QString VisualizationZoneWidget::name() const
322 QString VisualizationZoneWidget::name() const
312 {
323 {
313 return ui->zoneNameLabel->text();
324 return ui->zoneNameLabel->text();
314 }
325 }
315
326
316 QMimeData *VisualizationZoneWidget::mimeData() const
327 QMimeData *VisualizationZoneWidget::mimeData() const
317 {
328 {
318 auto mimeData = new QMimeData;
329 auto mimeData = new QMimeData;
319 mimeData->setData(MIME_TYPE_ZONE, QByteArray());
330 mimeData->setData(MIME_TYPE_ZONE, QByteArray());
320
331
321 return mimeData;
332 return mimeData;
322 }
333 }
323
334
324 bool VisualizationZoneWidget::isDragAllowed() const
335 bool VisualizationZoneWidget::isDragAllowed() const
325 {
336 {
326 return true;
337 return true;
327 }
338 }
328
339
329 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
340 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
330 {
341 {
331 // Closes graphs in the zone
342 // Closes graphs in the zone
332 processGraphs(*ui->dragDropContainer->layout(),
343 processGraphs(*ui->dragDropContainer->layout(),
333 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
344 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
334
345
335 // Delete synchronization group from variable controller
346 // Delete synchronization group from variable controller
336 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
347 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
337 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
348 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
338
349
339 QWidget::closeEvent(event);
350 QWidget::closeEvent(event);
340 }
351 }
341
352
342 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
353 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
343 {
354 {
344 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
355 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
345 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
356 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
346 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
357 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
347 }
358 }
348
359
349 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
360 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
350 {
361 {
351 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
362 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
352 Q_ARG(std::shared_ptr<Variable>, variable),
363 Q_ARG(std::shared_ptr<Variable>, variable),
353 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
364 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
354 }
365 }
355
366
356 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
367 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
357 {
368 {
358 auto &helper = sqpApp->dragDropHelper();
359 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
369 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
360 auto graphWidget = static_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
370 impl->dropGraph(index, this);
361 auto parentDragDropContainer
371 }
362 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
372 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
363 Q_ASSERT(parentDragDropContainer);
373 auto variables = sqpApp->variableController().variablesForMimeData(
364
374 mimeData->data(MIME_TYPE_VARIABLE_LIST));
365 const auto &variables = graphWidget->variables();
375 impl->dropVariables(variables, index, this);
366
376 }
367 if (parentDragDropContainer != ui->dragDropContainer && !variables.isEmpty()) {
377 else {
368 // The drop didn't occur in the same zone
378 qCWarning(LOG_VisualizationZoneWidget())
369
379 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
370 // Abort the requests for the variables (if any)
380 }
371 // Commented, because it's not sure if it's needed or not
381 }
372 // for (const auto& var : variables)
382
373 //{
383 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
374 // sqpApp->variableController().onAbortProgressRequested(var);
384 int index, VisualizationZoneWidget *zoneWidget)
375 //}
385 {
376
386 auto &helper = sqpApp->dragDropHelper();
377 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
387
378 auto nbGraph = parentDragDropContainer->countDragWidget();
388 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
379 if (nbGraph == 1) {
389 if (!graphWidget) {
380 // This is the only graph in the previous zone, close the zone
390 qCWarning(LOG_VisualizationZoneWidget())
381 previousParentZoneWidget->close();
391 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
382 }
392 "found or invalid.");
383 else {
393 Q_ASSERT(false);
384 // Close the graph
394 return;
385 graphWidget->close();
395 }
386 }
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
409 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
389 createGraph(variables, index);
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 else {
425 else {
392 // The drop occurred in the same zone or the graph is empty
426 // Close the graph
393 // Simple move of the graph, no variable operation associated
427 graphWidget->close();
394 parentDragDropContainer->layout()->removeWidget(graphWidget);
428 }
395
429
396 if (variables.isEmpty() && parentDragDropContainer != ui->dragDropContainer) {
430 // Creates the new graph in the zone
397 // The graph is empty and dropped in a different zone.
431 zoneWidget->createGraph(variables, index);
398 // Take the range of the first graph in the zone (if existing).
432 }
399 auto layout = ui->dragDropContainer->layout();
433 else {
400 if (layout->count() > 0) {
434 // The drop occurred in the same zone or the graph is empty
401 if (auto visualizationGraphWidget
435 // Simple move of the graph, no variable operation associated
402 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
436 parentDragDropContainer->layout()->removeWidget(graphWidget);
403 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
437
404 }
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