Smarter way to get a list of children in Tree Model
-
Hi guys, I'm being lazy here. Do you know of any Proxy model that shows only a certain level of a tree as a list?
What I need is to turn something like
- Item 1
- Item 2
- Item 3
- Item 4
- Item 5
into:
when level property is 0- Item 1
- Item 4
when level property is 1
- Item 2
- Item 3
- Item 5
I achieved it already using 3 proxies concatenated but wanted to know if there is a 1 proxy way already available.
My current solution:
#include <QIdentityProxyModel> class LevelDataProxy : public QIdentityProxyModel { Q_OBJECT public: explicit LevelDataProxy(QObject *parent = nullptr) : QIdentityProxyModel(parent) {} enum { LevelDataRole = 1989 }; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override{ if (index.isValid() && role == LevelDataRole) { Q_ASSERT(checkIndex(index)); int result = 0; for (QModelIndex cursor(index); cursor.parent().isValid(); cursor = cursor.parent(), ++result) {} return result; } return QIdentityProxyModel::data(index, role); } };
and then I use it and a QSortFilterProxyModel with a KDescendantsProxyModel in the middle:
// QAbstractItemModel* originalModel; LevelDataProxy* levelInfoProxy = new LevelDataProxy(&printSettingDialog); levelInfoProxy->setSourceModel(originalModel); KDescendantsProxyModel* flatModel = new KDescendantsProxyModel(&printSettingDialog); flatModel->setSourceModel(levelInfoProxy); flatModel->setDisplayAncestorData(false); QSortFilterProxyModel* levelInfoFilter = new QSortFilterProxyModel(&printSettingDialog); levelInfoFilter->setFilterRole(LevelDataProxy::LevelDataRole); levelInfoFilter->setFilterFixedString("1"); levelInfoFilter->setSourceModel(flatModel);
- Item 1
-
@VRonin
How about re-implementing filterAcceptsRow inQSortFilterProxyModel
and return true or false depending uponsource_parent
? For eg.Item 1
andItem 4
has invisible root as their parent but the their children don't.
Just a non educated guess. Haven't tried myself. -
Another speculative suggestion:
I don't really like the idea of deriving from the identity proxy and then overridingdata()
, somehow feels wrong. You want to change the structure, not the data. What I'd try if I were you, is to subclassQAbstractProxyModel
and do that depth-search like thingy only once, to obtain aQModelIndex
for the "parent". After that in the index* methods (especially relevant seems hasIndex()) I'd return invalid model indexes for items that aren't parented to the parent I've stored in the beginning.I hope that helps.
Kind regards. -
@p3c0 Most views would hide all children if the parent is hidden so you won't be able to achieve a list of children
@kshegunov the overridden data is to store somewhere the level in the original tree before it gets flattened by KDescendantsProxyModel. I know it's ugly and dirty that's why I asked the question. The second part seems pretty much the way to go but since this I need this just to show a combobox I didn't feel like going through building a QAbstractProxyModel from scratch
-
@VRonin said in Smarter way to get a list of children in Tree Model:
the overridden data is to store somewhere the level in the original tree before it gets flattened by KDescendantsProxyModel.
I don't believe you need that. Pushing a tree model to a list/table view should give you list/table with the root-level items (speculation again!). In my mind it should be just enough to "move" the root of the model before giving it to the view.
I didn't feel like going through building a QAbstractProxyModel from scratch
Well, yes, I can see why, but if you think about it, most of your methods should turn out trivial (more or less) - similarly to the identity proxy model.
Kind regards.