Bump version to 24.04.3.4
[LibreOffice.git] / svx / source / svdraw / svdmodel.cxx
blob90fc769e20b7a05aba967782896ddd6d96c0e564
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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/compatflags.hxx>
33 #include <svx/xbtmpit.hxx>
34 #include <svx/xlndsit.hxx>
35 #include <svx/xlnedit.hxx>
36 #include <svx/xflgrit.hxx>
37 #include <svx/xflftrit.hxx>
38 #include <svx/xflhtit.hxx>
39 #include <svx/xlnstit.hxx>
40 #include <editeng/editeng.hxx>
41 #include <svx/xtable.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 <svx/theme/IThemeColorChanger.hxx>
54 #include <svdoutlinercache.hxx>
55 #include <svx/sdasitm.hxx>
56 #include <officecfg/Office/Common.hxx>
57 #include <editeng/fontitem.hxx>
58 #include <editeng/colritem.hxx>
59 #include <editeng/fhgtitem.hxx>
60 #include <svl/style.hxx>
61 #include <editeng/forbiddencharacterstable.hxx>
62 #include <comphelper/servicehelper.hxx>
63 #include <comphelper/storagehelper.hxx>
64 #include <unotools/localedatawrapper.hxx>
65 #include <unotools/syslocale.hxx>
66 #include <editeng/eeitem.hxx>
67 #include <svl/itemset.hxx>
68 #include <vcl/settings.hxx>
69 #include <vcl/svapp.hxx>
70 #include <memory>
71 #include <libxml/xmlwriter.h>
72 #include <sfx2/viewsh.hxx>
73 #include <o3tl/enumrange.hxx>
74 #include <comphelper/diagnose_ex.hxx>
75 #include <tools/UnitConversion.hxx>
76 #include <docmodel/theme/Theme.hxx>
77 #include <svx/ColorSets.hxx>
78 #include <svx/svditer.hxx>
79 #include <svx/svdoashp.hxx>
82 using namespace ::com::sun::star;
84 struct SdrModelImpl
86 SfxUndoManager* mpUndoManager;
87 SdrUndoFactory* mpUndoFactory;
88 bool mbAnchoredTextOverflowLegacy; // tdf#99729 compatibility flag
89 bool mbLegacyFontwork; // tdf#148000 compatibility flag
90 bool mbConnectorUseSnapRect; // tdf#149756 compatibility flag
91 bool mbIgnoreBreakAfterMultilineField; ///< tdf#148966 compatibility flag
92 std::shared_ptr<model::Theme> mpTheme;
93 std::shared_ptr<svx::IThemeColorChanger> mpThemeColorChanger;
95 SdrModelImpl()
96 : mpUndoManager(nullptr)
97 , mpUndoFactory(nullptr)
98 , mbAnchoredTextOverflowLegacy(false)
99 , mbLegacyFontwork(false)
100 , mbConnectorUseSnapRect(false)
101 , mbIgnoreBreakAfterMultilineField(false)
102 , mpTheme(new model::Theme("Office"))
105 void initTheme()
107 auto const* pColorSet = svx::ColorSets::get().getColorSet(u"LibreOffice");
108 if (pColorSet)
110 std::shared_ptr<model::ColorSet> pDefaultColorSet(new model::ColorSet(*pColorSet));
111 mpTheme->setColorSet(pDefaultColorSet);
117 SdrModel::SdrModel(SfxItemPool* pPool, comphelper::IEmbeddedHelper* pEmbeddedHelper, bool bDisablePropertyFiles)
118 : m_eObjUnit(SdrEngineDefaults::GetMapUnit())
119 , m_eUIUnit(FieldUnit::MM)
120 , m_aUIScale(Fraction(1,1))
121 , m_nUIUnitDecimalMark(0)
122 , m_pLayerAdmin(new SdrLayerAdmin)
123 , m_pItemPool(pPool)
124 , m_pEmbeddedHelper(pEmbeddedHelper)
125 , mnDefTextHgt(SdrEngineDefaults::GetFontHeight())
126 , m_pRefOutDev(nullptr)
127 , m_pDefaultStyleSheet(nullptr)
128 , mpDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj(nullptr)
129 , m_pLinkManager(nullptr)
130 , m_nUndoLevel(0)
131 , m_bIsWriter(true)
132 , m_bThemedControls(true)
133 , mbUndoEnabled(true)
134 , mbChanged(false)
135 , m_bPagNumsDirty(false)
136 , m_bMPgNumsDirty(false)
137 , m_bTransportContainer(false)
138 , m_bReadOnly(false)
139 , m_bTransparentTextFrames(false)
140 , m_bSwapGraphics(false)
141 , m_bPasteResize(false)
142 , m_bStarDrawPreviewMode(false)
143 , mbDisableTextEditUsesCommonUndoManager(false)
144 , mbVOCInvalidationIsReliable(false)
145 , m_nDefaultTabulator(0)
146 , m_nMaxUndoCount(16)
147 , m_pTextChain(new TextChain)
148 , mpImpl(new SdrModelImpl)
149 , mnCharCompressType(CharCompressType::NONE)
150 , mnHandoutPageCount(0)
151 , mbModelLocked(false)
152 , mbKernAsianPunctuation(false)
153 , mbAddExtLeading(false)
154 , mbInDestruction(false)
156 if (!utl::ConfigManager::IsFuzzing())
158 mnCharCompressType = static_cast<CharCompressType>(
159 officecfg::Office::Common::AsianLayout::CompressCharacterDistance::get());
162 if (m_pItemPool == nullptr)
164 m_pItemPool = new SdrItemPool(nullptr);
165 // Outliner doesn't have its own Pool, so use the EditEngine's
166 rtl::Reference<SfxItemPool> pOutlPool=EditEngine::CreatePool();
167 // OutlinerPool as SecondaryPool of SdrPool
168 m_pItemPool->SetSecondaryPool(pOutlPool.get());
169 // remember that I created both pools myself
170 m_bIsWriter = false;
172 m_pItemPool->SetDefaultMetric(m_eObjUnit);
174 // using static SdrEngineDefaults only if default SvxFontHeight item is not available
175 const SfxPoolItem* pPoolItem = m_pItemPool->GetPoolDefaultItem( EE_CHAR_FONTHEIGHT );
176 if (pPoolItem)
177 mnDefTextHgt = static_cast<const SvxFontHeightItem*>(pPoolItem)->GetHeight();
179 m_pItemPool->SetPoolDefaultItem( makeSdrTextWordWrapItem( false ) );
181 SetTextDefaults();
182 m_pLayerAdmin->SetModel(this);
183 ImpSetUIUnit();
185 // can't create DrawOutliner OnDemand, because I can't get the Pool,
186 // then (only from 302 onwards!)
187 m_pDrawOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this);
188 ImpSetOutlinerDefaults(m_pDrawOutliner.get(), true);
190 m_pHitTestOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this);
191 ImpSetOutlinerDefaults(m_pHitTestOutliner.get(), true);
193 /* Start Text Chaining related code */
194 // Initialize Chaining Outliner
195 m_pChainingOutliner = SdrMakeOutliner( OutlinerMode::TextObject, *this );
196 ImpSetOutlinerDefaults(m_pChainingOutliner.get(), true);
198 ImpCreateTables(bDisablePropertyFiles || utl::ConfigManager::IsFuzzing());
200 mpImpl->initTheme();
203 void SdrModel::implDtorClearModel()
205 mbInDestruction = true;
207 Broadcast(SdrHint(SdrHintKind::ModelCleared));
209 mpOutlinerCache.reset();
211 ClearUndoBuffer();
212 #ifdef DBG_UTIL
213 SAL_WARN_IF(m_pCurrentUndoGroup, "svx", "In the Dtor of the SdrModel there is an open Undo left: \""
214 << m_pCurrentUndoGroup->GetComment() << '\"');
215 #endif
216 m_pCurrentUndoGroup.reset();
218 ClearModel(true);
221 SdrModel::~SdrModel()
223 implDtorClearModel();
225 #ifdef DBG_UTIL
226 // SdrObjectLifetimeWatchDog:
227 if(!maAllIncarnatedObjects.empty())
229 SAL_WARN("svx",
230 "SdrModel::~SdrModel: Not all incarnations of SdrObjects deleted, possible memory leak");
231 for (const auto & pObj : maAllIncarnatedObjects)
232 SAL_WARN("svx", "leaked instance of " << typeid(*pObj).name());
234 #endif
236 m_pLayerAdmin.reset();
238 m_pTextChain.reset();
239 // Delete DrawOutliner only after deleting ItemPool, because ItemPool
240 // references Items of the DrawOutliner!
241 m_pChainingOutliner.reset();
242 m_pHitTestOutliner.reset();
243 m_pDrawOutliner.reset();
245 // delete StyleSheetPool, derived classes should not do this since
246 // the DrawingEngine may need it in its destructor
247 if( mxStyleSheetPool.is() )
249 uno::Reference<lang::XComponent> xComponent( getXWeak( mxStyleSheetPool.get() ), uno::UNO_QUERY );
250 if( xComponent.is() ) try
252 xComponent->dispose();
254 catch (uno::RuntimeException&)
257 mxStyleSheetPool.clear();
260 mpForbiddenCharactersTable.reset();
262 delete mpImpl->mpUndoFactory;
265 void SdrModel::SetSwapGraphics()
267 m_bSwapGraphics = true;
270 bool SdrModel::IsReadOnly() const
272 return m_bReadOnly;
275 void SdrModel::SetReadOnly(bool bYes)
277 m_bReadOnly=bYes;
281 void SdrModel::SetMaxUndoActionCount(sal_uInt32 nCount)
283 if (nCount<1) nCount=1;
284 m_nMaxUndoCount=nCount;
285 while (m_aUndoStack.size()>m_nMaxUndoCount)
286 m_aUndoStack.pop_back();
289 void SdrModel::ClearUndoBuffer()
291 m_aUndoStack.clear();
292 m_aRedoStack.clear();
295 bool SdrModel::HasUndoActions() const
297 return !m_aUndoStack.empty();
300 bool SdrModel::HasRedoActions() const
302 return !m_aRedoStack.empty();
305 void SdrModel::Undo()
307 if( mpImpl->mpUndoManager )
309 OSL_FAIL("svx::SdrModel::Undo(), method not supported with application undo manager!");
311 else
313 if(HasUndoActions())
315 SfxUndoAction* pDo = m_aUndoStack.front().get();
316 const bool bWasUndoEnabled = mbUndoEnabled;
317 mbUndoEnabled = false;
318 pDo->Undo();
319 std::unique_ptr<SfxUndoAction> p = std::move(m_aUndoStack.front());
320 m_aUndoStack.pop_front();
321 m_aRedoStack.emplace_front(std::move(p));
322 mbUndoEnabled = bWasUndoEnabled;
327 void SdrModel::Redo()
329 if( mpImpl->mpUndoManager )
331 OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!");
333 else
335 if(HasRedoActions())
337 SfxUndoAction* pDo = m_aRedoStack.front().get();
338 const bool bWasUndoEnabled = mbUndoEnabled;
339 mbUndoEnabled = false;
340 pDo->Redo();
341 std::unique_ptr<SfxUndoAction> p = std::move(m_aRedoStack.front());
342 m_aRedoStack.pop_front();
343 m_aUndoStack.emplace_front(std::move(p));
344 mbUndoEnabled = bWasUndoEnabled;
349 void SdrModel::Repeat(SfxRepeatTarget& rView)
351 if( mpImpl->mpUndoManager )
353 OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!");
355 else
357 if(HasUndoActions())
359 SfxUndoAction* pDo = m_aUndoStack.front().get();
360 if(pDo->CanRepeat(rView))
362 pDo->Repeat(rView);
368 void SdrModel::ImpPostUndoAction(std::unique_ptr<SdrUndoAction> pUndo)
370 DBG_ASSERT( mpImpl->mpUndoManager == nullptr, "svx::SdrModel::ImpPostUndoAction(), method not supported with application undo manager!" );
371 if( !IsUndoEnabled() )
372 return;
374 if (m_aUndoLink)
376 m_aUndoLink(std::move(pUndo));
378 else
380 m_aUndoStack.emplace_front(std::move(pUndo));
381 while (m_aUndoStack.size()>m_nMaxUndoCount)
383 m_aUndoStack.pop_back();
385 m_aRedoStack.clear();
389 void SdrModel::BegUndo()
391 if( mpImpl->mpUndoManager )
393 ViewShellId nViewShellId(-1);
394 if (SfxViewShell* pViewShell = SfxViewShell::Current())
395 nViewShellId = pViewShell->GetViewShellId();
396 mpImpl->mpUndoManager->EnterListAction("","",0,nViewShellId);
397 m_nUndoLevel++;
399 else if( IsUndoEnabled() )
401 if(!m_pCurrentUndoGroup)
403 m_pCurrentUndoGroup.reset(new SdrUndoGroup(*this));
404 m_nUndoLevel=1;
406 else
408 m_nUndoLevel++;
413 void SdrModel::BegUndo(const OUString& rComment)
415 if( mpImpl->mpUndoManager )
417 ViewShellId nViewShellId(-1);
418 if (SfxViewShell* pViewShell = SfxViewShell::Current())
419 nViewShellId = pViewShell->GetViewShellId();
420 mpImpl->mpUndoManager->EnterListAction( rComment, "", 0, nViewShellId );
421 m_nUndoLevel++;
423 else if( IsUndoEnabled() )
425 BegUndo();
426 if (m_nUndoLevel==1)
428 m_pCurrentUndoGroup->SetComment(rComment);
433 void SdrModel::BegUndo(const OUString& rComment, const OUString& rObjDescr, SdrRepeatFunc eFunc)
435 if( mpImpl->mpUndoManager )
437 OUString aComment(rComment);
438 if( !aComment.isEmpty() && !rObjDescr.isEmpty() )
440 aComment = aComment.replaceFirst("%1", rObjDescr);
442 ViewShellId nViewShellId(-1);
443 if (SfxViewShell* pViewShell = SfxViewShell::Current())
444 nViewShellId = pViewShell->GetViewShellId();
445 mpImpl->mpUndoManager->EnterListAction( aComment,"",0,nViewShellId );
446 m_nUndoLevel++;
448 else if( IsUndoEnabled() )
450 BegUndo();
451 if (m_nUndoLevel==1)
453 m_pCurrentUndoGroup->SetComment(rComment);
454 m_pCurrentUndoGroup->SetObjDescription(rObjDescr);
455 m_pCurrentUndoGroup->SetRepeatFunction(eFunc);
460 void SdrModel::EndUndo()
462 DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::EndUndo(): UndoLevel is already 0!");
463 if( mpImpl->mpUndoManager )
465 if( m_nUndoLevel )
467 m_nUndoLevel--;
468 mpImpl->mpUndoManager->LeaveListAction();
471 else
473 if(m_pCurrentUndoGroup!=nullptr && IsUndoEnabled())
475 m_nUndoLevel--;
476 if(m_nUndoLevel==0)
478 if(m_pCurrentUndoGroup->GetActionCount()!=0)
480 ImpPostUndoAction(std::move(m_pCurrentUndoGroup));
482 else
484 // was empty
485 m_pCurrentUndoGroup.reset();
492 void SdrModel::SetUndoComment(const OUString& rComment)
494 DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!");
496 if( mpImpl->mpUndoManager )
498 OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" );
500 else if( IsUndoEnabled() && m_nUndoLevel==1)
502 m_pCurrentUndoGroup->SetComment(rComment);
506 void SdrModel::SetUndoComment(const OUString& rComment, const OUString& rObjDescr)
508 DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!");
509 if( mpImpl->mpUndoManager )
511 OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" );
513 else
515 if (m_nUndoLevel==1)
517 m_pCurrentUndoGroup->SetComment(rComment);
518 m_pCurrentUndoGroup->SetObjDescription(rObjDescr);
523 void SdrModel::AddUndo(std::unique_ptr<SdrUndoAction> pUndo)
525 if( mpImpl->mpUndoManager )
527 mpImpl->mpUndoManager->AddUndoAction( std::move(pUndo) );
529 else if( IsUndoEnabled() )
531 if (m_pCurrentUndoGroup)
533 m_pCurrentUndoGroup->AddAction(std::move(pUndo));
535 else
537 ImpPostUndoAction(std::move(pUndo));
542 void SdrModel::EnableUndo( bool bEnable )
544 if( mpImpl->mpUndoManager )
546 mpImpl->mpUndoManager->EnableUndo( bEnable );
548 else
550 mbUndoEnabled = bEnable;
554 bool SdrModel::IsUndoEnabled() const
556 if( mpImpl->mpUndoManager )
558 return mpImpl->mpUndoManager->IsUndoEnabled();
560 else
562 return mbUndoEnabled;
566 void SdrModel::ImpCreateTables(bool bDisablePropertyFiles)
568 // use standard path for initial construction
569 const OUString aTablePath(!bDisablePropertyFiles ? SvtPathOptions().GetPalettePath() : "");
571 for( auto i : o3tl::enumrange<XPropertyListType>() )
573 maProperties[i] = XPropertyList::CreatePropertyList(i, aTablePath, ""/*TODO?*/ );
577 void SdrModel::ClearModel(bool bCalledFromDestructor)
579 if(bCalledFromDestructor)
581 mbInDestruction = true;
584 sal_Int32 i;
585 // delete all drawing pages
586 sal_Int32 nCount=GetPageCount();
587 for (i=nCount-1; i>=0; i--)
589 DeletePage( static_cast<sal_uInt16>(i) );
591 maPages.clear();
592 PageListChanged();
594 // delete all Masterpages
595 nCount=GetMasterPageCount();
596 for(i=nCount-1; i>=0; i--)
598 DeleteMasterPage( static_cast<sal_uInt16>(i) );
600 maMasterPages.clear();
601 MasterPageListChanged();
603 m_pLayerAdmin->ClearLayers();
606 SdrModel* SdrModel::AllocModel() const
608 SdrModel* pModel=new SdrModel();
609 pModel->SetScaleUnit(m_eObjUnit);
610 return pModel;
613 rtl::Reference<SdrPage> SdrModel::AllocPage(bool bMasterPage)
615 return new SdrPage(*this,bMasterPage);
618 void SdrModel::SetTextDefaults() const
620 SetTextDefaults( m_pItemPool.get(), mnDefTextHgt );
623 void SdrModel::SetTextDefaults( SfxItemPool* pItemPool, sal_Int32 nDefTextHgt )
625 // set application-language specific dynamic pool language defaults
626 SvxFontItem aSvxFontItem( EE_CHAR_FONTINFO) ;
627 SvxFontItem aSvxFontItemCJK(EE_CHAR_FONTINFO_CJK);
628 SvxFontItem aSvxFontItemCTL(EE_CHAR_FONTINFO_CTL);
629 LanguageType nLanguage;
630 if (!utl::ConfigManager::IsFuzzing())
631 nLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
632 else
633 nLanguage = LANGUAGE_ENGLISH_US;
635 // get DEFAULTFONT_LATIN_TEXT and set at pool as dynamic default
636 vcl::Font aFont(OutputDevice::GetDefaultFont(DefaultFontType::LATIN_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
637 aSvxFontItem.SetFamily(aFont.GetFamilyType());
638 aSvxFontItem.SetFamilyName(aFont.GetFamilyName());
639 aSvxFontItem.SetStyleName(OUString());
640 aSvxFontItem.SetPitch( aFont.GetPitch());
641 aSvxFontItem.SetCharSet( aFont.GetCharSet() );
642 pItemPool->SetPoolDefaultItem(aSvxFontItem);
644 // get DEFAULTFONT_CJK_TEXT and set at pool as dynamic default
645 vcl::Font aFontCJK(OutputDevice::GetDefaultFont(DefaultFontType::CJK_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
646 aSvxFontItemCJK.SetFamily( aFontCJK.GetFamilyType());
647 aSvxFontItemCJK.SetFamilyName(aFontCJK.GetFamilyName());
648 aSvxFontItemCJK.SetStyleName(OUString());
649 aSvxFontItemCJK.SetPitch( aFontCJK.GetPitch());
650 aSvxFontItemCJK.SetCharSet( aFontCJK.GetCharSet());
651 pItemPool->SetPoolDefaultItem(aSvxFontItemCJK);
653 // get DEFAULTFONT_CTL_TEXT and set at pool as dynamic default
654 vcl::Font aFontCTL(OutputDevice::GetDefaultFont(DefaultFontType::CTL_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
655 aSvxFontItemCTL.SetFamily(aFontCTL.GetFamilyType());
656 aSvxFontItemCTL.SetFamilyName(aFontCTL.GetFamilyName());
657 aSvxFontItemCTL.SetStyleName(OUString());
658 aSvxFontItemCTL.SetPitch( aFontCTL.GetPitch() );
659 aSvxFontItemCTL.SetCharSet( aFontCTL.GetCharSet());
660 pItemPool->SetPoolDefaultItem(aSvxFontItemCTL);
662 // set dynamic FontHeight defaults
663 pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT ) );
664 pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CJK ) );
665 pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CTL ) );
667 // set FontColor defaults
668 pItemPool->SetPoolDefaultItem( SvxColorItem(SdrEngineDefaults::GetFontColor(), EE_CHAR_COLOR) );
671 SdrOutliner& SdrModel::GetDrawOutliner(const SdrTextObj* pObj) const
673 m_pDrawOutliner->SetTextObj(pObj);
674 return *m_pDrawOutliner;
677 SdrOutliner& SdrModel::GetChainingOutliner(const SdrTextObj* pObj) const
679 m_pChainingOutliner->SetTextObj(pObj);
680 return *m_pChainingOutliner;
683 const SdrTextObj* SdrModel::GetFormattingTextObj() const
685 if (m_pDrawOutliner!=nullptr) {
686 return m_pDrawOutliner->GetTextObj();
688 return nullptr;
691 void SdrModel::ImpSetOutlinerDefaults( SdrOutliner* pOutliner, bool bInit )
693 // Initialization of the Outliners for drawing text and HitTest
694 if( bInit )
696 pOutliner->EraseVirtualDevice();
697 pOutliner->SetUpdateLayout(false);
698 pOutliner->SetEditTextObjectPool(m_pItemPool.get());
699 pOutliner->SetDefTab(m_nDefaultTabulator);
702 pOutliner->SetRefDevice(GetRefDevice());
703 Outliner::SetForbiddenCharsTable(GetForbiddenCharsTable());
704 pOutliner->SetAsianCompressionMode( mnCharCompressType );
705 pOutliner->SetKernAsianPunctuation( IsKernAsianPunctuation() );
706 pOutliner->SetAddExtLeading( IsAddExtLeading() );
708 if ( !GetRefDevice() )
710 MapMode aMapMode(m_eObjUnit);
711 pOutliner->SetRefMapMode(aMapMode);
715 void SdrModel::SetRefDevice(OutputDevice* pDev)
717 m_pRefOutDev=pDev;
718 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
719 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
720 RefDeviceChanged();
723 void SdrModel::ImpReformatAllTextObjects()
725 if( isLocked() )
726 return;
728 sal_uInt16 nCount=GetMasterPageCount();
729 sal_uInt16 nNum;
730 for (nNum=0; nNum<nCount; nNum++) {
731 GetMasterPage(nNum)->ReformatAllTextObjects();
733 nCount=GetPageCount();
734 for (nNum=0; nNum<nCount; nNum++) {
735 GetPage(nNum)->ReformatAllTextObjects();
739 /* steps over all available pages and sends notify messages to
740 all edge objects that are connected to other objects so that
741 they may reposition themselves
743 void SdrModel::ImpReformatAllEdgeObjects()
745 if( isLocked() )
746 return;
748 sal_uInt16 nCount=GetMasterPageCount();
749 sal_uInt16 nNum;
750 for (nNum=0; nNum<nCount; nNum++)
752 GetMasterPage(nNum)->ReformatAllEdgeObjects();
754 nCount=GetPageCount();
755 for (nNum=0; nNum<nCount; nNum++)
757 GetPage(nNum)->ReformatAllEdgeObjects();
761 uno::Reference<embed::XStorage> SdrModel::GetDocumentStorage() const
763 uno::Reference<document::XStorageBasedDocument> const xSBD(
764 const_cast<SdrModel*>(this)->getUnoModel(), uno::UNO_QUERY);
765 if (!xSBD.is())
767 SAL_WARN("svx", "no UNO model");
768 return nullptr;
770 return xSBD->getDocumentStorage();
773 uno::Reference<io::XInputStream>
774 SdrModel::GetDocumentStream( OUString const& rURL,
775 ::comphelper::LifecycleProxy const & rProxy) const
777 uno::Reference<embed::XStorage> const xStorage(GetDocumentStorage());
778 if (!xStorage.is())
780 SAL_WARN("svx", "no storage?");
781 return nullptr;
783 try {
784 uno::Reference<io::XStream> const xStream(
785 ::comphelper::OStorageHelper::GetStreamAtPackageURL(
786 xStorage, rURL, embed::ElementModes::READ, rProxy));
787 return (xStream.is()) ? xStream->getInputStream() : nullptr;
789 catch (container::NoSuchElementException const&)
791 SAL_INFO("svx", "not found");
793 catch (uno::Exception const&)
795 TOOLS_WARN_EXCEPTION("svx", "");
797 return nullptr;
800 // convert template attributes from the string into "hard" attributes
801 void SdrModel::BurnInStyleSheetAttributes()
803 sal_uInt16 nCount=GetMasterPageCount();
804 sal_uInt16 nNum;
805 for (nNum=0; nNum<nCount; nNum++) {
806 GetMasterPage(nNum)->BurnInStyleSheetAttributes();
808 nCount=GetPageCount();
809 for (nNum=0; nNum<nCount; nNum++) {
810 GetPage(nNum)->BurnInStyleSheetAttributes();
814 void SdrModel::RefDeviceChanged()
816 Broadcast(SdrHint(SdrHintKind::RefDeviceChange));
817 ImpReformatAllTextObjects();
820 void SdrModel::SetDefaultFontHeight(sal_Int32 nVal)
822 if (nVal!=mnDefTextHgt) {
823 mnDefTextHgt=nVal;
824 ImpReformatAllTextObjects();
828 void SdrModel::SetDefaultTabulator(sal_uInt16 nVal)
830 if (m_nDefaultTabulator!=nVal) {
831 m_nDefaultTabulator=nVal;
832 Outliner& rOutliner=GetDrawOutliner();
833 rOutliner.SetDefTab(nVal);
834 Broadcast(SdrHint(SdrHintKind::DefaultTabChange));
835 ImpReformatAllTextObjects();
839 void SdrModel::ImpSetUIUnit()
841 if(0 == m_aUIScale.GetNumerator() || 0 == m_aUIScale.GetDenominator())
843 m_aUIScale = Fraction(1,1);
846 m_nUIUnitDecimalMark = 0;
848 o3tl::Length eFrom = MapToO3tlLength(m_eObjUnit, o3tl::Length::invalid);
849 o3tl::Length eTo;
851 switch (m_eUIUnit)
853 case FieldUnit::CHAR:
854 case FieldUnit::LINE:
855 eTo = o3tl::Length::invalid;
856 break;
857 case FieldUnit::PERCENT:
858 m_nUIUnitDecimalMark += 2;
859 [[fallthrough]];
860 default:
861 eTo = FieldToO3tlLength(m_eUIUnit, o3tl::Length::invalid);
862 } // switch
864 sal_Int32 nMul = 1, nDiv = 1;
865 if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
867 const auto& [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
868 nMul = mul;
869 nDiv = div;
871 // #i89872# take Unit of Measurement into account
872 if(1 != m_aUIScale.GetDenominator() || 1 != m_aUIScale.GetNumerator())
874 // divide by UIScale
875 nMul *= m_aUIScale.GetDenominator();
876 nDiv *= m_aUIScale.GetNumerator();
879 // shorten trailing zeros for dividend
880 while(0 == (nMul % 10))
882 m_nUIUnitDecimalMark--;
883 nMul /= 10;
886 // shorten trailing zeros for divisor
887 while(0 == (nDiv % 10))
889 m_nUIUnitDecimalMark++;
890 nDiv /= 10;
893 // end preparations, set member values
894 m_aUIUnitFact = Fraction(sal_Int32(nMul), sal_Int32(nDiv));
895 m_aUIUnitStr = GetUnitString(m_eUIUnit);
898 void SdrModel::SetScaleUnit(MapUnit eMap)
900 if (m_eObjUnit!=eMap) {
901 m_eObjUnit=eMap;
902 m_pItemPool->SetDefaultMetric(m_eObjUnit);
903 ImpSetUIUnit();
904 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
905 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
906 ImpReformatAllTextObjects();
910 void SdrModel::SetUIUnit(FieldUnit eUnit)
912 if (m_eUIUnit!=eUnit) {
913 m_eUIUnit=eUnit;
914 ImpSetUIUnit();
915 ImpReformatAllTextObjects();
919 void SdrModel::SetUIScale(const Fraction& rScale)
921 if (m_aUIScale!=rScale) {
922 m_aUIScale=rScale;
923 ImpSetUIUnit();
924 ImpReformatAllTextObjects();
928 void SdrModel::SetUIUnit(FieldUnit eUnit, const Fraction& rScale)
930 if (m_eUIUnit!=eUnit || m_aUIScale!=rScale) {
931 m_eUIUnit=eUnit;
932 m_aUIScale=rScale;
933 ImpSetUIUnit();
934 ImpReformatAllTextObjects();
938 OUString SdrModel::GetUnitString(FieldUnit eUnit)
940 switch(eUnit)
942 default:
943 case FieldUnit::NONE :
944 case FieldUnit::CUSTOM :
945 return OUString();
946 case FieldUnit::MM_100TH:
947 return OUString{"/100mm"};
948 case FieldUnit::MM :
949 return OUString{"mm"};
950 case FieldUnit::CM :
951 return OUString{"cm"};
952 case FieldUnit::M :
953 return OUString{"m"};
954 case FieldUnit::KM :
955 return OUString{"km"};
956 case FieldUnit::TWIP :
957 return OUString{"twip"};
958 case FieldUnit::POINT :
959 return OUString{"pt"};
960 case FieldUnit::PICA :
961 return OUString{"pica"};
962 case FieldUnit::INCH :
963 return OUString{"\""};
964 case FieldUnit::FOOT :
965 return OUString{"ft"};
966 case FieldUnit::MILE :
967 return OUString{"mile(s)"};
968 case FieldUnit::PERCENT:
969 return OUString{"%"};
973 OUString SdrModel::GetMetricString(tools::Long nVal, bool bNoUnitChars, sal_Int32 nNumDigits) const
975 // #i22167#
976 // change to double precision usage to not lose decimal places
977 const bool bNegative(nVal < 0);
978 SvtSysLocale aSysLoc;
979 const LocaleDataWrapper& rLoc(aSysLoc.GetLocaleData());
980 double fLocalValue(double(nVal) * double(m_aUIUnitFact));
982 if(bNegative)
984 fLocalValue = -fLocalValue;
987 if( -1 == nNumDigits )
989 nNumDigits = LocaleDataWrapper::getNumDigits();
992 sal_Int32 nDecimalMark(m_nUIUnitDecimalMark);
994 if(nDecimalMark > nNumDigits)
996 const sal_Int32 nDiff(nDecimalMark - nNumDigits);
997 const double fFactor(pow(10.0, static_cast<int>(nDiff)));
999 fLocalValue /= fFactor;
1000 nDecimalMark = nNumDigits;
1002 else if(nDecimalMark < nNumDigits)
1004 const sal_Int32 nDiff(nNumDigits - nDecimalMark);
1005 const double fFactor(pow(10.0, static_cast<int>(nDiff)));
1007 fLocalValue *= fFactor;
1008 nDecimalMark = nNumDigits;
1011 OUStringBuffer aBuf = OUString::number(static_cast<sal_Int32>(fLocalValue + 0.5));
1013 if(nDecimalMark < 0)
1015 // negative nDecimalMark (decimal point) means: add zeros
1016 sal_Int32 nCount(-nDecimalMark);
1018 for(sal_Int32 i=0; i<nCount; i++)
1019 aBuf.append('0');
1021 nDecimalMark = 0;
1024 // the second condition needs to be <= since inside this loop
1025 // also the leading zero is inserted.
1026 if (nDecimalMark > 0 && aBuf.getLength() <= nDecimalMark)
1028 // if necessary, add zeros before the decimal point
1029 sal_Int32 nCount = nDecimalMark - aBuf.getLength();
1031 if(nCount >= 0 && LocaleDataWrapper::isNumLeadingZero())
1032 nCount++;
1034 for(sal_Int32 i=0; i<nCount; i++)
1035 aBuf.insert(0, '0');
1038 const sal_Unicode cDec( rLoc.getNumDecimalSep()[0] );
1040 // insert the decimal mark character
1041 sal_Int32 nBeforeDecimalMark = aBuf.getLength() - nDecimalMark;
1043 if(nDecimalMark > 0)
1044 aBuf.insert(nBeforeDecimalMark, cDec);
1046 if(!LocaleDataWrapper::isNumTrailingZeros())
1048 sal_Int32 aPos=aBuf.getLength()-1;
1050 // Remove all trailing zeros.
1051 while (aPos>=0 && aBuf[aPos]=='0')
1052 --aPos;
1054 // Remove decimal if it's the last character.
1055 if (aPos>=0 && aBuf[aPos]==cDec)
1056 --aPos;
1058 // Adjust aPos to index first char to be truncated, if any
1059 if (++aPos<aBuf.getLength())
1060 aBuf.truncate(aPos);
1063 // if necessary, add separators before every third digit
1064 if( nBeforeDecimalMark > 3 )
1066 const OUString& aThoSep( rLoc.getNumThousandSep() );
1067 if ( !aThoSep.isEmpty() )
1069 sal_Unicode cTho( aThoSep[0] );
1070 sal_Int32 i(nBeforeDecimalMark - 3);
1072 while(i > 0)
1074 aBuf.insert(i, cTho);
1075 i -= 3;
1080 if (aBuf.isEmpty())
1081 aBuf.append("0");
1083 if(bNegative)
1085 aBuf.insert(0, "-");
1088 if(!bNoUnitChars)
1089 aBuf.append(m_aUIUnitStr);
1091 return aBuf.makeStringAndClear();
1094 OUString SdrModel::GetAngleString(Degree100 nAngle)
1096 bool bNeg = nAngle < 0_deg100;
1098 if(bNeg)
1099 nAngle = -nAngle;
1101 OUStringBuffer aBuf;
1102 aBuf.append(static_cast<sal_Int32>(nAngle));
1104 SvtSysLocale aSysLoc;
1105 const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
1106 sal_Int32 nCount = 2;
1108 if(LocaleDataWrapper::isNumLeadingZero())
1109 nCount++;
1111 while(aBuf.getLength() < nCount)
1112 aBuf.insert(0, '0');
1114 aBuf.insert(aBuf.getLength()-2, rLoc.getNumDecimalSep()[0]);
1116 if(bNeg)
1117 aBuf.insert(0, '-');
1119 aBuf.append(DEGREE_CHAR);
1121 return aBuf.makeStringAndClear();
1124 OUString SdrModel::GetPercentString(const Fraction& rVal)
1126 sal_Int32 nMul(rVal.GetNumerator());
1127 sal_Int32 nDiv(rVal.GetDenominator());
1128 bool bNeg {false};
1130 if (nDiv < 0)
1132 bNeg = !bNeg;
1133 nDiv = -nDiv;
1136 if (nMul < 0)
1138 bNeg = !bNeg;
1139 nMul = -nMul;
1142 sal_Int32 nPct = ((nMul*100) + nDiv/2)/nDiv;
1144 if (bNeg)
1145 nPct = -nPct;
1147 return OUString::number(nPct) + "%";
1150 void SdrModel::SetChanged(bool bFlg)
1152 mbChanged = bFlg;
1155 void SdrModel::RecalcPageNums(bool bMaster)
1157 if(bMaster)
1159 sal_uInt16 nCount=sal_uInt16(maMasterPages.size());
1160 sal_uInt16 i;
1161 for (i=0; i<nCount; i++) {
1162 SdrPage* pPg = maMasterPages[i].get();
1163 pPg->SetPageNum(i);
1165 m_bMPgNumsDirty=false;
1167 else
1169 sal_uInt16 nCount=sal_uInt16(maPages.size());
1170 sal_uInt16 i;
1171 for (i=0; i<nCount; i++) {
1172 SdrPage* pPg = maPages[i].get();
1173 pPg->SetPageNum(i);
1175 m_bPagNumsDirty=false;
1179 void SdrModel::InsertPage(SdrPage* pPage, sal_uInt16 nPos)
1181 sal_uInt16 nCount = GetPageCount();
1182 if (nPos > nCount)
1183 nPos = nCount;
1185 maPages.insert(maPages.begin() + nPos, pPage);
1186 PageListChanged();
1187 pPage->SetInserted();
1188 pPage->SetPageNum(nPos);
1190 if (mbMakePageObjectsNamesUnique)
1191 pPage->MakePageObjectsNamesUnique();
1193 if (nPos<nCount) m_bPagNumsDirty=true;
1194 SetChanged();
1195 SdrHint aHint(SdrHintKind::PageOrderChange, pPage);
1196 Broadcast(aHint);
1199 void SdrModel::DeletePage(sal_uInt16 nPgNum)
1201 RemovePage(nPgNum);
1204 rtl::Reference<SdrPage> SdrModel::RemovePage(sal_uInt16 nPgNum)
1206 rtl::Reference<SdrPage> pPg = maPages[nPgNum];
1207 maPages.erase(maPages.begin()+nPgNum);
1208 PageListChanged();
1209 if (pPg) {
1210 pPg->SetInserted(false);
1212 m_bPagNumsDirty=true;
1213 SetChanged();
1214 SdrHint aHint(SdrHintKind::PageOrderChange, pPg.get());
1215 Broadcast(aHint);
1216 return pPg;
1219 void SdrModel::MovePage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
1221 rtl::Reference<SdrPage> pPg = std::move(maPages[nPgNum]);
1222 if (pPg) {
1223 maPages.erase(maPages.begin()+nPgNum); // shortcut to avoid two broadcasts
1224 PageListChanged();
1225 pPg->SetInserted(false);
1226 InsertPage(pPg.get(), nNewPos);
1228 else
1229 RemovePage(nPgNum);
1232 void SdrModel::InsertMasterPage(SdrPage* pPage, sal_uInt16 nPos)
1234 sal_uInt16 nCount=GetMasterPageCount();
1235 if (nPos>nCount) nPos=nCount;
1236 maMasterPages.insert(maMasterPages.begin()+nPos,pPage);
1237 MasterPageListChanged();
1238 pPage->SetInserted();
1239 pPage->SetPageNum(nPos);
1241 if (nPos<nCount) {
1242 m_bMPgNumsDirty=true;
1245 SetChanged();
1246 SdrHint aHint(SdrHintKind::PageOrderChange, pPage);
1247 Broadcast(aHint);
1250 void SdrModel::DeleteMasterPage(sal_uInt16 nPgNum)
1252 RemoveMasterPage(nPgNum);
1255 rtl::Reference<SdrPage> SdrModel::RemoveMasterPage(sal_uInt16 nPgNum)
1257 rtl::Reference<SdrPage> pRetPg = std::move(maMasterPages[nPgNum]);
1258 maMasterPages.erase(maMasterPages.begin()+nPgNum);
1259 MasterPageListChanged();
1261 if(pRetPg)
1263 // Now delete the links from the normal drawing pages to the deleted master page.
1264 sal_uInt16 nPageCnt(GetPageCount());
1266 for(sal_uInt16 np(0); np < nPageCnt; np++)
1268 GetPage(np)->TRG_ImpMasterPageRemoved(*pRetPg);
1271 pRetPg->SetInserted(false);
1274 m_bMPgNumsDirty=true;
1275 SetChanged();
1276 SdrHint aHint(SdrHintKind::PageOrderChange, pRetPg.get());
1277 Broadcast(aHint);
1278 return pRetPg;
1281 void SdrModel::MoveMasterPage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
1283 rtl::Reference<SdrPage> pPg = std::move(maMasterPages[nPgNum]);
1284 maMasterPages.erase(maMasterPages.begin()+nPgNum);
1285 MasterPageListChanged();
1286 if (pPg) {
1287 pPg->SetInserted(false);
1288 maMasterPages.insert(maMasterPages.begin()+nNewPos,pPg);
1289 MasterPageListChanged();
1291 m_bMPgNumsDirty=true;
1292 SetChanged();
1293 SdrHint aHint(SdrHintKind::PageOrderChange, pPg.get());
1294 Broadcast(aHint);
1298 void SdrModel::CopyPages(sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum,
1299 sal_uInt16 nDestPos,
1300 bool bUndo, bool bMoveNoCopy)
1302 if( bUndo && !IsUndoEnabled() )
1303 bUndo = false;
1305 if( bUndo )
1306 BegUndo(SvxResId(STR_UndoMergeModel));
1308 sal_uInt16 nPageCnt=GetPageCount();
1309 sal_uInt16 nMaxPage=nPageCnt;
1311 if (nMaxPage!=0)
1312 nMaxPage--;
1313 if (nFirstPageNum>nMaxPage)
1314 nFirstPageNum=nMaxPage;
1315 if (nLastPageNum>nMaxPage)
1316 nLastPageNum =nMaxPage;
1317 bool bReverse=nLastPageNum<nFirstPageNum;
1318 if (nDestPos>nPageCnt)
1319 nDestPos=nPageCnt;
1321 // at first, save the pointers of the affected pages in an array
1322 sal_uInt16 nPageNum=nFirstPageNum;
1323 sal_uInt16 nCopyCnt=((!bReverse)?(nLastPageNum-nFirstPageNum):(nFirstPageNum-nLastPageNum))+1;
1324 std::unique_ptr<SdrPage*[]> pPagePtrs(new SdrPage*[nCopyCnt]);
1325 sal_uInt16 nCopyNum;
1326 for(nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++)
1328 pPagePtrs[nCopyNum]=GetPage(nPageNum);
1329 if (bReverse)
1330 nPageNum--;
1331 else
1332 nPageNum++;
1335 // now copy the pages
1336 sal_uInt16 nDestNum=nDestPos;
1337 for (nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++)
1339 rtl::Reference<SdrPage> pPg = pPagePtrs[nCopyNum];
1340 sal_uInt16 nPageNum2=pPg->GetPageNum();
1341 if (!bMoveNoCopy)
1343 const SdrPage* pPg1=GetPage(nPageNum2);
1345 // Clone to local model
1346 pPg = pPg1->CloneSdrPage(*this);
1348 InsertPage(pPg.get(), nDestNum);
1349 if (bUndo)
1350 AddUndo(GetSdrUndoFactory().CreateUndoCopyPage(*pPg));
1351 nDestNum++;
1353 else
1355 // TODO: Move is untested!
1356 if (nDestNum>nPageNum2)
1357 nDestNum--;
1359 if(bUndo)
1360 AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*GetPage(nPageNum2),nPageNum2,nDestNum));
1362 pPg=RemovePage(nPageNum2);
1363 InsertPage(pPg.get(), nDestNum);
1364 nDestNum++;
1367 if(bReverse)
1368 nPageNum2--;
1369 else
1370 nPageNum2++;
1373 pPagePtrs.reset();
1374 if(bUndo)
1375 EndUndo();
1378 void SdrModel::Merge(SdrModel& rSourceModel,
1379 sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum,
1380 sal_uInt16 nDestPos,
1381 bool bMergeMasterPages, bool bAllMasterPages,
1382 bool bUndo, bool bTreadSourceAsConst)
1384 if (&rSourceModel==this)
1386 CopyPages(nFirstPageNum,nLastPageNum,nDestPos,bUndo,!bTreadSourceAsConst);
1387 return;
1390 if( bUndo && !IsUndoEnabled() )
1391 bUndo = false;
1393 if (bUndo)
1394 BegUndo(SvxResId(STR_UndoMergeModel));
1396 sal_uInt16 nSrcPageCnt=rSourceModel.GetPageCount();
1397 sal_uInt16 nSrcMasterPageCnt=rSourceModel.GetMasterPageCount();
1398 sal_uInt16 nDstMasterPageCnt=GetMasterPageCount();
1399 bool bInsPages=(nFirstPageNum<nSrcPageCnt || nLastPageNum<nSrcPageCnt);
1400 sal_uInt16 nMaxSrcPage=nSrcPageCnt; if (nMaxSrcPage!=0) nMaxSrcPage--;
1401 if (nFirstPageNum>nMaxSrcPage) nFirstPageNum=nMaxSrcPage;
1402 if (nLastPageNum>nMaxSrcPage) nLastPageNum =nMaxSrcPage;
1403 bool bReverse=nLastPageNum<nFirstPageNum;
1405 std::unique_ptr<sal_uInt16[]> pMasterMap;
1406 std::unique_ptr<bool[]> pMasterNeed;
1407 sal_uInt16 nMasterNeed=0;
1408 if (bMergeMasterPages && nSrcMasterPageCnt!=0) {
1409 // determine which MasterPages from rSrcModel we need
1410 pMasterMap.reset(new sal_uInt16[nSrcMasterPageCnt]);
1411 pMasterNeed.reset(new bool[nSrcMasterPageCnt]);
1412 memset(pMasterMap.get(),0xFF,nSrcMasterPageCnt*sizeof(sal_uInt16));
1413 if (bAllMasterPages) {
1414 memset(pMasterNeed.get(), true, nSrcMasterPageCnt * sizeof(bool));
1415 } else {
1416 memset(pMasterNeed.get(), false, nSrcMasterPageCnt * sizeof(bool));
1417 sal_uInt16 nStart= bReverse ? nLastPageNum : nFirstPageNum;
1418 sal_uInt16 nEnd= bReverse ? nFirstPageNum : nLastPageNum;
1419 for (sal_uInt16 i=nStart; i<=nEnd; i++) {
1420 const SdrPage* pPg=rSourceModel.GetPage(i);
1421 if(pPg->TRG_HasMasterPage())
1423 SdrPage& rMasterPage = pPg->TRG_GetMasterPage();
1424 sal_uInt16 nMPgNum(rMasterPage.GetPageNum());
1426 if(nMPgNum < nSrcMasterPageCnt)
1428 pMasterNeed[nMPgNum] = true;
1433 // now determine the Mapping of the MasterPages
1434 sal_uInt16 nCurrentMaPagNum=nDstMasterPageCnt;
1435 for (sal_uInt16 i=0; i<nSrcMasterPageCnt; i++) {
1436 if (pMasterNeed[i]) {
1437 pMasterMap[i]=nCurrentMaPagNum;
1438 nCurrentMaPagNum++;
1439 nMasterNeed++;
1444 // get the MasterPages
1445 if (pMasterMap && pMasterNeed && nMasterNeed!=0) {
1446 for (sal_uInt16 i=nSrcMasterPageCnt; i>0;) {
1447 i--;
1448 if (pMasterNeed[i])
1450 // Always Clone to new model
1451 const SdrPage* pPg1(rSourceModel.GetMasterPage(i));
1452 rtl::Reference<SdrPage> pPg = pPg1->CloneSdrPage(*this);
1454 if(!bTreadSourceAsConst)
1456 // if requested, delete original/modify original model
1457 rSourceModel.RemoveMasterPage(i);
1460 if (pPg!=nullptr) {
1461 // Now append all of them to the end of the DstModel.
1462 // Don't use InsertMasterPage(), because everything is
1463 // inconsistent until all are in.
1464 maMasterPages.insert(maMasterPages.begin()+nDstMasterPageCnt, pPg);
1465 MasterPageListChanged();
1466 pPg->SetInserted();
1467 m_bMPgNumsDirty=true;
1468 if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg));
1469 } else {
1470 OSL_FAIL("SdrModel::Merge(): MasterPage not found in SourceModel.");
1476 // get the drawing pages
1477 if (bInsPages) {
1478 sal_uInt16 nSourcePos=nFirstPageNum;
1479 sal_uInt16 nMergeCount=sal_uInt16(std::abs(static_cast<tools::Long>(static_cast<tools::Long>(nFirstPageNum)-nLastPageNum))+1);
1480 if (nDestPos>GetPageCount()) nDestPos=GetPageCount();
1481 while (nMergeCount>0)
1483 // Always Clone to new model
1484 const SdrPage* pPg1(rSourceModel.GetPage(nSourcePos));
1485 rtl::Reference<SdrPage> pPg = pPg1->CloneSdrPage(*this);
1487 if(!bTreadSourceAsConst)
1489 // if requested, delete original/modify original model
1490 rSourceModel.RemovePage(nSourcePos);
1493 if (pPg!=nullptr) {
1494 InsertPage(pPg.get(),nDestPos);
1495 if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg));
1497 if(pPg->TRG_HasMasterPage())
1499 SdrPage& rMasterPage = pPg->TRG_GetMasterPage();
1500 sal_uInt16 nMaPgNum(rMasterPage.GetPageNum());
1502 if (bMergeMasterPages)
1504 sal_uInt16 nNewNum(0xFFFF);
1506 if(pMasterMap)
1508 nNewNum = pMasterMap[nMaPgNum];
1511 if(nNewNum != 0xFFFF)
1513 // tdf#90357 here pPg and the to-be-set new masterpage are parts of the new model
1514 // already, but the currently set masterpage is part of the old model. Remove master
1515 // page from already cloned page to prevent creating wrong undo action that can
1516 // eventually crash the app.
1517 // Do *not* remove it directly after cloning - the old masterpage is still needed
1518 // later to find the new to-be-set masterpage.
1519 pPg->TRG_ClearMasterPage();
1521 if(bUndo)
1523 AddUndo(GetSdrUndoFactory().CreateUndoPageChangeMasterPage(*pPg));
1526 pPg->TRG_SetMasterPage(*GetMasterPage(nNewNum));
1528 DBG_ASSERT(nNewNum!=0xFFFF,"SdrModel::Merge(): Something is crooked with the mapping of the MasterPages.");
1529 } else {
1530 if (nMaPgNum>=nDstMasterPageCnt) {
1531 // This is outside of the original area of the MasterPage of the DstModel.
1532 pPg->TRG_ClearMasterPage();
1537 } else {
1538 OSL_FAIL("SdrModel::Merge(): Drawing page not found in SourceModel.");
1540 nDestPos++;
1541 if (bReverse) nSourcePos--;
1542 else if (bTreadSourceAsConst) nSourcePos++;
1543 nMergeCount--;
1547 pMasterMap.reset();
1548 pMasterNeed.reset();
1550 m_bMPgNumsDirty=true;
1551 m_bPagNumsDirty=true;
1553 SetChanged();
1554 // TODO: Missing: merging and mapping of layers
1555 // at the objects as well as at the MasterPageDescriptors
1556 if (bUndo) EndUndo();
1559 void SdrModel::SetStarDrawPreviewMode(bool bPreview)
1561 if (!bPreview && m_bStarDrawPreviewMode && GetPageCount())
1563 // Resetting is not allowed, because the Model might not be loaded completely
1564 SAL_WARN("svx", "SdrModel::SetStarDrawPreviewMode(): Resetting not allowed, because Model might not be complete.");
1566 else
1568 m_bStarDrawPreviewMode = bPreview;
1572 void SdrModel::setTheme(std::shared_ptr<model::Theme> const& pTheme)
1574 mpImpl->mpTheme = pTheme;
1577 std::shared_ptr<model::Theme> const& SdrModel::getTheme() const
1579 return mpImpl->mpTheme;
1582 uno::Reference< frame::XModel > const & SdrModel::getUnoModel()
1584 if( !mxUnoModel.is() )
1585 mxUnoModel = createUnoModel();
1587 return mxUnoModel;
1590 void SdrModel::setUnoModel(const uno::Reference<frame::XModel>& xModel)
1592 mxUnoModel = xModel;
1595 void SdrModel::adaptSizeAndBorderForAllPages(
1596 const Size& /*rNewSize*/,
1597 tools::Long /*nLeft*/,
1598 tools::Long /*nRight*/,
1599 tools::Long /*nUpper*/,
1600 tools::Long /*nLower*/)
1602 // base implementation does currently nothing. It may be added if needed,
1603 // but we are on SdrModel level here, thus probably have not enough information
1604 // to do this for higher-level (derived) Models (e.g. Draw/Impress)
1607 uno::Reference< frame::XModel > SdrModel::createUnoModel()
1609 OSL_FAIL( "SdrModel::createUnoModel() - base implementation should not be called!" );
1610 return nullptr;
1613 void SdrModel::setLock( bool bLock )
1615 if( mbModelLocked != bLock )
1617 // #i120437# need to set first, else ImpReformatAllEdgeObjects will do nothing
1618 mbModelLocked = bLock;
1620 if( !bLock )
1622 ImpReformatAllEdgeObjects();
1628 void SdrModel::MigrateItemSet( const SfxItemSet* pSourceSet, SfxItemSet* pDestSet, SdrModel* pNewModelel )
1630 assert(pNewModelel != nullptr);
1631 if( !(pSourceSet && pDestSet && (pSourceSet != pDestSet )) )
1632 return;
1634 SfxWhichIter aWhichIter(*pSourceSet);
1635 sal_uInt16 nWhich(aWhichIter.FirstWhich());
1636 const SfxPoolItem *pPoolItem;
1638 while(nWhich)
1640 if(SfxItemState::SET == aWhichIter.GetItemState(false, &pPoolItem))
1642 std::unique_ptr<SfxPoolItem> pResultItem;
1644 switch( nWhich )
1646 case XATTR_FILLBITMAP:
1647 pResultItem = static_cast<const XFillBitmapItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1648 break;
1649 case XATTR_LINEDASH:
1650 pResultItem = static_cast<const XLineDashItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1651 break;
1652 case XATTR_LINESTART:
1653 pResultItem = static_cast<const XLineStartItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1654 break;
1655 case XATTR_LINEEND:
1656 pResultItem = static_cast<const XLineEndItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1657 break;
1658 case XATTR_FILLGRADIENT:
1659 pResultItem = static_cast<const XFillGradientItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1660 break;
1661 case XATTR_FILLFLOATTRANSPARENCE:
1662 // allow all kinds of XFillFloatTransparenceItem to be set
1663 pResultItem = static_cast<const XFillFloatTransparenceItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1664 break;
1665 case XATTR_FILLHATCH:
1666 pResultItem = static_cast<const XFillHatchItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
1667 break;
1670 // set item
1671 if( pResultItem )
1672 pDestSet->Put(std::move(pResultItem));
1673 else
1674 pDestSet->Put(*pPoolItem);
1676 nWhich = aWhichIter.NextWhich();
1681 void SdrModel::SetForbiddenCharsTable(const std::shared_ptr<SvxForbiddenCharactersTable>& xForbiddenChars)
1683 mpForbiddenCharactersTable = xForbiddenChars;
1685 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1686 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1690 void SdrModel::SetCharCompressType( CharCompressType nType )
1692 if( nType != mnCharCompressType )
1694 mnCharCompressType = nType;
1695 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1696 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1700 void SdrModel::SetKernAsianPunctuation( bool bEnabled )
1702 if( mbKernAsianPunctuation != bEnabled )
1704 mbKernAsianPunctuation = bEnabled;
1705 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1706 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1710 void SdrModel::SetAddExtLeading( bool bEnabled )
1712 if( mbAddExtLeading != bEnabled )
1714 mbAddExtLeading = bEnabled;
1715 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1716 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1720 void SdrModel::SetCompatibilityFlag(SdrCompatibilityFlag eFlag, bool bEnabled)
1722 switch (eFlag)
1724 case SdrCompatibilityFlag::AnchoredTextOverflowLegacy:
1725 mpImpl->mbAnchoredTextOverflowLegacy = bEnabled;
1726 break;
1727 case SdrCompatibilityFlag::LegacyFontwork:
1728 mpImpl->mbLegacyFontwork = bEnabled;
1729 break;
1730 case SdrCompatibilityFlag::ConnectorUseSnapRect:
1731 mpImpl->mbConnectorUseSnapRect = bEnabled;
1732 break;
1733 case SdrCompatibilityFlag::IgnoreBreakAfterMultilineField:
1734 mpImpl->mbIgnoreBreakAfterMultilineField = bEnabled;
1735 break;
1739 bool SdrModel::GetCompatibilityFlag(SdrCompatibilityFlag eFlag) const
1741 switch (eFlag)
1743 case SdrCompatibilityFlag::AnchoredTextOverflowLegacy:
1744 return mpImpl->mbAnchoredTextOverflowLegacy;
1745 case SdrCompatibilityFlag::LegacyFontwork:
1746 return mpImpl->mbLegacyFontwork;
1747 case SdrCompatibilityFlag::ConnectorUseSnapRect:
1748 return mpImpl->mbConnectorUseSnapRect;
1749 case SdrCompatibilityFlag::IgnoreBreakAfterMultilineField:
1750 return mpImpl->mbIgnoreBreakAfterMultilineField;
1751 default:
1752 return false;
1756 void SdrModel::ReformatAllTextObjects()
1758 ImpReformatAllTextObjects();
1761 std::unique_ptr<SdrOutliner> SdrModel::createOutliner( OutlinerMode nOutlinerMode )
1763 if( !mpOutlinerCache )
1764 mpOutlinerCache.reset(new SdrOutlinerCache(this));
1766 return mpOutlinerCache->createOutliner( nOutlinerMode );
1769 std::vector<SdrOutliner*> SdrModel::GetActiveOutliners() const
1771 std::vector< SdrOutliner* > aRet(mpOutlinerCache ? mpOutlinerCache->GetActiveOutliners() : std::vector< SdrOutliner* >());
1772 aRet.push_back(m_pDrawOutliner.get());
1773 aRet.push_back(m_pHitTestOutliner.get());
1775 return aRet;
1778 void SdrModel::disposeOutliner( std::unique_ptr<SdrOutliner> pOutliner )
1780 if( mpOutlinerCache )
1781 mpOutlinerCache->disposeOutliner( std::move(pOutliner) );
1784 SvxNumType SdrModel::GetPageNumType() const
1786 return SVX_NUM_ARABIC;
1789 void SdrModel::ReadUserDataSequenceValue(const beans::PropertyValue* pValue)
1791 if (pValue->Name == "AnchoredTextOverflowLegacy")
1793 bool bBool = false;
1794 if (pValue->Value >>= bBool)
1796 mpImpl->mbAnchoredTextOverflowLegacy = bBool;
1799 else if (pValue->Name == "ConnectorUseSnapRect")
1801 bool bBool = false;
1802 if (pValue->Value >>= bBool)
1804 mpImpl->mbConnectorUseSnapRect = bBool;
1807 else if (pValue->Name == "LegacySingleLineFontwork")
1809 bool bBool = false;
1810 if ((pValue->Value >>= bBool) && mpImpl->mbLegacyFontwork != bBool)
1812 mpImpl->mbLegacyFontwork = bBool;
1813 // tdf#148000 hack: reset all CustomShape geometry as they may depend on this property
1814 // Ideally this ReadUserDataSequenceValue should be called before geometry creation
1815 // Once the calling order will be fixed, this hack will not be needed.
1816 for (size_t i = 0; i < maPages.size(); ++i)
1818 if (const SdrPage* pPage = maPages[i].get())
1820 SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
1821 while (aIter.IsMore())
1823 SdrObject* pTempObj = aIter.Next();
1824 if (SdrObjCustomShape* pShape = dynamic_cast<SdrObjCustomShape*>(pTempObj))
1826 pShape->InvalidateRenderGeometry();
1833 else if (pValue->Name == "IgnoreBreakAfterMultilineField")
1835 bool bBool = false;
1836 if (pValue->Value >>= bBool)
1838 mpImpl->mbIgnoreBreakAfterMultilineField = bBool;
1843 void SdrModel::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& rValues)
1845 std::vector< std::pair< OUString, uno::Any > > aUserData
1847 { "AnchoredTextOverflowLegacy", uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy)) },
1848 { "LegacySingleLineFontwork", uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork)) },
1849 { "ConnectorUseSnapRect", uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::ConnectorUseSnapRect)) },
1850 { "IgnoreBreakAfterMultilineField", uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::IgnoreBreakAfterMultilineField)) }
1853 const sal_Int32 nOldLength = rValues.getLength();
1854 rValues.realloc(nOldLength + aUserData.size());
1856 beans::PropertyValue* pValue = &(rValues.getArray()[nOldLength]);
1858 for (const auto &aIter : aUserData)
1860 pValue->Name = aIter.first;
1861 pValue->Value = aIter.second;
1862 ++pValue;
1866 const SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum) const
1868 return nPgNum < maPages.size() ? maPages[nPgNum].get() : nullptr;
1871 SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum)
1873 return nPgNum < maPages.size() ? maPages[nPgNum].get() : nullptr;
1876 sal_uInt16 SdrModel::GetPageCount() const
1878 return sal_uInt16(maPages.size());
1881 void SdrModel::PageListChanged()
1885 TextChain *SdrModel::GetTextChain() const
1887 return m_pTextChain.get();
1890 const SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum) const
1892 DBG_ASSERT(nPgNum < maMasterPages.size(), "SdrModel::GetMasterPage: Access out of range (!)");
1893 return maMasterPages[nPgNum].get();
1896 SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum)
1898 DBG_ASSERT(nPgNum < maMasterPages.size(), "SdrModel::GetMasterPage: Access out of range (!)");
1899 return maMasterPages[nPgNum].get();
1902 sal_uInt16 SdrModel::GetMasterPageCount() const
1904 return sal_uInt16(maMasterPages.size());
1907 void SdrModel::MasterPageListChanged()
1911 void SdrModel::SetSdrUndoManager( SfxUndoManager* pUndoManager )
1913 mpImpl->mpUndoManager = pUndoManager;
1916 SfxUndoManager* SdrModel::GetSdrUndoManager() const
1918 return mpImpl->mpUndoManager;
1921 SdrUndoFactory& SdrModel::GetSdrUndoFactory() const
1923 if( !mpImpl->mpUndoFactory )
1924 mpImpl->mpUndoFactory = new SdrUndoFactory;
1925 return *mpImpl->mpUndoFactory;
1928 void SdrModel::SetSdrUndoFactory( SdrUndoFactory* pUndoFactory )
1930 if( pUndoFactory && (pUndoFactory != mpImpl->mpUndoFactory) )
1932 delete mpImpl->mpUndoFactory;
1933 mpImpl->mpUndoFactory = pUndoFactory;
1937 void SdrModel::dumpAsXml(xmlTextWriterPtr pWriter) const
1939 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrModel"));
1940 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1942 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("maMasterPages"));
1943 for (size_t i = 0; i < maMasterPages.size(); ++i)
1945 if (const SdrPage* pPage = maMasterPages[i].get())
1947 pPage->dumpAsXml(pWriter);
1950 (void)xmlTextWriterEndElement(pWriter);
1952 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("maPages"));
1953 for (size_t i = 0; i < maPages.size(); ++i)
1955 if (const SdrPage* pPage = maPages[i].get())
1957 pPage->dumpAsXml(pWriter);
1960 (void)xmlTextWriterEndElement(pWriter);
1962 if (mpImpl->mpTheme)
1964 mpImpl->mpTheme->dumpAsXml(pWriter);
1967 (void)xmlTextWriterEndElement(pWriter);
1970 const uno::Sequence<sal_Int8>& SdrModel::getUnoTunnelId()
1972 static const comphelper::UnoIdInit theSdrModelUnoTunnelImplementationId;
1973 return theSdrModelUnoTunnelImplementationId.getSeq();
1977 SdrHint::SdrHint(SdrHintKind eNewHint)
1978 : SfxHint(SfxHintId::ThisIsAnSdrHint),
1979 meHint(eNewHint),
1980 mpObj(nullptr),
1981 mpPage(nullptr)
1985 SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj)
1986 : SfxHint(SfxHintId::ThisIsAnSdrHint),
1987 meHint(eNewHint),
1988 mpObj(&rNewObj),
1989 mpPage(rNewObj.getSdrPageFromSdrObject())
1993 SdrHint::SdrHint(SdrHintKind eNewHint, const SdrPage* pPage)
1994 : SfxHint(SfxHintId::ThisIsAnSdrHint),
1995 meHint(eNewHint),
1996 mpObj(nullptr),
1997 mpPage(pPage)
2001 SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj, const SdrPage* pPage)
2002 : SfxHint(SfxHintId::ThisIsAnSdrHint),
2003 meHint(eNewHint),
2004 mpObj(&rNewObj),
2005 mpPage(pPage)
2009 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */