Reputation: 11
As you can see from the title, I use a QStandardItemModel to store a Tree Structure. I manipulate this structure inside a QTreeView, than I need to save it on a database in this format:
|id|Parent|Child |
| 1| |ITEM01|
| 2| 1|ITEM02|
| 3| 2|ITEM03|
| 4| 3|ITEM04|
| 5| 4|ITEM05|
| 6| 5|ITEM06|
| 7| 6|ITEM07|
| 8| 3|ITEM08|
| 9| 3|ITEM09|
|10| 3|ITEM10|
That represent this structure:
ITEM01
║
╠═► ITEM02
║ ║
║ ╚═► ITEM03
║ ║
║ ╠═► ITEM04
║ ║ ║
║ ║ ╚═► ITEM05
║ ║ ║
║ ║ ╚═► ITEM06
║ ║ ║
║ ║ ╚═► ITEM07
║ ║
║ ╠═► ITEM08
║ ╠═► ITEM09
║ ╚═► ITEM10
in other words "id" represent uniquely a node, the field "parent" is a reference to the parent node. The root node is an empty field.
My question is: how to get an uniquely id (in int format), from QStandardItemModel? I've tried with QModelIndex::row() and QPersistentModelIndex::row() but it seems not to be unique.
Many Thanks.
Upvotes: 1
Views: 663
Reputation: 654
You can iterate over QAbstractItemModel
using this approach.
void iterate(const QModelIndex & index, const QAbstractItemModel * model,
const std::function<void(const QModelIndex&, int)> & fun,
int depth = 0)
{
if (index.isValid())
fun(index, depth);
if ((index.flags() & Qt::ItemNeverHasChildren) || !model->hasChildren(index)) return;
auto rows = model->rowCount(index);
auto cols = model->columnCount(index);
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
iterate(model->index(i, j, index), model, fun, depth+1);
}
void dumpData(QAbstractItemView * view) {
iterate(view->rootIndex(), view->model(), [](const QModelIndex & idx, int depth){
qDebug() << depth << ":" << idx.row() << "," << idx.column() << "=" << idx.data();
});
}
Then get item's parent item using QModelIndex::parent()
and finally get unique ids of both parent's item and item itself using QModelIndex::internalId()
.
Upvotes: 0
Reputation: 98425
The easiest approach would be to assign the indices from an incrementing counter as you traverse the tree in a certain depth-first order, e.g. postorder - left...right, root.
If you store the id
and parent
as roles of your element, then:
int assignIdsPostorder(QStandardItem * e, int idRole, int parentRole, int counter = 0) {
auto const N = e->rowCount();
for (int i = 0; i < N; ++i)
counter = assignIdsDFS(e->child(i), idRole, parentRole, counter);
if (e->setData(counter, idRole)) counter++;
for (int i = 0; i < N; ++i)
e->child(i)->setData(e->data(idRole), parentRole);
return counter;
}
A minor modification would accommodate storing the id
and parent
in individual columns.
If the indices don't need to be valid at all times, then you can generate them lazily with memoization (caching). A QStandardItem
-derived element would reimplement data()
to perform partial tree traversals to generate its ids
. The order of traversal would need to be adapted to the properties of your tree if you'd want to avoid the case of potentially having to annotate the entire tree on a single id query.
Upvotes: 1