core/scriptmodel: add objectProp, allowing js objects to be compared

This commit is contained in:
outfoxxed 2025-05-16 00:11:09 -07:00
parent 34c0b4ca53
commit eb391e35fe
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
2 changed files with 48 additions and 6 deletions

View file

@ -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());

View file

@ -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);