Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / cui / source / dialogs / cuicharmap.cxx
blobc075c12326d2d4c8625886f9df77da2a377a1da1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <stdio.h>
24 #include <utility>
25 #include <vcl/svapp.hxx>
26 #include <svl/eitem.hxx>
27 #include <svl/intitem.hxx>
28 #include <svl/itempool.hxx>
30 #include <rtl/textenc.h>
31 #include <svx/ucsubset.hxx>
32 #include <vcl/settings.hxx>
33 #include <vcl/fontcharmap.hxx>
34 #include <vcl/virdev.hxx>
35 #include <svl/stritem.hxx>
36 #include <o3tl/temporary.hxx>
37 #include <officecfg/Office/Common.hxx>
38 #include <com/sun/star/beans/PropertyValue.hpp>
39 #include <comphelper/processfactory.hxx>
40 #include <comphelper/propertyvalue.hxx>
41 #include <comphelper/dispatchcommand.hxx>
43 #include <dialmgr.hxx>
44 #include <cui/cuicharmap.hxx>
45 #include <sfx2/app.hxx>
46 #include <svx/svxids.hrc>
47 #include <editeng/editids.hrc>
48 #include <editeng/fontitem.hxx>
49 #include <strings.hrc>
50 #include <unicode/uchar.h>
51 #include <unicode/utypes.h>
53 using namespace css;
55 SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, const SfxItemSet* pSet,
56 css::uno::Reference<css::frame::XFrame> xFrame)
57 : SfxDialogController(pParent, "cui/ui/specialcharacters.ui", "SpecialCharactersDialog")
58 , m_xVirDev(VclPtr<VirtualDevice>::Create())
59 , isSearchMode(true)
60 , m_xFrame(std::move(xFrame))
61 , m_aRecentCharView{SvxCharView(m_xVirDev),
62 SvxCharView(m_xVirDev),
63 SvxCharView(m_xVirDev),
64 SvxCharView(m_xVirDev),
65 SvxCharView(m_xVirDev),
66 SvxCharView(m_xVirDev),
67 SvxCharView(m_xVirDev),
68 SvxCharView(m_xVirDev),
69 SvxCharView(m_xVirDev),
70 SvxCharView(m_xVirDev),
71 SvxCharView(m_xVirDev),
72 SvxCharView(m_xVirDev),
73 SvxCharView(m_xVirDev),
74 SvxCharView(m_xVirDev),
75 SvxCharView(m_xVirDev),
76 SvxCharView(m_xVirDev)}
77 , m_aFavCharView{SvxCharView(m_xVirDev),
78 SvxCharView(m_xVirDev),
79 SvxCharView(m_xVirDev),
80 SvxCharView(m_xVirDev),
81 SvxCharView(m_xVirDev),
82 SvxCharView(m_xVirDev),
83 SvxCharView(m_xVirDev),
84 SvxCharView(m_xVirDev),
85 SvxCharView(m_xVirDev),
86 SvxCharView(m_xVirDev),
87 SvxCharView(m_xVirDev),
88 SvxCharView(m_xVirDev),
89 SvxCharView(m_xVirDev),
90 SvxCharView(m_xVirDev),
91 SvxCharView(m_xVirDev),
92 SvxCharView(m_xVirDev)}
93 , m_aShowChar(m_xVirDev)
94 , m_xOKBtn(m_xFrame.is() ? m_xBuilder->weld_button("insert") : m_xBuilder->weld_button("ok"))
95 , m_xFontText(m_xBuilder->weld_label("fontft"))
96 , m_xFontLB(m_xBuilder->weld_combo_box("fontlb"))
97 , m_xSubsetText(m_xBuilder->weld_label("subsetft"))
98 , m_xSubsetLB(m_xBuilder->weld_combo_box("subsetlb"))
99 , m_xSearchText(m_xBuilder->weld_entry("search"))
100 , m_xHexCodeText(m_xBuilder->weld_entry("hexvalue"))
101 , m_xDecimalCodeText(m_xBuilder->weld_entry("decimalvalue"))
102 , m_xFavouritesBtn(m_xBuilder->weld_button("favbtn"))
103 , m_xCharName(m_xBuilder->weld_label("charname"))
104 , m_xRecentGrid(m_xBuilder->weld_widget("viewgrid"))
105 , m_xFavGrid(m_xBuilder->weld_widget("favgrid"))
106 , m_xShowChar(new weld::CustomWeld(*m_xBuilder, "showchar", m_aShowChar))
107 , m_xRecentCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar1", m_aRecentCharView[0]),
108 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar2", m_aRecentCharView[1]),
109 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar3", m_aRecentCharView[2]),
110 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar4", m_aRecentCharView[3]),
111 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar5", m_aRecentCharView[4]),
112 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar6", m_aRecentCharView[5]),
113 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar7", m_aRecentCharView[6]),
114 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar8", m_aRecentCharView[7]),
115 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar9", m_aRecentCharView[8]),
116 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar10", m_aRecentCharView[9]),
117 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar11", m_aRecentCharView[10]),
118 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar12", m_aRecentCharView[11]),
119 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar13", m_aRecentCharView[12]),
120 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar14", m_aRecentCharView[13]),
121 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar15", m_aRecentCharView[14]),
122 std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar16", m_aRecentCharView[15])}
123 , m_xFavCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar1", m_aFavCharView[0]),
124 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar2", m_aFavCharView[1]),
125 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar3", m_aFavCharView[2]),
126 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar4", m_aFavCharView[3]),
127 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar5", m_aFavCharView[4]),
128 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar6", m_aFavCharView[5]),
129 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar7", m_aFavCharView[6]),
130 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar8", m_aFavCharView[7]),
131 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar9", m_aFavCharView[8]),
132 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar10", m_aFavCharView[9]),
133 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar11", m_aFavCharView[10]),
134 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar12", m_aFavCharView[11]),
135 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar13", m_aFavCharView[12]),
136 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar14", m_aFavCharView[13]),
137 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar15", m_aFavCharView[14]),
138 std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar16", m_aFavCharView[15])}
139 , m_xShowSet(new SvxShowCharSet(m_xBuilder->weld_scrolled_window("showscroll", true), m_xVirDev))
140 , m_xShowSetArea(new weld::CustomWeld(*m_xBuilder, "showcharset", *m_xShowSet))
141 , m_xSearchSet(new SvxSearchCharSet(m_xBuilder->weld_scrolled_window("searchscroll", true), m_xVirDev))
142 , m_xSearchSetArea(new weld::CustomWeld(*m_xBuilder, "searchcharset", *m_xSearchSet))
144 m_aShowChar.SetCentered(true);
145 m_xFontLB->make_sorted();
146 //lock the size request of this widget to the width of all possible entries
147 fillAllSubsets(*m_xSubsetLB);
148 m_xSubsetLB->set_size_request(m_xSubsetLB->get_preferred_size().Width(), -1);
149 m_xCharName->set_size_request(m_aShowChar.get_preferred_size().Width(), m_xCharName->get_text_height() * 4);
150 //lock the size request of this widget to the width of the original .ui string
151 m_xHexCodeText->set_size_request(m_xHexCodeText->get_preferred_size().Width(), -1);
152 //so things don't jump around if all the children are hidden
153 m_xRecentGrid->set_size_request(-1, m_aRecentCharView[0].get_preferred_size().Height());
154 m_xFavGrid->set_size_request(-1, m_aFavCharView[0].get_preferred_size().Height());
156 init();
158 const SfxInt32Item* pCharItem = SfxItemSet::GetItem<SfxInt32Item>(pSet, SID_ATTR_CHAR, false);
159 if ( pCharItem )
160 SetChar( pCharItem->GetValue() );
162 const SfxBoolItem* pDisableItem = SfxItemSet::GetItem<SfxBoolItem>(pSet, FN_PARAM_2, false);
163 if ( pDisableItem && pDisableItem->GetValue() )
164 DisableFontSelection();
166 const SvxFontItem* pFontItem = SfxItemSet::GetItem<SvxFontItem>(pSet, SID_ATTR_CHAR_FONT, false);
167 const SfxStringItem* pFontNameItem = SfxItemSet::GetItem<SfxStringItem>(pSet, SID_FONT_NAME, false);
168 if ( pFontItem )
170 vcl::Font aTmpFont( pFontItem->GetFamilyName(), pFontItem->GetStyleName(), GetCharFont().GetFontSize() );
171 aTmpFont.SetCharSet( pFontItem->GetCharSet() );
172 aTmpFont.SetPitch( pFontItem->GetPitch() );
173 SetCharFont( aTmpFont );
175 else if ( pFontNameItem )
177 vcl::Font aTmpFont( GetCharFont() );
178 aTmpFont.SetFamilyName( pFontNameItem->GetValue() );
179 SetCharFont( aTmpFont );
182 m_xOutputSet.reset(new SfxAllItemSet(pSet ? *pSet->GetPool() : SfxGetpApp()->GetPool()));
183 m_xShowSet->Show();
184 m_xSearchSet->Hide();
187 short SvxCharacterMap::run()
189 if( SvxShowCharSet::getSelectedChar() == ' ')
191 m_xOKBtn->set_sensitive(false);
192 setFavButtonState(u"", u"");
194 else
196 sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
197 // using the new UCS4 constructor
198 OUString aOUStr( &cChar, 1 );
199 m_aShowChar.SetText(aOUStr);
201 setFavButtonState(aOUStr, m_aShowChar.GetFont().GetFamilyName());
202 m_xOKBtn->set_sensitive(true);
205 return SfxDialogController::run();
208 void SvxCharacterMap::SetChar( sal_UCS4 c )
210 m_xShowSet->SelectCharacter( c );
211 setFavButtonState(OUString(&c, 1), aFont.GetFamilyName());
214 sal_UCS4 SvxCharacterMap::GetChar() const
216 return m_aShowChar.GetText().iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
219 void SvxCharacterMap::DisableFontSelection()
221 m_xFontText->set_sensitive(false);
222 m_xFontLB->set_sensitive(false);
226 void SvxCharacterMap::getRecentCharacterList()
228 //retrieve recent character list
229 const css::uno::Sequence< OUString > rRecentCharList( officecfg::Office::Common::RecentCharacters::RecentCharacterList::get() );
230 for (OUString const & s : rRecentCharList)
232 maRecentCharList.push_back(s);
235 //retrieve recent character font list
236 const css::uno::Sequence< OUString > rRecentCharFontList( officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::get() );
237 for (OUString const & s : rRecentCharFontList)
239 maRecentCharFontList.push_back(s);
242 // tdf#135997: make sure that the two lists are same length
243 const auto nCommonLength = std::min(maRecentCharList.size(), maRecentCharFontList.size());
244 maRecentCharList.resize(nCommonLength);
245 maRecentCharFontList.resize(nCommonLength);
249 void SvxCharacterMap::getFavCharacterList()
251 maFavCharList.clear();
252 maFavCharFontList.clear();
253 //retrieve recent character list
254 const css::uno::Sequence< OUString > rFavCharList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::get() );
255 for (const OUString& s : rFavCharList)
257 maFavCharList.push_back(s);
260 //retrieve recent character font list
261 const css::uno::Sequence< OUString > rFavCharFontList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::get() );
262 for (const OUString& s : rFavCharFontList)
264 maFavCharFontList.push_back(s);
267 // tdf#135997: make sure that the two lists are same length
268 const auto nCommonLength = std::min(maFavCharList.size(), maFavCharFontList.size());
269 maFavCharList.resize(nCommonLength);
270 maFavCharFontList.resize(nCommonLength);
273 static std::pair<std::deque<OUString>::const_iterator, std::deque<OUString>::const_iterator>
274 findInPair(std::u16string_view str1, const std::deque<OUString>& rContainer1,
275 std::u16string_view str2, const std::deque<OUString>& rContainer2)
277 assert(rContainer1.size() == rContainer2.size());
279 for (auto it1 = std::find(rContainer1.begin(), rContainer1.end(), str1);
280 it1 != rContainer1.end(); it1 = std::find(std::next(it1), rContainer1.end(), str1))
282 auto it2 = rContainer2.begin() + (it1 - rContainer1.begin());
283 if (*it2 == str2)
284 return { it1, it2 };
286 return { rContainer1.end(), rContainer2.end() };
289 std::pair<std::deque<OUString>::const_iterator, std::deque<OUString>::const_iterator>
290 SvxCharacterMap::getRecentChar(std::u16string_view sTitle, std::u16string_view rFont) const
292 return findInPair(sTitle, maRecentCharList, rFont, maRecentCharFontList);
295 std::pair<std::deque<OUString>::const_iterator, std::deque<OUString>::const_iterator>
296 SvxCharacterMap::getFavChar(std::u16string_view sTitle, std::u16string_view rFont) const
298 return findInPair(sTitle, maFavCharList, rFont, maFavCharFontList);
302 void SvxCharacterMap::updateRecentCharControl()
304 assert(maRecentCharList.size() == maRecentCharFontList.size());
306 int i = 0;
307 for ( std::deque< OUString >::iterator it = maRecentCharList.begin(), it2 = maRecentCharFontList.begin();
308 it != maRecentCharList.end() && it2 != maRecentCharFontList.end();
309 ++it, ++it2, i++)
311 m_aRecentCharView[i].SetText(*it);
312 vcl::Font rFont = m_aRecentCharView[i].GetFont();
313 rFont.SetFamilyName( *it2 );
314 m_aRecentCharView[i].SetFont(rFont);
315 m_aRecentCharView[i].Show();
318 for(; i < 16 ; i++)
320 m_aRecentCharView[i].SetText(OUString());
321 m_aRecentCharView[i].Hide();
325 void SvxCharacterMap::updateRecentCharacterList(const OUString& sTitle, const OUString& rFont)
327 // if recent char to be added is already in list, remove it
328 if( const auto& [itChar, itChar2] = getRecentChar(sTitle, rFont);
329 itChar != maRecentCharList.end() && itChar2 != maRecentCharFontList.end() )
331 maRecentCharList.erase( itChar );
332 maRecentCharFontList.erase( itChar2);
335 if (maRecentCharList.size() == 16)
337 maRecentCharList.pop_back();
338 maRecentCharFontList.pop_back();
341 maRecentCharList.push_front(sTitle);
342 maRecentCharFontList.push_front(rFont);
344 css::uno::Sequence< OUString > aRecentCharList(maRecentCharList.size());
345 auto aRecentCharListRange = asNonConstRange(aRecentCharList);
346 css::uno::Sequence< OUString > aRecentCharFontList(maRecentCharFontList.size());
347 auto aRecentCharFontListRange = asNonConstRange(aRecentCharFontList);
349 for (size_t i = 0; i < maRecentCharList.size(); ++i)
351 aRecentCharListRange[i] = maRecentCharList[i];
352 aRecentCharFontListRange[i] = maRecentCharFontList[i];
355 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
356 officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList, batch);
357 officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList, batch);
358 batch->commit();
360 updateRecentCharControl();
364 void SvxCharacterMap::updateFavCharacterList(const OUString& sTitle, const OUString& rFont)
366 // if Fav char to be added is already in list, remove it
367 if( const auto& [itChar, itChar2] = getFavChar(sTitle, rFont);
368 itChar != maFavCharList.end() && itChar2 != maFavCharFontList.end() )
370 maFavCharList.erase( itChar );
371 maFavCharFontList.erase( itChar2);
374 if (maFavCharList.size() == 16)
376 maFavCharList.pop_back();
377 maFavCharFontList.pop_back();
380 maFavCharList.push_back(sTitle);
381 maFavCharFontList.push_back(rFont);
383 css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
384 auto aFavCharListRange = asNonConstRange(aFavCharList);
385 css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
386 auto aFavCharFontListRange = asNonConstRange(aFavCharFontList);
388 for (size_t i = 0; i < maFavCharList.size(); ++i)
390 aFavCharListRange[i] = maFavCharList[i];
391 aFavCharFontListRange[i] = maFavCharFontList[i];
394 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
395 officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
396 officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
397 batch->commit();
401 void SvxCharacterMap::updateFavCharControl()
403 assert(maFavCharList.size() == maFavCharFontList.size());
405 int i = 0;
406 for ( std::deque< OUString >::iterator it = maFavCharList.begin(), it2 = maFavCharFontList.begin();
407 it != maFavCharList.end() && it2 != maFavCharFontList.end();
408 ++it, ++it2, i++)
410 m_aFavCharView[i].SetText(*it);
411 vcl::Font rFont = m_aFavCharView[i].GetFont();
412 rFont.SetFamilyName( *it2 );
413 m_aFavCharView[i].SetFont(rFont);
414 m_aFavCharView[i].Show();
417 for(; i < 16 ; i++)
419 m_aFavCharView[i].SetText(OUString());
420 m_aFavCharView[i].Hide();
422 m_xShowSet->getFavCharacterList();
423 m_xSearchSet->getFavCharacterList();
424 // tdf#109214 - redraw highlight of the favorite characters
425 m_xShowSet->Invalidate();
428 void SvxCharacterMap::deleteFavCharacterFromList(std::u16string_view sTitle, std::u16string_view rFont)
430 // if Fav char is found, remove it
431 if( const auto& [itChar, itChar2] = getFavChar(sTitle, rFont);
432 itChar != maFavCharList.end() && itChar2 != maFavCharFontList.end() )
434 maFavCharList.erase( itChar );
435 maFavCharFontList.erase( itChar2);
438 css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
439 auto aFavCharListRange = asNonConstRange(aFavCharList);
440 css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
441 auto aFavCharFontListRange = asNonConstRange(aFavCharFontList);
443 for (size_t i = 0; i < maFavCharList.size(); ++i)
445 aFavCharListRange[i] = maFavCharList[i];
446 aFavCharFontListRange[i] = maFavCharFontList[i];
449 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
450 officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
451 officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
452 batch->commit();
455 void SvxCharacterMap::init()
457 aFont = m_xVirDev->GetFont();
458 aFont.SetTransparent( true );
459 aFont.SetFamily( FAMILY_DONTKNOW );
460 aFont.SetPitch( PITCH_DONTKNOW );
461 aFont.SetCharSet( RTL_TEXTENCODING_DONTKNOW );
463 OUString aDefStr( aFont.GetFamilyName() );
464 OUString aLastName;
465 int nCount = m_xVirDev->GetFontFaceCollectionCount();
466 std::vector<weld::ComboBoxEntry> aEntries;
467 aEntries.reserve(nCount);
468 for (int i = 0; i < nCount; ++i)
470 OUString aFontName( m_xVirDev->GetFontMetricFromCollection( i ).GetFamilyName() );
471 if (aFontName != aLastName)
473 aLastName = aFontName;
474 aEntries.emplace_back(aFontName, OUString::number(i));
477 m_xFontLB->insert_vector(aEntries, true);
478 // the font may not be in the list =>
479 // try to find a font name token in list and select found font,
480 // else select topmost entry
481 bool bFound = (m_xFontLB->find_text(aDefStr) != -1);
482 if (!bFound)
484 sal_Int32 nIndex = 0;
487 OUString aToken = aDefStr.getToken(0, ';', nIndex);
488 if (m_xFontLB->find_text(aToken) != -1)
490 aDefStr = aToken;
491 bFound = true;
492 break;
495 while ( nIndex >= 0 );
498 if (bFound)
499 m_xFontLB->set_active_text(aDefStr);
500 else if (m_xFontLB->get_count() )
501 m_xFontLB->set_active(0);
502 FontSelectHdl(*m_xFontLB);
503 if (m_xSubsetLB->get_count())
504 m_xSubsetLB->set_active(0);
506 m_xFontLB->connect_changed(LINK( this, SvxCharacterMap, FontSelectHdl));
507 m_xSubsetLB->connect_changed(LINK( this, SvxCharacterMap, SubsetSelectHdl));
508 m_xOKBtn->connect_clicked(LINK(this, SvxCharacterMap, InsertClickHdl));
509 m_xOKBtn->show();
511 m_xShowSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) );
512 m_xShowSet->SetReturnKeyPressHdl(LINK(this, SvxCharacterMap, ReturnKeypressOnCharHdl));
513 m_xShowSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) );
514 m_xShowSet->SetHighlightHdl( LINK( this, SvxCharacterMap, CharHighlightHdl ) );
515 m_xShowSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) );
516 m_xShowSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
518 m_xSearchSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) );
519 m_xSearchSet->SetReturnKeyPressHdl(LINK(this, SvxCharacterMap, ReturnKeypressOnCharHdl));
520 m_xSearchSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) );
521 m_xSearchSet->SetHighlightHdl( LINK( this, SvxCharacterMap, SearchCharHighlightHdl ) );
522 m_xSearchSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) );
523 m_xSearchSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
525 m_xDecimalCodeText->connect_changed( LINK( this, SvxCharacterMap, DecimalCodeChangeHdl ) );
526 m_xHexCodeText->connect_changed( LINK( this, SvxCharacterMap, HexCodeChangeHdl ) );
527 m_xFavouritesBtn->connect_clicked( LINK(this, SvxCharacterMap, FavSelectHdl));
529 // tdf#117038 set the buttons width to its max possible width so it doesn't
530 // make layout change when the label changes
531 m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_REMOVE_FAVORITES));
532 auto nMaxWidth = m_xFavouritesBtn->get_preferred_size().Width();
533 m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_ADD_FAVORITES));
534 nMaxWidth = std::max(nMaxWidth, m_xFavouritesBtn->get_preferred_size().Width());
535 m_xFavouritesBtn->set_size_request(nMaxWidth, -1);
537 if( SvxShowCharSet::getSelectedChar() == ' ')
539 m_xOKBtn->set_sensitive(false);
541 else
543 sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
544 // using the new UCS4 constructor
545 OUString aOUStr( &cChar, 1 );
546 m_aShowChar.SetText(aOUStr);
548 setFavButtonState(aOUStr, aDefStr);
549 m_xOKBtn->set_sensitive(true);
552 getRecentCharacterList();
553 updateRecentCharControl();
555 getFavCharacterList();
556 updateFavCharControl();
558 bool bHasInsert = m_xFrame.is();
560 for(int i = 0; i < 16; i++)
562 m_aRecentCharView[i].SetHasInsert(bHasInsert);
563 m_aRecentCharView[i].setMouseClickHdl(LINK(this,SvxCharacterMap, CharClickHdl));
564 m_aRecentCharView[i].setClearClickHdl(LINK(this,SvxCharacterMap, RecentClearClickHdl));
565 m_aRecentCharView[i].setClearAllClickHdl(LINK(this,SvxCharacterMap, RecentClearAllClickHdl));
566 m_aFavCharView[i].SetHasInsert(bHasInsert);
567 m_aFavCharView[i].setMouseClickHdl(LINK(this,SvxCharacterMap, CharClickHdl));
568 m_aFavCharView[i].setClearClickHdl(LINK(this,SvxCharacterMap, FavClearClickHdl));
569 m_aFavCharView[i].setClearAllClickHdl(LINK(this,SvxCharacterMap, FavClearAllClickHdl));
572 setCharName(90);
574 m_xSearchText->connect_focus_in(LINK( this, SvxCharacterMap, SearchFieldGetFocusHdl ));
575 m_xSearchText->connect_changed(LINK(this, SvxCharacterMap, SearchUpdateHdl));
578 bool SvxCharacterMap::isFavChar(std::u16string_view sTitle, std::u16string_view rFont)
580 const auto& [itChar, itFont] = getFavChar(sTitle, rFont);
581 return itChar != maFavCharList.end() && itFont != maFavCharFontList.end();
585 void SvxCharacterMap::setFavButtonState(std::u16string_view sTitle, std::u16string_view rFont)
587 if(sTitle.empty() || rFont.empty())
589 m_xFavouritesBtn->set_sensitive(false);
590 return;
592 else
593 m_xFavouritesBtn->set_sensitive(true);
595 if (isFavChar(sTitle, rFont))
597 m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_REMOVE_FAVORITES));
599 else
601 if(maFavCharList.size() == 16)
603 m_xFavouritesBtn->set_sensitive(false);
606 m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_ADD_FAVORITES));
611 void SvxCharacterMap::SetCharFont( const vcl::Font& rFont )
613 // first get the underlying info in order to get font names
614 // like "Times New Roman;Times" resolved
615 vcl::Font aTmp(m_xVirDev->GetFontMetric(rFont));
617 // tdf#56363 - search font family without the font feature after the colon
618 OUString sFontFamilyName = aTmp.GetFamilyName();
619 if (const sal_Int32 nIndex = sFontFamilyName.indexOf(":"); nIndex != -1)
620 sFontFamilyName = sFontFamilyName.copy(0, nIndex);
621 if (sFontFamilyName == "StarSymbol" && m_xFontLB->find_text(sFontFamilyName) == -1)
623 //if for some reason, like font in an old document, StarSymbol is requested and it's not available, then
624 //try OpenSymbol instead
625 aTmp.SetFamilyName("OpenSymbol");
628 if (m_xFontLB->find_text(sFontFamilyName) == -1)
629 return;
631 m_xFontLB->set_active_text(sFontFamilyName);
632 aFont = aTmp;
633 FontSelectHdl(*m_xFontLB);
634 if (m_xSubsetLB->get_count())
635 m_xSubsetLB->set_active(0);
638 void SvxCharacterMap::fillAllSubsets(weld::ComboBox& rListBox)
640 SubsetMap aAll(nullptr);
641 std::vector<weld::ComboBoxEntry> aEntries;
642 for (auto & subset : aAll.GetSubsetMap())
643 aEntries.emplace_back(subset.GetName());
644 rListBox.insert_vector(aEntries, true);
647 void SvxCharacterMap::insertCharToDoc(const OUString& sGlyph)
649 if(sGlyph.isEmpty())
650 return;
652 if (m_xFrame.is()) {
653 uno::Sequence<beans::PropertyValue> aArgs{
654 comphelper::makePropertyValue("Symbols", sGlyph),
655 comphelper::makePropertyValue("FontName", aFont.GetFamilyName())
657 comphelper::dispatchCommand(".uno:InsertSymbol", m_xFrame, aArgs);
659 updateRecentCharacterList(sGlyph, aFont.GetFamilyName());
661 } else {
662 sal_UCS4 cChar = sGlyph.iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
663 const SfxItemPool* pPool = m_xOutputSet->GetPool();
664 m_xOutputSet->Put( SfxStringItem( SID_CHARMAP, sGlyph ) );
665 m_xOutputSet->Put( SvxFontItem( aFont.GetFamilyType(), aFont.GetFamilyName(),
666 aFont.GetStyleName(), aFont.GetPitch(), aFont.GetCharSet(), pPool->GetWhich(SID_ATTR_CHAR_FONT) ) );
667 m_xOutputSet->Put( SfxStringItem( SID_FONT_NAME, aFont.GetFamilyName() ) );
668 m_xOutputSet->Put( SfxInt32Item( SID_ATTR_CHAR, cChar ) );
672 IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, weld::ComboBox&, void)
674 const sal_uInt32 nFont = m_xFontLB->get_active_id().toUInt32();
675 aFont = m_xVirDev->GetFontMetricFromCollection(nFont);
676 aFont.SetWeight( WEIGHT_DONTKNOW );
677 aFont.SetItalic( ITALIC_NONE );
678 aFont.SetWidthType( WIDTH_DONTKNOW );
679 aFont.SetPitch( PITCH_DONTKNOW );
680 aFont.SetFamily( FAMILY_DONTKNOW );
682 // notify children using this font
683 m_xShowSet->SetFont( aFont );
684 m_xSearchSet->SetFont( aFont );
685 m_aShowChar.SetFont( aFont );
687 // setup unicode subset listbar with font specific subsets,
688 // hide unicode subset listbar for symbol fonts
689 // TODO: get info from the Font once it provides it
690 pSubsetMap.reset();
691 m_xSubsetLB->clear();
693 bool bNeedSubset = (aFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL);
694 if (bNeedSubset)
696 FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap();
697 pSubsetMap.reset(new SubsetMap( xFontCharMap ));
699 // update subset listbox for new font's unicode subsets
700 for (auto const& subset : pSubsetMap->GetSubsetMap())
702 m_xSubsetLB->append(weld::toId(&subset), subset.GetName());
703 // NOTE: subset must live at least as long as the selected font
706 if (m_xSubsetLB->get_count() <= 1)
707 bNeedSubset = false;
710 m_xSubsetText->set_sensitive(bNeedSubset);
711 m_xSubsetLB->set_sensitive(bNeedSubset);
713 if (isSearchMode)
715 // tdf#137294 do this after modifying m_xSubsetLB sensitivity to
716 // restore insensitive for the search case
717 SearchUpdateHdl(*m_xSearchText);
718 SearchCharHighlightHdl(m_xSearchSet.get());
721 // tdf#118304 reselect current glyph to see if it's still there in new font
722 selectCharByCode(Radix::hexadecimal);
725 void SvxCharacterMap::toggleSearchView(bool state)
727 isSearchMode = state;
728 m_xHexCodeText->set_editable(!state);
729 m_xDecimalCodeText->set_editable(!state);
730 m_xSubsetLB->set_sensitive(!state);
732 if(state)
734 m_xSearchSet->Show();
735 m_xShowSet->Hide();
737 else
739 m_xSearchSet->Hide();
740 m_xShowSet->Show();
744 void SvxCharacterMap::setCharName(sal_UCS4 nDecimalValue)
746 /* get the character name */
747 UErrorCode errorCode = U_ZERO_ERROR;
748 // icu has a private uprv_getMaxCharNameLength function which returns the max possible
749 // length of this property. Unicode 3.2 max char name length was 83
750 char buffer[100];
751 u_charName(nDecimalValue, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
752 if (U_SUCCESS(errorCode))
753 m_xCharName->set_label(OUString::createFromAscii(buffer));
756 IMPL_LINK_NOARG(SvxCharacterMap, SubsetSelectHdl, weld::ComboBox&, void)
758 const sal_Int32 nPos = m_xSubsetLB->get_active();
759 const Subset* pSubset = weld::fromId<const Subset*>(m_xSubsetLB->get_active_id());
761 if( pSubset && !isSearchMode)
763 sal_UCS4 cFirst = pSubset->GetRangeMin();
764 m_xShowSet->SelectCharacter( cFirst );
766 setFavButtonState(OUString(&cFirst, 1), aFont.GetFamilyName());
767 m_xSubsetLB->set_active(nPos);
769 else if( pSubset && isSearchMode)
771 m_xSearchSet->SelectCharacter( pSubset );
773 const Subset* curSubset = nullptr;
774 if( pSubsetMap )
775 curSubset = pSubsetMap->GetSubsetByUnicode( m_xSearchSet->GetSelectCharacter() );
776 if( curSubset )
777 m_xSubsetLB->set_active_text(curSubset->GetName());
778 else
779 m_xSubsetLB->set_active(-1);
781 sal_UCS4 sChar = m_xSearchSet->GetSelectCharacter();
782 setFavButtonState(OUString(&sChar, 1), aFont.GetFamilyName());
786 IMPL_LINK(SvxCharacterMap, RecentClearClickHdl, SvxCharView*, rView, void)
788 const OUString& sTitle = rView->GetText();
789 OUString sFont = rView->GetFont().GetFamilyName();
791 // if recent char to be added is already in list, remove it
792 if( const auto& [itChar, itChar2] = getRecentChar(sTitle, sFont);
793 itChar != maRecentCharList.end() && itChar2 != maRecentCharFontList.end() )
795 maRecentCharList.erase( itChar );
796 maRecentCharFontList.erase( itChar2);
799 css::uno::Sequence< OUString > aRecentCharList(maRecentCharList.size());
800 auto aRecentCharListRange = asNonConstRange(aRecentCharList);
801 css::uno::Sequence< OUString > aRecentCharFontList(maRecentCharFontList.size());
802 auto aRecentCharFontListRange = asNonConstRange(aRecentCharFontList);
804 for (size_t i = 0; i < maRecentCharList.size(); ++i)
806 aRecentCharListRange[i] = maRecentCharList[i];
807 aRecentCharFontListRange[i] = maRecentCharFontList[i];
810 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
811 officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList, batch);
812 officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList, batch);
813 batch->commit();
815 updateRecentCharControl();
818 IMPL_LINK_NOARG(SvxCharacterMap, RecentClearAllClickHdl, SvxCharView*, void)
820 maRecentCharList.clear();
821 maRecentCharFontList.clear();
823 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
824 officecfg::Office::Common::RecentCharacters::RecentCharacterList::set({ }, batch);
825 officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set({ }, batch);
826 batch->commit();
828 updateRecentCharControl();
831 IMPL_LINK(SvxCharacterMap, FavClearClickHdl, SvxCharView*, rView, void)
833 deleteFavCharacterFromList(rView->GetText(), rView->GetFont().GetFamilyName());
834 updateFavCharControl();
837 IMPL_LINK_NOARG(SvxCharacterMap, FavClearAllClickHdl, SvxCharView*, void)
839 maFavCharList.clear();
840 maFavCharFontList.clear();
842 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
843 officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set({ }, batch);
844 officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set({ }, batch);
845 batch->commit();
847 updateFavCharControl();
850 IMPL_LINK_NOARG(SvxCharacterMap, SearchFieldGetFocusHdl, weld::Widget&, void)
852 m_xOKBtn->set_sensitive(false);
855 IMPL_LINK_NOARG(SvxCharacterMap, SearchUpdateHdl, weld::Entry&, void)
857 if (!m_xSearchText->get_text().isEmpty())
859 m_xSearchSet->ClearPreviousData();
860 OUString aKeyword = m_xSearchText->get_text();
862 toggleSearchView(true);
864 FontCharMapRef xFontCharMap = m_xSearchSet->GetFontCharMap();
866 sal_UCS4 sChar = xFontCharMap->GetFirstChar();
867 while(sChar != xFontCharMap->GetLastChar())
869 UErrorCode errorCode = U_ZERO_ERROR;
870 char buffer[100];
871 u_charName(sChar, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
872 if (U_SUCCESS(errorCode))
874 OUString sName = OUString::createFromAscii(buffer);
875 if(!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword.toAsciiLowerCase()) >= 0)
876 m_xSearchSet->AppendCharToList(sChar);
878 sChar = xFontCharMap->GetNextChar(sChar);
880 //for last char
881 UErrorCode errorCode = U_ZERO_ERROR;
882 char buffer[100];
883 u_charName(sChar, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
884 if (U_SUCCESS(errorCode))
886 OUString sName = OUString::createFromAscii(buffer);
887 if(!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword.toAsciiLowerCase()) >= 0)
888 m_xSearchSet->AppendCharToList(sChar);
891 m_xSearchSet->UpdateScrollRange();
893 else
895 toggleSearchView(false);
900 IMPL_LINK(SvxCharacterMap, CharClickHdl, SvxCharView*, rView, void)
902 rView->GrabFocus();
904 m_aShowChar.SetText( rView->GetText() );
905 m_aShowChar.SetFont(rView->GetFont());
906 m_aShowChar.Invalidate();
908 setFavButtonState(rView->GetText(), rView->GetFont().GetFamilyName());//check state
910 // Get the hexadecimal code
911 OUString charValue = rView->GetText();
912 sal_UCS4 cChar = charValue.iterateCodePoints(&o3tl::temporary(sal_Int32(1)), -1);
913 OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
915 // Get the decimal code
916 OUString aDecimalText = OUString::number(cChar);
918 m_xHexCodeText->set_text(aHexText);
919 m_xDecimalCodeText->set_text(aDecimalText);
920 setCharName(cChar);
922 rView->Invalidate();
923 m_xOKBtn->set_sensitive(true);
926 void SvxCharacterMap::insertSelectedCharacter(const SvxShowCharSet* pCharSet)
928 assert(pCharSet);
929 sal_UCS4 cChar = pCharSet->GetSelectCharacter();
930 // using the new UCS4 constructor
931 OUString aOUStr( &cChar, 1 );
932 setFavButtonState(aOUStr, aFont.GetFamilyName());
933 insertCharToDoc(aOUStr);
936 IMPL_LINK(SvxCharacterMap, CharDoubleClickHdl, SvxShowCharSet*, pCharSet, void)
938 insertSelectedCharacter(pCharSet);
941 IMPL_LINK_NOARG(SvxCharacterMap, CharSelectHdl, SvxShowCharSet*, void)
943 m_xOKBtn->set_sensitive(true);
946 IMPL_LINK(SvxCharacterMap, ReturnKeypressOnCharHdl, SvxShowCharSet*, pCharSet, void)
948 insertSelectedCharacter(pCharSet);
949 m_xDialog->response(RET_OK);
952 IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, weld::Button&, void)
954 OUString sChar = m_aShowChar.GetText();
955 insertCharToDoc(sChar);
956 // Need to update recent character list, when OK button does not insert
957 if(!m_xFrame.is())
958 updateRecentCharacterList(sChar, aFont.GetFamilyName());
959 m_xDialog->response(RET_OK);
962 IMPL_LINK_NOARG(SvxCharacterMap, FavSelectHdl, weld::Button&, void)
964 if (m_xFavouritesBtn->get_label().match(CuiResId(RID_CUISTR_ADD_FAVORITES)))
966 updateFavCharacterList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
967 setFavButtonState(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
969 else
971 deleteFavCharacterFromList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
972 m_xFavouritesBtn->set_label(CuiResId(RID_CUISTR_ADD_FAVORITES));
973 m_xFavouritesBtn->set_sensitive(false);
976 updateFavCharControl();
979 IMPL_LINK_NOARG(SvxCharacterMap, FavClickHdl, SvxShowCharSet*, void)
981 getFavCharacterList();
982 updateFavCharControl();
985 IMPL_LINK_NOARG(SvxCharacterMap, CharHighlightHdl, SvxShowCharSet*, void)
987 OUString aText;
988 sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
989 bool bSelect = (cChar > 0);
991 // show char sample
992 if ( bSelect )
994 // using the new UCS4 constructor
995 aText = OUString( &cChar, 1 );
996 // Get the hexadecimal code
997 OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
998 // Get the decimal code
999 OUString aDecimalText = OUString::number(cChar);
1000 setCharName(cChar);
1002 // Update the hex and decimal codes only if necessary
1003 if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
1004 m_xHexCodeText->set_text(aHexText);
1005 if (m_xDecimalCodeText->get_text() != aDecimalText)
1006 m_xDecimalCodeText->set_text( aDecimalText );
1008 const Subset* pSubset = nullptr;
1009 if( pSubsetMap )
1010 pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
1011 if( pSubset )
1012 m_xSubsetLB->set_active_text(pSubset->GetName());
1013 else
1014 m_xSubsetLB->set_active(-1);
1017 m_aShowChar.SetText( aText );
1018 m_aShowChar.SetFont( aFont );
1019 m_aShowChar.Invalidate();
1021 setFavButtonState(aText, aFont.GetFamilyName());
1024 IMPL_LINK_NOARG(SvxCharacterMap, SearchCharHighlightHdl, SvxShowCharSet*, void)
1026 OUString aText;
1027 sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
1028 bool bSelect = (cChar > 0);
1030 // show char sample
1031 if ( bSelect )
1033 aText = OUString( &cChar, 1 );
1034 // Get the hexadecimal code
1035 OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
1036 // Get the decimal code
1037 OUString aDecimalText = OUString::number(cChar);
1038 setCharName(cChar);
1040 // Update the hex and decimal codes only if necessary
1041 if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
1042 m_xHexCodeText->set_text(aHexText);
1043 if (m_xDecimalCodeText->get_text() != aDecimalText)
1044 m_xDecimalCodeText->set_text( aDecimalText );
1046 const Subset* pSubset = nullptr;
1047 if( pSubsetMap )
1048 pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
1049 if( pSubset )
1050 m_xSubsetLB->set_active_text(pSubset->GetName());
1051 else
1052 m_xSubsetLB->set_active(-1);
1055 if(m_xSearchSet->HasFocus())
1057 m_aShowChar.SetText( aText );
1058 m_aShowChar.SetFont( aFont );
1059 m_aShowChar.Invalidate();
1061 setFavButtonState(aText, aFont.GetFamilyName());
1065 void SvxCharacterMap::selectCharByCode(Radix radix)
1067 OUString aCodeString;
1068 switch(radix)
1070 case Radix::decimal:
1071 aCodeString = m_xDecimalCodeText->get_text();
1072 break;
1073 case Radix::hexadecimal:
1074 aCodeString = m_xHexCodeText->get_text();
1075 break;
1077 // Convert the code back to a character using the appropriate radix
1078 sal_UCS4 cChar = aCodeString.toUInt32(static_cast<sal_Int16> (radix));
1079 // Use FontCharMap::HasChar(sal_UCS4 cChar) to see if the desired character is in the font
1080 FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap();
1081 if (xFontCharMap->HasChar(cChar))
1082 // Select the corresponding character
1083 SetChar(cChar);
1084 else {
1085 m_xCharName->set_label(CuiResId(RID_CUISTR_MISSING_CHAR));
1086 m_aShowChar.SetText(" ");
1087 switch(radix)
1089 case Radix::decimal:
1090 m_xHexCodeText->set_text(OUString::number(cChar, 16));
1091 break;
1092 case Radix::hexadecimal:
1093 m_xDecimalCodeText->set_text(OUString::number(cChar));
1094 break;
1099 IMPL_LINK_NOARG(SvxCharacterMap, DecimalCodeChangeHdl, weld::Entry&, void)
1101 selectCharByCode(Radix::decimal);
1104 IMPL_LINK_NOARG(SvxCharacterMap, HexCodeChangeHdl, weld::Entry&, void)
1106 selectCharByCode(Radix::hexadecimal);
1109 IMPL_LINK(SvxCharacterMap, CharPreSelectHdl, SvxShowCharSet*, pCharSet, void)
1111 assert(pCharSet);
1112 // adjust subset selection
1113 if( pSubsetMap )
1115 sal_UCS4 cChar = pCharSet->GetSelectCharacter();
1117 setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName());
1118 const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
1119 if( pSubset )
1120 m_xSubsetLB->set_active_text(pSubset->GetName());
1123 m_xOKBtn->set_sensitive(true);
1126 // class SvxShowText =====================================================
1127 SvxShowText::SvxShowText(const VclPtr<VirtualDevice>& rVirDev)
1128 : m_xVirDev(rVirDev)
1129 , mnY(0)
1130 , mbCenter(false)
1134 void SvxShowText::SetDrawingArea(weld::DrawingArea* pDrawingArea)
1136 CustomWidgetController::SetDrawingArea(pDrawingArea);
1137 vcl::Font aFont = m_xVirDev->GetFont();
1138 Size aFontSize(aFont.GetFontSize().Width() * 5, aFont.GetFontSize().Height() * 5);
1139 aFont.SetFontSize(aFontSize);
1140 m_xVirDev->Push(PUSH_ALLFONT);
1141 m_xVirDev->SetFont(aFont);
1142 pDrawingArea->set_size_request(m_xVirDev->approximate_digit_width() + 2 * 12,
1143 m_xVirDev->LogicToPixel(aFontSize).Height() * 2);
1144 m_xVirDev->Pop();
1147 void SvxShowText::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
1149 rRenderContext.SetFont(m_aFont);
1151 Color aTextCol = rRenderContext.GetTextColor();
1152 Color aFillCol = rRenderContext.GetFillColor();
1153 Color aLineCol = rRenderContext.GetLineColor();
1155 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1156 const Color aWindowTextColor(rStyleSettings.GetDialogTextColor());
1157 const Color aWindowColor(rStyleSettings.GetWindowColor());
1158 const Color aShadowColor(rStyleSettings.GetShadowColor());
1159 rRenderContext.SetTextColor(aWindowTextColor);
1160 rRenderContext.SetFillColor(aWindowColor);
1162 const OUString aText = GetText();
1164 Size aSize(GetOutputSizePixel());
1165 tools::Long nAvailWidth = aSize.Width();
1166 tools::Long nWinHeight = aSize.Height();
1168 bool bGotBoundary = true;
1169 bool bShrankFont = false;
1170 vcl::Font aOrigFont(rRenderContext.GetFont());
1171 Size aFontSize(aOrigFont.GetFontSize());
1172 ::tools::Rectangle aBoundRect;
1174 for (tools::Long nFontHeight = aFontSize.Height(); nFontHeight > 0; nFontHeight -= 5)
1176 if (!rRenderContext.GetTextBoundRect( aBoundRect, aText ) || aBoundRect.IsEmpty())
1178 bGotBoundary = false;
1179 break;
1181 if (!mbCenter)
1182 break;
1183 //only shrink in the single glyph large view mode
1184 tools::Long nTextWidth = aBoundRect.GetWidth();
1185 if (nAvailWidth > nTextWidth)
1186 break;
1187 vcl::Font aFont(aOrigFont);
1188 aFontSize.setHeight( nFontHeight );
1189 aFont.SetFontSize(aFontSize);
1190 rRenderContext.SetFont(aFont);
1191 mnY = (nWinHeight - rRenderContext.GetTextHeight()) / 2;
1192 bShrankFont = true;
1195 Point aPoint(2, mnY);
1196 // adjust position using ink boundary if possible
1197 if (!bGotBoundary)
1198 aPoint.setX( (aSize.Width() - rRenderContext.GetTextWidth(aText)) / 2 );
1199 else
1201 // adjust position before it gets out of bounds
1202 aBoundRect += aPoint;
1204 // shift back vertically if needed
1205 int nYLDelta = aBoundRect.Top();
1206 int nYHDelta = aSize.Height() - aBoundRect.Bottom();
1207 if( nYLDelta <= 0 )
1208 aPoint.AdjustY( -(nYLDelta - 1) );
1209 else if( nYHDelta <= 0 )
1210 aPoint.AdjustY(nYHDelta - 1 );
1212 if (mbCenter)
1214 // move glyph to middle of cell
1215 aPoint.setX( -aBoundRect.Left() + (aSize.Width() - aBoundRect.GetWidth()) / 2 );
1217 else
1219 // shift back horizontally if needed
1220 int nXLDelta = aBoundRect.Left();
1221 int nXHDelta = aSize.Width() - aBoundRect.Right();
1222 if( nXLDelta <= 0 )
1223 aPoint.AdjustX( -(nXLDelta - 1) );
1224 else if( nXHDelta <= 0 )
1225 aPoint.AdjustX(nXHDelta - 1 );
1229 rRenderContext.SetLineColor(aShadowColor);
1230 rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), aSize));
1231 rRenderContext.DrawText(aPoint, aText);
1232 rRenderContext.SetTextColor(aTextCol);
1233 rRenderContext.SetFillColor(aFillCol);
1234 rRenderContext.SetLineColor(aLineCol);
1235 if (bShrankFont)
1236 rRenderContext.SetFont(aOrigFont);
1239 void SvxShowText::SetFont( const vcl::Font& rFont )
1241 tools::Long nWinHeight = GetOutputSizePixel().Height();
1243 m_aFont = rFont;
1244 m_aFont.SetWeight(WEIGHT_NORMAL);
1245 m_aFont.SetAlignment(ALIGN_TOP);
1246 m_aFont.SetFontSize(m_xVirDev->PixelToLogic(Size(0, nWinHeight / 2)));
1247 m_aFont.SetTransparent(true);
1249 m_xVirDev->Push(PUSH_ALLFONT);
1250 m_xVirDev->SetFont(m_aFont);
1251 mnY = (nWinHeight - m_xVirDev->GetTextHeight()) / 2;
1252 m_xVirDev->Pop();
1254 Invalidate();
1257 void SvxShowText::Resize()
1259 SetFont(GetFont()); //force recalculation of size
1262 void SvxShowText::SetText(const OUString& rText)
1264 m_sText = rText;
1265 Invalidate();
1268 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */