chore(ModelEntry): Emit itemChanged event when the ModelEntry points to another model item
+ emit row changed after data is avaialble to squash - modelEntry
This commit is contained in:
parent
357ba99495
commit
73bcacbfc0
|
@ -1,6 +1,8 @@
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
|
import QtQuick.Window 2.15
|
||||||
|
import QtQml.Models 2.15
|
||||||
|
|
||||||
import StatusQ 0.1
|
import StatusQ 0.1
|
||||||
import StatusQ.Core.Utils 0.1
|
import StatusQ.Core.Utils 0.1
|
||||||
|
@ -20,6 +22,32 @@ Control {
|
||||||
sourceModel: usersModel
|
sourceModel: usersModel
|
||||||
key: "pubKey"
|
key: "pubKey"
|
||||||
value: pubKeySelector.currentText
|
value: pubKeySelector.currentText
|
||||||
|
|
||||||
|
onItemChanged: signalsModel.append({ signal: "Item changed", value: "", row: itemData.row, item: itemData.item, roles: JSON.stringify(itemData.roles), available: itemData.available})
|
||||||
|
onRowChanged: signalsModel.append({ signal: "Row changed", value: "", row: itemData.row, item: itemData.item, roles: JSON.stringify(itemData.roles), available: itemData.available})
|
||||||
|
onAvailableChanged: signalsModel.append({ signal: "Available changed",value: "", row: itemData.row, item: itemData.item, roles: JSON.stringify(itemData.roles), available: itemData.available})
|
||||||
|
onRolesChanged: signalsModel.append({ signal: "Roles changed", value: "", row: itemData.row, item: itemData.item, roles: JSON.stringify(itemData.roles), available: itemData.available})
|
||||||
|
}
|
||||||
|
|
||||||
|
Instantiator {
|
||||||
|
model: itemData.roles
|
||||||
|
delegate: QtObject {
|
||||||
|
property var connection: {
|
||||||
|
return Qt.createQmlObject(`
|
||||||
|
import QtQml 2.15
|
||||||
|
Connections {
|
||||||
|
target: itemData.item
|
||||||
|
function on${modelData.charAt(0).toUpperCase() + modelData.slice(1)}Changed() {
|
||||||
|
signalsModel.append({ signal: "${modelData} changed", value: itemData.item.${modelData}, row: itemData.row, item: itemData.item, roles: JSON.stringify(itemData.roles), available: itemData.available})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, this, "dynamicConnectionOn${modelData}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: signalsModel
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
|
@ -97,9 +125,28 @@ Control {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GenericListView {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
visible: showSignals.checked && !!count
|
||||||
|
model: signalsModel
|
||||||
|
header: Label {
|
||||||
|
width: parent.width
|
||||||
|
text: "Item Signals"
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: 16
|
||||||
|
bottomPadding: 20
|
||||||
|
Button {
|
||||||
|
anchors.right: parent.right
|
||||||
|
text: "clear"
|
||||||
|
onClicked: signalsModel.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Pane {
|
Pane {
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
ComboBox {
|
ComboBox {
|
||||||
|
Layout.preferredWidth: 250
|
||||||
id: pubKeySelector
|
id: pubKeySelector
|
||||||
model: [...ModelUtils.modelToFlatArray(usersModel, "pubKey"), "none"]
|
model: [...ModelUtils.modelToFlatArray(usersModel, "pubKey"), "none"]
|
||||||
}
|
}
|
||||||
|
@ -110,6 +157,10 @@ Control {
|
||||||
itemData.cacheOnRemoval = checked
|
itemData.cacheOnRemoval = checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CheckBox {
|
||||||
|
id: showSignals
|
||||||
|
text: "Show signals"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QQmlPropertyMap>
|
#include <QQmlPropertyMap>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
class ModelEntry : public QObject
|
class ModelEntry : public QObject
|
||||||
{
|
{
|
||||||
|
@ -60,6 +61,8 @@ protected:
|
||||||
void tryItemResetOrUpdate();
|
void tryItemResetOrUpdate();
|
||||||
void resetItem();
|
void resetItem();
|
||||||
void updateItem(const QList<int>& roles = {});
|
void updateItem(const QList<int>& roles = {});
|
||||||
|
QStringList fillItem(const QList<int>& roles = {});
|
||||||
|
void notifyItemChanges(const QStringList& roles);
|
||||||
|
|
||||||
QModelIndex findIndexInRange(int start, int end, const QList<int>& roles = {}) const;
|
QModelIndex findIndexInRange(int start, int end, const QList<int>& roles = {}) const;
|
||||||
bool itemHasCorrectRoles() const;
|
bool itemHasCorrectRoles() const;
|
||||||
|
|
|
@ -105,7 +105,7 @@ void ModelEntry::setSourceModel(QAbstractItemModel* sourceModel)
|
||||||
setRow(-1);
|
setRow(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
setAvailable(false);
|
||||||
setIndex({});
|
setIndex({});
|
||||||
});
|
});
|
||||||
connect(m_sourceModel,
|
connect(m_sourceModel,
|
||||||
|
@ -168,8 +168,8 @@ void ModelEntry::setIndex(const QModelIndex& index)
|
||||||
|
|
||||||
m_index = index;
|
m_index = index;
|
||||||
|
|
||||||
tryItemResetOrUpdate();
|
setRow(m_index.row());
|
||||||
setRow(m_index.row());
|
tryItemResetOrUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelEntry::setAvailable(bool available)
|
void ModelEntry::setAvailable(bool available)
|
||||||
|
@ -265,7 +265,7 @@ void ModelEntry::resetItem()
|
||||||
|
|
||||||
m_item.reset(new QQmlPropertyMap());
|
m_item.reset(new QQmlPropertyMap());
|
||||||
|
|
||||||
updateItem();
|
fillItem();
|
||||||
|
|
||||||
if(!m_index.isValid())
|
if(!m_index.isValid())
|
||||||
{
|
{
|
||||||
|
@ -283,8 +283,17 @@ void ModelEntry::resetItem()
|
||||||
|
|
||||||
void ModelEntry::updateItem(const QList<int>& roles /*{}*/)
|
void ModelEntry::updateItem(const QList<int>& roles /*{}*/)
|
||||||
{
|
{
|
||||||
if(!m_index.isValid() || !m_sourceModel) return;
|
const auto updatedRoles = fillItem(roles);
|
||||||
|
notifyItemChanges(updatedRoles);
|
||||||
|
|
||||||
|
setItemRemovedFromModel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList ModelEntry::fillItem(const QList<int>& roles /*{}*/)
|
||||||
|
{
|
||||||
|
if(!m_index.isValid() || !m_sourceModel) return {};
|
||||||
|
|
||||||
|
QStringList filledRoles;
|
||||||
const auto& rolesRef = roles.isEmpty() ? m_sourceModel->roleNames().keys() : roles;
|
const auto& rolesRef = roles.isEmpty() ? m_sourceModel->roleNames().keys() : roles;
|
||||||
|
|
||||||
for(auto role : rolesRef)
|
for(auto role : rolesRef)
|
||||||
|
@ -294,10 +303,26 @@ void ModelEntry::updateItem(const QList<int>& roles /*{}*/)
|
||||||
|
|
||||||
if(roleValue == m_item->value(roleName)) continue;
|
if(roleValue == m_item->value(roleName)) continue;
|
||||||
|
|
||||||
|
filledRoles.append(roleName);
|
||||||
m_item->insert(roleName, roleValue);
|
m_item->insert(roleName, roleValue);
|
||||||
emit m_item->valueChanged(roleName, roleValue);
|
|
||||||
}
|
}
|
||||||
setItemRemovedFromModel(false);
|
|
||||||
|
return filledRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelEntry::notifyItemChanges(const QStringList& roles)
|
||||||
|
{
|
||||||
|
if (roles.contains(m_key))
|
||||||
|
{
|
||||||
|
emit itemChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto role : roles)
|
||||||
|
{
|
||||||
|
auto value = m_item->value(role);
|
||||||
|
emit m_item->valueChanged(role, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelEntry::itemHasCorrectRoles() const
|
bool ModelEntry::itemHasCorrectRoles() const
|
||||||
|
|
|
@ -1215,7 +1215,7 @@ private slots:
|
||||||
QCOMPARE(sourceModelChangedSpy.count(), 1);
|
QCOMPARE(sourceModelChangedSpy.count(), 1);
|
||||||
QCOMPARE(keyChangedSpy.count(), 1);
|
QCOMPARE(keyChangedSpy.count(), 1);
|
||||||
QCOMPARE(valueChangedSpy.count(), 2);
|
QCOMPARE(valueChangedSpy.count(), 2);
|
||||||
QCOMPARE(itemChangedSpy.count(), 1);
|
QCOMPARE(itemChangedSpy.count(), 2);
|
||||||
QCOMPARE(availableChangedSpy.count(), 1);
|
QCOMPARE(availableChangedSpy.count(), 1);
|
||||||
QCOMPARE(rolesChangedSpy.count(), 1);
|
QCOMPARE(rolesChangedSpy.count(), 1);
|
||||||
QCOMPARE(testObject->row(), 0);
|
QCOMPARE(testObject->row(), 0);
|
||||||
|
@ -1444,6 +1444,10 @@ private slots:
|
||||||
QCOMPARE(testObject->item()->isEmpty(), false);
|
QCOMPARE(testObject->item()->isEmpty(), false);
|
||||||
QCOMPARE(testObject->roles().size(), 2);
|
QCOMPARE(testObject->roles().size(), 2);
|
||||||
QVERIFY(testObject->item()->value("key") != QVariant{});
|
QVERIFY(testObject->item()->value("key") != QVariant{});
|
||||||
|
if(testObject->available())
|
||||||
|
QCOMPARE(testObject->row(), 0);
|
||||||
|
else
|
||||||
|
QCOMPARE(testObject->row(), -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto itemChangedConnection = connect(testObject, &ModelEntry::itemChanged, this, [this]() {
|
auto itemChangedConnection = connect(testObject, &ModelEntry::itemChanged, this, [this]() {
|
||||||
|
@ -1497,6 +1501,47 @@ private slots:
|
||||||
QCOMPARE(testObject->item()->value("color"), {});
|
QCOMPARE(testObject->item()->value("color"), {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void itemSignalsTest()
|
||||||
|
{
|
||||||
|
// Testing the signals of the item object
|
||||||
|
// Expected:
|
||||||
|
// 1. changes in model role values produce valueChanged signals only for the roles that changed
|
||||||
|
// 2. changes in the model role used for filtering should produce itemChanged signals and no valueChanged signals
|
||||||
|
|
||||||
|
QQmlEngine engine;
|
||||||
|
ListModelWrapper sourceModel(
|
||||||
|
engine, QJsonArray{QJsonObject{{"key", 1}, {"color", "red"}, {"size", "small"}}, QJsonObject{{"key", 2}, {"color", "blue"}, {"size", "medium"}}});
|
||||||
|
|
||||||
|
QSignalSpy itemChangedSpy(testObject, &ModelEntry::itemChanged);
|
||||||
|
|
||||||
|
// setting the initial source model
|
||||||
|
QCOMPARE(sourceModelProperty.write(testObject, QVariant::fromValue<QAbstractItemModel*>(sourceModel.model())),
|
||||||
|
true);
|
||||||
|
// setting the filter
|
||||||
|
QCOMPARE(keyProperty.write(testObject, "key"), true);
|
||||||
|
QCOMPARE(valueProperty.write(testObject, 1), true);
|
||||||
|
|
||||||
|
QCOMPARE(itemChangedSpy.count(), 1);
|
||||||
|
|
||||||
|
QSignalSpy valueChangedSpy(testObject->item(), &QQmlPropertyMap::valueChanged);
|
||||||
|
|
||||||
|
// change the value of the item
|
||||||
|
sourceModel.setProperty(0, "color", "yellow");
|
||||||
|
QCOMPARE(valueChangedSpy.count(), 1);
|
||||||
|
QCOMPARE(valueChangedSpy.at(0).at(0).toString(), "color");
|
||||||
|
QCOMPARE(valueChangedSpy.at(0).at(1).toString(), "yellow");
|
||||||
|
|
||||||
|
sourceModel.setProperty(0, "size", "large");
|
||||||
|
QCOMPARE(valueChangedSpy.count(), 2);
|
||||||
|
QCOMPARE(valueChangedSpy.at(1).at(0).toString(), "size");
|
||||||
|
QCOMPARE(valueChangedSpy.at(1).at(1).toString(), "large");
|
||||||
|
|
||||||
|
// change the filter to the second item
|
||||||
|
QCOMPARE(valueProperty.write(testObject, 2), true);
|
||||||
|
QCOMPARE(itemChangedSpy.count(), 2);
|
||||||
|
QCOMPARE(valueChangedSpy.count(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
void itemObjectCleanupTest()
|
void itemObjectCleanupTest()
|
||||||
{
|
{
|
||||||
TestModel sourceModel1({{"key", {1, 2, 3}}, {"color", {"red", "blue", "green"}}});
|
TestModel sourceModel1({{"key", {1, 2, 3}}, {"color", {"red", "blue", "green"}}});
|
||||||
|
|
Loading…
Reference in New Issue