1090 lines
35 KiB
C++
1090 lines
35 KiB
C++
/* -*- 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/svdedtv.hxx>
|
|
#include <svx/svdundo.hxx>
|
|
#include <svx/svdograf.hxx>
|
|
#include <svx/svdoole2.hxx>
|
|
#include <svx/svdoedge.hxx>
|
|
#include <svx/svdlayer.hxx>
|
|
#include <svx/svdpagv.hxx>
|
|
#include <svx/svdpage.hxx>
|
|
#include <svx/svdpoev.hxx>
|
|
#include <svx/strings.hrc>
|
|
#include <svx/dialmgr.hxx>
|
|
#include <svx/e3dsceneupdater.hxx>
|
|
#include <rtl/strbuf.hxx>
|
|
#include <svx/svdview.hxx>
|
|
#include <clonelist.hxx>
|
|
#include <svx/svdogrp.hxx>
|
|
#include <svx/xfillit0.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <sfx2/viewsh.hxx>
|
|
|
|
#include <com/sun/star/lang/XServiceInfo.hpp>
|
|
|
|
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<const SdrObjGroup*>(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<const SdrObjGroup*>( 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<const SdrObjGroup*>(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<SdrObject*>::const_iterator iterPos;
|
|
const std::vector<SdrObject*>& 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<SdrEdgeObj*>( 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; i<nMarkedEdgeCnt; ++i) {
|
|
SdrMark* pEM = GetMarkedEdgesOfMarkedNodes().GetMark(i);
|
|
SdrObject* pEdgeTmp=pEM->GetMarkedSdrObj();
|
|
SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( 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;
|
|
|
|
const SdrMarkList& rMarkList = GetMarkedObjectList();
|
|
ImpResetPossibilityFlags();
|
|
rMarkList.ForceSort();
|
|
const size_t nMarkCount = rMarkList.GetMarkCount();
|
|
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=rMarkList.GetMark(0)->GetMarkedSdrObj();
|
|
//const SdrPathObj* pPath=dynamic_cast<SdrPathObj*>( 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 = rMarkList.GetMark(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; nm<nMarkCount; ++nm) {
|
|
const SdrMark* pM=rMarkList.GetMark(nm);
|
|
const SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
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<SdrPolyEditView*>(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=rMarkList.GetMark(0)->GetMarkedSdrObj();
|
|
SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( 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(rMarkList.GetMark(0)->GetMarkedSdrObj());
|
|
|
|
if(nullptr != pCandidate && pCandidate->isDiagram())
|
|
m_bGrpEnterPossible = false;
|
|
}
|
|
}
|
|
|
|
|
|
void SdrEditView::ForceMarkedObjToAnotherPage()
|
|
{
|
|
const SdrMarkList& rMarkList = GetMarkedObjectList();
|
|
bool bFlg=false;
|
|
for (size_t nm=0; nm<rMarkList.GetMarkCount(); ++nm) {
|
|
SdrMark* pM=rMarkList.GetMark(nm);
|
|
SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
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<rtl::Reference<SdrObject>> SdrEditView::DeleteMarkedList(SdrMarkList const& rMark)
|
|
{
|
|
std::vector<rtl::Reference<SdrObject>> 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<rtl::Reference<SdrObject>> & rLazyDelete)
|
|
{
|
|
// now delete removed scene objects
|
|
while (!rLazyDelete.empty())
|
|
rLazyDelete.pop_back();
|
|
}
|
|
|
|
void SdrEditView::DeleteMarkedObj()
|
|
{
|
|
const SdrMarkList& rMarkList = GetMarkedObjectList();
|
|
// #i110981# return when nothing is to be done at all
|
|
if(!rMarkList.GetMarkCount())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// moved breaking action and undo start outside loop
|
|
BrkAction();
|
|
BegUndo(SvxResId(STR_EditDelete),rMarkList.GetMarkDescription(),SdrRepeatFunc::Delete);
|
|
|
|
std::vector<rtl::Reference<SdrObject>> lazyDeleteObjects;
|
|
// remove as long as something is selected. This allows to schedule objects for
|
|
// removal for a next run as needed
|
|
while(rMarkList.GetMarkCount())
|
|
{
|
|
// vector to remember the parents which may be empty after object removal
|
|
std::vector< SdrObject* > aParents;
|
|
|
|
{
|
|
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(rMarkList));
|
|
lazyDeleteObjects.insert(lazyDeleteObjects.end(), temp.begin(), temp.end());
|
|
GetMarkedObjectListWriteAccess().Clear();
|
|
maHdlList.Clear();
|
|
|
|
while(!aParents.empty() && !rMarkList.GetMarkCount())
|
|
{
|
|
// 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()
|
|
{
|
|
const SdrMarkList& rMarkList = GetMarkedObjectList();
|
|
rMarkList.ForceSort();
|
|
|
|
SdrMarkList aSourceObjectsForCopy(rMarkList);
|
|
// 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<nEdgeCnt; ++nEdgeNum) {
|
|
SdrMark aM(*GetEdgesOfMarkedNodes().GetMark(nEdgeNum));
|
|
aM.SetUser(1);
|
|
aSourceObjectsForCopy.InsertEntry(aM);
|
|
}
|
|
aSourceObjectsForCopy.ForceSort();
|
|
|
|
// #i13033#
|
|
// New mechanism to re-create the connections of cloned connectors
|
|
CloneList aCloneList;
|
|
|
|
const bool bUndo = IsUndoEnabled();
|
|
|
|
GetMarkedObjectListWriteAccess().Clear();
|
|
size_t nCloneErrCnt=0;
|
|
std::unordered_set<rtl::OUString> aNameSet;
|
|
const size_t nMarkCount=aSourceObjectsForCopy.GetMarkCount();
|
|
for (size_t nm=0; nm<nMarkCount; ++nm) {
|
|
SdrMark* pM=aSourceObjectsForCopy.GetMark(nm);
|
|
SdrObject* pSource(pM->GetMarkedSdrObj());
|
|
rtl::Reference<SdrObject> 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<sal_Int32>(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<lang::XServiceInfo> 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<SdrView*>(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<SdrObjEditView*>(pListener);
|
|
if (pView && pView->IsTextEdit())
|
|
pView->SdrEndTextEdit();
|
|
return false;
|
|
});
|
|
}
|
|
|
|
void SdrEditView::EndTextEditCurrentView(bool bDontDeleteReally)
|
|
{
|
|
if (IsTextEdit())
|
|
{
|
|
SdrView* pSdrView = dynamic_cast<SdrView*>(this);
|
|
if (pSdrView)
|
|
pSdrView->SdrEndTextEdit(bDontDeleteReally);
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|