##// END OF EJS Templates
Implementation of the cache feature : download before display needs
perrinel -
r433:a2e6652524d1
parent child
Show More
@@ -1,90 +1,90
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/SqpDateTime.h>
4 #include <Data/SqpDateTime.h>
5
5
6 #include <QReadWriteLock>
6 #include <QReadWriteLock>
7 #include <QThread>
7 #include <QThread>
8
8
9 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
9 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10
10
11 struct Variable::VariablePrivate {
11 struct Variable::VariablePrivate {
12 explicit VariablePrivate(const QString &name, const SqpDateTime &dateTime,
12 explicit VariablePrivate(const QString &name, const SqpDateTime &dateTime,
13 const QVariantHash &metadata)
13 const QVariantHash &metadata)
14 : m_Name{name}, m_DateTime{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
14 : m_Name{name}, m_DateTime{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
15 {
15 {
16 }
16 }
17
17
18 QString m_Name;
18 QString m_Name;
19
19
20 SqpDateTime m_DateTime; // The dateTime available in the view and loaded. not the cache.
20 SqpDateTime m_DateTime; // The dateTime available in the view and loaded. not the cache.
21 QVariantHash m_Metadata;
21 QVariantHash m_Metadata;
22 std::unique_ptr<IDataSeries> m_DataSeries;
22 std::unique_ptr<IDataSeries> m_DataSeries;
23 };
23 };
24
24
25 Variable::Variable(const QString &name, const SqpDateTime &dateTime, const QVariantHash &metadata)
25 Variable::Variable(const QString &name, const SqpDateTime &dateTime, const QVariantHash &metadata)
26 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
26 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
27 {
27 {
28 }
28 }
29
29
30 QString Variable::name() const noexcept
30 QString Variable::name() const noexcept
31 {
31 {
32 return impl->m_Name;
32 return impl->m_Name;
33 }
33 }
34
34
35 SqpDateTime Variable::dateTime() const noexcept
35 SqpDateTime Variable::dateTime() const noexcept
36 {
36 {
37 return impl->m_DateTime;
37 return impl->m_DateTime;
38 }
38 }
39
39
40 void Variable::setDateTime(const SqpDateTime &dateTime) noexcept
40 void Variable::setDateTime(const SqpDateTime &dateTime) noexcept
41 {
41 {
42 impl->m_DateTime = dateTime;
42 impl->m_DateTime = dateTime;
43 }
43 }
44
44
45 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
45 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
46 {
46 {
47 qCDebug(LOG_Variable()) << "Variable::setDataSeries" << QThread::currentThread()->objectName();
47 qCDebug(LOG_Variable()) << "Variable::setDataSeries" << QThread::currentThread()->objectName();
48 if (!dataSeries) {
48 if (!dataSeries) {
49 /// @todo ALX : log
49 /// @todo ALX : log
50 return;
50 return;
51 }
51 }
52
52
53 // Inits the data series of the variable
53 // Inits the data series of the variable
54 if (!impl->m_DataSeries) {
54 if (!impl->m_DataSeries) {
55 impl->m_DataSeries = dataSeries->clone();
55 impl->m_DataSeries = dataSeries->clone();
56 }
56 }
57 else {
57 else {
58 dataSeries->lockWrite();
58 dataSeries->lockWrite();
59 impl->m_DataSeries->lockWrite();
59 impl->m_DataSeries->lockWrite();
60 impl->m_DataSeries->merge(dataSeries.get());
60 impl->m_DataSeries->merge(dataSeries.get());
61 impl->m_DataSeries->unlock();
61 impl->m_DataSeries->unlock();
62 dataSeries->unlock();
62 dataSeries->unlock();
63 emit updated();
63 // emit updated();
64 }
64 }
65 }
65 }
66
66
67 IDataSeries *Variable::dataSeries() const noexcept
67 IDataSeries *Variable::dataSeries() const noexcept
68 {
68 {
69 return impl->m_DataSeries.get();
69 return impl->m_DataSeries.get();
70 }
70 }
71
71
72 QVariantHash Variable::metadata() const noexcept
72 QVariantHash Variable::metadata() const noexcept
73 {
73 {
74 return impl->m_Metadata;
74 return impl->m_Metadata;
75 }
75 }
76
76
77 bool Variable::contains(const SqpDateTime &dateTime) const noexcept
77 bool Variable::contains(const SqpDateTime &dateTime) const noexcept
78 {
78 {
79 return impl->m_DateTime.contains(dateTime);
79 return impl->m_DateTime.contains(dateTime);
80 }
80 }
81
81
82 bool Variable::intersect(const SqpDateTime &dateTime) const noexcept
82 bool Variable::intersect(const SqpDateTime &dateTime) const noexcept
83 {
83 {
84 return impl->m_DateTime.intersect(dateTime);
84 return impl->m_DateTime.intersect(dateTime);
85 }
85 }
86
86
87 bool Variable::isInside(const SqpDateTime &dateTime) const noexcept
87 bool Variable::isInside(const SqpDateTime &dateTime) const noexcept
88 {
88 {
89 return dateTime.contains(SqpDateTime{impl->m_DateTime.m_TStart, impl->m_DateTime.m_TEnd});
89 return dateTime.contains(SqpDateTime{impl->m_DateTime.m_TStart, impl->m_DateTime.m_TEnd});
90 }
90 }
@@ -1,240 +1,241
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableCacheController.h>
2 #include <Variable/VariableCacheController.h>
3 #include <Variable/VariableController.h>
3 #include <Variable/VariableController.h>
4 #include <Variable/VariableModel.h>
4 #include <Variable/VariableModel.h>
5
5
6 #include <Data/DataProviderParameters.h>
6 #include <Data/DataProviderParameters.h>
7 #include <Data/IDataProvider.h>
7 #include <Data/IDataProvider.h>
8 #include <Data/IDataSeries.h>
8 #include <Data/IDataSeries.h>
9 #include <Time/TimeController.h>
9 #include <Time/TimeController.h>
10
10
11 #include <QDateTime>
11 #include <QDateTime>
12 #include <QMutex>
12 #include <QMutex>
13 #include <QThread>
13 #include <QThread>
14 #include <QUuid>
14 #include <QUuid>
15 #include <QtCore/QItemSelectionModel>
15 #include <QtCore/QItemSelectionModel>
16
16
17 #include <unordered_map>
17 #include <unordered_map>
18
18
19 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
19 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
20
20
21 struct VariableController::VariableControllerPrivate {
21 struct VariableController::VariableControllerPrivate {
22 explicit VariableControllerPrivate(VariableController *parent)
22 explicit VariableControllerPrivate(VariableController *parent)
23 : m_WorkingMutex{},
23 : m_WorkingMutex{},
24 m_VariableModel{new VariableModel{parent}},
24 m_VariableModel{new VariableModel{parent}},
25 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
25 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
26 m_VariableCacheController{std::make_unique<VariableCacheController>()}
26 m_VariableCacheController{std::make_unique<VariableCacheController>()}
27 {
27 {
28 }
28 }
29
29
30 QMutex m_WorkingMutex;
30 QMutex m_WorkingMutex;
31 /// Variable model. The VariableController has the ownership
31 /// Variable model. The VariableController has the ownership
32 VariableModel *m_VariableModel;
32 VariableModel *m_VariableModel;
33 QItemSelectionModel *m_VariableSelectionModel;
33 QItemSelectionModel *m_VariableSelectionModel;
34
34
35
35
36 TimeController *m_TimeController{nullptr};
36 TimeController *m_TimeController{nullptr};
37 std::unique_ptr<VariableCacheController> m_VariableCacheController;
37 std::unique_ptr<VariableCacheController> m_VariableCacheController;
38
38
39 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
39 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
40 m_VariableToProviderMap;
40 m_VariableToProviderMap;
41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
42 };
42 };
43
43
44 VariableController::VariableController(QObject *parent)
44 VariableController::VariableController(QObject *parent)
45 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
45 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
46 {
46 {
47 qCDebug(LOG_VariableController()) << tr("VariableController construction")
47 qCDebug(LOG_VariableController()) << tr("VariableController construction")
48 << QThread::currentThread();
48 << QThread::currentThread();
49
49
50 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
50 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
51 &VariableController::onAbortProgressRequested);
51 &VariableController::onAbortProgressRequested);
52 }
52 }
53
53
54 VariableController::~VariableController()
54 VariableController::~VariableController()
55 {
55 {
56 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
56 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
57 << QThread::currentThread();
57 << QThread::currentThread();
58 this->waitForFinish();
58 this->waitForFinish();
59 }
59 }
60
60
61 VariableModel *VariableController::variableModel() noexcept
61 VariableModel *VariableController::variableModel() noexcept
62 {
62 {
63 return impl->m_VariableModel;
63 return impl->m_VariableModel;
64 }
64 }
65
65
66 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
66 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
67 {
67 {
68 return impl->m_VariableSelectionModel;
68 return impl->m_VariableSelectionModel;
69 }
69 }
70
70
71 void VariableController::setTimeController(TimeController *timeController) noexcept
71 void VariableController::setTimeController(TimeController *timeController) noexcept
72 {
72 {
73 impl->m_TimeController = timeController;
73 impl->m_TimeController = timeController;
74 }
74 }
75
75
76 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
76 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
77 {
77 {
78 if (!variable) {
78 if (!variable) {
79 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
79 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
80 return;
80 return;
81 }
81 }
82
82
83 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
83 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
84 // make some treatments before the deletion
84 // make some treatments before the deletion
85 emit variableAboutToBeDeleted(variable);
85 emit variableAboutToBeDeleted(variable);
86
86
87 // Deletes identifier
87 // Deletes identifier
88 impl->m_VariableToIdentifierMap.erase(variable);
88 impl->m_VariableToIdentifierMap.erase(variable);
89
89
90 // Deletes provider
90 // Deletes provider
91 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
91 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
92 qCDebug(LOG_VariableController())
92 qCDebug(LOG_VariableController())
93 << tr("Number of providers deleted for variable %1: %2")
93 << tr("Number of providers deleted for variable %1: %2")
94 .arg(variable->name(), QString::number(nbProvidersDeleted));
94 .arg(variable->name(), QString::number(nbProvidersDeleted));
95
95
96 // Clears cache
96 // Clears cache
97 impl->m_VariableCacheController->clear(variable);
97 impl->m_VariableCacheController->clear(variable);
98
98
99 // Deletes from model
99 // Deletes from model
100 impl->m_VariableModel->deleteVariable(variable);
100 impl->m_VariableModel->deleteVariable(variable);
101 }
101 }
102
102
103 void VariableController::deleteVariables(
103 void VariableController::deleteVariables(
104 const QVector<std::shared_ptr<Variable> > &variables) noexcept
104 const QVector<std::shared_ptr<Variable> > &variables) noexcept
105 {
105 {
106 for (auto variable : qAsConst(variables)) {
106 for (auto variable : qAsConst(variables)) {
107 deleteVariable(variable);
107 deleteVariable(variable);
108 }
108 }
109 }
109 }
110
110
111 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
111 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
112 {
112 {
113 }
113 }
114
114
115 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
115 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
116 std::shared_ptr<IDataProvider> provider) noexcept
116 std::shared_ptr<IDataProvider> provider) noexcept
117 {
117 {
118
118
119 if (!impl->m_TimeController) {
119 if (!impl->m_TimeController) {
120 qCCritical(LOG_VariableController())
120 qCCritical(LOG_VariableController())
121 << tr("Impossible to create variable: The time controller is null");
121 << tr("Impossible to create variable: The time controller is null");
122 return;
122 return;
123 }
123 }
124
124
125 auto dateTime = impl->m_TimeController->dateTime();
125 auto dateTime = impl->m_TimeController->dateTime();
126
126
127 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime, metadata)) {
127 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime, metadata)) {
128 auto identifier = QUuid::createUuid();
128 auto identifier = QUuid::createUuid();
129
129
130 // store the provider
130 // store the provider
131 impl->m_VariableToProviderMap[newVariable] = provider;
131 impl->m_VariableToProviderMap[newVariable] = provider;
132 impl->m_VariableToIdentifierMap[newVariable] = identifier;
132 impl->m_VariableToIdentifierMap[newVariable] = identifier;
133
133
134 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
134 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
135 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
135 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
136 {
136 {
137 if (auto variable = varW.lock()) {
137 if (auto variable = varW.lock()) {
138 auto varIdentifier = impl->m_VariableToIdentifierMap.at(variable);
138 auto varIdentifier = impl->m_VariableToIdentifierMap.at(variable);
139 if (varIdentifier == identifier) {
139 if (varIdentifier == identifier) {
140 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
140 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
141 variable->setDataSeries(dataSeriesAcquired);
141 variable->setDataSeries(dataSeriesAcquired);
142 emit variable->updated();
142 }
143 }
143 }
144 }
144 };
145 };
145
146
146 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
147 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
147 connect(provider.get(), &IDataProvider::dataProvidedProgress, this,
148 connect(provider.get(), &IDataProvider::dataProvidedProgress, this,
148 &VariableController::onVariableRetrieveDataInProgress);
149 &VariableController::onVariableRetrieveDataInProgress);
149 this->onRequestDataLoading(newVariable, dateTime);
150 this->onRequestDataLoading(newVariable, dateTime);
150 }
151 }
151 }
152 }
152
153
153 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
154 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
154 {
155 {
155 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
156 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
156 << QThread::currentThread()->objectName();
157 << QThread::currentThread()->objectName();
157 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
158 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
158
159
159 for (const auto &selectedRow : qAsConst(selectedRows)) {
160 for (const auto &selectedRow : qAsConst(selectedRows)) {
160 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
161 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
161 selectedVariable->setDateTime(dateTime);
162 selectedVariable->setDateTime(dateTime);
162 this->onRequestDataLoading(selectedVariable, dateTime);
163 this->onRequestDataLoading(selectedVariable, dateTime);
163 }
164 }
164 }
165 }
165 }
166 }
166
167
167 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
168 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
168 {
169 {
169 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
170 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
170
171
171 auto end = impl->m_VariableToIdentifierMap.cend();
172 auto end = impl->m_VariableToIdentifierMap.cend();
172 auto it = std::find_if(impl->m_VariableToIdentifierMap.cbegin(), end, findReply);
173 auto it = std::find_if(impl->m_VariableToIdentifierMap.cbegin(), end, findReply);
173 if (it != end) {
174 if (it != end) {
174 impl->m_VariableModel->setDataProgress(it->first, progress);
175 impl->m_VariableModel->setDataProgress(it->first, progress);
175 }
176 }
176 }
177 }
177
178
178 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
179 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
179 {
180 {
180 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
181 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
181 << QThread::currentThread()->objectName();
182 << QThread::currentThread()->objectName();
182
183
183 auto it = impl->m_VariableToIdentifierMap.find(variable);
184 auto it = impl->m_VariableToIdentifierMap.find(variable);
184 if (it != impl->m_VariableToIdentifierMap.cend()) {
185 if (it != impl->m_VariableToIdentifierMap.cend()) {
185 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
186 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
186 }
187 }
187 else {
188 else {
188 qCWarning(LOG_VariableController())
189 qCWarning(LOG_VariableController())
189 << tr("Aborting progression of inexistant variable detected !!!")
190 << tr("Aborting progression of inexistant variable detected !!!")
190 << QThread::currentThread()->objectName();
191 << QThread::currentThread()->objectName();
191 }
192 }
192 }
193 }
193
194
194
195
195 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
196 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
196 const SqpDateTime &dateTime)
197 const SqpDateTime &dateTime)
197 {
198 {
198 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
199 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
199 << QThread::currentThread()->objectName();
200 << QThread::currentThread()->objectName();
200 // we want to load data of the variable for the dateTime.
201 // we want to load data of the variable for the dateTime.
201 // First we check if the cache contains some of them.
202 // First we check if the cache contains some of them.
202 // For the other, we ask the provider to give them.
203 // For the other, we ask the provider to give them.
203 if (variable) {
204 if (variable) {
204
205
205 auto dateTimeListNotInCache
206 auto dateTimeListNotInCache
206 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
207 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
207
208
208 if (!dateTimeListNotInCache.empty()) {
209 if (!dateTimeListNotInCache.empty()) {
209 // Ask the provider for each data on the dateTimeListNotInCache
210 // Ask the provider for each data on the dateTimeListNotInCache
210 auto identifier = impl->m_VariableToIdentifierMap.at(variable);
211 auto identifier = impl->m_VariableToIdentifierMap.at(variable);
211 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
212 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
212 identifier,
213 identifier,
213 DataProviderParameters{std::move(dateTimeListNotInCache), variable->metadata()});
214 DataProviderParameters{std::move(dateTimeListNotInCache), variable->metadata()});
214 }
215 }
215 else {
216 else {
216 emit variable->updated();
217 emit variable->updated();
217 }
218 }
218 }
219 }
219 else {
220 else {
220 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
221 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
221 }
222 }
222 }
223 }
223
224
224
225
225 void VariableController::initialize()
226 void VariableController::initialize()
226 {
227 {
227 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
228 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
228 impl->m_WorkingMutex.lock();
229 impl->m_WorkingMutex.lock();
229 qCDebug(LOG_VariableController()) << tr("VariableController init END");
230 qCDebug(LOG_VariableController()) << tr("VariableController init END");
230 }
231 }
231
232
232 void VariableController::finalize()
233 void VariableController::finalize()
233 {
234 {
234 impl->m_WorkingMutex.unlock();
235 impl->m_WorkingMutex.unlock();
235 }
236 }
236
237
237 void VariableController::waitForFinish()
238 void VariableController::waitForFinish()
238 {
239 {
239 QMutexLocker locker{&impl->m_WorkingMutex};
240 QMutexLocker locker{&impl->m_WorkingMutex};
240 }
241 }
@@ -1,285 +1,311
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationGraphHelper.h"
3 #include "Visualization/VisualizationGraphHelper.h"
4 #include "ui_VisualizationGraphWidget.h"
4 #include "ui_VisualizationGraphWidget.h"
5
5
6 #include <Data/ArrayData.h>
6 #include <Data/ArrayData.h>
7 #include <Data/IDataSeries.h>
7 #include <Data/IDataSeries.h>
8 #include <SqpApplication.h>
8 #include <SqpApplication.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
10 #include <Variable/VariableController.h>
11
11
12 #include <unordered_map>
12 #include <unordered_map>
13
13
14 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
14 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
15
15
16 namespace {
16 namespace {
17
17
18 /// Key pressed to enable zoom on horizontal axis
18 /// Key pressed to enable zoom on horizontal axis
19 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
19 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
20
20
21 /// Key pressed to enable zoom on vertical axis
21 /// Key pressed to enable zoom on vertical axis
22 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
22 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
23
23
24 } // namespace
24 } // namespace
25
25
26 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
26 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
27
27
28 // 1 variable -> n qcpplot
28 // 1 variable -> n qcpplot
29 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
29 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
30 };
30 };
31
31
32 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
32 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
33 : QWidget{parent},
33 : QWidget{parent},
34 ui{new Ui::VisualizationGraphWidget},
34 ui{new Ui::VisualizationGraphWidget},
35 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
35 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
36 {
36 {
37 ui->setupUi(this);
37 ui->setupUi(this);
38
38
39 ui->graphNameLabel->setText(name);
39 ui->graphNameLabel->setText(name);
40
40
41 // 'Close' options : widget is deleted when closed
41 // 'Close' options : widget is deleted when closed
42 setAttribute(Qt::WA_DeleteOnClose);
42 setAttribute(Qt::WA_DeleteOnClose);
43 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
43 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
44 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
44 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
45
45
46 // Set qcpplot properties :
46 // Set qcpplot properties :
47 // - Drag (on x-axis) and zoom are enabled
47 // - Drag (on x-axis) and zoom are enabled
48 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
48 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
49 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
49 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
50 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
50 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
51 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
51 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
52 connect(ui->widget->xAxis,
52 connect(ui->widget->xAxis,
53 static_cast<void (QCPAxis::*)(const QCPRange &)>(&QCPAxis::rangeChanged), this,
53 static_cast<void (QCPAxis::*)(const QCPRange &)>(&QCPAxis::rangeChanged), this,
54 &VisualizationGraphWidget::onRangeChanged);
54 &VisualizationGraphWidget::onRangeChanged);
55
55
56 // Activates menu when right clicking on the graph
56 // Activates menu when right clicking on the graph
57 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
57 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
58 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
58 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
59 &VisualizationGraphWidget::onGraphMenuRequested);
59 &VisualizationGraphWidget::onGraphMenuRequested);
60
60
61 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
61 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
62 &VariableController::onRequestDataLoading);
62 &VariableController::onRequestDataLoading);
63 }
63 }
64
64
65
65
66 VisualizationGraphWidget::~VisualizationGraphWidget()
66 VisualizationGraphWidget::~VisualizationGraphWidget()
67 {
67 {
68 delete ui;
68 delete ui;
69 }
69 }
70
70
71 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
71 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
72 {
72 {
73 // Uses delegate to create the qcpplot components according to the variable
73 // Uses delegate to create the qcpplot components according to the variable
74 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
74 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
75
75
76 for (auto createdPlottable : qAsConst(createdPlottables)) {
76 for (auto createdPlottable : qAsConst(createdPlottables)) {
77 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
77 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
78 }
78 }
79
79
80 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
80 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
81 }
81 }
82 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
82 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
83 {
83 {
84
84
85 // when adding a variable, we need to set its time range to the current graph range
85 // when adding a variable, we need to set its time range to the current graph range
86 auto grapheRange = ui->widget->xAxis->range();
86 auto grapheRange = ui->widget->xAxis->range();
87 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
87 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
88 variable->setDateTime(dateTime);
88 variable->setDateTime(dateTime);
89
89
90 auto variableDateTimeWithTolerance = dateTime;
90 auto variableDateTimeWithTolerance = dateTime;
91
91
92 // add 10% tolerance for each side
92 // add 10% tolerance for each side
93 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
93 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
94 variableDateTimeWithTolerance.m_TStart -= tolerance;
94 variableDateTimeWithTolerance.m_TStart -= tolerance;
95 variableDateTimeWithTolerance.m_TEnd += tolerance;
95 variableDateTimeWithTolerance.m_TEnd += tolerance;
96
96
97 // Uses delegate to create the qcpplot components according to the variable
97 // Uses delegate to create the qcpplot components according to the variable
98 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
98 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
99
99
100 for (auto createdPlottable : qAsConst(createdPlottables)) {
100 for (auto createdPlottable : qAsConst(createdPlottables)) {
101 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
101 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
102 }
102 }
103
103
104 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
104 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
105
105
106 // CHangement detected, we need to ask controller to request data loading
106 // CHangement detected, we need to ask controller to request data loading
107 emit requestDataLoading(variable, variableDateTimeWithTolerance);
107 emit requestDataLoading(variable, variableDateTimeWithTolerance);
108 }
108 }
109
109
110 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
110 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
111 {
111 {
112 // Each component associated to the variable :
112 // Each component associated to the variable :
113 // - is removed from qcpplot (which deletes it)
113 // - is removed from qcpplot (which deletes it)
114 // - is no longer referenced in the map
114 // - is no longer referenced in the map
115 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
115 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
116 for (auto it = componentsIt.first; it != componentsIt.second;) {
116 for (auto it = componentsIt.first; it != componentsIt.second;) {
117 ui->widget->removePlottable(it->second);
117 ui->widget->removePlottable(it->second);
118 it = impl->m_VariableToPlotMultiMap.erase(it);
118 it = impl->m_VariableToPlotMultiMap.erase(it);
119 }
119 }
120
120
121 // Updates graph
121 // Updates graph
122 ui->widget->replot();
122 ui->widget->replot();
123 }
123 }
124
124
125 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
125 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
126 {
126 {
127 if (visitor) {
127 if (visitor) {
128 visitor->visit(this);
128 visitor->visit(this);
129 }
129 }
130 else {
130 else {
131 qCCritical(LOG_VisualizationGraphWidget())
131 qCCritical(LOG_VisualizationGraphWidget())
132 << tr("Can't visit widget : the visitor is null");
132 << tr("Can't visit widget : the visitor is null");
133 }
133 }
134 }
134 }
135
135
136 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
136 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
137 {
137 {
138 /// @todo : for the moment, a graph can always accomodate a variable
138 /// @todo : for the moment, a graph can always accomodate a variable
139 Q_UNUSED(variable);
139 Q_UNUSED(variable);
140 return true;
140 return true;
141 }
141 }
142
142
143 bool VisualizationGraphWidget::contains(const Variable &variable) const
143 bool VisualizationGraphWidget::contains(const Variable &variable) const
144 {
144 {
145 // Finds the variable among the keys of the map
145 // Finds the variable among the keys of the map
146 auto variablePtr = &variable;
146 auto variablePtr = &variable;
147 auto findVariable
147 auto findVariable
148 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
148 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
149
149
150 auto end = impl->m_VariableToPlotMultiMap.cend();
150 auto end = impl->m_VariableToPlotMultiMap.cend();
151 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
151 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
152 return it != end;
152 return it != end;
153 }
153 }
154
154
155 QString VisualizationGraphWidget::name() const
155 QString VisualizationGraphWidget::name() const
156 {
156 {
157 return ui->graphNameLabel->text();
157 return ui->graphNameLabel->text();
158 }
158 }
159
159
160 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
160 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
161 {
161 {
162 QMenu graphMenu{};
162 QMenu graphMenu{};
163
163
164 // Iterates on variables (unique keys)
164 // Iterates on variables (unique keys)
165 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
165 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
166 end = impl->m_VariableToPlotMultiMap.cend();
166 end = impl->m_VariableToPlotMultiMap.cend();
167 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
167 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
168 // 'Remove variable' action
168 // 'Remove variable' action
169 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
169 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
170 [ this, var = it->first ]() { removeVariable(var); });
170 [ this, var = it->first ]() { removeVariable(var); });
171 }
171 }
172
172
173 if (!graphMenu.isEmpty()) {
173 if (!graphMenu.isEmpty()) {
174 graphMenu.exec(mapToGlobal(pos));
174 graphMenu.exec(mapToGlobal(pos));
175 }
175 }
176 }
176 }
177
177
178 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1)
178 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1)
179 {
179 {
180 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
180 qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
181 << QThread::currentThread()->objectName();
181 << QThread::currentThread()->objectName();
182
182
183 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
183 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
184 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
184 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
185
185
186 auto variable = it->first;
186 auto variable = it->first;
187 auto dateTime = SqpDateTime{t1.lower, t1.upper};
187 auto dateTime = SqpDateTime{t1.lower, t1.upper};
188 auto dateTimeRange = dateTime;
188
189
189 if (!variable->contains(dateTime)) {
190 auto tolerance = 0.2 * (dateTime.m_TEnd - dateTime.m_TStart);
191 auto variableDateTimeWithTolerance = dateTime;
192 variableDateTimeWithTolerance.m_TStart -= tolerance;
193 variableDateTimeWithTolerance.m_TEnd += tolerance;
194
195 qCInfo(LOG_VisualizationGraphWidget()) << "v" << dateTime;
196 qCInfo(LOG_VisualizationGraphWidget()) << "vtol" << variableDateTimeWithTolerance;
197 // If new range with tol is upper than variable datetime parameters. we need to request new
198 // data
199 if (!variable->contains(variableDateTimeWithTolerance)) {
190
200
191 auto variableDateTimeWithTolerance = dateTime;
201 auto variableDateTimeWithTolerance = dateTime;
192 if (!variable->isInside(dateTime)) {
202 if (!variable->isInside(dateTime)) {
193 auto variableDateTime = variable->dateTime();
203 auto variableDateTime = variable->dateTime();
194 if (variableDateTime.m_TStart < dateTime.m_TStart) {
204 if (variableDateTime.m_TStart < dateTime.m_TStart) {
195 qCDebug(LOG_VisualizationGraphWidget()) << tr("TDetection pan to right:");
205 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:");
196
206
197 auto diffEndToKeepDelta = dateTime.m_TEnd - variableDateTime.m_TEnd;
207 auto diffEndToKeepDelta = dateTime.m_TEnd - variableDateTime.m_TEnd;
198 dateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
208 dateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
199 // Tolerance have to be added to the right
209 // Tolerance have to be added to the right
200 // add 10% tolerance for right (end) side
210 // add 10% tolerance for right (end) side
201 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
211 // auto tolerance = 0.1 * (dateTime.m_TEnd -
212 // dateTime.m_TStart);
202 variableDateTimeWithTolerance.m_TEnd += tolerance;
213 variableDateTimeWithTolerance.m_TEnd += tolerance;
203 }
214 }
204 else if (variableDateTime.m_TEnd > dateTime.m_TEnd) {
215 else if (variableDateTime.m_TEnd > dateTime.m_TEnd) {
205 qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection pan to left: ");
216 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: ");
206 auto diffStartToKeepDelta = variableDateTime.m_TStart - dateTime.m_TStart;
217 auto diffStartToKeepDelta = variableDateTime.m_TStart - dateTime.m_TStart;
207 dateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
218 dateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
208 // Tolerance have to be added to the left
219 // Tolerance have to be added to the left
209 // add 10% tolerance for left (start) side
220 // add 10% tolerance for left (start) side
210 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
221 tolerance = 0.2 * (dateTime.m_TEnd - dateTime.m_TStart);
211 variableDateTimeWithTolerance.m_TStart -= tolerance;
222 variableDateTimeWithTolerance.m_TStart -= tolerance;
212 }
223 }
213 else {
224 else {
214 qCWarning(LOG_VisualizationGraphWidget())
225 qCWarning(LOG_VisualizationGraphWidget())
215 << tr("Detection anormal zoom detection: ");
226 << tr("Detection anormal zoom detection: ");
216 }
227 }
217 }
228 }
218 else {
229 else {
219 qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection zoom out: ");
230 qCInfo(LOG_VisualizationGraphWidget()) << tr("Detection zoom out: ");
220 // add 10% tolerance for each side
231 // add 10% tolerance for each side
221 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
232 tolerance = 0.2 * (dateTime.m_TEnd - dateTime.m_TStart);
222 variableDateTimeWithTolerance.m_TStart -= tolerance;
233 variableDateTimeWithTolerance.m_TStart -= tolerance;
223 variableDateTimeWithTolerance.m_TEnd += tolerance;
234 variableDateTimeWithTolerance.m_TEnd += tolerance;
224 }
235 }
225 variable->setDateTime(dateTime);
236 if (!variable->contains(dateTimeRange)) {
237 qCInfo(LOG_VisualizationGraphWidget()) << "newv" << dateTime;
238 variable->setDateTime(dateTime);
239 }
226
240
241 qCInfo(LOG_VisualizationGraphWidget()) << tr("Request data detection: ");
227 // CHangement detected, we need to ask controller to request data loading
242 // CHangement detected, we need to ask controller to request data loading
228 emit requestDataLoading(variable, variableDateTimeWithTolerance);
243 emit requestDataLoading(variable, variableDateTimeWithTolerance);
229 }
244 }
230 else {
245 else {
231 qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection zoom in: ");
246 qCInfo(LOG_VisualizationGraphWidget()) << tr("Detection zoom in: ");
232 }
247 }
233 }
248 }
234 }
249 }
235
250
236 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
251 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
237 {
252 {
238 auto zoomOrientations = QFlags<Qt::Orientation>{};
253 auto zoomOrientations = QFlags<Qt::Orientation>{};
239
254
240 // Lambda that enables a zoom orientation if the key modifier related to this orientation
255 // Lambda that enables a zoom orientation if the key modifier related to this orientation
241 // has
256 // has
242 // been pressed
257 // been pressed
243 auto enableOrientation
258 auto enableOrientation
244 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
259 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
245 auto orientationEnabled = event->modifiers().testFlag(modifier);
260 auto orientationEnabled = event->modifiers().testFlag(modifier);
246 zoomOrientations.setFlag(orientation, orientationEnabled);
261 zoomOrientations.setFlag(orientation, orientationEnabled);
247 };
262 };
248 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
263 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
249 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
264 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
250
265
251 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
266 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
252 }
267 }
253
268
254 void VisualizationGraphWidget::onDataCacheVariableUpdated()
269 void VisualizationGraphWidget::onDataCacheVariableUpdated()
255 {
270 {
256 // NOTE:
271 // NOTE:
257 // We don't want to call the method for each component of a variable unitarily, but for
272 // We don't want to call the method for each component of a variable unitarily, but for
258 // all
273 // all
259 // its components at once (eg its three components in the case of a vector).
274 // its components at once (eg its three components in the case of a vector).
260
275
261 // The unordered_multimap does not do this easily, so the question is whether to:
276 // The unordered_multimap does not do this easily, so the question is whether to:
262 // - use an ordered_multimap and the algos of std to group the values by key
277 // - use an ordered_multimap and the algos of std to group the values by key
263 // - use a map (unique keys) and store as values directly the list of components
278 // - use a map (unique keys) and store as values directly the list of components
264
279
280 auto grapheRange = ui->widget->xAxis->range();
281 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
282
265 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
283 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
266 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
284 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
267 auto variable = it->first;
285 auto variable = it->first;
268 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
286 qCInfo(LOG_VisualizationGraphWidget())
269 variable->dataSeries(), variable->dateTime());
287 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S"
288 << variable->dateTime();
289 qCInfo(LOG_VisualizationGraphWidget())
290 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
291 if (dateTime.contains(variable->dateTime()) || dateTime.intersect(variable->dateTime())) {
292
293 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
294 variable->dataSeries(), variable->dateTime());
295 }
270 }
296 }
271 }
297 }
272
298
273 void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable)
299 void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable)
274 {
300 {
275 auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable);
301 auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable);
276
302
277 auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{};
303 auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{};
278
304
279 for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) {
305 for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) {
280 abstractPlotableVect.push_back(it->second);
306 abstractPlotableVect.push_back(it->second);
281 }
307 }
282
308
283 VisualizationGraphHelper::updateData(abstractPlotableVect, variable->dataSeries(),
309 VisualizationGraphHelper::updateData(abstractPlotableVect, variable->dataSeries(),
284 variable->dateTime());
310 variable->dateTime());
285 }
311 }
General Comments 0
You need to be logged in to leave comments. Login now