xref: /core/cui/source/tabpages/border.cxx (revision 9b8daf901566eda4eea87acc629621969b999482)
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 <sal/config.h>
21 
22 #include <sfx2/objsh.hxx>
23 #include <svx/strings.hrc>
24 #include <svx/svxids.hrc>
25 
26 #include <strings.hrc>
27 #include <bitmaps.hlst>
28 
29 #include <editeng/boxitem.hxx>
30 #include <editeng/lineitem.hxx>
31 #include <border.hxx>
32 #include <svx/dlgutil.hxx>
33 #include <dialmgr.hxx>
34 #include <sfx2/htmlmode.hxx>
35 #include <vcl/fieldvalues.hxx>
36 #include <vcl/settings.hxx>
37 #include <vcl/svapp.hxx>
38 #include <svx/dialmgr.hxx>
39 #include <svx/flagsdef.hxx>
40 #include <svl/grabbagitem.hxx>
41 #include <svl/intitem.hxx>
42 #include <svl/ilstitem.hxx>
43 #include <svl/int64item.hxx>
44 #include <com/sun/star/lang/XServiceInfo.hpp>
45 #include <comphelper/lok.hxx>
46 #include <svtools/unitconv.hxx>
47 #include <vcl/virdev.hxx>
48 
49 using namespace ::editeng;
50 using ::com::sun::star::uno::Reference;
51 using ::com::sun::star::lang::XServiceInfo;
52 using ::com::sun::star::uno::UNO_QUERY;
53 
54 
55 /*
56  * [Description:]
57  * TabPage for setting the border attributes.
58  * Needs
59  *      a SvxShadowItem: shadow
60  *      a SvxBoxItem:    lines left, right, top, bottom,
61  *      a SvxBoxInfo:    lines vertical, horizontal, distance, flags
62  *
63  * Lines can have three conditions:
64  *      1. Show     ( -> valid values )
65  *      2. Hide     ( -> NULL-Pointer )
66  *      3. DontCare ( -> special Valid-Flags in the InfoItem )
67  */
68 
69 // static ----------------------------------------------------------------
70 
71 const WhichRangesContainer SvxBorderTabPage::pRanges(
72     svl::Items<
73         SID_ATTR_BORDER_INNER,      SID_ATTR_BORDER_SHADOW,
74         SID_ATTR_ALIGN_MARGIN,      SID_ATTR_ALIGN_MARGIN,
75         SID_ATTR_BORDER_CONNECT,    SID_ATTR_BORDER_CONNECT,
76         SID_SW_COLLAPSING_BORDERS,  SID_SW_COLLAPSING_BORDERS,
77         SID_ATTR_BORDER_DIAG_TLBR,  SID_ATTR_BORDER_DIAG_BLTR>);
78 
79 namespace
80 {
twipsToPt100(sal_Int64 nTwips)81 constexpr int twipsToPt100(sal_Int64 nTwips)
82 {
83     return o3tl::convert(nTwips * 100, o3tl::Length::twip, o3tl::Length::pt);
84 }
85 constexpr int s_LineWidths[] = { twipsToPt100(SvxBorderLineWidth::Hairline),
86                                  twipsToPt100(SvxBorderLineWidth::VeryThin),
87                                  twipsToPt100(SvxBorderLineWidth::Thin),
88                                  twipsToPt100(SvxBorderLineWidth::Medium),
89                                  twipsToPt100(SvxBorderLineWidth::Thick),
90                                  twipsToPt100(SvxBorderLineWidth::ExtraThick),
91                                  -1 };
92 }
93 
lcl_SetDecimalDigitsTo1(weld::MetricSpinButton & rField)94 static void lcl_SetDecimalDigitsTo1(weld::MetricSpinButton& rField)
95 {
96     auto nMin = rField.denormalize(rField.get_min(FieldUnit::TWIP));
97     rField.set_digits(1);
98     rField.set_min(rField.normalize(nMin), FieldUnit::TWIP);
99 }
100 
101 // returns in pt
lcl_GetMinLineWidth(SvxBorderLineStyle aStyle)102 static sal_Int64 lcl_GetMinLineWidth(SvxBorderLineStyle aStyle)
103 {
104     switch (aStyle)
105     {
106     case SvxBorderLineStyle::NONE:
107         return 0;
108 
109     case SvxBorderLineStyle::SOLID:
110     case SvxBorderLineStyle::DOTTED:
111     case SvxBorderLineStyle::DASHED:
112     case SvxBorderLineStyle::FINE_DASHED:
113     case SvxBorderLineStyle::DASH_DOT:
114     case SvxBorderLineStyle::DASH_DOT_DOT:
115         return 15;
116 
117         // Double lines
118     case SvxBorderLineStyle::DOUBLE: return 15;
119     case SvxBorderLineStyle::DOUBLE_THIN: return 15;
120     case SvxBorderLineStyle::THINTHICK_SMALLGAP: return 20;
121     case SvxBorderLineStyle::THINTHICK_MEDIUMGAP: return 15;
122     case SvxBorderLineStyle::THINTHICK_LARGEGAP: return 15;
123     case SvxBorderLineStyle::THICKTHIN_SMALLGAP: return 20;
124     case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP: return 15;
125     case SvxBorderLineStyle::THICKTHIN_LARGEGAP: return 15;
126 
127     case SvxBorderLineStyle::EMBOSSED: return 15;
128     case SvxBorderLineStyle::ENGRAVED: return 15;
129 
130     case SvxBorderLineStyle::OUTSET: return 10;
131     case SvxBorderLineStyle::INSET: return 10;
132 
133     default:
134         return 15;
135     }
136 }
137 
138 // number of preset images to show
139 const sal_uInt16 BORDER_PRESET_COUNT = 5;
140 
141 // number of shadow images to show
142 const sal_uInt16 BORDER_SHADOW_COUNT = 5;
143 
ShadowControlsWrapper(weld::IconView & rIvPos,weld::MetricSpinButton & rMfSize,ColorListBox & rLbColor)144 ShadowControlsWrapper::ShadowControlsWrapper(weld::IconView& rIvPos, weld::MetricSpinButton& rMfSize, ColorListBox& rLbColor)
145     : mrIvPos(rIvPos)
146     , mrMfSize(rMfSize)
147     , mrLbColor(rLbColor)
148 {
149 }
150 
GetControlValue(const SvxShadowItem & rItem) const151 SvxShadowItem ShadowControlsWrapper::GetControlValue(const SvxShadowItem& rItem) const
152 {
153     SvxShadowItem aItem(rItem);
154     OUString sSelectedId = mrIvPos.get_selected_id();
155     if (!sSelectedId.isEmpty())
156     {
157         sal_Int32 nSelectedId = sSelectedId.toInt32();
158         switch (nSelectedId)
159         {
160             case 1:
161                 aItem.SetLocation(SvxShadowLocation::NONE);
162                 break;
163             case 2:
164                 aItem.SetLocation(SvxShadowLocation::BottomRight);
165                 break;
166             case 3:
167                 aItem.SetLocation(SvxShadowLocation::TopRight);
168                 break;
169             case 4:
170                 aItem.SetLocation(SvxShadowLocation::BottomLeft);
171                 break;
172             case 5:
173                 aItem.SetLocation(SvxShadowLocation::TopLeft);
174                 break;
175             default:
176                 aItem.SetLocation(SvxShadowLocation::NONE);
177                 break;
178         }
179     }
180     // Default value was saved; so don't change the aItem's width if the control
181     // has not changed its value, to avoid round-trip errors (like twip->cm->twip)
182     // E.g., initial 100 twip will become 0.18 cm, which will return as 102 twip
183     if (mrMfSize.get_value_changed_from_saved())
184         aItem.SetWidth(mrMfSize.denormalize(mrMfSize.get_value(FieldUnit::TWIP)));
185     if (!mrLbColor.IsNoSelection())
186         aItem.SetColor(mrLbColor.GetSelectEntryColor());
187     return aItem;
188 }
189 
SetControlValue(const SvxShadowItem & rItem)190 void ShadowControlsWrapper::SetControlValue(const SvxShadowItem& rItem)
191 {
192     switch (rItem.GetLocation())
193     {
194         case SvxShadowLocation::NONE:
195             mrIvPos.select(0);
196             break;
197         case SvxShadowLocation::BottomRight:
198             mrIvPos.select(1);
199             break;
200         case SvxShadowLocation::TopRight:
201             mrIvPos.select(2);
202             break;
203         case SvxShadowLocation::BottomLeft:
204             mrIvPos.select(3);
205             break;
206         case SvxShadowLocation::TopLeft:
207             mrIvPos.select(4);
208             break;
209         default:
210             mrIvPos.unselect_all();
211             break;
212     }
213     msSavedShadowItemId = mrIvPos.get_selected_id();
214     mrMfSize.set_value(mrMfSize.normalize(rItem.GetWidth()), FieldUnit::TWIP);
215     mrMfSize.save_value();
216     mrLbColor.SelectEntry(rItem.GetColor());
217     mrLbColor.SaveValue();
218 }
219 
get_value_changed_from_saved() const220 bool ShadowControlsWrapper::get_value_changed_from_saved() const
221 {
222     return (mrIvPos.get_selected_id() != msSavedShadowItemId) ||
223            mrMfSize.get_value_changed_from_saved() ||
224            mrLbColor.IsValueChangedFromSaved();
225 }
226 
SetControlDontKnow()227 void ShadowControlsWrapper::SetControlDontKnow()
228 {
229     mrIvPos.unselect_all();
230     mrMfSize.set_text(u""_ustr);
231     mrLbColor.SetNoSelection();
232 }
233 
MarginControlsWrapper(weld::MetricSpinButton & rMfLeft,weld::MetricSpinButton & rMfRight,weld::MetricSpinButton & rMfTop,weld::MetricSpinButton & rMfBottom)234 MarginControlsWrapper::MarginControlsWrapper(weld::MetricSpinButton& rMfLeft, weld::MetricSpinButton& rMfRight,
235                                              weld::MetricSpinButton& rMfTop, weld::MetricSpinButton& rMfBottom)
236     : mrLeftWrp(rMfLeft)
237     , mrRightWrp(rMfRight)
238     , mrTopWrp(rMfTop)
239     , mrBottomWrp(rMfBottom)
240 {
241 }
242 
GetControlValue(const SvxMarginItem & rItem) const243 SvxMarginItem MarginControlsWrapper::GetControlValue(const SvxMarginItem &rItem) const
244 {
245     SvxMarginItem aItem(rItem);
246     if (mrLeftWrp.get_sensitive())
247         aItem.SetLeftMargin(mrLeftWrp.denormalize(mrLeftWrp.get_value(FieldUnit::TWIP)));
248     if (mrRightWrp.get_sensitive())
249         aItem.SetRightMargin(mrRightWrp.denormalize(mrRightWrp.get_value(FieldUnit::TWIP)));
250     if (mrTopWrp.get_sensitive())
251         aItem.SetTopMargin(mrTopWrp.denormalize(mrTopWrp.get_value(FieldUnit::TWIP)));
252     if (mrBottomWrp.get_sensitive())
253         aItem.SetBottomMargin(mrBottomWrp.denormalize(mrBottomWrp.get_value(FieldUnit::TWIP)));
254     return aItem;
255 }
256 
get_value_changed_from_saved() const257 bool MarginControlsWrapper::get_value_changed_from_saved() const
258 {
259     return mrLeftWrp.get_value_changed_from_saved() ||
260            mrRightWrp.get_value_changed_from_saved() ||
261            mrTopWrp.get_value_changed_from_saved() ||
262            mrBottomWrp.get_value_changed_from_saved();
263 }
264 
SetControlValue(const SvxMarginItem & rItem)265 void MarginControlsWrapper::SetControlValue(const SvxMarginItem& rItem)
266 {
267     mrLeftWrp.set_value(mrLeftWrp.normalize(rItem.GetLeftMargin()), FieldUnit::TWIP);
268     mrRightWrp.set_value(mrRightWrp.normalize(rItem.GetRightMargin()), FieldUnit::TWIP);
269     mrTopWrp.set_value(mrTopWrp.normalize(rItem.GetTopMargin()), FieldUnit::TWIP);
270     mrBottomWrp.set_value(mrBottomWrp.normalize(rItem.GetBottomMargin()), FieldUnit::TWIP);
271     mrLeftWrp.save_value();
272     mrRightWrp.save_value();
273     mrTopWrp.save_value();
274     mrBottomWrp.save_value();
275 }
276 
SetControlDontKnow()277 void MarginControlsWrapper::SetControlDontKnow()
278 {
279     const OUString sEmpty;
280     mrLeftWrp.set_text(sEmpty);
281     mrRightWrp.set_text(sEmpty);
282     mrTopWrp.set_text(sEmpty);
283     mrBottomWrp.set_text(sEmpty);
284 }
285 
SvxBorderTabPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rCoreAttrs)286 SvxBorderTabPage::SvxBorderTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
287     : SfxTabPage(pPage, pController, u"cui/ui/borderpage.ui"_ustr, u"BorderPage"_ustr, &rCoreAttrs)
288     , nMinValue(0)
289     , nSWMode(SwBorderModes::NONE)
290     , mnBoxSlot(SID_ATTR_BORDER_OUTER)
291     , mnShadowSlot(SID_ATTR_BORDER_SHADOW)
292     , mbHorEnabled(false)
293     , mbVerEnabled(false)
294     , mbTLBREnabled(false)
295     , mbBLTREnabled(false)
296     , mbUseMarginItem(false)
297     , mbLeftModified(false)
298     , mbRightModified(false)
299     , mbTopModified(false)
300     , mbBottomModified(false)
301     , mbSync(true)
302     , mbRemoveAdjacentCellBorders(false)
303     , bIsCalcDoc(false)
304     , m_xWndPresets(m_xBuilder->weld_icon_view(u"presets"_ustr))
305     , m_xUserDefFT(m_xBuilder->weld_label(u"userdefft"_ustr))
306     , m_xFrameSelWin(new weld::CustomWeld(*m_xBuilder, u"framesel"_ustr, m_aFrameSel))
307     , m_xLbLineStyle(new SvtLineListBox(m_xBuilder->weld_menu_button(u"linestylelb"_ustr)))
308     , m_xLbLineColor(new ColorListBox(m_xBuilder->weld_menu_button(u"linecolorlb"_ustr),
309                 [this]{ return GetDialogController()->getDialog(); }))
310     , m_xLineWidthLB(m_xBuilder->weld_combo_box(u"linewidthlb"_ustr))
311     , m_xLineWidthMF(m_xBuilder->weld_metric_spin_button(u"linewidthmf"_ustr, FieldUnit::POINT))
312     , m_xSpacingFrame(m_xBuilder->weld_container(u"spacing"_ustr))
313     , m_xLeftFT(m_xBuilder->weld_label(u"leftft"_ustr))
314     , m_xLeftMF(m_xBuilder->weld_metric_spin_button(u"leftmf"_ustr, FieldUnit::MM))
315     , m_xRightFT(m_xBuilder->weld_label(u"rightft"_ustr))
316     , m_xRightMF(m_xBuilder->weld_metric_spin_button(u"rightmf"_ustr, FieldUnit::MM))
317     , m_xTopFT(m_xBuilder->weld_label(u"topft"_ustr))
318     , m_xTopMF(m_xBuilder->weld_metric_spin_button(u"topmf"_ustr, FieldUnit::MM))
319     , m_xBottomFT(m_xBuilder->weld_label(u"bottomft"_ustr))
320     , m_xBottomMF(m_xBuilder->weld_metric_spin_button(u"bottommf"_ustr, FieldUnit::MM))
321     , m_xSynchronizeCB(m_xBuilder->weld_check_button(u"sync"_ustr))
322     , m_xShadowFrame(m_xBuilder->weld_container(u"shadow"_ustr))
323     , m_xWndShadows(m_xBuilder->weld_icon_view(u"shadows"_ustr))
324     , m_xFtShadowSize(m_xBuilder->weld_label(u"distanceft"_ustr))
325     , m_xEdShadowSize(m_xBuilder->weld_metric_spin_button(u"distancemf"_ustr, FieldUnit::MM))
326     , m_xFtShadowColor(m_xBuilder->weld_label(u"shadowcolorft"_ustr))
327     , m_xLbShadowColor(new ColorListBox(m_xBuilder->weld_menu_button(u"shadowcolorlb"_ustr),
__anonec23e7ba0302null328                 [this]{ return GetDialogController()->getDialog(); }))
329     , m_xPropertiesFrame(m_xBuilder->weld_container(u"properties"_ustr))
330     , m_xMergeWithNextCB(m_xBuilder->weld_check_button(u"mergewithnext"_ustr))
331     , m_xMergeAdjacentBordersCB(m_xBuilder->weld_check_button(u"mergeadjacent"_ustr))
332     , m_xRemoveAdjacentCellBordersCB(m_xBuilder->weld_check_button(u"rmadjcellborders"_ustr))
333     , m_xRemoveAdjacentCellBordersFT(m_xBuilder->weld_label(u"rmadjcellbordersft"_ustr))
334 {
335     static std::vector<OUString> aBorderImageIds;
336 
337     if (aBorderImageIds.empty())
338     {
339         if (comphelper::LibreOfficeKit::isActive())
340         {
341             aBorderImageIds.insert(aBorderImageIds.end(), {
342                 RID_SVXBMP_CELL_NONE_32,
343                 RID_SVXBMP_CELL_ALL_32,
344                 RID_SVXBMP_CELL_LR_32,
345                 RID_SVXBMP_CELL_TB_32,
346                 RID_SVXBMP_CELL_L_32,
347                 RID_SVXBMP_CELL_DIAG_32
348             });
349         }
350         else
351         {
352             aBorderImageIds.insert(aBorderImageIds.end(), {
353                 RID_SVXBMP_CELL_NONE,
354                 RID_SVXBMP_CELL_ALL,
355                 RID_SVXBMP_CELL_LR,
356                 RID_SVXBMP_CELL_TB,
357                 RID_SVXBMP_CELL_L,
358                 RID_SVXBMP_CELL_DIAG
359             });
360         }
361         aBorderImageIds.insert(aBorderImageIds.end(), {
362             RID_SVXBMP_HOR_NONE,
363             RID_SVXBMP_HOR_OUTER,
364             RID_SVXBMP_HOR_HOR,
365             RID_SVXBMP_HOR_ALL,
366             RID_SVXBMP_HOR_OUTER2,
367             RID_SVXBMP_VER_NONE,
368             RID_SVXBMP_VER_OUTER,
369             RID_SVXBMP_VER_VER,
370             RID_SVXBMP_VER_ALL,
371             RID_SVXBMP_VER_OUTER2,
372             RID_SVXBMP_TABLE_NONE,
373             RID_SVXBMP_TABLE_OUTER,
374             RID_SVXBMP_TABLE_OUTERH,
375             RID_SVXBMP_TABLE_ALL,
376             RID_SVXBMP_TABLE_OUTER2
377         });
378     }
379 
380     for (auto const & rImageId : aBorderImageIds)
381         m_aBorderImgVec.emplace_back(StockImage::Yes, rImageId);
382 
383     static std::vector<OUString> aShadowImageIds;
384     if (aShadowImageIds.empty())
385     {
386         if (comphelper::LibreOfficeKit::isActive())
387         {
388             aShadowImageIds.insert(aShadowImageIds.end(), {
389                 RID_SVXBMP_SHADOWNONE_32,
390                 RID_SVXBMP_SHADOW_BOT_RIGHT_32,
391                 RID_SVXBMP_SHADOW_TOP_RIGHT_32,
392                 RID_SVXBMP_SHADOW_BOT_LEFT_32,
393                 RID_SVXBMP_SHADOW_TOP_LEFT_32
394             });
395         }
396         else
397         {
398             aShadowImageIds.insert(aShadowImageIds.end(), {
399                 RID_SVXBMP_SHADOWNONE,
400                 RID_SVXBMP_SHADOW_BOT_RIGHT,
401                 RID_SVXBMP_SHADOW_TOP_RIGHT,
402                 RID_SVXBMP_SHADOW_BOT_LEFT,
403                 RID_SVXBMP_SHADOW_TOP_LEFT
404             });
405         }
406     }
407 
408     for (auto const & rImageId : aShadowImageIds)
409         m_aShadowImgVec.emplace_back(StockImage::Yes, rImageId);
410 
411     assert(m_aShadowImgVec.size() == BORDER_SHADOW_COUNT);
412 
413     // this page needs ExchangeSupport
414     SetExchangeSupport();
415 
416     /*  Use SvxMarginItem instead of margins from SvxBoxItem, if present.
417         ->  Remember this state in mbUseMarginItem, because other special handling
418             is needed across various functions... */
419     mbUseMarginItem = rCoreAttrs.GetItemState(GetWhich(SID_ATTR_ALIGN_MARGIN)) != SfxItemState::UNKNOWN;
420 
421     if (const SfxIntegerListItem* p = rCoreAttrs.GetItemIfSet(SID_ATTR_BORDER_STYLES))
422     {
423         std::vector<sal_Int32> aUsedStyles = p->GetList();
424         for (int aUsedStyle : aUsedStyles)
425             maUsedBorderStyles.insert(static_cast<SvxBorderLineStyle>(aUsedStyle));
426     }
427 
428     if (const SfxInt64Item* p = rCoreAttrs.GetItemIfSet(SID_ATTR_BORDER_DEFAULT_WIDTH))
429     {
430         // The caller specifies default line width.  Honor it.
431         SetLineWidth(p->GetValue());
432     }
433 
434     // set metric
435     FieldUnit eFUnit = GetModuleFieldUnit( rCoreAttrs );
436 
437     if( mbUseMarginItem )
438     {
439         // copied from SvxAlignmentTabPage
440         switch ( eFUnit )
441         {
442             //  #103396# the default value (1pt) can't be accurately represented in
443             //  inches or pica with two decimals, so point is used instead.
444             case FieldUnit::PICA:
445             case FieldUnit::INCH:
446             case FieldUnit::FOOT:
447             case FieldUnit::MILE:
448                 eFUnit = FieldUnit::POINT;
449                 break;
450 
451             case FieldUnit::CM:
452             case FieldUnit::M:
453             case FieldUnit::KM:
454                 eFUnit = FieldUnit::MM;
455                 break;
456             default: ;//prevent warning
457         }
458     }
459     else
460     {
461         switch ( eFUnit )
462         {
463             case FieldUnit::M:
464             case FieldUnit::KM:
465                 eFUnit = FieldUnit::MM;
466                 break;
467             default: ; //prevent warning
468         }
469     }
470 
471     SetFieldUnit(*m_xEdShadowSize, eFUnit);
472 
473     sal_uInt16 nWhich = GetWhich( SID_ATTR_BORDER_INNER, false );
474     bool bIsDontCare = true;
475 
476     if ( rCoreAttrs.GetItemState( nWhich ) >= SfxItemState::DEFAULT )
477     {
478         // paragraph or table
479         const SvxBoxInfoItem* pBoxInfo =
480             static_cast<const SvxBoxInfoItem*>(&( rCoreAttrs.Get( nWhich ) ));
481 
482         mbHorEnabled = pBoxInfo->IsHorEnabled();
483         mbVerEnabled = pBoxInfo->IsVerEnabled();
484         mbTLBREnabled = rCoreAttrs.GetItemState(GetWhich(SID_ATTR_BORDER_DIAG_TLBR)) != SfxItemState::UNKNOWN;
485         mbBLTREnabled = rCoreAttrs.GetItemState(GetWhich(SID_ATTR_BORDER_DIAG_BLTR)) != SfxItemState::UNKNOWN;
486 
487         if(pBoxInfo->IsDist())
488         {
489             SetFieldUnit(*m_xLeftMF, eFUnit);
490             SetFieldUnit(*m_xRightMF, eFUnit);
491             SetFieldUnit(*m_xTopMF, eFUnit);
492             SetFieldUnit(*m_xBottomMF, eFUnit);
493             m_xSynchronizeCB->connect_toggled(LINK(this, SvxBorderTabPage, SyncHdl_Impl));
494             m_xLeftMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyDistanceHdl_Impl));
495             m_xRightMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyDistanceHdl_Impl));
496             m_xTopMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyDistanceHdl_Impl));
497             m_xBottomMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyDistanceHdl_Impl));
498         }
499         else
500         {
501             m_xSpacingFrame->hide();
502         }
503         bIsDontCare = !pBoxInfo->IsValid( SvxBoxInfoItemValidFlags::DISABLE );
504     }
505     if(!mbUseMarginItem && eFUnit == FieldUnit::MM && MapUnit::MapTwip == rCoreAttrs.GetPool()->GetMetric( GetWhich( SID_ATTR_BORDER_INNER ) ))
506     {
507         //#i91548# changing the number of decimal digits changes the minimum values, too
508         lcl_SetDecimalDigitsTo1(*m_xLeftMF);
509         lcl_SetDecimalDigitsTo1(*m_xRightMF);
510         lcl_SetDecimalDigitsTo1(*m_xTopMF);
511         lcl_SetDecimalDigitsTo1(*m_xBottomMF);
512         lcl_SetDecimalDigitsTo1(*m_xEdShadowSize);
513     }
514 
515     FrameSelFlags nFlags = FrameSelFlags::Outer;
516     if( mbHorEnabled )
517         nFlags |= FrameSelFlags::InnerHorizontal;
518     if( mbVerEnabled )
519         nFlags |= FrameSelFlags::InnerVertical;
520     if( mbTLBREnabled )
521         nFlags |= FrameSelFlags::DiagonalTLBR;
522     if( mbBLTREnabled )
523         nFlags |= FrameSelFlags::DiagonalBLTR;
524     if( bIsDontCare )
525         nFlags |= FrameSelFlags::DontCare;
526     m_aFrameSel.Initialize( nFlags );
527 
528     m_aFrameSel.SetSelectHdl(LINK(this, SvxBorderTabPage, LinesChanged_Impl));
529     m_xLbLineStyle->SetSelectHdl( LINK( this, SvxBorderTabPage, SelStyleHdl_Impl ) );
530     m_xLbLineColor->SetSelectHdl( LINK( this, SvxBorderTabPage, SelColHdl_Impl ) );
531     m_xLineWidthLB->connect_changed(LINK(this, SvxBorderTabPage, ModifyWidthLBHdl_Impl));
532     m_xLineWidthMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyWidthMFHdl_Impl));
533     m_xWndPresets->connect_selection_changed( LINK( this, SvxBorderTabPage, SelPreHdl_Impl ) );
534     m_xWndPresets->connect_focus_out(LINK(this, SvxBorderTabPage, FocusOutPresets_Impl));
535     m_xWndShadows->connect_selection_changed( LINK( this, SvxBorderTabPage, SelSdwHdl_Impl ) );
536     m_xWndPresets->connect_query_tooltip( LINK( this, SvxBorderTabPage, QueryTooltipPreHdl ) );
537     m_xWndShadows->connect_query_tooltip( LINK( this, SvxBorderTabPage, QueryTooltipSdwHdl ) );
538 
539     FillIconViews();
540     FillLineListBox_Impl();
541 
542     // Reapply line width: probably one of predefined values should be selected
543     SetLineWidth(m_xLineWidthMF->get_value(FieldUnit::NONE));
544 
545     // connections
546     const SfxPoolItem* pItem = nullptr;
547     if (rCoreAttrs.HasItem(GetWhich(SID_ATTR_PARA_GRABBAG), &pItem))
548     {
549         const SfxGrabBagItem* pGrabBag = static_cast<const SfxGrabBagItem*>(pItem);
550         auto it = pGrabBag->GetGrabBag().find(u"DialogUseCharAttr"_ustr);
551         if (it != pGrabBag->GetGrabBag().end())
552         {
553             bool bDialogUseCharAttr = false;
554             it->second >>= bDialogUseCharAttr;
555             if (bDialogUseCharAttr)
556             {
557                 mnShadowSlot = SID_ATTR_CHAR_SHADOW;
558                 mnBoxSlot = SID_ATTR_CHAR_BOX;
559             }
560         }
561     }
562 
563     bool bSupportsShadow = !SfxItemPool::IsSlot(GetWhich(mnShadowSlot));
564     if( bSupportsShadow )
565         m_xShadowControls.reset(new ShadowControlsWrapper(*m_xWndShadows, *m_xEdShadowSize, *m_xLbShadowColor));
566     else
567         HideShadowControls();
568 
569     if (mbUseMarginItem)
570         m_xMarginControls.reset(new MarginControlsWrapper(*m_xLeftMF, *m_xRightMF, *m_xTopMF, *m_xBottomMF));
571 
572     // checkbox "Merge with next paragraph" only visible for Writer dialog format.paragraph
573     m_xMergeWithNextCB->hide();
574     // checkbox "Merge adjacent line styles" only visible for Writer dialog format.table
575     m_xMergeAdjacentBordersCB->hide();
576 
577     if (SfxObjectShell* pDocSh = SfxObjectShell::Current())
578     {
579         Reference< XServiceInfo > xSI( pDocSh->GetModel(), UNO_QUERY );
580         if ( xSI.is() )
581             bIsCalcDoc = xSI->supportsService(u"com.sun.star.sheet.SpreadsheetDocument"_ustr);
582     }
583     if( bIsCalcDoc )
584     {
585         m_xRemoveAdjacentCellBordersCB->connect_toggled(LINK(this, SvxBorderTabPage, RemoveAdjacentCellBorderHdl_Impl));
586         m_xRemoveAdjacentCellBordersCB->show();
587         m_xRemoveAdjacentCellBordersCB->set_sensitive(false);
588     }
589     else
590     {
591         m_xRemoveAdjacentCellBordersCB->hide();
592         m_xRemoveAdjacentCellBordersFT->hide();
593     }
594 }
595 
~SvxBorderTabPage()596 SvxBorderTabPage::~SvxBorderTabPage()
597 {
598     m_xLbShadowColor.reset();
599     m_xLbLineColor.reset();
600     m_xLbLineStyle.reset();
601     m_xFrameSelWin.reset();
602 }
603 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rAttrSet)604 std::unique_ptr<SfxTabPage> SvxBorderTabPage::Create( weld::Container* pPage, weld::DialogController* pController,
605                                              const SfxItemSet* rAttrSet )
606 {
607     return std::make_unique<SvxBorderTabPage>(pPage, pController, *rAttrSet);
608 }
609 
ResetFrameLine_Impl(svx::FrameBorderType eBorder,const SvxBorderLine * pCoreLine,bool bValid)610 void SvxBorderTabPage::ResetFrameLine_Impl( svx::FrameBorderType eBorder, const SvxBorderLine* pCoreLine, bool bValid )
611 {
612     if( m_aFrameSel.IsBorderEnabled( eBorder ) )
613     {
614         if( bValid )
615             m_aFrameSel.ShowBorder( eBorder, pCoreLine );
616         else
617             m_aFrameSel.SetBorderDontCare( eBorder );
618     }
619 }
620 
IsBorderLineStyleAllowed(SvxBorderLineStyle nStyle) const621 bool SvxBorderTabPage::IsBorderLineStyleAllowed( SvxBorderLineStyle nStyle ) const
622 {
623     if (maUsedBorderStyles.empty())
624         // All border styles are allowed.
625         return true;
626 
627     return maUsedBorderStyles.count(nStyle) > 0;
628 }
629 
Reset(const SfxItemSet * rSet)630 void SvxBorderTabPage::Reset( const SfxItemSet* rSet )
631 {
632     SfxItemPool* pPool = rSet->GetPool();
633 
634     if (m_aFrameSel.IsBorderEnabled(svx::FrameBorderType::TLBR))
635     {
636         sal_uInt16 nBorderDiagId = pPool->GetWhichIDFromSlotID(SID_ATTR_BORDER_DIAG_TLBR);
637         if (const SvxLineItem* pLineItem = static_cast<const SvxLineItem*>(rSet->GetItem(nBorderDiagId)))
638             m_aFrameSel.ShowBorder(svx::FrameBorderType::TLBR, pLineItem->GetLine());
639         else
640             m_aFrameSel.SetBorderDontCare(svx::FrameBorderType::TLBR);
641     }
642 
643     if (m_aFrameSel.IsBorderEnabled(svx::FrameBorderType::BLTR))
644     {
645         sal_uInt16 nBorderDiagId = pPool->GetWhichIDFromSlotID(SID_ATTR_BORDER_DIAG_BLTR);
646         if (const SvxLineItem* pLineItem = static_cast<const SvxLineItem*>(rSet->GetItem(nBorderDiagId)))
647             m_aFrameSel.ShowBorder(svx::FrameBorderType::BLTR, pLineItem->GetLine());
648         else
649             m_aFrameSel.SetBorderDontCare(svx::FrameBorderType::BLTR);
650     }
651 
652     if (m_xShadowControls)
653     {
654         sal_uInt16 nShadowId = pPool->GetWhichIDFromSlotID(mnShadowSlot);
655         const SfxPoolItem* pItem = rSet->GetItem(nShadowId);
656         if (pItem)
657             m_xShadowControls->SetControlValue(*static_cast<const SvxShadowItem*>(pItem));
658         else
659             m_xShadowControls->SetControlDontKnow();
660     }
661 
662     if (m_xMarginControls)
663     {
664         sal_uInt16 nAlignMarginId = pPool->GetWhichIDFromSlotID(SID_ATTR_ALIGN_MARGIN);
665         const SfxPoolItem* pItem = rSet->GetItem(nAlignMarginId);
666         if (pItem)
667             m_xMarginControls->SetControlValue(*static_cast<const SvxMarginItem*>(pItem));
668         else
669             m_xMarginControls->SetControlDontKnow();
670     }
671 
672     sal_uInt16 nMergeAdjacentBordersId = pPool->GetWhichIDFromSlotID(SID_SW_COLLAPSING_BORDERS);
673     const SfxBoolItem *pMergeAdjacentBorders = static_cast<const SfxBoolItem*>(rSet->GetItem(nMergeAdjacentBordersId));
674     if (!pMergeAdjacentBorders)
675         m_xMergeAdjacentBordersCB->set_state(TRISTATE_INDET);
676     else
677         m_xMergeAdjacentBordersCB->set_active(pMergeAdjacentBorders->GetValue());
678     m_xMergeAdjacentBordersCB->save_state();
679 
680     sal_uInt16 nMergeWithNextId = pPool->GetWhichIDFromSlotID(SID_ATTR_BORDER_CONNECT);
681     const SfxBoolItem *pMergeWithNext = static_cast<const SfxBoolItem*>(rSet->GetItem(nMergeWithNextId));
682     if (!pMergeWithNext)
683         m_xMergeWithNextCB->set_state(TRISTATE_INDET);
684     else
685         m_xMergeWithNextCB->set_active(pMergeWithNext->GetValue());
686     m_xMergeWithNextCB->save_state();
687 
688     const SvxBoxItem*       pBoxItem;
689     const SvxBoxInfoItem*   pBoxInfoItem;
690     sal_uInt16              nWhichBox       = GetWhich(mnBoxSlot);
691     MapUnit                 eCoreUnit;
692 
693     pBoxItem  = static_cast<const SvxBoxItem*>(GetItem( *rSet, mnBoxSlot ));
694 
695     pBoxInfoItem = GetItem( *rSet, SID_ATTR_BORDER_INNER, false );
696 
697     eCoreUnit = pPool->GetMetric( nWhichBox );
698 
699     if ( pBoxItem && pBoxInfoItem ) // -> Don't Care
700     {
701         ResetFrameLine_Impl( svx::FrameBorderType::Left,   pBoxItem->GetLeft(),     pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::LEFT ) );
702         ResetFrameLine_Impl( svx::FrameBorderType::Right,  pBoxItem->GetRight(),    pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::RIGHT ) );
703         ResetFrameLine_Impl( svx::FrameBorderType::Top,    pBoxItem->GetTop(),      pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::TOP ) );
704         ResetFrameLine_Impl( svx::FrameBorderType::Bottom, pBoxItem->GetBottom(),   pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::BOTTOM ) );
705         ResetFrameLine_Impl( svx::FrameBorderType::Vertical,    pBoxInfoItem->GetVert(), pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::VERT ) );
706         ResetFrameLine_Impl( svx::FrameBorderType::Horizontal,    pBoxInfoItem->GetHori(), pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::HORI ) );
707 
708 
709         // distance inside
710 
711         if( !mbUseMarginItem )
712         {
713             if (m_xLeftMF->get_visible())
714             {
715                 SetMetricValue(*m_xLeftMF,    pBoxInfoItem->GetDefDist(), eCoreUnit);
716                 SetMetricValue(*m_xRightMF,   pBoxInfoItem->GetDefDist(), eCoreUnit);
717                 SetMetricValue(*m_xTopMF,     pBoxInfoItem->GetDefDist(), eCoreUnit);
718                 SetMetricValue(*m_xBottomMF,  pBoxInfoItem->GetDefDist(), eCoreUnit);
719 
720                 nMinValue = m_xLeftMF->get_value(FieldUnit::NONE);
721 
722                 if ( pBoxInfoItem->IsDist() )
723                 {
724                     if( rSet->GetItemState( nWhichBox ) >= SfxItemState::DEFAULT )
725                     {
726                         bool bIsAnyBorderVisible = m_aFrameSel.IsAnyBorderVisible();
727                         if( !bIsAnyBorderVisible || !pBoxInfoItem->IsMinDist() )
728                         {
729                             m_xLeftMF->set_min(0, FieldUnit::NONE);
730                             m_xRightMF->set_min(0, FieldUnit::NONE);
731                             m_xTopMF->set_min(0, FieldUnit::NONE);
732                             m_xBottomMF->set_min(0, FieldUnit::NONE);
733                         }
734                         tools::Long nLeftDist = pBoxItem->GetDistance( SvxBoxItemLine::LEFT);
735                         SetMetricValue(*m_xLeftMF, nLeftDist, eCoreUnit);
736                         tools::Long nRightDist = pBoxItem->GetDistance( SvxBoxItemLine::RIGHT);
737                         SetMetricValue(*m_xRightMF, nRightDist, eCoreUnit);
738                         tools::Long nTopDist = pBoxItem->GetDistance( SvxBoxItemLine::TOP);
739                         SetMetricValue( *m_xTopMF, nTopDist, eCoreUnit );
740                         tools::Long nBottomDist = pBoxItem->GetDistance( SvxBoxItemLine::BOTTOM);
741                         SetMetricValue( *m_xBottomMF, nBottomDist, eCoreUnit );
742 
743                         // if the distance is set with no active border line
744                         // or it is null with an active border line
745                         // no automatic changes should be made
746                         const tools::Long nDefDist = bIsAnyBorderVisible ? pBoxInfoItem->GetDefDist() : 0;
747                         bool bDiffDist = (nDefDist != nLeftDist ||
748                                     nDefDist != nRightDist ||
749                                     nDefDist != nTopDist   ||
750                                     nDefDist != nBottomDist);
751                         if ((pBoxItem->GetSmallestDistance() || bIsAnyBorderVisible) && bDiffDist )
752                         {
753                             mbLeftModified = true;
754                             mbRightModified = true;
755                             mbTopModified = true;
756                             mbBottomModified = true;
757                         }
758                     }
759                     else
760                     {
761                         // #106224# different margins -> do not fill the edits
762                         m_xLeftMF->set_text( OUString() );
763                         m_xRightMF->set_text( OUString() );
764                         m_xTopMF->set_text( OUString() );
765                         m_xBottomMF->set_text( OUString() );
766                     }
767                 }
768                 m_xLeftMF->save_value();
769                 m_xRightMF->save_value();
770                 m_xTopMF->save_value();
771                 m_xBottomMF->save_value();
772             }
773         }
774     }
775     else
776     {
777         // avoid ResetFrameLine-calls:
778         m_aFrameSel.HideAllBorders();
779     }
780 
781     if( !m_aFrameSel.IsAnyBorderVisible() )
782         m_aFrameSel.DeselectAllBorders();
783 
784     // depict line (color) in controllers if unambiguous:
785 
786     {
787         // Do all visible lines show the same line widths?
788         tools::Long nWidth;
789         SvxBorderLineStyle nStyle;
790         bool bWidthEq = m_aFrameSel.GetVisibleWidth( nWidth, nStyle );
791         if( bWidthEq )
792         {
793             // Determine the width first as some styles can be missing depending on it
794             sal_Int64 nWidthPt =  static_cast<sal_Int64>(vcl::ConvertDoubleValue(
795                         sal_Int64( nWidth ), m_xLineWidthMF->get_digits(),
796                         MapUnit::MapTwip, FieldUnit::POINT ));
797             SetLineWidth(nWidthPt);
798             m_xLbLineStyle->SetWidth(nWidth);
799 
800             // then set the style
801             m_xLbLineStyle->SelectEntry( nStyle );
802         }
803         else
804             m_xLbLineStyle->SelectEntry(SvxBorderLineStyle::SOLID);
805 
806         // Do all visible lines show the same line color?
807         Color aColor;
808         bool bColorEq = m_aFrameSel.GetVisibleColor( aColor );
809         if( !bColorEq )
810             aColor = COL_BLACK;
811 
812         m_xLbLineColor->SelectEntry(aColor);
813         auto nTextColor = Application::GetSettings().GetStyleSettings().GetWindowTextColor();
814         m_xLbLineStyle->SetColor(nTextColor);
815 
816         // Select all visible lines, if they are all equal.
817         if( bWidthEq && bColorEq )
818             m_aFrameSel.SelectAllVisibleBorders();
819 
820         // set the current style and color (caches style in control even if nothing is selected)
821         SelStyleHdl_Impl(*m_xLbLineStyle);
822         SelColHdl_Impl(*m_xLbLineColor);
823     }
824 
825     OUString sShadowSelectedId = m_xWndShadows->get_selected_id();
826     bool bEnable = !sShadowSelectedId.isEmpty() && sShadowSelectedId.toInt32() > 1 ;
827     m_xFtShadowSize->set_sensitive(bEnable);
828     m_xEdShadowSize->set_sensitive(bEnable);
829     m_xFtShadowColor->set_sensitive(bEnable);
830     m_xLbShadowColor->set_sensitive(bEnable);
831 
832     m_xWndPresets->unselect_all();
833 
834     // - no line - should not be selected
835 
836     if (m_xLbLineStyle->GetSelectEntryStyle() == SvxBorderLineStyle::NONE)
837     {
838         m_xLbLineStyle->SelectEntry(SvxBorderLineStyle::SOLID);
839         SelStyleHdl_Impl(*m_xLbLineStyle);
840     }
841 
842     const SfxUInt16Item* pHtmlModeItem = rSet->GetItemIfSet(SID_HTML_MODE, false);
843     if(!pHtmlModeItem)
844     {
845         if (SfxObjectShell* pShell = SfxObjectShell::Current())
846             pHtmlModeItem = pShell->GetItem(SID_HTML_MODE);
847     }
848     if(pHtmlModeItem)
849     {
850         sal_uInt16 nHtmlMode = pHtmlModeItem->GetValue();
851         if(nHtmlMode & HTMLMODE_ON)
852         {
853             // there are no shadows in Html-mode and only complete borders
854             m_xShadowFrame->set_sensitive(false);
855 
856             if( !(nSWMode & SwBorderModes::TABLE) )
857             {
858                 m_xUserDefFT->set_sensitive(false);
859                 m_xFrameSelWin->set_sensitive(false);
860 
861                 if( m_xWndPresets->n_children() > 4 )
862                 {
863                     m_xWndPresets->remove(4);
864                     m_xWndPresets->remove(3);
865                     m_xWndPresets->remove(2);
866                 }
867             }
868         }
869     }
870 
871     LinesChanged_Impl( nullptr );
872     if (m_xLeftMF->get_value(FieldUnit::NONE) == m_xRightMF->get_value(FieldUnit::NONE) &&
873         m_xTopMF->get_value(FieldUnit::NONE) == m_xBottomMF->get_value(FieldUnit::NONE) &&
874         m_xTopMF->get_value(FieldUnit::NONE) == m_xLeftMF->get_value(FieldUnit::NONE))
875     {
876         mbSync = true;
877     }
878     else
879         mbSync = false;
880     m_xSynchronizeCB->set_active(mbSync);
881 
882     mbRemoveAdjacentCellBorders = false;
883     m_xRemoveAdjacentCellBordersCB->set_active(false);
884     m_xRemoveAdjacentCellBordersCB->set_sensitive(false);
885 }
886 
ChangesApplied()887 void SvxBorderTabPage::ChangesApplied()
888 {
889     m_xLeftMF->save_value();
890     m_xRightMF->save_value();
891     m_xTopMF->save_value();
892     m_xBottomMF->save_value();
893     m_xMergeWithNextCB->save_state();
894     m_xMergeAdjacentBordersCB->save_state();
895 }
896 
DeactivatePage(SfxItemSet * _pSet)897 DeactivateRC SvxBorderTabPage::DeactivatePage( SfxItemSet* _pSet )
898 {
899     if ( _pSet )
900         FillItemSet( _pSet );
901 
902     return DeactivateRC::LeavePage;
903 }
904 
FillItemSet(SfxItemSet * rCoreAttrs)905 bool SvxBorderTabPage::FillItemSet( SfxItemSet* rCoreAttrs )
906 {
907     bool bAttrsChanged = false;
908 
909     SfxItemPool* pPool = rCoreAttrs->GetPool();
910 
911     if (m_aFrameSel.IsBorderEnabled(svx::FrameBorderType::TLBR) &&
912         m_aFrameSel.GetFrameBorderState(svx::FrameBorderType::TLBR) != svx::FrameBorderState::DontCare)
913     {
914         if (const SfxPoolItem* pOldItem = GetOldItem(*rCoreAttrs, SID_ATTR_BORDER_DIAG_TLBR))
915         {
916             SvxLineItem aLineItem(*static_cast<const SvxLineItem*>(pOldItem));
917             aLineItem.SetLine(m_aFrameSel.GetFrameBorderStyle(svx::FrameBorderType::TLBR));
918             rCoreAttrs->Put(aLineItem);
919             bAttrsChanged = true;
920         }
921     }
922 
923     if (m_aFrameSel.IsBorderEnabled(svx::FrameBorderType::BLTR) &&
924         m_aFrameSel.GetFrameBorderState(svx::FrameBorderType::BLTR) != svx::FrameBorderState::DontCare)
925     {
926         if (const SfxPoolItem* pOldItem = GetOldItem(*rCoreAttrs, SID_ATTR_BORDER_DIAG_BLTR))
927         {
928             SvxLineItem aLineItem(*static_cast<const SvxLineItem*>(pOldItem));
929             aLineItem.SetLine(m_aFrameSel.GetFrameBorderStyle(svx::FrameBorderType::BLTR));
930             rCoreAttrs->Put(aLineItem);
931             bAttrsChanged = true;
932         }
933     }
934 
935     if (m_xShadowControls && m_xShadowControls->get_value_changed_from_saved())
936     {
937         if (const SfxPoolItem* pOldItem = GetOldItem(*rCoreAttrs, mnShadowSlot))
938         {
939             const SvxShadowItem& rOldShadowItem = *static_cast<const SvxShadowItem*>(pOldItem);
940             rCoreAttrs->Put(m_xShadowControls->GetControlValue(rOldShadowItem));
941             bAttrsChanged = true;
942         }
943     }
944 
945     if (m_xMarginControls && m_xMarginControls->get_value_changed_from_saved())
946     {
947         if (const SfxPoolItem* pOldItem = GetOldItem(*rCoreAttrs, SID_ATTR_ALIGN_MARGIN))
948         {
949             const SvxMarginItem& rOldMarginItem = *static_cast<const SvxMarginItem*>(pOldItem);
950             rCoreAttrs->Put(m_xMarginControls->GetControlValue(rOldMarginItem));
951             bAttrsChanged = true;
952         }
953     }
954 
955     if (m_xMergeAdjacentBordersCB->get_state_changed_from_saved())
956     {
957         auto nState = m_xMergeAdjacentBordersCB->get_state();
958         if (nState == TRISTATE_INDET)
959         {
960             sal_uInt16 nMergeAdjacentBordersId = pPool->GetWhichIDFromSlotID(SID_SW_COLLAPSING_BORDERS);
961             rCoreAttrs->ClearItem(nMergeAdjacentBordersId);
962         }
963         else
964         {
965             if (const SfxPoolItem* pOldItem = GetOldItem(*rCoreAttrs, SID_SW_COLLAPSING_BORDERS))
966             {
967                 std::unique_ptr<SfxBoolItem> xNewItem(static_cast<SfxBoolItem*>(pOldItem->Clone()));
968                 xNewItem->SetValue(static_cast<bool>(nState));
969                 rCoreAttrs->Put(std::move(xNewItem));
970             }
971         }
972         bAttrsChanged = true;
973     }
974 
975     if (m_xMergeWithNextCB->get_state_changed_from_saved())
976     {
977         auto nState = m_xMergeWithNextCB->get_state();
978         if (nState == TRISTATE_INDET)
979         {
980             sal_uInt16 nMergeWithNextId = pPool->GetWhichIDFromSlotID(SID_ATTR_BORDER_CONNECT);
981             rCoreAttrs->ClearItem(nMergeWithNextId);
982         }
983         else
984         {
985             if (const SfxPoolItem* pOldItem = GetOldItem(*rCoreAttrs, SID_ATTR_BORDER_CONNECT))
986             {
987                 std::unique_ptr<SfxBoolItem> xNewItem(static_cast<SfxBoolItem*>(pOldItem->Clone()));
988                 xNewItem->SetValue(static_cast<bool>(nState));
989                 rCoreAttrs->Put(std::move(xNewItem));
990             }
991         }
992         bAttrsChanged = true;
993     }
994 
995     bool                  bPut          = true;
996     sal_uInt16            nBoxWhich     = GetWhich( mnBoxSlot );
997     sal_uInt16            nBoxInfoWhich = pPool->GetWhichIDFromSlotID( SID_ATTR_BORDER_INNER, false );
998     const SfxItemSet&     rOldSet       = GetItemSet();
999     SvxBoxItem            aBoxItem      ( nBoxWhich );
1000     SvxBoxInfoItem        aBoxInfoItem  ( nBoxInfoWhich );
1001     const SvxBoxItem*     pOldBoxItem = static_cast<const SvxBoxItem*>(GetOldItem( *rCoreAttrs, mnBoxSlot ));
1002 
1003     MapUnit eCoreUnit = rOldSet.GetPool()->GetMetric( nBoxWhich );
1004 
1005 
1006     // outer border:
1007 
1008     std::pair<svx::FrameBorderType,SvxBoxItemLine> eTypes1[] = {
1009                                 { svx::FrameBorderType::Top,SvxBoxItemLine::TOP },
1010                                 { svx::FrameBorderType::Bottom,SvxBoxItemLine::BOTTOM },
1011                                 { svx::FrameBorderType::Left,SvxBoxItemLine::LEFT },
1012                                 { svx::FrameBorderType::Right,SvxBoxItemLine::RIGHT },
1013                             };
1014 
1015     for (std::pair<svx::FrameBorderType,SvxBoxItemLine> const & i : eTypes1)
1016         aBoxItem.SetLine( m_aFrameSel.GetFrameBorderStyle( i.first ), i.second );
1017 
1018 
1019     aBoxItem.SetRemoveAdjacentCellBorder( mbRemoveAdjacentCellBorders );
1020     // border hor/ver and TableFlag
1021 
1022     std::pair<svx::FrameBorderType,SvxBoxInfoItemLine> eTypes2[] = {
1023                                 { svx::FrameBorderType::Horizontal,SvxBoxInfoItemLine::HORI },
1024                                 { svx::FrameBorderType::Vertical,SvxBoxInfoItemLine::VERT }
1025                             };
1026     for (std::pair<svx::FrameBorderType,SvxBoxInfoItemLine> const & j : eTypes2)
1027         aBoxInfoItem.SetLine( m_aFrameSel.GetFrameBorderStyle( j.first ), j.second );
1028 
1029     aBoxInfoItem.EnableHor( mbHorEnabled );
1030     aBoxInfoItem.EnableVer( mbVerEnabled );
1031 
1032 
1033     // inner distance
1034 
1035     if (m_xLeftMF->get_visible())
1036     {
1037         // #i40405# enable distance controls for next dialog call
1038         aBoxInfoItem.SetDist( true );
1039 
1040         if( !mbUseMarginItem )
1041         {
1042             // #106224# all edits empty: do nothing
1043             if( !m_xLeftMF->get_text().isEmpty() || !m_xRightMF->get_text().isEmpty() ||
1044                 !m_xTopMF->get_text().isEmpty() || !m_xBottomMF->get_text().isEmpty() )
1045             {
1046                 const SvxBoxInfoItem* pOldBoxInfoItem = GetOldItem( *rCoreAttrs, SID_ATTR_BORDER_INNER );
1047                 if (
1048                     !pOldBoxItem ||
1049                     m_xLeftMF->get_value_changed_from_saved() ||
1050                     m_xRightMF->get_value_changed_from_saved() ||
1051                     m_xTopMF->get_value_changed_from_saved() ||
1052                     m_xBottomMF->get_value_changed_from_saved() ||
1053                     nMinValue == m_xLeftMF->get_value(FieldUnit::NONE) ||
1054                     nMinValue == m_xRightMF->get_value(FieldUnit::NONE) ||
1055                     nMinValue == m_xTopMF->get_value(FieldUnit::NONE) ||
1056                     nMinValue == m_xBottomMF->get_value(FieldUnit::NONE) ||
1057                     (pOldBoxInfoItem && !pOldBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::DISTANCE))
1058                    )
1059                 {
1060                     aBoxItem.SetDistance( static_cast<sal_uInt16>(GetCoreValue(*m_xLeftMF, eCoreUnit )), SvxBoxItemLine::LEFT  );
1061                     aBoxItem.SetDistance( static_cast<sal_uInt16>(GetCoreValue(*m_xRightMF, eCoreUnit )), SvxBoxItemLine::RIGHT );
1062                     aBoxItem.SetDistance( static_cast<sal_uInt16>(GetCoreValue(*m_xTopMF, eCoreUnit )), SvxBoxItemLine::TOP   );
1063                     aBoxItem.SetDistance( static_cast<sal_uInt16>(GetCoreValue(*m_xBottomMF, eCoreUnit )), SvxBoxItemLine::BOTTOM);
1064                 }
1065                 else
1066                 {
1067                     aBoxItem.SetDistance(pOldBoxItem->GetDistance(SvxBoxItemLine::LEFT ), SvxBoxItemLine::LEFT);
1068                     aBoxItem.SetDistance(pOldBoxItem->GetDistance(SvxBoxItemLine::RIGHT),  SvxBoxItemLine::RIGHT);
1069                     aBoxItem.SetDistance(pOldBoxItem->GetDistance(SvxBoxItemLine::TOP  ), SvxBoxItemLine::TOP);
1070                     aBoxItem.SetDistance(pOldBoxItem->GetDistance(SvxBoxItemLine::BOTTOM), SvxBoxItemLine::BOTTOM);
1071                 }
1072                 aBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
1073             }
1074         }
1075     }
1076 
1077 
1078     // note Don't Care Status in the Info-Item:
1079 
1080     aBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::TOP,    m_aFrameSel.GetFrameBorderState( svx::FrameBorderType::Top )    != svx::FrameBorderState::DontCare );
1081     aBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, m_aFrameSel.GetFrameBorderState( svx::FrameBorderType::Bottom ) != svx::FrameBorderState::DontCare );
1082     aBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::LEFT,   m_aFrameSel.GetFrameBorderState( svx::FrameBorderType::Left )   != svx::FrameBorderState::DontCare );
1083     aBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::RIGHT,  m_aFrameSel.GetFrameBorderState( svx::FrameBorderType::Right )  != svx::FrameBorderState::DontCare );
1084     aBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::HORI,   m_aFrameSel.GetFrameBorderState( svx::FrameBorderType::Horizontal )    != svx::FrameBorderState::DontCare );
1085     aBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::VERT,   m_aFrameSel.GetFrameBorderState( svx::FrameBorderType::Vertical )    != svx::FrameBorderState::DontCare );
1086 
1087 
1088     // Put or Clear of the border?
1089 
1090     bPut = true;
1091 
1092     if (   SfxItemState::DEFAULT == rOldSet.GetItemState( nBoxWhich,     false ))
1093     {
1094         bPut = aBoxItem != static_cast<const SvxBoxItem&>(rOldSet.Get(nBoxWhich));
1095     }
1096     if(  SfxItemState::DEFAULT == rOldSet.GetItemState( nBoxInfoWhich, false ) )
1097     {
1098         const SvxBoxInfoItem& rOldBoxInfo = static_cast<const SvxBoxInfoItem&>(
1099                                 rOldSet.Get(nBoxInfoWhich));
1100 
1101         aBoxInfoItem.SetMinDist( rOldBoxInfo.IsMinDist() );
1102         aBoxInfoItem.SetDefDist( rOldBoxInfo.GetDefDist() );
1103         bPut |= (aBoxInfoItem != rOldBoxInfo );
1104     }
1105 
1106     if ( bPut )
1107     {
1108         if ( !pOldBoxItem || *pOldBoxItem != aBoxItem )
1109         {
1110             rCoreAttrs->Put( aBoxItem );
1111             bAttrsChanged = true;
1112         }
1113         const SfxPoolItem* pOld = GetOldItem( *rCoreAttrs, SID_ATTR_BORDER_INNER, false );
1114 
1115         if ( !pOld || *static_cast<const SvxBoxInfoItem*>(pOld) != aBoxInfoItem )
1116         {
1117             rCoreAttrs->Put( aBoxInfoItem );
1118             bAttrsChanged = true;
1119         }
1120     }
1121     else
1122     {
1123         rCoreAttrs->ClearItem( nBoxWhich );
1124         rCoreAttrs->ClearItem( nBoxInfoWhich );
1125     }
1126 
1127     return bAttrsChanged;
1128 }
1129 
HideShadowControls()1130 void SvxBorderTabPage::HideShadowControls()
1131 {
1132     m_xShadowFrame->hide();
1133 }
1134 
1135 #define IID_PRE_CELL_NONE       1
1136 #define IID_PRE_CELL_ALL        2
1137 #define IID_PRE_CELL_LR         3
1138 #define IID_PRE_CELL_TB         4
1139 #define IID_PRE_CELL_L          5
1140 #define IID_PRE_CELL_DIAG       6
1141 #define IID_PRE_HOR_NONE        7
1142 #define IID_PRE_HOR_OUTER       8
1143 #define IID_PRE_HOR_HOR         9
1144 #define IID_PRE_HOR_ALL         10
1145 #define IID_PRE_HOR_OUTER2      11
1146 #define IID_PRE_VER_NONE        12
1147 #define IID_PRE_VER_OUTER       13
1148 #define IID_PRE_VER_VER         14
1149 #define IID_PRE_VER_ALL         15
1150 #define IID_PRE_VER_OUTER2      16
1151 #define IID_PRE_TABLE_NONE      17
1152 #define IID_PRE_TABLE_OUTER     18
1153 #define IID_PRE_TABLE_OUTERH    19
1154 #define IID_PRE_TABLE_ALL       20
1155 #define IID_PRE_TABLE_OUTER2    21
1156 
IMPL_LINK_NOARG(SvxBorderTabPage,SelPreHdl_Impl,weld::IconView &,void)1157 IMPL_LINK_NOARG(SvxBorderTabPage, SelPreHdl_Impl, weld::IconView&, void)
1158 {
1159     const svx::FrameBorderState SHOW = svx::FrameBorderState::Show;
1160     const svx::FrameBorderState HIDE = svx::FrameBorderState::Hide;
1161     const svx::FrameBorderState DONT = svx::FrameBorderState::DontCare;
1162 
1163     static const svx::FrameBorderState ppeStates[][ svx::FRAMEBORDERTYPE_COUNT ] =
1164     {                   /*    Left  Right Top   Bot   Hor   Ver   TLBR  BLTR */
1165 /* ---------------------+--------------------------------------------------- */
1166 /* IID_PRE_CELL_NONE    */  { HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE },
1167 /* IID_PRE_CELL_ALL     */  { SHOW, SHOW, SHOW, SHOW, HIDE, HIDE, HIDE, HIDE },
1168 /* IID_PRE_CELL_LR      */  { SHOW, SHOW, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE },
1169 /* IID_PRE_CELL_TB      */  { HIDE, HIDE, SHOW, SHOW, HIDE, HIDE, HIDE, HIDE },
1170 /* IID_PRE_CELL_L       */  { SHOW, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE },
1171 /* IID_PRE_CELL_DIAG    */  { HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, SHOW, SHOW },
1172 /* IID_PRE_HOR_NONE     */  { HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE },
1173 /* IID_PRE_HOR_OUTER    */  { SHOW, SHOW, SHOW, SHOW, HIDE, HIDE, HIDE, HIDE },
1174 /* IID_PRE_HOR_HOR      */  { HIDE, HIDE, SHOW, SHOW, SHOW, HIDE, HIDE, HIDE },
1175 /* IID_PRE_HOR_ALL      */  { SHOW, SHOW, SHOW, SHOW, SHOW, HIDE, HIDE, HIDE },
1176 /* IID_PRE_HOR_OUTER2   */  { SHOW, SHOW, SHOW, SHOW, DONT, HIDE, HIDE, HIDE },
1177 /* IID_PRE_VER_NONE     */  { HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE },
1178 /* IID_PRE_VER_OUTER    */  { SHOW, SHOW, SHOW, SHOW, HIDE, HIDE, HIDE, HIDE },
1179 /* IID_PRE_VER_VER      */  { SHOW, SHOW, HIDE, HIDE, HIDE, SHOW, HIDE, HIDE },
1180 /* IID_PRE_VER_ALL      */  { SHOW, SHOW, SHOW, SHOW, HIDE, SHOW, HIDE, HIDE },
1181 /* IID_PRE_VER_OUTER2   */  { SHOW, SHOW, SHOW, SHOW, HIDE, DONT, HIDE, HIDE },
1182 /* IID_PRE_TABLE_NONE   */  { HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE, HIDE },
1183 /* IID_PRE_TABLE_OUTER  */  { SHOW, SHOW, SHOW, SHOW, HIDE, HIDE, HIDE, HIDE },
1184 /* IID_PRE_TABLE_OUTERH */  { SHOW, SHOW, SHOW, SHOW, SHOW, HIDE, HIDE, HIDE },
1185 /* IID_PRE_TABLE_ALL    */  { SHOW, SHOW, SHOW, SHOW, SHOW, SHOW, HIDE, HIDE },
1186 /* IID_PRE_TABLE_OUTER2 */  { SHOW, SHOW, SHOW, SHOW, DONT, DONT, HIDE, HIDE }
1187     };
1188 
1189     // first hide and deselect all frame borders
1190     m_aFrameSel.HideAllBorders();
1191     m_aFrameSel.DeselectAllBorders();
1192 
1193     // Using image ID to find correct line in table above.
1194     sal_uInt16 nSelectedId = m_xWndPresets->get_selected_id().toUInt32();
1195     sal_uInt16 nLine = GetPresetImageId(nSelectedId) - 1;
1196 
1197     // Apply all styles from the table
1198     for( int nBorder = 0; nBorder < svx::FRAMEBORDERTYPE_COUNT; ++nBorder )
1199     {
1200         svx::FrameBorderType eBorder = svx::GetFrameBorderTypeFromIndex( nBorder );
1201         switch( ppeStates[ nLine ][ nBorder ] )
1202         {
1203             case SHOW:  m_aFrameSel.SelectBorder(eBorder, false); break;
1204             case HIDE:  /* nothing to do */                     break;
1205             case DONT:  m_aFrameSel.SetBorderDontCare( eBorder ); break;
1206         }
1207     }
1208 
1209     // Show all lines that have been selected above
1210     if( m_aFrameSel.IsAnyBorderSelected() )
1211     {
1212         // any visible style, but "no-line" in line list box? -> use hair-line
1213         if (m_xLbLineStyle->GetSelectEntryStyle() == SvxBorderLineStyle::NONE)
1214             m_xLbLineStyle->SelectEntry(SvxBorderLineStyle::SOLID);
1215 
1216         // set current style to all previously selected lines
1217         SelStyleHdl_Impl(*m_xLbLineStyle);
1218         SelColHdl_Impl(*m_xLbLineColor);
1219     }
1220 
1221     LinesChanged_Impl( nullptr );
1222     UpdateRemoveAdjCellBorderCB( nLine + 1 );
1223 }
1224 
IMPL_LINK_NOARG(SvxBorderTabPage,FocusOutPresets_Impl,weld::Widget &,void)1225 IMPL_LINK_NOARG(SvxBorderTabPage, FocusOutPresets_Impl, weld::Widget&, void)
1226 {
1227     // no longer show preset as selected, as it would become out of sync
1228     // if borders are changed manually
1229     m_xWndPresets->unselect_all();
1230 }
1231 
IMPL_LINK_NOARG(SvxBorderTabPage,SelSdwHdl_Impl,weld::IconView &,void)1232 IMPL_LINK_NOARG(SvxBorderTabPage, SelSdwHdl_Impl, weld::IconView&, void)
1233 {
1234     OUString sSelectedId = m_xWndShadows->get_selected_id();
1235     bool bEnable = !sSelectedId.isEmpty() && sSelectedId.toInt32() > 1;
1236     m_xFtShadowSize->set_sensitive(bEnable);
1237     m_xEdShadowSize->set_sensitive(bEnable);
1238     m_xFtShadowColor->set_sensitive(bEnable);
1239     m_xLbShadowColor->set_sensitive(bEnable);
1240 }
1241 
IMPL_LINK(SvxBorderTabPage,QueryTooltipPreHdl,const weld::TreeIter &,iter,OUString)1242 IMPL_LINK(SvxBorderTabPage, QueryTooltipPreHdl, const weld::TreeIter&, iter, OUString)
1243 {
1244     const OUString sId = m_xWndPresets->get_id(iter);
1245     if (!sId.isEmpty())
1246         return GetPresetName(sId.toInt32());
1247 
1248     return OUString();
1249 }
1250 
IMPL_LINK(SvxBorderTabPage,QueryTooltipSdwHdl,const weld::TreeIter &,iter,OUString)1251 IMPL_LINK(SvxBorderTabPage, QueryTooltipSdwHdl, const weld::TreeIter&, iter, OUString)
1252 {
1253     const OUString sId = m_xWndShadows->get_id(iter);
1254     if (!sId.isEmpty())
1255         return GetShadowTypeName(sId.toInt32());
1256 
1257     return OUString();
1258 }
1259 
IMPL_LINK(SvxBorderTabPage,SelColHdl_Impl,ColorListBox &,rColorBox,void)1260 IMPL_LINK(SvxBorderTabPage, SelColHdl_Impl, ColorListBox&, rColorBox, void)
1261 {
1262     const NamedColor& aNamedColor = rColorBox.GetSelectedEntry();
1263     m_aFrameSel.SetColorToSelection(aNamedColor.m_aColor, aNamedColor.getComplexColor());
1264 }
1265 
IMPL_LINK_NOARG(SvxBorderTabPage,ModifyWidthLBHdl_Impl,weld::ComboBox &,void)1266 IMPL_LINK_NOARG(SvxBorderTabPage, ModifyWidthLBHdl_Impl, weld::ComboBox&, void)
1267 {
1268     sal_Int32 nPos = m_xLineWidthLB->get_active();
1269     sal_Int32 nRemovedType = 0;
1270     if (m_xLineWidthLB->get_values_changed_from_saved()) {
1271         nRemovedType = std::size(s_LineWidths) - m_xLineWidthLB->get_count();
1272     }
1273 
1274     SetLineWidth(s_LineWidths[nPos + nRemovedType], nRemovedType);
1275 
1276     // Call the spinner handler to trigger all related modifications
1277     ModifyWidthMFHdl_Impl(*m_xLineWidthMF);
1278 }
1279 
IMPL_LINK_NOARG(SvxBorderTabPage,ModifyWidthMFHdl_Impl,weld::MetricSpinButton &,void)1280 IMPL_LINK_NOARG(SvxBorderTabPage, ModifyWidthMFHdl_Impl, weld::MetricSpinButton&, void)
1281 {
1282     sal_Int64 nVal = m_xLineWidthMF->get_value(FieldUnit::NONE);
1283 
1284     // for DOUBLE_THIN line style we cannot allow thinner line width then 1.10pt
1285     if (m_xLbLineStyle->GetSelectEntryStyle() == SvxBorderLineStyle::DOUBLE_THIN)
1286         m_xLineWidthMF->set_min(110, FieldUnit::NONE);
1287     else
1288         m_xLineWidthMF->set_min(5, FieldUnit::NONE);
1289 
1290     nVal = static_cast<sal_Int64>(vcl::ConvertDoubleValue(
1291                 nVal,
1292                 m_xLineWidthMF->get_digits(),
1293                 FieldUnit::POINT, MapUnit::MapTwip ));
1294     m_xLbLineStyle->SetWidth( nVal );
1295 
1296     m_aFrameSel.SetStyleToSelection( nVal,
1297         m_xLbLineStyle->GetSelectEntryStyle() );
1298 }
1299 
IMPL_LINK_NOARG(SvxBorderTabPage,SelStyleHdl_Impl,SvtLineListBox &,void)1300 IMPL_LINK_NOARG(SvxBorderTabPage, SelStyleHdl_Impl, SvtLineListBox&, void)
1301 {
1302     sal_Int64 nOldWidth = m_xLineWidthMF->get_value(FieldUnit::NONE);
1303 
1304     // for DOUBLE_THIN line style we cannot allow thinner line width then 1.10pt
1305     if (m_xLbLineStyle->GetSelectEntryStyle() == SvxBorderLineStyle::DOUBLE_THIN)
1306         m_xLineWidthMF->set_min(110, FieldUnit::NONE);
1307     else
1308         m_xLineWidthMF->set_min(5, FieldUnit::NONE);
1309 
1310     nOldWidth = static_cast<sal_Int64>(vcl::ConvertDoubleValue(
1311         nOldWidth,
1312         m_xLineWidthMF->get_digits(),
1313         FieldUnit::POINT,
1314         MapUnit::MapTwip));
1315 
1316     const sal_Int64 nOldMinWidth = lcl_GetMinLineWidth(m_aFrameSel.getCurrentStyleLineStyle());
1317     const sal_Int64 nNewMinWidth = lcl_GetMinLineWidth(m_xLbLineStyle->GetSelectEntryStyle());
1318 
1319     // auto change line-width if it doesn't correspond to minimal value
1320     // let's change only in case when user has not changed the line-width into some custom value
1321     sal_Int64 nNewWidth = (nOldMinWidth == nOldWidth) ? nNewMinWidth : nOldWidth;
1322 
1323     // if we had selected a predefined border width under SvxBorderLineWidth::Medium set the Medium as default
1324     // otherwise if we had a custom border width under 1.10pt then set the spinner to the maximum allowed value for double border styles
1325     bool bNewDoubleHairline = m_xLbLineStyle->GetSelectEntryStyle() == SvxBorderLineStyle::DOUBLE_THIN && !m_xLineWidthMF->get_visible() &&
1326         (nOldWidth == SvxBorderLineWidth::Hairline || nOldWidth == SvxBorderLineWidth::VeryThin || nOldWidth == SvxBorderLineWidth::Thin);
1327     if (bNewDoubleHairline && nNewWidth < SvxBorderLineWidth::Medium)
1328         nNewWidth = SvxBorderLineWidth::Medium;
1329 
1330     // set value inside edit box
1331     if (nOldWidth != nNewWidth)
1332     {
1333         const sal_Int64 nNewWidthPt = static_cast<sal_Int64>(vcl::ConvertDoubleValue(
1334             nNewWidth,
1335             m_xLineWidthMF->get_digits(),
1336             MapUnit::MapTwip,
1337             FieldUnit::POINT));
1338         SetLineWidth(nNewWidthPt);
1339     }
1340 
1341     if (m_xLbLineStyle->GetSelectEntryStyle() == SvxBorderLineStyle::DOUBLE_THIN)
1342     {
1343         for (size_t i = 0; i < 3; i++)
1344         {
1345             m_xLineWidthLB->save_values_by_id(OUString::number(i));
1346             m_xLineWidthLB->remove_id(OUString::number(i));
1347         }
1348         if (m_xLineWidthLB->get_active_id().isEmpty())
1349             m_xLineWidthLB->set_active_id(u"3"_ustr);
1350     }
1351     else
1352     {
1353         if (m_xLineWidthLB->get_values_changed_from_saved())
1354         {
1355             for (size_t i = 0; i < 3; i++)
1356                 m_xLineWidthLB->append(i, OUString::number(i), m_xLineWidthLB->get_saved_values(i));
1357             m_xLineWidthLB->removeSavedValues();
1358         }
1359     }
1360 
1361     // set value inside style box
1362     m_aFrameSel.SetStyleToSelection( nNewWidth,
1363         m_xLbLineStyle->GetSelectEntryStyle() );
1364 }
1365 
1366 
1367 // IconView handling
GetPresetImageId(sal_uInt16 nIconViewIdx) const1368 sal_uInt16 SvxBorderTabPage::GetPresetImageId( sal_uInt16 nIconViewIdx ) const
1369 {
1370     // table with all sets of predefined border styles
1371     static const sal_uInt16 ppnImgIds[][ BORDER_PRESET_COUNT ] =
1372     {
1373         // simple cell without diagonal frame borders
1374         {   IID_PRE_CELL_NONE,  IID_PRE_CELL_ALL,       IID_PRE_CELL_LR,        IID_PRE_CELL_TB,    IID_PRE_CELL_L          },
1375         // simple cell with diagonal frame borders
1376         {   IID_PRE_CELL_NONE,  IID_PRE_CELL_ALL,       IID_PRE_CELL_LR,        IID_PRE_CELL_TB,    IID_PRE_CELL_DIAG       },
1377         // with horizontal inner frame border
1378         {   IID_PRE_HOR_NONE,   IID_PRE_HOR_OUTER,      IID_PRE_HOR_HOR,        IID_PRE_HOR_ALL,    IID_PRE_HOR_OUTER2      },
1379         // with vertical inner frame border
1380         {   IID_PRE_VER_NONE,   IID_PRE_VER_OUTER,      IID_PRE_VER_VER,        IID_PRE_VER_ALL,    IID_PRE_VER_OUTER2      },
1381         // with horizontal and vertical inner frame borders
1382         {   IID_PRE_TABLE_NONE, IID_PRE_TABLE_OUTER,    IID_PRE_TABLE_OUTERH,   IID_PRE_TABLE_ALL,  IID_PRE_TABLE_OUTER2    }
1383     };
1384 
1385     // find correct set of presets
1386     int nLine = 0;
1387     if( !mbHorEnabled && !mbVerEnabled )
1388         nLine = (mbTLBREnabled || mbBLTREnabled) ? 1 : 0;
1389     else if( mbHorEnabled && !mbVerEnabled )
1390         nLine = 2;
1391     else if( !mbHorEnabled && mbVerEnabled )
1392         nLine = 3;
1393     else
1394         nLine = 4;
1395 
1396     DBG_ASSERT( (1 <= nIconViewIdx) && (nIconViewIdx <= BORDER_PRESET_COUNT),
1397         "SvxBorderTabPage::GetPresetImageId - wrong index" );
1398     return ppnImgIds[ nLine ][ nIconViewIdx - 1 ];
1399 }
1400 
GetShadowTypeName(sal_uInt16 nIconViewIdx)1401 OUString SvxBorderTabPage::GetShadowTypeName(sal_uInt16 nIconViewIdx)
1402 {
1403     static const TranslateId pnStrIds[ BORDER_SHADOW_COUNT ] =
1404     {
1405         RID_CUISTR_SHADOW_STYLE_NONE,
1406         RID_CUISTR_SHADOW_STYLE_BOTTOMRIGHT,
1407         RID_CUISTR_SHADOW_STYLE_TOPRIGHT,
1408         RID_CUISTR_SHADOW_STYLE_BOTTOMLEFT,
1409         RID_CUISTR_SHADOW_STYLE_TOPLEFT
1410     };
1411 
1412     return CuiResId(pnStrIds[nIconViewIdx - 1]);
1413 }
1414 
GetPresetName(sal_uInt16 nIconViewIdx) const1415 OUString SvxBorderTabPage::GetPresetName(sal_uInt16 nIconViewIdx) const
1416 {
1417     // string resource IDs for each image (in order of the IID_PRE_* image IDs)
1418     static const TranslateId pnStrIds[] =
1419     {
1420         RID_SVXSTR_TABLE_PRESET_NONE,
1421         RID_SVXSTR_PARA_PRESET_ALL,
1422         RID_SVXSTR_PARA_PRESET_ONLYLEFTRIGHT,
1423         RID_SVXSTR_PARA_PRESET_ONLYTOPBOTTOM,
1424         RID_SVXSTR_PARA_PRESET_ONLYLEFT,
1425         RID_SVXSTR_PARA_PRESET_DIAGONAL,
1426 
1427         RID_SVXSTR_TABLE_PRESET_NONE,
1428         RID_SVXSTR_TABLE_PRESET_ONLYOUTER,
1429         RID_SVXSTR_HOR_PRESET_ONLYHOR,
1430         RID_SVXSTR_TABLE_PRESET_OUTERALL,
1431         RID_SVXSTR_TABLE_PRESET_OUTERINNER,
1432 
1433         RID_SVXSTR_TABLE_PRESET_NONE,
1434         RID_SVXSTR_TABLE_PRESET_ONLYOUTER,
1435         RID_SVXSTR_VER_PRESET_ONLYVER,
1436         RID_SVXSTR_TABLE_PRESET_OUTERALL,
1437         RID_SVXSTR_TABLE_PRESET_OUTERINNER,
1438 
1439         RID_SVXSTR_TABLE_PRESET_NONE,
1440         RID_SVXSTR_TABLE_PRESET_ONLYOUTER,
1441         RID_SVXSTR_TABLE_PRESET_OUTERHORI,
1442         RID_SVXSTR_TABLE_PRESET_OUTERALL,
1443         RID_SVXSTR_TABLE_PRESET_OUTERINNER
1444     };
1445     return SvxResId(pnStrIds[GetPresetImageId(nIconViewIdx) - 1]);
1446 }
1447 
FillPresetIV()1448 void SvxBorderTabPage::FillPresetIV()
1449 {
1450     m_xWndPresets->clear();
1451 
1452     for( sal_uInt16 nIdx = 1; nIdx <= BORDER_PRESET_COUNT; ++nIdx )
1453     {
1454         OUString sId = OUString::number(nIdx);
1455         Bitmap aPreviewBitmap = GetPreviewAsBitmap(m_aBorderImgVec[GetPresetImageId(nIdx) - 1]);
1456         m_xWndPresets->insert(-1, nullptr, &sId, &aPreviewBitmap, nullptr);
1457         m_xWndPresets->set_item_accessible_name(m_xWndPresets->n_children() - 1,
1458                                                 GetPresetName(nIdx));
1459     }
1460 
1461     // show the control
1462     m_xWndPresets->unselect_all();
1463 }
1464 
FillShadowIV()1465 void SvxBorderTabPage::FillShadowIV()
1466 {
1467     // Clear any existing items
1468     m_xWndShadows->clear();
1469 
1470     // insert images and help texts
1471     for( sal_uInt16 nIdx = 1; nIdx <= BORDER_SHADOW_COUNT; ++nIdx )
1472     {
1473         OUString sId = OUString::number(nIdx);
1474         Bitmap aPreviewBitmap = GetPreviewAsBitmap(m_aShadowImgVec[nIdx-1]);
1475         m_xWndShadows->insert(-1, nullptr, &sId, &aPreviewBitmap, nullptr);
1476         m_xWndShadows->set_item_accessible_name(m_xWndShadows->n_children() - 1,
1477                                                 GetShadowTypeName(nIdx));
1478     }
1479 
1480     // show the control
1481     m_xWndShadows->select(0);
1482 }
1483 
GetPreviewAsBitmap(const Image & rImage)1484 Bitmap SvxBorderTabPage::GetPreviewAsBitmap(const Image& rImage)
1485 {
1486     Bitmap aPreviewBitmap(rImage.GetBitmap());
1487     ScopedVclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create();
1488     if (pVDev->GetDPIScaleFactor() > 1)
1489         aPreviewBitmap.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor());
1490 
1491     return aPreviewBitmap;
1492 }
1493 
FillIconViews()1494 void SvxBorderTabPage::FillIconViews()
1495 {
1496     FillPresetIV();
1497     FillShadowIV();
1498 }
1499 
SetLineWidth(sal_Int64 nWidth,sal_Int32 nRemovedType)1500 void SvxBorderTabPage::SetLineWidth( sal_Int64 nWidth, sal_Int32 nRemovedType )
1501 {
1502     if ( nWidth >= 0 )
1503         m_xLineWidthMF->set_value( nWidth, FieldUnit::POINT );
1504 
1505     auto it = std::find( std::begin(s_LineWidths), std::end(s_LineWidths), nWidth );
1506 
1507     if ( it != std::end(s_LineWidths) && *it >= 0 )
1508     {
1509         // Select predefined value in combobox
1510         m_xLineWidthMF->hide();
1511         m_xLineWidthLB->set_active(std::distance(std::begin(s_LineWidths), it) - nRemovedType);
1512     }
1513     else
1514     {
1515         // This is not one of predefined values. Show spinner
1516         m_xLineWidthLB->set_active(std::size(s_LineWidths) - nRemovedType -1);
1517         m_xLineWidthMF->show();
1518     }
1519 }
1520 
lcl_mediumColor(Color aMain,Color)1521 static Color lcl_mediumColor( Color aMain, Color /*aDefault*/ )
1522 {
1523     return SvxBorderLine::threeDMediumColor( aMain );
1524 }
1525 
FillLineListBox_Impl()1526 void SvxBorderTabPage::FillLineListBox_Impl()
1527 {
1528     using namespace ::com::sun::star::table::BorderLineStyle;
1529 
1530     static struct {
1531         SvxBorderLineStyle mnStyle;
1532         SvtLineListBox::ColorFunc mpColor1Fn;
1533         SvtLineListBox::ColorFunc mpColor2Fn;
1534         SvtLineListBox::ColorDistFunc mpColorDistFn;
1535     } const aLines[] = {
1536         // Simple lines
1537         { SvxBorderLineStyle::SOLID,        &sameColor, &sameColor, &sameDistColor },
1538         { SvxBorderLineStyle::DOTTED,       &sameColor, &sameColor, &sameDistColor },
1539         { SvxBorderLineStyle::DASHED,       &sameColor, &sameColor, &sameDistColor },
1540         { SvxBorderLineStyle::FINE_DASHED,  &sameColor, &sameColor, &sameDistColor },
1541         { SvxBorderLineStyle::DASH_DOT,     &sameColor, &sameColor, &sameDistColor },
1542         { SvxBorderLineStyle::DASH_DOT_DOT, &sameColor, &sameColor, &sameDistColor },
1543 
1544         // Double lines
1545         { SvxBorderLineStyle::DOUBLE,              &sameColor, &sameColor, &sameDistColor },
1546         { SvxBorderLineStyle::DOUBLE_THIN,         &sameColor, &sameColor, &sameDistColor },
1547         { SvxBorderLineStyle::THINTHICK_SMALLGAP,  &sameColor, &sameColor, &sameDistColor },
1548         { SvxBorderLineStyle::THINTHICK_MEDIUMGAP, &sameColor, &sameColor, &sameDistColor },
1549         { SvxBorderLineStyle::THINTHICK_LARGEGAP,  &sameColor, &sameColor, &sameDistColor },
1550         { SvxBorderLineStyle::THICKTHIN_SMALLGAP,  &sameColor, &sameColor, &sameDistColor },
1551         { SvxBorderLineStyle::THICKTHIN_MEDIUMGAP, &sameColor, &sameColor, &sameDistColor },
1552         { SvxBorderLineStyle::THICKTHIN_LARGEGAP,  &sameColor, &sameColor, &sameDistColor },
1553 
1554         { SvxBorderLineStyle::EMBOSSED, &SvxBorderLine::threeDLightColor, &SvxBorderLine::threeDDarkColor, &lcl_mediumColor },
1555         { SvxBorderLineStyle::ENGRAVED, &SvxBorderLine::threeDDarkColor, &SvxBorderLine::threeDLightColor, &lcl_mediumColor },
1556 
1557         { SvxBorderLineStyle::OUTSET, &SvxBorderLine::lightColor, &SvxBorderLine::darkColor, &sameDistColor },
1558         { SvxBorderLineStyle::INSET,  &SvxBorderLine::darkColor, &SvxBorderLine::lightColor, &sameDistColor }
1559     };
1560 
1561     m_xLbLineStyle->SetSourceUnit( FieldUnit::TWIP );
1562 
1563     for (size_t i = 0; i < std::size(aLines); ++i)
1564     {
1565         if (!IsBorderLineStyleAllowed(aLines[i].mnStyle))
1566             continue;
1567 
1568         m_xLbLineStyle->InsertEntry(
1569             SvxBorderLine::getWidthImpl(aLines[i].mnStyle),
1570             aLines[i].mnStyle,
1571             lcl_GetMinLineWidth(aLines[i].mnStyle),
1572             aLines[i].mpColor1Fn,
1573             aLines[i].mpColor2Fn,
1574             aLines[i].mpColorDistFn);
1575     }
1576 
1577     sal_Int64 nVal = m_xLineWidthMF->get_value(FieldUnit::NONE);
1578     nVal = static_cast<sal_Int64>(vcl::ConvertDoubleValue(nVal, m_xLineWidthMF->get_digits(),
1579                                                                   m_xLineWidthMF->get_unit(), MapUnit::MapTwip));
1580     m_xLbLineStyle->SetWidth( nVal );
1581 }
1582 
1583 
IMPL_LINK_NOARG(SvxBorderTabPage,LinesChanged_Impl,LinkParamNone *,void)1584 IMPL_LINK_NOARG(SvxBorderTabPage, LinesChanged_Impl, LinkParamNone*, void)
1585 {
1586     if (!mbUseMarginItem && m_xLeftMF->get_visible())
1587     {
1588         bool bLineSet = m_aFrameSel.IsAnyBorderVisible();
1589         bool bSpaceModified =   mbLeftModified ||
1590                                 mbRightModified ||
1591                                 mbTopModified ||
1592                                 mbBottomModified;
1593 
1594         if(bLineSet)
1595         {
1596             if(!bSpaceModified)
1597             {
1598                 m_xLeftMF->set_value(nMinValue, FieldUnit::NONE);
1599                 m_xRightMF->set_value(nMinValue, FieldUnit::NONE);
1600                 m_xTopMF->set_value(nMinValue, FieldUnit::NONE);
1601                 m_xBottomMF->set_value(nMinValue, FieldUnit::NONE);
1602             }
1603         }
1604         else
1605         {
1606             m_xLeftMF->set_min(0, FieldUnit::NONE);
1607             m_xRightMF->set_min(0, FieldUnit::NONE);
1608             m_xTopMF->set_min(0, FieldUnit::NONE);
1609             m_xBottomMF->set_min(0, FieldUnit::NONE);
1610         }
1611         // for tables everything is allowed
1612         SvxBoxInfoItemValidFlags nValid = SvxBoxInfoItemValidFlags::TOP|SvxBoxInfoItemValidFlags::BOTTOM|SvxBoxInfoItemValidFlags::LEFT|SvxBoxInfoItemValidFlags::RIGHT;
1613 
1614         m_xLeftFT->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::LEFT) );
1615         m_xRightFT->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::RIGHT) );
1616         m_xTopFT->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::TOP) );
1617         m_xBottomFT->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::BOTTOM) );
1618         m_xLeftMF->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::LEFT) );
1619         m_xRightMF->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::RIGHT) );
1620         m_xTopMF->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::TOP) );
1621         m_xBottomMF->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::BOTTOM) );
1622         m_xSynchronizeCB->set_sensitive(m_xRightMF->get_sensitive() || m_xTopMF->get_sensitive() ||
1623                                         m_xBottomMF->get_sensitive() || m_xLeftMF->get_sensitive());
1624     }
1625     UpdateRemoveAdjCellBorderCB( SAL_MAX_UINT16 );
1626 }
1627 
1628 
IMPL_LINK(SvxBorderTabPage,ModifyDistanceHdl_Impl,weld::MetricSpinButton &,rField,void)1629 IMPL_LINK( SvxBorderTabPage, ModifyDistanceHdl_Impl, weld::MetricSpinButton&, rField, void)
1630 {
1631     if (&rField == m_xLeftMF.get())
1632         mbLeftModified = true;
1633     else if (&rField == m_xRightMF.get())
1634         mbRightModified = true;
1635     else if (&rField == m_xTopMF.get())
1636         mbTopModified = true;
1637     else if (&rField == m_xBottomMF.get())
1638         mbBottomModified = true;
1639 
1640     if (mbSync)
1641     {
1642         const auto nVal = rField.get_value(FieldUnit::NONE);
1643         if (&rField != m_xLeftMF.get())
1644             m_xLeftMF->set_value(nVal, FieldUnit::NONE);
1645         if (&rField != m_xRightMF.get())
1646             m_xRightMF->set_value(nVal, FieldUnit::NONE);
1647         if (&rField != m_xTopMF.get())
1648             m_xTopMF->set_value(nVal, FieldUnit::NONE);
1649         if (&rField != m_xBottomMF.get())
1650             m_xBottomMF->set_value(nVal, FieldUnit::NONE);
1651     }
1652 }
1653 
IMPL_LINK(SvxBorderTabPage,SyncHdl_Impl,weld::Toggleable &,rBox,void)1654 IMPL_LINK( SvxBorderTabPage, SyncHdl_Impl, weld::Toggleable&, rBox, void)
1655 {
1656     mbSync = rBox.get_active();
1657 }
1658 
IMPL_LINK(SvxBorderTabPage,RemoveAdjacentCellBorderHdl_Impl,weld::Toggleable &,rBox,void)1659 IMPL_LINK( SvxBorderTabPage, RemoveAdjacentCellBorderHdl_Impl, weld::Toggleable&, rBox, void)
1660 {
1661     mbRemoveAdjacentCellBorders = rBox.get_active();
1662 }
1663 
UpdateRemoveAdjCellBorderCB(sal_uInt16 nPreset)1664 void SvxBorderTabPage::UpdateRemoveAdjCellBorderCB( sal_uInt16 nPreset )
1665 {
1666     if( !bIsCalcDoc )
1667         return;
1668     const SfxItemSet&     rOldSet         = GetItemSet();
1669     const SvxBoxInfoItem* pOldBoxInfoItem = GetOldItem( rOldSet, SID_ATTR_BORDER_INNER );
1670     const SvxBoxItem*     pOldBoxItem     = static_cast<const SvxBoxItem*>(GetOldItem( rOldSet, mnBoxSlot ));
1671     if( !pOldBoxInfoItem || !pOldBoxItem )
1672         return;
1673     std::pair<svx::FrameBorderType, SvxBoxInfoItemValidFlags> eTypes1[] = {
1674         { svx::FrameBorderType::Top,SvxBoxInfoItemValidFlags::TOP },
1675         { svx::FrameBorderType::Bottom,SvxBoxInfoItemValidFlags::BOTTOM },
1676         { svx::FrameBorderType::Left,SvxBoxInfoItemValidFlags::LEFT },
1677         { svx::FrameBorderType::Right,SvxBoxInfoItemValidFlags::RIGHT },
1678     };
1679     SvxBoxItemLine const eTypes2[] = {
1680         SvxBoxItemLine::TOP,
1681         SvxBoxItemLine::BOTTOM,
1682         SvxBoxItemLine::LEFT,
1683         SvxBoxItemLine::RIGHT,
1684     };
1685 
1686     // Check if current selection involves deletion of at least one border
1687     bool bBorderDeletionReq = false;
1688     for ( size_t i=0; i < std::size( eTypes1 ); ++i )
1689     {
1690         if( pOldBoxItem->GetLine( eTypes2[i] ) || !( pOldBoxInfoItem->IsValid( eTypes1[i].second ) ) )
1691         {
1692             if( m_aFrameSel.GetFrameBorderState( eTypes1[i].first ) == svx::FrameBorderState::Hide )
1693             {
1694                 bBorderDeletionReq = true;
1695                 break;
1696             }
1697         }
1698     }
1699 
1700     if( !bBorderDeletionReq && ( nPreset == IID_PRE_CELL_NONE || nPreset == IID_PRE_TABLE_NONE ) )
1701         bBorderDeletionReq = true;
1702 
1703     m_xRemoveAdjacentCellBordersCB->set_sensitive(bBorderDeletionReq);
1704 
1705     if( !bBorderDeletionReq )
1706     {
1707         mbRemoveAdjacentCellBorders = false;
1708         m_xRemoveAdjacentCellBordersCB->set_active(false);
1709     }
1710 }
1711 
PageCreated(const SfxAllItemSet & aSet)1712 void SvxBorderTabPage::PageCreated(const SfxAllItemSet& aSet)
1713 {
1714     const SfxUInt16Item* pSWModeItem = aSet.GetItem<SfxUInt16Item>(SID_SWMODE_TYPE, false);
1715     const SfxUInt32Item* pFlagItem = aSet.GetItem<SfxUInt32Item>(SID_FLAG_TYPE, false);
1716     if (pSWModeItem)
1717     {
1718         nSWMode = static_cast<SwBorderModes>(pSWModeItem->GetValue());
1719         // #i43593#
1720         // show checkbox <m_xMergeWithNextCB> for format.paragraph
1721         if ( nSWMode == SwBorderModes::PARA )
1722         {
1723             m_xMergeWithNextCB->show();
1724             m_xPropertiesFrame->show();
1725         }
1726         // show checkbox <m_xMergeAdjacentBordersCB> for format.paragraph
1727         else if ( nSWMode == SwBorderModes::TABLE )
1728         {
1729             m_xMergeAdjacentBordersCB->show();
1730             m_xPropertiesFrame->show();
1731         }
1732     }
1733     if (pFlagItem)
1734         if ( ( pFlagItem->GetValue() & SVX_HIDESHADOWCTL ) == SVX_HIDESHADOWCTL )
1735             HideShadowControls();
1736 }
1737 
SetTableMode()1738 void SvxBorderTabPage::SetTableMode()
1739 {
1740     nSWMode = SwBorderModes::TABLE;
1741 }
1742 
1743 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1744