cui/qa/uitest/dialogs/accelerators.py |   44 +++++
 cui/source/customize/acccfg.cxx       |  253 +++++++++++++++++++++-------------
 cui/source/inc/acccfg.hxx             |   38 ++---
 3 files changed, 219 insertions(+), 116 deletions(-)

New commits:
commit a1c00d4e3db74c6661266cf57eedae873dcd5238
Author:     Neil Roberts <[email protected]>
AuthorDate: Sat Feb 28 18:40:19 2026 +0100
Commit:     Neil Roberts <[email protected]>
CommitDate: Sun Mar 8 08:43:49 2026 +0100

    tdf#171077: Allow customizing shortcuts for multiple scopes
    
    Previously whenever the scope is changed in the accelerator
    configuration dialog it would silently forget any pending assignments.
    This patch makes it instead store an array of assignments for each
    possible scope and then apply them all when FillItemSet is called. The
    arrays are lazily created as each scope is accessed.
    
    Change-Id: I0cbff7945f7c11c0498c63314e288f45495529ef
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200697
    Reviewed-by: Neil Roberts <[email protected]>
    Tested-by: Jenkins

diff --git a/cui/qa/uitest/dialogs/accelerators.py 
b/cui/qa/uitest/dialogs/accelerators.py
index 34722ffc02a5..60391edc3f9a 100644
--- a/cui/qa/uitest/dialogs/accelerators.py
+++ b/cui/qa/uitest/dialogs/accelerators.py
@@ -181,4 +181,48 @@ class Test(UITestCase):
                 xAcceleratorPage.getChild("office").executeAction("CLICK", 
tuple())
                 self.assertEqual(get_state_as_dict(xScope)["Enabled"], "false")
 
+    def test_multiple_scopes(self):
+        # tdf#171077 Test setting accelerators in multiple scopes at the same 
time without closing
+        # the dialog in between changing the scope
+        with self.ui_test.create_doc_in_start_center("writer") as xDoc1, \
+             self.ui_test.load_empty_file("writer") as xDoc2:
+            with 
self.ui_test.execute_dialog_through_command(".uno:ConfigureDialog") as xDialog:
+                # Set a shortcut on the global scope
+                self.assign_key(xDialog, "office", "F7", ".uno:EditBookmark")
+                # Set a shortcut on the module scope
+                self.assign_key(xDialog, "module", "F7", ".uno:Credits")
+                # Set a shortcut in the first document
+                self.assign_key(xDialog, "Untitled 1", "F7", "Spelling")
+                # Set a shortcut in the second document
+                self.assign_key(xDialog, "Untitled 2", "F7", 
".uno:OptionsSecurityDialog")
+
+                # Switch back to the first document and make sure the binding 
is still in the list
+                xAcceleratorPage = xDialog.getChild("AccelConfigPage")
+                xScope = xAcceleratorPage.getChild("savein")
+                select_by_text(xScope, "Untitled 1")
+                xShortcuts = xAcceleratorPage.getChild("shortcuts")
+                select_key(xShortcuts, "F7")
+                
self.assertEqual(get_state_as_dict(xShortcuts)["SelectEntryText"].split("      
")[1],
+                                 "Spelling")
+
+            # Check that all the accelerators made it into the configs
+            xGlobalAccelCfg = self.xContext.ServiceManager.createInstance(
+                'com.sun.star.ui.GlobalAcceleratorConfiguration')
+            xKeyEvent = KeyEvent()
+            xKeyEvent.KeyCode = Key.F7
+            self.assertEqual(xGlobalAccelCfg.getCommandByKeyEvent(xKeyEvent), 
".uno:EditBookmark")
+
+            xModuleAccelCfg = 
self.xContext.ServiceManager.createInstanceWithArguments(
+                'com.sun.star.ui.ModuleAcceleratorConfiguration',
+                ('com.sun.star.text.TextDocument',))
+            self.assertEqual(xModuleAccelCfg.getCommandByKeyEvent(xKeyEvent), 
".uno:Credits")
+
+            xDocAccelCfg = 
xDoc1.getUIConfigurationManager().getShortCutManager()
+            self.assertEqual(xDocAccelCfg.getCommandByKeyEvent(xKeyEvent),
+                             ".uno:SpellingAndGrammarDialog")
+
+            xDocAccelCfg = 
xDoc2.getUIConfigurationManager().getShortCutManager()
+            self.assertEqual(xDocAccelCfg.getCommandByKeyEvent(xKeyEvent),
+                             ".uno:OptionsSecurityDialog")
+
 # vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/cui/source/customize/acccfg.cxx b/cui/source/customize/acccfg.cxx
index 68bb32250be8..32b3f751188b 100644
--- a/cui/source/customize/acccfg.cxx
+++ b/cui/source/customize/acccfg.cxx
@@ -843,6 +843,21 @@ struct AcceleratorSaveInData
 };
 }
 
