##// END OF EJS Templates
fix refresh of events after a discard
trabillard -
r1300:f0b824bb0975
parent child
Show More
@@ -1,68 +1,68
1 #ifndef SCIQLOP_CATALOGUEEVENTSMODEL_H
1 #ifndef SCIQLOP_CATALOGUEEVENTSMODEL_H
2 #define SCIQLOP_CATALOGUEEVENTSMODEL_H
2 #define SCIQLOP_CATALOGUEEVENTSMODEL_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QAbstractItemModel>
5 #include <QAbstractItemModel>
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7 #include <unordered_set>
7 #include <unordered_set>
8
8
9 class DBEvent;
9 class DBEvent;
10 class DBEventProduct;
10 class DBEventProduct;
11
11
12 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsModel)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsModel)
13
13
14 class CatalogueEventsModel : public QAbstractItemModel {
14 class CatalogueEventsModel : public QAbstractItemModel {
15 Q_OBJECT
15 Q_OBJECT
16
16
17 signals:
17 signals:
18 void modelSorted();
18 void modelSorted();
19
19
20 public:
20 public:
21 CatalogueEventsModel(QObject *parent = nullptr);
21 CatalogueEventsModel(QObject *parent = nullptr);
22
22
23 enum class Column { Name, TStart, TEnd, Tags, Product, Validation, NbColumn };
23 enum class Column { Name, TStart, TEnd, Tags, Product, Validation, NbColumn };
24
24
25 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events);
25 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events);
26 void addEvent(const std::shared_ptr<DBEvent> &event);
26 void addEvent(const std::shared_ptr<DBEvent> &event);
27 void removeEvent(const std::shared_ptr<DBEvent> &event);
27 void removeEvent(const std::shared_ptr<DBEvent> &event);
28 QVector<std::shared_ptr<DBEvent> > events() const;
28 QVector<std::shared_ptr<DBEvent> > events() const;
29
29
30 enum class ItemType { Root, Event, EventProduct };
30 enum class ItemType { Root, Event, EventProduct };
31 ItemType itemTypeOf(const QModelIndex &index) const;
31 ItemType itemTypeOf(const QModelIndex &index) const;
32 std::shared_ptr<DBEvent> getEvent(const QModelIndex &index) const;
32 std::shared_ptr<DBEvent> getEvent(const QModelIndex &index) const;
33 std::shared_ptr<DBEvent> getParentEvent(const QModelIndex &index) const;
33 std::shared_ptr<DBEvent> getParentEvent(const QModelIndex &index) const;
34 std::shared_ptr<DBEventProduct> getEventProduct(const QModelIndex &index) const;
34 std::shared_ptr<DBEventProduct> getEventProduct(const QModelIndex &index) const;
35
35
36 /// Refresh the data for the specified event
36 /// Refresh the data for the specified event
37 void refreshEvent(const std::shared_ptr<DBEvent> &event);
37 void refreshEvent(const std::shared_ptr<DBEvent> &event, bool refreshEventProducts = false);
38
38
39 /// Returns a QModelIndex which represent the specified event
39 /// Returns a QModelIndex which represent the specified event
40 QModelIndex indexOf(const std::shared_ptr<DBEvent> &event) const;
40 QModelIndex indexOf(const std::shared_ptr<DBEvent> &event) const;
41
41
42 /// Marks a change flag on the specified event to allow sorting on the validation column
42 /// Marks a change flag on the specified event to allow sorting on the validation column
43 void setEventHasChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
43 void setEventHasChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
44
44
45 /// Returns true if the specified event has unsaved changes
45 /// Returns true if the specified event has unsaved changes
46 bool eventsHasChanges(const std::shared_ptr<DBEvent> &event) const;
46 bool eventsHasChanges(const std::shared_ptr<DBEvent> &event) const;
47
47
48 // Model
48 // Model
49 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
49 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
50 QModelIndex parent(const QModelIndex &index) const;
50 QModelIndex parent(const QModelIndex &index) const;
51 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
51 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
52 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
52 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
53 Qt::ItemFlags flags(const QModelIndex &index) const override;
53 Qt::ItemFlags flags(const QModelIndex &index) const override;
54 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
54 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
55 QVariant headerData(int section, Qt::Orientation orientation,
55 QVariant headerData(int section, Qt::Orientation orientation,
56 int role = Qt::DisplayRole) const override;
56 int role = Qt::DisplayRole) const override;
57 void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
57 void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
58
58
59 Qt::DropActions supportedDragActions() const override;
59 Qt::DropActions supportedDragActions() const override;
60 QStringList mimeTypes() const override;
60 QStringList mimeTypes() const override;
61 QMimeData *mimeData(const QModelIndexList &indexes) const override;
61 QMimeData *mimeData(const QModelIndexList &indexes) const override;
62
62
63 private:
63 private:
64 class CatalogueEventsModelPrivate;
64 class CatalogueEventsModelPrivate;
65 spimpl::unique_impl_ptr<CatalogueEventsModelPrivate> impl;
65 spimpl::unique_impl_ptr<CatalogueEventsModelPrivate> impl;
66 };
66 };
67
67
68 #endif // SCIQLOP_CATALOGUEEVENTSMODEL_H
68 #endif // SCIQLOP_CATALOGUEEVENTSMODEL_H
@@ -1,55 +1,58
1 #ifndef SCIQLOP_CATALOGUEEVENTSWIDGET_H
1 #ifndef SCIQLOP_CATALOGUEEVENTSWIDGET_H
2 #define SCIQLOP_CATALOGUEEVENTSWIDGET_H
2 #define SCIQLOP_CATALOGUEEVENTSWIDGET_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QLoggingCategory>
5 #include <QLoggingCategory>
6 #include <QWidget>
6 #include <QWidget>
7
7
8 class DBCatalogue;
8 class DBCatalogue;
9 class DBEvent;
9 class DBEvent;
10 class DBEventProduct;
10 class DBEventProduct;
11 class VisualizationWidget;
11 class VisualizationWidget;
12
12
13 namespace Ui {
13 namespace Ui {
14 class CatalogueEventsWidget;
14 class CatalogueEventsWidget;
15 }
15 }
16
16
17 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsWidget)
17 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsWidget)
18
18
19 class CatalogueEventsWidget : public QWidget {
19 class CatalogueEventsWidget : public QWidget {
20 Q_OBJECT
20 Q_OBJECT
21
21
22 signals:
22 signals:
23 void eventsSelected(const QVector<std::shared_ptr<DBEvent> > &event);
23 void eventsSelected(const QVector<std::shared_ptr<DBEvent> > &event);
24 void eventProductsSelected(
24 void eventProductsSelected(
25 const QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > >
25 const QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > >
26 &eventproducts);
26 &eventproducts);
27 void selectionCleared();
27 void selectionCleared();
28
28
29 public:
29 public:
30 explicit CatalogueEventsWidget(QWidget *parent = 0);
30 explicit CatalogueEventsWidget(QWidget *parent = 0);
31 virtual ~CatalogueEventsWidget();
31 virtual ~CatalogueEventsWidget();
32
32
33 void setVisualizationWidget(VisualizationWidget *visualization);
33 void setVisualizationWidget(VisualizationWidget *visualization);
34
34
35 void addEvent(const std::shared_ptr<DBEvent> &event);
35 void addEvent(const std::shared_ptr<DBEvent> &event);
36 void setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
36 void setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
37
37
38 QVector<std::shared_ptr<DBCatalogue> > displayedCatalogues() const;
38 QVector<std::shared_ptr<DBCatalogue> > displayedCatalogues() const;
39 bool isAllEventsDisplayed() const;
39 bool isAllEventsDisplayed() const;
40 bool isEventDisplayed(const std::shared_ptr<DBEvent> &event) const;
40 bool isEventDisplayed(const std::shared_ptr<DBEvent> &event) const;
41
41
42 public slots:
42 public slots:
43 void populateWithCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
43 void populateWithCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
44 void populateWithAllEvents();
44 void populateWithAllEvents();
45 void clear();
45 void clear();
46 void refresh();
46 void refresh();
47
47
48 private:
48 private:
49 Ui::CatalogueEventsWidget *ui;
49 Ui::CatalogueEventsWidget *ui;
50
50
51 class CatalogueEventsWidgetPrivate;
51 class CatalogueEventsWidgetPrivate;
52 spimpl::unique_impl_ptr<CatalogueEventsWidgetPrivate> impl;
52 spimpl::unique_impl_ptr<CatalogueEventsWidgetPrivate> impl;
53
54 private slots:
55 void emitSelection();
53 };
56 };
54
57
55 #endif // SCIQLOP_CATALOGUEEVENTSWIDGET_H
58 #endif // SCIQLOP_CATALOGUEEVENTSWIDGET_H
@@ -1,437 +1,461
1 #include "Catalogue/CatalogueEventsModel.h"
1 #include "Catalogue/CatalogueEventsModel.h"
2
2
3 #include <Catalogue/CatalogueController.h>
3 #include <Catalogue/CatalogueController.h>
4 #include <Common/DateUtils.h>
4 #include <Common/DateUtils.h>
5 #include <Common/MimeTypesDef.h>
5 #include <Common/MimeTypesDef.h>
6 #include <DBEvent.h>
6 #include <DBEvent.h>
7 #include <DBEventProduct.h>
7 #include <DBEventProduct.h>
8 #include <DBTag.h>
8 #include <DBTag.h>
9 #include <Data/SqpRange.h>
9 #include <Data/SqpRange.h>
10 #include <SqpApplication.h>
10 #include <SqpApplication.h>
11 #include <Time/TimeController.h>
11 #include <Time/TimeController.h>
12
12
13 #include <list>
13 #include <list>
14 #include <unordered_map>
14 #include <unordered_map>
15
15
16 #include <QHash>
16 #include <QHash>
17 #include <QMimeData>
17 #include <QMimeData>
18
18
19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsModel, "CatalogueEventsModel")
19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsModel, "CatalogueEventsModel")
20
20
21 const auto EVENT_ITEM_TYPE = 1;
21 const auto EVENT_ITEM_TYPE = 1;
22 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
22 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
23
23
24 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
24 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
25 QVector<std::shared_ptr<DBEvent> > m_Events;
25 QVector<std::shared_ptr<DBEvent> > m_Events;
26 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
26 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
27
27
28 QStringList columnNames()
28 QStringList columnNames()
29 {
29 {
30 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"),
30 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"),
31 tr("Tags"), tr("Product"), tr("")};
31 tr("Tags"), tr("Product"), tr("")};
32 }
32 }
33
33
34 QVariant sortData(int col, const std::shared_ptr<DBEvent> &event) const
34 QVariant sortData(int col, const std::shared_ptr<DBEvent> &event) const
35 {
35 {
36 if (col == (int)CatalogueEventsModel::Column::Validation) {
36 if (col == (int)CatalogueEventsModel::Column::Validation) {
37 auto hasChanges = sqpApp->catalogueController().eventHasChanges(event);
37 auto hasChanges = sqpApp->catalogueController().eventHasChanges(event);
38 return hasChanges ? true : QVariant();
38 return hasChanges ? true : QVariant();
39 }
39 }
40
40
41 return eventData(col, event);
41 return eventData(col, event);
42 }
42 }
43
43
44 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
44 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
45 {
45 {
46 switch (static_cast<Column>(col)) {
46 switch (static_cast<Column>(col)) {
47 case CatalogueEventsModel::Column::Name:
47 case CatalogueEventsModel::Column::Name:
48 return event->getName();
48 return event->getName();
49 case CatalogueEventsModel::Column::TStart:
49 case CatalogueEventsModel::Column::TStart:
50 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTStart())
50 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTStart())
51 : QVariant{};
51 : QVariant{};
52 case CatalogueEventsModel::Column::TEnd:
52 case CatalogueEventsModel::Column::TEnd:
53 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTEnd())
53 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTEnd())
54 : QVariant{};
54 : QVariant{};
55 case CatalogueEventsModel::Column::Product:
55 case CatalogueEventsModel::Column::Product:
56 return QString::number(nbEventProducts(event)) + " product(s)";
56 return QString::number(nbEventProducts(event)) + " product(s)";
57 case CatalogueEventsModel::Column::Tags: {
57 case CatalogueEventsModel::Column::Tags: {
58 QString tagList;
58 QString tagList;
59 auto tags = event->getTags();
59 auto tags = event->getTags();
60 for (auto tag : tags) {
60 for (auto tag : tags) {
61 tagList += tag.getName();
61 tagList += tag.getName();
62 tagList += ' ';
62 tagList += ' ';
63 }
63 }
64
64
65 return tagList;
65 return tagList;
66 }
66 }
67 case CatalogueEventsModel::Column::Validation:
67 case CatalogueEventsModel::Column::Validation:
68 return QVariant();
68 return QVariant();
69 default:
69 default:
70 break;
70 break;
71 }
71 }
72
72
73 Q_ASSERT(false);
73 Q_ASSERT(false);
74 return QStringLiteral("Unknown Data");
74 return QStringLiteral("Unknown Data");
75 }
75 }
76
76
77 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
77 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
78 {
78 {
79 for (auto product : event->getEventProducts()) {
79 for (auto product : event->getEventProducts()) {
80 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
80 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
81 }
81 }
82 }
82 }
83
83
84 int nbEventProducts(const std::shared_ptr<DBEvent> &event) const
84 int nbEventProducts(const std::shared_ptr<DBEvent> &event) const
85 {
85 {
86 auto eventProductsIt = m_EventProducts.find(event.get());
86 auto eventProductsIt = m_EventProducts.find(event.get());
87 if (eventProductsIt != m_EventProducts.cend()) {
87 if (eventProductsIt != m_EventProducts.cend()) {
88 return m_EventProducts.at(event.get()).count();
88 return m_EventProducts.at(event.get()).count();
89 }
89 }
90 else {
90 else {
91 return 0;
91 return 0;
92 }
92 }
93 }
93 }
94
94
95 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
95 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
96 {
96 {
97 switch (static_cast<Column>(col)) {
97 switch (static_cast<Column>(col)) {
98 case CatalogueEventsModel::Column::Name:
98 case CatalogueEventsModel::Column::Name:
99 return eventProduct->getProductId();
99 return eventProduct->getProductId();
100 case CatalogueEventsModel::Column::TStart:
100 case CatalogueEventsModel::Column::TStart:
101 return DateUtils::dateTime(eventProduct->getTStart());
101 return DateUtils::dateTime(eventProduct->getTStart());
102 case CatalogueEventsModel::Column::TEnd:
102 case CatalogueEventsModel::Column::TEnd:
103 return DateUtils::dateTime(eventProduct->getTEnd());
103 return DateUtils::dateTime(eventProduct->getTEnd());
104 case CatalogueEventsModel::Column::Product:
104 case CatalogueEventsModel::Column::Product:
105 return eventProduct->getProductId();
105 return eventProduct->getProductId();
106 case CatalogueEventsModel::Column::Tags:
106 case CatalogueEventsModel::Column::Tags:
107 return QString();
107 return QString();
108 case CatalogueEventsModel::Column::Validation:
108 case CatalogueEventsModel::Column::Validation:
109 return QVariant();
109 return QVariant();
110 default:
110 default:
111 break;
111 break;
112 }
112 }
113
113
114 Q_ASSERT(false);
114 Q_ASSERT(false);
115 return QStringLiteral("Unknown Data");
115 return QStringLiteral("Unknown Data");
116 }
116 }
117
117
118 void refreshChildrenOfIndex(CatalogueEventsModel *model, const QModelIndex &index) const
118 void refreshChildrenOfIndex(CatalogueEventsModel *model, const QModelIndex &index) const
119 {
119 {
120 auto childCount = model->rowCount(index);
120 auto childCount = model->rowCount(index);
121 auto colCount = model->columnCount();
121 auto colCount = model->columnCount();
122 emit model->dataChanged(model->index(0, 0, index),
122 emit model->dataChanged(model->index(0, 0, index),
123 model->index(childCount, colCount, index));
123 model->index(childCount, colCount, index));
124 }
124 }
125 };
125 };
126
126
127 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
127 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
128 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
128 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
129 {
129 {
130 }
130 }
131
131
132 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
132 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
133 {
133 {
134 beginResetModel();
134 beginResetModel();
135
135
136 impl->m_Events = events;
136 impl->m_Events = events;
137 impl->m_EventProducts.clear();
137 impl->m_EventProducts.clear();
138 for (auto event : events) {
138 for (auto event : events) {
139 impl->parseEventProduct(event);
139 impl->parseEventProduct(event);
140 }
140 }
141
141
142 endResetModel();
142 endResetModel();
143 }
143 }
144
144
145 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
145 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
146 {
146 {
147 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
147 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
148 return impl->m_Events.value(index.row());
148 return impl->m_Events.value(index.row());
149 }
149 }
150 else {
150 else {
151 return nullptr;
151 return nullptr;
152 }
152 }
153 }
153 }
154
154
155 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
155 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
156 {
156 {
157 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
157 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
158 return getEvent(index.parent());
158 return getEvent(index.parent());
159 }
159 }
160 else {
160 else {
161 return nullptr;
161 return nullptr;
162 }
162 }
163 }
163 }
164
164
165 std::shared_ptr<DBEventProduct>
165 std::shared_ptr<DBEventProduct>
166 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
166 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
167 {
167 {
168 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
168 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
169 auto event = static_cast<DBEvent *>(index.internalPointer());
169 auto event = static_cast<DBEvent *>(index.internalPointer());
170 return impl->m_EventProducts.at(event).value(index.row());
170 return impl->m_EventProducts.at(event).value(index.row());
171 }
171 }
172 else {
172 else {
173 return nullptr;
173 return nullptr;
174 }
174 }
175 }
175 }
176
176
177 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
177 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
178 {
178 {
179 beginInsertRows(QModelIndex(), impl->m_Events.count(), impl->m_Events.count());
179 beginInsertRows(QModelIndex(), impl->m_Events.count(), impl->m_Events.count());
180 impl->m_Events.append(event);
180 impl->m_Events.append(event);
181 impl->parseEventProduct(event);
181 impl->parseEventProduct(event);
182 endInsertRows();
182 endInsertRows();
183
183
184 // Also refreshes its children event products
184 // Also refreshes its children event products
185 auto eventIndex = index(impl->m_Events.count(), 0);
185 auto eventIndex = index(impl->m_Events.count(), 0);
186 impl->refreshChildrenOfIndex(this, eventIndex);
186 impl->refreshChildrenOfIndex(this, eventIndex);
187 }
187 }
188
188
189 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
189 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
190 {
190 {
191 auto index = impl->m_Events.indexOf(event);
191 auto index = impl->m_Events.indexOf(event);
192 if (index >= 0) {
192 if (index >= 0) {
193 beginRemoveRows(QModelIndex(), index, index);
193 beginRemoveRows(QModelIndex(), index, index);
194 impl->m_Events.removeAt(index);
194 impl->m_Events.removeAt(index);
195 impl->m_EventProducts.erase(event.get());
195 impl->m_EventProducts.erase(event.get());
196 endRemoveRows();
196 endRemoveRows();
197 }
197 }
198 }
198 }
199
199
200 QVector<std::shared_ptr<DBEvent> > CatalogueEventsModel::events() const
200 QVector<std::shared_ptr<DBEvent> > CatalogueEventsModel::events() const
201 {
201 {
202 return impl->m_Events;
202 return impl->m_Events;
203 }
203 }
204
204
205 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event)
205 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event,
206 bool refreshEventProducts)
206 {
207 {
207 auto eventIndex = indexOf(event);
208 auto eventIndex = indexOf(event);
208 if (eventIndex.isValid()) {
209 if (eventIndex.isValid()) {
209
210
211 if (refreshEventProducts) {
212 // Reparse the associated event products
213
214 auto nbEventProducts = impl->nbEventProducts(event);
215 auto newNbOfEventProducts = event->getEventProducts().size();
216 if (newNbOfEventProducts < nbEventProducts) {
217 beginRemoveRows(eventIndex, newNbOfEventProducts, nbEventProducts - 1);
218 impl->m_EventProducts.erase(event.get());
219 impl->parseEventProduct(event);
220 endRemoveRows();
221 }
222 else if (newNbOfEventProducts > nbEventProducts) {
223 beginInsertRows(eventIndex, nbEventProducts, newNbOfEventProducts - 1);
224 impl->m_EventProducts.erase(event.get());
225 impl->parseEventProduct(event);
226 endInsertRows();
227 }
228 else { // newNbOfEventProducts == nbEventProducts
229 impl->m_EventProducts.erase(event.get());
230 impl->parseEventProduct(event);
231 }
232 }
233
210 // Refreshes the event line
234 // Refreshes the event line
211 auto colCount = columnCount();
235 auto colCount = columnCount();
212 emit dataChanged(eventIndex, index(eventIndex.row(), colCount));
236 emit dataChanged(eventIndex, index(eventIndex.row(), colCount));
213
237
214 // Also refreshes its children event products
238 // Also refreshes its children event products
215 impl->refreshChildrenOfIndex(this, eventIndex);
239 impl->refreshChildrenOfIndex(this, eventIndex);
216 }
240 }
217 else {
241 else {
218 qCWarning(LOG_CatalogueEventsModel()) << "refreshEvent: event not found.";
242 qCWarning(LOG_CatalogueEventsModel()) << "refreshEvent: event not found.";
219 }
243 }
220 }
244 }
221
245
222 QModelIndex CatalogueEventsModel::indexOf(const std::shared_ptr<DBEvent> &event) const
246 QModelIndex CatalogueEventsModel::indexOf(const std::shared_ptr<DBEvent> &event) const
223 {
247 {
224 auto row = impl->m_Events.indexOf(event);
248 auto row = impl->m_Events.indexOf(event);
225 if (row >= 0) {
249 if (row >= 0) {
226 return index(row, 0);
250 return index(row, 0);
227 }
251 }
228
252
229 return QModelIndex();
253 return QModelIndex();
230 }
254 }
231
255
232 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
256 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
233 {
257 {
234 if (!hasIndex(row, column, parent)) {
258 if (!hasIndex(row, column, parent)) {
235 return QModelIndex();
259 return QModelIndex();
236 }
260 }
237
261
238 switch (itemTypeOf(parent)) {
262 switch (itemTypeOf(parent)) {
239 case CatalogueEventsModel::ItemType::Root:
263 case CatalogueEventsModel::ItemType::Root:
240 return createIndex(row, column);
264 return createIndex(row, column);
241 case CatalogueEventsModel::ItemType::Event: {
265 case CatalogueEventsModel::ItemType::Event: {
242 auto event = getEvent(parent);
266 auto event = getEvent(parent);
243 return createIndex(row, column, event.get());
267 return createIndex(row, column, event.get());
244 }
268 }
245 case CatalogueEventsModel::ItemType::EventProduct:
269 case CatalogueEventsModel::ItemType::EventProduct:
246 break;
270 break;
247 default:
271 default:
248 break;
272 break;
249 }
273 }
250
274
251 return QModelIndex();
275 return QModelIndex();
252 }
276 }
253
277
254 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
278 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
255 {
279 {
256 switch (itemTypeOf(index)) {
280 switch (itemTypeOf(index)) {
257 case CatalogueEventsModel::ItemType::EventProduct: {
281 case CatalogueEventsModel::ItemType::EventProduct: {
258 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
282 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
259 auto it
283 auto it
260 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
284 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
261 [parentEvent](auto event) { return event.get() == parentEvent; });
285 [parentEvent](auto event) { return event.get() == parentEvent; });
262
286
263 if (it != impl->m_Events.cend()) {
287 if (it != impl->m_Events.cend()) {
264 return createIndex(it - impl->m_Events.cbegin(), 0);
288 return createIndex(it - impl->m_Events.cbegin(), 0);
265 }
289 }
266 else {
290 else {
267 return QModelIndex();
291 return QModelIndex();
268 }
292 }
269 }
293 }
270 case CatalogueEventsModel::ItemType::Root:
294 case CatalogueEventsModel::ItemType::Root:
271 break;
295 break;
272 case CatalogueEventsModel::ItemType::Event:
296 case CatalogueEventsModel::ItemType::Event:
273 break;
297 break;
274 default:
298 default:
275 break;
299 break;
276 }
300 }
277
301
278 return QModelIndex();
302 return QModelIndex();
279 }
303 }
280
304
281 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
305 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
282 {
306 {
283 if (parent.column() > 0) {
307 if (parent.column() > 0) {
284 return 0;
308 return 0;
285 }
309 }
286
310
287 switch (itemTypeOf(parent)) {
311 switch (itemTypeOf(parent)) {
288 case CatalogueEventsModel::ItemType::Root:
312 case CatalogueEventsModel::ItemType::Root:
289 return impl->m_Events.count();
313 return impl->m_Events.count();
290 case CatalogueEventsModel::ItemType::Event: {
314 case CatalogueEventsModel::ItemType::Event: {
291 auto event = getEvent(parent);
315 auto event = getEvent(parent);
292 return impl->m_EventProducts[event.get()].count();
316 return impl->m_EventProducts[event.get()].count();
293 }
317 }
294 case CatalogueEventsModel::ItemType::EventProduct:
318 case CatalogueEventsModel::ItemType::EventProduct:
295 break;
319 break;
296 default:
320 default:
297 break;
321 break;
298 }
322 }
299
323
300 return 0;
324 return 0;
301 }
325 }
302
326
303 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
327 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
304 {
328 {
305 return static_cast<int>(CatalogueEventsModel::Column::NbColumn);
329 return static_cast<int>(CatalogueEventsModel::Column::NbColumn);
306 }
330 }
307
331
308 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
332 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
309 {
333 {
310 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
334 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
311 }
335 }
312
336
313 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
337 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
314 {
338 {
315 if (index.isValid()) {
339 if (index.isValid()) {
316
340
317 auto type = itemTypeOf(index);
341 auto type = itemTypeOf(index);
318 if (type == CatalogueEventsModel::ItemType::Event) {
342 if (type == CatalogueEventsModel::ItemType::Event) {
319 auto event = getEvent(index);
343 auto event = getEvent(index);
320 switch (role) {
344 switch (role) {
321 case Qt::DisplayRole:
345 case Qt::DisplayRole:
322 return impl->eventData(index.column(), event);
346 return impl->eventData(index.column(), event);
323 break;
347 break;
324 }
348 }
325 }
349 }
326 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
350 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
327 auto product = getEventProduct(index);
351 auto product = getEventProduct(index);
328 switch (role) {
352 switch (role) {
329 case Qt::DisplayRole:
353 case Qt::DisplayRole:
330 return impl->eventProductData(index.column(), product);
354 return impl->eventProductData(index.column(), product);
331 break;
355 break;
332 }
356 }
333 }
357 }
334 }
358 }
335
359
336 return QVariant{};
360 return QVariant{};
337 }
361 }
338
362
339 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
363 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
340 {
364 {
341 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
365 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
342 return impl->columnNames().value(section);
366 return impl->columnNames().value(section);
343 }
367 }
344
368
345 return QVariant();
369 return QVariant();
346 }
370 }
347
371
348 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
372 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
349 {
373 {
350 beginResetModel();
374 beginResetModel();
351 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
375 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
352 [this, column, order](auto e1, auto e2) {
376 [this, column, order](auto e1, auto e2) {
353 auto data1 = impl->sortData(column, e1);
377 auto data1 = impl->sortData(column, e1);
354 auto data2 = impl->sortData(column, e2);
378 auto data2 = impl->sortData(column, e2);
355
379
356 auto result = data1.toString() < data2.toString();
380 auto result = data1.toString() < data2.toString();
357
381
358 return order == Qt::AscendingOrder ? result : !result;
382 return order == Qt::AscendingOrder ? result : !result;
359 });
383 });
360
384
361 endResetModel();
385 endResetModel();
362 emit modelSorted();
386 emit modelSorted();
363 }
387 }
364
388
365 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
389 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
366 {
390 {
367 return Qt::CopyAction;
391 return Qt::CopyAction;
368 }
392 }
369
393
370 QStringList CatalogueEventsModel::mimeTypes() const
394 QStringList CatalogueEventsModel::mimeTypes() const
371 {
395 {
372 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_TIME_RANGE};
396 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_TIME_RANGE};
373 }
397 }
374
398
375 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
399 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
376 {
400 {
377 auto mimeData = new QMimeData;
401 auto mimeData = new QMimeData;
378
402
379 bool isFirst = true;
403 bool isFirst = true;
380
404
381 QVector<std::shared_ptr<DBEvent> > eventList;
405 QVector<std::shared_ptr<DBEvent> > eventList;
382 QVector<std::shared_ptr<DBEventProduct> > eventProductList;
406 QVector<std::shared_ptr<DBEventProduct> > eventProductList;
383
407
384 SqpRange firstTimeRange;
408 SqpRange firstTimeRange;
385 for (const auto &index : indexes) {
409 for (const auto &index : indexes) {
386 if (index.column() == 0) { // only the first column
410 if (index.column() == 0) { // only the first column
387
411
388 auto type = itemTypeOf(index);
412 auto type = itemTypeOf(index);
389 if (type == ItemType::Event) {
413 if (type == ItemType::Event) {
390 auto event = getEvent(index);
414 auto event = getEvent(index);
391 eventList << event;
415 eventList << event;
392
416
393 if (isFirst) {
417 if (isFirst) {
394 isFirst = false;
418 isFirst = false;
395 firstTimeRange.m_TStart = event->getTStart();
419 firstTimeRange.m_TStart = event->getTStart();
396 firstTimeRange.m_TEnd = event->getTEnd();
420 firstTimeRange.m_TEnd = event->getTEnd();
397 }
421 }
398 }
422 }
399 else if (type == ItemType::EventProduct) {
423 else if (type == ItemType::EventProduct) {
400 auto product = getEventProduct(index);
424 auto product = getEventProduct(index);
401 eventProductList << product;
425 eventProductList << product;
402
426
403 if (isFirst) {
427 if (isFirst) {
404 isFirst = false;
428 isFirst = false;
405 firstTimeRange.m_TStart = product->getTStart();
429 firstTimeRange.m_TStart = product->getTStart();
406 firstTimeRange.m_TEnd = product->getTEnd();
430 firstTimeRange.m_TEnd = product->getTEnd();
407 }
431 }
408 }
432 }
409 }
433 }
410 }
434 }
411
435
412 if (!eventList.isEmpty() && eventProductList.isEmpty()) {
436 if (!eventList.isEmpty() && eventProductList.isEmpty()) {
413 auto eventsEncodedData = sqpApp->catalogueController().mimeDataForEvents(eventList);
437 auto eventsEncodedData = sqpApp->catalogueController().mimeDataForEvents(eventList);
414 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
438 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
415 }
439 }
416
440
417 if (eventList.count() + eventProductList.count() == 1) {
441 if (eventList.count() + eventProductList.count() == 1) {
418 // No time range MIME data if multiple events are dragged
442 // No time range MIME data if multiple events are dragged
419 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
443 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
420 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
444 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
421 }
445 }
422
446
423 return mimeData;
447 return mimeData;
424 }
448 }
425
449
426 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
450 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
427 {
451 {
428 if (!index.isValid()) {
452 if (!index.isValid()) {
429 return ItemType::Root;
453 return ItemType::Root;
430 }
454 }
431 else if (index.internalPointer() == nullptr) {
455 else if (index.internalPointer() == nullptr) {
432 return ItemType::Event;
456 return ItemType::Event;
433 }
457 }
434 else {
458 else {
435 return ItemType::EventProduct;
459 return ItemType::EventProduct;
436 }
460 }
437 }
461 }
@@ -1,457 +1,460
1 #include "Catalogue/CatalogueEventsWidget.h"
1 #include "Catalogue/CatalogueEventsWidget.h"
2 #include "ui_CatalogueEventsWidget.h"
2 #include "ui_CatalogueEventsWidget.h"
3
3
4 #include <Catalogue/CatalogueController.h>
4 #include <Catalogue/CatalogueController.h>
5 #include <Catalogue/CatalogueEventsModel.h>
5 #include <Catalogue/CatalogueEventsModel.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
7 #include <CatalogueDao.h>
7 #include <CatalogueDao.h>
8 #include <DBCatalogue.h>
8 #include <DBCatalogue.h>
9 #include <SqpApplication.h>
9 #include <SqpApplication.h>
10 #include <Visualization/VisualizationTabWidget.h>
10 #include <Visualization/VisualizationTabWidget.h>
11 #include <Visualization/VisualizationWidget.h>
11 #include <Visualization/VisualizationWidget.h>
12 #include <Visualization/VisualizationZoneWidget.h>
12 #include <Visualization/VisualizationZoneWidget.h>
13
13
14 #include <QDialog>
14 #include <QDialog>
15 #include <QDialogButtonBox>
15 #include <QDialogButtonBox>
16 #include <QListWidget>
16 #include <QListWidget>
17 #include <QMessageBox>
17 #include <QMessageBox>
18
18
19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
20
20
21 /// Fixed size of the validation column
21 /// Fixed size of the validation column
22 const auto VALIDATION_COLUMN_SIZE = 35;
22 const auto VALIDATION_COLUMN_SIZE = 35;
23
23
24 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
24 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
25
25
26 CatalogueEventsModel *m_Model = nullptr;
26 CatalogueEventsModel *m_Model = nullptr;
27 QStringList m_ZonesForTimeMode;
27 QStringList m_ZonesForTimeMode;
28 QString m_ZoneForGraphMode;
28 QString m_ZoneForGraphMode;
29 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
29 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
30
30
31 VisualizationWidget *m_VisualizationWidget = nullptr;
31 VisualizationWidget *m_VisualizationWidget = nullptr;
32
32
33 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
33 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
34 {
34 {
35 widget->ui->treeView->setSortingEnabled(false);
35 widget->ui->treeView->setSortingEnabled(false);
36 m_Model->setEvents(events);
36 m_Model->setEvents(events);
37 widget->ui->treeView->setSortingEnabled(true);
37 widget->ui->treeView->setSortingEnabled(true);
38
38
39 for (auto event : events) {
39 for (auto event : events) {
40 if (sqpApp->catalogueController().eventHasChanges(event)) {
40 if (sqpApp->catalogueController().eventHasChanges(event)) {
41 auto index = m_Model->indexOf(event);
41 auto index = m_Model->indexOf(event);
42 widget->setEventChanges(event, true);
42 widget->setEventChanges(event, true);
43 }
43 }
44 }
44 }
45 }
45 }
46
46
47 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
47 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
48 {
48 {
49 treeView->setSortingEnabled(false);
49 treeView->setSortingEnabled(false);
50 m_Model->addEvent(event);
50 m_Model->addEvent(event);
51 treeView->setSortingEnabled(true);
51 treeView->setSortingEnabled(true);
52 }
52 }
53
53
54 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
54 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
55 {
55 {
56 treeView->setSortingEnabled(false);
56 treeView->setSortingEnabled(false);
57 m_Model->removeEvent(event);
57 m_Model->removeEvent(event);
58 treeView->setSortingEnabled(true);
58 treeView->setSortingEnabled(true);
59 }
59 }
60
60
61 QStringList getAvailableVisualizationZoneList() const
61 QStringList getAvailableVisualizationZoneList() const
62 {
62 {
63 if (m_VisualizationWidget) {
63 if (m_VisualizationWidget) {
64 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
64 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
65 return tab->availableZoneWidgets();
65 return tab->availableZoneWidgets();
66 }
66 }
67 }
67 }
68
68
69 return QStringList{};
69 return QStringList{};
70 }
70 }
71
71
72 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
72 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
73 bool allowMultiSelection, const QPoint &location)
73 bool allowMultiSelection, const QPoint &location)
74 {
74 {
75 auto availableZones = getAvailableVisualizationZoneList();
75 auto availableZones = getAvailableVisualizationZoneList();
76 if (availableZones.isEmpty()) {
76 if (availableZones.isEmpty()) {
77 return QStringList{};
77 return QStringList{};
78 }
78 }
79
79
80 QDialog d(parent, Qt::Tool);
80 QDialog d(parent, Qt::Tool);
81 d.setWindowTitle("Choose a zone");
81 d.setWindowTitle("Choose a zone");
82 auto layout = new QVBoxLayout{&d};
82 auto layout = new QVBoxLayout{&d};
83 layout->setContentsMargins(0, 0, 0, 0);
83 layout->setContentsMargins(0, 0, 0, 0);
84 auto listWidget = new QListWidget{&d};
84 auto listWidget = new QListWidget{&d};
85 layout->addWidget(listWidget);
85 layout->addWidget(listWidget);
86
86
87 QSet<QListWidgetItem *> checkedItems;
87 QSet<QListWidgetItem *> checkedItems;
88 for (auto zone : availableZones) {
88 for (auto zone : availableZones) {
89 auto item = new QListWidgetItem{zone};
89 auto item = new QListWidgetItem{zone};
90 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
90 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
91 if (selectedZones.contains(zone)) {
91 if (selectedZones.contains(zone)) {
92 item->setCheckState(Qt::Checked);
92 item->setCheckState(Qt::Checked);
93 checkedItems << item;
93 checkedItems << item;
94 }
94 }
95 else {
95 else {
96 item->setCheckState(Qt::Unchecked);
96 item->setCheckState(Qt::Unchecked);
97 }
97 }
98
98
99 listWidget->addItem(item);
99 listWidget->addItem(item);
100 }
100 }
101
101
102 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
102 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
103 layout->addWidget(buttonBox);
103 layout->addWidget(buttonBox);
104
104
105 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
105 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
106 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
106 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
107
107
108 QObject::connect(listWidget, &QListWidget::itemChanged,
108 QObject::connect(listWidget, &QListWidget::itemChanged,
109 [&checkedItems, allowMultiSelection, listWidget](auto item) {
109 [&checkedItems, allowMultiSelection, listWidget](auto item) {
110 if (item->checkState() == Qt::Checked) {
110 if (item->checkState() == Qt::Checked) {
111 if (!allowMultiSelection) {
111 if (!allowMultiSelection) {
112 for (auto checkedItem : checkedItems) {
112 for (auto checkedItem : checkedItems) {
113 listWidget->blockSignals(true);
113 listWidget->blockSignals(true);
114 checkedItem->setCheckState(Qt::Unchecked);
114 checkedItem->setCheckState(Qt::Unchecked);
115 listWidget->blockSignals(false);
115 listWidget->blockSignals(false);
116 }
116 }
117
117
118 checkedItems.clear();
118 checkedItems.clear();
119 }
119 }
120 checkedItems << item;
120 checkedItems << item;
121 }
121 }
122 else {
122 else {
123 checkedItems.remove(item);
123 checkedItems.remove(item);
124 }
124 }
125 });
125 });
126
126
127 QStringList result;
127 QStringList result;
128
128
129 d.setMinimumWidth(120);
129 d.setMinimumWidth(120);
130 d.resize(d.minimumSizeHint());
130 d.resize(d.minimumSizeHint());
131 d.move(location);
131 d.move(location);
132 if (d.exec() == QDialog::Accepted) {
132 if (d.exec() == QDialog::Accepted) {
133 for (auto item : checkedItems) {
133 for (auto item : checkedItems) {
134 result += item->text();
134 result += item->text();
135 }
135 }
136 }
136 }
137 else {
137 else {
138 result = selectedZones;
138 result = selectedZones;
139 }
139 }
140
140
141 return result;
141 return result;
142 }
142 }
143
143
144 void updateForTimeMode(QTreeView *treeView)
144 void updateForTimeMode(QTreeView *treeView)
145 {
145 {
146 auto selectedRows = treeView->selectionModel()->selectedRows();
146 auto selectedRows = treeView->selectionModel()->selectedRows();
147
147
148 if (selectedRows.count() == 1) {
148 if (selectedRows.count() == 1) {
149 auto event = m_Model->getEvent(selectedRows.first());
149 auto event = m_Model->getEvent(selectedRows.first());
150 if (event) {
150 if (event) {
151 if (m_VisualizationWidget) {
151 if (m_VisualizationWidget) {
152 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
152 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
153
153
154 for (auto zoneName : m_ZonesForTimeMode) {
154 for (auto zoneName : m_ZonesForTimeMode) {
155 if (auto zone = tab->getZoneWithName(zoneName)) {
155 if (auto zone = tab->getZoneWithName(zoneName)) {
156 SqpRange eventRange;
156 SqpRange eventRange;
157 eventRange.m_TStart = event->getTStart();
157 eventRange.m_TStart = event->getTStart();
158 eventRange.m_TEnd = event->getTEnd();
158 eventRange.m_TEnd = event->getTEnd();
159 zone->setZoneRange(eventRange);
159 zone->setZoneRange(eventRange);
160 }
160 }
161 }
161 }
162 }
162 }
163 else {
163 else {
164 qCWarning(LOG_CatalogueEventsWidget())
164 qCWarning(LOG_CatalogueEventsWidget())
165 << "updateTimeZone: no tab found in the visualization";
165 << "updateTimeZone: no tab found in the visualization";
166 }
166 }
167 }
167 }
168 else {
168 else {
169 qCWarning(LOG_CatalogueEventsWidget())
169 qCWarning(LOG_CatalogueEventsWidget())
170 << "updateTimeZone: visualization widget not found";
170 << "updateTimeZone: visualization widget not found";
171 }
171 }
172 }
172 }
173 }
173 }
174 else {
174 else {
175 qCWarning(LOG_CatalogueEventsWidget())
175 qCWarning(LOG_CatalogueEventsWidget())
176 << "updateTimeZone: not compatible with multiple events selected";
176 << "updateTimeZone: not compatible with multiple events selected";
177 }
177 }
178 }
178 }
179
179
180 void updateForGraphMode(QTreeView *treeView)
180 void updateForGraphMode(QTreeView *treeView)
181 {
181 {
182 auto selectedRows = treeView->selectionModel()->selectedRows();
182 auto selectedRows = treeView->selectionModel()->selectedRows();
183
183
184 if (selectedRows.count() == 1) {
184 if (selectedRows.count() == 1) {
185 auto event = m_Model->getEvent(selectedRows.first());
185 auto event = m_Model->getEvent(selectedRows.first());
186 if (m_VisualizationWidget) {
186 if (m_VisualizationWidget) {
187 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
187 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
188 if (auto zone = tab->getZoneWithName(m_ZoneForGraphMode)) {
188 if (auto zone = tab->getZoneWithName(m_ZoneForGraphMode)) {
189 // TODO
189 // TODO
190 }
190 }
191 }
191 }
192 else {
192 else {
193 qCWarning(LOG_CatalogueEventsWidget())
193 qCWarning(LOG_CatalogueEventsWidget())
194 << "updateGraphMode: no tab found in the visualization";
194 << "updateGraphMode: no tab found in the visualization";
195 }
195 }
196 }
196 }
197 else {
197 else {
198 qCWarning(LOG_CatalogueEventsWidget())
198 qCWarning(LOG_CatalogueEventsWidget())
199 << "updateGraphMode: visualization widget not found";
199 << "updateGraphMode: visualization widget not found";
200 }
200 }
201 }
201 }
202 else {
202 else {
203 qCWarning(LOG_CatalogueEventsWidget())
203 qCWarning(LOG_CatalogueEventsWidget())
204 << "updateGraphMode: not compatible with multiple events selected";
204 << "updateGraphMode: not compatible with multiple events selected";
205 }
205 }
206 }
206 }
207
207
208 void getSelectedItems(
208 void getSelectedItems(
209 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
209 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
210 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
210 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
211 {
211 {
212 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
212 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
213 auto itemType = m_Model->itemTypeOf(rowIndex);
213 auto itemType = m_Model->itemTypeOf(rowIndex);
214 if (itemType == CatalogueEventsModel::ItemType::Event) {
214 if (itemType == CatalogueEventsModel::ItemType::Event) {
215 events << m_Model->getEvent(rowIndex);
215 events << m_Model->getEvent(rowIndex);
216 }
216 }
217 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
217 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
218 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
218 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
219 m_Model->getEventProduct(rowIndex));
219 m_Model->getEventProduct(rowIndex));
220 }
220 }
221 }
221 }
222 }
222 }
223 };
223 };
224
224
225 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
225 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
226 : QWidget(parent),
226 : QWidget(parent),
227 ui(new Ui::CatalogueEventsWidget),
227 ui(new Ui::CatalogueEventsWidget),
228 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
228 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
229 {
229 {
230 ui->setupUi(this);
230 ui->setupUi(this);
231
231
232 impl->m_Model = new CatalogueEventsModel{this};
232 impl->m_Model = new CatalogueEventsModel{this};
233 ui->treeView->setModel(impl->m_Model);
233 ui->treeView->setModel(impl->m_Model);
234
234
235 ui->treeView->setSortingEnabled(true);
235 ui->treeView->setSortingEnabled(true);
236 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
236 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
237 ui->treeView->setDragEnabled(true);
237 ui->treeView->setDragEnabled(true);
238
238
239 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
239 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
240 if (checked) {
240 if (checked) {
241 ui->btnChart->setChecked(false);
241 ui->btnChart->setChecked(false);
242 impl->m_ZonesForTimeMode
242 impl->m_ZonesForTimeMode
243 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
243 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
244 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
244 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
245
245
246 impl->updateForTimeMode(ui->treeView);
246 impl->updateForTimeMode(ui->treeView);
247 }
247 }
248 });
248 });
249
249
250 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
250 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
251 if (checked) {
251 if (checked) {
252 ui->btnTime->setChecked(false);
252 ui->btnTime->setChecked(false);
253 impl->m_ZoneForGraphMode
253 impl->m_ZoneForGraphMode
254 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
254 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
255 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
255 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
256 .value(0);
256 .value(0);
257
257
258 impl->updateForGraphMode(ui->treeView);
258 impl->updateForGraphMode(ui->treeView);
259 }
259 }
260 });
260 });
261
261
262 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
262 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
263 QVector<std::shared_ptr<DBEvent> > events;
263 QVector<std::shared_ptr<DBEvent> > events;
264 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
264 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
265 impl->getSelectedItems(ui->treeView, events, eventProducts);
265 impl->getSelectedItems(ui->treeView, events, eventProducts);
266
266
267 if (!events.isEmpty() && eventProducts.isEmpty()) {
267 if (!events.isEmpty() && eventProducts.isEmpty()) {
268
268
269 if (QMessageBox::warning(this, tr("Remove Event(s)"),
269 if (QMessageBox::warning(this, tr("Remove Event(s)"),
270 tr("The selected event(s) will be completly removed "
270 tr("The selected event(s) will be completly removed "
271 "from the repository!\nAre you sure you want to continue?"),
271 "from the repository!\nAre you sure you want to continue?"),
272 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
272 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
273 == QMessageBox::Yes) {
273 == QMessageBox::Yes) {
274
274
275 for (auto event : events) {
275 for (auto event : events) {
276 sqpApp->catalogueController().removeEvent(event);
276 sqpApp->catalogueController().removeEvent(event);
277 impl->removeEvent(event, ui->treeView);
277 impl->removeEvent(event, ui->treeView);
278 }
278 }
279 }
279 }
280 }
280 }
281 });
281 });
282
282
283 auto emitSelection = [this]() {
283 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueEventsWidget::emitSelection);
284 QVector<std::shared_ptr<DBEvent> > events;
284 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
285 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
285 &CatalogueEventsWidget::emitSelection);
286 impl->getSelectedItems(ui->treeView, events, eventProducts);
287
288 if (!events.isEmpty() && eventProducts.isEmpty()) {
289 emit this->eventsSelected(events);
290 }
291 else if (events.isEmpty() && !eventProducts.isEmpty()) {
292 emit this->eventProductsSelected(eventProducts);
293 }
294 else {
295 emit this->selectionCleared();
296 }
297 };
298
299 connect(ui->treeView, &QTreeView::clicked, emitSelection);
300 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, emitSelection);
301
286
302 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
287 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
303 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
288 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
304 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
289 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
305 ui->btnChart->setEnabled(isNotMultiSelection);
290 ui->btnChart->setEnabled(isNotMultiSelection);
306 ui->btnTime->setEnabled(isNotMultiSelection);
291 ui->btnTime->setEnabled(isNotMultiSelection);
307
292
308 if (isNotMultiSelection && ui->btnTime->isChecked()) {
293 if (isNotMultiSelection && ui->btnTime->isChecked()) {
309 impl->updateForTimeMode(ui->treeView);
294 impl->updateForTimeMode(ui->treeView);
310 }
295 }
311 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
296 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
312 impl->updateForGraphMode(ui->treeView);
297 impl->updateForGraphMode(ui->treeView);
313 }
298 }
314
299
315 QVector<std::shared_ptr<DBEvent> > events;
300 QVector<std::shared_ptr<DBEvent> > events;
316 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
301 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
317 impl->getSelectedItems(ui->treeView, events, eventProducts);
302 impl->getSelectedItems(ui->treeView, events, eventProducts);
318 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
303 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
319 });
304 });
320
305
321 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
306 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
322 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
307 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
323 QHeaderView::Stretch);
308 QHeaderView::Stretch);
324 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
309 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
325 QHeaderView::Fixed);
310 QHeaderView::Fixed);
326 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
311 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
327 QHeaderView::Interactive);
312 QHeaderView::Interactive);
328 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
313 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
329 VALIDATION_COLUMN_SIZE);
314 VALIDATION_COLUMN_SIZE);
330 ui->treeView->header()->setSortIndicatorShown(true);
315 ui->treeView->header()->setSortIndicatorShown(true);
331
316
332 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
317 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
333 auto allEvents = impl->m_Model->events();
318 auto allEvents = impl->m_Model->events();
334 for (auto event : allEvents) {
319 for (auto event : allEvents) {
335 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
320 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
336 }
321 }
337 });
322 });
338
323
339 populateWithAllEvents();
324 populateWithAllEvents();
340 }
325 }
341
326
342 CatalogueEventsWidget::~CatalogueEventsWidget()
327 CatalogueEventsWidget::~CatalogueEventsWidget()
343 {
328 {
344 delete ui;
329 delete ui;
345 }
330 }
346
331
347 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
332 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
348 {
333 {
349 impl->m_VisualizationWidget = visualization;
334 impl->m_VisualizationWidget = visualization;
350 }
335 }
351
336
352 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
337 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
353 {
338 {
354 impl->addEvent(event, ui->treeView);
339 impl->addEvent(event, ui->treeView);
355 }
340 }
356
341
357 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
342 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
358 {
343 {
359 impl->m_Model->refreshEvent(event);
344 impl->m_Model->refreshEvent(event);
360
345
361 auto eventIndex = impl->m_Model->indexOf(event);
346 auto eventIndex = impl->m_Model->indexOf(event);
362 auto validationIndex
347 auto validationIndex
363 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
348 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
364
349
365 if (validationIndex.isValid()) {
350 if (validationIndex.isValid()) {
366 if (hasChanges) {
351 if (hasChanges) {
367 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
352 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
368 auto widget = CatalogueExplorerHelper::buildValidationWidget(
353 auto widget = CatalogueExplorerHelper::buildValidationWidget(
369 ui->treeView,
354 ui->treeView,
370 [this, event]() {
355 [this, event]() {
371 sqpApp->catalogueController().saveEvent(event);
356 sqpApp->catalogueController().saveEvent(event);
372 setEventChanges(event, false);
357 setEventChanges(event, false);
373 },
358 },
374 [this, event]() {
359 [this, event]() {
375 sqpApp->catalogueController().discardEvent(event);
360 sqpApp->catalogueController().discardEvent(event);
376 setEventChanges(event, false);
361 setEventChanges(event, false);
377 impl->m_Model->refreshEvent(event);
362 impl->m_Model->refreshEvent(event, true);
363 emitSelection();
378 });
364 });
379 ui->treeView->setIndexWidget(validationIndex, widget);
365 ui->treeView->setIndexWidget(validationIndex, widget);
380 }
366 }
381 }
367 }
382 else {
368 else {
383 // Note: the widget is destroyed
369 // Note: the widget is destroyed
384 ui->treeView->setIndexWidget(validationIndex, nullptr);
370 ui->treeView->setIndexWidget(validationIndex, nullptr);
385 }
371 }
386 }
372 }
387 else {
373 else {
388 qCWarning(LOG_CatalogueEventsWidget())
374 qCWarning(LOG_CatalogueEventsWidget())
389 << "setEventChanges: the event is not displayed in the model.";
375 << "setEventChanges: the event is not displayed in the model.";
390 }
376 }
391 }
377 }
392
378
393 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
379 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
394 {
380 {
395 return impl->m_DisplayedCatalogues;
381 return impl->m_DisplayedCatalogues;
396 }
382 }
397
383
398 bool CatalogueEventsWidget::isAllEventsDisplayed() const
384 bool CatalogueEventsWidget::isAllEventsDisplayed() const
399 {
385 {
400 return impl->m_DisplayedCatalogues.isEmpty() && !impl->m_Model->events().isEmpty();
386 return impl->m_DisplayedCatalogues.isEmpty() && !impl->m_Model->events().isEmpty();
401 }
387 }
402
388
403 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
389 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
404 {
390 {
405 return impl->m_Model->indexOf(event).isValid();
391 return impl->m_Model->indexOf(event).isValid();
406 }
392 }
407
393
408 void CatalogueEventsWidget::populateWithCatalogues(
394 void CatalogueEventsWidget::populateWithCatalogues(
409 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
395 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
410 {
396 {
411 impl->m_DisplayedCatalogues = catalogues;
397 impl->m_DisplayedCatalogues = catalogues;
412
398
413 QSet<QUuid> eventIds;
399 QSet<QUuid> eventIds;
414 QVector<std::shared_ptr<DBEvent> > events;
400 QVector<std::shared_ptr<DBEvent> > events;
415
401
416 for (auto catalogue : catalogues) {
402 for (auto catalogue : catalogues) {
417 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
403 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
418 for (auto event : catalogueEvents) {
404 for (auto event : catalogueEvents) {
419 if (!eventIds.contains(event->getUniqId())) {
405 if (!eventIds.contains(event->getUniqId())) {
420 events << event;
406 events << event;
421 eventIds.insert(event->getUniqId());
407 eventIds.insert(event->getUniqId());
422 }
408 }
423 }
409 }
424 }
410 }
425
411
426 impl->setEvents(events, this);
412 impl->setEvents(events, this);
427 }
413 }
428
414
429 void CatalogueEventsWidget::populateWithAllEvents()
415 void CatalogueEventsWidget::populateWithAllEvents()
430 {
416 {
431 impl->m_DisplayedCatalogues.clear();
417 impl->m_DisplayedCatalogues.clear();
432
418
433 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
419 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
434
420
435 QVector<std::shared_ptr<DBEvent> > events;
421 QVector<std::shared_ptr<DBEvent> > events;
436 for (auto event : allEvents) {
422 for (auto event : allEvents) {
437 events << event;
423 events << event;
438 }
424 }
439
425
440 impl->setEvents(events, this);
426 impl->setEvents(events, this);
441 }
427 }
442
428
443 void CatalogueEventsWidget::clear()
429 void CatalogueEventsWidget::clear()
444 {
430 {
445 impl->m_DisplayedCatalogues.clear();
431 impl->m_DisplayedCatalogues.clear();
446 impl->setEvents({}, this);
432 impl->setEvents({}, this);
447 }
433 }
448
434
449 void CatalogueEventsWidget::refresh()
435 void CatalogueEventsWidget::refresh()
450 {
436 {
451 if (impl->m_DisplayedCatalogues.isEmpty()) {
437 if (impl->m_DisplayedCatalogues.isEmpty()) {
452 populateWithAllEvents();
438 populateWithAllEvents();
453 }
439 }
454 else {
440 else {
455 populateWithCatalogues(impl->m_DisplayedCatalogues);
441 populateWithCatalogues(impl->m_DisplayedCatalogues);
456 }
442 }
457 }
443 }
444
445 void CatalogueEventsWidget::emitSelection()
446 {
447 QVector<std::shared_ptr<DBEvent> > events;
448 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
449 impl->getSelectedItems(ui->treeView, events, eventProducts);
450
451 if (!events.isEmpty() && eventProducts.isEmpty()) {
452 emit eventsSelected(events);
453 }
454 else if (events.isEmpty() && !eventProducts.isEmpty()) {
455 emit eventProductsSelected(eventProducts);
456 }
457 else {
458 emit selectionCleared();
459 }
460 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

Status change > Approved

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