After some more testing i have found out that it seems to be strange handling in QTreeView::dragMoveEvent() function that causes the strange behavior. If i subclass QTreeView and make my own dragMoveEvent() function i can get the view and model to accept the disabled drop on the root item (while still allowing child items to be dropped on), but not otherwise. What i had to do was check the flags myself for each item being dragged over to make the drop function correctly.
Code needed: (beware, i dont claim this is complete... this is just a quick hack to verify my theory)
if (index.flags() & Qt::ItemIsDropEnabled) {
event->accept();
} else {
}
}
void MyTreeView::dragMoveEvent(QDragMoveEvent *event) {
QModelIndex index = indexAt(event->pos());
if (index.flags() & Qt::ItemIsDropEnabled) {
event->accept();
} else {
QTreeView::dragMoveEvent(event);
}
}
To copy to clipboard, switch view to plain text mode
The culprit was these lines in the implementation in QAbstractItemView:
...
if (index.isValid() && d->showDropIndicator) {
...
} else {
d
->dropIndicatorRect
= QRect();
d->dropIndicatorPosition = OnViewport;
if (d->model->flags(rootIndex()) & Qt::ItemIsDropEnabled) {
event->setDropAction(dropAction);
event->accept(); // allow dropping in empty areas
}
}
...
...
if (index.isValid() && d->showDropIndicator) {
...
} else {
d->dropIndicatorRect = QRect();
d->dropIndicatorPosition = OnViewport;
if (d->model->flags(rootIndex()) & Qt::ItemIsDropEnabled) {
event->setDropAction(dropAction);
event->accept(); // allow dropping in empty areas
}
}
...
To copy to clipboard, switch view to plain text mode
As i had drop indicator disabled (i draw my own) the code only checks the root items flags and thus it disables all drop indicators for the children as well. If i were to decide this would be a bug... the handling should be the same whether you want to draw your own drop indicators or not.
Below is the default implementation in QAbstractItemView:
{
if (dragDropMode() == InternalMove
&& (event->source() != this || !(event->possibleActions() & Qt::MoveAction)))
return;
// ignore by default
event->ignore();
if (!(event->source() == this && selectedIndexes().contains(index))
&& d->canDecode(event)) {
Qt::DropAction dropAction = (d->model->supportedDropActions() & event->proposedAction())
? event->proposedAction() : Qt::IgnoreAction;
if (index.isValid() && d->showDropIndicator) {
QRect rect
= visualRect
(index
);
d->dropIndicatorPosition = d->position(event->pos(), rect);
switch (d->dropIndicatorPosition) {
case AboveItem:
if (d->model->flags(index.parent()) & Qt::ItemIsDropEnabled) {
d
->dropIndicatorRect
= QRect(rect.
left(), rect.
top(), rect.
width(),
0);
event->setDropAction(dropAction);
event->accept();
} else {
d
->dropIndicatorRect
= QRect();
}
break;
case BelowItem:
if (d->model->flags(index.parent()) & Qt::ItemIsDropEnabled) {
d
->dropIndicatorRect
= QRect(rect.
left(), rect.
bottom(), rect.
width(),
0);
event->setDropAction(dropAction);
event->accept();
} else {
d
->dropIndicatorRect
= QRect();
}
break;
case OnItem:
if (d->model->flags(index) & Qt::ItemIsDropEnabled) {
d->dropIndicatorRect = rect;
event->setDropAction(dropAction);
event->accept();
} else {
d
->dropIndicatorRect
= QRect();
}
break;
case OnViewport:
d
->dropIndicatorRect
= QRect();
break;
}
} else {
d
->dropIndicatorRect
= QRect();
d->dropIndicatorPosition = OnViewport;
if (d->model->flags(rootIndex()) & Qt::ItemIsDropEnabled) {
event->setDropAction(dropAction);
event->accept(); // allow dropping in empty areas
}
}
d->viewport->update();
} // can decode
if (d->shouldAutoScroll(event->pos()))
startAutoScroll();
}
void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event)
{
Q_D(QAbstractItemView);
if (dragDropMode() == InternalMove
&& (event->source() != this || !(event->possibleActions() & Qt::MoveAction)))
return;
// ignore by default
event->ignore();
QModelIndex index = indexAt(event->pos());
if (!(event->source() == this && selectedIndexes().contains(index))
&& d->canDecode(event)) {
Qt::DropAction dropAction = (d->model->supportedDropActions() & event->proposedAction())
? event->proposedAction() : Qt::IgnoreAction;
if (index.isValid() && d->showDropIndicator) {
QRect rect = visualRect(index);
d->dropIndicatorPosition = d->position(event->pos(), rect);
switch (d->dropIndicatorPosition) {
case AboveItem:
if (d->model->flags(index.parent()) & Qt::ItemIsDropEnabled) {
d->dropIndicatorRect = QRect(rect.left(), rect.top(), rect.width(), 0);
event->setDropAction(dropAction);
event->accept();
} else {
d->dropIndicatorRect = QRect();
}
break;
case BelowItem:
if (d->model->flags(index.parent()) & Qt::ItemIsDropEnabled) {
d->dropIndicatorRect = QRect(rect.left(), rect.bottom(), rect.width(), 0);
event->setDropAction(dropAction);
event->accept();
} else {
d->dropIndicatorRect = QRect();
}
break;
case OnItem:
if (d->model->flags(index) & Qt::ItemIsDropEnabled) {
d->dropIndicatorRect = rect;
event->setDropAction(dropAction);
event->accept();
} else {
d->dropIndicatorRect = QRect();
}
break;
case OnViewport:
d->dropIndicatorRect = QRect();
break;
}
} else {
d->dropIndicatorRect = QRect();
d->dropIndicatorPosition = OnViewport;
if (d->model->flags(rootIndex()) & Qt::ItemIsDropEnabled) {
event->setDropAction(dropAction);
event->accept(); // allow dropping in empty areas
}
}
d->viewport->update();
} // can decode
if (d->shouldAutoScroll(event->pos()))
startAutoScroll();
}
To copy to clipboard, switch view to plain text mode
Bookmarks