cui/source/dialogs/cuicharmap.cxx      |  408 +-----------------------------
 include/cui/cuicharmap.hxx             |   34 --
 include/sfx2/charwin.hxx               |   58 ++++
 sfx2/inc/charmapcontrol.hxx            |   16 -
 sfx2/source/control/charmapcontrol.cxx |  440 ++++++++++++++++++++++++++-------
 sfx2/uiconfig/ui/charmapcontrol.ui     |    4 
 6 files changed, 430 insertions(+), 530 deletions(-)

New commits:
commit c706fde1c4ecc6974bcf32ce33aacf3093355ae1
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Tue Jun 27 12:35:57 2023 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Wed Jun 28 09:41:20 2023 +0200

    Resolves: tdf#156067 merge special char dialog/popup logic
    
    there was some cut and paste done to create the popup
    at some point, so put it back together and reuse the
    "delete recent" etc which is missing from the popup case
    
    Change-Id: Idc33d83ea04b46b0255e77bcecf565dc8174e426
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153647
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/cui/source/dialogs/cuicharmap.cxx 
b/cui/source/dialogs/cuicharmap.cxx
index c075c12326d2..4c4df2fe9cb3 100644
--- a/cui/source/dialogs/cuicharmap.cxx
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -58,38 +58,7 @@ SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, 
const SfxItemSet* pSet,
     , m_xVirDev(VclPtr<VirtualDevice>::Create())
     , isSearchMode(true)
     , m_xFrame(std::move(xFrame))
-    , m_aRecentCharView{SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev)}
-    , m_aFavCharView{SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev)}
+    , m_aCharmapContents(*m_xBuilder, m_xVirDev)
     , m_aShowChar(m_xVirDev)
     , m_xOKBtn(m_xFrame.is() ? m_xBuilder->weld_button("insert") : 
m_xBuilder->weld_button("ok"))
     , m_xFontText(m_xBuilder->weld_label("fontft"))
@@ -101,41 +70,7 @@ SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, 
const SfxItemSet* pSet,
     , m_xDecimalCodeText(m_xBuilder->weld_entry("decimalvalue"))
     , m_xFavouritesBtn(m_xBuilder->weld_button("favbtn"))
     , m_xCharName(m_xBuilder->weld_label("charname"))
-    , m_xRecentGrid(m_xBuilder->weld_widget("viewgrid"))
-    , m_xFavGrid(m_xBuilder->weld_widget("favgrid"))
     , m_xShowChar(new weld::CustomWeld(*m_xBuilder, "showchar", m_aShowChar))
-    , m_xRecentCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar1", m_aRecentCharView[0]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar2", m_aRecentCharView[1]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar3", m_aRecentCharView[2]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar4", m_aRecentCharView[3]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar5", m_aRecentCharView[4]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar6", m_aRecentCharView[5]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar7", m_aRecentCharView[6]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar8", m_aRecentCharView[7]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar9", m_aRecentCharView[8]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar10", m_aRecentCharView[9]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar11", m_aRecentCharView[10]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar12", m_aRecentCharView[11]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar13", m_aRecentCharView[12]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar14", m_aRecentCharView[13]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar15", m_aRecentCharView[14]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar16", m_aRecentCharView[15])}
-    , m_xFavCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar1", m_aFavCharView[0]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar2", m_aFavCharView[1]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar3", m_aFavCharView[2]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar4", m_aFavCharView[3]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar5", m_aFavCharView[4]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar6", m_aFavCharView[5]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar7", m_aFavCharView[6]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar8", m_aFavCharView[7]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar9", m_aFavCharView[8]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar10", m_aFavCharView[9]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar11", m_aFavCharView[10]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar12", m_aFavCharView[11]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar13", m_aFavCharView[12]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar14", m_aFavCharView[13]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar15", m_aFavCharView[14]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar16", m_aFavCharView[15])}
     , m_xShowSet(new 
SvxShowCharSet(m_xBuilder->weld_scrolled_window("showscroll", true), m_xVirDev))
     , m_xShowSetArea(new weld::CustomWeld(*m_xBuilder, "showcharset", 
*m_xShowSet))
     , m_xSearchSet(new 
SvxSearchCharSet(m_xBuilder->weld_scrolled_window("searchscroll", true), 
m_xVirDev))
@@ -149,9 +84,6 @@ SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, 
const SfxItemSet* pSet,
     m_xCharName->set_size_request(m_aShowChar.get_preferred_size().Width(), 
m_xCharName->get_text_height() * 4);
     //lock the size request of this widget to the width of the original .ui 
string
     
m_xHexCodeText->set_size_request(m_xHexCodeText->get_preferred_size().Width(), 
-1);
-    //so things don't jump around if all the children are hidden
-    m_xRecentGrid->set_size_request(-1, 
m_aRecentCharView[0].get_preferred_size().Height());
-    m_xFavGrid->set_size_request(-1, 
m_aFavCharView[0].get_preferred_size().Height());
 
     init();
 
@@ -222,236 +154,14 @@ void SvxCharacterMap::DisableFontSelection()
     m_xFontLB->set_sensitive(false);
 }
 
