forked from quickshell/quickshell
core/scriptmodel: add objectProp, allowing js objects to be compared
This commit is contained in:
parent
61f00a0442
commit
2e905f6447
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 iter = this->mValues.begin();
|
||||||
auto newIter = newValues.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) {
|
while (true) {
|
||||||
if (newIter == newValues.end()) {
|
if (newIter == newValues.end()) {
|
||||||
if (iter == this->mValues.end()) break;
|
if (iter == this->mValues.end()) break;
|
||||||
|
@ -40,18 +61,19 @@ void ScriptModel::updateValuesUnique(const QVariantList& newValues) {
|
||||||
this->endInsertRows();
|
this->endInsertRows();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
} else if (*newIter != *iter) {
|
} else if (!variantCmp(*newIter, *iter)) {
|
||||||
auto oldIter = std::find(iter, this->mValues.end(), *newIter);
|
auto oldIter = std::find_if(iter, this->mValues.end(), eqPredicate(*newIter));
|
||||||
|
|
||||||
if (oldIter != this->mValues.end()) {
|
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.
|
// Remove any entries we would otherwise move around that aren't in the new list.
|
||||||
auto startIter = iter;
|
auto startIter = iter;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
++iter;
|
++iter;
|
||||||
} while (iter != this->mValues.end()
|
} 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 index = static_cast<qint32>(std::distance(this->mValues.begin(), iter));
|
||||||
auto startIndex = static_cast<qint32>(std::distance(this->mValues.begin(), startIter));
|
auto startIndex = static_cast<qint32>(std::distance(this->mValues.begin(), startIter));
|
||||||
|
@ -66,7 +88,7 @@ void ScriptModel::updateValuesUnique(const QVariantList& newValues) {
|
||||||
++oldIter;
|
++oldIter;
|
||||||
++newIter;
|
++newIter;
|
||||||
} while (oldIter != this->mValues.end() && newIter != newValues.end()
|
} 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 index = static_cast<qint32>(std::distance(this->mValues.begin(), iter));
|
||||||
auto oldStartIndex =
|
auto oldStartIndex =
|
||||||
|
@ -90,7 +112,8 @@ void ScriptModel::updateValuesUnique(const QVariantList& newValues) {
|
||||||
do {
|
do {
|
||||||
newIter++;
|
newIter++;
|
||||||
} while (newIter != newValues.end()
|
} 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 index = static_cast<qint32>(std::distance(this->mValues.begin(), iter));
|
||||||
auto newIndex = static_cast<qint32>(std::distance(newValues.begin(), newIter));
|
auto newIndex = static_cast<qint32>(std::distance(newValues.begin(), newIter));
|
||||||
|
@ -123,6 +146,13 @@ void ScriptModel::setValues(const QVariantList& newValues) {
|
||||||
emit this->valuesChanged();
|
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 {
|
qint32 ScriptModel::rowCount(const QModelIndex& parent) const {
|
||||||
if (parent != QModelIndex()) return 0;
|
if (parent != QModelIndex()) return 0;
|
||||||
return static_cast<qint32>(this->mValues.length());
|
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);
|
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;
|
QML_ELEMENT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -79,15 +86,20 @@ public:
|
||||||
|
|
||||||
void setValues(const QVariantList& newValues);
|
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]] qint32 rowCount(const QModelIndex& parent) const override;
|
||||||
[[nodiscard]] QVariant data(const QModelIndex& index, qint32 role) const override;
|
[[nodiscard]] QVariant data(const QModelIndex& index, qint32 role) const override;
|
||||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void valuesChanged();
|
void valuesChanged();
|
||||||
|
void objectPropChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVariantList mValues;
|
QVariantList mValues;
|
||||||
|
QString cmpKey;
|
||||||
bool hasActiveIterators = false;
|
bool hasActiveIterators = false;
|
||||||
|
|
||||||
void updateValuesUnique(const QVariantList& newValues);
|
void updateValuesUnique(const QVariantList& newValues);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue