GSoC: Glyph View and Recent Characters Control in Special Characters dialog

Change-Id: Ia55f3fefe7c14327cff2e996ab0038dc52f9b017
Reviewed-on: https://gerrit.libreoffice.org/37496
Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
Tested-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index 2b9663a..4f1a89d 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -91,6 +91,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
    cui/source/dialogs/about \
    cui/source/dialogs/colorpicker \
    cui/source/dialogs/cuicharmap \
    cui/source/dialogs/charwin \
    cui/source/dialogs/cuifmsearch \
    cui/source/dialogs/cuigaldlg \
    cui/source/dialogs/cuigrfflt \
diff --git a/cui/source/dialogs/charwin.cxx b/cui/source/dialogs/charwin.cxx
new file mode 100644
index 0000000..5f9a7fa
--- /dev/null
+++ b/cui/source/dialogs/charwin.cxx
@@ -0,0 +1,213 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <vcl/settings.hxx>
#include <vcl/builderfactory.hxx>
#include "charwin.hxx"
#include <comphelper/propertysequence.hxx>
#include <comphelper/dispatchcommand.hxx>
#include <sfx2/app.hxx>
#include "cuicharmap.hxx"
#include "macroass.hxx"

using namespace com::sun::star;


SvxCharView::SvxCharView(vcl::Window* pParent)
    : Control(pParent, WB_TABSTOP | WB_BORDER)
    , mnY(0)
{
}

VCL_BUILDER_FACTORY(SvxCharView)

void SvxCharView::MouseButtonDown( const MouseEvent& rMEvt )
{
    if ( rMEvt.IsLeft() )
    {
        maMouseClickHdl.Call(this);
        if ( !(rMEvt.GetClicks() % 2) )
        {
            InsertCharToDoc();
        }
    }

    Control::MouseButtonDown(rMEvt);
}

void SvxCharView::KeyInput( const KeyEvent& rKEvt )
{
    vcl::KeyCode aCode = rKEvt.GetKeyCode();

    switch (aCode.GetCode())
    {
        case KEY_SPACE:
        case KEY_RETURN:
            InsertCharToDoc();
            break;
    }
    Control::KeyInput(rKEvt);
}

void SvxCharView::InsertCharToDoc()
{
    if(GetText().isEmpty())
        return;

    uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );

    uno::Sequence<beans::PropertyValue> aArgs(2);
    aArgs[0].Name = OUString::fromUtf8("Symbols");
    aArgs[0].Value <<= GetText();

    aArgs[1].Name = OUString::fromUtf8("FontName");
    aArgs[1].Value <<= maFont.GetFamilyName();

    comphelper::dispatchCommand(".uno:InsertSymbol", aArgs);
}

void SvxCharView::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle&)
{
    rRenderContext.SetFont(maFont);

    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    const Color aWindowTextColor(rStyleSettings.GetFieldTextColor());
    Color aHighlightColor(rStyleSettings.GetHighlightColor());
    Color aHighlightTextColor(rStyleSettings.GetHighlightTextColor());
    Color aLightColor(rStyleSettings.GetLightColor());

    const OUString aText = GetText();
    const Size aSize(GetOutputSizePixel());

    long nAvailWidth = aSize.Width();
    long nWinHeight = GetOutputSizePixel().Height();

    bool bGotBoundary = true;
    bool bShrankFont = false;
    vcl::Font aOrigFont(rRenderContext.GetFont());
    Size aFontSize(aOrigFont.GetFontSize());
    ::tools::Rectangle aBoundRect;

    for (long nFontHeight = aFontSize.Height(); nFontHeight > 0; nFontHeight -= 1)
    {
        if (!rRenderContext.GetTextBoundRect( aBoundRect, aText ) || aBoundRect.IsEmpty())
        {
            bGotBoundary = false;
            break;
        }

        //only shrink in the single glyph large view mode
        long nTextWidth = aBoundRect.GetWidth();
        if (nAvailWidth > nTextWidth)
            break;
        vcl::Font aFont(aOrigFont);
        aFontSize.Height() = nFontHeight;
        aFont.SetFontSize(aFontSize);
        rRenderContext.SetFont(aFont);
        mnY = (nWinHeight - GetTextHeight()) / 2;
        bShrankFont = true;
    }

    Point aPoint(2, mnY);

    if (!bGotBoundary)
        aPoint.X() = (aSize.Width() - rRenderContext.GetTextWidth(aText)) / 2;
    else
    {
        // adjust position
        aBoundRect += aPoint;

        // vertical adjustment
        int nYLDelta = aBoundRect.Top();
        int nYHDelta = aSize.Height() - aBoundRect.Bottom();
        if( nYLDelta <= 0 )
            aPoint.Y() -= nYLDelta - 1;
        else if( nYHDelta <= 0 )
            aPoint.Y() += nYHDelta - 1;

        // centrally align glyph
        aPoint.X() = -aBoundRect.Left() + (aSize.Width() - aBoundRect.GetWidth()) / 2;
    }

    if (HasFocus())
    {
        rRenderContext.SetFillColor(aHighlightColor);
        rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), Size(GetOutputSizePixel().Width(), GetOutputSizePixel().Height())));

        rRenderContext.SetTextColor(aHighlightTextColor);
        rRenderContext.DrawText(aPoint, aText);
    }
    else
    {
        rRenderContext.SetFillColor(aLightColor);
        rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), Size(GetOutputSizePixel().Width(), GetOutputSizePixel().Height())));

        rRenderContext.SetTextColor(aWindowTextColor);
        rRenderContext.DrawText(aPoint, aText);
    }

    if (bShrankFont)
        rRenderContext.SetFont(aOrigFont);
}

void SvxCharView::setInsertCharHdl(const Link<SvxCharView*,void> &rLink)
{
    maInsertCharHdl = rLink;
}

void SvxCharView::setMouseClickHdl(const Link<SvxCharView*,void> &rLink)
{
    maMouseClickHdl = rLink;
}

