diff --git a/src/qtgui/actsearch.ui b/src/qtgui/actsearch.ui
new file mode 100644
index 00000000..e10f51e7
--- /dev/null
+++ b/src/qtgui/actsearch.ui
@@ -0,0 +1,37 @@
+
+
+ ActSearchDLG
+
+
+
+ 0
+ 0
+ 314
+ 43
+
+
+
+ Menu search
+
+
+ -
+
+
+ true
+
+
+ 15
+
+
+ QComboBox::NoInsert
+
+
+ false
+
+
+
+
+
+
+
+
diff --git a/src/qtgui/actsearch_w.cpp b/src/qtgui/actsearch_w.cpp
new file mode 100644
index 00000000..973fed8f
--- /dev/null
+++ b/src/qtgui/actsearch_w.cpp
@@ -0,0 +1,111 @@
+/* Copyright (C) 2020-2021 J.F.Dockes
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "autoconfig.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include "log.h"
+#include "actsearch_w.h"
+
+// A window for letting the user to search among menu entries (actions) and execute the one found.
+
+void ActSearchW::init()
+{
+ new QShortcut(QKeySequence("Esc"), this, SLOT(hide()));
+ connect(actCMB, SIGNAL(activated(int)), this, SLOT(onActivated(int)));
+}
+
+void ActSearchW::setActList(QList actlist)
+{
+ for (int i = 0; i < actlist.size(); i++) {
+ if (!actlist[i]->text().isEmpty()) {
+ m_actions.push_back(actlist[i]);
+ }
+ }
+ std::sort(m_actions.begin(), m_actions.end(),
+ [] (const QAction *act1, const QAction *act2) {
+ auto txt1 = act1->text().remove('&');
+ auto txt2 = act2->text().remove('&');
+ return txt1.compare(txt2, Qt::CaseInsensitive) < 0;});
+ QStringList sl;
+ for (const auto act : m_actions) {
+ auto txt = act->text().remove('&');
+ actCMB->addItem(txt);
+ sl.push_back(txt);
+ }
+ actCMB->setCurrentText("");
+ m_completer = new QCompleter(sl, this);
+ m_completer->setCaseSensitivity(Qt::CaseInsensitive);
+ if (m_match_contains) {
+ m_completer->setFilterMode(Qt::MatchContains);
+ }
+ actCMB->setCompleter(m_completer);
+ m_completer->popup()->installEventFilter(this);
+ actCMB->installEventFilter(this);
+}
+
+// This is to avoid that if the user types Backspace or Del while we
+// have inserted / selected the current completion, the lineedit text
+// goes back to what it was, the completion fires, and it looks like
+// nothing was typed. Disable the completion after Del or Backspace
+// is typed.
+bool ActSearchW::eventFilter(QObject *target, QEvent *event)
+{
+ Q_UNUSED(target);
+ if (event->type() != QEvent::KeyPress) {
+ return false;
+ }
+ QKeyEvent *keyEvent = (QKeyEvent *)event;
+ if (keyEvent->key() == Qt::Key_Backspace || keyEvent->key()==Qt::Key_Delete) {
+ actCMB->setCompleter(nullptr);
+ return false;
+ } else {
+ if (nullptr == actCMB->completer()) {
+ actCMB->setCompleter(m_completer);
+ }
+ }
+ return false;
+}
+
+void ActSearchW::onTextChanged(const QString&)
+{
+ if (actCMB->completer() && actCMB->completer()->completionCount() == 1) {
+ // We append the completion part to the end of the current input, line, and select it so
+ // that the user has a clear indication of what will happen if they type Enter.
+ auto le = actCMB->lineEdit();
+ int pos = le->cursorPosition();
+ auto text = actCMB->completer()->currentCompletion();
+ int len = text.size() - actCMB->currentText().size();
+ le->setText(text);
+ if (!m_match_contains) {
+ le->setCursorPosition(pos);
+ le->setSelection(pos, len);
+ }
+ }
+}
+
+void ActSearchW::onActivated(int index)
+{
+ if (index < 0 || index >= int(m_actions.size()))
+ return;
+ m_actions[index]->trigger();
+ hide();
+}
diff --git a/src/qtgui/actsearch_w.h b/src/qtgui/actsearch_w.h
new file mode 100644
index 00000000..a334c900
--- /dev/null
+++ b/src/qtgui/actsearch_w.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2021 J.F.Dockes
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef _ACTSEARCH_H_INCLUDED_
+#define _ACTSEARCH_H_INCLUDED_
+
+// A window for letting the user to search among menu entries (actions) and execute the one found.
+
+#include
+#include
+
+#include
+
+#include "ui_actsearch.h"
+
+class QCompleter;
+class QAction;
+class QString;
+
+class ActSearchW : public QDialog, public Ui::ActSearchDLG {
+ Q_OBJECT;
+public:
+ ActSearchW(QWidget* parent = 0)
+ : QDialog(parent) {
+ setupUi(this);
+ init();
+ }
+ void setActList(QList);
+ virtual bool eventFilter(QObject *target, QEvent *event);
+
+private slots:
+ void onActivated(int);
+ void onTextChanged(const QString&);
+
+private:
+ void init();
+ std::vector m_actions;
+ QCompleter *m_completer{nullptr};
+ // Decides if we match the start only or anywhere. Anywhere seems better. May be made a pref one
+ // day.
+ bool m_match_contains{true};
+};
+
+#endif /* _ACTSEARCH_H_INCLUDED_ */
diff --git a/src/qtgui/rclm_wins.cpp b/src/qtgui/rclm_wins.cpp
index 7c8a551b..a917383e 100644
--- a/src/qtgui/rclm_wins.cpp
+++ b/src/qtgui/rclm_wins.cpp
@@ -36,6 +36,7 @@
#include "rclmain_w.h"
#include "webcache.h"
#include "restable.h"
+#include "actsearch_w.h"
using namespace std;
@@ -489,3 +490,16 @@ void RclMain::showSnippets(Rcl::Doc doc)
}
m_snippets->show();
}
+
+void RclMain::showActionsSearch()
+{
+ if (nullptr == actsearchw) {
+ actsearchw = new ActSearchW(this);
+ actsearchw->setActList(findChildren());
+ connect(actsearchw->actCMB, SIGNAL(editTextChanged(const QString&)),
+ actsearchw, SLOT(onTextChanged(const QString&)));
+ }
+ actsearchw->actCMB->setCurrentIndex(-1);
+ actsearchw->actCMB->clearEditText();
+ actsearchw->show();
+}
diff --git a/src/qtgui/rclmain_w.cpp b/src/qtgui/rclmain_w.cpp
index 9ae403f6..d12845dd 100644
--- a/src/qtgui/rclmain_w.cpp
+++ b/src/qtgui/rclmain_w.cpp
@@ -367,12 +367,11 @@ void RclMain::onNewShortcuts()
"Ctrl+Shift+S", m_focustosearcholdsc, takeFocus);
// We could set this as an action shortcut, but then, it would not
// be editable
- SETSHORTCUT(this, "main:357",
- tr("Main Window"), tr("Toggle tabular display"),
+ SETSHORTCUT(this, "main:357", tr("Main Window"), tr("Toggle tabular display"),
"Ctrl+T", m_toggletablesc, toggleTable);
-
- ks = scb.get("rclmain:361", tr("Main Window"),
- tr("Move keyboard focus to table"), "Ctrl+R");
+ SETSHORTCUT(this, "main:373", tr("Main Window"), tr("Show menu search dialog"),
+ "Alt+/", m_actionssearchsc, showActionsSearch);
+ ks = scb.get("rclmain:361", tr("Main Window"), tr("Move keyboard focus to table"), "Ctrl+R");
if (!ks.isEmpty()) {
delete m_focustotablesc;
m_focustotablesc = new QShortcut(ks, this);
diff --git a/src/qtgui/rclmain_w.h b/src/qtgui/rclmain_w.h
index 679ce8c3..592e9ad4 100644
--- a/src/qtgui/rclmain_w.h
+++ b/src/qtgui/rclmain_w.h
@@ -50,6 +50,7 @@ class ConfIndexW;
class RclTrayIcon;
class QShortcut;
class QActionGroup;
+class ActSearchW;
#include "ui_rclmain.h"
@@ -134,6 +135,7 @@ public slots:
virtual void docExpand(Rcl::Doc);
virtual void showSubDocs(Rcl::Doc);
virtual void showSnippets(Rcl::Doc);
+ virtual void showActionsSearch();
virtual void startPreview(int docnum, Rcl::Doc doc, int keymods);
virtual void startPreview(Rcl::Doc);
virtual void startNativeViewer(Rcl::Doc, int pagenum = -1,
@@ -176,7 +178,7 @@ private slots:
virtual void onWebcacheDestroyed(QObject *);
virtual void onSSTypMenu(QAction *act);
virtual void onSSTypCMB(int);
-
+
signals:
void docSourceChanged(std::shared_ptr);
void stemLangChanged(const QString& lang);
@@ -210,6 +212,7 @@ private:
WebcacheEdit *webcache{0};
ResTable *restable{0};
bool displayingTable{false};
+ ActSearchW *actsearchw{0};
QAction *m_idNoStem{0};
QAction *m_idAllStem{0};
QToolBar *m_toolsTB{0};
@@ -223,6 +226,7 @@ private:
QShortcut *m_focustosearcholdsc{0};
QShortcut *m_clearsearchsc{0};
QShortcut *m_toggletablesc{0};
+ QShortcut *m_actionssearchsc{0};
QFileSystemWatcher m_watcher;
vector m_viewers;
ExecCmd *m_idxproc{0}; // Indexing process
diff --git a/src/qtgui/recoll-win.pro b/src/qtgui/recoll-win.pro
index 350a0c05..730ce39a 100644
--- a/src/qtgui/recoll-win.pro
+++ b/src/qtgui/recoll-win.pro
@@ -1,5 +1,5 @@
# Note this is generated by configure on Linux (see recoll.pro.in).
-# recoll.pro is under version control anyway and used on Windows
+# recoll-win.pro is under version control anyway and used on Windows
TEMPLATE = app
LANGUAGE = C++
@@ -15,6 +15,7 @@ QT += xml printsupport
DEFINES += BUILDING_RECOLL
HEADERS += \
+ actsearch_w.h \
advsearch_w.h \
advshist.h \
confgui/confgui.h \
@@ -45,6 +46,7 @@ HEADERS += \
webcache.h
SOURCES += \
+ actsearch_w.cpp \
advsearch_w.cpp \
advshist.cpp \
confgui/confgui.cpp \
diff --git a/src/qtgui/recoll.pro.in b/src/qtgui/recoll.pro.in
index 134bc378..b3c331ac 100644
--- a/src/qtgui/recoll.pro.in
+++ b/src/qtgui/recoll.pro.in
@@ -27,6 +27,7 @@ CONFIG += qt warn_on thread release
HEADERS += \
+ actsearch_w.h \
advsearch_w.h \
advshist.h \
confgui/confgui.h \
@@ -59,6 +60,7 @@ HEADERS += \
widgets/qxtconfirmationmessage.h
SOURCES += \
+ actsearch_w.cpp \
advsearch_w.cpp \
advshist.cpp \
confgui/confgui.cpp \
@@ -98,6 +100,7 @@ SOURCES += \
xmltosd.cpp
FORMS = \
+ actsearch.ui \
advsearch.ui \
crontool.ui \
firstidx.ui \