From 90ecb036a26fe334394adc0581424be0992aa4f5 Mon Sep 17 00:00:00 2001
From: con <qtc-committer@nokia.com>
Date: Mon, 6 Dec 2010 17:21:03 +0100
Subject: [PATCH] Make it possible to specify shortcuts for Locator filters.

Task-number: QTCREATORBUG-1147
---
 .../actionmanager/actionmanager.cpp           | 37 ++++++++++++++++++-
 .../coreplugin/actionmanager/actionmanager.h  |  7 +++-
 .../actionmanager/actionmanager_p.h           |  1 +
 .../coreplugin/actionmanager/command.cpp      | 19 ++++++++++
 .../coreplugin/actionmanager/command_p.h      |  2 +
 .../actionmanager/commandmappings.cpp         |  9 +++++
 .../actionmanager/commandmappings.h           |  1 +
 .../coreplugin/dialogs/shortcutsettings.cpp   | 20 +++++++++-
 .../coreplugin/dialogs/shortcutsettings.h     |  4 +-
 src/plugins/locator/locatorplugin.cpp         | 12 +++---
 src/plugins/locator/locatorwidget.cpp         | 34 ++++++++++++++++-
 src/plugins/locator/locatorwidget.h           |  1 +
 12 files changed, 136 insertions(+), 11 deletions(-)

diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
index c44c6591695..8f96443600a 100644
--- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp
+++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
@@ -35,6 +35,7 @@
 
 #include <coreplugin/coreconstants.h>
 #include <coreplugin/icore.h>
+#include <utils/qtcassert.h>
 
 #include <QtCore/QDebug>
 #include <QtCore/QSettings>