void SvxCharView::SetFont( const vcl::Font& rFont )
{
    long nWinHeight = GetOutputSizePixel().Height();
    maFont = vcl::Font(rFont);
    maFont.SetWeight(WEIGHT_NORMAL);
    maFont.SetAlignment(ALIGN_TOP);
    maFont.SetFontSize(PixelToLogic(Size(0, nWinHeight / 2)));
    maFont.SetTransparent(true);
    Control::SetFont(maFont);

    mnY = (nWinHeight - GetTextHeight()) / 2;

    Invalidate();
}

Size SvxCharView::GetOptimalSize() const
{
    const vcl::Font &rFont = GetFont();
    const Size rFontSize = rFont.GetFontSize();
    long nWinHeight = LogicToPixel(rFontSize).Height() * 2;
    return Size( GetTextWidth( GetText() ) + 2 * 12, nWinHeight );
}

void SvxCharView::Resize()
{
    Control::Resize();
    SetFont(GetFont());
}


void SvxCharView::SetText( const OUString& rText )
{
    Control::SetText( rText );
    Invalidate();
}
diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx
index 8d1180a..59c9225 100644
--- a/cui/source/dialogs/cuicharmap.cxx
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -33,6 +33,11 @@
#include <vcl/builderfactory.hxx>
#include <vcl/fontcharmap.hxx>
#include <svl/stritem.hxx>
#include <officecfg/Office/Common.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/propertysequence.hxx>
#include <comphelper/dispatchcommand.hxx>
#include <sfx2/app.hxx>

#include <cuires.hrc>
#include <dialmgr.hxx>
@@ -43,18 +48,19 @@
#include <editeng/fontitem.hxx>
#include "macroass.hxx"

using namespace css;

// class SvxCharacterMap =================================================

SvxCharacterMap::SvxCharacterMap( vcl::Window* pParent, bool bOne_, const SfxItemSet* pSet )
    : SfxModalDialog(pParent, "SpecialCharactersDialog", "cui/ui/specialcharacters.ui")
    , bOne( bOne_ )
    , pSubsetMap( nullptr )
    , mxContext(comphelper::getProcessComponentContext())
{
    get(m_pShowSet, "showcharset");
    get(m_pShowChar, "showchar");
    m_pShowChar->SetCentered(true);
    get(m_pShowText, "showtext");
    m_pShowText->SetMaxTextLen(CHARMAP_MAXLEN);
    get(m_pOKBtn, "ok");
    get(m_pFontText, "fontft");
    get(m_pFontLB, "fontlb");
@@ -68,7 +74,23 @@ SvxCharacterMap::SvxCharacterMap( vcl::Window* pParent, bool bOne_, const SfxIte
    get(m_pDecimalCodeText, "decimalvalue");
    //lock the size request of this widget to the width of the original .ui string
    m_pHexCodeText->set_width_request(m_pHexCodeText->get_preferred_size().Width());
    get(m_pSymbolText, "symboltext");

    get( m_pRecentCharView[0], "viewchar1" );
    get( m_pRecentCharView[1], "viewchar2" );
    get( m_pRecentCharView[2], "viewchar3" );
    get( m_pRecentCharView[3], "viewchar4" );
    get( m_pRecentCharView[4], "viewchar5" );
    get( m_pRecentCharView[5], "viewchar6" );
    get( m_pRecentCharView[6], "viewchar7" );
    get( m_pRecentCharView[7], "viewchar8" );
    get( m_pRecentCharView[8], "viewchar9" );
    get( m_pRecentCharView[9], "viewchar10" );
    get( m_pRecentCharView[10], "viewchar11" );
    get( m_pRecentCharView[11], "viewchar12" );
    get( m_pRecentCharView[12], "viewchar13" );
    get( m_pRecentCharView[13], "viewchar14" );
    get( m_pRecentCharView[14], "viewchar15" );
    get( m_pRecentCharView[15], "viewchar16" );

    const SfxBoolItem* pItem = SfxItemSet::GetItem<SfxBoolItem>(pSet, FN_PARAM_1, false);
    if ( pItem )
@@ -108,19 +130,42 @@ SvxCharacterMap::~SvxCharacterMap()
    disposeOnce();
}

short SvxCharacterMap::Execute()
{
    if( SvxShowCharSet::getSelectedChar() == ' ')
    {
        m_pOKBtn->Disable();
    }
    else
    {
        sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
        // using the new UCS4 constructor
        OUString aOUStr( &cChar, 1 );
        m_pShowChar->SetText(aOUStr);
        m_pOKBtn->Enable();
    }

    return ModalDialog::Execute();
}

void SvxCharacterMap::dispose()
{
    for(int i = 0; i < 16; i++)
        m_pRecentCharView[i].clear();

    m_pShowSet.clear();
    m_pShowText.clear();
    m_pOKBtn.clear();
    m_pFontText.clear();
    m_pFontLB.clear();
    m_pSubsetText.clear();
    m_pSubsetLB.clear();
    m_pSymbolText.clear();
    m_pShowChar.clear();
    m_pHexCodeText.clear();
    m_pDecimalCodeText.clear();

    maRecentCharList.clear();
    maRecentCharFontList.clear();

    SfxModalDialog::dispose();
}

@@ -137,37 +182,426 @@ sal_UCS4 SvxCharacterMap::GetChar() const
}


OUString SvxCharacterMap::GetCharacters() const
{
    return m_pShowText->GetText();
}


void SvxCharacterMap::DisableFontSelection()
{
    m_pFontText->Disable();
    m_pFontLB->Disable();
}

short SvxCharacterMap::Execute()

