diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp index 3b5f4dffb93a033cbe1c092639b580d1b1d6fc4e..6e4f34133e2a5fe932618323d39142ef28d13289 100644 --- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp +++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp @@ -246,9 +246,13 @@ QList<int> ActionManagerPrivate::defaultGroups() const return m_defaultGroups; } -QList<CommandPrivate *> ActionManagerPrivate::commands() const +QList<Command *> ActionManagerPrivate::commands() const { - return m_idCmdMap.values(); + // transform list of CommandPrivate into list of Command + QList<Command *> result; + foreach(Command *cmd, m_idCmdMap.values()) + result << cmd; + return result; } QList<ActionContainerPrivate *> ActionManagerPrivate::containers() const diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.h b/src/plugins/coreplugin/actionmanager/actionmanager.h index a418321198444adc098edece2257e040a93665e8..9746d37bc46f43b021994742b567ed2318d60754 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<Command *> commands() const = 0; }; } // namespace Core diff --git a/src/plugins/coreplugin/actionmanager/actionmanager_p.h b/src/plugins/coreplugin/actionmanager/actionmanager_p.h index 62da0d8f19b6bf0b901f139ef0889fe01b27d513..0929130c66fedfd3e3ecbc152be93fb22a66d9e9 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<int> defaultGroups() const; - QList<CommandPrivate *> commands() const; + QList<Command *> commands() const; QList<ActionContainerPrivate *> containers() const; bool hasContext(int context) const; diff --git a/src/plugins/fakevim/fakevim.pro b/src/plugins/fakevim/fakevim.pro index 3d7195412a642892a7ab43f76e7e845b455c945d..71a94b06d78d9027879b8c7ea6830021407e264e 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 0000000000000000000000000000000000000000..98e30b7c07223d9d2200820e970999c6c4c20929 --- /dev/null +++ b/src/plugins/fakevim/fakevimexcommands.ui @@ -0,0 +1,156 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>FakeVimExCommandsPage</class> + <widget class="QWidget" name="FakeVimExCommandsPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>568</width> + <height>451</height> + </rect> + </property> + <layout class="QVBoxLayout"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Ex Command Mapping</string> + </property> + <layout class="QVBoxLayout"> + <item> + <layout class="QHBoxLayout"> + <item> + <widget class="QLabel" name="filterLabel"> + <property name="text"> + <string>Filter:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="filterEdit"/> + </item> + </layout> + </item> + <item> + <widget class="QTreeWidget" name="commandList"> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="uniformRowHeights"> + <bool>true</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="columnCount"> + <number>3</number> + </property> + <column> + <property name="text"> + <string>Command</string> + </property> + </column> + <column> + <property name="text"> + <string>Label</string> + </property> + </column> + <column> + <property name="text"> + <string>Ex Trigger Expression</string> + </property> + </column> + </widget> + </item> + <item> + <layout class="QHBoxLayout"> + <item> + <widget class="QPushButton" name="defaultButton"> + <property name="text"> + <string>Defaults</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="seqGrp"> + <property name="title"> + <string>Ex Command</string> + </property> + <layout class="QVBoxLayout"> + <item> + <layout class="QHBoxLayout"> + <item> + <widget class="QLabel" name="regexLabel"> + <property name="text"> + <string>Regular Expression:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="regexEdit"/> + </item> + <item> + <widget class="QToolButton" name="resetButton"> + <property name="toolTip"> + <string>Reset</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../coreplugin/core.qrc"> + <normaloff>:/core/images/reset.png</normaloff>:/core/images/reset.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="removeButton"> + <property name="toolTip"> + <string>Remove</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../coreplugin/core.qrc"> + <normaloff>:/core/images/clear.png</normaloff>:/core/images/clear.png</iconset> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="infoLabel"> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../coreplugin/core.qrc"/> + </resources> + <connections/> +</ui> diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 1f5ca6c0ce5a7bbc92e655e74cfb134fedb4aad5..97e9d5db4c5a5c66fca9e8c3a7745d28a03ec42c 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 <coreplugin/actionmanager/actionmanager.h> @@ -62,6 +63,8 @@ #include <utils/qtcassert.h> #include <utils/savedaction.h> +#include <cpptools/cpptoolsconstants.h> + #include <indenter.h> #include <QtCore/QDebug> @@ -73,6 +76,7 @@ #include <QtGui/QMessageBox> #include <QtGui/QPlainTextEdit> +#include <QtGui/QShortcut> #include <QtGui/QTextBlock> #include <QtGui/QTextCursor> #include <QtGui/QTextEdit> @@ -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<QString, QRegExp> s_exCommandMap; +static QMap<QString, QRegExp> 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<CommandItem *> 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<CommandItem *>(current->data(0, Qt::UserRole)); + m_ui.regexEdit->setText(citem->m_regex); +} + +void FakeVimExCommandsPage::filterChanged(const QString &f) +{ + for (int i=0; i<m_ui.commandList->topLevelItemCount(); ++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<CommandItem *>(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<CommandItem *>(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<Core::IEditor *, FakeVimHandler *> 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<QString, QRegExp>::const_iterator end = s_exCommandMap.constEnd(); + for (QMap<QString, QRegExp>::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; i<size; ++i) { + settings->setArrayIndex(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<QString, QRegExp>::const_iterator end = s_exCommandMap.constEnd(); + for (QMap<QString, QRegExp>::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)); } }