@@ -1,1 +1,1 | |||
|
1 | Subproject commit c08d1b8ad2976824def52cf0fca26a72b1069356 | |
|
1 | Subproject commit a05b0ab234936e28b6ba79535ccaee297d83a1e8 |
@@ -111,8 +111,7 public: | |||
|
111 | 111 | |
|
112 | 112 | signals: |
|
113 | 113 | void synchronize(const DateTimeRange &range, const DateTimeRange &oldRange); |
|
114 |
void |
|
|
115 | bool synchronise); | |
|
114 | void changeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange &range); | |
|
116 | 115 | |
|
117 | 116 | /// Signal emitted when the variable is about to be removed from the graph |
|
118 | 117 | void variableAboutToBeRemoved(std::shared_ptr<Variable> var); |
@@ -35,9 +35,6 public: | |||
|
35 | 35 | sqpApp->variableController().createVariable(variableName,variableMetadata,variableProvider,sqpApp->timeController().dateTime()); |
|
36 | 36 | }); |
|
37 | 37 | |
|
38 | // connect(m_VariableController->variableModel(), &VariableModel::requestVariable, | |
|
39 | // m_DataSourceController.get(), &DataSourceController::requestVariable); | |
|
40 | ||
|
41 | 38 | // VariableController <-> VisualizationController |
|
42 | 39 | // connect(m_VariableController.get(), |
|
43 | 40 | // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), |
@@ -80,6 +80,7 void TimeWidget::onTimeUpdateRequested() | |||
|
80 | 80 | { |
|
81 | 81 | auto dateTime = timeRange(); |
|
82 | 82 | emit timeUpdated(std::move(dateTime)); |
|
83 | sqpApp->timeController().setDateTimeRange(dateTime); | |
|
83 | 84 | } |
|
84 | 85 | |
|
85 | 86 | void TimeWidget::dragEnterEvent(QDragEnterEvent *event) |
@@ -297,35 +297,6 void VisualizationGraphWidget::setFlags(GraphFlags flags) | |||
|
297 | 297 | |
|
298 | 298 | void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, DateTimeRange range) |
|
299 | 299 | { |
|
300 | /// Lambda used to set graph's units and range according to the variable passed in parameter | |
|
301 | auto loadRange = [this](std::shared_ptr<Variable> variable, const DateTimeRange &range) { | |
|
302 | impl->m_RenderingDelegate->setAxesUnits(*variable); | |
|
303 | ||
|
304 | this->setFlags(GraphFlag::DisableAll); | |
|
305 | setGraphRange(range); | |
|
306 | this->setFlags(GraphFlag::EnableAll); | |
|
307 | emit requestDataLoading({variable}, range, false); | |
|
308 | }; | |
|
309 | ||
|
310 | connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated())); | |
|
311 | ||
|
312 | // Calls update of graph's range and units when the data of the variable have been initialized. | |
|
313 | // Note: we use QueuedConnection here as the update event must be called in the UI thread | |
|
314 | connect(variable.get(), &Variable::dataInitialized, this, | |
|
315 | [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() { | |
|
316 | if (auto var = varW.lock()) { | |
|
317 | // If the variable is the first added in the graph, we load its range | |
|
318 | auto firstVariableInGraph = range == INVALID_RANGE; | |
|
319 | auto loadedRange = graphRange(); | |
|
320 | if (impl->m_VariableAutoRangeOnInit) { | |
|
321 | loadedRange = firstVariableInGraph ? var->range() : range; | |
|
322 | } | |
|
323 | loadRange(var, loadedRange); | |
|
324 | setYRange(var); | |
|
325 | } | |
|
326 | }, | |
|
327 | Qt::QueuedConnection); | |
|
328 | ||
|
329 | 300 | // Uses delegate to create the qcpplot components according to the variable |
|
330 | 301 | auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget); |
|
331 | 302 | |
@@ -336,9 +307,17 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, D | |||
|
336 | 307 | |
|
337 | 308 | // If the variable already has its data loaded, load its units and its range in the graph |
|
338 | 309 | if (variable->dataSeries() != nullptr) { |
|
339 | loadRange(variable, range); | |
|
310 | impl->m_RenderingDelegate->setAxesUnits(*variable); | |
|
311 | this->setFlags(GraphFlag::DisableAll); | |
|
312 | setGraphRange(range); | |
|
313 | this->setFlags(GraphFlag::EnableAll); | |
|
340 | 314 | } |
|
341 | ||
|
315 | connect(variable.get(),&Variable::updated, | |
|
316 | [variable=variable,this]() | |
|
317 | { | |
|
318 | QMetaObject::invokeMethod(this,[variable=variable,this](){this->onUpdateVarDisplaying(variable,this->graphRange());}); | |
|
319 | }); | |
|
320 | this->onUpdateVarDisplaying(variable,range);//My bullshit | |
|
342 | 321 | emit variableAdded(variable); |
|
343 | 322 | } |
|
344 | 323 | |
@@ -395,8 +374,6 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept | |||
|
395 | 374 | |
|
396 | 375 | void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool calibration) |
|
397 | 376 | { |
|
398 | qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START"); | |
|
399 | ||
|
400 | 377 | if (calibration) { |
|
401 | 378 | impl->m_IsCalibration = true; |
|
402 | 379 | } |
@@ -407,8 +384,6 void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool ca | |||
|
407 | 384 | if (calibration) { |
|
408 | 385 | impl->m_IsCalibration = false; |
|
409 | 386 | } |
|
410 | ||
|
411 | qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END"); | |
|
412 | 387 | } |
|
413 | 388 | |
|
414 | 389 | void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value) |
@@ -768,29 +743,19 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept | |||
|
768 | 743 | |
|
769 | 744 | void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2) |
|
770 | 745 | { |
|
771 | qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged") | |
|
772 | << QThread::currentThread()->objectName() << "DoAcqui" | |
|
773 | << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition); | |
|
774 | ||
|
775 | 746 | auto graphRange = DateTimeRange{t1.lower, t1.upper}; |
|
776 | 747 | auto oldGraphRange = DateTimeRange{t2.lower, t2.upper}; |
|
777 | 748 | |
|
778 | 749 | if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) { |
|
779 | QVector<std::shared_ptr<Variable> > variableUnderGraphVector; | |
|
780 | ||
|
781 | 750 | for (auto it = impl->m_VariableToPlotMultiMap.begin(), |
|
782 | 751 | end = impl->m_VariableToPlotMultiMap.end(); |
|
783 | 752 | it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) { |
|
784 | variableUnderGraphVector.push_back(it->first); | |
|
753 | sqpApp->variableController().asyncChangeRange(it->first, graphRange); | |
|
785 | 754 | } |
|
786 | emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, | |
|
787 | !impl->m_IsCalibration); | |
|
788 | 755 | } |
|
789 | 756 | |
|
790 |
if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) |
|
|
791 | qCDebug(LOG_VisualizationGraphWidget()) | |
|
792 | << tr("TORM: VisualizationGraphWidget::Synchronize notify !!") | |
|
793 | << QThread::currentThread()->objectName() << graphRange << oldGraphRange; | |
|
757 | if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) | |
|
758 | { | |
|
794 | 759 | emit synchronize(graphRange, oldGraphRange); |
|
795 | 760 | } |
|
796 | 761 | |
@@ -804,9 +769,6 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange | |||
|
804 | 769 | parentZone->notifyMouseLeaveGraph(this); |
|
805 | 770 | } |
|
806 | 771 | } |
|
807 | else { | |
|
808 | qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget"; | |
|
809 | } | |
|
810 | 772 | |
|
811 | 773 | // Quits calibration |
|
812 | 774 | impl->m_IsCalibration = false; |
@@ -841,9 +803,6 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept | |||
|
841 | 803 | parentZone->notifyMouseLeaveGraph(this); |
|
842 | 804 | } |
|
843 | 805 | } |
|
844 | else { | |
|
845 | qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget"; | |
|
846 | } | |
|
847 | 806 | |
|
848 | 807 | // Search for the selection zone under the mouse |
|
849 | 808 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot()); |
@@ -909,7 +868,7 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept | |||
|
909 | 868 | plot().setNotAntialiasedElements(QCP::aeAll); |
|
910 | 869 | } |
|
911 | 870 | |
|
912 | plot().replot(QCustomPlot::rpQueuedReplot); | |
|
871 | //plot().replot(QCustomPlot::rpQueuedReplot); | |
|
913 | 872 | } |
|
914 | 873 | } |
|
915 | 874 | } |
@@ -23,22 +23,8 public: | |||
|
23 | 23 | explicit AmdaProvider(); |
|
24 | 24 | std::shared_ptr<IDataProvider> clone() const override; |
|
25 | 25 | |
|
26 |
v |
|
|
26 | virtual IDataSeries *getData(const DataProviderParameters ¶meters)override; | |
|
27 | 27 | |
|
28 | void requestDataAborting(QUuid acqIdentifier) override; | |
|
29 | ||
|
30 | private: | |
|
31 | void retrieveData(QUuid token, const DateTimeRange &dateTime, const QVariantHash &data); | |
|
32 | ||
|
33 | void updateRequestProgress(QUuid acqIdentifier, std::shared_ptr<QNetworkRequest> request, | |
|
34 | double progress); | |
|
35 | ||
|
36 | std::map<QUuid, std::map<std::shared_ptr<QNetworkRequest>, double> > | |
|
37 | m_AcqIdToRequestProgressMap; | |
|
38 | ||
|
39 | private slots: | |
|
40 | void onReplyDownloadProgress(QUuid acqIdentifier, | |
|
41 | std::shared_ptr<QNetworkRequest> networkRequest, double progress); | |
|
42 | 28 | }; |
|
43 | 29 | |
|
44 | 30 | #endif // SCIQLOP_AMDAPROVIDER_H |
@@ -16,6 +16,8 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParser) | |||
|
16 | 16 | struct SCIQLOP_AMDA_EXPORT AmdaResultParser { |
|
17 | 17 | static std::shared_ptr<IDataSeries> readTxt(const QString &filePath, |
|
18 | 18 | DataSeriesType valueType) noexcept; |
|
19 | static IDataSeries* readTxt(QTextStream stream, | |
|
20 | DataSeriesType type)noexcept; | |
|
19 | 21 | }; |
|
20 | 22 | |
|
21 | 23 | #endif // SCIQLOP_AMDARESULTPARSER_H |
@@ -33,7 +33,7 struct IAmdaResultParserHelper { | |||
|
33 | 33 | /// @warning as the data are moved in the data series, the helper shouldn't be used after |
|
34 | 34 | /// calling this method |
|
35 | 35 | /// @return the data series created |
|
36 |
virtual |
|
|
36 | virtual IDataSeries* createSeries() = 0; | |
|
37 | 37 | |
|
38 | 38 | /// Reads a line from the AMDA file to extract a property that will be used to generate the data |
|
39 | 39 | /// series |
@@ -51,7 +51,7 struct IAmdaResultParserHelper { | |||
|
51 | 51 | class ScalarParserHelper : public IAmdaResultParserHelper { |
|
52 | 52 | public: |
|
53 | 53 | bool checkProperties() override; |
|
54 |
|
|
|
54 | IDataSeries* createSeries() override; | |
|
55 | 55 | void readPropertyLine(const QString &line) override; |
|
56 | 56 | void readResultLine(const QString &line) override; |
|
57 | 57 | |
@@ -70,7 +70,7 private: | |||
|
70 | 70 | class SpectrogramParserHelper : public IAmdaResultParserHelper { |
|
71 | 71 | public: |
|
72 | 72 | bool checkProperties() override; |
|
73 |
|
|
|
73 | IDataSeries* createSeries() override; | |
|
74 | 74 | void readPropertyLine(const QString &line) override; |
|
75 | 75 | void readResultLine(const QString &line) override; |
|
76 | 76 | |
@@ -91,7 +91,7 private: | |||
|
91 | 91 | class VectorParserHelper : public IAmdaResultParserHelper { |
|
92 | 92 | public: |
|
93 | 93 | bool checkProperties() override; |
|
94 |
|
|
|
94 | IDataSeries* createSeries() override; | |
|
95 | 95 | void readPropertyLine(const QString &line) override; |
|
96 | 96 | void readResultLine(const QString &line) override; |
|
97 | 97 |
@@ -13,6 +13,8 | |||
|
13 | 13 | #include <QNetworkReply> |
|
14 | 14 | #include <QTemporaryFile> |
|
15 | 15 | #include <QThread> |
|
16 | #include <QJsonDocument> | |
|
17 | #include <Network/Downloader.h> | |
|
16 | 18 | |
|
17 | 19 | Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider") |
|
18 | 20 | |
@@ -29,6 +31,16 const auto AMDA_URL_FORMAT = QStringLiteral( | |||
|
29 | 31 | "getParameter.php?startTime=%2&stopTime=%3¶meterID=%4&outputFormat=ASCII&" |
|
30 | 32 | "timeFormat=ISO8601&gzip=0"); |
|
31 | 33 | |
|
34 | const auto AMDA_URL_FORMAT_WITH_TOKEN = QStringLiteral( | |
|
35 | "http://%1/php/rest/" | |
|
36 | "getParameter.php?startTime=%2&stopTime=%3¶meterID=%4&outputFormat=ASCII&" | |
|
37 | "timeFormat=ISO8601&gzip=0&" | |
|
38 | "token=%5"); | |
|
39 | ||
|
40 | const auto AMDA_TOKEN_URL_FORMAT = QStringLiteral( | |
|
41 | "http://%1/php/rest/" | |
|
42 | "auth.php"); | |
|
43 | ||
|
32 | 44 | /// Dates format passed in the URL (e.g 2013-09-23T09:00) |
|
33 | 45 | const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss"); |
|
34 | 46 | |
@@ -44,21 +56,7 QString dateFormat(double sqpRange) noexcept | |||
|
44 | 56 | |
|
45 | 57 | AmdaProvider::AmdaProvider() |
|
46 | 58 | { |
|
47 | qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread(); | |
|
48 | if (auto app = sqpApp) { | |
|
49 | auto &networkController = app->networkController(); | |
|
50 | connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid, | |
|
51 | std::function<void(QNetworkReply *, QUuid)>)), | |
|
52 | &networkController, | |
|
53 | SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid, | |
|
54 | std::function<void(QNetworkReply *, QUuid)>))); | |
|
55 | ||
|
56 | 59 | |
|
57 | connect(&sqpApp->networkController(), | |
|
58 | SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)), | |
|
59 | this, | |
|
60 | SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double))); | |
|
61 | } | |
|
62 | 60 | } |
|
63 | 61 | |
|
64 | 62 | std::shared_ptr<IDataProvider> AmdaProvider::clone() const |
@@ -67,208 +65,24 std::shared_ptr<IDataProvider> AmdaProvider::clone() const | |||
|
67 | 65 | return std::make_shared<AmdaProvider>(); |
|
68 | 66 | } |
|
69 | 67 | |
|
70 |
|
|
|
71 | { | |
|
72 | // NOTE: Try to use multithread if possible | |
|
73 | const auto times = parameters.m_Times; | |
|
74 | const auto data = parameters.m_Data; | |
|
75 | for (const auto &dateTime : qAsConst(times)) { | |
|
76 | qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier | |
|
77 | << dateTime; | |
|
78 | this->retrieveData(acqIdentifier, dateTime, data); | |
|
79 | ||
|
80 | ||
|
81 | // TORM when AMDA will support quick asynchrone request | |
|
82 | QThread::msleep(1000); | |
|
83 | } | |
|
84 | } | |
|
85 | ||
|
86 | void AmdaProvider::requestDataAborting(QUuid acqIdentifier) | |
|
87 | { | |
|
88 | if (auto app = sqpApp) { | |
|
89 | auto &networkController = app->networkController(); | |
|
90 | networkController.onReplyCanceled(acqIdentifier); | |
|
91 | } | |
|
92 | } | |
|
93 | ||
|
94 | void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier, | |
|
95 | std::shared_ptr<QNetworkRequest> networkRequest, | |
|
96 | double progress) | |
|
97 | { | |
|
98 | qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier | |
|
99 | << networkRequest.get() << progress; | |
|
100 | auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier); | |
|
101 | if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) { | |
|
102 | ||
|
103 | // Update the progression for the current request | |
|
104 | auto requestPtr = networkRequest; | |
|
105 | auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; }; | |
|
106 | ||
|
107 | auto &requestProgressMap = acqIdToRequestProgressMapIt->second; | |
|
108 | auto requestProgressMapEnd = requestProgressMap.end(); | |
|
109 | auto requestProgressMapIt | |
|
110 | = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest); | |
|
111 | ||
|
112 | if (requestProgressMapIt != requestProgressMapEnd) { | |
|
113 | requestProgressMapIt->second = progress; | |
|
114 | } | |
|
115 | else { | |
|
116 | // This case can happened when a progression is send after the request has been | |
|
117 | // finished. | |
|
118 | // Generaly the case when aborting a request | |
|
119 | qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier | |
|
120 | << networkRequest.get() << progress; | |
|
121 | } | |
|
122 | ||
|
123 | // Compute the current final progress and notify it | |
|
124 | double finalProgress = 0.0; | |
|
125 | ||
|
126 | auto fraq = requestProgressMap.size(); | |
|
127 | ||
|
128 | for (auto requestProgress : requestProgressMap) { | |
|
129 | finalProgress += requestProgress.second; | |
|
130 | qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:") | |
|
131 | << finalProgress << requestProgress.second; | |
|
132 | } | |
|
133 | ||
|
134 | if (fraq > 0) { | |
|
135 | finalProgress = finalProgress / fraq; | |
|
136 | } | |
|
137 | ||
|
138 | qCDebug(LOG_AmdaProvider()) << tr("Current final progress: ") << fraq << finalProgress; | |
|
139 | emit dataProvidedProgress(acqIdentifier, finalProgress); | |
|
140 | } | |
|
141 | else { | |
|
142 | // This case can happened when a progression is send after the request has been finished. | |
|
143 | // Generaly the case when aborting a request | |
|
144 | emit dataProvidedProgress(acqIdentifier, 100.0); | |
|
145 | } | |
|
146 | } | |
|
147 | ||
|
148 | void AmdaProvider::retrieveData(QUuid token, const DateTimeRange &dateTime, const QVariantHash &data) | |
|
68 | IDataSeries* AmdaProvider::getData(const DataProviderParameters ¶meters) | |
|
149 | 69 | { |
|
150 | // Retrieves product ID from data: if the value is invalid, no request is made | |
|
151 | auto productId = data.value(AMDA_XML_ID_KEY).toString(); | |
|
152 | if (productId.isNull()) { | |
|
153 | qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id"); | |
|
154 | return; | |
|
155 | } | |
|
156 | ||
|
157 | // Retrieves the data type that determines whether the expected format for the result file is | |
|
158 | // scalar, vector... | |
|
70 | auto range = parameters.m_Times.front(); | |
|
71 | auto metaData = parameters.m_Data; | |
|
72 | auto productId = metaData.value(AMDA_XML_ID_KEY).toString(); | |
|
159 | 73 | auto productValueType |
|
160 |
= DataSeriesTypeUtils::fromString( |
|
|
161 | ||
|
162 | // /////////// // | |
|
163 | // Creates URL // | |
|
164 | // /////////// // | |
|
165 | ||
|
166 | auto startDate = dateFormat(dateTime.m_TStart); | |
|
167 | auto endDate = dateFormat(dateTime.m_TEnd); | |
|
168 | ||
|
169 | QVariantHash urlProperties{{AMDA_SERVER_KEY, data.value(AMDA_SERVER_KEY)}}; | |
|
170 | auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties), | |
|
171 | startDate, endDate, productId)}; | |
|
172 | qCInfo(LOG_AmdaProvider()) << tr("TORM AmdaProvider::retrieveData url:") << url; | |
|
173 | auto tempFile = std::make_shared<QTemporaryFile>(); | |
|
174 | ||
|
175 | // LAMBDA | |
|
176 | auto httpDownloadFinished = [this, dateTime, tempFile, | |
|
177 | productValueType](QNetworkReply *reply, QUuid dataId) noexcept { | |
|
178 | ||
|
179 | // Don't do anything if the reply was abort | |
|
180 | if (reply->error() == QNetworkReply::NoError) { | |
|
181 | ||
|
182 | if (tempFile) { | |
|
183 | auto replyReadAll = reply->readAll(); | |
|
184 | if (!replyReadAll.isEmpty()) { | |
|
185 | tempFile->write(replyReadAll); | |
|
186 | } | |
|
187 | tempFile->close(); | |
|
188 | ||
|
189 | // Parse results file | |
|
190 | if (auto dataSeries | |
|
191 | = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) { | |
|
192 | emit dataProvided(dataId, dataSeries, dateTime); | |
|
193 | } | |
|
194 | else { | |
|
195 | /// @todo ALX : debug | |
|
196 | emit dataProvidedFailed(dataId); | |
|
197 | } | |
|
198 | } | |
|
199 | m_AcqIdToRequestProgressMap.erase(dataId); | |
|
200 | } | |
|
201 | else { | |
|
202 | qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR"); | |
|
203 | emit dataProvidedFailed(dataId); | |
|
204 | } | |
|
205 | ||
|
206 | }; | |
|
207 | auto httpFinishedLambda | |
|
208 | = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept { | |
|
209 | ||
|
210 | // Don't do anything if the reply was abort | |
|
211 | if (reply->error() == QNetworkReply::NoError) { | |
|
212 | auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()}; | |
|
213 | ||
|
214 | qCInfo(LOG_AmdaProvider()) | |
|
215 | << tr("TORM AmdaProvider::retrieveData downloadFileUrl:") << downloadFileUrl; | |
|
216 | // Executes request for downloading file // | |
|
217 | ||
|
218 | // Creates destination file | |
|
219 | if (tempFile->open()) { | |
|
220 | // Executes request and store the request for progression | |
|
221 | auto request = std::make_shared<QNetworkRequest>(downloadFileUrl); | |
|
222 | updateRequestProgress(dataId, request, 0.0); | |
|
223 | emit requestConstructed(request, dataId, httpDownloadFinished); | |
|
224 | } | |
|
225 | else { | |
|
226 | emit dataProvidedFailed(dataId); | |
|
227 | } | |
|
228 | } | |
|
229 | else { | |
|
230 | qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR"); | |
|
231 | m_AcqIdToRequestProgressMap.erase(dataId); | |
|
232 | emit dataProvidedFailed(dataId); | |
|
233 | } | |
|
234 | }; | |
|
235 | ||
|
236 | // //////////////// // | |
|
237 | // Executes request // | |
|
238 | // //////////////// // | |
|
239 | ||
|
240 | auto request = std::make_shared<QNetworkRequest>(url); | |
|
241 | qCDebug(LOG_AmdaProvider()) << tr("First Request creation") << request.get(); | |
|
242 | updateRequestProgress(token, request, 0.0); | |
|
243 | ||
|
244 | emit requestConstructed(request, token, httpFinishedLambda); | |
|
74 | = DataSeriesTypeUtils::fromString(metaData.value(AMDA_DATA_TYPE_KEY).toString()); | |
|
75 | auto startDate = dateFormat(range.m_TStart); | |
|
76 | auto endDate = dateFormat(range.m_TEnd); | |
|
77 | QVariantHash urlProperties{{AMDA_SERVER_KEY, metaData.value(AMDA_SERVER_KEY)}}; | |
|
78 | auto token_url = QString{AMDA_TOKEN_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties)); | |
|
79 | auto response = Downloader::get(token_url); | |
|
80 | auto url = QString{AMDA_URL_FORMAT_WITH_TOKEN}.arg(AmdaServer::instance().url(urlProperties), | |
|
81 | startDate, endDate, productId, QString(response.data())); | |
|
82 | response = Downloader::get(url); | |
|
83 | auto test = QJsonDocument::fromJson(response.data()); | |
|
84 | url = test["dataFileURLs"].toString(); | |
|
85 | response = Downloader::get(url); | |
|
86 | return AmdaResultParser::readTxt(QTextStream{response.data()},productValueType); | |
|
245 | 87 | } |
|
246 | 88 | |
|
247 | void AmdaProvider::updateRequestProgress(QUuid acqIdentifier, | |
|
248 | std::shared_ptr<QNetworkRequest> request, double progress) | |
|
249 | { | |
|
250 | qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress request") << request.get(); | |
|
251 | auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier); | |
|
252 | if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) { | |
|
253 | auto &requestProgressMap = acqIdToRequestProgressMapIt->second; | |
|
254 | auto requestProgressMapIt = requestProgressMap.find(request); | |
|
255 | if (requestProgressMapIt != requestProgressMap.end()) { | |
|
256 | requestProgressMapIt->second = progress; | |
|
257 | qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request") | |
|
258 | << acqIdentifier << request.get() << progress; | |
|
259 | } | |
|
260 | else { | |
|
261 | qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier | |
|
262 | << request.get() << progress; | |
|
263 | acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress)); | |
|
264 | } | |
|
265 | } | |
|
266 | else { | |
|
267 | qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier") | |
|
268 | << acqIdentifier << request.get() << progress; | |
|
269 | auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{}; | |
|
270 | requestProgressMap.insert(std::make_pair(request, progress)); | |
|
271 | m_AcqIdToRequestProgressMap.insert( | |
|
272 | std::make_pair(acqIdentifier, std::move(requestProgressMap))); | |
|
273 | } | |
|
274 | } |
@@ -5,6 +5,7 | |||
|
5 | 5 | #include <QFile> |
|
6 | 6 | |
|
7 | 7 | #include <cmath> |
|
8 | #include <Data/IDataSeries.h> | |
|
8 | 9 | |
|
9 | 10 | Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser") |
|
10 | 11 | |
@@ -99,14 +100,21 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath, | |||
|
99 | 100 | return nullptr; |
|
100 | 101 | } |
|
101 | 102 | |
|
102 | QTextStream stream{&file}; | |
|
103 | return std::shared_ptr<IDataSeries>{AmdaResultParser::readTxt(QTextStream{&file},type)}; | |
|
104 | } | |
|
105 | ||
|
106 | IDataSeries *AmdaResultParser::readTxt(QTextStream stream, | |
|
107 | DataSeriesType type) noexcept | |
|
108 | { | |
|
109 | if (type == DataSeriesType::UNKNOWN) | |
|
110 | { | |
|
111 | return nullptr; | |
|
112 | } | |
|
103 | 113 | |
|
104 | 114 | // Checks if the file was found on the server |
|
105 | 115 | auto firstLine = stream.readLine(); |
|
106 |
if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) |
|
|
107 | qCCritical(LOG_AmdaResultParser()) | |
|
108 | << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server") | |
|
109 | .arg(filePath); | |
|
116 | if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) | |
|
117 | { | |
|
110 | 118 | return nullptr; |
|
111 | 119 | } |
|
112 | 120 |
@@ -249,9 +249,9 bool ScalarParserHelper::checkProperties() | |||
|
249 | 249 | QObject::tr("The x-axis unit could not be found in the file")); |
|
250 | 250 | } |
|
251 | 251 | |
|
252 |
|
|
|
252 | IDataSeries* ScalarParserHelper::createSeries() | |
|
253 | 253 | { |
|
254 |
return |
|
|
254 | return new ScalarSeries(std::move(m_XAxisData), std::move(m_ValuesData), | |
|
255 | 255 | m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(), |
|
256 | 256 | m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>()); |
|
257 | 257 | } |
@@ -307,12 +307,12 bool SpectrogramParserHelper::checkProperties() | |||
|
307 | 307 | return true; |
|
308 | 308 | } |
|
309 | 309 | |
|
310 |
|
|
|
310 | IDataSeries* SpectrogramParserHelper::createSeries() | |
|
311 | 311 | { |
|
312 | 312 | // Before creating the series, we handle its data holes |
|
313 | 313 | handleDataHoles(); |
|
314 | 314 | |
|
315 |
return |
|
|
315 | return new SpectrogramSeries( | |
|
316 | 316 | std::move(m_XAxisData), std::move(m_YAxisData), std::move(m_ValuesData), |
|
317 | 317 | Unit{"t", true}, // x-axis unit is always a time unit |
|
318 | 318 | m_Properties.value(Y_AXIS_UNIT_PROPERTY).value<Unit>(), |
@@ -406,9 +406,9 bool VectorParserHelper::checkProperties() | |||
|
406 | 406 | QObject::tr("The x-axis unit could not be found in the file")); |
|
407 | 407 | } |
|
408 | 408 | |
|
409 |
|
|
|
409 | IDataSeries* VectorParserHelper::createSeries() | |
|
410 | 410 | { |
|
411 |
return |
|
|
411 | return new VectorSeries(std::move(m_XAxisData), std::move(m_ValuesData), | |
|
412 | 412 | m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(), |
|
413 | 413 | m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>()); |
|
414 | 414 | } |
@@ -115,11 +115,11 PYBIND11_MODULE(pytestamda, m){ | |||
|
115 | 115 | |
|
116 | 116 | py::class_<AmdaProvider, std::shared_ptr<AmdaProvider>, IDataProvider>(m, "AmdaProvider"); |
|
117 | 117 | |
|
118 | py::class_<AmdaResultParser>(m, "AmdaResultParser") | |
|
119 | .def_static("readTxt", AmdaResultParser::readTxt) | |
|
120 | .def("readScalarTxt", [](const QString& path){ | |
|
121 | return std::dynamic_pointer_cast<ScalarSeries>(AmdaResultParser::readTxt(path, DataSeriesType::SCALAR)); | |
|
122 | }, py::return_value_policy::copy); | |
|
118 | // py::class_<AmdaResultParser>(m, "AmdaResultParser") | |
|
119 | // .def_static("readTxt", AmdaResultParser::readTxt) | |
|
120 | // .def("readScalarTxt", [](const QString& path){ | |
|
121 | // return std::dynamic_pointer_cast<ScalarSeries>(AmdaResultParser::readTxt(path, DataSeriesType::SCALAR)); | |
|
122 | // }, py::return_value_policy::copy); | |
|
123 | 123 | |
|
124 | 124 | |
|
125 | 125 | } |
@@ -25,5 +25,5 include(sciqlop_tests) | |||
|
25 | 25 | |
|
26 | 26 | add_definitions(-DMOCKPLUGIN_TESTS_RESOURCES_DIR="${CMAKE_CURRENT_LIST_DIR}/tests-resources") |
|
27 | 27 | |
|
28 | declare_test(TestCosinusAcquisition TestCosinusAcquisition tests/TestCosinusAcquisition.cpp "mockplugin;Qt5::Test") | |
|
28 | #declare_test(TestCosinusAcquisition TestCosinusAcquisition tests/TestCosinusAcquisition.cpp "mockplugin;Qt5::Test") | |
|
29 | 29 |
@@ -9,7 +9,6 | |||
|
9 | 9 | #include <QUuid> |
|
10 | 10 | |
|
11 | 11 | #include <QHash> |
|
12 | Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider) | |
|
13 | 12 | |
|
14 | 13 | /** |
|
15 | 14 | * @brief The CosinusProvider class is an example of how a data provider can generate data |
@@ -18,21 +17,8 class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider { | |||
|
18 | 17 | public: |
|
19 | 18 | std::shared_ptr<IDataProvider> clone() const override; |
|
20 | 19 | |
|
21 | /// @sa IDataProvider::requestDataLoading(). The current impl isn't thread safe. | |
|
22 | void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters ¶meters) override; | |
|
23 | ||
|
24 | ||
|
25 | 20 | virtual IDataSeries* getData(const DataProviderParameters ¶meters) override; |
|
26 | 21 | |
|
27 | /// @sa IDataProvider::requestDataAborting(). The current impl isn't thread safe. | |
|
28 | void requestDataAborting(QUuid acqIdentifier) override; | |
|
29 | ||
|
30 | ||
|
31 | /// Provide data | |
|
32 | std::shared_ptr<IDataSeries> provideDataSeries(const DateTimeRange &dataRangeRequested, | |
|
33 | const QVariantHash &data); | |
|
34 | ||
|
35 | ||
|
36 | 22 | private: |
|
37 | 23 | std::shared_ptr<IDataSeries> |
|
38 | 24 | retrieveData(QUuid acqIdentifier, const DateTimeRange &dataRangeRequested, const QVariantHash &data); |
@@ -13,7 +13,6 | |||
|
13 | 13 | #include <QThread> |
|
14 | 14 | #include <QtConcurrent/QtConcurrent> |
|
15 | 15 | |
|
16 | Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider") | |
|
17 | 16 | |
|
18 | 17 | namespace { |
|
19 | 18 | |
@@ -158,95 +157,6 std::shared_ptr<IDataProvider> CosinusProvider::clone() const | |||
|
158 | 157 | return std::make_shared<CosinusProvider>(); |
|
159 | 158 | } |
|
160 | 159 | |
|
161 | std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier, | |
|
162 | const DateTimeRange &dataRangeRequested, | |
|
163 | const QVariantHash &data) | |
|
164 | { | |
|
165 | // TODO: Add Mutex | |
|
166 | auto dataIndex = 0; | |
|
167 | ||
|
168 | // Retrieves cosinus type | |
|
169 | auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE); | |
|
170 | if (!typeVariant.canConvert<QString>()) { | |
|
171 | qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type"); | |
|
172 | return nullptr; | |
|
173 | } | |
|
174 | ||
|
175 | auto type = cosinusType(typeVariant.toString()); | |
|
176 | if (!type) { | |
|
177 | qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type"); | |
|
178 | return nullptr; | |
|
179 | } | |
|
180 | ||
|
181 | // Retrieves frequency | |
|
182 | auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE); | |
|
183 | if (!freqVariant.canConvert<double>()) { | |
|
184 | qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency"); | |
|
185 | return nullptr; | |
|
186 | } | |
|
187 | ||
|
188 | // Gets the timerange from the parameters | |
|
189 | double freq = freqVariant.toDouble(); | |
|
190 | double start = std::ceil(dataRangeRequested.m_TStart * freq); | |
|
191 | double end = std::floor(dataRangeRequested.m_TEnd * freq); | |
|
192 | ||
|
193 | // We assure that timerange is valid | |
|
194 | if (end < start) { | |
|
195 | std::swap(start, end); | |
|
196 | } | |
|
197 | ||
|
198 | // Generates scalar series containing cosinus values (one value per second, end value is | |
|
199 | // included) | |
|
200 | auto dataCount = end - start + 1; | |
|
201 | ||
|
202 | // Number of components (depending on the cosinus type) | |
|
203 | auto componentCount = type->componentCount(); | |
|
204 | ||
|
205 | auto xAxisData = std::vector<double>{}; | |
|
206 | xAxisData.resize(dataCount); | |
|
207 | ||
|
208 | auto valuesData = std::vector<double>{}; | |
|
209 | valuesData.resize(dataCount * componentCount); | |
|
210 | ||
|
211 | int progress = 0; | |
|
212 | auto progressEnd = dataCount; | |
|
213 | for (auto time = start; time <= end; ++time, ++dataIndex) { | |
|
214 | auto it = m_VariableToEnableProvider.find(acqIdentifier); | |
|
215 | if (it != m_VariableToEnableProvider.end() && it.value()) { | |
|
216 | const auto x = time / freq; | |
|
217 | ||
|
218 | xAxisData[dataIndex] = x; | |
|
219 | ||
|
220 | // Generates values (depending on the type) | |
|
221 | type->generateValues(x, valuesData, dataIndex); | |
|
222 | ||
|
223 | // progression | |
|
224 | int currentProgress = (time - start) * 100.0 / progressEnd; | |
|
225 | if (currentProgress != progress) { | |
|
226 | progress = currentProgress; | |
|
227 | ||
|
228 | emit dataProvidedProgress(acqIdentifier, progress); | |
|
229 | qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData" | |
|
230 | << QThread::currentThread()->objectName() | |
|
231 | << progress; | |
|
232 | // NOTE: Try to use multithread if possible | |
|
233 | } | |
|
234 | } | |
|
235 | else { | |
|
236 | if (!it.value()) { | |
|
237 | qCDebug(LOG_CosinusProvider()) | |
|
238 | << "CosinusProvider::retrieveData: ARRET De l'acquisition detecté" | |
|
239 | << end - time; | |
|
240 | } | |
|
241 | } | |
|
242 | } | |
|
243 | if (progress != 100) { | |
|
244 | // We can close progression beacause all data has been retrieved | |
|
245 | emit dataProvidedProgress(acqIdentifier, 100); | |
|
246 | } | |
|
247 | return std::shared_ptr<IDataSeries>(type->createDataSeries(std::move(xAxisData), std::move(valuesData))); | |
|
248 | } | |
|
249 | ||
|
250 | 160 | IDataSeries *CosinusProvider::_generate(const DateTimeRange &range, const QVariantHash &metaData) |
|
251 | 161 | { |
|
252 | 162 | auto dataIndex = 0; |
@@ -282,51 +192,8 IDataSeries *CosinusProvider::_generate(const DateTimeRange &range, const QVaria | |||
|
282 | 192 | return type->createDataSeries(std::move(xAxisData), std::move(valuesData)); |
|
283 | 193 | } |
|
284 | 194 | |
|
285 | void CosinusProvider::requestDataLoading(QUuid acqIdentifier, | |
|
286 | const DataProviderParameters ¶meters) | |
|
287 | { | |
|
288 | // TODO: Add Mutex | |
|
289 | m_VariableToEnableProvider[acqIdentifier] = true; | |
|
290 | qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading" | |
|
291 | << QThread::currentThread()->objectName(); | |
|
292 | // NOTE: Try to use multithread if possible | |
|
293 | const auto times = parameters.m_Times; | |
|
294 | ||
|
295 | for (const auto &dateTime : qAsConst(times)) { | |
|
296 | if (m_VariableToEnableProvider[acqIdentifier]) { | |
|
297 | auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data); | |
|
298 | emit dataProvided(acqIdentifier, scalarSeries, dateTime); | |
|
299 | } | |
|
300 | } | |
|
301 | } | |
|
302 | ||
|
303 | 195 | IDataSeries* CosinusProvider::getData(const DataProviderParameters ¶meters) |
|
304 | 196 | { |
|
305 | 197 | return _generate(parameters.m_Times.front(),parameters.m_Data); |
|
306 | 198 | } |
|
307 | 199 | |
|
308 | ||
|
309 | void CosinusProvider::requestDataAborting(QUuid acqIdentifier) | |
|
310 | { | |
|
311 | qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier | |
|
312 | << QThread::currentThread()->objectName(); | |
|
313 | auto it = m_VariableToEnableProvider.find(acqIdentifier); | |
|
314 | if (it != m_VariableToEnableProvider.end()) { | |
|
315 | it.value() = false; | |
|
316 | } | |
|
317 | else { | |
|
318 | qCDebug(LOG_CosinusProvider()) | |
|
319 | << tr("Aborting progression of inexistant identifier detected !!!"); | |
|
320 | } | |
|
321 | } | |
|
322 | ||
|
323 | std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const DateTimeRange &dataRangeRequested, | |
|
324 | const QVariantHash &data) | |
|
325 | { | |
|
326 | auto uid = QUuid::createUuid(); | |
|
327 | m_VariableToEnableProvider[uid] = true; | |
|
328 | auto dataSeries = this->retrieveData(uid, dataRangeRequested, data); | |
|
329 | ||
|
330 | m_VariableToEnableProvider.remove(uid); | |
|
331 | return dataSeries; | |
|
332 | } |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now