cui/uiconfig/ui/specialcharacters.ui                 |   62 -
 include/sfx2/charwin.hxx                             |   23 
 include/svx/charmap.hxx                              |    2 
 include/svx/cuicharmap.hxx                           |   87 +
 sfx2/inc/charmapcontrol.hxx                          |    2 
 sfx2/source/control/charmapcontrol.cxx               |   43 
 svx/source/dialog/charmap.cxx                        |    6 
 svx/source/dialog/cuicharmap.cxx                     |  831 ++++++++++++++-----
 svx/source/dialog/searchcharmap.cxx                  |    2 
 sw/qa/extras/accessibility/dialogs.cxx               |   47 -
 sw/qa/uitest/writer_tests2/formatBulletsNumbering.py |    7 
 sw/qa/uitest/writer_tests3/specialCharacter.py       |    8 
 uitest/demo_ui/char_dialog.py                        |    4 
 13 files changed, 862 insertions(+), 262 deletions(-)

New commits:
commit 574892bdef37bb0b72340344827a940d2cadfa98
Author:     Parth Raiyani <[email protected]>
AuthorDate: Tue Nov 11 20:05:37 2025 +0530
Commit:     Szymon Kłos <[email protected]>
CommitDate: Wed Nov 12 05:49:52 2025 +0100

    Switch to IconView from GtkDrawingArea for special characters dialog
    
    - Replaced SvxShowCharSet with weld::IconView in cuicharmap
    - Updated UI in specialcharacters.ui to include GtkIconView and GtkTreeStore
    - Added tooltip support
    - Introduced necessary methods to make it work as expected with iconview 
conversion
    - introduced lazy loading to load it in batch to improve performance and 
reduce time to render special character icons
    - Added iconview and rendering support for both showchar(normal) and 
searchchar(search) mode
    - Updated relevant test cases
    
    Change-Id: Ib3d6e0fad93d97368692b83bc0d58f3bf8ad57c4
    Signed-off-by: Parth Raiyani <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193345
    Reviewed-by: Szymon Kłos <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/cui/uiconfig/ui/specialcharacters.ui 
b/cui/uiconfig/ui/specialcharacters.ui
index a397c2e5762d..50e8084328c1 100644
--- a/cui/uiconfig/ui/specialcharacters.ui
+++ b/cui/uiconfig/ui/specialcharacters.ui
@@ -2,6 +2,22 @@
 <!-- Generated with glade 3.40.0 -->
 <interface domain="cui">
   <requires lib="gtk+" version="3.20"/>
+  <object class="GtkTreeStore" id="showcharset_model">
+    <columns>
+      <!-- column-name pixbuf -->
+      <column type="GdkPixbuf"/>
+      <!-- column-name id -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkTreeStore" id="searchcharset_model">
+    <columns>
+      <!-- column-name pixbuf -->
+      <column type="GdkPixbuf"/>
+      <!-- column-name id -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
   <object class="GtkDialog" id="SpecialCharactersDialog">
     <property name="can-focus">False</property>
     <property name="border-width">6</property>
@@ -828,18 +844,19 @@
                     <property name="vscrollbar-policy">always</property>
                     <property name="shadow-type">in</property>
                     <child>
-                      <object class="GtkViewport">
+                      <object class="GtkIconView" id="showcharset">
                         <property name="visible">True</property>
-                        <property name="can-focus">False</property>
-                        <child>
-                          <object class="GtkDrawingArea" id="showcharset">
-                            <property name="visible">True</property>
-                            <property name="can-focus">True</property>
-                            <property name="events">GDK_BUTTON_MOTION_MASK | 
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
-                            <property name="hexpand">True</property>
-                            <property name="vexpand">True</property>
-                          </object>
-                        </child>
+                        <property name="can-focus">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="model">showcharset_model</property>
+                        <property name="pixbuf-column">0</property>
+                        <property name="columns">16</property>
+                        <property name="item-padding">4</property>
+                        <property name="margin">6</property>
+                        <property name="column-spacing">2</property>
+                        <property name="row-spacing">2</property>
+                        <property 
name="activate-on-single-click">False</property>
                       </object>
                     </child>
                   </object>
@@ -859,18 +876,19 @@
                     <property name="vscrollbar-policy">always</property>
                     <property name="shadow-type">in</property>
                     <child>
-                      <object class="GtkViewport">
+                      <object class="GtkIconView" id="searchcharset">
                         <property name="visible">True</property>
-                        <property name="can-focus">False</property>
-                        <child>
-                          <object class="GtkDrawingArea" id="searchcharset">
-                            <property name="visible">True</property>
-                            <property name="can-focus">True</property>
-                            <property name="events">GDK_BUTTON_MOTION_MASK | 
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
-                            <property name="hexpand">True</property>
-                            <property name="vexpand">True</property>
-                          </object>
-                        </child>
+                        <property name="can-focus">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="model">searchcharset_model</property>
+                        <property name="pixbuf-column">0</property>
+                        <property name="columns">16</property>
+                        <property name="item-padding">4</property>
+                        <property name="margin">6</property>
+                        <property name="column-spacing">2</property>
+                        <property name="row-spacing">2</property>
+                        <property 
name="activate-on-single-click">False</property>
                       </object>
                     </child>
                   </object>
diff --git a/include/sfx2/charwin.hxx b/include/sfx2/charwin.hxx
index 6bcafdbca9eb..7c6e6ceac116 100644
--- a/include/sfx2/charwin.hxx
+++ b/include/sfx2/charwin.hxx
@@ -76,6 +76,14 @@ public:
 
 class SFX2_DLLPUBLIC SfxCharmapContainer
 {
+public:
+    struct CharChange {
+        OUString sChar;
+        OUString sFont;
+        bool bRemoved;
+    };
+
+private:
     std::deque<OUString>   m_aRecentCharList;
     std::deque<OUString>   m_aRecentCharFontList;
     std::deque<OUString>   m_aFavCharList;
@@ -89,8 +97,8 @@ class SFX2_DLLPUBLIC SfxCharmapContainer
     std::unique_ptr<weld::Widget> m_xRecentGrid;
     std::unique_ptr<weld::Widget> m_xFavGrid;
 
-    Link<void*, void> m_aUpdateFavHdl;
-    Link<void*, void> m_aUpdateRecentHdl;
+    Link<CharChange*, void> m_aUpdateFavHdl;
+    Link<CharChange*, void> m_aUpdateRecentHdl;
 
     DECL_DLLPRIVATE_LINK(RecentClearClickHdl, SvxCharView*, void);
     DECL_DLLPRIVATE_LINK(FavClearClickHdl, SvxCharView*, void);
@@ -101,14 +109,17 @@ public:
     SfxCharmapContainer(weld::Builder& rBuilder, const VclPtr<VirtualDevice>& 
rVirDev, bool bLockGridSizes);
 
     void            init(bool bHasInsert, const Link<SvxCharView*,void> 
&rMouseClickHdl,
-                         const Link<void*,void> &rUpdateFavHdl,
-                         const Link<void*,void> &rUpdateRecentHdl,
+                         const Link<CharChange*,void> &rUpdateFavHdl,
+                         const Link<CharChange*,void> &rUpdateRecentHdl,
                          const Link<SvxCharView *,void> &rFocusInHdl = 
Link<SvxCharView *,void>());
 
-    void            getFavCharacterList();
+    void            loadFavCharacterList();
     void            updateFavCharControl();
 
-    void            getRecentCharacterList(); //gets both recent char and 
recent char font list
+    std::deque<OUString> getFavCharList() { return m_aFavCharList; }
+    std::deque<OUString> getFavCharFontList() { return m_aFavCharFontList; }
+
+    void            loadRecentCharacterList(); //loads both recent char and 
recent char font list
     void            updateRecentCharControl();
 
     void            updateRecentCharacterList(const OUString& sTitle, const 
OUString& rFont);
diff --git a/include/svx/charmap.hxx b/include/svx/charmap.hxx
index b5567a0c8702..1c9f9bf0523b 100644
--- a/include/svx/charmap.hxx
+++ b/include/svx/charmap.hxx
@@ -80,7 +80,7 @@ public:
     vcl::Font const & GetFont() const { return maFont; }
     SVX_DLLPUBLIC FontCharMapRef const & GetFontCharMap();
     bool            isFavChar(std::u16string_view sTitle, std::u16string_view 
rFont);
-    void            getFavCharacterList(); //gets both Fav char and Fav char 
font list
+    void            loadFavCharacterList(); //loads both Fav char and Fav char 
font list
     void            updateFavCharacterList(const OUString& rChar, const 
OUString& rFont);
 
     virtual svx::SvxShowCharSetItem*    ImplGetItem( int _nPos );
diff --git a/include/svx/cuicharmap.hxx b/include/svx/cuicharmap.hxx
index 006cdba0a402..42628e4b75b0 100644
--- a/include/svx/cuicharmap.hxx
+++ b/include/svx/cuicharmap.hxx
@@ -23,22 +23,18 @@
 #include <vcl/virdev.hxx>
 #include <sfx2/basedlgs.hxx>
 #include <svl/itemset.hxx>
-#include <svx/charmap.hxx>
-#include <svx/searchcharmap.hxx>
 #include <svx/ucsubset.hxx>
 #include <sfx2/charwin.hxx>
 #include <svx/svxdllapi.h>
 #include <com/sun/star/frame/XFrame.hpp>
 
+#include <string_view>
 #include <memory>
+#include <map>
 
 using namespace ::com::sun::star;
-class SubsetMap;
 
-namespace svx
-{
-struct SvxShowCharSetItem;
-}
+struct ImplSVEvent;
 
 /// Provides the show characters or texts in a drawing area with special sizes 
and fonts.
 class SVX_DLLPUBLIC SvxShowText final : public weld::CustomWidgetController
@@ -73,6 +69,40 @@ class SVX_DLLPUBLIC SvxCharacterMap final : public 
SfxDialogController
 private:
     void init();
 
+    // Character bitmap generation and model population
+    VclPtr<VirtualDevice> generateCharGraphic(sal_UCS4 cChar);
+    void clearSearchCharModel();
+    void populateShowCharModel();
+    void populateSearchCharModel();
+
+    // Character selection and retrieval
+    void selectCharacter(sal_UCS4 cChar);
+    void selectSearchSetCharFromSubset(const Subset* pSubset);
+    static sal_UCS4 getCharacterFromId(std::u16string_view rId);
+    static OUString getCharacterNameFromId(std::u16string_view sId);
+
+    void modifyFavCharacterList(const OUString& sChar, const OUString& sFont);
+    void rerenderCharacter(std::u16string_view favChar, std::u16string_view 
favCharFont);
+
+    // Context menu and clipboard
+    void createContextMenu(const Point& rPos, bool bSearchMode);
+    void contextMenuSelect(std::u16string_view rIdent);
+    void contextMenuHdl(weld::IconView& rIconView, const Point& pPos, bool 
bSearchMode);
+    static void copyToClipboard(const OUString& rText);
+
+    // Performance optimization via scheduling(lazy loading)
+    void scheduleShowSetBackgroundRendering();
+    void scheduleSearchSetBackgroundRendering();
+    void renderShowSetBatch(sal_Int32 nStartPos, sal_Int32 nCount);
+    void renderSearchSetBatch(sal_Int32 nStartPos, sal_Int32 nCount);
+
+    sal_Int32 m_nShowSetRenderedCount = 0;
+    sal_Int32 m_nSearchSetRenderedCount = 0;
+    static constexpr sal_Int32 RENDER_BATCH_SIZE = 500;
+
+    ImplSVEvent* m_nShowRenderIdleEvent = nullptr;
+    ImplSVEvent* m_nSearchRenderIdleEvent = nullptr;
+
     ScopedVclPtr<VirtualDevice> m_xVirDev;
     vcl::Font aFont;
     std::unique_ptr<const SubsetMap> pSubsetMap;
@@ -83,6 +113,14 @@ private:
 
     SvxShowText m_aShowChar;
 
+    FontCharMapRef mxFontCharMap;
+    std::map<sal_Int32, sal_UCS4> m_aSearchItemList;
+
+    std::unordered_map<OUString, sal_Int32> m_aShowCharPos;
+    std::unordered_map<OUString, sal_Int32> m_aSearchCharPos;
+
+    static sal_UCS4 m_cSelectedChar;
+
     std::unique_ptr<weld::Button> m_xOKBtn;
     std::unique_ptr<weld::Label> m_xFontText;
     std::unique_ptr<weld::ComboBox> m_xFontLB;
@@ -94,10 +132,10 @@ private:
     std::unique_ptr<weld::Button> m_xFavouritesBtn;
     std::unique_ptr<weld::Label> m_xCharName;
     std::unique_ptr<weld::CustomWeld> m_xShowChar;
-    std::unique_ptr<SvxShowCharSet> m_xShowSet;
-    std::unique_ptr<weld::CustomWeld> m_xShowSetArea;
-    std::unique_ptr<SvxSearchCharSet> m_xSearchSet;
-    std::unique_ptr<weld::CustomWeld> m_xSearchSetArea;
+    std::unique_ptr<weld::ScrolledWindow> m_xShowSetArea;
+    std::unique_ptr<weld::ScrolledWindow> m_xSearchSetArea;
+    std::unique_ptr<weld::IconView> m_xShowSet;
+    std::unique_ptr<weld::IconView> m_xSearchSet;
 
     std::unique_ptr<SfxAllItemSet> m_xOutputSet;
 
@@ -107,18 +145,18 @@ private:
         hexadecimal = 16
     };
 
