diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp index 3b5f4dffb93..6e4f34133e2 100644 --- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp +++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp @@ -246,9 +246,13 @@ QList ActionManagerPrivate::defaultGroups() const return m_defaultGroups; } -QList ActionManagerPrivate::commands() const +QList ActionManagerPrivate::commands() const { - return m_idCmdMap.values(); + // transform list of CommandPrivate into list of Command + QList result; + foreach(Command *cmd, m_idCmdMap.values()) + result << cmd; + return result; } QList ActionManagerPrivate::containers() const diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.h b/src/plugins/coreplugin/actionmanager/actionmanager.h index a4183211984..9746d37bc46 100644 --- a/src/plugins/coreplugin/actionmanager/actionmanager.h +++ b/src/plugins/coreplugin/actionmanager/actionmanager.h @@ -61,6 +61,8 @@ public: virtual Command *command(const QString &id) const = 0; virtual ActionContainer *actionContainer(const QString &id) const = 0; + + virtual QList commands() const = 0; }; } // namespace Core diff --git a/src/plugins/coreplugin/actionmanager/actionmanager_p.h b/src/plugins/coreplugin/actionmanager/actionmanager_p.h index 62da0d8f19b..0929130c66f 100644 --- a/src/plugins/coreplugin/actionmanager/actionmanager_p.h +++ b/src/plugins/coreplugin/actionmanager/actionmanager_p.h @@ -56,7 +56,7 @@ class ActionContainerPrivate; class MainWindow; class CommandPrivate; -class ActionManagerPrivate : public Core::ActionManager +class CORE_EXPORT ActionManagerPrivate : public Core::ActionManager { Q_OBJECT @@ -70,7 +70,7 @@ public: void saveSettings(QSettings *settings); QList defaultGroups() const; - QList commands() const; + QList commands() const; QList containers() const; bool hasContext(int context) const; diff --git a/src/plugins/fakevim/fakevim.pro b/src/plugins/fakevim/fakevim.pro index 3d7195412a6..71a94b06d78 100644 --- a/src/plugins/fakevim/fakevim.pro +++ b/src/plugins/fakevim/fakevim.pro @@ -13,18 +13,12 @@ include(../../shared/indenter/indenter.pri) # DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII QT += gui - -SOURCES += \ - fakevimactions.cpp \ +SOURCES += fakevimactions.cpp \ fakevimhandler.cpp \ fakevimplugin.cpp - -HEADERS += \ - fakevimactions.h \ +HEADERS += fakevimactions.h \ fakevimhandler.h \ fakevimplugin.h - -FORMS += \ - fakevimoptions.ui - +FORMS += fakevimoptions.ui \ + fakevimexcommands.ui OTHER_FILES += FakeVim.pluginspec diff --git a/src/plugins/fakevim/fakevimexcommands.ui b/src/plugins/fakevim/fakevimexcommands.ui new file mode 100644 index 00000000000..98e30b7c072 --- /dev/null +++ b/src/plugins/fakevim/fakevimexcommands.ui @@ -0,0 +1,156 @@ + + + FakeVimExCommandsPage + + + + 0 + 0 + 568 + 451 + + + + + + + Ex Command Mapping + + + + + + + + Filter: + + + + + + + + + + + + false + + + true + + + true + + + 3 + + + + Command + + + + + Label + + + + + Ex Trigger Expression + + + + + + + + + + Defaults + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Ex Command + + + + + + + + Regular Expression: + + + + + + + + + + Reset + + + + + + + :/core/images/reset.png:/core/images/reset.png + + + + + + + Remove + + + + + + + :/core/images/clear.png:/core/images/clear.png + + + + + + + + + Qt::RichText + + + + + + + + + + + + + diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 1f5ca6c0ce5..97e9d5db4c5 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -31,6 +31,7 @@ #include "fakevimhandler.h" #include "ui_fakevimoptions.h" +#include "ui_fakevimexcommands.h" #include @@ -62,6 +63,8 @@ #include #include +#include + #include #include @@ -73,6 +76,7 @@ #include #include +#include #include #include #include @@ -92,6 +96,7 @@ const char * const MINI_BUFFER = "TextEditor.FakeVimMiniBuffer"; const char * const INSTALL_KEY = "Alt+V,Alt+V"; const char * const SETTINGS_CATEGORY = "D.FakeVim"; const char * const SETTINGS_ID = "General"; +const char * const SETTINGS_EX_CMDS_ID = "ExCommands"; } // namespace Constants } // namespace FakeVim @@ -242,6 +247,239 @@ bool FakeVimOptionPage::matches(const QString &s) const } // namespace FakeVim +/////////////////////////////////////////////////////////////////////// +// +// FakeVimExCommandsPage +// +/////////////////////////////////////////////////////////////////////// + +struct CommandItem +{ + Command *m_cmd; + QString m_regex; + QTreeWidgetItem *m_item; +}; + +Q_DECLARE_METATYPE(CommandItem*); + +namespace FakeVim { +namespace Internal { + +static QMap s_exCommandMap; +static QMap s_defaultExCommandMap; + + +class FakeVimExCommandsPage : public Core::IOptionsPage +{ + Q_OBJECT + +public: + FakeVimExCommandsPage() {} + + // IOptionsPage + QString id() const { return QLatin1String(Constants::SETTINGS_EX_CMDS_ID); } + QString displayName() const { return tr("Ex Command Mapping"); } + QString category() const { return QLatin1String(Constants::SETTINGS_CATEGORY); } + QString displayCategory() const { return tr("FakeVim"); } + + QWidget *createPage(QWidget *parent); + void initialize(); + void apply() {} + void finish() {} + virtual bool matches(const QString &) const; + bool filter(const QString &f, const QTreeWidgetItem *item); + +public slots: + void filterChanged(const QString &f); + void commandChanged(QTreeWidgetItem *current); + void regexChanged(); + void resetRegex(); + void removeRegex(); + void defaultAction(); + +private: + Ui::FakeVimExCommandsPage m_ui; + QString m_searchKeywords; + void setRegex(const QString ®ex); + QList m_citems; +}; + +QWidget *FakeVimExCommandsPage::createPage(QWidget *parent) +{ + QWidget *w = new QWidget(parent); + m_ui.setupUi(w); + + connect(m_ui.resetButton, SIGNAL(clicked()), + this, SLOT(resetRegex())); + connect(m_ui.removeButton, SIGNAL(clicked()), + this, SLOT(removeRegex())); + connect(m_ui.defaultButton, SIGNAL(clicked()), + this, SLOT(defaultAction())); + + initialize(); + + m_ui.commandList->sortByColumn(0, Qt::AscendingOrder); + + connect(m_ui.filterEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); + connect(m_ui.commandList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), + this, SLOT(commandChanged(QTreeWidgetItem *))); + connect(m_ui.regexEdit, SIGNAL(textChanged(QString)), this, SLOT(regexChanged())); + + if (m_searchKeywords.isEmpty()) { + QTextStream(&m_searchKeywords) + << ' ' << m_ui.groupBox->title(); + m_searchKeywords.remove(QLatin1Char('&')); + } + + return w; +} + +void FakeVimExCommandsPage::initialize() +{ + Core::ActionManager *am = Core::ICore::instance()->actionManager(); + QTC_ASSERT(am, return); + UniqueIDManager *uidm = UniqueIDManager::instance(); + QTC_ASSERT(uidm, return); + + foreach (Command *c, am->commands()) { + if (c->action() && c->action()->isSeparator()) + continue; + + CommandItem *ci = new CommandItem; + QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.commandList); + ci->m_cmd = c; + ci->m_item = item; + m_citems << ci; + + const QString name = uidm->stringForUniqueIdentifier(c->id()); + item->setText(0, name); + + if (c->action()) { + QString text = c->hasAttribute(Command::CA_UpdateText) && !c->defaultText().isNull() ? c->defaultText() : c->action()->text(); + text.remove(QRegExp("&(?!&)")); + item->setText(1, text); + } else { + item->setText(1, c->shortcut()->whatsThis()); + } + if (s_exCommandMap.contains(name)) { + ci->m_regex = s_exCommandMap[name].pattern(); + } else { + ci->m_regex = ""; + } + + item->setText(2, ci->m_regex); + item->setData(0, Qt::UserRole, qVariantFromValue(ci)); + } + + commandChanged(0); +} + +void FakeVimExCommandsPage::commandChanged(QTreeWidgetItem *current) +{ + if (!current || !current->data(0, Qt::UserRole).isValid()) { + m_ui.regexEdit->setText(""); + m_ui.seqGrp->setEnabled(false); + return; + } + m_ui.seqGrp->setEnabled(true); + CommandItem *citem = qVariantValue(current->data(0, Qt::UserRole)); + m_ui.regexEdit->setText(citem->m_regex); +} + +void FakeVimExCommandsPage::filterChanged(const QString &f) +{ + for (int i=0; itopLevelItemCount(); ++i) { + QTreeWidgetItem *item = m_ui.commandList->topLevelItem(i); + item->setHidden(filter(f, item)); + } +} + +void FakeVimExCommandsPage::regexChanged() +{ + UniqueIDManager *uidm = UniqueIDManager::instance(); + QTreeWidgetItem *current = m_ui.commandList->currentItem(); + if (current && current->data(0, Qt::UserRole).isValid()) { + CommandItem *citem = qVariantValue(current->data(0, Qt::UserRole)); + citem->m_regex = m_ui.regexEdit->text(); + current->setText(2, citem->m_regex); + s_exCommandMap[uidm->stringForUniqueIdentifier(citem->m_cmd->id())] = QRegExp(citem->m_regex); + } +} + +void FakeVimExCommandsPage::setRegex(const QString ®ex) +{ + m_ui.regexEdit->setText(regex); +} + +bool FakeVimExCommandsPage::filter(const QString &f, const QTreeWidgetItem *item) +{ + if (item->childCount() == 0) { + if (f.isEmpty()) + return false; + for (int i = 0; i < item->columnCount(); ++i) { + if (item->text(i).contains(f, Qt::CaseInsensitive)) + return false; + } + return true; + } + + bool found = false; + for (int i = 0; i < item->childCount(); ++i) { + QTreeWidgetItem *citem = item->child(i); + if (filter(f, citem)) { + citem->setHidden(true); + } else { + citem->setHidden(false); + found = true; + } + } + return !found; +} + +void FakeVimExCommandsPage::resetRegex() +{ + UniqueIDManager *uidm = UniqueIDManager::instance(); + QTreeWidgetItem *current = m_ui.commandList->currentItem(); + if (current && current->data(0, Qt::UserRole).isValid()) { + CommandItem *citem = qVariantValue(current->data(0, Qt::UserRole)); + const QString &name = uidm->stringForUniqueIdentifier(citem->m_cmd->id()); + if (s_defaultExCommandMap.contains(name)) + setRegex(s_defaultExCommandMap[name].pattern()); + else + setRegex(""); + } +} + +void FakeVimExCommandsPage::removeRegex() +{ + m_ui.regexEdit->clear(); +} + +void FakeVimExCommandsPage::defaultAction() +{ + UniqueIDManager *uidm = UniqueIDManager::instance(); + foreach (CommandItem *item, m_citems) { + const QString &name = uidm->stringForUniqueIdentifier(item->m_cmd->id()); + if (s_defaultExCommandMap.contains(name)) { + item->m_regex = s_defaultExCommandMap[name].pattern(); + } else { + item->m_regex = ""; + } + item->m_item->setText(2, item->m_regex); + if (item->m_item == m_ui.commandList->currentItem()) + commandChanged(item->m_item); + } +} + +bool FakeVimExCommandsPage::matches(const QString &s) const +{ + return m_searchKeywords.contains(s, Qt::CaseInsensitive); +} + +} // namespace Internal +} // namespace FakeVim + + /////////////////////////////////////////////////////////////////////// // // FakeVimPluginPrivate @@ -295,10 +533,14 @@ signals: private: FakeVimPlugin *q; FakeVimOptionPage *m_fakeVimOptionsPage; + FakeVimExCommandsPage *m_fakeVimExCommandsPage; QHash m_editorToHandler; void triggerAction(const QString& code); void setActionChecked(const QString& code, bool check); + + void readSettings(QSettings *settings); + void writeSettings(QSettings *settings); }; } // namespace Internal @@ -308,6 +550,12 @@ FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin) { q = plugin; m_fakeVimOptionsPage = 0; + m_fakeVimExCommandsPage = 0; + + s_defaultExCommandMap[CppTools::Constants::SWITCH_HEADER_SOURCE] = QRegExp("^A$"); + s_defaultExCommandMap[ProjectExplorer::Constants::BUILD] = QRegExp("^make$"); + s_defaultExCommandMap["Coreplugin.OutputPane.previtem"] = QRegExp("^(cN(ext)?|cp(revious)?)!?( (.*))?$"); + s_defaultExCommandMap["Coreplugin.OutputPane.nextitem"] = QRegExp("^cn(ext)?!?( (.*))?$"); } FakeVimPluginPrivate::~FakeVimPluginPrivate() @@ -321,6 +569,11 @@ void FakeVimPluginPrivate::shutdown() m_fakeVimOptionsPage = 0; theFakeVimSettings()->writeSettings(Core::ICore::instance()->settings()); delete theFakeVimSettings(); + + q->removeObject(m_fakeVimExCommandsPage); + delete m_fakeVimExCommandsPage; + m_fakeVimExCommandsPage = 0; + writeSettings(Core::ICore::instance()->settings()); } bool FakeVimPluginPrivate::initialize() @@ -334,6 +587,10 @@ bool FakeVimPluginPrivate::initialize() m_fakeVimOptionsPage = new FakeVimOptionPage; q->addObject(m_fakeVimOptionsPage); theFakeVimSettings()->readSettings(Core::ICore::instance()->settings()); + + m_fakeVimExCommandsPage = new FakeVimExCommandsPage; + q->addObject(m_fakeVimExCommandsPage); + readSettings(Core::ICore::instance()->settings()); Core::Command *cmd = 0; cmd = actionManager->registerAction(theFakeVimSetting(ConfigUseFakeVim), @@ -365,6 +622,46 @@ bool FakeVimPluginPrivate::initialize() return true; } +static const char *exCommandMapGroup = "FakeVimExCommand"; +static const char *reKey = "RegEx"; +static const char *idKey = "Command"; + +void FakeVimPluginPrivate::writeSettings(QSettings *settings) +{ + settings->beginWriteArray(QLatin1String(exCommandMapGroup)); + + int count = 0; + const QMap::const_iterator end = s_exCommandMap.constEnd(); + for (QMap::const_iterator it = s_exCommandMap.constBegin(); it != end; ++it) { + const QString &id = it.key(); + const QRegExp &re = it.value(); + + if ((s_defaultExCommandMap.contains(id) && s_defaultExCommandMap[id] != re) + || (!s_defaultExCommandMap.contains(id) && !re.pattern().isEmpty())) { + settings->setArrayIndex(count); + settings->setValue(QLatin1String(idKey), id); + settings->setValue(QLatin1String(reKey), re.pattern()); + ++count; + } + } + + settings->endArray(); +} + +void FakeVimPluginPrivate::readSettings(QSettings *settings) +{ + s_exCommandMap = s_defaultExCommandMap; + + int size = settings->beginReadArray(QLatin1String(exCommandMapGroup)); + for (int i=0; isetArrayIndex(i); + const QString id = settings->value(QLatin1String(idKey)).toString(); + const QString re = settings->value(QLatin1String(reKey)).toString(); + s_exCommandMap[id] = QRegExp(re); + } + settings->endArray(); +} + void FakeVimPluginPrivate::showSettingsDialog() { Core::ICore::instance()->showOptionsDialog(QLatin1String(Constants::SETTINGS_CATEGORY), @@ -610,6 +907,17 @@ void FakeVimPluginPrivate::handleExCommand(const QString &cmd) bool forced = cmd.contains(QChar('!')); emit delayedQuitAllRequested(forced); } else { + const QMap::const_iterator end = s_exCommandMap.constEnd(); + for (QMap::const_iterator it = s_exCommandMap.constBegin(); it != end; ++it) { + const QString &id = it.key(); + const QRegExp &re = it.value(); + + if (re.indexIn(cmd) != -1) { + triggerAction(id); + return; + } + } + handler->showRedMessage(tr("Not an editor command: %1").arg(cmd)); } }