LibreOffice Module cui (master)  1
cuicharmap.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <stdio.h>
23 
24 #include <vcl/svapp.hxx>
25 #include <svl/eitem.hxx>
26 #include <svl/intitem.hxx>
27 #include <svl/itempool.hxx>
28 
29 #include <rtl/textenc.h>
30 #include <svx/ucsubset.hxx>
31 #include <vcl/settings.hxx>
32 #include <vcl/fontcharmap.hxx>
33 #include <vcl/virdev.hxx>
34 #include <svl/stritem.hxx>
35 #include <o3tl/temporary.hxx>
36 #include <officecfg/Office/Common.hxx>
37 #include <com/sun/star/beans/PropertyValue.hpp>
40 
41 #include <dialmgr.hxx>
42 #include <cui/cuicharmap.hxx>
43 #include <sfx2/app.hxx>
44 #include <svx/svxids.hrc>
45 #include <editeng/editids.hrc>
46 #include <editeng/fontitem.hxx>
47 #include <strings.hrc>
48 #include <unicode/uchar.h>
49 #include <unicode/utypes.h>
50 
51 using namespace css;
52 
54  const css::uno::Reference<css::frame::XFrame>& rFrame)
55  : SfxDialogController(pParent, "cui/ui/specialcharacters.ui", "SpecialCharactersDialog")
56  , m_xVirDev(VclPtr<VirtualDevice>::Create())
57  , isSearchMode(true)
58  , m_xFrame(rFrame)
60  , m_aRecentCharView{SvxCharView(m_xVirDev),
76  , m_aFavCharView{SvxCharView(m_xVirDev),
77  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  , m_aShowChar(m_xVirDev)
93  , m_xOKBtn(m_xFrame.is() ? m_xBuilder->weld_button("insert") : m_xBuilder->weld_button("ok"))
94  , m_xFontText(m_xBuilder->weld_label("fontft"))
95  , m_xFontLB(m_xBuilder->weld_combo_box("fontlb"))
96  , m_xSubsetText(m_xBuilder->weld_label("subsetft"))
97  , m_xSubsetLB(m_xBuilder->weld_combo_box("subsetlb"))
98  , m_xSearchText(m_xBuilder->weld_entry("search"))
99  , m_xHexCodeText(m_xBuilder->weld_entry("hexvalue"))
100  , m_xDecimalCodeText(m_xBuilder->weld_entry("decimalvalue"))
101  , m_xFavouritesBtn(m_xBuilder->weld_button("favbtn"))
102  , m_xCharName(m_xBuilder->weld_label("charname"))
103  , m_xRecentGrid(m_xBuilder->weld_widget("viewgrid"))
104  , m_xFavGrid(m_xBuilder->weld_widget("favgrid"))
105  , m_xShowChar(new weld::CustomWeld(*m_xBuilder, "showchar", m_aShowChar))
106  , m_xRecentCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar1", m_aRecentCharView[0]),
107  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar2", m_aRecentCharView[1]),
108  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar3", m_aRecentCharView[2]),
109  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar4", m_aRecentCharView[3]),
110  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar5", m_aRecentCharView[4]),
111  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar6", m_aRecentCharView[5]),
112  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar7", m_aRecentCharView[6]),
113  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar8", m_aRecentCharView[7]),
114  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar9", m_aRecentCharView[8]),
115  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar10", m_aRecentCharView[9]),
116  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar11", m_aRecentCharView[10]),
117  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar12", m_aRecentCharView[11]),
118  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar13", m_aRecentCharView[12]),
119  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar14", m_aRecentCharView[13]),
120  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar15", m_aRecentCharView[14]),
121  std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar16", m_aRecentCharView[15])}
122  , m_xFavCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar1", m_aFavCharView[0]),
123  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar2", m_aFavCharView[1]),
124  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar3", m_aFavCharView[2]),
125  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar4", m_aFavCharView[3]),
126  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar5", m_aFavCharView[4]),
127  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar6", m_aFavCharView[5]),
128  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar7", m_aFavCharView[6]),
129  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar8", m_aFavCharView[7]),
130  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar9", m_aFavCharView[8]),
131  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar10", m_aFavCharView[9]),
132  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar11", m_aFavCharView[10]),
133  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar12", m_aFavCharView[11]),
134  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar13", m_aFavCharView[12]),
135  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar14", m_aFavCharView[13]),
136  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar15", m_aFavCharView[14]),
137  std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar16", m_aFavCharView[15])}
138  , m_xShowSet(new SvxShowCharSet(m_xBuilder->weld_scrolled_window("showscroll", true), m_xVirDev))
139  , m_xShowSetArea(new weld::CustomWeld(*m_xBuilder, "showcharset", *m_xShowSet))
140  , m_xSearchSet(new SvxSearchCharSet(m_xBuilder->weld_scrolled_window("searchscroll", true), m_xVirDev))
141  , m_xSearchSetArea(new weld::CustomWeld(*m_xBuilder, "searchcharset", *m_xSearchSet))
142 {
143  m_aShowChar.SetCentered(true);
144  m_xFontLB->make_sorted();
145  //lock the size request of this widget to the width of all possible entries
146  fillAllSubsets(*m_xSubsetLB);
147  m_xSubsetLB->set_size_request(m_xSubsetLB->get_preferred_size().Width(), -1);
148  m_xCharName->set_size_request(m_aShowChar.get_preferred_size().Width(), m_xCharName->get_text_height() * 4);
149  //lock the size request of this widget to the width of the original .ui string
150  m_xHexCodeText->set_size_request(m_xHexCodeText->get_preferred_size().Width(), -1);
151  //so things don't jump around if all the children are hidden
152  m_xRecentGrid->set_size_request(-1, m_aRecentCharView[0].get_preferred_size().Height());
153  m_xFavGrid->set_size_request(-1, m_aFavCharView[0].get_preferred_size().Height());
154 
155  init();
156 
157  const SfxInt32Item* pCharItem = SfxItemSet::GetItem<SfxInt32Item>(pSet, SID_ATTR_CHAR, false);
158  if ( pCharItem )
159  SetChar( pCharItem->GetValue() );
160 
161  const SfxBoolItem* pDisableItem = SfxItemSet::GetItem<SfxBoolItem>(pSet, FN_PARAM_2, false);
162  if ( pDisableItem && pDisableItem->GetValue() )
163  DisableFontSelection();
164 
165  const SvxFontItem* pFontItem = SfxItemSet::GetItem<SvxFontItem>(pSet, SID_ATTR_CHAR_FONT, false);
166  const SfxStringItem* pFontNameItem = SfxItemSet::GetItem<SfxStringItem>(pSet, SID_FONT_NAME, false);
167  if ( pFontItem )
168  {
169  vcl::Font aTmpFont( pFontItem->GetFamilyName(), pFontItem->GetStyleName(), GetCharFont().GetFontSize() );
170  aTmpFont.SetCharSet( pFontItem->GetCharSet() );
171  aTmpFont.SetPitch( pFontItem->GetPitch() );
172  SetCharFont( aTmpFont );
173  }
174  else if ( pFontNameItem )
175  {
176  vcl::Font aTmpFont( GetCharFont() );
177  aTmpFont.SetFamilyName( pFontNameItem->GetValue() );
178  SetCharFont( aTmpFont );
179  }
180 
181  m_xOutputSet.reset(new SfxAllItemSet(pSet ? *pSet->GetPool() : SfxGetpApp()->GetPool()));
182  m_xShowSet->Show();
183  m_xSearchSet->Hide();
184 }
185 
187 {
188  if( SvxShowCharSet::getSelectedChar() == ' ')
189  {
190  m_xOKBtn->set_sensitive(false);
191  setFavButtonState(u"", u"");
192  }
193  else
194  {
195  sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
196  // using the new UCS4 constructor
197  OUString aOUStr( &cChar, 1 );
198  m_aShowChar.SetText(aOUStr);
199 
201  m_xOKBtn->set_sensitive(true);
202  }
203 
204  return SfxDialogController::run();
205 }
206 
208 {
209  m_xShowSet->SelectCharacter( c );
210  setFavButtonState(OUString(&c, 1), aFont.GetFamilyName());
211 }
212 
214 {
215  return m_aShowChar.GetText().iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
216 }
217 
219 {
220  m_xFontText->set_sensitive(false);
221  m_xFontLB->set_sensitive(false);
222 }
223 
224 
226 {
227  //retrieve recent character list
228  const css::uno::Sequence< OUString > rRecentCharList( officecfg::Office::Common::RecentCharacters::RecentCharacterList::get() );
229  for (OUString const & s : rRecentCharList)
230  {
231  maRecentCharList.push_back(s);
232  }
233 
234  //retrieve recent character font list
235  const css::uno::Sequence< OUString > rRecentCharFontList( officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::get() );
236  for (OUString const & s : rRecentCharFontList)
237  {
238  maRecentCharFontList.push_back(s);
239  }
240 
241  // tdf#135997: make sure that the two lists are same length
242  const auto nCommonLength = std::min(maRecentCharList.size(), maRecentCharFontList.size());
243  maRecentCharList.resize(nCommonLength);
244  maRecentCharFontList.resize(nCommonLength);
245 }
246 
247 
249 {
250  maFavCharList.clear();
251  maFavCharFontList.clear();
252  //retrieve recent character list
253  const css::uno::Sequence< OUString > rFavCharList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::get() );
254  for (const OUString& s : rFavCharList)
255  {
256  maFavCharList.push_back(s);
257  }
258 
259  //retrieve recent character font list
260  const css::uno::Sequence< OUString > rFavCharFontList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::get() );
261  for (const OUString& s : rFavCharFontList)
262  {
263  maFavCharFontList.push_back(s);
264  }
265 
266  // tdf#135997: make sure that the two lists are same length
267  const auto nCommonLength = std::min(maFavCharList.size(), maFavCharFontList.size());
268  maFavCharList.resize(nCommonLength);
269  maFavCharFontList.resize(nCommonLength);
270 }
271 
272 static std::pair<std::deque<OUString>::const_iterator, std::deque<OUString>::const_iterator>
273 findInPair(std::u16string_view str1, const std::deque<OUString>& rContainer1,
274  std::u16string_view str2, const std::deque<OUString>& rContainer2)
275 {
276  assert(rContainer1.size() == rContainer2.size());
277 
278  if (auto it1 = std::find(rContainer1.begin(), rContainer1.end(), str1);
279  it1 != rContainer1.end())
280  {
281  auto it2 = rContainer2.begin() + (it1 - rContainer1.begin());
282  if (*it2 == str2)
283  return { it1, it2 };
284  }
285  return { rContainer1.end(), rContainer2.end() };
286 }
287 
288 std::pair<std::deque<OUString>::const_iterator, std::deque<OUString>::const_iterator>
289 SvxCharacterMap::getRecentChar(std::u16string_view sTitle, std::u16string_view rFont) const
290 {
291  return findInPair(sTitle, maRecentCharList, rFont, maRecentCharFontList);
292 }
293 
294 std::pair<std::deque<OUString>::const_iterator, std::deque<OUString>::const_iterator>
295 SvxCharacterMap::getFavChar(std::u16string_view sTitle, std::u16string_view rFont) const
296 {
297  return findInPair(sTitle, maFavCharList, rFont, maFavCharFontList);
298 }
299 
300 
302 {
303  assert(maRecentCharList.size() == maRecentCharFontList.size());
304 
305  int i = 0;
306  for ( std::deque< OUString >::iterator it = maRecentCharList.begin(), it2 = maRecentCharFontList.begin();
307  it != maRecentCharList.end() && it2 != maRecentCharFontList.end();
308  ++it, ++it2, i++)
309  {
310  m_aRecentCharView[i].SetText(*it);
311  vcl::Font rFont = m_aRecentCharView[i].GetFont();
312  rFont.SetFamilyName( *it2 );
313  m_aRecentCharView[i].SetFont(rFont);
314  m_aRecentCharView[i].Show();
315  }
316 
317  for(; i < 16 ; i++)
318  {
319  m_aRecentCharView[i].SetText(OUString());
320  m_aRecentCharView[i].Hide();
321  }
322 }
323 
324 void SvxCharacterMap::updateRecentCharacterList(const OUString& sTitle, const OUString& rFont)
325 {
326  // if recent char to be added is already in list, remove it
327  if( const auto& [itChar, itChar2] = getRecentChar(sTitle, rFont);
328  itChar != maRecentCharList.end() && itChar2 != maRecentCharFontList.end() )
329  {
330  maRecentCharList.erase( itChar );
331  maRecentCharFontList.erase( itChar2);
332  }
333 
334  if (maRecentCharList.size() == 16)
335  {
336  maRecentCharList.pop_back();
337  maRecentCharFontList.pop_back();
338  }
339 
340  maRecentCharList.push_front(sTitle);
341  maRecentCharFontList.push_front(rFont);
342 
343  css::uno::Sequence< OUString > aRecentCharList(maRecentCharList.size());
344  css::uno::Sequence< OUString > aRecentCharFontList(maRecentCharFontList.size());
345 
346  for (size_t i = 0; i < maRecentCharList.size(); ++i)
347  {
348  aRecentCharList[i] = maRecentCharList[i];
349  aRecentCharFontList[i] = maRecentCharFontList[i];
350  }
351 
352  std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
353  officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList, batch);
354  officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList, batch);
355  batch->commit();
356 
358 }
359 
360 
361 void SvxCharacterMap::updateFavCharacterList(const OUString& sTitle, const OUString& rFont)
362 {
363  // if Fav char to be added is already in list, remove it
364  if( const auto& [itChar, itChar2] = getFavChar(sTitle, rFont);
365  itChar != maFavCharList.end() && itChar2 != maFavCharFontList.end() )
366  {
367  maFavCharList.erase( itChar );
368  maFavCharFontList.erase( itChar2);
369  }
370 
371  if (maFavCharList.size() == 16)
372  {
373  maFavCharList.pop_back();
374  maFavCharFontList.pop_back();
375  }
376 
377  maFavCharList.push_back(sTitle);
378  maFavCharFontList.push_back(rFont);
379 
380  css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
381  css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
382 
383  for (size_t i = 0; i < maFavCharList.size(); ++i)
384  {
385  aFavCharList[i] = maFavCharList[i];
386  aFavCharFontList[i] = maFavCharFontList[i];
387  }
388 
389  std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
390  officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
391  officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
392  batch->commit();
393 }
394 
395 
397 {
398  assert(maFavCharList.size() == maFavCharFontList.size());
399 
400  int i = 0;
401  for ( std::deque< OUString >::iterator it = maFavCharList.begin(), it2 = maFavCharFontList.begin();
402  it != maFavCharList.end() && it2 != maFavCharFontList.end();
403  ++it, ++it2, i++)
404  {
405  m_aFavCharView[i].SetText(*it);
406  vcl::Font rFont = m_aFavCharView[i].GetFont();
407  rFont.SetFamilyName( *it2 );
408  m_aFavCharView[i].SetFont(rFont);
409  m_aFavCharView[i].Show();
410  }
411 
412  for(; i < 16 ; i++)
413  {
414  m_aFavCharView[i].SetText(OUString());
415  m_aFavCharView[i].Hide();
416  }
417  m_xShowSet->getFavCharacterList();
418  m_xSearchSet->getFavCharacterList();
419 }
420 
421 void SvxCharacterMap::deleteFavCharacterFromList(std::u16string_view sTitle, std::u16string_view rFont)
422 {
423  // if Fav char is found, remove it
424  if( const auto& [itChar, itChar2] = getFavChar(sTitle, rFont);
425  itChar != maFavCharList.end() && itChar2 != maFavCharFontList.end() )
426  {
427  maFavCharList.erase( itChar );
428  maFavCharFontList.erase( itChar2);
429  }
430 
431  css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
432  css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
433 
434  for (size_t i = 0; i < maFavCharList.size(); ++i)
435  {
436  aFavCharList[i] = maFavCharList[i];
437  aFavCharFontList[i] = maFavCharFontList[i];
438  }
439 
440  std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
441  officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
442  officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
443  batch->commit();
444 }
445 
447 {
448  aFont = m_xVirDev->GetFont();
449  aFont.SetTransparent( true );
452  aFont.SetCharSet( RTL_TEXTENCODING_DONTKNOW );
453 
454  OUString aDefStr( aFont.GetFamilyName() );
455  OUString aLastName;
456  int nCount = m_xVirDev->GetFontFaceCollectionCount();
457  std::vector<weld::ComboBoxEntry> aEntries;
458  aEntries.reserve(nCount);
459  for (int i = 0; i < nCount; ++i)
460  {
461  OUString aFontName( m_xVirDev->GetFontMetricFromCollection( i ).GetFamilyName() );
462  if (aFontName != aLastName)
463  {
464  aLastName = aFontName;
465  aEntries.emplace_back(aFontName, OUString::number(i));
466  }
467  }
468  m_xFontLB->insert_vector(aEntries, true);
469  // the font may not be in the list =>
470  // try to find a font name token in list and select found font,
471  // else select topmost entry
472  bool bFound = (m_xFontLB->find_text(aDefStr) == -1);
473  if (!bFound)
474  {
475  sal_Int32 nIndex = 0;
476  do
477  {
478  OUString aToken = aDefStr.getToken(0, ';', nIndex);
479  if (m_xFontLB->find_text(aToken) != -1)
480  {
481  aDefStr = aToken;
482  bFound = true;
483  break;
484  }
485  }
486  while ( nIndex >= 0 );
487  }
488 
489  if (bFound)
490  m_xFontLB->set_active_text(aDefStr);
491  else if (m_xFontLB->get_count() )
492  m_xFontLB->set_active(0);
493  FontSelectHdl(*m_xFontLB);
494  if (m_xSubsetLB->get_count())
495  m_xSubsetLB->set_active(0);
496 
497  m_xFontLB->connect_changed(LINK( this, SvxCharacterMap, FontSelectHdl));
498  m_xSubsetLB->connect_changed(LINK( this, SvxCharacterMap, SubsetSelectHdl));
499  m_xOKBtn->connect_clicked(LINK(this, SvxCharacterMap, InsertClickHdl));
500  m_xOKBtn->show();
501 
502  m_xShowSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) );
503  m_xShowSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) );
504  m_xShowSet->SetHighlightHdl( LINK( this, SvxCharacterMap, CharHighlightHdl ) );
505  m_xShowSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) );
506  m_xShowSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
507 
508  m_xSearchSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, SearchCharDoubleClickHdl ) );
509  m_xSearchSet->SetSelectHdl( LINK( this, SvxCharacterMap, SearchCharSelectHdl ) );
510  m_xSearchSet->SetHighlightHdl( LINK( this, SvxCharacterMap, SearchCharHighlightHdl ) );
511  m_xSearchSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, SearchCharPreSelectHdl ) );
512  m_xSearchSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
513 
514  m_xDecimalCodeText->connect_changed( LINK( this, SvxCharacterMap, DecimalCodeChangeHdl ) );
515  m_xHexCodeText->connect_changed( LINK( this, SvxCharacterMap, HexCodeChangeHdl ) );
516  m_xFavouritesBtn->connect_clicked( LINK(this, SvxCharacterMap, FavSelectHdl));
517 
518  // tdf#117038 set the buttons width to its max possible width so it doesn't
519  // make layout change when the label changes
520  m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_REMOVE_FAVORITES));
521  auto nMaxWidth = m_xFavouritesBtn->get_preferred_size().Width();
522  m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_ADD_FAVORITES));
523  nMaxWidth = std::max(nMaxWidth, m_xFavouritesBtn->get_preferred_size().Width());
524  m_xFavouritesBtn->set_size_request(nMaxWidth, -1);
525 
526  if( SvxShowCharSet::getSelectedChar() == ' ')
527  {
528  m_xOKBtn->set_sensitive(false);
529  }
530  else
531  {
532  sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
533  // using the new UCS4 constructor
534  OUString aOUStr( &cChar, 1 );
535  m_aShowChar.SetText(aOUStr);
536 
537  setFavButtonState(aOUStr, aDefStr);
538  m_xOKBtn->set_sensitive(true);
539  }
540 
543 
546 
547  bool bHasInsert = m_xFrame.is();
548 
549  for(int i = 0; i < 16; i++)
550  {
551  m_aRecentCharView[i].SetHasInsert(bHasInsert);
553  m_aRecentCharView[i].setClearClickHdl(LINK(this,SvxCharacterMap, RecentClearClickHdl));
554  m_aRecentCharView[i].setClearAllClickHdl(LINK(this,SvxCharacterMap, RecentClearAllClickHdl));
555  m_aFavCharView[i].SetHasInsert(bHasInsert);
556  m_aFavCharView[i].setMouseClickHdl(LINK(this,SvxCharacterMap, CharClickHdl));
557  m_aFavCharView[i].setClearClickHdl(LINK(this,SvxCharacterMap, FavClearClickHdl));
558  m_aFavCharView[i].setClearAllClickHdl(LINK(this,SvxCharacterMap, FavClearAllClickHdl));
559  }
560 
561  setCharName(90);
562 
563  m_xSearchText->connect_focus_in(LINK( this, SvxCharacterMap, SearchFieldGetFocusHdl ));
564  m_xSearchText->connect_changed(LINK(this, SvxCharacterMap, SearchUpdateHdl));
565 }
566 
567 bool SvxCharacterMap::isFavChar(std::u16string_view sTitle, std::u16string_view rFont)
568 {
569  const auto& [itChar, itFont] = getFavChar(sTitle, rFont);
570  return itChar != maFavCharList.end() && itFont != maFavCharFontList.end();
571 }
572 
573 
574 void SvxCharacterMap::setFavButtonState(std::u16string_view sTitle, std::u16string_view rFont)
575 {
576  if(sTitle.empty() || rFont.empty())
577  {
578  m_xFavouritesBtn->set_sensitive(false);
579  return;
580  }
581  else
582  m_xFavouritesBtn->set_sensitive(true);
583 
584  if (isFavChar(sTitle, rFont))
585  {
586  m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_REMOVE_FAVORITES));
587  }
588  else
589  {
590  if(maFavCharList.size() == 16)
591  {
592  m_xFavouritesBtn->set_sensitive(false);
593  }
594 
595  m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_ADD_FAVORITES));
596  }
597 }
598 
599 
601 {
602  // first get the underlying info in order to get font names
603  // like "Times New Roman;Times" resolved
604  vcl::Font aTmp(m_xVirDev->GetFontMetric(rFont));
605 
606  if (aTmp.GetFamilyName() == "StarSymbol" && m_xFontLB->find_text(aTmp.GetFamilyName()) == -1)
607  {
608  //if for some reason, like font in an old document, StarSymbol is requested and it's not available, then
609  //try OpenSymbol instead
610  aTmp.SetFamilyName("OpenSymbol");
611  }
612 
613  if (m_xFontLB->find_text(aTmp.GetFamilyName()) == -1)
614  return;
615 
616  m_xFontLB->set_active_text(aTmp.GetFamilyName());
617  aFont = aTmp;
618  FontSelectHdl(*m_xFontLB);
619  if (m_xSubsetLB->get_count())
620  m_xSubsetLB->set_active(0);
621 }
622 
624 {
625  SubsetMap aAll(nullptr);
626  std::vector<weld::ComboBoxEntry> aEntries;
627  for (auto & subset : aAll.GetSubsetMap())
628  aEntries.emplace_back(subset.GetName());
629  rListBox.insert_vector(aEntries, true);
630 }
631 
632 void SvxCharacterMap::insertCharToDoc(const OUString& sGlyph)
633 {
634  if(sGlyph.isEmpty())
635  return;
636 
637  if (m_xFrame.is()) {
638  uno::Sequence<beans::PropertyValue> aArgs(2);
639  aArgs[0].Name = "Symbols";
640  aArgs[0].Value <<= sGlyph;
641 
642  aArgs[1].Name = "FontName";
643  aArgs[1].Value <<= aFont.GetFamilyName();
644  comphelper::dispatchCommand(".uno:InsertSymbol", m_xFrame, aArgs);
645 
647 
648  } else {
649  sal_UCS4 cChar = sGlyph.iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
650  const SfxItemPool* pPool = m_xOutputSet->GetPool();
651  m_xOutputSet->Put( SfxStringItem( pPool->GetWhich(SID_CHARMAP), sGlyph ) );
653  aFont.GetStyleName(), aFont.GetPitch(), aFont.GetCharSet(), pPool->GetWhich(SID_ATTR_CHAR_FONT) ) );
654  m_xOutputSet->Put( SfxStringItem( pPool->GetWhich(SID_FONT_NAME), aFont.GetFamilyName() ) );
655  m_xOutputSet->Put( SfxInt32Item( pPool->GetWhich(SID_ATTR_CHAR), cChar ) );
656  }
657 }
658 
660 {
661  const sal_uInt32 nFont = m_xFontLB->get_active_id().toUInt32();
662  aFont = m_xVirDev->GetFontMetricFromCollection(nFont);
663  aFont.SetWeight( WEIGHT_DONTKNOW );
664  aFont.SetItalic( ITALIC_NONE );
665  aFont.SetWidthType( WIDTH_DONTKNOW );
666  aFont.SetPitch( PITCH_DONTKNOW );
667  aFont.SetFamily( FAMILY_DONTKNOW );
668 
669  // notify children using this font
670  m_xShowSet->SetFont( aFont );
671  m_xSearchSet->SetFont( aFont );
672  m_aShowChar.SetFont( aFont );
673 
674  // setup unicode subset listbar with font specific subsets,
675  // hide unicode subset listbar for symbol fonts
676  // TODO: get info from the Font once it provides it
677  pSubsetMap.reset();
678  m_xSubsetLB->clear();
679 
680  bool bNeedSubset = (aFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL);
681  if (bNeedSubset)
682  {
683  FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap();
684  pSubsetMap.reset(new SubsetMap( xFontCharMap ));
685 
686  // update subset listbox for new font's unicode subsets
687  for (auto const& subset : pSubsetMap->GetSubsetMap())
688  {
689  m_xSubsetLB->append(OUString::number(reinterpret_cast<sal_uInt64>(&subset)), subset.GetName());
690  // NOTE: subset must live at least as long as the selected font
691  }
692 
693  if (m_xSubsetLB->get_count() <= 1)
694  bNeedSubset = false;
695  }
696 
697  m_xSubsetText->set_sensitive(bNeedSubset);
698  m_xSubsetLB->set_sensitive(bNeedSubset);
699 
700  if (isSearchMode)
701  {
702  // tdf#137294 do this after modifying m_xSubsetLB sensitivity to
703  // restore insensitive for the search case
704  SearchUpdateHdl(*m_xSearchText);
705  SearchCharHighlightHdl(m_xSearchSet.get());
706  }
707 
708  // tdf#118304 reselect current glyph to see if its still there in new font
709  selectCharByCode(Radix::hexadecimal);
710 }
711 
713 {
714  isSearchMode = state;
715  m_xHexCodeText->set_editable(!state);
716  m_xDecimalCodeText->set_editable(!state);
717  m_xSubsetLB->set_sensitive(!state);
718 
719  if(state)
720  {
721  m_xSearchSet->Show();
722  m_xShowSet->Hide();
723  }
724  else
725  {
726  m_xSearchSet->Hide();
727  m_xShowSet->Show();
728  }
729 }
730 
732 {
733  /* get the character name */
734  UErrorCode errorCode = U_ZERO_ERROR;
735  // icu has a private uprv_getMaxCharNameLength function which returns the max possible
736  // length of this property. Unicode 3.2 max char name length was 83
737  char buffer[100];
738  u_charName(nDecimalValue, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
739  if (U_SUCCESS(errorCode))
740  m_xCharName->set_label(OUString::createFromAscii(buffer));
741 }
742 
744 {
745  const sal_Int32 nPos = m_xSubsetLB->get_active();
746  const Subset* pSubset = reinterpret_cast<const Subset*>(m_xSubsetLB->get_active_id().toUInt64());
747 
748  if( pSubset && !isSearchMode)
749  {
750  sal_UCS4 cFirst = pSubset->GetRangeMin();
751  m_xShowSet->SelectCharacter( cFirst );
752 
753  setFavButtonState(OUString(&cFirst, 1), aFont.GetFamilyName());
754  m_xSubsetLB->set_active(nPos);
755  }
756  else if( pSubset && isSearchMode)
757  {
758  m_xSearchSet->SelectCharacter( pSubset );
759 
760  const Subset* curSubset = nullptr;
761  if( pSubsetMap )
762  curSubset = pSubsetMap->GetSubsetByUnicode( m_xSearchSet->GetSelectCharacter() );
763  if( curSubset )
764  m_xSubsetLB->set_active_text(curSubset->GetName());
765  else
766  m_xSubsetLB->set_active(-1);
767 
768  sal_UCS4 sChar = m_xSearchSet->GetSelectCharacter();
769  setFavButtonState(OUString(&sChar, 1), aFont.GetFamilyName());
770  }
771 }
772 
773 IMPL_LINK(SvxCharacterMap, RecentClearClickHdl, SvxCharView*, rView, void)
774 {
775  const OUString& sTitle = rView->GetText();
776  OUString sFont = rView->GetFont().GetFamilyName();
777 
778  // if recent char to be added is already in list, remove it
779  if( const auto& [itChar, itChar2] = getRecentChar(sTitle, sFont);
780  itChar != maRecentCharList.end() && itChar2 != maRecentCharFontList.end() )
781  {
782  maRecentCharList.erase( itChar );
783  maRecentCharFontList.erase( itChar2);
784  }
785 
786  css::uno::Sequence< OUString > aRecentCharList(maRecentCharList.size());
787  css::uno::Sequence< OUString > aRecentCharFontList(maRecentCharFontList.size());
788 
789  for (size_t i = 0; i < maRecentCharList.size(); ++i)
790  {
791  aRecentCharList[i] = maRecentCharList[i];
792  aRecentCharFontList[i] = maRecentCharFontList[i];
793  }
794 
795  std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
796  officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList, batch);
797  officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList, batch);
798  batch->commit();
799 
800  updateRecentCharControl();
801 }
802 
803 IMPL_LINK_NOARG(SvxCharacterMap, RecentClearAllClickHdl, SvxCharView*, void)
804 {
805  css::uno::Sequence< OUString > aRecentCharList(0);
806  css::uno::Sequence< OUString > aRecentCharFontList(0);
807 
808  maRecentCharList.clear();
809  maRecentCharFontList.clear();
810 
811  std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
812  officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList, batch);
813  officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList, batch);
814  batch->commit();
815 
816  updateRecentCharControl();
817 }
818 
819 IMPL_LINK(SvxCharacterMap, FavClearClickHdl, SvxCharView*, rView, void)
820 {
821  deleteFavCharacterFromList(rView->GetText(), rView->GetFont().GetFamilyName());
822  updateFavCharControl();
823 }
824 
825 IMPL_LINK_NOARG(SvxCharacterMap, FavClearAllClickHdl, SvxCharView*, void)
826 {
827  css::uno::Sequence< OUString > aFavCharList(0);
828  css::uno::Sequence< OUString > aFavCharFontList(0);
829 
830  maFavCharList.clear();
831  maFavCharFontList.clear();
832 
833  std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
834  officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
835  officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
836  batch->commit();
837 
838  updateFavCharControl();
839 }
840 
841 IMPL_LINK_NOARG(SvxCharacterMap, SearchFieldGetFocusHdl, weld::Widget&, void)
842 {
843  m_xOKBtn->set_sensitive(false);
844 }
845 
846 IMPL_LINK_NOARG(SvxCharacterMap, SearchUpdateHdl, weld::Entry&, void)
847 {
848  if (!m_xSearchText->get_text().isEmpty())
849  {
850  m_xSearchSet->ClearPreviousData();
851  OUString aKeyword = m_xSearchText->get_text();
852 
853  toggleSearchView(true);
854 
855  FontCharMapRef xFontCharMap = m_xSearchSet->GetFontCharMap();
856 
857  sal_UCS4 sChar = xFontCharMap->GetFirstChar();
858  while(sChar != xFontCharMap->GetLastChar())
859  {
860  UErrorCode errorCode = U_ZERO_ERROR;
861  char buffer[100];
862  u_charName(sChar, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
863  if (U_SUCCESS(errorCode))
864  {
865  OUString sName = OUString::createFromAscii(buffer);
866  if(!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword.toAsciiLowerCase()) >= 0)
867  m_xSearchSet->AppendCharToList(sChar);
868  }
869  sChar = xFontCharMap->GetNextChar(sChar);
870  }
871  //for last char
872  UErrorCode errorCode = U_ZERO_ERROR;
873  char buffer[100];
874  u_charName(sChar, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
875  if (U_SUCCESS(errorCode))
876  {
877  OUString sName = OUString::createFromAscii(buffer);
878  if(!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword.toAsciiLowerCase()) >= 0)
879  m_xSearchSet->AppendCharToList(sChar);
880  }
881  }
882  else
883  {
884  toggleSearchView(false);
885  }
886 }
887 
888 
889 IMPL_LINK(SvxCharacterMap, CharClickHdl, SvxCharView*, rView, void)
890 {
891  rView->GrabFocus();
892 
893  m_aShowChar.SetText( rView->GetText() );
894  m_aShowChar.SetFont(rView->GetFont());
895  m_aShowChar.Invalidate();
896 
897  setFavButtonState(rView->GetText(), rView->GetFont().GetFamilyName());//check state
898 
899  // Get the hexadecimal code
900  OUString charValue = rView->GetText();
901  sal_UCS4 cChar = charValue.iterateCodePoints(&o3tl::temporary(sal_Int32(1)), -1);
902  OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
903 
904  // Get the decimal code
905  OUString aDecimalText = OUString::number(cChar);
906 
907  m_xHexCodeText->set_text(aHexText);
908  m_xDecimalCodeText->set_text(aDecimalText);
909  setCharName(cChar);
910 
911  rView->Invalidate();
912  m_xOKBtn->set_sensitive(true);
913 }
914 
915 IMPL_LINK_NOARG(SvxCharacterMap, CharDoubleClickHdl, SvxShowCharSet*, void)
916 {
917  sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
918  // using the new UCS4 constructor
919  OUString aOUStr( &cChar, 1 );
920  setFavButtonState(aOUStr, aFont.GetFamilyName());
921  insertCharToDoc(aOUStr);
922 }
923 
924 IMPL_LINK_NOARG(SvxCharacterMap, SearchCharDoubleClickHdl, SvxShowCharSet*, void)
925 {
926  sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
927  // using the new UCS4 constructor
928  OUString aOUStr( &cChar, 1 );
929  setFavButtonState(aOUStr, aFont.GetFamilyName());
930  insertCharToDoc(aOUStr);
931 }
932 
934 {
935  m_xOKBtn->set_sensitive(true);
936 }
937 
938 IMPL_LINK_NOARG(SvxCharacterMap, SearchCharSelectHdl, SvxShowCharSet*, void)
939 {
940  m_xOKBtn->set_sensitive(true);
941 }
942 
944 {
945  OUString sChar = m_aShowChar.GetText();
946  insertCharToDoc(sChar);
947  // Need to update recent character list, when OK button does not insert
948  if(!m_xFrame.is())
949  updateRecentCharacterList(sChar, aFont.GetFamilyName());
950  m_xDialog->response(RET_OK);
951 }
952 
954 {
955  if (m_xFavouritesBtn->get_label().match(CuiResId(RID_SVXSTR_ADD_FAVORITES)))
956  {
957  updateFavCharacterList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
958  setFavButtonState(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
959  }
960  else
961  {
962  deleteFavCharacterFromList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
963  m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_ADD_FAVORITES));
964  m_xFavouritesBtn->set_sensitive(false);
965  }
966 
967  updateFavCharControl();
968 }
969 
971 {
972  getFavCharacterList();
973  updateFavCharControl();
974 }
975 
977 {
978  OUString aText;
979  sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
980  bool bSelect = (cChar > 0);
981 
982  // show char sample
983  if ( bSelect )
984  {
985  // using the new UCS4 constructor
986  aText = OUString( &cChar, 1 );
987  // Get the hexadecimal code
988  OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
989  // Get the decimal code
990  OUString aDecimalText = OUString::number(cChar);
991  setCharName(cChar);
992 
993  // Update the hex and decimal codes only if necessary
994  if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
995  m_xHexCodeText->set_text(aHexText);
996  if (m_xDecimalCodeText->get_text() != aDecimalText)
997  m_xDecimalCodeText->set_text( aDecimalText );
998 
999  const Subset* pSubset = nullptr;
1000  if( pSubsetMap )
1001  pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
1002  if( pSubset )
1003  m_xSubsetLB->set_active_text(pSubset->GetName());
1004  else
1005  m_xSubsetLB->set_active(-1);
1006  }
1007 
1008  m_aShowChar.SetText( aText );
1009  m_aShowChar.SetFont( aFont );
1010  m_aShowChar.Invalidate();
1011 
1012  setFavButtonState(aText, aFont.GetFamilyName());
1013 }
1014 
1015 IMPL_LINK_NOARG(SvxCharacterMap, SearchCharHighlightHdl, SvxShowCharSet*, void)
1016 {
1017  OUString aText;
1018  sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
1019  bool bSelect = (cChar > 0);
1020 
1021  // show char sample
1022  if ( bSelect )
1023  {
1024  aText = OUString( &cChar, 1 );
1025  // Get the hexadecimal code
1026  OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
1027  // Get the decimal code
1028  OUString aDecimalText = OUString::number(cChar);
1029  setCharName(cChar);
1030 
1031  // Update the hex and decimal codes only if necessary
1032  if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
1033  m_xHexCodeText->set_text(aHexText);
1034  if (m_xDecimalCodeText->get_text() != aDecimalText)
1035  m_xDecimalCodeText->set_text( aDecimalText );
1036 
1037  const Subset* pSubset = nullptr;
1038  if( pSubsetMap )
1039  pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
1040  if( pSubset )
1041  m_xSubsetLB->set_active_text(pSubset->GetName());
1042  else
1043  m_xSubsetLB->set_active(-1);
1044  }
1045 
1046  if(m_xSearchSet->HasFocus())
1047  {
1048  m_aShowChar.SetText( aText );
1049  m_aShowChar.SetFont( aFont );
1050  m_aShowChar.Invalidate();
1051 
1052  setFavButtonState(aText, aFont.GetFamilyName());
1053  }
1054 }
1055 
1057 {
1058  OUString aCodeString;
1059  switch(radix)
1060  {
1061  case Radix::decimal:
1062  aCodeString = m_xDecimalCodeText->get_text();
1063  break;
1064  case Radix::hexadecimal:
1065  aCodeString = m_xHexCodeText->get_text();
1066  break;
1067  }
1068  // Convert the code back to a character using the appropriate radix
1069  sal_UCS4 cChar = aCodeString.toUInt32(static_cast<sal_Int16> (radix));
1070  // Use FontCharMap::HasChar(sal_UCS4 cChar) to see if the desired character is in the font
1071  FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap();
1072  if (xFontCharMap->HasChar(cChar))
1073  // Select the corresponding character
1074  SetChar(cChar);
1075  else {
1076  m_xCharName->set_label(CuiResId(RID_SVXSTR_MISSING_CHAR));
1077  m_aShowChar.SetText(" ");
1078  switch(radix)
1079  {
1080  case Radix::decimal:
1081  m_xHexCodeText->set_text(OUString::number(cChar, 16));
1082  break;
1083  case Radix::hexadecimal:
1084  m_xDecimalCodeText->set_text(OUString::number(cChar));
1085  break;
1086  }
1087  }
1088 }
1089 
1090 IMPL_LINK_NOARG(SvxCharacterMap, DecimalCodeChangeHdl, weld::Entry&, void)
1091 {
1092  selectCharByCode(Radix::decimal);
1093 }
1094 
1095 IMPL_LINK_NOARG(SvxCharacterMap, HexCodeChangeHdl, weld::Entry&, void)
1096 {
1097  selectCharByCode(Radix::hexadecimal);
1098 }
1099 
1101 {
1102  // adjust subset selection
1103  if( pSubsetMap )
1104  {
1105  sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
1106 
1107  setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName());
1108  const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
1109  if( pSubset )
1110  m_xSubsetLB->set_active_text(pSubset->GetName());
1111  }
1112 
1113  m_xOKBtn->set_sensitive(true);
1114 }
1115 
1116 IMPL_LINK_NOARG(SvxCharacterMap, SearchCharPreSelectHdl, SvxShowCharSet*, void)
1117 {
1118  // adjust subset selection
1119  if( pSubsetMap )
1120  {
1121  sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
1122 
1123  setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName());
1124  const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
1125  if( pSubset )
1126  m_xSubsetLB->set_active_text(pSubset->GetName());
1127  }
1128 
1129  m_xOKBtn->set_sensitive(true);
1130 }
1131 
1132 // class SvxShowText =====================================================
1134  : m_xVirDev(rVirDev)
1135  , mnY(0)
1136  , mbCenter(false)
1137 {
1138 }
1139 
1141 {
1142  CustomWidgetController::SetDrawingArea(pDrawingArea);
1143  vcl::Font aFont = m_xVirDev->GetFont();
1144  Size aFontSize(aFont.GetFontSize().Width() * 5, aFont.GetFontSize().Height() * 5);
1145  aFont.SetFontSize(aFontSize);
1146  m_xVirDev->Push(PUSH_ALLFONT);
1147  m_xVirDev->SetFont(aFont);
1148  pDrawingArea->set_size_request(m_xVirDev->approximate_digit_width() + 2 * 12,
1149  m_xVirDev->LogicToPixel(aFontSize).Height() * 2);
1150  m_xVirDev->Pop();
1151 }
1152 
1154 {
1155  rRenderContext.SetFont(m_aFont);
1156 
1157  Color aTextCol = rRenderContext.GetTextColor();
1158  Color aFillCol = rRenderContext.GetFillColor();
1159 
1160  const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1161  const Color aWindowTextColor(rStyleSettings.GetDialogTextColor());
1162  const Color aWindowColor(rStyleSettings.GetWindowColor());
1163  rRenderContext.SetTextColor(aWindowTextColor);
1164  rRenderContext.SetFillColor(aWindowColor);
1165 
1166  const OUString aText = GetText();
1167 
1168  Size aSize(GetOutputSizePixel());
1169  tools::Long nAvailWidth = aSize.Width();
1170  tools::Long nWinHeight = aSize.Height();
1171 
1172  bool bGotBoundary = true;
1173  bool bShrankFont = false;
1174  vcl::Font aOrigFont(rRenderContext.GetFont());
1175  Size aFontSize(aOrigFont.GetFontSize());
1176  ::tools::Rectangle aBoundRect;
1177 
1178  for (tools::Long nFontHeight = aFontSize.Height(); nFontHeight > 0; nFontHeight -= 5)
1179  {
1180  if (!rRenderContext.GetTextBoundRect( aBoundRect, aText ) || aBoundRect.IsEmpty())
1181  {
1182  bGotBoundary = false;
1183  break;
1184  }
1185  if (!mbCenter)
1186  break;
1187  //only shrink in the single glyph large view mode
1188  tools::Long nTextWidth = aBoundRect.GetWidth();
1189  if (nAvailWidth > nTextWidth)
1190  break;
1191  vcl::Font aFont(aOrigFont);
1192  aFontSize.setHeight( nFontHeight );
1193  aFont.SetFontSize(aFontSize);
1194  rRenderContext.SetFont(aFont);
1195  mnY = (nWinHeight - rRenderContext.GetTextHeight()) / 2;
1196  bShrankFont = true;
1197  }
1198 
1199  Point aPoint(2, mnY);
1200  // adjust position using ink boundary if possible
1201  if (!bGotBoundary)
1202  aPoint.setX( (aSize.Width() - rRenderContext.GetTextWidth(aText)) / 2 );
1203  else
1204  {
1205  // adjust position before it gets out of bounds
1206  aBoundRect += aPoint;
1207 
1208  // shift back vertically if needed
1209  int nYLDelta = aBoundRect.Top();
1210  int nYHDelta = aSize.Height() - aBoundRect.Bottom();
1211  if( nYLDelta <= 0 )
1212  aPoint.AdjustY( -(nYLDelta - 1) );
1213  else if( nYHDelta <= 0 )
1214  aPoint.AdjustY(nYHDelta - 1 );
1215 
1216  if (mbCenter)
1217  {
1218  // move glyph to middle of cell
1219  aPoint.setX( -aBoundRect.Left() + (aSize.Width() - aBoundRect.GetWidth()) / 2 );
1220  }
1221  else
1222  {
1223  // shift back horizontally if needed
1224  int nXLDelta = aBoundRect.Left();
1225  int nXHDelta = aSize.Width() - aBoundRect.Right();
1226  if( nXLDelta <= 0 )
1227  aPoint.AdjustX( -(nXLDelta - 1) );
1228  else if( nXHDelta <= 0 )
1229  aPoint.AdjustX(nXHDelta - 1 );
1230  }
1231  }
1232 
1233  rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), aSize));
1234  rRenderContext.DrawText(aPoint, aText);
1235  rRenderContext.SetTextColor(aTextCol);
1236  rRenderContext.SetFillColor(aFillCol);
1237  if (bShrankFont)
1238  rRenderContext.SetFont(aOrigFont);
1239 }
1240 
1241 void SvxShowText::SetFont( const vcl::Font& rFont )
1242 {
1243  tools::Long nWinHeight = GetOutputSizePixel().Height();
1244 
1245  m_aFont = rFont;
1248  m_aFont.SetFontSize(m_xVirDev->PixelToLogic(Size(0, nWinHeight / 2)));
1249  m_aFont.SetTransparent(true);
1250 
1251  m_xVirDev->Push(PUSH_ALLFONT);
1252  m_xVirDev->SetFont(m_aFont);
1253  mnY = (nWinHeight - m_xVirDev->GetTextHeight()) / 2;
1254  m_xVirDev->Pop();
1255 
1256  Invalidate();
1257 }
1258 
1260 {
1261  SetFont(GetFont()); //force recalculation of size
1262 }
1263 
1264 void SvxShowText::SetText(const OUString& rText)
1265 {
1266  m_sText = rText;
1267  Invalidate();
1268 }
1269 
1270 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void updateRecentCharControl()
Definition: cuicharmap.cxx:301
void SetFamily(FontFamily)
const Color & GetTextColor() const
bool HasChar(sal_UCS4) const
sal_Int32 GetValue() const
SvxCharView m_aFavCharView[16]
Definition: cuicharmap.hxx:93
sal_Int32 nIndex
void SetFontSize(const Size &)
SvxShowText m_aShowChar
Definition: cuicharmap.hxx:94
ScopedVclPtr< VirtualDevice > m_xVirDev
Definition: cuicharmap.hxx:52
const OUString & GetFamilyName() const
tools::Long mnY
Definition: cuicharmap.hxx:54
sal_uInt32 sal_UCS4
const OUString & GetStyleName() const
const SubsetVec & GetSubsetMap() const
uno::Reference< uno::XComponentContext > mxContext
void Create(SwFormatVertOrient &rItem, SvStream &rStrm, sal_uInt16 nVersionAbusedAsSize)
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &) override
long Long
FAMILY_DONTKNOW
const OUString & GetName() const
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
std::unique_ptr< SvxSearchCharSet > m_xSearchSet
Definition: cuicharmap.hxx:113
void SetChar(sal_UCS4)
Definition: cuicharmap.cxx:207
css::uno::Reference< css::lang::XComponent > m_xFrame
void SetWeight(FontWeight)
void SetFont(const vcl::Font &rFont)
std::deque< OUString > maRecentCharList
Definition: cuicharmap.hxx:86
void setFavButtonState(std::u16string_view sTitle, std::u16string_view rFont)
Definition: cuicharmap.cxx:574
static void fillAllSubsets(weld::ComboBox &rListBox)
Definition: cuicharmap.cxx:623
void insertCharToDoc(const OUString &sChar)
Definition: cuicharmap.cxx:632
void SetCharSet(rtl_TextEncoding)
std::pair< std::deque< OUString >::const_iterator, std::deque< OUString >::const_iterator > getFavChar(std::u16string_view sTitle, std::u16string_view rFont) const
Definition: cuicharmap.cxx:295
FontPitch GetPitch() const
OUString const & GetText() const
Definition: cuicharmap.hxx:68
ScopedVclPtr< VirtualDevice > m_xVirDev
Definition: cuicharmap.hxx:81
std::pair< std::deque< OUString >::const_iterator, std::deque< OUString >::const_iterator > getRecentChar(std::u16string_view sTitle, std::u16string_view rFont) const
Definition: cuicharmap.cxx:289
Size const & GetOutputSizePixel() const
FontFamily GetFamilyType()
void selectCharByCode(Radix radix)
SfxApplication * SfxGetpApp()
std::unique_ptr< SfxAllItemSet > m_xOutputSet
Definition: cuicharmap.hxx:116
OUString m_sText
Definition: cuicharmap.hxx:53
constexpr tools::Long Width() const
void toggleSearchView(bool state)
Definition: cuicharmap.cxx:712
const vcl::Font & GetFont() const
std::unique_ptr< weld::Label > m_xFontText
Definition: cuicharmap.hxx:97
static sal_uInt32 & getSelectedChar()
rtl_TextEncoding GetCharSet() const
bool dispatchCommand(const OUString &rCommand, const uno::Reference< css::frame::XFrame > &rFrame, const css::uno::Sequence< css::beans::PropertyValue > &rArguments, const uno::Reference< css::frame::XDispatchResultListener > &rListener)
void deleteFavCharacterFromList(std::u16string_view rChar, std::u16string_view rFont)
Definition: cuicharmap.cxx:421
int nCount
constexpr tools::Long GetWidth() const
static std::shared_ptr< ConfigurationChanges > create(css::uno::Reference< css::uno::XComponentContext > const &context=comphelper::getProcessComponentContext())
std::unique_ptr< weld::ComboBox > m_xSubsetLB
Definition: cuicharmap.hxx:100
std::deque< OUString > maFavCharList
Definition: cuicharmap.hxx:88
void setCharName(sal_UCS4 nDecimalValue)
Definition: cuicharmap.cxx:731
const char * sName
void DrawRect(const tools::Rectangle &rRect)
void SetPitch(FontPitch ePitch)
SfxItemPool & GetPool() const
const OUString & GetStyleName() const
std::unique_ptr< weld::Entry > m_xDecimalCodeText
Definition: cuicharmap.hxx:103
uno::Reference< uno::XComponentContext > mxContext
Definition: cuicharmap.hxx:90
bool isFavChar(std::u16string_view sTitle, std::u16string_view rFont)
Definition: cuicharmap.cxx:567
css::uno::Reference< css::frame::XFrame > m_xFrame
Definition: cuicharmap.hxx:85
WEIGHT_DONTKNOW
OUString CuiResId(TranslateId aKey)
Definition: cuiresmgr.cxx:23
std::unique_ptr< SvxShowCharSet > m_xShowSet
Definition: cuicharmap.hxx:111
void updateRecentCharacterList(const OUString &rChar, const OUString &rFont)
Definition: cuicharmap.cxx:324
sal_UCS4 GetFirstChar() const
std::unique_ptr< weld::Button > m_xFavouritesBtn
Definition: cuicharmap.hxx:104
#define PUSH_ALLFONT
void SetFamilyName(const OUString &rFamilyName)
void getRecentCharacterList()
Definition: cuicharmap.cxx:225
void SetFont(const vcl::Font &rFont)
FontPitch GetPitch()
int i
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
void SetHasInsert(bool bInsert)
virtual void insert_vector(const std::vector< weld::ComboBoxEntry > &rItems, bool bKeepExisting)=0
vcl::Font m_aFont
Definition: cuicharmap.hxx:56
std::unique_ptr< weld::Entry > m_xHexCodeText
Definition: cuicharmap.hxx:102
void SetFillColor()
WEIGHT_NORMAL
float u
void SetTextColor(const Color &rColor)
void setClearAllClickHdl(const Link< SvxCharView *, void > &rLink)
const Size & GetFontSize() const
PITCH_DONTKNOW
void getFavCharacterList()
Definition: cuicharmap.cxx:248
void updateFavCharacterList(const OUString &rChar, const OUString &rFont)
Definition: cuicharmap.cxx:361
ITALIC_NONE
std::unique_ptr< weld::Entry > m_xSearchText
Definition: cuicharmap.hxx:101
vcl::Font aFont
Definition: cuicharmap.hxx:82
void SetText(const OUString &rText)
sal_UCS4 GetRangeMin() const
constexpr T & temporary(T &&x)
virtual short run() override
Definition: cuicharmap.cxx:186
void SetAlignment(TextAlign)
SvxCharacterMap(weld::Widget *pParent, const SfxItemSet *pSet, const css::uno::Reference< css::frame::XFrame > &rFrame)
Definition: cuicharmap.cxx:53
IMPL_LINK(SvxCharacterMap, RecentClearClickHdl, SvxCharView *, rView, void)
Definition: cuicharmap.cxx:773
const OUString & GetFamilyName() const
sal_UCS4 GetNextChar(sal_UCS4 cChar) const
std::deque< OUString > maFavCharFontList
Definition: cuicharmap.hxx:89
ALIGN_TOP
void setClearClickHdl(const Link< SvxCharView *, void > &rLink)
sal_uInt16 GetWhich(sal_uInt16 nSlot, bool bDeep=true) const
constexpr tools::Long Height() const
void setMouseClickHdl(const Link< SvxCharView *, void > &rLink)
WIDTH_DONTKNOW
std::deque< OUString > maRecentCharFontList
Definition: cuicharmap.hxx:87
void SetFont(const vcl::Font &rNewFont)
void SetTransparent(bool bTransparent)
tools::Long GetTextHeight() const
SvxShowText(const VclPtr< VirtualDevice > &rVirDev)
sal_UCS4 GetLastChar() const
RET_OK
Reference< XExecutableDialog > m_xDialog
Reference< XComponentContext > getProcessComponentContext()
void SetCharFont(const vcl::Font &rFont)
Definition: cuicharmap.cxx:600
void updateFavCharControl()
Definition: cuicharmap.cxx:396
const Color & GetWindowColor() const
virtual void SetDrawingArea(weld::DrawingArea *pDrawingArea) override
void DisableFontSelection()
Definition: cuicharmap.cxx:218
static std::pair< std::deque< OUString >::const_iterator, std::deque< OUString >::const_iterator > findInPair(std::u16string_view str1, const std::deque< OUString > &rContainer1, std::u16string_view str2, const std::deque< OUString > &rContainer2)
Definition: cuicharmap.cxx:273
FILE * init(int, char **)
std::unique_ptr< weld::ComboBox > m_xFontLB
Definition: cuicharmap.hxx:98
bool GetTextBoundRect(tools::Rectangle &rRect, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, const tools::Long *pDXArray=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
void SetText(const OUString &rText)
ScXMLEditAttributeMap::Entry const aEntries[]
sal_UCS4 GetChar() const
Definition: cuicharmap.cxx:213
vcl::Font const & GetFont() const
Definition: cuicharmap.hxx:66
The main purpose of this dialog is to enable the use of characters that are not easily accessible fro...
Definition: cuicharmap.hxx:76
IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, weld::ComboBox &, void)
Definition: cuicharmap.cxx:659
std::unique_ptr< weld::Button > m_xOKBtn
Definition: cuicharmap.hxx:96
const Color & GetDialogTextColor() const
virtual void set_size_request(int nWidth, int nHeight)=0
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
vcl::Font const & GetFont() const
rtl_TextEncoding GetCharSet() const
sal_uInt16 nPos
virtual void Resize() override
const Color & GetFillColor() const
SvxCharView m_aRecentCharView[16]
Definition: cuicharmap.hxx:92
std::unique_ptr< weld::Label > m_xCharName
Definition: cuicharmap.hxx:105