##// END OF EJS Templates
Merge branch 'feature/VariableColumns' into develop
Alexandre Leroux -
r552:780b372cbdd1 merge
parent child
Show More
@@ -1,96 +1,102
1 1 #ifndef SCIQLOP_DATASOURCEITEM_H
2 2 #define SCIQLOP_DATASOURCEITEM_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Common/spimpl.h>
7 7
8 8 #include <QVariant>
9 9 #include <QVector>
10 10
11 11 class DataSourceItemAction;
12 12
13 13 /**
14 14 * Possible types of an item
15 15 */
16 16 enum class DataSourceItemType { NODE, PRODUCT, COMPONENT };
17 17
18 18 /**
19 19 * @brief The DataSourceItem class aims to represent a structure element of a data source.
20 20 * A data source has a tree structure that is made up of a main DataSourceItem object (root)
21 21 * containing other DataSourceItem objects (children).
22 22 * For each DataSourceItem can be associated a set of data representing it.
23 23 */
24 24 class SCIQLOP_CORE_EXPORT DataSourceItem {
25 25 public:
26 26 /// Key associated with the name of the item
27 27 static const QString NAME_DATA_KEY;
28 28
29 29 explicit DataSourceItem(DataSourceItemType type, const QString &name);
30 30 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
31 31
32 32 /// @return the actions of the item as a vector
33 33 QVector<DataSourceItemAction *> actions() const noexcept;
34 34
35 35 /**
36 36 * Adds an action to the item. The item takes ownership of the action, and the action is
37 37 * automatically associated to the item
38 38 * @param action the action to add
39 39 */
40 40 void addAction(std::unique_ptr<DataSourceItemAction> action) noexcept;
41 41
42 42 /**
43 43 * Adds a child to the item. The item takes ownership of the child.
44 44 * @param child the child to add
45 45 */
46 46 void appendChild(std::unique_ptr<DataSourceItem> child) noexcept;
47 47
48 48 /**
49 49 * Returns the item's child associated to an index
50 50 * @param childIndex the index to search
51 51 * @return a pointer to the child if index is valid, nullptr otherwise
52 52 */
53 53 DataSourceItem *child(int childIndex) const noexcept;
54 54
55 55 int childCount() const noexcept;
56 56
57 57 /**
58 58 * Get the data associated to a key
59 59 * @param key the key to search
60 60 * @return the data found if key is valid, default QVariant otherwise
61 61 */
62 62 QVariant data(const QString &key) const noexcept;
63 63
64 64 /// Gets all data
65 65 QVariantHash data() const noexcept;
66 66
67 67 bool isRoot() const noexcept;
68 68
69 69 QString name() const noexcept;
70 70
71 71 /**
72 72 * Get the item's parent
73 73 * @return a pointer to the parent if it exists, nullptr if the item is a root
74 74 */
75 75 DataSourceItem *parentItem() const noexcept;
76 76
77 77 /**
78 * Gets the item's root
79 * @return the top parent, the item itself if it's the root item
80 */
81 const DataSourceItem &rootItem() const noexcept;
82
83 /**
78 84 * Sets or appends a value to a key
79 85 * @param key the key
80 86 * @param value the value
81 87 * @param append if true, the value is added to the values already existing for the key,
82 88 * otherwise it replaces the existing values
83 89 */
84 90 void setData(const QString &key, const QVariant &value, bool append = false) noexcept;
85 91
86 92 DataSourceItemType type() const noexcept;
87 93
88 94 bool operator==(const DataSourceItem &other);
89 95 bool operator!=(const DataSourceItem &other);
90 96
91 97 private:
92 98 class DataSourceItemPrivate;
93 99 spimpl::unique_impl_ptr<DataSourceItemPrivate> impl;
94 100 };
95 101
96 102 #endif // SCIQLOP_DATASOURCEITEMMODEL_H
@@ -1,120 +1,143
1 1 #include "DataSource/DataSourceController.h"
2 2 #include "DataSource/DataSourceItem.h"
3 3
4 4 #include <Data/IDataProvider.h>
5 5
6 6 #include <QMutex>
7 7 #include <QThread>
8 8
9 9 #include <QDir>
10 10 #include <QStandardPaths>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
13 13
14 namespace {
15
16 /**
17 * Builds the metadata of the variable that will be generated from the loading of an item
18 * @param dataSourceItem the data source item from which to generate the metadata
19 * @return the metadata of the variable
20 */
21 QVariantHash variableMetadata(const DataSourceItem &dataSourceItem)
22 {
23 // Variable metadata contains...
24
25 // ... all metadata of the item
26 auto result = dataSourceItem.data();
27
28 // ... and the name of the plugin, recovered from root item
29 result.insert(QStringLiteral("plugin"), dataSourceItem.rootItem().name());
30
31 return result;
32 }
33
34 } // namespace
35
14 36 class DataSourceController::DataSourceControllerPrivate {
15 37 public:
16 38 QMutex m_WorkingMutex;
17 39 /// Data sources registered
18 40 QHash<QUuid, QString> m_DataSources;
19 41 /// Data sources structures
20 42 std::map<QUuid, std::unique_ptr<DataSourceItem> > m_DataSourceItems;
21 43 /// Data providers registered
22 44 /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and
23 45 /// continue to live without necessarily the data source controller
24 46 std::map<QUuid, std::shared_ptr<IDataProvider> > m_DataProviders;
25 47 };
26 48
27 49 DataSourceController::DataSourceController(QObject *parent)
28 50 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
29 51 {
30 52 qCDebug(LOG_DataSourceController()) << tr("DataSourceController construction")
31 53 << QThread::currentThread();
32 54 }
33 55
34 56 DataSourceController::~DataSourceController()
35 57 {
36 58 qCDebug(LOG_DataSourceController()) << tr("DataSourceController destruction")
37 59 << QThread::currentThread();
38 60 this->waitForFinish();
39 61 }
40 62
41 63 QUuid DataSourceController::registerDataSource(const QString &dataSourceName) noexcept
42 64 {
43 65 auto dataSourceUid = QUuid::createUuid();
44 66 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
45 67
46 68 return dataSourceUid;
47 69 }
48 70
49 71 void DataSourceController::setDataSourceItem(
50 72 const QUuid &dataSourceUid, std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
51 73 {
52 74 if (!dataSourceItem) {
53 75 qCWarning(LOG_DataSourceController())
54 76 << tr("Data source item can't be registered (null item)");
55 77 return;
56 78 }
57 79
58 80 if (impl->m_DataSources.contains(dataSourceUid)) {
59 81 // The data provider is implicitly converted to a shared_ptr
60 82 impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem)));
61 83
62 84 // Retrieves the data source item to emit the signal with it
63 85 auto it = impl->m_DataSourceItems.find(dataSourceUid);
64 86 if (it != impl->m_DataSourceItems.end()) {
65 87 emit dataSourceItemSet(it->second.get());
66 88 }
67 89 }
68 90 else {
69 91 qCWarning(LOG_DataSourceController()) << tr("Can't set data source item for uid %1 : no "
70 92 "data source has been registered with the uid")
71 93 .arg(dataSourceUid.toString());
72 94 }
73 95 }
74 96
75 97 void DataSourceController::setDataProvider(const QUuid &dataSourceUid,
76 98 std::unique_ptr<IDataProvider> dataProvider) noexcept
77 99 {
78 100 if (impl->m_DataSources.contains(dataSourceUid)) {
79 101 impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider)));
80 102 }
81 103 else {
82 104 qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data "
83 105 "source has been registered with the uid")
84 106 .arg(dataSourceUid.toString());
85 107 }
86 108 }
87 109
88 110 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
89 111 const DataSourceItem &productItem) noexcept
90 112 {
91 113 if (productItem.type() == DataSourceItemType::PRODUCT
92 114 || productItem.type() == DataSourceItemType::COMPONENT) {
93 115 /// Retrieves the data provider of the data source (if any)
94 116 auto it = impl->m_DataProviders.find(dataSourceUid);
95 117 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
96 118
97 emit variableCreationRequested(productItem.name(), productItem.data(), dataProvider);
119 emit variableCreationRequested(productItem.name(), variableMetadata(productItem),
120 dataProvider);
98 121 }
99 122 else {
100 123 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
101 124 }
102 125 }
103 126
104 127 void DataSourceController::initialize()
105 128 {
106 129 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init")
107 130 << QThread::currentThread();
108 131 impl->m_WorkingMutex.lock();
109 132 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
110 133 }
111 134
112 135 void DataSourceController::finalize()
113 136 {
114 137 impl->m_WorkingMutex.unlock();
115 138 }
116 139
117 140 void DataSourceController::waitForFinish()
118 141 {
119 142 QMutexLocker locker{&impl->m_WorkingMutex};
120 143 }
@@ -1,140 +1,145
1 1 #include <DataSource/DataSourceItem.h>
2 2 #include <DataSource/DataSourceItemAction.h>
3 3
4 4 #include <QVector>
5 5
6 6 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
7 7
8 8 struct DataSourceItem::DataSourceItemPrivate {
9 9 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
10 10 : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{}
11 11 {
12 12 }
13 13
14 14 DataSourceItem *m_Parent;
15 15 std::vector<std::unique_ptr<DataSourceItem> > m_Children;
16 16 DataSourceItemType m_Type;
17 17 QVariantHash m_Data;
18 18 std::vector<std::unique_ptr<DataSourceItemAction> > m_Actions;
19 19 };
20 20
21 21 DataSourceItem::DataSourceItem(DataSourceItemType type, const QString &name)
22 22 : DataSourceItem{type, QVariantHash{{NAME_DATA_KEY, name}}}
23 23 {
24 24 }
25 25
26 26 DataSourceItem::DataSourceItem(DataSourceItemType type, QVariantHash data)
27 27 : impl{spimpl::make_unique_impl<DataSourceItemPrivate>(type, std::move(data))}
28 28 {
29 29 }
30 30
31 31 QVector<DataSourceItemAction *> DataSourceItem::actions() const noexcept
32 32 {
33 33 auto result = QVector<DataSourceItemAction *>{};
34 34
35 35 std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions),
36 36 std::back_inserter(result), [](const auto &action) { return action.get(); });
37 37
38 38 return result;
39 39 }
40 40
41 41 void DataSourceItem::addAction(std::unique_ptr<DataSourceItemAction> action) noexcept
42 42 {
43 43 action->setDataSourceItem(this);
44 44 impl->m_Actions.push_back(std::move(action));
45 45 }
46 46
47 47 void DataSourceItem::appendChild(std::unique_ptr<DataSourceItem> child) noexcept
48 48 {
49 49 child->impl->m_Parent = this;
50 50 impl->m_Children.push_back(std::move(child));
51 51 }
52 52
53 53 DataSourceItem *DataSourceItem::child(int childIndex) const noexcept
54 54 {
55 55 if (childIndex < 0 || childIndex >= childCount()) {
56 56 return nullptr;
57 57 }
58 58 else {
59 59 return impl->m_Children.at(childIndex).get();
60 60 }
61 61 }
62 62
63 63 int DataSourceItem::childCount() const noexcept
64 64 {
65 65 return impl->m_Children.size();
66 66 }
67 67
68 68 QVariant DataSourceItem::data(const QString &key) const noexcept
69 69 {
70 70 return impl->m_Data.value(key);
71 71 }
72 72
73 73 QVariantHash DataSourceItem::data() const noexcept
74 74 {
75 75 return impl->m_Data;
76 76 }
77 77
78 78 bool DataSourceItem::isRoot() const noexcept
79 79 {
80 80 return impl->m_Parent == nullptr;
81 81 }
82 82
83 83 QString DataSourceItem::name() const noexcept
84 84 {
85 85 return data(NAME_DATA_KEY).toString();
86 86 }
87 87
88 88 DataSourceItem *DataSourceItem::parentItem() const noexcept
89 89 {
90 90 return impl->m_Parent;
91 91 }
92 92
93 const DataSourceItem &DataSourceItem::rootItem() const noexcept
94 {
95 return isRoot() ? *this : parentItem()->rootItem();
96 }
97
93 98 void DataSourceItem::setData(const QString &key, const QVariant &value, bool append) noexcept
94 99 {
95 100 auto it = impl->m_Data.constFind(key);
96 101 if (append && it != impl->m_Data.constEnd()) {
97 102 // Case of an existing value to which we want to add to the new value
98 103 if (it->canConvert<QVariantList>()) {
99 104 auto variantList = it->value<QVariantList>();
100 105 variantList.append(value);
101 106
102 107 impl->m_Data.insert(key, variantList);
103 108 }
104 109 else {
105 110 impl->m_Data.insert(key, QVariantList{*it, value});
106 111 }
107 112 }
108 113 else {
109 114 // Other cases :
110 115 // - new value in map OR
111 116 // - replacement of an existing value (not appending)
112 117 impl->m_Data.insert(key, value);
113 118 }
114 119 }
115 120
116 121 DataSourceItemType DataSourceItem::type() const noexcept
117 122 {
118 123 return impl->m_Type;
119 124 }
120 125
121 126 bool DataSourceItem::operator==(const DataSourceItem &other)
122 127 {
123 128 // Compares items' attributes
124 129 if (std::tie(impl->m_Type, impl->m_Data) == std::tie(other.impl->m_Type, other.impl->m_Data)) {
125 130 // Compares contents of items' children
126 131 return std::equal(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
127 132 std::cbegin(other.impl->m_Children),
128 133 [](const auto &itemChild, const auto &otherChild) {
129 134 return *itemChild == *otherChild;
130 135 });
131 136 }
132 137 else {
133 138 return false;
134 139 }
135 140 }
136 141
137 142 bool DataSourceItem::operator!=(const DataSourceItem &other)
138 143 {
139 144 return !(*this == other);
140 145 }
@@ -1,249 +1,258
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableModel.h>
3 3
4 4 #include <Common/DateUtils.h>
5 5
6 6 #include <Data/IDataSeries.h>
7 7
8 8 #include <QSize>
9 9 #include <unordered_map>
10 10
11 11 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
12 12
13 13 namespace {
14 14
15 15 // Column indexes
16 16 const auto NAME_COLUMN = 0;
17 17 const auto TSTART_COLUMN = 1;
18 18 const auto TEND_COLUMN = 2;
19 const auto NB_COLUMNS = 3;
19 const auto UNIT_COLUMN = 3;
20 const auto MISSION_COLUMN = 4;
21 const auto PLUGIN_COLUMN = 5;
22 const auto NB_COLUMNS = 6;
20 23
21 24 // Column properties
22 25 const auto DEFAULT_HEIGHT = 25;
23 26 const auto DEFAULT_WIDTH = 100;
24 27
25 28 struct ColumnProperties {
26 29 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
27 30 int height = DEFAULT_HEIGHT)
28 31 : m_Name{name}, m_Width{width}, m_Height{height}
29 32 {
30 33 }
31 34
32 35 QString m_Name;
33 36 int m_Width;
34 37 int m_Height;
35 38 };
36 39
37 const auto COLUMN_PROPERTIES
38 = QHash<int, ColumnProperties>{{NAME_COLUMN, {QObject::tr("Name")}},
39 {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
40 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}};
40 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
41 {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
42 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {UNIT_COLUMN, {QObject::tr("Unit")}},
43 {MISSION_COLUMN, {QObject::tr("Mission")}}, {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
41 44
42 45 /// Format for datetimes
43 46 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
44 47
45 48
46 49 } // namespace
47 50
48 51 struct VariableModel::VariableModelPrivate {
49 52 /// Variables created in SciQlop
50 53 std::vector<std::shared_ptr<Variable> > m_Variables;
51 54 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
52 55
53 56 /// Return the row index of the variable. -1 if it's not found
54 57 int indexOfVariable(Variable *variable) const noexcept;
55 58 };
56 59
57 60 VariableModel::VariableModel(QObject *parent)
58 61 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
59 62 {
60 63 }
61 64
62 65 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
63 66 const SqpRange &dateTime,
64 67 const QVariantHash &metadata) noexcept
65 68 {
66 69 auto insertIndex = rowCount();
67 70 beginInsertRows({}, insertIndex, insertIndex);
68 71
69 72 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
70 73
71 74 impl->m_Variables.push_back(variable);
72 75 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
73 76
74 77 endInsertRows();
75 78
76 79 return variable;
77 80 }
78 81
79 82 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
80 83 {
81 84 if (!variable) {
82 85 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
83 86 return;
84 87 }
85 88
86 89 // Finds variable in the model
87 90 auto begin = impl->m_Variables.cbegin();
88 91 auto end = impl->m_Variables.cend();
89 92 auto it = std::find(begin, end, variable);
90 93 if (it != end) {
91 94 auto removeIndex = std::distance(begin, it);
92 95
93 96 // Deletes variable
94 97 beginRemoveRows({}, removeIndex, removeIndex);
95 98 impl->m_Variables.erase(it);
96 99 endRemoveRows();
97 100 }
98 101 else {
99 102 qCritical(LOG_VariableModel())
100 103 << tr("Can't delete variable %1 from the model: the variable is not in the model")
101 104 .arg(variable->name());
102 105 }
103 106
104 107 // Removes variable from progress map
105 108 impl->m_VariableToProgress.erase(variable);
106 109 }
107 110
108 111
109 112 std::shared_ptr<Variable> VariableModel::variable(int index) const
110 113 {
111 114 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
112 115 }
113 116
114 117 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
115 118 {
116 119 if (progress > 0.0) {
117 120 impl->m_VariableToProgress[variable] = progress;
118 121 }
119 122 else {
120 123 impl->m_VariableToProgress.erase(variable);
121 124 }
122 125 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
123 126
124 127 emit dataChanged(modelIndex, modelIndex);
125 128 }
126 129
127 130 int VariableModel::columnCount(const QModelIndex &parent) const
128 131 {
129 132 Q_UNUSED(parent);
130 133
131 134 return NB_COLUMNS;
132 135 }
133 136
134 137 int VariableModel::rowCount(const QModelIndex &parent) const
135 138 {
136 139 Q_UNUSED(parent);
137 140
138 141 return impl->m_Variables.size();
139 142 }
140 143
141 144 QVariant VariableModel::data(const QModelIndex &index, int role) const
142 145 {
143 146 if (!index.isValid()) {
144 147 return QVariant{};
145 148 }
146 149
147 150 if (index.row() < 0 || index.row() >= rowCount()) {
148 151 return QVariant{};
149 152 }
150 153
151 154 if (role == Qt::DisplayRole) {
152 155 if (auto variable = impl->m_Variables.at(index.row()).get()) {
153 156 /// Lambda function that builds the variant to return for a time value
154 157 auto dateTimeVariant = [](double secs) {
155 158 auto dateTime = DateUtils::dateTime(secs);
156 159 return dateTime.toString(DATETIME_FORMAT);
157 160 };
158 161
159 162 switch (index.column()) {
160 163 case NAME_COLUMN:
161 164 return variable->name();
162 165 case TSTART_COLUMN:
163 166 return dateTimeVariant(variable->range().m_TStart);
164 167 case TEND_COLUMN:
165 168 return dateTimeVariant(variable->range().m_TEnd);
169 case UNIT_COLUMN:
170 return variable->metadata().value(QStringLiteral("units"));
171 case MISSION_COLUMN:
172 return variable->metadata().value(QStringLiteral("mission"));
173 case PLUGIN_COLUMN:
174 return variable->metadata().value(QStringLiteral("plugin"));
166 175 default:
167 176 // No action
168 177 break;
169 178 }
170 179
171 180 qWarning(LOG_VariableModel())
172 181 << tr("Can't get data (unknown column %1)").arg(index.column());
173 182 }
174 183 else {
175 184 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
176 185 }
177 186 }
178 187 else if (role == VariableRoles::ProgressRole) {
179 188 if (auto variable = impl->m_Variables.at(index.row())) {
180 189
181 190 auto it = impl->m_VariableToProgress.find(variable);
182 191 if (it != impl->m_VariableToProgress.cend()) {
183 192 return it->second;
184 193 }
185 194 }
186 195 }
187 196
188 197 return QVariant{};
189 198 }
190 199
191 200 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
192 201 {
193 202 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
194 203 return QVariant{};
195 204 }
196 205
197 206 if (orientation == Qt::Horizontal) {
198 207 auto propertiesIt = COLUMN_PROPERTIES.find(section);
199 208 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
200 209 // Role is either DisplayRole or SizeHintRole
201 210 return (role == Qt::DisplayRole)
202 211 ? QVariant{propertiesIt->m_Name}
203 212 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
204 213 }
205 214 else {
206 215 qWarning(LOG_VariableModel())
207 216 << tr("Can't get header data (unknown column %1)").arg(section);
208 217 }
209 218 }
210 219
211 220 return QVariant{};
212 221 }
213 222
214 223 void VariableModel::abortProgress(const QModelIndex &index)
215 224 {
216 225 if (auto variable = impl->m_Variables.at(index.row())) {
217 226 emit abortProgessRequested(variable);
218 227 }
219 228 }
220 229
221 230 void VariableModel::onVariableUpdated() noexcept
222 231 {
223 232 // Finds variable that has been updated in the model
224 233 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
225 234 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
226 235
227 236 if (updatedVariableIndex > -1) {
228 237 emit dataChanged(createIndex(updatedVariableIndex, 0),
229 238 createIndex(updatedVariableIndex, columnCount() - 1));
230 239 }
231 240 }
232 241 }
233 242
234 243 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
235 244 {
236 245 auto begin = std::cbegin(m_Variables);
237 246 auto end = std::cend(m_Variables);
238 247 auto it
239 248 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
240 249
241 250 if (it != end) {
242 251 // Gets the index of the variable in the model: we assume here that views have the same
243 252 // order as the model
244 253 return std::distance(begin, it);
245 254 }
246 255 else {
247 256 return -1;
248 257 }
249 258 }
General Comments 0
You need to be logged in to leave comments. Login now