-    // inserts the character that is currently selected in the given 
SvxShowCharSet
-    void insertSelectedCharacter(const SvxShowCharSet* pCharSet);
+    // inserts the character that is currently selected in the given IconView
+    void insertSelectedCharacter(weld::IconView& rIconView);
 
     DECL_DLLPRIVATE_LINK(FontSelectHdl, weld::ComboBox&, void);
     DECL_DLLPRIVATE_LINK(SubsetSelectHdl, weld::ComboBox&, void);
-    DECL_DLLPRIVATE_LINK(CharDoubleClickHdl, SvxShowCharSet*, void);
-    DECL_DLLPRIVATE_LINK(CharSelectHdl, SvxShowCharSet*, void);
-    DECL_DLLPRIVATE_LINK(CharHighlightHdl, SvxShowCharSet*, void);
-    DECL_DLLPRIVATE_LINK(CharPreSelectHdl, SvxShowCharSet*, void);
-    DECL_DLLPRIVATE_LINK(ReturnKeypressOnCharHdl, SvxShowCharSet*, void);
-    DECL_DLLPRIVATE_LINK(FavClickHdl, SvxShowCharSet*, void);
-    DECL_DLLPRIVATE_LINK(SearchCharHighlightHdl, SvxShowCharSet*, void);
+    DECL_DLLPRIVATE_LINK(CharDoubleClickHdl, weld::IconView&, bool);
+    DECL_DLLPRIVATE_LINK(CharSelectHdl, weld::IconView&, void);
+    DECL_DLLPRIVATE_LINK(CharKeyPressHdl, const KeyEvent&, bool);
+    DECL_DLLPRIVATE_LINK(ShowCharMousePressHdl, const MouseEvent&, bool);
+    DECL_DLLPRIVATE_LINK(SearchCharMousePressHdl, const MouseEvent&, bool);
+    DECL_DLLPRIVATE_LINK(ShowCharQueryTooltipHdl, const weld::TreeIter&, 
OUString);
+    DECL_DLLPRIVATE_LINK(SearchCharQueryTooltipHdl, const weld::TreeIter&, 
OUString);
     DECL_DLLPRIVATE_LINK(DecimalCodeChangeHdl, weld::Entry&, void);
     DECL_DLLPRIVATE_LINK(HexCodeChangeHdl, weld::Entry&, void);
     DECL_DLLPRIVATE_LINK(CharClickHdl, SvxCharView*, void);
@@ -126,7 +164,12 @@ private:
     DECL_DLLPRIVATE_LINK(FavSelectHdl, weld::Button&, void);
     DECL_DLLPRIVATE_LINK(SearchUpdateHdl, weld::Entry&, void);
     DECL_DLLPRIVATE_LINK(SearchFieldGetFocusHdl, weld::Widget&, void);
-    DECL_DLLPRIVATE_LINK(UpdateFavHdl, void*, void);
+    DECL_DLLPRIVATE_LINK(UpdateFavHdl, SfxCharmapContainer::CharChange*, void);
+    DECL_DLLPRIVATE_LINK(UpdateRecentHdl, SfxCharmapContainer::CharChange*, 
void);
+    DECL_DLLPRIVATE_LINK(ShowSetScrollHdl, weld::ScrolledWindow&, void);
+    DECL_DLLPRIVATE_LINK(ShowRenderIdleHdl, void*, void);
+    DECL_DLLPRIVATE_LINK(SearchSetScrollHdl, weld::ScrolledWindow&, void);
+    DECL_DLLPRIVATE_LINK(SearchRenderIdleHdl, void*, void);
 
     static void fillAllSubsets(weld::ComboBox& rListBox);
     void selectCharByCode(Radix radix);
@@ -135,6 +178,8 @@ public:
     SvxCharacterMap(weld::Widget* pParent, const SfxItemSet* pSet,
                     css::uno::Reference<css::frame::XFrame> xFrame);
 
+    virtual ~SvxCharacterMap() override;
+
     // for explicit use before AsyncRun
     void prepForRun();
 
diff --git a/sfx2/inc/charmapcontrol.hxx b/sfx2/inc/charmapcontrol.hxx
index 72f0328da2af..968723b631a3 100644
--- a/sfx2/inc/charmapcontrol.hxx
+++ b/sfx2/inc/charmapcontrol.hxx
@@ -51,7 +51,7 @@ private:
     DECL_LINK(CharClickHdl, SvxCharView*, void);
     DECL_LINK(OpenDlgHdl, weld::Button&, void);
     DECL_LINK(DlgBtnFocusInHdl, weld::Widget&, void);
-    DECL_LINK(UpdateRecentHdl, void*, void);
+    DECL_LINK(UpdateRecentHdl, SfxCharmapContainer::CharChange*, void);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/control/charmapcontrol.cxx 
b/sfx2/source/control/charmapcontrol.cxx
index 63a8cb33a739..e3502f601260 100644
--- a/sfx2/source/control/charmapcontrol.cxx
+++ b/sfx2/source/control/charmapcontrol.cxx
@@ -104,16 +104,16 @@ SfxCharmapContainer::SfxCharmapContainer(weld::Builder& 
rBuilder, const VclPtr<V
 }
 
 void SfxCharmapContainer::init(bool bHasInsert, const Link<SvxCharView*,void> 
&rMouseClickHdl,
-                               const Link<void*, void>& rUpdateFavHdl,
-                               const Link<void*, void>& rUpdateRecentHdl,
+                               const Link<CharChange*, void>& rUpdateFavHdl,
+                               const Link<CharChange*, void>& rUpdateRecentHdl,
                                const Link<SvxCharView*,void> &rFocusInHdl)
 {
     m_aUpdateFavHdl = rUpdateFavHdl;
     m_aUpdateRecentHdl = rUpdateRecentHdl;
 
-    getRecentCharacterList();
+    loadRecentCharacterList();
     updateRecentCharControl();
-    getFavCharacterList();
+    loadFavCharacterList();
     updateFavCharControl();
 
     for(int i = 0; i < 16; i++)
@@ -143,7 +143,7 @@ SfxCharmapCtrl::SfxCharmapCtrl(CharmapPopup* pControl, 
weld::Widget* pParent)
     m_xCharInfoLabel->set_size_request(-1, m_xCharInfoLabel->get_text_height() 
* 2);
 
     m_aCharmapContents.init(false, LINK(this, SfxCharmapCtrl, CharClickHdl),
-                            Link<void*,void>(), LINK(this, SfxCharmapCtrl, 
UpdateRecentHdl),
+                            Link<SfxCharmapContainer::CharChange*,void>(), 
LINK(this, SfxCharmapCtrl, UpdateRecentHdl),
                             LINK(this, SfxCharmapCtrl, CharFocusInHdl));
 
     m_xDlgBtn->connect_clicked(LINK(this, SfxCharmapCtrl, OpenDlgHdl));
@@ -154,7 +154,7 @@ SfxCharmapCtrl::~SfxCharmapCtrl()
 {
 }
 
-void SfxCharmapContainer::getFavCharacterList()
+void SfxCharmapContainer::loadFavCharacterList()
 {
     m_aFavCharList.clear();
     m_aFavCharFontList.clear();
@@ -198,7 +198,7 @@ void SfxCharmapContainer::updateFavCharControl()
     m_aUpdateFavHdl.Call(nullptr);
 }
 
-void SfxCharmapContainer::getRecentCharacterList()
+void SfxCharmapContainer::loadRecentCharacterList()
 {
     m_aRecentCharList.clear();
     m_aRecentCharFontList.clear();
@@ -444,11 +444,17 @@ IMPL_LINK(SfxCharmapContainer, RecentClearClickHdl, 
SvxCharView*, rView, void)
     
officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList,
 batch);
     batch->commit();
 
+    CharChange change{sTitle, sFont, true};
+    m_aUpdateRecentHdl.Call(&change);
+
     updateRecentCharControl();
 }
 
 IMPL_LINK_NOARG(SfxCharmapContainer, RecentClearAllClickHdl, SvxCharView*, 
void)
 {
+    std::deque<OUString> oldChars = m_aRecentCharList;
+    std::deque<OUString> oldFonts = m_aRecentCharFontList;
+
     m_aRecentCharList.clear();
     m_aRecentCharFontList.clear();
 
@@ -457,17 +463,33 @@ IMPL_LINK_NOARG(SfxCharmapContainer, 
RecentClearAllClickHdl, SvxCharView*, void)
     
officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set({ }, 
batch);
     batch->commit();
 
+    for (size_t i = 0; i < oldChars.size(); ++i)
+    {
+        CharChange change{oldChars[i], oldFonts[i], true};
+        m_aUpdateRecentHdl.Call(&change);
+    }
+
     updateRecentCharControl();
 }
 
 IMPL_LINK(SfxCharmapContainer, FavClearClickHdl, SvxCharView*, rView, void)
 {
+    OUString sChar = rView->GetText();
+    OUString sFont = rView->GetFont().GetFamilyName();
+
     deleteFavCharacterFromList(rView->GetText(), 
rView->GetFont().GetFamilyName());
+
+    CharChange change{sChar, sFont, true};
+    m_aUpdateFavHdl.Call(&change);
+
     updateFavCharControl();
 }
 
 IMPL_LINK_NOARG(SfxCharmapContainer, FavClearAllClickHdl, SvxCharView*, void)
 {
+    std::deque<OUString> oldChars = m_aFavCharList;
+    std::deque<OUString> oldFonts = m_aFavCharFontList;
+
     m_aFavCharList.clear();
     m_aFavCharFontList.clear();
 
@@ -476,6 +498,11 @@ IMPL_LINK_NOARG(SfxCharmapContainer, FavClearAllClickHdl, 
SvxCharView*, void)
     
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set({ 
}, batch);
     batch->commit();
 
+    for (size_t i = 0; i < oldChars.size(); ++i)
+    {
+        CharChange change{oldChars[i], oldFonts[i], true};
+        m_aUpdateFavHdl.Call(&change);
+    }
     updateFavCharControl();
 }
 
@@ -489,7 +516,7 @@ bool SfxCharmapContainer::hasRecentChars() const
     return !m_aRecentCharList.empty();
 }
 
-IMPL_LINK_NOARG(SfxCharmapCtrl, UpdateRecentHdl, void*, void)
+IMPL_LINK_NOARG(SfxCharmapCtrl, UpdateRecentHdl, 
SfxCharmapContainer::CharChange*, void)
 {
     //checking if the characters are recently used or no
     m_xRecentLabel->set_label(m_aCharmapContents.hasRecentChars() ? 
SfxResId(STR_RECENT) : SfxResId(STR_NORECENT));
diff --git a/svx/source/dialog/charmap.cxx b/svx/source/dialog/charmap.cxx
index adb2749b11f8..9811f93deb5e 100644
--- a/svx/source/dialog/charmap.cxx
+++ b/svx/source/dialog/charmap.cxx
@@ -99,7 +99,7 @@ void SvxShowCharSet::init()
     m_nYGap = 0;
 
     mxScrollArea->connect_vadjustment_changed(LINK(this, SvxShowCharSet, 
VscrollHdl));
-    getFavCharacterList();
+    loadFavCharacterList();
     // other settings depend on selected font => see RecalculateFont
 
     bDrag = false;
@@ -216,7 +216,7 @@ sal_uInt16 SvxShowCharSet::GetRowPos(sal_uInt16 _nPos)
     return _nPos / COLUMN_COUNT ;
 }
 
-void SvxShowCharSet::getFavCharacterList()
+void SvxShowCharSet::loadFavCharacterList()
 {
     maFavCharList.clear();
     maFavCharFontList.clear();
@@ -703,7 +703,7 @@ void SvxShowCharSet::RecalculateFont(vcl::RenderContext& 
rRenderContext)
     rRenderContext.SetFont(aFont);
     rRenderContext.GetFontCharMap(mxFontCharMap);
     m_aItems.clear();
-    getFavCharacterList();
+    loadFavCharacterList();
 
     nX = aSize.Width() / COLUMN_COUNT;
     nY = aSize.Height() / ROW_COUNT;
diff --git a/svx/source/dialog/cuicharmap.cxx b/svx/source/dialog/cuicharmap.cxx
index 84195ccd5543..9b4eeec9633c 100644
--- a/svx/source/dialog/cuicharmap.cxx
+++ b/svx/source/dialog/cuicharmap.cxx
@@ -40,6 +40,11 @@
 #include <comphelper/processfactory.hxx>
 #include <comphelper/propertyvalue.hxx>
 #include <comphelper/dispatchcommand.hxx>
+#include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
+#include <vcl/unohelp2.hxx>
+#include <vcl/event.hxx>
+#include <vcl/keycod.hxx>
+#include <comphelper/lok.hxx>
 
 #include <svx/dialmgr.hxx>
 #include <svx/cuicharmap.hxx>
@@ -53,6 +58,8 @@
 
 using namespace css;
 
+sal_UCS4 SvxCharacterMap::m_cSelectedChar = ' ';  // Initialize with space
+
 SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, const SfxItemSet* pSet,
                                  css::uno::Reference<css::frame::XFrame> 
xFrame)
     : SfxDialogController(pParent, u"cui/ui/specialcharacters.ui"_ustr, 
u"SpecialCharactersDialog"_ustr)
@@ -72,10 +79,10 @@ SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, 
const SfxItemSet* pSet,
     , m_xFavouritesBtn(m_xBuilder->weld_button(u"favbtn"_ustr))
     , m_xCharName(m_xBuilder->weld_label(u"charname"_ustr))
     , m_xShowChar(new weld::CustomWeld(*m_xBuilder, u"showchar"_ustr, 
m_aShowChar))
-    , m_xShowSet(new 
SvxShowCharSet(m_xBuilder->weld_scrolled_window(u"showscroll"_ustr, true), 
m_xVirDev))
-    , m_xShowSetArea(new weld::CustomWeld(*m_xBuilder, u"showcharset"_ustr, 
*m_xShowSet))
-    , m_xSearchSet(new 
SvxSearchCharSet(m_xBuilder->weld_scrolled_window(u"searchscroll"_ustr, true), 
m_xVirDev))
-    , m_xSearchSetArea(new weld::CustomWeld(*m_xBuilder, 
u"searchcharset"_ustr, *m_xSearchSet))
+    , m_xShowSetArea(m_xBuilder->weld_scrolled_window(u"showscroll"_ustr))
+    , m_xSearchSetArea(m_xBuilder->weld_scrolled_window(u"searchscroll"_ustr))
+    , m_xShowSet(m_xBuilder->weld_icon_view(u"showcharset"_ustr))
+    , m_xSearchSet(m_xBuilder->weld_icon_view(u"searchcharset"_ustr))
 {
     m_aShowChar.SetCentered(true);
     m_xFontLB->make_sorted();
@@ -113,22 +120,21 @@ SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, 
const SfxItemSet* pSet,
     }
 
     m_xOutputSet.reset(new SfxAllItemSet(pSet ? *pSet->GetPool() : 
SfxGetpApp()->GetPool()));
-    m_xShowSet->Show();
-    m_xSearchSet->Hide();
+    m_xShowSet->show();
+    m_xSearchSet->hide();
 }
 
 void SvxCharacterMap::prepForRun()
 {
-    if( SvxShowCharSet::getSelectedChar() == ' ')
+    if (m_cSelectedChar == 0 || m_cSelectedChar == ' ')
     {
         m_xOKBtn->set_sensitive(false);
         setFavButtonState(u"", u"");
     }
     else
     {
-        sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
         // using the new UCS4 constructor
-        OUString aOUStr( &cChar, 1 );
+        OUString aOUStr(&m_cSelectedChar, 1);
         m_aShowChar.SetText(aOUStr);
 
         setFavButtonState(aOUStr, m_aShowChar.GetFont().GetFamilyName());
@@ -144,7 +150,7 @@ short SvxCharacterMap::run()
 
 void SvxCharacterMap::SetChar( sal_UCS4 c )
 {
-    m_xShowSet->SelectCharacter( c );
+    selectCharacter(c);
     setFavButtonState(OUString(&c, 1), aFont.GetFamilyName());
 }
 
@@ -159,14 +165,6 @@ void SvxCharacterMap::DisableFontSelection()
     m_xFontLB->set_sensitive(false);
 }
 
-IMPL_LINK_NOARG(SvxCharacterMap, UpdateFavHdl, void*, void)
-{
-    m_xShowSet->getFavCharacterList();
-    m_xSearchSet->getFavCharacterList();
-    // tdf#109214 - redraw highlight of the favorite characters
-    m_xShowSet->Invalidate();
-}
-
 void SvxCharacterMap::init()
 {
     aFont = m_xVirDev->GetFont();
@@ -212,34 +210,41 @@ void SvxCharacterMap::init()
 
     if (bFound)
         m_xFontLB->set_active_text(aDefStr);
-    else if (m_xFontLB->get_count() )
+    else if (m_xFontLB->get_count())
         m_xFontLB->set_active(0);
+
     FontSelectHdl(*m_xFontLB);
     if (m_xSubsetLB->get_count())
         m_xSubsetLB->set_active(0);
 
-    m_xFontLB->connect_changed(LINK( this, SvxCharacterMap, FontSelectHdl));
-    m_xSubsetLB->connect_changed(LINK( this, SvxCharacterMap, 
SubsetSelectHdl));
+    m_xFontLB->connect_changed(LINK(this, SvxCharacterMap, FontSelectHdl));
+    m_xSubsetLB->connect_changed(LINK(this, SvxCharacterMap, SubsetSelectHdl));
     m_xOKBtn->connect_clicked(LINK(this, SvxCharacterMap, InsertClickHdl));
     m_xOKBtn->show();
 
-    m_xShowSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, 
CharDoubleClickHdl ) );
-    m_xShowSet->SetReturnKeyPressHdl(LINK(this, SvxCharacterMap, 
ReturnKeypressOnCharHdl));
-    m_xShowSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) );
-    m_xShowSet->SetHighlightHdl( LINK( this, SvxCharacterMap, CharHighlightHdl 
) );
-    m_xShowSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl 
) );
-    m_xShowSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
-
-    m_xSearchSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, 
CharDoubleClickHdl ) );
-    m_xSearchSet->SetReturnKeyPressHdl(LINK(this, SvxCharacterMap, 
ReturnKeypressOnCharHdl));
-    m_xSearchSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) );
-    m_xSearchSet->SetHighlightHdl( LINK( this, SvxCharacterMap, 
SearchCharHighlightHdl ) );
-    m_xSearchSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, 
CharPreSelectHdl ) );
-    m_xSearchSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
+    m_xShowSet->connect_item_activated(LINK(this, SvxCharacterMap, 
CharDoubleClickHdl));
+    m_xShowSet->connect_selection_changed(LINK(this, SvxCharacterMap, 
CharSelectHdl));
+    m_xShowSet->connect_key_press(LINK(this, SvxCharacterMap, 
CharKeyPressHdl));
+    m_xShowSet->connect_query_tooltip(LINK(this, SvxCharacterMap, 
ShowCharQueryTooltipHdl));
+    if(m_xShowSetArea)
+        m_xShowSetArea->connect_vadjustment_changed(LINK(this, 
SvxCharacterMap, ShowSetScrollHdl));
+
+    m_xSearchSet->connect_item_activated(LINK(this, SvxCharacterMap, 
CharDoubleClickHdl));
+    m_xSearchSet->connect_selection_changed(LINK(this, SvxCharacterMap, 
CharSelectHdl));
+    m_xSearchSet->connect_key_press(LINK(this, SvxCharacterMap, 
CharKeyPressHdl));
+    m_xSearchSet->connect_query_tooltip(LINK(this, SvxCharacterMap, 
SearchCharQueryTooltipHdl));
+    if(m_xSearchSetArea)
+        m_xSearchSetArea->connect_vadjustment_changed(LINK(this, 
SvxCharacterMap, SearchSetScrollHdl));
+
+    if (!comphelper::LibreOfficeKit::isActive())
+    {
+        m_xShowSet->connect_mouse_press(LINK(this, SvxCharacterMap, 
ShowCharMousePressHdl));
+        m_xSearchSet->connect_mouse_press(LINK(this, SvxCharacterMap, 
SearchCharMousePressHdl));
+    }
 
-    m_xDecimalCodeText->connect_changed( LINK( this, SvxCharacterMap, 
DecimalCodeChangeHdl ) );
-    m_xHexCodeText->connect_changed( LINK( this, SvxCharacterMap, 
HexCodeChangeHdl ) );
-    m_xFavouritesBtn->connect_clicked( LINK(this, SvxCharacterMap, 
FavSelectHdl));
+    m_xDecimalCodeText->connect_changed(LINK(this, SvxCharacterMap, 
DecimalCodeChangeHdl));
+    m_xHexCodeText->connect_changed(LINK(this, SvxCharacterMap, 
HexCodeChangeHdl));
+    m_xFavouritesBtn->connect_clicked(LINK(this, SvxCharacterMap, 
FavSelectHdl));
 
     // tdf#117038 set the buttons width to its max possible width so it doesn't
     // make layout change when the label changes
@@ -249,15 +254,14 @@ void SvxCharacterMap::init()
     nMaxWidth = std::max(nMaxWidth, 
m_xFavouritesBtn->get_preferred_size().Width());
     m_xFavouritesBtn->set_size_request(nMaxWidth, -1);
 
-    if( SvxShowCharSet::getSelectedChar() == ' ')
+    if (m_cSelectedChar == 0 || m_cSelectedChar == ' ')
     {
         m_xOKBtn->set_sensitive(false);
     }
     else
     {
-        sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
         // using the new UCS4 constructor
-        OUString aOUStr( &cChar, 1 );
+        OUString aOUStr(&m_cSelectedChar, 1);
         m_aShowChar.SetText(aOUStr);
 
         setFavButtonState(aOUStr, aDefStr);
@@ -267,17 +271,18 @@ void SvxCharacterMap::init()
     m_aCharmapContents.init(m_xFrame.is(),
                             LINK(this, SvxCharacterMap, CharClickHdl),
                             LINK(this, SvxCharacterMap, UpdateFavHdl),
-                            Link<void*, void>());
+                            LINK(this, SvxCharacterMap, UpdateRecentHdl));
 
     setCharName(90);
 
-    m_xSearchText->connect_focus_in(LINK( this, SvxCharacterMap, 
SearchFieldGetFocusHdl ));
+    m_xSearchText->connect_focus_in(LINK(this, SvxCharacterMap, 
SearchFieldGetFocusHdl));
     m_xSearchText->connect_changed(LINK(this, SvxCharacterMap, 
SearchUpdateHdl));
+    m_aCharmapContents.loadFavCharacterList();
 }
 
 void SvxCharacterMap::setFavButtonState(std::u16string_view sTitle, 
std::u16string_view rFont)
 {
-    if(sTitle.empty() || rFont.empty())
+    if (sTitle.empty() || rFont.empty())
     {
         m_xFavouritesBtn->set_sensitive(false);
         return;
@@ -298,7 +303,6 @@ void SvxCharacterMap::setFavButtonState(std::u16string_view 
sTitle, std::u16stri
     }
 }
 
-
 void SvxCharacterMap::SetCharFont( const vcl::Font& rFont )
 {
     // first get the underlying info in order to get font names
@@ -337,7 +341,7 @@ void SvxCharacterMap::fillAllSubsets(weld::ComboBox& 
rListBox)
 
 void SvxCharacterMap::insertCharToDoc(const OUString& sGlyph)
 {
-    if(sGlyph.isEmpty())
+    if (sGlyph.isEmpty())
         return;
 
     if (m_xFrame.is()) {
@@ -360,6 +364,237 @@ void SvxCharacterMap::insertCharToDoc(const OUString& 
sGlyph)
     }
 }
 
+void SvxCharacterMap::populateShowCharModel()
+{
+    m_xShowSet->clear();
+    m_xShowSet->freeze();
+
+    if (!mxFontCharMap.is())
+        return;
+
+    sal_Int32 nId=0;
+    for (sal_UCS4 cChar = mxFontCharMap->GetFirstChar(); ; cChar = 
mxFontCharMap->GetNextChar(cChar))
+    {
+        OUString sId = OUString::number(cChar);
+        m_xShowSet->append(sId, u""_ustr, nullptr);
+        m_aShowCharPos[sId] = nId++;
+
+        if (cChar == mxFontCharMap->GetLastChar())
+            break;
+    }
+
+    m_xShowSet->thaw();
+
+    m_nShowSetRenderedCount = 0;
+    renderShowSetBatch(0, RENDER_BATCH_SIZE);
+    scheduleShowSetBackgroundRendering();
+}
+
+void SvxCharacterMap::renderShowSetBatch(sal_Int32 nStartPos, sal_Int32 nCount)
+{
+    if (!mxFontCharMap.is())
+        return;
+
+    m_xShowSet->freeze();
+
+    sal_Int32 nTotalItems = m_xShowSet->n_children();
+    sal_Int32 nEndPos = std::min(nStartPos + nCount, nTotalItems);
+
+    for (sal_Int32 i = nStartPos; i < nEndPos; ++i)
+    {
+        OUString sId = m_xShowSet->get_id(i);
+        if (sId.isEmpty())
+            continue;
+
+        sal_UCS4 cChar = getCharacterFromId(sId);
+        VclPtr<VirtualDevice> pVDev = generateCharGraphic(cChar);
+
+        m_xShowSet->set_image(i, pVDev);
+        pVDev.disposeAndClear();
+    }
+
+    m_xShowSet->thaw();
+    m_nShowSetRenderedCount = nEndPos;
+}
+
+
+IMPL_LINK_NOARG(SvxCharacterMap, ShowSetScrollHdl, weld::ScrolledWindow&, void)
+{
+    scheduleShowSetBackgroundRendering();
+}
+
+void SvxCharacterMap::scheduleShowSetBackgroundRendering()
+{
+    // Only schedule if there are items left to render
+    if (m_nShowRenderIdleEvent || m_nShowSetRenderedCount >= 
m_xShowSet->n_children())
+        return;
+
+    m_nShowRenderIdleEvent = Application::PostUserEvent(
+        LINK(this, SvxCharacterMap, ShowRenderIdleHdl));
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, ShowRenderIdleHdl, void*, void)
+{
+    m_nShowRenderIdleEvent = nullptr;
+
+    if (m_nShowSetRenderedCount >= m_xShowSet->n_children())
+        return;
+
+    renderShowSetBatch(m_nShowSetRenderedCount, RENDER_BATCH_SIZE);
+
+    // Schedule next batch if more items remain
+    if (m_nShowSetRenderedCount < m_xShowSet->n_children())
+    {
+        m_nShowRenderIdleEvent = Application::PostUserEvent(
+            LINK(this, SvxCharacterMap, ShowRenderIdleHdl));
+    }
+}
+
+void SvxCharacterMap::populateSearchCharModel()
+{
+    m_xSearchSet->clear();
+    m_xSearchSet->freeze();
+
+    sal_Int32 nId = 0;
+    for (const auto& [nIndex, cChar] : m_aSearchItemList)
+    {
+        OUString sId = OUString::number(cChar);
+        m_xSearchSet->append(sId, u""_ustr, nullptr);
+        m_aSearchCharPos[sId] = nId++;
+    }
+
+    m_xSearchSet->thaw();
+
+    m_nSearchSetRenderedCount = 0;
+    renderSearchSetBatch(0, RENDER_BATCH_SIZE);
+    scheduleSearchSetBackgroundRendering();
+}
+
+void SvxCharacterMap::renderSearchSetBatch(sal_Int32 nStartPos, sal_Int32 
nCount)
+{
+    m_xSearchSet->freeze();
+
+    sal_Int32 nTotalItems = m_xSearchSet->n_children();
+    sal_Int32 nEndPos = std::min(nStartPos + nCount, nTotalItems);
+
+    for (sal_Int32 i = nStartPos; i < nEndPos; ++i)
+    {
+        OUString sId = m_xSearchSet->get_id(i);
+        if (sId.isEmpty())
+            continue;
+
+        sal_UCS4 cChar = getCharacterFromId(sId);
+        VclPtr<VirtualDevice> pVDev = generateCharGraphic(cChar);
+
+        m_xSearchSet->set_image(i, pVDev);
+        pVDev.disposeAndClear();
+    }
+
+    m_xSearchSet->thaw();
+    m_nSearchSetRenderedCount = nEndPos;
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchSetScrollHdl, weld::ScrolledWindow&, 
void)
+{
+    scheduleSearchSetBackgroundRendering();
+}
+
+void SvxCharacterMap::scheduleSearchSetBackgroundRendering()
+{
+    // Only schedule if there are items left to render
+    if (m_nSearchRenderIdleEvent || m_nSearchSetRenderedCount >= 
m_xSearchSet->n_children())
+        return;
+
+    m_nSearchRenderIdleEvent = Application::PostUserEvent(
+        LINK(this, SvxCharacterMap, SearchRenderIdleHdl));
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchRenderIdleHdl, void*, void)
+{
+    m_nSearchRenderIdleEvent = nullptr;
+
+    if (m_nSearchSetRenderedCount >= m_xSearchSet->n_children())
+        return;
+
+    renderSearchSetBatch(m_nSearchSetRenderedCount, RENDER_BATCH_SIZE);
+
+    // Schedule next batch if more items remain
+    if (m_nSearchSetRenderedCount < m_xSearchSet->n_children())
+    {
+        m_nSearchRenderIdleEvent = Application::PostUserEvent(
+            LINK(this, SvxCharacterMap, SearchRenderIdleHdl));
+    }
+}
+
+VclPtr<VirtualDevice> SvxCharacterMap::generateCharGraphic(sal_UCS4 cChar)
+{
+    VclPtr<VirtualDevice> pVirDev = VclPtr<VirtualDevice>::Create();
+    pVirDev->SetOutputSizePixel(Size(48, 48));
+
+    vcl::Font aRenderFont = aFont;
+    Size aFontSize = aRenderFont.GetFontSize();
+    aFontSize.setHeight(24);
+    aRenderFont.SetFontSize(aFontSize);
+    pVirDev->SetFont(aRenderFont);
+    
pVirDev->SetBackground(Application::GetSettings().GetStyleSettings().GetWindowColor());
+    pVirDev->Erase();
+
+    OUString sChar(&cChar, 1);
+    if (m_aCharmapContents.isFavChar(sChar, aFont.GetFamilyName()))
+    {
+        const StyleSettings& rStyleSettings = 
Application::GetSettings().GetStyleSettings();
+        Color aHighlightColor(rStyleSettings.GetHighlightColor());
+        pVirDev->SetLineColor(aHighlightColor);
+        pVirDev->DrawRect(tools::Rectangle(Point(0, 0), Size(48, 48)));
+    }
+    Size aTextSize(pVirDev->GetTextWidth(sChar), pVirDev->GetTextHeight());
+    Point aPoint((48 - aTextSize.Width()) / 2, (48 - aTextSize.Height()) / 2);
+    pVirDev->DrawText(aPoint, sChar);
+
+    return pVirDev;
+}
+
+void SvxCharacterMap::selectCharacter(sal_UCS4 cChar)
+{
+    if (!mxFontCharMap.is())
+    {
+        m_xVirDev->SetFont(aFont);
+        m_xVirDev->GetFontCharMap(mxFontCharMap);
+    }
+
+    if (!mxFontCharMap->HasChar(cChar))
+    {
+        cChar = mxFontCharMap->GetNextChar((cChar > 0) ? cChar - 1 : cChar);
+    }
+
+    OUString sId = OUString::number(cChar);
+    const auto& posMap = isSearchMode ? m_aSearchCharPos : m_aShowCharPos;
+    auto it = posMap.find(sId);
+
+    if (it == posMap.end())
+        return; // Character not in current view
+
+    sal_Int32 pos = it->second;
+
+    if (!isSearchMode && pos < m_xShowSet->n_children())
+    {
+        m_xShowSet->select(pos);
+        m_cSelectedChar = cChar;
+    }
+    else if (isSearchMode && pos < m_xSearchSet->n_children())
+    {
+        m_xSearchSet->select(pos);
+        m_cSelectedChar = cChar;
+    }
+}
+
+sal_UCS4 SvxCharacterMap::getCharacterFromId(std::u16string_view rId)
+{
+    OUString sId(rId.data(), rId.size());
+
+    return static_cast<sal_UCS4>(sId.toUInt32());
+}
+
 IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, weld::ComboBox&, void)
 {
     const sal_uInt32 nFont = m_xFontLB->get_active_id().toUInt32();
@@ -370,10 +605,9 @@ IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, 
weld::ComboBox&, void)
     aFont.SetPitch( PITCH_DONTKNOW );
     aFont.SetFamily( FAMILY_DONTKNOW );
 
-    // notify children using this font
-    m_xShowSet->SetFont( aFont );
-    m_xSearchSet->SetFont( aFont );
     m_aShowChar.SetFont( aFont );
+    m_xVirDev->SetFont(aFont);
+    m_xVirDev->GetFontCharMap(mxFontCharMap);
 
     // setup unicode subset listbar with font specific subsets,
     // hide unicode subset listbar for symbol fonts
@@ -384,8 +618,7 @@ IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, 
weld::ComboBox&, void)
     bool bNeedSubset = (aFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL);
     if (bNeedSubset)
     {
-        FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap();
-        pSubsetMap.reset(new SubsetMap( xFontCharMap ));
+        pSubsetMap.reset(new SubsetMap(mxFontCharMap));
 
         // update subset listbox for new font's unicode subsets
         for (auto const& subset : pSubsetMap->GetSubsetMap())
@@ -406,11 +639,23 @@ IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, 
weld::ComboBox&, void)
         // tdf#137294 do this after modifying m_xSubsetLB sensitivity to
         // restore insensitive for the search case
         SearchUpdateHdl(*m_xSearchText);
-        SearchCharHighlightHdl(m_xSearchSet.get());
+        CharSelectHdl(*m_xSearchSet);
+    }
+    else
+    {
+        populateShowCharModel();
     }
 
-    // tdf#118304 reselect current glyph to see if it's still there in new font
-    selectCharByCode(Radix::hexadecimal);
+    if (m_cSelectedChar != 0 && m_cSelectedChar != ' ')
+    {
+        // Restore the previous selection
+        selectCharacter(m_cSelectedChar);
+    }
+    else
+    {
+        sal_UCS4 cChar = mxFontCharMap->GetFirstChar(); // Select the first 
char
+        selectCharacter(cChar);
+    }
 }
 
 void SvxCharacterMap::toggleSearchView(bool state)
@@ -420,15 +665,15 @@ void SvxCharacterMap::toggleSearchView(bool state)
     m_xDecimalCodeText->set_editable(!state);
     m_xSubsetLB->set_sensitive(!state);
 
-    if(state)
+    if (state)
     {
-        m_xSearchSet->Show();
-        m_xShowSet->Hide();
+        m_xSearchSet->show();
+        m_xShowSet->hide();
     }
     else
     {
-        m_xSearchSet->Hide();
-        m_xShowSet->Show();
+        m_xSearchSet->hide();
+        m_xShowSet->show();
     }
 }
 
@@ -449,28 +694,71 @@ IMPL_LINK_NOARG(SvxCharacterMap, SubsetSelectHdl, 
weld::ComboBox&, void)
     const sal_Int32 nPos = m_xSubsetLB->get_active();
     const Subset* pSubset = weld::fromId<const 
Subset*>(m_xSubsetLB->get_active_id());
 
-    if( pSubset && !isSearchMode)
+    if (pSubset && !isSearchMode)
     {
         sal_UCS4 cFirst = pSubset->GetRangeMin();
-        m_xShowSet->SelectCharacter( cFirst );
+        selectCharacter(cFirst);
 
         setFavButtonState(OUString(&cFirst, 1), aFont.GetFamilyName());
         m_xSubsetLB->set_active(nPos);
     }
-    else if( pSubset && isSearchMode)
+    else if (pSubset && isSearchMode)
     {
-        m_xSearchSet->SelectCharacter( pSubset );
+        selectSearchSetCharFromSubset(pSubset);
 
         const Subset* curSubset = nullptr;
-        if( pSubsetMap )
-            curSubset = pSubsetMap->GetSubsetByUnicode( 
m_xSearchSet->GetSelectCharacter() );
-        if( curSubset )
+        if ( pSubsetMap )
+            curSubset = pSubsetMap->GetSubsetByUnicode(m_cSelectedChar);
+        if ( curSubset )
             m_xSubsetLB->set_active_text(curSubset->GetName());
         else
             m_xSubsetLB->set_active(-1);
 
-        sal_UCS4 sChar = m_xSearchSet->GetSelectCharacter();
-        setFavButtonState(OUString(&sChar, 1), aFont.GetFamilyName());
+        setFavButtonState(OUString(&m_cSelectedChar, 1), 
aFont.GetFamilyName());
+    }
+}
+
+void SvxCharacterMap::selectSearchSetCharFromSubset(const Subset* pSubset)
+{
+    if (!mxFontCharMap.is())
+    {
+        m_xVirDev->SetFont(aFont);
+        m_xVirDev->GetFontCharMap(mxFontCharMap);
+    }
+
+    sal_UCS4 cChar = pSubset->GetRangeMin();
+    sal_Int32 foundPos = -1;
+
+    // Find first character from subset that exists in search results
+    while (cChar <= pSubset->GetRangeMax() && foundPos == -1)
+    {
+        auto it = std::find_if (m_aSearchItemList.begin(), 
m_aSearchItemList.end(),
+            [cChar](const auto& pair) {
+                return pair.second == cChar;
+            });
+
+        if (it != m_aSearchItemList.end())
+        {
+            OUString sId = OUString::number(cChar);
+            auto posIt = m_aSearchCharPos.find(sId);
+            if (posIt != m_aSearchCharPos.end())
+            {
+                foundPos = posIt->second;
+                break;
+            }
+        }
+        cChar++;
+    }
+
+    if (foundPos >= 0 && foundPos < m_xSearchSet->n_children())
+    {
+        m_xSearchSet->select(foundPos);
+        m_cSelectedChar = cChar;
+    }
+    else if (m_xSearchSet->n_children() > 0 && !m_aSearchItemList.empty())
+    {
+        m_xSearchSet->select(0);
+        m_cSelectedChar = m_aSearchItemList.begin()->second;
     }
 }
 
@@ -479,11 +767,18 @@ IMPL_LINK_NOARG(SvxCharacterMap, SearchFieldGetFocusHdl, 
weld::Widget&, void)
     m_xOKBtn->set_sensitive(false);
 }
 
