]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Fix keyboard issues when groups are enabled
authorPeter Penz <peter.penz19@gmail.com>
Mon, 26 Dec 2011 21:16:32 +0000 (22:16 +0100)
committerPeter Penz <peter.penz19@gmail.com>
Mon, 26 Dec 2011 21:22:50 +0000 (22:22 +0100)
When groups are enabled in Dolphin the key-up and key-down keys did not behave
consistent in comparison to traditional views or like done in editors.

CCBUG: 261995
CCBUG: 262038

src/kitemviews/kitemlistcontroller.cpp
src/kitemviews/kitemlistcontroller.h
src/kitemviews/kitemlistview.cpp
src/kitemviews/kitemlistview.h
src/kitemviews/kitemlistviewlayouter.cpp
src/kitemviews/kitemlistviewlayouter_p.h

index 8577bf8630ae0eb033be5ca748c457f6c4e3a14c..0cf62f8e0972fc24890fa7107c154cb9d955942f 100644 (file)
@@ -50,7 +50,9 @@ KItemListController::KItemListController(QObject* parent) :
     m_pressedIndex(-1),
     m_pressedMousePos(),
     m_autoActivationTimer(0),
-    m_oldSelection()
+    m_oldSelection(),
+    m_keyboardAnchorIndex(-1),
+    m_keyboardAnchorXPos(0)
 {
     connect(m_keyboardManager, SIGNAL(changeCurrentItem(QString,bool)),
             this, SLOT(slotChangeCurrentItem(QString,bool)));
@@ -175,7 +177,6 @@ bool KItemListController::keyPressEvent(QKeyEvent* event)
     const bool shiftOrControlPressed = shiftPressed || controlPressed;
 
     const int itemCount = m_model->count();
-    const int itemsPerRow = m_view->itemsPerOffset();
 
     // For horizontal scroll orientation, transform
     // the arrow keys to simplify the event handling.
@@ -210,37 +211,28 @@ bool KItemListController::keyPressEvent(QKeyEvent* event)
 
     case Qt::Key_Left:
         if (index > 0) {
-            index--;
+            --index;
+            m_keyboardAnchorIndex = index;
+            m_keyboardAnchorXPos = keyboardAnchorPos(index);
         }
         break;
 
     case Qt::Key_Right:
         if (index < itemCount - 1) {
-            index++;
+            ++index;
+            m_keyboardAnchorIndex = index;
+            m_keyboardAnchorXPos = keyboardAnchorPos(index);
         }
         break;
 
     case Qt::Key_Up:
-        if (index >= itemsPerRow) {
-            index -= itemsPerRow;
-        }
+        updateKeyboardAnchor();
+        index = previousRowIndex();
         break;
 
     case Qt::Key_Down:
-        if (index + itemsPerRow < itemCount) {
-            // We are not in the last row yet.
-            index += itemsPerRow;
-        } else {
-            // We are either in the last row already, or we are in the second-last row,
-            // and there is no item below the current item.
-            // In the latter case, we jump to the very last item.
-            const int currentColumn = index % itemsPerRow;
-            const int lastItemColumn = (itemCount - 1) % itemsPerRow;
-            const bool inLastRow = currentColumn < lastItemColumn;
-            if (!inLastRow) {
-                index = itemCount - 1;
-            }
-        }
+        updateKeyboardAnchor();
+        index = nextRowIndex();
         break;
 
     case Qt::Key_Enter:
@@ -955,4 +947,97 @@ KItemListWidget* KItemListController::widgetForPos(const QPointF& pos) const
     return 0;
 }
 
