##// END OF EJS Templates
Merge branch 'feature/ImprovePerf' into develop
Alexandre Leroux -
r615:4575ac2a0a6a merge
parent child
Show More
@@ -1,43 +1,56
1 1 #ifndef SCIQLOP_SQPRANGE_H
2 2 #define SCIQLOP_SQPRANGE_H
3 3
4 4 #include <QObject>
5 5
6 6 #include <QDebug>
7 7
8 8 #include <Common/DateUtils.h>
9 9 #include <Common/MetaTypes.h>
10 10
11 11 /**
12 12 * @brief The SqpRange struct holds the information of time parameters
13 13 */
14 14 struct SqpRange {
15 15 /// Start time (UTC)
16 16 double m_TStart;
17 17 /// End time (UTC)
18 18 double m_TEnd;
19 19
20 20 bool contains(const SqpRange &dateTime) const noexcept
21 21 {
22 22 return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd);
23 23 }
24 24
25 25 bool intersect(const SqpRange &dateTime) const noexcept
26 26 {
27 27 return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd);
28 28 }
29
30 bool operator==(const SqpRange &other) const
31 {
32 auto equals = [](const auto &v1, const auto &v2) {
33 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
34 };
35
36 return equals(m_TStart, other.m_TStart) && equals(m_TEnd, other.m_TEnd);
37 }
38 bool operator!=(const SqpRange &other) const { return !(*this == other); }
29 39 };
30 40
41 const auto INVALID_RANGE
42 = SqpRange{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()};
43
31 44 inline QDebug operator<<(QDebug d, SqpRange obj)
32 45 {
33 46 auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart);
34 47 auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd);
35 48
36 49 d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd;
37 50 return d;
38 51 }
39 52
40 53 // Required for using shared_ptr in signals/slots
41 54 SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, SqpRange)
42 55
43 56 #endif // SCIQLOP_SQPRANGE_H
@@ -1,66 +1,75
1 1 #ifndef SCIQLOP_VARIABLE_H
2 2 #define SCIQLOP_VARIABLE_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 #include <Data/DataSeriesIterator.h>
6 7 #include <Data/SqpRange.h>
7 8
8 9 #include <QLoggingCategory>
9 10 #include <QObject>
10 11
11 12 #include <Common/MetaTypes.h>
12 13 #include <Common/spimpl.h>
13 14
14 15 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
15 16
16 17 class IDataSeries;
17 18 class QString;
18 19
19 20 /**
20 21 * @brief The Variable class represents a variable in SciQlop.
21 22 */
22 23 class SCIQLOP_CORE_EXPORT Variable : public QObject {
23 24
24 25 Q_OBJECT
25 26
26 27 public:
27 28 explicit Variable(const QString &name, const SqpRange &dateTime,
28 29 const QVariantHash &metadata = {});
29 30
30 31 QString name() const noexcept;
31 32 SqpRange range() const noexcept;
32 33 void setRange(const SqpRange &range) noexcept;
33 34 SqpRange cacheRange() const noexcept;
34 35 void setCacheRange(const SqpRange &cacheRange) noexcept;
35 36
37 /// Returns the real range of the variable, i.e. the min and max x-axis values of the data
38 /// series between the range of the variable. The real range is updated each time the variable
39 /// range or the data series changed
40 /// @return the real range, invalid range if the data series is null or empty
41 /// @sa setDataSeries()
42 /// @sa setRange()
43 SqpRange realRange() const noexcept;
44
36 45 /// @return the data of the variable, nullptr if there is no data
37 46 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
38 47
39 48 QVariantHash metadata() const noexcept;
40 49
41 50 bool contains(const SqpRange &range) const noexcept;
42 51 bool intersect(const SqpRange &range) const noexcept;
43 52 bool isInside(const SqpRange &range) const noexcept;
44 53
45 54 bool cacheContains(const SqpRange &range) const noexcept;
46 55 bool cacheIntersect(const SqpRange &range) const noexcept;
47 56 bool cacheIsInside(const SqpRange &range) const noexcept;
48 57
49 58 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
50 59 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
51 60 void setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
52 61 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
53 62
54 63 signals:
55 64 void updated();
56 65
57 66 private:
58 67 class VariablePrivate;
59 68 spimpl::unique_impl_ptr<VariablePrivate> impl;
60 69 };
61 70
62 71 // Required for using shared_ptr in signals/slots
63 72 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
64 73 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
65 74
66 75 #endif // SCIQLOP_VARIABLE_H
@@ -1,61 +1,61
1 1 #ifndef SCIQLOP_VARIABLEACQUISITIONWORKER_H
2 2 #define SCIQLOP_VARIABLEACQUISITIONWORKER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <QLoggingCategory>
8 8 #include <QObject>
9 9 #include <QUuid>
10 10
11 11 #include <Data/AcquisitionDataPacket.h>
12 12 #include <Data/IDataSeries.h>
13 13 #include <Data/SqpRange.h>
14 14
15 15 #include <QLoggingCategory>
16 16
17 17 #include <Common/spimpl.h>
18 18
19 19 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker)
20 20
21 21 class Variable;
22 22 class IDataProvider;
23 23
24 24 /// This class aims to handle all acquisition request
25 25 class SCIQLOP_CORE_EXPORT VariableAcquisitionWorker : public QObject {
26 26 Q_OBJECT
27 27 public:
28 28 explicit VariableAcquisitionWorker(QObject *parent = 0);
29 29 virtual ~VariableAcquisitionWorker();
30 30
31 31 QUuid pushVariableRequest(QUuid varRequestId, QUuid vIdentifier, SqpRange rangeRequested,
32 32 SqpRange cacheRangeRequested, DataProviderParameters parameters,
33 33 std::shared_ptr<IDataProvider> provider);
34 34
35 35 void abortProgressRequested(QUuid vIdentifier);
36 36
37 37 void initialize();
38 38 void finalize();
39 39 signals:
40 40 void dataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
41 41 const SqpRange &cacheRangeRequested,
42 42 QVector<AcquisitionDataPacket> dataAcquired);
43 43
44 44 void variableRequestInProgress(QUuid vIdentifier, double progress);
45 45
46 46 public slots:
47 47 void onVariableDataAcquired(QUuid acqIdentifier, std::shared_ptr<IDataSeries> dataSeries,
48 48 SqpRange dataRangeAcquired);
49 49 void onVariableRetrieveDataInProgress(QUuid acqIdentifier, double progress);
50 50
51 private slots:
52 void onExecuteRequest(QUuid acqIdentifier);
53
54 51 private:
55 52 void waitForFinish();
56 53
57 54 class VariableAcquisitionWorkerPrivate;
58 55 spimpl::unique_impl_ptr<VariableAcquisitionWorkerPrivate> impl;
56
57 private slots:
58 void onExecuteRequest(QUuid acqIdentifier);
59 59 };
60 60
61 61 #endif // SCIQLOP_VARIABLEACQUISITIONWORKER_H
@@ -1,248 +1,279
1 1 #include "Variable/Variable.h"
2 2
3 3 #include <Data/IDataSeries.h>
4 4 #include <Data/SqpRange.h>
5 5
6 6 #include <QMutex>
7 7 #include <QReadWriteLock>
8 8 #include <QThread>
9 9
10 10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11 11
12 12 struct Variable::VariablePrivate {
13 13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
14 14 const QVariantHash &metadata)
15 : m_Name{name}, m_Range{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
15 : m_Name{name},
16 m_Range{dateTime},
17 m_Metadata{metadata},
18 m_DataSeries{nullptr},
19 m_RealRange{INVALID_RANGE}
16 20 {
17 21 }
18 22
19 23 void lockRead() { m_Lock.lockForRead(); }
20 24 void lockWrite() { m_Lock.lockForWrite(); }
21 25 void unlock() { m_Lock.unlock(); }
22 26
27 /// Updates real range according to current variable range and data series
28 void updateRealRange()
29 {
30 if (m_DataSeries) {
31 m_DataSeries->lockRead();
32 auto end = m_DataSeries->cend();
33 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
34 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
35
36 m_RealRange = (minXAxisIt != end && maxXAxisIt != end)
37 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
38 : INVALID_RANGE;
39 m_DataSeries->unlock();
40 }
41 else {
42 m_RealRange = INVALID_RANGE;
43 }
44 }
45
23 46 QString m_Name;
24 47
25 48 SqpRange m_Range;
26 49 SqpRange m_CacheRange;
27 50 QVariantHash m_Metadata;
28 51 std::shared_ptr<IDataSeries> m_DataSeries;
52 SqpRange m_RealRange;
29 53
30 54 QReadWriteLock m_Lock;
31 55 };
32 56
33 57 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
34 58 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
35 59 {
36 60 }
37 61
38 62 QString Variable::name() const noexcept
39 63 {
40 64 impl->lockRead();
41 65 auto name = impl->m_Name;
42 66 impl->unlock();
43 67 return name;
44 68 }
45 69
46 70 SqpRange Variable::range() const noexcept
47 71 {
48 72 impl->lockRead();
49 73 auto range = impl->m_Range;
50 74 impl->unlock();
51 75 return range;
52 76 }
53 77
54 78 void Variable::setRange(const SqpRange &range) noexcept
55 79 {
56 80 impl->lockWrite();
57 81 impl->m_Range = range;
82 impl->updateRealRange();
58 83 impl->unlock();
59 84 }
60 85
61 86 SqpRange Variable::cacheRange() const noexcept
62 87 {
63 88 impl->lockRead();
64 89 auto cacheRange = impl->m_CacheRange;
65 90 impl->unlock();
66 91 return cacheRange;
67 92 }
68 93
69 94 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
70 95 {
71 96 impl->lockWrite();
72 97 impl->m_CacheRange = cacheRange;
73 98 impl->unlock();
74 99 }
75 100
101 SqpRange Variable::realRange() const noexcept
102 {
103 return impl->m_RealRange;
104 }
105
76 106 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
77 107 {
78 108 qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries"
79 109 << QThread::currentThread()->objectName();
80 110 if (!dataSeries) {
81 111 /// @todo ALX : log
82 112 return;
83 113 }
84 114 impl->lockWrite();
85 115 impl->m_DataSeries = dataSeries->clone();
116 impl->updateRealRange();
86 117 impl->unlock();
87 118 }
88 119
89 120 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
90 121 {
91 122 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
92 123 << QThread::currentThread()->objectName();
93 124 if (!dataSeries) {
94 125 /// @todo ALX : log
95 126 return;
96 127 }
97 128
98 129 // Add or merge the data
99 130 // Inits the data series of the variable
100 131 impl->lockWrite();
101 132 if (!impl->m_DataSeries) {
102 133 impl->m_DataSeries = dataSeries->clone();
103 134 }
104 135 else {
105 136 impl->m_DataSeries->merge(dataSeries.get());
106 137 }
107 138 impl->unlock();
108 139
109 140 // sub the data
110 141 auto subData = this->dataSeries()->subDataSeries(this->cacheRange());
111 142 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range();
112 143 this->setDataSeries(subData);
113 144 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries set" << this->dataSeries()->range();
114 145 }
115 146
116 147 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
117 148 {
118 149 impl->lockRead();
119 150 auto dataSeries = impl->m_DataSeries;
120 151 impl->unlock();
121 152
122 153 return dataSeries;
123 154 }
124 155
125 156 QVariantHash Variable::metadata() const noexcept
126 157 {
127 158 impl->lockRead();
128 159 auto metadata = impl->m_Metadata;
129 160 impl->unlock();
130 161 return metadata;
131 162 }
132 163
133 164 bool Variable::contains(const SqpRange &range) const noexcept
134 165 {
135 166 impl->lockRead();
136 167 auto res = impl->m_Range.contains(range);
137 168 impl->unlock();
138 169 return res;
139 170 }
140 171
141 172 bool Variable::intersect(const SqpRange &range) const noexcept
142 173 {
143 174
144 175 impl->lockRead();
145 176 auto res = impl->m_Range.intersect(range);
146 177 impl->unlock();
147 178 return res;
148 179 }
149 180
150 181 bool Variable::isInside(const SqpRange &range) const noexcept
151 182 {
152 183 impl->lockRead();
153 184 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
154 185 impl->unlock();
155 186 return res;
156 187 }
157 188
158 189 bool Variable::cacheContains(const SqpRange &range) const noexcept
159 190 {
160 191 impl->lockRead();
161 192 auto res = impl->m_CacheRange.contains(range);
162 193 impl->unlock();
163 194 return res;
164 195 }
165 196
166 197 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
167 198 {
168 199 impl->lockRead();
169 200 auto res = impl->m_CacheRange.intersect(range);
170 201 impl->unlock();
171 202 return res;
172 203 }
173 204
174 205 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
175 206 {
176 207 impl->lockRead();
177 208 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
178 209 impl->unlock();
179 210 return res;
180 211 }
181 212
182 213
183 214 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
184 215 {
185 216 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
186 217
187 218 auto notInCache = QVector<SqpRange>{};
188 219
189 220 if (!this->cacheContains(range)) {
190 221 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
191 222 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
192 223 notInCache << range;
193 224 }
194 225 else if (range.m_TStart < impl->m_CacheRange.m_TStart
195 226 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
196 227 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
197 228 }
198 229 else if (range.m_TStart < impl->m_CacheRange.m_TStart
199 230 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
200 231 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
201 232 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
202 233 }
203 234 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
204 235 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
205 236 }
206 237 else {
207 238 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
208 239 << QThread::currentThread();
209 240 }
210 241 }
211 242
212 243 return notInCache;
213 244 }
214 245
215 246 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
216 247 {
217 248 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
218 249
219 250 auto inCache = QVector<SqpRange>{};
220 251
221 252
222 253 if (this->intersect(range)) {
223 254 if (range.m_TStart <= impl->m_CacheRange.m_TStart
224 255 && range.m_TEnd >= impl->m_CacheRange.m_TStart
225 256 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
226 257 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
227 258 }
228 259
229 260 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
230 261 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
231 262 inCache << range;
232 263 }
233 264 else if (range.m_TStart > impl->m_CacheRange.m_TStart
234 265 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
235 266 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
236 267 }
237 268 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
238 269 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
239 270 inCache << impl->m_CacheRange;
240 271 }
241 272 else {
242 273 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
243 274 << QThread::currentThread();
244 275 }
245 276 }
246 277
247 278 return inCache;
248 279 }
@@ -1,238 +1,238
1 1 #include "Variable/VariableAcquisitionWorker.h"
2 2
3 3 #include "Variable/Variable.h"
4 4
5 5 #include <Data/AcquisitionRequest.h>
6 6 #include <Data/SqpRange.h>
7 7
8 8 #include <unordered_map>
9 9 #include <utility>
10 10
11 11 #include <QMutex>
12 12 #include <QReadWriteLock>
13 13 #include <QThread>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
16 16
17 17 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
18 18
19 19 explicit VariableAcquisitionWorkerPrivate() : m_Lock{QReadWriteLock::Recursive} {}
20 20
21 21 void lockRead() { m_Lock.lockForRead(); }
22 22 void lockWrite() { m_Lock.lockForWrite(); }
23 23 void unlock() { m_Lock.unlock(); }
24 24
25 25 void removeVariableRequest(QUuid vIdentifier);
26 26
27 27 QMutex m_WorkingMutex;
28 28 QReadWriteLock m_Lock;
29 29
30 30 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
31 31 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
32 32 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
33 33 };
34 34
35 35
36 36 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
37 37 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>()}
38 38 {
39 39 }
40 40
41 41 VariableAcquisitionWorker::~VariableAcquisitionWorker()
42 42 {
43 43 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
44 44 << QThread::currentThread();
45 45 this->waitForFinish();
46 46 }
47 47
48 48
49 49 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
50 50 SqpRange rangeRequested,
51 51 SqpRange cacheRangeRequested,
52 52 DataProviderParameters parameters,
53 53 std::shared_ptr<IDataProvider> provider)
54 54 {
55 55 qCDebug(LOG_VariableAcquisitionWorker())
56 56 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
57 57 auto varRequestIdCanceled = QUuid();
58 58
59 59 // Request creation
60 60 auto acqRequest = AcquisitionRequest{};
61 61 acqRequest.m_VarRequestId = varRequestId;
62 62 acqRequest.m_vIdentifier = vIdentifier;
63 63 acqRequest.m_DataProviderParameters = parameters;
64 64 acqRequest.m_RangeRequested = rangeRequested;
65 65 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
66 66 acqRequest.m_Size = parameters.m_Times.size();
67 67 acqRequest.m_Provider = provider;
68 68
69 69
70 70 // Register request
71 71 impl->lockWrite();
72 72 impl->m_AcqIdentifierToAcqRequestMap.insert(
73 73 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
74 74
75 75 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
76 76 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
77 77 // A current request already exists, we can replace the next one
78 78 auto nextAcqId = it->second.second;
79 79 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(nextAcqId);
80 80 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
81 81 auto request = acqIdentifierToAcqRequestMapIt->second;
82 82 varRequestIdCanceled = request.m_VarRequestId;
83 83 }
84 84
85 85 it->second.second = acqRequest.m_AcqIdentifier;
86 86 impl->unlock();
87 87 }
88 88 else {
89 89 // First request for the variable, it must be stored and executed
90 90 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
91 91 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
92 92 impl->unlock();
93 93
94 94 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
95 95 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
96 96 }
97 97
98 98 return varRequestIdCanceled;
99 99 }
100 100
101 101 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
102 102 {
103 103 // TODO
104 104 }
105 105
106 106 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
107 107 double progress)
108 108 {
109 109 // TODO
110 110 }
111 111
112 112 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
113 113 std::shared_ptr<IDataSeries> dataSeries,
114 114 SqpRange dataRangeAcquired)
115 115 {
116 116 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableDataAcquired on range ")
117 117 << acqIdentifier << dataRangeAcquired;
118 118 impl->lockWrite();
119 119 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
120 120 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
121 121 // Store the result
122 122 auto dataPacket = AcquisitionDataPacket{};
123 123 dataPacket.m_Range = dataRangeAcquired;
124 124 dataPacket.m_DateSeries = dataSeries;
125 125
126 126 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
127 127 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
128 128 // A current request result already exists, we can update it
129 129 aIdToADPVit->second.push_back(dataPacket);
130 130 }
131 131 else {
132 132 // First request result for the variable, it must be stored
133 133 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
134 134 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
135 135 }
136 136
137 137
138 138 // Decrement the counter of the request
139 139 auto &acqRequest = aIdToARit->second;
140 140 acqRequest.m_Size = acqRequest.m_Size - 1;
141 141
142 142 // if the counter is 0, we can return data then run the next request if it exists and
143 143 // removed the finished request
144 144 if (acqRequest.m_Size == 0) {
145 145 // Return the data
146 146 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
147 147 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
148 148 emit dataProvided(acqRequest.m_vIdentifier, acqRequest.m_RangeRequested,
149 149 acqRequest.m_CacheRangeRequested, aIdToADPVit->second);
150 150 }
151 151
152 152 // Execute the next one
153 153 auto it
154 154 = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(acqRequest.m_vIdentifier);
155 155
156 156 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
157 157 if (it->second.second.isNull()) {
158 158 // There is no next request, we can remove the variable request
159 159 impl->removeVariableRequest(acqRequest.m_vIdentifier);
160 160 }
161 161 else {
162 162 auto acqIdentifierToRemove = it->second.first;
163 163 // Move the next request to the current request
164 164 it->second.first = it->second.second;
165 165 it->second.second = QUuid();
166 166 // Remove AcquisitionRequest and results;
167 167 impl->m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
168 168 impl->m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
169 169 // Execute the current request
170 170 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
171 171 Q_ARG(QUuid, it->second.first));
172 172 }
173 173 }
174 174 else {
175 175 qCCritical(LOG_VariableAcquisitionWorker())
176 176 << tr("Impossible to execute the acquisition on an unfound variable ");
177 177 }
178 178 }
179 179 }
180 180 else {
181 181 qCCritical(LOG_VariableAcquisitionWorker())
182 182 << tr("Impossible to retrieve AcquisitionRequest for the incoming data");
183 183 }
184 184 impl->unlock();
185 185 }
186 186
187 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
188 {
189 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
190 impl->lockRead();
191 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
192 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
193 auto request = it->second;
194 impl->unlock();
195 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
196 }
197 else {
198 impl->unlock();
199 // TODO log no acqIdentifier recognized
200 }
201 }
202
203 187 void VariableAcquisitionWorker::initialize()
204 188 {
205 189 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
206 190 << QThread::currentThread();
207 191 impl->m_WorkingMutex.lock();
208 192 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
209 193 }
210 194
211 195 void VariableAcquisitionWorker::finalize()
212 196 {
213 197 impl->m_WorkingMutex.unlock();
214 198 }
215 199
216 200 void VariableAcquisitionWorker::waitForFinish()
217 201 {
218 202 QMutexLocker locker{&impl->m_WorkingMutex};
219 203 }
220 204
221 205 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
222 206 QUuid vIdentifier)
223 207 {
224 208 lockWrite();
225 209 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
226 210
227 211 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
228 212 // A current request already exists, we can replace the next one
229 213
230 214 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
231 215 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
232 216
233 217 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
234 218 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
235 219 }
236 220 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
237 221 unlock();
238 222 }
223
224 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
225 {
226 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
227 impl->lockRead();
228 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
229 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
230 auto request = it->second;
231 impl->unlock();
232 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
233 }
234 else {
235 impl->unlock();
236 // TODO log no acqIdentifier recognized
237 }
238 }
@@ -1,274 +1,260
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableModel.h>
3 3
4 4 #include <Common/DateUtils.h>
5 5
6 6 #include <Data/IDataSeries.h>
7 7
8 8 #include <QSize>
9 9 #include <unordered_map>
10 10
11 11 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
12 12
13 13 namespace {
14 14
15 15 // Column indexes
16 16 const auto NAME_COLUMN = 0;
17 17 const auto TSTART_COLUMN = 1;
18 18 const auto TEND_COLUMN = 2;
19 19 const auto UNIT_COLUMN = 3;
20 20 const auto MISSION_COLUMN = 4;
21 21 const auto PLUGIN_COLUMN = 5;
22 22 const auto NB_COLUMNS = 6;
23 23
24 24 // Column properties
25 25 const auto DEFAULT_HEIGHT = 25;
26 26 const auto DEFAULT_WIDTH = 100;
27 27
28 28 struct ColumnProperties {
29 29 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
30 30 int height = DEFAULT_HEIGHT)
31 31 : m_Name{name}, m_Width{width}, m_Height{height}
32 32 {
33 33 }
34 34
35 35 QString m_Name;
36 36 int m_Width;
37 37 int m_Height;
38 38 };
39 39
40 40 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
41 41 {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
42 42 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {UNIT_COLUMN, {QObject::tr("Unit")}},
43 43 {MISSION_COLUMN, {QObject::tr("Mission")}}, {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
44 44
45 45 /// Format for datetimes
46 46 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
47 47
48 48
49 49 } // namespace
50 50
51 51 struct VariableModel::VariableModelPrivate {
52 52 /// Variables created in SciQlop
53 53 std::vector<std::shared_ptr<Variable> > m_Variables;
54 54 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
55 55
56 56 /// Return the row index of the variable. -1 if it's not found
57 57 int indexOfVariable(Variable *variable) const noexcept;
58 58 };
59 59
60 60 VariableModel::VariableModel(QObject *parent)
61 61 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
62 62 {
63 63 }
64 64
65 65 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
66 66 const SqpRange &dateTime,
67 67 const QVariantHash &metadata) noexcept
68 68 {
69 69 auto insertIndex = rowCount();
70 70 beginInsertRows({}, insertIndex, insertIndex);
71 71
72 72 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
73 73
74 74 impl->m_Variables.push_back(variable);
75 75 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
76 76
77 77 endInsertRows();
78 78
79 79 return variable;
80 80 }
81 81
82 82 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
83 83 {
84 84 if (!variable) {
85 85 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
86 86 return;
87 87 }
88 88
89 89 // Finds variable in the model
90 90 auto begin = impl->m_Variables.cbegin();
91 91 auto end = impl->m_Variables.cend();
92 92 auto it = std::find(begin, end, variable);
93 93 if (it != end) {
94 94 auto removeIndex = std::distance(begin, it);
95 95
96 96 // Deletes variable
97 97 beginRemoveRows({}, removeIndex, removeIndex);
98 98 impl->m_Variables.erase(it);
99 99 endRemoveRows();
100 100 }
101 101 else {
102 102 qCritical(LOG_VariableModel())
103 103 << tr("Can't delete variable %1 from the model: the variable is not in the model")
104 104 .arg(variable->name());
105 105 }
106 106
107 107 // Removes variable from progress map
108 108 impl->m_VariableToProgress.erase(variable);
109 109 }
110 110
111 111
112 112 std::shared_ptr<Variable> VariableModel::variable(int index) const
113 113 {
114 114 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
115 115 }
116 116
117 117 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
118 118 {
119 119 if (progress > 0.0) {
120 120 impl->m_VariableToProgress[variable] = progress;
121 121 }
122 122 else {
123 123 impl->m_VariableToProgress.erase(variable);
124 124 }
125 125 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
126 126
127 127 emit dataChanged(modelIndex, modelIndex);
128 128 }
129 129
130 130 int VariableModel::columnCount(const QModelIndex &parent) const
131 131 {
132 132 Q_UNUSED(parent);
133 133
134 134 return NB_COLUMNS;
135 135 }
136 136
137 137 int VariableModel::rowCount(const QModelIndex &parent) const
138 138 {
139 139 Q_UNUSED(parent);
140 140
141 141 return impl->m_Variables.size();
142 142 }
143 143
144 144 QVariant VariableModel::data(const QModelIndex &index, int role) const
145 145 {
146 146 if (!index.isValid()) {
147 147 return QVariant{};
148 148 }
149 149
150 150 if (index.row() < 0 || index.row() >= rowCount()) {
151 151 return QVariant{};
152 152 }
153 153
154 154 if (role == Qt::DisplayRole) {
155 155 if (auto variable = impl->m_Variables.at(index.row()).get()) {
156 /// Lambda function that builds the variant to return for a time value
157 /// @param getValueFun function used to get for a data series the iterator on the entry
158 /// that contains the time value to display
159 auto dateTimeVariant = [variable](const auto &getValueFun) {
160 if (auto dataSeries = variable->dataSeries()) {
161 dataSeries->lockRead();
162 auto it = getValueFun(*dataSeries);
163 auto resVariant = (it != dataSeries->cend())
164 ? DateUtils::dateTime(it->x()).toString(DATETIME_FORMAT)
165 : QVariant{};
166 dataSeries->unlock();
167 return resVariant;
168 }
169 else {
170 return QVariant{};
171 }
172 };
173
174 156 switch (index.column()) {
175 157 case NAME_COLUMN:
176 158 return variable->name();
177 case TSTART_COLUMN:
178 // Shows the min value of the data series above the range tstart
179 return dateTimeVariant([min = variable->range().m_TStart](
180 const auto &dataSeries) { return dataSeries.minXAxisData(min); });
181 case TEND_COLUMN:
182 // Shows the max value of the data series under the range tend
183 return dateTimeVariant([max = variable->range().m_TEnd](
184 const auto &dataSeries) { return dataSeries.maxXAxisData(max); });
159 case TSTART_COLUMN: {
160 auto range = variable->realRange();
161 return range != INVALID_RANGE
162 ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT)
163 : QVariant{};
164 }
165 case TEND_COLUMN: {
166 auto range = variable->realRange();
167 return range != INVALID_RANGE
168 ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT)
169 : QVariant{};
170 }
185 171 case UNIT_COLUMN:
186 172 return variable->metadata().value(QStringLiteral("units"));
187 173 case MISSION_COLUMN:
188 174 return variable->metadata().value(QStringLiteral("mission"));
189 175 case PLUGIN_COLUMN:
190 176 return variable->metadata().value(QStringLiteral("plugin"));
191 177 default:
192 178 // No action
193 179 break;
194 180 }
195 181
196 182 qWarning(LOG_VariableModel())
197 183 << tr("Can't get data (unknown column %1)").arg(index.column());
198 184 }
199 185 else {
200 186 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
201 187 }
202 188 }
203 189 else if (role == VariableRoles::ProgressRole) {
204 190 if (auto variable = impl->m_Variables.at(index.row())) {
205 191
206 192 auto it = impl->m_VariableToProgress.find(variable);
207 193 if (it != impl->m_VariableToProgress.cend()) {
208 194 return it->second;
209 195 }
210 196 }
211 197 }
212 198
213 199 return QVariant{};
214 200 }
215 201
216 202 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
217 203 {
218 204 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
219 205 return QVariant{};
220 206 }
221 207
222 208 if (orientation == Qt::Horizontal) {
223 209 auto propertiesIt = COLUMN_PROPERTIES.find(section);
224 210 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
225 211 // Role is either DisplayRole or SizeHintRole
226 212 return (role == Qt::DisplayRole)
227 213 ? QVariant{propertiesIt->m_Name}
228 214 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
229 215 }
230 216 else {
231 217 qWarning(LOG_VariableModel())
232 218 << tr("Can't get header data (unknown column %1)").arg(section);
233 219 }
234 220 }
235 221
236 222 return QVariant{};
237 223 }
238 224
239 225 void VariableModel::abortProgress(const QModelIndex &index)
240 226 {
241 227 if (auto variable = impl->m_Variables.at(index.row())) {
242 228 emit abortProgessRequested(variable);
243 229 }
244 230 }
245 231
246 232 void VariableModel::onVariableUpdated() noexcept
247 233 {
248 234 // Finds variable that has been updated in the model
249 235 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
250 236 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
251 237
252 238 if (updatedVariableIndex > -1) {
253 239 emit dataChanged(createIndex(updatedVariableIndex, 0),
254 240 createIndex(updatedVariableIndex, columnCount() - 1));
255 241 }
256 242 }
257 243 }
258 244
259 245 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
260 246 {
261 247 auto begin = std::cbegin(m_Variables);
262 248 auto end = std::cend(m_Variables);
263 249 auto it
264 250 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
265 251
266 252 if (it != end) {
267 253 // Gets the index of the variable in the model: we assume here that views have the same
268 254 // order as the model
269 255 return std::distance(begin, it);
270 256 }
271 257 else {
272 258 return -1;
273 259 }
274 260 }
@@ -1,52 +1,39
1 1 # On ignore toutes les règles vera++ pour le fichier spimpl
2 2 Common/spimpl\.h:\d+:.*
3 3
4 4 # Ignore false positive relative to two class definitions in a same file
5 ArrayData\.h:\d+:.*IPSIS_S01.*
6 ArrayDataIterator\.h:\d+:.*IPSIS_S01.*
5 7 DataSourceItem\.h:\d+:.*IPSIS_S01.*
6 8 DataSeries\.h:\d+:.*IPSIS_S01.*
7 9 DataSeriesIterator\.h:\d+:.*IPSIS_S01.*
8 10
9 11 # Ignore false positive relative to a template class
10 12 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (D)
11 13 ArrayData\.h:\d+:.*IPSIS_S04_NAMESPACE.*found: (arraydata_detail)
12 14 ArrayData\.h:\d+:.*IPSIS_S06.*found: (D)
13 15 ArrayData\.h:\d+:.*IPSIS_S06.*found: (Dim)
14 16 DataSeries\.h:\d+:.*IPSIS_S04_METHOD.*found: LOG_DataSeries
15 17 DataSeries\.h:\d+:.*IPSIS_S04_VARIABLE.*
16 18 DataSeries\.h:\d+:.*IPSIS_S04_NAMESPACE.*found: (dataseries_detail)
17 19
18 20 # Ignore false positive relative to iterators
19 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (forward_iterator_tag)
20 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (IteratorValue)
21 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (ptrdiff_t)
22 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (value_type)
23 ArrayData\.h:\d+:.*IPSIS_S05.*
24 ArrayData\.h:\d+:.*IPSIS_S06.*found: (iterator_category)
25 ArrayData\.h:\d+:.*IPSIS_S06.*found: (forward_iterator_tag)
26 ArrayData\.h:\d+:.*IPSIS_S06.*found: (value_type)
27 ArrayData\.h:\d+:.*IPSIS_S06.*found: (IteratorValue)
28 ArrayData\.h:\d+:.*IPSIS_S06.*found: (difference_type)
29 ArrayData\.h:\d+:.*IPSIS_S06.*found: (ptrdiff_t)
30 ArrayData\.h:\d+:.*IPSIS_S06.*found: (pointer)
31 ArrayData\.h:\d+:.*IPSIS_S06.*found: (reference)
32 ArrayData\.h:\d+:.*IPSIS_S06.*found: (value_type)
33 DataSeriesIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (forward_iterator_tag)
34 DataSeriesIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (DataSeriesIteratorValue)
35 DataSeriesIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (ptrdiff_t)
36 DataSeriesIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (value_type)
37 DataSeriesIterator\.h:\d+:.*IPSIS_S05.*
38 DataSeriesIterator\.h:\d+:.*IPSIS_S06.*found: (iterator_category)
39 DataSeriesIterator\.h:\d+:.*IPSIS_S06.*found: (forward_iterator_tag)
40 DataSeriesIterator\.h:\d+:.*IPSIS_S06.*found: (value_type)
41 DataSeriesIterator\.h:\d+:.*IPSIS_S06.*found: (DataSeriesIteratorValue)
42 DataSeriesIterator\.h:\d+:.*IPSIS_S06.*found: (difference_type)
43 DataSeriesIterator\.h:\d+:.*IPSIS_S06.*found: (ptrdiff_t)
44 DataSeriesIterator\.h:\d+:.*IPSIS_S06.*found: (pointer)
45 DataSeriesIterator\.h:\d+:.*IPSIS_S06.*found: (reference)
46 DataSeriesIterator\.h:\d+:.*IPSIS_S06.*found: (value_type)
21 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (forward_iterator_tag)
22 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (T)
23 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (ptrdiff_t)
24 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (value_type)
25 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (iterator_category)
26 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (forward_iterator_tag)
27 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (value_type)
28 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (T)
29 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (difference_type)
30 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (ptrdiff_t)
31 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (pointer)
32 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (reference)
33 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (value_type)
47 34
48 35 # Ignore false positive relative to an alias
49 36 DataSourceItemAction\.h:\d+:.*IPSIS_S06.*found: (ExecuteFunction)
50 37
51 38 # Ignore false positive relative to unnamed namespace
52 39 VariableController\.cpp:\d+:.*IPSIS_F13.*
@@ -1,56 +1,55
1 1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
14 14
15 15 namespace Ui {
16 16 class VisualizationZoneWidget;
17 17 } // Ui
18 18
19 19 class Variable;
20 20 class VisualizationGraphWidget;
21 21
22 22 class VisualizationZoneWidget : public QWidget, public IVisualizationWidget {
23 23 Q_OBJECT
24 24
25 25 public:
26 26 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
27 27 virtual ~VisualizationZoneWidget();
28 28
29 29 /// Add a graph widget
30 30 void addGraph(VisualizationGraphWidget *graphWidget);
31 31
32 32 /**
33 33 * Creates a graph using a variable. The variable will be displayed in the new graph.
34 34 * @param variable the variable for which to create the graph
35 35 * @return the pointer to the created graph
36 36 */
37 37 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
38 38
39 39 // IVisualizationWidget interface
40 40 void accept(IVisualizationWidgetVisitor *visitor) override;
41 41 bool canDrop(const Variable &variable) const override;
42 42 bool contains(const Variable &variable) const override;
43 43 QString name() const override;
44 44
45
46 private slots:
47 void onVariableAdded(std::shared_ptr<Variable> variable);
48
49 45 private:
50 46 Ui::VisualizationZoneWidget *ui;
51 47
52 48 class VisualizationZoneWidgetPrivate;
53 49 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
50
51 private slots:
52 void onVariableAdded(std::shared_ptr<Variable> variable);
54 53 };
55 54
56 55 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,100 +1,100
1 1 #include <DataSource/DataSourceWidget.h>
2 2
3 3 #include <ui_DataSourceWidget.h>
4 4
5 5 #include <DataSource/DataSourceItem.h>
6 6 #include <DataSource/DataSourceTreeWidgetHelper.h>
7 7 #include <DataSource/DataSourceTreeWidgetItem.h>
8 8
9 9 #include <QMenu>
10 10
11 11 namespace {
12 12
13 13 /// Number of columns displayed in the tree
14 14 const auto TREE_NB_COLUMNS = 1;
15 15
16 16 /// Header labels for the tree
17 17 const auto TREE_HEADER_LABELS = QStringList{QObject::tr("Name")};
18 18
19 19 /**
20 20 * Creates the item associated to a data source
21 21 * @param dataSource the data source for which to create the item
22 22 * @return the new item
23 23 */
24 24 DataSourceTreeWidgetItem *createTreeWidgetItem(DataSourceItem *dataSource)
25 25 {
26 26 // Creates item for the data source
27 27 auto item = new DataSourceTreeWidgetItem{dataSource};
28 28
29 29 // Generates items for the children of the data source
30 30 for (auto i = 0; i < dataSource->childCount(); ++i) {
31 31 item->addChild(createTreeWidgetItem(dataSource->child(i)));
32 32 }
33 33
34 34 return item;
35 35 }
36 36
37 37 } // namespace
38 38
39 39 DataSourceWidget::DataSourceWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::DataSourceWidget}
40 40 {
41 41 ui->setupUi(this);
42 42
43 43 // Set tree properties
44 44 ui->treeWidget->setColumnCount(TREE_NB_COLUMNS);
45 45 ui->treeWidget->setHeaderLabels(TREE_HEADER_LABELS);
46 46 ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
47 47
48 48 // Connection to show a menu when right clicking on the tree
49 49 connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this,
50 50 &DataSourceWidget::onTreeMenuRequested);
51 51
52 52 // Connection to filter tree
53 53 connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &DataSourceWidget::filterChanged);
54 54 }
55 55
56 56 DataSourceWidget::~DataSourceWidget() noexcept
57 57 {
58 58 delete ui;
59 59 }
60 60
61 61 void DataSourceWidget::addDataSource(DataSourceItem *dataSource) noexcept
62 62 {
63 63 // Creates the item associated to the source and adds it to the tree widget. The tree widget
64 64 // takes the ownership of the item
65 65 if (dataSource) {
66 66 ui->treeWidget->addTopLevelItem(createTreeWidgetItem(dataSource));
67 67 }
68 68 }
69 69
70 70 void DataSourceWidget::filterChanged(const QString &text) noexcept
71 71 {
72 72 auto validateItem = [&text](const DataSourceTreeWidgetItem &item) {
73 73 auto regExp = QRegExp{text, Qt::CaseInsensitive, QRegExp::Wildcard};
74 74
75 75 // An item is valid if any of its metadata validates the text filter
76 76 auto itemMetadata = item.data()->data();
77 77 auto itemMetadataEnd = itemMetadata.cend();
78 78 auto acceptFilter
79 79 = [&regExp](const auto &variant) { return variant.toString().contains(regExp); };
80 80
81 81 return std::find_if(itemMetadata.cbegin(), itemMetadataEnd, acceptFilter)
82 82 != itemMetadataEnd;
83 83 };
84 84
85 85 // Applies filter on tree widget
86 86 DataSourceTreeWidgetHelper::filter(*ui->treeWidget, validateItem);
87 87 }
88 88
89 89 void DataSourceWidget::onTreeMenuRequested(const QPoint &pos) noexcept
90 90 {
91 91 // Retrieves the selected item in the tree, and build the menu from its actions
92 92 if (auto selectedItem = dynamic_cast<DataSourceTreeWidgetItem *>(ui->treeWidget->itemAt(pos))) {
93 93 QMenu treeMenu{};
94 94 treeMenu.addActions(selectedItem->actions());
95 95
96 96 if (!treeMenu.isEmpty()) {
97 treeMenu.exec(mapToGlobal(pos));
97 treeMenu.exec(QCursor::pos());
98 98 }
99 99 }
100 100 }
@@ -1,45 +1,51
1 1 #include "Settings/SqpSettingsGeneralWidget.h"
2 2
3 3 #include "Settings/SqpSettingsDefs.h"
4 4
5 5 #include "ui_SqpSettingsGeneralWidget.h"
6 6
7 7 SqpSettingsGeneralWidget::SqpSettingsGeneralWidget(QWidget *parent)
8 8 : QWidget{parent}, ui{new Ui::SqpSettingsGeneralWidget}
9 9 {
10 10 ui->setupUi(this);
11
12 // Value limits
13 ui->toleranceInitSpinBox->setMinimum(0.);
14 ui->toleranceInitSpinBox->setMaximum(std::numeric_limits<double>::max());
15 ui->toleranceUpdateSpinBox->setMinimum(0.);
16 ui->toleranceUpdateSpinBox->setMaximum(std::numeric_limits<double>::max());
11 17 }
12 18
13 19 SqpSettingsGeneralWidget::~SqpSettingsGeneralWidget() noexcept
14 20 {
15 21 delete ui;
16 22 }
17 23
18 24 void SqpSettingsGeneralWidget::loadSettings()
19 25 {
20 26 QSettings settings{};
21 27
22 28 auto loadTolerance = [&settings](const QString &key, double defaultValue) {
23 29 // Tolerance is converted to percent
24 30 auto toleranceValue = settings.value(key, defaultValue).toDouble();
25 31 return toleranceValue * 100.;
26 32 };
27 33
28 34 ui->toleranceInitSpinBox->setValue(
29 35 loadTolerance(GENERAL_TOLERANCE_AT_INIT_KEY, GENERAL_TOLERANCE_AT_INIT_DEFAULT_VALUE));
30 36 ui->toleranceUpdateSpinBox->setValue(
31 37 loadTolerance(GENERAL_TOLERANCE_AT_UPDATE_KEY, GENERAL_TOLERANCE_AT_UPDATE_DEFAULT_VALUE));
32 38 }
33 39
34 40 void SqpSettingsGeneralWidget::saveSettings() const
35 41 {
36 42 QSettings settings{};
37 43
38 44 auto saveTolerance = [&settings](const QString &key, double value) {
39 45 // Tolerance is converted from percent
40 46 settings.setValue(key, value * 0.01);
41 47 };
42 48
43 49 saveTolerance(GENERAL_TOLERANCE_AT_INIT_KEY, ui->toleranceInitSpinBox->value());
44 50 saveTolerance(GENERAL_TOLERANCE_AT_UPDATE_KEY, ui->toleranceUpdateSpinBox->value());
45 51 }
@@ -1,199 +1,199
1 1 #include <Variable/VariableController.h>
2 2 #include <Variable/VariableInspectorWidget.h>
3 3 #include <Variable/VariableMenuHeaderWidget.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <ui_VariableInspectorWidget.h>
7 7
8 8 #include <QMouseEvent>
9 9 #include <QSortFilterProxyModel>
10 10 #include <QStyledItemDelegate>
11 11 #include <QWidgetAction>
12 12
13 13 #include <SqpApplication.h>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
16 16
17 17
18 18 class QProgressBarItemDelegate : public QStyledItemDelegate {
19 19
20 20 public:
21 21 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
22 22
23 23 void paint(QPainter *painter, const QStyleOptionViewItem &option,
24 24 const QModelIndex &index) const
25 25 {
26 26 auto data = index.data(Qt::DisplayRole);
27 27 auto progressData = index.data(VariableRoles::ProgressRole);
28 28 if (data.isValid() && progressData.isValid()) {
29 29 auto name = data.value<QString>();
30 30 auto progress = progressData.value<double>();
31 31 if (progress > 0) {
32 32 auto cancelButtonWidth = 20;
33 33 auto progressBarOption = QStyleOptionProgressBar{};
34 34 auto progressRect = option.rect;
35 35 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
36 36 progressBarOption.rect = progressRect;
37 37 progressBarOption.minimum = 0;
38 38 progressBarOption.maximum = 100;
39 39 progressBarOption.progress = progress;
40 40 progressBarOption.text
41 41 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
42 42 progressBarOption.textVisible = true;
43 43 progressBarOption.textAlignment = Qt::AlignCenter;
44 44
45 45
46 46 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
47 47 painter);
48 48
49 49 // Cancel button
50 50 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
51 51 option.rect.height());
52 52 auto buttonOption = QStyleOptionButton{};
53 53 buttonOption.rect = buttonRect;
54 54 buttonOption.text = "X";
55 55
56 56 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
57 57 }
58 58 else {
59 59 QStyledItemDelegate::paint(painter, option, index);
60 60 }
61 61 }
62 62 else {
63 63 QStyledItemDelegate::paint(painter, option, index);
64 64 }
65 65 }
66 66
67 67 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
68 68 const QModelIndex &index)
69 69 {
70 70 if (event->type() == QEvent::MouseButtonRelease) {
71 71 auto data = index.data(Qt::DisplayRole);
72 72 auto progressData = index.data(VariableRoles::ProgressRole);
73 73 if (data.isValid() && progressData.isValid()) {
74 74 auto cancelButtonWidth = 20;
75 75 auto progressRect = option.rect;
76 76 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
77 77 // Cancel button
78 78 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
79 79 option.rect.height());
80 80
81 81 auto e = (QMouseEvent *)event;
82 82 auto clickX = e->x();
83 83 auto clickY = e->y();
84 84
85 85 auto x = buttonRect.left(); // the X coordinate
86 86 auto y = buttonRect.top(); // the Y coordinate
87 87 auto w = buttonRect.width(); // button width
88 88 auto h = buttonRect.height(); // button height
89 89
90 90 if (clickX > x && clickX < x + w) {
91 91 if (clickY > y && clickY < y + h) {
92 92 auto variableModel = sqpApp->variableController().variableModel();
93 93 variableModel->abortProgress(index);
94 94 }
95 95 }
96 96 else {
97 97 QStyledItemDelegate::editorEvent(event, model, option, index);
98 98 }
99 99 }
100 100 else {
101 101 QStyledItemDelegate::editorEvent(event, model, option, index);
102 102 }
103 103 }
104 104 else {
105 105 QStyledItemDelegate::editorEvent(event, model, option, index);
106 106 }
107 107 }
108 108 };
109 109
110 110 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
111 111 : QWidget{parent},
112 112 ui{new Ui::VariableInspectorWidget},
113 113 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
114 114 {
115 115 ui->setupUi(this);
116 116
117 117 // Sets model for table
118 118 // auto sortFilterModel = new QSortFilterProxyModel{this};
119 119 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
120 120
121 121 auto variableModel = sqpApp->variableController().variableModel();
122 122 ui->tableView->setModel(variableModel);
123 123
124 124 // Adds extra signal/slot between view and model, so the view can be updated instantly when
125 125 // there is a change of data in the model
126 126 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
127 127 SLOT(refresh()));
128 128
129 129 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
130 130 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
131 131
132 132 // Fixes column sizes
133 133 auto model = ui->tableView->model();
134 134 const auto count = model->columnCount();
135 135 for (auto i = 0; i < count; ++i) {
136 136 ui->tableView->setColumnWidth(
137 137 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
138 138 }
139 139
140 140 // Sets selection options
141 141 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
142 142 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
143 143
144 144 // Connection to show a menu when right clicking on the tree
145 145 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
146 146 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
147 147 &VariableInspectorWidget::onTableMenuRequested);
148 148 }
149 149
150 150 VariableInspectorWidget::~VariableInspectorWidget()
151 151 {
152 152 delete ui;
153 153 }
154 154
155 155 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
156 156 {
157 157 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
158 158
159 159 // Gets the model to retrieve the underlying selected variables
160 160 auto model = sqpApp->variableController().variableModel();
161 161 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
162 162 for (const auto &selectedRow : qAsConst(selectedRows)) {
163 163 if (auto selectedVariable = model->variable(selectedRow.row())) {
164 164 selectedVariables.push_back(selectedVariable);
165 165 }
166 166 }
167 167
168 168 QMenu tableMenu{};
169 169
170 170 // Emits a signal so that potential receivers can populate the menu before displaying it
171 171 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
172 172
173 173 // Adds menu-specific actions
174 174 if (!selectedVariables.isEmpty()) {
175 175 // 'Delete' action
176 176 auto deleteFun = [&selectedVariables]() {
177 177 sqpApp->variableController().deleteVariables(selectedVariables);
178 178 };
179 179
180 180 tableMenu.addSeparator();
181 181 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
182 182 }
183 183
184 184 if (!tableMenu.isEmpty()) {
185 185 // Generates menu header (inserted before first action)
186 186 auto firstAction = tableMenu.actions().first();
187 187 auto headerAction = new QWidgetAction{&tableMenu};
188 188 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
189 189 tableMenu.insertAction(firstAction, headerAction);
190 190
191 191 // Displays menu
192 tableMenu.exec(mapToGlobal(pos));
192 tableMenu.exec(QCursor::pos());
193 193 }
194 194 }
195 195
196 196 void VariableInspectorWidget::refresh() noexcept
197 197 {
198 198 ui->tableView->viewport()->update();
199 199 }
@@ -1,313 +1,313
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationDefs.h"
4 4 #include "Visualization/VisualizationGraphHelper.h"
5 5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 6 #include "ui_VisualizationGraphWidget.h"
7 7
8 8 #include <Data/ArrayData.h>
9 9 #include <Data/IDataSeries.h>
10 10 #include <Settings/SqpSettingsDefs.h>
11 11 #include <SqpApplication.h>
12 12 #include <Variable/Variable.h>
13 13 #include <Variable/VariableController.h>
14 14
15 15 #include <unordered_map>
16 16
17 17 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
18 18
19 19 namespace {
20 20
21 21 /// Key pressed to enable zoom on horizontal axis
22 22 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
23 23
24 24 /// Key pressed to enable zoom on vertical axis
25 25 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
26 26
27 27 } // namespace
28 28
29 29 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
30 30
31 31 explicit VisualizationGraphWidgetPrivate()
32 32 : m_DoAcquisition{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
33 33 {
34 34 }
35 35
36 36 // 1 variable -> n qcpplot
37 37 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
38 38 bool m_DoAcquisition;
39 39 bool m_IsCalibration;
40 40 QCPItemTracer *m_TextTracer;
41 41 /// Delegate used to attach rendering features to the plot
42 42 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
43 43 };
44 44
45 45 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
46 46 : QWidget{parent},
47 47 ui{new Ui::VisualizationGraphWidget},
48 48 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
49 49 {
50 50 ui->setupUi(this);
51 51
52 52 // The delegate must be initialized after the ui as it uses the plot
53 53 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*ui->widget);
54 54
55 55 ui->graphNameLabel->setText(name);
56 56
57 57 // 'Close' options : widget is deleted when closed
58 58 setAttribute(Qt::WA_DeleteOnClose);
59 59 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
60 60 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
61 61
62 62 // Set qcpplot properties :
63 63 // - Drag (on x-axis) and zoom are enabled
64 64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
65 65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
66 66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
67 67
68 68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
69 69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
70 70 &VisualizationGraphWidget::onMouseRelease);
71 71 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
72 72 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
73 73 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
74 74 &QCPAxis::rangeChanged),
75 75 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
76 76
77 77 // Activates menu when right clicking on the graph
78 78 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
79 79 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
80 80 &VisualizationGraphWidget::onGraphMenuRequested);
81 81
82 82 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
83 83 &VariableController::onRequestDataLoading);
84 84
85 85 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
86 86 &VisualizationGraphWidget::onUpdateVarDisplaying);
87 87 }
88 88
89 89
90 90 VisualizationGraphWidget::~VisualizationGraphWidget()
91 91 {
92 92 delete ui;
93 93 }
94 94
95 95 void VisualizationGraphWidget::enableAcquisition(bool enable)
96 96 {
97 97 impl->m_DoAcquisition = enable;
98 98 }
99 99
100 100 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
101 101 {
102 102 // Uses delegate to create the qcpplot components according to the variable
103 103 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
104 104 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
105 105
106 106 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
107 107
108 108 auto varRange = variable->range();
109 109
110 110 this->enableAcquisition(false);
111 111 this->setGraphRange(range);
112 112 this->enableAcquisition(true);
113 113
114 114 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
115 115 false);
116 116
117 117 emit variableAdded(variable);
118 118 }
119 119
120 120 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
121 121 {
122 122 // Each component associated to the variable :
123 123 // - is removed from qcpplot (which deletes it)
124 124 // - is no longer referenced in the map
125 125 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
126 126 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
127 127 auto &plottablesMap = variableIt->second;
128 128
129 129 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
130 130 plottableIt != plottableEnd;) {
131 131 ui->widget->removePlottable(plottableIt->second);
132 132 plottableIt = plottablesMap.erase(plottableIt);
133 133 }
134 134
135 135 impl->m_VariableToPlotMultiMap.erase(variableIt);
136 136 }
137 137
138 138 // Updates graph
139 139 ui->widget->replot();
140 140 }
141 141
142 142 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
143 143 {
144 144 // Note: in case of different axes that depends on variable, we could start with a code like
145 145 // that:
146 146 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
147 147 // for (auto it = componentsIt.first; it != componentsIt.second;) {
148 148 // }
149 149 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
150 150 ui->widget->replot();
151 151 }
152 152
153 153 void VisualizationGraphWidget::setYRange(const SqpRange &range)
154 154 {
155 155 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
156 156 }
157 157
158 158 SqpRange VisualizationGraphWidget::graphRange() const noexcept
159 159 {
160 160 auto graphRange = ui->widget->xAxis->range();
161 161 return SqpRange{graphRange.lower, graphRange.upper};
162 162 }
163 163
164 164 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
165 165 {
166 166 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
167 167 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
168 168 ui->widget->replot();
169 169 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
170 170 }
171 171
172 172 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
173 173 {
174 174 if (visitor) {
175 175 visitor->visit(this);
176 176 }
177 177 else {
178 178 qCCritical(LOG_VisualizationGraphWidget())
179 179 << tr("Can't visit widget : the visitor is null");
180 180 }
181 181 }
182 182
183 183 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
184 184 {
185 185 /// @todo : for the moment, a graph can always accomodate a variable
186 186 Q_UNUSED(variable);
187 187 return true;
188 188 }
189 189
190 190 bool VisualizationGraphWidget::contains(const Variable &variable) const
191 191 {
192 192 // Finds the variable among the keys of the map
193 193 auto variablePtr = &variable;
194 194 auto findVariable
195 195 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
196 196
197 197 auto end = impl->m_VariableToPlotMultiMap.cend();
198 198 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
199 199 return it != end;
200 200 }
201 201
202 202 QString VisualizationGraphWidget::name() const
203 203 {
204 204 return ui->graphNameLabel->text();
205 205 }
206 206
207 207 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
208 208 {
209 209 QMenu graphMenu{};
210 210
211 211 // Iterates on variables (unique keys)
212 212 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
213 213 end = impl->m_VariableToPlotMultiMap.cend();
214 214 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
215 215 // 'Remove variable' action
216 216 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
217 217 [ this, var = it->first ]() { removeVariable(var); });
218 218 }
219 219
220 220 if (!graphMenu.isEmpty()) {
221 graphMenu.exec(mapToGlobal(pos));
221 graphMenu.exec(QCursor::pos());
222 222 }
223 223 }
224 224
225 225 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
226 226 {
227 227 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
228 228 << QThread::currentThread()->objectName() << "DoAcqui"
229 229 << impl->m_DoAcquisition;
230 230
231 231 auto graphRange = SqpRange{t1.lower, t1.upper};
232 232 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
233 233
234 234 if (impl->m_DoAcquisition) {
235 235 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
236 236
237 237 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
238 238 end = impl->m_VariableToPlotMultiMap.end();
239 239 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
240 240 variableUnderGraphVector.push_back(it->first);
241 241 }
242 242 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
243 243 !impl->m_IsCalibration);
244 244
245 245 if (!impl->m_IsCalibration) {
246 246 qCDebug(LOG_VisualizationGraphWidget())
247 247 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
248 248 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
249 249 emit synchronize(graphRange, oldGraphRange);
250 250 }
251 251 }
252 252 }
253 253
254 254 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
255 255 {
256 256 // Handles plot rendering when mouse is moving
257 257 impl->m_RenderingDelegate->onMouseMove(event);
258 258 }
259 259
260 260 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
261 261 {
262 262 auto zoomOrientations = QFlags<Qt::Orientation>{};
263 263
264 264 // Lambda that enables a zoom orientation if the key modifier related to this orientation
265 265 // has
266 266 // been pressed
267 267 auto enableOrientation
268 268 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
269 269 auto orientationEnabled = event->modifiers().testFlag(modifier);
270 270 zoomOrientations.setFlag(orientation, orientationEnabled);
271 271 };
272 272 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
273 273 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
274 274
275 275 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
276 276 }
277 277
278 278 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
279 279 {
280 280 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
281 281 }
282 282
283 283 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
284 284 {
285 285 impl->m_IsCalibration = false;
286 286 }
287 287
288 288 void VisualizationGraphWidget::onDataCacheVariableUpdated()
289 289 {
290 290 auto graphRange = ui->widget->xAxis->range();
291 291 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
292 292
293 293 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
294 294 auto variable = variableEntry.first;
295 295 qCDebug(LOG_VisualizationGraphWidget())
296 296 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
297 297 qCDebug(LOG_VisualizationGraphWidget())
298 298 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
299 299 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
300 300 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
301 301 variable->range());
302 302 }
303 303 }
304 304 }
305 305
306 306 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
307 307 const SqpRange &range)
308 308 {
309 309 auto it = impl->m_VariableToPlotMultiMap.find(variable);
310 310 if (it != impl->m_VariableToPlotMultiMap.end()) {
311 311 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
312 312 }
313 313 }
@@ -1,86 +1,74
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <ui version="4.0">
3 3 <class>SqpSettingsGeneralWidget</class>
4 4 <widget class="QWidget" name="SqpSettingsGeneralWidget">
5 5 <property name="geometry">
6 6 <rect>
7 7 <x>0</x>
8 8 <y>0</y>
9 9 <width>343</width>
10 10 <height>300</height>
11 11 </rect>
12 12 </property>
13 13 <property name="windowTitle">
14 14 <string>Form</string>
15 15 </property>
16 16 <layout class="QGridLayout" name="gridLayout">
17 17 <item row="0" column="0">
18 18 <widget class="QLabel" name="toleranceInitLabel">
19 19 <property name="text">
20 20 <string>Tolerance on first acquisition:</string>
21 21 </property>
22 22 </widget>
23 23 </item>
24 24 <item row="0" column="1">
25 25 <widget class="QDoubleSpinBox" name="toleranceInitSpinBox">
26 26 <property name="sizePolicy">
27 27 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
28 28 <horstretch>0</horstretch>
29 29 <verstretch>0</verstretch>
30 30 </sizepolicy>
31 31 </property>
32 32 <property name="suffix">
33 33 <string> %</string>
34 34 </property>
35 <property name="minimum">
36 <double>0.000000000000000</double>
37 </property>
38 <property name="maximum">
39 <double>500.000000000000000</double>
40 </property>
41 35 </widget>
42 36 </item>
43 37 <item row="1" column="0">
44 38 <widget class="QLabel" name="toleranceUpdateLabel">
45 39 <property name="text">
46 40 <string>Tolerance when updating acquisition:</string>
47 41 </property>
48 42 </widget>
49 43 </item>
50 44 <item row="1" column="1">
51 45 <widget class="QDoubleSpinBox" name="toleranceUpdateSpinBox">
52 46 <property name="sizePolicy">
53 47 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
54 48 <horstretch>0</horstretch>
55 49 <verstretch>0</verstretch>
56 50 </sizepolicy>
57 51 </property>
58 52 <property name="suffix">
59 53 <string> %</string>
60 54 </property>
61 <property name="minimum">
62 <double>0.000000000000000</double>
63 </property>
64 <property name="maximum">
65 <double>500.000000000000000</double>
66 </property>
67 55 </widget>
68 56 </item>
69 57 <item row="2" column="0">
70 58 <spacer name="verticalSpacer">
71 59 <property name="orientation">
72 60 <enum>Qt::Vertical</enum>
73 61 </property>
74 62 <property name="sizeHint" stdset="0">
75 63 <size>
76 64 <width>20</width>
77 65 <height>40</height>
78 66 </size>
79 67 </property>
80 68 </spacer>
81 69 </item>
82 70 </layout>
83 71 </widget>
84 72 <resources/>
85 73 <connections/>
86 74 </ui>
General Comments 0
You need to be logged in to leave comments. Login now