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