##// END OF EJS Templates
Fix drag&drop on time widget with event products
trabillard -
r1184:bd1680488073
parent child
Show More
@@ -1,364 +1,381
1 #include "Catalogue/CatalogueEventsModel.h"
1 #include "Catalogue/CatalogueEventsModel.h"
2
2
3 #include <Common/DateUtils.h>
3 #include <Common/DateUtils.h>
4 #include <Common/MimeTypesDef.h>
4 #include <Common/MimeTypesDef.h>
5 #include <DBEvent.h>
5 #include <DBEvent.h>
6 #include <DBEventProduct.h>
6 #include <DBEventProduct.h>
7 #include <DBTag.h>
7 #include <DBTag.h>
8 #include <Data/SqpRange.h>
8 #include <Data/SqpRange.h>
9 #include <SqpApplication.h>
9 #include <SqpApplication.h>
10 #include <Time/TimeController.h>
10 #include <Time/TimeController.h>
11
11
12 #include <list>
12 #include <list>
13 #include <unordered_map>
13 #include <unordered_map>
14
14
15 #include <QHash>
15 #include <QHash>
16 #include <QMimeData>
16 #include <QMimeData>
17
17
18 const auto EVENT_ITEM_TYPE = 1;
18 const auto EVENT_ITEM_TYPE = 1;
19 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
19 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
20
20
21 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
21 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
22 QVector<std::shared_ptr<DBEvent> > m_Events;
22 QVector<std::shared_ptr<DBEvent> > m_Events;
23 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
23 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
24
24
25 enum class Column { Name, TStart, TEnd, Tags, Product, NbColumn };
25 enum class Column { Name, TStart, TEnd, Tags, Product, NbColumn };
26 QStringList columnNames()
26 QStringList columnNames()
27 {
27 {
28 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"), tr("Tags"), tr("Product")};
28 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"), tr("Tags"), tr("Product")};
29 }
29 }
30
30
31 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
31 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
32 {
32 {
33 switch (static_cast<Column>(col)) {
33 switch (static_cast<Column>(col)) {
34 case Column::Name:
34 case Column::Name:
35 return event->getName();
35 return event->getName();
36 case Column::TStart:
36 case Column::TStart:
37 return "Oo"; // DateUtils::dateTime(event->getTStart());
37 return "Oo"; // DateUtils::dateTime(event->getTStart());
38 case Column::TEnd:
38 case Column::TEnd:
39 return "oO"; // DateUtils::dateTime(event->getTEnd());
39 return "oO"; // DateUtils::dateTime(event->getTEnd());
40 case Column::Product: {
40 case Column::Product: {
41 auto eventProductsIt = m_EventProducts.find(event.get());
41 auto eventProductsIt = m_EventProducts.find(event.get());
42 if (eventProductsIt != m_EventProducts.cend()) {
42 if (eventProductsIt != m_EventProducts.cend()) {
43 return QString::number(m_EventProducts.at(event.get()).count()) + " product(s)";
43 return QString::number(m_EventProducts.at(event.get()).count()) + " product(s)";
44 }
44 }
45 else {
45 else {
46 return "0 product";
46 return "0 product";
47 }
47 }
48 }
48 }
49 case Column::Tags: {
49 case Column::Tags: {
50 QString tagList;
50 QString tagList;
51 auto tags = event->getTags();
51 auto tags = event->getTags();
52 for (auto tag : tags) {
52 for (auto tag : tags) {
53 tagList += tag.getName();
53 tagList += tag.getName();
54 tagList += ' ';
54 tagList += ' ';
55 }
55 }
56
56
57 return tagList;
57 return tagList;
58 }
58 }
59 default:
59 default:
60 break;
60 break;
61 }
61 }
62
62
63 Q_ASSERT(false);
63 Q_ASSERT(false);
64 return QStringLiteral("Unknown Data");
64 return QStringLiteral("Unknown Data");
65 }
65 }
66
66
67 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
67 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
68 {
68 {
69 for (auto product : event->getEventProducts()) {
69 for (auto product : event->getEventProducts()) {
70 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
70 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
71 }
71 }
72 }
72 }
73
73
74 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
74 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
75 {
75 {
76 switch (static_cast<Column>(col)) {
76 switch (static_cast<Column>(col)) {
77 case Column::Name:
77 case Column::Name:
78 return eventProduct->getProductId();
78 return eventProduct->getProductId();
79 case Column::TStart:
79 case Column::TStart:
80 return DateUtils::dateTime(eventProduct->getTStart());
80 return DateUtils::dateTime(eventProduct->getTStart());
81 case Column::TEnd:
81 case Column::TEnd:
82 return DateUtils::dateTime(eventProduct->getTEnd());
82 return DateUtils::dateTime(eventProduct->getTEnd());
83 case Column::Product:
83 case Column::Product:
84 return eventProduct->getProductId();
84 return eventProduct->getProductId();
85 case Column::Tags: {
85 case Column::Tags: {
86 return QString();
86 return QString();
87 }
87 }
88 default:
88 default:
89 break;
89 break;
90 }
90 }
91
91
92 Q_ASSERT(false);
92 Q_ASSERT(false);
93 return QStringLiteral("Unknown Data");
93 return QStringLiteral("Unknown Data");
94 }
94 }
95 };
95 };
96
96
97 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
97 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
98 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
98 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
99 {
99 {
100 }
100 }
101
101
102 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
102 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
103 {
103 {
104 beginResetModel();
104 beginResetModel();
105
105
106 impl->m_Events = events;
106 impl->m_Events = events;
107 impl->m_EventProducts.clear();
107 impl->m_EventProducts.clear();
108 for (auto event : events) {
108 for (auto event : events) {
109 impl->parseEventProduct(event);
109 impl->parseEventProduct(event);
110 }
110 }
111
111
112 endResetModel();
112 endResetModel();
113 }
113 }
114
114
115 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
115 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
116 {
116 {
117 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
117 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
118 return impl->m_Events.value(index.row());
118 return impl->m_Events.value(index.row());
119 }
119 }
120 else {
120 else {
121 return nullptr;
121 return nullptr;
122 }
122 }
123 }
123 }
124
124
125 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
125 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
126 {
126 {
127 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
127 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
128 return getEvent(index.parent());
128 return getEvent(index.parent());
129 }
129 }
130 else {
130 else {
131 return nullptr;
131 return nullptr;
132 }
132 }
133 }
133 }
134
134
135 std::shared_ptr<DBEventProduct>
135 std::shared_ptr<DBEventProduct>
136 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
136 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
137 {
137 {
138 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
138 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
139 auto event = static_cast<DBEvent *>(index.internalPointer());
139 auto event = static_cast<DBEvent *>(index.internalPointer());
140 return impl->m_EventProducts.at(event).value(index.row());
140 return impl->m_EventProducts.at(event).value(index.row());
141 }
141 }
142 else {
142 else {
143 return nullptr;
143 return nullptr;
144 }
144 }
145 }
145 }
146
146
147 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
147 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
148 {
148 {
149 beginInsertRows(QModelIndex(), impl->m_Events.count() - 1, impl->m_Events.count() - 1);
149 beginInsertRows(QModelIndex(), impl->m_Events.count() - 1, impl->m_Events.count() - 1);
150 impl->m_Events.append(event);
150 impl->m_Events.append(event);
151 impl->parseEventProduct(event);
151 impl->parseEventProduct(event);
152 endInsertRows();
152 endInsertRows();
153 }
153 }
154
154
155 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
155 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
156 {
156 {
157 auto index = impl->m_Events.indexOf(event);
157 auto index = impl->m_Events.indexOf(event);
158 if (index >= 0) {
158 if (index >= 0) {
159 beginRemoveRows(QModelIndex(), index, index);
159 beginRemoveRows(QModelIndex(), index, index);
160 impl->m_Events.removeAt(index);
160 impl->m_Events.removeAt(index);
161 impl->m_EventProducts.erase(event.get());
161 impl->m_EventProducts.erase(event.get());
162 endRemoveRows();
162 endRemoveRows();
163 }
163 }
164 }
164 }
165
165
166 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event)
166 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event)
167 {
167 {
168 auto i = impl->m_Events.indexOf(event);
168 auto i = impl->m_Events.indexOf(event);
169 if (i >= 0) {
169 if (i >= 0) {
170 auto eventIndex = index(i, 0);
170 auto eventIndex = index(i, 0);
171 auto colCount = columnCount();
171 auto colCount = columnCount();
172 emit dataChanged(eventIndex, index(i, colCount));
172 emit dataChanged(eventIndex, index(i, colCount));
173
173
174 auto childCount = rowCount(eventIndex);
174 auto childCount = rowCount(eventIndex);
175 emit dataChanged(index(0, 0, eventIndex), index(childCount, colCount, eventIndex));
175 emit dataChanged(index(0, 0, eventIndex), index(childCount, colCount, eventIndex));
176 }
176 }
177 }
177 }
178
178
179 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
179 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
180 {
180 {
181 if (!hasIndex(row, column, parent)) {
181 if (!hasIndex(row, column, parent)) {
182 return QModelIndex();
182 return QModelIndex();
183 }
183 }
184
184
185 switch (itemTypeOf(parent)) {
185 switch (itemTypeOf(parent)) {
186 case CatalogueEventsModel::ItemType::Root:
186 case CatalogueEventsModel::ItemType::Root:
187 return createIndex(row, column);
187 return createIndex(row, column);
188 case CatalogueEventsModel::ItemType::Event: {
188 case CatalogueEventsModel::ItemType::Event: {
189 auto event = getEvent(parent);
189 auto event = getEvent(parent);
190 return createIndex(row, column, event.get());
190 return createIndex(row, column, event.get());
191 }
191 }
192 case CatalogueEventsModel::ItemType::EventProduct:
192 case CatalogueEventsModel::ItemType::EventProduct:
193 break;
193 break;
194 default:
194 default:
195 break;
195 break;
196 }
196 }
197
197
198 return QModelIndex();
198 return QModelIndex();
199 }
199 }
200
200
201 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
201 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
202 {
202 {
203 switch (itemTypeOf(index)) {
203 switch (itemTypeOf(index)) {
204 case CatalogueEventsModel::ItemType::EventProduct: {
204 case CatalogueEventsModel::ItemType::EventProduct: {
205 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
205 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
206 auto it
206 auto it
207 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
207 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
208 [parentEvent](auto event) { return event.get() == parentEvent; });
208 [parentEvent](auto event) { return event.get() == parentEvent; });
209
209
210 if (it != impl->m_Events.cend()) {
210 if (it != impl->m_Events.cend()) {
211 return createIndex(it - impl->m_Events.cbegin(), 0);
211 return createIndex(it - impl->m_Events.cbegin(), 0);
212 }
212 }
213 else {
213 else {
214 return QModelIndex();
214 return QModelIndex();
215 }
215 }
216 }
216 }
217 case CatalogueEventsModel::ItemType::Root:
217 case CatalogueEventsModel::ItemType::Root:
218 break;
218 break;
219 case CatalogueEventsModel::ItemType::Event:
219 case CatalogueEventsModel::ItemType::Event:
220 break;
220 break;
221 default:
221 default:
222 break;
222 break;
223 }
223 }
224
224
225 return QModelIndex();
225 return QModelIndex();
226 }
226 }
227
227
228 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
228 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
229 {
229 {
230 if (parent.column() > 0) {
230 if (parent.column() > 0) {
231 return 0;
231 return 0;
232 }
232 }
233
233
234 switch (itemTypeOf(parent)) {
234 switch (itemTypeOf(parent)) {
235 case CatalogueEventsModel::ItemType::Root:
235 case CatalogueEventsModel::ItemType::Root:
236 return impl->m_Events.count();
236 return impl->m_Events.count();
237 case CatalogueEventsModel::ItemType::Event: {
237 case CatalogueEventsModel::ItemType::Event: {
238 auto event = getEvent(parent);
238 auto event = getEvent(parent);
239 return impl->m_EventProducts[event.get()].count();
239 return impl->m_EventProducts[event.get()].count();
240 }
240 }
241 case CatalogueEventsModel::ItemType::EventProduct:
241 case CatalogueEventsModel::ItemType::EventProduct:
242 break;
242 break;
243 default:
243 default:
244 break;
244 break;
245 }
245 }
246
246
247 return 0;
247 return 0;
248 }
248 }
249
249
250 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
250 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
251 {
251 {
252 return static_cast<int>(CatalogueEventsModelPrivate::Column::NbColumn);
252 return static_cast<int>(CatalogueEventsModelPrivate::Column::NbColumn);
253 }
253 }
254
254
255 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
255 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
256 {
256 {
257 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
257 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
258 }
258 }
259
259
260 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
260 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
261 {
261 {
262 if (index.isValid()) {
262 if (index.isValid()) {
263
263
264 auto type = itemTypeOf(index);
264 auto type = itemTypeOf(index);
265 if (type == CatalogueEventsModel::ItemType::Event) {
265 if (type == CatalogueEventsModel::ItemType::Event) {
266 auto event = getEvent(index);
266 auto event = getEvent(index);
267 switch (role) {
267 switch (role) {
268 case Qt::DisplayRole:
268 case Qt::DisplayRole:
269 return impl->eventData(index.column(), event);
269 return impl->eventData(index.column(), event);
270 break;
270 break;
271 }
271 }
272 }
272 }
273 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
273 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
274 auto product = getEventProduct(index);
274 auto product = getEventProduct(index);
275 switch (role) {
275 switch (role) {
276 case Qt::DisplayRole:
276 case Qt::DisplayRole:
277 return impl->eventProductData(index.column(), product);
277 return impl->eventProductData(index.column(), product);
278 break;
278 break;
279 }
279 }
280 }
280 }
281 }
281 }
282
282
283 return QVariant{};
283 return QVariant{};
284 }
284 }
285
285
286 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
286 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
287 {
287 {
288 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
288 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
289 return impl->columnNames().value(section);
289 return impl->columnNames().value(section);
290 }
290 }
291
291
292 return QVariant();
292 return QVariant();
293 }
293 }
294
294
295 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
295 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
296 {
296 {
297 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
297 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
298 [this, column, order](auto e1, auto e2) {
298 [this, column, order](auto e1, auto e2) {
299 auto data1 = impl->eventData(column, e1);
299 auto data1 = impl->eventData(column, e1);
300 auto data2 = impl->eventData(column, e2);
300 auto data2 = impl->eventData(column, e2);
301
301
302 auto result = data1.toString() < data2.toString();
302 auto result = data1.toString() < data2.toString();
303
303
304 return order == Qt::AscendingOrder ? result : !result;
304 return order == Qt::AscendingOrder ? result : !result;
305 });
305 });
306
306
307 emit dataChanged(QModelIndex(), QModelIndex());
307 emit dataChanged(QModelIndex(), QModelIndex());
308 }
308 }
309
309
310 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
310 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
311 {
311 {
312 return Qt::CopyAction | Qt::MoveAction;
312 return Qt::CopyAction | Qt::MoveAction;
313 }
313 }
314
314
315 QStringList CatalogueEventsModel::mimeTypes() const
315 QStringList CatalogueEventsModel::mimeTypes() const
316 {
316 {
317 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_TIME_RANGE};
317 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_TIME_RANGE};
318 }
318 }
319
319
320 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
320 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
321 {
321 {
322 auto mimeData = new QMimeData;
322 auto mimeData = new QMimeData;
323
323
324 bool isFirst = true;
325
324 QVector<std::shared_ptr<DBEvent> > eventList;
326 QVector<std::shared_ptr<DBEvent> > eventList;
327 QVector<std::shared_ptr<DBEventProduct> > eventProductList;
325
328
326 SqpRange firstTimeRange;
329 SqpRange firstTimeRange;
327 for (const auto &index : indexes) {
330 for (const auto &index : indexes) {
328 if (index.column() == 0) { // only the first column
331 if (index.column() == 0) { // only the first column
329 auto event = getEvent(index);
330 if (eventList.isEmpty()) {
331 // Gets the range of the first variable
332 // firstTimeRange.m_TStart = event->getTStart();
333 // firstTimeRange.m_TEnd = event->getTEnd();
334 }
335
332
336 eventList << event;
333 auto type = itemTypeOf(index);
334 if (type == ItemType::Event) {
335 auto event = getEvent(index);
336 eventList << event;
337
338 if (isFirst) {
339 isFirst = false;
340 // firstTimeRange.m_TStart = event->getTStart();
341 // firstTimeRange.m_TEnd = event->getTEnd();
342 }
343 }
344 else if (type == ItemType::EventProduct) {
345 auto product = getEventProduct(index);
346 eventProductList << product;
347
348 if (isFirst) {
349 isFirst = false;
350 firstTimeRange.m_TStart = product->getTStart();
351 firstTimeRange.m_TEnd = product->getTEnd();
352 }
353 }
337 }
354 }
338 }
355 }
339
356
340 auto eventsEncodedData
357 auto eventsEncodedData
341 = QByteArray{}; // sqpApp->catalogueController().->mimeDataForEvents(eventList); //TODO
358 = QByteArray{}; // sqpApp->catalogueController().->mimeDataForEvents(eventList); //TODO
342 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
359 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
343
360
344 if (eventList.count() == 1) {
361 if (eventList.count() + eventProductList.count() == 1) {
345 // No time range MIME data if multiple events are dragged
362 // No time range MIME data if multiple events are dragged
346 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
363 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
347 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
364 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
348 }
365 }
349
366
350 return mimeData;
367 return mimeData;
351 }
368 }
352
369
353 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
370 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
354 {
371 {
355 if (!index.isValid()) {
372 if (!index.isValid()) {
356 return ItemType::Root;
373 return ItemType::Root;
357 }
374 }
358 else if (index.internalPointer() == nullptr) {
375 else if (index.internalPointer() == nullptr) {
359 return ItemType::Event;
376 return ItemType::Event;
360 }
377 }
361 else {
378 else {
362 return ItemType::EventProduct;
379 return ItemType::EventProduct;
363 }
380 }
364 }
381 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved

Status change > Approved

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