##// END OF EJS Templates
Move event in catalogue with Drag&Drop
trabillard -
r1362:c5e93e891fc6
parent child
Show More
@@ -1,86 +1,93
1 #ifndef SCIQLOP_CATALOGUECONTROLLER_H
1 #ifndef SCIQLOP_CATALOGUECONTROLLER_H
2 #define SCIQLOP_CATALOGUECONTROLLER_H
2 #define SCIQLOP_CATALOGUECONTROLLER_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/SqpRange.h>
6 #include <Data/SqpRange.h>
7
7
8 #include <QLoggingCategory>
8 #include <QLoggingCategory>
9 #include <QObject>
9 #include <QObject>
10 #include <QUuid>
10 #include <QUuid>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 #include <memory>
14 #include <memory>
15
15
16 class DBCatalogue;
16 class DBCatalogue;
17 class DBEvent;
17 class DBEvent;
18 class DBEventProduct;
18 class DBEventProduct;
19
19
20 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueController)
20 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueController)
21
21
22 class DataSourceItem;
22 class DataSourceItem;
23 class Variable;
23 class Variable;
24
24
25 /**
25 /**
26 * @brief The CatalogueController class aims to handle catalogues and event using the CatalogueAPI
26 * @brief The CatalogueController class aims to handle catalogues and event using the CatalogueAPI
27 * library.
27 * library.
28 */
28 */
29 class SCIQLOP_CORE_EXPORT CatalogueController : public QObject {
29 class SCIQLOP_CORE_EXPORT CatalogueController : public QObject {
30 Q_OBJECT
30 Q_OBJECT
31 public:
31 public:
32 explicit CatalogueController(QObject *parent = 0);
32 explicit CatalogueController(QObject *parent = 0);
33 virtual ~CatalogueController();
33 virtual ~CatalogueController();
34
34
35 // DB
35 // DB
36 QStringList getRepositories() const;
36 QStringList getRepositories() const;
37 void addDB(const QString &dbPath);
37 void addDB(const QString &dbPath);
38 void saveDB(const QString &destinationPath, const QString &repository);
38 void saveDB(const QString &destinationPath, const QString &repository);
39
39
40 // Event
40 // Event
41 /// retrieveEvents with empty repository retrieve them from the default repository
41 /// retrieveEvents with empty repository retrieve them from the default repository
42 std::list<std::shared_ptr<DBEvent> > retrieveEvents(const QString &repository) const;
42 std::list<std::shared_ptr<DBEvent> > retrieveEvents(const QString &repository) const;
43 std::list<std::shared_ptr<DBEvent> > retrieveAllEvents() const;
43 std::list<std::shared_ptr<DBEvent> > retrieveAllEvents() const;
44
44
45 void addEvent(std::shared_ptr<DBEvent> event);
45 void addEvent(std::shared_ptr<DBEvent> event);
46 void updateEvent(std::shared_ptr<DBEvent> event);
46 void updateEvent(std::shared_ptr<DBEvent> event);
47 void updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct);
47 void updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct);
48 void removeEvent(std::shared_ptr<DBEvent> event);
48 void removeEvent(std::shared_ptr<DBEvent> event);
49 // void trashEvent(std::shared_ptr<DBEvent> event);
49 // void trashEvent(std::shared_ptr<DBEvent> event);
50 // void restore(std::shared_ptr<DBEvent> event);
50 // void restore(std::shared_ptr<DBEvent> event);
51 void saveEvent(std::shared_ptr<DBEvent> event);
51 void saveEvent(std::shared_ptr<DBEvent> event);
52 void discardEvent(std::shared_ptr<DBEvent> event, bool &removed);
52 void discardEvent(std::shared_ptr<DBEvent> event, bool &removed);
53 bool eventHasChanges(std::shared_ptr<DBEvent> event) const;
53 bool eventHasChanges(std::shared_ptr<DBEvent> event) const;
54
54
55 // Catalogue
55 // Catalogue
56 std::list<std::shared_ptr<DBEvent> >
56 std::list<std::shared_ptr<DBEvent> >
57 retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const;
57 retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const;
58
58
59 /// retrieveEvents with empty repository retrieve them from the default repository
59 /// retrieveEvents with empty repository retrieve them from the default repository
60 std::list<std::shared_ptr<DBCatalogue> > retrieveCatalogues(const QString &repository
60 std::list<std::shared_ptr<DBCatalogue> > retrieveCatalogues(const QString &repository
61 = QString()) const;
61 = QString()) const;
62 void addCatalogue(std::shared_ptr<DBCatalogue> catalogue);
62 void addCatalogue(std::shared_ptr<DBCatalogue> catalogue);
63 void updateCatalogue(std::shared_ptr<DBCatalogue> catalogue);
63 void updateCatalogue(std::shared_ptr<DBCatalogue> catalogue);
64 void removeCatalogue(std::shared_ptr<DBCatalogue> catalogue);
64 void removeCatalogue(std::shared_ptr<DBCatalogue> catalogue);
65 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue);
65 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue);
66 void discardCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool &removed);
66 void discardCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool &removed);
67
67
68 void saveAll();
68 void saveAll();
69 bool hasChanges() const;
69 bool hasChanges() const;
70
70
71 /// Returns the MIME data associated to a list of variables
71 /// Returns the MIME data associated to a list of variables
72 QByteArray mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const;
72 QByteArray mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const;
73
73
74 /// Returns the list of variables contained in a MIME data
74 /// Returns the list of variables contained in a MIME data
75 QVector<std::shared_ptr<DBEvent> > eventsForMimeData(const QByteArray &mimeData) const;
75 QVector<std::shared_ptr<DBEvent> > eventsForMimeData(const QByteArray &mimeData) const;
76
76
77 /// Returns the MIME data associated to a list of variables
78 QByteArray
79 mimeDataForCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues) const;
80
81 /// Returns the list of variables contained in a MIME data
82 QVector<std::shared_ptr<DBCatalogue> > cataloguesForMimeData(const QByteArray &mimeData) const;
83
77 public slots:
84 public slots:
78 /// Manage init/end of the controller
85 /// Manage init/end of the controller
79 void initialize();
86 void initialize();
80
87
81 private:
88 private:
82 class CatalogueControllerPrivate;
89 class CatalogueControllerPrivate;
83 spimpl::unique_impl_ptr<CatalogueControllerPrivate> impl;
90 spimpl::unique_impl_ptr<CatalogueControllerPrivate> impl;
84 };
91 };
85
92
86 #endif // SCIQLOP_CATALOGUECONTROLLER_H
93 #endif // SCIQLOP_CATALOGUECONTROLLER_H
@@ -1,21 +1,22
1 #ifndef SCIQLOP_MIMETYPESDEF_H
1 #ifndef SCIQLOP_MIMETYPESDEF_H
2 #define SCIQLOP_MIMETYPESDEF_H
2 #define SCIQLOP_MIMETYPESDEF_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <QString>
6 #include <QString>
7
7
8 // ////////////////// //
8 // ////////////////// //
9 // SciQlop Mime Types //
9 // SciQlop Mime Types //
10 // ////////////////// //
10 // ////////////////// //
11
11
12 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH;
12 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH;
13 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
13 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
17 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_SELECTION_ZONE;
17 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_SELECTION_ZONE;
18 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_EVENT_LIST;
18 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_EVENT_LIST;
19 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_SOURCE_CATALOGUE_LIST;
19
20
20
21
21 #endif // SCIQLOP_MIMETYPESDEF_H
22 #endif // SCIQLOP_MIMETYPESDEF_H
@@ -1,526 +1,566
1 #include <Catalogue/CatalogueController.h>
1 #include <Catalogue/CatalogueController.h>
2
2
3 #include <Variable/Variable.h>
3 #include <Variable/Variable.h>
4
4
5 #include <CatalogueDao.h>
5 #include <CatalogueDao.h>
6
6
7 #include <ComparaisonPredicate.h>
7 #include <ComparaisonPredicate.h>
8 #include <CompoundPredicate.h>
8 #include <CompoundPredicate.h>
9 #include <DBCatalogue.h>
9 #include <DBCatalogue.h>
10 #include <DBEvent.h>
10 #include <DBEvent.h>
11 #include <DBEventProduct.h>
11 #include <DBEventProduct.h>
12 #include <DBTag.h>
12 #include <DBTag.h>
13 #include <IRequestPredicate.h>
13 #include <IRequestPredicate.h>
14
14
15 #include <QDataStream>
15 #include <QDataStream>
16 #include <QMutex>
16 #include <QMutex>
17 #include <QThread>
17 #include <QThread>
18
18
19 #include <QDir>
19 #include <QDir>
20 #include <QStandardPaths>
20 #include <QStandardPaths>
21
21
22 Q_LOGGING_CATEGORY(LOG_CatalogueController, "CatalogueController")
22 Q_LOGGING_CATEGORY(LOG_CatalogueController, "CatalogueController")
23
23
24 namespace {
24 namespace {
25
25
26 static QString REPOSITORY_WORK_SUFFIX = QString{"_work"};
26 static QString REPOSITORY_WORK_SUFFIX = QString{"_work"};
27 static QString REPOSITORY_TRASH_SUFFIX = QString{"_trash"};
27 static QString REPOSITORY_TRASH_SUFFIX = QString{"_trash"};
28 }
28 }
29
29
30 /**
30 /**
31 * Possible types of an repository
31 * Possible types of an repository
32 */
32 */
33 enum class DBType { SYNC, WORK, TRASH };
33 enum class DBType { SYNC, WORK, TRASH };
34 class CatalogueController::CatalogueControllerPrivate {
34 class CatalogueController::CatalogueControllerPrivate {
35
35
36 public:
36 public:
37 explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {}
37 explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {}
38
38
39 CatalogueDao m_CatalogueDao;
39 CatalogueDao m_CatalogueDao;
40
40
41 QStringList m_RepositoryList;
41 QStringList m_RepositoryList;
42 CatalogueController *m_Q;
42 CatalogueController *m_Q;
43
43
44 QSet<QString> m_KeysWithChanges;
44 QSet<QString> m_KeysWithChanges;
45
45
46 QString eventUniqueKey(const std::shared_ptr<DBEvent> &event) const;
46 QString eventUniqueKey(const std::shared_ptr<DBEvent> &event) const;
47 QString catalogueUniqueKey(const std::shared_ptr<DBCatalogue> &catalogue) const;
47 QString catalogueUniqueKey(const std::shared_ptr<DBCatalogue> &catalogue) const;
48
48
49 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
49 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
50 QString toWorkRepository(QString repository);
50 QString toWorkRepository(QString repository);
51 QString toSyncRepository(QString repository);
51 QString toSyncRepository(QString repository);
52 void savAllDB();
52 void savAllDB();
53
53
54 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
54 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
55 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
55 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
56
56
57 std::shared_ptr<IRequestPredicate> createFinder(const QUuid &uniqId, const QString &repository,
57 std::shared_ptr<IRequestPredicate> createFinder(const QUuid &uniqId, const QString &repository,
58 DBType type);
58 DBType type);
59 };
59 };
60
60
61 CatalogueController::CatalogueController(QObject *parent)
61 CatalogueController::CatalogueController(QObject *parent)
62 : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)}
62 : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)}
63 {
63 {
64 qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction")
64 qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction")
65 << QThread::currentThread();
65 << QThread::currentThread();
66 }
66 }
67
67
68 CatalogueController::~CatalogueController()
68 CatalogueController::~CatalogueController()
69 {
69 {
70 qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction")
70 qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction")
71 << QThread::currentThread();
71 << QThread::currentThread();
72 }
72 }
73
73
74 QStringList CatalogueController::getRepositories() const
74 QStringList CatalogueController::getRepositories() const
75 {
75 {
76 return impl->m_RepositoryList;
76 return impl->m_RepositoryList;
77 }
77 }
78
78
79 void CatalogueController::addDB(const QString &dbPath)
79 void CatalogueController::addDB(const QString &dbPath)
80 {
80 {
81 QDir dbDir(dbPath);
81 QDir dbDir(dbPath);
82 if (dbDir.exists()) {
82 if (dbDir.exists()) {
83 auto dirName = dbDir.dirName();
83 auto dirName = dbDir.dirName();
84
84
85 if (std::find(impl->m_RepositoryList.cbegin(), impl->m_RepositoryList.cend(), dirName)
85 if (std::find(impl->m_RepositoryList.cbegin(), impl->m_RepositoryList.cend(), dirName)
86 != impl->m_RepositoryList.cend()) {
86 != impl->m_RepositoryList.cend()) {
87 qCCritical(LOG_CatalogueController())
87 qCCritical(LOG_CatalogueController())
88 << tr("Impossible to addDB that is already loaded");
88 << tr("Impossible to addDB that is already loaded");
89 }
89 }
90
90
91 if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) {
91 if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) {
92 qCCritical(LOG_CatalogueController())
92 qCCritical(LOG_CatalogueController())
93 << tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath);
93 << tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath);
94 }
94 }
95 else {
95 else {
96 impl->m_RepositoryList << dirName;
96 impl->m_RepositoryList << dirName;
97 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
97 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
98 }
98 }
99 }
99 }
100 else {
100 else {
101 qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ")
101 qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ")
102 << dbPath;
102 << dbPath;
103 }
103 }
104 }
104 }
105
105
106 void CatalogueController::saveDB(const QString &destinationPath, const QString &repository)
106 void CatalogueController::saveDB(const QString &destinationPath, const QString &repository)
107 {
107 {
108 if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) {
108 if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) {
109 qCCritical(LOG_CatalogueController())
109 qCCritical(LOG_CatalogueController())
110 << tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath);
110 << tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath);
111 }
111 }
112 }
112 }
113
113
114 std::list<std::shared_ptr<DBEvent> >
114 std::list<std::shared_ptr<DBEvent> >
115 CatalogueController::retrieveEvents(const QString &repository) const
115 CatalogueController::retrieveEvents(const QString &repository) const
116 {
116 {
117 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
117 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
118
118
119 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
119 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
120 auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName));
120 auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName));
121 for (auto event : events) {
121 for (auto event : events) {
122 eventsShared.push_back(std::make_shared<DBEvent>(event));
122 eventsShared.push_back(std::make_shared<DBEvent>(event));
123 }
123 }
124 return eventsShared;
124 return eventsShared;
125 }
125 }
126
126
127 std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const
127 std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const
128 {
128 {
129 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
129 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
130 for (auto repository : impl->m_RepositoryList) {
130 for (auto repository : impl->m_RepositoryList) {
131 eventsShared.splice(eventsShared.end(), retrieveEvents(repository));
131 eventsShared.splice(eventsShared.end(), retrieveEvents(repository));
132 }
132 }
133
133
134 return eventsShared;
134 return eventsShared;
135 }
135 }
136
136
137 std::list<std::shared_ptr<DBEvent> >
137 std::list<std::shared_ptr<DBEvent> >
138 CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const
138 CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const
139 {
139 {
140 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
140 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
141 auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue);
141 auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue);
142 for (auto event : events) {
142 for (auto event : events) {
143 eventsShared.push_back(std::make_shared<DBEvent>(event));
143 eventsShared.push_back(std::make_shared<DBEvent>(event));
144 }
144 }
145 return eventsShared;
145 return eventsShared;
146 }
146 }
147
147
148 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
148 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
149 {
149 {
150 event->setRepository(impl->toWorkRepository(event->getRepository()));
150 event->setRepository(impl->toWorkRepository(event->getRepository()));
151
151
152 auto uniqueId = impl->eventUniqueKey(event);
152 auto uniqueId = impl->eventUniqueKey(event);
153 impl->m_KeysWithChanges.insert(uniqueId);
153 impl->m_KeysWithChanges.insert(uniqueId);
154
154
155 impl->m_CatalogueDao.updateEvent(*event);
155 impl->m_CatalogueDao.updateEvent(*event);
156 }
156 }
157
157
158 void CatalogueController::updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct)
158 void CatalogueController::updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct)
159 {
159 {
160 impl->m_CatalogueDao.updateEventProduct(*eventProduct);
160 impl->m_CatalogueDao.updateEventProduct(*eventProduct);
161 }
161 }
162
162
163 void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event)
163 void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event)
164 {
164 {
165 // Remove it from both repository and repository_work
165 // Remove it from both repository and repository_work
166 event->setRepository(impl->toWorkRepository(event->getRepository()));
166 event->setRepository(impl->toWorkRepository(event->getRepository()));
167 impl->m_CatalogueDao.removeEvent(*event);
167 impl->m_CatalogueDao.removeEvent(*event);
168 event->setRepository(impl->toSyncRepository(event->getRepository()));
168 event->setRepository(impl->toSyncRepository(event->getRepository()));
169 impl->m_CatalogueDao.removeEvent(*event);
169 impl->m_CatalogueDao.removeEvent(*event);
170 impl->savAllDB();
170 impl->savAllDB();
171 }
171 }
172
172
173 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
173 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
174 {
174 {
175 event->setRepository(impl->toWorkRepository(event->getRepository()));
175 event->setRepository(impl->toWorkRepository(event->getRepository()));
176
176
177 auto eventTemp = *event;
177 auto eventTemp = *event;
178 impl->m_CatalogueDao.addEvent(eventTemp);
178 impl->m_CatalogueDao.addEvent(eventTemp);
179
179
180 // Call update is necessary at the creation of add Event if it has some tags or some event
180 // Call update is necessary at the creation of add Event if it has some tags or some event
181 // products
181 // products
182 if (!event->getEventProducts().empty() || !event->getTags().empty()) {
182 if (!event->getEventProducts().empty() || !event->getTags().empty()) {
183
183
184 auto eventProductsTemp = eventTemp.getEventProducts();
184 auto eventProductsTemp = eventTemp.getEventProducts();
185 auto eventProductTempUpdated = std::list<DBEventProduct>{};
185 auto eventProductTempUpdated = std::list<DBEventProduct>{};
186 for (auto eventProductTemp : eventProductsTemp) {
186 for (auto eventProductTemp : eventProductsTemp) {
187 eventProductTemp.setEvent(eventTemp);
187 eventProductTemp.setEvent(eventTemp);
188 eventProductTempUpdated.push_back(eventProductTemp);
188 eventProductTempUpdated.push_back(eventProductTemp);
189 }
189 }
190 eventTemp.setEventProducts(eventProductTempUpdated);
190 eventTemp.setEventProducts(eventProductTempUpdated);
191
191
192 impl->m_CatalogueDao.updateEvent(eventTemp);
192 impl->m_CatalogueDao.updateEvent(eventTemp);
193 }
193 }
194
194
195 auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK);
195 auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK);
196
196
197 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
197 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
198 *event = workEvent;
198 *event = workEvent;
199
199
200
200
201 auto uniqueId = impl->eventUniqueKey(event);
201 auto uniqueId = impl->eventUniqueKey(event);
202 impl->m_KeysWithChanges.insert(uniqueId);
202 impl->m_KeysWithChanges.insert(uniqueId);
203 }
203 }
204
204
205 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
205 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
206 {
206 {
207 impl->saveEvent(event, true);
207 impl->saveEvent(event, true);
208 impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event));
208 impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event));
209 }
209 }
210
210
211 void CatalogueController::discardEvent(std::shared_ptr<DBEvent> event, bool &removed)
211 void CatalogueController::discardEvent(std::shared_ptr<DBEvent> event, bool &removed)
212 {
212 {
213 auto syncPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::SYNC);
213 auto syncPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::SYNC);
214 auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK);
214 auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK);
215
215
216 auto syncEvent = impl->m_CatalogueDao.getEvent(syncPred);
216 auto syncEvent = impl->m_CatalogueDao.getEvent(syncPred);
217 if (!syncEvent.getUniqId().isNull()) {
217 if (!syncEvent.getUniqId().isNull()) {
218 removed = false;
218 removed = false;
219 impl->m_CatalogueDao.copyEvent(syncEvent, impl->toWorkRepository(event->getRepository()),
219 impl->m_CatalogueDao.copyEvent(syncEvent, impl->toWorkRepository(event->getRepository()),
220 true);
220 true);
221
221
222 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
222 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
223 *event = workEvent;
223 *event = workEvent;
224 impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event));
224 impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event));
225 }
225 }
226 else {
226 else {
227 removed = true;
227 removed = true;
228 // Since the element wasn't in sync repository. Discard it means remove it
228 // Since the element wasn't in sync repository. Discard it means remove it
229 event->setRepository(impl->toWorkRepository(event->getRepository()));
229 event->setRepository(impl->toWorkRepository(event->getRepository()));
230 impl->m_CatalogueDao.removeEvent(*event);
230 impl->m_CatalogueDao.removeEvent(*event);
231 }
231 }
232 }
232 }
233
233
234 bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const
234 bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const
235 {
235 {
236 return impl->m_KeysWithChanges.contains(impl->eventUniqueKey(event));
236 return impl->m_KeysWithChanges.contains(impl->eventUniqueKey(event));
237 }
237 }
238
238
239 std::list<std::shared_ptr<DBCatalogue> >
239 std::list<std::shared_ptr<DBCatalogue> >
240 CatalogueController::retrieveCatalogues(const QString &repository) const
240 CatalogueController::retrieveCatalogues(const QString &repository) const
241 {
241 {
242 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
242 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
243
243
244 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
244 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
245 auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName));
245 auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName));
246 for (auto catalogue : catalogues) {
246 for (auto catalogue : catalogues) {
247 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
247 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
248 }
248 }
249 return cataloguesShared;
249 return cataloguesShared;
250 }
250 }
251
251
252 void CatalogueController::addCatalogue(std::shared_ptr<DBCatalogue> catalogue)
252 void CatalogueController::addCatalogue(std::shared_ptr<DBCatalogue> catalogue)
253 {
253 {
254 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
254 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
255
255
256 auto catalogueTemp = *catalogue;
256 auto catalogueTemp = *catalogue;
257 impl->m_CatalogueDao.addCatalogue(catalogueTemp);
257 impl->m_CatalogueDao.addCatalogue(catalogueTemp);
258
258
259 auto workPred
259 auto workPred
260 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK);
260 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK);
261
261
262 auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred);
262 auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred);
263 *catalogue = workCatalogue;
263 *catalogue = workCatalogue;
264
264
265 auto uniqueId = impl->catalogueUniqueKey(catalogue);
265 auto uniqueId = impl->catalogueUniqueKey(catalogue);
266 impl->m_KeysWithChanges.insert(uniqueId);
266 impl->m_KeysWithChanges.insert(uniqueId);
267 }
267 }
268
268
269 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
269 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
270 {
270 {
271 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
271 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
272
272
273 auto uniqueId = impl->catalogueUniqueKey(catalogue);
273 auto uniqueId = impl->catalogueUniqueKey(catalogue);
274 impl->m_KeysWithChanges.insert(uniqueId);
274 impl->m_KeysWithChanges.insert(uniqueId);
275
275
276 impl->m_CatalogueDao.updateCatalogue(*catalogue);
276 impl->m_CatalogueDao.updateCatalogue(*catalogue);
277 }
277 }
278
278
279 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue)
279 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue)
280 {
280 {
281 // Remove it from both repository and repository_work
281 // Remove it from both repository and repository_work
282 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
282 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
283 impl->m_CatalogueDao.removeCatalogue(*catalogue);
283 impl->m_CatalogueDao.removeCatalogue(*catalogue);
284 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
284 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
285 impl->m_CatalogueDao.removeCatalogue(*catalogue);
285 impl->m_CatalogueDao.removeCatalogue(*catalogue);
286 impl->savAllDB();
286 impl->savAllDB();
287 }
287 }
288
288
289 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
289 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
290 {
290 {
291 impl->saveCatalogue(catalogue, true);
291 impl->saveCatalogue(catalogue, true);
292 impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue));
292 impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue));
293 }
293 }
294
294
295 void CatalogueController::discardCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool &removed)
295 void CatalogueController::discardCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool &removed)
296 {
296 {
297 auto syncPred
297 auto syncPred
298 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::SYNC);
298 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::SYNC);
299 auto workPred
299 auto workPred
300 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK);
300 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK);
301
301
302 auto syncCatalogue = impl->m_CatalogueDao.getCatalogue(syncPred);
302 auto syncCatalogue = impl->m_CatalogueDao.getCatalogue(syncPred);
303 if (!syncCatalogue.getUniqId().isNull()) {
303 if (!syncCatalogue.getUniqId().isNull()) {
304 removed = false;
304 removed = false;
305 impl->m_CatalogueDao.copyCatalogue(
305 impl->m_CatalogueDao.copyCatalogue(
306 syncCatalogue, impl->toWorkRepository(catalogue->getRepository()), true);
306 syncCatalogue, impl->toWorkRepository(catalogue->getRepository()), true);
307
307
308 auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred);
308 auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred);
309 *catalogue = workCatalogue;
309 *catalogue = workCatalogue;
310 impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue));
310 impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue));
311 }
311 }
312 else {
312 else {
313 removed = true;
313 removed = true;
314 // Since the element wasn't in sync repository. Discard it means remove it
314 // Since the element wasn't in sync repository. Discard it means remove it
315 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
315 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
316 impl->m_CatalogueDao.removeCatalogue(*catalogue);
316 impl->m_CatalogueDao.removeCatalogue(*catalogue);
317 }
317 }
318 }
318 }
319
319
320 void CatalogueController::saveAll()
320 void CatalogueController::saveAll()
321 {
321 {
322 for (auto repository : impl->m_RepositoryList) {
322 for (auto repository : impl->m_RepositoryList) {
323 // Save Event
323 // Save Event
324 auto events = this->retrieveEvents(repository);
324 auto events = this->retrieveEvents(repository);
325 for (auto event : events) {
325 for (auto event : events) {
326 impl->saveEvent(event, false);
326 impl->saveEvent(event, false);
327 }
327 }
328
328
329 // Save Catalogue
329 // Save Catalogue
330 auto catalogues = this->retrieveCatalogues(repository);
330 auto catalogues = this->retrieveCatalogues(repository);
331 for (auto catalogue : catalogues) {
331 for (auto catalogue : catalogues) {
332 impl->saveCatalogue(catalogue, false);
332 impl->saveCatalogue(catalogue, false);
333 }
333 }
334 }
334 }
335
335
336 impl->savAllDB();
336 impl->savAllDB();
337 impl->m_KeysWithChanges.clear();
337 impl->m_KeysWithChanges.clear();
338 }
338 }
339
339
340 bool CatalogueController::hasChanges() const
340 bool CatalogueController::hasChanges() const
341 {
341 {
342 return !impl->m_KeysWithChanges.isEmpty();
342 return !impl->m_KeysWithChanges.isEmpty();
343 }
343 }
344
344
345 QByteArray
345 QByteArray
346 CatalogueController::mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const
346 CatalogueController::mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const
347 {
347 {
348 auto encodedData = QByteArray{};
348 auto encodedData = QByteArray{};
349
349
350 QMap<QString, QVariantList> idsPerRepository;
350 QMap<QString, QVariantList> idsPerRepository;
351 for (auto event : events) {
351 for (auto event : events) {
352 idsPerRepository[event->getRepository()] << event->getUniqId();
352 idsPerRepository[event->getRepository()] << event->getUniqId();
353 }
353 }
354
354
355 QDataStream stream{&encodedData, QIODevice::WriteOnly};
355 QDataStream stream{&encodedData, QIODevice::WriteOnly};
356 stream << idsPerRepository;
356 stream << idsPerRepository;
357
357
358 return encodedData;
358 return encodedData;
359 }
359 }
360
360
361 QVector<std::shared_ptr<DBEvent> >
361 QVector<std::shared_ptr<DBEvent> >
362 CatalogueController::eventsForMimeData(const QByteArray &mimeData) const
362 CatalogueController::eventsForMimeData(const QByteArray &mimeData) const
363 {
363 {
364 auto events = QVector<std::shared_ptr<DBEvent> >{};
364 auto events = QVector<std::shared_ptr<DBEvent> >{};
365 QDataStream stream{mimeData};
365 QDataStream stream{mimeData};
366
366
367 QMap<QString, QVariantList> idsPerRepository;
367 QMap<QString, QVariantList> idsPerRepository;
368 stream >> idsPerRepository;
368 stream >> idsPerRepository;
369
369
370 for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) {
370 for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) {
371 auto repository = it.key();
371 auto repository = it.key();
372 auto allRepositoryEvent = retrieveEvents(repository);
372 auto allRepositoryEvent = retrieveEvents(repository);
373 for (auto uuid : it.value()) {
373 for (auto uuid : it.value()) {
374 for (auto repositoryEvent : allRepositoryEvent) {
374 for (auto repositoryEvent : allRepositoryEvent) {
375 if (uuid.toUuid() == repositoryEvent->getUniqId()) {
375 if (uuid.toUuid() == repositoryEvent->getUniqId()) {
376 events << repositoryEvent;
376 events << repositoryEvent;
377 }
377 }
378 }
378 }
379 }
379 }
380 }
380 }
381
381
382 return events;
382 return events;
383 }
383 }
384
384
385 QByteArray CatalogueController::mimeDataForCatalogues(
386 const QVector<std::shared_ptr<DBCatalogue> > &catalogues) const
387 {
388 auto encodedData = QByteArray{};
389
390 QMap<QString, QVariantList> idsPerRepository;
391 for (auto catalogue : catalogues) {
392 idsPerRepository[catalogue->getRepository()] << catalogue->getUniqId();
393 }
394
395 QDataStream stream{&encodedData, QIODevice::WriteOnly};
396 stream << idsPerRepository;
397
398 return encodedData;
399 }
400
401 QVector<std::shared_ptr<DBCatalogue> >
402 CatalogueController::cataloguesForMimeData(const QByteArray &mimeData) const
403 {
404 auto catalogues = QVector<std::shared_ptr<DBCatalogue> >{};
405 QDataStream stream{mimeData};
406
407 QMap<QString, QVariantList> idsPerRepository;
408 stream >> idsPerRepository;
409
410 for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) {
411 auto repository = it.key();
412 auto allRepositoryCatalogues = retrieveCatalogues(repository);
413 for (auto uuid : it.value()) {
414 for (auto repositoryCatalogues : allRepositoryCatalogues) {
415 if (uuid.toUuid() == repositoryCatalogues->getUniqId()) {
416 catalogues << repositoryCatalogues;
417 }
418 }
419 }
420 }
421
422 return catalogues;
423 }
424
385 void CatalogueController::initialize()
425 void CatalogueController::initialize()
386 {
426 {
387 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
427 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
388 << QThread::currentThread();
428 << QThread::currentThread();
389
429
390 impl->m_CatalogueDao.initialize();
430 impl->m_CatalogueDao.initialize();
391 auto defaultRepositoryLocation
431 auto defaultRepositoryLocation
392 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
432 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
393
433
394 QDir defaultRepositoryLocationDir;
434 QDir defaultRepositoryLocationDir;
395 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
435 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
396 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
436 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
397 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
437 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
398
438
399 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
439 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
400 << defaultRepository;
440 << defaultRepository;
401
441
402 QDir dbDir(defaultRepository);
442 QDir dbDir(defaultRepository);
403 impl->m_RepositoryList << REPOSITORY_DEFAULT;
443 impl->m_RepositoryList << REPOSITORY_DEFAULT;
404 if (dbDir.exists()) {
444 if (dbDir.exists()) {
405 auto dirName = dbDir.dirName();
445 auto dirName = dbDir.dirName();
406
446
407 if (impl->m_CatalogueDao.addDB(defaultRepository, dirName)) {
447 if (impl->m_CatalogueDao.addDB(defaultRepository, dirName)) {
408 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
448 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
409 }
449 }
410 }
450 }
411 else {
451 else {
412 qCInfo(LOG_CatalogueController()) << tr("Initialisation of Default repository detected")
452 qCInfo(LOG_CatalogueController()) << tr("Initialisation of Default repository detected")
413 << defaultRepository;
453 << defaultRepository;
414 }
454 }
415 }
455 }
416 else {
456 else {
417 qCWarning(LOG_CatalogueController())
457 qCWarning(LOG_CatalogueController())
418 << tr("Cannot load the persistent default repository from ")
458 << tr("Cannot load the persistent default repository from ")
419 << defaultRepositoryLocation;
459 << defaultRepositoryLocation;
420 }
460 }
421
461
422 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END");
462 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END");
423 }
463 }
424
464
425 QString CatalogueController::CatalogueControllerPrivate::eventUniqueKey(
465 QString CatalogueController::CatalogueControllerPrivate::eventUniqueKey(
426 const std::shared_ptr<DBEvent> &event) const
466 const std::shared_ptr<DBEvent> &event) const
427 {
467 {
428 return event->getUniqId().toString().append(event->getRepository());
468 return event->getUniqId().toString().append(event->getRepository());
429 }
469 }
430
470
431 QString CatalogueController::CatalogueControllerPrivate::catalogueUniqueKey(
471 QString CatalogueController::CatalogueControllerPrivate::catalogueUniqueKey(
432 const std::shared_ptr<DBCatalogue> &catalogue) const
472 const std::shared_ptr<DBCatalogue> &catalogue) const
433 {
473 {
434 return catalogue->getUniqId().toString().append(catalogue->getRepository());
474 return catalogue->getUniqId().toString().append(catalogue->getRepository());
435 }
475 }
436
476
437 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
477 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
438 const QString &dbTo)
478 const QString &dbTo)
439 {
479 {
440 // auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
480 // auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
441 auto catalogues = m_CatalogueDao.getCatalogues(dbFrom);
481 auto catalogues = m_CatalogueDao.getCatalogues(dbFrom);
442 auto events = m_CatalogueDao.getEvents(dbFrom);
482 auto events = m_CatalogueDao.getEvents(dbFrom);
443 for (auto catalogue : catalogues) {
483 for (auto catalogue : catalogues) {
444 m_CatalogueDao.copyCatalogue(catalogue, dbTo, true);
484 m_CatalogueDao.copyCatalogue(catalogue, dbTo, true);
445 }
485 }
446
486
447 for (auto event : events) {
487 for (auto event : events) {
448 m_CatalogueDao.copyEvent(event, dbTo, true);
488 m_CatalogueDao.copyEvent(event, dbTo, true);
449 }
489 }
450 }
490 }
451
491
452 QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository)
492 QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository)
453 {
493 {
454 auto syncRepository = toSyncRepository(repository);
494 auto syncRepository = toSyncRepository(repository);
455
495
456 return QString("%1%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX);
496 return QString("%1%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX);
457 }
497 }
458
498
459 QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository)
499 QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository)
460 {
500 {
461 auto syncRepository = repository;
501 auto syncRepository = repository;
462 if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) {
502 if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) {
463 syncRepository.remove(REPOSITORY_WORK_SUFFIX);
503 syncRepository.remove(REPOSITORY_WORK_SUFFIX);
464 }
504 }
465 else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) {
505 else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) {
466 syncRepository.remove(REPOSITORY_TRASH_SUFFIX);
506 syncRepository.remove(REPOSITORY_TRASH_SUFFIX);
467 }
507 }
468 return syncRepository;
508 return syncRepository;
469 }
509 }
470
510
471 void CatalogueController::CatalogueControllerPrivate::savAllDB()
511 void CatalogueController::CatalogueControllerPrivate::savAllDB()
472 {
512 {
473 for (auto repository : m_RepositoryList) {
513 for (auto repository : m_RepositoryList) {
474 auto defaultRepositoryLocation
514 auto defaultRepositoryLocation
475 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
515 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
476 m_CatalogueDao.saveDB(defaultRepositoryLocation, repository);
516 m_CatalogueDao.saveDB(defaultRepositoryLocation, repository);
477 }
517 }
478 }
518 }
479
519
480 void CatalogueController::CatalogueControllerPrivate::saveEvent(std::shared_ptr<DBEvent> event,
520 void CatalogueController::CatalogueControllerPrivate::saveEvent(std::shared_ptr<DBEvent> event,
481 bool persist)
521 bool persist)
482 {
522 {
483 m_CatalogueDao.copyEvent(*event, toSyncRepository(event->getRepository()), true);
523 m_CatalogueDao.copyEvent(*event, toSyncRepository(event->getRepository()), true);
484 if (persist) {
524 if (persist) {
485 savAllDB();
525 savAllDB();
486 }
526 }
487 }
527 }
488
528
489 void CatalogueController::CatalogueControllerPrivate::saveCatalogue(
529 void CatalogueController::CatalogueControllerPrivate::saveCatalogue(
490 std::shared_ptr<DBCatalogue> catalogue, bool persist)
530 std::shared_ptr<DBCatalogue> catalogue, bool persist)
491 {
531 {
492 m_CatalogueDao.copyCatalogue(*catalogue, toSyncRepository(catalogue->getRepository()), true);
532 m_CatalogueDao.copyCatalogue(*catalogue, toSyncRepository(catalogue->getRepository()), true);
493 if (persist) {
533 if (persist) {
494 savAllDB();
534 savAllDB();
495 }
535 }
496 }
536 }
497
537
498 std::shared_ptr<IRequestPredicate> CatalogueController::CatalogueControllerPrivate::createFinder(
538 std::shared_ptr<IRequestPredicate> CatalogueController::CatalogueControllerPrivate::createFinder(
499 const QUuid &uniqId, const QString &repository, DBType type)
539 const QUuid &uniqId, const QString &repository, DBType type)
500 {
540 {
501 // update catalogue parameter
541 // update catalogue parameter
502 auto uniqIdPredicate = std::make_shared<ComparaisonPredicate>(QString{"uniqId"}, uniqId,
542 auto uniqIdPredicate = std::make_shared<ComparaisonPredicate>(QString{"uniqId"}, uniqId,
503 ComparaisonOperation::EQUALEQUAL);
543 ComparaisonOperation::EQUALEQUAL);
504
544
505 auto repositoryType = repository;
545 auto repositoryType = repository;
506 switch (type) {
546 switch (type) {
507 case DBType::SYNC:
547 case DBType::SYNC:
508 repositoryType = toSyncRepository(repositoryType);
548 repositoryType = toSyncRepository(repositoryType);
509 break;
549 break;
510 case DBType::WORK:
550 case DBType::WORK:
511 repositoryType = toWorkRepository(repositoryType);
551 repositoryType = toWorkRepository(repositoryType);
512 break;
552 break;
513 case DBType::TRASH:
553 case DBType::TRASH:
514 default:
554 default:
515 break;
555 break;
516 }
556 }
517
557
518 auto repositoryPredicate = std::make_shared<ComparaisonPredicate>(
558 auto repositoryPredicate = std::make_shared<ComparaisonPredicate>(
519 QString{"repository"}, repositoryType, ComparaisonOperation::EQUALEQUAL);
559 QString{"repository"}, repositoryType, ComparaisonOperation::EQUALEQUAL);
520
560
521 auto finderPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
561 auto finderPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
522 finderPred->AddRequestPredicate(uniqIdPredicate);
562 finderPred->AddRequestPredicate(uniqIdPredicate);
523 finderPred->AddRequestPredicate(repositoryPredicate);
563 finderPred->AddRequestPredicate(repositoryPredicate);
524
564
525 return finderPred;
565 return finderPred;
526 }
566 }
@@ -1,9 +1,10
1 #include "Common/MimeTypesDef.h"
1 #include "Common/MimeTypesDef.h"
2
2
3 const QString MIME_TYPE_GRAPH = QStringLiteral("sciqlop/graph");
3 const QString MIME_TYPE_GRAPH = QStringLiteral("sciqlop/graph");
4 const QString MIME_TYPE_ZONE = QStringLiteral("sciqlop/zone");
4 const QString MIME_TYPE_ZONE = QStringLiteral("sciqlop/zone");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list");
6 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
6 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
8 const QString MIME_TYPE_SELECTION_ZONE = QStringLiteral("sciqlop/selection-zone");
8 const QString MIME_TYPE_SELECTION_ZONE = QStringLiteral("sciqlop/selection-zone");
9 const QString MIME_TYPE_EVENT_LIST = QStringLiteral("sciqlop/event-list");
9 const QString MIME_TYPE_EVENT_LIST = QStringLiteral("sciqlop/event-list");
10 const QString MIME_TYPE_SOURCE_CATALOGUE_LIST = QStringLiteral("sciqlop/source-catalogue-list");
@@ -1,68 +1,70
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 DBCatalogue;
9 class DBEvent;
10 class DBEvent;
10 class DBEventProduct;
11 class DBEventProduct;
11
12
12 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsModel)
13 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsModel)
13
14
14 class CatalogueEventsModel : public QAbstractItemModel {
15 class CatalogueEventsModel : public QAbstractItemModel {
15 Q_OBJECT
16 Q_OBJECT
16
17
17 signals:
18 signals:
18 void modelSorted();
19 void modelSorted();
19
20
20 public:
21 public:
21 CatalogueEventsModel(QObject *parent = nullptr);
22 CatalogueEventsModel(QObject *parent = nullptr);
22
23
23 enum class Column { Name, TStart, TEnd, Tags, Product, Validation, NbColumn };
24 enum class Column { Name, TStart, TEnd, Tags, Product, Validation, NbColumn };
24
25
26 void setSourceCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
25 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events);
27 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events);
26 void addEvent(const std::shared_ptr<DBEvent> &event);
28 void addEvent(const std::shared_ptr<DBEvent> &event);
27 void removeEvent(const std::shared_ptr<DBEvent> &event);
29 void removeEvent(const std::shared_ptr<DBEvent> &event);
28 QVector<std::shared_ptr<DBEvent> > events() const;
30 QVector<std::shared_ptr<DBEvent> > events() const;
29
31
30 enum class ItemType { Root, Event, EventProduct };
32 enum class ItemType { Root, Event, EventProduct };
31 ItemType itemTypeOf(const QModelIndex &index) const;
33 ItemType itemTypeOf(const QModelIndex &index) const;
32 std::shared_ptr<DBEvent> getEvent(const QModelIndex &index) const;
34 std::shared_ptr<DBEvent> getEvent(const QModelIndex &index) const;
33 std::shared_ptr<DBEvent> getParentEvent(const QModelIndex &index) const;
35 std::shared_ptr<DBEvent> getParentEvent(const QModelIndex &index) const;
34 std::shared_ptr<DBEventProduct> getEventProduct(const QModelIndex &index) const;
36 std::shared_ptr<DBEventProduct> getEventProduct(const QModelIndex &index) const;
35
37
36 /// Refresh the data for the specified event
38 /// Refresh the data for the specified event
37 void refreshEvent(const std::shared_ptr<DBEvent> &event, bool refreshEventProducts = false);
39 void refreshEvent(const std::shared_ptr<DBEvent> &event, bool refreshEventProducts = false);
38
40
39 /// Returns a QModelIndex which represent the specified event
41 /// Returns a QModelIndex which represent the specified event
40 QModelIndex indexOf(const std::shared_ptr<DBEvent> &event) const;
42 QModelIndex indexOf(const std::shared_ptr<DBEvent> &event) const;
41
43
42 /// Marks a change flag on the specified event to allow sorting on the validation column
44 /// 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);
45 void setEventHasChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
44
46
45 /// Returns true if the specified event has unsaved changes
47 /// Returns true if the specified event has unsaved changes
46 bool eventsHasChanges(const std::shared_ptr<DBEvent> &event) const;
48 bool eventsHasChanges(const std::shared_ptr<DBEvent> &event) const;
47
49
48 // Model
50 // Model
49 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
51 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
50 QModelIndex parent(const QModelIndex &index) const;
52 QModelIndex parent(const QModelIndex &index) const;
51 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
53 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
52 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
54 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
53 Qt::ItemFlags flags(const QModelIndex &index) const override;
55 Qt::ItemFlags flags(const QModelIndex &index) const override;
54 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
56 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
55 QVariant headerData(int section, Qt::Orientation orientation,
57 QVariant headerData(int section, Qt::Orientation orientation,
56 int role = Qt::DisplayRole) const override;
58 int role = Qt::DisplayRole) const override;
57 void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
59 void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
58
60
59 Qt::DropActions supportedDragActions() const override;
61 Qt::DropActions supportedDragActions() const override;
60 QStringList mimeTypes() const override;
62 QStringList mimeTypes() const override;
61 QMimeData *mimeData(const QModelIndexList &indexes) const override;
63 QMimeData *mimeData(const QModelIndexList &indexes) const override;
62
64
63 private:
65 private:
64 class CatalogueEventsModelPrivate;
66 class CatalogueEventsModelPrivate;
65 spimpl::unique_impl_ptr<CatalogueEventsModelPrivate> impl;
67 spimpl::unique_impl_ptr<CatalogueEventsModelPrivate> impl;
66 };
68 };
67
69
68 #endif // SCIQLOP_CATALOGUEEVENTSMODEL_H
70 #endif // SCIQLOP_CATALOGUEEVENTSMODEL_H
@@ -1,59 +1,59
1 #ifndef SCIQLOP_CATALOGUETREEMODEL_H
1 #ifndef SCIQLOP_CATALOGUETREEMODEL_H
2 #define SCIQLOP_CATALOGUETREEMODEL_H
2 #define SCIQLOP_CATALOGUETREEMODEL_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QAbstractItemModel>
5 #include <QAbstractItemModel>
6
6
7 class CatalogueAbstractTreeItem;
7 class CatalogueAbstractTreeItem;
8
8
9 /**
9 /**
10 * @brief Model to display catalogue items based on QTreeWidgetItem
10 * @brief Model to display catalogue items based on QTreeWidgetItem
11 * @warning Do not use the method QTreeWidgetItem::treeWidget for an item added to this model or the
11 * @warning Do not use the method QTreeWidgetItem::treeWidget for an item added to this model or the
12 * application will crash
12 * application will crash
13 */
13 */
14 class CatalogueTreeModel : public QAbstractItemModel {
14 class CatalogueTreeModel : public QAbstractItemModel {
15 Q_OBJECT
15 Q_OBJECT
16
16
17 signals:
17 signals:
18 void itemRenamed(const QModelIndex &index);
18 void itemRenamed(const QModelIndex &index);
19 void itemDropped(const QModelIndex &parentIndex);
19 void itemDropped(const QModelIndex &parentIndex, const QMimeData *data, Qt::DropAction action);
20
20
21 public:
21 public:
22 CatalogueTreeModel(QObject *parent = nullptr);
22 CatalogueTreeModel(QObject *parent = nullptr);
23
23
24 enum class Column { Name, Validation, Count };
24 enum class Column { Name, Validation, Count };
25
25
26 QModelIndex addTopLevelItem(CatalogueAbstractTreeItem *item);
26 QModelIndex addTopLevelItem(CatalogueAbstractTreeItem *item);
27 QVector<CatalogueAbstractTreeItem *> topLevelItems() const;
27 QVector<CatalogueAbstractTreeItem *> topLevelItems() const;
28
28
29 void addChildItem(CatalogueAbstractTreeItem *child, const QModelIndex &parentIndex);
29 void addChildItem(CatalogueAbstractTreeItem *child, const QModelIndex &parentIndex);
30 void removeChildItem(CatalogueAbstractTreeItem *child, const QModelIndex &parentIndex);
30 void removeChildItem(CatalogueAbstractTreeItem *child, const QModelIndex &parentIndex);
31 /// Refresh the data for the specified index
31 /// Refresh the data for the specified index
32 void refresh(const QModelIndex &index);
32 void refresh(const QModelIndex &index);
33
33
34 CatalogueAbstractTreeItem *item(const QModelIndex &index) const;
34 CatalogueAbstractTreeItem *item(const QModelIndex &index) const;
35 QModelIndex indexOf(CatalogueAbstractTreeItem *item, int column = 0) const;
35 QModelIndex indexOf(CatalogueAbstractTreeItem *item, int column = 0) const;
36
36
37 // model
37 // model
38 QModelIndex index(int row, int column,
38 QModelIndex index(int row, int column,
39 const QModelIndex &parent = QModelIndex()) const override;
39 const QModelIndex &parent = QModelIndex()) const override;
40 QModelIndex parent(const QModelIndex &index) const override;
40 QModelIndex parent(const QModelIndex &index) const override;
41 int rowCount(const QModelIndex &parent) const override;
41 int rowCount(const QModelIndex &parent) const override;
42 int columnCount(const QModelIndex &parent) const override;
42 int columnCount(const QModelIndex &parent) const override;
43 Qt::ItemFlags flags(const QModelIndex &index) const override;
43 Qt::ItemFlags flags(const QModelIndex &index) const override;
44 QVariant data(const QModelIndex &index, int role) const override;
44 QVariant data(const QModelIndex &index, int role) const override;
45 bool setData(const QModelIndex &index, const QVariant &value, int role) override;
45 bool setData(const QModelIndex &index, const QVariant &value, int role) override;
46
46
47 bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
47 bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
48 const QModelIndex &parent) const override;
48 const QModelIndex &parent) const override;
49 bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
49 bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
50 const QModelIndex &parent) override;
50 const QModelIndex &parent) override;
51 Qt::DropActions supportedDropActions() const;
51 Qt::DropActions supportedDropActions() const;
52 QStringList mimeTypes() const;
52 QStringList mimeTypes() const;
53
53
54 private:
54 private:
55 class CatalogueTreeModelPrivate;
55 class CatalogueTreeModelPrivate;
56 spimpl::unique_impl_ptr<CatalogueTreeModelPrivate> impl;
56 spimpl::unique_impl_ptr<CatalogueTreeModelPrivate> impl;
57 };
57 };
58
58
59 #endif // CATALOGUETREEMODEL_H
59 #endif // CATALOGUETREEMODEL_H
@@ -1,461 +1,472
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 QVector<std::shared_ptr<DBCatalogue> > m_SourceCatalogue;
27
28
28 QStringList columnNames()
29 QStringList columnNames()
29 {
30 {
30 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"),
31 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"),
31 tr("Tags"), tr("Product"), tr("")};
32 tr("Tags"), tr("Product"), tr("")};
32 }
33 }
33
34
34 QVariant sortData(int col, const std::shared_ptr<DBEvent> &event) const
35 QVariant sortData(int col, const std::shared_ptr<DBEvent> &event) const
35 {
36 {
36 if (col == (int)CatalogueEventsModel::Column::Validation) {
37 if (col == (int)CatalogueEventsModel::Column::Validation) {
37 auto hasChanges = sqpApp->catalogueController().eventHasChanges(event);
38 auto hasChanges = sqpApp->catalogueController().eventHasChanges(event);
38 return hasChanges ? true : QVariant();
39 return hasChanges ? true : QVariant();
39 }
40 }
40
41
41 return eventData(col, event);
42 return eventData(col, event);
42 }
43 }
43
44
44 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
45 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
45 {
46 {
46 switch (static_cast<Column>(col)) {
47 switch (static_cast<Column>(col)) {
47 case CatalogueEventsModel::Column::Name:
48 case CatalogueEventsModel::Column::Name:
48 return event->getName();
49 return event->getName();
49 case CatalogueEventsModel::Column::TStart:
50 case CatalogueEventsModel::Column::TStart:
50 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTStart())
51 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTStart())
51 : QVariant{};
52 : QVariant{};
52 case CatalogueEventsModel::Column::TEnd:
53 case CatalogueEventsModel::Column::TEnd:
53 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTEnd())
54 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTEnd())
54 : QVariant{};
55 : QVariant{};
55 case CatalogueEventsModel::Column::Product:
56 case CatalogueEventsModel::Column::Product:
56 return QString::number(nbEventProducts(event)) + " product(s)";
57 return QString::number(nbEventProducts(event)) + " product(s)";
57 case CatalogueEventsModel::Column::Tags: {
58 case CatalogueEventsModel::Column::Tags: {
58 QString tagList;
59 QString tagList;
59 auto tags = event->getTags();
60 auto tags = event->getTags();
60 for (auto tag : tags) {
61 for (auto tag : tags) {
61 tagList += tag.getName();
62 tagList += tag.getName();
62 tagList += ' ';
63 tagList += ' ';
63 }
64 }
64
65
65 return tagList;
66 return tagList;
66 }
67 }
67 case CatalogueEventsModel::Column::Validation:
68 case CatalogueEventsModel::Column::Validation:
68 return QVariant();
69 return QVariant();
69 default:
70 default:
70 break;
71 break;
71 }
72 }
72
73
73 Q_ASSERT(false);
74 Q_ASSERT(false);
74 return QStringLiteral("Unknown Data");
75 return QStringLiteral("Unknown Data");
75 }
76 }
76
77
77 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
78 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
78 {
79 {
79 for (auto product : event->getEventProducts()) {
80 for (auto product : event->getEventProducts()) {
80 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
81 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
81 }
82 }
82 }
83 }
83
84
84 int nbEventProducts(const std::shared_ptr<DBEvent> &event) const
85 int nbEventProducts(const std::shared_ptr<DBEvent> &event) const
85 {
86 {
86 auto eventProductsIt = m_EventProducts.find(event.get());
87 auto eventProductsIt = m_EventProducts.find(event.get());
87 if (eventProductsIt != m_EventProducts.cend()) {
88 if (eventProductsIt != m_EventProducts.cend()) {
88 return m_EventProducts.at(event.get()).count();
89 return m_EventProducts.at(event.get()).count();
89 }
90 }
90 else {
91 else {
91 return 0;
92 return 0;
92 }
93 }
93 }
94 }
94
95
95 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
96 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
96 {
97 {
97 switch (static_cast<Column>(col)) {
98 switch (static_cast<Column>(col)) {
98 case CatalogueEventsModel::Column::Name:
99 case CatalogueEventsModel::Column::Name:
99 return eventProduct->getProductId();
100 return eventProduct->getProductId();
100 case CatalogueEventsModel::Column::TStart:
101 case CatalogueEventsModel::Column::TStart:
101 return DateUtils::dateTime(eventProduct->getTStart());
102 return DateUtils::dateTime(eventProduct->getTStart());
102 case CatalogueEventsModel::Column::TEnd:
103 case CatalogueEventsModel::Column::TEnd:
103 return DateUtils::dateTime(eventProduct->getTEnd());
104 return DateUtils::dateTime(eventProduct->getTEnd());
104 case CatalogueEventsModel::Column::Product:
105 case CatalogueEventsModel::Column::Product:
105 return eventProduct->getProductId();
106 return eventProduct->getProductId();
106 case CatalogueEventsModel::Column::Tags:
107 case CatalogueEventsModel::Column::Tags:
107 return QString();
108 return QString();
108 case CatalogueEventsModel::Column::Validation:
109 case CatalogueEventsModel::Column::Validation:
109 return QVariant();
110 return QVariant();
110 default:
111 default:
111 break;
112 break;
112 }
113 }
113
114
114 Q_ASSERT(false);
115 Q_ASSERT(false);
115 return QStringLiteral("Unknown Data");
116 return QStringLiteral("Unknown Data");
116 }
117 }
117
118
118 void refreshChildrenOfIndex(CatalogueEventsModel *model, const QModelIndex &index) const
119 void refreshChildrenOfIndex(CatalogueEventsModel *model, const QModelIndex &index) const
119 {
120 {
120 auto childCount = model->rowCount(index);
121 auto childCount = model->rowCount(index);
121 auto colCount = model->columnCount();
122 auto colCount = model->columnCount();
122 emit model->dataChanged(model->index(0, 0, index),
123 emit model->dataChanged(model->index(0, 0, index),
123 model->index(childCount, colCount, index));
124 model->index(childCount, colCount, index));
124 }
125 }
125 };
126 };
126
127
127 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
128 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
128 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
129 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
129 {
130 {
130 }
131 }
131
132
133 void CatalogueEventsModel::setSourceCatalogues(
134 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
135 {
136 impl->m_SourceCatalogue = catalogues;
137 }
138
132 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
139 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
133 {
140 {
134 beginResetModel();
141 beginResetModel();
135
142
136 impl->m_Events = events;
143 impl->m_Events = events;
137 impl->m_EventProducts.clear();
144 impl->m_EventProducts.clear();
138 for (auto event : events) {
145 for (auto event : events) {
139 impl->parseEventProduct(event);
146 impl->parseEventProduct(event);
140 }
147 }
141
148
142 endResetModel();
149 endResetModel();
143 }
150 }
144
151
145 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
152 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
146 {
153 {
147 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
154 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
148 return impl->m_Events.value(index.row());
155 return impl->m_Events.value(index.row());
149 }
156 }
150 else {
157 else {
151 return nullptr;
158 return nullptr;
152 }
159 }
153 }
160 }
154
161
155 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
162 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
156 {
163 {
157 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
164 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
158 return getEvent(index.parent());
165 return getEvent(index.parent());
159 }
166 }
160 else {
167 else {
161 return nullptr;
168 return nullptr;
162 }
169 }
163 }
170 }
164
171
165 std::shared_ptr<DBEventProduct>
172 std::shared_ptr<DBEventProduct>
166 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
173 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
167 {
174 {
168 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
175 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
169 auto event = static_cast<DBEvent *>(index.internalPointer());
176 auto event = static_cast<DBEvent *>(index.internalPointer());
170 return impl->m_EventProducts.at(event).value(index.row());
177 return impl->m_EventProducts.at(event).value(index.row());
171 }
178 }
172 else {
179 else {
173 return nullptr;
180 return nullptr;
174 }
181 }
175 }
182 }
176
183
177 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
184 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
178 {
185 {
179 beginInsertRows(QModelIndex(), impl->m_Events.count(), impl->m_Events.count());
186 beginInsertRows(QModelIndex(), impl->m_Events.count(), impl->m_Events.count());
180 impl->m_Events.append(event);
187 impl->m_Events.append(event);
181 impl->parseEventProduct(event);
188 impl->parseEventProduct(event);
182 endInsertRows();
189 endInsertRows();
183
190
184 // Also refreshes its children event products
191 // Also refreshes its children event products
185 auto eventIndex = index(impl->m_Events.count(), 0);
192 auto eventIndex = index(impl->m_Events.count(), 0);
186 impl->refreshChildrenOfIndex(this, eventIndex);
193 impl->refreshChildrenOfIndex(this, eventIndex);
187 }
194 }
188
195
189 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
196 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
190 {
197 {
191 auto index = impl->m_Events.indexOf(event);
198 auto index = impl->m_Events.indexOf(event);
192 if (index >= 0) {
199 if (index >= 0) {
193 beginRemoveRows(QModelIndex(), index, index);
200 beginRemoveRows(QModelIndex(), index, index);
194 impl->m_Events.removeAt(index);
201 impl->m_Events.removeAt(index);
195 impl->m_EventProducts.erase(event.get());
202 impl->m_EventProducts.erase(event.get());
196 endRemoveRows();
203 endRemoveRows();
197 }
204 }
198 }
205 }
199
206
200 QVector<std::shared_ptr<DBEvent> > CatalogueEventsModel::events() const
207 QVector<std::shared_ptr<DBEvent> > CatalogueEventsModel::events() const
201 {
208 {
202 return impl->m_Events;
209 return impl->m_Events;
203 }
210 }
204
211
205 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event,
212 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event,
206 bool refreshEventProducts)
213 bool refreshEventProducts)
207 {
214 {
208 auto eventIndex = indexOf(event);
215 auto eventIndex = indexOf(event);
209 if (eventIndex.isValid()) {
216 if (eventIndex.isValid()) {
210
217
211 if (refreshEventProducts) {
218 if (refreshEventProducts) {
212 // Reparse the associated event products
219 // Reparse the associated event products
213
220
214 auto nbEventProducts = impl->nbEventProducts(event);
221 auto nbEventProducts = impl->nbEventProducts(event);
215 auto newNbOfEventProducts = event->getEventProducts().size();
222 auto newNbOfEventProducts = event->getEventProducts().size();
216 if (newNbOfEventProducts < nbEventProducts) {
223 if (newNbOfEventProducts < nbEventProducts) {
217 beginRemoveRows(eventIndex, newNbOfEventProducts, nbEventProducts - 1);
224 beginRemoveRows(eventIndex, newNbOfEventProducts, nbEventProducts - 1);
218 impl->m_EventProducts.erase(event.get());
225 impl->m_EventProducts.erase(event.get());
219 impl->parseEventProduct(event);
226 impl->parseEventProduct(event);
220 endRemoveRows();
227 endRemoveRows();
221 }
228 }
222 else if (newNbOfEventProducts > nbEventProducts) {
229 else if (newNbOfEventProducts > nbEventProducts) {
223 beginInsertRows(eventIndex, nbEventProducts, newNbOfEventProducts - 1);
230 beginInsertRows(eventIndex, nbEventProducts, newNbOfEventProducts - 1);
224 impl->m_EventProducts.erase(event.get());
231 impl->m_EventProducts.erase(event.get());
225 impl->parseEventProduct(event);
232 impl->parseEventProduct(event);
226 endInsertRows();
233 endInsertRows();
227 }
234 }
228 else { // newNbOfEventProducts == nbEventProducts
235 else { // newNbOfEventProducts == nbEventProducts
229 impl->m_EventProducts.erase(event.get());
236 impl->m_EventProducts.erase(event.get());
230 impl->parseEventProduct(event);
237 impl->parseEventProduct(event);
231 }
238 }
232 }
239 }
233
240
234 // Refreshes the event line
241 // Refreshes the event line
235 auto colCount = columnCount();
242 auto colCount = columnCount();
236 emit dataChanged(eventIndex, index(eventIndex.row(), colCount));
243 emit dataChanged(eventIndex, index(eventIndex.row(), colCount));
237
244
238 // Also refreshes its children event products
245 // Also refreshes its children event products
239 impl->refreshChildrenOfIndex(this, eventIndex);
246 impl->refreshChildrenOfIndex(this, eventIndex);
240 }
247 }
241 else {
248 else {
242 qCWarning(LOG_CatalogueEventsModel()) << "refreshEvent: event not found.";
249 qCWarning(LOG_CatalogueEventsModel()) << "refreshEvent: event not found.";
243 }
250 }
244 }
251 }
245
252
246 QModelIndex CatalogueEventsModel::indexOf(const std::shared_ptr<DBEvent> &event) const
253 QModelIndex CatalogueEventsModel::indexOf(const std::shared_ptr<DBEvent> &event) const
247 {
254 {
248 auto row = impl->m_Events.indexOf(event);
255 auto row = impl->m_Events.indexOf(event);
249 if (row >= 0) {
256 if (row >= 0) {
250 return index(row, 0);
257 return index(row, 0);
251 }
258 }
252
259
253 return QModelIndex();
260 return QModelIndex();
254 }
261 }
255
262
256 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
263 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
257 {
264 {
258 if (!hasIndex(row, column, parent)) {
265 if (!hasIndex(row, column, parent)) {
259 return QModelIndex();
266 return QModelIndex();
260 }
267 }
261
268
262 switch (itemTypeOf(parent)) {
269 switch (itemTypeOf(parent)) {
263 case CatalogueEventsModel::ItemType::Root:
270 case CatalogueEventsModel::ItemType::Root:
264 return createIndex(row, column);
271 return createIndex(row, column);
265 case CatalogueEventsModel::ItemType::Event: {
272 case CatalogueEventsModel::ItemType::Event: {
266 auto event = getEvent(parent);
273 auto event = getEvent(parent);
267 return createIndex(row, column, event.get());
274 return createIndex(row, column, event.get());
268 }
275 }
269 case CatalogueEventsModel::ItemType::EventProduct:
276 case CatalogueEventsModel::ItemType::EventProduct:
270 break;
277 break;
271 default:
278 default:
272 break;
279 break;
273 }
280 }
274
281
275 return QModelIndex();
282 return QModelIndex();
276 }
283 }
277
284
278 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
285 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
279 {
286 {
280 switch (itemTypeOf(index)) {
287 switch (itemTypeOf(index)) {
281 case CatalogueEventsModel::ItemType::EventProduct: {
288 case CatalogueEventsModel::ItemType::EventProduct: {
282 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
289 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
283 auto it
290 auto it
284 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
291 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
285 [parentEvent](auto event) { return event.get() == parentEvent; });
292 [parentEvent](auto event) { return event.get() == parentEvent; });
286
293
287 if (it != impl->m_Events.cend()) {
294 if (it != impl->m_Events.cend()) {
288 return createIndex(it - impl->m_Events.cbegin(), 0);
295 return createIndex(it - impl->m_Events.cbegin(), 0);
289 }
296 }
290 else {
297 else {
291 return QModelIndex();
298 return QModelIndex();
292 }
299 }
293 }
300 }
294 case CatalogueEventsModel::ItemType::Root:
301 case CatalogueEventsModel::ItemType::Root:
295 break;
302 break;
296 case CatalogueEventsModel::ItemType::Event:
303 case CatalogueEventsModel::ItemType::Event:
297 break;
304 break;
298 default:
305 default:
299 break;
306 break;
300 }
307 }
301
308
302 return QModelIndex();
309 return QModelIndex();
303 }
310 }
304
311
305 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
312 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
306 {
313 {
307 if (parent.column() > 0) {
314 if (parent.column() > 0) {
308 return 0;
315 return 0;
309 }
316 }
310
317
311 switch (itemTypeOf(parent)) {
318 switch (itemTypeOf(parent)) {
312 case CatalogueEventsModel::ItemType::Root:
319 case CatalogueEventsModel::ItemType::Root:
313 return impl->m_Events.count();
320 return impl->m_Events.count();
314 case CatalogueEventsModel::ItemType::Event: {
321 case CatalogueEventsModel::ItemType::Event: {
315 auto event = getEvent(parent);
322 auto event = getEvent(parent);
316 return impl->m_EventProducts[event.get()].count();
323 return impl->m_EventProducts[event.get()].count();
317 }
324 }
318 case CatalogueEventsModel::ItemType::EventProduct:
325 case CatalogueEventsModel::ItemType::EventProduct:
319 break;
326 break;
320 default:
327 default:
321 break;
328 break;
322 }
329 }
323
330
324 return 0;
331 return 0;
325 }
332 }
326
333
327 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
334 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
328 {
335 {
329 return static_cast<int>(CatalogueEventsModel::Column::NbColumn);
336 return static_cast<int>(CatalogueEventsModel::Column::NbColumn);
330 }
337 }
331
338
332 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
339 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
333 {
340 {
334 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
341 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
335 }
342 }
336
343
337 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
344 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
338 {
345 {
339 if (index.isValid()) {
346 if (index.isValid()) {
340
347
341 auto type = itemTypeOf(index);
348 auto type = itemTypeOf(index);
342 if (type == CatalogueEventsModel::ItemType::Event) {
349 if (type == CatalogueEventsModel::ItemType::Event) {
343 auto event = getEvent(index);
350 auto event = getEvent(index);
344 switch (role) {
351 switch (role) {
345 case Qt::DisplayRole:
352 case Qt::DisplayRole:
346 return impl->eventData(index.column(), event);
353 return impl->eventData(index.column(), event);
347 break;
354 break;
348 }
355 }
349 }
356 }
350 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
357 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
351 auto product = getEventProduct(index);
358 auto product = getEventProduct(index);
352 switch (role) {
359 switch (role) {
353 case Qt::DisplayRole:
360 case Qt::DisplayRole:
354 return impl->eventProductData(index.column(), product);
361 return impl->eventProductData(index.column(), product);
355 break;
362 break;
356 }
363 }
357 }
364 }
358 }
365 }
359
366
360 return QVariant{};
367 return QVariant{};
361 }
368 }
362
369
363 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
370 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
364 {
371 {
365 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
372 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
366 return impl->columnNames().value(section);
373 return impl->columnNames().value(section);
367 }
374 }
368
375
369 return QVariant();
376 return QVariant();
370 }
377 }
371
378
372 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
379 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
373 {
380 {
374 beginResetModel();
381 beginResetModel();
375 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
382 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
376 [this, column, order](auto e1, auto e2) {
383 [this, column, order](auto e1, auto e2) {
377 auto data1 = impl->sortData(column, e1);
384 auto data1 = impl->sortData(column, e1);
378 auto data2 = impl->sortData(column, e2);
385 auto data2 = impl->sortData(column, e2);
379
386
380 auto result = data1.toString() < data2.toString();
387 auto result = data1.toString() < data2.toString();
381
388
382 return order == Qt::AscendingOrder ? result : !result;
389 return order == Qt::AscendingOrder ? result : !result;
383 });
390 });
384
391
385 endResetModel();
392 endResetModel();
386 emit modelSorted();
393 emit modelSorted();
387 }
394 }
388
395
389 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
396 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
390 {
397 {
391 return Qt::CopyAction;
398 return Qt::CopyAction | Qt::MoveAction;
392 }
399 }
393
400
394 QStringList CatalogueEventsModel::mimeTypes() const
401 QStringList CatalogueEventsModel::mimeTypes() const
395 {
402 {
396 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_TIME_RANGE};
403 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_SOURCE_CATALOGUE_LIST, MIME_TYPE_TIME_RANGE};
397 }
404 }
398
405
399 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
406 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
400 {
407 {
401 auto mimeData = new QMimeData;
408 auto mimeData = new QMimeData;
402
409
403 bool isFirst = true;
410 bool isFirst = true;
404
411
405 QVector<std::shared_ptr<DBEvent> > eventList;
412 QVector<std::shared_ptr<DBEvent> > eventList;
406 QVector<std::shared_ptr<DBEventProduct> > eventProductList;
413 QVector<std::shared_ptr<DBEventProduct> > eventProductList;
407
414
408 SqpRange firstTimeRange;
415 SqpRange firstTimeRange;
409 for (const auto &index : indexes) {
416 for (const auto &index : indexes) {
410 if (index.column() == 0) { // only the first column
417 if (index.column() == 0) { // only the first column
411
418
412 auto type = itemTypeOf(index);
419 auto type = itemTypeOf(index);
413 if (type == ItemType::Event) {
420 if (type == ItemType::Event) {
414 auto event = getEvent(index);
421 auto event = getEvent(index);
415 eventList << event;
422 eventList << event;
416
423
417 if (isFirst) {
424 if (isFirst) {
418 isFirst = false;
425 isFirst = false;
419 firstTimeRange.m_TStart = event->getTStart();
426 firstTimeRange.m_TStart = event->getTStart();
420 firstTimeRange.m_TEnd = event->getTEnd();
427 firstTimeRange.m_TEnd = event->getTEnd();
421 }
428 }
422 }
429 }
423 else if (type == ItemType::EventProduct) {
430 else if (type == ItemType::EventProduct) {
424 auto product = getEventProduct(index);
431 auto product = getEventProduct(index);
425 eventProductList << product;
432 eventProductList << product;
426
433
427 if (isFirst) {
434 if (isFirst) {
428 isFirst = false;
435 isFirst = false;
429 firstTimeRange.m_TStart = product->getTStart();
436 firstTimeRange.m_TStart = product->getTStart();
430 firstTimeRange.m_TEnd = product->getTEnd();
437 firstTimeRange.m_TEnd = product->getTEnd();
431 }
438 }
432 }
439 }
433 }
440 }
434 }
441 }
435
442
436 if (!eventList.isEmpty() && eventProductList.isEmpty()) {
443 if (!eventList.isEmpty() && eventProductList.isEmpty()) {
437 auto eventsEncodedData = sqpApp->catalogueController().mimeDataForEvents(eventList);
444 auto eventsEncodedData = sqpApp->catalogueController().mimeDataForEvents(eventList);
438 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
445 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
446
447 auto sourceCataloguesEncodedData
448 = sqpApp->catalogueController().mimeDataForCatalogues(impl->m_SourceCatalogue);
449 mimeData->setData(MIME_TYPE_SOURCE_CATALOGUE_LIST, sourceCataloguesEncodedData);
439 }
450 }
440
451
441 if (eventList.count() + eventProductList.count() == 1) {
452 if (eventList.count() + eventProductList.count() == 1) {
442 // No time range MIME data if multiple events are dragged
453 // No time range MIME data if multiple events are dragged
443 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
454 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
444 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
455 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
445 }
456 }
446
457
447 return mimeData;
458 return mimeData;
448 }
459 }
449
460
450 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
461 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
451 {
462 {
452 if (!index.isValid()) {
463 if (!index.isValid()) {
453 return ItemType::Root;
464 return ItemType::Root;
454 }
465 }
455 else if (index.internalPointer() == nullptr) {
466 else if (index.internalPointer() == nullptr) {
456 return ItemType::Event;
467 return ItemType::Event;
457 }
468 }
458 else {
469 else {
459 return ItemType::EventProduct;
470 return ItemType::EventProduct;
460 }
471 }
461 }
472 }
@@ -1,593 +1,594
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 <DBEventProduct.h>
9 #include <DBEventProduct.h>
10 #include <DataSource/DataSourceController.h>
10 #include <DataSource/DataSourceController.h>
11 #include <DataSource/DataSourceItem.h>
11 #include <DataSource/DataSourceItem.h>
12 #include <SqpApplication.h>
12 #include <SqpApplication.h>
13 #include <Variable/Variable.h>
13 #include <Variable/Variable.h>
14 #include <Variable/VariableController.h>
14 #include <Variable/VariableController.h>
15 #include <Visualization/VisualizationGraphWidget.h>
15 #include <Visualization/VisualizationGraphWidget.h>
16 #include <Visualization/VisualizationTabWidget.h>
16 #include <Visualization/VisualizationTabWidget.h>
17 #include <Visualization/VisualizationWidget.h>
17 #include <Visualization/VisualizationWidget.h>
18 #include <Visualization/VisualizationZoneWidget.h>
18 #include <Visualization/VisualizationZoneWidget.h>
19
19
20 #include <QDialog>
20 #include <QDialog>
21 #include <QDialogButtonBox>
21 #include <QDialogButtonBox>
22 #include <QListWidget>
22 #include <QListWidget>
23 #include <QMessageBox>
23 #include <QMessageBox>
24
24
25 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
25 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
26
26
27 /// Fixed size of the validation column
27 /// Fixed size of the validation column
28 const auto VALIDATION_COLUMN_SIZE = 35;
28 const auto VALIDATION_COLUMN_SIZE = 35;
29
29
30 /// Percentage added to the range of a event when it is displayed
30 /// Percentage added to the range of a event when it is displayed
31 const auto EVENT_RANGE_MARGE = 30; // in %
31 const auto EVENT_RANGE_MARGE = 30; // in %
32
32
33 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
33 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
34
34
35 CatalogueEventsModel *m_Model = nullptr;
35 CatalogueEventsModel *m_Model = nullptr;
36 QStringList m_ZonesForTimeMode;
36 QStringList m_ZonesForTimeMode;
37 QString m_ZoneForGraphMode;
37 QString m_ZoneForGraphMode;
38 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
38 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
39 bool m_AllEventDisplayed = false;
39 bool m_AllEventDisplayed = false;
40 QVector<VisualizationGraphWidget *> m_CustomGraphs;
40 QVector<VisualizationGraphWidget *> m_CustomGraphs;
41
41
42 VisualizationWidget *m_VisualizationWidget = nullptr;
42 VisualizationWidget *m_VisualizationWidget = nullptr;
43
43
44 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
44 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
45 {
45 {
46 widget->ui->treeView->setSortingEnabled(false);
46 widget->ui->treeView->setSortingEnabled(false);
47 m_Model->setSourceCatalogues(m_DisplayedCatalogues);
47 m_Model->setEvents(events);
48 m_Model->setEvents(events);
48 widget->ui->treeView->setSortingEnabled(true);
49 widget->ui->treeView->setSortingEnabled(true);
49
50
50 for (auto event : events) {
51 for (auto event : events) {
51 if (sqpApp->catalogueController().eventHasChanges(event)) {
52 if (sqpApp->catalogueController().eventHasChanges(event)) {
52 auto index = m_Model->indexOf(event);
53 auto index = m_Model->indexOf(event);
53 widget->setEventChanges(event, true);
54 widget->setEventChanges(event, true);
54 }
55 }
55 }
56 }
56 }
57 }
57
58
58 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
59 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
59 {
60 {
60 treeView->setSortingEnabled(false);
61 treeView->setSortingEnabled(false);
61 m_Model->addEvent(event);
62 m_Model->addEvent(event);
62 treeView->setSortingEnabled(true);
63 treeView->setSortingEnabled(true);
63 }
64 }
64
65
65 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
66 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
66 {
67 {
67 treeView->setSortingEnabled(false);
68 treeView->setSortingEnabled(false);
68 m_Model->removeEvent(event);
69 m_Model->removeEvent(event);
69 treeView->setSortingEnabled(true);
70 treeView->setSortingEnabled(true);
70 }
71 }
71
72
72 QStringList getAvailableVisualizationZoneList() const
73 QStringList getAvailableVisualizationZoneList() const
73 {
74 {
74 if (m_VisualizationWidget) {
75 if (m_VisualizationWidget) {
75 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
76 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
76 return tab->availableZoneWidgets();
77 return tab->availableZoneWidgets();
77 }
78 }
78 }
79 }
79
80
80 return QStringList{};
81 return QStringList{};
81 }
82 }
82
83
83 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
84 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
84 bool allowMultiSelection, const QPoint &location)
85 bool allowMultiSelection, const QPoint &location)
85 {
86 {
86 auto availableZones = getAvailableVisualizationZoneList();
87 auto availableZones = getAvailableVisualizationZoneList();
87 if (availableZones.isEmpty()) {
88 if (availableZones.isEmpty()) {
88 return QStringList{};
89 return QStringList{};
89 }
90 }
90
91
91 QDialog d(parent, Qt::Tool);
92 QDialog d(parent, Qt::Tool);
92 d.setWindowTitle("Choose a zone");
93 d.setWindowTitle("Choose a zone");
93 auto layout = new QVBoxLayout{&d};
94 auto layout = new QVBoxLayout{&d};
94 layout->setContentsMargins(0, 0, 0, 0);
95 layout->setContentsMargins(0, 0, 0, 0);
95 auto listWidget = new QListWidget{&d};
96 auto listWidget = new QListWidget{&d};
96 layout->addWidget(listWidget);
97 layout->addWidget(listWidget);
97
98
98 QSet<QListWidgetItem *> checkedItems;
99 QSet<QListWidgetItem *> checkedItems;
99 for (auto zone : availableZones) {
100 for (auto zone : availableZones) {
100 auto item = new QListWidgetItem{zone};
101 auto item = new QListWidgetItem{zone};
101 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
102 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
102 if (selectedZones.contains(zone)) {
103 if (selectedZones.contains(zone)) {
103 item->setCheckState(Qt::Checked);
104 item->setCheckState(Qt::Checked);
104 checkedItems << item;
105 checkedItems << item;
105 }
106 }
106 else {
107 else {
107 item->setCheckState(Qt::Unchecked);
108 item->setCheckState(Qt::Unchecked);
108 }
109 }
109
110
110 listWidget->addItem(item);
111 listWidget->addItem(item);
111 }
112 }
112
113
113 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
114 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
114 layout->addWidget(buttonBox);
115 layout->addWidget(buttonBox);
115
116
116 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
117 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
117 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
118 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
118
119
119 QObject::connect(listWidget, &QListWidget::itemChanged,
120 QObject::connect(listWidget, &QListWidget::itemChanged,
120 [&checkedItems, allowMultiSelection, listWidget](auto item) {
121 [&checkedItems, allowMultiSelection, listWidget](auto item) {
121 if (item->checkState() == Qt::Checked) {
122 if (item->checkState() == Qt::Checked) {
122 if (!allowMultiSelection) {
123 if (!allowMultiSelection) {
123 for (auto checkedItem : checkedItems) {
124 for (auto checkedItem : checkedItems) {
124 listWidget->blockSignals(true);
125 listWidget->blockSignals(true);
125 checkedItem->setCheckState(Qt::Unchecked);
126 checkedItem->setCheckState(Qt::Unchecked);
126 listWidget->blockSignals(false);
127 listWidget->blockSignals(false);
127 }
128 }
128
129
129 checkedItems.clear();
130 checkedItems.clear();
130 }
131 }
131 checkedItems << item;
132 checkedItems << item;
132 }
133 }
133 else {
134 else {
134 checkedItems.remove(item);
135 checkedItems.remove(item);
135 }
136 }
136 });
137 });
137
138
138 QStringList result;
139 QStringList result;
139
140
140 d.setMinimumWidth(120);
141 d.setMinimumWidth(120);
141 d.resize(d.minimumSizeHint());
142 d.resize(d.minimumSizeHint());
142 d.move(location);
143 d.move(location);
143 if (d.exec() == QDialog::Accepted) {
144 if (d.exec() == QDialog::Accepted) {
144 for (auto item : checkedItems) {
145 for (auto item : checkedItems) {
145 result += item->text();
146 result += item->text();
146 }
147 }
147 }
148 }
148 else {
149 else {
149 result = selectedZones;
150 result = selectedZones;
150 }
151 }
151
152
152 return result;
153 return result;
153 }
154 }
154
155
155 void updateForTimeMode(QTreeView *treeView)
156 void updateForTimeMode(QTreeView *treeView)
156 {
157 {
157 auto selectedRows = treeView->selectionModel()->selectedRows();
158 auto selectedRows = treeView->selectionModel()->selectedRows();
158
159
159 if (selectedRows.count() == 1) {
160 if (selectedRows.count() == 1) {
160 auto event = m_Model->getEvent(selectedRows.first());
161 auto event = m_Model->getEvent(selectedRows.first());
161 if (event) {
162 if (event) {
162 if (m_VisualizationWidget) {
163 if (m_VisualizationWidget) {
163 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
164 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
164
165
165 for (auto zoneName : m_ZonesForTimeMode) {
166 for (auto zoneName : m_ZonesForTimeMode) {
166 if (auto zone = tab->getZoneWithName(zoneName)) {
167 if (auto zone = tab->getZoneWithName(zoneName)) {
167 SqpRange eventRange;
168 SqpRange eventRange;
168 eventRange.m_TStart = event->getTStart();
169 eventRange.m_TStart = event->getTStart();
169 eventRange.m_TEnd = event->getTEnd();
170 eventRange.m_TEnd = event->getTEnd();
170 zone->setZoneRange(eventRange);
171 zone->setZoneRange(eventRange);
171 }
172 }
172 }
173 }
173 }
174 }
174 else {
175 else {
175 qCWarning(LOG_CatalogueEventsWidget())
176 qCWarning(LOG_CatalogueEventsWidget())
176 << "updateTimeZone: no tab found in the visualization";
177 << "updateTimeZone: no tab found in the visualization";
177 }
178 }
178 }
179 }
179 else {
180 else {
180 qCWarning(LOG_CatalogueEventsWidget())
181 qCWarning(LOG_CatalogueEventsWidget())
181 << "updateTimeZone: visualization widget not found";
182 << "updateTimeZone: visualization widget not found";
182 }
183 }
183 }
184 }
184 }
185 }
185 else {
186 else {
186 qCWarning(LOG_CatalogueEventsWidget())
187 qCWarning(LOG_CatalogueEventsWidget())
187 << "updateTimeZone: not compatible with multiple events selected";
188 << "updateTimeZone: not compatible with multiple events selected";
188 }
189 }
189 }
190 }
190
191
191 QVector<SqpRange> getGraphRanges(const std::shared_ptr<DBEvent> &event)
192 QVector<SqpRange> getGraphRanges(const std::shared_ptr<DBEvent> &event)
192 {
193 {
193 // Retrieves the range of each product and the maximum size
194 // Retrieves the range of each product and the maximum size
194 QVector<SqpRange> graphRanges;
195 QVector<SqpRange> graphRanges;
195 double maxDt = 0;
196 double maxDt = 0;
196 for (auto eventProduct : event->getEventProducts()) {
197 for (auto eventProduct : event->getEventProducts()) {
197 SqpRange eventRange;
198 SqpRange eventRange;
198 eventRange.m_TStart = eventProduct.getTStart();
199 eventRange.m_TStart = eventProduct.getTStart();
199 eventRange.m_TEnd = eventProduct.getTEnd();
200 eventRange.m_TEnd = eventProduct.getTEnd();
200 graphRanges << eventRange;
201 graphRanges << eventRange;
201
202
202 auto dt = eventRange.m_TEnd - eventRange.m_TStart;
203 auto dt = eventRange.m_TEnd - eventRange.m_TStart;
203 if (dt > maxDt) {
204 if (dt > maxDt) {
204 maxDt = dt;
205 maxDt = dt;
205 }
206 }
206 }
207 }
207
208
208 // Adds the marge
209 // Adds the marge
209 maxDt *= (100.0 + EVENT_RANGE_MARGE) / 100.0;
210 maxDt *= (100.0 + EVENT_RANGE_MARGE) / 100.0;
210
211
211 // Corrects the graph ranges so that they all have the same size
212 // Corrects the graph ranges so that they all have the same size
212 QVector<SqpRange> correctedGraphRanges;
213 QVector<SqpRange> correctedGraphRanges;
213 for (auto range : graphRanges) {
214 for (auto range : graphRanges) {
214 auto dt = range.m_TEnd - range.m_TStart;
215 auto dt = range.m_TEnd - range.m_TStart;
215 auto diff = qAbs((maxDt - dt) / 2.0);
216 auto diff = qAbs((maxDt - dt) / 2.0);
216
217
217 SqpRange correctedRange;
218 SqpRange correctedRange;
218 correctedRange.m_TStart = range.m_TStart - diff;
219 correctedRange.m_TStart = range.m_TStart - diff;
219 correctedRange.m_TEnd = range.m_TEnd + diff;
220 correctedRange.m_TEnd = range.m_TEnd + diff;
220
221
221 correctedGraphRanges << correctedRange;
222 correctedGraphRanges << correctedRange;
222 }
223 }
223
224
224 return correctedGraphRanges;
225 return correctedGraphRanges;
225 }
226 }
226
227
227 void updateForGraphMode(CatalogueEventsWidget *catalogueEventWidget)
228 void updateForGraphMode(CatalogueEventsWidget *catalogueEventWidget)
228 {
229 {
229 auto selectedRows = catalogueEventWidget->ui->treeView->selectionModel()->selectedRows();
230 auto selectedRows = catalogueEventWidget->ui->treeView->selectionModel()->selectedRows();
230 if (selectedRows.count() != 1) {
231 if (selectedRows.count() != 1) {
231 qCWarning(LOG_CatalogueEventsWidget())
232 qCWarning(LOG_CatalogueEventsWidget())
232 << "updateGraphMode: not compatible with multiple events selected";
233 << "updateGraphMode: not compatible with multiple events selected";
233 return;
234 return;
234 }
235 }
235
236
236 if (!m_VisualizationWidget) {
237 if (!m_VisualizationWidget) {
237 qCWarning(LOG_CatalogueEventsWidget())
238 qCWarning(LOG_CatalogueEventsWidget())
238 << "updateGraphMode: visualization widget not found";
239 << "updateGraphMode: visualization widget not found";
239 return;
240 return;
240 }
241 }
241
242
242 auto event = m_Model->getEvent(selectedRows.first());
243 auto event = m_Model->getEvent(selectedRows.first());
243 if (!event) {
244 if (!event) {
244 // A event product is probably selected
245 // A event product is probably selected
245 qCInfo(LOG_CatalogueEventsWidget()) << "updateGraphMode: no events are selected";
246 qCInfo(LOG_CatalogueEventsWidget()) << "updateGraphMode: no events are selected";
246 return;
247 return;
247 }
248 }
248
249
249 auto tab = m_VisualizationWidget->currentTabWidget();
250 auto tab = m_VisualizationWidget->currentTabWidget();
250 if (!tab) {
251 if (!tab) {
251 qCWarning(LOG_CatalogueEventsWidget())
252 qCWarning(LOG_CatalogueEventsWidget())
252 << "updateGraphMode: no tab found in the visualization";
253 << "updateGraphMode: no tab found in the visualization";
253 return;
254 return;
254 }
255 }
255
256
256 auto zone = tab->getZoneWithName(m_ZoneForGraphMode);
257 auto zone = tab->getZoneWithName(m_ZoneForGraphMode);
257 if (!zone) {
258 if (!zone) {
258 qCWarning(LOG_CatalogueEventsWidget()) << "updateGraphMode: zone not found";
259 qCWarning(LOG_CatalogueEventsWidget()) << "updateGraphMode: zone not found";
259 return;
260 return;
260 }
261 }
261
262
262 // Closes the previous graph and delete the asociated variables
263 // Closes the previous graph and delete the asociated variables
263 for (auto graph : m_CustomGraphs) {
264 for (auto graph : m_CustomGraphs) {
264 graph->close();
265 graph->close();
265 auto variables = graph->variables().toVector();
266 auto variables = graph->variables().toVector();
266
267
267 QMetaObject::invokeMethod(&sqpApp->variableController(), "deleteVariables",
268 QMetaObject::invokeMethod(&sqpApp->variableController(), "deleteVariables",
268 Qt::QueuedConnection,
269 Qt::QueuedConnection,
269 Q_ARG(QVector<std::shared_ptr<Variable> >, variables));
270 Q_ARG(QVector<std::shared_ptr<Variable> >, variables));
270 }
271 }
271 m_CustomGraphs.clear();
272 m_CustomGraphs.clear();
272
273
273 // Closes the remaining graphs inside the zone
274 // Closes the remaining graphs inside the zone
274 zone->closeAllGraphs();
275 zone->closeAllGraphs();
275
276
276 // Calculates the range of each graph which will be created
277 // Calculates the range of each graph which will be created
277 auto graphRange = getGraphRanges(event);
278 auto graphRange = getGraphRanges(event);
278
279
279 // Loops through the event products and create the graph
280 // Loops through the event products and create the graph
280 auto itRange = graphRange.cbegin();
281 auto itRange = graphRange.cbegin();
281 for (auto eventProduct : event->getEventProducts()) {
282 for (auto eventProduct : event->getEventProducts()) {
282 auto productId = eventProduct.getProductId();
283 auto productId = eventProduct.getProductId();
283
284
284 auto range = *itRange;
285 auto range = *itRange;
285 ++itRange;
286 ++itRange;
286
287
287 SqpRange productRange;
288 SqpRange productRange;
288 productRange.m_TStart = eventProduct.getTStart();
289 productRange.m_TStart = eventProduct.getTStart();
289 productRange.m_TEnd = eventProduct.getTEnd();
290 productRange.m_TEnd = eventProduct.getTEnd();
290
291
291 auto context = new QObject{catalogueEventWidget};
292 auto context = new QObject{catalogueEventWidget};
292 QObject::connect(
293 QObject::connect(
293 &sqpApp->variableController(), &VariableController::variableAdded, context,
294 &sqpApp->variableController(), &VariableController::variableAdded, context,
294 [this, catalogueEventWidget, zone, context, event, range, productRange,
295 [this, catalogueEventWidget, zone, context, event, range, productRange,
295 productId](auto variable) {
296 productId](auto variable) {
296
297
297 if (variable->metadata().value(DataSourceItem::ID_DATA_KEY).toString()
298 if (variable->metadata().value(DataSourceItem::ID_DATA_KEY).toString()
298 == productId) {
299 == productId) {
299 auto graph = zone->createGraph(variable);
300 auto graph = zone->createGraph(variable);
300 graph->setAutoRangeOnVariableInitialization(false);
301 graph->setAutoRangeOnVariableInitialization(false);
301
302
302 auto selectionZone
303 auto selectionZone
303 = graph->addSelectionZone(event->getName(), productRange);
304 = graph->addSelectionZone(event->getName(), productRange);
304 emit catalogueEventWidget->selectionZoneAdded(event, productId,
305 emit catalogueEventWidget->selectionZoneAdded(event, productId,
305 selectionZone);
306 selectionZone);
306 m_CustomGraphs << graph;
307 m_CustomGraphs << graph;
307
308
308 graph->setGraphRange(range, true);
309 graph->setGraphRange(range, true);
309
310
310 // Removes the graph from the graph list if it is closed manually
311 // Removes the graph from the graph list if it is closed manually
311 QObject::connect(graph, &VisualizationGraphWidget::destroyed,
312 QObject::connect(graph, &VisualizationGraphWidget::destroyed,
312 [this, graph]() { m_CustomGraphs.removeAll(graph); });
313 [this, graph]() { m_CustomGraphs.removeAll(graph); });
313
314
314 delete context; // removes the connection
315 delete context; // removes the connection
315 }
316 }
316 },
317 },
317 Qt::QueuedConnection);
318 Qt::QueuedConnection);
318
319
319 QMetaObject::invokeMethod(&sqpApp->dataSourceController(),
320 QMetaObject::invokeMethod(&sqpApp->dataSourceController(),
320 "requestVariableFromProductIdKey", Qt::QueuedConnection,
321 "requestVariableFromProductIdKey", Qt::QueuedConnection,
321 Q_ARG(QString, productId));
322 Q_ARG(QString, productId));
322 }
323 }
323 }
324 }
324
325
325 void getSelectedItems(
326 void getSelectedItems(
326 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
327 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
327 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
328 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
328 {
329 {
329 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
330 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
330 auto itemType = m_Model->itemTypeOf(rowIndex);
331 auto itemType = m_Model->itemTypeOf(rowIndex);
331 if (itemType == CatalogueEventsModel::ItemType::Event) {
332 if (itemType == CatalogueEventsModel::ItemType::Event) {
332 events << m_Model->getEvent(rowIndex);
333 events << m_Model->getEvent(rowIndex);
333 }
334 }
334 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
335 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
335 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
336 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
336 m_Model->getEventProduct(rowIndex));
337 m_Model->getEventProduct(rowIndex));
337 }
338 }
338 }
339 }
339 }
340 }
340 };
341 };
341
342
342 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
343 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
343 : QWidget(parent),
344 : QWidget(parent),
344 ui(new Ui::CatalogueEventsWidget),
345 ui(new Ui::CatalogueEventsWidget),
345 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
346 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
346 {
347 {
347 ui->setupUi(this);
348 ui->setupUi(this);
348
349
349 impl->m_Model = new CatalogueEventsModel{this};
350 impl->m_Model = new CatalogueEventsModel{this};
350 ui->treeView->setModel(impl->m_Model);
351 ui->treeView->setModel(impl->m_Model);
351
352
352 ui->treeView->setSortingEnabled(true);
353 ui->treeView->setSortingEnabled(true);
353 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
354 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
354 ui->treeView->setDragEnabled(true);
355 ui->treeView->setDragEnabled(true);
355
356
356 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
357 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
357 if (checked) {
358 if (checked) {
358 ui->btnChart->setChecked(false);
359 ui->btnChart->setChecked(false);
359 impl->m_ZonesForTimeMode
360 impl->m_ZonesForTimeMode
360 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
361 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
361 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
362 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
362
363
363 impl->updateForTimeMode(ui->treeView);
364 impl->updateForTimeMode(ui->treeView);
364 }
365 }
365 });
366 });
366
367
367 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
368 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
368 if (checked) {
369 if (checked) {
369 ui->btnTime->setChecked(false);
370 ui->btnTime->setChecked(false);
370 impl->m_ZoneForGraphMode
371 impl->m_ZoneForGraphMode
371 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
372 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
372 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
373 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
373 .value(0);
374 .value(0);
374
375
375 impl->updateForGraphMode(this);
376 impl->updateForGraphMode(this);
376 }
377 }
377 });
378 });
378
379
379 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
380 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
380 QVector<std::shared_ptr<DBEvent> > events;
381 QVector<std::shared_ptr<DBEvent> > events;
381 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
382 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
382 impl->getSelectedItems(ui->treeView, events, eventProducts);
383 impl->getSelectedItems(ui->treeView, events, eventProducts);
383
384
384 if (!events.isEmpty() && eventProducts.isEmpty()) {
385 if (!events.isEmpty() && eventProducts.isEmpty()) {
385
386
386 if (QMessageBox::warning(this, tr("Remove Event(s)"),
387 if (QMessageBox::warning(this, tr("Remove Event(s)"),
387 tr("The selected event(s) will be permanently removed "
388 tr("The selected event(s) will be permanently removed "
388 "from the repository!\nAre you sure you want to continue?"),
389 "from the repository!\nAre you sure you want to continue?"),
389 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
390 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
390 == QMessageBox::Yes) {
391 == QMessageBox::Yes) {
391
392
392 for (auto event : events) {
393 for (auto event : events) {
393 sqpApp->catalogueController().removeEvent(event);
394 sqpApp->catalogueController().removeEvent(event);
394 impl->removeEvent(event, ui->treeView);
395 impl->removeEvent(event, ui->treeView);
395 }
396 }
396
397
397 emit this->eventsRemoved(events);
398 emit this->eventsRemoved(events);
398 }
399 }
399 }
400 }
400 });
401 });
401
402
402 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueEventsWidget::emitSelection);
403 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueEventsWidget::emitSelection);
403 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
404 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
404 &CatalogueEventsWidget::emitSelection);
405 &CatalogueEventsWidget::emitSelection);
405
406
406 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
407 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
407 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
408 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
408 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
409 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
409 ui->btnChart->setEnabled(isNotMultiSelection);
410 ui->btnChart->setEnabled(isNotMultiSelection);
410 ui->btnTime->setEnabled(isNotMultiSelection);
411 ui->btnTime->setEnabled(isNotMultiSelection);
411
412
412 if (isNotMultiSelection && ui->btnTime->isChecked()) {
413 if (isNotMultiSelection && ui->btnTime->isChecked()) {
413 impl->updateForTimeMode(ui->treeView);
414 impl->updateForTimeMode(ui->treeView);
414 }
415 }
415 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
416 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
416 impl->updateForGraphMode(this);
417 impl->updateForGraphMode(this);
417 }
418 }
418
419
419 QVector<std::shared_ptr<DBEvent> > events;
420 QVector<std::shared_ptr<DBEvent> > events;
420 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
421 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
421 impl->getSelectedItems(ui->treeView, events, eventProducts);
422 impl->getSelectedItems(ui->treeView, events, eventProducts);
422 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
423 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
423 });
424 });
424
425
425 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
426 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
426 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
427 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
427 QHeaderView::Stretch);
428 QHeaderView::Stretch);
428 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
429 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
429 QHeaderView::Fixed);
430 QHeaderView::Fixed);
430 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
431 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
431 QHeaderView::Interactive);
432 QHeaderView::Interactive);
432 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
433 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
433 VALIDATION_COLUMN_SIZE);
434 VALIDATION_COLUMN_SIZE);
434 ui->treeView->header()->setSortIndicatorShown(true);
435 ui->treeView->header()->setSortIndicatorShown(true);
435
436
436 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
437 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
437 auto allEvents = impl->m_Model->events();
438 auto allEvents = impl->m_Model->events();
438 for (auto event : allEvents) {
439 for (auto event : allEvents) {
439 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
440 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
440 }
441 }
441 });
442 });
442
443
443 populateWithAllEvents();
444 populateWithAllEvents();
444 }
445 }
445
446
446 CatalogueEventsWidget::~CatalogueEventsWidget()
447 CatalogueEventsWidget::~CatalogueEventsWidget()
447 {
448 {
448 delete ui;
449 delete ui;
449 }
450 }
450
451
451 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
452 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
452 {
453 {
453 impl->m_VisualizationWidget = visualization;
454 impl->m_VisualizationWidget = visualization;
454 }
455 }
455
456
456 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
457 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
457 {
458 {
458 impl->addEvent(event, ui->treeView);
459 impl->addEvent(event, ui->treeView);
459 }
460 }
460
461
461 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
462 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
462 {
463 {
463 impl->m_Model->refreshEvent(event);
464 impl->m_Model->refreshEvent(event);
464
465
465 auto eventIndex = impl->m_Model->indexOf(event);
466 auto eventIndex = impl->m_Model->indexOf(event);
466 auto validationIndex
467 auto validationIndex
467 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
468 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
468
469
469 if (validationIndex.isValid()) {
470 if (validationIndex.isValid()) {
470 if (hasChanges) {
471 if (hasChanges) {
471 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
472 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
472 auto widget = CatalogueExplorerHelper::buildValidationWidget(
473 auto widget = CatalogueExplorerHelper::buildValidationWidget(
473 ui->treeView,
474 ui->treeView,
474 [this, event]() {
475 [this, event]() {
475 sqpApp->catalogueController().saveEvent(event);
476 sqpApp->catalogueController().saveEvent(event);
476 setEventChanges(event, false);
477 setEventChanges(event, false);
477 },
478 },
478 [this, event]() {
479 [this, event]() {
479 bool removed = false;
480 bool removed = false;
480 sqpApp->catalogueController().discardEvent(event, removed);
481 sqpApp->catalogueController().discardEvent(event, removed);
481 if (removed) {
482 if (removed) {
482 impl->m_Model->removeEvent(event);
483 impl->m_Model->removeEvent(event);
483 }
484 }
484 else {
485 else {
485 setEventChanges(event, false);
486 setEventChanges(event, false);
486 impl->m_Model->refreshEvent(event, true);
487 impl->m_Model->refreshEvent(event, true);
487 }
488 }
488 emitSelection();
489 emitSelection();
489 });
490 });
490 ui->treeView->setIndexWidget(validationIndex, widget);
491 ui->treeView->setIndexWidget(validationIndex, widget);
491 }
492 }
492 }
493 }
493 else {
494 else {
494 // Note: the widget is destroyed
495 // Note: the widget is destroyed
495 ui->treeView->setIndexWidget(validationIndex, nullptr);
496 ui->treeView->setIndexWidget(validationIndex, nullptr);
496 }
497 }
497 }
498 }
498 else {
499 else {
499 qCWarning(LOG_CatalogueEventsWidget())
500 qCWarning(LOG_CatalogueEventsWidget())
500 << "setEventChanges: the event is not displayed in the model.";
501 << "setEventChanges: the event is not displayed in the model.";
501 }
502 }
502 }
503 }
503
504
504 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
505 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
505 {
506 {
506 return impl->m_DisplayedCatalogues;
507 return impl->m_DisplayedCatalogues;
507 }
508 }
508
509
509 bool CatalogueEventsWidget::isAllEventsDisplayed() const
510 bool CatalogueEventsWidget::isAllEventsDisplayed() const
510 {
511 {
511 return impl->m_AllEventDisplayed;
512 return impl->m_AllEventDisplayed;
512 }
513 }
513
514
514 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
515 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
515 {
516 {
516 return impl->m_Model->indexOf(event).isValid();
517 return impl->m_Model->indexOf(event).isValid();
517 }
518 }
518
519
519 void CatalogueEventsWidget::refreshEvent(const std::shared_ptr<DBEvent> &event)
520 void CatalogueEventsWidget::refreshEvent(const std::shared_ptr<DBEvent> &event)
520 {
521 {
521 impl->m_Model->refreshEvent(event, true);
522 impl->m_Model->refreshEvent(event, true);
522 }
523 }
523
524
524 void CatalogueEventsWidget::populateWithCatalogues(
525 void CatalogueEventsWidget::populateWithCatalogues(
525 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
526 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
526 {
527 {
527 impl->m_DisplayedCatalogues = catalogues;
528 impl->m_DisplayedCatalogues = catalogues;
528 impl->m_AllEventDisplayed = false;
529 impl->m_AllEventDisplayed = false;
529
530
530 QSet<QUuid> eventIds;
531 QSet<QUuid> eventIds;
531 QVector<std::shared_ptr<DBEvent> > events;
532 QVector<std::shared_ptr<DBEvent> > events;
532
533
533 for (auto catalogue : catalogues) {
534 for (auto catalogue : catalogues) {
534 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
535 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
535 for (auto event : catalogueEvents) {
536 for (auto event : catalogueEvents) {
536 if (!eventIds.contains(event->getUniqId())) {
537 if (!eventIds.contains(event->getUniqId())) {
537 events << event;
538 events << event;
538 eventIds.insert(event->getUniqId());
539 eventIds.insert(event->getUniqId());
539 }
540 }
540 }
541 }
541 }
542 }
542
543
543 impl->setEvents(events, this);
544 impl->setEvents(events, this);
544 }
545 }
545
546
546 void CatalogueEventsWidget::populateWithAllEvents()
547 void CatalogueEventsWidget::populateWithAllEvents()
547 {
548 {
548 impl->m_DisplayedCatalogues.clear();
549 impl->m_DisplayedCatalogues.clear();
549 impl->m_AllEventDisplayed = true;
550 impl->m_AllEventDisplayed = true;
550
551
551 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
552 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
552
553
553 QVector<std::shared_ptr<DBEvent> > events;
554 QVector<std::shared_ptr<DBEvent> > events;
554 for (auto event : allEvents) {
555 for (auto event : allEvents) {
555 events << event;
556 events << event;
556 }
557 }
557
558
558 impl->setEvents(events, this);
559 impl->setEvents(events, this);
559 }
560 }
560
561
561 void CatalogueEventsWidget::clear()
562 void CatalogueEventsWidget::clear()
562 {
563 {
563 impl->m_DisplayedCatalogues.clear();
564 impl->m_DisplayedCatalogues.clear();
564 impl->m_AllEventDisplayed = false;
565 impl->m_AllEventDisplayed = false;
565 impl->setEvents({}, this);
566 impl->setEvents({}, this);
566 }
567 }
567
568
568 void CatalogueEventsWidget::refresh()
569 void CatalogueEventsWidget::refresh()
569 {
570 {
570 if (isAllEventsDisplayed()) {
571 if (isAllEventsDisplayed()) {
571 populateWithAllEvents();
572 populateWithAllEvents();
572 }
573 }
573 else if (!impl->m_DisplayedCatalogues.isEmpty()) {
574 else if (!impl->m_DisplayedCatalogues.isEmpty()) {
574 populateWithCatalogues(impl->m_DisplayedCatalogues);
575 populateWithCatalogues(impl->m_DisplayedCatalogues);
575 }
576 }
576 }
577 }
577
578
578 void CatalogueEventsWidget::emitSelection()
579 void CatalogueEventsWidget::emitSelection()
579 {
580 {
580 QVector<std::shared_ptr<DBEvent> > events;
581 QVector<std::shared_ptr<DBEvent> > events;
581 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
582 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
582 impl->getSelectedItems(ui->treeView, events, eventProducts);
583 impl->getSelectedItems(ui->treeView, events, eventProducts);
583
584
584 if (!events.isEmpty() && eventProducts.isEmpty()) {
585 if (!events.isEmpty() && eventProducts.isEmpty()) {
585 emit eventsSelected(events);
586 emit eventsSelected(events);
586 }
587 }
587 else if (events.isEmpty() && !eventProducts.isEmpty()) {
588 else if (events.isEmpty() && !eventProducts.isEmpty()) {
588 emit eventProductsSelected(eventProducts);
589 emit eventProductsSelected(eventProducts);
589 }
590 }
590 else {
591 else {
591 emit selectionCleared();
592 emit selectionCleared();
592 }
593 }
593 }
594 }
@@ -1,414 +1,429
1 #include "Catalogue/CatalogueSideBarWidget.h"
1 #include "Catalogue/CatalogueSideBarWidget.h"
2 #include "ui_CatalogueSideBarWidget.h"
2 #include "ui_CatalogueSideBarWidget.h"
3 #include <SqpApplication.h>
3 #include <SqpApplication.h>
4
4
5 #include <Catalogue/CatalogueController.h>
5 #include <Catalogue/CatalogueController.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
7 #include <Catalogue/CatalogueTreeItems/CatalogueTextTreeItem.h>
7 #include <Catalogue/CatalogueTreeItems/CatalogueTextTreeItem.h>
8 #include <Catalogue/CatalogueTreeItems/CatalogueTreeItem.h>
8 #include <Catalogue/CatalogueTreeItems/CatalogueTreeItem.h>
9 #include <Catalogue/CatalogueTreeModel.h>
9 #include <Catalogue/CatalogueTreeModel.h>
10 #include <CatalogueDao.h>
10 #include <CatalogueDao.h>
11 #include <Common/MimeTypesDef.h>
11 #include <ComparaisonPredicate.h>
12 #include <ComparaisonPredicate.h>
12 #include <DBCatalogue.h>
13 #include <DBCatalogue.h>
13
14
14 #include <QMenu>
15 #include <QMenu>
15 #include <QMessageBox>
16 #include <QMessageBox>
17 #include <QMimeData>
16
18
17 Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget")
19 Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget")
18
20
19
21
20 constexpr auto ALL_EVENT_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 1;
22 constexpr auto ALL_EVENT_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 1;
21 constexpr auto TRASH_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 2;
23 constexpr auto TRASH_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 2;
22 constexpr auto CATALOGUE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 3;
24 constexpr auto CATALOGUE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 3;
23 constexpr auto DATABASE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 4;
25 constexpr auto DATABASE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 4;
24
26
25
27
26 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
28 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
27
29
28 CatalogueTreeModel *m_TreeModel = nullptr;
30 CatalogueTreeModel *m_TreeModel = nullptr;
29
31
30 void configureTreeWidget(QTreeView *treeView);
32 void configureTreeWidget(QTreeView *treeView);
31 QModelIndex addDatabaseItem(const QString &name);
33 QModelIndex addDatabaseItem(const QString &name);
32 CatalogueAbstractTreeItem *getDatabaseItem(const QString &name);
34 CatalogueAbstractTreeItem *getDatabaseItem(const QString &name);
33 CatalogueAbstractTreeItem *addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
35 CatalogueAbstractTreeItem *addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
34 const QModelIndex &databaseIndex);
36 const QModelIndex &databaseIndex);
35
37
36 CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const;
38 CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const;
37 void setHasChanges(bool value, const QModelIndex &index, CatalogueSideBarWidget *sideBarWidget);
39 void setHasChanges(bool value, const QModelIndex &index, CatalogueSideBarWidget *sideBarWidget);
38 bool hasChanges(const QModelIndex &index, QTreeView *treeView);
40 bool hasChanges(const QModelIndex &index, QTreeView *treeView);
39
41
40 int selectionType(QTreeView *treeView) const
42 int selectionType(QTreeView *treeView) const
41 {
43 {
42 auto selectedItems = treeView->selectionModel()->selectedRows();
44 auto selectedItems = treeView->selectionModel()->selectedRows();
43 if (selectedItems.isEmpty()) {
45 if (selectedItems.isEmpty()) {
44 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
46 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
45 }
47 }
46 else {
48 else {
47 auto firstIndex = selectedItems.first();
49 auto firstIndex = selectedItems.first();
48 auto firstItem = m_TreeModel->item(firstIndex);
50 auto firstItem = m_TreeModel->item(firstIndex);
49 if (!firstItem) {
51 if (!firstItem) {
50 Q_ASSERT(false);
52 Q_ASSERT(false);
51 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
53 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
52 }
54 }
53 auto selectionType = firstItem->type();
55 auto selectionType = firstItem->type();
54
56
55 for (auto itemIndex : selectedItems) {
57 for (auto itemIndex : selectedItems) {
56 auto item = m_TreeModel->item(itemIndex);
58 auto item = m_TreeModel->item(itemIndex);
57 if (!item || item->type() != selectionType) {
59 if (!item || item->type() != selectionType) {
58 // Incoherent multi selection
60 // Incoherent multi selection
59 selectionType = CatalogueAbstractTreeItem::DEFAULT_TYPE;
61 selectionType = CatalogueAbstractTreeItem::DEFAULT_TYPE;
60 break;
62 break;
61 }
63 }
62 }
64 }
63
65
64 return selectionType;
66 return selectionType;
65 }
67 }
66 }
68 }
67
69
68 QVector<std::shared_ptr<DBCatalogue> > selectedCatalogues(QTreeView *treeView) const
70 QVector<std::shared_ptr<DBCatalogue> > selectedCatalogues(QTreeView *treeView) const
69 {
71 {
70 QVector<std::shared_ptr<DBCatalogue> > catalogues;
72 QVector<std::shared_ptr<DBCatalogue> > catalogues;
71 auto selectedItems = treeView->selectionModel()->selectedRows();
73 auto selectedItems = treeView->selectionModel()->selectedRows();
72 for (auto itemIndex : selectedItems) {
74 for (auto itemIndex : selectedItems) {
73 auto item = m_TreeModel->item(itemIndex);
75 auto item = m_TreeModel->item(itemIndex);
74 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
76 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
75 catalogues.append(static_cast<CatalogueTreeItem *>(item)->catalogue());
77 catalogues.append(static_cast<CatalogueTreeItem *>(item)->catalogue());
76 }
78 }
77 }
79 }
78
80
79 return catalogues;
81 return catalogues;
80 }
82 }
81
83
82 QStringList selectedRepositories(QTreeView *treeView) const
84 QStringList selectedRepositories(QTreeView *treeView) const
83 {
85 {
84 QStringList repositories;
86 QStringList repositories;
85 auto selectedItems = treeView->selectionModel()->selectedRows();
87 auto selectedItems = treeView->selectionModel()->selectedRows();
86 for (auto itemIndex : selectedItems) {
88 for (auto itemIndex : selectedItems) {
87 auto item = m_TreeModel->item(itemIndex);
89 auto item = m_TreeModel->item(itemIndex);
88 if (item && item->type() == DATABASE_ITEM_TYPE) {
90 if (item && item->type() == DATABASE_ITEM_TYPE) {
89 repositories.append(item->text());
91 repositories.append(item->text());
90 }
92 }
91 }
93 }
92
94
93 return repositories;
95 return repositories;
94 }
96 }
95 };
97 };
96
98
97 CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent)
99 CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent)
98 : QWidget(parent),
100 : QWidget(parent),
99 ui(new Ui::CatalogueSideBarWidget),
101 ui(new Ui::CatalogueSideBarWidget),
100 impl{spimpl::make_unique_impl<CatalogueSideBarWidgetPrivate>()}
102 impl{spimpl::make_unique_impl<CatalogueSideBarWidgetPrivate>()}
101 {
103 {
102 ui->setupUi(this);
104 ui->setupUi(this);
103
105
104 impl->m_TreeModel = new CatalogueTreeModel(this);
106 impl->m_TreeModel = new CatalogueTreeModel(this);
105 ui->treeView->setModel(impl->m_TreeModel);
107 ui->treeView->setModel(impl->m_TreeModel);
106
108
107 impl->configureTreeWidget(ui->treeView);
109 impl->configureTreeWidget(ui->treeView);
108
110
109 ui->treeView->header()->setStretchLastSection(false);
111 ui->treeView->header()->setStretchLastSection(false);
110 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
112 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
111 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
113 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
112
114
113 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueSideBarWidget::emitSelection);
115 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueSideBarWidget::emitSelection);
114 connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this,
116 connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this,
115 &CatalogueSideBarWidget::emitSelection);
117 &CatalogueSideBarWidget::emitSelection);
116
118
117
119
118 connect(ui->btnAdd, &QToolButton::clicked, [this]() {
120 connect(ui->btnAdd, &QToolButton::clicked, [this]() {
119 auto catalogue = std::make_shared<DBCatalogue>();
121 auto catalogue = std::make_shared<DBCatalogue>();
120 catalogue->setName(QString("Cat"));
122 catalogue->setName(QString("Cat"));
121 sqpApp->catalogueController().addCatalogue(catalogue);
123 sqpApp->catalogueController().addCatalogue(catalogue);
122 auto item = this->addCatalogue(catalogue, REPOSITORY_DEFAULT);
124 auto item = this->addCatalogue(catalogue, REPOSITORY_DEFAULT);
123 this->setCatalogueChanges(catalogue, true);
125 this->setCatalogueChanges(catalogue, true);
124 ui->treeView->edit(impl->m_TreeModel->indexOf(item));
126 ui->treeView->edit(impl->m_TreeModel->indexOf(item));
125
127
126 });
128 });
127
129
128
130
129 connect(impl->m_TreeModel, &CatalogueTreeModel::itemDropped, [this](auto index) {
131 connect(impl->m_TreeModel, &CatalogueTreeModel::itemDropped,
130 auto item = impl->m_TreeModel->item(index);
132 [this](auto index, auto mimeData, auto action) {
131 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
133 auto item = impl->m_TreeModel->item(index);
132 auto catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
134 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
133 this->setCatalogueChanges(catalogue, true);
135 auto catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
134 }
136 this->setCatalogueChanges(catalogue, true);
135 });
137 }
138
139 if (action == Qt::MoveAction) {
140 /// Display a save button on source catalogues
141 auto sourceCatalogues = sqpApp->catalogueController().cataloguesForMimeData(
142 mimeData->data(MIME_TYPE_SOURCE_CATALOGUE_LIST));
143 for (auto catalogue : sourceCatalogues) {
144 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
145 this->setCatalogueChanges(catalogue, true);
146 }
147 }
148 }
149 });
150
136 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
151 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
137 QVector<QPair<std::shared_ptr<DBCatalogue>, CatalogueAbstractTreeItem *> >
152 QVector<QPair<std::shared_ptr<DBCatalogue>, CatalogueAbstractTreeItem *> >
138 cataloguesToItems;
153 cataloguesToItems;
139 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
154 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
140
155
141 for (auto index : selectedIndexes) {
156 for (auto index : selectedIndexes) {
142 auto item = impl->m_TreeModel->item(index);
157 auto item = impl->m_TreeModel->item(index);
143 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
158 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
144 auto catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
159 auto catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
145 cataloguesToItems << qMakePair(catalogue, item);
160 cataloguesToItems << qMakePair(catalogue, item);
146 }
161 }
147 }
162 }
148
163
149 if (!cataloguesToItems.isEmpty()) {
164 if (!cataloguesToItems.isEmpty()) {
150
165
151 if (QMessageBox::warning(this, tr("Remove Catalogue(s)"),
166 if (QMessageBox::warning(this, tr("Remove Catalogue(s)"),
152 tr("The selected catalogues(s) will be completly removed "
167 tr("The selected catalogues(s) will be completly removed "
153 "from the repository!\nAre you sure you want to continue?"),
168 "from the repository!\nAre you sure you want to continue?"),
154 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
169 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
155 == QMessageBox::Yes) {
170 == QMessageBox::Yes) {
156
171
157 for (auto catalogueToItem : cataloguesToItems) {
172 for (auto catalogueToItem : cataloguesToItems) {
158 sqpApp->catalogueController().removeCatalogue(catalogueToItem.first);
173 sqpApp->catalogueController().removeCatalogue(catalogueToItem.first);
159 impl->m_TreeModel->removeChildItem(
174 impl->m_TreeModel->removeChildItem(
160 catalogueToItem.second,
175 catalogueToItem.second,
161 impl->m_TreeModel->indexOf(catalogueToItem.second->parent()));
176 impl->m_TreeModel->indexOf(catalogueToItem.second->parent()));
162 }
177 }
163 }
178 }
164 }
179 }
165 });
180 });
166
181
167 connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [this](auto index) {
182 connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [this](auto index) {
168 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
183 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
169 if (selectedIndexes.contains(index)) {
184 if (selectedIndexes.contains(index)) {
170 this->emitSelection();
185 this->emitSelection();
171 }
186 }
172 impl->setHasChanges(true, index, this);
187 impl->setHasChanges(true, index, this);
173 });
188 });
174
189
175 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
190 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
176 connect(ui->treeView, &QTreeView::customContextMenuRequested, this,
191 connect(ui->treeView, &QTreeView::customContextMenuRequested, this,
177 &CatalogueSideBarWidget::onContextMenuRequested);
192 &CatalogueSideBarWidget::onContextMenuRequested);
178 }
193 }
179
194
180 CatalogueSideBarWidget::~CatalogueSideBarWidget()
195 CatalogueSideBarWidget::~CatalogueSideBarWidget()
181 {
196 {
182 delete ui;
197 delete ui;
183 }
198 }
184
199
185 CatalogueAbstractTreeItem *
200 CatalogueAbstractTreeItem *
186 CatalogueSideBarWidget::addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
201 CatalogueSideBarWidget::addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
187 const QString &repository)
202 const QString &repository)
188 {
203 {
189 auto repositoryItem = impl->getDatabaseItem(repository);
204 auto repositoryItem = impl->getDatabaseItem(repository);
190 return impl->addCatalogueItem(catalogue, impl->m_TreeModel->indexOf(repositoryItem));
205 return impl->addCatalogueItem(catalogue, impl->m_TreeModel->indexOf(repositoryItem));
191 }
206 }
192
207
193 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue,
208 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue,
194 bool hasChanges)
209 bool hasChanges)
195 {
210 {
196 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
211 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
197 auto index = impl->m_TreeModel->indexOf(catalogueItem);
212 auto index = impl->m_TreeModel->indexOf(catalogueItem);
198 impl->setHasChanges(hasChanges, index, this);
213 impl->setHasChanges(hasChanges, index, this);
199 // catalogueItem->refresh();
214 // catalogueItem->refresh();
200 }
215 }
201 }
216 }
202
217
203 QVector<std::shared_ptr<DBCatalogue> >
218 QVector<std::shared_ptr<DBCatalogue> >
204 CatalogueSideBarWidget::getCatalogues(const QString &repository) const
219 CatalogueSideBarWidget::getCatalogues(const QString &repository) const
205 {
220 {
206 QVector<std::shared_ptr<DBCatalogue> > result;
221 QVector<std::shared_ptr<DBCatalogue> > result;
207 auto repositoryItem = impl->getDatabaseItem(repository);
222 auto repositoryItem = impl->getDatabaseItem(repository);
208 for (auto child : repositoryItem->children()) {
223 for (auto child : repositoryItem->children()) {
209 if (child->type() == CATALOGUE_ITEM_TYPE) {
224 if (child->type() == CATALOGUE_ITEM_TYPE) {
210 auto catalogueItem = static_cast<CatalogueTreeItem *>(child);
225 auto catalogueItem = static_cast<CatalogueTreeItem *>(child);
211 result << catalogueItem->catalogue();
226 result << catalogueItem->catalogue();
212 }
227 }
213 else {
228 else {
214 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogues: invalid structure";
229 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogues: invalid structure";
215 }
230 }
216 }
231 }
217
232
218 return result;
233 return result;
219 }
234 }
220
235
221 void CatalogueSideBarWidget::emitSelection()
236 void CatalogueSideBarWidget::emitSelection()
222 {
237 {
223 auto selectionType = impl->selectionType(ui->treeView);
238 auto selectionType = impl->selectionType(ui->treeView);
224
239
225 switch (selectionType) {
240 switch (selectionType) {
226 case CATALOGUE_ITEM_TYPE:
241 case CATALOGUE_ITEM_TYPE:
227 emit this->catalogueSelected(impl->selectedCatalogues(ui->treeView));
242 emit this->catalogueSelected(impl->selectedCatalogues(ui->treeView));
228 break;
243 break;
229 case DATABASE_ITEM_TYPE:
244 case DATABASE_ITEM_TYPE:
230 emit this->databaseSelected(impl->selectedRepositories(ui->treeView));
245 emit this->databaseSelected(impl->selectedRepositories(ui->treeView));
231 break;
246 break;
232 case ALL_EVENT_ITEM_TYPE:
247 case ALL_EVENT_ITEM_TYPE:
233 emit this->allEventsSelected();
248 emit this->allEventsSelected();
234 break;
249 break;
235 case TRASH_ITEM_TYPE:
250 case TRASH_ITEM_TYPE:
236 emit this->trashSelected();
251 emit this->trashSelected();
237 break;
252 break;
238 default:
253 default:
239 emit this->selectionCleared();
254 emit this->selectionCleared();
240 break;
255 break;
241 }
256 }
242 }
257 }
243
258
244 void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos)
259 void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos)
245 {
260 {
246 QMenu menu{this};
261 QMenu menu{this};
247
262
248 auto currentIndex = ui->treeView->currentIndex();
263 auto currentIndex = ui->treeView->currentIndex();
249 auto currentItem = impl->m_TreeModel->item(currentIndex);
264 auto currentItem = impl->m_TreeModel->item(currentIndex);
250 if (!currentItem) {
265 if (!currentItem) {
251 return;
266 return;
252 }
267 }
253
268
254 switch (currentItem->type()) {
269 switch (currentItem->type()) {
255 case CATALOGUE_ITEM_TYPE:
270 case CATALOGUE_ITEM_TYPE:
256 menu.addAction("Rename", [this, currentIndex]() { ui->treeView->edit(currentIndex); });
271 menu.addAction("Rename", [this, currentIndex]() { ui->treeView->edit(currentIndex); });
257 break;
272 break;
258 case DATABASE_ITEM_TYPE:
273 case DATABASE_ITEM_TYPE:
259 break;
274 break;
260 case ALL_EVENT_ITEM_TYPE:
275 case ALL_EVENT_ITEM_TYPE:
261 break;
276 break;
262 case TRASH_ITEM_TYPE:
277 case TRASH_ITEM_TYPE:
263 menu.addAction("Empty Trash", []() {
278 menu.addAction("Empty Trash", []() {
264 // TODO
279 // TODO
265 });
280 });
266 break;
281 break;
267 default:
282 default:
268 break;
283 break;
269 }
284 }
270
285
271 if (!menu.isEmpty()) {
286 if (!menu.isEmpty()) {
272 menu.exec(ui->treeView->mapToGlobal(pos));
287 menu.exec(ui->treeView->mapToGlobal(pos));
273 }
288 }
274 }
289 }
275
290
276 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(QTreeView *treeView)
291 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(QTreeView *treeView)
277 {
292 {
278 auto allEventsItem = new CatalogueTextTreeItem{QIcon{":/icones/allEvents.png"}, "All Events",
293 auto allEventsItem = new CatalogueTextTreeItem{QIcon{":/icones/allEvents.png"}, "All Events",
279 ALL_EVENT_ITEM_TYPE};
294 ALL_EVENT_ITEM_TYPE};
280 auto allEventIndex = m_TreeModel->addTopLevelItem(allEventsItem);
295 auto allEventIndex = m_TreeModel->addTopLevelItem(allEventsItem);
281 treeView->setCurrentIndex(allEventIndex);
296 treeView->setCurrentIndex(allEventIndex);
282
297
283 auto trashItem
298 auto trashItem
284 = new CatalogueTextTreeItem{QIcon{":/icones/trash.png"}, "Trash", TRASH_ITEM_TYPE};
299 = new CatalogueTextTreeItem{QIcon{":/icones/trash.png"}, "Trash", TRASH_ITEM_TYPE};
285 m_TreeModel->addTopLevelItem(trashItem);
300 m_TreeModel->addTopLevelItem(trashItem);
286
301
287 auto separator = new QFrame{treeView};
302 auto separator = new QFrame{treeView};
288 separator->setFrameShape(QFrame::HLine);
303 separator->setFrameShape(QFrame::HLine);
289 auto separatorItem
304 auto separatorItem
290 = new CatalogueTextTreeItem{QIcon{}, QString{}, CatalogueAbstractTreeItem::DEFAULT_TYPE};
305 = new CatalogueTextTreeItem{QIcon{}, QString{}, CatalogueAbstractTreeItem::DEFAULT_TYPE};
291 separatorItem->setEnabled(false);
306 separatorItem->setEnabled(false);
292 auto separatorIndex = m_TreeModel->addTopLevelItem(separatorItem);
307 auto separatorIndex = m_TreeModel->addTopLevelItem(separatorItem);
293 treeView->setIndexWidget(separatorIndex, separator);
308 treeView->setIndexWidget(separatorIndex, separator);
294
309
295 auto repositories = sqpApp->catalogueController().getRepositories();
310 auto repositories = sqpApp->catalogueController().getRepositories();
296 for (auto dbname : repositories) {
311 for (auto dbname : repositories) {
297 auto dbIndex = addDatabaseItem(dbname);
312 auto dbIndex = addDatabaseItem(dbname);
298 auto catalogues = sqpApp->catalogueController().retrieveCatalogues(dbname);
313 auto catalogues = sqpApp->catalogueController().retrieveCatalogues(dbname);
299 for (auto catalogue : catalogues) {
314 for (auto catalogue : catalogues) {
300 addCatalogueItem(catalogue, dbIndex);
315 addCatalogueItem(catalogue, dbIndex);
301 }
316 }
302 }
317 }
303
318
304 treeView->expandAll();
319 treeView->expandAll();
305 }
320 }
306
321
307 QModelIndex
322 QModelIndex
308 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name)
323 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name)
309 {
324 {
310 auto databaseItem
325 auto databaseItem
311 = new CatalogueTextTreeItem{QIcon{":/icones/database.png"}, {name}, DATABASE_ITEM_TYPE};
326 = new CatalogueTextTreeItem{QIcon{":/icones/database.png"}, {name}, DATABASE_ITEM_TYPE};
312 auto databaseIndex = m_TreeModel->addTopLevelItem(databaseItem);
327 auto databaseIndex = m_TreeModel->addTopLevelItem(databaseItem);
313
328
314 return databaseIndex;
329 return databaseIndex;
315 }
330 }
316
331
317 CatalogueAbstractTreeItem *
332 CatalogueAbstractTreeItem *
318 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name)
333 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name)
319 {
334 {
320 for (auto item : m_TreeModel->topLevelItems()) {
335 for (auto item : m_TreeModel->topLevelItems()) {
321 if (item->type() == DATABASE_ITEM_TYPE && item->text() == name) {
336 if (item->type() == DATABASE_ITEM_TYPE && item->text() == name) {
322 return item;
337 return item;
323 }
338 }
324 }
339 }
325
340
326 return nullptr;
341 return nullptr;
327 }
342 }
328
343
329 CatalogueAbstractTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem(
344 CatalogueAbstractTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem(
330 const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex)
345 const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex)
331 {
346 {
332 auto catalogueItem
347 auto catalogueItem
333 = new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE};
348 = new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE};
334 m_TreeModel->addChildItem(catalogueItem, databaseIndex);
349 m_TreeModel->addChildItem(catalogueItem, databaseIndex);
335
350
336 return catalogueItem;
351 return catalogueItem;
337 }
352 }
338
353
339 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem(
354 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem(
340 const std::shared_ptr<DBCatalogue> &catalogue) const
355 const std::shared_ptr<DBCatalogue> &catalogue) const
341 {
356 {
342 for (auto item : m_TreeModel->topLevelItems()) {
357 for (auto item : m_TreeModel->topLevelItems()) {
343 if (item->type() == DATABASE_ITEM_TYPE) {
358 if (item->type() == DATABASE_ITEM_TYPE) {
344 for (auto childItem : item->children()) {
359 for (auto childItem : item->children()) {
345 if (childItem->type() == CATALOGUE_ITEM_TYPE) {
360 if (childItem->type() == CATALOGUE_ITEM_TYPE) {
346 auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem);
361 auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem);
347 if (catalogueItem->catalogue() == catalogue) {
362 if (catalogueItem->catalogue()->getUniqId() == catalogue->getUniqId()) {
348 return catalogueItem;
363 return catalogueItem;
349 }
364 }
350 }
365 }
351 else {
366 else {
352 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogueItem: Invalid tree "
367 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogueItem: Invalid tree "
353 "structure. A database item should "
368 "structure. A database item should "
354 "only contain catalogues.";
369 "only contain catalogues.";
355 Q_ASSERT(false);
370 Q_ASSERT(false);
356 }
371 }
357 }
372 }
358 }
373 }
359 }
374 }
360
375
361 return nullptr;
376 return nullptr;
362 }
377 }
363
378
364 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(
379 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(
365 bool value, const QModelIndex &index, CatalogueSideBarWidget *sideBarWidget)
380 bool value, const QModelIndex &index, CatalogueSideBarWidget *sideBarWidget)
366 {
381 {
367 std::shared_ptr<DBCatalogue> catalogue = nullptr;
382 std::shared_ptr<DBCatalogue> catalogue = nullptr;
368 auto item = m_TreeModel->item(index);
383 auto item = m_TreeModel->item(index);
369 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
384 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
370 catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
385 catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
371 }
386 }
372
387
373 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
388 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
374 if (value) {
389 if (value) {
375 if (!hasChanges(validationIndex, sideBarWidget->ui->treeView)) {
390 if (!hasChanges(validationIndex, sideBarWidget->ui->treeView)) {
376 auto widget = CatalogueExplorerHelper::buildValidationWidget(
391 auto widget = CatalogueExplorerHelper::buildValidationWidget(
377 sideBarWidget->ui->treeView,
392 sideBarWidget->ui->treeView,
378 [this, validationIndex, sideBarWidget, catalogue]() {
393 [this, validationIndex, sideBarWidget, catalogue]() {
379 if (catalogue) {
394 if (catalogue) {
380 sqpApp->catalogueController().saveCatalogue(catalogue);
395 sqpApp->catalogueController().saveCatalogue(catalogue);
381 }
396 }
382 setHasChanges(false, validationIndex, sideBarWidget);
397 setHasChanges(false, validationIndex, sideBarWidget);
383 },
398 },
384 [this, validationIndex, sideBarWidget, catalogue, item]() {
399 [this, validationIndex, sideBarWidget, catalogue, item]() {
385 if (catalogue) {
400 if (catalogue) {
386 bool removed;
401 bool removed;
387 sqpApp->catalogueController().discardCatalogue(catalogue, removed);
402 sqpApp->catalogueController().discardCatalogue(catalogue, removed);
388
403
389 if (removed) {
404 if (removed) {
390 m_TreeModel->removeChildItem(item,
405 m_TreeModel->removeChildItem(item,
391 m_TreeModel->indexOf(item->parent()));
406 m_TreeModel->indexOf(item->parent()));
392 }
407 }
393 else {
408 else {
394 m_TreeModel->refresh(m_TreeModel->indexOf(item));
409 m_TreeModel->refresh(m_TreeModel->indexOf(item));
395 setHasChanges(false, validationIndex, sideBarWidget);
410 setHasChanges(false, validationIndex, sideBarWidget);
396 }
411 }
397 sideBarWidget->emitSelection();
412 sideBarWidget->emitSelection();
398 }
413 }
399 });
414 });
400 sideBarWidget->ui->treeView->setIndexWidget(validationIndex, widget);
415 sideBarWidget->ui->treeView->setIndexWidget(validationIndex, widget);
401 }
416 }
402 }
417 }
403 else {
418 else {
404 // Note: the widget is destroyed
419 // Note: the widget is destroyed
405 sideBarWidget->ui->treeView->setIndexWidget(validationIndex, nullptr);
420 sideBarWidget->ui->treeView->setIndexWidget(validationIndex, nullptr);
406 }
421 }
407 }
422 }
408
423
409 bool CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::hasChanges(const QModelIndex &index,
424 bool CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::hasChanges(const QModelIndex &index,
410 QTreeView *treeView)
425 QTreeView *treeView)
411 {
426 {
412 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
427 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
413 return treeView->indexWidget(validationIndex) != nullptr;
428 return treeView->indexWidget(validationIndex) != nullptr;
414 }
429 }
@@ -1,105 +1,129
1 #include "Catalogue/CatalogueTreeItems/CatalogueTreeItem.h"
1 #include "Catalogue/CatalogueTreeItems/CatalogueTreeItem.h"
2 #include <Catalogue/CatalogueExplorerHelper.h>
2 #include <Catalogue/CatalogueExplorerHelper.h>
3
3
4 #include <Catalogue/CatalogueController.h>
4 #include <Catalogue/CatalogueController.h>
5 #include <Common/MimeTypesDef.h>
5 #include <Common/MimeTypesDef.h>
6 #include <QIcon>
6 #include <QIcon>
7 #include <QMimeData>
7 #include <QMimeData>
8 #include <SqpApplication.h>
8 #include <SqpApplication.h>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 #include <DBCatalogue.h>
12 #include <DBCatalogue.h>
13
13
14 struct CatalogueTreeItem::CatalogueTreeItemPrivate {
14 struct CatalogueTreeItem::CatalogueTreeItemPrivate {
15
15
16 std::shared_ptr<DBCatalogue> m_Catalogue;
16 std::shared_ptr<DBCatalogue> m_Catalogue;
17 QIcon m_Icon;
17 QIcon m_Icon;
18
18
19 CatalogueTreeItemPrivate(std::shared_ptr<DBCatalogue> catalogue, const QIcon &icon)
19 CatalogueTreeItemPrivate(std::shared_ptr<DBCatalogue> catalogue, const QIcon &icon)
20 : m_Catalogue(catalogue), m_Icon(icon)
20 : m_Catalogue(catalogue), m_Icon(icon)
21 {
21 {
22 }
22 }
23 };
23 };
24
24
25
25
26 CatalogueTreeItem::CatalogueTreeItem(std::shared_ptr<DBCatalogue> catalogue, const QIcon &icon,
26 CatalogueTreeItem::CatalogueTreeItem(std::shared_ptr<DBCatalogue> catalogue, const QIcon &icon,
27 int type)
27 int type)
28 : CatalogueAbstractTreeItem(type),
28 : CatalogueAbstractTreeItem(type),
29 impl{spimpl::make_unique_impl<CatalogueTreeItemPrivate>(catalogue, icon)}
29 impl{spimpl::make_unique_impl<CatalogueTreeItemPrivate>(catalogue, icon)}
30 {
30 {
31 }
31 }
32
32
33 QVariant CatalogueTreeItem::data(int column, int role) const
33 QVariant CatalogueTreeItem::data(int column, int role) const
34 {
34 {
35 if (column == 0) {
35 if (column == 0) {
36 switch (role) {
36 switch (role) {
37 case Qt::EditRole: // fallthrough
37 case Qt::EditRole: // fallthrough
38 case Qt::DisplayRole:
38 case Qt::DisplayRole:
39 return impl->m_Catalogue->getName();
39 return impl->m_Catalogue->getName();
40 case Qt::DecorationRole:
40 case Qt::DecorationRole:
41 return impl->m_Icon;
41 return impl->m_Icon;
42 default:
42 default:
43 break;
43 break;
44 }
44 }
45 }
45 }
46
46
47 return QVariant();
47 return QVariant();
48 }
48 }
49
49
50 bool CatalogueTreeItem::setData(int column, int role, const QVariant &value)
50 bool CatalogueTreeItem::setData(int column, int role, const QVariant &value)
51 {
51 {
52 bool result = false;
52 bool result = false;
53
53
54 if (role == Qt::EditRole && column == 0) {
54 if (role == Qt::EditRole && column == 0) {
55 auto newName = value.toString();
55 auto newName = value.toString();
56 if (newName != impl->m_Catalogue->getName()) {
56 if (newName != impl->m_Catalogue->getName()) {
57 impl->m_Catalogue->setName(newName);
57 impl->m_Catalogue->setName(newName);
58 sqpApp->catalogueController().updateCatalogue(impl->m_Catalogue);
58 sqpApp->catalogueController().updateCatalogue(impl->m_Catalogue);
59 result = true;
59 result = true;
60 }
60 }
61 }
61 }
62
62
63 return result;
63 return result;
64 }
64 }
65
65
66 Qt::ItemFlags CatalogueTreeItem::flags(int column) const
66 Qt::ItemFlags CatalogueTreeItem::flags(int column) const
67 {
67 {
68 if (column == 0) {
68 if (column == 0) {
69 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable
69 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable
70 | Qt::ItemIsDropEnabled;
70 | Qt::ItemIsDropEnabled;
71 }
71 }
72 else {
72 else {
73 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
73 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
74 }
74 }
75 }
75 }
76
76
77 bool CatalogueTreeItem::canDropMimeData(const QMimeData *data, Qt::DropAction action)
77 bool CatalogueTreeItem::canDropMimeData(const QMimeData *data, Qt::DropAction action)
78 {
78 {
79 // Check that the event is not dropped on the same catalogue
80 auto sourceCatalogues = sqpApp->catalogueController().cataloguesForMimeData(
81 data->data(MIME_TYPE_SOURCE_CATALOGUE_LIST));
82 for (auto catalogue : sourceCatalogues) {
83 if (catalogue->getUniqId() == impl->m_Catalogue->getUniqId()) {
84 return false;
85 }
86 }
87
79 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
88 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
80 auto canDrop = data->hasFormat(MIME_TYPE_EVENT_LIST);
89 auto canDrop = data->hasFormat(MIME_TYPE_EVENT_LIST);
81
90
82 for (auto event : events) {
91 for (auto event : events) {
83 canDrop &= (event->getRepository() == impl->m_Catalogue->getRepository());
92 canDrop &= (event->getRepository() == impl->m_Catalogue->getRepository());
84 }
93 }
94
85 return canDrop;
95 return canDrop;
86 }
96 }
87
97
88 bool CatalogueTreeItem::dropMimeData(const QMimeData *data, Qt::DropAction action)
98 bool CatalogueTreeItem::dropMimeData(const QMimeData *data, Qt::DropAction action)
89 {
99 {
90 Q_ASSERT(canDropMimeData(data, action));
100 Q_ASSERT(canDropMimeData(data, action));
91 // Warning: Check that the events aren't already in the catalogue
101 // Warning: Check that the events aren't already in the catalogue
92 // Also check for the repository !!!
102 // No need to check check for the repository: inter-repository drop is forbidden in
103 // canDropMimeData
93
104
94 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
105 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
106 auto sourceCatalogues = sqpApp->catalogueController().cataloguesForMimeData(
107 data->data(MIME_TYPE_SOURCE_CATALOGUE_LIST));
95
108
96 for (auto event : events) {
109 for (auto event : events) {
110
111 if (action == Qt::MoveAction) {
112 for (auto catalogue : sourceCatalogues) {
113 catalogue->removeEvent(event->getUniqId());
114 }
115 }
116
97 impl->m_Catalogue->addEvent(event->getUniqId());
117 impl->m_Catalogue->addEvent(event->getUniqId());
98 sqpApp->catalogueController().updateCatalogue(impl->m_Catalogue);
99 }
118 }
119
120 for (auto catalogue : sourceCatalogues) {
121 sqpApp->catalogueController().updateCatalogue(catalogue);
122 }
123 sqpApp->catalogueController().updateCatalogue(impl->m_Catalogue);
100 }
124 }
101
125
102 std::shared_ptr<DBCatalogue> CatalogueTreeItem::catalogue() const
126 std::shared_ptr<DBCatalogue> CatalogueTreeItem::catalogue() const
103 {
127 {
104 return impl->m_Catalogue;
128 return impl->m_Catalogue;
105 }
129 }
@@ -1,218 +1,219
1 #include "Catalogue/CatalogueTreeModel.h"
1 #include "Catalogue/CatalogueTreeModel.h"
2 #include <Catalogue/CatalogueTreeItems/CatalogueAbstractTreeItem.h>
2 #include <Catalogue/CatalogueTreeItems/CatalogueAbstractTreeItem.h>
3
3
4 #include <QMimeData>
4 #include <QMimeData>
5 #include <memory>
5 #include <memory>
6
6
7 #include <Common/MimeTypesDef.h>
7 #include <Common/MimeTypesDef.h>
8
8
9 struct CatalogueTreeModel::CatalogueTreeModelPrivate {
9 struct CatalogueTreeModel::CatalogueTreeModelPrivate {
10 std::unique_ptr<CatalogueAbstractTreeItem> m_RootItem = nullptr;
10 std::unique_ptr<CatalogueAbstractTreeItem> m_RootItem = nullptr;
11
11
12 CatalogueTreeModelPrivate() : m_RootItem{std::make_unique<CatalogueAbstractTreeItem>()} {}
12 CatalogueTreeModelPrivate() : m_RootItem{std::make_unique<CatalogueAbstractTreeItem>()} {}
13 };
13 };
14
14
15 CatalogueTreeModel::CatalogueTreeModel(QObject *parent)
15 CatalogueTreeModel::CatalogueTreeModel(QObject *parent)
16 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueTreeModelPrivate>()}
16 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueTreeModelPrivate>()}
17 {
17 {
18 }
18 }
19
19
20 QModelIndex CatalogueTreeModel::addTopLevelItem(CatalogueAbstractTreeItem *item)
20 QModelIndex CatalogueTreeModel::addTopLevelItem(CatalogueAbstractTreeItem *item)
21 {
21 {
22 auto nbTopLevelItems = impl->m_RootItem->children().count();
22 auto nbTopLevelItems = impl->m_RootItem->children().count();
23 beginInsertRows(QModelIndex(), nbTopLevelItems, nbTopLevelItems);
23 beginInsertRows(QModelIndex(), nbTopLevelItems, nbTopLevelItems);
24 impl->m_RootItem->addChild(item);
24 impl->m_RootItem->addChild(item);
25 endInsertRows();
25 endInsertRows();
26
26
27 emit dataChanged(QModelIndex(), QModelIndex());
27 emit dataChanged(QModelIndex(), QModelIndex());
28
28
29 return index(nbTopLevelItems, 0);
29 return index(nbTopLevelItems, 0);
30 }
30 }
31
31
32 QVector<CatalogueAbstractTreeItem *> CatalogueTreeModel::topLevelItems() const
32 QVector<CatalogueAbstractTreeItem *> CatalogueTreeModel::topLevelItems() const
33 {
33 {
34 return impl->m_RootItem->children();
34 return impl->m_RootItem->children();
35 }
35 }
36
36
37 void CatalogueTreeModel::addChildItem(CatalogueAbstractTreeItem *child,
37 void CatalogueTreeModel::addChildItem(CatalogueAbstractTreeItem *child,
38 const QModelIndex &parentIndex)
38 const QModelIndex &parentIndex)
39 {
39 {
40 auto parentItem = item(parentIndex);
40 auto parentItem = item(parentIndex);
41 int c = parentItem->children().count();
41 int c = parentItem->children().count();
42 beginInsertRows(parentIndex, c, c);
42 beginInsertRows(parentIndex, c, c);
43 parentItem->addChild(child);
43 parentItem->addChild(child);
44 endInsertRows();
44 endInsertRows();
45
45
46 emit dataChanged(parentIndex, parentIndex);
46 emit dataChanged(parentIndex, parentIndex);
47 }
47 }
48
48
49 void CatalogueTreeModel::removeChildItem(CatalogueAbstractTreeItem *child,
49 void CatalogueTreeModel::removeChildItem(CatalogueAbstractTreeItem *child,
50 const QModelIndex &parentIndex)
50 const QModelIndex &parentIndex)
51 {
51 {
52 auto parentItem = item(parentIndex);
52 auto parentItem = item(parentIndex);
53 int i = parentItem->children().indexOf(child);
53 int i = parentItem->children().indexOf(child);
54 beginRemoveRows(parentIndex, i, i);
54 beginRemoveRows(parentIndex, i, i);
55 parentItem->removeChild(child);
55 parentItem->removeChild(child);
56 endRemoveRows();
56 endRemoveRows();
57
57
58 emit dataChanged(parentIndex, parentIndex);
58 emit dataChanged(parentIndex, parentIndex);
59 }
59 }
60
60
61 void CatalogueTreeModel::refresh(const QModelIndex &index)
61 void CatalogueTreeModel::refresh(const QModelIndex &index)
62 {
62 {
63 emit dataChanged(index, index);
63 emit dataChanged(index, index);
64 }
64 }
65
65
66 CatalogueAbstractTreeItem *CatalogueTreeModel::item(const QModelIndex &index) const
66 CatalogueAbstractTreeItem *CatalogueTreeModel::item(const QModelIndex &index) const
67 {
67 {
68 return static_cast<CatalogueAbstractTreeItem *>(index.internalPointer());
68 return static_cast<CatalogueAbstractTreeItem *>(index.internalPointer());
69 }
69 }
70
70
71 QModelIndex CatalogueTreeModel::indexOf(CatalogueAbstractTreeItem *item, int column) const
71 QModelIndex CatalogueTreeModel::indexOf(CatalogueAbstractTreeItem *item, int column) const
72 {
72 {
73 auto parentItem = item->parent();
73 auto parentItem = item->parent();
74 if (!parentItem) {
74 if (!parentItem) {
75 return QModelIndex();
75 return QModelIndex();
76 }
76 }
77
77
78 auto row = parentItem->children().indexOf(item);
78 auto row = parentItem->children().indexOf(item);
79 return createIndex(row, column, item);
79 return createIndex(row, column, item);
80 }
80 }
81
81
82 QModelIndex CatalogueTreeModel::index(int row, int column, const QModelIndex &parent) const
82 QModelIndex CatalogueTreeModel::index(int row, int column, const QModelIndex &parent) const
83 {
83 {
84 if (column > 0) {
84 if (column > 0) {
85 int a = 0;
85 int a = 0;
86 }
86 }
87
87
88 if (!hasIndex(row, column, parent)) {
88 if (!hasIndex(row, column, parent)) {
89 return QModelIndex();
89 return QModelIndex();
90 }
90 }
91
91
92 CatalogueAbstractTreeItem *parentItem = nullptr;
92 CatalogueAbstractTreeItem *parentItem = nullptr;
93
93
94 if (!parent.isValid()) {
94 if (!parent.isValid()) {
95 parentItem = impl->m_RootItem.get();
95 parentItem = impl->m_RootItem.get();
96 }
96 }
97 else {
97 else {
98 parentItem = item(parent);
98 parentItem = item(parent);
99 }
99 }
100
100
101 auto childItem = parentItem->children().value(row);
101 auto childItem = parentItem->children().value(row);
102 if (childItem) {
102 if (childItem) {
103 return createIndex(row, column, childItem);
103 return createIndex(row, column, childItem);
104 }
104 }
105
105
106 return QModelIndex();
106 return QModelIndex();
107 }
107 }
108
108
109
109
110 QModelIndex CatalogueTreeModel::parent(const QModelIndex &index) const
110 QModelIndex CatalogueTreeModel::parent(const QModelIndex &index) const
111 {
111 {
112 if (!index.isValid()) {
112 if (!index.isValid()) {
113 return QModelIndex();
113 return QModelIndex();
114 }
114 }
115
115
116 auto childItem = item(index);
116 auto childItem = item(index);
117 auto parentItem = childItem->parent();
117 auto parentItem = childItem->parent();
118
118
119 if (parentItem == nullptr || parentItem->parent() == nullptr) {
119 if (parentItem == nullptr || parentItem->parent() == nullptr) {
120 return QModelIndex();
120 return QModelIndex();
121 }
121 }
122
122
123 auto row = parentItem->parent()->children().indexOf(parentItem);
123 auto row = parentItem->parent()->children().indexOf(parentItem);
124 return createIndex(row, 0, parentItem);
124 return createIndex(row, 0, parentItem);
125 }
125 }
126
126
127 int CatalogueTreeModel::rowCount(const QModelIndex &parent) const
127 int CatalogueTreeModel::rowCount(const QModelIndex &parent) const
128 {
128 {
129 CatalogueAbstractTreeItem *parentItem = nullptr;
129 CatalogueAbstractTreeItem *parentItem = nullptr;
130
130
131 if (!parent.isValid()) {
131 if (!parent.isValid()) {
132 parentItem = impl->m_RootItem.get();
132 parentItem = impl->m_RootItem.get();
133 }
133 }
134 else {
134 else {
135 parentItem = item(parent);
135 parentItem = item(parent);
136 }
136 }
137
137
138 return parentItem->children().count();
138 return parentItem->children().count();
139 }
139 }
140
140
141 int CatalogueTreeModel::columnCount(const QModelIndex &parent) const
141 int CatalogueTreeModel::columnCount(const QModelIndex &parent) const
142 {
142 {
143 return (int)Column::Count;
143 return (int)Column::Count;
144 }
144 }
145
145
146 Qt::ItemFlags CatalogueTreeModel::flags(const QModelIndex &index) const
146 Qt::ItemFlags CatalogueTreeModel::flags(const QModelIndex &index) const
147 {
147 {
148 auto treeItem = item(index);
148 auto treeItem = item(index);
149 if (treeItem) {
149 if (treeItem) {
150 return treeItem->flags(index.column());
150 return treeItem->flags(index.column());
151 }
151 }
152
152
153 return Qt::NoItemFlags;
153 return Qt::NoItemFlags;
154 }
154 }
155
155
156 QVariant CatalogueTreeModel::data(const QModelIndex &index, int role) const
156 QVariant CatalogueTreeModel::data(const QModelIndex &index, int role) const
157 {
157 {
158 auto treeItem = item(index);
158 auto treeItem = item(index);
159 if (treeItem) {
159 if (treeItem) {
160 return treeItem->data(index.column(), role);
160 return treeItem->data(index.column(), role);
161 }
161 }
162
162
163 return QModelIndex();
163 return QModelIndex();
164 }
164 }
165
165
166 bool CatalogueTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
166 bool CatalogueTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
167 {
167 {
168 auto treeItem = item(index);
168 auto treeItem = item(index);
169 if (treeItem) {
169 if (treeItem) {
170 auto result = treeItem->setData(index.column(), role, value);
170 auto result = treeItem->setData(index.column(), role, value);
171
171
172 if (result && index.column() == (int)Column::Name) {
172 if (result && index.column() == (int)Column::Name) {
173 emit itemRenamed(index);
173 emit itemRenamed(index);
174 }
174 }
175
175
176 return result;
176 return result;
177 }
177 }
178
178
179 return false;
179 return false;
180 }
180 }
181
181 bool CatalogueTreeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
182 bool CatalogueTreeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
182 int column, const QModelIndex &parent) const
183 int column, const QModelIndex &parent) const
183 {
184 {
184 auto draggedIndex = parent;
185 auto draggedIndex = parent;
185 auto draggedItem = item(draggedIndex);
186 auto draggedItem = item(draggedIndex);
186 if (draggedItem) {
187 if (draggedItem) {
187 return draggedItem->canDropMimeData(data, action);
188 return draggedItem->canDropMimeData(data, action);
188 }
189 }
189
190
190 return false;
191 return false;
191 }
192 }
192
193
193 bool CatalogueTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row,
194 bool CatalogueTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row,
194 int column, const QModelIndex &parent)
195 int column, const QModelIndex &parent)
195 {
196 {
196 bool result = false;
197 bool result = false;
197
198
198 auto draggedIndex = parent;
199 auto draggedIndex = parent;
199 auto draggedItem = item(draggedIndex);
200 auto draggedItem = item(draggedIndex);
200 if (draggedItem) {
201 if (draggedItem) {
201 result = draggedItem->dropMimeData(data, action);
202 result = draggedItem->dropMimeData(data, action);
202 if (result) {
203 if (result) {
203 emit itemDropped(draggedIndex);
204 emit itemDropped(draggedIndex, data, action);
204 }
205 }
205 }
206 }
206
207
207 return result;
208 return result;
208 }
209 }
209
210
210 Qt::DropActions CatalogueTreeModel::supportedDropActions() const
211 Qt::DropActions CatalogueTreeModel::supportedDropActions() const
211 {
212 {
212 return Qt::CopyAction | Qt::MoveAction;
213 return Qt::CopyAction | Qt::MoveAction;
213 }
214 }
214
215
215 QStringList CatalogueTreeModel::mimeTypes() const
216 QStringList CatalogueTreeModel::mimeTypes() const
216 {
217 {
217 return {MIME_TYPE_EVENT_LIST};
218 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_SOURCE_CATALOGUE_LIST};
218 }
219 }
General Comments 0
You need to be logged in to leave comments. Login now