0
votes

I am using a QTreeWidget to display a tree of parent nodes with their leave nodes. Each parent can have various leaf nodes but leaf nodes should have no childs. The user should be able to move leaves between parents by dragging them to the new position. To avoid leaves from being dropped on other leaves, I have only set ItemIsDragEnabled on leaves while having ItemIsDropEnabled on parent nodes. This works fine if the QTreeWidget is set to "SingleSelection". However, if the SelectionMode is set to ExtendedSelection you are able to select a leave and a parent node together and drop them both on a leaf: http://i.stack.imgur.com/Kil3y.jpg (Screenshot)

Here is the sample code:

QTreeWidget *tree = this->ui->treeWidget;
QTreeWidgetItem *item;
QTreeWidgetItem *child;
tree->setSelectionMode(QAbstractItemView::ExtendedSelection);
tree->setDefaultDropAction(Qt::MoveAction);
tree->setDragEnabled(true);
tree->setAcceptDrops(true);
tree->setDropIndicatorShown(true);

// disable dropping of leaves as top level items
tree->invisibleRootItem()->setFlags( Qt::ItemIsSelectable |
                Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );

for (int i = 0; i < 2; i++) {
    // create top level item
    item = new QTreeWidgetItem();
    item->setText(0, "parent");
    item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable
                  | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled );

    // add 3 child items
    for (int j = 0; j < 3; j++) {
        child = new QTreeWidgetItem();
        child->setText(0, "child");
        child->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable
                      | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled );
        item->addChild(child);
    }

    // add item to tree
    tree->addTopLevelItem(item);
}

I googled quite a lot but could not come up with a solution. How can I keep child and parent nodes on their respective levels while using ExtendedSelection?

Do I have to subclass QTreeWidget and override insertRows()? Is there any way to intercept drag'n'drop actions on QTreeWidget so I could check if the action is ok? (If there is a way to get this to work with QStandardItemModel/QTreeView I would be happy too)

1

1 Answers

0
votes

One easy workaround is to connect a little function to the signal itemSelectionChanged that removes all items from the selection that are not of the same type as the last selected item. Works just perfect for me (and for other programs like the Warcraft 3 trigger editor)