##// END OF EJS Templates
Fixed untimely update of the range to be displayed in the variable widget
Alexandre Leroux -
r611:aff19a50babf
parent child
Show More
@@ -1,43 +1,56
1 #ifndef SCIQLOP_SQPRANGE_H
1 #ifndef SCIQLOP_SQPRANGE_H
2 #define SCIQLOP_SQPRANGE_H
2 #define SCIQLOP_SQPRANGE_H
3
3
4 #include <QObject>
4 #include <QObject>
5
5
6 #include <QDebug>
6 #include <QDebug>
7
7
8 #include <Common/DateUtils.h>
8 #include <Common/DateUtils.h>
9 #include <Common/MetaTypes.h>
9 #include <Common/MetaTypes.h>
10
10
11 /**
11 /**
12 * @brief The SqpRange struct holds the information of time parameters
12 * @brief The SqpRange struct holds the information of time parameters
13 */
13 */
14 struct SqpRange {
14 struct SqpRange {
15 /// Start time (UTC)
15 /// Start time (UTC)
16 double m_TStart;
16 double m_TStart;
17 /// End time (UTC)
17 /// End time (UTC)
18 double m_TEnd;
18 double m_TEnd;
19
19
20 bool contains(const SqpRange &dateTime) const noexcept
20 bool contains(const SqpRange &dateTime) const noexcept
21 {
21 {
22 return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd);
22 return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd);
23 }
23 }
24
24
25 bool intersect(const SqpRange &dateTime) const noexcept
25 bool intersect(const SqpRange &dateTime) const noexcept
26 {
26 {
27 return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd);
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 inline QDebug operator<<(QDebug d, SqpRange obj)
44 inline QDebug operator<<(QDebug d, SqpRange obj)
32 {
45 {
33 auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart);
46 auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart);
34 auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd);
47 auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd);
35
48
36 d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd;
49 d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd;
37 return d;
50 return d;
38 }
51 }
39
52
40 // Required for using shared_ptr in signals/slots
53 // Required for using shared_ptr in signals/slots
41 SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, SqpRange)
54 SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, SqpRange)
42
55
43 #endif // SCIQLOP_SQPRANGE_H
56 #endif // SCIQLOP_SQPRANGE_H
@@ -1,66 +1,75
1 #ifndef SCIQLOP_VARIABLE_H
1 #ifndef SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/DataSeriesIterator.h>
6 #include <Data/SqpRange.h>
7 #include <Data/SqpRange.h>
7
8
8 #include <QLoggingCategory>
9 #include <QLoggingCategory>
9 #include <QObject>
10 #include <QObject>
10
11
11 #include <Common/MetaTypes.h>
12 #include <Common/MetaTypes.h>
12 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
13
14
14 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
15
16
16 class IDataSeries;
17 class IDataSeries;
17 class QString;
18 class QString;
18
19
19 /**
20 /**
20 * @brief The Variable class represents a variable in SciQlop.
21 * @brief The Variable class represents a variable in SciQlop.
21 */
22 */
22 class SCIQLOP_CORE_EXPORT Variable : public QObject {
23 class SCIQLOP_CORE_EXPORT Variable : public QObject {
23
24
24 Q_OBJECT
25 Q_OBJECT
25
26
26 public:
27 public:
27 explicit Variable(const QString &name, const SqpRange &dateTime,
28 explicit Variable(const QString &name, const SqpRange &dateTime,
28 const QVariantHash &metadata = {});
29 const QVariantHash &metadata = {});
29
30
30 QString name() const noexcept;
31 QString name() const noexcept;
31 SqpRange range() const noexcept;
32 SqpRange range() const noexcept;
32 void setRange(const SqpRange &range) noexcept;
33 void setRange(const SqpRange &range) noexcept;
33 SqpRange cacheRange() const noexcept;
34 SqpRange cacheRange() const noexcept;
34 void setCacheRange(const SqpRange &cacheRange) noexcept;
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 /// @return the data of the variable, nullptr if there is no data
45 /// @return the data of the variable, nullptr if there is no data
37 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
46 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
38
47
39 QVariantHash metadata() const noexcept;
48 QVariantHash metadata() const noexcept;
40
49
41 bool contains(const SqpRange &range) const noexcept;
50 bool contains(const SqpRange &range) const noexcept;
42 bool intersect(const SqpRange &range) const noexcept;
51 bool intersect(const SqpRange &range) const noexcept;
43 bool isInside(const SqpRange &range) const noexcept;
52 bool isInside(const SqpRange &range) const noexcept;
44
53
45 bool cacheContains(const SqpRange &range) const noexcept;
54 bool cacheContains(const SqpRange &range) const noexcept;
46 bool cacheIntersect(const SqpRange &range) const noexcept;
55 bool cacheIntersect(const SqpRange &range) const noexcept;
47 bool cacheIsInside(const SqpRange &range) const noexcept;
56 bool cacheIsInside(const SqpRange &range) const noexcept;
48
57
49 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
58 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
50 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
59 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
51 void setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
60 void setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
52 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
61 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
53
62
54 signals:
63 signals:
55 void updated();
64 void updated();
56
65
57 private:
66 private:
58 class VariablePrivate;
67 class VariablePrivate;
59 spimpl::unique_impl_ptr<VariablePrivate> impl;
68 spimpl::unique_impl_ptr<VariablePrivate> impl;
60 };
69 };
61
70
62 // Required for using shared_ptr in signals/slots
71 // Required for using shared_ptr in signals/slots
63 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
72 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
64 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
73 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
65
74
66 #endif // SCIQLOP_VARIABLE_H
75 #endif // SCIQLOP_VARIABLE_H
@@ -1,248 +1,279
1 #include "Variable/Variable.h"
1 #include "Variable/Variable.h"
2
2
3 #include <Data/IDataSeries.h>
3 #include <Data/IDataSeries.h>
4 #include <Data/SqpRange.h>
4 #include <Data/SqpRange.h>
5
5
6 #include <QMutex>
6 #include <QMutex>
7 #include <QReadWriteLock>
7 #include <QReadWriteLock>
8 #include <QThread>
8 #include <QThread>
9
9
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11
11
12 struct Variable::VariablePrivate {
12 struct Variable::VariablePrivate {
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
14 const QVariantHash &metadata)
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 void lockRead() { m_Lock.lockForRead(); }
23 void lockRead() { m_Lock.lockForRead(); }
20 void lockWrite() { m_Lock.lockForWrite(); }
24 void lockWrite() { m_Lock.lockForWrite(); }
21 void unlock() { m_Lock.unlock(); }
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 QString m_Name;
46 QString m_Name;
24
47
25 SqpRange m_Range;
48 SqpRange m_Range;
26 SqpRange m_CacheRange;
49 SqpRange m_CacheRange;
27 QVariantHash m_Metadata;
50 QVariantHash m_Metadata;
28 std::shared_ptr<IDataSeries> m_DataSeries;
51 std::shared_ptr<IDataSeries> m_DataSeries;
52 SqpRange m_RealRange;
29
53
30 QReadWriteLock m_Lock;
54 QReadWriteLock m_Lock;
31 };
55 };
32
56
33 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
57 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
34 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
58 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
35 {
59 {
36 }
60 }
37
61
38 QString Variable::name() const noexcept
62 QString Variable::name() const noexcept
39 {
63 {
40 impl->lockRead();
64 impl->lockRead();
41 auto name = impl->m_Name;
65 auto name = impl->m_Name;
42 impl->unlock();
66 impl->unlock();
43 return name;
67 return name;
44 }
68 }
45
69
46 SqpRange Variable::range() const noexcept
70 SqpRange Variable::range() const noexcept
47 {
71 {
48 impl->lockRead();
72 impl->lockRead();
49 auto range = impl->m_Range;
73 auto range = impl->m_Range;
50 impl->unlock();
74 impl->unlock();
51 return range;
75 return range;
52 }
76 }
53
77
54 void Variable::setRange(const SqpRange &range) noexcept
78 void Variable::setRange(const SqpRange &range) noexcept
55 {
79 {
56 impl->lockWrite();
80 impl->lockWrite();
57 impl->m_Range = range;
81 impl->m_Range = range;
82 impl->updateRealRange();
58 impl->unlock();
83 impl->unlock();
59 }
84 }
60
85
61 SqpRange Variable::cacheRange() const noexcept
86 SqpRange Variable::cacheRange() const noexcept
62 {
87 {
63 impl->lockRead();
88 impl->lockRead();
64 auto cacheRange = impl->m_CacheRange;
89 auto cacheRange = impl->m_CacheRange;
65 impl->unlock();
90 impl->unlock();
66 return cacheRange;
91 return cacheRange;
67 }
92 }
68
93
69 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
94 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
70 {
95 {
71 impl->lockWrite();
96 impl->lockWrite();
72 impl->m_CacheRange = cacheRange;
97 impl->m_CacheRange = cacheRange;
73 impl->unlock();
98 impl->unlock();
74 }
99 }
75
100
101 SqpRange Variable::realRange() const noexcept
102 {
103 return impl->m_RealRange;
104 }
105
76 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
106 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
77 {
107 {
78 qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries"
108 qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries"
79 << QThread::currentThread()->objectName();
109 << QThread::currentThread()->objectName();
80 if (!dataSeries) {
110 if (!dataSeries) {
81 /// @todo ALX : log
111 /// @todo ALX : log
82 return;
112 return;
83 }
113 }
84 impl->lockWrite();
114 impl->lockWrite();
85 impl->m_DataSeries = dataSeries->clone();
115 impl->m_DataSeries = dataSeries->clone();
116 impl->updateRealRange();
86 impl->unlock();
117 impl->unlock();
87 }
118 }
88
119
89 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
120 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
90 {
121 {
91 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
122 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
92 << QThread::currentThread()->objectName();
123 << QThread::currentThread()->objectName();
93 if (!dataSeries) {
124 if (!dataSeries) {
94 /// @todo ALX : log
125 /// @todo ALX : log
95 return;
126 return;
96 }
127 }
97
128
98 // Add or merge the data
129 // Add or merge the data
99 // Inits the data series of the variable
130 // Inits the data series of the variable
100 impl->lockWrite();
131 impl->lockWrite();
101 if (!impl->m_DataSeries) {
132 if (!impl->m_DataSeries) {
102 impl->m_DataSeries = dataSeries->clone();
133 impl->m_DataSeries = dataSeries->clone();
103 }
134 }
104 else {
135 else {
105 impl->m_DataSeries->merge(dataSeries.get());
136 impl->m_DataSeries->merge(dataSeries.get());
106 }
137 }
107 impl->unlock();
138 impl->unlock();
108
139
109 // sub the data
140 // sub the data
110 auto subData = this->dataSeries()->subDataSeries(this->cacheRange());
141 auto subData = this->dataSeries()->subDataSeries(this->cacheRange());
111 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range();
142 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range();
112 this->setDataSeries(subData);
143 this->setDataSeries(subData);
113 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries set" << this->dataSeries()->range();
144 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries set" << this->dataSeries()->range();
114 }
145 }
115
146
116 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
147 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
117 {
148 {
118 impl->lockRead();
149 impl->lockRead();
119 auto dataSeries = impl->m_DataSeries;
150 auto dataSeries = impl->m_DataSeries;
120 impl->unlock();
151 impl->unlock();
121
152
122 return dataSeries;
153 return dataSeries;
123 }
154 }
124
155
125 QVariantHash Variable::metadata() const noexcept
156 QVariantHash Variable::metadata() const noexcept
126 {
157 {
127 impl->lockRead();
158 impl->lockRead();
128 auto metadata = impl->m_Metadata;
159 auto metadata = impl->m_Metadata;
129 impl->unlock();
160 impl->unlock();
130 return metadata;
161 return metadata;
131 }
162 }
132
163
133 bool Variable::contains(const SqpRange &range) const noexcept
164 bool Variable::contains(const SqpRange &range) const noexcept
134 {
165 {
135 impl->lockRead();
166 impl->lockRead();
136 auto res = impl->m_Range.contains(range);
167 auto res = impl->m_Range.contains(range);
137 impl->unlock();
168 impl->unlock();
138 return res;
169 return res;
139 }
170 }
140
171
141 bool Variable::intersect(const SqpRange &range) const noexcept
172 bool Variable::intersect(const SqpRange &range) const noexcept
142 {
173 {
143
174
144 impl->lockRead();
175 impl->lockRead();
145 auto res = impl->m_Range.intersect(range);
176 auto res = impl->m_Range.intersect(range);
146 impl->unlock();
177 impl->unlock();
147 return res;
178 return res;
148 }
179 }
149
180
150 bool Variable::isInside(const SqpRange &range) const noexcept
181 bool Variable::isInside(const SqpRange &range) const noexcept
151 {
182 {
152 impl->lockRead();
183 impl->lockRead();
153 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
184 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
154 impl->unlock();
185 impl->unlock();
155 return res;
186 return res;
156 }
187 }
157
188
158 bool Variable::cacheContains(const SqpRange &range) const noexcept
189 bool Variable::cacheContains(const SqpRange &range) const noexcept
159 {
190 {
160 impl->lockRead();
191 impl->lockRead();
161 auto res = impl->m_CacheRange.contains(range);
192 auto res = impl->m_CacheRange.contains(range);
162 impl->unlock();
193 impl->unlock();
163 return res;
194 return res;
164 }
195 }
165
196
166 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
197 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
167 {
198 {
168 impl->lockRead();
199 impl->lockRead();
169 auto res = impl->m_CacheRange.intersect(range);
200 auto res = impl->m_CacheRange.intersect(range);
170 impl->unlock();
201 impl->unlock();
171 return res;
202 return res;
172 }
203 }
173
204
174 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
205 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
175 {
206 {
176 impl->lockRead();
207 impl->lockRead();
177 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
208 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
178 impl->unlock();
209 impl->unlock();
179 return res;
210 return res;
180 }
211 }
181
212
182
213
183 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
214 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
184 {
215 {
185 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
216 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
186
217
187 auto notInCache = QVector<SqpRange>{};
218 auto notInCache = QVector<SqpRange>{};
188
219
189 if (!this->cacheContains(range)) {
220 if (!this->cacheContains(range)) {
190 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
221 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
191 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
222 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
192 notInCache << range;
223 notInCache << range;
193 }
224 }
194 else if (range.m_TStart < impl->m_CacheRange.m_TStart
225 else if (range.m_TStart < impl->m_CacheRange.m_TStart
195 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
226 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
196 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
227 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
197 }
228 }
198 else if (range.m_TStart < impl->m_CacheRange.m_TStart
229 else if (range.m_TStart < impl->m_CacheRange.m_TStart
199 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
230 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
200 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
231 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
201 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
232 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
202 }
233 }
203 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
234 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
204 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
235 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
205 }
236 }
206 else {
237 else {
207 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
238 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
208 << QThread::currentThread();
239 << QThread::currentThread();
209 }
240 }
210 }
241 }
211
242
212 return notInCache;
243 return notInCache;
213 }
244 }
214
245
215 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
246 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
216 {
247 {
217 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
248 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
218
249
219 auto inCache = QVector<SqpRange>{};
250 auto inCache = QVector<SqpRange>{};
220
251
221
252
222 if (this->intersect(range)) {
253 if (this->intersect(range)) {
223 if (range.m_TStart <= impl->m_CacheRange.m_TStart
254 if (range.m_TStart <= impl->m_CacheRange.m_TStart
224 && range.m_TEnd >= impl->m_CacheRange.m_TStart
255 && range.m_TEnd >= impl->m_CacheRange.m_TStart
225 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
256 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
226 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
257 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
227 }
258 }
228
259
229 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
260 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
230 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
261 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
231 inCache << range;
262 inCache << range;
232 }
263 }
233 else if (range.m_TStart > impl->m_CacheRange.m_TStart
264 else if (range.m_TStart > impl->m_CacheRange.m_TStart
234 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
265 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
235 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
266 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
236 }
267 }
237 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
268 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
238 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
269 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
239 inCache << impl->m_CacheRange;
270 inCache << impl->m_CacheRange;
240 }
271 }
241 else {
272 else {
242 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
273 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
243 << QThread::currentThread();
274 << QThread::currentThread();
244 }
275 }
245 }
276 }
246
277
247 return inCache;
278 return inCache;
248 }
279 }
@@ -1,274 +1,260
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableModel.h>
2 #include <Variable/VariableModel.h>
3
3
4 #include <Common/DateUtils.h>
4 #include <Common/DateUtils.h>
5
5
6 #include <Data/IDataSeries.h>
6 #include <Data/IDataSeries.h>
7
7
8 #include <QSize>
8 #include <QSize>
9 #include <unordered_map>
9 #include <unordered_map>
10
10
11 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
11 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
12
12
13 namespace {
13 namespace {
14
14
15 // Column indexes
15 // Column indexes
16 const auto NAME_COLUMN = 0;
16 const auto NAME_COLUMN = 0;
17 const auto TSTART_COLUMN = 1;
17 const auto TSTART_COLUMN = 1;
18 const auto TEND_COLUMN = 2;
18 const auto TEND_COLUMN = 2;
19 const auto UNIT_COLUMN = 3;
19 const auto UNIT_COLUMN = 3;
20 const auto MISSION_COLUMN = 4;
20 const auto MISSION_COLUMN = 4;
21 const auto PLUGIN_COLUMN = 5;
21 const auto PLUGIN_COLUMN = 5;
22 const auto NB_COLUMNS = 6;
22 const auto NB_COLUMNS = 6;
23
23
24 // Column properties
24 // Column properties
25 const auto DEFAULT_HEIGHT = 25;
25 const auto DEFAULT_HEIGHT = 25;
26 const auto DEFAULT_WIDTH = 100;
26 const auto DEFAULT_WIDTH = 100;
27
27
28 struct ColumnProperties {
28 struct ColumnProperties {
29 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
29 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
30 int height = DEFAULT_HEIGHT)
30 int height = DEFAULT_HEIGHT)
31 : m_Name{name}, m_Width{width}, m_Height{height}
31 : m_Name{name}, m_Width{width}, m_Height{height}
32 {
32 {
33 }
33 }
34
34
35 QString m_Name;
35 QString m_Name;
36 int m_Width;
36 int m_Width;
37 int m_Height;
37 int m_Height;
38 };
38 };
39
39
40 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
40 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
41 {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
41 {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
42 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {UNIT_COLUMN, {QObject::tr("Unit")}},
42 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {UNIT_COLUMN, {QObject::tr("Unit")}},
43 {MISSION_COLUMN, {QObject::tr("Mission")}}, {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
43 {MISSION_COLUMN, {QObject::tr("Mission")}}, {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
44
44
45 /// Format for datetimes
45 /// Format for datetimes
46 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
46 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
47
47
48
48
49 } // namespace
49 } // namespace
50
50
51 struct VariableModel::VariableModelPrivate {
51 struct VariableModel::VariableModelPrivate {
52 /// Variables created in SciQlop
52 /// Variables created in SciQlop
53 std::vector<std::shared_ptr<Variable> > m_Variables;
53 std::vector<std::shared_ptr<Variable> > m_Variables;
54 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
54 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
55
55
56 /// Return the row index of the variable. -1 if it's not found
56 /// Return the row index of the variable. -1 if it's not found
57 int indexOfVariable(Variable *variable) const noexcept;
57 int indexOfVariable(Variable *variable) const noexcept;
58 };
58 };
59
59
60 VariableModel::VariableModel(QObject *parent)
60 VariableModel::VariableModel(QObject *parent)
61 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
61 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
62 {
62 {
63 }
63 }
64
64
65 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
65 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
66 const SqpRange &dateTime,
66 const SqpRange &dateTime,
67 const QVariantHash &metadata) noexcept
67 const QVariantHash &metadata) noexcept
68 {
68 {
69 auto insertIndex = rowCount();
69 auto insertIndex = rowCount();
70 beginInsertRows({}, insertIndex, insertIndex);
70 beginInsertRows({}, insertIndex, insertIndex);
71
71
72 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
72 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
73
73
74 impl->m_Variables.push_back(variable);
74 impl->m_Variables.push_back(variable);
75 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
75 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
76
76
77 endInsertRows();
77 endInsertRows();
78
78
79 return variable;
79 return variable;
80 }
80 }
81
81
82 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
82 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
83 {
83 {
84 if (!variable) {
84 if (!variable) {
85 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
85 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
86 return;
86 return;
87 }
87 }
88
88
89 // Finds variable in the model
89 // Finds variable in the model
90 auto begin = impl->m_Variables.cbegin();
90 auto begin = impl->m_Variables.cbegin();
91 auto end = impl->m_Variables.cend();
91 auto end = impl->m_Variables.cend();
92 auto it = std::find(begin, end, variable);
92 auto it = std::find(begin, end, variable);
93 if (it != end) {
93 if (it != end) {
94 auto removeIndex = std::distance(begin, it);
94 auto removeIndex = std::distance(begin, it);
95
95
96 // Deletes variable
96 // Deletes variable
97 beginRemoveRows({}, removeIndex, removeIndex);
97 beginRemoveRows({}, removeIndex, removeIndex);
98 impl->m_Variables.erase(it);
98 impl->m_Variables.erase(it);
99 endRemoveRows();
99 endRemoveRows();
100 }
100 }
101 else {
101 else {
102 qCritical(LOG_VariableModel())
102 qCritical(LOG_VariableModel())
103 << tr("Can't delete variable %1 from the model: the variable is not in the model")
103 << tr("Can't delete variable %1 from the model: the variable is not in the model")
104 .arg(variable->name());
104 .arg(variable->name());
105 }
105 }
106
106
107 // Removes variable from progress map
107 // Removes variable from progress map
108 impl->m_VariableToProgress.erase(variable);
108 impl->m_VariableToProgress.erase(variable);
109 }
109 }
110
110
111
111
112 std::shared_ptr<Variable> VariableModel::variable(int index) const
112 std::shared_ptr<Variable> VariableModel::variable(int index) const
113 {
113 {
114 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
114 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
115 }
115 }
116
116
117 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
117 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
118 {
118 {
119 if (progress > 0.0) {
119 if (progress > 0.0) {
120 impl->m_VariableToProgress[variable] = progress;
120 impl->m_VariableToProgress[variable] = progress;
121 }
121 }
122 else {
122 else {
123 impl->m_VariableToProgress.erase(variable);
123 impl->m_VariableToProgress.erase(variable);
124 }
124 }
125 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
125 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
126
126
127 emit dataChanged(modelIndex, modelIndex);
127 emit dataChanged(modelIndex, modelIndex);
128 }
128 }
129
129
130 int VariableModel::columnCount(const QModelIndex &parent) const
130 int VariableModel::columnCount(const QModelIndex &parent) const
131 {
131 {
132 Q_UNUSED(parent);
132 Q_UNUSED(parent);
133
133
134 return NB_COLUMNS;
134 return NB_COLUMNS;
135 }
135 }
136
136
137 int VariableModel::rowCount(const QModelIndex &parent) const
137 int VariableModel::rowCount(const QModelIndex &parent) const
138 {
138 {
139 Q_UNUSED(parent);
139 Q_UNUSED(parent);
140
140
141 return impl->m_Variables.size();
141 return impl->m_Variables.size();
142 }
142 }
143
143
144 QVariant VariableModel::data(const QModelIndex &index, int role) const
144 QVariant VariableModel::data(const QModelIndex &index, int role) const
145 {
145 {
146 if (!index.isValid()) {
146 if (!index.isValid()) {
147 return QVariant{};
147 return QVariant{};
148 }
148 }
149
149
150 if (index.row() < 0 || index.row() >= rowCount()) {
150 if (index.row() < 0 || index.row() >= rowCount()) {
151 return QVariant{};
151 return QVariant{};
152 }
152 }
153
153
154 if (role == Qt::DisplayRole) {
154 if (role == Qt::DisplayRole) {
155 if (auto variable = impl->m_Variables.at(index.row()).get()) {
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 switch (index.column()) {
156 switch (index.column()) {
175 case NAME_COLUMN:
157 case NAME_COLUMN:
176 return variable->name();
158 return variable->name();
177 case TSTART_COLUMN:
159 case TSTART_COLUMN: {
178 // Shows the min value of the data series above the range tstart
160 auto range = variable->realRange();
179 return dateTimeVariant([min = variable->range().m_TStart](
161 return range != INVALID_RANGE
180 const auto &dataSeries) { return dataSeries.minXAxisData(min); });
162 ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT)
181 case TEND_COLUMN:
163 : QVariant{};
182 // Shows the max value of the data series under the range tend
164 }
183 return dateTimeVariant([max = variable->range().m_TEnd](
165 case TEND_COLUMN: {
184 const auto &dataSeries) { return dataSeries.maxXAxisData(max); });
166 auto range = variable->realRange();
167 return range != INVALID_RANGE
168 ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT)
169 : QVariant{};
170 }
185 case UNIT_COLUMN:
171 case UNIT_COLUMN:
186 return variable->metadata().value(QStringLiteral("units"));
172 return variable->metadata().value(QStringLiteral("units"));
187 case MISSION_COLUMN:
173 case MISSION_COLUMN:
188 return variable->metadata().value(QStringLiteral("mission"));
174 return variable->metadata().value(QStringLiteral("mission"));
189 case PLUGIN_COLUMN:
175 case PLUGIN_COLUMN:
190 return variable->metadata().value(QStringLiteral("plugin"));
176 return variable->metadata().value(QStringLiteral("plugin"));
191 default:
177 default:
192 // No action
178 // No action
193 break;
179 break;
194 }
180 }
195
181
196 qWarning(LOG_VariableModel())
182 qWarning(LOG_VariableModel())
197 << tr("Can't get data (unknown column %1)").arg(index.column());
183 << tr("Can't get data (unknown column %1)").arg(index.column());
198 }
184 }
199 else {
185 else {
200 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
186 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
201 }
187 }
202 }
188 }
203 else if (role == VariableRoles::ProgressRole) {
189 else if (role == VariableRoles::ProgressRole) {
204 if (auto variable = impl->m_Variables.at(index.row())) {
190 if (auto variable = impl->m_Variables.at(index.row())) {
205
191
206 auto it = impl->m_VariableToProgress.find(variable);
192 auto it = impl->m_VariableToProgress.find(variable);
207 if (it != impl->m_VariableToProgress.cend()) {
193 if (it != impl->m_VariableToProgress.cend()) {
208 return it->second;
194 return it->second;
209 }
195 }
210 }
196 }
211 }
197 }
212
198
213 return QVariant{};
199 return QVariant{};
214 }
200 }
215
201
216 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
202 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
217 {
203 {
218 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
204 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
219 return QVariant{};
205 return QVariant{};
220 }
206 }
221
207
222 if (orientation == Qt::Horizontal) {
208 if (orientation == Qt::Horizontal) {
223 auto propertiesIt = COLUMN_PROPERTIES.find(section);
209 auto propertiesIt = COLUMN_PROPERTIES.find(section);
224 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
210 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
225 // Role is either DisplayRole or SizeHintRole
211 // Role is either DisplayRole or SizeHintRole
226 return (role == Qt::DisplayRole)
212 return (role == Qt::DisplayRole)
227 ? QVariant{propertiesIt->m_Name}
213 ? QVariant{propertiesIt->m_Name}
228 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
214 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
229 }
215 }
230 else {
216 else {
231 qWarning(LOG_VariableModel())
217 qWarning(LOG_VariableModel())
232 << tr("Can't get header data (unknown column %1)").arg(section);
218 << tr("Can't get header data (unknown column %1)").arg(section);
233 }
219 }
234 }
220 }
235
221
236 return QVariant{};
222 return QVariant{};
237 }
223 }
238
224
239 void VariableModel::abortProgress(const QModelIndex &index)
225 void VariableModel::abortProgress(const QModelIndex &index)
240 {
226 {
241 if (auto variable = impl->m_Variables.at(index.row())) {
227 if (auto variable = impl->m_Variables.at(index.row())) {
242 emit abortProgessRequested(variable);
228 emit abortProgessRequested(variable);
243 }
229 }
244 }
230 }
245
231
246 void VariableModel::onVariableUpdated() noexcept
232 void VariableModel::onVariableUpdated() noexcept
247 {
233 {
248 // Finds variable that has been updated in the model
234 // Finds variable that has been updated in the model
249 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
235 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
250 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
236 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
251
237
252 if (updatedVariableIndex > -1) {
238 if (updatedVariableIndex > -1) {
253 emit dataChanged(createIndex(updatedVariableIndex, 0),
239 emit dataChanged(createIndex(updatedVariableIndex, 0),
254 createIndex(updatedVariableIndex, columnCount() - 1));
240 createIndex(updatedVariableIndex, columnCount() - 1));
255 }
241 }
256 }
242 }
257 }
243 }
258
244
259 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
245 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
260 {
246 {
261 auto begin = std::cbegin(m_Variables);
247 auto begin = std::cbegin(m_Variables);
262 auto end = std::cend(m_Variables);
248 auto end = std::cend(m_Variables);
263 auto it
249 auto it
264 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
250 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
265
251
266 if (it != end) {
252 if (it != end) {
267 // Gets the index of the variable in the model: we assume here that views have the same
253 // Gets the index of the variable in the model: we assume here that views have the same
268 // order as the model
254 // order as the model
269 return std::distance(begin, it);
255 return std::distance(begin, it);
270 }
256 }
271 else {
257 else {
272 return -1;
258 return -1;
273 }
259 }
274 }
260 }
General Comments 0
You need to be logged in to leave comments. Login now