]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kitemlistcontroller.cpp
portalize drag urls
[dolphin.git] / src / kitemviews / kitemlistcontroller.cpp
index 966dc822b530e3597279d8fa670fedafde0ad738..3d83bc9143a85ba7b18f426e8698a7fa1456ce83 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <KTwoFingerSwipe>
 #include <KTwoFingerTap>
+#include <KUrlMimeData>
 
 #include <QAccessible>
 #include <QApplication>
@@ -724,7 +725,7 @@ bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent* event, cons
     KItemListWidget* oldHoveredWidget = hoveredWidget();
 
     const QPointF pos = transform.map(event->pos());
-    KItemListWidget* newHoveredWidget = widgetForPos(pos);
+    KItemListWidget* newHoveredWidget = widgetForDropPos(pos);
 
     if (oldHoveredWidget != newHoveredWidget) {
         m_autoActivationTimer->stop();
@@ -806,7 +807,12 @@ bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent* event, const QT
         Q_EMIT aboveItemDropEvent(dropAboveIndex, event);
     } else if (!event->mimeData()->hasFormat(m_model->blacklistItemDropEventMimeType())) {
         // Something has been dropped on an item or on an empty part of the view.
-        Q_EMIT itemDropEvent(m_view->itemAt(pos).value_or(-1), event);
+        const KItemListWidget *receivingWidget = widgetForDropPos(pos);
+        if (receivingWidget) {
+            Q_EMIT itemDropEvent(receivingWidget->index(), event);
+        } else {
+            Q_EMIT itemDropEvent(-1, event);
+        }
     }
 
     QAccessibleEvent accessibilityEvent(view(), QAccessible::DragDropEnd);
@@ -872,7 +878,8 @@ bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const
             newHoveredWidget->setExpansionAreaHovered(true);
         } else {
             // make sure we unhover the old one first if old!=new
-            if (auto oldHoveredWidget = hoveredWidget(); oldHoveredWidget && oldHoveredWidget != newHoveredWidget) {
+            auto oldHoveredWidget = hoveredWidget();
+            if (oldHoveredWidget && oldHoveredWidget != newHoveredWidget) {
                 oldHoveredWidget->setHovered(false);
                 Q_EMIT itemUnhovered(oldHoveredWidget->index());
             }
@@ -889,9 +896,11 @@ bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const
 
                 // (no-op in this branch for masked hover)
             } else {
-                newHoveredWidget->setHovered(true);
                 newHoveredWidget->setHoverPosition(mappedPos);
-                Q_EMIT itemHovered(newHoveredWidget->index());
+                if (oldHoveredWidget != newHoveredWidget) {
+                    newHoveredWidget->setHovered(true);
+                    Q_EMIT itemHovered(newHoveredWidget->index());
+                }
             }
         }
     } else {
@@ -1310,10 +1319,11 @@ void KItemListController::startDragging()
         return;
     }
 
-    QMimeDatadata = m_model->createMimeData(selectedItems);
+    QMimeData *data = m_model->createMimeData(selectedItems);
     if (!data) {
         return;
     }
+    KUrlMimeData::exportUrlsToPortal(data);
 
     // The created drag object will be owned and deleted
     // by QApplication::activeWindow().
@@ -1361,6 +1371,21 @@ KItemListWidget* KItemListController::widgetForPos(const QPointF& pos) const
     return nullptr;
 }
 
+KItemListWidget* KItemListController::widgetForDropPos(const QPointF& pos) const
+{
+    Q_ASSERT(m_view);
+
+    const auto widgets = m_view->visibleItemListWidgets();
+    for (KItemListWidget* widget : widgets) {
+        const QPointF mappedPos = widget->mapFromItem(m_view, pos);
+        if (widget->contains(mappedPos)) {
+            return widget;
+        }
+    }
+
+    return nullptr;
+}
+
 void KItemListController::updateKeyboardAnchor()
 {
     const bool validAnchor = m_keyboardAnchorIndex >= 0 &&
@@ -1494,6 +1519,7 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
 
     const bool shiftPressed = modifiers & Qt::ShiftModifier;
     const bool controlPressed = modifiers & Qt::ControlModifier;
+    const bool leftClick = buttons & Qt::LeftButton;
     const bool rightClick = buttons & Qt::RightButton;
 
     // The previous selection is cleared if either
@@ -1575,6 +1601,7 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
     }
 
     if (m_pressedIndex.has_value()) {
+        // The hover highlight area of an item is being pressed.
         m_selectionManager->setCurrentItem(m_pressedIndex.value());
         const auto row = m_view->m_visibleItems.value(m_pressedIndex.value()); // anything outside of row.contains() will be the empty region of the row rect
         const bool hitTargetIsRowEmptyRegion = !row->contains(row->mapFromItem(m_view, pos));
@@ -1583,8 +1610,15 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
         bool createRubberBand = (hitTargetIsRowEmptyRegion && m_selectionManager->selectedItems().isEmpty());
 
         if (rightClick && hitTargetIsRowEmptyRegion) {
-            // we got a right click outside the text rect, default to action on the current url and not the pressed item
-            Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), screenPos);
+            // We have a right click outside the icon and text rect but within the hover highlight area
+            // but it is unclear if this means that a selection rectangle for an item was clicked or the background of the view.
+            if (m_selectionManager->selectedItems().contains(m_pressedIndex.value())) {
+                // The selection rectangle for an item was clicked
+                Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), screenPos);
+            } else {
+                row->setHovered(false); // Removes the hover highlight so the context menu doesn't look like it applies to the row.
+                Q_EMIT viewContextMenuRequested(screenPos);
+            }
             return true;
         }
 
@@ -1597,10 +1631,21 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
             break;
 
         case MultiSelection:
-            if (controlPressed && !shiftPressed) {
-                m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Toggle);
-                m_selectionManager->beginAnchoredSelection(m_pressedIndex.value());
-                createRubberBand = false; // multi selection, don't propagate any further
+            if (controlPressed && !shiftPressed && leftClick) {
+                // A left mouse button press is happening on an item while control is pressed. This either means a user wants to:
+                // - toggle the selection of item(s) or
+                // - they want to begin a drag on the item(s) to copy them.
+                // We rule out the latter, if the item is not clicked directly and was unselected previously.
+                const auto row = m_view->m_visibleItems.value(m_pressedIndex.value());
+                const auto mappedPos = row->mapFromItem(m_view, pos);
+                if (!row->iconRect().contains(mappedPos) && !row->textRect().contains(mappedPos) && !pressedItemAlreadySelected) {
+                    createRubberBand = true;
+                } else {
+                    m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Toggle);
+                    m_selectionManager->beginAnchoredSelection(m_pressedIndex.value());
+                    createRubberBand = false; // multi selection, don't propagate any further
+                    // This will be the start of an item drag-to-copy operation if the user now moves the mouse before releasing the mouse button.
+                }
             } else if (!shiftPressed || !m_selectionManager->isAnchoredSelectionActive()) {
                 // Select the pressed item and start a new anchored selection
                 m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Select);