tdf#161412 - UI: fix warning in PDF password dialog didn't disappear
[LibreOffice.git] / svx / source / svdraw / svdmodel.cxx
blob5d83be0ebe10b312b033be9202b2a7f5c77a223f
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 <sal/log.hxx>
23 #include <rtl/ustrbuf.hxx>
24 #include <com/sun/star/lang/XComponent.hpp>
25 #include <com/sun/star/document/XStorageBasedDocument.hpp>
26 #include <com/sun/star/embed/ElementModes.hpp>
27 #include <unotools/configmgr.hxx>
28 #include <unotools/pathoptions.hxx>
29 #include <svl/whiter.hxx>
30 #include <svl/asiancfg.hxx>
31 #include <svx/compatflags.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/svdpage.hxx>
42 #include <svx/svdlayer.hxx>
43 #include <svx/svdundo.hxx>
44 #include <svx/svdpool.hxx>
45 #include <svx/svdobj.hxx>
46 #include <svx/svdotext.hxx>
47 #include <svx/unoshape.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(u"Office"_ustr))
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_bTransportContainer(false)
136 , m_bReadOnly(false)
137 , m_bTransparentTextFrames(false)
138 , m_bSwapGraphics(false)
139 , m_bPasteResize(false)
140 , m_bStarDrawPreviewMode(false)
141 , mbDisableTextEditUsesCommonUndoManager(false)
142 , mbVOCInvalidationIsReliable(false)
143 , m_bIsPDFDocument(false)
144 , m_nDefaultTabulator(0)
145 , m_nMaxUndoCount(16)
146 , m_pTextChain(new TextChain)
147 , mpImpl(new SdrModelImpl)
148 , mnCharCompressType(CharCompressType::NONE)
149 , mnHandoutPageCount(0)
150 , mbModelLocked(false)
151 , mbKernAsianPunctuation(false)
152 , mbAddExtLeading(false)
153 , mbInDestruction(false)
155 if (!comphelper::IsFuzzing())
157 mnCharCompressType = static_cast<CharCompressType>(
158 officecfg::Office::Common::AsianLayout::CompressCharacterDistance::get());
161 if (m_pItemPool == nullptr)
163 m_pItemPool = new SdrItemPool(nullptr);
164 // Outliner doesn't have its own Pool, so use the EditEngine's
165 rtl::Reference<SfxItemPool> pOutlPool=EditEngine::CreatePool();
166 // OutlinerPool as SecondaryPool of SdrPool
167 m_pItemPool->SetSecondaryPool(pOutlPool.get());
168 // remember that I created both pools myself
169 m_bIsWriter = false;
171 m_pItemPool->SetDefaultMetric(m_eObjUnit);
173 // using static SdrEngineDefaults only if default SvxFontHeight item is not available
174 const SfxPoolItem* pPoolItem = m_pItemPool->GetUserDefaultItem( EE_CHAR_FONTHEIGHT );
175 if (pPoolItem)
176 mnDefTextHgt = static_cast<const SvxFontHeightItem*>(pPoolItem)->GetHeight();
178 m_pItemPool->SetUserDefaultItem( makeSdrTextWordWrapItem( false ) );
180 SetTextDefaults();
181 m_pLayerAdmin->SetModel(this);
182 ImpSetUIUnit();
184 // can't create DrawOutliner OnDemand, because I can't get the Pool,
185 // then (only from 302 onwards!)
186 m_pDrawOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this);
187 ImpSetOutlinerDefaults(m_pDrawOutliner.get(), true);
189 m_pHitTestOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this);
190 ImpSetOutlinerDefaults(m_pHitTestOutliner.get(), true);
192 /* Start Text Chaining related code */
193 // Initialize Chaining Outliner
194 m_pChainingOutliner = SdrMakeOutliner( OutlinerMode::TextObject, *this );
195 ImpSetOutlinerDefaults(m_pChainingOutliner.get(), true);
197 ImpCreateTables(bDisablePropertyFiles || comphelper::IsFuzzing());
199 mpImpl->initTheme();
202 void SdrModel::implDtorClearModel()
204 mbInDestruction = true;
206 Broadcast(SdrHint(SdrHintKind::ModelCleared));
208 mpOutlinerCache.reset();
210 ClearUndoBuffer();
211 #ifdef DBG_UTIL
212 SAL_WARN_IF(m_pCurrentUndoGroup, "svx", "In the Dtor of the SdrModel there is an open Undo left: \""
213 << m_pCurrentUndoGroup->GetComment() << '\"');
214 #endif
215 m_pCurrentUndoGroup.reset();
217 ClearModel(true);
220 SdrModel::~SdrModel()
222 implDtorClearModel();
224 #ifdef DBG_UTIL
225 if(!maAllIncarnatedObjects.empty())
227 SAL_WARN("svx",
228 "SdrModel::~SdrModel: Not all incarnations of SdrObjects deleted, possible memory leak");
229 for (const auto & pObj : maAllIncarnatedObjects)
230 SAL_WARN("svx", "leaked instance of " << typeid(*pObj).name());
232 #endif
234 m_pLayerAdmin.reset();
236 m_pTextChain.reset();
237 // Delete DrawOutliner only after deleting ItemPool, because ItemPool
238 // references Items of the DrawOutliner!
239 m_pChainingOutliner.reset();
240 m_pHitTestOutliner.reset();
241 m_pDrawOutliner.reset();
243 // delete StyleSheetPool, derived classes should not do this since
244 // the DrawingEngine may need it in its destructor
245 if( mxStyleSheetPool.is() )
247 uno::Reference<lang::XComponent> xComponent( getXWeak( mxStyleSheetPool.get() ), uno::UNO_QUERY );
248 if( xComponent.is() ) try
250 xComponent->dispose();
252 catch (uno::RuntimeException&)
255 mxStyleSheetPool.clear();
258 mpForbiddenCharactersTable.reset();
260 delete mpImpl->mpUndoFactory;
263 void SdrModel::SetSwapGraphics()
265 m_bSwapGraphics = true;
268 bool SdrModel::IsReadOnly() const
270 return m_bReadOnly;
273 void SdrModel::SetReadOnly(bool bYes)
275 m_bReadOnly=bYes;
279 void SdrModel::SetMaxUndoActionCount(sal_uInt32 nCount)
281 if (nCount<1) nCount=1;
282 m_nMaxUndoCount=nCount;
283 while (m_aUndoStack.size()>m_nMaxUndoCount)
284 m_aUndoStack.pop_back();
287 void SdrModel::ClearUndoBuffer()
289 m_aUndoStack.clear();
290 m_aRedoStack.clear();
293 bool SdrModel::HasUndoActions() const
295 return !m_aUndoStack.empty();
298 bool SdrModel::HasRedoActions() const
300 return !m_aRedoStack.empty();
303 void SdrModel::Undo()
305 if( mpImpl->mpUndoManager )
307 OSL_FAIL("svx::SdrModel::Undo(), method not supported with application undo manager!");
309 else
311 if(HasUndoActions())
313 SfxUndoAction* pDo = m_aUndoStack.front().get();
314 const bool bWasUndoEnabled = mbUndoEnabled;
315 mbUndoEnabled = false;
316 pDo->Undo();
317 std::unique_ptr<SfxUndoAction> p = std::move(m_aUndoStack.front());
318 m_aUndoStack.pop_front();
319 m_aRedoStack.emplace_front(std::move(p));
320 mbUndoEnabled = bWasUndoEnabled;
325 void SdrModel::Redo()
327 if( mpImpl->mpUndoManager )
329 OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!");
331 else
333 if(HasRedoActions())
335 SfxUndoAction* pDo = m_aRedoStack.front().get();
336 const bool bWasUndoEnabled = mbUndoEnabled;
337 mbUndoEnabled = false;
338 pDo->Redo();
339 std::unique_ptr<SfxUndoAction> p = std::move(m_aRedoStack.front());
340 m_aRedoStack.pop_front();
341 m_aUndoStack.emplace_front(std::move(p));
342 mbUndoEnabled = bWasUndoEnabled;
347 void SdrModel::Repeat(SfxRepeatTarget& rView)
349 if( mpImpl->mpUndoManager )
351 OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!");
353 else
355 if(HasUndoActions())
357 SfxUndoAction* pDo = m_aUndoStack.front().get();
358 if(pDo->CanRepeat(rView))
360 pDo->Repeat(rView);
366 void SdrModel::ImpPostUndoAction(std::unique_ptr<SdrUndoAction> pUndo)
368 DBG_ASSERT( mpImpl->mpUndoManager == nullptr, "svx::SdrModel::ImpPostUndoAction(), method not supported with application undo manager!" );
369 if( !IsUndoEnabled() )
370 return;
372 if (m_aUndoLink)
374 m_aUndoLink(std::move(pUndo));
376 else
378 m_aUndoStack.emplace_front(std::move(pUndo));
379 while (m_aUndoStack.size()>m_nMaxUndoCount)
381 m_aUndoStack.pop_back();
383 m_aRedoStack.clear();
387 void SdrModel::BegUndo()
389 if( mpImpl->mpUndoManager )
391 ViewShellId nViewShellId(-1);
392 if (SfxViewShell* pViewShell = SfxViewShell::Current())
393 nViewShellId = pViewShell->GetViewShellId();
394 mpImpl->mpUndoManager->EnterListAction(u""_ustr,u""_ustr,0,nViewShellId);
395 m_nUndoLevel++;
397 else if( IsUndoEnabled() )
399 if(!m_pCurrentUndoGroup)
401 m_pCurrentUndoGroup.reset(new SdrUndoGroup(*this));
402 m_nUndoLevel=1;
404 else
406 m_nUndoLevel++;
411 void SdrModel::BegUndo(const OUString& rComment)
413 if( mpImpl->mpUndoManager )
415 ViewShellId nViewShellId(-1);
416 if (SfxViewShell* pViewShell = SfxViewShell::Current())
417 nViewShellId = pViewShell->GetViewShellId();
418 mpImpl->mpUndoManager->EnterListAction( rComment, u""_ustr, 0, nViewShellId );
419 m_nUndoLevel++;
421 else if( IsUndoEnabled() )
423 BegUndo();
424 if (m_nUndoLevel==1)
426 m_pCurrentUndoGroup->SetComment(rComment);
431 void SdrModel::BegUndo(const OUString& rComment, const OUString& rObjDescr, SdrRepeatFunc eFunc)
433 if( mpImpl->mpUndoManager )
435 OUString aComment(rComment);
436 if( !aComment.isEmpty() && !rObjDescr.isEmpty() )
438 aComment = aComment.replaceFirst("%1", rObjDescr);
440 ViewShellId nViewShellId(-1);
441 if (SfxViewShell* pViewShell = SfxViewShell::Current())
442 nViewShellId = pViewShell->GetViewShellId();
443 mpImpl->mpUndoManager->EnterListAction( aComment,u""_ustr,0,nViewShellId );
444 m_nUndoLevel++;
446 else if( IsUndoEnabled() )
448 BegUndo();
449 if (m_nUndoLevel==1)
451 m_pCurrentUndoGroup->SetComment(rComment);
452 m_pCurrentUndoGroup->SetObjDescription(rObjDescr);
453 m_pCurrentUndoGroup->SetRepeatFunction(eFunc);
458 void SdrModel::EndUndo()
460 DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::EndUndo(): UndoLevel is already 0!");
461 if( mpImpl->mpUndoManager )
463 if( m_nUndoLevel )
465 m_nUndoLevel--;
466 mpImpl->mpUndoManager->LeaveListAction();
469 else
471 if(m_pCurrentUndoGroup!=nullptr && IsUndoEnabled())
473 m_nUndoLevel--;
474 if(m_nUndoLevel==0)
476 if(m_pCurrentUndoGroup->GetActionCount()!=0)
478 ImpPostUndoAction(std::move(m_pCurrentUndoGroup));
480 else
482 // was empty
483 m_pCurrentUndoGroup.reset();
490 void SdrModel::SetUndoComment(const OUString& rComment)
492 DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!");
494 if( mpImpl->mpUndoManager )
496 OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" );
498 else if( IsUndoEnabled() && m_nUndoLevel==1)
500 m_pCurrentUndoGroup->SetComment(rComment);
504 void SdrModel::SetUndoComment(const OUString& rComment, const OUString& rObjDescr)
506 DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!");
507 if( mpImpl->mpUndoManager )
509 OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" );
511 else
513 if (m_nUndoLevel==1)
515 m_pCurrentUndoGroup->SetComment(rComment);
516 m_pCurrentUndoGroup->SetObjDescription(rObjDescr);
521 void SdrModel::AddUndo(std::unique_ptr<SdrUndoAction> pUndo)
523 if( mpImpl->mpUndoManager )
525 mpImpl->mpUndoManager->AddUndoAction( std::move(pUndo) );
527 else if( IsUndoEnabled() )
529 if (m_pCurrentUndoGroup)
531 m_pCurrentUndoGroup->AddAction(std::move(pUndo));
533 else
535 ImpPostUndoAction(std::move(pUndo));
540 void SdrModel::EnableUndo( bool bEnable )
542 if( mpImpl->mpUndoManager )
544 mpImpl->mpUndoManager->EnableUndo( bEnable );
546 else
548 mbUndoEnabled = bEnable;
552 bool SdrModel::IsUndoEnabled() const
554 if( mpImpl->mpUndoManager )
556 return mpImpl->mpUndoManager->IsUndoEnabled();
558 else
560 return mbUndoEnabled;
564 void SdrModel::ImpCreateTables(bool bDisablePropertyFiles)
566 // use standard path for initial construction
567 const OUString aTablePath(!bDisablePropertyFiles ? SvtPathOptions().GetPalettePath() : u""_ustr);
569 for( auto i : o3tl::enumrange<XPropertyListType>() )
571 maProperties[i] = XPropertyList::CreatePropertyList(i, aTablePath, u""_ustr/*TODO?*/ );
575 void SdrModel::ClearModel(bool bCalledFromDestructor)
577 if(bCalledFromDestructor)
579 mbInDestruction = true;
582 // Disconnect all SvxShape's from their SdrObjects to prevent the SdrObjects
583 // from hanging around and causing use-after-free.
584 // Make a copy because it might modified during InvalidateSdrObject calls.
585 std::vector<rtl::Reference<SdrObject>> allObjs(maAllIncarnatedObjects.begin(), maAllIncarnatedObjects.end());
586 for (const auto & pSdrObj : allObjs)
588 uno::Reference<uno::XInterface> xShape = pSdrObj->getWeakUnoShape().get();
589 rtl::Reference<SvxShape> pSvxShape = dynamic_cast<SvxShape*>(xShape.get());
590 // calling getWeakUnoShape so we don't accidentally create new UNO shapes
591 if (pSvxShape)
592 pSvxShape->InvalidateSdrObject();
593 else
595 // because some things like SwXShape don't subclass SvxShape
596 uno::Reference<lang::XComponent> xComp(xShape, uno::UNO_QUERY);
597 if (xComp)
598 xComp->dispose();
601 sal_Int32 i;
602 // delete all drawing pages
603 sal_Int32 nCount=GetPageCount();
604 for (i=nCount-1; i>=0; i--)
606 DeletePage( static_cast<sal_uInt16>(i) );
608 maPages.clear();
609 PageListChanged();
611 // delete all Masterpages
612 nCount=GetMasterPageCount();
613 for(i=nCount-1; i>=0; i--)
615 DeleteMasterPage( static_cast<sal_uInt16>(i) );
617 maMasterPages.clear();
618 MasterPageListChanged();
620 m_pLayerAdmin->ClearLayers();
623 SdrModel* SdrModel::AllocModel() const
625 SdrModel* pModel=new SdrModel();
626 pModel->SetScaleUnit(m_eObjUnit);
627 return pModel;
630 rtl::Reference<SdrPage> SdrModel::AllocPage(bool bMasterPage)
632 return new SdrPage(*this,bMasterPage);
635 void SdrModel::SetTextDefaults() const
637 SetTextDefaults( m_pItemPool.get(), mnDefTextHgt );
640 void SdrModel::SetTextDefaults( SfxItemPool* pItemPool, sal_Int32 nDefTextHgt )
642 // set application-language specific dynamic pool language defaults
643 SvxFontItem aSvxFontItem( EE_CHAR_FONTINFO) ;
644 SvxFontItem aSvxFontItemCJK(EE_CHAR_FONTINFO_CJK);
645 SvxFontItem aSvxFontItemCTL(EE_CHAR_FONTINFO_CTL);
646 LanguageType nLanguage;
647 if (!comphelper::IsFuzzing())
648 nLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
649 else
650 nLanguage = LANGUAGE_ENGLISH_US;
652 // get DEFAULTFONT_LATIN_TEXT and set at pool as dynamic default
653 vcl::Font aFont(OutputDevice::GetDefaultFont(DefaultFontType::LATIN_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
654 aSvxFontItem.SetFamily(aFont.GetFamilyType());
655 aSvxFontItem.SetFamilyName(aFont.GetFamilyName());
656 aSvxFontItem.SetStyleName(OUString());
657 aSvxFontItem.SetPitch( aFont.GetPitch());
658 aSvxFontItem.SetCharSet( aFont.GetCharSet() );
659 pItemPool->SetUserDefaultItem(aSvxFontItem);
661 // get DEFAULTFONT_CJK_TEXT and set at pool as dynamic default
662 vcl::Font aFontCJK(OutputDevice::GetDefaultFont(DefaultFontType::CJK_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
663 aSvxFontItemCJK.SetFamily( aFontCJK.GetFamilyType());
664 aSvxFontItemCJK.SetFamilyName(aFontCJK.GetFamilyName());
665 aSvxFontItemCJK.SetStyleName(OUString());
666 aSvxFontItemCJK.SetPitch( aFontCJK.GetPitch());
667 aSvxFontItemCJK.SetCharSet( aFontCJK.GetCharSet());
668 pItemPool->SetUserDefaultItem(aSvxFontItemCJK);
670 // get DEFAULTFONT_CTL_TEXT and set at pool as dynamic default
671 vcl::Font aFontCTL(OutputDevice::GetDefaultFont(DefaultFontType::CTL_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
672 aSvxFontItemCTL.SetFamily(aFontCTL.GetFamilyType());
673 aSvxFontItemCTL.SetFamilyName(aFontCTL.GetFamilyName());
674 aSvxFontItemCTL.SetStyleName(OUString());
675 aSvxFontItemCTL.SetPitch( aFontCTL.GetPitch() );
676 aSvxFontItemCTL.SetCharSet( aFontCTL.GetCharSet());
677 pItemPool->SetUserDefaultItem(aSvxFontItemCTL);
679 // set dynamic FontHeight defaults
680 pItemPool->SetUserDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT ) );
681 pItemPool->SetUserDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CJK ) );
682 pItemPool->SetUserDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CTL ) );
684 // set FontColor defaults
685 pItemPool->SetUserDefaultItem( SvxColorItem(SdrEngineDefaults::GetFontColor(), EE_CHAR_COLOR) );
688 SdrOutliner& SdrModel::GetDrawOutliner(const SdrTextObj* pObj) const
690 m_pDrawOutliner->SetTextObj(pObj);
691 return *m_pDrawOutliner;
694 SdrOutliner& SdrModel::GetChainingOutliner(const SdrTextObj* pObj) const
696 m_pChainingOutliner->SetTextObj(pObj);
697 return *m_pChainingOutliner;
700 const SdrTextObj* SdrModel::GetFormattingTextObj() const
702 if (m_pDrawOutliner!=nullptr) {
703 return m_pDrawOutliner->GetTextObj();
705 return nullptr;
708 void SdrModel::ImpSetOutlinerDefaults( SdrOutliner* pOutliner, bool bInit )
710 // Initialization of the Outliners for drawing text and HitTest
711 if( bInit )
713 pOutliner->EraseVirtualDevice();
714 pOutliner->SetUpdateLayout(false);
715 pOutliner->SetEditTextObjectPool(m_pItemPool.get());
716 pOutliner->SetDefTab(m_nDefaultTabulator);
719 pOutliner->SetRefDevice(GetRefDevice());
720 Outliner::SetForbiddenCharsTable(GetForbiddenCharsTable());
721 pOutliner->SetAsianCompressionMode( mnCharCompressType );
722 pOutliner->SetKernAsianPunctuation( IsKernAsianPunctuation() );
723 pOutliner->SetAddExtLeading( IsAddExtLeading() );
725 if ( !GetRefDevice() )
727 MapMode aMapMode(m_eObjUnit);
728 pOutliner->SetRefMapMode(aMapMode);
732 void SdrModel::SetRefDevice(OutputDevice* pDev)
734 m_pRefOutDev=pDev;
735 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
736 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
737 RefDeviceChanged();
740 void SdrModel::ImpReformatAllTextObjects()
742 if( isLocked() )
743 return;
745 sal_uInt16 nCount=GetMasterPageCount();
746 sal_uInt16 nNum;
747 for (nNum=0; nNum<nCount; nNum++) {
748 GetMasterPage(nNum)->ReformatAllTextObjects();
750 nCount=GetPageCount();
751 for (nNum=0; nNum<nCount; nNum++) {
752 GetPage(nNum)->ReformatAllTextObjects();
756 /* steps over all available pages and sends notify messages to
757 all edge objects that are connected to other objects so that
758 they may reposition themselves
760 void SdrModel::ImpReformatAllEdgeObjects()
762 if( isLocked() )
763 return;
765 sal_uInt16 nCount=GetMasterPageCount();
766 sal_uInt16 nNum;
767 for (nNum=0; nNum<nCount; nNum++)
769 GetMasterPage(nNum)->ReformatAllEdgeObjects();
771 nCount=GetPageCount();
772 for (nNum=0; nNum<nCount; nNum++)
774 GetPage(nNum)->ReformatAllEdgeObjects();
778 uno::Reference<embed::XStorage> SdrModel::GetDocumentStorage() const
780 uno::Reference<document::XStorageBasedDocument> const xSBD(
781 const_cast<SdrModel*>(this)->getUnoModel(), uno::UNO_QUERY);
782 if (!xSBD.is())
784 SAL_WARN("svx", "no UNO model");
785 return nullptr;
787 return xSBD->getDocumentStorage();
790 uno::Reference<io::XInputStream>
791 SdrModel::GetDocumentStream( OUString const& rURL,
792 ::comphelper::LifecycleProxy const & rProxy) const
794 uno::Reference<embed::XStorage> const xStorage(GetDocumentStorage());
795 if (!xStorage.is())
797 SAL_WARN("svx", "no storage?");
798 return nullptr;
800 try {
801 uno::Reference<io::XStream> const xStream(
802 ::comphelper::OStorageHelper::GetStreamAtPackageURL(
803 xStorage, rURL, embed::ElementModes::READ, rProxy));
804 return (xStream.is()) ? xStream->getInputStream() : nullptr;
806 catch (container::NoSuchElementException const&)
808 SAL_INFO("svx", "not found");
810 catch (uno::Exception const&)
812 TOOLS_WARN_EXCEPTION("svx", "");
814 return nullptr;
817 // convert template attributes from the string into "hard" attributes
818 void SdrModel::BurnInStyleSheetAttributes()
820 sal_uInt16 nCount=GetMasterPageCount();
821 sal_uInt16 nNum;
822 for (nNum=0; nNum<nCount; nNum++) {
823 GetMasterPage(nNum)->BurnInStyleSheetAttributes();
825 nCount=GetPageCount();
826 for (nNum=0; nNum<nCount; nNum++) {
827 GetPage(nNum)->BurnInStyleSheetAttributes();
831 void SdrModel::RefDeviceChanged()
833 Broadcast(SdrHint(SdrHintKind::RefDeviceChange));
834 ImpReformatAllTextObjects();
837 void SdrModel::SetDefaultFontHeight(sal_Int32 nVal)
839 if (nVal!=mnDefTextHgt) {
840 mnDefTextHgt=nVal;
841 ImpReformatAllTextObjects();
845 void SdrModel::SetDefaultTabulator(sal_uInt16 nVal)
847 if (m_nDefaultTabulator!=nVal) {
848 m_nDefaultTabulator=nVal;
849 Outliner& rOutliner=GetDrawOutliner();
850 rOutliner.SetDefTab(nVal);
851 Broadcast(SdrHint(SdrHintKind::DefaultTabChange));
852 ImpReformatAllTextObjects();
856 void SdrModel::ImpSetUIUnit()
858 if(0 == m_aUIScale.GetNumerator() || 0 == m_aUIScale.GetDenominator())
860 m_aUIScale = Fraction(1,1);
863 m_nUIUnitDecimalMark = 0;
865 o3tl::Length eFrom = MapToO3tlLength(m_eObjUnit, o3tl::Length::invalid);
866 o3tl::Length eTo;
868 switch (m_eUIUnit)
870 case FieldUnit::CHAR:
871 case FieldUnit::LINE:
872 eTo = o3tl::Length::invalid;
873 break;
874 case FieldUnit::PERCENT:
875 m_nUIUnitDecimalMark += 2;
876 [[fallthrough]];
877 default:
878 eTo = FieldToO3tlLength(m_eUIUnit, o3tl::Length::invalid);
879 } // switch
881 sal_Int32 nMul = 1, nDiv = 1;
882 if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
884 const auto [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
885 nMul = mul;
886 nDiv = div;
888 // #i89872# take Unit of Measurement into account
889 if(1 != m_aUIScale.GetDenominator() || 1 != m_aUIScale.GetNumerator())
891 // divide by UIScale
892 nMul *= m_aUIScale.GetDenominator();
893 nDiv *= m_aUIScale.GetNumerator();
896 // shorten trailing zeros for dividend
897 while(0 == (nMul % 10))
899 m_nUIUnitDecimalMark--;
900 nMul /= 10;
903 // shorten trailing zeros for divisor
904 while(0 == (nDiv % 10))
906 m_nUIUnitDecimalMark++;
907 nDiv /= 10;
910 // end preparations, set member values
911 m_aUIUnitFact = Fraction(sal_Int32(nMul), sal_Int32(nDiv));
912 m_aUIUnitStr = GetUnitString(m_eUIUnit);
915 void SdrModel::SetScaleUnit(MapUnit eMap)
917 if (m_eObjUnit!=eMap) {
918 m_eObjUnit=eMap;
919 m_pItemPool->SetDefaultMetric(m_eObjUnit);
920 ImpSetUIUnit();
921 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
922 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
923 ImpReformatAllTextObjects();
927 void SdrModel::SetUIUnit(FieldUnit eUnit)
929 if (m_eUIUnit!=eUnit) {
930 m_eUIUnit=eUnit;
931 ImpSetUIUnit();
932 ImpReformatAllTextObjects();
936 void SdrModel::SetUIScale(const Fraction& rScale)
938 if (m_aUIScale!=rScale) {
939 m_aUIScale=rScale;
940 ImpSetUIUnit();
941 ImpReformatAllTextObjects();
945 void SdrModel::SetUIUnit(FieldUnit eUnit, const Fraction& rScale)
947 if (m_eUIUnit!=eUnit || m_aUIScale!=rScale) {
948 m_eUIUnit=eUnit;
949 m_aUIScale=rScale;
950 ImpSetUIUnit();
951 ImpReformatAllTextObjects();
955 OUString SdrModel::GetUnitString(FieldUnit eUnit)
957 switch(eUnit)
959 default:
960 case FieldUnit::NONE :
961 case FieldUnit::CUSTOM :
962 return OUString();
963 case FieldUnit::MM_100TH:
964 return u"/100mm"_ustr;
965 case FieldUnit::MM :
966 return u"mm"_ustr;
967 case FieldUnit::CM :
968 return u"cm"_ustr;
969 case FieldUnit::M :
970 return u"m"_ustr;
971 case FieldUnit::KM :
972 return u"km"_ustr;
973 case FieldUnit::TWIP :
974 return u"twip"_ustr;
975 case FieldUnit::POINT :
976 return u"pt"_ustr;
977 case FieldUnit::PICA :
978 return u"pica"_ustr;
979 case FieldUnit::INCH :
980 return u"\""_ustr;
981 case FieldUnit::FOOT :
982 return u"ft"_ustr;
983 case FieldUnit::MILE :
984 return u"mile(s)"_ustr;
985 case FieldUnit::PERCENT:
986 return u"%"_ustr;
990 OUString SdrModel::GetMetricString(tools::Long nVal, bool bNoUnitChars, sal_Int32 nNumDigits) const
992 // #i22167#
993 // change to double precision usage to not lose decimal places
994 const bool bNegative(nVal < 0);
995 SvtSysLocale aSysLoc;
996 const LocaleDataWrapper& rLoc(aSysLoc.GetLocaleData());
997 double fLocalValue(double(nVal) * double(m_aUIUnitFact));
999 if(bNegative)
1001 fLocalValue = -fLocalValue;
1004 if( -1 == nNumDigits )
1006 nNumDigits = LocaleDataWrapper::getNumDigits();
1009 sal_Int32 nDecimalMark(m_nUIUnitDecimalMark);
1011 if(nDecimalMark > nNumDigits)
1013 const sal_Int32 nDiff(nDecimalMark - nNumDigits);
1014 const double fFactor(pow(10.0, static_cast<int>(nDiff)));
1016 fLocalValue /= fFactor;
1017 nDecimalMark = nNumDigits;
1019 else if(nDecimalMark < nNumDigits)
1021 const sal_Int32 nDiff(nNumDigits - nDecimalMark);
1022 const double fFactor(pow(10.0, static_cast<int>(nDiff)));
1024 fLocalValue *= fFactor;
1025 nDecimalMark = nNumDigits;
1028 OUStringBuffer aBuf = OUString::number(static_cast<sal_Int32>(fLocalValue + 0.5));
1030 if(nDecimalMark < 0)
1032 // negative nDecimalMark (decimal point) means: add zeros
1033 sal_Int32 nCount(-nDecimalMark);
1035 for(sal_Int32 i=0; i<nCount; i++)
1036 aBuf.append('0');
1038 nDecimalMark = 0;
1041 // the second condition needs to be <= since inside this loop
1042 // also the leading zero is inserted.
1043 if (nDecimalMark > 0 && aBuf.getLength() <= nDecimalMark)
1045 // if necessary, add zeros before the decimal point
1046 sal_Int32 nCount = nDecimalMark - aBuf.getLength();
1048 if(nCount >= 0 && LocaleDataWrapper::isNumLeadingZero())
1049 nCount++;
1051 for(sal_Int32 i=0; i<nCount; i++)
1052 aBuf.insert(0, '0');
1055 const sal_Unicode cDec( rLoc.getNumDecimalSep()[0] );
1057 // insert the decimal mark character
1058 sal_Int32 nBeforeDecimalMark = aBuf.getLength() - nDecimalMark;
1060 if(nDecimalMark > 0)
1061 aBuf.insert(nBeforeDecimalMark, cDec);
1063 if(!LocaleDataWrapper::isNumTrailingZeros())
1065 sal_Int32 aPos=aBuf.getLength()-1;
1067 // Remove all trailing zeros.
1068 while (aPos>=0 && aBuf[aPos]=='0')
1069 --aPos;
1071 // Remove decimal if it's the last character.
1072 if (aPos>=0 && aBuf[aPos]==cDec)
1073 --aPos;
1075 // Adjust aPos to index first char to be truncated, if any
1076 if (++aPos<aBuf.getLength())
1077 aBuf.truncate(aPos);
1080 // if necessary, add separators before every third digit
1081 if( nBeforeDecimalMark > 3 )
1083 const OUString& aThoSep( rLoc.getNumThousandSep() );
1084 if ( !aThoSep.isEmpty() )
1086 sal_Unicode cTho( aThoSep[0] );
1087 sal_Int32 i(nBeforeDecimalMark - 3);
1089 while(i > 0)
1091 aBuf.insert(i, cTho);
1092 i -= 3;
1097 if (aBuf.isEmpty())
1098 aBuf.append("0");
1100 if(bNegative)
1102 aBuf.insert(0, "-");
1105 if(!bNoUnitChars)
1106 aBuf.append(m_aUIUnitStr);
1108 return aBuf.makeStringAndClear();
1111 OUString SdrModel::GetAngleString(Degree100 nAngle)
1113 bool bNeg = nAngle < 0_deg100;
1115 if(bNeg)
1116 nAngle = -nAngle;
1118 OUStringBuffer aBuf;
1119 aBuf.append(static_cast<sal_Int32>(nAngle));
1121 SvtSysLocale aSysLoc;
1122 const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
1123 sal_Int32 nCount = 2;
1125 if(LocaleDataWrapper::isNumLeadingZero())
1126 nCount++;
1128 while(aBuf.getLength() < nCount)
1129 aBuf.insert(0, '0');
1131 aBuf.insert(aBuf.getLength()-2, rLoc.getNumDecimalSep()[0]);
1133 if(bNeg)
1134 aBuf.insert(0, '-');
1136 aBuf.append(DEGREE_CHAR);
1138 return aBuf.makeStringAndClear();
1141 OUString SdrModel::GetPercentString(const Fraction& rVal)
1143 sal_Int32 nMul(rVal.GetNumerator());
1144 sal_Int32 nDiv(rVal.GetDenominator());
1145 bool bNeg {false};
1147 if (nDiv < 0)
1149 bNeg = !bNeg;
1150 nDiv = -nDiv;
1153 if (nMul < 0)
1155 bNeg = !bNeg;
1156 nMul = -nMul;
1159 sal_Int32 nPct = ((nMul*100) + nDiv/2)/nDiv;
1161 if (bNeg)
1162 nPct = -nPct;
1164 return OUString::number(nPct) + "%";
1167 void SdrModel::SetChanged(bool bFlg)
1169 mbChanged = bFlg;
1172 void SdrModel::RecalcPageNums(bool bMaster)
1174 if(bMaster)
1176 if (m_nMasterPageNumsDirtyFrom != SAL_MAX_UINT16)
1178 sal_uInt16 nCount=sal_uInt16(maMasterPages.size());
1179 for (sal_uInt16 i=m_nMasterPageNumsDirtyFrom; i<nCount; i++) {
1180 SdrPage* pPg = maMasterPages[i].get();
1181 pPg->SetPageNum(i);
1183 m_nMasterPageNumsDirtyFrom = SAL_MAX_UINT16;
1186 else
1188 if (m_nPageNumsDirtyFrom != SAL_MAX_UINT16)
1190 sal_uInt16 nCount=sal_uInt16(maPages.size());
1191 for (sal_uInt16 i = m_nPageNumsDirtyFrom; i<nCount; i++) {
1192 SdrPage* pPg = maPages[i].get();
1193 pPg->SetPageNum(i);
1195 m_nPageNumsDirtyFrom = SAL_MAX_UINT16;
1200 void SdrModel::InsertPage(SdrPage* pPage, sal_uInt16 nPos)
1202 sal_uInt16 nCount = GetPageCount();
1203 if (nPos > nCount)
1204 nPos = nCount;
1206 maPages.insert(maPages.begin() + nPos, pPage);
1207 PageListChanged();
1208 pPage->SetInserted();
1209 pPage->SetPageNum(nPos);
1211 if (mbMakePageObjectsNamesUnique)
1212 pPage->MakePageObjectsNamesUnique();
1214 if (nPos<nCount) m_nPageNumsDirtyFrom = std::min(m_nPageNumsDirtyFrom, static_cast<sal_uInt16>(nPos + 1));
1215 SetChanged();
1216 SdrHint aHint(SdrHintKind::PageOrderChange, pPage);
1217 Broadcast(aHint);
1220 void SdrModel::DeletePage(sal_uInt16 nPgNum)
1222 RemovePage(nPgNum);
1225 rtl::Reference<SdrPage> SdrModel::RemovePage(sal_uInt16 nPgNum)
1227 rtl::Reference<SdrPage> pPg = maPages[nPgNum];
1228 maPages.erase(maPages.begin()+nPgNum);
1229 PageListChanged();
1230 if (pPg) {
1231 pPg->SetInserted(false);
1233 m_nPageNumsDirtyFrom = std::min(m_nPageNumsDirtyFrom, nPgNum);
1234 SetChanged();
1235 SdrHint aHint(SdrHintKind::PageOrderChange, pPg.get());
1236 Broadcast(aHint);
1237 return pPg;
1240 void SdrModel::MovePage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
1242 rtl::Reference<SdrPage> pPg = std::move(maPages[nPgNum]);
1243 if (pPg) {
1244 maPages.erase(maPages.begin()+nPgNum); // shortcut to avoid two broadcasts
1245 PageListChanged();
1246 pPg->SetInserted(false);
1247 InsertPage(pPg.get(), nNewPos);
1249 else
1250 RemovePage(nPgNum);
1253 void SdrModel::InsertMasterPage(SdrPage* pPage, sal_uInt16 nPos)
1255 sal_uInt16 nCount=GetMasterPageCount();
1256 if (nPos>nCount) nPos=nCount;
1257 maMasterPages.insert(maMasterPages.begin()+nPos,pPage);
1258 MasterPageListChanged();
1259 pPage->SetInserted();
1260 pPage->SetPageNum(nPos);
1262 if (nPos<nCount) {
1263 m_nMasterPageNumsDirtyFrom = std::min(m_nMasterPageNumsDirtyFrom, static_cast<sal_uInt16>(nPos + 1));
1266 SetChanged();
1267 SdrHint aHint(SdrHintKind::PageOrderChange, pPage);
1268 Broadcast(aHint);
1271 void SdrModel::DeleteMasterPage(sal_uInt16 nPgNum)
1273 RemoveMasterPage(nPgNum);
1276 rtl::Reference<SdrPage> SdrModel::RemoveMasterPage(sal_uInt16 nPgNum)
1278 rtl::Reference<SdrPage> pRetPg = std::move(maMasterPages[nPgNum]);
1279 maMasterPages.erase(maMasterPages.begin()+nPgNum);
1280 MasterPageListChanged();
1282 if(pRetPg)
1284 // Now delete the links from the normal drawing pages to the deleted master page.
1285 sal_uInt16 nPageCnt(GetPageCount());
1287 for(sal_uInt16 np(0); np < nPageCnt; np++)
1289 GetPage(np)->TRG_ImpMasterPageRemoved(*pRetPg);
1292 pRetPg->SetInserted(false);
1295 m_nMasterPageNumsDirtyFrom = std::min(m_nMasterPageNumsDirtyFrom, nPgNum);
1296 SetChanged();
1297 SdrHint aHint(SdrHintKind::PageOrderChange, pRetPg.get());
1298 Broadcast(aHint);
1299 return pRetPg;
1302 void SdrModel::MoveMasterPage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
1304 rtl::Reference<SdrPage> pPg = std::move(maMasterPages[nPgNum]);
1305 maMasterPages.erase(maMasterPages.begin()+nPgNum);
1306 MasterPageListChanged();
1307 if (pPg) {
1308 pPg->SetInserted(false);
1309 maMasterPages.insert(maMasterPages.begin()+nNewPos,pPg);
1310 MasterPageListChanged();
1312 m_nMasterPageNumsDirtyFrom = std::min(m_nMasterPageNumsDirtyFrom, std::min(nPgNum, nNewPos));
1313 SetChanged();
1314 SdrHint aHint(SdrHintKind::PageOrderChange, pPg.get());
1315 Broadcast(aHint);
1319 void SdrModel::CopyPages(sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum,
1320 sal_uInt16 nDestPos,
1321 bool bUndo, bool bMoveNoCopy)
1323 if( bUndo && !IsUndoEnabled() )
1324 bUndo = false;
1326 if( bUndo )
1327 BegUndo(SvxResId(STR_UndoMergeModel));
1329 sal_uInt16 nPageCnt=GetPageCount();
1330 sal_uInt16 nMaxPage=nPageCnt;
1332 if (nMaxPage!=0)
1333 nMaxPage--;
1334 if (nFirstPageNum>nMaxPage)
1335 nFirstPageNum=nMaxPage;
1336 if (nLastPageNum>nMaxPage)
1337 nLastPageNum =nMaxPage;
1338 bool bReverse=nLastPageNum<nFirstPageNum;
1339 if (nDestPos>nPageCnt)
1340 nDestPos=nPageCnt;
1342 // at first, save the pointers of the affected pages in an array
1343 sal_uInt16 nPageNum=nFirstPageNum;
1344 sal_uInt16 nCopyCnt=((!bReverse)?(nLastPageNum-nFirstPageNum):(nFirstPageNum-nLastPageNum))+1;
1345 std::unique_ptr<SdrPage*[]> pPagePtrs(new SdrPage*[nCopyCnt]);
1346 sal_uInt16 nCopyNum;
1347 for(nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++)
1349 pPagePtrs[nCopyNum]=GetPage(nPageNum);
1350 if (bReverse)
1351 nPageNum--;
1352 else
1353 nPageNum++;
1356 // now copy the pages
1357 sal_uInt16 nDestNum=nDestPos;
1358 for (nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++)
1360 rtl::Reference<SdrPage> pPg = pPagePtrs[nCopyNum];
1361 sal_uInt16 nPageNum2=pPg->GetPageNum();
1362 if (!bMoveNoCopy)
1364 const SdrPage* pPg1=GetPage(nPageNum2);
1366 // Clone to local model
1367 pPg = pPg1->CloneSdrPage(*this);
1369 InsertPage(pPg.get(), nDestNum);
1370 if (bUndo)
1371 AddUndo(GetSdrUndoFactory().CreateUndoCopyPage(*pPg));
1372 nDestNum++;
1374 else
1376 // TODO: Move is untested!
1377 if (nDestNum>nPageNum2)
1378 nDestNum--;
1380 if(bUndo)
1381 AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*GetPage(nPageNum2),nPageNum2,nDestNum));
1383 pPg=RemovePage(nPageNum2);
1384 InsertPage(pPg.get(), nDestNum);
1385 nDestNum++;
1388 if(bReverse)
1389 nPageNum2--;
1390 else
1391 nPageNum2++;
1394 pPagePtrs.reset();
1395 if(bUndo)
1396 EndUndo();
1399 void SdrModel::Merge(SdrModel& rSourceModel,
1400 sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum,
1401 sal_uInt16 nDestPos,
1402 bool bMergeMasterPages, bool bAllMasterPages,
1403 bool bUndo, bool bTreadSourceAsConst)
1405 if (&rSourceModel==this)
1407 CopyPages(nFirstPageNum,nLastPageNum,nDestPos,bUndo,!bTreadSourceAsConst);
1408 return;
1411 if( bUndo && !IsUndoEnabled() )
1412 bUndo = false;
1414 if (bUndo)
1415 BegUndo(SvxResId(STR_UndoMergeModel));
1417 sal_uInt16 nSrcPageCnt=rSourceModel.GetPageCount();
1418 sal_uInt16 nSrcMasterPageCnt=rSourceModel.GetMasterPageCount();
1419 sal_uInt16 nDstMasterPageCnt=GetMasterPageCount();
1420 bool bInsPages=(nFirstPageNum<nSrcPageCnt || nLastPageNum<nSrcPageCnt);
1421 sal_uInt16 nMaxSrcPage=nSrcPageCnt; if (nMaxSrcPage!=0) nMaxSrcPage--;
1422 if (nFirstPageNum>nMaxSrcPage) nFirstPageNum=nMaxSrcPage;
1423 if (nLastPageNum>nMaxSrcPage) nLastPageNum =nMaxSrcPage;
1424 bool bReverse=nLastPageNum<nFirstPageNum;
1426 std::unique_ptr<sal_uInt16[]> pMasterMap;
1427 std::unique_ptr<bool[]> pMasterNeed;
1428 sal_uInt16 nMasterNeed=0;
1429 if (bMergeMasterPages && nSrcMasterPageCnt!=0) {
1430 // determine which MasterPages from rSrcModel we need
1431 pMasterMap.reset(new sal_uInt16[nSrcMasterPageCnt]);
1432 pMasterNeed.reset(new bool[nSrcMasterPageCnt]);
1433 memset(pMasterMap.get(),0xFF,nSrcMasterPageCnt*sizeof(sal_uInt16));
1434 if (bAllMasterPages) {
1435 memset(pMasterNeed.get(), true, nSrcMasterPageCnt * sizeof(bool));
1436 } else {
1437 memset(pMasterNeed.get(), false, nSrcMasterPageCnt * sizeof(bool));
1438 sal_uInt16 nStart= bReverse ? nLastPageNum : nFirstPageNum;
1439 sal_uInt16 nEnd= bReverse ? nFirstPageNum : nLastPageNum;
1440 for (sal_uInt16 i=nStart; i<=nEnd; i++) {
1441 const SdrPage* pPg=rSourceModel.GetPage(i);
1442 if(pPg->TRG_HasMasterPage())
1444 SdrPage& rMasterPage = pPg->TRG_GetMasterPage();
1445 sal_uInt16 nMPgNum(rMasterPage.GetPageNum());
1447 if(nMPgNum < nSrcMasterPageCnt)
1449 pMasterNeed[nMPgNum] = true;
1454 // now determine the Mapping of the MasterPages
1455 sal_uInt16 nCurrentMaPagNum=nDstMasterPageCnt;
1456 for (sal_uInt16 i=0; i<nSrcMasterPageCnt; i++) {
1457 if (pMasterNeed[i]) {
1458 pMasterMap[i]=nCurrentMaPagNum;
1459 nCurrentMaPagNum++;
1460 nMasterNeed++;
1465 // get the MasterPages
1466 if (pMasterMap && pMasterNeed && nMasterNeed!=0) {
1467 for (sal_uInt16 i=nSrcMasterPageCnt; i>0;) {
1468 i--;
1469 if (pMasterNeed[i])
1471 // Always Clone to new model
1472 const SdrPage* pPg1(rSourceModel.GetMasterPage(i));
1473 rtl::Reference<SdrPage> pPg = pPg1->CloneSdrPage(*this);
1475 if(!bTreadSourceAsConst)
1477 // if requested, delete original/modify original model
1478 rSourceModel.RemoveMasterPage(i);
1481 if (pPg!=nullptr) {
1482 // Now append all of them to the end of the DstModel.
1483 // Don't use InsertMasterPage(), because everything is
1484 // inconsistent until all are in.
1485 maMasterPages.insert(maMasterPages.begin()+nDstMasterPageCnt, pPg);
1486 MasterPageListChanged();
1487 pPg->SetInserted();
1488 m_nMasterPageNumsDirtyFrom = std::min(m_nMasterPageNumsDirtyFrom, nDstMasterPageCnt);
1489 if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg));
1490 } else {
1491 OSL_FAIL("SdrModel::Merge(): MasterPage not found in SourceModel.");
1497 // get the drawing pages
1498 if (bInsPages) {
1499 sal_uInt16 nSourcePos=nFirstPageNum;
1500 sal_uInt16 nMergeCount=sal_uInt16(std::abs(static_cast<tools::Long>(static_cast<tools::Long>(nFirstPageNum)-nLastPageNum))+1);
1501 if (nDestPos>GetPageCount()) nDestPos=GetPageCount();
1502 while (nMergeCount>0)
1504 // Always Clone to new model
1505 const SdrPage* pPg1(rSourceModel.GetPage(nSourcePos));
1506 rtl::Reference<SdrPage> pPg = pPg1->CloneSdrPage(*this);
1508 if(!bTreadSourceAsConst)
1510 // if requested, delete original/modify original model
1511 rSourceModel.RemovePage(nSourcePos);
1514 if (pPg!=nullptr) {
1515 InsertPage(pPg.get(),nDestPos);
1516 if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg));
1518 if(pPg->TRG_HasMasterPage())
1520 SdrPage& rMasterPage = pPg->TRG_GetMasterPage();
1521 sal_uInt16 nMaPgNum(rMasterPage.GetPageNum());
1523 if (bMergeMasterPages)
1525 sal_uInt16 nNewNum(0xFFFF);
1527 if(pMasterMap)
1529 nNewNum = pMasterMap[nMaPgNum];
1532 if(nNewNum != 0xFFFF)
1534 // tdf#90357 here pPg and the to-be-set new masterpage are parts of the new model
1535 // already, but the currently set masterpage is part of the old model. Remove master
1536 // page from already cloned page to prevent creating wrong undo action that can
1537 // eventually crash the app.
1538 // Do *not* remove it directly after cloning - the old masterpage is still needed
1539 // later to find the new to-be-set masterpage.
1540 pPg->TRG_ClearMasterPage();
1542 if(bUndo)
1544 AddUndo(GetSdrUndoFactory().CreateUndoPageChangeMasterPage(*pPg));
1547 pPg->TRG_SetMasterPage(*GetMasterPage(nNewNum));
1549 DBG_ASSERT(nNewNum!=0xFFFF,"SdrModel::Merge(): Something is crooked with the mapping of the MasterPages.");
1550 } else {
1551 if (nMaPgNum>=nDstMasterPageCnt) {
1552 // This is outside of the original area of the MasterPage of the DstModel.
1553 pPg->TRG_ClearMasterPage();
1558 } else {
1559 OSL_FAIL("SdrModel::Merge(): Drawing page not found in SourceModel.");
1561 nDestPos++;
1562 if (bReverse) nSourcePos--;
1563 else if (bTreadSourceAsConst) nSourcePos++;
1564 nMergeCount--;
1568 pMasterMap.reset();
1569 pMasterNeed.reset();
1571 m_nMasterPageNumsDirtyFrom = 0;
1572 m_nPageNumsDirtyFrom = 0;
1574 SetChanged();
1575 // TODO: Missing: merging and mapping of layers
1576 // at the objects as well as at the MasterPageDescriptors
1577 if (bUndo) EndUndo();
1580 void SdrModel::SetStarDrawPreviewMode(bool bPreview)
1582 if (!bPreview && m_bStarDrawPreviewMode && GetPageCount())
1584 // Resetting is not allowed, because the Model might not be loaded completely
1585 SAL_WARN("svx", "SdrModel::SetStarDrawPreviewMode(): Resetting not allowed, because Model might not be complete.");
1587 else
1589 m_bStarDrawPreviewMode = bPreview;
1593 void SdrModel::setTheme(std::shared_ptr<model::Theme> const& pTheme)
1595 mpImpl->mpTheme = pTheme;
1598 std::shared_ptr<model::Theme> const& SdrModel::getTheme() const
1600 return mpImpl->mpTheme;
1603 uno::Reference< frame::XModel > const & SdrModel::getUnoModel()
1605 if( !mxUnoModel.is() )
1606 mxUnoModel = createUnoModel();
1608 return mxUnoModel;
1611 void SdrModel::setUnoModel(const uno::Reference<frame::XModel>& xModel)
1613 mxUnoModel = xModel;
1616 void SdrModel::adaptSizeAndBorderForAllPages(
1617 const Size& /*rNewSize*/,
1618 tools::Long /*nLeft*/,
1619 tools::Long /*nRight*/,
1620 tools::Long /*nUpper*/,
1621 tools::Long /*nLower*/)
1623 // base implementation does currently nothing. It may be added if needed,
1624 // but we are on SdrModel level here, thus probably have not enough information
1625 // to do this for higher-level (derived) Models (e.g. Draw/Impress)
1628 uno::Reference< frame::XModel > SdrModel::createUnoModel()
1630 OSL_FAIL( "SdrModel::createUnoModel() - base implementation should not be called!" );
1631 return nullptr;
1634 void SdrModel::setLock( bool bLock )
1636 if( mbModelLocked != bLock )
1638 // #i120437# need to set first, else ImpReformatAllEdgeObjects will do nothing
1639 mbModelLocked = bLock;
1641 if( !bLock )
1643 ImpReformatAllEdgeObjects();
1649 void SdrModel::MigrateItemSet( const SfxItemSet* pSourceSet, SfxItemSet* pDestSet, SdrModel& rNewModel )
1651 if( !(pSourceSet && pDestSet && (pSourceSet != pDestSet )) )
1652 return;
1654 SfxWhichIter aWhichIter(*pSourceSet);
1655 sal_uInt16 nWhich(aWhichIter.FirstWhich());
1656 const SfxPoolItem *pPoolItem;
1658 while(nWhich)
1660 if(SfxItemState::SET == aWhichIter.GetItemState(false, &pPoolItem))
1662 std::unique_ptr<SfxPoolItem> pResultItem;
1664 switch( nWhich )
1666 case XATTR_FILLBITMAP:
1667 pResultItem = static_cast<const XFillBitmapItem*>(pPoolItem)->checkForUniqueItem( rNewModel );
1668 break;
1669 case XATTR_LINEDASH:
1670 pResultItem = static_cast<const XLineDashItem*>(pPoolItem)->checkForUniqueItem( rNewModel );
1671 break;
1672 case XATTR_LINESTART:
1673 pResultItem = static_cast<const XLineStartItem*>(pPoolItem)->checkForUniqueItem( rNewModel );
1674 break;
1675 case XATTR_LINEEND:
1676 pResultItem = static_cast<const XLineEndItem*>(pPoolItem)->checkForUniqueItem( rNewModel );
1677 break;
1678 case XATTR_FILLGRADIENT:
1679 pResultItem = static_cast<const XFillGradientItem*>(pPoolItem)->checkForUniqueItem( rNewModel );
1680 break;
1681 case XATTR_FILLFLOATTRANSPARENCE:
1682 // allow all kinds of XFillFloatTransparenceItem to be set
1683 pResultItem = static_cast<const XFillFloatTransparenceItem*>(pPoolItem)->checkForUniqueItem( rNewModel );
1684 break;
1685 case XATTR_FILLHATCH:
1686 pResultItem = static_cast<const XFillHatchItem*>(pPoolItem)->checkForUniqueItem( rNewModel );
1687 break;
1690 // set item
1691 if( pResultItem )
1692 pDestSet->Put(std::move(pResultItem));
1693 else
1694 pDestSet->Put(*pPoolItem);
1696 nWhich = aWhichIter.NextWhich();
1701 void SdrModel::SetForbiddenCharsTable(const std::shared_ptr<SvxForbiddenCharactersTable>& xForbiddenChars)
1703 mpForbiddenCharactersTable = xForbiddenChars;
1705 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1706 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1710 void SdrModel::SetCharCompressType( CharCompressType nType )
1712 if( nType != mnCharCompressType )
1714 mnCharCompressType = nType;
1715 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1716 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1720 void SdrModel::SetKernAsianPunctuation( bool bEnabled )
1722 if( mbKernAsianPunctuation != bEnabled )
1724 mbKernAsianPunctuation = bEnabled;
1725 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1726 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1730 void SdrModel::SetAddExtLeading( bool bEnabled )
1732 if( mbAddExtLeading != bEnabled )
1734 mbAddExtLeading = bEnabled;
1735 ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
1736 ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
1740 void SdrModel::SetCompatibilityFlag(SdrCompatibilityFlag eFlag, bool bEnabled)
1742 switch (eFlag)
1744 case SdrCompatibilityFlag::AnchoredTextOverflowLegacy:
1745 mpImpl->mbAnchoredTextOverflowLegacy = bEnabled;
1746 break;
1747 case SdrCompatibilityFlag::LegacyFontwork:
1748 mpImpl->mbLegacyFontwork = bEnabled;
1749 break;
1750 case SdrCompatibilityFlag::ConnectorUseSnapRect:
1751 mpImpl->mbConnectorUseSnapRect = bEnabled;
1752 break;
1753 case SdrCompatibilityFlag::IgnoreBreakAfterMultilineField:
1754 mpImpl->mbIgnoreBreakAfterMultilineField = bEnabled;
1755 break;
1759 bool SdrModel::GetCompatibilityFlag(SdrCompatibilityFlag eFlag) const
1761 switch (eFlag)
1763 case SdrCompatibilityFlag::AnchoredTextOverflowLegacy:
1764 return mpImpl->mbAnchoredTextOverflowLegacy;
1765 case SdrCompatibilityFlag::LegacyFontwork:
1766 return mpImpl->mbLegacyFontwork;
1767 case SdrCompatibilityFlag::ConnectorUseSnapRect:
1768 return mpImpl->mbConnectorUseSnapRect;
1769 case SdrCompatibilityFlag::IgnoreBreakAfterMultilineField:
1770 return mpImpl->mbIgnoreBreakAfterMultilineField;
1771 default:
1772 return false;
1776 void SdrModel::ReformatAllTextObjects()
1778 ImpReformatAllTextObjects();
1781 std::unique_ptr<SdrOutliner> SdrModel::createOutliner( OutlinerMode nOutlinerMode )
1783 if( !mpOutlinerCache )
1784 mpOutlinerCache.reset(new SdrOutlinerCache(this));
1786 return mpOutlinerCache->createOutliner( nOutlinerMode );
1789 std::vector<SdrOutliner*> SdrModel::GetActiveOutliners() const
1791 std::vector< SdrOutliner* > aRet(mpOutlinerCache ? mpOutlinerCache->GetActiveOutliners() : std::vector< SdrOutliner* >());
1792 aRet.push_back(m_pDrawOutliner.get());
1793 aRet.push_back(m_pHitTestOutliner.get());
1795 return aRet;
1798 void SdrModel::disposeOutliner( std::unique_ptr<SdrOutliner> pOutliner )
1800 if( mpOutlinerCache )
1801 mpOutlinerCache->disposeOutliner( std::move(pOutliner) );
1804 SvxNumType SdrModel::GetPageNumType() const
1806 return SVX_NUM_ARABIC;
1809 void SdrModel::ReadUserDataSequenceValue(const beans::PropertyValue* pValue)
1811 if (pValue->Name == "AnchoredTextOverflowLegacy")
1813 bool bBool = false;
1814 if (pValue->Value >>= bBool)
1816 mpImpl->mbAnchoredTextOverflowLegacy = bBool;
1819 else if (pValue->Name == "ConnectorUseSnapRect")
1821 bool bBool = false;
1822 if (pValue->Value >>= bBool)
1824 mpImpl->mbConnectorUseSnapRect = bBool;
1827 else if (pValue->Name == "LegacySingleLineFontwork")
1829 bool bBool = false;
1830 if ((pValue->Value >>= bBool) && mpImpl->mbLegacyFontwork != bBool)
1832 mpImpl->mbLegacyFontwork = bBool;
1833 // tdf#148000 hack: reset all CustomShape geometry as they may depend on this property
1834 // Ideally this ReadUserDataSequenceValue should be called before geometry creation
1835 // Once the calling order will be fixed, this hack will not be needed.
1836 for (size_t i = 0; i < maPages.size(); ++i)
1838 if (const SdrPage* pPage = maPages[i].get())
1840 SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
1841 while (aIter.IsMore())
1843 SdrObject* pTempObj = aIter.Next();
1844 if (SdrObjCustomShape* pShape = dynamic_cast<SdrObjCustomShape*>(pTempObj))
1846 pShape->InvalidateRenderGeometry();
1853 else if (pValue->Name == "IgnoreBreakAfterMultilineField")
1855 bool bBool = false;
1856 if (pValue->Value >>= bBool)
1858 mpImpl->mbIgnoreBreakAfterMultilineField = bBool;
1863 void SdrModel::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& rValues)
1865 std::vector< std::pair< OUString, uno::Any > > aUserData
1867 { "AnchoredTextOverflowLegacy", uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy)) },
1868 { "LegacySingleLineFontwork", uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork)) },
1869 { "ConnectorUseSnapRect", uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::ConnectorUseSnapRect)) },
1870 { "IgnoreBreakAfterMultilineField", uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::IgnoreBreakAfterMultilineField)) }
1873 const sal_Int32 nOldLength = rValues.getLength();
1874 rValues.realloc(nOldLength + aUserData.size());
1876 beans::PropertyValue* pValue = &(rValues.getArray()[nOldLength]);
1878 for (const auto &aIter : aUserData)
1880 pValue->Name = aIter.first;
1881 pValue->Value = aIter.second;
1882 ++pValue;
1886 const SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum) const
1888 return nPgNum < maPages.size() ? maPages[nPgNum].get() : nullptr;
1891 SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum)
1893 return nPgNum < maPages.size() ? maPages[nPgNum].get() : nullptr;
1896 sal_uInt16 SdrModel::GetPageCount() const
1898 return sal_uInt16(maPages.size());
1901 void SdrModel::PageListChanged()
1905 TextChain *SdrModel::GetTextChain() const
1907 return m_pTextChain.get();
1910 const SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum) const
1912 DBG_ASSERT(nPgNum < maMasterPages.size(), "SdrModel::GetMasterPage: Access out of range (!)");
1913 return maMasterPages[nPgNum].get();
1916 SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum)
1918 DBG_ASSERT(nPgNum < maMasterPages.size(), "SdrModel::GetMasterPage: Access out of range (!)");
1919 return maMasterPages[nPgNum].get();
1922 sal_uInt16 SdrModel::GetMasterPageCount() const
1924 return sal_uInt16(maMasterPages.size());
1927 void SdrModel::MasterPageListChanged()
1931 void SdrModel::SetSdrUndoManager( SfxUndoManager* pUndoManager )
1933 mpImpl->mpUndoManager = pUndoManager;
1936 SfxUndoManager* SdrModel::GetSdrUndoManager() const
1938 return mpImpl->mpUndoManager;
1941 SdrUndoFactory& SdrModel::GetSdrUndoFactory() const
1943 if( !mpImpl->mpUndoFactory )
1944 mpImpl->mpUndoFactory = new SdrUndoFactory;
1945 return *mpImpl->mpUndoFactory;
1948 void SdrModel::SetSdrUndoFactory( SdrUndoFactory* pUndoFactory )
1950 if( pUndoFactory && (pUndoFactory != mpImpl->mpUndoFactory) )
1952 delete mpImpl->mpUndoFactory;
1953 mpImpl->mpUndoFactory = pUndoFactory;
1957 void SdrModel::dumpAsXml(xmlTextWriterPtr pWriter) const
1959 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrModel"));
1960 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1962 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("maMasterPages"));
1963 for (size_t i = 0; i < maMasterPages.size(); ++i)
1965 if (const SdrPage* pPage = maMasterPages[i].get())
1967 pPage->dumpAsXml(pWriter);
1970 (void)xmlTextWriterEndElement(pWriter);
1972 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("maPages"));
1973 for (size_t i = 0; i < maPages.size(); ++i)
1975 if (const SdrPage* pPage = maPages[i].get())
1977 pPage->dumpAsXml(pWriter);
1980 (void)xmlTextWriterEndElement(pWriter);
1982 if (mpImpl->mpTheme)
1984 mpImpl->mpTheme->dumpAsXml(pWriter);
1987 (void)xmlTextWriterEndElement(pWriter);
1990 const uno::Sequence<sal_Int8>& SdrModel::getUnoTunnelId()
1992 static const comphelper::UnoIdInit theSdrModelUnoTunnelImplementationId;
1993 return theSdrModelUnoTunnelImplementationId.getSeq();
1997 SdrHint::SdrHint(SdrHintKind eNewHint)
1998 : SfxHint(SfxHintId::ThisIsAnSdrHint),
1999 meHint(eNewHint),
2000 mpObj(nullptr),
2001 mpPage(nullptr)
2005 SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj)
2006 : SfxHint(SfxHintId::ThisIsAnSdrHint),
2007 meHint(eNewHint),
2008 mpObj(&rNewObj),
2009 mpPage(rNewObj.getSdrPageFromSdrObject())
2013 SdrHint::SdrHint(SdrHintKind eNewHint, const SdrPage* pPage)
2014 : SfxHint(SfxHintId::ThisIsAnSdrHint),
2015 meHint(eNewHint),
2016 mpObj(nullptr),
2017 mpPage(pPage)
2021 SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj, const SdrPage* pPage)
2022 : SfxHint(SfxHintId::ThisIsAnSdrHint),
2023 meHint(eNewHint),
2024 mpObj(&rNewObj),
2025 mpPage(pPage)
2029 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */