summaryrefslogtreecommitdiffstats
path: root/svx/source/tbxctrls/tbcontrl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/tbxctrls/tbcontrl.cxx')
-rw-r--r--svx/source/tbxctrls/tbcontrl.cxx4523
1 files changed, 4523 insertions, 0 deletions
diff --git a/svx/source/tbxctrls/tbcontrl.cxx b/svx/source/tbxctrls/tbcontrl.cxx
new file mode 100644
index 0000000000..9a3669aac5
--- /dev/null
+++ b/svx/source/tbxctrls/tbcontrl.cxx
@@ -0,0 +1,4523 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <utility>
+
+#include <comphelper/configurationlistener.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <tools/color.hxx>
+#include <svl/numformat.hxx>
+#include <svl/poolitem.hxx>
+#include <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/event.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/weldutils.hxx>
+#include <svtools/valueset.hxx>
+#include <svtools/ctrlbox.hxx>
+#include <svl/style.hxx>
+#include <svtools/ctrltool.hxx>
+#include <svtools/borderhelper.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <sfx2/tplpitem.hxx>
+#include <sfx2/sfxstatuslistener.hxx>
+#include <sfx2/viewsh.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <helpids.h>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <svx/xtable.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/svxfont.hxx>
+#include <editeng/cmapitem.hxx>
+#include <svx/colorwindow.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/tbcontrl.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/PaletteManager.hxx>
+#include <memory>
+
+#include <tbxcolorupdate.hxx>
+#include <editeng/eerdll.hxx>
+#include <editeng/editrids.hrc>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svl/currencytable.hxx>
+#include <svtools/langtab.hxx>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <bitmaps.hlst>
+#include <sal/log.hxx>
+#include <unotools/collatorwrapper.hxx>
+
+#include <comphelper/lok.hxx>
+#include <tools/json_writer.hxx>
+
+#include <editeng/editeng.hxx>
+
+#define MAX_MRU_FONTNAME_ENTRIES 5
+
+#define COMBO_WIDTH_IN_CHARS 18
+
+#define MAX_MRU_CURRENCIES 5
+
+#define INVALID_CURRENCY sal_uInt16(-2)
+
+// namespaces
+using namespace ::editeng;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+
+namespace
+{
+struct ScriptInfo
+{
+ tools::Long textWidth;
+ SvtScriptType scriptType;
+ sal_Int32 changePos;
+ ScriptInfo(SvtScriptType scrptType, sal_Int32 position)
+ : textWidth(0)
+ , scriptType(scrptType)
+ , changePos(position)
+ {
+ }
+};
+
+class SvxStyleBox_Base
+{
+public:
+ SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget, OUString rCommand, SfxStyleFamily eFamily,
+ const Reference<XFrame>& _xFrame, OUString aClearFormatKey,
+ OUString aMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl);
+
+ virtual ~SvxStyleBox_Base()
+ {
+ }
+
+ void SetFamily( SfxStyleFamily eNewFamily );
+
+ void SetDefaultStyle( const OUString& rDefault ) { sDefaultStyle = rDefault; }
+
+ int get_count() const { return m_xWidget->get_count(); }
+ OUString get_text(int nIndex) const { return m_xWidget->get_text(nIndex); }
+ OUString get_active_text() const { return m_xWidget->get_active_text(); }
+
+ void append_text(const OUString& rStr)
+ {
+ OUString sId(OUString::number(m_xWidget->get_count()));
+ m_xWidget->append(sId, rStr);
+ }
+
+ void insert_separator(int pos, const OUString& rId)
+ {
+ m_xWidget->insert_separator(pos, rId);
+ }
+
+ void set_active_or_entry_text(const OUString& rText)
+ {
+ const int nFound = m_xWidget->find_text(rText);
+ if (nFound != -1)
+ m_xWidget->set_active(nFound);
+ else
+ m_xWidget->set_entry_text(rText);
+ }
+
+ void set_active(int nActive)
+ {
+ m_xWidget->set_active(nActive);
+ }
+
+ void freeze()
+ {
+ m_xWidget->freeze();
+ }
+
+ void save_value()
+ {
+ m_xWidget->save_value();
+ }
+
+ void clear()
+ {
+ m_xWidget->clear();
+ m_nMaxUserDrawFontWidth = 0;
+ }
+
+ void thaw()
+ {
+ m_xWidget->thaw();
+ }
+
+ virtual bool DoKeyInput(const KeyEvent& rKEvt);
+
+private:
+ std::optional<SvxFont> m_oFont;
+ std::optional<SvxFont> m_oCJKFont;
+ std::optional<SvxFont> m_oCTLFont;
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+ DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void);
+ DECL_LINK(CustomRenderHdl, weld::ComboBox::render_args, void);
+ DECL_LINK(CustomGetSizeHdl, OutputDevice&, Size);
+
+ /// Calculate the optimal width of the dropdown. Very expensive operation, triggers lots of font measurement.
+ void CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext);
+
+ void Select(bool bNonTravelSelect);
+
+ tools::Rectangle CalcBoundRect(vcl::RenderContext& rRenderContext, const OUString &rStyleName, std::vector<ScriptInfo>& rScriptChanges, double fRatio = 1);
+
+protected:
+ SvxStyleToolBoxControl& m_rCtrl;
+
+ std::unique_ptr<weld::Builder> m_xMenuBuilder;
+ std::unique_ptr<weld::Menu> m_xMenu;
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+
+ SfxStyleFamily eStyleFamily;
+ int m_nMaxUserDrawFontWidth;
+ int m_nLastItemWithMenu;
+ bool bRelease;
+ Reference< XFrame > m_xFrame;
+ OUString m_aCommand;
+ OUString aClearFormatKey;
+ OUString aMoreKey;
+ OUString sDefaultStyle;
+ bool bInSpecialMode;
+
+ void ReleaseFocus();
+ static Color TestColorsVisible(const Color &FontCol, const Color &BackCol);
+ void UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const tools::Rectangle& rTextRect, const OUString &rStyleName, const std::vector<ScriptInfo>& rScriptChanges);
+ void SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected);
+ DECL_LINK(MenuSelectHdl, const OUString&, void);
+ DECL_STATIC_LINK(SvxStyleBox_Base, ShowMoreHdl, void*, void);
+};
+
+class SvxStyleBox_Impl final : public InterimItemWindow
+ , public SvxStyleBox_Base
+{
+public:
+ SvxStyleBox_Impl(vcl::Window* pParent, const OUString& rCommand, SfxStyleFamily eFamily,
+ const Reference< XFrame >& _xFrame,const OUString& rClearFormatKey, const OUString& rMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl);
+
+ virtual ~SvxStyleBox_Impl() override
+ {
+ disposeOnce();
+ }
+
+ virtual void dispose() override
+ {
+ m_xWidget.reset();
+ m_xMenu.reset();
+ m_xMenuBuilder.reset();
+ InterimItemWindow::dispose();
+ }
+
+ virtual bool DoKeyInput(const KeyEvent& rKEvt) override;
+
+private:
+
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+ void SetOptimalSize();
+};
+
+class SvxFontNameBox_Impl;
+class SvxFontNameBox_Base;
+
+class SvxFontNameToolBoxControl final : public cppu::ImplInheritanceHelper<svt::ToolboxController,
+ css::lang::XServiceInfo>
+{
+public:
+ SvxFontNameToolBoxControl();
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+
+ // XToolbarController
+ virtual css::uno::Reference<css::awt::XWindow> SAL_CALL createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+private:
+ VclPtr<SvxFontNameBox_Impl> m_xVclBox;
+ std::unique_ptr<SvxFontNameBox_Base> m_xWeldBox;
+ SvxFontNameBox_Base* m_pBox;
+};
+
+class FontOptionsListener final : public comphelper::ConfigurationListenerProperty<bool>
+{
+private:
+ SvxFontNameBox_Base& m_rBox;
+
+ virtual void setProperty(const css::uno::Any &rProperty) override;
+public:
+ FontOptionsListener(const rtl::Reference<comphelper::ConfigurationListener>& rListener, const OUString& rProp, SvxFontNameBox_Base& rBox)
+ : comphelper::ConfigurationListenerProperty<bool>(rListener, rProp)
+ , m_rBox(rBox)
+ {
+ }
+};
+
+class SvxFontNameBox_Base
+{
+private:
+ rtl::Reference<comphelper::ConfigurationListener> m_xListener;
+ FontOptionsListener m_aWYSIWYG;
+ FontOptionsListener m_aHistory;
+
+protected:
+ SvxFontNameToolBoxControl& m_rCtrl;
+
+ std::unique_ptr<FontNameBox> m_xWidget;
+ const FontList* pFontList;
+ ::std::unique_ptr<FontList> m_aOwnFontList;
+ vcl::Font aCurFont;
+ sal_uInt16 nFtCount;
+ bool bRelease;
+ Reference< XFrame > m_xFrame;
+ bool mbCheckingUnknownFont;
+ bool mbDropDownActive;
+
+ void ReleaseFocus_Impl();
+
+ void Select(bool bNonTravelSelect);
+
+ void EndPreview()
+ {
+ Sequence< PropertyValue > aArgs;
+ const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
+ SfxToolBoxControl::Dispatch(xProvider, ".uno:CharEndPreviewFontName", aArgs);
+ }
+
+ bool CheckFontIsAvailable(std::u16string_view fontname);
+ void CheckAndMarkUnknownFont();
+
+public:
+ SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget, const Reference<XFrame>& rFrame,
+ SvxFontNameToolBoxControl& rCtrl);
+ virtual ~SvxFontNameBox_Base()
+ {
+ m_xListener->dispose();
+ }
+
+ void FillList();
+ void Update( const css::awt::FontDescriptor* pFontDesc );
+ sal_uInt16 GetListCount() const { return nFtCount; }
+ void Clear() { m_xWidget->clear(); nFtCount = 0; }
+ void Fill( const FontList* pList )
+ {
+ m_xWidget->Fill(pList);
+ nFtCount = pList->GetFontNameCount();
+ }
+
+ void SetOwnFontList(::std::unique_ptr<FontList> && _aOwnFontList) { m_aOwnFontList = std::move(_aOwnFontList); }
+
+ virtual void set_sensitive(bool bSensitive)
+ {
+ m_xWidget->set_sensitive(bSensitive);
+ }
+
+ void set_active_or_entry_text(const OUString& rText);
+
+ void statusChanged_Impl(const css::frame::FeatureStateEvent& rEvent);
+
+ virtual bool DoKeyInput(const KeyEvent& rKEvt);
+
+ void EnableControls();
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+ DECL_LINK(PopupToggledHdl, weld::ComboBox&, void);
+ DECL_LINK(LivePreviewHdl, const FontMetric&, void);
+ DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void);
+};
+
+void FontOptionsListener::setProperty(const css::uno::Any &rProperty)
+{
+ comphelper::ConfigurationListenerProperty<bool>::setProperty(rProperty);
+ m_rBox.EnableControls();
+}
+
+class SvxFontNameBox_Impl final : public InterimItemWindow
+ , public SvxFontNameBox_Base
+{
+private:
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+ virtual void GetFocus() override
+ {
+ if (m_xWidget)
+ m_xWidget->grab_focus();
+ InterimItemWindow::GetFocus();
+ }
+
+ void SetOptimalSize();
+
+ virtual bool DoKeyInput(const KeyEvent& rKEvt) override;
+
+public:
+ SvxFontNameBox_Impl(vcl::Window* pParent,
+ const Reference<XFrame>& rFrame, SvxFontNameToolBoxControl& rCtrl);
+
+ virtual void dispose() override
+ {
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+ }
+
+ virtual ~SvxFontNameBox_Impl() override
+ {
+ disposeOnce();
+ }
+
+ virtual Reference< css::accessibility::XAccessible > CreateAccessible() override;
+
+ virtual void set_sensitive(bool bSensitive) override
+ {
+ m_xWidget->set_sensitive(bSensitive);
+ if (bSensitive)
+ InterimItemWindow::Enable();
+ else
+ InterimItemWindow::Disable();
+ }
+};
+
+
+// SelectHdl needs the Modifiers, get them in MouseButtonUp
+class SvxFrmValueSet_Impl final : public ValueSet
+{
+private:
+ sal_uInt16 nModifier;
+
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override
+ {
+ nModifier = rMEvt.GetModifier();
+ return ValueSet::MouseButtonUp(rMEvt);
+ }
+
+public:
+ SvxFrmValueSet_Impl()
+ : ValueSet(nullptr)
+ , nModifier(0)
+ {
+ }
+ sal_uInt16 GetModifier() const {return nModifier;}
+};
+
+}
+
+namespace {
+
+class SvxFrameToolBoxControl;
+
+class SvxFrameWindow_Impl final : public WeldToolbarPopup
+{
+private:
+ rtl::Reference<SvxFrameToolBoxControl> mxControl;
+ std::unique_ptr<SvxFrmValueSet_Impl> mxFrameSet;
+ std::unique_ptr<weld::CustomWeld> mxFrameSetWin;
+ std::vector<std::pair<BitmapEx, OUString>> aImgVec;
+ bool bParagraphMode;
+ bool m_bIsWriter;
+
+ void InitImageList();
+ void CalcSizeValueSet();
+ DECL_LINK( SelectHdl, ValueSet*, void );
+
+ void SetDiagonalDownBorder(const SvxLineItem& dDownLineItem);
+ void SetDiagonalUpBorder(const SvxLineItem& dUpLineItem);
+
+public:
+ SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent);
+ virtual void GrabFocus() override
+ {
+ mxFrameSet->GrabFocus();
+ }
+
+ virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+};
+
+class SvxFrameToolBoxControl : public svt::PopupWindowController
+{
+public:
+ explicit SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext );
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ virtual void SAL_CALL execute(sal_Int16 nKeyModifier) override;
+private:
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+};
+
+ class LineListBox final : public ValueSet
+ {
+ public:
+ typedef Color (*ColorFunc)(Color);
+ typedef Color (*ColorDistFunc)(Color, Color);
+
+ LineListBox();
+
+ /** Set the width in Twips */
+ Size SetWidth( tools::Long nWidth )
+ {
+ tools::Long nOldWidth = m_nWidth;
+ m_nWidth = nWidth;
+ return UpdateEntries( nOldWidth );
+ }
+
+ void SetNone( const OUString& sNone )
+ {
+ m_sNone = sNone;
+ }
+
+ /** Insert a listbox entry with all widths in Twips. */
+ void InsertEntry(const BorderWidthImpl& rWidthImpl,
+ SvxBorderLineStyle nStyle, tools::Long nMinWidth = 0,
+ ColorFunc pColor1Fn = &sameColor,
+ ColorFunc pColor2Fn = &sameColor,
+ ColorDistFunc pColorDistFn = &sameDistColor);
+
+ SvxBorderLineStyle GetEntryStyle( sal_Int32 nPos ) const;
+
+ SvxBorderLineStyle GetSelectEntryStyle() const;
+
+ void SetSourceUnit( FieldUnit eNewUnit ) { eSourceUnit = eNewUnit; }
+
+ const Color& GetColor() const { return aColor; }
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ private:
+
+ void ImpGetLine(tools::Long nLine1, tools::Long nLine2, tools::Long nDistance,
+ Color nColor1, Color nColor2, Color nColorDist,
+ SvxBorderLineStyle nStyle, BitmapEx& rBmp);
+
+ void UpdatePaintLineColor(); // returns sal_True if maPaintCol has changed
+
+ Size UpdateEntries( tools::Long nOldWidth );
+ sal_Int32 GetStylePos( sal_Int32 nListPos, tools::Long nWidth );
+
+ const Color& GetPaintColor() const
+ {
+ return maPaintCol;
+ }
+
+ Color GetColorLine1( sal_Int32 nPos );
+ Color GetColorLine2( sal_Int32 nPos );
+ Color GetColorDist( sal_Int32 nPos );
+
+ LineListBox( const LineListBox& ) = delete;
+ LineListBox& operator =( const LineListBox& ) = delete;
+
+ std::vector<std::unique_ptr<ImpLineListData>> m_vLineList;
+ tools::Long m_nWidth;
+ OUString m_sNone;
+ ScopedVclPtr<VirtualDevice> aVirDev;
+ Size aTxtSize;
+ Color const aColor;
+ Color maPaintCol;
+ FieldUnit eSourceUnit;
+ };
+
+ SvxBorderLineStyle LineListBox::GetSelectEntryStyle() const
+ {
+ SvxBorderLineStyle nStyle = SvxBorderLineStyle::SOLID;
+ size_t nPos = GetSelectItemPos();
+ if (nPos != VALUESET_ITEM_NOTFOUND)
+ {
+ if (!m_sNone.isEmpty())
+ --nPos;
+ nStyle = GetEntryStyle( nPos );
+ }
+
+ return nStyle;
+ }
+
+ void LineListBox::ImpGetLine( tools::Long nLine1, tools::Long nLine2, tools::Long nDistance,
+ Color aColor1, Color aColor2, Color aColorDist,
+ SvxBorderLineStyle nStyle, BitmapEx& rBmp )
+ {
+ auto nMinWidth = GetDrawingArea()->get_ref_device().approximate_digit_width() * COMBO_WIDTH_IN_CHARS;
+ Size aSize(nMinWidth, aTxtSize.Height());
+ aSize.AdjustWidth( -(aTxtSize.Width()) );
+ aSize.AdjustWidth( -6 );
+
+ // SourceUnit to Twips
+ if ( eSourceUnit == FieldUnit::POINT )
+ {
+ nLine1 /= 5;
+ nLine2 /= 5;
+ nDistance /= 5;
+ }
+
+ // Paint the lines
+ aSize = aVirDev->PixelToLogic( aSize );
+ tools::Long nPix = aVirDev->PixelToLogic( Size( 0, 1 ) ).Height();
+ sal_uInt32 n1 = nLine1;
+ sal_uInt32 n2 = nLine2;
+ tools::Long nDist = nDistance;
+ n1 += nPix-1;
+ n1 -= n1%nPix;
+ if ( n2 )
+ {
+ nDist += nPix-1;
+ nDist -= nDist%nPix;
+ n2 += nPix-1;
+ n2 -= n2%nPix;
+ }
+ tools::Long nVirHeight = n1+nDist+n2;
+ if ( nVirHeight > aSize.Height() )
+ aSize.setHeight( nVirHeight );
+ // negative width should not be drawn
+ if ( aSize.Width() <= 0 )
+ return;
+
+ Size aVirSize = aVirDev->LogicToPixel( aSize );
+ if ( aVirDev->GetOutputSizePixel() != aVirSize )
+ aVirDev->SetOutputSizePixel( aVirSize );
+ aVirDev->SetFillColor( aColorDist );
+ aVirDev->DrawRect( tools::Rectangle( Point(), aSize ) );
+
+ aVirDev->SetFillColor( aColor1 );
+
+ double y1 = double( n1 ) / 2;
+ svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle );
+
+ if ( n2 )
+ {
+ double y2 = n1 + nDist + double( n2 ) / 2;
+ aVirDev->SetFillColor( aColor2 );
+ svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, SvxBorderLineStyle::SOLID );
+ }
+ rBmp = aVirDev->GetBitmapEx( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
+ }
+
+ LineListBox::LineListBox()
+ : ValueSet(nullptr)
+ , m_nWidth( 5 )
+ , aVirDev(VclPtr<VirtualDevice>::Create())
+ , aColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor())
+ , maPaintCol(COL_BLACK)
+ , eSourceUnit(FieldUnit::POINT)
+ {
+ aVirDev->SetLineColor();
+ aVirDev->SetMapMode( MapMode( MapUnit::MapTwip ) );
+ }
+
+ void LineListBox::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+ {
+ ValueSet::SetDrawingArea(pDrawingArea);
+
+ OutputDevice& rDevice = pDrawingArea->get_ref_device();
+
+ aTxtSize.setWidth( rDevice.approximate_digit_width() );
+ aTxtSize.setHeight( rDevice.GetTextHeight() );
+
+ UpdatePaintLineColor();
+ }
+
+ sal_Int32 LineListBox::GetStylePos( sal_Int32 nListPos, tools::Long nWidth )
+ {
+ sal_Int32 nPos = -1;
+ if (!m_sNone.isEmpty())
+ nListPos--;
+
+ sal_Int32 n = 0;
+ size_t i = 0;
+ size_t nCount = m_vLineList.size();
+ while ( nPos == -1 && i < nCount )
+ {
+ auto& pData = m_vLineList[ i ];
+ if ( pData->GetMinWidth() <= nWidth )
+ {
+ if ( nListPos == n )
+ nPos = static_cast<sal_Int32>(i);
+ n++;
+ }
+ i++;
+ }
+
+ return nPos;
+ }
+
+ void LineListBox::InsertEntry(
+ const BorderWidthImpl& rWidthImpl, SvxBorderLineStyle nStyle, tools::Long nMinWidth,
+ ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn )
+ {
+ m_vLineList.emplace_back(new ImpLineListData(
+ rWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn));
+ }
+
+ SvxBorderLineStyle LineListBox::GetEntryStyle( sal_Int32 nPos ) const
+ {
+ ImpLineListData* pData = (0 <= nPos && o3tl::make_unsigned(nPos) < m_vLineList.size()) ? m_vLineList[ nPos ].get() : nullptr;
+ return pData ? pData->GetStyle() : SvxBorderLineStyle::NONE;
+ }
+
+ void LineListBox::UpdatePaintLineColor()
+ {
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ Color aNewCol( rSettings.GetWindowColor().IsDark()? rSettings.GetLabelTextColor() : aColor );
+
+ bool bRet = aNewCol != maPaintCol;
+
+ if( bRet )
+ maPaintCol = aNewCol;
+ }
+
+ Size LineListBox::UpdateEntries( tools::Long nOldWidth )
+ {
+ Size aSize;
+
+ UpdatePaintLineColor( );
+
+ sal_Int32 nSelEntry = GetSelectItemPos();
+ sal_Int32 nTypePos = GetStylePos( nSelEntry, nOldWidth );
+
+ // Remove the old entries
+ Clear();
+
+ sal_uInt16 nId(1);
+
+ // Add the new entries based on the defined width
+ if (!m_sNone.isEmpty())
+ InsertItem(nId++, Image(), m_sNone);
+
+ sal_uInt16 n = 0;
+ sal_uInt16 nCount = m_vLineList.size( );
+ while ( n < nCount )
+ {
+ auto& pData = m_vLineList[ n ];
+ if ( pData->GetMinWidth() <= m_nWidth )
+ {
+ BitmapEx aBmp;
+ ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
+ pData->GetLine2ForWidth( m_nWidth ),
+ pData->GetDistForWidth( m_nWidth ),
+ GetColorLine1( GetItemCount( ) ),
+ GetColorLine2( GetItemCount( ) ),
+ GetColorDist( GetItemCount( ) ),
+ pData->GetStyle(), aBmp );
+ InsertItem(nId, Image(aBmp), SvtLineListBox::GetLineStyleName(pData->GetStyle()));
+ Size aBmpSize = aBmp.GetSizePixel();
+ if (aBmpSize.Width() > aSize.Width())
+ aSize.setWidth(aBmpSize.getWidth());
+ if (aBmpSize.Height() > aSize.Height())
+ aSize.setHeight(aBmpSize.getHeight());
+ if ( n == nTypePos )
+ SelectItem(nId);
+ }
+ else if ( n == nTypePos )
+ SetNoSelection();
+ n++;
+ ++nId;
+ }
+
+ Invalidate();
+
+ return aSize;
+ }
+
+ Color LineListBox::GetColorLine1( sal_Int32 nPos )
+ {
+ sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
+ if (nStyle == -1)
+ return GetPaintColor( );
+ auto& pData = m_vLineList[ nStyle ];
+ return pData->GetColorLine1( GetColor( ) );
+ }
+
+ Color LineListBox::GetColorLine2( sal_Int32 nPos )
+ {
+ sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
+ if (nStyle == -1)
+ return GetPaintColor( );
+ auto& pData = m_vLineList[ nStyle ];
+ return pData->GetColorLine2( GetColor( ) );
+ }
+
+ Color LineListBox::GetColorDist( sal_Int32 nPos )
+ {
+ Color rResult = Application::GetSettings().GetStyleSettings().GetFieldColor();
+
+ sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
+ if (nStyle == -1)
+ return rResult;
+ auto& pData = m_vLineList[ nStyle ];
+ return pData->GetColorDist( GetColor( ), rResult );
+ }
+}
+
+namespace {
+
+class SvxLineWindow_Impl final : public WeldToolbarPopup
+{
+private:
+ rtl::Reference<SvxFrameToolBoxControl> m_xControl;
+ std::unique_ptr<LineListBox> m_xLineStyleLb;
+ std::unique_ptr<weld::CustomWeld> m_xLineStyleLbWin;
+ bool m_bIsWriter;
+
+ DECL_LINK( SelectHdl, ValueSet*, void );
+
+public:
+ SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent);
+ virtual void GrabFocus() override
+ {
+ m_xLineStyleLb->GrabFocus();
+ }
+};
+
+}
+
+class SvxStyleToolBoxControl;
+
+class SfxStyleControllerItem_Impl : public SfxStatusListener
+{
+ public:
+ SfxStyleControllerItem_Impl( const Reference< XDispatchProvider >& rDispatchProvider,
+ sal_uInt16 nSlotId,
+ const OUString& rCommand,
+ SvxStyleToolBoxControl& rTbxCtl );
+
+ protected:
+ virtual void StateChangedAtStatusListener( SfxItemState eState, const SfxPoolItem* pState ) override;
+
+ private:
+ SvxStyleToolBoxControl& rControl;
+};
+
+#define BUTTON_PADDING 10
+#define ITEM_HEIGHT 30
+
+SvxStyleBox_Base::SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
+ OUString aCommand,
+ SfxStyleFamily eFamily,
+ const Reference< XFrame >& _xFrame,
+ OUString _aClearFormatKey,
+ OUString _aMoreKey,
+ bool bInSpec, SvxStyleToolBoxControl& rCtrl)
+ : m_rCtrl(rCtrl)
+ , m_xMenuBuilder(Application::CreateBuilder(nullptr, "svx/ui/stylemenu.ui"))
+ , m_xMenu(m_xMenuBuilder->weld_menu("menu"))
+ , m_xWidget(std::move(xWidget))
+ , eStyleFamily( eFamily )
+ , m_nMaxUserDrawFontWidth(0)
+ , m_nLastItemWithMenu(-1)
+ , bRelease( true )
+ , m_xFrame(_xFrame)
+ , m_aCommand(std::move( aCommand ))
+ , aClearFormatKey(std::move( _aClearFormatKey ))
+ , aMoreKey(std::move( _aMoreKey ))
+ , bInSpecialMode( bInSpec )
+{
+ m_xWidget->connect_changed(LINK(this, SvxStyleBox_Base, SelectHdl));
+ m_xWidget->connect_key_press(LINK(this, SvxStyleBox_Base, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, SvxStyleBox_Base, ActivateHdl));
+ m_xWidget->connect_focus_out(LINK(this, SvxStyleBox_Base, FocusOutHdl));
+ m_xWidget->connect_get_property_tree(LINK(this, SvxStyleBox_Base, DumpAsPropertyTreeHdl));
+ m_xWidget->set_help_id(HID_STYLE_LISTBOX);
+ m_xWidget->set_entry_completion(true);
+ m_xMenu->connect_activate(LINK(this, SvxStyleBox_Base, MenuSelectHdl));
+
+ m_xWidget->connect_custom_get_size(LINK(this, SvxStyleBox_Base, CustomGetSizeHdl));
+ m_xWidget->connect_custom_render(LINK(this, SvxStyleBox_Base, CustomRenderHdl));
+ m_xWidget->set_custom_renderer(true);
+
+ m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 3);
+}
+
+IMPL_LINK(SvxStyleBox_Base, CustomGetSizeHdl, OutputDevice&, rArg, Size)
+{
+ CalcOptimalExtraUserWidth(rArg);
+ if (comphelper::LibreOfficeKit::isActive())
+ return Size(m_nMaxUserDrawFontWidth * rArg.GetDPIX() / 96, ITEM_HEIGHT * rArg.GetDPIY() / 96);
+ return Size(m_nMaxUserDrawFontWidth, ITEM_HEIGHT);
+}
+
+SvxStyleBox_Impl::SvxStyleBox_Impl(vcl::Window* pParent,
+ const OUString& rCommand,
+ SfxStyleFamily eFamily,
+ const Reference< XFrame >& _xFrame,
+ const OUString& rClearFormatKey,
+ const OUString& rMoreKey,
+ bool bInSpec, SvxStyleToolBoxControl& rCtrl)
+ : InterimItemWindow(pParent, "svx/ui/applystylebox.ui", "ApplyStyleBox")
+ , SvxStyleBox_Base(m_xBuilder->weld_combo_box("applystyle"), rCommand, eFamily, _xFrame,
+ rClearFormatKey, rMoreKey, bInSpec, rCtrl)
+{
+ InitControlBase(m_xWidget.get());
+
+ set_id("applystyle");
+ SetOptimalSize();
+}
+
+void SvxStyleBox_Base::ReleaseFocus()
+{
+ if ( !bRelease )
+ {
+ bRelease = true;
+ return;
+ }
+ if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() )
+ m_xFrame->getContainerWindow()->setFocus();
+}
+
+IMPL_LINK(SvxStyleBox_Base, MenuSelectHdl, const OUString&, rMenuIdent, void)
+{
+ if (m_nLastItemWithMenu < 0 || m_nLastItemWithMenu >= m_xWidget->get_count())
+ return;
+
+ OUString sEntry = m_xWidget->get_text(m_nLastItemWithMenu);
+
+ ReleaseFocus(); // It must be after getting entry pos!
+ Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("Param", sEntry),
+ comphelper::makePropertyValue("Family",
+ sal_Int16( eStyleFamily )) };
+
+ const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
+ if (rMenuIdent == "update")
+ {
+ SfxToolBoxControl::Dispatch(xProvider, ".uno:StyleUpdateByExample", aArgs);
+ }
+ else if (rMenuIdent == "edit")
+ {
+ SfxToolBoxControl::Dispatch(xProvider, ".uno:EditStyle", aArgs);
+ }
+}
+
+IMPL_STATIC_LINK_NOARG(SvxStyleBox_Base, ShowMoreHdl, void*, void)
+{
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ DBG_ASSERT( pViewFrm, "SvxStyleBox_Base::Select(): no viewframe" );
+ if (!pViewFrm)
+ return;
+ pViewFrm->ShowChildWindow(SID_SIDEBAR);
+ ::sfx2::sidebar::Sidebar::ShowPanel(u"StyleListPanel", pViewFrm->GetFrame().GetFrameInterface(), true);
+}
+
+IMPL_LINK(SvxStyleBox_Base, SelectHdl, weld::ComboBox&, rCombo, void)
+{
+ Select(rCombo.changed_by_direct_pick()); // only when picked from the list
+}
+
+IMPL_LINK_NOARG(SvxStyleBox_Base, ActivateHdl, weld::ComboBox&, bool)
+{
+ Select(true);
+ return true;
+}
+
+void SvxStyleBox_Base::Select(bool bNonTravelSelect)
+{
+ if (!bNonTravelSelect)
+ return;
+
+ OUString aSearchEntry(m_xWidget->get_active_text());
+ bool bDoIt = true, bClear = false;
+ if( bInSpecialMode )
+ {
+ if( aSearchEntry == aClearFormatKey && m_xWidget->get_active() == 0 )
+ {
+ aSearchEntry = sDefaultStyle;
+ bClear = true;
+ //not only apply default style but also call 'ClearFormatting'
+ Sequence< PropertyValue > aEmptyVals;
+ const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
+ SfxToolBoxControl::Dispatch(xProvider, ".uno:ResetAttributes", aEmptyVals);
+ }
+ else if (aSearchEntry == aMoreKey && m_xWidget->get_active() == (m_xWidget->get_count() - 1))
+ {
+ Application::PostUserEvent(LINK(nullptr, SvxStyleBox_Base, ShowMoreHdl));
+ //tdf#113214 change text back to previous entry
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+ bDoIt = false;
+ }
+ }
+
+ //Do we need to create a new style?
+ SfxObjectShell *pShell = SfxObjectShell::Current();
+ if (!pShell)
+ return;
+
+ SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyle = nullptr;
+
+ bool bCreateNew = false;
+
+ if ( pPool )
+ {
+ pStyle = pPool->First(eStyleFamily);
+ while ( pStyle && pStyle->GetName() != aSearchEntry )
+ pStyle = pPool->Next();
+ }
+
+ if ( !pStyle )
+ {
+ // cannot find the style for whatever reason
+ // therefore create a new style
+ bCreateNew = true;
+ }
+
+ /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
+ This instance may be deleted in the meantime (i.e. when a dialog is opened
+ while in Dispatch()), accessing members will crash in this case. */
+ ReleaseFocus();
+
+ if( !bDoIt )
+ return;
+
+ if ( bClear )
+ set_active_or_entry_text(aSearchEntry);
+ m_xWidget->save_value();
+
+ Sequence< PropertyValue > aArgs( 2 );
+ auto pArgs = aArgs.getArray();
+ pArgs[0].Value <<= aSearchEntry;
+ pArgs[1].Name = "Family";
+ pArgs[1].Value <<= sal_Int16( eStyleFamily );
+
+ const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
+ if( bCreateNew )
+ {
+ pArgs[0].Name = "Param";
+ SfxToolBoxControl::Dispatch(xProvider, ".uno:StyleNewByExample", aArgs);
+ }
+ else
+ {
+ pArgs[0].Name = "Template";
+ SfxToolBoxControl::Dispatch(xProvider, m_aCommand, aArgs);
+ }
+}
+
+void SvxStyleBox_Base::SetFamily( SfxStyleFamily eNewFamily )
+{
+ eStyleFamily = eNewFamily;
+}
+
+IMPL_LINK_NOARG(SvxStyleBox_Base, FocusOutHdl, weld::Widget&, void)
+{
+ if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+}
+
+IMPL_LINK(SvxStyleBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return DoKeyInput(rKEvt);
+}
+
+bool SvxStyleBox_Base::DoKeyInput(const KeyEvent& rKEvt)
+{
+ bool bHandled = false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+
+ switch (nCode)
+ {
+ case KEY_TAB:
+ bRelease = false;
+ Select(true);
+ break;
+ case KEY_ESCAPE:
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+ if (!m_rCtrl.IsInSidebar())
+ {
+ ReleaseFocus();
+ bHandled = true;
+ }
+ break;
+ }
+
+ return bHandled;
+}
+
+bool SvxStyleBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
+{
+ return SvxStyleBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt);
+}
+
+void SvxStyleBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ SetOptimalSize();
+ }
+
+ InterimItemWindow::DataChanged( rDCEvt );
+}
+
+void SvxStyleBox_Impl::SetOptimalSize()
+{
+ // set width in chars low so the size request will not be overridden
+ m_xWidget->set_entry_width_chars(1);
+ // tdf#132338 purely using this calculation to keep things their traditional width
+ Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS + 3) * 4, 0), MapMode(MapUnit::MapAppFont)));
+ m_xWidget->set_size_request(aSize.Width(), -1);
+
+ SetSizePixel(get_preferred_size());
+}
+
+namespace
+{
+std::vector<ScriptInfo> CheckScript(const OUString &rStyleName)
+{
+ assert(!rStyleName.isEmpty()); // must have a preview text here!
+
+ std::vector<ScriptInfo> aScriptChanges;
+
+ auto aEditEngine = EditEngine(nullptr);
+ aEditEngine.SetText(rStyleName);
+
+ auto aScript = aEditEngine.GetScriptType({ 0, 0, 0, 0 });
+ for (sal_Int32 i = 1; i <= rStyleName.getLength(); i++)
+ {
+ auto aNextScript = aEditEngine.GetScriptType({ 0, i, 0, i });
+ if (aNextScript != aScript || i == rStyleName.getLength())
+ aScriptChanges.emplace_back(aScript, i);
+ aScript = aNextScript;
+ }
+
+ return aScriptChanges;
+}
+}
+
+tools::Rectangle SvxStyleBox_Base::CalcBoundRect(vcl::RenderContext& rRenderContext, const OUString &rStyleName, std::vector<ScriptInfo>& rScriptChanges, double fRatio)
+{
+ tools::Rectangle aTextRect;
+
+ SvtScriptType aScript;
+ sal_uInt16 nIdx = 0;
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd;
+ size_t nCnt = rScriptChanges.size();
+
+ if (nCnt)
+ {
+ nEnd = rScriptChanges[nIdx].changePos;
+ aScript = rScriptChanges[nIdx].scriptType;
+ }
+ else
+ {
+ nEnd = rStyleName.getLength();
+ aScript = SvtScriptType::LATIN;
+ }
+
+ do
+ {
+ auto oFont = (aScript == SvtScriptType::ASIAN) ?
+ m_oCJKFont :
+ ((aScript == SvtScriptType::COMPLEX) ?
+ m_oCTLFont :
+ m_oFont);
+
+ rRenderContext.Push(vcl::PushFlags::FONT);
+
+ if (oFont)
+ rRenderContext.SetFont(*oFont);
+
+ if (fRatio != 1)
+ {
+ vcl::Font aFont(rRenderContext.GetFont());
+ Size aPixelSize(aFont.GetFontSize());
+ aPixelSize.setWidth(aPixelSize.Width() * fRatio);
+ aPixelSize.setHeight(aPixelSize.Height() * fRatio);
+ aFont.SetFontSize(aPixelSize);
+ rRenderContext.SetFont(aFont);
+ }
+
+ tools::Rectangle aRect;
+ rRenderContext.GetTextBoundRect(aRect, rStyleName, nStart, nStart, nEnd - nStart);
+ aTextRect = aTextRect.Union(aRect);
+
+ tools::Long nWidth = rRenderContext.GetTextWidth(rStyleName, nStart, nEnd - nStart);
+
+ rRenderContext.Pop();
+
+ if (nIdx >= rScriptChanges.size())
+ break;
+
+ rScriptChanges[nIdx++].textWidth = nWidth;
+
+ if (nEnd < rStyleName.getLength() && nIdx < nCnt)
+ {
+ nStart = nEnd;
+ nEnd = rScriptChanges[nIdx].changePos;
+ aScript = rScriptChanges[nIdx].scriptType;
+ }
+ else
+ break;
+ }
+ while(true);
+
+ return aTextRect;
+}
+
+void SvxStyleBox_Base::UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const tools::Rectangle& rTextRect, const OUString &rStyleName, const std::vector<ScriptInfo>& rScriptChanges)
+{
+ // IMG_TXT_DISTANCE in ilstbox.hxx is 6, then 1 is added as
+ // nBorder, and we are adding 1 in order to look better when
+ // italics is present
+ const int nLeftDistance = 8;
+
+ Point aPos(rRect.TopLeft());
+ aPos.AdjustX(nLeftDistance );
+
+ double fRatio = 1;
+ if (rTextRect.Bottom() > rRect.GetHeight())
+ fRatio = static_cast<double>(rRect.GetHeight()) / rTextRect.Bottom();
+ else
+ aPos.AdjustY((rRect.GetHeight() - rTextRect.Bottom()) / 2);
+
+ SvtScriptType aScript;
+ sal_uInt16 nIdx = 0;
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd;
+ size_t nCnt = rScriptChanges.size();
+
+ if (nCnt)
+ {
+ nEnd = rScriptChanges[nIdx].changePos;
+ aScript = rScriptChanges[nIdx].scriptType;
+ }
+ else
+ {
+ nEnd = rStyleName.getLength();
+ aScript = SvtScriptType::LATIN;
+ }
+
+
+ do
+ {
+ auto oFont = (aScript == SvtScriptType::ASIAN) ?
+ m_oCJKFont :
+ ((aScript == SvtScriptType::COMPLEX) ?
+ m_oCTLFont :
+ m_oFont);
+
+ rRenderContext.Push(vcl::PushFlags::FONT);
+
+ if (oFont)
+ rRenderContext.SetFont(*oFont);
+
+ if (fRatio != 1)
+ {
+ vcl::Font aFont(rRenderContext.GetFont());
+ Size aPixelSize(aFont.GetFontSize());
+ aPixelSize.setWidth(aPixelSize.Width() * fRatio);
+ aPixelSize.setHeight(aPixelSize.Height() * fRatio);
+ aFont.SetFontSize(aPixelSize);
+ rRenderContext.SetFont(aFont);
+ }
+
+ rRenderContext.DrawText(aPos, rStyleName, nStart, nEnd - nStart);
+
+ rRenderContext.Pop();
+
+ aPos.AdjustX(rScriptChanges[nIdx++].textWidth * fRatio);
+ if (nEnd < rStyleName.getLength() && nIdx < nCnt)
+ {
+ nStart = nEnd;
+ nEnd = rScriptChanges[nIdx].changePos;
+ aScript = rScriptChanges[nIdx].scriptType;
+ }
+ else
+ break;
+ }
+ while(true);
+}
+
+static bool GetWhich(const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich)
+{
+ rWhich = rSet.GetPool()->GetWhich(nSlot);
+ return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT;
+}
+
+static bool SetFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
+{
+ sal_uInt16 nWhich;
+ if (GetWhich(rSet, nSlot, nWhich))
+ {
+ const auto& rFontItem = static_cast<const SvxFontItem&>(rSet.Get(nWhich));
+ rFont.SetFamilyName(rFontItem.GetFamilyName());
+ rFont.SetStyleName(rFontItem.GetStyleName());
+ return true;
+ }
+ return false;
+}
+
+static bool SetFontSize(vcl::RenderContext& rRenderContext, const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
+{
+ sal_uInt16 nWhich;
+ if (GetWhich(rSet, nSlot, nWhich))
+ {
+ const auto& rFontHeightItem = static_cast<const SvxFontHeightItem&>(rSet.Get(nWhich));
+ if (SfxObjectShell *pShell = SfxObjectShell::Current())
+ {
+ Size aFontSize(0, rFontHeightItem.GetHeight());
+ Size aPixelSize(rRenderContext.LogicToPixel(aFontSize, MapMode(pShell->GetMapUnit())));
+ rFont.SetFontSize(aPixelSize);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void SetFontStyle(const SfxItemSet& rSet, sal_uInt16 nPosture, sal_uInt16 nWeight, SvxFont& rFont)
+{
+ sal_uInt16 nWhich;
+ if (GetWhich(rSet, nPosture, nWhich))
+ {
+ const auto& rItem = static_cast<const SvxPostureItem&>(rSet.Get(nWhich));
+ rFont.SetItalic(rItem.GetPosture());
+ }
+
+ if (GetWhich(rSet, nWeight, nWhich))
+ {
+ const auto& rItem = static_cast<const SvxWeightItem&>(rSet.Get(nWhich));
+ rFont.SetWeight(rItem.GetWeight());
+ }
+}
+
+void SvxStyleBox_Base::SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected)
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ if (!bIsNotSelected)
+ rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
+ else
+ rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
+
+ // handle the push-button
+ if (!bIsNotSelected)
+ {
+ if (nItem == 0 || nItem == m_xWidget->get_count() - 1)
+ m_xWidget->set_item_menu(OUString::number(nItem), nullptr);
+ else
+ {
+ m_nLastItemWithMenu = nItem;
+ m_xWidget->set_item_menu(OUString::number(nItem), m_xMenu.get());
+ }
+ }
+
+ if (nItem <= 0 || nItem >= m_xWidget->get_count() - 1)
+ return;
+
+ SfxObjectShell *pShell = SfxObjectShell::Current();
+ if (!pShell)
+ return;
+
+ SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
+ if (!pPool)
+ return;
+
+ SfxStyleSheetBase* pStyle = pPool->First(eStyleFamily);
+ while (pStyle && pStyle->GetName() != rStyleName)
+ pStyle = pPool->Next();
+
+ if (!pStyle )
+ return;
+
+ std::optional<SfxItemSet> const pItemSet(pStyle->GetItemSetForPreview());
+ if (!pItemSet) return;
+
+ SvxFont aFont;
+ SvxFont aCJKFont;
+ SvxFont aCTLFont;
+
+ SetFontStyle(*pItemSet, SID_ATTR_CHAR_POSTURE, SID_ATTR_CHAR_WEIGHT, aFont);
+ SetFontStyle(*pItemSet, SID_ATTR_CHAR_CJK_POSTURE, SID_ATTR_CHAR_CJK_WEIGHT, aCJKFont);
+ SetFontStyle(*pItemSet, SID_ATTR_CHAR_CTL_POSTURE, SID_ATTR_CHAR_CTL_WEIGHT, aCTLFont);
+
+ const SfxPoolItem *pItem = pItemSet->GetItem( SID_ATTR_CHAR_CONTOUR );
+ if ( pItem )
+ {
+ auto aVal = static_cast< const SvxContourItem* >( pItem )->GetValue();
+ aFont.SetOutline(aVal);
+ aCJKFont.SetOutline(aVal);
+ aCTLFont.SetOutline(aVal);
+ }
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_SHADOWED );
+ if ( pItem )
+ {
+ auto aVal = static_cast< const SvxShadowedItem* >( pItem )->GetValue();
+ aFont.SetShadow(aVal);
+ aCJKFont.SetShadow(aVal);
+ aCTLFont.SetShadow(aVal);
+ }
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_RELIEF );
+ if ( pItem )
+ {
+ auto aVal = static_cast< const SvxCharReliefItem* >( pItem )->GetValue();
+ aFont.SetRelief(aVal);
+ aCJKFont.SetRelief(aVal);
+ aCTLFont.SetRelief(aVal);
+ }
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_UNDERLINE );
+ if ( pItem )
+ {
+ auto aVal = static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle();
+ aFont.SetUnderline(aVal);
+ aCJKFont.SetUnderline(aVal);
+ aCTLFont.SetUnderline(aVal);
+ }
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_OVERLINE );
+ if ( pItem )
+ {
+ auto aVal = static_cast< const SvxOverlineItem* >( pItem )->GetValue();
+ aFont.SetOverline(aVal);
+ aCJKFont.SetOverline(aVal);
+ aCTLFont.SetOverline(aVal);
+ }
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_STRIKEOUT );
+ if ( pItem )
+ {
+ auto aVal = static_cast< const SvxCrossedOutItem* >( pItem )->GetStrikeout();
+ aFont.SetStrikeout(aVal);
+ aCJKFont.SetStrikeout(aVal);
+ aCTLFont.SetStrikeout(aVal);
+ }
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_CASEMAP );
+ if ( pItem )
+ {
+ auto aVal = static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap();
+ aFont.SetCaseMap(aVal);
+ aCJKFont.SetCaseMap(aVal);
+ aCTLFont.SetCaseMap(aVal);
+ }
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_EMPHASISMARK );
+ if ( pItem )
+ {
+ auto aVal = static_cast< const SvxEmphasisMarkItem* >( pItem )->GetEmphasisMark();
+ aFont.SetEmphasisMark(aVal);
+ aCJKFont.SetEmphasisMark(aVal);
+ aCTLFont.SetEmphasisMark(aVal);
+ }
+
+ // setup the device & draw
+ Color aFontCol = COL_AUTO, aBackCol = COL_AUTO;
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_COLOR );
+ // text color, when nothing is selected
+ if ( (nullptr != pItem) && bIsNotSelected)
+ aFontCol = static_cast< const SvxColorItem* >( pItem )->GetValue();
+
+ drawing::FillStyle style = drawing::FillStyle_NONE;
+ // which kind of Fill style is selected
+ pItem = pItemSet->GetItem( XATTR_FILLSTYLE );
+ // only when ok and not selected
+ if ( (nullptr != pItem) && bIsNotSelected)
+ style = static_cast< const XFillStyleItem* >( pItem )->GetValue();
+
+ switch(style)
+ {
+ case drawing::FillStyle_SOLID:
+ {
+ // set background color
+ pItem = pItemSet->GetItem( XATTR_FILLCOLOR );
+ if ( nullptr != pItem )
+ aBackCol = static_cast< const XFillColorItem* >( pItem )->GetColorValue();
+
+ if ( aBackCol != COL_AUTO )
+ {
+ rRenderContext.SetFillColor(aBackCol);
+ rRenderContext.DrawRect(rRect);
+ }
+ }
+ break;
+
+ default: break;
+ //TODO Draw the other background styles: gradient, hatching and bitmap
+ }
+
+ // when the font and background color are too similar, adjust the Font-Color
+ if( (aFontCol != COL_AUTO) || (aBackCol != COL_AUTO) )
+ aFontCol = TestColorsVisible(aFontCol, (aBackCol != COL_AUTO) ? aBackCol : rRenderContext.GetBackground().GetColor());
+
+ // set text color
+ if ( aFontCol != COL_AUTO )
+ rRenderContext.SetTextColor(aFontCol);
+
+ if (SetFont(*pItemSet, SID_ATTR_CHAR_FONT, aFont) &&
+ SetFontSize(rRenderContext, *pItemSet, SID_ATTR_CHAR_FONTHEIGHT, aFont))
+ m_oFont = aFont;
+
+ if (SetFont(*pItemSet, SID_ATTR_CHAR_CJK_FONT, aCJKFont) &&
+ SetFontSize(rRenderContext, *pItemSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, aCJKFont))
+ m_oCJKFont = aCJKFont;
+
+ if (SetFont(*pItemSet, SID_ATTR_CHAR_CTL_FONT, aCTLFont) &&
+ SetFontSize(rRenderContext, *pItemSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, aCTLFont))
+ m_oCTLFont = aCTLFont;
+}
+
+IMPL_LINK(SvxStyleBox_Base, CustomRenderHdl, weld::ComboBox::render_args, aPayload, void)
+{
+ vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
+ const ::tools::Rectangle& rRect = std::get<1>(aPayload);
+ bool bSelected = std::get<2>(aPayload);
+ const OUString& rId = std::get<3>(aPayload);
+
+ sal_uInt32 nIndex = rId.toUInt32();
+
+ OUString aStyleName(m_xWidget->get_text(nIndex));
+
+ rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
+
+ SetupEntry(rRenderContext, nIndex, rRect, aStyleName, !bSelected);
+ auto aScriptChanges = CheckScript(aStyleName);
+ auto aTextRect = CalcBoundRect(rRenderContext, aStyleName, aScriptChanges);
+ UserDrawEntry(rRenderContext, rRect, aTextRect, aStyleName, aScriptChanges);
+
+ rRenderContext.Pop();
+}
+
+void SvxStyleBox_Base::CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext)
+{
+ if (m_nMaxUserDrawFontWidth)
+ return;
+
+ tools::Long nMaxNormalFontWidth = 0;
+ sal_Int32 nEntryCount = m_xWidget->get_count();
+ for (sal_Int32 i = 0; i < nEntryCount; ++i)
+ {
+ OUString sStyleName(get_text(i));
+ tools::Rectangle aTextRectForDefaultFont;
+ rRenderContext.GetTextBoundRect(aTextRectForDefaultFont, sStyleName);
+
+ const tools::Long nWidth = aTextRectForDefaultFont.GetWidth();
+
+ nMaxNormalFontWidth = std::max(nWidth, nMaxNormalFontWidth);
+ }
+
+ m_nMaxUserDrawFontWidth = nMaxNormalFontWidth;
+ for (sal_Int32 i = 1; i < nEntryCount-1; ++i)
+ {
+ OUString sStyleName(get_text(i));
+
+ if (sStyleName.isEmpty())
+ continue;
+
+ rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
+ SetupEntry(rRenderContext, i, tools::Rectangle(0, 0, RECT_MAX, ITEM_HEIGHT), sStyleName, true);
+ auto aScriptChanges = CheckScript(sStyleName);
+ tools::Rectangle aTextRectForActualFont = CalcBoundRect(rRenderContext, sStyleName, aScriptChanges);
+ if (aTextRectForActualFont.Bottom() > ITEM_HEIGHT)
+ {
+ //Font didn't fit, re-calculate with adjustment ratio.
+ double fRatio = static_cast<double>(ITEM_HEIGHT) / aTextRectForActualFont.Bottom();
+ aTextRectForActualFont = CalcBoundRect(rRenderContext, sStyleName, aScriptChanges, fRatio);
+ }
+ rRenderContext.Pop();
+
+ const int nWidth = aTextRectForActualFont.GetWidth() + m_xWidget->get_menu_button_width() + BUTTON_PADDING;
+
+ m_nMaxUserDrawFontWidth = std::max(nWidth, m_nMaxUserDrawFontWidth);
+ }
+}
+
+// test is the color between Font- and background-color to be identify
+// return is always the Font-Color
+// when both light or dark, change the Contrast
+// in other case do not change the origin color
+// when the color is R=G=B=128 the DecreaseContrast make 128 the need an exception
+Color SvxStyleBox_Base::TestColorsVisible(const Color &FontCol, const Color &BackCol)
+{
+ constexpr sal_uInt8 ChgVal = 60; // increase/decrease the Contrast
+
+ Color retCol = FontCol;
+ if ((FontCol.IsDark() == BackCol.IsDark()) && (FontCol.IsBright() == BackCol.IsBright()))
+ {
+ sal_uInt8 lumi = retCol.GetLuminance();
+
+ if((lumi > 120) && (lumi < 140))
+ retCol.DecreaseLuminance(ChgVal / 2);
+ else
+ retCol.DecreaseContrast(ChgVal);
+ }
+
+ return retCol;
+}
+
+IMPL_LINK(SvxStyleBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
+{
+ if (!m_xWidget)
+ return;
+
+ {
+ auto entriesNode = rJsonWriter.startNode("entries");
+ for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i)
+ {
+ auto entryNode = rJsonWriter.startNode("");
+ rJsonWriter.put("", m_xWidget->get_text(i));
+ }
+ }
+
+ int nActive = m_xWidget->get_active();
+ rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nActive == -1 ? 0 : 1));
+
+ {
+ auto selectedNode = rJsonWriter.startNode("selectedEntries");
+ if (nActive != -1)
+ {
+ auto node = rJsonWriter.startNode("");
+ rJsonWriter.put("", static_cast<sal_Int32>(nActive));
+ }
+ }
+
+ rJsonWriter.put("command", ".uno:StyleApply");
+}
+
+static bool lcl_GetDocFontList(const FontList** ppFontList, SvxFontNameBox_Base* pBox)
+{
+ bool bChanged = false;
+ const SfxObjectShell* pDocSh = SfxObjectShell::Current();
+ const SvxFontListItem* pFontListItem = nullptr;
+
+ if ( pDocSh )
+ pFontListItem =
+ static_cast<const SvxFontListItem*>(pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST ));
+ else
+ {
+ ::std::unique_ptr<FontList> aFontList(new FontList(Application::GetDefaultDevice()));
+ *ppFontList = aFontList.get();
+ pBox->SetOwnFontList(std::move(aFontList));
+ bChanged = true;
+ }
+
+ if ( pFontListItem )
+ {
+ const FontList* pNewFontList = pFontListItem->GetFontList();
+ DBG_ASSERT( pNewFontList, "Doc-FontList not available!" );
+
+ // No old list, but a new list
+ if ( !*ppFontList && pNewFontList )
+ {
+ // => take over
+ *ppFontList = pNewFontList;
+ bChanged = true;
+ }
+ else
+ {
+ // Comparing the font lists is not perfect.
+ // When you change the font list in the Doc, you can track
+ // changes here only on the Listbox, because ppFontList
+ // has already been updated.
+ bChanged =
+ ( ( *ppFontList != pNewFontList ) ||
+ pBox->GetListCount() != pNewFontList->GetFontNameCount() );
+ // HACK: Comparing is incomplete
+
+ if ( bChanged )
+ *ppFontList = pNewFontList;
+ }
+
+ if ( pBox )
+ pBox->set_sensitive(true);
+ }
+ else if ( pBox && ( pDocSh || !ppFontList ))
+ {
+ // Disable box only when we have a SfxObjectShell and didn't get a font list OR
+ // we don't have a SfxObjectShell and no current font list.
+ // It's possible that we currently have no SfxObjectShell, but a current font list.
+ // See #i58471: When a user set the focus into the font name combo box and opens
+ // the help window with F1. After closing the help window, we disable the font name
+ // combo box. The SfxObjectShell::Current() method returns in that case zero. But the
+ // font list hasn't changed and therefore the combo box shouldn't be disabled!
+ pBox->set_sensitive(false);
+ }
+
+ // Fill the FontBox, also the new list if necessary
+ if ( pBox && bChanged )
+ {
+ if ( *ppFontList )
+ pBox->Fill( *ppFontList );
+ else
+ pBox->Clear();
+ }
+ return bChanged;
+}
+
+SvxFontNameBox_Base::SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
+ const Reference<XFrame>& rFrame,
+ SvxFontNameToolBoxControl& rCtrl)
+ : m_xListener(new comphelper::ConfigurationListener("/org.openoffice.Office.Common/Font/View"))
+ , m_aWYSIWYG(m_xListener, "ShowFontBoxWYSIWYG", *this)
+ , m_aHistory(m_xListener, "History", *this)
+ , m_rCtrl(rCtrl)
+ , m_xWidget(new FontNameBox(std::move(xWidget)))
+ , pFontList(nullptr)
+ , nFtCount(0)
+ , bRelease(true)
+ , m_xFrame(rFrame)
+ , mbCheckingUnknownFont(false)
+ , mbDropDownActive(false)
+{
+ EnableControls();
+
+ m_xWidget->connect_changed(LINK(this, SvxFontNameBox_Base, SelectHdl));
+ m_xWidget->connect_key_press(LINK(this, SvxFontNameBox_Base, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, SvxFontNameBox_Base, ActivateHdl));
+ m_xWidget->connect_focus_in(LINK(this, SvxFontNameBox_Base, FocusInHdl));
+ m_xWidget->connect_focus_out(LINK(this, SvxFontNameBox_Base, FocusOutHdl));
+ m_xWidget->connect_popup_toggled(LINK(this, SvxFontNameBox_Base, PopupToggledHdl));
+ m_xWidget->connect_live_preview(LINK(this, SvxFontNameBox_Base, LivePreviewHdl));
+ m_xWidget->connect_get_property_tree(LINK(this, SvxFontNameBox_Base, DumpAsPropertyTreeHdl));
+
+ m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 5);
+}
+
+SvxFontNameBox_Impl::SvxFontNameBox_Impl(vcl::Window* pParent, const Reference<XFrame>& rFrame,
+ SvxFontNameToolBoxControl& rCtrl)
+ : InterimItemWindow(pParent, "svx/ui/fontnamebox.ui", "FontNameBox", true, reinterpret_cast<sal_uInt64>(SfxViewShell::Current()))
+ , SvxFontNameBox_Base(m_xBuilder->weld_combo_box("fontnamecombobox"), rFrame, rCtrl)
+{
+ set_id("fontnamecombobox");
+ SetOptimalSize();
+}
+
+void SvxFontNameBox_Base::FillList()
+{
+ if (!m_xWidget) // e.g. disposed
+ return;
+ // Save old Selection, set back in the end
+ int nStartPos, nEndPos;
+ m_xWidget->get_entry_selection_bounds(nStartPos, nEndPos);
+
+ // Did Doc-Fontlist change?
+ lcl_GetDocFontList(&pFontList, this);
+
+ m_xWidget->select_entry_region(nStartPos, nEndPos);
+}
+
+bool SvxFontNameBox_Base::CheckFontIsAvailable(std::u16string_view fontname)
+{
+ lcl_GetDocFontList(&pFontList, this);
+ return pFontList && pFontList->IsAvailable(fontname);
+}
+
+void SvxFontNameBox_Base::CheckAndMarkUnknownFont()
+{
+ if (mbCheckingUnknownFont) //tdf#117537 block rentry
+ return;
+ mbCheckingUnknownFont = true;
+ OUString fontname = m_xWidget->get_active_text();
+ // tdf#154680 If a font is set and that font is unknown, show it in italic.
+ vcl::Font font = m_xWidget->get_entry_font();
+ if (fontname.isEmpty() || CheckFontIsAvailable(fontname))
+ {
+ if( font.GetItalic() != ITALIC_NONE )
+ {
+ font.SetItalic( ITALIC_NONE );
+ m_xWidget->set_entry_font(font);
+ m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME));
+ }
+ }
+ else
+ {
+ if( font.GetItalic() != ITALIC_NORMAL )
+ {
+ font.SetItalic( ITALIC_NORMAL );
+ m_xWidget->set_entry_font(font);
+ m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME_NOTAVAILABLE));
+ }
+ }
+ mbCheckingUnknownFont = false;
+}
+
+void SvxFontNameBox_Base::Update( const css::awt::FontDescriptor* pFontDesc )
+{
+ if ( pFontDesc )
+ {
+ aCurFont.SetFamilyName ( pFontDesc->Name );
+ aCurFont.SetFamily ( FontFamily( pFontDesc->Family ) );
+ aCurFont.SetStyleName ( pFontDesc->StyleName );
+ aCurFont.SetPitch ( FontPitch( pFontDesc->Pitch ) );
+ aCurFont.SetCharSet ( rtl_TextEncoding( pFontDesc->CharSet ) );
+ }
+ OUString aCurName = aCurFont.GetFamilyName();
+ OUString aText = m_xWidget->get_active_text();
+ if (aText != aCurName)
+ set_active_or_entry_text(aCurName);
+}
+
+void SvxFontNameBox_Base::set_active_or_entry_text(const OUString& rText)
+{
+ m_xWidget->set_active_or_entry_text(rText);
+ CheckAndMarkUnknownFont();
+}
+
+IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusInHdl, weld::Widget&, void)
+{
+ FillList();
+}
+
+IMPL_LINK(SvxFontNameBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return DoKeyInput(rKEvt);
+}
+
+bool SvxFontNameBox_Base::DoKeyInput(const KeyEvent& rKEvt)
+{
+ bool bHandled = false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+
+ switch (nCode)
+ {
+ case KEY_TAB:
+ bRelease = false;
+ Select(true);
+ break;
+
+ case KEY_ESCAPE:
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+ if (!m_rCtrl.IsInSidebar())
+ {
+ ReleaseFocus_Impl();
+ bHandled = true;
+ }
+ break;
+ }
+
+ return bHandled;
+}
+
+bool SvxFontNameBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
+{
+ return SvxFontNameBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusOutHdl, weld::Widget&, void)
+{
+ if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
+ {
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+ // send EndPreview
+ EndPreview();
+ }
+}
+
+IMPL_LINK(SvxFontNameBox_Base, LivePreviewHdl, const FontMetric&, rFontMetric, void)
+{
+ Sequence<PropertyValue> aArgs(1);
+
+ SvxFontItem aFontItem(rFontMetric.GetFamilyType(),
+ rFontMetric.GetFamilyName(),
+ rFontMetric.GetStyleName(),
+ rFontMetric.GetPitch(),
+ rFontMetric.GetCharSet(),
+ SID_ATTR_CHAR_FONT);
+ PropertyValue* pArgs = aArgs.getArray();
+ aFontItem.QueryValue(pArgs[0].Value);
+ pArgs[0].Name = "CharPreviewFontName";
+ const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
+ SfxToolBoxControl::Dispatch(xProvider, ".uno:CharPreviewFontName", aArgs);
+}
+
+IMPL_LINK_NOARG(SvxFontNameBox_Base, PopupToggledHdl, weld::ComboBox&, void)
+{
+ mbDropDownActive = !mbDropDownActive;
+ if (!mbDropDownActive)
+ EndPreview();
+}
+
+void SvxFontNameBox_Impl::SetOptimalSize()
+{
+ // set width in chars low so the size request will not be overridden
+ m_xWidget->set_entry_width_chars(1);
+ // tdf#132338 purely using this calculation to keep things their traditional width
+ Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS +5) * 4, 0), MapMode(MapUnit::MapAppFont)));
+ m_xWidget->set_size_request(aSize.Width(), -1);
+
+ SetSizePixel(get_preferred_size());
+}
+
+void SvxFontNameBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ SetOptimalSize();
+ }
+ else if ( ( rDCEvt.GetType() == DataChangedEventType::FONTS ) ||
+ ( rDCEvt.GetType() == DataChangedEventType::DISPLAY ) )
+ {
+ // The old font list in shell has likely been destroyed at this point, so we need to get
+ // the new one before doing anything further.
+ lcl_GetDocFontList( &pFontList, this );
+ }
+}
+
+void SvxFontNameBox_Base::ReleaseFocus_Impl()
+{
+ if ( !bRelease )
+ {
+ bRelease = true;
+ return;
+ }
+ if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() )
+ m_xFrame->getContainerWindow()->setFocus();
+}
+
+void SvxFontNameBox_Base::EnableControls()
+{
+ bool bEnableMRU = m_aHistory.get();
+ sal_uInt16 nEntries = bEnableMRU ? MAX_MRU_FONTNAME_ENTRIES : 0;
+
+ bool bNewWYSIWYG = m_aWYSIWYG.get();
+ bool bOldWYSIWYG = m_xWidget->IsWYSIWYGEnabled();
+
+ if (m_xWidget->get_max_mru_count() != nEntries || bNewWYSIWYG != bOldWYSIWYG)
+ {
+ // refill in the next GetFocus-Handler
+ pFontList = nullptr;
+ Clear();
+ m_xWidget->set_max_mru_count(nEntries);
+ }
+
+ if (bNewWYSIWYG != bOldWYSIWYG)
+ m_xWidget->EnableWYSIWYG(bNewWYSIWYG);
+}
+
+IMPL_LINK(SvxFontNameBox_Base, SelectHdl, weld::ComboBox&, rCombo, void)
+{
+ Select(rCombo.changed_by_direct_pick()); // only when picked from the list
+}
+
+IMPL_LINK_NOARG(SvxFontNameBox_Base, ActivateHdl, weld::ComboBox&, bool)
+{
+ Select(true);
+ return true;
+}
+
+void SvxFontNameBox_Base::Select(bool bNonTravelSelect)
+{
+ Sequence< PropertyValue > aArgs( 1 );
+ auto pArgs = aArgs.getArray();
+ std::unique_ptr<SvxFontItem> pFontItem;
+ if ( pFontList )
+ {
+ FontMetric aFontMetric( pFontList->Get(m_xWidget->get_active_text(),
+ aCurFont.GetWeight(),
+ aCurFont.GetItalic() ) );
+ aCurFont = aFontMetric;
+
+ pFontItem.reset( new SvxFontItem( aFontMetric.GetFamilyType(),
+ aFontMetric.GetFamilyName(),
+ aFontMetric.GetStyleName(),
+ aFontMetric.GetPitch(),
+ aFontMetric.GetCharSet(),
+ SID_ATTR_CHAR_FONT ) );
+
+ Any a;
+ pFontItem->QueryValue( a );
+ pArgs[0].Value = a;
+ }
+
+ const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY);
+ if (bNonTravelSelect)
+ {
+ CheckAndMarkUnknownFont();
+ // #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
+ // This instance may be deleted in the meantime (i.e. when a dialog is opened
+ // while in Dispatch()), accessing members will crash in this case.
+ ReleaseFocus_Impl();
+ EndPreview();
+ if (pFontItem)
+ {
+ pArgs[0].Name = "CharFontName";
+ SfxToolBoxControl::Dispatch(xProvider, ".uno:CharFontName", aArgs);
+ }
+ }
+ else
+ {
+ if (pFontItem)
+ {
+ pArgs[0].Name = "CharPreviewFontName";
+ SfxToolBoxControl::Dispatch(xProvider, ".uno:CharPreviewFontName", aArgs);
+ }
+ }
+}
+
+IMPL_LINK(SvxFontNameBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
+{
+ {
+ auto entriesNode = rJsonWriter.startNode("entries");
+ for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i)
+ {
+ auto entryNode = rJsonWriter.startNode("");
+ rJsonWriter.put("", m_xWidget->get_text(i));
+ }
+ }
+
+ int nSelectedEntry = m_xWidget->get_active();
+ rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nSelectedEntry == -1 ? 0 : 1));
+
+ {
+ auto selectedNode = rJsonWriter.startNode("selectedEntries");
+ if (nSelectedEntry != -1)
+ {
+ auto entryNode = rJsonWriter.startNode("");
+ rJsonWriter.put("", m_xWidget->get_text(nSelectedEntry));
+ }
+ }
+
+ rJsonWriter.put("command", ".uno:CharFontName");
+}
+
+ColorWindow::ColorWindow(OUString rCommand,
+ std::shared_ptr<PaletteManager> xPaletteManager,
+ ColorStatus& rColorStatus,
+ sal_uInt16 nSlotId,
+ const Reference< XFrame >& rFrame,
+ const MenuOrToolMenuButton& rMenuButton,
+ TopLevelParentFunction aTopLevelParentFunction,
+ ColorSelectFunction aColorSelectFunction)
+ : WeldToolbarPopup(rFrame, rMenuButton.get_widget(), "svx/ui/colorwindow.ui", "palette_popup_window")
+ , theSlotId(nSlotId)
+ , maCommand(std::move(rCommand))
+ , maMenuButton(rMenuButton)
+ , mxPaletteManager(std::move(xPaletteManager))
+ , mrColorStatus(rColorStatus)
+ , maTopLevelParentFunction(std::move(aTopLevelParentFunction))
+ , maColorSelectFunction(std::move(aColorSelectFunction))
+ , mxColorSet(new SvxColorValueSet(m_xBuilder->weld_scrolled_window("colorsetwin", true)))
+ , mxRecentColorSet(new SvxColorValueSet(nullptr))
+ , mxPaletteListBox(m_xBuilder->weld_combo_box("palette_listbox"))
+ , mxButtonAutoColor(m_xBuilder->weld_button("auto_color_button"))
+ , mxButtonNoneColor(m_xBuilder->weld_button("none_color_button"))
+ , mxButtonPicker(m_xBuilder->weld_button("color_picker_button"))
+ , mxAutomaticSeparator(m_xBuilder->weld_widget("separator4"))
+ , mxColorSetWin(new weld::CustomWeld(*m_xBuilder, "colorset", *mxColorSet))
+ , mxRecentColorSetWin(new weld::CustomWeld(*m_xBuilder, "recent_colorset", *mxRecentColorSet))
+ , mpDefaultButton(nullptr)
+{
+ mxColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
+ mxRecentColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
+
+ switch ( theSlotId )
+ {
+ case SID_ATTR_CHAR_COLOR_BACKGROUND:
+ case SID_BACKGROUND_COLOR:
+ case SID_ATTR_CHAR_BACK_COLOR:
+ case SID_TABLE_CELL_BACKGROUND_COLOR:
+ {
+ mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_NOFILL ) );
+ break;
+ }
+ case SID_AUTHOR_COLOR:
+ {
+ mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_BY_AUTHOR ) );
+ break;
+ }
+ case SID_BMPMASK_COLOR:
+ {
+ mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_TRANSPARENT ) );
+ break;
+ }
+ case SID_ATTR_CHAR_COLOR:
+ case SID_ATTR_CHAR_COLOR2:
+ case SID_EXTRUSION_3D_COLOR:
+ {
+ mxButtonAutoColor->set_label(EditResId(RID_SVXSTR_AUTOMATIC));
+ break;
+ }
+ case SID_FM_CTL_PROPERTIES:
+ {
+ mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_DEFAULT ) );
+ break;
+ }
+ default:
+ {
+ mxButtonAutoColor->hide();
+ mxAutomaticSeparator->hide();
+ break;
+ }
+ }
+
+ mxPaletteListBox->connect_changed(LINK(this, ColorWindow, SelectPaletteHdl));
+ std::vector<OUString> aPaletteList = mxPaletteManager->GetPaletteList();
+ mxPaletteListBox->freeze();
+ for (const auto& rPalette : aPaletteList)
+ mxPaletteListBox->append_text(rPalette);
+ mxPaletteListBox->thaw();
+ OUString aPaletteName( officecfg::Office::Common::UserColors::PaletteName::get() );
+ mxPaletteListBox->set_active_text(aPaletteName);
+ const int nSelectedEntry(mxPaletteListBox->get_active());
+ if (nSelectedEntry != -1)
+ mxPaletteManager->SetPalette(nSelectedEntry);
+
+ mxButtonAutoColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl));
+ mxButtonNoneColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl));
+ mxButtonPicker->connect_clicked(LINK(this, ColorWindow, OpenPickerClickHdl));
+
+ mxColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl));
+ mxRecentColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl));
+ m_xTopLevel->set_help_id(HID_POPUP_COLOR);
+ mxColorSet->SetHelpId(HID_POPUP_COLOR_CTRL);
+
+ mxPaletteManager->ReloadColorSet(*mxColorSet);
+ const sal_uInt32 nMaxItems(SvxColorValueSet::getMaxRowCount() * SvxColorValueSet::getColumnCount());
+ Size aSize = mxColorSet->layoutAllVisible(nMaxItems);
+ mxColorSet->set_size_request(aSize.Width(), aSize.Height());
+
+ mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
+ aSize = mxRecentColorSet->layoutAllVisible(mxPaletteManager->GetRecentColorCount());
+ mxRecentColorSet->set_size_request(aSize.Width(), aSize.Height());
+
+ AddStatusListener( ".uno:ColorTableState" );
+ AddStatusListener( maCommand );
+ if ( maCommand == ".uno:FrameLineColor" )
+ {
+ AddStatusListener( ".uno:BorderTLBR" );
+ AddStatusListener( ".uno:BorderBLTR" );
+ }
+}
+
+void ColorWindow::GrabFocus()
+{
+ if (mxColorSet->IsNoSelection() && mpDefaultButton)
+ mpDefaultButton->grab_focus();
+ else
+ mxColorSet->GrabFocus();
+}
+
+void ColorWindow::ShowNoneButton()
+{
+ mxButtonNoneColor->show();
+}
+
+ColorWindow::~ColorWindow()
+{
+}
+
+NamedColor ColorWindow::GetSelectEntryColor(ValueSet const * pColorSet)
+{
+ Color aColor = pColorSet->GetItemColor(pColorSet->GetSelectedItemId());
+ OUString sColorName = pColorSet->GetItemText(pColorSet->GetSelectedItemId());
+ return { aColor, sColorName };
+}
+
+namespace
+{
+ NamedColor GetAutoColor(sal_uInt16 nSlotId)
+ {
+ Color aColor;
+ OUString sColorName;
+ switch (nSlotId)
+ {
+ case SID_ATTR_CHAR_COLOR_BACKGROUND:
+ case SID_BACKGROUND_COLOR:
+ case SID_ATTR_CHAR_BACK_COLOR:
+ case SID_TABLE_CELL_BACKGROUND_COLOR:
+ aColor = COL_TRANSPARENT;
+ sColorName = SvxResId(RID_SVXSTR_NOFILL);
+ break;
+ case SID_AUTHOR_COLOR:
+ aColor = COL_TRANSPARENT;
+ sColorName = SvxResId(RID_SVXSTR_BY_AUTHOR);
+ break;
+ case SID_BMPMASK_COLOR:
+ aColor = COL_TRANSPARENT;
+ sColorName = SvxResId(RID_SVXSTR_TRANSPARENT);
+ break;
+ case SID_FM_CTL_PROPERTIES:
+ aColor = COL_TRANSPARENT;
+ sColorName = SvxResId(RID_SVXSTR_DEFAULT);
+ break;
+ case SID_ATTR_CHAR_COLOR:
+ case SID_ATTR_CHAR_COLOR2:
+ case SID_EXTRUSION_3D_COLOR:
+ default:
+ aColor = COL_AUTO;
+ sColorName = EditResId(RID_SVXSTR_AUTOMATIC);
+ break;
+ }
+
+ return {aColor, sColorName};
+ }
+
+ NamedColor GetNoneColor()
+ {
+ OUString aName = comphelper::LibreOfficeKit::isActive()
+ ? SvxResId(RID_SVXSTR_INVISIBLE)
+ : SvxResId(RID_SVXSTR_NONE);
+ return { COL_NONE_COLOR, aName };
+ }
+}
+
+NamedColor ColorWindow::GetSelectEntryColor() const
+{
+ if (!mxColorSet->IsNoSelection())
+ return GetSelectEntryColor(mxColorSet.get());
+ if (!mxRecentColorSet->IsNoSelection())
+ return GetSelectEntryColor(mxRecentColorSet.get());
+ if (mxButtonNoneColor.get() == mpDefaultButton)
+ return GetNoneColor();
+ return GetAutoColor();
+}
+
+IMPL_LINK(ColorWindow, SelectHdl, ValueSet*, pColorSet, void)
+{
+ NamedColor aNamedColor = GetSelectEntryColor(pColorSet);
+
+ if (pColorSet != mxRecentColorSet.get())
+ {
+ mxPaletteManager->AddRecentColor(aNamedColor.m_aColor, aNamedColor.m_aName);
+ if (!maMenuButton.get_active())
+ mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
+ }
+
+ mxPaletteManager->SetSplitButtonColor(aNamedColor);
+
+ // deliberate take a copy here in case maMenuButton.set_inactive
+ // triggers a callback that destroys ourself
+ ColorSelectFunction aColorSelectFunction(maColorSelectFunction);
+ OUString sCommand(maCommand);
+ // Same for querying IsTheme early.
+ bool bThemePaletteSelected = mxPaletteManager->IsThemePaletteSelected();
+ sal_uInt16 nSelectedItemId = pColorSet->GetSelectedItemId();
+
+ if (bThemePaletteSelected)
+ {
+ sal_uInt16 nThemeIndex;
+ sal_uInt16 nEffectIndex;
+ if (PaletteManager::GetThemeAndEffectIndex(nSelectedItemId, nThemeIndex, nEffectIndex))
+ {
+ aNamedColor.m_nThemeIndex = nThemeIndex;
+ mxPaletteManager->GetLumModOff(nThemeIndex, nEffectIndex, aNamedColor.m_nLumMod, aNamedColor.m_nLumOff);
+ }
+ }
+
+ maMenuButton.set_inactive();
+ aColorSelectFunction(sCommand, aNamedColor);
+}
+
+IMPL_LINK_NOARG(ColorWindow, SelectPaletteHdl, weld::ComboBox&, void)
+{
+ int nPos = mxPaletteListBox->get_active();
+ mxPaletteManager->SetPalette( nPos );
+ mxPaletteManager->ReloadColorSet(*mxColorSet);
+ mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount());
+}
+
+NamedColor ColorWindow::GetAutoColor() const
+{
+ return ::GetAutoColor(theSlotId);
+}
+
+IMPL_LINK(ColorWindow, AutoColorClickHdl, weld::Button&, rButton, void)
+{
+ NamedColor aNamedColor = &rButton == mxButtonAutoColor.get() ? GetAutoColor() : GetNoneColor();
+
+ mxColorSet->SetNoSelection();
+ mxRecentColorSet->SetNoSelection();
+ mpDefaultButton = &rButton;
+
+ mxPaletteManager->SetSplitButtonColor(aNamedColor);
+
+ // deliberate take a copy here in case maMenuButton.set_inactive
+ // triggers a callback that destroys ourself
+ ColorSelectFunction aColorSelectFunction(maColorSelectFunction);
+ OUString sCommand(maCommand);
+
+ maMenuButton.set_inactive();
+
+ aColorSelectFunction(sCommand, aNamedColor);
+}
+
+IMPL_LINK_NOARG(ColorWindow, OpenPickerClickHdl, weld::Button&, void)
+{
+ // copy before set_inactive
+ auto nColor = GetSelectEntryColor().m_aColor;
+ auto pParentWindow = maTopLevelParentFunction();
+ OUString sCommand = maCommand;
+ std::shared_ptr<PaletteManager> xPaletteManager(mxPaletteManager);
+
+ maMenuButton.set_inactive();
+
+ xPaletteManager->PopupColorPicker(pParentWindow, sCommand, nColor);
+}
+
+void ColorWindow::SetNoSelection()
+{
+ mxColorSet->SetNoSelection();
+ mxRecentColorSet->SetNoSelection();
+ mpDefaultButton = nullptr;
+}
+
+bool ColorWindow::IsNoSelection() const
+{
+ if (!mxColorSet->IsNoSelection())
+ return false;
+ if (!mxRecentColorSet->IsNoSelection())
+ return false;
+ return !mxButtonAutoColor->get_visible() && !mxButtonNoneColor->get_visible();
+}
+
+void ColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ if (rEvent.FeatureURL.Complete == ".uno:ColorTableState")
+ {
+ if (rEvent.IsEnabled && mxPaletteManager->GetPalette() == 0)
+ {
+ mxPaletteManager->ReloadColorSet(*mxColorSet);
+ mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount());
+ }
+ }
+ else
+ {
+ mrColorStatus.statusChanged(rEvent);
+ SelectEntry(mrColorStatus.GetColor());
+ }
+}
+
+bool ColorWindow::SelectValueSetEntry(SvxColorValueSet* pColorSet, const Color& rColor)
+{
+ for (size_t i = 1; i <= pColorSet->GetItemCount(); ++i)
+ {
+ if (rColor == pColorSet->GetItemColor(i))
+ {
+ pColorSet->SelectItem(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void ColorWindow::SelectEntry(const NamedColor& rNamedColor)
+{
+ SetNoSelection();
+
+ const Color &rColor = rNamedColor.m_aColor;
+
+ if (mxButtonAutoColor->get_visible() && rColor.IsFullyTransparent())
+ {
+ mpDefaultButton = mxButtonAutoColor.get();
+ return;
+ }
+
+ if (mxButtonNoneColor->get_visible() && rColor == COL_NONE_COLOR)
+ {
+ mpDefaultButton = mxButtonNoneColor.get();
+ return;
+ }
+
+ // try current palette
+ bool bFoundColor = SelectValueSetEntry(mxColorSet.get(), rColor);
+ // try recently used
+ if (!bFoundColor)
+ bFoundColor = SelectValueSetEntry(mxRecentColorSet.get(), rColor);
+ // if it's not there, add it there now to the end of the recently used
+ // so its available somewhere handy, but not without trashing the
+ // whole recently used
+ if (!bFoundColor)
+ {
+ const OUString& rColorName = rNamedColor.m_aName;
+ mxPaletteManager->AddRecentColor(rColor, rColorName, false);
+ mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
+ SelectValueSetEntry(mxRecentColorSet.get(), rColor);
+ }
+}
+
+void ColorWindow::SelectEntry(const Color& rColor)
+{
+ OUString sColorName = "#" + rColor.AsRGBHexString().toAsciiUpperCase();
+ ColorWindow::SelectEntry({rColor, sColorName});
+}
+
+ColorStatus::ColorStatus() :
+ maColor( COL_TRANSPARENT ),
+ maTLBRColor( COL_TRANSPARENT ),
+ maBLTRColor( COL_TRANSPARENT )
+{
+}
+
+void ColorStatus::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ Color aColor( COL_TRANSPARENT );
+ css::table::BorderLine2 aTable;
+
+ if ( rEvent.State >>= aTable )
+ {
+ SvxBorderLine aLine;
+ SvxBoxItem::LineToSvxLine( aTable, aLine, false );
+ if ( !aLine.isEmpty() )
+ aColor = aLine.GetColor();
+ }
+ else
+ rEvent.State >>= aColor;
+
+ if ( rEvent.FeatureURL.Path == "BorderTLBR" )
+ maTLBRColor = aColor;
+ else if ( rEvent.FeatureURL.Path == "BorderBLTR" )
+ maBLTRColor = aColor;
+ else
+ maColor = aColor;
+}
+
+Color ColorStatus::GetColor()
+{
+ Color aColor( maColor );
+
+ if ( maTLBRColor != COL_TRANSPARENT )
+ {
+ if ( aColor != maTLBRColor && aColor != COL_TRANSPARENT )
+ return COL_TRANSPARENT;
+ aColor = maTLBRColor;
+ }
+
+ if ( maBLTRColor != COL_TRANSPARENT )
+ {
+ if ( aColor != maBLTRColor && aColor != COL_TRANSPARENT )
+ return COL_TRANSPARENT;
+ return maBLTRColor;
+ }
+
+ return aColor;
+}
+
+
+SvxFrameWindow_Impl::SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder")
+ , mxControl(pControl)
+ , mxFrameSet(new SvxFrmValueSet_Impl)
+ , mxFrameSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxFrameSet))
+ , bParagraphMode(false)
+ , m_bIsWriter(false)
+{
+
+ // check whether the document is Writer or not
+ if (Reference<lang::XServiceInfo> xSI{ m_xFrame->getController()->getModel(), UNO_QUERY })
+ m_bIsWriter = xSI->supportsService("com.sun.star.text.TextDocument");
+
+ mxFrameSet->SetStyle(WB_ITEMBORDER | WB_DOUBLEBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT);
+ AddStatusListener(".uno:BorderReducedMode");
+ InitImageList();
+
+ /*
+ * 1 2 3 4 5
+ * ------------------------------------------------------
+ * NONE LEFT RIGHT LEFTRIGHT DIAGONALDOWN
+ * TOP BOTTOM TOPBOTTOM OUTER DIAGONALUP
+ * ------------------------------------------------------
+ * HOR HORINNER VERINNER ALL CRISSCROSS <- can be switched of via bParagraphMode
+ */
+
+ sal_uInt16 i = 0;
+
+ // diagonal borders available only for Calc.
+ // Therefore, Calc uses 10 border types while
+ // Writer uses 8 of them - for a single cell.
+ for ( i=1; i < (m_bIsWriter ? 9 : 11); i++ )
+ mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
+
+ //bParagraphMode should have been set in StateChanged
+ if ( !bParagraphMode )
+ // when multiple cell selected:
+ // Writer has 12 border types and Calc has 15 of them.
+ for ( i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
+ mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
+
+ // adjust frame column for Writer
+ sal_uInt16 colCount = m_bIsWriter ? 4 : 5;
+ mxFrameSet->SetColCount( colCount );
+ mxFrameSet->SetSelectHdl( LINK( this, SvxFrameWindow_Impl, SelectHdl ) );
+ CalcSizeValueSet();
+
+ mxFrameSet->SetHelpId( HID_POPUP_FRAME );
+ mxFrameSet->SetAccessibleName( SvxResId(RID_SVXSTR_FRAME) );
+}
+
+namespace {
+
+enum class FrmValidFlags {
+ NONE = 0x00,
+ Left = 0x01,
+ Right = 0x02,
+ Top = 0x04,
+ Bottom = 0x08,
+ HInner = 0x10,
+ VInner = 0x20,
+ AllMask = 0x3f,
+};
+
+}
+
+namespace o3tl {
+ template<> struct typed_flags<FrmValidFlags> : is_typed_flags<FrmValidFlags, 0x3f> {};
+}
+
+// By default unset lines remain unchanged.
+// Via Shift unset lines are reset
+
+IMPL_LINK_NOARG(SvxFrameWindow_Impl, SelectHdl, ValueSet*, void)
+{
+ SvxBoxItem aBorderOuter( SID_ATTR_BORDER_OUTER );
+ SvxBoxInfoItem aBorderInner( SID_ATTR_BORDER_INNER );
+ SvxBorderLine theDefLine;
+
+ // diagonal down border
+ SvxBorderLine dDownBorderLine(nullptr, SvxBorderLineWidth::Hairline);
+ SvxLineItem dDownLineItem(SID_ATTR_BORDER_DIAG_TLBR);
+
+ // diagonal up border
+ SvxBorderLine dUpBorderLine(nullptr, SvxBorderLineWidth::Hairline);
+ SvxLineItem dUpLineItem(SID_ATTR_BORDER_DIAG_BLTR);
+
+ bool bIsDiagonalBorder = false;
+
+ SvxBorderLine *pLeft = nullptr,
+ *pRight = nullptr,
+ *pTop = nullptr,
+ *pBottom = nullptr;
+ sal_uInt16 nSel = mxFrameSet->GetSelectedItemId();
+ sal_uInt16 nModifier = mxFrameSet->GetModifier();
+ FrmValidFlags nValidFlags = FrmValidFlags::NONE;
+
+ // tdf#48622, tdf#145828 use correct default to create intended 0.75pt
+ // cell border using the border formatting tool in the standard toolbar
+ theDefLine.GuessLinesWidths(theDefLine.GetBorderLineStyle(), SvxBorderLineWidth::Thin);
+
+ // nSel has 15 cases which means 15 border
+ // types for Calc. But Writer uses only 12
+ // of them - when diagonal borders excluded.
+ if (m_bIsWriter)
+ {
+ // add appropriate increments
+ // to match the correct borders.
+ if (nSel > 8) { nSel += 2; }
+ else if (nSel > 4) { nSel++; }
+ }
+
+ switch ( nSel )
+ {
+ case 1: nValidFlags |= FrmValidFlags::AllMask;
+ // set nullptr to remove diagonal lines
+ dDownLineItem.SetLine(nullptr);
+ dUpLineItem.SetLine(nullptr);
+ SetDiagonalDownBorder(dDownLineItem);
+ SetDiagonalUpBorder(dUpLineItem);
+ break; // NONE
+ case 2: pLeft = &theDefLine;
+ nValidFlags |= FrmValidFlags::Left;
+ break; // LEFT
+ case 3: pRight = &theDefLine;
+ nValidFlags |= FrmValidFlags::Right;
+ break; // RIGHT
+ case 4: pLeft = pRight = &theDefLine;
+ nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left;
+ break; // LEFTRIGHT
+ case 5: dDownLineItem.SetLine(&dDownBorderLine);
+ SetDiagonalDownBorder(dDownLineItem);
+ bIsDiagonalBorder = true;
+ break; // DIAGONAL DOWN
+ case 6: pTop = &theDefLine;
+ nValidFlags |= FrmValidFlags::Top;
+ break; // TOP
+ case 7: pBottom = &theDefLine;
+ nValidFlags |= FrmValidFlags::Bottom;
+ break; // BOTTOM
+ case 8: pTop = pBottom = &theDefLine;
+ nValidFlags |= FrmValidFlags::Bottom|FrmValidFlags::Top;
+ break; // TOPBOTTOM
+ case 9: pLeft = pRight = pTop = pBottom = &theDefLine;
+ nValidFlags |= FrmValidFlags::Left | FrmValidFlags::Right | FrmValidFlags::Top | FrmValidFlags::Bottom;
+ break; // OUTER
+ case 10:
+ dUpLineItem.SetLine(&dUpBorderLine);
+ SetDiagonalUpBorder(dUpLineItem);
+ bIsDiagonalBorder = true;
+ break; // DIAGONAL UP
+
+ // Inner Table:
+ case 11: // HOR
+ pTop = pBottom = &theDefLine;
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
+ aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
+ nValidFlags |= FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
+ break;
+
+ case 12: // HORINNER
+ pLeft = pRight = pTop = pBottom = &theDefLine;
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
+ aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
+ nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
+ break;
+
+ case 13: // VERINNER
+ pLeft = pRight = pTop = pBottom = &theDefLine;
+ aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::HORI );
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT );
+ nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::VInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
+ break;
+
+ case 14: // ALL
+ pLeft = pRight = pTop = pBottom = &theDefLine;
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT );
+ nValidFlags |= FrmValidFlags::AllMask;
+ break;
+
+ case 15:
+ // set both diagonal lines to draw criss-cross line
+ dDownLineItem.SetLine(&dDownBorderLine);
+ dUpLineItem.SetLine(&dUpBorderLine);
+
+ SetDiagonalDownBorder(dDownLineItem);
+ SetDiagonalUpBorder(dUpLineItem);
+ bIsDiagonalBorder = true;
+ break; // CRISS-CROSS
+
+ default:
+ break;
+ }
+
+ // if diagonal borders selected,
+ // no need to execute this block
+ if (!bIsDiagonalBorder)
+ {
+ aBorderOuter.SetLine( pLeft, SvxBoxItemLine::LEFT );
+ aBorderOuter.SetLine( pRight, SvxBoxItemLine::RIGHT );
+ aBorderOuter.SetLine( pTop, SvxBoxItemLine::TOP );
+ aBorderOuter.SetLine( pBottom, SvxBoxItemLine::BOTTOM );
+
+ if(nModifier == KEY_SHIFT)
+ nValidFlags |= FrmValidFlags::AllMask;
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::TOP, bool(nValidFlags&FrmValidFlags::Top ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, bool(nValidFlags&FrmValidFlags::Bottom ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, bool(nValidFlags&FrmValidFlags::Left));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, bool(nValidFlags&FrmValidFlags::Right ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::HORI, bool(nValidFlags&FrmValidFlags::HInner ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::VERT, bool(nValidFlags&FrmValidFlags::VInner));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISABLE, false );
+
+ Any a1, a2;
+ aBorderOuter.QueryValue( a1 );
+ aBorderInner.QueryValue( a2 );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("OuterBorder", a1),
+ comphelper::makePropertyValue("InnerBorder", a2) };
+
+ mxControl->dispatchCommand( ".uno:SetBorderStyle", aArgs );
+ }
+
+ // coverity[ check_after_deref : FALSE]
+ if (mxFrameSet)
+ {
+ /* #i33380# Moved the following line above the Dispatch() call.
+ This instance may be deleted in the meantime (i.e. when a dialog is opened
+ while in Dispatch()), accessing members will crash in this case. */
+ mxFrameSet->SetNoSelection();
+ }
+
+ mxControl->EndPopupMode();
+}
+
+void SvxFrameWindow_Impl::SetDiagonalDownBorder(const SvxLineItem& dDownLineItem)
+{
+ // apply diagonal down border
+ Any a;
+ dDownLineItem.QueryValue(a);
+ Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderTLBR", a) };
+
+ mxControl->dispatchCommand(".uno:BorderTLBR", aArgs);
+}
+
+void SvxFrameWindow_Impl::SetDiagonalUpBorder(const SvxLineItem& dUpLineItem)
+{
+ // apply diagonal up border
+ Any a;
+ dUpLineItem.QueryValue(a);
+ Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderBLTR", a) };
+
+ mxControl->dispatchCommand(".uno:BorderBLTR", aArgs);
+}
+
+void SvxFrameWindow_Impl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ if ( rEvent.FeatureURL.Complete != ".uno:BorderReducedMode" )
+ return;
+
+ bool bValue;
+ if ( !(rEvent.State >>= bValue) )
+ return;
+
+ bParagraphMode = bValue;
+ //initial calls mustn't insert or remove elements
+ if(!mxFrameSet->GetItemCount())
+ return;
+
+ // set 12 border types for Writer, otherwise 15 for Calc.
+ bool bTableMode = ( mxFrameSet->GetItemCount() == static_cast<size_t>(m_bIsWriter ? 12 : 15) );
+ bool bResize = false;
+
+ if ( bTableMode && bParagraphMode )
+ {
+ for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
+ mxFrameSet->RemoveItem(i);
+ bResize = true;
+ }
+ else if ( !bTableMode && !bParagraphMode )
+ {
+ for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
+ mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
+ bResize = true;
+ }
+
+ if ( bResize )
+ {
+ CalcSizeValueSet();
+ }
+}
+
+void SvxFrameWindow_Impl::CalcSizeValueSet()
+{
+ weld::DrawingArea* pDrawingArea = mxFrameSet->GetDrawingArea();
+ const OutputDevice& rDevice = pDrawingArea->get_ref_device();
+ Size aItemSize( 20 * rDevice.GetDPIScaleFactor(), 20 * rDevice.GetDPIScaleFactor() );
+ Size aSize = mxFrameSet->CalcWindowSizePixel( aItemSize );
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ mxFrameSet->SetOutputSizePixel(aSize);
+}
+
+void SvxFrameWindow_Impl::InitImageList()
+{
+ if (m_bIsWriter)
+ {
+ // Writer-specific aImgVec.
+ // Since Writer doesn't have diagonal borders,
+ // we have to use 12 border types here.
+ aImgVec = {
+ {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)},
+ {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)},
+ {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)},
+ {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)},
+
+ {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)},
+ {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)},
+ {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)},
+ {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)},
+
+ {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)},
+ {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)},
+ {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)},
+ {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)}
+ };
+ }
+ else
+ {
+ // Calc has diagonal borders feature.
+ // Therefore use additional 3 diagonal border types,
+ // which make border types 15 in total.
+ aImgVec = {
+ {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)},
+ {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)},
+ {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)},
+ {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)},
+ {BitmapEx(RID_SVXBMP_FRAME14), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALDOWN)}, // diagonal down border
+
+ {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)},
+ {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)},
+ {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)},
+ {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)},
+ {BitmapEx(RID_SVXBMP_FRAME13), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALUP)}, // diagonal up border
+
+ {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)},
+ {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)},
+ {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)},
+ {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)},
+ {BitmapEx(RID_SVXBMP_FRAME15), SvxResId(RID_SVXSTR_PARA_PRESET_CRISSCROSS)} // criss-cross border
+ };
+ }
+}
+
+static Color lcl_mediumColor( Color aMain, Color /*aDefault*/ )
+{
+ return SvxBorderLine::threeDMediumColor( aMain );
+}
+
+SvxLineWindow_Impl::SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder")
+ , m_xControl(pControl)
+ , m_xLineStyleLb(new LineListBox)
+ , m_xLineStyleLbWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xLineStyleLb))
+ , m_bIsWriter(false)
+{
+ try
+ {
+ Reference< lang::XServiceInfo > xServices(m_xFrame->getController()->getModel(), UNO_QUERY_THROW);
+ m_bIsWriter = xServices->supportsService("com.sun.star.text.TextDocument");
+ }
+ catch(const uno::Exception& )
+ {
+ }
+
+ m_xLineStyleLb->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
+
+ m_xLineStyleLb->SetSourceUnit( FieldUnit::TWIP );
+ m_xLineStyleLb->SetNone( comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE)
+ :SvxResId(RID_SVXSTR_NONE) );
+
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::SOLID ), SvxBorderLineStyle::SOLID );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOTTED ), SvxBorderLineStyle::DOTTED );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DASHED ), SvxBorderLineStyle::DASHED );
+
+ // Double lines
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOUBLE ), SvxBorderLineStyle::DOUBLE );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_SMALLGAP ), SvxBorderLineStyle::THINTHICK_SMALLGAP, 20 );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_MEDIUMGAP ), SvxBorderLineStyle::THINTHICK_MEDIUMGAP );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_LARGEGAP ), SvxBorderLineStyle::THINTHICK_LARGEGAP );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_SMALLGAP ), SvxBorderLineStyle::THICKTHIN_SMALLGAP, 20 );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_MEDIUMGAP ), SvxBorderLineStyle::THICKTHIN_MEDIUMGAP );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_LARGEGAP ), SvxBorderLineStyle::THICKTHIN_LARGEGAP );
+
+ // Engraved / Embossed
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::EMBOSSED ), SvxBorderLineStyle::EMBOSSED, 15,
+ &SvxBorderLine::threeDLightColor, &SvxBorderLine::threeDDarkColor,
+ &lcl_mediumColor );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::ENGRAVED ), SvxBorderLineStyle::ENGRAVED, 15,
+ &SvxBorderLine::threeDDarkColor, &SvxBorderLine::threeDLightColor,
+ &lcl_mediumColor );
+
+ // Inset / Outset
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::OUTSET ), SvxBorderLineStyle::OUTSET, 10,
+ &SvxBorderLine::lightColor, &SvxBorderLine::darkColor );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::INSET ), SvxBorderLineStyle::INSET, 10,
+ &SvxBorderLine::darkColor, &SvxBorderLine::lightColor );
+ Size aSize = m_xLineStyleLb->SetWidth( 20 ); // 1pt by default
+
+ m_xLineStyleLb->SetSelectHdl( LINK( this, SvxLineWindow_Impl, SelectHdl ) );
+
+ m_xContainer->set_help_id(HID_POPUP_LINE);
+
+ aSize.AdjustWidth(6);
+ aSize.AdjustHeight(6);
+ aSize = m_xLineStyleLb->CalcWindowSizePixel(aSize);
+ m_xLineStyleLb->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
+ m_xLineStyleLb->SetOutputSizePixel(aSize);
+}
+
+IMPL_LINK_NOARG(SvxLineWindow_Impl, SelectHdl, ValueSet*, void)
+{
+ SvxLineItem aLineItem( SID_FRAME_LINESTYLE );
+ SvxBorderLineStyle nStyle = m_xLineStyleLb->GetSelectEntryStyle();
+
+ if ( m_xLineStyleLb->GetSelectItemPos( ) > 0 )
+ {
+ SvxBorderLine aTmp;
+ aTmp.SetBorderLineStyle( nStyle );
+ aTmp.SetWidth( SvxBorderLineWidth::Thin ); // TODO Make it depend on a width field
+ aLineItem.SetLine( &aTmp );
+ }
+ else
+ aLineItem.SetLine( nullptr );
+
+ Any a;
+ aLineItem.QueryValue( a, m_bIsWriter ? CONVERT_TWIPS : 0 );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("LineStyle", a) };
+
+ m_xControl->dispatchCommand( ".uno:LineStyle", aArgs );
+
+ m_xControl->EndPopupMode();
+}
+
+SfxStyleControllerItem_Impl::SfxStyleControllerItem_Impl(
+ const Reference< XDispatchProvider >& rDispatchProvider,
+ sal_uInt16 nSlotId, // Family-ID
+ const OUString& rCommand, // .uno: command bound to this item
+ SvxStyleToolBoxControl& rTbxCtl ) // controller instance, which the item is assigned to.
+ : SfxStatusListener( rDispatchProvider, nSlotId, rCommand ),
+ rControl( rTbxCtl )
+{
+}
+
+void SfxStyleControllerItem_Impl::StateChangedAtStatusListener(
+ SfxItemState eState, const SfxPoolItem* pState )
+{
+ switch ( GetId() )
+ {
+ case SID_STYLE_FAMILY1:
+ case SID_STYLE_FAMILY2:
+ case SID_STYLE_FAMILY3:
+ case SID_STYLE_FAMILY4:
+ case SID_STYLE_FAMILY5:
+ {
+ const sal_uInt16 nIdx = GetId() - SID_STYLE_FAMILY_START;
+
+ if ( SfxItemState::DEFAULT == eState )
+ {
+ const SfxTemplateItem* pStateItem =
+ dynamic_cast<const SfxTemplateItem*>( pState );
+ DBG_ASSERT( pStateItem != nullptr, "SfxTemplateItem expected" );
+ rControl.SetFamilyState( nIdx, pStateItem );
+ }
+ else
+ rControl.SetFamilyState( nIdx, nullptr );
+ break;
+ }
+ }
+}
+
+struct SvxStyleToolBoxControl::Impl
+{
+ OUString aClearForm;
+ OUString aMore;
+ ::std::vector< std::pair< OUString, OUString > > aDefaultStyles;
+ bool bSpecModeWriter;
+ bool bSpecModeCalc;
+
+ VclPtr<SvxStyleBox_Impl> m_xVclBox;
+ std::unique_ptr<SvxStyleBox_Base> m_xWeldBox;
+ SvxStyleBox_Base* m_pBox;
+
+ Impl()
+ :aClearForm ( SvxResId( RID_SVXSTR_CLEARFORM ) )
+ ,aMore ( SvxResId( RID_SVXSTR_MORE_STYLES ) )
+ ,bSpecModeWriter ( false )
+ ,bSpecModeCalc ( false )
+ ,m_pBox ( nullptr )
+ {
+
+
+ }
+ void InitializeStyles(const Reference < frame::XModel >& xModel)
+ {
+ aDefaultStyles.clear();
+
+ //now convert the default style names to the localized names
+ try
+ {
+ Reference< style::XStyleFamiliesSupplier > xStylesSupplier( xModel, UNO_QUERY_THROW );
+ Reference< lang::XServiceInfo > xServices( xModel, UNO_QUERY_THROW );
+ bSpecModeWriter = xServices->supportsService("com.sun.star.text.TextDocument");
+ if(bSpecModeWriter)
+ {
+ Reference<container::XNameAccess> xParaStyles;
+ xStylesSupplier->getStyleFamilies()->getByName("ParagraphStyles") >>=
+ xParaStyles;
+ static const std::vector<OUString> aWriterStyles =
+ {
+ "Standard",
+ "Text body",
+ "Title",
+ "Subtitle",
+ "Heading 1",
+ "Heading 2",
+ "Heading 3",
+ "Heading 4",
+ "Quotations",
+ "Preformatted Text"
+ };
+ for( const OUString& aStyle: aWriterStyles )
+ {
+ try
+ {
+ Reference< beans::XPropertySet > xStyle;
+ xParaStyles->getByName( aStyle ) >>= xStyle;
+ OUString sName;
+ xStyle->getPropertyValue("DisplayName") >>= sName;
+ if( !sName.isEmpty() )
+ aDefaultStyles.push_back(
+ std::pair<OUString, OUString>(aStyle, sName) );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+
+ }
+ else if( (
+ bSpecModeCalc = xServices->supportsService(
+ "com.sun.star.sheet.SpreadsheetDocument")))
+ {
+ static const char* aCalcStyles[] =
+ {
+ "Default",
+ "Accent 1",
+ "Accent 2",
+ "Accent 3",
+ "Heading 1",
+ "Heading 2",
+ "Result"
+ };
+ Reference<container::XNameAccess> xCellStyles;
+ xStylesSupplier->getStyleFamilies()->getByName("CellStyles") >>= xCellStyles;
+ for(const char* pCalcStyle : aCalcStyles)
+ {
+ try
+ {
+ const OUString sStyleName( OUString::createFromAscii( pCalcStyle ) );
+ if( xCellStyles->hasByName( sStyleName ) )
+ {
+ Reference< beans::XPropertySet > xStyle( xCellStyles->getByName( sStyleName), UNO_QUERY_THROW );
+ OUString sName;
+ xStyle->getPropertyValue("DisplayName") >>= sName;
+ if( !sName.isEmpty() )
+ aDefaultStyles.push_back(
+ std::pair<OUString, OUString>(sStyleName, sName) );
+ }
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ }
+ }
+ catch(const uno::Exception& )
+ {
+ OSL_FAIL("error while initializing style names");
+ }
+ }
+};
+
+// mapping table from bound items. BE CAREFUL this table must be in the
+// same order as the uno commands bound to the slots SID_STYLE_FAMILY1..n
+// MAX_FAMILIES must also be correctly set!
+static const char* StyleSlotToStyleCommand[MAX_FAMILIES] =
+{
+ ".uno:CharStyle",
+ ".uno:ParaStyle",
+ ".uno:FrameStyle",
+ ".uno:PageStyle",
+ ".uno:TemplateFamily5"
+};
+
+SvxStyleToolBoxControl::SvxStyleToolBoxControl()
+ : pImpl(new Impl)
+ , pStyleSheetPool(nullptr)
+ , nActFamily(0xffff)
+{
+ for (sal_uInt16 i = 0; i < MAX_FAMILIES; ++i)
+ {
+ m_xBoundItems[i].clear();
+ pFamilyState[i] = nullptr;
+ }
+}
+
+SvxStyleToolBoxControl::~SvxStyleToolBoxControl()
+{
+}
+
+void SAL_CALL SvxStyleToolBoxControl::initialize(const Sequence<Any>& rArguments)
+{
+ svt::ToolboxController::initialize(rArguments);
+
+ // After initialize we should have a valid frame member where we can retrieve our
+ // dispatch provider.
+ if ( !m_xFrame.is() )
+ return;
+
+ pImpl->InitializeStyles(m_xFrame->getController()->getModel());
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame->getController(), UNO_QUERY );
+ for ( sal_uInt16 i=0; i<MAX_FAMILIES; i++ )
+ {
+ m_xBoundItems[i] = new SfxStyleControllerItem_Impl( xDispatchProvider,
+ SID_STYLE_FAMILY_START + i,
+ OUString::createFromAscii( StyleSlotToStyleCommand[i] ),
+ *this );
+ pFamilyState[i] = nullptr;
+ }
+}
+
+// XComponent
+void SAL_CALL SvxStyleToolBoxControl::dispose()
+{
+ svt::ToolboxController::dispose();
+
+ SolarMutexGuard aSolarMutexGuard;
+ pImpl->m_xVclBox.disposeAndClear();
+ pImpl->m_xWeldBox.reset();
+ pImpl->m_pBox = nullptr;
+
+ for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems)
+ {
+ if (!pBoundItem)
+ continue;
+ pBoundItem->UnBind();
+ }
+ unbindListener();
+
+ for( sal_uInt16 i=0; i<MAX_FAMILIES; i++ )
+ {
+ if ( m_xBoundItems[i].is() )
+ {
+ try
+ {
+ m_xBoundItems[i]->dispose();
+ }
+ catch ( Exception& )
+ {
+ }
+
+ m_xBoundItems[i].clear();
+ }
+ pFamilyState[i].reset();
+ }
+ pStyleSheetPool = nullptr;
+ pImpl.reset();
+}
+
+OUString SvxStyleToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.StyleToolBoxControl";
+}
+
+sal_Bool SvxStyleToolBoxControl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService( this, rServiceName );
+}
+
+css::uno::Sequence< OUString > SvxStyleToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_StyleToolBoxControl_get_implementation(
+ css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxStyleToolBoxControl() );
+}
+
+void SAL_CALL SvxStyleToolBoxControl::update()
+{
+ for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems)
+ pBoundItem->ReBind();
+ bindListener();
+}
+
+SfxStyleFamily SvxStyleToolBoxControl::GetActFamily() const
+{
+ switch ( nActFamily-1 + SID_STYLE_FAMILY_START )
+ {
+ case SID_STYLE_FAMILY1: return SfxStyleFamily::Char;
+ case SID_STYLE_FAMILY2: return SfxStyleFamily::Para;
+ case SID_STYLE_FAMILY3: return SfxStyleFamily::Frame;
+ case SID_STYLE_FAMILY4: return SfxStyleFamily::Page;
+ case SID_STYLE_FAMILY5: return SfxStyleFamily::Pseudo;
+ default:
+ OSL_FAIL( "unknown style family" );
+ break;
+ }
+ return SfxStyleFamily::Para;
+}
+
+void SvxStyleToolBoxControl::FillStyleBox()
+{
+ SvxStyleBox_Base* pBox = pImpl->m_pBox;
+
+ DBG_ASSERT( pStyleSheetPool, "StyleSheetPool not found!" );
+ DBG_ASSERT( pBox, "Control not found!" );
+
+ if ( !(pStyleSheetPool && pBox && nActFamily!=0xffff) )
+ return;
+
+ const SfxStyleFamily eFamily = GetActFamily();
+ SfxStyleSheetBase* pStyle = nullptr;
+ bool bDoFill = false;
+
+ auto xIter = pStyleSheetPool->CreateIterator(eFamily, SfxStyleSearchBits::Used);
+ sal_uInt16 nCount = xIter->Count();
+
+ // Check whether fill is necessary
+ pStyle = xIter->First();
+ //!!! TODO: This condition isn't right any longer, because we always show some default entries
+ //!!! so the list doesn't show the count
+ if ( nCount != pBox->get_count() )
+ {
+ bDoFill = true;
+ }
+ else
+ {
+ sal_uInt16 i= 0;
+ while ( pStyle && !bDoFill )
+ {
+ bDoFill = ( pBox->get_text(i) != pStyle->GetName() );
+ pStyle = xIter->Next();
+ i++;
+ }
+ }
+
+ if ( !bDoFill )
+ return;
+
+ OUString aStrSel(pBox->get_active_text());
+ pBox->freeze();
+ pBox->clear();
+
+ std::vector<OUString> aStyles;
+
+ // add used styles
+ pStyle = xIter->Next();
+ while ( pStyle )
+ {
+ aStyles.push_back(pStyle->GetName());
+ pStyle = xIter->Next();
+ }
+
+ if (pImpl->bSpecModeWriter || pImpl->bSpecModeCalc)
+ {
+ pBox->append_text(pImpl->aClearForm);
+ pBox->insert_separator(1, "separator");
+
+ // add default styles if less than 12 items
+ for( const auto &rStyle : pImpl->aDefaultStyles )
+ {
+ if ( aStyles.size() + pBox->get_count() > 12)
+ break;
+ // insert default style only if not used (and added to rStyle before)
+ if (std::find(aStyles.begin(), aStyles.end(), rStyle.second) >= aStyles.end())
+ pBox->append_text(rStyle.second);
+ }
+ }
+ std::sort(aStyles.begin(), aStyles.end());
+
+ for (const auto& rStyle : aStyles)
+ pBox->append_text(rStyle);
+
+ if ((pImpl->bSpecModeWriter || pImpl->bSpecModeCalc) && !comphelper::LibreOfficeKit::isActive())
+ pBox->append_text(pImpl->aMore);
+
+ pBox->thaw();
+ pBox->set_active_or_entry_text(aStrSel);
+ pBox->SetFamily( eFamily );
+}
+
+void SvxStyleToolBoxControl::SelectStyle( const OUString& rStyleName )
+{
+ SvxStyleBox_Base* pBox = pImpl->m_pBox;
+ DBG_ASSERT( pBox, "Control not found!" );
+
+ if ( !pBox )
+ return;
+
+ OUString aStrSel(pBox->get_active_text());
+
+ if ( !rStyleName.isEmpty() )
+ {
+ OUString aNewStyle = rStyleName;
+
+ auto aFound = std::find_if(pImpl->aDefaultStyles.begin(), pImpl->aDefaultStyles.end(),
+ [rStyleName] (auto it) { return it.first == rStyleName || it.second == rStyleName; }
+ );
+
+ if (aFound != pImpl->aDefaultStyles.end())
+ aNewStyle = aFound->second;
+
+ if ( aNewStyle != aStrSel )
+ pBox->set_active_or_entry_text( aNewStyle );
+ }
+ else
+ pBox->set_active(-1);
+ pBox->save_value();
+}
+
+void SvxStyleToolBoxControl::Update()
+{
+ SfxStyleSheetBasePool* pPool = nullptr;
+ SfxObjectShell* pDocShell = SfxObjectShell::Current();
+
+ if ( pDocShell )
+ pPool = pDocShell->GetStyleSheetPool();
+
+ sal_uInt16 i;
+ for ( i=0; i<MAX_FAMILIES; i++ )
+ if( pFamilyState[i] )
+ break;
+
+ if ( i==MAX_FAMILIES || !pPool )
+ {
+ pStyleSheetPool = pPool;
+ return;
+ }
+
+
+ const SfxTemplateItem* pItem = nullptr;
+
+ if ( nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get()) )
+ // Current range not within allowed ranges or default
+ {
+ pStyleSheetPool = pPool;
+ nActFamily = 2;
+
+ pItem = pFamilyState[nActFamily-1].get();
+ if ( !pItem )
+ {
+ nActFamily++;
+ pItem = pFamilyState[nActFamily-1].get();
+ }
+ }
+ else if ( pPool != pStyleSheetPool )
+ pStyleSheetPool = pPool;
+
+ FillStyleBox(); // Decides by itself whether Fill is needed
+
+ if ( pItem )
+ SelectStyle( pItem->GetStyleName() );
+}
+
+void SvxStyleToolBoxControl::SetFamilyState( sal_uInt16 nIdx,
+ const SfxTemplateItem* pItem )
+{
+ pFamilyState[nIdx].reset( pItem == nullptr ? nullptr : new SfxTemplateItem( *pItem ) );
+ Update();
+}
+
+void SvxStyleToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+
+ if (m_pToolbar)
+ m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled);
+ else
+ {
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId( nId, &pToolBox ) )
+ return;
+ pToolBox->EnableItem( nId, rEvent.IsEnabled );
+ }
+
+ if (rEvent.IsEnabled)
+ Update();
+}
+
+css::uno::Reference<css::awt::XWindow> SvxStyleToolBoxControl::createItemWindow(const css::uno::Reference< css::awt::XWindow>& rParent)
+{
+ uno::Reference< awt::XWindow > xItemWindow;
+
+ if (m_pBuilder)
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("applystyle"));
+
+ xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
+
+ pImpl->m_xWeldBox.reset(new SvxStyleBox_Base(std::move(xWidget),
+ ".uno:StyleApply",
+ SfxStyleFamily::Para,
+ m_xFrame,
+ pImpl->aClearForm,
+ pImpl->aMore,
+ pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this));
+ pImpl->m_pBox = pImpl->m_xWeldBox.get();
+ }
+ else
+ {
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent);
+ if ( pParent )
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ pImpl->m_xVclBox = VclPtr<SvxStyleBox_Impl>::Create(pParent,
+ ".uno:StyleApply",
+ SfxStyleFamily::Para,
+ m_xFrame,
+ pImpl->aClearForm,
+ pImpl->aMore,
+ pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this);
+ pImpl->m_pBox = pImpl->m_xVclBox.get();
+ xItemWindow = VCLUnoHelper::GetInterface(pImpl->m_xVclBox);
+ }
+ }
+
+ if (pImpl->m_pBox && !pImpl->aDefaultStyles.empty())
+ pImpl->m_pBox->SetDefaultStyle(pImpl->aDefaultStyles[0].second);
+
+ return xItemWindow;
+}
+
+SvxFontNameToolBoxControl::SvxFontNameToolBoxControl()
+ : m_pBox(nullptr)
+{
+}
+
+void SvxFontNameBox_Base::statusChanged_Impl( const css::frame::FeatureStateEvent& rEvent )
+{
+ if ( !rEvent.IsEnabled )
+ {
+ set_sensitive(false);
+ Update( nullptr );
+ }
+ else
+ {
+ set_sensitive(true);
+
+ css::awt::FontDescriptor aFontDesc;
+ if ( rEvent.State >>= aFontDesc )
+ Update(&aFontDesc);
+ else {
+ // no active element; delete value in the display
+ m_xWidget->set_active(-1);
+ set_active_or_entry_text("");
+ }
+ m_xWidget->save_value();
+ }
+}
+
+void SvxFontNameToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+ m_pBox->statusChanged_Impl(rEvent);
+
+ if (m_pToolbar)
+ m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled);
+ else
+ {
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId( nId, &pToolBox ) )
+ return;
+ pToolBox->EnableItem( nId, rEvent.IsEnabled );
+ }
+}
+
+css::uno::Reference<css::awt::XWindow> SvxFontNameToolBoxControl::createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ uno::Reference< awt::XWindow > xItemWindow;
+
+ if (m_pBuilder)
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("fontnamecombobox"));
+
+ xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
+
+ m_xWeldBox.reset(new SvxFontNameBox_Base(std::move(xWidget), m_xFrame, *this));
+ m_pBox = m_xWeldBox.get();
+ }
+ else
+ {
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent);
+ if ( pParent )
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ m_xVclBox = VclPtr<SvxFontNameBox_Impl>::Create(pParent, m_xFrame, *this);
+ m_pBox = m_xVclBox.get();
+ xItemWindow = VCLUnoHelper::GetInterface(m_xVclBox);
+ }
+ }
+
+ return xItemWindow;
+}
+
+void SvxFontNameToolBoxControl::dispose()
+{
+ ToolboxController::dispose();
+
+ SolarMutexGuard aSolarMutexGuard;
+ m_xVclBox.disposeAndClear();
+ m_xWeldBox.reset();
+ m_pBox = nullptr;
+}
+
+OUString SvxFontNameToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.FontNameToolBoxControl";
+}
+
+sal_Bool SvxFontNameToolBoxControl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService( this, rServiceName );
+}
+
+css::uno::Sequence< OUString > SvxFontNameToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_FontNameToolBoxControl_get_implementation(
+ css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxFontNameToolBoxControl() );
+}
+
+SvxColorToolBoxControl::SvxColorToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) :
+ ImplInheritanceHelper( rContext, nullptr, OUString() ),
+ m_bSplitButton(true),
+ m_nSlotId(0),
+ m_aColorSelectFunction(PaletteManager::DispatchColorCommand)
+{
+}
+
+namespace {
+
+sal_uInt16 MapCommandToSlotId(const OUString& rCommand)
+{
+ if (rCommand == ".uno:Color")
+ return SID_ATTR_CHAR_COLOR;
+ else if (rCommand == ".uno:FontColor")
+ return SID_ATTR_CHAR_COLOR2;
+ else if (rCommand == ".uno:BackColor") // deprecated - use CharBackColor
+ return SID_ATTR_CHAR_COLOR_BACKGROUND;
+ else if (rCommand == ".uno:CharBackColor")
+ return SID_ATTR_CHAR_BACK_COLOR;
+ else if (rCommand == ".uno:BackgroundColor")
+ return SID_BACKGROUND_COLOR;
+ else if (rCommand == ".uno:TableCellBackgroundColor")
+ return SID_TABLE_CELL_BACKGROUND_COLOR;
+ else if (rCommand == ".uno:Extrusion3DColor")
+ return SID_EXTRUSION_3D_COLOR;
+ else if (rCommand == ".uno:XLineColor")
+ return SID_ATTR_LINE_COLOR;
+ else if (rCommand == ".uno:FillColor")
+ return SID_ATTR_FILL_COLOR;
+ else if (rCommand == ".uno:FrameLineColor")
+ return SID_FRAME_LINECOLOR;
+
+ SAL_WARN("svx.tbxcrtls", "Unknown color command: " << rCommand);
+ return 0;
+}
+
+}
+
+void SvxColorToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>& rArguments )
+{
+ PopupWindowController::initialize( rArguments );
+
+ m_nSlotId = MapCommandToSlotId( m_aCommandURL );
+
+ if ( m_nSlotId == SID_ATTR_LINE_COLOR || m_nSlotId == SID_ATTR_FILL_COLOR ||
+ m_nSlotId == SID_FRAME_LINECOLOR || m_nSlotId == SID_BACKGROUND_COLOR )
+ {
+ // Sidebar uses wide buttons for those.
+ m_bSplitButton = !m_bSidebar;
+ }
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(getCommandURL(), getModuleName());
+ OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
+ m_xBtnUpdater.reset(new svx::ToolboxButtonColorUpdater(m_nSlotId, m_aCommandURL, m_pToolbar, !m_bSplitButton, aCommandLabel, m_xFrame));
+ return;
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ {
+ m_xBtnUpdater.reset( new svx::VclToolboxButtonColorUpdater( m_nSlotId, nId, pToolBox, !m_bSplitButton, aCommandLabel, m_aCommandURL, m_xFrame ) );
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ( m_bSplitButton ? ToolBoxItemBits::DROPDOWN : ToolBoxItemBits::DROPDOWNONLY ) );
+ }
+}
+
+void SvxColorToolBoxControl::update()
+{
+ PopupWindowController::update();
+
+ switch( m_nSlotId )
+ {
+ case SID_ATTR_CHAR_COLOR2:
+ addStatusListener( ".uno:CharColorExt");
+ break;
+
+ case SID_ATTR_CHAR_BACK_COLOR:
+ case SID_ATTR_CHAR_COLOR_BACKGROUND:
+ addStatusListener( ".uno:CharBackgroundExt");
+ break;
+
+ case SID_FRAME_LINECOLOR:
+ addStatusListener( ".uno:BorderTLBR");
+ addStatusListener( ".uno:BorderBLTR");
+ break;
+ }
+}
+
+void SvxColorToolBoxControl::EnsurePaletteManager()
+{
+ if (!m_xPaletteManager)
+ {
+ m_xPaletteManager = std::make_shared<PaletteManager>();
+ m_xPaletteManager->SetBtnUpdater(m_xBtnUpdater.get());
+ }
+}
+
+SvxColorToolBoxControl::~SvxColorToolBoxControl()
+{
+ if (m_xPaletteManager)
+ m_xPaletteManager->SetBtnUpdater(nullptr);
+}
+
+void SvxColorToolBoxControl::setColorSelectFunction(const ColorSelectFunction& aColorSelectFunction)
+{
+ m_aColorSelectFunction = aColorSelectFunction;
+ if (m_xPaletteManager)
+ m_xPaletteManager->SetColorSelectFunction(aColorSelectFunction);
+}
+
+weld::Window* SvxColorToolBoxControl::GetParentFrame() const
+{
+ const css::uno::Reference<css::awt::XWindow> xParent = m_xFrame->getContainerWindow();
+ return Application::GetFrameWeld(xParent);
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxColorToolBoxControl::weldPopupWindow()
+{
+ EnsurePaletteManager();
+
+ auto xPopover = std::make_unique<ColorWindow>(
+ m_aCommandURL,
+ m_xPaletteManager,
+ m_aColorStatus,
+ m_nSlotId,
+ m_xFrame,
+ MenuOrToolMenuButton(m_pToolbar, m_aCommandURL),
+ [this] { return GetParentFrame(); },
+ m_aColorSelectFunction);
+
+ return xPopover;
+}
+
+VclPtr<vcl::Window> SvxColorToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId(nId, &pToolBox))
+ return nullptr;
+
+ EnsurePaletteManager();
+
+ auto xPopover = std::make_unique<ColorWindow>(
+ m_aCommandURL,
+ m_xPaletteManager,
+ m_aColorStatus,
+ m_nSlotId,
+ m_xFrame,
+ MenuOrToolMenuButton(this, pToolBox, nId),
+ [this] { return GetParentFrame(); },
+ m_aColorSelectFunction);
+
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::move(xPopover), true);
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(m_aCommandURL, m_sModuleName);
+ OUString aWindowTitle = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
+ mxInterimPopover->SetText(aWindowTitle);
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+void SvxColorToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId(nId, &pToolBox) && !m_pToolbar)
+ return;
+
+ if ( rEvent.FeatureURL.Complete == m_aCommandURL )
+ {
+ if (m_pToolbar)
+ m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled);
+ else
+ pToolBox->EnableItem( nId, rEvent.IsEnabled );
+ }
+
+ bool bValue;
+ if ( !m_bSplitButton )
+ {
+ m_aColorStatus.statusChanged( rEvent );
+ m_xBtnUpdater->Update( m_aColorStatus.GetColor() );
+ }
+ else if ( rEvent.State >>= bValue )
+ {
+ if (m_pToolbar)
+ m_pToolbar->set_item_active(m_aCommandURL, bValue);
+ else if (pToolBox)
+ pToolBox->CheckItem( nId, bValue );
+ }
+}
+
+void SvxColorToolBoxControl::execute(sal_Int16 /*nSelectModifier*/)
+{
+ if ( !m_bSplitButton )
+ {
+ if (m_pToolbar)
+ {
+ // Toggle the popup also when toolbutton is activated
+ m_pToolbar->set_menu_item_active(m_aCommandURL, !m_pToolbar->get_menu_item_active(m_aCommandURL));
+ }
+ else
+ {
+ // Open the popup also when Enter key is pressed.
+ createPopupWindow();
+ }
+ return;
+ }
+
+ OUString aCommand = m_aCommandURL;
+ Color aColor = m_xBtnUpdater->GetCurrentColor();
+
+ switch( m_nSlotId )
+ {
+ case SID_ATTR_CHAR_COLOR2 :
+ aCommand = ".uno:CharColorExt";
+ break;
+ }
+
+ auto aArgs( comphelper::InitPropertySequence( {
+ { m_aCommandURL.copy(5), css::uno::Any(aColor) }
+ } ) );
+ dispatchCommand( aCommand, aArgs );
+
+ EnsurePaletteManager();
+ OUString sColorName = m_xBtnUpdater->GetCurrentColorName();
+ m_xPaletteManager->AddRecentColor(aColor, sColorName);
+}
+
+sal_Bool SvxColorToolBoxControl::opensSubToolbar()
+{
+ // We mark this controller as a sub-toolbar controller, so we get notified
+ // (through updateImage method) on button image changes, and could redraw
+ // the last used color on top of it.
+ return true;
+}
+
+void SvxColorToolBoxControl::updateImage()
+{
+ m_xBtnUpdater->Update(m_xBtnUpdater->GetCurrentColor(), true);
+}
+
+OUString SvxColorToolBoxControl::getSubToolbarName()
+{
+ return OUString();
+}
+
+void SvxColorToolBoxControl::functionSelected( const OUString& /*rCommand*/ )
+{
+}
+
+OUString SvxColorToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.ColorToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxColorToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_ColorToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxColorToolBoxControl( rContext ) );
+}
+
+SvxFrameToolBoxControl::SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext )
+ : svt::PopupWindowController( rContext, nullptr, OUString() )
+{
+}
+
+void SAL_CALL SvxFrameToolBoxControl::execute(sal_Int16 /*KeyModifier*/)
+{
+ if (m_pToolbar)
+ {
+ // Toggle the popup also when toolbutton is activated
+ m_pToolbar->set_menu_item_active(m_aCommandURL, !m_pToolbar->get_menu_item_active(m_aCommandURL));
+ }
+ else
+ {
+ // Open the popup also when Enter key is pressed.
+ createPopupWindow();
+ }
+}
+
+void SvxFrameToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
+{
+ svt::PopupWindowController::initialize( rArguments );
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxFrameToolBoxControl::weldPopupWindow()
+{
+ if ( m_aCommandURL == ".uno:LineStyle" )
+ return std::make_unique<SvxLineWindow_Impl>(this, m_pToolbar);
+ return std::make_unique<SvxFrameWindow_Impl>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> SvxFrameToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ if ( m_aCommandURL == ".uno:LineStyle" )
+ {
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<SvxLineWindow_Impl>(this, pParent->GetFrameWeld()), true);
+
+ mxInterimPopover->Show();
+
+ mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME_STYLE));
+
+ return mxInterimPopover;
+ }
+
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<SvxFrameWindow_Impl>(this, pParent->GetFrameWeld()), true);
+
+ mxInterimPopover->Show();
+
+ mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME));
+
+ return mxInterimPopover;
+}
+
+OUString SvxFrameToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.FrameToolBoxControl";
+}
+
+css::uno::Sequence< OUString > SvxFrameToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_FrameToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxFrameToolBoxControl( rContext ) );
+}
+
+SvxCurrencyToolBoxControl::SvxCurrencyToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) :
+ PopupWindowController( rContext, nullptr, OUString() ),
+ m_eLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ),
+ m_nFormatKey( NUMBERFORMAT_ENTRY_NOT_FOUND )
+{
+}
+
+SvxCurrencyToolBoxControl::~SvxCurrencyToolBoxControl() {}
+
+namespace
+{
+ /** Implementation of the currency combo widget **/
+ class SvxCurrencyList_Impl : public WeldToolbarPopup
+ {
+ private:
+ rtl::Reference<SvxCurrencyToolBoxControl> m_xControl;
+ std::unique_ptr<weld::Label> m_xLabel;
+ std::unique_ptr<weld::TreeView> m_xCurrencyLb;
+ std::unique_ptr<weld::Button> m_xOkBtn;
+ OUString& m_rSelectedFormat;
+ LanguageType& m_eSelectedLanguage;
+
+ std::vector<OUString> m_aFormatEntries;
+ LanguageType m_eFormatLanguage;
+ DECL_LINK(RowActivatedHdl, weld::TreeView&, bool);
+ DECL_LINK(OKHdl, weld::Button&, void);
+
+ virtual void GrabFocus() override;
+
+ public:
+ SvxCurrencyList_Impl(SvxCurrencyToolBoxControl* pControl, weld::Widget* pParent, OUString& rSelectedFormat, LanguageType& eSelectedLanguage)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/currencywindow.ui", "CurrencyWindow")
+ , m_xControl(pControl)
+ , m_xLabel(m_xBuilder->weld_label("label"))
+ , m_xCurrencyLb(m_xBuilder->weld_tree_view("currency"))
+ , m_xOkBtn(m_xBuilder->weld_button("ok"))
+ , m_rSelectedFormat(rSelectedFormat)
+ , m_eSelectedLanguage(eSelectedLanguage)
+ {
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nLen = rCurrencyTable.size();
+
+ SvNumberFormatter aFormatter( m_xControl->getContext(), LANGUAGE_SYSTEM );
+ m_eFormatLanguage = aFormatter.GetLanguage();
+
+ const SvxCurrencyToolBoxControl::SvxCurrencyVect_t &rCurrencies = pControl->GetCurrencySymbols( );
+
+ sal_uInt16 nPos = 0, nCount = 0;
+ sal_Int32 nSelectedPos = -1;
+ bool bIsSymbol;
+ NfWSStringsDtor aStringsDtor;
+
+ OUString sLongestString;
+
+ m_xCurrencyLb->freeze();
+ for( const SvxCurrencyToolBoxControl::SvxCurrencyData& curr : rCurrencies )
+ {
+ const OUString& rItem = curr.m_label;
+ sal_uInt16 rCurrencyIndex = rCurrencies[ nCount ].m_currencyIdx;
+
+ if ( rCurrencyIndex < nLen )
+ {
+ m_xCurrencyLb->append_text(rItem);
+
+ if (rItem.getLength() > sLongestString.getLength())
+ sLongestString = rItem;
+
+ bIsSymbol = nPos >= nLen;
+
+ sal_uInt16 nDefaultFormat;
+ const NfCurrencyEntry& rCurrencyEntry = rCurrencyTable[ rCurrencyIndex ];
+ if (rCurrencyIndex == 0)
+ {
+ // Stored with system locale, but we want the resolved
+ // full LCID format string. For example
+ // "[$$-409]#,##0.00" instead of "[$$]#,##0.00".
+ NfCurrencyEntry aCurrencyEntry( rCurrencyEntry);
+ aCurrencyEntry.SetLanguage( LanguageTag( aCurrencyEntry.GetLanguage()).getLanguageType());
+ nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, aCurrencyEntry, bIsSymbol);
+ }
+ else
+ {
+ nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, rCurrencyEntry, bIsSymbol);
+ }
+ const OUString& rFormatStr = aStringsDtor[ nDefaultFormat ];
+ m_aFormatEntries.push_back( rFormatStr );
+ if( rFormatStr == m_rSelectedFormat )
+ nSelectedPos = nPos;
+ ++nPos;
+ }
+ ++nCount;
+ }
+ m_xCurrencyLb->thaw();
+ // enable multiple selection enabled so we can start with nothing selected
+ m_xCurrencyLb->set_selection_mode(SelectionMode::Multiple);
+ m_xCurrencyLb->connect_row_activated( LINK( this, SvxCurrencyList_Impl, RowActivatedHdl ) );
+ m_xLabel->set_label(SvxResId(RID_SVXSTR_TBLAFMT_CURRENCY));
+ m_xCurrencyLb->select( nSelectedPos );
+ m_xOkBtn->connect_clicked(LINK(this, SvxCurrencyList_Impl, OKHdl));
+
+ // gtk will initially make a best guess depending on the first few entries, so copy the probable
+ // longest entry to the start temporarily and force in the width at this point
+ m_xCurrencyLb->insert_text(0, sLongestString);
+ m_xCurrencyLb->set_size_request(m_xCurrencyLb->get_preferred_size().Width(), m_xCurrencyLb->get_height_rows(12));
+ m_xCurrencyLb->remove(0);
+ }
+ };
+
+ void SvxCurrencyList_Impl::GrabFocus()
+ {
+ m_xCurrencyLb->grab_focus();
+ }
+
+ IMPL_LINK_NOARG(SvxCurrencyList_Impl, OKHdl, weld::Button&, void)
+ {
+ RowActivatedHdl(*m_xCurrencyLb);
+ }
+
+ IMPL_LINK_NOARG(SvxCurrencyList_Impl, RowActivatedHdl, weld::TreeView&, bool)
+ {
+ if (!m_xControl.is())
+ return true;
+
+ // multiple selection enabled so we can start with nothing selected,
+ // so force single selection after something is picked
+ int nSelected = m_xCurrencyLb->get_selected_index();
+ if (nSelected == -1)
+ return true;
+
+ m_xCurrencyLb->set_selection_mode(SelectionMode::Single);
+
+ m_rSelectedFormat = m_aFormatEntries[nSelected];
+ m_eSelectedLanguage = m_eFormatLanguage;
+
+ m_xControl->execute(nSelected + 1);
+
+ m_xCurrencyLb->scroll_to_row(0);
+
+ m_xControl->EndPopupMode();
+
+ return true;
+ }
+}
+
+void SvxCurrencyToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
+{
+ PopupWindowController::initialize(rArguments);
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
+ return;
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox) && pToolBox->GetItemCommand(nId) == m_aCommandURL)
+ pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWN | pToolBox->GetItemBits(nId));
+}
+
+const SvxCurrencyToolBoxControl::SvxCurrencyVect_t &SvxCurrencyToolBoxControl::GetCurrencySymbols( ) {
+ inner_GetCurrencySymbols( true, m_currencies, m_mru_currencies );
+ return m_currencies;
+}
+
+void SvxCurrencyToolBoxControl::addMruCurrency(sal_Int16 currencyPosition) {
+ if (currencyPosition == 1)
+ return;
+
+ const SvxCurrencyData& curr = m_currencies[currencyPosition];
+ auto currencyIter = std::find( m_mru_currencies.begin(), m_mru_currencies.end(), curr );
+
+ if ( currencyIter != m_mru_currencies.end() )
+ m_mru_currencies.erase( currencyIter );
+
+ m_mru_currencies.insert( m_mru_currencies.begin(), curr );
+ if (m_mru_currencies.size() > MAX_MRU_CURRENCIES)
+ m_mru_currencies.resize( MAX_MRU_CURRENCIES );
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxCurrencyToolBoxControl::weldPopupWindow()
+{
+ return std::make_unique<SvxCurrencyList_Impl>(this, m_pToolbar, m_aFormatString, m_eLanguage);
+}
+
+VclPtr<vcl::Window> SvxCurrencyToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<SvxCurrencyList_Impl>(this, pParent->GetFrameWeld(), m_aFormatString, m_eLanguage));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+void SvxCurrencyToolBoxControl::execute( sal_Int16 nSelectModifier )
+{
+ sal_uInt32 nFormatKey;
+ if (m_aFormatString.isEmpty())
+ nFormatKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
+ else
+ {
+ if ( nSelectModifier > 0 )
+ {
+ try
+ {
+ uno::Reference< util::XNumberFormatsSupplier > xRef( m_xFrame->getController()->getModel(), uno::UNO_QUERY );
+ uno::Reference< util::XNumberFormats > rxNumberFormats( xRef->getNumberFormats(), uno::UNO_SET_THROW );
+ css::lang::Locale aLocale = LanguageTag::convertToLocale( m_eLanguage );
+ nFormatKey = rxNumberFormats->queryKey( m_aFormatString, aLocale, false );
+ if ( nFormatKey == NUMBERFORMAT_ENTRY_NOT_FOUND )
+ nFormatKey = rxNumberFormats->addNew( m_aFormatString, aLocale );
+ addMruCurrency(nSelectModifier);
+ }
+ catch( const uno::Exception& )
+ {
+ nFormatKey = m_nFormatKey;
+ }
+ }
+ else
+ nFormatKey = m_nFormatKey;
+ }
+
+ if( nFormatKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
+ {
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("NumberFormatCurrency",
+ nFormatKey) };
+ dispatchCommand( m_aCommandURL, aArgs );
+ m_nFormatKey = nFormatKey;
+ }
+ else
+ PopupWindowController::execute( nSelectModifier );
+}
+
+OUString SvxCurrencyToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.CurrencyToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxCurrencyToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_CurrencyToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxCurrencyToolBoxControl( rContext ) );
+}
+
+Reference< css::accessibility::XAccessible > SvxFontNameBox_Impl::CreateAccessible()
+{
+ FillList();
+ return InterimItemWindow::CreateAccessible();
+}
+
+//static
+sal_uInt16 const SvxCurrencyToolBoxControl::SvxCurrencyData::InvalidCurrency = INVALID_CURRENCY;
+
+SvxCurrencyToolBoxControl::SvxCurrencyData::SvxCurrencyData(
+ sal_uInt16 currencyIdx,
+ bool onlyIsoCode
+) :
+ m_currencyIdx(currencyIdx),
+ m_onlyIsoCode(onlyIsoCode)
+{}
+
+bool SvxCurrencyToolBoxControl::SvxCurrencyData::operator == (const SvxCurrencyData& other) const
+{
+ return
+ (m_currencyIdx == other.m_currencyIdx) &&
+ (m_onlyIsoCode == other.m_onlyIsoCode);
+}
+
+//static
+void SvxCurrencyToolBoxControl::GetCurrencySymbols( std::vector<OUString>& rList, bool bFlag,
+ std::vector<sal_uInt16>& rCurrencyList )
+{
+ SvxCurrencyVect_t currencies, mru_currencies;
+
+ inner_GetCurrencySymbols(bFlag, currencies, mru_currencies);
+
+ rList.resize(currencies.size());
+ rCurrencyList.resize(currencies.size());
+
+ for (size_t j = 0; j < currencies.size(); j++) {
+ rList[j] = std::move(currencies[j].m_label);
+ rCurrencyList[j] = currencies[j].m_currencyIdx;
+ }
+}
+
+//static
+void SvxCurrencyToolBoxControl::inner_GetCurrencySymbols(
+ bool bFlag,
+ SvxCurrencyVect_t &pCurrencies,
+ SvxCurrencyVect_t &p_mru_currencies)
+{
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nCount = rCurrencyTable.size();
+
+ // reserving space for mru currencies on top of vector after -1 element
+ pCurrencies.resize( p_mru_currencies.size() + 1);
+ std::fill( pCurrencies.begin() + 1, pCurrencies.end(), SvxCurrencyData() );
+
+ // lambda for vector insertion: mru currencies are on top
+ auto addCurrency = [&pCurrencies, &p_mru_currencies]
+ (SvxCurrencyData& curr, size_t position = SIZE_MAX)
+ {
+ auto mruIter = std::find(p_mru_currencies.begin(), p_mru_currencies.end(), curr);
+
+ if (mruIter == p_mru_currencies.end()) {
+ if (position == SIZE_MAX)
+ pCurrencies.push_back( std::move(curr) );
+ else
+ pCurrencies.insert( pCurrencies.begin() + position, std::move(curr) );
+ }
+ else {
+ size_t index = mruIter - p_mru_currencies.begin();
+ pCurrencies[index] = std::move(curr);
+ }
+ };
+
+ SvxCurrencyData aCurr( sal_uInt16(-1) );
+ aCurr.m_label = ApplyLreOrRleEmbedding( rCurrencyTable[0].GetSymbol() ) + " ";
+ aCurr.m_label += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString(
+ rCurrencyTable[0].GetLanguage() ) );
+
+ pCurrencies[0] = aCurr;
+ if( bFlag ) {
+ aCurr.m_currencyIdx = 0;
+ addCurrency( aCurr );
+ }
+
+ sal_uInt16 nStart = pCurrencies.size();
+
+ CollatorWrapper aCollator( ::comphelper::getProcessComponentContext() );
+ aCollator.loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 );
+
+ static constexpr OUString aTwoSpace(u" "_ustr);
+
+ // appending "long symbol" list
+ for( sal_uInt16 i = 1; i < nCount; ++i )
+ {
+ SvxCurrencyData curr( i );
+ curr.m_label = ApplyLreOrRleEmbedding( rCurrencyTable[i].GetBankSymbol() );
+ curr.m_label += aTwoSpace;
+ curr.m_label += ApplyLreOrRleEmbedding( rCurrencyTable[i].GetSymbol() );
+ curr.m_label += aTwoSpace;
+ curr.m_label += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString(
+ rCurrencyTable[i].GetLanguage() ) );
+
+ SvxCurrencyVect_t::size_type j = nStart;
+ for( ; j < pCurrencies.size(); ++j )
+ if ( aCollator.compareString( curr.m_label, pCurrencies[j].m_label ) < 0 )
+ break; // insert before first greater than
+
+ addCurrency( curr, j );
+ }
+
+ // Append ISO codes to symbol list.
+ // XXX If this is to be changed, various other places would had to be
+ // adapted that assume this order!
+ size_t nCont = pCurrencies.size();
+
+ for ( sal_uInt16 i = 1; i < nCount; ++i )
+ {
+ bool bInsert = true;
+ SvxCurrencyData curr( i, true );
+ curr.m_label = ApplyLreOrRleEmbedding(rCurrencyTable[i].GetBankSymbol());
+
+ size_t j = nCont;
+ for ( ; j < pCurrencies.size() && bInsert; ++j )
+ {
+ if( pCurrencies[j].m_label == curr.m_label )
+ bInsert = false;
+ else if ( aCollator.compareString( curr.m_label, pCurrencies[j].m_label ) < 0 )
+ break; // insert before first greater than
+ }
+ if ( bInsert )
+ addCurrency( curr, j );
+ }
+
+ for ( int j = p_mru_currencies.size() - 1; j > 0; j-- )
+ if ( pCurrencies[j].m_currencyIdx == SvxCurrencyData::InvalidCurrency )
+ pCurrencies.erase( pCurrencies.begin() + j );
+}
+
+ListBoxColorWrapper::ListBoxColorWrapper(ColorListBox* pControl)
+ : mpControl(pControl)
+{
+}
+
+void ListBoxColorWrapper::operator()(
+ [[maybe_unused]] const OUString& /*rCommand*/, const NamedColor& rColor)
+{
+ mpControl->Selected(rColor);
+}
+
+void ColorListBox::EnsurePaletteManager()
+{
+ if (!m_xPaletteManager)
+ {
+ m_xPaletteManager = std::make_shared<PaletteManager>();
+ m_xPaletteManager->SetColorSelectFunction(std::ref(m_aColorWrapper));
+ }
+}
+
+void ColorListBox::SetSlotId(sal_uInt16 nSlotId, bool bShowNoneButton)
+{
+ m_nSlotId = nSlotId;
+ m_bShowNoneButton = bShowNoneButton;
+ m_xButton->set_popover(nullptr);
+ m_xColorWindow.reset();
+ m_aSelectedColor = bShowNoneButton ? GetNoneColor() : GetAutoColor(m_nSlotId);
+ ShowPreview(m_aSelectedColor);
+ createColorWindow();
+}
+
+ColorListBox::ColorListBox(std::unique_ptr<weld::MenuButton> pControl,
+ TopLevelParentFunction aTopLevelParentFunction,
+ const ColorListBox* pCache)
+ : m_xButton(std::move(pControl))
+ , m_aColorWrapper(this)
+ , m_aAutoDisplayColor(Application::GetSettings().GetStyleSettings().GetDialogColor())
+ , m_nSlotId(0)
+ , m_bShowNoneButton(false)
+ , m_aTopLevelParentFunction(std::move(aTopLevelParentFunction))
+{
+ m_xButton->connect_toggled(LINK(this, ColorListBox, ToggleHdl));
+ m_aSelectedColor = GetAutoColor(m_nSlotId);
+ if (!pCache)
+ LockWidthRequest(CalcBestWidthRequest());
+ else
+ {
+ LockWidthRequest(pCache->m_xButton->get_size_request().Width());
+ m_xPaletteManager.reset(pCache->m_xPaletteManager->Clone());
+ m_xPaletteManager->SetColorSelectFunction(std::ref(m_aColorWrapper));
+ }
+ ShowPreview(m_aSelectedColor);
+}
+
+IMPL_LINK(ColorListBox, ToggleHdl, weld::Toggleable&, rButton, void)
+{
+ if (rButton.get_active())
+ {
+ ColorWindow* pColorWindow = getColorWindow();
+ if (pColorWindow && !comphelper::LibreOfficeKit::isActive())
+ pColorWindow->GrabFocus();
+ }
+}
+
+ColorListBox::~ColorListBox()
+{
+}
+
+ColorWindow* ColorListBox::getColorWindow() const
+{
+ if (!m_xColorWindow)
+ const_cast<ColorListBox*>(this)->createColorWindow();
+ return m_xColorWindow.get();
+}
+
+void ColorListBox::createColorWindow()
+{
+ const SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ const SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
+ css::uno::Reference<css::frame::XFrame> xFrame(pFrame ? pFrame->GetFrameInterface() : uno::Reference<css::frame::XFrame>());
+
+ EnsurePaletteManager();
+
+ m_xColorWindow.reset(new ColorWindow(
+ OUString() /*m_aCommandURL*/,
+ m_xPaletteManager,
+ m_aColorStatus,
+ m_nSlotId,
+ xFrame,
+ m_xButton.get(),
+ m_aTopLevelParentFunction,
+ m_aColorWrapper));
+
+ SetNoSelection();
+ m_xButton->set_popover(m_xColorWindow->getTopLevel());
+ if (m_bShowNoneButton)
+ m_xColorWindow->ShowNoneButton();
+ m_xColorWindow->SelectEntry(m_aSelectedColor);
+}
+
+void ColorListBox::SelectEntry(const NamedColor& rColor)
+{
+ if (o3tl::trim(rColor.m_aName).empty())
+ {
+ SelectEntry(rColor.m_aColor);
+ return;
+ }
+ ColorWindow* pColorWindow = getColorWindow();
+ pColorWindow->SelectEntry(rColor);
+ m_aSelectedColor = pColorWindow->GetSelectEntryColor();
+ ShowPreview(m_aSelectedColor);
+}
+
+void ColorListBox::SelectEntry(const Color& rColor)
+{
+ ColorWindow* pColorWindow = getColorWindow();
+ pColorWindow->SelectEntry(rColor);
+ m_aSelectedColor = pColorWindow->GetSelectEntryColor();
+ ShowPreview(m_aSelectedColor);
+}
+
+void ColorListBox::Selected(const NamedColor& rColor)
+{
+ ShowPreview(rColor);
+ m_aSelectedColor = rColor;
+ if (m_aSelectedLink.IsSet())
+ m_aSelectedLink.Call(*this);
+}
+
+//to avoid the box resizing every time the color is changed to
+//the optimal size of the individual color, get the longest
+//standard color and stick with that as the size for all
+int ColorListBox::CalcBestWidthRequest()
+{
+ NamedColor aLongestColor;
+ tools::Long nMaxStandardColorTextWidth = 0;
+ XColorListRef const xColorTable = XColorList::CreateStdColorList();
+ for (tools::Long i = 0; i != xColorTable->Count(); ++i)
+ {
+ XColorEntry& rEntry = *xColorTable->GetColor(i);
+ auto nColorTextWidth = m_xButton->get_pixel_size(rEntry.GetName()).Width();
+ if (nColorTextWidth > nMaxStandardColorTextWidth)
+ {
+ nMaxStandardColorTextWidth = nColorTextWidth;
+ aLongestColor.m_aName = rEntry.GetName();
+ }
+ }
+ ShowPreview(aLongestColor);
+ return m_xButton->get_preferred_size().Width();
+}
+
+void ColorListBox::LockWidthRequest(int nWidth)
+{
+ m_xButton->set_size_request(nWidth, -1);
+}
+
+void ColorListBox::ShowPreview(const NamedColor &rColor)
+{
+ // ScGridWindow::UpdateAutoFilterFromMenu is similar
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
+
+ ScopedVclPtrInstance<VirtualDevice> xDevice;
+ xDevice->SetOutputSize(aImageSize);
+ const tools::Rectangle aRect(Point(0, 0), aImageSize);
+ if (m_bShowNoneButton && rColor.m_aColor == COL_NONE_COLOR)
+ {
+ const Color aW(COL_WHITE);
+ const Color aG(0xef, 0xef, 0xef);
+ int nMinDim = std::min(aImageSize.Width(), aImageSize.Height()) + 1;
+ int nCheckSize = nMinDim / 3;
+ xDevice->DrawCheckered(aRect.TopLeft(), aRect.GetSize(), std::min(nCheckSize, 8), aW, aG);
+ xDevice->SetFillColor();
+ }
+ else
+ {
+ if (rColor.m_aColor == COL_AUTO)
+ xDevice->SetFillColor(m_aAutoDisplayColor);
+ else
+ xDevice->SetFillColor(rColor.m_aColor);
+ }
+
+ xDevice->SetLineColor(rStyleSettings.GetDisableColor());
+ xDevice->DrawRect(aRect);
+
+ m_xButton->set_image(xDevice.get());
+ m_xButton->set_label(rColor.m_aName);
+}
+
+MenuOrToolMenuButton::MenuOrToolMenuButton(weld::MenuButton* pMenuButton)
+ : m_pMenuButton(pMenuButton)
+ , m_pToolbar(nullptr)
+ , m_pControl(nullptr)
+ , m_nId(0)
+{
+}
+
+MenuOrToolMenuButton::MenuOrToolMenuButton(weld::Toolbar* pToolbar, OUString aIdent)
+ : m_pMenuButton(nullptr)
+ , m_pToolbar(pToolbar)
+ , m_aIdent(std::move(aIdent))
+ , m_pControl(nullptr)
+ , m_nId(0)
+{
+}
+
+MenuOrToolMenuButton::MenuOrToolMenuButton(SvxColorToolBoxControl* pControl, ToolBox* pToolbar, ToolBoxItemId nId)
+ : m_pMenuButton(nullptr)
+ , m_pToolbar(nullptr)
+ , m_pControl(pControl)
+ , m_xToolBox(pToolbar)
+ , m_nId(nId)
+{
+}
+
+MenuOrToolMenuButton::~MenuOrToolMenuButton()
+{
+}
+
+bool MenuOrToolMenuButton::get_active() const
+{
+ if (m_pMenuButton)
+ return m_pMenuButton->get_active();
+ if (m_pToolbar)
+ return m_pToolbar->get_menu_item_active(m_aIdent);
+ return m_xToolBox->GetDownItemId() == m_nId;
+}
+
+void MenuOrToolMenuButton::set_inactive() const
+{
+ if (m_pMenuButton)
+ {
+ if (m_pMenuButton->get_active())
+ m_pMenuButton->set_active(false);
+ return;
+ }
+ if (m_pToolbar)
+ {
+ if (m_pToolbar->get_menu_item_active(m_aIdent))
+ m_pToolbar->set_menu_item_active(m_aIdent, false);
+ return;
+ }
+ m_pControl->EndPopupMode();
+}
+
+weld::Widget* MenuOrToolMenuButton::get_widget() const
+{
+ if (m_pMenuButton)
+ return m_pMenuButton;
+ if (m_pToolbar)
+ return m_pToolbar;
+ return m_xToolBox->GetFrameWeld();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */