Core: add menu bar locator filter

Adding the possibility to trigger menu actions from the locator

Change-Id: I70d595c167f5b43b02f8125eafbb83e5b45012c9
Reviewed-by: André Hartmann <aha_1980@gmx.de>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
David Schulz
2018-01-10 14:32:21 +01:00
parent 0af3a2d29a
commit 92ec21e5b5
5 changed files with 373 additions and 73 deletions

View File

@@ -26,12 +26,13 @@
#include "coreplugin.h"
#include "designmode.h"
#include "editmode.h"
#include "idocument.h"
#include "helpmanager.h"
#include "mainwindow.h"
#include "modemanager.h"
#include "idocument.h"
#include "infobar.h"
#include "iwizardfactory.h"
#include "mainwindow.h"
#include "menubarfilter.h"
#include "modemanager.h"
#include "reaper_p.h"
#include "themechooser.h"
@@ -162,6 +163,8 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
InfoBar::initialize(ICore::settings(), creatorTheme());
}
addAutoReleasedObject(new MenuBarFilter);
IWizardFactory::initialize();
// Make sure we respect the process's umask when creating new files

View File

@@ -111,7 +111,8 @@ SOURCES += corejsextensions.cpp \
externaltoolmanager.cpp \
systemsettings.cpp \
coreicons.cpp \
diffservice.cpp
diffservice.cpp \
menubarfilter.cpp
HEADERS += corejsextensions.h \
mainwindow.h \
@@ -222,7 +223,8 @@ HEADERS += corejsextensions.h \
systemsettings.h \
coreicons.h \
editormanager/documentmodel_p.h \
diffservice.h
diffservice.h \
menubarfilter.h
FORMS += dialogs/newdialog.ui \
dialogs/saveitemsdialog.ui \

View File

