/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; void SdrEditView::ImpResetPossibilityFlags() { m_bReadOnly =false; m_bGroupPossible =false; m_bUnGroupPossible =false; m_bGrpEnterPossible =false; m_bToTopPossible =false; m_bToBtmPossible =false; m_bReverseOrderPossible =false; m_bImportMtfPossible =false; m_bCombinePossible =false; m_bDismantlePossible =false; m_bCombineNoPolyPolyPossible =false; m_bDismantleMakeLinesPossible=false; m_bOrthoDesiredOnMarked =false; m_bOneOrMoreMovable =false; m_bMoreThanOneNoMovRot =false; m_bContortionPossible =false; m_bMoveAllowed =false; m_bResizeFreeAllowed =false; m_bResizePropAllowed =false; m_bRotateFreeAllowed =false; m_bRotate90Allowed =false; m_bMirrorFreeAllowed =false; m_bMirror45Allowed =false; m_bMirror90Allowed =false; m_bTransparenceAllowed =false; m_bCropAllowed =false; m_bGradientAllowed =false; m_bShearAllowed =false; m_bEdgeRadiusAllowed =false; m_bCanConvToPath =false; m_bCanConvToPoly =false; m_bCanConvToContour =false; m_bMoveProtect =false; m_bResizeProtect =false; } SdrEditView::SdrEditView(SdrModel& rSdrModel, OutputDevice* pOut) : SdrMarkView(rSdrModel, pOut) , m_bPossibilitiesDirty(true) , m_bReadOnly(false) , m_bGroupPossible(false) , m_bUnGroupPossible(false) , m_bGrpEnterPossible(false) , m_bToTopPossible(false) , m_bToBtmPossible(false) , m_bReverseOrderPossible(false) , m_bImportMtfPossible(false) , m_bCombinePossible(false) , m_bDismantlePossible(false) , m_bCombineNoPolyPolyPossible(false) , m_bDismantleMakeLinesPossible(false) , m_bOrthoDesiredOnMarked(false) , m_bOneOrMoreMovable(false) , m_bMoreThanOneNoMovRot(false) , m_bContortionPossible(false) , m_bMoveAllowed(false) , m_bResizeFreeAllowed(false) , m_bResizePropAllowed(false) , m_bRotateFreeAllowed(false) , m_bRotate90Allowed(false) , m_bMirrorFreeAllowed(false) , m_bMirror45Allowed(false) , m_bMirror90Allowed(false) , m_bShearAllowed(false) , m_bEdgeRadiusAllowed(false) , m_bTransparenceAllowed(false) , m_bCropAllowed(false) , m_bGradientAllowed(false) , m_bCanConvToPath(false) , m_bCanConvToPoly(false) , m_bCanConvToContour(false) , m_bMoveProtect(false) , m_bResizeProtect(false) { } SdrEditView::~SdrEditView() { } void SdrEditView::InsertNewLayer(const OUString& rName, sal_uInt16 nPos) { SdrLayerAdmin& rLA = GetModel().GetLayerAdmin(); sal_uInt16 nMax=rLA.GetLayerCount(); if (nPos>nMax) nPos=nMax; rLA.NewLayer(rName,nPos); if( GetModel().IsUndoEnabled() ) AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewLayer(nPos,rLA, GetModel())); GetModel().SetChanged(); } bool SdrEditView::ImpDelLayerCheck(SdrObjList const * pOL, SdrLayerID nDelID) const { bool bDelAll(true); for(size_t nObjNum = pOL->GetObjCount(); nObjNum > 0 && bDelAll;) { nObjNum--; SdrObject* pObj = pOL->GetObj(nObjNum); assert(pObj); SdrObjList* pSubOL = pObj->GetSubList(); // explicitly test for group objects and 3d scenes if(pSubOL && (dynamic_cast(pObj) != nullptr || DynCastE3dScene(pObj))) { if(!ImpDelLayerCheck(pSubOL, nDelID)) { bDelAll = false; } } else { if(pObj->GetLayer() != nDelID) { bDelAll = false; } } } return bDelAll; } void SdrEditView::ImpDelLayerDelObjs(SdrObjList* pOL, SdrLayerID nDelID) { const size_t nObjCount(pOL->GetObjCount()); // make sure OrdNums are correct pOL->GetObj(0)->GetOrdNum(); const bool bUndo = GetModel().IsUndoEnabled(); for(size_t nObjNum = nObjCount; nObjNum > 0;) { nObjNum--; SdrObject* pObj = pOL->GetObj(nObjNum); assert(pObj); SdrObjList* pSubOL = pObj->GetSubList(); // explicitly test for group objects and 3d scenes if(pSubOL && (dynamic_cast( pObj) != nullptr || DynCastE3dScene(pObj))) { if(ImpDelLayerCheck(pSubOL, nDelID)) { if( bUndo ) AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true)); pOL->RemoveObject(nObjNum); } else { ImpDelLayerDelObjs(pSubOL, nDelID); } } else { if(pObj->GetLayer() == nDelID) { if( bUndo ) AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true)); pOL->RemoveObject(nObjNum); } } } } void SdrEditView::DeleteLayer(const OUString& rName) { SdrLayerAdmin& rLA = GetModel().GetLayerAdmin(); SdrLayer* pLayer = rLA.GetLayer(rName); if(!pLayer) return; sal_uInt16 nLayerNum(rLA.GetLayerPos(pLayer)); SdrLayerID nDelID = pLayer->GetID(); const bool bUndo = IsUndoEnabled(); if( bUndo ) BegUndo(SvxResId(STR_UndoDelLayer)); bool bMaPg(true); for(sal_uInt16 nPageKind(0); nPageKind < 2; nPageKind++) { // MasterPages and DrawPages sal_uInt16 nPgCount(bMaPg ? GetModel().GetMasterPageCount() : GetModel().GetPageCount()); for(sal_uInt16 nPgNum(0); nPgNum < nPgCount; nPgNum++) { // over all pages SdrPage* pPage = bMaPg ? GetModel().GetMasterPage(nPgNum) : GetModel().GetPage(nPgNum); const size_t nObjCount(pPage->GetObjCount()); // make sure OrdNums are correct if(nObjCount) pPage->GetObj(0)->GetOrdNum(); for(size_t nObjNum(nObjCount); nObjNum > 0;) { nObjNum--; SdrObject* pObj = pPage->GetObj(nObjNum); assert(pObj); SdrObjList* pSubOL = pObj->GetSubList(); // explicitly test for group objects and 3d scenes if(pSubOL && (dynamic_cast(pObj) != nullptr || DynCastE3dScene(pObj))) { if(ImpDelLayerCheck(pSubOL, nDelID)) { if( bUndo ) AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true)); pPage->RemoveObject(nObjNum); } else { ImpDelLayerDelObjs(pSubOL, nDelID); } } else { if(pObj->GetLayer() == nDelID) { if( bUndo ) AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true)); pPage->RemoveObject(nObjNum); } } } } bMaPg = false; } if( bUndo ) { AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteLayer(nLayerNum, rLA, GetModel())); // coverity[leaked_storage] - ownership transferred to UndoDeleteLayer rLA.RemoveLayer(nLayerNum).release(); EndUndo(); } else { rLA.RemoveLayer(nLayerNum); } GetModel().SetChanged(); } void SdrEditView::EndUndo() { // #i13033# // Comparison changed to 1L since EndUndo() is called later now // and EndUndo WILL change count to count-1 if(1 == GetModel().GetUndoBracketLevel()) { ImpBroadcastEdgesOfMarkedNodes(); } // #i13033# // moved to bottom to still have access to UNDOs inside of // ImpBroadcastEdgesOfMarkedNodes() GetModel().EndUndo(); } void SdrEditView::ImpBroadcastEdgesOfMarkedNodes() { std::vector::const_iterator iterPos; const std::vector& rAllMarkedObjects = GetTransitiveHullOfMarkedObjects(); // #i13033# // New mechanism to search for necessary disconnections for // changed connectors inside the transitive hull of all at // the beginning of UNDO selected objects for(size_t a(0); a < rAllMarkedObjects.size(); a++) { SdrEdgeObj* pEdge = dynamic_cast( rAllMarkedObjects[a] ); if(pEdge) { SdrObject* pObj1 = pEdge->GetConnectedNode(false); SdrObject* pObj2 = pEdge->GetConnectedNode(true); if(pObj1 && !pEdge->CheckNodeConnection(false)) { iterPos = std::find(rAllMarkedObjects.begin(),rAllMarkedObjects.end(),pObj1); if (iterPos == rAllMarkedObjects.end()) { if( IsUndoEnabled() ) AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pEdge)); pEdge->DisconnectFromNode(false); } } if(pObj2 && !pEdge->CheckNodeConnection(true)) { iterPos = std::find(rAllMarkedObjects.begin(),rAllMarkedObjects.end(),pObj2); if (iterPos == rAllMarkedObjects.end()) { if( IsUndoEnabled() ) AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pEdge)); pEdge->DisconnectFromNode(true); } } } } const size_t nMarkedEdgeCnt = GetMarkedEdgesOfMarkedNodes().GetMarkCount(); for (size_t i=0; iGetMarkedSdrObj(); SdrEdgeObj* pEdge=dynamic_cast( pEdgeTmp ); if (pEdge!=nullptr) { pEdge->SetEdgeTrackDirty(); } } } // Possibilities void SdrEditView::MarkListHasChanged() { SdrMarkView::MarkListHasChanged(); m_bPossibilitiesDirty=true; } void SdrEditView::ModelHasChanged() { SdrMarkView::ModelHasChanged(); m_bPossibilitiesDirty=true; } bool SdrEditView::IsResizeAllowed(bool bProp) const { ForcePossibilities(); if (m_bResizeProtect) return false; if (bProp) return m_bResizePropAllowed; return m_bResizeFreeAllowed; } bool SdrEditView::IsRotateAllowed(bool b90Deg) const { ForcePossibilities(); if (m_bMoveProtect) return false; if (b90Deg) return m_bRotate90Allowed; return m_bRotateFreeAllowed; } bool SdrEditView::IsMirrorAllowed(bool b45Deg, bool b90Deg) const { ForcePossibilities(); if (m_bMoveProtect) return false; if (b90Deg) return m_bMirror90Allowed; if (b45Deg) return m_bMirror45Allowed; return m_bMirrorFreeAllowed; } bool SdrEditView::IsTransparenceAllowed() const { ForcePossibilities(); return m_bTransparenceAllowed; } bool SdrEditView::IsCropAllowed() const { ForcePossibilities(); return m_bCropAllowed; } bool SdrEditView::IsGradientAllowed() const { ForcePossibilities(); return m_bGradientAllowed; } bool SdrEditView::IsShearAllowed() const { ForcePossibilities(); if (m_bResizeProtect) return false; return m_bShearAllowed; } bool SdrEditView::IsEdgeRadiusAllowed() const { ForcePossibilities(); return m_bEdgeRadiusAllowed; } bool SdrEditView::IsCrookAllowed(bool bNoContortion) const { // CrookMode missing here (no rotations allowed when shearing ...) ForcePossibilities(); if (bNoContortion) { if (!m_bRotateFreeAllowed) return false; return !m_bMoveProtect && m_bMoveAllowed; } else { return !m_bResizeProtect && m_bContortionPossible; } } bool SdrEditView::IsDistortAllowed(bool bNoContortion) const { ForcePossibilities(); if (bNoContortion) { return false; } else { return !m_bResizeProtect && m_bContortionPossible; } } bool SdrEditView::IsCombinePossible(bool bNoPolyPoly) const { ForcePossibilities(); if (bNoPolyPoly) return m_bCombineNoPolyPolyPossible; else return m_bCombinePossible; } bool SdrEditView::IsDismantlePossible(bool bMakeLines) const { ForcePossibilities(); if (bMakeLines) return m_bDismantleMakeLinesPossible; else return m_bDismantlePossible; } void SdrEditView::CheckPossibilities() { if (mbSomeObjChgdFlag) { m_bPossibilitiesDirty = true; // This call IS necessary to correct the MarkList, in which // no longer to the model belonging objects still can reside. // These ones need to be removed. CheckMarked(); } if (!m_bPossibilitiesDirty) return; ImpResetPossibilityFlags(); SortMarkedObjects(); const size_t nMarkCount = GetMarkedObjectCount(); if (nMarkCount != 0) { m_bReverseOrderPossible = (nMarkCount >= 2); size_t nMovableCount=0; m_bGroupPossible=nMarkCount>=2; m_bCombinePossible=nMarkCount>=2; if (nMarkCount==1) { // check bCombinePossible more thoroughly // still missing ... const SdrObject* pObj=GetMarkedObjectByIndex(0); //const SdrPathObj* pPath=dynamic_cast( pObj ); bool bGroup=pObj->GetSubList()!=nullptr; bool bHasText=pObj->GetOutlinerParaObject()!=nullptr; if (bGroup || bHasText) { m_bCombinePossible=true; } } m_bCombineNoPolyPolyPossible=m_bCombinePossible; // accept transformations for now m_bMoveAllowed =true; m_bResizeFreeAllowed=true; m_bResizePropAllowed=true; m_bRotateFreeAllowed=true; m_bRotate90Allowed =true; m_bMirrorFreeAllowed=true; m_bMirror45Allowed =true; m_bMirror90Allowed =true; m_bShearAllowed =true; m_bEdgeRadiusAllowed=false; m_bContortionPossible=true; m_bCanConvToContour = true; // these ones are only allowed when single object is selected m_bTransparenceAllowed = (nMarkCount == 1); m_bGradientAllowed = (nMarkCount == 1); m_bCropAllowed = (nMarkCount == 1); if(m_bGradientAllowed) { // gradient depends on fill style const SdrMark* pM = GetSdrMarkByIndex(0); const SdrObject* pObj = pM->GetMarkedSdrObj(); // may be group object, so get merged ItemSet const SfxItemSet& rSet = pObj->GetMergedItemSet(); SfxItemState eState = rSet.GetItemState(XATTR_FILLSTYLE, false); if(SfxItemState::INVALID != eState) { // If state is not DONTCARE, test the item drawing::FillStyle eFillStyle = rSet.Get(XATTR_FILLSTYLE).GetValue(); if(eFillStyle != drawing::FillStyle_GRADIENT) { m_bGradientAllowed = false; } } } bool bNoMovRotFound=false; const SdrPageView* pPV0=nullptr; for (size_t nm=0; nmGetMarkedSdrObj(); const SdrPageView* pPV=pM->GetPageView(); if (pPV!=pPV0) { if (pPV->IsReadOnly()) m_bReadOnly=true; pPV0=pPV; } SdrObjTransformInfoRec aInfo; pObj->TakeObjInfo(aInfo); bool bMovPrt=pObj->IsMoveProtect(); bool bSizPrt=pObj->IsResizeProtect(); if (!bMovPrt && aInfo.bMoveAllowed) nMovableCount++; // count MovableObjs if (bMovPrt) m_bMoveProtect=true; if (bSizPrt) m_bResizeProtect=true; // not allowed when not allowed at one object if(!aInfo.bTransparenceAllowed) m_bTransparenceAllowed = false; // If one of these can't do something, none can if (!aInfo.bMoveAllowed ) m_bMoveAllowed =false; if (!aInfo.bResizeFreeAllowed) m_bResizeFreeAllowed=false; if (!aInfo.bResizePropAllowed) m_bResizePropAllowed=false; if (!aInfo.bRotateFreeAllowed) m_bRotateFreeAllowed=false; if (!aInfo.bRotate90Allowed ) m_bRotate90Allowed =false; if (!aInfo.bMirrorFreeAllowed) m_bMirrorFreeAllowed=false; if (!aInfo.bMirror45Allowed ) m_bMirror45Allowed =false; if (!aInfo.bMirror90Allowed ) m_bMirror90Allowed =false; if (!aInfo.bShearAllowed ) m_bShearAllowed =false; if (aInfo.bEdgeRadiusAllowed) m_bEdgeRadiusAllowed=true; if (aInfo.bNoContortion ) m_bContortionPossible=false; // For Crook with Contortion: all objects have to be // Movable and Rotatable, except for a maximum of 1 of them if (!m_bMoreThanOneNoMovRot) { if (!aInfo.bMoveAllowed || !aInfo.bResizeFreeAllowed) { m_bMoreThanOneNoMovRot=bNoMovRotFound; bNoMovRotFound=true; } } // Must be resizable to allow cropping if (!aInfo.bResizeFreeAllowed && !aInfo.bResizePropAllowed) m_bCropAllowed = false; // if one member cannot be converted, no conversion is possible if(!aInfo.bCanConvToContour) m_bCanConvToContour = false; // Ungroup if (!m_bUnGroupPossible) m_bUnGroupPossible=pObj->GetSubList()!=nullptr; // ConvertToCurve: If at least one can be converted, that is fine. if (aInfo.bCanConvToPath ) m_bCanConvToPath =true; if (aInfo.bCanConvToPoly ) m_bCanConvToPoly =true; // Combine/Dismantle if(m_bCombinePossible) { m_bCombinePossible = ImpCanConvertForCombine(pObj); m_bCombineNoPolyPolyPossible = m_bCombinePossible; } if (!m_bDismantlePossible) m_bDismantlePossible = ImpCanDismantle(pObj, false); if (!m_bDismantleMakeLinesPossible) m_bDismantleMakeLinesPossible = ImpCanDismantle(pObj, true); // check OrthoDesiredOnMarked if (!m_bOrthoDesiredOnMarked && !aInfo.bNoOrthoDesired) m_bOrthoDesiredOnMarked=true; // check ImportMtf if (!m_bImportMtfPossible) { const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pObj); if (pSdrGrafObj != nullptr) { if ((pSdrGrafObj->HasGDIMetaFile() && !pSdrGrafObj->IsEPS()) || pSdrGrafObj->isEmbeddedVectorGraphicData()) { m_bImportMtfPossible = true; } } const SdrOle2Obj* pSdrOle2Obj = dynamic_cast< const SdrOle2Obj* >(pObj); if (pSdrOle2Obj) { m_bImportMtfPossible = pSdrOle2Obj->GetObjRef().is(); } } } m_bOneOrMoreMovable=nMovableCount!=0; m_bGrpEnterPossible=m_bUnGroupPossible; } ImpCheckToTopBtmPossible(); static_cast(this)->ImpCheckPolyPossibilities(); m_bPossibilitiesDirty=false; if (m_bReadOnly || SfxViewShell::IsCurrentLokViewReadOnly() ) { bool bTemp=m_bGrpEnterPossible; ImpResetPossibilityFlags(); m_bReadOnly=true; m_bGrpEnterPossible=bTemp; } if (!m_bMoveAllowed) return; // Don't allow moving glued connectors. // Currently only implemented for single selection. if (nMarkCount==1) { SdrObject* pObj=GetMarkedObjectByIndex(0); SdrEdgeObj* pEdge=dynamic_cast( pObj ); if (pEdge!=nullptr) { SdrObject* pNode1=pEdge->GetConnectedNode(true); SdrObject* pNode2=pEdge->GetConnectedNode(false); if (pNode1!=nullptr || pNode2!=nullptr) m_bMoveAllowed=false; } } // Don't allow enter Diagrams if (1 == nMarkCount && m_bGrpEnterPossible) { SdrObject* pCandidate(GetMarkedObjectByIndex(0)); if(nullptr != pCandidate && pCandidate->isDiagram()) m_bGrpEnterPossible = false; } } void SdrEditView::ForceMarkedObjToAnotherPage() { bool bFlg=false; for (size_t nm=0; nmGetMarkedSdrObj(); tools::Rectangle aObjRect(pObj->GetCurrentBoundRect()); tools::Rectangle aPgRect(pM->GetPageView()->GetPageRect()); if (!aObjRect.Overlaps(aPgRect)) { bool bFnd=false; SdrPageView* pPV = GetSdrPageView(); if(pPV) { bFnd = aObjRect.Overlaps(pPV->GetPageRect()); } if(bFnd) { pM->GetPageView()->GetObjList()->RemoveObject(pObj->GetOrdNum()); pPV->GetObjList()->InsertObject(pObj, SAL_MAX_SIZE); pM->SetPageView(pPV); InvalidateAllWin(aObjRect); bFlg=true; } } } if (bFlg) { MarkListHasChanged(); } } std::vector> SdrEditView::DeleteMarkedList(SdrMarkList const& rMark) { std::vector> ret; if (rMark.GetMarkCount()!=0) { rMark.ForceSort(); const bool bUndo = IsUndoEnabled(); if( bUndo ) BegUndo(); const size_t nMarkCount(rMark.GetMarkCount()); if(nMarkCount) { std::vector< E3DModifySceneSnapRectUpdater* > aUpdaters; if( bUndo ) { for(size_t nm = nMarkCount; nm > 0;) { --nm; SdrMark* pM = rMark.GetMark(nm); SdrObject* pObj = pM->GetMarkedSdrObj(); // extra undo actions for changed connector which now may hold its laid out path (SJ) AddUndoActions(CreateConnectorUndo( *pObj )); AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj)); } } // make sure, OrderNums are correct: rMark.GetMark(0)->GetMarkedSdrObj()->GetOrdNum(); for(size_t nm = nMarkCount; nm > 0;) { --nm; SdrMark* pM = rMark.GetMark(nm); SdrObject* pObj = pM->GetMarkedSdrObj(); SdrObjList* pOL = pObj->getParentSdrObjListFromSdrObject(); const size_t nOrdNum(pObj->GetOrdNumDirect()); bool bIs3D = DynCastE3dObject(pObj); // set up a scene updater if object is a 3d object if(bIs3D) { aUpdaters.push_back(new E3DModifySceneSnapRectUpdater(pObj)); } if( !bUndo ) { // tdf#108863 and tdf#108889 don't delete objects before EndUndo() ret.push_back(pObj); } pOL->RemoveObject(nOrdNum); } // fire scene updaters while(!aUpdaters.empty()) { delete aUpdaters.back(); aUpdaters.pop_back(); } } if( bUndo ) EndUndo(); } return ret; } static void lcl_LazyDelete(std::vector> & rLazyDelete) { // now delete removed scene objects while (!rLazyDelete.empty()) rLazyDelete.pop_back(); } void SdrEditView::DeleteMarkedObj() { // #i110981# return when nothing is to be done at all if(!GetMarkedObjectCount()) { return; } // moved breaking action and undo start outside loop BrkAction(); BegUndo(SvxResId(STR_EditDelete),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::Delete); std::vector> lazyDeleteObjects; // remove as long as something is selected. This allows to schedule objects for // removal for a next run as needed while(GetMarkedObjectCount()) { // vector to remember the parents which may be empty after object removal std::vector< SdrObject* > aParents; { const SdrMarkList& rMarkList = GetMarkedObjectList(); const size_t nCount(rMarkList.GetMarkCount()); for(size_t a = 0; a < nCount; ++a) { // in the first run, add all found parents, but only once SdrMark* pMark(rMarkList.GetMark(a)); SdrObject* pObject(pMark->GetMarkedSdrObj()); SdrObject* pParent(pObject->getParentSdrObjectFromSdrObject()); if(pParent) { if(!aParents.empty()) { std::vector< SdrObject* >::iterator aFindResult = std::find(aParents.begin(), aParents.end(), pParent); if(aFindResult == aParents.end()) { aParents.push_back(pParent); } } else { aParents.push_back(pParent); } } } if(!aParents.empty()) { // in a 2nd run, remove all objects which may already be scheduled for // removal. I am not sure if this can happen, but theoretically // a to-be-removed object may already be the group/3DScene itself for(size_t a = 0; a < nCount; ++a) { SdrMark* pMark = rMarkList.GetMark(a); SdrObject* pObject = pMark->GetMarkedSdrObj(); std::vector< SdrObject* >::iterator aFindResult = std::find(aParents.begin(), aParents.end(), pObject); if(aFindResult != aParents.end()) { aParents.erase(aFindResult); } } } } // original stuff: remove selected objects. Handle clear will // do something only once auto temp(DeleteMarkedList(GetMarkedObjectList())); lazyDeleteObjects.insert(lazyDeleteObjects.end(), temp.begin(), temp.end()); GetMarkedObjectListWriteAccess().Clear(); maHdlList.Clear(); while(!aParents.empty() && !GetMarkedObjectCount()) { // iterate over remembered parents SdrObject* pParent = aParents.back(); aParents.pop_back(); if(pParent->GetSubList() && 0 == pParent->GetSubList()->GetObjCount()) { // we detected an empty parent, a candidate to leave group/3DScene // if entered if(GetSdrPageView()->GetCurrentGroup() && GetSdrPageView()->GetCurrentGroup() == pParent) { GetSdrPageView()->LeaveOneGroup(); } // schedule empty parent for removal GetMarkedObjectListWriteAccess().InsertEntry( SdrMark(pParent, GetSdrPageView())); } } } // end undo and change messaging moved at the end EndUndo(); MarkListHasChanged(); lcl_LazyDelete(lazyDeleteObjects); } void SdrEditView::CopyMarkedObj() { SortMarkedObjects(); SdrMarkList aSourceObjectsForCopy(GetMarkedObjectList()); // The following loop is used instead of MarkList::Merge(), to be // able to flag the MarkEntries. const size_t nEdgeCnt = GetEdgesOfMarkedNodes().GetMarkCount(); for (size_t nEdgeNum=0; nEdgeNum aNameSet; const size_t nMarkCount=aSourceObjectsForCopy.GetMarkCount(); for (size_t nm=0; nmGetMarkedSdrObj()); rtl::Reference pO(pSource->CloneSdrObject(pSource->getSdrModelFromSdrObject())); if (pO!=nullptr) { pM->GetPageView()->GetObjList()->InsertObjectThenMakeNameUnique(pO.get(), aNameSet); if( bUndo ) AddUndo(GetModel().GetSdrUndoFactory().CreateUndoCopyObject(*pO)); SdrMark aME(*pM); aME.SetMarkedSdrObj(pO.get()); aCloneList.AddPair(pM->GetMarkedSdrObj(), pO.get()); if (pM->GetUser()==0) { // otherwise it is only an Edge we have to copy as well GetMarkedObjectListWriteAccess().InsertEntry(aME); } } else { nCloneErrCnt++; } } // #i13033# // New mechanism to re-create the connections of cloned connectors aCloneList.CopyConnections(); if(nCloneErrCnt) { #ifdef DBG_UTIL OStringBuffer aStr("SdrEditView::CopyMarkedObj(): Error when cloning "); if(nCloneErrCnt == 1) { aStr.append("a drawing object."); } else { aStr.append(OString::number(static_cast(nCloneErrCnt)) + " drawing objects."); } aStr.append(" This object's/These objects's connections will not be copied."); OSL_FAIL(aStr.getStr()); #endif } MarkListHasChanged(); } bool SdrEditView::InsertObjectAtView(SdrObject* pObj, SdrPageView& rPV, SdrInsertFlags nOptions) { if (nOptions & SdrInsertFlags::SETDEFLAYER) { SdrLayerID nLayer=rPV.GetPage()->GetLayerAdmin().GetLayerID(maActualLayer); if (nLayer==SDRLAYER_NOTFOUND) nLayer=SdrLayerID(0); if (rPV.GetLockedLayers().IsSet(nLayer) || !rPV.GetVisibleLayers().IsSet(nLayer)) { return false; } pObj->NbcSetLayer(nLayer); } if (nOptions & SdrInsertFlags::SETDEFATTR) { if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false); pObj->SetMergedItemSet(maDefaultAttr); } if (!pObj->IsInserted()) { rPV.GetObjList()->InsertObject(pObj, SAL_MAX_SIZE); } css::uno::Reference xServices(GetModel().getUnoModel(), css::uno::UNO_QUERY); if (xServices.is() && (xServices->supportsService(u"com.sun.star.sheet.SpreadsheetDocument"_ustr) || xServices->supportsService(u"com.sun.star.text.TextDocument"_ustr))) { const bool bUndo(IsUndoEnabled()); GetModel().EnableUndo(false); pObj->MakeNameUnique(); GetModel().EnableUndo(bUndo); } if( IsUndoEnabled()) { bool bDontDeleteReally = true; EndTextEditCurrentView(bDontDeleteReally); AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pObj)); } if (!(nOptions & SdrInsertFlags::DONTMARK)) { if (!(nOptions & SdrInsertFlags::ADDMARK)) UnmarkAllObj(); MarkObj(pObj,&rPV); } return true; } void SdrEditView::ReplaceObjectAtView(SdrObject* pOldObj, SdrPageView& rPV, SdrObject* pNewObj, bool bMark) { if(IsTextEdit()) { #ifdef DBG_UTIL if(auto pTextObj = DynCastSdrTextObj(pOldObj)) if (pTextObj->IsTextEditActive()) OSL_ENSURE(false, "OldObject is in TextEdit mode, this has to be ended before replacing it using SdrEndTextEdit (!)"); if(auto pTextObj = DynCastSdrTextObj(pNewObj)) if (pTextObj->IsTextEditActive()) OSL_ENSURE(false, "NewObject is in TextEdit mode, this has to be ended before replacing it using SdrEndTextEdit (!)"); #endif // #i123468# emergency repair situation, needs to cast up to a class derived from // this one; (aw080 has a mechanism for that and the view hierarchy is secured to // always be a SdrView) SdrView *pSdrView = dynamic_cast(this); if (pSdrView) pSdrView->SdrEndTextEdit(); } SdrObjList* pOL=pOldObj->getParentSdrObjListFromSdrObject(); const bool bUndo = IsUndoEnabled(); if( bUndo ) AddUndo(GetModel().GetSdrUndoFactory().CreateUndoReplaceObject(*pOldObj,*pNewObj)); if( IsObjMarked( pOldObj ) ) MarkObj( pOldObj, &rPV, true /*unmark!*/ ); pOL->ReplaceObject(pNewObj,pOldObj->GetOrdNum()); if (bMark) MarkObj(pNewObj,&rPV); } bool SdrEditView::IsUndoEnabled() const { return GetModel().IsUndoEnabled(); } void SdrEditView::EndTextEditAllViews() const { GetModel().ForAllListeners( [](SfxListener* pListener) { SdrObjEditView* pView = dynamic_cast(pListener); if (pView && pView->IsTextEdit()) pView->SdrEndTextEdit(); return false; }); } void SdrEditView::EndTextEditCurrentView(bool bDontDeleteReally) { if (IsTextEdit()) { SdrView* pSdrView = dynamic_cast(this); if (pSdrView) pSdrView->SdrEndTextEdit(bDontDeleteReally); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */