0

I try to handle a set of actions for multiple items selection on a ListView. The context: a RSS reader. An article can be read/unread, marked/unmarked, published/unpublished. Currently, my code adds every possible action when the multi-selection is started by the user: mark as read, keep unread, … So mark as read is available even if every selected article is already marked as read.

I'm trying to hide irrelevant actions. There's an example in the documentation to switch between multiple selection handlers, with predefined action lists. I would need to create an handler for every possibility, so 8 handlers. That's clearly not the solution.

I tried to call MultiSelectionHandler::removeAllActions() every time my selection changes and MultiSelectionHandler::addAction() to add back needed actions. This is the relevant part of my current code:

ListView {
    dataModel: _articleModel
    id: listView

    multiSelectAction: MultiSelectActionItem {
    }

    multiSelectHandler {
        status: qsTr("None selected")
        actions: []

        attachedObjects: [
            ActionItem {
                id: actionMultiRead
                title: qsTr("Mark as read")
                imageSource: "asset:///images/mark_as_read.png"

                onTriggered: {
                    var selectionList = listView.selectionList();
                    listView.clearSelection();
                    for (var i = 0; i < selectionList.length; ++i)
                        _articleModel.data(selectionList[i]).unread = false;
                }
            },
            ActionItem {
                id: actionMultiUnread
                title: qsTr("Keep unread")
                imageSource: "asset:///images/keep_unread.png"

                onTriggered: {
                    var selectionList = listView.selectionList();
                    listView.clearSelection();
                    for (var i = 0; i < selectionList.length; ++ i)
                        _articleModel.data(selectionList[i]).unread = true;
                }
            },

            ActionItem {
                id: actionMultiPublish
                title: qsTr("Publish")
                imageSource: "asset:///images/publish.png"

                onTriggered: {
                    var selectionList = listView.selectionList();
                    listView.clearSelection();
                    for (var i = 0; i < selectionList.length; ++ i)
                        _articleModel.data(selectionList[i]).published = true;
                }
            },
            ActionItem {
                id: actionMultiUnpublish
                title: qsTr("Unpublish")
                imageSource: "asset:///images/unpublish.png"

                onTriggered: {
                    var selectionList = listView.selectionList();
                    listView.clearSelection();
                    for (var i = 0; i < selectionList.length; ++ i)
                        _articleModel.data(selectionList[i]).published = false;
                }
            },

            ActionItem {
                id: actionMultiStar
                title: qsTr("Star")
                imageSource: "asset:///images/star.png"

                onTriggered: {
                    var selectionList = listView.selectionList();
                    listView.clearSelection();
                    for (var i = 0; i < selectionList.length; ++ i)
                        _articleModel.data(selectionList[i]).marked = true;
                }
            },
            ActionItem {
                id: actionMultiUnstar
                title: qsTr("Unstar")
                imageSource: "asset:///images/unstar.png"

                onTriggered: {
                    var selectionList = listView.selectionList();
                    listView.clearSelection();
                    for (var i = 0; i < selectionList.length; ++ i)
                        _articleModel.data(selectionList[i]).marked = false;
                }
            }
        ]
    }

    onSelectionChanged: {
        if (selectionList().length > 1) {
            multiSelectHandler.status = qsTr("%1 items selected").arg(selectionList().length);
        } else if (selectionList().length == 1) {
            multiSelectHandler.status = qsTr("1 item selected");
        } else {
            multiSelectHandler.status = qsTr("None selected");
        }

        // Update available actions
        multiSelectHandler.removeAllActions();
        for (var i = 0; i < selectionList().length; ++ i) {
            var elt = _articleModel.data(selectionList()[i]);
            if (elt.marked) {
                multiSelectHandler.addAction(actionMultiUnstar);
                console.log("Adding unstar");
            } else {
                multiSelectHandler.addAction(actionMultiStar);
                console.log("Adding star");
            }

            if (elt.published) {
                multiSelectHandler.addAction(actionMultiUnpublish);
                console.log("Adding unpublish");
            } else {
                multiSelectHandler.addAction(actionMultiPublish);
                console.log("Adding publish");
            }

            if (elt.unread) {
                multiSelectHandler.addAction(actionMultiRead);
                console.log("Adding read");
            } else {
                multiSelectHandler.addAction(actionMultiUnread);
                console.log("Adding unread");
            }
        }
    }
}

While it could greatly be optimized and works fine until the selection changes, it doesn't work anymore after a change: MultiSelectionHandler::removeAllActions() delete the actions, they can't be added back.

Is there any way to achieve this without declaring 8 multi selection handlers?

Marc Plano-Lesay
  • 6,808
  • 10
  • 44
  • 75

1 Answers1

1

the question is quite old, and probably you have already solved, but for any other one who stumbled up on this question my solution is to use MultiSelectionHandler::removeAction() instead of removeAllActions().

removeAllActions automatically delete the object, thus one should recreated the actions every time.

for (var i = 0; i < multiSelectAction.actionCount(); ++ i)
     multiSelectAction.removeAction(multiSelectAction.actionAt(i));

Cheers.

FabioDch
  • 516
  • 4
  • 8
  • Nice catch. I didn't notice the difference. I can't test it right now (I probably still have this code somewhere, I didn't worked on this app in a long time), but I'll keep you posted. – Marc Plano-Lesay May 26 '14 at 12:53
  • And I'm sorry, I never took the time to test this, and I don't have the possibility anymore… – Marc Plano-Lesay Jan 27 '15 at 16:17