+void SvxCharacterMap::clearSearchCharModel()
+{
+    m_xSearchSet->clear();
+    m_aSearchItemList.clear();
+}
+
 IMPL_LINK_NOARG(SvxCharacterMap, SearchUpdateHdl, weld::Entry&, void)
 {
     if (!m_xSearchText->get_text().isEmpty())
     {
-        m_xSearchSet->ClearPreviousData();
+        clearSearchCharModel();
+
         OUString aKeyword = 
m_xSearchText->get_text().trim().toAsciiLowerCase();
         OUString hex_code;
         if (std::u16string_view rest; aKeyword.startsWith("u+", &rest))
@@ -492,20 +787,20 @@ IMPL_LINK_NOARG(SvxCharacterMap, SearchUpdateHdl, 
weld::Entry&, void)
 
         toggleSearchView(true);
 
-        FontCharMapRef xFontCharMap = m_xSearchSet->GetFontCharMap();
-
-        for (sal_UCS4 ucs4 = xFontCharMap->GetFirstChar();; ucs4 = 
xFontCharMap->GetNextChar(ucs4))
+        sal_Int32 nIndex = 0;
+        for (sal_UCS4 ucs4 = mxFontCharMap->GetFirstChar(); ; ucs4 = 
mxFontCharMap->GetNextChar(ucs4))
         {
             bool bAdded = false;
             UErrorCode errorCode = U_ZERO_ERROR;
             char buffer[100];
             u_charName(ucs4, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), 
&errorCode);
+
             if (U_SUCCESS(errorCode))
             {
                 OUString sName = OUString::createFromAscii(buffer);
                 if (!sName.isEmpty() && 
sName.toAsciiLowerCase().indexOf(aKeyword) >= 0)
                 {
-                    m_xSearchSet->AppendCharToList(ucs4);
+                    m_aSearchItemList[nIndex++] = ucs4;
                     bAdded = true;
                 }
             }
@@ -513,13 +808,13 @@ IMPL_LINK_NOARG(SvxCharacterMap, SearchUpdateHdl, 
weld::Entry&, void)
             {
                 OUString actual_number = OUString::number(ucs4, 16);
                 if (actual_number.startsWith(hex_code))
-                    m_xSearchSet->AppendCharToList(ucs4);
+                    m_aSearchItemList[nIndex++] = ucs4;
             }
-            if (ucs4 == xFontCharMap->GetLastChar())
+            if (ucs4 == mxFontCharMap->GetLastChar())
                 break;
         }
 
-        m_xSearchSet->UpdateScrollRange();
+        populateSearchCharModel();
     }
     else
     {
@@ -527,18 +822,15 @@ IMPL_LINK_NOARG(SvxCharacterMap, SearchUpdateHdl, 
weld::Entry&, void)
     }
 }
 
-
 IMPL_LINK(SvxCharacterMap, CharClickHdl, SvxCharView*, rView, void)
 {
     rView->GrabFocus();
 
     SetCharFont(rView->GetFont());
-    m_aShowChar.SetText( rView->GetText() );
+    m_aShowChar.SetText(rView->GetText());
     m_aShowChar.SetFont(rView->GetFont());
     m_aShowChar.Invalidate();
 
-    setFavButtonState(rView->GetText(), 
rView->GetFont().GetFamilyName());//check state
-
     // Get the hexadecimal code
     OUString charValue = rView->GetText();
     sal_UCS4 cChar = 
charValue.iterateCodePoints(&o3tl::temporary(sal_Int32(1)), -1);
@@ -547,6 +839,27 @@ IMPL_LINK(SvxCharacterMap, CharClickHdl, SvxCharView*, 
rView, void)
     // Get the decimal code
     OUString aDecimalText = OUString::number(cChar);
 
+    auto& posMap = isSearchMode ? m_aSearchCharPos : m_aShowCharPos;
+    auto it = posMap.find(aDecimalText);
+
+    if (it != posMap.end())
+    {
+        sal_Int32 pos = it->second;
+
+        if (!isSearchMode)
+        {
+            m_xShowSet->select(pos);
+            m_cSelectedChar = cChar;
+        }
+        else
+        {
+            m_xSearchSet->select(pos);
+            m_cSelectedChar = cChar;
+        }
+    }
+
+    setFavButtonState(rView->GetText(), 
rView->GetFont().GetFamilyName());//check state
+
     m_xHexCodeText->set_text(aHexText);
     m_xDecimalCodeText->set_text(aDecimalText);
     setCharName(cChar);
@@ -555,30 +868,203 @@ IMPL_LINK(SvxCharacterMap, CharClickHdl, SvxCharView*, 
rView, void)
     m_xOKBtn->set_sensitive(true);
 }
 
-void SvxCharacterMap::insertSelectedCharacter(const SvxShowCharSet* pCharSet)
+void SvxCharacterMap::insertSelectedCharacter(weld::IconView& rIconView)
 {
-    assert(pCharSet);
-    sal_UCS4 cChar = pCharSet->GetSelectCharacter();
-    // using the new UCS4 constructor
-    OUString aOUStr( &cChar, 1 );
-    setFavButtonState(aOUStr, aFont.GetFamilyName());
-    insertCharToDoc(aOUStr);
+    auto aSelectedId = rIconView.get_selected_id();
+    if (!aSelectedId.isEmpty()) {
+        sal_UCS4 cChar = getCharacterFromId(aSelectedId);
+        m_cSelectedChar = cChar;
+        OUString aOUStr( &cChar, 1 );
+        setFavButtonState(aOUStr, aFont.GetFamilyName());
+        insertCharToDoc(aOUStr);
+    }
 }
 
-IMPL_LINK(SvxCharacterMap, CharDoubleClickHdl, SvxShowCharSet*, pCharSet, void)
+IMPL_LINK(SvxCharacterMap, CharDoubleClickHdl, weld::IconView&, rIconView, 
bool)
 {
-    insertSelectedCharacter(pCharSet);
+    insertSelectedCharacter(rIconView);
+    return true;
 }
 
-IMPL_LINK_NOARG(SvxCharacterMap, CharSelectHdl, SvxShowCharSet*, void)
+IMPL_LINK(SvxCharacterMap, CharKeyPressHdl, const KeyEvent&, rKEvt, bool)
 {
-    m_xOKBtn->set_sensitive(true);
+    const vcl::KeyCode& rKey = rKEvt.GetKeyCode();
+
+    if (rKey.GetCode() == KEY_RETURN && !rKey.GetModifier())
+    {
+        weld::IconView* pIconView = isSearchMode ? m_xSearchSet.get() : 
m_xShowSet.get();
+        auto aSelectedId = pIconView->get_selected_id();
+        insertSelectedCharacter(*pIconView);
+        if (!aSelectedId.isEmpty())
+        {
+            m_xDialog->response(RET_OK);
+            return true;
+        }
+    }
+
+    return false;
 }
 
-IMPL_LINK(SvxCharacterMap, ReturnKeypressOnCharHdl, SvxShowCharSet*, pCharSet, 
void)
+IMPL_LINK(SvxCharacterMap, CharSelectHdl, weld::IconView&, rIconView, void)
 {
-    insertSelectedCharacter(pCharSet);
-    m_xDialog->response(RET_OK);
+    auto aSelectedId = rIconView.get_selected_id();
+    if (!aSelectedId.isEmpty())
+    {
+        sal_UCS4 cChar = getCharacterFromId(aSelectedId);
+        m_cSelectedChar = cChar;
+
+        OUString aText(&cChar, 1);
+        m_aShowChar.SetText(aText);
+        m_aShowChar.SetFont(aFont);
+        m_aShowChar.Invalidate();
+
+        OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
+        OUString aDecimalText = OUString::number(cChar);
+
+        if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
+            m_xHexCodeText->set_text(aHexText);
+        if (m_xDecimalCodeText->get_text() != aDecimalText)
+            m_xDecimalCodeText->set_text(aDecimalText);
+
+        setCharName(cChar);
+
+        const Subset* pSubset = nullptr;
+        if (pSubsetMap)
+            pSubset = pSubsetMap->GetSubsetByUnicode(cChar);
+        if (pSubset)
+            m_xSubsetLB->set_active_text(pSubset->GetName());
+        else
+            m_xSubsetLB->set_active(-1);
+
+        setFavButtonState(aText, aFont.GetFamilyName());
+        m_xOKBtn->set_sensitive(true);
+    }
+}
+
+IMPL_LINK(SvxCharacterMap, ShowCharMousePressHdl, const MouseEvent&, rMEvt, 
bool)
+{
+    if (!rMEvt.IsRight())
+        return false;
+
+    const Point& pPos = rMEvt.GetPosPixel();
+    contextMenuHdl(*m_xShowSet, pPos, false);
+    return true;
+}
+
+IMPL_LINK(SvxCharacterMap, SearchCharMousePressHdl, const MouseEvent&, rMEvt, 
bool)
+{
+    if (!rMEvt.IsRight())
+        return false;
+
+    const Point& pPos = rMEvt.GetPosPixel();
+    contextMenuHdl(*m_xSearchSet, pPos, true);
+    return true;
+}
+
+void SvxCharacterMap::contextMenuHdl(weld::IconView& rIconView, const Point& 
pPos, bool bSearchMode)
+{
+    for (int i = 0; i < rIconView.n_children(); i++)
+    {
+        const ::tools::Rectangle aRect = rIconView.get_rect(i);
+        if (aRect.Contains(pPos))
+        {
+            rIconView.select(i);
+            OUString sId = rIconView.get_selected_id();
+            if (!sId.isEmpty())
+                m_cSelectedChar = getCharacterFromId(sId);
+            createContextMenu(pPos, bSearchMode);
+            break;
+        }
+    }
+}
+
+void SvxCharacterMap::createContextMenu(const Point& rPos, bool bSearchMode)
+{
+    ::tools::Rectangle aRect(rPos, Size(1, 1));
+
+    std::unique_ptr<weld::Builder> xBuilder(
+        Application::CreateBuilder(bSearchMode ? m_xSearchSet.get() : 
m_xShowSet.get(),
+                                  u"svx/ui/charsetmenu.ui"_ustr));
+    std::unique_ptr<weld::Menu> 
xMenu(xBuilder->weld_menu(u"charsetmenu"_ustr));
+
+    OUString sChar(&m_cSelectedChar, 1);
+    bool bIsFavorite = m_aCharmapContents.isFavChar(sChar, 
aFont.GetFamilyName());
+
+    if (bIsFavorite || m_aCharmapContents.FavCharListIsFull())
+        xMenu->set_visible(u"add"_ustr, false);
+    else
+        xMenu->set_visible(u"remove"_ustr, false);
+
+    OUString sCommand = xMenu->popup_at_rect(
+        bSearchMode ? m_xSearchSet.get() : m_xShowSet.get(), aRect);
+
+    contextMenuSelect(sCommand);
+}
+
+void SvxCharacterMap::contextMenuSelect(std::u16string_view rIdent)
+{
+    if (rIdent.empty())
+        return;
+
+    if (rIdent == u"copy")
+    {
+        OUString sChar(&m_cSelectedChar, 1);
+        copyToClipboard(sChar);
+    }
+    else if (rIdent == u"insert")
+    {
+        insertCharToDoc(OUString(&m_cSelectedChar, 1));
+    }
+    else if (rIdent == u"add" || rIdent == u"remove")
+    {
+        OUString sChar(&m_cSelectedChar, 1);
+        modifyFavCharacterList(sChar, aFont.GetFamilyName());
+        setFavButtonState(sChar, aFont.GetFamilyName());
+        m_aCharmapContents.updateFavCharControl();
+    }
+}
+
+void SvxCharacterMap::copyToClipboard(const OUString& rText)
+{
+    css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard =
+        css::datatransfer::clipboard::SystemClipboard::create(
+            comphelper::getProcessComponentContext());
+
+    if (xClipboard.is())
+    {
+        vcl::unohelper::TextDataObject::CopyStringTo(rText, xClipboard);
+    }
+}
+
+OUString SvxCharacterMap::getCharacterNameFromId(std::u16string_view sId)
+{
+    OUString aStr(sId);
+
+    if (aStr.isEmpty())
+        return OUString();
+
+    sal_UCS4 cChar = getCharacterFromId(aStr);
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    char buffer[100];
+    u_charName(cChar, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
+
+    if (U_SUCCESS(errorCode) && buffer[0] != '
+    {
+        return OUString::createFromAscii(buffer);
+    }
+
+    return OUString();
+}
+
+IMPL_LINK(SvxCharacterMap, ShowCharQueryTooltipHdl, const weld::TreeIter&, 
iter, OUString)
+{
+    return getCharacterNameFromId(m_xShowSet->get_id(iter));
+}
+
+IMPL_LINK(SvxCharacterMap, SearchCharQueryTooltipHdl, const weld::TreeIter&, 
iter, OUString)
+{
+    return getCharacterNameFromId(m_xSearchSet->get_id(iter));
 }
 
 IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, weld::Button&, void)
@@ -586,21 +1072,21 @@ IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, 
weld::Button&, void)
     OUString sChar = m_aShowChar.GetText();
     insertCharToDoc(sChar);
     // Need to update recent character list, when OK button does not insert