-
-void SvxCharacterMap::getRecentCharacterList()
-{
-    //retrieve recent character list
-    const css::uno::Sequence< OUString > rRecentCharList( 
officecfg::Office::Common::RecentCharacters::RecentCharacterList::get() );
-    for (OUString const & s : rRecentCharList)
-    {
-        maRecentCharList.push_back(s);
-    }
-
-    //retrieve recent character font list
-    const css::uno::Sequence< OUString > rRecentCharFontList( 
officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::get() );
-    for (OUString const & s : rRecentCharFontList)
-    {
-        maRecentCharFontList.push_back(s);
-    }
-
-    // tdf#135997: make sure that the two lists are same length
-    const auto nCommonLength = std::min(maRecentCharList.size(), 
maRecentCharFontList.size());
-    maRecentCharList.resize(nCommonLength);
-    maRecentCharFontList.resize(nCommonLength);
-}
-
-
-void SvxCharacterMap::getFavCharacterList()
-{
-    maFavCharList.clear();
-    maFavCharFontList.clear();
-    //retrieve recent character list
-    const css::uno::Sequence< OUString > rFavCharList( 
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::get() );
-    for (const OUString& s : rFavCharList)
-    {
-        maFavCharList.push_back(s);
-    }
-
-    //retrieve recent character font list
-    const css::uno::Sequence< OUString > rFavCharFontList( 
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::get() 
);
-    for (const OUString& s : rFavCharFontList)
-    {
-        maFavCharFontList.push_back(s);
-    }
-
-    // tdf#135997: make sure that the two lists are same length
-    const auto nCommonLength = std::min(maFavCharList.size(), 
maFavCharFontList.size());
-    maFavCharList.resize(nCommonLength);
-    maFavCharFontList.resize(nCommonLength);
-}
-
-static std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
-findInPair(std::u16string_view str1, const std::deque<OUString>& rContainer1,
-           std::u16string_view str2, const std::deque<OUString>& rContainer2)
-{
-    assert(rContainer1.size() == rContainer2.size());
-
-    for (auto it1 = std::find(rContainer1.begin(), rContainer1.end(), str1);
-         it1 != rContainer1.end(); it1 = std::find(std::next(it1), 
rContainer1.end(), str1))
-    {
-        auto it2 = rContainer2.begin() + (it1 - rContainer1.begin());
-        if (*it2 == str2)
-            return { it1, it2 };
-    }
-    return { rContainer1.end(), rContainer2.end() };
-}
-
-std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
-SvxCharacterMap::getRecentChar(std::u16string_view sTitle, std::u16string_view 
rFont) const
-{
-    return findInPair(sTitle, maRecentCharList, rFont, maRecentCharFontList);
-}
-
-std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
-SvxCharacterMap::getFavChar(std::u16string_view sTitle, std::u16string_view 
rFont) const
+IMPL_LINK_NOARG(SvxCharacterMap, UpdateFavHdl, void*, void)
 {
-    return findInPair(sTitle, maFavCharList, rFont, maFavCharFontList);
-}
-
-
-void SvxCharacterMap::updateRecentCharControl()
-{
-    assert(maRecentCharList.size() == maRecentCharFontList.size());
-
-    int i = 0;
-    for ( std::deque< OUString >::iterator it = maRecentCharList.begin(), it2 
= maRecentCharFontList.begin();
-        it != maRecentCharList.end() && it2 != maRecentCharFontList.end();
-        ++it, ++it2, i++)
-    {
-        m_aRecentCharView[i].SetText(*it);
-        vcl::Font rFont = m_aRecentCharView[i].GetFont();
-        rFont.SetFamilyName( *it2 );
-        m_aRecentCharView[i].SetFont(rFont);
-        m_aRecentCharView[i].Show();
-    }
-
-    for(; i < 16 ; i++)
-    {
-        m_aRecentCharView[i].SetText(OUString());
-        m_aRecentCharView[i].Hide();
-    }
-}
-
-void SvxCharacterMap::updateRecentCharacterList(const OUString& sTitle, const 
OUString& rFont)
-{
-    // if recent char to be added is already in list, remove it
-    if( const auto& [itChar, itChar2] = getRecentChar(sTitle, rFont);
-        itChar != maRecentCharList.end() &&  itChar2 != 
maRecentCharFontList.end() )
-    {
-        maRecentCharList.erase( itChar );
-        maRecentCharFontList.erase( itChar2);
-    }
-
-    if (maRecentCharList.size() == 16)
-    {
-        maRecentCharList.pop_back();
-        maRecentCharFontList.pop_back();
-    }
-
-    maRecentCharList.push_front(sTitle);
-    maRecentCharFontList.push_front(rFont);
-
-    css::uno::Sequence< OUString > aRecentCharList(maRecentCharList.size());
-    auto aRecentCharListRange = asNonConstRange(aRecentCharList);
-    css::uno::Sequence< OUString > 
aRecentCharFontList(maRecentCharFontList.size());
-    auto aRecentCharFontListRange = asNonConstRange(aRecentCharFontList);
-
-    for (size_t i = 0; i < maRecentCharList.size(); ++i)
-    {
-        aRecentCharListRange[i] = maRecentCharList[i];
-        aRecentCharFontListRange[i] = maRecentCharFontList[i];
-    }
-
-    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
-    
officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList,
 batch);
-    
officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList,
 batch);
-    batch->commit();
-
-    updateRecentCharControl();
-}
-
-
-void SvxCharacterMap::updateFavCharacterList(const OUString& sTitle, const 
OUString& rFont)
-{
-    // if Fav char to be added is already in list, remove it
-    if( const auto& [itChar, itChar2] = getFavChar(sTitle, rFont);
-        itChar != maFavCharList.end() &&  itChar2 != maFavCharFontList.end() )
-    {
-        maFavCharList.erase( itChar );
-        maFavCharFontList.erase( itChar2);
-    }
-
-    if (maFavCharList.size() == 16)
-    {
-        maFavCharList.pop_back();
-        maFavCharFontList.pop_back();
-    }
-
-    maFavCharList.push_back(sTitle);
-    maFavCharFontList.push_back(rFont);
-
-    css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
-    auto aFavCharListRange = asNonConstRange(aFavCharList);
-    css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
-    auto aFavCharFontListRange = asNonConstRange(aFavCharFontList);
-
-    for (size_t i = 0; i < maFavCharList.size(); ++i)
-    {
-        aFavCharListRange[i] = maFavCharList[i];
-        aFavCharFontListRange[i] = maFavCharFontList[i];
-    }
-
-    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
-    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList,
 batch);
-    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList,
 batch);
-    batch->commit();
-}
-
-
-void SvxCharacterMap::updateFavCharControl()
-{
-    assert(maFavCharList.size() == maFavCharFontList.size());
-
-    int i = 0;
-    for ( std::deque< OUString >::iterator it = maFavCharList.begin(), it2 = 
maFavCharFontList.begin();
-        it != maFavCharList.end() && it2 != maFavCharFontList.end();
-        ++it, ++it2, i++)
-    {
-        m_aFavCharView[i].SetText(*it);
-        vcl::Font rFont = m_aFavCharView[i].GetFont();
-        rFont.SetFamilyName( *it2 );
-        m_aFavCharView[i].SetFont(rFont);
-        m_aFavCharView[i].Show();
-    }
-
-    for(; i < 16 ; i++)
-    {
-        m_aFavCharView[i].SetText(OUString());
-        m_aFavCharView[i].Hide();
-    }
     m_xShowSet->getFavCharacterList();
     m_xSearchSet->getFavCharacterList();
     // tdf#109214 - redraw highlight of the favorite characters
     m_xShowSet->Invalidate();
 }
 
-void SvxCharacterMap::deleteFavCharacterFromList(std::u16string_view sTitle, 
std::u16string_view rFont)
-{
-    // if Fav char is found, remove it
-    if( const auto& [itChar, itChar2] = getFavChar(sTitle, rFont);
-        itChar != maFavCharList.end() &&  itChar2 != maFavCharFontList.end() )
-    {
-        maFavCharList.erase( itChar );
-        maFavCharFontList.erase( itChar2);
-    }
-
-    css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
-    auto aFavCharListRange = asNonConstRange(aFavCharList);
-    css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
-    auto aFavCharFontListRange = asNonConstRange(aFavCharFontList);
-
-    for (size_t i = 0; i < maFavCharList.size(); ++i)
-    {
-        aFavCharListRange[i] = maFavCharList[i];
-        aFavCharFontListRange[i] = maFavCharFontList[i];
-    }
-
-    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
-    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList,
 batch);
-    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList,
 batch);
-    batch->commit();
-}
-
 void SvxCharacterMap::init()
 {
     aFont = m_xVirDev->GetFont();
@@ -549,25 +259,10 @@ void SvxCharacterMap::init()
         m_xOKBtn->set_sensitive(true);
     }
 
-    getRecentCharacterList();
-    updateRecentCharControl();
-
-    getFavCharacterList();
-    updateFavCharControl();
-
-    bool bHasInsert = m_xFrame.is();
-
-    for(int i = 0; i < 16; i++)
-    {
-        m_aRecentCharView[i].SetHasInsert(bHasInsert);
-        m_aRecentCharView[i].setMouseClickHdl(LINK(this,SvxCharacterMap, 
CharClickHdl));
-        m_aRecentCharView[i].setClearClickHdl(LINK(this,SvxCharacterMap, 
RecentClearClickHdl));
-        m_aRecentCharView[i].setClearAllClickHdl(LINK(this,SvxCharacterMap, 
RecentClearAllClickHdl));
-        m_aFavCharView[i].SetHasInsert(bHasInsert);
-        m_aFavCharView[i].setMouseClickHdl(LINK(this,SvxCharacterMap, 
CharClickHdl));
-        m_aFavCharView[i].setClearClickHdl(LINK(this,SvxCharacterMap, 
FavClearClickHdl));
-        m_aFavCharView[i].setClearAllClickHdl(LINK(this,SvxCharacterMap, 
FavClearAllClickHdl));
-    }
+    m_aCharmapContents.init(m_xFrame.is(),
+                            LINK(this, SvxCharacterMap, CharClickHdl),
+                            LINK(this, SvxCharacterMap, UpdateFavHdl),
+                            Link<void*, void>());
 
     setCharName(90);
 
@@ -575,13 +270,6 @@ void SvxCharacterMap::init()
     m_xSearchText->connect_changed(LINK(this, SvxCharacterMap, 
SearchUpdateHdl));
 }
 
-bool SvxCharacterMap::isFavChar(std::u16string_view sTitle, 
std::u16string_view rFont)
-{
-    const auto& [itChar, itFont] = getFavChar(sTitle, rFont);
-    return itChar != maFavCharList.end() && itFont != maFavCharFontList.end();
-}
-
-
 void SvxCharacterMap::setFavButtonState(std::u16string_view sTitle, 
std::u16string_view rFont)
 {
     if(sTitle.empty() || rFont.empty())
@@ -592,16 +280,14 @@ void 
SvxCharacterMap::setFavButtonState(std::u16string_view sTitle, std::u16stri
     else
         m_xFavouritesBtn->set_sensitive(true);
 
-    if (isFavChar(sTitle, rFont))
+    if (m_aCharmapContents.isFavChar(sTitle, rFont))
     {
         m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_REMOVE_FAVORITES));
     }
     else
     {
-        if(maFavCharList.size() == 16)
-        {
+        if (m_aCharmapContents.FavCharListIsFull())
             m_xFavouritesBtn->set_sensitive(false);
-        }
 
         m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_ADD_FAVORITES));
     }
@@ -656,7 +342,7 @@ void SvxCharacterMap::insertCharToDoc(const OUString& 
sGlyph)
         };
         comphelper::dispatchCommand(".uno:InsertSymbol", m_xFrame, aArgs);
 
-        updateRecentCharacterList(sGlyph, aFont.GetFamilyName());
+        m_aCharmapContents.updateRecentCharacterList(sGlyph, 
aFont.GetFamilyName());
 
     } else {
         sal_UCS4 cChar = 
sGlyph.iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
@@ -783,70 +469,6 @@ IMPL_LINK_NOARG(SvxCharacterMap, SubsetSelectHdl, 
weld::ComboBox&, void)
     }
 }
 
-IMPL_LINK(SvxCharacterMap, RecentClearClickHdl, SvxCharView*, rView, void)
-{
-    const OUString& sTitle = rView->GetText();
-    OUString sFont = rView->GetFont().GetFamilyName();
-
-    // if recent char to be added is already in list, remove it
-    if( const auto& [itChar, itChar2] = getRecentChar(sTitle, sFont);
-        itChar != maRecentCharList.end() &&  itChar2 != 
maRecentCharFontList.end() )
-    {
-        maRecentCharList.erase( itChar );
-        maRecentCharFontList.erase( itChar2);
-    }
-
-    css::uno::Sequence< OUString > aRecentCharList(maRecentCharList.size());
-    auto aRecentCharListRange = asNonConstRange(aRecentCharList);
-    css::uno::Sequence< OUString > 
aRecentCharFontList(maRecentCharFontList.size());
-    auto aRecentCharFontListRange = asNonConstRange(aRecentCharFontList);
-
-    for (size_t i = 0; i < maRecentCharList.size(); ++i)
-    {
-        aRecentCharListRange[i] = maRecentCharList[i];
-        aRecentCharFontListRange[i] = maRecentCharFontList[i];
-    }
-
-    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
-    
officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList,
 batch);
-    
officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList,
 batch);
-    batch->commit();
-
-    updateRecentCharControl();
-}
-
-IMPL_LINK_NOARG(SvxCharacterMap, RecentClearAllClickHdl, SvxCharView*, void)
-{
-    maRecentCharList.clear();
-    maRecentCharFontList.clear();
-
-    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
-    officecfg::Office::Common::RecentCharacters::RecentCharacterList::set({ }, 
batch);
-    
officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set({ }, 
batch);
-    batch->commit();
-
-    updateRecentCharControl();
-}
-
-IMPL_LINK(SvxCharacterMap, FavClearClickHdl, SvxCharView*, rView, void)
-{
-    deleteFavCharacterFromList(rView->GetText(), 
rView->GetFont().GetFamilyName());
-    updateFavCharControl();
-}
-
-IMPL_LINK_NOARG(SvxCharacterMap, FavClearAllClickHdl, SvxCharView*, void)
-{
-    maFavCharList.clear();
-    maFavCharFontList.clear();
-
-    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
-    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set({ }, 
batch);
-    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set({ 
}, batch);
-    batch->commit();
-
-    updateFavCharControl();
-}
-
 IMPL_LINK_NOARG(SvxCharacterMap, SearchFieldGetFocusHdl, weld::Widget&, void)
 {
     m_xOKBtn->set_sensitive(false);
@@ -955,7 +577,7 @@ IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, 
weld::Button&, void)
     insertCharToDoc(sChar);
     // Need to update recent character list, when OK button does not insert
     if(!m_xFrame.is())
