##// END OF EJS Templates
drop of products in visu
trabillard -
r1341:36d2186e2f24
parent child
Show More
@@ -1,106 +1,106
1 1 #ifndef SCIQLOP_DATASOURCECONTROLLER_H
2 2 #define SCIQLOP_DATASOURCECONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8 #include <QUuid>
9 9
10 10 #include <Common/spimpl.h>
11 11
12 12 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceController)
13 13
14 14 class DataSourceItem;
15 15 class IDataProvider;
16 16
17 17 /**
18 18 * @brief The DataSourceController class aims to make the link between SciQlop and its plugins. This
19 19 * is the intermediate class that SciQlop has to use in the way to connect a data source. Please
20 20 * first use register method to initialize a plugin specified by its metadata name (JSON plugin
21 21 * source) then others specifics method will be able to access it. You can load a data source driver
22 22 * plugin then create a data source.
23 23 */
24 24 class SCIQLOP_CORE_EXPORT DataSourceController : public QObject {
25 25 Q_OBJECT
26 26 public:
27 27 explicit DataSourceController(QObject *parent = 0);
28 28 virtual ~DataSourceController();
29 29
30 30 /**
31 31 * Registers a data source. The method delivers a unique id that can be used afterwards to
32 32 * access to the data source properties (structure, connection parameters, data provider, etc.)
33 33 * @param dataSourceName the name of the data source
34 34 * @return the unique id with which the data source has been registered
35 35 */
36 36 QUuid registerDataSource(const QString &dataSourceName) noexcept;
37 37
38 38 /**
39 39 * Sets the structure of a data source. The controller takes ownership of the structure.
40 40 * @param dataSourceUid the unique id with which the data source has been registered into the
41 41 * controller. If it is invalid, the method has no effect.
42 42 * @param dataSourceItem the structure of the data source. It must be not null to be registered
43 43 * @sa registerDataSource()
44 44 */
45 45 void setDataSourceItem(const QUuid &dataSourceUid,
46 46 std::unique_ptr<DataSourceItem> dataSourceItem) noexcept;
47 47
48 48 /**
49 49 * Sets the data provider used to retrieve data from of a data source. The controller takes
50 50 * ownership of the provider.
51 51 * @param dataSourceUid the unique id with which the data source has been registered into the
52 52 * controller. If it is invalid, the method has no effect.
53 53 * @param dataProvider the provider of the data source
54 54 * @sa registerDataSource()
55 55 */
56 56 void setDataProvider(const QUuid &dataSourceUid,
57 57 std::unique_ptr<IDataProvider> dataProvider) noexcept;
58 58
59 59 /**
60 60 * Loads an item (product) as a variable in SciQlop
61 61 * @param dataSourceUid the unique id of the data source containing the item. It is used to get
62 62 * the data provider associated to the data source, and pass it to for the variable creation
63 63 * @param productItem the item to load
64 64 */
65 65 void loadProductItem(const QUuid &dataSourceUid, const DataSourceItem &productItem) noexcept;
66 66
67 67 /// Returns the MIME data associated to a list of product meta data
68 68 static QByteArray mimeDataForProductsData(const QVariantList &productsData);
69 69
70 70 /// Returns the list of meta data contained in a MIME data
71 71 static QVariantList productsDataForMimeData(const QByteArray &mimeData);
72 72
73 73 public slots:
74 74 /// Manage init/end of the controller
75 75 void initialize();
76 76 void finalize();
77 77
78 78 /// Request the creation of a variable from the ID_DATA_KEY of a product
79 void requestVariable(const QString &datasourceIdKey);
79 void requestVariableFromProductIdKey(const QString &datasourceIdKey);
80 80
81 81 /// Request the creation of a variable from metadata of a product
82 82 void requestVariable(const QVariantHash &productData);
83 83
84 84 signals:
85 85 /// Signal emitted when a structure has been set for a data source
86 86 void dataSourceItemSet(DataSourceItem *dataSourceItem);
87 87
88 88 /**
89 89 * Signal emitted when a variable creation is asked for a product
90 90 * @param variableName the name of the variable
91 91 * @param variableMetadata the metadata of the variable
92 92 * @param variableProvider the provider that will be used to retrieve the data of the variable
93 93 * (can be null)
94 94 */
95 95 void variableCreationRequested(const QString &variableName,
96 96 const QVariantHash &variableMetadata,
97 97 std::shared_ptr<IDataProvider> variableProvider);
98 98
99 99 private:
100 100 void waitForFinish();
101 101
102 102 class DataSourceControllerPrivate;
103 103 spimpl::unique_impl_ptr<DataSourceControllerPrivate> impl;
104 104 };
105 105
106 106 #endif // SCIQLOP_DATASOURCECONTROLLER_H
@@ -1,197 +1,197
1 1 #include "DataSource/DataSourceController.h"
2 2 #include "DataSource/DataSourceItem.h"
3 3
4 4 #include <Data/IDataProvider.h>
5 5
6 6 #include <QMutex>
7 7 #include <QThread>
8 8
9 9 #include <QDataStream>
10 10 #include <QDir>
11 11 #include <QStandardPaths>
12 12
13 13 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
14 14
15 15 class DataSourceController::DataSourceControllerPrivate {
16 16 public:
17 17 QMutex m_WorkingMutex;
18 18 /// Data sources registered
19 19 QHash<QUuid, QString> m_DataSources;
20 20 /// Data sources structures
21 21 std::map<QUuid, std::unique_ptr<DataSourceItem> > m_DataSourceItems;
22 22 /// Data providers registered
23 23 /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and
24 24 /// continue to live without necessarily the data source controller
25 25 std::map<QUuid, std::shared_ptr<IDataProvider> > m_DataProviders;
26 26
27 27 // Search for the first datasource item matching the specified data
28 28 DataSourceItem *findDataSourceItem(const QVariantHash &data)
29 29 {
30 30 DataSourceItem *sourceItem = nullptr;
31 31 for (const auto &item : m_DataSourceItems) {
32 32 sourceItem = item.second->findItem(data, true);
33 33 if (sourceItem) {
34 34 break;
35 35 }
36 36 }
37 37
38 38 return sourceItem;
39 39 }
40 40
41 41 // Search for the first datasource item matching the specified ID_DATA_KEY
42 42 DataSourceItem *findDataSourceItem(const QString &datasourceIdKey)
43 43 {
44 44 DataSourceItem *sourceItem = nullptr;
45 45 for (const auto &item : m_DataSourceItems) {
46 46 sourceItem = item.second->findItem(datasourceIdKey, true);
47 47 if (sourceItem) {
48 48 break;
49 49 }
50 50 }
51 51
52 52 return sourceItem;
53 53 }
54 54 };
55 55
56 56 DataSourceController::DataSourceController(QObject *parent)
57 57 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
58 58 {
59 59 qCDebug(LOG_DataSourceController()) << tr("DataSourceController construction")
60 60 << QThread::currentThread();
61 61 }
62 62
63 63 DataSourceController::~DataSourceController()
64 64 {
65 65 qCDebug(LOG_DataSourceController()) << tr("DataSourceController destruction")
66 66 << QThread::currentThread();
67 67 this->waitForFinish();
68 68 }
69 69
70 70 QUuid DataSourceController::registerDataSource(const QString &dataSourceName) noexcept
71 71 {
72 72 auto dataSourceUid = QUuid::createUuid();
73 73 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
74 74
75 75 return dataSourceUid;
76 76 }
77 77
78 78 void DataSourceController::setDataSourceItem(
79 79 const QUuid &dataSourceUid, std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
80 80 {
81 81 if (!dataSourceItem) {
82 82 qCWarning(LOG_DataSourceController())
83 83 << tr("Data source item can't be registered (null item)");
84 84 return;
85 85 }
86 86
87 87 if (impl->m_DataSources.contains(dataSourceUid)) {
88 88 // The data provider is implicitly converted to a shared_ptr
89 89 impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem)));
90 90
91 91 // Retrieves the data source item to emit the signal with it
92 92 auto it = impl->m_DataSourceItems.find(dataSourceUid);
93 93 if (it != impl->m_DataSourceItems.end()) {
94 94 emit dataSourceItemSet(it->second.get());
95 95 }
96 96 }
97 97 else {
98 98 qCWarning(LOG_DataSourceController()) << tr("Can't set data source item for uid %1 : no "
99 99 "data source has been registered with the uid")
100 100 .arg(dataSourceUid.toString());
101 101 }
102 102 }
103 103
104 104 void DataSourceController::setDataProvider(const QUuid &dataSourceUid,
105 105 std::unique_ptr<IDataProvider> dataProvider) noexcept
106 106 {
107 107 if (impl->m_DataSources.contains(dataSourceUid)) {
108 108 impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider)));
109 109 }
110 110 else {
111 111 qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data "
112 112 "source has been registered with the uid")
113 113 .arg(dataSourceUid.toString());
114 114 }
115 115 }
116 116
117 117 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
118 118 const DataSourceItem &productItem) noexcept
119 119 {
120 120 if (productItem.type() == DataSourceItemType::PRODUCT
121 121 || productItem.type() == DataSourceItemType::COMPONENT) {
122 122 /// Retrieves the data provider of the data source (if any)
123 123 auto it = impl->m_DataProviders.find(dataSourceUid);
124 124 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
125 125
126 126 emit variableCreationRequested(productItem.name(), productItem.data(), dataProvider);
127 127 }
128 128 else {
129 129 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
130 130 }
131 131 }
132 132
133 133 QByteArray DataSourceController::mimeDataForProductsData(const QVariantList &productsData)
134 134 {
135 135 QByteArray encodedData;
136 136 QDataStream stream{&encodedData, QIODevice::WriteOnly};
137 137
138 138 stream << productsData;
139 139
140 140 return encodedData;
141 141 }
142 142
143 143 QVariantList DataSourceController::productsDataForMimeData(const QByteArray &mimeData)
144 144 {
145 145 QDataStream stream{mimeData};
146 146
147 147 QVariantList productList;
148 148 stream >> productList;
149 149
150 150 return productList;
151 151 }
152 152
153 153 void DataSourceController::initialize()
154 154 {
155 155 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init")
156 156 << QThread::currentThread();
157 157 impl->m_WorkingMutex.lock();
158 158 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
159 159 }
160 160
161 161 void DataSourceController::finalize()
162 162 {
163 163 impl->m_WorkingMutex.unlock();
164 164 }
165 165
166 void DataSourceController::requestVariable(const QString &datasourceIdKey)
166 void DataSourceController::requestVariableFromProductIdKey(const QString &datasourceIdKey)
167 167 {
168 168 auto sourceItem = impl->findDataSourceItem(datasourceIdKey);
169 169
170 170 if (sourceItem) {
171 171 auto sourceName = sourceItem->rootItem().name();
172 172 auto sourceId = impl->m_DataSources.key(sourceName);
173 173 loadProductItem(sourceId, *sourceItem);
174 174 }
175 175 else {
176 176 qCWarning(LOG_DataSourceController()) << tr("requestVariable, product data not found");
177 177 }
178 178 }
179 179
180 180 void DataSourceController::requestVariable(const QVariantHash &productData)
181 181 {
182 182 auto sourceItem = impl->findDataSourceItem(productData);
183 183
184 184 if (sourceItem) {
185 185 auto sourceName = sourceItem->rootItem().name();
186 186 auto sourceId = impl->m_DataSources.key(sourceName);
187 187 loadProductItem(sourceId, *sourceItem);
188 188 }
189 189 else {
190 190 qCWarning(LOG_DataSourceController()) << tr("requestVariable, product data not found");
191 191 }
192 192 }
193 193
194 194 void DataSourceController::waitForFinish()
195 195 {
196 196 QMutexLocker locker{&impl->m_WorkingMutex};
197 197 }
@@ -1,296 +1,308
1 1 #include "DragAndDrop/DragDropGuiController.h"
2 2 #include "DragAndDrop/DragDropScroller.h"
3 3 #include "DragAndDrop/DragDropTabSwitcher.h"
4 4 #include "SqpApplication.h"
5 5 #include "Visualization/VisualizationDragDropContainer.h"
6 6 #include "Visualization/VisualizationDragWidget.h"
7 7 #include "Visualization/VisualizationWidget.h"
8 8 #include "Visualization/operations/FindVariableOperation.h"
9 9
10 #include "DataSource/DataSourceController.h"
10 11 #include "Variable/Variable.h"
11 12 #include "Variable/VariableController.h"
12 13
13 14 #include "Common/MimeTypesDef.h"
14 15 #include "Common/VisualizationDef.h"
15 16
16 17 #include <QDir>
17 18 #include <QLabel>
18 19 #include <QUrl>
19 20 #include <QVBoxLayout>
20 21
21 22
22 23 Q_LOGGING_CATEGORY(LOG_DragDropGuiController, "DragDropGuiController")
23 24
24 25
25 26 struct DragDropGuiController::DragDropGuiControllerPrivate {
26 27
27 28 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
28 29 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
29 30 QLabel *m_PlaceHolderLabel;
30 31 QWidget *m_PlaceBackground;
31 32 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
32 33 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
33 34 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
34 35 // QTemporaryFile to have a name which is not generated.
35 36
36 37 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
37 38
38 39 QMetaObject::Connection m_DragWidgetDestroyedConnection;
39 40 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
40 41
41 42 QList<QWidget *> m_WidgetToClose;
42 43
43 44 explicit DragDropGuiControllerPrivate()
44 45 : m_PlaceHolder{std::make_unique<QWidget>()},
45 46 m_DragDropScroller{std::make_unique<DragDropScroller>()},
46 47 m_DragDropTabSwitcher{std::make_unique<DragDropTabSwitcher>()}
47 48 {
48 49
49 50 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
50 51 layout->setSpacing(0);
51 52 layout->setContentsMargins(0, 0, 0, 0);
52 53
53 54 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
54 55 m_PlaceHolderLabel->setMinimumHeight(25);
55 56 layout->addWidget(m_PlaceHolderLabel);
56 57
57 58 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
58 59 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
59 60 layout->addWidget(m_PlaceBackground);
60 61
61 62 sqpApp->installEventFilter(m_DragDropScroller.get());
62 63 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
63 64
64 65 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
65 66 }
66 67
67 68 void preparePlaceHolder(DragDropGuiController::PlaceHolderType type,
68 69 const QString &topLabelText) const
69 70 {
70 71 if (m_CurrentDragWidget) {
71 72 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
72 73 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
73 74 }
74 75 else {
75 76 // Configuration of the placeHolder when there is no dragWidget
76 77 // (for instance with a drag from a variable)
77 78
78 79 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
79 80 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
80 81 }
81 82
82 83 switch (type) {
83 84 case DragDropGuiController::PlaceHolderType::Graph:
84 85 m_PlaceBackground->setStyleSheet(
85 86 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
86 87 break;
87 88 case DragDropGuiController::PlaceHolderType::Zone:
88 89 case DragDropGuiController::PlaceHolderType::Default:
89 90 m_PlaceBackground->setStyleSheet(
90 91 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
91 92 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
92 93 break;
93 94 }
94 95
95 96 m_PlaceHolderLabel->setText(topLabelText);
96 97 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
97 98 }
98 99 };
99 100
100 101
101 102 DragDropGuiController::DragDropGuiController()
102 103 : impl{spimpl::make_unique_impl<DragDropGuiControllerPrivate>()}
103 104 {
104 105 }
105 106
106 107 DragDropGuiController::~DragDropGuiController()
107 108 {
108 109 QFile::remove(impl->m_ImageTempUrl);
109 110 }
110 111
111 112 void DragDropGuiController::resetDragAndDrop()
112 113 {
113 114 setCurrentDragWidget(nullptr);
114 115 impl->m_HighlightedDragWidget = nullptr;
115 116 }
116 117
117 118 void DragDropGuiController::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
118 119 {
119 120 if (impl->m_CurrentDragWidget) {
120 121
121 122 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
122 123 }
123 124
124 125 if (dragWidget) {
125 126 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
126 127 impl->m_DragWidgetDestroyedConnection
127 128 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
128 129 [this]() { impl->m_CurrentDragWidget = nullptr; });
129 130 }
130 131
131 132 impl->m_CurrentDragWidget = dragWidget;
132 133 }
133 134
134 135 VisualizationDragWidget *DragDropGuiController::getCurrentDragWidget() const
135 136 {
136 137 return impl->m_CurrentDragWidget;
137 138 }
138 139
139 140 QWidget &DragDropGuiController::placeHolder() const
140 141 {
141 142 return *impl->m_PlaceHolder;
142 143 }
143 144
144 145 void DragDropGuiController::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
145 146 const QString &topLabelText)
146 147 {
147 148 removePlaceHolder();
148 149 impl->preparePlaceHolder(type, topLabelText);
149 150 layout->insertWidget(index, impl->m_PlaceHolder.get());
150 151 impl->m_PlaceHolder->show();
151 152 }
152 153
153 154 void DragDropGuiController::removePlaceHolder()
154 155 {
155 156 auto parentWidget = impl->m_PlaceHolder->parentWidget();
156 157 if (parentWidget) {
157 158 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
158 159 impl->m_PlaceHolder->setParent(nullptr);
159 160 impl->m_PlaceHolder->hide();
160 161 }
161 162 }
162 163
163 164 bool DragDropGuiController::isPlaceHolderSet() const
164 165 {
165 166 return impl->m_PlaceHolder->parentWidget();
166 167 }
167 168
168 169 void DragDropGuiController::addDragDropScrollArea(QScrollArea *scrollArea)
169 170 {
170 171 impl->m_DragDropScroller->addScrollArea(scrollArea);
171 172 }
172 173
173 174 void DragDropGuiController::removeDragDropScrollArea(QScrollArea *scrollArea)
174 175 {
175 176 impl->m_DragDropScroller->removeScrollArea(scrollArea);
176 177 }
177 178
178 179 void DragDropGuiController::addDragDropTabBar(QTabBar *tabBar)
179 180 {
180 181 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
181 182 }
182 183
183 184 void DragDropGuiController::removeDragDropTabBar(QTabBar *tabBar)
184 185 {
185 186 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
186 187 }
187 188
188 189 QUrl DragDropGuiController::imageTemporaryUrl(const QImage &image) const
189 190 {
190 191 image.save(impl->m_ImageTempUrl);
191 192 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
192 193 }
193 194
194 195 void DragDropGuiController::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
195 196 {
196 197 if (impl->m_HighlightedDragWidget) {
197 198 impl->m_HighlightedDragWidget->highlightForMerge(false);
198 199 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
199 200 }
200 201
201 202 if (dragWidget) {
202 203 dragWidget->highlightForMerge(true);
203 204
204 205 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
205 206 impl->m_DragWidgetDestroyedConnection
206 207 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
207 208 [this]() { impl->m_HighlightedDragWidget = nullptr; });
208 209 }
209 210
210 211 impl->m_HighlightedDragWidget = dragWidget;
211 212 }
212 213
213 214 VisualizationDragWidget *DragDropGuiController::getHightlightedDragWidget() const
214 215 {
215 216 return impl->m_HighlightedDragWidget;
216 217 }
217 218
218 219 void DragDropGuiController::delayedCloseWidget(QWidget *widget)
219 220 {
220 221 widget->hide();
221 222 impl->m_WidgetToClose << widget;
222 223 }
223 224
224 225 void DragDropGuiController::doCloseWidgets()
225 226 {
226 227 for (auto widget : impl->m_WidgetToClose) {
227 228 widget->close();
228 229 }
229 230
230 231 impl->m_WidgetToClose.clear();
231 232 }
232 233
233 234 bool DragDropGuiController::checkMimeDataForVisualization(
234 235 const QMimeData *mimeData, VisualizationDragDropContainer *dropContainer)
235 236 {
236 237 if (!mimeData || !dropContainer) {
237 238 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
238 239 "DragDropGuiController::checkMimeDataForVisualization, invalid input parameters.");
239 240 Q_ASSERT(false);
240 241 return false;
241 242 }
242 243
243 244 auto result = false;
244 245
245 246 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
246 247 auto variables = sqpApp->variableController().variablesForMimeData(
247 248 mimeData->data(MIME_TYPE_VARIABLE_LIST));
248 249
249 250 if (variables.count() == 1) {
250 251
251 252 auto variable = variables.first();
252 253 if (variable->dataSeries() != nullptr) {
253 254
254 255 // Check that the variable is not already in a graph
255 256
256 257 auto parent = dropContainer->parentWidget();
257 258 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
258 259 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
259 260 }
260 261
261 262 if (parent) {
262 263 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
263 264
264 265 FindVariableOperation findVariableOperation{variable};
265 266 visualizationWidget->accept(&findVariableOperation);
266 267 auto variableContainers = findVariableOperation.result();
267 268 if (variableContainers.empty()) {
268 269 result = true;
269 270 }
270 271 else {
271 272 // result = false: the variable already exist in the visualisation
272 273 }
273 274 }
274 275 else {
275 276 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
276 277 "DragDropGuiController::checkMimeDataForVisualization, the parent "
277 278 "VisualizationWidget cannot be found. Cannot check if the variable is "
278 279 "already used or not.");
279 280 }
280 281 }
281 282 else {
282 283 // result = false: the variable is not fully loaded
283 284 }
284 285 }
285 286 else {
286 287 // result = false: cannot drop multiple variables in the visualisation
287 288 }
288 289 }
290 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
291 auto productDataList = sqpApp->dataSourceController().productsDataForMimeData(
292 mimeData->data(MIME_TYPE_PRODUCT_LIST));
293 if (productDataList.count() == 1) {
294 result = true;
295 }
296 else {
297 // result = false: cannot drop multiple products in the visualisation
298 }
299 }
289 300 else {
290 301 // Other MIME data
291 302 // no special rules, accepted by default
292 303 result = true;
293 304 }
294 305
306
295 307 return result;
296 308 }
@@ -1,354 +1,384
1 1 #include "Visualization/VisualizationTabWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "ui_VisualizationTabWidget.h"
4 4
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7
8 8 #include "Visualization/MacScrollBarStyle.h"
9 9
10 #include "DataSource/DataSourceController.h"
10 11 #include "Variable/VariableController.h"
11 12
12 13 #include "Common/MimeTypesDef.h"
13 14
14 15 #include "DragAndDrop/DragDropGuiController.h"
15 16 #include "SqpApplication.h"
16 17
17 18 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
18 19
19 20 namespace {
20 21
21 22 /**
22 23 * Applies a function to all zones of the tab represented by its layout
23 24 * @param layout the layout that contains zones
24 25 * @param fun the function to apply to each zone
25 26 */
26 27 template <typename Fun>
27 28 void processZones(QLayout &layout, Fun fun)
28 29 {
29 30 for (auto i = 0; i < layout.count(); ++i) {
30 31 if (auto item = layout.itemAt(i)) {
31 32 if (auto visualizationZoneWidget
32 33 = qobject_cast<VisualizationZoneWidget *>(item->widget())) {
33 34 fun(*visualizationZoneWidget);
34 35 }
35 36 }
36 37 }
37 38 }
38 39
39 40 /// Generates a default name for a new zone, according to the number of zones already displayed in
40 41 /// the tab
41 42 QString defaultZoneName(QLayout &layout)
42 43 {
43 44 QSet<QString> existingNames;
44 45 processZones(layout,
45 46 [&existingNames](auto &zoneWidget) { existingNames.insert(zoneWidget.name()); });
46 47
47 48 int zoneNum = 1;
48 49 QString name;
49 50 do {
50 51 name = QObject::tr("Zone ").append(QString::number(zoneNum));
51 52 ++zoneNum;
52 53 } while (existingNames.contains(name));
53 54
54 55 return name;
55 56 }
56 57
57 58 } // namespace
58 59
59 60 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
60 61 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
61 62
62 63 QString m_Name;
63 64
64 65 #ifdef Q_OS_MAC
65 66 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
66 67 #endif
67 68
68 69 void dropGraph(int index, VisualizationTabWidget *tabWidget);
69 70 void dropZone(int index, VisualizationTabWidget *tabWidget);
70 71 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
71 72 VisualizationTabWidget *tabWidget);
73 void dropProducts(const QVariantList &productsMetaData, int index,
74 VisualizationTabWidget *tabWidget);
72 75 };
73 76
74 77 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
75 78 : QWidget{parent},
76 79 ui{new Ui::VisualizationTabWidget},
77 80 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
78 81 {
79 82 ui->setupUi(this);
80 83
81 84 #ifdef Q_OS_MAC
82 85 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
83 86 #endif
84 87
85 88 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Zone, "Zone");
86 89 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
87 90 ui->dragDropContainer->layout()->setSpacing(0);
88 91 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
89 92 VisualizationDragDropContainer::DropBehavior::Inserted);
90 93 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
91 94 VisualizationDragDropContainer::DropBehavior::Inserted);
92 95 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
93 96 VisualizationDragDropContainer::DropBehavior::Inserted);
97 ui->dragDropContainer->setMimeType(MIME_TYPE_PRODUCT_LIST,
98 VisualizationDragDropContainer::DropBehavior::Inserted);
94 99
95 100 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
96 101 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
97 102 ui->dragDropContainer);
98 103 });
99 104
100 105 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
101 106 &VisualizationTabWidget::dropMimeData);
102 107
103 108 sqpApp->dragDropGuiController().addDragDropScrollArea(ui->scrollArea);
104 109
105 110 // Widget is deleted when closed
106 111 setAttribute(Qt::WA_DeleteOnClose);
107 112 }
108 113
109 114 VisualizationTabWidget::~VisualizationTabWidget()
110 115 {
111 116 sqpApp->dragDropGuiController().removeDragDropScrollArea(ui->scrollArea);
112 117 delete ui;
113 118 }
114 119
115 120 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
116 121 {
117 122 ui->dragDropContainer->addDragWidget(zoneWidget);
118 123 }
119 124
120 125 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
121 126 {
122 127 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
123 128 }
124 129
125 130 QStringList VisualizationTabWidget::availableZoneWidgets() const
126 131 {
127 132 QStringList zones;
128 133 processZones(tabLayout(),
129 134 [&zones](VisualizationZoneWidget &zoneWidget) { zones << zoneWidget.name(); });
130 135
131 136 return zones;
132 137 }
133 138
134 139 VisualizationZoneWidget *VisualizationTabWidget::getZoneWithName(const QString &zoneName)
135 140 {
136 141 VisualizationZoneWidget *result = nullptr;
137 142 processZones(tabLayout(), [&zoneName, &result](VisualizationZoneWidget &zoneWidget) {
138 143 if (!result && zoneWidget.name() == zoneName) {
139 144 result = &zoneWidget;
140 145 }
141 146 });
142 147
143 148 return result;
144 149 }
145 150
146 151 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
147 152 {
148 153 return createZone({variable}, -1);
149 154 }
150 155
151 156 VisualizationZoneWidget *
152 157 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
153 158 {
154 159 auto zoneWidget = createEmptyZone(index);
155 160
156 161 // Creates a new graph into the zone
157 162 zoneWidget->createGraph(variables, index);
158 163
159 164 return zoneWidget;
160 165 }
161 166
162 167 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
163 168 {
164 169 auto zoneWidget
165 170 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
166 171 this->insertZone(index, zoneWidget);
167 172
168 173 return zoneWidget;
169 174 }
170 175
171 176 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
172 177 {
173 178 if (visitor) {
174 179 visitor->visitEnter(this);
175 180
176 181 // Apply visitor to zone children: widgets different from zones are not visited (no action)
177 182 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
178 183 zoneWidget.accept(visitor);
179 184 });
180 185
181 186 visitor->visitLeave(this);
182 187 }
183 188 else {
184 189 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
185 190 }
186 191 }
187 192
188 193 bool VisualizationTabWidget::canDrop(const Variable &variable) const
189 194 {
190 195 // A tab can always accomodate a variable
191 196 Q_UNUSED(variable);
192 197 return true;
193 198 }
194 199
195 200 bool VisualizationTabWidget::contains(const Variable &variable) const
196 201 {
197 202 Q_UNUSED(variable);
198 203 return false;
199 204 }
200 205
201 206 QString VisualizationTabWidget::name() const
202 207 {
203 208 return impl->m_Name;
204 209 }
205 210
206 211 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
207 212 {
208 213 // Closes zones in the tab
209 214 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
210 215
211 216 QWidget::closeEvent(event);
212 217 }
213 218
214 219 QLayout &VisualizationTabWidget::tabLayout() const noexcept
215 220 {
216 221 return *ui->dragDropContainer->layout();
217 222 }
218 223
219 224 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
220 225 {
221 226 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
222 227 impl->dropGraph(index, this);
223 228 }
224 229 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
225 230 impl->dropZone(index, this);
226 231 }
227 232 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
228 233 auto variables = sqpApp->variableController().variablesForMimeData(
229 234 mimeData->data(MIME_TYPE_VARIABLE_LIST));
230 235 impl->dropVariables(variables, index, this);
231 236 }
237 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
238 auto productsData = sqpApp->dataSourceController().productsDataForMimeData(
239 mimeData->data(MIME_TYPE_PRODUCT_LIST));
240 impl->dropProducts(productsData, index, this);
241 }
232 242 else {
233 243 qCWarning(LOG_VisualizationZoneWidget())
234 244 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
235 245 }
236 246 }
237 247
238 248 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
239 249 int index, VisualizationTabWidget *tabWidget)
240 250 {
241 251 auto &helper = sqpApp->dragDropGuiController();
242 252
243 253 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
244 254 if (!graphWidget) {
245 255 qCWarning(LOG_VisualizationZoneWidget())
246 256 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
247 257 "found or invalid.");
248 258 Q_ASSERT(false);
249 259 return;
250 260 }
251 261
252 262 auto parentDragDropContainer
253 263 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
254 264 if (!parentDragDropContainer) {
255 265 qCWarning(LOG_VisualizationZoneWidget())
256 266 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
257 267 "the dropped graph is not found.");
258 268 Q_ASSERT(false);
259 269 return;
260 270 }
261 271
262 272 auto nbGraph = parentDragDropContainer->countDragWidget();
263 273
264 274 const auto &variables = graphWidget->variables();
265 275
266 276 if (!variables.isEmpty()) {
267 277 // Abort the requests for the variables (if any)
268 278 // Commented, because it's not sure if it's needed or not
269 279 // for (const auto& var : variables)
270 280 //{
271 281 // sqpApp->variableController().onAbortProgressRequested(var);
272 282 //}
273 283
274 284 if (nbGraph == 1) {
275 285 // This is the only graph in the previous zone, close the zone
276 286 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
277 287 }
278 288 else {
279 289 // Close the graph
280 290 helper.delayedCloseWidget(graphWidget);
281 291 }
282 292
283 293 auto zoneWidget = tabWidget->createZone(variables, index);
284 294 auto firstGraph = zoneWidget->firstGraph();
285 295 if (firstGraph) {
286 296 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
287 297 }
288 298 else {
289 299 qCWarning(LOG_VisualizationZoneWidget())
290 300 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
291 301 Q_ASSERT(false);
292 302 }
293 303 }
294 304 else {
295 305 // The graph is empty, create an empty zone and move the graph inside
296 306
297 307 auto parentZoneWidget = graphWidget->parentZoneWidget();
298 308
299 309 parentDragDropContainer->layout()->removeWidget(graphWidget);
300 310
301 311 auto zoneWidget = tabWidget->createEmptyZone(index);
302 312 zoneWidget->addGraph(graphWidget);
303 313
304 314 // Close the old zone if it was the only graph inside
305 315 if (nbGraph == 1) {
306 316 helper.delayedCloseWidget(parentZoneWidget);
307 317 }
308 318 }
309 319 }
310 320
311 321 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
312 322 int index, VisualizationTabWidget *tabWidget)
313 323 {
314 324 auto &helper = sqpApp->dragDropGuiController();
315 325
316 326 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
317 327 if (!zoneWidget) {
318 328 qCWarning(LOG_VisualizationZoneWidget())
319 329 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
320 330 "found or invalid.");
321 331 Q_ASSERT(false);
322 332 return;
323 333 }
324 334
325 335 auto parentDragDropContainer
326 336 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
327 337 if (!parentDragDropContainer) {
328 338 qCWarning(LOG_VisualizationZoneWidget())
329 339 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
330 340 "the dropped zone is not found.");
331 341 Q_ASSERT(false);
332 342 return;
333 343 }
334 344
335 345 // Simple move of the zone, no variable operation associated
336 346 parentDragDropContainer->layout()->removeWidget(zoneWidget);
337 347 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
338 348 }
339 349
340 350 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
341 351 const QList<std::shared_ptr<Variable> > &variables, int index,
342 352 VisualizationTabWidget *tabWidget)
343 353 {
344 354 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
345 355 // compatible variable here
346 356 if (variables.count() > 1) {
347 357 qCWarning(LOG_VisualizationZoneWidget())
348 358 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
349 359 "aborted.");
350 360 return;
351 361 }
352 362
353 363 tabWidget->createZone(variables, index);
354 364 }
365
366 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropProducts(
367 const QVariantList &productsMetaData, int index, VisualizationTabWidget *tabWidget)
368 {
369 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
370 // compatible variable here
371 if (productsMetaData.count() != 1) {
372 qCWarning(LOG_VisualizationZoneWidget())
373 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
374 "aborted.");
375 return;
376 }
377
378 auto productData = productsMetaData.first().toHash();
379 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
380 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
381
382
383 // TODO: add graph
384 }
@@ -1,601 +1,639
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 4 #include "Visualization/QCustomPlotSynchronizer.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "Visualization/VisualizationWidget.h"
7 7 #include "ui_VisualizationZoneWidget.h"
8 8
9 9 #include "Common/MimeTypesDef.h"
10 10 #include "Common/VisualizationDef.h"
11 11
12 12 #include <Data/SqpRange.h>
13 #include <DataSource/DataSourceController.h>
13 14 #include <Time/TimeController.h>
14 15 #include <Variable/Variable.h>
15 16 #include <Variable/VariableController.h>
16 17
17 18 #include <Visualization/operations/FindVariableOperation.h>
18 19
19 20 #include <DragAndDrop/DragDropGuiController.h>
20 21 #include <QUuid>
21 22 #include <SqpApplication.h>
22 23 #include <cmath>
23 24
24 25 #include <QLayout>
25 26
26 27 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27 28
28 29 namespace {
29 30
30 31 /**
31 32 * Applies a function to all graphs of the zone represented by its layout
32 33 * @param layout the layout that contains graphs
33 34 * @param fun the function to apply to each graph
34 35 */
35 36 template <typename Fun>
36 37 void processGraphs(QLayout &layout, Fun fun)
37 38 {
38 39 for (auto i = 0; i < layout.count(); ++i) {
39 40 if (auto item = layout.itemAt(i)) {
40 41 if (auto visualizationGraphWidget
41 42 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
42 43 fun(*visualizationGraphWidget);
43 44 }
44 45 }
45 46 }
46 47 }
47 48
48 49 /// Generates a default name for a new graph, according to the number of graphs already displayed in
49 50 /// the zone
50 51 QString defaultGraphName(QLayout &layout)
51 52 {
52 53 QSet<QString> existingNames;
53 54 processGraphs(
54 55 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
55 56
56 57 int zoneNum = 1;
57 58 QString name;
58 59 do {
59 60 name = QObject::tr("Graph ").append(QString::number(zoneNum));
60 61 ++zoneNum;
61 62 } while (existingNames.contains(name));
62 63
63 64 return name;
64 65 }
65 66
66 67 } // namespace
67 68
68 69 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
69 70
70 71 explicit VisualizationZoneWidgetPrivate()
71 72 : m_SynchronisationGroupId{QUuid::createUuid()},
72 73 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
73 74 {
74 75 }
75 76 QUuid m_SynchronisationGroupId;
76 77 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
77 78
78 79 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
79 80 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
80 81 VisualizationZoneWidget *zoneWidget);
82 void dropProducts(const QVariantList &productsData, int index,
83 VisualizationZoneWidget *zoneWidget);
81 84 };
82 85
83 86 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
84 87 : VisualizationDragWidget{parent},
85 88 ui{new Ui::VisualizationZoneWidget},
86 89 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
87 90 {
88 91 ui->setupUi(this);
89 92
90 93 ui->zoneNameLabel->setText(name);
91 94
92 95 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
93 96 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
94 97 VisualizationDragDropContainer::DropBehavior::Inserted);
95 98 ui->dragDropContainer->setMimeType(
96 99 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
100 ui->dragDropContainer->setMimeType(
101 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
97 102 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
98 103 VisualizationDragDropContainer::DropBehavior::Merged);
99 104 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
100 105 VisualizationDragDropContainer::DropBehavior::Forbidden);
101 106 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
102 107 VisualizationDragDropContainer::DropBehavior::Forbidden);
103 108 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
104 109 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
105 110 ui->dragDropContainer);
106 111 });
107 112
108 113 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
109 114 if (!mimeData) {
110 115 return false;
111 116 }
112 117
113 118 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
114 119 auto variables = sqpApp->variableController().variablesForMimeData(
115 120 mimeData->data(MIME_TYPE_VARIABLE_LIST));
116 121
117 122 if (variables.count() != 1) {
118 123 return false;
119 124 }
120 125 auto variable = variables.first();
121 126
122 127 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
123 128 return graphWidget->canDrop(*variable);
124 129 }
125 130 }
126 131
127 132 return true;
128 133 };
129 134 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
130 135
131 136 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
132 137 &VisualizationZoneWidget::dropMimeData);
133 138 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
134 139 &VisualizationZoneWidget::dropMimeDataOnGraph);
135 140
136 141 // 'Close' options : widget is deleted when closed
137 142 setAttribute(Qt::WA_DeleteOnClose);
138 143 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
139 144 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
140 145
141 146 // Synchronisation id
142 147 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
143 148 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
144 149 }
145 150
146 151 VisualizationZoneWidget::~VisualizationZoneWidget()
147 152 {
148 153 delete ui;
149 154 }
150 155
151 156 void VisualizationZoneWidget::setZoneRange(const SqpRange &range)
152 157 {
153 158 if (auto graph = firstGraph()) {
154 159 graph->setGraphRange(range);
155 160 }
156 161 else {
157 162 qCWarning(LOG_VisualizationZoneWidget())
158 163 << tr("setZoneRange:Cannot set the range of an empty zone.");
159 164 }
160 165 }
161 166
162 167 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
163 168 {
164 169 // Synchronize new graph with others in the zone
165 170 impl->m_Synchronizer->addGraph(*graphWidget);
166 171
167 172 ui->dragDropContainer->addDragWidget(graphWidget);
168 173 }
169 174
170 175 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
171 176 {
172 177 // Synchronize new graph with others in the zone
173 178 impl->m_Synchronizer->addGraph(*graphWidget);
174 179
175 180 ui->dragDropContainer->insertDragWidget(index, graphWidget);
176 181 }
177 182
178 183 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
179 184 {
180 185 return createGraph(variable, -1);
181 186 }
182 187
183 188 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
184 189 int index)
185 190 {
186 191 auto graphWidget
187 192 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
188 193
189 194
190 195 // Set graph properties
191 196 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
192 197 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
193 198
194 199
195 200 // Lambda to synchronize zone widget
196 201 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
197 202 const SqpRange &oldGraphRange) {
198 203
199 204 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
200 205 auto frameLayout = ui->dragDropContainer->layout();
201 206 for (auto i = 0; i < frameLayout->count(); ++i) {
202 207 auto graphChild
203 208 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
204 209 if (graphChild && (graphChild != graphWidget)) {
205 210
206 211 auto graphChildRange = graphChild->graphRange();
207 212 switch (zoomType) {
208 213 case AcquisitionZoomType::ZoomIn: {
209 214 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
210 215 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
211 216 graphChildRange.m_TStart += deltaLeft;
212 217 graphChildRange.m_TEnd -= deltaRight;
213 218 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
214 219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
215 220 << deltaLeft;
216 221 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
217 222 << deltaRight;
218 223 qCDebug(LOG_VisualizationZoneWidget())
219 224 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
220 225
221 226 break;
222 227 }
223 228
224 229 case AcquisitionZoomType::ZoomOut: {
225 230 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
226 231 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
227 232 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
228 233 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
229 234 << deltaLeft;
230 235 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
231 236 << deltaRight;
232 237 qCDebug(LOG_VisualizationZoneWidget())
233 238 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
234 239 graphChildRange.m_TStart -= deltaLeft;
235 240 graphChildRange.m_TEnd += deltaRight;
236 241 break;
237 242 }
238 243 case AcquisitionZoomType::PanRight: {
239 244 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
240 245 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
241 246 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
242 247 graphChildRange.m_TStart += deltaLeft;
243 248 graphChildRange.m_TEnd += deltaRight;
244 249 qCDebug(LOG_VisualizationZoneWidget())
245 250 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
246 251 break;
247 252 }
248 253 case AcquisitionZoomType::PanLeft: {
249 254 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
250 255 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
251 256 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
252 257 graphChildRange.m_TStart -= deltaLeft;
253 258 graphChildRange.m_TEnd -= deltaRight;
254 259 break;
255 260 }
256 261 case AcquisitionZoomType::Unknown: {
257 262 qCDebug(LOG_VisualizationZoneWidget())
258 263 << tr("Impossible to synchronize: zoom type unknown");
259 264 break;
260 265 }
261 266 default:
262 267 qCCritical(LOG_VisualizationZoneWidget())
263 268 << tr("Impossible to synchronize: zoom type not take into account");
264 269 // No action
265 270 break;
266 271 }
267 272 graphChild->setFlags(GraphFlag::DisableAll);
268 273 qCDebug(LOG_VisualizationZoneWidget())
269 274 << tr("TORM: Range before: ") << graphChild->graphRange();
270 275 qCDebug(LOG_VisualizationZoneWidget())
271 276 << tr("TORM: Range after : ") << graphChildRange;
272 277 qCDebug(LOG_VisualizationZoneWidget())
273 278 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
274 279 graphChild->setGraphRange(graphChildRange);
275 280 graphChild->setFlags(GraphFlag::EnableAll);
276 281 }
277 282 }
278 283 };
279 284
280 285 // connection for synchronization
281 286 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
282 287 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
283 288 &VisualizationZoneWidget::onVariableAdded);
284 289 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
285 290 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
286 291
287 292 auto range = SqpRange{};
288 293 if (auto firstGraph = this->firstGraph()) {
289 294 // Case of a new graph in a existant zone
290 295 range = firstGraph->graphRange();
291 296 }
292 297 else {
293 298 // Case of a new graph as the first of the zone
294 299 range = variable->range();
295 300 }
296 301
297 302 this->insertGraph(index, graphWidget);
298 303
299 304 graphWidget->addVariable(variable, range);
300 305 graphWidget->setYRange(variable);
301 306
302 307 return graphWidget;
303 308 }
304 309
305 310 VisualizationGraphWidget *
306 311 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
307 312 {
308 313 if (variables.isEmpty()) {
309 314 return nullptr;
310 315 }
311 316
312 317 auto graphWidget = createGraph(variables.first(), index);
313 318 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
314 319 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
315 320 }
316 321
317 322 return graphWidget;
318 323 }
319 324
320 325 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
321 326 {
322 327 VisualizationGraphWidget *firstGraph = nullptr;
323 328 auto layout = ui->dragDropContainer->layout();
324 329 if (layout->count() > 0) {
325 330 if (auto visualizationGraphWidget
326 331 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
327 332 firstGraph = visualizationGraphWidget;
328 333 }
329 334 }
330 335
331 336 return firstGraph;
332 337 }
333 338
334 339 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
335 340 {
336 341 if (visitor) {
337 342 visitor->visitEnter(this);
338 343
339 344 // Apply visitor to graph children: widgets different from graphs are not visited (no
340 345 // action)
341 346 processGraphs(
342 347 *ui->dragDropContainer->layout(),
343 348 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
344 349
345 350 visitor->visitLeave(this);
346 351 }
347 352 else {
348 353 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
349 354 }
350 355 }
351 356
352 357 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
353 358 {
354 359 // A tab can always accomodate a variable
355 360 Q_UNUSED(variable);
356 361 return true;
357 362 }
358 363
359 364 bool VisualizationZoneWidget::contains(const Variable &variable) const
360 365 {
361 366 Q_UNUSED(variable);
362 367 return false;
363 368 }
364 369
365 370 QString VisualizationZoneWidget::name() const
366 371 {
367 372 return ui->zoneNameLabel->text();
368 373 }
369 374
370 375 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
371 376 {
372 377 Q_UNUSED(position);
373 378
374 379 auto mimeData = new QMimeData;
375 380 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
376 381
377 382 if (auto firstGraph = this->firstGraph()) {
378 383 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
379 384 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
380 385 }
381 386
382 387 return mimeData;
383 388 }
384 389
385 390 bool VisualizationZoneWidget::isDragAllowed() const
386 391 {
387 392 return true;
388 393 }
389 394
390 395 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
391 396 const QPointF &plotPosition,
392 397 VisualizationGraphWidget *graphWidget)
393 398 {
394 399 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
395 400 VisualizationGraphWidget &processedGraph) {
396 401
397 402 switch (sqpApp->plotsCursorMode()) {
398 403 case SqpApplication::PlotsCursorMode::Vertical:
399 404 processedGraph.removeHorizontalCursor();
400 405 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
401 406 break;
402 407 case SqpApplication::PlotsCursorMode::Temporal:
403 408 processedGraph.addVerticalCursor(plotPosition.x());
404 409 processedGraph.removeHorizontalCursor();
405 410 break;
406 411 case SqpApplication::PlotsCursorMode::Horizontal:
407 412 processedGraph.removeVerticalCursor();
408 413 if (&processedGraph == graphWidget) {
409 414 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
410 415 }
411 416 else {
412 417 processedGraph.removeHorizontalCursor();
413 418 }
414 419 break;
415 420 case SqpApplication::PlotsCursorMode::Cross:
416 421 if (&processedGraph == graphWidget) {
417 422 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
418 423 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
419 424 }
420 425 else {
421 426 processedGraph.removeHorizontalCursor();
422 427 processedGraph.removeVerticalCursor();
423 428 }
424 429 break;
425 430 case SqpApplication::PlotsCursorMode::NoCursor:
426 431 processedGraph.removeHorizontalCursor();
427 432 processedGraph.removeVerticalCursor();
428 433 break;
429 434 }
430 435
431 436
432 437 });
433 438 }
434 439
435 440 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
436 441 {
437 442 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
438 443 processedGraph.removeHorizontalCursor();
439 444 processedGraph.removeVerticalCursor();
440 445 });
441 446 }
442 447
443 448 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
444 449 {
445 450 // Closes graphs in the zone
446 451 processGraphs(*ui->dragDropContainer->layout(),
447 452 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
448 453
449 454 // Delete synchronization group from variable controller
450 455 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
451 456 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
452 457
453 458 QWidget::closeEvent(event);
454 459 }
455 460
456 461 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
457 462 {
458 463 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
459 464 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
460 465 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
461 466 }
462 467
463 468 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
464 469 {
465 470 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
466 471 Q_ARG(std::shared_ptr<Variable>, variable),
467 472 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
468 473 }
469 474
470 475 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
471 476 {
472 477 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
473 478 impl->dropGraph(index, this);
474 479 }
475 480 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
476 481 auto variables = sqpApp->variableController().variablesForMimeData(
477 482 mimeData->data(MIME_TYPE_VARIABLE_LIST));
478 483 impl->dropVariables(variables, index, this);
479 484 }
485 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
486 auto products = sqpApp->dataSourceController().productsDataForMimeData(
487 mimeData->data(MIME_TYPE_PRODUCT_LIST));
488 impl->dropProducts(products, index, this);
489 }
480 490 else {
481 491 qCWarning(LOG_VisualizationZoneWidget())
482 492 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
483 493 }
484 494 }
485 495
486 496 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
487 497 const QMimeData *mimeData)
488 498 {
489 499 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
490 500 if (!graphWidget) {
491 501 qCWarning(LOG_VisualizationZoneWidget())
492 502 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
493 503 "drop aborted");
494 504 Q_ASSERT(false);
495 505 return;
496 506 }
497 507
498 508 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
499 509 auto variables = sqpApp->variableController().variablesForMimeData(
500 510 mimeData->data(MIME_TYPE_VARIABLE_LIST));
501 511 for (const auto &var : variables) {
502 512 graphWidget->addVariable(var, graphWidget->graphRange());
503 513 }
504 514 }
515 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
516 auto products = sqpApp->dataSourceController().productsDataForMimeData(
517 mimeData->data(MIME_TYPE_PRODUCT_LIST));
518
519 auto productData = products.first().toHash();
520 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
521 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
522 }
505 523 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
506 524 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
507 525 graphWidget->setGraphRange(range);
508 526 }
509 527 else {
510 528 qCWarning(LOG_VisualizationZoneWidget())
511 529 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
512 530 }
513 531 }
514 532
515 533 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
516 534 int index, VisualizationZoneWidget *zoneWidget)
517 535 {
518 536 auto &helper = sqpApp->dragDropGuiController();
519 537
520 538 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
521 539 if (!graphWidget) {
522 540 qCWarning(LOG_VisualizationZoneWidget())
523 541 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
524 542 "found or invalid.");
525 543 Q_ASSERT(false);
526 544 return;
527 545 }
528 546
529 547 auto parentDragDropContainer
530 548 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
531 549 if (!parentDragDropContainer) {
532 550 qCWarning(LOG_VisualizationZoneWidget())
533 551 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
534 552 "the dropped graph is not found.");
535 553 Q_ASSERT(false);
536 554 return;
537 555 }
538 556
539 557 const auto &variables = graphWidget->variables();
540 558
541 559 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
542 560 // The drop didn't occur in the same zone
543 561
544 562 // Abort the requests for the variables (if any)
545 563 // Commented, because it's not sure if it's needed or not
546 564 // for (const auto& var : variables)
547 565 //{
548 566 // sqpApp->variableController().onAbortProgressRequested(var);
549 567 //}
550 568
551 569 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
552 570 auto nbGraph = parentDragDropContainer->countDragWidget();
553 571 if (nbGraph == 1) {
554 572 // This is the only graph in the previous zone, close the zone
555 573 helper.delayedCloseWidget(previousParentZoneWidget);
556 574 }
557 575 else {
558 576 // Close the graph
559 577 helper.delayedCloseWidget(graphWidget);
560 578 }
561 579
562 580 // Creates the new graph in the zone
563 581 auto newGraphWidget = zoneWidget->createGraph(variables, index);
564 582 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
565 583 }
566 584 else {
567 585 // The drop occurred in the same zone or the graph is empty
568 586 // Simple move of the graph, no variable operation associated
569 587 parentDragDropContainer->layout()->removeWidget(graphWidget);
570 588
571 589 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
572 590 // The graph is empty and dropped in a different zone.
573 591 // Take the range of the first graph in the zone (if existing).
574 592 auto layout = zoneWidget->ui->dragDropContainer->layout();
575 593 if (layout->count() > 0) {
576 594 if (auto visualizationGraphWidget
577 595 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
578 596 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
579 597 }
580 598 }
581 599 }
582 600
583 601 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
584 602 }
585 603 }
586 604
587 605 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
588 606 const QList<std::shared_ptr<Variable> > &variables, int index,
589 607 VisualizationZoneWidget *zoneWidget)
590 608 {
591 609 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
592 610 // compatible variable here
593 611 if (variables.count() > 1) {
594 612 qCWarning(LOG_VisualizationZoneWidget())
595 613 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
596 614 "aborted.");
597 615 return;
598 616 }
599 617
600 618 zoneWidget->createGraph(variables, index);
601 619 }
620
621 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
622 const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget)
623 {
624 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
625 // compatible variable here
626 if (productsData.count() != 1) {
627 qCWarning(LOG_VisualizationZoneWidget())
628 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
629 "aborted.");
630 return;
631 }
632
633 auto productData = productsData.first().toHash();
634 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
635 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
636
637
638 // TODO: add graph
639 }
General Comments 0
You need to be logged in to leave comments. Login now