diff options
Diffstat (limited to 'svx/source/svdraw/svdpage.cxx')
-rw-r--r-- | svx/source/svdraw/svdpage.cxx | 1895 |
1 files changed, 1895 insertions, 0 deletions
diff --git a/svx/source/svdraw/svdpage.cxx b/svx/source/svdraw/svdpage.cxx new file mode 100644 index 000000000..b7aa8777e --- /dev/null +++ b/svx/source/svdraw/svdpage.cxx @@ -0,0 +1,1895 @@ +/* -*- 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 <memory> +#include <cassert> +#include <set> +#include <unordered_set> + +#include <svx/svdpage.hxx> + +#include <o3tl/safeint.hxx> +#include <string.h> + +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> + +#include <svtools/colorcfg.hxx> +#include <svx/svdetc.hxx> +#include <svx/svdobj.hxx> +#include <svx/svdogrp.hxx> +#include <svx/svdoedge.hxx> +#include <svx/svdoole2.hxx> +#include <svx/svditer.hxx> +#include <svx/svdmodel.hxx> +#include <svx/svdlayer.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdundo.hxx> +#include <svx/xfillit0.hxx> +#include <svx/fmdpage.hxx> + +#include <sdr/contact/viewcontactofsdrpage.hxx> +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <svx/sdr/contact/displayinfo.hxx> +#include <algorithm> +#include <svl/hint.hxx> +#include <rtl/strbuf.hxx> +#include <libxml/xmlwriter.h> + +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +using namespace ::com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +SdrObjList::SdrObjList() +: mbObjOrdNumsDirty(false), + mbRectsDirty(false), + mbIsNavigationOrderDirty(false) +{ +} + +void SdrObjList::impClearSdrObjList(bool bBroadcast) +{ + SdrModel* pSdrModelFromRemovedSdrObject(nullptr); + + while(!maList.empty()) + { + // remove last object from list + SdrObject* pObj(maList.back()); + RemoveObjectFromContainer(maList.size()-1); + + // flushViewObjectContacts() is done since SdrObject::Free is not guaranteed + // to delete the object and thus refresh visualisations + pObj->GetViewContact().flushViewObjectContacts(); + + if(bBroadcast) + { + if(nullptr == pSdrModelFromRemovedSdrObject) + { + pSdrModelFromRemovedSdrObject = &pObj->getSdrModelFromSdrObject(); + } + + // sent remove hint (after removal, see RemoveObject()) + // TTTT SdrPage not needed, can be accessed using SdrObject + SdrHint aHint(SdrHintKind::ObjectRemoved, *pObj, getSdrPageFromSdrObjList()); + pObj->getSdrModelFromSdrObject().Broadcast(aHint); + } + + // delete the object itself + SdrObject::Free( pObj ); + } + + if(bBroadcast && nullptr != pSdrModelFromRemovedSdrObject) + { + pSdrModelFromRemovedSdrObject->SetChanged(); + } +} + +void SdrObjList::ClearSdrObjList() +{ + // clear SdrObjects with broadcasting + impClearSdrObjList(true); +} + +SdrObjList::~SdrObjList() +{ + // clear SdrObjects without broadcasting + impClearSdrObjList(false); +} + +SdrPage* SdrObjList::getSdrPageFromSdrObjList() const +{ + // default is no page and returns zero + return nullptr; +} + +SdrObject* SdrObjList::getSdrObjectFromSdrObjList() const +{ + // default is no SdrObject (SdrObjGroup) + return nullptr; +} + +void SdrObjList::CopyObjects(const SdrObjList& rSrcList) +{ + // clear SdrObjects with broadcasting + ClearSdrObjList(); + + mbObjOrdNumsDirty = false; + mbRectsDirty = false; + size_t nCloneErrCnt(0); + const size_t nCount(rSrcList.GetObjCount()); + + if(nullptr == getSdrObjectFromSdrObjList() && nullptr == getSdrPageFromSdrObjList()) + { + OSL_ENSURE(false, "SdrObjList which is not part of SdrPage or SdrObject (!)"); + return; + } + + SdrModel& rTargetSdrModel(nullptr == getSdrObjectFromSdrObjList() + ? getSdrPageFromSdrObjList()->getSdrModelFromSdrPage() + : getSdrObjectFromSdrObjList()->getSdrModelFromSdrObject()); + + for (size_t no(0); no < nCount; ++no) + { + SdrObject* pSO(rSrcList.GetObj(no)); + SdrObject* pDO(pSO->CloneSdrObject(rTargetSdrModel)); + + if(nullptr != pDO) + { + NbcInsertObject(pDO, SAL_MAX_SIZE); + } + else + { + nCloneErrCnt++; + } + } + + // and now for the Connectors + // The new objects would be shown in the rSrcList + // and then the object connections are made. + // Similar implementation are setup as the following: + // void SdrObjList::CopyObjects(const SdrObjList& rSrcList) + // SdrModel* SdrExchangeView::CreateMarkedObjModel() const + // BOOL SdrExchangeView::Paste(const SdrModel& rMod,...) + // void SdrEditView::CopyMarked() + if (nCloneErrCnt==0) { + for (size_t no=0; no<nCount; ++no) { + const SdrObject* pSrcOb=rSrcList.GetObj(no); + const SdrEdgeObj* pSrcEdge=dynamic_cast<const SdrEdgeObj*>( pSrcOb ); + if (pSrcEdge!=nullptr) { + SdrObject* pSrcNode1=pSrcEdge->GetConnectedNode(true); + SdrObject* pSrcNode2=pSrcEdge->GetConnectedNode(false); + if (pSrcNode1!=nullptr && pSrcNode1->getParentSdrObjListFromSdrObject()!=pSrcEdge->getParentSdrObjListFromSdrObject()) pSrcNode1=nullptr; // can't do this + if (pSrcNode2!=nullptr && pSrcNode2->getParentSdrObjListFromSdrObject()!=pSrcEdge->getParentSdrObjListFromSdrObject()) pSrcNode2=nullptr; // across all lists (yet) + if (pSrcNode1!=nullptr || pSrcNode2!=nullptr) { + SdrObject* pEdgeObjTmp=GetObj(no); + SdrEdgeObj* pDstEdge=dynamic_cast<SdrEdgeObj*>( pEdgeObjTmp ); + if (pDstEdge!=nullptr) { + if (pSrcNode1!=nullptr) { + sal_uInt32 nDstNode1=pSrcNode1->GetOrdNum(); + SdrObject* pDstNode1=GetObj(nDstNode1); + if (pDstNode1!=nullptr) { // else we get an error! + pDstEdge->ConnectToNode(true,pDstNode1); + } else { + OSL_FAIL("SdrObjList::operator=(): pDstNode1==NULL!"); + } + } + if (pSrcNode2!=nullptr) { + sal_uInt32 nDstNode2=pSrcNode2->GetOrdNum(); + SdrObject* pDstNode2=GetObj(nDstNode2); + if (pDstNode2!=nullptr) { // else the node was probably not selected + pDstEdge->ConnectToNode(false,pDstNode2); + } else { + OSL_FAIL("SdrObjList::operator=(): pDstNode2==NULL!"); + } + } + } else { + OSL_FAIL("SdrObjList::operator=(): pDstEdge==NULL!"); + } + } + } + } + } else { +#ifdef DBG_UTIL + OStringBuffer aStr("SdrObjList::operator=(): Error when cloning "); + + if(nCloneErrCnt == 1) + { + aStr.append("a drawing object."); + } + else + { + aStr.append(static_cast<sal_Int32>(nCloneErrCnt)); + aStr.append(" drawing objects."); + } + + aStr.append(" Not copying connectors."); + + OSL_FAIL(aStr.getStr()); +#endif + } +} + +void SdrObjList::RecalcObjOrdNums() +{ + const size_t nCount = GetObjCount(); + for (size_t no=0; no<nCount; ++no) { + SdrObject* pObj=GetObj(no); + pObj->SetOrdNum(no); + } + mbObjOrdNumsDirty=false; +} + +void SdrObjList::RecalcRects() +{ + maSdrObjListOutRect=tools::Rectangle(); + maSdrObjListSnapRect=maSdrObjListOutRect; + const size_t nCount = GetObjCount(); + for (size_t i=0; i<nCount; ++i) { + SdrObject* pObj=GetObj(i); + if (i==0) { + maSdrObjListOutRect=pObj->GetCurrentBoundRect(); + maSdrObjListSnapRect=pObj->GetSnapRect(); + } else { + maSdrObjListOutRect.Union(pObj->GetCurrentBoundRect()); + maSdrObjListSnapRect.Union(pObj->GetSnapRect()); + } + } +} + +void SdrObjList::SetSdrObjListRectsDirty() +{ + mbRectsDirty=true; + SdrObject* pParentSdrObject(getSdrObjectFromSdrObjList()); + + if(nullptr != pParentSdrObject) + { + pParentSdrObject->SetBoundAndSnapRectsDirty(); + } +} + +void SdrObjList::impChildInserted(SdrObject const & rChild) +{ + sdr::contact::ViewContact* pParent = rChild.GetViewContact().GetParentContact(); + + if(pParent) + { + pParent->ActionChildInserted(rChild.GetViewContact()); + } +} + +void SdrObjList::NbcInsertObject(SdrObject* pObj, size_t nPos) +{ + DBG_ASSERT(pObj!=nullptr,"SdrObjList::NbcInsertObject(NULL)"); + if (pObj==nullptr) + return; + + DBG_ASSERT(!pObj->IsInserted(),"The object already has the status Inserted."); + const size_t nCount = GetObjCount(); + if (nPos>nCount) nPos=nCount; + InsertObjectIntoContainer(*pObj,nPos); + + if (nPos<nCount) mbObjOrdNumsDirty=true; + pObj->SetOrdNum(nPos); + pObj->setParentOfSdrObject(this); + + // Inform the parent about change to allow invalidations at + // evtl. existing parent visualisations + impChildInserted(*pObj); + + if (!mbRectsDirty) { + mbRectsDirty = true; + } + pObj->InsertedStateChange(); // calls the UserCall (among others) +} + +void SdrObjList::InsertObjectThenMakeNameUnique(SdrObject* pObj) +{ + std::unordered_set<rtl::OUString> aNameSet; + InsertObjectThenMakeNameUnique(pObj, aNameSet); +} + +void SdrObjList::InsertObjectThenMakeNameUnique(SdrObject* pObj, std::unordered_set<OUString>& rNameSet, size_t nPos) +{ + InsertObject(pObj, nPos); + if (pObj->GetName().isEmpty()) + return; + + pObj->MakeNameUnique(rNameSet); + SdrObjList* pSdrObjList = pObj->GetSubList(); // group + if (pSdrObjList) + { + SdrObject* pListObj; + SdrObjListIter aIter(pSdrObjList, SdrIterMode::DeepWithGroups); + while (aIter.IsMore()) + { + pListObj = aIter.Next(); + pListObj->MakeNameUnique(rNameSet); + } + } +} + +void SdrObjList::InsertObject(SdrObject* pObj, size_t nPos) +{ + DBG_ASSERT(pObj!=nullptr,"SdrObjList::InsertObject(NULL)"); + + if(!pObj) + return; + + // if anchor is used, reset it before grouping + if(getSdrObjectFromSdrObjList()) + { + const Point& rAnchorPos = pObj->GetAnchorPos(); + if(rAnchorPos.X() || rAnchorPos.Y()) + pObj->NbcSetAnchorPos(Point()); + } + + // do insert to new group + NbcInsertObject(pObj, nPos); + + // In case the object is inserted into a group and doesn't overlap with + // the group's other members, it needs an own repaint. + SdrObject* pParentSdrObject(getSdrObjectFromSdrObjList()); + + if(pParentSdrObject) + { + // only repaint here + pParentSdrObject->ActionChanged(); + } + + // TODO: We need a different broadcast here! + // Repaint from object number ... (heads-up: GroupObj) + if(pObj->getSdrPageFromSdrObject() && !pObj->getSdrModelFromSdrObject().isLocked()) + { + SdrHint aHint(SdrHintKind::ObjectInserted, *pObj); + pObj->getSdrModelFromSdrObject().Broadcast(aHint); + } + + pObj->getSdrModelFromSdrObject().SetChanged(); +} + +SdrObject* SdrObjList::NbcRemoveObject(size_t nObjNum) +{ + if (nObjNum >= maList.size()) + { + OSL_ASSERT(nObjNum<maList.size()); + return nullptr; + } + + const size_t nCount = GetObjCount(); + SdrObject* pObj=maList[nObjNum]; + RemoveObjectFromContainer(nObjNum); + + DBG_ASSERT(pObj!=nullptr,"Could not find object to remove."); + if (pObj!=nullptr) + { + // flushViewObjectContacts() clears the VOC's and those invalidate + pObj->GetViewContact().flushViewObjectContacts(); + + DBG_ASSERT(pObj->IsInserted(),"The object does not have the status Inserted."); + + // tdf#121022 Do first remove from SdrObjList - InsertedStateChange + // relies now on IsInserted which uses getParentSdrObjListFromSdrObject + pObj->setParentOfSdrObject(nullptr); + + // calls UserCall, among other + pObj->InsertedStateChange(); + + if (!mbObjOrdNumsDirty) + { + // optimizing for the case that the last object has to be removed + if (nObjNum+1!=nCount) { + mbObjOrdNumsDirty=true; + } + } + SetSdrObjListRectsDirty(); + } + return pObj; +} + +SdrObject* SdrObjList::RemoveObject(size_t nObjNum) +{ + if (nObjNum >= maList.size()) + { + OSL_ASSERT(nObjNum<maList.size()); + return nullptr; + } + + const size_t nCount = GetObjCount(); + SdrObject* pObj=maList[nObjNum]; + RemoveObjectFromContainer(nObjNum); + + DBG_ASSERT(pObj!=nullptr,"Object to remove not found."); + if(pObj) + { + // flushViewObjectContacts() clears the VOC's and those invalidate + pObj->GetViewContact().flushViewObjectContacts(); + DBG_ASSERT(pObj->IsInserted(),"The object does not have the status Inserted."); + + // TODO: We need a different broadcast here. + if (pObj->getSdrPageFromSdrObject()!=nullptr) + { + SdrHint aHint(SdrHintKind::ObjectRemoved, *pObj); + pObj->getSdrModelFromSdrObject().Broadcast(aHint); + } + + pObj->getSdrModelFromSdrObject().SetChanged(); + + // tdf#121022 Do first remove from SdrObjList - InsertedStateChange + // relies now on IsInserted which uses getParentSdrObjListFromSdrObject + pObj->setParentOfSdrObject(nullptr); + + // calls, among other things, the UserCall + pObj->InsertedStateChange(); + + if (!mbObjOrdNumsDirty) + { + // optimization for the case that the last object is removed + if (nObjNum+1!=nCount) { + mbObjOrdNumsDirty=true; + } + } + + SetSdrObjListRectsDirty(); + SdrObject* pParentSdrObject(getSdrObjectFromSdrObjList()); + + if(pParentSdrObject && !GetObjCount()) + { + // empty group created; it needs to be repainted since it's + // visualization changes + pParentSdrObject->ActionChanged(); + } + } + return pObj; +} + +SdrObject* SdrObjList::ReplaceObject(SdrObject* pNewObj, size_t nObjNum) +{ + if (nObjNum >= maList.size()) + { + OSL_ASSERT(nObjNum<maList.size()); + return nullptr; + } + if (pNewObj == nullptr) + { + OSL_ASSERT(pNewObj!=nullptr); + return nullptr; + } + + SdrObject* pObj=maList[nObjNum]; + DBG_ASSERT(pObj!=nullptr,"SdrObjList::ReplaceObject: Could not find object to remove."); + if (pObj!=nullptr) { + DBG_ASSERT(pObj->IsInserted(),"SdrObjList::ReplaceObject: the object does not have status Inserted."); + + // TODO: We need a different broadcast here. + if (pObj->getSdrPageFromSdrObject()!=nullptr) + { + SdrHint aHint(SdrHintKind::ObjectRemoved, *pObj); + pObj->getSdrModelFromSdrObject().Broadcast(aHint); + } + + // Change parent and replace in SdrObjList + pObj->setParentOfSdrObject(nullptr); + ReplaceObjectInContainer(*pNewObj,nObjNum); + + // tdf#121022 InsertedStateChange uses the parent + // to detect if pObj is inserted or not, so have to call + // it *after* changing these settings, else an obviously wrong + // 'SdrUserCallType::Inserted' would be sent + pObj->InsertedStateChange(); + + // flushViewObjectContacts() clears the VOC's and those + // trigger the evtl. needed invalidate(s) + pObj->GetViewContact().flushViewObjectContacts(); + + // Setup data at new SdrObject - it already *is* inserted to + // the SdrObjList due to 'ReplaceObjectInContainer' above + pNewObj->SetOrdNum(nObjNum); + pNewObj->setParentOfSdrObject(this); + + // Inform the parent about change to allow invalidations at + // evtl. existing parent visualisations, but also react on + // newly inserted SdrObjects (as e.g. GraphCtrlUserCall does) + impChildInserted(*pNewObj); + + pNewObj->InsertedStateChange(); + + // TODO: We need a different broadcast here. + if (pNewObj->getSdrPageFromSdrObject()!=nullptr) { + SdrHint aHint(SdrHintKind::ObjectInserted, *pNewObj); + pNewObj->getSdrModelFromSdrObject().Broadcast(aHint); + } + + pNewObj->getSdrModelFromSdrObject().SetChanged(); + + SetSdrObjListRectsDirty(); + } + return pObj; +} + +SdrObject* SdrObjList::SetObjectOrdNum(size_t nOldObjNum, size_t nNewObjNum) +{ + if (nOldObjNum >= maList.size() || nNewObjNum >= maList.size()) + { + OSL_ASSERT(nOldObjNum<maList.size()); + OSL_ASSERT(nNewObjNum<maList.size()); + return nullptr; + } + + SdrObject* pObj=maList[nOldObjNum]; + if (nOldObjNum==nNewObjNum) return pObj; + DBG_ASSERT(pObj!=nullptr,"SdrObjList::SetObjectOrdNum: Object not found."); + if (pObj!=nullptr) { + DBG_ASSERT(pObj->IsInserted(),"SdrObjList::SetObjectOrdNum: the object does not have status Inserted."); + RemoveObjectFromContainer(nOldObjNum); + InsertObjectIntoContainer(*pObj,nNewObjNum); + + // No need to delete visualisation data since same object + // gets inserted again. Also a single ActionChanged is enough + pObj->ActionChanged(); + + pObj->SetOrdNum(nNewObjNum); + mbObjOrdNumsDirty=true; + + // TODO: We need a different broadcast here. + if (pObj->getSdrPageFromSdrObject()!=nullptr) + pObj->getSdrModelFromSdrObject().Broadcast(SdrHint(SdrHintKind::ObjectChange, *pObj)); + pObj->getSdrModelFromSdrObject().SetChanged(); + } + return pObj; +} + +void SdrObjList::SetExistingObjectOrdNum(SdrObject* pObj, size_t nNewObjNum) +{ + assert(std::find(maList.begin(), maList.end(), pObj) != maList.end() && "This method requires that the child object already be inserted"); + assert(pObj->IsInserted() && "SdrObjList::SetObjectOrdNum: the object does not have status Inserted."); + + // I am deliberately bypassing getOrdNum() because I don't want to unnecessarily + // trigger RecalcObjOrdNums() + const sal_uInt32 nOldOrdNum = pObj->m_nOrdNum; + if (!mbObjOrdNumsDirty && nOldOrdNum == nNewObjNum) + return; + + // Update the navigation positions. + if (HasObjectNavigationOrder()) + { + tools::WeakReference<SdrObject> aReference (pObj); + auto iObject = ::std::find( + mxNavigationOrder->begin(), + mxNavigationOrder->end(), + aReference); + mxNavigationOrder->erase(iObject); + mbIsNavigationOrderDirty = true; + // The new object does not have a user defined position so append it + // to the list. + pObj->SetNavigationPosition(mxNavigationOrder->size()); + mxNavigationOrder->push_back(pObj); + } + if (nOldOrdNum < maList.size() && maList[nOldOrdNum] == pObj) + maList.erase(maList.begin()+nOldOrdNum); + else + { + auto it = std::find(maList.begin(), maList.end(), pObj); + maList.erase(it); + } + // Insert object into object list. Because the insert() method requires + // a valid iterator as insertion position, we have to use push_back() to + // insert at the end of the list. + if (nNewObjNum >= maList.size()) + maList.push_back(pObj); + else + maList.insert(maList.begin()+nNewObjNum, pObj); + + mbObjOrdNumsDirty=true; + + // No need to delete visualisation data since same object + // gets inserted again. Also a single ActionChanged is enough + pObj->ActionChanged(); + + pObj->SetOrdNum(nNewObjNum); + mbObjOrdNumsDirty=true; + + // TODO: We need a different broadcast here. + if (pObj->getSdrPageFromSdrObject()!=nullptr) + pObj->getSdrModelFromSdrObject().Broadcast(SdrHint(SdrHintKind::ObjectChange, *pObj)); + pObj->getSdrModelFromSdrObject().SetChanged(); +} + +void SdrObjList::sort( std::vector<sal_Int32>& sortOrder) +{ + // no negative indexes and indexes larger than maList size are allowed + auto it = std::find_if( sortOrder.begin(), sortOrder.end(), [this](const sal_Int32& rIt) + { return ( rIt < 0 || o3tl::make_unsigned(rIt) >= maList.size() ); } ); + if ( it != sortOrder.end()) + throw css::lang::IllegalArgumentException("negative index of shape", nullptr, 1); + + // no duplicates + std::vector<bool> aNoDuplicates(sortOrder.size(), false); + for (size_t i = 0; i < sortOrder.size(); ++i ) + { + size_t idx = static_cast<size_t>( sortOrder[i] ); + + if ( aNoDuplicates[idx] ) + throw css::lang::IllegalArgumentException("duplicate index of shape", nullptr, 2); + + aNoDuplicates[idx] = true; + } + + // example sortOrder [2 0 1] + // example maList [T T S T T] ( T T = shape with textbox, S = just a shape ) + // (shapes at positions 0 and 2 have a textbox) + + std::deque<SdrObject*> aNewList(maList.size()); + std::set<sal_Int32> aShapesWithTextbox; + std::vector<sal_Int32> aIncrements; + std::vector<sal_Int32> aDuplicates; + + if ( maList.size() > 1) + { + for (size_t i = 1; i< maList.size(); ++i) + { + // if this shape is a textbox, then look at its left neighbour + // (shape this textbox is in) + // and insert the number of textboxes to the left of it + if (maList[i]->IsTextBox()) + aShapesWithTextbox.insert( i - 1 - aShapesWithTextbox.size() ); + } + // example aShapesWithTextbox [0 2] + } + + if (aShapesWithTextbox.size() != maList.size() - sortOrder.size()) + { + throw lang::IllegalArgumentException("mismatch of no. of shapes", nullptr, 0); + } + + for (size_t i = 0; i< sortOrder.size(); ++i) + { + + if (aShapesWithTextbox.count(sortOrder[i]) > 0) + aDuplicates.push_back(sortOrder[i]); + + aDuplicates.push_back(sortOrder[i]); + + // example aDuplicates [2 2 0 0 1] + } + assert(aDuplicates.size() == maList.size()); + + aIncrements.push_back(0); + for (size_t i = 1; i< sortOrder.size(); ++i) + { + if (aShapesWithTextbox.count(i - 1)) + aIncrements.push_back(aIncrements[i-1] + 1 ); + else + aIncrements.push_back(aIncrements[i-1]); + + // example aIncrements [0 1 1] + } + assert(aIncrements.size() == sortOrder.size()); + + std::vector<sal_Int32> aNewSortOrder(maList.size()); + sal_Int32 nPrev = -1; + for (size_t i = 0; i< aDuplicates.size(); ++i) + { + if (nPrev != aDuplicates[i]) + aNewSortOrder[i] = aDuplicates[i] + aIncrements[aDuplicates[i]]; + else + aNewSortOrder[i] = aNewSortOrder[i-1] + 1; + + nPrev = aDuplicates[i]; + + // example aNewSortOrder [3 4 0 1 2] + } + assert(aNewSortOrder.size() == maList.size()); + +#ifndef NDEBUG + { + std::vector<sal_Int32> tmp(aNewSortOrder); + std::sort(tmp.begin(), tmp.end()); + for (size_t i = 0; i < tmp.size(); ++i) + { + assert(size_t(tmp[i]) == i); + } + } +#endif + + SdrModel & rModel(getSdrPageFromSdrObjList()->getSdrModelFromSdrPage()); + bool const isUndo(rModel.IsUndoEnabled()); + if (isUndo) + { + rModel.AddUndo(SdrUndoFactory::CreateUndoSort(*getSdrPageFromSdrObjList(), sortOrder)); + } + + for (size_t i = 0; i < aNewSortOrder.size(); ++i) + { + aNewList[i] = maList[ aNewSortOrder[i] ]; + aNewList[i]->SetOrdNum(i); + } + + std::swap(aNewList, maList); +} + +const tools::Rectangle& SdrObjList::GetAllObjSnapRect() const +{ + if (mbRectsDirty) { + const_cast<SdrObjList*>(this)->RecalcRects(); + const_cast<SdrObjList*>(this)->mbRectsDirty=false; + } + return maSdrObjListSnapRect; +} + +const tools::Rectangle& SdrObjList::GetAllObjBoundRect() const +{ + // #i106183# for deep group hierarchies like in chart2, the invalidates + // through the hierarchy are not correct; use a 2nd hint for the needed + // recalculation. Future versions will have no bool flag at all, but + // just maSdrObjListOutRect in empty state to represent an invalid state, thus + // it's a step in the right direction. + if (mbRectsDirty || maSdrObjListOutRect.IsEmpty()) + { + const_cast<SdrObjList*>(this)->RecalcRects(); + const_cast<SdrObjList*>(this)->mbRectsDirty=false; + } + return maSdrObjListOutRect; +} + +void SdrObjList::NbcReformatAllTextObjects() +{ + size_t nCount=GetObjCount(); + size_t nNum=0; + + while (nNum<nCount) + { + SdrObject* pObj = GetObj(nNum); + + pObj->NbcReformatText(); + nCount=GetObjCount(); // ReformatText may delete an object + nNum++; + } + +} + +void SdrObjList::ReformatAllTextObjects() +{ + NbcReformatAllTextObjects(); +} + +/** steps over all available objects and reformats all + edge objects that are connected to other objects so that + they may reposition themselves. +*/ +void SdrObjList::ReformatAllEdgeObjects() +{ + // #i120437# go over whole hierarchy, not only over object level null (seen from grouping) + SdrObjListIter aIter(this, SdrIterMode::DeepNoGroups); + + while(aIter.IsMore()) + { + SdrObject* pObj = aIter.Next(); + if (pObj->GetObjIdentifier() != SdrObjKind::Edge) + continue; + + SdrEdgeObj* pSdrEdgeObj = static_cast< SdrEdgeObj* >(pObj); + pSdrEdgeObj->Reformat(); + } +} + +void SdrObjList::BurnInStyleSheetAttributes() +{ + for(size_t a = 0; a < GetObjCount(); ++a) + { + GetObj(a)->BurnInStyleSheetAttributes(); + } +} + +size_t SdrObjList::GetObjCount() const +{ + return maList.size(); +} + + +SdrObject* SdrObjList::GetObj(size_t nNum) const +{ + if (nNum < maList.size()) + return maList[nNum]; + + return nullptr; +} + + +bool SdrObjList::IsReadOnly() const +{ + bool bRet(false); + SdrObject* pParentSdrObject(getSdrObjectFromSdrObjList()); + + if(nullptr != pParentSdrObject) + { + SdrPage* pSdrPage(pParentSdrObject->getSdrPageFromSdrObject()); + + if(nullptr != pSdrPage) + { + bRet = pSdrPage->IsReadOnly(); + } + } + + return bRet; +} + +void SdrObjList::FlattenGroups() +{ + const size_t nObj = GetObjCount(); + for( size_t i = nObj; i>0; ) + UnGroupObj(--i); +} + +void SdrObjList::UnGroupObj( size_t nObjNum ) +{ + // if the given object is no group, this method is a noop + SdrObject* pUngroupObj = GetObj( nObjNum ); + if( pUngroupObj ) + { + SdrObjList* pSrcLst = pUngroupObj->GetSubList(); + if(pSrcLst) + if(auto pUngroupGroup = dynamic_cast<SdrObjGroup*>( pUngroupObj)) + { + // ungroup recursively (has to be head recursion, + // otherwise our indices will get trashed when doing it in + // the loop) + pSrcLst->FlattenGroups(); + + // the position at which we insert the members of rUngroupGroup + size_t nInsertPos( pUngroupGroup->GetOrdNum() ); + + const size_t nCount = pSrcLst->GetObjCount(); + for( size_t i=0; i<nCount; ++i ) + { + SdrObject* pObj = pSrcLst->RemoveObject(0); + InsertObject(pObj, nInsertPos); + ++nInsertPos; + } + + RemoveObject(nInsertPos); + } + } +#ifdef DBG_UTIL + else + OSL_FAIL("SdrObjList::UnGroupObj: object index invalid"); +#endif +} + +bool SdrObjList::HasObjectNavigationOrder() const { return bool(mxNavigationOrder); } + +void SdrObjList::SetObjectNavigationPosition ( + SdrObject& rObject, + const sal_uInt32 nNewPosition) +{ + // When the navigation order container has not yet been created then + // create one now. It is initialized with the z-order taken from + // maList. + if (!mxNavigationOrder) + { + mxNavigationOrder.emplace(maList.begin(), maList.end()); + } + OSL_ASSERT(bool(mxNavigationOrder)); + OSL_ASSERT( mxNavigationOrder->size() == maList.size()); + + tools::WeakReference<SdrObject> aReference (&rObject); + + // Look up the object whose navigation position is to be changed. + auto iObject = ::std::find( + mxNavigationOrder->begin(), + mxNavigationOrder->end(), + aReference); + if (iObject == mxNavigationOrder->end()) + { + // The given object is not a member of the navigation order. + return; + } + + // Move the object to its new position. + const sal_uInt32 nOldPosition = ::std::distance(mxNavigationOrder->begin(), iObject); + if (nOldPosition == nNewPosition) + return; + + mxNavigationOrder->erase(iObject); + sal_uInt32 nInsertPosition (nNewPosition); + // Adapt insertion position for the just erased object. + if (nNewPosition >= nOldPosition) + nInsertPosition -= 1; + if (nInsertPosition >= mxNavigationOrder->size()) + mxNavigationOrder->push_back(aReference); + else + mxNavigationOrder->insert(mxNavigationOrder->begin()+nInsertPosition, aReference); + + mbIsNavigationOrderDirty = true; + + // The navigation order is written out to file so mark the model as modified. + rObject.getSdrModelFromSdrObject().SetChanged(); +} + + +SdrObject* SdrObjList::GetObjectForNavigationPosition (const sal_uInt32 nNavigationPosition) const +{ + if (HasObjectNavigationOrder()) + { + // There is a user defined navigation order. Make sure the object + // index is correct and look up the object in mxNavigationOrder. + if (nNavigationPosition >= mxNavigationOrder->size()) + { + OSL_ASSERT(nNavigationPosition < mxNavigationOrder->size()); + } + else + return (*mxNavigationOrder)[nNavigationPosition].get(); + } + else + { + // There is no user defined navigation order. Use the z-order + // instead. + if (nNavigationPosition >= maList.size()) + { + OSL_ASSERT(nNavigationPosition < maList.size()); + } + else + return maList[nNavigationPosition]; + } + return nullptr; +} + + +void SdrObjList::ClearObjectNavigationOrder() +{ + mxNavigationOrder.reset(); + mbIsNavigationOrderDirty = true; +} + + +bool SdrObjList::RecalcNavigationPositions() +{ + if (mbIsNavigationOrderDirty) + { + if (mxNavigationOrder) + { + mbIsNavigationOrderDirty = false; + + sal_uInt32 nIndex (0); + for (auto& rpObject : *mxNavigationOrder) + { + rpObject->SetNavigationPosition(nIndex); + ++nIndex; + } + } + } + + return bool(mxNavigationOrder); +} + + +void SdrObjList::SetNavigationOrder (const uno::Reference<container::XIndexAccess>& rxOrder) +{ + if (rxOrder.is()) + { + const sal_Int32 nCount = rxOrder->getCount(); + if (static_cast<sal_uInt32>(nCount) != maList.size()) + return; + + if (!mxNavigationOrder) + mxNavigationOrder = std::vector<tools::WeakReference<SdrObject>>(nCount); + + for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) + { + uno::Reference<uno::XInterface> xShape (rxOrder->getByIndex(nIndex), uno::UNO_QUERY); + SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShape); + if (pObject == nullptr) + break; + (*mxNavigationOrder)[nIndex] = pObject; + } + + mbIsNavigationOrderDirty = true; + } + else + { + ClearObjectNavigationOrder(); + } +} + + +void SdrObjList::InsertObjectIntoContainer ( + SdrObject& rObject, + const sal_uInt32 nInsertPosition) +{ + OSL_ASSERT(nInsertPosition<=maList.size()); + + // Update the navigation positions. + if (HasObjectNavigationOrder()) + { + // The new object does not have a user defined position so append it + // to the list. + rObject.SetNavigationPosition(mxNavigationOrder->size()); + mxNavigationOrder->push_back(&rObject); + } + + // Insert object into object list. Because the insert() method requires + // a valid iterator as insertion position, we have to use push_back() to + // insert at the end of the list. + if (nInsertPosition >= maList.size()) + maList.push_back(&rObject); + else + maList.insert(maList.begin()+nInsertPosition, &rObject); + mbObjOrdNumsDirty=true; +} + + +void SdrObjList::ReplaceObjectInContainer ( + SdrObject& rNewObject, + const sal_uInt32 nObjectPosition) +{ + if (nObjectPosition >= maList.size()) + { + OSL_ASSERT(nObjectPosition<maList.size()); + return; + } + + // Update the navigation positions. + if (HasObjectNavigationOrder()) + { + // A user defined position of the object that is to be replaced is + // not transferred to the new object so erase the former and append + // the later object from/to the navigation order. + OSL_ASSERT(nObjectPosition < maList.size()); + tools::WeakReference<SdrObject> aReference (maList[nObjectPosition]); + auto iObject = ::std::find( + mxNavigationOrder->begin(), + mxNavigationOrder->end(), + aReference); + if (iObject != mxNavigationOrder->end()) + mxNavigationOrder->erase(iObject); + + mxNavigationOrder->push_back(&rNewObject); + + mbIsNavigationOrderDirty = true; + } + + maList[nObjectPosition] = &rNewObject; + mbObjOrdNumsDirty=true; +} + + +void SdrObjList::RemoveObjectFromContainer ( + const sal_uInt32 nObjectPosition) +{ + if (nObjectPosition >= maList.size()) + { + OSL_ASSERT(nObjectPosition<maList.size()); + return; + } + + // Update the navigation positions. + if (HasObjectNavigationOrder()) + { + tools::WeakReference<SdrObject> aReference (maList[nObjectPosition]); + auto iObject = ::std::find( + mxNavigationOrder->begin(), + mxNavigationOrder->end(), + aReference); + if (iObject != mxNavigationOrder->end()) + mxNavigationOrder->erase(iObject); + mbIsNavigationOrderDirty = true; + } + + maList.erase(maList.begin()+nObjectPosition); + mbObjOrdNumsDirty=true; +} + +void SdrObjList::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrObjList")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name())); + + size_t nObjCount = GetObjCount(); + for (size_t i = 0; i < nObjCount; ++i) + { + if (const SdrObject* pObject = GetObj(i)) + pObject->dumpAsXml(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); +} + + +void SdrPageGridFrameList::Clear() +{ + sal_uInt16 nCount=GetCount(); + for (sal_uInt16 i=0; i<nCount; i++) { + delete GetObject(i); + } + aList.clear(); +} + + +// PageUser section + +void SdrPage::AddPageUser(sdr::PageUser& rNewUser) +{ + maPageUsers.push_back(&rNewUser); +} + +void SdrPage::RemovePageUser(sdr::PageUser& rOldUser) +{ + const sdr::PageUserVector::iterator aFindResult = ::std::find(maPageUsers.begin(), maPageUsers.end(), &rOldUser); + if(aFindResult != maPageUsers.end()) + { + maPageUsers.erase(aFindResult); + } +} + + +// DrawContact section + +std::unique_ptr<sdr::contact::ViewContact> SdrPage::CreateObjectSpecificViewContact() +{ + return std::make_unique<sdr::contact::ViewContactOfSdrPage>(*this); +} + +const sdr::contact::ViewContact& SdrPage::GetViewContact() const +{ + if (!mpViewContact) + const_cast<SdrPage*>(this)->mpViewContact = + const_cast<SdrPage*>(this)->CreateObjectSpecificViewContact(); + + return *mpViewContact; +} + +sdr::contact::ViewContact& SdrPage::GetViewContact() +{ + if (!mpViewContact) + mpViewContact = CreateObjectSpecificViewContact(); + + return *mpViewContact; +} + +void SdrPageProperties::ImpRemoveStyleSheet() +{ + if(mpStyleSheet) + { + EndListening(*mpStyleSheet); + maProperties.SetParent(nullptr); + mpStyleSheet = nullptr; + } +} + +void SdrPageProperties::ImpAddStyleSheet(SfxStyleSheet& rNewStyleSheet) +{ + if(mpStyleSheet != &rNewStyleSheet) + { + ImpRemoveStyleSheet(); + mpStyleSheet = &rNewStyleSheet; + StartListening(rNewStyleSheet); + maProperties.SetParent(&rNewStyleSheet.GetItemSet()); + } +} + +static void ImpPageChange(SdrPage& rSdrPage) +{ + rSdrPage.ActionChanged(); + rSdrPage.getSdrModelFromSdrPage().SetChanged(); + SdrHint aHint(SdrHintKind::PageOrderChange, &rSdrPage); + rSdrPage.getSdrModelFromSdrPage().Broadcast(aHint); +} + +SdrPageProperties::SdrPageProperties(SdrPage& rSdrPage) +: mpSdrPage(&rSdrPage), + mpStyleSheet(nullptr), + maProperties( + mpSdrPage->getSdrModelFromSdrPage().GetItemPool(), + svl::Items<XATTR_FILL_FIRST, XATTR_FILL_LAST>) +{ + if(!rSdrPage.IsMasterPage()) + { + maProperties.Put(XFillStyleItem(drawing::FillStyle_NONE)); + } +} + +SdrPageProperties::~SdrPageProperties() +{ + ImpRemoveStyleSheet(); +} + +void SdrPageProperties::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint) +{ + switch(rHint.GetId()) + { + case SfxHintId::DataChanged : + { + // notify change, broadcast + ImpPageChange(*mpSdrPage); + break; + } + case SfxHintId::Dying : + { + // Style needs to be forgotten + ImpRemoveStyleSheet(); + break; + } + default: break; + } +} + +bool SdrPageProperties::isUsedByModel() const +{ + assert(mpSdrPage); + return mpSdrPage->IsInserted(); +} + + +void SdrPageProperties::PutItemSet(const SfxItemSet& rSet) +{ + OSL_ENSURE(!mpSdrPage->IsMasterPage(), "Item set at MasterPage Attributes (!)"); + maProperties.Put(rSet); + ImpPageChange(*mpSdrPage); +} + +void SdrPageProperties::PutItem(const SfxPoolItem& rItem) +{ + OSL_ENSURE(!mpSdrPage->IsMasterPage(), "Item set at MasterPage Attributes (!)"); + maProperties.Put(rItem); + ImpPageChange(*mpSdrPage); +} + +void SdrPageProperties::ClearItem(const sal_uInt16 nWhich) +{ + maProperties.ClearItem(nWhich); + ImpPageChange(*mpSdrPage); +} + +void SdrPageProperties::SetStyleSheet(SfxStyleSheet* pStyleSheet) +{ + if(pStyleSheet) + { + ImpAddStyleSheet(*pStyleSheet); + } + else + { + ImpRemoveStyleSheet(); + } + + ImpPageChange(*mpSdrPage); +} + +void SdrPageProperties::SetTheme(std::unique_ptr<svx::Theme> pTheme) +{ + mpTheme = std::move(pTheme); + + if (mpTheme && mpSdrPage->IsMasterPage()) + { + SdrModel& rModel = mpSdrPage->getSdrModelFromSdrPage(); + sal_uInt16 nPageCount = rModel.GetPageCount(); + for (sal_uInt16 nPage = 0; nPage < nPageCount; ++nPage) + { + SdrPage* pPage = rModel.GetPage(nPage); + if (!pPage->TRG_HasMasterPage() || &pPage->TRG_GetMasterPage() != mpSdrPage) + { + continue; + } + + mpTheme->UpdateSdrPage(pPage); + } + } +} + +svx::Theme* SdrPageProperties::GetTheme() { return mpTheme.get(); } + +void SdrPageProperties::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrPageProperties")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + + if (mpTheme) + { + mpTheme->dumpAsXml(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); +} + +SdrPage::SdrPage(SdrModel& rModel, bool bMasterPage) +: mrSdrModelFromSdrPage(rModel), + mnWidth(10), + mnHeight(10), + mnBorderLeft(0), + mnBorderUpper(0), + mnBorderRight(0), + mnBorderLower(0), + mpLayerAdmin(new SdrLayerAdmin(&rModel.GetLayerAdmin())), + nPageNum(0), + mbMaster(bMasterPage), + mbInserted(false), + mbObjectsNotPersistent(false), + mbPageBorderOnlyLeftRight(false) +{ + mpSdrPageProperties.reset(new SdrPageProperties(*this)); +} + +SdrPage::~SdrPage() +{ + if( mxUnoPage.is() ) try + { + uno::Reference< lang::XComponent > xPageComponent( mxUnoPage, uno::UNO_QUERY_THROW ); + mxUnoPage.clear(); + xPageComponent->dispose(); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("svx"); + } + + // tell all the registered PageUsers that the page is in destruction + // This causes some (all?) PageUsers to remove themselves from the list + // of page users. Therefore we have to use a copy of the list for the + // iteration. + sdr::PageUserVector aListCopy (maPageUsers.begin(), maPageUsers.end()); + for(sdr::PageUser* pPageUser : aListCopy) + { + DBG_ASSERT(pPageUser, "SdrPage::~SdrPage: corrupt PageUser list (!)"); + pPageUser->PageInDestruction(*this); + } + + // Clear the vector. This means that user do not need to call RemovePageUser() + // when they get called from PageInDestruction(). + maPageUsers.clear(); + + mpLayerAdmin.reset(); + + TRG_ClearMasterPage(); + + mpViewContact.reset(); + mpSdrPageProperties.reset(); +} + +void SdrPage::lateInit(const SdrPage& rSrcPage) +{ + assert(!mpViewContact); + assert(!mxUnoPage.is()); + + // copy all the local parameters to make this instance + // a valid copy of source page before copying and inserting + // the contained objects + mbMaster = rSrcPage.mbMaster; + mbPageBorderOnlyLeftRight = rSrcPage.mbPageBorderOnlyLeftRight; + mnWidth = rSrcPage.mnWidth; + mnHeight = rSrcPage.mnHeight; + mnBorderLeft = rSrcPage.mnBorderLeft; + mnBorderUpper = rSrcPage.mnBorderUpper; + mnBorderRight = rSrcPage.mnBorderRight; + mnBorderLower = rSrcPage.mnBorderLower; + mbBackgroundFullSize = rSrcPage.mbBackgroundFullSize; + nPageNum = rSrcPage.nPageNum; + + if(rSrcPage.TRG_HasMasterPage()) + { + TRG_SetMasterPage(rSrcPage.TRG_GetMasterPage()); + TRG_SetMasterPageVisibleLayers(rSrcPage.TRG_GetMasterPageVisibleLayers()); + } + else + { + TRG_ClearMasterPage(); + } + + mbObjectsNotPersistent = rSrcPage.mbObjectsNotPersistent; + + { + mpSdrPageProperties.reset(new SdrPageProperties(*this)); + + if(!IsMasterPage()) + { + mpSdrPageProperties->PutItemSet(rSrcPage.getSdrPageProperties().GetItemSet()); + } + + mpSdrPageProperties->SetStyleSheet(rSrcPage.getSdrPageProperties().GetStyleSheet()); + } + + // Now copy the contained objects + if(0 != rSrcPage.GetObjCount()) + { + CopyObjects(rSrcPage); + } +} + +rtl::Reference<SdrPage> SdrPage::CloneSdrPage(SdrModel& rTargetModel) const +{ + rtl::Reference<SdrPage> pClonedPage(new SdrPage(rTargetModel)); + pClonedPage->lateInit(*this); + return pClonedPage; +} + +void SdrPage::SetSize(const Size& aSiz) +{ + bool bChanged(false); + + if(aSiz.Width() != mnWidth) + { + mnWidth = aSiz.Width(); + bChanged = true; + } + + if(aSiz.Height() != mnHeight) + { + mnHeight = aSiz.Height(); + bChanged = true; + } + + if(bChanged) + { + SetChanged(); + } +} + +Size SdrPage::GetSize() const +{ + return Size(mnWidth,mnHeight); +} + +tools::Long SdrPage::GetWidth() const +{ + return mnWidth; +} + +void SdrPage::SetOrientation(Orientation eOri) +{ + // square: handle like portrait format + Size aSiz(GetSize()); + if (aSiz.Width()!=aSiz.Height()) { + if ((eOri==Orientation::Portrait) == (aSiz.Width()>aSiz.Height())) { + // coverity[swapped_arguments : FALSE] - this is in the correct order + SetSize(Size(aSiz.Height(),aSiz.Width())); + } + } +} + +Orientation SdrPage::GetOrientation() const +{ + // square: handle like portrait format + Orientation eRet=Orientation::Portrait; + Size aSiz(GetSize()); + if (aSiz.Width()>aSiz.Height()) eRet=Orientation::Landscape; + return eRet; +} + +tools::Long SdrPage::GetHeight() const +{ + return mnHeight; +} + +void SdrPage::SetBorder(sal_Int32 nLft, sal_Int32 nUpp, sal_Int32 nRgt, sal_Int32 nLwr) +{ + bool bChanged(false); + + if(mnBorderLeft != nLft) + { + mnBorderLeft = nLft; + bChanged = true; + } + + if(mnBorderUpper != nUpp) + { + mnBorderUpper = nUpp; + bChanged = true; + } + + if(mnBorderRight != nRgt) + { + mnBorderRight = nRgt; + bChanged = true; + } + + if(mnBorderLower != nLwr) + { + mnBorderLower = nLwr; + bChanged = true; + } + + if(bChanged) + { + SetChanged(); + } +} + +void SdrPage::SetLeftBorder(sal_Int32 nBorder) +{ + if(mnBorderLeft != nBorder) + { + mnBorderLeft = nBorder; + SetChanged(); + } +} + +void SdrPage::SetUpperBorder(sal_Int32 nBorder) +{ + if(mnBorderUpper != nBorder) + { + mnBorderUpper = nBorder; + SetChanged(); + } +} + +void SdrPage::SetRightBorder(sal_Int32 nBorder) +{ + if(mnBorderRight != nBorder) + { + mnBorderRight=nBorder; + SetChanged(); + } +} + +void SdrPage::SetLowerBorder(sal_Int32 nBorder) +{ + if(mnBorderLower != nBorder) + { + mnBorderLower=nBorder; + SetChanged(); + } +} + +sal_Int32 SdrPage::GetLeftBorder() const +{ + return mnBorderLeft; +} + +sal_Int32 SdrPage::GetUpperBorder() const +{ + return mnBorderUpper; +} + +sal_Int32 SdrPage::GetRightBorder() const +{ + return mnBorderRight; +} + +sal_Int32 SdrPage::GetLowerBorder() const +{ + return mnBorderLower; +} + +void SdrPage::SetBackgroundFullSize(bool const bIn) +{ + if (bIn != mbBackgroundFullSize) + { + mbBackgroundFullSize = bIn; + SetChanged(); + } +} + +bool SdrPage::IsBackgroundFullSize() const +{ + return mbBackgroundFullSize; +} + +// #i68775# React on PageNum changes (from Model in most cases) +void SdrPage::SetPageNum(sal_uInt16 nNew) +{ + if(nNew != nPageNum) + { + // change + nPageNum = nNew; + + // notify visualisations, also notifies e.g. buffered MasterPages + ActionChanged(); + } +} + +sal_uInt16 SdrPage::GetPageNum() const +{ + if (!mbInserted) + return 0; + + if (mbMaster) { + if (getSdrModelFromSdrPage().IsMPgNumsDirty()) + getSdrModelFromSdrPage().RecalcPageNums(true); + } else { + if (getSdrModelFromSdrPage().IsPagNumsDirty()) + getSdrModelFromSdrPage().RecalcPageNums(false); + } + return nPageNum; +} + +void SdrPage::SetChanged() +{ + // For test purposes, use the new ViewContact for change + // notification now. + ActionChanged(); + getSdrModelFromSdrPage().SetChanged(); +} + +SdrPage* SdrPage::getSdrPageFromSdrObjList() const +{ + return const_cast< SdrPage* >(this); +} + +// MasterPage interface + +void SdrPage::TRG_SetMasterPage(SdrPage& rNew) +{ + if(mpMasterPageDescriptor && &(mpMasterPageDescriptor->GetUsedPage()) == &rNew) + return; + + if(mpMasterPageDescriptor) + TRG_ClearMasterPage(); + + mpMasterPageDescriptor.reset(new sdr::MasterPageDescriptor(*this, rNew)); + GetViewContact().ActionChanged(); +} + +void SdrPage::TRG_ClearMasterPage() +{ + if(mpMasterPageDescriptor) + { + SetChanged(); + + // the flushViewObjectContacts() will do needed invalidates by deleting the involved VOCs + mpMasterPageDescriptor->GetUsedPage().GetViewContact().flushViewObjectContacts(); + + mpMasterPageDescriptor.reset(); + } +} + +SdrPage& SdrPage::TRG_GetMasterPage() const +{ + DBG_ASSERT(mpMasterPageDescriptor != nullptr, "TRG_GetMasterPage(): No MasterPage available. Use TRG_HasMasterPage() before access (!)"); + return mpMasterPageDescriptor->GetUsedPage(); +} + +const SdrLayerIDSet& SdrPage::TRG_GetMasterPageVisibleLayers() const +{ + DBG_ASSERT(mpMasterPageDescriptor != nullptr, "TRG_GetMasterPageVisibleLayers(): No MasterPage available. Use TRG_HasMasterPage() before access (!)"); + return mpMasterPageDescriptor->GetVisibleLayers(); +} + +void SdrPage::TRG_SetMasterPageVisibleLayers(const SdrLayerIDSet& rNew) +{ + DBG_ASSERT(mpMasterPageDescriptor != nullptr, "TRG_SetMasterPageVisibleLayers(): No MasterPage available. Use TRG_HasMasterPage() before access (!)"); + mpMasterPageDescriptor->SetVisibleLayers(rNew); +} + +sdr::contact::ViewContact& SdrPage::TRG_GetMasterPageDescriptorViewContact() const +{ + DBG_ASSERT(mpMasterPageDescriptor != nullptr, "TRG_GetMasterPageDescriptorViewContact(): No MasterPage available. Use TRG_HasMasterPage() before access (!)"); + return mpMasterPageDescriptor->GetViewContact(); +} + +// used from SdrModel::RemoveMasterPage +void SdrPage::TRG_ImpMasterPageRemoved(const SdrPage& rRemovedPage) +{ + if(TRG_HasMasterPage()) + { + if(&TRG_GetMasterPage() == &rRemovedPage) + { + TRG_ClearMasterPage(); + } + } +} + +void SdrPage::MakePageObjectsNamesUnique() +{ + std::unordered_set<OUString> aNameSet; + for (size_t no(0); no < GetObjCount(); ++no) + { + SdrObject* pObj(GetObj(no)); + if(nullptr != pObj) + { + if (!pObj->GetName().isEmpty()) + { + pObj->MakeNameUnique(aNameSet); + SdrObjList* pSdrObjList = pObj->GetSubList(); // group + if (pSdrObjList) + { + SdrObject* pListObj; + SdrObjListIter aIter(pSdrObjList, SdrIterMode::DeepWithGroups); + while (aIter.IsMore()) + { + pListObj = aIter.Next(); + pListObj->MakeNameUnique(aNameSet); + } + } + } + } + } +} + +const SdrPageGridFrameList* SdrPage::GetGridFrameList(const SdrPageView* /*pPV*/, const tools::Rectangle* /*pRect*/) const +{ + return nullptr; +} + +const SdrLayerAdmin& SdrPage::GetLayerAdmin() const +{ + return *mpLayerAdmin; +} + +SdrLayerAdmin& SdrPage::GetLayerAdmin() +{ + return *mpLayerAdmin; +} + +OUString SdrPage::GetLayoutName() const +{ + return OUString(); +} + +void SdrPage::SetInserted( bool bIns ) +{ + if( mbInserted == bIns ) + return; + + mbInserted = bIns; + + // #i120437# go over whole hierarchy, not only over object level null (seen from grouping) + SdrObjListIter aIter(this, SdrIterMode::DeepNoGroups); + + while ( aIter.IsMore() ) + { + SdrObject* pObj = aIter.Next(); + if ( auto pOleObj = dynamic_cast<SdrOle2Obj* >(pObj) ) + { + if( mbInserted ) + pOleObj->Connect(); + else + pOleObj->Disconnect(); + } + } +} + +void SdrPage::SetUnoPage(uno::Reference<drawing::XDrawPage> const& xNewPage) +{ + mxUnoPage = xNewPage; +} + +uno::Reference< uno::XInterface > const & SdrPage::getUnoPage() +{ + if( !mxUnoPage.is() ) + { + // create one + mxUnoPage = createUnoPage(); + } + + return mxUnoPage; +} + +uno::Reference< uno::XInterface > SdrPage::createUnoPage() +{ + css::uno::Reference< css::uno::XInterface > xInt = + static_cast<cppu::OWeakObject*>( new SvxFmDrawPage( this ) ); + return xInt; +} + +SfxStyleSheet* SdrPage::GetTextStyleSheetForObject( SdrObject* pObj ) const +{ + return pObj->GetStyleSheet(); +} + +/** returns an averaged background color of this page */ +// #i75566# GetBackgroundColor -> GetPageBackgroundColor and bScreenDisplay hint value +Color SdrPage::GetPageBackgroundColor( SdrPageView const * pView, bool bScreenDisplay ) const +{ + Color aColor; + + if(bScreenDisplay && (!pView || pView->GetApplicationDocumentColor() == COL_AUTO)) + { + svtools::ColorConfig aColorConfig; + aColor = aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor; + } + else + { + aColor = pView->GetApplicationDocumentColor(); + } + + const SfxItemSet* pBackgroundFill = &getSdrPageProperties().GetItemSet(); + + if(!IsMasterPage() && TRG_HasMasterPage()) + { + if(drawing::FillStyle_NONE == pBackgroundFill->Get(XATTR_FILLSTYLE).GetValue()) + { + pBackgroundFill = &TRG_GetMasterPage().getSdrPageProperties().GetItemSet(); + } + } + + GetDraftFillColor(*pBackgroundFill, aColor); + + return aColor; +} + +/** *deprecated, use GetBackgroundColor with SdrPageView */ +Color SdrPage::GetPageBackgroundColor() const +// #i75566# GetBackgroundColor -> GetPageBackgroundColor +{ + return GetPageBackgroundColor( nullptr ); +} + +/** this method returns true if the object from the ViewObjectContact should + be visible on this page while rendering. + bEdit selects if visibility test is for an editing view or a final render, + like printing. +*/ +bool SdrPage::checkVisibility( + const sdr::contact::ViewObjectContact& /*rOriginal*/, + const sdr::contact::DisplayInfo& /*rDisplayInfo*/, + bool /*bEdit*/) +{ + // this will be handled in the application if needed + return true; +} + +void SdrPage::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrPage")); + SdrObjList::dumpAsXml(pWriter); + + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("width")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("value"), "%s", + BAD_CAST(OString::number(mnWidth).getStr())); + (void)xmlTextWriterEndElement(pWriter); + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("height")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("value"), "%s", + BAD_CAST(OString::number(mnHeight).getStr())); + (void)xmlTextWriterEndElement(pWriter); + + if (mpSdrPageProperties) + { + mpSdrPageProperties->dumpAsXml(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); +} + +// DrawContact support: Methods for handling Page changes +void SdrPage::ActionChanged() +{ + // Do necessary ViewContact actions + GetViewContact().ActionChanged(); + + // #i48535# also handle MasterPage change + if(TRG_HasMasterPage()) + { + TRG_GetMasterPageDescriptorViewContact().ActionChanged(); + } +} + +SdrPageProperties& SdrPage::getSdrPageProperties() +{ + return *mpSdrPageProperties; +} + +const SdrPageProperties& SdrPage::getSdrPageProperties() const +{ + return *mpSdrPageProperties; +} + +const SdrPageProperties* SdrPage::getCorrectSdrPageProperties() const +{ + if(mpMasterPageDescriptor) + { + return mpMasterPageDescriptor->getCorrectSdrPageProperties(); + } + else + { + return &getSdrPageProperties(); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |