From 3d1a97e6dfa9bb82b3fbef4573e779de95d137f2 Mon Sep 17 00:00:00 2001
From: con <qtc-committer@nokia.com>
Date: Thu, 22 Apr 2010 17:36:09 +0200
Subject: [PATCH] Fix updating the state of menus.

The menus were only updated during context changes
(not if action states where updated directly),
and didn't take into account that the active action for a context
might still be disabled.
Also, enabled separators should not automatically lead to enabled menus.
---
 .../actionmanager/actioncontainer.cpp         | 24 +++++++++++++++----
 .../actionmanager/actioncontainer.h           |  1 -
 .../actionmanager/actioncontainer_p.h         | 16 +++++++++++--
 .../actionmanager/actionmanager.cpp           |  4 ----
 .../coreplugin/actionmanager/command.cpp      | 22 +++++++++++++----
 .../coreplugin/actionmanager/command.h        |  1 +
 .../coreplugin/actionmanager/command_p.h      |  2 ++
 7 files changed, 55 insertions(+), 15 deletions(-)

diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer.cpp b/src/plugins/coreplugin/actionmanager/actioncontainer.cpp
index fb50edfd95b..aa8ff2c7ed7 100644
--- a/src/plugins/coreplugin/actionmanager/actioncontainer.cpp
+++ b/src/plugins/coreplugin/actionmanager/actioncontainer.cpp
@@ -36,6 +36,7 @@
 #include "uniqueidmanager.h"
 
 #include <QtCore/QDebug>
+#include <QtCore/QTimer>
 #include <QtGui/QAction>
 #include <QtGui/QMenuBar>
 
@@ -152,7 +153,7 @@ using namespace Core::Internal;
 */
 
 ActionContainerPrivate::ActionContainerPrivate(int id)
-    : m_data(0), m_id(id)
+    : m_data(0), m_id(id), m_updateRequested(false)
 {
 
 }
@@ -253,6 +254,7 @@ void ActionContainerPrivate::addAction(Command *action, int pos, bool setpos)
 
     m_commands.append(action);
     m_posmap.insert(pos, action->id());
+    connect(action, SIGNAL(activeStateChanged()), this, SLOT(scheduleUpdate()));
     insertAction(ba, a->action());
 }
 
@@ -320,6 +322,20 @@ int ActionContainerPrivate::calcPosition(int pos, int prevKey) const
     return grp + (prevKey & 0xFFFF) + 10;
 }
 
+void ActionContainerPrivate::scheduleUpdate()
+{
+    if (m_updateRequested)
+        return;
+    m_updateRequested = true;
+    QTimer::singleShot(0, this, SLOT(update()));
+}
+
+void ActionContainerPrivate::update()
+{
+    updateInternal();
+    m_updateRequested = false;
+}
+
 // ---------- MenuActionContainer ------------
 
 /*!
@@ -368,7 +384,7 @@ CommandLocation MenuActionContainer::location() const
     return m_location;
 }
 
-bool MenuActionContainer::update()
+bool MenuActionContainer::updateInternal()
 {
     if (hasEmptyAction(EA_None))
         return true;
@@ -380,7 +396,7 @@ bool MenuActionContainer::update()
             qWarning() << Q_FUNC_INFO << "container" << (this->menu() ? this->menu()->title() : "") <<  "contains itself as subcontainer";
             continue;
         }
-        if (container->update()) {
+        if (qobject_cast<ActionContainerPrivate*>(container)->updateInternal()) {
             hasitems = true;
             break;
         }
@@ -441,7 +457,7 @@ void MenuBarActionContainer::insertMenu(QAction *before, QMenu *menu)
     m_menuBar->insertMenu(before, menu);
 }
 
-bool MenuBarActionContainer::update()
+bool MenuBarActionContainer::updateInternal()
 {
     if (hasEmptyAction(EA_None))
         return true;
diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer.h b/src/plugins/coreplugin/actionmanager/actioncontainer.h
index 2fa268ba3f6..042921df65b 100644
--- a/src/plugins/coreplugin/actionmanager/actioncontainer.h
+++ b/src/plugins/coreplugin/actionmanager/actioncontainer.h
@@ -66,7 +66,6 @@ public:
     virtual void addAction(Core::Command *action, const QString &group = QString()) = 0;
     virtual void addMenu(Core::ActionContainer *menu, const QString &group = QString()) = 0;
 
-    virtual bool update() = 0;
     virtual ~ActionContainer() {}
 };
 
diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer_p.h b/src/plugins/coreplugin/actionmanager/actioncontainer_p.h
index ba9f7ed6c0c..226fcc35acf 100644
--- a/src/plugins/coreplugin/actionmanager/actioncontainer_p.h
+++ b/src/plugins/coreplugin/actionmanager/actioncontainer_p.h
@@ -40,6 +40,8 @@ namespace Internal {
 
 class ActionContainerPrivate : public Core::ActionContainer
 {
+    Q_OBJECT
+
 public:
     ActionContainerPrivate(int id);
     virtual ~ActionContainerPrivate() {}
@@ -62,6 +64,9 @@ public:
 
     QList<Command *> commands() const { return m_commands; }
     QList<ActionContainer *> subContainers() const { return m_subContainers; }
+
+    virtual bool updateInternal() = 0;
+
 protected:
     bool canAddAction(Command *action) const;
     bool canAddMenu(ActionContainer *menu) const;
@@ -70,6 +75,10 @@ protected:
     void addAction(Command *action, int pos, bool setpos);
     void addMenu(ActionContainer *menu, int pos, bool setpos);
 
+private slots:
+    void scheduleUpdate();
+    void update();
+
 private:
     QAction *beforeAction(int pos, int *prevKey) const;
     int calcPosition(int pos, int prevKey) const;
@@ -80,6 +89,7 @@ private:
     QMap<int, int> m_posmap;
     QList<ActionContainer *> m_subContainers;
     QList<Command *> m_commands;
+    bool m_updateRequested;
 };
 
 class MenuActionContainer : public ActionContainerPrivate
@@ -95,10 +105,11 @@ public:
 
     void insertAction(QAction *before, QAction *action);
     void insertMenu(QAction *before, QMenu *menu);
-    bool update();
 
 protected:
     bool canBeAddedToMenu() const;
+    bool updateInternal();
+
 private:
     QMenu *m_menu;
     CommandLocation m_location;
@@ -114,10 +125,11 @@ public:
 
     void insertAction(QAction *before, QAction *action);
     void insertMenu(QAction *before, QMenu *menu);
-    bool update();
 
 protected:
     bool canBeAddedToMenu() const;
+    bool updateInternal();
+
 private:
     QMenuBar *m_menuBar;
 };
diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
index 91289fb1c9a..ff219e117f9 100644
--- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp
+++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
@@ -274,10 +274,6 @@ void ActionManagerPrivate::setContext(const QList<int> &context)
     const IdCmdMap::const_iterator cmdcend = m_idCmdMap.constEnd();
     for (IdCmdMap::const_iterator it = m_idCmdMap.constBegin(); it != cmdcend; ++it)
         it.value()->setCurrentContext(m_context);
-
-    const IdContainerMap::const_iterator acend = m_idContainerMap.constEnd();
-    for (IdContainerMap::const_iterator it = m_idContainerMap.constBegin(); it != acend; ++it)
-        it.value()->update();
 }
 
 bool ActionManagerPrivate::hasContext(QList<int> context) const
diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp
index 5cb8ad0f398..015f4f344c9 100644
--- a/src/plugins/coreplugin/actionmanager/command.cpp
+++ b/src/plugins/coreplugin/actionmanager/command.cpp
@@ -337,11 +337,17 @@ bool Shortcut::setCurrentContext(const QList<int> &context)
 {
     foreach (int ctxt, m_context) {
         if (context.contains(ctxt)) {
-            m_shortcut->setEnabled(true);
+            if (!m_shortcut->isEnabled()) {
+                m_shortcut->setEnabled(true);
+                emit activeStateChanged();
+            }
             return true;
         }
     }
-    m_shortcut->setEnabled(false);
+    if (m_shortcut->isEnabled()) {
+        m_shortcut->setEnabled(false);
+        emit activeStateChanged();
+    }
     return false;
 }
 
@@ -454,14 +460,13 @@ bool Action::setCurrentContext(const QList<int> &context)
         // we need to update the checked state, so we connect to setChecked slot, which also fires a toggled signal
         connect(m_action, SIGNAL(toggled(bool)), m_currentAction, SLOT(setChecked(bool)));
         actionChanged();
-        m_active = true;
         return true;
     }
     // no active/delegate action, "visible" action is not enabled/visible
     if (hasAttribute(CA_Hide))
         m_action->setVisible(false);
     m_action->setEnabled(false);
-    m_active = false;
+    setActive(false);
     return false;
 }
 
@@ -517,9 +522,18 @@ void Action::actionChanged()
 
     m_action->setEnabled(m_currentAction->isEnabled());
     m_action->setVisible(m_currentAction->isVisible());
+    setActive(m_action->isEnabled() && m_action->isVisible() && !m_action->isSeparator());
 }
 
 bool Action::isActive() const
 {
     return m_active;
 }
+
+void Action::setActive(bool state)
+{
+    if (state != m_active) {
+        m_active = state;
+        emit activeStateChanged();
+    }
+}
diff --git a/src/plugins/coreplugin/actionmanager/command.h b/src/plugins/coreplugin/actionmanager/command.h
index 88651f6cd66..2d842b13f83 100644
--- a/src/plugins/coreplugin/actionmanager/command.h
+++ b/src/plugins/coreplugin/actionmanager/command.h
@@ -81,6 +81,7 @@ public:
 
 signals:
     void keySequenceChanged();
+    void activeStateChanged();
 };
 
 } // namespace Core
diff --git a/src/plugins/coreplugin/actionmanager/command_p.h b/src/plugins/coreplugin/actionmanager/command_p.h
index aaf6da028b3..6c99cab2e94 100644
--- a/src/plugins/coreplugin/actionmanager/command_p.h
+++ b/src/plugins/coreplugin/actionmanager/command_p.h
@@ -137,6 +137,8 @@ private slots:
     void actionChanged();
 
 private:
+    void setActive(bool state);
+
     QAction *m_action;
     QList<CommandLocation> m_locations;
     QString m_toolTip;
-- 
GitLab