-    if(!m_xFrame.is())
+    if (!m_xFrame.is())
         m_aCharmapContents.updateRecentCharacterList(sChar, 
aFont.GetFamilyName());
     m_xDialog->response(RET_OK);
 }
 
 IMPL_LINK_NOARG(SvxCharacterMap, FavSelectHdl, weld::Button&, void)
 {
+    modifyFavCharacterList(m_aShowChar.GetText(), 
m_aShowChar.GetFont().GetFamilyName());
+
     if 
(m_xFavouritesBtn->get_label().match(SvxResId(RID_SVXSTR_ADD_FAVORITES)))
     {
-        m_aCharmapContents.updateFavCharacterList(m_aShowChar.GetText(), 
m_aShowChar.GetFont().GetFamilyName());
         setFavButtonState(m_aShowChar.GetText(), 
m_aShowChar.GetFont().GetFamilyName());
     }
     else
     {
-        m_aCharmapContents.deleteFavCharacterFromList(m_aShowChar.GetText(), 
m_aShowChar.GetFont().GetFamilyName());
         m_xFavouritesBtn->set_label(SvxResId(RID_SVXSTR_ADD_FAVORITES));
         m_xFavouritesBtn->set_sensitive(false);
     }
@@ -608,89 +1094,70 @@ IMPL_LINK_NOARG(SvxCharacterMap, FavSelectHdl, 
weld::Button&, void)
     m_aCharmapContents.updateFavCharControl();
 }
 
-IMPL_LINK_NOARG(SvxCharacterMap, FavClickHdl, SvxShowCharSet*, void)
+void SvxCharacterMap::modifyFavCharacterList(const OUString& sChar, const 
OUString& sFont)
 {
-    m_aCharmapContents.getFavCharacterList();
-    m_aCharmapContents.updateFavCharControl();
+    if (m_aCharmapContents.isFavChar(sChar, sFont))
+    {
+        m_aCharmapContents.deleteFavCharacterFromList(sChar, sFont);
+    }
+    else
+    {
+        m_aCharmapContents.updateFavCharacterList(sChar, sFont);
+    }
+
+    rerenderCharacter(sChar, sFont);
 }
 
-IMPL_LINK_NOARG(SvxCharacterMap, CharHighlightHdl, SvxShowCharSet*, void)
+IMPL_LINK(SvxCharacterMap, UpdateFavHdl, SfxCharmapContainer::CharChange*, 
pChange, void)
 {
-    OUString aText;
-    sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
-    bool bSelect = (cChar > 0);
-
-    // show char sample
-    if ( bSelect )
+    if (!pChange)
     {
-        // using the new UCS4 constructor
-        aText = OUString( &cChar, 1 );
-        // Get the hexadecimal code
-        OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
-        // Get the decimal code
-        OUString aDecimalText = OUString::number(cChar);
-        setCharName(cChar);
+        m_aCharmapContents.loadFavCharacterList();
+        return;
+    }
 
-        // Update the hex and decimal codes only if necessary
-        if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
-            m_xHexCodeText->set_text(aHexText);
-        if (m_xDecimalCodeText->get_text() != aDecimalText)
-            m_xDecimalCodeText->set_text( aDecimalText );
+    rerenderCharacter(pChange->sChar, pChange->sFont);
 
-        const Subset* pSubset = nullptr;
-        if( pSubsetMap )
-            pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
-        if( pSubset )
-            m_xSubsetLB->set_active_text(pSubset->GetName());
-        else
-            m_xSubsetLB->set_active(-1);
-    }
+    if (pChange->bRemoved)
+        setFavButtonState(pChange->sChar, pChange->sFont);
+}
 
-    m_aShowChar.SetText( aText );
-    m_aShowChar.SetFont( aFont );
-    m_aShowChar.Invalidate();
+IMPL_LINK(SvxCharacterMap, UpdateRecentHdl, SfxCharmapContainer::CharChange*, 
pChange, void)
+{
+    if (!pChange)
+    {
+        m_aCharmapContents.loadRecentCharacterList();
+        return;
+    }
 
-    setFavButtonState(aText, aFont.GetFamilyName());
+    rerenderCharacter(pChange->sChar, pChange->sFont);
 }
 
-IMPL_LINK_NOARG(SvxCharacterMap, SearchCharHighlightHdl, SvxShowCharSet*, void)
+void SvxCharacterMap::rerenderCharacter(std::u16string_view sChar, 
std::u16string_view sFont)
 {
-    OUString aText;
-    sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
-    bool bSelect = (cChar > 0);
+    OUString favChar(sChar.data(), sChar.size());
+    OUString favCharFont(sFont.data(), sFont.size());
 
-    // show char sample
-    if ( bSelect )
-    {
-        aText = OUString( &cChar, 1 );
-        // Get the hexadecimal code
-        OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
-        // Get the decimal code
-        OUString aDecimalText = OUString::number(cChar);
-        setCharName(cChar);
+    if (favCharFont != aFont.GetFamilyName())
+        return;
 
-        // Update the hex and decimal codes only if necessary
-        if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
-            m_xHexCodeText->set_text(aHexText);
-        if (m_xDecimalCodeText->get_text() != aDecimalText)
-            m_xDecimalCodeText->set_text( aDecimalText );
+    sal_UCS4 cChar = favChar.iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
+    OUString sId = OUString::number(cChar);
 
-        const Subset* pSubset = nullptr;
-        if( pSubsetMap )
-            pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
-        if( pSubset )
-            m_xSubsetLB->set_active_text(pSubset->GetName());
-        else
-            m_xSubsetLB->set_active(-1);
-    }
+    auto& posMap = isSearchMode ? m_aSearchCharPos : m_aShowCharPos;
+    auto it = posMap.find(sId);
 
-    if(m_xSearchSet->HasFocus())
+    if (it != posMap.end())
     {
-        m_aShowChar.SetText( aText );
-        m_aShowChar.SetFont( aFont );
-        m_aShowChar.Invalidate();
+        sal_Int32 pos = it->second;
+        VclPtr<VirtualDevice> pVDev = generateCharGraphic(cChar);
 
-        setFavButtonState(aText, aFont.GetFamilyName());
+        if (!isSearchMode)
+            m_xShowSet->set_image(pos, pVDev);
+        else
+            m_xSearchSet->set_image(pos, pVDev);
+
+        pVDev.disposeAndClear();
     }
 }
 
@@ -707,10 +1174,9 @@ void SvxCharacterMap::selectCharByCode(Radix radix)
             break;
     }
     // Convert the code back to a character using the appropriate radix
-    sal_UCS4 cChar = aCodeString.toUInt32(static_cast<sal_Int16> (radix));
+    sal_UCS4 cChar = aCodeString.toUInt32(static_cast<sal_Int16>(radix));
     // Use FontCharMap::HasChar(sal_UCS4 cChar) to see if the desired 
character is in the font
-    FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap();
-    if (xFontCharMap->HasChar(cChar))
+    if (mxFontCharMap->HasChar(cChar))
         // Select the corresponding character
         SetChar(cChar);
     else {
@@ -728,6 +1194,18 @@ void SvxCharacterMap::selectCharByCode(Radix radix)
     }
 }
 
+SvxCharacterMap::~SvxCharacterMap()
+{
+    if (!comphelper::LibreOfficeKit::isActive())
+    {
+        if (m_nShowRenderIdleEvent)
+            Application::RemoveUserEvent(m_nShowRenderIdleEvent);
+        if (m_nSearchRenderIdleEvent)
+            Application::RemoveUserEvent(m_nSearchRenderIdleEvent);
+    }
+
+}
+
 IMPL_LINK_NOARG(SvxCharacterMap, DecimalCodeChangeHdl, weld::Entry&, void)
 {
     selectCharByCode(Radix::decimal);
@@ -738,23 +1216,6 @@ IMPL_LINK_NOARG(SvxCharacterMap, HexCodeChangeHdl, 
weld::Entry&, void)
     selectCharByCode(Radix::hexadecimal);
 }
 
-IMPL_LINK(SvxCharacterMap, CharPreSelectHdl, SvxShowCharSet*, pCharSet, void)
-{
-    assert(pCharSet);
-    // adjust subset selection
-    if( pSubsetMap )
-    {
-        sal_UCS4 cChar = pCharSet->GetSelectCharacter();
-
-        setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName());
-        const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
-        if( pSubset )
-            m_xSubsetLB->set_active_text(pSubset->GetName());
-    }
-
-    m_xOKBtn->set_sensitive(true);
-}
-
 // class SvxShowText =====================================================
 SvxShowText::SvxShowText(const VclPtr<VirtualDevice>& rVirDev)
     : m_xVirDev(rVirDev)
