]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kitemlistcontroller.cpp
Respect Shift- and Control-key for the rubberband selection
[dolphin.git] / src / kitemviews / kitemlistcontroller.cpp
index 7331131a94f8a638566806d107ac030cb195f0cc..92a14b23d5f37fd9917a07e0bf66e488ddee1d25 100644 (file)
@@ -26,6 +26,7 @@
 #include "kitemlistrubberband_p.h"
 #include "kitemlistselectionmanager.h"
 
+#include <QApplication>
 #include <QEvent>
 #include <QGraphicsSceneEvent>
 
@@ -285,12 +286,18 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const
         QPointF startPos = pos;
         if (m_view->scrollOrientation() == Qt::Vertical) {
             startPos.ry() += m_view->offset();
+            if (m_view->itemSize().width() < 0) {
+                // Use a special rubberband for views that have only one column and
+                // expand the rubberband to use the whole width of the view.
+                startPos.setX(0);
+            }
         } else {
             startPos.rx() += m_view->offset();
         }
         rubberBand->setStartPosition(startPos);
         rubberBand->setEndPosition(startPos);
         rubberBand->setActive(true);
+        connect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged()));
     }
 
     return false;
@@ -307,6 +314,11 @@ bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const
         QPointF endPos = transform.map(event->pos());
         if (m_view->scrollOrientation() == Qt::Vertical) {
             endPos.ry() += m_view->offset();
+            if (m_view->itemSize().width() < 0) {
+                // Use a special rubberband for views that have only one column and
+                // expand the rubberband to use the whole width of the view.
+                endPos.setX(m_view->size().width());
+            }
         } else {
             endPos.rx() += m_view->offset();
         }
@@ -322,7 +334,13 @@ bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, con
         return false;
     }
 
-    m_view->rubberBand()->setActive(false);
+    KItemListRubberBand* rubberBand = m_view->rubberBand();
+    if (rubberBand->isActive()) {
+        disconnect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged()));
+        rubberBand->setActive(false);
+        m_pressedIndex = -1;
+        return false;
+    }
 
     const QPointF pos = transform.map(event->pos());
     const int index = m_view->itemAt(pos);
@@ -541,4 +559,79 @@ void KItemListController::slotViewOffsetChanged(qreal current, qreal previous)
     }
 }
 
+void KItemListController::slotRubberBandChanged()
+{
+    if (!m_view || !m_model || m_model->count() <= 0) {
+        return;
+    }
+
+    const KItemListRubberBand* rubberBand = m_view->rubberBand();
+    const QPointF startPos = rubberBand->startPosition();
+    const QPointF endPos = rubberBand->endPosition();
+    QRectF rubberBandRect = QRectF(startPos, endPos).normalized();
+
+    const bool scrollVertical = (m_view->scrollOrientation() == Qt::Vertical);
+    if (scrollVertical) {
+        rubberBandRect.translate(0, -m_view->offset());
+    } else {
+        rubberBandRect.translate(-m_view->offset(), 0);
+    }
+
+    QSet<int> previousSelectedItems;
+    if (m_selectionManager->hasSelection()) {
+        // Don't clear the current selection in case if the user pressed the
+        // Shift- or Control-key during the rubberband selection
+        const bool shiftOrControlPressed = QApplication::keyboardModifiers() & Qt::ShiftModifier ||
+                                           QApplication::keyboardModifiers() & Qt::ControlModifier;
+        if (shiftOrControlPressed) {
+            previousSelectedItems = m_selectionManager->selectedItems();
+        }
+    }
+
+    QSet<int> selectedItems;
+
+    // Select all visible items that intersect with the rubberband
+    foreach (const KItemListWidget* widget, m_view->visibleItemListWidgets()) {
+        const int index = widget->index();
+
+        const QRectF widgetRect = m_view->itemBoundingRect(index);
+        if (widgetRect.intersects(rubberBandRect)) {
+            const QRectF iconRect = widget->iconBoundingRect().translated(widgetRect.topLeft());
+            const QRectF textRect = widget->textBoundingRect().translated(widgetRect.topLeft());
+            if (iconRect.intersects(rubberBandRect) || textRect.intersects(rubberBandRect)) {
+                selectedItems.insert(index);
+            }
+        }
+    }
+
+    // Select all invisible items that intersect with the rubberband. Instead of
+    // iterating all items only the area which might be touched by the rubberband
+    // will be checked.
+    const bool increaseIndex = scrollVertical ?
+                               startPos.y() > endPos.y(): startPos.x() > endPos.x();
+
+    int index = increaseIndex ? m_view->lastVisibleIndex() + 1 : m_view->firstVisibleIndex() - 1;
+    bool selectionFinished = false;
+    do {
+        const QRectF widgetRect = m_view->itemBoundingRect(index);
+        if (widgetRect.intersects(rubberBandRect)) {
+            selectedItems.insert(index);
+        }
+
+        if (increaseIndex) {
+            ++index;
+            selectionFinished = (index >= m_model->count()) ||
+                                ( scrollVertical && widgetRect.top()  > rubberBandRect.bottom()) ||
+                                (!scrollVertical && widgetRect.left() > rubberBandRect.right());
+        } else {
+            --index;
+            selectionFinished = (index < 0) ||
+                                ( scrollVertical && widgetRect.bottom() < rubberBandRect.top()) ||
+                                (!scrollVertical && widgetRect.right()  < rubberBandRect.left());
+        }
+    } while (!selectionFinished);
+
+    m_selectionManager->setSelectedItems(selectedItems + previousSelectedItems);
+}
+
 #include "kitemlistcontroller.moc"