void SvxCharacterMap::getRecentCharacterList()
{
    short nResult = SfxModalDialog::Execute();
    if ( nResult == RET_OK )
    //retrieve recent character list
    css::uno::Sequence< OUString > rRecentCharList( officecfg::Office::Common::RecentCharacters::RecentCharacterList::get() );
    for (int i = 0; i < rRecentCharList.getLength(); ++i)
    {
        SfxItemSet* pSet = GetItemSet();
        if ( pSet )
        {
            const SfxItemPool* pPool = pSet->GetPool();
            const vcl::Font& rFont( GetCharFont() );
            pSet->Put( SfxStringItem( pPool->GetWhich(SID_CHARMAP), GetCharacters() ) );
            pSet->Put( SvxFontItem( rFont.GetFamilyType(), rFont.GetFamilyName(),
                rFont.GetStyleName(), rFont.GetPitch(), rFont.GetCharSet(), pPool->GetWhich(SID_ATTR_CHAR_FONT) ) );
            pSet->Put( SfxStringItem( pPool->GetWhich(SID_FONT_NAME), rFont.GetFamilyName() ) );
            pSet->Put( SfxInt32Item( pPool->GetWhich(SID_ATTR_CHAR), GetChar() ) );
        }
        maRecentCharList.push_back(rRecentCharList[i]);
    }

    return nResult;
    //retrieve recent character font list
    css::uno::Sequence< OUString > rRecentCharFontList( officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::get() );
    for (int i = 0; i < rRecentCharFontList.getLength(); ++i)
    {
        maRecentCharFontList.push_back(rRecentCharFontList[i]);
    }
}

void SvxCharacterMap::updateRecentCharControl()
{
    int i = 0;
    for ( std::deque< OUString >::iterator it = maRecentCharList.begin(), it2 = maRecentCharFontList.begin();
        it != maRecentCharList.end() || it2 != maRecentCharFontList.end();
        ++it, ++it2, i++)
    {
        m_pRecentCharView[i]->SetText(*it);
        vcl::Font rFont = m_pRecentCharView[i]->GetControlFont();
        rFont.SetFamilyName( *it2 );
        m_pRecentCharView[i]->SetFont(rFont);
        m_pRecentCharView[i]->Show();
    }

    for(; i < 16 ; i++)
    {
        m_pRecentCharView[i]->SetText(OUString());
        m_pRecentCharView[i]->Hide();
    }
}

void SvxCharacterMap::updateRecentCharacterList(const OUString& sTitle, const OUString& rFont)
{
    auto itChar = std::find_if(maRecentCharList.begin(),
         maRecentCharList.end(),
         [sTitle] (const OUString & a) { return a == sTitle; });

    auto itChar2 = std::find_if(maRecentCharFontList.begin(),
         maRecentCharFontList.end(),
         [rFont] (const OUString & a) { return a == rFont; });

    // if recent char to be added is already in list, remove it
    if( 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());
    css::uno::Sequence< OUString > aRecentCharFontList(maRecentCharFontList.size());

    for (size_t i = 0; i < maRecentCharList.size(); ++i)
    {
        aRecentCharList[i] = maRecentCharList[i];
        aRecentCharFontList[i] = maRecentCharFontList[i];
    }

    std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
    officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList, batch);
    officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList, batch);
    batch->commit();

    updateRecentCharControl();
}


void SvxCharacterMap::init()
{
    aFont = GetFont();
    aFont.SetTransparent( true );
    aFont.SetFamily( FAMILY_DONTKNOW );
    aFont.SetPitch( PITCH_DONTKNOW );
    aFont.SetCharSet( RTL_TEXTENCODING_DONTKNOW );

    OUString aDefStr( aFont.GetFamilyName() );
    OUString aLastName;
    int nCount = GetDevFontCount();
    for ( int i = 0; i < nCount; i++ )
    {
        OUString aFontName( GetDevFont( i ).GetFamilyName() );
        if ( aFontName != aLastName )
        {
            aLastName = aFontName;
            const sal_Int32 nPos = m_pFontLB->InsertEntry( aFontName );
            m_pFontLB->SetEntryData( nPos, reinterpret_cast<void*>(i) );
        }
    }
    // the font may not be in the list =>
    // try to find a font name token in list and select found font,
    // else select topmost entry
    bool bFound = (m_pFontLB->GetEntryPos( aDefStr ) == LISTBOX_ENTRY_NOTFOUND );
    if( !bFound )
    {
        sal_Int32 nIndex = 0;
        do
        {
            OUString aToken = aDefStr.getToken(0, ';', nIndex);
            if ( m_pFontLB->GetEntryPos( aToken ) != LISTBOX_ENTRY_NOTFOUND )
            {
                aDefStr = aToken;
                bFound = true;
                break;
            }
        }
        while ( nIndex >= 0 );
    }

    if ( bFound )
        m_pFontLB->SelectEntry( aDefStr );
    else if ( m_pFontLB->GetEntryCount() )
        m_pFontLB->SelectEntryPos(0);
    FontSelectHdl(*m_pFontLB);

    m_pFontLB->SetSelectHdl( LINK( this, SvxCharacterMap, FontSelectHdl ) );
    m_pSubsetLB->SetSelectHdl( LINK( this, SvxCharacterMap, SubsetSelectHdl ) );
    m_pOKBtn->SetClickHdl( LINK( this, SvxCharacterMap, InsertClickHdl ) );
    m_pShowSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) );
    m_pShowSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) );
    m_pShowSet->SetHighlightHdl( LINK( this, SvxCharacterMap, CharHighlightHdl ) );
    m_pShowSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) );
    m_pDecimalCodeText->SetModifyHdl( LINK( this, SvxCharacterMap, DecimalCodeChangeHdl ) );
    m_pHexCodeText->SetModifyHdl( LINK( this, SvxCharacterMap, HexCodeChangeHdl ) );

    if( SvxShowCharSet::getSelectedChar() == ' ')
    {
        m_pOKBtn->Disable();
    }
    else
    {
        sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
        // using the new UCS4 constructor
        OUString aOUStr( &cChar, 1 );
        m_pShowChar->SetText(aOUStr);
        m_pOKBtn->Enable();
    }

    getRecentCharacterList();
    updateRecentCharControl();

    for(int i = 0; i < 16; i++)
    {
        m_pRecentCharView[i]->setMouseClickHdl(LINK(this,SvxCharacterMap, RecentClickHdl));
        m_pRecentCharView[i]->SetLoseFocusHdl(LINK(this,SvxCharacterMap, LoseFocusHdl));
    }
}


