core/scriptmodel: add objectProp, allowing js objects to be compared
This commit is contained in:
parent
34c0b4ca53
commit
eb391e35fe
2 changed files with 48 additions and 6 deletions
|
@ -18,6 +18,27 @@ void ScriptModel::updateValuesUnique(const QVariantList& newValues) {
|
|||
auto iter = this->mValues.begin();
|
||||
auto newIter = newValues.begin();
|
||||
|
||||
// TODO: cache this
|
||||
auto getCmpKey = [&](const QVariant& v) {
|
||||
if (v.canConvert<QVariantMap>()) {
|
||||
auto vMap = v.value<QVariantMap>();
|
||||
if (vMap.contains(this->cmpKey)) {
|
||||
return vMap.value(this->cmpKey);
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
};
|
||||
|
||||
auto variantCmp = [&](const QVariant& a, const QVariant& b) {
|
||||
if (!this->cmpKey.isEmpty()) return getCmpKey(a) == getCmpKey(b);
|
||||
else return a == b;
|
||||
};
|
||||
|
||||
auto eqPredicate = [&](const QVariant& b) {
|
||||
return [&](const QVariant& a) { return variantCmp(a, b); };
|
||||
};
|
||||
|
||||
while (true) {
|
||||
if (newIter == newValues.end()) {
|
||||
if (iter == this->mValues.end()) break;
|
||||
|
@ -40,18 +61,19 @@ void ScriptModel::updateValuesUnique(const QVariantList& newValues) {
|
|||
this->endInsertRows();
|
||||
|
||||
break;
|
||||
} else if (*newIter != *iter) {
|
||||
auto oldIter = std::find(iter, this->mValues.end(), *newIter);
|
||||
} else if (!variantCmp(*newIter, *iter)) {
|
||||
auto oldIter = std::find_if(iter, this->mValues.end(), eqPredicate(*newIter));
|
||||
|
||||
if (oldIter != this->mValues.end()) {
|
||||
if (std::find(newIter, newValues.end(), *iter) == newValues.end()) {
|
||||
if (std::find_if(newIter, newValues.end(), eqPredicate(*iter)) == newValues.end()) {
|
||||
// Remove any entries we would otherwise move around that aren't in the new list.
|
||||
auto startIter = iter;
|
||||
|
||||
do {
|
||||
++iter;
|
||||
} while (iter != this->mValues.end()
|
||||
&& std::find(newIter, newValues.end(), *iter) == newValues.end());
|
||||
&& std::find_if(newIter, newValues.end(), eqPredicate(*iter)) == newValues.end()
|
||||
);
|
||||
|
||||
auto index = static_cast<qint32>(std::distance(this->mValues.begin(), iter));
|
||||
auto startIndex = static_cast<qint32>(std::distance(this->mValues.begin(), startIter));
|
||||
|
@ -66,7 +88,7 @@ void ScriptModel::updateValuesUnique(const QVariantList& newValues) {
|
|||
++oldIter;
|
||||
++newIter;
|
||||
} while (oldIter != this->mValues.end() && newIter != newValues.end()
|
||||
&& *oldIter == *newIter);
|
||||
&& variantCmp(*oldIter, *newIter));
|
||||
|
||||
auto index = static_cast<qint32>(std::distance(this->mValues.begin(), iter));
|
||||
auto oldStartIndex =
|
||||
|
@ -90,7 +112,8 @@ void ScriptModel::updateValuesUnique(const QVariantList& newValues) {
|
|||
do {
|
||||
newIter++;
|
||||
} while (newIter != newValues.end()
|
||||
&& std::find(iter, this->mValues.end(), *newIter) == this->mValues.end());
|
||||
&& std::find_if(iter, this->mValues.end(), eqPredicate(*newIter))
|
||||
== this->mValues.end());
|
||||
|
||||
auto index = static_cast<qint32>(std::distance(this->mValues.begin(), iter));
|
||||
auto newIndex = static_cast<qint32>(std::distance(newValues.begin(), newIter));
|
||||
|
@ -123,6 +146,13 @@ void ScriptModel::setValues(const QVariantList& newValues) {
|
|||
emit this->valuesChanged();
|
||||
}
|
||||
|
||||
void ScriptModel::setObjectProp(const QString& objectProp) {
|
||||
if (objectProp == this->cmpKey) return;
|
||||
this->cmpKey = objectProp;
|
||||
this->updateValuesUnique(this->mValues);
|
||||
emit this->objectPropChanged();
|
||||
}
|
||||
|
||||
qint32 ScriptModel::rowCount(const QModelIndex& parent) const {
|
||||
if (parent != QModelIndex()) return 0;
|
||||
return static_cast<qint32>(this->mValues.length());
|
||||
|
|
|
@ -67,6 +67,13 @@ class ScriptModel: public QAbstractListModel {
|
|||
/// > }
|
||||
/// > ```
|
||||
Q_PROPERTY(QVariantList values READ values WRITE setValues NOTIFY valuesChanged);
|
||||
/// The property that javascript objects passed into the model will be compared with.
|
||||
///
|
||||
/// For example, if `objectProp` is `"myprop"` then `{ myprop: "a", other: "y" }` and
|
||||
/// `{ myprop: "a", other: "z" }` will be considered equal.
|
||||
///
|
||||
/// Defaults to `""`, meaning no key.
|
||||
Q_PROPERTY(QString objectProp READ objectProp WRITE setObjectProp NOTIFY objectPropChanged);
|
||||
QML_ELEMENT;
|
||||
|
||||
public:
|
||||
|
@ -79,15 +86,20 @@ public:
|
|||
|
||||
void setValues(const QVariantList& newValues);
|
||||
|
||||
[[nodiscard]] QString objectProp() const { return this->cmpKey; }
|
||||
void setObjectProp(const QString& objectProp);
|
||||
|
||||
[[nodiscard]] qint32 rowCount(const QModelIndex& parent) const override;
|
||||
[[nodiscard]] QVariant data(const QModelIndex& index, qint32 role) const override;
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
signals:
|
||||
void valuesChanged();
|
||||
void objectPropChanged();
|
||||
|
||||
private:
|
||||
QVariantList mValues;
|
||||
QString cmpKey;
|
||||
bool hasActiveIterators = false;
|
||||
|
||||
void updateValuesUnique(const QVariantList& newValues);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue