xref: /core/cui/source/tabpages/border.cxx (revision 6abc0992)
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 <sal/macros.h>
45 #include <com/sun/star/lang/XServiceInfo.hpp>
46 #include <comphelper/lok.hxx>
47 #include <svtools/unitconv.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 {
81 int lcl_twipsToPt(sal_Int64 nTwips)
82 {
83     return vcl::ConvertDoubleValue(nTwips, 0, FieldUnit::TWIP, MapUnit::MapPoint) * 100;
84 }
85 }
86 
87 const std::vector<int> SvxBorderTabPage::m_aLineWidths = {
88     lcl_twipsToPt(SvxBorderLineWidth::Hairline),
89     lcl_twipsToPt(SvxBorderLineWidth::VeryThin),
90     lcl_twipsToPt(SvxBorderLineWidth::Thin),
91     lcl_twipsToPt(SvxBorderLineWidth::Medium),
92     lcl_twipsToPt(SvxBorderLineWidth::Thick),
93     lcl_twipsToPt(SvxBorderLineWidth::ExtraThick),
94     -1
95 };
96 
97 static void lcl_SetDecimalDigitsTo1(weld::MetricSpinButton& rField)
98 {
99     auto nMin = rField.denormalize(rField.get_min(FieldUnit::TWIP));
100     rField.set_digits(1);
101     rField.set_min(rField.normalize(nMin), FieldUnit::TWIP);
102 }
103 
104 // returns in pt
105 static sal_Int64 lcl_GetMinLineWidth(SvxBorderLineStyle aStyle)
106 {
107     switch (aStyle)
108     {
109     case SvxBorderLineStyle::NONE:
110         return 0;
111 
112     case SvxBorderLineStyle::SOLID:
113     case SvxBorderLineStyle::DOTTED:
114     case SvxBorderLineStyle::DASHED:
115     case SvxBorderLineStyle::FINE_DASHED:
116     case SvxBorderLineStyle::DASH_DOT:
117     case SvxBorderLineStyle::DASH_DOT_DOT:
118         return 15;
119 
120         // Double lines
121     case SvxBorderLineStyle::DOUBLE: return 15;
122     case SvxBorderLineStyle::DOUBLE_THIN: return 15;
123     case SvxBorderLineStyle::THINTHICK_SMALLGAP: return 20;
124     case SvxBorderLineStyle::THINTHICK_MEDIUMGAP: return 15;
125     case SvxBorderLineStyle::THINTHICK_LARGEGAP: return 15;
126     case SvxBorderLineStyle::THICKTHIN_SMALLGAP: return 20;
127     case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP: return 15;
128     case SvxBorderLineStyle::THICKTHIN_LARGEGAP: return 15;
129 
130     case SvxBorderLineStyle::EMBOSSED: return 15;
131     case SvxBorderLineStyle::ENGRAVED: return 15;
132 
133     case SvxBorderLineStyle::OUTSET: return 10;
134     case SvxBorderLineStyle::INSET: return 10;
135 
136     default:
137         return 15;
138     }
139 }
140 
141 // number of preset images to show
142 const sal_uInt16 BORDER_PRESET_COUNT = 5;
143 
144 // number of shadow images to show
145 const sal_uInt16 BORDER_SHADOW_COUNT = 5;
146 
147 ShadowControlsWrapper::ShadowControlsWrapper(ValueSet& rVsPos, weld::MetricSpinButton& rMfSize, ColorListBox& rLbColor)
148     : mrVsPos(rVsPos)
149     , mrMfSize(rMfSize)
150     , mrLbColor(rLbColor)
151 {
152 }
153 
154 SvxShadowItem ShadowControlsWrapper::GetControlValue(const SvxShadowItem& rItem) const
155 {
156     SvxShadowItem aItem(rItem);
157     if (!mrVsPos.IsNoSelection())
158     {
159         switch (mrVsPos.GetSelectedItemId())
160         {
161             case 1:
162                 aItem.SetLocation(SvxShadowLocation::NONE);
163                 break;
164             case 2:
165                 aItem.SetLocation(SvxShadowLocation::BottomRight);
166                 break;
167             case 3:
168                 aItem.SetLocation(SvxShadowLocation::TopRight);
169                 break;
170             case 4:
171                 aItem.SetLocation(SvxShadowLocation::BottomLeft);
172                 break;
173             case 5:
174                 aItem.SetLocation(SvxShadowLocation::TopLeft);
175                 break;
176             default:
177                 aItem.SetLocation(SvxShadowLocation::NONE);
178                 break;
179         }
180     }
181     // Default value was saved; so don't change the aItem's width if the control
182     // has not changed its value, to avoid round-trip errors (like twip->cm->twip)
183     // E.g., initial 100 twip will become 0.18 cm, which will return as 102 twip
184     if (mrMfSize.get_value_changed_from_saved())
185         aItem.SetWidth(mrMfSize.denormalize(mrMfSize.get_value(FieldUnit::TWIP)));
186     if (!mrLbColor.IsNoSelection())
187         aItem.SetColor(mrLbColor.GetSelectEntryColor());
188     return aItem;
189 }
190 
191 void ShadowControlsWrapper::SetControlValue(const SvxShadowItem& rItem)
192 {
193     switch (rItem.GetLocation())
194     {
195         case SvxShadowLocation::NONE:
196             mrVsPos.SelectItem(1);
197             break;
198         case SvxShadowLocation::BottomRight:
199             mrVsPos.SelectItem(2);
200             break;
201         case SvxShadowLocation::TopRight:
202             mrVsPos.SelectItem(3);
203             break;
204         case SvxShadowLocation::BottomLeft:
205             mrVsPos.SelectItem(4);
206             break;
207         case SvxShadowLocation::TopLeft:
208             mrVsPos.SelectItem(5);
209             break;
210         default:
211             mrVsPos.SetNoSelection();
212             break;
213     }
214     mrVsPos.SaveValue();
215     mrMfSize.set_value(mrMfSize.normalize(rItem.GetWidth()), FieldUnit::TWIP);
216     mrMfSize.save_value();
217     mrLbColor.SelectEntry(rItem.GetColor());
218     mrLbColor.SaveValue();
219 }
220 
221 bool ShadowControlsWrapper::get_value_changed_from_saved() const
222 {
223     return mrVsPos.IsValueChangedFromSaved() ||
224            mrMfSize.get_value_changed_from_saved() ||
225            mrLbColor.IsValueChangedFromSaved();
226 }
227 
228 void ShadowControlsWrapper::SetControlDontKnow()
229 {
230     mrVsPos.SetNoSelection();
231     mrMfSize.set_text("");
232     mrLbColor.SetNoSelection();
233 }
234 
235 MarginControlsWrapper::MarginControlsWrapper(weld::MetricSpinButton& rMfLeft, weld::MetricSpinButton& rMfRight,
236                                              weld::MetricSpinButton& rMfTop, weld::MetricSpinButton& rMfBottom)
237     : mrLeftWrp(rMfLeft)
238     , mrRightWrp(rMfRight)
239     , mrTopWrp(rMfTop)
240     , mrBottomWrp(rMfBottom)
241 {
242 }
243 
244 SvxMarginItem MarginControlsWrapper::GetControlValue(const SvxMarginItem &rItem) const
245 {
246     SvxMarginItem aItem(rItem);
247     if (mrLeftWrp.get_sensitive())
248         aItem.SetLeftMargin(mrLeftWrp.denormalize(mrLeftWrp.get_value(FieldUnit::TWIP)));
249     if (mrRightWrp.get_sensitive())
250         aItem.SetRightMargin(mrRightWrp.denormalize(mrRightWrp.get_value(FieldUnit::TWIP)));
251     if (mrTopWrp.get_sensitive())
252         aItem.SetTopMargin(mrTopWrp.denormalize(mrTopWrp.get_value(FieldUnit::TWIP)));
253     if (mrBottomWrp.get_sensitive())
254         aItem.SetBottomMargin(mrBottomWrp.denormalize(mrBottomWrp.get_value(FieldUnit::TWIP)));
255     return aItem;
256 }
257 
258 bool MarginControlsWrapper::get_value_changed_from_saved() const
259 {
260     return mrLeftWrp.get_value_changed_from_saved() ||
261            mrRightWrp.get_value_changed_from_saved() ||
262            mrTopWrp.get_value_changed_from_saved() ||
263            mrBottomWrp.get_value_changed_from_saved();
264 }
265 
266 void MarginControlsWrapper::SetControlValue(const SvxMarginItem& rItem)
267 {
268     mrLeftWrp.set_value(mrLeftWrp.normalize(rItem.GetLeftMargin()), FieldUnit::TWIP);
269     mrRightWrp.set_value(mrRightWrp.normalize(rItem.GetRightMargin()), FieldUnit::TWIP);
270     mrTopWrp.set_value(mrTopWrp.normalize(rItem.GetTopMargin()), FieldUnit::TWIP);
271     mrBottomWrp.set_value(mrBottomWrp.normalize(rItem.GetBottomMargin()), FieldUnit::TWIP);
272     mrLeftWrp.save_value();
273     mrRightWrp.save_value();
274     mrTopWrp.save_value();
275     mrBottomWrp.save_value();
276 }
277 
278 void MarginControlsWrapper::SetControlDontKnow()
279 {
280     const OUString sEmpty;
281     mrLeftWrp.set_text(sEmpty);
282     mrRightWrp.set_text(sEmpty);
283     mrTopWrp.set_text(sEmpty);
284     mrBottomWrp.set_text(sEmpty);
285 }
286 
287 SvxBorderTabPage::SvxBorderTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
288     : SfxTabPage(pPage, pController, "cui/ui/borderpage.ui", "BorderPage", &rCoreAttrs)
289     , nMinValue(0)
290     , nSWMode(SwBorderModes::NONE)
291     , mnBoxSlot(SID_ATTR_BORDER_OUTER)
292     , mnShadowSlot(SID_ATTR_BORDER_SHADOW)
293     , mbHorEnabled(false)
294     , mbVerEnabled(false)
295     , mbTLBREnabled(false)
296     , mbBLTREnabled(false)
297     , mbUseMarginItem(false)
298     , mbLeftModified(false)
299     , mbRightModified(false)
300     , mbTopModified(false)
301     , mbBottomModified(false)
302     , mbSync(true)
303     , mbRemoveAdjacentCellBorders(false)
304     , bIsCalcDoc(false)
305     , m_xWndPresets(new ValueSet(nullptr))
306     , m_xWndPresetsWin(new weld::CustomWeld(*m_xBuilder, "presets", *m_xWndPresets))
307     , m_xUserDefFT(m_xBuilder->weld_label("userdefft"))
308     , m_xFrameSelWin(new weld::CustomWeld(*m_xBuilder, "framesel", m_aFrameSel))
309     , m_xLbLineStyle(new SvtLineListBox(m_xBuilder->weld_menu_button("linestylelb")))
310     , m_xLbLineColor(new ColorListBox(m_xBuilder->weld_menu_button("linecolorlb"),
311                 [this]{ return GetDialogController()->getDialog(); }))
312     , m_xLineWidthLB(m_xBuilder->weld_combo_box("linewidthlb"))
313     , m_xLineWidthMF(m_xBuilder->weld_metric_spin_button("linewidthmf", FieldUnit::POINT))
314     , m_xSpacingFrame(m_xBuilder->weld_container("spacing"))
315     , m_xLeftFT(m_xBuilder->weld_label("leftft"))
316     , m_xLeftMF(m_xBuilder->weld_metric_spin_button("leftmf", FieldUnit::MM))
317     , m_xRightFT(m_xBuilder->weld_label("rightft"))
318     , m_xRightMF(m_xBuilder->weld_metric_spin_button("rightmf", FieldUnit::MM))
319     , m_xTopFT(m_xBuilder->weld_label("topft"))
320     , m_xTopMF(m_xBuilder->weld_metric_spin_button("topmf", FieldUnit::MM))
321     , m_xBottomFT(m_xBuilder->weld_label("bottomft"))
322     , m_xBottomMF(m_xBuilder->weld_metric_spin_button("bottommf", FieldUnit::MM))
323     , m_xSynchronizeCB(m_xBuilder->weld_check_button("sync"))
324     , m_xShadowFrame(m_xBuilder->weld_container("shadow"))
325     , m_xWndShadows(new ValueSet(nullptr))
326     , m_xWndShadowsWin(new weld::CustomWeld(*m_xBuilder, "shadows", *m_xWndShadows))
327     , m_xFtShadowSize(m_xBuilder->weld_label("distanceft"))
328     , m_xEdShadowSize(m_xBuilder->weld_metric_spin_button("distancemf", FieldUnit::MM))
329     , m_xFtShadowColor(m_xBuilder->weld_label("shadowcolorft"))
330     , m_xLbShadowColor(new ColorListBox(m_xBuilder->weld_menu_button("shadowcolorlb"),
331                 [this]{ return GetDialogController()->getDialog(); }))
332     , m_xPropertiesFrame(m_xBuilder->weld_container("properties"))
333     , m_xMergeWithNextCB(m_xBuilder->weld_check_button("mergewithnext"))
334     , m_xMergeAdjacentBordersCB(m_xBuilder->weld_check_button("mergeadjacent"))
335     , m_xRemoveAdjacentCellBordersCB(m_xBuilder->weld_check_button("rmadjcellborders"))
336     , m_xRemoveAdjacentCellBordersFT(m_xBuilder->weld_label("rmadjcellbordersft"))
337 {
338     static std::vector<OUString> aBorderImageIds;
339 
340     if (aBorderImageIds.empty())
341     {
342         if (comphelper::LibreOfficeKit::isActive())
343         {
344             aBorderImageIds.insert(aBorderImageIds.end(), {
345                 RID_SVXBMP_CELL_NONE_32,
346                 RID_SVXBMP_CELL_ALL_32,
347                 RID_SVXBMP_CELL_LR_32,
348                 RID_SVXBMP_CELL_TB_32,
349                 RID_SVXBMP_CELL_L_32,
350                 RID_SVXBMP_CELL_DIAG_32
351             });
352         }
353         else
354         {
355             aBorderImageIds.insert(aBorderImageIds.end(), {
356                 RID_SVXBMP_CELL_NONE,
357                 RID_SVXBMP_CELL_ALL,
358                 RID_SVXBMP_CELL_LR,
359                 RID_SVXBMP_CELL_TB,
360                 RID_SVXBMP_CELL_L,
361                 RID_SVXBMP_CELL_DIAG
362             });
363         }
364         aBorderImageIds.insert(aBorderImageIds.end(), {
365             RID_SVXBMP_HOR_NONE,
366             RID_SVXBMP_HOR_OUTER,
367             RID_SVXBMP_HOR_HOR,
368             RID_SVXBMP_HOR_ALL,
369             RID_SVXBMP_HOR_OUTER2,
370             RID_SVXBMP_VER_NONE,
371             RID_SVXBMP_VER_OUTER,
372             RID_SVXBMP_VER_VER,
373             RID_SVXBMP_VER_ALL,
374             RID_SVXBMP_VER_OUTER2,
375             RID_SVXBMP_TABLE_NONE,
376             RID_SVXBMP_TABLE_OUTER,
377             RID_SVXBMP_TABLE_OUTERH,
378             RID_SVXBMP_TABLE_ALL,
379             RID_SVXBMP_TABLE_OUTER2
380         });
381     }
382 
383     for (auto const & rImageId : aBorderImageIds)
384         m_aBorderImgVec.emplace_back(StockImage::Yes, rImageId);
385 
386     static std::vector<OUString> aShadowImageIds;
387     if (aShadowImageIds.empty())
388     {
389         if (comphelper::LibreOfficeKit::isActive())
390         {
391             aShadowImageIds.insert(aShadowImageIds.end(), {
392                 RID_SVXBMP_SHADOWNONE_32,
393                 RID_SVXBMP_SHADOW_BOT_RIGHT_32,
394                 RID_SVXBMP_SHADOW_TOP_RIGHT_32,
395                 RID_SVXBMP_SHADOW_BOT_LEFT_32,
396                 RID_SVXBMP_SHADOW_TOP_LEFT_32
397             });
398         }
399         else
400         {
401             aShadowImageIds.insert(aShadowImageIds.end(), {
402                 RID_SVXBMP_SHADOWNONE,
403                 RID_SVXBMP_SHADOW_BOT_RIGHT,
404                 RID_SVXBMP_SHADOW_TOP_RIGHT,
405                 RID_SVXBMP_SHADOW_BOT_LEFT,
406                 RID_SVXBMP_SHADOW_TOP_LEFT
407             });
408         }
409     }
410 
411     for (auto const & rImageId : aShadowImageIds)
412         m_aShadowImgVec.emplace_back(StockImage::Yes, rImageId);
413 
414     assert(m_aShadowImgVec.size() == BORDER_SHADOW_COUNT);
415 
416     // this page needs ExchangeSupport
417     SetExchangeSupport();
418 
419     /*  Use SvxMarginItem instead of margins from SvxBoxItem, if present.
420         ->  Remember this state in mbUseMarginItem, because other special handling
421             is needed across various functions... */
422     mbUseMarginItem = rCoreAttrs.GetItemState(GetWhich(SID_ATTR_ALIGN_MARGIN)) != SfxItemState::UNKNOWN;
423 
424     if (const SfxIntegerListItem* p = rCoreAttrs.GetItemIfSet(SID_ATTR_BORDER_STYLES))
425     {
426         std::vector<sal_Int32> aUsedStyles = p->GetList();
427         for (int aUsedStyle : aUsedStyles)
428             maUsedBorderStyles.insert(static_cast<SvxBorderLineStyle>(aUsedStyle));
429     }
430 
431     if (const SfxInt64Item* p = rCoreAttrs.GetItemIfSet(SID_ATTR_BORDER_DEFAULT_WIDTH))
432     {
433         // The caller specifies default line width.  Honor it.
434         SetLineWidth(p->GetValue());
435     }
436 
437     // set metric
438     FieldUnit eFUnit = GetModuleFieldUnit( rCoreAttrs );
439 
440     if( mbUseMarginItem )
441     {
442         // copied from SvxAlignmentTabPage
443         switch ( eFUnit )
444         {
445             //  #103396# the default value (1pt) can't be accurately represented in
446             //  inches or pica with two decimals, so point is used instead.
447             case FieldUnit::PICA:
448             case FieldUnit::INCH:
449             case FieldUnit::FOOT:
450             case FieldUnit::MILE:
451                 eFUnit = FieldUnit::POINT;
452                 break;
453 
454             case FieldUnit::CM:
455             case FieldUnit::M:
456             case FieldUnit::KM:
457                 eFUnit = FieldUnit::MM;
458                 break;
459             default: ;//prevent warning
460         }
461     }
462     else
463     {
464         switch ( eFUnit )
465         {
466             case FieldUnit::M:
467             case FieldUnit::KM:
468                 eFUnit = FieldUnit::MM;
469                 break;
470             default: ; //prevent warning
471         }
472     }
473 
474     SetFieldUnit(*m_xEdShadowSize, eFUnit);
475 
476     sal_uInt16 nWhich = GetWhich( SID_ATTR_BORDER_INNER, false );
477     bool bIsDontCare = true;
478 
479     if ( rCoreAttrs.GetItemState( nWhich ) >= SfxItemState::DEFAULT )
480     {
481         // paragraph or table
482         const SvxBoxInfoItem* pBoxInfo =
483             static_cast<const SvxBoxInfoItem*>(&( rCoreAttrs.Get( nWhich ) ));
484 
485         mbHorEnabled = pBoxInfo->IsHorEnabled();
486         mbVerEnabled = pBoxInfo->IsVerEnabled();
487         mbTLBREnabled = rCoreAttrs.GetItemState(GetWhich(SID_ATTR_BORDER_DIAG_TLBR)) != SfxItemState::UNKNOWN;
488         mbBLTREnabled = rCoreAttrs.GetItemState(GetWhich(SID_ATTR_BORDER_DIAG_BLTR)) != SfxItemState::UNKNOWN;
489 
490         if(pBoxInfo->IsDist())
491         {
492             SetFieldUnit(*m_xLeftMF, eFUnit);
493             SetFieldUnit(*m_xRightMF, eFUnit);
494             SetFieldUnit(*m_xTopMF, eFUnit);
495             SetFieldUnit(*m_xBottomMF, eFUnit);
496             m_xSynchronizeCB->connect_toggled(LINK(this, SvxBorderTabPage, SyncHdl_Impl));
497             m_xLeftMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyDistanceHdl_Impl));
498             m_xRightMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyDistanceHdl_Impl));
499             m_xTopMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyDistanceHdl_Impl));
500             m_xBottomMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyDistanceHdl_Impl));
501         }
502         else
503         {
504             m_xSpacingFrame->hide();
505         }
506         bIsDontCare = !pBoxInfo->IsValid( SvxBoxInfoItemValidFlags::DISABLE );
507     }
508     if(!mbUseMarginItem && eFUnit == FieldUnit::MM && MapUnit::MapTwip == rCoreAttrs.GetPool()->GetMetric( GetWhich( SID_ATTR_BORDER_INNER ) ))
509     {
510         //#i91548# changing the number of decimal digits changes the minimum values, too
511         lcl_SetDecimalDigitsTo1(*m_xLeftMF);
512         lcl_SetDecimalDigitsTo1(*m_xRightMF);
513         lcl_SetDecimalDigitsTo1(*m_xTopMF);
514         lcl_SetDecimalDigitsTo1(*m_xBottomMF);
515         lcl_SetDecimalDigitsTo1(*m_xEdShadowSize);
516     }
517 
518     FrameSelFlags nFlags = FrameSelFlags::Outer;
519     if( mbHorEnabled )
520         nFlags |= FrameSelFlags::InnerHorizontal;
521     if( mbVerEnabled )
522         nFlags |= FrameSelFlags::InnerVertical;
523     if( mbTLBREnabled )
524         nFlags |= FrameSelFlags::DiagonalTLBR;
525     if( mbBLTREnabled )
526         nFlags |= FrameSelFlags::DiagonalBLTR;
527     if( bIsDontCare )
528         nFlags |= FrameSelFlags::DontCare;
529     m_aFrameSel.Initialize( nFlags );
530 
531     m_aFrameSel.SetSelectHdl(LINK(this, SvxBorderTabPage, LinesChanged_Impl));
532     m_xLbLineStyle->SetSelectHdl( LINK( this, SvxBorderTabPage, SelStyleHdl_Impl ) );
533     m_xLbLineColor->SetSelectHdl( LINK( this, SvxBorderTabPage, SelColHdl_Impl ) );
534     m_xLineWidthLB->connect_changed(LINK(this, SvxBorderTabPage, ModifyWidthLBHdl_Impl));
535     m_xLineWidthMF->connect_value_changed(LINK(this, SvxBorderTabPage, ModifyWidthMFHdl_Impl));
536     m_xWndPresets->SetSelectHdl( LINK( this, SvxBorderTabPage, SelPreHdl_Impl ) );
537     m_xWndShadows->SetSelectHdl( LINK( this, SvxBorderTabPage, SelSdwHdl_Impl ) );
538 
539     FillValueSets();
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("DialogUseCharAttr");
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     SfxObjectShell* pDocSh = SfxObjectShell::Current();
578     if (pDocSh)
579     {
580         Reference< XServiceInfo > xSI( pDocSh->GetModel(), UNO_QUERY );
581         if ( xSI.is() )
582             bIsCalcDoc = xSI->supportsService("com.sun.star.sheet.SpreadsheetDocument");
583     }
584     if( bIsCalcDoc )
585     {
586         m_xRemoveAdjacentCellBordersCB->connect_toggled(LINK(this, SvxBorderTabPage, RemoveAdjacentCellBorderHdl_Impl));
587         m_xRemoveAdjacentCellBordersCB->show();
588         m_xRemoveAdjacentCellBordersCB->set_sensitive(false);
589     }
590     else
591     {
592         m_xRemoveAdjacentCellBordersCB->hide();
593         m_xRemoveAdjacentCellBordersFT->hide();
594     }
595 }
596 
597 SvxBorderTabPage::~SvxBorderTabPage()
598 {
599     m_xLbShadowColor.reset();
600     m_xWndShadowsWin.reset();
601     m_xWndShadows.reset();
602     m_xLbLineColor.reset();
603     m_xLbLineStyle.reset();
604     m_xFrameSelWin.reset();
605     m_xWndPresetsWin.reset();
606     m_xWndPresets.reset();
607 }
608 
609 std::unique_ptr<SfxTabPage> SvxBorderTabPage::Create( weld::Container* pPage, weld::DialogController* pController,
610                                              const SfxItemSet* rAttrSet )
611 {
612     return std::make_unique<SvxBorderTabPage>(pPage, pController, *rAttrSet);
613 }
614 
615 void SvxBorderTabPage::ResetFrameLine_Impl( svx::FrameBorderType eBorder, const SvxBorderLine* pCoreLine, bool bValid )
616 {
617     if( m_aFrameSel.IsBorderEnabled( eBorder ) )
618     {
619         if( bValid )
620             m_aFrameSel.ShowBorder( eBorder, pCoreLine );
621         else
622             m_aFrameSel.SetBorderDontCare( eBorder );
623     }
624 }
625 
626 bool SvxBorderTabPage::IsBorderLineStyleAllowed( SvxBorderLineStyle nStyle ) const
627 {
628     if (maUsedBorderStyles.empty())
629         // All border styles are allowed.
630         return true;
631 
632     return maUsedBorderStyles.count(nStyle) > 0;
633 }
634 
635 void SvxBorderTabPage::Reset( const SfxItemSet* rSet )
636 {
637     SfxItemPool* pPool = rSet->GetPool();
638 
639     if (m_aFrameSel.IsBorderEnabled(svx::FrameBorderType::TLBR))
640     {
641         sal_uInt16 nBorderDiagId = pPool->GetWhich(SID_ATTR_BORDER_DIAG_TLBR);
642         if (const SvxLineItem* pLineItem = static_cast<const SvxLineItem*>(rSet->GetItem(nBorderDiagId)))
643             m_aFrameSel.ShowBorder(svx::FrameBorderType::TLBR, pLineItem->GetLine());
644         else
645             m_aFrameSel.SetBorderDontCare(svx::FrameBorderType::TLBR);
646     }
647 
648     if (m_aFrameSel.IsBorderEnabled(svx::FrameBorderType::BLTR))
649     {
650         sal_uInt16 nBorderDiagId = pPool->GetWhich(SID_ATTR_BORDER_DIAG_BLTR);
651         if (const SvxLineItem* pLineItem = static_cast<const SvxLineItem*>(rSet->GetItem(nBorderDiagId)))
652             m_aFrameSel.ShowBorder(svx::FrameBorderType::BLTR, pLineItem->GetLine());
653         else
654             m_aFrameSel.SetBorderDontCare(svx::FrameBorderType::BLTR);
655     }
656 
657     if (m_xShadowControls)
658     {
659         sal_uInt16 nShadowId = pPool->GetWhich(mnShadowSlot);
660         const SfxPoolItem* pItem = rSet->GetItem(nShadowId);
661         if (pItem)
662             m_xShadowControls->SetControlValue(*static_cast<const SvxShadowItem*>(pItem));
663         else
664             m_xShadowControls->SetControlDontKnow();
665     }
666 
667     if (m_xMarginControls)
668     {
669         sal_uInt16 nAlignMarginId = pPool->GetWhich(SID_ATTR_ALIGN_MARGIN);
670         const SfxPoolItem* pItem = rSet->GetItem(nAlignMarginId);
671         if (pItem)
672             m_xMarginControls->SetControlValue(*static_cast<const SvxMarginItem*>(pItem));
673         else
674             m_xMarginControls->SetControlDontKnow();
675     }
676 
677     sal_uInt16 nMergeAdjacentBordersId = pPool->GetWhich(SID_SW_COLLAPSING_BORDERS);
678     const SfxBoolItem *pMergeAdjacentBorders = static_cast<const SfxBoolItem*>(rSet->GetItem(nMergeAdjacentBordersId));
679     if (!pMergeAdjacentBorders)
680         m_xMergeAdjacentBordersCB->set_state(TRISTATE_INDET);
681     else
682         m_xMergeAdjacentBordersCB->set_active(pMergeAdjacentBorders->GetValue());
683     m_xMergeAdjacentBordersCB->save_state();
684 
685     sal_uInt16 nMergeWithNextId = pPool->GetWhich(SID_ATTR_BORDER_CONNECT);
686     const SfxBoolItem *pMergeWithNext = static_cast<const SfxBoolItem*>(rSet->GetItem(nMergeWithNextId));
687     if (!pMergeWithNext)
688         m_xMergeWithNextCB->set_state(TRISTATE_INDET);
689     else
690         m_xMergeWithNextCB->set_active(pMergeWithNext->GetValue());
691     m_xMergeWithNextCB->save_state();
692 
693     const SvxBoxItem*       pBoxItem;
694     const SvxBoxInfoItem*   pBoxInfoItem;
695     sal_uInt16              nWhichBox       = GetWhich(mnBoxSlot);
696     MapUnit                 eCoreUnit;
697 
698     pBoxItem  = static_cast<const SvxBoxItem*>(GetItem( *rSet, mnBoxSlot ));
699 
700     pBoxInfoItem = GetItem( *rSet, SID_ATTR_BORDER_INNER, false );
701 
702     eCoreUnit = pPool->GetMetric( nWhichBox );
703 
704     if ( pBoxItem && pBoxInfoItem ) // -> Don't Care
705     {
706         ResetFrameLine_Impl( svx::FrameBorderType::Left,   pBoxItem->GetLeft(),     pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::LEFT ) );
707         ResetFrameLine_Impl( svx::FrameBorderType::Right,  pBoxItem->GetRight(),    pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::RIGHT ) );
708         ResetFrameLine_Impl( svx::FrameBorderType::Top,    pBoxItem->GetTop(),      pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::TOP ) );
709         ResetFrameLine_Impl( svx::FrameBorderType::Bottom, pBoxItem->GetBottom(),   pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::BOTTOM ) );
710         ResetFrameLine_Impl( svx::FrameBorderType::Vertical,    pBoxInfoItem->GetVert(), pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::VERT ) );
711         ResetFrameLine_Impl( svx::FrameBorderType::Horizontal,    pBoxInfoItem->GetHori(), pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::HORI ) );
712 
713 
714         // distance inside
715 
716         if( !mbUseMarginItem )
717         {
718             if (m_xLeftMF->get_visible())
719             {
720                 SetMetricValue(*m_xLeftMF,    pBoxInfoItem->GetDefDist(), eCoreUnit);
721                 SetMetricValue(*m_xRightMF,   pBoxInfoItem->GetDefDist(), eCoreUnit);
722                 SetMetricValue(*m_xTopMF,     pBoxInfoItem->GetDefDist(), eCoreUnit);
723                 SetMetricValue(*m_xBottomMF,  pBoxInfoItem->GetDefDist(), eCoreUnit);
724 
725                 nMinValue = m_xLeftMF->get_value(FieldUnit::NONE);
726 
727                 if ( pBoxInfoItem->IsDist() )
728                 {
729                     if( rSet->GetItemState( nWhichBox ) >= SfxItemState::DEFAULT )
730                     {
731                         bool bIsAnyBorderVisible = m_aFrameSel.IsAnyBorderVisible();
732                         if( !bIsAnyBorderVisible || !pBoxInfoItem->IsMinDist() )
733                         {
734                             m_xLeftMF->set_min(0, FieldUnit::NONE);
735                             m_xRightMF->set_min(0, FieldUnit::NONE);
736                             m_xTopMF->set_min(0, FieldUnit::NONE);
737                             m_xBottomMF->set_min(0, FieldUnit::NONE);
738                         }
739                         tools::Long nLeftDist = pBoxItem->GetDistance( SvxBoxItemLine::LEFT);
740                         SetMetricValue(*m_xLeftMF, nLeftDist, eCoreUnit);
741                         tools::Long nRightDist = pBoxItem->GetDistance( SvxBoxItemLine::RIGHT);
742                         SetMetricValue(*m_xRightMF, nRightDist, eCoreUnit);
743                         tools::Long nTopDist = pBoxItem->GetDistance( SvxBoxItemLine::TOP);
744                         SetMetricValue( *m_xTopMF, nTopDist, eCoreUnit );
745                         tools::Long nBottomDist = pBoxItem->GetDistance( SvxBoxItemLine::BOTTOM);
746                         SetMetricValue( *m_xBottomMF, nBottomDist, eCoreUnit );
747 
748                         // if the distance is set with no active border line
749                         // or it is null with an active border line
750                         // no automatic changes should be made
751                         const tools::Long nDefDist = bIsAnyBorderVisible ? pBoxInfoItem->GetDefDist() : 0;
752                         bool bDiffDist = (nDefDist != nLeftDist ||
753                                     nDefDist != nRightDist ||
754                                     nDefDist != nTopDist   ||
755                                     nDefDist != nBottomDist);
756                         if ((pBoxItem->GetSmallestDistance() || bIsAnyBorderVisible) && bDiffDist )
757                         {
758                             mbLeftModified = true;
759                             mbRightModified = true;
760                             mbTopModified = true;
761                             mbBottomModified = true;
762                         }
763                     }
764                     else
765                     {
766                         // #106224# different margins -> do not fill the edits
767                         m_xLeftMF->set_text( OUString() );
768                         m_xRightMF->set_text( OUString() );
769                         m_xTopMF->set_text( OUString() );
770                         m_xBottomMF->set_text( OUString() );
771                     }
772                 }
773                 m_xLeftMF->save_value();
774                 m_xRightMF->save_value();
775                 m_xTopMF->save_value();
776                 m_xBottomMF->save_value();
777             }
778         }
779     }
780     else
781     {
782         // avoid ResetFrameLine-calls:
783         m_aFrameSel.HideAllBorders();
784     }
785 
786     if( !m_aFrameSel.IsAnyBorderVisible() )
787         m_aFrameSel.DeselectAllBorders();
788 
789     // depict line (color) in controllers if unambiguous:
790 
791     {
792         // Do all visible lines show the same line widths?
793         tools::Long nWidth;
794         SvxBorderLineStyle nStyle;
795         bool bWidthEq = m_aFrameSel.GetVisibleWidth( nWidth, nStyle );
796         if( bWidthEq )
797         {
798             // Determine the width first as some styles can be missing depending on it
799             sal_Int64 nWidthPt =  static_cast<sal_Int64>(vcl::ConvertDoubleValue(
800                         sal_Int64( nWidth ), m_xLineWidthMF->get_digits(),
801                         MapUnit::MapTwip, FieldUnit::POINT ));
802             SetLineWidth(nWidthPt);
803             m_xLbLineStyle->SetWidth(nWidth);
804 
805             // then set the style
806             m_xLbLineStyle->SelectEntry( nStyle );
807         }
808         else
809             m_xLbLineStyle->SelectEntry(SvxBorderLineStyle::SOLID);
810 
811         // Do all visible lines show the same line color?
812         Color aColor;
813         bool bColorEq = m_aFrameSel.GetVisibleColor( aColor );
814         if( !bColorEq )
815             aColor = COL_BLACK;
816 
817         m_xLbLineColor->SelectEntry(aColor);
818         auto nTextColor = Application::GetSettings().GetStyleSettings().GetWindowTextColor();
819         m_xLbLineStyle->SetColor(nTextColor);
820 
821         // Select all visible lines, if they are all equal.
822         if( bWidthEq && bColorEq )
823             m_aFrameSel.SelectAllVisibleBorders();
824 
825         // set the current style and color (caches style in control even if nothing is selected)
826         SelStyleHdl_Impl(*m_xLbLineStyle);
827         SelColHdl_Impl(*m_xLbLineColor);
828     }
829 
830     bool bEnable = m_xWndShadows->GetSelectedItemId() > 1 ;
831     m_xFtShadowSize->set_sensitive(bEnable);
832     m_xEdShadowSize->set_sensitive(bEnable);
833     m_xFtShadowColor->set_sensitive(bEnable);
834     m_xLbShadowColor->set_sensitive(bEnable);
835 
836     m_xWndPresets->SetNoSelection();
837 
838     // - no line - should not be selected
839 
840     if (m_xLbLineStyle->GetSelectEntryStyle() == SvxBorderLineStyle::NONE)
841     {
842         m_xLbLineStyle->SelectEntry(SvxBorderLineStyle::SOLID);
843         SelStyleHdl_Impl(*m_xLbLineStyle);
844     }
845 
846     const SfxUInt16Item* pHtmlModeItem = rSet->GetItemIfSet(SID_HTML_MODE, false);
847     if(!pHtmlModeItem)
848     {
849         if (SfxObjectShell* pShell = SfxObjectShell::Current())
850             pHtmlModeItem = pShell->GetItem(SID_HTML_MODE);
851     }
852     if(pHtmlModeItem)
853     {
854         sal_uInt16 nHtmlMode = pHtmlModeItem->GetValue();
855         if(nHtmlMode & HTMLMODE_ON)
856         {
857             // there are no shadows in Html-mode and only complete borders
858             m_xShadowFrame->set_sensitive(false);
859 
860             if( !(nSWMode & SwBorderModes::TABLE) )
861             {
862                 m_xUserDefFT->set_sensitive(false);
863                 m_xFrameSelWin->set_sensitive(false);
864                 m_xWndPresets->RemoveItem(3);
865                 m_xWndPresets->RemoveItem(4);
866                 m_xWndPresets->RemoveItem(5);
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 
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 
897 DeactivateRC SvxBorderTabPage::DeactivatePage( SfxItemSet* _pSet )
898 {
899     if ( _pSet )
900         FillItemSet( _pSet );
901 
902     return DeactivateRC::LeavePage;
903 }
904 
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->GetWhich(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->GetWhich(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->GetWhich( 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 
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 
1157 IMPL_LINK_NOARG(SvxBorderTabPage, SelPreHdl_Impl, ValueSet*, 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 nLine = GetPresetImageId( m_xWndPresets->GetSelectedItemId() ) - 1;
1195 
1196     // Apply all styles from the table
1197     for( int nBorder = 0; nBorder < svx::FRAMEBORDERTYPE_COUNT; ++nBorder )
1198     {
1199         svx::FrameBorderType eBorder = svx::GetFrameBorderTypeFromIndex( nBorder );
1200         switch( ppeStates[ nLine ][ nBorder ] )
1201         {
1202             case SHOW:  m_aFrameSel.SelectBorder( eBorder );      break;
1203             case HIDE:  /* nothing to do */                     break;
1204             case DONT:  m_aFrameSel.SetBorderDontCare( eBorder ); break;
1205         }
1206     }
1207 
1208     // Show all lines that have been selected above
1209     if( m_aFrameSel.IsAnyBorderSelected() )
1210     {
1211         // any visible style, but "no-line" in line list box? -> use hair-line
1212         if (m_xLbLineStyle->GetSelectEntryStyle() == SvxBorderLineStyle::NONE)
1213             m_xLbLineStyle->SelectEntry(SvxBorderLineStyle::SOLID);
1214 
1215         // set current style to all previously selected lines
1216         SelStyleHdl_Impl(*m_xLbLineStyle);
1217         SelColHdl_Impl(*m_xLbLineColor);
1218     }
1219 
1220     // Presets ValueSet does not show a selection (used as push buttons).
1221     m_xWndPresets->SetNoSelection();
1222 
1223     LinesChanged_Impl( nullptr );
1224     UpdateRemoveAdjCellBorderCB( nLine + 1 );
1225 }
1226 
1227 IMPL_LINK_NOARG(SvxBorderTabPage, SelSdwHdl_Impl, ValueSet*, void)
1228 {
1229     bool bEnable = m_xWndShadows->GetSelectedItemId() > 1;
1230     m_xFtShadowSize->set_sensitive(bEnable);
1231     m_xEdShadowSize->set_sensitive(bEnable);
1232     m_xFtShadowColor->set_sensitive(bEnable);
1233     m_xLbShadowColor->set_sensitive(bEnable);
1234 }
1235 
1236 IMPL_LINK(SvxBorderTabPage, SelColHdl_Impl, ColorListBox&, rColorBox, void)
1237 {
1238     Color aColor = rColorBox.GetSelectEntryColor();
1239     m_aFrameSel.SetColorToSelection(aColor);
1240 }
1241 
1242 IMPL_LINK_NOARG(SvxBorderTabPage, ModifyWidthLBHdl_Impl, weld::ComboBox&, void)
1243 {
1244     sal_Int32 nPos = m_xLineWidthLB->get_active();
1245 
1246     SetLineWidth(m_aLineWidths[nPos]);
1247 
1248     // Call the spinner handler to trigger all related modifications
1249     ModifyWidthMFHdl_Impl(*m_xLineWidthMF);
1250 }
1251 
1252 IMPL_LINK_NOARG(SvxBorderTabPage, ModifyWidthMFHdl_Impl, weld::MetricSpinButton&, void)
1253 {
1254     sal_Int64 nVal = m_xLineWidthMF->get_value(FieldUnit::NONE);
1255     nVal = static_cast<sal_Int64>(vcl::ConvertDoubleValue(
1256                 nVal,
1257                 m_xLineWidthMF->get_digits(),
1258                 FieldUnit::POINT, MapUnit::MapTwip ));
1259     m_xLbLineStyle->SetWidth( nVal );
1260 
1261     m_aFrameSel.SetStyleToSelection( nVal,
1262         m_xLbLineStyle->GetSelectEntryStyle() );
1263 }
1264 
1265 IMPL_LINK_NOARG(SvxBorderTabPage, SelStyleHdl_Impl, SvtLineListBox&, void)
1266 {
1267     sal_Int64 nOldWidth = m_xLineWidthMF->get_value(FieldUnit::NONE);
1268     nOldWidth = static_cast<sal_Int64>(vcl::ConvertDoubleValue(
1269         nOldWidth,
1270         m_xLineWidthMF->get_digits(),
1271         FieldUnit::POINT,
1272         MapUnit::MapTwip));
1273 
1274     const sal_Int64 nOldMinWidth = lcl_GetMinLineWidth(m_aFrameSel.getCurrentStyleLineStyle());
1275     const sal_Int64 nNewMinWidth = lcl_GetMinLineWidth(m_xLbLineStyle->GetSelectEntryStyle());
1276 
1277     // auto change line-width if it doesn't correspond to minimal value
1278     // let's change only in case when user has not changed the line-width into some custom value
1279     const sal_Int64 nNewWidth = (nOldMinWidth == nOldWidth)? nNewMinWidth : nOldWidth;
1280 
1281     // set value inside edit box
1282     if (nOldWidth != nNewWidth)
1283     {
1284         const sal_Int64 nNewWidthPt = static_cast<sal_Int64>(vcl::ConvertDoubleValue(
1285             nNewWidth,
1286             m_xLineWidthMF->get_digits(),
1287             MapUnit::MapTwip,
1288             FieldUnit::POINT));
1289         SetLineWidth(nNewWidthPt);
1290     }
1291 
1292     // set value inside style box
1293     m_aFrameSel.SetStyleToSelection( nNewWidth,
1294         m_xLbLineStyle->GetSelectEntryStyle() );
1295 }
1296 
1297 
1298 // ValueSet handling
1299 sal_uInt16 SvxBorderTabPage::GetPresetImageId( sal_uInt16 nValueSetIdx ) const
1300 {
1301     // table with all sets of predefined border styles
1302     static const sal_uInt16 ppnImgIds[][ BORDER_PRESET_COUNT ] =
1303     {
1304         // simple cell without diagonal frame borders
1305         {   IID_PRE_CELL_NONE,  IID_PRE_CELL_ALL,       IID_PRE_CELL_LR,        IID_PRE_CELL_TB,    IID_PRE_CELL_L          },
1306         // simple cell with diagonal frame borders
1307         {   IID_PRE_CELL_NONE,  IID_PRE_CELL_ALL,       IID_PRE_CELL_LR,        IID_PRE_CELL_TB,    IID_PRE_CELL_DIAG       },
1308         // with horizontal inner frame border
1309         {   IID_PRE_HOR_NONE,   IID_PRE_HOR_OUTER,      IID_PRE_HOR_HOR,        IID_PRE_HOR_ALL,    IID_PRE_HOR_OUTER2      },
1310         // with vertical inner frame border
1311         {   IID_PRE_VER_NONE,   IID_PRE_VER_OUTER,      IID_PRE_VER_VER,        IID_PRE_VER_ALL,    IID_PRE_VER_OUTER2      },
1312         // with horizontal and vertical inner frame borders
1313         {   IID_PRE_TABLE_NONE, IID_PRE_TABLE_OUTER,    IID_PRE_TABLE_OUTERH,   IID_PRE_TABLE_ALL,  IID_PRE_TABLE_OUTER2    }
1314     };
1315 
1316     // find correct set of presets
1317     int nLine = 0;
1318     if( !mbHorEnabled && !mbVerEnabled )
1319         nLine = (mbTLBREnabled || mbBLTREnabled) ? 1 : 0;
1320     else if( mbHorEnabled && !mbVerEnabled )
1321         nLine = 2;
1322     else if( !mbHorEnabled && mbVerEnabled )
1323         nLine = 3;
1324     else
1325         nLine = 4;
1326 
1327     DBG_ASSERT( (1 <= nValueSetIdx) && (nValueSetIdx <= BORDER_PRESET_COUNT),
1328         "SvxBorderTabPage::GetPresetImageId - wrong index" );
1329     return ppnImgIds[ nLine ][ nValueSetIdx - 1 ];
1330 }
1331 
1332 TranslateId SvxBorderTabPage::GetPresetStringId( sal_uInt16 nValueSetIdx ) const
1333 {
1334     // string resource IDs for each image (in order of the IID_PRE_* image IDs)
1335     static const TranslateId pnStrIds[] =
1336     {
1337         RID_SVXSTR_TABLE_PRESET_NONE,
1338         RID_SVXSTR_PARA_PRESET_ALL,
1339         RID_SVXSTR_PARA_PRESET_LEFTRIGHT,
1340         RID_SVXSTR_PARA_PRESET_TOPBOTTOM,
1341         RID_SVXSTR_PARA_PRESET_ONLYLEFT,
1342         RID_SVXSTR_PARA_PRESET_DIAGONAL,
1343 
1344         RID_SVXSTR_TABLE_PRESET_NONE,
1345         RID_SVXSTR_TABLE_PRESET_ONLYOUTER,
1346         RID_SVXSTR_HOR_PRESET_ONLYHOR,
1347         RID_SVXSTR_TABLE_PRESET_OUTERALL,
1348         RID_SVXSTR_TABLE_PRESET_OUTERINNER,
1349 
1350         RID_SVXSTR_TABLE_PRESET_NONE,
1351         RID_SVXSTR_TABLE_PRESET_ONLYOUTER,
1352         RID_SVXSTR_VER_PRESET_ONLYVER,
1353         RID_SVXSTR_TABLE_PRESET_OUTERALL,
1354         RID_SVXSTR_TABLE_PRESET_OUTERINNER,
1355 
1356         RID_SVXSTR_TABLE_PRESET_NONE,
1357         RID_SVXSTR_TABLE_PRESET_ONLYOUTER,
1358         RID_SVXSTR_TABLE_PRESET_OUTERHORI,
1359         RID_SVXSTR_TABLE_PRESET_OUTERALL,
1360         RID_SVXSTR_TABLE_PRESET_OUTERINNER
1361     };
1362     return pnStrIds[ GetPresetImageId( nValueSetIdx ) - 1 ];
1363 }
1364 
1365 void SvxBorderTabPage::FillPresetVS()
1366 {
1367     // basic initialization of the ValueSet
1368     m_xWndPresets->SetStyle( m_xWndPresets->GetStyle() | WB_ITEMBORDER | WB_DOUBLEBORDER );
1369     m_xWndPresets->SetColCount( BORDER_PRESET_COUNT );
1370 
1371     // insert images and help texts
1372     for( sal_uInt16 nVSIdx = 1; nVSIdx <= BORDER_PRESET_COUNT; ++nVSIdx )
1373     {
1374         m_xWndPresets->InsertItem( nVSIdx );
1375         m_xWndPresets->SetItemImage(nVSIdx, m_aBorderImgVec[GetPresetImageId(nVSIdx) - 1]);
1376         m_xWndPresets->SetItemText( nVSIdx, SvxResId( GetPresetStringId( nVSIdx ) ) );
1377     }
1378 
1379     // show the control
1380     m_xWndPresets->SetNoSelection();
1381     m_xWndPresets->SetOptimalSize();
1382     m_xWndPresets->Show();
1383 }
1384 
1385 void SvxBorderTabPage::FillShadowVS()
1386 {
1387     // basic initialization of the ValueSet
1388     m_xWndShadows->SetStyle( m_xWndShadows->GetStyle() | WB_ITEMBORDER | WB_DOUBLEBORDER );
1389     m_xWndShadows->SetColCount( BORDER_SHADOW_COUNT );
1390 
1391     // string resource IDs for each image
1392     static const TranslateId pnStrIds[ BORDER_SHADOW_COUNT ] =
1393         { RID_CUISTR_SHADOW_STYLE_NONE, RID_CUISTR_SHADOW_STYLE_BOTTOMRIGHT, RID_CUISTR_SHADOW_STYLE_TOPRIGHT, RID_CUISTR_SHADOW_STYLE_BOTTOMLEFT, RID_CUISTR_SHADOW_STYLE_TOPLEFT };
1394 
1395     // insert images and help texts
1396     for( sal_uInt16 nVSIdx = 1; nVSIdx <= BORDER_SHADOW_COUNT; ++nVSIdx )
1397     {
1398         m_xWndShadows->InsertItem( nVSIdx );
1399         m_xWndShadows->SetItemImage(nVSIdx, m_aShadowImgVec[nVSIdx-1]);
1400         m_xWndShadows->SetItemText( nVSIdx, CuiResId( pnStrIds[ nVSIdx - 1 ] ) );
1401     }
1402 
1403     // show the control
1404     m_xWndShadows->SelectItem( 1 );
1405     m_xWndShadows->SetOptimalSize();
1406     m_xWndShadows->Show();
1407 }
1408 
1409 
1410 void SvxBorderTabPage::FillValueSets()
1411 {
1412     FillPresetVS();
1413     FillShadowVS();
1414 }
1415 
1416 void SvxBorderTabPage::SetLineWidth( sal_Int64 nWidth )
1417 {
1418     if ( nWidth >= 0 )
1419         m_xLineWidthMF->set_value( nWidth, FieldUnit::POINT );
1420 
1421     auto it = std::find_if( m_aLineWidths.begin(), m_aLineWidths.end(),
1422                             [nWidth](const int val) -> bool { return val == nWidth; } );
1423 
1424     if ( it != m_aLineWidths.end() && *it >= 0 )
1425     {
1426         // Select predefined value in combobox
1427         m_xLineWidthMF->hide();
1428         m_xLineWidthLB->set_active(std::distance(m_aLineWidths.begin(), it));
1429     }
1430     else
1431     {
1432         // This is not one of predefined values. Show spinner
1433         m_xLineWidthLB->set_active(m_aLineWidths.size()-1);
1434         m_xLineWidthMF->show();
1435     }
1436 }
1437 
1438 static Color lcl_mediumColor( Color aMain, Color /*aDefault*/ )
1439 {
1440     return SvxBorderLine::threeDMediumColor( aMain );
1441 }
1442 
1443 void SvxBorderTabPage::FillLineListBox_Impl()
1444 {
1445     using namespace ::com::sun::star::table::BorderLineStyle;
1446 
1447     static struct {
1448         SvxBorderLineStyle mnStyle;
1449         SvtLineListBox::ColorFunc mpColor1Fn;
1450         SvtLineListBox::ColorFunc mpColor2Fn;
1451         SvtLineListBox::ColorDistFunc mpColorDistFn;
1452     } const aLines[] = {
1453         // Simple lines
1454         { SvxBorderLineStyle::SOLID,        &sameColor, &sameColor, &sameDistColor },
1455         { SvxBorderLineStyle::DOTTED,       &sameColor, &sameColor, &sameDistColor },
1456         { SvxBorderLineStyle::DASHED,       &sameColor, &sameColor, &sameDistColor },
1457         { SvxBorderLineStyle::FINE_DASHED,  &sameColor, &sameColor, &sameDistColor },
1458         { SvxBorderLineStyle::DASH_DOT,     &sameColor, &sameColor, &sameDistColor },
1459         { SvxBorderLineStyle::DASH_DOT_DOT, &sameColor, &sameColor, &sameDistColor },
1460 
1461         // Double lines
1462         { SvxBorderLineStyle::DOUBLE,              &sameColor, &sameColor, &sameDistColor },
1463         { SvxBorderLineStyle::DOUBLE_THIN,         &sameColor, &sameColor, &sameDistColor },
1464         { SvxBorderLineStyle::THINTHICK_SMALLGAP,  &sameColor, &sameColor, &sameDistColor },
1465         { SvxBorderLineStyle::THINTHICK_MEDIUMGAP, &sameColor, &sameColor, &sameDistColor },
1466         { SvxBorderLineStyle::THINTHICK_LARGEGAP,  &sameColor, &sameColor, &sameDistColor },
1467         { SvxBorderLineStyle::THICKTHIN_SMALLGAP,  &sameColor, &sameColor, &sameDistColor },
1468         { SvxBorderLineStyle::THICKTHIN_MEDIUMGAP, &sameColor, &sameColor, &sameDistColor },
1469         { SvxBorderLineStyle::THICKTHIN_LARGEGAP,  &sameColor, &sameColor, &sameDistColor },
1470 
1471         { SvxBorderLineStyle::EMBOSSED, &SvxBorderLine::threeDLightColor, &SvxBorderLine::threeDDarkColor, &lcl_mediumColor },
1472         { SvxBorderLineStyle::ENGRAVED, &SvxBorderLine::threeDDarkColor, &SvxBorderLine::threeDLightColor, &lcl_mediumColor },
1473 
1474         { SvxBorderLineStyle::OUTSET, &SvxBorderLine::lightColor, &SvxBorderLine::darkColor, &sameDistColor },
1475         { SvxBorderLineStyle::INSET,  &SvxBorderLine::darkColor, &SvxBorderLine::lightColor, &sameDistColor }
1476     };
1477 
1478     m_xLbLineStyle->SetSourceUnit( FieldUnit::TWIP );
1479 
1480     for (size_t i = 0; i < std::size(aLines); ++i)
1481     {
1482         if (!IsBorderLineStyleAllowed(aLines[i].mnStyle))
1483             continue;
1484 
1485         m_xLbLineStyle->InsertEntry(
1486             SvxBorderLine::getWidthImpl(aLines[i].mnStyle),
1487             aLines[i].mnStyle,
1488             lcl_GetMinLineWidth(aLines[i].mnStyle),
1489             aLines[i].mpColor1Fn,
1490             aLines[i].mpColor2Fn,
1491             aLines[i].mpColorDistFn);
1492     }
1493 
1494     sal_Int64 nVal = m_xLineWidthMF->get_value(FieldUnit::NONE);
1495     nVal = static_cast<sal_Int64>(vcl::ConvertDoubleValue(nVal, m_xLineWidthMF->get_digits(),
1496                                                                   m_xLineWidthMF->get_unit(), MapUnit::MapTwip));
1497     m_xLbLineStyle->SetWidth( nVal );
1498 }
1499 
1500 
1501 IMPL_LINK_NOARG(SvxBorderTabPage, LinesChanged_Impl, LinkParamNone*, void)
1502 {
1503     if (!mbUseMarginItem && m_xLeftMF->get_visible())
1504     {
1505         bool bLineSet = m_aFrameSel.IsAnyBorderVisible();
1506         bool bSpaceModified =   mbLeftModified ||
1507                                 mbRightModified ||
1508                                 mbTopModified ||
1509                                 mbBottomModified;
1510 
1511         if(bLineSet)
1512         {
1513             if(!bSpaceModified)
1514             {
1515                 m_xLeftMF->set_value(nMinValue, FieldUnit::NONE);
1516                 m_xRightMF->set_value(nMinValue, FieldUnit::NONE);
1517                 m_xTopMF->set_value(nMinValue, FieldUnit::NONE);
1518                 m_xBottomMF->set_value(nMinValue, FieldUnit::NONE);
1519             }
1520         }
1521         else
1522         {
1523             m_xLeftMF->set_min(0, FieldUnit::NONE);
1524             m_xRightMF->set_min(0, FieldUnit::NONE);
1525             m_xTopMF->set_min(0, FieldUnit::NONE);
1526             m_xBottomMF->set_min(0, FieldUnit::NONE);
1527         }
1528         // for tables everything is allowed
1529         SvxBoxInfoItemValidFlags nValid = SvxBoxInfoItemValidFlags::TOP|SvxBoxInfoItemValidFlags::BOTTOM|SvxBoxInfoItemValidFlags::LEFT|SvxBoxInfoItemValidFlags::RIGHT;
1530 
1531         m_xLeftFT->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::LEFT) );
1532         m_xRightFT->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::RIGHT) );
1533         m_xTopFT->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::TOP) );
1534         m_xBottomFT->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::BOTTOM) );
1535         m_xLeftMF->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::LEFT) );
1536         m_xRightMF->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::RIGHT) );
1537         m_xTopMF->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::TOP) );
1538         m_xBottomMF->set_sensitive( bool(nValid & SvxBoxInfoItemValidFlags::BOTTOM) );
1539         m_xSynchronizeCB->set_sensitive(m_xRightMF->get_sensitive() || m_xTopMF->get_sensitive() ||
1540                                         m_xBottomMF->get_sensitive() || m_xLeftMF->get_sensitive());
1541     }
1542     UpdateRemoveAdjCellBorderCB( SAL_MAX_UINT16 );
1543 }
1544 
1545 
1546 IMPL_LINK( SvxBorderTabPage, ModifyDistanceHdl_Impl, weld::MetricSpinButton&, rField, void)
1547 {
1548     if (&rField == m_xLeftMF.get())
1549         mbLeftModified = true;
1550     else if (&rField == m_xRightMF.get())
1551         mbRightModified = true;
1552     else if (&rField == m_xTopMF.get())
1553         mbTopModified = true;
1554     else if (&rField == m_xBottomMF.get())
1555         mbBottomModified = true;
1556 
1557     if (mbSync)
1558     {
1559         const auto nVal = rField.get_value(FieldUnit::NONE);
1560         if (&rField != m_xLeftMF.get())
1561             m_xLeftMF->set_value(nVal, FieldUnit::NONE);
1562         if (&rField != m_xRightMF.get())
1563             m_xRightMF->set_value(nVal, FieldUnit::NONE);
1564         if (&rField != m_xTopMF.get())
1565             m_xTopMF->set_value(nVal, FieldUnit::NONE);
1566         if (&rField != m_xBottomMF.get())
1567             m_xBottomMF->set_value(nVal, FieldUnit::NONE);
1568     }
1569 }
1570 
1571 IMPL_LINK( SvxBorderTabPage, SyncHdl_Impl, weld::Toggleable&, rBox, void)
1572 {
1573     mbSync = rBox.get_active();
1574 }
1575 
1576 IMPL_LINK( SvxBorderTabPage, RemoveAdjacentCellBorderHdl_Impl, weld::Toggleable&, rBox, void)
1577 {
1578     mbRemoveAdjacentCellBorders = rBox.get_active();
1579 }
1580 
1581 void SvxBorderTabPage::UpdateRemoveAdjCellBorderCB( sal_uInt16 nPreset )
1582 {
1583     if( !bIsCalcDoc )
1584         return;
1585     const SfxItemSet&     rOldSet         = GetItemSet();
1586     const SvxBoxInfoItem* pOldBoxInfoItem = GetOldItem( rOldSet, SID_ATTR_BORDER_INNER );
1587     const SvxBoxItem*     pOldBoxItem     = static_cast<const SvxBoxItem*>(GetOldItem( rOldSet, mnBoxSlot ));
1588     if( !pOldBoxInfoItem || !pOldBoxItem )
1589         return;
1590     std::pair<svx::FrameBorderType, SvxBoxInfoItemValidFlags> eTypes1[] = {
1591         { svx::FrameBorderType::Top,SvxBoxInfoItemValidFlags::TOP },
1592         { svx::FrameBorderType::Bottom,SvxBoxInfoItemValidFlags::BOTTOM },
1593         { svx::FrameBorderType::Left,SvxBoxInfoItemValidFlags::LEFT },
1594         { svx::FrameBorderType::Right,SvxBoxInfoItemValidFlags::RIGHT },
1595     };
1596     SvxBoxItemLine const eTypes2[] = {
1597         SvxBoxItemLine::TOP,
1598         SvxBoxItemLine::BOTTOM,
1599         SvxBoxItemLine::LEFT,
1600         SvxBoxItemLine::RIGHT,
1601     };
1602 
1603     // Check if current selection involves deletion of at least one border
1604     bool bBorderDeletionReq = false;
1605     for ( size_t i=0; i < std::size( eTypes1 ); ++i )
1606     {
1607         if( pOldBoxItem->GetLine( eTypes2[i] ) || !( pOldBoxInfoItem->IsValid( eTypes1[i].second ) ) )
1608         {
1609             if( m_aFrameSel.GetFrameBorderState( eTypes1[i].first ) == svx::FrameBorderState::Hide )
1610             {
1611                 bBorderDeletionReq = true;
1612                 break;
1613             }
1614         }
1615     }
1616 
1617     if( !bBorderDeletionReq && ( nPreset == IID_PRE_CELL_NONE || nPreset == IID_PRE_TABLE_NONE ) )
1618         bBorderDeletionReq = true;
1619 
1620     m_xRemoveAdjacentCellBordersCB->set_sensitive(bBorderDeletionReq);
1621 
1622     if( !bBorderDeletionReq )
1623     {
1624         mbRemoveAdjacentCellBorders = false;
1625         m_xRemoveAdjacentCellBordersCB->set_active(false);
1626     }
1627 }
1628 
1629 void SvxBorderTabPage::PageCreated(const SfxAllItemSet& aSet)
1630 {
1631     const SfxUInt16Item* pSWModeItem = aSet.GetItem<SfxUInt16Item>(SID_SWMODE_TYPE, false);
1632     const SfxUInt32Item* pFlagItem = aSet.GetItem<SfxUInt32Item>(SID_FLAG_TYPE, false);
1633     if (pSWModeItem)
1634     {
1635         nSWMode = static_cast<SwBorderModes>(pSWModeItem->GetValue());
1636         // #i43593#
1637         // show checkbox <m_xMergeWithNextCB> for format.paragraph
1638         if ( nSWMode == SwBorderModes::PARA )
1639         {
1640             m_xMergeWithNextCB->show();
1641             m_xPropertiesFrame->show();
1642         }
1643         // show checkbox <m_xMergeAdjacentBordersCB> for format.paragraph
1644         else if ( nSWMode == SwBorderModes::TABLE )
1645         {
1646             m_xMergeAdjacentBordersCB->show();
1647             m_xPropertiesFrame->show();
1648         }
1649     }
1650     if (pFlagItem)
1651         if ( ( pFlagItem->GetValue() & SVX_HIDESHADOWCTL ) == SVX_HIDESHADOWCTL )
1652             HideShadowControls();
1653 }
1654 
1655 void SvxBorderTabPage::SetTableMode()
1656 {
1657     nSWMode = SwBorderModes::TABLE;
1658 }
1659 
1660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1661