diff --git a/Pdf4QtViewer/pdfactioncombobox.cpp b/Pdf4QtViewer/pdfactioncombobox.cpp index b94fc9b..e3cc285 100644 --- a/Pdf4QtViewer/pdfactioncombobox.cpp +++ b/Pdf4QtViewer/pdfactioncombobox.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include namespace pdfviewer { @@ -30,37 +32,26 @@ PDFActionComboBox::PDFActionComboBox(QWidget* parent) : BaseClass(parent), m_model(nullptr) { - setEditable(true); - lineEdit()->setPlaceholderText(tr("Find action...")); - lineEdit()->setClearButtonEnabled(true); + setPlaceholderText(tr("Find action...")); + setClearButtonEnabled(true); setMinimumWidth(pdf::PDFWidgetUtils::scaleDPI_x(this, DEFAULT_WIDTH)); m_model = new QStandardItemModel(this); - m_proxyModel = new QSortFilterProxyModel(this); - - m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - m_proxyModel->setDynamicSortFilter(true); - m_proxyModel->setFilterKeyColumn(0); - m_proxyModel->setFilterRole(Qt::DisplayRole); - m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); - m_proxyModel->setSortLocaleAware(true); - m_proxyModel->setSortRole(Qt::DisplayRole); - m_proxyModel->setSourceModel(m_model); + QCompleter* completer = new QCompleter(m_model, this); setFocusPolicy(Qt::StrongFocus); - setCompleter(nullptr); - setInsertPolicy(QComboBox::NoInsert); -/* - completer()->setCompletionMode(QCompleter::PopupCompletion); - completer()->setCompletionColumn(-1); - completer()->setFilterMode(Qt::MatchContains | Qt::MatchWildcard); - completer()->setCaseSensitivity(Qt::CaseInsensitive); - completer()->setModelSorting(QCompleter::UnsortedModel);*/ + setCompleter(completer); - connect(this, &PDFActionComboBox::activated, this, &PDFActionComboBox::onActionActivated); - connect(this, &PDFActionComboBox::editTextChanged, this, &PDFActionComboBox::onEditTextChanged, Qt::QueuedConnection); + completer->setCompletionMode(QCompleter::PopupCompletion); + completer->setCompletionColumn(0); + completer->setCompletionRole(Qt::DisplayRole); + completer->setFilterMode(Qt::MatchContains); + completer->setCaseSensitivity(Qt::CaseInsensitive); + completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel); + completer->setWrapAround(false); + completer->setMaxVisibleItems(20); - setModel(m_proxyModel); + connect(this, &QLineEdit::editingFinished, this, &PDFActionComboBox::performExecuteAction, Qt::QueuedConnection); } QSize PDFActionComboBox::sizeHint() const @@ -87,54 +78,85 @@ void PDFActionComboBox::addQuickFindAction(QAction* action) } } +bool PDFActionComboBox::event(QEvent* event) +{ + if (event->type() == QEvent::ShortcutOverride) + { + QKeyEvent* keyEvent = dynamic_cast(event); + switch (keyEvent->key()) + { + case Qt::Key_Down: + case Qt::Key_Up: + event->accept(); + return true; + } + } + + if (event->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = dynamic_cast(event); + + // Redirect up and down arrows to the completer + switch (keyEvent->key()) + { + case Qt::Key_Down: + case Qt::Key_Up: + { + if (completer()) + { + if (completer()->popup()->isVisible()) + { + QCoreApplication::sendEvent(completer()->popup(), event); + } + else + { + completer()->complete(); + } + } + return true; + } + + case Qt::Key_Enter: + case Qt::Key_Return: + clearFocus(); + return true; + + default: + break; + } + } + + return BaseClass::event(event); +} + void PDFActionComboBox::onActionChanged() { QAction* action = qobject_cast(sender()); updateAction(action); } -void PDFActionComboBox::onActionActivated(int index) +void PDFActionComboBox::performExecuteAction() { - QVariant actionData = itemData(index, Qt::UserRole); - QAction* action = actionData.value(); + QString text = this->text(); - lineEdit()->clear(); - setCurrentIndex(-1); + QAction* action = nullptr; + for (QAction* currentAction : m_actions) + { + if (currentAction->text() == text) + { + action = currentAction; + } + } - if (action && action->isEnabled()) + clear(); + completer()->setCompletionPrefix(QString()); + + if (action) { action->trigger(); } } -void PDFActionComboBox::onEditTextChanged(const QString& text) -{ - if (text.isEmpty()) - { - m_proxyModel->setFilterFixedString(QString()); - } - else if (text.contains(QChar('*')) || text.contains(QChar('?'))) - { - m_proxyModel->setFilterWildcard(text); - } - else - { - m_proxyModel->setFilterFixedString(text); - } - - if (!text.isEmpty()) - { - showPopup(); - } - else - { - hidePopup(); - } - - lineEdit()->setFocus(); - lineEdit()->setCursorPosition(text.size()); -} - void PDFActionComboBox::updateAction(QAction* action) { if (!action) @@ -166,8 +188,6 @@ void PDFActionComboBox::updateAction(QAction* action) m_model->removeRow(actionIndex); } } - - setCurrentIndex(-1); } int PDFActionComboBox::findAction(QAction* action) diff --git a/Pdf4QtViewer/pdfactioncombobox.h b/Pdf4QtViewer/pdfactioncombobox.h index 32709c7..7c3a545 100644 --- a/Pdf4QtViewer/pdfactioncombobox.h +++ b/Pdf4QtViewer/pdfactioncombobox.h @@ -22,6 +22,7 @@ #include #include +#include class QStandardItemModel; class QSortFilterProxyModel; @@ -29,18 +30,19 @@ class QSortFilterProxyModel; namespace pdfviewer { -class PDFActionComboBox : public QComboBox +class PDFActionComboBox : public QLineEdit { Q_OBJECT private: - using BaseClass = QComboBox; + using BaseClass = QLineEdit; public: PDFActionComboBox(QWidget* parent); virtual QSize sizeHint() const override; virtual QSize minimumSizeHint() const override; + virtual bool event(QEvent* event) override; void addQuickFindAction(QAction* action); @@ -48,15 +50,13 @@ private: static constexpr int DEFAULT_WIDTH = 220; void onActionChanged(); - void onActionActivated(int index); - void onEditTextChanged(const QString& text); + void performExecuteAction(); void updateAction(QAction* action); int findAction(QAction* action); std::vector m_actions; QStandardItemModel* m_model; - QSortFilterProxyModel* m_proxyModel; }; } // namespace pdfviewer diff --git a/RELEASES.txt b/RELEASES.txt index 08eb77f..d970570 100644 --- a/RELEASES.txt +++ b/RELEASES.txt @@ -1,4 +1,5 @@ CURRENT: + - Issue #134: Add search bar for actions - Issue #129: Cannot compile with lcms 2.16 - Issue #128: Create list of markup annotations - Issue #126: Remove include from main headers