diff options
Diffstat (limited to '')
-rw-r--r-- | svx/source/svdraw/svdmodel.cxx | 2035 |
1 files changed, 2035 insertions, 0 deletions
diff --git a/svx/source/svdraw/svdmodel.cxx b/svx/source/svdraw/svdmodel.cxx new file mode 100644 index 000000000..ccab4da45 --- /dev/null +++ b/svx/source/svdraw/svdmodel.cxx @@ -0,0 +1,2035 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svx/svdmodel.hxx> +#include <cassert> +#include <math.h> +#include <sal/log.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/document/XStorageBasedDocument.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <unotools/configmgr.hxx> +#include <unotools/pathoptions.hxx> +#include <svl/whiter.hxx> +#include <svl/asiancfg.hxx> +#include <svx/xbtmpit.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xlnedit.hxx> +#include <svx/xflgrit.hxx> +#include <svx/xflftrit.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xlnstit.hxx> +#include <editeng/editeng.hxx> +#include <svx/xtable.hxx> +#include <svx/svdtrans.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdlayer.hxx> +#include <svx/svdundo.hxx> +#include <svx/svdpool.hxx> +#include <svx/svdobj.hxx> +#include <svx/svdotext.hxx> +#include <textchain.hxx> +#include <svx/svdetc.hxx> +#include <svx/svdoutl.hxx> +#include <svx/dialmgr.hxx> +#include <svx/strings.hrc> +#include <svdoutlinercache.hxx> +#include <svx/sdasitm.hxx> +#include <officecfg/Office/Common.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fhgtitem.hxx> +#include <svl/style.hxx> +#include <editeng/forbiddencharacterstable.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/storagehelper.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/syslocale.hxx> +#include <editeng/eeitem.hxx> +#include <svl/itemset.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <memory> +#include <libxml/xmlwriter.h> +#include <sfx2/viewsh.hxx> +#include <o3tl/enumrange.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + + +struct SdrModelImpl +{ + SfxUndoManager* mpUndoManager; + SdrUndoFactory* mpUndoFactory; + + bool mbAnchoredTextOverflowLegacy; // tdf#99729 compatibility flag +}; + + +void SdrModel::ImpCtor( + SfxItemPool* pPool, + ::comphelper::IEmbeddedHelper* _pEmbeddedHelper, + bool bDisablePropertyFiles) +{ + mpImpl.reset(new SdrModelImpl); + mpImpl->mpUndoManager=nullptr; + mpImpl->mpUndoFactory=nullptr; + mpImpl->mbAnchoredTextOverflowLegacy = false; + mbInDestruction = false; + m_aObjUnit=SdrEngineDefaults::GetMapFraction(); + m_eObjUnit=SdrEngineDefaults::GetMapUnit(); + m_eUIUnit=FieldUnit::MM; + m_aUIScale=Fraction(1,1); + m_nUIUnitDecimalMark=0; + m_pLayerAdmin=nullptr; + m_pItemPool=pPool; + m_bMyPool=false; + m_pEmbeddedHelper=_pEmbeddedHelper; + m_pDrawOutliner=nullptr; + m_pHitTestOutliner=nullptr; + m_pRefOutDev=nullptr; + m_pDefaultStyleSheet=nullptr; + mpDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj = nullptr; + m_pLinkManager=nullptr; + m_pUndoStack=nullptr; + m_pRedoStack=nullptr; + m_nMaxUndoCount=16; + m_pCurrentUndoGroup=nullptr; + m_nUndoLevel=0; + mbUndoEnabled=true; + mbChanged = false; + m_bPagNumsDirty=false; + m_bMPgNumsDirty=false; + m_bTransportContainer = false; + m_bSwapGraphics=false; + m_bPasteResize=false; + m_bReadOnly=false; + m_nDefaultTabulator=0; + m_bTransparentTextFrames=false; + m_bStarDrawPreviewMode = false; + mpForbiddenCharactersTable = nullptr; + mbModelLocked = false; + mpOutlinerCache = nullptr; + mbKernAsianPunctuation = false; + mbAddExtLeading = false; + mnHandoutPageCount = 0; + + mbDisableTextEditUsesCommonUndoManager = false; + + if (!utl::ConfigManager::IsFuzzing()) + mnCharCompressType = static_cast<CharCompressType>(officecfg::Office::Common::AsianLayout::CompressCharacterDistance:: + get()); + else + mnCharCompressType = CharCompressType::NONE; + + if ( pPool == nullptr ) + { + m_pItemPool=new SdrItemPool(nullptr); + // Outliner doesn't have its own Pool, so use the EditEngine's + SfxItemPool* pOutlPool=EditEngine::CreatePool(); + // OutlinerPool as SecondaryPool of SdrPool + m_pItemPool->SetSecondaryPool(pOutlPool); + // remember that I created both pools myself + m_bMyPool=true; + } + m_pItemPool->SetDefaultMetric(m_eObjUnit); + +// using static SdrEngineDefaults only if default SvxFontHeight item is not available + const SfxPoolItem* pPoolItem = m_pItemPool->GetPoolDefaultItem( EE_CHAR_FONTHEIGHT ); + if ( pPoolItem ) + mnDefTextHgt = static_cast<const SvxFontHeightItem*>(pPoolItem)->GetHeight(); + else + mnDefTextHgt = SdrEngineDefaults::GetFontHeight(); + + m_pItemPool->SetPoolDefaultItem( makeSdrTextWordWrapItem( false ) ); + + SetTextDefaults(); + m_pLayerAdmin.reset(new SdrLayerAdmin); + m_pLayerAdmin->SetModel(this); + ImpSetUIUnit(); + + // can't create DrawOutliner OnDemand, because I can't get the Pool, + // then (only from 302 onwards!) + m_pDrawOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this); + ImpSetOutlinerDefaults(m_pDrawOutliner.get(), true); + + m_pHitTestOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this); + ImpSetOutlinerDefaults(m_pHitTestOutliner.get(), true); + + /* Start Text Chaining related code */ + // Initialize Chaining Outliner + m_pChainingOutliner = SdrMakeOutliner( OutlinerMode::TextObject, *this ); + ImpSetOutlinerDefaults(m_pChainingOutliner.get(), true); + + // Make a TextChain + m_pTextChain.reset(new TextChain); + /* End Text Chaining related code */ + + ImpCreateTables(bDisablePropertyFiles || utl::ConfigManager::IsFuzzing()); +} + +SdrModel::SdrModel( + SfxItemPool* pPool, + ::comphelper::IEmbeddedHelper* pPers, + bool bDisablePropertyFiles) +: +#ifdef DBG_UTIL + // SdrObjectLifetimeWatchDog: + maAllIncarnatedObjects(), +#endif + maMaPag(), + maPages() +{ + ImpCtor(pPool,pPers,bDisablePropertyFiles); +} + +SdrModel::~SdrModel() +{ + + mbInDestruction = true; + + Broadcast(SdrHint(SdrHintKind::ModelCleared)); + + mpOutlinerCache.reset(); + + ClearUndoBuffer(); +#ifdef DBG_UTIL + SAL_WARN_IF(m_pCurrentUndoGroup, "svx", "In the Dtor of the SdrModel there is an open Undo left: \"" + << m_pCurrentUndoGroup->GetComment() << '\"'); +#endif + m_pCurrentUndoGroup.reset(); + + ClearModel(true); + +#ifdef DBG_UTIL + // SdrObjectLifetimeWatchDog: + if(!maAllIncarnatedObjects.empty()) + { + SAL_WARN("svx","SdrModel::~SdrModel: Not all incarnations of SdrObjects deleted, possible memory leak (!)"); + // copy to std::vector - calling SdrObject::Free will change maAllIncarnatedObjects + const std::vector< const SdrObject* > maRemainingObjects(maAllIncarnatedObjects.begin(), maAllIncarnatedObjects.end()); + for(auto pSdrObject : maRemainingObjects) + { + SdrObject* pCandidate(const_cast<SdrObject*>(pSdrObject)); + SdrObject::Free(pCandidate); + } + } +#endif + + m_pLayerAdmin.reset(); + + m_pTextChain.reset(); + // Delete DrawOutliner only after deleting ItemPool, because ItemPool + // references Items of the DrawOutliner! + m_pChainingOutliner.reset(); + m_pHitTestOutliner.reset(); + m_pDrawOutliner.reset(); + + // delete StyleSheetPool, derived classes should not do this since + // the DrawingEngine may need it in its destructor + if( mxStyleSheetPool.is() ) + { + Reference< XComponent > xComponent( dynamic_cast< cppu::OWeakObject* >( mxStyleSheetPool.get() ), UNO_QUERY ); + if( xComponent.is() ) try + { + xComponent->dispose(); + } + catch( RuntimeException& ) + { + } + mxStyleSheetPool.clear(); + } + + if (m_bMyPool) + { + // delete Pools if they're mine + SfxItemPool* pOutlPool=m_pItemPool->GetSecondaryPool(); + SfxItemPool::Free(m_pItemPool); + // OutlinerPool has to be deleted after deleting ItemPool, because + // ItemPool contains SetItems that themselves reference Items from OutlinerPool. + SfxItemPool::Free(pOutlPool); + } + + mpForbiddenCharactersTable.reset(); + + delete mpImpl->mpUndoFactory; +} + +void SdrModel::SetSwapGraphics() +{ + m_bSwapGraphics = true; +} + +bool SdrModel::IsReadOnly() const +{ + return m_bReadOnly; +} + +void SdrModel::SetReadOnly(bool bYes) +{ + m_bReadOnly=bYes; +} + + +void SdrModel::SetMaxUndoActionCount(sal_uInt32 nCount) +{ + if (nCount<1) nCount=1; + m_nMaxUndoCount=nCount; + if (m_pUndoStack) { + while (m_pUndoStack->size()>m_nMaxUndoCount) { + m_pUndoStack->pop_back(); + } + } +} + +void SdrModel::ClearUndoBuffer() +{ + m_pUndoStack.reset(); + m_pRedoStack.reset(); +} + +bool SdrModel::HasUndoActions() const +{ + return m_pUndoStack && !m_pUndoStack->empty(); +} + +bool SdrModel::HasRedoActions() const +{ + return m_pRedoStack && !m_pRedoStack->empty(); +} + +void SdrModel::Undo() +{ + if( mpImpl->mpUndoManager ) + { + OSL_FAIL("svx::SdrModel::Undo(), method not supported with application undo manager!"); + } + else + { + if(HasUndoActions()) + { + SfxUndoAction* pDo = m_pUndoStack->front().get(); + const bool bWasUndoEnabled = mbUndoEnabled; + mbUndoEnabled = false; + pDo->Undo(); + if(!m_pRedoStack) + m_pRedoStack.reset(new std::deque<std::unique_ptr<SfxUndoAction>>); + std::unique_ptr<SfxUndoAction> p = std::move(m_pUndoStack->front()); + m_pUndoStack->pop_front(); + m_pRedoStack->emplace_front(std::move(p)); + mbUndoEnabled = bWasUndoEnabled; + } + } +} + +void SdrModel::Redo() +{ + if( mpImpl->mpUndoManager ) + { + OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!"); + } + else + { + if(HasRedoActions()) + { + SfxUndoAction* pDo = m_pRedoStack->front().get(); + const bool bWasUndoEnabled = mbUndoEnabled; + mbUndoEnabled = false; + pDo->Redo(); + if(!m_pUndoStack) + m_pUndoStack.reset(new std::deque<std::unique_ptr<SfxUndoAction>>); + std::unique_ptr<SfxUndoAction> p = std::move(m_pRedoStack->front()); + m_pRedoStack->pop_front(); + m_pUndoStack->emplace_front(std::move(p)); + mbUndoEnabled = bWasUndoEnabled; + } + } +} + +void SdrModel::Repeat(SfxRepeatTarget& rView) +{ + if( mpImpl->mpUndoManager ) + { + OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!"); + } + else + { + if(HasUndoActions()) + { + SfxUndoAction* pDo = m_pUndoStack->front().get(); + if(pDo->CanRepeat(rView)) + { + pDo->Repeat(rView); + } + } + } +} + +void SdrModel::ImpPostUndoAction(std::unique_ptr<SdrUndoAction> pUndo) +{ + DBG_ASSERT( mpImpl->mpUndoManager == nullptr, "svx::SdrModel::ImpPostUndoAction(), method not supported with application undo manager!" ); + if( IsUndoEnabled() ) + { + if (m_aUndoLink) + { + m_aUndoLink(std::move(pUndo)); + } + else + { + if (!m_pUndoStack) + m_pUndoStack.reset(new std::deque<std::unique_ptr<SfxUndoAction>>); + m_pUndoStack->emplace_front(std::move(pUndo)); + while (m_pUndoStack->size()>m_nMaxUndoCount) + { + m_pUndoStack->pop_back(); + } + if (m_pRedoStack!=nullptr) + m_pRedoStack->clear(); + } + } +} + +void SdrModel::BegUndo() +{ + if( mpImpl->mpUndoManager ) + { + ViewShellId nViewShellId(-1); + if (SfxViewShell* pViewShell = SfxViewShell::Current()) + nViewShellId = pViewShell->GetViewShellId(); + mpImpl->mpUndoManager->EnterListAction("","",0,nViewShellId); + m_nUndoLevel++; + } + else if( IsUndoEnabled() ) + { + if(!m_pCurrentUndoGroup) + { + m_pCurrentUndoGroup.reset(new SdrUndoGroup(*this)); + m_nUndoLevel=1; + } + else + { + m_nUndoLevel++; + } + } +} + +void SdrModel::BegUndo(const OUString& rComment) +{ + if( mpImpl->mpUndoManager ) + { + ViewShellId nViewShellId(-1); + if (SfxViewShell* pViewShell = SfxViewShell::Current()) + nViewShellId = pViewShell->GetViewShellId(); + mpImpl->mpUndoManager->EnterListAction( rComment, "", 0, nViewShellId ); + m_nUndoLevel++; + } + else if( IsUndoEnabled() ) + { + BegUndo(); + if (m_nUndoLevel==1) + { + m_pCurrentUndoGroup->SetComment(rComment); + } + } +} + +void SdrModel::BegUndo(const OUString& rComment, const OUString& rObjDescr, SdrRepeatFunc eFunc) +{ + if( mpImpl->mpUndoManager ) + { + OUString aComment(rComment); + if( !aComment.isEmpty() && !rObjDescr.isEmpty() ) + { + aComment = aComment.replaceFirst("%1", rObjDescr); + } + ViewShellId nViewShellId(-1); + if (SfxViewShell* pViewShell = SfxViewShell::Current()) + nViewShellId = pViewShell->GetViewShellId(); + mpImpl->mpUndoManager->EnterListAction( aComment,"",0,nViewShellId ); + m_nUndoLevel++; + } + else if( IsUndoEnabled() ) + { + BegUndo(); + if (m_nUndoLevel==1) + { + m_pCurrentUndoGroup->SetComment(rComment); + m_pCurrentUndoGroup->SetObjDescription(rObjDescr); + m_pCurrentUndoGroup->SetRepeatFunction(eFunc); + } + } +} + +void SdrModel::EndUndo() +{ + DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::EndUndo(): UndoLevel is already 0!"); + if( mpImpl->mpUndoManager ) + { + if( m_nUndoLevel ) + { + m_nUndoLevel--; + mpImpl->mpUndoManager->LeaveListAction(); + } + } + else + { + if(m_pCurrentUndoGroup!=nullptr && IsUndoEnabled()) + { + m_nUndoLevel--; + if(m_nUndoLevel==0) + { + if(m_pCurrentUndoGroup->GetActionCount()!=0) + { + ImpPostUndoAction(std::move(m_pCurrentUndoGroup)); + } + else + { + // was empty + m_pCurrentUndoGroup.reset(); + } + } + } + } +} + +void SdrModel::SetUndoComment(const OUString& rComment) +{ + DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!"); + + if( mpImpl->mpUndoManager ) + { + OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" ); + } + else if( IsUndoEnabled() && m_nUndoLevel==1) + { + m_pCurrentUndoGroup->SetComment(rComment); + } +} + +void SdrModel::SetUndoComment(const OUString& rComment, const OUString& rObjDescr) +{ + DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!"); + if( mpImpl->mpUndoManager ) + { + OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" ); + } + else + { + if (m_nUndoLevel==1) + { + m_pCurrentUndoGroup->SetComment(rComment); + m_pCurrentUndoGroup->SetObjDescription(rObjDescr); + } + } +} + +void SdrModel::AddUndo(std::unique_ptr<SdrUndoAction> pUndo) +{ + if( mpImpl->mpUndoManager ) + { + mpImpl->mpUndoManager->AddUndoAction( std::move(pUndo) ); + } + else if( IsUndoEnabled() ) + { + if (m_pCurrentUndoGroup) + { + m_pCurrentUndoGroup->AddAction(std::move(pUndo)); + } + else + { + ImpPostUndoAction(std::move(pUndo)); + } + } +} + +void SdrModel::EnableUndo( bool bEnable ) +{ + if( mpImpl->mpUndoManager ) + { + mpImpl->mpUndoManager->EnableUndo( bEnable ); + } + else + { + mbUndoEnabled = bEnable; + } +} + +bool SdrModel::IsUndoEnabled() const +{ + if( mpImpl->mpUndoManager ) + { + return mpImpl->mpUndoManager->IsUndoEnabled(); + } + else + { + return mbUndoEnabled; + } +} + +void SdrModel::ImpCreateTables(bool bDisablePropertyFiles) +{ + // use standard path for initial construction + const OUString aTablePath(!bDisablePropertyFiles ? SvtPathOptions().GetPalettePath() : ""); + + for( auto i : o3tl::enumrange<XPropertyListType>() ) + { + maProperties[i] = XPropertyList::CreatePropertyList(i, aTablePath, ""/*TODO?*/ ); + } +} + +void SdrModel::ClearModel(bool bCalledFromDestructor) +{ + if(bCalledFromDestructor) + { + mbInDestruction = true; + } + + sal_Int32 i; + // delete all drawing pages + sal_Int32 nCount=GetPageCount(); + for (i=nCount-1; i>=0; i--) + { + DeletePage( static_cast<sal_uInt16>(i) ); + } + maPages.clear(); + PageListChanged(); + + // delete all Masterpages + nCount=GetMasterPageCount(); + for(i=nCount-1; i>=0; i--) + { + DeleteMasterPage( static_cast<sal_uInt16>(i) ); + } + maMaPag.clear(); + MasterPageListChanged(); + + m_pLayerAdmin->ClearLayers(); +} + +SdrModel* SdrModel::AllocModel() const +{ + SdrModel* pModel=new SdrModel(); + pModel->SetScaleUnit(m_eObjUnit,m_aObjUnit); + return pModel; +} + +SdrPage* SdrModel::AllocPage(bool bMasterPage) +{ + return new SdrPage(*this,bMasterPage); +} + +void SdrModel::SetTextDefaults() const +{ + SetTextDefaults( m_pItemPool, mnDefTextHgt ); +} + +void SdrModel::SetTextDefaults( SfxItemPool* pItemPool, sal_Int32 nDefTextHgt ) +{ + // set application-language specific dynamic pool language defaults + SvxFontItem aSvxFontItem( EE_CHAR_FONTINFO) ; + SvxFontItem aSvxFontItemCJK(EE_CHAR_FONTINFO_CJK); + SvxFontItem aSvxFontItemCTL(EE_CHAR_FONTINFO_CTL); + LanguageType nLanguage; + if (!utl::ConfigManager::IsFuzzing()) + nLanguage = Application::GetSettings().GetLanguageTag().getLanguageType(); + else + nLanguage = LANGUAGE_ENGLISH_US; + + // get DEFAULTFONT_LATIN_TEXT and set at pool as dynamic default + vcl::Font aFont(OutputDevice::GetDefaultFont(DefaultFontType::LATIN_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne)); + aSvxFontItem.SetFamily(aFont.GetFamilyType()); + aSvxFontItem.SetFamilyName(aFont.GetFamilyName()); + aSvxFontItem.SetStyleName(OUString()); + aSvxFontItem.SetPitch( aFont.GetPitch()); + aSvxFontItem.SetCharSet( aFont.GetCharSet() ); + pItemPool->SetPoolDefaultItem(aSvxFontItem); + + // get DEFAULTFONT_CJK_TEXT and set at pool as dynamic default + vcl::Font aFontCJK(OutputDevice::GetDefaultFont(DefaultFontType::CJK_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne)); + aSvxFontItemCJK.SetFamily( aFontCJK.GetFamilyType()); + aSvxFontItemCJK.SetFamilyName(aFontCJK.GetFamilyName()); + aSvxFontItemCJK.SetStyleName(OUString()); + aSvxFontItemCJK.SetPitch( aFontCJK.GetPitch()); + aSvxFontItemCJK.SetCharSet( aFontCJK.GetCharSet()); + pItemPool->SetPoolDefaultItem(aSvxFontItemCJK); + + // get DEFAULTFONT_CTL_TEXT and set at pool as dynamic default + vcl::Font aFontCTL(OutputDevice::GetDefaultFont(DefaultFontType::CTL_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne)); + aSvxFontItemCTL.SetFamily(aFontCTL.GetFamilyType()); + aSvxFontItemCTL.SetFamilyName(aFontCTL.GetFamilyName()); + aSvxFontItemCTL.SetStyleName(OUString()); + aSvxFontItemCTL.SetPitch( aFontCTL.GetPitch() ); + aSvxFontItemCTL.SetCharSet( aFontCTL.GetCharSet()); + pItemPool->SetPoolDefaultItem(aSvxFontItemCTL); + + // set dynamic FontHeight defaults + pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT ) ); + pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CJK ) ); + pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CTL ) ); + + // set FontColor defaults + pItemPool->SetPoolDefaultItem( SvxColorItem(SdrEngineDefaults::GetFontColor(), EE_CHAR_COLOR) ); +} + +SdrOutliner& SdrModel::GetDrawOutliner(const SdrTextObj* pObj) const +{ + m_pDrawOutliner->SetTextObj(pObj); + return *m_pDrawOutliner; +} + +SdrOutliner& SdrModel::GetChainingOutliner(const SdrTextObj* pObj) const +{ + m_pChainingOutliner->SetTextObj(pObj); + return *m_pChainingOutliner; +} + +const SdrTextObj* SdrModel::GetFormattingTextObj() const +{ + if (m_pDrawOutliner!=nullptr) { + return m_pDrawOutliner->GetTextObj(); + } + return nullptr; +} + +void SdrModel::ImpSetOutlinerDefaults( SdrOutliner* pOutliner, bool bInit ) +{ + // Initialization of the Outliners for drawing text and HitTest + if( bInit ) + { + pOutliner->EraseVirtualDevice(); + pOutliner->SetUpdateMode(false); + pOutliner->SetEditTextObjectPool(m_pItemPool); + pOutliner->SetDefTab(m_nDefaultTabulator); + } + + pOutliner->SetRefDevice(GetRefDevice()); + Outliner::SetForbiddenCharsTable(GetForbiddenCharsTable()); + pOutliner->SetAsianCompressionMode( mnCharCompressType ); + pOutliner->SetKernAsianPunctuation( IsKernAsianPunctuation() ); + pOutliner->SetAddExtLeading( IsAddExtLeading() ); + + if ( !GetRefDevice() ) + { + MapMode aMapMode(m_eObjUnit, Point(0,0), m_aObjUnit, m_aObjUnit); + pOutliner->SetRefMapMode(aMapMode); + } +} + +void SdrModel::SetRefDevice(OutputDevice* pDev) +{ + m_pRefOutDev=pDev; + ImpSetOutlinerDefaults( m_pDrawOutliner.get() ); + ImpSetOutlinerDefaults( m_pHitTestOutliner.get() ); + RefDeviceChanged(); +} + +void SdrModel::ImpReformatAllTextObjects() +{ + if( isLocked() ) + return; + + sal_uInt16 nCount=GetMasterPageCount(); + sal_uInt16 nNum; + for (nNum=0; nNum<nCount; nNum++) { + GetMasterPage(nNum)->ReformatAllTextObjects(); + } + nCount=GetPageCount(); + for (nNum=0; nNum<nCount; nNum++) { + GetPage(nNum)->ReformatAllTextObjects(); + } +} + +/* steps over all available pages and sends notify messages to + all edge objects that are connected to other objects so that + they may reposition themselves +*/ +void SdrModel::ImpReformatAllEdgeObjects() +{ + if( isLocked() ) + return; + + sal_uInt16 nCount=GetMasterPageCount(); + sal_uInt16 nNum; + for (nNum=0; nNum<nCount; nNum++) + { + GetMasterPage(nNum)->ReformatAllEdgeObjects(); + } + nCount=GetPageCount(); + for (nNum=0; nNum<nCount; nNum++) + { + GetPage(nNum)->ReformatAllEdgeObjects(); + } +} + +uno::Reference<embed::XStorage> SdrModel::GetDocumentStorage() const +{ + uno::Reference<document::XStorageBasedDocument> const xSBD( + const_cast<SdrModel*>(this)->getUnoModel(), uno::UNO_QUERY); + if (!xSBD.is()) + { + SAL_WARN("svx", "no UNO model"); + return nullptr; + } + return xSBD->getDocumentStorage(); +} + +uno::Reference<io::XInputStream> +SdrModel::GetDocumentStream( OUString const& rURL, + ::comphelper::LifecycleProxy const & rProxy) const +{ + uno::Reference<embed::XStorage> const xStorage(GetDocumentStorage()); + if (!xStorage.is()) + { + SAL_WARN("svx", "no storage?"); + return nullptr; + } + try { + uno::Reference<io::XStream> const xStream( + ::comphelper::OStorageHelper::GetStreamAtPackageURL( + xStorage, rURL, embed::ElementModes::READ, rProxy)); + return (xStream.is()) ? xStream->getInputStream() : nullptr; + } + catch (container::NoSuchElementException const&) + { + SAL_INFO("svx", "not found"); + } + catch (uno::Exception const&) + { + TOOLS_WARN_EXCEPTION("svx", ""); + } + return nullptr; +} + +// convert template attributes from the string into "hard" attributes +void SdrModel::BurnInStyleSheetAttributes() +{ + sal_uInt16 nCount=GetMasterPageCount(); + sal_uInt16 nNum; + for (nNum=0; nNum<nCount; nNum++) { + GetMasterPage(nNum)->BurnInStyleSheetAttributes(); + } + nCount=GetPageCount(); + for (nNum=0; nNum<nCount; nNum++) { + GetPage(nNum)->BurnInStyleSheetAttributes(); + } +} + +void SdrModel::RefDeviceChanged() +{ + Broadcast(SdrHint(SdrHintKind::RefDeviceChange)); + ImpReformatAllTextObjects(); +} + +void SdrModel::SetDefaultFontHeight(sal_Int32 nVal) +{ + if (nVal!=mnDefTextHgt) { + mnDefTextHgt=nVal; + ImpReformatAllTextObjects(); + } +} + +void SdrModel::SetDefaultTabulator(sal_uInt16 nVal) +{ + if (m_nDefaultTabulator!=nVal) { + m_nDefaultTabulator=nVal; + Outliner& rOutliner=GetDrawOutliner(); + rOutliner.SetDefTab(nVal); + Broadcast(SdrHint(SdrHintKind::DefaultTabChange)); + ImpReformatAllTextObjects(); + } +} + +void SdrModel::ImpSetUIUnit() +{ + if(0 == m_aUIScale.GetNumerator() || 0 == m_aUIScale.GetDenominator()) + { + m_aUIScale = Fraction(1,1); + } + + // set start values + m_nUIUnitDecimalMark = 0; + sal_Int64 nMul(1); + sal_Int64 nDiv(1); + + // normalize on meters resp. inch + switch (m_eObjUnit) + { + case MapUnit::Map100thMM : m_nUIUnitDecimalMark+=5; break; + case MapUnit::Map10thMM : m_nUIUnitDecimalMark+=4; break; + case MapUnit::MapMM : m_nUIUnitDecimalMark+=3; break; + case MapUnit::MapCM : m_nUIUnitDecimalMark+=2; break; + case MapUnit::Map1000thInch: m_nUIUnitDecimalMark+=3; break; + case MapUnit::Map100thInch : m_nUIUnitDecimalMark+=2; break; + case MapUnit::Map10thInch : m_nUIUnitDecimalMark+=1; break; + case MapUnit::MapInch : m_nUIUnitDecimalMark+=0; break; + case MapUnit::MapPoint : nDiv=72; break; // 1Pt = 1/72" + case MapUnit::MapTwip : nDiv=144; m_nUIUnitDecimalMark++; break; // 1Twip = 1/1440" + case MapUnit::MapPixel : break; + case MapUnit::MapSysFont : break; + case MapUnit::MapAppFont : break; + case MapUnit::MapRelative : break; + default: break; + } // switch + + // 1 mile = 8 furlong = 63.360" = 1.609.344,0mm + // 1 furlong = 10 chains = 7.920" = 201.168,0mm + // 1 chain = 4 poles = 792" = 20.116,8mm + // 1 pole = 5 1/2 yd = 198" = 5.029,2mm + // 1 yd = 3 ft = 36" = 914,4mm + // 1 ft = 12 " = 1" = 304,8mm + switch (m_eUIUnit) + { + case FieldUnit::NONE : break; + // metric + case FieldUnit::MM_100TH: m_nUIUnitDecimalMark-=5; break; + case FieldUnit::MM : m_nUIUnitDecimalMark-=3; break; + case FieldUnit::CM : m_nUIUnitDecimalMark-=2; break; + case FieldUnit::M : m_nUIUnitDecimalMark+=0; break; + case FieldUnit::KM : m_nUIUnitDecimalMark+=3; break; + // Inch + case FieldUnit::TWIP : nMul=144; m_nUIUnitDecimalMark--; break; // 1Twip = 1/1440" + case FieldUnit::POINT : nMul=72; break; // 1Pt = 1/72" + case FieldUnit::PICA : nMul=6; break; // 1Pica = 1/6" + case FieldUnit::INCH : break; // 1" = 1" + case FieldUnit::FOOT : nDiv*=12; break; // 1Ft = 12" + case FieldUnit::MILE : nDiv*=6336; m_nUIUnitDecimalMark++; break; // 1mile = 63360" + // other + case FieldUnit::CUSTOM : break; + case FieldUnit::PERCENT: m_nUIUnitDecimalMark+=2; break; + // TODO: Add code to handle the following if needed (added to remove warning) + case FieldUnit::CHAR : break; + case FieldUnit::LINE : break; + case FieldUnit::PIXEL : break; + case FieldUnit::DEGREE : break; + case FieldUnit::SECOND : break; + case FieldUnit::MILLISECOND : break; + } // switch + + // check if mapping is from metric to inch and adapt + const bool bMapInch(IsInch(m_eObjUnit)); + const bool bUIMetr(IsMetric(m_eUIUnit)); + + if (bMapInch && bUIMetr) + { + m_nUIUnitDecimalMark += 4; + nMul *= 254; + } + + // check if mapping is from inch to metric and adapt + const bool bMapMetr(IsMetric(m_eObjUnit)); + const bool bUIInch(IsInch(m_eUIUnit)); + + if (bMapMetr && bUIInch) + { + m_nUIUnitDecimalMark -= 4; + nDiv *= 254; + } + + // use temporary fraction for reduction (fallback to 32bit here), + // may need to be changed in the future, too + if(1 != nMul || 1 != nDiv) + { + const Fraction aTemp(static_cast< long >(nMul), static_cast< long >(nDiv)); + nMul = aTemp.GetNumerator(); + nDiv = aTemp.GetDenominator(); + } + + // #i89872# take Unit of Measurement into account + if(1 != m_aUIScale.GetDenominator() || 1 != m_aUIScale.GetNumerator()) + { + // divide by UIScale + nMul *= m_aUIScale.GetDenominator(); + nDiv *= m_aUIScale.GetNumerator(); + } + + // shorten trailing zeros for dividend + while(0 == (nMul % 10)) + { + m_nUIUnitDecimalMark--; + nMul /= 10; + } + + // shorten trailing zeros for divisor + while(0 == (nDiv % 10)) + { + m_nUIUnitDecimalMark++; + nDiv /= 10; + } + + // end preparations, set member values + m_aUIUnitFact = Fraction(sal_Int32(nMul), sal_Int32(nDiv)); + m_aUIUnitStr = GetUnitString(m_eUIUnit); +} + +void SdrModel::SetScaleUnit(MapUnit eMap, const Fraction& rFrac) +{ + if (m_eObjUnit!=eMap || m_aObjUnit!=rFrac) { + m_eObjUnit=eMap; + m_aObjUnit=rFrac; + m_pItemPool->SetDefaultMetric(m_eObjUnit); + ImpSetUIUnit(); + ImpSetOutlinerDefaults( m_pDrawOutliner.get() ); + ImpSetOutlinerDefaults( m_pHitTestOutliner.get() ); + ImpReformatAllTextObjects(); + } +} + +void SdrModel::SetScaleUnit(MapUnit eMap) +{ + if (m_eObjUnit!=eMap) { + m_eObjUnit=eMap; + m_pItemPool->SetDefaultMetric(m_eObjUnit); + ImpSetUIUnit(); + ImpSetOutlinerDefaults( m_pDrawOutliner.get() ); + ImpSetOutlinerDefaults( m_pHitTestOutliner.get() ); + ImpReformatAllTextObjects(); + } +} + +void SdrModel::SetScaleFraction(const Fraction& rFrac) +{ + if (m_aObjUnit!=rFrac) { + m_aObjUnit=rFrac; + ImpSetUIUnit(); + ImpSetOutlinerDefaults( m_pDrawOutliner.get() ); + ImpSetOutlinerDefaults( m_pHitTestOutliner.get() ); + ImpReformatAllTextObjects(); + } +} + +void SdrModel::SetUIUnit(FieldUnit eUnit) +{ + if (m_eUIUnit!=eUnit) { + m_eUIUnit=eUnit; + ImpSetUIUnit(); + ImpReformatAllTextObjects(); + } +} + +void SdrModel::SetUIScale(const Fraction& rScale) +{ + if (m_aUIScale!=rScale) { + m_aUIScale=rScale; + ImpSetUIUnit(); + ImpReformatAllTextObjects(); + } +} + +void SdrModel::SetUIUnit(FieldUnit eUnit, const Fraction& rScale) +{ + if (m_eUIUnit!=eUnit || m_aUIScale!=rScale) { + m_eUIUnit=eUnit; + m_aUIScale=rScale; + ImpSetUIUnit(); + ImpReformatAllTextObjects(); + } +} + +OUString SdrModel::GetUnitString(FieldUnit eUnit) +{ + switch(eUnit) + { + default: + case FieldUnit::NONE : + case FieldUnit::CUSTOM : + return OUString(); + case FieldUnit::MM_100TH: + return OUString{"/100mm"}; + case FieldUnit::MM : + return OUString{"mm"}; + case FieldUnit::CM : + return OUString{"cm"}; + case FieldUnit::M : + return OUString{"m"}; + case FieldUnit::KM : + return OUString{"km"}; + case FieldUnit::TWIP : + return OUString{"twip"}; + case FieldUnit::POINT : + return OUString{"pt"}; + case FieldUnit::PICA : + return OUString{"pica"}; + case FieldUnit::INCH : + return OUString{"\""}; + case FieldUnit::FOOT : + return OUString{"ft"}; + case FieldUnit::MILE : + return OUString{"mile(s)"}; + case FieldUnit::PERCENT: + return OUString{"%"}; + } +} + +OUString SdrModel::GetMetricString(long nVal, bool bNoUnitChars, sal_Int32 nNumDigits) const +{ + // #i22167# + // change to double precision usage to not lose decimal places + const bool bNegative(nVal < 0); + SvtSysLocale aSysLoc; + const LocaleDataWrapper& rLoc(aSysLoc.GetLocaleData()); + double fLocalValue(double(nVal) * double(m_aUIUnitFact)); + + if(bNegative) + { + fLocalValue = -fLocalValue; + } + + if( -1 == nNumDigits ) + { + nNumDigits = LocaleDataWrapper::getNumDigits(); + } + + sal_Int32 nDecimalMark(m_nUIUnitDecimalMark); + + if(nDecimalMark > nNumDigits) + { + const sal_Int32 nDiff(nDecimalMark - nNumDigits); + const double fFactor(pow(10.0, static_cast<int>(nDiff))); + + fLocalValue /= fFactor; + nDecimalMark = nNumDigits; + } + else if(nDecimalMark < nNumDigits) + { + const sal_Int32 nDiff(nNumDigits - nDecimalMark); + const double fFactor(pow(10.0, static_cast<int>(nDiff))); + + fLocalValue *= fFactor; + nDecimalMark = nNumDigits; + } + + OUStringBuffer aBuf; + aBuf.append(static_cast<sal_Int32>(fLocalValue + 0.5)); + + if(nDecimalMark < 0) + { + // negative nDecimalMark (decimal point) means: add zeros + sal_Int32 nCount(-nDecimalMark); + + for(sal_Int32 i=0; i<nCount; i++) + aBuf.append('0'); + + nDecimalMark = 0; + } + + // the second condition needs to be <= since inside this loop + // also the leading zero is inserted. + if (nDecimalMark > 0 && aBuf.getLength() <= nDecimalMark) + { + // if necessary, add zeros before the decimal point + sal_Int32 nCount = nDecimalMark - aBuf.getLength(); + + if(nCount >= 0 && LocaleDataWrapper::isNumLeadingZero()) + nCount++; + + for(sal_Int32 i=0; i<nCount; i++) + aBuf.insert(0, '0'); + } + + const sal_Unicode cDec( rLoc.getNumDecimalSep()[0] ); + + // insert the decimal mark character + sal_Int32 nBeforeDecimalMark = aBuf.getLength() - nDecimalMark; + + if(nDecimalMark > 0) + aBuf.insert(nBeforeDecimalMark, cDec); + + if(!LocaleDataWrapper::isNumTrailingZeros()) + { + sal_Int32 aPos=aBuf.getLength()-1; + + // Remove all trailing zeros. + while (aPos>=0 && aBuf[aPos]=='0') + --aPos; + + // Remove decimal if it's the last character. + if (aPos>=0 && aBuf[aPos]==cDec) + --aPos; + + // Adjust aPos to index first char to be truncated, if any + if (++aPos<aBuf.getLength()) + aBuf.truncate(aPos); + } + + // if necessary, add separators before every third digit + if( nBeforeDecimalMark > 3 ) + { + const OUString& aThoSep( rLoc.getNumThousandSep() ); + if ( !aThoSep.isEmpty() ) + { + sal_Unicode cTho( aThoSep[0] ); + sal_Int32 i(nBeforeDecimalMark - 3); + + while(i > 0) + { + aBuf.insert(i, cTho); + i -= 3; + } + } + } + + if (aBuf.isEmpty()) + aBuf.append("0"); + + if(bNegative) + { + aBuf.insert(0, "-"); + } + + if(!bNoUnitChars) + aBuf.append(m_aUIUnitStr); + + return aBuf.makeStringAndClear(); +} + +OUString SdrModel::GetAngleString(long nAngle) +{ + bool bNeg = nAngle < 0; + + if(bNeg) + nAngle = -nAngle; + + OUStringBuffer aBuf; + aBuf.append(static_cast<sal_Int32>(nAngle)); + + SvtSysLocale aSysLoc; + const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData(); + sal_Int32 nCount = 2; + + if(LocaleDataWrapper::isNumLeadingZero()) + nCount++; + + while(aBuf.getLength() < nCount) + aBuf.insert(0, '0'); + + aBuf.insert(aBuf.getLength()-2, rLoc.getNumDecimalSep()[0]); + + if(bNeg) + aBuf.insert(0, '-'); + + aBuf.append(DEGREE_CHAR); + + return aBuf.makeStringAndClear(); +} + +OUString SdrModel::GetPercentString(const Fraction& rVal) +{ + sal_Int32 nMul(rVal.GetNumerator()); + sal_Int32 nDiv(rVal.GetDenominator()); + bool bNeg {false}; + + if (nDiv < 0) + { + bNeg = !bNeg; + nDiv = -nDiv; + } + + if (nMul < 0) + { + bNeg = !bNeg; + nMul = -nMul; + } + + sal_Int32 nPct = ((nMul*100) + nDiv/2)/nDiv; + + if (bNeg) + nPct = -nPct; + + return OUString::number(nPct) + "%"; +} + +void SdrModel::SetChanged(bool bFlg) +{ + mbChanged = bFlg; +} + +void SdrModel::RecalcPageNums(bool bMaster) +{ + if(bMaster) + { + sal_uInt16 nCount=sal_uInt16(maMaPag.size()); + sal_uInt16 i; + for (i=0; i<nCount; i++) { + SdrPage* pPg=maMaPag[i]; + pPg->SetPageNum(i); + } + m_bMPgNumsDirty=false; + } + else + { + sal_uInt16 nCount=sal_uInt16(maPages.size()); + sal_uInt16 i; + for (i=0; i<nCount; i++) { + SdrPage* pPg=maPages[i]; + pPg->SetPageNum(i); + } + m_bPagNumsDirty=false; + } +} + +void SdrModel::InsertPage(SdrPage* pPage, sal_uInt16 nPos) +{ + sal_uInt16 nCount=GetPageCount(); + if (nPos>nCount) nPos=nCount; + maPages.insert(maPages.begin()+nPos,pPage); + PageListChanged(); + pPage->SetInserted(); + pPage->SetPageNum(nPos); + + if (mbMakePageObjectsNamesUnique) + pPage->MakePageObjectsNamesUnique(); + + if (nPos<nCount) m_bPagNumsDirty=true; + SetChanged(); + SdrHint aHint(SdrHintKind::PageOrderChange, pPage); + Broadcast(aHint); +} + +void SdrModel::DeletePage(sal_uInt16 nPgNum) +{ + SdrPage* pPg=RemovePage(nPgNum); + delete pPg; +} + +SdrPage* SdrModel::RemovePage(sal_uInt16 nPgNum) +{ + SdrPage* pPg=maPages[nPgNum]; + maPages.erase(maPages.begin()+nPgNum); + PageListChanged(); + if (pPg!=nullptr) { + pPg->SetInserted(false); + } + m_bPagNumsDirty=true; + SetChanged(); + SdrHint aHint(SdrHintKind::PageOrderChange, pPg); + Broadcast(aHint); + return pPg; +} + +void SdrModel::MovePage(sal_uInt16 nPgNum, sal_uInt16 nNewPos) +{ + SdrPage* pPg=maPages[nPgNum]; + if (pPg!=nullptr) { + maPages.erase(maPages.begin()+nPgNum); // shortcut to avoid two broadcasts + PageListChanged(); + pPg->SetInserted(false); + InsertPage(pPg,nNewPos); + } + else + RemovePage(nPgNum); +} + +void SdrModel::InsertMasterPage(SdrPage* pPage, sal_uInt16 nPos) +{ + sal_uInt16 nCount=GetMasterPageCount(); + if (nPos>nCount) nPos=nCount; + maMaPag.insert(maMaPag.begin()+nPos,pPage); + MasterPageListChanged(); + pPage->SetInserted(); + pPage->SetPageNum(nPos); + + if (nPos<nCount) { + m_bMPgNumsDirty=true; + } + + SetChanged(); + SdrHint aHint(SdrHintKind::PageOrderChange, pPage); + Broadcast(aHint); +} + +void SdrModel::DeleteMasterPage(sal_uInt16 nPgNum) +{ + SdrPage* pPg=RemoveMasterPage(nPgNum); + delete pPg; +} + +SdrPage* SdrModel::RemoveMasterPage(sal_uInt16 nPgNum) +{ + SdrPage* pRetPg=maMaPag[nPgNum]; + maMaPag.erase(maMaPag.begin()+nPgNum); + MasterPageListChanged(); + + if(pRetPg) + { + // Now delete the links from the normal drawing pages to the deleted master page. + sal_uInt16 nPageCnt(GetPageCount()); + + for(sal_uInt16 np(0); np < nPageCnt; np++) + { + GetPage(np)->TRG_ImpMasterPageRemoved(*pRetPg); + } + + pRetPg->SetInserted(false); + } + + m_bMPgNumsDirty=true; + SetChanged(); + SdrHint aHint(SdrHintKind::PageOrderChange, pRetPg); + Broadcast(aHint); + return pRetPg; +} + +void SdrModel::MoveMasterPage(sal_uInt16 nPgNum, sal_uInt16 nNewPos) +{ + SdrPage* pPg=maMaPag[nPgNum]; + maMaPag.erase(maMaPag.begin()+nPgNum); + MasterPageListChanged(); + if (pPg!=nullptr) { + pPg->SetInserted(false); + maMaPag.insert(maMaPag.begin()+nNewPos,pPg); + MasterPageListChanged(); + } + m_bMPgNumsDirty=true; + SetChanged(); + SdrHint aHint(SdrHintKind::PageOrderChange, pPg); + Broadcast(aHint); +} + + +void SdrModel::CopyPages(sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum, + sal_uInt16 nDestPos, + bool bUndo, bool bMoveNoCopy) +{ + if( bUndo && !IsUndoEnabled() ) + bUndo = false; + + if( bUndo ) + BegUndo(SvxResId(STR_UndoMergeModel)); + + sal_uInt16 nPageCnt=GetPageCount(); + sal_uInt16 nMaxPage=nPageCnt; + + if (nMaxPage!=0) + nMaxPage--; + if (nFirstPageNum>nMaxPage) + nFirstPageNum=nMaxPage; + if (nLastPageNum>nMaxPage) + nLastPageNum =nMaxPage; + bool bReverse=nLastPageNum<nFirstPageNum; + if (nDestPos>nPageCnt) + nDestPos=nPageCnt; + + // at first, save the pointers of the affected pages in an array + sal_uInt16 nPageNum=nFirstPageNum; + sal_uInt16 nCopyCnt=((!bReverse)?(nLastPageNum-nFirstPageNum):(nFirstPageNum-nLastPageNum))+1; + std::unique_ptr<SdrPage*[]> pPagePtrs(new SdrPage*[nCopyCnt]); + sal_uInt16 nCopyNum; + for(nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++) + { + pPagePtrs[nCopyNum]=GetPage(nPageNum); + if (bReverse) + nPageNum--; + else + nPageNum++; + } + + // now copy the pages + sal_uInt16 nDestNum=nDestPos; + for (nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++) + { + SdrPage* pPg=pPagePtrs[nCopyNum]; + sal_uInt16 nPageNum2=pPg->GetPageNum(); + if (!bMoveNoCopy) + { + const SdrPage* pPg1=GetPage(nPageNum2); + + // Clone to local model + pPg = pPg1->CloneSdrPage(*this); + + InsertPage(pPg,nDestNum); + if (bUndo) + AddUndo(GetSdrUndoFactory().CreateUndoCopyPage(*pPg)); + nDestNum++; + } + else + { + // TODO: Move is untested! + if (nDestNum>nPageNum2) + nDestNum--; + + if(bUndo) + AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*GetPage(nPageNum2),nPageNum2,nDestNum)); + + pPg=RemovePage(nPageNum2); + InsertPage(pPg,nDestNum); + nDestNum++; + } + + if(bReverse) + nPageNum2--; + else + nPageNum2++; + } + + pPagePtrs.reset(); + if(bUndo) + EndUndo(); +} + +void SdrModel::Merge(SdrModel& rSourceModel, + sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum, + sal_uInt16 nDestPos, + bool bMergeMasterPages, bool bAllMasterPages, + bool bUndo, bool bTreadSourceAsConst) +{ + if (&rSourceModel==this) + { + CopyPages(nFirstPageNum,nLastPageNum,nDestPos,bUndo,!bTreadSourceAsConst); + return; + } + + if( bUndo && !IsUndoEnabled() ) + bUndo = false; + + if (bUndo) + BegUndo(SvxResId(STR_UndoMergeModel)); + + sal_uInt16 nSrcPageCnt=rSourceModel.GetPageCount(); + sal_uInt16 nSrcMasterPageCnt=rSourceModel.GetMasterPageCount(); + sal_uInt16 nDstMasterPageCnt=GetMasterPageCount(); + bool bInsPages=(nFirstPageNum<nSrcPageCnt || nLastPageNum<nSrcPageCnt); + sal_uInt16 nMaxSrcPage=nSrcPageCnt; if (nMaxSrcPage!=0) nMaxSrcPage--; + if (nFirstPageNum>nMaxSrcPage) nFirstPageNum=nMaxSrcPage; + if (nLastPageNum>nMaxSrcPage) nLastPageNum =nMaxSrcPage; + bool bReverse=nLastPageNum<nFirstPageNum; + + std::unique_ptr<sal_uInt16[]> pMasterMap; + std::unique_ptr<bool[]> pMasterNeed; + sal_uInt16 nMasterNeed=0; + if (bMergeMasterPages && nSrcMasterPageCnt!=0) { + // determine which MasterPages from rSrcModel we need + pMasterMap.reset(new sal_uInt16[nSrcMasterPageCnt]); + pMasterNeed.reset(new bool[nSrcMasterPageCnt]); + memset(pMasterMap.get(),0xFF,nSrcMasterPageCnt*sizeof(sal_uInt16)); + if (bAllMasterPages) { + memset(pMasterNeed.get(), true, nSrcMasterPageCnt * sizeof(bool)); + } else { + memset(pMasterNeed.get(), false, nSrcMasterPageCnt * sizeof(bool)); + sal_uInt16 nStart= bReverse ? nLastPageNum : nFirstPageNum; + sal_uInt16 nEnd= bReverse ? nFirstPageNum : nLastPageNum; + for (sal_uInt16 i=nStart; i<=nEnd; i++) { + const SdrPage* pPg=rSourceModel.GetPage(i); + if(pPg->TRG_HasMasterPage()) + { + SdrPage& rMasterPage = pPg->TRG_GetMasterPage(); + sal_uInt16 nMPgNum(rMasterPage.GetPageNum()); + + if(nMPgNum < nSrcMasterPageCnt) + { + pMasterNeed[nMPgNum] = true; + } + } + } + } + // now determine the Mapping of the MasterPages + sal_uInt16 nCurrentMaPagNum=nDstMasterPageCnt; + for (sal_uInt16 i=0; i<nSrcMasterPageCnt; i++) { + if (pMasterNeed[i]) { + pMasterMap[i]=nCurrentMaPagNum; + nCurrentMaPagNum++; + nMasterNeed++; + } + } + } + + // get the MasterPages + if (pMasterMap && pMasterNeed && nMasterNeed!=0) { + for (sal_uInt16 i=nSrcMasterPageCnt; i>0;) { + i--; + if (pMasterNeed[i]) + { + // Always Clone to new model + const SdrPage* pPg1(rSourceModel.GetMasterPage(i)); + SdrPage* pPg(pPg1->CloneSdrPage(*this)); + + if(!bTreadSourceAsConst) + { + // if requested, delete original/modify original model + delete rSourceModel.RemoveMasterPage(i); + } + + if (pPg!=nullptr) { + // Now append all of them to the end of the DstModel. + // Don't use InsertMasterPage(), because everything is + // inconsistent until all are in. + maMaPag.insert(maMaPag.begin()+nDstMasterPageCnt, pPg); + MasterPageListChanged(); + pPg->SetInserted(); + m_bMPgNumsDirty=true; + if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg)); + } else { + OSL_FAIL("SdrModel::Merge(): MasterPage not found in SourceModel."); + } + } + } + } + + // get the drawing pages + if (bInsPages) { + sal_uInt16 nSourcePos=nFirstPageNum; + sal_uInt16 nMergeCount=sal_uInt16(std::abs(static_cast<long>(static_cast<long>(nFirstPageNum)-nLastPageNum))+1); + if (nDestPos>GetPageCount()) nDestPos=GetPageCount(); + while (nMergeCount>0) + { + // Always Clone to new model + const SdrPage* pPg1(rSourceModel.GetPage(nSourcePos)); + SdrPage* pPg(pPg1->CloneSdrPage(*this)); + + if(!bTreadSourceAsConst) + { + // if requested, delete original/modify original model + delete rSourceModel.RemovePage(nSourcePos); + } + + if (pPg!=nullptr) { + InsertPage(pPg,nDestPos); + if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg)); + + if(pPg->TRG_HasMasterPage()) + { + SdrPage& rMasterPage = pPg->TRG_GetMasterPage(); + sal_uInt16 nMaPgNum(rMasterPage.GetPageNum()); + + if (bMergeMasterPages) + { + sal_uInt16 nNewNum(0xFFFF); + + if(pMasterMap) + { + nNewNum = pMasterMap[nMaPgNum]; + } + + if(nNewNum != 0xFFFF) + { + // tdf#90357 here pPg and the to-be-set new masterpage are parts of the new model + // already, but the currently set masterpage is part of the old model. Remove master + // page from already cloned page to prevent creating wrong undo action that can + // eventually crash the app. + // Do *not* remove it directly after cloning - the old masterpage is still needed + // later to find the new to-be-set masterpage. + pPg->TRG_ClearMasterPage(); + + if(bUndo) + { + AddUndo(GetSdrUndoFactory().CreateUndoPageChangeMasterPage(*pPg)); + } + + pPg->TRG_SetMasterPage(*GetMasterPage(nNewNum)); + } + DBG_ASSERT(nNewNum!=0xFFFF,"SdrModel::Merge(): Something is crooked with the mapping of the MasterPages."); + } else { + if (nMaPgNum>=nDstMasterPageCnt) { + // This is outside of the original area of the MasterPage of the DstModel. + pPg->TRG_ClearMasterPage(); + } + } + } + + } else { + OSL_FAIL("SdrModel::Merge(): Drawing page not found in SourceModel."); + } + nDestPos++; + if (bReverse) nSourcePos--; + else if (bTreadSourceAsConst) nSourcePos++; + nMergeCount--; + } + } + + pMasterMap.reset(); + pMasterNeed.reset(); + + m_bMPgNumsDirty=true; + m_bPagNumsDirty=true; + + SetChanged(); + // TODO: Missing: merging and mapping of layers + // at the objects as well as at the MasterPageDescriptors + if (bUndo) EndUndo(); +} + +void SdrModel::SetStarDrawPreviewMode(bool bPreview) +{ + if (!bPreview && m_bStarDrawPreviewMode && GetPageCount()) + { + // Resetting is not allowed, because the Model might not be loaded completely + SAL_WARN("svx", "SdrModel::SetStarDrawPreviewMode(): Resetting not allowed, because Model might not be complete."); + } + else + { + m_bStarDrawPreviewMode = bPreview; + } +} + +uno::Reference< uno::XInterface > const & SdrModel::getUnoModel() +{ + if( !mxUnoModel.is() ) + mxUnoModel = createUnoModel(); + + return mxUnoModel; +} + +void SdrModel::setUnoModel( const css::uno::Reference< css::uno::XInterface >& xModel ) +{ + mxUnoModel = xModel; +} + +void SdrModel::adaptSizeAndBorderForAllPages( + const Size& /*rNewSize*/, + long /*nLeft*/, + long /*nRight*/, + long /*nUpper*/, + long /*nLower*/) +{ + // base implementation does currently nothing. It may be added if needed, + // but we are on SdrModel level here, thus probably have not enough information + // to do this for higher-level (derived) Models (e.g. Draw/Impress) +} + +uno::Reference< uno::XInterface > SdrModel::createUnoModel() +{ + OSL_FAIL( "SdrModel::createUnoModel() - base implementation should not be called!" ); + css::uno::Reference< css::uno::XInterface > xInt; + return xInt; +} + +void SdrModel::setLock( bool bLock ) +{ + if( mbModelLocked != bLock ) + { + // #i120437# need to set first, else ImpReformatAllEdgeObjects will do nothing + mbModelLocked = bLock; + + if( !bLock ) + { + ImpReformatAllEdgeObjects(); + } + } +} + + +void SdrModel::MigrateItemSet( const SfxItemSet* pSourceSet, SfxItemSet* pDestSet, SdrModel* pNewModelel ) +{ + assert(pNewModelel != nullptr); + if( pSourceSet && pDestSet && (pSourceSet != pDestSet ) ) + { + SfxWhichIter aWhichIter(*pSourceSet); + sal_uInt16 nWhich(aWhichIter.FirstWhich()); + const SfxPoolItem *pPoolItem; + + while(nWhich) + { + if(SfxItemState::SET == pSourceSet->GetItemState(nWhich, false, &pPoolItem)) + { + std::unique_ptr<SfxPoolItem> pResultItem; + + switch( nWhich ) + { + case XATTR_FILLBITMAP: + pResultItem = static_cast<const XFillBitmapItem*>(pPoolItem)->checkForUniqueItem( pNewModelel ); + break; + case XATTR_LINEDASH: + pResultItem = static_cast<const XLineDashItem*>(pPoolItem)->checkForUniqueItem( pNewModelel ); + break; + case XATTR_LINESTART: + pResultItem = static_cast<const XLineStartItem*>(pPoolItem)->checkForUniqueItem( pNewModelel ); + break; + case XATTR_LINEEND: + pResultItem = static_cast<const XLineEndItem*>(pPoolItem)->checkForUniqueItem( pNewModelel ); + break; + case XATTR_FILLGRADIENT: + pResultItem = static_cast<const XFillGradientItem*>(pPoolItem)->checkForUniqueItem( pNewModelel ); + break; + case XATTR_FILLFLOATTRANSPARENCE: + // allow all kinds of XFillFloatTransparenceItem to be set + pResultItem = static_cast<const XFillFloatTransparenceItem*>(pPoolItem)->checkForUniqueItem( pNewModelel ); + break; + case XATTR_FILLHATCH: + pResultItem = static_cast<const XFillHatchItem*>(pPoolItem)->checkForUniqueItem( pNewModelel ); + break; + } + + // set item + if( pResultItem ) + { + pDestSet->Put(*pResultItem); + pResultItem.reset(); + } + else + pDestSet->Put(*pPoolItem); + } + nWhich = aWhichIter.NextWhich(); + } + } +} + + +void SdrModel::SetForbiddenCharsTable(const std::shared_ptr<SvxForbiddenCharactersTable>& xForbiddenChars) +{ + mpForbiddenCharactersTable = xForbiddenChars; + + ImpSetOutlinerDefaults( m_pDrawOutliner.get() ); + ImpSetOutlinerDefaults( m_pHitTestOutliner.get() ); +} + + +void SdrModel::SetCharCompressType( CharCompressType nType ) +{ + if( nType != mnCharCompressType ) + { + mnCharCompressType = nType; + ImpSetOutlinerDefaults( m_pDrawOutliner.get() ); + ImpSetOutlinerDefaults( m_pHitTestOutliner.get() ); + } +} + +void SdrModel::SetKernAsianPunctuation( bool bEnabled ) +{ + if( mbKernAsianPunctuation != bEnabled ) + { + mbKernAsianPunctuation = bEnabled; + ImpSetOutlinerDefaults( m_pDrawOutliner.get() ); + ImpSetOutlinerDefaults( m_pHitTestOutliner.get() ); + } +} + +void SdrModel::SetAddExtLeading( bool bEnabled ) +{ + if( mbAddExtLeading != bEnabled ) + { + mbAddExtLeading = bEnabled; + ImpSetOutlinerDefaults( m_pDrawOutliner.get() ); + ImpSetOutlinerDefaults( m_pHitTestOutliner.get() ); + } +} + +void SdrModel::SetAnchoredTextOverflowLegacy(bool bEnabled) +{ + mpImpl->mbAnchoredTextOverflowLegacy = bEnabled; +} + +bool SdrModel::IsAnchoredTextOverflowLegacy() const +{ + return mpImpl->mbAnchoredTextOverflowLegacy; +} + +void SdrModel::ReformatAllTextObjects() +{ + ImpReformatAllTextObjects(); +} + +std::unique_ptr<SdrOutliner> SdrModel::createOutliner( OutlinerMode nOutlinerMode ) +{ + if( !mpOutlinerCache ) + mpOutlinerCache.reset(new SdrOutlinerCache(this)); + + return mpOutlinerCache->createOutliner( nOutlinerMode ); +} + +std::vector<SdrOutliner*> SdrModel::GetActiveOutliners() const +{ + std::vector< SdrOutliner* > aRet(mpOutlinerCache ? mpOutlinerCache->GetActiveOutliners() : std::vector< SdrOutliner* >()); + aRet.push_back(m_pDrawOutliner.get()); + aRet.push_back(m_pHitTestOutliner.get()); + + return aRet; +} + +void SdrModel::disposeOutliner( std::unique_ptr<SdrOutliner> pOutliner ) +{ + if( mpOutlinerCache ) + mpOutlinerCache->disposeOutliner( std::move(pOutliner) ); +} + +SvxNumType SdrModel::GetPageNumType() const +{ + return SVX_NUM_ARABIC; +} + +void SdrModel::ReadUserDataSequenceValue(const css::beans::PropertyValue* pValue) +{ + bool bBool = false; + if (pValue->Name == "AnchoredTextOverflowLegacy") + { + if (pValue->Value >>= bBool) + { + mpImpl->mbAnchoredTextOverflowLegacy = bBool; + } + } +} + +template <typename T> +static void addPair(std::vector< std::pair< OUString, Any > >& aUserData, const OUString& name, const T val) +{ + aUserData.push_back(std::pair< OUString, Any >(name, css::uno::makeAny(val))); +} + +void SdrModel::WriteUserDataSequence(css::uno::Sequence < css::beans::PropertyValue >& rValues) +{ + std::vector< std::pair< OUString, Any > > aUserData; + addPair(aUserData, "AnchoredTextOverflowLegacy", IsAnchoredTextOverflowLegacy()); + + const sal_Int32 nOldLength = rValues.getLength(); + rValues.realloc(nOldLength + aUserData.size()); + + css::beans::PropertyValue* pValue = &(rValues.getArray()[nOldLength]); + + for (const auto &aIter : aUserData) + { + pValue->Name = aIter.first; + pValue->Value = aIter.second; + ++pValue; + } +} + +const SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum) const +{ + DBG_ASSERT(nPgNum < maPages.size(), "SdrModel::GetPage: Access out of range (!)"); + return nPgNum < maPages.size() ? maPages[nPgNum] : nullptr; +} + +SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum) +{ + DBG_ASSERT(nPgNum < maPages.size(), "SdrModel::GetPage: Access out of range (!)"); + return nPgNum < maPages.size() ? maPages[nPgNum] : nullptr; +} + +sal_uInt16 SdrModel::GetPageCount() const +{ + return sal_uInt16(maPages.size()); +} + +void SdrModel::PageListChanged() +{ +} + +TextChain *SdrModel::GetTextChain() const +{ + return m_pTextChain.get(); +} + +const SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum) const +{ + DBG_ASSERT(nPgNum < maMaPag.size(), "SdrModel::GetMasterPage: Access out of range (!)"); + return maMaPag[nPgNum]; +} + +SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum) +{ + DBG_ASSERT(nPgNum < maMaPag.size(), "SdrModel::GetMasterPage: Access out of range (!)"); + return maMaPag[nPgNum]; +} + +sal_uInt16 SdrModel::GetMasterPageCount() const +{ + return sal_uInt16(maMaPag.size()); +} + +void SdrModel::MasterPageListChanged() +{ +} + +void SdrModel::SetSdrUndoManager( SfxUndoManager* pUndoManager ) +{ + mpImpl->mpUndoManager = pUndoManager; +} + +SfxUndoManager* SdrModel::GetSdrUndoManager() const +{ + return mpImpl->mpUndoManager; +} + +SdrUndoFactory& SdrModel::GetSdrUndoFactory() const +{ + if( !mpImpl->mpUndoFactory ) + mpImpl->mpUndoFactory = new SdrUndoFactory; + return *mpImpl->mpUndoFactory; +} + +void SdrModel::SetSdrUndoFactory( SdrUndoFactory* pUndoFactory ) +{ + if( pUndoFactory && (pUndoFactory != mpImpl->mpUndoFactory) ) + { + delete mpImpl->mpUndoFactory; + mpImpl->mpUndoFactory = pUndoFactory; + } +} + +void SdrModel::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + xmlTextWriterStartElement(pWriter, BAD_CAST("SdrModel")); + xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + + sal_uInt16 nPageCount = GetPageCount(); + for (sal_uInt16 i = 0; i < nPageCount; ++i) + { + if (const SdrPage* pPage = GetPage(i)) + pPage->dumpAsXml(pWriter); + } + + xmlTextWriterEndElement(pWriter); +} + +namespace +{ + class theSdrModelUnoTunnelImplementationId : public rtl::Static< UnoTunnelIdInit, theSdrModelUnoTunnelImplementationId > {}; +} + +const css::uno::Sequence< sal_Int8 >& SdrModel::getUnoTunnelId() +{ + return theSdrModelUnoTunnelImplementationId::get().getSeq(); +} + + +SdrHint::SdrHint(SdrHintKind eNewHint) +: SfxHint(SfxHintId::ThisIsAnSdrHint), + meHint(eNewHint), + mpObj(nullptr), + mpPage(nullptr) +{ +} + +SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj) +: SfxHint(SfxHintId::ThisIsAnSdrHint), + meHint(eNewHint), + mpObj(&rNewObj), + mpPage(rNewObj.getSdrPageFromSdrObject()) +{ +} + +SdrHint::SdrHint(SdrHintKind eNewHint, const SdrPage* pPage) +: SfxHint(SfxHintId::ThisIsAnSdrHint), + meHint(eNewHint), + mpObj(nullptr), + mpPage(pPage) +{ +} + +SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj, const SdrPage* pPage) +: SfxHint(SfxHintId::ThisIsAnSdrHint), + meHint(eNewHint), + mpObj(&rNewObj), + mpPage(pPage) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |