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