1
0
Fork 0
libreoffice/svx/source/dialog/cuicharmap.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

900 lines
31 KiB
C++

/* -*- 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/string_view.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 <svx/dialmgr.hxx>
#include <svx/cuicharmap.hxx>
#include <svx/strings.hrc>
#include <sfx2/app.hxx>
#include <svx/svxids.hrc>
#include <editeng/editids.hrc>
#include <editeng/fontitem.hxx>
#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, u"cui/ui/specialcharacters.ui"_ustr, u"SpecialCharactersDialog"_ustr)
, m_xVirDev(VclPtr<VirtualDevice>::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(u"insert"_ustr) : m_xBuilder->weld_button(u"ok"_ustr))
, m_xFontText(m_xBuilder->weld_label(u"fontft"_ustr))
, m_xFontLB(m_xBuilder->weld_combo_box(u"fontlb"_ustr))
, m_xSubsetText(m_xBuilder->weld_label(u"subsetft"_ustr))
, m_xSubsetLB(m_xBuilder->weld_combo_box(u"subsetlb"_ustr))
, m_xSearchText(m_xBuilder->weld_entry(u"search"_ustr))
, m_xHexCodeText(m_xBuilder->weld_entry(u"hexvalue"_ustr))
, m_xDecimalCodeText(m_xBuilder->weld_entry(u"decimalvalue"_ustr))
, m_xFavouritesBtn(m_xBuilder->weld_button(u"favbtn"_ustr))
, m_xCharName(m_xBuilder->weld_label(u"charname"_ustr))
, m_xShowChar(new weld::CustomWeld(*m_xBuilder, u"showchar"_ustr, m_aShowChar))
, m_xShowSet(new SvxShowCharSet(m_xBuilder->weld_scrolled_window(u"showscroll"_ustr, true), m_xVirDev))
, m_xShowSetArea(new weld::CustomWeld(*m_xBuilder, u"showcharset"_ustr, *m_xShowSet))
, m_xSearchSet(new SvxSearchCharSet(m_xBuilder->weld_scrolled_window(u"searchscroll"_ustr, true), m_xVirDev))
, m_xSearchSetArea(new weld::CustomWeld(*m_xBuilder, u"searchcharset"_ustr, *m_xSearchSet))
{
m_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<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();
}
void SvxCharacterMap::prepForRun()
{
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);
}
}
short SvxCharacterMap::run()
{
prepForRun();
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<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->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(SvxResId(RID_SVXSTR_REMOVE_FAVORITES));
auto nMaxWidth = m_xFavouritesBtn->get_preferred_size().Width();
m_xFavouritesBtn->set_label(SvxResId(RID_SVXSTR_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<void*, void>());
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(SvxResId(RID_SVXSTR_REMOVE_FAVORITES));
}
else
{
if (m_aCharmapContents.FavCharListIsFull())
m_xFavouritesBtn->set_sensitive(false);
m_xFavouritesBtn->set_label(SvxResId(RID_SVXSTR_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(u"OpenSymbol"_ustr);
}
if (m_xFontLB->find_text(sFontFamilyName) == -1)
return;
m_xFontLB->set_active_text(sFontFamilyName);
aFont = std::move(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(u"Symbols"_ustr, sGlyph),
comphelper::makePropertyValue(u"FontName"_ustr, aFont.GetFamilyName())
};
comphelper::dispatchCommand(u".uno:InsertSymbol"_ustr, 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->GetWhichIDFromSlotID(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_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().trim().toAsciiLowerCase();
OUString hex_code;
if (std::u16string_view rest; aKeyword.startsWith("u+", &rest))
if (auto n = o3tl::toInt32(rest, 16))
hex_code = OUString::number(n, 16); // this removes leading zeroes
toggleSearchView(true);
FontCharMapRef xFontCharMap = m_xSearchSet->GetFontCharMap();
for (sal_UCS4 ucs4 = xFontCharMap->GetFirstChar();; ucs4 = xFontCharMap->GetNextChar(ucs4))
{
bool bAdded = false;
UErrorCode errorCode = U_ZERO_ERROR;
char buffer[100];
u_charName(ucs4, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
if (U_SUCCESS(errorCode))
{
OUString sName = OUString::createFromAscii(buffer);
if (!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword) >= 0)
{
m_xSearchSet->AppendCharToList(ucs4);
bAdded = true;
}
}
if (!bAdded && !hex_code.isEmpty())
{
OUString actual_number = OUString::number(ucs4, 16);
if (actual_number.startsWith(hex_code))
m_xSearchSet->AppendCharToList(ucs4);
}
if (ucs4 == xFontCharMap->GetLastChar())
break;
}
m_xSearchSet->UpdateScrollRange();
}
else
{
toggleSearchView(false);
}
}
IMPL_LINK(SvxCharacterMap, CharClickHdl, SvxCharView*, rView, void)
{
rView->GrabFocus();
SetCharFont(rView->GetFont());
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(SvxResId(RID_SVXSTR_ADD_FAVORITES)))
{
m_aCharmapContents.updateFavCharacterList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
setFavButtonState(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
}
else
{
m_aCharmapContents.deleteFavCharacterFromList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
m_xFavouritesBtn->set_label(SvxResId(RID_SVXSTR_ADD_FAVORITES));
m_xFavouritesBtn->set_sensitive(false);
}
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<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(SvxResId(RID_SVXSTR_MISSING_CHAR));
m_aShowChar.SetText(u" "_ustr);
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<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: */