diff --git a/src/widget/wlibrarysidebar.cpp b/src/widget/wlibrarysidebar.cpp index 2e392afe6474..fb4f4f5b5a92 100644 --- a/src/widget/wlibrarysidebar.cpp +++ b/src/widget/wlibrarysidebar.cpp @@ -183,40 +183,43 @@ bool WLibrarySidebar::isLeafNodeSelected() { } void WLibrarySidebar::keyPressEvent(QKeyEvent* event) { - if (event->key() == Qt::Key_Return) { + switch (event->key()) { + case Qt::Key_Return: toggleSelectedItem(); return; - } else if (event->key() == Qt::Key_Down || - event->key() == Qt::Key_Up || - event->key() == Qt::Key_PageDown || - event->key() == Qt::Key_PageUp || - event->key() == Qt::Key_End || - event->key() == Qt::Key_Home) { + case Qt::Key_Down: + case Qt::Key_Up: + case Qt::Key_PageDown: + case Qt::Key_PageUp: + case Qt::Key_End: + case Qt::Key_Home: { // Let the tree view move up and down for us. QTreeView::keyPressEvent(event); - // But force the index to be activated/clicked after the selection - // changes. (Saves you from having to push "enter" after changing the - // selection.) + // After the selection changed force-activate (click) the newly selected + // item to save us from having to push "Enter". QModelIndexList selectedIndices = selectionModel()->selectedRows(); - //Note: have to get the selected indices _after_ QTreeView::keyPressEvent() - if (selectedIndices.size() > 0) { - QModelIndex index = selectedIndices.at(0); - emit pressed(index); + if (selectedIndices.isEmpty()) { + return; + } + QModelIndex selIndex = selectedIndices.first(); + VERIFY_OR_DEBUG_ASSERT(selIndex.isValid()) { + qDebug() << "invalid sidebar index"; + return; } + emit pressed(selIndex); return; - //} else if (event->key() == Qt::Key_Enter && (event->modifiers() & Qt::AltModifier)) { - // // encoder click via "GoToItem" - // qDebug() << "GoToItem"; - // TODO(xxx) decide what todo here instead of in librarycontrol - } else if (event->key() == Qt::Key_Left) { - auto selModel = selectionModel(); - QModelIndexList selectedRows = selModel->selectedRows(); - if (selectedRows.isEmpty()) { + } + case Qt::Key_Left: { + QModelIndexList selectedIndices = selectionModel()->selectedRows(); + if (selectedIndices.isEmpty()) { return; } // If an expanded item is selected let QTreeView collapse it - QModelIndex selIndex = selectedRows.first(); - DEBUG_ASSERT(selIndex.isValid()); + QModelIndex selIndex = selectedIndices.first(); + VERIFY_OR_DEBUG_ASSERT(selIndex.isValid()) { + qDebug() << "invalid sidebar index"; + return; + } if (isExpanded(selIndex)) { QTreeView::keyPressEvent(event); return; @@ -229,9 +232,13 @@ void WLibrarySidebar::keyPressEvent(QKeyEvent* event) { } return; } - - // Fall through to default handler. - QTreeView::keyPressEvent(event); + case Qt::Key_Escape: + // Focus tracks table + emit sidebarFocusChange(FocusWidget::TracksTable); + return; + default: + QTreeView::keyPressEvent(event); + } } void WLibrarySidebar::selectIndex(const QModelIndex& index) { diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 883512ae0683..cdcdb7fc6e16 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -92,7 +92,13 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent, UserSettingsPointer pConfig) //: Shown in the library search bar when it is empty. lineEdit()->setPlaceholderText(tr("Search...")); - installEventFilter(this); + + // The goal is to make Esc natively close the popup, while in the line edit it + // should move the keyboard focus to the tracks table. Unfortunately, eventFilter() + // can't catch Esc before the popup is closed, and keyPressEvent() can't catch + // keyPresses sent to the popup. So the only way to get this to work is to use + // keyPressEvent() for catching all keypress events sent to the line edit, + // while eventFilter() catches those sent to the popup. view()->installEventFilter(this); m_clearButton->setCursor(Qt::ArrowCursor); @@ -223,7 +229,7 @@ void WSearchLineEdit::setup(const QDomNode& node, const SkinContext& context) { tr("Shortcut") + ": \n" + tr("Ctrl+Backspace")); - setToolTip(tr("Search", "noun") + "\n" + + setBaseTooltip(tr("Search", "noun") + "\n" + tr("Enter a string to search for") + "\n" + tr("Use operators like bpm:115-128, artist:BooFar, -year:1990") + "\n" + tr("For more information see User Manual > Mixxx Library") + @@ -324,58 +330,81 @@ QString WSearchLineEdit::getSearchText() const { bool WSearchLineEdit::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast(event); - // if the popup is open don't intercept Up/Down keys - if (!view()->isVisible()) { - if (keyEvent->key() == Qt::Key_Up) { - // if we're at the top of the list the Up key clears the search bar, - // no matter if it's a saved and unsaved query - if (findCurrentTextIndex() == 0 || - (findCurrentTextIndex() == -1 && !currentText().isEmpty())) { - slotClearSearch(); - return true; - } - } else if (keyEvent->key() == Qt::Key_Down) { - // after clearing the text field the down key is expected to - // show the latest entry - if (currentText().isEmpty()) { - setCurrentIndex(0); - return true; - } - // in case the user entered a new search query - // and presses the down key, save the query for later recall - if (findCurrentTextIndex() == -1) { - slotSaveSearch(); - } - } - } else { - if (keyEvent->key() == Qt::Key_Backspace || - keyEvent->key() == Qt::Key_Delete) { - // remove the highlighted item from the list - deleteSelectedListItem(); - return true; - } - } - if (keyEvent->key() == Qt::Key_Enter) { - if (findCurrentTextIndex() == -1) { - slotSaveSearch(); - } - // The default handler will add the entry to the list, - // this already happened in slotSaveSearch - slotTriggerSearch(); + const int key = keyEvent->key(); + // Esc has already closed the popup by now and we don't want to process it. + // We don't need to handle Up/Down in the popup either. + // Any other keypress is forwarded. + if (key != Qt::Key_Escape && + key != Qt::Key_Down && + key != Qt::Key_Up) { + keyPressEvent(keyEvent); return true; - } else if (keyEvent->key() == Qt::Key_Space && - keyEvent->modifiers() == Qt::ControlModifier) { - // open/close popup on ctrl + space + } + } + return QComboBox::eventFilter(obj, event); +} + +void WSearchLineEdit::keyPressEvent(QKeyEvent* keyEvent) { + int currentTextIndex = 0; + switch (keyEvent->key()) { + // Ctrl + F is handled in slotSetShortcutFocus() + case Qt::Key_Backspace: + case Qt::Key_Delete: + // If the popup is open remove the highlighted item from the list + if (view()->isVisible()) { + deleteSelectedListItem(); + return; + } + break; + case Qt::Key_Up: + // If we're at the top of the list the Up key clears the search bar, + // no matter if it's a saved or unsaved query. + // Otherwise Up is handled by the combobox itself. + currentTextIndex = findCurrentTextIndex(); + if (currentTextIndex == 0 || + (currentTextIndex == -1 && !currentText().isEmpty())) { + slotClearSearch(); + return; + } + break; + case Qt::Key_Down: + // After clearing the text field the Down key + // is expected to show the latest query + if (currentText().isEmpty()) { + setCurrentIndex(0); + return; + } + // After entering a new search query the Down key saves the query, + // then selects the previous query + if (findCurrentTextIndex() == -1) { + slotSaveSearch(); + } + break; + case Qt::Key_Enter: + if (findCurrentTextIndex() == -1) { + slotSaveSearch(); + } + slotTriggerSearch(); + return; + case Qt::Key_Space: + // Open/close popup with Ctrl + space + if (keyEvent->modifiers() == Qt::ControlModifier) { if (view()->isVisible()) { hidePopup(); } else { showPopup(); } - return true; + return; } - // if the line edit has focus Ctrl + F selects the text + break; + case Qt::Key_Escape: + emit searchbarFocusChange(FocusWidget::TracksTable); + return; + default: + break; } - return QComboBox::eventFilter(obj, event); + + return QComboBox::keyPressEvent(keyEvent); } void WSearchLineEdit::focusInEvent(QFocusEvent* event) { diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index 800d4a2c4370..8c83d27e02b9 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -38,6 +38,7 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { void focusOutEvent(QFocusEvent*) override; bool event(QEvent*) override; bool eventFilter(QObject* obj, QEvent* event) override; + void keyPressEvent(QKeyEvent* event) override; signals: void search(const QString& text); diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 92ee26bed0ae..cea503530adb 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -77,13 +77,6 @@ WTrackTableView::WTrackTableView(QWidget* parent, &WTrackTableView::scrollValueChanged, this, &WTrackTableView::slotScrollValueChanged); - - QShortcut* setFocusShortcut = - new QShortcut(QKeySequence(tr("ESC", "Focus")), this); - connect(setFocusShortcut, - &QShortcut::activated, - this, - QOverload<>::of(&WTrackTableView::setFocus)); } WTrackTableView::~WTrackTableView() {