@@ -836,9 +1297,9 @@ void SvxShowText::Paint(vcl::RenderContext& 
rRenderContext, const tools::Rectang
         // shift back vertically if needed
         int nYLDelta = aBoundRect.Top();
         int nYHDelta = aSize.Height() - aBoundRect.Bottom();
-        if( nYLDelta <= 0 )
+        if ( nYLDelta <= 0 )
             aPoint.AdjustY( -(nYLDelta - 1) );
-        else if( nYHDelta <= 0 )
+        else if ( nYHDelta <= 0 )
             aPoint.AdjustY(nYHDelta - 1 );
 
         if (mbCenter)
@@ -851,9 +1312,9 @@ void SvxShowText::Paint(vcl::RenderContext& 
rRenderContext, const tools::Rectang
             // shift back horizontally if needed
             int nXLDelta = aBoundRect.Left();
             int nXHDelta = aSize.Width() - aBoundRect.Right();
-            if( nXLDelta <= 0 )
+            if ( nXLDelta <= 0 )
                 aPoint.AdjustX( -(nXLDelta - 1) );
-            else if( nXHDelta <= 0 )
+            else if ( nXHDelta <= 0 )
                 aPoint.AdjustX(nXHDelta - 1 );
         }
     }
diff --git a/svx/source/dialog/searchcharmap.cxx 
b/svx/source/dialog/searchcharmap.cxx
index 16acbc61e985..b883ac39694e 100644
--- a/svx/source/dialog/searchcharmap.cxx
+++ b/svx/source/dialog/searchcharmap.cxx
@@ -180,7 +180,7 @@ void SvxSearchCharSet::RecalculateFont(vcl::RenderContext& 
rRenderContext)
     rRenderContext.SetFont(aFont);
     rRenderContext.GetFontCharMap(mxFontCharMap);
     m_aItems.clear();
-    getFavCharacterList();
+    loadFavCharacterList();
 
     nX = aSize.Width() / COLUMN_COUNT;
     nY = aSize.Height() / ROW_COUNT;
diff --git a/sw/qa/extras/accessibility/dialogs.cxx 
b/sw/qa/extras/accessibility/dialogs.cxx
index 75d5f15bdc54..71b427e0843e 100644
--- a/sw/qa/extras/accessibility/dialogs.cxx
+++ b/sw/qa/extras/accessibility/dialogs.cxx
@@ -13,6 +13,7 @@
 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
 #include <com/sun/star/linguistic2/XLinguServiceManager2.hpp>
 #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
 
 #include <vcl/scheduler.hxx>
 
@@ -41,7 +42,25 @@ CPPUNIT_TEST_FIXTURE(test::AccessibleTestBase, 
BasicTestSpecialCharactersDialog)
         dialog.postExtTextEventAsync(u"copyright"_ustr);
         Scheduler::ProcessEventsToIdle();
 
-        CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::TABLE_CELL, 
u"©"));
+        CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::LIST, u""));
+
+        auto xList = getFocusedObject(dialog.getAccessible());
+        dialog.postKeyEventAsync(0, awt::Key::DOWN);
+        Scheduler::ProcessEventsToIdle();
+
+        uno::Reference<css::accessibility::XAccessibleSelection> 
xSelection(xList, uno::UNO_QUERY);
+        CPPUNIT_ASSERT(xSelection.is());
+
+        sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount();
+        CPPUNIT_ASSERT(nSelected > 0);
+
+        auto xSelectedChild = xSelection->getSelectedAccessibleChild(0);
+        CPPUNIT_ASSERT(xSelectedChild.is());
+
+        auto xSelectedContext = xSelectedChild->getAccessibleContext();
+        CPPUNIT_ASSERT(xSelectedContext.is());
+
+        CPPUNIT_ASSERT_EQUAL(u"COPYRIGHT SIGN"_ustr, 
xSelectedContext->getAccessibleDescription());
 
         /* there was a focus issue in this dialog: the table holding the 
characters always had the
          * selected element as focused, even when tabbing outside.
@@ -68,19 +87,35 @@ CPPUNIT_TEST_FIXTURE(test::AccessibleTestBase, 
TestSpecialCharactersDialogFocus)
     load(u"private:factory/swriter"_ustr);
 
     auto dialogWaiter = awaitDialog(u"Special Characters", [](Dialog& dialog) {
-        CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::TABLE_CELL, 
u" "));
+        CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::LIST, u""));
 
         /* as there is a bug that focusing the character table doesn't enable 
the Insert button
          * (https://bugs.documentfoundation.org/show_bug.cgi?id=153806), we 
move to another cell
          * so it works. */
 
         // tdf#153918: Check that '!' char has correct accessible name and 
insert it
+        auto xList = getFocusedObject(dialog.getAccessible());
+
+        dialog.postKeyEventAsync(0, awt::Key::HOME);
+        Scheduler::ProcessEventsToIdle();
+
         dialog.postKeyEventAsync(0, awt::Key::RIGHT);
         Scheduler::ProcessEventsToIdle();
-        CPPUNIT_ASSERT_EQUAL(
-            AccessibilityTools::getAccessibleObjectForName(
-                dialog.getAccessible(), 
accessibility::AccessibleRole::TABLE_CELL, u"!"),
-            getFocusedObject(dialog.getAccessible()));
+
+        uno::Reference<css::accessibility::XAccessibleSelection> 
xSelection(xList, uno::UNO_QUERY);
+        CPPUNIT_ASSERT(xSelection.is());
+
+        sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount();
+        CPPUNIT_ASSERT(nSelected > 0);
+
+        auto xSelectedChild = xSelection->getSelectedAccessibleChild(0);
+        CPPUNIT_ASSERT(xSelectedChild.is());
+
+        auto xSelectedContext = xSelectedChild->getAccessibleContext();
+        CPPUNIT_ASSERT(xSelectedContext.is());
+
+        CPPUNIT_ASSERT_EQUAL(u"EXCLAMATION MARK"_ustr,
+                             xSelectedContext->getAccessibleDescription());
 
         
CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::PUSH_BUTTON, 
u"Insert"));
         dialog.postKeyEventAsync(0, awt::Key::RETURN);
diff --git a/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py 
b/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py
index 31810c8af751..ca2457103a29 100644
--- a/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py
+++ b/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py
@@ -36,7 +36,8 @@ class formatBulletsNumbering(UITestCase):
                 xChangeBulletBtn = xBulletPage.getChild("changeBulletBtn")
                 with 
self.ui_test.execute_blocking_action(xChangeBulletBtn.executeAction, 
args=('CLICK', ())) as xCharSetDialog:
                     xCharSet = xCharSetDialog.getChild("showcharset")
-                    xCharSet.executeAction("SELECT", 
mkPropertyValues({"COLUMN": "21", "ROW": "1"}))
+                    character6 = xCharSet.getChild("5")
+                    character6.executeAction("SELECT", mkPropertyValues({}))
 
             # Check that the "black down-pointing triangle" bullet is the 
third item
             with 
self.ui_test.execute_dialog_through_command(".uno:BulletsAndNumberingDialog") 
as xDialog:
@@ -56,8 +57,8 @@ class formatBulletsNumbering(UITestCase):
                     xHexText = xCharSetDialog.getChild("hexvalue")
                     xDecText = xCharSetDialog.getChild("decimalvalue")
                     # Check the "black down-pointing triangle" bullet Hex and 
Decimal value
-                    self.assertEqual(get_state_as_dict(xHexText)["Text"], 
"25BC")
-                    self.assertEqual(get_state_as_dict(xDecText)["Text"], 
"9660")
+                    self.assertEqual(get_state_as_dict(xHexText)["Text"], "A2")
+                    self.assertEqual(get_state_as_dict(xDecText)["Text"], 
"162")
 
 
    def test_bullets_and_numbering_dialog_tab_position(self):
diff --git a/sw/qa/uitest/writer_tests3/specialCharacter.py 
b/sw/qa/uitest/writer_tests3/specialCharacter.py
index 02a105835c44..d9a276afcce9 100644
--- a/sw/qa/uitest/writer_tests3/specialCharacter.py
+++ b/sw/qa/uitest/writer_tests3/specialCharacter.py
@@ -38,7 +38,8 @@ class specialCharacter(UITestCase):
             with 
self.ui_test.execute_dialog_through_command(".uno:InsertSymbol", 
close_button="cancel") as xDialog:
                 xCharSet = xDialog.getChild("showcharset")  # default charset
 
-                xCharSet.executeAction("SELECT", mkPropertyValues({"COLUMN": 
"1", "ROW": "4"}))  # digit 4 selected
+                element21 = xCharSet.getChild("20") # digit 4 selected
+                element21.executeAction("SELECT", mkPropertyValues({}))
 
                 xHexText = xDialog.getChild("hexvalue")
                 xDecText = xDialog.getChild("decimalvalue")
@@ -70,9 +71,10 @@ class specialCharacter(UITestCase):
                 # Markus: Actually after a round of debugging I think the 
problem is actually that the test depends on the used font.
                 # Therefore, if the font is not available or not selected by 
default the test fails.
                 #        xCharSet = xDialog.getChild("searchcharset")    
#another charset -> search charset
-                #        xCharSet.executeAction("SELECT", 
mkPropertyValues({"COLUMN": "0", "ROW": "0"}))   #digit 4 selected, we have 
only one result;
+                #        element = xCharSet.getChild("0")   #digit 4 selected, 
we have only one result;
+                #        element.executeAction("SELECT", mkPropertyValues({}))
                 #        sleep(1)                                              
    #try sleep here
-                #        xCharSet.executeAction("SELECT", 
mkPropertyValues({"COLUMN": "0", "ROW": "0"}))   #try it twice, because it 
works at local,but fail on gerrit
+                #        element.executeAction("SELECT", mkPropertyValues({})) 
  #try it twice, because it works at local,but fail on gerrit
                 ##gerrit:self.assertEqual(get_state_as_dict(xHexText)["Text"], 
"34")    # check the values for digit 4; AssertionError: '1' != '34'
 
                 #        xHexText = xDialog.getChild("hexvalue")
diff --git a/uitest/demo_ui/char_dialog.py b/uitest/demo_ui/char_dialog.py
index 9475f3b16edd..a1bf5a2ef617 100644
--- a/uitest/demo_ui/char_dialog.py
+++ b/uitest/demo_ui/char_dialog.py
@@ -18,8 +18,8 @@ class CharDialogText(UITestCase):
             with 
self.ui_test.execute_dialog_through_command(".uno:InsertSymbol", 
close_button="cancel") as xCharDialog:
 
                 xCharSet = xCharDialog.getChild("showcharset")
-
-                xCharSet.executeAction("SELECT", mkPropertyValues({"COLUMN": 
"2", "ROW": "2"}))
+                element35 = xCharSet.getChild("34")
+                element35.executeAction("SELECT", mkPropertyValues({}))
 
 
 

Reply via email to