Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve handling of QTBUG-57971 (ListModel initializing roles on first insertion) #5

Merged
merged 1 commit into from
Sep 16, 2024

Conversation

micieslak
Copy link
Member

Description

So far the provided workaround was missing some corner cases when there is more than one SFPM (or other proxies) in a chain, providing some custom roles like proxy roles in SFPM. Detailed explanation provided as a comment directly in the source.

Additional information about failing corner cases can be found here: status-im/status-desktop#16310

&QQmlSortFilterProxyModel::initRoles, Qt::UniqueConnection);

if (sourceModel) {
connect(sourceModel, &QAbstractItemModel::modelReset, this, [sourceModel, this]() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also disconnect this after the first insertion, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this connection must stay here forever, otherwise cases like status-im/status-desktop#16310 (comment) won't work. The reset may be emitted because the source model has own source changed. And source of source may be e.g. ListModel with not initialized roles. So we must assume that after every source reset the workaround procedure must be connected again if source is empty.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks! In this case I think we should disconnect on sourceModel change

Copy link
Member Author

@micieslak micieslak Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, you are right! Your statement is true even for the original implementation. The connection to rowsInserted should be also disconnected on source change.

Copy link
Member Author

@micieslak micieslak Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @alexjba for your discovery, there is excerpt exploiting that problem:

import QtQuick 2.15
import QtQuick.Controls 2.15

import StatusQ.Core.Utils 0.1

import SortFilterProxyModel 0.2

Item {
    id: root

    ListModel {
        id: emptyModel
    }

    ListModel {
        id: emptyModel2
    }

    SortFilterProxyModel {
        id: sfpm

        sourceModel: emptyModel

        proxyRoles: ExpressionRole {
            name: "customRole"
            expression: "X" + model.index
        }
    }

    ListView {
        id: lv

        anchors.fill: parent

        model: sfpm

        delegate: Text {
            text: model.text + " | " + model.customRole
        }
    }

    Button {
        anchors.centerIn: parent

        text: "ADD"

        onClicked: {
            sfpm.sourceModel = emptyModel2

            emptyModel.append({ text: "d" })
            emptyModel2.append({ text: "d" })
        }
    }
}

Inserting into model that was a source (but is not currently) triggers the initRoles and disconnects the slot from currently used model 😱. So when inserting into current source, roles are not initialized properly... 🤦‍♂️

Copy link
Member Author

@micieslak micieslak Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another example, this one exploiting lack of disconnection from modelReset:

import QtQuick 2.15
import QtQuick.Controls 2.15

import StatusQ.Core.Utils 0.1

import SortFilterProxyModel 0.2

Item {
    id: root

    ListModel {
        id: emptyModel
    }

    ListModel {
        id: emptyModel2
    }

    ListModel {
        id: emptyModel3
    }

    SortFilterProxyModel {
        id: sfpm1

        sourceModel: emptyModel

        proxyRoles: ExpressionRole {
            name: "customRole"
            expression: "X" + model.index
        }
    }

    SortFilterProxyModel {
        id: sfpm3

        sourceModel: emptyModel3

        proxyRoles: ExpressionRole {
            name: "customRole"
            expression: "X-" + model.index
        }
    }


    SortFilterProxyModel {
        id: sfpm2

        sourceModel: sfpm1
    }

    ListView {
        id: lv

        anchors.fill: parent

        model: sfpm2

        delegate: Text {
            text: model.text + " | " + model.customRole
        }
    }

    Button {
        anchors.centerIn: parent

        text: "ADD"

        onClicked: {
            sfpm2.sourceModel = sfpm3

            sfpm1.sourceModel = emptyModel2

            emptyModel2.append({ text: "d" })
            emptyModel3.append({ text: "d" })
        }
    }
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I provided a fix. @alexjba @caybro please take one more look.

Copy link
Member

@caybro caybro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

Need a regression test; since we know the scenarios under which this happens

@micieslak
Copy link
Member Author

Looks good

Need a regression test; since we know the scenarios under which this happens

Once it's merged we can test the app in a status-im/status-desktop#16321 where the SFPM is bumped.

@caybro
Copy link
Member

caybro commented Sep 13, 2024

Looks good

Need a regression test; since we know the scenarios under which this happens

Once it's merged we can test the app in a status-im/status-desktop#16321 where the SFPM is bumped.

Yeah sure, realized too late this is a different repo 😊

…t insertion)

So far the provided workaround was missing some corner cases when there
is more than one SFPM (or other proxies) in a chain, providing some
custom roles like proxy roles in SFPM. Detailed explanation provided as
a comment directly in the source.
@micieslak micieslak force-pushed the fix/improved-QTBUG-57971-handling branch from d6df62f to 40daec0 Compare September 13, 2024 14:30
Copy link
Member

@caybro caybro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link

@alexjba alexjba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Thank you 🍻

@micieslak
Copy link
Member Author

Ideally we should add proper unit tests for those corner cases. However now it's not easy as all helpers we are using for proxy models testing are located in status-desktop repository and are not available for SFPM. For now, I'm placing here list of scenarios failing before the fix was introduces:

status-im/status-desktop#16310 (comment)
status-im/status-desktop#16310 (comment)
#5 (comment)
#5 (comment)

@caybro
Copy link
Member

caybro commented Sep 16, 2024

Ideally we should add proper unit tests for those corner cases. However now it's not easy as all helpers we are using for proxy models testing are located in status-desktop repository and are not available for SFPM. For now, I'm placing here list of scenarios failing before the fix was introduces:

status-im/status-desktop#16310 (comment) status-im/status-desktop#16310 (comment) #5 (comment) #5 (comment)

There already some tests under vendor/SortFilterProxyModel/tests; we could add new ones there and integrate the whole suite into ui-tests

@micieslak
Copy link
Member Author

Ideally we should add proper unit tests for those corner cases. However now it's not easy as all helpers we are using for proxy models testing are located in status-desktop repository and are not available for SFPM. For now, I'm placing here list of scenarios failing before the fix was introduces:
status-im/status-desktop#16310 (comment) status-im/status-desktop#16310 (comment) #5 (comment) #5 (comment)

There already some tests under vendor/SortFilterProxyModel/tests; we could add new ones there and integrate the whole suite into ui-tests

Good point, I created a ticket: status-im/status-desktop#16343

@micieslak micieslak merged commit 984560c into master Sep 16, 2024
2 checks passed
@micieslak micieslak deleted the fix/improved-QTBUG-57971-handling branch September 16, 2024 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants