##// END OF EJS Templates
Add discard method for event
perrinel -
r1298:85d482a16060
parent child
Show More
@@ -1,82 +1,83
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 std::list<std::shared_ptr<DBEvent> >
44 std::list<std::shared_ptr<DBEvent> >
45 retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const;
45 retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const;
46 void addEvent(std::shared_ptr<DBEvent> event);
46 void addEvent(std::shared_ptr<DBEvent> event);
47 void updateEvent(std::shared_ptr<DBEvent> event);
47 void updateEvent(std::shared_ptr<DBEvent> event);
48 void updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct);
48 void updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct);
49 void removeEvent(std::shared_ptr<DBEvent> event);
49 void removeEvent(std::shared_ptr<DBEvent> event);
50 // void trashEvent(std::shared_ptr<DBEvent> event);
50 // void trashEvent(std::shared_ptr<DBEvent> event);
51 // void restore(QUuid eventId);
51 // void restore(std::shared_ptr<DBEvent> event);
52 void saveEvent(std::shared_ptr<DBEvent> event);
52 void saveEvent(std::shared_ptr<DBEvent> event);
53 void discardEvent(std::shared_ptr<DBEvent> event);
53 bool eventHasChanges(std::shared_ptr<DBEvent> event) const;
54 bool eventHasChanges(std::shared_ptr<DBEvent> event) const;
54
55
55 // Catalogue
56 // Catalogue
56 // bool createCatalogue(const QString &name, QVector<QUuid> eventList);
57 // bool createCatalogue(const QString &name, QVector<QUuid> eventList);
57 /// retrieveEvents with empty repository retrieve them from the default repository
58 /// retrieveEvents with empty repository retrieve them from the default repository
58 std::list<std::shared_ptr<DBCatalogue> > retrieveCatalogues(const QString &repository
59 std::list<std::shared_ptr<DBCatalogue> > retrieveCatalogues(const QString &repository
59 = QString()) const;
60 = QString()) const;
60 void updateCatalogue(std::shared_ptr<DBCatalogue> catalogue);
61 void updateCatalogue(std::shared_ptr<DBCatalogue> catalogue);
61 void removeCatalogue(std::shared_ptr<DBCatalogue> catalogue);
62 void removeCatalogue(std::shared_ptr<DBCatalogue> catalogue);
62 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue);
63 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue);
63
64
64 void saveAll();
65 void saveAll();
65 bool hasChanges() const;
66 bool hasChanges() const;
66
67
67 /// Returns the MIME data associated to a list of variables
68 /// Returns the MIME data associated to a list of variables
68 QByteArray mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const;
69 QByteArray mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const;
69
70
70 /// Returns the list of variables contained in a MIME data
71 /// Returns the list of variables contained in a MIME data
71 QVector<std::shared_ptr<DBEvent> > eventsForMimeData(const QByteArray &mimeData) const;
72 QVector<std::shared_ptr<DBEvent> > eventsForMimeData(const QByteArray &mimeData) const;
72
73
73 public slots:
74 public slots:
74 /// Manage init/end of the controller
75 /// Manage init/end of the controller
75 void initialize();
76 void initialize();
76
77
77 private:
78 private:
78 class CatalogueControllerPrivate;
79 class CatalogueControllerPrivate;
79 spimpl::unique_impl_ptr<CatalogueControllerPrivate> impl;
80 spimpl::unique_impl_ptr<CatalogueControllerPrivate> impl;
80 };
81 };
81
82
82 #endif // SCIQLOP_CATALOGUECONTROLLER_H
83 #endif // SCIQLOP_CATALOGUECONTROLLER_H
@@ -1,389 +1,409
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 class CatalogueController::CatalogueControllerPrivate {
30 class CatalogueController::CatalogueControllerPrivate {
31
31
32 public:
32 public:
33 explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {}
33 explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {}
34
34
35 CatalogueDao m_CatalogueDao;
35 CatalogueDao m_CatalogueDao;
36
36
37 QStringList m_RepositoryList;
37 QStringList m_RepositoryList;
38 CatalogueController *m_Q;
38 CatalogueController *m_Q;
39
39
40 QSet<QString> m_EventKeysWithChanges;
40 QSet<QString> m_EventKeysWithChanges;
41
41
42 QString eventUniqueKey(const std::shared_ptr<DBEvent> &event) const;
42 QString eventUniqueKey(const std::shared_ptr<DBEvent> &event) const;
43
43
44 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
44 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
45 QString toWorkRepository(QString repository);
45 QString toWorkRepository(QString repository);
46 QString toSyncRepository(QString repository);
46 QString toSyncRepository(QString repository);
47 void savAllDB();
47 void savAllDB();
48
48
49 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
49 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
50 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
50 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
51 };
51 };
52
52
53 CatalogueController::CatalogueController(QObject *parent)
53 CatalogueController::CatalogueController(QObject *parent)
54 : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)}
54 : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)}
55 {
55 {
56 qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction")
56 qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction")
57 << QThread::currentThread();
57 << QThread::currentThread();
58 }
58 }
59
59
60 CatalogueController::~CatalogueController()
60 CatalogueController::~CatalogueController()
61 {
61 {
62 qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction")
62 qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction")
63 << QThread::currentThread();
63 << QThread::currentThread();
64 }
64 }
65
65
66 QStringList CatalogueController::getRepositories() const
66 QStringList CatalogueController::getRepositories() const
67 {
67 {
68 return impl->m_RepositoryList;
68 return impl->m_RepositoryList;
69 }
69 }
70
70
71 void CatalogueController::addDB(const QString &dbPath)
71 void CatalogueController::addDB(const QString &dbPath)
72 {
72 {
73 QDir dbDir(dbPath);
73 QDir dbDir(dbPath);
74 if (dbDir.exists()) {
74 if (dbDir.exists()) {
75 auto dirName = dbDir.dirName();
75 auto dirName = dbDir.dirName();
76
76
77 if (std::find(impl->m_RepositoryList.cbegin(), impl->m_RepositoryList.cend(), dirName)
77 if (std::find(impl->m_RepositoryList.cbegin(), impl->m_RepositoryList.cend(), dirName)
78 != impl->m_RepositoryList.cend()) {
78 != impl->m_RepositoryList.cend()) {
79 qCCritical(LOG_CatalogueController())
79 qCCritical(LOG_CatalogueController())
80 << tr("Impossible to addDB that is already loaded");
80 << tr("Impossible to addDB that is already loaded");
81 }
81 }
82
82
83 if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) {
83 if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) {
84 qCCritical(LOG_CatalogueController())
84 qCCritical(LOG_CatalogueController())
85 << tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath);
85 << tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath);
86 }
86 }
87 else {
87 else {
88 impl->m_RepositoryList << dirName;
88 impl->m_RepositoryList << dirName;
89 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
89 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
90 }
90 }
91 }
91 }
92 else {
92 else {
93 qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ")
93 qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ")
94 << dbPath;
94 << dbPath;
95 }
95 }
96 }
96 }
97
97
98 void CatalogueController::saveDB(const QString &destinationPath, const QString &repository)
98 void CatalogueController::saveDB(const QString &destinationPath, const QString &repository)
99 {
99 {
100 if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) {
100 if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) {
101 qCCritical(LOG_CatalogueController())
101 qCCritical(LOG_CatalogueController())
102 << tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath);
102 << tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath);
103 }
103 }
104 }
104 }
105
105
106 std::list<std::shared_ptr<DBEvent> >
106 std::list<std::shared_ptr<DBEvent> >
107 CatalogueController::retrieveEvents(const QString &repository) const
107 CatalogueController::retrieveEvents(const QString &repository) const
108 {
108 {
109 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
109 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
110
110
111 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
111 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
112 auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName));
112 auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName));
113 for (auto event : events) {
113 for (auto event : events) {
114 eventsShared.push_back(std::make_shared<DBEvent>(event));
114 eventsShared.push_back(std::make_shared<DBEvent>(event));
115 }
115 }
116 return eventsShared;
116 return eventsShared;
117 }
117 }
118
118
119 std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const
119 std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const
120 {
120 {
121 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
121 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
122 for (auto repository : impl->m_RepositoryList) {
122 for (auto repository : impl->m_RepositoryList) {
123 eventsShared.splice(eventsShared.end(), retrieveEvents(repository));
123 eventsShared.splice(eventsShared.end(), retrieveEvents(repository));
124 }
124 }
125
125
126 return eventsShared;
126 return eventsShared;
127 }
127 }
128
128
129 std::list<std::shared_ptr<DBEvent> >
129 std::list<std::shared_ptr<DBEvent> >
130 CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const
130 CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const
131 {
131 {
132 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
132 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
133 auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue);
133 auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue);
134 for (auto event : events) {
134 for (auto event : events) {
135 eventsShared.push_back(std::make_shared<DBEvent>(event));
135 eventsShared.push_back(std::make_shared<DBEvent>(event));
136 }
136 }
137 return eventsShared;
137 return eventsShared;
138 }
138 }
139
139
140 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
140 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
141 {
141 {
142 event->setRepository(impl->toWorkRepository(event->getRepository()));
142 event->setRepository(impl->toWorkRepository(event->getRepository()));
143
143
144 auto uniqueId = impl->eventUniqueKey(event);
144 auto uniqueId = impl->eventUniqueKey(event);
145 impl->m_EventKeysWithChanges.insert(uniqueId);
145 impl->m_EventKeysWithChanges.insert(uniqueId);
146
146
147 impl->m_CatalogueDao.updateEvent(*event);
147 impl->m_CatalogueDao.updateEvent(*event);
148 }
148 }
149
149
150 void CatalogueController::updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct)
150 void CatalogueController::updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct)
151 {
151 {
152 impl->m_CatalogueDao.updateEventProduct(*eventProduct);
152 impl->m_CatalogueDao.updateEventProduct(*eventProduct);
153 }
153 }
154
154
155 void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event)
155 void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event)
156 {
156 {
157 // Remove it from both repository and repository_work
157 // Remove it from both repository and repository_work
158 event->setRepository(impl->toWorkRepository(event->getRepository()));
158 event->setRepository(impl->toWorkRepository(event->getRepository()));
159 impl->m_CatalogueDao.removeEvent(*event);
159 impl->m_CatalogueDao.removeEvent(*event);
160 event->setRepository(impl->toSyncRepository(event->getRepository()));
160 event->setRepository(impl->toSyncRepository(event->getRepository()));
161 impl->m_CatalogueDao.removeEvent(*event);
161 impl->m_CatalogueDao.removeEvent(*event);
162 impl->savAllDB();
162 impl->savAllDB();
163 }
163 }
164
164
165 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
165 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
166 {
166 {
167 event->setRepository(impl->toWorkRepository(event->getRepository()));
167 event->setRepository(impl->toWorkRepository(event->getRepository()));
168
168
169 auto eventTemp = *event;
169 auto eventTemp = *event;
170 impl->m_CatalogueDao.addEvent(eventTemp);
170 impl->m_CatalogueDao.addEvent(eventTemp);
171
171
172 // Call update is necessary at the creation of add Event if it has some tags or some event
172 // Call update is necessary at the creation of add Event if it has some tags or some event
173 // products
173 // products
174 if (!event->getEventProducts().empty() || !event->getTags().empty()) {
174 if (!event->getEventProducts().empty() || !event->getTags().empty()) {
175
175
176 auto eventProductsTemp = eventTemp.getEventProducts();
176 auto eventProductsTemp = eventTemp.getEventProducts();
177 auto eventProductTempUpdated = std::list<DBEventProduct>{};
177 auto eventProductTempUpdated = std::list<DBEventProduct>{};
178 for (auto eventProductTemp : eventProductsTemp) {
178 for (auto eventProductTemp : eventProductsTemp) {
179 eventProductTemp.setEvent(eventTemp);
179 eventProductTemp.setEvent(eventTemp);
180 eventProductTempUpdated.push_back(eventProductTemp);
180 eventProductTempUpdated.push_back(eventProductTemp);
181 }
181 }
182 eventTemp.setEventProducts(eventProductTempUpdated);
182 eventTemp.setEventProducts(eventProductTempUpdated);
183
183
184 impl->m_CatalogueDao.updateEvent(eventTemp);
184 impl->m_CatalogueDao.updateEvent(eventTemp);
185 }
185 }
186 }
186 }
187
187
188 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
188 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
189 {
189 {
190 impl->saveEvent(event, true);
190 impl->saveEvent(event, true);
191 impl->m_EventKeysWithChanges.remove(impl->eventUniqueKey(event));
191 impl->m_EventKeysWithChanges.remove(impl->eventUniqueKey(event));
192 }
192 }
193
193
194 void CatalogueController::discardEvent(std::shared_ptr<DBEvent> event)
195 {
196 auto uniqIdPredicate = std::make_shared<ComparaisonPredicate>(
197 QString{"uniqId"}, event->getUniqId(), ComparaisonOperation::EQUALEQUAL);
198
199 auto repositoryPredicate = std::make_shared<ComparaisonPredicate>(
200 QString{"repository"}, impl->toSyncRepository(event->getRepository()),
201 ComparaisonOperation::EQUALEQUAL);
202
203 auto compCompoundPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
204 compCompoundPred->AddRequestPredicate(uniqIdPredicate);
205 compCompoundPred->AddRequestPredicate(repositoryPredicate);
206
207
208 auto syncEvent = impl->m_CatalogueDao.getEvent(compCompoundPred);
209 impl->m_CatalogueDao.copyEvent(syncEvent, impl->toWorkRepository(event->getRepository()), true);
210 *event = syncEvent;
211 impl->m_EventKeysWithChanges.remove(impl->eventUniqueKey(event));
212 }
213
194 bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const
214 bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const
195 {
215 {
196 return impl->m_EventKeysWithChanges.contains(impl->eventUniqueKey(event));
216 return impl->m_EventKeysWithChanges.contains(impl->eventUniqueKey(event));
197 }
217 }
198
218
199 std::list<std::shared_ptr<DBCatalogue> >
219 std::list<std::shared_ptr<DBCatalogue> >
200 CatalogueController::retrieveCatalogues(const QString &repository) const
220 CatalogueController::retrieveCatalogues(const QString &repository) const
201 {
221 {
202 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
222 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
203
223
204 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
224 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
205 auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName));
225 auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName));
206 for (auto catalogue : catalogues) {
226 for (auto catalogue : catalogues) {
207 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
227 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
208 }
228 }
209 return cataloguesShared;
229 return cataloguesShared;
210 }
230 }
211
231
212 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
232 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
213 {
233 {
214 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
234 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
215
235
216 impl->m_CatalogueDao.updateCatalogue(*catalogue);
236 impl->m_CatalogueDao.updateCatalogue(*catalogue);
217 }
237 }
218
238
219 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue)
239 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue)
220 {
240 {
221 // Remove it from both repository and repository_work
241 // Remove it from both repository and repository_work
222 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
242 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
223 impl->m_CatalogueDao.removeCatalogue(*catalogue);
243 impl->m_CatalogueDao.removeCatalogue(*catalogue);
224 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
244 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
225 impl->m_CatalogueDao.removeCatalogue(*catalogue);
245 impl->m_CatalogueDao.removeCatalogue(*catalogue);
226 }
246 }
227
247
228 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
248 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
229 {
249 {
230 impl->saveCatalogue(catalogue, true);
250 impl->saveCatalogue(catalogue, true);
231 }
251 }
232
252
233 void CatalogueController::saveAll()
253 void CatalogueController::saveAll()
234 {
254 {
235 for (auto repository : impl->m_RepositoryList) {
255 for (auto repository : impl->m_RepositoryList) {
236 // Save Event
256 // Save Event
237 auto events = this->retrieveEvents(repository);
257 auto events = this->retrieveEvents(repository);
238 for (auto event : events) {
258 for (auto event : events) {
239 impl->saveEvent(event, false);
259 impl->saveEvent(event, false);
240 }
260 }
241
261
242 // Save Catalogue
262 // Save Catalogue
243 auto catalogues = this->retrieveCatalogues(repository);
263 auto catalogues = this->retrieveCatalogues(repository);
244 for (auto catalogue : catalogues) {
264 for (auto catalogue : catalogues) {
245 impl->saveCatalogue(catalogue, false);
265 impl->saveCatalogue(catalogue, false);
246 }
266 }
247 }
267 }
248
268
249 impl->savAllDB();
269 impl->savAllDB();
250 impl->m_EventKeysWithChanges.clear();
270 impl->m_EventKeysWithChanges.clear();
251 }
271 }
252
272
253 bool CatalogueController::hasChanges() const
273 bool CatalogueController::hasChanges() const
254 {
274 {
255 return !impl->m_EventKeysWithChanges.isEmpty(); // TODO: catalogues
275 return !impl->m_EventKeysWithChanges.isEmpty(); // TODO: catalogues
256 }
276 }
257
277
258 QByteArray
278 QByteArray
259 CatalogueController::mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const
279 CatalogueController::mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const
260 {
280 {
261 auto encodedData = QByteArray{};
281 auto encodedData = QByteArray{};
262
282
263 QMap<QString, QVariantList> idsPerRepository;
283 QMap<QString, QVariantList> idsPerRepository;
264 for (auto event : events) {
284 for (auto event : events) {
265 idsPerRepository[event->getRepository()] << event->getUniqId();
285 idsPerRepository[event->getRepository()] << event->getUniqId();
266 }
286 }
267
287
268 QDataStream stream{&encodedData, QIODevice::WriteOnly};
288 QDataStream stream{&encodedData, QIODevice::WriteOnly};
269 stream << idsPerRepository;
289 stream << idsPerRepository;
270
290
271 return encodedData;
291 return encodedData;
272 }
292 }
273
293
274 QVector<std::shared_ptr<DBEvent> >
294 QVector<std::shared_ptr<DBEvent> >
275 CatalogueController::eventsForMimeData(const QByteArray &mimeData) const
295 CatalogueController::eventsForMimeData(const QByteArray &mimeData) const
276 {
296 {
277 auto events = QVector<std::shared_ptr<DBEvent> >{};
297 auto events = QVector<std::shared_ptr<DBEvent> >{};
278 QDataStream stream{mimeData};
298 QDataStream stream{mimeData};
279
299
280 QMap<QString, QVariantList> idsPerRepository;
300 QMap<QString, QVariantList> idsPerRepository;
281 stream >> idsPerRepository;
301 stream >> idsPerRepository;
282
302
283 for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) {
303 for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) {
284 auto repository = it.key();
304 auto repository = it.key();
285 auto allRepositoryEvent = retrieveEvents(repository);
305 auto allRepositoryEvent = retrieveEvents(repository);
286 for (auto uuid : it.value()) {
306 for (auto uuid : it.value()) {
287 for (auto repositoryEvent : allRepositoryEvent) {
307 for (auto repositoryEvent : allRepositoryEvent) {
288 if (uuid.toUuid() == repositoryEvent->getUniqId()) {
308 if (uuid.toUuid() == repositoryEvent->getUniqId()) {
289 events << repositoryEvent;
309 events << repositoryEvent;
290 }
310 }
291 }
311 }
292 }
312 }
293 }
313 }
294
314
295 return events;
315 return events;
296 }
316 }
297
317
298 void CatalogueController::initialize()
318 void CatalogueController::initialize()
299 {
319 {
300 qCDebug(LOG_CatalogueController())
320 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
301 << tr("CatalogueController init") << QThread::currentThread();
321 << QThread::currentThread();
302
322
303 impl->m_CatalogueDao.initialize();
323 impl->m_CatalogueDao.initialize();
304 auto defaultRepositoryLocation
324 auto defaultRepositoryLocation
305 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
325 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
306
326
307 QDir defaultRepositoryLocationDir;
327 QDir defaultRepositoryLocationDir;
308 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
328 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
309 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
329 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
310 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
330 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
311 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
331 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
312 << defaultRepository;
332 << defaultRepository;
313 this->addDB(defaultRepository);
333 this->addDB(defaultRepository);
314 }
334 }
315 else {
335 else {
316 qCWarning(LOG_CatalogueController())
336 qCWarning(LOG_CatalogueController())
317 << tr("Cannot load the persistent default repository from ")
337 << tr("Cannot load the persistent default repository from ")
318 << defaultRepositoryLocation;
338 << defaultRepositoryLocation;
319 }
339 }
320
340
321 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END");
341 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END");
322 }
342 }
323
343
324 QString CatalogueController::CatalogueControllerPrivate::eventUniqueKey(
344 QString CatalogueController::CatalogueControllerPrivate::eventUniqueKey(
325 const std::shared_ptr<DBEvent> &event) const
345 const std::shared_ptr<DBEvent> &event) const
326 {
346 {
327 return event->getUniqId().toString().append(event->getRepository());
347 return event->getUniqId().toString().append(event->getRepository());
328 }
348 }
329
349
330 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
350 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
331 const QString &dbTo)
351 const QString &dbTo)
332 {
352 {
333 // auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
353 // auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
334 auto catalogues = m_CatalogueDao.getCatalogues(dbFrom);
354 auto catalogues = m_CatalogueDao.getCatalogues(dbFrom);
335 auto events = m_CatalogueDao.getEvents(dbFrom);
355 auto events = m_CatalogueDao.getEvents(dbFrom);
336 for (auto catalogue : catalogues) {
356 for (auto catalogue : catalogues) {
337 m_CatalogueDao.copyCatalogue(catalogue, dbTo, true);
357 m_CatalogueDao.copyCatalogue(catalogue, dbTo, true);
338 }
358 }
339
359
340 for (auto event : events) {
360 for (auto event : events) {
341 m_CatalogueDao.copyEvent(event, dbTo, true);
361 m_CatalogueDao.copyEvent(event, dbTo, true);
342 }
362 }
343 }
363 }
344
364
345 QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository)
365 QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository)
346 {
366 {
347 auto syncRepository = toSyncRepository(repository);
367 auto syncRepository = toSyncRepository(repository);
348
368
349 return QString("%1%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX);
369 return QString("%1%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX);
350 }
370 }
351
371
352 QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository)
372 QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository)
353 {
373 {
354 auto syncRepository = repository;
374 auto syncRepository = repository;
355 if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) {
375 if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) {
356 syncRepository.remove(REPOSITORY_WORK_SUFFIX);
376 syncRepository.remove(REPOSITORY_WORK_SUFFIX);
357 }
377 }
358 else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) {
378 else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) {
359 syncRepository.remove(REPOSITORY_TRASH_SUFFIX);
379 syncRepository.remove(REPOSITORY_TRASH_SUFFIX);
360 }
380 }
361 return syncRepository;
381 return syncRepository;
362 }
382 }
363
383
364 void CatalogueController::CatalogueControllerPrivate::savAllDB()
384 void CatalogueController::CatalogueControllerPrivate::savAllDB()
365 {
385 {
366 for (auto repository : m_RepositoryList) {
386 for (auto repository : m_RepositoryList) {
367 auto defaultRepositoryLocation
387 auto defaultRepositoryLocation
368 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
388 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
369 m_CatalogueDao.saveDB(defaultRepositoryLocation, repository);
389 m_CatalogueDao.saveDB(defaultRepositoryLocation, repository);
370 }
390 }
371 }
391 }
372
392
373 void CatalogueController::CatalogueControllerPrivate::saveEvent(std::shared_ptr<DBEvent> event,
393 void CatalogueController::CatalogueControllerPrivate::saveEvent(std::shared_ptr<DBEvent> event,
374 bool persist)
394 bool persist)
375 {
395 {
376 m_CatalogueDao.copyEvent(*event, toSyncRepository(event->getRepository()), true);
396 m_CatalogueDao.copyEvent(*event, toSyncRepository(event->getRepository()), true);
377 if (persist) {
397 if (persist) {
378 savAllDB();
398 savAllDB();
379 }
399 }
380 }
400 }
381
401
382 void CatalogueController::CatalogueControllerPrivate::saveCatalogue(
402 void CatalogueController::CatalogueControllerPrivate::saveCatalogue(
383 std::shared_ptr<DBCatalogue> catalogue, bool persist)
403 std::shared_ptr<DBCatalogue> catalogue, bool persist)
384 {
404 {
385 m_CatalogueDao.copyCatalogue(*catalogue, toSyncRepository(catalogue->getRepository()), true);
405 m_CatalogueDao.copyCatalogue(*catalogue, toSyncRepository(catalogue->getRepository()), true);
386 if (persist) {
406 if (persist) {
387 savAllDB();
407 savAllDB();
388 }
408 }
389 }
409 }
@@ -1,453 +1,457
1 #include "Catalogue/CatalogueEventsWidget.h"
1 #include "Catalogue/CatalogueEventsWidget.h"
2 #include "ui_CatalogueEventsWidget.h"
2 #include "ui_CatalogueEventsWidget.h"
3
3
4 #include <Catalogue/CatalogueController.h>
4 #include <Catalogue/CatalogueController.h>
5 #include <Catalogue/CatalogueEventsModel.h>
5 #include <Catalogue/CatalogueEventsModel.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
7 #include <CatalogueDao.h>
7 #include <CatalogueDao.h>
8 #include <DBCatalogue.h>
8 #include <DBCatalogue.h>
9 #include <SqpApplication.h>
9 #include <SqpApplication.h>
10 #include <Visualization/VisualizationTabWidget.h>
10 #include <Visualization/VisualizationTabWidget.h>
11 #include <Visualization/VisualizationWidget.h>
11 #include <Visualization/VisualizationWidget.h>
12 #include <Visualization/VisualizationZoneWidget.h>
12 #include <Visualization/VisualizationZoneWidget.h>
13
13
14 #include <QDialog>
14 #include <QDialog>
15 #include <QDialogButtonBox>
15 #include <QDialogButtonBox>
16 #include <QListWidget>
16 #include <QListWidget>
17 #include <QMessageBox>
17 #include <QMessageBox>
18
18
19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
20
20
21 /// Fixed size of the validation column
21 /// Fixed size of the validation column
22 const auto VALIDATION_COLUMN_SIZE = 35;
22 const auto VALIDATION_COLUMN_SIZE = 35;
23
23
24 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
24 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
25
25
26 CatalogueEventsModel *m_Model = nullptr;
26 CatalogueEventsModel *m_Model = nullptr;
27 QStringList m_ZonesForTimeMode;
27 QStringList m_ZonesForTimeMode;
28 QString m_ZoneForGraphMode;
28 QString m_ZoneForGraphMode;
29 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
29 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
30
30
31 VisualizationWidget *m_VisualizationWidget = nullptr;
31 VisualizationWidget *m_VisualizationWidget = nullptr;
32
32
33 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
33 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
34 {
34 {
35 widget->ui->treeView->setSortingEnabled(false);
35 widget->ui->treeView->setSortingEnabled(false);
36 m_Model->setEvents(events);
36 m_Model->setEvents(events);
37 widget->ui->treeView->setSortingEnabled(true);
37 widget->ui->treeView->setSortingEnabled(true);
38
38
39 for (auto event : events) {
39 for (auto event : events) {
40 if (sqpApp->catalogueController().eventHasChanges(event)) {
40 if (sqpApp->catalogueController().eventHasChanges(event)) {
41 auto index = m_Model->indexOf(event);
41 auto index = m_Model->indexOf(event);
42 widget->setEventChanges(event, true);
42 widget->setEventChanges(event, true);
43 }
43 }
44 }
44 }
45 }
45 }
46
46
47 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
47 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
48 {
48 {
49 treeView->setSortingEnabled(false);
49 treeView->setSortingEnabled(false);
50 m_Model->addEvent(event);
50 m_Model->addEvent(event);
51 treeView->setSortingEnabled(true);
51 treeView->setSortingEnabled(true);
52 }
52 }
53
53
54 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
54 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
55 {
55 {
56 treeView->setSortingEnabled(false);
56 treeView->setSortingEnabled(false);
57 m_Model->removeEvent(event);
57 m_Model->removeEvent(event);
58 treeView->setSortingEnabled(true);
58 treeView->setSortingEnabled(true);
59 }
59 }
60
60
61 QStringList getAvailableVisualizationZoneList() const
61 QStringList getAvailableVisualizationZoneList() const
62 {
62 {
63 if (m_VisualizationWidget) {
63 if (m_VisualizationWidget) {
64 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
64 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
65 return tab->availableZoneWidgets();
65 return tab->availableZoneWidgets();
66 }
66 }
67 }
67 }
68
68
69 return QStringList{};
69 return QStringList{};
70 }
70 }
71
71
72 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
72 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
73 bool allowMultiSelection, const QPoint &location)
73 bool allowMultiSelection, const QPoint &location)
74 {
74 {
75 auto availableZones = getAvailableVisualizationZoneList();
75 auto availableZones = getAvailableVisualizationZoneList();
76 if (availableZones.isEmpty()) {
76 if (availableZones.isEmpty()) {
77 return QStringList{};
77 return QStringList{};
78 }
78 }
79
79
80 QDialog d(parent, Qt::Tool);
80 QDialog d(parent, Qt::Tool);
81 d.setWindowTitle("Choose a zone");
81 d.setWindowTitle("Choose a zone");
82 auto layout = new QVBoxLayout{&d};
82 auto layout = new QVBoxLayout{&d};
83 layout->setContentsMargins(0, 0, 0, 0);
83 layout->setContentsMargins(0, 0, 0, 0);
84 auto listWidget = new QListWidget{&d};
84 auto listWidget = new QListWidget{&d};
85 layout->addWidget(listWidget);
85 layout->addWidget(listWidget);
86
86
87 QSet<QListWidgetItem *> checkedItems;
87 QSet<QListWidgetItem *> checkedItems;
88 for (auto zone : availableZones) {
88 for (auto zone : availableZones) {
89 auto item = new QListWidgetItem{zone};
89 auto item = new QListWidgetItem{zone};
90 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
90 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
91 if (selectedZones.contains(zone)) {
91 if (selectedZones.contains(zone)) {
92 item->setCheckState(Qt::Checked);
92 item->setCheckState(Qt::Checked);
93 checkedItems << item;
93 checkedItems << item;
94 }
94 }
95 else {
95 else {
96 item->setCheckState(Qt::Unchecked);
96 item->setCheckState(Qt::Unchecked);
97 }
97 }
98
98
99 listWidget->addItem(item);
99 listWidget->addItem(item);
100 }
100 }
101
101
102 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
102 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
103 layout->addWidget(buttonBox);
103 layout->addWidget(buttonBox);
104
104
105 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
105 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
106 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
106 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
107
107
108 QObject::connect(listWidget, &QListWidget::itemChanged,
108 QObject::connect(listWidget, &QListWidget::itemChanged,
109 [&checkedItems, allowMultiSelection, listWidget](auto item) {
109 [&checkedItems, allowMultiSelection, listWidget](auto item) {
110 if (item->checkState() == Qt::Checked) {
110 if (item->checkState() == Qt::Checked) {
111 if (!allowMultiSelection) {
111 if (!allowMultiSelection) {
112 for (auto checkedItem : checkedItems) {
112 for (auto checkedItem : checkedItems) {
113 listWidget->blockSignals(true);
113 listWidget->blockSignals(true);
114 checkedItem->setCheckState(Qt::Unchecked);
114 checkedItem->setCheckState(Qt::Unchecked);
115 listWidget->blockSignals(false);
115 listWidget->blockSignals(false);
116 }
116 }
117
117
118 checkedItems.clear();
118 checkedItems.clear();
119 }
119 }
120 checkedItems << item;
120 checkedItems << item;
121 }
121 }
122 else {
122 else {
123 checkedItems.remove(item);
123 checkedItems.remove(item);
124 }
124 }
125 });
125 });
126
126
127 QStringList result;
127 QStringList result;
128
128
129 d.setMinimumWidth(120);
129 d.setMinimumWidth(120);
130 d.resize(d.minimumSizeHint());
130 d.resize(d.minimumSizeHint());
131 d.move(location);
131 d.move(location);
132 if (d.exec() == QDialog::Accepted) {
132 if (d.exec() == QDialog::Accepted) {
133 for (auto item : checkedItems) {
133 for (auto item : checkedItems) {
134 result += item->text();
134 result += item->text();
135 }
135 }
136 }
136 }
137 else {
137 else {
138 result = selectedZones;
138 result = selectedZones;
139 }
139 }
140
140
141 return result;
141 return result;
142 }
142 }
143
143
144 void updateForTimeMode(QTreeView *treeView)
144 void updateForTimeMode(QTreeView *treeView)
145 {
145 {
146 auto selectedRows = treeView->selectionModel()->selectedRows();
146 auto selectedRows = treeView->selectionModel()->selectedRows();
147
147
148 if (selectedRows.count() == 1) {
148 if (selectedRows.count() == 1) {
149 auto event = m_Model->getEvent(selectedRows.first());
149 auto event = m_Model->getEvent(selectedRows.first());
150 if (event) {
150 if (event) {
151 if (m_VisualizationWidget) {
151 if (m_VisualizationWidget) {
152 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
152 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
153
153
154 for (auto zoneName : m_ZonesForTimeMode) {
154 for (auto zoneName : m_ZonesForTimeMode) {
155 if (auto zone = tab->getZoneWithName(zoneName)) {
155 if (auto zone = tab->getZoneWithName(zoneName)) {
156 SqpRange eventRange;
156 SqpRange eventRange;
157 eventRange.m_TStart = event->getTStart();
157 eventRange.m_TStart = event->getTStart();
158 eventRange.m_TEnd = event->getTEnd();
158 eventRange.m_TEnd = event->getTEnd();
159 zone->setZoneRange(eventRange);
159 zone->setZoneRange(eventRange);
160 }
160 }
161 }
161 }
162 }
162 }
163 else {
163 else {
164 qCWarning(LOG_CatalogueEventsWidget())
164 qCWarning(LOG_CatalogueEventsWidget())
165 << "updateTimeZone: no tab found in the visualization";
165 << "updateTimeZone: no tab found in the visualization";
166 }
166 }
167 }
167 }
168 else {
168 else {
169 qCWarning(LOG_CatalogueEventsWidget())
169 qCWarning(LOG_CatalogueEventsWidget())
170 << "updateTimeZone: visualization widget not found";
170 << "updateTimeZone: visualization widget not found";
171 }
171 }
172 }
172 }
173 }
173 }
174 else {
174 else {
175 qCWarning(LOG_CatalogueEventsWidget())
175 qCWarning(LOG_CatalogueEventsWidget())
176 << "updateTimeZone: not compatible with multiple events selected";
176 << "updateTimeZone: not compatible with multiple events selected";
177 }
177 }
178 }
178 }
179
179
180 void updateForGraphMode(QTreeView *treeView)
180 void updateForGraphMode(QTreeView *treeView)
181 {
181 {
182 auto selectedRows = treeView->selectionModel()->selectedRows();
182 auto selectedRows = treeView->selectionModel()->selectedRows();
183
183
184 if (selectedRows.count() == 1) {
184 if (selectedRows.count() == 1) {
185 auto event = m_Model->getEvent(selectedRows.first());
185 auto event = m_Model->getEvent(selectedRows.first());
186 if (m_VisualizationWidget) {
186 if (m_VisualizationWidget) {
187 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
187 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
188 if (auto zone = tab->getZoneWithName(m_ZoneForGraphMode)) {
188 if (auto zone = tab->getZoneWithName(m_ZoneForGraphMode)) {
189 // TODO
189 // TODO
190 }
190 }
191 }
191 }
192 else {
192 else {
193 qCWarning(LOG_CatalogueEventsWidget())
193 qCWarning(LOG_CatalogueEventsWidget())
194 << "updateGraphMode: no tab found in the visualization";
194 << "updateGraphMode: no tab found in the visualization";
195 }
195 }
196 }
196 }
197 else {
197 else {
198 qCWarning(LOG_CatalogueEventsWidget())
198 qCWarning(LOG_CatalogueEventsWidget())
199 << "updateGraphMode: visualization widget not found";
199 << "updateGraphMode: visualization widget not found";
200 }
200 }
201 }
201 }
202 else {
202 else {
203 qCWarning(LOG_CatalogueEventsWidget())
203 qCWarning(LOG_CatalogueEventsWidget())
204 << "updateGraphMode: not compatible with multiple events selected";
204 << "updateGraphMode: not compatible with multiple events selected";
205 }
205 }
206 }
206 }
207
207
208 void getSelectedItems(
208 void getSelectedItems(
209 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
209 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
210 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
210 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
211 {
211 {
212 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
212 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
213 auto itemType = m_Model->itemTypeOf(rowIndex);
213 auto itemType = m_Model->itemTypeOf(rowIndex);
214 if (itemType == CatalogueEventsModel::ItemType::Event) {
214 if (itemType == CatalogueEventsModel::ItemType::Event) {
215 events << m_Model->getEvent(rowIndex);
215 events << m_Model->getEvent(rowIndex);
216 }
216 }
217 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
217 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
218 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
218 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
219 m_Model->getEventProduct(rowIndex));
219 m_Model->getEventProduct(rowIndex));
220 }
220 }
221 }
221 }
222 }
222 }
223 };
223 };
224
224
225 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
225 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
226 : QWidget(parent),
226 : QWidget(parent),
227 ui(new Ui::CatalogueEventsWidget),
227 ui(new Ui::CatalogueEventsWidget),
228 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
228 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
229 {
229 {
230 ui->setupUi(this);
230 ui->setupUi(this);
231
231
232 impl->m_Model = new CatalogueEventsModel{this};
232 impl->m_Model = new CatalogueEventsModel{this};
233 ui->treeView->setModel(impl->m_Model);
233 ui->treeView->setModel(impl->m_Model);
234
234
235 ui->treeView->setSortingEnabled(true);
235 ui->treeView->setSortingEnabled(true);
236 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
236 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
237 ui->treeView->setDragEnabled(true);
237 ui->treeView->setDragEnabled(true);
238
238
239 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
239 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
240 if (checked) {
240 if (checked) {
241 ui->btnChart->setChecked(false);
241 ui->btnChart->setChecked(false);
242 impl->m_ZonesForTimeMode
242 impl->m_ZonesForTimeMode
243 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
243 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
244 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
244 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
245
245
246 impl->updateForTimeMode(ui->treeView);
246 impl->updateForTimeMode(ui->treeView);
247 }
247 }
248 });
248 });
249
249
250 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
250 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
251 if (checked) {
251 if (checked) {
252 ui->btnTime->setChecked(false);
252 ui->btnTime->setChecked(false);
253 impl->m_ZoneForGraphMode
253 impl->m_ZoneForGraphMode
254 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
254 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
255 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
255 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
256 .value(0);
256 .value(0);
257
257
258 impl->updateForGraphMode(ui->treeView);
258 impl->updateForGraphMode(ui->treeView);
259 }
259 }
260 });
260 });
261
261
262 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
262 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
263 QVector<std::shared_ptr<DBEvent> > events;
263 QVector<std::shared_ptr<DBEvent> > events;
264 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
264 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
265 impl->getSelectedItems(ui->treeView, events, eventProducts);
265 impl->getSelectedItems(ui->treeView, events, eventProducts);
266
266
267 if (!events.isEmpty() && eventProducts.isEmpty()) {
267 if (!events.isEmpty() && eventProducts.isEmpty()) {
268
268
269 if (QMessageBox::warning(this, tr("Remove Event(s)"),
269 if (QMessageBox::warning(this, tr("Remove Event(s)"),
270 tr("The selected event(s) will be completly removed "
270 tr("The selected event(s) will be completly removed "
271 "from the repository!\nAre you sure you want to continue?"),
271 "from the repository!\nAre you sure you want to continue?"),
272 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
272 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
273 == QMessageBox::Yes) {
273 == QMessageBox::Yes) {
274
274
275 for (auto event : events) {
275 for (auto event : events) {
276 sqpApp->catalogueController().removeEvent(event);
276 sqpApp->catalogueController().removeEvent(event);
277 impl->removeEvent(event, ui->treeView);
277 impl->removeEvent(event, ui->treeView);
278 }
278 }
279 }
279 }
280 }
280 }
281 });
281 });
282
282
283 auto emitSelection = [this]() {
283 auto emitSelection = [this]() {
284 QVector<std::shared_ptr<DBEvent> > events;
284 QVector<std::shared_ptr<DBEvent> > events;
285 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
285 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
286 impl->getSelectedItems(ui->treeView, events, eventProducts);
286 impl->getSelectedItems(ui->treeView, events, eventProducts);
287
287
288 if (!events.isEmpty() && eventProducts.isEmpty()) {
288 if (!events.isEmpty() && eventProducts.isEmpty()) {
289 emit this->eventsSelected(events);
289 emit this->eventsSelected(events);
290 }
290 }
291 else if (events.isEmpty() && !eventProducts.isEmpty()) {
291 else if (events.isEmpty() && !eventProducts.isEmpty()) {
292 emit this->eventProductsSelected(eventProducts);
292 emit this->eventProductsSelected(eventProducts);
293 }
293 }
294 else {
294 else {
295 emit this->selectionCleared();
295 emit this->selectionCleared();
296 }
296 }
297 };
297 };
298
298
299 connect(ui->treeView, &QTreeView::clicked, emitSelection);
299 connect(ui->treeView, &QTreeView::clicked, emitSelection);
300 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, emitSelection);
300 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, emitSelection);
301
301
302 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
302 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
303 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
303 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
304 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
304 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
305 ui->btnChart->setEnabled(isNotMultiSelection);
305 ui->btnChart->setEnabled(isNotMultiSelection);
306 ui->btnTime->setEnabled(isNotMultiSelection);
306 ui->btnTime->setEnabled(isNotMultiSelection);
307
307
308 if (isNotMultiSelection && ui->btnTime->isChecked()) {
308 if (isNotMultiSelection && ui->btnTime->isChecked()) {
309 impl->updateForTimeMode(ui->treeView);
309 impl->updateForTimeMode(ui->treeView);
310 }
310 }
311 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
311 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
312 impl->updateForGraphMode(ui->treeView);
312 impl->updateForGraphMode(ui->treeView);
313 }
313 }
314
314
315 QVector<std::shared_ptr<DBEvent> > events;
315 QVector<std::shared_ptr<DBEvent> > events;
316 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
316 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
317 impl->getSelectedItems(ui->treeView, events, eventProducts);
317 impl->getSelectedItems(ui->treeView, events, eventProducts);
318 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
318 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
319 });
319 });
320
320
321 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
321 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
322 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
322 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
323 QHeaderView::Stretch);
323 QHeaderView::Stretch);
324 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
324 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
325 QHeaderView::Fixed);
325 QHeaderView::Fixed);
326 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
326 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
327 QHeaderView::Interactive);
327 QHeaderView::Interactive);
328 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
328 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
329 VALIDATION_COLUMN_SIZE);
329 VALIDATION_COLUMN_SIZE);
330 ui->treeView->header()->setSortIndicatorShown(true);
330 ui->treeView->header()->setSortIndicatorShown(true);
331
331
332 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
332 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
333 auto allEvents = impl->m_Model->events();
333 auto allEvents = impl->m_Model->events();
334 for (auto event : allEvents) {
334 for (auto event : allEvents) {
335 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
335 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
336 }
336 }
337 });
337 });
338
338
339 populateWithAllEvents();
339 populateWithAllEvents();
340 }
340 }
341
341
342 CatalogueEventsWidget::~CatalogueEventsWidget()
342 CatalogueEventsWidget::~CatalogueEventsWidget()
343 {
343 {
344 delete ui;
344 delete ui;
345 }
345 }
346
346
347 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
347 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
348 {
348 {
349 impl->m_VisualizationWidget = visualization;
349 impl->m_VisualizationWidget = visualization;
350 }
350 }
351
351
352 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
352 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
353 {
353 {
354 impl->addEvent(event, ui->treeView);
354 impl->addEvent(event, ui->treeView);
355 }
355 }
356
356
357 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
357 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
358 {
358 {
359 impl->m_Model->refreshEvent(event);
359 impl->m_Model->refreshEvent(event);
360
360
361 auto eventIndex = impl->m_Model->indexOf(event);
361 auto eventIndex = impl->m_Model->indexOf(event);
362 auto validationIndex
362 auto validationIndex
363 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
363 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
364
364
365 if (validationIndex.isValid()) {
365 if (validationIndex.isValid()) {
366 if (hasChanges) {
366 if (hasChanges) {
367 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
367 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
368 auto widget = CatalogueExplorerHelper::buildValidationWidget(
368 auto widget = CatalogueExplorerHelper::buildValidationWidget(
369 ui->treeView,
369 ui->treeView,
370 [this, event]() {
370 [this, event]() {
371 sqpApp->catalogueController().saveEvent(event);
371 sqpApp->catalogueController().saveEvent(event);
372 setEventChanges(event, false);
372 setEventChanges(event, false);
373 },
373 },
374 [this, event]() { setEventChanges(event, false); });
374 [this, event]() {
375 sqpApp->catalogueController().discardEvent(event);
376 setEventChanges(event, false);
377 impl->m_Model->refreshEvent(event);
378 });
375 ui->treeView->setIndexWidget(validationIndex, widget);
379 ui->treeView->setIndexWidget(validationIndex, widget);
376 }
380 }
377 }
381 }
378 else {
382 else {
379 // Note: the widget is destroyed
383 // Note: the widget is destroyed
380 ui->treeView->setIndexWidget(validationIndex, nullptr);
384 ui->treeView->setIndexWidget(validationIndex, nullptr);
381 }
385 }
382 }
386 }
383 else {
387 else {
384 qCWarning(LOG_CatalogueEventsWidget())
388 qCWarning(LOG_CatalogueEventsWidget())
385 << "setEventChanges: the event is not displayed in the model.";
389 << "setEventChanges: the event is not displayed in the model.";
386 }
390 }
387 }
391 }
388
392
389 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
393 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
390 {
394 {
391 return impl->m_DisplayedCatalogues;
395 return impl->m_DisplayedCatalogues;
392 }
396 }
393
397
394 bool CatalogueEventsWidget::isAllEventsDisplayed() const
398 bool CatalogueEventsWidget::isAllEventsDisplayed() const
395 {
399 {
396 return impl->m_DisplayedCatalogues.isEmpty() && !impl->m_Model->events().isEmpty();
400 return impl->m_DisplayedCatalogues.isEmpty() && !impl->m_Model->events().isEmpty();
397 }
401 }
398
402
399 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
403 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
400 {
404 {
401 return impl->m_Model->indexOf(event).isValid();
405 return impl->m_Model->indexOf(event).isValid();
402 }
406 }
403
407
404 void CatalogueEventsWidget::populateWithCatalogues(
408 void CatalogueEventsWidget::populateWithCatalogues(
405 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
409 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
406 {
410 {
407 impl->m_DisplayedCatalogues = catalogues;
411 impl->m_DisplayedCatalogues = catalogues;
408
412
409 QSet<QUuid> eventIds;
413 QSet<QUuid> eventIds;
410 QVector<std::shared_ptr<DBEvent> > events;
414 QVector<std::shared_ptr<DBEvent> > events;
411
415
412 for (auto catalogue : catalogues) {
416 for (auto catalogue : catalogues) {
413 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
417 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
414 for (auto event : catalogueEvents) {
418 for (auto event : catalogueEvents) {
415 if (!eventIds.contains(event->getUniqId())) {
419 if (!eventIds.contains(event->getUniqId())) {
416 events << event;
420 events << event;
417 eventIds.insert(event->getUniqId());
421 eventIds.insert(event->getUniqId());
418 }
422 }
419 }
423 }
420 }
424 }
421
425
422 impl->setEvents(events, this);
426 impl->setEvents(events, this);
423 }
427 }
424
428
425 void CatalogueEventsWidget::populateWithAllEvents()
429 void CatalogueEventsWidget::populateWithAllEvents()
426 {
430 {
427 impl->m_DisplayedCatalogues.clear();
431 impl->m_DisplayedCatalogues.clear();
428
432
429 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
433 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
430
434
431 QVector<std::shared_ptr<DBEvent> > events;
435 QVector<std::shared_ptr<DBEvent> > events;
432 for (auto event : allEvents) {
436 for (auto event : allEvents) {
433 events << event;
437 events << event;
434 }
438 }
435
439
436 impl->setEvents(events, this);
440 impl->setEvents(events, this);
437 }
441 }
438
442
439 void CatalogueEventsWidget::clear()
443 void CatalogueEventsWidget::clear()
440 {
444 {
441 impl->m_DisplayedCatalogues.clear();
445 impl->m_DisplayedCatalogues.clear();
442 impl->setEvents({}, this);
446 impl->setEvents({}, this);
443 }
447 }
444
448
445 void CatalogueEventsWidget::refresh()
449 void CatalogueEventsWidget::refresh()
446 {
450 {
447 if (impl->m_DisplayedCatalogues.isEmpty()) {
451 if (impl->m_DisplayedCatalogues.isEmpty()) {
448 populateWithAllEvents();
452 populateWithAllEvents();
449 }
453 }
450 else {
454 else {
451 populateWithCatalogues(impl->m_DisplayedCatalogues);
455 populateWithCatalogues(impl->m_DisplayedCatalogues);
452 }
456 }
453 }
457 }
@@ -1,339 +1,337
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 <ComparaisonPredicate.h>
11 #include <ComparaisonPredicate.h>
12 #include <DBCatalogue.h>
12 #include <DBCatalogue.h>
13
13
14 #include <QMenu>
14 #include <QMenu>
15
15
16 Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget")
16 Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget")
17
17
18
18
19 constexpr auto ALL_EVENT_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 1;
19 constexpr auto ALL_EVENT_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 1;
20 constexpr auto TRASH_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 2;
20 constexpr auto TRASH_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 2;
21 constexpr auto CATALOGUE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 3;
21 constexpr auto CATALOGUE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 3;
22 constexpr auto DATABASE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 4;
22 constexpr auto DATABASE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 4;
23
23
24
24
25 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
25 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
26
26
27 CatalogueTreeModel *m_TreeModel = nullptr;
27 CatalogueTreeModel *m_TreeModel = nullptr;
28
28
29 void configureTreeWidget(QTreeView *treeView);
29 void configureTreeWidget(QTreeView *treeView);
30 QModelIndex addDatabaseItem(const QString &name);
30 QModelIndex addDatabaseItem(const QString &name);
31 CatalogueAbstractTreeItem *getDatabaseItem(const QString &name);
31 CatalogueAbstractTreeItem *getDatabaseItem(const QString &name);
32 void addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
32 void addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
33 const QModelIndex &databaseIndex);
33 const QModelIndex &databaseIndex);
34
34
35 CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const;
35 CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const;
36 void setHasChanges(bool value, const QModelIndex &index, QTreeView *treeView);
36 void setHasChanges(bool value, const QModelIndex &index, QTreeView *treeView);
37 bool hasChanges(const QModelIndex &index, QTreeView *treeView);
37 bool hasChanges(const QModelIndex &index, QTreeView *treeView);
38
38
39 int selectionType(QTreeView *treeView) const
39 int selectionType(QTreeView *treeView) const
40 {
40 {
41 auto selectedItems = treeView->selectionModel()->selectedRows();
41 auto selectedItems = treeView->selectionModel()->selectedRows();
42 if (selectedItems.isEmpty()) {
42 if (selectedItems.isEmpty()) {
43 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
43 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
44 }
44 }
45 else {
45 else {
46 auto firstIndex = selectedItems.first();
46 auto firstIndex = selectedItems.first();
47 auto firstItem = m_TreeModel->item(firstIndex);
47 auto firstItem = m_TreeModel->item(firstIndex);
48 if (!firstItem) {
48 if (!firstItem) {
49 Q_ASSERT(false);
49 Q_ASSERT(false);
50 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
50 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
51 }
51 }
52 auto selectionType = firstItem->type();
52 auto selectionType = firstItem->type();
53
53
54 for (auto itemIndex : selectedItems) {
54 for (auto itemIndex : selectedItems) {
55 auto item = m_TreeModel->item(itemIndex);
55 auto item = m_TreeModel->item(itemIndex);
56 if (!item || item->type() != selectionType) {
56 if (!item || item->type() != selectionType) {
57 // Incoherent multi selection
57 // Incoherent multi selection
58 selectionType = CatalogueAbstractTreeItem::DEFAULT_TYPE;
58 selectionType = CatalogueAbstractTreeItem::DEFAULT_TYPE;
59 break;
59 break;
60 }
60 }
61 }
61 }
62
62
63 return selectionType;
63 return selectionType;
64 }
64 }
65 }
65 }
66
66
67 QVector<std::shared_ptr<DBCatalogue> > selectedCatalogues(QTreeView *treeView) const
67 QVector<std::shared_ptr<DBCatalogue> > selectedCatalogues(QTreeView *treeView) const
68 {
68 {
69 QVector<std::shared_ptr<DBCatalogue> > catalogues;
69 QVector<std::shared_ptr<DBCatalogue> > catalogues;
70 auto selectedItems = treeView->selectionModel()->selectedRows();
70 auto selectedItems = treeView->selectionModel()->selectedRows();
71 for (auto itemIndex : selectedItems) {
71 for (auto itemIndex : selectedItems) {
72 auto item = m_TreeModel->item(itemIndex);
72 auto item = m_TreeModel->item(itemIndex);
73 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
73 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
74 catalogues.append(static_cast<CatalogueTreeItem *>(item)->catalogue());
74 catalogues.append(static_cast<CatalogueTreeItem *>(item)->catalogue());
75 }
75 }
76 }
76 }
77
77
78 return catalogues;
78 return catalogues;
79 }
79 }
80
80
81 QStringList selectedRepositories(QTreeView *treeView) const
81 QStringList selectedRepositories(QTreeView *treeView) const
82 {
82 {
83 QStringList repositories;
83 QStringList repositories;
84 auto selectedItems = treeView->selectionModel()->selectedRows();
84 auto selectedItems = treeView->selectionModel()->selectedRows();
85 for (auto itemIndex : selectedItems) {
85 for (auto itemIndex : selectedItems) {
86 auto item = m_TreeModel->item(itemIndex);
86 auto item = m_TreeModel->item(itemIndex);
87 if (item && item->type() == DATABASE_ITEM_TYPE) {
87 if (item && item->type() == DATABASE_ITEM_TYPE) {
88 repositories.append(item->text());
88 repositories.append(item->text());
89 }
89 }
90 }
90 }
91
91
92 return repositories;
92 return repositories;
93 }
93 }
94 };
94 };
95
95
96 CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent)
96 CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent)
97 : QWidget(parent),
97 : QWidget(parent),
98 ui(new Ui::CatalogueSideBarWidget),
98 ui(new Ui::CatalogueSideBarWidget),
99 impl{spimpl::make_unique_impl<CatalogueSideBarWidgetPrivate>()}
99 impl{spimpl::make_unique_impl<CatalogueSideBarWidgetPrivate>()}
100 {
100 {
101 ui->setupUi(this);
101 ui->setupUi(this);
102
102
103 impl->m_TreeModel = new CatalogueTreeModel(this);
103 impl->m_TreeModel = new CatalogueTreeModel(this);
104 ui->treeView->setModel(impl->m_TreeModel);
104 ui->treeView->setModel(impl->m_TreeModel);
105
105
106 impl->configureTreeWidget(ui->treeView);
106 impl->configureTreeWidget(ui->treeView);
107
107
108 ui->treeView->header()->setStretchLastSection(false);
108 ui->treeView->header()->setStretchLastSection(false);
109 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
109 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
110 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
110 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
111
111
112 auto emitSelection = [this]() {
112 auto emitSelection = [this]() {
113
113
114 auto selectionType = impl->selectionType(ui->treeView);
114 auto selectionType = impl->selectionType(ui->treeView);
115
115
116 switch (selectionType) {
116 switch (selectionType) {
117 case CATALOGUE_ITEM_TYPE:
117 case CATALOGUE_ITEM_TYPE:
118 emit this->catalogueSelected(impl->selectedCatalogues(ui->treeView));
118 emit this->catalogueSelected(impl->selectedCatalogues(ui->treeView));
119 break;
119 break;
120 case DATABASE_ITEM_TYPE:
120 case DATABASE_ITEM_TYPE:
121 emit this->databaseSelected(impl->selectedRepositories(ui->treeView));
121 emit this->databaseSelected(impl->selectedRepositories(ui->treeView));
122 break;
122 break;
123 case ALL_EVENT_ITEM_TYPE:
123 case ALL_EVENT_ITEM_TYPE:
124 emit this->allEventsSelected();
124 emit this->allEventsSelected();
125 break;
125 break;
126 case TRASH_ITEM_TYPE:
126 case TRASH_ITEM_TYPE:
127 emit this->trashSelected();
127 emit this->trashSelected();
128 break;
128 break;
129 default:
129 default:
130 emit this->selectionCleared();
130 emit this->selectionCleared();
131 break;
131 break;
132 }
132 }
133 };
133 };
134
134
135 connect(ui->treeView, &QTreeView::clicked, emitSelection);
135 connect(ui->treeView, &QTreeView::clicked, emitSelection);
136 connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, emitSelection);
136 connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, emitSelection);
137 connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [emitSelection, this](auto index) {
137 connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [emitSelection, this](auto index) {
138 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
138 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
139 if (selectedIndexes.contains(index)) {
139 if (selectedIndexes.contains(index)) {
140 emitSelection();
140 emitSelection();
141 }
141 }
142
142
143 auto item = impl->m_TreeModel->item(index);
143 auto item = impl->m_TreeModel->item(index);
144 impl->setHasChanges(true, index, ui->treeView);
144 impl->setHasChanges(true, index, ui->treeView);
145 });
145 });
146
146
147 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
147 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
148 connect(ui->treeView, &QTreeView::customContextMenuRequested, this,
148 connect(ui->treeView, &QTreeView::customContextMenuRequested, this,
149 &CatalogueSideBarWidget::onContextMenuRequested);
149 &CatalogueSideBarWidget::onContextMenuRequested);
150 }
150 }
151
151
152 CatalogueSideBarWidget::~CatalogueSideBarWidget()
152 CatalogueSideBarWidget::~CatalogueSideBarWidget()
153 {
153 {
154 delete ui;
154 delete ui;
155 }
155 }
156
156
157 void CatalogueSideBarWidget::addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
157 void CatalogueSideBarWidget::addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
158 const QString &repository)
158 const QString &repository)
159 {
159 {
160 auto repositoryItem = impl->getDatabaseItem(repository);
160 auto repositoryItem = impl->getDatabaseItem(repository);
161 impl->addCatalogueItem(catalogue, impl->m_TreeModel->indexOf(repositoryItem));
161 impl->addCatalogueItem(catalogue, impl->m_TreeModel->indexOf(repositoryItem));
162 }
162 }
163
163
164 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue,
164 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue,
165 bool hasChanges)
165 bool hasChanges)
166 {
166 {
167 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
167 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
168 auto index = impl->m_TreeModel->indexOf(catalogueItem);
168 auto index = impl->m_TreeModel->indexOf(catalogueItem);
169 impl->setHasChanges(hasChanges, index, ui->treeView);
169 impl->setHasChanges(hasChanges, index, ui->treeView);
170 // catalogueItem->refresh();
170 // catalogueItem->refresh();
171 }
171 }
172 }
172 }
173
173
174 QVector<std::shared_ptr<DBCatalogue> >
174 QVector<std::shared_ptr<DBCatalogue> >
175 CatalogueSideBarWidget::getCatalogues(const QString &repository) const
175 CatalogueSideBarWidget::getCatalogues(const QString &repository) const
176 {
176 {
177 QVector<std::shared_ptr<DBCatalogue> > result;
177 QVector<std::shared_ptr<DBCatalogue> > result;
178 auto repositoryItem = impl->getDatabaseItem(repository);
178 auto repositoryItem = impl->getDatabaseItem(repository);
179 for (auto child : repositoryItem->children()) {
179 for (auto child : repositoryItem->children()) {
180 if (child->type() == CATALOGUE_ITEM_TYPE) {
180 if (child->type() == CATALOGUE_ITEM_TYPE) {
181 auto catalogueItem = static_cast<CatalogueTreeItem *>(child);
181 auto catalogueItem = static_cast<CatalogueTreeItem *>(child);
182 result << catalogueItem->catalogue();
182 result << catalogueItem->catalogue();
183 }
183 }
184 else {
184 else {
185 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogues: invalid structure";
185 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogues: invalid structure";
186 }
186 }
187 }
187 }
188
188
189 return result;
189 return result;
190 }
190 }
191
191
192 void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos)
192 void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos)
193 {
193 {
194 QMenu menu{this};
194 QMenu menu{this};
195
195
196 auto currentIndex = ui->treeView->currentIndex();
196 auto currentIndex = ui->treeView->currentIndex();
197 auto currentItem = impl->m_TreeModel->item(currentIndex);
197 auto currentItem = impl->m_TreeModel->item(currentIndex);
198 if (!currentItem) {
198 if (!currentItem) {
199 return;
199 return;
200 }
200 }
201
201
202 switch (currentItem->type()) {
202 switch (currentItem->type()) {
203 case CATALOGUE_ITEM_TYPE:
203 case CATALOGUE_ITEM_TYPE:
204 menu.addAction("Rename", [this, currentIndex]() { ui->treeView->edit(currentIndex); });
204 menu.addAction("Rename", [this, currentIndex]() { ui->treeView->edit(currentIndex); });
205 break;
205 break;
206 case DATABASE_ITEM_TYPE:
206 case DATABASE_ITEM_TYPE:
207 break;
207 break;
208 case ALL_EVENT_ITEM_TYPE:
208 case ALL_EVENT_ITEM_TYPE:
209 break;
209 break;
210 case TRASH_ITEM_TYPE:
210 case TRASH_ITEM_TYPE:
211 menu.addAction("Empty Trash", []() {
211 menu.addAction("Empty Trash", []() {
212 // TODO
212 // TODO
213 });
213 });
214 break;
214 break;
215 default:
215 default:
216 break;
216 break;
217 }
217 }
218
218
219 if (!menu.isEmpty()) {
219 if (!menu.isEmpty()) {
220 menu.exec(ui->treeView->mapToGlobal(pos));
220 menu.exec(ui->treeView->mapToGlobal(pos));
221 }
221 }
222 }
222 }
223
223
224 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(QTreeView *treeView)
224 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(QTreeView *treeView)
225 {
225 {
226 auto allEventsItem = new CatalogueTextTreeItem{QIcon{":/icones/allEvents.png"}, "All Events",
226 auto allEventsItem = new CatalogueTextTreeItem{QIcon{":/icones/allEvents.png"}, "All Events",
227 ALL_EVENT_ITEM_TYPE};
227 ALL_EVENT_ITEM_TYPE};
228 auto allEventIndex = m_TreeModel->addTopLevelItem(allEventsItem);
228 auto allEventIndex = m_TreeModel->addTopLevelItem(allEventsItem);
229 treeView->setCurrentIndex(allEventIndex);
229 treeView->setCurrentIndex(allEventIndex);
230
230
231 auto trashItem
231 auto trashItem
232 = new CatalogueTextTreeItem{QIcon{":/icones/trash.png"}, "Trash", TRASH_ITEM_TYPE};
232 = new CatalogueTextTreeItem{QIcon{":/icones/trash.png"}, "Trash", TRASH_ITEM_TYPE};
233 m_TreeModel->addTopLevelItem(trashItem);
233 m_TreeModel->addTopLevelItem(trashItem);
234
234
235 auto separator = new QFrame{treeView};
235 auto separator = new QFrame{treeView};
236 separator->setFrameShape(QFrame::HLine);
236 separator->setFrameShape(QFrame::HLine);
237 auto separatorItem
237 auto separatorItem
238 = new CatalogueTextTreeItem{QIcon{}, QString{}, CatalogueAbstractTreeItem::DEFAULT_TYPE};
238 = new CatalogueTextTreeItem{QIcon{}, QString{}, CatalogueAbstractTreeItem::DEFAULT_TYPE};
239 separatorItem->setEnabled(false);
239 separatorItem->setEnabled(false);
240 auto separatorIndex = m_TreeModel->addTopLevelItem(separatorItem);
240 auto separatorIndex = m_TreeModel->addTopLevelItem(separatorItem);
241 treeView->setIndexWidget(separatorIndex, separator);
241 treeView->setIndexWidget(separatorIndex, separator);
242
242
243 auto repositories = sqpApp->catalogueController().getRepositories();
243 auto repositories = sqpApp->catalogueController().getRepositories();
244 for (auto dbname : repositories) {
244 for (auto dbname : repositories) {
245 auto dbIndex = addDatabaseItem(dbname);
245 auto dbIndex = addDatabaseItem(dbname);
246 auto catalogues = sqpApp->catalogueController().retrieveCatalogues(dbname);
246 auto catalogues = sqpApp->catalogueController().retrieveCatalogues(dbname);
247 for (auto catalogue : catalogues) {
247 for (auto catalogue : catalogues) {
248 addCatalogueItem(catalogue, dbIndex);
248 addCatalogueItem(catalogue, dbIndex);
249 }
249 }
250 }
250 }
251
251
252 treeView->expandAll();
252 treeView->expandAll();
253 }
253 }
254
254
255 QModelIndex
255 QModelIndex
256 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name)
256 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name)
257 {
257 {
258 auto databaseItem
258 auto databaseItem
259 = new CatalogueTextTreeItem{QIcon{":/icones/database.png"}, {name}, DATABASE_ITEM_TYPE};
259 = new CatalogueTextTreeItem{QIcon{":/icones/database.png"}, {name}, DATABASE_ITEM_TYPE};
260 auto databaseIndex = m_TreeModel->addTopLevelItem(databaseItem);
260 auto databaseIndex = m_TreeModel->addTopLevelItem(databaseItem);
261
261
262 return databaseIndex;
262 return databaseIndex;
263 }
263 }
264
264
265 CatalogueAbstractTreeItem *
265 CatalogueAbstractTreeItem *
266 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name)
266 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name)
267 {
267 {
268 for (auto item : m_TreeModel->topLevelItems()) {
268 for (auto item : m_TreeModel->topLevelItems()) {
269 if (item->type() == DATABASE_ITEM_TYPE && item->text() == name) {
269 if (item->type() == DATABASE_ITEM_TYPE && item->text() == name) {
270 return item;
270 return item;
271 }
271 }
272 }
272 }
273
273
274 return nullptr;
274 return nullptr;
275 }
275 }
276
276
277 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem(
277 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem(
278 const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex)
278 const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex)
279 {
279 {
280 auto catalogueItem
280 auto catalogueItem
281 = new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE};
281 = new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE};
282 m_TreeModel->addChildItem(catalogueItem, databaseIndex);
282 m_TreeModel->addChildItem(catalogueItem, databaseIndex);
283 }
283 }
284
284
285 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem(
285 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem(
286 const std::shared_ptr<DBCatalogue> &catalogue) const
286 const std::shared_ptr<DBCatalogue> &catalogue) const
287 {
287 {
288 for (auto item : m_TreeModel->topLevelItems()) {
288 for (auto item : m_TreeModel->topLevelItems()) {
289 if (item->type() == DATABASE_ITEM_TYPE) {
289 if (item->type() == DATABASE_ITEM_TYPE) {
290 for (auto childItem : item->children()) {
290 for (auto childItem : item->children()) {
291 if (childItem->type() == CATALOGUE_ITEM_TYPE) {
291 if (childItem->type() == CATALOGUE_ITEM_TYPE) {
292 auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem);
292 auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem);
293 if (catalogueItem->catalogue() == catalogue) {
293 if (catalogueItem->catalogue() == catalogue) {
294 return catalogueItem;
294 return catalogueItem;
295 }
295 }
296 }
296 }
297 else {
297 else {
298 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogueItem: Invalid tree "
298 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogueItem: Invalid tree "
299 "structure. A database item should "
299 "structure. A database item should "
300 "only contain catalogues.";
300 "only contain catalogues.";
301 Q_ASSERT(false);
301 Q_ASSERT(false);
302 }
302 }
303 }
303 }
304 }
304 }
305 }
305 }
306
306
307 return nullptr;
307 return nullptr;
308 }
308 }
309
309
310 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(bool value,
310 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(bool value,
311 const QModelIndex &index,
311 const QModelIndex &index,
312 QTreeView *treeView)
312 QTreeView *treeView)
313 {
313 {
314 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
314 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
315 if (value) {
315 if (value) {
316 if (!hasChanges(validationIndex, treeView)) {
316 if (!hasChanges(validationIndex, treeView)) {
317 auto widget = CatalogueExplorerHelper::buildValidationWidget(
317 auto widget = CatalogueExplorerHelper::buildValidationWidget(
318 treeView,
318 treeView, [this, validationIndex,
319 [this, validationIndex, treeView]() {
319 treeView]() { setHasChanges(false, validationIndex, treeView); },
320 setHasChanges(false, validationIndex, treeView);
321 },
322 [this, validationIndex, treeView]() {
320 [this, validationIndex, treeView]() {
323 setHasChanges(false, validationIndex, treeView);
321 setHasChanges(false, validationIndex, treeView);
324 });
322 });
325 treeView->setIndexWidget(validationIndex, widget);
323 treeView->setIndexWidget(validationIndex, widget);
326 }
324 }
327 }
325 }
328 else {
326 else {
329 // Note: the widget is destroyed
327 // Note: the widget is destroyed
330 treeView->setIndexWidget(validationIndex, nullptr);
328 treeView->setIndexWidget(validationIndex, nullptr);
331 }
329 }
332 }
330 }
333
331
334 bool CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::hasChanges(const QModelIndex &index,
332 bool CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::hasChanges(const QModelIndex &index,
335 QTreeView *treeView)
333 QTreeView *treeView)
336 {
334 {
337 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
335 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
338 return treeView->indexWidget(validationIndex) != nullptr;
336 return treeView->indexWidget(validationIndex) != nullptr;
339 }
337 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

Status change > Approved

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