diff --git a/plugins/projectmanagerview/projecttreeview.h b/plugins/projectmanagerview/projecttreeview.h --- a/plugins/projectmanagerview/projecttreeview.h +++ b/plugins/projectmanagerview/projecttreeview.h @@ -23,13 +23,17 @@ #include #include +#include + +#include class QAbstractProxyModel; namespace KDevelop { class IProject; class ProjectBaseItem; +class ProjectFolderItem; class Path; } @@ -58,6 +62,9 @@ protected: void keyPressEvent(QKeyEvent *event) override; + void timerEvent(QTimerEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void dragLeaveEvent(QDragLeaveEvent *event) override; void dropEvent(QDropEvent* event) override; void drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const override; @@ -68,6 +75,11 @@ KDevelop::IProject* getCurrentProject(); QPointer m_previousSelection; + + // drag'n'drop implementation + QBasicTimer expandTimer; + KDevelop::ProjectFolderItem *curExpandTarget; + std::stack expandStack; }; #endif // KDEVPLATFORM_PLUGIN_PROJECTTREEVIEW_H diff --git a/plugins/projectmanagerview/projecttreeview.cpp b/plugins/projectmanagerview/projecttreeview.cpp --- a/plugins/projectmanagerview/projecttreeview.cpp +++ b/plugins/projectmanagerview/projecttreeview.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -52,6 +54,7 @@ #include #include + using namespace KDevelop; namespace { @@ -123,7 +126,8 @@ setDragEnabled(true); setDragDropMode(QAbstractItemView::InternalMove); setAutoScroll(true); - setAutoExpandDelay(300); + setAutoScrollMargin(32); + setAutoExpandDelay(400); setItemDelegate(new ProjectModelItemDelegate(this)); connect( this, &ProjectTreeView::customContextMenuRequested, this, &ProjectTreeView::popupContextMenu ); @@ -146,6 +150,74 @@ return indexAt(pos).data(ProjectModel::ProjectItemRole).value(); } +void ProjectTreeView::timerEvent(QTimerEvent *event) { + if (event->timerId() == expandTimer.timerId()) { + expandTimer.stop(); + auto expandTargetItem = mapFromItem(curExpandTarget); + expand(expandTargetItem); + + auto isDescendant = [](ProjectBaseItem *needle, ProjectBaseItem *haystack) { + while (needle) { + if (needle->parent() == haystack) { + return true; + } + needle = needle->parent(); + } + return false; + }; + + // collapse unneeded previously opened folders + int prevTargetPos = visualRect(expandTargetItem).top(); + while (!expandStack.empty() && !isDescendant(curExpandTarget, expandStack.top())) { + collapse(mapFromItem(expandStack.top())); + expandStack.pop(); + } + + // try to return the expanded folder back to the mouse cursor if the folder has shifted + int curTargetPos = visualRect(expandTargetItem).top(); + int targtPosChange = curTargetPos - prevTargetPos; + ScrollMode prevMode = verticalScrollMode(); + setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + verticalScrollBar()->setValue(verticalScrollBar()->value() + targtPosChange); + setVerticalScrollMode(prevMode); + + expandStack.push(curExpandTarget); + curExpandTarget = nullptr; + } else { + QTreeView::timerEvent(event); + } +} + +void ProjectTreeView::dragMoveEvent(QDragMoveEvent *event) +{ + ProjectBaseItem *destItem = itemAtPos(event->pos()); + if (destItem && dropIndicatorPosition() == OnItem) { + ProjectFolderItem *folder = destItem->folder(); + bool canExpand = folder && !isExpanded(mapFromItem(folder)) && autoExpandDelay() >= 0; + bool expandTargetNotChanged = folder && folder == curExpandTarget; + if (folder != curExpandTarget && canExpand) { + curExpandTarget = folder; + expandTimer.start(autoExpandDelay(), this); + } else if (!expandTargetNotChanged) { + expandTimer.stop(); + curExpandTarget = nullptr; + } + } else { + expandTimer.stop(); + curExpandTarget = nullptr; + } + QAbstractItemView::dragMoveEvent(event); +} + +void ProjectTreeView::dragLeaveEvent(QDragLeaveEvent *event) +{ + while (!expandStack.empty()) { + collapse(mapFromItem(expandStack.top())); + expandStack.pop(); + } + QTreeView::dragLeaveEvent(event); +} + void ProjectTreeView::dropEvent(QDropEvent* event) { ProjectItemContext* selectionCtxt = @@ -251,6 +323,11 @@ } } } + + if (!expandStack.empty()) { + expandStack = std::stack(); + } + event->accept(); }