+ int index = m_selectionManager->currentItem();
+ int key = event->key();
+
+ // 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;
+ }
+ } else if (key == Qt::Key_Left) {
+ if (m_model->setExpanded(index, false)) {
+ return true;
+ }
+ }
+ }
+
+ const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
+ const bool controlPressed = event->modifiers() & Qt::ControlModifier;
+ const bool shiftOrControlPressed = shiftPressed || controlPressed;
+
+ const int itemCount = m_model->count();
+
+ // For horizontal scroll orientation, transform
+ // 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;
+ }
+ }
+
+ const bool selectSingleItem = m_selectionBehavior != NoSelection &&
+ itemCount == 1 &&
+ (key == Qt::Key_Home || key == Qt::Key_End ||
+ key == Qt::Key_Up || key == Qt::Key_Down ||
+ key == Qt::Key_Left || key == Qt::Key_Right);
+ if (selectSingleItem) {
+ const int current = m_selectionManager->currentItem();
+ m_selectionManager->setSelected(current);
+ return true;
+ }
+
+ switch (key) {
+ case Qt::Key_Home:
+ index = 0;
+ m_keyboardAnchorIndex = index;
+ m_keyboardAnchorPos = keyboardAnchorPos(index);
+ break;
+
+ case Qt::Key_End:
+ index = itemCount - 1;
+ m_keyboardAnchorIndex = index;
+ m_keyboardAnchorPos = keyboardAnchorPos(index);
+ break;
+
+ case Qt::Key_Left:
+ if (index > 0) {
+ const int expandedParentsCount = m_model->expandedParentsCount(index);
+ if (expandedParentsCount == 0) {
+ --index;
+ } else {
+ // Go to the parent of the current item.
+ do {
+ --index;
+ } while (index > 0 && m_model->expandedParentsCount(index) == expandedParentsCount);
+ }
+ m_keyboardAnchorIndex = index;
+ m_keyboardAnchorPos = keyboardAnchorPos(index);
+ }
+ break;
+
+ case Qt::Key_Right:
+ if (index < itemCount - 1) {
+ ++index;
+ m_keyboardAnchorIndex = index;
+ m_keyboardAnchorPos = keyboardAnchorPos(index);
+ }
+ break;
+
+ case Qt::Key_Up:
+ updateKeyboardAnchor();
+ index = previousRowIndex(index);
+ break;
+
+ case Qt::Key_Down:
+ updateKeyboardAnchor();
+ index = nextRowIndex(index);
+ break;
+
+ case Qt::Key_PageUp:
+ if (m_view->scrollOrientation() == Qt::Horizontal) {
+ // The new current index should correspond to the first item in the current column.
+ int newIndex = qMax(index - 1, 0);
+ while (newIndex != index && m_view->itemRect(newIndex).topLeft().y() < m_view->itemRect(index).topLeft().y()) {
+ index = newIndex;
+ newIndex = qMax(index - 1, 0);
+ }
+ m_keyboardAnchorIndex = index;
+ m_keyboardAnchorPos = keyboardAnchorPos(index);
+ } else {
+ const qreal currentItemBottom = m_view->itemRect(index).bottomLeft().y();
+ const qreal height = m_view->geometry().height();
+
+ // The new current item should be the first item in the current
+ // column whose itemRect's top coordinate is larger than targetY.
+ const qreal targetY = currentItemBottom - height;
+
+ updateKeyboardAnchor();
+ int newIndex = previousRowIndex(index);
+ do {
+ index = newIndex;
+ updateKeyboardAnchor();
+ newIndex = previousRowIndex(index);
+ } while (m_view->itemRect(newIndex).topLeft().y() > targetY && newIndex != index);
+ }
+ break;
+
+ case Qt::Key_PageDown:
+ if (m_view->scrollOrientation() == Qt::Horizontal) {
+ // The new current index should correspond to the last item in the current column.
+ int newIndex = qMin(index + 1, m_model->count() - 1);
+ while (newIndex != index && m_view->itemRect(newIndex).topLeft().y() > m_view->itemRect(index).topLeft().y()) {
+ index = newIndex;
+ newIndex = qMin(index + 1, m_model->count() - 1);
+ }
+ m_keyboardAnchorIndex = index;
+ m_keyboardAnchorPos = keyboardAnchorPos(index);
+ } else {
+ const qreal currentItemTop = m_view->itemRect(index).topLeft().y();
+ const qreal height = m_view->geometry().height();
+
+ // The new current item should be the last item in the current
+ // column whose itemRect's bottom coordinate is smaller than targetY.
+ const qreal targetY = currentItemTop + height;
+
+ updateKeyboardAnchor();
+ int newIndex = nextRowIndex(index);
+ do {
+ index = newIndex;
+ updateKeyboardAnchor();
+ newIndex = nextRowIndex(index);
+ } while (m_view->itemRect(newIndex).bottomLeft().y() < targetY && newIndex != index);
+ }
+ break;
+
+ case Qt::Key_Enter:
+ case Qt::Key_Return: {
+ const KItemSet selectedItems = m_selectionManager->selectedItems();
+ if (selectedItems.count() >= 2) {
+ emit itemsActivated(selectedItems);
+ } else if (selectedItems.count() == 1) {
+ emit itemActivated(selectedItems.first());
+ } else {
+ emit itemActivated(index);
+ }
+ 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()));
+ emit itemContextMenuRequested(index, pos);
+ } else {
+ emit viewContextMenuRequested(QCursor::pos());
+ }
+ break;
+ }
+
+ case Qt::Key_Escape:
+ if (m_selectionBehavior != SingleSelection) {
+ m_selectionManager->clearSelection();
+ }
+ m_keyboardManager->cancelSearch();
+ emit escapePressed();
+ break;
+
+ case Qt::Key_Space:
+ if (m_selectionBehavior == MultiSelection) {
+ if (controlPressed) {
+ // Toggle the selection state of the current item.
+ m_selectionManager->endAnchoredSelection();
+ m_selectionManager->setSelected(index, 1, KItemListSelectionManager::Toggle);
+ m_selectionManager->beginAnchoredSelection(index);
+ break;
+ } else {
+ // Select the current item if it is not selected yet.
+ const int current = m_selectionManager->currentItem();
+ if (!m_selectionManager->isSelected(current)) {
+ m_selectionManager->setSelected(current);
+ break;
+ }
+ }
+ }
+ // 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
+ event->ignore();
+ return false;
+ }
+
+ if (m_selectionManager->currentItem() != index) {
+ switch (m_selectionBehavior) {
+ case NoSelection:
+ m_selectionManager->setCurrentItem(index);
+ break;
+
+ case SingleSelection:
+ m_selectionManager->setCurrentItem(index);
+ m_selectionManager->clearSelection();
+ m_selectionManager->setSelected(index, 1);
+ break;
+
+ case MultiSelection:
+ if (controlPressed) {
+ m_selectionManager->endAnchoredSelection();
+ }
+
+ m_selectionManager->setCurrentItem(index);
+
+ if (!shiftOrControlPressed) {
+ m_selectionManager->clearSelection();
+ m_selectionManager->setSelected(index, 1);
+ }
+
+ if (!shiftPressed) {
+ m_selectionManager->beginAnchoredSelection(index);
+ }
+ break;
+ }
+
+ m_view->scrollToItem(index);
+ }
+ return true;
+}
+
+void KItemListController::slotChangeCurrentItem(const QString& text, bool searchFromNextItem)
+{
+ if (!m_model || m_model->count() == 0) {
+ return;
+ }
+ const int currentIndex = m_selectionManager->currentItem();
+ int index;
+ if (searchFromNextItem) {
+ index = m_model->indexForKeyboardSearch(text, (currentIndex + 1) % m_model->count());
+ } else {
+ index = m_model->indexForKeyboardSearch(text, currentIndex);
+ }
+ if (index >= 0) {
+ m_selectionManager->setCurrentItem(index);
+
+ if (m_selectionBehavior != NoSelection) {
+ m_selectionManager->clearSelection();
+ m_selectionManager->setSelected(index, 1);
+ m_selectionManager->beginAnchoredSelection(index);
+ }
+
+ m_view->scrollToItem(index);
+ }
+}
+
+void KItemListController::slotAutoActivationTimeout()
+{
+ if (!m_model || !m_view) {
+ return;
+ }
+
+ const int index = m_autoActivationTimer->property("index").toInt();
+ if (index < 0 || index >= m_model->count()) {
+ return;
+ }
+
+ /* m_view->isUnderMouse() fixes a bug in the Folder-View-Panel and in the
+ * Places-Panel.
+ *
+ * Bug: When you drag a file onto a Folder-View-Item or a Places-Item and
+ * then move away before the auto-activation timeout triggers, than the
+ * item still becomes activated/expanded.
+ *
+ * See Bug 293200 and 305783
+ */
+ if (m_model->supportsDropping(index) && m_view->isUnderMouse()) {
+ if (m_view->supportsItemExpanding() && m_model->isExpandable(index)) {
+ const bool expanded = m_model->isExpanded(index);
+ m_model->setExpanded(index, !expanded);
+ } else if (m_autoActivationBehavior != ExpansionOnly) {
+ emit itemActivated(index);
+ }
+ }