##// END OF EJS Templates
Product field now display products event list instead of only its size
perrinel -
r1364:6ea80a9a6c65
parent child
Show More
@@ -1,472 +1,478
1 1 #include "Catalogue/CatalogueEventsModel.h"
2 2
3 3 #include <Catalogue/CatalogueController.h>
4 4 #include <Common/DateUtils.h>
5 5 #include <Common/MimeTypesDef.h>
6 6 #include <DBEvent.h>
7 7 #include <DBEventProduct.h>
8 8 #include <DBTag.h>
9 9 #include <Data/SqpRange.h>
10 10 #include <SqpApplication.h>
11 11 #include <Time/TimeController.h>
12 12
13 13 #include <list>
14 14 #include <unordered_map>
15 15
16 16 #include <QHash>
17 17 #include <QMimeData>
18 18
19 19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsModel, "CatalogueEventsModel")
20 20
21 21 const auto EVENT_ITEM_TYPE = 1;
22 22 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
23 23
24 24 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
25 25 QVector<std::shared_ptr<DBEvent> > m_Events;
26 26 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
27 27 QVector<std::shared_ptr<DBCatalogue> > m_SourceCatalogue;
28 28
29 29 QStringList columnNames()
30 30 {
31 31 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"),
32 32 tr("Tags"), tr("Product"), tr("")};
33 33 }
34 34
35 35 QVariant sortData(int col, const std::shared_ptr<DBEvent> &event) const
36 36 {
37 37 if (col == (int)CatalogueEventsModel::Column::Validation) {
38 38 auto hasChanges = sqpApp->catalogueController().eventHasChanges(event);
39 39 return hasChanges ? true : QVariant();
40 40 }
41 41
42 42 return eventData(col, event);
43 43 }
44 44
45 45 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
46 46 {
47 47 switch (static_cast<Column>(col)) {
48 48 case CatalogueEventsModel::Column::Name:
49 49 return event->getName();
50 50 case CatalogueEventsModel::Column::TStart:
51 51 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTStart())
52 52 : QVariant{};
53 53 case CatalogueEventsModel::Column::TEnd:
54 54 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTEnd())
55 55 : QVariant{};
56 case CatalogueEventsModel::Column::Product:
57 return QString::number(nbEventProducts(event)) + " product(s)";
56 case CatalogueEventsModel::Column::Product: {
57 auto eventProducts = event->getEventProducts();
58 QStringList eventProductList;
59 for (auto evtProduct : eventProducts) {
60 eventProductList << evtProduct.getProductId();
61 }
62 return eventProductList.join(";");
63 }
58 64 case CatalogueEventsModel::Column::Tags: {
59 65 QString tagList;
60 66 auto tags = event->getTags();
61 67 for (auto tag : tags) {
62 68 tagList += tag.getName();
63 69 tagList += ' ';
64 70 }
65 71
66 72 return tagList;
67 73 }
68 74 case CatalogueEventsModel::Column::Validation:
69 75 return QVariant();
70 76 default:
71 77 break;
72 78 }
73 79
74 80 Q_ASSERT(false);
75 81 return QStringLiteral("Unknown Data");
76 82 }
77 83
78 84 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
79 85 {
80 86 for (auto product : event->getEventProducts()) {
81 87 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
82 88 }
83 89 }
84 90
85 91 int nbEventProducts(const std::shared_ptr<DBEvent> &event) const
86 92 {
87 93 auto eventProductsIt = m_EventProducts.find(event.get());
88 94 if (eventProductsIt != m_EventProducts.cend()) {
89 95 return m_EventProducts.at(event.get()).count();
90 96 }
91 97 else {
92 98 return 0;
93 99 }
94 100 }
95 101
96 102 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
97 103 {
98 104 switch (static_cast<Column>(col)) {
99 105 case CatalogueEventsModel::Column::Name:
100 106 return eventProduct->getProductId();
101 107 case CatalogueEventsModel::Column::TStart:
102 108 return DateUtils::dateTime(eventProduct->getTStart());
103 109 case CatalogueEventsModel::Column::TEnd:
104 110 return DateUtils::dateTime(eventProduct->getTEnd());
105 111 case CatalogueEventsModel::Column::Product:
106 112 return eventProduct->getProductId();
107 113 case CatalogueEventsModel::Column::Tags:
108 114 return QString();
109 115 case CatalogueEventsModel::Column::Validation:
110 116 return QVariant();
111 117 default:
112 118 break;
113 119 }
114 120
115 121 Q_ASSERT(false);
116 122 return QStringLiteral("Unknown Data");
117 123 }
118 124
119 125 void refreshChildrenOfIndex(CatalogueEventsModel *model, const QModelIndex &index) const
120 126 {
121 127 auto childCount = model->rowCount(index);
122 128 auto colCount = model->columnCount();
123 129 emit model->dataChanged(model->index(0, 0, index),
124 130 model->index(childCount, colCount, index));
125 131 }
126 132 };
127 133
128 134 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
129 135 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
130 136 {
131 137 }
132 138
133 139 void CatalogueEventsModel::setSourceCatalogues(
134 140 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
135 141 {
136 142 impl->m_SourceCatalogue = catalogues;
137 143 }
138 144
139 145 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
140 146 {
141 147 beginResetModel();
142 148
143 149 impl->m_Events = events;
144 150 impl->m_EventProducts.clear();
145 151 for (auto event : events) {
146 152 impl->parseEventProduct(event);
147 153 }
148 154
149 155 endResetModel();
150 156 }
151 157
152 158 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
153 159 {
154 160 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
155 161 return impl->m_Events.value(index.row());
156 162 }
157 163 else {
158 164 return nullptr;
159 165 }
160 166 }
161 167
162 168 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
163 169 {
164 170 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
165 171 return getEvent(index.parent());
166 172 }
167 173 else {
168 174 return nullptr;
169 175 }
170 176 }
171 177
172 178 std::shared_ptr<DBEventProduct>
173 179 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
174 180 {
175 181 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
176 182 auto event = static_cast<DBEvent *>(index.internalPointer());
177 183 return impl->m_EventProducts.at(event).value(index.row());
178 184 }
179 185 else {
180 186 return nullptr;
181 187 }
182 188 }
183 189
184 190 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
185 191 {
186 192 beginInsertRows(QModelIndex(), impl->m_Events.count(), impl->m_Events.count());
187 193 impl->m_Events.append(event);
188 194 impl->parseEventProduct(event);
189 195 endInsertRows();
190 196
191 197 // Also refreshes its children event products
192 198 auto eventIndex = index(impl->m_Events.count(), 0);
193 199 impl->refreshChildrenOfIndex(this, eventIndex);
194 200 }
195 201
196 202 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
197 203 {
198 204 auto index = impl->m_Events.indexOf(event);
199 205 if (index >= 0) {
200 206 beginRemoveRows(QModelIndex(), index, index);
201 207 impl->m_Events.removeAt(index);
202 208 impl->m_EventProducts.erase(event.get());
203 209 endRemoveRows();
204 210 }
205 211 }
206 212
207 213 QVector<std::shared_ptr<DBEvent> > CatalogueEventsModel::events() const
208 214 {
209 215 return impl->m_Events;
210 216 }
211 217
212 218 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event,
213 219 bool refreshEventProducts)
214 220 {
215 221 auto eventIndex = indexOf(event);
216 222 if (eventIndex.isValid()) {
217 223
218 224 if (refreshEventProducts) {
219 225 // Reparse the associated event products
220 226
221 227 auto nbEventProducts = impl->nbEventProducts(event);
222 228 auto newNbOfEventProducts = event->getEventProducts().size();
223 229 if (newNbOfEventProducts < nbEventProducts) {
224 230 beginRemoveRows(eventIndex, newNbOfEventProducts, nbEventProducts - 1);
225 231 impl->m_EventProducts.erase(event.get());
226 232 impl->parseEventProduct(event);
227 233 endRemoveRows();
228 234 }
229 235 else if (newNbOfEventProducts > nbEventProducts) {
230 236 beginInsertRows(eventIndex, nbEventProducts, newNbOfEventProducts - 1);
231 237 impl->m_EventProducts.erase(event.get());
232 238 impl->parseEventProduct(event);
233 239 endInsertRows();
234 240 }
235 241 else { // newNbOfEventProducts == nbEventProducts
236 242 impl->m_EventProducts.erase(event.get());
237 243 impl->parseEventProduct(event);
238 244 }
239 245 }
240 246
241 247 // Refreshes the event line
242 248 auto colCount = columnCount();
243 249 emit dataChanged(eventIndex, index(eventIndex.row(), colCount));
244 250
245 251 // Also refreshes its children event products
246 252 impl->refreshChildrenOfIndex(this, eventIndex);
247 253 }
248 254 else {
249 255 qCWarning(LOG_CatalogueEventsModel()) << "refreshEvent: event not found.";
250 256 }
251 257 }
252 258
253 259 QModelIndex CatalogueEventsModel::indexOf(const std::shared_ptr<DBEvent> &event) const
254 260 {
255 261 auto row = impl->m_Events.indexOf(event);
256 262 if (row >= 0) {
257 263 return index(row, 0);
258 264 }
259 265
260 266 return QModelIndex();
261 267 }
262 268
263 269 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
264 270 {
265 271 if (!hasIndex(row, column, parent)) {
266 272 return QModelIndex();
267 273 }
268 274
269 275 switch (itemTypeOf(parent)) {
270 276 case CatalogueEventsModel::ItemType::Root:
271 277 return createIndex(row, column);
272 278 case CatalogueEventsModel::ItemType::Event: {
273 279 auto event = getEvent(parent);
274 280 return createIndex(row, column, event.get());
275 281 }
276 282 case CatalogueEventsModel::ItemType::EventProduct:
277 283 break;
278 284 default:
279 285 break;
280 286 }
281 287
282 288 return QModelIndex();
283 289 }
284 290
285 291 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
286 292 {
287 293 switch (itemTypeOf(index)) {
288 294 case CatalogueEventsModel::ItemType::EventProduct: {
289 295 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
290 296 auto it
291 297 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
292 298 [parentEvent](auto event) { return event.get() == parentEvent; });
293 299
294 300 if (it != impl->m_Events.cend()) {
295 301 return createIndex(it - impl->m_Events.cbegin(), 0);
296 302 }
297 303 else {
298 304 return QModelIndex();
299 305 }
300 306 }
301 307 case CatalogueEventsModel::ItemType::Root:
302 308 break;
303 309 case CatalogueEventsModel::ItemType::Event:
304 310 break;
305 311 default:
306 312 break;
307 313 }
308 314
309 315 return QModelIndex();
310 316 }
311 317
312 318 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
313 319 {
314 320 if (parent.column() > 0) {
315 321 return 0;
316 322 }
317 323
318 324 switch (itemTypeOf(parent)) {
319 325 case CatalogueEventsModel::ItemType::Root:
320 326 return impl->m_Events.count();
321 327 case CatalogueEventsModel::ItemType::Event: {
322 328 auto event = getEvent(parent);
323 329 return impl->m_EventProducts[event.get()].count();
324 330 }
325 331 case CatalogueEventsModel::ItemType::EventProduct:
326 332 break;
327 333 default:
328 334 break;
329 335 }
330 336
331 337 return 0;
332 338 }
333 339
334 340 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
335 341 {
336 342 return static_cast<int>(CatalogueEventsModel::Column::NbColumn);
337 343 }
338 344
339 345 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
340 346 {
341 347 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
342 348 }
343 349
344 350 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
345 351 {
346 352 if (index.isValid()) {
347 353
348 354 auto type = itemTypeOf(index);
349 355 if (type == CatalogueEventsModel::ItemType::Event) {
350 356 auto event = getEvent(index);
351 357 switch (role) {
352 358 case Qt::DisplayRole:
353 359 return impl->eventData(index.column(), event);
354 360 break;
355 361 }
356 362 }
357 363 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
358 364 auto product = getEventProduct(index);
359 365 switch (role) {
360 366 case Qt::DisplayRole:
361 367 return impl->eventProductData(index.column(), product);
362 368 break;
363 369 }
364 370 }
365 371 }
366 372
367 373 return QVariant{};
368 374 }
369 375
370 376 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
371 377 {
372 378 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
373 379 return impl->columnNames().value(section);
374 380 }
375 381
376 382 return QVariant();
377 383 }
378 384
379 385 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
380 386 {
381 387 beginResetModel();
382 388 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
383 389 [this, column, order](auto e1, auto e2) {
384 390 auto data1 = impl->sortData(column, e1);
385 391 auto data2 = impl->sortData(column, e2);
386 392
387 393 auto result = data1.toString() < data2.toString();
388 394
389 395 return order == Qt::AscendingOrder ? result : !result;
390 396 });
391 397
392 398 endResetModel();
393 399 emit modelSorted();
394 400 }
395 401
396 402 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
397 403 {
398 404 return Qt::CopyAction | Qt::MoveAction;
399 405 }
400 406
401 407 QStringList CatalogueEventsModel::mimeTypes() const
402 408 {
403 409 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_SOURCE_CATALOGUE_LIST, MIME_TYPE_TIME_RANGE};
404 410 }
405 411
406 412 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
407 413 {
408 414 auto mimeData = new QMimeData;
409 415
410 416 bool isFirst = true;
411 417
412 418 QVector<std::shared_ptr<DBEvent> > eventList;
413 419 QVector<std::shared_ptr<DBEventProduct> > eventProductList;
414 420
415 421 SqpRange firstTimeRange;
416 422 for (const auto &index : indexes) {
417 423 if (index.column() == 0) { // only the first column
418 424
419 425 auto type = itemTypeOf(index);
420 426 if (type == ItemType::Event) {
421 427 auto event = getEvent(index);
422 428 eventList << event;
423 429
424 430 if (isFirst) {
425 431 isFirst = false;
426 432 firstTimeRange.m_TStart = event->getTStart();
427 433 firstTimeRange.m_TEnd = event->getTEnd();
428 434 }
429 435 }
430 436 else if (type == ItemType::EventProduct) {
431 437 auto product = getEventProduct(index);
432 438 eventProductList << product;
433 439
434 440 if (isFirst) {
435 441 isFirst = false;
436 442 firstTimeRange.m_TStart = product->getTStart();
437 443 firstTimeRange.m_TEnd = product->getTEnd();
438 444 }
439 445 }
440 446 }
441 447 }
442 448
443 449 if (!eventList.isEmpty() && eventProductList.isEmpty()) {
444 450 auto eventsEncodedData = sqpApp->catalogueController().mimeDataForEvents(eventList);
445 451 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
446 452
447 453 auto sourceCataloguesEncodedData
448 454 = sqpApp->catalogueController().mimeDataForCatalogues(impl->m_SourceCatalogue);
449 455 mimeData->setData(MIME_TYPE_SOURCE_CATALOGUE_LIST, sourceCataloguesEncodedData);
450 456 }
451 457
452 458 if (eventList.count() + eventProductList.count() == 1) {
453 459 // No time range MIME data if multiple events are dragged
454 460 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
455 461 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
456 462 }
457 463
458 464 return mimeData;
459 465 }
460 466
461 467 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
462 468 {
463 469 if (!index.isValid()) {
464 470 return ItemType::Root;
465 471 }
466 472 else if (index.internalPointer() == nullptr) {
467 473 return ItemType::Event;
468 474 }
469 475 else {
470 476 return ItemType::EventProduct;
471 477 }
472 478 }
@@ -1,227 +1,233
1 1 #include "Catalogue/CatalogueInspectorWidget.h"
2 2 #include "ui_CatalogueInspectorWidget.h"
3 3
4 4 #include <Common/DateUtils.h>
5 5 #include <DBCatalogue.h>
6 6 #include <DBEvent.h>
7 7 #include <DBEventProduct.h>
8 8 #include <DBTag.h>
9 9
10 10 struct CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate {
11 11 std::shared_ptr<DBCatalogue> m_DisplayedCatalogue = nullptr;
12 12 std::shared_ptr<DBEvent> m_DisplayedEvent = nullptr;
13 13 std::shared_ptr<DBEventProduct> m_DisplayedEventProduct = nullptr;
14 14
15 15 void connectCatalogueUpdateSignals(CatalogueInspectorWidget *inspector,
16 16 Ui::CatalogueInspectorWidget *ui);
17 17 void connectEventUpdateSignals(CatalogueInspectorWidget *inspector,
18 18 Ui::CatalogueInspectorWidget *ui);
19 19 };
20 20
21 21 CatalogueInspectorWidget::CatalogueInspectorWidget(QWidget *parent)
22 22 : QWidget(parent),
23 23 ui(new Ui::CatalogueInspectorWidget),
24 24 impl{spimpl::make_unique_impl<CatalogueInspectorWidgetPrivate>()}
25 25 {
26 26 ui->setupUi(this);
27 27 showPage(Page::Empty);
28 28
29 29 impl->connectCatalogueUpdateSignals(this, ui);
30 30 impl->connectEventUpdateSignals(this, ui);
31 31 }
32 32
33 33 CatalogueInspectorWidget::~CatalogueInspectorWidget()
34 34 {
35 35 delete ui;
36 36 }
37 37
38 38 void CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate::connectCatalogueUpdateSignals(
39 39 CatalogueInspectorWidget *inspector, Ui::CatalogueInspectorWidget *ui)
40 40 {
41 41 connect(ui->leCatalogueName, &QLineEdit::editingFinished, [ui, inspector, this]() {
42 42 if (ui->leCatalogueName->text() != m_DisplayedCatalogue->getName()) {
43 43 m_DisplayedCatalogue->setName(ui->leCatalogueName->text());
44 44 emit inspector->catalogueUpdated(m_DisplayedCatalogue);
45 45 }
46 46 });
47 47
48 48 connect(ui->leCatalogueAuthor, &QLineEdit::editingFinished, [ui, inspector, this]() {
49 49 if (ui->leCatalogueAuthor->text() != m_DisplayedCatalogue->getAuthor()) {
50 50 m_DisplayedCatalogue->setAuthor(ui->leCatalogueAuthor->text());
51 51 emit inspector->catalogueUpdated(m_DisplayedCatalogue);
52 52 }
53 53 });
54 54 }
55 55
56 56 void CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate::connectEventUpdateSignals(
57 57 CatalogueInspectorWidget *inspector, Ui::CatalogueInspectorWidget *ui)
58 58 {
59 59 connect(ui->leEventName, &QLineEdit::editingFinished, [ui, inspector, this]() {
60 60 if (ui->leEventName->text() != m_DisplayedEvent->getName()) {
61 61 m_DisplayedEvent->setName(ui->leEventName->text());
62 62 emit inspector->eventUpdated(m_DisplayedEvent);
63 63 }
64 64 });
65 65
66 66 connect(ui->leEventTags, &QLineEdit::editingFinished, [ui, inspector, this]() {
67 67 auto tags = ui->leEventTags->text().split(QRegExp("\\s+"), QString::SkipEmptyParts);
68 68 std::list<QString> tagNames;
69 69 for (auto tag : tags) {
70 70 tagNames.push_back(tag);
71 71 }
72 72
73 73 if (m_DisplayedEvent->getTagsNames() != tagNames) {
74 74 m_DisplayedEvent->setTagsNames(tagNames);
75 75 emit inspector->eventUpdated(m_DisplayedEvent);
76 76 }
77 77 });
78 78
79 79 connect(ui->leEventProduct, &QLineEdit::editingFinished, [ui, inspector, this]() {
80 80 if (ui->leEventProduct->text() != m_DisplayedEventProduct->getProductId()) {
81 81 auto oldProductId = m_DisplayedEventProduct->getProductId();
82 82 m_DisplayedEventProduct->setProductId(ui->leEventProduct->text());
83 83
84 84 auto eventProducts = m_DisplayedEvent->getEventProducts();
85 85 for (auto &eventProduct : eventProducts) {
86 86 if (eventProduct.getProductId() == oldProductId) {
87 87 eventProduct.setProductId(m_DisplayedEventProduct->getProductId());
88 88 }
89 89 }
90 90 m_DisplayedEvent->setEventProducts(eventProducts);
91 91
92 92 emit inspector->eventUpdated(m_DisplayedEvent);
93 93 }
94 94 });
95 95
96 96 connect(ui->dateTimeEventTStart, &QDateTimeEdit::editingFinished, [ui, inspector, this]() {
97 97 auto time = DateUtils::secondsSinceEpoch(ui->dateTimeEventTStart->dateTime());
98 98 if (time != m_DisplayedEventProduct->getTStart()) {
99 99 m_DisplayedEventProduct->setTStart(time);
100 100
101 101 auto eventProducts = m_DisplayedEvent->getEventProducts();
102 102 for (auto &eventProduct : eventProducts) {
103 103 if (eventProduct.getProductId() == m_DisplayedEventProduct->getProductId()) {
104 104 eventProduct.setTStart(m_DisplayedEventProduct->getTStart());
105 105 }
106 106 }
107 107 m_DisplayedEvent->setEventProducts(eventProducts);
108 108
109 109 emit inspector->eventUpdated(m_DisplayedEvent);
110 110 }
111 111 });
112 112
113 113 connect(ui->dateTimeEventTEnd, &QDateTimeEdit::editingFinished, [ui, inspector, this]() {
114 114 auto time = DateUtils::secondsSinceEpoch(ui->dateTimeEventTEnd->dateTime());
115 115 if (time != m_DisplayedEventProduct->getTEnd()) {
116 116 m_DisplayedEventProduct->setTEnd(time);
117 117
118 118 auto eventProducts = m_DisplayedEvent->getEventProducts();
119 119 for (auto &eventProduct : eventProducts) {
120 120 if (eventProduct.getProductId() == m_DisplayedEventProduct->getProductId()) {
121 121 eventProduct.setTEnd(m_DisplayedEventProduct->getTEnd());
122 122 }
123 123 }
124 124 m_DisplayedEvent->setEventProducts(eventProducts);
125 125
126 126 emit inspector->eventUpdated(m_DisplayedEvent);
127 127 }
128 128 });
129 129 }
130 130
131 131 void CatalogueInspectorWidget::showPage(CatalogueInspectorWidget::Page page)
132 132 {
133 133 ui->stackedWidget->setCurrentIndex(static_cast<int>(page));
134 134 }
135 135
136 136 CatalogueInspectorWidget::Page CatalogueInspectorWidget::currentPage() const
137 137 {
138 138 return static_cast<Page>(ui->stackedWidget->currentIndex());
139 139 }
140 140
141 141 void CatalogueInspectorWidget::setEvent(const std::shared_ptr<DBEvent> &event)
142 142 {
143 143 impl->m_DisplayedEvent = event;
144 144
145 145 blockSignals(true);
146 146
147 147 showPage(Page::EventProperties);
148 148 ui->leEventName->setEnabled(true);
149 149 ui->leEventName->setText(event->getName());
150 150 ui->leEventProduct->setEnabled(false);
151 ui->leEventProduct->setText(
152 QString::number(event->getEventProducts().size()).append(" product(s)"));
151
152 auto eventProducts = event->getEventProducts();
153 QStringList eventProductList;
154 for (auto evtProduct : eventProducts) {
155 eventProductList << evtProduct.getProductId();
156 }
157
158 ui->leEventProduct->setText(eventProductList.join(";"));
153 159
154 160 QString tagList;
155 161 auto tags = event->getTagsNames();
156 162 for (auto tag : tags) {
157 163 tagList += tag;
158 164 tagList += ' ';
159 165 }
160 166
161 167 ui->leEventTags->setEnabled(true);
162 168 ui->leEventTags->setText(tagList);
163 169
164 170 ui->dateTimeEventTStart->setEnabled(false);
165 171 ui->dateTimeEventTEnd->setEnabled(false);
166 172
167 173 ui->dateTimeEventTStart->setDateTime(DateUtils::dateTime(event->getTStart()));
168 174 ui->dateTimeEventTEnd->setDateTime(DateUtils::dateTime(event->getTEnd()));
169 175
170 176 blockSignals(false);
171 177 }
172 178
173 179 void CatalogueInspectorWidget::setEventProduct(const std::shared_ptr<DBEvent> &event,
174 180 const std::shared_ptr<DBEventProduct> &eventProduct)
175 181 {
176 182
177 183 impl->m_DisplayedEvent = event;
178 184 impl->m_DisplayedEventProduct = eventProduct;
179 185
180 186 blockSignals(true);
181 187
182 188 showPage(Page::EventProperties);
183 189 ui->leEventName->setEnabled(false);
184 190 ui->leEventName->setText(event->getName());
185 191 ui->leEventProduct->setEnabled(false);
186 192 ui->leEventProduct->setText(eventProduct->getProductId());
187 193
188 194 ui->leEventTags->setEnabled(false);
189 195 ui->leEventTags->clear();
190 196
191 197 ui->dateTimeEventTStart->setEnabled(true);
192 198 ui->dateTimeEventTEnd->setEnabled(true);
193 199
194 200 ui->dateTimeEventTStart->setDateTime(DateUtils::dateTime(eventProduct->getTStart()));
195 201 ui->dateTimeEventTEnd->setDateTime(DateUtils::dateTime(eventProduct->getTEnd()));
196 202
197 203 blockSignals(false);
198 204 }
199 205
200 206 void CatalogueInspectorWidget::setCatalogue(const std::shared_ptr<DBCatalogue> &catalogue)
201 207 {
202 208 impl->m_DisplayedCatalogue = catalogue;
203 209
204 210 blockSignals(true);
205 211
206 212 showPage(Page::CatalogueProperties);
207 213 ui->leCatalogueName->setText(catalogue->getName());
208 214 ui->leCatalogueAuthor->setText(catalogue->getAuthor());
209 215
210 216 blockSignals(false);
211 217 }
212 218
213 219 void CatalogueInspectorWidget::refresh()
214 220 {
215 221 switch (static_cast<Page>(ui->stackedWidget->currentIndex())) {
216 222 case Page::CatalogueProperties:
217 223 setCatalogue(impl->m_DisplayedCatalogue);
218 224 break;
219 225 case Page::EventProperties: {
220 226 auto isEventShowed = ui->leEventName->isEnabled();
221 227 setEvent(impl->m_DisplayedEvent);
222 228 if (!isEventShowed && impl->m_DisplayedEvent) {
223 229 setEventProduct(impl->m_DisplayedEvent, impl->m_DisplayedEventProduct);
224 230 }
225 231 }
226 232 }
227 233 }
@@ -1,658 +1,658
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 13 #include <DataSource/DataSourceController.h>
14 14 #include <Time/TimeController.h>
15 15 #include <Variable/Variable.h>
16 16 #include <Variable/VariableController.h>
17 17
18 18 #include <Visualization/operations/FindVariableOperation.h>
19 19
20 20 #include <DragAndDrop/DragDropGuiController.h>
21 21 #include <QUuid>
22 22 #include <SqpApplication.h>
23 23 #include <cmath>
24 24
25 25 #include <QLayout>
26 26
27 27 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
28 28
29 29 namespace {
30 30
31 31 /**
32 32 * Applies a function to all graphs of the zone represented by its layout
33 33 * @param layout the layout that contains graphs
34 34 * @param fun the function to apply to each graph
35 35 */
36 36 template <typename Fun>
37 37 void processGraphs(QLayout &layout, Fun fun)
38 38 {
39 39 for (auto i = 0; i < layout.count(); ++i) {
40 40 if (auto item = layout.itemAt(i)) {
41 41 if (auto visualizationGraphWidget
42 42 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
43 43 fun(*visualizationGraphWidget);
44 44 }
45 45 }
46 46 }
47 47 }
48 48
49 49 /// Generates a default name for a new graph, according to the number of graphs already displayed in
50 50 /// the zone
51 51 QString defaultGraphName(QLayout &layout)
52 52 {
53 53 QSet<QString> existingNames;
54 54 processGraphs(
55 55 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
56 56
57 57 int zoneNum = 1;
58 58 QString name;
59 59 do {
60 60 name = QObject::tr("Graph ").append(QString::number(zoneNum));
61 61 ++zoneNum;
62 62 } while (existingNames.contains(name));
63 63
64 64 return name;
65 65 }
66 66
67 67 } // namespace
68 68
69 69 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
70 70
71 71 explicit VisualizationZoneWidgetPrivate()
72 72 : m_SynchronisationGroupId{QUuid::createUuid()},
73 73 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
74 74 {
75 75 }
76 76 QUuid m_SynchronisationGroupId;
77 77 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
78 78
79 79 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
80 80 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
81 81 VisualizationZoneWidget *zoneWidget);
82 82 void dropProducts(const QVariantList &productsData, int index,
83 83 VisualizationZoneWidget *zoneWidget);
84 84 };
85 85
86 86 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
87 87 : VisualizationDragWidget{parent},
88 88 ui{new Ui::VisualizationZoneWidget},
89 89 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
90 90 {
91 91 ui->setupUi(this);
92 92
93 93 ui->zoneNameLabel->setText(name);
94 94
95 95 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
96 96 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
97 97 VisualizationDragDropContainer::DropBehavior::Inserted);
98 98 ui->dragDropContainer->setMimeType(
99 99 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
100 100 ui->dragDropContainer->setMimeType(
101 101 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
102 102 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
103 103 VisualizationDragDropContainer::DropBehavior::Merged);
104 104 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
105 105 VisualizationDragDropContainer::DropBehavior::Forbidden);
106 106 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
107 107 VisualizationDragDropContainer::DropBehavior::Forbidden);
108 108 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
109 109 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
110 110 ui->dragDropContainer);
111 111 });
112 112
113 113 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
114 114 if (!mimeData) {
115 115 return false;
116 116 }
117 117
118 118 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
119 119 auto variables = sqpApp->variableController().variablesForMimeData(
120 120 mimeData->data(MIME_TYPE_VARIABLE_LIST));
121 121
122 122 if (variables.count() != 1) {
123 123 return false;
124 124 }
125 125 auto variable = variables.first();
126 126
127 127 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
128 128 return graphWidget->canDrop(*variable);
129 129 }
130 130 }
131 131
132 132 return true;
133 133 };
134 134 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
135 135
136 136 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
137 137 &VisualizationZoneWidget::dropMimeData);
138 138 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
139 139 &VisualizationZoneWidget::dropMimeDataOnGraph);
140 140
141 141 // 'Close' options : widget is deleted when closed
142 142 setAttribute(Qt::WA_DeleteOnClose);
143 143 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
144 144 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
145 145
146 146 // Synchronisation id
147 147 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
148 148 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
149 149 }
150 150
151 151 VisualizationZoneWidget::~VisualizationZoneWidget()
152 152 {
153 153 delete ui;
154 154 }
155 155
156 156 void VisualizationZoneWidget::setZoneRange(const SqpRange &range)
157 157 {
158 158 if (auto graph = firstGraph()) {
159 159 graph->setGraphRange(range);
160 160 }
161 161 else {
162 162 qCWarning(LOG_VisualizationZoneWidget())
163 163 << tr("setZoneRange:Cannot set the range of an empty zone.");
164 164 }
165 165 }
166 166
167 167 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
168 168 {
169 169 // Synchronize new graph with others in the zone
170 170 impl->m_Synchronizer->addGraph(*graphWidget);
171 171
172 172 ui->dragDropContainer->addDragWidget(graphWidget);
173 173 }
174 174
175 175 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
176 176 {
177 177 // Synchronize new graph with others in the zone
178 178 impl->m_Synchronizer->addGraph(*graphWidget);
179 179
180 180 ui->dragDropContainer->insertDragWidget(index, graphWidget);
181 181 }
182 182
183 183 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
184 184 {
185 185 return createGraph(variable, -1);
186 186 }
187 187
188 188 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
189 189 int index)
190 190 {
191 191 auto graphWidget
192 192 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
193 193
194 194
195 195 // Set graph properties
196 196 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
197 197 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
198 198
199 199
200 200 // Lambda to synchronize zone widget
201 201 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
202 202 const SqpRange &oldGraphRange) {
203 203
204 204 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
205 205 auto frameLayout = ui->dragDropContainer->layout();
206 206 for (auto i = 0; i < frameLayout->count(); ++i) {
207 207 auto graphChild
208 208 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
209 209 if (graphChild && (graphChild != graphWidget)) {
210 210
211 211 auto graphChildRange = graphChild->graphRange();
212 212 switch (zoomType) {
213 213 case AcquisitionZoomType::ZoomIn: {
214 214 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
215 215 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
216 216 graphChildRange.m_TStart += deltaLeft;
217 217 graphChildRange.m_TEnd -= deltaRight;
218 218 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
219 219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
220 220 << deltaLeft;
221 221 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
222 222 << deltaRight;
223 223 qCDebug(LOG_VisualizationZoneWidget())
224 224 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
225 225
226 226 break;
227 227 }
228 228
229 229 case AcquisitionZoomType::ZoomOut: {
230 230 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
231 231 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
232 232 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
233 233 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
234 234 << deltaLeft;
235 235 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
236 236 << deltaRight;
237 237 qCDebug(LOG_VisualizationZoneWidget())
238 238 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
239 239 graphChildRange.m_TStart -= deltaLeft;
240 240 graphChildRange.m_TEnd += deltaRight;
241 241 break;
242 242 }
243 243 case AcquisitionZoomType::PanRight: {
244 244 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
245 245 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
246 246 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
247 247 graphChildRange.m_TStart += deltaLeft;
248 248 graphChildRange.m_TEnd += deltaRight;
249 249 qCDebug(LOG_VisualizationZoneWidget())
250 250 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
251 251 break;
252 252 }
253 253 case AcquisitionZoomType::PanLeft: {
254 254 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
255 255 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
256 256 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
257 257 graphChildRange.m_TStart -= deltaLeft;
258 258 graphChildRange.m_TEnd -= deltaRight;
259 259 break;
260 260 }
261 261 case AcquisitionZoomType::Unknown: {
262 262 qCDebug(LOG_VisualizationZoneWidget())
263 263 << tr("Impossible to synchronize: zoom type unknown");
264 264 break;
265 265 }
266 266 default:
267 267 qCCritical(LOG_VisualizationZoneWidget())
268 268 << tr("Impossible to synchronize: zoom type not take into account");
269 269 // No action
270 270 break;
271 271 }
272 272 graphChild->setFlags(GraphFlag::DisableAll);
273 qCDebug(LOG_VisualizationZoneWidget())
274 << tr("TORM: Range before: ") << graphChild->graphRange();
275 qCDebug(LOG_VisualizationZoneWidget())
276 << tr("TORM: Range after : ") << graphChildRange;
273 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
274 << graphChild->graphRange();
275 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
276 << graphChildRange;
277 277 qCDebug(LOG_VisualizationZoneWidget())
278 278 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
279 279 graphChild->setGraphRange(graphChildRange);
280 280 graphChild->setFlags(GraphFlag::EnableAll);
281 281 }
282 282 }
283 283 };
284 284
285 285 // connection for synchronization
286 286 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
287 287 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
288 288 &VisualizationZoneWidget::onVariableAdded);
289 289 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
290 290 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
291 291
292 292 auto range = SqpRange{};
293 293 if (auto firstGraph = this->firstGraph()) {
294 294 // Case of a new graph in a existant zone
295 295 range = firstGraph->graphRange();
296 296 }
297 297 else {
298 298 // Case of a new graph as the first of the zone
299 299 range = variable->range();
300 300 }
301 301
302 302 this->insertGraph(index, graphWidget);
303 303
304 304 graphWidget->addVariable(variable, range);
305 305 graphWidget->setYRange(variable);
306 306
307 307 return graphWidget;
308 308 }
309 309
310 310 VisualizationGraphWidget *
311 311 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
312 312 {
313 313 if (variables.isEmpty()) {
314 314 return nullptr;
315 315 }
316 316
317 317 auto graphWidget = createGraph(variables.first(), index);
318 318 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
319 319 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
320 320 }
321 321
322 322 return graphWidget;
323 323 }
324 324
325 325 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
326 326 {
327 327 VisualizationGraphWidget *firstGraph = nullptr;
328 328 auto layout = ui->dragDropContainer->layout();
329 329 if (layout->count() > 0) {
330 330 if (auto visualizationGraphWidget
331 331 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
332 332 firstGraph = visualizationGraphWidget;
333 333 }
334 334 }
335 335
336 336 return firstGraph;
337 337 }
338 338
339 339 void VisualizationZoneWidget::closeAllGraphs()
340 340 {
341 341 processGraphs(*ui->dragDropContainer->layout(),
342 342 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
343 343 }
344 344
345 345 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
346 346 {
347 347 if (visitor) {
348 348 visitor->visitEnter(this);
349 349
350 350 // Apply visitor to graph children: widgets different from graphs are not visited (no
351 351 // action)
352 352 processGraphs(
353 353 *ui->dragDropContainer->layout(),
354 354 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
355 355
356 356 visitor->visitLeave(this);
357 357 }
358 358 else {
359 359 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
360 360 }
361 361 }
362 362
363 363 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
364 364 {
365 365 // A tab can always accomodate a variable
366 366 Q_UNUSED(variable);
367 367 return true;
368 368 }
369 369
370 370 bool VisualizationZoneWidget::contains(const Variable &variable) const
371 371 {
372 372 Q_UNUSED(variable);
373 373 return false;
374 374 }
375 375
376 376 QString VisualizationZoneWidget::name() const
377 377 {
378 378 return ui->zoneNameLabel->text();
379 379 }
380 380
381 381 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
382 382 {
383 383 Q_UNUSED(position);
384 384
385 385 auto mimeData = new QMimeData;
386 386 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
387 387
388 388 if (auto firstGraph = this->firstGraph()) {
389 389 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
390 390 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
391 391 }
392 392
393 393 return mimeData;
394 394 }
395 395
396 396 bool VisualizationZoneWidget::isDragAllowed() const
397 397 {
398 398 return true;
399 399 }
400 400
401 401 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
402 402 const QPointF &plotPosition,
403 403 VisualizationGraphWidget *graphWidget)
404 404 {
405 405 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
406 406 VisualizationGraphWidget &processedGraph) {
407 407
408 408 switch (sqpApp->plotsCursorMode()) {
409 409 case SqpApplication::PlotsCursorMode::Vertical:
410 410 processedGraph.removeHorizontalCursor();
411 411 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
412 412 break;
413 413 case SqpApplication::PlotsCursorMode::Temporal:
414 414 processedGraph.addVerticalCursor(plotPosition.x());
415 415 processedGraph.removeHorizontalCursor();
416 416 break;
417 417 case SqpApplication::PlotsCursorMode::Horizontal:
418 418 processedGraph.removeVerticalCursor();
419 419 if (&processedGraph == graphWidget) {
420 420 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
421 421 }
422 422 else {
423 423 processedGraph.removeHorizontalCursor();
424 424 }
425 425 break;
426 426 case SqpApplication::PlotsCursorMode::Cross:
427 427 if (&processedGraph == graphWidget) {
428 428 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
429 429 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
430 430 }
431 431 else {
432 432 processedGraph.removeHorizontalCursor();
433 433 processedGraph.removeVerticalCursor();
434 434 }
435 435 break;
436 436 case SqpApplication::PlotsCursorMode::NoCursor:
437 437 processedGraph.removeHorizontalCursor();
438 438 processedGraph.removeVerticalCursor();
439 439 break;
440 440 }
441 441
442 442
443 443 });
444 444 }
445 445
446 446 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
447 447 {
448 448 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
449 449 processedGraph.removeHorizontalCursor();
450 450 processedGraph.removeVerticalCursor();
451 451 });
452 452 }
453 453
454 454 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
455 455 {
456 456 // Closes graphs in the zone
457 457 processGraphs(*ui->dragDropContainer->layout(),
458 458 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
459 459
460 460 // Delete synchronization group from variable controller
461 461 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
462 462 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
463 463
464 464 QWidget::closeEvent(event);
465 465 }
466 466
467 467 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
468 468 {
469 469 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
470 470 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
471 471 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
472 472 }
473 473
474 474 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
475 475 {
476 476 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
477 477 Q_ARG(std::shared_ptr<Variable>, variable),
478 478 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
479 479 }
480 480
481 481 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
482 482 {
483 483 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
484 484 impl->dropGraph(index, this);
485 485 }
486 486 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
487 487 auto variables = sqpApp->variableController().variablesForMimeData(
488 488 mimeData->data(MIME_TYPE_VARIABLE_LIST));
489 489 impl->dropVariables(variables, index, this);
490 490 }
491 491 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
492 492 auto products = sqpApp->dataSourceController().productsDataForMimeData(
493 493 mimeData->data(MIME_TYPE_PRODUCT_LIST));
494 494 impl->dropProducts(products, index, this);
495 495 }
496 496 else {
497 497 qCWarning(LOG_VisualizationZoneWidget())
498 498 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
499 499 }
500 500 }
501 501
502 502 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
503 503 const QMimeData *mimeData)
504 504 {
505 505 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
506 506 if (!graphWidget) {
507 507 qCWarning(LOG_VisualizationZoneWidget())
508 508 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
509 509 "drop aborted");
510 510 Q_ASSERT(false);
511 511 return;
512 512 }
513 513
514 514 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
515 515 auto variables = sqpApp->variableController().variablesForMimeData(
516 516 mimeData->data(MIME_TYPE_VARIABLE_LIST));
517 517 for (const auto &var : variables) {
518 518 graphWidget->addVariable(var, graphWidget->graphRange());
519 519 }
520 520 }
521 521 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
522 522 auto products = sqpApp->dataSourceController().productsDataForMimeData(
523 523 mimeData->data(MIME_TYPE_PRODUCT_LIST));
524 524
525 525 auto context = new QObject{this};
526 526 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
527 527 [this, graphWidget, context](auto variable) {
528 528 graphWidget->addVariable(variable, graphWidget->graphRange());
529 529 delete context; // removes the connection
530 530 },
531 531 Qt::QueuedConnection);
532 532
533 533 auto productData = products.first().toHash();
534 534 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
535 535 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
536 536 }
537 537 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
538 538 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
539 539 graphWidget->setGraphRange(range);
540 540 }
541 541 else {
542 542 qCWarning(LOG_VisualizationZoneWidget())
543 543 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
544 544 }
545 545 }
546 546
547 547 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
548 548 int index, VisualizationZoneWidget *zoneWidget)
549 549 {
550 550 auto &helper = sqpApp->dragDropGuiController();
551 551
552 552 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
553 553 if (!graphWidget) {
554 554 qCWarning(LOG_VisualizationZoneWidget())
555 555 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
556 556 "found or invalid.");
557 557 Q_ASSERT(false);
558 558 return;
559 559 }
560 560
561 561 auto parentDragDropContainer
562 562 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
563 563 if (!parentDragDropContainer) {
564 564 qCWarning(LOG_VisualizationZoneWidget())
565 565 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
566 566 "the dropped graph is not found.");
567 567 Q_ASSERT(false);
568 568 return;
569 569 }
570 570
571 571 const auto &variables = graphWidget->variables();
572 572
573 573 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
574 574 // The drop didn't occur in the same zone
575 575
576 576 // Abort the requests for the variables (if any)
577 577 // Commented, because it's not sure if it's needed or not
578 578 // for (const auto& var : variables)
579 579 //{
580 580 // sqpApp->variableController().onAbortProgressRequested(var);
581 581 //}
582 582
583 583 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
584 584 auto nbGraph = parentDragDropContainer->countDragWidget();
585 585 if (nbGraph == 1) {
586 586 // This is the only graph in the previous zone, close the zone
587 587 helper.delayedCloseWidget(previousParentZoneWidget);
588 588 }
589 589 else {
590 590 // Close the graph
591 591 helper.delayedCloseWidget(graphWidget);
592 592 }
593 593
594 594 // Creates the new graph in the zone
595 595 auto newGraphWidget = zoneWidget->createGraph(variables, index);
596 596 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
597 597 }
598 598 else {
599 599 // The drop occurred in the same zone or the graph is empty
600 600 // Simple move of the graph, no variable operation associated
601 601 parentDragDropContainer->layout()->removeWidget(graphWidget);
602 602
603 603 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
604 604 // The graph is empty and dropped in a different zone.
605 605 // Take the range of the first graph in the zone (if existing).
606 606 auto layout = zoneWidget->ui->dragDropContainer->layout();
607 607 if (layout->count() > 0) {
608 608 if (auto visualizationGraphWidget
609 609 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
610 610 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
611 611 }
612 612 }
613 613 }
614 614
615 615 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
616 616 }
617 617 }
618 618
619 619 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
620 620 const QList<std::shared_ptr<Variable> > &variables, int index,
621 621 VisualizationZoneWidget *zoneWidget)
622 622 {
623 623 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
624 624 // compatible variable here
625 625 if (variables.count() > 1) {
626 626 qCWarning(LOG_VisualizationZoneWidget())
627 627 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
628 628 "aborted.");
629 629 return;
630 630 }
631 631
632 632 zoneWidget->createGraph(variables, index);
633 633 }
634 634
635 635 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
636 636 const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget)
637 637 {
638 638 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
639 639 // compatible variable here
640 640 if (productsData.count() != 1) {
641 641 qCWarning(LOG_VisualizationZoneWidget())
642 642 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
643 643 "aborted.");
644 644 return;
645 645 }
646 646
647 647 auto context = new QObject{zoneWidget};
648 648 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
649 649 [this, index, zoneWidget, context](auto variable) {
650 650 zoneWidget->createGraph(variable, index);
651 651 delete context; // removes the connection
652 652 },
653 653 Qt::QueuedConnection);
654 654
655 655 auto productData = productsData.first().toHash();
656 656 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
657 657 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
658 658 }
General Comments 0
You need to be logged in to leave comments. Login now