diff --git a/src/kitemviews/kitemlistcontainer.cpp b/src/kitemviews/kitemlistcontainer.cpp --- a/src/kitemviews/kitemlistcontainer.cpp +++ b/src/kitemviews/kitemlistcontainer.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include /** @@ -89,6 +90,8 @@ this, &KItemListContainer::slotModelChanged); connect(controller, &KItemListController::viewChanged, this, &KItemListContainer::slotViewChanged); + + QScroller::grabGesture(viewport(), QScroller::TouchGesture); } KItemListContainer::~KItemListContainer() diff --git a/src/kitemviews/kitemlistcontroller.h b/src/kitemviews/kitemlistcontroller.h --- a/src/kitemviews/kitemlistcontroller.h +++ b/src/kitemviews/kitemlistcontroller.h @@ -28,6 +28,7 @@ #include #include +#include class QTimer; class KItemModelBase; @@ -153,6 +154,9 @@ virtual bool hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform); virtual bool wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform); virtual bool resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform); + virtual bool touchBeginEvent(QTouchEvent* event, const QTransform& transform); + virtual bool touchUpdateEvent(QTouchEvent* event, const QTransform& transform); + virtual bool touchEndEvent(QTouchEvent* event, const QTransform& transform); virtual bool processEvent(QEvent* event, const QTransform& transform); signals: @@ -307,21 +311,30 @@ */ void updateExtendedSelectionRegion(); + bool onPress(const QPoint& screenPos, const Qt::KeyboardModifiers modifiers = Qt::NoModifier, const Qt::MouseButtons buttons = Qt::NoButton); + void onMove(const QPointF& pos, const Qt::MouseButtons buttons); + bool onRelease(const QPointF& pos, const Qt::KeyboardModifiers modifiers = Qt::NoModifier, const Qt::MouseButtons buttons = Qt::NoButton); + bool onDoubleClick(const QPointF& pos, const QPoint& screenPos, const int index, const Qt::MouseButton button); private: bool m_singleClickActivationEnforced; bool m_selectionTogglePressed; bool m_clearSelectionIfItemsAreNotDragged; + bool m_cancelTouchOnRelease; + bool m_touchDoubleClickInProgress; + QPointF m_touchDoubleClickStartPos; SelectionBehavior m_selectionBehavior; AutoActivationBehavior m_autoActivationBehavior; MouseDoubleClickAction m_mouseDoubleClickAction; KItemModelBase* m_model; KItemListView* m_view; KItemListSelectionManager* m_selectionManager; KItemListKeyboardSearchManager* m_keyboardManager; int m_pressedIndex; + int m_touchDoubleClickStartIndex; QPointF m_pressedMousePos; QTimer* m_autoActivationTimer; + QTimer m_touchDoubleClickTimer; /** * When starting a rubberband selection during a Shift- or Control-key has been diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -43,6 +43,8 @@ m_singleClickActivationEnforced(false), m_selectionTogglePressed(false), m_clearSelectionIfItemsAreNotDragged(false), + m_cancelTouchOnRelease(false), + m_touchDoubleClickInProgress(false), m_selectionBehavior(NoSelection), m_autoActivationBehavior(ActivationAndExpansion), m_mouseDoubleClickAction(ActivateItemOnly), @@ -67,6 +69,10 @@ m_autoActivationTimer->setInterval(-1); connect(m_autoActivationTimer, &QTimer::timeout, this, &KItemListController::slotAutoActivationTimeout); + m_touchDoubleClickTimer.setSingleShot(true); + connect(&m_touchDoubleClickTimer, &QTimer::timeout, this, [this]() { + m_touchDoubleClickInProgress = false; + }); setModel(model); setView(view); } @@ -545,188 +551,51 @@ m_pressedMousePos = transform.map(event->pos()); m_pressedIndex = m_view->itemAt(m_pressedMousePos); - emit mouseButtonPressed(m_pressedIndex, event->buttons()); + const Qt::MouseButtons buttons = event->buttons(); + emit mouseButtonPressed(m_pressedIndex, buttons); - if (event->buttons() & (Qt::BackButton | Qt::ForwardButton)) { + if (buttons & (Qt::BackButton | Qt::ForwardButton)) { // Do not select items when clicking the back/forward buttons, see // https://bugs.kde.org/show_bug.cgi?id=327412. return true; } - if (m_view->isAboveExpansionToggle(m_pressedIndex, m_pressedMousePos)) { - m_selectionManager->endAnchoredSelection(); - m_selectionManager->setCurrentItem(m_pressedIndex); - m_selectionManager->beginAnchoredSelection(m_pressedIndex); - return true; - } - - 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; - } - - const bool shiftPressed = event->modifiers() & Qt::ShiftModifier; - const bool controlPressed = event->modifiers() & Qt::ControlModifier; - - // The previous selection is cleared if either - // 1. The selection mode is SingleSelection, or - // 2. the selection mode is MultiSelection, and *none* of the following conditions are met: - // a) Shift or Control are pressed. - // b) The clicked item is selected already. In that case, the user might want to: - // - start dragging multiple items, or - // - open the context menu and perform an action for all selected items. - const bool shiftOrControlPressed = shiftPressed || controlPressed; - const bool pressedItemAlreadySelected = m_pressedIndex >= 0 && m_selectionManager->isSelected(m_pressedIndex); - const bool clearSelection = m_selectionBehavior == SingleSelection || - (!shiftOrControlPressed && !pressedItemAlreadySelected); - if (clearSelection) { - m_selectionManager->clearSelection(); - } else if (pressedItemAlreadySelected && !shiftOrControlPressed && (event->buttons() & Qt::LeftButton)) { - // The user might want to start dragging multiple items, but if he clicks the item - // in order to trigger it instead, the other selected items must be deselected. - // However, we do not know yet what the user is going to do. - // -> remember that the user pressed an item which had been selected already and - // clear the selection in mouseReleaseEvent(), unless the items are dragged. - m_clearSelectionIfItemsAreNotDragged = true; - - if (m_selectionManager->selectedItems().count() == 1 && m_view->isAboveText(m_pressedIndex, m_pressedMousePos)) { - emit selectedItemTextPressed(m_pressedIndex); - } - } - - 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 && !shiftPressed) { - 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); + if (!onPress(event->screenPos(), event->modifiers(), buttons)) { + if (m_selectionBehavior == MultiSelection) { + QPointF startPos = m_pressedMousePos; + if (m_view->scrollOrientation() == Qt::Vertical) { + startPos.ry() += m_view->scrollOffset(); + 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->scrollOffset(); } - break; - - default: - Q_ASSERT(false); - break; - } - if (event->buttons() & Qt::RightButton) { - emit itemContextMenuRequested(m_pressedIndex, event->screenPos()); + m_oldSelection = m_selectionManager->selectedItems(); + KItemListRubberBand* rubberBand = m_view->rubberBand(); + rubberBand->setStartPosition(startPos); + rubberBand->setEndPosition(startPos); + rubberBand->setActive(true); + connect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged); + m_view->setAutoScroll(true); } - return true; - } - - if (event->buttons() & Qt::RightButton) { - const QRectF headerBounds = m_view->headerBoundaries(); - if (headerBounds.contains(event->pos())) { - emit headerContextMenuRequested(event->screenPos()); - } else { - emit viewContextMenuRequested(event->screenPos()); - } - return true; - } - - if (m_selectionBehavior == MultiSelection) { - QPointF startPos = m_pressedMousePos; - if (m_view->scrollOrientation() == Qt::Vertical) { - startPos.ry() += m_view->scrollOffset(); - 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->scrollOffset(); - } - - m_oldSelection = m_selectionManager->selectedItems(); - KItemListRubberBand* rubberBand = m_view->rubberBand(); - rubberBand->setStartPosition(startPos); - rubberBand->setEndPosition(startPos); - rubberBand->setActive(true); - connect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged); - m_view->setAutoScroll(true); + return false; } - return false; + return true; } bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform) { if (!m_view) { return false; } - if (m_pressedIndex >= 0) { - // Check whether a dragging should be started - if (event->buttons() & Qt::LeftButton) { - const QPointF pos = transform.map(event->pos()); - if ((pos - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) { - if (!m_selectionManager->isSelected(m_pressedIndex)) { - // Always assure that the dragged item gets selected. Usually this is already - // done on the mouse-press event, but when using the selection-toggle on a - // selected item the dragged item is not selected yet. - m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle); - } else { - // A selected item has been clicked to drag all selected items - // -> the selection should not be cleared when the mouse button is released. - m_clearSelectionIfItemsAreNotDragged = false; - } - - startDragging(); - } - } - } else { - KItemListRubberBand* rubberBand = m_view->rubberBand(); - if (rubberBand->isActive()) { - QPointF endPos = transform.map(event->pos()); - - // Update the current item. - const int newCurrent = m_view->itemAt(endPos); - if (newCurrent >= 0) { - // It's expected that the new current index is also the new anchor (bug 163451). - m_selectionManager->endAnchoredSelection(); - m_selectionManager->setCurrentItem(newCurrent); - m_selectionManager->beginAnchoredSelection(newCurrent); - } - - if (m_view->scrollOrientation() == Qt::Vertical) { - endPos.ry() += m_view->scrollOffset(); - 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->scrollOffset(); - } - rubberBand->setEndPosition(endPos); - } - } - + onMove(transform.map(event->pos()), event->buttons()); return false; } @@ -738,107 +607,15 @@ emit mouseButtonReleased(m_pressedIndex, event->buttons()); - const bool isAboveSelectionToggle = m_view->isAboveSelectionToggle(m_pressedIndex, m_pressedMousePos); - if (isAboveSelectionToggle) { - m_selectionTogglePressed = false; - return true; - } - - if (!isAboveSelectionToggle && m_selectionTogglePressed) { - m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle); - m_selectionTogglePressed = false; - return true; - } - - const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier || - event->modifiers() & Qt::ControlModifier; - - KItemListRubberBand* rubberBand = m_view->rubberBand(); - if (rubberBand->isActive()) { - disconnect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged); - rubberBand->setActive(false); - m_oldSelection.clear(); - m_view->setAutoScroll(false); - } - - const QPointF pos = transform.map(event->pos()); - const int index = m_view->itemAt(pos); - - if (index >= 0 && index == m_pressedIndex) { - // The release event is done above the same item as the press event - - if (m_clearSelectionIfItemsAreNotDragged) { - // A selected item has been clicked, but no drag operation has been started - // -> clear the rest of the selection. - m_selectionManager->clearSelection(); - m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Select); - m_selectionManager->beginAnchoredSelection(m_pressedIndex); - } - - if (event->button() & Qt::LeftButton) { - bool emitItemActivated = true; - if (m_view->isAboveExpansionToggle(index, pos)) { - const bool expanded = m_model->isExpanded(index); - m_model->setExpanded(index, !expanded); - - emit itemExpansionToggleClicked(index); - emitItemActivated = false; - } else if (shiftOrControlPressed) { - // The mouse click should only update the selection, not trigger the item - emitItemActivated = false; - } else if (!(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced)) { - emitItemActivated = false; - } - if (emitItemActivated) { - emit itemActivated(index); - } - } else if (event->button() & Qt::MidButton) { - emit itemMiddleClicked(index); - } - } - - m_pressedMousePos = QPointF(); - m_pressedIndex = -1; - m_clearSelectionIfItemsAreNotDragged = false; - return false; + return onRelease(transform.map(event->pos()), event->modifiers(), event->button()); } bool KItemListController::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform) { const QPointF pos = transform.map(event->pos()); const int index = m_view->itemAt(pos); - // Expand item if desired - See Bug 295573 - if (m_mouseDoubleClickAction != ActivateItemOnly) { - if (m_view && m_model && m_view->supportsItemExpanding() && m_model->isExpandable(index)) { - const bool expanded = m_model->isExpanded(index); - m_model->setExpanded(index, !expanded); - } - } - - if (event->button() & Qt::RightButton) { - m_selectionManager->clearSelection(); - if (index >= 0) { - m_selectionManager->setSelected(index); - emit itemContextMenuRequested(index, event->screenPos()); - } else { - const QRectF headerBounds = m_view->headerBoundaries(); - if (headerBounds.contains(event->pos())) { - emit headerContextMenuRequested(event->screenPos()); - } else { - emit viewContextMenuRequested(event->screenPos()); - } - } - return true; - } - - bool emitItemActivated = !(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced) && - (event->button() & Qt::LeftButton) && - index >= 0 && index < m_model->count(); - if (emitItemActivated) { - emit itemActivated(index); - } - return false; + return onDoubleClick(pos, event->screenPos(), index, event->button()); } bool KItemListController::dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform) @@ -1035,6 +812,75 @@ return false; } +bool KItemListController::touchBeginEvent(QTouchEvent* event, const QTransform& transform) +{ + if (!m_view) { + return false; + } + + const QTouchEvent::TouchPoint& touchPoint = event->touchPoints()[0]; + + m_pressedMousePos = transform.map(touchPoint.pos()); + m_pressedIndex = m_view->itemAt(m_pressedMousePos); + onPress(touchPoint.screenPos().toPoint(), event->modifiers()); + return true; +} + +bool KItemListController::touchUpdateEvent(QTouchEvent* event, const QTransform& transform) +{ + if (!m_view) { + return false; + } + + const auto touchState = event->touchPointStates(); + + if (event->touchPoints().length() > 1) { + return true; + } + if (touchState & Qt::TouchPointMoved) { + if (!m_cancelTouchOnRelease) { + const QPointF& pos = transform.map(event->touchPoints()[0].pos()); + // allow finger to fumble about a bit, but beyond the threshold suppress on release action + if ((m_pressedMousePos - pos).manhattanLength() >= QApplication::startDragDistance()) { + m_cancelTouchOnRelease = true; + } + } + } + return true; +} + +bool KItemListController::touchEndEvent(QTouchEvent* event, const QTransform& transform) +{ + if (!m_view) { + return false; + } + + if (m_cancelTouchOnRelease) { + m_cancelTouchOnRelease = false; + return true; + } + + const QTouchEvent::TouchPoint& touchPoint = event->touchPoints()[0]; + const QPointF pos = transform.map(touchPoint.pos()); + const int index = m_view->itemAt(pos); + if (m_touchDoubleClickInProgress) { + if ( + (index >= 0 && index == m_touchDoubleClickStartIndex) || + (pos - m_touchDoubleClickStartPos).manhattanLength() < 20 + ) { + onDoubleClick(pos, touchPoint.screenPos().toPoint(), m_pressedIndex, Qt::LeftButton); + } + } else { + m_touchDoubleClickInProgress = true; + } + m_touchDoubleClickStartPos = pos; + m_touchDoubleClickStartIndex = index; + m_touchDoubleClickTimer.start(QApplication::doubleClickInterval()); + + onRelease(pos, event->modifiers(), Qt::LeftButton); + return true; +} + bool KItemListController::processEvent(QEvent* event, const QTransform& transform) { if (!event) { @@ -1072,6 +918,12 @@ return hoverLeaveEvent(static_cast(event), QTransform()); case QEvent::GraphicsSceneResize: return resizeEvent(static_cast(event), transform); + case QEvent::TouchBegin: + return touchBeginEvent(static_cast(event), QTransform()); + case QEvent::TouchUpdate: + return touchUpdateEvent(static_cast(event), QTransform()); + case QEvent::TouchEnd: + return touchEndEvent(static_cast(event), QTransform()); default: break; } @@ -1352,3 +1204,249 @@ } } +bool KItemListController::onPress(const QPoint& screenPos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons) +{ + if (m_view->isAboveExpansionToggle(m_pressedIndex, m_pressedMousePos)) { + m_selectionManager->endAnchoredSelection(); + m_selectionManager->setCurrentItem(m_pressedIndex); + m_selectionManager->beginAnchoredSelection(m_pressedIndex); + return true; + } + + 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; + } + + const bool shiftPressed = modifiers & Qt::ShiftModifier; + const bool controlPressed = modifiers & Qt::ControlModifier; + + // The previous selection is cleared if either + // 1. The selection mode is SingleSelection, or + // 2. the selection mode is MultiSelection, and *none* of the following conditions are met: + // a) Shift or Control are pressed. + // b) The clicked item is selected already. In that case, the user might want to: + // - start dragging multiple items, or + // - open the context menu and perform an action for all selected items. + const bool shiftOrControlPressed = shiftPressed || controlPressed; + const bool pressedItemAlreadySelected = m_pressedIndex >= 0 && m_selectionManager->isSelected(m_pressedIndex); + const bool clearSelection = m_selectionBehavior == SingleSelection || + (!shiftOrControlPressed && !pressedItemAlreadySelected); + if (clearSelection) { + m_selectionManager->clearSelection(); + } else if (pressedItemAlreadySelected && !shiftOrControlPressed && (buttons & Qt::LeftButton)) { + // The user might want to start dragging multiple items, but if he clicks the item + // in order to trigger it instead, the other selected items must be deselected. + // However, we do not know yet what the user is going to do. + // -> remember that the user pressed an item which had been selected already and + // clear the selection in mouseReleaseEvent(), unless the items are dragged. + m_clearSelectionIfItemsAreNotDragged = true; + + if (m_selectionManager->selectedItems().count() == 1 && m_view->isAboveText(m_pressedIndex, m_pressedMousePos)) { + emit selectedItemTextPressed(m_pressedIndex); + } + } + + 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 && !shiftPressed) { + 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; + } + + if (buttons & Qt::RightButton) { + emit itemContextMenuRequested(m_pressedIndex, screenPos); + } + + return true; + } + + if (buttons & Qt::RightButton) { + const QRectF headerBounds = m_view->headerBoundaries(); + if (headerBounds.contains(m_pressedMousePos)) { + emit headerContextMenuRequested(screenPos); + } else { + emit viewContextMenuRequested(screenPos); + } + return true; + } + + return false; +} + +void KItemListController::onMove(const QPointF& pos, const Qt::MouseButtons buttons) +{ + if (m_pressedIndex >= 0) { + // Check whether a dragging should be started + if (buttons & Qt::LeftButton) { + if ((pos - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) { + if (!m_selectionManager->isSelected(m_pressedIndex)) { + // Always assure that the dragged item gets selected. Usually this is already + // done on the mouse-press event, but when using the selection-toggle on a + // selected item the dragged item is not selected yet. + m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle); + } else { + // A selected item has been clicked to drag all selected items + // -> the selection should not be cleared when the mouse button is released. + m_clearSelectionIfItemsAreNotDragged = false; + } + + startDragging(); + } + } + } else { + KItemListRubberBand* rubberBand = m_view->rubberBand(); + if (rubberBand->isActive()) { + // Update the current item. + QPointF endPos(pos); + const int newCurrent = m_view->itemAt(endPos); + if (newCurrent >= 0) { + // It's expected that the new current index is also the new anchor (bug 163451). + m_selectionManager->endAnchoredSelection(); + m_selectionManager->setCurrentItem(newCurrent); + m_selectionManager->beginAnchoredSelection(newCurrent); + } + + if (m_view->scrollOrientation() == Qt::Vertical) { + endPos.ry() += m_view->scrollOffset(); + 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->scrollOffset(); + } + rubberBand->setEndPosition(endPos); + } + } +} + +bool KItemListController::onRelease(const QPointF& pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons button) +{ + const bool isAboveSelectionToggle = m_view->isAboveSelectionToggle(m_pressedIndex, m_pressedMousePos); + if (isAboveSelectionToggle) { + m_selectionTogglePressed = false; + return true; + } + + if (!isAboveSelectionToggle && m_selectionTogglePressed) { + m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle); + m_selectionTogglePressed = false; + return true; + } + + const bool shiftOrControlPressed = modifiers & Qt::ShiftModifier || + modifiers & Qt::ControlModifier; + + KItemListRubberBand* rubberBand = m_view->rubberBand(); + if (rubberBand->isActive()) { + disconnect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged); + rubberBand->setActive(false); + m_oldSelection.clear(); + m_view->setAutoScroll(false); + } + + const int index = m_view->itemAt(pos); + + if (index >= 0 && index == m_pressedIndex) { + // The release event is done above the same item as the press event + + if (m_clearSelectionIfItemsAreNotDragged) { + // A selected item has been clicked, but no drag operation has been started + // -> clear the rest of the selection. + m_selectionManager->clearSelection(); + m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Select); + m_selectionManager->beginAnchoredSelection(m_pressedIndex); + } + + if (button & Qt::LeftButton) { + if (m_view->isAboveExpansionToggle(index, pos)) { + const bool expanded = m_model->isExpanded(index); + m_model->setExpanded(index, !expanded); + + emit itemExpansionToggleClicked(index); + } else if ( + !shiftOrControlPressed && ( + m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || + m_singleClickActivationEnforced + ) + ) { + emit itemActivated(index); + } + } else if (button & Qt::MidButton) { + emit itemMiddleClicked(index); + } + } + + m_pressedMousePos = QPointF(); + m_pressedIndex = -1; + m_clearSelectionIfItemsAreNotDragged = false; + return false; +} + +bool KItemListController::onDoubleClick(const QPointF& pos, const QPoint& screenPos, const int index, const Qt::MouseButton button) +{ + // Expand item if desired - See Bug 295573 + if (m_mouseDoubleClickAction != ActivateItemOnly) { + if (m_view && m_model && m_view->supportsItemExpanding() && m_model->isExpandable(index)) { + const bool expanded = m_model->isExpanded(index); + m_model->setExpanded(index, !expanded); + } + } + + if (button & Qt::RightButton) { + m_selectionManager->clearSelection(); + if (index >= 0) { + m_selectionManager->setSelected(index); + emit itemContextMenuRequested(index, screenPos); + } else { + const QRectF headerBounds = m_view->headerBoundaries(); + if (headerBounds.contains(pos)) { + emit headerContextMenuRequested(screenPos); + } else { + emit viewContextMenuRequested(screenPos); + } + } + return true; + } + + bool emitItemActivated = !(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced) && + (button & Qt::LeftButton) && + index >= 0 && index < m_model->count(); + if (emitItemActivated) { + emit itemActivated(index); + } + return false; +} diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -102,6 +102,7 @@ m_dropIndicator() { setAcceptHoverEvents(true); + setAcceptTouchEvents(true); m_sizeHintResolver = new KItemListSizeHintResolver(this); diff --git a/src/panels/information/informationpanelcontent.cpp b/src/panels/information/informationpanelcontent.cpp --- a/src/panels/information/informationpanelcontent.cpp +++ b/src/panels/information/informationpanelcontent.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include "dolphin_informationpanelsettings.h" @@ -125,6 +126,7 @@ m_metaDataArea->setFrameShape(QFrame::NoFrame); QWidget* viewport = m_metaDataArea->viewport(); + QScroller::grabGesture(viewport, QScroller::TouchGesture); viewport->installEventFilter(this); layout->addWidget(m_preview); diff --git a/src/settings/general/previewssettingspage.cpp b/src/settings/general/previewssettingspage.cpp --- a/src/settings/general/previewssettingspage.cpp +++ b/src/settings/general/previewssettingspage.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,7 @@ QLabel* showPreviewsLabel = new QLabel(i18nc("@title:group", "Show previews in the view for:"), this); m_listView = new QListView(this); + QScroller::grabGesture(m_listView->viewport(), QScroller::TouchGesture); ServiceItemDelegate* delegate = new ServiceItemDelegate(m_listView, m_listView); connect(delegate, &ServiceItemDelegate::requestServiceConfiguration, @@ -64,6 +66,7 @@ m_listView->setModel(proxyModel); m_listView->setItemDelegate(delegate); + m_listView->setUniformItemSizes(true); m_listView->setVerticalScrollMode(QListView::ScrollPerPixel); QLabel* remoteFileSizeLabel = new QLabel(i18nc("@label", "Skip previews for remote files above:"), this); diff --git a/src/settings/services/servicessettingspage.cpp b/src/settings/services/servicessettingspage.cpp --- a/src/settings/services/servicessettingspage.cpp +++ b/src/settings/services/servicessettingspage.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include namespace @@ -62,6 +63,7 @@ label->setWordWrap(true); m_listView = new QListView(this); + QScroller::grabGesture(m_listView->viewport(), QScroller::TouchGesture); ServiceItemDelegate* delegate = new ServiceItemDelegate(m_listView, m_listView); m_serviceModel = new ServiceModel(this); m_sortModel = new QSortFilterProxyModel(this);