diff --git a/containments/desktop/package/contents/ui/FolderItemDelegate.qml b/containments/desktop/package/contents/ui/FolderItemDelegate.qml --- a/containments/desktop/package/contents/ui/FolderItemDelegate.qml +++ b/containments/desktop/package/contents/ui/FolderItemDelegate.qml @@ -41,6 +41,12 @@ property Item hoverArea: loader.item ? loader.item.hoverArea : null property Item toolTip: loader.item ? loader.item.toolTip : null + function openPopup() { + if (isDir) { + loader.item.openPopup(); + } + } + Loader { id: loader @@ -90,13 +96,13 @@ } onHoveredChanged: { - if (hovered && !main.GridView.view.isRootView && model.isDir) { + if (hovered && (!main.GridView.view.isRootView || root.containsDrag) && model.isDir) { openPopupTimer.start(); } else if (!hovered) openPopupTimer.stop(); if (popupDialog != null) { - popupDialog.destroy(); + popupDialog.requestDestroy(); popupDialog = null; } } @@ -113,13 +119,27 @@ Timer { id: openPopupTimer - interval: units.longDuration * 3 + interval: 750 // Magic number that matches Dolphin's auto-expand folders delay. onTriggered: { impl.openPopup(); } } + Connections { + target: main.GridView.view + + enabled: hovered + + onContentXChanged: { + openPopupTimer.stop(); + } + + onContentYChanged: { + openPopupTimer.stop(); + } + } + PlasmaCore.ToolTipArea { id: toolTip @@ -314,6 +334,22 @@ Column { id: actions + visible: { + if (main.GridView.view.isRootView && root.containsDrag) { + return false; + } + + if (!main.GridView.view.isRootView && dialog.containsDrag) { + return false; + } + + if (popupDialog) { + return false; + } + + return true; + } + x: units.smallSpacing * 3 y: units.smallSpacing * 3 diff --git a/containments/desktop/package/contents/ui/FolderView.qml b/containments/desktop/package/contents/ui/FolderView.qml --- a/containments/desktop/package/contents/ui/FolderView.qml +++ b/containments/desktop/package/contents/ui/FolderView.qml @@ -42,6 +42,7 @@ property alias url: dir.url property alias positions: positioner.positions property alias errorString: dir.errorString + property alias dragging: dir.dragging property alias locked: dir.locked property alias sortMode: dir.sortMode property alias filterMode: dir.filterMode @@ -56,6 +57,7 @@ property alias scrollRight: gridView.scrollRight property alias scrollUp: gridView.scrollUp property alias scrollDown: gridView.scrollDown + property alias hoveredItem: gridView.hoveredItem property var history: [] property Item backButton: null @@ -70,6 +72,11 @@ dir.linkHere(sourceUrl); } + function itemAt(x, y) { + var pos = mapToItem(gridView.contentItem, x, y); + return gridView.itemAt(pos.x, pos.y); + } + function dropItemAt(pos) { var item = gridView.itemAt(pos.x, pos.y); diff --git a/containments/desktop/package/contents/ui/FolderViewDialog.qml b/containments/desktop/package/contents/ui/FolderViewDialog.qml --- a/containments/desktop/package/contents/ui/FolderViewDialog.qml +++ b/containments/desktop/package/contents/ui/FolderViewDialog.qml @@ -29,6 +29,18 @@ visible: false + property bool containsDrag: { + if (folderViewDropArea.containsDrag) { + return true; + } + + if (folderView.hoveredItem && folderView.hoveredItem.popupDialog) { + return folderView.hoveredItem.popupDialog.containsDrag; + } + + return false; + } + property QtObject closeTimer: closeTimer property QtObject childDialog: (folderView.hoveredItem != null) ? folderView.hoveredItem.popupDialog : null property bool containsMouse: folderView.containsMouse || (childDialog != null && childDialog.containsMouse) @@ -46,22 +58,36 @@ } } - mainItem: FolderView { - id: folderView + mainItem: FolderViewDropArea { + id: folderViewDropArea + + width: folderView.cellWidth * 3 + (10 * units.devicePixelRatio) // FIXME HACK: Use actual scrollbar width. + height: folderView.cellHeight * 2 + + folderView: folderView + + FolderView { + id: folderView - width: cellWidth * 3 + (10 * units.devicePixelRatio) // FIXME HACK: Use actual scrollbar width. - height: cellHeight * 2 + anchors.fill: parent - isRootView: false + isRootView: false - locked: true + locked: true - sortMode: ((plasmoid.configuration.sortMode == 0) ? 1 : plasmoid.configuration.sortMode) - filterMode: 0 + sortMode: ((plasmoid.configuration.sortMode == 0) ? 1 : plasmoid.configuration.sortMode) + filterMode: 0 - // TODO: Bidi. - flow: GridView.FlowLeftToRight - layoutDirection: Qt.LeftToRight + // TODO: Bidi. + flow: GridView.FlowLeftToRight + layoutDirection: Qt.LeftToRight + + onDraggingChanged: { + if (!dragging && !dialog.visible) { + dialog.destroy(); + } + } + } } data: [ @@ -82,13 +108,23 @@ } ] + function requestDestroy() { + if (folderView.dragging) { + visible = false; + } else { + destroy(); + } + } + function delayedDestroy() { var timer = Qt.createQmlObject('import QtQuick 2.0; Timer { onTriggered: itemDialog.destroy() }', itemDialog); timer.interval = 0; timer.start(); } Component.onDestruction: { closeTimer.stop(); + + console.log("destroying"); } } diff --git a/containments/desktop/package/contents/ui/FolderViewDropArea.qml b/containments/desktop/package/contents/ui/FolderViewDropArea.qml new file mode 100644 --- /dev/null +++ b/containments/desktop/package/contents/ui/FolderViewDropArea.qml @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2014-2017 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.4 + +import org.kde.draganddrop 2.0 as DragDrop + +DragDrop.DropArea { + id: dropArea + + property Item folderView: null + + function handleDragMove(folderView, event) { + // Trigger autoscroll. + folderView.scrollLeft = (event.x < (units.largeSpacing * 3)); + folderView.scrollRight = (event.x > width - (units.largeSpacing * 3)); + folderView.scrollUp = (event.y < (units.largeSpacing * 3)); + folderView.scrollDown = (event.y > height - (units.largeSpacing * 3)); + + // Set hovered item. + var item = folderView.itemAt(event.x, event.y); + + if (item && item.isDir) { + folderView.hoveredItem = item; + } + } + + function handleDragEnd(folderView) { + // Cancel autoscroll. + folderView.scrollLeft = false; + folderView.scrollRight = false; + folderView.scrollUp = false; + folderView.scrollDown = false; + + // Unset hovered item. + if (folderView.hoveredItem && !folderView.hoveredItem.popupDialog) { + folderView.hoveredItem = null; + } + } + + onDragMove: { + // TODO: We should reject drag moves onto file items that don't accept drops + // (cf. QAbstractItemModel::flags() here, but DeclarativeDropArea currently + // is currently incapable of rejecting drag events. + + if (folderView) { + handleDragMove(folderView, event); + } + } + + onDragLeave: { + if (folderView) { + handleDragEnd(folderView); + } + } + + onDrop: { + if (folderView) { + handleDragEnd(folderView); + + folderView.drop(folderView, event, mapToItem(folderView, event.x, event.y)); + } + } +} diff --git a/containments/desktop/package/contents/ui/main.qml b/containments/desktop/package/contents/ui/main.qml --- a/containments/desktop/package/contents/ui/main.qml +++ b/containments/desktop/package/contents/ui/main.qml @@ -33,7 +33,7 @@ import "LayoutManager.js" as LayoutManager import "FolderTools.js" as FolderTools -DragDrop.DropArea { +FolderViewDropArea { id: root objectName: isFolder ? "folder" : "desktop" @@ -255,10 +255,7 @@ // Trigger autoscroll. if (isFolder && FolderTools.isFileDrag(event)) { - folderViewLayer.view.scrollLeft = (event.x < (units.largeSpacing * 3)); - folderViewLayer.view.scrollRight = (event.x > width - (units.largeSpacing * 3)); - folderViewLayer.view.scrollUp = (event.y < (units.largeSpacing * 3)); - folderViewLayer.view.scrollDown = (event.y > height - (units.largeSpacing * 3)); + handleDragMove(folderViewLayer.view, event); } else if (isContainment) { placeHolder.width = LayoutManager.defaultAppletSize.width; placeHolder.height = LayoutManager.defaultAppletSize.height; @@ -274,10 +271,7 @@ onDragLeave: { // Cancel autoscroll. if (isFolder) { - folderViewLayer.view.scrollLeft = false; - folderViewLayer.view.scrollRight = false; - folderViewLayer.view.scrollUp = false; - folderViewLayer.view.scrollDown = false; + handleDragEnd(folderViewLayer.view); } if (isContainment) { @@ -287,12 +281,7 @@ onDrop: { if (isFolder && FolderTools.isFileDrag(event)) { - // Cancel autoscroll. - folderViewLayer.view.scrollLeft = false; - folderViewLayer.view.scrollRight = false; - folderViewLayer.view.scrollUp = false; - folderViewLayer.view.scrollDown = false; - + handleDragEnd(folderViewLayer.view); folderViewLayer.view.drop(root, event, mapToItem(folderViewLayer.view, event.x, event.y)); } else if (isContainment) { placeHolderPaint.opacity = 0; diff --git a/containments/desktop/plugins/folder/foldermodel.h b/containments/desktop/plugins/folder/foldermodel.h --- a/containments/desktop/plugins/folder/foldermodel.h +++ b/containments/desktop/plugins/folder/foldermodel.h @@ -73,6 +73,7 @@ Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged) Q_PROPERTY(QUrl resolvedUrl READ resolvedUrl NOTIFY resolvedUrlChanged) Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged) + Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) Q_PROPERTY(bool usedByContainment READ usedByContainment WRITE setUsedByContainment NOTIFY usedByContainmentChanged) Q_PROPERTY(bool locked READ locked WRITE setLocked NOTIFY lockedChanged) Q_PROPERTY(int sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged) @@ -123,6 +124,8 @@ QString errorString() const; + bool dragging() const; + bool usedByContainment() const; void setUsedByContainment(bool used); @@ -212,6 +215,7 @@ void iconNameChanged() const; void resolvedUrlChanged() const; void errorStringChanged() const; + void draggingChanged() const; void usedByContainmentChanged() const; void lockedChanged() const; void sortModeChanged() const; diff --git a/containments/desktop/plugins/folder/foldermodel.cpp b/containments/desktop/plugins/folder/foldermodel.cpp --- a/containments/desktop/plugins/folder/foldermodel.cpp +++ b/containments/desktop/plugins/folder/foldermodel.cpp @@ -238,6 +238,11 @@ return m_errorString; } +bool FolderModel::dragging() const +{ + return m_dragInProgress; +} + bool FolderModel::usedByContainment() const { return m_usedByContainment; @@ -758,6 +763,7 @@ } m_dragInProgress = true; + emit draggingChanged(); // Avoid starting a drag synchronously in a mouse handler or interferes with // child event filtering in parent items (and thus e.g. press-and-hold hand- @@ -771,6 +777,7 @@ { if (!m_viewAdapter || !m_selectionModel->hasSelection()) { m_dragInProgress = false; + emit draggingChanged(); return; } @@ -798,9 +805,12 @@ item->grabMouse(); drag->exec(supportedDragActions()); - m_dragInProgress = false; + item->ungrabMouse(); + m_dragInProgress = false; + emit draggingChanged(); + const QModelIndex first(m_dragIndexes.first()); const QModelIndex last(m_dragIndexes.last()); m_dragIndexes.clear(); @@ -875,6 +885,11 @@ QUrl dropTargetUrl; + // So we get to run mostLocalUrl() over the current URL. + if (item.isNull()) { + item = m_dirModel->dirLister()->rootItem(); + } + if (item.isNull()) { dropTargetUrl = m_dirModel->dirLister()->url(); } else if (m_parseDesktopFiles && item.isDesktopFile()) {