##// END OF EJS Templates
Merge pull request 184 from SCIQLOP-Initialisation develop...
leroux -
r403:756d172725c6 merge
parent child
Show More
@@ -1,43 +1,46
1 1 #ifndef SCIQLOP_NETWORKCONTROLLER_H
2 2 #define SCIQLOP_NETWORKCONTROLLER_H
3 3
4 4 #include <QLoggingCategory>
5 5 #include <QObject>
6 6 #include <QUuid>
7 7
8 8 #include <Common/spimpl.h>
9 9 #include <functional>
10 10
11 11 Q_DECLARE_LOGGING_CATEGORY(LOG_NetworkController)
12 12
13 13 class QNetworkReply;
14 14 class QNetworkRequest;
15 15
16 16 /**
17 17 * @brief The NetworkController class aims to handle all network connection of SciQlop.
18 18 */
19 19 class NetworkController : public QObject {
20 20 Q_OBJECT
21 21 public:
22 22 explicit NetworkController(QObject *parent = 0);
23 23
24 24 void initialize();
25 25 void finalize();
26 26
27 27 public slots:
28 /// Execute request and call callback when the reply is finished. Identifier is attached to the
29 /// callback
28 30 void onProcessRequested(const QNetworkRequest &request, QUuid identifier,
29 31 std::function<void(QNetworkReply *, QUuid)> callback);
32 /// Cancel the request of identifier
30 33 void onReplyCanceled(QUuid identifier);
31 34
32 35 signals:
33 36 void replyFinished(QNetworkReply *reply, QUuid identifier);
34 void replyDownloadProgress(QUuid identifier);
37 void replyDownloadProgress(QUuid identifier, double progress);
35 38
36 39 private:
37 40 void waitForFinish();
38 41
39 42 class NetworkControllerPrivate;
40 43 spimpl::unique_impl_ptr<NetworkControllerPrivate> impl;
41 44 };
42 45
43 46 #endif // SCIQLOP_NETWORKCONTROLLER_H
@@ -1,80 +1,83
1 1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECONTROLLER_H
3 3
4 4 #include <Data/SqpDateTime.h>
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8
9 9 #include <Common/spimpl.h>
10 10
11 11 class IDataProvider;
12 12 class QItemSelectionModel;
13 13 class TimeController;
14 14 class Variable;
15 15 class VariableModel;
16 16
17 17 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
18 18
19 19 /**
20 20 * @brief The VariableController class aims to handle the variables in SciQlop.
21 21 */
22 22 class VariableController : public QObject {
23 23 Q_OBJECT
24 24 public:
25 25 explicit VariableController(QObject *parent = 0);
26 26 virtual ~VariableController();
27 27
28 28 VariableModel *variableModel() noexcept;
29 29 QItemSelectionModel *variableSelectionModel() noexcept;
30 30
31 31 void setTimeController(TimeController *timeController) noexcept;
32 32
33 33 /**
34 34 * Deletes from the controller the variable passed in parameter.
35 35 *
36 36 * Delete a variable includes:
37 37 * - the deletion of the various references to the variable in SciQlop
38 38 * - the deletion of the model variable
39 39 * - the deletion of the provider associated with the variable
40 40 * - removing the cache associated with the variable
41 41 *
42 42 * @param variable the variable to delete from the controller.
43 43 */
44 44 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
45 45
46 46 /**
47 47 * Deletes from the controller the variables passed in parameter.
48 48 * @param variables the variables to delete from the controller.
49 49 * @sa deleteVariable()
50 50 */
51 51 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
52 52
53 53 signals:
54 54 /// Signal emitted when a variable is about to be deleted from the controller
55 55 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
56 56
57 57 public slots:
58 58 /// Request the data loading of the variable whithin dateTime
59 59 void onRequestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
60 60 /**
61 61 * Creates a new variable and adds it to the model
62 62 * @param name the name of the new variable
63 63 * @param provider the data provider for the new variable
64 64 */
65 65 void createVariable(const QString &name, std::shared_ptr<IDataProvider> provider) noexcept;
66 66
67 67 /// Update the temporal parameters of every selected variable to dateTime
68 68 void onDateTimeOnSelection(const SqpDateTime &dateTime);
69 69
70
71 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
72
70 73 void initialize();
71 74 void finalize();
72 75
73 76 private:
74 77 void waitForFinish();
75 78
76 79 class VariableControllerPrivate;
77 80 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
78 81 };
79 82
80 83 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,63 +1,70
1 1 #ifndef SCIQLOP_VARIABLEMODEL_H
2 2 #define SCIQLOP_VARIABLEMODEL_H
3 3
4 4
5 5 #include <Data/SqpDateTime.h>
6 6
7 7 #include <QAbstractTableModel>
8 8 #include <QLoggingCategory>
9 9
10 10 #include <Common/MetaTypes.h>
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel)
14 14
15 enum VariableRoles { ProgressRole = Qt::UserRole };
16
17
15 18 class IDataSeries;
16 19 class Variable;
17 20
18 21 /**
19 22 * @brief The VariableModel class aims to hold the variables that have been created in SciQlop
20 23 */
21 24 class VariableModel : public QAbstractTableModel {
22 25 public:
23 26 explicit VariableModel(QObject *parent = nullptr);
24 27
25 28 /**
26 29 * Creates a new variable in the model
27 30 * @param name the name of the new variable
28 31 * @param dateTime the dateTime of the new variable
29 32 * @return the pointer to the new variable
30 33 */
31 34 std::shared_ptr<Variable> createVariable(const QString &name,
32 35 const SqpDateTime &dateTime) noexcept;
33 36
34 37 /**
35 38 * Deletes a variable from the model, if it exists
36 39 * @param variable the variable to delete
37 40 */
38 41 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
39 42
43
40 44 std::shared_ptr<Variable> variable(int index) const;
41 45
46 void setDataProgress(std::shared_ptr<Variable> variable, double progress);
47
42 48 // /////////////////////////// //
43 49 // QAbstractTableModel methods //
44 50 // /////////////////////////// //
51
45 52 virtual int columnCount(const QModelIndex &parent = QModelIndex{}) const override;
46 53 virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const override;
47 54 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
48 55 virtual QVariant headerData(int section, Qt::Orientation orientation,
49 56 int role = Qt::DisplayRole) const override;
50 57
51 58 private:
52 59 class VariableModelPrivate;
53 60 spimpl::unique_impl_ptr<VariableModelPrivate> impl;
54 61
55 62 private slots:
56 63 /// Slot called when data of a variable has been updated
57 64 void onVariableUpdated() noexcept;
58 65 };
59 66
60 67 // Registers QVector<int> metatype so it can be used in VariableModel::dataChanged() signal
61 68 SCIQLOP_REGISTER_META_TYPE(QVECTOR_INT_REGISTRY, QVector<int>)
62 69
63 70 #endif // SCIQLOP_VARIABLEMODEL_H
@@ -1,88 +1,87
1 1 #include "Network/NetworkController.h"
2 2
3 3 #include <QMutex>
4 4 #include <QNetworkAccessManager>
5 5 #include <QNetworkReply>
6 6 #include <QNetworkRequest>
7 7 #include <QThread>
8 8
9 9 #include <unordered_map>
10 10
11 11 Q_LOGGING_CATEGORY(LOG_NetworkController, "NetworkController")
12 12
13 13 struct NetworkController::NetworkControllerPrivate {
14 14 explicit NetworkControllerPrivate(NetworkController *parent) : m_WorkingMutex{} {}
15 15 QMutex m_WorkingMutex;
16 16
17 17 std::unordered_map<QNetworkReply *, QUuid> m_NetworkReplyToVariableId;
18 18 std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr};
19 19 };
20 20
21 21 NetworkController::NetworkController(QObject *parent)
22 22 : QObject(parent), impl{spimpl::make_unique_impl<NetworkControllerPrivate>(this)}
23 23 {
24 24 }
25 25
26 26 void NetworkController::onProcessRequested(const QNetworkRequest &request, QUuid identifier,
27 27 std::function<void(QNetworkReply *, QUuid)> callback)
28 28 {
29 qCDebug(LOG_NetworkController()) << tr("NetworkController registered")
30 << QThread::currentThread();
29 qCInfo(LOG_NetworkController()) << tr("NetworkController registered")
30 << QThread::currentThread();
31 31 auto reply = impl->m_AccessManager->get(request);
32 32
33 33 // Store the couple reply id
34 34 impl->m_NetworkReplyToVariableId[reply] = identifier;
35 35
36 36 auto onReplyFinished = [reply, this, identifier, callback]() {
37 37
38 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished")
39 << QThread::currentThread();
38 qCInfo(LOG_NetworkController()) << tr("NetworkController onReplyFinished")
39 << QThread::currentThread();
40 40 auto it = impl->m_NetworkReplyToVariableId.find(reply);
41 41 if (it != impl->m_NetworkReplyToVariableId.cend()) {
42 42 callback(reply, identifier);
43 43 }
44 44 };
45 45
46 auto onReplyDownloadProgress = [reply, this]() {
46 auto onReplyProgress = [reply, this](qint64 bytesRead, qint64 totalBytes) {
47 47
48 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyDownloadProgress")
49 << QThread::currentThread();
48 double progress = (bytesRead * 100.0) / totalBytes;
50 49 auto it = impl->m_NetworkReplyToVariableId.find(reply);
51 50 if (it != impl->m_NetworkReplyToVariableId.cend()) {
52 emit this->replyDownloadProgress(it->second);
51 emit this->replyDownloadProgress(it->second, progress);
53 52 }
54 53 };
55 54
56 55
57 56 connect(reply, &QNetworkReply::finished, this, onReplyFinished);
58 connect(reply, &QNetworkReply::downloadProgress, this, onReplyDownloadProgress);
57 connect(reply, &QNetworkReply::downloadProgress, this, onReplyProgress);
59 58 }
60 59
61 60 void NetworkController::initialize()
62 61 {
63 62 qCDebug(LOG_NetworkController()) << tr("NetworkController init") << QThread::currentThread();
64 63 impl->m_WorkingMutex.lock();
65 64 impl->m_AccessManager = std::make_unique<QNetworkAccessManager>();
66 65 qCDebug(LOG_NetworkController()) << tr("NetworkController init END");
67 66 }
68 67
69 68 void NetworkController::finalize()
70 69 {
71 70 impl->m_WorkingMutex.unlock();
72 71 }
73 72
74 73 void NetworkController::onReplyCanceled(QUuid identifier)
75 74 {
76 75 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
77 76
78 77 auto end = impl->m_NetworkReplyToVariableId.cend();
79 78 auto it = std::find_if(impl->m_NetworkReplyToVariableId.cbegin(), end, findReply);
80 79 if (it != end) {
81 80 it->first->abort();
82 81 }
83 82 }
84 83
85 84 void NetworkController::waitForFinish()
86 85 {
87 86 QMutexLocker locker{&impl->m_WorkingMutex};
88 87 }
@@ -1,205 +1,216
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableCacheController.h>
3 3 #include <Variable/VariableController.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Data/IDataProvider.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Time/TimeController.h>
10 10
11 11 #include <QDateTime>
12 12 #include <QMutex>
13 13 #include <QThread>
14 14 #include <QUuid>
15 15 #include <QtCore/QItemSelectionModel>
16 16
17 17 #include <unordered_map>
18 18
19 19 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
20 20
21 21 struct VariableController::VariableControllerPrivate {
22 22 explicit VariableControllerPrivate(VariableController *parent)
23 23 : m_WorkingMutex{},
24 24 m_VariableModel{new VariableModel{parent}},
25 25 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
26 26 m_VariableCacheController{std::make_unique<VariableCacheController>()}
27 27 {
28 28 }
29 29
30 30 QMutex m_WorkingMutex;
31 31 /// Variable model. The VariableController has the ownership
32 32 VariableModel *m_VariableModel;
33 33 QItemSelectionModel *m_VariableSelectionModel;
34 34
35 35
36 36 TimeController *m_TimeController{nullptr};
37 37 std::unique_ptr<VariableCacheController> m_VariableCacheController;
38 38
39 39 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
40 40 m_VariableToProviderMap;
41 41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifier;
42 42 };
43 43
44 44 VariableController::VariableController(QObject *parent)
45 45 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
46 46 {
47 47 qCDebug(LOG_VariableController()) << tr("VariableController construction")
48 48 << QThread::currentThread();
49 49 }
50 50
51 51 VariableController::~VariableController()
52 52 {
53 53 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
54 54 << QThread::currentThread();
55 55 this->waitForFinish();
56 56 }
57 57
58 58 VariableModel *VariableController::variableModel() noexcept
59 59 {
60 60 return impl->m_VariableModel;
61 61 }
62 62
63 63 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
64 64 {
65 65 return impl->m_VariableSelectionModel;
66 66 }
67 67
68 68 void VariableController::setTimeController(TimeController *timeController) noexcept
69 69 {
70 70 impl->m_TimeController = timeController;
71 71 }
72 72
73 73 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
74 74 {
75 75 if (!variable) {
76 76 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
77 77 return;
78 78 }
79 79
80 80 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
81 81 // make some treatments before the deletion
82 82 emit variableAboutToBeDeleted(variable);
83 83
84 84 // Deletes provider
85 85 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
86 86 qCDebug(LOG_VariableController())
87 87 << tr("Number of providers deleted for variable %1: %2")
88 88 .arg(variable->name(), QString::number(nbProvidersDeleted));
89 89
90 90 // Clears cache
91 91 impl->m_VariableCacheController->clear(variable);
92 92
93 93 // Deletes from model
94 94 impl->m_VariableModel->deleteVariable(variable);
95 95 }
96 96
97 97 void VariableController::deleteVariables(
98 98 const QVector<std::shared_ptr<Variable> > &variables) noexcept
99 99 {
100 100 for (auto variable : qAsConst(variables)) {
101 101 deleteVariable(variable);
102 102 }
103 103 }
104 104
105 105 void VariableController::createVariable(const QString &name,
106 106 std::shared_ptr<IDataProvider> provider) noexcept
107 107 {
108 108
109 109 if (!impl->m_TimeController) {
110 110 qCCritical(LOG_VariableController())
111 111 << tr("Impossible to create variable: The time controller is null");
112 112 return;
113 113 }
114 114
115 115
116 116 /// @todo : for the moment :
117 117 /// - the provider is only used to retrieve data from the variable for its initialization, but
118 118 /// it will be retained later
119 119 /// - default data are generated for the variable, without taking into account the timerange set
120 120 /// in sciqlop
121 121 auto dateTime = impl->m_TimeController->dateTime();
122 122 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime)) {
123 123 auto identifier = QUuid::createUuid();
124 124
125 125 // store the provider
126 126 impl->m_VariableToProviderMap[newVariable] = provider;
127 127 impl->m_VariableToIdentifier[newVariable] = identifier;
128 128
129 129 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
130 130 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
131 131 {
132 132 if (auto variable = varW.lock()) {
133 133 auto varIdentifier = impl->m_VariableToIdentifier.at(variable);
134 134 if (varIdentifier == identifier) {
135 135 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
136 136 variable->setDataSeries(dataSeriesAcquired);
137 137 }
138 138 }
139 139 };
140 140
141 141 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
142 142 this->onRequestDataLoading(newVariable, dateTime);
143 143 }
144 144 }
145 145
146 146 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
147 147 {
148 148 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
149 149 << QThread::currentThread()->objectName();
150 150 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
151 151
152 152 for (const auto &selectedRow : qAsConst(selectedRows)) {
153 153 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
154 154 selectedVariable->setDateTime(dateTime);
155 155 this->onRequestDataLoading(selectedVariable, dateTime);
156 156 }
157 157 }
158 158 }
159 159
160 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
161 {
162 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
163
164 auto end = impl->m_VariableToIdentifier.cend();
165 auto it = std::find_if(impl->m_VariableToIdentifier.cbegin(), end, findReply);
166 if (it != end) {
167 impl->m_VariableModel->setDataProgress(it->first, progress);
168 }
169 }
170
160 171
161 172 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
162 173 const SqpDateTime &dateTime)
163 174 {
164 175 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
165 176 << QThread::currentThread()->objectName();
166 177 // we want to load data of the variable for the dateTime.
167 178 // First we check if the cache contains some of them.
168 179 // For the other, we ask the provider to give them.
169 180 if (variable) {
170 181
171 182 auto dateTimeListNotInCache
172 183 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
173 184
174 185 if (!dateTimeListNotInCache.empty()) {
175 186 // Ask the provider for each data on the dateTimeListNotInCache
176 187 auto identifier = impl->m_VariableToIdentifier.at(variable);
177 188 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
178 189 identifier, std::move(dateTimeListNotInCache));
179 190 }
180 191 else {
181 192 emit variable->updated();
182 193 }
183 194 }
184 195 else {
185 196 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
186 197 }
187 198 }
188 199
189 200
190 201 void VariableController::initialize()
191 202 {
192 203 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
193 204 impl->m_WorkingMutex.lock();
194 205 qCDebug(LOG_VariableController()) << tr("VariableController init END");
195 206 }
196 207
197 208 void VariableController::finalize()
198 209 {
199 210 impl->m_WorkingMutex.unlock();
200 211 }
201 212
202 213 void VariableController::waitForFinish()
203 214 {
204 215 QMutexLocker locker{&impl->m_WorkingMutex};
205 216 }
@@ -1,200 +1,236
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableModel.h>
3 3
4 4 #include <Data/IDataSeries.h>
5 5
6 6 #include <QDateTime>
7 7 #include <QSize>
8 #include <unordered_map>
8 9
9 10 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
10 11
11 12 namespace {
12 13
13 14 // Column indexes
14 15 const auto NAME_COLUMN = 0;
15 16 const auto TSTART_COLUMN = 1;
16 17 const auto TEND_COLUMN = 2;
17 18 const auto NB_COLUMNS = 3;
18 19
19 20 // Column properties
20 21 const auto DEFAULT_HEIGHT = 25;
21 22 const auto DEFAULT_WIDTH = 100;
22 23
23 24 struct ColumnProperties {
24 25 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
25 26 int height = DEFAULT_HEIGHT)
26 27 : m_Name{name}, m_Width{width}, m_Height{height}
27 28 {
28 29 }
29 30
30 31 QString m_Name;
31 32 int m_Width;
32 33 int m_Height;
33 34 };
34 35
35 36 const auto COLUMN_PROPERTIES
36 37 = QHash<int, ColumnProperties>{{NAME_COLUMN, {QObject::tr("Name")}},
37 38 {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
38 39 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}};
39 40
40 41 /// Format for datetimes
41 42 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
42 43
44
43 45 } // namespace
44 46
45 47 struct VariableModel::VariableModelPrivate {
46 48 /// Variables created in SciQlop
47 49 std::vector<std::shared_ptr<Variable> > m_Variables;
50 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
51
52
53 /// Return the row index of the variable. -1 if it's not found
54 int indexOfVariable(Variable *variable) const noexcept;
48 55 };
49 56
50 57 VariableModel::VariableModel(QObject *parent)
51 58 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
52 59 {
53 60 }
54 61
55 62 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
56 63 const SqpDateTime &dateTime) noexcept
57 64 {
58 65 auto insertIndex = rowCount();
59 66 beginInsertRows({}, insertIndex, insertIndex);
60 67
61 68 /// @todo For the moment, the other data of the variable is initialized with default values
62 69 auto variable = std::make_shared<Variable>(name, QStringLiteral("unit"),
63 70 QStringLiteral("mission"), dateTime);
64 71
65 72 impl->m_Variables.push_back(variable);
66 73 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
67 74
68 75 endInsertRows();
69 76
70 77 return variable;
71 78 }
72 79
73 80 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
74 81 {
75 82 if (!variable) {
76 83 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
77 84 return;
78 85 }
79 86
80 87 // Finds variable in the model
81 88 auto begin = impl->m_Variables.cbegin();
82 89 auto end = impl->m_Variables.cend();
83 90 auto it = std::find(begin, end, variable);
84 91 if (it != end) {
85 92 auto removeIndex = std::distance(begin, it);
86 93
87 94 // Deletes variable
88 95 beginRemoveRows({}, removeIndex, removeIndex);
89 96 impl->m_Variables.erase(it);
90 97 endRemoveRows();
91 98 }
92 99 else {
93 100 qCritical(LOG_VariableModel())
94 101 << tr("Can't delete variable %1 from the model: the variable is not in the model")
95 102 .arg(variable->name());
96 103 }
97 104 }
98 105
106
99 107 std::shared_ptr<Variable> VariableModel::variable(int index) const
100 108 {
101 109 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
102 110 }
103 111
112 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
113 {
114
115 impl->m_VariableToProgress[variable] = progress;
116 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
117
118 emit dataChanged(modelIndex, modelIndex);
119 }
120
104 121 int VariableModel::columnCount(const QModelIndex &parent) const
105 122 {
106 123 Q_UNUSED(parent);
107 124
108 125 return NB_COLUMNS;
109 126 }
110 127
111 128 int VariableModel::rowCount(const QModelIndex &parent) const
112 129 {
113 130 Q_UNUSED(parent);
114 131
115 132 return impl->m_Variables.size();
116 133 }
117 134
118 135 QVariant VariableModel::data(const QModelIndex &index, int role) const
119 136 {
120 137 if (!index.isValid()) {
121 138 return QVariant{};
122 139 }
123 140
124 141 if (index.row() < 0 || index.row() >= rowCount()) {
125 142 return QVariant{};
126 143 }
127 144
128 145 if (role == Qt::DisplayRole) {
129 146 if (auto variable = impl->m_Variables.at(index.row()).get()) {
130 147 /// Lambda function that builds the variant to return for a time value
131 148 auto dateTimeVariant = [](double time) {
132 149 auto dateTime = QDateTime::fromMSecsSinceEpoch(time * 1000.);
133 150 return dateTime.toString(DATETIME_FORMAT);
134 151 };
135 152
136 153 switch (index.column()) {
137 154 case NAME_COLUMN:
138 155 return variable->name();
139 156 case TSTART_COLUMN:
140 157 return dateTimeVariant(variable->dateTime().m_TStart);
141 158 case TEND_COLUMN:
142 159 return dateTimeVariant(variable->dateTime().m_TEnd);
143 160 default:
144 161 // No action
145 162 break;
146 163 }
147 164
148 165 qWarning(LOG_VariableModel())
149 166 << tr("Can't get data (unknown column %1)").arg(index.column());
150 167 }
151 168 else {
152 169 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
153 170 }
154 171 }
172 else if (role == VariableRoles::ProgressRole) {
173 if (auto variable = impl->m_Variables.at(index.row())) {
174
175 auto it = impl->m_VariableToProgress.find(variable);
176 if (it != impl->m_VariableToProgress.cend()) {
177 return it->second;
178 }
179 }
180 }
155 181
156 182 return QVariant{};
157 183 }
158 184
159 185 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
160 186 {
161 187 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
162 188 return QVariant{};
163 189 }
164 190
165 191 if (orientation == Qt::Horizontal) {
166 192 auto propertiesIt = COLUMN_PROPERTIES.find(section);
167 193 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
168 194 // Role is either DisplayRole or SizeHintRole
169 195 return (role == Qt::DisplayRole)
170 196 ? QVariant{propertiesIt->m_Name}
171 197 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
172 198 }
173 199 else {
174 200 qWarning(LOG_VariableModel())
175 201 << tr("Can't get header data (unknown column %1)").arg(section);
176 202 }
177 203 }
178 204
179 205 return QVariant{};
180 206 }
181 207
182 208 void VariableModel::onVariableUpdated() noexcept
183 209 {
184 210 // Finds variable that has been updated in the model
185 211 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
186 auto begin = std::cbegin(impl->m_Variables);
187 auto end = std::cend(impl->m_Variables);
188 auto it = std::find_if(begin, end, [updatedVariable](const auto &variable) {
189 return variable.get() == updatedVariable;
190 });
191
192 if (it != end) {
193 // Gets the index of the variable in the model: we assume here that views have the same
194 // order as the model
195 auto updateVariableIndex = std::distance(begin, it);
196 emit dataChanged(createIndex(updateVariableIndex, 0),
197 createIndex(updateVariableIndex, columnCount() - 1));
212 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
213
214 if (updatedVariableIndex > -1) {
215 emit dataChanged(createIndex(updatedVariableIndex, 0),
216 createIndex(updatedVariableIndex, columnCount() - 1));
198 217 }
199 218 }
200 219 }
220
221 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
222 {
223 auto begin = std::cbegin(m_Variables);
224 auto end = std::cend(m_Variables);
225 auto it
226 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
227
228 if (it != end) {
229 // Gets the index of the variable in the model: we assume here that views have the same
230 // order as the model
231 return std::distance(begin, it);
232 }
233 else {
234 return -1;
235 }
236 }
@@ -1,52 +1,56
1 1 #ifndef SCIQLOP_VARIABLEINSPECTORWIDGET_H
2 2 #define SCIQLOP_VARIABLEINSPECTORWIDGET_H
3 3
4 4 #include <QLoggingCategory>
5 5 #include <QMenu>
6 6 #include <QWidget>
7 7
8 8 #include <memory>
9 9
10 10 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableInspectorWidget)
11 11
12 12 class Variable;
13 13
14 class QProgressBarItemDelegate;
15
14 16 namespace Ui {
15 17 class VariableInspectorWidget;
16 18 } // Ui
17 19
18 20 /**
19 21 * @brief The VariableInspectorWidget class representes represents the variable inspector, from
20 22 * which it is possible to view the loaded variables, handle them or trigger their display in
21 23 * visualization
22 24 */
23 25 class VariableInspectorWidget : public QWidget {
24 26 Q_OBJECT
25 27
26 28 public:
27 29 explicit VariableInspectorWidget(QWidget *parent = 0);
28 30 virtual ~VariableInspectorWidget();
29 31
30 32 signals:
31 33 /**
32 34 * Signal emitted before a menu concerning variables is displayed. It is used for other widgets
33 35 * to complete the menu.
34 36 * @param tableMenu the menu to be completed
35 37 * @param variables the variables concerned by the menu
36 38 * @remarks To make the dynamic addition of menus work, the connections to this signal must be
37 39 * in Qt :: DirectConnection
38 40 */
39 41 void tableMenuAboutToBeDisplayed(QMenu *tableMenu,
40 42 const QVector<std::shared_ptr<Variable> > &variables);
41 43
42 44 private:
43 45 Ui::VariableInspectorWidget *ui;
44 46
47 QProgressBarItemDelegate *m_ProgressBarItemDelegate;
48
45 49 private slots:
46 50 /// Slot called when right clicking on an variable in the table (displays a menu)
47 51 void onTableMenuRequested(const QPoint &pos) noexcept;
48 52 /// Refreshes instantly the variable view
49 53 void refresh() noexcept;
50 54 };
51 55
52 56 #endif // SCIQLOP_VARIABLEINSPECTORWIDGET_H
@@ -1,140 +1,145
1 1 #include "SqpApplication.h"
2 2
3 3 #include <Data/IDataProvider.h>
4 4 #include <DataSource/DataSourceController.h>
5 5 #include <Network/NetworkController.h>
6 6 #include <QThread>
7 7 #include <Time/TimeController.h>
8 8 #include <Variable/Variable.h>
9 9 #include <Variable/VariableController.h>
10 10 #include <Visualization/VisualizationController.h>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
13 13
14 14 class SqpApplication::SqpApplicationPrivate {
15 15 public:
16 16 SqpApplicationPrivate()
17 17 : m_DataSourceController{std::make_unique<DataSourceController>()},
18 18 m_NetworkController{std::make_unique<NetworkController>()},
19 19 m_TimeController{std::make_unique<TimeController>()},
20 20 m_VariableController{std::make_unique<VariableController>()},
21 21 m_VisualizationController{std::make_unique<VisualizationController>()}
22 22 {
23 23 // /////////////////////////////// //
24 24 // Connections between controllers //
25 25 // /////////////////////////////// //
26 26
27 27 // VariableController <-> DataSourceController
28 28 connect(m_DataSourceController.get(),
29 29 SIGNAL(variableCreationRequested(const QString &, std::shared_ptr<IDataProvider>)),
30 30 m_VariableController.get(),
31 31 SLOT(createVariable(const QString &, std::shared_ptr<IDataProvider>)));
32 32
33 33 // VariableController <-> VisualizationController
34 34 connect(m_VariableController.get(),
35 35 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
36 36 m_VisualizationController.get(),
37 37 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
38 38
39 39
40 40 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
41 41 m_NetworkController->moveToThread(&m_NetworkControllerThread);
42 42 m_VariableController->moveToThread(&m_VariableControllerThread);
43 43 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
44 44
45 45
46 46 // Additionnal init
47 47 m_VariableController->setTimeController(m_TimeController.get());
48 48 }
49 49
50 50 virtual ~SqpApplicationPrivate()
51 51 {
52 52 qCInfo(LOG_SqpApplication()) << tr("SqpApplicationPrivate destruction");
53 53 m_DataSourceControllerThread.quit();
54 54 m_DataSourceControllerThread.wait();
55 55
56 56 m_NetworkControllerThread.quit();
57 57 m_NetworkControllerThread.wait();
58 58
59 59 m_VariableControllerThread.quit();
60 60 m_VariableControllerThread.wait();
61 61
62 62 m_VisualizationControllerThread.quit();
63 63 m_VisualizationControllerThread.wait();
64 64 }
65 65
66 66 std::unique_ptr<DataSourceController> m_DataSourceController;
67 67 std::unique_ptr<VariableController> m_VariableController;
68 68 std::unique_ptr<TimeController> m_TimeController;
69 69 std::unique_ptr<NetworkController> m_NetworkController;
70 70 std::unique_ptr<VisualizationController> m_VisualizationController;
71 71 QThread m_DataSourceControllerThread;
72 72 QThread m_NetworkControllerThread;
73 73 QThread m_VariableControllerThread;
74 74 QThread m_VisualizationControllerThread;
75 75 };
76 76
77 77
78 78 SqpApplication::SqpApplication(int &argc, char **argv)
79 79 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
80 80 {
81 81 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
82 82
83 83 connect(&impl->m_DataSourceControllerThread, &QThread::started,
84 84 impl->m_DataSourceController.get(), &DataSourceController::initialize);
85 85 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
86 86 impl->m_DataSourceController.get(), &DataSourceController::finalize);
87 87
88 88 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
89 89 &NetworkController::initialize);
90 90 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
91 91 &NetworkController::finalize);
92 92
93 93 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
94 94 &VariableController::initialize);
95 95 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
96 96 &VariableController::finalize);
97 97
98 98 connect(&impl->m_VisualizationControllerThread, &QThread::started,
99 99 impl->m_VisualizationController.get(), &VisualizationController::initialize);
100 100 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
101 101 impl->m_VisualizationController.get(), &VisualizationController::finalize);
102 102
103 103 impl->m_DataSourceControllerThread.start();
104 104 impl->m_NetworkControllerThread.start();
105 105 impl->m_VariableControllerThread.start();
106 106 impl->m_VisualizationControllerThread.start();
107
108 // Core connections:
109 // NetworkController <-> VariableController
110 connect(&sqpApp->networkController(), &NetworkController::replyDownloadProgress,
111 &sqpApp->variableController(), &VariableController::onVariableRetrieveDataInProgress);
107 112 }
108 113
109 114 SqpApplication::~SqpApplication()
110 115 {
111 116 }
112 117
113 118 void SqpApplication::initialize()
114 119 {
115 120 }
116 121
117 122 DataSourceController &SqpApplication::dataSourceController() noexcept
118 123 {
119 124 return *impl->m_DataSourceController;
120 125 }
121 126
122 127 NetworkController &SqpApplication::networkController() noexcept
123 128 {
124 129 return *impl->m_NetworkController;
125 130 }
126 131
127 132 TimeController &SqpApplication::timeController() noexcept
128 133 {
129 134 return *impl->m_TimeController;
130 135 }
131 136
132 137 VariableController &SqpApplication::variableController() noexcept
133 138 {
134 139 return *impl->m_VariableController;
135 140 }
136 141
137 142 VisualizationController &SqpApplication::visualizationController() noexcept
138 143 {
139 144 return *impl->m_VisualizationController;
140 145 }
@@ -1,101 +1,140
1 1 #include <Variable/VariableController.h>
2 2 #include <Variable/VariableInspectorWidget.h>
3 3 #include <Variable/VariableMenuHeaderWidget.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <ui_VariableInspectorWidget.h>
7 7
8 8 #include <QSortFilterProxyModel>
9 #include <QStyledItemDelegate>
9 10 #include <QWidgetAction>
10 11
11 12 #include <SqpApplication.h>
12 13
13 14 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
14 15
16
17 class QProgressBarItemDelegate : public QStyledItemDelegate {
18
19 public:
20 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
21
22 void paint(QPainter *painter, const QStyleOptionViewItem &option,
23 const QModelIndex &index) const
24 {
25 auto data = index.data(Qt::DisplayRole);
26 auto progressData = index.data(VariableRoles::ProgressRole);
27 if (data.isValid() && progressData.isValid()) {
28 auto name = data.value<QString>();
29 auto progress = progressData.value<double>();
30 if (progress >= 0) {
31 auto progressBarOption = QStyleOptionProgressBar{};
32 progressBarOption.rect = option.rect;
33 progressBarOption.minimum = 0;
34 progressBarOption.maximum = 100;
35 progressBarOption.progress = progress;
36 progressBarOption.text
37 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
38 progressBarOption.textVisible = true;
39 progressBarOption.textAlignment = Qt::AlignCenter;
40
41 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
42 painter);
43 }
44 }
45 else {
46 QStyledItemDelegate::paint(painter, option, index);
47 }
48 }
49 };
50
15 51 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
16 : QWidget{parent}, ui{new Ui::VariableInspectorWidget}
52 : QWidget{parent},
53 ui{new Ui::VariableInspectorWidget},
54 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
17 55 {
18 56 ui->setupUi(this);
19 57
20 58 // Sets model for table
21 59 // auto sortFilterModel = new QSortFilterProxyModel{this};
22 60 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
23 61
24 62 auto variableModel = sqpApp->variableController().variableModel();
25 63 ui->tableView->setModel(variableModel);
26 64
27 65 // Adds extra signal/slot between view and model, so the view can be updated instantly when
28 66 // there is a change of data in the model
29 67 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
30 68 SLOT(refresh()));
31 69
32 70 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
71 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
33 72
34 73 // Fixes column sizes
35 74 auto model = ui->tableView->model();
36 75 const auto count = model->columnCount();
37 76 for (auto i = 0; i < count; ++i) {
38 77 ui->tableView->setColumnWidth(
39 78 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
40 79 }
41 80
42 81 // Sets selection options
43 82 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
44 83 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
45 84
46 85 // Connection to show a menu when right clicking on the tree
47 86 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
48 87 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
49 88 &VariableInspectorWidget::onTableMenuRequested);
50 89 }
51 90
52 91 VariableInspectorWidget::~VariableInspectorWidget()
53 92 {
54 93 delete ui;
55 94 }
56 95
57 96 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
58 97 {
59 98 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
60 99
61 100 // Gets the model to retrieve the underlying selected variables
62 101 auto model = sqpApp->variableController().variableModel();
63 102 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
64 103 for (const auto &selectedRow : qAsConst(selectedRows)) {
65 104 if (auto selectedVariable = model->variable(selectedRow.row())) {
66 105 selectedVariables.push_back(selectedVariable);
67 106 }
68 107 }
69 108
70 109 QMenu tableMenu{};
71 110
72 111 // Emits a signal so that potential receivers can populate the menu before displaying it
73 112 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
74 113
75 114 // Adds menu-specific actions
76 115 if (!selectedVariables.isEmpty()) {
77 116 // 'Delete' action
78 117 auto deleteFun = [&selectedVariables]() {
79 118 sqpApp->variableController().deleteVariables(selectedVariables);
80 119 };
81 120
82 121 tableMenu.addSeparator();
83 122 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
84 123 }
85 124
86 125 if (!tableMenu.isEmpty()) {
87 126 // Generates menu header (inserted before first action)
88 127 auto firstAction = tableMenu.actions().first();
89 128 auto headerAction = new QWidgetAction{&tableMenu};
90 129 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
91 130 tableMenu.insertAction(firstAction, headerAction);
92 131
93 132 // Displays menu
94 133 tableMenu.exec(mapToGlobal(pos));
95 134 }
96 135 }
97 136
98 137 void VariableInspectorWidget::refresh() noexcept
99 138 {
100 139 ui->tableView->viewport()->update();
101 140 }
@@ -1,132 +1,134
1 1 #include "AmdaResultParser.h"
2 2
3 3 #include <Data/ScalarSeries.h>
4 4
5 5 #include <QDateTime>
6 6 #include <QFile>
7 7 #include <QRegularExpression>
8 8
9 #include <cmath>
10
9 11 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
10 12
11 13 namespace {
12 14
13 15 /// Format for dates in result files
14 16 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
15 17
16 18 /// Separator between values in a result line
17 19 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
18 20
19 21 /// Regex to find unit in a line. Examples of valid lines:
20 22 /// ... - Units : nT - ...
21 23 /// ... -Units:nT- ...
22 24 /// ... -Units: mΒ²- ...
23 25 /// ... - Units : m/s - ...
24 26 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
25 27
26 28 /// Converts a string date to a double date
27 29 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
28 30 double doubleDate(const QString &stringDate) noexcept
29 31 {
30 32 auto dateTime = QDateTime::fromString(stringDate, DATE_FORMAT);
31 33 return dateTime.isValid() ? (dateTime.toMSecsSinceEpoch() / 1000.)
32 34 : std::numeric_limits<double>::quiet_NaN();
33 35 }
34 36
35 37 /**
36 38 * Reads stream to retrieve x-axis unit
37 39 * @param stream the stream to read
38 40 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
39 41 * error occured during reading
40 42 */
41 43 Unit readXAxisUnit(QTextStream &stream)
42 44 {
43 45 QString line{};
44 46
45 47 if (stream.readLineInto(&line)) {
46 48 auto match = UNIT_REGEX.match(line);
47 49 if (match.hasMatch()) {
48 50 return Unit{match.captured(1), true};
49 51 }
50 52 else {
51 53 qCWarning(LOG_AmdaResultParser())
52 54 << QObject::tr("Can't read unit: invalid line %1").arg(line);
53 55 }
54 56 }
55 57 else {
56 58 qCWarning(LOG_AmdaResultParser()) << QObject::tr("Can't read unit: end of file");
57 59 }
58 60
59 61 // Error cases
60 62 return Unit{{}, true};
61 63 }
62 64
63 65 /**
64 66 * Reads stream to retrieve results
65 67 * @param stream the stream to read
66 68 * @return the pair of vectors x-axis data/values data that has been read in the stream
67 69 */
68 70 QPair<QVector<double>, QVector<double> > readResults(QTextStream &stream)
69 71 {
70 72 auto xData = QVector<double>{};
71 73 auto valuesData = QVector<double>{};
72 74
73 75 QString line{};
74 76 while (stream.readLineInto(&line)) {
75 77 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
76 78 if (lineData.size() == 2) {
77 79 // X : the data is converted from date to double (in secs)
78 80 auto x = doubleDate(lineData.at(0));
79 81
80 82 // Value
81 83 bool valueOk;
82 84 auto value = lineData.at(1).toDouble(&valueOk);
83 85
84 86 // Adds result only if x and value are valid
85 87 if (!std::isnan(x) && !std::isnan(value) && valueOk) {
86 88 xData.push_back(x);
87 89 valuesData.push_back(value);
88 90 }
89 91 else {
90 92 qCWarning(LOG_AmdaResultParser())
91 93 << QObject::tr(
92 94 "Can't retrieve results from line %1: x and/or value are invalid")
93 95 .arg(line);
94 96 }
95 97 }
96 98 else {
97 99 qCWarning(LOG_AmdaResultParser())
98 100 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
99 101 }
100 102 }
101 103
102 104 return qMakePair(std::move(xData), std::move(valuesData));
103 105 }
104 106
105 107 } // namespace
106 108
107 109 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath) noexcept
108 110 {
109 111 QFile file{filePath};
110 112
111 113 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
112 114 qCCritical(LOG_AmdaResultParser())
113 115 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
114 116 .arg(filePath, file.errorString());
115 117 return nullptr;
116 118 }
117 119
118 120 QTextStream stream{&file};
119 121
120 122 // Ignore first two lines (comments lines)
121 123 stream.readLine();
122 124 stream.readLine();
123 125
124 126 // Reads x-axis unit
125 127 auto xAxisUnit = readXAxisUnit(stream);
126 128
127 129 // Reads results
128 130 auto results = readResults(stream);
129 131
130 132 return std::make_shared<ScalarSeries>(std::move(results.first), std::move(results.second),
131 133 xAxisUnit, Unit{});
132 134 }
@@ -1,179 +1,179
1 1 #include "AmdaResultParser.h"
2 2
3 3 #include <Data/ScalarSeries.h>
4 4
5 5 #include <QObject>
6 6 #include <QtTest>
7 7
8 8 namespace {
9 9
10 10 /// Path for the tests
11 11 const auto TESTS_RESOURCES_PATH
12 12 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
13 13
14 14 QString inputFilePath(const QString &inputFileName)
15 15 {
16 16 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
17 17 }
18 18
19 19 struct ExpectedResults {
20 20 explicit ExpectedResults() = default;
21 21
22 22 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
23 23 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
24 24 QVector<double> valuesData)
25 25 : m_ParsingOK{true},
26 26 m_XAxisUnit{xAxisUnit},
27 27 m_ValuesUnit{valuesUnit},
28 28 m_XAxisData{},
29 29 m_ValuesData{std::move(valuesData)}
30 30 {
31 31 // Converts QVector<QDateTime> to QVector<double>
32 32 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
33 33 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
34 34 }
35 35
36 36 /**
37 37 * Validates a DataSeries compared to the expected results
38 38 * @param results the DataSeries to validate
39 39 */
40 40 void validate(std::shared_ptr<IDataSeries> results)
41 41 {
42 42 if (m_ParsingOK) {
43 43 auto scalarSeries = dynamic_cast<ScalarSeries *>(results.get());
44 44 QVERIFY(scalarSeries != nullptr);
45 45
46 46 // Checks units
47 47 QVERIFY(scalarSeries->xAxisUnit() == m_XAxisUnit);
48 48 QVERIFY(scalarSeries->valuesUnit() == m_ValuesUnit);
49 49
50 50 // Checks values
51 51 QVERIFY(scalarSeries->xAxisData()->data() == m_XAxisData);
52 52 QVERIFY(scalarSeries->valuesData()->data() == m_ValuesData);
53 53 }
54 54 else {
55 55 QVERIFY(results == nullptr);
56 56 }
57 57 }
58 58
59 59 // Parsing was successfully completed
60 60 bool m_ParsingOK{false};
61 61 // Expected x-axis unit
62 62 Unit m_XAxisUnit{};
63 63 // Expected values unit
64 64 Unit m_ValuesUnit{};
65 65 // Expected x-axis data
66 66 QVector<double> m_XAxisData{};
67 67 // Expected values data
68 68 QVector<double> m_ValuesData{};
69 69 };
70 70
71 71 } // namespace
72 72
73 73 Q_DECLARE_METATYPE(ExpectedResults)
74 74
75 75 class TestAmdaResultParser : public QObject {
76 76 Q_OBJECT
77 77 private slots:
78 78 /// Input test data
79 79 /// @sa testTxtJson()
80 80 void testReadTxt_data();
81 81
82 82 /// Tests parsing of a TXT file
83 83 void testReadTxt();
84 84 };
85 85
86 86 void TestAmdaResultParser::testReadTxt_data()
87 87 {
88 88 // ////////////// //
89 89 // Test structure //
90 90 // ////////////// //
91 91
92 92 // Name of TXT file to read
93 93 QTest::addColumn<QString>("inputFileName");
94 94 // Expected results
95 95 QTest::addColumn<ExpectedResults>("expectedResults");
96 96
97 97 // ////////// //
98 98 // Test cases //
99 99 // ////////// //
100 100
101 101 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
102 102 return QDateTime{{year, month, day}, {hours, minutes, seconds}};
103 103 };
104 104
105 105 // Valid file
106 106 QTest::newRow("Valid file")
107 107 << QStringLiteral("ValidScalar1.txt")
108 108 << ExpectedResults{
109 109 Unit{QStringLiteral("nT"), true}, Unit{},
110 110 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
111 111 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
112 112 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
113 113 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
114 114 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
115 115 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
116 116 -2.55800, -2.43250, -2.42200}};
117 117
118 118 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
119 119 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
120 120 << ExpectedResults{Unit{QStringLiteral(""), true}, Unit{},
121 121 QVector<QDateTime>{}, QVector<double>{}};
122 122 QTest::newRow("Wrong unit file")
123 123 << QStringLiteral("WrongUnit.txt")
124 124 << ExpectedResults{Unit{QStringLiteral(""), true}, Unit{},
125 125 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
126 126 dateTime(2013, 9, 23, 9, 1, 30),
127 127 dateTime(2013, 9, 23, 9, 2, 30)},
128 128 QVector<double>{-2.83950, -2.71850, -2.52150}};
129 129
130 130 QTest::newRow("Wrong results file (date of first line is invalid")
131 131 << QStringLiteral("WrongDate.txt")
132 132 << ExpectedResults{
133 133 Unit{QStringLiteral("nT"), true}, Unit{},
134 134 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
135 135 QVector<double>{-2.71850, -2.52150}};
136 136
137 137 QTest::newRow("Wrong results file (too many values for first line")
138 138 << QStringLiteral("TooManyValues.txt")
139 139 << ExpectedResults{
140 140 Unit{QStringLiteral("nT"), true}, Unit{},
141 141 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
142 142 QVector<double>{-2.71850, -2.52150}};
143 143
144 144 QTest::newRow("Wrong results file (value of first line is invalid")
145 145 << QStringLiteral("WrongValue.txt")
146 146 << ExpectedResults{
147 147 Unit{QStringLiteral("nT"), true}, Unit{},
148 148 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
149 149 QVector<double>{-2.71850, -2.52150}};
150 150
151 151 QTest::newRow("Wrong results file (value of first line is NaN")
152 152 << QStringLiteral("NaNValue.txt")
153 153 << ExpectedResults{
154 154 Unit{QStringLiteral("nT"), true}, Unit{},
155 155 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
156 156 QVector<double>{-2.71850, -2.52150}};
157 157
158 158 // Invalid file
159 QTest::newRow("Invalid file (unexisting file)")
160 << QStringLiteral("UnexistingFile.txt") << ExpectedResults{};
159 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.txt")
160 << ExpectedResults{};
161 161 }
162 162
163 163 void TestAmdaResultParser::testReadTxt()
164 164 {
165 165 QFETCH(QString, inputFileName);
166 166 QFETCH(ExpectedResults, expectedResults);
167 167
168 168 // Parses file
169 169 auto filePath = inputFilePath(inputFileName);
170 170 auto results = AmdaResultParser::readTxt(filePath);
171 171
172 172 // ///////////////// //
173 173 // Validates results //
174 174 // ///////////////// //
175 175 expectedResults.validate(results);
176 176 }
177 177
178 178 QTEST_MAIN(TestAmdaResultParser)
179 179 #include "TestAmdaResultParser.moc"
General Comments 0
You need to be logged in to leave comments. Login now