diff --git a/krusader/BookMan/krbookmarkhandler.h b/krusader/BookMan/krbookmarkhandler.h --- a/krusader/BookMan/krbookmarkhandler.h +++ b/krusader/BookMan/krbookmarkhandler.h @@ -63,8 +63,6 @@ void buildMenu(KrBookmark *parent, QMenu *menu, int depth = 0); bool eventFilter(QObject *obj, QEvent *ev); - QString createShortcutUnderline(const QString &, int underlineEnd); - void resetShortcuts(); void rightClicked(QMenu *menu, KrBookmark *bm); void rightClickOnSpecialBookmark(); @@ -84,13 +82,15 @@ QPointer _mainBookmarkPopup; // main bookmark popup menu QList _specialBookmarks; // the action list of the special bookmarks - QHash _msNamesWithAccelerators; // List of changed shortcuts and their old values QWidgetAction *_quickSearchAction; QLineEdit *_quickSearchBar; + QHash _quickSearchOriginalActionTitles; ///< Saved original action text values to restore after search void _setQuickSearchText(const QString &text); QString _quickSearchText() const; + static void _highlightAction(QAction *action, bool isMatched = true); + void _resetActionTextAndHighlighting(); }; Q_DECLARE_METATYPE(KrBookmark *) diff --git a/krusader/BookMan/krbookmarkhandler.cpp b/krusader/BookMan/krbookmarkhandler.cpp --- a/krusader/BookMan/krbookmarkhandler.cpp +++ b/krusader/BookMan/krbookmarkhandler.cpp @@ -34,6 +34,7 @@ #include #include #include +#include // QtGui #include #include @@ -328,15 +329,25 @@ _quickSearchAction->setVisible(length > 0); _quickSearchBar->setVisible(length > 0); if (length == 0) { - resetShortcuts(); + qDebug() << "Bookmark search: reset"; + _resetActionTextAndHighlighting(); + } else { + qDebug() << "Bookmark search: query =" << text; } } QString KrBookmarkHandler::_quickSearchText() const { return _quickSearchBar->text(); } +void KrBookmarkHandler::_highlightAction(QAction *action, bool isMatched) +{ + auto font = action->font(); + font.setBold(isMatched); + action->setFont(font); +} + void KrBookmarkHandler::populate(QMenu *menu) { _mainBookmarkPopup = menu; @@ -510,19 +521,20 @@ } // Having it occur on keypress is consistent with other shortcuts, - // such as ctrl+w and the '&' bookmark shortcut standard - // (&movies makes m a shortcut for said bookmark) + // such as Ctrl+W and accelerator keys if (ev->type() == QEvent::KeyPress && obj->inherits("QMenu")) { QKeyEvent *kev = static_cast(ev); QMenu *menu = static_cast(obj); QList acts = menu->actions(); + bool quickSearchStarted = false; if (kev->modifiers() != Qt::NoModifier || kev->text().isEmpty() || kev->key() == Qt::Key_Delete) { return QObject::eventFilter(obj, ev); } + // update quick search text if (kev->key() == Qt::Key_Backspace) { auto newSearchText = _quickSearchText(); newSearchText.chop(1); @@ -532,49 +544,66 @@ return QObject::eventFilter(obj, ev); } } else { + quickSearchStarted = _quickSearchText().length() == 0; _setQuickSearchText(_quickSearchText().append(kev->text())); } - QAction* found = nullptr; - const int quickSearchTextLength = _quickSearchText().length(); - bool solematch; + if (quickSearchStarted) { + qDebug() << "Bookmark search: started"; + } + + // match actions + QAction *firstMatch = nullptr; + int nMatches = 0; for (auto act : acts) { if (act->isSeparator() || act->text() == "") { continue; } - if (quickSearchTextLength == 1 && kev->key() != Qt::Key_Backspace && !kev->text().isEmpty()) { + if (quickSearchStarted) { + // if the first key press is an accelerator key, let the accelerator handler process this event if (act->text().contains('&' + kev->text(), Qt::CaseInsensitive)) { + qDebug() << "Bookmark search: hit accelerator key of" << act; _setQuickSearchText(""); break; } - _msNamesWithAccelerators.insert(act, act->text()); + // strip accelerator keys from actions so they don't interfere with the search key press events + auto text = act->text(); + _quickSearchOriginalActionTitles.insert(act, text); + act->setText(KLocalizedString::removeAcceleratorMarker(text)); } - act->setText(KLocalizedString::removeAcceleratorMarker(act->text())); - if (act->text().left(quickSearchTextLength).compare(_quickSearchText(), Qt::CaseInsensitive) == 0) { - act->setText(createShortcutUnderline(act->text(), quickSearchTextLength)); - if (!found) { - found = act; - solematch = true; - } else { - solematch = false; + // match prefix of the action text to the query + if (act->text().left(_quickSearchText().length()).compare(_quickSearchText(), Qt::CaseInsensitive) == 0) { + _highlightAction(act); + if (!firstMatch) { + firstMatch = act; } + nMatches++; + } else { + _highlightAction(act, false); } } - if (found && solematch) { - if ((bool) found->menu()) { - menu->setActiveAction(found); + if (firstMatch) { + qDebug() << "Bookmark search: first match =" << firstMatch->text() << ", number of matches =" << nMatches; + } else { + qDebug() << "Bookmark search: no matches"; + } + + // trigger the matched menu item or set an active item accordingly + if (nMatches == 1) { + _setQuickSearchText(""); + if ((bool) firstMatch->menu()) { + menu->setActiveAction(firstMatch); } else { - found->activate(QAction::Trigger); + firstMatch->activate(QAction::Trigger); } - _setQuickSearchText(""); - } else if (found && quickSearchTextLength > 1) { - // & bookmark code will give focus as long as there is only one - // & character - menu->setActiveAction(found); + } else { + // if no match is found, firstMatch == nullptr + // this is intended as it will unset active item of the menu + menu->setActiveAction(firstMatch); } } @@ -614,33 +643,16 @@ return QObject::eventFilter(obj, ev); } -void KrBookmarkHandler::resetShortcuts() -{ - QHash::const_iterator i = _msNamesWithAccelerators.begin(); - for (; i != _msNamesWithAccelerators.end(); ++i) { - if (i.key()) { - i.key()->setText(i.value()); - } - } - _msNamesWithAccelerators.clear(); -} - -QString KrBookmarkHandler::createShortcutUnderline(const QString &text, int underlineEnd) +void KrBookmarkHandler::_resetActionTextAndHighlighting() { - if (underlineEnd <= 0) { - return text; - } - if (underlineEnd > text.length()) { - underlineEnd = text.length(); + for (QHash::const_iterator i = _quickSearchOriginalActionTitles.begin(); + i != _quickSearchOriginalActionTitles.end(); ++i) { + QAction *action = i.key(); + action->setText(i.value()); + _highlightAction(action, false); } - QString underlinedtext = text; - for (int i = 0; i < underlineEnd; i++) { - if (underlinedtext[2 * i] != '&') { - underlinedtext.insert(2 * i, '&'); - } - } - return underlinedtext; + _quickSearchOriginalActionTitles.clear(); } #define POPULAR_URLS_ID 100100