xref: /core/svx/source/tbxctrls/tbcontrl.cxx (revision 1d2b6b70)
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 <utility>
21 
22 #include <comphelper/configurationlistener.hxx>
23 #include <comphelper/propertysequence.hxx>
24 #include <comphelper/propertyvalue.hxx>
25 #include <tools/color.hxx>
26 #include <svl/numformat.hxx>
27 #include <svl/poolitem.hxx>
28 #include <svl/itemset.hxx>
29 #include <vcl/commandinfoprovider.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/toolbox.hxx>
32 #include <vcl/customweld.hxx>
33 #include <vcl/vclptr.hxx>
34 #include <vcl/weldutils.hxx>
35 #include <svtools/valueset.hxx>
36 #include <svtools/ctrlbox.hxx>
37 #include <svl/style.hxx>
38 #include <svtools/ctrltool.hxx>
39 #include <svtools/borderhelper.hxx>
40 #include <vcl/InterimItemWindow.hxx>
41 #include <sfx2/tbxctrl.hxx>
42 #include <sfx2/tplpitem.hxx>
43 #include <sfx2/sfxstatuslistener.hxx>
44 #include <toolkit/helper/vclunohelper.hxx>
45 #include <sfx2/viewfrm.hxx>
46 #include <vcl/svapp.hxx>
47 #include <vcl/settings.hxx>
48 #include <vcl/virdev.hxx>
49 #include <com/sun/star/awt/FontDescriptor.hpp>
50 #include <com/sun/star/table/BorderLine2.hpp>
51 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
52 #include <com/sun/star/lang/XServiceInfo.hpp>
53 #include <com/sun/star/beans/XPropertySet.hpp>
54 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
55 #include <com/sun/star/frame/XDispatchProvider.hpp>
56 #include <com/sun/star/frame/XFrame.hpp>
57 #include <svx/strings.hrc>
58 #include <svx/svxids.hrc>
59 #include <helpids.h>
60 #include <sfx2/sidebar/Sidebar.hxx>
61 #include <svx/xtable.hxx>
62 #include <editeng/editids.hrc>
63 #include <editeng/fontitem.hxx>
64 #include <editeng/fhgtitem.hxx>
65 #include <editeng/boxitem.hxx>
66 #include <editeng/charreliefitem.hxx>
67 #include <editeng/contouritem.hxx>
68 #include <editeng/colritem.hxx>
69 #include <editeng/crossedoutitem.hxx>
70 #include <editeng/emphasismarkitem.hxx>
71 #include <editeng/flstitem.hxx>
72 #include <editeng/lineitem.hxx>
73 #include <editeng/postitem.hxx>
74 #include <editeng/shdditem.hxx>
75 #include <editeng/udlnitem.hxx>
76 #include <editeng/wghtitem.hxx>
77 #include <editeng/svxfont.hxx>
78 #include <editeng/cmapitem.hxx>
79 #include <svx/colorwindow.hxx>
80 #include <svx/colorbox.hxx>
81 #include <svx/tbcontrl.hxx>
82 #include <svx/dialmgr.hxx>
83 #include <svx/PaletteManager.hxx>
84 #include <memory>
85 
86 #include <tbxcolorupdate.hxx>
87 #include <editeng/eerdll.hxx>
88 #include <editeng/editrids.hrc>
89 #include <svx/xdef.hxx>
90 #include <svx/xfillit0.hxx>
91 #include <svx/xflclit.hxx>
92 #include <svl/currencytable.hxx>
93 #include <svtools/langtab.hxx>
94 #include <cppu/unotype.hxx>
95 #include <cppuhelper/supportsservice.hxx>
96 #include <officecfg/Office/Common.hxx>
97 #include <o3tl/safeint.hxx>
98 #include <o3tl/typed_flags_set.hxx>
99 #include <bitmaps.hlst>
100 #include <sal/log.hxx>
101 #include <unotools/collatorwrapper.hxx>
102 
103 #include <comphelper/lok.hxx>
104 #include <tools/json_writer.hxx>
105 
106 #define MAX_MRU_FONTNAME_ENTRIES    5
107 
108 #define COMBO_WIDTH_IN_CHARS        18
109 
110 // namespaces
111 using namespace ::editeng;
112 using namespace ::com::sun::star;
113 using namespace ::com::sun::star::uno;
114 using namespace ::com::sun::star::frame;
115 using namespace ::com::sun::star::beans;
116 using namespace ::com::sun::star::lang;
117 
118 namespace
119 {
120 class SvxStyleBox_Base
121 {
122 public:
123     SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget, const OUString& rCommand, SfxStyleFamily eFamily,
124                      const Reference<XDispatchProvider>& rDispatchProvider,
125                      const Reference<XFrame>& _xFrame,const OUString& rClearFormatKey,
126                      const OUString& rMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl);
127 
128     virtual ~SvxStyleBox_Base()
129     {
130     }
131 
132     void            SetFamily( SfxStyleFamily eNewFamily );
133 
134     void            SetDefaultStyle( const OUString& rDefault ) { sDefaultStyle = rDefault; }
135 
136     int get_count() const { return m_xWidget->get_count(); }
137     OUString get_text(int nIndex) const { return m_xWidget->get_text(nIndex); }
138     OUString get_active_text() const { return m_xWidget->get_active_text(); }
139 
140     void append_text(const OUString& rStr)
141     {
142         OUString sId(OUString::number(m_xWidget->get_count()));
143         m_xWidget->append(sId, rStr);
144     }
145 
146     void insert_separator(int pos, const OUString& rId)
147     {
148         m_xWidget->insert_separator(pos, rId);
149     }
150 
151     void set_active_or_entry_text(const OUString& rText)
152     {
153         const int nFound = m_xWidget->find_text(rText);
154         if (nFound != -1)
155             m_xWidget->set_active(nFound);
156         else
157             m_xWidget->set_entry_text(rText);
158     }
159 
160     void set_active(int nActive)
161     {
162         m_xWidget->set_active(nActive);
163     }
164 
165     void freeze()
166     {
167         m_xWidget->freeze();
168     }
169 
170     void save_value()
171     {
172         m_xWidget->save_value();
173     }
174 
175     void clear()
176     {
177         m_xWidget->clear();
178         m_nMaxUserDrawFontWidth = 0;
179     }
180 
181     void thaw()
182     {
183         m_xWidget->thaw();
184     }
185 
186     virtual bool DoKeyInput(const KeyEvent& rKEvt);
187 
188 private:
189     DECL_LINK(SelectHdl, weld::ComboBox&, void);
190     DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
191     DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
192     DECL_LINK(FocusOutHdl, weld::Widget&, void);
193     DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void);
194     DECL_LINK(CustomRenderHdl, weld::ComboBox::render_args, void);
195     DECL_LINK(CustomGetSizeHdl, OutputDevice&, Size);
196 
197     /// Calculate the optimal width of the dropdown.  Very expensive operation, triggers lots of font measurement.
198     void CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext);
199 
200     void Select(bool bNonTravelSelect);
201 
202 protected:
203     SvxStyleToolBoxControl& m_rCtrl;
204 
205     std::unique_ptr<weld::Builder>  m_xMenuBuilder;
206     std::unique_ptr<weld::Menu>     m_xMenu;
207     std::unique_ptr<weld::ComboBox> m_xWidget;
208 
209     SfxStyleFamily                  eStyleFamily;
210     int                             m_nMaxUserDrawFontWidth;
211     int                             m_nLastItemWithMenu;
212     bool                            bRelease;
213     Reference< XDispatchProvider >  m_xDispatchProvider;
214     Reference< XFrame >             m_xFrame;
215     OUString                        m_aCommand;
216     OUString                        aClearFormatKey;
217     OUString                        aMoreKey;
218     OUString                        sDefaultStyle;
219     bool                            bInSpecialMode;
220 
221     void            ReleaseFocus();
222     static Color    TestColorsVisible(const Color &FontCol, const Color &BackCol);
223     static void     UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const OUString &rStyleName);
224     void            SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected);
225     static bool     AdjustFontForItemHeight(OutputDevice& rDevice, tools::Rectangle const & rTextRect, tools::Long nHeight);
226     DECL_LINK(MenuSelectHdl, const OString&, void);
227     DECL_STATIC_LINK(SvxStyleBox_Base, ShowMoreHdl, void*, void);
228 };
229 
230 class SvxStyleBox_Impl final : public InterimItemWindow
231                              , public SvxStyleBox_Base
232 {
233 public:
234     SvxStyleBox_Impl(vcl::Window* pParent, const OUString& rCommand, SfxStyleFamily eFamily, const Reference< XDispatchProvider >& rDispatchProvider,
235                      const Reference< XFrame >& _xFrame,const OUString& rClearFormatKey, const OUString& rMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl);
236 
237     virtual ~SvxStyleBox_Impl() override
238     {
239         disposeOnce();
240     }
241 
242     virtual void dispose() override
243     {
244         m_xWidget.reset();
245         m_xMenu.reset();
246         m_xMenuBuilder.reset();
247         InterimItemWindow::dispose();
248     }
249 
250     virtual bool DoKeyInput(const KeyEvent& rKEvt) override;
251 
252 private:
253 
254     virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
255     void  SetOptimalSize();
256 };
257 
258 class SvxFontNameBox_Impl;
259 class SvxFontNameBox_Base;
260 
261 class SvxFontNameToolBoxControl final : public cppu::ImplInheritanceHelper<svt::ToolboxController,
262                                                                            css::lang::XServiceInfo>
263 {
264 public:
265     SvxFontNameToolBoxControl();
266 
267     // XStatusListener
268     virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
269 
270     // XToolbarController
271     virtual css::uno::Reference<css::awt::XWindow> SAL_CALL createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent) override;
272 
273     // XComponent
274     virtual void SAL_CALL dispose() override;
275 
276     // XServiceInfo
277     virtual OUString SAL_CALL getImplementationName() override;
278     virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
279     virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
280 
281 private:
282     VclPtr<SvxFontNameBox_Impl> m_xVclBox;
283     std::unique_ptr<SvxFontNameBox_Base> m_xWeldBox;
284     SvxFontNameBox_Base* m_pBox;
285 };
286 
287 class FontOptionsListener final : public comphelper::ConfigurationListenerProperty<bool>
288 {
289 private:
290     SvxFontNameBox_Base& m_rBox;
291 
292     virtual void setProperty(const css::uno::Any &rProperty) override;
293 public:
294     FontOptionsListener(const rtl::Reference<comphelper::ConfigurationListener>& rListener, const OUString& rProp, SvxFontNameBox_Base& rBox)
295         : comphelper::ConfigurationListenerProperty<bool>(rListener, rProp)
296         , m_rBox(rBox)
297     {
298     }
299 };
300 
301 class SvxFontNameBox_Base
302 {
303 private:
304     rtl::Reference<comphelper::ConfigurationListener> m_xListener;
305     FontOptionsListener m_aWYSIWYG;
306     FontOptionsListener m_aHistory;
307 
308 protected:
309     SvxFontNameToolBoxControl& m_rCtrl;
310 
311     std::unique_ptr<FontNameBox>   m_xWidget;
312     const FontList*                pFontList;
313     ::std::unique_ptr<FontList>    m_aOwnFontList;
314     vcl::Font                      aCurFont;
315     sal_uInt16                     nFtCount;
316     bool                           bRelease;
317     Reference< XDispatchProvider > m_xDispatchProvider;
318     Reference< XFrame >            m_xFrame;
319     bool            mbCheckingUnknownFont;
320 
321     void            ReleaseFocus_Impl();
322 
323     void            Select(bool bNonTravelSelect);
324 
325     void            EndPreview()
326     {
327         Sequence< PropertyValue > aArgs;
328         SfxToolBoxControl::Dispatch( m_xDispatchProvider,
329                                          ".uno:CharEndPreviewFontName",
330                                          aArgs );
331     }
332     void            CheckAndMarkUnknownFont();
333 
334 public:
335     SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget, const Reference<XDispatchProvider>& rDispatchProvider,
336                         const Reference<XFrame>& rFrame, SvxFontNameToolBoxControl& rCtrl);
337     virtual ~SvxFontNameBox_Base()
338     {
339         m_xListener->dispose();
340     }
341 
342     void            FillList();
343     void            Update( const css::awt::FontDescriptor* pFontDesc );
344     sal_uInt16      GetListCount() const { return nFtCount; }
345     void            Clear() { m_xWidget->clear(); nFtCount = 0; }
346     void            Fill( const FontList* pList )
347     {
348         m_xWidget->Fill(pList);
349         nFtCount = pList->GetFontNameCount();
350     }
351 
352     void SetOwnFontList(::std::unique_ptr<FontList> && _aOwnFontList) { m_aOwnFontList = std::move(_aOwnFontList); }
353 
354     virtual void set_sensitive(bool bSensitive)
355     {
356         m_xWidget->set_sensitive(bSensitive);
357     }
358 
359     void set_active_or_entry_text(const OUString& rText);
360 
361     void statusChanged_Impl(const css::frame::FeatureStateEvent& rEvent);
362 
363     virtual bool DoKeyInput(const KeyEvent& rKEvt);
364 
365     void EnableControls();
366 
367     DECL_LINK(SelectHdl, weld::ComboBox&, void);
368     DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
369     DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
370     DECL_LINK(FocusInHdl, weld::Widget&, void);
371     DECL_LINK(FocusOutHdl, weld::Widget&, void);
372     DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void);
373 };
374 
375 void FontOptionsListener::setProperty(const css::uno::Any &rProperty)
376 {
377     comphelper::ConfigurationListenerProperty<bool>::setProperty(rProperty);
378     m_rBox.EnableControls();
379 }
380 
381 class SvxFontNameBox_Impl final : public InterimItemWindow
382                                 , public SvxFontNameBox_Base
383 {
384 private:
385     virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
386     virtual void GetFocus() override
387     {
388         if (m_xWidget)
389             m_xWidget->grab_focus();
390         InterimItemWindow::GetFocus();
391     }
392 
393     void            SetOptimalSize();
394 
395     virtual bool DoKeyInput(const KeyEvent& rKEvt) override;
396 
397 public:
398     SvxFontNameBox_Impl(vcl::Window* pParent, const Reference<XDispatchProvider>& rDispatchProvider,
399                         const Reference<XFrame>& rFrame, SvxFontNameToolBoxControl& rCtrl);
400 
401     virtual void dispose() override
402     {
403         m_xWidget.reset();
404         InterimItemWindow::dispose();
405     }
406 
407     virtual ~SvxFontNameBox_Impl() override
408     {
409         disposeOnce();
410     }
411 
412     virtual Reference< css::accessibility::XAccessible > CreateAccessible() override;
413 
414     virtual void set_sensitive(bool bSensitive) override
415     {
416         m_xWidget->set_sensitive(bSensitive);
417         if (bSensitive)
418             InterimItemWindow::Enable();
419         else
420             InterimItemWindow::Disable();
421     }
422 };
423 
424 
425 // SelectHdl needs the Modifiers, get them in MouseButtonUp
426 class SvxFrmValueSet_Impl final : public ValueSet
427 {
428 private:
429     sal_uInt16 nModifier;
430 
431     virtual bool MouseButtonUp(const MouseEvent& rMEvt) override
432     {
433         nModifier = rMEvt.GetModifier();
434         return ValueSet::MouseButtonUp(rMEvt);
435     }
436 
437 public:
438     SvxFrmValueSet_Impl()
439         : ValueSet(nullptr)
440         , nModifier(0)
441     {
442     }
443     sal_uInt16 GetModifier() const {return nModifier;}
444 };
445 
446 }
447 
448 namespace {
449 
450 class SvxFrameToolBoxControl;
451 
452 class SvxFrameWindow_Impl final : public WeldToolbarPopup
453 {
454 private:
455     rtl::Reference<SvxFrameToolBoxControl> mxControl;
456     std::unique_ptr<SvxFrmValueSet_Impl> mxFrameSet;
457     std::unique_ptr<weld::CustomWeld> mxFrameSetWin;
458     std::vector<std::pair<BitmapEx, OUString>> aImgVec;
459     bool                        bParagraphMode;
460     bool                        m_bIsWriter;
461 
462     void InitImageList();
463     void CalcSizeValueSet();
464     DECL_LINK( SelectHdl, ValueSet*, void );
465 
466     void SetDiagonalDownBorder(const SvxLineItem& dDownLineItem);
467     void SetDiagonalUpBorder(const SvxLineItem& dUpLineItem);
468 
469 public:
470     SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent);
471     virtual void GrabFocus() override
472     {
473         mxFrameSet->GrabFocus();
474     }
475 
476     virtual void    statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
477 };
478 
479 class SvxFrameToolBoxControl : public svt::PopupWindowController
480 {
481 public:
482     explicit SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext );
483 
484     // XInitialization
485     virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) override;
486 
487     // XServiceInfo
488     virtual OUString SAL_CALL getImplementationName() override;
489     virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
490 
491     virtual void SAL_CALL execute(sal_Int16 nKeyModifier) override;
492 private:
493     virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
494     virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
495 };
496 
497     class LineListBox final : public ValueSet
498     {
499     public:
500         typedef Color (*ColorFunc)(Color);
501         typedef Color (*ColorDistFunc)(Color, Color);
502 
503         LineListBox();
504 
505         /** Set the width in Twips */
506         Size SetWidth( tools::Long nWidth )
507         {
508             tools::Long nOldWidth = m_nWidth;
509             m_nWidth = nWidth;
510             return UpdateEntries( nOldWidth );
511         }
512 
513         void SetNone( const OUString& sNone )
514         {
515             m_sNone = sNone;
516         }
517 
518         /** Insert a listbox entry with all widths in Twips. */
519         void            InsertEntry(const BorderWidthImpl& rWidthImpl,
520                             SvxBorderLineStyle nStyle, tools::Long nMinWidth = 0,
521                             ColorFunc pColor1Fn = &sameColor,
522                             ColorFunc pColor2Fn = &sameColor,
523                             ColorDistFunc pColorDistFn = &sameDistColor);
524 
525         SvxBorderLineStyle GetEntryStyle( sal_Int32 nPos ) const;
526 
527         SvxBorderLineStyle GetSelectEntryStyle() const;
528 
529         void            SetSourceUnit( FieldUnit eNewUnit ) { eSourceUnit = eNewUnit; }
530 
531         const Color&    GetColor() const { return aColor; }
532 
533         virtual void    SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
534     private:
535 
536         void         ImpGetLine(tools::Long nLine1, tools::Long nLine2, tools::Long nDistance,
537                                 Color nColor1, Color nColor2, Color nColorDist,
538                                 SvxBorderLineStyle nStyle, BitmapEx& rBmp);
539 
540         void            UpdatePaintLineColor();       // returns sal_True if maPaintCol has changed
541 
542         Size            UpdateEntries( tools::Long nOldWidth );
543         sal_Int32       GetStylePos( sal_Int32  nListPos, tools::Long nWidth );
544 
545         const Color& GetPaintColor() const
546         {
547             return maPaintCol;
548         }
549 
550         Color   GetColorLine1( sal_Int32  nPos );
551         Color   GetColorLine2( sal_Int32  nPos );
552         Color   GetColorDist( sal_Int32  nPos );
553 
554                         LineListBox( const LineListBox& ) = delete;
555         LineListBox&    operator =( const LineListBox& ) = delete;
556 
557         std::vector<std::unique_ptr<ImpLineListData>> m_vLineList;
558         tools::Long            m_nWidth;
559         OUString        m_sNone;
560         ScopedVclPtr<VirtualDevice>   aVirDev;
561         Size            aTxtSize;
562         Color const     aColor;
563         Color           maPaintCol;
564         FieldUnit       eSourceUnit;
565     };
566 
567     SvxBorderLineStyle LineListBox::GetSelectEntryStyle() const
568     {
569         SvxBorderLineStyle nStyle = SvxBorderLineStyle::SOLID;
570         size_t nPos = GetSelectItemPos();
571         if (nPos != VALUESET_ITEM_NOTFOUND)
572         {
573             if (!m_sNone.isEmpty())
574                 --nPos;
575             nStyle = GetEntryStyle( nPos );
576         }
577 
578         return nStyle;
579     }
580 
581     void LineListBox::ImpGetLine( tools::Long nLine1, tools::Long nLine2, tools::Long nDistance,
582                                 Color aColor1, Color aColor2, Color aColorDist,
583                                 SvxBorderLineStyle nStyle, BitmapEx& rBmp )
584     {
585         auto nMinWidth = GetDrawingArea()->get_ref_device().approximate_digit_width() * COMBO_WIDTH_IN_CHARS;
586         Size aSize(nMinWidth, aTxtSize.Height());
587         aSize.AdjustWidth( -(aTxtSize.Width()) );
588         aSize.AdjustWidth( -6 );
589 
590         // SourceUnit to Twips
591         if ( eSourceUnit == FieldUnit::POINT )
592         {
593             nLine1      /= 5;
594             nLine2      /= 5;
595             nDistance   /= 5;
596         }
597 
598         // Paint the lines
599         aSize = aVirDev->PixelToLogic( aSize );
600         tools::Long nPix = aVirDev->PixelToLogic( Size( 0, 1 ) ).Height();
601         sal_uInt32 n1 = nLine1;
602         sal_uInt32 n2 = nLine2;
603         tools::Long nDist  = nDistance;
604         n1 += nPix-1;
605         n1 -= n1%nPix;
606         if ( n2 )
607         {
608             nDist += nPix-1;
609             nDist -= nDist%nPix;
610             n2    += nPix-1;
611             n2    -= n2%nPix;
612         }
613         tools::Long nVirHeight = n1+nDist+n2;
614         if ( nVirHeight > aSize.Height() )
615             aSize.setHeight( nVirHeight );
616         // negative width should not be drawn
617         if ( aSize.Width() <= 0 )
618             return;
619 
620         Size aVirSize = aVirDev->LogicToPixel( aSize );
621         if ( aVirDev->GetOutputSizePixel() != aVirSize )
622             aVirDev->SetOutputSizePixel( aVirSize );
623         aVirDev->SetFillColor( aColorDist );
624         aVirDev->DrawRect( tools::Rectangle( Point(), aSize ) );
625 
626         aVirDev->SetFillColor( aColor1 );
627 
628         double y1 = double( n1 ) / 2;
629         svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle );
630 
631         if ( n2 )
632         {
633             double y2 =  n1 + nDist + double( n2 ) / 2;
634             aVirDev->SetFillColor( aColor2 );
635             svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, SvxBorderLineStyle::SOLID );
636         }
637         rBmp = aVirDev->GetBitmapEx( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
638     }
639 
640     LineListBox::LineListBox()
641         : ValueSet(nullptr)
642         , m_nWidth( 5 )
643         , aVirDev(VclPtr<VirtualDevice>::Create())
644         , aColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor())
645         , maPaintCol(COL_BLACK)
646         , eSourceUnit(FieldUnit::POINT)
647     {
648         aVirDev->SetLineColor();
649         aVirDev->SetMapMode( MapMode( MapUnit::MapTwip ) );
650     }
651 
652     void LineListBox::SetDrawingArea(weld::DrawingArea* pDrawingArea)
653     {
654         ValueSet::SetDrawingArea(pDrawingArea);
655 
656         OutputDevice& rDevice = pDrawingArea->get_ref_device();
657 
658         aTxtSize.setWidth( rDevice.approximate_digit_width() );
659         aTxtSize.setHeight( rDevice.GetTextHeight() );
660 
661         UpdatePaintLineColor();
662     }
663 
664     sal_Int32 LineListBox::GetStylePos( sal_Int32 nListPos, tools::Long nWidth )
665     {
666         sal_Int32 nPos = -1;
667         if (!m_sNone.isEmpty())
668             nListPos--;
669 
670         sal_Int32 n = 0;
671         size_t i = 0;
672         size_t nCount = m_vLineList.size();
673         while ( nPos == -1 && i < nCount )
674         {
675             auto& pData = m_vLineList[ i ];
676             if ( pData->GetMinWidth() <= nWidth )
677             {
678                 if ( nListPos == n )
679                     nPos = static_cast<sal_Int32>(i);
680                 n++;
681             }
682             i++;
683         }
684 
685         return nPos;
686     }
687 
688     void LineListBox::InsertEntry(
689         const BorderWidthImpl& rWidthImpl, SvxBorderLineStyle nStyle, tools::Long nMinWidth,
690         ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn )
691     {
692         m_vLineList.emplace_back(new ImpLineListData(
693             rWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn));
694     }
695 
696     SvxBorderLineStyle LineListBox::GetEntryStyle( sal_Int32 nPos ) const
697     {
698         ImpLineListData* pData = (0 <= nPos && o3tl::make_unsigned(nPos) < m_vLineList.size()) ? m_vLineList[ nPos ].get() : nullptr;
699         return pData ? pData->GetStyle() : SvxBorderLineStyle::NONE;
700     }
701 
702     void LineListBox::UpdatePaintLineColor()
703     {
704         const StyleSettings&    rSettings = Application::GetSettings().GetStyleSettings();
705         Color                   aNewCol( rSettings.GetWindowColor().IsDark()? rSettings.GetLabelTextColor() : aColor );
706 
707         bool bRet = aNewCol != maPaintCol;
708 
709         if( bRet )
710             maPaintCol = aNewCol;
711     }
712 
713     Size LineListBox::UpdateEntries( tools::Long nOldWidth )
714     {
715         Size aSize;
716 
717         UpdatePaintLineColor( );
718 
719         sal_Int32      nSelEntry = GetSelectItemPos();
720         sal_Int32       nTypePos = GetStylePos( nSelEntry, nOldWidth );
721 
722         // Remove the old entries
723         Clear();
724 
725         sal_uInt16 nId(1);
726 
727         // Add the new entries based on the defined width
728         if (!m_sNone.isEmpty())
729             InsertItem(nId++, Image(), m_sNone);
730 
731         sal_uInt16 n = 0;
732         sal_uInt16 nCount = m_vLineList.size( );
733         while ( n < nCount )
734         {
735             auto& pData = m_vLineList[ n ];
736             if ( pData->GetMinWidth() <= m_nWidth )
737             {
738                 BitmapEx aBmp;
739                 ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
740                         pData->GetLine2ForWidth( m_nWidth ),
741                         pData->GetDistForWidth( m_nWidth ),
742                         GetColorLine1( GetItemCount( ) ),
743                         GetColorLine2( GetItemCount( ) ),
744                         GetColorDist( GetItemCount( ) ),
745                         pData->GetStyle(), aBmp );
746                 InsertItem(nId, Image(aBmp), SvtLineListBox::GetLineStyleName(pData->GetStyle()));
747                 Size aBmpSize = aBmp.GetSizePixel();
748                 if (aBmpSize.Width() > aSize.Width())
749                     aSize.setWidth(aBmpSize.getWidth());
750                 if (aBmpSize.Height() > aSize.Height())
751                     aSize.setHeight(aBmpSize.getHeight());
752                 if ( n == nTypePos )
753                     SelectItem(nId);
754             }
755             else if ( n == nTypePos )
756                 SetNoSelection();
757             n++;
758             ++nId;
759         }
760 
761         Invalidate();
762 
763         return aSize;
764     }
765 
766     Color LineListBox::GetColorLine1( sal_Int32 nPos )
767     {
768         sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
769         if (nStyle == -1)
770             return GetPaintColor( );
771         auto& pData = m_vLineList[ nStyle ];
772         return pData->GetColorLine1( GetColor( ) );
773     }
774 
775     Color LineListBox::GetColorLine2( sal_Int32 nPos )
776     {
777         sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
778         if (nStyle == -1)
779             return GetPaintColor( );
780         auto& pData = m_vLineList[ nStyle ];
781         return pData->GetColorLine2( GetColor( ) );
782     }
783 
784     Color LineListBox::GetColorDist( sal_Int32 nPos )
785     {
786         Color rResult = Application::GetSettings().GetStyleSettings().GetFieldColor();
787 
788         sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
789         if (nStyle == -1)
790             return rResult;
791         auto& pData = m_vLineList[ nStyle ];
792         return pData->GetColorDist( GetColor( ), rResult );
793     }
794 }
795 
796 namespace {
797 
798 class SvxLineWindow_Impl final : public WeldToolbarPopup
799 {
800 private:
801     rtl::Reference<SvxFrameToolBoxControl> m_xControl;
802     std::unique_ptr<LineListBox> m_xLineStyleLb;
803     std::unique_ptr<weld::CustomWeld> m_xLineStyleLbWin;
804     bool                m_bIsWriter;
805 
806     DECL_LINK( SelectHdl, ValueSet*, void );
807 
808 public:
809     SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent);
810     virtual void GrabFocus() override
811     {
812         m_xLineStyleLb->GrabFocus();
813     }
814 };
815 
816 }
817 
818 class SvxStyleToolBoxControl;
819 
820 class SfxStyleControllerItem_Impl : public SfxStatusListener
821 {
822     public:
823         SfxStyleControllerItem_Impl( const Reference< XDispatchProvider >& rDispatchProvider,
824                                      sal_uInt16 nSlotId,
825                                      const OUString& rCommand,
826                                      SvxStyleToolBoxControl& rTbxCtl );
827 
828     protected:
829         virtual void StateChangedAtStatusListener( SfxItemState eState, const SfxPoolItem* pState ) override;
830 
831     private:
832         SvxStyleToolBoxControl& rControl;
833 };
834 
835 #define BUTTON_PADDING 10
836 #define ITEM_HEIGHT 30
837 
838 SvxStyleBox_Base::SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
839                                    const OUString& rCommand,
840                                    SfxStyleFamily eFamily,
841                                    const Reference< XDispatchProvider >& rDispatchProvider,
842                                    const Reference< XFrame >& _xFrame,
843                                    const OUString& rClearFormatKey,
844                                    const OUString& rMoreKey,
845                                    bool bInSpec, SvxStyleToolBoxControl& rCtrl)
846     : m_rCtrl(rCtrl)
847     , m_xMenuBuilder(Application::CreateBuilder(nullptr, "svx/ui/stylemenu.ui"))
848     , m_xMenu(m_xMenuBuilder->weld_menu("menu"))
849     , m_xWidget(std::move(xWidget))
850     , eStyleFamily( eFamily )
851     , m_nMaxUserDrawFontWidth(0)
852     , m_nLastItemWithMenu(-1)
853     , bRelease( true )
854     , m_xDispatchProvider( rDispatchProvider )
855     , m_xFrame(_xFrame)
856     , m_aCommand( rCommand )
857     , aClearFormatKey( rClearFormatKey )
858     , aMoreKey( rMoreKey )
859     , bInSpecialMode( bInSpec )
860 {
861     m_xWidget->connect_changed(LINK(this, SvxStyleBox_Base, SelectHdl));
862     m_xWidget->connect_key_press(LINK(this, SvxStyleBox_Base, KeyInputHdl));
863     m_xWidget->connect_entry_activate(LINK(this, SvxStyleBox_Base, ActivateHdl));
864     m_xWidget->connect_focus_out(LINK(this, SvxStyleBox_Base, FocusOutHdl));
865     m_xWidget->connect_get_property_tree(LINK(this, SvxStyleBox_Base, DumpAsPropertyTreeHdl));
866     m_xWidget->set_help_id(HID_STYLE_LISTBOX);
867     m_xWidget->set_entry_completion(true);
868     m_xMenu->connect_activate(LINK(this, SvxStyleBox_Base, MenuSelectHdl));
869 
870     m_xWidget->connect_custom_get_size(LINK(this, SvxStyleBox_Base, CustomGetSizeHdl));
871     m_xWidget->connect_custom_render(LINK(this, SvxStyleBox_Base, CustomRenderHdl));
872     m_xWidget->set_custom_renderer(true);
873 
874     m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 3);
875 }
876 
877 IMPL_LINK(SvxStyleBox_Base, CustomGetSizeHdl, OutputDevice&, rArg, Size)
878 {
879     CalcOptimalExtraUserWidth(rArg);
880     return Size(m_nMaxUserDrawFontWidth, ITEM_HEIGHT);
881 }
882 
883 SvxStyleBox_Impl::SvxStyleBox_Impl(vcl::Window* pParent,
884                                    const OUString& rCommand,
885                                    SfxStyleFamily eFamily,
886                                    const Reference< XDispatchProvider >& rDispatchProvider,
887                                    const Reference< XFrame >& _xFrame,
888                                    const OUString& rClearFormatKey,
889                                    const OUString& rMoreKey,
890                                    bool bInSpec, SvxStyleToolBoxControl& rCtrl)
891     : InterimItemWindow(pParent, "svx/ui/applystylebox.ui", "ApplyStyleBox")
892     , SvxStyleBox_Base(m_xBuilder->weld_combo_box("applystyle"), rCommand, eFamily,
893                        rDispatchProvider, _xFrame, rClearFormatKey, rMoreKey, bInSpec, rCtrl)
894 {
895     InitControlBase(m_xWidget.get());
896 
897     set_id("applystyle");
898     SetOptimalSize();
899 }
900 
901 void SvxStyleBox_Base::ReleaseFocus()
902 {
903     if ( !bRelease )
904     {
905         bRelease = true;
906         return;
907     }
908     if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() )
909         m_xFrame->getContainerWindow()->setFocus();
910 }
911 
912 IMPL_LINK(SvxStyleBox_Base, MenuSelectHdl, const OString&, rMenuIdent, void)
913 {
914     if (m_nLastItemWithMenu < 0 || m_nLastItemWithMenu >= m_xWidget->get_count())
915         return;
916 
917     OUString sEntry = m_xWidget->get_text(m_nLastItemWithMenu);
918 
919     ReleaseFocus(); // It must be after getting entry pos!
920     Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("Param", sEntry),
921                                    comphelper::makePropertyValue("Family",
922                                                                  sal_Int16( eStyleFamily )) };
923 
924     if (rMenuIdent == "update")
925     {
926         SfxToolBoxControl::Dispatch( m_xDispatchProvider,
927             ".uno:StyleUpdateByExample", aArgs );
928     }
929     else if (rMenuIdent == "edit")
930     {
931         SfxToolBoxControl::Dispatch( m_xDispatchProvider,
932             ".uno:EditStyle", aArgs );
933     }
934 }
935 
936 IMPL_STATIC_LINK_NOARG(SvxStyleBox_Base, ShowMoreHdl, void*, void)
937 {
938     SfxViewFrame* pViewFrm = SfxViewFrame::Current();
939     DBG_ASSERT( pViewFrm, "SvxStyleBox_Base::Select(): no viewframe" );
940     if (!pViewFrm)
941         return;
942     pViewFrm->ShowChildWindow(SID_SIDEBAR);
943     ::sfx2::sidebar::Sidebar::ShowPanel(u"StyleListPanel", pViewFrm->GetFrame().GetFrameInterface(), true);
944 }
945 
946 IMPL_LINK(SvxStyleBox_Base, SelectHdl, weld::ComboBox&, rCombo, void)
947 {
948     Select(rCombo.changed_by_direct_pick()); // only when picked from the list
949 }
950 
951 IMPL_LINK_NOARG(SvxStyleBox_Base, ActivateHdl, weld::ComboBox&, bool)
952 {
953     Select(true);
954     return true;
955 }
956 
957 void SvxStyleBox_Base::Select(bool bNonTravelSelect)
958 {
959     if (!bNonTravelSelect)
960         return;
961 
962     OUString aSearchEntry(m_xWidget->get_active_text());
963     bool bDoIt = true, bClear = false;
964     if( bInSpecialMode )
965     {
966         if( aSearchEntry == aClearFormatKey && m_xWidget->get_active() == 0 )
967         {
968             aSearchEntry = sDefaultStyle;
969             bClear = true;
970             //not only apply default style but also call 'ClearFormatting'
971             Sequence< PropertyValue > aEmptyVals;
972             SfxToolBoxControl::Dispatch( m_xDispatchProvider, ".uno:ResetAttributes",
973                 aEmptyVals);
974         }
975         else if (aSearchEntry == aMoreKey && m_xWidget->get_active() == (m_xWidget->get_count() - 1))
976         {
977             Application::PostUserEvent(LINK(nullptr, SvxStyleBox_Base, ShowMoreHdl));
978             //tdf#113214 change text back to previous entry
979             set_active_or_entry_text(m_xWidget->get_saved_value());
980             bDoIt = false;
981         }
982     }
983 
984     //Do we need to create a new style?
985     SfxObjectShell *pShell = SfxObjectShell::Current();
986     SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
987     SfxStyleSheetBase* pStyle = nullptr;
988 
989     bool bCreateNew = false;
990 
991     if ( pPool )
992     {
993         pStyle = pPool->First(eStyleFamily);
994         while ( pStyle && pStyle->GetName() != aSearchEntry )
995             pStyle = pPool->Next();
996     }
997 
998     if ( !pStyle )
999     {
1000         // cannot find the style for whatever reason
1001         // therefore create a new style
1002         bCreateNew = true;
1003     }
1004 
1005     /*  #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
1006         This instance may be deleted in the meantime (i.e. when a dialog is opened
1007         while in Dispatch()), accessing members will crash in this case. */
1008     ReleaseFocus();
1009 
1010     if( !bDoIt )
1011         return;
1012 
1013     if ( bClear )
1014         set_active_or_entry_text(aSearchEntry);
1015     m_xWidget->save_value();
1016 
1017     Sequence< PropertyValue > aArgs( 2 );
1018     auto pArgs = aArgs.getArray();
1019     pArgs[0].Value  <<= aSearchEntry;
1020     pArgs[1].Name   = "Family";
1021     pArgs[1].Value  <<= sal_Int16( eStyleFamily );
1022     if( bCreateNew )
1023     {
1024         pArgs[0].Name   = "Param";
1025         SfxToolBoxControl::Dispatch( m_xDispatchProvider, ".uno:StyleNewByExample", aArgs);
1026     }
1027     else
1028     {
1029         pArgs[0].Name   = "Template";
1030         SfxToolBoxControl::Dispatch( m_xDispatchProvider, m_aCommand, aArgs );
1031     }
1032 }
1033 
1034 void SvxStyleBox_Base::SetFamily( SfxStyleFamily eNewFamily )
1035 {
1036     eStyleFamily = eNewFamily;
1037 }
1038 
1039 IMPL_LINK_NOARG(SvxStyleBox_Base, FocusOutHdl, weld::Widget&, void)
1040 {
1041     if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
1042         set_active_or_entry_text(m_xWidget->get_saved_value());
1043 }
1044 
1045 IMPL_LINK(SvxStyleBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool)
1046 {
1047     return DoKeyInput(rKEvt);
1048 }
1049 
1050 bool SvxStyleBox_Base::DoKeyInput(const KeyEvent& rKEvt)
1051 {
1052     bool bHandled = false;
1053 
1054     sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1055 
1056     switch (nCode)
1057     {
1058         case KEY_TAB:
1059             bRelease = false;
1060             Select(true);
1061             break;
1062         case KEY_ESCAPE:
1063             set_active_or_entry_text(m_xWidget->get_saved_value());
1064             if (!m_rCtrl.IsInSidebar())
1065             {
1066                 ReleaseFocus();
1067                 bHandled = true;
1068             }
1069             break;
1070     }
1071 
1072     return bHandled;
1073 }
1074 
1075 bool SvxStyleBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
1076 {
1077     return SvxStyleBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt);
1078 }
1079 
1080 void SvxStyleBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
1081 {
1082     if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1083          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1084     {
1085         SetOptimalSize();
1086     }
1087 
1088     InterimItemWindow::DataChanged( rDCEvt );
1089 }
1090 
1091 bool SvxStyleBox_Base::AdjustFontForItemHeight(OutputDevice& rDevice, tools::Rectangle const & rTextRect, tools::Long nHeight)
1092 {
1093     if (rTextRect.Bottom() > nHeight)
1094     {
1095         // the text does not fit, adjust the font size
1096         double ratio = static_cast< double >( nHeight ) / rTextRect.Bottom();
1097         vcl::Font aFont(rDevice.GetFont());
1098         Size aPixelSize(aFont.GetFontSize());
1099         aPixelSize.setWidth( aPixelSize.Width() * ratio );
1100         aPixelSize.setHeight( aPixelSize.Height() * ratio );
1101         aFont.SetFontSize(aPixelSize);
1102         rDevice.SetFont(aFont);
1103         return true;
1104     }
1105     return false;
1106 }
1107 
1108 void SvxStyleBox_Impl::SetOptimalSize()
1109 {
1110     // set width in chars low so the size request will not be overridden
1111     m_xWidget->set_entry_width_chars(1);
1112     // tdf#132338 purely using this calculation to keep things their traditional width
1113     Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS + 3) * 4, 0), MapMode(MapUnit::MapAppFont)));
1114     m_xWidget->set_size_request(aSize.Width(), -1);
1115 
1116     SetSizePixel(get_preferred_size());
1117 }
1118 
1119 void SvxStyleBox_Base::UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const OUString &rStyleName)
1120 {
1121     // IMG_TXT_DISTANCE in ilstbox.hxx is 6, then 1 is added as
1122     // nBorder, and we are adding 1 in order to look better when
1123     // italics is present
1124     const int nLeftDistance = 8;
1125 
1126     tools::Rectangle aTextRect;
1127     rRenderContext.GetTextBoundRect(aTextRect, rStyleName);
1128 
1129     Point aPos(rRect.TopLeft());
1130     aPos.AdjustX(nLeftDistance );
1131 
1132     if (!AdjustFontForItemHeight(rRenderContext, aTextRect, rRect.GetHeight()))
1133         aPos.AdjustY((rRect.GetHeight() - aTextRect.Bottom() ) / 2);
1134 
1135     rRenderContext.DrawText(aPos, rStyleName);
1136 }
1137 
1138 void SvxStyleBox_Base::SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected)
1139 {
1140     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1141     if (!bIsNotSelected)
1142         rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
1143     else
1144         rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
1145 
1146     // handle the push-button
1147     if (!bIsNotSelected)
1148     {
1149         if (nItem == 0 || nItem == m_xWidget->get_count() - 1)
1150             m_xWidget->set_item_menu(OString::number(nItem), nullptr);
1151         else
1152         {
1153             m_nLastItemWithMenu = nItem;
1154             m_xWidget->set_item_menu(OString::number(nItem), m_xMenu.get());
1155         }
1156     }
1157 
1158     if (nItem <= 0 || nItem >= m_xWidget->get_count() - 1)
1159         return;
1160 
1161     SfxObjectShell *pShell = SfxObjectShell::Current();
1162     SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
1163     SfxStyleSheetBase* pStyle = nullptr;
1164 
1165     if ( pPool )
1166     {
1167         pStyle = pPool->First(eStyleFamily);
1168         while (pStyle && pStyle->GetName() != rStyleName)
1169             pStyle = pPool->Next();
1170     }
1171 
1172     if (!pStyle )
1173         return;
1174 
1175     std::optional<SfxItemSet> const pItemSet(pStyle->GetItemSetForPreview());
1176     if (!pItemSet) return;
1177 
1178     const SvxFontItem * const pFontItem =
1179         pItemSet->GetItem<SvxFontItem>(SID_ATTR_CHAR_FONT);
1180     const SvxFontHeightItem * const pFontHeightItem =
1181         pItemSet->GetItem<SvxFontHeightItem>(SID_ATTR_CHAR_FONTHEIGHT);
1182 
1183     if ( !(pFontItem && pFontHeightItem) )
1184         return;
1185 
1186     Size aFontSize( 0, pFontHeightItem->GetHeight() );
1187     Size aPixelSize(rRenderContext.LogicToPixel(aFontSize, MapMode(pShell->GetMapUnit())));
1188 
1189     // setup the font properties
1190     SvxFont aFont;
1191     aFont.SetFamilyName(pFontItem->GetFamilyName());
1192     aFont.SetStyleName(pFontItem->GetStyleName());
1193     aFont.SetFontSize(aPixelSize);
1194 
1195     const SfxPoolItem *pItem = pItemSet->GetItem( SID_ATTR_CHAR_WEIGHT );
1196     if ( pItem )
1197         aFont.SetWeight( static_cast< const SvxWeightItem* >( pItem )->GetWeight() );
1198 
1199     pItem = pItemSet->GetItem( SID_ATTR_CHAR_POSTURE );
1200     if ( pItem )
1201         aFont.SetItalic( static_cast< const SvxPostureItem* >( pItem )->GetPosture() );
1202 
1203     pItem = pItemSet->GetItem( SID_ATTR_CHAR_CONTOUR );
1204     if ( pItem )
1205         aFont.SetOutline( static_cast< const SvxContourItem* >( pItem )->GetValue() );
1206 
1207     pItem = pItemSet->GetItem( SID_ATTR_CHAR_SHADOWED );
1208     if ( pItem )
1209         aFont.SetShadow( static_cast< const SvxShadowedItem* >( pItem )->GetValue() );
1210 
1211     pItem = pItemSet->GetItem( SID_ATTR_CHAR_RELIEF );
1212     if ( pItem )
1213         aFont.SetRelief( static_cast< const SvxCharReliefItem* >( pItem )->GetValue() );
1214 
1215     pItem = pItemSet->GetItem( SID_ATTR_CHAR_UNDERLINE );
1216     if ( pItem )
1217         aFont.SetUnderline( static_cast< const SvxUnderlineItem* >( pItem )->GetLineStyle() );
1218 
1219     pItem = pItemSet->GetItem( SID_ATTR_CHAR_OVERLINE );
1220     if ( pItem )
1221         aFont.SetOverline( static_cast< const SvxOverlineItem* >( pItem )->GetValue() );
1222 
1223     pItem = pItemSet->GetItem( SID_ATTR_CHAR_STRIKEOUT );
1224     if ( pItem )
1225         aFont.SetStrikeout( static_cast< const SvxCrossedOutItem* >( pItem )->GetStrikeout() );
1226 
1227     pItem = pItemSet->GetItem( SID_ATTR_CHAR_CASEMAP );
1228     if ( pItem )
1229         aFont.SetCaseMap(static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap());
1230 
1231     pItem = pItemSet->GetItem( SID_ATTR_CHAR_EMPHASISMARK );
1232     if ( pItem )
1233         aFont.SetEmphasisMark( static_cast< const SvxEmphasisMarkItem* >( pItem )->GetEmphasisMark() );
1234 
1235     // setup the device & draw
1236     Color aFontCol = COL_AUTO, aBackCol = COL_AUTO;
1237 
1238     rRenderContext.SetFont(aFont);
1239 
1240     pItem = pItemSet->GetItem( SID_ATTR_CHAR_COLOR );
1241     // text color, when nothing is selected
1242     if ( (nullptr != pItem) && bIsNotSelected)
1243         aFontCol = static_cast< const SvxColorItem* >( pItem )->GetValue();
1244 
1245     drawing::FillStyle style = drawing::FillStyle_NONE;
1246     // which kind of Fill style is selected
1247     pItem = pItemSet->GetItem( XATTR_FILLSTYLE );
1248     // only when ok and not selected
1249     if ( (nullptr != pItem) && bIsNotSelected)
1250         style = static_cast< const XFillStyleItem* >( pItem )->GetValue();
1251 
1252     switch(style)
1253     {
1254         case drawing::FillStyle_SOLID:
1255         {
1256             // set background color
1257             pItem = pItemSet->GetItem( XATTR_FILLCOLOR );
1258             if ( nullptr != pItem )
1259                 aBackCol = static_cast< const XFillColorItem* >( pItem )->GetColorValue();
1260 
1261             if ( aBackCol != COL_AUTO )
1262             {
1263                 rRenderContext.SetFillColor(aBackCol);
1264                 rRenderContext.DrawRect(rRect);
1265             }
1266         }
1267         break;
1268 
1269         default: break;
1270         //TODO Draw the other background styles: gradient, hatching and bitmap
1271     }
1272 
1273     // when the font and background color are too similar, adjust the Font-Color
1274     if( (aFontCol != COL_AUTO) || (aBackCol != COL_AUTO) )
1275         aFontCol = TestColorsVisible(aFontCol, (aBackCol != COL_AUTO) ? aBackCol : rRenderContext.GetBackground().GetColor());
1276 
1277     // set text color
1278     if ( aFontCol != COL_AUTO )
1279         rRenderContext.SetTextColor(aFontCol);
1280 }
1281 
1282 IMPL_LINK(SvxStyleBox_Base, CustomRenderHdl, weld::ComboBox::render_args, aPayload, void)
1283 {
1284     vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
1285     const ::tools::Rectangle& rRect = std::get<1>(aPayload);
1286     bool bSelected = std::get<2>(aPayload);
1287     const OUString& rId = std::get<3>(aPayload);
1288 
1289     sal_uInt32 nIndex = rId.toUInt32();
1290 
1291     OUString aStyleName(m_xWidget->get_text(nIndex));
1292 
1293     rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
1294 
1295     SetupEntry(rRenderContext, nIndex, rRect, aStyleName, !bSelected);
1296 
1297     UserDrawEntry(rRenderContext, rRect, aStyleName);
1298 
1299     rRenderContext.Pop();
1300 }
1301 
1302 void SvxStyleBox_Base::CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext)
1303 {
1304     if (m_nMaxUserDrawFontWidth)
1305         return;
1306 
1307     tools::Long nMaxNormalFontWidth = 0;
1308     sal_Int32 nEntryCount = m_xWidget->get_count();
1309     for (sal_Int32 i = 0; i < nEntryCount; ++i)
1310     {
1311         OUString sStyleName(get_text(i));
1312         tools::Rectangle aTextRectForDefaultFont;
1313         rRenderContext.GetTextBoundRect(aTextRectForDefaultFont, sStyleName);
1314 
1315         const tools::Long nWidth = aTextRectForDefaultFont.GetWidth();
1316 
1317         nMaxNormalFontWidth = std::max(nWidth, nMaxNormalFontWidth);
1318     }
1319 
1320     m_nMaxUserDrawFontWidth = nMaxNormalFontWidth;
1321     for (sal_Int32 i = 1; i < nEntryCount-1; ++i)
1322     {
1323         OUString sStyleName(get_text(i));
1324 
1325         rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
1326         SetupEntry(rRenderContext, i, tools::Rectangle(0, 0, RECT_MAX, ITEM_HEIGHT), sStyleName, true);
1327         tools::Rectangle aTextRectForActualFont;
1328         rRenderContext.GetTextBoundRect(aTextRectForActualFont, sStyleName);
1329         if (AdjustFontForItemHeight(rRenderContext, aTextRectForActualFont, ITEM_HEIGHT))
1330         {
1331             //Font didn't fit, so it was changed, refetch with final font size
1332             rRenderContext.GetTextBoundRect(aTextRectForActualFont, sStyleName);
1333         }
1334         rRenderContext.Pop();
1335 
1336         const int nWidth = aTextRectForActualFont.GetWidth() + m_xWidget->get_menu_button_width() + BUTTON_PADDING;
1337 
1338         m_nMaxUserDrawFontWidth = std::max(nWidth, m_nMaxUserDrawFontWidth);
1339     }
1340 }
1341 
1342 // test is the color between Font- and background-color to be identify
1343 // return is always the Font-Color
1344 //        when both light or dark, change the Contrast
1345 //        in other case do not change the origin color
1346 //        when the color is R=G=B=128 the DecreaseContrast make 128 the need an exception
1347 Color SvxStyleBox_Base::TestColorsVisible(const Color &FontCol, const Color &BackCol)
1348 {
1349     constexpr sal_uInt8  ChgVal = 60;       // increase/decrease the Contrast
1350 
1351     Color  retCol = FontCol;
1352     if ((FontCol.IsDark() == BackCol.IsDark()) && (FontCol.IsBright() == BackCol.IsBright()))
1353     {
1354         sal_uInt8 lumi = retCol.GetLuminance();
1355 
1356         if((lumi > 120) && (lumi < 140))
1357             retCol.DecreaseLuminance(ChgVal / 2);
1358         else
1359             retCol.DecreaseContrast(ChgVal);
1360     }
1361 
1362     return retCol;
1363 }
1364 
1365 IMPL_LINK(SvxStyleBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
1366 {
1367     {
1368         auto entriesNode = rJsonWriter.startNode("entries");
1369         for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i)
1370         {
1371             auto entryNode = rJsonWriter.startNode("");
1372             rJsonWriter.put("", m_xWidget->get_text(i));
1373         }
1374     }
1375 
1376     int nActive = m_xWidget->get_active();
1377     rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nActive == -1 ? 0 : 1));
1378 
1379     {
1380         auto selectedNode = rJsonWriter.startNode("selectedEntries");
1381         if (nActive != -1)
1382         {
1383             auto node = rJsonWriter.startNode("");
1384             rJsonWriter.put("", static_cast<sal_Int32>(nActive));
1385         }
1386     }
1387 
1388     rJsonWriter.put("command", ".uno:StyleApply");
1389 }
1390 
1391 static bool lcl_GetDocFontList(const FontList** ppFontList, SvxFontNameBox_Base* pBox)
1392 {
1393     bool bChanged = false;
1394     const SfxObjectShell* pDocSh = SfxObjectShell::Current();
1395     const SvxFontListItem* pFontListItem = nullptr;
1396 
1397     if ( pDocSh )
1398         pFontListItem =
1399             static_cast<const SvxFontListItem*>(pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST ));
1400     else
1401     {
1402         ::std::unique_ptr<FontList> aFontList(new FontList(Application::GetDefaultDevice()));
1403         *ppFontList = aFontList.get();
1404         pBox->SetOwnFontList(std::move(aFontList));
1405         bChanged = true;
1406     }
1407 
1408     if ( pFontListItem )
1409     {
1410         const FontList* pNewFontList = pFontListItem->GetFontList();
1411         DBG_ASSERT( pNewFontList, "Doc-FontList not available!" );
1412 
1413         // No old list, but a new list
1414         if ( !*ppFontList && pNewFontList )
1415         {
1416             // => take over
1417             *ppFontList = pNewFontList;
1418             bChanged = true;
1419         }
1420         else
1421         {
1422             // Comparing the font lists is not perfect.
1423             // When you change the font list in the Doc, you can track
1424             // changes here only on the Listbox, because ppFontList
1425             // has already been updated.
1426             bChanged =
1427                 ( ( *ppFontList != pNewFontList ) ||
1428                   pBox->GetListCount() != pNewFontList->GetFontNameCount() );
1429             // HACK: Comparing is incomplete
1430 
1431             if ( bChanged )
1432                 *ppFontList = pNewFontList;
1433         }
1434 
1435         if ( pBox )
1436             pBox->set_sensitive(true);
1437     }
1438     else if ( pBox && ( pDocSh || !ppFontList ))
1439     {
1440         // Disable box only when we have a SfxObjectShell and didn't get a font list OR
1441         // we don't have a SfxObjectShell and no current font list.
1442         // It's possible that we currently have no SfxObjectShell, but a current font list.
1443         // See #i58471: When a user set the focus into the font name combo box and opens
1444         // the help window with F1. After closing the help window, we disable the font name
1445         // combo box. The SfxObjectShell::Current() method returns in that case zero. But the
1446         // font list hasn't changed and therefore the combo box shouldn't be disabled!
1447         pBox->set_sensitive(false);
1448     }
1449 
1450     // Fill the FontBox, also the new list if necessary
1451     if ( pBox && bChanged )
1452     {
1453         if ( *ppFontList )
1454             pBox->Fill( *ppFontList );
1455         else
1456             pBox->Clear();
1457     }
1458     return bChanged;
1459 }
1460 
1461 SvxFontNameBox_Base::SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
1462                                          const Reference<XDispatchProvider>& rDispatchProvider,
1463                                          const Reference<XFrame>& rFrame,
1464                                          SvxFontNameToolBoxControl& rCtrl)
1465     : m_xListener(new comphelper::ConfigurationListener("/org.openoffice.Office.Common/Font/View"))
1466     , m_aWYSIWYG(m_xListener, "ShowFontBoxWYSIWYG", *this)
1467     , m_aHistory(m_xListener, "History", *this)
1468     , m_rCtrl(rCtrl)
1469     , m_xWidget(new FontNameBox(std::move(xWidget)))
1470     , pFontList(nullptr)
1471     , nFtCount(0)
1472     , bRelease(true)
1473     , m_xDispatchProvider(rDispatchProvider)
1474     , m_xFrame(rFrame)
1475     , mbCheckingUnknownFont(false)
1476 {
1477     EnableControls();
1478 
1479     m_xWidget->connect_changed(LINK(this, SvxFontNameBox_Base, SelectHdl));
1480     m_xWidget->connect_key_press(LINK(this, SvxFontNameBox_Base, KeyInputHdl));
1481     m_xWidget->connect_entry_activate(LINK(this, SvxFontNameBox_Base, ActivateHdl));
1482     m_xWidget->connect_focus_in(LINK(this, SvxFontNameBox_Base, FocusInHdl));
1483     m_xWidget->connect_focus_out(LINK(this, SvxFontNameBox_Base, FocusOutHdl));
1484     m_xWidget->connect_get_property_tree(LINK(this, SvxFontNameBox_Base, DumpAsPropertyTreeHdl));
1485 
1486     m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 5);
1487 }
1488 
1489 SvxFontNameBox_Impl::SvxFontNameBox_Impl(vcl::Window* pParent, const Reference<XDispatchProvider>& rDispatchProvider,
1490                                          const Reference<XFrame>& rFrame, SvxFontNameToolBoxControl& rCtrl)
1491     : InterimItemWindow(pParent, "svx/ui/fontnamebox.ui", "FontNameBox")
1492     , SvxFontNameBox_Base(m_xBuilder->weld_combo_box("fontnamecombobox"), rDispatchProvider, rFrame, rCtrl)
1493 {
1494     set_id("fontnamecombobox");
1495     SetOptimalSize();
1496 }
1497 
1498 void SvxFontNameBox_Base::FillList()
1499 {
1500     if (!m_xWidget) // e.g. disposed
1501         return;
1502     // Save old Selection, set back in the end
1503     int nStartPos, nEndPos;
1504     m_xWidget->get_entry_selection_bounds(nStartPos, nEndPos);
1505 
1506     // Did Doc-Fontlist change?
1507     lcl_GetDocFontList(&pFontList, this);
1508 
1509     m_xWidget->select_entry_region(nStartPos, nEndPos);
1510 }
1511 
1512 void SvxFontNameBox_Base::CheckAndMarkUnknownFont()
1513 {
1514     if (mbCheckingUnknownFont) //tdf#117537 block rentry
1515         return;
1516     mbCheckingUnknownFont = true;
1517     OUString fontname = m_xWidget->get_active_text();
1518     lcl_GetDocFontList( &pFontList, this );
1519     // If the font is unknown, show it in italic.
1520     vcl::Font font = m_xWidget->get_entry_font();
1521     if( pFontList != nullptr && pFontList->IsAvailable( fontname ))
1522     {
1523         if( font.GetItalic() != ITALIC_NONE )
1524         {
1525             font.SetItalic( ITALIC_NONE );
1526             m_xWidget->set_entry_font(font);
1527             m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME));
1528         }
1529     }
1530     else
1531     {
1532         if( font.GetItalic() != ITALIC_NORMAL )
1533         {
1534             font.SetItalic( ITALIC_NORMAL );
1535             m_xWidget->set_entry_font(font);
1536             m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME_NOTAVAILABLE));
1537         }
1538     }
1539     mbCheckingUnknownFont = false;
1540 }
1541 
1542 void SvxFontNameBox_Base::Update( const css::awt::FontDescriptor* pFontDesc )
1543 {
1544     if ( pFontDesc )
1545     {
1546         aCurFont.SetFamilyName  ( pFontDesc->Name );
1547         aCurFont.SetFamily      ( FontFamily( pFontDesc->Family ) );
1548         aCurFont.SetStyleName   ( pFontDesc->StyleName );
1549         aCurFont.SetPitch       ( FontPitch( pFontDesc->Pitch ) );
1550         aCurFont.SetCharSet     ( rtl_TextEncoding( pFontDesc->CharSet ) );
1551     }
1552     OUString aCurName = aCurFont.GetFamilyName();
1553     OUString aText = m_xWidget->get_active_text();
1554     if (aText != aCurName)
1555         set_active_or_entry_text(aCurName);
1556 }
1557 
1558 void SvxFontNameBox_Base::set_active_or_entry_text(const OUString& rText)
1559 {
1560     m_xWidget->set_active_or_entry_text(rText);
1561     CheckAndMarkUnknownFont();
1562 }
1563 
1564 IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusInHdl, weld::Widget&, void)
1565 {
1566     FillList();
1567 }
1568 
1569 IMPL_LINK(SvxFontNameBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool)
1570 {
1571     return DoKeyInput(rKEvt);
1572 }
1573 
1574 bool SvxFontNameBox_Base::DoKeyInput(const KeyEvent& rKEvt)
1575 {
1576     bool bHandled = false;
1577 
1578     sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1579 
1580     switch (nCode)
1581     {
1582         case KEY_TAB:
1583             bRelease = false;
1584             Select(true);
1585             break;
1586 
1587         case KEY_ESCAPE:
1588             set_active_or_entry_text(m_xWidget->get_saved_value());
1589             if (!m_rCtrl.IsInSidebar())
1590             {
1591                 ReleaseFocus_Impl();
1592                 bHandled = true;
1593             }
1594             EndPreview();
1595             break;
1596     }
1597 
1598     return bHandled;
1599 }
1600 
1601 bool SvxFontNameBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
1602 {
1603     return SvxFontNameBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt);
1604 }
1605 
1606 IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusOutHdl, weld::Widget&, void)
1607 {
1608     if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
1609     {
1610         set_active_or_entry_text(m_xWidget->get_saved_value());
1611         // send EndPreview
1612         EndPreview();
1613     }
1614 }
1615 
1616 void SvxFontNameBox_Impl::SetOptimalSize()
1617 {
1618     // set width in chars low so the size request will not be overridden
1619     m_xWidget->set_entry_width_chars(1);
1620     // tdf#132338 purely using this calculation to keep things their traditional width
1621     Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS +5) * 4, 0), MapMode(MapUnit::MapAppFont)));
1622     m_xWidget->set_size_request(aSize.Width(), -1);
1623 
1624     SetSizePixel(get_preferred_size());
1625 }
1626 
1627 void SvxFontNameBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
1628 {
1629     if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1630          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1631     {
1632         SetOptimalSize();
1633     }
1634     else if ( ( rDCEvt.GetType() == DataChangedEventType::FONTS ) ||
1635               ( rDCEvt.GetType() == DataChangedEventType::DISPLAY ) )
1636     {
1637         // The old font list in shell has likely been destroyed at this point, so we need to get
1638         // the new one before doing anything further.
1639         lcl_GetDocFontList( &pFontList, this );
1640     }
1641 }
1642 
1643 void SvxFontNameBox_Base::ReleaseFocus_Impl()
1644 {
1645     if ( !bRelease )
1646     {
1647         bRelease = true;
1648         return;
1649     }
1650     if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() )
1651         m_xFrame->getContainerWindow()->setFocus();
1652 }
1653 
1654 void SvxFontNameBox_Base::EnableControls()
1655 {
1656     bool bEnableMRU = m_aHistory.get();
1657     sal_uInt16 nEntries = bEnableMRU ? MAX_MRU_FONTNAME_ENTRIES : 0;
1658 
1659     bool bNewWYSIWYG = m_aWYSIWYG.get();
1660     bool bOldWYSIWYG = m_xWidget->IsWYSIWYGEnabled();
1661 
1662     if (m_xWidget->get_max_mru_count() != nEntries || bNewWYSIWYG != bOldWYSIWYG)
1663     {
1664         // refill in the next GetFocus-Handler
1665         pFontList = nullptr;
1666         Clear();
1667         m_xWidget->set_max_mru_count(nEntries);
1668     }
1669 
1670     if (bNewWYSIWYG != bOldWYSIWYG)
1671         m_xWidget->EnableWYSIWYG(bNewWYSIWYG);
1672 }
1673 
1674 IMPL_LINK(SvxFontNameBox_Base, SelectHdl, weld::ComboBox&, rCombo, void)
1675 {
1676     Select(rCombo.changed_by_direct_pick()); // only when picked from the list
1677 }
1678 
1679 IMPL_LINK_NOARG(SvxFontNameBox_Base, ActivateHdl, weld::ComboBox&, bool)
1680 {
1681     Select(true);
1682     return true;
1683 }
1684 
1685 void SvxFontNameBox_Base::Select(bool bNonTravelSelect)
1686 {
1687     Sequence< PropertyValue > aArgs( 1 );
1688     auto pArgs = aArgs.getArray();
1689     std::unique_ptr<SvxFontItem> pFontItem;
1690     if ( pFontList )
1691     {
1692         FontMetric aFontMetric( pFontList->Get(m_xWidget->get_active_text(),
1693             aCurFont.GetWeight(),
1694             aCurFont.GetItalic() ) );
1695         aCurFont = aFontMetric;
1696 
1697         pFontItem.reset( new SvxFontItem( aFontMetric.GetFamilyType(),
1698             aFontMetric.GetFamilyName(),
1699             aFontMetric.GetStyleName(),
1700             aFontMetric.GetPitch(),
1701             aFontMetric.GetCharSet(),
1702             SID_ATTR_CHAR_FONT ) );
1703 
1704         Any a;
1705         pFontItem->QueryValue( a );
1706         pArgs[0].Value  = a;
1707     }
1708 
1709     if (bNonTravelSelect)
1710     {
1711         CheckAndMarkUnknownFont();
1712         //  #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
1713         //  This instance may be deleted in the meantime (i.e. when a dialog is opened
1714         //  while in Dispatch()), accessing members will crash in this case.
1715         ReleaseFocus_Impl();
1716         EndPreview();
1717         if (pFontItem)
1718         {
1719             pArgs[0].Name   = "CharFontName";
1720             SfxToolBoxControl::Dispatch( m_xDispatchProvider,
1721                                          ".uno:CharFontName",
1722                                          aArgs );
1723         }
1724     }
1725     else
1726     {
1727         if (pFontItem)
1728         {
1729             pArgs[0].Name   = "CharPreviewFontName";
1730             SfxToolBoxControl::Dispatch( m_xDispatchProvider,
1731                                          ".uno:CharPreviewFontName",
1732                                          aArgs );
1733         }
1734     }
1735 }
1736 
1737 IMPL_LINK(SvxFontNameBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
1738 {
1739     {
1740         auto entriesNode = rJsonWriter.startNode("entries");
1741         for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i)
1742         {
1743             auto entryNode = rJsonWriter.startNode("");
1744             rJsonWriter.put("", m_xWidget->get_text(i));
1745         }
1746     }
1747 
1748     int nSelectedEntry = m_xWidget->get_active();
1749     rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nSelectedEntry == -1 ? 0 : 1));
1750 
1751     {
1752         auto selectedNode = rJsonWriter.startNode("selectedEntries");
1753         if (nSelectedEntry != -1)
1754         {
1755             auto entryNode = rJsonWriter.startNode("");
1756             rJsonWriter.put("", m_xWidget->get_text(nSelectedEntry));
1757         }
1758     }
1759 
1760     rJsonWriter.put("command", ".uno:CharFontName");
1761 }
1762 
1763 ColorWindow::ColorWindow(const OUString& rCommand,
1764                          std::shared_ptr<PaletteManager> const & rPaletteManager,
1765                          ColorStatus&               rColorStatus,
1766                          sal_uInt16                 nSlotId,
1767                          const Reference< XFrame >& rFrame,
1768                          const MenuOrToolMenuButton& rMenuButton,
1769                          TopLevelParentFunction const& rTopLevelParentFunction,
1770                          ColorSelectFunction const & rColorSelectFunction)
1771     : WeldToolbarPopup(rFrame, rMenuButton.get_widget(), "svx/ui/colorwindow.ui", "palette_popup_window")
1772     , theSlotId(nSlotId)
1773     , maCommand(rCommand)
1774     , maMenuButton(rMenuButton)
1775     , mxPaletteManager(rPaletteManager)
1776     , mrColorStatus(rColorStatus)
1777     , maTopLevelParentFunction(rTopLevelParentFunction)
1778     , maColorSelectFunction(rColorSelectFunction)
1779     , mxColorSet(new SvxColorValueSet(m_xBuilder->weld_scrolled_window("colorsetwin", true)))
1780     , mxRecentColorSet(new SvxColorValueSet(nullptr))
1781     , mxPaletteListBox(m_xBuilder->weld_combo_box("palette_listbox"))
1782     , mxButtonAutoColor(m_xBuilder->weld_button("auto_color_button"))
1783     , mxButtonNoneColor(m_xBuilder->weld_button("none_color_button"))
1784     , mxButtonPicker(m_xBuilder->weld_button("color_picker_button"))
1785     , mxAutomaticSeparator(m_xBuilder->weld_widget("separator4"))
1786     , mxColorSetWin(new weld::CustomWeld(*m_xBuilder, "colorset", *mxColorSet))
1787     , mxRecentColorSetWin(new weld::CustomWeld(*m_xBuilder, "recent_colorset", *mxRecentColorSet))
1788     , mpDefaultButton(nullptr)
1789 {
1790     mxColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
1791     mxRecentColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
1792 
1793     switch ( theSlotId )
1794     {
1795         case SID_ATTR_CHAR_COLOR_BACKGROUND:
1796         case SID_BACKGROUND_COLOR:
1797         case SID_ATTR_CHAR_BACK_COLOR:
1798         case SID_TABLE_CELL_BACKGROUND_COLOR:
1799         {
1800             mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_NOFILL ) );
1801             break;
1802         }
1803         case SID_AUTHOR_COLOR:
1804         {
1805             mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_BY_AUTHOR ) );
1806             break;
1807         }
1808         case SID_BMPMASK_COLOR:
1809         {
1810             mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_TRANSPARENT ) );
1811             break;
1812         }
1813         case SID_ATTR_CHAR_COLOR:
1814         case SID_ATTR_CHAR_COLOR2:
1815         case SID_EXTRUSION_3D_COLOR:
1816         {
1817             mxButtonAutoColor->set_label(EditResId(RID_SVXSTR_AUTOMATIC));
1818             break;
1819         }
1820         case SID_FM_CTL_PROPERTIES:
1821         {
1822             mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_DEFAULT ) );
1823             break;
1824         }
1825         default:
1826         {
1827             mxButtonAutoColor->hide();
1828             mxAutomaticSeparator->hide();
1829             break;
1830         }
1831     }
1832 
1833     mxPaletteListBox->connect_changed(LINK(this, ColorWindow, SelectPaletteHdl));
1834     std::vector<OUString> aPaletteList = mxPaletteManager->GetPaletteList();
1835     mxPaletteListBox->freeze();
1836     for (const auto& rPalette : aPaletteList)
1837         mxPaletteListBox->append_text(rPalette);
1838     mxPaletteListBox->thaw();
1839     OUString aPaletteName( officecfg::Office::Common::UserColors::PaletteName::get() );
1840     mxPaletteListBox->set_active_text(aPaletteName);
1841     const int nSelectedEntry(mxPaletteListBox->get_active());
1842     if (nSelectedEntry != -1)
1843         mxPaletteManager->SetPalette(nSelectedEntry);
1844 
1845     mxButtonAutoColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl));
1846     mxButtonNoneColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl));
1847     mxButtonPicker->connect_clicked(LINK(this, ColorWindow, OpenPickerClickHdl));
1848 
1849     mxColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl));
1850     mxRecentColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl));
1851     m_xTopLevel->set_help_id(HID_POPUP_COLOR);
1852     mxColorSet->SetHelpId(HID_POPUP_COLOR_CTRL);
1853 
1854     mxPaletteManager->ReloadColorSet(*mxColorSet);
1855     const sal_uInt32 nMaxItems(SvxColorValueSet::getMaxRowCount() * SvxColorValueSet::getColumnCount());
1856     Size aSize = mxColorSet->layoutAllVisible(nMaxItems);
1857     mxColorSet->set_size_request(aSize.Width(), aSize.Height());
1858 
1859     mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
1860     aSize = mxRecentColorSet->layoutAllVisible(mxPaletteManager->GetRecentColorCount());
1861     mxRecentColorSet->set_size_request(aSize.Width(), aSize.Height());
1862 
1863     AddStatusListener( ".uno:ColorTableState" );
1864     AddStatusListener( maCommand );
1865     if ( maCommand == ".uno:FrameLineColor" )
1866     {
1867         AddStatusListener( ".uno:BorderTLBR" );
1868         AddStatusListener( ".uno:BorderBLTR" );
1869     }
1870 }
1871 
1872 void ColorWindow::GrabFocus()
1873 {
1874     if (mxColorSet->IsNoSelection() && mpDefaultButton)
1875         mpDefaultButton->grab_focus();
1876     else
1877         mxColorSet->GrabFocus();
1878 }
1879 
1880 void ColorWindow::ShowNoneButton()
1881 {
1882     mxButtonNoneColor->show();
1883 }
1884 
1885 ColorWindow::~ColorWindow()
1886 {
1887 }
1888 
1889 NamedColor ColorWindow::GetSelectEntryColor(ValueSet const * pColorSet)
1890 {
1891     Color aColor = pColorSet->GetItemColor(pColorSet->GetSelectedItemId());
1892     OUString sColorName = pColorSet->GetItemText(pColorSet->GetSelectedItemId());
1893     return std::make_pair(aColor, sColorName);
1894 }
1895 
1896 namespace
1897 {
1898     NamedColor GetAutoColor(sal_uInt16 nSlotId)
1899     {
1900         Color aColor;
1901         OUString sColorName;
1902         switch (nSlotId)
1903         {
1904             case SID_ATTR_CHAR_COLOR_BACKGROUND:
1905             case SID_BACKGROUND_COLOR:
1906             case SID_ATTR_CHAR_BACK_COLOR:
1907             case SID_TABLE_CELL_BACKGROUND_COLOR:
1908                 aColor = COL_TRANSPARENT;
1909                 sColorName = SvxResId(RID_SVXSTR_NOFILL);
1910                 break;
1911             case SID_AUTHOR_COLOR:
1912                 aColor = COL_TRANSPARENT;
1913                 sColorName = SvxResId(RID_SVXSTR_BY_AUTHOR);
1914                 break;
1915             case SID_BMPMASK_COLOR:
1916                 aColor = COL_TRANSPARENT;
1917                 sColorName = SvxResId(RID_SVXSTR_TRANSPARENT);
1918                 break;
1919             case SID_FM_CTL_PROPERTIES:
1920                 aColor = COL_TRANSPARENT;
1921                 sColorName = SvxResId(RID_SVXSTR_DEFAULT);
1922                 break;
1923             case SID_ATTR_CHAR_COLOR:
1924             case SID_ATTR_CHAR_COLOR2:
1925             case SID_EXTRUSION_3D_COLOR:
1926             default:
1927                 aColor = COL_AUTO;
1928                 sColorName = EditResId(RID_SVXSTR_AUTOMATIC);
1929                 break;
1930         }
1931 
1932         return std::make_pair(aColor, sColorName);
1933     }
1934 
1935     NamedColor GetNoneColor()
1936     {
1937         return std::make_pair(COL_NONE_COLOR, comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE)
1938             : SvxResId(RID_SVXSTR_NONE));
1939     }
1940 }
1941 
1942 NamedColor ColorWindow::GetSelectEntryColor() const
1943 {
1944     if (!mxColorSet->IsNoSelection())
1945         return GetSelectEntryColor(mxColorSet.get());
1946     if (!mxRecentColorSet->IsNoSelection())
1947         return GetSelectEntryColor(mxRecentColorSet.get());
1948     if (mxButtonNoneColor.get() == mpDefaultButton)
1949         return GetNoneColor();
1950     return GetAutoColor();
1951 }
1952 
1953 IMPL_LINK(ColorWindow, SelectHdl, ValueSet*, pColorSet, void)
1954 {
1955     NamedColor aNamedColor = GetSelectEntryColor(pColorSet);
1956 
1957     if (pColorSet != mxRecentColorSet.get())
1958     {
1959          mxPaletteManager->AddRecentColor(aNamedColor.first, aNamedColor.second);
1960          if (!maMenuButton.get_active())
1961             mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
1962     }
1963 
1964     maSelectedLink.Call(aNamedColor);
1965 
1966     // deliberate take a copy here in case maMenuButton.set_inactive
1967     // triggers a callback that destroys ourself
1968     ColorSelectFunction aColorSelectFunction(maColorSelectFunction);
1969     OUString sCommand(maCommand);
1970     // Same for querying IsTheme early.
1971     bool bThemePaletteSelected = mxPaletteManager->IsThemePaletteSelected();
1972     sal_uInt16 nSelectedItemId = pColorSet->GetSelectedItemId();
1973 
1974     maMenuButton.set_inactive();
1975 
1976     auto aNamedThemedColor = svx::NamedThemedColor::FromNamedColor(aNamedColor);
1977     if (bThemePaletteSelected)
1978     {
1979         PaletteManager::GetThemeIndexLumModOff(nSelectedItemId, aNamedThemedColor.m_nThemeIndex,
1980                                                aNamedThemedColor.m_nLumMod,
1981                                                aNamedThemedColor.m_nLumOff);
1982     }
1983     aColorSelectFunction(sCommand, aNamedThemedColor);
1984 }
1985 
1986 IMPL_LINK_NOARG(ColorWindow, SelectPaletteHdl, weld::ComboBox&, void)
1987 {
1988     int nPos = mxPaletteListBox->get_active();
1989     mxPaletteManager->SetPalette( nPos );
1990     mxPaletteManager->ReloadColorSet(*mxColorSet);
1991     mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount());
1992 }
1993 
1994 NamedColor ColorWindow::GetAutoColor() const
1995 {
1996     return ::GetAutoColor(theSlotId);
1997 }
1998 
1999 IMPL_LINK(ColorWindow, AutoColorClickHdl, weld::Button&, rButton, void)
2000 {
2001     NamedColor aNamedColor = &rButton == mxButtonAutoColor.get() ? GetAutoColor() : GetNoneColor();
2002 
2003     mxColorSet->SetNoSelection();
2004     mxRecentColorSet->SetNoSelection();
2005     mpDefaultButton = &rButton;
2006 
2007     maSelectedLink.Call(aNamedColor);
2008 
2009     // deliberate take a copy here in case maMenuButton.set_inactive
2010     // triggers a callback that destroys ourself
2011     ColorSelectFunction aColorSelectFunction(maColorSelectFunction);
2012     OUString sCommand(maCommand);
2013 
2014     maMenuButton.set_inactive();
2015 
2016     aColorSelectFunction(sCommand, svx::NamedThemedColor::FromNamedColor(aNamedColor));
2017 }
2018 
2019 IMPL_LINK_NOARG(ColorWindow, OpenPickerClickHdl, weld::Button&, void)
2020 {
2021     // copy before set_inactive
2022     auto nColor = GetSelectEntryColor().first;
2023     auto pParentWindow = maTopLevelParentFunction();
2024     OUString sCommand = maCommand;
2025     std::shared_ptr<PaletteManager> xPaletteManager(mxPaletteManager);
2026 
2027     maMenuButton.set_inactive();
2028 
2029     xPaletteManager->PopupColorPicker(pParentWindow, sCommand, nColor);
2030 }
2031 
2032 void ColorWindow::SetNoSelection()
2033 {
2034     mxColorSet->SetNoSelection();
2035     mxRecentColorSet->SetNoSelection();
2036     mpDefaultButton = nullptr;
2037 }
2038 
2039 bool ColorWindow::IsNoSelection() const
2040 {
2041     if (!mxColorSet->IsNoSelection())
2042         return false;
2043     if (!mxRecentColorSet->IsNoSelection())
2044         return false;
2045     return !mxButtonAutoColor->get_visible() && !mxButtonNoneColor->get_visible();
2046 }
2047 
2048 void ColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent )
2049 {
2050     if (rEvent.FeatureURL.Complete == ".uno:ColorTableState")
2051     {
2052         if (rEvent.IsEnabled && mxPaletteManager->GetPalette() == 0)
2053         {
2054             mxPaletteManager->ReloadColorSet(*mxColorSet);
2055             mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount());
2056         }
2057     }
2058     else
2059     {
2060         mrColorStatus.statusChanged(rEvent);
2061         SelectEntry(mrColorStatus.GetColor());
2062     }
2063 }
2064 
2065 bool ColorWindow::SelectValueSetEntry(SvxColorValueSet* pColorSet, const Color& rColor)
2066 {
2067     for (size_t i = 1; i <= pColorSet->GetItemCount(); ++i)
2068     {
2069         if (rColor == pColorSet->GetItemColor(i))
2070         {
2071             pColorSet->SelectItem(i);
2072             return true;
2073         }
2074     }
2075     return false;
2076 }
2077 
2078 void ColorWindow::SelectEntry(const NamedColor& rNamedColor)
2079 {
2080     SetNoSelection();
2081 
2082     const Color &rColor = rNamedColor.first;
2083 
2084     if (mxButtonAutoColor->get_visible() && (rColor == COL_TRANSPARENT || rColor == COL_AUTO))
2085     {
2086         mpDefaultButton = mxButtonAutoColor.get();
2087         return;
2088     }
2089 
2090     if (mxButtonNoneColor->get_visible() && rColor == COL_NONE_COLOR)
2091     {
2092         mpDefaultButton = mxButtonNoneColor.get();
2093         return;
2094     }
2095 
2096     // try current palette
2097     bool bFoundColor = SelectValueSetEntry(mxColorSet.get(), rColor);
2098     // try recently used
2099     if (!bFoundColor)
2100         bFoundColor = SelectValueSetEntry(mxRecentColorSet.get(), rColor);
2101     // if it's not there, add it there now to the end of the recently used
2102     // so its available somewhere handy, but not without trashing the
2103     // whole recently used
2104     if (!bFoundColor)
2105     {
2106         const OUString& rColorName = rNamedColor.second;
2107         mxPaletteManager->AddRecentColor(rColor, rColorName, false);
2108         mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
2109         SelectValueSetEntry(mxRecentColorSet.get(), rColor);
2110     }
2111 }
2112 
2113 void ColorWindow::SelectEntry(const Color& rColor)
2114 {
2115     OUString sColorName = "#" + rColor.AsRGBHexString().toAsciiUpperCase();
2116     ColorWindow::SelectEntry(std::make_pair(rColor, sColorName));
2117 }
2118 
2119 ColorStatus::ColorStatus() :
2120     maColor( COL_TRANSPARENT ),
2121     maTLBRColor( COL_TRANSPARENT ),
2122     maBLTRColor( COL_TRANSPARENT )
2123 {
2124 }
2125 
2126 void ColorStatus::statusChanged( const css::frame::FeatureStateEvent& rEvent )
2127 {
2128     Color aColor( COL_TRANSPARENT );
2129     css::table::BorderLine2 aTable;
2130 
2131     if ( rEvent.State >>= aTable )
2132     {
2133         SvxBorderLine aLine;
2134         SvxBoxItem::LineToSvxLine( aTable, aLine, false );
2135         if ( !aLine.isEmpty() )
2136             aColor = aLine.GetColor();
2137     }
2138     else
2139         rEvent.State >>= aColor;
2140 
2141     if ( rEvent.FeatureURL.Path == "BorderTLBR" )
2142         maTLBRColor = aColor;
2143     else if ( rEvent.FeatureURL.Path == "BorderBLTR" )
2144         maBLTRColor = aColor;
2145     else
2146         maColor = aColor;
2147 }
2148 
2149 Color ColorStatus::GetColor()
2150 {
2151     Color aColor( maColor );
2152 
2153     if ( maTLBRColor != COL_TRANSPARENT )
2154     {
2155         if ( aColor != maTLBRColor && aColor != COL_TRANSPARENT )
2156             return COL_TRANSPARENT;
2157         aColor = maTLBRColor;
2158     }
2159 
2160     if ( maBLTRColor != COL_TRANSPARENT )
2161     {
2162         if ( aColor != maBLTRColor && aColor != COL_TRANSPARENT )
2163             return COL_TRANSPARENT;
2164         return maBLTRColor;
2165     }
2166 
2167     return aColor;
2168 }
2169 
2170 
2171 SvxFrameWindow_Impl::SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent)
2172     : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder")
2173     , mxControl(pControl)
2174     , mxFrameSet(new SvxFrmValueSet_Impl)
2175     , mxFrameSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxFrameSet))
2176     , bParagraphMode(false)
2177     , m_bIsWriter(false)
2178 {
2179 
2180     // check whether the document is Writer or not
2181     if (Reference<lang::XServiceInfo> xSI{ m_xFrame->getController()->getModel(), UNO_QUERY })
2182         m_bIsWriter = xSI->supportsService("com.sun.star.text.TextDocument");
2183 
2184     mxFrameSet->SetStyle(WB_ITEMBORDER | WB_DOUBLEBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT);
2185     AddStatusListener(".uno:BorderReducedMode");
2186     InitImageList();
2187 
2188     /*
2189      *  1       2        3         4            5
2190      *  ------------------------------------------------------
2191      *  NONE    LEFT     RIGHT     LEFTRIGHT    DIAGONALDOWN
2192      *  TOP     BOTTOM   TOPBOTTOM OUTER        DIAGONALUP
2193      *  ------------------------------------------------------
2194      *  HOR     HORINNER VERINNER   ALL         CRISSCROSS      <- can be switched of via bParagraphMode
2195      */
2196 
2197     sal_uInt16 i = 0;
2198 
2199     // diagonal borders available only for Calc.
2200     // Therefore, Calc uses 10 border types while
2201     // Writer uses 8 of them - for a single cell.
2202     for ( i=1; i < (m_bIsWriter ? 9 : 11); i++ )
2203         mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
2204 
2205     //bParagraphMode should have been set in StateChanged
2206     if ( !bParagraphMode )
2207         // when multiple cell selected:
2208         // Writer has 12 border types and Calc has 15 of them.
2209         for ( i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
2210             mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
2211 
2212     // adjust frame column for Writer
2213     sal_uInt16 colCount = m_bIsWriter ? 4 : 5;
2214     mxFrameSet->SetColCount( colCount );
2215     mxFrameSet->SetSelectHdl( LINK( this, SvxFrameWindow_Impl, SelectHdl ) );
2216     CalcSizeValueSet();
2217 
2218     mxFrameSet->SetHelpId( HID_POPUP_FRAME );
2219     mxFrameSet->SetAccessibleName( SvxResId(RID_SVXSTR_FRAME) );
2220 }
2221 
2222 namespace {
2223 
2224 enum class FrmValidFlags {
2225     NONE      = 0x00,
2226     Left      = 0x01,
2227     Right     = 0x02,
2228     Top       = 0x04,
2229     Bottom    = 0x08,
2230     HInner    = 0x10,
2231     VInner    = 0x20,
2232     AllMask   = 0x3f,
2233 };
2234 
2235 }
2236 
2237 namespace o3tl {
2238     template<> struct typed_flags<FrmValidFlags> : is_typed_flags<FrmValidFlags, 0x3f> {};
2239 }
2240 
2241 // By default unset lines remain unchanged.
2242 // Via Shift unset lines are reset
2243 
2244 IMPL_LINK_NOARG(SvxFrameWindow_Impl, SelectHdl, ValueSet*, void)
2245 {
2246     SvxBoxItem          aBorderOuter( SID_ATTR_BORDER_OUTER );
2247     SvxBoxInfoItem      aBorderInner( SID_ATTR_BORDER_INNER );
2248     SvxBorderLine       theDefLine;
2249 
2250     // diagonal down border
2251     SvxBorderLine       dDownBorderLine(nullptr, SvxBorderLineWidth::Hairline);
2252     SvxLineItem         dDownLineItem(SID_ATTR_BORDER_DIAG_TLBR);
2253 
2254     // diagonal up border
2255     SvxBorderLine       dUpBorderLine(nullptr, SvxBorderLineWidth::Hairline);
2256     SvxLineItem         dUpLineItem(SID_ATTR_BORDER_DIAG_BLTR);
2257 
2258     bool                bIsDiagonalBorder = false;
2259 
2260     SvxBorderLine       *pLeft = nullptr,
2261                         *pRight = nullptr,
2262                         *pTop = nullptr,
2263                         *pBottom = nullptr;
2264     sal_uInt16           nSel = mxFrameSet->GetSelectedItemId();
2265     sal_uInt16           nModifier = mxFrameSet->GetModifier();
2266     FrmValidFlags        nValidFlags = FrmValidFlags::NONE;
2267 
2268     // tdf#48622, tdf#145828 use correct default to create intended 0.75pt
2269     // cell border using the border formatting tool in the standard toolbar
2270     theDefLine.GuessLinesWidths(theDefLine.GetBorderLineStyle(), SvxBorderLineWidth::Thin);
2271 
2272     // nSel has 15 cases which means 15 border
2273     // types for Calc. But Writer uses only 12
2274     // of them - when diagonal borders excluded.
2275     if (m_bIsWriter)
2276     {
2277         // add appropriate increments
2278         // to match the correct borders.
2279         if (nSel > 8) { nSel += 2; }
2280         else if (nSel > 4) { nSel++; }
2281     }
2282 
2283     switch ( nSel )
2284     {
2285         case 1: nValidFlags |= FrmValidFlags::AllMask;
2286                 // set nullptr to remove diagonal lines
2287                 dDownLineItem.SetLine(nullptr);
2288                 dUpLineItem.SetLine(nullptr);
2289                 SetDiagonalDownBorder(dDownLineItem);
2290                 SetDiagonalUpBorder(dUpLineItem);
2291         break;  // NONE
2292         case 2: pLeft = &theDefLine;
2293                 nValidFlags |= FrmValidFlags::Left;
2294         break;  // LEFT
2295         case 3: pRight = &theDefLine;
2296                 nValidFlags |= FrmValidFlags::Right;
2297         break;  // RIGHT
2298         case 4: pLeft = pRight = &theDefLine;
2299                 nValidFlags |=  FrmValidFlags::Right|FrmValidFlags::Left;
2300         break;  // LEFTRIGHT
2301         case 5: dDownLineItem.SetLine(&dDownBorderLine);
2302                 SetDiagonalDownBorder(dDownLineItem);
2303                 bIsDiagonalBorder = true;
2304         break;  // DIAGONAL DOWN
2305         case 6: pTop = &theDefLine;
2306                 nValidFlags |= FrmValidFlags::Top;
2307         break;  // TOP
2308         case 7: pBottom = &theDefLine;
2309                 nValidFlags |= FrmValidFlags::Bottom;
2310         break;  // BOTTOM
2311         case 8: pTop =  pBottom = &theDefLine;
2312                 nValidFlags |= FrmValidFlags::Bottom|FrmValidFlags::Top;
2313         break;  // TOPBOTTOM
2314         case 9: pLeft = pRight = pTop = pBottom = &theDefLine;
2315                 nValidFlags |= FrmValidFlags::Left | FrmValidFlags::Right | FrmValidFlags::Top | FrmValidFlags::Bottom;
2316         break;  // OUTER
2317         case 10:
2318                 dUpLineItem.SetLine(&dUpBorderLine);
2319                 SetDiagonalUpBorder(dUpLineItem);
2320                 bIsDiagonalBorder = true;
2321         break;  // DIAGONAL UP
2322 
2323         // Inner Table:
2324         case 11: // HOR
2325             pTop = pBottom = &theDefLine;
2326             aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
2327             aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
2328             nValidFlags |= FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
2329             break;
2330 
2331         case 12: // HORINNER
2332             pLeft = pRight = pTop = pBottom = &theDefLine;
2333             aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
2334             aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
2335             nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
2336             break;
2337 
2338         case 13: // VERINNER
2339             pLeft = pRight = pTop = pBottom = &theDefLine;
2340             aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::HORI );
2341             aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT );
2342             nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::VInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
2343         break;
2344 
2345         case 14: // ALL
2346             pLeft = pRight = pTop = pBottom = &theDefLine;
2347             aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
2348             aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT );
2349             nValidFlags |= FrmValidFlags::AllMask;
2350             break;
2351 
2352         case 15:
2353             // set both diagonal lines to draw criss-cross line
2354             dDownLineItem.SetLine(&dDownBorderLine);
2355             dUpLineItem.SetLine(&dUpBorderLine);
2356 
2357             SetDiagonalDownBorder(dDownLineItem);
2358             SetDiagonalUpBorder(dUpLineItem);
2359             bIsDiagonalBorder = true;
2360             break; // CRISS-CROSS
2361 
2362         default:
2363         break;
2364     }
2365 
2366     // if diagonal borders selected,
2367     // no need to execute this block
2368     if (!bIsDiagonalBorder)
2369     {
2370         aBorderOuter.SetLine( pLeft, SvxBoxItemLine::LEFT );
2371         aBorderOuter.SetLine( pRight, SvxBoxItemLine::RIGHT );
2372         aBorderOuter.SetLine( pTop, SvxBoxItemLine::TOP );
2373         aBorderOuter.SetLine( pBottom, SvxBoxItemLine::BOTTOM );
2374 
2375         if(nModifier == KEY_SHIFT)
2376             nValidFlags |= FrmValidFlags::AllMask;
2377         aBorderInner.SetValid( SvxBoxInfoItemValidFlags::TOP,       bool(nValidFlags&FrmValidFlags::Top ));
2378         aBorderInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM,    bool(nValidFlags&FrmValidFlags::Bottom ));
2379         aBorderInner.SetValid( SvxBoxInfoItemValidFlags::LEFT,      bool(nValidFlags&FrmValidFlags::Left));
2380         aBorderInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT,     bool(nValidFlags&FrmValidFlags::Right ));
2381         aBorderInner.SetValid( SvxBoxInfoItemValidFlags::HORI,      bool(nValidFlags&FrmValidFlags::HInner ));
2382         aBorderInner.SetValid( SvxBoxInfoItemValidFlags::VERT,      bool(nValidFlags&FrmValidFlags::VInner));
2383         aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
2384         aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISABLE,   false );
2385 
2386         Any a1, a2;
2387         aBorderOuter.QueryValue( a1 );
2388         aBorderInner.QueryValue( a2 );
2389         Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("OuterBorder", a1),
2390                                          comphelper::makePropertyValue("InnerBorder", a2) };
2391 
2392         mxControl->dispatchCommand( ".uno:SetBorderStyle", aArgs );
2393     }
2394 
2395     if (mxFrameSet)
2396     {
2397         /* #i33380# Moved the following line above the Dispatch() call.
2398            This instance may be deleted in the meantime (i.e. when a dialog is opened
2399            while in Dispatch()), accessing members will crash in this case. */
2400         mxFrameSet->SetNoSelection();
2401     }
2402 
2403     mxControl->EndPopupMode();
2404 }
2405 
2406 void SvxFrameWindow_Impl::SetDiagonalDownBorder(const SvxLineItem& dDownLineItem)
2407 {
2408     // apply diagonal down border
2409     Any a;
2410     dDownLineItem.QueryValue(a);
2411     Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderTLBR", a) };
2412 
2413     mxControl->dispatchCommand(".uno:BorderTLBR", aArgs);
2414 }
2415 
2416 void SvxFrameWindow_Impl::SetDiagonalUpBorder(const SvxLineItem& dUpLineItem)
2417 {
2418     // apply diagonal up border
2419     Any a;
2420     dUpLineItem.QueryValue(a);
2421     Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderBLTR", a) };
2422 
2423     mxControl->dispatchCommand(".uno:BorderBLTR", aArgs);
2424 }
2425 
2426 void SvxFrameWindow_Impl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
2427 {
2428     if ( rEvent.FeatureURL.Complete != ".uno:BorderReducedMode" )
2429         return;
2430 
2431     bool bValue;
2432     if ( !(rEvent.State >>= bValue) )
2433         return;
2434 
2435     bParagraphMode = bValue;
2436     //initial calls mustn't insert or remove elements
2437     if(!mxFrameSet->GetItemCount())
2438         return;
2439 
2440     // set 12 border types for Writer, otherwise 15 for Calc.
2441     bool bTableMode = ( mxFrameSet->GetItemCount() == static_cast<size_t>(m_bIsWriter ? 12 : 15) );
2442     bool bResize    = false;
2443 
2444     if ( bTableMode && bParagraphMode )
2445     {
2446         for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
2447             mxFrameSet->RemoveItem(i);
2448         bResize = true;
2449     }
2450     else if ( !bTableMode && !bParagraphMode )
2451     {
2452         for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
2453             mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
2454         bResize = true;
2455     }
2456 
2457     if ( bResize )
2458     {
2459         CalcSizeValueSet();
2460     }
2461 }
2462 
2463 void SvxFrameWindow_Impl::CalcSizeValueSet()
2464 {
2465     weld::DrawingArea* pDrawingArea = mxFrameSet->GetDrawingArea();
2466     const OutputDevice& rDevice = pDrawingArea->get_ref_device();
2467     Size aItemSize( 20 * rDevice.GetDPIScaleFactor(), 20 * rDevice.GetDPIScaleFactor() );
2468     Size aSize = mxFrameSet->CalcWindowSizePixel( aItemSize );
2469     pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
2470     mxFrameSet->SetOutputSizePixel(aSize);
2471 }
2472 
2473 void SvxFrameWindow_Impl::InitImageList()
2474 {
2475     if (m_bIsWriter)
2476     {
2477         // Writer-specific aImgVec.
2478         // Since Writer doesn't have diagonal borders,
2479         // we have to use 12 border types here.
2480         aImgVec = {
2481             {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)},
2482             {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)},
2483             {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)},
2484             {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)},
2485 
2486             {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)},
2487             {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)},
2488             {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)},
2489             {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)},
2490 
2491             {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)},
2492             {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)},
2493             {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)},
2494             {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)}
2495         };
2496     }
2497     else
2498     {
2499         // Calc has diagonal borders feature.
2500         // Therefore use additional 3 diagonal border types,
2501         // which make border types 15 in total.
2502         aImgVec = {
2503             {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)},
2504             {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)},
2505             {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)},
2506             {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)},
2507             {BitmapEx(RID_SVXBMP_FRAME14), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALDOWN)}, // diagonal down border
2508 
2509             {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)},
2510             {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)},
2511             {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)},
2512             {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)},
2513             {BitmapEx(RID_SVXBMP_FRAME13), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALUP)}, // diagonal up border
2514 
2515             {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)},
2516             {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)},
2517             {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)},
2518             {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)},
2519             {BitmapEx(RID_SVXBMP_FRAME15), SvxResId(RID_SVXSTR_PARA_PRESET_CRISSCROSS)} // criss-cross border
2520         };
2521     }
2522 }
2523 
2524 static Color lcl_mediumColor( Color aMain, Color /*aDefault*/ )
2525 {
2526     return SvxBorderLine::threeDMediumColor( aMain );
2527 }
2528 
2529 SvxLineWindow_Impl::SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent)
2530     : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder")
2531     , m_xControl(pControl)
2532     , m_xLineStyleLb(new LineListBox)
2533     , m_xLineStyleLbWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xLineStyleLb))
2534     , m_bIsWriter(false)
2535 {
2536     try
2537     {
2538         Reference< lang::XServiceInfo > xServices(m_xFrame->getController()->getModel(), UNO_QUERY_THROW);
2539         m_bIsWriter = xServices->supportsService("com.sun.star.text.TextDocument");
2540     }
2541     catch(const uno::Exception& )
2542     {
2543     }
2544 
2545     m_xLineStyleLb->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
2546 
2547     m_xLineStyleLb->SetSourceUnit( FieldUnit::TWIP );
2548     m_xLineStyleLb->SetNone( comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE)
2549         :SvxResId(RID_SVXSTR_NONE) );
2550 
2551     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::SOLID ), SvxBorderLineStyle::SOLID );
2552     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOTTED ), SvxBorderLineStyle::DOTTED );
2553     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DASHED ), SvxBorderLineStyle::DASHED );
2554 
2555     // Double lines
2556     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOUBLE ), SvxBorderLineStyle::DOUBLE );
2557     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_SMALLGAP ), SvxBorderLineStyle::THINTHICK_SMALLGAP, 20 );
2558     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_MEDIUMGAP ), SvxBorderLineStyle::THINTHICK_MEDIUMGAP );
2559     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_LARGEGAP ), SvxBorderLineStyle::THINTHICK_LARGEGAP );
2560     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_SMALLGAP ), SvxBorderLineStyle::THICKTHIN_SMALLGAP, 20 );
2561     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_MEDIUMGAP ), SvxBorderLineStyle::THICKTHIN_MEDIUMGAP );
2562     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_LARGEGAP ), SvxBorderLineStyle::THICKTHIN_LARGEGAP );
2563 
2564     // Engraved / Embossed
2565     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::EMBOSSED ), SvxBorderLineStyle::EMBOSSED, 15,
2566             &SvxBorderLine::threeDLightColor, &SvxBorderLine::threeDDarkColor,
2567             &lcl_mediumColor );
2568     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::ENGRAVED ), SvxBorderLineStyle::ENGRAVED, 15,
2569             &SvxBorderLine::threeDDarkColor, &SvxBorderLine::threeDLightColor,
2570             &lcl_mediumColor );
2571 
2572     // Inset / Outset
2573     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::OUTSET ), SvxBorderLineStyle::OUTSET, 10,
2574            &SvxBorderLine::lightColor, &SvxBorderLine::darkColor );
2575     m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::INSET ), SvxBorderLineStyle::INSET, 10,
2576            &SvxBorderLine::darkColor, &SvxBorderLine::lightColor );
2577     Size aSize = m_xLineStyleLb->SetWidth( 20 ); // 1pt by default
2578 
2579     m_xLineStyleLb->SetSelectHdl( LINK( this, SvxLineWindow_Impl, SelectHdl ) );
2580 
2581     m_xContainer->set_help_id(HID_POPUP_LINE);
2582 
2583     aSize.AdjustWidth(6);
2584     aSize.AdjustHeight(6);
2585     aSize = m_xLineStyleLb->CalcWindowSizePixel(aSize);
2586     m_xLineStyleLb->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
2587     m_xLineStyleLb->SetOutputSizePixel(aSize);
2588 }
2589 
2590 IMPL_LINK_NOARG(SvxLineWindow_Impl, SelectHdl, ValueSet*, void)
2591 {
2592     SvxLineItem     aLineItem( SID_FRAME_LINESTYLE );
2593     SvxBorderLineStyle  nStyle = m_xLineStyleLb->GetSelectEntryStyle();
2594 
2595     if ( m_xLineStyleLb->GetSelectItemPos( ) > 0 )
2596     {
2597         SvxBorderLine aTmp;
2598         aTmp.SetBorderLineStyle( nStyle );
2599         aTmp.SetWidth( SvxBorderLineWidth::Thin ); // TODO Make it depend on a width field
2600         aLineItem.SetLine( &aTmp );
2601     }
2602     else
2603         aLineItem.SetLine( nullptr );
2604 
2605     Any a;
2606     aLineItem.QueryValue( a, m_bIsWriter ? CONVERT_TWIPS : 0 );
2607     Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("LineStyle", a) };
2608 
2609     m_xControl->dispatchCommand( ".uno:LineStyle", aArgs );
2610 
2611     m_xControl->EndPopupMode();
2612 }
2613 
2614 SfxStyleControllerItem_Impl::SfxStyleControllerItem_Impl(
2615     const Reference< XDispatchProvider >& rDispatchProvider,
2616     sal_uInt16                                nSlotId,      // Family-ID
2617     const OUString&                  rCommand,     // .uno: command bound to this item
2618     SvxStyleToolBoxControl&               rTbxCtl )     // controller instance, which the item is assigned to.
2619     :   SfxStatusListener( rDispatchProvider, nSlotId, rCommand ),
2620         rControl( rTbxCtl )
2621 {
2622 }
2623 
2624 void SfxStyleControllerItem_Impl::StateChangedAtStatusListener(
2625     SfxItemState eState, const SfxPoolItem* pState )
2626 {
2627     switch ( GetId() )
2628     {
2629         case SID_STYLE_FAMILY1:
2630         case SID_STYLE_FAMILY2:
2631         case SID_STYLE_FAMILY3:
2632         case SID_STYLE_FAMILY4:
2633         case SID_STYLE_FAMILY5:
2634         {
2635             const sal_uInt16 nIdx = GetId() - SID_STYLE_FAMILY_START;
2636 
2637             if ( SfxItemState::DEFAULT == eState )
2638             {
2639                 const SfxTemplateItem* pStateItem =
2640                     dynamic_cast<const SfxTemplateItem*>( pState  );
2641                 DBG_ASSERT( pStateItem != nullptr, "SfxTemplateItem expected" );
2642                 rControl.SetFamilyState( nIdx, pStateItem );
2643             }
2644             else
2645                 rControl.SetFamilyState( nIdx, nullptr );
2646             break;
2647         }
2648     }
2649 }
2650 
2651 struct SvxStyleToolBoxControl::Impl
2652 {
2653     OUString                     aClearForm;
2654     OUString                     aMore;
2655     ::std::vector< std::pair< OUString, OUString > >    aDefaultStyles;
2656     bool                     bSpecModeWriter;
2657     bool                     bSpecModeCalc;
2658 
2659     VclPtr<SvxStyleBox_Impl> m_xVclBox;
2660     std::unique_ptr<SvxStyleBox_Base> m_xWeldBox;
2661     SvxStyleBox_Base* m_pBox;
2662 
2663     Impl()
2664         :aClearForm         ( SvxResId( RID_SVXSTR_CLEARFORM ) )
2665         ,aMore              ( SvxResId( RID_SVXSTR_MORE_STYLES ) )
2666         ,bSpecModeWriter    ( false )
2667         ,bSpecModeCalc      ( false )
2668         ,m_pBox             ( nullptr )
2669     {
2670 
2671 
2672     }
2673     void InitializeStyles(const Reference < frame::XModel >& xModel)
2674     {
2675         aDefaultStyles.clear();
2676 
2677         //now convert the default style names to the localized names
2678         try
2679         {
2680             Reference< style::XStyleFamiliesSupplier > xStylesSupplier( xModel, UNO_QUERY_THROW );
2681             Reference< lang::XServiceInfo > xServices( xModel, UNO_QUERY_THROW );
2682             bSpecModeWriter = xServices->supportsService("com.sun.star.text.TextDocument");
2683             if(bSpecModeWriter)
2684             {
2685                 Reference<container::XNameAccess> xParaStyles;
2686                 xStylesSupplier->getStyleFamilies()->getByName("ParagraphStyles") >>=
2687                     xParaStyles;
2688                 static const std::vector<OUString> aWriterStyles =
2689                 {
2690                     "Standard",
2691                     "Text body",
2692                     "Title",
2693                     "Subtitle",
2694                     "Heading 1",
2695                     "Heading 2",
2696                     "Heading 3",
2697                     "Heading 4",
2698                     "Quotations",
2699                     "Preformatted Text"
2700                 };
2701                 for( const OUString& aStyle: aWriterStyles )
2702                 {
2703                     try
2704                     {
2705                         Reference< beans::XPropertySet > xStyle;
2706                         xParaStyles->getByName( aStyle ) >>= xStyle;
2707                         OUString sName;
2708                         xStyle->getPropertyValue("DisplayName") >>= sName;
2709                         if( !sName.isEmpty() )
2710                             aDefaultStyles.push_back(
2711                                 std::pair<OUString, OUString>(aStyle, sName) );
2712                     }
2713                     catch( const uno::Exception& )
2714                     {}
2715                 }
2716 
2717             }
2718             else if( (
2719                 bSpecModeCalc = xServices->supportsService(
2720                     "com.sun.star.sheet.SpreadsheetDocument")))
2721             {
2722                 static const char* aCalcStyles[] =
2723                 {
2724                     "Default",
2725                     "Accent 1",
2726                     "Accent 2",
2727                     "Accent 3",
2728                     "Heading 1",
2729                     "Heading 2",
2730                     "Result"
2731                 };
2732                 Reference<container::XNameAccess> xCellStyles;
2733                 xStylesSupplier->getStyleFamilies()->getByName("CellStyles") >>= xCellStyles;
2734                 for(const char* pCalcStyle : aCalcStyles)
2735                 {
2736                     try
2737                     {
2738                         const OUString sStyleName( OUString::createFromAscii( pCalcStyle ) );
2739                         if( xCellStyles->hasByName( sStyleName ) )
2740                         {
2741                             Reference< beans::XPropertySet > xStyle( xCellStyles->getByName( sStyleName), UNO_QUERY_THROW );
2742                             OUString sName;
2743                             xStyle->getPropertyValue("DisplayName") >>= sName;
2744                             if( !sName.isEmpty() )
2745                                 aDefaultStyles.push_back(
2746                                     std::pair<OUString, OUString>(sStyleName, sName) );
2747                         }
2748                     }
2749                     catch( const uno::Exception& )
2750                     {}
2751                 }
2752             }
2753         }
2754         catch(const uno::Exception& )
2755         {
2756             OSL_FAIL("error while initializing style names");
2757         }
2758     }
2759 };
2760 
2761 // mapping table from bound items. BE CAREFUL this table must be in the
2762 // same order as the uno commands bound to the slots SID_STYLE_FAMILY1..n
2763 // MAX_FAMILIES must also be correctly set!
2764 static const char* StyleSlotToStyleCommand[MAX_FAMILIES] =
2765 {
2766     ".uno:CharStyle",
2767     ".uno:ParaStyle",
2768     ".uno:FrameStyle",
2769     ".uno:PageStyle",
2770     ".uno:TemplateFamily5"
2771 };
2772 
2773 SvxStyleToolBoxControl::SvxStyleToolBoxControl()
2774     : pImpl(new Impl)
2775     , pStyleSheetPool(nullptr)
2776     , nActFamily(0xffff)
2777 {
2778     for (sal_uInt16 i = 0; i < MAX_FAMILIES; ++i)
2779     {
2780         m_xBoundItems[i].clear();
2781         pFamilyState[i]  = nullptr;
2782     }
2783 }
2784 
2785 SvxStyleToolBoxControl::~SvxStyleToolBoxControl()
2786 {
2787 }
2788 
2789 void SAL_CALL SvxStyleToolBoxControl::initialize(const Sequence<Any>& rArguments)
2790 {
2791     svt::ToolboxController::initialize(rArguments);
2792 
2793     // After initialize we should have a valid frame member where we can retrieve our
2794     // dispatch provider.
2795     if ( !m_xFrame.is() )
2796         return;
2797 
2798     pImpl->InitializeStyles(m_xFrame->getController()->getModel());
2799     Reference< XDispatchProvider > xDispatchProvider( m_xFrame->getController(), UNO_QUERY );
2800     for ( sal_uInt16 i=0; i<MAX_FAMILIES; i++ )
2801     {
2802         m_xBoundItems[i] = new SfxStyleControllerItem_Impl( xDispatchProvider,
2803                                                             SID_STYLE_FAMILY_START + i,
2804                                                             OUString::createFromAscii( StyleSlotToStyleCommand[i] ),
2805                                                             *this );
2806         pFamilyState[i]  = nullptr;
2807     }
2808 }
2809 
2810 // XComponent
2811 void SAL_CALL SvxStyleToolBoxControl::dispose()
2812 {
2813     svt::ToolboxController::dispose();
2814 
2815     SolarMutexGuard aSolarMutexGuard;
2816     pImpl->m_xVclBox.disposeAndClear();
2817     pImpl->m_xWeldBox.reset();
2818     pImpl->m_pBox = nullptr;
2819 
2820     for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems)
2821     {
2822         if (!pBoundItem)
2823             continue;
2824         pBoundItem->UnBind();
2825     }
2826     unbindListener();
2827 
2828     for( sal_uInt16 i=0; i<MAX_FAMILIES; i++ )
2829     {
2830         if ( m_xBoundItems[i].is() )
2831         {
2832             try
2833             {
2834                 m_xBoundItems[i]->dispose();
2835             }
2836             catch ( Exception& )
2837             {
2838             }
2839 
2840             m_xBoundItems[i].clear();
2841         }
2842         pFamilyState[i].reset();
2843     }
2844     pStyleSheetPool = nullptr;
2845     pImpl.reset();
2846 }
2847 
2848 OUString SvxStyleToolBoxControl::getImplementationName()
2849 {
2850     return "com.sun.star.comp.svx.StyleToolBoxControl";
2851 }
2852 
2853 sal_Bool SvxStyleToolBoxControl::supportsService( const OUString& rServiceName )
2854 {
2855     return cppu::supportsService( this, rServiceName );
2856 }
2857 
2858 css::uno::Sequence< OUString > SvxStyleToolBoxControl::getSupportedServiceNames()
2859 {
2860     return { "com.sun.star.frame.ToolbarController" };
2861 }
2862 
2863 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
2864 com_sun_star_comp_svx_StyleToolBoxControl_get_implementation(
2865     css::uno::XComponentContext*,
2866     css::uno::Sequence<css::uno::Any> const & )
2867 {
2868     return cppu::acquire( new SvxStyleToolBoxControl() );
2869 }
2870 
2871 void SAL_CALL SvxStyleToolBoxControl::update()
2872 {
2873     for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems)
2874         pBoundItem->ReBind();
2875     bindListener();
2876 }
2877 
2878 SfxStyleFamily SvxStyleToolBoxControl::GetActFamily() const
2879 {
2880     switch ( nActFamily-1 + SID_STYLE_FAMILY_START )
2881     {
2882         case SID_STYLE_FAMILY1: return SfxStyleFamily::Char;
2883         case SID_STYLE_FAMILY2: return SfxStyleFamily::Para;
2884         case SID_STYLE_FAMILY3: return SfxStyleFamily::Frame;
2885         case SID_STYLE_FAMILY4: return SfxStyleFamily::Page;
2886         case SID_STYLE_FAMILY5: return SfxStyleFamily::Pseudo;
2887         default:
2888             OSL_FAIL( "unknown style family" );
2889             break;
2890     }
2891     return SfxStyleFamily::Para;
2892 }
2893 
2894 void SvxStyleToolBoxControl::FillStyleBox()
2895 {
2896     SvxStyleBox_Base* pBox = pImpl->m_pBox;
2897 
2898     DBG_ASSERT( pStyleSheetPool, "StyleSheetPool not found!" );
2899     DBG_ASSERT( pBox,            "Control not found!" );
2900 
2901     if ( !(pStyleSheetPool && pBox && nActFamily!=0xffff) )
2902         return;
2903 
2904     const SfxStyleFamily    eFamily     = GetActFamily();
2905     SfxStyleSheetBase*      pStyle      = nullptr;
2906     bool                    bDoFill     = false;
2907 
2908     auto xIter = pStyleSheetPool->CreateIterator(eFamily, SfxStyleSearchBits::Used);
2909     sal_uInt16 nCount = xIter->Count();
2910 
2911     // Check whether fill is necessary
2912     pStyle = xIter->First();
2913     //!!! TODO: This condition isn't right any longer, because we always show some default entries
2914     //!!! so the list doesn't show the count
2915     if ( nCount != pBox->get_count() )
2916     {
2917         bDoFill = true;
2918     }
2919     else
2920     {
2921         sal_uInt16 i= 0;
2922         while ( pStyle && !bDoFill )
2923         {
2924             bDoFill = ( pBox->get_text(i) != pStyle->GetName() );
2925             pStyle = xIter->Next();
2926             i++;
2927         }
2928     }
2929 
2930     if ( !bDoFill )
2931         return;
2932 
2933     OUString aStrSel(pBox->get_active_text());
2934     pBox->freeze();
2935     pBox->clear();
2936 
2937     std::vector<OUString> aStyles;
2938 
2939     {
2940         pStyle = xIter->Next();
2941 
2942         if( pImpl->bSpecModeWriter || pImpl->bSpecModeCalc )
2943         {
2944             while ( pStyle )
2945             {
2946                 // sort out default styles
2947                 bool bInsert = true;
2948                 OUString aName( pStyle->GetName() );
2949                 for( auto const & _i: pImpl->aDefaultStyles )
2950                 {
2951                     if( _i.first == aName || _i.second == aName )
2952                     {
2953                         bInsert = false;
2954                         break;
2955                     }
2956                 }
2957 
2958                 if( bInsert )
2959                     aStyles.push_back(aName);
2960                 pStyle = xIter->Next();
2961             }
2962         }
2963         else
2964         {
2965             while ( pStyle )
2966             {
2967                 aStyles.push_back(pStyle->GetName());
2968                 pStyle = xIter->Next();
2969             }
2970         }
2971     }
2972 
2973     if (pImpl->bSpecModeWriter || pImpl->bSpecModeCalc)
2974     {
2975         pBox->append_text(pImpl->aClearForm);
2976         pBox->insert_separator(1, "separator");
2977 
2978         // insert default styles
2979         for (const auto &rStyle : pImpl->aDefaultStyles)
2980             pBox->append_text(rStyle.second);
2981     }
2982 
2983     std::sort(aStyles.begin(), aStyles.end());
2984 
2985     for (const auto& rStyle : aStyles)
2986         pBox->append_text(rStyle);
2987 
2988     if ((pImpl->bSpecModeWriter || pImpl->bSpecModeCalc) && !comphelper::LibreOfficeKit::isActive())
2989         pBox->append_text(pImpl->aMore);
2990 
2991     pBox->thaw();
2992     pBox->set_active_or_entry_text(aStrSel);
2993     pBox->SetFamily( eFamily );
2994 }
2995 
2996 void SvxStyleToolBoxControl::SelectStyle( const OUString& rStyleName )
2997 {
2998     SvxStyleBox_Base* pBox = pImpl->m_pBox;
2999     DBG_ASSERT( pBox, "Control not found!" );
3000 
3001     if ( !pBox )
3002         return;
3003 
3004     OUString aStrSel(pBox->get_active_text());
3005 
3006     if ( !rStyleName.isEmpty() )
3007     {
3008         OUString aNewStyle = rStyleName;
3009 
3010         auto aFound = std::find_if(pImpl->aDefaultStyles.begin(), pImpl->aDefaultStyles.end(),
3011             [rStyleName] (auto it) { return it.first == rStyleName || it.second == rStyleName; }
3012         );
3013 
3014         if (aFound != pImpl->aDefaultStyles.end())
3015             aNewStyle = aFound->second;
3016 
3017         if ( aNewStyle != aStrSel )
3018             pBox->set_active_or_entry_text( aNewStyle );
3019     }
3020     else
3021         pBox->set_active(-1);
3022     pBox->save_value();
3023 }
3024 
3025 void SvxStyleToolBoxControl::Update()
3026 {
3027     SfxStyleSheetBasePool*  pPool     = nullptr;
3028     SfxObjectShell*         pDocShell = SfxObjectShell::Current();
3029 
3030     if ( pDocShell )
3031         pPool = pDocShell->GetStyleSheetPool();
3032 
3033     sal_uInt16 i;
3034     for ( i=0; i<MAX_FAMILIES; i++ )
3035         if( pFamilyState[i] )
3036             break;
3037 
3038     if ( i==MAX_FAMILIES || !pPool )
3039     {
3040         pStyleSheetPool = pPool;
3041         return;
3042     }
3043 
3044 
3045     const SfxTemplateItem* pItem = nullptr;
3046 
3047     if ( nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get()) )
3048     // Current range not within allowed ranges or default
3049     {
3050         pStyleSheetPool = pPool;
3051         nActFamily      = 2;
3052 
3053         pItem = pFamilyState[nActFamily-1].get();
3054         if ( !pItem )
3055         {
3056             nActFamily++;
3057             pItem = pFamilyState[nActFamily-1].get();
3058         }
3059     }
3060     else if ( pPool != pStyleSheetPool )
3061         pStyleSheetPool = pPool;
3062 
3063     FillStyleBox(); // Decides by itself whether Fill is needed
3064 
3065     if ( pItem )
3066         SelectStyle( pItem->GetStyleName() );
3067 }
3068 
3069 void SvxStyleToolBoxControl::SetFamilyState( sal_uInt16 nIdx,
3070                                              const SfxTemplateItem* pItem )
3071 {
3072     pFamilyState[nIdx].reset( pItem == nullptr ? nullptr : new SfxTemplateItem( *pItem ) );
3073     Update();
3074 }
3075 
3076 void SvxStyleToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
3077 {
3078     SolarMutexGuard aGuard;
3079 
3080     if (m_pToolbar)
3081         m_pToolbar->set_item_sensitive(m_aCommandURL.toUtf8(), rEvent.IsEnabled);
3082     else
3083     {
3084         ToolBox* pToolBox = nullptr;
3085         ToolBoxItemId nId;
3086         if (!getToolboxId( nId, &pToolBox ) )
3087             return;
3088         pToolBox->EnableItem( nId, rEvent.IsEnabled );
3089     }
3090 
3091     if (rEvent.IsEnabled)
3092         Update();
3093 }
3094 
3095 css::uno::Reference<css::awt::XWindow> SvxStyleToolBoxControl::createItemWindow(const css::uno::Reference< css::awt::XWindow>& rParent)
3096 {
3097     uno::Reference< awt::XWindow > xItemWindow;
3098 
3099     if (m_pBuilder)
3100     {
3101         SolarMutexGuard aSolarMutexGuard;
3102 
3103         std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("applystyle"));
3104 
3105         xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
3106 
3107         pImpl->m_xWeldBox.reset(new SvxStyleBox_Base(std::move(xWidget),
3108                                                      ".uno:StyleApply",
3109                                                      SfxStyleFamily::Para,
3110                                                      Reference< XDispatchProvider >( m_xFrame->getController(), UNO_QUERY ),
3111                                                      m_xFrame,
3112                                                      pImpl->aClearForm,
3113                                                      pImpl->aMore,
3114                                                      pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this));
3115         pImpl->m_pBox = pImpl->m_xWeldBox.get();
3116     }
3117     else
3118     {
3119         VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent);
3120         if ( pParent )
3121         {
3122             SolarMutexGuard aSolarMutexGuard;
3123 
3124             pImpl->m_xVclBox = VclPtr<SvxStyleBox_Impl>::Create(pParent,
3125                                                                 ".uno:StyleApply",
3126                                                                 SfxStyleFamily::Para,
3127                                                                 Reference< XDispatchProvider >( m_xFrame->getController(), UNO_QUERY ),
3128                                                                 m_xFrame,
3129                                                                 pImpl->aClearForm,
3130                                                                 pImpl->aMore,
3131                                                                 pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this);
3132             pImpl->m_pBox = pImpl->m_xVclBox.get();
3133             xItemWindow = VCLUnoHelper::GetInterface(pImpl->m_xVclBox);
3134         }
3135     }
3136 
3137     if (pImpl->m_pBox && !pImpl->aDefaultStyles.empty())
3138         pImpl->m_pBox->SetDefaultStyle(pImpl->aDefaultStyles[0].second);
3139 
3140     return xItemWindow;
3141 }
3142 
3143 SvxFontNameToolBoxControl::SvxFontNameToolBoxControl()
3144     : m_pBox(nullptr)
3145 {
3146 }
3147 
3148 void SvxFontNameBox_Base::statusChanged_Impl( const css::frame::FeatureStateEvent& rEvent )
3149 {
3150     if ( !rEvent.IsEnabled )
3151     {
3152         set_sensitive(false);
3153         Update( nullptr );
3154     }
3155     else
3156     {
3157         set_sensitive(true);
3158 
3159         css::awt::FontDescriptor aFontDesc;
3160         if ( rEvent.State >>= aFontDesc )
3161             Update(&aFontDesc);
3162         else {
3163             // no active element; delete value in the display
3164             m_xWidget->set_active(-1);
3165             set_active_or_entry_text("");
3166         }
3167         m_xWidget->save_value();
3168     }
3169 }
3170 
3171 void SvxFontNameToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
3172 {
3173     SolarMutexGuard aGuard;
3174     m_pBox->statusChanged_Impl(rEvent);
3175 
3176     if (m_pToolbar)
3177         m_pToolbar->set_item_sensitive(m_aCommandURL.toUtf8(), rEvent.IsEnabled);
3178     else
3179     {
3180         ToolBox* pToolBox = nullptr;
3181         ToolBoxItemId nId;
3182         if (!getToolboxId( nId, &pToolBox ) )
3183             return;
3184         pToolBox->EnableItem( nId, rEvent.IsEnabled );
3185     }
3186 }
3187 
3188 css::uno::Reference<css::awt::XWindow> SvxFontNameToolBoxControl::createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent)
3189 {
3190     uno::Reference< awt::XWindow > xItemWindow;
3191 
3192     if (m_pBuilder)
3193     {
3194         SolarMutexGuard aSolarMutexGuard;
3195 
3196         std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("fontnamecombobox"));
3197 
3198         xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
3199 
3200         m_xWeldBox.reset(new SvxFontNameBox_Base(std::move(xWidget),
3201                                                  Reference<XDispatchProvider>(m_xFrame->getController(), UNO_QUERY),
3202                                                  m_xFrame, *this));
3203         m_pBox = m_xWeldBox.get();
3204     }
3205     else
3206     {
3207         VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent);
3208         if ( pParent )
3209         {
3210             SolarMutexGuard aSolarMutexGuard;
3211             m_xVclBox = VclPtr<SvxFontNameBox_Impl>::Create(pParent,
3212                                                             Reference<XDispatchProvider>(m_xFrame->getController(), UNO_QUERY),
3213                                                             m_xFrame, *this);
3214             m_pBox = m_xVclBox.get();
3215             xItemWindow = VCLUnoHelper::GetInterface(m_xVclBox);
3216         }
3217     }
3218 
3219     return xItemWindow;
3220 }
3221 
3222 void SvxFontNameToolBoxControl::dispose()
3223 {
3224     ToolboxController::dispose();
3225 
3226     SolarMutexGuard aSolarMutexGuard;
3227     m_xVclBox.disposeAndClear();
3228     m_xWeldBox.reset();
3229     m_pBox = nullptr;
3230 }
3231 
3232 OUString SvxFontNameToolBoxControl::getImplementationName()
3233 {
3234     return "com.sun.star.comp.svx.FontNameToolBoxControl";
3235 }
3236 
3237 sal_Bool SvxFontNameToolBoxControl::supportsService( const OUString& rServiceName )
3238 {
3239     return cppu::supportsService( this, rServiceName );
3240 }
3241 
3242 css::uno::Sequence< OUString > SvxFontNameToolBoxControl::getSupportedServiceNames()
3243 {
3244     return { "com.sun.star.frame.ToolbarController" };
3245 }
3246 
3247 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3248 com_sun_star_comp_svx_FontNameToolBoxControl_get_implementation(
3249     css::uno::XComponentContext*,
3250     css::uno::Sequence<css::uno::Any> const & )
3251 {
3252     return cppu::acquire( new SvxFontNameToolBoxControl() );
3253 }
3254 
3255 SvxColorToolBoxControl::SvxColorToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) :
3256     ImplInheritanceHelper( rContext, nullptr, OUString() ),
3257     m_bSplitButton(true),
3258     m_nSlotId(0),
3259     m_aColorSelectFunction(PaletteManager::DispatchColorCommand)
3260 {
3261 }
3262 
3263 namespace {
3264 
3265 sal_uInt16 MapCommandToSlotId(const OUString& rCommand)
3266 {
3267     if (rCommand == ".uno:Color")
3268         return SID_ATTR_CHAR_COLOR;
3269     else if (rCommand == ".uno:FontColor")
3270         return SID_ATTR_CHAR_COLOR2;
3271     else if (rCommand == ".uno:BackColor")
3272         return SID_ATTR_CHAR_COLOR_BACKGROUND;
3273     else if (rCommand == ".uno:CharBackColor")
3274         return SID_ATTR_CHAR_BACK_COLOR;
3275     else if (rCommand == ".uno:BackgroundColor")
3276         return SID_BACKGROUND_COLOR;
3277     else if (rCommand == ".uno:TableCellBackgroundColor")
3278         return SID_TABLE_CELL_BACKGROUND_COLOR;
3279     else if (rCommand == ".uno:Extrusion3DColor")
3280         return SID_EXTRUSION_3D_COLOR;
3281     else if (rCommand == ".uno:XLineColor")
3282         return SID_ATTR_LINE_COLOR;
3283     else if (rCommand == ".uno:FillColor")
3284         return SID_ATTR_FILL_COLOR;
3285     else if (rCommand == ".uno:FrameLineColor")
3286         return SID_FRAME_LINECOLOR;
3287 
3288     SAL_WARN("svx.tbxcrtls", "Unknown color command: " << rCommand);
3289     return 0;
3290 }
3291 
3292 }
3293 
3294 void SvxColorToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>& rArguments )
3295 {
3296     PopupWindowController::initialize( rArguments );
3297 
3298     m_nSlotId = MapCommandToSlotId( m_aCommandURL );
3299 
3300     if ( m_nSlotId == SID_ATTR_LINE_COLOR || m_nSlotId == SID_ATTR_FILL_COLOR ||
3301          m_nSlotId == SID_FRAME_LINECOLOR || m_nSlotId == SID_BACKGROUND_COLOR )
3302     {
3303         // Sidebar uses wide buttons for those.
3304         m_bSplitButton = !m_bSidebar;
3305     }
3306 
3307     auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(getCommandURL(), getModuleName());
3308     OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
3309 
3310     OString aId(m_aCommandURL.toUtf8());
3311 
3312     if (m_pToolbar)
3313     {
3314         mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
3315         m_pToolbar->set_item_popover(aId, mxPopoverContainer->getTopLevel());
3316         m_xBtnUpdater.reset(new svx::ToolboxButtonColorUpdater(m_nSlotId, aId, m_pToolbar, !m_bSplitButton, aCommandLabel, m_xFrame));
3317         return;
3318     }
3319 
3320     ToolBox* pToolBox = nullptr;
3321     ToolBoxItemId nId;
3322     if (getToolboxId(nId, &pToolBox))
3323     {
3324         m_xBtnUpdater.reset( new svx::VclToolboxButtonColorUpdater( m_nSlotId, nId, pToolBox, !m_bSplitButton,  aCommandLabel, m_aCommandURL, m_xFrame ) );
3325         pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ( m_bSplitButton ? ToolBoxItemBits::DROPDOWN : ToolBoxItemBits::DROPDOWNONLY ) );
3326     }
3327 }
3328 
3329 void SvxColorToolBoxControl::update()
3330 {
3331     PopupWindowController::update();
3332 
3333     switch( m_nSlotId )
3334     {
3335         case SID_ATTR_CHAR_COLOR2:
3336             addStatusListener( ".uno:CharColorExt");
3337             break;
3338 
3339         case SID_ATTR_CHAR_COLOR_BACKGROUND:
3340             addStatusListener( ".uno:CharBackgroundExt");
3341             break;
3342 
3343         case SID_FRAME_LINECOLOR:
3344             addStatusListener( ".uno:BorderTLBR");
3345             addStatusListener( ".uno:BorderBLTR");
3346             break;
3347     }
3348 }
3349 
3350 void SvxColorToolBoxControl::EnsurePaletteManager()
3351 {
3352     if (!m_xPaletteManager)
3353     {
3354         m_xPaletteManager = std::make_shared<PaletteManager>();
3355         m_xPaletteManager->SetBtnUpdater(m_xBtnUpdater.get());
3356     }
3357 }
3358 
3359 SvxColorToolBoxControl::~SvxColorToolBoxControl()
3360 {
3361     if (m_xPaletteManager)
3362         m_xPaletteManager->SetBtnUpdater(nullptr);
3363 }
3364 
3365 void SvxColorToolBoxControl::setColorSelectFunction(const ColorSelectFunction& aColorSelectFunction)
3366 {
3367     m_aColorSelectFunction = aColorSelectFunction;
3368     if (m_xPaletteManager)
3369         m_xPaletteManager->SetColorSelectFunction(aColorSelectFunction);
3370 }
3371 
3372 weld::Window* SvxColorToolBoxControl::GetParentFrame() const
3373 {
3374     const css::uno::Reference<css::awt::XWindow> xParent = m_xFrame->getContainerWindow();
3375     return Application::GetFrameWeld(xParent);
3376 }
3377 
3378 std::unique_ptr<WeldToolbarPopup> SvxColorToolBoxControl::weldPopupWindow()
3379 {
3380     EnsurePaletteManager();
3381 
3382     const OString aId(m_aCommandURL.toUtf8());
3383 
3384     auto xPopover = std::make_unique<ColorWindow>(
3385                         m_aCommandURL,
3386                         m_xPaletteManager,
3387                         m_aColorStatus,
3388                         m_nSlotId,
3389                         m_xFrame,
3390                         MenuOrToolMenuButton(m_pToolbar, aId),
3391                         [this] { return GetParentFrame(); },
3392                         m_aColorSelectFunction);
3393 
3394     if ( m_bSplitButton )
3395         xPopover->SetSelectedHdl( LINK( this, SvxColorToolBoxControl, SelectedHdl ) );
3396 
3397     return xPopover;
3398 }
3399 
3400 VclPtr<vcl::Window> SvxColorToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
3401 {
3402     ToolBox* pToolBox = nullptr;
3403     ToolBoxItemId nId;
3404     if (!getToolboxId(nId, &pToolBox))
3405         return nullptr;
3406 
3407     EnsurePaletteManager();
3408 
3409     auto xPopover = std::make_unique<ColorWindow>(
3410                         m_aCommandURL,
3411                         m_xPaletteManager,
3412                         m_aColorStatus,
3413                         m_nSlotId,
3414                         m_xFrame,
3415                         MenuOrToolMenuButton(this, pToolBox, nId),
3416                         [this] { return GetParentFrame(); },
3417                         m_aColorSelectFunction);
3418 
3419     if ( m_bSplitButton )
3420         xPopover->SetSelectedHdl( LINK( this, SvxColorToolBoxControl, SelectedHdl ) );
3421 
3422     mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
3423         std::move(xPopover), true);
3424 
3425     auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(m_aCommandURL, m_sModuleName);
3426     OUString aWindowTitle = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
3427     mxInterimPopover->SetText(aWindowTitle);
3428 
3429     mxInterimPopover->Show();
3430 
3431     return mxInterimPopover;
3432 }
3433 
3434 IMPL_LINK(SvxColorToolBoxControl, SelectedHdl, const NamedColor&, rColor, void)
3435 {
3436     m_xBtnUpdater->Update(rColor);
3437 }
3438 
3439 void SvxColorToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
3440 {
3441     ToolBox* pToolBox = nullptr;
3442     ToolBoxItemId nId;
3443     if (!getToolboxId(nId, &pToolBox) && !m_pToolbar)
3444         return;
3445 
3446     if ( rEvent.FeatureURL.Complete == m_aCommandURL )
3447     {
3448         if (m_pToolbar)
3449             m_pToolbar->set_item_sensitive(m_aCommandURL.toUtf8(), rEvent.IsEnabled);
3450         else
3451             pToolBox->EnableItem( nId, rEvent.IsEnabled );
3452     }
3453 
3454     bool bValue;
3455     if ( !m_bSplitButton )
3456     {
3457         m_aColorStatus.statusChanged( rEvent );
3458         m_xBtnUpdater->Update( m_aColorStatus.GetColor() );
3459     }
3460     else if ( rEvent.State >>= bValue )
3461     {
3462         if (m_pToolbar)
3463             m_pToolbar->set_item_active(m_aCommandURL.toUtf8(), bValue);
3464         else if (pToolBox)
3465             pToolBox->CheckItem( nId, bValue );
3466     }
3467 }
3468 
3469 void SvxColorToolBoxControl::execute(sal_Int16 /*nSelectModifier*/)
3470 {
3471     if ( !m_bSplitButton )
3472     {
3473         if (m_pToolbar)
3474         {
3475             // Toggle the popup also when toolbutton is activated
3476             const OString aId(m_aCommandURL.toUtf8());
3477             m_pToolbar->set_menu_item_active(aId, !m_pToolbar->get_menu_item_active(aId));
3478         }
3479         else
3480         {
3481             // Open the popup also when Enter key is pressed.
3482             createPopupWindow();
3483         }
3484         return;
3485     }
3486 
3487     OUString aCommand = m_aCommandURL;
3488     Color aColor = m_xBtnUpdater->GetCurrentColor();
3489 
3490     switch( m_nSlotId )
3491     {
3492         case SID_ATTR_CHAR_COLOR2 :
3493             aCommand    = ".uno:CharColorExt";
3494             break;
3495 
3496         case SID_ATTR_CHAR_COLOR_BACKGROUND :
3497             aCommand    = ".uno:CharBackgroundExt";
3498             break;
3499     }
3500 
3501     auto aArgs( comphelper::InitPropertySequence( {
3502         { m_aCommandURL.copy(5), css::uno::Any(aColor) }
3503     } ) );
3504     dispatchCommand( aCommand, aArgs );
3505 
3506     EnsurePaletteManager();
3507     OUString sColorName = m_xBtnUpdater->GetCurrentColorName();
3508     m_xPaletteManager->AddRecentColor(aColor, sColorName);
3509 }
3510 
3511 sal_Bool SvxColorToolBoxControl::opensSubToolbar()
3512 {
3513     // We mark this controller as a sub-toolbar controller, so we get notified
3514     // (through updateImage method) on button image changes, and could redraw
3515     // the last used color on top of it.
3516     return true;
3517 }
3518 
3519 void SvxColorToolBoxControl::updateImage()
3520 {
3521     m_xBtnUpdater->Update(m_xBtnUpdater->GetCurrentColor(), true);
3522 }
3523 
3524 OUString SvxColorToolBoxControl::getSubToolbarName()
3525 {
3526     return OUString();
3527 }
3528 
3529 void SvxColorToolBoxControl::functionSelected( const OUString& /*rCommand*/ )
3530 {
3531 }
3532 
3533 OUString SvxColorToolBoxControl::getImplementationName()
3534 {
3535     return "com.sun.star.comp.svx.ColorToolBoxControl";
3536 }
3537 
3538 css::uno::Sequence<OUString> SvxColorToolBoxControl::getSupportedServiceNames()
3539 {
3540     return { "com.sun.star.frame.ToolbarController" };
3541 }
3542 
3543 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3544 com_sun_star_comp_svx_ColorToolBoxControl_get_implementation(
3545     css::uno::XComponentContext* rContext,
3546     css::uno::Sequence<css::uno::Any> const & )
3547 {
3548     return cppu::acquire( new SvxColorToolBoxControl( rContext ) );
3549 }
3550 
3551 SvxFrameToolBoxControl::SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext )
3552     : svt::PopupWindowController( rContext, nullptr, OUString() )
3553 {
3554 }
3555 
3556 void SAL_CALL SvxFrameToolBoxControl::execute(sal_Int16 /*KeyModifier*/)
3557 {
3558     if (m_pToolbar)
3559     {
3560         // Toggle the popup also when toolbutton is activated
3561         const OString aId(m_aCommandURL.toUtf8());
3562         m_pToolbar->set_menu_item_active(aId, !m_pToolbar->get_menu_item_active(aId));
3563     }
3564     else
3565     {
3566         // Open the popup also when Enter key is pressed.
3567         createPopupWindow();
3568     }
3569 }
3570 
3571 void SvxFrameToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
3572 {
3573     svt::PopupWindowController::initialize( rArguments );
3574 
3575     if (m_pToolbar)
3576     {
3577         mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
3578         m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
3579     }
3580 
3581     ToolBox* pToolBox = nullptr;
3582     ToolBoxItemId nId;
3583     if (getToolboxId(nId, &pToolBox))
3584         pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
3585 }
3586 
3587 std::unique_ptr<WeldToolbarPopup> SvxFrameToolBoxControl::weldPopupWindow()
3588 {
3589     if ( m_aCommandURL == ".uno:LineStyle" )
3590         return std::make_unique<SvxLineWindow_Impl>(this, m_pToolbar);
3591     return std::make_unique<SvxFrameWindow_Impl>(this, m_pToolbar);
3592 }
3593 
3594 VclPtr<vcl::Window> SvxFrameToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
3595 {
3596     if ( m_aCommandURL == ".uno:LineStyle" )
3597     {
3598         mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
3599             std::make_unique<SvxLineWindow_Impl>(this, pParent->GetFrameWeld()));
3600 
3601         mxInterimPopover->Show();
3602 
3603         mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME_STYLE));
3604 
3605         return mxInterimPopover;
3606     }
3607 
3608     mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
3609         std::make_unique<SvxFrameWindow_Impl>(this, pParent->GetFrameWeld()));
3610 
3611     mxInterimPopover->Show();
3612 
3613     mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME));
3614 
3615     return mxInterimPopover;
3616 }
3617 
3618 OUString SvxFrameToolBoxControl::getImplementationName()
3619 {
3620     return "com.sun.star.comp.svx.FrameToolBoxControl";
3621 }
3622 
3623 css::uno::Sequence< OUString > SvxFrameToolBoxControl::getSupportedServiceNames()
3624 {
3625     return { "com.sun.star.frame.ToolbarController" };
3626 }
3627 
3628 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3629 com_sun_star_comp_svx_FrameToolBoxControl_get_implementation(
3630     css::uno::XComponentContext* rContext,
3631     css::uno::Sequence<css::uno::Any> const & )
3632 {
3633     return cppu::acquire( new SvxFrameToolBoxControl( rContext ) );
3634 }
3635 
3636 SvxCurrencyToolBoxControl::SvxCurrencyToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) :
3637     PopupWindowController( rContext, nullptr, OUString() ),
3638     m_eLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ),
3639     m_nFormatKey( NUMBERFORMAT_ENTRY_NOT_FOUND )
3640 {
3641 }
3642 
3643 SvxCurrencyToolBoxControl::~SvxCurrencyToolBoxControl() {}
3644 
3645 namespace
3646 {
3647     class SvxCurrencyList_Impl : public WeldToolbarPopup
3648     {
3649     private:
3650         rtl::Reference<SvxCurrencyToolBoxControl> m_xControl;
3651         std::unique_ptr<weld::Label> m_xLabel;
3652         std::unique_ptr<weld::TreeView> m_xCurrencyLb;
3653         std::unique_ptr<weld::Button> m_xOkBtn;
3654         OUString&       m_rSelectedFormat;
3655         LanguageType&   m_eSelectedLanguage;
3656 
3657         std::vector<OUString> m_aFormatEntries;
3658         LanguageType          m_eFormatLanguage;
3659         DECL_LINK(RowActivatedHdl, weld::TreeView&, bool);
3660         DECL_LINK(OKHdl, weld::Button&, void);
3661 
3662         virtual void GrabFocus() override;
3663 
3664     public:
3665         SvxCurrencyList_Impl(SvxCurrencyToolBoxControl* pControl, weld::Widget* pParent, OUString& rSelectedFormat, LanguageType& eSelectedLanguage)
3666             : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/currencywindow.ui", "CurrencyWindow")
3667             , m_xControl(pControl)
3668             , m_xLabel(m_xBuilder->weld_label("label"))
3669             , m_xCurrencyLb(m_xBuilder->weld_tree_view("currency"))
3670             , m_xOkBtn(m_xBuilder->weld_button("ok"))
3671             , m_rSelectedFormat(rSelectedFormat)
3672             , m_eSelectedLanguage(eSelectedLanguage)
3673         {
3674             std::vector< OUString > aList;
3675             std::vector< sal_uInt16 > aCurrencyList;
3676             const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
3677             sal_uInt16 nLen = rCurrencyTable.size();
3678 
3679             SvNumberFormatter aFormatter( m_xControl->getContext(), LANGUAGE_SYSTEM );
3680             m_eFormatLanguage = aFormatter.GetLanguage();
3681 
3682             SvxCurrencyToolBoxControl::GetCurrencySymbols( aList, true, aCurrencyList );
3683 
3684             sal_uInt16 nPos = 0, nCount = 0;
3685             sal_Int32 nSelectedPos = -1;
3686             bool bIsSymbol;
3687             NfWSStringsDtor aStringsDtor;
3688 
3689             OUString sLongestString;
3690 
3691             m_xCurrencyLb->freeze();
3692             for( const auto& rItem : aList )
3693             {
3694                 sal_uInt16& rCurrencyIndex = aCurrencyList[ nCount ];
3695                 if ( rCurrencyIndex < nLen )
3696                 {
3697                     m_xCurrencyLb->append_text(rItem);
3698 
3699                     if (rItem.getLength() > sLongestString.getLength())
3700                         sLongestString = rItem;
3701 
3702                     bIsSymbol = nPos >= nLen;
3703 
3704                     sal_uInt16 nDefaultFormat;
3705                     const NfCurrencyEntry& rCurrencyEntry = rCurrencyTable[ rCurrencyIndex ];
3706                     if (rCurrencyIndex == 0)
3707                     {
3708                         // Stored with system locale, but we want the resolved
3709                         // full LCID format string. For example
3710                         // "[$$-409]#,##0.00" instead of "[$$]#,##0.00".
3711                         NfCurrencyEntry aCurrencyEntry( rCurrencyEntry);
3712                         aCurrencyEntry.SetLanguage( LanguageTag( aCurrencyEntry.GetLanguage()).getLanguageType());
3713                         nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, aCurrencyEntry, bIsSymbol);
3714                     }
3715                     else
3716                     {
3717                         nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, rCurrencyEntry, bIsSymbol);
3718                     }
3719                     const OUString& rFormatStr = aStringsDtor[ nDefaultFormat ];
3720                     m_aFormatEntries.push_back( rFormatStr );
3721                     if( rFormatStr == m_rSelectedFormat )
3722                         nSelectedPos = nPos;
3723                     ++nPos;
3724                 }
3725                 ++nCount;
3726             }
3727             m_xCurrencyLb->thaw();
3728             // enable multiple selection enabled so we can start with nothing selected
3729             m_xCurrencyLb->set_selection_mode(SelectionMode::Multiple);
3730             m_xCurrencyLb->connect_row_activated( LINK( this, SvxCurrencyList_Impl, RowActivatedHdl ) );
3731             m_xLabel->set_label(SvxResId(RID_SVXSTR_TBLAFMT_CURRENCY));
3732             m_xCurrencyLb->select( nSelectedPos );
3733             m_xOkBtn->connect_clicked(LINK(this, SvxCurrencyList_Impl, OKHdl));
3734 
3735             // gtk will initially make a best guess depending on the first few entries, so copy the probable
3736             // longest entry to the start temporarily and force in the width at this point
3737             m_xCurrencyLb->insert_text(0, sLongestString);
3738             m_xCurrencyLb->set_size_request(m_xCurrencyLb->get_preferred_size().Width(), m_xCurrencyLb->get_height_rows(12));
3739             m_xCurrencyLb->remove(0);
3740         }
3741     };
3742 
3743     void SvxCurrencyList_Impl::GrabFocus()
3744     {
3745         m_xCurrencyLb->grab_focus();
3746     }
3747 
3748     IMPL_LINK_NOARG(SvxCurrencyList_Impl, OKHdl, weld::Button&, void)
3749     {
3750         RowActivatedHdl(*m_xCurrencyLb);
3751     }
3752 
3753     IMPL_LINK_NOARG(SvxCurrencyList_Impl, RowActivatedHdl, weld::TreeView&, bool)
3754     {
3755         if (!m_xControl.is())
3756             return true;
3757 
3758         // multiple selection enabled so we can start with nothing selected,
3759         // so force single selection after something is picked
3760         int nSelected = m_xCurrencyLb->get_selected_index();
3761         if (nSelected == -1)
3762             return true;
3763 
3764         m_xCurrencyLb->set_selection_mode(SelectionMode::Single);
3765 
3766         m_rSelectedFormat = m_aFormatEntries[nSelected];
3767         m_eSelectedLanguage = m_eFormatLanguage;
3768 
3769         m_xControl->execute(nSelected + 1);
3770 
3771         m_xControl->EndPopupMode();
3772 
3773         return true;
3774     }
3775 }
3776 
3777 void SvxCurrencyToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
3778 {
3779     PopupWindowController::initialize(rArguments);
3780 
3781     if (m_pToolbar)
3782     {
3783         mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
3784         m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
3785         return;
3786     }
3787 
3788     ToolBox* pToolBox = nullptr;
3789     ToolBoxItemId nId;
3790     if (getToolboxId(nId, &pToolBox) && pToolBox->GetItemCommand(nId) == m_aCommandURL)
3791         pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWN | pToolBox->GetItemBits(nId));
3792 }
3793 
3794 std::unique_ptr<WeldToolbarPopup> SvxCurrencyToolBoxControl::weldPopupWindow()
3795 {
3796     return std::make_unique<SvxCurrencyList_Impl>(this, m_pToolbar, m_aFormatString, m_eLanguage);
3797 }
3798 
3799 VclPtr<vcl::Window> SvxCurrencyToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
3800 {
3801     mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
3802         std::make_unique<SvxCurrencyList_Impl>(this, pParent->GetFrameWeld(), m_aFormatString, m_eLanguage));
3803 
3804     mxInterimPopover->Show();
3805 
3806     return mxInterimPopover;
3807 }
3808 
3809 void SvxCurrencyToolBoxControl::execute( sal_Int16 nSelectModifier )
3810 {
3811     sal_uInt32 nFormatKey;
3812     if (m_aFormatString.isEmpty())
3813         nFormatKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
3814     else
3815     {
3816         if ( nSelectModifier > 0 )
3817         {
3818             try
3819             {
3820                 uno::Reference< util::XNumberFormatsSupplier > xRef( m_xFrame->getController()->getModel(), uno::UNO_QUERY );
3821                 uno::Reference< util::XNumberFormats > rxNumberFormats( xRef->getNumberFormats(), uno::UNO_SET_THROW );
3822                 css::lang::Locale aLocale = LanguageTag::convertToLocale( m_eLanguage );
3823                 nFormatKey = rxNumberFormats->queryKey( m_aFormatString, aLocale, false );
3824                 if ( nFormatKey == NUMBERFORMAT_ENTRY_NOT_FOUND )
3825                     nFormatKey = rxNumberFormats->addNew( m_aFormatString, aLocale );
3826                 }
3827                 catch( const uno::Exception& )
3828                 {
3829                     nFormatKey = m_nFormatKey;
3830                 }
3831         }
3832         else
3833             nFormatKey = m_nFormatKey;
3834     }
3835 
3836     if( nFormatKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
3837     {
3838         Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("NumberFormatCurrency",
3839                                                                        nFormatKey) };
3840         dispatchCommand( m_aCommandURL, aArgs );
3841         m_nFormatKey = nFormatKey;
3842     }
3843     else
3844         PopupWindowController::execute( nSelectModifier );
3845 }
3846 
3847 OUString SvxCurrencyToolBoxControl::getImplementationName()
3848 {
3849     return "com.sun.star.comp.svx.CurrencyToolBoxControl";
3850 }
3851 
3852 css::uno::Sequence<OUString> SvxCurrencyToolBoxControl::getSupportedServiceNames()
3853 {
3854     return { "com.sun.star.frame.ToolbarController" };
3855 }
3856 
3857 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3858 com_sun_star_comp_svx_CurrencyToolBoxControl_get_implementation(
3859     css::uno::XComponentContext* rContext,
3860     css::uno::Sequence<css::uno::Any> const & )
3861 {
3862     return cppu::acquire( new SvxCurrencyToolBoxControl( rContext ) );
3863 }
3864 
3865 Reference< css::accessibility::XAccessible > SvxFontNameBox_Impl::CreateAccessible()
3866 {
3867     FillList();
3868     return InterimItemWindow::CreateAccessible();
3869 }
3870 
3871 //static
3872 void SvxCurrencyToolBoxControl::GetCurrencySymbols( std::vector<OUString>& rList, bool bFlag,
3873                                                     std::vector<sal_uInt16>& rCurrencyList )
3874 {
3875     rCurrencyList.clear();
3876 
3877     const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
3878     sal_uInt16 nCount = rCurrencyTable.size();
3879 
3880     sal_uInt16 nStart = 1;
3881 
3882     OUString aString( ApplyLreOrRleEmbedding( rCurrencyTable[0].GetSymbol() ) + " " );
3883     aString += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString(
3884                                        rCurrencyTable[0].GetLanguage() ) );
3885 
3886     rList.push_back( aString );
3887     rCurrencyList.push_back( sal_uInt16(-1) ); // nAuto
3888 
3889     if( bFlag )
3890     {
3891         rList.push_back( aString );
3892         rCurrencyList.push_back( 0 );
3893         ++nStart;
3894     }
3895 
3896     CollatorWrapper aCollator( ::comphelper::getProcessComponentContext() );
3897     aCollator.loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 );
3898 
3899     static const OUStringLiteral aTwoSpace(u"  ");
3900 
3901     for( sal_uInt16 i = 1; i < nCount; ++i )
3902     {
3903         OUString aStr( ApplyLreOrRleEmbedding( rCurrencyTable[i].GetBankSymbol() ) );
3904         aStr += aTwoSpace;
3905         aStr += ApplyLreOrRleEmbedding( rCurrencyTable[i].GetSymbol() );
3906         aStr += aTwoSpace;
3907         aStr += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString(
3908                                         rCurrencyTable[i].GetLanguage() ) );
3909 
3910         std::vector<OUString>::size_type j = nStart;
3911         for( ; j < rList.size(); ++j )
3912             if ( aCollator.compareString( aStr, rList[j] ) < 0 )
3913                 break;  // insert before first greater than
3914 
3915         rList.insert( rList.begin() + j, aStr );
3916         rCurrencyList.insert( rCurrencyList.begin() + j, i );
3917     }
3918 
3919     // Append ISO codes to symbol list.
3920     // XXX If this is to be changed, various other places would had to be
3921     // adapted that assume this order!
3922     std::vector<OUString>::size_type nCont = rList.size();
3923 
3924     for ( sal_uInt16 i = 1; i < nCount; ++i )
3925     {
3926         bool bInsert = true;
3927         OUString aStr( ApplyLreOrRleEmbedding( rCurrencyTable[i].GetBankSymbol() ) );
3928 
3929         std::vector<OUString>::size_type j = nCont;
3930         for ( ; j < rList.size() && bInsert; ++j )
3931         {
3932             if( rList[j] == aStr )
3933                 bInsert = false;
3934             else if ( aCollator.compareString( aStr, rList[j] ) < 0 )
3935                 break;  // insert before first greater than
3936         }
3937         if ( bInsert )
3938         {
3939             rList.insert( rList.begin() + j, aStr );
3940             rCurrencyList.insert( rCurrencyList.begin() + j, i );
3941         }
3942     }
3943 }
3944 
3945 ListBoxColorWrapper::ListBoxColorWrapper(ColorListBox* pControl)
3946     : mpControl(pControl)
3947 {
3948 }
3949 
3950 void ListBoxColorWrapper::operator()(
3951     [[maybe_unused]] const OUString& /*rCommand*/, const svx::NamedThemedColor& rColor)
3952 {
3953     mpControl->Selected(rColor);
3954 }
3955 
3956 void ColorListBox::EnsurePaletteManager()
3957 {
3958     if (!m_xPaletteManager)
3959     {
3960         m_xPaletteManager = std::make_shared<PaletteManager>();
3961         m_xPaletteManager->SetColorSelectFunction(std::ref(m_aColorWrapper));
3962     }
3963 }
3964 
3965 void ColorListBox::SetSlotId(sal_uInt16 nSlotId, bool bShowNoneButton)
3966 {
3967     m_nSlotId = nSlotId;
3968     m_bShowNoneButton = bShowNoneButton;
3969     m_xButton->set_popover(nullptr);
3970     m_xColorWindow.reset();
3971     m_aSelectedColor = svx::NamedThemedColor::FromNamedColor(bShowNoneButton ? GetNoneColor() : GetAutoColor(m_nSlotId));
3972     ShowPreview(m_aSelectedColor.ToNamedColor());
3973     createColorWindow();
3974 }
3975 
3976 ColorListBox::ColorListBox(std::unique_ptr<weld::MenuButton> pControl, TopLevelParentFunction const& rTopLevelParentFunction)
3977     : m_xButton(std::move(pControl))
3978     , m_aColorWrapper(this)
3979     , m_aAutoDisplayColor(Application::GetSettings().GetStyleSettings().GetDialogColor())
3980     , m_nSlotId(0)
3981     , m_bShowNoneButton(false)
3982     , m_aTopLevelParentFunction(rTopLevelParentFunction)
3983 {
3984     m_xButton->connect_toggled(LINK(this, ColorListBox, ToggleHdl));
3985     m_aSelectedColor = svx::NamedThemedColor::FromNamedColor(GetAutoColor(m_nSlotId));
3986     LockWidthRequest();
3987     ShowPreview(m_aSelectedColor.ToNamedColor());
3988 }
3989 
3990 IMPL_LINK(ColorListBox, ToggleHdl, weld::Toggleable&, rButton, void)
3991 {
3992     if (rButton.get_active())
3993     {
3994         ColorWindow* pColorWindow = getColorWindow();
3995         if (pColorWindow && !comphelper::LibreOfficeKit::isActive())
3996             pColorWindow->GrabFocus();
3997     }
3998 }
3999 
4000 ColorListBox::~ColorListBox()
4001 {
4002 }
4003 
4004 ColorWindow* ColorListBox::getColorWindow() const
4005 {
4006     if (!m_xColorWindow)
4007         const_cast<ColorListBox*>(this)->createColorWindow();
4008     return m_xColorWindow.get();
4009 }
4010 
4011 void ColorListBox::createColorWindow()
4012 {
4013     const SfxViewFrame* pViewFrame = SfxViewFrame::Current();
4014     const SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
4015     css::uno::Reference<css::frame::XFrame> xFrame(pFrame ? pFrame->GetFrameInterface() : uno::Reference<css::frame::XFrame>());
4016 
4017     EnsurePaletteManager();
4018 
4019     m_xColorWindow.reset(new ColorWindow(
4020                             OUString() /*m_aCommandURL*/,
4021                             m_xPaletteManager,
4022                             m_aColorStatus,
4023                             m_nSlotId,
4024                             xFrame,
4025                             m_xButton.get(),
4026                             m_aTopLevelParentFunction,
4027                             m_aColorWrapper));
4028 
4029     SetNoSelection();
4030     m_xButton->set_popover(m_xColorWindow->getTopLevel());
4031     if (m_bShowNoneButton)
4032         m_xColorWindow->ShowNoneButton();
4033     m_xColorWindow->SelectEntry(m_aSelectedColor.ToNamedColor());
4034 }
4035 
4036 void ColorListBox::SelectEntry(const NamedColor& rColor)
4037 {
4038     if (rColor.second.trim().isEmpty())
4039     {
4040         SelectEntry(rColor.first);
4041         return;
4042     }
4043     ColorWindow* pColorWindow = getColorWindow();
4044     pColorWindow->SelectEntry(rColor);
4045     m_aSelectedColor = svx::NamedThemedColor::FromNamedColor(pColorWindow->GetSelectEntryColor());
4046     ShowPreview(m_aSelectedColor.ToNamedColor());
4047 }
4048 
4049 void ColorListBox::SelectEntry(const Color& rColor)
4050 {
4051     ColorWindow* pColorWindow = getColorWindow();
4052     pColorWindow->SelectEntry(rColor);
4053     m_aSelectedColor = svx::NamedThemedColor::FromNamedColor(pColorWindow->GetSelectEntryColor());
4054     ShowPreview(m_aSelectedColor.ToNamedColor());
4055 }
4056 
4057 void ColorListBox::Selected(const svx::NamedThemedColor& rColor)
4058 {
4059     ShowPreview(rColor.ToNamedColor());
4060     m_aSelectedColor = rColor;
4061     if (m_aSelectedLink.IsSet())
4062         m_aSelectedLink.Call(*this);
4063 }
4064 
4065 //to avoid the box resizing every time the color is changed to
4066 //the optimal size of the individual color, get the longest
4067 //standard color and stick with that as the size for all
4068 void ColorListBox::LockWidthRequest()
4069 {
4070     NamedColor aLongestColor;
4071     tools::Long nMaxStandardColorTextWidth = 0;
4072     XColorListRef const xColorTable = XColorList::CreateStdColorList();
4073     for (tools::Long i = 0; i != xColorTable->Count(); ++i)
4074     {
4075         XColorEntry& rEntry = *xColorTable->GetColor(i);
4076         auto nColorTextWidth = m_xButton->get_pixel_size(rEntry.GetName()).Width();
4077         if (nColorTextWidth > nMaxStandardColorTextWidth)
4078         {
4079             nMaxStandardColorTextWidth = nColorTextWidth;
4080             aLongestColor.second = rEntry.GetName();
4081         }
4082     }
4083     ShowPreview(aLongestColor);
4084     m_xButton->set_size_request(m_xButton->get_preferred_size().Width(), -1);
4085 }
4086 
4087 void ColorListBox::ShowPreview(const NamedColor &rColor)
4088 {
4089     // ScGridWindow::UpdateAutoFilterFromMenu is similar
4090     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
4091     Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
4092 
4093     ScopedVclPtrInstance<VirtualDevice> xDevice;
4094     xDevice->SetOutputSize(aImageSize);
4095     const tools::Rectangle aRect(Point(0, 0), aImageSize);
4096     if (m_bShowNoneButton && rColor.first == COL_NONE_COLOR)
4097     {
4098         const Color aW(COL_WHITE);
4099         const Color aG(0xef, 0xef, 0xef);
4100         int nMinDim = std::min(aImageSize.Width(), aImageSize.Height()) + 1;
4101         int nCheckSize = nMinDim / 3;
4102         xDevice->DrawCheckered(aRect.TopLeft(), aRect.GetSize(), std::min(nCheckSize, 8), aW, aG);
4103         xDevice->SetFillColor();
4104     }
4105     else
4106     {
4107         if (rColor.first == COL_AUTO)
4108             xDevice->SetFillColor(m_aAutoDisplayColor);
4109         else
4110             xDevice->SetFillColor(rColor.first);
4111     }
4112 
4113     xDevice->SetLineColor(rStyleSettings.GetDisableColor());
4114     xDevice->DrawRect(aRect);
4115 
4116     m_xButton->set_image(xDevice.get());
4117     m_xButton->set_label(rColor.second);
4118 }
4119 
4120 MenuOrToolMenuButton::MenuOrToolMenuButton(weld::MenuButton* pMenuButton)
4121     : m_pMenuButton(pMenuButton)
4122     , m_pToolbar(nullptr)
4123     , m_pControl(nullptr)
4124     , m_nId(0)
4125 {
4126 }
4127 
4128 MenuOrToolMenuButton::MenuOrToolMenuButton(weld::Toolbar* pToolbar, const OString& rIdent)
4129     : m_pMenuButton(nullptr)
4130     , m_pToolbar(pToolbar)
4131     , m_aIdent(rIdent)
4132     , m_pControl(nullptr)
4133     , m_nId(0)
4134 {
4135 }
4136 
4137 MenuOrToolMenuButton::MenuOrToolMenuButton(SvxColorToolBoxControl* pControl, ToolBox* pToolbar, ToolBoxItemId nId)
4138     : m_pMenuButton(nullptr)
4139     , m_pToolbar(nullptr)
4140     , m_pControl(pControl)
4141     , m_xToolBox(pToolbar)
4142     , m_nId(nId)
4143 {
4144 }
4145 
4146 MenuOrToolMenuButton::~MenuOrToolMenuButton()
4147 {
4148 }
4149 
4150 bool MenuOrToolMenuButton::get_active() const
4151 {
4152     if (m_pMenuButton)
4153         return m_pMenuButton->get_active();
4154     if (m_pToolbar)
4155         return m_pToolbar->get_menu_item_active(m_aIdent);
4156     return m_xToolBox->GetDownItemId() == m_nId;
4157 }
4158 
4159 void MenuOrToolMenuButton::set_inactive() const
4160 {
4161     if (m_pMenuButton)
4162     {
4163         if (m_pMenuButton->get_active())
4164             m_pMenuButton->set_active(false);
4165         return;
4166     }
4167     if (m_pToolbar)
4168     {
4169         if (m_pToolbar->get_menu_item_active(m_aIdent))
4170             m_pToolbar->set_menu_item_active(m_aIdent, false);
4171         return;
4172     }
4173     m_pControl->EndPopupMode();
4174 }
4175 
4176 weld::Widget* MenuOrToolMenuButton::get_widget() const
4177 {
4178     if (m_pMenuButton)
4179         return m_pMenuButton;
4180     if (m_pToolbar)
4181         return m_pToolbar;
4182     return m_xToolBox->GetFrameWeld();
4183 }
4184 
4185 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4186