#include <KTwoFingerSwipe>
#include <KTwoFingerTap>
+#include <KUrlMimeData>
#include <QAccessible>
#include <QApplication>
#include <QTimer>
#include <QTouchEvent>
-KItemListController::KItemListController(KItemModelBase* model, KItemListView* view, QObject* parent) :
- QObject(parent),
- m_singleClickActivationEnforced(false),
- m_selectionTogglePressed(false),
- m_clearSelectionIfItemsAreNotDragged(false),
- m_isSwipeGesture(false),
- m_dragActionOrRightClick(false),
- m_scrollerIsScrolling(false),
- m_pinchGestureInProgress(false),
- m_mousePress(false),
- m_isTouchEvent(false),
- m_selectionBehavior(NoSelection),
- m_autoActivationBehavior(ActivationAndExpansion),
- m_mouseDoubleClickAction(ActivateItemOnly),
- m_model(nullptr),
- m_view(nullptr),
- m_selectionManager(new KItemListSelectionManager(this)),
- m_keyboardManager(new KItemListKeyboardSearchManager(this)),
- m_pressedIndex(std::nullopt),
- m_pressedMousePos(),
- m_autoActivationTimer(nullptr),
- m_swipeGesture(Qt::CustomGesture),
- m_twoFingerTapGesture(Qt::CustomGesture),
- m_oldSelection(),
- m_keyboardAnchorIndex(-1),
- m_keyboardAnchorPos(0)
+KItemListController::KItemListController(KItemModelBase *model, KItemListView *view, QObject *parent)
+ : QObject(parent)
+ , m_singleClickActivationEnforced(false)
+ , m_selectionMode(false)
+ , m_selectionTogglePressed(false)
+ , m_clearSelectionIfItemsAreNotDragged(false)
+ , m_isSwipeGesture(false)
+ , m_dragActionOrRightClick(false)
+ , m_scrollerIsScrolling(false)
+ , m_pinchGestureInProgress(false)
+ , m_mousePress(false)
+ , m_isTouchEvent(false)
+ , m_selectionBehavior(NoSelection)
+ , m_autoActivationBehavior(ActivationAndExpansion)
+ , m_mouseDoubleClickAction(ActivateItemOnly)
+ , m_model(nullptr)
+ , m_view(nullptr)
+ , m_selectionManager(new KItemListSelectionManager(this))
+ , m_keyboardManager(new KItemListKeyboardSearchManager(this))
+ , m_pressedIndex(std::nullopt)
+ , m_pressedMouseGlobalPos()
+ , m_autoActivationTimer(nullptr)
+ , m_swipeGesture(Qt::CustomGesture)
+ , m_twoFingerTapGesture(Qt::CustomGesture)
+ , m_oldSelection()
+ , m_keyboardAnchorIndex(-1)
+ , m_keyboardAnchorPos(0)
{
- connect(m_keyboardManager, &KItemListKeyboardSearchManager::changeCurrentItem,
- this, &KItemListController::slotChangeCurrentItem);
- connect(m_selectionManager, &KItemListSelectionManager::currentChanged,
- m_keyboardManager, &KItemListKeyboardSearchManager::slotCurrentChanged);
- connect(m_selectionManager, &KItemListSelectionManager::selectionChanged,
- m_keyboardManager, &KItemListKeyboardSearchManager::slotSelectionChanged);
+ connect(m_keyboardManager, &KItemListKeyboardSearchManager::changeCurrentItem, this, &KItemListController::slotChangeCurrentItem);
+ connect(m_selectionManager, &KItemListSelectionManager::currentChanged, m_keyboardManager, &KItemListKeyboardSearchManager::slotCurrentChanged);
+ connect(m_selectionManager, &KItemListSelectionManager::selectionChanged, m_keyboardManager, &KItemListKeyboardSearchManager::slotSelectionChanged);
m_autoActivationTimer = new QTimer(this);
m_autoActivationTimer->setSingleShot(true);
Q_ASSERT(!m_model);
}
-void KItemListController::setModel(KItemModelBase* model)
+void KItemListController::setModel(KItemModelBase *model)
{
if (m_model == model) {
return;
}
- KItemModelBase* oldModel = m_model;
+ KItemModelBase *oldModel = m_model;
if (oldModel) {
oldModel->deleteLater();
}
Q_EMIT modelChanged(m_model, oldModel);
}
-KItemModelBase* KItemListController::model() const
+KItemModelBase *KItemListController::model() const
{
return m_model;
}
-KItemListSelectionManager* KItemListController::selectionManager() const
+KItemListSelectionManager *KItemListController::selectionManager() const
{
return m_selectionManager;
}
-void KItemListController::setView(KItemListView* view)
+void KItemListController::setView(KItemListView *view)
{
if (m_view == view) {
return;
}
- KItemListView* oldView = m_view;
+ KItemListView *oldView = m_view;
if (oldView) {
disconnect(oldView, &KItemListView::scrollOffsetChanged, this, &KItemListController::slotViewScrollOffsetChanged);
oldView->deleteLater();
Q_EMIT viewChanged(m_view, oldView);
}
-KItemListView* KItemListController::view() const
+KItemListView *KItemListController::view() const
{
return m_view;
}
int KItemListController::indexCloseToMousePressedPosition() const
{
- QHashIterator<KItemListWidget*, KItemListGroupHeader*> it(m_view->m_visibleGroups);
+ const QPointF pressedMousePos = m_view->transform().map(m_view->scene()->views().first()->mapFromGlobal(m_pressedMouseGlobalPos.toPoint()));
+
+ QHashIterator<KItemListWidget *, KItemListGroupHeader *> it(m_view->m_visibleGroups);
while (it.hasNext()) {
it.next();
KItemListGroupHeader *groupHeader = it.value();
- const QPointF mappedToGroup = groupHeader->mapFromItem(nullptr, m_pressedMousePos);
+ const QPointF mappedToGroup = groupHeader->mapFromItem(nullptr, pressedMousePos);
if (groupHeader->contains(mappedToGroup)) {
return it.key()->index();
}
return m_singleClickActivationEnforced;
}
-bool KItemListController::keyPressEvent(QKeyEvent* event)
+void KItemListController::setSelectionModeEnabled(bool enabled)
+{
+ m_selectionMode = enabled;
+}
+
+bool KItemListController::selectionMode() const
+{
+ return m_selectionMode;
+}
+
+bool KItemListController::isSearchAsYouTypeActive() const
+{
+ return m_keyboardManager->isSearchAsYouTypeActive();
+}
+
+bool KItemListController::keyPressEvent(QKeyEvent *event)
{
int index = m_selectionManager->currentItem();
int key = event->key();
+ const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
// Handle the expanding/collapsing of items
- if (m_view->supportsItemExpanding() && m_model->isExpandable(index)) {
- if (key == Qt::Key_Right) {
- if (m_model->setExpanded(index, true)) {
- return true;
+ // expand / collapse all selected directories
+ if (m_view->supportsItemExpanding() && m_model->isExpandable(index) && (key == Qt::Key_Right || key == Qt::Key_Left)) {
+ const bool expandOrCollapse = key == Qt::Key_Right ? true : false;
+ bool shouldReturn = m_model->setExpanded(index, expandOrCollapse);
+
+ // edit in reverse to preserve index of the first handled items
+ const auto selectedItems = m_selectionManager->selectedItems();
+ for (auto it = selectedItems.rbegin(); it != selectedItems.rend(); ++it) {
+ shouldReturn |= m_model->setExpanded(*it, expandOrCollapse);
+ if (!shiftPressed) {
+ m_selectionManager->setSelected(*it);
}
- } else if (key == Qt::Key_Left) {
- if (m_model->setExpanded(index, false)) {
- return true;
+ }
+ if (shouldReturn) {
+ // update keyboard anchors
+ if (shiftPressed) {
+ m_keyboardAnchorIndex = selectedItems.count() > 0 ? qMin(index, selectedItems.last()) : index;
+ m_keyboardAnchorPos = keyboardAnchorPos(m_keyboardAnchorIndex);
}
+
+ event->ignore();
+ return true;
}
}
- const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
const bool controlPressed = event->modifiers() & Qt::ControlModifier;
const bool shiftOrControlPressed = shiftPressed || controlPressed;
- const bool navigationPressed = key == Qt::Key_Home || key == Qt::Key_End ||
- key == Qt::Key_PageUp || key == Qt::Key_PageDown ||
- key == Qt::Key_Up || key == Qt::Key_Down ||
- key == Qt::Key_Left || key == Qt::Key_Right;
+ const bool navigationPressed = key == Qt::Key_Home || key == Qt::Key_End || key == Qt::Key_PageUp || key == Qt::Key_PageDown || key == Qt::Key_Up
+ || key == Qt::Key_Down || key == Qt::Key_Left || key == Qt::Key_Right;
const int itemCount = m_model->count();
// the arrow keys to simplify the event handling.
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;
+ 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;
}
}
case Qt::Key_Up:
updateKeyboardAnchor();
+ if (shiftPressed && !m_selectionManager->isAnchoredSelectionActive() && m_selectionManager->isSelected(index)) {
+ m_selectionManager->beginAnchoredSelection(index);
+ }
index = previousRowIndex(index);
break;
case Qt::Key_Down:
updateKeyboardAnchor();
+ if (shiftPressed && !m_selectionManager->isAnchoredSelectionActive() && m_selectionManager->isSelected(index)) {
+ m_selectionManager->beginAnchoredSelection(index);
+ }
index = nextRowIndex(index);
break;
int index = -1;
if (selectedItems.count() >= 2) {
const int currentItemIndex = m_selectionManager->currentItem();
- index = selectedItems.contains(currentItemIndex)
- ? currentItemIndex : selectedItems.first();
+ index = selectedItems.contains(currentItemIndex) ? currentItemIndex : selectedItems.first();
} else if (selectedItems.count() == 1) {
index = selectedItems.first();
}
}
case Qt::Key_Escape:
- if (m_selectionBehavior != SingleSelection) {
+ if (m_selectionMode) {
+ Q_EMIT selectionModeChangeRequested(false);
+ } else if (m_selectionBehavior != SingleSelection) {
m_selectionManager->clearSelection();
}
m_keyboardManager->cancelSearch();
}
}
}
- Q_FALLTHROUGH(); // fall through to the default case and add the Space to the current search string.
+ Q_FALLTHROUGH(); // fall through to the default case and add the Space to the current search string.
default:
m_keyboardManager->addKeys(event->text());
// Make sure unconsumed events get propagated up the chain. #302329
return true;
}
-void KItemListController::slotChangeCurrentItem(const QString& text, bool searchFromNextItem)
+void KItemListController::slotChangeCurrentItem(const QString &text, bool searchFromNextItem)
{
if (!m_model || m_model->count() == 0) {
return;
*
* See Bug 293200 and 305783
*/
- if (m_model->supportsDropping(index) && m_view->isUnderMouse()) {
+ if (m_view->isUnderMouse()) {
if (m_view->supportsItemExpanding() && m_model->isExpandable(index)) {
const bool expanded = m_model->isExpanded(index);
m_model->setExpanded(index, !expanded);
}
}
-bool KItemListController::inputMethodEvent(QInputMethodEvent* event)
+bool KItemListController::inputMethodEvent(QInputMethodEvent *event)
{
Q_UNUSED(event)
return false;
}
-bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
+bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent *event, const QTransform &transform)
{
m_mousePress = true;
+ m_pressedMouseGlobalPos = event->screenPos();
if (event->source() == Qt::MouseEventSynthesizedByQt && m_isTouchEvent) {
return false;
return false;
}
- m_pressedMousePos = transform.map(event->pos());
- m_pressedIndex = m_view->itemAt(m_pressedMousePos);
+ const QPointF pressedMousePos = transform.map(event->pos());
+ m_pressedIndex = m_view->itemAt(pressedMousePos);
const Qt::MouseButtons buttons = event->buttons();
return true;
}
-bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
+bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent *event, const QTransform &transform)
{
if (!m_view) {
return false;
if (m_pressedIndex.has_value() && !m_view->rubberBand()->isActive()) {
// 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()) {
+ const auto distance = (event->screenPos() - m_pressedMouseGlobalPos).manhattanLength();
+ if (distance >= QApplication::startDragDistance()) {
if (!m_selectionManager->isSelected(m_pressedIndex.value())) {
// 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
}
}
} else {
- KItemListRubberBand* rubberBand = m_view->rubberBand();
+ KItemListRubberBand *rubberBand = m_view->rubberBand();
if (rubberBand->isActive()) {
QPointF endPos = transform.map(event->pos());
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();
}
return false;
}
-bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
+bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent *event, const QTransform &transform)
{
m_mousePress = false;
m_isTouchEvent = false;
m_view->m_tapAndHoldIndicator->setActive(false);
}
- KItemListRubberBand* rubberBand = m_view->rubberBand();
+ KItemListRubberBand *rubberBand = m_view->rubberBand();
if (event->source() == Qt::MouseEventSynthesizedByQt && !rubberBand->isActive() && m_isTouchEvent) {
return false;
}
return onRelease(transform.map(event->pos()), event->modifiers(), event->button(), false);
}
-bool KItemListController::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
+bool KItemListController::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event, const QTransform &transform)
{
const QPointF pos = transform.map(event->pos());
const std::optional<int> index = m_view->itemAt(pos);
return true;
}
- bool emitItemActivated = !(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced) &&
- (event->button() & Qt::LeftButton) &&
- index.has_value() && index.value() < m_model->count();
+ bool emitItemActivated = !(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced)
+ && (event->button() & Qt::LeftButton) && index.has_value() && index.value() < m_model->count();
if (emitItemActivated) {
Q_EMIT itemActivated(index.value());
}
return false;
}
-bool KItemListController::dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
+bool KItemListController::dragEnterEvent(QGraphicsSceneDragDropEvent *event, const QTransform &transform)
{
Q_UNUSED(event)
Q_UNUSED(transform)
return false;
}
-bool KItemListController::dragLeaveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
+bool KItemListController::dragLeaveEvent(QGraphicsSceneDragDropEvent *event, const QTransform &transform)
{
Q_UNUSED(event)
Q_UNUSED(transform)
m_view->setAutoScroll(false);
m_view->hideDropIndicator();
- KItemListWidget* widget = hoveredWidget();
+ KItemListWidget *widget = hoveredWidget();
if (widget) {
widget->setHovered(false);
Q_EMIT itemUnhovered(widget->index());
return false;
}
-bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
+bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent *event, const QTransform &transform)
{
if (!m_model || !m_view) {
return false;
}
-
QUrl hoveredDir = m_model->directory();
- KItemListWidget* oldHoveredWidget = hoveredWidget();
+ KItemListWidget *oldHoveredWidget = hoveredWidget();
const QPointF pos = transform.map(event->pos());
- KItemListWidget* newHoveredWidget = widgetForDropPos(pos);
+ KItemListWidget *newHoveredWidget = widgetForDropPos(pos);
+ int index = -1;
if (oldHoveredWidget != newHoveredWidget) {
m_autoActivationTimer->stop();
droppingBetweenItems = (m_view->showDropIndicator(pos) >= 0);
}
- const int index = newHoveredWidget->index();
+ index = newHoveredWidget->index();
if (m_model->isDir(index)) {
hoveredDir = m_model->url(index);
}
if (!droppingBetweenItems) {
- if (m_model->supportsDropping(index)) {
- // Something has been dragged on an item.
- m_view->hideDropIndicator();
- if (!newHoveredWidget->isHovered()) {
- newHoveredWidget->setHovered(true);
- Q_EMIT itemHovered(index);
- }
+ // Something has been dragged on an item.
+ m_view->hideDropIndicator();
+ if (!newHoveredWidget->isHovered()) {
+ newHoveredWidget->setHovered(true);
+ Q_EMIT itemHovered(index);
+ }
- if (!m_autoActivationTimer->isActive() && m_autoActivationTimer->interval() >= 0) {
- m_autoActivationTimer->setProperty("index", index);
- m_autoActivationTimer->start();
- }
+ if (!m_autoActivationTimer->isActive() && m_autoActivationTimer->interval() >= 0) {
+ m_autoActivationTimer->setProperty("index", index);
+ m_autoActivationTimer->start();
}
} else {
m_autoActivationTimer->stop();
event->setDropAction(Qt::IgnoreAction);
event->ignore();
} else {
- event->setDropAction(event->proposedAction());
- event->accept();
+ if (m_model->supportsDropping(index)) {
+ event->setDropAction(event->proposedAction());
+ event->accept();
+ } else {
+ event->setDropAction(Qt::IgnoreAction);
+ event->ignore();
+ }
}
return false;
}
-bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
+bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent *event, const QTransform &transform)
{
if (!m_view) {
return false;
return true;
}
-bool KItemListController::hoverEnterEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
+bool KItemListController::hoverEnterEvent(QGraphicsSceneHoverEvent *event, const QTransform &transform)
{
Q_UNUSED(event)
Q_UNUSED(transform)
return false;
}
-bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
+bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent *event, const QTransform &transform)
{
Q_UNUSED(transform)
if (!m_model || !m_view) {
const auto oldHoveredExpansionWidgetIterator = std::find_if(visibleItemListWidgets.begin(), visibleItemListWidgets.end(), [](auto &widget) {
return widget->expansionAreaHovered();
});
- const auto oldHoveredExpansionWidget = oldHoveredExpansionWidgetIterator == visibleItemListWidgets.end() ?
- std::nullopt : std::make_optional(*oldHoveredExpansionWidgetIterator);
+ const auto oldHoveredExpansionWidget =
+ oldHoveredExpansionWidgetIterator == visibleItemListWidgets.end() ? std::nullopt : std::make_optional(*oldHoveredExpansionWidgetIterator);
const auto unhoverOldHoveredWidget = [&]() {
if (auto oldHoveredWidget = hoveredWidget(); oldHoveredWidget) {
// we also unhover any old icon+text hovers, in case the mouse movement from icon+text to expansion toggle is too fast (i.e. newHoveredWidget is never null between the transition)
unhoverOldHoveredWidget();
-
newHoveredWidget->setExpansionAreaHovered(true);
} else {
// make sure we unhover the old one first if old!=new
return false;
}
-bool KItemListController::hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
+bool KItemListController::hoverLeaveEvent(QGraphicsSceneHoverEvent *event, const QTransform &transform)
{
Q_UNUSED(event)
Q_UNUSED(transform)
}
const auto widgets = m_view->visibleItemListWidgets();
- for (KItemListWidget* widget : widgets) {
+ for (KItemListWidget *widget : widgets) {
if (widget->isHovered()) {
widget->setHovered(false);
Q_EMIT itemUnhovered(widget->index());
return false;
}
-bool KItemListController::wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform)
+bool KItemListController::wheelEvent(QGraphicsSceneWheelEvent *event, const QTransform &transform)
{
Q_UNUSED(event)
Q_UNUSED(transform)
return false;
}
-bool KItemListController::resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform)
+bool KItemListController::resizeEvent(QGraphicsSceneResizeEvent *event, const QTransform &transform)
{
Q_UNUSED(event)
Q_UNUSED(transform)
return false;
}
-bool KItemListController::gestureEvent(QGestureEvent* event, const QTransform& transform)
+bool KItemListController::gestureEvent(QGestureEvent *event, const QTransform &transform)
{
if (!m_view) {
return false;
//we use this to get the right QWidget
//the only exception is a tap gesture with state GestureStarted, we need to reset some variable
if (!m_mousePress) {
- if (QGesture* tap = event->gesture(Qt::TapGesture)) {
- QTapGesture* tapGesture = static_cast<QTapGesture*>(tap);
+ if (QGesture *tap = event->gesture(Qt::TapGesture)) {
+ QTapGesture *tapGesture = static_cast<QTapGesture *>(tap);
if (tapGesture->state() == Qt::GestureStarted) {
tapTriggered(tapGesture, transform);
}
bool accepted = false;
- if (QGesture* tap = event->gesture(Qt::TapGesture)) {
- tapTriggered(static_cast<QTapGesture*>(tap), transform);
+ if (QGesture *tap = event->gesture(Qt::TapGesture)) {
+ tapTriggered(static_cast<QTapGesture *>(tap), transform);
accepted = true;
}
if (event->gesture(Qt::TapAndHoldGesture)) {
return accepted;
}
-bool KItemListController::touchBeginEvent(QTouchEvent* event, const QTransform& transform)
+bool KItemListController::touchBeginEvent(QTouchEvent *event, const QTransform &transform)
{
Q_UNUSED(event)
Q_UNUSED(transform)
return false;
}
-void KItemListController::tapTriggered(QTapGesture* tap, const QTransform& transform)
+void KItemListController::tapTriggered(QTapGesture *tap, const QTransform &transform)
{
static bool scrollerWasActive = false;
m_view->m_tapAndHoldIndicator->setActive(false);
}
- m_pressedMousePos = transform.map(tap->position());
- m_pressedIndex = m_view->itemAt(m_pressedMousePos);
-
+ const QPointF pressedMousePos = transform.map(tap->position());
+ m_pressedIndex = m_view->itemAt(pressedMousePos);
if (m_dragActionOrRightClick) {
- onPress(tap->hotSpot().toPoint(), tap->position().toPoint(), Qt::NoModifier, Qt::RightButton);
- onRelease(transform.map(tap->position()), Qt::NoModifier, Qt::RightButton, false);
m_dragActionOrRightClick = false;
- }
- else {
- onPress(tap->hotSpot().toPoint(), tap->position().toPoint(), Qt::NoModifier, Qt::LeftButton);
+ } else {
+ onPress(m_pressedMouseGlobalPos.toPoint(), tap->position().toPoint(), Qt::NoModifier, Qt::LeftButton);
onRelease(transform.map(tap->position()), Qt::NoModifier, Qt::LeftButton, true);
}
m_isTouchEvent = false;
}
}
-void KItemListController::tapAndHoldTriggered(QGestureEvent* event, const QTransform& transform)
+void KItemListController::tapAndHoldTriggered(QGestureEvent *event, const QTransform &transform)
{
-
//the Qt TabAndHold gesture is triggerable with a mouse click, we don't want this
if (!m_isTouchEvent) {
return;
}
- const QTapAndHoldGesture* tap = static_cast<QTapAndHoldGesture*>(event->gesture(Qt::TapAndHoldGesture));
+ const QTapAndHoldGesture *tap = static_cast<QTapAndHoldGesture *>(event->gesture(Qt::TapAndHoldGesture));
if (tap->state() == Qt::GestureFinished) {
//if a pinch gesture is in progress we don't want a TabAndHold gesture
if (m_pinchGestureInProgress) {
return;
}
- m_pressedMousePos = transform.map(event->mapToGraphicsScene(tap->position()));
- m_pressedIndex = m_view->itemAt(m_pressedMousePos);
-
- if (m_pressedIndex.has_value() && !m_selectionManager->isSelected(m_pressedIndex.value())) {
- m_selectionManager->clearSelection();
- m_selectionManager->setSelected(m_pressedIndex.value());
- } else if (!m_pressedIndex.has_value()) {
+ const QPointF pressedMousePos = transform.map(event->mapToGraphicsScene(tap->position()));
+ m_pressedIndex = m_view->itemAt(pressedMousePos);
+ if (m_pressedIndex.has_value()) {
+ if (!m_selectionManager->isSelected(m_pressedIndex.value())) {
+ m_selectionManager->clearSelection();
+ m_selectionManager->setSelected(m_pressedIndex.value());
+ }
+ if (!m_selectionMode) {
+ Q_EMIT selectionModeChangeRequested(true);
+ }
+ } else {
m_selectionManager->clearSelection();
startRubberBand();
}
Q_EMIT scrollerStop();
- m_view->m_tapAndHoldIndicator->setStartPosition(m_pressedMousePos);
+ m_view->m_tapAndHoldIndicator->setStartPosition(pressedMousePos);
m_view->m_tapAndHoldIndicator->setActive(true);
m_dragActionOrRightClick = true;
}
}
-void KItemListController::pinchTriggered(QGestureEvent* event, const QTransform& transform)
+void KItemListController::pinchTriggered(QGestureEvent *event, const QTransform &transform)
{
Q_UNUSED(transform)
- const QPinchGesture* pinch = static_cast<QPinchGesture*>(event->gesture(Qt::PinchGesture));
+ const QPinchGesture *pinch = static_cast<QPinchGesture *>(event->gesture(Qt::PinchGesture));
const qreal sensitivityModifier = 0.2;
static qreal counter = 0;
}
}
-void KItemListController::swipeTriggered(QGestureEvent* event, const QTransform& transform)
+void KItemListController::swipeTriggered(QGestureEvent *event, const QTransform &transform)
{
Q_UNUSED(transform)
- const KTwoFingerSwipe* swipe = static_cast<KTwoFingerSwipe*>(event->gesture(m_swipeGesture));
+ const KTwoFingerSwipe *swipe = static_cast<KTwoFingerSwipe *>(event->gesture(m_swipeGesture));
if (!swipe) {
return;
}
}
-void KItemListController::twoFingerTapTriggered(QGestureEvent* event, const QTransform& transform)
+void KItemListController::twoFingerTapTriggered(QGestureEvent *event, const QTransform &transform)
{
- const KTwoFingerTap* twoTap = static_cast<KTwoFingerTap*>(event->gesture(m_twoFingerTapGesture));
+ const KTwoFingerTap *twoTap = static_cast<KTwoFingerTap *>(event->gesture(m_twoFingerTapGesture));
if (!twoTap) {
return;
}
if (twoTap->state() == Qt::GestureStarted) {
- m_pressedMousePos = transform.map(twoTap->pos());
- m_pressedIndex = m_view->itemAt(m_pressedMousePos);
+ const QPointF pressedMousePos = transform.map(twoTap->pos());
+ m_pressedIndex = m_view->itemAt(pressedMousePos);
if (m_pressedIndex.has_value()) {
onPress(twoTap->screenPos().toPoint(), twoTap->pos().toPoint(), Qt::ControlModifier, Qt::LeftButton);
onRelease(transform.map(twoTap->pos()), Qt::ControlModifier, Qt::LeftButton, false);
}
-
}
}
-bool KItemListController::processEvent(QEvent* event, const QTransform& transform)
+bool KItemListController::processEvent(QEvent *event, const QTransform &transform)
{
if (!event) {
return false;
switch (event->type()) {
case QEvent::KeyPress:
- return keyPressEvent(static_cast<QKeyEvent*>(event));
+ return keyPressEvent(static_cast<QKeyEvent *>(event));
case QEvent::InputMethod:
- return inputMethodEvent(static_cast<QInputMethodEvent*>(event));
+ return inputMethodEvent(static_cast<QInputMethodEvent *>(event));
case QEvent::GraphicsSceneMousePress:
- return mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
+ return mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event), QTransform());
case QEvent::GraphicsSceneMouseMove:
- return mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
+ return mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event), QTransform());
case QEvent::GraphicsSceneMouseRelease:
- return mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
+ return mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event), QTransform());
case QEvent::GraphicsSceneMouseDoubleClick:
- return mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
+ return mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event), QTransform());
case QEvent::GraphicsSceneWheel:
- return wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(event), QTransform());
+ return wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event), QTransform());
case QEvent::GraphicsSceneDragEnter:
- return dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
+ return dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent *>(event), QTransform());
case QEvent::GraphicsSceneDragLeave:
- return dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
+ return dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event), QTransform());
case QEvent::GraphicsSceneDragMove:
- return dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
+ return dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event), QTransform());
case QEvent::GraphicsSceneDrop:
- return dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
+ return dropEvent(static_cast<QGraphicsSceneDragDropEvent *>(event), QTransform());
case QEvent::GraphicsSceneHoverEnter:
- return hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
+ return hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent *>(event), QTransform());
case QEvent::GraphicsSceneHoverMove:
- return hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
+ return hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event), QTransform());
case QEvent::GraphicsSceneHoverLeave:
- return hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
+ return hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent *>(event), QTransform());
case QEvent::GraphicsSceneResize:
- return resizeEvent(static_cast<QGraphicsSceneResizeEvent*>(event), transform);
+ return resizeEvent(static_cast<QGraphicsSceneResizeEvent *>(event), transform);
case QEvent::Gesture:
- return gestureEvent(static_cast<QGestureEvent*>(event), transform);
+ return gestureEvent(static_cast<QGestureEvent *>(event), transform);
case QEvent::TouchBegin:
- return touchBeginEvent(static_cast<QTouchEvent*>(event), transform);
+ return touchBeginEvent(static_cast<QTouchEvent *>(event), transform);
default:
break;
}
return;
}
- KItemListRubberBand* rubberBand = m_view->rubberBand();
+ KItemListRubberBand *rubberBand = m_view->rubberBand();
if (rubberBand->isActive()) {
const qreal diff = current - previous;
// TODO: Ideally just QCursor::pos() should be used as
return;
}
- const KItemListRubberBand* rubberBand = m_view->rubberBand();
+ const KItemListRubberBand *rubberBand = m_view->rubberBand();
const QPointF startPos = rubberBand->startPosition();
const QPointF endPos = rubberBand->endPosition();
QRectF rubberBandRect = QRectF(startPos, endPos).normalized();
if (!m_oldSelection.isEmpty()) {
// Clear the old selection that was available before the rubberband has
// been activated in case if no Shift- or Control-key are pressed
- const bool shiftOrControlPressed = QApplication::keyboardModifiers() & Qt::ShiftModifier ||
- QApplication::keyboardModifiers() & Qt::ControlModifier;
- if (!shiftOrControlPressed) {
+ const bool shiftOrControlPressed = QApplication::keyboardModifiers() & Qt::ShiftModifier || QApplication::keyboardModifiers() & Qt::ControlModifier;
+ if (!shiftOrControlPressed && !m_selectionMode) {
m_oldSelection.clear();
}
}
// Select all visible items that intersect with the rubberband
const auto widgets = m_view->visibleItemListWidgets();
- for (const KItemListWidget* widget : widgets) {
+ for (const KItemListWidget *widget : widgets) {
const int index = widget->index();
const QRectF widgetRect = m_view->itemRect(index);
if (widgetRect.intersects(rubberBandRect)) {
- const QRectF iconRect = widget->iconRect().translated(widgetRect.topLeft());
- const QRectF textRect = widget->textRect().translated(widgetRect.topLeft());
- if (iconRect.intersects(rubberBandRect) || textRect.intersects(rubberBandRect)) {
+ // Select the full row intersecting with the rubberband rectangle
+ const QRectF selectionRect = widget->selectionRect().translated(widgetRect.topLeft());
+ if (selectionRect.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();
+ 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;
if (increaseIndex) {
++index;
- selectionFinished = (index >= m_model->count()) ||
- ( scrollVertical && widgetRect.top() > rubberBandRect.bottom()) ||
- (!scrollVertical && widgetRect.left() > rubberBandRect.right());
+ 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());
+ selectionFinished = (index < 0) || (scrollVertical && widgetRect.bottom() < rubberBandRect.top())
+ || (!scrollVertical && widgetRect.right() < rubberBandRect.left());
}
} while (!selectionFinished);
- if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
+ if ((QApplication::keyboardModifiers() & Qt::ControlModifier) || m_selectionMode) {
// If Control is pressed, the selection state of all items in the rubberband is toggled.
// Therefore, the new selection contains:
// 1. All previously selected items which are not inside the rubberband, and
// 2. all items inside the rubberband which have not been selected previously.
m_selectionManager->setSelectedItems(m_oldSelection ^ selectedItems);
- }
- else {
+ } else {
m_selectionManager->setSelectedItems(selectedItems + m_oldSelection);
}
}
return;
}
- QMimeData* data = m_model->createMimeData(selectedItems);
+ QMimeData *data = m_model->createMimeData(selectedItems);
if (!data) {
return;
}
+ KUrlMimeData::exportUrlsToPortal(data);
// The created drag object will be owned and deleted
// by QApplication::activeWindow().
- QDrag* drag = new QDrag(QApplication::activeWindow());
+ QDrag *drag = new QDrag(QApplication::activeWindow());
drag->setMimeData(data);
const QPixmap pixmap = m_view->createDragPixmap(selectedItems);
QAccessible::updateAccessibility(&accessibilityEvent);
}
-KItemListWidget* KItemListController::hoveredWidget() const
+KItemListWidget *KItemListController::hoveredWidget() const
{
Q_ASSERT(m_view);
const auto widgets = m_view->visibleItemListWidgets();
- for (KItemListWidget* widget : widgets) {
+ for (KItemListWidget *widget : widgets) {
if (widget->isHovered()) {
return widget;
}
return nullptr;
}
-KItemListWidget* KItemListController::widgetForPos(const QPointF& pos) const
+KItemListWidget *KItemListController::widgetForPos(const QPointF &pos) const
{
Q_ASSERT(m_view);
const auto widgets = m_view->visibleItemListWidgets();
- for (KItemListWidget* widget : widgets) {
+ for (KItemListWidget *widget : widgets) {
const QPointF mappedPos = widget->mapFromItem(m_view, pos);
if (widget->contains(mappedPos) || widget->selectionRect().contains(mappedPos)) {
return widget;
return nullptr;
}
-KItemListWidget* KItemListController::widgetForDropPos(const QPointF& pos) const
+KItemListWidget *KItemListController::widgetForDropPos(const QPointF &pos) const
{
Q_ASSERT(m_view);
const auto widgets = m_view->visibleItemListWidgets();
- for (KItemListWidget* widget : widgets) {
+ for (KItemListWidget *widget : widgets) {
const QPointF mappedPos = widget->mapFromItem(m_view, pos);
if (widget->contains(mappedPos)) {
return widget;
void KItemListController::updateKeyboardAnchor()
{
- const bool validAnchor = m_keyboardAnchorIndex >= 0 &&
- m_keyboardAnchorIndex < m_model->count() &&
- keyboardAnchorPos(m_keyboardAnchorIndex) == m_keyboardAnchorPos;
+ 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;
}
}
-bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons)
+bool KItemListController::onPress(const QPoint &screenPos, const QPointF &pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons)
{
Q_EMIT mouseButtonPressed(m_pressedIndex.value_or(-1), buttons);
return true;
}
- if (m_view->isAboveExpansionToggle(m_pressedIndex.value_or(-1), m_pressedMousePos)) {
+ const QPointF pressedMousePos = m_view->transform().map(pos);
+
+ if (m_view->isAboveExpansionToggle(m_pressedIndex.value_or(-1), pressedMousePos)) {
m_selectionManager->endAnchoredSelection();
m_selectionManager->setCurrentItem(m_pressedIndex.value());
m_selectionManager->beginAnchoredSelection(m_pressedIndex.value());
return true;
}
- m_selectionTogglePressed = m_view->isAboveSelectionToggle(m_pressedIndex.value_or(-1), m_pressedMousePos);
+ m_selectionTogglePressed = m_view->isAboveSelectionToggle(m_pressedIndex.value_or(-1), pressedMousePos);
if (m_selectionTogglePressed) {
m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Toggle);
// The previous anchored selection has been finished already in
}
const bool shiftPressed = modifiers & Qt::ShiftModifier;
- const bool controlPressed = modifiers & Qt::ControlModifier;
+ const bool controlPressed = (modifiers & Qt::ControlModifier) || m_selectionMode; // Keeping selectionMode similar to pressing control will hopefully
+ // simplify the overall logic and possibilities both for users and devs.
const bool leftClick = buttons & Qt::LeftButton;
const bool rightClick = buttons & Qt::RightButton;
// - open the context menu and perform an action for all selected items.
const bool shiftOrControlPressed = shiftPressed || controlPressed;
const bool pressedItemAlreadySelected = m_pressedIndex.has_value() && m_selectionManager->isSelected(m_pressedIndex.value());
- const bool clearSelection = m_selectionBehavior == SingleSelection ||
- (!shiftOrControlPressed && !pressedItemAlreadySelected);
-
+ const bool clearSelection = m_selectionBehavior == SingleSelection || (!shiftOrControlPressed && !pressedItemAlreadySelected);
// When this method returns false, a rubberBand selection is created using KItemListController::startRubberBand via the caller.
if (clearSelection) {
const int selectedItemsCount = m_selectionManager->selectedItems().count();
m_selectionManager->clearSelection();
// clear and bail when we got an existing multi-selection
- if (selectedItemsCount > 1 && m_pressedIndex.has_value()) {
+ if (selectedItemsCount > 1 && m_pressedIndex.has_value()) {
const auto row = m_view->m_visibleItems.value(m_pressedIndex.value());
const auto mappedPos = row->mapFromItem(m_view, pos);
if (pressedItemAlreadySelected || row->iconRect().contains(mappedPos) || row->textRect().contains(mappedPos)) {
return false;
}
}
- } else if (pressedItemAlreadySelected && !shiftOrControlPressed && (buttons & Qt::LeftButton)) {
+ } else if (pressedItemAlreadySelected && !shiftOrControlPressed && leftClick) {
// 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.
// clear the selection in mouseReleaseEvent(), unless the items are dragged.
m_clearSelectionIfItemsAreNotDragged = true;
- if (m_selectionManager->selectedItems().count() == 1 && m_view->isAboveText(m_pressedIndex.value_or(-1), m_pressedMousePos)) {
+ if (m_selectionManager->selectedItems().count() == 1 && m_view->isAboveText(m_pressedIndex.value_or(-1), pressedMousePos)) {
Q_EMIT selectedItemTextPressed(m_pressedIndex.value_or(-1));
}
}
}
if (rightClick) {
-
// Do header hit check and short circuit before commencing any state changing effects
if (m_view->headerBoundaries().contains(pos)) {
Q_EMIT headerContextMenuRequested(screenPos);
}
// Stop rubber band from persisting after right-clicks
- KItemListRubberBand* rubberBand = m_view->rubberBand();
+ KItemListRubberBand *rubberBand = m_view->rubberBand();
if (rubberBand->isActive()) {
disconnect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged);
rubberBand->setActive(false);
return false;
}
-bool KItemListController::onRelease(const QPointF& pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons, bool touch)
+bool KItemListController::onRelease(const QPointF &pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons, bool touch)
{
- const bool isAboveSelectionToggle = m_view->isAboveSelectionToggle(m_pressedIndex.value_or(-1), m_pressedMousePos);
+ const QPointF pressedMousePos = pos;
+ const bool isAboveSelectionToggle = m_view->isAboveSelectionToggle(m_pressedIndex.value_or(-1), pressedMousePos);
if (isAboveSelectionToggle) {
m_selectionTogglePressed = false;
return true;
}
const bool controlPressed = modifiers & Qt::ControlModifier;
- const bool shiftOrControlPressed = modifiers & Qt::ShiftModifier ||
- controlPressed;
+ const bool shiftOrControlPressed = modifiers & Qt::ShiftModifier || controlPressed;
const std::optional<int> index = m_view->itemAt(pos);
- KItemListRubberBand* rubberBand = m_view->rubberBand();
+ KItemListRubberBand *rubberBand = m_view->rubberBand();
bool rubberBandRelease = false;
if (rubberBand->isActive()) {
disconnect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged);
} else {
const bool singleClickActivation = m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced;
if (!singleClickActivation) {
- emitItemActivated = touch;
+ emitItemActivated = touch && !m_selectionMode;
} else {
// activate on single click only if we didn't come from a rubber band release
emitItemActivated = !rubberBandRelease;
}
}
- m_pressedMousePos = QPointF();
+ m_pressedMouseGlobalPos = QPointF();
m_pressedIndex = std::nullopt;
m_clearSelectionIfItemsAreNotDragged = false;
return false;
void KItemListController::startRubberBand()
{
if (m_selectionBehavior == MultiSelection) {
- QPointF startPos = m_pressedMousePos;
+ QPoint startPos = m_view->transform().map(m_view->scene()->views().first()->mapFromGlobal(m_pressedMouseGlobalPos.toPoint()));
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();
+ KItemListRubberBand *rubberBand = m_view->rubberBand();
rubberBand->setStartPosition(startPos);
rubberBand->setEndPosition(startPos);
rubberBand->setActive(true);
m_scrollerIsScrolling = false;
}
}
+
+#include "moc_kitemlistcontroller.cpp"