-        updateRecentCharacterList(sChar, aFont.GetFamilyName());
+        m_aCharmapContents.updateRecentCharacterList(sChar, 
aFont.GetFamilyName());
     m_xDialog->response(RET_OK);
 }
 
@@ -963,23 +585,23 @@ IMPL_LINK_NOARG(SvxCharacterMap, FavSelectHdl, 
weld::Button&, void)
 {
     if 
(m_xFavouritesBtn->get_label().match(CuiResId(RID_CUISTR_ADD_FAVORITES)))
     {
-        updateFavCharacterList(m_aShowChar.GetText(), 
m_aShowChar.GetFont().GetFamilyName());
+        m_aCharmapContents.updateFavCharacterList(m_aShowChar.GetText(), 
m_aShowChar.GetFont().GetFamilyName());
         setFavButtonState(m_aShowChar.GetText(), 
m_aShowChar.GetFont().GetFamilyName());
     }
     else
     {
-        deleteFavCharacterFromList(m_aShowChar.GetText(), 
m_aShowChar.GetFont().GetFamilyName());
+        m_aCharmapContents.deleteFavCharacterFromList(m_aShowChar.GetText(), 
m_aShowChar.GetFont().GetFamilyName());
         m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_ADD_FAVORITES));
         m_xFavouritesBtn->set_sensitive(false);
     }
 
-    updateFavCharControl();
+    m_aCharmapContents.updateFavCharControl();
 }
 
 IMPL_LINK_NOARG(SvxCharacterMap, FavClickHdl, SvxShowCharSet*, void)
 {
-    getFavCharacterList();
-    updateFavCharControl();
+    m_aCharmapContents.getFavCharacterList();
+    m_aCharmapContents.updateFavCharControl();
 }
 
 IMPL_LINK_NOARG(SvxCharacterMap, CharHighlightHdl, SvxShowCharSet*, void)
diff --git a/include/cui/cuicharmap.hxx b/include/cui/cuicharmap.hxx
index 431ce6dc30f5..8b85b1883ea5 100644
--- a/include/cui/cuicharmap.hxx
+++ b/include/cui/cuicharmap.hxx
@@ -83,13 +83,9 @@ private:
     std::unique_ptr<const SubsetMap> pSubsetMap;
     bool isSearchMode;
     css::uno::Reference<css::frame::XFrame> m_xFrame;
-    std::deque<OUString> maRecentCharList;
-    std::deque<OUString> maRecentCharFontList;
-    std::deque<OUString> maFavCharList;
-    std::deque<OUString> maFavCharFontList;
 
-    SvxCharView m_aRecentCharView[16];
-    SvxCharView m_aFavCharView[16];
+    SfxCharmapContainer m_aCharmapContents;
+
     SvxShowText m_aShowChar;
 
     std::unique_ptr<weld::Button> m_xOKBtn;
@@ -102,11 +98,7 @@ private:
     std::unique_ptr<weld::Entry> m_xDecimalCodeText;
     std::unique_ptr<weld::Button> m_xFavouritesBtn;
     std::unique_ptr<weld::Label> m_xCharName;
-    std::unique_ptr<weld::Widget> m_xRecentGrid;
-    std::unique_ptr<weld::Widget> m_xFavGrid;
     std::unique_ptr<weld::CustomWeld> m_xShowChar;
-    std::unique_ptr<weld::CustomWeld> m_xRecentCharView[16];
-    std::unique_ptr<weld::CustomWeld> m_xFavCharView[16];
     std::unique_ptr<SvxShowCharSet> m_xShowSet;
     std::unique_ptr<weld::CustomWeld> m_xShowSetArea;
     std::unique_ptr<SvxSearchCharSet> m_xSearchSet;
@@ -135,14 +127,11 @@ private:
     DECL_DLLPRIVATE_LINK(DecimalCodeChangeHdl, weld::Entry&, void);
     DECL_DLLPRIVATE_LINK(HexCodeChangeHdl, weld::Entry&, void);
     DECL_DLLPRIVATE_LINK(CharClickHdl, SvxCharView*, void);
-    DECL_DLLPRIVATE_LINK(RecentClearClickHdl, SvxCharView*, void);
-    DECL_DLLPRIVATE_LINK(FavClearClickHdl, SvxCharView*, void);
-    DECL_DLLPRIVATE_LINK(RecentClearAllClickHdl, SvxCharView*, void);
-    DECL_DLLPRIVATE_LINK(FavClearAllClickHdl, SvxCharView*, void);
     DECL_DLLPRIVATE_LINK(InsertClickHdl, weld::Button&, void);
     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);
 
     static void fillAllSubsets(weld::ComboBox& rListBox);
     void selectCharByCode(Radix radix);
@@ -164,30 +153,13 @@ public:
     void SetChar(sal_UCS4);
     sal_UCS4 GetChar() const;
 
-    void getRecentCharacterList(); //gets both recent char and recent char 
font list
-    void updateRecentCharacterList(const OUString& rChar, const OUString& 
rFont);
-
-    void getFavCharacterList(); //gets both Fav char and Fav char font list
-    void updateFavCharacterList(const OUString& rChar, const OUString& rFont);
-    void deleteFavCharacterFromList(std::u16string_view rChar, 
std::u16string_view rFont);
-    bool isFavChar(std::u16string_view sTitle, std::u16string_view rFont);
-
-    void updateRecentCharControl();
     void insertCharToDoc(const OUString& sChar);
 
-    void updateFavCharControl();
     void setFavButtonState(std::u16string_view sTitle, std::u16string_view 
rFont);
 
     void setCharName(sal_UCS4 nDecimalValue);
 
     void toggleSearchView(bool state);
-
-private:
-    std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
-    getRecentChar(std::u16string_view sTitle, std::u16string_view rFont) const;
-
-    std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
-    getFavChar(std::u16string_view sTitle, std::u16string_view rFont) const;
 };
 
 #endif
