##// END OF EJS Templates
drop of product on the visu
trabillard -
r875:4aae8a8d06e9 DropProductOnVisu...
parent child
Show More
@@ -1,99 +1,101
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 std::shared_ptr<IDataProvider> providerForProductData(const QVariantHash &productData);
68
67 69 QByteArray mimeDataForProductsData(const QVariantList &productsData) const;
68 70 QVariantList productsDataForMimeData(const QByteArray &mimeData) const;
69 71
70 72 public slots:
71 73 /// Manage init/end of the controller
72 74 void initialize();
73 75 void finalize();
74 76
75 77 void requestVariable(const QVariantHash &productData);
76 78
77 79 signals:
78 80 /// Signal emitted when a structure has been set for a data source
79 81 void dataSourceItemSet(DataSourceItem *dataSourceItem);
80 82
81 83 /**
82 84 * Signal emitted when a variable creation is asked for a product
83 85 * @param variableName the name of the variable
84 86 * @param variableMetadata the metadata of the variable
85 87 * @param variableProvider the provider that will be used to retrieve the data of the variable
86 88 * (can be null)
87 89 */
88 90 void variableCreationRequested(const QString &variableName,
89 91 const QVariantHash &variableMetadata,
90 92 std::shared_ptr<IDataProvider> variableProvider);
91 93
92 94 private:
93 95 void waitForFinish();
94 96
95 97 class DataSourceControllerPrivate;
96 98 spimpl::unique_impl_ptr<DataSourceControllerPrivate> impl;
97 99 };
98 100
99 101 #endif // SCIQLOP_DATASOURCECONTROLLER_H
@@ -1,192 +1,212
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 namespace {
16 16
17 17 /**
18 18 * Builds the metadata of the variable that will be generated from the loading of an item
19 19 * @param dataSourceItem the data source item from which to generate the metadata
20 20 * @return the metadata of the variable
21 21 */
22 22 QVariantHash variableMetadata(const DataSourceItem &dataSourceItem)
23 23 {
24 24 // Variable metadata contains...
25 25
26 26 // ... all metadata of the item
27 27 auto result = dataSourceItem.data();
28 28
29 29 // ... and the name of the plugin, recovered from root item
30 30 result.insert(QStringLiteral("plugin"), dataSourceItem.rootItem().name());
31 31
32 32 return result;
33 33 }
34 34
35 35 } // namespace
36 36
37 37 class DataSourceController::DataSourceControllerPrivate {
38 38 public:
39 39 QMutex m_WorkingMutex;
40 40 /// Data sources registered
41 41 QHash<QUuid, QString> m_DataSources;
42 42 /// Data sources structures
43 43 std::map<QUuid, std::unique_ptr<DataSourceItem> > m_DataSourceItems;
44 44 /// Data providers registered
45 45 /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and
46 46 /// continue to live without necessarily the data source controller
47 47 std::map<QUuid, std::shared_ptr<IDataProvider> > m_DataProviders;
48 48
49 49 // Search for the first datasource item matching the specified data
50 50 DataSourceItem *findDataSourceItem(const QVariantHash &data)
51 51 {
52 52 DataSourceItem *sourceItem = nullptr;
53 53 for (const auto &item : m_DataSourceItems) {
54 54 sourceItem = item.second->findItem(data, true);
55 55 if (sourceItem) {
56 56 break;
57 57 }
58 58 }
59 59
60 60 return sourceItem;
61 61 }
62 62 };
63 63
64 64 DataSourceController::DataSourceController(QObject *parent)
65 65 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
66 66 {
67 67 qCDebug(LOG_DataSourceController())
68 68 << tr("DataSourceController construction") << QThread::currentThread();
69 69 }
70 70
71 71 DataSourceController::~DataSourceController()
72 72 {
73 73 qCDebug(LOG_DataSourceController())
74 74 << tr("DataSourceController destruction") << QThread::currentThread();
75 75 this->waitForFinish();
76 76 }
77 77
78 78 QUuid DataSourceController::registerDataSource(const QString &dataSourceName) noexcept
79 79 {
80 80 auto dataSourceUid = QUuid::createUuid();
81 81 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
82 82
83 83 return dataSourceUid;
84 84 }
85 85
86 86 void DataSourceController::setDataSourceItem(
87 87 const QUuid &dataSourceUid, std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
88 88 {
89 89 if (!dataSourceItem) {
90 90 qCWarning(LOG_DataSourceController())
91 91 << tr("Data source item can't be registered (null item)");
92 92 return;
93 93 }
94 94
95 95 if (impl->m_DataSources.contains(dataSourceUid)) {
96 96 // The data provider is implicitly converted to a shared_ptr
97 97 impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem)));
98 98
99 99 // Retrieves the data source item to emit the signal with it
100 100 auto it = impl->m_DataSourceItems.find(dataSourceUid);
101 101 if (it != impl->m_DataSourceItems.end()) {
102 102 emit dataSourceItemSet(it->second.get());
103 103 }
104 104 }
105 105 else {
106 106 qCWarning(LOG_DataSourceController()) << tr("Can't set data source item for uid %1 : no "
107 107 "data source has been registered with the uid")
108 108 .arg(dataSourceUid.toString());
109 109 }
110 110 }
111 111
112 112 void DataSourceController::setDataProvider(const QUuid &dataSourceUid,
113 113 std::unique_ptr<IDataProvider> dataProvider) noexcept
114 114 {
115 115 if (impl->m_DataSources.contains(dataSourceUid)) {
116 116 impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider)));
117 117 }
118 118 else {
119 119 qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data "
120 120 "source has been registered with the uid")
121 121 .arg(dataSourceUid.toString());
122 122 }
123 123 }
124 124
125 125 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
126 126 const DataSourceItem &productItem) noexcept
127 127 {
128 128 if (productItem.type() == DataSourceItemType::PRODUCT
129 129 || productItem.type() == DataSourceItemType::COMPONENT) {
130 130 /// Retrieves the data provider of the data source (if any)
131 131 auto it = impl->m_DataProviders.find(dataSourceUid);
132 132 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
133 133
134 134 emit variableCreationRequested(productItem.name(), variableMetadata(productItem),
135 135 dataProvider);
136 136 }
137 137 else {
138 138 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
139 139 }
140 140 }
141 141
142 std::shared_ptr<IDataProvider>
143 DataSourceController::providerForProductData(const QVariantHash &productData)
144 {
145 DataSourceItem *sourceItem = impl->findDataSourceItem(productData);
146
147 if (sourceItem && sourceItem->type() == DataSourceItemType::PRODUCT
148 || sourceItem->type() == DataSourceItemType::COMPONENT) {
149 auto sourceName = sourceItem->rootItem().name();
150 auto sourceId = impl->m_DataSources.key(sourceName);
151 auto it = impl->m_DataProviders.find(sourceId);
152 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
153 return dataProvider;
154 }
155 else {
156 qCWarning(LOG_DataSourceController()) << tr("requestVariable, product data not found");
157 }
158
159 return nullptr;
160 }
161
142 162 QByteArray DataSourceController::mimeDataForProductsData(const QVariantList &productsData) const
143 163 {
144 164 QByteArray encodedData;
145 165 QDataStream stream(&encodedData, QIODevice::WriteOnly);
146 166
147 167 stream << productsData;
148 168
149 169 return encodedData;
150 170 }
151 171
152 172 QVariantList DataSourceController::productsDataForMimeData(const QByteArray &mimeData) const
153 173 {
154 174 QDataStream stream(mimeData);
155 175
156 176 QVariantList productList;
157 177 stream >> productList;
158 178
159 179 return productList;
160 180 }
161 181
162 182 void DataSourceController::initialize()
163 183 {
164 184 qCDebug(LOG_DataSourceController())
165 185 << tr("DataSourceController init") << QThread::currentThread();
166 186 impl->m_WorkingMutex.lock();
167 187 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
168 188 }
169 189
170 190 void DataSourceController::finalize()
171 191 {
172 192 impl->m_WorkingMutex.unlock();
173 193 }
174 194
175 195 void DataSourceController::requestVariable(const QVariantHash &productData)
176 196 {
177 197 DataSourceItem *sourceItem = impl->findDataSourceItem(productData);
178 198
179 199 if (sourceItem) {
180 200 auto sourceName = sourceItem->rootItem().name();
181 201 auto sourceId = impl->m_DataSources.key(sourceName);
182 202 loadProductItem(sourceId, *sourceItem);
183 203 }
184 204 else {
185 205 qCWarning(LOG_DataSourceController()) << tr("requestVariable, product data not found");
186 206 }
187 207 }
188 208
189 209 void DataSourceController::waitForFinish()
190 210 {
191 211 QMutexLocker locker{&impl->m_WorkingMutex};
192 212 }
@@ -1,287 +1,295
1 1 #include "DragDropHelper.h"
2 2 #include "SqpApplication.h"
3 3 #include "Visualization/VisualizationDragDropContainer.h"
4 4 #include "Visualization/VisualizationDragWidget.h"
5 5 #include "Visualization/VisualizationWidget.h"
6 6 #include "Visualization/operations/FindVariableOperation.h"
7 7
8 8 #include "Variable/VariableController.h"
9 9
10 10 #include "Common/MimeTypesDef.h"
11 11 #include "Common/VisualizationDef.h"
12 12
13 13 #include <QDir>
14 14 #include <QDragEnterEvent>
15 15 #include <QDragMoveEvent>
16 16 #include <QScrollArea>
17 17 #include <QScrollBar>
18 18 #include <QTimer>
19 19 #include <QVBoxLayout>
20 20
21 21 const int SCROLL_SPEED = 5;
22 22 const int SCROLL_ZONE_SIZE = 50;
23 23
24 24 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
25 25
26 26 struct DragDropScroller::DragDropScrollerPrivate {
27 27
28 28 QList<QScrollArea *> m_ScrollAreas;
29 29 QScrollArea *m_CurrentScrollArea = nullptr;
30 30 std::unique_ptr<QTimer> m_Timer = nullptr;
31 31
32 32
33 33 enum class ScrollDirection { up, down, unknown };
34 34 ScrollDirection m_Direction = ScrollDirection::unknown;
35 35
36 36 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
37 37 {
38 38 m_Timer->setInterval(0);
39 39 }
40 40 };
41 41
42 42 DragDropScroller::DragDropScroller(QObject *parent)
43 43 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
44 44 {
45 45 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
46 46 }
47 47
48 48 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
49 49 {
50 50 impl->m_ScrollAreas << scrollArea;
51 51 scrollArea->viewport()->setAcceptDrops(true);
52 52 }
53 53
54 54 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
55 55 {
56 56 impl->m_ScrollAreas.removeAll(scrollArea);
57 57 scrollArea->viewport()->setAcceptDrops(false);
58 58 }
59 59
60 60 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
61 61 {
62 62 if (event->type() == QEvent::DragMove) {
63 63 auto w = static_cast<QWidget *>(obj);
64 64
65 65 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
66 66 auto moveEvent = static_cast<QDragMoveEvent *>(event);
67 67
68 68 auto pos = moveEvent->pos();
69 69 if (impl->m_CurrentScrollArea->viewport() != w) {
70 70 auto globalPos = w->mapToGlobal(moveEvent->pos());
71 71 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
72 72 }
73 73
74 74 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
75 75 - SCROLL_ZONE_SIZE;
76 76 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
77 77
78 78 if (!isInTopZone && !isInBottomZone) {
79 79 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
80 80 impl->m_Timer->stop();
81 81 }
82 82 else if (!impl->m_Timer->isActive()) {
83 83 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
84 84 : DragDropScrollerPrivate::ScrollDirection::down;
85 85 impl->m_Timer->start();
86 86 }
87 87 }
88 88 }
89 89 else if (event->type() == QEvent::DragEnter) {
90 90 auto w = static_cast<QWidget *>(obj);
91 91
92 92 for (auto scrollArea : impl->m_ScrollAreas) {
93 93 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
94 94 auto enterEvent = static_cast<QDragEnterEvent *>(event);
95 95 enterEvent->acceptProposedAction();
96 96 enterEvent->setDropAction(Qt::IgnoreAction);
97 97 impl->m_CurrentScrollArea = scrollArea;
98 98 break;
99 99 }
100 100 }
101 101 }
102 102 else if (event->type() == QEvent::DragLeave) {
103 103 if (impl->m_CurrentScrollArea) {
104 104 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
105 105 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
106 106 impl->m_CurrentScrollArea = nullptr;
107 107 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
108 108 impl->m_Timer->stop();
109 109 }
110 110 }
111 111 }
112 112 else if (event->type() == QEvent::Drop) {
113 113 if (impl->m_CurrentScrollArea) {
114 114 impl->m_CurrentScrollArea = nullptr;
115 115 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
116 116 impl->m_Timer->stop();
117 117 }
118 118 }
119 119
120 120 return false;
121 121 }
122 122
123 123 void DragDropScroller::onTimer()
124 124 {
125 125 if (impl->m_CurrentScrollArea) {
126 126 auto mvt = 0;
127 127 switch (impl->m_Direction) {
128 128 case DragDropScrollerPrivate::ScrollDirection::up:
129 129 mvt = SCROLL_SPEED;
130 130 break;
131 131 case DragDropScrollerPrivate::ScrollDirection::down:
132 132 mvt = -SCROLL_SPEED;
133 133 break;
134 134 default:
135 135 break;
136 136 }
137 137
138 138 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
139 139 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
140 140 }
141 141 }
142 142
143 143 struct DragDropHelper::DragDropHelperPrivate {
144 144
145 145 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
146 146 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
147 147 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
148 148 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
149 149 // QTemporaryFile to have a name which is not generated.
150 150
151 151 explicit DragDropHelperPrivate()
152 152 : m_PlaceHolder{std::make_unique<QWidget>()},
153 153 m_DragDropScroller{std::make_unique<DragDropScroller>()}
154 154 {
155 155 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
156 156 sqpApp->installEventFilter(m_DragDropScroller.get());
157 157
158 158
159 159 m_ImageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png");
160 160 }
161 161
162 162 void preparePlaceHolder() const
163 163 {
164 164 if (m_CurrentDragWidget) {
165 165 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
166 166 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
167 167 }
168 168 else {
169 169 // Configuration of the placeHolder when there is no dragWidget
170 170 // (for instance with a drag from a variable)
171 171
172 172 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
173 173 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
174 174 }
175 175 }
176 176 };
177 177
178 178
179 179 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()} {}
180 180
181 181 DragDropHelper::~DragDropHelper()
182 182 {
183 183 QFile::remove(impl->m_ImageTempUrl);
184 184 }
185 185
186 186 void DragDropHelper::resetDragAndDrop()
187 187 {
188 188 setCurrentDragWidget(nullptr);
189 189 }
190 190
191 191 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
192 192 {
193 193 impl->m_CurrentDragWidget = dragWidget;
194 194 }
195 195
196 196 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
197 197 {
198 198 return impl->m_CurrentDragWidget;
199 199 }
200 200
201 201
202 202 QWidget &DragDropHelper::placeHolder() const
203 203 {
204 204 return *impl->m_PlaceHolder;
205 205 }
206 206
207 207 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
208 208 {
209 209 removePlaceHolder();
210 210 impl->preparePlaceHolder();
211 211 layout->insertWidget(index, impl->m_PlaceHolder.get());
212 212 impl->m_PlaceHolder->show();
213 213 }
214 214
215 215 void DragDropHelper::removePlaceHolder()
216 216 {
217 217 auto parentWidget = impl->m_PlaceHolder->parentWidget();
218 218 if (parentWidget) {
219 219 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
220 220 impl->m_PlaceHolder->setParent(nullptr);
221 221 impl->m_PlaceHolder->hide();
222 222 }
223 223 }
224 224
225 225 bool DragDropHelper::isPlaceHolderSet() const
226 226 {
227 227 return impl->m_PlaceHolder->parentWidget();
228 228 }
229 229
230 230 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
231 231 {
232 232 impl->m_DragDropScroller->addScrollArea(scrollArea);
233 233 }
234 234
235 235 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
236 236 {
237 237 impl->m_DragDropScroller->removeScrollArea(scrollArea);
238 238 }
239 239
240 240 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
241 241 {
242 242 image.save(impl->m_ImageTempUrl);
243 243 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
244 244 }
245 245
246 246 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
247 247 VisualizationDragDropContainer *dropContainer)
248 248 {
249 249 auto result = true;
250 250
251 251 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
252 252 auto variables = sqpApp->variableController().variablesForMimeData(
253 253 mimeData->data(MIME_TYPE_VARIABLE_LIST));
254 254
255 255 if (variables.count() == 1) {
256 256 // Check that the viariable is not already in a graph
257 257
258 258 // Search for the top level VisualizationWidget
259 259 auto parent = dropContainer->parentWidget();
260 260 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
261 261 parent = parent->parentWidget();
262 262 }
263 263
264 264 if (parent) {
265 265 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
266 266
267 267 FindVariableOperation findVariableOperation{variables.first()};
268 268 visualizationWidget->accept(&findVariableOperation);
269 269 auto variableContainers = findVariableOperation.result();
270 270 if (!variableContainers.empty()) {
271 271 result = false;
272 272 }
273 273 }
274 274 else {
275 275 qCWarning(LOG_DragDropHelper()) << QObject::tr(
276 276 "DragDropHelper::checkMimeDataForVisualization, the parent "
277 277 "VisualizationWidget cannot be found.");
278 278 result = false;
279 279 }
280 280 }
281 281 else {
282 282 result = false;
283 283 }
284 284 }
285 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
286 QDataStream stream(mimeData->data(MIME_TYPE_PRODUCT_LIST));
287
288 QVariantList productList;
289 stream >> productList;
290
291 result = productList.count() == 1;
292 }
285 293
286 294 return result;
287 295 }
@@ -1,294 +1,330
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 #include "DataSource/DataSourceController.h"
9 #include "DataSource/DataSourceItem.h"
8 10 #include "Variable/VariableController.h"
9 11
10 12 #include "Common/MimeTypesDef.h"
11 13
12 14 #include "DragDropHelper.h"
13 15 #include "SqpApplication.h"
14 16
17 #include <QTimer>
18
15 19 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
16 20
17 21 namespace {
18 22
19 23 /// Generates a default name for a new zone, according to the number of zones already displayed in
20 24 /// the tab
21 25 QString defaultZoneName(const QLayout &layout)
22 26 {
23 27 auto count = 0;
24 28 for (auto i = 0; i < layout.count(); ++i) {
25 29 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
26 30 count++;
27 31 }
28 32 }
29 33
30 34 return QObject::tr("Zone %1").arg(count + 1);
31 35 }
32 36
33 37 /**
34 38 * Applies a function to all zones of the tab represented by its layout
35 39 * @param layout the layout that contains zones
36 40 * @param fun the function to apply to each zone
37 41 */
38 42 template <typename Fun>
39 43 void processZones(QLayout &layout, Fun fun)
40 44 {
41 45 for (auto i = 0; i < layout.count(); ++i) {
42 46 if (auto item = layout.itemAt(i)) {
43 47 if (auto visualizationZoneWidget
44 48 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
45 49 fun(*visualizationZoneWidget);
46 50 }
47 51 }
48 52 }
49 53 }
50 54
51 55 } // namespace
52 56
53 57 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
54 58 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
55 59
56 60 QString m_Name;
57 61
58 62 void dropGraph(int index, VisualizationTabWidget *tabWidget);
59 63 void dropZone(int index, VisualizationTabWidget *tabWidget);
60 64 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
61 65 VisualizationTabWidget *tabWidget);
66 void dropProduct(const QVariantList &productDataList, int index,
67 VisualizationTabWidget *tabWidget);
62 68 };
63 69
64 70 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
65 71 : QWidget{parent},
66 72 ui{new Ui::VisualizationTabWidget},
67 73 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
68 74 {
69 75 ui->setupUi(this);
70 76
71 77 ui->dragDropContainer->setAcceptedMimeTypes(
72 {MIME_TYPE_GRAPH, MIME_TYPE_ZONE, MIME_TYPE_VARIABLE_LIST});
78 {MIME_TYPE_GRAPH, MIME_TYPE_ZONE, MIME_TYPE_VARIABLE_LIST, MIME_TYPE_PRODUCT_LIST});
73 79 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
74 80 &VisualizationTabWidget::dropMimeData);
75 81 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
76 82 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
77 83 ui->dragDropContainer);
78 84 });
79 85 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
80 86
81 87 // Widget is deleted when closed
82 88 setAttribute(Qt::WA_DeleteOnClose);
83 89 }
84 90
85 91 VisualizationTabWidget::~VisualizationTabWidget()
86 92 {
87 93 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
88 94 delete ui;
89 95 }
90 96
91 97 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
92 98 {
93 99 ui->dragDropContainer->addDragWidget(zoneWidget);
94 100 }
95 101
96 102 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
97 103 {
98 104 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
99 105 }
100 106
101 107 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
102 108 {
103 109 return createZone({variable}, -1);
104 110 }
105 111
106 112 VisualizationZoneWidget *
107 113 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
108 114 {
109 115 auto zoneWidget = createEmptyZone(index);
110 116
111 117 // Creates a new graph into the zone
112 118 zoneWidget->createGraph(variables, index);
113 119
114 120 return zoneWidget;
115 121 }
116 122
117 123 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
118 124 {
119 125 auto zoneWidget
120 126 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
121 127 this->insertZone(index, zoneWidget);
122 128
123 129 return zoneWidget;
124 130 }
125 131
126 132 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
127 133 {
128 134 if (visitor) {
129 135 visitor->visitEnter(this);
130 136
131 137 // Apply visitor to zone children: widgets different from zones are not visited (no action)
132 138 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
133 139 zoneWidget.accept(visitor);
134 140 });
135 141
136 142 visitor->visitLeave(this);
137 143 }
138 144 else {
139 145 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
140 146 }
141 147 }
142 148
143 149 bool VisualizationTabWidget::canDrop(const Variable &variable) const
144 150 {
145 151 // A tab can always accomodate a variable
146 152 Q_UNUSED(variable);
147 153 return true;
148 154 }
149 155
150 156 bool VisualizationTabWidget::contains(const Variable &variable) const
151 157 {
152 158 Q_UNUSED(variable);
153 159 return false;
154 160 }
155 161
156 162 QString VisualizationTabWidget::name() const
157 163 {
158 164 return impl->m_Name;
159 165 }
160 166
161 167 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
162 168 {
163 169 // Closes zones in the tab
164 170 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
165 171
166 172 QWidget::closeEvent(event);
167 173 }
168 174
169 175 QLayout &VisualizationTabWidget::tabLayout() const noexcept
170 176 {
171 177 return *ui->dragDropContainer->layout();
172 178 }
173 179
174 180 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
175 181 {
176 182 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
177 183 impl->dropGraph(index, this);
178 184 }
179 185 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
180 186 impl->dropZone(index, this);
181 187 }
182 188 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
183 189 auto variables = sqpApp->variableController().variablesForMimeData(
184 190 mimeData->data(MIME_TYPE_VARIABLE_LIST));
185 191 impl->dropVariables(variables, index, this);
186 192 }
193 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
194 auto productList = sqpApp->dataSourceController().productsDataForMimeData(
195 mimeData->data(MIME_TYPE_PRODUCT_LIST));
196 impl->dropProduct(productList, index, this);
197 }
187 198 else {
188 199 qCWarning(LOG_VisualizationZoneWidget())
189 200 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
190 201 }
191 202 }
192 203
193 204 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
194 205 int index, VisualizationTabWidget *tabWidget)
195 206 {
196 207 auto &helper = sqpApp->dragDropHelper();
197 208
198 209 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
199 210 if (!graphWidget) {
200 211 qCWarning(LOG_VisualizationZoneWidget())
201 212 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
202 213 "found or invalid.");
203 214 Q_ASSERT(false);
204 215 return;
205 216 }
206 217
207 218 auto parentDragDropContainer
208 219 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
209 220 if (!parentDragDropContainer) {
210 221 qCWarning(LOG_VisualizationZoneWidget())
211 222 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
212 223 "the dropped graph is not found.");
213 224 Q_ASSERT(false);
214 225 return;
215 226 }
216 227
217 228 auto nbGraph = parentDragDropContainer->countDragWidget();
218 229
219 230 const auto &variables = graphWidget->variables();
220 231
221 232 if (!variables.isEmpty()) {
222 233 // Abort the requests for the variables (if any)
223 234 // Commented, because it's not sure if it's needed or not
224 235 // for (const auto& var : variables)
225 236 //{
226 237 // sqpApp->variableController().onAbortProgressRequested(var);
227 238 //}
228 239
229 240 if (nbGraph == 1) {
230 241 // This is the only graph in the previous zone, close the zone
231 242 graphWidget->parentZoneWidget()->close();
232 243 }
233 244 else {
234 245 // Close the graph
235 246 graphWidget->close();
236 247 }
237 248
238 249 tabWidget->createZone(variables, index);
239 250 }
240 251 else {
241 252 // The graph is empty, create an empty zone and move the graph inside
242 253
243 254 auto parentZoneWidget = graphWidget->parentZoneWidget();
244 255
245 256 parentDragDropContainer->layout()->removeWidget(graphWidget);
246 257
247 258 auto zoneWidget = tabWidget->createEmptyZone(index);
248 259 zoneWidget->addGraph(graphWidget);
249 260
250 261 // Close the old zone if it was the only graph inside
251 262 if (nbGraph == 1) {
252 263 parentZoneWidget->close();
253 264 }
254 265 }
255 266 }
256 267
257 268 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
258 269 int index, VisualizationTabWidget *tabWidget)
259 270 {
260 271 auto &helper = sqpApp->dragDropHelper();
261 272
262 273 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
263 274 if (!zoneWidget) {
264 275 qCWarning(LOG_VisualizationZoneWidget())
265 276 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
266 277 "found or invalid.");
267 278 Q_ASSERT(false);
268 279 return;
269 280 }
270 281
271 282 auto parentDragDropContainer
272 283 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
273 284 if (!parentDragDropContainer) {
274 285 qCWarning(LOG_VisualizationZoneWidget())
275 286 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
276 287 "the dropped zone is not found.");
277 288 Q_ASSERT(false);
278 289 return;
279 290 }
280 291
281 292 // Simple move of the zone, no variable operation associated
282 293 parentDragDropContainer->layout()->removeWidget(zoneWidget);
283 294 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
284 295 }
285 296
286 297 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
287 298 const QList<std::shared_ptr<Variable> > &variables, int index,
288 299 VisualizationTabWidget *tabWidget)
289 300 {
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.
301 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
302 // compatible variable here
303 if (variables.count() > 1) {
304 qCWarning(LOG_VisualizationZoneWidget())
305 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
306 "aborted.");
307 return;
308 }
309
293 310 tabWidget->createZone(variables, index);
294 311 }
312
313 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropProduct(
314 const QVariantList &productDataList, int index, VisualizationTabWidget *tabWidget)
315 {
316 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
317 // compatible product here
318 if (productDataList.count() > 1) {
319 qCWarning(LOG_VisualizationZoneWidget()) << tr(
320 "VisualizationTabWidget::dropProduct, dropping multiple products, operation aborted.");
321 return;
322 }
323
324 auto productData = productDataList.first().toHash();
325 auto provider = sqpApp->dataSourceController().providerForProductData(productData);
326 auto name = productData.value(DataSourceItem::NAME_DATA_KEY).toString();
327 auto variable = sqpApp->variableController().createVariable(name, productData, provider);
328 QTimer::singleShot(
329 3000, [tabWidget, variable, index]() { tabWidget->createZone({variable}, index); });
330 }
@@ -1,484 +1,497
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>
14 #include <DataSource/DataSourceItem.h>
13 15 #include <Variable/Variable.h>
14 16 #include <Variable/VariableController.h>
15 17
16 18 #include <Visualization/operations/FindVariableOperation.h>
17 19
18 20 #include <DragDropHelper.h>
19 21 #include <QUuid>
20 22 #include <SqpApplication.h>
21 23 #include <cmath>
22 24
23 25 #include <QLayout>
24 26
25 27 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
26 28
27 29 namespace {
28 30
29 31
30 32 /// Generates a default name for a new graph, according to the number of graphs already displayed in
31 33 /// the zone
32 34 QString defaultGraphName(const QLayout &layout)
33 35 {
34 36 auto count = 0;
35 37 for (auto i = 0; i < layout.count(); ++i) {
36 38 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
37 39 count++;
38 40 }
39 41 }
40 42
41 43 return QObject::tr("Graph %1").arg(count + 1);
42 44 }
43 45
44 46 /**
45 47 * Applies a function to all graphs of the zone represented by its layout
46 48 * @param layout the layout that contains graphs
47 49 * @param fun the function to apply to each graph
48 50 */
49 51 template <typename Fun>
50 52 void processGraphs(QLayout &layout, Fun fun)
51 53 {
52 54 for (auto i = 0; i < layout.count(); ++i) {
53 55 if (auto item = layout.itemAt(i)) {
54 56 if (auto visualizationGraphWidget
55 57 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
56 58 fun(*visualizationGraphWidget);
57 59 }
58 60 }
59 61 }
60 62 }
61 63
62 64 } // namespace
63 65
64 66 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
65 67
66 68 explicit VisualizationZoneWidgetPrivate()
67 69 : m_SynchronisationGroupId{QUuid::createUuid()},
68 70 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
69 71 {
70 72 }
71 73 QUuid m_SynchronisationGroupId;
72 74 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
73 75
74 76 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
75 77 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
76 78 VisualizationZoneWidget *zoneWidget);
79 void dropProduct(const QVariantList &productDataList, int index,
80 VisualizationZoneWidget *zoneWidget);
77 81 };
78 82
79 83 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
80 84 : VisualizationDragWidget{parent},
81 85 ui{new Ui::VisualizationZoneWidget},
82 86 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
83 87 {
84 88 ui->setupUi(this);
85 89
86 90 ui->zoneNameLabel->setText(name);
87 91
88 ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH, MIME_TYPE_VARIABLE_LIST});
92 ui->dragDropContainer->setAcceptedMimeTypes(
93 {MIME_TYPE_GRAPH, MIME_TYPE_VARIABLE_LIST, MIME_TYPE_PRODUCT_LIST});
89 94 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
90 95 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
91 96 ui->dragDropContainer);
92 97 });
93 98 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
94 99 &VisualizationZoneWidget::dropMimeData);
95 100
96 101 // 'Close' options : widget is deleted when closed
97 102 setAttribute(Qt::WA_DeleteOnClose);
98 103 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
99 104 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
100 105
101 106 // Synchronisation id
102 107 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
103 108 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
104 109 }
105 110
106 111 VisualizationZoneWidget::~VisualizationZoneWidget()
107 112 {
108 113 delete ui;
109 114 }
110 115
111 116 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
112 117 {
113 118 // Synchronize new graph with others in the zone
114 119 impl->m_Synchronizer->addGraph(*graphWidget);
115 120
116 121 ui->dragDropContainer->addDragWidget(graphWidget);
117 122 }
118 123
119 124 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
120 125 {
121 126 // Synchronize new graph with others in the zone
122 127 impl->m_Synchronizer->addGraph(*graphWidget);
123 128
124 129 ui->dragDropContainer->insertDragWidget(index, graphWidget);
125 130 }
126 131
127 132 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
128 133 {
129 134 return createGraph(variable, -1);
130 135 }
131 136
132 137 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
133 138 int index)
134 139 {
135 140 auto graphWidget
136 141 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
137 142
138 143
139 144 // Set graph properties
140 145 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
141 146 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
142 147
143 148
144 149 // Lambda to synchronize zone widget
145 150 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
146 151 const SqpRange &oldGraphRange) {
147 152
148 153 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
149 154 auto frameLayout = ui->dragDropContainer->layout();
150 155 for (auto i = 0; i < frameLayout->count(); ++i) {
151 156 auto graphChild
152 157 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
153 158 if (graphChild && (graphChild != graphWidget)) {
154 159
155 160 auto graphChildRange = graphChild->graphRange();
156 161 switch (zoomType) {
157 162 case AcquisitionZoomType::ZoomIn: {
158 163 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
159 164 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
160 165 graphChildRange.m_TStart += deltaLeft;
161 166 graphChildRange.m_TEnd -= deltaRight;
162 167 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
163 168 qCDebug(LOG_VisualizationZoneWidget())
164 169 << tr("TORM: deltaLeft") << deltaLeft;
165 170 qCDebug(LOG_VisualizationZoneWidget())
166 171 << tr("TORM: deltaRight") << deltaRight;
167 172 qCDebug(LOG_VisualizationZoneWidget())
168 173 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
169 174
170 175 break;
171 176 }
172 177
173 178 case AcquisitionZoomType::ZoomOut: {
174 179 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
175 180 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
176 181 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
177 182 qCDebug(LOG_VisualizationZoneWidget())
178 183 << tr("TORM: deltaLeft") << deltaLeft;
179 184 qCDebug(LOG_VisualizationZoneWidget())
180 185 << tr("TORM: deltaRight") << deltaRight;
181 186 qCDebug(LOG_VisualizationZoneWidget())
182 187 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
183 188 graphChildRange.m_TStart -= deltaLeft;
184 189 graphChildRange.m_TEnd += deltaRight;
185 190 break;
186 191 }
187 192 case AcquisitionZoomType::PanRight: {
188 193 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
189 194 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
190 195 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
191 196 graphChildRange.m_TStart += deltaLeft;
192 197 graphChildRange.m_TEnd += deltaRight;
193 198 qCDebug(LOG_VisualizationZoneWidget())
194 199 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
195 200 break;
196 201 }
197 202 case AcquisitionZoomType::PanLeft: {
198 203 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
199 204 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
200 205 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
201 206 graphChildRange.m_TStart -= deltaLeft;
202 207 graphChildRange.m_TEnd -= deltaRight;
203 208 break;
204 209 }
205 210 case AcquisitionZoomType::Unknown: {
206 211 qCDebug(LOG_VisualizationZoneWidget())
207 212 << tr("Impossible to synchronize: zoom type unknown");
208 213 break;
209 214 }
210 215 default:
211 216 qCCritical(LOG_VisualizationZoneWidget())
212 217 << tr("Impossible to synchronize: zoom type not take into account");
213 218 // No action
214 219 break;
215 220 }
216 221 graphChild->enableAcquisition(false);
217 222 qCDebug(LOG_VisualizationZoneWidget())
218 223 << tr("TORM: Range before: ") << graphChild->graphRange();
219 224 qCDebug(LOG_VisualizationZoneWidget())
220 225 << tr("TORM: Range after : ") << graphChildRange;
221 226 qCDebug(LOG_VisualizationZoneWidget())
222 227 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
223 228 graphChild->setGraphRange(graphChildRange);
224 229 graphChild->enableAcquisition(true);
225 230 }
226 231 }
227 232 };
228 233
229 234 // connection for synchronization
230 235 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
231 236 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
232 237 &VisualizationZoneWidget::onVariableAdded);
233 238 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
234 239 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
235 240
236 241 auto range = SqpRange{};
237 242
238 243 // Apply visitor to graph children
239 244 auto layout = ui->dragDropContainer->layout();
240 245 if (layout->count() > 0) {
241 246 // Case of a new graph in a existant zone
242 247 if (auto visualizationGraphWidget
243 248 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
244 249 range = visualizationGraphWidget->graphRange();
245 250 }
246 251 }
247 252 else {
248 253 // Case of a new graph as the first of the zone
249 254 range = variable->range();
250 255 }
251 256
252 257 this->insertGraph(index, graphWidget);
253 258
254 259 graphWidget->addVariable(variable, range);
255 260
256 261 // get y using variable range
257 262 if (auto dataSeries = variable->dataSeries()) {
258 263 dataSeries->lockRead();
259 264 auto valuesBounds
260 265 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
261 266 auto end = dataSeries->cend();
262 267 if (valuesBounds.first != end && valuesBounds.second != end) {
263 268 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
264 269
265 270 auto minValue = rangeValue(valuesBounds.first->minValue());
266 271 auto maxValue = rangeValue(valuesBounds.second->maxValue());
267 272
268 273 graphWidget->setYRange(SqpRange{minValue, maxValue});
269 274 }
270 275 dataSeries->unlock();
271 276 }
272 277
273 278 return graphWidget;
274 279 }
275 280
276 281 VisualizationGraphWidget *
277 282 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
278 283 {
279 284 if (variables.isEmpty()) {
280 285 return nullptr;
281 286 }
282 287
283 288 auto graphWidget = createGraph(variables.first(), index);
284 289 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
285 290 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
286 291 }
287 292
288 293 return graphWidget;
289 294 }
290 295
291 296 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
292 297 {
293 298 if (visitor) {
294 299 visitor->visitEnter(this);
295 300
296 301 // Apply visitor to graph children: widgets different from graphs are not visited (no
297 302 // action)
298 303 processGraphs(
299 304 *ui->dragDropContainer->layout(),
300 305 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
301 306
302 307 visitor->visitLeave(this);
303 308 }
304 309 else {
305 310 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
306 311 }
307 312 }
308 313
309 314 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
310 315 {
311 316 // A tab can always accomodate a variable
312 317 Q_UNUSED(variable);
313 318 return true;
314 319 }
315 320
316 321 bool VisualizationZoneWidget::contains(const Variable &variable) const
317 322 {
318 323 Q_UNUSED(variable);
319 324 return false;
320 325 }
321 326
322 327 QString VisualizationZoneWidget::name() const
323 328 {
324 329 return ui->zoneNameLabel->text();
325 330 }
326 331
327 332 QMimeData *VisualizationZoneWidget::mimeData() const
328 333 {
329 334 auto mimeData = new QMimeData;
330 335 mimeData->setData(MIME_TYPE_ZONE, QByteArray());
331 336
332 337 return mimeData;
333 338 }
334 339
335 340 bool VisualizationZoneWidget::isDragAllowed() const
336 341 {
337 342 return true;
338 343 }
339 344
340 345 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
341 346 {
342 347 // Closes graphs in the zone
343 348 processGraphs(*ui->dragDropContainer->layout(),
344 349 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
345 350
346 351 // Delete synchronization group from variable controller
347 352 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
348 353 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
349 354
350 355 QWidget::closeEvent(event);
351 356 }
352 357
353 358 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
354 359 {
355 360 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
356 361 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
357 362 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
358 363 }
359 364
360 365 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
361 366 {
362 367 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
363 368 Q_ARG(std::shared_ptr<Variable>, variable),
364 369 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
365 370 }
366 371
367 372 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
368 373 {
369 374 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
370 375 impl->dropGraph(index, this);
371 376 }
372 377 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
373 378 auto variables = sqpApp->variableController().variablesForMimeData(
374 379 mimeData->data(MIME_TYPE_VARIABLE_LIST));
375 380 impl->dropVariables(variables, index, this);
376 381 }
382 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
383 auto productList = sqpApp->dataSourceController().productsDataForMimeData(
384 mimeData->data(MIME_TYPE_PRODUCT_LIST));
385 impl->dropProduct(productList, index, this);
386 }
377 387 else {
378 388 qCWarning(LOG_VisualizationZoneWidget())
379 389 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
380 390 }
381 391 }
382 392
383 393 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
384 394 int index, VisualizationZoneWidget *zoneWidget)
385 395 {
386 396 auto &helper = sqpApp->dragDropHelper();
387 397
388 398 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
389 399 if (!graphWidget) {
390 400 qCWarning(LOG_VisualizationZoneWidget())
391 401 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
392 402 "found or invalid.");
393 403 Q_ASSERT(false);
394 404 return;
395 405 }
396 406
397 407 auto parentDragDropContainer
398 408 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
399 409 if (!parentDragDropContainer) {
400 410 qCWarning(LOG_VisualizationZoneWidget())
401 411 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
402 412 "the dropped graph is not found.");
403 413 Q_ASSERT(false);
404 414 return;
405 415 }
406 416
407 417 const auto &variables = graphWidget->variables();
408 418
409 419 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
410 420 // The drop didn't occur in the same zone
411 421
412 422 // Abort the requests for the variables (if any)
413 423 // Commented, because it's not sure if it's needed or not
414 424 // for (const auto& var : variables)
415 425 //{
416 426 // sqpApp->variableController().onAbortProgressRequested(var);
417 427 //}
418 428
419 429 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
420 430 auto nbGraph = parentDragDropContainer->countDragWidget();
421 431 if (nbGraph == 1) {
422 432 // This is the only graph in the previous zone, close the zone
423 433 previousParentZoneWidget->close();
424 434 }
425 435 else {
426 436 // Close the graph
427 437 graphWidget->close();
428 438 }
429 439
430 440 // Creates the new graph in the zone
431 441 zoneWidget->createGraph(variables, index);
432 442 }
433 443 else {
434 444 // The drop occurred in the same zone or the graph is empty
435 445 // Simple move of the graph, no variable operation associated
436 446 parentDragDropContainer->layout()->removeWidget(graphWidget);
437 447
438 448 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
439 449 // The graph is empty and dropped in a different zone.
440 450 // Take the range of the first graph in the zone (if existing).
441 451 auto layout = zoneWidget->ui->dragDropContainer->layout();
442 452 if (layout->count() > 0) {
443 453 if (auto visualizationGraphWidget
444 454 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
445 455 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
446 456 }
447 457 }
448 458 }
449 459
450 460 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
451 461 }
452 462 }
453 463
454 464 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
455 465 const QList<std::shared_ptr<Variable> > &variables, int index,
456 466 VisualizationZoneWidget *zoneWidget)
457 467 {
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) {
468 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
469 // compatible variable here
470 if (variables.count() > 1) {
465 471 qCWarning(LOG_VisualizationZoneWidget())
466 << tr("VisualizationZoneWidget::dropVariables, drop aborted, the parent "
467 "VisualizationWidget cannot be found.");
468 Q_ASSERT(false);
472 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
473 "aborted.");
469 474 return;
470 475 }
471 476
472 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
477 Q_ASSERT(variables.count() == 1);
478 zoneWidget->createGraph(variables, index);
479 }
473 480
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;
482 }
481 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProduct(
482 const QVariantList &productDataList, int index, VisualizationZoneWidget *zoneWidget)
483 {
484 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
485 // compatible product here
486 if (productDataList.count() > 1) {
487 qCWarning(LOG_VisualizationZoneWidget()) << tr(
488 "VisualizationZoneWidget::dropProduct, dropping multiple products, operation aborted.");
489 return;
483 490 }
491
492 auto productData = productDataList.first().toHash();
493 auto provider = sqpApp->dataSourceController().providerForProductData(productData);
494 auto name = productData.value(DataSourceItem::NAME_DATA_KEY).toString();
495 auto variable = sqpApp->variableController().createVariable(name, productData, provider);
496 zoneWidget->createGraph(variable, index);
484 497 }
General Comments 0
You need to be logged in to leave comments. Login now