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