+// Pairs a reference to an accelerator configuration with a list of assignments
+struct AssignmentData
+{
+    AssignmentData(const uno::Reference<ui::XAcceleratorConfiguration>& 
xAccMgr)
+        : m_xAccMgr(xAccMgr)
+        // Create an array with an empty string for each key
+        , m_aAssignments(std::size(KEYCODE_ARRAY))
+    {
+    }
+
+    uno::Reference<ui::XAcceleratorConfiguration> m_xAccMgr;
+    // A list of assignments using the same indices as KEYCODE_ARRAY
+    std::vector<OUString> m_aAssignments;
+};
+
 // Helper class to listen for components being disposed so we can
 // remove them from the SaveIn combobox
 class ComponentDisposedListener : public 
::cppu::WeakImplHelper<lang::XEventListener>
@@ -893,6 +908,12 @@ void ComponentDisposedListener::disposing(const 
lang::EventObject& rEvent)
                 m_pAccelCfgPage->m_xDocumentButton->hide();
             }
 
+            // Abandon any assignment data for this document
+            std::erase_if(m_pAccelCfgPage->m_aAssignmentData,
+                          [pData](const AssignmentData& rAssignmentData) {
+                              return rAssignmentData.m_xAccMgr == 
pData->m_xAccMgr;
+                          });
+
             pData->m_xModel->removeEventListener(this);
 
             delete pData;
@@ -1108,15 +1129,35 @@ void SfxAcceleratorConfigPage::InitAccCfg()
     }
 }
 
