@@ -0,0 +1,35 | |||||
|
1 | #ifndef SCIQLOP_STRINGUTILS_H | |||
|
2 | #define SCIQLOP_STRINGUTILS_H | |||
|
3 | ||||
|
4 | #include "CoreGlobal.h" | |||
|
5 | ||||
|
6 | #include <vector> | |||
|
7 | ||||
|
8 | class QString; | |||
|
9 | ||||
|
10 | /** | |||
|
11 | * Utility class with methods for strings | |||
|
12 | */ | |||
|
13 | struct SCIQLOP_CORE_EXPORT StringUtils { | |||
|
14 | /** | |||
|
15 | * Generates a unique name from a default name and a set of forbidden names. | |||
|
16 | * | |||
|
17 | * Generating the unique name is done by adding an index to the default name and stopping at the | |||
|
18 | * first index for which the generated name is not in the forbidden names. | |||
|
19 | * | |||
|
20 | * Examples (defaultName, forbiddenNames -> result): | |||
|
21 | * - "FGM", {"FGM"} -> "FGM1" | |||
|
22 | * - "FGM", {"ABC"} -> "FGM" | |||
|
23 | * - "FGM", {"FGM", "FGM1"} -> "FGM2" | |||
|
24 | * - "FGM", {"FGM", "FGM2"} -> "FGM1" | |||
|
25 | * - "", {"ABC"} -> "1" | |||
|
26 | * | |||
|
27 | * @param defaultName the default name | |||
|
28 | * @param forbiddenNames the set of forbidden names | |||
|
29 | * @return the unique name generated | |||
|
30 | */ | |||
|
31 | static QString uniqueName(const QString &defaultName, | |||
|
32 | const std::vector<QString> &forbiddenNames) noexcept; | |||
|
33 | }; | |||
|
34 | ||||
|
35 | #endif // SCIQLOP_STRINGUTILS_H |
@@ -0,0 +1,30 | |||||
|
1 | #include "Common/StringUtils.h" | |||
|
2 | ||||
|
3 | #include <QRegExp> | |||
|
4 | #include <QString> | |||
|
5 | ||||
|
6 | #include <set> | |||
|
7 | ||||
|
8 | QString StringUtils::uniqueName(const QString &defaultName, | |||
|
9 | const std::vector<QString> &forbiddenNames) noexcept | |||
|
10 | { | |||
|
11 | // Gets the base of the unique name to generate, by removing trailing number (for example, base | |||
|
12 | // name of "FGM12" is "FGM") | |||
|
13 | auto baseName = defaultName; | |||
|
14 | baseName.remove(QRegExp{QStringLiteral("\\d*$")}); | |||
|
15 | ||||
|
16 | // Finds the unique name by adding an index to the base name and stops when the generated name | |||
|
17 | // isn't forbidden | |||
|
18 | QString newName{}; | |||
|
19 | auto forbidden = true; | |||
|
20 | for (auto i = 0; forbidden; ++i) { | |||
|
21 | newName = (i == 0) ? baseName : baseName + QString::number(i); | |||
|
22 | forbidden = newName.isEmpty() | |||
|
23 | || std::any_of(forbiddenNames.cbegin(), forbiddenNames.cend(), | |||
|
24 | [&newName](const auto &name) { | |||
|
25 | return name.compare(newName, Qt::CaseInsensitive) == 0; | |||
|
26 | }); | |||
|
27 | } | |||
|
28 | ||||
|
29 | return newName; | |||
|
30 | } |
@@ -0,0 +1,50 | |||||
|
1 | #include <Common/StringUtils.h> | |||
|
2 | ||||
|
3 | #include <QObject> | |||
|
4 | #include <QtTest> | |||
|
5 | ||||
|
6 | class TestStringUtils : public QObject { | |||
|
7 | Q_OBJECT | |||
|
8 | ||||
|
9 | private slots: | |||
|
10 | void testUniqueName_data(); | |||
|
11 | void testUniqueName(); | |||
|
12 | }; | |||
|
13 | ||||
|
14 | void TestStringUtils::testUniqueName_data() | |||
|
15 | { | |||
|
16 | // ////////////// // | |||
|
17 | // Test structure // | |||
|
18 | // ////////////// // | |||
|
19 | ||||
|
20 | QTest::addColumn<QString>("defaultName"); | |||
|
21 | QTest::addColumn<std::vector<QString> >("forbiddenNames"); | |||
|
22 | QTest::addColumn<QString>("expectedName"); | |||
|
23 | ||||
|
24 | // ////////// // | |||
|
25 | // Test cases // | |||
|
26 | // ////////// // | |||
|
27 | ||||
|
28 | QTest::newRow("uniqueName") << "FGM" << std::vector<QString>{"FGM2"} << "FGM"; | |||
|
29 | QTest::newRow("uniqueName2") << "FGM2" << std::vector<QString>{"FGM", "FGM1", "FGM2"} << "FGM3"; | |||
|
30 | QTest::newRow("uniqueName3") << "FGM1" << std::vector<QString>{"FGM1"} << "FGM"; | |||
|
31 | QTest::newRow("uniqueName4") << "FGM" << std::vector<QString>{"FGM"} << "FGM1"; | |||
|
32 | QTest::newRow("uniqueName5") << "FGM" << std::vector<QString>{"FGM", "FGM1", "FGM3"} << "FGM2"; | |||
|
33 | QTest::newRow("uniqueName6") << "FGM" << std::vector<QString>{"A", "B", "C"} << "FGM"; | |||
|
34 | QTest::newRow("uniqueName7") << "FGM" << std::vector<QString>{"fGm", "FGm1", "Fgm2"} << "FGM3"; | |||
|
35 | QTest::newRow("uniqueName8") << "" << std::vector<QString>{"A", "B", "C"} << "1"; | |||
|
36 | QTest::newRow("uniqueName9") << "24" << std::vector<QString>{"A", "B", "C"} << "1"; | |||
|
37 | } | |||
|
38 | ||||
|
39 | void TestStringUtils::testUniqueName() | |||
|
40 | { | |||
|
41 | QFETCH(QString, defaultName); | |||
|
42 | QFETCH(std::vector<QString>, forbiddenNames); | |||
|
43 | QFETCH(QString, expectedName); | |||
|
44 | ||||
|
45 | auto result = StringUtils::uniqueName(defaultName, forbiddenNames); | |||
|
46 | QCOMPARE(result, expectedName); | |||
|
47 | } | |||
|
48 | ||||
|
49 | QTEST_MAIN(TestStringUtils) | |||
|
50 | #include "TestStringUtils.moc" |
@@ -1,62 +1,63 | |||||
1 |
|
1 | |||
2 | core_moc_headers = [ |
|
2 | core_moc_headers = [ | |
3 | 'include/Data/IDataProvider.h', |
|
3 | 'include/Data/IDataProvider.h', | |
4 | 'include/DataSource/DataSourceController.h', |
|
4 | 'include/DataSource/DataSourceController.h', | |
5 | 'include/DataSource/DataSourceItemAction.h', |
|
5 | 'include/DataSource/DataSourceItemAction.h', | |
6 | 'include/Network/NetworkController.h', |
|
6 | 'include/Network/NetworkController.h', | |
7 | 'include/Time/TimeController.h', |
|
7 | 'include/Time/TimeController.h', | |
8 | 'include/Variable/Variable.h', |
|
8 | 'include/Variable/Variable.h', | |
9 | 'include/Variable/VariableCacheController.h', |
|
9 | 'include/Variable/VariableCacheController.h', | |
10 | 'include/Variable/VariableController.h', |
|
10 | 'include/Variable/VariableController.h', | |
11 | 'include/Variable/VariableAcquisitionWorker.h', |
|
11 | 'include/Variable/VariableAcquisitionWorker.h', | |
12 | 'include/Variable/VariableCacheStrategy.h', |
|
12 | 'include/Variable/VariableCacheStrategy.h', | |
13 | 'include/Variable/VariableSynchronizationGroup.h', |
|
13 | 'include/Variable/VariableSynchronizationGroup.h', | |
14 | 'include/Variable/VariableModel.h', |
|
14 | 'include/Variable/VariableModel.h', | |
15 | 'include/Visualization/VisualizationController.h' |
|
15 | 'include/Visualization/VisualizationController.h' | |
16 | ] |
|
16 | ] | |
17 |
|
17 | |||
18 |
|
18 | |||
19 | core_moc_files = qt5.preprocess(moc_headers : core_moc_headers) |
|
19 | core_moc_files = qt5.preprocess(moc_headers : core_moc_headers) | |
20 |
|
20 | |||
21 | core_sources = [ |
|
21 | core_sources = [ | |
22 | 'src/Common/DateUtils.cpp', |
|
22 | 'src/Common/DateUtils.cpp', | |
|
23 | 'src/Common/StringUtils.cpp', | |||
23 | 'src/Data/ScalarSeries.cpp', |
|
24 | 'src/Data/ScalarSeries.cpp', | |
24 | 'src/Data/DataSeriesIterator.cpp', |
|
25 | 'src/Data/DataSeriesIterator.cpp', | |
25 | 'src/Data/ArrayDataIterator.cpp', |
|
26 | 'src/Data/ArrayDataIterator.cpp', | |
26 | 'src/Data/VectorSeries.cpp', |
|
27 | 'src/Data/VectorSeries.cpp', | |
27 | 'src/DataSource/DataSourceController.cpp', |
|
28 | 'src/DataSource/DataSourceController.cpp', | |
28 | 'src/DataSource/DataSourceItem.cpp', |
|
29 | 'src/DataSource/DataSourceItem.cpp', | |
29 | 'src/DataSource/DataSourceItemAction.cpp', |
|
30 | 'src/DataSource/DataSourceItemAction.cpp', | |
30 | 'src/Network/NetworkController.cpp', |
|
31 | 'src/Network/NetworkController.cpp', | |
31 | 'src/Plugin/PluginManager.cpp', |
|
32 | 'src/Plugin/PluginManager.cpp', | |
32 | 'src/Settings/SqpSettingsDefs.cpp', |
|
33 | 'src/Settings/SqpSettingsDefs.cpp', | |
33 | 'src/Time/TimeController.cpp', |
|
34 | 'src/Time/TimeController.cpp', | |
34 | 'src/Variable/Variable.cpp', |
|
35 | 'src/Variable/Variable.cpp', | |
35 | 'src/Variable/VariableCacheController.cpp', |
|
36 | 'src/Variable/VariableCacheController.cpp', | |
36 | 'src/Variable/VariableController.cpp', |
|
37 | 'src/Variable/VariableController.cpp', | |
37 | 'src/Variable/VariableAcquisitionWorker.cpp', |
|
38 | 'src/Variable/VariableAcquisitionWorker.cpp', | |
38 | 'src/Variable/VariableCacheStrategy.cpp', |
|
39 | 'src/Variable/VariableCacheStrategy.cpp', | |
39 | 'src/Variable/VariableSynchronizationGroup.cpp', |
|
40 | 'src/Variable/VariableSynchronizationGroup.cpp', | |
40 | 'src/Variable/VariableModel.cpp', |
|
41 | 'src/Variable/VariableModel.cpp', | |
41 | 'src/Visualization/VisualizationController.cpp' |
|
42 | 'src/Visualization/VisualizationController.cpp' | |
42 | ] |
|
43 | ] | |
43 |
|
44 | |||
44 | core_inc = include_directories(['include', '../plugin/include']) |
|
45 | core_inc = include_directories(['include', '../plugin/include']) | |
45 |
|
46 | |||
46 | sciqlop_core_lib = library('sciqlopcore', |
|
47 | sciqlop_core_lib = library('sciqlopcore', | |
47 | core_sources, |
|
48 | core_sources, | |
48 | core_moc_files, |
|
49 | core_moc_files, | |
49 | cpp_args : '-DCORE_LIB', |
|
50 | cpp_args : '-DCORE_LIB', | |
50 | include_directories : core_inc, |
|
51 | include_directories : core_inc, | |
51 | dependencies : [qt5core, qt5network], |
|
52 | dependencies : [qt5core, qt5network], | |
52 | install : true |
|
53 | install : true | |
53 | ) |
|
54 | ) | |
54 |
|
55 | |||
55 |
|
56 | |||
56 | sciqlop_core = declare_dependency(link_with : sciqlop_core_lib, |
|
57 | sciqlop_core = declare_dependency(link_with : sciqlop_core_lib, | |
57 | include_directories : core_inc, |
|
58 | include_directories : core_inc, | |
58 | dependencies : [qt5core, qt5network]) |
|
59 | dependencies : [qt5core, qt5network]) | |
59 |
|
60 | |||
60 |
|
61 | |||
61 | subdir('tests') |
|
62 | subdir('tests') | |
62 |
|
63 |
@@ -1,269 +1,284 | |||||
1 | #include <Variable/Variable.h> |
|
1 | #include <Variable/Variable.h> | |
2 | #include <Variable/VariableModel.h> |
|
2 | #include <Variable/VariableModel.h> | |
3 |
|
3 | |||
4 | #include <Common/DateUtils.h> |
|
4 | #include <Common/DateUtils.h> | |
|
5 | #include <Common/StringUtils.h> | |||
5 |
|
6 | |||
6 | #include <Data/IDataSeries.h> |
|
7 | #include <Data/IDataSeries.h> | |
7 |
|
8 | |||
8 | #include <QSize> |
|
9 | #include <QSize> | |
9 | #include <unordered_map> |
|
10 | #include <unordered_map> | |
10 |
|
11 | |||
11 | Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel") |
|
12 | Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel") | |
12 |
|
13 | |||
13 | namespace { |
|
14 | namespace { | |
14 |
|
15 | |||
15 | // Column indexes |
|
16 | // Column indexes | |
16 | const auto NAME_COLUMN = 0; |
|
17 | const auto NAME_COLUMN = 0; | |
17 | const auto TSTART_COLUMN = 1; |
|
18 | const auto TSTART_COLUMN = 1; | |
18 | const auto TEND_COLUMN = 2; |
|
19 | const auto TEND_COLUMN = 2; | |
19 | const auto UNIT_COLUMN = 3; |
|
20 | const auto UNIT_COLUMN = 3; | |
20 | const auto MISSION_COLUMN = 4; |
|
21 | const auto MISSION_COLUMN = 4; | |
21 | const auto PLUGIN_COLUMN = 5; |
|
22 | const auto PLUGIN_COLUMN = 5; | |
22 | const auto NB_COLUMNS = 6; |
|
23 | const auto NB_COLUMNS = 6; | |
23 |
|
24 | |||
24 | // Column properties |
|
25 | // Column properties | |
25 | const auto DEFAULT_HEIGHT = 25; |
|
26 | const auto DEFAULT_HEIGHT = 25; | |
26 | const auto DEFAULT_WIDTH = 100; |
|
27 | const auto DEFAULT_WIDTH = 100; | |
27 |
|
28 | |||
28 | struct ColumnProperties { |
|
29 | struct ColumnProperties { | |
29 | ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH, |
|
30 | ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH, | |
30 | int height = DEFAULT_HEIGHT) |
|
31 | int height = DEFAULT_HEIGHT) | |
31 | : m_Name{name}, m_Width{width}, m_Height{height} |
|
32 | : m_Name{name}, m_Width{width}, m_Height{height} | |
32 | { |
|
33 | { | |
33 | } |
|
34 | } | |
34 |
|
35 | |||
35 | QString m_Name; |
|
36 | QString m_Name; | |
36 | int m_Width; |
|
37 | int m_Width; | |
37 | int m_Height; |
|
38 | int m_Height; | |
38 | }; |
|
39 | }; | |
39 |
|
40 | |||
40 | const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{ |
|
41 | const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{ | |
41 | {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}}, |
|
42 | {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}}, | |
42 | {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {UNIT_COLUMN, {QObject::tr("Unit")}}, |
|
43 | {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {UNIT_COLUMN, {QObject::tr("Unit")}}, | |
43 | {MISSION_COLUMN, {QObject::tr("Mission")}}, {PLUGIN_COLUMN, {QObject::tr("Plugin")}}}; |
|
44 | {MISSION_COLUMN, {QObject::tr("Mission")}}, {PLUGIN_COLUMN, {QObject::tr("Plugin")}}}; | |
44 |
|
45 | |||
45 | /// Format for datetimes |
|
46 | /// Format for datetimes | |
46 | const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz"); |
|
47 | const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz"); | |
47 |
|
48 | |||
|
49 | QString uniqueName(const QString &defaultName, | |||
|
50 | const std::vector<std::shared_ptr<Variable> > &variables) | |||
|
51 | { | |||
|
52 | auto forbiddenNames = std::vector<QString>(variables.size()); | |||
|
53 | std::transform(variables.cbegin(), variables.cend(), forbiddenNames.begin(), | |||
|
54 | [](const auto &variable) { return variable->name(); }); | |||
|
55 | auto uniqueName = StringUtils::uniqueName(defaultName, forbiddenNames); | |||
|
56 | Q_ASSERT(!uniqueName.isEmpty()); | |||
|
57 | ||||
|
58 | return uniqueName; | |||
|
59 | } | |||
48 |
|
60 | |||
49 | } // namespace |
|
61 | } // namespace | |
50 |
|
62 | |||
51 | struct VariableModel::VariableModelPrivate { |
|
63 | struct VariableModel::VariableModelPrivate { | |
52 | /// Variables created in SciQlop |
|
64 | /// Variables created in SciQlop | |
53 | std::vector<std::shared_ptr<Variable> > m_Variables; |
|
65 | std::vector<std::shared_ptr<Variable> > m_Variables; | |
54 | std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress; |
|
66 | std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress; | |
55 |
|
67 | |||
56 | /// Return the row index of the variable. -1 if it's not found |
|
68 | /// Return the row index of the variable. -1 if it's not found | |
57 | int indexOfVariable(Variable *variable) const noexcept; |
|
69 | int indexOfVariable(Variable *variable) const noexcept; | |
58 | }; |
|
70 | }; | |
59 |
|
71 | |||
60 | VariableModel::VariableModel(QObject *parent) |
|
72 | VariableModel::VariableModel(QObject *parent) | |
61 | : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()} |
|
73 | : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()} | |
62 | { |
|
74 | { | |
63 | } |
|
75 | } | |
64 |
|
76 | |||
65 | void VariableModel::addVariable(std::shared_ptr<Variable> variable) noexcept |
|
77 | void VariableModel::addVariable(std::shared_ptr<Variable> variable) noexcept | |
66 | { |
|
78 | { | |
67 | auto insertIndex = rowCount(); |
|
79 | auto insertIndex = rowCount(); | |
68 | beginInsertRows({}, insertIndex, insertIndex); |
|
80 | beginInsertRows({}, insertIndex, insertIndex); | |
69 |
|
81 | |||
|
82 | // Generates unique name for the variable | |||
|
83 | variable->setName(uniqueName(variable->name(), impl->m_Variables)); | |||
|
84 | ||||
70 | impl->m_Variables.push_back(variable); |
|
85 | impl->m_Variables.push_back(variable); | |
71 | connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated); |
|
86 | connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated); | |
72 |
|
87 | |||
73 | endInsertRows(); |
|
88 | endInsertRows(); | |
74 | } |
|
89 | } | |
75 |
|
90 | |||
76 | std::shared_ptr<Variable> VariableModel::createVariable(const QString &name, |
|
91 | std::shared_ptr<Variable> VariableModel::createVariable(const QString &name, | |
77 | const SqpRange &dateTime, |
|
92 | const SqpRange &dateTime, | |
78 | const QVariantHash &metadata) noexcept |
|
93 | const QVariantHash &metadata) noexcept | |
79 | { |
|
94 | { | |
80 | auto variable = std::make_shared<Variable>(name, dateTime, metadata); |
|
95 | auto variable = std::make_shared<Variable>(name, dateTime, metadata); | |
81 | addVariable(variable); |
|
96 | addVariable(variable); | |
82 |
|
97 | |||
83 | return variable; |
|
98 | return variable; | |
84 | } |
|
99 | } | |
85 |
|
100 | |||
86 | void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept |
|
101 | void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept | |
87 | { |
|
102 | { | |
88 | if (!variable) { |
|
103 | if (!variable) { | |
89 | qCCritical(LOG_Variable()) << "Can't delete a null variable from the model"; |
|
104 | qCCritical(LOG_Variable()) << "Can't delete a null variable from the model"; | |
90 | return; |
|
105 | return; | |
91 | } |
|
106 | } | |
92 |
|
107 | |||
93 | // Finds variable in the model |
|
108 | // Finds variable in the model | |
94 | auto begin = impl->m_Variables.cbegin(); |
|
109 | auto begin = impl->m_Variables.cbegin(); | |
95 | auto end = impl->m_Variables.cend(); |
|
110 | auto end = impl->m_Variables.cend(); | |
96 | auto it = std::find(begin, end, variable); |
|
111 | auto it = std::find(begin, end, variable); | |
97 | if (it != end) { |
|
112 | if (it != end) { | |
98 | auto removeIndex = std::distance(begin, it); |
|
113 | auto removeIndex = std::distance(begin, it); | |
99 |
|
114 | |||
100 | // Deletes variable |
|
115 | // Deletes variable | |
101 | beginRemoveRows({}, removeIndex, removeIndex); |
|
116 | beginRemoveRows({}, removeIndex, removeIndex); | |
102 | impl->m_Variables.erase(it); |
|
117 | impl->m_Variables.erase(it); | |
103 | endRemoveRows(); |
|
118 | endRemoveRows(); | |
104 | } |
|
119 | } | |
105 | else { |
|
120 | else { | |
106 | qCritical(LOG_VariableModel()) |
|
121 | qCritical(LOG_VariableModel()) | |
107 | << tr("Can't delete variable %1 from the model: the variable is not in the model") |
|
122 | << tr("Can't delete variable %1 from the model: the variable is not in the model") | |
108 | .arg(variable->name()); |
|
123 | .arg(variable->name()); | |
109 | } |
|
124 | } | |
110 |
|
125 | |||
111 | // Removes variable from progress map |
|
126 | // Removes variable from progress map | |
112 | impl->m_VariableToProgress.erase(variable); |
|
127 | impl->m_VariableToProgress.erase(variable); | |
113 | } |
|
128 | } | |
114 |
|
129 | |||
115 |
|
130 | |||
116 | std::shared_ptr<Variable> VariableModel::variable(int index) const |
|
131 | std::shared_ptr<Variable> VariableModel::variable(int index) const | |
117 | { |
|
132 | { | |
118 | return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr; |
|
133 | return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr; | |
119 | } |
|
134 | } | |
120 |
|
135 | |||
121 | std::vector<std::shared_ptr<Variable> > VariableModel::variables() const |
|
136 | std::vector<std::shared_ptr<Variable> > VariableModel::variables() const | |
122 | { |
|
137 | { | |
123 | return impl->m_Variables; |
|
138 | return impl->m_Variables; | |
124 | } |
|
139 | } | |
125 |
|
140 | |||
126 | void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress) |
|
141 | void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress) | |
127 | { |
|
142 | { | |
128 | if (progress > 0.0) { |
|
143 | if (progress > 0.0) { | |
129 | impl->m_VariableToProgress[variable] = progress; |
|
144 | impl->m_VariableToProgress[variable] = progress; | |
130 | } |
|
145 | } | |
131 | else { |
|
146 | else { | |
132 | impl->m_VariableToProgress.erase(variable); |
|
147 | impl->m_VariableToProgress.erase(variable); | |
133 | } |
|
148 | } | |
134 | auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN); |
|
149 | auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN); | |
135 |
|
150 | |||
136 | emit dataChanged(modelIndex, modelIndex); |
|
151 | emit dataChanged(modelIndex, modelIndex); | |
137 | } |
|
152 | } | |
138 |
|
153 | |||
139 | int VariableModel::columnCount(const QModelIndex &parent) const |
|
154 | int VariableModel::columnCount(const QModelIndex &parent) const | |
140 | { |
|
155 | { | |
141 | Q_UNUSED(parent); |
|
156 | Q_UNUSED(parent); | |
142 |
|
157 | |||
143 | return NB_COLUMNS; |
|
158 | return NB_COLUMNS; | |
144 | } |
|
159 | } | |
145 |
|
160 | |||
146 | int VariableModel::rowCount(const QModelIndex &parent) const |
|
161 | int VariableModel::rowCount(const QModelIndex &parent) const | |
147 | { |
|
162 | { | |
148 | Q_UNUSED(parent); |
|
163 | Q_UNUSED(parent); | |
149 |
|
164 | |||
150 | return impl->m_Variables.size(); |
|
165 | return impl->m_Variables.size(); | |
151 | } |
|
166 | } | |
152 |
|
167 | |||
153 | QVariant VariableModel::data(const QModelIndex &index, int role) const |
|
168 | QVariant VariableModel::data(const QModelIndex &index, int role) const | |
154 | { |
|
169 | { | |
155 | if (!index.isValid()) { |
|
170 | if (!index.isValid()) { | |
156 | return QVariant{}; |
|
171 | return QVariant{}; | |
157 | } |
|
172 | } | |
158 |
|
173 | |||
159 | if (index.row() < 0 || index.row() >= rowCount()) { |
|
174 | if (index.row() < 0 || index.row() >= rowCount()) { | |
160 | return QVariant{}; |
|
175 | return QVariant{}; | |
161 | } |
|
176 | } | |
162 |
|
177 | |||
163 | if (role == Qt::DisplayRole) { |
|
178 | if (role == Qt::DisplayRole) { | |
164 | if (auto variable = impl->m_Variables.at(index.row()).get()) { |
|
179 | if (auto variable = impl->m_Variables.at(index.row()).get()) { | |
165 | switch (index.column()) { |
|
180 | switch (index.column()) { | |
166 | case NAME_COLUMN: |
|
181 | case NAME_COLUMN: | |
167 | return variable->name(); |
|
182 | return variable->name(); | |
168 | case TSTART_COLUMN: { |
|
183 | case TSTART_COLUMN: { | |
169 | auto range = variable->realRange(); |
|
184 | auto range = variable->realRange(); | |
170 | return range != INVALID_RANGE |
|
185 | return range != INVALID_RANGE | |
171 | ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT) |
|
186 | ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT) | |
172 | : QVariant{}; |
|
187 | : QVariant{}; | |
173 | } |
|
188 | } | |
174 | case TEND_COLUMN: { |
|
189 | case TEND_COLUMN: { | |
175 | auto range = variable->realRange(); |
|
190 | auto range = variable->realRange(); | |
176 | return range != INVALID_RANGE |
|
191 | return range != INVALID_RANGE | |
177 | ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT) |
|
192 | ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT) | |
178 | : QVariant{}; |
|
193 | : QVariant{}; | |
179 | } |
|
194 | } | |
180 | case UNIT_COLUMN: |
|
195 | case UNIT_COLUMN: | |
181 | return variable->metadata().value(QStringLiteral("units")); |
|
196 | return variable->metadata().value(QStringLiteral("units")); | |
182 | case MISSION_COLUMN: |
|
197 | case MISSION_COLUMN: | |
183 | return variable->metadata().value(QStringLiteral("mission")); |
|
198 | return variable->metadata().value(QStringLiteral("mission")); | |
184 | case PLUGIN_COLUMN: |
|
199 | case PLUGIN_COLUMN: | |
185 | return variable->metadata().value(QStringLiteral("plugin")); |
|
200 | return variable->metadata().value(QStringLiteral("plugin")); | |
186 | default: |
|
201 | default: | |
187 | // No action |
|
202 | // No action | |
188 | break; |
|
203 | break; | |
189 | } |
|
204 | } | |
190 |
|
205 | |||
191 | qWarning(LOG_VariableModel()) |
|
206 | qWarning(LOG_VariableModel()) | |
192 | << tr("Can't get data (unknown column %1)").arg(index.column()); |
|
207 | << tr("Can't get data (unknown column %1)").arg(index.column()); | |
193 | } |
|
208 | } | |
194 | else { |
|
209 | else { | |
195 | qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)"); |
|
210 | qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)"); | |
196 | } |
|
211 | } | |
197 | } |
|
212 | } | |
198 | else if (role == VariableRoles::ProgressRole) { |
|
213 | else if (role == VariableRoles::ProgressRole) { | |
199 | if (auto variable = impl->m_Variables.at(index.row())) { |
|
214 | if (auto variable = impl->m_Variables.at(index.row())) { | |
200 |
|
215 | |||
201 | auto it = impl->m_VariableToProgress.find(variable); |
|
216 | auto it = impl->m_VariableToProgress.find(variable); | |
202 | if (it != impl->m_VariableToProgress.cend()) { |
|
217 | if (it != impl->m_VariableToProgress.cend()) { | |
203 | return it->second; |
|
218 | return it->second; | |
204 | } |
|
219 | } | |
205 | } |
|
220 | } | |
206 | } |
|
221 | } | |
207 |
|
222 | |||
208 | return QVariant{}; |
|
223 | return QVariant{}; | |
209 | } |
|
224 | } | |
210 |
|
225 | |||
211 | QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const |
|
226 | QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const | |
212 | { |
|
227 | { | |
213 | if (role != Qt::DisplayRole && role != Qt::SizeHintRole) { |
|
228 | if (role != Qt::DisplayRole && role != Qt::SizeHintRole) { | |
214 | return QVariant{}; |
|
229 | return QVariant{}; | |
215 | } |
|
230 | } | |
216 |
|
231 | |||
217 | if (orientation == Qt::Horizontal) { |
|
232 | if (orientation == Qt::Horizontal) { | |
218 | auto propertiesIt = COLUMN_PROPERTIES.find(section); |
|
233 | auto propertiesIt = COLUMN_PROPERTIES.find(section); | |
219 | if (propertiesIt != COLUMN_PROPERTIES.cend()) { |
|
234 | if (propertiesIt != COLUMN_PROPERTIES.cend()) { | |
220 | // Role is either DisplayRole or SizeHintRole |
|
235 | // Role is either DisplayRole or SizeHintRole | |
221 | return (role == Qt::DisplayRole) |
|
236 | return (role == Qt::DisplayRole) | |
222 | ? QVariant{propertiesIt->m_Name} |
|
237 | ? QVariant{propertiesIt->m_Name} | |
223 | : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}}; |
|
238 | : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}}; | |
224 | } |
|
239 | } | |
225 | else { |
|
240 | else { | |
226 | qWarning(LOG_VariableModel()) |
|
241 | qWarning(LOG_VariableModel()) | |
227 | << tr("Can't get header data (unknown column %1)").arg(section); |
|
242 | << tr("Can't get header data (unknown column %1)").arg(section); | |
228 | } |
|
243 | } | |
229 | } |
|
244 | } | |
230 |
|
245 | |||
231 | return QVariant{}; |
|
246 | return QVariant{}; | |
232 | } |
|
247 | } | |
233 |
|
248 | |||
234 | void VariableModel::abortProgress(const QModelIndex &index) |
|
249 | void VariableModel::abortProgress(const QModelIndex &index) | |
235 | { |
|
250 | { | |
236 | if (auto variable = impl->m_Variables.at(index.row())) { |
|
251 | if (auto variable = impl->m_Variables.at(index.row())) { | |
237 | emit abortProgessRequested(variable); |
|
252 | emit abortProgessRequested(variable); | |
238 | } |
|
253 | } | |
239 | } |
|
254 | } | |
240 |
|
255 | |||
241 | void VariableModel::onVariableUpdated() noexcept |
|
256 | void VariableModel::onVariableUpdated() noexcept | |
242 | { |
|
257 | { | |
243 | // Finds variable that has been updated in the model |
|
258 | // Finds variable that has been updated in the model | |
244 | if (auto updatedVariable = dynamic_cast<Variable *>(sender())) { |
|
259 | if (auto updatedVariable = dynamic_cast<Variable *>(sender())) { | |
245 | auto updatedVariableIndex = impl->indexOfVariable(updatedVariable); |
|
260 | auto updatedVariableIndex = impl->indexOfVariable(updatedVariable); | |
246 |
|
261 | |||
247 | if (updatedVariableIndex > -1) { |
|
262 | if (updatedVariableIndex > -1) { | |
248 | emit dataChanged(createIndex(updatedVariableIndex, 0), |
|
263 | emit dataChanged(createIndex(updatedVariableIndex, 0), | |
249 | createIndex(updatedVariableIndex, columnCount() - 1)); |
|
264 | createIndex(updatedVariableIndex, columnCount() - 1)); | |
250 | } |
|
265 | } | |
251 | } |
|
266 | } | |
252 | } |
|
267 | } | |
253 |
|
268 | |||
254 | int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept |
|
269 | int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept | |
255 | { |
|
270 | { | |
256 | auto begin = std::cbegin(m_Variables); |
|
271 | auto begin = std::cbegin(m_Variables); | |
257 | auto end = std::cend(m_Variables); |
|
272 | auto end = std::cend(m_Variables); | |
258 | auto it |
|
273 | auto it | |
259 | = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; }); |
|
274 | = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; }); | |
260 |
|
275 | |||
261 | if (it != end) { |
|
276 | if (it != end) { | |
262 | // Gets the index of the variable in the model: we assume here that views have the same |
|
277 | // Gets the index of the variable in the model: we assume here that views have the same | |
263 | // order as the model |
|
278 | // order as the model | |
264 | return std::distance(begin, it); |
|
279 | return std::distance(begin, it); | |
265 | } |
|
280 | } | |
266 | else { |
|
281 | else { | |
267 | return -1; |
|
282 | return -1; | |
268 | } |
|
283 | } | |
269 | } |
|
284 | } |
@@ -1,18 +1,19 | |||||
1 |
|
1 | |||
2 |
|
2 | |||
3 | tests = [ |
|
3 | tests = [ | |
|
4 | [['Common/TestStringUtils.cpp'],'test_string_utils','StringUtils test'], | |||
4 | [['Data/TestDataSeries.cpp'],'test_data','DataSeries test'], |
|
5 | [['Data/TestDataSeries.cpp'],'test_data','DataSeries test'], | |
5 | [['Data/TestOneDimArrayData.cpp'],'test_1d','One Dim Array test'], |
|
6 | [['Data/TestOneDimArrayData.cpp'],'test_1d','One Dim Array test'], | |
6 | [['Data/TestTwoDimArrayData.cpp'],'test_2d','Two Dim Array test'], |
|
7 | [['Data/TestTwoDimArrayData.cpp'],'test_2d','Two Dim Array test'], | |
7 | [['DataSource/TestDataSourceController.cpp'],'test_data_source','DataSourceController test'], |
|
8 | [['DataSource/TestDataSourceController.cpp'],'test_data_source','DataSourceController test'], | |
8 | [['Variable/TestVariableCacheController.cpp'],'test_variable_cache','VariableCacheController test'], |
|
9 | [['Variable/TestVariableCacheController.cpp'],'test_variable_cache','VariableCacheController test'], | |
9 | [['Variable/TestVariable.cpp'],'test_variable','Variable test'] |
|
10 | [['Variable/TestVariable.cpp'],'test_variable','Variable test'] | |
10 | ] |
|
11 | ] | |
11 |
|
12 | |||
12 | foreach unit_test : tests |
|
13 | foreach unit_test : tests | |
13 | test_moc_files = qt5.preprocess(moc_sources : unit_test[0]) |
|
14 | test_moc_files = qt5.preprocess(moc_sources : unit_test[0]) | |
14 | test_exe = executable(unit_test[1],unit_test[0] , test_moc_files, |
|
15 | test_exe = executable(unit_test[1],unit_test[0] , test_moc_files, | |
15 | dependencies : [sciqlop_core, qt5test]) |
|
16 | dependencies : [sciqlop_core, qt5test]) | |
16 | test(unit_test[2], test_exe, args: ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test[1])]) |
|
17 | test(unit_test[2], test_exe, args: ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test[1])]) | |
17 | endforeach |
|
18 | endforeach | |
18 |
|
19 |
General Comments 0
You need to be logged in to leave comments.
Login now