void SvxCharacterMap::SetCharFont( const vcl::Font& rFont )
{
    // first get the underlying info in order to get font names
    // like "Times New Roman;Times" resolved
    vcl::Font aTmp( GetFontMetric( rFont ) );

    if (aTmp.GetFamilyName() == "StarSymbol" && m_pFontLB->GetEntryPos(aTmp.GetFamilyName()) == LISTBOX_ENTRY_NOTFOUND)
    {
        //if for some reason, like font in an old document, StarSymbol is requested and its not available, then
        //try OpenSymbol instead
        aTmp.SetFamilyName("OpenSymbol");
    }

    if ( m_pFontLB->GetEntryPos( aTmp.GetFamilyName() ) == LISTBOX_ENTRY_NOTFOUND )
        return;

    m_pFontLB->SelectEntry( aTmp.GetFamilyName() );
    aFont = aTmp;
    FontSelectHdl(*m_pFontLB);

    // for compatibility reasons
    ModalDialog::SetFont( aFont );
}


void SvxCharacterMap::fillAllSubsets(ListBox &rListBox)
{
    SubsetMap aAll(nullptr);
    rListBox.Clear();
    bool bFirst = true;
    while (const Subset *s = aAll.GetNextSubset(bFirst))
    {
        rListBox.InsertEntry( s->GetName() );
        bFirst = false;
    }
}


void SvxCharacterMap::insertCharToDoc(const OUString& sGlyph)
{
    if(sGlyph.isEmpty())
        return;

    uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );

    uno::Sequence<beans::PropertyValue> aArgs(2);
    aArgs[0].Name = OUString::fromUtf8("Symbols");
    aArgs[0].Value <<= sGlyph;

    aArgs[1].Name = OUString::fromUtf8("FontName");
    aArgs[1].Value <<= aFont.GetFamilyName();
    comphelper::dispatchCommand(".uno:InsertSymbol", aArgs);

    updateRecentCharacterList(sGlyph, aFont.GetFamilyName());
}


IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, ListBox&, void)
{
    const sal_Int32 nPos = m_pFontLB->GetSelectEntryPos();
    const sal_uInt16 nFont = (sal_uInt16)reinterpret_cast<sal_uLong>(m_pFontLB->GetEntryData( nPos ));
    aFont = GetDevFont( nFont );
    aFont.SetWeight( WEIGHT_DONTKNOW );
    aFont.SetItalic( ITALIC_NONE );
    aFont.SetWidthType( WIDTH_DONTKNOW );
    aFont.SetPitch( PITCH_DONTKNOW );
    aFont.SetFamily( FAMILY_DONTKNOW );

    // notify children using this font
    m_pShowSet->SetFont( aFont );
    m_pShowChar->SetFont( aFont );

    // setup unicode subset listbar with font specific subsets,
    // hide unicode subset listbar for symbol fonts
    // TODO: get info from the Font once it provides it
    delete pSubsetMap;
    pSubsetMap = nullptr;
    m_pSubsetLB->Clear();

    bool bNeedSubset = (aFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL);
    if( bNeedSubset )
    {
        FontCharMapRef xFontCharMap( new FontCharMap() );
        m_pShowSet->GetFontCharMap( xFontCharMap );
        pSubsetMap = new SubsetMap( xFontCharMap );

        // update subset listbox for new font's unicode subsets
        // TODO: is it worth to improve the stupid linear search?
        bool bFirst = true;
        const Subset* s;
        while( nullptr != (s = pSubsetMap->GetNextSubset( bFirst ))  )
        {
            const sal_Int32 nPos_ = m_pSubsetLB->InsertEntry( s->GetName() );
            m_pSubsetLB->SetEntryData( nPos_, const_cast<Subset *>(s) );
            // NOTE: subset must live at least as long as the selected font
            if( bFirst )
                m_pSubsetLB->SelectEntryPos( nPos_ );
            bFirst = false;
        }
        if( m_pSubsetLB->GetEntryCount() <= 1 )
            bNeedSubset = false;
    }

    m_pSubsetText->Enable(bNeedSubset);
    m_pSubsetLB->Enable(bNeedSubset);
}


IMPL_LINK_NOARG(SvxCharacterMap, SubsetSelectHdl, ListBox&, void)
{
    const sal_Int32 nPos = m_pSubsetLB->GetSelectEntryPos();
    const Subset* pSubset = static_cast<const Subset*> (m_pSubsetLB->GetEntryData(nPos));
    if( pSubset )
    {
        sal_UCS4 cFirst = pSubset->GetRangeMin();
        m_pShowSet->SelectCharacter( cFirst );
    }
    m_pSubsetLB->SelectEntryPos( nPos );
}

IMPL_LINK(SvxCharacterMap, RecentClickHdl, SvxCharView*, rView, void)
{
    m_pShowChar->SetText( rView->GetText() );
    m_pShowChar->SetFont(rView->GetFont());
    m_pShowChar->Update();
    rView->GrabFocus();
    rView->Invalidate();
    m_pOKBtn->Enable();
}

IMPL_LINK_NOARG(SvxCharacterMap, CharDoubleClickHdl, SvxShowCharSet*, void)
{
    sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
    // using the new UCS4 constructor
    OUString aOUStr( &cChar, 1 );
    insertCharToDoc(aOUStr);
}

IMPL_LINK_NOARG(SvxCharacterMap, CharSelectHdl, SvxShowCharSet*, void)
{
    m_pOKBtn->Enable();
}

IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, Button*, void)
{
   insertCharToDoc(m_pShowChar->GetText());
   EndDialog(RET_OK);
}


IMPL_STATIC_LINK(SvxCharacterMap, LoseFocusHdl, Control&, pItem, void)
{
    pItem.Invalidate();
}


