xref: /core/cui/source/tabpages/numpages.cxx (revision 71001798)
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 <com/sun/star/text/VertOrientation.hpp>
21 
22 #include <numpages.hxx>
23 #include <dialmgr.hxx>
24 #include <tools/mapunit.hxx>
25 #include <i18nlangtag/languagetag.hxx>
26 #include <i18nlangtag/mslangid.hxx>
27 #include <editeng/numitem.hxx>
28 #include <svl/eitem.hxx>
29 #include <vcl/svapp.hxx>
30 #include <svx/colorbox.hxx>
31 #include <svx/dlgutil.hxx>
32 #include <svx/strarray.hxx>
33 #include <svx/gallery.hxx>
34 #include <editeng/brushitem.hxx>
35 #include <svl/intitem.hxx>
36 #include <sfx2/objsh.hxx>
37 #include <vcl/graph.hxx>
38 #include <vcl/settings.hxx>
39 #include <cui/cuicharmap.hxx>
40 #include <editeng/flstitem.hxx>
41 #include <svx/numvset.hxx>
42 #include <sfx2/htmlmode.hxx>
43 #include <unotools/pathoptions.hxx>
44 #include <svtools/ctrltool.hxx>
45 #include <svtools/unitconv.hxx>
46 #include <com/sun/star/style/NumberingType.hpp>
47 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
48 #include <com/sun/star/container/XIndexAccess.hpp>
49 #include <com/sun/star/text/XDefaultNumberingProvider.hpp>
50 #include <com/sun/star/text/XNumberingFormatter.hpp>
51 #include <com/sun/star/beans/PropertyValue.hpp>
52 #include <comphelper/processfactory.hxx>
53 #include <comphelper/propertyvalue.hxx>
54 #include <svx/svxids.hrc>
55 #include <o3tl/string_view.hxx>
56 
57 #include <algorithm>
58 #include <memory>
59 #include <vector>
60 #include <sfx2/opengrf.hxx>
61 
62 #include <strings.hrc>
63 #include <svl/stritem.hxx>
64 #include <svl/slstitm.hxx>
65 #include <sfx2/filedlghelper.hxx>
66 #include <unotools/ucbstreamhelper.hxx>
67 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
68 #include <sal/log.hxx>
69 #include <vcl/cvtgrf.hxx>
70 #include <vcl/graphicfilter.hxx>
71 #include <svx/SvxNumOptionsTabPageHelper.hxx>
72 #include <tools/urlobj.hxx>
73 #include <o3tl/temporary.hxx>
74 #include <osl/diagnose.h>
75 
76 using namespace css;
77 using namespace css::uno;
78 using namespace css::beans;
79 using namespace css::lang;
80 using namespace css::text;
81 using namespace css::container;
82 using namespace css::style;
83 
84 #define SHOW_NUMBERING              0
85 #define SHOW_BULLET                 1
86 #define SHOW_BITMAP                 2
87 
88 #define MAX_BMP_WIDTH               16
89 #define MAX_BMP_HEIGHT              16
90 #define SEARCHPATH_DELIMITER        u';'
91 #define SEARCHFILENAME_DELIMITER    u'/'
92 
93 static bool bLastRelative =         false;
94 
95 static SvxNumSettings_Impl* lcl_CreateNumSettingsPtr(const Sequence<PropertyValue>& rLevelProps)
96 {
97     const PropertyValue* pValues = rLevelProps.getConstArray();
98     SvxNumSettings_Impl* pNew = new SvxNumSettings_Impl;
99     for(sal_Int32 j = 0; j < rLevelProps.getLength(); j++)
100     {
101         if ( pValues[j].Name == "NumberingType" )
102         {
103             sal_Int16 nTmp;
104             if (pValues[j].Value >>= nTmp)
105                 pNew->nNumberType = static_cast<SvxNumType>(nTmp);
106         }
107         else if ( pValues[j].Name == "Prefix" )
108             pValues[j].Value >>= pNew->sPrefix;
109         else if ( pValues[j].Name == "Suffix" )
110             pValues[j].Value >>= pNew->sSuffix;
111         else if ( pValues[j].Name == "ParentNumbering" )
112             pValues[j].Value >>= pNew->nParentNumbering;
113         else if ( pValues[j].Name == "BulletChar" )
114             pValues[j].Value >>= pNew->sBulletChar;
115         else if ( pValues[j].Name == "BulletFontName" )
116             pValues[j].Value >>= pNew->sBulletFont;
117     }
118     return pNew;
119 }
120 
121 // the selection of bullets from the OpenSymbol
122 const sal_Unicode aBulletTypes[] =
123 {
124     0x2022,
125     0x25cf,
126     0xe00c,
127     0xe00a,
128     0x2794,
129     0x27a2,
130     0x2717,
131     0x2714
132 };
133 
134 // Is one of the masked formats set?
135 static bool lcl_IsNumFmtSet(SvxNumRule const * pNum, sal_uInt16 nLevelMask)
136 {
137     bool bRet = false;
138     sal_uInt16 nMask = 1;
139     for( sal_uInt16 i = 0; i < SVX_MAX_NUM && !bRet; i++ )
140     {
141         if(nLevelMask & nMask)
142             bRet |= nullptr != pNum->Get( i );
143         nMask <<= 1 ;
144     }
145     return bRet;
146 }
147 
148 static const vcl::Font& lcl_GetDefaultBulletFont()
149 {
150     static vcl::Font aDefBulletFont = []()
151     {
152         vcl::Font tmp("OpenSymbol", "", Size(0, 14));
153         tmp.SetCharSet( RTL_TEXTENCODING_SYMBOL );
154         tmp.SetFamily( FAMILY_DONTKNOW );
155         tmp.SetPitch( PITCH_DONTKNOW );
156         tmp.SetWeight( WEIGHT_DONTKNOW );
157         tmp.SetTransparent( true );
158         return tmp;
159     }();
160     return aDefBulletFont;
161 }
162 
163 SvxSingleNumPickTabPage::SvxSingleNumPickTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
164     : SfxTabPage(pPage, pController, "cui/ui/picknumberingpage.ui", "PickNumberingPage", &rSet)
165     , nActNumLvl(SAL_MAX_UINT16)
166     , bModified(false)
167     , bPreset(false)
168     , nNumItemId(SID_ATTR_NUMBERING_RULE)
169     , m_xExamplesVS(new SvxNumValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
170     , m_xExamplesVSWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xExamplesVS))
171 {
172     SetExchangeSupport();
173     m_xExamplesVS->init(NumberingPageType::SINGLENUM);
174     m_xExamplesVS->SetSelectHdl(LINK(this, SvxSingleNumPickTabPage, NumSelectHdl_Impl));
175     m_xExamplesVS->SetDoubleClickHdl(LINK(this, SvxSingleNumPickTabPage, DoubleClickHdl_Impl));
176 
177     Reference<XDefaultNumberingProvider> xDefNum = SvxNumOptionsTabPageHelper::GetNumberingProvider();
178     if(!xDefNum.is())
179         return;
180 
181     Sequence< Sequence< PropertyValue > > aNumberings;
182     const Locale& rLocale = Application::GetSettings().GetLanguageTag().getLocale();
183     try
184     {
185         aNumberings =
186             xDefNum->getDefaultContinuousNumberingLevels( rLocale );
187 
188 
189         sal_Int32 nLength = std::min<sal_Int32>(aNumberings.getLength(), NUM_VALUSET_COUNT);
190 
191         const Sequence<PropertyValue>* pValuesArr = aNumberings.getConstArray();
192         for(sal_Int32 i = 0; i < nLength; i++)
193         {
194             SvxNumSettings_Impl* pNew = lcl_CreateNumSettingsPtr(pValuesArr[i]);
195             aNumSettingsArr.push_back(std::unique_ptr<SvxNumSettings_Impl>(pNew));
196         }
197     }
198     catch(const Exception&)
199     {
200     }
201     Reference<XNumberingFormatter> xFormat(xDefNum, UNO_QUERY);
202     m_xExamplesVS->SetNumberingSettings(aNumberings, xFormat, rLocale);
203 }
204 
205 SvxSingleNumPickTabPage::~SvxSingleNumPickTabPage()
206 {
207     m_xExamplesVSWin.reset();
208     m_xExamplesVS.reset();
209 }
210 
211 std::unique_ptr<SfxTabPage> SvxSingleNumPickTabPage::Create(weld::Container* pPage, weld::DialogController* pController,
212                                                    const SfxItemSet* rAttrSet)
213 {
214     return std::make_unique<SvxSingleNumPickTabPage>(pPage, pController, *rAttrSet);
215 }
216 
217 bool  SvxSingleNumPickTabPage::FillItemSet( SfxItemSet* rSet )
218 {
219     if( (bPreset || bModified) && pSaveNum)
220     {
221         *pSaveNum = *pActNum;
222         rSet->Put(SvxNumBulletItem( *pSaveNum, nNumItemId ));
223         rSet->Put(SfxBoolItem(SID_PARAM_NUM_PRESET, bPreset));
224     }
225 
226     return bModified;
227 }
228 
229 void  SvxSingleNumPickTabPage::ActivatePage(const SfxItemSet& rSet)
230 {
231     bPreset = false;
232     bool bIsPreset = false;
233     const SfxItemSet* pExampleSet = GetDialogExampleSet();
234     if(pExampleSet)
235     {
236         if(const SfxBoolItem* pPresetItem = pExampleSet->GetItemIfSet(SID_PARAM_NUM_PRESET, false))
237             bIsPreset = pPresetItem->GetValue();
238         if(const SfxUInt16Item* pLevelItem = pExampleSet->GetItemIfSet(SID_PARAM_CUR_NUM_LEVEL, false))
239             nActNumLvl = pLevelItem->GetValue();
240     }
241     if(const SvxNumBulletItem* pNumItem = rSet.GetItemIfSet(nNumItemId, false))
242     {
243         pSaveNum.reset( new SvxNumRule(pNumItem->GetNumRule()) );
244     }
245     if(pActNum && *pSaveNum != *pActNum)
246     {
247         *pActNum = *pSaveNum;
248         m_xExamplesVS->SetNoSelection();
249     }
250 
251     if(pActNum && (!lcl_IsNumFmtSet(pActNum.get(), nActNumLvl) || bIsPreset))
252     {
253         m_xExamplesVS->SelectItem(1);
254         NumSelectHdl_Impl(m_xExamplesVS.get());
255         bPreset = true;
256     }
257     bPreset |= bIsPreset;
258 
259     bModified = false;
260 }
261 
262 DeactivateRC SvxSingleNumPickTabPage::DeactivatePage(SfxItemSet *_pSet)
263 {
264     if(_pSet)
265         FillItemSet(_pSet);
266     return DeactivateRC::LeavePage;
267 }
268 
269 void  SvxSingleNumPickTabPage::Reset( const SfxItemSet* rSet )
270 {
271     const SfxPoolItem* pItem;
272 
273     // in Draw the item exists as WhichId, in Writer only as SlotId
274     SfxItemState eState = rSet->GetItemState(SID_ATTR_NUMBERING_RULE, false, &pItem);
275     if(eState != SfxItemState::SET)
276     {
277         nNumItemId = rSet->GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE);
278         eState = rSet->GetItemState(nNumItemId, false, &pItem);
279 
280         if( eState != SfxItemState::SET )
281         {
282             pItem = & rSet->Get( nNumItemId );
283             eState = SfxItemState::SET;
284         }
285     }
286     DBG_ASSERT(eState == SfxItemState::SET, "no item found!");
287     pSaveNum.reset( new SvxNumRule(static_cast<const SvxNumBulletItem*>(pItem)->GetNumRule()) );
288 
289     if(!pActNum)
290         pActNum.reset( new SvxNumRule(*pSaveNum) );
291     else if(*pSaveNum != *pActNum)
292         *pActNum = *pSaveNum;
293 }
294 
295 IMPL_LINK_NOARG(SvxSingleNumPickTabPage, NumSelectHdl_Impl, ValueSet*, void)
296 {
297     if(!pActNum)
298         return;
299 
300     bPreset = false;
301     bModified = true;
302     sal_uInt16 nIdx = m_xExamplesVS->GetSelectedItemId() - 1;
303     DBG_ASSERT(aNumSettingsArr.size() > nIdx, "wrong index");
304     if(aNumSettingsArr.size() <= nIdx)
305         return;
306     SvxNumSettings_Impl* _pSet = aNumSettingsArr[nIdx].get();
307     SvxNumType eNewType = _pSet->nNumberType;
308     const sal_Unicode cLocalPrefix = !_pSet->sPrefix.isEmpty() ? _pSet->sPrefix[0] : 0;
309     const sal_Unicode cLocalSuffix = !_pSet->sSuffix.isEmpty() ? _pSet->sSuffix[0] : 0;
310 
311     sal_uInt16 nMask = 1;
312     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
313     {
314         if(nActNumLvl & nMask)
315         {
316             SvxNumberFormat aFmt(pActNum->GetLevel(i));
317             aFmt.SetNumberingType(eNewType);
318             aFmt.SetListFormat(cLocalPrefix == ' ' ? "" : _pSet->sPrefix,
319                                cLocalSuffix == ' ' ? "" : _pSet->sSuffix, i);
320             aFmt.SetCharFormatName("");
321             aFmt.SetBulletRelSize(100);
322             pActNum->SetLevel(i, aFmt);
323         }
324         nMask <<= 1;
325     }
326 }
327 
328 IMPL_LINK_NOARG(SvxSingleNumPickTabPage, DoubleClickHdl_Impl, ValueSet*, void)
329 {
330     NumSelectHdl_Impl(m_xExamplesVS.get());
331     weld::Button& rOk = GetDialogController()->GetOKButton();
332     rOk.clicked();
333 }
334 
335 SvxBulletPickTabPage::SvxBulletPickTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
336     : SfxTabPage(pPage, pController, "cui/ui/pickbulletpage.ui", "PickBulletPage", &rSet)
337     , nActNumLvl(SAL_MAX_UINT16)
338     , bModified(false)
339     , bPreset(false)
340     , nNumItemId(SID_ATTR_NUMBERING_RULE)
341     , m_xExamplesVS(new SvxNumValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
342     , m_xExamplesVSWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xExamplesVS))
343 {
344     SetExchangeSupport();
345     m_xExamplesVS->init(NumberingPageType::BULLET);
346     m_xExamplesVS->SetSelectHdl(LINK(this, SvxBulletPickTabPage, NumSelectHdl_Impl));
347     m_xExamplesVS->SetDoubleClickHdl(LINK(this, SvxBulletPickTabPage, DoubleClickHdl_Impl));
348 }
349 
350 SvxBulletPickTabPage::~SvxBulletPickTabPage()
351 {
352     m_xExamplesVSWin.reset();
353     m_xExamplesVS.reset();
354 }
355 
356 std::unique_ptr<SfxTabPage> SvxBulletPickTabPage::Create(weld::Container* pPage, weld::DialogController* pController,
357                                                 const SfxItemSet* rAttrSet)
358 {
359     return std::make_unique<SvxBulletPickTabPage>(pPage, pController, *rAttrSet);
360 }
361 
362 bool  SvxBulletPickTabPage::FillItemSet( SfxItemSet* rSet )
363 {
364     if( (bPreset || bModified) && pActNum)
365     {
366         *pSaveNum = *pActNum;
367         rSet->Put(SvxNumBulletItem( *pSaveNum, nNumItemId ));
368         rSet->Put(SfxBoolItem(SID_PARAM_NUM_PRESET, bPreset));
369     }
370     return bModified;
371 }
372 
373 void  SvxBulletPickTabPage::ActivatePage(const SfxItemSet& rSet)
374 {
375     bPreset = false;
376     bool bIsPreset = false;
377     const SfxItemSet* pExampleSet = GetDialogExampleSet();
378     if(pExampleSet)
379     {
380         if(const SfxBoolItem* pPresetItem = pExampleSet->GetItemIfSet(SID_PARAM_NUM_PRESET, false))
381             bIsPreset = pPresetItem->GetValue();
382         if(const SfxUInt16Item* pLevelItem = pExampleSet->GetItemIfSet(SID_PARAM_CUR_NUM_LEVEL, false))
383             nActNumLvl = pLevelItem->GetValue();
384     }
385     if(const SvxNumBulletItem* pBulletItem = rSet.GetItemIfSet(nNumItemId, false))
386     {
387         pSaveNum.reset( new SvxNumRule(pBulletItem->GetNumRule()) );
388     }
389     if(pActNum && *pSaveNum != *pActNum)
390     {
391         *pActNum = *pSaveNum;
392         m_xExamplesVS->SetNoSelection();
393     }
394 
395     if(pActNum && (!lcl_IsNumFmtSet(pActNum.get(), nActNumLvl) || bIsPreset))
396     {
397         m_xExamplesVS->SelectItem(1);
398         NumSelectHdl_Impl(m_xExamplesVS.get());
399         bPreset = true;
400     }
401     bPreset |= bIsPreset;
402     bModified = false;
403 }
404 
405 DeactivateRC SvxBulletPickTabPage::DeactivatePage(SfxItemSet *_pSet)
406 {
407     if(_pSet)
408         FillItemSet(_pSet);
409     return DeactivateRC::LeavePage;
410 }
411 
412 void  SvxBulletPickTabPage::Reset( const SfxItemSet* rSet )
413 {
414     // in Draw the item exists as WhichId, in Writer only as SlotId
415     const SvxNumBulletItem* pItem = rSet->GetItemIfSet(SID_ATTR_NUMBERING_RULE, false);
416     if(!pItem)
417     {
418         nNumItemId = rSet->GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE);
419         pItem = rSet->GetItemIfSet(nNumItemId, false);
420 
421         if( !pItem )
422         {
423             pItem = & rSet->Get( nNumItemId );
424         }
425 
426     }
427     pSaveNum.reset( new SvxNumRule(pItem->GetNumRule()) );
428 
429     if(!pActNum)
430         pActNum.reset( new SvxNumRule(*pSaveNum) );
431     else if(*pSaveNum != *pActNum)
432         *pActNum = *pSaveNum;
433 }
434 
435 IMPL_LINK_NOARG(SvxBulletPickTabPage, NumSelectHdl_Impl, ValueSet*, void)
436 {
437     if(!pActNum)
438         return;
439 
440     bPreset = false;
441     bModified = true;
442     sal_Unicode cChar = aBulletTypes[m_xExamplesVS->GetSelectedItemId() - 1];
443     const vcl::Font& rActBulletFont = lcl_GetDefaultBulletFont();
444 
445     sal_uInt16 nMask = 1;
446     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
447     {
448         if(nActNumLvl & nMask)
449         {
450             SvxNumberFormat aFmt(pActNum->GetLevel(i));
451             aFmt.SetNumberingType( SVX_NUM_CHAR_SPECIAL );
452             // #i93908# clear suffix for bullet lists
453             aFmt.SetListFormat("", "", i);
454             aFmt.SetBulletFont(&rActBulletFont);
455             aFmt.SetBulletChar(cChar );
456             aFmt.SetCharFormatName(sBulletCharFormatName);
457             aFmt.SetBulletRelSize(45);
458             pActNum->SetLevel(i, aFmt);
459         }
460         nMask <<= 1;
461     }
462 }
463 
464 IMPL_LINK_NOARG(SvxBulletPickTabPage, DoubleClickHdl_Impl, ValueSet*, void)
465 {
466     NumSelectHdl_Impl(m_xExamplesVS.get());
467     weld::Button& rOk = GetDialogController()->GetOKButton();
468     rOk.clicked();
469 }
470 
471 void SvxBulletPickTabPage::PageCreated(const SfxAllItemSet& aSet)
472 {
473     const SfxStringItem* pBulletCharFmt = aSet.GetItem<SfxStringItem>(SID_BULLET_CHAR_FMT, false);
474 
475     if (pBulletCharFmt)
476         sBulletCharFormatName = pBulletCharFmt->GetValue();
477 }
478 
479 SvxNumPickTabPage::SvxNumPickTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
480     : SfxTabPage(pPage, pController, "cui/ui/pickoutlinepage.ui", "PickOutlinePage", &rSet)
481     , nActNumLvl(SAL_MAX_UINT16)
482     , nNumItemId(SID_ATTR_NUMBERING_RULE)
483     , bModified(false)
484     , bPreset(false)
485     , m_xExamplesVS(new SvxNumValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
486     , m_xExamplesVSWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xExamplesVS))
487 {
488     SetExchangeSupport();
489 
490     m_xExamplesVS->init(NumberingPageType::OUTLINE);
491     m_xExamplesVS->SetSelectHdl(LINK(this, SvxNumPickTabPage, NumSelectHdl_Impl));
492     m_xExamplesVS->SetDoubleClickHdl(LINK(this, SvxNumPickTabPage, DoubleClickHdl_Impl));
493 
494     Reference<XDefaultNumberingProvider> xDefNum = SvxNumOptionsTabPageHelper::GetNumberingProvider();
495     if(!xDefNum.is())
496         return;
497 
498     Sequence<Reference<XIndexAccess> > aOutlineAccess;
499     const Locale& rLocale = Application::GetSettings().GetLanguageTag().getLocale();
500     try
501     {
502         aOutlineAccess = xDefNum->getDefaultOutlineNumberings( rLocale );
503 
504         for(sal_Int32 nItem = 0;
505             nItem < aOutlineAccess.getLength() && nItem < NUM_VALUSET_COUNT;
506             nItem++ )
507         {
508             SvxNumSettingsArr_Impl& rItemArr = aNumSettingsArrays[ nItem ];
509 
510             Reference<XIndexAccess> xLevel = aOutlineAccess.getConstArray()[nItem];
511             for(sal_Int32 nLevel = 0; nLevel < SVX_MAX_NUM; nLevel++)
512             {
513                 // use the last locale-defined level for all remaining levels.
514                 sal_Int32 nLocaleLevel = std::min(nLevel, xLevel->getCount() - 1);
515                 Sequence<PropertyValue> aLevelProps;
516                 if (nLocaleLevel >= 0)
517                     xLevel->getByIndex(nLocaleLevel) >>= aLevelProps;
518 
519                 SvxNumSettings_Impl* pNew = lcl_CreateNumSettingsPtr(aLevelProps);
520                 rItemArr.push_back( std::unique_ptr<SvxNumSettings_Impl>(pNew) );
521             }
522         }
523     }
524     catch(const Exception&)
525     {
526     }
527     Reference<XNumberingFormatter> xFormat(xDefNum, UNO_QUERY);
528     m_xExamplesVS->SetOutlineNumberingSettings(aOutlineAccess, xFormat, rLocale);
529 }
530 
531 SvxNumPickTabPage::~SvxNumPickTabPage()
532 {
533     m_xExamplesVSWin.reset();
534     m_xExamplesVS.reset();
535 }
536 
537 std::unique_ptr<SfxTabPage> SvxNumPickTabPage::Create(weld::Container* pPage, weld::DialogController* pController,
538                                              const SfxItemSet* rAttrSet)
539 {
540     return std::make_unique<SvxNumPickTabPage>(pPage, pController, *rAttrSet);
541 }
542 
543 bool  SvxNumPickTabPage::FillItemSet( SfxItemSet* rSet )
544 {
545     if( (bPreset || bModified) && pActNum)
546     {
547         *pSaveNum = *pActNum;
548         rSet->Put(SvxNumBulletItem( *pSaveNum, nNumItemId ));
549         rSet->Put(SfxBoolItem(SID_PARAM_NUM_PRESET, bPreset));
550     }
551     return bModified;
552 }
553 
554 void  SvxNumPickTabPage::ActivatePage(const SfxItemSet& rSet)
555 {
556     bPreset = false;
557     bool bIsPreset = false;
558     const SfxItemSet* pExampleSet = GetDialogExampleSet();
559     if(pExampleSet)
560     {
561         if(const SfxBoolItem* pPresetItem = pExampleSet->GetItemIfSet(SID_PARAM_NUM_PRESET, false))
562             bIsPreset = pPresetItem->GetValue();
563         if(const SfxUInt16Item* pLevelItem = pExampleSet->GetItemIfSet(SID_PARAM_CUR_NUM_LEVEL, false))
564             nActNumLvl = pLevelItem->GetValue();
565     }
566     if(const SvxNumBulletItem* pBulletItem = rSet.GetItemIfSet(nNumItemId, false))
567     {
568         pSaveNum.reset( new SvxNumRule(pBulletItem->GetNumRule()) );
569     }
570     if(pActNum && *pSaveNum != *pActNum)
571     {
572         *pActNum = *pSaveNum;
573         m_xExamplesVS->SetNoSelection();
574     }
575 
576     if(pActNum && (!lcl_IsNumFmtSet(pActNum.get(), nActNumLvl) || bIsPreset))
577     {
578         m_xExamplesVS->SelectItem(1);
579         NumSelectHdl_Impl(m_xExamplesVS.get());
580         bPreset = true;
581     }
582     bPreset |= bIsPreset;
583     bModified = false;
584 }
585 
586 DeactivateRC SvxNumPickTabPage::DeactivatePage(SfxItemSet *_pSet)
587 {
588     if(_pSet)
589         FillItemSet(_pSet);
590     return DeactivateRC::LeavePage;
591 }
592 
593 void  SvxNumPickTabPage::Reset( const SfxItemSet* rSet )
594 {
595     // in Draw the item exists as WhichId, in Writer only as SlotId
596     const SvxNumBulletItem* pItem = rSet->GetItemIfSet(SID_ATTR_NUMBERING_RULE, false);
597     if(!pItem)
598     {
599         nNumItemId = rSet->GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE);
600         pItem = rSet->GetItemIfSet(nNumItemId, false);
601 
602         if( !pItem )
603         {
604             pItem = & rSet->Get( nNumItemId );
605         }
606     }
607     pSaveNum.reset( new SvxNumRule(pItem->GetNumRule()) );
608 
609     if(!pActNum)
610         pActNum.reset( new SvxNumRule(*pSaveNum) );
611     else if(*pSaveNum != *pActNum)
612         *pActNum = *pSaveNum;
613 
614 }
615 
616 // all levels are changed here
617 IMPL_LINK_NOARG(SvxNumPickTabPage, NumSelectHdl_Impl, ValueSet*, void)
618 {
619     if(!pActNum)
620         return;
621 
622     bPreset = false;
623     bModified = true;
624 
625     const FontList*  pList = nullptr;
626 
627     SvxNumSettingsArr_Impl& rItemArr = aNumSettingsArrays[m_xExamplesVS->GetSelectedItemId() - 1];
628 
629     const vcl::Font& rActBulletFont = lcl_GetDefaultBulletFont();
630     SvxNumSettings_Impl* pLevelSettings = nullptr;
631     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
632     {
633         if(rItemArr.size() > i)
634             pLevelSettings = rItemArr[i].get();
635         if(!pLevelSettings)
636             break;
637         SvxNumberFormat aFmt(pActNum->GetLevel(i));
638         aFmt.SetNumberingType( pLevelSettings->nNumberType );
639         sal_uInt16 nUpperLevelOrChar = static_cast<sal_uInt16>(pLevelSettings->nParentNumbering);
640         if(aFmt.GetNumberingType() == SVX_NUM_CHAR_SPECIAL)
641         {
642             // #i93908# clear suffix for bullet lists
643             aFmt.SetListFormat("", "", i);
644             if( !pLevelSettings->sBulletFont.isEmpty() &&
645                 pLevelSettings->sBulletFont != rActBulletFont.GetFamilyName())
646             {
647                 //search for the font
648                 if(!pList)
649                 {
650                     if (SfxObjectShell* pCurDocShell = SfxObjectShell::Current())
651                     {
652                         const SvxFontListItem* pFontListItem =
653                                 static_cast<const SvxFontListItem*>( pCurDocShell
654                                                     ->GetItem( SID_ATTR_CHAR_FONTLIST ));
655                         pList = pFontListItem ? pFontListItem->GetFontList() : nullptr;
656                     }
657                 }
658                 if(pList && pList->IsAvailable( pLevelSettings->sBulletFont ) )
659                 {
660                     FontMetric aFontMetric = pList->Get(
661                         pLevelSettings->sBulletFont,WEIGHT_NORMAL, ITALIC_NONE);
662                     vcl::Font aFont(aFontMetric);
663                     aFmt.SetBulletFont(&aFont);
664                 }
665                 else
666                 {
667                     //if it cannot be found then create a new one
668                     vcl::Font aCreateFont( pLevelSettings->sBulletFont,
669                                             OUString(), Size( 0, 14 ) );
670                     aCreateFont.SetCharSet( RTL_TEXTENCODING_DONTKNOW );
671                     aCreateFont.SetFamily( FAMILY_DONTKNOW );
672                     aCreateFont.SetPitch( PITCH_DONTKNOW );
673                     aCreateFont.SetWeight( WEIGHT_DONTKNOW );
674                     aCreateFont.SetTransparent( true );
675                     aFmt.SetBulletFont( &aCreateFont );
676                 }
677             }
678             else
679                 aFmt.SetBulletFont( &rActBulletFont );
680 
681             aFmt.SetBulletChar( !pLevelSettings->sBulletChar.isEmpty()
682                                     ? pLevelSettings->sBulletChar.iterateCodePoints(
683                                         &o3tl::temporary(sal_Int32(0)))
684                                     : 0 );
685             aFmt.SetCharFormatName( sBulletCharFormatName );
686             aFmt.SetBulletRelSize(45);
687         }
688         else
689         {
690             aFmt.SetIncludeUpperLevels(sal::static_int_cast< sal_uInt8 >(0 != nUpperLevelOrChar ? pActNum->GetLevelCount() : 1));
691             aFmt.SetCharFormatName(sNumCharFmtName);
692             aFmt.SetBulletRelSize(100);
693 
694             // Completely ignore the Left/Right value provided by the locale outline definition,
695             // because this function doesn't actually modify the indents at all,
696             // and right-adjusted numbering definitely needs a different FirstLineIndent.
697 
698             // #i93908#
699             aFmt.SetListFormat(pLevelSettings->sPrefix, pLevelSettings->sSuffix, i);
700         }
701         pActNum->SetLevel(i, aFmt);
702     }
703 }
704 
705 IMPL_LINK_NOARG(SvxNumPickTabPage, DoubleClickHdl_Impl, ValueSet*, void)
706 {
707     NumSelectHdl_Impl(m_xExamplesVS.get());
708     weld::Button& rOk = GetDialogController()->GetOKButton();
709     rOk.clicked();
710 }
711 
712 void SvxNumPickTabPage::PageCreated(const SfxAllItemSet& aSet)
713 {
714     const SfxStringItem* pNumCharFmt = aSet.GetItem<SfxStringItem>(SID_NUM_CHAR_FMT, false);
715     const SfxStringItem* pBulletCharFmt = aSet.GetItem<SfxStringItem>(SID_BULLET_CHAR_FMT, false);
716 
717 
718     if (pNumCharFmt &&pBulletCharFmt)
719         SetCharFormatNames( pNumCharFmt->GetValue(),pBulletCharFmt->GetValue());
720 }
721 
722 SvxBitmapPickTabPage::SvxBitmapPickTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
723     : SfxTabPage(pPage, pController, "cui/ui/pickgraphicpage.ui", "PickGraphicPage", &rSet)
724     , nActNumLvl(SAL_MAX_UINT16)
725     , nNumItemId(SID_ATTR_NUMBERING_RULE)
726     , bModified(false)
727     , bPreset(false)
728     , m_xErrorText(m_xBuilder->weld_label("errorft"))
729     , m_xBtBrowseFile(m_xBuilder->weld_button("browseBtn"))
730     , m_xExamplesVS(new SvxBmpNumValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
731     , m_xExamplesVSWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xExamplesVS))
732 {
733     SetExchangeSupport();
734 
735     m_xExamplesVS->init();
736     m_xExamplesVS->SetSelectHdl(LINK(this, SvxBitmapPickTabPage, NumSelectHdl_Impl));
737     m_xExamplesVS->SetDoubleClickHdl(LINK(this, SvxBitmapPickTabPage, DoubleClickHdl_Impl));
738     m_xBtBrowseFile->connect_clicked(LINK(this, SvxBitmapPickTabPage, ClickAddBrowseHdl_Impl));
739 
740     eCoreUnit = rSet.GetPool()->GetMetric(rSet.GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE));
741 
742     // determine graphic name
743     GalleryExplorer::FillObjList(GALLERY_THEME_BULLETS, aGrfNames);
744 
745     size_t i = 0;
746     for (auto & grfName : aGrfNames)
747     {
748         m_xExamplesVS->InsertItem( i + 1, i);
749 
750         INetURLObject aObj(grfName);
751         if (aObj.GetProtocol() == INetProtocol::File)
752         {
753             // tdf#114070 - only show the last name of the filename without its extension
754             aObj.removeExtension();
755             grfName = aObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
756         }
757 
758         m_xExamplesVS->SetItemText( i + 1, grfName );
759         ++i;
760     }
761 
762     if(aGrfNames.empty())
763     {
764         m_xErrorText->show();
765     }
766     else
767     {
768         m_xExamplesVS->Show();
769         m_xExamplesVS->SetFormat();
770         m_xExamplesVS->Invalidate();
771     }
772 }
773 
774 SvxBitmapPickTabPage::~SvxBitmapPickTabPage()
775 {
776     m_xExamplesVSWin.reset();
777     m_xExamplesVS.reset();
778 }
779 
780 std::unique_ptr<SfxTabPage> SvxBitmapPickTabPage::Create(weld::Container* pPage, weld::DialogController* pController,
781                                                 const SfxItemSet* rAttrSet)
782 {
783     return std::make_unique<SvxBitmapPickTabPage>(pPage, pController, *rAttrSet);
784 }
785 
786 void  SvxBitmapPickTabPage::ActivatePage(const SfxItemSet& rSet)
787 {
788     bPreset = false;
789     bool bIsPreset = false;
790     const SfxItemSet* pExampleSet = GetDialogExampleSet();
791     if(pExampleSet)
792     {
793         if(const SfxBoolItem* pPresetItem = pExampleSet->GetItemIfSet(SID_PARAM_NUM_PRESET, false))
794             bIsPreset = pPresetItem->GetValue();
795         if(const SfxUInt16Item* pLevelItem = pExampleSet->GetItemIfSet(SID_PARAM_CUR_NUM_LEVEL, false))
796             nActNumLvl = pLevelItem->GetValue();
797     }
798     if(const SvxNumBulletItem* pBulletItem = rSet.GetItemIfSet(nNumItemId, false))
799     {
800         pSaveNum.reset( new SvxNumRule(pBulletItem->GetNumRule()) );
801     }
802     if(pActNum && *pSaveNum != *pActNum)
803     {
804         *pActNum = *pSaveNum;
805         m_xExamplesVS->SetNoSelection();
806     }
807 
808     if(!aGrfNames.empty() &&
809         (pActNum && (!lcl_IsNumFmtSet(pActNum.get(), nActNumLvl) || bIsPreset)))
810     {
811         m_xExamplesVS->SelectItem(1);
812         NumSelectHdl_Impl(m_xExamplesVS.get());
813         bPreset = true;
814     }
815     bPreset |= bIsPreset;
816     bModified = false;
817 }
818 
819 DeactivateRC SvxBitmapPickTabPage::DeactivatePage(SfxItemSet *_pSet)
820 {
821     if(_pSet)
822         FillItemSet(_pSet);
823     return DeactivateRC::LeavePage;
824 }
825 
826 bool  SvxBitmapPickTabPage::FillItemSet( SfxItemSet* rSet )
827 {
828     if ( aGrfNames.empty() )
829     {
830         return false;
831     }
832     if( (bPreset || bModified) && pActNum)
833     {
834         *pSaveNum = *pActNum;
835         rSet->Put(SvxNumBulletItem( *pSaveNum, nNumItemId ) );
836         rSet->Put(SfxBoolItem(SID_PARAM_NUM_PRESET, bPreset));
837     }
838 
839     return bModified;
840 }
841 
842 void  SvxBitmapPickTabPage::Reset( const SfxItemSet* rSet )
843 {
844     // in Draw the item exists as WhichId, in Writer only as SlotId
845     const SvxNumBulletItem* pItem = rSet->GetItemIfSet(SID_ATTR_NUMBERING_RULE, false);
846     if(!pItem)
847     {
848         nNumItemId = rSet->GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE);
849         pItem = rSet->GetItemIfSet(nNumItemId, false);
850 
851         if( !pItem )
852         {
853             pItem = & rSet->Get( nNumItemId );
854         }
855 
856     }
857     DBG_ASSERT(pItem, "no item found!");
858     pSaveNum.reset( new SvxNumRule(pItem->GetNumRule()) );
859 
860     if(!pActNum)
861         pActNum.reset( new SvxNumRule(*pSaveNum) );
862     else if(*pSaveNum != *pActNum)
863         *pActNum = *pSaveNum;
864 }
865 
866 IMPL_LINK_NOARG(SvxBitmapPickTabPage, NumSelectHdl_Impl, ValueSet*, void)
867 {
868     if(!pActNum)
869         return;
870 
871     bPreset = false;
872     bModified = true;
873     sal_uInt16 nIdx = m_xExamplesVS->GetSelectedItemId() - 1;
874 
875     sal_uInt16 nMask = 1;
876     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
877     {
878         if(nActNumLvl & nMask)
879         {
880             SvxNumberFormat aFmt(pActNum->GetLevel(i));
881             aFmt.SetNumberingType(SVX_NUM_BITMAP);
882             aFmt.SetListFormat("", "", i);
883             aFmt.SetCharFormatName( "" );
884 
885             Graphic aGraphic;
886             if(GalleryExplorer::GetGraphicObj( GALLERY_THEME_BULLETS, nIdx, &aGraphic))
887             {
888                 Size aSize = SvxNumberFormat::GetGraphicSizeMM100(&aGraphic);
889                 sal_Int16 eOrient = text::VertOrientation::LINE_CENTER;
890                 aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(eCoreUnit));
891                 SvxBrushItem aBrush(aGraphic, GPOS_AREA, SID_ATTR_BRUSH );
892                 aFmt.SetGraphicBrush( &aBrush, &aSize, &eOrient );
893             }
894             else if(aGrfNames.size() > nIdx)
895                 aFmt.SetGraphic( aGrfNames[nIdx] );
896             pActNum->SetLevel(i, aFmt);
897         }
898         nMask <<= 1;
899     }
900 }
901 
902 IMPL_LINK_NOARG(SvxBitmapPickTabPage, DoubleClickHdl_Impl, ValueSet*, void)
903 {
904     NumSelectHdl_Impl(m_xExamplesVS.get());
905     weld::Button& rOk = GetDialogController()->GetOKButton();
906     rOk.clicked();
907 }
908 
909 IMPL_LINK_NOARG(SvxBitmapPickTabPage, ClickAddBrowseHdl_Impl, weld::Button&, void)
910 {
911     sfx2::FileDialogHelper aFileDialog(0, FileDialogFlags::NONE, GetFrameWeld());
912     aFileDialog.SetContext(sfx2::FileDialogHelper::BulletsAddImage);
913     aFileDialog.SetTitle(CuiResId(RID_CUISTR_ADD_IMAGE));
914     if ( aFileDialog.Execute() != ERRCODE_NONE )
915         return;
916 
917     OUString aPath = SvtPathOptions().GetGalleryPath();
918     std::u16string_view aPathToken = o3tl::getToken(aPath, 1 , SEARCHPATH_DELIMITER );
919 
920     OUString aUserImageURL = aFileDialog.GetPath();
921 
922     OUString aFileName;
923     const sal_Int32 nPos {aUserImageURL.lastIndexOf(SEARCHFILENAME_DELIMITER)+1};
924     if (nPos<=0)
925         aFileName = aUserImageURL;
926     else if (nPos<aUserImageURL.getLength())
927         aFileName = aUserImageURL.copy(nPos);
928 
929     OUString aUserGalleryURL = OUString::Concat(aPathToken) + "/" + aFileName;
930     INetURLObject aURL( aUserImageURL );
931     DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
932 
933     GraphicDescriptor aDescriptor(aURL);
934     if (!aDescriptor.Detect())
935         return;
936 
937     uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
938     uno::Reference<ucb::XSimpleFileAccess3> xSimpleFileAccess(
939                  ucb::SimpleFileAccess::create( ::comphelper::getComponentContext(xFactory) ) );
940     if ( !xSimpleFileAccess->exists( aUserImageURL ))
941         return;
942 
943     xSimpleFileAccess->copy( aUserImageURL, aUserGalleryURL );
944     INetURLObject gURL( aUserGalleryURL );
945     std::unique_ptr<SvStream> pIn(::utl::UcbStreamHelper::CreateStream(
946                   gURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));
947     if ( !pIn )
948         return;
949 
950     Graphic aGraphic;
951     GraphicConverter::Import( *pIn, aGraphic );
952 
953     BitmapEx aBitmap = aGraphic.GetBitmapEx();
954     tools::Long nPixelX = aBitmap.GetSizePixel().Width();
955     tools::Long nPixelY = aBitmap.GetSizePixel().Height();
956     double ratio = nPixelY/static_cast<double>(nPixelX);
957     if(nPixelX > 30)
958     {
959         nPixelX = 30;
960         nPixelY = static_cast<tools::Long>(nPixelX*ratio);
961     }
962     if(nPixelY > 30)
963     {
964         nPixelY = 30;
965         nPixelX = static_cast<tools::Long>(nPixelY/ratio);
966     }
967 
968     aBitmap.Scale( Size( nPixelX, nPixelY ), BmpScaleFlag::Fast );
969     Graphic aScaledGraphic( aBitmap );
970     GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
971 
972     Sequence< PropertyValue > aFilterData{
973         comphelper::makePropertyValue("Compression", sal_Int32(-1)),
974         comphelper::makePropertyValue("Quality", sal_Int32(1))
975     };
976 
977     sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName( gURL.GetFileExtension() );
978     rFilter.ExportGraphic( aScaledGraphic, gURL , nFilterFormat, &aFilterData );
979     GalleryExplorer::InsertURL( GALLERY_THEME_BULLETS, aUserGalleryURL );
980 
981     aGrfNames.push_back(aUserGalleryURL);
982     size_t i = 0;
983     for (auto & grfName : aGrfNames)
984     {
985         m_xExamplesVS->InsertItem( i + 1, i);
986         INetURLObject aObj(grfName);
987         if (aObj.GetProtocol() == INetProtocol::File)
988         {
989             // tdf#114070 - only show the last name of the filename without its extension
990             aObj.removeExtension();
991             grfName = aObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
992         }
993         m_xExamplesVS->SetItemText( i + 1, grfName );
994         ++i;
995     }
996 
997     if(aGrfNames.empty())
998     {
999         m_xErrorText->show();
1000     }
1001     else
1002     {
1003         m_xExamplesVS->Show();
1004         m_xExamplesVS->SetFormat();
1005     }
1006 }
1007 
1008 // tabpage numbering options
1009 SvxNumOptionsTabPage::SvxNumOptionsTabPage(weld::Container* pPage, weld::DialogController* pController,
1010                                const SfxItemSet& rSet)
1011     : SfxTabPage(pPage, pController, "cui/ui/numberingoptionspage.ui", "NumberingOptionsPage", &rSet)
1012     , aInvalidateTimer("cui SvxNumOptionsTabPage aInvalidateTimer")
1013     , m_pLevelHdlEvent(nullptr)
1014     , bLastWidthModified(false)
1015     , bModified(false)
1016     , bPreset(false)
1017     , bAutomaticCharStyles(true)
1018     , bHTMLMode(false)
1019     , nBullet(0xff)
1020     , nActNumLvl(1)
1021     , nNumItemId(SID_ATTR_NUMBERING_RULE)
1022     , m_xGrid(m_xBuilder->weld_widget("grid2"))
1023     , m_xLevelLB(m_xBuilder->weld_tree_view("levellb"))
1024     , m_xFmtLB(m_xBuilder->weld_combo_box("numfmtlb"))
1025     , m_xSeparatorFT(m_xBuilder->weld_label("separator"))
1026     , m_xPrefixFT(m_xBuilder->weld_label("prefixft"))
1027     , m_xPrefixED(m_xBuilder->weld_entry("prefix"))
1028     , m_xSuffixFT(m_xBuilder->weld_label("suffixft"))
1029     , m_xSuffixED(m_xBuilder->weld_entry("suffix"))
1030     , m_xCharFmtFT(m_xBuilder->weld_label("charstyleft"))
1031     , m_xCharFmtLB(m_xBuilder->weld_combo_box("charstyle"))
1032     , m_xBulColorFT(m_xBuilder->weld_label("colorft"))
1033     , m_xBulColLB(new ColorListBox(m_xBuilder->weld_menu_button("color"),
1034                 [this]{ return GetDialogController()->getDialog(); }))
1035     , m_xBulRelSizeFT(m_xBuilder->weld_label("relsizeft"))
1036     , m_xBulRelSizeMF(m_xBuilder->weld_metric_spin_button("relsize", FieldUnit::PERCENT))
1037     , m_xAllLevelFT(m_xBuilder->weld_label("sublevelsft"))
1038     , m_xAllLevelNF(m_xBuilder->weld_spin_button("sublevels"))
1039     , m_xStartFT(m_xBuilder->weld_label("startatft"))
1040     , m_xStartED(m_xBuilder->weld_spin_button("startat"))
1041     , m_xBulletFT(m_xBuilder->weld_label("bulletft"))
1042     , m_xBulletPB(m_xBuilder->weld_button("bullet"))
1043     , m_xBitmapFT(m_xBuilder->weld_label("bitmapft"))
1044     , m_xBitmapMB(m_xBuilder->weld_menu_button("bitmap"))
1045     , m_xWidthFT(m_xBuilder->weld_label("widthft"))
1046     , m_xWidthMF(m_xBuilder->weld_metric_spin_button("widthmf", FieldUnit::CM))
1047     , m_xHeightFT(m_xBuilder->weld_label("heightft"))
1048     , m_xHeightMF(m_xBuilder->weld_metric_spin_button("heightmf", FieldUnit::CM))
1049     , m_xRatioCB(m_xBuilder->weld_check_button("keepratio"))
1050     , m_xOrientFT(m_xBuilder->weld_label("orientft"))
1051     , m_xOrientLB(m_xBuilder->weld_combo_box("orientlb"))
1052     , m_xAllLevelsFrame(m_xBuilder->weld_widget("levelsframe"))
1053     , m_xSameLevelCB(m_xBuilder->weld_check_button("allsame"))
1054     , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreviewWIN))
1055 {
1056     m_xBulColLB->SetSlotId(SID_ATTR_CHAR_COLOR);
1057     m_xBulRelSizeMF->set_min(SVX_NUM_REL_SIZE_MIN, FieldUnit::PERCENT);
1058     m_xBulRelSizeMF->set_increments(5, 50, FieldUnit::PERCENT);
1059     SetExchangeSupport();
1060     aActBulletFont = lcl_GetDefaultBulletFont();
1061 
1062     m_xBulletPB->connect_clicked(LINK(this, SvxNumOptionsTabPage, BulletHdl_Impl));
1063     m_xFmtLB->connect_changed(LINK(this, SvxNumOptionsTabPage, NumberTypeSelectHdl_Impl));
1064     m_xBitmapMB->connect_selected(LINK(this, SvxNumOptionsTabPage, GraphicHdl_Impl));
1065     m_xBitmapMB->connect_toggled(LINK(this, SvxNumOptionsTabPage, PopupActivateHdl_Impl));
1066     m_xLevelLB->set_selection_mode(SelectionMode::Multiple);
1067     m_xLevelLB->connect_changed(LINK(this, SvxNumOptionsTabPage, LevelHdl_Impl));
1068     m_xCharFmtLB->connect_changed(LINK(this, SvxNumOptionsTabPage, CharFmtHdl_Impl));
1069     m_xWidthMF->connect_value_changed(LINK(this, SvxNumOptionsTabPage, SizeHdl_Impl));
1070     m_xHeightMF->connect_value_changed(LINK(this, SvxNumOptionsTabPage, SizeHdl_Impl));
1071     m_xRatioCB->connect_toggled(LINK(this, SvxNumOptionsTabPage, RatioHdl_Impl));
1072     m_xStartED->connect_value_changed(LINK(this, SvxNumOptionsTabPage, SpinModifyHdl_Impl));
1073     m_xPrefixED->connect_changed(LINK(this, SvxNumOptionsTabPage, EditModifyHdl_Impl));
1074     m_xSuffixED->connect_changed(LINK(this, SvxNumOptionsTabPage, EditModifyHdl_Impl));
1075     m_xAllLevelNF->connect_value_changed(LINK(this,SvxNumOptionsTabPage, AllLevelHdl_Impl));
1076     m_xOrientLB->connect_changed(LINK(this, SvxNumOptionsTabPage, OrientHdl_Impl));
1077     m_xSameLevelCB->connect_toggled(LINK(this, SvxNumOptionsTabPage, SameLevelHdl_Impl));
1078     m_xBulRelSizeMF->connect_value_changed(LINK(this,SvxNumOptionsTabPage, BulRelSizeHdl_Impl));
1079     m_xBulColLB->SetSelectHdl(LINK(this, SvxNumOptionsTabPage, BulColorHdl_Impl));
1080     aInvalidateTimer.SetInvokeHandler(LINK(this, SvxNumOptionsTabPage, PreviewInvalidateHdl_Impl));
1081     aInvalidateTimer.SetTimeout(50);
1082 
1083     eCoreUnit = rSet.GetPool()->GetMetric(rSet.GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE));
1084 
1085     // Fill ListBox with predefined / translated numbering types.
1086     sal_uInt32 nCount = SvxNumberingTypeTable::Count();
1087     for (sal_uInt32 i = 0; i < nCount; ++i)
1088     {
1089         m_xFmtLB->append(OUString::number(SvxNumberingTypeTable::GetValue(i)), SvxNumberingTypeTable::GetString(i));
1090     }
1091 
1092     // Get advanced numbering types from the component.
1093     // Watch out for the ugly
1094     // 136 == 0x88 == SVX_NUM_BITMAP|0x80 == SVX_NUM_BITMAP|LINK_TOKEN
1095     // to not remove that.
1096     SvxNumOptionsTabPageHelper::GetI18nNumbering( *m_xFmtLB, (SVX_NUM_BITMAP | LINK_TOKEN));
1097 
1098     m_xFmtLB->set_active(0);
1099 
1100     m_xCharFmtLB->set_size_request(m_xCharFmtLB->get_approximate_digit_width() * 10, -1);
1101     Size aSize(m_xGrid->get_preferred_size());
1102     m_xGrid->set_size_request(aSize.Width(), -1);
1103 }
1104 
1105 SvxNumOptionsTabPage::~SvxNumOptionsTabPage()
1106 {
1107     m_xPreviewWIN.reset();
1108     m_xBulColLB.reset();
1109     pActNum.reset();
1110     pSaveNum.reset();
1111     if (m_pLevelHdlEvent)
1112     {
1113         Application::RemoveUserEvent(m_pLevelHdlEvent);
1114         m_pLevelHdlEvent = nullptr;
1115     }
1116 }
1117 
1118 void SvxNumOptionsTabPage::SetMetric(FieldUnit eMetric)
1119 {
1120     if(eMetric == FieldUnit::MM)
1121     {
1122         m_xWidthMF->set_digits(1);
1123         m_xHeightMF->set_digits(1);
1124     }
1125     m_xWidthMF->set_unit(eMetric);
1126     m_xHeightMF->set_unit(eMetric);
1127 }
1128 
1129 std::unique_ptr<SfxTabPage> SvxNumOptionsTabPage::Create(weld::Container* pPage, weld::DialogController* pController,
1130                                                 const SfxItemSet* rAttrSet)
1131 {
1132     return std::make_unique<SvxNumOptionsTabPage>(pPage, pController, *rAttrSet);
1133 };
1134 
1135 void    SvxNumOptionsTabPage::ActivatePage(const SfxItemSet& rSet)
1136 {
1137     const SfxItemSet* pExampleSet = GetDialogExampleSet();
1138     sal_uInt16 nTmpNumLvl = 1;
1139     if(pExampleSet)
1140     {
1141         if(const SfxBoolItem* pPresetItem = pExampleSet->GetItemIfSet(SID_PARAM_NUM_PRESET, false))
1142             bPreset = pPresetItem->GetValue();
1143         if(const SfxUInt16Item* pLevelItem = pExampleSet->GetItemIfSet(SID_PARAM_CUR_NUM_LEVEL, false))
1144             nTmpNumLvl = pLevelItem->GetValue();
1145     }
1146     if(const SvxNumBulletItem* pBulletItem = rSet.GetItemIfSet(nNumItemId, false))
1147     {
1148         pSaveNum.reset( new SvxNumRule(pBulletItem->GetNumRule()) );
1149     }
1150 
1151     bModified = (!pActNum->Get( 0 ) || bPreset);
1152     if(*pActNum == *pSaveNum && nActNumLvl == nTmpNumLvl)
1153         return;
1154 
1155     nActNumLvl = nTmpNumLvl;
1156     sal_uInt16 nMask = 1;
1157     m_xLevelLB->unselect_all();
1158     if (nActNumLvl == SAL_MAX_UINT16)
1159         m_xLevelLB->select(pActNum->GetLevelCount());
1160     if(nActNumLvl != SAL_MAX_UINT16)
1161     {
1162         for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1163         {
1164             if(nActNumLvl & nMask)
1165                 m_xLevelLB->select(i);
1166             nMask <<= 1 ;
1167         }
1168     }
1169     *pActNum = *pSaveNum;
1170 
1171     InitControls();
1172 }
1173 
1174 DeactivateRC SvxNumOptionsTabPage::DeactivatePage(SfxItemSet * _pSet)
1175 {
1176     if(_pSet)
1177         FillItemSet(_pSet);
1178     return DeactivateRC::LeavePage;
1179 }
1180 
1181 bool    SvxNumOptionsTabPage::FillItemSet( SfxItemSet* rSet )
1182 {
1183     rSet->Put(SfxUInt16Item(SID_PARAM_CUR_NUM_LEVEL, nActNumLvl));
1184     if(bModified && pActNum)
1185     {
1186         *pSaveNum = *pActNum;
1187         rSet->Put(SvxNumBulletItem( *pSaveNum, nNumItemId ));
1188         rSet->Put(SfxBoolItem(SID_PARAM_NUM_PRESET, false));
1189     }
1190     return bModified;
1191 };
1192 
1193 void    SvxNumOptionsTabPage::Reset( const SfxItemSet* rSet )
1194 {
1195     // in Draw the item exists as WhichId, in Writer only as SlotId
1196     const SvxNumBulletItem* pBulletItem =
1197         rSet->GetItemIfSet(SID_ATTR_NUMBERING_RULE, false);
1198     if(!pBulletItem)
1199     {
1200         nNumItemId = rSet->GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE);
1201         pBulletItem = rSet->GetItemIfSet(nNumItemId, false);
1202 
1203         if( !pBulletItem )
1204         {
1205             pBulletItem = & rSet->Get( nNumItemId );
1206         }
1207     }
1208     DBG_ASSERT(pBulletItem, "no item found!");
1209     pSaveNum.reset( new SvxNumRule(pBulletItem->GetNumRule()) );
1210 
1211     // insert levels
1212     if (!m_xLevelLB->n_children())
1213     {
1214         for(sal_uInt16 i = 1; i <= pSaveNum->GetLevelCount(); i++)
1215             m_xLevelLB->append_text(OUString::number(i));
1216         if(pSaveNum->GetLevelCount() > 1)
1217         {
1218             OUString sEntry = "1 - " + OUString::number( pSaveNum->GetLevelCount() );
1219             m_xLevelLB->append_text(sEntry);
1220             m_xLevelLB->select_text(sEntry);
1221         }
1222         else
1223             m_xLevelLB->select(0);
1224     }
1225     else
1226         m_xLevelLB->select(m_xLevelLB->n_children() - 1);
1227 
1228     sal_uInt16 nMask = 1;
1229     m_xLevelLB->unselect_all();
1230     if (nActNumLvl == SAL_MAX_UINT16)
1231     {
1232         m_xLevelLB->select( pSaveNum->GetLevelCount() );
1233     }
1234     else
1235     {
1236         for(sal_uInt16 i = 0; i < pSaveNum->GetLevelCount(); i++)
1237         {
1238             if(nActNumLvl & nMask)
1239                 m_xLevelLB->select( i );
1240             nMask <<= 1 ;
1241         }
1242     }
1243 
1244     if(!pActNum)
1245         pActNum.reset( new SvxNumRule(*pSaveNum) );
1246     else if(*pSaveNum != *pActNum)
1247         *pActNum = *pSaveNum;
1248     m_aPreviewWIN.SetNumRule(pActNum.get());
1249     m_xSameLevelCB->set_active(pActNum->IsContinuousNumbering());
1250 
1251     const SfxUInt16Item* pHtmlModeItem =
1252         rSet->GetItemIfSet( SID_HTML_MODE, false );
1253     if (!pHtmlModeItem)
1254     {
1255         if (SfxObjectShell* pShell = SfxObjectShell::Current())
1256             pHtmlModeItem = pShell->GetItem( SID_HTML_MODE );
1257     }
1258     if ( pHtmlModeItem )
1259     {
1260         sal_uInt16 nHtmlMode = pHtmlModeItem->GetValue();
1261         bHTMLMode = 0 != (nHtmlMode&HTMLMODE_ON);
1262     }
1263 
1264     bool bCharFmt = pActNum->IsFeatureSupported(SvxNumRuleFlags::CHAR_STYLE);
1265     m_xCharFmtFT->set_visible(bCharFmt);
1266     m_xCharFmtLB->set_visible(bCharFmt);
1267 
1268     bool bContinuous = pActNum->IsFeatureSupported(SvxNumRuleFlags::CONTINUOUS);
1269 
1270     bool bAllLevel = bContinuous && !bHTMLMode;
1271     m_xAllLevelFT->set_visible(bAllLevel);
1272     m_xAllLevelNF->set_visible(bAllLevel);
1273 
1274     m_xAllLevelsFrame->set_visible(bContinuous);
1275 
1276     // again misusage: in Draw there is numeration only until the bitmap
1277     // without SVX_NUM_NUMBER_NONE
1278     //remove types that are unsupported by Draw/Impress
1279     if(!bContinuous)
1280     {
1281         sal_Int32 nFmtCount = m_xFmtLB->get_count();
1282         for(sal_Int32 i = nFmtCount; i; i--)
1283         {
1284             sal_uInt16 nEntryData = m_xFmtLB->get_id(i - 1).toUInt32();
1285             if(/*SVX_NUM_NUMBER_NONE == nEntryData ||*/
1286                 (SVX_NUM_BITMAP|LINK_TOKEN) ==  nEntryData)
1287                 m_xFmtLB->remove(i - 1);
1288         }
1289     }
1290     //one must be enabled
1291     if(!pActNum->IsFeatureSupported(SvxNumRuleFlags::ENABLE_LINKED_BMP))
1292     {
1293         auto nPos = m_xFmtLB->find_id(OUString::number(SVX_NUM_BITMAP|LINK_TOKEN));
1294         if (nPos != -1)
1295             m_xFmtLB->remove(nPos);
1296     }
1297     else if(!pActNum->IsFeatureSupported(SvxNumRuleFlags::ENABLE_EMBEDDED_BMP))
1298     {
1299         auto nPos = m_xFmtLB->find_id(OUString::number(SVX_NUM_BITMAP));
1300         if (nPos != -1)
1301             m_xFmtLB->remove(nPos);
1302     }
1303 
1304     // MegaHack: because of a not-fixable 'design mistake/error' in Impress
1305     // delete all kinds of numeric enumerations
1306     if(pActNum->IsFeatureSupported(SvxNumRuleFlags::NO_NUMBERS))
1307     {
1308         sal_Int32 nFmtCount = m_xFmtLB->get_count();
1309         for(sal_Int32 i = nFmtCount; i; i--)
1310         {
1311             sal_uInt16 nEntryData = m_xFmtLB->get_id(i - 1).toUInt32();
1312             if( /*nEntryData >= SVX_NUM_CHARS_UPPER_LETTER &&*/  nEntryData <= SVX_NUM_NUMBER_NONE)
1313                 m_xFmtLB->remove(i - 1);
1314         }
1315     }
1316 
1317     InitControls();
1318     bModified = false;
1319 }
1320 
1321 void SvxNumOptionsTabPage::InitControls()
1322 {
1323     bool bShowBullet    = true;
1324     bool bShowBitmap    = true;
1325     bool bSameType      = true;
1326     bool bSameStart     = true;
1327     bool bSamePrefix    = true;
1328     bool bSameSuffix    = true;
1329     bool bAllLevel      = true;
1330     bool bSameCharFmt   = true;
1331     bool bSameVOrient   = true;
1332     bool bSameSize      = true;
1333     bool bSameBulColor  = true;
1334     bool bSameBulRelSize= true;
1335 
1336     const SvxNumberFormat* aNumFmtArr[SVX_MAX_NUM];
1337     OUString sFirstCharFmt;
1338     sal_Int16 eFirstOrient = text::VertOrientation::NONE;
1339     Size aFirstSize(0,0);
1340     sal_uInt16 nMask = 1;
1341     sal_uInt16 nLvl = SAL_MAX_UINT16;
1342     sal_uInt16 nHighestLevel = 0;
1343 
1344     bool bBullColor = pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_COLOR);
1345     bool bBullRelSize = pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_REL_SIZE);
1346     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1347     {
1348         if(nActNumLvl & nMask)
1349         {
1350             aNumFmtArr[i] = &pActNum->GetLevel(i);
1351             bShowBullet &= aNumFmtArr[i]->GetNumberingType() == SVX_NUM_CHAR_SPECIAL;
1352             bShowBitmap &= (aNumFmtArr[i]->GetNumberingType()&(~LINK_TOKEN)) == SVX_NUM_BITMAP;
1353             if(SAL_MAX_UINT16 == nLvl)
1354             {
1355                 nLvl = i;
1356                 sFirstCharFmt = aNumFmtArr[i]->GetCharFormatName();
1357                 eFirstOrient = aNumFmtArr[i]->GetVertOrient();
1358                 if(bShowBitmap)
1359                     aFirstSize = aNumFmtArr[i]->GetGraphicSize();
1360             }
1361             if( i > nLvl)
1362             {
1363                 bSameType &=   aNumFmtArr[i]->GetNumberingType() == aNumFmtArr[nLvl]->GetNumberingType();
1364                 bSameStart = aNumFmtArr[i]->GetStart() == aNumFmtArr[nLvl]->GetStart();
1365 
1366                 bSamePrefix = aNumFmtArr[i]->GetPrefix() == aNumFmtArr[nLvl]->GetPrefix();
1367                 bSameSuffix = aNumFmtArr[i]->GetSuffix() == aNumFmtArr[nLvl]->GetSuffix();
1368                 bAllLevel &= aNumFmtArr[i]->GetIncludeUpperLevels() == aNumFmtArr[nLvl]->GetIncludeUpperLevels();
1369                 bSameCharFmt    &= sFirstCharFmt == aNumFmtArr[i]->GetCharFormatName();
1370                 bSameVOrient    &= eFirstOrient == aNumFmtArr[i]->GetVertOrient();
1371                 if(bShowBitmap && bSameSize)
1372                     bSameSize &= aNumFmtArr[i]->GetGraphicSize() == aFirstSize;
1373                 bSameBulColor &= aNumFmtArr[i]->GetBulletColor() == aNumFmtArr[nLvl]->GetBulletColor();
1374                 bSameBulRelSize &= aNumFmtArr[i]->GetBulletRelSize() == aNumFmtArr[nLvl]->GetBulletRelSize();
1375             }
1376             nHighestLevel = i;
1377         }
1378         else
1379             aNumFmtArr[i] = nullptr;
1380 
1381         nMask <<= 1 ;
1382     }
1383     SwitchNumberType(bShowBullet ? 1 : bShowBitmap ? 2 : 0);
1384 
1385     sal_uInt16 nNumberingType;
1386     if (nLvl != SAL_MAX_UINT16)
1387         nNumberingType = aNumFmtArr[nLvl]->GetNumberingType();
1388     else
1389     {
1390         nNumberingType = SVX_NUM_NUMBER_NONE;
1391         bAllLevel = false;
1392         bSameBulRelSize = false;
1393         bSameBulColor = false;
1394         bSameStart = false;
1395         bSamePrefix = false;
1396         bSameSuffix = false;
1397     }
1398 
1399     CheckForStartValue_Impl(nNumberingType);
1400 
1401     if(bShowBitmap)
1402     {
1403         if(!bSameVOrient || eFirstOrient == text::VertOrientation::NONE)
1404             m_xOrientLB->set_active(-1);
1405         else
1406             m_xOrientLB->set_active(
1407                 sal::static_int_cast< sal_Int32 >(eFirstOrient - 1));
1408                 // no text::VertOrientation::NONE
1409 
1410         if(bSameSize)
1411         {
1412             SetMetricValue(*m_xHeightMF, aFirstSize.Height(), eCoreUnit);
1413             SetMetricValue(*m_xWidthMF, aFirstSize.Width(), eCoreUnit);
1414         }
1415         else
1416         {
1417             m_xHeightMF->set_text("");
1418             m_xWidthMF->set_text("");
1419         }
1420     }
1421 
1422     if(bSameType)
1423     {
1424         sal_uInt16 nLBData = nNumberingType;
1425         m_xFmtLB->set_active_id(OUString::number(nLBData));
1426     }
1427     else
1428         m_xFmtLB->set_active(-1);
1429 
1430     m_xAllLevelNF->set_sensitive(nHighestLevel > 0 && !m_xSameLevelCB->get_active());
1431     m_xAllLevelNF->set_max(nHighestLevel + 1);
1432     if(bAllLevel)
1433     {
1434         m_xAllLevelNF->set_value(aNumFmtArr[nLvl]->GetIncludeUpperLevels());
1435     }
1436     else
1437     {
1438         m_xAllLevelNF->set_text("");
1439     }
1440 
1441     if(bBullRelSize)
1442     {
1443         if(bSameBulRelSize)
1444             m_xBulRelSizeMF->set_value(aNumFmtArr[nLvl]->GetBulletRelSize(), FieldUnit::PERCENT);
1445         else
1446             m_xBulRelSizeMF->set_text("");
1447     }
1448     if(bBullColor)
1449     {
1450         if(bSameBulColor)
1451             m_xBulColLB->SelectEntry(aNumFmtArr[nLvl]->GetBulletColor());
1452         else
1453             m_xBulColLB->SetNoSelection();
1454     }
1455     switch(nBullet)
1456     {
1457         case SHOW_NUMBERING:
1458             if(bSameStart)
1459             {
1460                 m_xStartED->set_value(aNumFmtArr[nLvl]->GetStart());
1461             }
1462             else
1463                 m_xStartED->set_text("");
1464         break;
1465         case SHOW_BULLET:
1466         break;
1467         case SHOW_BITMAP:
1468         break;
1469     }
1470 
1471     if(bSamePrefix)
1472         m_xPrefixED->set_text(aNumFmtArr[nLvl]->GetPrefix());
1473     else
1474         m_xPrefixED->set_text("");
1475     if(bSameSuffix)
1476         m_xSuffixED->set_text(aNumFmtArr[nLvl]->GetSuffix());
1477     else
1478         m_xSuffixED->set_text("");
1479 
1480     if(bSameCharFmt)
1481     {
1482         if (!sFirstCharFmt.isEmpty())
1483             m_xCharFmtLB->set_active_text(sFirstCharFmt);
1484         else
1485             m_xCharFmtLB->set_active(0);
1486     }
1487     else
1488         m_xCharFmtLB->set_active(-1);
1489 
1490     m_aPreviewWIN.SetLevel(nActNumLvl);
1491     m_aPreviewWIN.Invalidate();
1492 }
1493 
1494 // 0 - Number; 1 - Bullet; 2 - Bitmap
1495 void SvxNumOptionsTabPage::SwitchNumberType( sal_uInt8 nType )
1496 {
1497     if(nBullet == nType)
1498         return;
1499     nBullet = nType;
1500     bool bBullet = (nType == SHOW_BULLET);
1501     bool bBitmap = (nType == SHOW_BITMAP);
1502     bool bEnableBitmap = (nType == SHOW_BITMAP);
1503     bool bNumeric = !(bBitmap||bBullet);
1504     m_xSeparatorFT->set_visible(bNumeric);
1505     m_xPrefixFT->set_visible(bNumeric);
1506     m_xPrefixED->set_visible(bNumeric);
1507     m_xSuffixFT->set_visible(bNumeric);
1508     m_xSuffixED->set_visible(bNumeric);
1509 
1510     bool bCharFmt = pActNum->IsFeatureSupported(SvxNumRuleFlags::CHAR_STYLE);
1511     m_xCharFmtFT->set_visible(!bBitmap && bCharFmt);
1512     m_xCharFmtLB->set_visible(!bBitmap && bCharFmt);
1513 
1514     // this is rather misusage, as there is no own flag
1515     // for complete numeration
1516     bool bAllLevelFeature = pActNum->IsFeatureSupported(SvxNumRuleFlags::CONTINUOUS);
1517     bool bAllLevel = bNumeric && bAllLevelFeature && !bHTMLMode;
1518     m_xAllLevelFT->set_visible(bAllLevel);
1519     m_xAllLevelNF->set_visible(bAllLevel);
1520 
1521     m_xStartFT->set_visible(!(bBullet||bBitmap));
1522     m_xStartED->set_visible(!(bBullet||bBitmap));
1523 
1524     m_xBulletFT->set_visible(bBullet);
1525     m_xBulletPB->set_visible(bBullet);
1526     bool bBullColor = pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_COLOR);
1527     m_xBulColorFT->set_visible(!bBitmap && bBullColor);
1528     m_xBulColLB->set_visible(!bBitmap && bBullColor);
1529     bool bBullResSize = pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_REL_SIZE);
1530     m_xBulRelSizeFT->set_visible(!bBitmap && bBullResSize);
1531     m_xBulRelSizeMF->set_visible(!bBitmap && bBullResSize);
1532 
1533     m_xBitmapFT->set_visible(bBitmap);
1534     m_xBitmapMB->set_visible(bBitmap);
1535 
1536     m_xWidthFT->set_visible(bBitmap);
1537     m_xWidthMF->set_visible(bBitmap);
1538     m_xHeightFT->set_visible(bBitmap);
1539     m_xHeightMF->set_visible(bBitmap);
1540     m_xRatioCB->set_visible(bBitmap);
1541 
1542     m_xOrientFT->set_visible(bBitmap && bAllLevelFeature);
1543     m_xOrientLB->set_visible(bBitmap && bAllLevelFeature);
1544 
1545     m_xWidthFT->set_sensitive(bEnableBitmap);
1546     m_xWidthMF->set_sensitive(bEnableBitmap);
1547     m_xHeightFT->set_sensitive(bEnableBitmap);
1548     m_xHeightMF->set_sensitive(bEnableBitmap);
1549     m_xRatioCB->set_sensitive(bEnableBitmap);
1550     m_xOrientFT->set_sensitive(bEnableBitmap);
1551     m_xOrientLB->set_sensitive(bEnableBitmap);
1552 }
1553 
1554 IMPL_LINK_NOARG(SvxNumOptionsTabPage, LevelHdl_Impl, weld::TreeView&, void)
1555 {
1556     if (m_pLevelHdlEvent)
1557         return;
1558     // tdf#127112 (borrowing tdf#127120 solution) multiselection may be implemented by deselect follow by select so
1559     // fire off the handler to happen on next event loop and only process the
1560     // final state
1561     m_pLevelHdlEvent = Application::PostUserEvent(LINK(this, SvxNumOptionsTabPage, LevelHdl));
1562 }
1563 
1564 IMPL_LINK_NOARG(SvxNumOptionsTabPage, LevelHdl, void*, void)
1565 {
1566     m_pLevelHdlEvent = nullptr;
1567 
1568     sal_uInt16 nSaveNumLvl = nActNumLvl;
1569     nActNumLvl = 0;
1570     std::vector<int> aSelectedRows = m_xLevelLB->get_selected_rows();
1571     if (std::find(aSelectedRows.begin(), aSelectedRows.end(), pActNum->GetLevelCount()) != aSelectedRows.end() &&
1572         (aSelectedRows.size() == 1 || nSaveNumLvl != 0xffff))
1573     {
1574         nActNumLvl = 0xFFFF;
1575         for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++ )
1576              m_xLevelLB->unselect(i);
1577     }
1578     else if (!aSelectedRows.empty())
1579     {
1580         sal_uInt16 nMask = 1;
1581         for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++ )
1582         {
1583             if (std::find(aSelectedRows.begin(), aSelectedRows.end(), i) != aSelectedRows.end())
1584                 nActNumLvl |= nMask;
1585             nMask <<= 1;
1586         }
1587         m_xLevelLB->unselect(pActNum->GetLevelCount());
1588     }
1589     else
1590     {
1591         nActNumLvl = nSaveNumLvl;
1592         sal_uInt16 nMask = 1;
1593         for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++ )
1594         {
1595             if(nActNumLvl & nMask)
1596             {
1597                 m_xLevelLB->select(i);
1598                 break;
1599             }
1600             nMask <<=1;
1601         }
1602     }
1603     InitControls();
1604 }
1605 
1606 IMPL_LINK_NOARG(SvxNumOptionsTabPage, PreviewInvalidateHdl_Impl, Timer *, void)
1607 {
1608     m_aPreviewWIN.Invalidate();
1609 }
1610 
1611 IMPL_LINK(SvxNumOptionsTabPage, AllLevelHdl_Impl, weld::SpinButton&, rBox, void)
1612 {
1613     sal_uInt16 nMask = 1;
1614     for(sal_uInt16 e = 0; e < pActNum->GetLevelCount(); e++)
1615     {
1616         if(nActNumLvl & nMask)
1617         {
1618             SvxNumberFormat aNumFmt(pActNum->GetLevel(e));
1619             aNumFmt.SetIncludeUpperLevels(static_cast<sal_uInt8>(std::min(rBox.get_value(), sal_Int64(e + 1))) );
1620             // Set the same prefix/suffix to generate list format with changed IncludedUpperLevels
1621             aNumFmt.SetListFormat(aNumFmt.GetPrefix(), aNumFmt.GetSuffix(), e);
1622             pActNum->SetLevel(e, aNumFmt);
1623         }
1624         nMask <<= 1;
1625     }
1626     SetModified();
1627 }
1628 
1629 IMPL_LINK(SvxNumOptionsTabPage, NumberTypeSelectHdl_Impl, weld::ComboBox&, rBox, void)
1630 {
1631     OUString sSelectStyle;
1632     bool bShowOrient = false;
1633     bool bBmp = false;
1634     sal_uInt16 nMask = 1;
1635     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1636     {
1637         if(nActNumLvl & nMask)
1638         {
1639             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
1640             // PAGEDESC does not exist
1641             SvxNumType nNumType = static_cast<SvxNumType>(rBox.get_active_id().toUInt32());
1642             aNumFmt.SetNumberingType(nNumType);
1643             sal_uInt16 nNumberingType = aNumFmt.GetNumberingType();
1644             if(SVX_NUM_BITMAP == (nNumberingType&(~LINK_TOKEN)))
1645             {
1646                 bBmp |= nullptr != aNumFmt.GetBrush();
1647                 aNumFmt.SetIncludeUpperLevels( 1 );
1648                 aNumFmt.SetListFormat("", "", i);
1649                 if(!bBmp)
1650                     aNumFmt.SetGraphic("");
1651                 pActNum->SetLevel(i, aNumFmt);
1652                 SwitchNumberType(SHOW_BITMAP);
1653                 bShowOrient = true;
1654             }
1655             else if( SVX_NUM_CHAR_SPECIAL == nNumberingType )
1656             {
1657                 aNumFmt.SetIncludeUpperLevels( 1 );
1658                 aNumFmt.SetListFormat("", "", i);
1659                 if( !aNumFmt.GetBulletFont() )
1660                     aNumFmt.SetBulletFont(&aActBulletFont);
1661                 if( !aNumFmt.GetBulletChar() )
1662                     aNumFmt.SetBulletChar( SVX_DEF_BULLET );
1663                 pActNum->SetLevel(i, aNumFmt);
1664                 SwitchNumberType(SHOW_BULLET);
1665                 // allocation of the drawing pattern is automatic
1666                 if(bAutomaticCharStyles)
1667                 {
1668                     sSelectStyle = m_sBulletCharFormatName;
1669                 }
1670             }
1671             else
1672             {
1673                 aNumFmt.SetListFormat(m_xPrefixED->get_text(), m_xSuffixED->get_text(), i);
1674 
1675                 SwitchNumberType(SHOW_NUMBERING);
1676                 pActNum->SetLevel(i, aNumFmt);
1677                 CheckForStartValue_Impl(nNumberingType);
1678 
1679                 // allocation of the drawing pattern is automatic
1680                 if(bAutomaticCharStyles)
1681                 {
1682                     sSelectStyle = m_sNumCharFmtName;
1683                 }
1684             }
1685         }
1686         nMask <<= 1;
1687     }
1688     bool bAllLevelFeature = pActNum->IsFeatureSupported(SvxNumRuleFlags::CONTINUOUS);
1689     if(bShowOrient && bAllLevelFeature)
1690     {
1691         m_xOrientFT->show();
1692         m_xOrientLB->show();
1693     }
1694     else
1695     {
1696         m_xOrientFT->hide();
1697         m_xOrientLB->hide();
1698     }
1699     SetModified();
1700     if(!sSelectStyle.isEmpty())
1701     {
1702         m_xCharFmtLB->set_active_text(sSelectStyle);
1703         CharFmtHdl_Impl(*m_xCharFmtLB);
1704         bAutomaticCharStyles = true;
1705     }
1706 }
1707 
1708 void SvxNumOptionsTabPage::CheckForStartValue_Impl(sal_uInt16 nNumberingType)
1709 {
1710     bool bIsNull = m_xStartED->get_value() == 0;
1711     bool bNoZeroAllowed = nNumberingType < SVX_NUM_ARABIC ||
1712                         SVX_NUM_CHARS_UPPER_LETTER_N == nNumberingType ||
1713                         SVX_NUM_CHARS_LOWER_LETTER_N == nNumberingType;
1714     m_xStartED->set_min(bNoZeroAllowed ? 1 : 0);
1715     if (bIsNull && bNoZeroAllowed)
1716         EditModifyHdl_Impl(*m_xStartED);
1717 }
1718 
1719 IMPL_LINK(SvxNumOptionsTabPage, OrientHdl_Impl, weld::ComboBox&, rBox, void)
1720 {
1721     sal_Int32 nPos = rBox.get_active();
1722     nPos ++; // no VERT_NONE
1723 
1724     sal_uInt16 nMask = 1;
1725     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1726     {
1727         if(nActNumLvl & nMask)
1728         {
1729             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
1730             if(SVX_NUM_BITMAP == (aNumFmt.GetNumberingType()&(~LINK_TOKEN)))
1731             {
1732                 const SvxBrushItem* pBrushItem =  aNumFmt.GetBrush();
1733                 const Size& rSize = aNumFmt.GetGraphicSize();
1734                 sal_Int16 eOrient = static_cast<sal_Int16>(nPos);
1735                 aNumFmt.SetGraphicBrush( pBrushItem, &rSize, &eOrient );
1736                 pActNum->SetLevel(i, aNumFmt);
1737             }
1738         }
1739         nMask <<= 1;
1740     }
1741     SetModified(false);
1742 }
1743 
1744 IMPL_LINK(SvxNumOptionsTabPage, SameLevelHdl_Impl, weld::Toggleable&, rBox, void)
1745 {
1746     bool bSet = rBox.get_active();
1747     pActNum->SetContinuousNumbering(bSet);
1748     bool bRepaint = false;
1749     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1750     {
1751         SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
1752         if(aNumFmt.GetNumberingType() != SVX_NUM_NUMBER_NONE)
1753         {
1754             bRepaint = true;
1755             break;
1756         }
1757     }
1758     SetModified(bRepaint);
1759     InitControls();
1760 }
1761 
1762 IMPL_LINK(SvxNumOptionsTabPage, BulColorHdl_Impl, ColorListBox&, rColorBox, void)
1763 {
1764     Color nSetColor = rColorBox.GetSelectEntryColor();
1765 
1766     sal_uInt16 nMask = 1;
1767     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1768     {
1769         if(nActNumLvl & nMask)
1770         {
1771             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
1772             aNumFmt.SetBulletColor(nSetColor);
1773             pActNum->SetLevel(i, aNumFmt);
1774         }
1775         nMask <<= 1;
1776     }
1777     SetModified();
1778 }
1779 
1780 IMPL_LINK(SvxNumOptionsTabPage, BulRelSizeHdl_Impl, weld::MetricSpinButton&, rField, void)
1781 {
1782     sal_uInt16 nRelSize = rField.get_value(FieldUnit::PERCENT);
1783 
1784     sal_uInt16 nMask = 1;
1785     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1786     {
1787         if(nActNumLvl & nMask)
1788         {
1789             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
1790             aNumFmt.SetBulletRelSize(nRelSize);
1791             pActNum->SetLevel(i, aNumFmt);
1792         }
1793         nMask <<= 1;
1794     }
1795     SetModified();
1796 }
1797 
1798 IMPL_LINK(SvxNumOptionsTabPage, GraphicHdl_Impl, const OString&, rIdent, void)
1799 {
1800     OUString                aGrfName;
1801     Size                    aSize;
1802     bool                bSucc(false);
1803     SvxOpenGraphicDialog aGrfDlg(CuiResId(RID_CUISTR_EDIT_GRAPHIC), GetFrameWeld());
1804 
1805     OString sNumber;
1806     if (rIdent.startsWith("gallery", &sNumber))
1807     {
1808         auto idx = sNumber.toUInt32();
1809         if (idx < aGrfNames.size())
1810         {
1811             aGrfName = aGrfNames[idx];
1812             Graphic aGraphic;
1813             if(GalleryExplorer::GetGraphicObj( GALLERY_THEME_BULLETS, idx, &aGraphic))
1814             {
1815                 aSize = SvxNumberFormat::GetGraphicSizeMM100(&aGraphic);
1816                 bSucc = true;
1817             }
1818         }
1819     }
1820     else if (rIdent == "fromfile")
1821     {
1822         aGrfDlg.EnableLink( false );
1823         aGrfDlg.AsLink( false );
1824         if ( !aGrfDlg.Execute() )
1825         {
1826             // memorize selected filter
1827             aGrfName = aGrfDlg.GetPath();
1828 
1829             Graphic aGraphic;
1830             if( !aGrfDlg.GetGraphic(aGraphic) )
1831             {
1832                 aSize = SvxNumberFormat::GetGraphicSizeMM100(&aGraphic);
1833                 bSucc = true;
1834             }
1835         }
1836     }
1837     if(!bSucc)
1838         return;
1839 
1840     aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(eCoreUnit));
1841 
1842     sal_uInt16 nMask = 1;
1843     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1844     {
1845         if(nActNumLvl & nMask)
1846         {
1847             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
1848             aNumFmt.SetCharFormatName(m_sNumCharFmtName);
1849             aNumFmt.SetGraphic(aGrfName);
1850 
1851             // set size for a later comparison
1852             const SvxBrushItem* pBrushItem = aNumFmt.GetBrush();
1853             // initiate asynchronous loading
1854             sal_Int16 eOrient = aNumFmt.GetVertOrient();
1855             aNumFmt.SetGraphicBrush( pBrushItem, &aSize, &eOrient );
1856             aInitSize[i] = aNumFmt.GetGraphicSize();
1857 
1858             pActNum->SetLevel(i, aNumFmt);
1859         }
1860         nMask <<= 1;
1861     }
1862     m_xRatioCB->set_sensitive(true);
1863     m_xWidthFT->set_sensitive(true);
1864     m_xHeightFT->set_sensitive(true);
1865     m_xWidthMF->set_sensitive(true);
1866     m_xHeightMF->set_sensitive(true);
1867     SetMetricValue(*m_xWidthMF, aSize.Width(), eCoreUnit);
1868     SetMetricValue(*m_xHeightMF, aSize.Height(), eCoreUnit);
1869     m_xOrientFT->set_sensitive(true);
1870     m_xOrientLB->set_sensitive(true);
1871     SetModified();
1872     //needed due to asynchronous loading of graphics in the SvxBrushItem
1873     aInvalidateTimer.Start();
1874 }
1875 
1876 IMPL_LINK_NOARG(SvxNumOptionsTabPage, PopupActivateHdl_Impl, weld::Toggleable&, void)
1877 {
1878     if (m_xGalleryMenu)
1879         return;
1880 
1881     m_xGalleryMenu = m_xBuilder->weld_menu("gallerysubmenu");
1882     weld::WaitObject aWait(GetFrameWeld());
1883 
1884     if (!GalleryExplorer::FillObjList(GALLERY_THEME_BULLETS, aGrfNames))
1885         return;
1886 
1887     GalleryExplorer::BeginLocking(GALLERY_THEME_BULLETS);
1888 
1889     Graphic aGraphic;
1890     OUString sGrfName;
1891     ScopedVclPtrInstance< VirtualDevice > pVD;
1892     size_t i = 0;
1893     for (const auto & grfName : aGrfNames)
1894     {
1895         sGrfName = grfName;
1896         OUString sItemId = "gallery" + OUString::number(i);
1897         INetURLObject aObj(sGrfName);
1898         if (aObj.GetProtocol() == INetProtocol::File)
1899         {
1900             // tdf#141334 - only show the last name of the filename without its extension
1901             aObj.removeExtension();
1902             sGrfName = aObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
1903         }
1904         if(GalleryExplorer::GetGraphicObj( GALLERY_THEME_BULLETS, i, &aGraphic))
1905         {
1906             BitmapEx aBitmap(aGraphic.GetBitmapEx());
1907             Size aSize(aBitmap.GetSizePixel());
1908             if(aSize.Width() > MAX_BMP_WIDTH ||
1909                 aSize.Height() > MAX_BMP_HEIGHT)
1910             {
1911                 bool bWidth = aSize.Width() > aSize.Height();
1912                 double nScale = bWidth ?
1913                                     double(MAX_BMP_WIDTH) / static_cast<double>(aSize.Width()):
1914                                         double(MAX_BMP_HEIGHT) / static_cast<double>(aSize.Height());
1915                 aBitmap.Scale(nScale, nScale);
1916             }
1917             pVD->SetOutputSizePixel(aBitmap.GetSizePixel(), false);
1918             pVD->DrawBitmapEx(Point(), aBitmap);
1919             m_xGalleryMenu->append(sItemId, sGrfName, *pVD);
1920         }
1921         else
1922         {
1923             m_xGalleryMenu->append(sItemId, sGrfName);
1924         }
1925         ++i;
1926     }
1927     GalleryExplorer::EndLocking(GALLERY_THEME_BULLETS);
1928 }
1929 
1930 IMPL_LINK_NOARG(SvxNumOptionsTabPage, BulletHdl_Impl, weld::Button&, void)
1931 {
1932     SvxCharacterMap aMap(GetFrameWeld(), nullptr, nullptr);
1933 
1934     sal_uInt16 nMask = 1;
1935     std::optional<vcl::Font> pFmtFont;
1936     bool bSameBullet = true;
1937     sal_UCS4 cBullet = 0;
1938     bool bFirst = true;
1939     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1940     {
1941         if(nActNumLvl & nMask)
1942         {
1943             const SvxNumberFormat&  rCurFmt = pActNum->GetLevel(i);
1944             if(bFirst)
1945             {
1946                  cBullet = rCurFmt.GetBulletChar();
1947             }
1948             else if(rCurFmt.GetBulletChar() != cBullet )
1949             {
1950                 bSameBullet = false;
1951                 break;
1952             }
1953             if(!pFmtFont)
1954                 pFmtFont = rCurFmt.GetBulletFont();
1955             bFirst = false;
1956         }
1957         nMask <<= 1;
1958 
1959     }
1960 
1961     if (pFmtFont)
1962         aMap.SetCharFont(*pFmtFont);
1963     else
1964         aMap.SetCharFont(aActBulletFont);
1965     if (bSameBullet)
1966         aMap.SetChar(cBullet);
1967     if (aMap.run() != RET_OK)
1968         return;
1969 
1970     // change Font Numrules
1971     aActBulletFont = aMap.GetCharFont();
1972 
1973     sal_uInt16 _nMask = 1;
1974     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
1975     {
1976         if(nActNumLvl & _nMask)
1977         {
1978             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
1979             aNumFmt.SetBulletFont(&aActBulletFont);
1980             aNumFmt.SetBulletChar(aMap.GetChar());
1981             pActNum->SetLevel(i, aNumFmt);
1982         }
1983         _nMask <<= 1;
1984     }
1985 
1986     SetModified();
1987 }
1988 
1989 IMPL_LINK( SvxNumOptionsTabPage, SizeHdl_Impl, weld::MetricSpinButton&, rField, void)
1990 {
1991     bool bWidth = &rField == m_xWidthMF.get();
1992     bLastWidthModified = bWidth;
1993     bool bRatio = m_xRatioCB->get_active();
1994     tools::Long nWidthVal = static_cast<tools::Long>(m_xWidthMF->denormalize(m_xWidthMF->get_value(FieldUnit::MM_100TH)));
1995     tools::Long nHeightVal = static_cast<tools::Long>(m_xHeightMF->denormalize(m_xHeightMF->get_value(FieldUnit::MM_100TH)));
1996     nWidthVal = OutputDevice::LogicToLogic( nWidthVal ,
1997                                                 MapUnit::Map100thMM, eCoreUnit );
1998     nHeightVal = OutputDevice::LogicToLogic( nHeightVal,
1999                                                 MapUnit::Map100thMM, eCoreUnit);
2000     double  fSizeRatio;
2001 
2002     bool bRepaint = false;
2003     sal_uInt16 nMask = 1;
2004     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
2005     {
2006         if(nActNumLvl & nMask)
2007         {
2008             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
2009             if(SVX_NUM_BITMAP == (aNumFmt.GetNumberingType()&(~LINK_TOKEN)))
2010             {
2011                 Size aSize(aNumFmt.GetGraphicSize() );
2012                 Size aSaveSize(aSize);
2013 
2014                 if (aInitSize[i].Height())
2015                     fSizeRatio = static_cast<double>(aInitSize[i].Width()) / static_cast<double>(aInitSize[i].Height());
2016                 else
2017                     fSizeRatio = double(1);
2018 
2019                 if(bWidth)
2020                 {
2021                     tools::Long nDelta = nWidthVal - aInitSize[i].Width();
2022                     aSize.setWidth( nWidthVal );
2023                     if (bRatio)
2024                     {
2025                         aSize.setHeight( aInitSize[i].Height() + static_cast<tools::Long>(static_cast<double>(nDelta) / fSizeRatio) );
2026                         m_xHeightMF->set_value(m_xHeightMF->normalize(
2027                             OutputDevice::LogicToLogic( aSize.Height(), eCoreUnit, MapUnit::Map100thMM )),
2028                                 FieldUnit::MM_100TH);
2029                     }
2030                 }
2031                 else
2032                 {
2033                     tools::Long nDelta = nHeightVal - aInitSize[i].Height();
2034                     aSize.setHeight( nHeightVal );
2035                     if (bRatio)
2036                     {
2037                         aSize.setWidth( aInitSize[i].Width() + static_cast<tools::Long>(static_cast<double>(nDelta) * fSizeRatio) );
2038                         m_xWidthMF->set_value(m_xWidthMF->normalize(
2039                             OutputDevice::LogicToLogic( aSize.Width(), eCoreUnit, MapUnit::Map100thMM )),
2040                                 FieldUnit::MM_100TH);
2041                     }
2042                 }
2043                 const SvxBrushItem* pBrushItem =  aNumFmt.GetBrush();
2044                 sal_Int16 eOrient = aNumFmt.GetVertOrient();
2045                 if(aSize != aSaveSize)
2046                     bRepaint = true;
2047                 aNumFmt.SetGraphicBrush( pBrushItem, &aSize, &eOrient );
2048                 pActNum->SetLevel(i, aNumFmt);
2049             }
2050         }
2051         nMask <<= 1;
2052     }
2053     SetModified(bRepaint);
2054 }
2055 
2056 IMPL_LINK(SvxNumOptionsTabPage, RatioHdl_Impl, weld::Toggleable&, rBox, void)
2057 {
2058     if (rBox.get_active())
2059     {
2060         if (bLastWidthModified)
2061             SizeHdl_Impl(*m_xWidthMF);
2062         else
2063             SizeHdl_Impl(*m_xHeightMF);
2064     }
2065 }
2066 
2067 IMPL_LINK_NOARG(SvxNumOptionsTabPage, CharFmtHdl_Impl, weld::ComboBox&, void)
2068 {
2069     bAutomaticCharStyles = false;
2070     sal_Int32 nEntryPos = m_xCharFmtLB->get_active();
2071     OUString sEntry = m_xCharFmtLB->get_active_text();
2072     sal_uInt16 nMask = 1;
2073     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
2074     {
2075         if(nActNumLvl & nMask)
2076         {
2077             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
2078             if( 0 == nEntryPos )
2079                 aNumFmt.SetCharFormatName("");
2080             else
2081             {
2082                 if(SVX_NUM_BITMAP != (aNumFmt.GetNumberingType()&(~LINK_TOKEN)))
2083                     aNumFmt.SetCharFormatName(sEntry);
2084             }
2085             pActNum->SetLevel(i, aNumFmt);
2086         }
2087         nMask <<= 1;
2088     }
2089     SetModified(false);
2090 };
2091 
2092 IMPL_LINK(SvxNumOptionsTabPage, EditModifyHdl_Impl, weld::Entry&, rEdit, void)
2093 {
2094     EditModifyHdl_Impl(&rEdit);
2095 }
2096 
2097 IMPL_LINK(SvxNumOptionsTabPage, SpinModifyHdl_Impl, weld::SpinButton&, rSpinButton, void)
2098 {
2099     EditModifyHdl_Impl(&rSpinButton);
2100 }
2101 
2102 void SvxNumOptionsTabPage::EditModifyHdl_Impl(const weld::Entry* pEdit)
2103 {
2104     bool bPrefixSuffix = (pEdit == m_xPrefixED.get())|| (pEdit == m_xSuffixED.get());
2105     bool bStart = pEdit == m_xStartED.get();
2106     sal_uInt16 nMask = 1;
2107     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
2108     {
2109         if(nActNumLvl & nMask)
2110         {
2111             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
2112             if (bPrefixSuffix)
2113                 aNumFmt.SetListFormat(m_xPrefixED->get_text(), m_xSuffixED->get_text(), i);
2114             else if(bStart)
2115                 aNumFmt.SetStart(m_xStartED->get_value());
2116             pActNum->SetLevel(i, aNumFmt);
2117         }
2118         nMask <<= 1;
2119     }
2120     SetModified();
2121 }
2122 
2123 static tools::Long lcl_DrawGraphic(VirtualDevice& rVDev, const SvxNumberFormat &rFmt, tools::Long nXStart,
2124                         tools::Long nYMiddle, tools::Long nDivision)
2125 {
2126     const SvxBrushItem* pBrushItem = rFmt.GetBrush();
2127     tools::Long nRet = 0;
2128     if(pBrushItem)
2129     {
2130         const Graphic* pGrf = pBrushItem->GetGraphic();
2131         if(pGrf)
2132         {
2133             Size aGSize( rFmt.GetGraphicSize() );
2134             aGSize.setWidth( aGSize.Width() / nDivision );
2135             nRet = aGSize.Width();
2136             aGSize.setHeight( aGSize.Height() / nDivision );
2137             pGrf->Draw(rVDev, Point(nXStart,nYMiddle - ( aGSize.Height() / 2) ),
2138                        rVDev.PixelToLogic( aGSize ) );
2139         }
2140     }
2141     return nRet;
2142 
2143 }
2144 
2145 static tools::Long lcl_DrawBullet(VirtualDevice* pVDev,
2146             const SvxNumberFormat& rFmt, tools::Long nXStart,
2147             tools::Long nYStart, const Size& rSize)
2148 {
2149     vcl::Font aTmpFont(pVDev->GetFont());
2150 
2151     // via Uno it's possible that no font has been set!
2152     vcl::Font aFont(rFmt.GetBulletFont() ? *rFmt.GetBulletFont() : aTmpFont);
2153     Size aTmpSize(rSize);
2154     aTmpSize.setWidth( aTmpSize.Width() * ( rFmt.GetBulletRelSize()) );
2155     aTmpSize.setWidth( aTmpSize.Width() / 100 ) ;
2156     aTmpSize.setHeight( aTmpSize.Height() * ( rFmt.GetBulletRelSize()) );
2157     aTmpSize.setHeight( aTmpSize.Height() / 100 ) ;
2158     // in case of a height of zero it is drawn in original height
2159     if(!aTmpSize.Height())
2160         aTmpSize.setHeight( 1 );
2161     aFont.SetFontSize(aTmpSize);
2162     aFont.SetTransparent(true);
2163     Color aBulletColor = rFmt.GetBulletColor();
2164     if(aBulletColor == COL_AUTO)
2165         aBulletColor = pVDev->GetFillColor().IsDark() ? COL_WHITE : COL_BLACK;
2166     else if(aBulletColor == pVDev->GetFillColor())
2167         aBulletColor.Invert();
2168     aFont.SetColor(aBulletColor);
2169     pVDev->SetFont( aFont );
2170     sal_UCS4 cChar = rFmt.GetBulletChar();
2171     OUString aText(&cChar, 1);
2172     tools::Long nY = nYStart;
2173     nY -= ((aTmpSize.Height() - rSize.Height())/ 2);
2174     pVDev->DrawText( Point(nXStart, nY), aText );
2175     tools::Long nRet = pVDev->GetTextWidth(aText);
2176 
2177     pVDev->SetFont(aTmpFont);
2178     return nRet;
2179 }
2180 
2181 SvxNumberingPreview::SvxNumberingPreview()
2182     : pActNum(nullptr)
2183     , bPosition(false)
2184     , nActLevel(SAL_MAX_UINT16)
2185 {
2186 }
2187 
2188 // paint preview of numeration
2189 void SvxNumberingPreview::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& /*rRect*/)
2190 {
2191     Size aSize(rRenderContext.PixelToLogic(GetOutputSizePixel()));
2192 
2193     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2194     const Color aBackColor = rStyleSettings.GetFieldColor();
2195     const Color aTextColor = rStyleSettings.GetFieldTextColor();
2196 
2197     ScopedVclPtrInstance<VirtualDevice> pVDev(rRenderContext);
2198     pVDev->EnableRTL(rRenderContext.IsRTLEnabled());
2199     pVDev->SetMapMode(rRenderContext.GetMapMode());
2200     pVDev->SetOutputSize(aSize);
2201 
2202     Color aLineColor(COL_LIGHTGRAY);
2203     if (aLineColor == aBackColor)
2204         aLineColor.Invert();
2205     pVDev->SetLineColor(aLineColor);
2206     pVDev->SetFillColor(aBackColor);
2207 
2208     if (pActNum)
2209     {
2210         tools::Long nWidthRelation = 30; // chapter dialog
2211 
2212         // height per level
2213         tools::Long nXStep = aSize.Width() / (pActNum->GetLevelCount() > 1 ? 3 * pActNum->GetLevelCount() : 3);
2214         if (pActNum->GetLevelCount() < 10)
2215             nXStep /= 2;
2216         tools::Long nYStart = 4;
2217         // the whole height mustn't be used for a single level
2218         tools::Long nYStep = (aSize.Height() - 6)/ (pActNum->GetLevelCount() > 1 ? pActNum->GetLevelCount() : 5);
2219 
2220         aStdFont = OutputDevice::GetDefaultFont(DefaultFontType::UI_SANS, MsLangId::getConfiguredSystemLanguage(), GetDefaultFontFlags::OnlyOne);
2221         aStdFont.SetColor(aTextColor);
2222         aStdFont.SetFillColor(aBackColor);
2223 
2224         tools::Long nFontHeight = nYStep * 6 / 10;
2225         if (bPosition)
2226             nFontHeight = nYStep * 15 / 10;
2227         aStdFont.SetFontSize(Size( 0, nFontHeight ));
2228 
2229         SvxNodeNum aNum;
2230         sal_uInt16 nPreNum = pActNum->GetLevel(0).GetStart();
2231 
2232         if (bPosition)
2233         {
2234             tools::Long nLineHeight = nFontHeight * 8 / 7;
2235             sal_uInt8 nStart = 0;
2236             while (!(nActLevel & (1<<nStart)))
2237             {
2238                 nStart++;
2239             }
2240             if (nStart)
2241                 nStart--;
2242             sal_uInt8 nEnd = std::min(sal_uInt8(nStart + 3), sal_uInt8(pActNum->GetLevelCount()));
2243             for (sal_uInt8 nLevel = nStart; nLevel < nEnd; ++nLevel)
2244             {
2245                 const SvxNumberFormat &rFmt = pActNum->GetLevel(nLevel);
2246                 aNum.GetLevelVal()[nLevel] = rFmt.GetStart();
2247 
2248                 tools::Long nXStart( 0 );
2249                 short nTextOffset( 0 );
2250                 tools::Long nNumberXPos( 0 );
2251                 if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION)
2252                 {
2253                     nXStart = rFmt.GetAbsLSpace() / nWidthRelation;
2254                     nTextOffset = rFmt.GetCharTextDistance() / nWidthRelation;
2255                     nNumberXPos = nXStart;
2256                     tools::Long nFirstLineOffset = (-rFmt.GetFirstLineOffset()) / nWidthRelation;
2257 
2258                     if (nFirstLineOffset <= nNumberXPos)
2259                         nNumberXPos = nNumberXPos - nFirstLineOffset;
2260                     else
2261                         nNumberXPos = 0;
2262                     // in draw this is valid
2263                     if (nTextOffset < 0)
2264                         nNumberXPos = nNumberXPos + nTextOffset;
2265                 }
2266                 else if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT)
2267                 {
2268                     const tools::Long nTmpNumberXPos((rFmt.GetIndentAt() + rFmt.GetFirstLineIndent() ) / nWidthRelation);
2269                     if (nTmpNumberXPos < 0)
2270                     {
2271                         nNumberXPos = 0;
2272                     }
2273                     else
2274                     {
2275                         nNumberXPos = nTmpNumberXPos;
2276                     }
2277                 }
2278 
2279                 tools::Long nBulletWidth = 0;
2280                 if (SVX_NUM_BITMAP == (rFmt.GetNumberingType() &(~LINK_TOKEN)))
2281                 {
2282                     tools::Long nYMiddle = nYStart + ( nFontHeight / 2 );
2283                     nBulletWidth = rFmt.IsShowSymbol() ? lcl_DrawGraphic(*pVDev, rFmt, nNumberXPos, nYMiddle, nWidthRelation) : 0;
2284                 }
2285                 else if (SVX_NUM_CHAR_SPECIAL == rFmt.GetNumberingType())
2286                 {
2287                     nBulletWidth =  rFmt.IsShowSymbol() ? lcl_DrawBullet(pVDev.get(), rFmt, nNumberXPos, nYStart, aStdFont.GetFontSize()) : 0;
2288                 }
2289                 else
2290                 {
2291                     pVDev->SetFont(aStdFont);
2292                     aNum.SetLevel(nLevel);
2293                     if (pActNum->IsContinuousNumbering())
2294                         aNum.GetLevelVal()[nLevel] = nPreNum;
2295                     OUString aText(pActNum->MakeNumString( aNum ));
2296                     vcl::Font aSaveFont = pVDev->GetFont();
2297                     vcl::Font aColorFont(aSaveFont);
2298                     Color aTmpBulletColor = rFmt.GetBulletColor();
2299                     if (aTmpBulletColor == COL_AUTO)
2300                         aTmpBulletColor = aBackColor.IsDark() ? COL_WHITE : COL_BLACK;
2301                     else if (aTmpBulletColor == aBackColor)
2302                         aTmpBulletColor.Invert();
2303                     aColorFont.SetColor(aTmpBulletColor);
2304                     pVDev->SetFont(aColorFont);
2305                     pVDev->DrawText(Point(nNumberXPos, nYStart), aText);
2306                     pVDev->SetFont(aSaveFont);
2307                     nBulletWidth = pVDev->GetTextWidth(aText);
2308                     nPreNum++;
2309                 }
2310                 if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT &&
2311                     rFmt.GetLabelFollowedBy() == SvxNumberFormat::SPACE )
2312                 {
2313                     pVDev->SetFont(aStdFont);
2314                     OUString aText(' ');
2315                     pVDev->DrawText( Point(nNumberXPos, nYStart), aText );
2316                     nBulletWidth = nBulletWidth + pVDev->GetTextWidth(aText);
2317                 }
2318 
2319                 tools::Long nTextXPos( 0 );
2320                 if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION)
2321                 {
2322                     nTextXPos = nXStart;
2323                     if (nTextOffset < 0)
2324                          nTextXPos = nTextXPos + nTextOffset;
2325                     if (nNumberXPos + nBulletWidth + nTextOffset > nTextXPos)
2326                         nTextXPos = nNumberXPos + nBulletWidth + nTextOffset;
2327                 }
2328                 else if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT)
2329                 {
2330                     switch (rFmt.GetLabelFollowedBy())
2331                     {
2332                         case SvxNumberFormat::LISTTAB:
2333                         {
2334                             nTextXPos = rFmt.GetListtabPos() / nWidthRelation;
2335                             if (nTextXPos < nNumberXPos + nBulletWidth)
2336                             {
2337                                 nTextXPos = nNumberXPos + nBulletWidth;
2338                             }
2339                         }
2340                         break;
2341                         case SvxNumberFormat::SPACE:
2342                         case SvxNumberFormat::NOTHING:
2343                         case SvxNumberFormat::NEWLINE:
2344                         {
2345                             nTextXPos = nNumberXPos + nBulletWidth;
2346                         }
2347                         break;
2348                     }
2349 
2350                     nXStart = rFmt.GetIndentAt() / nWidthRelation;
2351                 }
2352 
2353                 ::tools::Rectangle aRect1(Point(nTextXPos, nYStart + nFontHeight / 2), Size(aSize.Width() / 2, 2));
2354                 pVDev->SetFillColor(aBackColor);
2355                 pVDev->DrawRect(aRect1);
2356 
2357                 ::tools::Rectangle aRect2(Point(nXStart, nYStart + nLineHeight + nFontHeight / 2 ), Size(aSize.Width() / 2, 2));
2358                 pVDev->DrawRect(aRect2);
2359                 nYStart += 2 * nLineHeight;
2360             }
2361         }
2362         else
2363         {
2364             //#i5153# painting gray or black rectangles as 'normal' numbering text
2365             tools::Long nWidth = pVDev->GetTextWidth("Preview");
2366             tools::Long nTextHeight = pVDev->GetTextHeight();
2367             tools::Long nRectHeight = nTextHeight * 2 / 3;
2368             tools::Long nTopOffset = nTextHeight - nRectHeight;
2369             Color aBlackColor(COL_BLACK);
2370             if (aBlackColor == aBackColor)
2371                 aBlackColor.Invert();
2372 
2373             for (sal_uInt16 nLevel = 0; nLevel < pActNum->GetLevelCount(); ++nLevel, nYStart = nYStart + nYStep)
2374             {
2375                 const SvxNumberFormat &rFmt = pActNum->GetLevel(nLevel);
2376                 aNum.GetLevelVal()[ nLevel ] = rFmt.GetStart();
2377                 tools::Long nXStart( 0 );
2378                 pVDev->SetFillColor( aBackColor );
2379 
2380                 if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION)
2381                 {
2382                     nXStart = rFmt.GetAbsLSpace() / nWidthRelation;
2383                 }
2384                 else if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT)
2385                 {
2386                     const tools::Long nTmpXStart((rFmt.GetIndentAt() + rFmt.GetFirstLineIndent() ) / nWidthRelation);
2387                     if (nTmpXStart < 0)
2388                     {
2389                         nXStart = 0;
2390                     }
2391                     else
2392                     {
2393                         nXStart = nTmpXStart;
2394                     }
2395                 }
2396                 nXStart /= 2;
2397                 nXStart += 2;
2398                 tools::Long nTextOffset = 2 * nXStep;
2399                 if (SVX_NUM_BITMAP == (rFmt.GetNumberingType()&(~LINK_TOKEN)))
2400                 {
2401                     if (rFmt.IsShowSymbol())
2402                     {
2403                         tools::Long nYMiddle = nYStart + ( nFontHeight / 2 );
2404                         nTextOffset = lcl_DrawGraphic(*pVDev, rFmt, nXStart, nYMiddle, nWidthRelation);
2405                         nTextOffset = nTextOffset + nXStep;
2406                     }
2407                 }
2408                 else if (SVX_NUM_CHAR_SPECIAL == rFmt.GetNumberingType())
2409                 {
2410                     if (rFmt.IsShowSymbol())
2411                     {
2412                         nTextOffset =  lcl_DrawBullet(pVDev.get(), rFmt, nXStart, nYStart, aStdFont.GetFontSize());
2413                         nTextOffset = nTextOffset + nXStep;
2414                     }
2415                 }
2416                 else
2417                 {
2418                     vcl::Font aFont(aStdFont);
2419                     Size aTmpSize(aStdFont.GetFontSize());
2420                     if(pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_REL_SIZE))
2421                     {
2422                         aTmpSize.setWidth( aTmpSize.Width() * ( rFmt.GetBulletRelSize()) );
2423                         aTmpSize.setWidth( aTmpSize.Width() / 100 ) ;
2424                         aTmpSize.setHeight( aTmpSize.Height() * ( rFmt.GetBulletRelSize()) );
2425                         aTmpSize.setHeight( aTmpSize.Height() / 100 ) ;
2426                     }
2427                     if(!aTmpSize.Height())
2428                         aTmpSize.setHeight( 1 );
2429                     aFont.SetFontSize(aTmpSize);
2430                     Color aTmpBulletColor = rFmt.GetBulletColor();
2431                     if (aTmpBulletColor == COL_AUTO)
2432                         aTmpBulletColor = aBackColor.IsDark() ? COL_WHITE : COL_BLACK;
2433                     else if (aTmpBulletColor == aBackColor)
2434                         aTmpBulletColor.Invert();
2435                     aFont.SetColor(aTmpBulletColor);
2436                     pVDev->SetFont(aFont);
2437                     aNum.SetLevel( nLevel );
2438                     if (pActNum->IsContinuousNumbering())
2439                         aNum.GetLevelVal()[nLevel] = nPreNum;
2440                     OUString aText(pActNum->MakeNumString(aNum));
2441                     tools::Long nY = nYStart;
2442                     nY -= (pVDev->GetTextHeight() - nTextHeight - pVDev->GetFontMetric().GetDescent());
2443                     pVDev->DrawText(Point(nXStart, nY), aText);
2444                     nTextOffset = pVDev->GetTextWidth(aText);
2445                     nTextOffset = nTextOffset + nXStep;
2446                     nPreNum++;
2447                     pVDev->SetFont(aStdFont);
2448                 }
2449                 //#i5153# the selected rectangle(s) should be black
2450                 if (0 != (nActLevel & (1<<nLevel)))
2451                 {
2452                     pVDev->SetFillColor( aBlackColor );
2453                     pVDev->SetLineColor( aBlackColor );
2454                 }
2455                 else
2456                 {
2457                     //#i5153# unselected levels are gray
2458                     pVDev->SetFillColor( aLineColor );
2459                     pVDev->SetLineColor( aLineColor );
2460                 }
2461                 ::tools::Rectangle aRect1(Point(nXStart + nTextOffset, nYStart + nTopOffset), Size(nWidth, nRectHeight));
2462                 pVDev->DrawRect(aRect1);
2463             }
2464         }
2465     }
2466     rRenderContext.DrawOutDev(Point(), aSize, Point(), aSize, *pVDev);
2467 }
2468 
2469 
2470 //See uiconfig/swriter/ui/outlinepositionpage.ui for effectively a duplicate
2471 //dialog to this one, except with a different preview window impl.
2472 //TODO, determine if SwNumPositionTabPage and SvxNumPositionTabPage can be
2473 //merged
2474 SvxNumPositionTabPage::SvxNumPositionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
2475     : SfxTabPage(pPage, pController, "cui/ui/numberingpositionpage.ui", "NumberingPositionPage", &rSet)
2476     , m_pLevelHdlEvent(nullptr)
2477     , nActNumLvl(1)
2478     , nNumItemId(SID_ATTR_NUMBERING_RULE)
2479     , bModified(false)
2480     , bPreset(false)
2481     , bInInintControl(false)
2482     , bLabelAlignmentPosAndSpaceModeActive(false)
2483     , m_xLevelLB(m_xBuilder->weld_tree_view("levellb"))
2484     , m_xDistBorderFT(m_xBuilder->weld_label("indent"))
2485     , m_xDistBorderMF(m_xBuilder->weld_metric_spin_button("indentmf", FieldUnit::CM))
2486     , m_xRelativeCB(m_xBuilder->weld_check_button("relative"))
2487     , m_xIndentFT(m_xBuilder->weld_label("numberingwidth"))
2488     , m_xIndentMF(m_xBuilder->weld_metric_spin_button("numberingwidthmf", FieldUnit::CM))
2489     , m_xDistNumFT(m_xBuilder->weld_label("numdist"))
2490     , m_xDistNumMF(m_xBuilder->weld_metric_spin_button("numdistmf", FieldUnit::CM))
2491     , m_xAlignFT(m_xBuilder->weld_label("numalign"))
2492     , m_xAlignLB(m_xBuilder->weld_combo_box("numalignlb"))
2493     , m_xLabelFollowedByFT(m_xBuilder->weld_label("numfollowedby"))
2494     , m_xLabelFollowedByLB(m_xBuilder->weld_combo_box("numfollowedbylb"))
2495     , m_xListtabFT(m_xBuilder->weld_label("at"))
2496     , m_xListtabMF(m_xBuilder->weld_metric_spin_button("atmf", FieldUnit::CM))
2497     , m_xAlign2FT(m_xBuilder->weld_label("num2align"))
2498     , m_xAlign2LB(m_xBuilder->weld_combo_box("num2alignlb"))
2499     , m_xAlignedAtFT(m_xBuilder->weld_label("alignedat"))
2500     , m_xAlignedAtMF(m_xBuilder->weld_metric_spin_button("alignedatmf", FieldUnit::CM))
2501     , m_xIndentAtFT(m_xBuilder->weld_label("indentat"))
2502     , m_xIndentAtMF(m_xBuilder->weld_metric_spin_button("indentatmf", FieldUnit::CM))
2503     , m_xStandardPB(m_xBuilder->weld_button("standard"))
2504     , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreviewWIN))
2505 {
2506     SetExchangeSupport();
2507 
2508     // set metric
2509     FieldUnit eFUnit = GetModuleFieldUnit(rSet);
2510 
2511     SetFieldUnit( *m_xDistBorderMF, eFUnit );
2512     SetFieldUnit( *m_xIndentMF, eFUnit );
2513     SetFieldUnit( *m_xDistNumMF, eFUnit );
2514 
2515     m_xAlignedAtMF->set_range(0, SAL_MAX_INT32, FieldUnit::NONE);
2516     m_xListtabMF->set_range(0, SAL_MAX_INT32, FieldUnit::NONE);
2517     m_xIndentAtMF->set_range(0, SAL_MAX_INT32, FieldUnit::NONE);
2518 
2519     m_xRelativeCB->set_active(true);
2520     m_xAlignLB->connect_changed(LINK(this, SvxNumPositionTabPage, EditModifyHdl_Impl));
2521     m_xAlign2LB->connect_changed(LINK(this, SvxNumPositionTabPage, EditModifyHdl_Impl));
2522     for ( sal_Int32 i = 0; i < m_xAlignLB->get_count(); ++i )
2523     {
2524         m_xAlign2LB->append_text(m_xAlignLB->get_text(i));
2525     }
2526 
2527     Link<weld::MetricSpinButton&,void> aLk3 = LINK(this, SvxNumPositionTabPage, DistanceHdl_Impl);
2528     m_xDistBorderMF->connect_value_changed(aLk3);
2529     m_xDistNumMF->connect_value_changed(aLk3);
2530     m_xIndentMF->connect_value_changed(aLk3);
2531 
2532     m_xLabelFollowedByLB->connect_changed(LINK(this, SvxNumPositionTabPage, LabelFollowedByHdl_Impl));
2533 
2534     m_xListtabMF->connect_value_changed(LINK(this, SvxNumPositionTabPage, ListtabPosHdl_Impl));
2535     m_xAlignedAtMF->connect_value_changed(LINK(this, SvxNumPositionTabPage, AlignAtHdl_Impl));
2536     m_xIndentAtMF->connect_value_changed(LINK(this, SvxNumPositionTabPage, IndentAtHdl_Impl));
2537 
2538     m_xLevelLB->set_selection_mode(SelectionMode::Multiple);
2539     m_xLevelLB->connect_changed(LINK(this, SvxNumPositionTabPage, LevelHdl_Impl));
2540     m_xRelativeCB->connect_toggled(LINK(this, SvxNumPositionTabPage, RelativeHdl_Impl));
2541     m_xStandardPB->connect_clicked(LINK(this, SvxNumPositionTabPage, StandardHdl_Impl));
2542 
2543     m_xRelativeCB->set_active(bLastRelative);
2544     m_aPreviewWIN.SetPositionMode();
2545     eCoreUnit = rSet.GetPool()->GetMetric(rSet.GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE));
2546 }
2547 
2548 SvxNumPositionTabPage::~SvxNumPositionTabPage()
2549 {
2550     if (m_pLevelHdlEvent)
2551     {
2552         Application::RemoveUserEvent(m_pLevelHdlEvent);
2553         m_pLevelHdlEvent = nullptr;
2554     }
2555     m_xPreviewWIN.reset();
2556 }
2557 
2558 /*-------------------------------------------------------*/
2559 
2560 void SvxNumPositionTabPage::InitControls()
2561 {
2562     bInInintControl = true;
2563     const bool bRelative = !bLabelAlignmentPosAndSpaceModeActive &&
2564                      m_xRelativeCB->get_sensitive() && m_xRelativeCB->get_active();
2565     const bool bSingleSelection = m_xLevelLB->count_selected_rows() == 1 &&
2566                             SAL_MAX_UINT16 != nActNumLvl;
2567 
2568     m_xDistBorderMF->set_sensitive( !bLabelAlignmentPosAndSpaceModeActive &&
2569                           ( bSingleSelection || bRelative ) );
2570     m_xDistBorderFT->set_sensitive( !bLabelAlignmentPosAndSpaceModeActive &&
2571                           ( bSingleSelection || bRelative ) );
2572 
2573     bool bSetDistEmpty = false;
2574     bool bSameDistBorderNum = !bLabelAlignmentPosAndSpaceModeActive;
2575     bool bSameDist      = !bLabelAlignmentPosAndSpaceModeActive;
2576     bool bSameIndent    = !bLabelAlignmentPosAndSpaceModeActive;
2577     bool bSameAdjust    = true;
2578 
2579     bool bSameLabelFollowedBy = bLabelAlignmentPosAndSpaceModeActive;
2580     bool bSameListtab = bLabelAlignmentPosAndSpaceModeActive;
2581     bool bSameAlignAt = bLabelAlignmentPosAndSpaceModeActive;
2582     bool bSameIndentAt = bLabelAlignmentPosAndSpaceModeActive;
2583 
2584     const SvxNumberFormat* aNumFmtArr[SVX_MAX_NUM];
2585     sal_uInt16 nMask = 1;
2586     sal_uInt16 nLvl = SAL_MAX_UINT16;
2587     tools::Long nFirstBorderTextRelative = -1;
2588     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
2589     {
2590         aNumFmtArr[i] = &pActNum->GetLevel(i);
2591         if(nActNumLvl & nMask)
2592         {
2593             if(SAL_MAX_UINT16 == nLvl)
2594                 nLvl = i;
2595 
2596             if( i > nLvl)
2597             {
2598                 bSameAdjust &= aNumFmtArr[i]->GetNumAdjust() == aNumFmtArr[nLvl]->GetNumAdjust();
2599                 if ( !bLabelAlignmentPosAndSpaceModeActive )
2600                 {
2601                     if(bRelative)
2602                     {
2603                         if(nFirstBorderTextRelative == -1)
2604                             nFirstBorderTextRelative =
2605                             (aNumFmtArr[i]->GetAbsLSpace() + aNumFmtArr[i]->GetFirstLineOffset() -
2606                             aNumFmtArr[i - 1]->GetAbsLSpace() + aNumFmtArr[i - 1]->GetFirstLineOffset());
2607                         else
2608                             bSameDistBorderNum &= nFirstBorderTextRelative ==
2609                             (aNumFmtArr[i]->GetAbsLSpace() + aNumFmtArr[i]->GetFirstLineOffset() -
2610                             aNumFmtArr[i - 1]->GetAbsLSpace() + aNumFmtArr[i - 1]->GetFirstLineOffset());
2611                     }
2612                     else
2613                         bSameDistBorderNum &=
2614                         aNumFmtArr[i]->GetAbsLSpace() - aNumFmtArr[i]->GetFirstLineOffset() ==
2615                         aNumFmtArr[i - 1]->GetAbsLSpace() - aNumFmtArr[i - 1]->GetFirstLineOffset();
2616 
2617                     bSameDist       &= aNumFmtArr[i]->GetCharTextDistance() == aNumFmtArr[nLvl]->GetCharTextDistance();
2618                     bSameIndent     &= aNumFmtArr[i]->GetFirstLineOffset() == aNumFmtArr[nLvl]->GetFirstLineOffset();
2619                 }
2620                 else
2621                 {
2622                     bSameLabelFollowedBy &=
2623                         aNumFmtArr[i]->GetLabelFollowedBy() == aNumFmtArr[nLvl]->GetLabelFollowedBy();
2624                     bSameListtab &=
2625                         aNumFmtArr[i]->GetListtabPos() == aNumFmtArr[nLvl]->GetListtabPos();
2626                     bSameAlignAt &=
2627                         ( ( aNumFmtArr[i]->GetIndentAt() + aNumFmtArr[i]->GetFirstLineIndent() )
2628                             == ( aNumFmtArr[nLvl]->GetIndentAt() + aNumFmtArr[nLvl]->GetFirstLineIndent() ) );
2629                     bSameIndentAt &=
2630                         aNumFmtArr[i]->GetIndentAt() == aNumFmtArr[nLvl]->GetIndentAt();
2631                 }
2632             }
2633         }
2634         nMask <<= 1;
2635 
2636     }
2637     if (SVX_MAX_NUM <= nLvl)
2638     {
2639         OSL_ENSURE(false, "cannot happen.");
2640         return;
2641     }
2642 
2643     if(bSameDistBorderNum)
2644     {
2645         tools::Long nDistBorderNum;
2646         if(bRelative)
2647         {
2648             nDistBorderNum = static_cast<tools::Long>(aNumFmtArr[nLvl]->GetAbsLSpace())+ aNumFmtArr[nLvl]->GetFirstLineOffset();
2649             if(nLvl)
2650                 nDistBorderNum -= static_cast<tools::Long>(aNumFmtArr[nLvl - 1]->GetAbsLSpace())+ aNumFmtArr[nLvl - 1]->GetFirstLineOffset();
2651         }
2652         else
2653         {
2654             nDistBorderNum = static_cast<tools::Long>(aNumFmtArr[nLvl]->GetAbsLSpace())+ aNumFmtArr[nLvl]->GetFirstLineOffset();
2655         }
2656         SetMetricValue(*m_xDistBorderMF, nDistBorderNum, eCoreUnit);
2657     }
2658     else
2659         bSetDistEmpty = true;
2660 
2661     if(bSameDist)
2662         SetMetricValue(*m_xDistNumMF, aNumFmtArr[nLvl]->GetCharTextDistance(), eCoreUnit);
2663     else
2664         m_xDistNumMF->set_text("");
2665     if(bSameIndent)
2666         SetMetricValue(*m_xIndentMF, - aNumFmtArr[nLvl]->GetFirstLineOffset(), eCoreUnit);
2667     else
2668         m_xIndentMF->set_text("");
2669 
2670     if(bSameAdjust)
2671     {
2672         sal_Int32 nPos = 1; // centered
2673         if(aNumFmtArr[nLvl]->GetNumAdjust() == SvxAdjust::Left)
2674             nPos = 0;
2675         else if(aNumFmtArr[nLvl]->GetNumAdjust() == SvxAdjust::Right)
2676             nPos = 2;
2677         m_xAlignLB->set_active(nPos);
2678         m_xAlign2LB->set_active(nPos);
2679     }
2680     else
2681     {
2682         m_xAlignLB->set_active(-1);
2683         m_xAlign2LB->set_active(-1);
2684     }
2685 
2686     if ( bSameLabelFollowedBy )
2687     {
2688         sal_Int32 nPos = 0; // LISTTAB
2689         if ( aNumFmtArr[nLvl]->GetLabelFollowedBy() == SvxNumberFormat::SPACE )
2690         {
2691             nPos = 1;
2692         }
2693         else if ( aNumFmtArr[nLvl]->GetLabelFollowedBy() == SvxNumberFormat::NOTHING )
2694         {
2695             nPos = 2;
2696         }
2697         else if ( aNumFmtArr[nLvl]->GetLabelFollowedBy() == SvxNumberFormat::NEWLINE )
2698         {
2699             nPos = 3;
2700         }
2701         m_xLabelFollowedByLB->set_active(nPos);
2702     }
2703     else
2704     {
2705         m_xLabelFollowedByLB->set_active(-1);
2706     }
2707 
2708     if ( aNumFmtArr[nLvl]->GetLabelFollowedBy() == SvxNumberFormat::LISTTAB )
2709     {
2710         m_xListtabFT->set_sensitive(true);
2711         m_xListtabMF->set_sensitive(true);
2712         if ( bSameListtab )
2713         {
2714             SetMetricValue(*m_xListtabMF, aNumFmtArr[nLvl]->GetListtabPos(), eCoreUnit);
2715         }
2716         else
2717         {
2718             m_xListtabMF->set_text("");
2719         }
2720     }
2721     else
2722     {
2723         m_xListtabFT->set_sensitive(false);
2724         m_xListtabMF->set_sensitive(false);
2725         m_xListtabMF->set_text("");
2726     }
2727 
2728     if ( bSameAlignAt )
2729     {
2730         SetMetricValue(*m_xAlignedAtMF,
2731                         aNumFmtArr[nLvl]->GetIndentAt() + aNumFmtArr[nLvl]->GetFirstLineIndent(),
2732                         eCoreUnit);
2733     }
2734     else
2735     {
2736         m_xAlignedAtMF->set_text("");
2737     }
2738 
2739     if ( bSameIndentAt )
2740     {
2741         SetMetricValue(*m_xIndentAtMF, aNumFmtArr[nLvl]->GetIndentAt(), eCoreUnit);
2742     }
2743     else
2744     {
2745         m_xIndentAtMF->set_text("");
2746     }
2747 
2748     if ( bSetDistEmpty )
2749         m_xDistBorderMF->set_text("");
2750 
2751     bInInintControl = false;
2752 }
2753 
2754 void SvxNumPositionTabPage::ActivatePage(const SfxItemSet& rSet)
2755 {
2756     sal_uInt16 nTmpNumLvl = 1;
2757     const SfxItemSet* pExampleSet = GetDialogExampleSet();
2758     if(pExampleSet)
2759     {
2760         if(const SfxBoolItem* pPresetItem = pExampleSet->GetItemIfSet(SID_PARAM_NUM_PRESET, false))
2761             bPreset = pPresetItem->GetValue();
2762         if(const SfxUInt16Item* pLevelItem = pExampleSet->GetItemIfSet(SID_PARAM_CUR_NUM_LEVEL, false))
2763             nTmpNumLvl = pLevelItem->GetValue();
2764     }
2765     if(const SvxNumBulletItem* pBulletItem = rSet.GetItemIfSet(nNumItemId, false))
2766     {
2767         pSaveNum.reset( new SvxNumRule(pBulletItem->GetNumRule()) );
2768     }
2769     bModified = (!pActNum->Get( 0 ) || bPreset);
2770     if(*pSaveNum != *pActNum ||
2771         nActNumLvl != nTmpNumLvl )
2772     {
2773         *pActNum = *pSaveNum;
2774         nActNumLvl = nTmpNumLvl;
2775         sal_uInt16 nMask = 1;
2776         m_xLevelLB->unselect_all();
2777         if (nActNumLvl == SAL_MAX_UINT16)
2778             m_xLevelLB->select(pActNum->GetLevelCount());
2779         if (nActNumLvl != SAL_MAX_UINT16)
2780             for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
2781             {
2782                 if (nActNumLvl & nMask)
2783                     m_xLevelLB->select(i);
2784                 nMask <<= 1 ;
2785             }
2786         m_xRelativeCB->set_sensitive(nActNumLvl != 1);
2787 
2788         InitPosAndSpaceMode();
2789         ShowControlsDependingOnPosAndSpaceMode();
2790 
2791         InitControls();
2792     }
2793     m_aPreviewWIN.SetLevel(nActNumLvl);
2794     m_aPreviewWIN.Invalidate();
2795 }
2796 
2797 DeactivateRC SvxNumPositionTabPage::DeactivatePage(SfxItemSet *_pSet)
2798 {
2799     if(_pSet)
2800     {
2801         if (m_xDistBorderMF->get_sensitive())
2802             DistanceHdl_Impl(*m_xDistBorderMF);
2803         DistanceHdl_Impl(*m_xIndentMF);
2804         FillItemSet(_pSet);
2805     }
2806     return DeactivateRC::LeavePage;
2807 }
2808 
2809 bool SvxNumPositionTabPage::FillItemSet( SfxItemSet* rSet )
2810 {
2811     rSet->Put(SfxUInt16Item(SID_PARAM_CUR_NUM_LEVEL, nActNumLvl));
2812 
2813     if(bModified && pActNum)
2814     {
2815         *pSaveNum = *pActNum;
2816         rSet->Put(SvxNumBulletItem( *pSaveNum, nNumItemId ));
2817         rSet->Put(SfxBoolItem(SID_PARAM_NUM_PRESET, false));
2818     }
2819     return bModified;
2820 }
2821 
2822 void SvxNumPositionTabPage::Reset( const SfxItemSet* rSet )
2823 {
2824     // in Draw the item exists as WhichId, in Writer only as SlotId
2825     const SvxNumBulletItem* pItem =
2826         rSet->GetItemIfSet(SID_ATTR_NUMBERING_RULE, false);
2827     if(!pItem)
2828     {
2829         nNumItemId = rSet->GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE);
2830         pItem = rSet->GetItemIfSet(nNumItemId, false);
2831 
2832         if( !pItem )
2833         {
2834             pItem = & rSet->Get( nNumItemId );
2835         }
2836     }
2837     DBG_ASSERT(pItem, "no item found!");
2838     pSaveNum.reset( new SvxNumRule(pItem->GetNumRule()) );
2839 
2840     // insert levels
2841     if (!m_xLevelLB->count_selected_rows())
2842     {
2843         for(sal_uInt16 i = 1; i <= pSaveNum->GetLevelCount(); i++)
2844             m_xLevelLB->append_text(OUString::number(i));
2845         if(pSaveNum->GetLevelCount() > 1)
2846         {
2847             OUString sEntry = "1 - " + OUString::number( pSaveNum->GetLevelCount() );
2848             m_xLevelLB->append_text(sEntry);
2849             m_xLevelLB->select_text(sEntry);
2850         }
2851         else
2852             m_xLevelLB->select(0);
2853     }
2854     else
2855         m_xLevelLB->select(m_xLevelLB->count_selected_rows() - 1);
2856     sal_uInt16 nMask = 1;
2857     m_xLevelLB->unselect_all();
2858     if (nActNumLvl == SAL_MAX_UINT16)
2859     {
2860         m_xLevelLB->select(pSaveNum->GetLevelCount());
2861     }
2862     else
2863     {
2864         for(sal_uInt16 i = 0; i < pSaveNum->GetLevelCount(); i++)
2865         {
2866             if(nActNumLvl & nMask)
2867                 m_xLevelLB->select(i);
2868             nMask <<= 1;
2869         }
2870     }
2871 
2872     if(!pActNum)
2873         pActNum.reset( new SvxNumRule(*pSaveNum) );
2874     else if(*pSaveNum != *pActNum)
2875         *pActNum = *pSaveNum;
2876     m_aPreviewWIN.SetNumRule(pActNum.get());
2877 
2878     InitPosAndSpaceMode();
2879     ShowControlsDependingOnPosAndSpaceMode();
2880 
2881     InitControls();
2882     bModified = false;
2883 }
2884 
2885 void SvxNumPositionTabPage::InitPosAndSpaceMode()
2886 {
2887     if ( pActNum == nullptr )
2888     {
2889         SAL_WARN( "cui.tabpages",
2890                 "<SvxNumPositionTabPage::InitPosAndSpaceMode()> - misusage of method -> <pAktNum> has to be already set!" );
2891         return;
2892     }
2893 
2894     SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode =
2895                                             SvxNumberFormat::LABEL_ALIGNMENT;
2896     sal_uInt16 nMask = 1;
2897     for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); ++i )
2898     {
2899         if(nActNumLvl & nMask)
2900         {
2901             SvxNumberFormat aNumFmt( pActNum->GetLevel(i) );
2902             ePosAndSpaceMode = aNumFmt.GetPositionAndSpaceMode();
2903             if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
2904             {
2905                 break;
2906             }
2907         }
2908         nMask <<= 1;
2909     }
2910 
2911     bLabelAlignmentPosAndSpaceModeActive =
2912                     ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT;
2913 }
2914 
2915 void SvxNumPositionTabPage::ShowControlsDependingOnPosAndSpaceMode()
2916 {
2917     m_xDistBorderFT->set_visible( !bLabelAlignmentPosAndSpaceModeActive );
2918     m_xDistBorderMF->set_visible( !bLabelAlignmentPosAndSpaceModeActive );
2919     m_xRelativeCB->set_visible( !bLabelAlignmentPosAndSpaceModeActive );
2920     m_xIndentFT->set_visible( !bLabelAlignmentPosAndSpaceModeActive );
2921     m_xIndentMF->set_visible( !bLabelAlignmentPosAndSpaceModeActive );
2922     m_xDistNumFT->set_visible( !bLabelAlignmentPosAndSpaceModeActive &&
2923                     pActNum->IsFeatureSupported(SvxNumRuleFlags::CONTINUOUS) );
2924     m_xDistNumMF->set_visible( !bLabelAlignmentPosAndSpaceModeActive &&
2925                     pActNum->IsFeatureSupported(SvxNumRuleFlags::CONTINUOUS));
2926     m_xAlignFT->set_visible( !bLabelAlignmentPosAndSpaceModeActive );
2927     m_xAlignLB->set_visible( !bLabelAlignmentPosAndSpaceModeActive );
2928 
2929     m_xLabelFollowedByFT->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2930     m_xLabelFollowedByLB->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2931     m_xListtabFT->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2932     m_xListtabMF->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2933     m_xAlign2FT->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2934     m_xAlign2LB->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2935     m_xAlignedAtFT->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2936     m_xAlignedAtMF->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2937     m_xIndentAtFT->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2938     m_xIndentAtMF->set_visible( bLabelAlignmentPosAndSpaceModeActive );
2939 }
2940 
2941 std::unique_ptr<SfxTabPage> SvxNumPositionTabPage::Create(weld::Container* pPage, weld::DialogController* pController,
2942                                                  const SfxItemSet* rAttrSet)
2943 {
2944     return std::make_unique<SvxNumPositionTabPage>(pPage, pController, *rAttrSet);
2945 }
2946 
2947 void SvxNumPositionTabPage::SetMetric(FieldUnit eMetric)
2948 {
2949     if (eMetric == FieldUnit::MM)
2950     {
2951         m_xDistBorderMF->set_digits(1);
2952         m_xDistNumMF->set_digits(1);
2953         m_xIndentMF->set_digits(1);
2954         m_xListtabMF->set_digits(1);
2955         m_xAlignedAtMF->set_digits(1);
2956         m_xIndentAtMF->set_digits(1);
2957     }
2958     m_xDistBorderMF->set_unit(eMetric);
2959     m_xDistNumMF->set_unit(eMetric);
2960     m_xIndentMF->set_unit(eMetric);
2961     m_xListtabMF->set_unit(eMetric);
2962     m_xAlignedAtMF->set_unit(eMetric);
2963     m_xIndentAtMF->set_unit(eMetric);
2964 }
2965 
2966 IMPL_LINK_NOARG(SvxNumPositionTabPage, EditModifyHdl_Impl, weld::ComboBox&, void)
2967 {
2968     sal_uInt16 nMask = 1;
2969     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
2970     {
2971         if(nActNumLvl & nMask)
2972         {
2973             SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
2974 
2975             const sal_Int32 nPos = m_xAlignLB->get_visible()
2976                                 ? m_xAlignLB->get_active()
2977                                 : m_xAlign2LB->get_active();
2978             SvxAdjust eAdjust = SvxAdjust::Center;
2979             if(nPos == 0)
2980                 eAdjust = SvxAdjust::Left;
2981             else if(nPos == 2)
2982                 eAdjust = SvxAdjust::Right;
2983             aNumFmt.SetNumAdjust( eAdjust );
2984             pActNum->SetLevel(i, aNumFmt);
2985         }
2986         nMask <<= 1;
2987     }
2988     SetModified();
2989 }
2990 
2991 IMPL_LINK_NOARG(SvxNumPositionTabPage, LevelHdl_Impl, weld::TreeView&, void)
2992 {
2993     if (m_pLevelHdlEvent)
2994         return;
2995     // tdf#127120 multiselection may be implemented by deselect follow by select so
2996     // fire off the handler to happen on next event loop and only process the
2997     // final state
2998     m_pLevelHdlEvent = Application::PostUserEvent(LINK(this, SvxNumPositionTabPage, LevelHdl));
2999 }
3000 
3001 IMPL_LINK_NOARG(SvxNumPositionTabPage, LevelHdl, void*, void)
3002 {
3003     m_pLevelHdlEvent = nullptr;
3004 
3005     sal_uInt16 nSaveNumLvl = nActNumLvl;
3006     nActNumLvl = 0;
3007     std::vector<int> aSelectedRows = m_xLevelLB->get_selected_rows();
3008     if (std::find(aSelectedRows.begin(), aSelectedRows.end(), pActNum->GetLevelCount()) != aSelectedRows.end() &&
3009             (aSelectedRows.size() == 1 || nSaveNumLvl != 0xffff))
3010     {
3011         nActNumLvl = 0xFFFF;
3012         for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++ )
3013             m_xLevelLB->unselect(i);
3014     }
3015     else if (!aSelectedRows.empty())
3016     {
3017         sal_uInt16 nMask = 1;
3018         for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++ )
3019         {
3020             if (std::find(aSelectedRows.begin(), aSelectedRows.end(), i) != aSelectedRows.end())
3021                 nActNumLvl |= nMask;
3022             nMask <<= 1;
3023         }
3024         m_xLevelLB->unselect(pActNum->GetLevelCount());
3025     }
3026     else
3027     {
3028         nActNumLvl = nSaveNumLvl;
3029         sal_uInt16 nMask = 1;
3030         for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++ )
3031         {
3032             if(nActNumLvl & nMask)
3033             {
3034                 m_xLevelLB->select(i);
3035                 break;
3036             }
3037             nMask <<=1;
3038         }
3039     }
3040     m_xRelativeCB->set_sensitive(nActNumLvl != 1);
3041     SetModified();
3042     InitPosAndSpaceMode();
3043     ShowControlsDependingOnPosAndSpaceMode();
3044     InitControls();
3045 }
3046 
3047 IMPL_LINK(SvxNumPositionTabPage, DistanceHdl_Impl, weld::MetricSpinButton&, rFld, void)
3048 {
3049     if(bInInintControl)
3050         return;
3051     tools::Long nValue = GetCoreValue(rFld, eCoreUnit);
3052     sal_uInt16 nMask = 1;
3053     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
3054     {
3055         if(nActNumLvl & nMask)
3056         {
3057             SvxNumberFormat aNumFmt( pActNum->GetLevel( i ) );
3058             if (&rFld == m_xDistBorderMF.get())
3059             {
3060 
3061                 if (m_xRelativeCB->get_active())
3062                 {
3063                     if(0 == i)
3064                     {
3065                         auto const nTmp = aNumFmt.GetFirstLineOffset();
3066                         aNumFmt.SetAbsLSpace( nValue - nTmp);
3067                     }
3068                     else
3069                     {
3070                         tools::Long nTmp = pActNum->GetLevel( i - 1 ).GetAbsLSpace() +
3071                                     pActNum->GetLevel( i - 1 ).GetFirstLineOffset() -
3072                                     pActNum->GetLevel( i ).GetFirstLineOffset();
3073 
3074                         aNumFmt.SetAbsLSpace( nValue + nTmp);
3075                     }
3076                 }
3077                 else
3078                 {
3079                     aNumFmt.SetAbsLSpace( nValue - aNumFmt.GetFirstLineOffset());
3080                 }
3081             }
3082             else if (&rFld == m_xDistNumMF.get())
3083             {
3084                 aNumFmt.SetCharTextDistance( static_cast<short>(nValue) );
3085             }
3086             else if (&rFld == m_xIndentMF.get())
3087             {
3088                 // together with the FirstLineOffset the AbsLSpace must be changed, too
3089                 tools::Long nDiff = nValue + aNumFmt.GetFirstLineOffset();
3090                 auto const nAbsLSpace = aNumFmt.GetAbsLSpace();
3091                 aNumFmt.SetAbsLSpace(nAbsLSpace + nDiff);
3092                 aNumFmt.SetFirstLineOffset( -nValue );
3093             }
3094 
3095             pActNum->SetLevel( i, aNumFmt );
3096         }
3097         nMask <<= 1;
3098     }
3099 
3100     SetModified();
3101     if (!m_xDistBorderMF->get_sensitive())
3102     {
3103         m_xDistBorderMF->set_text("");
3104     }
3105 }
3106 
3107 IMPL_LINK(SvxNumPositionTabPage, RelativeHdl_Impl, weld::Toggleable&, rBox, void)
3108 {
3109     bool bOn = rBox.get_active();
3110     bool bSingleSelection = m_xLevelLB->count_selected_rows() == 1 && SAL_MAX_UINT16 != nActNumLvl;
3111     bool bSetValue = false;
3112     tools::Long nValue = 0;
3113     if(bOn || bSingleSelection)
3114     {
3115         sal_uInt16 nMask = 1;
3116         bool bFirst = true;
3117         bSetValue = true;
3118         for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
3119         {
3120             if(nActNumLvl & nMask)
3121             {
3122                 const SvxNumberFormat &rNumFmt = pActNum->GetLevel(i);
3123                 if(bFirst)
3124                 {
3125                     nValue = rNumFmt.GetAbsLSpace() + rNumFmt.GetFirstLineOffset();
3126                     if(bOn && i)
3127                         nValue -= (pActNum->GetLevel(i - 1).GetAbsLSpace() + pActNum->GetLevel(i - 1).GetFirstLineOffset());
3128                 }
3129                 else
3130                     bSetValue = nValue ==
3131                         (rNumFmt.GetAbsLSpace() + rNumFmt.GetFirstLineOffset()) -
3132                             (pActNum->GetLevel(i - 1).GetAbsLSpace() + pActNum->GetLevel(i - 1).GetFirstLineOffset());
3133                 bFirst = false;
3134             }
3135             nMask <<= 1;
3136         }
3137 
3138     }
3139     if(bSetValue)
3140         SetMetricValue(*m_xDistBorderMF, nValue,   eCoreUnit);
3141     else
3142         m_xDistBorderMF->set_text("");
3143     m_xDistBorderMF->set_sensitive(bOn || bSingleSelection);
3144     m_xDistBorderFT->set_sensitive(bOn || bSingleSelection);
3145     bLastRelative = bOn;
3146 }
3147 
3148 IMPL_LINK_NOARG(SvxNumPositionTabPage, LabelFollowedByHdl_Impl, weld::ComboBox&, void)
3149 {
3150     // determine value to be set at the chosen list levels
3151     SvxNumberFormat::LabelFollowedBy eLabelFollowedBy = SvxNumberFormat::LISTTAB;
3152     {
3153         const auto nPos = m_xLabelFollowedByLB->get_active();
3154         if ( nPos == 1 )
3155         {
3156             eLabelFollowedBy = SvxNumberFormat::SPACE;
3157         }
3158         else if ( nPos == 2 )
3159         {
3160             eLabelFollowedBy = SvxNumberFormat::NOTHING;
3161         }
3162         else if ( nPos == 3 )
3163         {
3164             eLabelFollowedBy = SvxNumberFormat::NEWLINE;
3165         }
3166     }
3167 
3168     // set value at the chosen list levels
3169     bool bSameListtabPos = true;
3170     sal_uInt16 nFirstLvl = SAL_MAX_UINT16;
3171     sal_uInt16 nMask = 1;
3172     for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); ++i )
3173     {
3174         if ( nActNumLvl & nMask )
3175         {
3176             SvxNumberFormat aNumFmt( pActNum->GetLevel(i) );
3177             aNumFmt.SetLabelFollowedBy( eLabelFollowedBy );
3178             pActNum->SetLevel( i, aNumFmt );
3179 
3180             if ( nFirstLvl == SAL_MAX_UINT16 )
3181             {
3182                 nFirstLvl = i;
3183             }
3184             else
3185             {
3186                 bSameListtabPos &= aNumFmt.GetListtabPos() ==
3187                         pActNum->GetLevel( nFirstLvl ).GetListtabPos();
3188             }
3189         }
3190         nMask <<= 1;
3191     }
3192 
3193     // enable/disable metric field for list tab stop position depending on
3194     // selected item following the list label.
3195     m_xListtabFT->set_sensitive( eLabelFollowedBy == SvxNumberFormat::LISTTAB );
3196     m_xListtabMF->set_sensitive( eLabelFollowedBy == SvxNumberFormat::LISTTAB );
3197     if ( bSameListtabPos && eLabelFollowedBy == SvxNumberFormat::LISTTAB )
3198     {
3199         SetMetricValue(*m_xListtabMF, pActNum->GetLevel( nFirstLvl ).GetListtabPos(), eCoreUnit);
3200     }
3201     else
3202     {
3203         m_xListtabMF->set_text(OUString());
3204     }
3205 
3206     SetModified();
3207 }
3208 
3209 IMPL_LINK(SvxNumPositionTabPage, ListtabPosHdl_Impl, weld::MetricSpinButton&, rFld, void)
3210 {
3211     // determine value to be set at the chosen list levels
3212     const tools::Long nValue = GetCoreValue(rFld, eCoreUnit);
3213 
3214     // set value at the chosen list levels
3215     sal_uInt16 nMask = 1;
3216     for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); ++i )
3217     {
3218         if ( nActNumLvl & nMask )
3219         {
3220             SvxNumberFormat aNumFmt( pActNum->GetLevel(i) );
3221             aNumFmt.SetListtabPos( nValue );
3222             pActNum->SetLevel( i, aNumFmt );
3223         }
3224         nMask <<= 1;
3225     }
3226 
3227     SetModified();
3228 }
3229 
3230 IMPL_LINK(SvxNumPositionTabPage, AlignAtHdl_Impl, weld::MetricSpinButton&, rFld, void)
3231 {
3232     // determine value to be set at the chosen list levels
3233     const tools::Long nValue = GetCoreValue(rFld, eCoreUnit);
3234 
3235     // set value at the chosen list levels
3236     sal_uInt16 nMask = 1;
3237     for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); ++i )
3238     {
3239         if ( nActNumLvl & nMask )
3240         {
3241             SvxNumberFormat aNumFmt( pActNum->GetLevel(i) );
3242             const tools::Long nFirstLineIndent = nValue - aNumFmt.GetIndentAt();
3243             aNumFmt.SetFirstLineIndent( nFirstLineIndent );
3244             pActNum->SetLevel( i, aNumFmt );
3245         }
3246         nMask <<= 1;
3247     }
3248 
3249     SetModified();
3250 }
3251 
3252 IMPL_LINK(SvxNumPositionTabPage, IndentAtHdl_Impl, weld::MetricSpinButton&, rFld, void)
3253 {
3254     // determine value to be set at the chosen list levels
3255     const tools::Long nValue = GetCoreValue(rFld, eCoreUnit);
3256 
3257     // set value at the chosen list levels
3258     sal_uInt16 nMask = 1;
3259     for( sal_uInt16 i = 0; i < pActNum->GetLevelCount(); ++i )
3260     {
3261         if ( nActNumLvl & nMask )
3262         {
3263             SvxNumberFormat aNumFmt( pActNum->GetLevel(i) );
3264             const tools::Long nAlignedAt = aNumFmt.GetIndentAt() +
3265                                     aNumFmt.GetFirstLineIndent();
3266             aNumFmt.SetIndentAt( nValue );
3267             const tools::Long nNewFirstLineIndent = nAlignedAt - nValue;
3268             aNumFmt.SetFirstLineIndent( nNewFirstLineIndent );
3269             pActNum->SetLevel( i, aNumFmt );
3270         }
3271         nMask <<= 1;
3272     }
3273 
3274     SetModified();
3275 }
3276 
3277 IMPL_LINK_NOARG(SvxNumPositionTabPage, StandardHdl_Impl, weld::Button&, void)
3278 {
3279     sal_uInt16 nMask = 1;
3280     SvxNumRule aTmpNumRule( pActNum->GetFeatureFlags(),
3281                             pActNum->GetLevelCount(),
3282                             pActNum->IsContinuousNumbering(),
3283                             SvxNumRuleType::NUMBERING,
3284                             pActNum->GetLevel( 0 ).GetPositionAndSpaceMode() );
3285     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
3286     {
3287         if(nActNumLvl & nMask)
3288         {
3289             SvxNumberFormat aNumFmt( pActNum->GetLevel( i ) );
3290             const SvxNumberFormat& aTempFmt(aTmpNumRule.GetLevel( i ));
3291             aNumFmt.SetPositionAndSpaceMode( aTempFmt.GetPositionAndSpaceMode() );
3292             if ( aTempFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
3293             {
3294                 aNumFmt.SetAbsLSpace( aTempFmt.GetAbsLSpace() );
3295                 aNumFmt.SetCharTextDistance( aTempFmt.GetCharTextDistance() );
3296                 aNumFmt.SetFirstLineOffset( aTempFmt.GetFirstLineOffset() );
3297             }
3298             else if ( aTempFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
3299             {
3300                 aNumFmt.SetNumAdjust( aTempFmt.GetNumAdjust() );
3301                 aNumFmt.SetLabelFollowedBy( aTempFmt.GetLabelFollowedBy() );
3302                 aNumFmt.SetListtabPos( aTempFmt.GetListtabPos() );
3303                 aNumFmt.SetFirstLineIndent( aTempFmt.GetFirstLineIndent() );
3304                 aNumFmt.SetIndentAt( aTempFmt.GetIndentAt() );
3305             }
3306 
3307             pActNum->SetLevel( i, aNumFmt );
3308         }
3309         nMask <<= 1;
3310     }
3311 
3312     InitControls();
3313     SetModified();
3314 }
3315 
3316 void SvxNumPositionTabPage::SetModified()
3317 {
3318     bModified = true;
3319     m_aPreviewWIN.SetLevel(nActNumLvl);
3320     m_aPreviewWIN.Invalidate();
3321 }
3322 
3323 void SvxNumOptionsTabPage::SetModified(bool bRepaint)
3324 {
3325     bModified = true;
3326     if (bRepaint)
3327     {
3328         m_aPreviewWIN.SetLevel(nActNumLvl);
3329         m_aPreviewWIN.Invalidate();
3330     }
3331 }
3332 
3333 void SvxNumOptionsTabPage::PageCreated(const SfxAllItemSet& aSet)
3334 {
3335     const SfxStringListItem* pListItem = aSet.GetItem<SfxStringListItem>(SID_CHAR_FMT_LIST_BOX, false);
3336     const SfxStringItem* pNumCharFmt = aSet.GetItem<SfxStringItem>(SID_NUM_CHAR_FMT, false);
3337     const SfxStringItem* pBulletCharFmt = aSet.GetItem<SfxStringItem>(SID_BULLET_CHAR_FMT, false);
3338     const SfxUInt16Item* pMetricItem = aSet.GetItem<SfxUInt16Item>(SID_METRIC_ITEM, false);
3339 
3340     if (pNumCharFmt &&pBulletCharFmt)
3341         SetCharFmts( pNumCharFmt->GetValue(),pBulletCharFmt->GetValue());
3342 
3343     if (pListItem)
3344     {
3345         const std::vector<OUString> &aList = pListItem->GetList();
3346         sal_uInt32 nCount = aList.size();
3347         for(sal_uInt32 i = 0; i < nCount; i++)
3348             m_xCharFmtLB->append_text(aList[i]);
3349     }
3350     if (pMetricItem)
3351         SetMetric(static_cast<FieldUnit>(pMetricItem->GetValue()));
3352 }
3353 
3354 void SvxNumPositionTabPage::PageCreated(const SfxAllItemSet& aSet)
3355 {
3356     const SfxUInt16Item* pMetricItem = aSet.GetItem<SfxUInt16Item>(SID_METRIC_ITEM, false);
3357 
3358     if (pMetricItem)
3359         SetMetric(static_cast<FieldUnit>(pMetricItem->GetValue()));
3360 }
3361 
3362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3363