}
}
+ // For right to left languages, exchange right and left arrow keys.
+ if (m_view->layoutDirection() == Qt::RightToLeft) {
+ switch (key) {
+ case Qt::Key_Left:
+ key = Qt::Key_Right;
+ break;
+ case Qt::Key_Right:
+ key = Qt::Key_Left;
+ break;
+ default:
+ break;
+ }
+ }
+
const bool selectSingleItem = m_selectionBehavior != NoSelection && itemCount == 1 && navigationPressed;
if (selectSingleItem) {
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 KItemSet selectedItems = m_selectionManager->selectedItems();
- int index = -1;
- if (selectedItems.count() >= 2) {
- const int currentItemIndex = m_selectionManager->currentItem();
- index = selectedItems.contains(currentItemIndex) ? currentItemIndex : selectedItems.first();
- } else if (selectedItems.count() == 1) {
- index = selectedItems.first();
- }
-
- if (index >= 0) {
- const QRectF contextRect = m_view->itemContextRect(index);
- const QPointF pos(m_view->scene()->views().first()->mapToGlobal(contextRect.bottomRight().toPoint()));
- Q_EMIT itemContextMenuRequested(index, pos);
- } else {
- Q_EMIT viewContextMenuRequested(QCursor::pos());
- }
- break;
- }
-
case Qt::Key_Escape:
if (m_selectionMode) {
Q_EMIT selectionModeChangeRequested(false);
m_selectionManager->beginAnchoredSelection(index);
}
- m_view->scrollToItem(index);
+ m_view->scrollToItem(index, KItemListView::ViewItemPosition::Beginning);
}
}
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();
}
}
if (event->button() & Qt::RightButton) {
- m_selectionManager->clearSelection();
- if (index.has_value()) {
- m_selectionManager->setSelected(index.value());
- Q_EMIT itemContextMenuRequested(index.value(), event->screenPos());
- } else {
- const QRectF headerBounds = m_view->headerBoundaries();
- if (headerBounds.contains(event->pos())) {
- Q_EMIT headerContextMenuRequested(event->screenPos());
- } else {
- Q_EMIT viewContextMenuRequested(event->screenPos());
- }
- }
- return true;
+ return false;
}
bool emitItemActivated = !(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced)
return false;
}
+bool KItemListController::contextMenuEvent(QContextMenuEvent *event)
+{
+ if (event->reason() == QContextMenuEvent::Keyboard) {
+ // Emit the signal itemContextMenuRequested() if at least one item is selected.
+ // Otherwise the signal viewContextMenuRequested() will be emitted.
+ const KItemSet selectedItems = m_selectionManager->selectedItems();
+ int index = -1;
+ if (selectedItems.count() >= 2) {
+ const int currentItemIndex = m_selectionManager->currentItem();
+ index = selectedItems.contains(currentItemIndex) ? currentItemIndex : selectedItems.first();
+ } else if (selectedItems.count() == 1) {
+ index = selectedItems.first();
+ }
+
+ if (index >= 0) {
+ const QRectF contextRect = m_view->itemContextRect(index);
+ const QPointF pos(m_view->scene()->views().first()->mapToGlobal(contextRect.bottomRight().toPoint()));
+ Q_EMIT itemContextMenuRequested(index, pos);
+ } else {
+ Q_EMIT viewContextMenuRequested(event->globalPos());
+ }
+ return true;
+ }
+
+ const auto pos = event->pos();
+ const auto globalPos = event->globalPos();
+
+ if (m_view->headerBoundaries().contains(pos)) {
+ Q_EMIT headerContextMenuRequested(globalPos);
+ return true;
+ }
+
+ const auto pressedItem = m_view->itemAt(pos);
+ // We only open a context menu for the pressed item if it is selected.
+ // That's because the same click might have de-selected the item or because the press was only in the row of the item but not on it.
+ if (pressedItem && m_selectionManager->selectedItems().contains(pressedItem.value())) {
+ // The selection rectangle for an item was clicked
+ Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), globalPos);
+ return true;
+ }
+
+ // Remove any hover highlights so the context menu doesn't look like it applies to a row.
+ const auto widgets = m_view->visibleItemListWidgets();
+ for (KItemListWidget *widget : widgets) {
+ if (widget->isHovered()) {
+ widget->setHovered(false);
+ Q_EMIT itemUnhovered(widget->index());
+ }
+ }
+ Q_EMIT viewContextMenuRequested(globalPos);
+ return true;
+}
+
bool KItemListController::dragEnterEvent(QGraphicsSceneDragDropEvent *event, const QTransform &transform)
{
Q_UNUSED(event)
if (!m_autoActivationTimer->isActive() && m_autoActivationTimer->interval() >= 0) {
m_autoActivationTimer->setProperty("index", index);
m_autoActivationTimer->start();
+ newHoveredWidget->startActivateSoonAnimation(m_autoActivationTimer->remainingTime());
}
} else {
m_autoActivationTimer->stop();
return mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event), QTransform());
case QEvent::GraphicsSceneMouseDoubleClick:
return mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event), QTransform());
+ case QEvent::ContextMenu:
+ return contextMenuEvent(static_cast<QContextMenuEvent *>(event));
case QEvent::GraphicsSceneWheel:
return wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event), QTransform());
case QEvent::GraphicsSceneDragEnter:
if (widgetRect.intersects(rubberBandRect)) {
// Select the full row intersecting with the rubberband rectangle
const QRectF selectionRect = widget->selectionRect().translated(widgetRect.topLeft());
- if (selectionRect.intersects(rubberBandRect)) {
+ const QRectF iconRect = widget->iconRect().translated(widgetRect.topLeft());
+ if (selectionRect.intersects(rubberBandRect) || iconRect.intersects(rubberBandRect)) {
selectedItems.insert(index);
}
}
{
Q_ASSERT(m_view);
+ if (m_view->headerBoundaries().contains(pos)) {
+ return nullptr;
+ }
+
const auto widgets = m_view->visibleItemListWidgets();
for (KItemListWidget *widget : widgets) {
const QPointF mappedPos = widget->mapFromItem(m_view, pos);
{
Q_ASSERT(m_view);
+ if (m_view->headerBoundaries().contains(pos)) {
+ return nullptr;
+ }
+
const auto widgets = m_view->visibleItemListWidgets();
for (KItemListWidget *widget : widgets) {
const QPointF mappedPos = widget->mapFromItem(m_view, pos);
return index;
}
+ const bool leftToRight = m_view->layoutDirection() != Qt::RightToLeft;
+
// Calculate the index of the last column inside the row of the current index
int lastColumnIndex = index;
- while (keyboardAnchorPos(lastColumnIndex + 1) > keyboardAnchorPos(lastColumnIndex)) {
+ while ((leftToRight && keyboardAnchorPos(lastColumnIndex + 1) > keyboardAnchorPos(lastColumnIndex))
+ || (!leftToRight && keyboardAnchorPos(lastColumnIndex + 1) < keyboardAnchorPos(lastColumnIndex))) {
++lastColumnIndex;
if (lastColumnIndex >= maxIndex) {
return index;
int nextRowIndex = lastColumnIndex + 1;
int searchIndex = nextRowIndex;
qreal minDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(nextRowIndex));
- while (searchIndex < maxIndex && keyboardAnchorPos(searchIndex + 1) > keyboardAnchorPos(searchIndex)) {
+ while (searchIndex < maxIndex
+ && ((leftToRight && keyboardAnchorPos(searchIndex + 1) > keyboardAnchorPos(searchIndex))
+ || (!leftToRight && keyboardAnchorPos(searchIndex + 1) < keyboardAnchorPos(searchIndex)))) {
++searchIndex;
const qreal searchDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(searchIndex));
if (searchDiff < minDiff) {
return index;
}
+ const bool leftToRight = m_view->layoutDirection() != Qt::RightToLeft;
+
// Calculate the index of the first column inside the row of the current index
int firstColumnIndex = index;
- while (keyboardAnchorPos(firstColumnIndex - 1) < keyboardAnchorPos(firstColumnIndex)) {
+ while ((leftToRight && keyboardAnchorPos(firstColumnIndex - 1) < keyboardAnchorPos(firstColumnIndex))
+ || (!leftToRight && keyboardAnchorPos(firstColumnIndex - 1) > keyboardAnchorPos(firstColumnIndex))) {
--firstColumnIndex;
if (firstColumnIndex <= 0) {
return index;
int previousRowIndex = firstColumnIndex - 1;
int searchIndex = previousRowIndex;
qreal minDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(previousRowIndex));
- while (searchIndex > 0 && keyboardAnchorPos(searchIndex - 1) < keyboardAnchorPos(searchIndex)) {
+ while (searchIndex > 0
+ && ((leftToRight && keyboardAnchorPos(searchIndex - 1) < keyboardAnchorPos(searchIndex))
+ || (!leftToRight && keyboardAnchorPos(searchIndex - 1) > keyboardAnchorPos(searchIndex)))) {
--searchIndex;
const qreal searchDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(searchIndex));
if (searchDiff < minDiff) {
}
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);
- return true;
- }
-
// Stop rubber band from persisting after right-clicks
KItemListRubberBand *rubberBand = m_view->rubberBand();
if (rubberBand->isActive()) {
if (m_pressedIndex.has_value()) {
// The hover highlight area of an item is being pressed.
- m_selectionManager->setCurrentItem(m_pressedIndex.value());
const auto row = m_view->m_visibleItems.value(m_pressedIndex.value()); // anything outside of row.contains() will be the empty region of the row rect
const bool hitTargetIsRowEmptyRegion = !row->contains(row->mapFromItem(m_view, pos));
// again, when this method returns false, a rubberBand selection is created as the event is not consumed;
bool createRubberBand = (hitTargetIsRowEmptyRegion && m_selectionManager->selectedItems().isEmpty());
if (rightClick && hitTargetIsRowEmptyRegion) {
- // We have a right click outside the icon and text rect but within the hover highlight area
- // but it is unclear if this means that a selection rectangle for an item was clicked or the background of the view.
- if (m_selectionManager->selectedItems().contains(m_pressedIndex.value())) {
- // The selection rectangle for an item was clicked
- Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), screenPos);
- } else {
- row->setHovered(false); // Removes the hover highlight so the context menu doesn't look like it applies to the row.
- Q_EMIT viewContextMenuRequested(screenPos);
- }
+ // We have a right click outside the icon and text rect but within the hover highlight area.
+ // We don't want items to get selected through this, so we return now.
return true;
}
+ m_selectionManager->setCurrentItem(m_pressedIndex.value());
+
switch (m_selectionBehavior) {
case NoSelection:
break;
break;
}
- if (rightClick) {
- Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), screenPos);
- }
return !createRubberBand;
}
- if (rightClick) {
- // header right click handling would have been done before this so just normal context
- // menu here is fine
- Q_EMIT viewContextMenuRequested(screenPos);
- return true;
- }
-
return false;
}
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();
}