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)

Qt Code:
  1. void MyTreeView::dragMoveEvent(QDragMoveEvent *event) {
  2. QModelIndex index = indexAt(event->pos());
  3.  
  4. if (index.flags() & Qt::ItemIsDropEnabled) {
  5. event->accept();
  6. } else {
  7. QTreeView::dragMoveEvent(event);
  8. }
  9. }
To copy to clipboard, switch view to plain text mode 

The culprit was these lines in the implementation in QAbstractItemView:

Qt Code:
  1. ...
  2. if (index.isValid() && d->showDropIndicator) {
  3. ...
  4. } else {
  5. d->dropIndicatorRect = QRect();
  6. d->dropIndicatorPosition = OnViewport;
  7. if (d->model->flags(rootIndex()) & Qt::ItemIsDropEnabled) {
  8. event->setDropAction(dropAction);
  9. event->accept(); // allow dropping in empty areas
  10. }
  11. }
  12. ...
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:

Qt Code:
  1. void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event)
  2. {
  3. if (dragDropMode() == InternalMove
  4. && (event->source() != this || !(event->possibleActions() & Qt::MoveAction)))
  5. return;
  6.  
  7. // ignore by default
  8. event->ignore();
  9.  
  10. QModelIndex index = indexAt(event->pos());
  11. if (!(event->source() == this && selectedIndexes().contains(index))
  12. && d->canDecode(event)) {
  13. Qt::DropAction dropAction = (d->model->supportedDropActions() & event->proposedAction())
  14. ? event->proposedAction() : Qt::IgnoreAction;
  15.  
  16. if (index.isValid() && d->showDropIndicator) {
  17. QRect rect = visualRect(index);
  18. d->dropIndicatorPosition = d->position(event->pos(), rect);
  19. switch (d->dropIndicatorPosition) {
  20. case AboveItem:
  21. if (d->model->flags(index.parent()) & Qt::ItemIsDropEnabled) {
  22. d->dropIndicatorRect = QRect(rect.left(), rect.top(), rect.width(), 0);
  23. event->setDropAction(dropAction);
  24. event->accept();
  25. } else {
  26. d->dropIndicatorRect = QRect();
  27. }
  28. break;
  29. case BelowItem:
  30. if (d->model->flags(index.parent()) & Qt::ItemIsDropEnabled) {
  31. d->dropIndicatorRect = QRect(rect.left(), rect.bottom(), rect.width(), 0);
  32. event->setDropAction(dropAction);
  33. event->accept();
  34. } else {
  35. d->dropIndicatorRect = QRect();
  36. }
  37. break;
  38. case OnItem:
  39. if (d->model->flags(index) & Qt::ItemIsDropEnabled) {
  40. d->dropIndicatorRect = rect;
  41. event->setDropAction(dropAction);
  42. event->accept();
  43. } else {
  44. d->dropIndicatorRect = QRect();
  45. }
  46. break;
  47. case OnViewport:
  48. d->dropIndicatorRect = QRect();
  49. break;
  50. }
  51. } else {
  52. d->dropIndicatorRect = QRect();
  53. d->dropIndicatorPosition = OnViewport;
  54. if (d->model->flags(rootIndex()) & Qt::ItemIsDropEnabled) {
  55. event->setDropAction(dropAction);
  56. event->accept(); // allow dropping in empty areas
  57. }
  58. }
  59. d->viewport->update();
  60. } // can decode
  61.  
  62. if (d->shouldAutoScroll(event->pos()))
  63. startAutoScroll();
  64. }
To copy to clipboard, switch view to plain text mode