IMPL_LINK_NOARG(SvxCharacterMap, CharHighlightHdl, SvxShowCharSet*, void)
{
    OUString aText;
    OUString aHexText;
    OUString aDecimalText;
    sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
    bool bSelect = (cChar > 0);

    // show char sample
    if ( bSelect )
    {
        // using the new UCS4 constructor
        aText = OUString( &cChar, 1 );

        const Subset* pSubset = nullptr;
        if( pSubsetMap )
            pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
        if( pSubset )
            m_pSubsetLB->SelectEntry( pSubset->GetName() );
        else
            m_pSubsetLB->SetNoSelection();
    }

    if(m_pShowSet->HasFocus())
    {
        m_pShowChar->SetText( aText );
        m_pShowChar->SetFont( aFont );
        m_pShowChar->Update();
    }

    // show char codes
    if ( bSelect )
    {
        // Get the hexadecimal code
        char aBuf[32];
        snprintf( aBuf, sizeof(aBuf), "%X", static_cast<unsigned>(cChar) );
        aHexText = OUString::createFromAscii(aBuf);
        // Get the decimal code
        char aDecBuf[32];
        snprintf( aDecBuf, sizeof(aDecBuf), "%u", static_cast<unsigned>(cChar) );
        aDecimalText = OUString::createFromAscii(aDecBuf);
    }

    // Update the hex and decimal codes only if necessary
    if (m_pHexCodeText->GetText() != aHexText)
        m_pHexCodeText->SetText( aHexText );
    if (m_pDecimalCodeText->GetText() != aDecimalText)
        m_pDecimalCodeText->SetText( aDecimalText );
}

void SvxCharacterMap::selectCharByCode(Radix radix)
{
    OUString aCodeString;
    switch(radix)
    {
        case Radix::decimal:
            aCodeString = m_pDecimalCodeText->GetText();
            break;
        case Radix::hexadecimal:
            aCodeString = m_pHexCodeText->GetText();
            break;
    }
    // Convert the code back to a character using the appropriate 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(new FontCharMap());
    m_pShowSet->GetFontCharMap(xFontCharMap);
    if (xFontCharMap->HasChar(cChar))
        // Select the corresponding character
        SetChar(cChar);
}

IMPL_LINK_NOARG(SvxCharacterMap, DecimalCodeChangeHdl, Edit&, void)
{
    selectCharByCode(Radix::decimal);
}

IMPL_LINK_NOARG(SvxCharacterMap, HexCodeChangeHdl, Edit&, void)
{
    selectCharByCode(Radix::hexadecimal);
}

IMPL_LINK_NOARG(SvxCharacterMap, CharPreSelectHdl, SvxShowCharSet*, void)
{
    // adjust subset selection
    if( pSubsetMap )
    {
        sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
        const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
        if( pSubset )
            m_pSubsetLB->SelectEntry( pSubset->GetName() );
    }

    m_pOKBtn->Enable();
}


@@ -302,326 +736,4 @@ void SvxShowText::SetText( const OUString& rText )
}


// class SvxCharacterMap =================================================

void SvxCharacterMap::init()
{
    aFont = GetFont();
    aFont.SetTransparent( true );
    aFont.SetFamily( FAMILY_DONTKNOW );
    aFont.SetPitch( PITCH_DONTKNOW );
    aFont.SetCharSet( RTL_TEXTENCODING_DONTKNOW );

    if (bOne)
    {
        m_pSymbolText->Hide();
        m_pShowText->Hide();
    }

    OUString aDefStr( aFont.GetFamilyName() );
    OUString aLastName;
    int nCount = GetDevFontCount();
    for ( int i = 0; i < nCount; i++ )
    {
        OUString aFontName( GetDevFont( i ).GetFamilyName() );
        if ( aFontName != aLastName )
        {
            aLastName = aFontName;
            const sal_Int32 nPos = m_pFontLB->InsertEntry( aFontName );
            m_pFontLB->SetEntryData( nPos, reinterpret_cast<void*>(i) );
        }
    }
    // the font may not be in the list =>
    // try to find a font name token in list and select found font,
    // else select topmost entry
    bool bFound = (m_pFontLB->GetEntryPos( aDefStr ) == LISTBOX_ENTRY_NOTFOUND );
    if( !bFound )
    {
        sal_Int32 nIndex = 0;
        do
        {
            OUString aToken = aDefStr.getToken(0, ';', nIndex);
            if ( m_pFontLB->GetEntryPos( aToken ) != LISTBOX_ENTRY_NOTFOUND )
            {
                aDefStr = aToken;
                bFound = true;
                break;
            }
        }
        while ( nIndex >= 0 );
    }

    if ( bFound )
        m_pFontLB->SelectEntry( aDefStr );
    else if ( m_pFontLB->GetEntryCount() )
        m_pFontLB->SelectEntryPos(0);
    FontSelectHdl(*m_pFontLB);

    m_pOKBtn->SetClickHdl( LINK( this, SvxCharacterMap, OKHdl ) );
    m_pFontLB->SetSelectHdl( LINK( this, SvxCharacterMap, FontSelectHdl ) );
    m_pSubsetLB->SetSelectHdl( LINK( this, SvxCharacterMap, SubsetSelectHdl ) );
    m_pShowSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) );
    m_pShowSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) );
    m_pShowSet->SetHighlightHdl( LINK( this, SvxCharacterMap, CharHighlightHdl ) );
    m_pShowSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) );
    m_pDecimalCodeText->SetModifyHdl( LINK( this, SvxCharacterMap, DecimalCodeChangeHdl ) );
    m_pHexCodeText->SetModifyHdl( LINK( this, SvxCharacterMap, HexCodeChangeHdl ) );

    if( SvxShowCharSet::getSelectedChar() == ' ')
        m_pOKBtn->Disable();
    else
        m_pOKBtn->Enable();
}


void SvxCharacterMap::SetCharFont( const vcl::Font& rFont )
{
    // first get the underlying info in order to get font names
    // like "Times New Roman;Times" resolved
    vcl::Font aTmp( GetFontMetric( rFont ) );

    if (aTmp.GetFamilyName() == "StarSymbol" && m_pFontLB->GetEntryPos(aTmp.GetFamilyName()) == LISTBOX_ENTRY_NOTFOUND)
    {
        //if for some reason, like font in an old document, StarSymbol is requested and its not available, then
        //try OpenSymbol instead
        aTmp.SetFamilyName("OpenSymbol");
    }

    if ( m_pFontLB->GetEntryPos( aTmp.GetFamilyName() ) == LISTBOX_ENTRY_NOTFOUND )
        return;

    m_pFontLB->SelectEntry( aTmp.GetFamilyName() );
    aFont = aTmp;
    FontSelectHdl(*m_pFontLB);

    // for compatibility reasons
    ModalDialog::SetFont( aFont );
}


