framework/source/accelerators/acceleratorcache.cxx     |   48 ++++++++++-------
 framework/source/inc/accelerators/acceleratorcache.hxx |    4 +
 2 files changed, 35 insertions(+), 17 deletions(-)

New commits:
commit 4be9be221922db6e1872e061b312f3942bca900e
Author:     Neil Roberts <bpee...@yahoo.co.uk>
AuthorDate: Sat Sep 13 19:30:07 2025 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Sun Sep 14 21:14:06 2025 +0200

    tdf#144560 Remove old key from command when setting new one
    
    The accelerator cache maintains a 1:1 mapping for key→command and a
    1:n mapping for command→keys. When a new command is set for a key it was
    previously only updating the key→command map and then adding the key to
    the command→keys map. It never removed the key from the command→keys map
    for the old command. When the menus are eventually updated, it looks up
    whether each item has a shortcut based on the item’s command. Because
    the old command was never removed, this ended up making it display the
    same key binding on multiple menu items.
    
    Change-Id: I6d75834f4c49b1f5c105ec40cb27b8e73006152d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190928
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/framework/source/accelerators/acceleratorcache.cxx 
b/framework/source/accelerators/acceleratorcache.cxx
index 8f64ed330e19..4b993d9f232a 100644
--- a/framework/source/accelerators/acceleratorcache.cxx
+++ b/framework/source/accelerators/acceleratorcache.cxx
@@ -48,8 +48,38 @@ AcceleratorCache::TKeyList AcceleratorCache::getAllKeys() 
const
     return lKeys;
 }
 
+void AcceleratorCache::removeKeyForCommand(const OUString& sCommand, const 
css::awt::KeyEvent& aKey)
+{
+    // get keylist for that command
+    TCommand2Keys::iterator pCommand = m_lCommand2Keys.find(sCommand);
+    if (pCommand == m_lCommand2Keys.end())
+        return;
+    TKeyList& lKeys = pCommand->second;
+
+    // one or more keys assign
+    if (lKeys.size() == 1)
+        // remove key from optimized command list
+        m_lCommand2Keys.erase(sCommand);
+    else // only remove this key from the keylist
+    {
+        auto pKeys = ::std::find(lKeys.begin(), lKeys.end(), aKey);
+
+        if (pKeys != lKeys.end())
+            lKeys.erase(pKeys);
+    }
+}
+
 void AcceleratorCache::setKeyCommandPair(const css::awt::KeyEvent& aKey, const 
OUString& sCommand)
 {
+    // remove any previous binding for the key
+    if (auto oldCommandPos = m_lKey2Commands.find(aKey); oldCommandPos != 
m_lKey2Commands.end())
+    {
+        // Take another ref to the command because the other string is
+        // the key in the map and it’s going to get destroyed.
+        OUString oldCommand = oldCommandPos->second;
+        removeKeyForCommand(oldCommand, aKey);
+    }
+
     // register command for the specified key
     m_lKey2Commands[aKey] = sCommand;
 
@@ -90,23 +120,7 @@ void AcceleratorCache::removeKey(const css::awt::KeyEvent& 
aKey)
     // remove key from primary list
     m_lKey2Commands.erase(aKey);
 
-    // get keylist for that command
-    TCommand2Keys::iterator pCommand = m_lCommand2Keys.find(sCommand);
-    if (pCommand == m_lCommand2Keys.end())
-        return;
-    TKeyList& lKeys = pCommand->second;
-
-    // one or more keys assign
-    if (lKeys.size() == 1)
-        // remove key from optimized command list
-        m_lCommand2Keys.erase(sCommand);
-    else // only remove this key from the keylist
-    {
-        auto pKeys = ::std::find(lKeys.begin(), lKeys.end(), aKey);
-
-        if (pKeys != lKeys.end())
-            lKeys.erase(pKeys);
-    }
+    removeKeyForCommand(sCommand, aKey);
 }
 
 void AcceleratorCache::removeCommand(const OUString& sCommand)
diff --git a/framework/source/inc/accelerators/acceleratorcache.hxx 
b/framework/source/inc/accelerators/acceleratorcache.hxx
index adfdf8fe5aa2..a8ada0d5a9a4 100644
--- a/framework/source/inc/accelerators/acceleratorcache.hxx
+++ b/framework/source/inc/accelerators/acceleratorcache.hxx
@@ -108,6 +108,10 @@ class AcceleratorCache
         OUString getCommandByKey(const css::awt::KeyEvent& aKey) const;
         void removeKey(const css::awt::KeyEvent& aKey);
         void removeCommand(const OUString& sCommand);
+
+    private:
+        void removeKeyForCommand(const OUString& sCommand,
+                                 const css::awt::KeyEvent& aKey);
 };
 
 } // namespace framework

Reply via email to