xref: /core/svx/source/svdraw/svdmodel.cxx (revision 6362c905)
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 <svx/svdmodel.hxx>
21 #include <cassert>
22 #include <math.h>
23 #include <sal/log.hxx>
24 #include <rtl/ustrbuf.hxx>
25 #include <com/sun/star/lang/XComponent.hpp>
26 #include <com/sun/star/document/XStorageBasedDocument.hpp>
27 #include <com/sun/star/embed/ElementModes.hpp>
28 #include <unotools/configmgr.hxx>
29 #include <unotools/pathoptions.hxx>
30 #include <svl/whiter.hxx>
31 #include <svl/asiancfg.hxx>
32 #include <svx/xbtmpit.hxx>
33 #include <svx/xlndsit.hxx>
34 #include <svx/xlnedit.hxx>
35 #include <svx/xflgrit.hxx>
36 #include <svx/xflftrit.hxx>
37 #include <svx/xflhtit.hxx>
38 #include <svx/xlnstit.hxx>
39 #include <editeng/editeng.hxx>
40 #include <svx/xtable.hxx>
41 #include <svx/svdtrans.hxx>
42 #include <svx/svdpage.hxx>
43 #include <svx/svdlayer.hxx>
44 #include <svx/svdundo.hxx>
45 #include <svx/svdpool.hxx>
46 #include <svx/svdobj.hxx>
47 #include <svx/svdotext.hxx>
48 #include <textchain.hxx>
49 #include <svx/svdetc.hxx>
50 #include <svx/svdoutl.hxx>
51 #include <svx/dialmgr.hxx>
52 #include <svx/strings.hrc>
53 #include <svdoutlinercache.hxx>
54 #include <svx/sdasitm.hxx>
55 #include <officecfg/Office/Common.hxx>
56 #include <editeng/fontitem.hxx>
57 #include <editeng/colritem.hxx>
58 #include <editeng/fhgtitem.hxx>
59 #include <svl/style.hxx>
60 #include <editeng/forbiddencharacterstable.hxx>
61 #include <comphelper/servicehelper.hxx>
62 #include <comphelper/storagehelper.hxx>
63 #include <unotools/localedatawrapper.hxx>
64 #include <unotools/syslocale.hxx>
65 #include <editeng/eeitem.hxx>
66 #include <svl/itemset.hxx>
67 #include <vcl/settings.hxx>
68 #include <vcl/svapp.hxx>
69 #include <memory>
70 #include <libxml/xmlwriter.h>
71 #include <sfx2/viewsh.hxx>
72 #include <o3tl/enumrange.hxx>
73 #include <tools/diagnose_ex.h>
74 #include <tools/UnitConversion.hxx>
75 
76 using namespace ::com::sun::star;
77 using namespace ::com::sun::star::uno;
78 using namespace ::com::sun::star::lang;
79 
80 
81 struct SdrModelImpl
82 {
83     SfxUndoManager* mpUndoManager;
84     SdrUndoFactory* mpUndoFactory;
85     bool mbAnchoredTextOverflowLegacy; // tdf#99729 compatibility flag
86 
87     SdrModelImpl()
88         : mpUndoManager(nullptr)
89         , mpUndoFactory(nullptr)
90         , mbAnchoredTextOverflowLegacy(false)
91     {}
92 };
93 
94 
95 SdrModel::SdrModel(SfxItemPool* pPool, comphelper::IEmbeddedHelper* pEmbeddedHelper, bool bDisablePropertyFiles)
96     : m_aObjUnit(SdrEngineDefaults::GetMapFraction())
97     , m_eObjUnit(SdrEngineDefaults::GetMapUnit())
98     , m_eUIUnit(FieldUnit::MM)
99     , m_aUIScale(Fraction(1,1))
100     , m_nUIUnitDecimalMark(0)
101     , m_pLayerAdmin(new SdrLayerAdmin)
102     , m_pItemPool(pPool)
103     , m_pEmbeddedHelper(pEmbeddedHelper)
104     , mnDefTextHgt(SdrEngineDefaults::GetFontHeight())
105     , m_pRefOutDev(nullptr)
106     , m_pDefaultStyleSheet(nullptr)
107     , mpDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj(nullptr)
108     , m_pLinkManager(nullptr)
109     , m_nUndoLevel(0)
110     , m_bIsWriter(true)
111     , mbUndoEnabled(true)
112     , mbChanged(false)
113     , m_bPagNumsDirty(false)
114     , m_bMPgNumsDirty(false)
115     , m_bTransportContainer(false)
116     , m_bReadOnly(false)
117     , m_bTransparentTextFrames(false)
118     , m_bSwapGraphics(false)
119     , m_bPasteResize(false)
120     , m_bStarDrawPreviewMode(false)
121     , mbDisableTextEditUsesCommonUndoManager(false)
122     , m_nDefaultTabulator(0)
123     , m_nMaxUndoCount(16)
124     , m_pTextChain(new TextChain)
125     , mpImpl(new SdrModelImpl)
126     , mnCharCompressType(CharCompressType::NONE)
127     , mnHandoutPageCount(0)
128     , mbModelLocked(false)
129     , mbKernAsianPunctuation(false)
130     , mbAddExtLeading(false)
131     , mbInDestruction(false)
132 {
133     if (!utl::ConfigManager::IsFuzzing())
134     {
135         mnCharCompressType = static_cast<CharCompressType>(
136             officecfg::Office::Common::AsianLayout::CompressCharacterDistance::get());
137     }
138 
139     if (m_pItemPool == nullptr)
140     {
141         m_pItemPool = new SdrItemPool(nullptr);
142         // Outliner doesn't have its own Pool, so use the EditEngine's
143         rtl::Reference<SfxItemPool> pOutlPool=EditEngine::CreatePool();
144         // OutlinerPool as SecondaryPool of SdrPool
145         m_pItemPool->SetSecondaryPool(pOutlPool.get());
146         // remember that I created both pools myself
147         m_bIsWriter = false;
148     }
149     m_pItemPool->SetDefaultMetric(m_eObjUnit);
150 
151 // using static SdrEngineDefaults only if default SvxFontHeight item is not available
152     const SfxPoolItem* pPoolItem = m_pItemPool->GetPoolDefaultItem( EE_CHAR_FONTHEIGHT );
153     if (pPoolItem)
154         mnDefTextHgt = static_cast<const SvxFontHeightItem*>(pPoolItem)->GetHeight();
155 
156     m_pItemPool->SetPoolDefaultItem( makeSdrTextWordWrapItem( false ) );
157 
158     SetTextDefaults();
159     m_pLayerAdmin->SetModel(this);
160     ImpSetUIUnit();
161 
162     // can't create DrawOutliner OnDemand, because I can't get the Pool,
163     // then (only from 302 onwards!)
164     m_pDrawOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this);
165     ImpSetOutlinerDefaults(m_pDrawOutliner.get(), true);
166 
167     m_pHitTestOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this);
168     ImpSetOutlinerDefaults(m_pHitTestOutliner.get(), true);
169 
170     /* Start Text Chaining related code */
171     // Initialize Chaining Outliner
172     m_pChainingOutliner = SdrMakeOutliner( OutlinerMode::TextObject, *this );
173     ImpSetOutlinerDefaults(m_pChainingOutliner.get(), true);
174 
175     ImpCreateTables(bDisablePropertyFiles || utl::ConfigManager::IsFuzzing());
176 }
177 
178 SdrModel::~SdrModel()
179 {
180     mbInDestruction = true;
181 
182     Broadcast(SdrHint(SdrHintKind::ModelCleared));
183 
184     mpOutlinerCache.reset();
185 
186     ClearUndoBuffer();
187 #ifdef DBG_UTIL
188     SAL_WARN_IF(m_pCurrentUndoGroup, "svx", "In the Dtor of the SdrModel there is an open Undo left: \""
189                     << m_pCurrentUndoGroup->GetComment() << '\"');
190 #endif
191     m_pCurrentUndoGroup.reset();
192 
193     ClearModel(true);
194 
195 #ifdef DBG_UTIL
196     // SdrObjectLifetimeWatchDog:
197     if(!maAllIncarnatedObjects.empty())
198     {
199         SAL_WARN("svx","SdrModel::~SdrModel: Not all incarnations of SdrObjects deleted, possible memory leak (!)");
200         // calling SdrObject::Free will change maAllIncarnatedObjects, and potentially remove more
201         // than one - do not copy to another container, to not try to free already removed object.
202         do
203         {
204             SdrObject* pCandidate(const_cast<SdrObject*>(*maAllIncarnatedObjects.begin()));
205             SdrObject::Free(pCandidate);
206         } while (!maAllIncarnatedObjects.empty());
207     }
208 #endif
209 
210     m_pLayerAdmin.reset();
211 
212     m_pTextChain.reset();
213     // Delete DrawOutliner only after deleting ItemPool, because ItemPool
214     // references Items of the DrawOutliner!
215     m_pChainingOutliner.reset();
216     m_pHitTestOutliner.reset();
217     m_pDrawOutliner.reset();
218 
219     // delete StyleSheetPool, derived classes should not do this since
220     // the DrawingEngine may need it in its destructor
221     if( mxStyleSheetPool.is() )
222     {
223         Reference< XComponent > xComponent( static_cast< cppu::OWeakObject* >( mxStyleSheetPool.get() ), UNO_QUERY );
224         if( xComponent.is() ) try
225         {
226             xComponent->dispose();
227         }
228         catch( RuntimeException& )
229         {
230         }
231         mxStyleSheetPool.clear();
232     }
233 
234     mpForbiddenCharactersTable.reset();
235 
236     delete mpImpl->mpUndoFactory;
237 }
238 
239 void SdrModel::SetSwapGraphics()
240 {
241     m_bSwapGraphics = true;
242 }
243 
244 bool SdrModel::IsReadOnly() const
245 {
246     return m_bReadOnly;
247 }
248 
249 void SdrModel::SetReadOnly(bool bYes)
250 {
251     m_bReadOnly=bYes;
252 }
253 
254 
255 void SdrModel::SetMaxUndoActionCount(sal_uInt32 nCount)
256 {
257     if (nCount<1) nCount=1;
258     m_nMaxUndoCount=nCount;
259     while (m_aUndoStack.size()>m_nMaxUndoCount)
260         m_aUndoStack.pop_back();
261 }
262 
263 void SdrModel::ClearUndoBuffer()
264 {
265     m_aUndoStack.clear();
266     m_aRedoStack.clear();
267 }
268 
269 bool SdrModel::HasUndoActions() const
270 {
271     return !m_aUndoStack.empty();
272 }
273 
274 bool SdrModel::HasRedoActions() const
275 {
276     return !m_aRedoStack.empty();
277 }
278 
279 void SdrModel::Undo()
280 {
281     if( mpImpl->mpUndoManager )
282     {
283         OSL_FAIL("svx::SdrModel::Undo(), method not supported with application undo manager!");
284     }
285     else
286     {
287         if(HasUndoActions())
288         {
289             SfxUndoAction* pDo = m_aUndoStack.front().get();
290             const bool bWasUndoEnabled = mbUndoEnabled;
291             mbUndoEnabled = false;
292             pDo->Undo();
293             std::unique_ptr<SfxUndoAction> p = std::move(m_aUndoStack.front());
294             m_aUndoStack.pop_front();
295             m_aRedoStack.emplace_front(std::move(p));
296             mbUndoEnabled = bWasUndoEnabled;
297         }
298     }
299 }
300 
301 void SdrModel::Redo()
302 {
303     if( mpImpl->mpUndoManager )
304     {
305         OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!");
306     }
307     else
308     {
309         if(HasRedoActions())
310         {
311             SfxUndoAction* pDo = m_aRedoStack.front().get();
312             const bool bWasUndoEnabled = mbUndoEnabled;
313             mbUndoEnabled = false;
314             pDo->Redo();
315             std::unique_ptr<SfxUndoAction> p = std::move(m_aRedoStack.front());
316             m_aRedoStack.pop_front();
317             m_aUndoStack.emplace_front(std::move(p));
318             mbUndoEnabled = bWasUndoEnabled;
319         }
320     }
321 }
322 
323 void SdrModel::Repeat(SfxRepeatTarget& rView)
324 {
325     if( mpImpl->mpUndoManager )
326     {
327         OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!");
328     }
329     else
330     {
331         if(HasUndoActions())
332         {
333             SfxUndoAction* pDo =  m_aUndoStack.front().get();
334             if(pDo->CanRepeat(rView))
335             {
336                 pDo->Repeat(rView);
337             }
338         }
339     }
340 }
341 
342 void SdrModel::ImpPostUndoAction(std::unique_ptr<SdrUndoAction> pUndo)
343 {
344     DBG_ASSERT( mpImpl->mpUndoManager == nullptr, "svx::SdrModel::ImpPostUndoAction(), method not supported with application undo manager!" );
345     if( !IsUndoEnabled() )
346         return;
347 
348     if (m_aUndoLink)
349     {
350         m_aUndoLink(std::move(pUndo));
351     }
352     else
353     {
354         m_aUndoStack.emplace_front(std::move(pUndo));
355         while (m_aUndoStack.size()>m_nMaxUndoCount)
356         {
357             m_aUndoStack.pop_back();
358         }
359         m_aRedoStack.clear();
360     }
361 }
362 
363 void SdrModel::BegUndo()
364 {
365     if( mpImpl->mpUndoManager )
366     {
367         ViewShellId nViewShellId(-1);
368         if (SfxViewShell* pViewShell = SfxViewShell::Current())
369             nViewShellId = pViewShell->GetViewShellId();
370         mpImpl->mpUndoManager->EnterListAction("","",0,nViewShellId);
371         m_nUndoLevel++;
372     }
373     else if( IsUndoEnabled() )
374     {
375         if(!m_pCurrentUndoGroup)
376         {
377             m_pCurrentUndoGroup.reset(new SdrUndoGroup(*this));
378             m_nUndoLevel=1;
379         }
380         else
381         {
382             m_nUndoLevel++;
383         }
384     }
385 }
386 
387 void SdrModel::BegUndo(const OUString& rComment)
388 {
389     if( mpImpl->mpUndoManager )
390     {
391         ViewShellId nViewShellId(-1);
392         if (SfxViewShell* pViewShell = SfxViewShell::Current())
393             nViewShellId = pViewShell->GetViewShellId();
394         mpImpl->mpUndoManager->EnterListAction( rComment, "", 0, nViewShellId );
395         m_nUndoLevel++;
396     }
397     else if( IsUndoEnabled() )
398     {
399         BegUndo();
400         if (m_nUndoLevel==1)
401         {
402             m_pCurrentUndoGroup->SetComment(rComment);
403         }
404     }
405 }
406 
407 void SdrModel::BegUndo(const OUString& rComment, const OUString& rObjDescr, SdrRepeatFunc eFunc)
408 {
409     if( mpImpl->mpUndoManager )
410     {
411         OUString aComment(rComment);
412         if( !aComment.isEmpty() && !rObjDescr.isEmpty() )
413         {
414             aComment = aComment.replaceFirst("%1", rObjDescr);
415         }
416         ViewShellId nViewShellId(-1);
417         if (SfxViewShell* pViewShell = SfxViewShell::Current())
418             nViewShellId = pViewShell->GetViewShellId();
419         mpImpl->mpUndoManager->EnterListAction( aComment,"",0,nViewShellId );
420         m_nUndoLevel++;
421     }
422     else if( IsUndoEnabled() )
423     {
424         BegUndo();
425         if (m_nUndoLevel==1)
426         {
427             m_pCurrentUndoGroup->SetComment(rComment);
428             m_pCurrentUndoGroup->SetObjDescription(rObjDescr);
429             m_pCurrentUndoGroup->SetRepeatFunction(eFunc);
430         }
431     }
432 }
433 
434 void SdrModel::EndUndo()
435 {
436     DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::EndUndo(): UndoLevel is already 0!");
437     if( mpImpl->mpUndoManager )
438     {
439         if( m_nUndoLevel )
440         {
441             m_nUndoLevel--;
442             mpImpl->mpUndoManager->LeaveListAction();
443         }
444     }
445     else
446     {
447         if(m_pCurrentUndoGroup!=nullptr && IsUndoEnabled())
448         {
449             m_nUndoLevel--;
450             if(m_nUndoLevel==0)
451             {
452                 if(m_pCurrentUndoGroup->GetActionCount()!=0)
453                 {
454                     ImpPostUndoAction(std::move(m_pCurrentUndoGroup));
455                 }
456                 else
457                 {
458                     // was empty
459                     m_pCurrentUndoGroup.reset();
460                 }
461             }
462         }
463     }
464 }
465 
466 void SdrModel::SetUndoComment(const OUString& rComment)
467 {
468     DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!");
469 
470     if( mpImpl->mpUndoManager )
471     {
472         OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" );
473     }
474     else if( IsUndoEnabled() && m_nUndoLevel==1)
475     {
476         m_pCurrentUndoGroup->SetComment(rComment);
477     }
478 }
479 
480 void SdrModel::SetUndoComment(const OUString& rComment, const OUString& rObjDescr)
481 {
482     DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!");
483     if( mpImpl->mpUndoManager )
484     {
485         OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" );
486     }
487     else
488     {
489         if (m_nUndoLevel==1)
490         {
491             m_pCurrentUndoGroup->SetComment(rComment);
492             m_pCurrentUndoGroup->SetObjDescription(rObjDescr);
493         }
494     }
495 }
496 
497 void SdrModel::AddUndo(std::unique_ptr<SdrUndoAction> pUndo)
498 {
499     if( mpImpl->mpUndoManager )
500     {
501         mpImpl->mpUndoManager->AddUndoAction( std::move(pUndo) );
502     }
503     else if( IsUndoEnabled() )
504     {
505         if (m_pCurrentUndoGroup)
506         {
507             m_pCurrentUndoGroup->AddAction(std::move(pUndo));
508         }
509         else
510         {
511             ImpPostUndoAction(std::move(pUndo));
512         }
513     }
514 }
515 
516 void SdrModel::EnableUndo( bool bEnable )
517 {
518     if( mpImpl->mpUndoManager )
519     {
520         mpImpl->mpUndoManager->EnableUndo( bEnable );
521     }
522     else
523     {
524         mbUndoEnabled = bEnable;
525     }
526 }
527 
528 bool SdrModel::IsUndoEnabled() const
529 {
530     if( mpImpl->mpUndoManager )
531     {
532         return mpImpl->mpUndoManager->IsUndoEnabled();
533     }
534     else
535     {
536         return mbUndoEnabled;
537     }
538 }
539 
540 void SdrModel::ImpCreateTables(bool bDisablePropertyFiles)
541 {
542     // use standard path for initial construction
543     const OUString aTablePath(!bDisablePropertyFiles ? SvtPathOptions().GetPalettePath() : "");
544 
545     for( auto i : o3tl::enumrange<XPropertyListType>() )
546     {
547         maProperties[i] = XPropertyList::CreatePropertyList(i, aTablePath, ""/*TODO?*/ );
548     }
549 }
550 
551 void SdrModel::ClearModel(bool bCalledFromDestructor)
552 {
553     if(bCalledFromDestructor)
554     {
555         mbInDestruction = true;
556     }
557 
558     sal_Int32 i;
559     // delete all drawing pages
560     sal_Int32 nCount=GetPageCount();
561     for (i=nCount-1; i>=0; i--)
562     {
563         DeletePage( static_cast<sal_uInt16>(i) );
564     }
565     maPages.clear();
566     PageListChanged();
567 
568     // delete all Masterpages
569     nCount=GetMasterPageCount();
570     for(i=nCount-1; i>=0; i--)
571     {
572         DeleteMasterPage( static_cast<sal_uInt16>(i) );
573     }
574     maMasterPages.clear();
575     MasterPageListChanged();
576 
577     m_pLayerAdmin->ClearLayers();
578 }
579 
580 SdrModel* SdrModel::AllocModel() const
581 {
582     SdrModel* pModel=new SdrModel();
583     pModel->SetScaleUnit(m_eObjUnit,m_aObjUnit);
584     return pModel;
585 }
586 
587 rtl::Reference<SdrPage> SdrModel::AllocPage(bool bMasterPage)
588 {
589     return new SdrPage(*this,bMasterPage);
590 }
591 
592 void SdrModel::SetTextDefaults() const
593 {
594     SetTextDefaults( m_pItemPool.get(), mnDefTextHgt );
595 }
596 
597 void SdrModel::SetTextDefaults( SfxItemPool* pItemPool, sal_Int32 nDefTextHgt )
598 {
599     // set application-language specific dynamic pool language defaults
600     SvxFontItem aSvxFontItem( EE_CHAR_FONTINFO) ;
601     SvxFontItem aSvxFontItemCJK(EE_CHAR_FONTINFO_CJK);
602     SvxFontItem aSvxFontItemCTL(EE_CHAR_FONTINFO_CTL);
603     LanguageType nLanguage;
604     if (!utl::ConfigManager::IsFuzzing())
605         nLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
606     else
607         nLanguage = LANGUAGE_ENGLISH_US;
608 
609     // get DEFAULTFONT_LATIN_TEXT and set at pool as dynamic default
610     vcl::Font aFont(OutputDevice::GetDefaultFont(DefaultFontType::LATIN_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
611     aSvxFontItem.SetFamily(aFont.GetFamilyType());
612     aSvxFontItem.SetFamilyName(aFont.GetFamilyName());
613     aSvxFontItem.SetStyleName(OUString());
614     aSvxFontItem.SetPitch( aFont.GetPitch());
615     aSvxFontItem.SetCharSet( aFont.GetCharSet() );
616     pItemPool->SetPoolDefaultItem(aSvxFontItem);
617 
618     // get DEFAULTFONT_CJK_TEXT and set at pool as dynamic default
619     vcl::Font aFontCJK(OutputDevice::GetDefaultFont(DefaultFontType::CJK_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
620     aSvxFontItemCJK.SetFamily( aFontCJK.GetFamilyType());
621     aSvxFontItemCJK.SetFamilyName(aFontCJK.GetFamilyName());
622     aSvxFontItemCJK.SetStyleName(OUString());
623     aSvxFontItemCJK.SetPitch( aFontCJK.GetPitch());
624     aSvxFontItemCJK.SetCharSet( aFontCJK.GetCharSet());
625     pItemPool->SetPoolDefaultItem(aSvxFontItemCJK);
626 
627     // get DEFAULTFONT_CTL_TEXT and set at pool as dynamic default
628     vcl::Font aFontCTL(OutputDevice::GetDefaultFont(DefaultFontType::CTL_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
629     aSvxFontItemCTL.SetFamily(aFontCTL.GetFamilyType());
630     aSvxFontItemCTL.SetFamilyName(aFontCTL.GetFamilyName());
631     aSvxFontItemCTL.SetStyleName(OUString());
632     aSvxFontItemCTL.SetPitch( aFontCTL.GetPitch() );
633     aSvxFontItemCTL.SetCharSet( aFontCTL.GetCharSet());
634     pItemPool->SetPoolDefaultItem(aSvxFontItemCTL);
635 
636     // set dynamic FontHeight defaults
637     pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT ) );
638     pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CJK ) );
639     pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CTL ) );
640 
641     // set FontColor defaults
642     pItemPool->SetPoolDefaultItem( SvxColorItem(SdrEngineDefaults::GetFontColor(), EE_CHAR_COLOR) );
643 }
644 
645 SdrOutliner& SdrModel::GetDrawOutliner(const SdrTextObj* pObj) const
646 {
647     m_pDrawOutliner->SetTextObj(pObj);
648     return *m_pDrawOutliner;
649 }
650 
651 SdrOutliner& SdrModel::GetChainingOutliner(const SdrTextObj* pObj) const
652 {
653     m_pChainingOutliner->SetTextObj(pObj);
654     return *m_pChainingOutliner;
655 }
656 
657 const SdrTextObj* SdrModel::GetFormattingTextObj() const
658 {
659     if (m_pDrawOutliner!=nullptr) {
660         return m_pDrawOutliner->GetTextObj();
661     }
662     return nullptr;
663 }
664 
665 void SdrModel::ImpSetOutlinerDefaults( SdrOutliner* pOutliner, bool bInit )
666 {
667     // Initialization of the Outliners for drawing text and HitTest
668     if( bInit )
669     {
670         pOutliner->EraseVirtualDevice();
671         pOutliner->SetUpdateMode(false);
672         pOutliner->SetEditTextObjectPool(m_pItemPool.get());
673         pOutliner->SetDefTab(m_nDefaultTabulator);
674     }
675 
676     pOutliner->SetRefDevice(GetRefDevice());
677     Outliner::SetForbiddenCharsTable(GetForbiddenCharsTable());
678     pOutliner->SetAsianCompressionMode( mnCharCompressType );
679     pOutliner->SetKernAsianPunctuation( IsKernAsianPunctuation() );
680     pOutliner->SetAddExtLeading( IsAddExtLeading() );
681 
682     if ( !GetRefDevice() )
683     {
684         MapMode aMapMode(m_eObjUnit, Point(0,0), m_aObjUnit, m_aObjUnit);
685         pOutliner->SetRefMapMode(aMapMode);
686     }
687 }
688 
689 void SdrModel::SetRefDevice(OutputDevice* pDev)
690 {
691     m_pRefOutDev=pDev;
692     ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
693     ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
694     RefDeviceChanged();
695 }
696 
697 void SdrModel::ImpReformatAllTextObjects()
698 {
699     if( isLocked() )
700         return;
701 
702     sal_uInt16 nCount=GetMasterPageCount();
703     sal_uInt16 nNum;
704     for (nNum=0; nNum<nCount; nNum++) {
705         GetMasterPage(nNum)->ReformatAllTextObjects();
706     }
707     nCount=GetPageCount();
708     for (nNum=0; nNum<nCount; nNum++) {
709         GetPage(nNum)->ReformatAllTextObjects();
710     }
711 }
712 
713 /*  steps over all available pages and sends notify messages to
714     all edge objects that are connected to other objects so that
715     they may reposition themselves
716 */
717 void SdrModel::ImpReformatAllEdgeObjects()
718 {
719     if( isLocked() )
720         return;
721 
722     sal_uInt16 nCount=GetMasterPageCount();
723     sal_uInt16 nNum;
724     for (nNum=0; nNum<nCount; nNum++)
725     {
726         GetMasterPage(nNum)->ReformatAllEdgeObjects();
727     }
728     nCount=GetPageCount();
729     for (nNum=0; nNum<nCount; nNum++)
730     {
731         GetPage(nNum)->ReformatAllEdgeObjects();
732     }
733 }
734 
735 uno::Reference<embed::XStorage> SdrModel::GetDocumentStorage() const
736 {
737     uno::Reference<document::XStorageBasedDocument> const xSBD(
738             const_cast<SdrModel*>(this)->getUnoModel(), uno::UNO_QUERY);
739     if (!xSBD.is())
740     {
741         SAL_WARN("svx", "no UNO model");
742         return nullptr;
743     }
744     return xSBD->getDocumentStorage();
745 }
746 
747 uno::Reference<io::XInputStream>
748 SdrModel::GetDocumentStream( OUString const& rURL,
749                 ::comphelper::LifecycleProxy const & rProxy) const
750 {
751     uno::Reference<embed::XStorage> const xStorage(GetDocumentStorage());
752     if (!xStorage.is())
753     {
754         SAL_WARN("svx", "no storage?");
755         return nullptr;
756     }
757     try {
758         uno::Reference<io::XStream> const xStream(
759             ::comphelper::OStorageHelper::GetStreamAtPackageURL(
760                 xStorage, rURL, embed::ElementModes::READ, rProxy));
761         return (xStream.is()) ? xStream->getInputStream() : nullptr;
762     }
763     catch (container::NoSuchElementException const&)
764     {
765         SAL_INFO("svx", "not found");
766     }
767     catch (uno::Exception const&)
768     {
769         TOOLS_WARN_EXCEPTION("svx", "");
770     }
771     return nullptr;
772 }
773 
774 // convert template attributes from the string into "hard" attributes
775 void SdrModel::BurnInStyleSheetAttributes()
776 {
777     sal_uInt16 nCount=GetMasterPageCount();
778     sal_uInt16 nNum;
779     for (nNum=0; nNum<nCount; nNum++) {
780         GetMasterPage(nNum)->BurnInStyleSheetAttributes();
781     }
782     nCount=GetPageCount();
783     for (nNum=0; nNum<nCount; nNum++) {
784         GetPage(nNum)->BurnInStyleSheetAttributes();
785     }
786 }
787 
788 void SdrModel::RefDeviceChanged()
789 {
790     Broadcast(SdrHint(SdrHintKind::RefDeviceChange));
791     ImpReformatAllTextObjects();
792 }
793 
794 void SdrModel::SetDefaultFontHeight(sal_Int32 nVal)
795 {
796     if (nVal!=mnDefTextHgt) {
797         mnDefTextHgt=nVal;
798         ImpReformatAllTextObjects();
799     }
800 }
801 
802 void SdrModel::SetDefaultTabulator(sal_uInt16 nVal)
803 {
804     if (m_nDefaultTabulator!=nVal) {
805         m_nDefaultTabulator=nVal;
806         Outliner& rOutliner=GetDrawOutliner();
807         rOutliner.SetDefTab(nVal);
808         Broadcast(SdrHint(SdrHintKind::DefaultTabChange));
809         ImpReformatAllTextObjects();
810     }
811 }
812 
813 void SdrModel::ImpSetUIUnit()
814 {
815     if(0 == m_aUIScale.GetNumerator() || 0 == m_aUIScale.GetDenominator())
816     {
817         m_aUIScale = Fraction(1,1);
818     }
819 
820     m_nUIUnitDecimalMark = 0;
821 
822     o3tl::Length eFrom = MapToO3tlLength(m_eObjUnit, o3tl::Length::invalid);
823     o3tl::Length eTo;
824 
825     switch (m_eUIUnit)
826     {
827         case FieldUnit::CHAR:
828         case FieldUnit::LINE:
829             eTo = o3tl::Length::invalid;
830             break;
831         case FieldUnit::PERCENT:
832             m_nUIUnitDecimalMark += 2;
833             [[fallthrough]];
834         default:
835             eTo = FieldToO3tlLength(m_eUIUnit, o3tl::Length::invalid);
836     } // switch
837 
838     sal_Int32 nMul = 1, nDiv = 1;
839     if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
840     {
841         const auto& [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
842         nMul = mul;
843         nDiv = div;
844     }
845     // #i89872# take Unit of Measurement into account
846     if(1 != m_aUIScale.GetDenominator() || 1 != m_aUIScale.GetNumerator())
847     {
848         // divide by UIScale
849         nMul *= m_aUIScale.GetDenominator();
850         nDiv *= m_aUIScale.GetNumerator();
851     }
852 
853     // shorten trailing zeros for dividend
854     while(0 == (nMul % 10))
855     {
856         m_nUIUnitDecimalMark--;
857         nMul /= 10;
858     }
859 
860     // shorten trailing zeros for divisor
861     while(0 == (nDiv % 10))
862     {
863         m_nUIUnitDecimalMark++;
864         nDiv /= 10;
865     }
866 
867     // end preparations, set member values
868     m_aUIUnitFact = Fraction(sal_Int32(nMul), sal_Int32(nDiv));
869     m_aUIUnitStr = GetUnitString(m_eUIUnit);
870 }
871 
872 void SdrModel::SetScaleUnit(MapUnit eMap, const Fraction& rFrac)
873 {
874     if (m_eObjUnit!=eMap || m_aObjUnit!=rFrac) {
875         m_eObjUnit=eMap;
876         m_aObjUnit=rFrac;
877         m_pItemPool->SetDefaultMetric(m_eObjUnit);
878         ImpSetUIUnit();
879         ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
880         ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
881         ImpReformatAllTextObjects();
882     }
883 }
884 
885 void SdrModel::SetScaleUnit(MapUnit eMap)
886 {
887     if (m_eObjUnit!=eMap) {
888         m_eObjUnit=eMap;
889         m_pItemPool->SetDefaultMetric(m_eObjUnit);
890         ImpSetUIUnit();
891         ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
892         ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
893         ImpReformatAllTextObjects();
894     }
895 }
896 
897 void SdrModel::SetScaleFraction(const Fraction& rFrac)
898 {
899     if (m_aObjUnit!=rFrac) {
900         m_aObjUnit=rFrac;
901         ImpSetUIUnit();
902         ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
903         ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
904         ImpReformatAllTextObjects();
905     }
906 }
907 
908 void SdrModel::SetUIUnit(FieldUnit eUnit)
909 {
910     if (m_eUIUnit!=eUnit) {
911         m_eUIUnit=eUnit;
912         ImpSetUIUnit();
913         ImpReformatAllTextObjects();
914     }
915 }
916 
917 void SdrModel::SetUIScale(const Fraction& rScale)
918 {
919     if (m_aUIScale!=rScale) {
920         m_aUIScale=rScale;
921         ImpSetUIUnit();
922         ImpReformatAllTextObjects();
923     }
924 }
925 
926 void SdrModel::SetUIUnit(FieldUnit eUnit, const Fraction& rScale)
927 {
928     if (m_eUIUnit!=eUnit || m_aUIScale!=rScale) {
929         m_eUIUnit=eUnit;
930         m_aUIScale=rScale;
931         ImpSetUIUnit();
932         ImpReformatAllTextObjects();
933     }
934 }
935 
936 OUString SdrModel::GetUnitString(FieldUnit eUnit)
937 {
938     switch(eUnit)
939     {
940         default:
941         case FieldUnit::NONE   :
942         case FieldUnit::CUSTOM :
943             return OUString();
944         case FieldUnit::MM_100TH:
945             return OUString{"/100mm"};
946         case FieldUnit::MM     :
947             return OUString{"mm"};
948         case FieldUnit::CM     :
949             return OUString{"cm"};
950         case FieldUnit::M      :
951             return OUString{"m"};
952         case FieldUnit::KM     :
953             return OUString{"km"};
954         case FieldUnit::TWIP   :
955             return OUString{"twip"};
956         case FieldUnit::POINT  :
957             return OUString{"pt"};
958         case FieldUnit::PICA   :
959             return OUString{"pica"};
960         case FieldUnit::INCH   :
961             return OUString{"\""};
962         case FieldUnit::FOOT   :
963             return OUString{"ft"};
964         case FieldUnit::MILE   :
965             return OUString{"mile(s)"};
966         case FieldUnit::PERCENT:
967             return OUString{"%"};
968     }
969 }
970 
971 OUString SdrModel::GetMetricString(tools::Long nVal, bool bNoUnitChars, sal_Int32 nNumDigits) const
972 {
973     // #i22167#
974     // change to double precision usage to not lose decimal places
975     const bool bNegative(nVal < 0);
976     SvtSysLocale aSysLoc;
977     const LocaleDataWrapper& rLoc(aSysLoc.GetLocaleData());
978     double fLocalValue(double(nVal) * double(m_aUIUnitFact));
979 
980     if(bNegative)
981     {
982         fLocalValue = -fLocalValue;
983     }
984 
985     if( -1 == nNumDigits )
986     {
987         nNumDigits = LocaleDataWrapper::getNumDigits();
988     }
989 
990     sal_Int32 nDecimalMark(m_nUIUnitDecimalMark);
991 
992     if(nDecimalMark > nNumDigits)
993     {
994         const sal_Int32 nDiff(nDecimalMark - nNumDigits);
995         const double fFactor(pow(10.0, static_cast<int>(nDiff)));
996 
997         fLocalValue /= fFactor;
998         nDecimalMark = nNumDigits;
999     }
1000     else if(nDecimalMark < nNumDigits)
1001     {
1002         const sal_Int32 nDiff(nNumDigits - nDecimalMark);
1003         const double fFactor(pow(10.0, static_cast<int>(nDiff)));
1004 
1005         fLocalValue *= fFactor;
1006         nDecimalMark = nNumDigits;
1007     }
1008 
1009     OUStringBuffer aBuf;
1010     aBuf.append(static_cast<sal_Int32>(fLocalValue + 0.5));
1011 
1012     if(nDecimalMark < 0)
1013     {
1014         // negative nDecimalMark (decimal point) means: add zeros
1015         sal_Int32 nCount(-nDecimalMark);
1016 
1017         for(sal_Int32 i=0; i<nCount; i++)
1018             aBuf.append('0');
1019 
1020         nDecimalMark = 0;
1021     }
1022 
1023     // the second condition needs to be <= since inside this loop
1024     // also the leading zero is inserted.
1025     if (nDecimalMark > 0 && aBuf.getLength() <= nDecimalMark)
1026     {
1027         // if necessary, add zeros before the decimal point
1028         sal_Int32 nCount = nDecimalMark - aBuf.getLength();
1029 
1030         if(nCount >= 0 && LocaleDataWrapper::isNumLeadingZero())
1031             nCount++;
1032 
1033         for(sal_Int32 i=0; i<nCount; i++)
1034             aBuf.insert(0, '0');
1035     }
1036 
1037     const sal_Unicode cDec( rLoc.getNumDecimalSep()[0] );
1038 
1039     // insert the decimal mark character
1040     sal_Int32 nBeforeDecimalMark = aBuf.getLength() - nDecimalMark;
1041 
1042     if(nDecimalMark > 0)
1043         aBuf.insert(nBeforeDecimalMark, cDec);
1044 
1045     if(!LocaleDataWrapper::isNumTrailingZeros())
1046     {
1047         sal_Int32 aPos=aBuf.getLength()-1;
1048 
1049         // Remove all trailing zeros.
1050         while (aPos>=0 && aBuf[aPos]=='0')
1051             --aPos;
1052 
1053         // Remove decimal if it's the last character.
1054         if (aPos>=0 && aBuf[aPos]==cDec)
1055             --aPos;
1056 
1057         // Adjust aPos to index first char to be truncated, if any
1058         if (++aPos<aBuf.getLength())
1059             aBuf.truncate(aPos);
1060     }
1061 
1062     // if necessary, add separators before every third digit
1063     if( nBeforeDecimalMark > 3 )
1064     {
1065         const OUString& aThoSep( rLoc.getNumThousandSep() );
1066         if ( !aThoSep.isEmpty() )
1067         {
1068             sal_Unicode cTho( aThoSep[0] );
1069             sal_Int32 i(nBeforeDecimalMark - 3);
1070 
1071             while(i > 0)
1072             {
1073                 aBuf.insert(i, cTho);
1074                 i -= 3;
1075             }
1076         }
1077     }
1078 
1079     if (aBuf.isEmpty())
1080         aBuf.append("0");
1081 
1082     if(bNegative)
1083     {
1084         aBuf.insert(0, "-");
1085     }
1086 
1087     if(!bNoUnitChars)
1088         aBuf.append(m_aUIUnitStr);
1089 
1090     return aBuf.makeStringAndClear();
1091 }
1092 
1093 OUString SdrModel::GetAngleString(Degree100 nAngle)
1094 {
1095     bool bNeg = nAngle < 0_deg100;
1096 
1097     if(bNeg)
1098         nAngle = -nAngle;
1099 
1100     OUStringBuffer aBuf;
1101     aBuf.append(static_cast<sal_Int32>(nAngle));
1102 
1103     SvtSysLocale aSysLoc;
1104     const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
1105     sal_Int32 nCount = 2;
1106 
1107     if(LocaleDataWrapper::isNumLeadingZero())
1108         nCount++;
1109 
1110     while(aBuf.getLength() < nCount)
1111         aBuf.insert(0, '0');
1112 
1113     aBuf.insert(aBuf.getLength()-2, rLoc.getNumDecimalSep()[0]);
1114 
1115     if(bNeg)
1116         aBuf.insert(0, '-');
1117 
1118     aBuf.append(DEGREE_CHAR);
1119 
1120     return aBuf.makeStringAndClear();
1121 }
1122 
1123 OUString SdrModel::GetPercentString(const Fraction& rVal)
1124 {
1125     sal_Int32 nMul(rVal.GetNumerator());
1126     sal_Int32 nDiv(rVal.GetDenominator());
1127     bool bNeg {false};
1128 
1129     if (nDiv < 0)
1130     {
1131         bNeg = !bNeg;
1132         nDiv = -nDiv;
1133     }
1134 
1135     if (nMul < 0)
1136     {
1137         bNeg = !bNeg;
1138         nMul = -nMul;
1139     }
1140 
1141     sal_Int32 nPct = ((nMul*100) + nDiv/2)/nDiv;
1142 
1143     if (bNeg)
1144         nPct = -nPct;
1145 
1146     return OUString::number(nPct) + "%";
1147 }
1148 
1149 void SdrModel::SetChanged(bool bFlg)
1150 {
1151     mbChanged = bFlg;
1152 }
1153 
1154 void SdrModel::RecalcPageNums(bool bMaster)
1155 {
1156     if(bMaster)
1157     {
1158         sal_uInt16 nCount=sal_uInt16(maMasterPages.size());
1159         sal_uInt16 i;
1160         for (i=0; i<nCount; i++) {
1161             SdrPage* pPg = maMasterPages[i].get();
1162             pPg->SetPageNum(i);
1163         }
1164         m_bMPgNumsDirty=false;
1165     }
1166     else
1167     {
1168         sal_uInt16 nCount=sal_uInt16(maPages.size());
1169         sal_uInt16 i;
1170         for (i=0; i<nCount; i++) {
1171             SdrPage* pPg = maPages[i].get();
1172             pPg->SetPageNum(i);
1173         }
1174         m_bPagNumsDirty=false;
1175     }
1176 }
1177 
1178 void SdrModel::InsertPage(SdrPage* pPage, sal_uInt16 nPos)
1179 {
1180     sal_uInt16 nCount = GetPageCount();
1181     if (nPos > nCount)
1182         nPos = nCount;
1183 
1184     maPages.insert(maPages.begin() + nPos, pPage);
1185     PageListChanged();
1186     pPage->SetInserted();
1187     pPage->SetPageNum(nPos);
1188 
1189     if (mbMakePageObjectsNamesUnique)
1190         pPage->MakePageObjectsNamesUnique();
1191 
1192     if (nPos<nCount) m_bPagNumsDirty=true;
1193     SetChanged();
1194     SdrHint aHint(SdrHintKind::PageOrderChange, pPage);
1195     Broadcast(aHint);
1196 }
1197 
1198 void SdrModel::DeletePage(sal_uInt16 nPgNum)
1199 {
1200     RemovePage(nPgNum);
1201 }
1202 
1203 rtl::Reference<SdrPage> SdrModel::RemovePage(sal_uInt16 nPgNum)
1204 {
1205     rtl::Reference<SdrPage> pPg = maPages[nPgNum];
1206     maPages.erase(maPages.begin()+nPgNum);
1207     PageListChanged();
1208     if (pPg) {
1209         pPg->SetInserted(false);
1210     }
1211     m_bPagNumsDirty=true;
1212     SetChanged();
1213     SdrHint aHint(SdrHintKind::PageOrderChange, pPg.get());
1214     Broadcast(aHint);
1215     return pPg;
1216 }
1217 
1218 void SdrModel::MovePage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
1219 {
1220     rtl::Reference<SdrPage> pPg = std::move(maPages[nPgNum]);
1221     if (pPg) {
1222         maPages.erase(maPages.begin()+nPgNum); // shortcut to avoid two broadcasts
1223         PageListChanged();
1224         pPg->SetInserted(false);
1225         InsertPage(pPg.get(), nNewPos);
1226     }
1227     else
1228         RemovePage(nPgNum);
1229 }
1230 
1231 void SdrModel::InsertMasterPage(SdrPage* pPage, sal_uInt16 nPos)
1232 {
1233     sal_uInt16 nCount=GetMasterPageCount();
1234     if (nPos>nCount) nPos=nCount;
1235     maMasterPages.insert(maMasterPages.begin()+nPos,pPage);
1236     MasterPageListChanged();
1237     pPage->SetInserted();
1238     pPage->SetPageNum(nPos);
1239 
1240     if (nPos<nCount) {
1241         m_bMPgNumsDirty=true;
1242     }
1243 
1244     SetChanged();
1245     SdrHint aHint(SdrHintKind::PageOrderChange, pPage);
1246     Broadcast(aHint);
1247 }
1248 
1249 void SdrModel::DeleteMasterPage(sal_uInt16 nPgNum)
1250 {
1251     RemoveMasterPage(nPgNum);
1252 }
1253 
1254 rtl::Reference<SdrPage> SdrModel::RemoveMasterPage(sal_uInt16 nPgNum)
1255 {
1256     rtl::Reference<SdrPage> pRetPg = std::move(maMasterPages[nPgNum]);
1257     maMasterPages.erase(maMasterPages.begin()+nPgNum);
1258     MasterPageListChanged();
1259 
1260     if(pRetPg)
1261     {
1262         // Now delete the links from the normal drawing pages to the deleted master page.
1263         sal_uInt16 nPageCnt(GetPageCount());
1264 
1265         for(sal_uInt16 np(0); np < nPageCnt; np++)
1266         {
1267             GetPage(np)->TRG_ImpMasterPageRemoved(*pRetPg);
1268         }
1269 
1270         pRetPg->SetInserted(false);
1271     }
1272 
1273     m_bMPgNumsDirty=true;
1274     SetChanged();
1275     SdrHint aHint(SdrHintKind::PageOrderChange, pRetPg.get());
1276     Broadcast(aHint);
1277     return pRetPg;
1278 }
1279 
1280 void SdrModel::MoveMasterPage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
1281 {
1282     rtl::Reference<SdrPage> pPg = std::move(maMasterPages[nPgNum]);
1283     maMasterPages.erase(maMasterPages.begin()+nPgNum);
1284     MasterPageListChanged();
1285     if (pPg) {
1286         pPg->SetInserted(false);
1287         maMasterPages.insert(maMasterPages.begin()+nNewPos,pPg);
1288         MasterPageListChanged();
1289     }
1290     m_bMPgNumsDirty=true;
1291     SetChanged();
1292     SdrHint aHint(SdrHintKind::PageOrderChange, pPg.get());
1293     Broadcast(aHint);
1294 }
1295 
1296 
1297 void SdrModel::CopyPages(sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum,
1298                          sal_uInt16 nDestPos,
1299                          bool bUndo, bool bMoveNoCopy)
1300 {
1301     if( bUndo && !IsUndoEnabled() )
1302         bUndo = false;
1303 
1304     if( bUndo )
1305         BegUndo(SvxResId(STR_UndoMergeModel));
1306 
1307     sal_uInt16 nPageCnt=GetPageCount();
1308     sal_uInt16 nMaxPage=nPageCnt;
1309 
1310     if (nMaxPage!=0)
1311         nMaxPage--;
1312     if (nFirstPageNum>nMaxPage)
1313         nFirstPageNum=nMaxPage;
1314     if (nLastPageNum>nMaxPage)
1315         nLastPageNum =nMaxPage;
1316     bool bReverse=nLastPageNum<nFirstPageNum;
1317     if (nDestPos>nPageCnt)
1318         nDestPos=nPageCnt;
1319 
1320     // at first, save the pointers of the affected pages in an array
1321     sal_uInt16 nPageNum=nFirstPageNum;
1322     sal_uInt16 nCopyCnt=((!bReverse)?(nLastPageNum-nFirstPageNum):(nFirstPageNum-nLastPageNum))+1;
1323     std::unique_ptr<SdrPage*[]> pPagePtrs(new SdrPage*[nCopyCnt]);
1324     sal_uInt16 nCopyNum;
1325     for(nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++)
1326     {
1327         pPagePtrs[nCopyNum]=GetPage(nPageNum);
1328         if (bReverse)
1329             nPageNum--;
1330         else
1331             nPageNum++;
1332     }
1333 
1334     // now copy the pages
1335     sal_uInt16 nDestNum=nDestPos;
1336     for (nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++)
1337     {
1338         rtl::Reference<SdrPage> pPg = pPagePtrs[nCopyNum];
1339         sal_uInt16 nPageNum2=pPg->GetPageNum();
1340         if (!bMoveNoCopy)
1341         {
1342             const SdrPage* pPg1=GetPage(nPageNum2);
1343 
1344             // Clone to local model
1345             pPg = pPg1->CloneSdrPage(*this);
1346 
1347             InsertPage(pPg.get(), nDestNum);
1348             if (bUndo)
1349                 AddUndo(GetSdrUndoFactory().CreateUndoCopyPage(*pPg));
1350             nDestNum++;
1351         }
1352         else
1353         {
1354             // TODO: Move is untested!
1355             if (nDestNum>nPageNum2)
1356                 nDestNum--;
1357 
1358             if(bUndo)
1359                 AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*GetPage(nPageNum2),nPageNum2,nDestNum));
1360 
1361             pPg=RemovePage(nPageNum2);
1362             InsertPage(pPg.get(), nDestNum);
1363             nDestNum++;
1364         }
1365 
1366         if(bReverse)
1367             nPageNum2--;
1368         else
1369             nPageNum2++;
1370     }
1371 
1372     pPagePtrs.reset();
1373     if(bUndo)
1374         EndUndo();
1375 }
1376 
1377 void SdrModel::Merge(SdrModel& rSourceModel,
1378                      sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum,
1379                      sal_uInt16 nDestPos,
1380                      bool bMergeMasterPages, bool bAllMasterPages,
1381                      bool bUndo, bool bTreadSourceAsConst)
1382 {
1383     if (&rSourceModel==this)
1384     {
1385         CopyPages(nFirstPageNum,nLastPageNum,nDestPos,bUndo,!bTreadSourceAsConst);
1386         return;
1387     }
1388 
1389     if( bUndo && !IsUndoEnabled() )
1390         bUndo = false;
1391 
1392     if (bUndo)
1393         BegUndo(SvxResId(STR_UndoMergeModel));
1394 
1395     sal_uInt16 nSrcPageCnt=rSourceModel.GetPageCount();
1396     sal_uInt16 nSrcMasterPageCnt=rSourceModel.GetMasterPageCount();
1397     sal_uInt16 nDstMasterPageCnt=GetMasterPageCount();
1398     bool bInsPages=(nFirstPageNum<nSrcPageCnt || nLastPageNum<nSrcPageCnt);
1399     sal_uInt16 nMaxSrcPage=nSrcPageCnt; if (nMaxSrcPage!=0) nMaxSrcPage--;
1400     if (nFirstPageNum>nMaxSrcPage) nFirstPageNum=nMaxSrcPage;
1401     if (nLastPageNum>nMaxSrcPage)  nLastPageNum =nMaxSrcPage;
1402     bool bReverse=nLastPageNum<nFirstPageNum;
1403 
1404     std::unique_ptr<sal_uInt16[]> pMasterMap;
1405     std::unique_ptr<bool[]> pMasterNeed;
1406     sal_uInt16    nMasterNeed=0;
1407     if (bMergeMasterPages && nSrcMasterPageCnt!=0) {
1408         // determine which MasterPages from rSrcModel we need
1409         pMasterMap.reset(new sal_uInt16[nSrcMasterPageCnt]);
1410         pMasterNeed.reset(new bool[nSrcMasterPageCnt]);
1411         memset(pMasterMap.get(),0xFF,nSrcMasterPageCnt*sizeof(sal_uInt16));
1412         if (bAllMasterPages) {
1413             memset(pMasterNeed.get(), true, nSrcMasterPageCnt * sizeof(bool));
1414         } else {
1415             memset(pMasterNeed.get(), false, nSrcMasterPageCnt * sizeof(bool));
1416             sal_uInt16 nStart= bReverse ? nLastPageNum : nFirstPageNum;
1417             sal_uInt16 nEnd= bReverse ? nFirstPageNum : nLastPageNum;
1418             for (sal_uInt16 i=nStart; i<=nEnd; i++) {
1419                 const SdrPage* pPg=rSourceModel.GetPage(i);
1420                 if(pPg->TRG_HasMasterPage())
1421                 {
1422                     SdrPage& rMasterPage = pPg->TRG_GetMasterPage();
1423                     sal_uInt16 nMPgNum(rMasterPage.GetPageNum());
1424 
1425                     if(nMPgNum < nSrcMasterPageCnt)
1426                     {
1427                         pMasterNeed[nMPgNum] = true;
1428                     }
1429                 }
1430             }
1431         }
1432         // now determine the Mapping of the MasterPages
1433         sal_uInt16 nCurrentMaPagNum=nDstMasterPageCnt;
1434         for (sal_uInt16 i=0; i<nSrcMasterPageCnt; i++) {
1435             if (pMasterNeed[i]) {
1436                 pMasterMap[i]=nCurrentMaPagNum;
1437                 nCurrentMaPagNum++;
1438                 nMasterNeed++;
1439             }
1440         }
1441     }
1442 
1443     // get the MasterPages
1444     if (pMasterMap && pMasterNeed && nMasterNeed!=0) {
1445         for (sal_uInt16 i=nSrcMasterPageCnt; i>0;) {
1446             i--;
1447             if (pMasterNeed[i])
1448             {
1449                 // Always Clone to new model
1450                 const SdrPage* pPg1(rSourceModel.GetMasterPage(i));
1451                 rtl::Reference<SdrPage> pPg = pPg1->CloneSdrPage(*this);
1452 
1453                 if(!bTreadSourceAsConst)
1454                 {
1455                     // if requested, delete original/modify original model
1456                     rSourceModel.RemoveMasterPage(i);
1457                 }
1458 
1459                 if (pPg!=nullptr) {
1460                     // Now append all of them to the end of the DstModel.
1461                     // Don't use InsertMasterPage(), because everything is
1462                     // inconsistent until all are in.
1463                     maMasterPages.insert(maMasterPages.begin()+nDstMasterPageCnt, pPg);
1464                     MasterPageListChanged();
1465                     pPg->SetInserted();
1466                     m_bMPgNumsDirty=true;
1467                     if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg));
1468                 } else {
1469                     OSL_FAIL("SdrModel::Merge(): MasterPage not found in SourceModel.");
1470                 }
1471             }
1472         }
1473     }
1474 
1475     // get the drawing pages
1476     if (bInsPages) {
1477         sal_uInt16 nSourcePos=nFirstPageNum;
1478         sal_uInt16 nMergeCount=sal_uInt16(std::abs(static_cast<tools::Long>(static_cast<tools::Long>(nFirstPageNum)-nLastPageNum))+1);
1479         if (nDestPos>GetPageCount()) nDestPos=GetPageCount();
1480         while (nMergeCount>0)
1481         {
1482             // Always Clone to new model
1483             const SdrPage* pPg1(rSourceModel.GetPage(nSourcePos));
1484             rtl::Reference<SdrPage> pPg = pPg1->CloneSdrPage(*this);
1485 
1486             if(!bTreadSourceAsConst)
1487             {
1488                 // if requested, delete original/modify original model
1489                 rSourceModel.RemovePage(nSourcePos);
1490             }
1491 
1492             if (pPg!=nullptr) {
1493                 InsertPage(pPg.get(),nDestPos);
1494                 if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg));
1495 
1496                 if(pPg->TRG_HasMasterPage())
1497                 {
1498                     SdrPage& rMasterPage = pPg->TRG_GetMasterPage();
1499                     sal_uInt16 nMaPgNum(rMasterPage.GetPageNum());
1500 
1501                     if (bMergeMasterPages)
1502                     {
1503                         sal_uInt16 nNewNum(0xFFFF);
1504 
1505                         if(pMasterMap)
1506                         {
1507                             nNewNum = pMasterMap[nMaPgNum];
1508                         }
1509 
1510                         if(nNewNum != 0xFFFF)
1511                         {
1512                             // tdf#90357 here pPg and the to-be-set new masterpage are parts of the new model
1513                             // already, but the currently set masterpage is part of the old model. Remove master
1514                             // page from already cloned page to prevent creating wrong undo action that can
1515                             // eventually crash the app.
1516                             // Do *not* remove it directly after cloning - the old masterpage is still needed
1517                             // later to find the new to-be-set masterpage.
1518                             pPg->TRG_ClearMasterPage();
1519 
1520                             if(bUndo)
1521                             {
1522                                 AddUndo(GetSdrUndoFactory().CreateUndoPageChangeMasterPage(*pPg));
1523                             }
1524 
1525                             pPg->TRG_SetMasterPage(*GetMasterPage(nNewNum));
1526                         }
1527                         DBG_ASSERT(nNewNum!=0xFFFF,"SdrModel::Merge(): Something is crooked with the mapping of the MasterPages.");
1528                     } else {
1529                         if (nMaPgNum>=nDstMasterPageCnt) {
1530                             // This is outside of the original area of the MasterPage of the DstModel.
1531                             pPg->TRG_ClearMasterPage();
1532                         }
1533                     }
1534                 }
1535 
1536             } else {
1537                 OSL_FAIL("SdrModel::Merge(): Drawing page not found in SourceModel.");
1538             }
1539             nDestPos++;
1540             if (bReverse) nSourcePos--;
1541             else if (bTreadSourceAsConst) nSourcePos++;
1542             nMergeCount--;
1543         }
1544     }
1545 
1546     pMasterMap.reset();
1547     pMasterNeed.reset();
1548 
1549     m_bMPgNumsDirty=true;
1550     m_bPagNumsDirty=true;
1551 
1552     SetChanged();
1553     // TODO: Missing: merging and mapping of layers
1554     // at the objects as well as at the MasterPageDescriptors
1555     if (bUndo) EndUndo();
1556 }
1557 
1558 void SdrModel::SetStarDrawPreviewMode(bool bPreview)
1559 {
1560     if (!bPreview && m_bStarDrawPreviewMode && GetPageCount())
1561     {
1562         // Resetting is not allowed, because the Model might not be loaded completely
1563         SAL_WARN("svx", "SdrModel::SetStarDrawPreviewMode(): Resetting not allowed, because Model might not be complete.");
1564     }
1565     else
1566     {
1567         m_bStarDrawPreviewMode = bPreview;
1568     }
1569 }
1570 
1571 uno::Reference< uno::XInterface > const & SdrModel::getUnoModel()
1572 {
1573     if( !mxUnoModel.is() )
1574         mxUnoModel = createUnoModel();
1575 
1576     return mxUnoModel;
1577 }
1578 
1579 void SdrModel::setUnoModel( const css::uno::Reference< css::uno::XInterface >& xModel )
1580 {
1581     mxUnoModel = xModel;
1582 }
1583 
1584 void SdrModel::adaptSizeAndBorderForAllPages(
1585     const Size& /*rNewSize*/,
1586     tools::Long /*nLeft*/,
1587     tools::Long /*nRight*/,
1588     tools::Long /*nUpper*/,
1589     tools::Long /*nLower*/)
1590 {
1591     // base implementation does currently nothing. It may be added if needed,
1592     // but we are on SdrModel level here, thus probably have not enough information
1593     // to do this for higher-level (derived) Models (e.g. Draw/Impress)
1594 }
1595 
1596 uno::Reference< uno::XInterface > SdrModel::createUnoModel()
1597 {
1598     OSL_FAIL( "SdrModel::createUnoModel() - base implementation should not be called!" );
1599     css::uno::Reference< css::uno::XInterface > xInt;
1600     return xInt;
1601 }
1602 
1603 void SdrModel::setLock( bool bLock )
1604 {
1605     if( mbModelLocked != bLock )
1606     {
1607         // #i120437# need to set first, else ImpReformatAllEdgeObjects will do nothing
1608         mbModelLocked = bLock;
1609 
1610         if( !bLock )
1611         {
1612             ImpReformatAllEdgeObjects();
1613         }
1614     }
1615 }
1616 
1617 
1618 void SdrModel::MigrateItemSet( const SfxItemSet* pSourceSet, SfxItemSet* pDestSet, SdrModel* pNewModelel )
1619 {
1620     assert(pNewModelel != nullptr);
1621     if( !(pSourceSet && pDestSet && (pSourceSet != pDestSet )) )
1622         return;
1623 
1624     SfxWhichIter aWhichIter(*pSourceSet);
1625     sal_uInt16 nWhich(aWhichIter.FirstWhich());
1626     const SfxPoolItem *pPoolItem;
1627 
1628     while(nWhich)
1629     {
1630         if(SfxItemState::SET == pSourceSet->GetItemState(nWhich, false, &pPoolItem))
1631         {
1632             std::unique_ptr<SfxPoolItem> pResultItem;
1633 
1634             switch( nWhich )
1635             {
1636             case XATTR_FILLBITMAP:
1637                 pResultItem = static_cast<const XFillBitmapItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1638                 break;
1639             case XATTR_LINEDASH:
1640                 pResultItem = static_cast<const XLineDashItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1641                 break;
1642             case XATTR_LINESTART:
1643                 pResultItem = static_cast<const XLineStartItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1644                 break;
1645             case XATTR_LINEEND:
1646                 pResultItem = static_cast<const XLineEndItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1647                 break;
1648             case XATTR_FILLGRADIENT:
1649                 pResultItem = static_cast<const XFillGradientItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1650                 break;
1651             case XATTR_FILLFLOATTRANSPARENCE:
1652                 // allow all kinds of XFillFloatTransparenceItem to be set
1653                 pResultItem = static_cast<const XFillFloatTransparenceItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1654                 break;
1655             case XATTR_FILLHATCH:
1656                 pResultItem = static_cast<const XFillHatchItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1657                 break;
1658             }
1659 
1660             // set item
1661             if( pResultItem )
1662             {
1663                 pDestSet->Put(*pResultItem);
1664                 pResultItem.reset();
1665             }
1666             else
1667                 pDestSet->Put(*pPoolItem);
1668         }
1669         nWhich = aWhichIter.NextWhich();
1670     }
1671 }
1672 
1673 
1674 void SdrModel::SetForbiddenCharsTable(const std::shared_ptr<SvxForbiddenCharactersTable>& xForbiddenChars)
1675 {
1676     mpForbiddenCharactersTable = xForbiddenChars;
1677 
1678     ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1679     ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1680 }
1681 
1682 
1683 void SdrModel::SetCharCompressType( CharCompressType nType )
1684 {
1685     if( nType != mnCharCompressType )
1686     {
1687         mnCharCompressType = nType;
1688         ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1689         ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1690     }
1691 }
1692 
1693 void SdrModel::SetKernAsianPunctuation( bool bEnabled )
1694 {
1695     if( mbKernAsianPunctuation != bEnabled )
1696     {
1697         mbKernAsianPunctuation = bEnabled;
1698         ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1699         ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1700     }
1701 }
1702 
1703 void SdrModel::SetAddExtLeading( bool bEnabled )
1704 {
1705     if( mbAddExtLeading != bEnabled )
1706     {
1707         mbAddExtLeading = bEnabled;
1708         ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1709         ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1710     }
1711 }
1712 
1713 void SdrModel::SetAnchoredTextOverflowLegacy(bool bEnabled)
1714 {
1715     mpImpl->mbAnchoredTextOverflowLegacy = bEnabled;
1716 }
1717 
1718 bool SdrModel::IsAnchoredTextOverflowLegacy() const
1719 {
1720     return mpImpl->mbAnchoredTextOverflowLegacy;
1721 }
1722 
1723 void SdrModel::ReformatAllTextObjects()
1724 {
1725     ImpReformatAllTextObjects();
1726 }
1727 
1728 std::unique_ptr<SdrOutliner> SdrModel::createOutliner( OutlinerMode nOutlinerMode )
1729 {
1730     if( !mpOutlinerCache )
1731         mpOutlinerCache.reset(new SdrOutlinerCache(this));
1732 
1733     return mpOutlinerCache->createOutliner( nOutlinerMode );
1734 }
1735 
1736 std::vector<SdrOutliner*> SdrModel::GetActiveOutliners() const
1737 {
1738     std::vector< SdrOutliner* > aRet(mpOutlinerCache ? mpOutlinerCache->GetActiveOutliners() : std::vector< SdrOutliner* >());
1739     aRet.push_back(m_pDrawOutliner.get());
1740     aRet.push_back(m_pHitTestOutliner.get());
1741 
1742     return aRet;
1743 }
1744 
1745 void SdrModel::disposeOutliner( std::unique_ptr<SdrOutliner> pOutliner )
1746 {
1747     if( mpOutlinerCache )
1748         mpOutlinerCache->disposeOutliner( std::move(pOutliner) );
1749 }
1750 
1751 SvxNumType SdrModel::GetPageNumType() const
1752 {
1753     return SVX_NUM_ARABIC;
1754 }
1755 
1756 void SdrModel::ReadUserDataSequenceValue(const css::beans::PropertyValue* pValue)
1757 {
1758     if (pValue->Name == "AnchoredTextOverflowLegacy")
1759     {
1760         bool bBool = false;
1761         if (pValue->Value >>= bBool)
1762         {
1763             mpImpl->mbAnchoredTextOverflowLegacy = bBool;
1764         }
1765     }
1766 }
1767 
1768 template <typename T>
1769 static void addPair(std::vector< std::pair< OUString, Any > >& aUserData, const OUString& name, const T val)
1770 {
1771     aUserData.push_back(std::pair< OUString, Any >(name, css::uno::makeAny(val)));
1772 }
1773 
1774 void SdrModel::WriteUserDataSequence(css::uno::Sequence < css::beans::PropertyValue >& rValues)
1775 {
1776     std::vector< std::pair< OUString, Any > > aUserData;
1777     addPair(aUserData, "AnchoredTextOverflowLegacy", IsAnchoredTextOverflowLegacy());
1778 
1779     const sal_Int32 nOldLength = rValues.getLength();
1780     rValues.realloc(nOldLength + aUserData.size());
1781 
1782     css::beans::PropertyValue* pValue = &(rValues.getArray()[nOldLength]);
1783 
1784     for (const auto &aIter : aUserData)
1785     {
1786         pValue->Name = aIter.first;
1787         pValue->Value = aIter.second;
1788         ++pValue;
1789     }
1790 }
1791 
1792 const SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum) const
1793 {
1794     return nPgNum < maPages.size() ? maPages[nPgNum].get() : nullptr;
1795 }
1796 
1797 SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum)
1798 {
1799     return nPgNum < maPages.size() ? maPages[nPgNum].get() : nullptr;
1800 }
1801 
1802 sal_uInt16 SdrModel::GetPageCount() const
1803 {
1804     return sal_uInt16(maPages.size());
1805 }
1806 
1807 void SdrModel::PageListChanged()
1808 {
1809 }
1810 
1811 TextChain *SdrModel::GetTextChain() const
1812 {
1813     return m_pTextChain.get();
1814 }
1815 
1816 const SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum) const
1817 {
1818     DBG_ASSERT(nPgNum < maMasterPages.size(), "SdrModel::GetMasterPage: Access out of range (!)");
1819     return maMasterPages[nPgNum].get();
1820 }
1821 
1822 SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum)
1823 {
1824     DBG_ASSERT(nPgNum < maMasterPages.size(), "SdrModel::GetMasterPage: Access out of range (!)");
1825     return maMasterPages[nPgNum].get();
1826 }
1827 
1828 sal_uInt16 SdrModel::GetMasterPageCount() const
1829 {
1830     return sal_uInt16(maMasterPages.size());
1831 }
1832 
1833 void SdrModel::MasterPageListChanged()
1834 {
1835 }
1836 
1837 void SdrModel::SetSdrUndoManager( SfxUndoManager* pUndoManager )
1838 {
1839     mpImpl->mpUndoManager = pUndoManager;
1840 }
1841 
1842 SfxUndoManager* SdrModel::GetSdrUndoManager() const
1843 {
1844     return mpImpl->mpUndoManager;
1845 }
1846 
1847 SdrUndoFactory& SdrModel::GetSdrUndoFactory() const
1848 {
1849     if( !mpImpl->mpUndoFactory )
1850         mpImpl->mpUndoFactory = new SdrUndoFactory;
1851     return *mpImpl->mpUndoFactory;
1852 }
1853 
1854 void SdrModel::SetSdrUndoFactory( SdrUndoFactory* pUndoFactory )
1855 {
1856     if( pUndoFactory && (pUndoFactory != mpImpl->mpUndoFactory) )
1857     {
1858         delete mpImpl->mpUndoFactory;
1859         mpImpl->mpUndoFactory = pUndoFactory;
1860     }
1861 }
1862 
1863 void SdrModel::dumpAsXml(xmlTextWriterPtr pWriter) const
1864 {
1865     (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrModel"));
1866     (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1867 
1868     sal_uInt16 nPageCount = GetPageCount();
1869     for (sal_uInt16 i = 0; i < nPageCount; ++i)
1870     {
1871         if (const SdrPage* pPage = GetPage(i))
1872             pPage->dumpAsXml(pWriter);
1873     }
1874 
1875     (void)xmlTextWriterEndElement(pWriter);
1876 }
1877 
1878 const css::uno::Sequence< sal_Int8 >& SdrModel::getUnoTunnelId()
1879 {
1880     static const UnoTunnelIdInit theSdrModelUnoTunnelImplementationId;
1881     return theSdrModelUnoTunnelImplementationId.getSeq();
1882 }
1883 
1884 
1885 SdrHint::SdrHint(SdrHintKind eNewHint)
1886 :   SfxHint(SfxHintId::ThisIsAnSdrHint),
1887     meHint(eNewHint),
1888     mpObj(nullptr),
1889     mpPage(nullptr)
1890 {
1891 }
1892 
1893 SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj)
1894 :   SfxHint(SfxHintId::ThisIsAnSdrHint),
1895     meHint(eNewHint),
1896     mpObj(&rNewObj),
1897     mpPage(rNewObj.getSdrPageFromSdrObject())
1898 {
1899 }
1900 
1901 SdrHint::SdrHint(SdrHintKind eNewHint, const SdrPage* pPage)
1902 :   SfxHint(SfxHintId::ThisIsAnSdrHint),
1903     meHint(eNewHint),
1904     mpObj(nullptr),
1905     mpPage(pPage)
1906 {
1907 }
1908 
1909 SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj, const SdrPage* pPage)
1910 :   SfxHint(SfxHintId::ThisIsAnSdrHint),
1911     meHint(eNewHint),
1912     mpObj(&rNewObj),
1913     mpPage(pPage)
1914 {
1915 }
1916 
1917 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1918