##// END OF EJS Templates
Removes compilation warnings (with Meson)
Alexandre Leroux -
r961:15899f42a907
parent child
Show More
@@ -1,139 +1,139
1 1 #ifndef SCIQLOP_SORTUTILS_H
2 2 #define SCIQLOP_SORTUTILS_H
3 3
4 4 #include <algorithm>
5 5 #include <cmath>
6 6 #include <numeric>
7 7 #include <vector>
8 8
9 9 /**
10 10 * Utility class with methods for sorting data
11 11 */
12 12 struct SortUtils {
13 13 /**
14 14 * Generates a vector representing the index of insertion of each data of a container if this
15 15 * one had to be sorted according to a comparison function.
16 16 *
17 17 * For example:
18 18 * If the container is a vector {1; 4; 2; 5; 3} and the comparison function is std::less, the
19 19 * result would be : {0; 3; 1; 4; 2}
20 20 *
21 21 * @tparam Container the type of the container.
22 22 * @tparam Compare the type of the comparison function
23 23 * @param container the container from which to generate the result. The container must have a
24 24 * at() method that returns a value associated to an index
25 25 * @param compare the comparison function
26 26 */
27 27 template <typename Container, typename Compare>
28 28 static std::vector<int> sortPermutation(const Container &container, const Compare &compare)
29 29 {
30 30 auto permutation = std::vector<int>{};
31 31 permutation.resize(container.size());
32 32
33 33 std::iota(permutation.begin(), permutation.end(), 0);
34 34 std::sort(permutation.begin(), permutation.end(),
35 35 [&](int i, int j) { return compare(container.at(i), container.at(j)); });
36 36 return permutation;
37 37 }
38 38
39 39 /**
40 40 * Sorts a container according to indices passed in parameter. The number of data in the
41 41 * container must be a multiple of the number of indices used to sort the container.
42 42 *
43 43 * Example 1:
44 44 * container: {1, 2, 3, 4, 5, 6}
45 45 * sortPermutation: {1, 0}
46 46 *
47 47 * Values will be sorted three by three, and the result will be:
48 48 * {4, 5, 6, 1, 2, 3}
49 49 *
50 50 * Example 2:
51 51 * container: {1, 2, 3, 4, 5, 6}
52 52 * sortPermutation: {2, 0, 1}
53 53 *
54 54 * Values will be sorted two by two, and the result will be:
55 55 * {5, 6, 1, 2, 3, 4}
56 56 *
57 57 * @param container the container sorted
58 58 * @param sortPermutation the indices used to sort the container
59 59 * @return the container sorted
60 60 * @warning no verification is made on validity of sortPermutation (i.e. the vector has unique
61 61 * indices and its range is [0 ; vector.size()[ )
62 62 */
63 63 template <typename Container>
64 64 static Container sort(const Container &container, int nbValues,
65 65 const std::vector<int> &sortPermutation)
66 66 {
67 67 auto containerSize = container.size();
68 68 if (containerSize % nbValues != 0
69 69 || ((containerSize / nbValues) != sortPermutation.size())) {
70 70 return Container{};
71 71 }
72 72
73 73 // Inits result
74 74 auto sortedData = Container{};
75 75 sortedData.reserve(containerSize);
76 76
77 for (auto i = 0, componentIndex = 0, permutationIndex = 0; i < containerSize;
77 for (auto i = 0u, componentIndex = 0u, permutationIndex = 0u; i < containerSize;
78 78 ++i, componentIndex = i % nbValues, permutationIndex = i / nbValues) {
79 79 auto insertIndex = sortPermutation.at(permutationIndex) * nbValues + componentIndex;
80 80 sortedData.push_back(container.at(insertIndex));
81 81 }
82 82
83 83 return sortedData;
84 84 }
85 85
86 86 /**
87 87 * Compares two values that can be NaN. This method is intended to be used as a compare function
88 88 * for searching min value by excluding NaN values.
89 89 *
90 90 * Examples of use:
91 91 * - f({1, 3, 2, 4, 5}) will return 1
92 92 * - f({NaN, 3, 2, 4, 5}) will return 2 (NaN is excluded)
93 93 * - f({NaN, NaN, 3, NaN, NaN}) will return 3 (NaN are excluded)
94 94 * - f({NaN, NaN, NaN, NaN, NaN}) will return NaN (no existing value)
95 95 *
96 96 * @param v1 first value
97 97 * @param v2 second value
98 98 * @return true if v1 < v2, false otherwise
99 99 * @sa std::min_element
100 100 */
101 101 template <typename T>
102 102 static bool minCompareWithNaN(const T &v1, const T &v2)
103 103 {
104 104 // Table used with NaN values:
105 105 // NaN < v2 -> false
106 106 // v1 < NaN -> true
107 107 // NaN < NaN -> false
108 108 // v1 < v2 -> v1 < v2
109 109 return std::isnan(v1) ? false : std::isnan(v2) || (v1 < v2);
110 110 }
111 111
112 112 /**
113 113 * Compares two values that can be NaN. This method is intended to be used as a compare function
114 114 * for searching max value by excluding NaN values.
115 115 *
116 116 * Examples of use:
117 117 * - f({1, 3, 2, 4, 5}) will return 5
118 118 * - f({1, 3, 2, 4, NaN}) will return 4 (NaN is excluded)
119 119 * - f({NaN, NaN, 3, NaN, NaN}) will return 3 (NaN are excluded)
120 120 * - f({NaN, NaN, NaN, NaN, NaN}) will return NaN (no existing value)
121 121 *
122 122 * @param v1 first value
123 123 * @param v2 second value
124 124 * @return true if v1 < v2, false otherwise
125 125 * @sa std::max_element
126 126 */
127 127 template <typename T>
128 128 static bool maxCompareWithNaN(const T &v1, const T &v2)
129 129 {
130 130 // Table used with NaN values:
131 131 // NaN < v2 -> true
132 132 // v1 < NaN -> false
133 133 // NaN < NaN -> false
134 134 // v1 < v2 -> v1 < v2
135 135 return std::isnan(v1) ? true : !std::isnan(v2) && (v1 < v2);
136 136 }
137 137 };
138 138
139 139 #endif // SCIQLOP_SORTUTILS_H
@@ -1,31 +1,32
1 1 #ifndef SCIQLOP_VARIABLECACHESTRATEGY_H
2 2 #define SCIQLOP_VARIABLECACHESTRATEGY_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8
9 9 #include <Data/SqpRange.h>
10 10
11 11 #include <QLoggingCategory>
12 12
13 13 #include <Common/spimpl.h>
14 14 #include <utility>
15 15
16 16
17 17 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableCacheStrategy)
18 18
19 19 class Variable;
20 20
21 21 /// This class aims to hande the cache strategy.
22 22 class SCIQLOP_CORE_EXPORT VariableCacheStrategy {
23 23
24 24 public:
25 virtual ~VariableCacheStrategy() noexcept = default;
25 26 virtual std::pair<SqpRange, SqpRange> computeRange(const SqpRange &vRange,
26 27 const SqpRange &rangeRequested)
27 28 = 0;
28 29 };
29 30
30 31
31 32 #endif // SCIQLOP_VARIABLECACHESTRATEGY_H
@@ -1,44 +1,46
1 1 #ifndef SCIQLOP_VARIABLECACHESTRATEGYFACTORY_H
2 2 #define SCIQLOP_VARIABLECACHESTRATEGYFACTORY_H
3 3
4 4
5 5 #include <memory>
6 6 #include <stdexcept>
7 7
8 8 #include "VariableCacheStrategy.h"
9 9 #include "VariableSingleThresholdCacheStrategy.h"
10 10
11 11 #include <QLoggingCategory>
12 12 #include <QString>
13 13
14 14 Q_LOGGING_CATEGORY(LOG_VariableCacheStrategyFactory, "VariableCacheStrategyFactory")
15 15
16 16 enum class CacheStrategy { SingleThreshold, TwoThreashold };
17 17
18 18 class VariableCacheStrategyFactory {
19 19
20 20 using cacheStratPtr = std::unique_ptr<VariableCacheStrategy>;
21 21
22 22 public:
23 23 static cacheStratPtr createCacheStrategy(CacheStrategy specificStrategy)
24 24 {
25 25 switch (specificStrategy) {
26 26 case CacheStrategy::SingleThreshold: {
27 27 return std::unique_ptr<VariableCacheStrategy>{
28 28 new VariableSingleThresholdCacheStrategy{}};
29 29 break;
30 30 }
31 31 case CacheStrategy::TwoThreashold: {
32 32 qCCritical(LOG_VariableCacheStrategyFactory())
33 33 << QObject::tr("cache strategy not implemented yet");
34 34 break;
35 35 }
36 36 default:
37 37 qCCritical(LOG_VariableCacheStrategyFactory())
38 38 << QObject::tr("Unknown cache strategy");
39 39 }
40
41 return nullptr;
40 42 }
41 43 };
42 44
43 45
44 46 #endif // VARIABLECACHESTRATEGYFACTORY_H
@@ -1,65 +1,64
1 1
2 2 core_moc_headers = [
3 3 'include/Data/IDataProvider.h',
4 4 'include/DataSource/DataSourceController.h',
5 5 'include/DataSource/DataSourceItemAction.h',
6 6 'include/Network/NetworkController.h',
7 7 'include/Time/TimeController.h',
8 8 'include/Variable/Variable.h',
9 9 'include/Variable/VariableCacheController.h',
10 10 'include/Variable/VariableController.h',
11 11 'include/Variable/VariableAcquisitionWorker.h',
12 'include/Variable/VariableCacheStrategy.h',
13 12 'include/Variable/VariableSynchronizationGroup.h',
14 13 'include/Variable/VariableModel.h',
15 14 'include/Visualization/VisualizationController.h'
16 15 ]
17 16
18 17
19 18 core_moc_files = qt5.preprocess(moc_headers : core_moc_headers)
20 19
21 20 core_sources = [
22 21 'src/Common/DateUtils.cpp',
23 22 'src/Common/StringUtils.cpp',
24 23 'src/Common/MimeTypesDef.cpp',
25 24 'src/Data/ScalarSeries.cpp',
26 25 'src/Data/SpectrogramSeries.cpp',
27 26 'src/Data/DataSeriesIterator.cpp',
28 27 'src/Data/ArrayDataIterator.cpp',
29 28 'src/Data/VectorSeries.cpp',
30 29 'src/Data/OptionalAxis.cpp',
31 30 'src/DataSource/DataSourceController.cpp',
32 31 'src/DataSource/DataSourceItem.cpp',
33 32 'src/DataSource/DataSourceItemAction.cpp',
34 33 'src/Network/NetworkController.cpp',
35 34 'src/Plugin/PluginManager.cpp',
36 35 'src/Settings/SqpSettingsDefs.cpp',
37 36 'src/Time/TimeController.cpp',
38 37 'src/Variable/Variable.cpp',
39 38 'src/Variable/VariableCacheController.cpp',
40 39 'src/Variable/VariableController.cpp',
41 40 'src/Variable/VariableAcquisitionWorker.cpp',
42 41 'src/Variable/VariableSynchronizationGroup.cpp',
43 42 'src/Variable/VariableModel.cpp',
44 43 'src/Visualization/VisualizationController.cpp'
45 44 ]
46 45
47 46 core_inc = include_directories(['include', '../plugin/include'])
48 47
49 48 sciqlop_core_lib = library('sciqlopcore',
50 49 core_sources,
51 50 core_moc_files,
52 51 cpp_args : '-DCORE_LIB',
53 52 include_directories : core_inc,
54 53 dependencies : [qt5core, qt5network],
55 54 install : true
56 55 )
57 56
58 57
59 58 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
60 59 include_directories : core_inc,
61 60 dependencies : [qt5core, qt5network])
62 61
63 62
64 63 subdir('tests')
65 64
@@ -1,101 +1,99
1 1 #include <Data/OptionalAxis.h>
2 2
3 3 #include "Data/ArrayData.h"
4 4
5 5 OptionalAxis::OptionalAxis() : m_Defined{false}, m_Data{nullptr}, m_Unit{}
6 6 {
7 7 }
8 8
9 9 OptionalAxis::OptionalAxis(std::shared_ptr<ArrayData<1> > data, Unit unit)
10 10 : m_Defined{true}, m_Data{data}, m_Unit{std::move(unit)}
11 11 {
12 12 if (m_Data == nullptr) {
13 13 throw std::invalid_argument{"Data can't be null for a defined axis"};
14 14 }
15 15 }
16 16
17 17 OptionalAxis::OptionalAxis(const OptionalAxis &other)
18 18 : m_Defined{other.m_Defined},
19 19 m_Data{other.m_Data ? std::make_shared<ArrayData<1> >(*other.m_Data) : nullptr},
20 20 m_Unit{other.m_Unit}
21 21 {
22 22 }
23 23
24 24 OptionalAxis &OptionalAxis::operator=(OptionalAxis other)
25 25 {
26 26 std::swap(m_Defined, other.m_Defined);
27 27 std::swap(m_Data, other.m_Data);
28 28 std::swap(m_Unit, other.m_Unit);
29 29
30 30 return *this;
31 31 }
32 32
33 33 bool OptionalAxis::isDefined() const
34 34 {
35 35 return m_Defined;
36 36 }
37 37
38 38 double OptionalAxis::at(int index) const
39 39 {
40 40 if (m_Defined) {
41 41 return (index >= 0 && index < m_Data->size()) ? m_Data->at(index)
42 42 : std::numeric_limits<double>::quiet_NaN();
43 43 }
44 44 else {
45 45 return std::numeric_limits<double>::quiet_NaN();
46 46 }
47 47 }
48 48
49 49 std::pair<double, double> OptionalAxis::bounds() const
50 50 {
51 51 if (!m_Defined || m_Data->size() == 0) {
52 52 return std::make_pair(std::numeric_limits<double>::quiet_NaN(),
53 53 std::numeric_limits<double>::quiet_NaN());
54 54 }
55 55 else {
56 56
57 57 auto minIt = std::min_element(
58 58 m_Data->cbegin(), m_Data->cend(), [](const auto &it1, const auto &it2) {
59 59 return SortUtils::minCompareWithNaN(it1.first(), it2.first());
60 60 });
61 61
62 62 // Gets the iterator on the max of all values data
63 63 auto maxIt = std::max_element(
64 64 m_Data->cbegin(), m_Data->cend(), [](const auto &it1, const auto &it2) {
65 65 return SortUtils::maxCompareWithNaN(it1.first(), it2.first());
66 66 });
67 67
68 auto pair = std::make_pair(minIt->first(), maxIt->first());
69
70 68 return std::make_pair(minIt->first(), maxIt->first());
71 69 }
72 70 }
73 71
74 72 int OptionalAxis::size() const
75 73 {
76 74 return m_Defined ? m_Data->size() : 0;
77 75 }
78 76
79 77 Unit OptionalAxis::unit() const
80 78 {
81 79 return m_Defined ? m_Unit : Unit{};
82 80 }
83 81
84 82 bool OptionalAxis::operator==(const OptionalAxis &other)
85 83 {
86 84 // Axis not defined
87 85 if (!m_Defined) {
88 86 return !other.m_Defined;
89 87 }
90 88
91 89 // Axis defined
92 90 return m_Unit == other.m_Unit
93 91 && std::equal(
94 92 m_Data->cbegin(), m_Data->cend(), other.m_Data->cbegin(), other.m_Data->cend(),
95 93 [](const auto &it1, const auto &it2) { return it1.values() == it2.values(); });
96 94 }
97 95
98 96 bool OptionalAxis::operator!=(const OptionalAxis &other)
99 97 {
100 98 return !(*this == other);
101 99 }
@@ -1,83 +1,83
1 1 #include "Data/VectorSeries.h"
2 2
3 3 namespace {
4 4
5 5 /**
6 6 * Flatten the three components of a vector to a single QVector that can be passed to an ArrayData
7 7 *
8 8 * Example:
9 9 * xValues = {1, 2, 3}
10 10 * yValues = {4, 5, 6}
11 11 * zValues = {7, 8, 9}
12 12 *
13 13 * result = {1, 4, 7, 2, 5, 8, 3, 6, 9}
14 14 *
15 15 * @param xValues the x-component values of the vector
16 16 * @param yValues the y-component values of the vector
17 17 * @param zValues the z-component values of the vector
18 18 * @return the single QVector
19 19 * @remarks the three components are consumed
20 20 * @sa ArrayData
21 21 */
22 22 std::vector<double> flatten(std::vector<double> xValues, std::vector<double> yValues,
23 23 std::vector<double> zValues)
24 24 {
25 25 if (xValues.size() != yValues.size() || xValues.size() != zValues.size()) {
26 26 /// @todo ALX : log
27 27 return {};
28 28 }
29 29
30 30 auto result = std::vector<double>();
31 31 result.reserve(xValues.size() * 3);
32 for (int i = 0; i < xValues.size(); i++) {
32 for (auto i = 0u; i < xValues.size(); ++i) {
33 33 result.push_back(xValues[i]);
34 34 result.push_back(yValues[i]);
35 35 result.push_back(zValues[i]);
36 36 }
37 37
38 38 return result;
39 39 }
40 40
41 41 } // namespace
42 42
43 43 VectorSeries::VectorSeries(std::vector<double> xAxisData, std::vector<double> xValuesData,
44 44 std::vector<double> yValuesData, std::vector<double> zValuesData,
45 45 const Unit &xAxisUnit, const Unit &valuesUnit)
46 46 : VectorSeries{std::move(xAxisData), flatten(std::move(xValuesData), std::move(yValuesData),
47 47 std::move(zValuesData)),
48 48 xAxisUnit, valuesUnit}
49 49 {
50 50 }
51 51
52 52 VectorSeries::VectorSeries(std::vector<double> xAxisData, std::vector<double> valuesData,
53 53 const Unit &xAxisUnit, const Unit &valuesUnit)
54 54 : DataSeries{std::make_shared<ArrayData<1> >(std::move(xAxisData)), xAxisUnit,
55 55 std::make_shared<ArrayData<2> >(std::move(valuesData), 3), valuesUnit}
56 56 {
57 57 }
58 58
59 59 std::unique_ptr<IDataSeries> VectorSeries::clone() const
60 60 {
61 61 return std::make_unique<VectorSeries>(*this);
62 62 }
63 63
64 64 std::shared_ptr<IDataSeries> VectorSeries::subDataSeries(const SqpRange &range)
65 65 {
66 66 auto subXAxisData = std::vector<double>();
67 67 auto subValuesData = std::vector<double>();
68 68
69 69 this->lockRead();
70 70 {
71 71 auto bounds = xAxisRange(range.m_TStart, range.m_TEnd);
72 72 for (auto it = bounds.first; it != bounds.second; ++it) {
73 73 subXAxisData.push_back(it->x());
74 74 subValuesData.push_back(it->value(0));
75 75 subValuesData.push_back(it->value(1));
76 76 subValuesData.push_back(it->value(2));
77 77 }
78 78 }
79 79 this->unlock();
80 80
81 81 return std::make_shared<VectorSeries>(std::move(subXAxisData), std::move(subValuesData),
82 82 this->xAxisUnit(), this->valuesUnit());
83 83 }
@@ -1,1060 +1,1063
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableAcquisitionWorker.h>
3 3 #include <Variable/VariableCacheStrategy.h>
4 4 #include <Variable/VariableCacheStrategyFactory.h>
5 5 #include <Variable/VariableController.h>
6 6 #include <Variable/VariableModel.h>
7 7 #include <Variable/VariableSynchronizationGroup.h>
8 8
9 9 #include <Data/DataProviderParameters.h>
10 10 #include <Data/IDataProvider.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <Data/VariableRequest.h>
13 13 #include <Time/TimeController.h>
14 14
15 15 #include <QDataStream>
16 16 #include <QMutex>
17 17 #include <QThread>
18 18 #include <QUuid>
19 19 #include <QtCore/QItemSelectionModel>
20 20
21 21 #include <deque>
22 22 #include <set>
23 23 #include <unordered_map>
24 24
25 25 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
26 26
27 27 namespace {
28 28
29 29 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
30 30 const SqpRange &oldGraphRange)
31 31 {
32 32 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
33 33
34 34 auto varRangeRequested = varRange;
35 35 switch (zoomType) {
36 36 case AcquisitionZoomType::ZoomIn: {
37 37 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
38 38 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
39 39 varRangeRequested.m_TStart += deltaLeft;
40 40 varRangeRequested.m_TEnd -= deltaRight;
41 41 break;
42 42 }
43 43
44 44 case AcquisitionZoomType::ZoomOut: {
45 45 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
46 46 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
47 47 varRangeRequested.m_TStart -= deltaLeft;
48 48 varRangeRequested.m_TEnd += deltaRight;
49 49 break;
50 50 }
51 51 case AcquisitionZoomType::PanRight: {
52 52 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
53 53 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
54 54 varRangeRequested.m_TStart += deltaLeft;
55 55 varRangeRequested.m_TEnd += deltaRight;
56 56 break;
57 57 }
58 58 case AcquisitionZoomType::PanLeft: {
59 59 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
60 60 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
61 61 varRangeRequested.m_TStart -= deltaLeft;
62 62 varRangeRequested.m_TEnd -= deltaRight;
63 63 break;
64 64 }
65 65 case AcquisitionZoomType::Unknown: {
66 66 qCCritical(LOG_VariableController())
67 67 << VariableController::tr("Impossible to synchronize: zoom type unknown");
68 68 break;
69 69 }
70 70 default:
71 71 qCCritical(LOG_VariableController()) << VariableController::tr(
72 72 "Impossible to synchronize: zoom type not take into account");
73 73 // No action
74 74 break;
75 75 }
76 76
77 77 return varRangeRequested;
78 78 }
79 79 }
80 80
81 81 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
82 82
83 83 struct VariableRequestHandler {
84 84
85 85 VariableRequestHandler()
86 86 {
87 87 m_CanUpdate = false;
88 88 m_State = VariableRequestHandlerState::OFF;
89 89 }
90 90
91 91 QUuid m_VarId;
92 92 VariableRequest m_RunningVarRequest;
93 93 VariableRequest m_PendingVarRequest;
94 94 VariableRequestHandlerState m_State;
95 95 bool m_CanUpdate;
96 96 };
97 97
98 98 struct VariableController::VariableControllerPrivate {
99 99 explicit VariableControllerPrivate(VariableController *parent)
100 100 : m_WorkingMutex{},
101 101 m_VariableModel{new VariableModel{parent}},
102 102 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
103 103 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
104 104 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
105 105 CacheStrategy::SingleThreshold)},
106 106 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
107 107 q{parent}
108 108 {
109 109
110 110 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
111 111 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
112 112 }
113 113
114 114
115 115 virtual ~VariableControllerPrivate()
116 116 {
117 117 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
118 118 m_VariableAcquisitionWorkerThread.quit();
119 119 m_VariableAcquisitionWorkerThread.wait();
120 120 }
121 121
122 122
123 123 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
124 124 QUuid varRequestId);
125 125
126 126 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
127 127 std::shared_ptr<IDataSeries>
128 128 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
129 129
130 130 void registerProvider(std::shared_ptr<IDataProvider> provider);
131 131
132 132 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
133 133 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
134 134 void updateVariables(QUuid varRequestId);
135 135 void updateVariableRequest(QUuid varRequestId);
136 136 void cancelVariableRequest(QUuid varRequestId);
137 137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
138 138
139 139 QMutex m_WorkingMutex;
140 140 /// Variable model. The VariableController has the ownership
141 141 VariableModel *m_VariableModel;
142 142 QItemSelectionModel *m_VariableSelectionModel;
143 143
144 144
145 145 TimeController *m_TimeController{nullptr};
146 146 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
147 147 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
148 148 QThread m_VariableAcquisitionWorkerThread;
149 149
150 150 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
151 151 m_VariableToProviderMap;
152 152 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
153 153 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
154 154 m_GroupIdToVariableSynchronizationGroupMap;
155 155 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
156 156 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
157 157
158 158 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
159 159 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
160 160
161 161 VariableController *q;
162 162 };
163 163
164 164
165 165 VariableController::VariableController(QObject *parent)
166 166 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
167 167 {
168 168 qCDebug(LOG_VariableController()) << tr("VariableController construction")
169 169 << QThread::currentThread();
170 170
171 171 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
172 172 &VariableController::onAbortProgressRequested);
173 173
174 174 connect(impl->m_VariableAcquisitionWorker.get(),
175 175 &VariableAcquisitionWorker::variableCanceledRequested, this,
176 176 &VariableController::onAbortAcquisitionRequested);
177 177
178 178 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
179 179 &VariableController::onDataProvided);
180 180 connect(impl->m_VariableAcquisitionWorker.get(),
181 181 &VariableAcquisitionWorker::variableRequestInProgress, this,
182 182 &VariableController::onVariableRetrieveDataInProgress);
183 183
184 184
185 185 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
186 186 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
187 187 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
188 188 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
189 189
190 190 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
191 191 &VariableController::onUpdateDateTime);
192 192
193 193 impl->m_VariableAcquisitionWorkerThread.start();
194 194 }
195 195
196 196 VariableController::~VariableController()
197 197 {
198 198 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
199 199 << QThread::currentThread();
200 200 this->waitForFinish();
201 201 }
202 202
203 203 VariableModel *VariableController::variableModel() noexcept
204 204 {
205 205 return impl->m_VariableModel;
206 206 }
207 207
208 208 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
209 209 {
210 210 return impl->m_VariableSelectionModel;
211 211 }
212 212
213 213 void VariableController::setTimeController(TimeController *timeController) noexcept
214 214 {
215 215 impl->m_TimeController = timeController;
216 216 }
217 217
218 218 std::shared_ptr<Variable>
219 219 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
220 220 {
221 221 if (impl->m_VariableModel->containsVariable(variable)) {
222 222 // Clones variable
223 223 auto duplicate = variable->clone();
224 224
225 225 // Adds clone to model
226 226 impl->m_VariableModel->addVariable(duplicate);
227 227
228 228 // Generates clone identifier
229 229 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
230 230
231 231 // Registers provider
232 232 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
233 233 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
234 234
235 235 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
236 236 if (duplicateProvider) {
237 237 impl->registerProvider(duplicateProvider);
238 238 }
239 239
240 240 return duplicate;
241 241 }
242 242 else {
243 243 qCCritical(LOG_VariableController())
244 244 << tr("Can't create duplicate of variable %1: variable not registered in the model")
245 245 .arg(variable->name());
246 246 return nullptr;
247 247 }
248 248 }
249 249
250 250 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
251 251 {
252 252 if (!variable) {
253 253 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
254 254 return;
255 255 }
256 256
257 257 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
258 258 // make some treatments before the deletion
259 259 emit variableAboutToBeDeleted(variable);
260 260
261 261 // Deletes identifier
262 262 impl->m_VariableToIdentifierMap.erase(variable);
263 263
264 264 // Deletes provider
265 265 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
266 266 qCDebug(LOG_VariableController())
267 267 << tr("Number of providers deleted for variable %1: %2")
268 268 .arg(variable->name(), QString::number(nbProvidersDeleted));
269 269
270 270
271 271 // Deletes from model
272 272 impl->m_VariableModel->deleteVariable(variable);
273 273 }
274 274
275 275 void VariableController::deleteVariables(
276 276 const QVector<std::shared_ptr<Variable> > &variables) noexcept
277 277 {
278 278 for (auto variable : qAsConst(variables)) {
279 279 deleteVariable(variable);
280 280 }
281 281 }
282 282
283 283 QByteArray
284 284 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
285 285 {
286 286 auto encodedData = QByteArray{};
287 287
288 288 QVariantList ids;
289 289 for (auto &var : variables) {
290 290 auto itVar = impl->m_VariableToIdentifierMap.find(var);
291 291 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
292 292 qCCritical(LOG_VariableController())
293 293 << tr("Impossible to find the data for an unknown variable.");
294 294 }
295 295
296 296 ids << itVar->second.toByteArray();
297 297 }
298 298
299 299 QDataStream stream{&encodedData, QIODevice::WriteOnly};
300 300 stream << ids;
301 301
302 302 return encodedData;
303 303 }
304 304
305 305 QList<std::shared_ptr<Variable> >
306 306 VariableController::variablesForMimeData(const QByteArray &mimeData) const
307 307 {
308 308 auto variables = QList<std::shared_ptr<Variable> >{};
309 309 QDataStream stream{mimeData};
310 310
311 311 QVariantList ids;
312 312 stream >> ids;
313 313
314 314 for (auto id : ids) {
315 315 auto uuid = QUuid{id.toByteArray()};
316 316 auto var = impl->findVariable(uuid);
317 317 variables << var;
318 318 }
319 319
320 320 return variables;
321 321 }
322 322
323 323 std::shared_ptr<Variable>
324 324 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
325 325 std::shared_ptr<IDataProvider> provider) noexcept
326 326 {
327 327 if (!impl->m_TimeController) {
328 328 qCCritical(LOG_VariableController())
329 329 << tr("Impossible to create variable: The time controller is null");
330 330 return nullptr;
331 331 }
332 332
333 333 auto range = impl->m_TimeController->dateTime();
334 334
335 335 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
336 336 auto varId = QUuid::createUuid();
337 337
338 338 // Create the handler
339 339 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
340 340 varRequestHandler->m_VarId = varId;
341 341
342 342 impl->m_VarIdToVarRequestHandler.insert(
343 343 std::make_pair(varId, std::move(varRequestHandler)));
344 344
345 345 // store the provider
346 346 impl->registerProvider(provider);
347 347
348 348 // Associate the provider
349 349 impl->m_VariableToProviderMap[newVariable] = provider;
350 350 impl->m_VariableToIdentifierMap[newVariable] = varId;
351 351
352 352 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
353 353
354 354 // auto varRequestId = QUuid::createUuid();
355 355 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
356 356 // impl->processRequest(newVariable, range, varRequestId);
357 357 // impl->updateVariableRequest(varRequestId);
358 358
359 359 return newVariable;
360 360 }
361
362 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
363 return nullptr;
361 364 }
362 365
363 366 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
364 367 {
365 368 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
366 369 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
367 370 << QThread::currentThread()->objectName();
368 371 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
369 372
370 373 // NOTE we only permit the time modification for one variable
371 374 // DEPRECATED
372 375 // auto variables = QVector<std::shared_ptr<Variable> >{};
373 376 // for (const auto &selectedRow : qAsConst(selectedRows)) {
374 377 // if (auto selectedVariable =
375 378 // impl->m_VariableModel->variable(selectedRow.row())) {
376 379 // variables << selectedVariable;
377 380
378 381 // // notify that rescale operation has to be done
379 382 // emit rangeChanged(selectedVariable, dateTime);
380 383 // }
381 384 // }
382 385 // if (!variables.isEmpty()) {
383 386 // this->onRequestDataLoading(variables, dateTime, synchro);
384 387 // }
385 388 if (selectedRows.size() == 1) {
386 389
387 390 if (auto selectedVariable
388 391 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
389 392
390 393 onUpdateDateTime(selectedVariable, dateTime);
391 394 }
392 395 }
393 396 else if (selectedRows.size() > 1) {
394 397 qCCritical(LOG_VariableController())
395 398 << tr("Impossible to set time for more than 1 variable in the same time");
396 399 }
397 400 else {
398 401 qCWarning(LOG_VariableController())
399 402 << tr("There is no variable selected to set the time one");
400 403 }
401 404 }
402 405
403 406 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
404 407 const SqpRange &dateTime)
405 408 {
406 409 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
407 410 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
408 411 qCCritical(LOG_VariableController())
409 412 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
410 413 return;
411 414 }
412 415
413 416 // notify that rescale operation has to be done
414 417 emit rangeChanged(variable, dateTime);
415 418
416 419 auto synchro
417 420 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
418 421
419 422 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
420 423 }
421 424
422 425 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
423 426 const SqpRange &cacheRangeRequested,
424 427 QVector<AcquisitionDataPacket> dataAcquired)
425 428 {
426 429 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
427 430 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
428 431 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
429 432 if (!varRequestId.isNull()) {
430 433 impl->updateVariables(varRequestId);
431 434 }
432 435 }
433 436
434 437 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
435 438 {
436 439 qCDebug(LOG_VariableController())
437 440 << "TORM: variableController::onVariableRetrieveDataInProgress"
438 441 << QThread::currentThread()->objectName() << progress;
439 442 if (auto var = impl->findVariable(identifier)) {
440 443 impl->m_VariableModel->setDataProgress(var, progress);
441 444 }
442 445 else {
443 446 qCCritical(LOG_VariableController())
444 447 << tr("Impossible to notify progression of a null variable");
445 448 }
446 449 }
447 450
448 451 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
449 452 {
450 453 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
451 454 << QThread::currentThread()->objectName() << variable->name();
452 455
453 456 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
454 457 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
455 458 qCCritical(LOG_VariableController())
456 459 << tr("Impossible to onAbortProgressRequested request for unknown variable");
457 460 return;
458 461 }
459 462
460 463 auto varId = itVar->second;
461 464
462 465 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
463 466 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
464 467 qCCritical(LOG_VariableController())
465 468 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
466 469 return;
467 470 }
468 471
469 472 auto varHandler = itVarHandler->second.get();
470 473
471 474 // case where a variable has a running request
472 475 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
473 476 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
474 477 }
475 478 }
476 479
477 480 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
478 481 {
479 482 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
480 483 << QThread::currentThread()->objectName() << vIdentifier;
481 484
482 485 if (auto var = impl->findVariable(vIdentifier)) {
483 486 this->onAbortProgressRequested(var);
484 487 }
485 488 else {
486 489 qCCritical(LOG_VariableController())
487 490 << tr("Impossible to abort Acquisition Requestof a null variable");
488 491 }
489 492 }
490 493
491 494 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
492 495 {
493 496 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
494 497 << QThread::currentThread()->objectName()
495 498 << synchronizationGroupId;
496 499 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
497 500 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
498 501 std::make_pair(synchronizationGroupId, vSynchroGroup));
499 502 }
500 503
501 504 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
502 505 {
503 506 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
504 507 }
505 508
506 509 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
507 510 QUuid synchronizationGroupId)
508 511
509 512 {
510 513 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
511 514 << synchronizationGroupId;
512 515 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
513 516 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
514 517 auto groupIdToVSGIt
515 518 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
516 519 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
517 520 impl->m_VariableIdGroupIdMap.insert(
518 521 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
519 522 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
520 523 }
521 524 else {
522 525 qCCritical(LOG_VariableController())
523 526 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
524 527 << variable->name();
525 528 }
526 529 }
527 530 else {
528 531 qCCritical(LOG_VariableController())
529 532 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
530 533 }
531 534 }
532 535
533 536 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
534 537 QUuid synchronizationGroupId)
535 538 {
536 539 // Gets variable id
537 540 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
538 541 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
539 542 qCCritical(LOG_VariableController())
540 543 << tr("Can't desynchronize variable %1: variable identifier not found")
541 544 .arg(variable->name());
542 545 return;
543 546 }
544 547
545 548 // Gets synchronization group
546 549 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
547 550 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
548 551 qCCritical(LOG_VariableController())
549 552 << tr("Can't desynchronize variable %1: unknown synchronization group")
550 553 .arg(variable->name());
551 554 return;
552 555 }
553 556
554 557 auto variableId = variableIt->second;
555 558
556 559 // Removes variable from synchronization group
557 560 auto synchronizationGroup = groupIt->second;
558 561 synchronizationGroup->removeVariableId(variableId);
559 562
560 563 // Removes link between variable and synchronization group
561 564 impl->m_VariableIdGroupIdMap.erase(variableId);
562 565 }
563 566
564 567 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
565 568 const SqpRange &range, bool synchronise)
566 569 {
567 570 // variables is assumed synchronized
568 571 // TODO: Asser variables synchronization
569 572 // we want to load data of the variable for the dateTime.
570 573 if (variables.isEmpty()) {
571 574 return;
572 575 }
573 576
574 577 auto varRequestId = QUuid::createUuid();
575 578 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
576 579 << QThread::currentThread()->objectName() << varRequestId
577 580 << range << synchronise;
578 581
579 582 if (!synchronise) {
580 583 auto varIds = std::list<QUuid>{};
581 584 for (const auto &var : variables) {
582 585 auto vId = impl->m_VariableToIdentifierMap.at(var);
583 586 varIds.push_back(vId);
584 587 }
585 588 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
586 589 for (const auto &var : variables) {
587 590 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
588 591 << varIds.size();
589 592 impl->processRequest(var, range, varRequestId);
590 593 }
591 594 }
592 595 else {
593 596 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
594 597 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
595 598 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
596 599 auto groupId = varIdToGroupIdIt->second;
597 600
598 601 auto vSynchronizationGroup
599 602 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
600 603 auto vSyncIds = vSynchronizationGroup->getIds();
601 604
602 605 auto varIds = std::list<QUuid>{};
603 606 for (auto vId : vSyncIds) {
604 607 varIds.push_back(vId);
605 608 }
606 609 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
607 610
608 611 for (auto vId : vSyncIds) {
609 612 auto var = impl->findVariable(vId);
610 613
611 614 // Don't process already processed var
612 615 if (var != nullptr) {
613 616 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
614 617 << varRequestId;
615 618 auto vSyncRangeRequested
616 619 = variables.contains(var)
617 620 ? range
618 621 : computeSynchroRangeRequested(var->range(), range,
619 622 variables.first()->range());
620 623 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
621 624 impl->processRequest(var, vSyncRangeRequested, varRequestId);
622 625 }
623 626 else {
624 627 qCCritical(LOG_VariableController())
625 628
626 629 << tr("Impossible to synchronize a null variable");
627 630 }
628 631 }
629 632 }
630 633 }
631 634
632 635 impl->updateVariables(varRequestId);
633 636 }
634 637
635 638
636 639 void VariableController::initialize()
637 640 {
638 641 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
639 642 impl->m_WorkingMutex.lock();
640 643 qCDebug(LOG_VariableController()) << tr("VariableController init END");
641 644 }
642 645
643 646 void VariableController::finalize()
644 647 {
645 648 impl->m_WorkingMutex.unlock();
646 649 }
647 650
648 651 void VariableController::waitForFinish()
649 652 {
650 653 QMutexLocker locker{&impl->m_WorkingMutex};
651 654 }
652 655
653 656 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
654 657 {
655 658 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
656 659 auto zoomType = AcquisitionZoomType::Unknown;
657 660 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
658 661 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
659 662 zoomType = AcquisitionZoomType::ZoomOut;
660 663 }
661 664 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
662 665 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
663 666 zoomType = AcquisitionZoomType::PanRight;
664 667 }
665 668 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
666 669 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
667 670 zoomType = AcquisitionZoomType::PanLeft;
668 671 }
669 672 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
670 673 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
671 674 zoomType = AcquisitionZoomType::ZoomIn;
672 675 }
673 676 else {
674 677 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
675 678 }
676 679 return zoomType;
677 680 }
678 681
679 682 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
680 683 const SqpRange &rangeRequested,
681 684 QUuid varRequestId)
682 685 {
683 686 auto itVar = m_VariableToIdentifierMap.find(var);
684 687 if (itVar == m_VariableToIdentifierMap.cend()) {
685 688 qCCritical(LOG_VariableController())
686 689 << tr("Impossible to process request for unknown variable");
687 690 return;
688 691 }
689 692
690 693 auto varId = itVar->second;
691 694
692 695 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
693 696 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
694 697 qCCritical(LOG_VariableController())
695 698 << tr("Impossible to process request for variable with unknown handler");
696 699 return;
697 700 }
698 701
699 702 auto oldRange = var->range();
700 703
701 704 auto varHandler = itVarHandler->second.get();
702 705
703 706 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
704 707 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
705 708 }
706 709
707 710 auto varRequest = VariableRequest{};
708 711 varRequest.m_VariableGroupId = varRequestId;
709 712 auto varStrategyRangesRequested
710 713 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
711 714 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
712 715 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
713 716
714 717 switch (varHandler->m_State) {
715 718 case VariableRequestHandlerState::OFF: {
716 719 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
717 720 << varRequest.m_RangeRequested
718 721 << varRequest.m_CacheRangeRequested;
719 722 varHandler->m_RunningVarRequest = varRequest;
720 723 varHandler->m_State = VariableRequestHandlerState::RUNNING;
721 724 executeVarRequest(var, varRequest);
722 725 break;
723 726 }
724 727 case VariableRequestHandlerState::RUNNING: {
725 728 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
726 729 << varRequest.m_RangeRequested
727 730 << varRequest.m_CacheRangeRequested;
728 731 varHandler->m_State = VariableRequestHandlerState::PENDING;
729 732 varHandler->m_PendingVarRequest = varRequest;
730 733 break;
731 734 }
732 735 case VariableRequestHandlerState::PENDING: {
733 736 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
734 737 << varRequest.m_RangeRequested
735 738 << varRequest.m_CacheRangeRequested;
736 739 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
737 740 cancelVariableRequest(variableGroupIdToCancel);
738 741 // Cancel variable can make state downgrade
739 742 varHandler->m_State = VariableRequestHandlerState::PENDING;
740 743 varHandler->m_PendingVarRequest = varRequest;
741 744
742 745 break;
743 746 }
744 747 default:
745 748 qCCritical(LOG_VariableController())
746 749 << QObject::tr("Unknown VariableRequestHandlerState");
747 750 }
748 751 }
749 752
750 753 std::shared_ptr<Variable>
751 754 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
752 755 {
753 756 std::shared_ptr<Variable> var;
754 757 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
755 758
756 759 auto end = m_VariableToIdentifierMap.cend();
757 760 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
758 761 if (it != end) {
759 762 var = it->first;
760 763 }
761 764 else {
762 765 qCCritical(LOG_VariableController())
763 766 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
764 767 }
765 768
766 769 return var;
767 770 }
768 771
769 772 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
770 773 const QVector<AcquisitionDataPacket> acqDataPacketVector)
771 774 {
772 775 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
773 776 << acqDataPacketVector.size();
774 777 std::shared_ptr<IDataSeries> dataSeries;
775 778 if (!acqDataPacketVector.isEmpty()) {
776 779 dataSeries = acqDataPacketVector[0].m_DateSeries;
777 780 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
778 781 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
779 782 }
780 783 }
781 784 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
782 785 << acqDataPacketVector.size();
783 786 return dataSeries;
784 787 }
785 788
786 789 void VariableController::VariableControllerPrivate::registerProvider(
787 790 std::shared_ptr<IDataProvider> provider)
788 791 {
789 792 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
790 793 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
791 794 << provider->objectName();
792 795 m_ProviderSet.insert(provider);
793 796 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
794 797 &VariableAcquisitionWorker::onVariableDataAcquired);
795 798 connect(provider.get(), &IDataProvider::dataProvidedProgress,
796 799 m_VariableAcquisitionWorker.get(),
797 800 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
798 801 connect(provider.get(), &IDataProvider::dataProvidedFailed,
799 802 m_VariableAcquisitionWorker.get(),
800 803 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
801 804 }
802 805 else {
803 806 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
804 807 }
805 808 }
806 809
807 810 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
808 811 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
809 812 {
810 813 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
811 814 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
812 815 return QUuid();
813 816 }
814 817
815 818 auto varHandler = itVarHandler->second.get();
816 819 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
817 820 qCCritical(LOG_VariableController())
818 821 << tr("acceptVariableRequest impossible on a variable with OFF state");
819 822 }
820 823
821 824 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
822 825 varHandler->m_CanUpdate = true;
823 826
824 827 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
825 828 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
826 829 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
827 830 << m_VarGroupIdToVarIds.size();
828 831
829 832 return varHandler->m_RunningVarRequest.m_VariableGroupId;
830 833 }
831 834
832 835 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
833 836 {
834 837 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
835 838 << QThread::currentThread()->objectName() << varRequestId;
836 839
837 840 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
838 841 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
839 842 qCWarning(LOG_VariableController())
840 843 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
841 844 return;
842 845 }
843 846
844 847 auto &varIds = varGroupIdToVarIdsIt->second;
845 848 auto varIdsEnd = varIds.end();
846 849 bool processVariableUpdate = true;
847 850 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
848 851 << varRequestId << varIds.size();
849 852 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
850 853 ++varIdsIt) {
851 854 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
852 855 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
853 856 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
854 857 }
855 858 }
856 859
857 860 if (processVariableUpdate) {
858 861 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
859 862 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
860 863 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
861 864 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
862 865 if (auto var = findVariable(*varIdsIt)) {
863 866 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
864 867 var->setRange(varRequest.m_RangeRequested);
865 868 var->setCacheRange(varRequest.m_CacheRangeRequested);
866 869 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
867 870 << varRequest.m_RangeRequested
868 871 << varRequest.m_CacheRangeRequested;
869 872 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
870 873 << var->nbPoints()
871 874 << varRequest.m_DataSeries->nbPoints();
872 875 var->mergeDataSeries(varRequest.m_DataSeries);
873 876 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
874 877 << var->nbPoints();
875 878
876 879 emit var->updated();
877 880 qCDebug(LOG_VariableController()) << tr("Update OK");
878 881 }
879 882 else {
880 883 qCCritical(LOG_VariableController())
881 884 << tr("Impossible to update data to a null variable");
882 885 }
883 886 }
884 887 }
885 888 updateVariableRequest(varRequestId);
886 889
887 890 // cleaning varRequestId
888 891 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
889 892 m_VarGroupIdToVarIds.erase(varRequestId);
890 893 }
891 894 }
892 895
893 896
894 897 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
895 898 {
896 899 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
897 900 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
898 901 qCCritical(LOG_VariableController()) << QObject::tr(
899 902 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
900 903
901 904 return;
902 905 }
903 906
904 907 auto &varIds = varGroupIdToVarIdsIt->second;
905 908 auto varIdsEnd = varIds.end();
906 909 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
907 910 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
908 911 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
909 912
910 913 auto varHandler = itVarHandler->second.get();
911 914 varHandler->m_CanUpdate = false;
912 915
913 916
914 917 switch (varHandler->m_State) {
915 918 case VariableRequestHandlerState::OFF: {
916 919 qCCritical(LOG_VariableController())
917 920 << QObject::tr("Impossible to update a variable with handler in OFF state");
918 921 } break;
919 922 case VariableRequestHandlerState::RUNNING: {
920 923 varHandler->m_State = VariableRequestHandlerState::OFF;
921 924 varHandler->m_RunningVarRequest = VariableRequest{};
922 925 break;
923 926 }
924 927 case VariableRequestHandlerState::PENDING: {
925 928 varHandler->m_State = VariableRequestHandlerState::RUNNING;
926 929 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
927 930 varHandler->m_PendingVarRequest = VariableRequest{};
928 931 auto var = findVariable(itVarHandler->first);
929 932 executeVarRequest(var, varHandler->m_RunningVarRequest);
930 933 break;
931 934 }
932 935 default:
933 936 qCCritical(LOG_VariableController())
934 937 << QObject::tr("Unknown VariableRequestHandlerState");
935 938 }
936 939 }
937 940 }
938 941 }
939 942
940 943
941 944 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
942 945 {
943 946 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
944 947
945 948 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
946 949 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
947 950 qCCritical(LOG_VariableController())
948 951 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
949 952 return;
950 953 }
951 954
952 955 auto &varIds = varGroupIdToVarIdsIt->second;
953 956 auto varIdsEnd = varIds.end();
954 957 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
955 958 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
956 959 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
957 960
958 961 auto varHandler = itVarHandler->second.get();
959 962 varHandler->m_VarId = QUuid{};
960 963 switch (varHandler->m_State) {
961 964 case VariableRequestHandlerState::OFF: {
962 965 qCWarning(LOG_VariableController())
963 966 << QObject::tr("Impossible to cancel a variable with no running request");
964 967 break;
965 968 }
966 969 case VariableRequestHandlerState::RUNNING: {
967 970
968 971 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
969 972 auto var = findVariable(itVarHandler->first);
970 973 auto varProvider = m_VariableToProviderMap.at(var);
971 974 if (varProvider != nullptr) {
972 975 m_VariableAcquisitionWorker->abortProgressRequested(
973 976 itVarHandler->first);
974 977 }
975 978 m_VariableModel->setDataProgress(var, 0.0);
976 979 varHandler->m_CanUpdate = false;
977 980 varHandler->m_State = VariableRequestHandlerState::OFF;
978 981 varHandler->m_RunningVarRequest = VariableRequest{};
979 982 }
980 983 else {
981 984 // TODO: log Impossible to cancel the running variable request beacause its
982 985 // varRequestId isn't not the canceled one
983 986 }
984 987 break;
985 988 }
986 989 case VariableRequestHandlerState::PENDING: {
987 990 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
988 991 auto var = findVariable(itVarHandler->first);
989 992 auto varProvider = m_VariableToProviderMap.at(var);
990 993 if (varProvider != nullptr) {
991 994 m_VariableAcquisitionWorker->abortProgressRequested(
992 995 itVarHandler->first);
993 996 }
994 997 m_VariableModel->setDataProgress(var, 0.0);
995 998 varHandler->m_CanUpdate = false;
996 999 varHandler->m_State = VariableRequestHandlerState::RUNNING;
997 1000 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
998 1001 varHandler->m_PendingVarRequest = VariableRequest{};
999 1002 executeVarRequest(var, varHandler->m_RunningVarRequest);
1000 1003 }
1001 1004 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1002 1005 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1003 1006 varHandler->m_PendingVarRequest = VariableRequest{};
1004 1007 }
1005 1008 else {
1006 1009 // TODO: log Impossible to cancel the variable request beacause its
1007 1010 // varRequestId isn't not the canceled one
1008 1011 }
1009 1012 break;
1010 1013 }
1011 1014 default:
1012 1015 qCCritical(LOG_VariableController())
1013 1016 << QObject::tr("Unknown VariableRequestHandlerState");
1014 1017 }
1015 1018 }
1016 1019 }
1017 1020 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1018 1021 m_VarGroupIdToVarIds.erase(varRequestId);
1019 1022 }
1020 1023
1021 1024 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1022 1025 VariableRequest &varRequest)
1023 1026 {
1024 1027 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1025 1028
1026 1029 auto varId = m_VariableToIdentifierMap.at(var);
1027 1030
1028 1031 auto varCacheRange = var->cacheRange();
1029 1032 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1030 1033 auto notInCacheRangeList
1031 1034 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1032 1035 auto inCacheRangeList
1033 1036 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1034 1037
1035 1038 if (!notInCacheRangeList.empty()) {
1036 1039
1037 1040 auto varProvider = m_VariableToProviderMap.at(var);
1038 1041 if (varProvider != nullptr) {
1039 1042 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1040 1043 << varRequest.m_CacheRangeRequested;
1041 1044 m_VariableAcquisitionWorker->pushVariableRequest(
1042 1045 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1043 1046 varRequest.m_CacheRangeRequested,
1044 1047 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1045 1048 varProvider);
1046 1049 }
1047 1050 else {
1048 1051 qCCritical(LOG_VariableController())
1049 1052 << "Impossible to provide data with a null provider";
1050 1053 }
1051 1054
1052 1055 if (!inCacheRangeList.empty()) {
1053 1056 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1054 1057 }
1055 1058 }
1056 1059 else {
1057 1060 acceptVariableRequest(varId,
1058 1061 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1059 1062 }
1060 1063 }
@@ -1,394 +1,396
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableController.h>
3 3 #include <Variable/VariableModel.h>
4 4
5 5 #include <Common/DateUtils.h>
6 6 #include <Common/MimeTypesDef.h>
7 7 #include <Common/StringUtils.h>
8 8
9 9 #include <Data/IDataSeries.h>
10 10
11 11 #include <DataSource/DataSourceController.h>
12 12 #include <Time/TimeController.h>
13 13
14 14 #include <QMimeData>
15 15 #include <QSize>
16 16 #include <QTimer>
17 17 #include <unordered_map>
18 18
19 19 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
20 20
21 21 namespace {
22 22
23 23 // Column indexes
24 24 const auto NAME_COLUMN = 0;
25 25 const auto TSTART_COLUMN = 1;
26 26 const auto TEND_COLUMN = 2;
27 27 const auto NBPOINTS_COLUMN = 3;
28 28 const auto UNIT_COLUMN = 4;
29 29 const auto MISSION_COLUMN = 5;
30 30 const auto PLUGIN_COLUMN = 6;
31 31 const auto NB_COLUMNS = 7;
32 32
33 33 // Column properties
34 34 const auto DEFAULT_HEIGHT = 25;
35 35 const auto DEFAULT_WIDTH = 100;
36 36
37 37 struct ColumnProperties {
38 38 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
39 39 int height = DEFAULT_HEIGHT)
40 40 : m_Name{name}, m_Width{width}, m_Height{height}
41 41 {
42 42 }
43 43
44 44 QString m_Name;
45 45 int m_Width;
46 46 int m_Height;
47 47 };
48 48
49 49 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
50 50 {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
51 51 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {NBPOINTS_COLUMN, {QObject::tr("Nb points")}},
52 52 {UNIT_COLUMN, {QObject::tr("Unit")}}, {MISSION_COLUMN, {QObject::tr("Mission")}},
53 53 {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
54 54
55 55 /// Format for datetimes
56 56 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
57 57
58 58 QString uniqueName(const QString &defaultName,
59 59 const std::vector<std::shared_ptr<Variable> > &variables)
60 60 {
61 61 auto forbiddenNames = std::vector<QString>(variables.size());
62 62 std::transform(variables.cbegin(), variables.cend(), forbiddenNames.begin(),
63 63 [](const auto &variable) { return variable->name(); });
64 64 auto uniqueName = StringUtils::uniqueName(defaultName, forbiddenNames);
65 65 Q_ASSERT(!uniqueName.isEmpty());
66 66
67 67 return uniqueName;
68 68 }
69 69
70 70 } // namespace
71 71
72 72 struct VariableModel::VariableModelPrivate {
73 73 /// Variables created in SciQlop
74 74 std::vector<std::shared_ptr<Variable> > m_Variables;
75 75 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
76 76 VariableController *m_VariableController;
77 77
78 78 /// Return the row index of the variable. -1 if it's not found
79 79 int indexOfVariable(Variable *variable) const noexcept;
80 80 };
81 81
82 82 VariableModel::VariableModel(VariableController *parent)
83 83 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
84 84 {
85 85 impl->m_VariableController = parent;
86 86 }
87 87
88 88 void VariableModel::addVariable(std::shared_ptr<Variable> variable) noexcept
89 89 {
90 90 auto insertIndex = rowCount();
91 91 beginInsertRows({}, insertIndex, insertIndex);
92 92
93 93 // Generates unique name for the variable
94 94 variable->setName(uniqueName(variable->name(), impl->m_Variables));
95 95
96 96 impl->m_Variables.push_back(variable);
97 97 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
98 98
99 99 endInsertRows();
100 100 }
101 101
102 102 bool VariableModel::containsVariable(std::shared_ptr<Variable> variable) const noexcept
103 103 {
104 104 auto end = impl->m_Variables.cend();
105 105 return std::find(impl->m_Variables.cbegin(), end, variable) != end;
106 106 }
107 107
108 108 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
109 109 const QVariantHash &metadata) noexcept
110 110 {
111 111 auto variable = std::make_shared<Variable>(name, metadata);
112 112 addVariable(variable);
113 113
114 114 return variable;
115 115 }
116 116
117 117 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
118 118 {
119 119 if (!variable) {
120 120 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
121 121 return;
122 122 }
123 123
124 124 // Finds variable in the model
125 125 auto begin = impl->m_Variables.cbegin();
126 126 auto end = impl->m_Variables.cend();
127 127 auto it = std::find(begin, end, variable);
128 128 if (it != end) {
129 129 auto removeIndex = std::distance(begin, it);
130 130
131 131 // Deletes variable
132 132 beginRemoveRows({}, removeIndex, removeIndex);
133 133 impl->m_Variables.erase(it);
134 134 endRemoveRows();
135 135 }
136 136 else {
137 137 qCritical(LOG_VariableModel())
138 138 << tr("Can't delete variable %1 from the model: the variable is not in the model")
139 139 .arg(variable->name());
140 140 }
141 141
142 142 // Removes variable from progress map
143 143 impl->m_VariableToProgress.erase(variable);
144 144 }
145 145
146 146
147 147 std::shared_ptr<Variable> VariableModel::variable(int index) const
148 148 {
149 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
149 return (index >= 0u && static_cast<size_t>(index) < impl->m_Variables.size())
150 ? impl->m_Variables[index]
151 : nullptr;
150 152 }
151 153
152 154 std::vector<std::shared_ptr<Variable> > VariableModel::variables() const
153 155 {
154 156 return impl->m_Variables;
155 157 }
156 158
157 159 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
158 160 {
159 161 if (progress > 0.0) {
160 162 impl->m_VariableToProgress[variable] = progress;
161 163 }
162 164 else {
163 165 impl->m_VariableToProgress.erase(variable);
164 166 }
165 167 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
166 168
167 169 emit dataChanged(modelIndex, modelIndex);
168 170 }
169 171
170 172 int VariableModel::columnCount(const QModelIndex &parent) const
171 173 {
172 174 Q_UNUSED(parent);
173 175
174 176 return NB_COLUMNS;
175 177 }
176 178
177 179 int VariableModel::rowCount(const QModelIndex &parent) const
178 180 {
179 181 Q_UNUSED(parent);
180 182
181 183 return impl->m_Variables.size();
182 184 }
183 185
184 186 QVariant VariableModel::data(const QModelIndex &index, int role) const
185 187 {
186 188 if (!index.isValid()) {
187 189 return QVariant{};
188 190 }
189 191
190 192 if (index.row() < 0 || index.row() >= rowCount()) {
191 193 return QVariant{};
192 194 }
193 195
194 196 if (role == Qt::DisplayRole) {
195 197 if (auto variable = impl->m_Variables.at(index.row()).get()) {
196 198 switch (index.column()) {
197 199 case NAME_COLUMN:
198 200 return variable->name();
199 201 case TSTART_COLUMN: {
200 202 auto range = variable->realRange();
201 203 return range != INVALID_RANGE
202 204 ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT)
203 205 : QVariant{};
204 206 }
205 207 case TEND_COLUMN: {
206 208 auto range = variable->realRange();
207 209 return range != INVALID_RANGE
208 210 ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT)
209 211 : QVariant{};
210 212 }
211 213 case NBPOINTS_COLUMN:
212 214 return variable->nbPoints();
213 215 case UNIT_COLUMN:
214 216 return variable->metadata().value(QStringLiteral("units"));
215 217 case MISSION_COLUMN:
216 218 return variable->metadata().value(QStringLiteral("mission"));
217 219 case PLUGIN_COLUMN:
218 220 return variable->metadata().value(QStringLiteral("plugin"));
219 221 default:
220 222 // No action
221 223 break;
222 224 }
223 225
224 226 qWarning(LOG_VariableModel())
225 227 << tr("Can't get data (unknown column %1)").arg(index.column());
226 228 }
227 229 else {
228 230 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
229 231 }
230 232 }
231 233 else if (role == VariableRoles::ProgressRole) {
232 234 if (auto variable = impl->m_Variables.at(index.row())) {
233 235
234 236 auto it = impl->m_VariableToProgress.find(variable);
235 237 if (it != impl->m_VariableToProgress.cend()) {
236 238 return it->second;
237 239 }
238 240 }
239 241 }
240 242
241 243 return QVariant{};
242 244 }
243 245
244 246 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
245 247 {
246 248 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
247 249 return QVariant{};
248 250 }
249 251
250 252 if (orientation == Qt::Horizontal) {
251 253 auto propertiesIt = COLUMN_PROPERTIES.find(section);
252 254 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
253 255 // Role is either DisplayRole or SizeHintRole
254 256 return (role == Qt::DisplayRole)
255 257 ? QVariant{propertiesIt->m_Name}
256 258 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
257 259 }
258 260 else {
259 261 qWarning(LOG_VariableModel())
260 262 << tr("Can't get header data (unknown column %1)").arg(section);
261 263 }
262 264 }
263 265
264 266 return QVariant{};
265 267 }
266 268
267 269 Qt::ItemFlags VariableModel::flags(const QModelIndex &index) const
268 270 {
269 271 return QAbstractTableModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
270 272 }
271 273
272 274 Qt::DropActions VariableModel::supportedDropActions() const
273 275 {
274 276 return Qt::CopyAction | Qt::MoveAction;
275 277 }
276 278
277 279 Qt::DropActions VariableModel::supportedDragActions() const
278 280 {
279 281 return Qt::CopyAction | Qt::MoveAction;
280 282 }
281 283
282 284 QStringList VariableModel::mimeTypes() const
283 285 {
284 286 return {MIME_TYPE_VARIABLE_LIST, MIME_TYPE_TIME_RANGE};
285 287 }
286 288
287 289 QMimeData *VariableModel::mimeData(const QModelIndexList &indexes) const
288 290 {
289 291 auto mimeData = new QMimeData;
290 292
291 293 QList<std::shared_ptr<Variable> > variableList;
292 294
293 295
294 296 SqpRange firstTimeRange;
295 297 for (const auto &index : indexes) {
296 298 if (index.column() == 0) { // only the first column
297 299 auto variable = impl->m_Variables.at(index.row());
298 300 if (variable.get() && index.isValid()) {
299 301
300 302 if (variableList.isEmpty()) {
301 303 // Gets the range of the first variable
302 304 firstTimeRange = std::move(variable->range());
303 305 }
304 306
305 307 variableList << variable;
306 308 }
307 309 }
308 310 }
309 311
310 312 auto variablesEncodedData = impl->m_VariableController->mimeDataForVariables(variableList);
311 313 mimeData->setData(MIME_TYPE_VARIABLE_LIST, variablesEncodedData);
312 314
313 315 if (variableList.count() == 1) {
314 316 // No time range MIME data if multiple variables are dragged
315 317 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
316 318 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
317 319 }
318 320
319 321 return mimeData;
320 322 }
321 323
322 324 bool VariableModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
323 325 int column, const QModelIndex &parent) const
324 326 {
325 327 // drop of a product
326 328 return data->hasFormat(MIME_TYPE_PRODUCT_LIST)
327 329 || (data->hasFormat(MIME_TYPE_TIME_RANGE) && parent.isValid()
328 330 && !data->hasFormat(MIME_TYPE_VARIABLE_LIST));
329 331 }
330 332
331 333 bool VariableModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
332 334 const QModelIndex &parent)
333 335 {
334 336 auto dropDone = false;
335 337
336 338 if (data->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
337 339
338 340 auto productList
339 341 = DataSourceController::productsDataForMimeData(data->data(MIME_TYPE_PRODUCT_LIST));
340 342
341 343 for (auto metaData : productList) {
342 344 emit requestVariable(metaData.toHash());
343 345 }
344 346
345 347 dropDone = true;
346 348 }
347 349 else if (data->hasFormat(MIME_TYPE_TIME_RANGE) && parent.isValid()) {
348 350 auto variable = this->variable(parent.row());
349 351 auto range = TimeController::timeRangeForMimeData(data->data(MIME_TYPE_TIME_RANGE));
350 352
351 353 emit requestVariableRangeUpdate(variable, range);
352 354
353 355 dropDone = true;
354 356 }
355 357
356 358 return dropDone;
357 359 }
358 360
359 361 void VariableModel::abortProgress(const QModelIndex &index)
360 362 {
361 363 if (auto variable = impl->m_Variables.at(index.row())) {
362 364 emit abortProgessRequested(variable);
363 365 }
364 366 }
365 367
366 368 void VariableModel::onVariableUpdated() noexcept
367 369 {
368 370 // Finds variable that has been updated in the model
369 371 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
370 372 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
371 373
372 374 if (updatedVariableIndex > -1) {
373 375 emit dataChanged(createIndex(updatedVariableIndex, 0),
374 376 createIndex(updatedVariableIndex, columnCount() - 1));
375 377 }
376 378 }
377 379 }
378 380
379 381 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
380 382 {
381 383 auto begin = std::cbegin(m_Variables);
382 384 auto end = std::cend(m_Variables);
383 385 auto it
384 386 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
385 387
386 388 if (it != end) {
387 389 // Gets the index of the variable in the model: we assume here that views have the same
388 390 // order as the model
389 391 return std::distance(begin, it);
390 392 }
391 393 else {
392 394 return -1;
393 395 }
394 396 }
@@ -1,24 +1,24
1 1 #include "DataSeriesUtils.h"
2 2
3 3 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
4 4 const DataContainer &valuesData)
5 5 {
6 6 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
7 7 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
8 8 QVERIFY(std::equal(
9 9 first, last, valuesData.cbegin(), valuesData.cend(),
10 10 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
11 11 }
12 12
13 13 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData, const std::vector<DataContainer> &valuesData)
14 14 {
15 15 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
16 16 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
17 for (auto i = 0; i < valuesData.size(); ++i) {
17 for (auto i = 0u; i < valuesData.size(); ++i) {
18 18 auto componentData = valuesData.at(i);
19 19
20 20 QVERIFY(std::equal(
21 21 first, last, componentData.cbegin(), componentData.cend(),
22 22 [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; }));
23 23 }
24 24 }
@@ -1,240 +1,240
1 1 #include "Data/ArrayData.h"
2 2 #include <QObject>
3 3 #include <QtTest>
4 4
5 5 using DataContainer = std::vector<double>;
6 6 using Container = std::vector<DataContainer>;
7 7 using InputData = QPair<DataContainer, int>;
8 8
9 9 namespace {
10 10
11 11 InputData flatten(const Container &container)
12 12 {
13 13 if (container.empty()) {
14 14 return {};
15 15 }
16 16
17 17 // We assume here that each component of the container have the same size
18 18 auto containerSize = container.size();
19 19 auto componentSize = container.front().size();
20 20
21 21 auto result = DataContainer{};
22 22 result.reserve(componentSize * containerSize);
23 23
24 for (auto i = 0; i < componentSize; ++i) {
25 for (auto j = 0; j < containerSize; ++j) {
24 for (auto i = 0u; i < componentSize; ++i) {
25 for (auto j = 0u; j < containerSize; ++j) {
26 26 result.push_back(container.at(j).at(i));
27 27 }
28 28 }
29 29
30 30 return {result, static_cast<int>(containerSize)};
31 31 }
32 32
33 33 void verifyArrayData(const ArrayData<2> &arrayData, const Container &expectedData)
34 34 {
35 35 auto verifyComponent = [&arrayData](const auto &componentData, const auto &equalFun) {
36 36 QVERIFY(std::equal(arrayData.cbegin(), arrayData.cend(), componentData.cbegin(),
37 37 componentData.cend(),
38 38 [&equalFun](const auto &dataSeriesIt, const auto &expectedValue) {
39 39 return equalFun(dataSeriesIt, expectedValue);
40 40 }));
41 41 };
42 42
43 for (auto i = 0; i < expectedData.size(); ++i) {
43 for (auto i = 0u; i < expectedData.size(); ++i) {
44 44 verifyComponent(expectedData.at(i), [i](const auto &seriesIt, const auto &value) {
45 45 return seriesIt.at(i) == value;
46 46 });
47 47 }
48 48 }
49 49
50 50 } // namespace
51 51
52 52 class TestTwoDimArrayData : public QObject {
53 53 Q_OBJECT
54 54 private slots:
55 55 /// Tests @sa ArrayData ctor
56 56 void testCtor_data();
57 57 void testCtor();
58 58
59 59 /// Tests @sa ArrayData::add()
60 60 void testAdd_data();
61 61 void testAdd();
62 62
63 63 /// Tests @sa ArrayData::clear()
64 64 void testClear_data();
65 65 void testClear();
66 66
67 67 /// Tests @sa ArrayData::size()
68 68 void testSize_data();
69 69 void testSize();
70 70
71 71 /// Tests @sa ArrayData::sort()
72 72 void testSort_data();
73 73 void testSort();
74 74 };
75 75
76 76 void TestTwoDimArrayData::testCtor_data()
77 77 {
78 78 // Test structure
79 79 QTest::addColumn<InputData>("inputData"); // array data's input
80 80 QTest::addColumn<bool>("success"); // array data has been successfully constructed
81 81 QTest::addColumn<Container>("expectedData"); // expected array data (when success)
82 82
83 83 // Test cases
84 84 QTest::newRow("validInput") << flatten(Container{{1., 2., 3., 4., 5.},
85 85 {6., 7., 8., 9., 10.},
86 86 {11., 12., 13., 14., 15.}})
87 87 << true << Container{{1., 2., 3., 4., 5.},
88 88 {6., 7., 8., 9., 10.},
89 89 {11., 12., 13., 14., 15.}};
90 90 QTest::newRow("invalidInput (invalid data size") << InputData{{1., 2., 3., 4., 5., 6., 7.}, 3}
91 91 << false << Container{{}, {}, {}};
92 92 QTest::newRow("invalidInput (less than two components")
93 93 << flatten(Container{{1., 2., 3., 4., 5.}}) << false << Container{{}, {}, {}};
94 94 }
95 95
96 96 void TestTwoDimArrayData::testCtor()
97 97 {
98 98 QFETCH(InputData, inputData);
99 99 QFETCH(bool, success);
100 100
101 101 if (success) {
102 102 QFETCH(Container, expectedData);
103 103
104 104 ArrayData<2> arrayData{inputData.first, inputData.second};
105 105 verifyArrayData(arrayData, expectedData);
106 106 }
107 107 else {
108 108 QVERIFY_EXCEPTION_THROWN(ArrayData<2>(inputData.first, inputData.second),
109 109 std::invalid_argument);
110 110 }
111 111 }
112 112
113 113 void TestTwoDimArrayData::testAdd_data()
114 114 {
115 115 // Test structure
116 116 QTest::addColumn<InputData>("inputData"); // array's data input
117 117 QTest::addColumn<InputData>("otherData"); // array data's input to merge with
118 118 QTest::addColumn<bool>("prepend"); // prepend or append merge
119 119 QTest::addColumn<Container>("expectedData"); // expected data after merge
120 120
121 121 // Test cases
122 122 auto inputData = flatten(
123 123 Container{{1., 2., 3., 4., 5.}, {11., 12., 13., 14., 15.}, {21., 22., 23., 24., 25.}});
124 124
125 125 auto vectorContainer = flatten(Container{{6., 7., 8.}, {16., 17., 18.}, {26., 27., 28}});
126 126 auto tensorContainer = flatten(Container{{6., 7., 8.},
127 127 {16., 17., 18.},
128 128 {26., 27., 28},
129 129 {36., 37., 38.},
130 130 {46., 47., 48.},
131 131 {56., 57., 58}});
132 132
133 133 QTest::newRow("appendMerge") << inputData << vectorContainer << false
134 134 << Container{{1., 2., 3., 4., 5., 6., 7., 8.},
135 135 {11., 12., 13., 14., 15., 16., 17., 18.},
136 136 {21., 22., 23., 24., 25., 26., 27., 28}};
137 137 QTest::newRow("prependMerge") << inputData << vectorContainer << true
138 138 << Container{{6., 7., 8., 1., 2., 3., 4., 5.},
139 139 {16., 17., 18., 11., 12., 13., 14., 15.},
140 140 {26., 27., 28, 21., 22., 23., 24., 25.}};
141 141 QTest::newRow("invalidMerge") << inputData << tensorContainer << false
142 142 << Container{{1., 2., 3., 4., 5.},
143 143 {11., 12., 13., 14., 15.},
144 144 {21., 22., 23., 24., 25.}};
145 145 }
146 146
147 147 void TestTwoDimArrayData::testAdd()
148 148 {
149 149 QFETCH(InputData, inputData);
150 150 QFETCH(InputData, otherData);
151 151 QFETCH(bool, prepend);
152 152 QFETCH(Container, expectedData);
153 153
154 154 ArrayData<2> arrayData{inputData.first, inputData.second};
155 155 ArrayData<2> other{otherData.first, otherData.second};
156 156
157 157 arrayData.add(other, prepend);
158 158
159 159 verifyArrayData(arrayData, expectedData);
160 160 }
161 161
162 162 void TestTwoDimArrayData::testClear_data()
163 163 {
164 164 // Test structure
165 165 QTest::addColumn<InputData>("inputData"); // array data's input
166 166
167 167 // Test cases
168 168 QTest::newRow("data1") << flatten(
169 169 Container{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, {11., 12., 13., 14., 15.}});
170 170 }
171 171
172 172 void TestTwoDimArrayData::testClear()
173 173 {
174 174 QFETCH(InputData, inputData);
175 175
176 176 ArrayData<2> arrayData{inputData.first, inputData.second};
177 177 arrayData.clear();
178 178
179 179 auto emptyData = Container(inputData.second, DataContainer{});
180 180 verifyArrayData(arrayData, emptyData);
181 181 }
182 182
183 183 void TestTwoDimArrayData::testSize_data()
184 184 {
185 185 // Test structure
186 186 QTest::addColumn<InputData>("inputData"); // array data's input
187 187 QTest::addColumn<int>("expectedSize"); // expected array data size
188 188
189 189 // Test cases
190 190 QTest::newRow("data1") << flatten(Container{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}}) << 5;
191 191 QTest::newRow("data2") << flatten(Container{{1., 2., 3., 4., 5.},
192 192 {6., 7., 8., 9., 10.},
193 193 {11., 12., 13., 14., 15.}})
194 194 << 5;
195 195 }
196 196
197 197 void TestTwoDimArrayData::testSize()
198 198 {
199 199 QFETCH(InputData, inputData);
200 200 QFETCH(int, expectedSize);
201 201
202 202 ArrayData<2> arrayData{inputData.first, inputData.second};
203 203 QVERIFY(arrayData.size() == expectedSize);
204 204 }
205 205
206 206 void TestTwoDimArrayData::testSort_data()
207 207 {
208 208 // Test structure
209 209 QTest::addColumn<InputData>("inputData"); // array data's input
210 210 QTest::addColumn<std::vector<int> >("sortPermutation"); // permutation used to sort data
211 211 QTest::addColumn<Container>("expectedData"); // expected data after sorting
212 212
213 213 // Test cases
214 214 QTest::newRow("data1")
215 215 << flatten(
216 216 Container{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, {11., 12., 13., 14., 15.}})
217 217 << std::vector<int>{0, 2, 3, 1, 4}
218 218 << Container{{1., 3., 4., 2., 5.}, {6., 8., 9., 7., 10.}, {11., 13., 14., 12., 15.}};
219 219 QTest::newRow("data2")
220 220 << flatten(
221 221 Container{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, {11., 12., 13., 14., 15.}})
222 222 << std::vector<int>{2, 4, 3, 0, 1}
223 223 << Container{{3., 5., 4., 1., 2.}, {8., 10., 9., 6., 7.}, {13., 15., 14., 11., 12.}};
224 224 }
225 225
226 226 void TestTwoDimArrayData::testSort()
227 227 {
228 228 QFETCH(InputData, inputData);
229 229 QFETCH(std::vector<int>, sortPermutation);
230 230 QFETCH(Container, expectedData);
231 231
232 232 ArrayData<2> arrayData{inputData.first, inputData.second};
233 233 auto sortedArrayData = arrayData.sort(sortPermutation);
234 234 QVERIFY(sortedArrayData != nullptr);
235 235
236 236 verifyArrayData(*sortedArrayData, expectedData);
237 237 }
238 238
239 239 QTEST_MAIN(TestTwoDimArrayData)
240 240 #include "TestTwoDimArrayData.moc"
@@ -1,98 +1,95
1 1
2 2 gui_moc_headers = [
3 3 'include/DataSource/DataSourceWidget.h',
4 'include/DataSource/DataSourceTreeWidget.h',
5 4 'include/Settings/SqpSettingsDialog.h',
6 5 'include/Settings/SqpSettingsGeneralWidget.h',
7 6 'include/SidePane/SqpSidePane.h',
8 7 'include/SqpApplication.h',
9 'include/DragAndDrop/DragDropHelper.h',
10 8 'include/DragAndDrop/DragDropScroller.h',
11 9 'include/DragAndDrop/DragDropTabSwitcher.h',
12 10 'include/TimeWidget/TimeWidget.h',
13 11 'include/Variable/VariableInspectorWidget.h',
14 'include/Variable/VariableInspectorTableView.h',
15 12 'include/Variable/RenameVariableDialog.h',
16 13 'include/Visualization/qcustomplot.h',
17 14 'include/Visualization/VisualizationGraphWidget.h',
18 15 'include/Visualization/VisualizationTabWidget.h',
19 16 'include/Visualization/VisualizationWidget.h',
20 17 'include/Visualization/VisualizationZoneWidget.h',
21 18 'include/Visualization/VisualizationDragDropContainer.h',
22 19 'include/Visualization/VisualizationDragWidget.h'
23 20 ]
24 21
25 22 gui_ui_files = [
26 23 'ui/DataSource/DataSourceWidget.ui',
27 24 'ui/Settings/SqpSettingsDialog.ui',
28 25 'ui/Settings/SqpSettingsGeneralWidget.ui',
29 26 'ui/SidePane/SqpSidePane.ui',
30 27 'ui/TimeWidget/TimeWidget.ui',
31 28 'ui/Variable/VariableInspectorWidget.ui',
32 29 'ui/Variable/RenameVariableDialog.ui',
33 30 'ui/Variable/VariableMenuHeaderWidget.ui',
34 31 'ui/Visualization/VisualizationGraphWidget.ui',
35 32 'ui/Visualization/VisualizationTabWidget.ui',
36 33 'ui/Visualization/VisualizationWidget.ui',
37 34 'ui/Visualization/VisualizationZoneWidget.ui'
38 35 ]
39 36
40 37 gui_qresources = ['resources/sqpguiresources.qrc']
41 38
42 39 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
43 40 ui_files : gui_ui_files,
44 41 qresources : gui_qresources)
45 42
46 43 gui_sources = [
47 44 'src/SqpApplication.cpp',
48 45 'src/DragAndDrop/DragDropHelper.cpp',
49 46 'src/DragAndDrop/DragDropScroller.cpp',
50 47 'src/DragAndDrop/DragDropTabSwitcher.cpp',
51 48 'src/Common/ColorUtils.cpp',
52 49 'src/Common/VisualizationDef.cpp',
53 50 'src/DataSource/DataSourceTreeWidgetItem.cpp',
54 51 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
55 52 'src/DataSource/DataSourceWidget.cpp',
56 53 'src/DataSource/DataSourceTreeWidget.cpp',
57 54 'src/Settings/SqpSettingsDialog.cpp',
58 55 'src/Settings/SqpSettingsGeneralWidget.cpp',
59 56 'src/SidePane/SqpSidePane.cpp',
60 57 'src/TimeWidget/TimeWidget.cpp',
61 58 'src/Variable/VariableInspectorWidget.cpp',
62 59 'src/Variable/VariableInspectorTableView.cpp',
63 60 'src/Variable/VariableMenuHeaderWidget.cpp',
64 61 'src/Variable/RenameVariableDialog.cpp',
65 62 'src/Visualization/VisualizationGraphHelper.cpp',
66 63 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
67 64 'src/Visualization/VisualizationGraphWidget.cpp',
68 65 'src/Visualization/VisualizationTabWidget.cpp',
69 66 'src/Visualization/VisualizationWidget.cpp',
70 67 'src/Visualization/VisualizationZoneWidget.cpp',
71 68 'src/Visualization/qcustomplot.cpp',
72 69 'src/Visualization/QCustomPlotSynchronizer.cpp',
73 70 'src/Visualization/operations/FindVariableOperation.cpp',
74 71 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
75 72 'src/Visualization/operations/MenuBuilder.cpp',
76 73 'src/Visualization/operations/RemoveVariableOperation.cpp',
77 74 'src/Visualization/operations/RescaleAxeOperation.cpp',
78 75 'src/Visualization/VisualizationDragDropContainer.cpp',
79 76 'src/Visualization/VisualizationDragWidget.cpp',
80 77 'src/Visualization/AxisRenderingUtils.cpp',
81 78 'src/Visualization/PlottablesRenderingUtils.cpp',
82 79 'src/Visualization/MacScrollBarStyle.cpp'
83 80 ]
84 81
85 82 gui_inc = include_directories(['include'])
86 83
87 84 sciqlop_gui_lib = library('sciqlopgui',
88 85 gui_sources,
89 86 gui_moc_files,
90 87 include_directories : [gui_inc],
91 88 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
92 89 install : true
93 90 )
94 91
95 92 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
96 93 include_directories : gui_inc,
97 94 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
98 95
@@ -1,163 +1,163
1 1 #include "SqpApplication.h"
2 2
3 3 #include <Data/IDataProvider.h>
4 4 #include <DataSource/DataSourceController.h>
5 5 #include <DragAndDrop/DragDropHelper.h>
6 6 #include <Network/NetworkController.h>
7 7 #include <QThread>
8 8 #include <Time/TimeController.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11 #include <Variable/VariableModel.h>
12 12 #include <Visualization/VisualizationController.h>
13 13
14 14 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
15 15
16 16 class SqpApplication::SqpApplicationPrivate {
17 17 public:
18 18 SqpApplicationPrivate()
19 19 : m_DataSourceController{std::make_unique<DataSourceController>()},
20 m_NetworkController{std::make_unique<NetworkController>()},
21 m_TimeController{std::make_unique<TimeController>()},
22 20 m_VariableController{std::make_unique<VariableController>()},
21 m_TimeController{std::make_unique<TimeController>()},
22 m_NetworkController{std::make_unique<NetworkController>()},
23 23 m_VisualizationController{std::make_unique<VisualizationController>()},
24 24 m_DragDropHelper{std::make_unique<DragDropHelper>()}
25 25 {
26 26 // /////////////////////////////// //
27 27 // Connections between controllers //
28 28 // /////////////////////////////// //
29 29
30 30 // VariableController <-> DataSourceController
31 31 connect(m_DataSourceController.get(),
32 32 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
33 33 std::shared_ptr<IDataProvider>)),
34 34 m_VariableController.get(),
35 35 SLOT(createVariable(const QString &, const QVariantHash &,
36 36 std::shared_ptr<IDataProvider>)));
37 37
38 38 connect(m_VariableController->variableModel(), &VariableModel::requestVariable,
39 39 m_DataSourceController.get(), &DataSourceController::requestVariable);
40 40
41 41 // VariableController <-> VisualizationController
42 42 connect(m_VariableController.get(),
43 43 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
44 44 m_VisualizationController.get(),
45 45 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
46 46
47 47 connect(m_VariableController.get(),
48 48 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)),
49 49 m_VisualizationController.get(),
50 50 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
51 51
52 52
53 53 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
54 54 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
55 55 m_NetworkController->moveToThread(&m_NetworkControllerThread);
56 56 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
57 57 m_VariableController->moveToThread(&m_VariableControllerThread);
58 58 m_VariableControllerThread.setObjectName("VariableControllerThread");
59 59 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
60 60 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
61 61
62 62
63 63 // Additionnal init
64 64 m_VariableController->setTimeController(m_TimeController.get());
65 65 }
66 66
67 67 virtual ~SqpApplicationPrivate()
68 68 {
69 69 m_DataSourceControllerThread.quit();
70 70 m_DataSourceControllerThread.wait();
71 71
72 72 m_NetworkControllerThread.quit();
73 73 m_NetworkControllerThread.wait();
74 74
75 75 m_VariableControllerThread.quit();
76 76 m_VariableControllerThread.wait();
77 77
78 78 m_VisualizationControllerThread.quit();
79 79 m_VisualizationControllerThread.wait();
80 80 }
81 81
82 82 std::unique_ptr<DataSourceController> m_DataSourceController;
83 83 std::unique_ptr<VariableController> m_VariableController;
84 84 std::unique_ptr<TimeController> m_TimeController;
85 85 std::unique_ptr<NetworkController> m_NetworkController;
86 86 std::unique_ptr<VisualizationController> m_VisualizationController;
87 87 QThread m_DataSourceControllerThread;
88 88 QThread m_NetworkControllerThread;
89 89 QThread m_VariableControllerThread;
90 90 QThread m_VisualizationControllerThread;
91 91
92 92 std::unique_ptr<DragDropHelper> m_DragDropHelper;
93 93 };
94 94
95 95
96 96 SqpApplication::SqpApplication(int &argc, char **argv)
97 97 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
98 98 {
99 99 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
100 100
101 101 connect(&impl->m_DataSourceControllerThread, &QThread::started,
102 102 impl->m_DataSourceController.get(), &DataSourceController::initialize);
103 103 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
104 104 impl->m_DataSourceController.get(), &DataSourceController::finalize);
105 105
106 106 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
107 107 &NetworkController::initialize);
108 108 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
109 109 &NetworkController::finalize);
110 110
111 111 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
112 112 &VariableController::initialize);
113 113 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
114 114 &VariableController::finalize);
115 115
116 116 connect(&impl->m_VisualizationControllerThread, &QThread::started,
117 117 impl->m_VisualizationController.get(), &VisualizationController::initialize);
118 118 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
119 119 impl->m_VisualizationController.get(), &VisualizationController::finalize);
120 120
121 121 impl->m_DataSourceControllerThread.start();
122 122 impl->m_NetworkControllerThread.start();
123 123 impl->m_VariableControllerThread.start();
124 124 impl->m_VisualizationControllerThread.start();
125 125 }
126 126
127 127 SqpApplication::~SqpApplication()
128 128 {
129 129 }
130 130
131 131 void SqpApplication::initialize()
132 132 {
133 133 }
134 134
135 135 DataSourceController &SqpApplication::dataSourceController() noexcept
136 136 {
137 137 return *impl->m_DataSourceController;
138 138 }
139 139
140 140 NetworkController &SqpApplication::networkController() noexcept
141 141 {
142 142 return *impl->m_NetworkController;
143 143 }
144 144
145 145 TimeController &SqpApplication::timeController() noexcept
146 146 {
147 147 return *impl->m_TimeController;
148 148 }
149 149
150 150 VariableController &SqpApplication::variableController() noexcept
151 151 {
152 152 return *impl->m_VariableController;
153 153 }
154 154
155 155 VisualizationController &SqpApplication::visualizationController() noexcept
156 156 {
157 157 return *impl->m_VisualizationController;
158 158 }
159 159
160 160 DragDropHelper &SqpApplication::dragDropHelper() noexcept
161 161 {
162 162 return *impl->m_DragDropHelper;
163 163 }
@@ -1,216 +1,216
1 1 #include "Visualization/operations/GenerateVariableMenuOperation.h"
2 2 #include "Visualization/operations/MenuBuilder.h"
3 3
4 4 #include "Visualization/VisualizationGraphWidget.h"
5 5 #include "Visualization/VisualizationTabWidget.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7
8 8 #include <Variable/Variable.h>
9 9
10 10 #include <QMenu>
11 11 #include <QStack>
12 12
13 13 Q_LOGGING_CATEGORY(LOG_GenerateVariableMenuOperation, "GenerateVariableMenuOperation")
14 14
15 15 struct GenerateVariableMenuOperation::GenerateVariableMenuOperationPrivate {
16 16 explicit GenerateVariableMenuOperationPrivate(
17 17 QMenu *menu, std::shared_ptr<Variable> variable,
18 18 std::set<IVisualizationWidget *> variableContainers)
19 19 : m_Variable{variable},
20 m_VariableContainers{std::move(variableContainers)},
20 21 m_PlotMenuBuilder{menu},
21 m_UnplotMenuBuilder{menu},
22 m_VariableContainers{std::move(variableContainers)}
22 m_UnplotMenuBuilder{menu}
23 23 {
24 24 }
25 25
26 26 void visitRootEnter()
27 27 {
28 28 // Creates the root menu
29 29 if (auto plotMenu
30 30 = m_PlotMenuBuilder.addMenu(QObject::tr("Plot"), QIcon{":/icones/plot.png"})) {
31 31 plotMenu->setEnabled(m_Variable && m_Variable->dataSeries() != nullptr);
32 32 }
33 33
34 34 m_UnplotMenuBuilder.addMenu(QObject::tr("Unplot"), QIcon{":/icones/unplot.png"});
35 35 }
36 36
37 37 void visitRootLeave()
38 38 {
39 39 // Closes the root menu
40 40 m_PlotMenuBuilder.closeMenu();
41 41 m_UnplotMenuBuilder.closeMenu();
42 42 }
43 43
44 44 void visitNodeEnter(const IVisualizationWidget &container)
45 45 {
46 46 // Opens a new menu associated to the node
47 47 m_PlotMenuBuilder.addMenu(container.name());
48 48 m_UnplotMenuBuilder.addMenu(container.name());
49 49 }
50 50
51 51 template <typename ActionFun>
52 52 void visitNodeLeavePlot(const IVisualizationWidget &container, const QString &actionName,
53 53 ActionFun actionFunction)
54 54 {
55 55 if (isValidContainer(container)) {
56 56 m_PlotMenuBuilder.addSeparator();
57 57 m_PlotMenuBuilder.addAction(actionName, actionFunction);
58 58 }
59 59
60 60 // Closes the menu associated to the node
61 61 m_PlotMenuBuilder.closeMenu();
62 62 }
63 63
64 64 void visitNodeLeaveUnplot()
65 65 {
66 66 // Closes the menu associated to the node
67 67 m_UnplotMenuBuilder.closeMenu();
68 68 }
69 69
70 70 template <typename ActionFun>
71 71 void visitLeafPlot(const IVisualizationWidget &container, const QString &actionName,
72 72 ActionFun actionFunction)
73 73 {
74 74 if (isValidContainer(container)) {
75 75 m_PlotMenuBuilder.addAction(actionName, actionFunction);
76 76 }
77 77 }
78 78
79 79 template <typename ActionFun>
80 80 void visitLeafUnplot(IVisualizationWidget *container, const QString &actionName,
81 81 ActionFun actionFunction)
82 82 {
83 83 // If the container contains the variable, we generate 'unplot' action
84 84 if (m_VariableContainers.count(container) == 1) {
85 85 m_UnplotMenuBuilder.addAction(actionName, actionFunction);
86 86 }
87 87 }
88 88
89 89 bool isValidContainer(const IVisualizationWidget &container) const noexcept
90 90 {
91 91 // A container is valid if it can contain the variable and if the variable is not already
92 92 // contained in another container
93 93 return m_Variable && m_VariableContainers.size() == 0 && container.canDrop(*m_Variable);
94 94 }
95 95
96 96 std::shared_ptr<Variable> m_Variable;
97 97 std::set<IVisualizationWidget *> m_VariableContainers;
98 98 MenuBuilder m_PlotMenuBuilder; ///< Builder for the 'Plot' menu
99 99 MenuBuilder m_UnplotMenuBuilder; ///< Builder for the 'Unplot' menu
100 100 };
101 101
102 102 GenerateVariableMenuOperation::GenerateVariableMenuOperation(
103 103 QMenu *menu, std::shared_ptr<Variable> variable,
104 104 std::set<IVisualizationWidget *> variableContainers)
105 105 : impl{spimpl::make_unique_impl<GenerateVariableMenuOperationPrivate>(
106 106 menu, variable, std::move(variableContainers))}
107 107 {
108 108 }
109 109
110 110 void GenerateVariableMenuOperation::visitEnter(VisualizationWidget *widget)
111 111 {
112 112 // VisualizationWidget is not intended to accommodate a variable
113 113 Q_UNUSED(widget)
114 114
115 115 // 'Plot' and 'Unplot' menus
116 116 impl->visitRootEnter();
117 117 }
118 118
119 119 void GenerateVariableMenuOperation::visitLeave(VisualizationWidget *widget)
120 120 {
121 121 // VisualizationWidget is not intended to accommodate a variable
122 122 Q_UNUSED(widget)
123 123
124 124 // 'Plot' and 'Unplot' menus
125 125 impl->visitRootLeave();
126 126 }
127 127
128 128 void GenerateVariableMenuOperation::visitEnter(VisualizationTabWidget *tabWidget)
129 129 {
130 130 if (tabWidget) {
131 131 // 'Plot' and 'Unplot' menus
132 132 impl->visitNodeEnter(*tabWidget);
133 133 }
134 134 else {
135 135 qCCritical(LOG_GenerateVariableMenuOperation(),
136 136 "Can't visit enter VisualizationTabWidget : the widget is null");
137 137 }
138 138 }
139 139
140 140 void GenerateVariableMenuOperation::visitLeave(VisualizationTabWidget *tabWidget)
141 141 {
142 142 if (tabWidget) {
143 143 // 'Plot' menu
144 144 impl->visitNodeLeavePlot(*tabWidget, QObject::tr("Open in a new zone"),
145 145 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, tabWidget ]() {
146 146 if (auto var = varW.lock()) {
147 147 tabWidget->createZone(var);
148 148 }
149 149 });
150 150
151 151 // 'Unplot' menu
152 152 impl->visitNodeLeaveUnplot();
153 153 }
154 154 else {
155 155 qCCritical(LOG_GenerateVariableMenuOperation(),
156 156 "Can't visit leave VisualizationTabWidget : the widget is null");
157 157 }
158 158 }
159 159
160 160 void GenerateVariableMenuOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
161 161 {
162 162 if (zoneWidget) {
163 163 // 'Plot' and 'Unplot' menus
164 164 impl->visitNodeEnter(*zoneWidget);
165 165 }
166 166 else {
167 167 qCCritical(LOG_GenerateVariableMenuOperation(),
168 168 "Can't visit enter VisualizationZoneWidget : the widget is null");
169 169 }
170 170 }
171 171
172 172 void GenerateVariableMenuOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
173 173 {
174 174 if (zoneWidget) {
175 175 // 'Plot' menu
176 176 impl->visitNodeLeavePlot(
177 177 *zoneWidget, QObject::tr("Open in a new graph"),
178 178 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, zoneWidget ]() {
179 179 if (auto var = varW.lock()) {
180 180 zoneWidget->createGraph(var);
181 181 }
182 182 });
183 183
184 184 // 'Unplot' menu
185 185 impl->visitNodeLeaveUnplot();
186 186 }
187 187 else {
188 188 qCCritical(LOG_GenerateVariableMenuOperation(),
189 189 "Can't visit leave VisualizationZoneWidget : the widget is null");
190 190 }
191 191 }
192 192
193 193 void GenerateVariableMenuOperation::visit(VisualizationGraphWidget *graphWidget)
194 194 {
195 195 if (graphWidget) {
196 196 // 'Plot' menu
197 197 impl->visitLeafPlot(*graphWidget, QObject::tr("Open in %1").arg(graphWidget->name()),
198 198 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, graphWidget ]() {
199 199 if (auto var = varW.lock()) {
200 200 graphWidget->addVariable(var, graphWidget->graphRange());
201 201 }
202 202 });
203 203
204 204 // 'Unplot' menu
205 205 impl->visitLeafUnplot(graphWidget, QObject::tr("Remove from %1").arg(graphWidget->name()),
206 206 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, graphWidget ]() {
207 207 if (auto var = varW.lock()) {
208 208 graphWidget->removeVariable(var);
209 209 }
210 210 });
211 211 }
212 212 else {
213 213 qCCritical(LOG_GenerateVariableMenuOperation(),
214 214 "Can't visit VisualizationGraphWidget : the widget is null");
215 215 }
216 216 }
@@ -1,387 +1,387
1 1 #include "AmdaResultParserHelper.h"
2 2
3 3 #include <Common/DateUtils.h>
4 4 #include <Common/SortUtils.h>
5 5
6 6 #include <Data/ScalarSeries.h>
7 7 #include <Data/SpectrogramSeries.h>
8 8 #include <Data/Unit.h>
9 9 #include <Data/VectorSeries.h>
10 10
11 11 #include <QtCore/QDateTime>
12 12 #include <QtCore/QRegularExpression>
13 13
14 14 #include <functional>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_AmdaResultParserHelper, "AmdaResultParserHelper")
17 17
18 18 namespace {
19 19
20 20 // ///////// //
21 21 // Constants //
22 22 // ///////// //
23 23
24 24 /// Separator between values in a result line
25 25 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
26 26
27 27 /// Format for dates in result files
28 28 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
29 29
30 30 // /////// //
31 31 // Methods //
32 32 // /////// //
33 33
34 34 /**
35 35 * Checks that the properties contain a specific unit and that this unit is valid
36 36 * @param properties the properties map in which to search unit
37 37 * @param key the key to search for the unit in the properties
38 38 * @param errorMessage the error message to log in case the unit is invalid
39 39 * @return true if the unit is valid, false it it's invalid or was not found in the properties
40 40 */
41 41 bool checkUnit(const Properties &properties, const QString &key, const QString &errorMessage)
42 42 {
43 43 auto unit = properties.value(key).value<Unit>();
44 44 if (unit.m_Name.isEmpty()) {
45 45 qCWarning(LOG_AmdaResultParserHelper()) << errorMessage;
46 46 return false;
47 47 }
48 48
49 49 return true;
50 50 }
51 51
52 52 QDateTime dateTimeFromString(const QString &stringDate) noexcept
53 53 {
54 54 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
55 55 return QDateTime::fromString(stringDate, Qt::ISODateWithMs);
56 56 #else
57 57 return QDateTime::fromString(stringDate, DATE_FORMAT);
58 58 #endif
59 59 }
60 60
61 61 /// Converts a string date to a double date
62 62 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
63 63 double doubleDate(const QString &stringDate) noexcept
64 64 {
65 65 // Format: yyyy-MM-ddThh:mm:ss.zzz
66 66 auto dateTime = dateTimeFromString(stringDate);
67 67 dateTime.setTimeSpec(Qt::UTC);
68 68 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
69 69 : std::numeric_limits<double>::quiet_NaN();
70 70 }
71 71
72 72 /**
73 73 * Reads a line from the AMDA file and tries to extract a x-axis data and value data from it
74 74 * @param xAxisData the vector in which to store the x-axis data extracted
75 75 * @param valuesData the vector in which to store the value extracted
76 76 * @param line the line to read to extract the property
77 77 * @param valuesIndexes indexes of insertion of read values. For example, if the line contains three
78 78 * columns of values, and valuesIndexes are {2, 0, 1}, the value of the third column will be read
79 79 * and inserted first, then the value of the first column, and finally the value of the second
80 80 * column.
81 81 * @param fillValue value that tags an invalid data. For example, if fillValue is -1 and a read
82 82 * value is -1, then this value is considered as invalid and converted to NaN
83 83 */
84 84 void tryReadResult(std::vector<double> &xAxisData, std::vector<double> &valuesData,
85 85 const QString &line, const std::vector<int> &valuesIndexes,
86 86 double fillValue = std::numeric_limits<double>::quiet_NaN())
87 87 {
88 88 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
89 89
90 90 // Checks that the line contains expected number of values + x-axis value
91 if (lineData.size() == valuesIndexes.size() + 1) {
91 if (static_cast<size_t>(lineData.size()) == valuesIndexes.size() + 1) {
92 92 // X : the data is converted from date to double (in secs)
93 93 auto x = doubleDate(lineData.at(0));
94 94
95 95 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
96 96 if (!std::isnan(x)) {
97 97 xAxisData.push_back(x);
98 98
99 99 // Values
100 100 for (auto valueIndex : valuesIndexes) {
101 101 bool valueOk;
102 102 // we use valueIndex + 1 to skip column 0 (x-axis value)
103 103 auto value = lineData.at(valueIndex + 1).toDouble(&valueOk);
104 104
105 105 if (!valueOk) {
106 106 qCWarning(LOG_AmdaResultParserHelper())
107 107 << QObject::tr(
108 108 "Value from (line %1, column %2) is invalid and will be "
109 109 "converted to NaN")
110 110 .arg(line, valueIndex);
111 111 value = std::numeric_limits<double>::quiet_NaN();
112 112 }
113 113
114 114 // Handles fill value
115 115 if (!std::isnan(fillValue) && !std::isnan(value) && fillValue == value) {
116 116 value = std::numeric_limits<double>::quiet_NaN();
117 117 }
118 118
119 119 valuesData.push_back(value);
120 120 }
121 121 }
122 122 else {
123 123 qCWarning(LOG_AmdaResultParserHelper())
124 124 << QObject::tr("Can't retrieve results from line %1: x is invalid").arg(line);
125 125 }
126 126 }
127 127 else {
128 128 qCWarning(LOG_AmdaResultParserHelper())
129 129 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
130 130 }
131 131 }
132 132
133 133 /**
134 134 * Reads a line from the AMDA file and tries to extract a property from it
135 135 * @param properties the properties map in which to put the property extracted from the line
136 136 * @param key the key to which the property is added in the properties map
137 137 * @param line the line to read to extract the property
138 138 * @param regex the expected regex to extract the property. If the line matches this regex, the
139 139 * property is generated
140 140 * @param fun the function used to generate the property
141 141 * @return true if the property could be generated, false if the line does not match the regex, or
142 142 * if a property has already been generated for the key
143 143 */
144 144 template <typename GeneratePropertyFun>
145 145 bool tryReadProperty(Properties &properties, const QString &key, const QString &line,
146 146 const QRegularExpression &regex, GeneratePropertyFun fun)
147 147 {
148 148 if (properties.contains(key)) {
149 149 return false;
150 150 }
151 151
152 152 auto match = regex.match(line);
153 153 if (match.hasMatch()) {
154 154 properties.insert(key, fun(match));
155 155 }
156 156
157 157 return match.hasMatch();
158 158 }
159 159
160 160 /**
161 161 * Reads a line from the AMDA file and tries to extract a double from it
162 162 * @sa tryReadProperty()
163 163 */
164 164 bool tryReadDouble(Properties &properties, const QString &key, const QString &line,
165 165 const QRegularExpression &regex)
166 166 {
167 167 return tryReadProperty(properties, key, line, regex, [](const auto &match) {
168 168 bool ok;
169 169
170 170 // If the value can't be converted to double, it is set to NaN
171 171 auto doubleValue = match.captured(1).toDouble(&ok);
172 172 if (!ok) {
173 173 doubleValue = std::numeric_limits<double>::quiet_NaN();
174 174 }
175 175
176 176 return QVariant::fromValue(doubleValue);
177 177 });
178 178 }
179 179
180 180 /**
181 181 * Reads a line from the AMDA file and tries to extract a vector of doubles from it
182 182 * @param sep the separator of double values in the line
183 183 * @sa tryReadProperty()
184 184 */
185 185 bool tryReadDoubles(Properties &properties, const QString &key, const QString &line,
186 186 const QRegularExpression &regex, const QString &sep = QStringLiteral(","))
187 187 {
188 188 return tryReadProperty(properties, key, line, regex, [sep](const auto &match) {
189 189 std::vector<double> doubleValues{};
190 190
191 191 // If the value can't be converted to double, it is set to NaN
192 192 auto values = match.captured(1).split(sep);
193 193 for (auto value : values) {
194 194 bool ok;
195 195
196 196 auto doubleValue = value.toDouble(&ok);
197 197 if (!ok) {
198 198 doubleValue = std::numeric_limits<double>::quiet_NaN();
199 199 }
200 200
201 201 doubleValues.push_back(doubleValue);
202 202 }
203 203
204 204 return QVariant::fromValue(doubleValues);
205 205 });
206 206 }
207 207
208 208 /**
209 209 * Reads a line from the AMDA file and tries to extract a unit from it
210 210 * @sa tryReadProperty()
211 211 */
212 212 bool tryReadUnit(Properties &properties, const QString &key, const QString &line,
213 213 const QRegularExpression &regex, bool timeUnit = false)
214 214 {
215 215 return tryReadProperty(properties, key, line, regex, [timeUnit](const auto &match) {
216 216 return QVariant::fromValue(Unit{match.captured(1), timeUnit});
217 217 });
218 218 }
219 219
220 220 } // namespace
221 221
222 222 // ////////////////// //
223 223 // ScalarParserHelper //
224 224 // ////////////////// //
225 225
226 226 bool ScalarParserHelper::checkProperties()
227 227 {
228 228 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
229 229 QObject::tr("The x-axis unit could not be found in the file"));
230 230 }
231 231
232 232 std::shared_ptr<IDataSeries> ScalarParserHelper::createSeries()
233 233 {
234 234 return std::make_shared<ScalarSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
235 235 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
236 236 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
237 237 }
238 238
239 239 void ScalarParserHelper::readPropertyLine(const QString &line)
240 240 {
241 241 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
242 242 }
243 243
244 244 void ScalarParserHelper::readResultLine(const QString &line)
245 245 {
246 246 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
247 247 }
248 248
249 249 std::vector<int> ScalarParserHelper::valuesIndexes() const
250 250 {
251 251 // Only one value to read
252 252 static auto result = std::vector<int>{0};
253 253 return result;
254 254 }
255 255
256 256 // /////////////////////// //
257 257 // SpectrogramParserHelper //
258 258 // /////////////////////// //
259 259
260 260 bool SpectrogramParserHelper::checkProperties()
261 261 {
262 262 // Generates y-axis data from bands extracted (take the middle of the intervals)
263 263 auto minBands = m_Properties.value(MIN_BANDS_PROPERTY).value<std::vector<double> >();
264 264 auto maxBands = m_Properties.value(MAX_BANDS_PROPERTY).value<std::vector<double> >();
265 265
266 266 if (minBands.size() != maxBands.size()) {
267 267 qCWarning(LOG_AmdaResultParserHelper()) << QObject::tr(
268 268 "Can't generate y-axis data from bands extracted: bands intervals are invalid");
269 269 return false;
270 270 }
271 271
272 272 std::transform(
273 273 minBands.begin(), minBands.end(), maxBands.begin(), std::back_inserter(m_YAxisData),
274 274 [](const auto &minValue, const auto &maxValue) { return (minValue + maxValue) / 2.; });
275 275
276 276 // Generates values indexes, i.e. the order in which each value will be retrieved (in ascending
277 277 // order of the associated bands)
278 278 m_ValuesIndexes = SortUtils::sortPermutation(m_YAxisData, std::less<double>());
279 279
280 280 // Sorts y-axis data accoding to the ascending order
281 281 m_YAxisData = SortUtils::sort(m_YAxisData, 1, m_ValuesIndexes);
282 282
283 283 // Sets fill value
284 284 m_FillValue = m_Properties.value(FILL_VALUE_PROPERTY).value<double>();
285 285
286 286 /// @todo: handle min/max samplings?
287 287
288 288 return true;
289 289 }
290 290
291 291 std::shared_ptr<IDataSeries> SpectrogramParserHelper::createSeries()
292 292 {
293 293 return std::make_shared<SpectrogramSeries>(
294 294 std::move(m_XAxisData), std::move(m_YAxisData), std::move(m_ValuesData),
295 295 Unit{"t", true}, // x-axis unit is always a time unit
296 296 m_Properties.value(Y_AXIS_UNIT_PROPERTY).value<Unit>(),
297 297 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
298 298 }
299 299
300 300 void SpectrogramParserHelper::readPropertyLine(const QString &line)
301 301 {
302 302 // Set of functions to test on the line to generate a property. If a function is valid (i.e. a
303 303 // property has been generated for the line), the line is treated as processed and the other
304 304 // functions are not called
305 305 std::vector<std::function<bool()> > functions{
306 306 // values unit
307 307 [&] {
308 308 return tryReadUnit(m_Properties, VALUES_UNIT_PROPERTY, line,
309 309 SPECTROGRAM_VALUES_UNIT_REGEX);
310 310 },
311 311 // y-axis unit
312 312 [&] {
313 313 return tryReadUnit(m_Properties, Y_AXIS_UNIT_PROPERTY, line,
314 314 SPECTROGRAM_Y_AXIS_UNIT_REGEX);
315 315 },
316 316 // min sampling
317 317 [&] {
318 318 return tryReadDouble(m_Properties, MIN_SAMPLING_PROPERTY, line,
319 319 SPECTROGRAM_MIN_SAMPLING_REGEX);
320 320 },
321 321 // max sampling
322 322 [&] {
323 323 return tryReadDouble(m_Properties, MAX_SAMPLING_PROPERTY, line,
324 324 SPECTROGRAM_MAX_SAMPLING_REGEX);
325 325 },
326 326 // fill value
327 327 [&] {
328 328 return tryReadDouble(m_Properties, FILL_VALUE_PROPERTY, line,
329 329 SPECTROGRAM_FILL_VALUE_REGEX);
330 330 },
331 331 // min bounds of each band
332 332 [&] {
333 333 return tryReadDoubles(m_Properties, MIN_BANDS_PROPERTY, line,
334 334 SPECTROGRAM_MIN_BANDS_REGEX);
335 335 },
336 336 // max bounds of each band
337 337 [&] {
338 338 return tryReadDoubles(m_Properties, MAX_BANDS_PROPERTY, line,
339 339 SPECTROGRAM_MAX_BANDS_REGEX);
340 340 }};
341 341
342 342 for (auto function : functions) {
343 343 // Stops at the first function that is valid
344 344 if (function()) {
345 345 return;
346 346 }
347 347 }
348 348 }
349 349
350 350 void SpectrogramParserHelper::readResultLine(const QString &line)
351 351 {
352 352 tryReadResult(m_XAxisData, m_ValuesData, line, m_ValuesIndexes, m_FillValue);
353 353 }
354 354
355 355 // ////////////////// //
356 356 // VectorParserHelper //
357 357 // ////////////////// //
358 358
359 359 bool VectorParserHelper::checkProperties()
360 360 {
361 361 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
362 362 QObject::tr("The x-axis unit could not be found in the file"));
363 363 }
364 364
365 365 std::shared_ptr<IDataSeries> VectorParserHelper::createSeries()
366 366 {
367 367 return std::make_shared<VectorSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
368 368 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
369 369 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
370 370 }
371 371
372 372 void VectorParserHelper::readPropertyLine(const QString &line)
373 373 {
374 374 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
375 375 }
376 376
377 377 void VectorParserHelper::readResultLine(const QString &line)
378 378 {
379 379 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
380 380 }
381 381
382 382 std::vector<int> VectorParserHelper::valuesIndexes() const
383 383 {
384 384 // 3 values to read, in order in the file (x, y, z)
385 385 static auto result = std::vector<int>{0, 1, 2};
386 386 return result;
387 387 }
General Comments 0
You need to be logged in to leave comments. Login now