@@ -198,6 +199,17 @@ namespace {
     \sa ActionManager::createMenu()
     \sa ActionManager::createMenuBar()
 */
+
+/*!
+    \fn Command *ActionManager::unregisterAction(QAction *action, const QString &id)
+    \brief Removes the knowledge about an \a action under the specified string \a id.
+
+    Usually you do not need to unregister actions. The only valid use case for unregistering
+    actions, is for actions that represent user definable actions, like for the custom Locator
+    filters. If the user removes such an action, it also has to be unregistered from the action manager,
+    to make it disappear from shortcut settings etc.
+*/
+
 /*!
     \fn ActionManager::ActionManager(QObject *parent)
     \internal
@@ -332,6 +344,7 @@ Command *ActionManagerPrivate::registerAction(QAction *action, const Id &id, con
     a = static_cast<Action *>(c);
     if (a)
         a->addOverrideAction(action, context);
+    emit commandListChanged();
     return a;
 }
 
@@ -375,10 +388,31 @@ Command *ActionManagerPrivate::registerOverridableAction(QAction *action, const
     } else  if (checkUnique) {
         qWarning() << "registerOverridableAction: id" << id << "is already registered.";
     }
-
     return a;
 }
 
+void ActionManagerPrivate::unregisterAction(QAction *action, const Id &id)
+{
+    Action *a = 0;
+    const int uid = UniqueIDManager::instance()->uniqueIdentifier(id);
+    CommandPrivate *c = m_idCmdMap.value(uid, 0);
+    QTC_ASSERT(c, return);
+    a = qobject_cast<Action *>(c);
+    if (!a) {
+        qWarning() << "registerAction: id" << id << "is registered with a different command type.";
+        return;
+    }
+    a->removeOverrideAction(action);
+    if (a->isEmpty()) {
+        // clean up
+        m_mainWnd->removeAction(a->action());
+        delete a->action();
+        m_idCmdMap.remove(uid);
+        delete a;
+    }
+    emit commandListChanged();
+}
+
 Command *ActionManagerPrivate::registerShortcut(QShortcut *shortcut, const Id &id, const Context &context)
 {
     Shortcut *sc = 0;
@@ -410,6 +444,7 @@ Command *ActionManagerPrivate::registerShortcut(QShortcut *shortcut, const Id &i
     else
         sc->setContext(context);
 
+    emit commandListChanged();
     return sc;
 }
 
diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.h b/src/plugins/coreplugin/actionmanager/actionmanager.h
index eca4b877894..4dcc7d029b3 100644
--- a/src/plugins/coreplugin/actionmanager/actionmanager.h
+++ b/src/plugins/coreplugin/actionmanager/actionmanager.h
@@ -32,6 +32,7 @@
 
 #include "coreplugin/core_global.h"
 #include "coreplugin/uniqueidmanager.h"
+#include "coreplugin/icontext.h"
 
 #include <QtCore/QObject>
 #include <QtCore/QList>
@@ -46,7 +47,6 @@ namespace Core {
 
 class ActionContainer;
 class Command;
-class Context;
 
 class CORE_EXPORT ActionManager : public QObject
 {
@@ -65,6 +65,11 @@ public:
     virtual ActionContainer *actionContainer(const Id &id) const = 0;
 
     virtual QList<Command *> commands() const = 0;
+
+    virtual void unregisterAction(QAction *action, const Id &id) = 0;
+
+signals:
+    void commandListChanged();
 };
 
 } // namespace Core
diff --git a/src/plugins/coreplugin/actionmanager/actionmanager_p.h b/src/plugins/coreplugin/actionmanager/actionmanager_p.h
index 39cb3f65665..67a4746b9b0 100644
--- a/src/plugins/coreplugin/actionmanager/actionmanager_p.h
+++ b/src/plugins/coreplugin/actionmanager/actionmanager_p.h
@@ -91,6 +91,7 @@ public:
 
     Core::Command *command(const Id &id) const;
     Core::ActionContainer *actionContainer(const Id &id) const;
+    void unregisterAction(QAction *action, const Id &id);
 
 private:
     bool hasContext(const Context &context) const;
diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp
index ccf4ccd56ee..d82a377fd5e 100644
--- a/src/plugins/coreplugin/actionmanager/command.cpp
+++ b/src/plugins/coreplugin/actionmanager/command.cpp
@@ -495,6 +495,20 @@ void Action::addOverrideAction(QAction *action, const Core::Context &context)
     }
 }
 
+void Action::removeOverrideAction(QAction *action)
+{
+    QMutableMapIterator<int, QPointer<QAction> > it(m_contextActionMap);
+    while (it.hasNext()) {
+        it.next();
+        if (it.value() == 0) {
+            it.remove();
+        } else if (it.value() == action) {
+            it.remove();
+        }
+    }
+    setCurrentContext(m_context);
+}
+
 void Action::actionChanged()
 {
     if (hasAttribute(CA_UpdateIcon)) {
@@ -535,3 +549,8 @@ void Action::setActive(bool state)
     }
 }
 
+bool Action::isEmpty() const
+{
+    return m_contextActionMap.isEmpty();
+}
+
diff --git a/src/plugins/coreplugin/actionmanager/command_p.h b/src/plugins/coreplugin/actionmanager/command_p.h
index a7bac35da14..37e534ebff3 100644
--- a/src/plugins/coreplugin/actionmanager/command_p.h
+++ b/src/plugins/coreplugin/actionmanager/command_p.h
@@ -130,6 +130,8 @@ public:
     bool setCurrentContext(const Context &context);
     bool isActive() const;
     void addOverrideAction(QAction *action, const Context &context);
+    void removeOverrideAction(QAction *action);
+    bool isEmpty() const;
 
 protected:
     void updateToolTipWithKeySequence();
diff --git a/src/plugins/coreplugin/actionmanager/commandmappings.cpp b/src/plugins/coreplugin/actionmanager/commandmappings.cpp
index f49f621bc99..541ac4768c7 100644
--- a/src/plugins/coreplugin/actionmanager/commandmappings.cpp
+++ b/src/plugins/coreplugin/actionmanager/commandmappings.cpp
@@ -158,6 +158,8 @@ void CommandMappings::commandChanged(QTreeWidgetItem *current)
 
 void CommandMappings::filterChanged(const QString &f)
 {
+    if (!m_page)
+        return;
     for (int i=0; i<m_page->commandList->topLevelItemCount(); ++i) {
         QTreeWidgetItem *item = m_page->commandList->topLevelItem(i);
         item->setHidden(filter(f, item));
@@ -203,3 +205,10 @@ void CommandMappings::setModified(QTreeWidgetItem *item , bool modified)
     f.setBold(modified);
     item->setFont(2, f);
 }
+
+QString CommandMappings::filterText() const
+{
+    if (!m_page)
+        return QString();
+    return m_page->filterEdit->text();
+}
diff --git a/src/plugins/coreplugin/actionmanager/commandmappings.h b/src/plugins/coreplugin/actionmanager/commandmappings.h
index 66631e99a49..e809b80e7ea 100644
--- a/src/plugins/coreplugin/actionmanager/commandmappings.h
+++ b/src/plugins/coreplugin/actionmanager/commandmappings.h
@@ -80,6 +80,7 @@ protected:
     void setImportExportEnabled(bool enabled);
     QTreeWidget *commandList() const;
     QLineEdit *targetEdit() const;
+    QString filterText() const;
     void setPageTitle(const QString &s);
     void setTargetLabelText(const QString &s);
     void setTargetEditTitle(const QString &s);
diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
index 74abe1321e1..abc491adce7 100644
--- a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
+++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
@@ -56,8 +56,10 @@ using namespace Core;
 using namespace Core::Internal;
 
 ShortcutSettings::ShortcutSettings(QObject *parent)
-    : CommandMappings(parent)
+    : CommandMappings(parent), m_initialized(false)
 {
+    Core::Internal::ActionManagerPrivate *am = ActionManagerPrivate::instance();
+    connect(am, SIGNAL(commandListChanged()), this, SLOT(initialize()));
 }
 
 ShortcutSettings::~ShortcutSettings()
@@ -94,6 +96,7 @@ QIcon ShortcutSettings::categoryIcon() const
 
 QWidget *ShortcutSettings::createPage(QWidget *parent)
 {
+    m_initialized = true;
     m_keyNum = m_key[0] = m_key[1] = m_key[2] = m_key[3] = 0;
 
     QWidget *w = CommandMappings::createPage(parent);
@@ -128,6 +131,7 @@ void ShortcutSettings::finish()
     m_scitems.clear();
 
     CommandMappings::finish();
+    m_initialized = false;
 }
 
 bool ShortcutSettings::matches(const QString &s) const
@@ -271,8 +275,21 @@ void ShortcutSettings::exportAction()
     }
 }
 
+void ShortcutSettings::clear()
+{
+    QTreeWidget *tree = commandList();
+    for (int i = tree->topLevelItemCount()-1; i >= 0 ; --i) {
+        delete tree->takeTopLevelItem(i);
+    }
+    qDeleteAll(m_scitems);
+    m_scitems.clear();
+}
+
 void ShortcutSettings::initialize()
 {
+    if (!m_initialized)
+        return;
+    clear();
     Core::Internal::ActionManagerPrivate *am = ActionManagerPrivate::instance();
     UniqueIDManager *uidm = UniqueIDManager::instance();
 
@@ -325,6 +342,7 @@ void ShortcutSettings::initialize()
 
         markPossibleCollisions(s);
     }
+    filterChanged(filterText());
 }
 
 void ShortcutSettings::handleKeyEvent(QKeyEvent *e)
diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.h b/src/plugins/coreplugin/dialogs/shortcutsettings.h
index 161ed2d4a8f..19f0b14fbb6 100644
--- a/src/plugins/coreplugin/dialogs/shortcutsettings.h
+++ b/src/plugins/coreplugin/dialogs/shortcutsettings.h
@@ -86,10 +86,11 @@ private slots:
     void importAction();
     void exportAction();
     void defaultAction();
+    void initialize();
 
 private:
     void setKeySequence(const QKeySequence &key);
-    void initialize();
+    void clear();
 
     void handleKeyEvent(QKeyEvent *e);
     int translateModifiers(Qt::KeyboardModifiers state, const QString &text);
@@ -101,6 +102,7 @@ private:
     int m_key[4], m_keyNum;
 
     QString m_searchKeywords;
+    bool m_initialized;
 };
 
 } // namespace Internal
diff --git a/src/plugins/locator/locatorplugin.cpp b/src/plugins/locator/locatorplugin.cpp
index d88f44b6ef5..6b18c994180 100644
--- a/src/plugins/locator/locatorplugin.cpp
+++ b/src/plugins/locator/locatorplugin.cpp
@@ -36,11 +36,6 @@
 #include "filesystemfilter.h"
 #include "settingspage.h"
 
-#include <QtCore/QSettings>
-#include <QtCore/QtPlugin>
-#include <QtCore/QFuture>
-#include <QtCore/QFutureWatcher>
-
 #include <coreplugin/statusbarwidget.h>
 #include <coreplugin/coreconstants.h>
 #include <coreplugin/settingsdatabase.h>
@@ -54,6 +49,12 @@
 #include <extensionsystem/pluginmanager.h>
 #include <qtconcurrent/QtConcurrentTools>
 
+#include <QtCore/QSettings>
+#include <QtCore/QtPlugin>
+#include <QtCore/QFuture>
+#include <QtCore/QFutureWatcher>
+#include <QtGui/QAction>
+
 /*!
     \namespace Locator
     The Locator namespace provides the hooks for Locator content.
@@ -142,6 +143,7 @@ void LocatorPlugin::extensionsInitialized()
 {
     m_filters = ExtensionSystem::PluginManager::instance()->getObjects<ILocatorFilter>();
     qSort(m_filters.begin(), m_filters.end(), filterLessThan);
+    setFilters(m_filters);
 }
 
 void LocatorPlugin::startSettingsLoad()
diff --git a/src/plugins/locator/locatorwidget.cpp b/src/plugins/locator/locatorwidget.cpp
index 044213d091c..5d650d65464 100644
--- a/src/plugins/locator/locatorwidget.cpp
+++ b/src/plugins/locator/locatorwidget.cpp
@@ -37,6 +37,8 @@
 #include <extensionsystem/pluginmanager.h>
 #include <coreplugin/icore.h>
 #include <coreplugin/modemanager.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/command.h>
 #include <coreplugin/coreconstants.h>
 #include <coreplugin/fileiconprovider.h>
 #include <utils/filterlineedit.h>
@@ -321,12 +323,40 @@ LocatorWidget::LocatorWidget(LocatorPlugin *qop) :
 void LocatorWidget::updateFilterList()
 {
     m_filterMenu->clear();
+
+    // update actions and menu
+    Core::ActionManager *am = Core::ICore::instance()->actionManager();
+    QMap<QString, QAction *> actionCopy = m_filterActionMap;
+    m_filterActionMap.clear();
+    // register new actions, update existent
     foreach (ILocatorFilter *filter, m_locatorPlugin->filters()) {
-        if (!filter->shortcutString().isEmpty() && !filter->isHidden()) {
-            QAction *action = m_filterMenu->addAction(filter->displayName(), this, SLOT(filterSelected()));
+        if (filter->shortcutString().isEmpty() || filter->isHidden())
+            continue;
+        QAction *action = 0;
+        Core::Command *cmd = 0;
+        if (!actionCopy.contains(filter->id())) {
+            // register new action
+            action = new QAction(filter->displayName(), this);
+            cmd = am->registerAction(action, QLatin1String("Locator.") + filter->id(),
+                               Core::Context(Core::Constants::C_GLOBAL));
+            cmd->setAttribute(Core::Command::CA_UpdateText);
+            connect(action, SIGNAL(triggered()), this, SLOT(filterSelected()));
             action->setData(qVariantFromValue(filter));
+        } else {
+            action = actionCopy.take(filter->id());
+            action->setText(filter->displayName());
+            cmd = am->command(QLatin1String("Locator.") + filter->id());
         }
+        m_filterActionMap.insert(filter->id(), action);
+        m_filterMenu->addAction(cmd->action());
+    }
+
+    // unregister actions that are deleted now
+    foreach (const QString &id, actionCopy.keys()) {
+        am->unregisterAction(actionCopy.value(id), QLatin1String("Locator.") + id);
     }
+    qDeleteAll(actionCopy);
+
     m_filterMenu->addSeparator();
     m_filterMenu->addAction(m_refreshAction);
     m_filterMenu->addAction(m_configureAction);
diff --git a/src/plugins/locator/locatorwidget.h b/src/plugins/locator/locatorwidget.h
index a3a0cd33b63..a3452067246 100644
--- a/src/plugins/locator/locatorwidget.h
+++ b/src/plugins/locator/locatorwidget.h
@@ -91,6 +91,7 @@ private:
     Utils::FilterLineEdit *m_fileLineEdit;
     QTimer *m_showPopupTimer;
     QFutureWatcher<FilterEntry> *m_entriesWatcher;
+    QMap<QString, QAction *> m_filterActionMap;
 };
 
 } // namespace Internal
-- 
GitLab