From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- cui/source/dialogs/cuicharmap.cxx | 890 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 890 insertions(+) create mode 100644 cui/source/dialogs/cuicharmap.cxx (limited to 'cui/source/dialogs/cuicharmap.cxx') diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx new file mode 100644 index 0000000000..03d1e8c90b --- /dev/null +++ b/cui/source/dialogs/cuicharmap.cxx @@ -0,0 +1,890 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace css; + +SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, const SfxItemSet* pSet, + css::uno::Reference xFrame) + : SfxDialogController(pParent, "cui/ui/specialcharacters.ui", "SpecialCharactersDialog") + , m_xVirDev(VclPtr::Create()) + , isSearchMode(true) + , m_xFrame(std::move(xFrame)) + , m_aCharmapContents(*m_xBuilder, m_xVirDev, true) + , 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_xShowChar(new weld::CustomWeld(*m_xBuilder, "showchar", m_aShowChar)) + , 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); + + init(); + + const SfxInt32Item* pCharItem = SfxItemSet::GetItem(pSet, SID_ATTR_CHAR, false); + if ( pCharItem ) + SetChar( pCharItem->GetValue() ); + + const SfxBoolItem* pDisableItem = SfxItemSet::GetItem(pSet, FN_PARAM_2, false); + if ( pDisableItem && pDisableItem->GetValue() ) + DisableFontSelection(); + + const SvxFontItem* pFontItem = SfxItemSet::GetItem(pSet, SID_ATTR_CHAR_FONT, false); + const SfxStringItem* pFontNameItem = SfxItemSet::GetItem(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); +} + +IMPL_LINK_NOARG(SvxCharacterMap, UpdateFavHdl, void*, void) +{ + m_xShowSet->getFavCharacterList(); + m_xSearchSet->getFavCharacterList(); + // tdf#109214 - redraw highlight of the favorite characters + m_xShowSet->Invalidate(); +} + +void SvxCharacterMap::init() +{ + aFont = m_xVirDev->GetFont(); + 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 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->SetReturnKeyPressHdl(LINK(this, SvxCharacterMap, ReturnKeypressOnCharHdl)); + m_xShowSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) ); + m_xShowSet->SetHighlightHdl( LINK( this, SvxCharacterMap, CharHighlightHdl ) ); + m_xShowSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) ); + m_xShowSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) ); + + m_xSearchSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) ); + m_xSearchSet->SetReturnKeyPressHdl(LINK(this, SvxCharacterMap, ReturnKeypressOnCharHdl)); + m_xSearchSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) ); + m_xSearchSet->SetHighlightHdl( LINK( this, SvxCharacterMap, SearchCharHighlightHdl ) ); + m_xSearchSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) ); + m_xSearchSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) ); + + m_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); + } + + m_aCharmapContents.init(m_xFrame.is(), + LINK(this, SvxCharacterMap, CharClickHdl), + LINK(this, SvxCharacterMap, UpdateFavHdl), + Link()); + + setCharName(90); + + m_xSearchText->connect_focus_in(LINK( this, SvxCharacterMap, SearchFieldGetFocusHdl )); + m_xSearchText->connect_changed(LINK(this, SvxCharacterMap, SearchUpdateHdl)); +} + +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 (m_aCharmapContents.isFavChar(sTitle, rFont)) + { + m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_REMOVE_FAVORITES)); + } + else + { + if (m_aCharmapContents.FavCharListIsFull()) + 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 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 aArgs{ + comphelper::makePropertyValue("Symbols", sGlyph), + comphelper::makePropertyValue("FontName", aFont.GetFamilyName()) + }; + comphelper::dispatchCommand(".uno:InsertSymbol", m_xFrame, aArgs); + + m_aCharmapContents.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(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_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); +} + +void SvxCharacterMap::insertSelectedCharacter(const SvxShowCharSet* pCharSet) +{ + assert(pCharSet); + sal_UCS4 cChar = pCharSet->GetSelectCharacter(); + // using the new UCS4 constructor + OUString aOUStr( &cChar, 1 ); + setFavButtonState(aOUStr, aFont.GetFamilyName()); + insertCharToDoc(aOUStr); +} + +IMPL_LINK(SvxCharacterMap, CharDoubleClickHdl, SvxShowCharSet*, pCharSet, void) +{ + insertSelectedCharacter(pCharSet); +} + +IMPL_LINK_NOARG(SvxCharacterMap, CharSelectHdl, SvxShowCharSet*, void) +{ + m_xOKBtn->set_sensitive(true); +} + +IMPL_LINK(SvxCharacterMap, ReturnKeypressOnCharHdl, SvxShowCharSet*, pCharSet, void) +{ + insertSelectedCharacter(pCharSet); + m_xDialog->response(RET_OK); +} + +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()) + m_aCharmapContents.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))) + { + m_aCharmapContents.updateFavCharacterList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName()); + setFavButtonState(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName()); + } + else + { + m_aCharmapContents.deleteFavCharacterFromList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName()); + m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_ADD_FAVORITES)); + m_xFavouritesBtn->set_sensitive(false); + } + + m_aCharmapContents.updateFavCharControl(); +} + +IMPL_LINK_NOARG(SvxCharacterMap, FavClickHdl, SvxShowCharSet*, void) +{ + m_aCharmapContents.getFavCharacterList(); + m_aCharmapContents.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 (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(SvxCharacterMap, CharPreSelectHdl, SvxShowCharSet*, pCharSet, void) +{ + assert(pCharSet); + // adjust subset selection + if( pSubsetMap ) + { + sal_UCS4 cChar = pCharSet->GetSelectCharacter(); + + setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName()); + const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar ); + if( pSubset ) + m_xSubsetLB->set_active_text(pSubset->GetName()); + } + + m_xOKBtn->set_sensitive(true); +} + +// class SvxShowText ===================================================== +SvxShowText::SvxShowText(const VclPtr& 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: */ -- cgit v1.2.3