IMPL_LINK_NOARG(SvxCharacterMap, OKHdl, Button*, void)
{
    OUString aStr = m_pShowText->GetText();

    if ( aStr.isEmpty() )
    {
        sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
        // using the new UCS4 constructor
        OUString aOUStr( &cChar, 1 );
        m_pShowText->SetText( aOUStr );
    }
    EndDialog( RET_OK );
}

void SvxCharacterMap::fillAllSubsets(ListBox &rListBox)
{
    SubsetMap aAll(nullptr);
    rListBox.Clear();
    bool bFirst = true;
    while (const Subset *s = aAll.GetNextSubset(bFirst))
    {
        rListBox.InsertEntry( s->GetName() );
        bFirst = false;
    }
}


IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, ListBox&, void)
{
    const sal_Int32 nPos = m_pFontLB->GetSelectEntryPos();
    const sal_uInt16 nFont = (sal_uInt16)reinterpret_cast<sal_uLong>(m_pFontLB->GetEntryData( nPos ));
    aFont = GetDevFont( nFont );
    aFont.SetWeight( WEIGHT_DONTKNOW );
    aFont.SetItalic( ITALIC_NONE );
    aFont.SetWidthType( WIDTH_DONTKNOW );
    aFont.SetPitch( PITCH_DONTKNOW );
    aFont.SetFamily( FAMILY_DONTKNOW );

    // notify children using this font
    m_pShowSet->SetFont( aFont );
    m_pShowChar->SetFont( aFont );
    m_pShowText->SetControlFont( aFont );

    // setup unicode subset listbar with font specific subsets,
    // hide unicode subset listbar for symbol fonts
    // TODO: get info from the Font once it provides it
    delete pSubsetMap;
    pSubsetMap = nullptr;
    m_pSubsetLB->Clear();

    bool bNeedSubset = (aFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL);
    if( bNeedSubset )
    {
        FontCharMapRef xFontCharMap( new FontCharMap() );
        m_pShowSet->GetFontCharMap( xFontCharMap );
        pSubsetMap = new SubsetMap( xFontCharMap );

        // update subset listbox for new font's unicode subsets
        // TODO: is it worth to improve the stupid linear search?
        bool bFirst = true;
        const Subset* s;
        while( nullptr != (s = pSubsetMap->GetNextSubset( bFirst ))  )
        {
            const sal_Int32 nPos_ = m_pSubsetLB->InsertEntry( s->GetName() );
            m_pSubsetLB->SetEntryData( nPos_, const_cast<Subset *>(s) );
            // NOTE: subset must live at least as long as the selected font
            if( bFirst )
                m_pSubsetLB->SelectEntryPos( nPos_ );
            bFirst = false;
        }
        if( m_pSubsetLB->GetEntryCount() <= 1 )
            bNeedSubset = false;
    }

    m_pSubsetText->Enable(bNeedSubset);
    m_pSubsetLB->Enable(bNeedSubset);
}


IMPL_LINK_NOARG(SvxCharacterMap, SubsetSelectHdl, ListBox&, void)
{
    const sal_Int32 nPos = m_pSubsetLB->GetSelectEntryPos();
    const Subset* pSubset = static_cast<const Subset*> (m_pSubsetLB->GetEntryData(nPos));
    if( pSubset )
    {
        sal_UCS4 cFirst = pSubset->GetRangeMin();
        m_pShowSet->SelectCharacter( cFirst );
    }
    m_pSubsetLB->SelectEntryPos( nPos );
}


IMPL_LINK_NOARG(SvxCharacterMap, CharDoubleClickHdl, SvxShowCharSet*, void)
{
    if (bOne)
    {
        sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
        m_pShowText->SetText(OUString(&cChar, 1));
    }
    EndDialog( RET_OK );
}


IMPL_LINK_NOARG(SvxCharacterMap, CharSelectHdl, SvxShowCharSet*, void)
{
    if ( !bOne )
    {
        OUString aText = m_pShowText->GetText();
        Selection aSelection = m_pShowText->GetSelection();
        aSelection.Justify();
        long nLen = aSelection.Len();

        if ( aText.getLength() != CHARMAP_MAXLEN || nLen > 0 )
        {
            sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
            // using the new UCS4 constructor
            OUString aOUStr( &cChar, 1 );

            long nPos = aSelection.Min();
            if( aText.getLength() )
            {
                m_pShowText->SetText( aText.copy( 0, nPos ) + aOUStr + aText.copy( nPos + nLen ) );
            }
            else
                m_pShowText->SetText( aOUStr );

            m_pShowText->SetSelection(Selection(nPos + aOUStr.getLength()));
        }

    }
    m_pOKBtn->Enable();
}


IMPL_LINK_NOARG(SvxCharacterMap, CharHighlightHdl, SvxShowCharSet*, void)
{
    OUString aText;
    OUString aHexText;
    OUString aDecimalText;
    sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
    bool bSelect = (cChar > 0);

    // show char sample
    if ( bSelect )
    {
        // using the new UCS4 constructor
        aText = OUString( &cChar, 1 );

        const Subset* pSubset = nullptr;
        if( pSubsetMap )
            pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
        if( pSubset )
            m_pSubsetLB->SelectEntry( pSubset->GetName() );
        else
            m_pSubsetLB->SetNoSelection();
    }
    m_pShowChar->SetText( aText );
    m_pShowChar->Update();

    // show char codes
    if ( bSelect )
    {
        // Get the hexadecimal code
        char aBuf[32];
        snprintf( aBuf, sizeof(aBuf), "%X", static_cast<unsigned>(cChar) );
        aHexText = OUString::createFromAscii(aBuf);
        // Get the decimal code
        char aDecBuf[32];
        snprintf( aDecBuf, sizeof(aDecBuf), "%u", static_cast<unsigned>(cChar) );
        aDecimalText = OUString::createFromAscii(aDecBuf);
    }

    // Update the hex and decimal codes only if necessary
    if (m_pHexCodeText->GetText() != aHexText)
        m_pHexCodeText->SetText( aHexText );
    if (m_pDecimalCodeText->GetText() != aDecimalText)
        m_pDecimalCodeText->SetText( aDecimalText );
}

