Index: Scribus.pro =================================================================== --- Scribus.pro (revision 23086) +++ Scribus.pro (working copy) @@ -20,6 +20,7 @@ # Input HEADERS += scribus/actionmanager.h \ + scribus/actionsearch.h \ scribus/annotation.h \ scribus/appmodehelper.h \ scribus/appmodes.h \ @@ -394,6 +395,7 @@ scribus/text/textsource.h \ scribus/ui/about.h \ scribus/ui/aboutplugins.h \ + scribus/ui/actionsearchdialog.h \ scribus/ui/AdapterWidget.h \ scribus/ui/adjustcmsdialog.h \ scribus/ui/aligndistribute.h \ @@ -1022,7 +1024,9 @@ scribus/plugins/tools/2geomtools/meshdistortion/meshdistortiondialog.h \ scribus/plugins/tools/2geomtools/pathalongpath/pathalongpath.h \ scribus/plugins/tools/2geomtools/pathalongpath/pathdialog.h + FORMS += scribus/ui/aboutplugins.ui \ + scribus/ui/actionsearchdialog.ui \ scribus/ui/aligndistribute.ui \ scribus/ui/annot.ui \ scribus/ui/arcvectorbase.ui \ @@ -1178,7 +1182,9 @@ scribus/plugins/scripter/python/sceditor/mainwindow.ui \ scribus/plugins/tools/2geomtools/meshdistortion/meshdistortiondialog.ui \ scribus/plugins/tools/2geomtools/pathalongpath/pathdialogbase.ui + SOURCES += scribus/actionmanager.cpp \ + scribus/actionsearch.cpp \ scribus/appmodehelper.cpp \ scribus/canvas.cpp \ scribus/canvasgesture_cellselect.cpp \ @@ -1514,6 +1520,7 @@ scribus/text/textsource.cpp \ scribus/ui/about.cpp \ scribus/ui/aboutplugins.cpp \ + scribus/ui/actionsearchdialog.cpp \ scribus/ui/AdapterWidget.cpp \ scribus/ui/adjustcmsdialog.cpp \ scribus/ui/aligndistribute.cpp \ Index: scribus/actionmanager.cpp =================================================================== --- scribus/actionmanager.cpp (revision 23086) +++ scribus/actionmanager.cpp (working copy) @@ -991,6 +991,8 @@ name="helpAboutQt"; scrActions->insert(name, new ScrAction("", defaultKey(name), mainWindow)); (*scrActions)[name]->setMenuRole(QAction::AboutQtRole); + name="helpActionSearch"; + scrActions->insert(name, new ScrAction("", defaultKey(name), mainWindow)); name="helpTooltips"; scrActions->insert(name, new ScrAction("", defaultKey(name), mainWindow)); name="helpManual"; @@ -1014,6 +1016,7 @@ connect( (*scrActions)["helpAboutScribus"], SIGNAL(triggered()), mainWindow, SLOT(slotHelpAbout()) ); connect( (*scrActions)["helpAboutPlugins"], SIGNAL(triggered()), mainWindow, SLOT(slotHelpAboutPlugins()) ); connect( (*scrActions)["helpAboutQt"], SIGNAL(triggered()), mainWindow, SLOT(slotHelpAboutQt()) ); + connect( (*scrActions)["helpActionSearch"], SIGNAL(triggered()), mainWindow, SLOT(slotHelpActionSearch()) ); connect( (*scrActions)["helpTooltips"], SIGNAL(triggered()), mainWindow, SLOT(ToggleTips()) ); connect( (*scrActions)["helpManual"], SIGNAL(triggered()), mainWindow, SLOT(slotOnlineHelp()) ); connect( (*scrActions)["helpCheckUpdates"], SIGNAL(triggered()), mainWindow, SLOT(slotHelpCheckUpdates()) ); @@ -1744,6 +1747,7 @@ (*scrActions)["helpAboutScribus"]->setTexts( tr("&About Scribus")); (*scrActions)["helpAboutPlugins"]->setTexts( tr("&About Plugins")); (*scrActions)["helpAboutQt"]->setTexts( tr("About &Qt")); + (*scrActions)["helpActionSearch"]->setTexts( tr("Action &Search")); (*scrActions)["helpTooltips"]->setTexts( tr("Toolti&ps")); (*scrActions)["showMouseCoordinates"]->setTexts( tr("Move/Resize Value Indicator")); (*scrActions)["helpManual"]->setTexts( tr("Scribus &Manual...")); @@ -1968,6 +1972,7 @@ //Extras Menu //Windows Menu //Help Menu + defKeys.insert("helpActionSearch", Qt::CTRL+Qt::Key_Slash); defKeys.insert("helpManual", Qt::Key_F1); //GUI and specials Index: scribus/actionsearch.cpp =================================================================== --- scribus/actionsearch.cpp (nonexistent) +++ scribus/actionsearch.cpp (working copy) @@ -0,0 +1,77 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "actionsearch.h" + +#include +#include +#include +#include +#include +#include + +ActionSearch::ActionSearch(QMenuBar *menuBar) + : menuBar{menuBar} +{ + +} + +void ActionSearch::update() +{ + m_actions.clear(); + + for (auto menuAction: menuBar->actions()) + readMenuActions(menuAction->menu()); +} + +void ActionSearch::execute(QString actionName) +{ + if (!m_actions.contains(actionName)) + return; + + QAction* action = m_actions[actionName]; + if (!action->isEnabled()) + return; + action->trigger(); +} + +void ActionSearch::readMenuActions(QMenu* menu) +{ + // TODO: check why menu can be null + if (menu == nullptr) + return; + + QStringList menus; + QMenu* currentMenu = menu; + while (currentMenu != nullptr) + { + QString title = currentMenu->title().replace("&", ""); + menus.prepend(title); + currentMenu = dynamic_cast(currentMenu->parentWidget()); + } + QString menuName = menus.join(" > "); + + for (auto action: menu->actions()) + { + if (action->menu() != nullptr) + { + readMenuActions(action->menu()); + continue; + } + + QString actionName = action->text().replace("&", ""); + if (actionName.isEmpty() || !action->isEnabled()) + continue; + + // TODO: we might want to have a multilevel menuName + if (!menuName.isEmpty()) + actionName += " (" + menuName +")"; + m_actions.insert(actionName, action); + } +} Index: scribus/actionsearch.h =================================================================== --- scribus/actionsearch.h (nonexistent) +++ scribus/actionsearch.h (working copy) @@ -0,0 +1,41 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef ACTIONSEARCH_H +#define ACTIONSEARCH_H + +class QAction; +class QMenu; +class QMenuBar; + +#include +#include + +#include "scribusapi.h" + +class SCRIBUS_API ActionSearch +{ +public: + ActionSearch(QMenuBar *menuBar); + ~ActionSearch() {} + + QList getActionNames() const { return m_actions.keys(); } + + void update(); + void execute(QString actionName); + +private: + QMenuBar* menuBar; + + void readMenuActions(QMenu* menu); + + QHash m_actions; // std::unordered_map +}; + +#endif Index: scribus/CMakeLists.txt =================================================================== --- scribus/CMakeLists.txt (revision 23086) +++ scribus/CMakeLists.txt (working copy) @@ -88,6 +88,7 @@ set(SCRIBUS_UI_SRC ui/aboutplugins.ui + ui/actionsearchdialog.ui ui/aligndistribute.ui ui/annot.ui ui/arcvectorbase.ui @@ -307,6 +308,7 @@ urllauncher.h ui/about.h ui/aboutplugins.h + ui/actionsearchdialog.h ui/adjustcmsdialog.h ui/aligndistribute.h ui/alignselect.h @@ -564,6 +566,7 @@ set(SCRIBUS_SOURCES actionmanager.cpp + actionsearch.cpp appmodehelper.cpp canvas.cpp canvasgesture_cellselect.cpp @@ -808,6 +811,7 @@ third_party/fparser/fparser.cc ui/about.cpp ui/aboutplugins.cpp + ui/actionsearchdialog.cpp ui/adjustcmsdialog.cpp ui/aligndistribute.cpp ui/alignselect.cpp Index: scribus/scribus.cpp =================================================================== --- scribus/scribus.cpp (revision 23086) +++ scribus/scribus.cpp (working copy) @@ -95,6 +95,7 @@ #include "actionmanager.h" +#include "actionsearch.h" #include "appmodehelper.h" #include "appmodes.h" #include "canvasmode.h" @@ -156,6 +157,7 @@ #include "tocgenerator.h" #include "ui/about.h" #include "ui/aboutplugins.h" +#include "ui/actionsearchdialog.h" #include "ui/adjustcmsdialog.h" #include "ui/aligndistribute.h" #include "ui/annot.h" @@ -1151,6 +1153,7 @@ scrMenuMgr->addMenuItemString("helpManual", "Help"); scrMenuMgr->addMenuItemString("helpChat", "Help"); scrMenuMgr->addMenuItemString("SEPARATOR", "Help"); + scrMenuMgr->addMenuItemString("helpActionSearch", "Help"); scrMenuMgr->addMenuItemString("helpTooltips", "Help"); scrMenuMgr->addMenuItemString("SEPARATOR", "Help"); scrMenuMgr->addMenuItemString("helpOnlineWWW", "Help"); @@ -5222,6 +5225,24 @@ ScMessageBox::aboutQt(this, tr("About Qt")); } +void ScribusMainWindow::slotHelpActionSearch() +{ + ActionSearch actionSearch(this->menuBar()); + actionSearch.update(); + + QScopedPointer dialog(new ActionSearchDialog(this, actionSearch.getActionNames())); + dialog->setModal(true); + + int result = dialog->exec(); + if (result != QDialog::Accepted) + return; + + QString actionName = dialog->getActionName(); + if (actionName.isEmpty()) + return; + actionSearch.execute(actionName); +} + void ScribusMainWindow::slotHelpCheckUpdates() { About dia(this, About::CheckUpdates); Index: scribus/scribus.h =================================================================== --- scribus/scribus.h (revision 23086) +++ scribus/scribus.h (working copy) @@ -390,6 +390,7 @@ void slotHelpAbout(); void slotHelpAboutPlugins(); void slotHelpAboutQt(); + void slotHelpActionSearch(); void slotHelpCheckUpdates(); void slotRaiseOnlineHelp(); void slotOnlineHelp(const QString & jumpToSection=QString(), const QString & jumpToFile=QString()); Index: scribus/ui/actionsearchdialog.cpp =================================================================== --- scribus/ui/actionsearchdialog.cpp (nonexistent) +++ scribus/ui/actionsearchdialog.cpp (working copy) @@ -0,0 +1,144 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "actionsearchdialog.h" +#include "ui_actionsearchdialog.h" + +ActionSearchDialog::ActionSearchDialog(QMainWindow *parent, QList actionNames) : + QDialog{parent}, + ui{new Ui::ActionSearchDialog}, + m_actionNames{actionNames} +{ + ui->setupUi(this); + + ui->filterLineEdit->installEventFilter(this); + installEventFilter(this); + + connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &ActionSearchDialog::updateList); + connect(this, &ActionSearchDialog::keyArrowUpPressed, this, &ActionSearchDialog::moveSelectionUp); + connect(this, &ActionSearchDialog::keyArrowDownPressed, this, &ActionSearchDialog::moveSelectionDown); + connect(ui->actionsListWidget, &QListWidget::itemDoubleClicked, this, &QDialog::accept); +} + +ActionSearchDialog::~ActionSearchDialog() +{ + delete ui; +} + +QString ActionSearchDialog::getActionName() const +{ + if (ui->actionsListWidget->count() == 0) + return QString(); + + return ui->actionsListWidget->currentItem()->text(); +} + +/** + * @brief capture return, arrow keys, and tab + */ +bool ActionSearchDialog::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == ui->filterLineEdit) { + if (event->type() == QEvent::KeyPress) { + return filterLineEditKeyPress(static_cast(event)); + } + } + return false; +} + +bool ActionSearchDialog::filterLineEditKeyPress(QKeyEvent * event) +{ + switch (event->key()) + { + case Qt::Key_Enter: + case Qt::Key_Return: + this->accept(); + return true; + case Qt::Key_Up: + emit keyArrowUpPressed(); + return true; + case Qt::Key_Down: + case Qt::Key_Tab: + emit keyArrowDownPressed(); + return true; + default: + return false; + } +} + +void ActionSearchDialog::moveSelectionUp() +{ + int i = ui->actionsListWidget->currentRow(); + if (i > 0) + { + ui->actionsListWidget->setCurrentRow(i - 1); + } +} + +void ActionSearchDialog::moveSelectionDown() +{ + int i = ui->actionsListWidget->currentRow(); + if (i < ui->actionsListWidget->count() - 1) + ui->actionsListWidget->setCurrentRow(i + 1); +} + + +/** + * Fill the list with all actions that match the filter. + * If the filter contains multiple words, acceppts all actions that + * contain all the words + */ +void ActionSearchDialog::updateList() +{ + ui->actionsListWidget->clear(); + + const auto filter = ui->filterLineEdit->text().trimmed(); + if (filter.isEmpty()) + return; + + if (!filter.contains(" ")) + { + for (const auto& name: m_actionNames) + { + if (name.contains(filter, Qt::CaseInsensitive)) + { + ui->actionsListWidget->addItem(name); + } + } + } + else + { + auto words = filter.split(" "); + for (const auto& name: m_actionNames) + { + bool matches(true); + for (const auto& word: words) + { + if (!name.contains(word, Qt::CaseInsensitive)) + { + matches = false; + break; + } + } + + if (!matches) + continue; + ui->actionsListWidget->addItem(name); + } + } + + if (ui->actionsListWidget->count() > 0) + ui->actionsListWidget->setCurrentRow(0); +} Index: scribus/ui/actionsearchdialog.h =================================================================== --- scribus/ui/actionsearchdialog.h (nonexistent) +++ scribus/ui/actionsearchdialog.h (working copy) @@ -0,0 +1,52 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef ACTIONSEARCHDIALOG_H +#define ACTIONSEARCHDIALOG_H + +class QKeyEvent; +class QMainWindow; +class QString; +class QEvent; + +#include +#include + +namespace Ui { class ActionSearchDialog; } + +class ActionSearchDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ActionSearchDialog(QMainWindow *parent, QList actionNames); + ~ActionSearchDialog(); + + QString getActionName() const; + +protected: + bool eventFilter(QObject *obj, QEvent *ev); + +private: + Ui::ActionSearchDialog *ui; + QList m_actionNames; + + bool filterLineEditKeyPress(QKeyEvent * event); + +private slots: + void moveSelectionUp(); + void moveSelectionDown(); + void updateList(); + +signals: + void keyArrowUpPressed(); + void keyArrowDownPressed(); +}; + +#endif Index: scribus/ui/actionsearchdialog.ui =================================================================== --- scribus/ui/actionsearchdialog.ui (nonexistent) +++ scribus/ui/actionsearchdialog.ui (working copy) @@ -0,0 +1,31 @@ + + + ActionSearchDialog + + + + 0 + 0 + 400 + 300 + + + + Action Search + + + + + + Search for action... + + + + + + + + + + + Index: win32/msvc2013/scribus-main/Scribus.vcxproj =================================================================== --- win32/msvc2013/scribus-main/Scribus.vcxproj (revision 23086) +++ win32/msvc2013/scribus-main/Scribus.vcxproj (working copy) @@ -236,6 +236,7 @@ + @@ -605,6 +606,7 @@ + @@ -843,6 +845,7 @@ + @@ -902,6 +905,7 @@ + @@ -1528,6 +1532,7 @@ + Index: win32/msvc2013/scribus-main/Scribus.vcxproj.filters =================================================================== --- win32/msvc2013/scribus-main/Scribus.vcxproj.filters (revision 23086) +++ win32/msvc2013/scribus-main/Scribus.vcxproj.filters (working copy) @@ -797,10 +797,10 @@ Header Files - + Header Files - + Header Files @@ -2488,6 +2488,12 @@ Source Files + + Source Files + + + Source Files + @@ -2866,6 +2872,9 @@ Form Files + + Form Files + @@ -4103,6 +4112,12 @@ Header Files + + Header Files + + + Header Files + Index: win32/msvc2015/scribus-main/Scribus.vcxproj =================================================================== --- win32/msvc2015/scribus-main/Scribus.vcxproj (revision 23086) +++ win32/msvc2015/scribus-main/Scribus.vcxproj (working copy) @@ -236,6 +236,7 @@ + @@ -605,6 +606,7 @@ + @@ -843,6 +845,7 @@ + @@ -902,6 +905,7 @@ + @@ -1528,6 +1532,7 @@ + Index: win32/msvc2015/scribus-main/Scribus.vcxproj.filters =================================================================== --- win32/msvc2015/scribus-main/Scribus.vcxproj.filters (revision 23086) +++ win32/msvc2015/scribus-main/Scribus.vcxproj.filters (working copy) @@ -797,10 +797,10 @@ Header Files - + Header Files - + Header Files @@ -2488,6 +2488,12 @@ Source Files + + Source Files + + + Source Files + @@ -2866,6 +2872,9 @@ Form Files + + Form Files + @@ -4103,6 +4112,12 @@ Header Files + + Header Files + + + Header Files +