##// END OF EJS Templates
Merge branch 'feature/CatalogueCatalogue' into develop
mperrinel -
r1359:2a3a8fe0212d merge
parent child
Show More
@@ -1,84 +1,86
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 // bool createCatalogue(const QString &name, QVector<QUuid> eventList);
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 updateCatalogue(std::shared_ptr<DBCatalogue> catalogue);
63 void updateCatalogue(std::shared_ptr<DBCatalogue> catalogue);
63 void removeCatalogue(std::shared_ptr<DBCatalogue> catalogue);
64 void removeCatalogue(std::shared_ptr<DBCatalogue> catalogue);
64 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);
65
67
66 void saveAll();
68 void saveAll();
67 bool hasChanges() const;
69 bool hasChanges() const;
68
70
69 /// Returns the MIME data associated to a list of variables
71 /// Returns the MIME data associated to a list of variables
70 QByteArray mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const;
72 QByteArray mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const;
71
73
72 /// Returns the list of variables contained in a MIME data
74 /// Returns the list of variables contained in a MIME data
73 QVector<std::shared_ptr<DBEvent> > eventsForMimeData(const QByteArray &mimeData) const;
75 QVector<std::shared_ptr<DBEvent> > eventsForMimeData(const QByteArray &mimeData) const;
74
76
75 public slots:
77 public slots:
76 /// Manage init/end of the controller
78 /// Manage init/end of the controller
77 void initialize();
79 void initialize();
78
80
79 private:
81 private:
80 class CatalogueControllerPrivate;
82 class CatalogueControllerPrivate;
81 spimpl::unique_impl_ptr<CatalogueControllerPrivate> impl;
83 spimpl::unique_impl_ptr<CatalogueControllerPrivate> impl;
82 };
84 };
83
85
84 #endif // SCIQLOP_CATALOGUECONTROLLER_H
86 #endif // SCIQLOP_CATALOGUECONTROLLER_H
@@ -1,462 +1,526
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 /**
31 * Possible types of an repository
32 */
33 enum class DBType { SYNC, WORK, TRASH };
30 class CatalogueController::CatalogueControllerPrivate {
34 class CatalogueController::CatalogueControllerPrivate {
31
35
32 public:
36 public:
33 explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {}
37 explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {}
34
38
35 CatalogueDao m_CatalogueDao;
39 CatalogueDao m_CatalogueDao;
36
40
37 QStringList m_RepositoryList;
41 QStringList m_RepositoryList;
38 CatalogueController *m_Q;
42 CatalogueController *m_Q;
39
43
40 QSet<QString> m_EventKeysWithChanges;
44 QSet<QString> m_KeysWithChanges;
41
45
42 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;
43
48
44 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
49 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
45 QString toWorkRepository(QString repository);
50 QString toWorkRepository(QString repository);
46 QString toSyncRepository(QString repository);
51 QString toSyncRepository(QString repository);
47 void savAllDB();
52 void savAllDB();
48
53
49 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
54 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
50 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
55 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
56
57 std::shared_ptr<IRequestPredicate> createFinder(const QUuid &uniqId, const QString &repository,
58 DBType type);
51 };
59 };
52
60
53 CatalogueController::CatalogueController(QObject *parent)
61 CatalogueController::CatalogueController(QObject *parent)
54 : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)}
62 : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)}
55 {
63 {
56 qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction")
64 qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction")
57 << QThread::currentThread();
65 << QThread::currentThread();
58 }
66 }
59
67
60 CatalogueController::~CatalogueController()
68 CatalogueController::~CatalogueController()
61 {
69 {
62 qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction")
70 qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction")
63 << QThread::currentThread();
71 << QThread::currentThread();
64 }
72 }
65
73
66 QStringList CatalogueController::getRepositories() const
74 QStringList CatalogueController::getRepositories() const
67 {
75 {
68 return impl->m_RepositoryList;
76 return impl->m_RepositoryList;
69 }
77 }
70
78
71 void CatalogueController::addDB(const QString &dbPath)
79 void CatalogueController::addDB(const QString &dbPath)
72 {
80 {
73 QDir dbDir(dbPath);
81 QDir dbDir(dbPath);
74 if (dbDir.exists()) {
82 if (dbDir.exists()) {
75 auto dirName = dbDir.dirName();
83 auto dirName = dbDir.dirName();
76
84
77 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)
78 != impl->m_RepositoryList.cend()) {
86 != impl->m_RepositoryList.cend()) {
79 qCCritical(LOG_CatalogueController())
87 qCCritical(LOG_CatalogueController())
80 << tr("Impossible to addDB that is already loaded");
88 << tr("Impossible to addDB that is already loaded");
81 }
89 }
82
90
83 if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) {
91 if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) {
84 qCCritical(LOG_CatalogueController())
92 qCCritical(LOG_CatalogueController())
85 << tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath);
93 << tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath);
86 }
94 }
87 else {
95 else {
88 impl->m_RepositoryList << dirName;
96 impl->m_RepositoryList << dirName;
89 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
97 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
90 }
98 }
91 }
99 }
92 else {
100 else {
93 qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ")
101 qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ")
94 << dbPath;
102 << dbPath;
95 }
103 }
96 }
104 }
97
105
98 void CatalogueController::saveDB(const QString &destinationPath, const QString &repository)
106 void CatalogueController::saveDB(const QString &destinationPath, const QString &repository)
99 {
107 {
100 if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) {
108 if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) {
101 qCCritical(LOG_CatalogueController())
109 qCCritical(LOG_CatalogueController())
102 << tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath);
110 << tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath);
103 }
111 }
104 }
112 }
105
113
106 std::list<std::shared_ptr<DBEvent> >
114 std::list<std::shared_ptr<DBEvent> >
107 CatalogueController::retrieveEvents(const QString &repository) const
115 CatalogueController::retrieveEvents(const QString &repository) const
108 {
116 {
109 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
117 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
110
118
111 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
119 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
112 auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName));
120 auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName));
113 for (auto event : events) {
121 for (auto event : events) {
114 eventsShared.push_back(std::make_shared<DBEvent>(event));
122 eventsShared.push_back(std::make_shared<DBEvent>(event));
115 }
123 }
116 return eventsShared;
124 return eventsShared;
117 }
125 }
118
126
119 std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const
127 std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const
120 {
128 {
121 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
129 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
122 for (auto repository : impl->m_RepositoryList) {
130 for (auto repository : impl->m_RepositoryList) {
123 eventsShared.splice(eventsShared.end(), retrieveEvents(repository));
131 eventsShared.splice(eventsShared.end(), retrieveEvents(repository));
124 }
132 }
125
133
126 return eventsShared;
134 return eventsShared;
127 }
135 }
128
136
129 std::list<std::shared_ptr<DBEvent> >
137 std::list<std::shared_ptr<DBEvent> >
130 CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const
138 CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const
131 {
139 {
132 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
140 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
133 auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue);
141 auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue);
134 for (auto event : events) {
142 for (auto event : events) {
135 eventsShared.push_back(std::make_shared<DBEvent>(event));
143 eventsShared.push_back(std::make_shared<DBEvent>(event));
136 }
144 }
137 return eventsShared;
145 return eventsShared;
138 }
146 }
139
147
140 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
148 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
141 {
149 {
142 event->setRepository(impl->toWorkRepository(event->getRepository()));
150 event->setRepository(impl->toWorkRepository(event->getRepository()));
143
151
144 auto uniqueId = impl->eventUniqueKey(event);
152 auto uniqueId = impl->eventUniqueKey(event);
145 impl->m_EventKeysWithChanges.insert(uniqueId);
153 impl->m_KeysWithChanges.insert(uniqueId);
146
154
147 impl->m_CatalogueDao.updateEvent(*event);
155 impl->m_CatalogueDao.updateEvent(*event);
148 }
156 }
149
157
150 void CatalogueController::updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct)
158 void CatalogueController::updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct)
151 {
159 {
152 impl->m_CatalogueDao.updateEventProduct(*eventProduct);
160 impl->m_CatalogueDao.updateEventProduct(*eventProduct);
153 }
161 }
154
162
155 void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event)
163 void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event)
156 {
164 {
157 // Remove it from both repository and repository_work
165 // Remove it from both repository and repository_work
158 event->setRepository(impl->toWorkRepository(event->getRepository()));
166 event->setRepository(impl->toWorkRepository(event->getRepository()));
159 impl->m_CatalogueDao.removeEvent(*event);
167 impl->m_CatalogueDao.removeEvent(*event);
160 event->setRepository(impl->toSyncRepository(event->getRepository()));
168 event->setRepository(impl->toSyncRepository(event->getRepository()));
161 impl->m_CatalogueDao.removeEvent(*event);
169 impl->m_CatalogueDao.removeEvent(*event);
162 impl->savAllDB();
170 impl->savAllDB();
163 }
171 }
164
172
165 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
173 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
166 {
174 {
167 event->setRepository(impl->toWorkRepository(event->getRepository()));
175 event->setRepository(impl->toWorkRepository(event->getRepository()));
168
176
169 auto eventTemp = *event;
177 auto eventTemp = *event;
170 impl->m_CatalogueDao.addEvent(eventTemp);
178 impl->m_CatalogueDao.addEvent(eventTemp);
171
179
172 // 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
173 // products
181 // products
174 if (!event->getEventProducts().empty() || !event->getTags().empty()) {
182 if (!event->getEventProducts().empty() || !event->getTags().empty()) {
175
183
176 auto eventProductsTemp = eventTemp.getEventProducts();
184 auto eventProductsTemp = eventTemp.getEventProducts();
177 auto eventProductTempUpdated = std::list<DBEventProduct>{};
185 auto eventProductTempUpdated = std::list<DBEventProduct>{};
178 for (auto eventProductTemp : eventProductsTemp) {
186 for (auto eventProductTemp : eventProductsTemp) {
179 eventProductTemp.setEvent(eventTemp);
187 eventProductTemp.setEvent(eventTemp);
180 eventProductTempUpdated.push_back(eventProductTemp);
188 eventProductTempUpdated.push_back(eventProductTemp);
181 }
189 }
182 eventTemp.setEventProducts(eventProductTempUpdated);
190 eventTemp.setEventProducts(eventProductTempUpdated);
183
191
184 impl->m_CatalogueDao.updateEvent(eventTemp);
192 impl->m_CatalogueDao.updateEvent(eventTemp);
185 }
193 }
186
194
187 // update event parameter
195 auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK);
188 auto uniqIdPredicate = std::make_shared<ComparaisonPredicate>(
189 QString{"uniqId"}, event->getUniqId(), ComparaisonOperation::EQUALEQUAL);
190
191 auto workRepositoryPredicate = std::make_shared<ComparaisonPredicate>(
192 QString{"repository"}, impl->toWorkRepository(event->getRepository()),
193 ComparaisonOperation::EQUALEQUAL);
194
195 auto workPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
196 workPred->AddRequestPredicate(uniqIdPredicate);
197 workPred->AddRequestPredicate(workRepositoryPredicate);
198
196
199 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
197 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
200 *event = workEvent;
198 *event = workEvent;
201
199
200
202 auto uniqueId = impl->eventUniqueKey(event);
201 auto uniqueId = impl->eventUniqueKey(event);
203 impl->m_EventKeysWithChanges.insert(uniqueId);
202 impl->m_KeysWithChanges.insert(uniqueId);
204 }
203 }
205
204
206 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
205 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
207 {
206 {
208 impl->saveEvent(event, true);
207 impl->saveEvent(event, true);
209 impl->m_EventKeysWithChanges.remove(impl->eventUniqueKey(event));
208 impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event));
210 }
209 }
211
210
212 void CatalogueController::discardEvent(std::shared_ptr<DBEvent> event, bool &removed)
211 void CatalogueController::discardEvent(std::shared_ptr<DBEvent> event, bool &removed)
213 {
212 {
214 auto uniqIdPredicate = std::make_shared<ComparaisonPredicate>(
213 auto syncPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::SYNC);
215 QString{"uniqId"}, event->getUniqId(), ComparaisonOperation::EQUALEQUAL);
214 auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK);
216
217 auto syncRepositoryPredicate = std::make_shared<ComparaisonPredicate>(
218 QString{"repository"}, impl->toSyncRepository(event->getRepository()),
219 ComparaisonOperation::EQUALEQUAL);
220
221 auto syncPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
222 syncPred->AddRequestPredicate(uniqIdPredicate);
223 syncPred->AddRequestPredicate(syncRepositoryPredicate);
224
225
226 auto workRepositoryPredicate = std::make_shared<ComparaisonPredicate>(
227 QString{"repository"}, impl->toWorkRepository(event->getRepository()),
228 ComparaisonOperation::EQUALEQUAL);
229
230 auto workPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
231 workPred->AddRequestPredicate(uniqIdPredicate);
232 workPred->AddRequestPredicate(workRepositoryPredicate);
233
234
215
235 auto syncEvent = impl->m_CatalogueDao.getEvent(syncPred);
216 auto syncEvent = impl->m_CatalogueDao.getEvent(syncPred);
236 if (!syncEvent.getUniqId().isNull()) {
217 if (!syncEvent.getUniqId().isNull()) {
237 removed = false;
218 removed = false;
238 impl->m_CatalogueDao.copyEvent(syncEvent, impl->toWorkRepository(event->getRepository()),
219 impl->m_CatalogueDao.copyEvent(syncEvent, impl->toWorkRepository(event->getRepository()),
239 true);
220 true);
240
221
241 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
222 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
242 *event = workEvent;
223 *event = workEvent;
243 impl->m_EventKeysWithChanges.remove(impl->eventUniqueKey(event));
224 impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event));
244 }
225 }
245 else {
226 else {
246 removed = true;
227 removed = true;
247 // 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
248 event->setRepository(impl->toWorkRepository(event->getRepository()));
229 event->setRepository(impl->toWorkRepository(event->getRepository()));
249 impl->m_CatalogueDao.removeEvent(*event);
230 impl->m_CatalogueDao.removeEvent(*event);
250 }
231 }
251 }
232 }
252
233
253 bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const
234 bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const
254 {
235 {
255 return impl->m_EventKeysWithChanges.contains(impl->eventUniqueKey(event));
236 return impl->m_KeysWithChanges.contains(impl->eventUniqueKey(event));
256 }
237 }
257
238
258 std::list<std::shared_ptr<DBCatalogue> >
239 std::list<std::shared_ptr<DBCatalogue> >
259 CatalogueController::retrieveCatalogues(const QString &repository) const
240 CatalogueController::retrieveCatalogues(const QString &repository) const
260 {
241 {
261 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
242 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
262
243
263 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
244 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
264 auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName));
245 auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName));
265 for (auto catalogue : catalogues) {
246 for (auto catalogue : catalogues) {
266 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
247 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
267 }
248 }
268 return cataloguesShared;
249 return cataloguesShared;
269 }
250 }
270
251
252 void CatalogueController::addCatalogue(std::shared_ptr<DBCatalogue> catalogue)
253 {
254 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
255
256 auto catalogueTemp = *catalogue;
257 impl->m_CatalogueDao.addCatalogue(catalogueTemp);
258
259 auto workPred
260 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK);
261
262 auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred);
263 *catalogue = workCatalogue;
264
265 auto uniqueId = impl->catalogueUniqueKey(catalogue);
266 impl->m_KeysWithChanges.insert(uniqueId);
267 }
268
271 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
269 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
272 {
270 {
273 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
271 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
274
272
273 auto uniqueId = impl->catalogueUniqueKey(catalogue);
274 impl->m_KeysWithChanges.insert(uniqueId);
275
275 impl->m_CatalogueDao.updateCatalogue(*catalogue);
276 impl->m_CatalogueDao.updateCatalogue(*catalogue);
276 }
277 }
277
278
278 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue)
279 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue)
279 {
280 {
280 // Remove it from both repository and repository_work
281 // Remove it from both repository and repository_work
281 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
282 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
282 impl->m_CatalogueDao.removeCatalogue(*catalogue);
283 impl->m_CatalogueDao.removeCatalogue(*catalogue);
283 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
284 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
284 impl->m_CatalogueDao.removeCatalogue(*catalogue);
285 impl->m_CatalogueDao.removeCatalogue(*catalogue);
286 impl->savAllDB();
285 }
287 }
286
288
287 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
289 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
288 {
290 {
289 impl->saveCatalogue(catalogue, true);
291 impl->saveCatalogue(catalogue, true);
292 impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue));
293 }
294
295 void CatalogueController::discardCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool &removed)
296 {
297 auto syncPred
298 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::SYNC);
299 auto workPred
300 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK);
301
302 auto syncCatalogue = impl->m_CatalogueDao.getCatalogue(syncPred);
303 if (!syncCatalogue.getUniqId().isNull()) {
304 removed = false;
305 impl->m_CatalogueDao.copyCatalogue(
306 syncCatalogue, impl->toWorkRepository(catalogue->getRepository()), true);
307
308 auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred);
309 *catalogue = workCatalogue;
310 impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue));
311 }
312 else {
313 removed = true;
314 // Since the element wasn't in sync repository. Discard it means remove it
315 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
316 impl->m_CatalogueDao.removeCatalogue(*catalogue);
317 }
290 }
318 }
291
319
292 void CatalogueController::saveAll()
320 void CatalogueController::saveAll()
293 {
321 {
294 for (auto repository : impl->m_RepositoryList) {
322 for (auto repository : impl->m_RepositoryList) {
295 // Save Event
323 // Save Event
296 auto events = this->retrieveEvents(repository);
324 auto events = this->retrieveEvents(repository);
297 for (auto event : events) {
325 for (auto event : events) {
298 impl->saveEvent(event, false);
326 impl->saveEvent(event, false);
299 }
327 }
300
328
301 // Save Catalogue
329 // Save Catalogue
302 auto catalogues = this->retrieveCatalogues(repository);
330 auto catalogues = this->retrieveCatalogues(repository);
303 for (auto catalogue : catalogues) {
331 for (auto catalogue : catalogues) {
304 impl->saveCatalogue(catalogue, false);
332 impl->saveCatalogue(catalogue, false);
305 }
333 }
306 }
334 }
307
335
308 impl->savAllDB();
336 impl->savAllDB();
309 impl->m_EventKeysWithChanges.clear();
337 impl->m_KeysWithChanges.clear();
310 }
338 }
311
339
312 bool CatalogueController::hasChanges() const
340 bool CatalogueController::hasChanges() const
313 {
341 {
314 return !impl->m_EventKeysWithChanges.isEmpty(); // TODO: catalogues
342 return !impl->m_KeysWithChanges.isEmpty();
315 }
343 }
316
344
317 QByteArray
345 QByteArray
318 CatalogueController::mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const
346 CatalogueController::mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const
319 {
347 {
320 auto encodedData = QByteArray{};
348 auto encodedData = QByteArray{};
321
349
322 QMap<QString, QVariantList> idsPerRepository;
350 QMap<QString, QVariantList> idsPerRepository;
323 for (auto event : events) {
351 for (auto event : events) {
324 idsPerRepository[event->getRepository()] << event->getUniqId();
352 idsPerRepository[event->getRepository()] << event->getUniqId();
325 }
353 }
326
354
327 QDataStream stream{&encodedData, QIODevice::WriteOnly};
355 QDataStream stream{&encodedData, QIODevice::WriteOnly};
328 stream << idsPerRepository;
356 stream << idsPerRepository;
329
357
330 return encodedData;
358 return encodedData;
331 }
359 }
332
360
333 QVector<std::shared_ptr<DBEvent> >
361 QVector<std::shared_ptr<DBEvent> >
334 CatalogueController::eventsForMimeData(const QByteArray &mimeData) const
362 CatalogueController::eventsForMimeData(const QByteArray &mimeData) const
335 {
363 {
336 auto events = QVector<std::shared_ptr<DBEvent> >{};
364 auto events = QVector<std::shared_ptr<DBEvent> >{};
337 QDataStream stream{mimeData};
365 QDataStream stream{mimeData};
338
366
339 QMap<QString, QVariantList> idsPerRepository;
367 QMap<QString, QVariantList> idsPerRepository;
340 stream >> idsPerRepository;
368 stream >> idsPerRepository;
341
369
342 for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) {
370 for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) {
343 auto repository = it.key();
371 auto repository = it.key();
344 auto allRepositoryEvent = retrieveEvents(repository);
372 auto allRepositoryEvent = retrieveEvents(repository);
345 for (auto uuid : it.value()) {
373 for (auto uuid : it.value()) {
346 for (auto repositoryEvent : allRepositoryEvent) {
374 for (auto repositoryEvent : allRepositoryEvent) {
347 if (uuid.toUuid() == repositoryEvent->getUniqId()) {
375 if (uuid.toUuid() == repositoryEvent->getUniqId()) {
348 events << repositoryEvent;
376 events << repositoryEvent;
349 }
377 }
350 }
378 }
351 }
379 }
352 }
380 }
353
381
354 return events;
382 return events;
355 }
383 }
356
384
357 void CatalogueController::initialize()
385 void CatalogueController::initialize()
358 {
386 {
359 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
387 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
360 << QThread::currentThread();
388 << QThread::currentThread();
361
389
362 impl->m_CatalogueDao.initialize();
390 impl->m_CatalogueDao.initialize();
363 auto defaultRepositoryLocation
391 auto defaultRepositoryLocation
364 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
392 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
365
393
366 QDir defaultRepositoryLocationDir;
394 QDir defaultRepositoryLocationDir;
367 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
395 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
368 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
396 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
369 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
397 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
370
398
371 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
399 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
372 << defaultRepository;
400 << defaultRepository;
373
401
374 QDir dbDir(defaultRepository);
402 QDir dbDir(defaultRepository);
375 impl->m_RepositoryList << REPOSITORY_DEFAULT;
403 impl->m_RepositoryList << REPOSITORY_DEFAULT;
376 if (dbDir.exists()) {
404 if (dbDir.exists()) {
377 auto dirName = dbDir.dirName();
405 auto dirName = dbDir.dirName();
378
406
379 if (impl->m_CatalogueDao.addDB(defaultRepository, dirName)) {
407 if (impl->m_CatalogueDao.addDB(defaultRepository, dirName)) {
380 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
408 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
381 }
409 }
382 }
410 }
383 else {
411 else {
384 qCInfo(LOG_CatalogueController()) << tr("Initialisation of Default repository detected")
412 qCInfo(LOG_CatalogueController()) << tr("Initialisation of Default repository detected")
385 << defaultRepository;
413 << defaultRepository;
386 }
414 }
387 }
415 }
388 else {
416 else {
389 qCWarning(LOG_CatalogueController())
417 qCWarning(LOG_CatalogueController())
390 << tr("Cannot load the persistent default repository from ")
418 << tr("Cannot load the persistent default repository from ")
391 << defaultRepositoryLocation;
419 << defaultRepositoryLocation;
392 }
420 }
393
421
394 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END");
422 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END");
395 }
423 }
396
424
397 QString CatalogueController::CatalogueControllerPrivate::eventUniqueKey(
425 QString CatalogueController::CatalogueControllerPrivate::eventUniqueKey(
398 const std::shared_ptr<DBEvent> &event) const
426 const std::shared_ptr<DBEvent> &event) const
399 {
427 {
400 return event->getUniqId().toString().append(event->getRepository());
428 return event->getUniqId().toString().append(event->getRepository());
401 }
429 }
402
430
431 QString CatalogueController::CatalogueControllerPrivate::catalogueUniqueKey(
432 const std::shared_ptr<DBCatalogue> &catalogue) const
433 {
434 return catalogue->getUniqId().toString().append(catalogue->getRepository());
435 }
436
403 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
437 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
404 const QString &dbTo)
438 const QString &dbTo)
405 {
439 {
406 // auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
440 // auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
407 auto catalogues = m_CatalogueDao.getCatalogues(dbFrom);
441 auto catalogues = m_CatalogueDao.getCatalogues(dbFrom);
408 auto events = m_CatalogueDao.getEvents(dbFrom);
442 auto events = m_CatalogueDao.getEvents(dbFrom);
409 for (auto catalogue : catalogues) {
443 for (auto catalogue : catalogues) {
410 m_CatalogueDao.copyCatalogue(catalogue, dbTo, true);
444 m_CatalogueDao.copyCatalogue(catalogue, dbTo, true);
411 }
445 }
412
446
413 for (auto event : events) {
447 for (auto event : events) {
414 m_CatalogueDao.copyEvent(event, dbTo, true);
448 m_CatalogueDao.copyEvent(event, dbTo, true);
415 }
449 }
416 }
450 }
417
451
418 QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository)
452 QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository)
419 {
453 {
420 auto syncRepository = toSyncRepository(repository);
454 auto syncRepository = toSyncRepository(repository);
421
455
422 return QString("%1%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX);
456 return QString("%1%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX);
423 }
457 }
424
458
425 QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository)
459 QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository)
426 {
460 {
427 auto syncRepository = repository;
461 auto syncRepository = repository;
428 if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) {
462 if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) {
429 syncRepository.remove(REPOSITORY_WORK_SUFFIX);
463 syncRepository.remove(REPOSITORY_WORK_SUFFIX);
430 }
464 }
431 else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) {
465 else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) {
432 syncRepository.remove(REPOSITORY_TRASH_SUFFIX);
466 syncRepository.remove(REPOSITORY_TRASH_SUFFIX);
433 }
467 }
434 return syncRepository;
468 return syncRepository;
435 }
469 }
436
470
437 void CatalogueController::CatalogueControllerPrivate::savAllDB()
471 void CatalogueController::CatalogueControllerPrivate::savAllDB()
438 {
472 {
439 for (auto repository : m_RepositoryList) {
473 for (auto repository : m_RepositoryList) {
440 auto defaultRepositoryLocation
474 auto defaultRepositoryLocation
441 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
475 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
442 m_CatalogueDao.saveDB(defaultRepositoryLocation, repository);
476 m_CatalogueDao.saveDB(defaultRepositoryLocation, repository);
443 }
477 }
444 }
478 }
445
479
446 void CatalogueController::CatalogueControllerPrivate::saveEvent(std::shared_ptr<DBEvent> event,
480 void CatalogueController::CatalogueControllerPrivate::saveEvent(std::shared_ptr<DBEvent> event,
447 bool persist)
481 bool persist)
448 {
482 {
449 m_CatalogueDao.copyEvent(*event, toSyncRepository(event->getRepository()), true);
483 m_CatalogueDao.copyEvent(*event, toSyncRepository(event->getRepository()), true);
450 if (persist) {
484 if (persist) {
451 savAllDB();
485 savAllDB();
452 }
486 }
453 }
487 }
454
488
455 void CatalogueController::CatalogueControllerPrivate::saveCatalogue(
489 void CatalogueController::CatalogueControllerPrivate::saveCatalogue(
456 std::shared_ptr<DBCatalogue> catalogue, bool persist)
490 std::shared_ptr<DBCatalogue> catalogue, bool persist)
457 {
491 {
458 m_CatalogueDao.copyCatalogue(*catalogue, toSyncRepository(catalogue->getRepository()), true);
492 m_CatalogueDao.copyCatalogue(*catalogue, toSyncRepository(catalogue->getRepository()), true);
459 if (persist) {
493 if (persist) {
460 savAllDB();
494 savAllDB();
461 }
495 }
462 }
496 }
497
498 std::shared_ptr<IRequestPredicate> CatalogueController::CatalogueControllerPrivate::createFinder(
499 const QUuid &uniqId, const QString &repository, DBType type)
500 {
501 // update catalogue parameter
502 auto uniqIdPredicate = std::make_shared<ComparaisonPredicate>(QString{"uniqId"}, uniqId,
503 ComparaisonOperation::EQUALEQUAL);
504
505 auto repositoryType = repository;
506 switch (type) {
507 case DBType::SYNC:
508 repositoryType = toSyncRepository(repositoryType);
509 break;
510 case DBType::WORK:
511 repositoryType = toWorkRepository(repositoryType);
512 break;
513 case DBType::TRASH:
514 default:
515 break;
516 }
517
518 auto repositoryPredicate = std::make_shared<ComparaisonPredicate>(
519 QString{"repository"}, repositoryType, ComparaisonOperation::EQUALEQUAL);
520
521 auto finderPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
522 finderPred->AddRequestPredicate(uniqIdPredicate);
523 finderPred->AddRequestPredicate(repositoryPredicate);
524
525 return finderPred;
526 }
@@ -1,46 +1,51
1 #ifndef SCIQLOP_CATALOGUESIDEBARWIDGET_H
1 #ifndef SCIQLOP_CATALOGUESIDEBARWIDGET_H
2 #define SCIQLOP_CATALOGUESIDEBARWIDGET_H
2 #define SCIQLOP_CATALOGUESIDEBARWIDGET_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QLoggingCategory>
5 #include <QLoggingCategory>
6 #include <QTreeWidgetItem>
6 #include <QTreeWidgetItem>
7 #include <QWidget>
7 #include <QWidget>
8
8
9 class CatalogueAbstractTreeItem;
9 class DBCatalogue;
10 class DBCatalogue;
10
11
11 namespace Ui {
12 namespace Ui {
12 class CatalogueSideBarWidget;
13 class CatalogueSideBarWidget;
13 }
14 }
14
15
15 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget)
16 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget)
16
17
17 class CatalogueSideBarWidget : public QWidget {
18 class CatalogueSideBarWidget : public QWidget {
18 Q_OBJECT
19 Q_OBJECT
19
20
20 signals:
21 signals:
21 void catalogueSelected(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
22 void catalogueSelected(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
22 void databaseSelected(const QStringList &databases);
23 void databaseSelected(const QStringList &databases);
23 void allEventsSelected();
24 void allEventsSelected();
24 void trashSelected();
25 void trashSelected();
25 void selectionCleared();
26 void selectionCleared();
26
27
27 public:
28 public:
28 explicit CatalogueSideBarWidget(QWidget *parent = 0);
29 explicit CatalogueSideBarWidget(QWidget *parent = 0);
29 virtual ~CatalogueSideBarWidget();
30 virtual ~CatalogueSideBarWidget();
30
31
31 void addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue, const QString &repository);
32 CatalogueAbstractTreeItem *addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
33 const QString &repository);
32 void setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue, bool hasChanges);
34 void setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue, bool hasChanges);
33
35
34 QVector<std::shared_ptr<DBCatalogue> > getCatalogues(const QString &repository) const;
36 QVector<std::shared_ptr<DBCatalogue> > getCatalogues(const QString &repository) const;
35
37
38 private slots:
39 void emitSelection();
40
36 private:
41 private:
37 Ui::CatalogueSideBarWidget *ui;
42 Ui::CatalogueSideBarWidget *ui;
38
43
39 class CatalogueSideBarWidgetPrivate;
44 class CatalogueSideBarWidgetPrivate;
40 spimpl::unique_impl_ptr<CatalogueSideBarWidgetPrivate> impl;
45 spimpl::unique_impl_ptr<CatalogueSideBarWidgetPrivate> impl;
41
46
42 private slots:
47 private slots:
43 void onContextMenuRequested(const QPoint &pos);
48 void onContextMenuRequested(const QPoint &pos);
44 };
49 };
45
50
46 #endif // SCIQLOP_CATALOGUESIDEBARWIDGET_H
51 #endif // SCIQLOP_CATALOGUESIDEBARWIDGET_H
@@ -1,35 +1,36
1 #ifndef SCIQLOP_CATALOGUEABSTRACTTREEITEM_H
1 #ifndef SCIQLOP_CATALOGUEABSTRACTTREEITEM_H
2 #define SCIQLOP_CATALOGUEABSTRACTTREEITEM_H
2 #define SCIQLOP_CATALOGUEABSTRACTTREEITEM_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QVariant>
5 #include <QVariant>
6 #include <QVector>
6 #include <QVector>
7
7
8 class QMimeData;
8 class QMimeData;
9
9
10 class CatalogueAbstractTreeItem {
10 class CatalogueAbstractTreeItem {
11 public:
11 public:
12 constexpr static const int DEFAULT_TYPE = -1;
12 constexpr static const int DEFAULT_TYPE = -1;
13
13
14 CatalogueAbstractTreeItem(int type = DEFAULT_TYPE);
14 CatalogueAbstractTreeItem(int type = DEFAULT_TYPE);
15 virtual ~CatalogueAbstractTreeItem();
15 virtual ~CatalogueAbstractTreeItem();
16
16
17 void addChild(CatalogueAbstractTreeItem *child);
17 void addChild(CatalogueAbstractTreeItem *child);
18 void removeChild(CatalogueAbstractTreeItem *child);
18 QVector<CatalogueAbstractTreeItem *> children() const;
19 QVector<CatalogueAbstractTreeItem *> children() const;
19 CatalogueAbstractTreeItem *parent() const;
20 CatalogueAbstractTreeItem *parent() const;
20
21
21 int type() const;
22 int type() const;
22 QString text(int column = 0) const;
23 QString text(int column = 0) const;
23
24
24 virtual QVariant data(int column, int role) const;
25 virtual QVariant data(int column, int role) const;
25 virtual Qt::ItemFlags flags(int column) const;
26 virtual Qt::ItemFlags flags(int column) const;
26 virtual bool setData(int column, int role, const QVariant &value);
27 virtual bool setData(int column, int role, const QVariant &value);
27 virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action);
28 virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action);
28 virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action);
29 virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action);
29
30
30 private:
31 private:
31 class CatalogueAbstractTreeItemPrivate;
32 class CatalogueAbstractTreeItemPrivate;
32 spimpl::unique_impl_ptr<CatalogueAbstractTreeItemPrivate> impl;
33 spimpl::unique_impl_ptr<CatalogueAbstractTreeItemPrivate> impl;
33 };
34 };
34
35
35 #endif // SCIQLOP_CATALOGUEABSTRACTTREEITEM_H
36 #endif // SCIQLOP_CATALOGUEABSTRACTTREEITEM_H
@@ -1,56 +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);
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);
31 /// Refresh the data for the specified index
32 void refresh(const QModelIndex &index);
30
33
31 CatalogueAbstractTreeItem *item(const QModelIndex &index) const;
34 CatalogueAbstractTreeItem *item(const QModelIndex &index) const;
32 QModelIndex indexOf(CatalogueAbstractTreeItem *item, int column = 0) const;
35 QModelIndex indexOf(CatalogueAbstractTreeItem *item, int column = 0) const;
33
36
34 // model
37 // model
35 QModelIndex index(int row, int column,
38 QModelIndex index(int row, int column,
36 const QModelIndex &parent = QModelIndex()) const override;
39 const QModelIndex &parent = QModelIndex()) const override;
37 QModelIndex parent(const QModelIndex &index) const override;
40 QModelIndex parent(const QModelIndex &index) const override;
38 int rowCount(const QModelIndex &parent) const override;
41 int rowCount(const QModelIndex &parent) const override;
39 int columnCount(const QModelIndex &parent) const override;
42 int columnCount(const QModelIndex &parent) const override;
40 Qt::ItemFlags flags(const QModelIndex &index) const override;
43 Qt::ItemFlags flags(const QModelIndex &index) const override;
41 QVariant data(const QModelIndex &index, int role) const override;
44 QVariant data(const QModelIndex &index, int role) const override;
42 bool setData(const QModelIndex &index, const QVariant &value, int role) override;
45 bool setData(const QModelIndex &index, const QVariant &value, int role) override;
43
46
44 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,
45 const QModelIndex &parent) const override;
48 const QModelIndex &parent) const override;
46 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,
47 const QModelIndex &parent) override;
50 const QModelIndex &parent) override;
48 Qt::DropActions supportedDropActions() const;
51 Qt::DropActions supportedDropActions() const;
49 QStringList mimeTypes() const;
52 QStringList mimeTypes() const;
50
53
51 private:
54 private:
52 class CatalogueTreeModelPrivate;
55 class CatalogueTreeModelPrivate;
53 spimpl::unique_impl_ptr<CatalogueTreeModelPrivate> impl;
56 spimpl::unique_impl_ptr<CatalogueTreeModelPrivate> impl;
54 };
57 };
55
58
56 #endif // CATALOGUETREEMODEL_H
59 #endif // CATALOGUETREEMODEL_H
@@ -1,147 +1,147
1 #include "Catalogue/CatalogueActionManager.h"
1 #include "Catalogue/CatalogueActionManager.h"
2
2
3 #include <Actions/ActionsGuiController.h>
3 #include <Actions/ActionsGuiController.h>
4 #include <Catalogue/CatalogueController.h>
4 #include <Catalogue/CatalogueController.h>
5 #include <DataSource/DataSourceItem.h>
5 #include <DataSource/DataSourceItem.h>
6 #include <SqpApplication.h>
6 #include <SqpApplication.h>
7 #include <Variable/Variable.h>
7 #include <Variable/Variable.h>
8 #include <Visualization/VisualizationGraphWidget.h>
8 #include <Visualization/VisualizationGraphWidget.h>
9 #include <Visualization/VisualizationSelectionZoneItem.h>
9 #include <Visualization/VisualizationSelectionZoneItem.h>
10
10
11 #include <Catalogue/CatalogueEventsWidget.h>
11 #include <Catalogue/CatalogueEventsWidget.h>
12 #include <Catalogue/CatalogueExplorer.h>
12 #include <Catalogue/CatalogueExplorer.h>
13 #include <Catalogue/CatalogueSideBarWidget.h>
13 #include <Catalogue/CatalogueSideBarWidget.h>
14 #include <Catalogue/CreateEventDialog.h>
14 #include <Catalogue/CreateEventDialog.h>
15
15
16 #include <CatalogueDao.h>
16 #include <CatalogueDao.h>
17 #include <DBCatalogue.h>
17 #include <DBCatalogue.h>
18 #include <DBEvent.h>
18 #include <DBEvent.h>
19 #include <DBEventProduct.h>
19 #include <DBEventProduct.h>
20
20
21 #include <QBoxLayout>
21 #include <QBoxLayout>
22 #include <QComboBox>
22 #include <QComboBox>
23 #include <QDialog>
23 #include <QDialog>
24 #include <QDialogButtonBox>
24 #include <QDialogButtonBox>
25 #include <QLineEdit>
25 #include <QLineEdit>
26 #include <memory>
26 #include <memory>
27
27
28 struct CatalogueActionManager::CatalogueActionManagerPrivate {
28 struct CatalogueActionManager::CatalogueActionManagerPrivate {
29
29
30 CatalogueExplorer *m_CatalogueExplorer = nullptr;
30 CatalogueExplorer *m_CatalogueExplorer = nullptr;
31
31
32 CatalogueActionManagerPrivate(CatalogueExplorer *catalogueExplorer)
32 CatalogueActionManagerPrivate(CatalogueExplorer *catalogueExplorer)
33 : m_CatalogueExplorer(catalogueExplorer)
33 : m_CatalogueExplorer(catalogueExplorer)
34 {
34 {
35 }
35 }
36
36
37 void createEventFromZones(const QString &eventName,
37 void createEventFromZones(const QString &eventName,
38 const QVector<VisualizationSelectionZoneItem *> &zones,
38 const QVector<VisualizationSelectionZoneItem *> &zones,
39 const std::shared_ptr<DBCatalogue> &catalogue = nullptr)
39 const std::shared_ptr<DBCatalogue> &catalogue = nullptr)
40 {
40 {
41 auto event = std::make_shared<DBEvent>();
41 auto event = std::make_shared<DBEvent>();
42 event->setName(eventName);
42 event->setName(eventName);
43
43
44 std::list<DBEventProduct> productList;
44 std::list<DBEventProduct> productList;
45 for (auto zone : zones) {
45 for (auto zone : zones) {
46 auto graph = zone->parentGraphWidget();
46 auto graph = zone->parentGraphWidget();
47 for (auto var : graph->variables()) {
47 for (auto var : graph->variables()) {
48 auto eventProduct = std::make_shared<DBEventProduct>();
48 auto eventProduct = std::make_shared<DBEventProduct>();
49 eventProduct->setEvent(*event);
49 eventProduct->setEvent(*event);
50
50
51 auto productId
51 auto productId
52 = var->metadata().value(DataSourceItem::ID_DATA_KEY, "UnknownID").toString();
52 = var->metadata().value(DataSourceItem::ID_DATA_KEY, "UnknownID").toString();
53
53
54 auto zoneRange = zone->range();
54 auto zoneRange = zone->range();
55 eventProduct->setTStart(zoneRange.m_TStart);
55 eventProduct->setTStart(zoneRange.m_TStart);
56 eventProduct->setTEnd(zoneRange.m_TEnd);
56 eventProduct->setTEnd(zoneRange.m_TEnd);
57
57
58 eventProduct->setProductId(productId);
58 eventProduct->setProductId(productId);
59
59
60 productList.push_back(*eventProduct);
60 productList.push_back(*eventProduct);
61
61
62 m_CatalogueExplorer->addSelectionZoneItem(event, productId, zone);
62 m_CatalogueExplorer->addSelectionZoneItem(event, productId, zone);
63 }
63 }
64 }
64 }
65
65
66 event->setEventProducts(productList);
66 event->setEventProducts(productList);
67
67
68 sqpApp->catalogueController().addEvent(event);
68 sqpApp->catalogueController().addEvent(event);
69
69
70
70
71 if (catalogue) {
71 if (catalogue) {
72 // TODO
72 catalogue->addEvent(event->getUniqId());
73 // catalogue->addEvent(event);
73 sqpApp->catalogueController().updateCatalogue(catalogue);
74 m_CatalogueExplorer->sideBarWidget().setCatalogueChanges(catalogue, true);
74 m_CatalogueExplorer->sideBarWidget().setCatalogueChanges(catalogue, true);
75 if (m_CatalogueExplorer->eventsWidget().displayedCatalogues().contains(catalogue)) {
75 if (m_CatalogueExplorer->eventsWidget().displayedCatalogues().contains(catalogue)) {
76 m_CatalogueExplorer->eventsWidget().addEvent(event);
76 m_CatalogueExplorer->eventsWidget().addEvent(event);
77 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
77 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
78 }
78 }
79 }
79 }
80 else if (m_CatalogueExplorer->eventsWidget().isAllEventsDisplayed()) {
80 else if (m_CatalogueExplorer->eventsWidget().isAllEventsDisplayed()) {
81 m_CatalogueExplorer->eventsWidget().addEvent(event);
81 m_CatalogueExplorer->eventsWidget().addEvent(event);
82 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
82 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
83 }
83 }
84 }
84 }
85 };
85 };
86
86
87 CatalogueActionManager::CatalogueActionManager(CatalogueExplorer *catalogueExplorer)
87 CatalogueActionManager::CatalogueActionManager(CatalogueExplorer *catalogueExplorer)
88 : impl{spimpl::make_unique_impl<CatalogueActionManagerPrivate>(catalogueExplorer)}
88 : impl{spimpl::make_unique_impl<CatalogueActionManagerPrivate>(catalogueExplorer)}
89 {
89 {
90 }
90 }
91
91
92 void CatalogueActionManager::installSelectionZoneActions()
92 void CatalogueActionManager::installSelectionZoneActions()
93 {
93 {
94 auto &actionController = sqpApp->actionsGuiController();
94 auto &actionController = sqpApp->actionsGuiController();
95
95
96 auto createEventEnableFuntion = [](auto zones) {
96 auto createEventEnableFuntion = [](auto zones) {
97
97
98 // Checks that all variables in the zones doesn't refer to the same product
98 // Checks that all variables in the zones doesn't refer to the same product
99 QSet<QString> usedDatasource;
99 QSet<QString> usedDatasource;
100 for (auto zone : zones) {
100 for (auto zone : zones) {
101 auto graph = zone->parentGraphWidget();
101 auto graph = zone->parentGraphWidget();
102 auto variables = graph->variables();
102 auto variables = graph->variables();
103
103
104 for (auto var : variables) {
104 for (auto var : variables) {
105 auto datasourceId = var->metadata().value(DataSourceItem::ID_DATA_KEY).toString();
105 auto datasourceId = var->metadata().value(DataSourceItem::ID_DATA_KEY).toString();
106 if (!usedDatasource.contains(datasourceId)) {
106 if (!usedDatasource.contains(datasourceId)) {
107 usedDatasource.insert(datasourceId);
107 usedDatasource.insert(datasourceId);
108 }
108 }
109 else {
109 else {
110 return false;
110 return false;
111 }
111 }
112 }
112 }
113 }
113 }
114
114
115 return true;
115 return true;
116 };
116 };
117
117
118 auto createEventAction = actionController.addSectionZoneAction(
118 auto createEventAction = actionController.addSectionZoneAction(
119 {QObject::tr("Catalogues")}, QObject::tr("New Event..."), [this](auto zones) {
119 {QObject::tr("Catalogues")}, QObject::tr("New Event..."), [this](auto zones) {
120 CreateEventDialog dialog(
120 CreateEventDialog dialog(
121 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
121 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
122 dialog.hideCatalogueChoice();
122 dialog.hideCatalogueChoice();
123 if (dialog.exec() == QDialog::Accepted) {
123 if (dialog.exec() == QDialog::Accepted) {
124 impl->createEventFromZones(dialog.eventName(), zones);
124 impl->createEventFromZones(dialog.eventName(), zones);
125 }
125 }
126 });
126 });
127 createEventAction->setEnableFunction(createEventEnableFuntion);
127 createEventAction->setEnableFunction(createEventEnableFuntion);
128
128
129 auto createEventInCatalogueAction = actionController.addSectionZoneAction(
129 auto createEventInCatalogueAction = actionController.addSectionZoneAction(
130 {QObject::tr("Catalogues")}, QObject::tr("New Event in Catalogue..."), [this](auto zones) {
130 {QObject::tr("Catalogues")}, QObject::tr("New Event in Catalogue..."), [this](auto zones) {
131 CreateEventDialog dialog(
131 CreateEventDialog dialog(
132 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
132 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
133 if (dialog.exec() == QDialog::Accepted) {
133 if (dialog.exec() == QDialog::Accepted) {
134 auto selectedCatalogue = dialog.selectedCatalogue();
134 auto selectedCatalogue = dialog.selectedCatalogue();
135 if (!selectedCatalogue) {
135 if (!selectedCatalogue) {
136 selectedCatalogue = std::make_shared<DBCatalogue>();
136 selectedCatalogue = std::make_shared<DBCatalogue>();
137 selectedCatalogue->setName(dialog.catalogueName());
137 selectedCatalogue->setName(dialog.catalogueName());
138 // sqpApp->catalogueController().addCatalogue(selectedCatalogue); TODO
138 sqpApp->catalogueController().addCatalogue(selectedCatalogue);
139 impl->m_CatalogueExplorer->sideBarWidget().addCatalogue(selectedCatalogue,
139 impl->m_CatalogueExplorer->sideBarWidget().addCatalogue(selectedCatalogue,
140 REPOSITORY_DEFAULT);
140 REPOSITORY_DEFAULT);
141 }
141 }
142
142
143 impl->createEventFromZones(dialog.eventName(), zones, selectedCatalogue);
143 impl->createEventFromZones(dialog.eventName(), zones, selectedCatalogue);
144 }
144 }
145 });
145 });
146 createEventInCatalogueAction->setEnableFunction(createEventEnableFuntion);
146 createEventInCatalogueAction->setEnableFunction(createEventEnableFuntion);
147 }
147 }
@@ -1,337 +1,414
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 #include <QMessageBox>
15
16
16 Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget")
17 Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget")
17
18
18
19
19 constexpr auto ALL_EVENT_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 1;
20 constexpr auto ALL_EVENT_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 1;
20 constexpr auto TRASH_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 2;
21 constexpr auto TRASH_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 2;
21 constexpr auto CATALOGUE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 3;
22 constexpr auto CATALOGUE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 3;
22 constexpr auto DATABASE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 4;
23 constexpr auto DATABASE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 4;
23
24
24
25
25 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
26 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
26
27
27 CatalogueTreeModel *m_TreeModel = nullptr;
28 CatalogueTreeModel *m_TreeModel = nullptr;
28
29
29 void configureTreeWidget(QTreeView *treeView);
30 void configureTreeWidget(QTreeView *treeView);
30 QModelIndex addDatabaseItem(const QString &name);
31 QModelIndex addDatabaseItem(const QString &name);
31 CatalogueAbstractTreeItem *getDatabaseItem(const QString &name);
32 CatalogueAbstractTreeItem *getDatabaseItem(const QString &name);
32 void addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
33 CatalogueAbstractTreeItem *addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
33 const QModelIndex &databaseIndex);
34 const QModelIndex &databaseIndex);
34
35
35 CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const;
36 CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const;
36 void setHasChanges(bool value, const QModelIndex &index, QTreeView *treeView);
37 void setHasChanges(bool value, const QModelIndex &index, CatalogueSideBarWidget *sideBarWidget);
37 bool hasChanges(const QModelIndex &index, QTreeView *treeView);
38 bool hasChanges(const QModelIndex &index, QTreeView *treeView);
38
39
39 int selectionType(QTreeView *treeView) const
40 int selectionType(QTreeView *treeView) const
40 {
41 {
41 auto selectedItems = treeView->selectionModel()->selectedRows();
42 auto selectedItems = treeView->selectionModel()->selectedRows();
42 if (selectedItems.isEmpty()) {
43 if (selectedItems.isEmpty()) {
43 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
44 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
44 }
45 }
45 else {
46 else {
46 auto firstIndex = selectedItems.first();
47 auto firstIndex = selectedItems.first();
47 auto firstItem = m_TreeModel->item(firstIndex);
48 auto firstItem = m_TreeModel->item(firstIndex);
48 if (!firstItem) {
49 if (!firstItem) {
49 Q_ASSERT(false);
50 Q_ASSERT(false);
50 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
51 return CatalogueAbstractTreeItem::DEFAULT_TYPE;
51 }
52 }
52 auto selectionType = firstItem->type();
53 auto selectionType = firstItem->type();
53
54
54 for (auto itemIndex : selectedItems) {
55 for (auto itemIndex : selectedItems) {
55 auto item = m_TreeModel->item(itemIndex);
56 auto item = m_TreeModel->item(itemIndex);
56 if (!item || item->type() != selectionType) {
57 if (!item || item->type() != selectionType) {
57 // Incoherent multi selection
58 // Incoherent multi selection
58 selectionType = CatalogueAbstractTreeItem::DEFAULT_TYPE;
59 selectionType = CatalogueAbstractTreeItem::DEFAULT_TYPE;
59 break;
60 break;
60 }
61 }
61 }
62 }
62
63
63 return selectionType;
64 return selectionType;
64 }
65 }
65 }
66 }
66
67
67 QVector<std::shared_ptr<DBCatalogue> > selectedCatalogues(QTreeView *treeView) const
68 QVector<std::shared_ptr<DBCatalogue> > selectedCatalogues(QTreeView *treeView) const
68 {
69 {
69 QVector<std::shared_ptr<DBCatalogue> > catalogues;
70 QVector<std::shared_ptr<DBCatalogue> > catalogues;
70 auto selectedItems = treeView->selectionModel()->selectedRows();
71 auto selectedItems = treeView->selectionModel()->selectedRows();
71 for (auto itemIndex : selectedItems) {
72 for (auto itemIndex : selectedItems) {
72 auto item = m_TreeModel->item(itemIndex);
73 auto item = m_TreeModel->item(itemIndex);
73 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
74 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
74 catalogues.append(static_cast<CatalogueTreeItem *>(item)->catalogue());
75 catalogues.append(static_cast<CatalogueTreeItem *>(item)->catalogue());
75 }
76 }
76 }
77 }
77
78
78 return catalogues;
79 return catalogues;
79 }
80 }
80
81
81 QStringList selectedRepositories(QTreeView *treeView) const
82 QStringList selectedRepositories(QTreeView *treeView) const
82 {
83 {
83 QStringList repositories;
84 QStringList repositories;
84 auto selectedItems = treeView->selectionModel()->selectedRows();
85 auto selectedItems = treeView->selectionModel()->selectedRows();
85 for (auto itemIndex : selectedItems) {
86 for (auto itemIndex : selectedItems) {
86 auto item = m_TreeModel->item(itemIndex);
87 auto item = m_TreeModel->item(itemIndex);
87 if (item && item->type() == DATABASE_ITEM_TYPE) {
88 if (item && item->type() == DATABASE_ITEM_TYPE) {
88 repositories.append(item->text());
89 repositories.append(item->text());
89 }
90 }
90 }
91 }
91
92
92 return repositories;
93 return repositories;
93 }
94 }
94 };
95 };
95
96
96 CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent)
97 CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent)
97 : QWidget(parent),
98 : QWidget(parent),
98 ui(new Ui::CatalogueSideBarWidget),
99 ui(new Ui::CatalogueSideBarWidget),
99 impl{spimpl::make_unique_impl<CatalogueSideBarWidgetPrivate>()}
100 impl{spimpl::make_unique_impl<CatalogueSideBarWidgetPrivate>()}
100 {
101 {
101 ui->setupUi(this);
102 ui->setupUi(this);
102
103
103 impl->m_TreeModel = new CatalogueTreeModel(this);
104 impl->m_TreeModel = new CatalogueTreeModel(this);
104 ui->treeView->setModel(impl->m_TreeModel);
105 ui->treeView->setModel(impl->m_TreeModel);
105
106
106 impl->configureTreeWidget(ui->treeView);
107 impl->configureTreeWidget(ui->treeView);
107
108
108 ui->treeView->header()->setStretchLastSection(false);
109 ui->treeView->header()->setStretchLastSection(false);
109 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
110 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
110 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
111 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
111
112
112 auto emitSelection = [this]() {
113 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueSideBarWidget::emitSelection);
113
114 connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this,
114 auto selectionType = impl->selectionType(ui->treeView);
115 &CatalogueSideBarWidget::emitSelection);
115
116
116 switch (selectionType) {
117
117 case CATALOGUE_ITEM_TYPE:
118 connect(ui->btnAdd, &QToolButton::clicked, [this]() {
118 emit this->catalogueSelected(impl->selectedCatalogues(ui->treeView));
119 auto catalogue = std::make_shared<DBCatalogue>();
119 break;
120 catalogue->setName(QString("Cat"));
120 case DATABASE_ITEM_TYPE:
121 sqpApp->catalogueController().addCatalogue(catalogue);
121 emit this->databaseSelected(impl->selectedRepositories(ui->treeView));
122 auto item = this->addCatalogue(catalogue, REPOSITORY_DEFAULT);
122 break;
123 this->setCatalogueChanges(catalogue, true);
123 case ALL_EVENT_ITEM_TYPE:
124 ui->treeView->edit(impl->m_TreeModel->indexOf(item));
124 emit this->allEventsSelected();
125
125 break;
126 });
126 case TRASH_ITEM_TYPE:
127
127 emit this->trashSelected();
128
128 break;
129 connect(impl->m_TreeModel, &CatalogueTreeModel::itemDropped, [this](auto index) {
129 default:
130 auto item = impl->m_TreeModel->item(index);
130 emit this->selectionCleared();
131 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
131 break;
132 auto catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
133 this->setCatalogueChanges(catalogue, true);
134 }
135 });
136 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
137 QVector<QPair<std::shared_ptr<DBCatalogue>, CatalogueAbstractTreeItem *> >
138 cataloguesToItems;
139 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
140
141 for (auto index : selectedIndexes) {
142 auto item = impl->m_TreeModel->item(index);
143 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
144 auto catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
145 cataloguesToItems << qMakePair(catalogue, item);
146 }
132 }
147 }
133 };
134
148
135 connect(ui->treeView, &QTreeView::clicked, emitSelection);
149 if (!cataloguesToItems.isEmpty()) {
136 connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, emitSelection);
150
137 connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [emitSelection, this](auto index) {
151 if (QMessageBox::warning(this, tr("Remove Catalogue(s)"),
152 tr("The selected catalogues(s) will be completly removed "
153 "from the repository!\nAre you sure you want to continue?"),
154 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
155 == QMessageBox::Yes) {
156
157 for (auto catalogueToItem : cataloguesToItems) {
158 sqpApp->catalogueController().removeCatalogue(catalogueToItem.first);
159 impl->m_TreeModel->removeChildItem(
160 catalogueToItem.second,
161 impl->m_TreeModel->indexOf(catalogueToItem.second->parent()));
162 }
163 }
164 }
165 });
166
167 connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [this](auto index) {
138 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
168 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
139 if (selectedIndexes.contains(index)) {
169 if (selectedIndexes.contains(index)) {
140 emitSelection();
170 this->emitSelection();
141 }
171 }
142
172 impl->setHasChanges(true, index, this);
143 auto item = impl->m_TreeModel->item(index);
144 impl->setHasChanges(true, index, ui->treeView);
145 });
173 });
146
174
147 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
175 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
148 connect(ui->treeView, &QTreeView::customContextMenuRequested, this,
176 connect(ui->treeView, &QTreeView::customContextMenuRequested, this,
149 &CatalogueSideBarWidget::onContextMenuRequested);
177 &CatalogueSideBarWidget::onContextMenuRequested);
150 }
178 }
151
179
152 CatalogueSideBarWidget::~CatalogueSideBarWidget()
180 CatalogueSideBarWidget::~CatalogueSideBarWidget()
153 {
181 {
154 delete ui;
182 delete ui;
155 }
183 }
156
184
157 void CatalogueSideBarWidget::addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
185 CatalogueAbstractTreeItem *
158 const QString &repository)
186 CatalogueSideBarWidget::addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
187 const QString &repository)
159 {
188 {
160 auto repositoryItem = impl->getDatabaseItem(repository);
189 auto repositoryItem = impl->getDatabaseItem(repository);
161 impl->addCatalogueItem(catalogue, impl->m_TreeModel->indexOf(repositoryItem));
190 return impl->addCatalogueItem(catalogue, impl->m_TreeModel->indexOf(repositoryItem));
162 }
191 }
163
192
164 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue,
193 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue,
165 bool hasChanges)
194 bool hasChanges)
166 {
195 {
167 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
196 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
168 auto index = impl->m_TreeModel->indexOf(catalogueItem);
197 auto index = impl->m_TreeModel->indexOf(catalogueItem);
169 impl->setHasChanges(hasChanges, index, ui->treeView);
198 impl->setHasChanges(hasChanges, index, this);
170 // catalogueItem->refresh();
199 // catalogueItem->refresh();
171 }
200 }
172 }
201 }
173
202
174 QVector<std::shared_ptr<DBCatalogue> >
203 QVector<std::shared_ptr<DBCatalogue> >
175 CatalogueSideBarWidget::getCatalogues(const QString &repository) const
204 CatalogueSideBarWidget::getCatalogues(const QString &repository) const
176 {
205 {
177 QVector<std::shared_ptr<DBCatalogue> > result;
206 QVector<std::shared_ptr<DBCatalogue> > result;
178 auto repositoryItem = impl->getDatabaseItem(repository);
207 auto repositoryItem = impl->getDatabaseItem(repository);
179 for (auto child : repositoryItem->children()) {
208 for (auto child : repositoryItem->children()) {
180 if (child->type() == CATALOGUE_ITEM_TYPE) {
209 if (child->type() == CATALOGUE_ITEM_TYPE) {
181 auto catalogueItem = static_cast<CatalogueTreeItem *>(child);
210 auto catalogueItem = static_cast<CatalogueTreeItem *>(child);
182 result << catalogueItem->catalogue();
211 result << catalogueItem->catalogue();
183 }
212 }
184 else {
213 else {
185 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogues: invalid structure";
214 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogues: invalid structure";
186 }
215 }
187 }
216 }
188
217
189 return result;
218 return result;
190 }
219 }
191
220
221 void CatalogueSideBarWidget::emitSelection()
222 {
223 auto selectionType = impl->selectionType(ui->treeView);
224
225 switch (selectionType) {
226 case CATALOGUE_ITEM_TYPE:
227 emit this->catalogueSelected(impl->selectedCatalogues(ui->treeView));
228 break;
229 case DATABASE_ITEM_TYPE:
230 emit this->databaseSelected(impl->selectedRepositories(ui->treeView));
231 break;
232 case ALL_EVENT_ITEM_TYPE:
233 emit this->allEventsSelected();
234 break;
235 case TRASH_ITEM_TYPE:
236 emit this->trashSelected();
237 break;
238 default:
239 emit this->selectionCleared();
240 break;
241 }
242 }
243
192 void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos)
244 void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos)
193 {
245 {
194 QMenu menu{this};
246 QMenu menu{this};
195
247
196 auto currentIndex = ui->treeView->currentIndex();
248 auto currentIndex = ui->treeView->currentIndex();
197 auto currentItem = impl->m_TreeModel->item(currentIndex);
249 auto currentItem = impl->m_TreeModel->item(currentIndex);
198 if (!currentItem) {
250 if (!currentItem) {
199 return;
251 return;
200 }
252 }
201
253
202 switch (currentItem->type()) {
254 switch (currentItem->type()) {
203 case CATALOGUE_ITEM_TYPE:
255 case CATALOGUE_ITEM_TYPE:
204 menu.addAction("Rename", [this, currentIndex]() { ui->treeView->edit(currentIndex); });
256 menu.addAction("Rename", [this, currentIndex]() { ui->treeView->edit(currentIndex); });
205 break;
257 break;
206 case DATABASE_ITEM_TYPE:
258 case DATABASE_ITEM_TYPE:
207 break;
259 break;
208 case ALL_EVENT_ITEM_TYPE:
260 case ALL_EVENT_ITEM_TYPE:
209 break;
261 break;
210 case TRASH_ITEM_TYPE:
262 case TRASH_ITEM_TYPE:
211 menu.addAction("Empty Trash", []() {
263 menu.addAction("Empty Trash", []() {
212 // TODO
264 // TODO
213 });
265 });
214 break;
266 break;
215 default:
267 default:
216 break;
268 break;
217 }
269 }
218
270
219 if (!menu.isEmpty()) {
271 if (!menu.isEmpty()) {
220 menu.exec(ui->treeView->mapToGlobal(pos));
272 menu.exec(ui->treeView->mapToGlobal(pos));
221 }
273 }
222 }
274 }
223
275
224 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(QTreeView *treeView)
276 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(QTreeView *treeView)
225 {
277 {
226 auto allEventsItem = new CatalogueTextTreeItem{QIcon{":/icones/allEvents.png"}, "All Events",
278 auto allEventsItem = new CatalogueTextTreeItem{QIcon{":/icones/allEvents.png"}, "All Events",
227 ALL_EVENT_ITEM_TYPE};
279 ALL_EVENT_ITEM_TYPE};
228 auto allEventIndex = m_TreeModel->addTopLevelItem(allEventsItem);
280 auto allEventIndex = m_TreeModel->addTopLevelItem(allEventsItem);
229 treeView->setCurrentIndex(allEventIndex);
281 treeView->setCurrentIndex(allEventIndex);
230
282
231 auto trashItem
283 auto trashItem
232 = new CatalogueTextTreeItem{QIcon{":/icones/trash.png"}, "Trash", TRASH_ITEM_TYPE};
284 = new CatalogueTextTreeItem{QIcon{":/icones/trash.png"}, "Trash", TRASH_ITEM_TYPE};
233 m_TreeModel->addTopLevelItem(trashItem);
285 m_TreeModel->addTopLevelItem(trashItem);
234
286
235 auto separator = new QFrame{treeView};
287 auto separator = new QFrame{treeView};
236 separator->setFrameShape(QFrame::HLine);
288 separator->setFrameShape(QFrame::HLine);
237 auto separatorItem
289 auto separatorItem
238 = new CatalogueTextTreeItem{QIcon{}, QString{}, CatalogueAbstractTreeItem::DEFAULT_TYPE};
290 = new CatalogueTextTreeItem{QIcon{}, QString{}, CatalogueAbstractTreeItem::DEFAULT_TYPE};
239 separatorItem->setEnabled(false);
291 separatorItem->setEnabled(false);
240 auto separatorIndex = m_TreeModel->addTopLevelItem(separatorItem);
292 auto separatorIndex = m_TreeModel->addTopLevelItem(separatorItem);
241 treeView->setIndexWidget(separatorIndex, separator);
293 treeView->setIndexWidget(separatorIndex, separator);
242
294
243 auto repositories = sqpApp->catalogueController().getRepositories();
295 auto repositories = sqpApp->catalogueController().getRepositories();
244 for (auto dbname : repositories) {
296 for (auto dbname : repositories) {
245 auto dbIndex = addDatabaseItem(dbname);
297 auto dbIndex = addDatabaseItem(dbname);
246 auto catalogues = sqpApp->catalogueController().retrieveCatalogues(dbname);
298 auto catalogues = sqpApp->catalogueController().retrieveCatalogues(dbname);
247 for (auto catalogue : catalogues) {
299 for (auto catalogue : catalogues) {
248 addCatalogueItem(catalogue, dbIndex);
300 addCatalogueItem(catalogue, dbIndex);
249 }
301 }
250 }
302 }
251
303
252 treeView->expandAll();
304 treeView->expandAll();
253 }
305 }
254
306
255 QModelIndex
307 QModelIndex
256 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name)
308 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name)
257 {
309 {
258 auto databaseItem
310 auto databaseItem
259 = new CatalogueTextTreeItem{QIcon{":/icones/database.png"}, {name}, DATABASE_ITEM_TYPE};
311 = new CatalogueTextTreeItem{QIcon{":/icones/database.png"}, {name}, DATABASE_ITEM_TYPE};
260 auto databaseIndex = m_TreeModel->addTopLevelItem(databaseItem);
312 auto databaseIndex = m_TreeModel->addTopLevelItem(databaseItem);
261
313
262 return databaseIndex;
314 return databaseIndex;
263 }
315 }
264
316
265 CatalogueAbstractTreeItem *
317 CatalogueAbstractTreeItem *
266 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name)
318 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name)
267 {
319 {
268 for (auto item : m_TreeModel->topLevelItems()) {
320 for (auto item : m_TreeModel->topLevelItems()) {
269 if (item->type() == DATABASE_ITEM_TYPE && item->text() == name) {
321 if (item->type() == DATABASE_ITEM_TYPE && item->text() == name) {
270 return item;
322 return item;
271 }
323 }
272 }
324 }
273
325
274 return nullptr;
326 return nullptr;
275 }
327 }
276
328
277 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem(
329 CatalogueAbstractTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem(
278 const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex)
330 const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex)
279 {
331 {
280 auto catalogueItem
332 auto catalogueItem
281 = new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE};
333 = new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE};
282 m_TreeModel->addChildItem(catalogueItem, databaseIndex);
334 m_TreeModel->addChildItem(catalogueItem, databaseIndex);
335
336 return catalogueItem;
283 }
337 }
284
338
285 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem(
339 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem(
286 const std::shared_ptr<DBCatalogue> &catalogue) const
340 const std::shared_ptr<DBCatalogue> &catalogue) const
287 {
341 {
288 for (auto item : m_TreeModel->topLevelItems()) {
342 for (auto item : m_TreeModel->topLevelItems()) {
289 if (item->type() == DATABASE_ITEM_TYPE) {
343 if (item->type() == DATABASE_ITEM_TYPE) {
290 for (auto childItem : item->children()) {
344 for (auto childItem : item->children()) {
291 if (childItem->type() == CATALOGUE_ITEM_TYPE) {
345 if (childItem->type() == CATALOGUE_ITEM_TYPE) {
292 auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem);
346 auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem);
293 if (catalogueItem->catalogue() == catalogue) {
347 if (catalogueItem->catalogue() == catalogue) {
294 return catalogueItem;
348 return catalogueItem;
295 }
349 }
296 }
350 }
297 else {
351 else {
298 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogueItem: Invalid tree "
352 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogueItem: Invalid tree "
299 "structure. A database item should "
353 "structure. A database item should "
300 "only contain catalogues.";
354 "only contain catalogues.";
301 Q_ASSERT(false);
355 Q_ASSERT(false);
302 }
356 }
303 }
357 }
304 }
358 }
305 }
359 }
306
360
307 return nullptr;
361 return nullptr;
308 }
362 }
309
363
310 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(bool value,
364 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(
311 const QModelIndex &index,
365 bool value, const QModelIndex &index, CatalogueSideBarWidget *sideBarWidget)
312 QTreeView *treeView)
313 {
366 {
367 std::shared_ptr<DBCatalogue> catalogue = nullptr;
368 auto item = m_TreeModel->item(index);
369 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
370 catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
371 }
372
314 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
373 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
315 if (value) {
374 if (value) {
316 if (!hasChanges(validationIndex, treeView)) {
375 if (!hasChanges(validationIndex, sideBarWidget->ui->treeView)) {
317 auto widget = CatalogueExplorerHelper::buildValidationWidget(
376 auto widget = CatalogueExplorerHelper::buildValidationWidget(
318 treeView, [this, validationIndex,
377 sideBarWidget->ui->treeView,
319 treeView]() { setHasChanges(false, validationIndex, treeView); },
378 [this, validationIndex, sideBarWidget, catalogue]() {
320 [this, validationIndex, treeView]() {
379 if (catalogue) {
321 setHasChanges(false, validationIndex, treeView);
380 sqpApp->catalogueController().saveCatalogue(catalogue);
381 }
382 setHasChanges(false, validationIndex, sideBarWidget);
383 },
384 [this, validationIndex, sideBarWidget, catalogue, item]() {
385 if (catalogue) {
386 bool removed;
387 sqpApp->catalogueController().discardCatalogue(catalogue, removed);
388
389 if (removed) {
390 m_TreeModel->removeChildItem(item,
391 m_TreeModel->indexOf(item->parent()));
392 }
393 else {
394 m_TreeModel->refresh(m_TreeModel->indexOf(item));
395 setHasChanges(false, validationIndex, sideBarWidget);
396 }
397 sideBarWidget->emitSelection();
398 }
322 });
399 });
323 treeView->setIndexWidget(validationIndex, widget);
400 sideBarWidget->ui->treeView->setIndexWidget(validationIndex, widget);
324 }
401 }
325 }
402 }
326 else {
403 else {
327 // Note: the widget is destroyed
404 // Note: the widget is destroyed
328 treeView->setIndexWidget(validationIndex, nullptr);
405 sideBarWidget->ui->treeView->setIndexWidget(validationIndex, nullptr);
329 }
406 }
330 }
407 }
331
408
332 bool CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::hasChanges(const QModelIndex &index,
409 bool CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::hasChanges(const QModelIndex &index,
333 QTreeView *treeView)
410 QTreeView *treeView)
334 {
411 {
335 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
412 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
336 return treeView->indexWidget(validationIndex) != nullptr;
413 return treeView->indexWidget(validationIndex) != nullptr;
337 }
414 }
@@ -1,81 +1,87
1 #include "Catalogue/CatalogueTreeItems/CatalogueAbstractTreeItem.h"
1 #include "Catalogue/CatalogueTreeItems/CatalogueAbstractTreeItem.h"
2
2
3 struct CatalogueAbstractTreeItem::CatalogueAbstractTreeItemPrivate {
3 struct CatalogueAbstractTreeItem::CatalogueAbstractTreeItemPrivate {
4 int m_Type;
4 int m_Type;
5 QVector<CatalogueAbstractTreeItem *> m_Children;
5 QVector<CatalogueAbstractTreeItem *> m_Children;
6 CatalogueAbstractTreeItem *m_Parent = nullptr;
6 CatalogueAbstractTreeItem *m_Parent = nullptr;
7
7
8 CatalogueAbstractTreeItemPrivate(int type) : m_Type(type) {}
8 CatalogueAbstractTreeItemPrivate(int type) : m_Type(type) {}
9 };
9 };
10
10
11 CatalogueAbstractTreeItem::CatalogueAbstractTreeItem(int type)
11 CatalogueAbstractTreeItem::CatalogueAbstractTreeItem(int type)
12 : impl{spimpl::make_unique_impl<CatalogueAbstractTreeItemPrivate>(type)}
12 : impl{spimpl::make_unique_impl<CatalogueAbstractTreeItemPrivate>(type)}
13 {
13 {
14 }
14 }
15
15
16 CatalogueAbstractTreeItem::~CatalogueAbstractTreeItem()
16 CatalogueAbstractTreeItem::~CatalogueAbstractTreeItem()
17 {
17 {
18 qDeleteAll(impl->m_Children);
18 qDeleteAll(impl->m_Children);
19 }
19 }
20
20
21 void CatalogueAbstractTreeItem::addChild(CatalogueAbstractTreeItem *child)
21 void CatalogueAbstractTreeItem::addChild(CatalogueAbstractTreeItem *child)
22 {
22 {
23 impl->m_Children << child;
23 impl->m_Children << child;
24 child->impl->m_Parent = this;
24 child->impl->m_Parent = this;
25 }
25 }
26
26
27 void CatalogueAbstractTreeItem::removeChild(CatalogueAbstractTreeItem *child)
28 {
29 impl->m_Children.removeAll(child);
30 delete child;
31 }
32
27 QVector<CatalogueAbstractTreeItem *> CatalogueAbstractTreeItem::children() const
33 QVector<CatalogueAbstractTreeItem *> CatalogueAbstractTreeItem::children() const
28 {
34 {
29 return impl->m_Children;
35 return impl->m_Children;
30 }
36 }
31
37
32 CatalogueAbstractTreeItem *CatalogueAbstractTreeItem::parent() const
38 CatalogueAbstractTreeItem *CatalogueAbstractTreeItem::parent() const
33 {
39 {
34 return impl->m_Parent;
40 return impl->m_Parent;
35 }
41 }
36
42
37 int CatalogueAbstractTreeItem::type() const
43 int CatalogueAbstractTreeItem::type() const
38 {
44 {
39 return impl->m_Type;
45 return impl->m_Type;
40 }
46 }
41
47
42 QString CatalogueAbstractTreeItem::text(int column) const
48 QString CatalogueAbstractTreeItem::text(int column) const
43 {
49 {
44 return data(0, Qt::DisplayRole).toString();
50 return data(0, Qt::DisplayRole).toString();
45 }
51 }
46
52
47 QVariant CatalogueAbstractTreeItem::data(int column, int role) const
53 QVariant CatalogueAbstractTreeItem::data(int column, int role) const
48 {
54 {
49 Q_UNUSED(column);
55 Q_UNUSED(column);
50 Q_UNUSED(role);
56 Q_UNUSED(role);
51 return QVariant();
57 return QVariant();
52 }
58 }
53
59
54 Qt::ItemFlags CatalogueAbstractTreeItem::flags(int column) const
60 Qt::ItemFlags CatalogueAbstractTreeItem::flags(int column) const
55 {
61 {
56 Q_UNUSED(column);
62 Q_UNUSED(column);
57 return Qt::NoItemFlags;
63 return Qt::NoItemFlags;
58 }
64 }
59
65
60 bool CatalogueAbstractTreeItem::setData(int column, int role, const QVariant &value)
66 bool CatalogueAbstractTreeItem::setData(int column, int role, const QVariant &value)
61 {
67 {
62 Q_UNUSED(column);
68 Q_UNUSED(column);
63 Q_UNUSED(role);
69 Q_UNUSED(role);
64 Q_UNUSED(value);
70 Q_UNUSED(value);
65
71
66 return false;
72 return false;
67 }
73 }
68
74
69 bool CatalogueAbstractTreeItem::canDropMimeData(const QMimeData *data, Qt::DropAction action)
75 bool CatalogueAbstractTreeItem::canDropMimeData(const QMimeData *data, Qt::DropAction action)
70 {
76 {
71 Q_UNUSED(data);
77 Q_UNUSED(data);
72 Q_UNUSED(action);
78 Q_UNUSED(action);
73 return false;
79 return false;
74 }
80 }
75
81
76 bool CatalogueAbstractTreeItem::dropMimeData(const QMimeData *data, Qt::DropAction action)
82 bool CatalogueAbstractTreeItem::dropMimeData(const QMimeData *data, Qt::DropAction action)
77 {
83 {
78 Q_UNUSED(data);
84 Q_UNUSED(data);
79 Q_UNUSED(action);
85 Q_UNUSED(action);
80 return false;
86 return false;
81 }
87 }
@@ -1,95 +1,105
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 return data->hasFormat(MIME_TYPE_EVENT_LIST);
79 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
80 auto canDrop = data->hasFormat(MIME_TYPE_EVENT_LIST);
81
82 for (auto event : events) {
83 canDrop &= (event->getRepository() == impl->m_Catalogue->getRepository());
84 }
85 return canDrop;
80 }
86 }
81
87
82 bool CatalogueTreeItem::dropMimeData(const QMimeData *data, Qt::DropAction action)
88 bool CatalogueTreeItem::dropMimeData(const QMimeData *data, Qt::DropAction action)
83 {
89 {
84 Q_ASSERT(canDropMimeData(data, action));
90 Q_ASSERT(canDropMimeData(data, action));
85
86 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
87 // impl->m_Catalogue->addEvents(events); TODO: move events in the new catalogue
88 // Warning: Check that the events aren't already in the catalogue
91 // Warning: Check that the events aren't already in the catalogue
89 // Also check for the repository !!!
92 // Also check for the repository !!!
93
94 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
95
96 for (auto event : events) {
97 impl->m_Catalogue->addEvent(event->getUniqId());
98 sqpApp->catalogueController().updateCatalogue(impl->m_Catalogue);
99 }
90 }
100 }
91
101
92 std::shared_ptr<DBCatalogue> CatalogueTreeItem::catalogue() const
102 std::shared_ptr<DBCatalogue> CatalogueTreeItem::catalogue() const
93 {
103 {
94 return impl->m_Catalogue;
104 return impl->m_Catalogue;
95 }
105 }
@@ -1,201 +1,218
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,
50 const QModelIndex &parentIndex)
51 {
52 auto parentItem = item(parentIndex);
53 int i = parentItem->children().indexOf(child);
54 beginRemoveRows(parentIndex, i, i);
55 parentItem->removeChild(child);
56 endRemoveRows();
57
58 emit dataChanged(parentIndex, parentIndex);
59 }
60
61 void CatalogueTreeModel::refresh(const QModelIndex &index)
62 {
63 emit dataChanged(index, index);
64 }
65
49 CatalogueAbstractTreeItem *CatalogueTreeModel::item(const QModelIndex &index) const
66 CatalogueAbstractTreeItem *CatalogueTreeModel::item(const QModelIndex &index) const
50 {
67 {
51 return static_cast<CatalogueAbstractTreeItem *>(index.internalPointer());
68 return static_cast<CatalogueAbstractTreeItem *>(index.internalPointer());
52 }
69 }
53
70
54 QModelIndex CatalogueTreeModel::indexOf(CatalogueAbstractTreeItem *item, int column) const
71 QModelIndex CatalogueTreeModel::indexOf(CatalogueAbstractTreeItem *item, int column) const
55 {
72 {
56 auto parentItem = item->parent();
73 auto parentItem = item->parent();
57 if (!parentItem) {
74 if (!parentItem) {
58 return QModelIndex();
75 return QModelIndex();
59 }
76 }
60
77
61 auto row = parentItem->children().indexOf(item);
78 auto row = parentItem->children().indexOf(item);
62 return createIndex(row, column, item);
79 return createIndex(row, column, item);
63 }
80 }
64
81
65 QModelIndex CatalogueTreeModel::index(int row, int column, const QModelIndex &parent) const
82 QModelIndex CatalogueTreeModel::index(int row, int column, const QModelIndex &parent) const
66 {
83 {
67 if (column > 0) {
84 if (column > 0) {
68 int a = 0;
85 int a = 0;
69 }
86 }
70
87
71 if (!hasIndex(row, column, parent)) {
88 if (!hasIndex(row, column, parent)) {
72 return QModelIndex();
89 return QModelIndex();
73 }
90 }
74
91
75 CatalogueAbstractTreeItem *parentItem = nullptr;
92 CatalogueAbstractTreeItem *parentItem = nullptr;
76
93
77 if (!parent.isValid()) {
94 if (!parent.isValid()) {
78 parentItem = impl->m_RootItem.get();
95 parentItem = impl->m_RootItem.get();
79 }
96 }
80 else {
97 else {
81 parentItem = item(parent);
98 parentItem = item(parent);
82 }
99 }
83
100
84 auto childItem = parentItem->children().value(row);
101 auto childItem = parentItem->children().value(row);
85 if (childItem) {
102 if (childItem) {
86 return createIndex(row, column, childItem);
103 return createIndex(row, column, childItem);
87 }
104 }
88
105
89 return QModelIndex();
106 return QModelIndex();
90 }
107 }
91
108
92
109
93 QModelIndex CatalogueTreeModel::parent(const QModelIndex &index) const
110 QModelIndex CatalogueTreeModel::parent(const QModelIndex &index) const
94 {
111 {
95 if (!index.isValid()) {
112 if (!index.isValid()) {
96 return QModelIndex();
113 return QModelIndex();
97 }
114 }
98
115
99 auto childItem = item(index);
116 auto childItem = item(index);
100 auto parentItem = childItem->parent();
117 auto parentItem = childItem->parent();
101
118
102 if (parentItem == nullptr || parentItem->parent() == nullptr) {
119 if (parentItem == nullptr || parentItem->parent() == nullptr) {
103 return QModelIndex();
120 return QModelIndex();
104 }
121 }
105
122
106 auto row = parentItem->parent()->children().indexOf(parentItem);
123 auto row = parentItem->parent()->children().indexOf(parentItem);
107 return createIndex(row, 0, parentItem);
124 return createIndex(row, 0, parentItem);
108 }
125 }
109
126
110 int CatalogueTreeModel::rowCount(const QModelIndex &parent) const
127 int CatalogueTreeModel::rowCount(const QModelIndex &parent) const
111 {
128 {
112 CatalogueAbstractTreeItem *parentItem = nullptr;
129 CatalogueAbstractTreeItem *parentItem = nullptr;
113
130
114 if (!parent.isValid()) {
131 if (!parent.isValid()) {
115 parentItem = impl->m_RootItem.get();
132 parentItem = impl->m_RootItem.get();
116 }
133 }
117 else {
134 else {
118 parentItem = item(parent);
135 parentItem = item(parent);
119 }
136 }
120
137
121 return parentItem->children().count();
138 return parentItem->children().count();
122 }
139 }
123
140
124 int CatalogueTreeModel::columnCount(const QModelIndex &parent) const
141 int CatalogueTreeModel::columnCount(const QModelIndex &parent) const
125 {
142 {
126 return (int)Column::Count;
143 return (int)Column::Count;
127 }
144 }
128
145
129 Qt::ItemFlags CatalogueTreeModel::flags(const QModelIndex &index) const
146 Qt::ItemFlags CatalogueTreeModel::flags(const QModelIndex &index) const
130 {
147 {
131 auto treeItem = item(index);
148 auto treeItem = item(index);
132 if (treeItem) {
149 if (treeItem) {
133 return treeItem->flags(index.column());
150 return treeItem->flags(index.column());
134 }
151 }
135
152
136 return Qt::NoItemFlags;
153 return Qt::NoItemFlags;
137 }
154 }
138
155
139 QVariant CatalogueTreeModel::data(const QModelIndex &index, int role) const
156 QVariant CatalogueTreeModel::data(const QModelIndex &index, int role) const
140 {
157 {
141 auto treeItem = item(index);
158 auto treeItem = item(index);
142 if (treeItem) {
159 if (treeItem) {
143 return treeItem->data(index.column(), role);
160 return treeItem->data(index.column(), role);
144 }
161 }
145
162
146 return QModelIndex();
163 return QModelIndex();
147 }
164 }
148
165
149 bool CatalogueTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
166 bool CatalogueTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
150 {
167 {
151 auto treeItem = item(index);
168 auto treeItem = item(index);
152 if (treeItem) {
169 if (treeItem) {
153 auto result = treeItem->setData(index.column(), role, value);
170 auto result = treeItem->setData(index.column(), role, value);
154
171
155 if (result && index.column() == (int)Column::Name) {
172 if (result && index.column() == (int)Column::Name) {
156 emit itemRenamed(index);
173 emit itemRenamed(index);
157 }
174 }
158
175
159 return result;
176 return result;
160 }
177 }
161
178
162 return false;
179 return false;
163 }
180 }
164 bool CatalogueTreeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
181 bool CatalogueTreeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
165 int column, const QModelIndex &parent) const
182 int column, const QModelIndex &parent) const
166 {
183 {
167 auto draggedIndex = parent;
184 auto draggedIndex = parent;
168 auto draggedItem = item(draggedIndex);
185 auto draggedItem = item(draggedIndex);
169 if (draggedItem) {
186 if (draggedItem) {
170 return draggedItem->canDropMimeData(data, action);
187 return draggedItem->canDropMimeData(data, action);
171 }
188 }
172
189
173 return false;
190 return false;
174 }
191 }
175
192
176 bool CatalogueTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row,
193 bool CatalogueTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row,
177 int column, const QModelIndex &parent)
194 int column, const QModelIndex &parent)
178 {
195 {
179 bool result = false;
196 bool result = false;
180
197
181 auto draggedIndex = parent;
198 auto draggedIndex = parent;
182 auto draggedItem = item(draggedIndex);
199 auto draggedItem = item(draggedIndex);
183 if (draggedItem) {
200 if (draggedItem) {
184 result = draggedItem->dropMimeData(data, action);
201 result = draggedItem->dropMimeData(data, action);
185 if (result) {
202 if (result) {
186 emit itemDropped(draggedIndex);
203 emit itemDropped(draggedIndex);
187 }
204 }
188 }
205 }
189
206
190 return result;
207 return result;
191 }
208 }
192
209
193 Qt::DropActions CatalogueTreeModel::supportedDropActions() const
210 Qt::DropActions CatalogueTreeModel::supportedDropActions() const
194 {
211 {
195 return Qt::CopyAction | Qt::MoveAction;
212 return Qt::CopyAction | Qt::MoveAction;
196 }
213 }
197
214
198 QStringList CatalogueTreeModel::mimeTypes() const
215 QStringList CatalogueTreeModel::mimeTypes() const
199 {
216 {
200 return {MIME_TYPE_EVENT_LIST};
217 return {MIME_TYPE_EVENT_LIST};
201 }
218 }
@@ -1,1055 +1,1054
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
10 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
13
13
14 #include <Actions/ActionsGuiController.h>
14 #include <Actions/ActionsGuiController.h>
15 #include <Common/MimeTypesDef.h>
15 #include <Common/MimeTypesDef.h>
16 #include <Data/ArrayData.h>
16 #include <Data/ArrayData.h>
17 #include <Data/IDataSeries.h>
17 #include <Data/IDataSeries.h>
18 #include <Data/SpectrogramSeries.h>
18 #include <Data/SpectrogramSeries.h>
19 #include <DragAndDrop/DragDropGuiController.h>
19 #include <DragAndDrop/DragDropGuiController.h>
20 #include <Settings/SqpSettingsDefs.h>
20 #include <Settings/SqpSettingsDefs.h>
21 #include <SqpApplication.h>
21 #include <SqpApplication.h>
22 #include <Time/TimeController.h>
22 #include <Time/TimeController.h>
23 #include <Variable/Variable.h>
23 #include <Variable/Variable.h>
24 #include <Variable/VariableController.h>
24 #include <Variable/VariableController.h>
25
25
26 #include <unordered_map>
26 #include <unordered_map>
27
27
28 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
28 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
29
29
30 namespace {
30 namespace {
31
31
32 /// Key pressed to enable drag&drop in all modes
32 /// Key pressed to enable drag&drop in all modes
33 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
33 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
34
34
35 /// Key pressed to enable zoom on horizontal axis
35 /// Key pressed to enable zoom on horizontal axis
36 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
36 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
37
37
38 /// Key pressed to enable zoom on vertical axis
38 /// Key pressed to enable zoom on vertical axis
39 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
39 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
40
40
41 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
41 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
42 const auto PAN_SPEED = 5;
42 const auto PAN_SPEED = 5;
43
43
44 /// Key pressed to enable a calibration pan
44 /// Key pressed to enable a calibration pan
45 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
45 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
46
46
47 /// Key pressed to enable multi selection of selection zones
47 /// Key pressed to enable multi selection of selection zones
48 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
48 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
49
49
50 /// Minimum size for the zoom box, in percentage of the axis range
50 /// Minimum size for the zoom box, in percentage of the axis range
51 const auto ZOOM_BOX_MIN_SIZE = 0.8;
51 const auto ZOOM_BOX_MIN_SIZE = 0.8;
52
52
53 /// Format of the dates appearing in the label of a cursor
53 /// Format of the dates appearing in the label of a cursor
54 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
54 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
55
55
56 } // namespace
56 } // namespace
57
57
58 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
58 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
59
59
60 explicit VisualizationGraphWidgetPrivate(const QString &name)
60 explicit VisualizationGraphWidgetPrivate(const QString &name)
61 : m_Name{name},
61 : m_Name{name},
62 m_Flags{GraphFlag::EnableAll},
62 m_Flags{GraphFlag::EnableAll},
63 m_IsCalibration{false},
63 m_IsCalibration{false},
64 m_RenderingDelegate{nullptr}
64 m_RenderingDelegate{nullptr}
65 {
65 {
66 }
66 }
67
67
68 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
68 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
69 const SqpRange &range)
69 const SqpRange &range)
70 {
70 {
71 VisualizationGraphHelper::updateData(plottables, variable, range);
71 VisualizationGraphHelper::updateData(plottables, variable, range);
72
72
73 // Prevents that data has changed to update rendering
73 // Prevents that data has changed to update rendering
74 m_RenderingDelegate->onPlotUpdated();
74 m_RenderingDelegate->onPlotUpdated();
75 }
75 }
76
76
77 QString m_Name;
77 QString m_Name;
78 // 1 variable -> n qcpplot
78 // 1 variable -> n qcpplot
79 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
79 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
80 GraphFlags m_Flags;
80 GraphFlags m_Flags;
81 bool m_IsCalibration;
81 bool m_IsCalibration;
82 /// Delegate used to attach rendering features to the plot
82 /// Delegate used to attach rendering features to the plot
83 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
83 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
84
84
85 QCPItemRect *m_DrawingZoomRect = nullptr;
85 QCPItemRect *m_DrawingZoomRect = nullptr;
86 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
86 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
87
87
88 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
90
90
91 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
91 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
92 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
92 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
93 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
93 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
94
94
95 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
95 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
96
96
97 bool m_VariableAutoRangeOnInit = true;
97 bool m_VariableAutoRangeOnInit = true;
98
98
99 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
99 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
100 {
100 {
101 removeDrawingRect(plot);
101 removeDrawingRect(plot);
102
102
103 auto axisPos = posToAxisPos(pos, plot);
103 auto axisPos = posToAxisPos(pos, plot);
104
104
105 m_DrawingZoomRect = new QCPItemRect{&plot};
105 m_DrawingZoomRect = new QCPItemRect{&plot};
106 QPen p;
106 QPen p;
107 p.setWidth(2);
107 p.setWidth(2);
108 m_DrawingZoomRect->setPen(p);
108 m_DrawingZoomRect->setPen(p);
109
109
110 m_DrawingZoomRect->topLeft->setCoords(axisPos);
110 m_DrawingZoomRect->topLeft->setCoords(axisPos);
111 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
111 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
112 }
112 }
113
113
114 void removeDrawingRect(QCustomPlot &plot)
114 void removeDrawingRect(QCustomPlot &plot)
115 {
115 {
116 if (m_DrawingZoomRect) {
116 if (m_DrawingZoomRect) {
117 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
117 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
118 m_DrawingZoomRect = nullptr;
118 m_DrawingZoomRect = nullptr;
119 plot.replot(QCustomPlot::rpQueuedReplot);
119 plot.replot(QCustomPlot::rpQueuedReplot);
120 }
120 }
121 }
121 }
122
122
123 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
123 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
124 {
124 {
125 endDrawingZone(graph);
125 endDrawingZone(graph);
126
126
127 auto axisPos = posToAxisPos(pos, graph->plot());
127 auto axisPos = posToAxisPos(pos, graph->plot());
128
128
129 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
129 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
130 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
130 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
131 m_DrawingZone->setEditionEnabled(false);
131 m_DrawingZone->setEditionEnabled(false);
132 }
132 }
133
133
134 void endDrawingZone(VisualizationGraphWidget *graph)
134 void endDrawingZone(VisualizationGraphWidget *graph)
135 {
135 {
136 if (m_DrawingZone) {
136 if (m_DrawingZone) {
137 auto drawingZoneRange = m_DrawingZone->range();
137 auto drawingZoneRange = m_DrawingZone->range();
138 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
138 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
139 m_DrawingZone->setEditionEnabled(true);
139 m_DrawingZone->setEditionEnabled(true);
140 addSelectionZone(m_DrawingZone);
140 addSelectionZone(m_DrawingZone);
141 }
141 }
142 else {
142 else {
143 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
143 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
144 }
144 }
145
145
146 graph->plot().replot(QCustomPlot::rpQueuedReplot);
146 graph->plot().replot(QCustomPlot::rpQueuedReplot);
147 m_DrawingZone = nullptr;
147 m_DrawingZone = nullptr;
148 }
148 }
149 }
149 }
150
150
151 void setSelectionZonesEditionEnabled(bool value)
151 void setSelectionZonesEditionEnabled(bool value)
152 {
152 {
153 for (auto s : m_SelectionZones) {
153 for (auto s : m_SelectionZones) {
154 s->setEditionEnabled(value);
154 s->setEditionEnabled(value);
155 }
155 }
156 }
156 }
157
157
158 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
158 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
159
159
160 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
160 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
161 const QCustomPlot &plot) const
161 const QCustomPlot &plot) const
162 {
162 {
163 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
163 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
164 auto minDistanceToZone = -1;
164 auto minDistanceToZone = -1;
165 for (auto zone : m_SelectionZones) {
165 for (auto zone : m_SelectionZones) {
166 auto distanceToZone = zone->selectTest(pos, false);
166 auto distanceToZone = zone->selectTest(pos, false);
167 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
167 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
168 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
168 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
169 selectionZoneItemUnderCursor = zone;
169 selectionZoneItemUnderCursor = zone;
170 }
170 }
171 }
171 }
172
172
173 return selectionZoneItemUnderCursor;
173 return selectionZoneItemUnderCursor;
174 }
174 }
175
175
176 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
176 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
177 const QCustomPlot &plot) const
177 const QCustomPlot &plot) const
178 {
178 {
179 QVector<VisualizationSelectionZoneItem *> zones;
179 QVector<VisualizationSelectionZoneItem *> zones;
180 for (auto zone : m_SelectionZones) {
180 for (auto zone : m_SelectionZones) {
181 auto distanceToZone = zone->selectTest(pos, false);
181 auto distanceToZone = zone->selectTest(pos, false);
182 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
182 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
183 zones << zone;
183 zones << zone;
184 }
184 }
185 }
185 }
186
186
187 return zones;
187 return zones;
188 }
188 }
189
189
190 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
190 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
191 {
191 {
192 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
192 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
193 zone->moveToTop();
193 zone->moveToTop();
194 m_SelectionZones.removeAll(zone);
194 m_SelectionZones.removeAll(zone);
195 m_SelectionZones.append(zone);
195 m_SelectionZones.append(zone);
196 }
196 }
197 }
197 }
198
198
199 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
199 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
200 {
200 {
201 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
201 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
202 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
202 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
203 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
203 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
204 }
204 }
205
205
206 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
206 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
207 {
207 {
208 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
208 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
209 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
209 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
210 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
210 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
211 }
211 }
212 };
212 };
213
213
214 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
214 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
215 : VisualizationDragWidget{parent},
215 : VisualizationDragWidget{parent},
216 ui{new Ui::VisualizationGraphWidget},
216 ui{new Ui::VisualizationGraphWidget},
217 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
217 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
218 {
218 {
219 ui->setupUi(this);
219 ui->setupUi(this);
220
220
221 // 'Close' options : widget is deleted when closed
221 // 'Close' options : widget is deleted when closed
222 setAttribute(Qt::WA_DeleteOnClose);
222 setAttribute(Qt::WA_DeleteOnClose);
223
223
224 // Set qcpplot properties :
224 // Set qcpplot properties :
225 // - zoom is enabled
225 // - zoom is enabled
226 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
226 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
227 ui->widget->setInteractions(QCP::iRangeZoom);
227 ui->widget->setInteractions(QCP::iRangeZoom);
228 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
228 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
229
229
230 // The delegate must be initialized after the ui as it uses the plot
230 // The delegate must be initialized after the ui as it uses the plot
231 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
231 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
232
232
233 // Init the cursors
233 // Init the cursors
234 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
234 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
235 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
235 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
236 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
236 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
237 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
237 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
238
238
239 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
239 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
240 connect(ui->widget, &QCustomPlot::mouseRelease, this,
240 connect(ui->widget, &QCustomPlot::mouseRelease, this,
241 &VisualizationGraphWidget::onMouseRelease);
241 &VisualizationGraphWidget::onMouseRelease);
242 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
242 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
243 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
243 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
244 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
244 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
245 &VisualizationGraphWidget::onMouseDoubleClick);
245 &VisualizationGraphWidget::onMouseDoubleClick);
246 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
246 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
247 &QCPAxis::rangeChanged),
247 &QCPAxis::rangeChanged),
248 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
248 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
249
249
250 // Activates menu when right clicking on the graph
250 // Activates menu when right clicking on the graph
251 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
251 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
252 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
252 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
253 &VisualizationGraphWidget::onGraphMenuRequested);
253 &VisualizationGraphWidget::onGraphMenuRequested);
254
254
255 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
255 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
256 &VariableController::onRequestDataLoading);
256 &VariableController::onRequestDataLoading);
257
257
258 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
258 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
259 &VisualizationGraphWidget::onUpdateVarDisplaying);
259 &VisualizationGraphWidget::onUpdateVarDisplaying);
260
260
261 #ifdef Q_OS_MAC
261 #ifdef Q_OS_MAC
262 plot().setPlottingHint(QCP::phFastPolylines, true);
262 plot().setPlottingHint(QCP::phFastPolylines, true);
263 #endif
263 #endif
264 }
264 }
265
265
266
266
267 VisualizationGraphWidget::~VisualizationGraphWidget()
267 VisualizationGraphWidget::~VisualizationGraphWidget()
268 {
268 {
269 delete ui;
269 delete ui;
270 }
270 }
271
271
272 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
272 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
273 {
273 {
274 auto parent = parentWidget();
274 auto parent = parentWidget();
275 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
275 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
276 parent = parent->parentWidget();
276 parent = parent->parentWidget();
277 }
277 }
278
278
279 return qobject_cast<VisualizationZoneWidget *>(parent);
279 return qobject_cast<VisualizationZoneWidget *>(parent);
280 }
280 }
281
281
282 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
282 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
283 {
283 {
284 auto parent = parentWidget();
284 auto parent = parentWidget();
285 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
285 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
286 parent = parent->parentWidget();
286 parent = parent->parentWidget();
287 }
287 }
288
288
289 return qobject_cast<VisualizationWidget *>(parent);
289 return qobject_cast<VisualizationWidget *>(parent);
290 }
290 }
291
291
292 void VisualizationGraphWidget::setFlags(GraphFlags flags)
292 void VisualizationGraphWidget::setFlags(GraphFlags flags)
293 {
293 {
294 impl->m_Flags = std::move(flags);
294 impl->m_Flags = std::move(flags);
295 }
295 }
296
296
297 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
297 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
298 {
298 {
299 /// Lambda used to set graph's units and range according to the variable passed in parameter
299 /// Lambda used to set graph's units and range according to the variable passed in parameter
300 auto loadRange = [this](std::shared_ptr<Variable> variable, const SqpRange &range) {
300 auto loadRange = [this](std::shared_ptr<Variable> variable, const SqpRange &range) {
301 impl->m_RenderingDelegate->setAxesUnits(*variable);
301 impl->m_RenderingDelegate->setAxesUnits(*variable);
302
302
303 this->setFlags(GraphFlag::DisableAll);
303 this->setFlags(GraphFlag::DisableAll);
304 setGraphRange(range);
304 setGraphRange(range);
305 this->setFlags(GraphFlag::EnableAll);
305 this->setFlags(GraphFlag::EnableAll);
306
307 emit requestDataLoading({variable}, range, false);
306 emit requestDataLoading({variable}, range, false);
308 };
307 };
309
308
310 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
309 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
311
310
312 // Calls update of graph's range and units when the data of the variable have been initialized.
311 // Calls update of graph's range and units when the data of the variable have been initialized.
313 // Note: we use QueuedConnection here as the update event must be called in the UI thread
312 // Note: we use QueuedConnection here as the update event must be called in the UI thread
314 connect(variable.get(), &Variable::dataInitialized, this,
313 connect(variable.get(), &Variable::dataInitialized, this,
315 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
314 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
316 if (auto var = varW.lock()) {
315 if (auto var = varW.lock()) {
317 // If the variable is the first added in the graph, we load its range
316 // If the variable is the first added in the graph, we load its range
318 auto firstVariableInGraph = range == INVALID_RANGE;
317 auto firstVariableInGraph = range == INVALID_RANGE;
319 auto loadedRange = graphRange();
318 auto loadedRange = graphRange();
320 if (impl->m_VariableAutoRangeOnInit) {
319 if (impl->m_VariableAutoRangeOnInit) {
321 loadedRange = firstVariableInGraph ? var->range() : range;
320 loadedRange = firstVariableInGraph ? var->range() : range;
322 }
321 }
323 loadRange(var, loadedRange);
322 loadRange(var, loadedRange);
324 setYRange(var);
323 setYRange(var);
325 }
324 }
326 },
325 },
327 Qt::QueuedConnection);
326 Qt::QueuedConnection);
328
327
329 // Uses delegate to create the qcpplot components according to the variable
328 // Uses delegate to create the qcpplot components according to the variable
330 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
329 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
331
330
332 // Sets graph properties
331 // Sets graph properties
333 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
332 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
334
333
335 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
334 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
336
335
337 // If the variable already has its data loaded, load its units and its range in the graph
336 // If the variable already has its data loaded, load its units and its range in the graph
338 if (variable->dataSeries() != nullptr) {
337 if (variable->dataSeries() != nullptr) {
339 loadRange(variable, range);
338 loadRange(variable, range);
340 }
339 }
341
340
342 emit variableAdded(variable);
341 emit variableAdded(variable);
343 }
342 }
344
343
345 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
344 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
346 {
345 {
347 // Each component associated to the variable :
346 // Each component associated to the variable :
348 // - is removed from qcpplot (which deletes it)
347 // - is removed from qcpplot (which deletes it)
349 // - is no longer referenced in the map
348 // - is no longer referenced in the map
350 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
349 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
351 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
350 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
352 emit variableAboutToBeRemoved(variable);
351 emit variableAboutToBeRemoved(variable);
353
352
354 auto &plottablesMap = variableIt->second;
353 auto &plottablesMap = variableIt->second;
355
354
356 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
355 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
357 plottableIt != plottableEnd;) {
356 plottableIt != plottableEnd;) {
358 ui->widget->removePlottable(plottableIt->second);
357 ui->widget->removePlottable(plottableIt->second);
359 plottableIt = plottablesMap.erase(plottableIt);
358 plottableIt = plottablesMap.erase(plottableIt);
360 }
359 }
361
360
362 impl->m_VariableToPlotMultiMap.erase(variableIt);
361 impl->m_VariableToPlotMultiMap.erase(variableIt);
363 }
362 }
364
363
365 // Updates graph
364 // Updates graph
366 ui->widget->replot();
365 ui->widget->replot();
367 }
366 }
368
367
369 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
368 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
370 {
369 {
371 auto variables = QList<std::shared_ptr<Variable> >{};
370 auto variables = QList<std::shared_ptr<Variable> >{};
372 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
371 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
373 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
372 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
374 variables << it->first;
373 variables << it->first;
375 }
374 }
376
375
377 return variables;
376 return variables;
378 }
377 }
379
378
380 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
379 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
381 {
380 {
382 if (!variable) {
381 if (!variable) {
383 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
382 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
384 return;
383 return;
385 }
384 }
386
385
387 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
386 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
388 }
387 }
389
388
390 SqpRange VisualizationGraphWidget::graphRange() const noexcept
389 SqpRange VisualizationGraphWidget::graphRange() const noexcept
391 {
390 {
392 auto graphRange = ui->widget->xAxis->range();
391 auto graphRange = ui->widget->xAxis->range();
393 return SqpRange{graphRange.lower, graphRange.upper};
392 return SqpRange{graphRange.lower, graphRange.upper};
394 }
393 }
395
394
396 void VisualizationGraphWidget::setGraphRange(const SqpRange &range, bool calibration)
395 void VisualizationGraphWidget::setGraphRange(const SqpRange &range, bool calibration)
397 {
396 {
398 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
397 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
399
398
400 if (calibration) {
399 if (calibration) {
401 impl->m_IsCalibration = true;
400 impl->m_IsCalibration = true;
402 }
401 }
403
402
404 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
403 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
405 ui->widget->replot();
404 ui->widget->replot();
406
405
407 if (calibration) {
406 if (calibration) {
408 impl->m_IsCalibration = false;
407 impl->m_IsCalibration = false;
409 }
408 }
410
409
411 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
410 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
412 }
411 }
413
412
414 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
413 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
415 {
414 {
416 impl->m_VariableAutoRangeOnInit = value;
415 impl->m_VariableAutoRangeOnInit = value;
417 }
416 }
418
417
419 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
418 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
420 {
419 {
421 QVector<SqpRange> ranges;
420 QVector<SqpRange> ranges;
422 for (auto zone : impl->m_SelectionZones) {
421 for (auto zone : impl->m_SelectionZones) {
423 ranges << zone->range();
422 ranges << zone->range();
424 }
423 }
425
424
426 return ranges;
425 return ranges;
427 }
426 }
428
427
429 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
428 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
430 {
429 {
431 for (const auto &range : ranges) {
430 for (const auto &range : ranges) {
432 // note: ownership is transfered to QCustomPlot
431 // note: ownership is transfered to QCustomPlot
433 auto zone = new VisualizationSelectionZoneItem(&plot());
432 auto zone = new VisualizationSelectionZoneItem(&plot());
434 zone->setRange(range.m_TStart, range.m_TEnd);
433 zone->setRange(range.m_TStart, range.m_TEnd);
435 impl->addSelectionZone(zone);
434 impl->addSelectionZone(zone);
436 }
435 }
437
436
438 plot().replot(QCustomPlot::rpQueuedReplot);
437 plot().replot(QCustomPlot::rpQueuedReplot);
439 }
438 }
440
439
441 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
440 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
442 const SqpRange &range)
441 const SqpRange &range)
443 {
442 {
444 // note: ownership is transfered to QCustomPlot
443 // note: ownership is transfered to QCustomPlot
445 auto zone = new VisualizationSelectionZoneItem(&plot());
444 auto zone = new VisualizationSelectionZoneItem(&plot());
446 zone->setName(name);
445 zone->setName(name);
447 zone->setRange(range.m_TStart, range.m_TEnd);
446 zone->setRange(range.m_TStart, range.m_TEnd);
448 impl->addSelectionZone(zone);
447 impl->addSelectionZone(zone);
449
448
450 plot().replot(QCustomPlot::rpQueuedReplot);
449 plot().replot(QCustomPlot::rpQueuedReplot);
451
450
452 return zone;
451 return zone;
453 }
452 }
454
453
455 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
454 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
456 {
455 {
457 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
456 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
458
457
459 if (impl->m_HoveredZone == selectionZone) {
458 if (impl->m_HoveredZone == selectionZone) {
460 impl->m_HoveredZone = nullptr;
459 impl->m_HoveredZone = nullptr;
461 setCursor(Qt::ArrowCursor);
460 setCursor(Qt::ArrowCursor);
462 }
461 }
463
462
464 impl->m_SelectionZones.removeAll(selectionZone);
463 impl->m_SelectionZones.removeAll(selectionZone);
465 plot().removeItem(selectionZone);
464 plot().removeItem(selectionZone);
466 plot().replot(QCustomPlot::rpQueuedReplot);
465 plot().replot(QCustomPlot::rpQueuedReplot);
467 }
466 }
468
467
469 void VisualizationGraphWidget::undoZoom()
468 void VisualizationGraphWidget::undoZoom()
470 {
469 {
471 auto zoom = impl->m_ZoomStack.pop();
470 auto zoom = impl->m_ZoomStack.pop();
472 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
471 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
473 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
472 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
474
473
475 axisX->setRange(zoom.first);
474 axisX->setRange(zoom.first);
476 axisY->setRange(zoom.second);
475 axisY->setRange(zoom.second);
477
476
478 plot().replot(QCustomPlot::rpQueuedReplot);
477 plot().replot(QCustomPlot::rpQueuedReplot);
479 }
478 }
480
479
481 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
480 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
482 {
481 {
483 if (visitor) {
482 if (visitor) {
484 visitor->visit(this);
483 visitor->visit(this);
485 }
484 }
486 else {
485 else {
487 qCCritical(LOG_VisualizationGraphWidget())
486 qCCritical(LOG_VisualizationGraphWidget())
488 << tr("Can't visit widget : the visitor is null");
487 << tr("Can't visit widget : the visitor is null");
489 }
488 }
490 }
489 }
491
490
492 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
491 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
493 {
492 {
494 auto isSpectrogram = [](const auto &variable) {
493 auto isSpectrogram = [](const auto &variable) {
495 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
494 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
496 };
495 };
497
496
498 // - A spectrogram series can't be dropped on graph with existing plottables
497 // - A spectrogram series can't be dropped on graph with existing plottables
499 // - No data series can be dropped on graph with existing spectrogram series
498 // - No data series can be dropped on graph with existing spectrogram series
500 return isSpectrogram(variable)
499 return isSpectrogram(variable)
501 ? impl->m_VariableToPlotMultiMap.empty()
500 ? impl->m_VariableToPlotMultiMap.empty()
502 : std::none_of(
501 : std::none_of(
503 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
502 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
504 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
503 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
505 }
504 }
506
505
507 bool VisualizationGraphWidget::contains(const Variable &variable) const
506 bool VisualizationGraphWidget::contains(const Variable &variable) const
508 {
507 {
509 // Finds the variable among the keys of the map
508 // Finds the variable among the keys of the map
510 auto variablePtr = &variable;
509 auto variablePtr = &variable;
511 auto findVariable
510 auto findVariable
512 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
511 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
513
512
514 auto end = impl->m_VariableToPlotMultiMap.cend();
513 auto end = impl->m_VariableToPlotMultiMap.cend();
515 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
514 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
516 return it != end;
515 return it != end;
517 }
516 }
518
517
519 QString VisualizationGraphWidget::name() const
518 QString VisualizationGraphWidget::name() const
520 {
519 {
521 return impl->m_Name;
520 return impl->m_Name;
522 }
521 }
523
522
524 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
523 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
525 {
524 {
526 auto mimeData = new QMimeData;
525 auto mimeData = new QMimeData;
527
526
528 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
527 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
529 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
528 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
530 && selectionZoneItemUnderCursor) {
529 && selectionZoneItemUnderCursor) {
531 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
530 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
532 selectionZoneItemUnderCursor->range()));
531 selectionZoneItemUnderCursor->range()));
533 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
532 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
534 selectionZoneItemUnderCursor->range()));
533 selectionZoneItemUnderCursor->range()));
535 }
534 }
536 else {
535 else {
537 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
536 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
538
537
539 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
538 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
540 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
539 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
541 }
540 }
542
541
543 return mimeData;
542 return mimeData;
544 }
543 }
545
544
546 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
545 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
547 {
546 {
548 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
547 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
549 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
548 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
550 && selectionZoneItemUnderCursor) {
549 && selectionZoneItemUnderCursor) {
551
550
552 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
551 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
553 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
552 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
554
553
555 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
554 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
556 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
555 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
557 .toSize();
556 .toSize();
558
557
559 auto pixmap = QPixmap(zoneSize);
558 auto pixmap = QPixmap(zoneSize);
560 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
559 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
561
560
562 return pixmap;
561 return pixmap;
563 }
562 }
564
563
565 return QPixmap();
564 return QPixmap();
566 }
565 }
567
566
568 bool VisualizationGraphWidget::isDragAllowed() const
567 bool VisualizationGraphWidget::isDragAllowed() const
569 {
568 {
570 return true;
569 return true;
571 }
570 }
572
571
573 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
572 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
574 {
573 {
575 if (highlighted) {
574 if (highlighted) {
576 plot().setBackground(QBrush(QColor("#BBD5EE")));
575 plot().setBackground(QBrush(QColor("#BBD5EE")));
577 }
576 }
578 else {
577 else {
579 plot().setBackground(QBrush(Qt::white));
578 plot().setBackground(QBrush(Qt::white));
580 }
579 }
581
580
582 plot().update();
581 plot().update();
583 }
582 }
584
583
585 void VisualizationGraphWidget::addVerticalCursor(double time)
584 void VisualizationGraphWidget::addVerticalCursor(double time)
586 {
585 {
587 impl->m_VerticalCursor->setPosition(time);
586 impl->m_VerticalCursor->setPosition(time);
588 impl->m_VerticalCursor->setVisible(true);
587 impl->m_VerticalCursor->setVisible(true);
589
588
590 auto text
589 auto text
591 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
590 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
592 impl->m_VerticalCursor->setLabelText(text);
591 impl->m_VerticalCursor->setLabelText(text);
593 }
592 }
594
593
595 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
594 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
596 {
595 {
597 impl->m_VerticalCursor->setAbsolutePosition(position);
596 impl->m_VerticalCursor->setAbsolutePosition(position);
598 impl->m_VerticalCursor->setVisible(true);
597 impl->m_VerticalCursor->setVisible(true);
599
598
600 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
599 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
601 auto text
600 auto text
602 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
601 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
603 impl->m_VerticalCursor->setLabelText(text);
602 impl->m_VerticalCursor->setLabelText(text);
604 }
603 }
605
604
606 void VisualizationGraphWidget::removeVerticalCursor()
605 void VisualizationGraphWidget::removeVerticalCursor()
607 {
606 {
608 impl->m_VerticalCursor->setVisible(false);
607 impl->m_VerticalCursor->setVisible(false);
609 plot().replot(QCustomPlot::rpQueuedReplot);
608 plot().replot(QCustomPlot::rpQueuedReplot);
610 }
609 }
611
610
612 void VisualizationGraphWidget::addHorizontalCursor(double value)
611 void VisualizationGraphWidget::addHorizontalCursor(double value)
613 {
612 {
614 impl->m_HorizontalCursor->setPosition(value);
613 impl->m_HorizontalCursor->setPosition(value);
615 impl->m_HorizontalCursor->setVisible(true);
614 impl->m_HorizontalCursor->setVisible(true);
616 impl->m_HorizontalCursor->setLabelText(QString::number(value));
615 impl->m_HorizontalCursor->setLabelText(QString::number(value));
617 }
616 }
618
617
619 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
618 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
620 {
619 {
621 impl->m_HorizontalCursor->setAbsolutePosition(position);
620 impl->m_HorizontalCursor->setAbsolutePosition(position);
622 impl->m_HorizontalCursor->setVisible(true);
621 impl->m_HorizontalCursor->setVisible(true);
623
622
624 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
623 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
625 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
624 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
626 }
625 }
627
626
628 void VisualizationGraphWidget::removeHorizontalCursor()
627 void VisualizationGraphWidget::removeHorizontalCursor()
629 {
628 {
630 impl->m_HorizontalCursor->setVisible(false);
629 impl->m_HorizontalCursor->setVisible(false);
631 plot().replot(QCustomPlot::rpQueuedReplot);
630 plot().replot(QCustomPlot::rpQueuedReplot);
632 }
631 }
633
632
634 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
633 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
635 {
634 {
636 Q_UNUSED(event);
635 Q_UNUSED(event);
637
636
638 // Prevents that all variables will be removed from graph when it will be closed
637 // Prevents that all variables will be removed from graph when it will be closed
639 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
638 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
640 emit variableAboutToBeRemoved(variableEntry.first);
639 emit variableAboutToBeRemoved(variableEntry.first);
641 }
640 }
642 }
641 }
643
642
644 void VisualizationGraphWidget::enterEvent(QEvent *event)
643 void VisualizationGraphWidget::enterEvent(QEvent *event)
645 {
644 {
646 Q_UNUSED(event);
645 Q_UNUSED(event);
647 impl->m_RenderingDelegate->showGraphOverlay(true);
646 impl->m_RenderingDelegate->showGraphOverlay(true);
648 }
647 }
649
648
650 void VisualizationGraphWidget::leaveEvent(QEvent *event)
649 void VisualizationGraphWidget::leaveEvent(QEvent *event)
651 {
650 {
652 Q_UNUSED(event);
651 Q_UNUSED(event);
653 impl->m_RenderingDelegate->showGraphOverlay(false);
652 impl->m_RenderingDelegate->showGraphOverlay(false);
654
653
655 if (auto parentZone = parentZoneWidget()) {
654 if (auto parentZone = parentZoneWidget()) {
656 parentZone->notifyMouseLeaveGraph(this);
655 parentZone->notifyMouseLeaveGraph(this);
657 }
656 }
658 else {
657 else {
659 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
658 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
660 }
659 }
661
660
662 if (impl->m_HoveredZone) {
661 if (impl->m_HoveredZone) {
663 impl->m_HoveredZone->setHovered(false);
662 impl->m_HoveredZone->setHovered(false);
664 impl->m_HoveredZone = nullptr;
663 impl->m_HoveredZone = nullptr;
665 }
664 }
666 }
665 }
667
666
668 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
667 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
669 {
668 {
670 return *ui->widget;
669 return *ui->widget;
671 }
670 }
672
671
673 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
672 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
674 {
673 {
675 QMenu graphMenu{};
674 QMenu graphMenu{};
676
675
677 // Iterates on variables (unique keys)
676 // Iterates on variables (unique keys)
678 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
677 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
679 end = impl->m_VariableToPlotMultiMap.cend();
678 end = impl->m_VariableToPlotMultiMap.cend();
680 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
679 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
681 // 'Remove variable' action
680 // 'Remove variable' action
682 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
681 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
683 [ this, var = it->first ]() { removeVariable(var); });
682 [ this, var = it->first ]() { removeVariable(var); });
684 }
683 }
685
684
686 if (!impl->m_ZoomStack.isEmpty()) {
685 if (!impl->m_ZoomStack.isEmpty()) {
687 if (!graphMenu.isEmpty()) {
686 if (!graphMenu.isEmpty()) {
688 graphMenu.addSeparator();
687 graphMenu.addSeparator();
689 }
688 }
690
689
691 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
690 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
692 }
691 }
693
692
694 // Selection Zone Actions
693 // Selection Zone Actions
695 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
694 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
696 if (selectionZoneItem) {
695 if (selectionZoneItem) {
697 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
696 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
698 selectedItems.removeAll(selectionZoneItem);
697 selectedItems.removeAll(selectionZoneItem);
699 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
698 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
700
699
701 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
700 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
702 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
701 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
703 graphMenu.addSeparator();
702 graphMenu.addSeparator();
704 }
703 }
705
704
706 QHash<QString, QMenu *> subMenus;
705 QHash<QString, QMenu *> subMenus;
707 QHash<QString, bool> subMenusEnabled;
706 QHash<QString, bool> subMenusEnabled;
708
707
709 for (auto zoneAction : zoneActions) {
708 for (auto zoneAction : zoneActions) {
710
709
711 auto isEnabled = zoneAction->isEnabled(selectedItems);
710 auto isEnabled = zoneAction->isEnabled(selectedItems);
712
711
713 auto menu = &graphMenu;
712 auto menu = &graphMenu;
714 for (auto subMenuName : zoneAction->subMenuList()) {
713 for (auto subMenuName : zoneAction->subMenuList()) {
715 if (!subMenus.contains(subMenuName)) {
714 if (!subMenus.contains(subMenuName)) {
716 menu = menu->addMenu(subMenuName);
715 menu = menu->addMenu(subMenuName);
717 subMenus[subMenuName] = menu;
716 subMenus[subMenuName] = menu;
718 subMenusEnabled[subMenuName] = isEnabled;
717 subMenusEnabled[subMenuName] = isEnabled;
719 }
718 }
720 else {
719 else {
721 menu = subMenus.value(subMenuName);
720 menu = subMenus.value(subMenuName);
722 if (isEnabled) {
721 if (isEnabled) {
723 // The sub menu is enabled if at least one of its actions is enabled
722 // The sub menu is enabled if at least one of its actions is enabled
724 subMenusEnabled[subMenuName] = true;
723 subMenusEnabled[subMenuName] = true;
725 }
724 }
726 }
725 }
727 }
726 }
728
727
729 auto action = menu->addAction(zoneAction->name());
728 auto action = menu->addAction(zoneAction->name());
730 action->setEnabled(isEnabled);
729 action->setEnabled(isEnabled);
731 action->setShortcut(zoneAction->displayedShortcut());
730 action->setShortcut(zoneAction->displayedShortcut());
732 QObject::connect(action, &QAction::triggered,
731 QObject::connect(action, &QAction::triggered,
733 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
732 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
734 }
733 }
735
734
736 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
735 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
737 it.value()->setEnabled(subMenusEnabled[it.key()]);
736 it.value()->setEnabled(subMenusEnabled[it.key()]);
738 }
737 }
739 }
738 }
740
739
741 if (!graphMenu.isEmpty()) {
740 if (!graphMenu.isEmpty()) {
742 graphMenu.exec(QCursor::pos());
741 graphMenu.exec(QCursor::pos());
743 }
742 }
744 }
743 }
745
744
746 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
745 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
747 {
746 {
748 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
747 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
749 << QThread::currentThread()->objectName() << "DoAcqui"
748 << QThread::currentThread()->objectName() << "DoAcqui"
750 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
749 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
751
750
752 auto graphRange = SqpRange{t1.lower, t1.upper};
751 auto graphRange = SqpRange{t1.lower, t1.upper};
753 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
752 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
754
753
755 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
754 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
756 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
755 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
757
756
758 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
757 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
759 end = impl->m_VariableToPlotMultiMap.end();
758 end = impl->m_VariableToPlotMultiMap.end();
760 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
759 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
761 variableUnderGraphVector.push_back(it->first);
760 variableUnderGraphVector.push_back(it->first);
762 }
761 }
763 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
762 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
764 !impl->m_IsCalibration);
763 !impl->m_IsCalibration);
765 }
764 }
766
765
767 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
766 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
768 qCDebug(LOG_VisualizationGraphWidget())
767 qCDebug(LOG_VisualizationGraphWidget())
769 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
768 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
770 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
769 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
771 emit synchronize(graphRange, oldGraphRange);
770 emit synchronize(graphRange, oldGraphRange);
772 }
771 }
773
772
774 auto pos = mapFromGlobal(QCursor::pos());
773 auto pos = mapFromGlobal(QCursor::pos());
775 auto axisPos = impl->posToAxisPos(pos, plot());
774 auto axisPos = impl->posToAxisPos(pos, plot());
776 if (auto parentZone = parentZoneWidget()) {
775 if (auto parentZone = parentZoneWidget()) {
777 if (impl->pointIsInAxisRect(axisPos, plot())) {
776 if (impl->pointIsInAxisRect(axisPos, plot())) {
778 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
777 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
779 }
778 }
780 else {
779 else {
781 parentZone->notifyMouseLeaveGraph(this);
780 parentZone->notifyMouseLeaveGraph(this);
782 }
781 }
783 }
782 }
784 else {
783 else {
785 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
784 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
786 }
785 }
787
786
788 // Quits calibration
787 // Quits calibration
789 impl->m_IsCalibration = false;
788 impl->m_IsCalibration = false;
790 }
789 }
791
790
792 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
791 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
793 {
792 {
794 impl->m_RenderingDelegate->onMouseDoubleClick(event);
793 impl->m_RenderingDelegate->onMouseDoubleClick(event);
795 }
794 }
796
795
797 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
796 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
798 {
797 {
799 // Handles plot rendering when mouse is moving
798 // Handles plot rendering when mouse is moving
800 impl->m_RenderingDelegate->onMouseMove(event);
799 impl->m_RenderingDelegate->onMouseMove(event);
801
800
802 auto axisPos = impl->posToAxisPos(event->pos(), plot());
801 auto axisPos = impl->posToAxisPos(event->pos(), plot());
803
802
804 // Zoom box and zone drawing
803 // Zoom box and zone drawing
805 if (impl->m_DrawingZoomRect) {
804 if (impl->m_DrawingZoomRect) {
806 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
805 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
807 }
806 }
808 else if (impl->m_DrawingZone) {
807 else if (impl->m_DrawingZone) {
809 impl->m_DrawingZone->setEnd(axisPos.x());
808 impl->m_DrawingZone->setEnd(axisPos.x());
810 }
809 }
811
810
812 // Cursor
811 // Cursor
813 if (auto parentZone = parentZoneWidget()) {
812 if (auto parentZone = parentZoneWidget()) {
814 if (impl->pointIsInAxisRect(axisPos, plot())) {
813 if (impl->pointIsInAxisRect(axisPos, plot())) {
815 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
814 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
816 }
815 }
817 else {
816 else {
818 parentZone->notifyMouseLeaveGraph(this);
817 parentZone->notifyMouseLeaveGraph(this);
819 }
818 }
820 }
819 }
821 else {
820 else {
822 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
821 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
823 }
822 }
824
823
825 // Search for the selection zone under the mouse
824 // Search for the selection zone under the mouse
826 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
825 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
827 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
826 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
828 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
827 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
829
828
830 // Sets the appropriate cursor shape
829 // Sets the appropriate cursor shape
831 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
830 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
832 setCursor(cursorShape);
831 setCursor(cursorShape);
833
832
834 // Manages the hovered zone
833 // Manages the hovered zone
835 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
834 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
836 if (impl->m_HoveredZone) {
835 if (impl->m_HoveredZone) {
837 impl->m_HoveredZone->setHovered(false);
836 impl->m_HoveredZone->setHovered(false);
838 }
837 }
839 selectionZoneItemUnderCursor->setHovered(true);
838 selectionZoneItemUnderCursor->setHovered(true);
840 impl->m_HoveredZone = selectionZoneItemUnderCursor;
839 impl->m_HoveredZone = selectionZoneItemUnderCursor;
841 plot().replot(QCustomPlot::rpQueuedReplot);
840 plot().replot(QCustomPlot::rpQueuedReplot);
842 }
841 }
843 }
842 }
844 else {
843 else {
845 // There is no zone under the mouse or the interaction mode is not "selection zones"
844 // There is no zone under the mouse or the interaction mode is not "selection zones"
846 if (impl->m_HoveredZone) {
845 if (impl->m_HoveredZone) {
847 impl->m_HoveredZone->setHovered(false);
846 impl->m_HoveredZone->setHovered(false);
848 impl->m_HoveredZone = nullptr;
847 impl->m_HoveredZone = nullptr;
849 }
848 }
850
849
851 setCursor(Qt::ArrowCursor);
850 setCursor(Qt::ArrowCursor);
852 }
851 }
853
852
854 impl->m_HasMovedMouse = true;
853 impl->m_HasMovedMouse = true;
855 VisualizationDragWidget::mouseMoveEvent(event);
854 VisualizationDragWidget::mouseMoveEvent(event);
856 }
855 }
857
856
858 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
857 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
859 {
858 {
860 auto value = event->angleDelta().x() + event->angleDelta().y();
859 auto value = event->angleDelta().x() + event->angleDelta().y();
861 if (value != 0) {
860 if (value != 0) {
862
861
863 auto direction = value > 0 ? 1.0 : -1.0;
862 auto direction = value > 0 ? 1.0 : -1.0;
864 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
863 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
865 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
864 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
866 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
865 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
867
866
868 auto zoomOrientations = QFlags<Qt::Orientation>{};
867 auto zoomOrientations = QFlags<Qt::Orientation>{};
869 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
868 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
870 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
869 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
871
870
872 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
871 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
873
872
874 if (!isZoomX && !isZoomY) {
873 if (!isZoomX && !isZoomY) {
875 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
874 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
876 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
875 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
877
876
878 axis->setRange(axis->range() + diff);
877 axis->setRange(axis->range() + diff);
879
878
880 if (plot().noAntialiasingOnDrag()) {
879 if (plot().noAntialiasingOnDrag()) {
881 plot().setNotAntialiasedElements(QCP::aeAll);
880 plot().setNotAntialiasedElements(QCP::aeAll);
882 }
881 }
883
882
884 plot().replot(QCustomPlot::rpQueuedReplot);
883 plot().replot(QCustomPlot::rpQueuedReplot);
885 }
884 }
886 }
885 }
887 }
886 }
888
887
889 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
888 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
890 {
889 {
891 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
890 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
892 auto isSelectionZoneMode
891 auto isSelectionZoneMode
893 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
892 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
894 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
893 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
895
894
896 if (!isDragDropClick && isLeftClick) {
895 if (!isDragDropClick && isLeftClick) {
897 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
896 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
898 // Starts a zoom box
897 // Starts a zoom box
899 impl->startDrawingRect(event->pos(), plot());
898 impl->startDrawingRect(event->pos(), plot());
900 }
899 }
901 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
900 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
902 // Starts a new selection zone
901 // Starts a new selection zone
903 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
902 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
904 if (!zoneAtPos) {
903 if (!zoneAtPos) {
905 impl->startDrawingZone(event->pos(), this);
904 impl->startDrawingZone(event->pos(), this);
906 }
905 }
907 }
906 }
908 }
907 }
909
908
910 // Allows mouse panning only in default mode
909 // Allows mouse panning only in default mode
911 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
910 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
912 == SqpApplication::PlotsInteractionMode::None
911 == SqpApplication::PlotsInteractionMode::None
913 && !isDragDropClick);
912 && !isDragDropClick);
914
913
915 // Allows zone edition only in selection zone mode without drag&drop
914 // Allows zone edition only in selection zone mode without drag&drop
916 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
915 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
917
916
918 // Selection / Deselection
917 // Selection / Deselection
919 if (isSelectionZoneMode) {
918 if (isSelectionZoneMode) {
920 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
919 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
921 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
920 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
922
921
923
922
924 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
923 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
925 && !isMultiSelectionClick) {
924 && !isMultiSelectionClick) {
926 parentVisualizationWidget()->selectionZoneManager().select(
925 parentVisualizationWidget()->selectionZoneManager().select(
927 {selectionZoneItemUnderCursor});
926 {selectionZoneItemUnderCursor});
928 }
927 }
929 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
928 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
930 parentVisualizationWidget()->selectionZoneManager().clearSelection();
929 parentVisualizationWidget()->selectionZoneManager().clearSelection();
931 }
930 }
932 else {
931 else {
933 // No selection change
932 // No selection change
934 }
933 }
935
934
936 if (selectionZoneItemUnderCursor && isLeftClick) {
935 if (selectionZoneItemUnderCursor && isLeftClick) {
937 selectionZoneItemUnderCursor->setAssociatedEditedZones(
936 selectionZoneItemUnderCursor->setAssociatedEditedZones(
938 parentVisualizationWidget()->selectionZoneManager().selectedItems());
937 parentVisualizationWidget()->selectionZoneManager().selectedItems());
939 }
938 }
940 }
939 }
941
940
942
941
943 impl->m_HasMovedMouse = false;
942 impl->m_HasMovedMouse = false;
944 VisualizationDragWidget::mousePressEvent(event);
943 VisualizationDragWidget::mousePressEvent(event);
945 }
944 }
946
945
947 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
946 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
948 {
947 {
949 if (impl->m_DrawingZoomRect) {
948 if (impl->m_DrawingZoomRect) {
950
949
951 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
950 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
952 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
951 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
953
952
954 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
953 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
955 impl->m_DrawingZoomRect->bottomRight->coords().x()};
954 impl->m_DrawingZoomRect->bottomRight->coords().x()};
956
955
957 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
956 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
958 impl->m_DrawingZoomRect->bottomRight->coords().y()};
957 impl->m_DrawingZoomRect->bottomRight->coords().y()};
959
958
960 impl->removeDrawingRect(plot());
959 impl->removeDrawingRect(plot());
961
960
962 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
961 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
963 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
962 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
964 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
963 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
965 axisX->setRange(newAxisXRange);
964 axisX->setRange(newAxisXRange);
966 axisY->setRange(newAxisYRange);
965 axisY->setRange(newAxisYRange);
967
966
968 plot().replot(QCustomPlot::rpQueuedReplot);
967 plot().replot(QCustomPlot::rpQueuedReplot);
969 }
968 }
970 }
969 }
971
970
972 impl->endDrawingZone(this);
971 impl->endDrawingZone(this);
973
972
974 // Selection / Deselection
973 // Selection / Deselection
975 auto isSelectionZoneMode
974 auto isSelectionZoneMode
976 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
975 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
977 if (isSelectionZoneMode) {
976 if (isSelectionZoneMode) {
978 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
977 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
979 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
978 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
980 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
979 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
981 && !impl->m_HasMovedMouse) {
980 && !impl->m_HasMovedMouse) {
982
981
983 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
982 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
984 if (zonesUnderCursor.count() > 1) {
983 if (zonesUnderCursor.count() > 1) {
985 // There are multiple zones under the mouse.
984 // There are multiple zones under the mouse.
986 // Performs the selection with a selection dialog.
985 // Performs the selection with a selection dialog.
987 VisualizationMultiZoneSelectionDialog dialog{this};
986 VisualizationMultiZoneSelectionDialog dialog{this};
988 dialog.setZones(zonesUnderCursor);
987 dialog.setZones(zonesUnderCursor);
989 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
988 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
990 dialog.activateWindow();
989 dialog.activateWindow();
991 dialog.raise();
990 dialog.raise();
992 if (dialog.exec() == QDialog::Accepted) {
991 if (dialog.exec() == QDialog::Accepted) {
993 auto selection = dialog.selectedZones();
992 auto selection = dialog.selectedZones();
994
993
995 if (!isMultiSelectionClick) {
994 if (!isMultiSelectionClick) {
996 parentVisualizationWidget()->selectionZoneManager().clearSelection();
995 parentVisualizationWidget()->selectionZoneManager().clearSelection();
997 }
996 }
998
997
999 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
998 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
1000 auto zone = it.key();
999 auto zone = it.key();
1001 auto isSelected = it.value();
1000 auto isSelected = it.value();
1002 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1001 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1003 isSelected);
1002 isSelected);
1004
1003
1005 if (isSelected) {
1004 if (isSelected) {
1006 // Puts the zone on top of the stack so it can be moved or resized
1005 // Puts the zone on top of the stack so it can be moved or resized
1007 impl->moveSelectionZoneOnTop(zone, plot());
1006 impl->moveSelectionZoneOnTop(zone, plot());
1008 }
1007 }
1009 }
1008 }
1010 }
1009 }
1011 }
1010 }
1012 else {
1011 else {
1013 if (!isMultiSelectionClick) {
1012 if (!isMultiSelectionClick) {
1014 parentVisualizationWidget()->selectionZoneManager().select(
1013 parentVisualizationWidget()->selectionZoneManager().select(
1015 {selectionZoneItemUnderCursor});
1014 {selectionZoneItemUnderCursor});
1016 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1015 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1017 }
1016 }
1018 else {
1017 else {
1019 parentVisualizationWidget()->selectionZoneManager().setSelected(
1018 parentVisualizationWidget()->selectionZoneManager().setSelected(
1020 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1019 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1021 || event->button() == Qt::RightButton);
1020 || event->button() == Qt::RightButton);
1022 }
1021 }
1023 }
1022 }
1024 }
1023 }
1025 else {
1024 else {
1026 // No selection change
1025 // No selection change
1027 }
1026 }
1028 }
1027 }
1029 }
1028 }
1030
1029
1031 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1030 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1032 {
1031 {
1033 auto graphRange = ui->widget->xAxis->range();
1032 auto graphRange = ui->widget->xAxis->range();
1034 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
1033 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
1035
1034
1036 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1035 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1037 auto variable = variableEntry.first;
1036 auto variable = variableEntry.first;
1038 qCDebug(LOG_VisualizationGraphWidget())
1037 qCDebug(LOG_VisualizationGraphWidget())
1039 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1038 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1040 qCDebug(LOG_VisualizationGraphWidget())
1039 qCDebug(LOG_VisualizationGraphWidget())
1041 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1040 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1042 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1041 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1043 impl->updateData(variableEntry.second, variable, variable->range());
1042 impl->updateData(variableEntry.second, variable, variable->range());
1044 }
1043 }
1045 }
1044 }
1046 }
1045 }
1047
1046
1048 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1047 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1049 const SqpRange &range)
1048 const SqpRange &range)
1050 {
1049 {
1051 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1050 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1052 if (it != impl->m_VariableToPlotMultiMap.end()) {
1051 if (it != impl->m_VariableToPlotMultiMap.end()) {
1053 impl->updateData(it->second, variable, range);
1052 impl->updateData(it->second, variable, range);
1054 }
1053 }
1055 }
1054 }
@@ -1,106 +1,105
1 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
2 <ui version="4.0">
3 <class>CatalogueSideBarWidget</class>
3 <class>CatalogueSideBarWidget</class>
4 <widget class="QWidget" name="CatalogueSideBarWidget">
4 <widget class="QWidget" name="CatalogueSideBarWidget">
5 <property name="geometry">
5 <property name="geometry">
6 <rect>
6 <rect>
7 <x>0</x>
7 <x>0</x>
8 <y>0</y>
8 <y>0</y>
9 <width>330</width>
9 <width>330</width>
10 <height>523</height>
10 <height>523</height>
11 </rect>
11 </rect>
12 </property>
12 </property>
13 <property name="windowTitle">
13 <property name="windowTitle">
14 <string>Form</string>
14 <string>Form</string>
15 </property>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <property name="leftMargin">
17 <property name="leftMargin">
18 <number>0</number>
18 <number>0</number>
19 </property>
19 </property>
20 <property name="topMargin">
20 <property name="topMargin">
21 <number>0</number>
21 <number>0</number>
22 </property>
22 </property>
23 <property name="rightMargin">
23 <property name="rightMargin">
24 <number>0</number>
24 <number>0</number>
25 </property>
25 </property>
26 <property name="bottomMargin">
26 <property name="bottomMargin">
27 <number>0</number>
27 <number>0</number>
28 </property>
28 </property>
29 <item>
29 <item>
30 <layout class="QHBoxLayout" name="horizontalLayout">
30 <layout class="QHBoxLayout" name="horizontalLayout">
31 <item>
31 <item>
32 <widget class="QToolButton" name="btnAdd">
32 <widget class="QToolButton" name="btnAdd">
33 <property name="enabled">
33 <property name="enabled">
34 <bool>false</bool>
34 <bool>true</bool>
35 </property>
35 </property>
36 <property name="text">
36 <property name="text">
37 <string>+</string>
37 <string>+</string>
38 </property>
38 </property>
39 <property name="icon">
39 <property name="icon">
40 <iconset resource="../../resources/sqpguiresources.qrc">
40 <iconset resource="../../resources/sqpguiresources.qrc">
41 <normaloff>:/icones/add.png</normaloff>:/icones/add.png</iconset>
41 <normaloff>:/icones/add.png</normaloff>:/icones/add.png</iconset>
42 </property>
42 </property>
43 <property name="autoRaise">
43 <property name="autoRaise">
44 <bool>true</bool>
44 <bool>true</bool>
45 </property>
45 </property>
46 </widget>
46 </widget>
47 </item>
47 </item>
48 <item>
48 <item>
49 <widget class="QToolButton" name="btnRemove">
49 <widget class="QToolButton" name="btnRemove">
50 <property name="enabled">
50 <property name="enabled">
51 <bool>false</bool>
51 <bool>true</bool>
52 </property>
52 </property>
53 <property name="text">
53 <property name="text">
54 <string> - </string>
54 <string> - </string>
55 </property>
55 </property>
56 <property name="icon">
56 <property name="icon">
57 <iconset resource="../../resources/sqpguiresources.qrc">
57 <iconset resource="../../resources/sqpguiresources.qrc">
58 <normaloff>:/icones/remove.png</normaloff>:/icones/remove.png</iconset>
58 <normaloff>:/icones/remove.png</normaloff>:/icones/remove.png</iconset>
59 </property>
59 </property>
60 <property name="autoRaise">
60 <property name="autoRaise">
61 <bool>true</bool>
61 <bool>true</bool>
62 </property>
62 </property>
63 </widget>
63 </widget>
64 </item>
64 </item>
65 <item>
65 <item>
66 <spacer name="horizontalSpacer">
66 <spacer name="horizontalSpacer">
67 <property name="orientation">
67 <property name="orientation">
68 <enum>Qt::Horizontal</enum>
68 <enum>Qt::Horizontal</enum>
69 </property>
69 </property>
70 <property name="sizeHint" stdset="0">
70 <property name="sizeHint" stdset="0">
71 <size>
71 <size>
72 <width>40</width>
72 <width>40</width>
73 <height>20</height>
73 <height>20</height>
74 </size>
74 </size>
75 </property>
75 </property>
76 </spacer>
76 </spacer>
77 </item>
77 </item>
78 </layout>
78 </layout>
79 </item>
79 </item>
80 <item>
80 <item>
81 <widget class="QTreeView" name="treeView">
81 <widget class="QTreeView" name="treeView">
82 <property name="acceptDrops">
82 <property name="acceptDrops">
83 <bool>true</bool>
83 <bool>true</bool>
84 </property>
84 </property>
85 <property name="dragDropMode">
85 <property name="dragDropMode">
86 <enum>QAbstractItemView::DragDrop</enum>
86 <enum>QAbstractItemView::DragDrop</enum>
87 </property>
87 </property>
88 <property name="selectionMode">
88 <property name="selectionMode">
89 <enum>QAbstractItemView::ExtendedSelection</enum>
89 <enum>QAbstractItemView::ExtendedSelection</enum>
90 </property>
90 </property>
91 <attribute name="headerVisible">
91 <attribute name="headerVisible">
92 <bool>false</bool>
92 <bool>false</bool>
93 </attribute>
93 </attribute>
94 <attribute name="headerStretchLastSection">
94 <attribute name="headerStretchLastSection">
95 <bool>false</bool>
95 <bool>false</bool>
96 </attribute>
96 </attribute>
97 </widget>
97 </widget>
98 </item>
98 </item>
99 </layout>
99 </layout>
100 </widget>
100 </widget>
101 <resources>
101 <resources>
102 <include location="../../resources/sqpguiresources.qrc"/>
102 <include location="../../resources/sqpguiresources.qrc"/>
103 <include location="../../resources/sqpguiresources.qrc"/>
104 </resources>
103 </resources>
105 <connections/>
104 <connections/>
106 </ui>
105 </ui>
General Comments 0
You need to be logged in to leave comments. Login now