@@ -32,79 +32,154 @@ Project {
Group {
name: "General"
files: [
"basefilewizard.cpp", "basefilewizard.h",
"basefilewizardfactory.cpp", "basefilewizardfactory.h",
"basefilewizard.cpp",
"basefilewizard.h",
"basefilewizardfactory.cpp",
"basefilewizardfactory.h",
"core.qrc",
"core_global.h",
"coreconstants.h",
"coreicons.cpp", "coreicons.h",
"corejsextensions.cpp", "corejsextensions.h",
"coreplugin.cpp", "coreplugin.h",
"designmode.cpp", "designmode.h",
"diffservice.cpp", "diffservice.h",
"documentmanager.cpp", "documentmanager.h",
"editmode.cpp", "editmode.h",
"editortoolbar.cpp", "editortoolbar.h",
"externaltool.cpp", "externaltool.h",
"externaltoolmanager.cpp", "externaltoolmanager.h",
"fancyactionbar.cpp", "fancyactionbar.h", "fancyactionbar.qrc",
"fancytabwidget.cpp", "fancytabwidget.h",
"featureprovider.cpp", "featureprovider.h",
"fileiconprovider.cpp", "fileiconprovider.h",
"fileutils.cpp", "fileutils.h",
"findplaceholder.cpp", "findplaceholder.h",
"generalsettings.cpp", "generalsettings.h", "generalsettings.ui",
"generatedfile.cpp", "generatedfile.h",
"helpmanager.cpp", "helpmanager.h",
"icontext.cpp", "icontext.h",
"icore.cpp", "icore.h",
"id.cpp", "id.h",
"idocument.cpp", "idocument.h",
"idocumentfactory.cpp", "idocumentfactory.h",
"coreicons.cpp",
"coreicons.h",
"corejsextensions.cpp",
"corejsextensions.h",
"coreplugin.cpp",
"coreplugin.h",
"designmode.cpp",
"designmode.h",
"diffservice.cpp",
"diffservice.h",
"documentmanager.cpp",
"documentmanager.h",
"editmode.cpp",
"editmode.h",
"editortoolbar.cpp",
"editortoolbar.h",
"externaltool.cpp",
"externaltool.h",
"externaltoolmanager.cpp",
"externaltoolmanager.h",
"fancyactionbar.cpp",
"fancyactionbar.h",
"fancyactionbar.qrc",
"fancytabwidget.cpp",
"fancytabwidget.h",
"featureprovider.cpp",
"featureprovider.h",
"fileiconprovider.cpp",
"fileiconprovider.h",
"fileutils.cpp",
"fileutils.h",
"findplaceholder.cpp",
"findplaceholder.h",
"generalsettings.cpp",
"generalsettings.h",
"generalsettings.ui",
"generatedfile.cpp",
"generatedfile.h",
"helpmanager.cpp",
"helpmanager.h",
"icontext.cpp",
"icontext.h",
"icore.cpp",
"icore.h",
"id.cpp",
"id.h",
"idocument.cpp",
"idocument.h",
"idocumentfactory.cpp",
"idocumentfactory.h",
"ifilewizardextension.h",
"imode.cpp", "imode.h",
"inavigationwidgetfactory.cpp", "inavigationwidgetfactory.h",
"infobar.cpp", "infobar.h",
"ioutputpane.cpp", "ioutputpane.h",
"iversioncontrol.cpp", "iversioncontrol.h",
"iwelcomepage.cpp", "iwelcomepage.h",
"iwizardfactory.cpp", "iwizardfactory.h",
"jsexpander.cpp", "jsexpander.h",
"mainwindow.cpp", "mainwindow.h",
"manhattanstyle.cpp", "manhattanstyle.h",
"messagebox.cpp", "messagebox.h",
"messagemanager.cpp", "messagemanager.h",
"messageoutputwindow.cpp", "messageoutputwindow.h",
"mimetypemagicdialog.cpp", "mimetypemagicdialog.h", "mimetypemagicdialog.ui",
"mimetypesettings.cpp", "mimetypesettings.h",
"imode.cpp",
"imode.h",
"inavigationwidgetfactory.cpp",
"inavigationwidgetfactory.h",
"infobar.cpp",
"infobar.h",
"ioutputpane.cpp",
"ioutputpane.h",
"iversioncontrol.cpp",
"iversioncontrol.h",
"iwelcomepage.cpp",
"iwelcomepage.h",
"iwizardfactory.cpp",
"iwizardfactory.h",
"jsexpander.cpp",
"jsexpander.h",
"mainwindow.cpp",
"mainwindow.h",
"manhattanstyle.cpp",
"manhattanstyle.h",
"menubarfilter.cpp",
"menubarfilter.h",
"messagebox.cpp",
"messagebox.h",
"messagemanager.cpp",
"messagemanager.h",
"messageoutputwindow.cpp",
"messageoutputwindow.h",
"mimetypemagicdialog.cpp",
"mimetypemagicdialog.h",
"mimetypemagicdialog.ui",
"mimetypesettings.cpp",
"mimetypesettings.h",
"mimetypesettingspage.ui",
"minisplitter.cpp", "minisplitter.h",
"modemanager.cpp", "modemanager.h",
"navigationsubwidget.cpp", "navigationsubwidget.h",
"navigationwidget.cpp", "navigationwidget.h",
"opendocumentstreeview.cpp", "opendocumentstreeview.h",
"outputpane.cpp", "outputpane.h",
"outputpanemanager.cpp", "outputpanemanager.h",
"outputwindow.cpp", "outputwindow.h",
"patchtool.cpp", "patchtool.h",
"plugindialog.cpp", "plugindialog.h",
"reaper.cpp", "reaper.h", "reaper_p.h",
"rightpane.cpp", "rightpane.h",
"settingsdatabase.cpp", "settingsdatabase.h",
"shellcommand.cpp", "shellcommand.h",
"sidebar.cpp", "sidebar.h",
"sidebarwidget.cpp", "sidebarwidget.h",
"statusbarmanager.cpp", "statusbarmanager.h",
"statusbarwidget.cpp", "statusbarwidget.h",
"styleanimator.cpp", "styleanimator.h",
"systemsettings.cpp", "systemsettings.h", "systemsettings.ui",
"textdocument.cpp", "textdocument.h",
"themechooser.cpp", "themechooser.h",
"toolsettings.cpp", "toolsettings.h",
"variablechooser.cpp", "variablechooser.h",
"vcsmanager.cpp", "vcsmanager.h",
"versiondialog.cpp", "versiondialog.h",
"windowsupport.cpp", "windowsupport.h"
"minisplitter.cpp",
"minisplitter.h",
"modemanager.cpp",
"modemanager.h",
"navigationsubwidget.cpp",
"navigationsubwidget.h",
"navigationwidget.cpp",
"navigationwidget.h",
"opendocumentstreeview.cpp",
"opendocumentstreeview.h",
"outputpane.cpp",
"outputpane.h",
"outputpanemanager.cpp",
"outputpanemanager.h",
"outputwindow.cpp",
"outputwindow.h",
"patchtool.cpp",
"patchtool.h",
"plugindialog.cpp",
"plugindialog.h",
"reaper.cpp",
"reaper.h",
"reaper_p.h",
"rightpane.cpp",
"rightpane.h",
"settingsdatabase.cpp",
"settingsdatabase.h",
"shellcommand.cpp",
"shellcommand.h",
"sidebar.cpp",
"sidebar.h",
"sidebarwidget.cpp",
"sidebarwidget.h",
"statusbarmanager.cpp",
"statusbarmanager.h",
"statusbarwidget.cpp",
"statusbarwidget.h",
"styleanimator.cpp",
"styleanimator.h",
"systemsettings.cpp",
"systemsettings.h",
"systemsettings.ui",
"textdocument.cpp",
"textdocument.h",
"themechooser.cpp",
"themechooser.h",
"toolsettings.cpp",
"toolsettings.h",
"variablechooser.cpp",
"variablechooser.h",
"vcsmanager.cpp",
"vcsmanager.h",
"versiondialog.cpp",
"versiondialog.h",
"windowsupport.cpp",
"windowsupport.h",
]
}

View File

@@ -0,0 +1,162 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "menubarfilter.h"
#include "actionmanager/actioncontainer.h"
#include "actionmanager/actionmanager.h"
#include "coreconstants.h"
#include <utils/algorithm.h>
#include <utils/asconst.h>
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
#include <QMenuBar>
#include <QPointer>
#include <QRegularExpression>
using namespace Core::Internal;
using namespace Core;
MenuBarFilter::MenuBarFilter()
{
setId("Actions from the menu");
setDisplayName(tr("Actions from the Menu"));
setShortcutString("t");
}
static const QList<QAction *> menuBarActions()
{
QMenuBar *menuBar = Core::ActionManager::actionContainer(Constants::MENU_BAR)->menuBar();
QTC_ASSERT(menuBar, return {});
return menuBar->actions();
}
QList<LocatorFilterEntry> MenuBarFilter::matchesFor(QFutureInterface<LocatorFilterEntry> &future,
const QString &entry)
{
Q_UNUSED(future);
static const QString separators = ". >/";
static const QRegularExpression seperatorRegExp(QString("[%1]").arg(separators));
QList<LocatorFilterEntry> entries;
QString normalized = entry;
normalized.replace(seperatorRegExp, separators.at(0));
const QStringList entryPath = normalized.split(separators.at(0), QString::SkipEmptyParts);
QVector<const QMenu *> processedMenus;
for (QAction* action : menuBarActions())
entries << matchesForAction(action, entryPath, QStringList(), processedMenus);
return entries;
}
void MenuBarFilter::accept(LocatorFilterEntry selection, QString *newText,
int *selectionStart, int *selectionLength) const
{
Q_UNUSED(newText);
Q_UNUSED(selectionStart);
Q_UNUSED(selectionLength);
if (auto action = selection.internalData.value<QPointer<QAction>>())
action->trigger();
}
void MenuBarFilter::refresh(QFutureInterface<void> &future)
{
Q_UNUSED(future);
}
QList<LocatorFilterEntry> MenuBarFilter::matchesForAction(QAction *action,
const QStringList &entryPath,
const QStringList &path,
QVector<const QMenu *> &processedMenus)
{
QList<LocatorFilterEntry> entries;
if (!action->isEnabled())
return entries;
const QString text = Utils::stripAccelerator(action->text());
if (QMenu *menu = action->menu()) {
if (processedMenus.contains(menu))
return entries;
processedMenus.append(menu);
if (menu->isEnabled()) {
const QList<QAction *> &actions = menu->actions();
QStringList menuPath(path);
menuPath << text;
for (QAction *menuAction : actions)
entries << matchesForAction(menuAction, entryPath, menuPath, processedMenus);
}
} else if (!text.isEmpty()) {
int entryIndex = 0;
int entryLength = 0;
int pathIndex = 0;
LocatorFilterEntry::HighlightInfo::DataType highlightType =
LocatorFilterEntry::HighlightInfo::DisplayName;
const QString pathText = path.join(" > ");
QStringList actionPath(path);
if (!entryPath.isEmpty()) {
actionPath << text;
for (const QString &entry : entryPath) {
const QRegularExpression re(".*" + entry + ".*",
QRegularExpression::CaseInsensitiveOption);
pathIndex = actionPath.indexOf(re, pathIndex);
if (pathIndex < 0)
return entries;
}
const QString &lastEntry(entryPath.last());
entryLength = lastEntry.length();
entryIndex = text.indexOf(lastEntry, 0, Qt::CaseInsensitive);
if (entryIndex >= 0) {
highlightType = LocatorFilterEntry::HighlightInfo::DisplayName;
} else {
entryIndex = pathText.indexOf(lastEntry, 0, Qt::CaseInsensitive);
QTC_ASSERT(entryIndex >= 0, return entries);
highlightType = LocatorFilterEntry::HighlightInfo::ExtraInfo;
}
}
LocatorFilterEntry filterEntry(this, text, QVariant(), action->icon());
filterEntry.internalData.setValue(QPointer<QAction>(action));
filterEntry.extraInfo = pathText;
filterEntry.highlightInfo = {entryIndex, entryLength, highlightType};
entries << filterEntry;
}
return entries;
}
static void requestMenuUpdate(const QAction* action)
{
if (QMenu *menu = action->menu()) {
emit menu->aboutToShow();
const QList<QAction *> &actions = menu->actions();
for (const QAction *menuActions : actions)
requestMenuUpdate(menuActions);
}
}
void Core::Internal::MenuBarFilter::prepareSearch(const QString &entry)
{
Q_UNUSED(entry);
for (const QAction *action : menuBarActions())
requestMenuUpdate(action);
}

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <coreplugin/locator/ilocatorfilter.h>
QT_BEGIN_NAMESPACE
class QAction;
class QMenu;
QT_END_NAMESPACE
namespace Core {
namespace Internal {
class MenuBarFilter : public ILocatorFilter
{
public:
MenuBarFilter();
QList<LocatorFilterEntry> matchesFor(QFutureInterface<LocatorFilterEntry> &future,
const QString &entry) override;
void accept(LocatorFilterEntry selection, QString *newText,
int *selectionStart, int *selectionLength) const override;
void refresh(QFutureInterface<void> &future) override;
void prepareSearch(const QString &entry) override;
private:
QList<LocatorFilterEntry> matchesForAction(QAction *action,
const QStringList &entryPath,
const QStringList &path,
QVector<const QMenu *> &processedMenus);
};
} // namespace Internal
} // namespace Core