diff options
author | Be <be@mixxx.org> | 2020-10-29 18:07:48 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-29 18:07:48 -0500 |
commit | 524c41a79679ca169f28f315fd34ca129a133171 (patch) | |
tree | 67f463d95fdfa1da004ee89a048011ce520ff956 | |
parent | 26d27fb116f06d6d19b1d4e158ab4a8cbd85351a (diff) | |
parent | 9e29613ef50f544159cbd31a0142aef49d038472 (diff) |
Merge pull request #3171 from poelzi/searchbox-combo
Use a combobox instead of a lineedit widget for library search history
-rw-r--r-- | res/skins/LateNight/style.qss | 2 | ||||
-rw-r--r-- | src/controllers/controlpickermenu.cpp | 24 | ||||
-rw-r--r-- | src/library/librarycontrol.cpp | 57 | ||||
-rw-r--r-- | src/library/librarycontrol.h | 5 | ||||
-rw-r--r-- | src/preferences/dialog/dlgpreflibrary.cpp | 2 | ||||
-rw-r--r-- | src/widget/wsearchlineedit.cpp | 233 | ||||
-rw-r--r-- | src/widget/wsearchlineedit.h | 22 |
7 files changed, 299 insertions, 46 deletions
diff --git a/res/skins/LateNight/style.qss b/res/skins/LateNight/style.qss index 1bf52d253e..c8257c4527 100644 --- a/res/skins/LateNight/style.qss +++ b/res/skins/LateNight/style.qss @@ -15,7 +15,6 @@ WTrackText, WTrackProperty, WBeatSpinBox, QSpinBox, -QComboBox, WLibrary QHeaderView, WLibrary QHeaderView::item, QToolTip, @@ -27,6 +26,7 @@ WCoverArtMenu, WTrackMenu, WTrackMenu QMenu, WOverview /* Hotcue labels in the overview */, +WBeatSpinBox, #spinBoxTransition, WEffectSelector, WEffectSelector QAbstractScrollArea, #fadeModeCombobox, diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp index 79075386e1..912240f12e 100644 --- a/src/controllers/controlpickermenu.cpp +++ b/src/controllers/controlpickermenu.cpp @@ -645,6 +645,30 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) tr("Replace Auto DJ Queue with selected tracks"), libraryMenu, false, m_libraryStr); libraryMenu->addSeparator(); + addControl("[Library]", + "search_history_next", + tr("Select next search history"), + tr("Selects the next search history entry"), + libraryMenu, + false, + m_libraryStr); + addControl("[Library]", + "search_history_prev", + tr("Select previous search history"), + tr("Selects the previous search history entry"), + libraryMenu, + false, + m_libraryStr); + addControl("[Library]", + "search_history_selector", + tr("Move selected search entry"), + tr("Moves the selected search history item into given direction " + "and steps"), + libraryMenu, + false, + m_libraryStr); + + libraryMenu->addSeparator(); addControl("[Recording]", "toggle_recording", tr("Record Mix"), tr("Toggle mix recording"), diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index a4a71b45ed..8bd0df6116 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -211,6 +211,47 @@ LibraryControl::LibraryControl(Library* pLibrary) this, &LibraryControl::slotTrackColorNext); + // Control to navigate between widgets (tab/shit+tab button) + m_pSelectHistoryNext = std::make_unique<ControlPushButton>( + ConfigKey("[Library]", "search_history_next")); + m_pSelectHistoryPrev = std::make_unique<ControlPushButton>( + ConfigKey("[Library]", "search_history_prev")); + m_pSelectHistorySelect = std::make_unique<ControlEncoder>( + ConfigKey("[Library]", "search_history_selector"), false); + connect(m_pSelectHistoryNext.get(), + &ControlPushButton::valueChanged, + this, + [this](double value) { + VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { + return; + } + if (value >= 1.0) { + m_pSearchbox->slotMoveSelectedHistory(1); + } + }); + connect(m_pSelectHistoryPrev.get(), + &ControlPushButton::valueChanged, + this, + [this](double value) { + VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { + return; + } + if (value >= 1.0) { + m_pSearchbox->slotMoveSelectedHistory(-1); + } + }); + connect(m_pSelectHistorySelect.get(), + &ControlEncoder::valueChanged, + this, + [this](double steps) { + VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { + return; + } + if (steps >= 1.0 || steps <= -1.0) { + m_pSearchbox->slotMoveSelectedHistory(static_cast<int>(steps)); + } + }); + /// Deprecated controls m_pSelectNextTrack = std::make_unique<ControlPushButton>(ConfigKey("[Playlist]", "SelectNextTrack")); connect(m_pSelectNextTrack.get(), @@ -537,19 +578,26 @@ void LibraryControl::emitKeyEvent(QKeyEvent&& event) { VERIFY_OR_DEBUG_ASSERT(m_pLibraryWidget) { return; } + VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { + return; + } if (!QApplication::focusWindow()) { qDebug() << "Mixxx window is not focused, don't send key events"; return; } - bool keyIsTab = event.key() == static_cast<int>(Qt::Key_Tab); + bool keyIsTab = event.key() == Qt::Key_Tab; + bool keyIsUpDown = event.key() == Qt::Key_Up || event.key() == Qt::Key_Down; // If the main window has focus, any widget can receive Tab. // Other keys should be sent to library widgets only to not // accidentally alter spinboxes etc. + // If the searchbox has focus allow only Up/Down to select previous queries. if (!keyIsTab && !m_pSidebarWidget->hasFocus() && !m_pLibraryWidget->getActiveView()->hasFocus()) { - setLibraryFocus(); + if (keyIsUpDown && !m_pSearchbox->hasFocus()) { + setLibraryFocus(); + } } if (keyIsTab && !QApplication::focusWidget()){ setLibraryFocus(); @@ -652,6 +700,11 @@ void LibraryControl::slotGoToItem(double v) { return activeView->loadSelectedTrack(); } + // If searchbox has focus jump to the tracks table + if (m_pSearchbox->hasFocus()) { + return setLibraryFocus(); + } + // Clear the search if the searchbox has focus emit clearSearchIfClearButtonHasFocus(); diff --git a/src/library/librarycontrol.h b/src/library/librarycontrol.h index dd8046c89e..84d70811c9 100644 --- a/src/library/librarycontrol.h +++ b/src/library/librarycontrol.h @@ -144,6 +144,11 @@ class LibraryControl : public QObject { std::unique_ptr<ControlPushButton> m_pTrackColorPrev; std::unique_ptr<ControlPushButton> m_pTrackColorNext; + // Controls to navigate search history + std::unique_ptr<ControlPushButton> m_pSelectHistoryNext; + std::unique_ptr<ControlPushButton> m_pSelectHistoryPrev; + std::unique_ptr<ControlEncoder> m_pSelectHistorySelect; + // Font sizes std::unique_ptr<ControlPushButton> m_pFontSizeIncrement; std::unique_ptr<ControlPushButton> m_pFontSizeDecrement; diff --git a/src/preferences/dialog/dlgpreflibrary.cpp b/src/preferences/dialog/dlgpreflibrary.cpp index fad1406ef0..26f4ad356a 100644 --- a/src/preferences/dialog/dlgpreflibrary.cpp +++ b/src/preferences/dialog/dlgpreflibrary.cpp @@ -278,6 +278,8 @@ void DlgPrefLibrary::slotRemoveDir() { } else if (removeMsgBox.clickedButton() == deleteAllButton) { removalType = Library::RemovalType::PurgeTracks; } else { + // Only used in DEBUG_ASSERT + Q_UNUSED(leaveUnchangedButton); DEBUG_ASSERT(removeMsgBox.clickedButton() == leaveUnchangedButton); removalType = Library::RemovalType::KeepTracks; } diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index ca004c5600..70c627fba5 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -1,15 +1,17 @@ +#include "wsearchlineedit.h" + +#include <QAbstractItemView> #include <QFont> +#include <QLineEdit> #include <QShortcut> +#include <QSizePolicy> #include <QStyle> -#include "wsearchlineedit.h" -#include "wskincolor.h" -#include "wwidget.h" - #include "skin/skincontext.h" - #include "util/assert.h" #include "util/logger.h" +#include "wskincolor.h" +#include "wwidget.h" #define ENABLE_TRACE_LOG false @@ -23,11 +25,19 @@ const QString kEmptySearch = QStringLiteral(""); const QString kDisabledText = QStringLiteral("- - -"); -inline QString clearButtonStyleSheet(int pxPaddingRight) { - DEBUG_ASSERT(pxPaddingRight >= 0); - return QString( - QStringLiteral("QLineEdit { padding-right: %1px; }")) - .arg(pxPaddingRight); +constexpr int kClearButtonClearence = 1; + +inline QString clearButtonStyleSheet(int pxPadding, Qt::LayoutDirection direction) { + DEBUG_ASSERT(pxPadding >= 0); + if (direction == Qt::RightToLeft) { + return QString( + QStringLiteral("WSearchLineEdit { padding-left: %1px; }")) + .arg(pxPadding); + } else { + return QString( + QStringLiteral("WSearchLineEdit { padding-right: %1px; }")) + .arg(pxPadding); + } } int verifyDebouncingTimeoutMillis(int debouncingTimeoutMillis) { @@ -52,6 +62,12 @@ constexpr int WSearchLineEdit::kDefaultDebouncingTimeoutMillis; constexpr int WSearchLineEdit::kMaxDebouncingTimeoutMillis; //static +constexpr int WSearchLineEdit::kSaveTimeoutMillis; + +//static +constexpr int WSearchLineEdit::kMaxSearchEntries; + +//static int WSearchLineEdit::s_debouncingTimeoutMillis = kDefaultDebouncingTimeoutMillis; //static @@ -60,31 +76,36 @@ void WSearchLineEdit::setDebouncingTimeoutMillis(int debouncingTimeoutMillis) { } WSearchLineEdit::WSearchLineEdit(QWidget* pParent) - : QLineEdit(pParent), - WBaseWidget(this), - m_clearButton(make_parented<QToolButton>(this)) { + : QComboBox(pParent), + WBaseWidget(this), + m_clearButton(make_parented<QToolButton>(this)) { DEBUG_ASSERT(kEmptySearch.isEmpty()); DEBUG_ASSERT(!kEmptySearch.isNull()); setAcceptDrops(false); + setEditable(true); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + setIconSize(QSize(0, 0)); + setInsertPolicy(QComboBox::InsertAtTop); + setMinimumSize(0, 0); + setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToMinimumContentsLengthWithIcon); //: Shown in the library search bar when it is empty. - setPlaceholderText(tr("Search...")); + lineEdit()->setPlaceholderText(tr("Search...")); + installEventFilter(this); + view()->installEventFilter(this); m_clearButton->setCursor(Qt::ArrowCursor); m_clearButton->setObjectName(QStringLiteral("SearchClearButton")); - // Assume the qss border is at least 1px wide - m_frameWidth = 1; + // Query style for arrow width and frame border + updateStyleMetrics(); + m_clearButton->hide(); connect(m_clearButton, &QAbstractButton::clicked, this, &WSearchLineEdit::slotClearSearch); - // This prevents the searchbox from being focused by Tab key (real or emulated) - // so it is skipped when using the library controls 'MoveFocus[...]' - // The Clear button can still be focused by Tab. - setFocusPolicy(Qt::ClickFocus); QShortcut* setFocusShortcut = new QShortcut(QKeySequence(tr("Ctrl+F", "Search|Focus")), this); connect(setFocusShortcut, &QShortcut::activated, @@ -94,17 +115,26 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) // Set up a timer to search after a few hundred milliseconds timeout. This // stops us from thrashing the database if you type really fast. m_debouncingTimer.setSingleShot(true); + m_saveTimer.setSingleShot(true); connect(&m_debouncingTimer, &QTimer::timeout, this, &WSearchLineEdit::slotTriggerSearch); + connect(&m_saveTimer, + &QTimer::timeout, + this, + &WSearchLineEdit::slotSaveSearch); connect(this, - &QLineEdit::textChanged, + &QComboBox::currentTextChanged, this, &WSearchLineEdit::slotTextChanged); + connect(this, + QOverload<int>::of(&QComboBox::currentIndexChanged), + this, + &WSearchLineEdit::slotIndexChanged); // When you hit enter, it will trigger or clear the search. - connect(this, + connect(this->lineEdit(), &QLineEdit::returnPressed, this, [this] { @@ -116,7 +146,9 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) QSize clearButtonSize = m_clearButton->sizeHint(); // Ensures the text does not obscure the clear image. - setStyleSheet(clearButtonStyleSheet(clearButtonSize.width() + m_frameWidth + 1)); + setStyleSheet(clearButtonStyleSheet( + clearButtonSize.width() + m_frameWidth + kClearButtonClearence, + layoutDirection())); refreshState(); } @@ -189,17 +221,33 @@ void WSearchLineEdit::setup(const QDomNode& node, const SkinContext& context) { setToolTip(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") + "\n\n" + - - tr("Shortcut") + ": \n" + - tr("Ctrl+F") + " " + tr("Focus", "Give search bar input focus") + "\n" + - tr("Ctrl+Backspace") + " " + tr("Clear input", "Clear the search bar input field") + "\n" + + tr("Use operators like bpm:115-128, artist:BooFar, -year:1990") + + "\n" + tr("For more information see User Manual > Mixxx Library") + + "\n\n" + + tr("Shortcut") + ": \n" + tr("Ctrl+F") + " " + + tr("Focus", "Give search bar input focus") + "\n" + + tr("Ctrl+Backspace") + " " + + tr("Clear input", "Clear the search bar input field") + "\n" + + tr("Ctrl+Space") + " " + + tr("Toggle search history", + "Shows/hides the search history entries") + + "\n" + tr("Esc") + " " + tr("Exit search", "Exit search bar and leave focus")); } +void WSearchLineEdit::updateStyleMetrics() { + QStyleOptionComboBox styleArrow; + styleArrow.initFrom(this); + QRect rectArrow(style()->subControlRect( + QStyle::CC_ComboBox, &styleArrow, QStyle::SC_ComboBoxArrow, this)); + + m_dropButtonWidth = rectArrow.width() + 1; + m_frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this); +} + void WSearchLineEdit::resizeEvent(QResizeEvent* e) { - QLineEdit::resizeEvent(e); + QComboBox::resizeEvent(e); + updateStyleMetrics(); m_innerHeight = this->height() - 2 * m_frameWidth; // Test if this is a vertical resize due to changed library font. // Assuming current button height is innerHeight from last resize, @@ -214,27 +262,64 @@ void WSearchLineEdit::resizeEvent(QResizeEvent* e) { } int top = rect().top() + m_frameWidth; if (layoutDirection() == Qt::LeftToRight) { - m_clearButton->move(rect().right() - m_innerHeight - m_frameWidth, top); + m_clearButton->move(rect().right() - m_innerHeight - m_frameWidth - m_dropButtonWidth, top); } else { - m_clearButton->move(m_frameWidth, top); + m_clearButton->move(m_frameWidth + m_dropButtonWidth, top); } } QString WSearchLineEdit::getSearchText() const { if (isEnabled()) { - DEBUG_ASSERT(!text().isNull()); - return text(); + DEBUG_ASSERT(!currentText().isNull()); + return currentText(); } else { return QString(); } } +bool WSearchLineEdit::eventFilter(QObject* obj, QEvent* event) { + if (event->type() == QEvent::KeyPress) { + QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); + if (keyEvent->key() == Qt::Key_Down) { + // after clearing the text field the down key is expected to + // show the last entry + if (currentText().isEmpty()) { + setCurrentIndex(0); + return true; + } + // in case the user entered a new search query + // und presses the down key, save the query for later recall + if (findCurrentTextIndex() == -1) { + slotSaveSearch(); + } + } else 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(); + return true; + } else if (keyEvent->key() == Qt::Key_Space && + keyEvent->modifiers() == Qt::ControlModifier) { + // open popup on ctrl + space + if (view()->isVisible()) { + hidePopup(); + } else { + showPopup(); + } + return true; + } + } + return QComboBox::eventFilter(obj, event); +} + void WSearchLineEdit::focusInEvent(QFocusEvent* event) { #if ENABLE_TRACE_LOG kLogger.trace() << "focusInEvent"; #endif // ENABLE_TRACE_LOG - QLineEdit::focusInEvent(event); + QComboBox::focusInEvent(event); } void WSearchLineEdit::focusOutEvent(QFocusEvent* event) { @@ -242,7 +327,7 @@ void WSearchLineEdit::focusOutEvent(QFocusEvent* event) { kLogger.trace() << "focusOutEvent"; #endif // ENABLE_TRACE_LOG - QLineEdit::focusOutEvent(event); + QComboBox::focusOutEvent(event); if (m_debouncingTimer.isActive()) { // Trigger a pending search before leaving the edit box. // Otherwise the entered text might be ignored and get lost @@ -258,7 +343,7 @@ void WSearchLineEdit::setTextBlockSignals(const QString& text) { << text; #endif // ENABLE_TRACE_LOG blockSignals(true); - setText(text); + setCurrentText(text); blockSignals(false); } @@ -294,6 +379,8 @@ void WSearchLineEdit::slotRestoreSearch(const QString& text) { if (text.isNull()) { slotDisableSearch(); } else { + // we save the current search before we switch to a new text + slotSaveSearch(); enableSearch(text); } } @@ -309,6 +396,42 @@ void WSearchLineEdit::slotTriggerSearch() { emit search(getSearchText()); } +/// saves the current query as selection +void WSearchLineEdit::slotSaveSearch() { + int cIndex = findCurrentTextIndex(); +#if ENABLE_TRACE_LOG + kLogger.trace() + << "save search. Index: " + << cIndex; +#endif // ENABLE_TRACE_LOG + m_saveTimer.stop(); + // entry already exists and is on top + if (cIndex == 0) { + return; + } + if (!currentText().isEmpty() && isEnabled()) { + // we remove the existing item and add a new one at the top + if (cIndex != -1) { + removeItem(cIndex); + } + insertItem(0, currentText()); + setCurrentIndex(0); + while (count() > kMaxSearchEntries) { + removeItem(kMaxSearchEntries); + } + } +} + +void WSearchLineEdit::slotMoveSelectedHistory(int steps) { + int nIndex = currentIndex() + steps; + // we wrap around to the last entry on backwards direction + if (nIndex < -1) { + nIndex = count() - 1; + } + setCurrentIndex(nIndex); + m_saveTimer.stop(); +} + void WSearchLineEdit::refreshState() { #if ENABLE_TRACE_LOG kLogger.trace() @@ -321,6 +444,17 @@ void WSearchLineEdit::refreshState() { } } +void WSearchLineEdit::showPopup() { + int cIndex = findCurrentTextIndex(); + if (cIndex == -1) { + slotSaveSearch(); + } else { + m_saveTimer.stop(); + setCurrentIndex(cIndex); + } + QComboBox::showPopup(); +} + void WSearchLineEdit::updateEditBox(const QString& text) { #if ENABLE_TRACE_LOG kLogger.trace() @@ -352,12 +486,15 @@ void WSearchLineEdit::updateClearButton(const QString& text) { // Disable while placeholder is shown m_clearButton->setVisible(false); // no right padding - setStyleSheet(clearButtonStyleSheet(0)); + setStyleSheet(clearButtonStyleSheet(0, layoutDirection())); } else { // Enable otherwise m_clearButton->setVisible(true); // make sure the text won't be drawn behind the Clear button icon - setStyleSheet(clearButtonStyleSheet(m_innerHeight + m_frameWidth)); + setStyleSheet(clearButtonStyleSheet( + m_innerHeight + m_dropButtonWidth + + m_frameWidth + kClearButtonClearence, + layoutDirection())); } } @@ -365,7 +502,7 @@ bool WSearchLineEdit::event(QEvent* pEvent) { if (pEvent->type() == QEvent::ToolTip) { updateTooltip(); } - return QLineEdit::event(pEvent); + return QComboBox::event(pEvent); } void WSearchLineEdit::slotClearSearch() { @@ -374,12 +511,15 @@ void WSearchLineEdit::slotClearSearch() { << "slotClearSearch"; #endif // ENABLE_TRACE_LOG DEBUG_ASSERT(isEnabled()); + // select the last entry as current before cleaning the text field + // so arrow keys will work as expected + setCurrentIndex(-1); // Clearing the edit field will engage the debouncing timer // and gives the user the chance for entering a new search // before returning the whole (and probably huge) library. // No need to manually trigger a search at this point! // See also: https://bugs.launchpad.net/mixxx/+bug/1635087 - setText(kEmptySearch); + setCurrentText(kEmptySearch); // Refocus the edit field setFocus(Qt::OtherFocusReason); } @@ -392,6 +532,12 @@ bool WSearchLineEdit::slotClearSearchIfClearButtonHasFocus() { return true; } +void WSearchLineEdit::slotIndexChanged(int index) { + if (index != -1) { + m_saveTimer.stop(); + } +} + void WSearchLineEdit::slotTextChanged(const QString& text) { #if ENABLE_TRACE_LOG kLogger.trace() @@ -413,6 +559,7 @@ void WSearchLineEdit::slotTextChanged(const QString& text) { // to an invalid value is an expected and valid use case. DEBUG_ASSERT(!m_debouncingTimer.isActive()); } + m_saveTimer.start(kSaveTimeoutMillis); } void WSearchLineEdit::slotSetShortcutFocus() { @@ -421,5 +568,9 @@ void WSearchLineEdit::slotSetShortcutFocus() { // Use the same font as the library table and the sidebar void WSearchLineEdit::slotSetFont(const QFont& font) { + updateStyleMetrics(); setFont(font); + if (lineEdit()) { + lineEdit()->setFont(font); + } } diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index f3807ce003..9709cc8a57 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -1,8 +1,8 @@ #pragma once +#include <QComboBox> #include <QDomNode> #include <QEvent> -#include <QLineEdit> #include <QTimer> #include <QToolButton> @@ -11,16 +11,19 @@ class SkinContext; -class WSearchLineEdit : public QLineEdit, public WBaseWidget { +class WSearchLineEdit : public QComboBox, public WBaseWidget { Q_OBJECT public: // Delay for triggering a search while typing static constexpr int kMinDebouncingTimeoutMillis = 100; static constexpr int kDefaultDebouncingTimeoutMillis = 300; static constexpr int kMaxDebouncingTimeoutMillis = 9999; + static constexpr int kSaveTimeoutMillis = 5000; + static constexpr int kMaxSearchEntries = 50; // TODO(XXX): Replace with a public slot static void setDebouncingTimeoutMillis(int debouncingTimeoutMillis); + virtual void showPopup() override; explicit WSearchLineEdit(QWidget* pParent); ~WSearchLineEdit() override = default; @@ -32,6 +35,7 @@ class WSearchLineEdit : public QLineEdit, public WBaseWidget { void focusInEvent(QFocusEvent*) override; void focusOutEvent(QFocusEvent*) override; bool event(QEvent*) override; + bool eventFilter(QObject* obj, QEvent* event) override; signals: void search(const QString& text); @@ -45,11 +49,18 @@ class WSearchLineEdit : public QLineEdit, public WBaseWidget { void slotClearSearch(); bool slotClearSearchIfClearButtonHasFocus(); + /// The function selects an entry relative to the currently selected + /// entry in the history and executes the search. + /// The parameter specifies the distance in steps (positive/negative = downward/upward) + void slotMoveSelectedHistory(int steps); + private slots: void slotSetShortcutFocus(); void slotTextChanged(const QString& text); + void slotIndexChanged(int index); void slotTriggerSearch(); + void slotSaveSearch(); private: // TODO(XXX): This setting shouldn't be static and the widget @@ -64,6 +75,11 @@ class WSearchLineEdit : public QLineEdit, public WBaseWidget { void enableSearch(const QString& text); void updateEditBox(const QString& text); void updateClearButton(const QString& text); + void updateStyleMetrics(); + + inline int findCurrentTextIndex() { + return findData(currentText(), Qt::DisplayRole); + } QString getSearchText() const; @@ -74,6 +90,8 @@ class WSearchLineEdit : public QLineEdit, public WBaseWidget { int m_frameWidth; int m_innerHeight; + int m_dropButtonWidth; QTimer m_debouncingTimer; + QTimer m_saveTimer; }; |