diff --git a/include/sfx2/charwin.hxx b/include/sfx2/charwin.hxx
index a2beabc5b2df..515aa64a4acb 100644
--- a/include/sfx2/charwin.hxx
+++ b/include/sfx2/charwin.hxx
@@ -24,6 +24,7 @@
 #include <vcl/customweld.hxx>
 #include <vcl/virdev.hxx>
 #include <vcl/weld.hxx>
+#include <deque>
 
 class SFX2_DLLPUBLIC SvxCharView final : public weld::CustomWidgetController
 {
@@ -67,6 +68,63 @@ public:
     void ContextMenuSelect(std::u16string_view rIdent);
 };
 
+class SFX2_DLLPUBLIC SfxCharmapContainer
+{
+    std::deque<OUString>   m_aRecentCharList;
+    std::deque<OUString>   m_aRecentCharFontList;
+    std::deque<OUString>   m_aFavCharList;
+    std::deque<OUString>   m_aFavCharFontList;
+
+    SvxCharView m_aRecentCharView[16];
+    SvxCharView m_aFavCharView[16];
+    std::unique_ptr<weld::CustomWeld> m_xRecentCharView[16];
+    std::unique_ptr<weld::CustomWeld> m_xFavCharView[16];
+
+    std::unique_ptr<weld::Widget> m_xRecentGrid;
+    std::unique_ptr<weld::Widget> m_xFavGrid;
+
+    Link<SvxCharView*, void> m_aMouseClickHdl;
+    Link<void*, void> m_aUpdateFavHdl;
+    Link<void*, void> m_aUpdateRecentHdl;
+
+    DECL_DLLPRIVATE_LINK(CharClickHdl, SvxCharView*, void);
+    DECL_DLLPRIVATE_LINK(RecentClearClickHdl, SvxCharView*, void);
+    DECL_DLLPRIVATE_LINK(FavClearClickHdl, SvxCharView*, void);
+    DECL_DLLPRIVATE_LINK(RecentClearAllClickHdl, SvxCharView*, void);
+    DECL_DLLPRIVATE_LINK(FavClearAllClickHdl, SvxCharView*, void);
+
+public:
+    SfxCharmapContainer(weld::Builder& rBuilder, const VclPtr<VirtualDevice>& 
rVirDev);
+
+    void            init(bool bHasInsert, const Link<SvxCharView*,void> 
&rMouseClickHdl,
+                         const Link<void*,void> &rUpdateFavHdl,
+                         const Link<void*,void> &rUpdateRecentHdl);
+
+    void            getFavCharacterList();
+    void            updateFavCharControl();
+
+    void            getRecentCharacterList(); //gets both recent char and 
recent char font list
+    void            updateRecentCharControl();
+
+    void            updateRecentCharacterList(const OUString& sTitle, const 
OUString& rFont);
+    void            updateFavCharacterList(const OUString& sTitle, const 
OUString& rFont);
+    void            deleteFavCharacterFromList(std::u16string_view sTitle, 
std::u16string_view rFont);
+
+    bool            isFavChar(std::u16string_view sTitle, std::u16string_view 
rFont);
+    bool            hasRecentChars() const;
+
+    bool            FavCharListIsFull() const;
+
+    void            GrabFocusToFirstFavorite();
+
+private:
+    std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
+    getRecentChar(std::u16string_view sTitle, std::u16string_view rFont) const;
+
+    std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
+    getFavChar(std::u16string_view sTitle, std::u16string_view rFont) const;
+};
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sfx2/inc/charmapcontrol.hxx b/sfx2/inc/charmapcontrol.hxx
index e2c1e1e07349..c6045154583e 100644
--- a/sfx2/inc/charmapcontrol.hxx
+++ b/sfx2/inc/charmapcontrol.hxx
@@ -41,26 +41,14 @@ private:
 
     ScopedVclPtr<VirtualDevice> m_xVirDev;
 
-    std::deque<OUString>   m_aRecentCharList;
-    std::deque<OUString>   m_aRecentCharFontList;
-    std::deque<OUString>   m_aFavCharList;
-    std::deque<OUString>   m_aFavCharFontList;
+    SfxCharmapContainer m_aCharmapContents;
 
-    SvxCharView m_aRecentCharView[16];
-    SvxCharView m_aFavCharView[16];
     std::unique_ptr<weld::Label> m_xRecentLabel;
     std::unique_ptr<weld::Button> m_xDlgBtn;
-    std::unique_ptr<weld::CustomWeld> m_xRecentCharView[16];
-    std::unique_ptr<weld::CustomWeld> m_xFavCharView[16];
 
     DECL_LINK(CharClickHdl, SvxCharView*, void);
     DECL_LINK(OpenDlgHdl, weld::Button&, void);
-
-    void            getFavCharacterList();
-    void            updateFavCharControl();
-
-    void            getRecentCharacterList(); //gets both recent char and 
recent char font list
-    void            updateRecentCharControl();
+    DECL_LINK(UpdateRecentHdl, void*, void);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/control/charmapcontrol.cxx 
b/sfx2/source/control/charmapcontrol.cxx
index a79da745be26..359b81c49330 100644
--- a/sfx2/source/control/charmapcontrol.cxx
+++ b/sfx2/source/control/charmapcontrol.cxx
@@ -27,97 +27,127 @@
 
 using namespace css;
 