+void KItemListController::updateKeyboardAnchor()
+{
+    const bool validAnchor = m_keyboardAnchorIndex >= 0 &&
+                             m_keyboardAnchorIndex < m_model->count() &&
+                             keyboardAnchorPos(m_keyboardAnchorIndex) == m_keyboardAnchorXPos;
+    if (!validAnchor) {
+        const int index = m_selectionManager->currentItem();
+        m_keyboardAnchorIndex = index;
+        m_keyboardAnchorXPos = keyboardAnchorPos(index);
+    }
+}
+
+int KItemListController::nextRowIndex() const
+{
+    const int currentIndex = m_selectionManager->currentItem();
+    if (m_keyboardAnchorIndex < 0) {
+        return currentIndex;
+    }
+
+    const int maxIndex = m_model->count() - 1;
+    if (currentIndex == maxIndex) {
+        return currentIndex;
+    }
+
+    // Calculate the index of the last column inside the row of the current index
+    int lastColumnIndex = currentIndex;
+    while (keyboardAnchorPos(lastColumnIndex + 1) > keyboardAnchorPos(lastColumnIndex)) {
+        ++lastColumnIndex;
+        if (lastColumnIndex >= maxIndex) {
+            return currentIndex;
+        }
+    }
+
+    // Based on the last column index go to the next row and calculate the nearest index
+    // that is below the current index
+    int nextRowIndex = lastColumnIndex + 1;
+    int searchIndex = nextRowIndex;
+    qreal minDiff = qAbs(m_keyboardAnchorXPos - keyboardAnchorPos(nextRowIndex));
+    while (searchIndex < maxIndex && keyboardAnchorPos(searchIndex + 1) > keyboardAnchorPos(searchIndex)) {
+        ++searchIndex;
+        const qreal searchDiff = qAbs(m_keyboardAnchorXPos - keyboardAnchorPos(searchIndex));
+        if (searchDiff < minDiff) {
+            minDiff = searchDiff;
+            nextRowIndex = searchIndex;
+        }
+    }
+
+    return nextRowIndex;
+}
+
+int KItemListController::previousRowIndex() const
+{
+    const int currentIndex = m_selectionManager->currentItem();
+    if (m_keyboardAnchorIndex < 0 || currentIndex == 0) {
+        return currentIndex;
+    }
+
+    // Calculate the index of the first column inside the row of the current index
+    int firstColumnIndex = currentIndex;
+    while (keyboardAnchorPos(firstColumnIndex - 1) < keyboardAnchorPos(firstColumnIndex)) {
+        --firstColumnIndex;
+        if (firstColumnIndex <= 0) {
+            return currentIndex;
+        }
+    }
+
+    // Based on the first column index go to the previous row and calculate the nearest index
+    // that is above the current index
+    int previousRowIndex = firstColumnIndex - 1;
+    int searchIndex = previousRowIndex;
+    qreal minDiff = qAbs(m_keyboardAnchorXPos - keyboardAnchorPos(previousRowIndex));
+    while (searchIndex > 0 && keyboardAnchorPos(searchIndex - 1) < keyboardAnchorPos(searchIndex)) {
+        --searchIndex;
+        const qreal searchDiff = qAbs(m_keyboardAnchorXPos - keyboardAnchorPos(searchIndex));
+        if (searchDiff < minDiff) {
+            minDiff = searchDiff;
+            previousRowIndex = searchIndex;
+        }
+    }
+
+    return previousRowIndex;
+}
+
+qreal KItemListController::keyboardAnchorPos(int index) const
+{
+    const QRectF itemRect = m_view->itemRect(index);
+    if (!itemRect.isEmpty()) {
+        return (m_view->scrollOrientation() == Qt::Vertical) ? itemRect.x() : itemRect.y();
+    }
+
+    return 0;
+}
+
 #include "kitemlistcontroller.moc"
index e0e8b0a9ba5291a2086618942d4e5bdd6fb70898..b2c7d65b2e595b7df70f3fc12df9cc94c851875e 100644 (file)
@@ -220,6 +220,34 @@ private:
      */
     KItemListWidget* widgetForPos(const QPointF& pos) const;
 
+    /**
+     * Updates m_keyboardAnchorIndex and m_keyboardAnchorPos. If no anchor is
+     * set, it will be adjusted to the current item. If it is set it will be
+     * checked whether it is still valid, otherwise it will be reset to the
+     * current item.
+     */
+    void updateKeyboardAnchor();
+
+    /**
+     * @return Index for the next row based on the current index.
+     *         If there is no next row the current index will be returned.
+     */
+    int nextRowIndex() const;
+
+    /**
+     * @return Index for the previous row based on the current index.
+     *         If there is no previous row the current index will be returned.
+     */
+    int previousRowIndex() const;
+
+    /**
+     * Helper method for updateKeyboardAnchor(), previousRowIndex() and nextRowIndex().
+     * @return The position of the keyboard anchor for the item with the index \a index.
+     *         If a horizontal scrolling is used the y-position of the item will be returned,
+     *         for the vertical scrolling the x-position will be returned.
+     */
+    qreal keyboardAnchorPos(int index) const;
+
 private:
     bool m_selectionTogglePressed;
     SelectionBehavior m_selectionBehavior;
@@ -235,10 +263,27 @@ private:
     /**
      * When starting a rubberband selection during a Shift- or Control-key has been
      * pressed the current selection should never be deleted. To be able to restore
-     * the current selection it is remembered in m_oldSelection before
+     * the current selection it is remembered in m_oldSelection before the
      * rubberband gets activated.
      */
     QSet<int> m_oldSelection;
+
+    /**
+     * Assuming a view is given with a vertical scroll-orientation, grouped items and
+     * a maximum of 4 columns:
+     *
+     *  1  2  3  4
+     *  5  6  7
+     *  8  9 10 11
+     * 12 13 14
+     *
+     * If the current index is on 4 and key-down is pressed, then item 7 gets the current
+     * item. Now when pressing key-down again item 11 should get the current item and not
+     * item 10. This makes it necessary to keep track of the requested column to have a
+     * similar behavior like in a text editor:
+     */
+    int m_keyboardAnchorIndex;
+    qreal m_keyboardAnchorXPos;
 };
 
 #endif
index 42445dcfe89951dd46e7ba08c2eee5e13e3e60c4..be03606cea158deac84f66867b79954f5a4bcc37 100644 (file)
@@ -485,11 +485,6 @@ void KItemListView::scrollToItem(int index)
     }
 }
 
-int KItemListView::itemsPerOffset() const
-{
-    return m_layouter->itemsPerOffset();
-}
-
 void KItemListView::beginTransaction()
 {
     ++m_activeTransactions;
index 90f753087a62f5334e43f6553c06df4bb3ce1cc7..d44a08c027a880a1e53faa1bcc71a367fc42b55b 100644 (file)
@@ -202,15 +202,6 @@ public:
      */
     void scrollToItem(int index);
 
-    /**
-     * @return The number of items that can be shown in parallel for one offset.
-     *         Assuming the scrolldirection is vertical then a value of 4 means
-     *         that 4 columns for items are available. Assuming the scrolldirection
-     *         is horizontal then a value of 4 means that 4 lines for items are
-     *         available.
-     */
-    int itemsPerOffset() const;
-
     void beginTransaction();
     void endTransaction();
     bool isTransactionActive() const;
index 8dbbb372aa3e3d297e19c15dcee2fa2218114122..b486a390babc89c588d92a71e8450bc3218707a9 100644 (file)
@@ -253,11 +253,6 @@ int KItemListViewLayouter::maximumVisibleItems() const
     return rows * m_columnCount;
 }
 
-int KItemListViewLayouter::itemsPerOffset() const
-{
-    return m_columnCount;
-}
-
 bool KItemListViewLayouter::isFirstGroupItem(int itemIndex) const
 {
     const_cast<KItemListViewLayouter*>(this)->doLayout();
index 109528c634d56ed08d491dc28379585c9eca8f50..3d2f1090639a03b979bb1e0353ea34f56f55ece4 100644 (file)
@@ -107,13 +107,6 @@ public:
      */
     int maximumVisibleItems() const;
 
-    /**
-     * @return Maximum number of items that can be shown in the same row
-     *          (= vertical scrolldirection) or same column
-     *          (= horizontal scrolldirection).
-     */
-    int itemsPerOffset() const;
-
     /**
      * @return True if the item with the index \p itemIndex
      *         is the first item within a group.