Implement menu search window: look for menu entry and activate it

This commit is contained in:
Jean-Francois Dockes 2021-10-08 09:49:07 +02:00
parent ffcd856353
commit 80146437d8
8 changed files with 234 additions and 7 deletions

37
src/qtgui/actsearch.ui Normal file
View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ActSearchDLG</class>
<widget class="QDialog" name="ActSearchDLG">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>314</width>
<height>43</height>
</rect>
</property>
<property name="windowTitle">
<string>Menu search</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="actCMB">
<property name="editable">
<bool>true</bool>
</property>
<property name="maxVisibleItems">
<number>15</number>
</property>
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
<property name="frame">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

111
src/qtgui/actsearch_w.cpp Normal file
View File

@ -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 <QShortcut>
#include <QCompleter>
#include <QAbstractItemView>
#include <QLineEdit>
#include <QAction>
#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<QAction*> 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();
}

57
src/qtgui/actsearch_w.h Normal file
View File

@ -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 <QDialog>
#include <QList>
#include <vector>
#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<QAction *>);
virtual bool eventFilter(QObject *target, QEvent *event);
private slots:
void onActivated(int);
void onTextChanged(const QString&);
private:
void init();
std::vector<QAction *> 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_ */

View File

@ -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<QAction *>());
connect(actsearchw->actCMB, SIGNAL(editTextChanged(const QString&)),
actsearchw, SLOT(onTextChanged(const QString&)));
}
actsearchw->actCMB->setCurrentIndex(-1);
actsearchw->actCMB->clearEditText();
actsearchw->show();
}

View File

@ -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);

View File

@ -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<DocSequence>);
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<ExecCmd*> m_viewers;
ExecCmd *m_idxproc{0}; // Indexing process

View File

@ -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 \

View File

@ -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 \