+SfxCharmapContainer::SfxCharmapContainer(weld::Builder& rBuilder, const 
VclPtr<VirtualDevice>& rVirDev)
+    : m_aRecentCharView{SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev),
+                        SvxCharView(rVirDev)}
+    , m_aFavCharView{SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev),
+                     SvxCharView(rVirDev)}
+    , m_xRecentCharView{std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar1", m_aRecentCharView[0]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar2", m_aRecentCharView[1]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar3", m_aRecentCharView[2]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar4", m_aRecentCharView[3]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar5", m_aRecentCharView[4]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar6", m_aRecentCharView[5]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar7", m_aRecentCharView[6]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar8", m_aRecentCharView[7]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar9", m_aRecentCharView[8]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar10", m_aRecentCharView[9]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar11", m_aRecentCharView[10]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar12", m_aRecentCharView[11]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar13", m_aRecentCharView[12]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar14", m_aRecentCharView[13]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar15", m_aRecentCharView[14]),
+                        std::make_unique<weld::CustomWeld>(rBuilder, 
"viewchar16", m_aRecentCharView[15])}
+    , m_xFavCharView{std::make_unique<weld::CustomWeld>(rBuilder, "favchar1", 
m_aFavCharView[0]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar2", 
m_aFavCharView[1]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar3", 
m_aFavCharView[2]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar4", 
m_aFavCharView[3]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar5", 
m_aFavCharView[4]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar6", 
m_aFavCharView[5]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar7", 
m_aFavCharView[6]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar8", 
m_aFavCharView[7]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar9", 
m_aFavCharView[8]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar10", 
m_aFavCharView[9]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar11", 
m_aFavCharView[10]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar12", 
m_aFavCharView[11]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar13", 
m_aFavCharView[12]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar14", 
m_aFavCharView[13]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar15", 
m_aFavCharView[14]),
+                     std::make_unique<weld::CustomWeld>(rBuilder, "favchar16", 
m_aFavCharView[15])}
+    , m_xRecentGrid(rBuilder.weld_widget("viewgrid"))
+    , m_xFavGrid(rBuilder.weld_widget("favgrid"))
+{
+    //so things don't jump around if all the children are hidden
+    m_xRecentGrid->set_size_request(-1, 
m_aRecentCharView[0].get_preferred_size().Height());
+    m_xFavGrid->set_size_request(-1, 
m_aFavCharView[0].get_preferred_size().Height());
+}
+
+void SfxCharmapContainer::init(bool bHasInsert, const Link<SvxCharView*,void> 
&rMouseClickHdl,
+                               const Link<void*, void>& rUpdateFavHdl,
+                               const Link<void*, void>& rUpdateRecentHdl)
+{
+    m_aUpdateFavHdl = rUpdateFavHdl;
+    m_aUpdateRecentHdl = rUpdateRecentHdl;
+
+    getRecentCharacterList();
+    updateRecentCharControl();
+    getFavCharacterList();
+    updateFavCharControl();
+
+    for(int i = 0; i < 16; i++)
+    {
+        m_aRecentCharView[i].SetHasInsert(bHasInsert);
+        m_aRecentCharView[i].setMouseClickHdl(rMouseClickHdl);
+        m_aRecentCharView[i].setClearClickHdl(LINK(this, SfxCharmapContainer, 
RecentClearClickHdl));
+        m_aRecentCharView[i].setClearAllClickHdl(LINK(this, 
SfxCharmapContainer, RecentClearAllClickHdl));
+        m_aFavCharView[i].SetHasInsert(bHasInsert);
+        m_aFavCharView[i].setMouseClickHdl(rMouseClickHdl);
+        m_aFavCharView[i].setClearClickHdl(LINK(this, SfxCharmapContainer, 
FavClearClickHdl));
+        m_aFavCharView[i].setClearAllClickHdl(LINK(this, SfxCharmapContainer, 
FavClearAllClickHdl));
+    }
+}
+
 SfxCharmapCtrl::SfxCharmapCtrl(CharmapPopup* pControl, weld::Widget* pParent)
     : WeldToolbarPopup(pControl->getFrameInterface(), pParent, 
"sfx/ui/charmapcontrol.ui", "charmapctrl")
     , m_xControl(pControl)
     , m_xVirDev(VclPtr<VirtualDevice>::Create())
-    , m_aRecentCharView{SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev),
-                        SvxCharView(m_xVirDev)}
-    , m_aFavCharView{SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev),
-                     SvxCharView(m_xVirDev)}
+    , m_aCharmapContents(*m_xBuilder, m_xVirDev)
     , m_xRecentLabel(m_xBuilder->weld_label("label2"))
     , m_xDlgBtn(m_xBuilder->weld_button("specialchardlg"))
-    , m_xRecentCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar1", m_aRecentCharView[0]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar2", m_aRecentCharView[1]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar3", m_aRecentCharView[2]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar4", m_aRecentCharView[3]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar5", m_aRecentCharView[4]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar6", m_aRecentCharView[5]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar7", m_aRecentCharView[6]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar8", m_aRecentCharView[7]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar9", m_aRecentCharView[8]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar10", m_aRecentCharView[9]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar11", m_aRecentCharView[10]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar12", m_aRecentCharView[11]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar13", m_aRecentCharView[12]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar14", m_aRecentCharView[13]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar15", m_aRecentCharView[14]),
-                        std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"viewchar16", m_aRecentCharView[15])}
-    , m_xFavCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar1", m_aFavCharView[0]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar2", m_aFavCharView[1]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar3", m_aFavCharView[2]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar4", m_aFavCharView[3]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar5", m_aFavCharView[4]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar6", m_aFavCharView[5]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar7", m_aFavCharView[6]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar8", m_aFavCharView[7]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar9", m_aFavCharView[8]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar10", m_aFavCharView[9]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar11", m_aFavCharView[10]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar12", m_aFavCharView[11]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar13", m_aFavCharView[12]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar14", m_aFavCharView[13]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar15", m_aFavCharView[14]),
-                     std::make_unique<weld::CustomWeld>(*m_xBuilder, 
"favchar16", m_aFavCharView[15])}
 {
-    for(int i = 0; i < 16; i++)
-    {
-        m_aRecentCharView[i].setMouseClickHdl(LINK(this,SfxCharmapCtrl, 
CharClickHdl));
-        m_aFavCharView[i].setMouseClickHdl(LINK(this,SfxCharmapCtrl, 
CharClickHdl));
-    }
+    m_aCharmapContents.init(false, LINK(this, SfxCharmapCtrl, CharClickHdl),
+                            Link<void*,void>(), LINK(this, SfxCharmapCtrl, 
UpdateRecentHdl));
 
     m_xDlgBtn->connect_clicked(LINK(this, SfxCharmapCtrl, OpenDlgHdl));
-
-    getRecentCharacterList();
-    updateRecentCharControl();
-    getFavCharacterList();
-    updateFavCharControl();
 }
 
 SfxCharmapCtrl::~SfxCharmapCtrl()
 {
 }
 
-void SfxCharmapCtrl::getFavCharacterList()
+void SfxCharmapContainer::getFavCharacterList()
 {
+    m_aFavCharList.clear();
+    m_aFavCharFontList.clear();
+
     //retrieve recent character list
     const css::uno::Sequence< OUString > rFavCharList( 
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::get() );
     m_aFavCharList.insert( m_aFavCharList.end(), rFavCharList.begin(), 
rFavCharList.end() );
@@ -132,7 +162,7 @@ void SfxCharmapCtrl::getFavCharacterList()
     m_aFavCharFontList.resize(nCommonLength);
 }
 
-void SfxCharmapCtrl::updateFavCharControl()
+void SfxCharmapContainer::updateFavCharControl()
 {
     assert(m_aFavCharList.size() == m_aFavCharFontList.size());
 
@@ -153,10 +183,15 @@ void SfxCharmapCtrl::updateFavCharControl()
         m_aFavCharView[i].SetText(OUString());
         m_aFavCharView[i].Hide();
     }
