X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/9d5d18739fde76f2d606a4cc9f1e7cc442faa7e0..c8d8556950005dfd96ebdb41d2f43ad90356367c:/src/kitemviews/kitemlistcontroller.cpp diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index e77de292a..026c245f5 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -30,7 +30,9 @@ #include #include #include +#include #include +#include #include #include @@ -48,7 +50,9 @@ KItemListController::KItemListController(QObject* parent) : m_pressedIndex(-1), m_pressedMousePos(), m_autoActivationTimer(0), - m_oldSelection() + m_oldSelection(), + m_keyboardAnchorIndex(-1), + m_keyboardAnchorPos(0) { connect(m_keyboardManager, SIGNAL(changeCurrentItem(QString,bool)), this, SLOT(slotChangeCurrentItem(QString,bool))); @@ -173,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. @@ -186,6 +189,16 @@ bool KItemListController::keyPressEvent(QKeyEvent* event) default: break; } } + + const bool selectSingleItem = itemCount == 1 && + (key == Qt::Key_Home || key == Qt::Key_End || + key == Qt::Key_Up || key == Qt::Key_Down || + key == Qt::Key_Left || key == Qt::Key_Right); + if (selectSingleItem) { + const int current = m_selectionManager->currentItem(); + m_selectionManager->setSelected(current); + return true; + } switch (key) { case Qt::Key_Home: @@ -198,38 +211,28 @@ bool KItemListController::keyPressEvent(QKeyEvent* event) case Qt::Key_Left: if (index > 0) { - index--; + --index; + m_keyboardAnchorIndex = index; + m_keyboardAnchorPos = keyboardAnchorPos(index); } break; case Qt::Key_Right: if (index < itemCount - 1) { - index++; + ++index; + m_keyboardAnchorIndex = index; + m_keyboardAnchorPos = 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: @@ -250,9 +253,35 @@ bool KItemListController::keyPressEvent(QKeyEvent* event) m_selectionManager->endAnchoredSelection(); m_selectionManager->setSelected(index, 1, KItemListSelectionManager::Toggle); m_selectionManager->beginAnchoredSelection(index); - break; + } else { + const int current = m_selectionManager->currentItem(); + m_selectionManager->setSelected(current); + } + break; + + case Qt::Key_Menu: { + // Emit the signal itemContextMenuRequested() in case if at least one + // item is selected. Otherwise the signal viewContextMenuRequested() will be emitted. + const QSet selectedItems = m_selectionManager->selectedItems(); + int index = -1; + if (selectedItems.count() >= 2) { + const int currentItemIndex = m_selectionManager->currentItem(); + index = selectedItems.contains(currentItemIndex) + ? currentItemIndex : selectedItems.toList().first(); + } else if (selectedItems.count() == 1) { + index = selectedItems.toList().first(); } + if (index >= 0) { + const QRectF contextRect = m_view->itemContextRect(index); + const QPointF pos(m_view->scene()->views().first()->mapToGlobal(contextRect.bottomRight().toPoint())); + emit itemContextMenuRequested(index, pos); + } else { + emit viewContextMenuRequested(QCursor::pos()); + } + break; + } + default: m_keyboardManager->addKeys(event->text()); return false; @@ -288,8 +317,7 @@ void KItemListController::slotChangeCurrentItem(const QString& text, bool search int index; if (searchFromNextItem) { index = m_model->indexForKeyboardSearch(text, (currentIndex + 1) % m_model->count()); - } - else { + } else { index = m_model->indexForKeyboardSearch(text, currentIndex); } if (index >= 0) { @@ -297,6 +325,7 @@ void KItemListController::slotChangeCurrentItem(const QString& text, bool search m_selectionManager->clearSelection(); m_selectionManager->setSelected(index, 1); m_selectionManager->beginAnchoredSelection(index); + m_view->scrollToItem(index); } } @@ -335,6 +364,9 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const m_pressedMousePos = transform.map(event->pos()); m_pressedIndex = m_view->itemAt(m_pressedMousePos); + if (m_pressedIndex >= 0) { + emit itemPressed(m_pressedIndex, event->button()); + } if (m_view->isAboveExpansionToggle(m_pressedIndex, m_pressedMousePos)) { m_selectionManager->setCurrentItem(m_pressedIndex); @@ -344,7 +376,11 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const m_selectionTogglePressed = m_view->isAboveSelectionToggle(m_pressedIndex, m_pressedMousePos); if (m_selectionTogglePressed) { m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle); + // The previous anchored selection has been finished already in + // KItemListSelectionManager::setSelected(). We can safely change + // the current item and start a new anchored selection now. m_selectionManager->setCurrentItem(m_pressedIndex); + m_selectionManager->beginAnchoredSelection(m_pressedIndex); return true; } @@ -497,6 +533,10 @@ bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, con return false; } + if (m_pressedIndex >= 0) { + emit itemReleased(m_pressedIndex, event->button()); + } + const bool isAboveSelectionToggle = m_view->isAboveSelectionToggle(m_pressedIndex, m_pressedMousePos); if (isAboveSelectionToggle) { m_selectionTogglePressed = false; @@ -874,7 +914,7 @@ void KItemListController::startDragging() const QPixmap pixmap = m_view->createDragPixmap(selectedItems); drag->setPixmap(pixmap); - drag->exec(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction, Qt::IgnoreAction); + drag->exec(Qt::CopyAction); } KItemListWidget* KItemListController::hoveredWidget() const @@ -907,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_keyboardAnchorPos; + if (!validAnchor) { + const int index = m_selectionManager->currentItem(); + m_keyboardAnchorIndex = index; + m_keyboardAnchorPos = 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_keyboardAnchorPos - keyboardAnchorPos(nextRowIndex)); + while (searchIndex < maxIndex && keyboardAnchorPos(searchIndex + 1) > keyboardAnchorPos(searchIndex)) { + ++searchIndex; + const qreal searchDiff = qAbs(m_keyboardAnchorPos - 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_keyboardAnchorPos - keyboardAnchorPos(previousRowIndex)); + while (searchIndex > 0 && keyboardAnchorPos(searchIndex - 1) < keyboardAnchorPos(searchIndex)) { + --searchIndex; + const qreal searchDiff = qAbs(m_keyboardAnchorPos - 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"