Sorting trees with Kirigami2

Greetings !

I’m working on an RSS aggregator using Kirigami: feeds are sorted in a folder tree. I’d like to make an interface for users to sort their feeds, changing their orders, moving feeds from one folder to another, and moving an entire folder in or out of a new parent folder.

I didn’t find much resources on how to do that with QML, much less with Kirigami. The “List View” example from the Kirigami Gallery provides some guidance, but it only sorts items on a single level… so maybe I shouldn’t even try to use that as a starting point.

I may not even be taking the best approach to implement this feature. My questions would be: is there a defined way to do such things in Kirigami ? How can I sort items in a tree in the most Kirigami-like way, and making the most out of existing Kirigami components ?

I use a folder tree in my app.

The key here is to use a Qabstractitemmodel in C++ representing your tree. And then pass this tree model to a Kirigami Addons treeview.

Here’s my finished Tree model and the qml part.

My tree model is pretty complet and specific, so here’s the code it is based on (thanks Carl Schwan)

If you need more explaination I’m okay to help :smiley:

3 Likes

For sorting you have two options:

  1. If you want the user’s sort to affect the underlying data then implement sorting directly into the TreeModel
  2. If you want the user’s sort to be independent of the underlying data (most likely case), then you should create a new class TreeSortModel which inherits a QSortFilterProxyModel and reimplements TreeSortModel::lessThan.

When you create your actual tree model you also create the proxy model like so:

auto *realModel = new MyTreeModel(this);
auto *proxyModel = new TreeSortModel(this);
proxyModel->setSource(realModel);

and pass proxyModel to the treeview. See here for more information about QSortFilterProxyModel.

2 Likes

[EDIT: mostly a rant about an issue I’ve had while trying to implement this. I haven’t done everything I can yet though. Building KLeverNotes locally reveals that the Kirigami TreeView addons does work on my system, with your implementation. So there has to be something wrong with mine… might be a few more weeks before I find out what’s precisely wrong, but I’ll manage.]

Thanks ! It doesn’t seem like the Kirigami TreeView addon works for me.

I’ve made an implementation of QAbstractItemModel that works with Qt6’s TreeView, but when I use that implementation with Kirigami’s TreeView (and Qt5, since I’m using KF5), I end up with the following errors:

file:///usr/lib64/qt5/qml/org/kde/kirigamiaddons/treeview/styles/org.kde.desktop/TreeViewDecoration.qml:0: ReferenceError: kDescendantLevel is not defined
file:///usr/lib64/qt5/qml/org/kde/kirigamiaddons/treeview/styles/org.kde.desktop/TreeViewDecoration.qml:0: ReferenceError: kDescendantExpandable is not defined
file:///usr/lib64/qt5/qml/org/kde/kirigamiaddons/treeview/styles/org.kde.desktop/TreeViewDecoration.qml:0: ReferenceError: kDescendantExpanded is not defined
file:///usr/lib64/qt5/qml/org/kde/kirigamiaddons/treeview/styles/org.kde.desktop/TreeViewDecoration.qml:0: ReferenceError: kDescendantExpandable is not defined
file:///usr/lib64/qt5/qml/org/kde/kirigamiaddons/treeview/AbstractTreeItem.qml:134: ReferenceError: listItem is not defined

The last one was easy to fix: apparently, the implementation of AbstractTreeItem MUST use listItem as its id. That’s how it seems to work in your own implementation, and it does seem to work with mine as well.

I see that I can also define the kDescendantHasSiblings, kDescendantExpanded and kDescendantExpandable properties myself: it removes the warning, and brings some visible changes to the view. However, it does not seem to work as intended, as trying to expand an item just clears the entire view.

Furthermore, I don’t see any of this in your implementation… so I’m pretty sure I shouldn’t be doing that. After exploring the code for Kirigami’s TreeView, I still have no clue where these properties are supposed to be coming from, and why they aren’t defined for me. It seems to me like they should be provided by the delegated component. But it’s not coming from AbstractTreeItem, and since your implementation expands on this component, but still does not provide these properties… I just don’t get it !

Maybe I’m not using the right Kirigami version ? But my QML files import the 2.19 version, just like yours… and I’m building it with Qt 5.15, which I assume is not a problem.

If I understand correctly you’re mixing the QabstractItemModel with a KSortFilterProxyModel directly from C++. (maybe extending the KSortFilterProxyModel)

I take a different approach, I implement the QabstractItemModel in C++ and then pass it to a KSortFilterProxyModel from QML, see this part of code.

The only thing I need then is to provide a filterString to KSortFilterProxyModel.

If it’s not what you’re doing, I’m sorry, it’s not easy to understand without viewing the code