+
+    m_aUpdateFavHdl.Call(nullptr);
 }
 
-void SfxCharmapCtrl::getRecentCharacterList()
+void SfxCharmapContainer::getRecentCharacterList()
 {
+    m_aRecentCharList.clear();
+    m_aRecentCharFontList.clear();
+
     //retrieve recent character list
     const css::uno::Sequence< OUString > rRecentCharList( 
officecfg::Office::Common::RecentCharacters::RecentCharacterList::get() );
     m_aRecentCharList.insert( m_aRecentCharList.end(), 
rRecentCharList.begin(), rRecentCharList.end() );
@@ -171,9 +206,66 @@ void SfxCharmapCtrl::getRecentCharacterList()
     m_aRecentCharFontList.resize(nCommonLength);
 }
 
-void SfxCharmapCtrl::updateRecentCharControl()
+IMPL_LINK(SfxCharmapCtrl, CharClickHdl, SvxCharView*, pView, void)
+{
+    m_xControl->EndPopupMode();
+
+    pView->InsertCharToDoc();
+}
+
+IMPL_LINK_NOARG(SfxCharmapCtrl, OpenDlgHdl, weld::Button&, void)
+{
+    m_xControl->EndPopupMode();
+
+    if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+    {
+        uno::Reference<frame::XFrame> xFrame = 
pViewFrm->GetFrame().GetFrameInterface();
+        comphelper::dispatchCommand(".uno:InsertSymbol", xFrame, {});
+    }
+}
+
+void SfxCharmapCtrl::GrabFocus()
+{
+    m_aCharmapContents.GrabFocusToFirstFavorite();
+}
+
+void SfxCharmapContainer::GrabFocusToFirstFavorite()
+{
+    m_aFavCharView[0].GrabFocus();
+}
+
+static std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
+findInPair(std::u16string_view str1, const std::deque<OUString>& rContainer1,
+           std::u16string_view str2, const std::deque<OUString>& rContainer2)
+{
+    assert(rContainer1.size() == rContainer2.size());
+
+    for (auto it1 = std::find(rContainer1.begin(), rContainer1.end(), str1);
+         it1 != rContainer1.end(); it1 = std::find(std::next(it1), 
rContainer1.end(), str1))
+    {
+        auto it2 = rContainer2.begin() + (it1 - rContainer1.begin());
+        if (*it2 == str2)
+            return { it1, it2 };
+    }
+    return { rContainer1.end(), rContainer2.end() };
+}
+
+std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
+SfxCharmapContainer::getRecentChar(std::u16string_view sTitle, 
std::u16string_view rFont) const
+{
+    return findInPair(sTitle, m_aRecentCharList, rFont, m_aRecentCharFontList);
+}
+
+std::pair<std::deque<OUString>::const_iterator, 
std::deque<OUString>::const_iterator>
+SfxCharmapContainer::getFavChar(std::u16string_view sTitle, 
std::u16string_view rFont) const
+{
+    return findInPair(sTitle, m_aFavCharList, rFont, m_aFavCharFontList);
+}
+
+void SfxCharmapContainer::updateRecentCharControl()
 {
     assert(m_aRecentCharList.size() == m_aRecentCharFontList.size());
+
     int i = 0;
     for ( std::deque< OUString >::iterator it = m_aRecentCharList.begin(), it2 
= m_aRecentCharFontList.begin();
         it != m_aRecentCharList.end() && it2 != m_aRecentCharFontList.end();
@@ -192,31 +284,199 @@ void SfxCharmapCtrl::updateRecentCharControl()
         m_aRecentCharView[i].Hide();
     }
 
-    //checking if the characters are recently used or no
-    m_xRecentLabel->set_label(m_aRecentCharList.size() > 0 ? 
SfxResId(STR_RECENT) : SfxResId(STR_NORECENT));
+    m_aUpdateRecentHdl.Call(nullptr);
 }
 
-IMPL_LINK(SfxCharmapCtrl, CharClickHdl, SvxCharView*, pView, void)
+void SfxCharmapContainer::updateRecentCharacterList(const OUString& sTitle, 
const OUString& rFont)
 {
-    m_xControl->EndPopupMode();
+    // if recent char to be added is already in list, remove it
+    if( const auto& [itChar, itChar2] = getRecentChar(sTitle, rFont);
+        itChar != m_aRecentCharList.end() &&  itChar2 != 
m_aRecentCharFontList.end() )
+    {
+        m_aRecentCharList.erase( itChar );
+        m_aRecentCharFontList.erase( itChar2);
+    }
 
-    pView->InsertCharToDoc();
+    if (m_aRecentCharList.size() == 16)
+    {
+        m_aRecentCharList.pop_back();
+        m_aRecentCharFontList.pop_back();
+    }
+
+    m_aRecentCharList.push_front(sTitle);
+    m_aRecentCharFontList.push_front(rFont);
+
+    css::uno::Sequence< OUString > aRecentCharList(m_aRecentCharList.size());
+    auto aRecentCharListRange = asNonConstRange(aRecentCharList);
+    css::uno::Sequence< OUString > 
aRecentCharFontList(m_aRecentCharFontList.size());
+    auto aRecentCharFontListRange = asNonConstRange(aRecentCharFontList);
+
+    for (size_t i = 0; i < m_aRecentCharList.size(); ++i)
+    {
+        aRecentCharListRange[i] = m_aRecentCharList[i];
+        aRecentCharFontListRange[i] = m_aRecentCharFontList[i];
+    }
+
+    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
+    
officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList,
 batch);
+    
officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList,
 batch);
+    batch->commit();
+
+    updateRecentCharControl();
 }
 
-IMPL_LINK_NOARG(SfxCharmapCtrl, OpenDlgHdl, weld::Button&, void)
+void SfxCharmapContainer::updateFavCharacterList(const OUString& sTitle, const 
OUString& rFont)
 {
-    m_xControl->EndPopupMode();
+    // if Fav char to be added is already in list, remove it
+    if( const auto& [itChar, itChar2] = getFavChar(sTitle, rFont);
+        itChar != m_aFavCharList.end() &&  itChar2 != m_aFavCharFontList.end() 
)
+    {
+        m_aFavCharList.erase( itChar );
+        m_aFavCharFontList.erase( itChar2);
+    }
 
-    if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+    if (m_aFavCharList.size() == 16)
     {
-        uno::Reference<frame::XFrame> xFrame = 
pViewFrm->GetFrame().GetFrameInterface();
-        comphelper::dispatchCommand(".uno:InsertSymbol", xFrame, {});
+        m_aFavCharList.pop_back();
+        m_aFavCharFontList.pop_back();
+    }
+
+    m_aFavCharList.push_back(sTitle);
+    m_aFavCharFontList.push_back(rFont);
+
+    css::uno::Sequence< OUString > aFavCharList(m_aFavCharList.size());
+    auto aFavCharListRange = asNonConstRange(aFavCharList);
+    css::uno::Sequence< OUString > aFavCharFontList(m_aFavCharFontList.size());
+    auto aFavCharFontListRange = asNonConstRange(aFavCharFontList);
+
+    for (size_t i = 0; i < m_aFavCharList.size(); ++i)
+    {
+        aFavCharListRange[i] = m_aFavCharList[i];
+        aFavCharFontListRange[i] = m_aFavCharFontList[i];
     }
+
+    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
+    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList,
 batch);
+    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList,
 batch);
+    batch->commit();
 }
 
-void SfxCharmapCtrl::GrabFocus()
+void SfxCharmapContainer::deleteFavCharacterFromList(std::u16string_view 
sTitle, std::u16string_view rFont)
 {
-    m_aFavCharView[0].GrabFocus();
+    // if Fav char is found, remove it
+    if( const auto& [itChar, itChar2] = getFavChar(sTitle, rFont);
+        itChar != m_aFavCharList.end() &&  itChar2 != m_aFavCharFontList.end() 
)
+    {
+        m_aFavCharList.erase( itChar );
+        m_aFavCharFontList.erase( itChar2);
+    }
+
+    css::uno::Sequence< OUString > aFavCharList(m_aFavCharList.size());
+    auto aFavCharListRange = asNonConstRange(aFavCharList);
+    css::uno::Sequence< OUString > aFavCharFontList(m_aFavCharFontList.size());
+    auto aFavCharFontListRange = asNonConstRange(aFavCharFontList);
+
+    for (size_t i = 0; i < m_aFavCharList.size(); ++i)
+    {
+        aFavCharListRange[i] = m_aFavCharList[i];
+        aFavCharFontListRange[i] = m_aFavCharFontList[i];
+    }
+
+    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
+    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList,
 batch);
+    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList,
 batch);
+    batch->commit();
+}
+
+bool SfxCharmapContainer::isFavChar(std::u16string_view sTitle, 
std::u16string_view rFont)
+{
+    const auto& [itChar, itFont] = getFavChar(sTitle, rFont);
+    return itChar != m_aFavCharList.end() && itFont != 
m_aFavCharFontList.end();
+}
+
+IMPL_LINK(SfxCharmapContainer, CharClickHdl, SvxCharView*, pView, void)
+{
+    m_aMouseClickHdl.Call(pView);
+}
+
+IMPL_LINK(SfxCharmapContainer, RecentClearClickHdl, SvxCharView*, rView, void)
+{
+    const OUString& sTitle = rView->GetText();
+    OUString sFont = rView->GetFont().GetFamilyName();
+
+    // if recent char to be added is already in list, remove it
+    if( const auto& [itChar, itChar2] = getRecentChar(sTitle, sFont);
+        itChar != m_aRecentCharList.end() &&  itChar2 != 
m_aRecentCharFontList.end() )
+    {
+        m_aRecentCharList.erase( itChar );
+        m_aRecentCharFontList.erase( itChar2);
+    }
+
+    css::uno::Sequence< OUString > aRecentCharList(m_aRecentCharList.size());
+    auto aRecentCharListRange = asNonConstRange(aRecentCharList);
+    css::uno::Sequence< OUString > 
aRecentCharFontList(m_aRecentCharFontList.size());
+    auto aRecentCharFontListRange = asNonConstRange(aRecentCharFontList);
+
+    for (size_t i = 0; i < m_aRecentCharList.size(); ++i)
+    {
+        aRecentCharListRange[i] = m_aRecentCharList[i];
+        aRecentCharFontListRange[i] = m_aRecentCharFontList[i];
+    }
+
+    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
+    
officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList,
 batch);
+    
officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList,
 batch);
+    batch->commit();
+
+    updateRecentCharControl();
+}
+
+IMPL_LINK_NOARG(SfxCharmapContainer, RecentClearAllClickHdl, SvxCharView*, 
void)
+{
+    m_aRecentCharList.clear();
+    m_aRecentCharFontList.clear();
+
+    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
+    officecfg::Office::Common::RecentCharacters::RecentCharacterList::set({ }, 
batch);
+    
officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set({ }, 
batch);
+    batch->commit();
+
+    updateRecentCharControl();
+}
+
+IMPL_LINK(SfxCharmapContainer, FavClearClickHdl, SvxCharView*, rView, void)
+{
+    deleteFavCharacterFromList(rView->GetText(), 
rView->GetFont().GetFamilyName());
+    updateFavCharControl();
+}
+
+IMPL_LINK_NOARG(SfxCharmapContainer, FavClearAllClickHdl, SvxCharView*, void)
+{
+    m_aFavCharList.clear();
+    m_aFavCharFontList.clear();
+
+    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
+    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set({ }, 
batch);
+    
officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set({ 
}, batch);
+    batch->commit();
+
+    updateFavCharControl();
+}
+
+bool SfxCharmapContainer::FavCharListIsFull() const
+{
+    return m_aFavCharList.size() == 16;
+}
+
+bool SfxCharmapContainer::hasRecentChars() const
+{
+    return !m_aRecentCharList.empty();
+}
+
+IMPL_LINK_NOARG(SfxCharmapCtrl, UpdateRecentHdl, void*, void)
+{
+    //checking if the characters are recently used or no
+    m_xRecentLabel->set_label(m_aCharmapContents.hasRecentChars() ? 
SfxResId(STR_RECENT) : SfxResId(STR_NORECENT));
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/uiconfig/ui/charmapcontrol.ui 
b/sfx2/uiconfig/ui/charmapcontrol.ui
index f1d0128b7f7f..28a080a88433 100644
--- a/sfx2/uiconfig/ui/charmapcontrol.ui
+++ b/sfx2/uiconfig/ui/charmapcontrol.ui
@@ -27,7 +27,7 @@
         </child>
         <child>
           <!-- n-columns=1 n-rows=1 -->
-          <object class="GtkGrid" id="grid1">
+          <object class="GtkGrid" id="favgrid">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="halign">start</property>
@@ -268,7 +268,7 @@
         </child>
         <child>
           <!-- n-columns=1 n-rows=1 -->
-          <object class="GtkGrid" id="grid2">
+          <object class="GtkGrid" id="viewgrid">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="halign">start</property>

Reply via email to