X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/71ccc7e36139dbd4c9beb2b1142d555d256feb6a..dbe2152912cc58f1d2bfba187175ec0e4b3e4761:/src/kitemviews/kitemlistcontroller.cpp diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index 91fb86806..7331131a9 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -23,11 +23,11 @@ #include "kitemlistcontroller.h" #include "kitemlistview.h" +#include "kitemlistrubberband_p.h" #include "kitemlistselectionmanager.h" #include #include -#include #include @@ -80,11 +80,16 @@ void KItemListController::setView(KItemListView* view) } KItemListView* oldView = m_view; + if (oldView) { + disconnect(oldView, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(slotViewOffsetChanged(qreal,qreal))); + } + m_view = view; if (m_view) { m_view->setController(this); m_view->setModel(m_model); + connect(m_view, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(slotViewOffsetChanged(qreal,qreal))); } emit viewChanged(m_view, oldView); @@ -119,8 +124,100 @@ bool KItemListController::hideEvent(QHideEvent* event) bool KItemListController::keyPressEvent(QKeyEvent* event) { - Q_UNUSED(event); - return false; + const bool shiftPressed = event->modifiers() & Qt::ShiftModifier; + const bool controlPressed = event->modifiers() & Qt::ControlModifier; + const bool shiftOrControlPressed = shiftPressed || controlPressed; + + int index = m_selectionManager->currentItem(); + 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. + int key = event->key(); + if (m_view->scrollOrientation() == Qt::Horizontal) { + switch (key) { + case Qt::Key_Up: key = Qt::Key_Left; break; + case Qt::Key_Down: key = Qt::Key_Right; break; + case Qt::Key_Left: key = Qt::Key_Up; break; + case Qt::Key_Right: key = Qt::Key_Down; break; + default: break; + } + } + + switch (key) { + case Qt::Key_Home: + index = 0; + break; + + case Qt::Key_End: + index = itemCount - 1; + break; + + case Qt::Key_Left: + if (index > 0) { + index--; + } + break; + + case Qt::Key_Right: + if (index < itemCount - 1) { + index++; + } + break; + + case Qt::Key_Up: + if (index >= itemsPerRow) { + index -= itemsPerRow; + } + 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; + } + } + break; + + case Qt::Key_Space: + if (controlPressed) { + m_selectionManager->endAnchoredSelection(); + m_selectionManager->setSelected(index, 1, KItemListSelectionManager::Toggle); + m_selectionManager->beginAnchoredSelection(index); + } + + default: + break; + } + + if (m_selectionManager->currentItem() != index) { + if (controlPressed) { + m_selectionManager->endAnchoredSelection(); + } + + m_selectionManager->setCurrentItem(index); + + if (!shiftOrControlPressed || m_selectionBehavior == SingleSelection) { + m_selectionManager->clearSelection(); + m_selectionManager->setSelected(index, 1); + } + + if (!shiftPressed) { + m_selectionManager->beginAnchoredSelection(index); + } + } + return true; } bool KItemListController::inputMethodEvent(QInputMethodEvent* event) @@ -131,38 +228,125 @@ bool KItemListController::inputMethodEvent(QInputMethodEvent* event) bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform) { - Q_UNUSED(event); - Q_UNUSED(transform); + if (!m_view) { + return false; + } + const QPointF pos = transform.map(event->pos()); m_pressedIndex = m_view->itemAt(pos); + + if (m_view->isAboveExpansionToggle(m_pressedIndex, pos)) { + return true; + } + + const bool shiftPressed = event->modifiers() & Qt::ShiftModifier; + const bool controlPressed = event->modifiers() & Qt::ControlModifier; + const bool shiftOrControlPressed = shiftPressed || controlPressed; + + if (!shiftOrControlPressed || m_selectionBehavior == SingleSelection) { + m_selectionManager->clearSelection(); + } + + if (!shiftPressed) { + // Finish the anchored selection before the current index is changed + m_selectionManager->endAnchoredSelection(); + } + + if (m_pressedIndex >= 0) { + m_selectionManager->setCurrentItem(m_pressedIndex); + + switch (m_selectionBehavior) { + case NoSelection: + break; + + case SingleSelection: + m_selectionManager->setSelected(m_pressedIndex); + break; + + case MultiSelection: + if (controlPressed) { + m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle); + m_selectionManager->beginAnchoredSelection(m_pressedIndex); + } else if (!shiftPressed || !m_selectionManager->isAnchoredSelectionActive()) { + // Select the pressed item and start a new anchored selection + m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Select); + m_selectionManager->beginAnchoredSelection(m_pressedIndex); + } + break; + + default: + Q_ASSERT(false); + break; + } + + return true; + } else { + KItemListRubberBand* rubberBand = m_view->rubberBand(); + QPointF startPos = pos; + if (m_view->scrollOrientation() == Qt::Vertical) { + startPos.ry() += m_view->offset(); + } else { + startPos.rx() += m_view->offset(); + } + rubberBand->setStartPosition(startPos); + rubberBand->setEndPosition(startPos); + rubberBand->setActive(true); + } + return false; } bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform) { - Q_UNUSED(event); - Q_UNUSED(transform); + if (!m_view) { + return false; + } + + KItemListRubberBand* rubberBand = m_view->rubberBand(); + if (rubberBand->isActive()) { + QPointF endPos = transform.map(event->pos()); + if (m_view->scrollOrientation() == Qt::Vertical) { + endPos.ry() += m_view->offset(); + } else { + endPos.rx() += m_view->offset(); + } + rubberBand->setEndPosition(endPos); + } + return false; } bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform) { - if (m_view) { - const QPointF pos = transform.map(event->pos()); - const int index = m_view->itemAt(pos); - if (index >= 0 && index == m_pressedIndex) { - bool emitItemClicked = true; - if (event->button() & Qt::LeftButton) { - if (m_view->isAboveExpansionToggle(index, pos)) { - emit itemExpansionToggleClicked(index); - emitItemClicked = false; - } - } + if (!m_view) { + return false; + } + + m_view->rubberBand()->setActive(false); - if (emitItemClicked) { - emit itemClicked(index, event->button()); + const QPointF pos = transform.map(event->pos()); + const int index = m_view->itemAt(pos); + const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier || event->modifiers() & Qt::ControlModifier; + + if (index >= 0 && index == m_pressedIndex) { + // The release event is done above the same item as the press event + bool emitItemClicked = true; + if (event->button() & Qt::LeftButton) { + if (m_view->isAboveExpansionToggle(index, pos)) { + emit itemExpansionToggleClicked(index); + emitItemClicked = false; + } + else if (shiftOrControlPressed) { + // The mouse click should only update the selection, not trigger the item + emitItemClicked = false; } } + + if (emitItemClicked) { + emit itemClicked(index, event->button()); + } + } else if (!shiftOrControlPressed) { + m_selectionManager->clearSelection(); } m_pressedIndex = -1; @@ -213,8 +397,49 @@ bool KItemListController::hoverEnterEvent(QGraphicsSceneHoverEvent* event, const bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform) { - Q_UNUSED(event); + // The implementation assumes that only one item can get hovered no matter + // whether they overlap or not. + Q_UNUSED(transform); + if (!m_model || !m_view) { + return false; + } + + // Search the previously hovered item that might get unhovered + KItemListWidget* unhoveredWidget = 0; + foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) { + if (widget->isHovered()) { + unhoveredWidget = widget; + break; + } + } + + // Search the currently hovered item + KItemListWidget* hoveredWidget = 0; + foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) { + const QPointF mappedPos = widget->mapFromItem(m_view, event->pos()); + + const bool hovered = widget->contains(mappedPos) && + !widget->expansionToggleRect().contains(mappedPos) && + !widget->selectionToggleRect().contains(mappedPos); + if (hovered) { + hoveredWidget = widget; + break; + } + } + + if (unhoveredWidget != hoveredWidget) { + if (unhoveredWidget) { + unhoveredWidget->setHovered(false); + emit itemUnhovered(unhoveredWidget->index()); + } + + if (hoveredWidget) { + hoveredWidget->setHovered(true); + emit itemHovered(hoveredWidget->index()); + } + } + return false; } @@ -222,6 +447,17 @@ bool KItemListController::hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const { Q_UNUSED(event); Q_UNUSED(transform); + + if (!m_model || !m_view) { + return false; + } + + foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) { + if (widget->isHovered()) { + widget->setHovered(false); + emit itemUnhovered(widget->index()); + } + } return false; } @@ -246,9 +482,6 @@ bool KItemListController::processEvent(QEvent* event, const QTransform& transfor } switch (event->type()) { -// case QEvent::FocusIn: -// case QEvent::FocusOut: -// return focusEvent(static_cast(event)); case QEvent::KeyPress: return keyPressEvent(static_cast(event)); case QEvent::InputMethod: @@ -284,4 +517,28 @@ bool KItemListController::processEvent(QEvent* event, const QTransform& transfor return false; } +void KItemListController::slotViewOffsetChanged(qreal current, qreal previous) +{ + if (!m_view) { + return; + } + + KItemListRubberBand* rubberBand = m_view->rubberBand(); + if (rubberBand->isActive()) { + const qreal diff = current - previous; + // TODO: Ideally just QCursor::pos() should be used as + // new end-position but it seems there is no easy way + // to have something like QWidget::mapFromGlobal() for QGraphicsWidget + // (... or I just missed an easy way to do the mapping) + QPointF endPos = rubberBand->endPosition(); + if (m_view->scrollOrientation() == Qt::Vertical) { + endPos.ry() += diff; + } else { + endPos.rx() += diff; + } + + rubberBand->setEndPosition(endPos); + } +} + #include "kitemlistcontroller.moc"