xref: /core/cui/source/tabpages/chardlg.cxx (revision 87e27e402edab3a231682626b6a65fa076d9ab08)
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 <vcl/svapp.hxx>
21 #include <vcl/idle.hxx>
22 #include <svtools/ctrltool.hxx>
23 #include <sfx2/objsh.hxx>
24 #include <svx/svxids.hrc>
25 #include <svtools/unitconv.hxx>
26 #include <svl/cjkoptions.hxx>
27 #include <svl/ctloptions.hxx>
28 #include <chardlg.hxx>
29 #include <editeng/fontitem.hxx>
30 #include <editeng/postitem.hxx>
31 #include <editeng/udlnitem.hxx>
32 #include <editeng/crossedoutitem.hxx>
33 #include <editeng/contouritem.hxx>
34 #include <editeng/langitem.hxx>
35 #include <editeng/wghtitem.hxx>
36 #include <editeng/fhgtitem.hxx>
37 #include <editeng/shdditem.hxx>
38 #include <editeng/escapementitem.hxx>
39 #include <editeng/wrlmitem.hxx>
40 #include <editeng/cmapitem.hxx>
41 #include <editeng/kernitem.hxx>
42 #include <editeng/flstitem.hxx>
43 #include <editeng/autokernitem.hxx>
44 #include <editeng/nhypitem.hxx>
45 #include <editeng/colritem.hxx>
46 #include <dialmgr.hxx>
47 #include <sfx2/htmlmode.hxx>
48 #include <svx/cuicharmap.hxx>
49 #include "chardlg.h"
50 #include <editeng/emphasismarkitem.hxx>
51 #include <editeng/charreliefitem.hxx>
52 #include <editeng/twolinesitem.hxx>
53 #include <editeng/charhiddenitem.hxx>
54 #include <editeng/charscaleitem.hxx>
55 #include <editeng/charrotateitem.hxx>
56 #include <officecfg/Office/Common.hxx>
57 #include <strings.hrc>
58 #include <twolines.hrc>
59 #include <svl/intitem.hxx>
60 #include <svx/flagsdef.hxx>
61 #include <FontFeatures.hxx>
62 #include <FontFeaturesDialog.hxx>
63 #include <sal/log.hxx>
64 #include <osl/diagnose.h>
65 #include <o3tl/unit_conversion.hxx>
66 #include <o3tl/string_view.hxx>
67 
68 using namespace ::com::sun::star;
69 
70 // static ----------------------------------------------------------------
71 
72 const WhichRangesContainer SvxCharNamePage::pNameRanges(svl::Items<
73     SID_ATTR_CHAR_FONT, SID_ATTR_CHAR_WEIGHT,
74     SID_ATTR_CHAR_FONTHEIGHT, SID_ATTR_CHAR_FONTHEIGHT,
75     SID_ATTR_CHAR_COLOR, SID_ATTR_CHAR_COLOR,
76     SID_ATTR_CHAR_LANGUAGE, SID_ATTR_CHAR_LANGUAGE,
77     SID_ATTR_CHAR_CJK_FONT, SID_ATTR_CHAR_CJK_WEIGHT,
78     SID_ATTR_CHAR_CTL_FONT, SID_ATTR_CHAR_CTL_WEIGHT
79 >);
80 
81 const WhichRangesContainer SvxCharEffectsPage::pEffectsRanges(svl::Items<
82     SID_ATTR_CHAR_SHADOWED, SID_ATTR_CHAR_UNDERLINE,
83     SID_ATTR_CHAR_COLOR, SID_ATTR_CHAR_COLOR,
84     SID_ATTR_CHAR_CASEMAP, SID_ATTR_CHAR_CASEMAP,
85     SID_ATTR_FLASH, SID_ATTR_FLASH,
86     SID_ATTR_CHAR_EMPHASISMARK, SID_ATTR_CHAR_EMPHASISMARK,
87     SID_ATTR_CHAR_RELIEF, SID_ATTR_CHAR_RELIEF,
88     SID_ATTR_CHAR_HIDDEN, SID_ATTR_CHAR_HIDDEN,
89     SID_ATTR_CHAR_OVERLINE, SID_ATTR_CHAR_OVERLINE
90 >);
91 
92 const WhichRangesContainer SvxCharPositionPage::pPositionRanges(svl::Items<
93     SID_ATTR_CHAR_KERNING, SID_ATTR_CHAR_KERNING,
94     SID_ATTR_CHAR_ESCAPEMENT, SID_ATTR_CHAR_ESCAPEMENT,
95     SID_ATTR_CHAR_AUTOKERN, SID_ATTR_CHAR_AUTOKERN,
96     SID_ATTR_CHAR_ROTATED, SID_ATTR_CHAR_SCALEWIDTH,
97     SID_ATTR_CHAR_WIDTH_FIT_TO_LINE, SID_ATTR_CHAR_WIDTH_FIT_TO_LINE
98 >);
99 
100 const WhichRangesContainer SvxCharTwoLinesPage::pTwoLinesRanges(svl::Items<
101     SID_ATTR_CHAR_TWO_LINES, SID_ATTR_CHAR_TWO_LINES
102 >);
103 
104 // C-Function ------------------------------------------------------------
105 
StateToAttr(TriState aState)106 static bool StateToAttr( TriState aState )
107 {
108     return ( TRISTATE_TRUE == aState );
109 }
110 
111 namespace
112 {
setPrevFontEscapement(SvxFont & _rFont,sal_uInt8 nProp,sal_uInt8 nEscProp,short nEsc)113     void setPrevFontEscapement(SvxFont& _rFont,sal_uInt8 nProp, sal_uInt8 nEscProp, short nEsc )
114     {
115         _rFont.SetPropr( nProp );
116         _rFont.SetProprRel( nEscProp );
117         _rFont.SetEscapement( nEsc );
118     }
119 }
120 
GetPreviewFont()121 inline SvxFont& SvxCharBasePage::GetPreviewFont()
122 {
123     return m_aPreviewWin.GetFont();
124 }
125 
GetPreviewCJKFont()126 inline SvxFont& SvxCharBasePage::GetPreviewCJKFont()
127 {
128     return m_aPreviewWin.GetCJKFont();
129 }
130 
GetPreviewCTLFont()131 inline SvxFont& SvxCharBasePage::GetPreviewCTLFont()
132 {
133     return m_aPreviewWin.GetCTLFont();
134 }
135 
SvxCharBasePage(weld::Container * pPage,weld::DialogController * pController,const OUString & rUIXMLDescription,const OUString & rID,const SfxItemSet & rItemset)136 SvxCharBasePage::SvxCharBasePage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OUString& rID, const SfxItemSet& rItemset)
137     : SfxTabPage(pPage, pController, rUIXMLDescription, rID, &rItemset)
138     , m_bPreviewBackgroundToCharacter( false )
139 {
140 }
141 
~SvxCharBasePage()142 SvxCharBasePage::~SvxCharBasePage()
143 {
144 }
145 
ActivatePage(const SfxItemSet & rSet)146 void SvxCharBasePage::ActivatePage(const SfxItemSet& rSet)
147 {
148     m_aPreviewWin.SetFromItemSet(rSet, m_bPreviewBackgroundToCharacter);
149 }
150 
SetPrevFontWidthScale(const SfxItemSet & rSet)151 void SvxCharBasePage::SetPrevFontWidthScale( const SfxItemSet& rSet )
152 {
153     sal_uInt16 nWhich = GetWhich( SID_ATTR_CHAR_SCALEWIDTH );
154     if (rSet.GetItemState(nWhich)>=SfxItemState::DEFAULT)
155     {
156         const SvxCharScaleWidthItem &rItem = static_cast<const SvxCharScaleWidthItem&>( rSet.Get( nWhich ) );
157         m_aPreviewWin.SetFontWidthScale(rItem.GetValue());
158     }
159 }
160 
SetPrevFontEscapement(sal_uInt8 nProp,sal_uInt8 nEscProp,short nEsc)161 void SvxCharBasePage::SetPrevFontEscapement( sal_uInt8 nProp, sal_uInt8 nEscProp, short nEsc )
162 {
163     setPrevFontEscapement(GetPreviewFont(),nProp,nEscProp,nEsc);
164     setPrevFontEscapement(GetPreviewCJKFont(),nProp,nEscProp,nEsc);
165     setPrevFontEscapement(GetPreviewCTLFont(),nProp,nEscProp,nEsc);
166     m_aPreviewWin.Invalidate();
167 }
168 
169 
170 // SvxCharNamePage_Impl --------------------------------------------------
171 
172 struct SvxCharNamePage_Impl
173 {
174     Idle            m_aUpdateIdle { "cui SvxCharNamePage_Impl m_aUpdateIdle" };
175     OUString        m_aNoStyleText;
176     std::unique_ptr<FontList> m_pFontList;
177     int             m_nExtraEntryPos;
178     bool            m_bInSearchMode;
179 
SvxCharNamePage_ImplSvxCharNamePage_Impl180     SvxCharNamePage_Impl()
181         : m_nExtraEntryPos(std::numeric_limits<int>::max())
182         , m_bInSearchMode(false)
183 
184     {
185         m_aUpdateIdle.SetPriority( TaskPriority::LOWEST );
186     }
187 };
188 
189 // class SvxCharNamePage -------------------------------------------------
190 
SvxCharNamePage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rInSet)191 SvxCharNamePage::SvxCharNamePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInSet)
192     : SvxCharBasePage(pPage, pController, u"cui/ui/charnamepage.ui"_ustr, u"CharNamePage"_ustr, rInSet)
193     , m_pImpl(new SvxCharNamePage_Impl)
194     // Western
195     , m_xWestern(m_xBuilder->weld_notebook(u"nbWestern"_ustr))
196     , m_xWestFontNameFT(m_xBuilder->weld_label(u"lbWestFontname"_ustr))
197     , m_xWestFontStyleFT(m_xBuilder->weld_label(u"lbWestStyle"_ustr))
198     , m_xWestFontStyleLB(new FontStyleBox(m_xBuilder->weld_combo_box(u"cbWestStyle"_ustr)))
199     , m_xWestFontSizeFT(m_xBuilder->weld_label(u"lbWestSize"_ustr))
200     , m_xWestFontSizeLB(new FontSizeBox(m_xBuilder->weld_combo_box(u"cbWestSize"_ustr)))
201     , m_xWestFontLanguageFT(m_xBuilder->weld_label(u"lbWestLanguage"_ustr))
202     , m_xWestFontLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"cbWestLanguage"_ustr)))
203     , m_xWestFontFeaturesButton(m_xBuilder->weld_button(u"btnWestFeatures"_ustr))
204     , m_xWestFontTypeFT(m_xBuilder->weld_label(u"lbWestFontinfo"_ustr))
205     , m_xCJK_CTL(m_xBuilder->weld_notebook(u"nbCJKCTL"_ustr))
206     // CJK
207     , m_xEastFontNameFT(m_xBuilder->weld_label(u"lbCJKFontname"_ustr))
208     , m_xEastFontStyleFT(m_xBuilder->weld_label(u"lbCJKStyle"_ustr))
209     , m_xEastFontStyleLB(new FontStyleBox(m_xBuilder->weld_combo_box(u"cbCJKStyle"_ustr)))
210     , m_xEastFontSizeFT(m_xBuilder->weld_label(u"lbCJKSize"_ustr))
211     , m_xEastFontSizeLB(new FontSizeBox(m_xBuilder->weld_combo_box(u"cbCJKSize"_ustr)))
212     , m_xEastFontLanguageFT(m_xBuilder->weld_label(u"lbCJKLanguage"_ustr))
213     , m_xEastFontLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"cbCJKLanguage"_ustr)))
214     , m_xEastFontFeaturesButton(m_xBuilder->weld_button(u"btnCJKFeatures"_ustr))
215     , m_xEastFontTypeFT(m_xBuilder->weld_label(u"lbCJKFontinfo"_ustr))
216     // CTL
217     , m_xCTLFontNameFT(m_xBuilder->weld_label(u"lbCTLFontname"_ustr))
218     // tree
219     , m_xCTLFontStyleFT(m_xBuilder->weld_label(u"lbCTLStyle"_ustr))
220     , m_xCTLFontStyleLB(new FontStyleBox(m_xBuilder->weld_combo_box(u"cbCTLStyle"_ustr)))
221     , m_xCTLFontSizeFT(m_xBuilder->weld_label(u"lbCTLSize"_ustr))
222     , m_xCTLFontSizeLB(new FontSizeBox(m_xBuilder->weld_combo_box(u"cbCTLSize"_ustr)))
223     , m_xCTLFontLanguageFT(m_xBuilder->weld_label(u"lbCTLLanguage"_ustr))
224     , m_xCTLFontLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box(u"cbCTLLanguage"_ustr)))
225     , m_xCTLFontFeaturesButton(m_xBuilder->weld_button(u"btnCTLFeatures"_ustr))
226     , m_xCTLFontTypeFT(m_xBuilder->weld_label(u"lbCTLFontinfo"_ustr))
227 
228     , m_xVDev(*Application::GetDefaultDevice(), DeviceFormat::WITH_ALPHA)
229 {
230     m_xPreviewWin.reset(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, m_aPreviewWin));
231 #ifdef IOS
232     m_xPreviewWin->hide();
233 #endif
234     m_pImpl->m_aNoStyleText = CuiResId( RID_CUISTR_CHARNAME_NOSTYLE );
235 
236     std::unique_ptr<weld::EntryTreeView> xWestFontName = m_xBuilder->weld_entry_tree_view(u"gdWestern"_ustr, u"edWestFontName"_ustr, u"trWestFontName"_ustr);
237     std::unique_ptr<weld::EntryTreeView> xCJKFontName = m_xBuilder->weld_entry_tree_view(u"gdCJK"_ustr, u"edCJKFontName"_ustr, u"trCJKFontName"_ustr);
238     std::unique_ptr<weld::EntryTreeView> xCTLFontName = m_xBuilder->weld_entry_tree_view(u"gdCTL"_ustr, u"edCTLFontName"_ustr, u"trCTLFontName"_ustr);
239 
240     // 7 lines in the treeview
241     xWestFontName->set_height_request_by_rows(7);
242     xCJKFontName->set_height_request_by_rows(7);
243     xCTLFontName->set_height_request_by_rows(7);
244 
245     m_xWestFontNameLB = std::move(xWestFontName);
246     m_xEastFontNameLB = std::move(xCJKFontName);
247     m_xCTLFontNameLB = std::move(xCTLFontName);
248 
249     bool bShowCJK = SvtCJKOptions::IsCJKFontEnabled();
250     bool bShowCTL = SvtCTLOptions::IsCTLFontEnabled();
251     bool bShowNonWestern = bShowCJK || bShowCTL;
252     if (!bShowNonWestern)
253     {
254         m_xCJK_CTL->hide();
255         m_xWestern->set_show_tabs(false); //hide single tab in case of Western only
256     }
257     else if (!bShowCJK) m_xCJK_CTL->remove_page(u"nbCJK"_ustr);
258     else if (!bShowCTL) m_xCJK_CTL->remove_page(u"nbCTL"_ustr);
259 
260 
261     //In MacOSX the standard dialogs name font-name, font-style as
262     //Family, Typeface
263     //In GNOME the standard dialogs name font-name, font-style as
264     //Family, Style
265     //In Windows the standard dialogs name font-name, font-style as
266     //Font, Style
267 #ifdef _WIN32
268     OUString sFontFamilyString(CuiResId(RID_CUISTR_CHARNAME_FONT));
269 #else
270     OUString sFontFamilyString(CuiResId(RID_CUISTR_CHARNAME_FAMILY));
271 #endif
272     m_xWestFontNameFT->set_label(sFontFamilyString);
273     m_xCTLFontNameFT->set_label(sFontFamilyString);
274     m_xEastFontNameFT->set_label(sFontFamilyString);
275 
276 #ifdef MACOSX
277     OUString sFontStyleString(CuiResId(RID_CUISTR_CHARNAME_TYPEFACE));
278 #else
279     OUString sFontStyleString(CuiResId(RID_CUISTR_CHARNAME_STYLE));
280 #endif
281     m_xWestFontStyleFT->set_label(sFontStyleString);
282     m_xEastFontStyleFT->set_label(sFontStyleString);
283     m_xCTLFontStyleFT->set_label(sFontStyleString);
284 
285     m_xWestFontLanguageLB->SetLanguageList(SvxLanguageListFlags::WESTERN, true, false, true, true,
286                                              LANGUAGE_SYSTEM, css::i18n::ScriptType::LATIN);
287     m_xEastFontLanguageLB->SetLanguageList(SvxLanguageListFlags::CJK, true, false, true, true,
288                                             LANGUAGE_SYSTEM, css::i18n::ScriptType::ASIAN);
289     m_xCTLFontLanguageLB->SetLanguageList(SvxLanguageListFlags::CTL, true, false, true, true,
290                                             LANGUAGE_SYSTEM, css::i18n::ScriptType::COMPLEX);
291     int nVisibleChars = 15;
292     // read-only combobox / HasEntry asserts on set_width_char()
293     m_xWestFontLanguageLB->set_width_chars(nVisibleChars);
294     m_xEastFontLanguageLB->set_width_chars(nVisibleChars);
295     m_xCTLFontLanguageLB->set_width_chars(nVisibleChars);
296 
297     Initialize();
298 }
299 
~SvxCharNamePage()300 SvxCharNamePage::~SvxCharNamePage()
301 {
302     m_pImpl.reset();
303     m_xCTLFontStyleLB.reset();
304     m_xEastFontLanguageLB.reset();
305     m_xWestFontStyleLB.reset();
306     m_xCTLFontSizeLB.reset();
307     m_xEastFontSizeLB.reset();
308     m_xWestFontSizeLB.reset();
309     m_xWestFontLanguageLB.reset();
310     m_xPreviewWin.reset();
311     m_xCTLFontLanguageLB.reset();
312     m_xEastFontLanguageLB.reset();
313 }
314 
Initialize()315 void SvxCharNamePage::Initialize()
316 {
317     // to handle the changes of the other pages
318     SetExchangeSupport();
319 
320     Link<weld::ComboBox&,void> aLink = LINK(this, SvxCharNamePage, FontModifyComboBoxHdl_Impl);
321     m_xWestFontNameLB->connect_changed(aLink);
322     m_xWestFontStyleLB->connect_changed(aLink);
323     m_xWestFontSizeLB->connect_changed(aLink);
324     m_xWestFontLanguageLB->connect_changed(aLink);
325 
326     m_xWestFontFeaturesButton->connect_clicked(LINK(this, SvxCharNamePage, FontFeatureButtonClicked));
327 
328     m_xEastFontNameLB->connect_changed(aLink);
329     m_xEastFontStyleLB->connect_changed(aLink);
330     m_xEastFontSizeLB->connect_changed(aLink);
331     m_xEastFontLanguageLB->connect_changed(aLink);
332     m_xEastFontFeaturesButton->connect_clicked(LINK(this, SvxCharNamePage, FontFeatureButtonClicked));
333 
334     m_xCTLFontNameLB->connect_changed(aLink);
335     m_xCTLFontStyleLB->connect_changed(aLink);
336     m_xCTLFontSizeLB->connect_changed(aLink);
337     m_xCTLFontLanguageLB->connect_changed(aLink);
338     m_xCTLFontFeaturesButton->connect_clicked(LINK(this, SvxCharNamePage, FontFeatureButtonClicked));
339 
340     m_pImpl->m_aUpdateIdle.SetInvokeHandler( LINK( this, SvxCharNamePage, UpdateHdl_Impl ) );
341 }
342 
GetFontList() const343 const FontList* SvxCharNamePage::GetFontList() const
344 {
345     if ( !m_pImpl->m_pFontList )
346     {
347         /* #110771# SvxFontListItem::GetFontList can return NULL */
348         if (SfxObjectShell* pDocSh = SfxObjectShell::Current())
349         {
350             const SfxPoolItem* pItem = pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST );
351             if ( pItem != nullptr )
352             {
353                 DBG_ASSERT(nullptr != static_cast<const SvxFontListItem*>(pItem)->GetFontList(),
354                            "Where is the font list?");
355                 m_pImpl->m_pFontList = static_cast<const SvxFontListItem*>(pItem )->GetFontList()->Clone();
356             }
357         }
358         if(!m_pImpl->m_pFontList)
359         {
360             m_pImpl->m_pFontList.reset(new FontList( Application::GetDefaultDevice() ));
361         }
362     }
363 
364     return m_pImpl->m_pFontList.get();
365 }
366 
367 
368 namespace
369 {
calcFontMetrics(SvxFont & _rFont,SvxCharNamePage const * _pPage,const weld::ComboBox * _pFontNameLB,const FontStyleBox * _pFontStyleLB,const FontSizeBox * _pFontSizeLB,const SvxLanguageBox * _pLanguageLB,const FontList * _pFontList,sal_uInt16 _nFontWhich,sal_uInt16 _nFontHeightWhich)370     FontMetric calcFontMetrics(  SvxFont& _rFont,
371                     SvxCharNamePage const * _pPage,
372                     const weld::ComboBox* _pFontNameLB,
373                     const FontStyleBox* _pFontStyleLB,
374                     const FontSizeBox* _pFontSizeLB,
375                     const SvxLanguageBox* _pLanguageLB,
376                     const FontList* _pFontList,
377                     sal_uInt16 _nFontWhich,
378                     sal_uInt16 _nFontHeightWhich)
379     {
380         Size aSize = _rFont.GetFontSize();
381         aSize.setWidth( 0 );
382         FontMetric aFontMetrics;
383         OUString sFontName(_pFontNameLB->get_active_text());
384         bool bFontAvailable = _pFontList->IsAvailable( sFontName );
385         if (bFontAvailable  || _pFontNameLB->get_value_changed_from_saved())
386             aFontMetrics = _pFontList->Get(sFontName, _pFontStyleLB->get_active_text());
387         else
388         {
389             //get the font from itemset
390             SfxItemState eState = _pPage->GetItemSet().GetItemState( _nFontWhich );
391             if ( eState >= SfxItemState::DEFAULT )
392             {
393                 const SvxFontItem* pFontItem = static_cast<const SvxFontItem*>(&( _pPage->GetItemSet().Get( _nFontWhich ) ));
394                 aFontMetrics.SetFamilyName(pFontItem->GetFamilyName());
395                 aFontMetrics.SetStyleName(pFontItem->GetStyleName());
396                 aFontMetrics.SetFamily(pFontItem->GetFamily());
397                 aFontMetrics.SetPitch(pFontItem->GetPitch());
398                 aFontMetrics.SetCharSet(pFontItem->GetCharSet());
399             }
400         }
401         if ( _pFontSizeLB->IsRelative() )
402         {
403             DBG_ASSERT( _pPage->GetItemSet().GetParent(), "No parent set" );
404             const SvxFontHeightItem& rOldItem = static_cast<const SvxFontHeightItem&>(_pPage->GetItemSet().GetParent()->Get( _nFontHeightWhich ));
405 
406             // old value, scaled
407             tools::Long nHeight;
408             if ( _pFontSizeLB->IsPtRelative() )
409                 nHeight = rOldItem.GetHeight()
410                           + o3tl::convert(_pFontSizeLB->get_value(), o3tl::Length::pt,
411                                           o3tl::Length::twip) / 10;
412             else
413                 nHeight = static_cast<tools::Long>(rOldItem.GetHeight() * _pFontSizeLB->get_value() / 100);
414 
415             // conversion twips for the example-window
416             aSize.setHeight(
417                 ItemToControl( nHeight, _pPage->GetItemSet().GetPool()->GetMetric( _nFontHeightWhich ), FieldUnit::TWIP ) );
418         }
419         else if ( !_pFontSizeLB->get_active_text().isEmpty() )
420             aSize.setHeight(o3tl::convert(_pFontSizeLB->get_value(), o3tl::Length::pt,
421                                           o3tl::Length::twip) / 10);
422         else
423             aSize.setHeight( 200 );   // default 10pt
424         aFontMetrics.SetFontSize( aSize );
425 
426         _rFont.SetLanguage(_pLanguageLB->get_active_id());
427 
428         _rFont.SetFamily( aFontMetrics.GetFamilyTypeMaybeAskConfig() );
429         _rFont.SetFamilyName( aFontMetrics.GetFamilyName() );
430         _rFont.SetStyleName( aFontMetrics.GetStyleName() );
431         _rFont.SetPitch( aFontMetrics.GetPitchMaybeAskConfig() );
432         _rFont.SetCharSet( aFontMetrics.GetCharSet() );
433         _rFont.SetWeight( aFontMetrics.GetWeightMaybeAskConfig() );
434         _rFont.SetItalic( aFontMetrics.GetItalicMaybeAskConfig() );
435         _rFont.SetFontSize( aFontMetrics.GetFontSize() );
436 
437         return aFontMetrics;
438     }
439 }
440 
441 
UpdatePreview_Impl()442 void SvxCharNamePage::UpdatePreview_Impl()
443 {
444     SvxFont& rFont = GetPreviewFont();
445     SvxFont& rCJKFont = GetPreviewCJKFont();
446     SvxFont& rCTLFont = GetPreviewCTLFont();
447     // Font
448     const FontList* pFontList = GetFontList();
449 
450     FontMetric aWestFontMetric = calcFontMetrics(rFont, this, m_xWestFontNameLB.get(),
451         m_xWestFontStyleLB.get(), m_xWestFontSizeLB.get(), m_xWestFontLanguageLB.get(),
452         pFontList, GetWhich(SID_ATTR_CHAR_FONT),
453         GetWhich(SID_ATTR_CHAR_FONTHEIGHT));
454 
455     m_xWestFontTypeFT->set_label(pFontList->GetFontMapText(aWestFontMetric));
456 
457     FontMetric aEastFontMetric = calcFontMetrics(rCJKFont, this, m_xEastFontNameLB.get(),
458         m_xEastFontStyleLB.get(), m_xEastFontSizeLB.get(), m_xEastFontLanguageLB.get(),
459         pFontList, GetWhich(SID_ATTR_CHAR_CJK_FONT),
460         GetWhich(SID_ATTR_CHAR_CJK_FONTHEIGHT));
461 
462     m_xEastFontTypeFT->set_label(pFontList->GetFontMapText(aEastFontMetric));
463 
464     FontMetric aCTLFontMetric = calcFontMetrics(rCTLFont,
465         this, m_xCTLFontNameLB.get(), m_xCTLFontStyleLB.get(), m_xCTLFontSizeLB.get(),
466         m_xCTLFontLanguageLB.get(), pFontList, GetWhich(SID_ATTR_CHAR_CTL_FONT),
467         GetWhich(SID_ATTR_CHAR_CTL_FONTHEIGHT));
468 
469     m_xCTLFontTypeFT->set_label(pFontList->GetFontMapText(aCTLFontMetric));
470 
471     m_aPreviewWin.Invalidate();
472 }
EnableFeatureButton(const weld::Widget & rNameBox)473 void SvxCharNamePage::EnableFeatureButton(const weld::Widget& rNameBox)
474 {
475     OUString sFontName;
476     weld::Button* pButton= nullptr;
477     if (m_xWestFontNameLB.get() == &rNameBox)
478     {
479         sFontName = m_xWestFontNameLB->get_active_text();
480         pButton= m_xWestFontFeaturesButton.get();
481     }
482     else if (m_xEastFontNameLB.get() == &rNameBox)
483     {
484         sFontName = m_xEastFontNameLB->get_active_text();
485         pButton=m_xEastFontFeaturesButton.get();
486     }
487     else if (m_xCTLFontNameLB.get() == &rNameBox)
488     {
489         sFontName = m_xCTLFontNameLB->get_active_text();
490         pButton= m_xCTLFontFeaturesButton.get();
491     }
492     else
493     {
494         SAL_WARN( "cui.tabpages", "invalid font name box" );
495         return;
496     }
497 
498     bool  bEnable = !getFontFeatureList(sFontName, *m_xVDev).empty();
499 
500     pButton->set_sensitive(bEnable);
501 }
502 
FillStyleBox_Impl(const weld::Widget & rNameBox)503 void SvxCharNamePage::FillStyleBox_Impl(const weld::Widget& rNameBox)
504 {
505     const FontList* pFontList = GetFontList();
506     assert(pFontList && "no fontlist");
507 
508     FontStyleBox* pStyleBox = nullptr;
509     OUString sFontName;
510 
511     if (m_xWestFontNameLB.get() == &rNameBox)
512     {
513         pStyleBox = m_xWestFontStyleLB.get();
514         sFontName = m_xWestFontNameLB->get_active_text();
515     }
516     else if (m_xEastFontNameLB.get() == &rNameBox)
517     {
518         pStyleBox = m_xEastFontStyleLB.get();
519         sFontName = m_xEastFontStyleLB->get_active_text();
520     }
521     else if (m_xCTLFontNameLB.get() == &rNameBox)
522     {
523         pStyleBox = m_xCTLFontStyleLB.get();
524         sFontName = m_xCTLFontNameLB->get_active_text();
525     }
526     else
527     {
528         SAL_WARN( "cui.tabpages", "invalid font name box" );
529         return;
530     }
531 
532     pStyleBox->Fill(sFontName, pFontList);
533 
534     if ( !m_pImpl->m_bInSearchMode )
535         return;
536 
537     // additional entries for the search:
538     // "not bold" and "not italic"
539     OUString aEntry = m_pImpl->m_aNoStyleText;
540     const char sS[] = "%1";
541     aEntry = aEntry.replaceFirst( sS, pFontList->GetBoldStr() );
542     m_pImpl->m_nExtraEntryPos = pStyleBox->get_count();
543     pStyleBox->append_text( aEntry );
544     aEntry = m_pImpl->m_aNoStyleText;
545     aEntry = aEntry.replaceFirst( sS, pFontList->GetItalicStr() );
546     pStyleBox->append_text(aEntry);
547 }
548 
FillSizeBox_Impl(const weld::Widget & rNameBox)549 void SvxCharNamePage::FillSizeBox_Impl(const weld::Widget& rNameBox)
550 {
551     const FontList* pFontList = GetFontList();
552     DBG_ASSERT( pFontList, "no fontlist" );
553 
554     FontSizeBox* pSizeBox = nullptr;
555 
556     if (m_xWestFontNameLB.get() == &rNameBox)
557     {
558         pSizeBox = m_xWestFontSizeLB.get();
559     }
560     else if (m_xEastFontNameLB.get() == &rNameBox)
561     {
562         pSizeBox = m_xEastFontSizeLB.get();
563     }
564     else if (m_xCTLFontNameLB.get() == &rNameBox)
565     {
566         pSizeBox = m_xCTLFontSizeLB.get();
567     }
568     else
569     {
570         SAL_WARN( "cui.tabpages", "invalid font name box" );
571         return;
572     }
573 
574     pSizeBox->Fill( pFontList );
575 }
576 
577 namespace
578 {
FillFontNames(weld::ComboBox & rBox,const FontList & rList)579     void FillFontNames(weld::ComboBox& rBox, const FontList& rList)
580     {
581         // insert fonts
582         sal_uInt16 nFontCount = rList.GetFontNameCount();
583         std::vector<weld::ComboBoxEntry> aVector;
584         aVector.reserve(nFontCount);
585         for (sal_uInt16 i = 0; i < nFontCount; ++i)
586         {
587             const FontMetric& rFontMetric = rList.GetFontName(i);
588             aVector.emplace_back(rFontMetric.GetFamilyName());
589         }
590         rBox.insert_vector(aVector, false);
591     }
592 }
593 
Reset_Impl(const SfxItemSet & rSet,LanguageGroup eLangGrp)594 void SvxCharNamePage::Reset_Impl( const SfxItemSet& rSet, LanguageGroup eLangGrp )
595 {
596     weld::ComboBox* pNameBox = nullptr;
597     weld::Label* pStyleLabel = nullptr;
598     FontStyleBox* pStyleBox = nullptr;
599     weld::Label* pSizeLabel = nullptr;
600     FontSizeBox* pSizeBox = nullptr;
601     weld::Label* pLangFT = nullptr;
602     SvxLanguageBox* pLangBox = nullptr;
603     sal_uInt16 nWhich = 0;
604 
605     switch ( eLangGrp )
606     {
607         case Western :
608             pNameBox = m_xWestFontNameLB.get();
609             pStyleLabel = m_xWestFontStyleFT.get();
610             pStyleBox = m_xWestFontStyleLB.get();
611             pSizeLabel = m_xWestFontSizeFT.get();
612             pSizeBox = m_xWestFontSizeLB.get();
613             pLangFT = m_xWestFontLanguageFT.get();
614             pLangBox = m_xWestFontLanguageLB.get();
615             nWhich = GetWhich( SID_ATTR_CHAR_FONT );
616             break;
617 
618         case Asian :
619             pNameBox = m_xEastFontNameLB.get();
620             pStyleLabel = m_xEastFontStyleFT.get();
621             pStyleBox = m_xEastFontStyleLB.get();
622             pSizeLabel = m_xEastFontSizeFT.get();
623             pSizeBox = m_xEastFontSizeLB.get();
624             pLangFT = m_xEastFontLanguageFT.get();
625             pLangBox = m_xEastFontLanguageLB.get();
626             nWhich = GetWhich( SID_ATTR_CHAR_CJK_FONT );
627             break;
628 
629         case Ctl :
630             pNameBox = m_xCTLFontNameLB.get();
631             pStyleLabel = m_xCTLFontStyleFT.get();
632             pStyleBox = m_xCTLFontStyleLB.get();
633             pSizeLabel = m_xCTLFontSizeFT.get();
634             pSizeBox = m_xCTLFontSizeLB.get();
635             pLangFT = m_xCTLFontLanguageFT.get();
636             pLangBox = m_xCTLFontLanguageLB.get();
637             nWhich = GetWhich( SID_ATTR_CHAR_CTL_FONT );
638             break;
639     }
640 
641     const FontList* pFontList = GetFontList();
642     FillFontNames(*pNameBox, *pFontList);
643 
644     const SvxFontItem* pFontItem = nullptr;
645     SfxItemState eState = rSet.GetItemState( nWhich );
646 
647     if ( eState >= SfxItemState::DEFAULT )
648     {
649         pFontItem = static_cast<const SvxFontItem*>(&( rSet.Get( nWhich ) ));
650         const OUString &rName = pFontItem->GetFamilyName();
651         int nIndex = pNameBox->find_text(rName);
652         pNameBox->set_active(nIndex);
653         // tdf#122992 if it didn't exist in the list, set the entry text to it anyway
654         if (nIndex == -1)
655             pNameBox->set_entry_text(rName);
656     }
657     else
658     {
659         pNameBox->set_active_text( OUString() );
660     }
661 
662     FillStyleBox_Impl(*pNameBox);
663 
664     bool bStyle = false;
665     bool bStyleAvailable = true;
666     FontItalic eItalic = ITALIC_NONE;
667     FontWeight eWeight = WEIGHT_NORMAL;
668     switch ( eLangGrp )
669     {
670         case Western : nWhich = GetWhich( SID_ATTR_CHAR_POSTURE ); break;
671         case Asian : nWhich = GetWhich( SID_ATTR_CHAR_CJK_POSTURE ); break;
672         case Ctl : nWhich = GetWhich( SID_ATTR_CHAR_CTL_POSTURE ); break;
673     }
674     eState = rSet.GetItemState( nWhich );
675 
676     if ( eState >= SfxItemState::DEFAULT )
677     {
678         const SvxPostureItem& rItem = static_cast<const SvxPostureItem&>(rSet.Get( nWhich ));
679         eItalic = rItem.GetValue();
680         bStyle = true;
681     }
682     bStyleAvailable = bStyleAvailable && (eState >= SfxItemState::INVALID);
683 
684     switch ( eLangGrp )
685     {
686         case Western : nWhich = GetWhich( SID_ATTR_CHAR_WEIGHT ); break;
687         case Asian : nWhich = GetWhich( SID_ATTR_CHAR_CJK_WEIGHT ); break;
688         case Ctl : nWhich = GetWhich( SID_ATTR_CHAR_CTL_WEIGHT ); break;
689     }
690     eState = rSet.GetItemState( nWhich );
691 
692     if ( eState >= SfxItemState::DEFAULT )
693     {
694         const SvxWeightItem& rItem = static_cast<const SvxWeightItem&>(rSet.Get( nWhich ));
695         eWeight = rItem.GetValue();
696     }
697     else
698         bStyle = false;
699     bStyleAvailable = bStyleAvailable && (eState >= SfxItemState::INVALID);
700 
701     // currently chosen font
702     if ( bStyle && pFontItem )
703     {
704         FontMetric aFontMetric = pFontList->Get( pFontItem->GetFamilyName(), eWeight, eItalic );
705         pStyleBox->set_active_text( pFontList->GetStyleName( aFontMetric ) );
706     }
707     else if ( !m_pImpl->m_bInSearchMode || !bStyle )
708     {
709         pStyleBox->set_active_text( OUString() );
710     }
711     else if ( bStyle )
712     {
713         FontMetric aFontMetric = pFontList->Get( OUString(), eWeight, eItalic );
714         pStyleBox->set_active_text( pFontList->GetStyleName( aFontMetric ) );
715     }
716     if (!bStyleAvailable)
717     {
718         pStyleBox->set_sensitive(false);
719         pStyleLabel->set_sensitive(false);
720     }
721 
722     FillSizeBox_Impl(*pNameBox);
723     switch ( eLangGrp )
724     {
725         case Western : nWhich = GetWhich( SID_ATTR_CHAR_FONTHEIGHT ); break;
726         case Asian : nWhich = GetWhich( SID_ATTR_CHAR_CJK_FONTHEIGHT ); break;
727         case Ctl : nWhich = GetWhich( SID_ATTR_CHAR_CTL_FONTHEIGHT ); break;
728     }
729     eState = rSet.GetItemState( nWhich );
730 
731     if ( pSizeBox->IsRelativeMode() )
732     {
733         MapUnit eUnit = rSet.GetPool()->GetMetric( nWhich );
734         const SvxFontHeightItem& rItem = static_cast<const SvxFontHeightItem&>(rSet.Get( nWhich ));
735 
736         if( rItem.GetProp() != 100 || MapUnit::MapRelative != rItem.GetPropUnit() )
737         {
738             bool bPtRel = MapUnit::MapPoint == rItem.GetPropUnit();
739             pSizeBox->SetPtRelative( bPtRel );
740             pSizeBox->set_value( bPtRel ? static_cast<short>(rItem.GetProp()) * 10 : rItem.GetProp() );
741         }
742         else
743         {
744             pSizeBox->SetRelative(false);
745             pSizeBox->set_value( CalcToPoint( rItem.GetHeight(), eUnit, 10 ) );
746         }
747     }
748     else if ( eState >= SfxItemState::DEFAULT )
749     {
750         MapUnit eUnit = rSet.GetPool()->GetMetric( nWhich );
751         const SvxFontHeightItem& rItem = static_cast<const SvxFontHeightItem&>(rSet.Get( nWhich ));
752         pSizeBox->set_value( CalcToPoint( rItem.GetHeight(), eUnit, 10 ) );
753     }
754     else
755     {
756         pSizeBox->set_active_or_entry_text(OUString());
757         if ( eState <= SfxItemState::DISABLED )
758         {
759             pSizeBox->set_sensitive(false);
760             pSizeLabel->set_sensitive(false);
761         }
762     }
763 
764     switch ( eLangGrp )
765     {
766         case Western : nWhich = GetWhich( SID_ATTR_CHAR_LANGUAGE ); break;
767         case Asian : nWhich = GetWhich( SID_ATTR_CHAR_CJK_LANGUAGE ); break;
768         case Ctl : nWhich = GetWhich( SID_ATTR_CHAR_CTL_LANGUAGE ); break;
769     }
770     pLangBox->set_active(-1);
771     eState = rSet.GetItemState( nWhich );
772 
773     switch ( eState )
774     {
775         case SfxItemState::UNKNOWN:
776             pLangFT->hide();
777             pLangBox->hide();
778             break;
779 
780         case SfxItemState::DISABLED:
781             pLangFT->set_sensitive(false);
782             pLangBox->set_sensitive(false);
783             break;
784 
785         case SfxItemState::DEFAULT:
786         case SfxItemState::SET:
787         {
788             const SvxLanguageItem& rItem = static_cast<const SvxLanguageItem&>(rSet.Get( nWhich ));
789             LanguageType eLangType = rItem.GetValue();
790             DBG_ASSERT( eLangType != LANGUAGE_SYSTEM, "LANGUAGE_SYSTEM not allowed" );
791             if (eLangType != LANGUAGE_DONTKNOW)
792                 pLangBox->set_active_id(eLangType);
793             break;
794         }
795         case SfxItemState::INVALID:
796             break;
797     }
798 
799     OUString sMapText(pFontList->GetFontMapText(
800         pFontList->Get(pNameBox->get_active_text(), pStyleBox->get_active_text())));
801 
802     switch (eLangGrp)
803     {
804         case Western:
805             m_xWestFontTypeFT->set_label(sMapText);
806             break;
807         case Asian:
808             m_xEastFontTypeFT->set_label(sMapText);
809             break;
810         case Ctl:
811             m_xCTLFontTypeFT->set_label(sMapText);
812             break;
813     }
814 
815     EnableFeatureButton(*pNameBox);
816 
817     // save these settings
818     pNameBox->save_value();
819     pStyleBox->save_value();
820     pSizeBox->save_value();
821     pLangBox->save_active_id();
822 }
823 
FillItemSet_Impl(SfxItemSet & rSet,LanguageGroup eLangGrp)824 bool SvxCharNamePage::FillItemSet_Impl( SfxItemSet& rSet, LanguageGroup eLangGrp )
825 {
826     bool bModified = false;
827 
828     weld::ComboBox* pNameBox = nullptr;
829     FontStyleBox* pStyleBox = nullptr;
830     FontSizeBox* pSizeBox = nullptr;
831     SvxLanguageBox* pLangBox = nullptr;
832     sal_uInt16 nWhich = 0;
833     sal_uInt16 nSlot = 0;
834 
835     switch ( eLangGrp )
836     {
837         case Western :
838             pNameBox = m_xWestFontNameLB.get();
839             pStyleBox = m_xWestFontStyleLB.get();
840             pSizeBox = m_xWestFontSizeLB.get();
841             pLangBox = m_xWestFontLanguageLB.get();
842             nSlot = SID_ATTR_CHAR_FONT;
843             break;
844 
845         case Asian :
846             pNameBox = m_xEastFontNameLB.get();
847             pStyleBox = m_xEastFontStyleLB.get();
848             pSizeBox = m_xEastFontSizeLB.get();
849             pLangBox = m_xEastFontLanguageLB.get();
850             nSlot = SID_ATTR_CHAR_CJK_FONT;
851             break;
852 
853         case Ctl :
854             pNameBox = m_xCTLFontNameLB.get();
855             pStyleBox = m_xCTLFontStyleLB.get();
856             pSizeBox = m_xCTLFontSizeLB.get();
857             pLangBox = m_xCTLFontLanguageLB.get();
858             nSlot = SID_ATTR_CHAR_CTL_FONT;
859             break;
860     }
861 
862     nWhich = GetWhich( nSlot );
863     const SfxPoolItem* pItem = nullptr;
864     const SfxItemSet& rOldSet = GetItemSet();
865     const SfxPoolItem* pOld = nullptr;
866 
867     const SfxItemSet* pExampleSet = GetDialogExampleSet();
868 
869     bool bChanged = true;
870     const OUString aFontName  = pNameBox->get_active_text();
871     const FontList* pFontList = GetFontList();
872     OUString aStyleBoxText = pStyleBox->get_active_text();
873     int nEntryPos = pStyleBox->find_text(aStyleBoxText);
874     if (nEntryPos >= m_pImpl->m_nExtraEntryPos)
875         aStyleBoxText.clear();
876     FontMetric aInfo( pFontList->Get( aFontName, aStyleBoxText ) );
877     SvxFontItem aFontItem( aInfo.GetFamilyTypeMaybeAskConfig(), aInfo.GetFamilyName(), aInfo.GetStyleName(),
878                            aInfo.GetPitchMaybeAskConfig(), aInfo.GetCharSet(), nWhich );
879     pOld = GetOldItem( rSet, nSlot );
880 
881     if ( pOld )
882     {
883         const SvxFontItem& rItem = *static_cast<const SvxFontItem*>(pOld);
884 
885         if ( rItem.GetFamilyName() == aFontItem.GetFamilyName() )
886             bChanged = false;
887     }
888 
889     if ( !bChanged )
890         bChanged = pNameBox->get_saved_value().isEmpty();
891 
892     if ( !bChanged && pExampleSet &&
893          pExampleSet->GetItemState( nWhich, false, &pItem ) == SfxItemState::SET &&
894          static_cast<const SvxFontItem*>(pItem)->GetFamilyName() != aFontItem.GetFamilyName() )
895         bChanged = true;
896 
897     if ( bChanged && !aFontName.isEmpty() )
898     {
899         rSet.Put( aFontItem );
900         bModified = true;
901     }
902     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
903         rSet.ClearItem( nWhich );
904 
905 
906     bChanged = true;
907     switch ( eLangGrp )
908     {
909         case Western : nSlot = SID_ATTR_CHAR_WEIGHT; break;
910         case Asian : nSlot = SID_ATTR_CHAR_CJK_WEIGHT; break;
911         case Ctl : nSlot = SID_ATTR_CHAR_CTL_WEIGHT; break;
912     }
913     nWhich = GetWhich( nSlot );
914     FontWeight eWeight = aInfo.GetWeightMaybeAskConfig();
915     if ( nEntryPos >= m_pImpl->m_nExtraEntryPos )
916         eWeight = WEIGHT_NORMAL;
917     SvxWeightItem aWeightItem( eWeight, nWhich );
918     pOld = GetOldItem( rSet, nSlot );
919 
920     if ( pOld )
921     {
922         const SvxWeightItem& rItem = *static_cast<const SvxWeightItem*>(pOld);
923 
924         if ( rItem.GetValue() == aWeightItem.GetValue() )
925             bChanged = false;
926     }
927 
928     if ( !bChanged )
929     {
930         bChanged = pStyleBox->get_saved_value().isEmpty();
931 
932         if ( m_pImpl->m_bInSearchMode && bChanged &&
933              aInfo.GetWeightMaybeAskConfig() == WEIGHT_NORMAL && aInfo.GetItalicMaybeAskConfig() != ITALIC_NONE )
934             bChanged = false;
935     }
936 
937     if ( !bChanged && pExampleSet &&
938          pExampleSet->GetItemState( nWhich, false, &pItem ) == SfxItemState::SET &&
939          static_cast<const SvxWeightItem*>(pItem)->GetValue() != aWeightItem.GetValue() )
940         bChanged = true;
941 
942     if ( nEntryPos >= m_pImpl->m_nExtraEntryPos )
943         bChanged = ( nEntryPos == m_pImpl->m_nExtraEntryPos );
944 
945     OUString aText( pStyleBox->get_active_text() ); // Tristate, then text empty
946 
947     if ( bChanged && !aText.isEmpty() )
948     {
949         rSet.Put( aWeightItem );
950         bModified = true;
951     }
952     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
953         rSet.InvalidateItem(nWhich);
954 
955     bChanged = true;
956     switch ( eLangGrp )
957     {
958         case Western : nSlot = SID_ATTR_CHAR_POSTURE; break;
959         case Asian : nSlot = SID_ATTR_CHAR_CJK_POSTURE; break;
960         case Ctl : nSlot = SID_ATTR_CHAR_CTL_POSTURE; break;
961     }
962     nWhich = GetWhich( nSlot );
963     FontItalic eItalic = aInfo.GetItalicMaybeAskConfig();
964     if ( nEntryPos >= m_pImpl->m_nExtraEntryPos )
965         eItalic = ITALIC_NONE;
966     SvxPostureItem aPostureItem( eItalic, nWhich );
967     pOld = GetOldItem( rSet, nSlot );
968 
969     if ( pOld )
970     {
971         const SvxPostureItem& rItem = *static_cast<const SvxPostureItem*>(pOld);
972 
973         if ( rItem.GetValue() == aPostureItem.GetValue() )
974             bChanged = false;
975     }
976 
977     if ( !bChanged )
978     {
979         bChanged = pStyleBox->get_saved_value().isEmpty();
980 
981         if ( m_pImpl->m_bInSearchMode && bChanged &&
982              aInfo.GetItalicMaybeAskConfig() == ITALIC_NONE && aInfo.GetWeightMaybeAskConfig() != WEIGHT_NORMAL )
983             bChanged = false;
984     }
985 
986     if ( !bChanged && pExampleSet &&
987          pExampleSet->GetItemState( nWhich, false, &pItem ) == SfxItemState::SET &&
988          static_cast<const SvxPostureItem*>(pItem)->GetValue() != aPostureItem.GetValue() )
989         bChanged = true;
990 
991     if ( nEntryPos >= m_pImpl->m_nExtraEntryPos )
992         bChanged = ( nEntryPos == ( m_pImpl->m_nExtraEntryPos + 1 ) );
993 
994     if ( bChanged && !aText.isEmpty() )
995     {
996         rSet.Put( aPostureItem );
997         bModified = true;
998     }
999     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
1000         rSet.InvalidateItem(nWhich);
1001 
1002     // FontSize
1003     tools::Long nSize = pSizeBox->get_value();
1004 
1005     if ( pSizeBox->get_active_text().isEmpty() )   // GetValue() returns the min-value
1006         nSize = 0;
1007     tools::Long nSavedSize = pSizeBox->get_saved_value();
1008     const bool bRel = pSizeBox->IsRelative();
1009 
1010     switch ( eLangGrp )
1011     {
1012         case Western : nSlot = SID_ATTR_CHAR_FONTHEIGHT; break;
1013         case Asian : nSlot = SID_ATTR_CHAR_CJK_FONTHEIGHT; break;
1014         case Ctl : nSlot = SID_ATTR_CHAR_CTL_FONTHEIGHT; break;
1015     }
1016     nWhich = GetWhich( nSlot );
1017     const SvxFontHeightItem* pOldHeight = static_cast<const SvxFontHeightItem*>(GetOldItem( rSet, nSlot ));
1018     bChanged = ( nSize != nSavedSize );
1019 
1020     if ( !bChanged && pExampleSet &&
1021          pExampleSet->GetItemState( nWhich, false, &pItem ) == SfxItemState::SET )
1022     {
1023         float fSize = static_cast<float>(nSize) / 10;
1024         tools::Long nVal = CalcToUnit( fSize, rSet.GetPool()->GetMetric( nWhich ) );
1025         if ( static_cast<const SvxFontHeightItem*>(pItem)->GetHeight() != static_cast<sal_uInt32>(nVal) )
1026             bChanged = true;
1027     }
1028 
1029     if ( bChanged || !pOldHeight ||
1030          bRel != ( MapUnit::MapRelative != pOldHeight->GetPropUnit() || 100 != pOldHeight->GetProp() ) )
1031     {
1032         MapUnit eUnit = rSet.GetPool()->GetMetric( nWhich );
1033         if ( pSizeBox->IsRelative() )
1034         {
1035             DBG_ASSERT( GetItemSet().GetParent(), "No parent set" );
1036             const SvxFontHeightItem& rOldItem =
1037                 static_cast<const SvxFontHeightItem&>(GetItemSet().GetParent()->Get( nWhich ));
1038 
1039             SvxFontHeightItem aHeight( 240, 100, nWhich );
1040             if ( pSizeBox->IsPtRelative() )
1041                 aHeight.SetHeight( rOldItem.GetHeight(), static_cast<sal_uInt16>( nSize / 10 ), MapUnit::MapPoint, eUnit );
1042             else
1043                 aHeight.SetHeight( rOldItem.GetHeight(), static_cast<sal_uInt16>(nSize) );
1044             rSet.Put( aHeight );
1045         }
1046         else
1047         {
1048             float fSize = static_cast<float>(nSize) / 10;
1049             rSet.Put( SvxFontHeightItem( CalcToUnit( fSize, eUnit ), 100, nWhich ) );
1050         }
1051         bModified = true;
1052     }
1053     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
1054         rSet.InvalidateItem(nWhich);
1055 
1056     bChanged = true;
1057     switch ( eLangGrp )
1058     {
1059         case Western : nSlot = SID_ATTR_CHAR_LANGUAGE; break;
1060         case Asian : nSlot = SID_ATTR_CHAR_CJK_LANGUAGE; break;
1061         case Ctl : nSlot = SID_ATTR_CHAR_CTL_LANGUAGE; break;
1062     }
1063 
1064     // For language list boxes acting as ComboBox, check for, add and select an
1065     // edited entry.
1066     switch (pLangBox->GetEditedAndValid())
1067     {
1068         case SvxLanguageBox::EditedAndValid::No:
1069             ;   // nothing to do
1070         break;
1071         case SvxLanguageBox::EditedAndValid::Valid:
1072             {
1073                 SvxLanguageBox* ppBoxes[3]
1074                     = {m_xWestFontLanguageLB.get(), m_xEastFontLanguageLB.get(), m_xCTLFontLanguageLB.get()};
1075                 SvxLanguageBox* pBox = pLangBox->SaveEditedAsEntry(ppBoxes);
1076                 if (pBox != pLangBox)
1077                 {
1078                     // Get item from corresponding slot.
1079                     if (pBox == m_xWestFontLanguageLB.get())
1080                         nSlot = SID_ATTR_CHAR_LANGUAGE;
1081                     else if (pBox == m_xEastFontLanguageLB.get())
1082                         nSlot = SID_ATTR_CHAR_CJK_LANGUAGE;
1083                     else if (pBox == m_xCTLFontLanguageLB.get())
1084                         nSlot = SID_ATTR_CHAR_CTL_LANGUAGE;
1085                     pLangBox = pBox;
1086                 }
1087             }
1088         break;
1089         case SvxLanguageBox::EditedAndValid::Invalid:
1090             pLangBox->set_active_id(pLangBox->get_saved_active_id());
1091         break;
1092     }
1093 
1094     nWhich = GetWhich( nSlot );
1095     pOld = GetOldItem( rSet, nSlot );
1096 
1097     int nLangPos = pLangBox->get_active();
1098     LanguageType eLangType = pLangBox->get_active_id();
1099 
1100     if (pOld)
1101     {
1102         const SvxLanguageItem& rItem = *static_cast<const SvxLanguageItem*>(pOld);
1103         if (nLangPos == -1 || eLangType == rItem.GetValue())
1104             bChanged = false;
1105     }
1106 
1107     if (!bChanged)
1108         bChanged = pLangBox->get_active_id_changed_from_saved();
1109 
1110     if (bChanged && nLangPos != -1)
1111     {
1112         rSet.Put(SvxLanguageItem(eLangType, nWhich));
1113         bModified = true;
1114     }
1115     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
1116         rSet.InvalidateItem(nWhich);
1117 
1118     return bModified;
1119 }
1120 
IMPL_LINK_NOARG(SvxCharNamePage,UpdateHdl_Impl,Timer *,void)1121 IMPL_LINK_NOARG(SvxCharNamePage, UpdateHdl_Impl, Timer *, void)
1122 {
1123     UpdatePreview_Impl();
1124 }
1125 
IMPL_LINK(SvxCharNamePage,FontModifyComboBoxHdl_Impl,weld::ComboBox &,rBox,void)1126 IMPL_LINK(SvxCharNamePage, FontModifyComboBoxHdl_Impl, weld::ComboBox&, rBox, void)
1127 {
1128     FontModifyHdl_Impl(rBox);
1129 }
1130 
IMPL_LINK(SvxCharNamePage,FontFeatureButtonClicked,weld::Button &,rButton,void)1131 IMPL_LINK(SvxCharNamePage, FontFeatureButtonClicked, weld::Button&, rButton, void)
1132 {
1133     OUString sFontName;
1134     weld::ComboBox* pNameBox = nullptr;
1135 
1136     if (&rButton == m_xWestFontFeaturesButton.get())
1137     {
1138         pNameBox = m_xWestFontNameLB.get();
1139         sFontName = GetPreviewFont().GetFamilyName();
1140     }
1141     else if (&rButton == m_xEastFontFeaturesButton.get())
1142     {
1143         pNameBox = m_xEastFontNameLB.get();
1144         sFontName = GetPreviewCJKFont().GetFamilyName();
1145     }
1146     else if (&rButton == m_xCTLFontFeaturesButton.get())
1147     {
1148         pNameBox = m_xCTLFontNameLB.get();
1149         sFontName = GetPreviewCTLFont().GetFamilyName();
1150     }
1151 
1152     if (!sFontName.isEmpty() && pNameBox)
1153     {
1154         cui::FontFeaturesDialog aDialog(GetFrameWeld(), sFontName);
1155         if (aDialog.run() == RET_OK)
1156         {
1157             pNameBox->set_entry_text(aDialog.getResultFontName());
1158             UpdatePreview_Impl();
1159         }
1160     }
1161 }
1162 
FontModifyHdl_Impl(const weld::Widget & rNameBox)1163 void SvxCharNamePage::FontModifyHdl_Impl(const weld::Widget& rNameBox)
1164 {
1165     m_pImpl->m_aUpdateIdle.Start();
1166 
1167     if (m_xWestFontNameLB.get() == &rNameBox || m_xEastFontNameLB.get() == &rNameBox || m_xCTLFontNameLB.get() == &rNameBox)
1168     {
1169         FillStyleBox_Impl(rNameBox);
1170         FillSizeBox_Impl(rNameBox);
1171         EnableFeatureButton(rNameBox);
1172     }
1173 }
1174 
ActivatePage(const SfxItemSet & rSet)1175 void SvxCharNamePage::ActivatePage( const SfxItemSet& rSet )
1176 {
1177     SvxCharBasePage::ActivatePage( rSet );
1178 
1179     UpdatePreview_Impl();       // instead of asynchronous calling in ctor
1180 }
1181 
DeactivatePage(SfxItemSet * _pSet)1182 DeactivateRC SvxCharNamePage::DeactivatePage( SfxItemSet* _pSet )
1183 {
1184     if ( _pSet )
1185         FillItemSet( _pSet );
1186     return DeactivateRC::LeavePage;
1187 }
1188 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)1189 std::unique_ptr<SfxTabPage> SvxCharNamePage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet)
1190 {
1191     return std::make_unique<SvxCharNamePage>(pPage, pController, *rSet );
1192 }
1193 
Reset(const SfxItemSet * rSet)1194 void SvxCharNamePage::Reset( const SfxItemSet* rSet )
1195 {
1196     Reset_Impl( *rSet, Western );
1197     Reset_Impl( *rSet, Asian );
1198     Reset_Impl( *rSet, Ctl );
1199 
1200     SetPrevFontWidthScale( *rSet );
1201     UpdatePreview_Impl();
1202 }
1203 
ChangesApplied()1204 void  SvxCharNamePage::ChangesApplied()
1205 {
1206     m_xWestFontNameLB->save_value();
1207     m_xWestFontStyleLB->save_value();
1208     m_xWestFontSizeLB->save_value();
1209     m_xWestFontLanguageLB->save_active_id();
1210     m_xEastFontNameLB->save_value();
1211     m_xEastFontStyleLB->save_value();
1212     m_xEastFontSizeLB->save_value();
1213     m_xEastFontLanguageLB->save_active_id();
1214     m_xCTLFontNameLB->save_value();
1215     m_xCTLFontStyleLB->save_value();
1216     m_xCTLFontSizeLB->save_value();
1217     m_xCTLFontLanguageLB->save_active_id();
1218 }
1219 
FillItemSet(SfxItemSet * rSet)1220 bool SvxCharNamePage::FillItemSet( SfxItemSet* rSet )
1221 {
1222     bool bModified = FillItemSet_Impl( *rSet, Western );
1223     bModified |= FillItemSet_Impl( *rSet, Asian );
1224     bModified |= FillItemSet_Impl( *rSet, Ctl );
1225     return bModified;
1226 }
1227 
SetFontList(const SvxFontListItem & rItem)1228 void SvxCharNamePage::SetFontList( const SvxFontListItem& rItem )
1229 {
1230     m_pImpl->m_pFontList = rItem.GetFontList()->Clone();
1231 }
1232 
1233 namespace
1234 {
enableRelativeMode(SvxCharNamePage const * _pPage,FontSizeBox * _pFontSizeLB,sal_uInt16 _nHeightWhich)1235     void enableRelativeMode( SvxCharNamePage const * _pPage, FontSizeBox* _pFontSizeLB, sal_uInt16 _nHeightWhich )
1236     {
1237         _pFontSizeLB->EnableRelativeMode( 5, 995 ); // min 5%, max 995%, step 5
1238 
1239         const SvxFontHeightItem& rHeightItem =
1240             static_cast<const SvxFontHeightItem&>(_pPage->GetItemSet().GetParent()->Get( _nHeightWhich ));
1241         MapUnit eUnit = _pPage->GetItemSet().GetPool()->GetMetric( _nHeightWhich );
1242         short nCurHeight =
1243             static_cast< short >( CalcToPoint( rHeightItem.GetHeight(), eUnit, 1 ) * 10 );
1244 
1245         // based on the current height:
1246         //      - negative until minimum of 2 pt
1247         //      - positive until maximum of 999 pt
1248         _pFontSizeLB->EnablePtRelativeMode( sal::static_int_cast< short >(-(nCurHeight - 20)), (9999 - nCurHeight) );
1249     }
1250 }
1251 
EnableRelativeMode()1252 void SvxCharNamePage::EnableRelativeMode()
1253 {
1254     DBG_ASSERT( GetItemSet().GetParent(), "RelativeMode, but no ParentSet!" );
1255     enableRelativeMode(this,m_xWestFontSizeLB.get(),GetWhich( SID_ATTR_CHAR_FONTHEIGHT ));
1256     enableRelativeMode(this,m_xEastFontSizeLB.get(),GetWhich( SID_ATTR_CHAR_CJK_FONTHEIGHT ));
1257     enableRelativeMode(this,m_xCTLFontSizeLB.get(),GetWhich( SID_ATTR_CHAR_CTL_FONTHEIGHT ));
1258 }
1259 
EnableSearchMode()1260 void SvxCharNamePage::EnableSearchMode()
1261 {
1262     m_pImpl->m_bInSearchMode = true;
1263 }
1264 
DisableControls(sal_uInt16 nDisable)1265 void SvxCharNamePage::DisableControls( sal_uInt16 nDisable )
1266 {
1267     if ( DISABLE_HIDE_LANGUAGE & nDisable )
1268     {
1269         if ( m_xWestFontLanguageFT ) m_xWestFontLanguageFT->hide();
1270         if ( m_xWestFontLanguageLB ) m_xWestFontLanguageLB->hide();
1271         if ( m_xEastFontLanguageFT ) m_xEastFontLanguageFT->hide();
1272         if ( m_xEastFontLanguageLB ) m_xEastFontLanguageLB->hide();
1273         if ( m_xCTLFontLanguageFT ) m_xCTLFontLanguageFT->hide();
1274         if ( m_xCTLFontLanguageLB ) m_xCTLFontLanguageLB->hide();
1275     }
1276 }
1277 
PageCreated(const SfxAllItemSet & aSet)1278 void SvxCharNamePage::PageCreated(const SfxAllItemSet& aSet)
1279 {
1280     const SvxFontListItem* pFontListItem = aSet.GetItem<SvxFontListItem>(SID_ATTR_CHAR_FONTLIST, false);
1281     const SfxUInt32Item* pFlagItem = aSet.GetItem<SfxUInt32Item>(SID_FLAG_TYPE, false);
1282     const SfxUInt16Item* pDisableItem = aSet.GetItem<SfxUInt16Item>(SID_DISABLE_CTL, false);
1283     if (pFontListItem)
1284         SetFontList(*pFontListItem);
1285 
1286     if (pFlagItem)
1287     {
1288         sal_uInt32 nFlags=pFlagItem->GetValue();
1289         if ( ( nFlags & SVX_RELATIVE_MODE ) == SVX_RELATIVE_MODE )
1290             EnableRelativeMode();
1291         if ( ( nFlags & SVX_PREVIEW_CHARACTER ) == SVX_PREVIEW_CHARACTER )
1292             // the writer uses SID_ATTR_BRUSH as font background
1293             m_bPreviewBackgroundToCharacter = true;
1294     }
1295     if (pDisableItem)
1296         DisableControls(pDisableItem->GetValue());
1297 }
1298 // class SvxCharEffectsPage ----------------------------------------------
1299 
SvxCharEffectsPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rInSet)1300 SvxCharEffectsPage::SvxCharEffectsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInSet)
1301     : SvxCharBasePage(pPage, pController, u"cui/ui/effectspage.ui"_ustr, u"EffectsPage"_ustr, rInSet)
1302     , m_bOrigFontColor(false)
1303     , m_bNewFontColor(false)
1304     , m_bEnableNoneFontColor(false)
1305     , m_xFontColorFT(m_xBuilder->weld_label(u"fontcolorft"_ustr))
1306     , m_xFontColorLB(new ColorListBox(m_xBuilder->weld_menu_button(u"fontcolorlb"_ustr),
1307         [this]{ return GetDialogController()->getDialog(); }))
1308     , m_xFontTransparencyFT(m_xBuilder->weld_label(u"fonttransparencyft"_ustr))
1309     , m_xFontTransparencyMtr(
1310           m_xBuilder->weld_metric_spin_button(u"fonttransparencymtr"_ustr, FieldUnit::PERCENT))
1311     , m_xEffectsFT(m_xBuilder->weld_label(u"effectsft"_ustr))
1312     , m_xEffectsLB(m_xBuilder->weld_combo_box(u"effectslb"_ustr))
1313     , m_xReliefFT(m_xBuilder->weld_label(u"reliefft"_ustr))
1314     , m_xReliefLB(m_xBuilder->weld_combo_box(u"relieflb"_ustr))
1315     , m_xOutlineBtn(m_xBuilder->weld_check_button(u"outlinecb"_ustr))
1316     , m_xShadowBtn(m_xBuilder->weld_check_button(u"shadowcb"_ustr))
1317     , m_xHiddenBtn(m_xBuilder->weld_check_button(u"hiddencb"_ustr))
1318     , m_xOverlineLB(m_xBuilder->weld_combo_box(u"overlinelb"_ustr))
1319     , m_xOverlineColorFT(m_xBuilder->weld_label(u"overlinecolorft"_ustr))
1320     , m_xOverlineColorLB(new ColorListBox(m_xBuilder->weld_menu_button(u"overlinecolorlb"_ustr),
__anonb1fa9ad10602null1321         [this]{ return GetDialogController()->getDialog(); }))
1322     , m_xStrikeoutLB(m_xBuilder->weld_combo_box(u"strikeoutlb"_ustr))
1323     , m_xUnderlineLB(m_xBuilder->weld_combo_box(u"underlinelb"_ustr))
1324     , m_xUnderlineColorFT(m_xBuilder->weld_label(u"underlinecolorft"_ustr))
1325     , m_xUnderlineColorLB(new ColorListBox(m_xBuilder->weld_menu_button(u"underlinecolorlb"_ustr),
__anonb1fa9ad10702null1326         [this]{ return GetDialogController()->getDialog(); }))
1327     , m_xIndividualWordsBtn(m_xBuilder->weld_check_button(u"individualwordscb"_ustr))
1328     , m_xEmphasisFT(m_xBuilder->weld_label(u"emphasisft"_ustr))
1329     , m_xEmphasisLB(m_xBuilder->weld_combo_box(u"emphasislb"_ustr))
1330     , m_xPositionFT(m_xBuilder->weld_label(u"positionft"_ustr))
1331     , m_xPositionLB(m_xBuilder->weld_combo_box(u"positionlb"_ustr))
1332     , m_xA11yWarningFT(m_xBuilder->weld_label(u"a11ywarning"_ustr))
1333 {
1334     m_xPreviewWin.reset(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, m_aPreviewWin));
1335 #ifdef IOS
1336     m_xPreviewWin->hide();
1337 #endif
1338     m_xFontColorLB->SetSlotId(SID_ATTR_CHAR_COLOR);
1339     m_xOverlineColorLB->SetSlotId(SID_ATTR_CHAR_COLOR);
1340     m_xUnderlineColorLB->SetSlotId(SID_ATTR_CHAR_COLOR);
1341     Initialize();
1342 }
1343 
EnableNoneFontColor()1344 void SvxCharEffectsPage::EnableNoneFontColor()
1345 {
1346     m_xFontColorLB->SetSlotId(SID_ATTR_CHAR_COLOR, true);
1347     m_bEnableNoneFontColor = true;
1348 }
1349 
~SvxCharEffectsPage()1350 SvxCharEffectsPage::~SvxCharEffectsPage()
1351 {
1352     m_xUnderlineColorLB.reset();
1353     m_xOverlineColorLB.reset();
1354     m_xFontTransparencyMtr.reset();
1355     m_xFontColorLB.reset();
1356 }
1357 
Initialize()1358 void SvxCharEffectsPage::Initialize()
1359 {
1360     // to handle the changes of the other pages
1361     SetExchangeSupport();
1362 
1363     // HTML-Mode
1364     const SfxUInt16Item* pHtmlModeItem = GetItemSet().GetItemIfSet( SID_HTML_MODE, false );
1365     if ( !pHtmlModeItem)
1366     {
1367         if (SfxObjectShell* pShell = SfxObjectShell::Current())
1368            pHtmlModeItem = pShell->GetItem( SID_HTML_MODE );
1369     }
1370     if (pHtmlModeItem)
1371     {
1372         sal_uInt16 nHtmlMode = pHtmlModeItem->GetValue();
1373         if ( ( nHtmlMode & HTMLMODE_ON ) == HTMLMODE_ON )
1374         {
1375             //!!! hide some controls please
1376         }
1377     }
1378 
1379     m_xFontColorLB->SetSelectHdl(LINK(this, SvxCharEffectsPage, ColorBoxSelectHdl_Impl));
1380     m_xFontTransparencyMtr->connect_value_changed(
1381         LINK(this, SvxCharEffectsPage, ModifyFontTransparencyHdl_Impl));
1382 
1383     // handler
1384     Link<weld::ComboBox&,void> aLink = LINK( this, SvxCharEffectsPage, SelectListBoxHdl_Impl );
1385     m_xUnderlineLB->connect_changed( aLink );
1386     m_xUnderlineColorLB->SetSelectHdl(LINK(this, SvxCharEffectsPage, ColorBoxSelectHdl_Impl));
1387     m_xOverlineLB->connect_changed( aLink );
1388     m_xOverlineColorLB->SetSelectHdl(LINK(this, SvxCharEffectsPage, ColorBoxSelectHdl_Impl));
1389     m_xStrikeoutLB->connect_changed( aLink );
1390     m_xEmphasisLB->connect_changed( aLink );
1391     m_xPositionLB->connect_changed( aLink );
1392     m_xEffectsLB->connect_changed( aLink );
1393     m_xReliefLB->connect_changed( aLink );
1394 
1395     m_xUnderlineLB->set_active( 0 );
1396     m_xOverlineLB->set_active( 0 );
1397     m_xStrikeoutLB->set_active( 0 );
1398     m_xEmphasisLB->set_active( 0 );
1399     m_xPositionLB->set_active( 0 );
1400     SelectHdl_Impl(nullptr);
1401     SelectHdl_Impl(m_xEmphasisLB.get());
1402 
1403     m_xEffectsLB->set_active( 0 );
1404 
1405     m_xHiddenBtn->connect_toggled(LINK(this, SvxCharEffectsPage, HiddenBtnClickHdl));
1406     m_xIndividualWordsBtn->connect_toggled(LINK(this, SvxCharEffectsPage, CbClickHdl_Impl));
1407     m_xOutlineBtn->connect_toggled(LINK(this, SvxCharEffectsPage, OutlineBtnClickHdl));
1408     m_xShadowBtn->connect_toggled(LINK(this, SvxCharEffectsPage, ShadowBtnClickHdl));
1409 
1410     if ( !SvtCJKOptions::IsAsianTypographyEnabled() )
1411     {
1412         m_xEmphasisFT->hide();
1413         m_xEmphasisLB->hide();
1414         m_xPositionFT->hide();
1415         m_xPositionLB->hide();
1416     }
1417 
1418     m_xA11yWarningFT->set_visible(officecfg::Office::Common::Accessibility::IsAutomaticFontColor::get());
1419 }
1420 
UpdatePreview_Impl()1421 void SvxCharEffectsPage::UpdatePreview_Impl()
1422 {
1423     SvxFont& rFont = GetPreviewFont();
1424     SvxFont& rCJKFont = GetPreviewCJKFont();
1425     SvxFont& rCTLFont = GetPreviewCTLFont();
1426 
1427     const Color& rSelectedColor = m_xFontColorLB->GetSelectEntryColor();
1428     rFont.SetColor(rSelectedColor);
1429     rCJKFont.SetColor(rSelectedColor);
1430     rCTLFont.SetColor(rSelectedColor);
1431     m_aPreviewWin.AutoCorrectFontColor(); // handle color COL_AUTO
1432 
1433     FontLineStyle eUnderline = static_cast<FontLineStyle>(m_xUnderlineLB->get_active_id().toInt32());
1434     FontLineStyle eOverline = static_cast<FontLineStyle>(m_xOverlineLB->get_active_id().toInt32());
1435     FontStrikeout eStrikeout = static_cast<FontStrikeout>(m_xStrikeoutLB->get_active_id().toInt32());
1436     rFont.SetUnderline( eUnderline );
1437     rCJKFont.SetUnderline( eUnderline );
1438     rCTLFont.SetUnderline( eUnderline );
1439     m_aPreviewWin.SetTextLineColor( m_xUnderlineColorLB->GetSelectEntryColor() );
1440     rFont.SetOverline( eOverline );
1441     rCJKFont.SetOverline( eOverline );
1442     rCTLFont.SetOverline( eOverline );
1443     m_aPreviewWin.SetOverlineColor( m_xOverlineColorLB->GetSelectEntryColor() );
1444     rFont.SetStrikeout( eStrikeout );
1445     rCJKFont.SetStrikeout( eStrikeout );
1446     rCTLFont.SetStrikeout( eStrikeout );
1447 
1448     auto nEmphasis = m_xEmphasisLB->get_active();
1449     if (nEmphasis != -1)
1450     {
1451         bool bUnder = (CHRDLG_POSITION_UNDER == m_xPositionLB->get_active_id().toInt32());
1452         FontEmphasisMark eMark = static_cast<FontEmphasisMark>(nEmphasis);
1453         eMark |= bUnder ? FontEmphasisMark::PosBelow : FontEmphasisMark::PosAbove;
1454         rFont.SetEmphasisMark( eMark );
1455         rCJKFont.SetEmphasisMark( eMark );
1456         rCTLFont.SetEmphasisMark( eMark );
1457     }
1458 
1459     auto nRelief = m_xReliefLB->get_active();
1460     if (nRelief != -1)
1461     {
1462         rFont.SetRelief( static_cast<FontRelief>(nRelief) );
1463         rCJKFont.SetRelief( static_cast<FontRelief>(nRelief) );
1464         rCTLFont.SetRelief( static_cast<FontRelief>(nRelief) );
1465     }
1466 
1467     rFont.SetOutline( StateToAttr( m_xOutlineBtn->get_state() ) );
1468     rCJKFont.SetOutline( rFont.IsOutline() );
1469     rCTLFont.SetOutline( rFont.IsOutline() );
1470 
1471     rFont.SetShadow( StateToAttr( m_xShadowBtn->get_state() ) );
1472     rCJKFont.SetShadow( rFont.IsShadow() );
1473     rCTLFont.SetShadow( rFont.IsShadow() );
1474 
1475     auto nCapsPos = m_xEffectsLB->get_active();
1476     if (nCapsPos != -1)
1477     {
1478         SvxCaseMap eCaps = static_cast<SvxCaseMap>(nCapsPos);
1479         rFont.SetCaseMap( eCaps );
1480         rCJKFont.SetCaseMap( eCaps );
1481         // #i78474# small caps do not exist in CTL fonts
1482         rCTLFont.SetCaseMap( eCaps == SvxCaseMap::SmallCaps ? SvxCaseMap::NotMapped : eCaps );
1483     }
1484 
1485     bool bWordLine = StateToAttr( m_xIndividualWordsBtn->get_state() );
1486     rFont.SetWordLineMode( bWordLine );
1487     rCJKFont.SetWordLineMode( bWordLine );
1488     rCTLFont.SetWordLineMode( bWordLine );
1489 
1490     m_aPreviewWin.Invalidate();
1491 }
1492 
SetCaseMap_Impl(SvxCaseMap eCaseMap)1493 void SvxCharEffectsPage::SetCaseMap_Impl( SvxCaseMap eCaseMap )
1494 {
1495     if ( SvxCaseMap::End > eCaseMap )
1496         m_xEffectsLB->set_active(
1497             sal::static_int_cast< sal_Int32 >( eCaseMap ) );
1498     else
1499     {
1500         // not mapped
1501         m_xEffectsLB->set_active(-1);
1502     }
1503 
1504     UpdatePreview_Impl();
1505 }
1506 
ResetColor_Impl(const SfxItemSet & rSet)1507 void SvxCharEffectsPage::ResetColor_Impl( const SfxItemSet& rSet )
1508 {
1509     sal_uInt16 nWhich = GetWhich( SID_ATTR_CHAR_COLOR );
1510     SfxItemState eState = rSet.GetItemState( nWhich );
1511 
1512     m_bOrigFontColor = false;
1513     switch ( eState )
1514     {
1515         case SfxItemState::UNKNOWN:
1516             m_xFontColorFT->hide();
1517             m_xFontColorLB->hide();
1518             break;
1519 
1520         case SfxItemState::DISABLED:
1521             m_xFontColorFT->set_sensitive(false);
1522             m_xFontColorLB->set_sensitive(false);
1523             break;
1524 
1525         case SfxItemState::INVALID:
1526             //Related: tdf#106080 if there is no font color, then allow "none"
1527             //as a color so the listbox can display that state.
1528             EnableNoneFontColor();
1529             m_xFontColorLB->SetNoSelection();
1530             break;
1531 
1532         case SfxItemState::DEFAULT:
1533         case SfxItemState::SET:
1534         {
1535             SvxFont& rFont = GetPreviewFont();
1536             SvxFont& rCJKFont = GetPreviewCJKFont();
1537             SvxFont& rCTLFont = GetPreviewCTLFont();
1538 
1539             const SvxColorItem& rItem = static_cast<const SvxColorItem&>(rSet.Get( nWhich ));
1540             Color aColor = rItem.GetValue();
1541             rFont.SetColor(aColor);
1542             rCJKFont.SetColor(aColor);
1543             rCTLFont.SetColor(aColor);
1544             m_aPreviewWin.AutoCorrectFontColor(); // handle color COL_AUTO
1545 
1546             m_aPreviewWin.Invalidate();
1547 
1548             Color aRGBColor = aColor;
1549             if (aRGBColor.IsTransparent() && aColor != COL_AUTO)
1550             {
1551                 aRGBColor.SetAlpha(255);
1552             }
1553             m_xFontColorLB->SelectEntry(aRGBColor);
1554 
1555             if (m_xFontTransparencyMtr->get_visible() && aColor != COL_AUTO)
1556             {
1557                 double fTransparency = (255 - aColor.GetAlpha()) * 100.0 / 255;
1558                 m_xFontTransparencyMtr->set_value(basegfx::fround(fTransparency),
1559                                                   FieldUnit::PERCENT);
1560             }
1561 
1562             m_aOrigFontColor = aColor;
1563             m_bOrigFontColor = true;
1564             break;
1565         }
1566     }
1567     m_bNewFontColor = false;
1568 }
1569 
FillItemSetColor_Impl(SfxItemSet & rSet)1570 bool SvxCharEffectsPage::FillItemSetColor_Impl( SfxItemSet& rSet )
1571 {
1572     sal_uInt16 nWhich = GetWhich( SID_ATTR_CHAR_COLOR );
1573     const SfxItemSet& rOldSet = GetItemSet();
1574 
1575     NamedColor aSelectedColor;
1576     bool bChanged = m_bNewFontColor;
1577 
1578     if (bChanged)
1579     {
1580         aSelectedColor = m_xFontColorLB->GetSelectedEntryThemedColor();
1581 
1582         if (m_xFontTransparencyMtr->get_value_changed_from_saved())
1583         {
1584             double fTransparency
1585                 = m_xFontTransparencyMtr->get_value(FieldUnit::PERCENT) * 255.0 / 100;
1586             aSelectedColor.m_aColor.SetAlpha(255 - static_cast<sal_uInt8>(basegfx::fround(fTransparency)));
1587         }
1588 
1589         if (m_bOrigFontColor)
1590             bChanged = aSelectedColor.m_aColor != m_aOrigFontColor;
1591         if (m_bEnableNoneFontColor && bChanged && aSelectedColor.m_aColor == COL_NONE_COLOR)
1592             bChanged = false;
1593     }
1594 
1595     if (bChanged)
1596     {
1597         SvxColorItem aItem(aSelectedColor.m_aColor, aSelectedColor.getComplexColor(), nWhich);
1598         rSet.Put(aItem);
1599     }
1600     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
1601         rSet.InvalidateItem(nWhich);
1602 
1603     return bChanged;
1604 }
1605 
IMPL_LINK(SvxCharEffectsPage,SelectListBoxHdl_Impl,weld::ComboBox &,rBox,void)1606 IMPL_LINK( SvxCharEffectsPage, SelectListBoxHdl_Impl, weld::ComboBox&, rBox, void )
1607 {
1608     SelectHdl_Impl(&rBox);
1609 }
1610 
SelectHdl_Impl(const weld::ComboBox * pBox)1611 void SvxCharEffectsPage::SelectHdl_Impl(const weld::ComboBox* pBox)
1612 {
1613     if (m_xEmphasisLB.get() == pBox)
1614     {
1615         auto nEPos = m_xEmphasisLB->get_active();
1616         bool bEnable = nEPos > 0;
1617         m_xPositionFT->set_sensitive( bEnable );
1618         m_xPositionLB->set_sensitive( bEnable );
1619     }
1620     else if (m_xReliefLB.get() == pBox)
1621     {
1622         bool bEnable = ( pBox->get_active() == 0 );
1623         m_xOutlineBtn->set_sensitive( bEnable );
1624         m_xShadowBtn->set_sensitive( bEnable );
1625     }
1626     else if (m_xPositionLB.get() != pBox)
1627     {
1628         auto nUPos = m_xUnderlineLB->get_active();
1629         bool bUEnable = nUPos > 0;
1630         m_xUnderlineColorFT->set_sensitive(bUEnable);
1631         m_xUnderlineColorLB->set_sensitive(bUEnable);
1632 
1633         auto nOPos = m_xOverlineLB->get_active();
1634         bool bOEnable = nOPos > 0;
1635         m_xOverlineColorFT->set_sensitive(bOEnable);
1636         m_xOverlineColorLB->set_sensitive(bOEnable);
1637 
1638         auto nSPos = m_xStrikeoutLB->get_active();
1639         m_xIndividualWordsBtn->set_sensitive( bUEnable || bOEnable || nSPos > 0);
1640     }
1641     UpdatePreview_Impl();
1642 }
1643 
IMPL_LINK_NOARG(SvxCharEffectsPage,CbClickHdl_Impl,weld::Toggleable &,void)1644 IMPL_LINK_NOARG(SvxCharEffectsPage, CbClickHdl_Impl, weld::Toggleable&, void)
1645 {
1646     m_aIndividualWordsState.CheckButtonToggled(*m_xIndividualWordsBtn);
1647     UpdatePreview_Impl();
1648     UpdatePreview_Impl();
1649 }
1650 
IMPL_LINK(SvxCharEffectsPage,ColorBoxSelectHdl_Impl,ColorListBox &,rBox,void)1651 IMPL_LINK(SvxCharEffectsPage, ColorBoxSelectHdl_Impl, ColorListBox&, rBox, void)
1652 {
1653     if (m_xFontColorLB.get() == &rBox)
1654         m_bNewFontColor = true;
1655     UpdatePreview_Impl();
1656 }
1657 
IMPL_LINK_NOARG(SvxCharEffectsPage,ModifyFontTransparencyHdl_Impl,weld::MetricSpinButton &,void)1658 IMPL_LINK_NOARG(SvxCharEffectsPage, ModifyFontTransparencyHdl_Impl, weld::MetricSpinButton&, void)
1659 {
1660     m_bNewFontColor = true;
1661 }
1662 
DeactivatePage(SfxItemSet * _pSet)1663 DeactivateRC SvxCharEffectsPage::DeactivatePage( SfxItemSet* _pSet )
1664 {
1665     if ( _pSet )
1666         FillItemSet( _pSet );
1667     return DeactivateRC::LeavePage;
1668 }
1669 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)1670 std::unique_ptr<SfxTabPage> SvxCharEffectsPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
1671 {
1672     return std::make_unique<SvxCharEffectsPage>( pPage, pController, *rSet );
1673 }
1674 
Reset(const SfxItemSet * rSet)1675 void SvxCharEffectsPage::Reset( const SfxItemSet* rSet )
1676 {
1677     SvxFont& rFont = GetPreviewFont();
1678     SvxFont& rCJKFont = GetPreviewCJKFont();
1679     SvxFont& rCTLFont = GetPreviewCTLFont();
1680 
1681     bool bEnable = false;
1682 
1683     // Underline
1684     sal_uInt16 nWhich = GetWhich( SID_ATTR_CHAR_UNDERLINE );
1685     rFont.SetUnderline( LINESTYLE_NONE );
1686     rCJKFont.SetUnderline( LINESTYLE_NONE );
1687     rCTLFont.SetUnderline( LINESTYLE_NONE );
1688 
1689     m_xUnderlineLB->set_active( 0 );
1690     SfxItemState eState = rSet->GetItemState( nWhich );
1691 
1692     if ( eState >= SfxItemState::INVALID )
1693     {
1694         if ( eState == SfxItemState::INVALID )
1695             m_xUnderlineLB->set_active(-1);
1696         else
1697         {
1698             const SvxUnderlineItem& rItem = static_cast<const SvxUnderlineItem&>(rSet->Get( nWhich ));
1699             FontLineStyle eUnderline = rItem.GetValue();
1700             rFont.SetUnderline( eUnderline );
1701             rCJKFont.SetUnderline( eUnderline );
1702             rCTLFont.SetUnderline( eUnderline );
1703 
1704             if ( eUnderline != LINESTYLE_NONE )
1705             {
1706                 auto nPos = m_xUnderlineLB->find_id(OUString::number(eUnderline));
1707                 if (nPos != -1)
1708                 {
1709                     m_xUnderlineLB->set_active(nPos);
1710                     bEnable = true;
1711                 }
1712                 Color aColor = rItem.GetColor();
1713                 m_xUnderlineColorLB->SelectEntry(aColor);
1714             }
1715             else
1716             {
1717                 m_xUnderlineColorLB->SelectEntry(COL_AUTO);
1718                 m_xUnderlineColorLB->set_sensitive(false);
1719             }
1720         }
1721     }
1722 
1723     // Overline
1724     nWhich = GetWhich( SID_ATTR_CHAR_OVERLINE );
1725     rFont.SetOverline( LINESTYLE_NONE );
1726     rCJKFont.SetOverline( LINESTYLE_NONE );
1727     rCTLFont.SetOverline( LINESTYLE_NONE );
1728 
1729     m_xOverlineLB->set_active( 0 );
1730     eState = rSet->GetItemState( nWhich );
1731 
1732     if ( eState >= SfxItemState::INVALID )
1733     {
1734         if ( eState == SfxItemState::INVALID )
1735             m_xOverlineLB->set_active(-1);
1736         else
1737         {
1738             const SvxOverlineItem& rItem = static_cast<const SvxOverlineItem&>(rSet->Get( nWhich ));
1739             FontLineStyle eOverline = rItem.GetValue();
1740             rFont.SetOverline( eOverline );
1741             rCJKFont.SetOverline( eOverline );
1742             rCTLFont.SetOverline( eOverline );
1743 
1744             if ( eOverline != LINESTYLE_NONE )
1745             {
1746                 auto nPos = m_xOverlineLB->find_id(OUString::number(eOverline));
1747                 if (nPos != -1)
1748                 {
1749                     m_xOverlineLB->set_active(nPos);
1750                     bEnable = true;
1751                 }
1752                 Color aColor = rItem.GetColor();
1753                 m_xOverlineColorLB->SelectEntry(aColor);
1754             }
1755             else
1756             {
1757                 m_xOverlineColorLB->SelectEntry(COL_AUTO);
1758                 m_xOverlineColorLB->set_sensitive(false);
1759             }
1760         }
1761     }
1762 
1763     //  Strikeout
1764     nWhich = GetWhich( SID_ATTR_CHAR_STRIKEOUT );
1765     rFont.SetStrikeout( STRIKEOUT_NONE );
1766     rCJKFont.SetStrikeout( STRIKEOUT_NONE );
1767     rCTLFont.SetStrikeout( STRIKEOUT_NONE );
1768 
1769     m_xStrikeoutLB->set_active( 0 );
1770     eState = rSet->GetItemState( nWhich );
1771 
1772     if ( eState >= SfxItemState::INVALID )
1773     {
1774         if ( eState == SfxItemState::INVALID )
1775             m_xStrikeoutLB->set_active(-1);
1776         else
1777         {
1778             const SvxCrossedOutItem& rItem = static_cast<const SvxCrossedOutItem&>(rSet->Get( nWhich ));
1779             FontStrikeout eStrikeout = rItem.GetValue();
1780             rFont.SetStrikeout( eStrikeout );
1781             rCJKFont.SetStrikeout( eStrikeout );
1782             rCTLFont.SetStrikeout( eStrikeout );
1783 
1784             if ( eStrikeout != STRIKEOUT_NONE )
1785             {
1786                 auto nPos = m_xStrikeoutLB->find_id(OUString::number(eStrikeout));
1787                 if (nPos != -1)
1788                 {
1789                     m_xStrikeoutLB->set_active(nPos);
1790                     bEnable = true;
1791                 }
1792             }
1793         }
1794     }
1795 
1796     // WordLineMode
1797     nWhich = GetWhich( SID_ATTR_CHAR_WORDLINEMODE );
1798     eState = rSet->GetItemState( nWhich );
1799 
1800     switch ( eState )
1801     {
1802         case SfxItemState::UNKNOWN:
1803             m_aIndividualWordsState.bTriStateEnabled = false;
1804             m_xIndividualWordsBtn->hide();
1805             break;
1806 
1807         case SfxItemState::DISABLED:
1808             m_aIndividualWordsState.bTriStateEnabled = false;
1809             m_xIndividualWordsBtn->set_sensitive(false);
1810             break;
1811 
1812         case SfxItemState::INVALID:
1813             m_aIndividualWordsState.bTriStateEnabled = true;
1814             m_xIndividualWordsBtn->set_state( TRISTATE_INDET );
1815             break;
1816 
1817         case SfxItemState::DEFAULT:
1818         case SfxItemState::SET:
1819         {
1820             const SvxWordLineModeItem& rItem = static_cast<const SvxWordLineModeItem&>(rSet->Get( nWhich ));
1821             rFont.SetWordLineMode( rItem.GetValue() );
1822             rCJKFont.SetWordLineMode( rItem.GetValue() );
1823             rCTLFont.SetWordLineMode( rItem.GetValue() );
1824 
1825             m_aIndividualWordsState.bTriStateEnabled = false;
1826             m_xIndividualWordsBtn->set_active(rItem.GetValue());
1827             m_xIndividualWordsBtn->set_sensitive(bEnable);
1828             break;
1829         }
1830     }
1831 
1832     // Emphasis
1833     nWhich = GetWhich( SID_ATTR_CHAR_EMPHASISMARK );
1834     eState = rSet->GetItemState( nWhich );
1835 
1836     if ( eState >= SfxItemState::DEFAULT )
1837     {
1838         const SvxEmphasisMarkItem& rItem = static_cast<const SvxEmphasisMarkItem&>(rSet->Get( nWhich ));
1839         FontEmphasisMark eMark = rItem.GetEmphasisMark();
1840         rFont.SetEmphasisMark( eMark );
1841         rCJKFont.SetEmphasisMark( eMark );
1842         rCTLFont.SetEmphasisMark( eMark );
1843 
1844         m_xEmphasisLB->set_active( static_cast<sal_Int32>(FontEmphasisMark( eMark & FontEmphasisMark::Style )) );
1845         eMark &= ~FontEmphasisMark::Style;
1846         int nEntryData = ( eMark == FontEmphasisMark::PosAbove )
1847             ? CHRDLG_POSITION_OVER
1848             : ( eMark == FontEmphasisMark::PosBelow ) ? CHRDLG_POSITION_UNDER : 0;
1849 
1850         auto nPos = m_xPositionLB->find_id(OUString::number(nEntryData));
1851         if (nPos != -1)
1852             m_xPositionLB->set_active(nPos);
1853     }
1854     else if ( eState == SfxItemState::INVALID )
1855         m_xEmphasisLB->set_active(-1);
1856     else if ( eState == SfxItemState::UNKNOWN )
1857     {
1858         m_xEmphasisFT->hide();
1859         m_xEmphasisLB->hide();
1860     }
1861     else // SfxItemState::DISABLED
1862     {
1863         m_xEmphasisFT->set_sensitive(false);
1864         m_xEmphasisLB->set_sensitive(false);
1865     }
1866 
1867     // the select handler for the underline/overline/strikeout list boxes
1868     SelectHdl_Impl(m_xUnderlineLB.get());
1869 
1870     // the select handler for the emphasis listbox
1871     SelectHdl_Impl(m_xEmphasisLB.get());
1872 
1873     // Effects
1874     SvxCaseMap eCaseMap = SvxCaseMap::End;
1875     nWhich = GetWhich( SID_ATTR_CHAR_CASEMAP );
1876     eState = rSet->GetItemState( nWhich );
1877     switch ( eState )
1878     {
1879         case SfxItemState::UNKNOWN:
1880             m_xEffectsFT->hide();
1881             m_xEffectsLB->hide();
1882             break;
1883 
1884         case SfxItemState::DISABLED:
1885             m_xEffectsFT->set_sensitive(false);
1886             m_xEffectsLB->set_sensitive(false);
1887             break;
1888 
1889         case SfxItemState::INVALID:
1890             m_xEffectsLB->set_active(-1);
1891             break;
1892 
1893         case SfxItemState::DEFAULT:
1894         case SfxItemState::SET:
1895         {
1896             const SvxCaseMapItem& rItem = static_cast<const SvxCaseMapItem&>(rSet->Get( nWhich ));
1897             eCaseMap = rItem.GetValue();
1898             break;
1899         }
1900     }
1901     SetCaseMap_Impl( eCaseMap );
1902 
1903     //Relief
1904     nWhich = GetWhich(SID_ATTR_CHAR_RELIEF);
1905     eState = rSet->GetItemState( nWhich );
1906     switch ( eState )
1907     {
1908         case SfxItemState::UNKNOWN:
1909             m_xReliefFT->hide();
1910             m_xReliefLB->hide();
1911             break;
1912 
1913         case SfxItemState::DISABLED:
1914             m_xReliefFT->set_sensitive(false);
1915             m_xReliefLB->set_sensitive(false);
1916             break;
1917 
1918         case SfxItemState::INVALID:
1919             m_xReliefLB->set_active(-1);
1920             break;
1921 
1922         case SfxItemState::DEFAULT:
1923         case SfxItemState::SET:
1924         {
1925             const SvxCharReliefItem& rItem = static_cast<const SvxCharReliefItem&>(rSet->Get( nWhich ));
1926             m_xReliefLB->set_active(static_cast<sal_Int32>(rItem.GetValue()));
1927             SelectHdl_Impl(m_xReliefLB.get());
1928             break;
1929         }
1930     }
1931 
1932     // Outline
1933     nWhich = GetWhich( SID_ATTR_CHAR_CONTOUR );
1934     eState = rSet->GetItemState( nWhich );
1935     switch ( eState )
1936     {
1937         case SfxItemState::UNKNOWN:
1938             m_aOutlineState.bTriStateEnabled = false;
1939             m_xOutlineBtn->hide();
1940             break;
1941 
1942         case SfxItemState::DISABLED:
1943             m_aOutlineState.bTriStateEnabled = false;
1944             m_xOutlineBtn->set_sensitive(false);
1945             break;
1946 
1947         case SfxItemState::INVALID:
1948             m_aOutlineState.bTriStateEnabled = true;
1949             m_xOutlineBtn->set_state(TRISTATE_INDET);
1950             break;
1951 
1952         case SfxItemState::DEFAULT:
1953         case SfxItemState::SET:
1954         {
1955             const SvxContourItem& rItem = static_cast<const SvxContourItem&>(rSet->Get( nWhich ));
1956             m_aOutlineState.bTriStateEnabled = false;
1957             m_xOutlineBtn->set_state(static_cast<TriState>(rItem.GetValue()));
1958             break;
1959         }
1960     }
1961 
1962     // Shadow
1963     nWhich = GetWhich( SID_ATTR_CHAR_SHADOWED );
1964     eState = rSet->GetItemState( nWhich );
1965 
1966     switch ( eState )
1967     {
1968         case SfxItemState::UNKNOWN:
1969             m_aShadowState.bTriStateEnabled = false;
1970             m_xShadowBtn->hide();
1971             break;
1972 
1973         case SfxItemState::DISABLED:
1974             m_aShadowState.bTriStateEnabled = false;
1975             m_xShadowBtn->set_sensitive(false);
1976             break;
1977 
1978         case SfxItemState::INVALID:
1979             m_aShadowState.bTriStateEnabled = true;
1980             m_xShadowBtn->set_state( TRISTATE_INDET );
1981             break;
1982 
1983         case SfxItemState::DEFAULT:
1984         case SfxItemState::SET:
1985         {
1986             const SvxShadowedItem& rItem = static_cast<const SvxShadowedItem&>(rSet->Get( nWhich ));
1987             m_aShadowState.bTriStateEnabled = false;
1988             m_xShadowBtn->set_state( static_cast<TriState>(rItem.GetValue()) );
1989             break;
1990         }
1991     }
1992 
1993     // Hidden
1994     nWhich = GetWhich( SID_ATTR_CHAR_HIDDEN );
1995     eState = rSet->GetItemState( nWhich );
1996 
1997     switch ( eState )
1998     {
1999         case SfxItemState::UNKNOWN:
2000             m_aHiddenState.bTriStateEnabled = false;
2001             m_xHiddenBtn->hide();
2002             break;
2003 
2004         case SfxItemState::DISABLED:
2005             m_aHiddenState.bTriStateEnabled = false;
2006             m_xHiddenBtn->set_sensitive(false);
2007             break;
2008 
2009         case SfxItemState::INVALID:
2010             m_aHiddenState.bTriStateEnabled = true;
2011             m_xHiddenBtn->set_state(TRISTATE_INDET);
2012             break;
2013 
2014         case SfxItemState::DEFAULT:
2015         case SfxItemState::SET:
2016         {
2017             const SvxCharHiddenItem& rItem = static_cast<const SvxCharHiddenItem&>(rSet->Get( nWhich ));
2018             m_aHiddenState.bTriStateEnabled = false;
2019             m_xHiddenBtn->set_state(static_cast<TriState>(rItem.GetValue()));
2020             break;
2021         }
2022     }
2023 
2024     SetPrevFontWidthScale( *rSet );
2025     ResetColor_Impl( *rSet );
2026 
2027     // preview update
2028     m_aPreviewWin.Invalidate();
2029 
2030     // save this settings
2031     ChangesApplied();
2032 }
2033 
IMPL_LINK_NOARG(SvxCharEffectsPage,HiddenBtnClickHdl,weld::Toggleable &,void)2034 IMPL_LINK_NOARG(SvxCharEffectsPage, HiddenBtnClickHdl, weld::Toggleable&, void)
2035 {
2036     m_aHiddenState.CheckButtonToggled(*m_xHiddenBtn);
2037 }
2038 
IMPL_LINK_NOARG(SvxCharEffectsPage,OutlineBtnClickHdl,weld::Toggleable &,void)2039 IMPL_LINK_NOARG(SvxCharEffectsPage, OutlineBtnClickHdl, weld::Toggleable&, void)
2040 {
2041     m_aOutlineState.CheckButtonToggled(*m_xOutlineBtn);
2042     UpdatePreview_Impl();
2043 }
2044 
IMPL_LINK_NOARG(SvxCharEffectsPage,ShadowBtnClickHdl,weld::Toggleable &,void)2045 IMPL_LINK_NOARG(SvxCharEffectsPage, ShadowBtnClickHdl, weld::Toggleable&, void)
2046 {
2047     m_aShadowState.CheckButtonToggled(*m_xShadowBtn);
2048     UpdatePreview_Impl();
2049 }
2050 
ChangesApplied()2051 void SvxCharEffectsPage::ChangesApplied()
2052 {
2053     m_xUnderlineLB->save_value();
2054     m_xOverlineLB->save_value();
2055     m_xStrikeoutLB->save_value();
2056     m_xIndividualWordsBtn->save_state();
2057     m_xEmphasisLB->save_value();
2058     m_xPositionLB->save_value();
2059     m_xEffectsLB->save_value();
2060     m_xReliefLB->save_value();
2061     m_xOutlineBtn->save_state();
2062     m_xShadowBtn->save_state();
2063     m_xHiddenBtn->save_state();
2064     m_xFontTransparencyMtr->save_value();
2065 }
2066 
FillItemSet(SfxItemSet * rSet)2067 bool SvxCharEffectsPage::FillItemSet( SfxItemSet* rSet )
2068 {
2069     const SfxPoolItem* pOld = nullptr;
2070     const SfxItemSet& rOldSet = GetItemSet();
2071     bool bModified = false;
2072     bool bChanged = true;
2073 
2074     // Underline
2075     sal_uInt16 nWhich = GetWhich( SID_ATTR_CHAR_UNDERLINE );
2076     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_UNDERLINE );
2077     auto nPos = m_xUnderlineLB->get_active();
2078     FontLineStyle eUnder = static_cast<FontLineStyle>(m_xUnderlineLB->get_active_id().toInt32());
2079 
2080     if ( pOld )
2081     {
2082         //! if there are different underline styles in the selection the
2083         //! item-state in the 'rOldSet' will be invalid. In this case
2084         //! changing the underline style will be allowed if a style is
2085         //! selected in the listbox.
2086         bool bAllowChange = nPos != -1  &&
2087                          SfxItemState::DEFAULT > rOldSet.GetItemState( nWhich );
2088 
2089         const SvxUnderlineItem& rItem = *static_cast<const SvxUnderlineItem*>(pOld);
2090         if (rItem.GetValue() == eUnder &&
2091              (LINESTYLE_NONE == eUnder || (rItem.GetColor() == m_xUnderlineColorLB->GetSelectEntryColor() &&
2092                                            rItem.getComplexColor() == m_xUnderlineColorLB->GetSelectedEntry().getComplexColor())) &&
2093              !bAllowChange)
2094         {
2095             bChanged = false;
2096         }
2097     }
2098 
2099     if ( bChanged )
2100     {
2101         SvxUnderlineItem aNewItem( eUnder, nWhich );
2102         const NamedColor& rNamedColor = m_xUnderlineColorLB->GetSelectedEntry();
2103         aNewItem.SetColor(rNamedColor.m_aColor);
2104         aNewItem.setComplexColor(rNamedColor.getComplexColor());
2105         rSet->Put(aNewItem);
2106         bModified = true;
2107     }
2108     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2109         rSet->InvalidateItem(nWhich);
2110 
2111     bChanged = true;
2112 
2113     // Overline
2114     nWhich = GetWhich( SID_ATTR_CHAR_OVERLINE );
2115     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_OVERLINE );
2116     nPos = m_xOverlineLB->get_active();
2117     FontLineStyle eOver = static_cast<FontLineStyle>(m_xOverlineLB->get_active_id().toInt32());
2118 
2119     if ( pOld )
2120     {
2121         //! if there are different underline styles in the selection the
2122         //! item-state in the 'rOldSet' will be invalid. In this case
2123         //! changing the underline style will be allowed if a style is
2124         //! selected in the listbox.
2125         bool bAllowChange = nPos != -1 &&
2126                          SfxItemState::DEFAULT > rOldSet.GetItemState( nWhich );
2127 
2128         const SvxOverlineItem& rItem = *static_cast<const SvxOverlineItem*>(pOld);
2129         if (rItem.GetValue() == eOver &&
2130              (LINESTYLE_NONE == eOver || (rItem.GetColor() == m_xOverlineColorLB->GetSelectEntryColor() &&
2131                                            rItem.getComplexColor() == m_xOverlineColorLB->GetSelectedEntry().getComplexColor())) &&
2132              !bAllowChange)
2133         {
2134             bChanged = false;
2135         }
2136     }
2137 
2138     if ( bChanged )
2139     {
2140         SvxOverlineItem aNewItem( eOver, nWhich );
2141         const NamedColor& rNamedColor = m_xOverlineColorLB->GetSelectedEntry();
2142         aNewItem.SetColor(rNamedColor.m_aColor);
2143         aNewItem.setComplexColor(rNamedColor.getComplexColor());
2144         rSet->Put(aNewItem);
2145         bModified = true;
2146     }
2147     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2148         rSet->InvalidateItem(nWhich);
2149 
2150     bChanged = true;
2151 
2152     // Strikeout
2153     nWhich = GetWhich( SID_ATTR_CHAR_STRIKEOUT );
2154     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_STRIKEOUT );
2155     nPos = m_xStrikeoutLB->get_active();
2156     FontStrikeout eStrike = static_cast<FontStrikeout>(m_xStrikeoutLB->get_active_id().toInt32());
2157 
2158     if ( pOld )
2159     {
2160         //! if there are different strikeout styles in the selection the
2161         //! item-state in the 'rOldSet' will be invalid. In this case
2162         //! changing the strikeout style will be allowed if a style is
2163         //! selected in the listbox.
2164         bool bAllowChg = nPos != -1 &&
2165                          SfxItemState::DEFAULT > rOldSet.GetItemState( nWhich );
2166 
2167         const SvxCrossedOutItem& rItem = *static_cast<const SvxCrossedOutItem*>(pOld);
2168         if ( !m_xStrikeoutLB->get_sensitive()
2169             || (rItem.GetValue() == eStrike  && !bAllowChg) )
2170             bChanged = false;
2171     }
2172 
2173     if ( bChanged )
2174     {
2175         rSet->Put( SvxCrossedOutItem( eStrike, nWhich ) );
2176         bModified = true;
2177     }
2178     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2179         rSet->InvalidateItem(nWhich);
2180 
2181     bChanged = true;
2182 
2183     // Individual words
2184     const SfxItemSet* pExampleSet = GetDialogExampleSet();
2185     nWhich = GetWhich( SID_ATTR_CHAR_WORDLINEMODE );
2186     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_WORDLINEMODE );
2187     TriState eState = m_xIndividualWordsBtn->get_state();
2188     const SfxPoolItem* pItem;
2189 
2190     if ( pOld )
2191     {
2192         const SvxWordLineModeItem& rItem = *static_cast<const SvxWordLineModeItem*>(pOld);
2193         if ( rItem.GetValue() == StateToAttr( eState ) && m_xIndividualWordsBtn->get_saved_state() == eState )
2194             bChanged = false;
2195     }
2196 
2197     if ( !bChanged && pExampleSet && pExampleSet->GetItemState( nWhich, false, &pItem ) == SfxItemState::SET &&
2198          !StateToAttr( eState ) && static_cast<const SvxWordLineModeItem*>(pItem)->GetValue() )
2199         bChanged = true;
2200 
2201     if ( bChanged && eState != TRISTATE_INDET )
2202     {
2203         rSet->Put( SvxWordLineModeItem( StateToAttr( eState ), nWhich ) );
2204         bModified = true;
2205     }
2206     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2207         rSet->InvalidateItem(nWhich);
2208 
2209     bChanged = true;
2210 
2211     // Emphasis
2212     nWhich = GetWhich( SID_ATTR_CHAR_EMPHASISMARK );
2213     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_EMPHASISMARK );
2214     int nMarkPos = m_xEmphasisLB->get_active();
2215     OUString sMarkPos = m_xEmphasisLB->get_active_text();
2216     OUString sPosPos = m_xPositionLB->get_active_text();
2217     FontEmphasisMark eMark = static_cast<FontEmphasisMark>(nMarkPos);
2218     if (m_xPositionLB->get_sensitive())
2219     {
2220         eMark |= (CHRDLG_POSITION_UNDER == m_xPositionLB->get_active_id().toInt32())
2221             ? FontEmphasisMark::PosBelow : FontEmphasisMark::PosAbove;
2222     }
2223 
2224     if ( pOld )
2225     {
2226         if( rOldSet.GetItemState( nWhich ) != SfxItemState::INVALID )
2227         {
2228             const SvxEmphasisMarkItem& rItem = *static_cast<const SvxEmphasisMarkItem*>(pOld);
2229             if ( rItem.GetEmphasisMark() == eMark )
2230                 bChanged = false;
2231         }
2232     }
2233 
2234     if (rOldSet.GetItemState( nWhich ) == SfxItemState::INVALID &&
2235          m_xEmphasisLB->get_saved_value() == sMarkPos && m_xPositionLB->get_saved_value() == sPosPos)
2236     {
2237         bChanged = false;
2238     }
2239 
2240     if (bChanged)
2241     {
2242         rSet->Put( SvxEmphasisMarkItem( eMark, TypedWhichId<SvxEmphasisMarkItem>(nWhich) ) );
2243         bModified = true;
2244     }
2245     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2246         rSet->InvalidateItem(nWhich);
2247 
2248     bChanged = true;
2249 
2250     // Effects
2251     nWhich = GetWhich( SID_ATTR_CHAR_CASEMAP );
2252     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_CASEMAP );
2253     SvxCaseMap eCaseMap = SvxCaseMap::NotMapped;
2254     bool bChecked = false;
2255     auto nCapsPos = m_xEffectsLB->get_active();
2256     if (nCapsPos != -1)
2257     {
2258         eCaseMap = static_cast<SvxCaseMap>(nCapsPos);
2259         bChecked = true;
2260     }
2261 
2262     if ( pOld )
2263     {
2264         //! if there are different effect styles in the selection the
2265         //! item-state in the 'rOldSet' will be invalid. In this case
2266         //! changing the effect style will be allowed if a style is
2267         //! selected in the listbox.
2268         bool bAllowChg = nPos != -1 &&
2269                          SfxItemState::DEFAULT > rOldSet.GetItemState( nWhich );
2270 
2271         const SvxCaseMapItem& rItem = *static_cast<const SvxCaseMapItem*>(pOld);
2272         if ( rItem.GetValue() == eCaseMap  &&  !bAllowChg )
2273             bChanged = false;
2274     }
2275 
2276     if ( bChanged && bChecked )
2277     {
2278         rSet->Put( SvxCaseMapItem( eCaseMap, nWhich ) );
2279         bModified = true;
2280     }
2281     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2282         rSet->InvalidateItem(nWhich);
2283 
2284     bChanged = true;
2285 
2286     //Relief
2287     nWhich = GetWhich(SID_ATTR_CHAR_RELIEF);
2288     if (m_xReliefLB->get_value_changed_from_saved())
2289     {
2290         m_xReliefLB->save_value();
2291         SvxCharReliefItem aRelief(static_cast<FontRelief>(m_xReliefLB->get_active()), nWhich);
2292         rSet->Put(aRelief);
2293     }
2294 
2295     // Outline
2296     nWhich = GetWhich( SID_ATTR_CHAR_CONTOUR );
2297     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_CONTOUR );
2298     eState = m_xOutlineBtn->get_state();
2299 
2300     if ( pOld )
2301     {
2302         const SvxContourItem& rItem = *static_cast<const SvxContourItem*>(pOld);
2303         if ( rItem.GetValue() == StateToAttr( eState ) && m_xOutlineBtn->get_saved_state() == eState )
2304             bChanged = false;
2305     }
2306 
2307     if ( !bChanged && pExampleSet && pExampleSet->GetItemState( nWhich, false, &pItem ) == SfxItemState::SET &&
2308          !StateToAttr( eState ) && static_cast<const SvxContourItem*>(pItem)->GetValue() )
2309         bChanged = true;
2310 
2311     if ( bChanged && eState != TRISTATE_INDET )
2312     {
2313         rSet->Put( SvxContourItem( StateToAttr( eState ), nWhich ) );
2314         bModified = true;
2315     }
2316     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2317         rSet->InvalidateItem(nWhich);
2318 
2319     bChanged = true;
2320 
2321     // Shadow
2322     nWhich = GetWhich( SID_ATTR_CHAR_SHADOWED );
2323     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_SHADOWED );
2324     eState = m_xShadowBtn->get_state();
2325 
2326     if ( pOld )
2327     {
2328         const SvxShadowedItem& rItem = *static_cast<const SvxShadowedItem*>(pOld);
2329         if ( rItem.GetValue() == StateToAttr( eState ) && m_xShadowBtn->get_saved_state() == eState )
2330             bChanged = false;
2331     }
2332 
2333     if ( !bChanged && pExampleSet && pExampleSet->GetItemState( nWhich, false, &pItem ) == SfxItemState::SET &&
2334          !StateToAttr( eState ) && static_cast<const SvxShadowedItem*>(pItem)->GetValue() )
2335         bChanged = true;
2336 
2337     if ( bChanged && eState != TRISTATE_INDET )
2338     {
2339         rSet->Put( SvxShadowedItem( StateToAttr( eState ), nWhich ) );
2340         bModified = true;
2341     }
2342     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2343         rSet->InvalidateItem(nWhich);
2344 
2345     bChanged = true;
2346 
2347     // Hidden
2348     nWhich = GetWhich( SID_ATTR_CHAR_HIDDEN );
2349     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_HIDDEN );
2350     eState = m_xHiddenBtn->get_state();
2351     bChanged = true;
2352 
2353     if ( pOld )
2354     {
2355         const SvxCharHiddenItem& rItem = *static_cast<const SvxCharHiddenItem*>(pOld);
2356         if ( rItem.GetValue() == StateToAttr( eState ) && m_xHiddenBtn->get_saved_state() == eState )
2357             bChanged = false;
2358     }
2359 
2360     if ( !bChanged && pExampleSet && pExampleSet->GetItemState( nWhich, false, &pItem ) == SfxItemState::SET &&
2361          !StateToAttr( eState ) && static_cast<const SvxCharHiddenItem*>(pItem)->GetValue() )
2362         bChanged = true;
2363 
2364     if ( bChanged && eState != TRISTATE_INDET )
2365     {
2366         rSet->Put( SvxCharHiddenItem( StateToAttr( eState ), nWhich ) );
2367         bModified = true;
2368     }
2369     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2370         rSet->InvalidateItem(nWhich);
2371 
2372     bModified |= FillItemSetColor_Impl( *rSet );
2373 
2374     return bModified;
2375 }
2376 
DisableControls(sal_uInt16 nDisable)2377 void SvxCharEffectsPage::DisableControls( sal_uInt16 nDisable )
2378 {
2379     if ( ( DISABLE_CASEMAP & nDisable ) == DISABLE_CASEMAP )
2380     {
2381         m_xEffectsFT->set_sensitive(false);
2382         m_xEffectsLB->set_sensitive(false);
2383     }
2384 }
2385 
PageCreated(const SfxAllItemSet & aSet)2386 void SvxCharEffectsPage::PageCreated(const SfxAllItemSet& aSet)
2387 {
2388     const SfxUInt16Item* pDisableCtlItem = aSet.GetItem<SfxUInt16Item>(SID_DISABLE_CTL, false);
2389     const SfxUInt32Item* pFlagItem = aSet.GetItem<SfxUInt32Item>(SID_FLAG_TYPE, false);
2390     if (pDisableCtlItem)
2391         DisableControls(pDisableCtlItem->GetValue());
2392 
2393     sal_uInt32 nFlags = pFlagItem ? pFlagItem->GetValue() : 0;
2394     if ( ( nFlags & SVX_PREVIEW_CHARACTER ) == SVX_PREVIEW_CHARACTER )
2395         // the writer uses SID_ATTR_BRUSH as font background
2396         m_bPreviewBackgroundToCharacter = true;
2397     if ((nFlags & SVX_ENABLE_CHAR_TRANSPARENCY) != SVX_ENABLE_CHAR_TRANSPARENCY)
2398     {
2399         // Only show these in case client code explicitly wants this.
2400         m_xFontTransparencyFT->hide();
2401         m_xFontTransparencyMtr->hide();
2402     }
2403 }
2404 
2405 // class SvxCharPositionPage ---------------------------------------------
2406 
SvxCharPositionPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rInSet)2407 SvxCharPositionPage::SvxCharPositionPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInSet)
2408     : SvxCharBasePage(pPage, pController, u"cui/ui/positionpage.ui"_ustr, u"PositionPage"_ustr, rInSet)
2409     , m_nSuperEsc(short(DFLT_ESC_SUPER))
2410     , m_nSubEsc(short(DFLT_ESC_SUB))
2411     , m_nScaleWidthItemSetVal(100)
2412     , m_nScaleWidthInitialVal(100)
2413     , m_nSuperProp(sal_uInt8(DFLT_ESC_PROP))
2414     , m_nSubProp(sal_uInt8(DFLT_ESC_PROP))
2415     , m_xHighPosBtn(m_xBuilder->weld_radio_button(u"superscript"_ustr))
2416     , m_xNormalPosBtn(m_xBuilder->weld_radio_button(u"normal"_ustr))
2417     , m_xLowPosBtn(m_xBuilder->weld_radio_button(u"subscript"_ustr))
2418     , m_xHighLowFT(m_xBuilder->weld_label(u"raiselower"_ustr))
2419     , m_xHighLowMF(m_xBuilder->weld_metric_spin_button(u"raiselowersb"_ustr, FieldUnit::PERCENT))
2420     , m_xHighLowRB(m_xBuilder->weld_check_button(u"automatic"_ustr))
2421     , m_xFontSizeFT(m_xBuilder->weld_label(u"relativefontsize"_ustr))
2422     , m_xFontSizeMF(m_xBuilder->weld_metric_spin_button(u"fontsizesb"_ustr, FieldUnit::PERCENT))
2423     , m_xRotationContainer(m_xBuilder->weld_widget(u"rotationcontainer"_ustr))
2424     , m_xRotationAndScalingFrame(m_xBuilder->weld_frame(u"rotationandscalingframe"_ustr))
2425     , m_x0degRB(m_xBuilder->weld_radio_button(u"0deg"_ustr))
2426     , m_x90degRB(m_xBuilder->weld_radio_button(u"90deg"_ustr))
2427     , m_x270degRB(m_xBuilder->weld_radio_button(u"270deg"_ustr))
2428     , m_xFitToLineCB(m_xBuilder->weld_check_button(u"fittoline"_ustr))
2429     , m_xScaleWidthMF(m_xBuilder->weld_metric_spin_button(u"scalewidthsb"_ustr, FieldUnit::PERCENT))
2430     , m_xKerningMF(m_xBuilder->weld_metric_spin_button(u"kerningsb"_ustr, FieldUnit::POINT))
2431     , m_xPairKerningBtn(m_xBuilder->weld_check_button(u"pairkerning"_ustr))
2432     , m_xNoHyphenationBtn(m_xBuilder->weld_check_button(u"nohyphenation"_ustr))
2433 {
2434     m_xPreviewWin.reset(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, m_aPreviewWin));
2435 #ifdef IOS
2436     m_xPreviewWin->hide();
2437 #endif
2438     Initialize();
2439 }
2440 
~SvxCharPositionPage()2441 SvxCharPositionPage::~SvxCharPositionPage()
2442 {
2443 }
2444 
2445 
Initialize()2446 void SvxCharPositionPage::Initialize()
2447 {
2448     // to handle the changes of the other pages
2449     SetExchangeSupport();
2450 
2451     GetPreviewFont().SetFontSize( Size( 0, 240 ) );
2452     GetPreviewCJKFont().SetFontSize( Size( 0, 240 ) );
2453     GetPreviewCTLFont().SetFontSize( Size( 0, 240 ) );
2454 
2455     m_xNormalPosBtn->set_active(true);
2456     PositionHdl_Impl(*m_xNormalPosBtn);
2457 
2458     Link<weld::Toggleable&,void> aLink2 = LINK(this, SvxCharPositionPage, PositionHdl_Impl);
2459     m_xHighPosBtn->connect_toggled(aLink2);
2460     m_xNormalPosBtn->connect_toggled(aLink2);
2461     m_xLowPosBtn->connect_toggled(aLink2);
2462 
2463     aLink2 = LINK( this, SvxCharPositionPage, RotationHdl_Impl );
2464     m_x0degRB->connect_toggled(aLink2);
2465     m_x90degRB->connect_toggled(aLink2);
2466     m_x270degRB->connect_toggled(aLink2);
2467 
2468     Link<weld::MetricSpinButton&,void> aLink3 = LINK(this, SvxCharPositionPage, ValueChangedHdl_Impl);
2469     m_xHighLowMF->connect_value_changed(aLink3);
2470     m_xFontSizeMF->connect_value_changed(aLink3);
2471 
2472     m_xHighLowRB->connect_toggled(LINK(this, SvxCharPositionPage, AutoPositionHdl_Impl));
2473     m_xFitToLineCB->connect_toggled(LINK(this, SvxCharPositionPage, FitToLineHdl_Impl));
2474     m_xKerningMF->connect_value_changed(LINK(this, SvxCharPositionPage, KerningModifyHdl_Impl));
2475     m_xScaleWidthMF->connect_value_changed(LINK(this, SvxCharPositionPage, ScaleWidthModifyHdl_Impl));
2476 }
2477 
UpdatePreview_Impl(sal_uInt8 nProp,sal_uInt8 nEscProp,short nEsc)2478 void SvxCharPositionPage::UpdatePreview_Impl( sal_uInt8 nProp, sal_uInt8 nEscProp, short nEsc )
2479 {
2480     SetPrevFontEscapement( nProp, nEscProp, nEsc );
2481 }
2482 
2483 
SetEscapement_Impl(SvxEscapement nEsc)2484 void SvxCharPositionPage::SetEscapement_Impl( SvxEscapement nEsc )
2485 {
2486     SvxEscapementItem aEscItm( nEsc, SID_ATTR_CHAR_ESCAPEMENT );
2487 
2488     if ( SvxEscapement::Superscript == nEsc )
2489     {
2490         aEscItm.SetEsc( m_nSuperEsc );
2491         aEscItm.SetProportionalHeight(m_nSuperProp);
2492     }
2493     else if ( SvxEscapement::Subscript == nEsc )
2494     {
2495         aEscItm.SetEsc( m_nSubEsc );
2496         aEscItm.SetProportionalHeight( m_nSubProp );
2497     }
2498 
2499     short nFac = aEscItm.GetEsc() < 0 ? -1 : 1;
2500 
2501     m_xHighLowMF->set_value(aEscItm.GetEsc() * nFac, FieldUnit::PERCENT);
2502     m_xFontSizeMF->set_value(aEscItm.GetProportionalHeight(), FieldUnit::PERCENT);
2503 
2504     if ( SvxEscapement::Off == nEsc )
2505     {
2506         m_xHighLowFT->set_sensitive(false);
2507         m_xHighLowMF->set_sensitive(false);
2508         m_xFontSizeFT->set_sensitive(false);
2509         m_xFontSizeMF->set_sensitive(false);
2510         m_xHighLowRB->set_sensitive(false);
2511     }
2512     else
2513     {
2514         m_xFontSizeFT->set_sensitive(true);
2515         m_xFontSizeMF->set_sensitive(true);
2516         m_xHighLowRB->set_sensitive(true);
2517 
2518         if (!m_xHighLowRB->get_active())
2519         {
2520             m_xHighLowFT->set_sensitive(true);
2521             m_xHighLowMF->set_sensitive(true);
2522         }
2523         else
2524             AutoPositionHdl_Impl(*m_xHighLowRB);
2525     }
2526 
2527     UpdatePreview_Impl( 100, aEscItm.GetProportionalHeight(), aEscItm.GetEsc() );
2528 }
2529 
2530 
IMPL_LINK_NOARG(SvxCharPositionPage,PositionHdl_Impl,weld::Toggleable &,void)2531 IMPL_LINK_NOARG(SvxCharPositionPage, PositionHdl_Impl, weld::Toggleable&, void)
2532 {
2533     SvxEscapement nEsc = SvxEscapement::Off;   // also when pBtn == NULL
2534 
2535     if (m_xHighPosBtn->get_active())
2536         nEsc = SvxEscapement::Superscript;
2537     else if (m_xLowPosBtn->get_active())
2538         nEsc = SvxEscapement::Subscript;
2539 
2540     SetEscapement_Impl( nEsc );
2541 }
2542 
IMPL_LINK_NOARG(SvxCharPositionPage,RotationHdl_Impl,weld::Toggleable &,void)2543 IMPL_LINK_NOARG(SvxCharPositionPage, RotationHdl_Impl, weld::Toggleable&, void)
2544 {
2545     bool bEnable = false;
2546     if (m_x90degRB->get_active() || m_x270degRB->get_active())
2547         bEnable = true;
2548     else
2549         OSL_ENSURE(m_x0degRB->get_active(), "unexpected button");
2550     m_xFitToLineCB->set_sensitive(bEnable);
2551 }
2552 
FontModifyHdl_Impl()2553 void SvxCharPositionPage::FontModifyHdl_Impl()
2554 {
2555     sal_uInt8 nEscProp = static_cast<sal_uInt8>(m_xFontSizeMF->get_value(FieldUnit::PERCENT));
2556     short nEsc  = static_cast<short>(m_xHighLowMF->get_value(FieldUnit::PERCENT));
2557     nEsc *= m_xLowPosBtn->get_active() ? -1 : 1;
2558     UpdatePreview_Impl( 100, nEscProp, nEsc );
2559 }
2560 
IMPL_LINK(SvxCharPositionPage,AutoPositionHdl_Impl,weld::Toggleable &,rBox,void)2561 IMPL_LINK(SvxCharPositionPage, AutoPositionHdl_Impl, weld::Toggleable&, rBox, void)
2562 {
2563     if (rBox.get_active())
2564     {
2565         m_xHighLowFT->set_sensitive(false);
2566         m_xHighLowMF->set_sensitive(false);
2567     }
2568     else
2569         PositionHdl_Impl(m_xHighPosBtn->get_active() ? *m_xHighPosBtn
2570                                                      : m_xLowPosBtn->get_active() ? *m_xLowPosBtn
2571                                                                                   : *m_xNormalPosBtn);
2572 }
2573 
IMPL_LINK_NOARG(SvxCharPositionPage,FitToLineHdl_Impl,weld::Toggleable &,void)2574 IMPL_LINK_NOARG(SvxCharPositionPage, FitToLineHdl_Impl, weld::Toggleable&, void)
2575 {
2576     sal_uInt16 nVal = m_nScaleWidthInitialVal;
2577     if (m_xFitToLineCB->get_active())
2578         nVal = m_nScaleWidthItemSetVal;
2579     m_xScaleWidthMF->set_value(nVal, FieldUnit::PERCENT);
2580     m_aPreviewWin.SetFontWidthScale( nVal );
2581 }
2582 
IMPL_LINK_NOARG(SvxCharPositionPage,KerningModifyHdl_Impl,weld::MetricSpinButton &,void)2583 IMPL_LINK_NOARG(SvxCharPositionPage, KerningModifyHdl_Impl, weld::MetricSpinButton&, void)
2584 {
2585     tools::Long nVal = static_cast<tools::Long>(m_xKerningMF->get_value(FieldUnit::POINT));
2586     nVal = o3tl::convert(nVal, o3tl::Length::pt, o3tl::Length::twip);
2587 
2588     tools::Long nKern = static_cast<short>(m_xKerningMF->denormalize(nVal));
2589 
2590     SvxFont& rFont = GetPreviewFont();
2591     SvxFont& rCJKFont = GetPreviewCJKFont();
2592     SvxFont& rCTLFont = GetPreviewCTLFont();
2593 
2594     rFont.SetFixKerning( static_cast<short>(nKern) );
2595     rCJKFont.SetFixKerning( static_cast<short>(nKern) );
2596     rCTLFont.SetFixKerning( static_cast<short>(nKern) );
2597     m_aPreviewWin.Invalidate();
2598 }
2599 
IMPL_LINK(SvxCharPositionPage,ValueChangedHdl_Impl,weld::MetricSpinButton &,rField,void)2600 IMPL_LINK(SvxCharPositionPage, ValueChangedHdl_Impl, weld::MetricSpinButton&, rField, void)
2601 {
2602     bool bHigh = m_xHighPosBtn->get_active();
2603     bool bLow = m_xLowPosBtn->get_active();
2604     DBG_ASSERT( bHigh || bLow, "normal position is not valid" );
2605 
2606     if (m_xHighLowMF.get() == &rField)
2607     {
2608         if ( bLow )
2609             m_nSubEsc = static_cast<short>(m_xHighLowMF->get_value(FieldUnit::PERCENT)) * -1;
2610         else
2611             m_nSuperEsc = static_cast<short>(m_xHighLowMF->get_value(FieldUnit::PERCENT));
2612     }
2613     else if (m_xFontSizeMF.get() == &rField)
2614     {
2615         if ( bLow )
2616             m_nSubProp = static_cast<sal_uInt8>(m_xFontSizeMF->get_value(FieldUnit::PERCENT));
2617         else
2618             m_nSuperProp = static_cast<sal_uInt8>(m_xFontSizeMF->get_value(FieldUnit::PERCENT));
2619     }
2620 
2621     FontModifyHdl_Impl();
2622 }
2623 
IMPL_LINK_NOARG(SvxCharPositionPage,ScaleWidthModifyHdl_Impl,weld::MetricSpinButton &,void)2624 IMPL_LINK_NOARG(SvxCharPositionPage, ScaleWidthModifyHdl_Impl, weld::MetricSpinButton&, void)
2625 {
2626     m_aPreviewWin.SetFontWidthScale(sal_uInt16(m_xScaleWidthMF->get_value(FieldUnit::PERCENT)));
2627 }
2628 
DeactivatePage(SfxItemSet * _pSet)2629 DeactivateRC SvxCharPositionPage::DeactivatePage( SfxItemSet* _pSet )
2630 {
2631     if ( _pSet )
2632         FillItemSet( _pSet );
2633     return DeactivateRC::LeavePage;
2634 }
2635 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)2636 std::unique_ptr<SfxTabPage> SvxCharPositionPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet)
2637 {
2638     return std::make_unique<SvxCharPositionPage>(pPage, pController, *rSet);
2639 }
2640 
Reset(const SfxItemSet * rSet)2641 void SvxCharPositionPage::Reset( const SfxItemSet* rSet )
2642 {
2643     OUString sUser = GetUserData();
2644 
2645     if ( !sUser.isEmpty() )
2646     {
2647         sal_Int32 nIdx {0};
2648         m_nSuperEsc = static_cast<short>(o3tl::toInt32(o3tl::getToken(sUser, 0, ';', nIdx )));
2649         m_nSubEsc = static_cast<short>(o3tl::toInt32(o3tl::getToken(sUser, 0, ';', nIdx )));
2650         m_nSuperProp = static_cast<sal_uInt8>(o3tl::toInt32(o3tl::getToken(sUser, 0, ';', nIdx )));
2651         m_nSubProp = static_cast<sal_uInt8>(o3tl::toInt32(o3tl::getToken(sUser, 0, ';', nIdx )));
2652 
2653         m_xHighLowMF->set_max(MAX_ESC_POS, FieldUnit::PERCENT);
2654 
2655         //fdo#75307 validate all the entries and discard all of them if any are
2656         //out of range
2657         bool bValid = true;
2658         if (m_nSuperEsc < m_xHighLowMF->get_min(FieldUnit::PERCENT) || m_nSuperEsc > m_xHighLowMF->get_max(FieldUnit::PERCENT))
2659             bValid = false;
2660         if (m_nSubEsc*-1 < m_xHighLowMF->get_min(FieldUnit::PERCENT) || m_nSubEsc*-1 > m_xHighLowMF->get_max(FieldUnit::PERCENT))
2661             bValid = false;
2662         if (m_nSuperProp < m_xFontSizeMF->get_min(FieldUnit::PERCENT) || m_nSuperProp > m_xFontSizeMF->get_max(FieldUnit::PERCENT))
2663             bValid = false;
2664         if (m_nSubProp < m_xFontSizeMF->get_min(FieldUnit::PERCENT) || m_nSubProp > m_xFontSizeMF->get_max(FieldUnit::PERCENT))
2665             bValid = false;
2666 
2667         if (!bValid)
2668         {
2669             m_nSuperEsc = DFLT_ESC_SUPER;
2670             m_nSubEsc = DFLT_ESC_SUB;
2671             m_nSuperProp = DFLT_ESC_PROP;
2672             m_nSubProp = DFLT_ESC_PROP;
2673         }
2674     }
2675 
2676     short nEsc = 0;
2677     sal_uInt8 nEscProp = 100;
2678 
2679     m_xHighLowFT->set_sensitive(false);
2680     m_xHighLowMF->set_sensitive(false);
2681     m_xFontSizeFT->set_sensitive(false);
2682     m_xFontSizeMF->set_sensitive(false);
2683 
2684     SvxFont& rFont = GetPreviewFont();
2685     SvxFont& rCJKFont = GetPreviewCJKFont();
2686     SvxFont& rCTLFont = GetPreviewCTLFont();
2687     sal_uInt16 nWhich = GetWhich( SID_ATTR_CHAR_ESCAPEMENT );
2688 
2689     if ( rSet->GetItemState( nWhich ) >= SfxItemState::DEFAULT )
2690     {
2691         const SvxEscapementItem& rItem = static_cast<const SvxEscapementItem&>(rSet->Get( nWhich ));
2692         nEsc = rItem.GetEsc();
2693         nEscProp = rItem.GetProportionalHeight();
2694 
2695         if ( nEsc != 0 )
2696         {
2697             m_xHighLowFT->set_sensitive(true);
2698             m_xHighLowMF->set_sensitive(true);
2699             m_xFontSizeFT->set_sensitive(true);
2700             m_xFontSizeMF->set_sensitive(true);
2701 
2702             short nFac;
2703             bool bAutomatic(false);
2704 
2705             if ( nEsc > 0 )
2706             {
2707                 nFac = 1;
2708                 m_xHighPosBtn->set_active(true);
2709                 if ( nEsc == DFLT_ESC_AUTO_SUPER )
2710                 {
2711                     nEsc = .8 * (100 - nEscProp);  //approximation of actual percentage used
2712                     bAutomatic = true;
2713                 }
2714             }
2715             else
2716             {
2717                 nFac = -1;
2718                 m_xLowPosBtn->set_active(true);
2719                 if ( nEsc == DFLT_ESC_AUTO_SUB )
2720                 {
2721                     nEsc = .2 * -(100 - nEscProp);  //approximation of actual percentage used
2722                     bAutomatic = true;
2723                 }
2724             }
2725             if (!m_xHighLowRB->get_sensitive())
2726             {
2727                 m_xHighLowRB->set_sensitive(true);
2728             }
2729             m_xHighLowRB->set_active(bAutomatic);
2730 
2731             if (m_xHighLowRB->get_active())
2732             {
2733                 m_xHighLowFT->set_sensitive(false);
2734                 m_xHighLowMF->set_sensitive(false);
2735             }
2736             m_xHighLowMF->set_value(m_xHighLowMF->normalize(nFac * nEsc), FieldUnit::PERCENT);
2737         }
2738         else
2739         {
2740             m_xNormalPosBtn->set_active(true);
2741             m_xHighLowRB->set_active(true);
2742             PositionHdl_Impl(*m_xNormalPosBtn);
2743         }
2744         //the height has to be set after the handler is called to keep the value also if the escapement is zero
2745         m_xFontSizeMF->set_value(m_xFontSizeMF->normalize(nEscProp), FieldUnit::PERCENT);
2746     }
2747     else
2748     {
2749         m_xHighPosBtn->set_active(false);
2750         m_xNormalPosBtn->set_active(false);
2751         m_xLowPosBtn->set_active(false);
2752 
2753         m_xHighLowRB->set_active(true);
2754     }
2755 
2756     // set BspFont
2757     SetPrevFontEscapement( 100, nEscProp, nEsc );
2758 
2759     // Kerning
2760     nWhich = GetWhich( SID_ATTR_CHAR_KERNING );
2761 
2762     if ( rSet->GetItemState( nWhich ) >= SfxItemState::DEFAULT )
2763     {
2764         const SvxKerningItem& rItem = static_cast<const SvxKerningItem&>(rSet->Get( nWhich ));
2765         MapUnit eUnit = rSet->GetPool()->GetMetric( nWhich );
2766         tools::Long nBig = static_cast<tools::Long>(m_xKerningMF->normalize( static_cast<tools::Long>(rItem.GetValue()) ));
2767         tools::Long nKerning = OutputDevice::LogicToLogic(nBig, eUnit, MapUnit::MapPoint);
2768 
2769         // set Kerning at the Font, convert into Twips before
2770         tools::Long nKern = OutputDevice::LogicToLogic(rItem.GetValue(), eUnit, MapUnit::MapTwip);
2771         rFont.SetFixKerning( static_cast<short>(nKern) );
2772         rCJKFont.SetFixKerning( static_cast<short>(nKern) );
2773         rCTLFont.SetFixKerning( static_cast<short>(nKern) );
2774 
2775         //the attribute value must be displayed also if it's above/below the maximum allowed value
2776         tools::Long nVal = static_cast<tools::Long>(m_xKerningMF->get_max(FieldUnit::POINT));
2777         if(nVal < nKerning)
2778             m_xKerningMF->set_max(nKerning, FieldUnit::POINT);
2779         nVal = static_cast<tools::Long>(m_xKerningMF->get_min(FieldUnit::POINT));
2780         if (nVal > nKerning)
2781             m_xKerningMF->set_min(nKerning, FieldUnit::POINT);
2782         m_xKerningMF->set_value(nKerning, FieldUnit::POINT);
2783     }
2784     else
2785         m_xKerningMF->set_text(OUString());
2786 
2787     // Pair kerning
2788     nWhich = GetWhich( SID_ATTR_CHAR_AUTOKERN );
2789 
2790     if ( rSet->GetItemState( nWhich ) >= SfxItemState::DEFAULT )
2791     {
2792         const SvxAutoKernItem& rItem = static_cast<const SvxAutoKernItem&>(rSet->Get( nWhich ));
2793         m_xPairKerningBtn->set_active(rItem.GetValue());
2794     }
2795     else
2796         m_xPairKerningBtn->set_active(false);
2797 
2798     // No hyphenation
2799     nWhich = GetWhich( sal_uInt16(19) );  // number borrowed from RES_CHRATR_NOHYPHEN
2800     if ( rSet->GetItemState( nWhich ) >= SfxItemState::DEFAULT )
2801     {
2802         const SvxNoHyphenItem& rItem = static_cast<const SvxNoHyphenItem&>(rSet->Get( nWhich ));
2803         m_xNoHyphenationBtn->set_active(rItem.GetValue());
2804     }
2805     else
2806         m_xNoHyphenationBtn->set_active(false);
2807 
2808     // Scale Width
2809     nWhich = GetWhich( SID_ATTR_CHAR_SCALEWIDTH );
2810     if ( rSet->GetItemState( nWhich ) >= SfxItemState::DEFAULT )
2811     {
2812         const SvxCharScaleWidthItem& rItem = static_cast<const SvxCharScaleWidthItem&>( rSet->Get( nWhich ) );
2813         m_nScaleWidthInitialVal = rItem.GetValue();
2814         m_xScaleWidthMF->set_value(m_nScaleWidthInitialVal, FieldUnit::PERCENT);
2815     }
2816     else
2817         m_xScaleWidthMF->set_value(100, FieldUnit::PERCENT);
2818 
2819     if ( rSet->GetItemState( SID_ATTR_CHAR_WIDTH_FIT_TO_LINE ) >= SfxItemState::DEFAULT )
2820         m_nScaleWidthItemSetVal = rSet->Get( SID_ATTR_CHAR_WIDTH_FIT_TO_LINE ).GetValue();
2821 
2822     // Rotation
2823     nWhich = GetWhich( SID_ATTR_CHAR_ROTATED );
2824     SfxItemState eState = rSet->GetItemState( nWhich );
2825     if( SfxItemState::UNKNOWN == eState )
2826     {
2827         m_xRotationContainer->hide();
2828         m_xRotationAndScalingFrame->set_label(CuiResId(RID_CUISTR_SCALING));
2829     }
2830     else
2831     {
2832         m_xRotationContainer->show();
2833         m_xRotationAndScalingFrame->set_label(CuiResId(RID_CUISTR_ROTATION_SCALING));
2834 
2835         if( eState >= SfxItemState::DEFAULT )
2836         {
2837             const SvxCharRotateItem& rItem =
2838                     static_cast<const SvxCharRotateItem&>( rSet->Get( nWhich ));
2839             if (rItem.IsBottomToTop())
2840                 m_x90degRB->set_active(true);
2841             else if (rItem.IsTopToBottom())
2842                 m_x270degRB->set_active(true);
2843             else
2844             {
2845                 DBG_ASSERT( 0_deg10 == rItem.GetValue(), "incorrect value" );
2846                 m_x0degRB->set_active(true);
2847             }
2848             m_xFitToLineCB->set_active(rItem.IsFitToLine());
2849         }
2850         else
2851         {
2852             if( eState == SfxItemState::INVALID )
2853             {
2854                 m_x0degRB->set_active(false);
2855                 m_x90degRB->set_active(false);
2856                 m_x270degRB->set_active(false);
2857             }
2858             else
2859                 m_x0degRB->set_active(true);
2860 
2861             m_xFitToLineCB->set_active(false);
2862         }
2863         m_xFitToLineCB->set_sensitive(!m_x0degRB->get_active());
2864 
2865         // is this value set?
2866         if( SfxItemState::UNKNOWN == rSet->GetItemState(
2867                                         SID_ATTR_CHAR_WIDTH_FIT_TO_LINE ))
2868             m_xFitToLineCB->hide();
2869     }
2870     ChangesApplied();
2871 }
2872 
ChangesApplied()2873 void SvxCharPositionPage::ChangesApplied()
2874 {
2875     m_xHighPosBtn->save_state();
2876     m_xNormalPosBtn->save_state();
2877     m_xLowPosBtn->save_state();
2878     m_xHighLowRB->save_state();
2879     m_x0degRB->save_state();
2880     m_x90degRB->save_state();
2881     m_x270degRB->save_state();
2882     m_xFitToLineCB->save_state();
2883     m_xScaleWidthMF->save_value();
2884     m_xKerningMF->save_value();
2885     m_xPairKerningBtn->save_state();
2886     m_xNoHyphenationBtn->save_state();
2887 }
2888 
FillItemSet(SfxItemSet * rSet)2889 bool SvxCharPositionPage::FillItemSet( SfxItemSet* rSet )
2890 {
2891     //  Position (high, normal or low)
2892     const SfxItemSet& rOldSet = GetItemSet();
2893     bool bModified = false, bChanged = true;
2894     sal_uInt16 nWhich = GetWhich( SID_ATTR_CHAR_ESCAPEMENT );
2895     const SfxPoolItem* pOld = GetOldItem( *rSet, SID_ATTR_CHAR_ESCAPEMENT );
2896     const bool bHigh = m_xHighPosBtn->get_active();
2897     short nEsc;
2898     sal_uInt8  nEscProp;
2899 
2900     if (bHigh || m_xLowPosBtn->get_active())
2901     {
2902         if (m_xHighLowRB->get_active())
2903             nEsc = bHigh ? DFLT_ESC_AUTO_SUPER : DFLT_ESC_AUTO_SUB;
2904         else
2905         {
2906             nEsc = static_cast<short>(m_xHighLowMF->denormalize(m_xHighLowMF->get_value(FieldUnit::PERCENT)));
2907             nEsc *= (bHigh ? 1 : -1);
2908         }
2909         nEscProp = static_cast<sal_uInt8>(m_xFontSizeMF->denormalize(m_xFontSizeMF->get_value(FieldUnit::PERCENT)));
2910     }
2911     else
2912     {
2913         nEsc  = 0;
2914         nEscProp = 100;
2915     }
2916 
2917     if ( pOld )
2918     {
2919         const SvxEscapementItem& rItem = *static_cast<const SvxEscapementItem*>(pOld);
2920         if (rItem.GetEsc() == nEsc && rItem.GetProportionalHeight() == nEscProp)
2921             bChanged = false;
2922     }
2923 
2924     if ( !bChanged && !m_xHighPosBtn->get_saved_state() &&
2925          !m_xNormalPosBtn->get_saved_state() && !m_xLowPosBtn->get_saved_state() )
2926         bChanged = true;
2927 
2928     if ( bChanged &&
2929          ( m_xHighPosBtn->get_active() || m_xNormalPosBtn->get_active() || m_xLowPosBtn->get_active() ) )
2930     {
2931         rSet->Put( SvxEscapementItem( nEsc, nEscProp, nWhich ) );
2932         bModified = true;
2933     }
2934     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2935         rSet->InvalidateItem(nWhich);
2936 
2937     bChanged = true;
2938 
2939     // Kerning
2940     nWhich = GetWhich( SID_ATTR_CHAR_KERNING );
2941     pOld = GetOldItem( *rSet, SID_ATTR_CHAR_KERNING );
2942     short nKerning = 0;
2943     MapUnit eUnit = rSet->GetPool()->GetMetric( nWhich );
2944 
2945     tools::Long nTmp = static_cast<tools::Long>(m_xKerningMF->get_value(FieldUnit::POINT));
2946     tools::Long nVal = OutputDevice::LogicToLogic(nTmp, MapUnit::MapPoint, eUnit);
2947     nKerning = static_cast<short>(m_xKerningMF->denormalize( nVal ));
2948 
2949     SfxItemState eOldKernState = rOldSet.GetItemState( nWhich, false );
2950     if ( pOld )
2951     {
2952         const SvxKerningItem& rItem = *static_cast<const SvxKerningItem*>(pOld);
2953         if ( (eOldKernState >= SfxItemState::DEFAULT || m_xKerningMF->get_text().isEmpty()) && rItem.GetValue() == nKerning )
2954             bChanged = false;
2955     }
2956 
2957     if ( bChanged )
2958     {
2959         rSet->Put( SvxKerningItem( nKerning, nWhich ) );
2960         bModified = true;
2961     }
2962     else if ( SfxItemState::DEFAULT == eOldKernState )
2963         rSet->InvalidateItem(nWhich);
2964 
2965     // Pair-Kerning
2966     nWhich = GetWhich( SID_ATTR_CHAR_AUTOKERN );
2967 
2968     if (m_xPairKerningBtn->get_state_changed_from_saved())
2969     {
2970         rSet->Put( SvxAutoKernItem( m_xPairKerningBtn->get_active(), nWhich ) );
2971         bModified = true;
2972     }
2973     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2974         rSet->InvalidateItem(nWhich);
2975 
2976     // No hyphenation
2977 
2978     nWhich = GetWhich( sal_uInt16(19) );  // number borrowed from RES_CHRATR_NOHYPHEN
2979 
2980     if (m_xNoHyphenationBtn->get_state_changed_from_saved())
2981     {
2982         rSet->Put( SvxNoHyphenItem( m_xNoHyphenationBtn->get_active(), nWhich ) );
2983         bModified = true;
2984     }
2985     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2986         rSet->InvalidateItem(nWhich);
2987 
2988     // Scale Width
2989     nWhich = GetWhich( SID_ATTR_CHAR_SCALEWIDTH );
2990     if (m_xScaleWidthMF->get_value_changed_from_saved())
2991     {
2992         rSet->Put(SvxCharScaleWidthItem(static_cast<sal_uInt16>(m_xScaleWidthMF->get_value(FieldUnit::PERCENT)), TypedWhichId<SvxCharScaleWidthItem>(nWhich)));
2993         bModified = true;
2994     }
2995     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
2996         rSet->InvalidateItem(nWhich);
2997 
2998     // Rotation
2999     nWhich = GetWhich( SID_ATTR_CHAR_ROTATED );
3000     if ( m_x0degRB->get_state_changed_from_saved()  ||
3001          m_x90degRB->get_state_changed_from_saved()  ||
3002          m_x270degRB->get_state_changed_from_saved()  ||
3003          m_xFitToLineCB->get_state_changed_from_saved() )
3004     {
3005         SvxCharRotateItem aItem( 0_deg10, m_xFitToLineCB->get_active(), TypedWhichId<SvxCharRotateItem>(nWhich) );
3006         if (m_x90degRB->get_active())
3007             aItem.SetBottomToTop();
3008         else if (m_x270degRB->get_active())
3009             aItem.SetTopToBottom();
3010         rSet->Put( aItem );
3011         bModified = true;
3012     }
3013     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
3014         rSet->InvalidateItem(nWhich);
3015 
3016     return bModified;
3017 }
3018 
3019 
FillUserData()3020 void SvxCharPositionPage::FillUserData()
3021 {
3022     static constexpr OUString cTok( u";"_ustr );
3023 
3024     OUString sUser = OUString::number( m_nSuperEsc )  + cTok +
3025                      OUString::number( m_nSubEsc )    + cTok +
3026                      OUString::number( m_nSuperProp ) + cTok +
3027                      OUString::number( m_nSubProp );
3028     SetUserData( sUser );
3029 }
3030 
3031 
PageCreated(const SfxAllItemSet & aSet)3032 void SvxCharPositionPage::PageCreated(const SfxAllItemSet& aSet)
3033 {
3034     const SfxUInt32Item* pFlagItem = aSet.GetItem<SfxUInt32Item>(SID_FLAG_TYPE, false);
3035     if (pFlagItem)
3036     {
3037         sal_uInt32 nFlags=pFlagItem->GetValue();
3038         if ( ( nFlags & SVX_PREVIEW_CHARACTER ) == SVX_PREVIEW_CHARACTER )
3039             // the writer uses SID_ATTR_BRUSH as font background
3040             m_bPreviewBackgroundToCharacter = true;
3041     }
3042 }
3043 // class SvxCharTwoLinesPage ------------------------------------------------
3044 
SvxCharTwoLinesPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rInSet)3045 SvxCharTwoLinesPage::SvxCharTwoLinesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInSet)
3046     : SvxCharBasePage(pPage, pController, u"cui/ui/twolinespage.ui"_ustr, u"TwoLinesPage"_ustr, rInSet)
3047     , m_nStartBracketPosition( 0 )
3048     , m_nEndBracketPosition( 0 )
3049     , m_xTwoLinesBtn(m_xBuilder->weld_check_button(u"twolines"_ustr))
3050     , m_xEnclosingFrame(m_xBuilder->weld_widget(u"enclosing"_ustr))
3051     , m_xStartBracketLB(m_xBuilder->weld_tree_view(u"startbracket"_ustr))
3052     , m_xEndBracketLB(m_xBuilder->weld_tree_view(u"endbracket"_ustr))
3053 {
3054     for (size_t i = 0; i < std::size(TWOLINE_OPEN); ++i)
3055         m_xStartBracketLB->append(OUString::number(TWOLINE_OPEN[i].second), CuiResId(TWOLINE_OPEN[i].first));
3056     for (size_t i = 0; i < std::size(TWOLINE_CLOSE); ++i)
3057         m_xEndBracketLB->append(OUString::number(TWOLINE_CLOSE[i].second), CuiResId(TWOLINE_CLOSE[i].first));
3058 
3059     m_xPreviewWin.reset(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, m_aPreviewWin));
3060 #ifdef IOS
3061     m_xPreviewWin->hide();
3062 #endif
3063     Initialize();
3064 }
3065 
~SvxCharTwoLinesPage()3066 SvxCharTwoLinesPage::~SvxCharTwoLinesPage()
3067 {
3068 }
3069 
Initialize()3070 void SvxCharTwoLinesPage::Initialize()
3071 {
3072     m_xTwoLinesBtn->set_active(false);
3073     TwoLinesHdl_Impl(*m_xTwoLinesBtn);
3074 
3075     m_xTwoLinesBtn->connect_toggled(LINK(this, SvxCharTwoLinesPage, TwoLinesHdl_Impl));
3076 
3077     Link<weld::TreeView&,void> aLink = LINK(this, SvxCharTwoLinesPage, CharacterMapHdl_Impl);
3078     m_xStartBracketLB->connect_selection_changed(aLink);
3079     m_xEndBracketLB->connect_selection_changed(aLink);
3080 
3081     SvxFont& rFont = GetPreviewFont();
3082     SvxFont& rCJKFont = GetPreviewCJKFont();
3083     SvxFont& rCTLFont = GetPreviewCTLFont();
3084     rFont.SetFontSize( Size( 0, 220 ) );
3085     rCJKFont.SetFontSize( Size( 0, 220 ) );
3086     rCTLFont.SetFontSize( Size( 0, 220 ) );
3087 }
3088 
SelectCharacter(weld::TreeView * pBox)3089 void SvxCharTwoLinesPage::SelectCharacter(weld::TreeView* pBox)
3090 {
3091     bool bStart = pBox == m_xStartBracketLB.get();
3092     SvxCharacterMap aDlg(GetFrameWeld(), nullptr, nullptr);
3093     aDlg.DisableFontSelection();
3094 
3095     if (aDlg.run() == RET_OK)
3096     {
3097         sal_Unicode cChar = static_cast<sal_Unicode>(aDlg.GetChar());
3098         SetBracket( cChar, bStart );
3099     }
3100     else
3101     {
3102         pBox->select(bStart ? m_nStartBracketPosition : m_nEndBracketPosition);
3103     }
3104 }
3105 
3106 
SetBracket(sal_Unicode cBracket,bool bStart)3107 void SvxCharTwoLinesPage::SetBracket( sal_Unicode cBracket, bool bStart )
3108 {
3109     int nEntryPos = 0;
3110     weld::TreeView* pBox = bStart ? m_xStartBracketLB.get() : m_xEndBracketLB.get();
3111     if (cBracket == 0)
3112         pBox->select(0);
3113     else
3114     {
3115         bool bFound = false;
3116         for (int i = 1; i < pBox->n_children(); ++i)
3117         {
3118             if (pBox->get_id(i).toInt32() != CHRDLG_ENCLOSE_SPECIAL_CHAR)
3119             {
3120                 const sal_Unicode cChar = pBox->get_text(i)[0];
3121                 if (cChar == cBracket)
3122                 {
3123                     pBox->select(i);
3124                     nEntryPos = i;
3125                     bFound = true;
3126                     break;
3127                 }
3128             }
3129         }
3130 
3131         if (!bFound)
3132         {
3133             pBox->append_text(OUString(cBracket));
3134             nEntryPos = pBox->n_children() - 1;
3135             pBox->select(nEntryPos);
3136         }
3137     }
3138     if (bStart)
3139         m_nStartBracketPosition = nEntryPos;
3140     else
3141         m_nEndBracketPosition = nEntryPos;
3142 }
3143 
IMPL_LINK_NOARG(SvxCharTwoLinesPage,TwoLinesHdl_Impl,weld::Toggleable &,void)3144 IMPL_LINK_NOARG(SvxCharTwoLinesPage, TwoLinesHdl_Impl, weld::Toggleable&, void)
3145 {
3146     bool bChecked = m_xTwoLinesBtn->get_active();
3147     m_xEnclosingFrame->set_sensitive(bChecked);
3148     UpdatePreview_Impl();
3149 }
3150 
IMPL_LINK(SvxCharTwoLinesPage,CharacterMapHdl_Impl,weld::TreeView &,rBox,void)3151 IMPL_LINK(SvxCharTwoLinesPage, CharacterMapHdl_Impl, weld::TreeView&, rBox, void)
3152 {
3153     int nPos = rBox.get_selected_index();
3154     if (rBox.get_id(nPos).toInt32() == CHRDLG_ENCLOSE_SPECIAL_CHAR)
3155         SelectCharacter( &rBox );
3156     else
3157     {
3158         bool bStart = &rBox == m_xStartBracketLB.get();
3159         if (bStart)
3160             m_nStartBracketPosition = nPos;
3161         else
3162             m_nEndBracketPosition = nPos;
3163     }
3164     UpdatePreview_Impl();
3165 }
3166 
ActivatePage(const SfxItemSet & rSet)3167 void SvxCharTwoLinesPage::ActivatePage( const SfxItemSet& rSet )
3168 {
3169     SvxCharBasePage::ActivatePage(rSet);
3170 }
3171 
DeactivatePage(SfxItemSet * _pSet)3172 DeactivateRC SvxCharTwoLinesPage::DeactivatePage( SfxItemSet* _pSet )
3173 {
3174     if ( _pSet )
3175         FillItemSet( _pSet );
3176     return DeactivateRC::LeavePage;
3177 }
3178 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)3179 std::unique_ptr<SfxTabPage> SvxCharTwoLinesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet)
3180 {
3181     return std::make_unique<SvxCharTwoLinesPage>(pPage, pController, *rSet);
3182 }
3183 
Reset(const SfxItemSet * rSet)3184 void SvxCharTwoLinesPage::Reset( const SfxItemSet* rSet )
3185 {
3186     m_xTwoLinesBtn->set_active(false);
3187     sal_uInt16 nWhich = GetWhich( SID_ATTR_CHAR_TWO_LINES );
3188     SfxItemState eState = rSet->GetItemState( nWhich );
3189 
3190     if ( eState >= SfxItemState::INVALID )
3191     {
3192         const SvxTwoLinesItem& rItem = static_cast<const SvxTwoLinesItem&>(rSet->Get( nWhich ));
3193         m_xTwoLinesBtn->set_active(rItem.GetValue());
3194 
3195         if ( rItem.GetValue() )
3196         {
3197             SetBracket( rItem.GetStartBracket(), true );
3198             SetBracket( rItem.GetEndBracket(), false );
3199         }
3200     }
3201     TwoLinesHdl_Impl(*m_xTwoLinesBtn);
3202 
3203     SetPrevFontWidthScale( *rSet );
3204 }
3205 
FillItemSet(SfxItemSet * rSet)3206 bool SvxCharTwoLinesPage::FillItemSet( SfxItemSet* rSet )
3207 {
3208     const SfxItemSet& rOldSet = GetItemSet();
3209     bool bModified = false, bChanged = true;
3210     sal_uInt16 nWhich = GetWhich( SID_ATTR_CHAR_TWO_LINES );
3211     const SfxPoolItem* pOld = GetOldItem( *rSet, SID_ATTR_CHAR_TWO_LINES );
3212     bool bOn = m_xTwoLinesBtn->get_active();
3213     sal_Unicode cStart = ( bOn && m_xStartBracketLB->get_selected_index() > 0 )
3214         ? m_xStartBracketLB->get_selected_text()[0] : 0;
3215     sal_Unicode cEnd = ( bOn && m_xEndBracketLB->get_selected_index() > 0 )
3216         ? m_xEndBracketLB->get_selected_text()[0] : 0;
3217 
3218     if ( pOld )
3219     {
3220         const SvxTwoLinesItem& rItem = *static_cast<const SvxTwoLinesItem*>(pOld);
3221         if ( rItem.GetValue() ==  bOn &&
3222              ( !bOn || ( rItem.GetStartBracket() == cStart && rItem.GetEndBracket() == cEnd ) ) )
3223             bChanged = false;
3224     }
3225 
3226     if ( bChanged )
3227     {
3228         rSet->Put( SvxTwoLinesItem( bOn, cStart, cEnd, nWhich ) );
3229         bModified = true;
3230     }
3231     else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
3232         rSet->InvalidateItem(nWhich);
3233 
3234     return bModified;
3235 }
3236 
UpdatePreview_Impl()3237 void    SvxCharTwoLinesPage::UpdatePreview_Impl()
3238 {
3239     sal_Unicode cStart = m_xStartBracketLB->get_selected_index() > 0
3240         ? m_xStartBracketLB->get_selected_text()[0] : 0;
3241     sal_Unicode cEnd = m_xEndBracketLB->get_selected_index() > 0
3242         ? m_xEndBracketLB->get_selected_text()[0] : 0;
3243     m_aPreviewWin.SetBrackets(cStart, cEnd);
3244     m_aPreviewWin.SetTwoLines(m_xTwoLinesBtn->get_active());
3245     m_aPreviewWin.Invalidate();
3246 }
3247 
PageCreated(const SfxAllItemSet & aSet)3248 void SvxCharTwoLinesPage::PageCreated(const SfxAllItemSet& aSet)
3249 {
3250     const SfxUInt32Item* pFlagItem = aSet.GetItem<SfxUInt32Item>(SID_FLAG_TYPE, false);
3251     if (pFlagItem)
3252     {
3253         sal_uInt32 nFlags=pFlagItem->GetValue();
3254         if ( ( nFlags & SVX_PREVIEW_CHARACTER ) == SVX_PREVIEW_CHARACTER )
3255             // the writer uses SID_ATTR_BRUSH as font background
3256             m_bPreviewBackgroundToCharacter = true;
3257     }
3258 }
3259 
3260 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3261