summaryrefslogtreecommitdiffstats
path: root/cui/source/dialogs/cuicharmap.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'cui/source/dialogs/cuicharmap.cxx')
-rw-r--r--cui/source/dialogs/cuicharmap.cxx1283
1 files changed, 1283 insertions, 0 deletions
diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx
new file mode 100644
index 000000000..c6994000e
--- /dev/null
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -0,0 +1,1283 @@
+/* -*- 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 <sal/config.h>
+
+#include <stdio.h>
+
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+
+#include <rtl/textenc.h>
+#include <svx/ucsubset.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/fontcharmap.hxx>
+#include <vcl/virdev.hxx>
+#include <svl/stritem.hxx>
+#include <o3tl/temporary.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/dispatchcommand.hxx>
+
+#include <dialmgr.hxx>
+#include <cui/cuicharmap.hxx>
+#include <sfx2/app.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/editids.hrc>
+#include <editeng/fontitem.hxx>
+#include <strings.hrc>
+#include <unicode/uchar.h>
+#include <unicode/utypes.h>
+
+using namespace css;
+
+SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, const SfxItemSet* pSet,
+ css::uno::Reference<css::frame::XFrame> xFrame)
+ : SfxDialogController(pParent, "cui/ui/specialcharacters.ui", "SpecialCharactersDialog")
+ , 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_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"))
+ , m_xFontLB(m_xBuilder->weld_combo_box("fontlb"))
+ , m_xSubsetText(m_xBuilder->weld_label("subsetft"))
+ , m_xSubsetLB(m_xBuilder->weld_combo_box("subsetlb"))
+ , m_xSearchText(m_xBuilder->weld_entry("search"))
+ , m_xHexCodeText(m_xBuilder->weld_entry("hexvalue"))
+ , 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))
+ , m_xSearchSetArea(new weld::CustomWeld(*m_xBuilder, "searchcharset", *m_xSearchSet))
+{
+ m_aShowChar.SetCentered(true);
+ m_xFontLB->make_sorted();
+ //lock the size request of this widget to the width of all possible entries
+ fillAllSubsets(*m_xSubsetLB);
+ m_xSubsetLB->set_size_request(m_xSubsetLB->get_preferred_size().Width(), -1);
+ 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();
+
+ const SfxInt32Item* pCharItem = SfxItemSet::GetItem<SfxInt32Item>(pSet, SID_ATTR_CHAR, false);
+ if ( pCharItem )
+ SetChar( pCharItem->GetValue() );
+
+ const SfxBoolItem* pDisableItem = SfxItemSet::GetItem<SfxBoolItem>(pSet, FN_PARAM_2, false);
+ if ( pDisableItem && pDisableItem->GetValue() )
+ DisableFontSelection();
+
+ const SvxFontItem* pFontItem = SfxItemSet::GetItem<SvxFontItem>(pSet, SID_ATTR_CHAR_FONT, false);
+ const SfxStringItem* pFontNameItem = SfxItemSet::GetItem<SfxStringItem>(pSet, SID_FONT_NAME, false);
+ if ( pFontItem )
+ {
+ vcl::Font aTmpFont( pFontItem->GetFamilyName(), pFontItem->GetStyleName(), GetCharFont().GetFontSize() );
+ aTmpFont.SetCharSet( pFontItem->GetCharSet() );
+ aTmpFont.SetPitch( pFontItem->GetPitch() );
+ SetCharFont( aTmpFont );
+ }
+ else if ( pFontNameItem )
+ {
+ vcl::Font aTmpFont( GetCharFont() );
+ aTmpFont.SetFamilyName( pFontNameItem->GetValue() );
+ SetCharFont( aTmpFont );
+ }
+
+ m_xOutputSet.reset(new SfxAllItemSet(pSet ? *pSet->GetPool() : SfxGetpApp()->GetPool()));
+ m_xShowSet->Show();
+ m_xSearchSet->Hide();
+}
+
+short SvxCharacterMap::run()
+{
+ if( SvxShowCharSet::getSelectedChar() == ' ')
+ {
+ m_xOKBtn->set_sensitive(false);
+ setFavButtonState(u"", u"");
+ }
+ else
+ {
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+ // using the new UCS4 constructor
+ OUString aOUStr( &cChar, 1 );
+ m_aShowChar.SetText(aOUStr);
+
+ setFavButtonState(aOUStr, m_aShowChar.GetFont().GetFamilyName());
+ m_xOKBtn->set_sensitive(true);
+ }
+
+ return SfxDialogController::run();
+}
+
+void SvxCharacterMap::SetChar( sal_UCS4 c )
+{
+ m_xShowSet->SelectCharacter( c );
+ setFavButtonState(OUString(&c, 1), aFont.GetFamilyName());
+}
+
+sal_UCS4 SvxCharacterMap::GetChar() const
+{
+ return m_aShowChar.GetText().iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
+}
+
+void SvxCharacterMap::DisableFontSelection()
+{
+ m_xFontText->set_sensitive(false);
+ 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());
+
+ if (auto it1 = std::find(rContainer1.begin(), rContainer1.end(), str1);
+ it1 != rContainer1.end())
+ {
+ 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
+{
+ 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();
+ aFont.SetTransparent( true );
+ aFont.SetFamily( FAMILY_DONTKNOW );
+ aFont.SetPitch( PITCH_DONTKNOW );
+ aFont.SetCharSet( RTL_TEXTENCODING_DONTKNOW );
+
+ OUString aDefStr( aFont.GetFamilyName() );
+ OUString aLastName;
+ int nCount = m_xVirDev->GetFontFaceCollectionCount();
+ std::vector<weld::ComboBoxEntry> aEntries;
+ aEntries.reserve(nCount);
+ for (int i = 0; i < nCount; ++i)
+ {
+ OUString aFontName( m_xVirDev->GetFontMetricFromCollection( i ).GetFamilyName() );
+ if (aFontName != aLastName)
+ {
+ aLastName = aFontName;
+ aEntries.emplace_back(aFontName, OUString::number(i));
+ }
+ }
+ m_xFontLB->insert_vector(aEntries, true);
+ // 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_xFontLB->find_text(aDefStr) != -1);
+ if (!bFound)
+ {
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OUString aToken = aDefStr.getToken(0, ';', nIndex);
+ if (m_xFontLB->find_text(aToken) != -1)
+ {
+ aDefStr = aToken;
+ bFound = true;
+ break;
+ }
+ }
+ while ( nIndex >= 0 );
+ }
+
+ if (bFound)
+ m_xFontLB->set_active_text(aDefStr);
+ else if (m_xFontLB->get_count() )
+ m_xFontLB->set_active(0);
+ FontSelectHdl(*m_xFontLB);
+ if (m_xSubsetLB->get_count())
+ m_xSubsetLB->set_active(0);
+
+ m_xFontLB->connect_changed(LINK( this, SvxCharacterMap, FontSelectHdl));
+ m_xSubsetLB->connect_changed(LINK( this, SvxCharacterMap, SubsetSelectHdl));
+ m_xOKBtn->connect_clicked(LINK(this, SvxCharacterMap, InsertClickHdl));
+ m_xOKBtn->show();
+
+ m_xShowSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) );
+ m_xShowSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) );
+ m_xShowSet->SetHighlightHdl( LINK( this, SvxCharacterMap, CharHighlightHdl ) );
+ m_xShowSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) );
+ m_xShowSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
+
+ m_xSearchSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, SearchCharDoubleClickHdl ) );
+ m_xSearchSet->SetSelectHdl( LINK( this, SvxCharacterMap, SearchCharSelectHdl ) );
+ m_xSearchSet->SetHighlightHdl( LINK( this, SvxCharacterMap, SearchCharHighlightHdl ) );
+ m_xSearchSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, SearchCharPreSelectHdl ) );
+ m_xSearchSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
+
+ m_xDecimalCodeText->connect_changed( LINK( this, SvxCharacterMap, DecimalCodeChangeHdl ) );
+ m_xHexCodeText->connect_changed( LINK( this, SvxCharacterMap, HexCodeChangeHdl ) );
+ m_xFavouritesBtn->connect_clicked( LINK(this, SvxCharacterMap, FavSelectHdl));
+
+ // tdf#117038 set the buttons width to its max possible width so it doesn't
+ // make layout change when the label changes
+ m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_REMOVE_FAVORITES));
+ auto nMaxWidth = m_xFavouritesBtn->get_preferred_size().Width();
+ m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_ADD_FAVORITES));
+ nMaxWidth = std::max(nMaxWidth, m_xFavouritesBtn->get_preferred_size().Width());
+ m_xFavouritesBtn->set_size_request(nMaxWidth, -1);
+
+ if( SvxShowCharSet::getSelectedChar() == ' ')
+ {
+ m_xOKBtn->set_sensitive(false);
+ }
+ else
+ {
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+ // using the new UCS4 constructor
+ OUString aOUStr( &cChar, 1 );
+ m_aShowChar.SetText(aOUStr);
+
+ setFavButtonState(aOUStr, aDefStr);
+ 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));
+ }
+
+ setCharName(90);
+
+ m_xSearchText->connect_focus_in(LINK( this, SvxCharacterMap, SearchFieldGetFocusHdl ));
+ 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())
+ {
+ m_xFavouritesBtn->set_sensitive(false);
+ return;
+ }
+ else
+ m_xFavouritesBtn->set_sensitive(true);
+
+ if (isFavChar(sTitle, rFont))
+ {
+ m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_REMOVE_FAVORITES));
+ }
+ else
+ {
+ if(maFavCharList.size() == 16)
+ {
+ m_xFavouritesBtn->set_sensitive(false);
+ }
+
+ m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_ADD_FAVORITES));
+ }
+}
+
+
+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(m_xVirDev->GetFontMetric(rFont));
+
+ // tdf#56363 - search font family without the font feature after the colon
+ OUString sFontFamilyName = aTmp.GetFamilyName();
+ if (const sal_Int32 nIndex = sFontFamilyName.indexOf(":"); nIndex != -1)
+ sFontFamilyName = sFontFamilyName.copy(0, nIndex);
+ if (sFontFamilyName == "StarSymbol" && m_xFontLB->find_text(sFontFamilyName) == -1)
+ {
+ //if for some reason, like font in an old document, StarSymbol is requested and it's not available, then
+ //try OpenSymbol instead
+ aTmp.SetFamilyName("OpenSymbol");
+ }
+
+ if (m_xFontLB->find_text(sFontFamilyName) == -1)
+ return;
+
+ m_xFontLB->set_active_text(sFontFamilyName);
+ aFont = aTmp;
+ FontSelectHdl(*m_xFontLB);
+ if (m_xSubsetLB->get_count())
+ m_xSubsetLB->set_active(0);
+}
+
+void SvxCharacterMap::fillAllSubsets(weld::ComboBox& rListBox)
+{
+ SubsetMap aAll(nullptr);
+ std::vector<weld::ComboBoxEntry> aEntries;
+ for (auto & subset : aAll.GetSubsetMap())
+ aEntries.emplace_back(subset.GetName());
+ rListBox.insert_vector(aEntries, true);
+}
+
+void SvxCharacterMap::insertCharToDoc(const OUString& sGlyph)
+{
+ if(sGlyph.isEmpty())
+ return;
+
+ if (m_xFrame.is()) {
+ uno::Sequence<beans::PropertyValue> aArgs{
+ comphelper::makePropertyValue("Symbols", sGlyph),
+ comphelper::makePropertyValue("FontName", aFont.GetFamilyName())
+ };
+ comphelper::dispatchCommand(".uno:InsertSymbol", m_xFrame, aArgs);
+
+ updateRecentCharacterList(sGlyph, aFont.GetFamilyName());
+
+ } else {
+ sal_UCS4 cChar = sGlyph.iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
+ const SfxItemPool* pPool = m_xOutputSet->GetPool();
+ m_xOutputSet->Put( SfxStringItem( SID_CHARMAP, sGlyph ) );
+ m_xOutputSet->Put( SvxFontItem( aFont.GetFamilyType(), aFont.GetFamilyName(),
+ aFont.GetStyleName(), aFont.GetPitch(), aFont.GetCharSet(), pPool->GetWhich(SID_ATTR_CHAR_FONT) ) );
+ m_xOutputSet->Put( SfxStringItem( SID_FONT_NAME, aFont.GetFamilyName() ) );
+ m_xOutputSet->Put( SfxInt32Item( SID_ATTR_CHAR, cChar ) );
+ }
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, weld::ComboBox&, void)
+{
+ const sal_uInt32 nFont = m_xFontLB->get_active_id().toUInt32();
+ aFont = m_xVirDev->GetFontMetricFromCollection(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_xShowSet->SetFont( aFont );
+ m_xSearchSet->SetFont( aFont );
+ m_aShowChar.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
+ pSubsetMap.reset();
+ m_xSubsetLB->clear();
+
+ bool bNeedSubset = (aFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL);
+ if (bNeedSubset)
+ {
+ FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap();
+ pSubsetMap.reset(new SubsetMap( xFontCharMap ));
+
+ // update subset listbox for new font's unicode subsets
+ for (auto const& subset : pSubsetMap->GetSubsetMap())
+ {
+ m_xSubsetLB->append(weld::toId(&subset), subset.GetName());
+ // NOTE: subset must live at least as long as the selected font
+ }
+
+ if (m_xSubsetLB->get_count() <= 1)
+ bNeedSubset = false;
+ }
+
+ m_xSubsetText->set_sensitive(bNeedSubset);
+ m_xSubsetLB->set_sensitive(bNeedSubset);
+
+ if (isSearchMode)
+ {
+ // tdf#137294 do this after modifying m_xSubsetLB sensitivity to
+ // restore insensitive for the search case
+ SearchUpdateHdl(*m_xSearchText);
+ SearchCharHighlightHdl(m_xSearchSet.get());
+ }
+
+ // tdf#118304 reselect current glyph to see if it's still there in new font
+ selectCharByCode(Radix::hexadecimal);
+}
+
+void SvxCharacterMap::toggleSearchView(bool state)
+{
+ isSearchMode = state;
+ m_xHexCodeText->set_editable(!state);
+ m_xDecimalCodeText->set_editable(!state);
+ m_xSubsetLB->set_sensitive(!state);
+
+ if(state)
+ {
+ m_xSearchSet->Show();
+ m_xShowSet->Hide();
+ }
+ else
+ {
+ m_xSearchSet->Hide();
+ m_xShowSet->Show();
+ }
+}
+
+void SvxCharacterMap::setCharName(sal_UCS4 nDecimalValue)
+{
+ /* get the character name */
+ UErrorCode errorCode = U_ZERO_ERROR;
+ // icu has a private uprv_getMaxCharNameLength function which returns the max possible
+ // length of this property. Unicode 3.2 max char name length was 83
+ char buffer[100];
+ u_charName(nDecimalValue, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
+ if (U_SUCCESS(errorCode))
+ m_xCharName->set_label(OUString::createFromAscii(buffer));
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SubsetSelectHdl, weld::ComboBox&, void)
+{
+ const sal_Int32 nPos = m_xSubsetLB->get_active();
+ const Subset* pSubset = weld::fromId<const Subset*>(m_xSubsetLB->get_active_id());
+
+ if( pSubset && !isSearchMode)
+ {
+ sal_UCS4 cFirst = pSubset->GetRangeMin();
+ m_xShowSet->SelectCharacter( cFirst );
+
+ setFavButtonState(OUString(&cFirst, 1), aFont.GetFamilyName());
+ m_xSubsetLB->set_active(nPos);
+ }
+ else if( pSubset && isSearchMode)
+ {
+ m_xSearchSet->SelectCharacter( pSubset );
+
+ const Subset* curSubset = nullptr;
+ if( pSubsetMap )
+ curSubset = pSubsetMap->GetSubsetByUnicode( m_xSearchSet->GetSelectCharacter() );
+ if( curSubset )
+ m_xSubsetLB->set_active_text(curSubset->GetName());
+ else
+ m_xSubsetLB->set_active(-1);
+
+ sal_UCS4 sChar = m_xSearchSet->GetSelectCharacter();
+ setFavButtonState(OUString(&sChar, 1), aFont.GetFamilyName());
+ }
+}
+
+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);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchUpdateHdl, weld::Entry&, void)
+{
+ if (!m_xSearchText->get_text().isEmpty())
+ {
+ m_xSearchSet->ClearPreviousData();
+ OUString aKeyword = m_xSearchText->get_text();
+
+ toggleSearchView(true);
+
+ FontCharMapRef xFontCharMap = m_xSearchSet->GetFontCharMap();
+
+ sal_UCS4 sChar = xFontCharMap->GetFirstChar();
+ while(sChar != xFontCharMap->GetLastChar())
+ {
+ UErrorCode errorCode = U_ZERO_ERROR;
+ char buffer[100];
+ u_charName(sChar, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
+ if (U_SUCCESS(errorCode))
+ {
+ OUString sName = OUString::createFromAscii(buffer);
+ if(!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword.toAsciiLowerCase()) >= 0)
+ m_xSearchSet->AppendCharToList(sChar);
+ }
+ sChar = xFontCharMap->GetNextChar(sChar);
+ }
+ //for last char
+ UErrorCode errorCode = U_ZERO_ERROR;
+ char buffer[100];
+ u_charName(sChar, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
+ if (U_SUCCESS(errorCode))
+ {
+ OUString sName = OUString::createFromAscii(buffer);
+ if(!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword.toAsciiLowerCase()) >= 0)
+ m_xSearchSet->AppendCharToList(sChar);
+ }
+
+ m_xSearchSet->UpdateScrollRange();
+ }
+ else
+ {
+ toggleSearchView(false);
+ }
+}
+
+
+IMPL_LINK(SvxCharacterMap, CharClickHdl, SvxCharView*, rView, void)
+{
+ rView->GrabFocus();
+
+ m_aShowChar.SetText( rView->GetText() );
+ m_aShowChar.SetFont(rView->GetFont());
+ m_aShowChar.Invalidate();
+
+ setFavButtonState(rView->GetText(), rView->GetFont().GetFamilyName());//check state
+
+ // Get the hexadecimal code
+ OUString charValue = rView->GetText();
+ sal_UCS4 cChar = charValue.iterateCodePoints(&o3tl::temporary(sal_Int32(1)), -1);
+ OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
+
+ // Get the decimal code
+ OUString aDecimalText = OUString::number(cChar);
+
+ m_xHexCodeText->set_text(aHexText);
+ m_xDecimalCodeText->set_text(aDecimalText);
+ setCharName(cChar);
+
+ rView->Invalidate();
+ m_xOKBtn->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, CharDoubleClickHdl, SvxShowCharSet*, void)
+{
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+ // using the new UCS4 constructor
+ OUString aOUStr( &cChar, 1 );
+ setFavButtonState(aOUStr, aFont.GetFamilyName());
+ insertCharToDoc(aOUStr);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchCharDoubleClickHdl, SvxShowCharSet*, void)
+{
+ sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
+ // using the new UCS4 constructor
+ OUString aOUStr( &cChar, 1 );
+ setFavButtonState(aOUStr, aFont.GetFamilyName());
+ insertCharToDoc(aOUStr);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, CharSelectHdl, SvxShowCharSet*, void)
+{
+ m_xOKBtn->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchCharSelectHdl, SvxShowCharSet*, void)
+{
+ m_xOKBtn->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, weld::Button&, void)
+{
+ OUString sChar = m_aShowChar.GetText();
+ insertCharToDoc(sChar);
+ // Need to update recent character list, when OK button does not insert
+ if(!m_xFrame.is())
+ updateRecentCharacterList(sChar, aFont.GetFamilyName());
+ m_xDialog->response(RET_OK);
+}
+
+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());
+ setFavButtonState(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
+ }
+ else
+ {
+ deleteFavCharacterFromList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
+ m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_ADD_FAVORITES));
+ m_xFavouritesBtn->set_sensitive(false);
+ }
+
+ updateFavCharControl();
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, FavClickHdl, SvxShowCharSet*, void)
+{
+ getFavCharacterList();
+ updateFavCharControl();
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, CharHighlightHdl, SvxShowCharSet*, void)
+{
+ OUString aText;
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+ bool bSelect = (cChar > 0);
+
+ // show char sample
+ if ( bSelect )
+ {
+ // using the new UCS4 constructor
+ aText = OUString( &cChar, 1 );
+ // Get the hexadecimal code
+ OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
+ // Get the decimal code
+ OUString aDecimalText = OUString::number(cChar);
+ setCharName(cChar);
+
+ // Update the hex and decimal codes only if necessary
+ if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
+ m_xHexCodeText->set_text(aHexText);
+ if (m_xDecimalCodeText->get_text() != aDecimalText)
+ m_xDecimalCodeText->set_text( aDecimalText );
+
+ const Subset* pSubset = nullptr;
+ if( pSubsetMap )
+ pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
+ if( pSubset )
+ m_xSubsetLB->set_active_text(pSubset->GetName());
+ else
+ m_xSubsetLB->set_active(-1);
+ }
+
+ m_aShowChar.SetText( aText );
+ m_aShowChar.SetFont( aFont );
+ m_aShowChar.Invalidate();
+
+ setFavButtonState(aText, aFont.GetFamilyName());
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchCharHighlightHdl, SvxShowCharSet*, void)
+{
+ OUString aText;
+ sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
+ bool bSelect = (cChar > 0);
+
+ // show char sample
+ if ( bSelect )
+ {
+ aText = OUString( &cChar, 1 );
+ // Get the hexadecimal code
+ OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
+ // Get the decimal code
+ OUString aDecimalText = OUString::number(cChar);
+ setCharName(cChar);
+
+ // Update the hex and decimal codes only if necessary
+ if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
+ m_xHexCodeText->set_text(aHexText);
+ if (m_xDecimalCodeText->get_text() != aDecimalText)
+ m_xDecimalCodeText->set_text( aDecimalText );
+
+ const Subset* pSubset = nullptr;
+ if( pSubsetMap )
+ pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
+ if( pSubset )
+ m_xSubsetLB->set_active_text(pSubset->GetName());
+ else
+ m_xSubsetLB->set_active(-1);
+ }
+
+ if(m_xSearchSet->HasFocus())
+ {
+ m_aShowChar.SetText( aText );
+ m_aShowChar.SetFont( aFont );
+ m_aShowChar.Invalidate();
+
+ setFavButtonState(aText, aFont.GetFamilyName());
+ }
+}
+
+void SvxCharacterMap::selectCharByCode(Radix radix)
+{
+ OUString aCodeString;
+ switch(radix)
+ {
+ case Radix::decimal:
+ aCodeString = m_xDecimalCodeText->get_text();
+ break;
+ case Radix::hexadecimal:
+ aCodeString = m_xHexCodeText->get_text();
+ 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 = m_xShowSet->GetFontCharMap();
+ if (xFontCharMap->HasChar(cChar))
+ // Select the corresponding character
+ SetChar(cChar);
+ else {
+ m_xCharName->set_label(CuiResId(RID_CUISTR_MISSING_CHAR));
+ m_aShowChar.SetText(" ");
+ switch(radix)
+ {
+ case Radix::decimal:
+ m_xHexCodeText->set_text(OUString::number(cChar, 16));
+ break;
+ case Radix::hexadecimal:
+ m_xDecimalCodeText->set_text(OUString::number(cChar));
+ break;
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, DecimalCodeChangeHdl, weld::Entry&, void)
+{
+ selectCharByCode(Radix::decimal);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, HexCodeChangeHdl, weld::Entry&, void)
+{
+ selectCharByCode(Radix::hexadecimal);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, CharPreSelectHdl, SvxShowCharSet*, void)
+{
+ // adjust subset selection
+ if( pSubsetMap )
+ {
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+
+ setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName());
+ const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
+ if( pSubset )
+ m_xSubsetLB->set_active_text(pSubset->GetName());
+ }
+
+ m_xOKBtn->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchCharPreSelectHdl, SvxShowCharSet*, void)
+{
+ // adjust subset selection
+ if( pSubsetMap )
+ {
+ sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
+
+ setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName());
+ const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
+ if( pSubset )
+ m_xSubsetLB->set_active_text(pSubset->GetName());
+ }
+
+ m_xOKBtn->set_sensitive(true);
+}
+
+// class SvxShowText =====================================================
+SvxShowText::SvxShowText(const VclPtr<VirtualDevice>& rVirDev)
+ : m_xVirDev(rVirDev)
+ , mnY(0)
+ , mbCenter(false)
+{
+}
+
+void SvxShowText::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ vcl::Font aFont = m_xVirDev->GetFont();
+ Size aFontSize(aFont.GetFontSize().Width() * 5, aFont.GetFontSize().Height() * 5);
+ aFont.SetFontSize(aFontSize);
+ m_xVirDev->Push(PUSH_ALLFONT);
+ m_xVirDev->SetFont(aFont);
+ pDrawingArea->set_size_request(m_xVirDev->approximate_digit_width() + 2 * 12,
+ m_xVirDev->LogicToPixel(aFontSize).Height() * 2);
+ m_xVirDev->Pop();
+}
+
+void SvxShowText::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.SetFont(m_aFont);
+
+ Color aTextCol = rRenderContext.GetTextColor();
+ Color aFillCol = rRenderContext.GetFillColor();
+ Color aLineCol = rRenderContext.GetLineColor();
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Color aWindowTextColor(rStyleSettings.GetDialogTextColor());
+ const Color aWindowColor(rStyleSettings.GetWindowColor());
+ const Color aShadowColor(rStyleSettings.GetShadowColor());
+ rRenderContext.SetTextColor(aWindowTextColor);
+ rRenderContext.SetFillColor(aWindowColor);
+
+ const OUString aText = GetText();
+
+ Size aSize(GetOutputSizePixel());
+ tools::Long nAvailWidth = aSize.Width();
+ tools::Long nWinHeight = aSize.Height();
+
+ bool bGotBoundary = true;
+ bool bShrankFont = false;
+ vcl::Font aOrigFont(rRenderContext.GetFont());
+ Size aFontSize(aOrigFont.GetFontSize());
+ ::tools::Rectangle aBoundRect;
+
+ for (tools::Long nFontHeight = aFontSize.Height(); nFontHeight > 0; nFontHeight -= 5)
+ {
+ if (!rRenderContext.GetTextBoundRect( aBoundRect, aText ) || aBoundRect.IsEmpty())
+ {
+ bGotBoundary = false;
+ break;
+ }
+ if (!mbCenter)
+ break;
+ //only shrink in the single glyph large view mode
+ tools::Long nTextWidth = aBoundRect.GetWidth();
+ if (nAvailWidth > nTextWidth)
+ break;
+ vcl::Font aFont(aOrigFont);
+ aFontSize.setHeight( nFontHeight );
+ aFont.SetFontSize(aFontSize);
+ rRenderContext.SetFont(aFont);
+ mnY = (nWinHeight - rRenderContext.GetTextHeight()) / 2;
+ bShrankFont = true;
+ }
+
+ Point aPoint(2, mnY);
+ // adjust position using ink boundary if possible
+ if (!bGotBoundary)
+ aPoint.setX( (aSize.Width() - rRenderContext.GetTextWidth(aText)) / 2 );
+ else
+ {
+ // adjust position before it gets out of bounds
+ aBoundRect += aPoint;
+
+ // shift back vertically if needed
+ int nYLDelta = aBoundRect.Top();
+ int nYHDelta = aSize.Height() - aBoundRect.Bottom();
+ if( nYLDelta <= 0 )
+ aPoint.AdjustY( -(nYLDelta - 1) );
+ else if( nYHDelta <= 0 )
+ aPoint.AdjustY(nYHDelta - 1 );
+
+ if (mbCenter)
+ {
+ // move glyph to middle of cell
+ aPoint.setX( -aBoundRect.Left() + (aSize.Width() - aBoundRect.GetWidth()) / 2 );
+ }
+ else
+ {
+ // shift back horizontally if needed
+ int nXLDelta = aBoundRect.Left();
+ int nXHDelta = aSize.Width() - aBoundRect.Right();
+ if( nXLDelta <= 0 )
+ aPoint.AdjustX( -(nXLDelta - 1) );
+ else if( nXHDelta <= 0 )
+ aPoint.AdjustX(nXHDelta - 1 );
+ }
+ }
+
+ rRenderContext.SetLineColor(aShadowColor);
+ rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), aSize));
+ rRenderContext.DrawText(aPoint, aText);
+ rRenderContext.SetTextColor(aTextCol);
+ rRenderContext.SetFillColor(aFillCol);
+ rRenderContext.SetLineColor(aLineCol);
+ if (bShrankFont)
+ rRenderContext.SetFont(aOrigFont);
+}
+
+void SvxShowText::SetFont( const vcl::Font& rFont )
+{
+ tools::Long nWinHeight = GetOutputSizePixel().Height();
+
+ m_aFont = rFont;
+ m_aFont.SetWeight(WEIGHT_NORMAL);
+ m_aFont.SetAlignment(ALIGN_TOP);
+ m_aFont.SetFontSize(m_xVirDev->PixelToLogic(Size(0, nWinHeight / 2)));
+ m_aFont.SetTransparent(true);
+
+ m_xVirDev->Push(PUSH_ALLFONT);
+ m_xVirDev->SetFont(m_aFont);
+ mnY = (nWinHeight - m_xVirDev->GetTextHeight()) / 2;
+ m_xVirDev->Pop();
+
+ Invalidate();
+}
+
+void SvxShowText::Resize()
+{
+ SetFont(GetFont()); //force recalculation of size
+}
+
+void SvxShowText::SetText(const OUString& rText)
+{
+ m_sText = rText;
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */