Version 24.2.2.2, tag libreoffice-24.2.2.2
[LibreOffice.git] / svx / source / tbxctrls / tbcontrl.cxx
blob9a3669aac56ae6e9ab1591d7fc1dbaf2f796588b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <utility>
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>
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 <cppu/unotype.hxx>
97 #include <cppuhelper/supportsservice.hxx>
98 #include <officecfg/Office/Common.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>
106 #include <comphelper/lok.hxx>
107 #include <tools/json_writer.hxx>
109 #include <editeng/editeng.hxx>
111 #define MAX_MRU_FONTNAME_ENTRIES 5
113 #define COMBO_WIDTH_IN_CHARS 18
115 #define MAX_MRU_CURRENCIES 5
117 #define INVALID_CURRENCY sal_uInt16(-2)
119 // namespaces
120 using namespace ::editeng;
121 using namespace ::com::sun::star;
122 using namespace ::com::sun::star::uno;
123 using namespace ::com::sun::star::frame;
124 using namespace ::com::sun::star::beans;
125 using namespace ::com::sun::star::lang;
127 namespace
129 struct ScriptInfo
131 tools::Long textWidth;
132 SvtScriptType scriptType;
133 sal_Int32 changePos;
134 ScriptInfo(SvtScriptType scrptType, sal_Int32 position)
135 : textWidth(0)
136 , scriptType(scrptType)
137 , changePos(position)
142 class SvxStyleBox_Base
144 public:
145 SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget, OUString rCommand, SfxStyleFamily eFamily,
146 const Reference<XFrame>& _xFrame, OUString aClearFormatKey,
147 OUString aMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl);
149 virtual ~SvxStyleBox_Base()
153 void SetFamily( SfxStyleFamily eNewFamily );
155 void SetDefaultStyle( const OUString& rDefault ) { sDefaultStyle = rDefault; }
157 int get_count() const { return m_xWidget->get_count(); }
158 OUString get_text(int nIndex) const { return m_xWidget->get_text(nIndex); }
159 OUString get_active_text() const { return m_xWidget->get_active_text(); }
161 void append_text(const OUString& rStr)
163 OUString sId(OUString::number(m_xWidget->get_count()));
164 m_xWidget->append(sId, rStr);
167 void insert_separator(int pos, const OUString& rId)
169 m_xWidget->insert_separator(pos, rId);
172 void set_active_or_entry_text(const OUString& rText)
174 const int nFound = m_xWidget->find_text(rText);
175 if (nFound != -1)
176 m_xWidget->set_active(nFound);
177 else
178 m_xWidget->set_entry_text(rText);
181 void set_active(int nActive)
183 m_xWidget->set_active(nActive);
186 void freeze()
188 m_xWidget->freeze();
191 void save_value()
193 m_xWidget->save_value();
196 void clear()
198 m_xWidget->clear();
199 m_nMaxUserDrawFontWidth = 0;
202 void thaw()
204 m_xWidget->thaw();
207 virtual bool DoKeyInput(const KeyEvent& rKEvt);
209 private:
210 std::optional<SvxFont> m_oFont;
211 std::optional<SvxFont> m_oCJKFont;
212 std::optional<SvxFont> m_oCTLFont;
214 DECL_LINK(SelectHdl, weld::ComboBox&, void);
215 DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
216 DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
217 DECL_LINK(FocusOutHdl, weld::Widget&, void);
218 DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void);
219 DECL_LINK(CustomRenderHdl, weld::ComboBox::render_args, void);
220 DECL_LINK(CustomGetSizeHdl, OutputDevice&, Size);
222 /// Calculate the optimal width of the dropdown. Very expensive operation, triggers lots of font measurement.
223 void CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext);
225 void Select(bool bNonTravelSelect);
227 tools::Rectangle CalcBoundRect(vcl::RenderContext& rRenderContext, const OUString &rStyleName, std::vector<ScriptInfo>& rScriptChanges, double fRatio = 1);
229 protected:
230 SvxStyleToolBoxControl& m_rCtrl;
232 std::unique_ptr<weld::Builder> m_xMenuBuilder;
233 std::unique_ptr<weld::Menu> m_xMenu;
234 std::unique_ptr<weld::ComboBox> m_xWidget;
236 SfxStyleFamily eStyleFamily;
237 int m_nMaxUserDrawFontWidth;
238 int m_nLastItemWithMenu;
239 bool bRelease;
240 Reference< XFrame > m_xFrame;
241 OUString m_aCommand;
242 OUString aClearFormatKey;
243 OUString aMoreKey;
244 OUString sDefaultStyle;
245 bool bInSpecialMode;
247 void ReleaseFocus();
248 static Color TestColorsVisible(const Color &FontCol, const Color &BackCol);
249 void UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const tools::Rectangle& rTextRect, const OUString &rStyleName, const std::vector<ScriptInfo>& rScriptChanges);
250 void SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected);
251 DECL_LINK(MenuSelectHdl, const OUString&, void);
252 DECL_STATIC_LINK(SvxStyleBox_Base, ShowMoreHdl, void*, void);
255 class SvxStyleBox_Impl final : public InterimItemWindow
256 , public SvxStyleBox_Base
258 public:
259 SvxStyleBox_Impl(vcl::Window* pParent, const OUString& rCommand, SfxStyleFamily eFamily,
260 const Reference< XFrame >& _xFrame,const OUString& rClearFormatKey, const OUString& rMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl);
262 virtual ~SvxStyleBox_Impl() override
264 disposeOnce();
267 virtual void dispose() override
269 m_xWidget.reset();
270 m_xMenu.reset();
271 m_xMenuBuilder.reset();
272 InterimItemWindow::dispose();
275 virtual bool DoKeyInput(const KeyEvent& rKEvt) override;
277 private:
279 virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
280 void SetOptimalSize();
283 class SvxFontNameBox_Impl;
284 class SvxFontNameBox_Base;
286 class SvxFontNameToolBoxControl final : public cppu::ImplInheritanceHelper<svt::ToolboxController,
287 css::lang::XServiceInfo>
289 public:
290 SvxFontNameToolBoxControl();
292 // XStatusListener
293 virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
295 // XToolbarController
296 virtual css::uno::Reference<css::awt::XWindow> SAL_CALL createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent) override;
298 // XComponent
299 virtual void SAL_CALL dispose() override;
301 // XServiceInfo
302 virtual OUString SAL_CALL getImplementationName() override;
303 virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
304 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
306 private:
307 VclPtr<SvxFontNameBox_Impl> m_xVclBox;
308 std::unique_ptr<SvxFontNameBox_Base> m_xWeldBox;
309 SvxFontNameBox_Base* m_pBox;
312 class FontOptionsListener final : public comphelper::ConfigurationListenerProperty<bool>
314 private:
315 SvxFontNameBox_Base& m_rBox;
317 virtual void setProperty(const css::uno::Any &rProperty) override;
318 public:
319 FontOptionsListener(const rtl::Reference<comphelper::ConfigurationListener>& rListener, const OUString& rProp, SvxFontNameBox_Base& rBox)
320 : comphelper::ConfigurationListenerProperty<bool>(rListener, rProp)
321 , m_rBox(rBox)
326 class SvxFontNameBox_Base
328 private:
329 rtl::Reference<comphelper::ConfigurationListener> m_xListener;
330 FontOptionsListener m_aWYSIWYG;
331 FontOptionsListener m_aHistory;
333 protected:
334 SvxFontNameToolBoxControl& m_rCtrl;
336 std::unique_ptr<FontNameBox> m_xWidget;
337 const FontList* pFontList;
338 ::std::unique_ptr<FontList> m_aOwnFontList;
339 vcl::Font aCurFont;
340 sal_uInt16 nFtCount;
341 bool bRelease;
342 Reference< XFrame > m_xFrame;
343 bool mbCheckingUnknownFont;
344 bool mbDropDownActive;
346 void ReleaseFocus_Impl();
348 void Select(bool bNonTravelSelect);
350 void EndPreview()
352 Sequence< PropertyValue > aArgs;
353 const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
354 SfxToolBoxControl::Dispatch(xProvider, ".uno:CharEndPreviewFontName", aArgs);
357 bool CheckFontIsAvailable(std::u16string_view fontname);
358 void CheckAndMarkUnknownFont();
360 public:
361 SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget, const Reference<XFrame>& rFrame,
362 SvxFontNameToolBoxControl& rCtrl);
363 virtual ~SvxFontNameBox_Base()
365 m_xListener->dispose();
368 void FillList();
369 void Update( const css::awt::FontDescriptor* pFontDesc );
370 sal_uInt16 GetListCount() const { return nFtCount; }
371 void Clear() { m_xWidget->clear(); nFtCount = 0; }
372 void Fill( const FontList* pList )
374 m_xWidget->Fill(pList);
375 nFtCount = pList->GetFontNameCount();
378 void SetOwnFontList(::std::unique_ptr<FontList> && _aOwnFontList) { m_aOwnFontList = std::move(_aOwnFontList); }
380 virtual void set_sensitive(bool bSensitive)
382 m_xWidget->set_sensitive(bSensitive);
385 void set_active_or_entry_text(const OUString& rText);
387 void statusChanged_Impl(const css::frame::FeatureStateEvent& rEvent);
389 virtual bool DoKeyInput(const KeyEvent& rKEvt);
391 void EnableControls();
393 DECL_LINK(SelectHdl, weld::ComboBox&, void);
394 DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
395 DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
396 DECL_LINK(FocusInHdl, weld::Widget&, void);
397 DECL_LINK(FocusOutHdl, weld::Widget&, void);
398 DECL_LINK(PopupToggledHdl, weld::ComboBox&, void);
399 DECL_LINK(LivePreviewHdl, const FontMetric&, void);
400 DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void);
403 void FontOptionsListener::setProperty(const css::uno::Any &rProperty)
405 comphelper::ConfigurationListenerProperty<bool>::setProperty(rProperty);
406 m_rBox.EnableControls();
409 class SvxFontNameBox_Impl final : public InterimItemWindow
410 , public SvxFontNameBox_Base
412 private:
413 virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
414 virtual void GetFocus() override
416 if (m_xWidget)
417 m_xWidget->grab_focus();
418 InterimItemWindow::GetFocus();
421 void SetOptimalSize();
423 virtual bool DoKeyInput(const KeyEvent& rKEvt) override;
425 public:
426 SvxFontNameBox_Impl(vcl::Window* pParent,
427 const Reference<XFrame>& rFrame, SvxFontNameToolBoxControl& rCtrl);
429 virtual void dispose() override
431 m_xWidget.reset();
432 InterimItemWindow::dispose();
435 virtual ~SvxFontNameBox_Impl() override
437 disposeOnce();
440 virtual Reference< css::accessibility::XAccessible > CreateAccessible() override;
442 virtual void set_sensitive(bool bSensitive) override
444 m_xWidget->set_sensitive(bSensitive);
445 if (bSensitive)
446 InterimItemWindow::Enable();
447 else
448 InterimItemWindow::Disable();
453 // SelectHdl needs the Modifiers, get them in MouseButtonUp
454 class SvxFrmValueSet_Impl final : public ValueSet
456 private:
457 sal_uInt16 nModifier;
459 virtual bool MouseButtonUp(const MouseEvent& rMEvt) override
461 nModifier = rMEvt.GetModifier();
462 return ValueSet::MouseButtonUp(rMEvt);
465 public:
466 SvxFrmValueSet_Impl()
467 : ValueSet(nullptr)
468 , nModifier(0)
471 sal_uInt16 GetModifier() const {return nModifier;}
476 namespace {
478 class SvxFrameToolBoxControl;
480 class SvxFrameWindow_Impl final : public WeldToolbarPopup
482 private:
483 rtl::Reference<SvxFrameToolBoxControl> mxControl;
484 std::unique_ptr<SvxFrmValueSet_Impl> mxFrameSet;
485 std::unique_ptr<weld::CustomWeld> mxFrameSetWin;
486 std::vector<std::pair<BitmapEx, OUString>> aImgVec;
487 bool bParagraphMode;
488 bool m_bIsWriter;
490 void InitImageList();
491 void CalcSizeValueSet();
492 DECL_LINK( SelectHdl, ValueSet*, void );
494 void SetDiagonalDownBorder(const SvxLineItem& dDownLineItem);
495 void SetDiagonalUpBorder(const SvxLineItem& dUpLineItem);
497 public:
498 SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent);
499 virtual void GrabFocus() override
501 mxFrameSet->GrabFocus();
504 virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
507 class SvxFrameToolBoxControl : public svt::PopupWindowController
509 public:
510 explicit SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext );
512 // XInitialization
513 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) override;
515 // XServiceInfo
516 virtual OUString SAL_CALL getImplementationName() override;
517 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
519 virtual void SAL_CALL execute(sal_Int16 nKeyModifier) override;
520 private:
521 virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
522 virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
525 class LineListBox final : public ValueSet
527 public:
528 typedef Color (*ColorFunc)(Color);
529 typedef Color (*ColorDistFunc)(Color, Color);
531 LineListBox();
533 /** Set the width in Twips */
534 Size SetWidth( tools::Long nWidth )
536 tools::Long nOldWidth = m_nWidth;
537 m_nWidth = nWidth;
538 return UpdateEntries( nOldWidth );
541 void SetNone( const OUString& sNone )
543 m_sNone = sNone;
546 /** Insert a listbox entry with all widths in Twips. */
547 void InsertEntry(const BorderWidthImpl& rWidthImpl,
548 SvxBorderLineStyle nStyle, tools::Long nMinWidth = 0,
549 ColorFunc pColor1Fn = &sameColor,
550 ColorFunc pColor2Fn = &sameColor,
551 ColorDistFunc pColorDistFn = &sameDistColor);
553 SvxBorderLineStyle GetEntryStyle( sal_Int32 nPos ) const;
555 SvxBorderLineStyle GetSelectEntryStyle() const;
557 void SetSourceUnit( FieldUnit eNewUnit ) { eSourceUnit = eNewUnit; }
559 const Color& GetColor() const { return aColor; }
561 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
562 private:
564 void ImpGetLine(tools::Long nLine1, tools::Long nLine2, tools::Long nDistance,
565 Color nColor1, Color nColor2, Color nColorDist,
566 SvxBorderLineStyle nStyle, BitmapEx& rBmp);
568 void UpdatePaintLineColor(); // returns sal_True if maPaintCol has changed
570 Size UpdateEntries( tools::Long nOldWidth );
571 sal_Int32 GetStylePos( sal_Int32 nListPos, tools::Long nWidth );
573 const Color& GetPaintColor() const
575 return maPaintCol;
578 Color GetColorLine1( sal_Int32 nPos );
579 Color GetColorLine2( sal_Int32 nPos );
580 Color GetColorDist( sal_Int32 nPos );
582 LineListBox( const LineListBox& ) = delete;
583 LineListBox& operator =( const LineListBox& ) = delete;
585 std::vector<std::unique_ptr<ImpLineListData>> m_vLineList;
586 tools::Long m_nWidth;
587 OUString m_sNone;
588 ScopedVclPtr<VirtualDevice> aVirDev;
589 Size aTxtSize;
590 Color const aColor;
591 Color maPaintCol;
592 FieldUnit eSourceUnit;
595 SvxBorderLineStyle LineListBox::GetSelectEntryStyle() const
597 SvxBorderLineStyle nStyle = SvxBorderLineStyle::SOLID;
598 size_t nPos = GetSelectItemPos();
599 if (nPos != VALUESET_ITEM_NOTFOUND)
601 if (!m_sNone.isEmpty())
602 --nPos;
603 nStyle = GetEntryStyle( nPos );
606 return nStyle;
609 void LineListBox::ImpGetLine( tools::Long nLine1, tools::Long nLine2, tools::Long nDistance,
610 Color aColor1, Color aColor2, Color aColorDist,
611 SvxBorderLineStyle nStyle, BitmapEx& rBmp )
613 auto nMinWidth = GetDrawingArea()->get_ref_device().approximate_digit_width() * COMBO_WIDTH_IN_CHARS;
614 Size aSize(nMinWidth, aTxtSize.Height());
615 aSize.AdjustWidth( -(aTxtSize.Width()) );
616 aSize.AdjustWidth( -6 );
618 // SourceUnit to Twips
619 if ( eSourceUnit == FieldUnit::POINT )
621 nLine1 /= 5;
622 nLine2 /= 5;
623 nDistance /= 5;
626 // Paint the lines
627 aSize = aVirDev->PixelToLogic( aSize );
628 tools::Long nPix = aVirDev->PixelToLogic( Size( 0, 1 ) ).Height();
629 sal_uInt32 n1 = nLine1;
630 sal_uInt32 n2 = nLine2;
631 tools::Long nDist = nDistance;
632 n1 += nPix-1;
633 n1 -= n1%nPix;
634 if ( n2 )
636 nDist += nPix-1;
637 nDist -= nDist%nPix;
638 n2 += nPix-1;
639 n2 -= n2%nPix;
641 tools::Long nVirHeight = n1+nDist+n2;
642 if ( nVirHeight > aSize.Height() )
643 aSize.setHeight( nVirHeight );
644 // negative width should not be drawn
645 if ( aSize.Width() <= 0 )
646 return;
648 Size aVirSize = aVirDev->LogicToPixel( aSize );
649 if ( aVirDev->GetOutputSizePixel() != aVirSize )
650 aVirDev->SetOutputSizePixel( aVirSize );
651 aVirDev->SetFillColor( aColorDist );
652 aVirDev->DrawRect( tools::Rectangle( Point(), aSize ) );
654 aVirDev->SetFillColor( aColor1 );
656 double y1 = double( n1 ) / 2;
657 svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle );
659 if ( n2 )
661 double y2 = n1 + nDist + double( n2 ) / 2;
662 aVirDev->SetFillColor( aColor2 );
663 svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, SvxBorderLineStyle::SOLID );
665 rBmp = aVirDev->GetBitmapEx( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
668 LineListBox::LineListBox()
669 : ValueSet(nullptr)
670 , m_nWidth( 5 )
671 , aVirDev(VclPtr<VirtualDevice>::Create())
672 , aColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor())
673 , maPaintCol(COL_BLACK)
674 , eSourceUnit(FieldUnit::POINT)
676 aVirDev->SetLineColor();
677 aVirDev->SetMapMode( MapMode( MapUnit::MapTwip ) );
680 void LineListBox::SetDrawingArea(weld::DrawingArea* pDrawingArea)
682 ValueSet::SetDrawingArea(pDrawingArea);
684 OutputDevice& rDevice = pDrawingArea->get_ref_device();
686 aTxtSize.setWidth( rDevice.approximate_digit_width() );
687 aTxtSize.setHeight( rDevice.GetTextHeight() );
689 UpdatePaintLineColor();
692 sal_Int32 LineListBox::GetStylePos( sal_Int32 nListPos, tools::Long nWidth )
694 sal_Int32 nPos = -1;
695 if (!m_sNone.isEmpty())
696 nListPos--;
698 sal_Int32 n = 0;
699 size_t i = 0;
700 size_t nCount = m_vLineList.size();
701 while ( nPos == -1 && i < nCount )
703 auto& pData = m_vLineList[ i ];
704 if ( pData->GetMinWidth() <= nWidth )
706 if ( nListPos == n )
707 nPos = static_cast<sal_Int32>(i);
708 n++;
710 i++;
713 return nPos;
716 void LineListBox::InsertEntry(
717 const BorderWidthImpl& rWidthImpl, SvxBorderLineStyle nStyle, tools::Long nMinWidth,
718 ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn )
720 m_vLineList.emplace_back(new ImpLineListData(
721 rWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn));
724 SvxBorderLineStyle LineListBox::GetEntryStyle( sal_Int32 nPos ) const
726 ImpLineListData* pData = (0 <= nPos && o3tl::make_unsigned(nPos) < m_vLineList.size()) ? m_vLineList[ nPos ].get() : nullptr;
727 return pData ? pData->GetStyle() : SvxBorderLineStyle::NONE;
730 void LineListBox::UpdatePaintLineColor()
732 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
733 Color aNewCol( rSettings.GetWindowColor().IsDark()? rSettings.GetLabelTextColor() : aColor );
735 bool bRet = aNewCol != maPaintCol;
737 if( bRet )
738 maPaintCol = aNewCol;
741 Size LineListBox::UpdateEntries( tools::Long nOldWidth )
743 Size aSize;
745 UpdatePaintLineColor( );
747 sal_Int32 nSelEntry = GetSelectItemPos();
748 sal_Int32 nTypePos = GetStylePos( nSelEntry, nOldWidth );
750 // Remove the old entries
751 Clear();
753 sal_uInt16 nId(1);
755 // Add the new entries based on the defined width
756 if (!m_sNone.isEmpty())
757 InsertItem(nId++, Image(), m_sNone);
759 sal_uInt16 n = 0;
760 sal_uInt16 nCount = m_vLineList.size( );
761 while ( n < nCount )
763 auto& pData = m_vLineList[ n ];
764 if ( pData->GetMinWidth() <= m_nWidth )
766 BitmapEx aBmp;
767 ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
768 pData->GetLine2ForWidth( m_nWidth ),
769 pData->GetDistForWidth( m_nWidth ),
770 GetColorLine1( GetItemCount( ) ),
771 GetColorLine2( GetItemCount( ) ),
772 GetColorDist( GetItemCount( ) ),
773 pData->GetStyle(), aBmp );
774 InsertItem(nId, Image(aBmp), SvtLineListBox::GetLineStyleName(pData->GetStyle()));
775 Size aBmpSize = aBmp.GetSizePixel();
776 if (aBmpSize.Width() > aSize.Width())
777 aSize.setWidth(aBmpSize.getWidth());
778 if (aBmpSize.Height() > aSize.Height())
779 aSize.setHeight(aBmpSize.getHeight());
780 if ( n == nTypePos )
781 SelectItem(nId);
783 else if ( n == nTypePos )
784 SetNoSelection();
785 n++;
786 ++nId;
789 Invalidate();
791 return aSize;
794 Color LineListBox::GetColorLine1( sal_Int32 nPos )
796 sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
797 if (nStyle == -1)
798 return GetPaintColor( );
799 auto& pData = m_vLineList[ nStyle ];
800 return pData->GetColorLine1( GetColor( ) );
803 Color LineListBox::GetColorLine2( sal_Int32 nPos )
805 sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
806 if (nStyle == -1)
807 return GetPaintColor( );
808 auto& pData = m_vLineList[ nStyle ];
809 return pData->GetColorLine2( GetColor( ) );
812 Color LineListBox::GetColorDist( sal_Int32 nPos )
814 Color rResult = Application::GetSettings().GetStyleSettings().GetFieldColor();
816 sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
817 if (nStyle == -1)
818 return rResult;
819 auto& pData = m_vLineList[ nStyle ];
820 return pData->GetColorDist( GetColor( ), rResult );
824 namespace {
826 class SvxLineWindow_Impl final : public WeldToolbarPopup
828 private:
829 rtl::Reference<SvxFrameToolBoxControl> m_xControl;
830 std::unique_ptr<LineListBox> m_xLineStyleLb;
831 std::unique_ptr<weld::CustomWeld> m_xLineStyleLbWin;
832 bool m_bIsWriter;
834 DECL_LINK( SelectHdl, ValueSet*, void );
836 public:
837 SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent);
838 virtual void GrabFocus() override
840 m_xLineStyleLb->GrabFocus();
846 class SvxStyleToolBoxControl;
848 class SfxStyleControllerItem_Impl : public SfxStatusListener
850 public:
851 SfxStyleControllerItem_Impl( const Reference< XDispatchProvider >& rDispatchProvider,
852 sal_uInt16 nSlotId,
853 const OUString& rCommand,
854 SvxStyleToolBoxControl& rTbxCtl );
856 protected:
857 virtual void StateChangedAtStatusListener( SfxItemState eState, const SfxPoolItem* pState ) override;
859 private:
860 SvxStyleToolBoxControl& rControl;
863 #define BUTTON_PADDING 10
864 #define ITEM_HEIGHT 30
866 SvxStyleBox_Base::SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
867 OUString aCommand,
868 SfxStyleFamily eFamily,
869 const Reference< XFrame >& _xFrame,
870 OUString _aClearFormatKey,
871 OUString _aMoreKey,
872 bool bInSpec, SvxStyleToolBoxControl& rCtrl)
873 : m_rCtrl(rCtrl)
874 , m_xMenuBuilder(Application::CreateBuilder(nullptr, "svx/ui/stylemenu.ui"))
875 , m_xMenu(m_xMenuBuilder->weld_menu("menu"))
876 , m_xWidget(std::move(xWidget))
877 , eStyleFamily( eFamily )
878 , m_nMaxUserDrawFontWidth(0)
879 , m_nLastItemWithMenu(-1)
880 , bRelease( true )
881 , m_xFrame(_xFrame)
882 , m_aCommand(std::move( aCommand ))
883 , aClearFormatKey(std::move( _aClearFormatKey ))
884 , aMoreKey(std::move( _aMoreKey ))
885 , bInSpecialMode( bInSpec )
887 m_xWidget->connect_changed(LINK(this, SvxStyleBox_Base, SelectHdl));
888 m_xWidget->connect_key_press(LINK(this, SvxStyleBox_Base, KeyInputHdl));
889 m_xWidget->connect_entry_activate(LINK(this, SvxStyleBox_Base, ActivateHdl));
890 m_xWidget->connect_focus_out(LINK(this, SvxStyleBox_Base, FocusOutHdl));
891 m_xWidget->connect_get_property_tree(LINK(this, SvxStyleBox_Base, DumpAsPropertyTreeHdl));
892 m_xWidget->set_help_id(HID_STYLE_LISTBOX);
893 m_xWidget->set_entry_completion(true);
894 m_xMenu->connect_activate(LINK(this, SvxStyleBox_Base, MenuSelectHdl));
896 m_xWidget->connect_custom_get_size(LINK(this, SvxStyleBox_Base, CustomGetSizeHdl));
897 m_xWidget->connect_custom_render(LINK(this, SvxStyleBox_Base, CustomRenderHdl));
898 m_xWidget->set_custom_renderer(true);
900 m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 3);
903 IMPL_LINK(SvxStyleBox_Base, CustomGetSizeHdl, OutputDevice&, rArg, Size)
905 CalcOptimalExtraUserWidth(rArg);
906 if (comphelper::LibreOfficeKit::isActive())
907 return Size(m_nMaxUserDrawFontWidth * rArg.GetDPIX() / 96, ITEM_HEIGHT * rArg.GetDPIY() / 96);
908 return Size(m_nMaxUserDrawFontWidth, ITEM_HEIGHT);
911 SvxStyleBox_Impl::SvxStyleBox_Impl(vcl::Window* pParent,
912 const OUString& rCommand,
913 SfxStyleFamily eFamily,
914 const Reference< XFrame >& _xFrame,
915 const OUString& rClearFormatKey,
916 const OUString& rMoreKey,
917 bool bInSpec, SvxStyleToolBoxControl& rCtrl)
918 : InterimItemWindow(pParent, "svx/ui/applystylebox.ui", "ApplyStyleBox")
919 , SvxStyleBox_Base(m_xBuilder->weld_combo_box("applystyle"), rCommand, eFamily, _xFrame,
920 rClearFormatKey, rMoreKey, bInSpec, rCtrl)
922 InitControlBase(m_xWidget.get());
924 set_id("applystyle");
925 SetOptimalSize();
928 void SvxStyleBox_Base::ReleaseFocus()
930 if ( !bRelease )
932 bRelease = true;
933 return;
935 if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() )
936 m_xFrame->getContainerWindow()->setFocus();
939 IMPL_LINK(SvxStyleBox_Base, MenuSelectHdl, const OUString&, rMenuIdent, void)
941 if (m_nLastItemWithMenu < 0 || m_nLastItemWithMenu >= m_xWidget->get_count())
942 return;
944 OUString sEntry = m_xWidget->get_text(m_nLastItemWithMenu);
946 ReleaseFocus(); // It must be after getting entry pos!
947 Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("Param", sEntry),
948 comphelper::makePropertyValue("Family",
949 sal_Int16( eStyleFamily )) };
951 const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
952 if (rMenuIdent == "update")
954 SfxToolBoxControl::Dispatch(xProvider, ".uno:StyleUpdateByExample", aArgs);
956 else if (rMenuIdent == "edit")
958 SfxToolBoxControl::Dispatch(xProvider, ".uno:EditStyle", aArgs);
962 IMPL_STATIC_LINK_NOARG(SvxStyleBox_Base, ShowMoreHdl, void*, void)
964 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
965 DBG_ASSERT( pViewFrm, "SvxStyleBox_Base::Select(): no viewframe" );
966 if (!pViewFrm)
967 return;
968 pViewFrm->ShowChildWindow(SID_SIDEBAR);
969 ::sfx2::sidebar::Sidebar::ShowPanel(u"StyleListPanel", pViewFrm->GetFrame().GetFrameInterface(), true);
972 IMPL_LINK(SvxStyleBox_Base, SelectHdl, weld::ComboBox&, rCombo, void)
974 Select(rCombo.changed_by_direct_pick()); // only when picked from the list
977 IMPL_LINK_NOARG(SvxStyleBox_Base, ActivateHdl, weld::ComboBox&, bool)
979 Select(true);
980 return true;
983 void SvxStyleBox_Base::Select(bool bNonTravelSelect)
985 if (!bNonTravelSelect)
986 return;
988 OUString aSearchEntry(m_xWidget->get_active_text());
989 bool bDoIt = true, bClear = false;
990 if( bInSpecialMode )
992 if( aSearchEntry == aClearFormatKey && m_xWidget->get_active() == 0 )
994 aSearchEntry = sDefaultStyle;
995 bClear = true;
996 //not only apply default style but also call 'ClearFormatting'
997 Sequence< PropertyValue > aEmptyVals;
998 const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
999 SfxToolBoxControl::Dispatch(xProvider, ".uno:ResetAttributes", aEmptyVals);
1001 else if (aSearchEntry == aMoreKey && m_xWidget->get_active() == (m_xWidget->get_count() - 1))
1003 Application::PostUserEvent(LINK(nullptr, SvxStyleBox_Base, ShowMoreHdl));
1004 //tdf#113214 change text back to previous entry
1005 set_active_or_entry_text(m_xWidget->get_saved_value());
1006 bDoIt = false;
1010 //Do we need to create a new style?
1011 SfxObjectShell *pShell = SfxObjectShell::Current();
1012 if (!pShell)
1013 return;
1015 SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
1016 SfxStyleSheetBase* pStyle = nullptr;
1018 bool bCreateNew = false;
1020 if ( pPool )
1022 pStyle = pPool->First(eStyleFamily);
1023 while ( pStyle && pStyle->GetName() != aSearchEntry )
1024 pStyle = pPool->Next();
1027 if ( !pStyle )
1029 // cannot find the style for whatever reason
1030 // therefore create a new style
1031 bCreateNew = true;
1034 /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
1035 This instance may be deleted in the meantime (i.e. when a dialog is opened
1036 while in Dispatch()), accessing members will crash in this case. */
1037 ReleaseFocus();
1039 if( !bDoIt )
1040 return;
1042 if ( bClear )
1043 set_active_or_entry_text(aSearchEntry);
1044 m_xWidget->save_value();
1046 Sequence< PropertyValue > aArgs( 2 );
1047 auto pArgs = aArgs.getArray();
1048 pArgs[0].Value <<= aSearchEntry;
1049 pArgs[1].Name = "Family";
1050 pArgs[1].Value <<= sal_Int16( eStyleFamily );
1052 const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
1053 if( bCreateNew )
1055 pArgs[0].Name = "Param";
1056 SfxToolBoxControl::Dispatch(xProvider, ".uno:StyleNewByExample", aArgs);
1058 else
1060 pArgs[0].Name = "Template";
1061 SfxToolBoxControl::Dispatch(xProvider, m_aCommand, aArgs);
1065 void SvxStyleBox_Base::SetFamily( SfxStyleFamily eNewFamily )
1067 eStyleFamily = eNewFamily;
1070 IMPL_LINK_NOARG(SvxStyleBox_Base, FocusOutHdl, weld::Widget&, void)
1072 if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
1073 set_active_or_entry_text(m_xWidget->get_saved_value());
1076 IMPL_LINK(SvxStyleBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool)
1078 return DoKeyInput(rKEvt);
1081 bool SvxStyleBox_Base::DoKeyInput(const KeyEvent& rKEvt)
1083 bool bHandled = false;
1085 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1087 switch (nCode)
1089 case KEY_TAB:
1090 bRelease = false;
1091 Select(true);
1092 break;
1093 case KEY_ESCAPE:
1094 set_active_or_entry_text(m_xWidget->get_saved_value());
1095 if (!m_rCtrl.IsInSidebar())
1097 ReleaseFocus();
1098 bHandled = true;
1100 break;
1103 return bHandled;
1106 bool SvxStyleBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
1108 return SvxStyleBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt);
1111 void SvxStyleBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
1113 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1114 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1116 SetOptimalSize();
1119 InterimItemWindow::DataChanged( rDCEvt );
1122 void SvxStyleBox_Impl::SetOptimalSize()
1124 // set width in chars low so the size request will not be overridden
1125 m_xWidget->set_entry_width_chars(1);
1126 // tdf#132338 purely using this calculation to keep things their traditional width
1127 Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS + 3) * 4, 0), MapMode(MapUnit::MapAppFont)));
1128 m_xWidget->set_size_request(aSize.Width(), -1);
1130 SetSizePixel(get_preferred_size());
1133 namespace
1135 std::vector<ScriptInfo> CheckScript(const OUString &rStyleName)
1137 assert(!rStyleName.isEmpty()); // must have a preview text here!
1139 std::vector<ScriptInfo> aScriptChanges;
1141 auto aEditEngine = EditEngine(nullptr);
1142 aEditEngine.SetText(rStyleName);
1144 auto aScript = aEditEngine.GetScriptType({ 0, 0, 0, 0 });
1145 for (sal_Int32 i = 1; i <= rStyleName.getLength(); i++)
1147 auto aNextScript = aEditEngine.GetScriptType({ 0, i, 0, i });
1148 if (aNextScript != aScript || i == rStyleName.getLength())
1149 aScriptChanges.emplace_back(aScript, i);
1150 aScript = aNextScript;
1153 return aScriptChanges;
1157 tools::Rectangle SvxStyleBox_Base::CalcBoundRect(vcl::RenderContext& rRenderContext, const OUString &rStyleName, std::vector<ScriptInfo>& rScriptChanges, double fRatio)
1159 tools::Rectangle aTextRect;
1161 SvtScriptType aScript;
1162 sal_uInt16 nIdx = 0;
1163 sal_Int32 nStart = 0;
1164 sal_Int32 nEnd;
1165 size_t nCnt = rScriptChanges.size();
1167 if (nCnt)
1169 nEnd = rScriptChanges[nIdx].changePos;
1170 aScript = rScriptChanges[nIdx].scriptType;
1172 else
1174 nEnd = rStyleName.getLength();
1175 aScript = SvtScriptType::LATIN;
1180 auto oFont = (aScript == SvtScriptType::ASIAN) ?
1181 m_oCJKFont :
1182 ((aScript == SvtScriptType::COMPLEX) ?
1183 m_oCTLFont :
1184 m_oFont);
1186 rRenderContext.Push(vcl::PushFlags::FONT);
1188 if (oFont)
1189 rRenderContext.SetFont(*oFont);
1191 if (fRatio != 1)
1193 vcl::Font aFont(rRenderContext.GetFont());
1194 Size aPixelSize(aFont.GetFontSize());
1195 aPixelSize.setWidth(aPixelSize.Width() * fRatio);
1196 aPixelSize.setHeight(aPixelSize.Height() * fRatio);
1197 aFont.SetFontSize(aPixelSize);
1198 rRenderContext.SetFont(aFont);
1201 tools::Rectangle aRect;
1202 rRenderContext.GetTextBoundRect(aRect, rStyleName, nStart, nStart, nEnd - nStart);
1203 aTextRect = aTextRect.Union(aRect);
1205 tools::Long nWidth = rRenderContext.GetTextWidth(rStyleName, nStart, nEnd - nStart);
1207 rRenderContext.Pop();
1209 if (nIdx >= rScriptChanges.size())
1210 break;
1212 rScriptChanges[nIdx++].textWidth = nWidth;
1214 if (nEnd < rStyleName.getLength() && nIdx < nCnt)
1216 nStart = nEnd;
1217 nEnd = rScriptChanges[nIdx].changePos;
1218 aScript = rScriptChanges[nIdx].scriptType;
1220 else
1221 break;
1223 while(true);
1225 return aTextRect;
1228 void SvxStyleBox_Base::UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const tools::Rectangle& rTextRect, const OUString &rStyleName, const std::vector<ScriptInfo>& rScriptChanges)
1230 // IMG_TXT_DISTANCE in ilstbox.hxx is 6, then 1 is added as
1231 // nBorder, and we are adding 1 in order to look better when
1232 // italics is present
1233 const int nLeftDistance = 8;
1235 Point aPos(rRect.TopLeft());
1236 aPos.AdjustX(nLeftDistance );
1238 double fRatio = 1;
1239 if (rTextRect.Bottom() > rRect.GetHeight())
1240 fRatio = static_cast<double>(rRect.GetHeight()) / rTextRect.Bottom();
1241 else
1242 aPos.AdjustY((rRect.GetHeight() - rTextRect.Bottom()) / 2);
1244 SvtScriptType aScript;
1245 sal_uInt16 nIdx = 0;
1246 sal_Int32 nStart = 0;
1247 sal_Int32 nEnd;
1248 size_t nCnt = rScriptChanges.size();
1250 if (nCnt)
1252 nEnd = rScriptChanges[nIdx].changePos;
1253 aScript = rScriptChanges[nIdx].scriptType;
1255 else
1257 nEnd = rStyleName.getLength();
1258 aScript = SvtScriptType::LATIN;
1264 auto oFont = (aScript == SvtScriptType::ASIAN) ?
1265 m_oCJKFont :
1266 ((aScript == SvtScriptType::COMPLEX) ?
1267 m_oCTLFont :
1268 m_oFont);
1270 rRenderContext.Push(vcl::PushFlags::FONT);
1272 if (oFont)
1273 rRenderContext.SetFont(*oFont);
1275 if (fRatio != 1)
1277 vcl::Font aFont(rRenderContext.GetFont());
1278 Size aPixelSize(aFont.GetFontSize());
1279 aPixelSize.setWidth(aPixelSize.Width() * fRatio);
1280 aPixelSize.setHeight(aPixelSize.Height() * fRatio);
1281 aFont.SetFontSize(aPixelSize);
1282 rRenderContext.SetFont(aFont);
1285 rRenderContext.DrawText(aPos, rStyleName, nStart, nEnd - nStart);
1287 rRenderContext.Pop();
1289 aPos.AdjustX(rScriptChanges[nIdx++].textWidth * fRatio);
1290 if (nEnd < rStyleName.getLength() && nIdx < nCnt)
1292 nStart = nEnd;
1293 nEnd = rScriptChanges[nIdx].changePos;
1294 aScript = rScriptChanges[nIdx].scriptType;
1296 else
1297 break;
1299 while(true);
1302 static bool GetWhich(const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich)
1304 rWhich = rSet.GetPool()->GetWhich(nSlot);
1305 return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT;
1308 static bool SetFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
1310 sal_uInt16 nWhich;
1311 if (GetWhich(rSet, nSlot, nWhich))
1313 const auto& rFontItem = static_cast<const SvxFontItem&>(rSet.Get(nWhich));
1314 rFont.SetFamilyName(rFontItem.GetFamilyName());
1315 rFont.SetStyleName(rFontItem.GetStyleName());
1316 return true;
1318 return false;
1321 static bool SetFontSize(vcl::RenderContext& rRenderContext, const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
1323 sal_uInt16 nWhich;
1324 if (GetWhich(rSet, nSlot, nWhich))
1326 const auto& rFontHeightItem = static_cast<const SvxFontHeightItem&>(rSet.Get(nWhich));
1327 if (SfxObjectShell *pShell = SfxObjectShell::Current())
1329 Size aFontSize(0, rFontHeightItem.GetHeight());
1330 Size aPixelSize(rRenderContext.LogicToPixel(aFontSize, MapMode(pShell->GetMapUnit())));
1331 rFont.SetFontSize(aPixelSize);
1332 return true;
1335 return false;
1338 static void SetFontStyle(const SfxItemSet& rSet, sal_uInt16 nPosture, sal_uInt16 nWeight, SvxFont& rFont)
1340 sal_uInt16 nWhich;
1341 if (GetWhich(rSet, nPosture, nWhich))
1343 const auto& rItem = static_cast<const SvxPostureItem&>(rSet.Get(nWhich));
1344 rFont.SetItalic(rItem.GetPosture());
1347 if (GetWhich(rSet, nWeight, nWhich))
1349 const auto& rItem = static_cast<const SvxWeightItem&>(rSet.Get(nWhich));
1350 rFont.SetWeight(rItem.GetWeight());
1354 void SvxStyleBox_Base::SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected)
1356 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1357 if (!bIsNotSelected)
1358 rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
1359 else
1360 rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
1362 // handle the push-button
1363 if (!bIsNotSelected)
1365 if (nItem == 0 || nItem == m_xWidget->get_count() - 1)
1366 m_xWidget->set_item_menu(OUString::number(nItem), nullptr);
1367 else
1369 m_nLastItemWithMenu = nItem;
1370 m_xWidget->set_item_menu(OUString::number(nItem), m_xMenu.get());
1374 if (nItem <= 0 || nItem >= m_xWidget->get_count() - 1)
1375 return;
1377 SfxObjectShell *pShell = SfxObjectShell::Current();
1378 if (!pShell)
1379 return;
1381 SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
1382 if (!pPool)
1383 return;
1385 SfxStyleSheetBase* pStyle = pPool->First(eStyleFamily);
1386 while (pStyle && pStyle->GetName() != rStyleName)
1387 pStyle = pPool->Next();
1389 if (!pStyle )
1390 return;
1392 std::optional<SfxItemSet> const pItemSet(pStyle->GetItemSetForPreview());
1393 if (!pItemSet) return;
1395 SvxFont aFont;
1396 SvxFont aCJKFont;
1397 SvxFont aCTLFont;
1399 SetFontStyle(*pItemSet, SID_ATTR_CHAR_POSTURE, SID_ATTR_CHAR_WEIGHT, aFont);
1400 SetFontStyle(*pItemSet, SID_ATTR_CHAR_CJK_POSTURE, SID_ATTR_CHAR_CJK_WEIGHT, aCJKFont);
1401 SetFontStyle(*pItemSet, SID_ATTR_CHAR_CTL_POSTURE, SID_ATTR_CHAR_CTL_WEIGHT, aCTLFont);
1403 const SfxPoolItem *pItem = pItemSet->GetItem( SID_ATTR_CHAR_CONTOUR );
1404 if ( pItem )
1406 auto aVal = static_cast< const SvxContourItem* >( pItem )->GetValue();
1407 aFont.SetOutline(aVal);
1408 aCJKFont.SetOutline(aVal);
1409 aCTLFont.SetOutline(aVal);
1412 pItem = pItemSet->GetItem( SID_ATTR_CHAR_SHADOWED );
1413 if ( pItem )
1415 auto aVal = static_cast< const SvxShadowedItem* >( pItem )->GetValue();
1416 aFont.SetShadow(aVal);
1417 aCJKFont.SetShadow(aVal);
1418 aCTLFont.SetShadow(aVal);
1421 pItem = pItemSet->GetItem( SID_ATTR_CHAR_RELIEF );
1422 if ( pItem )
1424 auto aVal = static_cast< const SvxCharReliefItem* >( pItem )->GetValue();
1425 aFont.SetRelief(aVal);
1426 aCJKFont.SetRelief(aVal);
1427 aCTLFont.SetRelief(aVal);
1430 pItem = pItemSet->GetItem( SID_ATTR_CHAR_UNDERLINE );
1431 if ( pItem )
1433 auto aVal = static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle();
1434 aFont.SetUnderline(aVal);
1435 aCJKFont.SetUnderline(aVal);
1436 aCTLFont.SetUnderline(aVal);
1439 pItem = pItemSet->GetItem( SID_ATTR_CHAR_OVERLINE );
1440 if ( pItem )
1442 auto aVal = static_cast< const SvxOverlineItem* >( pItem )->GetValue();
1443 aFont.SetOverline(aVal);
1444 aCJKFont.SetOverline(aVal);
1445 aCTLFont.SetOverline(aVal);
1448 pItem = pItemSet->GetItem( SID_ATTR_CHAR_STRIKEOUT );
1449 if ( pItem )
1451 auto aVal = static_cast< const SvxCrossedOutItem* >( pItem )->GetStrikeout();
1452 aFont.SetStrikeout(aVal);
1453 aCJKFont.SetStrikeout(aVal);
1454 aCTLFont.SetStrikeout(aVal);
1457 pItem = pItemSet->GetItem( SID_ATTR_CHAR_CASEMAP );
1458 if ( pItem )
1460 auto aVal = static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap();
1461 aFont.SetCaseMap(aVal);
1462 aCJKFont.SetCaseMap(aVal);
1463 aCTLFont.SetCaseMap(aVal);
1466 pItem = pItemSet->GetItem( SID_ATTR_CHAR_EMPHASISMARK );
1467 if ( pItem )
1469 auto aVal = static_cast< const SvxEmphasisMarkItem* >( pItem )->GetEmphasisMark();
1470 aFont.SetEmphasisMark(aVal);
1471 aCJKFont.SetEmphasisMark(aVal);
1472 aCTLFont.SetEmphasisMark(aVal);
1475 // setup the device & draw
1476 Color aFontCol = COL_AUTO, aBackCol = COL_AUTO;
1478 pItem = pItemSet->GetItem( SID_ATTR_CHAR_COLOR );
1479 // text color, when nothing is selected
1480 if ( (nullptr != pItem) && bIsNotSelected)
1481 aFontCol = static_cast< const SvxColorItem* >( pItem )->GetValue();
1483 drawing::FillStyle style = drawing::FillStyle_NONE;
1484 // which kind of Fill style is selected
1485 pItem = pItemSet->GetItem( XATTR_FILLSTYLE );
1486 // only when ok and not selected
1487 if ( (nullptr != pItem) && bIsNotSelected)
1488 style = static_cast< const XFillStyleItem* >( pItem )->GetValue();
1490 switch(style)
1492 case drawing::FillStyle_SOLID:
1494 // set background color
1495 pItem = pItemSet->GetItem( XATTR_FILLCOLOR );
1496 if ( nullptr != pItem )
1497 aBackCol = static_cast< const XFillColorItem* >( pItem )->GetColorValue();
1499 if ( aBackCol != COL_AUTO )
1501 rRenderContext.SetFillColor(aBackCol);
1502 rRenderContext.DrawRect(rRect);
1505 break;
1507 default: break;
1508 //TODO Draw the other background styles: gradient, hatching and bitmap
1511 // when the font and background color are too similar, adjust the Font-Color
1512 if( (aFontCol != COL_AUTO) || (aBackCol != COL_AUTO) )
1513 aFontCol = TestColorsVisible(aFontCol, (aBackCol != COL_AUTO) ? aBackCol : rRenderContext.GetBackground().GetColor());
1515 // set text color
1516 if ( aFontCol != COL_AUTO )
1517 rRenderContext.SetTextColor(aFontCol);
1519 if (SetFont(*pItemSet, SID_ATTR_CHAR_FONT, aFont) &&
1520 SetFontSize(rRenderContext, *pItemSet, SID_ATTR_CHAR_FONTHEIGHT, aFont))
1521 m_oFont = aFont;
1523 if (SetFont(*pItemSet, SID_ATTR_CHAR_CJK_FONT, aCJKFont) &&
1524 SetFontSize(rRenderContext, *pItemSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, aCJKFont))
1525 m_oCJKFont = aCJKFont;
1527 if (SetFont(*pItemSet, SID_ATTR_CHAR_CTL_FONT, aCTLFont) &&
1528 SetFontSize(rRenderContext, *pItemSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, aCTLFont))
1529 m_oCTLFont = aCTLFont;
1532 IMPL_LINK(SvxStyleBox_Base, CustomRenderHdl, weld::ComboBox::render_args, aPayload, void)
1534 vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
1535 const ::tools::Rectangle& rRect = std::get<1>(aPayload);
1536 bool bSelected = std::get<2>(aPayload);
1537 const OUString& rId = std::get<3>(aPayload);
1539 sal_uInt32 nIndex = rId.toUInt32();
1541 OUString aStyleName(m_xWidget->get_text(nIndex));
1543 rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
1545 SetupEntry(rRenderContext, nIndex, rRect, aStyleName, !bSelected);
1546 auto aScriptChanges = CheckScript(aStyleName);
1547 auto aTextRect = CalcBoundRect(rRenderContext, aStyleName, aScriptChanges);
1548 UserDrawEntry(rRenderContext, rRect, aTextRect, aStyleName, aScriptChanges);
1550 rRenderContext.Pop();
1553 void SvxStyleBox_Base::CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext)
1555 if (m_nMaxUserDrawFontWidth)
1556 return;
1558 tools::Long nMaxNormalFontWidth = 0;
1559 sal_Int32 nEntryCount = m_xWidget->get_count();
1560 for (sal_Int32 i = 0; i < nEntryCount; ++i)
1562 OUString sStyleName(get_text(i));
1563 tools::Rectangle aTextRectForDefaultFont;
1564 rRenderContext.GetTextBoundRect(aTextRectForDefaultFont, sStyleName);
1566 const tools::Long nWidth = aTextRectForDefaultFont.GetWidth();
1568 nMaxNormalFontWidth = std::max(nWidth, nMaxNormalFontWidth);
1571 m_nMaxUserDrawFontWidth = nMaxNormalFontWidth;
1572 for (sal_Int32 i = 1; i < nEntryCount-1; ++i)
1574 OUString sStyleName(get_text(i));
1576 if (sStyleName.isEmpty())
1577 continue;
1579 rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
1580 SetupEntry(rRenderContext, i, tools::Rectangle(0, 0, RECT_MAX, ITEM_HEIGHT), sStyleName, true);
1581 auto aScriptChanges = CheckScript(sStyleName);
1582 tools::Rectangle aTextRectForActualFont = CalcBoundRect(rRenderContext, sStyleName, aScriptChanges);
1583 if (aTextRectForActualFont.Bottom() > ITEM_HEIGHT)
1585 //Font didn't fit, re-calculate with adjustment ratio.
1586 double fRatio = static_cast<double>(ITEM_HEIGHT) / aTextRectForActualFont.Bottom();
1587 aTextRectForActualFont = CalcBoundRect(rRenderContext, sStyleName, aScriptChanges, fRatio);
1589 rRenderContext.Pop();
1591 const int nWidth = aTextRectForActualFont.GetWidth() + m_xWidget->get_menu_button_width() + BUTTON_PADDING;
1593 m_nMaxUserDrawFontWidth = std::max(nWidth, m_nMaxUserDrawFontWidth);
1597 // test is the color between Font- and background-color to be identify
1598 // return is always the Font-Color
1599 // when both light or dark, change the Contrast
1600 // in other case do not change the origin color
1601 // when the color is R=G=B=128 the DecreaseContrast make 128 the need an exception
1602 Color SvxStyleBox_Base::TestColorsVisible(const Color &FontCol, const Color &BackCol)
1604 constexpr sal_uInt8 ChgVal = 60; // increase/decrease the Contrast
1606 Color retCol = FontCol;
1607 if ((FontCol.IsDark() == BackCol.IsDark()) && (FontCol.IsBright() == BackCol.IsBright()))
1609 sal_uInt8 lumi = retCol.GetLuminance();
1611 if((lumi > 120) && (lumi < 140))
1612 retCol.DecreaseLuminance(ChgVal / 2);
1613 else
1614 retCol.DecreaseContrast(ChgVal);
1617 return retCol;
1620 IMPL_LINK(SvxStyleBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
1622 if (!m_xWidget)
1623 return;
1626 auto entriesNode = rJsonWriter.startNode("entries");
1627 for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i)
1629 auto entryNode = rJsonWriter.startNode("");
1630 rJsonWriter.put("", m_xWidget->get_text(i));
1634 int nActive = m_xWidget->get_active();
1635 rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nActive == -1 ? 0 : 1));
1638 auto selectedNode = rJsonWriter.startNode("selectedEntries");
1639 if (nActive != -1)
1641 auto node = rJsonWriter.startNode("");
1642 rJsonWriter.put("", static_cast<sal_Int32>(nActive));
1646 rJsonWriter.put("command", ".uno:StyleApply");
1649 static bool lcl_GetDocFontList(const FontList** ppFontList, SvxFontNameBox_Base* pBox)
1651 bool bChanged = false;
1652 const SfxObjectShell* pDocSh = SfxObjectShell::Current();
1653 const SvxFontListItem* pFontListItem = nullptr;
1655 if ( pDocSh )
1656 pFontListItem =
1657 static_cast<const SvxFontListItem*>(pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST ));
1658 else
1660 ::std::unique_ptr<FontList> aFontList(new FontList(Application::GetDefaultDevice()));
1661 *ppFontList = aFontList.get();
1662 pBox->SetOwnFontList(std::move(aFontList));
1663 bChanged = true;
1666 if ( pFontListItem )
1668 const FontList* pNewFontList = pFontListItem->GetFontList();
1669 DBG_ASSERT( pNewFontList, "Doc-FontList not available!" );
1671 // No old list, but a new list
1672 if ( !*ppFontList && pNewFontList )
1674 // => take over
1675 *ppFontList = pNewFontList;
1676 bChanged = true;
1678 else
1680 // Comparing the font lists is not perfect.
1681 // When you change the font list in the Doc, you can track
1682 // changes here only on the Listbox, because ppFontList
1683 // has already been updated.
1684 bChanged =
1685 ( ( *ppFontList != pNewFontList ) ||
1686 pBox->GetListCount() != pNewFontList->GetFontNameCount() );
1687 // HACK: Comparing is incomplete
1689 if ( bChanged )
1690 *ppFontList = pNewFontList;
1693 if ( pBox )
1694 pBox->set_sensitive(true);
1696 else if ( pBox && ( pDocSh || !ppFontList ))
1698 // Disable box only when we have a SfxObjectShell and didn't get a font list OR
1699 // we don't have a SfxObjectShell and no current font list.
1700 // It's possible that we currently have no SfxObjectShell, but a current font list.
1701 // See #i58471: When a user set the focus into the font name combo box and opens
1702 // the help window with F1. After closing the help window, we disable the font name
1703 // combo box. The SfxObjectShell::Current() method returns in that case zero. But the
1704 // font list hasn't changed and therefore the combo box shouldn't be disabled!
1705 pBox->set_sensitive(false);
1708 // Fill the FontBox, also the new list if necessary
1709 if ( pBox && bChanged )
1711 if ( *ppFontList )
1712 pBox->Fill( *ppFontList );
1713 else
1714 pBox->Clear();
1716 return bChanged;
1719 SvxFontNameBox_Base::SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
1720 const Reference<XFrame>& rFrame,
1721 SvxFontNameToolBoxControl& rCtrl)
1722 : m_xListener(new comphelper::ConfigurationListener("/org.openoffice.Office.Common/Font/View"))
1723 , m_aWYSIWYG(m_xListener, "ShowFontBoxWYSIWYG", *this)
1724 , m_aHistory(m_xListener, "History", *this)
1725 , m_rCtrl(rCtrl)
1726 , m_xWidget(new FontNameBox(std::move(xWidget)))
1727 , pFontList(nullptr)
1728 , nFtCount(0)
1729 , bRelease(true)
1730 , m_xFrame(rFrame)
1731 , mbCheckingUnknownFont(false)
1732 , mbDropDownActive(false)
1734 EnableControls();
1736 m_xWidget->connect_changed(LINK(this, SvxFontNameBox_Base, SelectHdl));
1737 m_xWidget->connect_key_press(LINK(this, SvxFontNameBox_Base, KeyInputHdl));
1738 m_xWidget->connect_entry_activate(LINK(this, SvxFontNameBox_Base, ActivateHdl));
1739 m_xWidget->connect_focus_in(LINK(this, SvxFontNameBox_Base, FocusInHdl));
1740 m_xWidget->connect_focus_out(LINK(this, SvxFontNameBox_Base, FocusOutHdl));
1741 m_xWidget->connect_popup_toggled(LINK(this, SvxFontNameBox_Base, PopupToggledHdl));
1742 m_xWidget->connect_live_preview(LINK(this, SvxFontNameBox_Base, LivePreviewHdl));
1743 m_xWidget->connect_get_property_tree(LINK(this, SvxFontNameBox_Base, DumpAsPropertyTreeHdl));
1745 m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 5);
1748 SvxFontNameBox_Impl::SvxFontNameBox_Impl(vcl::Window* pParent, const Reference<XFrame>& rFrame,
1749 SvxFontNameToolBoxControl& rCtrl)
1750 : InterimItemWindow(pParent, "svx/ui/fontnamebox.ui", "FontNameBox", true, reinterpret_cast<sal_uInt64>(SfxViewShell::Current()))
1751 , SvxFontNameBox_Base(m_xBuilder->weld_combo_box("fontnamecombobox"), rFrame, rCtrl)
1753 set_id("fontnamecombobox");
1754 SetOptimalSize();
1757 void SvxFontNameBox_Base::FillList()
1759 if (!m_xWidget) // e.g. disposed
1760 return;
1761 // Save old Selection, set back in the end
1762 int nStartPos, nEndPos;
1763 m_xWidget->get_entry_selection_bounds(nStartPos, nEndPos);
1765 // Did Doc-Fontlist change?
1766 lcl_GetDocFontList(&pFontList, this);
1768 m_xWidget->select_entry_region(nStartPos, nEndPos);
1771 bool SvxFontNameBox_Base::CheckFontIsAvailable(std::u16string_view fontname)
1773 lcl_GetDocFontList(&pFontList, this);
1774 return pFontList && pFontList->IsAvailable(fontname);
1777 void SvxFontNameBox_Base::CheckAndMarkUnknownFont()
1779 if (mbCheckingUnknownFont) //tdf#117537 block rentry
1780 return;
1781 mbCheckingUnknownFont = true;
1782 OUString fontname = m_xWidget->get_active_text();
1783 // tdf#154680 If a font is set and that font is unknown, show it in italic.
1784 vcl::Font font = m_xWidget->get_entry_font();
1785 if (fontname.isEmpty() || CheckFontIsAvailable(fontname))
1787 if( font.GetItalic() != ITALIC_NONE )
1789 font.SetItalic( ITALIC_NONE );
1790 m_xWidget->set_entry_font(font);
1791 m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME));
1794 else
1796 if( font.GetItalic() != ITALIC_NORMAL )
1798 font.SetItalic( ITALIC_NORMAL );
1799 m_xWidget->set_entry_font(font);
1800 m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME_NOTAVAILABLE));
1803 mbCheckingUnknownFont = false;
1806 void SvxFontNameBox_Base::Update( const css::awt::FontDescriptor* pFontDesc )
1808 if ( pFontDesc )
1810 aCurFont.SetFamilyName ( pFontDesc->Name );
1811 aCurFont.SetFamily ( FontFamily( pFontDesc->Family ) );
1812 aCurFont.SetStyleName ( pFontDesc->StyleName );
1813 aCurFont.SetPitch ( FontPitch( pFontDesc->Pitch ) );
1814 aCurFont.SetCharSet ( rtl_TextEncoding( pFontDesc->CharSet ) );
1816 OUString aCurName = aCurFont.GetFamilyName();
1817 OUString aText = m_xWidget->get_active_text();
1818 if (aText != aCurName)
1819 set_active_or_entry_text(aCurName);
1822 void SvxFontNameBox_Base::set_active_or_entry_text(const OUString& rText)
1824 m_xWidget->set_active_or_entry_text(rText);
1825 CheckAndMarkUnknownFont();
1828 IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusInHdl, weld::Widget&, void)
1830 FillList();
1833 IMPL_LINK(SvxFontNameBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool)
1835 return DoKeyInput(rKEvt);
1838 bool SvxFontNameBox_Base::DoKeyInput(const KeyEvent& rKEvt)
1840 bool bHandled = false;
1842 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1844 switch (nCode)
1846 case KEY_TAB:
1847 bRelease = false;
1848 Select(true);
1849 break;
1851 case KEY_ESCAPE:
1852 set_active_or_entry_text(m_xWidget->get_saved_value());
1853 if (!m_rCtrl.IsInSidebar())
1855 ReleaseFocus_Impl();
1856 bHandled = true;
1858 break;
1861 return bHandled;
1864 bool SvxFontNameBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
1866 return SvxFontNameBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt);
1869 IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusOutHdl, weld::Widget&, void)
1871 if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
1873 set_active_or_entry_text(m_xWidget->get_saved_value());
1874 // send EndPreview
1875 EndPreview();
1879 IMPL_LINK(SvxFontNameBox_Base, LivePreviewHdl, const FontMetric&, rFontMetric, void)
1881 Sequence<PropertyValue> aArgs(1);
1883 SvxFontItem aFontItem(rFontMetric.GetFamilyType(),
1884 rFontMetric.GetFamilyName(),
1885 rFontMetric.GetStyleName(),
1886 rFontMetric.GetPitch(),
1887 rFontMetric.GetCharSet(),
1888 SID_ATTR_CHAR_FONT);
1889 PropertyValue* pArgs = aArgs.getArray();
1890 aFontItem.QueryValue(pArgs[0].Value);
1891 pArgs[0].Name = "CharPreviewFontName";
1892 const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
1893 SfxToolBoxControl::Dispatch(xProvider, ".uno:CharPreviewFontName", aArgs);
1896 IMPL_LINK_NOARG(SvxFontNameBox_Base, PopupToggledHdl, weld::ComboBox&, void)
1898 mbDropDownActive = !mbDropDownActive;
1899 if (!mbDropDownActive)
1900 EndPreview();
1903 void SvxFontNameBox_Impl::SetOptimalSize()
1905 // set width in chars low so the size request will not be overridden
1906 m_xWidget->set_entry_width_chars(1);
1907 // tdf#132338 purely using this calculation to keep things their traditional width
1908 Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS +5) * 4, 0), MapMode(MapUnit::MapAppFont)));
1909 m_xWidget->set_size_request(aSize.Width(), -1);
1911 SetSizePixel(get_preferred_size());
1914 void SvxFontNameBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
1916 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1917 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1919 SetOptimalSize();
1921 else if ( ( rDCEvt.GetType() == DataChangedEventType::FONTS ) ||
1922 ( rDCEvt.GetType() == DataChangedEventType::DISPLAY ) )
1924 // The old font list in shell has likely been destroyed at this point, so we need to get
1925 // the new one before doing anything further.
1926 lcl_GetDocFontList( &pFontList, this );
1930 void SvxFontNameBox_Base::ReleaseFocus_Impl()
1932 if ( !bRelease )
1934 bRelease = true;
1935 return;
1937 if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() )
1938 m_xFrame->getContainerWindow()->setFocus();
1941 void SvxFontNameBox_Base::EnableControls()
1943 bool bEnableMRU = m_aHistory.get();
1944 sal_uInt16 nEntries = bEnableMRU ? MAX_MRU_FONTNAME_ENTRIES : 0;
1946 bool bNewWYSIWYG = m_aWYSIWYG.get();
1947 bool bOldWYSIWYG = m_xWidget->IsWYSIWYGEnabled();
1949 if (m_xWidget->get_max_mru_count() != nEntries || bNewWYSIWYG != bOldWYSIWYG)
1951 // refill in the next GetFocus-Handler
1952 pFontList = nullptr;
1953 Clear();
1954 m_xWidget->set_max_mru_count(nEntries);
1957 if (bNewWYSIWYG != bOldWYSIWYG)
1958 m_xWidget->EnableWYSIWYG(bNewWYSIWYG);
1961 IMPL_LINK(SvxFontNameBox_Base, SelectHdl, weld::ComboBox&, rCombo, void)
1963 Select(rCombo.changed_by_direct_pick()); // only when picked from the list
1966 IMPL_LINK_NOARG(SvxFontNameBox_Base, ActivateHdl, weld::ComboBox&, bool)
1968 Select(true);
1969 return true;
1972 void SvxFontNameBox_Base::Select(bool bNonTravelSelect)
1974 Sequence< PropertyValue > aArgs( 1 );
1975 auto pArgs = aArgs.getArray();
1976 std::unique_ptr<SvxFontItem> pFontItem;
1977 if ( pFontList )
1979 FontMetric aFontMetric( pFontList->Get(m_xWidget->get_active_text(),
1980 aCurFont.GetWeight(),
1981 aCurFont.GetItalic() ) );
1982 aCurFont = aFontMetric;
1984 pFontItem.reset( new SvxFontItem( aFontMetric.GetFamilyType(),
1985 aFontMetric.GetFamilyName(),
1986 aFontMetric.GetStyleName(),
1987 aFontMetric.GetPitch(),
1988 aFontMetric.GetCharSet(),
1989 SID_ATTR_CHAR_FONT ) );
1991 Any a;
1992 pFontItem->QueryValue( a );
1993 pArgs[0].Value = a;
1996 const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
1997 if (bNonTravelSelect)
1999 CheckAndMarkUnknownFont();
2000 // #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
2001 // This instance may be deleted in the meantime (i.e. when a dialog is opened
2002 // while in Dispatch()), accessing members will crash in this case.
2003 ReleaseFocus_Impl();
2004 EndPreview();
2005 if (pFontItem)
2007 pArgs[0].Name = "CharFontName";
2008 SfxToolBoxControl::Dispatch(xProvider, ".uno:CharFontName", aArgs);
2011 else
2013 if (pFontItem)
2015 pArgs[0].Name = "CharPreviewFontName";
2016 SfxToolBoxControl::Dispatch(xProvider, ".uno:CharPreviewFontName", aArgs);
2021 IMPL_LINK(SvxFontNameBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
2024 auto entriesNode = rJsonWriter.startNode("entries");
2025 for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i)
2027 auto entryNode = rJsonWriter.startNode("");
2028 rJsonWriter.put("", m_xWidget->get_text(i));
2032 int nSelectedEntry = m_xWidget->get_active();
2033 rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nSelectedEntry == -1 ? 0 : 1));
2036 auto selectedNode = rJsonWriter.startNode("selectedEntries");
2037 if (nSelectedEntry != -1)
2039 auto entryNode = rJsonWriter.startNode("");
2040 rJsonWriter.put("", m_xWidget->get_text(nSelectedEntry));
2044 rJsonWriter.put("command", ".uno:CharFontName");
2047 ColorWindow::ColorWindow(OUString rCommand,
2048 std::shared_ptr<PaletteManager> xPaletteManager,
2049 ColorStatus& rColorStatus,
2050 sal_uInt16 nSlotId,
2051 const Reference< XFrame >& rFrame,
2052 const MenuOrToolMenuButton& rMenuButton,
2053 TopLevelParentFunction aTopLevelParentFunction,
2054 ColorSelectFunction aColorSelectFunction)
2055 : WeldToolbarPopup(rFrame, rMenuButton.get_widget(), "svx/ui/colorwindow.ui", "palette_popup_window")
2056 , theSlotId(nSlotId)
2057 , maCommand(std::move(rCommand))
2058 , maMenuButton(rMenuButton)
2059 , mxPaletteManager(std::move(xPaletteManager))
2060 , mrColorStatus(rColorStatus)
2061 , maTopLevelParentFunction(std::move(aTopLevelParentFunction))
2062 , maColorSelectFunction(std::move(aColorSelectFunction))
2063 , mxColorSet(new SvxColorValueSet(m_xBuilder->weld_scrolled_window("colorsetwin", true)))
2064 , mxRecentColorSet(new SvxColorValueSet(nullptr))
2065 , mxPaletteListBox(m_xBuilder->weld_combo_box("palette_listbox"))
2066 , mxButtonAutoColor(m_xBuilder->weld_button("auto_color_button"))
2067 , mxButtonNoneColor(m_xBuilder->weld_button("none_color_button"))
2068 , mxButtonPicker(m_xBuilder->weld_button("color_picker_button"))
2069 , mxAutomaticSeparator(m_xBuilder->weld_widget("separator4"))
2070 , mxColorSetWin(new weld::CustomWeld(*m_xBuilder, "colorset", *mxColorSet))
2071 , mxRecentColorSetWin(new weld::CustomWeld(*m_xBuilder, "recent_colorset", *mxRecentColorSet))
2072 , mpDefaultButton(nullptr)
2074 mxColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
2075 mxRecentColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
2077 switch ( theSlotId )
2079 case SID_ATTR_CHAR_COLOR_BACKGROUND:
2080 case SID_BACKGROUND_COLOR:
2081 case SID_ATTR_CHAR_BACK_COLOR:
2082 case SID_TABLE_CELL_BACKGROUND_COLOR:
2084 mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_NOFILL ) );
2085 break;
2087 case SID_AUTHOR_COLOR:
2089 mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_BY_AUTHOR ) );
2090 break;
2092 case SID_BMPMASK_COLOR:
2094 mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_TRANSPARENT ) );
2095 break;
2097 case SID_ATTR_CHAR_COLOR:
2098 case SID_ATTR_CHAR_COLOR2:
2099 case SID_EXTRUSION_3D_COLOR:
2101 mxButtonAutoColor->set_label(EditResId(RID_SVXSTR_AUTOMATIC));
2102 break;
2104 case SID_FM_CTL_PROPERTIES:
2106 mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_DEFAULT ) );
2107 break;
2109 default:
2111 mxButtonAutoColor->hide();
2112 mxAutomaticSeparator->hide();
2113 break;
2117 mxPaletteListBox->connect_changed(LINK(this, ColorWindow, SelectPaletteHdl));
2118 std::vector<OUString> aPaletteList = mxPaletteManager->GetPaletteList();
2119 mxPaletteListBox->freeze();
2120 for (const auto& rPalette : aPaletteList)
2121 mxPaletteListBox->append_text(rPalette);
2122 mxPaletteListBox->thaw();
2123 OUString aPaletteName( officecfg::Office::Common::UserColors::PaletteName::get() );
2124 mxPaletteListBox->set_active_text(aPaletteName);
2125 const int nSelectedEntry(mxPaletteListBox->get_active());
2126 if (nSelectedEntry != -1)
2127 mxPaletteManager->SetPalette(nSelectedEntry);
2129 mxButtonAutoColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl));
2130 mxButtonNoneColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl));
2131 mxButtonPicker->connect_clicked(LINK(this, ColorWindow, OpenPickerClickHdl));
2133 mxColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl));
2134 mxRecentColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl));
2135 m_xTopLevel->set_help_id(HID_POPUP_COLOR);
2136 mxColorSet->SetHelpId(HID_POPUP_COLOR_CTRL);
2138 mxPaletteManager->ReloadColorSet(*mxColorSet);
2139 const sal_uInt32 nMaxItems(SvxColorValueSet::getMaxRowCount() * SvxColorValueSet::getColumnCount());
2140 Size aSize = mxColorSet->layoutAllVisible(nMaxItems);
2141 mxColorSet->set_size_request(aSize.Width(), aSize.Height());
2143 mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
2144 aSize = mxRecentColorSet->layoutAllVisible(mxPaletteManager->GetRecentColorCount());
2145 mxRecentColorSet->set_size_request(aSize.Width(), aSize.Height());
2147 AddStatusListener( ".uno:ColorTableState" );
2148 AddStatusListener( maCommand );
2149 if ( maCommand == ".uno:FrameLineColor" )
2151 AddStatusListener( ".uno:BorderTLBR" );
2152 AddStatusListener( ".uno:BorderBLTR" );
2156 void ColorWindow::GrabFocus()
2158 if (mxColorSet->IsNoSelection() && mpDefaultButton)
2159 mpDefaultButton->grab_focus();
2160 else
2161 mxColorSet->GrabFocus();
2164 void ColorWindow::ShowNoneButton()
2166 mxButtonNoneColor->show();
2169 ColorWindow::~ColorWindow()
2173 NamedColor ColorWindow::GetSelectEntryColor(ValueSet const * pColorSet)
2175 Color aColor = pColorSet->GetItemColor(pColorSet->GetSelectedItemId());
2176 OUString sColorName = pColorSet->GetItemText(pColorSet->GetSelectedItemId());
2177 return { aColor, sColorName };
2180 namespace
2182 NamedColor GetAutoColor(sal_uInt16 nSlotId)
2184 Color aColor;
2185 OUString sColorName;
2186 switch (nSlotId)
2188 case SID_ATTR_CHAR_COLOR_BACKGROUND:
2189 case SID_BACKGROUND_COLOR:
2190 case SID_ATTR_CHAR_BACK_COLOR:
2191 case SID_TABLE_CELL_BACKGROUND_COLOR:
2192 aColor = COL_TRANSPARENT;
2193 sColorName = SvxResId(RID_SVXSTR_NOFILL);
2194 break;
2195 case SID_AUTHOR_COLOR:
2196 aColor = COL_TRANSPARENT;
2197 sColorName = SvxResId(RID_SVXSTR_BY_AUTHOR);
2198 break;
2199 case SID_BMPMASK_COLOR:
2200 aColor = COL_TRANSPARENT;
2201 sColorName = SvxResId(RID_SVXSTR_TRANSPARENT);
2202 break;
2203 case SID_FM_CTL_PROPERTIES:
2204 aColor = COL_TRANSPARENT;
2205 sColorName = SvxResId(RID_SVXSTR_DEFAULT);
2206 break;
2207 case SID_ATTR_CHAR_COLOR:
2208 case SID_ATTR_CHAR_COLOR2:
2209 case SID_EXTRUSION_3D_COLOR:
2210 default:
2211 aColor = COL_AUTO;
2212 sColorName = EditResId(RID_SVXSTR_AUTOMATIC);
2213 break;
2216 return {aColor, sColorName};
2219 NamedColor GetNoneColor()
2221 OUString aName = comphelper::LibreOfficeKit::isActive()
2222 ? SvxResId(RID_SVXSTR_INVISIBLE)
2223 : SvxResId(RID_SVXSTR_NONE);
2224 return { COL_NONE_COLOR, aName };
2228 NamedColor ColorWindow::GetSelectEntryColor() const
2230 if (!mxColorSet->IsNoSelection())
2231 return GetSelectEntryColor(mxColorSet.get());
2232 if (!mxRecentColorSet->IsNoSelection())
2233 return GetSelectEntryColor(mxRecentColorSet.get());
2234 if (mxButtonNoneColor.get() == mpDefaultButton)
2235 return GetNoneColor();
2236 return GetAutoColor();
2239 IMPL_LINK(ColorWindow, SelectHdl, ValueSet*, pColorSet, void)
2241 NamedColor aNamedColor = GetSelectEntryColor(pColorSet);
2243 if (pColorSet != mxRecentColorSet.get())
2245 mxPaletteManager->AddRecentColor(aNamedColor.m_aColor, aNamedColor.m_aName);
2246 if (!maMenuButton.get_active())
2247 mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
2250 mxPaletteManager->SetSplitButtonColor(aNamedColor);
2252 // deliberate take a copy here in case maMenuButton.set_inactive
2253 // triggers a callback that destroys ourself
2254 ColorSelectFunction aColorSelectFunction(maColorSelectFunction);
2255 OUString sCommand(maCommand);
2256 // Same for querying IsTheme early.
2257 bool bThemePaletteSelected = mxPaletteManager->IsThemePaletteSelected();
2258 sal_uInt16 nSelectedItemId = pColorSet->GetSelectedItemId();
2260 if (bThemePaletteSelected)
2262 sal_uInt16 nThemeIndex;
2263 sal_uInt16 nEffectIndex;
2264 if (PaletteManager::GetThemeAndEffectIndex(nSelectedItemId, nThemeIndex, nEffectIndex))
2266 aNamedColor.m_nThemeIndex = nThemeIndex;
2267 mxPaletteManager->GetLumModOff(nThemeIndex, nEffectIndex, aNamedColor.m_nLumMod, aNamedColor.m_nLumOff);
2271 maMenuButton.set_inactive();
2272 aColorSelectFunction(sCommand, aNamedColor);
2275 IMPL_LINK_NOARG(ColorWindow, SelectPaletteHdl, weld::ComboBox&, void)
2277 int nPos = mxPaletteListBox->get_active();
2278 mxPaletteManager->SetPalette( nPos );
2279 mxPaletteManager->ReloadColorSet(*mxColorSet);
2280 mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount());
2283 NamedColor ColorWindow::GetAutoColor() const
2285 return ::GetAutoColor(theSlotId);
2288 IMPL_LINK(ColorWindow, AutoColorClickHdl, weld::Button&, rButton, void)
2290 NamedColor aNamedColor = &rButton == mxButtonAutoColor.get() ? GetAutoColor() : GetNoneColor();
2292 mxColorSet->SetNoSelection();
2293 mxRecentColorSet->SetNoSelection();
2294 mpDefaultButton = &rButton;
2296 mxPaletteManager->SetSplitButtonColor(aNamedColor);
2298 // deliberate take a copy here in case maMenuButton.set_inactive
2299 // triggers a callback that destroys ourself
2300 ColorSelectFunction aColorSelectFunction(maColorSelectFunction);
2301 OUString sCommand(maCommand);
2303 maMenuButton.set_inactive();
2305 aColorSelectFunction(sCommand, aNamedColor);
2308 IMPL_LINK_NOARG(ColorWindow, OpenPickerClickHdl, weld::Button&, void)
2310 // copy before set_inactive
2311 auto nColor = GetSelectEntryColor().m_aColor;
2312 auto pParentWindow = maTopLevelParentFunction();
2313 OUString sCommand = maCommand;
2314 std::shared_ptr<PaletteManager> xPaletteManager(mxPaletteManager);
2316 maMenuButton.set_inactive();
2318 xPaletteManager->PopupColorPicker(pParentWindow, sCommand, nColor);
2321 void ColorWindow::SetNoSelection()
2323 mxColorSet->SetNoSelection();
2324 mxRecentColorSet->SetNoSelection();
2325 mpDefaultButton = nullptr;
2328 bool ColorWindow::IsNoSelection() const
2330 if (!mxColorSet->IsNoSelection())
2331 return false;
2332 if (!mxRecentColorSet->IsNoSelection())
2333 return false;
2334 return !mxButtonAutoColor->get_visible() && !mxButtonNoneColor->get_visible();
2337 void ColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent )
2339 if (rEvent.FeatureURL.Complete == ".uno:ColorTableState")
2341 if (rEvent.IsEnabled && mxPaletteManager->GetPalette() == 0)
2343 mxPaletteManager->ReloadColorSet(*mxColorSet);
2344 mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount());
2347 else
2349 mrColorStatus.statusChanged(rEvent);
2350 SelectEntry(mrColorStatus.GetColor());
2354 bool ColorWindow::SelectValueSetEntry(SvxColorValueSet* pColorSet, const Color& rColor)
2356 for (size_t i = 1; i <= pColorSet->GetItemCount(); ++i)
2358 if (rColor == pColorSet->GetItemColor(i))
2360 pColorSet->SelectItem(i);
2361 return true;
2364 return false;
2367 void ColorWindow::SelectEntry(const NamedColor& rNamedColor)
2369 SetNoSelection();
2371 const Color &rColor = rNamedColor.m_aColor;
2373 if (mxButtonAutoColor->get_visible() && rColor.IsFullyTransparent())
2375 mpDefaultButton = mxButtonAutoColor.get();
2376 return;
2379 if (mxButtonNoneColor->get_visible() && rColor == COL_NONE_COLOR)
2381 mpDefaultButton = mxButtonNoneColor.get();
2382 return;
2385 // try current palette
2386 bool bFoundColor = SelectValueSetEntry(mxColorSet.get(), rColor);
2387 // try recently used
2388 if (!bFoundColor)
2389 bFoundColor = SelectValueSetEntry(mxRecentColorSet.get(), rColor);
2390 // if it's not there, add it there now to the end of the recently used
2391 // so its available somewhere handy, but not without trashing the
2392 // whole recently used
2393 if (!bFoundColor)
2395 const OUString& rColorName = rNamedColor.m_aName;
2396 mxPaletteManager->AddRecentColor(rColor, rColorName, false);
2397 mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
2398 SelectValueSetEntry(mxRecentColorSet.get(), rColor);
2402 void ColorWindow::SelectEntry(const Color& rColor)
2404 OUString sColorName = "#" + rColor.AsRGBHexString().toAsciiUpperCase();
2405 ColorWindow::SelectEntry({rColor, sColorName});
2408 ColorStatus::ColorStatus() :
2409 maColor( COL_TRANSPARENT ),
2410 maTLBRColor( COL_TRANSPARENT ),
2411 maBLTRColor( COL_TRANSPARENT )
2415 void ColorStatus::statusChanged( const css::frame::FeatureStateEvent& rEvent )
2417 Color aColor( COL_TRANSPARENT );
2418 css::table::BorderLine2 aTable;
2420 if ( rEvent.State >>= aTable )
2422 SvxBorderLine aLine;
2423 SvxBoxItem::LineToSvxLine( aTable, aLine, false );
2424 if ( !aLine.isEmpty() )
2425 aColor = aLine.GetColor();
2427 else
2428 rEvent.State >>= aColor;
2430 if ( rEvent.FeatureURL.Path == "BorderTLBR" )
2431 maTLBRColor = aColor;
2432 else if ( rEvent.FeatureURL.Path == "BorderBLTR" )
2433 maBLTRColor = aColor;
2434 else
2435 maColor = aColor;
2438 Color ColorStatus::GetColor()
2440 Color aColor( maColor );
2442 if ( maTLBRColor != COL_TRANSPARENT )
2444 if ( aColor != maTLBRColor && aColor != COL_TRANSPARENT )
2445 return COL_TRANSPARENT;
2446 aColor = maTLBRColor;
2449 if ( maBLTRColor != COL_TRANSPARENT )
2451 if ( aColor != maBLTRColor && aColor != COL_TRANSPARENT )
2452 return COL_TRANSPARENT;
2453 return maBLTRColor;
2456 return aColor;
2460 SvxFrameWindow_Impl::SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent)
2461 : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder")
2462 , mxControl(pControl)
2463 , mxFrameSet(new SvxFrmValueSet_Impl)
2464 , mxFrameSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxFrameSet))
2465 , bParagraphMode(false)
2466 , m_bIsWriter(false)
2469 // check whether the document is Writer or not
2470 if (Reference<lang::XServiceInfo> xSI{ m_xFrame->getController()->getModel(), UNO_QUERY })
2471 m_bIsWriter = xSI->supportsService("com.sun.star.text.TextDocument");
2473 mxFrameSet->SetStyle(WB_ITEMBORDER | WB_DOUBLEBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT);
2474 AddStatusListener(".uno:BorderReducedMode");
2475 InitImageList();
2478 * 1 2 3 4 5
2479 * ------------------------------------------------------
2480 * NONE LEFT RIGHT LEFTRIGHT DIAGONALDOWN
2481 * TOP BOTTOM TOPBOTTOM OUTER DIAGONALUP
2482 * ------------------------------------------------------
2483 * HOR HORINNER VERINNER ALL CRISSCROSS <- can be switched of via bParagraphMode
2486 sal_uInt16 i = 0;
2488 // diagonal borders available only for Calc.
2489 // Therefore, Calc uses 10 border types while
2490 // Writer uses 8 of them - for a single cell.
2491 for ( i=1; i < (m_bIsWriter ? 9 : 11); i++ )
2492 mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
2494 //bParagraphMode should have been set in StateChanged
2495 if ( !bParagraphMode )
2496 // when multiple cell selected:
2497 // Writer has 12 border types and Calc has 15 of them.
2498 for ( i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
2499 mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
2501 // adjust frame column for Writer
2502 sal_uInt16 colCount = m_bIsWriter ? 4 : 5;
2503 mxFrameSet->SetColCount( colCount );
2504 mxFrameSet->SetSelectHdl( LINK( this, SvxFrameWindow_Impl, SelectHdl ) );
2505 CalcSizeValueSet();
2507 mxFrameSet->SetHelpId( HID_POPUP_FRAME );
2508 mxFrameSet->SetAccessibleName( SvxResId(RID_SVXSTR_FRAME) );
2511 namespace {
2513 enum class FrmValidFlags {
2514 NONE = 0x00,
2515 Left = 0x01,
2516 Right = 0x02,
2517 Top = 0x04,
2518 Bottom = 0x08,
2519 HInner = 0x10,
2520 VInner = 0x20,
2521 AllMask = 0x3f,
2526 namespace o3tl {
2527 template<> struct typed_flags<FrmValidFlags> : is_typed_flags<FrmValidFlags, 0x3f> {};
2530 // By default unset lines remain unchanged.
2531 // Via Shift unset lines are reset
2533 IMPL_LINK_NOARG(SvxFrameWindow_Impl, SelectHdl, ValueSet*, void)
2535 SvxBoxItem aBorderOuter( SID_ATTR_BORDER_OUTER );
2536 SvxBoxInfoItem aBorderInner( SID_ATTR_BORDER_INNER );
2537 SvxBorderLine theDefLine;
2539 // diagonal down border
2540 SvxBorderLine dDownBorderLine(nullptr, SvxBorderLineWidth::Hairline);
2541 SvxLineItem dDownLineItem(SID_ATTR_BORDER_DIAG_TLBR);
2543 // diagonal up border
2544 SvxBorderLine dUpBorderLine(nullptr, SvxBorderLineWidth::Hairline);
2545 SvxLineItem dUpLineItem(SID_ATTR_BORDER_DIAG_BLTR);
2547 bool bIsDiagonalBorder = false;
2549 SvxBorderLine *pLeft = nullptr,
2550 *pRight = nullptr,
2551 *pTop = nullptr,
2552 *pBottom = nullptr;
2553 sal_uInt16 nSel = mxFrameSet->GetSelectedItemId();
2554 sal_uInt16 nModifier = mxFrameSet->GetModifier();
2555 FrmValidFlags nValidFlags = FrmValidFlags::NONE;
2557 // tdf#48622, tdf#145828 use correct default to create intended 0.75pt
2558 // cell border using the border formatting tool in the standard toolbar
2559 theDefLine.GuessLinesWidths(theDefLine.GetBorderLineStyle(), SvxBorderLineWidth::Thin);
2561 // nSel has 15 cases which means 15 border
2562 // types for Calc. But Writer uses only 12
2563 // of them - when diagonal borders excluded.
2564 if (m_bIsWriter)
2566 // add appropriate increments
2567 // to match the correct borders.
2568 if (nSel > 8) { nSel += 2; }
2569 else if (nSel > 4) { nSel++; }
2572 switch ( nSel )
2574 case 1: nValidFlags |= FrmValidFlags::AllMask;
2575 // set nullptr to remove diagonal lines
2576 dDownLineItem.SetLine(nullptr);
2577 dUpLineItem.SetLine(nullptr);
2578 SetDiagonalDownBorder(dDownLineItem);
2579 SetDiagonalUpBorder(dUpLineItem);
2580 break; // NONE
2581 case 2: pLeft = &theDefLine;
2582 nValidFlags |= FrmValidFlags::Left;
2583 break; // LEFT
2584 case 3: pRight = &theDefLine;
2585 nValidFlags |= FrmValidFlags::Right;
2586 break; // RIGHT
2587 case 4: pLeft = pRight = &theDefLine;
2588 nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left;
2589 break; // LEFTRIGHT
2590 case 5: dDownLineItem.SetLine(&dDownBorderLine);
2591 SetDiagonalDownBorder(dDownLineItem);
2592 bIsDiagonalBorder = true;
2593 break; // DIAGONAL DOWN
2594 case 6: pTop = &theDefLine;
2595 nValidFlags |= FrmValidFlags::Top;
2596 break; // TOP
2597 case 7: pBottom = &theDefLine;
2598 nValidFlags |= FrmValidFlags::Bottom;
2599 break; // BOTTOM
2600 case 8: pTop = pBottom = &theDefLine;
2601 nValidFlags |= FrmValidFlags::Bottom|FrmValidFlags::Top;
2602 break; // TOPBOTTOM
2603 case 9: pLeft = pRight = pTop = pBottom = &theDefLine;
2604 nValidFlags |= FrmValidFlags::Left | FrmValidFlags::Right | FrmValidFlags::Top | FrmValidFlags::Bottom;
2605 break; // OUTER
2606 case 10:
2607 dUpLineItem.SetLine(&dUpBorderLine);
2608 SetDiagonalUpBorder(dUpLineItem);
2609 bIsDiagonalBorder = true;
2610 break; // DIAGONAL UP
2612 // Inner Table:
2613 case 11: // HOR
2614 pTop = pBottom = &theDefLine;
2615 aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
2616 aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
2617 nValidFlags |= FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
2618 break;
2620 case 12: // HORINNER
2621 pLeft = pRight = pTop = pBottom = &theDefLine;
2622 aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
2623 aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
2624 nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
2625 break;
2627 case 13: // VERINNER
2628 pLeft = pRight = pTop = pBottom = &theDefLine;
2629 aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::HORI );
2630 aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT );
2631 nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::VInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
2632 break;
2634 case 14: // ALL
2635 pLeft = pRight = pTop = pBottom = &theDefLine;
2636 aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
2637 aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT );
2638 nValidFlags |= FrmValidFlags::AllMask;
2639 break;
2641 case 15:
2642 // set both diagonal lines to draw criss-cross line
2643 dDownLineItem.SetLine(&dDownBorderLine);
2644 dUpLineItem.SetLine(&dUpBorderLine);
2646 SetDiagonalDownBorder(dDownLineItem);
2647 SetDiagonalUpBorder(dUpLineItem);
2648 bIsDiagonalBorder = true;
2649 break; // CRISS-CROSS
2651 default:
2652 break;
2655 // if diagonal borders selected,
2656 // no need to execute this block
2657 if (!bIsDiagonalBorder)
2659 aBorderOuter.SetLine( pLeft, SvxBoxItemLine::LEFT );
2660 aBorderOuter.SetLine( pRight, SvxBoxItemLine::RIGHT );
2661 aBorderOuter.SetLine( pTop, SvxBoxItemLine::TOP );
2662 aBorderOuter.SetLine( pBottom, SvxBoxItemLine::BOTTOM );
2664 if(nModifier == KEY_SHIFT)
2665 nValidFlags |= FrmValidFlags::AllMask;
2666 aBorderInner.SetValid( SvxBoxInfoItemValidFlags::TOP, bool(nValidFlags&FrmValidFlags::Top ));
2667 aBorderInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, bool(nValidFlags&FrmValidFlags::Bottom ));
2668 aBorderInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, bool(nValidFlags&FrmValidFlags::Left));
2669 aBorderInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, bool(nValidFlags&FrmValidFlags::Right ));
2670 aBorderInner.SetValid( SvxBoxInfoItemValidFlags::HORI, bool(nValidFlags&FrmValidFlags::HInner ));
2671 aBorderInner.SetValid( SvxBoxInfoItemValidFlags::VERT, bool(nValidFlags&FrmValidFlags::VInner));
2672 aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
2673 aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISABLE, false );
2675 Any a1, a2;
2676 aBorderOuter.QueryValue( a1 );
2677 aBorderInner.QueryValue( a2 );
2678 Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("OuterBorder", a1),
2679 comphelper::makePropertyValue("InnerBorder", a2) };
2681 mxControl->dispatchCommand( ".uno:SetBorderStyle", aArgs );
2684 // coverity[ check_after_deref : FALSE]
2685 if (mxFrameSet)
2687 /* #i33380# Moved the following line above the Dispatch() call.
2688 This instance may be deleted in the meantime (i.e. when a dialog is opened
2689 while in Dispatch()), accessing members will crash in this case. */
2690 mxFrameSet->SetNoSelection();
2693 mxControl->EndPopupMode();
2696 void SvxFrameWindow_Impl::SetDiagonalDownBorder(const SvxLineItem& dDownLineItem)
2698 // apply diagonal down border
2699 Any a;
2700 dDownLineItem.QueryValue(a);
2701 Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderTLBR", a) };
2703 mxControl->dispatchCommand(".uno:BorderTLBR", aArgs);
2706 void SvxFrameWindow_Impl::SetDiagonalUpBorder(const SvxLineItem& dUpLineItem)
2708 // apply diagonal up border
2709 Any a;
2710 dUpLineItem.QueryValue(a);
2711 Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderBLTR", a) };
2713 mxControl->dispatchCommand(".uno:BorderBLTR", aArgs);
2716 void SvxFrameWindow_Impl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
2718 if ( rEvent.FeatureURL.Complete != ".uno:BorderReducedMode" )
2719 return;
2721 bool bValue;
2722 if ( !(rEvent.State >>= bValue) )
2723 return;
2725 bParagraphMode = bValue;
2726 //initial calls mustn't insert or remove elements
2727 if(!mxFrameSet->GetItemCount())
2728 return;
2730 // set 12 border types for Writer, otherwise 15 for Calc.
2731 bool bTableMode = ( mxFrameSet->GetItemCount() == static_cast<size_t>(m_bIsWriter ? 12 : 15) );
2732 bool bResize = false;
2734 if ( bTableMode && bParagraphMode )
2736 for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
2737 mxFrameSet->RemoveItem(i);
2738 bResize = true;
2740 else if ( !bTableMode && !bParagraphMode )
2742 for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
2743 mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
2744 bResize = true;
2747 if ( bResize )
2749 CalcSizeValueSet();
2753 void SvxFrameWindow_Impl::CalcSizeValueSet()
2755 weld::DrawingArea* pDrawingArea = mxFrameSet->GetDrawingArea();
2756 const OutputDevice& rDevice = pDrawingArea->get_ref_device();
2757 Size aItemSize( 20 * rDevice.GetDPIScaleFactor(), 20 * rDevice.GetDPIScaleFactor() );
2758 Size aSize = mxFrameSet->CalcWindowSizePixel( aItemSize );
2759 pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
2760 mxFrameSet->SetOutputSizePixel(aSize);
2763 void SvxFrameWindow_Impl::InitImageList()
2765 if (m_bIsWriter)
2767 // Writer-specific aImgVec.
2768 // Since Writer doesn't have diagonal borders,
2769 // we have to use 12 border types here.
2770 aImgVec = {
2771 {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)},
2772 {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)},
2773 {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)},
2774 {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)},
2776 {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)},
2777 {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)},
2778 {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)},
2779 {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)},
2781 {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)},
2782 {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)},
2783 {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)},
2784 {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)}
2787 else
2789 // Calc has diagonal borders feature.
2790 // Therefore use additional 3 diagonal border types,
2791 // which make border types 15 in total.
2792 aImgVec = {
2793 {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)},
2794 {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)},
2795 {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)},
2796 {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)},
2797 {BitmapEx(RID_SVXBMP_FRAME14), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALDOWN)}, // diagonal down border
2799 {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)},
2800 {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)},
2801 {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)},
2802 {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)},
2803 {BitmapEx(RID_SVXBMP_FRAME13), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALUP)}, // diagonal up border
2805 {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)},
2806 {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)},
2807 {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)},
2808 {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)},
2809 {BitmapEx(RID_SVXBMP_FRAME15), SvxResId(RID_SVXSTR_PARA_PRESET_CRISSCROSS)} // criss-cross border
2814 static Color lcl_mediumColor( Color aMain, Color /*aDefault*/ )
2816 return SvxBorderLine::threeDMediumColor( aMain );
2819 SvxLineWindow_Impl::SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent)
2820 : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder")
2821 , m_xControl(pControl)
2822 , m_xLineStyleLb(new LineListBox)
2823 , m_xLineStyleLbWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xLineStyleLb))
2824 , m_bIsWriter(false)
2828 Reference< lang::XServiceInfo > xServices(m_xFrame->getController()->getModel(), UNO_QUERY_THROW);
2829 m_bIsWriter = xServices->supportsService("com.sun.star.text.TextDocument");
2831 catch(const uno::Exception& )
2835 m_xLineStyleLb->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
2837 m_xLineStyleLb->SetSourceUnit( FieldUnit::TWIP );
2838 m_xLineStyleLb->SetNone( comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE)
2839 :SvxResId(RID_SVXSTR_NONE) );
2841 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::SOLID ), SvxBorderLineStyle::SOLID );
2842 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOTTED ), SvxBorderLineStyle::DOTTED );
2843 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DASHED ), SvxBorderLineStyle::DASHED );
2845 // Double lines
2846 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOUBLE ), SvxBorderLineStyle::DOUBLE );
2847 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_SMALLGAP ), SvxBorderLineStyle::THINTHICK_SMALLGAP, 20 );
2848 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_MEDIUMGAP ), SvxBorderLineStyle::THINTHICK_MEDIUMGAP );
2849 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_LARGEGAP ), SvxBorderLineStyle::THINTHICK_LARGEGAP );
2850 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_SMALLGAP ), SvxBorderLineStyle::THICKTHIN_SMALLGAP, 20 );
2851 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_MEDIUMGAP ), SvxBorderLineStyle::THICKTHIN_MEDIUMGAP );
2852 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_LARGEGAP ), SvxBorderLineStyle::THICKTHIN_LARGEGAP );
2854 // Engraved / Embossed
2855 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::EMBOSSED ), SvxBorderLineStyle::EMBOSSED, 15,
2856 &SvxBorderLine::threeDLightColor, &SvxBorderLine::threeDDarkColor,
2857 &lcl_mediumColor );
2858 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::ENGRAVED ), SvxBorderLineStyle::ENGRAVED, 15,
2859 &SvxBorderLine::threeDDarkColor, &SvxBorderLine::threeDLightColor,
2860 &lcl_mediumColor );
2862 // Inset / Outset
2863 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::OUTSET ), SvxBorderLineStyle::OUTSET, 10,
2864 &SvxBorderLine::lightColor, &SvxBorderLine::darkColor );
2865 m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::INSET ), SvxBorderLineStyle::INSET, 10,
2866 &SvxBorderLine::darkColor, &SvxBorderLine::lightColor );
2867 Size aSize = m_xLineStyleLb->SetWidth( 20 ); // 1pt by default
2869 m_xLineStyleLb->SetSelectHdl( LINK( this, SvxLineWindow_Impl, SelectHdl ) );
2871 m_xContainer->set_help_id(HID_POPUP_LINE);
2873 aSize.AdjustWidth(6);
2874 aSize.AdjustHeight(6);
2875 aSize = m_xLineStyleLb->CalcWindowSizePixel(aSize);
2876 m_xLineStyleLb->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
2877 m_xLineStyleLb->SetOutputSizePixel(aSize);
2880 IMPL_LINK_NOARG(SvxLineWindow_Impl, SelectHdl, ValueSet*, void)
2882 SvxLineItem aLineItem( SID_FRAME_LINESTYLE );
2883 SvxBorderLineStyle nStyle = m_xLineStyleLb->GetSelectEntryStyle();
2885 if ( m_xLineStyleLb->GetSelectItemPos( ) > 0 )
2887 SvxBorderLine aTmp;
2888 aTmp.SetBorderLineStyle( nStyle );
2889 aTmp.SetWidth( SvxBorderLineWidth::Thin ); // TODO Make it depend on a width field
2890 aLineItem.SetLine( &aTmp );
2892 else
2893 aLineItem.SetLine( nullptr );
2895 Any a;
2896 aLineItem.QueryValue( a, m_bIsWriter ? CONVERT_TWIPS : 0 );
2897 Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("LineStyle", a) };
2899 m_xControl->dispatchCommand( ".uno:LineStyle", aArgs );
2901 m_xControl->EndPopupMode();
2904 SfxStyleControllerItem_Impl::SfxStyleControllerItem_Impl(
2905 const Reference< XDispatchProvider >& rDispatchProvider,
2906 sal_uInt16 nSlotId, // Family-ID
2907 const OUString& rCommand, // .uno: command bound to this item
2908 SvxStyleToolBoxControl& rTbxCtl ) // controller instance, which the item is assigned to.
2909 : SfxStatusListener( rDispatchProvider, nSlotId, rCommand ),
2910 rControl( rTbxCtl )
2914 void SfxStyleControllerItem_Impl::StateChangedAtStatusListener(
2915 SfxItemState eState, const SfxPoolItem* pState )
2917 switch ( GetId() )
2919 case SID_STYLE_FAMILY1:
2920 case SID_STYLE_FAMILY2:
2921 case SID_STYLE_FAMILY3:
2922 case SID_STYLE_FAMILY4:
2923 case SID_STYLE_FAMILY5:
2925 const sal_uInt16 nIdx = GetId() - SID_STYLE_FAMILY_START;
2927 if ( SfxItemState::DEFAULT == eState )
2929 const SfxTemplateItem* pStateItem =
2930 dynamic_cast<const SfxTemplateItem*>( pState );
2931 DBG_ASSERT( pStateItem != nullptr, "SfxTemplateItem expected" );
2932 rControl.SetFamilyState( nIdx, pStateItem );
2934 else
2935 rControl.SetFamilyState( nIdx, nullptr );
2936 break;
2941 struct SvxStyleToolBoxControl::Impl
2943 OUString aClearForm;
2944 OUString aMore;
2945 ::std::vector< std::pair< OUString, OUString > > aDefaultStyles;
2946 bool bSpecModeWriter;
2947 bool bSpecModeCalc;
2949 VclPtr<SvxStyleBox_Impl> m_xVclBox;
2950 std::unique_ptr<SvxStyleBox_Base> m_xWeldBox;
2951 SvxStyleBox_Base* m_pBox;
2953 Impl()
2954 :aClearForm ( SvxResId( RID_SVXSTR_CLEARFORM ) )
2955 ,aMore ( SvxResId( RID_SVXSTR_MORE_STYLES ) )
2956 ,bSpecModeWriter ( false )
2957 ,bSpecModeCalc ( false )
2958 ,m_pBox ( nullptr )
2963 void InitializeStyles(const Reference < frame::XModel >& xModel)
2965 aDefaultStyles.clear();
2967 //now convert the default style names to the localized names
2970 Reference< style::XStyleFamiliesSupplier > xStylesSupplier( xModel, UNO_QUERY_THROW );
2971 Reference< lang::XServiceInfo > xServices( xModel, UNO_QUERY_THROW );
2972 bSpecModeWriter = xServices->supportsService("com.sun.star.text.TextDocument");
2973 if(bSpecModeWriter)
2975 Reference<container::XNameAccess> xParaStyles;
2976 xStylesSupplier->getStyleFamilies()->getByName("ParagraphStyles") >>=
2977 xParaStyles;
2978 static const std::vector<OUString> aWriterStyles =
2980 "Standard",
2981 "Text body",
2982 "Title",
2983 "Subtitle",
2984 "Heading 1",
2985 "Heading 2",
2986 "Heading 3",
2987 "Heading 4",
2988 "Quotations",
2989 "Preformatted Text"
2991 for( const OUString& aStyle: aWriterStyles )
2995 Reference< beans::XPropertySet > xStyle;
2996 xParaStyles->getByName( aStyle ) >>= xStyle;
2997 OUString sName;
2998 xStyle->getPropertyValue("DisplayName") >>= sName;
2999 if( !sName.isEmpty() )
3000 aDefaultStyles.push_back(
3001 std::pair<OUString, OUString>(aStyle, sName) );
3003 catch( const uno::Exception& )
3008 else if( (
3009 bSpecModeCalc = xServices->supportsService(
3010 "com.sun.star.sheet.SpreadsheetDocument")))
3012 static const char* aCalcStyles[] =
3014 "Default",
3015 "Accent 1",
3016 "Accent 2",
3017 "Accent 3",
3018 "Heading 1",
3019 "Heading 2",
3020 "Result"
3022 Reference<container::XNameAccess> xCellStyles;
3023 xStylesSupplier->getStyleFamilies()->getByName("CellStyles") >>= xCellStyles;
3024 for(const char* pCalcStyle : aCalcStyles)
3028 const OUString sStyleName( OUString::createFromAscii( pCalcStyle ) );
3029 if( xCellStyles->hasByName( sStyleName ) )
3031 Reference< beans::XPropertySet > xStyle( xCellStyles->getByName( sStyleName), UNO_QUERY_THROW );
3032 OUString sName;
3033 xStyle->getPropertyValue("DisplayName") >>= sName;
3034 if( !sName.isEmpty() )
3035 aDefaultStyles.push_back(
3036 std::pair<OUString, OUString>(sStyleName, sName) );
3039 catch( const uno::Exception& )
3044 catch(const uno::Exception& )
3046 OSL_FAIL("error while initializing style names");
3051 // mapping table from bound items. BE CAREFUL this table must be in the
3052 // same order as the uno commands bound to the slots SID_STYLE_FAMILY1..n
3053 // MAX_FAMILIES must also be correctly set!
3054 static const char* StyleSlotToStyleCommand[MAX_FAMILIES] =
3056 ".uno:CharStyle",
3057 ".uno:ParaStyle",
3058 ".uno:FrameStyle",
3059 ".uno:PageStyle",
3060 ".uno:TemplateFamily5"
3063 SvxStyleToolBoxControl::SvxStyleToolBoxControl()
3064 : pImpl(new Impl)
3065 , pStyleSheetPool(nullptr)
3066 , nActFamily(0xffff)
3068 for (sal_uInt16 i = 0; i < MAX_FAMILIES; ++i)
3070 m_xBoundItems[i].clear();
3071 pFamilyState[i] = nullptr;
3075 SvxStyleToolBoxControl::~SvxStyleToolBoxControl()
3079 void SAL_CALL SvxStyleToolBoxControl::initialize(const Sequence<Any>& rArguments)
3081 svt::ToolboxController::initialize(rArguments);
3083 // After initialize we should have a valid frame member where we can retrieve our
3084 // dispatch provider.
3085 if ( !m_xFrame.is() )
3086 return;
3088 pImpl->InitializeStyles(m_xFrame->getController()->getModel());
3089 Reference< XDispatchProvider > xDispatchProvider( m_xFrame->getController(), UNO_QUERY );
3090 for ( sal_uInt16 i=0; i<MAX_FAMILIES; i++ )
3092 m_xBoundItems[i] = new SfxStyleControllerItem_Impl( xDispatchProvider,
3093 SID_STYLE_FAMILY_START + i,
3094 OUString::createFromAscii( StyleSlotToStyleCommand[i] ),
3095 *this );
3096 pFamilyState[i] = nullptr;
3100 // XComponent
3101 void SAL_CALL SvxStyleToolBoxControl::dispose()
3103 svt::ToolboxController::dispose();
3105 SolarMutexGuard aSolarMutexGuard;
3106 pImpl->m_xVclBox.disposeAndClear();
3107 pImpl->m_xWeldBox.reset();
3108 pImpl->m_pBox = nullptr;
3110 for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems)
3112 if (!pBoundItem)
3113 continue;
3114 pBoundItem->UnBind();
3116 unbindListener();
3118 for( sal_uInt16 i=0; i<MAX_FAMILIES; i++ )
3120 if ( m_xBoundItems[i].is() )
3124 m_xBoundItems[i]->dispose();
3126 catch ( Exception& )
3130 m_xBoundItems[i].clear();
3132 pFamilyState[i].reset();
3134 pStyleSheetPool = nullptr;
3135 pImpl.reset();
3138 OUString SvxStyleToolBoxControl::getImplementationName()
3140 return "com.sun.star.comp.svx.StyleToolBoxControl";
3143 sal_Bool SvxStyleToolBoxControl::supportsService( const OUString& rServiceName )
3145 return cppu::supportsService( this, rServiceName );
3148 css::uno::Sequence< OUString > SvxStyleToolBoxControl::getSupportedServiceNames()
3150 return { "com.sun.star.frame.ToolbarController" };
3153 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3154 com_sun_star_comp_svx_StyleToolBoxControl_get_implementation(
3155 css::uno::XComponentContext*,
3156 css::uno::Sequence<css::uno::Any> const & )
3158 return cppu::acquire( new SvxStyleToolBoxControl() );
3161 void SAL_CALL SvxStyleToolBoxControl::update()
3163 for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems)
3164 pBoundItem->ReBind();
3165 bindListener();
3168 SfxStyleFamily SvxStyleToolBoxControl::GetActFamily() const
3170 switch ( nActFamily-1 + SID_STYLE_FAMILY_START )
3172 case SID_STYLE_FAMILY1: return SfxStyleFamily::Char;
3173 case SID_STYLE_FAMILY2: return SfxStyleFamily::Para;
3174 case SID_STYLE_FAMILY3: return SfxStyleFamily::Frame;
3175 case SID_STYLE_FAMILY4: return SfxStyleFamily::Page;
3176 case SID_STYLE_FAMILY5: return SfxStyleFamily::Pseudo;
3177 default:
3178 OSL_FAIL( "unknown style family" );
3179 break;
3181 return SfxStyleFamily::Para;
3184 void SvxStyleToolBoxControl::FillStyleBox()
3186 SvxStyleBox_Base* pBox = pImpl->m_pBox;
3188 DBG_ASSERT( pStyleSheetPool, "StyleSheetPool not found!" );
3189 DBG_ASSERT( pBox, "Control not found!" );
3191 if ( !(pStyleSheetPool && pBox && nActFamily!=0xffff) )
3192 return;
3194 const SfxStyleFamily eFamily = GetActFamily();
3195 SfxStyleSheetBase* pStyle = nullptr;
3196 bool bDoFill = false;
3198 auto xIter = pStyleSheetPool->CreateIterator(eFamily, SfxStyleSearchBits::Used);
3199 sal_uInt16 nCount = xIter->Count();
3201 // Check whether fill is necessary
3202 pStyle = xIter->First();
3203 //!!! TODO: This condition isn't right any longer, because we always show some default entries
3204 //!!! so the list doesn't show the count
3205 if ( nCount != pBox->get_count() )
3207 bDoFill = true;
3209 else
3211 sal_uInt16 i= 0;
3212 while ( pStyle && !bDoFill )
3214 bDoFill = ( pBox->get_text(i) != pStyle->GetName() );
3215 pStyle = xIter->Next();
3216 i++;
3220 if ( !bDoFill )
3221 return;
3223 OUString aStrSel(pBox->get_active_text());
3224 pBox->freeze();
3225 pBox->clear();
3227 std::vector<OUString> aStyles;
3229 // add used styles
3230 pStyle = xIter->Next();
3231 while ( pStyle )
3233 aStyles.push_back(pStyle->GetName());
3234 pStyle = xIter->Next();
3237 if (pImpl->bSpecModeWriter || pImpl->bSpecModeCalc)
3239 pBox->append_text(pImpl->aClearForm);
3240 pBox->insert_separator(1, "separator");
3242 // add default styles if less than 12 items
3243 for( const auto &rStyle : pImpl->aDefaultStyles )
3245 if ( aStyles.size() + pBox->get_count() > 12)
3246 break;
3247 // insert default style only if not used (and added to rStyle before)
3248 if (std::find(aStyles.begin(), aStyles.end(), rStyle.second) >= aStyles.end())
3249 pBox->append_text(rStyle.second);
3252 std::sort(aStyles.begin(), aStyles.end());
3254 for (const auto& rStyle : aStyles)
3255 pBox->append_text(rStyle);
3257 if ((pImpl->bSpecModeWriter || pImpl->bSpecModeCalc) && !comphelper::LibreOfficeKit::isActive())
3258 pBox->append_text(pImpl->aMore);
3260 pBox->thaw();
3261 pBox->set_active_or_entry_text(aStrSel);
3262 pBox->SetFamily( eFamily );
3265 void SvxStyleToolBoxControl::SelectStyle( const OUString& rStyleName )
3267 SvxStyleBox_Base* pBox = pImpl->m_pBox;
3268 DBG_ASSERT( pBox, "Control not found!" );
3270 if ( !pBox )
3271 return;
3273 OUString aStrSel(pBox->get_active_text());
3275 if ( !rStyleName.isEmpty() )
3277 OUString aNewStyle = rStyleName;
3279 auto aFound = std::find_if(pImpl->aDefaultStyles.begin(), pImpl->aDefaultStyles.end(),
3280 [rStyleName] (auto it) { return it.first == rStyleName || it.second == rStyleName; }
3283 if (aFound != pImpl->aDefaultStyles.end())
3284 aNewStyle = aFound->second;
3286 if ( aNewStyle != aStrSel )
3287 pBox->set_active_or_entry_text( aNewStyle );
3289 else
3290 pBox->set_active(-1);
3291 pBox->save_value();
3294 void SvxStyleToolBoxControl::Update()
3296 SfxStyleSheetBasePool* pPool = nullptr;
3297 SfxObjectShell* pDocShell = SfxObjectShell::Current();
3299 if ( pDocShell )
3300 pPool = pDocShell->GetStyleSheetPool();
3302 sal_uInt16 i;
3303 for ( i=0; i<MAX_FAMILIES; i++ )
3304 if( pFamilyState[i] )
3305 break;
3307 if ( i==MAX_FAMILIES || !pPool )
3309 pStyleSheetPool = pPool;
3310 return;
3314 const SfxTemplateItem* pItem = nullptr;
3316 if ( nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get()) )
3317 // Current range not within allowed ranges or default
3319 pStyleSheetPool = pPool;
3320 nActFamily = 2;
3322 pItem = pFamilyState[nActFamily-1].get();
3323 if ( !pItem )
3325 nActFamily++;
3326 pItem = pFamilyState[nActFamily-1].get();
3329 else if ( pPool != pStyleSheetPool )
3330 pStyleSheetPool = pPool;
3332 FillStyleBox(); // Decides by itself whether Fill is needed
3334 if ( pItem )
3335 SelectStyle( pItem->GetStyleName() );
3338 void SvxStyleToolBoxControl::SetFamilyState( sal_uInt16 nIdx,
3339 const SfxTemplateItem* pItem )
3341 pFamilyState[nIdx].reset( pItem == nullptr ? nullptr : new SfxTemplateItem( *pItem ) );
3342 Update();
3345 void SvxStyleToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
3347 SolarMutexGuard aGuard;
3349 if (m_pToolbar)
3350 m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled);
3351 else
3353 ToolBox* pToolBox = nullptr;
3354 ToolBoxItemId nId;
3355 if (!getToolboxId( nId, &pToolBox ) )
3356 return;
3357 pToolBox->EnableItem( nId, rEvent.IsEnabled );
3360 if (rEvent.IsEnabled)
3361 Update();
3364 css::uno::Reference<css::awt::XWindow> SvxStyleToolBoxControl::createItemWindow(const css::uno::Reference< css::awt::XWindow>& rParent)
3366 uno::Reference< awt::XWindow > xItemWindow;
3368 if (m_pBuilder)
3370 SolarMutexGuard aSolarMutexGuard;
3372 std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("applystyle"));
3374 xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
3376 pImpl->m_xWeldBox.reset(new SvxStyleBox_Base(std::move(xWidget),
3377 ".uno:StyleApply",
3378 SfxStyleFamily::Para,
3379 m_xFrame,
3380 pImpl->aClearForm,
3381 pImpl->aMore,
3382 pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this));
3383 pImpl->m_pBox = pImpl->m_xWeldBox.get();
3385 else
3387 VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent);
3388 if ( pParent )
3390 SolarMutexGuard aSolarMutexGuard;
3392 pImpl->m_xVclBox = VclPtr<SvxStyleBox_Impl>::Create(pParent,
3393 ".uno:StyleApply",
3394 SfxStyleFamily::Para,
3395 m_xFrame,
3396 pImpl->aClearForm,
3397 pImpl->aMore,
3398 pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this);
3399 pImpl->m_pBox = pImpl->m_xVclBox.get();
3400 xItemWindow = VCLUnoHelper::GetInterface(pImpl->m_xVclBox);
3404 if (pImpl->m_pBox && !pImpl->aDefaultStyles.empty())
3405 pImpl->m_pBox->SetDefaultStyle(pImpl->aDefaultStyles[0].second);
3407 return xItemWindow;
3410 SvxFontNameToolBoxControl::SvxFontNameToolBoxControl()
3411 : m_pBox(nullptr)
3415 void SvxFontNameBox_Base::statusChanged_Impl( const css::frame::FeatureStateEvent& rEvent )
3417 if ( !rEvent.IsEnabled )
3419 set_sensitive(false);
3420 Update( nullptr );
3422 else
3424 set_sensitive(true);
3426 css::awt::FontDescriptor aFontDesc;
3427 if ( rEvent.State >>= aFontDesc )
3428 Update(&aFontDesc);
3429 else {
3430 // no active element; delete value in the display
3431 m_xWidget->set_active(-1);
3432 set_active_or_entry_text("");
3434 m_xWidget->save_value();
3438 void SvxFontNameToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
3440 SolarMutexGuard aGuard;
3441 m_pBox->statusChanged_Impl(rEvent);
3443 if (m_pToolbar)
3444 m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled);
3445 else
3447 ToolBox* pToolBox = nullptr;
3448 ToolBoxItemId nId;
3449 if (!getToolboxId( nId, &pToolBox ) )
3450 return;
3451 pToolBox->EnableItem( nId, rEvent.IsEnabled );
3455 css::uno::Reference<css::awt::XWindow> SvxFontNameToolBoxControl::createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent)
3457 uno::Reference< awt::XWindow > xItemWindow;
3459 if (m_pBuilder)
3461 SolarMutexGuard aSolarMutexGuard;
3463 std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("fontnamecombobox"));
3465 xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
3467 m_xWeldBox.reset(new SvxFontNameBox_Base(std::move(xWidget), m_xFrame, *this));
3468 m_pBox = m_xWeldBox.get();
3470 else
3472 VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent);
3473 if ( pParent )
3475 SolarMutexGuard aSolarMutexGuard;
3476 m_xVclBox = VclPtr<SvxFontNameBox_Impl>::Create(pParent, m_xFrame, *this);
3477 m_pBox = m_xVclBox.get();
3478 xItemWindow = VCLUnoHelper::GetInterface(m_xVclBox);
3482 return xItemWindow;
3485 void SvxFontNameToolBoxControl::dispose()
3487 ToolboxController::dispose();
3489 SolarMutexGuard aSolarMutexGuard;
3490 m_xVclBox.disposeAndClear();
3491 m_xWeldBox.reset();
3492 m_pBox = nullptr;
3495 OUString SvxFontNameToolBoxControl::getImplementationName()
3497 return "com.sun.star.comp.svx.FontNameToolBoxControl";
3500 sal_Bool SvxFontNameToolBoxControl::supportsService( const OUString& rServiceName )
3502 return cppu::supportsService( this, rServiceName );
3505 css::uno::Sequence< OUString > SvxFontNameToolBoxControl::getSupportedServiceNames()
3507 return { "com.sun.star.frame.ToolbarController" };
3510 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3511 com_sun_star_comp_svx_FontNameToolBoxControl_get_implementation(
3512 css::uno::XComponentContext*,
3513 css::uno::Sequence<css::uno::Any> const & )
3515 return cppu::acquire( new SvxFontNameToolBoxControl() );
3518 SvxColorToolBoxControl::SvxColorToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) :
3519 ImplInheritanceHelper( rContext, nullptr, OUString() ),
3520 m_bSplitButton(true),
3521 m_nSlotId(0),
3522 m_aColorSelectFunction(PaletteManager::DispatchColorCommand)
3526 namespace {
3528 sal_uInt16 MapCommandToSlotId(const OUString& rCommand)
3530 if (rCommand == ".uno:Color")
3531 return SID_ATTR_CHAR_COLOR;
3532 else if (rCommand == ".uno:FontColor")
3533 return SID_ATTR_CHAR_COLOR2;
3534 else if (rCommand == ".uno:BackColor") // deprecated - use CharBackColor
3535 return SID_ATTR_CHAR_COLOR_BACKGROUND;
3536 else if (rCommand == ".uno:CharBackColor")
3537 return SID_ATTR_CHAR_BACK_COLOR;
3538 else if (rCommand == ".uno:BackgroundColor")
3539 return SID_BACKGROUND_COLOR;
3540 else if (rCommand == ".uno:TableCellBackgroundColor")
3541 return SID_TABLE_CELL_BACKGROUND_COLOR;
3542 else if (rCommand == ".uno:Extrusion3DColor")
3543 return SID_EXTRUSION_3D_COLOR;
3544 else if (rCommand == ".uno:XLineColor")
3545 return SID_ATTR_LINE_COLOR;
3546 else if (rCommand == ".uno:FillColor")
3547 return SID_ATTR_FILL_COLOR;
3548 else if (rCommand == ".uno:FrameLineColor")
3549 return SID_FRAME_LINECOLOR;
3551 SAL_WARN("svx.tbxcrtls", "Unknown color command: " << rCommand);
3552 return 0;
3557 void SvxColorToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>& rArguments )
3559 PopupWindowController::initialize( rArguments );
3561 m_nSlotId = MapCommandToSlotId( m_aCommandURL );
3563 if ( m_nSlotId == SID_ATTR_LINE_COLOR || m_nSlotId == SID_ATTR_FILL_COLOR ||
3564 m_nSlotId == SID_FRAME_LINECOLOR || m_nSlotId == SID_BACKGROUND_COLOR )
3566 // Sidebar uses wide buttons for those.
3567 m_bSplitButton = !m_bSidebar;
3570 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(getCommandURL(), getModuleName());
3571 OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
3573 if (m_pToolbar)
3575 mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
3576 m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
3577 m_xBtnUpdater.reset(new svx::ToolboxButtonColorUpdater(m_nSlotId, m_aCommandURL, m_pToolbar, !m_bSplitButton, aCommandLabel, m_xFrame));
3578 return;
3581 ToolBox* pToolBox = nullptr;
3582 ToolBoxItemId nId;
3583 if (getToolboxId(nId, &pToolBox))
3585 m_xBtnUpdater.reset( new svx::VclToolboxButtonColorUpdater( m_nSlotId, nId, pToolBox, !m_bSplitButton, aCommandLabel, m_aCommandURL, m_xFrame ) );
3586 pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ( m_bSplitButton ? ToolBoxItemBits::DROPDOWN : ToolBoxItemBits::DROPDOWNONLY ) );
3590 void SvxColorToolBoxControl::update()
3592 PopupWindowController::update();
3594 switch( m_nSlotId )
3596 case SID_ATTR_CHAR_COLOR2:
3597 addStatusListener( ".uno:CharColorExt");
3598 break;
3600 case SID_ATTR_CHAR_BACK_COLOR:
3601 case SID_ATTR_CHAR_COLOR_BACKGROUND:
3602 addStatusListener( ".uno:CharBackgroundExt");
3603 break;
3605 case SID_FRAME_LINECOLOR:
3606 addStatusListener( ".uno:BorderTLBR");
3607 addStatusListener( ".uno:BorderBLTR");
3608 break;
3612 void SvxColorToolBoxControl::EnsurePaletteManager()
3614 if (!m_xPaletteManager)
3616 m_xPaletteManager = std::make_shared<PaletteManager>();
3617 m_xPaletteManager->SetBtnUpdater(m_xBtnUpdater.get());
3621 SvxColorToolBoxControl::~SvxColorToolBoxControl()
3623 if (m_xPaletteManager)
3624 m_xPaletteManager->SetBtnUpdater(nullptr);
3627 void SvxColorToolBoxControl::setColorSelectFunction(const ColorSelectFunction& aColorSelectFunction)
3629 m_aColorSelectFunction = aColorSelectFunction;
3630 if (m_xPaletteManager)
3631 m_xPaletteManager->SetColorSelectFunction(aColorSelectFunction);
3634 weld::Window* SvxColorToolBoxControl::GetParentFrame() const
3636 const css::uno::Reference<css::awt::XWindow> xParent = m_xFrame->getContainerWindow();
3637 return Application::GetFrameWeld(xParent);
3640 std::unique_ptr<WeldToolbarPopup> SvxColorToolBoxControl::weldPopupWindow()
3642 EnsurePaletteManager();
3644 auto xPopover = std::make_unique<ColorWindow>(
3645 m_aCommandURL,
3646 m_xPaletteManager,
3647 m_aColorStatus,
3648 m_nSlotId,
3649 m_xFrame,
3650 MenuOrToolMenuButton(m_pToolbar, m_aCommandURL),
3651 [this] { return GetParentFrame(); },
3652 m_aColorSelectFunction);
3654 return xPopover;
3657 VclPtr<vcl::Window> SvxColorToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
3659 ToolBox* pToolBox = nullptr;
3660 ToolBoxItemId nId;
3661 if (!getToolboxId(nId, &pToolBox))
3662 return nullptr;
3664 EnsurePaletteManager();
3666 auto xPopover = std::make_unique<ColorWindow>(
3667 m_aCommandURL,
3668 m_xPaletteManager,
3669 m_aColorStatus,
3670 m_nSlotId,
3671 m_xFrame,
3672 MenuOrToolMenuButton(this, pToolBox, nId),
3673 [this] { return GetParentFrame(); },
3674 m_aColorSelectFunction);
3676 mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
3677 std::move(xPopover), true);
3679 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(m_aCommandURL, m_sModuleName);
3680 OUString aWindowTitle = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
3681 mxInterimPopover->SetText(aWindowTitle);
3683 mxInterimPopover->Show();
3685 return mxInterimPopover;
3688 void SvxColorToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
3690 ToolBox* pToolBox = nullptr;
3691 ToolBoxItemId nId;
3692 if (!getToolboxId(nId, &pToolBox) && !m_pToolbar)
3693 return;
3695 if ( rEvent.FeatureURL.Complete == m_aCommandURL )
3697 if (m_pToolbar)
3698 m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled);
3699 else
3700 pToolBox->EnableItem( nId, rEvent.IsEnabled );
3703 bool bValue;
3704 if ( !m_bSplitButton )
3706 m_aColorStatus.statusChanged( rEvent );
3707 m_xBtnUpdater->Update( m_aColorStatus.GetColor() );
3709 else if ( rEvent.State >>= bValue )
3711 if (m_pToolbar)
3712 m_pToolbar->set_item_active(m_aCommandURL, bValue);
3713 else if (pToolBox)
3714 pToolBox->CheckItem( nId, bValue );
3718 void SvxColorToolBoxControl::execute(sal_Int16 /*nSelectModifier*/)
3720 if ( !m_bSplitButton )
3722 if (m_pToolbar)
3724 // Toggle the popup also when toolbutton is activated
3725 m_pToolbar->set_menu_item_active(m_aCommandURL, !m_pToolbar->get_menu_item_active(m_aCommandURL));
3727 else
3729 // Open the popup also when Enter key is pressed.
3730 createPopupWindow();
3732 return;
3735 OUString aCommand = m_aCommandURL;
3736 Color aColor = m_xBtnUpdater->GetCurrentColor();
3738 switch( m_nSlotId )
3740 case SID_ATTR_CHAR_COLOR2 :
3741 aCommand = ".uno:CharColorExt";
3742 break;
3745 auto aArgs( comphelper::InitPropertySequence( {
3746 { m_aCommandURL.copy(5), css::uno::Any(aColor) }
3747 } ) );
3748 dispatchCommand( aCommand, aArgs );
3750 EnsurePaletteManager();
3751 OUString sColorName = m_xBtnUpdater->GetCurrentColorName();
3752 m_xPaletteManager->AddRecentColor(aColor, sColorName);
3755 sal_Bool SvxColorToolBoxControl::opensSubToolbar()
3757 // We mark this controller as a sub-toolbar controller, so we get notified
3758 // (through updateImage method) on button image changes, and could redraw
3759 // the last used color on top of it.
3760 return true;
3763 void SvxColorToolBoxControl::updateImage()
3765 m_xBtnUpdater->Update(m_xBtnUpdater->GetCurrentColor(), true);
3768 OUString SvxColorToolBoxControl::getSubToolbarName()
3770 return OUString();
3773 void SvxColorToolBoxControl::functionSelected( const OUString& /*rCommand*/ )
3777 OUString SvxColorToolBoxControl::getImplementationName()
3779 return "com.sun.star.comp.svx.ColorToolBoxControl";
3782 css::uno::Sequence<OUString> SvxColorToolBoxControl::getSupportedServiceNames()
3784 return { "com.sun.star.frame.ToolbarController" };
3787 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3788 com_sun_star_comp_svx_ColorToolBoxControl_get_implementation(
3789 css::uno::XComponentContext* rContext,
3790 css::uno::Sequence<css::uno::Any> const & )
3792 return cppu::acquire( new SvxColorToolBoxControl( rContext ) );
3795 SvxFrameToolBoxControl::SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext )
3796 : svt::PopupWindowController( rContext, nullptr, OUString() )
3800 void SAL_CALL SvxFrameToolBoxControl::execute(sal_Int16 /*KeyModifier*/)
3802 if (m_pToolbar)
3804 // Toggle the popup also when toolbutton is activated
3805 m_pToolbar->set_menu_item_active(m_aCommandURL, !m_pToolbar->get_menu_item_active(m_aCommandURL));
3807 else
3809 // Open the popup also when Enter key is pressed.
3810 createPopupWindow();
3814 void SvxFrameToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
3816 svt::PopupWindowController::initialize( rArguments );
3818 if (m_pToolbar)
3820 mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
3821 m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
3824 ToolBox* pToolBox = nullptr;
3825 ToolBoxItemId nId;
3826 if (getToolboxId(nId, &pToolBox))
3827 pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
3830 std::unique_ptr<WeldToolbarPopup> SvxFrameToolBoxControl::weldPopupWindow()
3832 if ( m_aCommandURL == ".uno:LineStyle" )
3833 return std::make_unique<SvxLineWindow_Impl>(this, m_pToolbar);
3834 return std::make_unique<SvxFrameWindow_Impl>(this, m_pToolbar);
3837 VclPtr<vcl::Window> SvxFrameToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
3839 if ( m_aCommandURL == ".uno:LineStyle" )
3841 mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
3842 std::make_unique<SvxLineWindow_Impl>(this, pParent->GetFrameWeld()), true);
3844 mxInterimPopover->Show();
3846 mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME_STYLE));
3848 return mxInterimPopover;
3851 mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
3852 std::make_unique<SvxFrameWindow_Impl>(this, pParent->GetFrameWeld()), true);
3854 mxInterimPopover->Show();
3856 mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME));
3858 return mxInterimPopover;
3861 OUString SvxFrameToolBoxControl::getImplementationName()
3863 return "com.sun.star.comp.svx.FrameToolBoxControl";
3866 css::uno::Sequence< OUString > SvxFrameToolBoxControl::getSupportedServiceNames()
3868 return { "com.sun.star.frame.ToolbarController" };
3871 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3872 com_sun_star_comp_svx_FrameToolBoxControl_get_implementation(
3873 css::uno::XComponentContext* rContext,
3874 css::uno::Sequence<css::uno::Any> const & )
3876 return cppu::acquire( new SvxFrameToolBoxControl( rContext ) );
3879 SvxCurrencyToolBoxControl::SvxCurrencyToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) :
3880 PopupWindowController( rContext, nullptr, OUString() ),
3881 m_eLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ),
3882 m_nFormatKey( NUMBERFORMAT_ENTRY_NOT_FOUND )
3886 SvxCurrencyToolBoxControl::~SvxCurrencyToolBoxControl() {}
3888 namespace
3890 /** Implementation of the currency combo widget **/
3891 class SvxCurrencyList_Impl : public WeldToolbarPopup
3893 private:
3894 rtl::Reference<SvxCurrencyToolBoxControl> m_xControl;
3895 std::unique_ptr<weld::Label> m_xLabel;
3896 std::unique_ptr<weld::TreeView> m_xCurrencyLb;
3897 std::unique_ptr<weld::Button> m_xOkBtn;
3898 OUString& m_rSelectedFormat;
3899 LanguageType& m_eSelectedLanguage;
3901 std::vector<OUString> m_aFormatEntries;
3902 LanguageType m_eFormatLanguage;
3903 DECL_LINK(RowActivatedHdl, weld::TreeView&, bool);
3904 DECL_LINK(OKHdl, weld::Button&, void);
3906 virtual void GrabFocus() override;
3908 public:
3909 SvxCurrencyList_Impl(SvxCurrencyToolBoxControl* pControl, weld::Widget* pParent, OUString& rSelectedFormat, LanguageType& eSelectedLanguage)
3910 : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/currencywindow.ui", "CurrencyWindow")
3911 , m_xControl(pControl)
3912 , m_xLabel(m_xBuilder->weld_label("label"))
3913 , m_xCurrencyLb(m_xBuilder->weld_tree_view("currency"))
3914 , m_xOkBtn(m_xBuilder->weld_button("ok"))
3915 , m_rSelectedFormat(rSelectedFormat)
3916 , m_eSelectedLanguage(eSelectedLanguage)
3918 const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
3919 sal_uInt16 nLen = rCurrencyTable.size();
3921 SvNumberFormatter aFormatter( m_xControl->getContext(), LANGUAGE_SYSTEM );
3922 m_eFormatLanguage = aFormatter.GetLanguage();
3924 const SvxCurrencyToolBoxControl::SvxCurrencyVect_t &rCurrencies = pControl->GetCurrencySymbols( );
3926 sal_uInt16 nPos = 0, nCount = 0;
3927 sal_Int32 nSelectedPos = -1;
3928 bool bIsSymbol;
3929 NfWSStringsDtor aStringsDtor;
3931 OUString sLongestString;
3933 m_xCurrencyLb->freeze();
3934 for( const SvxCurrencyToolBoxControl::SvxCurrencyData& curr : rCurrencies )
3936 const OUString& rItem = curr.m_label;
3937 sal_uInt16 rCurrencyIndex = rCurrencies[ nCount ].m_currencyIdx;
3939 if ( rCurrencyIndex < nLen )
3941 m_xCurrencyLb->append_text(rItem);
3943 if (rItem.getLength() > sLongestString.getLength())
3944 sLongestString = rItem;
3946 bIsSymbol = nPos >= nLen;
3948 sal_uInt16 nDefaultFormat;
3949 const NfCurrencyEntry& rCurrencyEntry = rCurrencyTable[ rCurrencyIndex ];
3950 if (rCurrencyIndex == 0)
3952 // Stored with system locale, but we want the resolved
3953 // full LCID format string. For example
3954 // "[$$-409]#,##0.00" instead of "[$$]#,##0.00".
3955 NfCurrencyEntry aCurrencyEntry( rCurrencyEntry);
3956 aCurrencyEntry.SetLanguage( LanguageTag( aCurrencyEntry.GetLanguage()).getLanguageType());
3957 nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, aCurrencyEntry, bIsSymbol);
3959 else
3961 nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, rCurrencyEntry, bIsSymbol);
3963 const OUString& rFormatStr = aStringsDtor[ nDefaultFormat ];
3964 m_aFormatEntries.push_back( rFormatStr );
3965 if( rFormatStr == m_rSelectedFormat )
3966 nSelectedPos = nPos;
3967 ++nPos;
3969 ++nCount;
3971 m_xCurrencyLb->thaw();
3972 // enable multiple selection enabled so we can start with nothing selected
3973 m_xCurrencyLb->set_selection_mode(SelectionMode::Multiple);
3974 m_xCurrencyLb->connect_row_activated( LINK( this, SvxCurrencyList_Impl, RowActivatedHdl ) );
3975 m_xLabel->set_label(SvxResId(RID_SVXSTR_TBLAFMT_CURRENCY));
3976 m_xCurrencyLb->select( nSelectedPos );
3977 m_xOkBtn->connect_clicked(LINK(this, SvxCurrencyList_Impl, OKHdl));
3979 // gtk will initially make a best guess depending on the first few entries, so copy the probable
3980 // longest entry to the start temporarily and force in the width at this point
3981 m_xCurrencyLb->insert_text(0, sLongestString);
3982 m_xCurrencyLb->set_size_request(m_xCurrencyLb->get_preferred_size().Width(), m_xCurrencyLb->get_height_rows(12));
3983 m_xCurrencyLb->remove(0);
3987 void SvxCurrencyList_Impl::GrabFocus()
3989 m_xCurrencyLb->grab_focus();
3992 IMPL_LINK_NOARG(SvxCurrencyList_Impl, OKHdl, weld::Button&, void)
3994 RowActivatedHdl(*m_xCurrencyLb);
3997 IMPL_LINK_NOARG(SvxCurrencyList_Impl, RowActivatedHdl, weld::TreeView&, bool)
3999 if (!m_xControl.is())
4000 return true;
4002 // multiple selection enabled so we can start with nothing selected,
4003 // so force single selection after something is picked
4004 int nSelected = m_xCurrencyLb->get_selected_index();
4005 if (nSelected == -1)
4006 return true;
4008 m_xCurrencyLb->set_selection_mode(SelectionMode::Single);
4010 m_rSelectedFormat = m_aFormatEntries[nSelected];
4011 m_eSelectedLanguage = m_eFormatLanguage;
4013 m_xControl->execute(nSelected + 1);
4015 m_xCurrencyLb->scroll_to_row(0);
4017 m_xControl->EndPopupMode();
4019 return true;
4023 void SvxCurrencyToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
4025 PopupWindowController::initialize(rArguments);
4027 if (m_pToolbar)
4029 mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
4030 m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
4031 return;
4034 ToolBox* pToolBox = nullptr;
4035 ToolBoxItemId nId;
4036 if (getToolboxId(nId, &pToolBox) && pToolBox->GetItemCommand(nId) == m_aCommandURL)
4037 pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWN | pToolBox->GetItemBits(nId));
4040 const SvxCurrencyToolBoxControl::SvxCurrencyVect_t &SvxCurrencyToolBoxControl::GetCurrencySymbols( ) {
4041 inner_GetCurrencySymbols( true, m_currencies, m_mru_currencies );
4042 return m_currencies;
4045 void SvxCurrencyToolBoxControl::addMruCurrency(sal_Int16 currencyPosition) {
4046 if (currencyPosition == 1)
4047 return;
4049 const SvxCurrencyData& curr = m_currencies[currencyPosition];
4050 auto currencyIter = std::find( m_mru_currencies.begin(), m_mru_currencies.end(), curr );
4052 if ( currencyIter != m_mru_currencies.end() )
4053 m_mru_currencies.erase( currencyIter );
4055 m_mru_currencies.insert( m_mru_currencies.begin(), curr );
4056 if (m_mru_currencies.size() > MAX_MRU_CURRENCIES)
4057 m_mru_currencies.resize( MAX_MRU_CURRENCIES );
4060 std::unique_ptr<WeldToolbarPopup> SvxCurrencyToolBoxControl::weldPopupWindow()
4062 return std::make_unique<SvxCurrencyList_Impl>(this, m_pToolbar, m_aFormatString, m_eLanguage);
4065 VclPtr<vcl::Window> SvxCurrencyToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
4067 mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
4068 std::make_unique<SvxCurrencyList_Impl>(this, pParent->GetFrameWeld(), m_aFormatString, m_eLanguage));
4070 mxInterimPopover->Show();
4072 return mxInterimPopover;
4075 void SvxCurrencyToolBoxControl::execute( sal_Int16 nSelectModifier )
4077 sal_uInt32 nFormatKey;
4078 if (m_aFormatString.isEmpty())
4079 nFormatKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
4080 else
4082 if ( nSelectModifier > 0 )
4086 uno::Reference< util::XNumberFormatsSupplier > xRef( m_xFrame->getController()->getModel(), uno::UNO_QUERY );
4087 uno::Reference< util::XNumberFormats > rxNumberFormats( xRef->getNumberFormats(), uno::UNO_SET_THROW );
4088 css::lang::Locale aLocale = LanguageTag::convertToLocale( m_eLanguage );
4089 nFormatKey = rxNumberFormats->queryKey( m_aFormatString, aLocale, false );
4090 if ( nFormatKey == NUMBERFORMAT_ENTRY_NOT_FOUND )
4091 nFormatKey = rxNumberFormats->addNew( m_aFormatString, aLocale );
4092 addMruCurrency(nSelectModifier);
4094 catch( const uno::Exception& )
4096 nFormatKey = m_nFormatKey;
4099 else
4100 nFormatKey = m_nFormatKey;
4103 if( nFormatKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
4105 Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("NumberFormatCurrency",
4106 nFormatKey) };
4107 dispatchCommand( m_aCommandURL, aArgs );
4108 m_nFormatKey = nFormatKey;
4110 else
4111 PopupWindowController::execute( nSelectModifier );
4114 OUString SvxCurrencyToolBoxControl::getImplementationName()
4116 return "com.sun.star.comp.svx.CurrencyToolBoxControl";
4119 css::uno::Sequence<OUString> SvxCurrencyToolBoxControl::getSupportedServiceNames()
4121 return { "com.sun.star.frame.ToolbarController" };
4124 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
4125 com_sun_star_comp_svx_CurrencyToolBoxControl_get_implementation(
4126 css::uno::XComponentContext* rContext,
4127 css::uno::Sequence<css::uno::Any> const & )
4129 return cppu::acquire( new SvxCurrencyToolBoxControl( rContext ) );
4132 Reference< css::accessibility::XAccessible > SvxFontNameBox_Impl::CreateAccessible()
4134 FillList();
4135 return InterimItemWindow::CreateAccessible();
4138 //static
4139 sal_uInt16 const SvxCurrencyToolBoxControl::SvxCurrencyData::InvalidCurrency = INVALID_CURRENCY;
4141 SvxCurrencyToolBoxControl::SvxCurrencyData::SvxCurrencyData(
4142 sal_uInt16 currencyIdx,
4143 bool onlyIsoCode
4145 m_currencyIdx(currencyIdx),
4146 m_onlyIsoCode(onlyIsoCode)
4149 bool SvxCurrencyToolBoxControl::SvxCurrencyData::operator == (const SvxCurrencyData& other) const
4151 return
4152 (m_currencyIdx == other.m_currencyIdx) &&
4153 (m_onlyIsoCode == other.m_onlyIsoCode);
4156 //static
4157 void SvxCurrencyToolBoxControl::GetCurrencySymbols( std::vector<OUString>& rList, bool bFlag,
4158 std::vector<sal_uInt16>& rCurrencyList )
4160 SvxCurrencyVect_t currencies, mru_currencies;
4162 inner_GetCurrencySymbols(bFlag, currencies, mru_currencies);
4164 rList.resize(currencies.size());
4165 rCurrencyList.resize(currencies.size());
4167 for (size_t j = 0; j < currencies.size(); j++) {
4168 rList[j] = std::move(currencies[j].m_label);
4169 rCurrencyList[j] = currencies[j].m_currencyIdx;
4173 //static
4174 void SvxCurrencyToolBoxControl::inner_GetCurrencySymbols(
4175 bool bFlag,
4176 SvxCurrencyVect_t &pCurrencies,
4177 SvxCurrencyVect_t &p_mru_currencies)
4179 const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
4180 sal_uInt16 nCount = rCurrencyTable.size();
4182 // reserving space for mru currencies on top of vector after -1 element
4183 pCurrencies.resize( p_mru_currencies.size() + 1);
4184 std::fill( pCurrencies.begin() + 1, pCurrencies.end(), SvxCurrencyData() );
4186 // lambda for vector insertion: mru currencies are on top
4187 auto addCurrency = [&pCurrencies, &p_mru_currencies]
4188 (SvxCurrencyData& curr, size_t position = SIZE_MAX)
4190 auto mruIter = std::find(p_mru_currencies.begin(), p_mru_currencies.end(), curr);
4192 if (mruIter == p_mru_currencies.end()) {
4193 if (position == SIZE_MAX)
4194 pCurrencies.push_back( std::move(curr) );
4195 else
4196 pCurrencies.insert( pCurrencies.begin() + position, std::move(curr) );
4198 else {
4199 size_t index = mruIter - p_mru_currencies.begin();
4200 pCurrencies[index] = std::move(curr);
4204 SvxCurrencyData aCurr( sal_uInt16(-1) );
4205 aCurr.m_label = ApplyLreOrRleEmbedding( rCurrencyTable[0].GetSymbol() ) + " ";
4206 aCurr.m_label += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString(
4207 rCurrencyTable[0].GetLanguage() ) );
4209 pCurrencies[0] = aCurr;
4210 if( bFlag ) {
4211 aCurr.m_currencyIdx = 0;
4212 addCurrency( aCurr );
4215 sal_uInt16 nStart = pCurrencies.size();
4217 CollatorWrapper aCollator( ::comphelper::getProcessComponentContext() );
4218 aCollator.loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 );
4220 static constexpr OUString aTwoSpace(u" "_ustr);
4222 // appending "long symbol" list
4223 for( sal_uInt16 i = 1; i < nCount; ++i )
4225 SvxCurrencyData curr( i );
4226 curr.m_label = ApplyLreOrRleEmbedding( rCurrencyTable[i].GetBankSymbol() );
4227 curr.m_label += aTwoSpace;
4228 curr.m_label += ApplyLreOrRleEmbedding( rCurrencyTable[i].GetSymbol() );
4229 curr.m_label += aTwoSpace;
4230 curr.m_label += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString(
4231 rCurrencyTable[i].GetLanguage() ) );
4233 SvxCurrencyVect_t::size_type j = nStart;
4234 for( ; j < pCurrencies.size(); ++j )
4235 if ( aCollator.compareString( curr.m_label, pCurrencies[j].m_label ) < 0 )
4236 break; // insert before first greater than
4238 addCurrency( curr, j );
4241 // Append ISO codes to symbol list.
4242 // XXX If this is to be changed, various other places would had to be
4243 // adapted that assume this order!
4244 size_t nCont = pCurrencies.size();
4246 for ( sal_uInt16 i = 1; i < nCount; ++i )
4248 bool bInsert = true;
4249 SvxCurrencyData curr( i, true );
4250 curr.m_label = ApplyLreOrRleEmbedding(rCurrencyTable[i].GetBankSymbol());
4252 size_t j = nCont;
4253 for ( ; j < pCurrencies.size() && bInsert; ++j )
4255 if( pCurrencies[j].m_label == curr.m_label )
4256 bInsert = false;
4257 else if ( aCollator.compareString( curr.m_label, pCurrencies[j].m_label ) < 0 )
4258 break; // insert before first greater than
4260 if ( bInsert )
4261 addCurrency( curr, j );
4264 for ( int j = p_mru_currencies.size() - 1; j > 0; j-- )
4265 if ( pCurrencies[j].m_currencyIdx == SvxCurrencyData::InvalidCurrency )
4266 pCurrencies.erase( pCurrencies.begin() + j );
4269 ListBoxColorWrapper::ListBoxColorWrapper(ColorListBox* pControl)
4270 : mpControl(pControl)
4274 void ListBoxColorWrapper::operator()(
4275 [[maybe_unused]] const OUString& /*rCommand*/, const NamedColor& rColor)
4277 mpControl->Selected(rColor);
4280 void ColorListBox::EnsurePaletteManager()
4282 if (!m_xPaletteManager)
4284 m_xPaletteManager = std::make_shared<PaletteManager>();
4285 m_xPaletteManager->SetColorSelectFunction(std::ref(m_aColorWrapper));
4289 void ColorListBox::SetSlotId(sal_uInt16 nSlotId, bool bShowNoneButton)
4291 m_nSlotId = nSlotId;
4292 m_bShowNoneButton = bShowNoneButton;
4293 m_xButton->set_popover(nullptr);
4294 m_xColorWindow.reset();
4295 m_aSelectedColor = bShowNoneButton ? GetNoneColor() : GetAutoColor(m_nSlotId);
4296 ShowPreview(m_aSelectedColor);
4297 createColorWindow();
4300 ColorListBox::ColorListBox(std::unique_ptr<weld::MenuButton> pControl,
4301 TopLevelParentFunction aTopLevelParentFunction,
4302 const ColorListBox* pCache)
4303 : m_xButton(std::move(pControl))
4304 , m_aColorWrapper(this)
4305 , m_aAutoDisplayColor(Application::GetSettings().GetStyleSettings().GetDialogColor())
4306 , m_nSlotId(0)
4307 , m_bShowNoneButton(false)
4308 , m_aTopLevelParentFunction(std::move(aTopLevelParentFunction))
4310 m_xButton->connect_toggled(LINK(this, ColorListBox, ToggleHdl));
4311 m_aSelectedColor = GetAutoColor(m_nSlotId);
4312 if (!pCache)
4313 LockWidthRequest(CalcBestWidthRequest());
4314 else
4316 LockWidthRequest(pCache->m_xButton->get_size_request().Width());
4317 m_xPaletteManager.reset(pCache->m_xPaletteManager->Clone());
4318 m_xPaletteManager->SetColorSelectFunction(std::ref(m_aColorWrapper));
4320 ShowPreview(m_aSelectedColor);
4323 IMPL_LINK(ColorListBox, ToggleHdl, weld::Toggleable&, rButton, void)
4325 if (rButton.get_active())
4327 ColorWindow* pColorWindow = getColorWindow();
4328 if (pColorWindow && !comphelper::LibreOfficeKit::isActive())
4329 pColorWindow->GrabFocus();
4333 ColorListBox::~ColorListBox()
4337 ColorWindow* ColorListBox::getColorWindow() const
4339 if (!m_xColorWindow)
4340 const_cast<ColorListBox*>(this)->createColorWindow();
4341 return m_xColorWindow.get();
4344 void ColorListBox::createColorWindow()
4346 const SfxViewFrame* pViewFrame = SfxViewFrame::Current();
4347 const SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
4348 css::uno::Reference<css::frame::XFrame> xFrame(pFrame ? pFrame->GetFrameInterface() : uno::Reference<css::frame::XFrame>());
4350 EnsurePaletteManager();
4352 m_xColorWindow.reset(new ColorWindow(
4353 OUString() /*m_aCommandURL*/,
4354 m_xPaletteManager,
4355 m_aColorStatus,
4356 m_nSlotId,
4357 xFrame,
4358 m_xButton.get(),
4359 m_aTopLevelParentFunction,
4360 m_aColorWrapper));
4362 SetNoSelection();
4363 m_xButton->set_popover(m_xColorWindow->getTopLevel());
4364 if (m_bShowNoneButton)
4365 m_xColorWindow->ShowNoneButton();
4366 m_xColorWindow->SelectEntry(m_aSelectedColor);
4369 void ColorListBox::SelectEntry(const NamedColor& rColor)
4371 if (o3tl::trim(rColor.m_aName).empty())
4373 SelectEntry(rColor.m_aColor);
4374 return;
4376 ColorWindow* pColorWindow = getColorWindow();
4377 pColorWindow->SelectEntry(rColor);
4378 m_aSelectedColor = pColorWindow->GetSelectEntryColor();
4379 ShowPreview(m_aSelectedColor);
4382 void ColorListBox::SelectEntry(const Color& rColor)
4384 ColorWindow* pColorWindow = getColorWindow();
4385 pColorWindow->SelectEntry(rColor);
4386 m_aSelectedColor = pColorWindow->GetSelectEntryColor();
4387 ShowPreview(m_aSelectedColor);
4390 void ColorListBox::Selected(const NamedColor& rColor)
4392 ShowPreview(rColor);
4393 m_aSelectedColor = rColor;
4394 if (m_aSelectedLink.IsSet())
4395 m_aSelectedLink.Call(*this);
4398 //to avoid the box resizing every time the color is changed to
4399 //the optimal size of the individual color, get the longest
4400 //standard color and stick with that as the size for all
4401 int ColorListBox::CalcBestWidthRequest()
4403 NamedColor aLongestColor;
4404 tools::Long nMaxStandardColorTextWidth = 0;
4405 XColorListRef const xColorTable = XColorList::CreateStdColorList();
4406 for (tools::Long i = 0; i != xColorTable->Count(); ++i)
4408 XColorEntry& rEntry = *xColorTable->GetColor(i);
4409 auto nColorTextWidth = m_xButton->get_pixel_size(rEntry.GetName()).Width();
4410 if (nColorTextWidth > nMaxStandardColorTextWidth)
4412 nMaxStandardColorTextWidth = nColorTextWidth;
4413 aLongestColor.m_aName = rEntry.GetName();
4416 ShowPreview(aLongestColor);
4417 return m_xButton->get_preferred_size().Width();
4420 void ColorListBox::LockWidthRequest(int nWidth)
4422 m_xButton->set_size_request(nWidth, -1);
4425 void ColorListBox::ShowPreview(const NamedColor &rColor)
4427 // ScGridWindow::UpdateAutoFilterFromMenu is similar
4428 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
4429 Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
4431 ScopedVclPtrInstance<VirtualDevice> xDevice;
4432 xDevice->SetOutputSize(aImageSize);
4433 const tools::Rectangle aRect(Point(0, 0), aImageSize);
4434 if (m_bShowNoneButton && rColor.m_aColor == COL_NONE_COLOR)
4436 const Color aW(COL_WHITE);
4437 const Color aG(0xef, 0xef, 0xef);
4438 int nMinDim = std::min(aImageSize.Width(), aImageSize.Height()) + 1;
4439 int nCheckSize = nMinDim / 3;
4440 xDevice->DrawCheckered(aRect.TopLeft(), aRect.GetSize(), std::min(nCheckSize, 8), aW, aG);
4441 xDevice->SetFillColor();
4443 else
4445 if (rColor.m_aColor == COL_AUTO)
4446 xDevice->SetFillColor(m_aAutoDisplayColor);
4447 else
4448 xDevice->SetFillColor(rColor.m_aColor);
4451 xDevice->SetLineColor(rStyleSettings.GetDisableColor());
4452 xDevice->DrawRect(aRect);
4454 m_xButton->set_image(xDevice.get());
4455 m_xButton->set_label(rColor.m_aName);
4458 MenuOrToolMenuButton::MenuOrToolMenuButton(weld::MenuButton* pMenuButton)
4459 : m_pMenuButton(pMenuButton)
4460 , m_pToolbar(nullptr)
4461 , m_pControl(nullptr)
4462 , m_nId(0)
4466 MenuOrToolMenuButton::MenuOrToolMenuButton(weld::Toolbar* pToolbar, OUString aIdent)
4467 : m_pMenuButton(nullptr)
4468 , m_pToolbar(pToolbar)
4469 , m_aIdent(std::move(aIdent))
4470 , m_pControl(nullptr)
4471 , m_nId(0)
4475 MenuOrToolMenuButton::MenuOrToolMenuButton(SvxColorToolBoxControl* pControl, ToolBox* pToolbar, ToolBoxItemId nId)
4476 : m_pMenuButton(nullptr)
4477 , m_pToolbar(nullptr)
4478 , m_pControl(pControl)
4479 , m_xToolBox(pToolbar)
4480 , m_nId(nId)
4484 MenuOrToolMenuButton::~MenuOrToolMenuButton()
4488 bool MenuOrToolMenuButton::get_active() const
4490 if (m_pMenuButton)
4491 return m_pMenuButton->get_active();
4492 if (m_pToolbar)
4493 return m_pToolbar->get_menu_item_active(m_aIdent);
4494 return m_xToolBox->GetDownItemId() == m_nId;
4497 void MenuOrToolMenuButton::set_inactive() const
4499 if (m_pMenuButton)
4501 if (m_pMenuButton->get_active())
4502 m_pMenuButton->set_active(false);
4503 return;
4505 if (m_pToolbar)
4507 if (m_pToolbar->get_menu_item_active(m_aIdent))
4508 m_pToolbar->set_menu_item_active(m_aIdent, false);
4509 return;
4511 m_pControl->EndPopupMode();
4514 weld::Widget* MenuOrToolMenuButton::get_widget() const
4516 if (m_pMenuButton)
4517 return m_pMenuButton;
4518 if (m_pToolbar)
4519 return m_pToolbar;
4520 return m_xToolBox->GetFrameWeld();
4523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */