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