void SvxCharacterMap::selectCharByCode(Radix radix)
{
    OUString aCodeString;
    switch(radix)
    {
        case Radix::decimal:
            aCodeString = m_pDecimalCodeText->GetText();
            break;
        case Radix::hexadecimal:
            aCodeString = m_pHexCodeText->GetText();
            break;
    }
    // Convert the code back to a character using the appropriate 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(new FontCharMap());
    m_pShowSet->GetFontCharMap(xFontCharMap);
    if (xFontCharMap->HasChar(cChar))
        // Select the corresponding character
        SetChar(cChar);
}

IMPL_LINK_NOARG(SvxCharacterMap, DecimalCodeChangeHdl, Edit&, void)
{
    selectCharByCode(Radix::decimal);
}

IMPL_LINK_NOARG(SvxCharacterMap, HexCodeChangeHdl, Edit&, void)
{
    selectCharByCode(Radix::hexadecimal);
}

IMPL_LINK_NOARG(SvxCharacterMap, CharPreSelectHdl, SvxShowCharSet*, void)
{
    // adjust subset selection
    if( pSubsetMap )
    {
        sal_UCS4 cChar = m_pShowSet->GetSelectCharacter();
        const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
        if( pSubset )
            m_pSubsetLB->SelectEntry( pSubset->GetName() );
    }

    m_pOKBtn->Enable();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/factory/init.cxx b/cui/source/factory/init.cxx
index fd7cbc6..e23077a 100644
--- a/cui/source/factory/init.cxx
+++ b/cui/source/factory/init.cxx
@@ -32,7 +32,10 @@ SAL_DLLPUBLIC_EXPORT bool GetSpecialCharsForEdit(vcl::Window* i_pParent, const v
    aDlg->SetCharFont(i_rFont);
    if ( aDlg->Execute() == RET_OK )
    {
        o_rResult = aDlg->GetCharacters();
        sal_UCS4 cChar = aDlg->GetChar();
        // using the new UCS4 constructor
        OUString aOUStr( &cChar, 1 );
        o_rResult = aOUStr;
        bRet = true;
    }
    return bRet;
diff --git a/cui/source/inc/charwin.hxx b/cui/source/inc/charwin.hxx
new file mode 100644
index 0000000..7feb068
--- /dev/null
+++ b/cui/source/inc/charwin.hxx
@@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_CUI_SOURCE_INC_CHARWIN_HXX
#define INCLUDED_CUI_SOURCE_INC_CHARWIN_HXX

#include <vcl/ctrl.hxx>

class SvxCharView : public Control
{
public:
    SvxCharView(vcl::Window* pParent);

    void            SetFont( const vcl::Font& rFont );
    void            SetText( const OUString& rText ) override;
    void            InsertCharToDoc();

    virtual void    Resize() override;

    virtual Size    GetOptimalSize() const override;

    void setInsertCharHdl(const Link<SvxCharView*,void> &rLink);
    void setMouseClickHdl(const Link<SvxCharView*,void> &rLink);

protected:
    virtual void    Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle&) override;

    virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;

    virtual void KeyInput( const KeyEvent& rKEvt ) override;

private:
    long            mnY;
    vcl::Font       maFont;

    Link<SvxCharView*, void> maInsertCharHdl;
    Link<SvxCharView*, void> maMouseClickHdl;
};

#endif
diff --git a/cui/source/inc/cuicharmap.hxx b/cui/source/inc/cuicharmap.hxx
index 8d83798..4f1a63f 100644
--- a/cui/source/inc/cuicharmap.hxx
+++ b/cui/source/inc/cuicharmap.hxx
@@ -26,7 +26,9 @@
#include <vcl/lstbox.hxx>
#include <sfx2/basedlgs.hxx>
#include <svx/charmap.hxx>
#include "charwin.hxx"

using namespace ::com::sun::star;
class SubsetMap;

#define CHARMAP_MAXLEN  32
@@ -68,22 +70,26 @@ private:
    void            init();

    VclPtr<SvxShowCharSet> m_pShowSet;
    VclPtr<Edit>           m_pShowText;
    VclPtr<PushButton>     m_pOKBtn;
    VclPtr<FixedText>      m_pFontText;
    VclPtr<ListBox>        m_pFontLB;
    VclPtr<FixedText>      m_pSubsetText;
    VclPtr<ListBox>        m_pSubsetLB;
    VclPtr<FixedText>      m_pSymbolText;
    VclPtr<SvxShowText>    m_pShowChar;
    VclPtr<Edit>           m_pHexCodeText;
    VclPtr<Edit>           m_pDecimalCodeText;
    VclPtr<SvxCharView>    m_pRecentCharView[16];
    vcl::Font       aFont;
    bool            bOne;
    const SubsetMap* pSubsetMap;

    std::deque<OUString> maRecentCharList;
    std::deque<OUString> maRecentCharFontList;

    uno::Reference< uno::XComponentContext > mxContext;

    enum class Radix : sal_Int16 {decimal = 10, hexadecimal=16};

    DECL_LINK(OKHdl, Button*, void);
    DECL_LINK(FontSelectHdl, ListBox&, void);
    DECL_LINK(SubsetSelectHdl, ListBox&, void);
    DECL_LINK(CharDoubleClickHdl, SvxShowCharSet*,void);
@@ -92,6 +98,9 @@ private:
    DECL_LINK(CharPreSelectHdl, SvxShowCharSet*, void);
    DECL_LINK(DecimalCodeChangeHdl, Edit&, void);
    DECL_LINK(HexCodeChangeHdl, Edit&, void);
    DECL_LINK(RecentClickHdl, SvxCharView*, void);
    DECL_LINK(InsertClickHdl, Button*, void);
    DECL_STATIC_LINK(SvxCharacterMap, LoseFocusHdl, Control&, void);

    static void fillAllSubsets(ListBox &rListBox);
    void selectCharByCode(Radix radix);
@@ -99,6 +108,7 @@ private:
public:
                    SvxCharacterMap( vcl::Window* pParent, bool bOne=true, const SfxItemSet* pSet=nullptr );
    virtual         ~SvxCharacterMap() override;
    virtual short Execute() override;
    virtual void    dispose() override;

    void            DisableFontSelection();
@@ -109,9 +119,11 @@ public:
    void            SetChar( sal_UCS4 );
    sal_UCS4        GetChar() const;

    OUString        GetCharacters() const;
    void            getRecentCharacterList(); //gets both recent char and recent char font list
    void            updateRecentCharacterList(const OUString& rChar, const OUString& rFont);

    virtual short   Execute() override;
    void            updateRecentCharControl();
    void            insertCharToDoc(const OUString& sChar);
};

#endif
diff --git a/cui/uiconfig/ui/specialcharacters.ui b/cui/uiconfig/ui/specialcharacters.ui
index 80ec3d2..130f564 100644
--- a/cui/uiconfig/ui/specialcharacters.ui
+++ b/cui/uiconfig/ui/specialcharacters.ui
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.19.0 -->
<!-- Generated with glade 3.18.3 -->
<interface>
  <requires lib="gtk+" version="3.0"/>
  <requires lib="LibreOffice" version="1.0"/>
@@ -140,44 +140,6 @@
              </packing>
            </child>
            <child>
              <object class="GtkBox" id="box2">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="spacing">12</property>
                <child>
                  <object class="GtkLabel" id="symboltext">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="valign">center</property>
                    <property name="label" translatable="yes">Characters:</property>
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">True</property>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="showtext">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="valign">center</property>
                    <property name="invisible_char">•</property>
                  </object>
                  <packing>
                    <property name="expand">True</property>
                    <property name="fill">True</property>
                    <property name="position">1</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">2</property>
                <property name="width">2</property>
              </packing>
            </child>
            <child>
              <object class="svxlo-SvxShowCharSet" id="showcharset">
                <property name="width_request">580</property>
                <property name="height_request">250</property>
@@ -221,8 +183,8 @@
                      <object class="GtkLabel" id="hexlabel">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">Hexadecimal:</property>
                        <property name="xalign">0</property>
                        <property name="label" translatable="yes">Hexadecimal:</property>
                      </object>
                      <packing>
                        <property name="left_attach">0</property>
@@ -240,7 +202,7 @@
                            <property name="can_focus">True</property>
                            <property name="halign">center</property>
                            <property name="width_chars">8</property>
                            <property name="text" translatable="no">A2</property>
                            <property name="text">A2</property>
                          </object>
                          <packing>
                            <property name="left_attach">1</property>
@@ -251,7 +213,7 @@
                          <object class="GtkLabel" id="hexulabel">
                            <property name="visible">True</property>
                            <property name="can_focus">False</property>
                            <property name="label" translatable="no">U+</property>
                            <property name="label">U+</property>
                            <property name="width_chars">3</property>
                            <property name="single_line_mode">True</property>
                            <property name="max_width_chars">3</property>
@@ -272,8 +234,8 @@
                      <object class="GtkLabel" id="decimallabel">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">Decimal:</property>
                        <property name="xalign">0</property>
                        <property name="label" translatable="yes">Decimal:</property>
                      </object>
                      <packing>
                        <property name="left_attach">0</property>
@@ -304,6 +266,236 @@
                <property name="top_attach">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkBox" id="box1">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="orientation">vertical</property>
                <property name="spacing">12</property>
                <child>
                  <object class="GtkLabel" id="symboltext1">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="halign">start</property>
                    <property name="valign">start</property>
                    <property name="label" translatable="yes">Recent Characters:</property>
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkBox" id="box3">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar1">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar2">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">1</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar3">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">2</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar4">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">3</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar5">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">4</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar6">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">5</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar7">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">6</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar8">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">7</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar9">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">8</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar10">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">9</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar11">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">10</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar12">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">11</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar13">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">12</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar14">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">13</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar15">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">14</property>
                      </packing>
                    </child>
                    <child>
                      <object class="cuilo-SvxCharView" id="viewchar16">
                        <property name="width_request">40</property>
                        <property name="height_request">35</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">15</property>
                      </packing>
                    </child>
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">True</property>
                    <property name="position">1</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">2</property>
                <property name="width">2</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
diff --git a/extras/source/glade/libreoffice-catalog.xml.in b/extras/source/glade/libreoffice-catalog.xml.in
index 2b723ca..1ea0c98 100644
--- a/extras/source/glade/libreoffice-catalog.xml.in
+++ b/extras/source/glade/libreoffice-catalog.xml.in
@@ -815,6 +815,9 @@
    <glade-widget-class title="Show Text" name="cuilo-SvxShowText"
                        generic-name="ShowText" parent="GtkDrawingArea"
                        icon-name="widget-gtk-drawingarea"/>
    <glade-widget-class title="Char Win" name="cuilo-SvxCharView"
                        generic-name="ShowText" parent="GtkDrawingArea"
                        icon-name="widget-gtk-drawingarea"/>
    <glade-widget-class title="Notebook switching tabs depending on context" name="sfxlo-NotebookbarTabControl"
                        generic-name="NotebookbarTabControl" parent="GtkNotebook"
                        icon-name="widget-gtk-notebook"/>
diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
index 36c0b5f..6844e63 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
@@ -3476,6 +3476,23 @@
        <value/>
      </prop>
    </group>
    <group oor:name="RecentCharacters">
      <info>
        <desc>Contains recent characters</desc>
      </info>
      <prop oor:name="RecentCharacterList" oor:type="oor:string-list" oor:nillable="false">
        <info>
          <desc>List of Recent characters</desc>
        </info>
        <value/>
      </prop>
      <prop oor:name="RecentCharacterFontList" oor:type="oor:string-list" oor:nillable="false">
        <info>
          <desc>List of Recent character font</desc>
        </info>
        <value/>
      </prop>
    </group>
    <group oor:name="Help">
      <info>
        <desc>Contains settings that specify the common help settings.</desc>