-void SfxAcceleratorConfigPage::Init(const 
uno::Reference<ui::XAcceleratorConfiguration>& xAccMgr)
+void SfxAcceleratorConfigPage::LoadAcceleratorConfig(
+    const css::uno::Reference<css::ui::XAcceleratorConfiguration>& xAccMgr)
 {
-    if (!xAccMgr.is())
-        return;
+    std::vector<OUString>& rAssignments = GetAssignments();
+
+    // Reset all of the assignments
+    for (auto& rAssignment : rAssignments)
+        rAssignment.clear();
+
+    // Assign all commands to its shortcuts - reading the accelerator config.
+    uno::Sequence<awt::KeyEvent> lKeys = xAccMgr->getAllKeyEvents();
+
+    for (sal_Int32 i = 0, nKeys = lKeys.getLength(); i < nKeys; ++i)
+    {
+        const awt::KeyEvent& aAWTKey = lKeys[i];
+        vcl::KeyCode aKeyCode = 
svt::AcceleratorExecute::st_AWTKey2VCLKey(aAWTKey);
 
-    // Initially set all of the assignments to an empty string
-    m_aAssignments.clear();
-    m_aAssignments.resize(KEYCODE_ARRAY_SIZE);
+        const sal_uInt16* pKeycodePos = std::find(KEYCODE_ARRAY, KEYCODE_ARRAY 
+ KEYCODE_ARRAY_SIZE,
+                                                  aKeyCode.GetCode() | 
aKeyCode.GetModifier());
 
+        if (pKeycodePos >= KEYCODE_ARRAY + KEYCODE_ARRAY_SIZE)
+            continue;
+
+        rAssignments[pKeycodePos - KEYCODE_ARRAY] = 
xAccMgr->getCommandByKeyEvent(aAWTKey);
+    }
+}
+
+void SfxAcceleratorConfigPage::Init()
+{
     if (!m_bStylesInfoInitialized)
     {
         uno::Reference<frame::XController> xController;
@@ -1131,6 +1172,8 @@ void SfxAcceleratorConfigPage::Init(const 
uno::Reference<ui::XAcceleratorConfigu
         m_bStylesInfoInitialized = true;
     }
 
+    const std::vector<OUString>& rAssignments = GetAssignments();
+
     // Insert all editable accelerators into list box. It is possible
     // that some accelerators are not mapped on the current system/keyboard
     // but we don't want to lose these mappings.
@@ -1142,39 +1185,14 @@ void SfxAcceleratorConfigPage::Init(const 
uno::Reference<ui::XAcceleratorConfigu
             continue;
         m_xEntriesBox->append(OUString::number(i1), sKey);
         int nPos = m_xEntriesBox->n_children() - 1;
-        m_xEntriesBox->set_text(nPos, OUString(), 1);
-        m_xEntriesBox->set_sensitive(nPos, !IsReservedKeyCode(aKey));
-    }
-
-    // Assign all commands to its shortcuts - reading the accelerator config.
-    uno::Sequence<awt::KeyEvent> lKeys = xAccMgr->getAllKeyEvents();
-    sal_Int32 c2 = lKeys.getLength();
-    sal_Int32 i2 = 0;
-
-    for (i2 = 0; i2 < c2; ++i2)
-    {
-        const awt::KeyEvent& aAWTKey = lKeys[i2];
-        vcl::KeyCode aKeyCode = 
svt::AcceleratorExecute::st_AWTKey2VCLKey(aAWTKey);
-        OUString sCommand = xAccMgr->getCommandByKeyEvent(aAWTKey);
-
-        const sal_uInt16* pKeyCode
-            = std::find(KEYCODE_ARRAY, KEYCODE_ARRAY + KEYCODE_ARRAY_SIZE, 
aKeyCode.GetFullCode());
-
-        if (pKeyCode < KEYCODE_ARRAY + KEYCODE_ARRAY_SIZE)
-            m_aAssignments[pKeyCode - KEYCODE_ARRAY] = sCommand;
-
-        sal_Int32 nPos = MapKeyCodeToPos(aKeyCode);
-
-        if (nPos == -1)
-            continue;
-
-        OUString sLabel = GetLabel4Command(sCommand);
-
+        OUString sLabel = GetLabel4Command(rAssignments[i1]);
         m_xEntriesBox->set_text(nPos, sLabel, 1);
+        m_xEntriesBox->set_sensitive(nPos, !IsReservedKeyCode(aKey));
     }
 }
 
-void SfxAcceleratorConfigPage::Apply(const 
uno::Reference<ui::XAcceleratorConfiguration>& xAccMgr)
+void SfxAcceleratorConfigPage::Apply(const 
uno::Reference<ui::XAcceleratorConfiguration>& xAccMgr,
+                                     const std::vector<OUString>& rAssignments)
 {
     if (!xAccMgr.is())
         return;
@@ -1182,11 +1200,11 @@ void SfxAcceleratorConfigPage::Apply(const 
uno::Reference<ui::XAcceleratorConfig
     // Go through the list from the bottom to the top ...
     // because logical accelerator must be preferred instead of
     // physical ones!
-    for (int i = 0, nCount = m_aAssignments.size(); i < nCount; ++i)
+    for (int i = 0, nCount = rAssignments.size(); i < nCount; ++i)
     {
         vcl::KeyCode aKey = KEYCODE_ARRAY[i];
         awt::KeyEvent aAWTKey = 
svt::AcceleratorExecute::st_VCLKey2AWTKey(aKey);
-        OUString sCommand = m_aAssignments[i];
+        OUString sCommand = rAssignments[i];
 
         try
         {
@@ -1207,6 +1225,26 @@ void SfxAcceleratorConfigPage::Apply(const 
uno::Reference<ui::XAcceleratorConfig
 
 void SfxAcceleratorConfigPage::ResetConfig() { m_xEntriesBox->clear(); }
 
+std::vector<OUString>* SfxAcceleratorConfigPage::FindAssignments()
+{
+    for (auto& rAssignmentData : m_aAssignmentData)
+    {
+        if (rAssignmentData.m_xAccMgr == m_xAct)
+            return &rAssignmentData.m_aAssignments;
+    }
+
+    return nullptr;
+}
+
+std::vector<OUString>& SfxAcceleratorConfigPage::GetAssignments()
+{
+    if (std::vector<OUString>* pAssignments = FindAssignments())
+        return *pAssignments;
+
+    // Lazily create the data
+    return m_aAssignmentData.emplace_back(m_xAct).m_aAssignments;
+}
+
 IMPL_LINK_NOARG(SfxAcceleratorConfigPage, ImplUpdateDataHdl, Timer*, void)
 {
     SelectHdl(m_xGroupLBox->get_widget());
@@ -1249,7 +1287,8 @@ IMPL_LINK_NOARG(SfxAcceleratorConfigPage, Default, 
weld::Button&, void)
 
     m_xEntriesBox->freeze();
     ResetConfig();
-    Init(m_xAct);
+    LoadAcceleratorConfig(m_xAct);
+    Init();
     m_xEntriesBox->thaw();
     m_xEntriesBox->select(0);
     SelectHdl(*m_xEntriesBox);
@@ -1267,7 +1306,7 @@ IMPL_LINK_NOARG(SfxAcceleratorConfigPage, ChangeHdl, 
weld::Button&, void)
     if (sLabel.isEmpty())
         sLabel = GetLabel4Command(sNewCommand);
 
-    m_aAssignments[nKeyPos] = sNewCommand;
+    GetAssignments()[nKeyPos] = sNewCommand;
     m_xEntriesBox->set_text(nPos, sLabel, 1);
 
     SelectHdl(m_xFunctionBox->get_widget());
@@ -1284,13 +1323,15 @@ IMPL_LINK_NOARG(SfxAcceleratorConfigPage, RemoveHdl, 
weld::Button&, void)
 
     // remove function name from selected entry
     m_xEntriesBox->set_text(nPos, OUString(), 1);
-    m_aAssignments[nKeyPos].clear();
+    GetAssignments()[nKeyPos].clear();
 
     SelectHdl(m_xFunctionBox->get_widget());
 }
 
 IMPL_LINK(SfxAcceleratorConfigPage, SelectHdl, weld::TreeView&, rListBox, void)
 {
+    const std::vector<OUString>& rAssignments = GetAssignments();
+
     if (&rListBox == m_xEntriesBox.get())
     {
         OUString nSelectedId = m_xEntriesBox->get_selected_id();
@@ -1306,7 +1347,7 @@ IMPL_LINK(SfxAcceleratorConfigPage, SelectHdl, 
weld::TreeView&, rListBox, void)
 
             if (!IsReservedKeyCode(KEYCODE_ARRAY[nKeyPos]))
             {
-                OUString sCommand = m_aAssignments[nKeyPos];
+                OUString sCommand = rAssignments[nKeyPos];
                 if (!sCommand.isEmpty())
                     m_xRemoveButton->set_sensitive(true);
                 m_xChangeButton->set_sensitive(sCommand != 
sPossibleNewCommand);
@@ -1349,7 +1390,7 @@ IMPL_LINK(SfxAcceleratorConfigPage, SelectHdl, 
weld::TreeView&, rListBox, void)
 
             if (!IsReservedKeyCode(KEYCODE_ARRAY[nKeyPos]))
             {
-                OUString sCommand = m_aAssignments[nKeyPos];
+                OUString sCommand = rAssignments[nKeyPos];
                 if (!sCommand.isEmpty())
                     m_xRemoveButton->set_sensitive(true);
                 m_xChangeButton->set_sensitive(sCommand != sPossibleNewCommand
@@ -1363,7 +1404,7 @@ IMPL_LINK(SfxAcceleratorConfigPage, SelectHdl, 
weld::TreeView&, rListBox, void)
                 for (int i = 0, nCount = m_xEntriesBox->n_children(); i < 
nCount; ++i)
                 {
                     sal_uInt32 nEntryKeyPos = 
m_xEntriesBox->get_id(i).toUInt32();
-                    if (m_aAssignments[nEntryKeyPos] == sPossibleNewCommand)
+                    if (rAssignments[nEntryKeyPos] == sPossibleNewCommand)
                     {
                         vcl::KeyCode aKey(KEYCODE_ARRAY[nEntryKeyPos]);
                         m_xKeyBox->append(OUString::number(nEntryKeyPos), 
aKey.GetName());
@@ -1427,7 +1468,11 @@ void SfxAcceleratorConfigPage::HandleScopeChanged()
 
     m_xEntriesBox->freeze();
     ResetConfig();
-    Init(m_xAct);
+    // If we don’t have any saved assignments for this scope then load from 
the accelerator
+    // configuration
+    if (FindAssignments() == nullptr && m_xAct.is())
+        LoadAcceleratorConfig(m_xAct);
+    Init();
     m_xEntriesBox->thaw();
 
     m_xGroupLBox->Init(m_xContext, m_xFrame, m_sModuleLongName, true);
@@ -1487,7 +1532,8 @@ IMPL_LINK_NOARG(SfxAcceleratorConfigPage, LoadHdl, 
sfx2::FileDialogHelper*, void
 
             m_xEntriesBox->freeze();
             ResetConfig();
-            Init(xTempAccMgr);
+            LoadAcceleratorConfig(xTempAccMgr);
+            Init();
             m_xEntriesBox->thaw();
             if (m_xEntriesBox->n_children())
             {
@@ -1615,10 +1661,26 @@ void 
SfxAcceleratorConfigPage::StartFileDialog(StartFileDialogType nType, const
 
 bool SfxAcceleratorConfigPage::FillItemSet(SfxItemSet*)
 {
-    Apply(m_xAct);
+    for (const AssignmentData& rAssignmentData : m_aAssignmentData)
+    {
+        Apply(rAssignmentData.m_xAccMgr, rAssignmentData.m_aAssignments);
+
+        try
+        {
+            rAssignmentData.m_xAccMgr->store();
+        }
+        catch (const uno::RuntimeException&)
+        {
+            throw;
+        }
+        catch (const uno::Exception&)
+        {
+            return false;
+        }
+    }
+
     try
     {
-        m_xAct->store();
         css::uno::Reference<css::beans::XPropertySet> xFrameProps(m_xFrame,
                                                                   
css::uno::UNO_QUERY_THROW);
         css::uno::Reference<css::frame::XLayoutManager> xLayoutManager;
diff --git a/cui/source/inc/acccfg.hxx b/cui/source/inc/acccfg.hxx
index 960fbbe7efc1..abc29984cb3d 100644
--- a/cui/source/inc/acccfg.hxx
+++ b/cui/source/inc/acccfg.hxx
@@ -51,6 +51,7 @@ enum class StartFileDialogType
 };
 
 class ComponentDisposedListener;
+struct AssignmentData;
 
 class SfxAcceleratorConfigPage : public SfxTabPage
 {
@@ -69,8 +70,8 @@ private:
     // Array of reserved key codes in sorted order
     std::vector<sal_uInt16> m_aReservedKeyCodes;
 
-    // Array mapping key code index to a command. The indices are the same as 
for KEYCODE_ARRAY.
-    std::vector<OUString> m_aAssignments;
+    // Lazily created assignment data for each accelerator configuration
+    std::vector<AssignmentData> m_aAssignmentData;
 
     css::uno::Reference<css::uno::XComponentContext> m_xContext;
     css::uno::Reference<css::ui::XAcceleratorConfiguration> m_xGlobal;
@@ -129,7 +130,9 @@ private:
     sal_Int32 MapKeyCodeToPos(const vcl::KeyCode& rCode) const;
     void StartFileDialog(StartFileDialogType nType, const OUString& rTitle);
 
-    void Init(const css::uno::Reference<css::ui::XAcceleratorConfiguration>& 
pAccMgr);
+    void
+    LoadAcceleratorConfig(const 
css::uno::Reference<css::ui::XAcceleratorConfiguration>& pAccMgr);
+    void Init();
     void ResetConfig();
     void ClearSaveInComboBox();
     void AddFrameToSaveInComboBox(const 
css::uno::Reference<css::frame::XFrame>& xFrame);
@@ -137,6 +140,17 @@ private:
     void HandleScopeChanged();
     bool IsReservedKeyCode(const vcl::KeyCode& rCode) const;
     static std::vector<sal_uInt16> GetReservedKeyCodes();
+    // Find the assignments array for the current configuration or return 
nullptr if there isn’t one
+    // yet
+    std::vector<OUString>* FindAssignments();
+    // Get the assignments for the current configuration or lazily create it 
if there isn’t one yet
+    std::vector<OUString>& GetAssignments();
+    static void Apply(const 
css::uno::Reference<css::ui::XAcceleratorConfiguration>& pAccMgr,
+                      const std::vector<OUString>& rAssignments);
+    void Apply(const css::uno::Reference<css::ui::XAcceleratorConfiguration>& 
pAccMgr)
+    {
+        Apply(pAccMgr, GetAssignments());
+    };
 
 public:
     SfxAcceleratorConfigPage(weld::Container* pPage, weld::DialogController* 
pController,
@@ -145,8 +159,6 @@ public:
 
     virtual bool FillItemSet(SfxItemSet*) override;
     virtual void Reset(const SfxItemSet*) override;
-
-    void Apply(const css::uno::Reference<css::ui::XAcceleratorConfiguration>& 
pAccMgr);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 5d46f3e5513d13371b32f45a1cce11fa98a9ed10
Author:     Neil Roberts <[email protected]>
AuthorDate: Sun Mar 1 02:54:44 2026 +0100
Commit:     Neil Roberts <[email protected]>
CommitDate: Sun Mar 8 08:43:36 2026 +0100

    acccfg: Store key assignments in a separate array
    
    Previously the assignments for each key were stored as user data for
    each entry in the key list box. Instead they are now stored in a vector
    which maps key indices to a command string. The key indices are the
    indices of KEYCODE_ARRAY. The user data in TAccInfo which was attached
    to each entry in the list box no longer has any useful information so
    the struct has been removed entirely. The ID of an entry in the list box
    is now directly a key index instead of storing a pointer to the user
    data.
    
    The goal is to make it easier to store the assignments for multiple
    scopes in a later patch.
    
    Change-Id: I267da16210e7354834833b7f5277569e1208a46c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200696
    Tested-by: Jenkins
    Reviewed-by: Neil Roberts <[email protected]>

diff --git a/cui/source/customize/acccfg.cxx b/cui/source/customize/acccfg.cxx
index 1f1d1fa6159f..68bb32250be8 100644
--- a/cui/source/customize/acccfg.cxx
+++ b/cui/source/customize/acccfg.cxx
@@ -919,18 +919,16 @@ IMPL_LINK(SfxAcceleratorConfigPage, KeyInputHdl, const 
KeyEvent&, rKey, bool)
 
     for (int i = 0, nCount = m_xEntriesBox->n_children(); i < nCount; ++i)
     {
-        TAccInfo* pUserData = 
weld::fromId<TAccInfo*>(m_xEntriesBox->get_id(i));
-        if (pUserData)
-        {
-            sal_uInt16 nCode2 = pUserData->m_aKey.GetCode();
-            sal_uInt16 nMod2 = pUserData->m_aKey.GetModifier();
+        sal_uInt32 nKeyPos = m_xEntriesBox->get_id(i).toUInt32();
+        vcl::KeyCode aCode2 = KEYCODE_ARRAY[nKeyPos];
+        sal_uInt16 nCode2 = aCode2.GetCode();
+        sal_uInt16 nMod2 = aCode2.GetModifier();
 
-            if (nCode1 == nCode2 && nMod1 == nMod2)
-            {
-                m_xEntriesBox->select(i);
-                m_xEntriesBox->scroll_to_row(i);
-                return true;
-            }
+        if (nCode1 == nCode2 && nMod1 == nMod2)
+        {
+            m_xEntriesBox->select(i);
+            m_xEntriesBox->scroll_to_row(i);
+            return true;
         }
     }
 
@@ -1053,13 +1051,6 @@ bool SfxAcceleratorConfigPage::IsReservedKeyCode(const 
vcl::KeyCode& rKeyCode) c
 
 SfxAcceleratorConfigPage::~SfxAcceleratorConfigPage()
 {
-    // free memory - remove all dynamic user data
-    for (int i = 0, nCount = m_xEntriesBox->n_children(); i < nCount; ++i)
-    {
-        TAccInfo* pUserData = 
weld::fromId<TAccInfo*>(m_xEntriesBox->get_id(i));
-        delete pUserData;
-    }
-
     // Free the dynamic user data for the SaveIn combobox
     ClearSaveInComboBox();
 
@@ -1122,6 +1113,10 @@ void SfxAcceleratorConfigPage::Init(const 
uno::Reference<ui::XAcceleratorConfigu
     if (!xAccMgr.is())
         return;
 
+    // Initially set all of the assignments to an empty string
+    m_aAssignments.clear();
+    m_aAssignments.resize(KEYCODE_ARRAY_SIZE);
+
     if (!m_bStylesInfoInitialized)
     {
         uno::Reference<frame::XController> xController;
@@ -1145,8 +1140,7 @@ void SfxAcceleratorConfigPage::Init(const 
uno::Reference<ui::XAcceleratorConfigu
         OUString sKey = aKey.GetName();
         if (sKey.isEmpty())
             continue;
-        TAccInfo* pEntry = new TAccInfo(i1, aKey);
-        m_xEntriesBox->append(weld::toId(pEntry), sKey);
+        m_xEntriesBox->append(OUString::number(i1), sKey);
         int nPos = m_xEntriesBox->n_children() - 1;
         m_xEntriesBox->set_text(nPos, OUString(), 1);
         m_xEntriesBox->set_sensitive(nPos, !IsReservedKeyCode(aKey));
@@ -1160,19 +1154,23 @@ void SfxAcceleratorConfigPage::Init(const 
uno::Reference<ui::XAcceleratorConfigu
     for (i2 = 0; i2 < c2; ++i2)
     {
         const awt::KeyEvent& aAWTKey = lKeys[i2];
-        OUString sCommand = xAccMgr->getCommandByKeyEvent(aAWTKey);
-        OUString sLabel = GetLabel4Command(sCommand);
         vcl::KeyCode aKeyCode = 
svt::AcceleratorExecute::st_AWTKey2VCLKey(aAWTKey);
+        OUString sCommand = xAccMgr->getCommandByKeyEvent(aAWTKey);
+
+        const sal_uInt16* pKeyCode
+            = std::find(KEYCODE_ARRAY, KEYCODE_ARRAY + KEYCODE_ARRAY_SIZE, 
aKeyCode.GetFullCode());
+
+        if (pKeyCode < KEYCODE_ARRAY + KEYCODE_ARRAY_SIZE)
+            m_aAssignments[pKeyCode - KEYCODE_ARRAY] = sCommand;
+
         sal_Int32 nPos = MapKeyCodeToPos(aKeyCode);
 
         if (nPos == -1)
             continue;
 
-        m_xEntriesBox->set_text(nPos, sLabel, 1);
-
-        TAccInfo* pEntry = 
weld::fromId<TAccInfo*>(m_xEntriesBox->get_id(nPos));
+        OUString sLabel = GetLabel4Command(sCommand);
 
-        pEntry->m_sCommand = sCommand;
+        m_xEntriesBox->set_text(nPos, sLabel, 1);
     }
 }
 
@@ -1184,17 +1182,11 @@ void SfxAcceleratorConfigPage::Apply(const 
uno::Reference<ui::XAcceleratorConfig
     // Go through the list from the bottom to the top ...
     // because logical accelerator must be preferred instead of
     // physical ones!
-    for (int i = 0, nCount = m_xEntriesBox->n_children(); i < nCount; ++i)
+    for (int i = 0, nCount = m_aAssignments.size(); i < nCount; ++i)
     {
-        TAccInfo* pUserData = 
weld::fromId<TAccInfo*>(m_xEntriesBox->get_id(i));
-        OUString sCommand;
-        awt::KeyEvent aAWTKey;
-
-        if (pUserData)
-        {
-            sCommand = pUserData->m_sCommand;
-            aAWTKey = 
svt::AcceleratorExecute::st_VCLKey2AWTKey(pUserData->m_aKey);
-        }
+        vcl::KeyCode aKey = KEYCODE_ARRAY[i];
+        awt::KeyEvent aAWTKey = 
svt::AcceleratorExecute::st_VCLKey2AWTKey(aKey);
+        OUString sCommand = m_aAssignments[i];
 
         try
         {
@@ -1269,13 +1261,13 @@ IMPL_LINK_NOARG(SfxAcceleratorConfigPage, ChangeHdl, 
weld::Button&, void)
     if (nPos == -1)
         return;
 
-    TAccInfo* pEntry = weld::fromId<TAccInfo*>(m_xEntriesBox->get_id(nPos));
+    sal_uInt32 nKeyPos = m_xEntriesBox->get_id(nPos).toUInt32();
     OUString sNewCommand = m_xFunctionBox->GetCurCommand();
     OUString sLabel = m_xFunctionBox->GetCurLabel();
     if (sLabel.isEmpty())
         sLabel = GetLabel4Command(sNewCommand);
 
-    pEntry->m_sCommand = sNewCommand;
+    m_aAssignments[nKeyPos] = sNewCommand;
     m_xEntriesBox->set_text(nPos, sLabel, 1);
 
     SelectHdl(m_xFunctionBox->get_widget());
@@ -1288,11 +1280,11 @@ IMPL_LINK_NOARG(SfxAcceleratorConfigPage, RemoveHdl, 
weld::Button&, void)
     if (nPos == -1)
         return;
 
-    TAccInfo* pEntry = weld::fromId<TAccInfo*>(m_xEntriesBox->get_id(nPos));
+    sal_uInt32 nKeyPos = m_xEntriesBox->get_id(nPos).toUInt32();
 
     // remove function name from selected entry
     m_xEntriesBox->set_text(nPos, OUString(), 1);
-    pEntry->m_sCommand.clear();
+    m_aAssignments[nKeyPos].clear();
 
     SelectHdl(m_xFunctionBox->get_widget());
 }
@@ -1301,18 +1293,24 @@ IMPL_LINK(SfxAcceleratorConfigPage, SelectHdl, 
weld::TreeView&, rListBox, void)
 {
     if (&rListBox == m_xEntriesBox.get())
     {
-        TAccInfo* pEntry = 
weld::fromId<TAccInfo*>(m_xEntriesBox->get_selected_id());
+        OUString nSelectedId = m_xEntriesBox->get_selected_id();
 
         OUString sPossibleNewCommand = m_xFunctionBox->GetCurCommand();
 
         m_xRemoveButton->set_sensitive(false);
         m_xChangeButton->set_sensitive(false);
 
-        if (pEntry && !IsReservedKeyCode(pEntry->m_aKey))
+        if (!nSelectedId.isEmpty())
         {
-            if (pEntry->isConfigured())
-                m_xRemoveButton->set_sensitive(true);
-            m_xChangeButton->set_sensitive(pEntry->m_sCommand != 
sPossibleNewCommand);
+            sal_uInt32 nKeyPos = nSelectedId.toUInt32();
+
+            if (!IsReservedKeyCode(KEYCODE_ARRAY[nKeyPos]))
+            {
+                OUString sCommand = m_aAssignments[nKeyPos];
+                if (!sCommand.isEmpty())
+                    m_xRemoveButton->set_sensitive(true);
+                m_xChangeButton->set_sensitive(sCommand != 
sPossibleNewCommand);
+            }
         }
     }
     else if (&rListBox == &m_xGroupLBox->get_widget())
@@ -1343,16 +1341,18 @@ IMPL_LINK(SfxAcceleratorConfigPage, SelectHdl, 
weld::TreeView&, rListBox, void)
         m_xChangeButton->set_sensitive(false);
 
         // #i36994 First selected can return null!
-        TAccInfo* pEntry = 
weld::fromId<TAccInfo*>(m_xEntriesBox->get_selected_id());
-        if (pEntry)
+        OUString sSelectedId = m_xEntriesBox->get_selected_id();
+        if (!sSelectedId.isEmpty())
         {
+            sal_uInt32 nKeyPos = sSelectedId.toUInt32();
             OUString sPossibleNewCommand = m_xFunctionBox->GetCurCommand();
 
-            if (!IsReservedKeyCode(pEntry->m_aKey))
+            if (!IsReservedKeyCode(KEYCODE_ARRAY[nKeyPos]))
             {
-                if (pEntry->isConfigured())
+                OUString sCommand = m_aAssignments[nKeyPos];
+                if (!sCommand.isEmpty())
                     m_xRemoveButton->set_sensitive(true);
-                m_xChangeButton->set_sensitive(pEntry->m_sCommand != 
sPossibleNewCommand
+                m_xChangeButton->set_sensitive(sCommand != sPossibleNewCommand
                                                && 
!sPossibleNewCommand.isEmpty());
             }
 
@@ -1362,10 +1362,11 @@ IMPL_LINK(SfxAcceleratorConfigPage, SelectHdl, 
weld::TreeView&, rListBox, void)
             {
                 for (int i = 0, nCount = m_xEntriesBox->n_children(); i < 
nCount; ++i)
                 {
-                    TAccInfo* pUserData = 
weld::fromId<TAccInfo*>(m_xEntriesBox->get_id(i));
-                    if (pUserData && pUserData->m_sCommand == 
sPossibleNewCommand)
+                    sal_uInt32 nEntryKeyPos = 
m_xEntriesBox->get_id(i).toUInt32();
+                    if (m_aAssignments[nEntryKeyPos] == sPossibleNewCommand)
                     {
-                        m_xKeyBox->append(weld::toId(pUserData), 
pUserData->m_aKey.GetName());
+                        vcl::KeyCode aKey(KEYCODE_ARRAY[nEntryKeyPos]);
+                        m_xKeyBox->append(OUString::number(nEntryKeyPos), 
aKey.GetName());
                     }
                 }
             }
@@ -1374,15 +1375,17 @@ IMPL_LINK(SfxAcceleratorConfigPage, SelectHdl, 
weld::TreeView&, rListBox, void)
     else
     {
         // goto selected "key" entry of the key box
-        int nP2 = -1;
-        TAccInfo* pU2 = weld::fromId<TAccInfo*>(m_xKeyBox->get_selected_id());
-        if (pU2)
-            nP2 = MapKeyCodeToPos(pU2->m_aKey);
-        if (nP2 != -1)
+        OUString sSelectedId = m_xKeyBox->get_selected_id();
+        if (!sSelectedId.isEmpty())
         {
-            m_xEntriesBox->select(nP2);
-            m_xEntriesBox->scroll_to_row(nP2);
-            SelectHdl(*m_xEntriesBox);
+            sal_uInt32 nKeyPos = sSelectedId.toUInt32();
+            int nPos = MapKeyCodeToPos(KEYCODE_ARRAY[nKeyPos]);
+            if (nPos != -1)
+            {
+                m_xEntriesBox->select(nPos);
+                m_xEntriesBox->scroll_to_row(nPos);
+                SelectHdl(*m_xEntriesBox);
+            }
         }
     }
 }
@@ -1784,16 +1787,12 @@ void SfxAcceleratorConfigPage::Reset(const SfxItemSet* 
rSet)
 
 sal_Int32 SfxAcceleratorConfigPage::MapKeyCodeToPos(const vcl::KeyCode& aKey) 
const
 {
-    sal_uInt16 nCode1 = aKey.GetCode() + aKey.GetModifier();
+    sal_uInt16 nCode = aKey.GetCode() + aKey.GetModifier();
     for (int i = 0, nCount = m_xEntriesBox->n_children(); i < nCount; ++i)
     {
-        TAccInfo* pUserData = 
weld::fromId<TAccInfo*>(m_xEntriesBox->get_id(i));
-        if (pUserData)
-        {
-            sal_uInt16 nCode2 = pUserData->m_aKey.GetCode() + 
pUserData->m_aKey.GetModifier();
-            if (nCode1 == nCode2)
-                return i;
-        }
+        sal_uInt32 nKeyPos = m_xEntriesBox->get_id(i).toUInt32();
+        if (nCode == KEYCODE_ARRAY[nKeyPos])
+            return i;
     }
 
     return -1;
diff --git a/cui/source/inc/acccfg.hxx b/cui/source/inc/acccfg.hxx
index 11051f350bb2..960fbbe7efc1 100644
--- a/cui/source/inc/acccfg.hxx
+++ b/cui/source/inc/acccfg.hxx
@@ -39,23 +39,6 @@ class SfxMacroInfoItem;
 
 // class SfxAcceleratorConfigPage ----------------------------------------
 
-struct TAccInfo
-{
-public:
-    TAccInfo(sal_Int32 nKeyPos, const vcl::KeyCode& aKey)
-        : m_nKeyPos(nKeyPos)
-        , m_sCommand()
-        , m_aKey(aKey)
-    {
-    }
-
-    bool isConfigured() const { return (m_nKeyPos > -1 && 
!m_sCommand.isEmpty()); }
-
-    sal_Int32 m_nKeyPos;
-    OUString m_sCommand;
-    vcl::KeyCode m_aKey;
-};
-
 namespace sfx2
 {
 class FileDialogHelper;
@@ -86,6 +69,9 @@ private:
     // Array of reserved key codes in sorted order
     std::vector<sal_uInt16> m_aReservedKeyCodes;
 
+    // Array mapping key code index to a command. The indices are the same as 
for KEYCODE_ARRAY.
+    std::vector<OUString> m_aAssignments;
+
     css::uno::Reference<css::uno::XComponentContext> m_xContext;
     css::uno::Reference<css::ui::XAcceleratorConfiguration> m_xGlobal;
     css::uno::Reference<css::ui::XAcceleratorConfiguration> m_xModule;

Reply via email to