2081 lines
75 KiB
C++
2081 lines
75 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
#include <svx/svdedtv.hxx>
|
|
#include <editeng/outliner.hxx>
|
|
#include <svx/svdundo.hxx>
|
|
#include <svx/svdogrp.hxx> // for grouping objects
|
|
#include <svx/svdovirt.hxx> // for VirtualObject bundling (Writer)
|
|
#include <svx/svdopath.hxx> // for CombineObjects
|
|
#include <svx/svdpage.hxx>
|
|
#include <svx/svdpagv.hxx>
|
|
#include "svx/svditer.hxx"
|
|
#include <svx/svdograf.hxx> // for Possibilities
|
|
#include <svx/svdoole2.hxx> // and Mtf-Import
|
|
#include "svx/svdstr.hrc" // names taken from the resource
|
|
#include "svx/svdglob.hxx" // StringCache
|
|
#include "svdfmtf.hxx"
|
|
#include <svx/svdetc.hxx>
|
|
#include <sfx2/basedlgs.hxx>
|
|
#include <vcl/msgbox.hxx>
|
|
#include <editeng/outlobj.hxx>
|
|
#include <editeng/eeitem.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
|
|
|
#include <svx/svxdlg.hxx>
|
|
#include <svx/dialogs.hrc>
|
|
|
|
// #i37011#
|
|
#include <svx/svdoashp.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
|
|
|
|
#include <vector>
|
|
using ::std::vector;
|
|
|
|
SdrObject* SdrEditView::GetMaxToTopObj(SdrObject* /*pObj*/) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
SdrObject* SdrEditView::GetMaxToBtmObj(SdrObject* /*pObj*/) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void SdrEditView::ObjOrderChanged(SdrObject* /*pObj*/, sal_uIntPtr /*nOldPos*/, sal_uIntPtr /*nNewPos*/)
|
|
{
|
|
}
|
|
|
|
void SdrEditView::MovMarkedToTop()
|
|
{
|
|
sal_uIntPtr nAnz=GetMarkedObjectCount();
|
|
if (nAnz!=0)
|
|
{
|
|
const bool bUndo = IsUndoEnabled();
|
|
|
|
if( bUndo )
|
|
BegUndo(ImpGetResStr(STR_EditMovToTop),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_MOVTOTOP);
|
|
|
|
SortMarkedObjects();
|
|
sal_uIntPtr nm;
|
|
for (nm=0; nm<nAnz; nm++)
|
|
{ // All Ordnums have to be correct!
|
|
GetMarkedObjectByIndex(nm)->GetOrdNum();
|
|
}
|
|
sal_Bool bChg=sal_False;
|
|
SdrObjList* pOL0=NULL;
|
|
sal_uIntPtr nNewPos=0;
|
|
for (nm=nAnz; nm>0;)
|
|
{
|
|
nm--;
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
if (pOL!=pOL0)
|
|
{
|
|
nNewPos=sal_uIntPtr(pOL->GetObjCount()-1);
|
|
pOL0=pOL;
|
|
}
|
|
sal_uIntPtr nNowPos=pObj->GetOrdNumDirect();
|
|
const Rectangle& rBR=pObj->GetCurrentBoundRect();
|
|
sal_uIntPtr nCmpPos=nNowPos+1;
|
|
SdrObject* pMaxObj=GetMaxToTopObj(pObj);
|
|
if (pMaxObj!=NULL)
|
|
{
|
|
sal_uIntPtr nMaxPos=pMaxObj->GetOrdNum();
|
|
if (nMaxPos!=0)
|
|
nMaxPos--;
|
|
if (nNewPos>nMaxPos)
|
|
nNewPos=nMaxPos; // neither go faster...
|
|
if (nNewPos<nNowPos)
|
|
nNewPos=nNowPos; // nor go in the other direction
|
|
}
|
|
sal_Bool bEnd=sal_False;
|
|
while (nCmpPos<nNewPos && !bEnd)
|
|
{
|
|
SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
|
|
if (pCmpObj==NULL)
|
|
{
|
|
OSL_FAIL("MovMarkedToTop(): Reference object not found.");
|
|
bEnd=sal_True;
|
|
}
|
|
else if (pCmpObj==pMaxObj)
|
|
{
|
|
nNewPos=nCmpPos;
|
|
nNewPos--;
|
|
bEnd=sal_True;
|
|
}
|
|
else if (rBR.IsOver(pCmpObj->GetCurrentBoundRect()))
|
|
{
|
|
nNewPos=nCmpPos;
|
|
bEnd=sal_True;
|
|
}
|
|
else
|
|
{
|
|
nCmpPos++;
|
|
}
|
|
}
|
|
if (nNowPos!=nNewPos)
|
|
{
|
|
bChg=sal_True;
|
|
pOL->SetObjectOrdNum(nNowPos,nNewPos);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
|
|
ObjOrderChanged(pObj,nNowPos,nNewPos);
|
|
}
|
|
nNewPos--;
|
|
}
|
|
|
|
if( bUndo )
|
|
EndUndo();
|
|
|
|
if (bChg)
|
|
MarkListHasChanged();
|
|
}
|
|
}
|
|
|
|
void SdrEditView::MovMarkedToBtm()
|
|
{
|
|
sal_uIntPtr nAnz=GetMarkedObjectCount();
|
|
if (nAnz!=0)
|
|
{
|
|
const bool bUndo = IsUndoEnabled();
|
|
|
|
if( bUndo )
|
|
BegUndo(ImpGetResStr(STR_EditMovToBtm),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_MOVTOBTM);
|
|
|
|
SortMarkedObjects();
|
|
sal_uIntPtr nm;
|
|
for (nm=0; nm<nAnz; nm++)
|
|
{ // All Ordnums have to be correct!
|
|
GetMarkedObjectByIndex(nm)->GetOrdNum();
|
|
}
|
|
|
|
sal_Bool bChg=sal_False;
|
|
SdrObjList* pOL0=NULL;
|
|
sal_uIntPtr nNewPos=0;
|
|
for (nm=0; nm<nAnz; nm++)
|
|
{
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
if (pOL!=pOL0)
|
|
{
|
|
nNewPos=0;
|
|
pOL0=pOL;
|
|
}
|
|
sal_uIntPtr nNowPos=pObj->GetOrdNumDirect();
|
|
const Rectangle& rBR=pObj->GetCurrentBoundRect();
|
|
sal_uIntPtr nCmpPos=nNowPos; if (nCmpPos>0) nCmpPos--;
|
|
SdrObject* pMaxObj=GetMaxToBtmObj(pObj);
|
|
if (pMaxObj!=NULL)
|
|
{
|
|
sal_uIntPtr nMinPos=pMaxObj->GetOrdNum()+1;
|
|
if (nNewPos<nMinPos)
|
|
nNewPos=nMinPos; // neither go faster...
|
|
if (nNewPos>nNowPos)
|
|
nNewPos=nNowPos; // nor go in the other direction
|
|
}
|
|
sal_Bool bEnd=sal_False;
|
|
// nNewPos in this case is the "maximum" position
|
|
// the object may reach without going faster than the object before
|
|
// it (multiple selection).
|
|
while (nCmpPos>nNewPos && !bEnd)
|
|
{
|
|
SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
|
|
if (pCmpObj==NULL)
|
|
{
|
|
OSL_FAIL("MovMarkedToBtm(): Reference object not found.");
|
|
bEnd=sal_True;
|
|
}
|
|
else if (pCmpObj==pMaxObj)
|
|
{
|
|
nNewPos=nCmpPos;
|
|
nNewPos++;
|
|
bEnd=sal_True;
|
|
}
|
|
else if (rBR.IsOver(pCmpObj->GetCurrentBoundRect()))
|
|
{
|
|
nNewPos=nCmpPos;
|
|
bEnd=sal_True;
|
|
}
|
|
else
|
|
{
|
|
nCmpPos--;
|
|
}
|
|
}
|
|
if (nNowPos!=nNewPos)
|
|
{
|
|
bChg=sal_True;
|
|
pOL->SetObjectOrdNum(nNowPos,nNewPos);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
|
|
ObjOrderChanged(pObj,nNowPos,nNewPos);
|
|
}
|
|
nNewPos++;
|
|
}
|
|
|
|
if(bUndo)
|
|
EndUndo();
|
|
|
|
if(bChg)
|
|
MarkListHasChanged();
|
|
}
|
|
}
|
|
|
|
void SdrEditView::PutMarkedToTop()
|
|
{
|
|
PutMarkedInFrontOfObj(NULL);
|
|
}
|
|
|
|
void SdrEditView::PutMarkedInFrontOfObj(const SdrObject* pRefObj)
|
|
{
|
|
sal_uIntPtr nAnz=GetMarkedObjectCount();
|
|
if (nAnz!=0)
|
|
{
|
|
const bool bUndo = IsUndoEnabled();
|
|
if( bUndo )
|
|
BegUndo(ImpGetResStr(STR_EditPutToTop),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_PUTTOTOP);
|
|
|
|
SortMarkedObjects();
|
|
|
|
if (pRefObj!=NULL)
|
|
{
|
|
// Make "in front of the object" work, even if the
|
|
// selected objects are already in front of the other object
|
|
sal_uIntPtr nRefMark=TryToFindMarkedObject(pRefObj);
|
|
SdrMark aRefMark;
|
|
if (nRefMark!=CONTAINER_ENTRY_NOTFOUND)
|
|
{
|
|
aRefMark=*GetSdrMarkByIndex(nRefMark);
|
|
GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
|
|
}
|
|
PutMarkedToBtm();
|
|
if (nRefMark!=CONTAINER_ENTRY_NOTFOUND)
|
|
{
|
|
GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
|
|
SortMarkedObjects();
|
|
}
|
|
}
|
|
sal_uIntPtr nm;
|
|
for (nm=0; nm<nAnz; nm++)
|
|
{ // All Ordnums have to be correct!
|
|
GetMarkedObjectByIndex(nm)->GetOrdNum();
|
|
}
|
|
sal_Bool bChg=sal_False;
|
|
SdrObjList* pOL0=NULL;
|
|
sal_uIntPtr nNewPos=0;
|
|
for (nm=nAnz; nm>0;)
|
|
{
|
|
nm--;
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
if (pObj!=pRefObj)
|
|
{
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
if (pOL!=pOL0)
|
|
{
|
|
nNewPos=sal_uIntPtr(pOL->GetObjCount()-1);
|
|
pOL0=pOL;
|
|
}
|
|
sal_uIntPtr nNowPos=pObj->GetOrdNumDirect();
|
|
SdrObject* pMaxObj=GetMaxToTopObj(pObj);
|
|
if (pMaxObj!=NULL)
|
|
{
|
|
sal_uIntPtr nMaxOrd=pMaxObj->GetOrdNum(); // sadly doesn't work any other way
|
|
if (nMaxOrd>0)
|
|
nMaxOrd--;
|
|
if (nNewPos>nMaxOrd)
|
|
nNewPos=nMaxOrd; // neither go faster...
|
|
if (nNewPos<nNowPos)
|
|
nNewPos=nNowPos; // nor go into the other direction
|
|
}
|
|
if (pRefObj!=NULL)
|
|
{
|
|
if (pRefObj->GetObjList()==pObj->GetObjList())
|
|
{
|
|
sal_uIntPtr nMaxOrd=pRefObj->GetOrdNum(); // sadly doesn't work any other way
|
|
if (nNewPos>nMaxOrd)
|
|
nNewPos=nMaxOrd; // neither go faster...
|
|
if (nNewPos<nNowPos)
|
|
nNewPos=nNowPos; // nor go into the other direction
|
|
}
|
|
else
|
|
{
|
|
nNewPos=nNowPos; // different PageView, so don't change
|
|
}
|
|
}
|
|
if (nNowPos!=nNewPos)
|
|
{
|
|
bChg=sal_True;
|
|
pOL->SetObjectOrdNum(nNowPos,nNewPos);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
|
|
ObjOrderChanged(pObj,nNowPos,nNewPos);
|
|
}
|
|
nNewPos--;
|
|
} // if (pObj!=pRefObj)
|
|
} // for loop over all selected objects
|
|
|
|
if( bUndo )
|
|
EndUndo();
|
|
|
|
if(bChg)
|
|
MarkListHasChanged();
|
|
}
|
|
}
|
|
|
|
void SdrEditView::PutMarkedToBtm()
|
|
{
|
|
PutMarkedBehindObj(NULL);
|
|
}
|
|
|
|
void SdrEditView::PutMarkedBehindObj(const SdrObject* pRefObj)
|
|
{
|
|
sal_uIntPtr nAnz=GetMarkedObjectCount();
|
|
if (nAnz!=0)
|
|
{
|
|
const bool bUndo = IsUndoEnabled();
|
|
|
|
if( bUndo )
|
|
BegUndo(ImpGetResStr(STR_EditPutToBtm),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_PUTTOBTM);
|
|
|
|
SortMarkedObjects();
|
|
if (pRefObj!=NULL)
|
|
{
|
|
// Make "behind the object" work, even if the
|
|
// selected objects are already behind the other object
|
|
sal_uIntPtr nRefMark=TryToFindMarkedObject(pRefObj);
|
|
SdrMark aRefMark;
|
|
if (nRefMark!=CONTAINER_ENTRY_NOTFOUND)
|
|
{
|
|
aRefMark=*GetSdrMarkByIndex(nRefMark);
|
|
GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
|
|
}
|
|
PutMarkedToTop();
|
|
if (nRefMark!=CONTAINER_ENTRY_NOTFOUND)
|
|
{
|
|
GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
|
|
SortMarkedObjects();
|
|
}
|
|
}
|
|
sal_uIntPtr nm;
|
|
for (nm=0; nm<nAnz; nm++) { // All Ordnums have to be correct!
|
|
GetMarkedObjectByIndex(nm)->GetOrdNum();
|
|
}
|
|
sal_Bool bChg=sal_False;
|
|
SdrObjList* pOL0=NULL;
|
|
sal_uIntPtr nNewPos=0;
|
|
for (nm=0; nm<nAnz; nm++) {
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
if (pObj!=pRefObj) {
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
if (pOL!=pOL0) {
|
|
nNewPos=0;
|
|
pOL0=pOL;
|
|
}
|
|
sal_uIntPtr nNowPos=pObj->GetOrdNumDirect();
|
|
SdrObject* pMinObj=GetMaxToBtmObj(pObj);
|
|
if (pMinObj!=NULL) {
|
|
sal_uIntPtr nMinOrd=pMinObj->GetOrdNum()+1; // sadly doesn't work any differently
|
|
if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster...
|
|
if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
|
|
}
|
|
if (pRefObj!=NULL) {
|
|
if (pRefObj->GetObjList()==pObj->GetObjList()) {
|
|
sal_uIntPtr nMinOrd=pRefObj->GetOrdNum(); // sadly doesn't work any differently
|
|
if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster...
|
|
if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
|
|
} else {
|
|
nNewPos=nNowPos; // different PageView, so don't change
|
|
}
|
|
}
|
|
if (nNowPos!=nNewPos) {
|
|
bChg=sal_True;
|
|
pOL->SetObjectOrdNum(nNowPos,nNewPos);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
|
|
ObjOrderChanged(pObj,nNowPos,nNewPos);
|
|
}
|
|
nNewPos++;
|
|
} // if (pObj!=pRefObj)
|
|
} // for loop over all selected objects
|
|
|
|
if(bUndo)
|
|
EndUndo();
|
|
|
|
if(bChg)
|
|
MarkListHasChanged();
|
|
}
|
|
}
|
|
|
|
void SdrEditView::ReverseOrderOfMarked()
|
|
{
|
|
SortMarkedObjects();
|
|
sal_uIntPtr nMarkAnz=GetMarkedObjectCount();
|
|
if (nMarkAnz>0)
|
|
{
|
|
//sal_Bool bNeedBundle=sal_False;
|
|
sal_Bool bChg=sal_False;
|
|
|
|
bool bUndo = IsUndoEnabled();
|
|
if( bUndo )
|
|
BegUndo(ImpGetResStr(STR_EditRevOrder),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_REVORDER);
|
|
|
|
sal_uIntPtr a=0;
|
|
do {
|
|
// take into account selection across multiple PageViews
|
|
sal_uIntPtr b=a+1;
|
|
while (b<nMarkAnz && GetSdrPageViewOfMarkedByIndex(b) == GetSdrPageViewOfMarkedByIndex(a)) b++;
|
|
b--;
|
|
SdrObjList* pOL=GetSdrPageViewOfMarkedByIndex(a)->GetObjList();
|
|
sal_uIntPtr c=b;
|
|
if (a<c) { // make sure OrdNums aren't dirty
|
|
GetMarkedObjectByIndex(a)->GetOrdNum();
|
|
}
|
|
while (a<c) {
|
|
SdrObject* pObj1=GetMarkedObjectByIndex(a);
|
|
SdrObject* pObj2=GetMarkedObjectByIndex(c);
|
|
sal_uIntPtr nOrd1=pObj1->GetOrdNumDirect();
|
|
sal_uIntPtr nOrd2=pObj2->GetOrdNumDirect();
|
|
if( bUndo )
|
|
{
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj1,nOrd1,nOrd2));
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj2,nOrd2-1,nOrd1));
|
|
}
|
|
pOL->SetObjectOrdNum(nOrd1,nOrd2);
|
|
// Obj 2 has moved forward by one position, so now nOrd2-1
|
|
pOL->SetObjectOrdNum(nOrd2-1,nOrd1);
|
|
// use Replace instead of SetOrdNum for performance reasons (recalculation of Ordnums)
|
|
a++; c--;
|
|
bChg=sal_True;
|
|
}
|
|
a=b+1;
|
|
} while (a<nMarkAnz);
|
|
|
|
if(bUndo)
|
|
EndUndo();
|
|
|
|
if(bChg)
|
|
MarkListHasChanged();
|
|
}
|
|
}
|
|
|
|
void SdrEditView::ImpCheckToTopBtmPossible()
|
|
{
|
|
sal_uIntPtr nAnz=GetMarkedObjectCount();
|
|
if (nAnz==0)
|
|
return;
|
|
if (nAnz==1)
|
|
{ // special-casing for single selection
|
|
SdrObject* pObj=GetMarkedObjectByIndex(0);
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
sal_uIntPtr nMax=pOL->GetObjCount();
|
|
sal_uIntPtr nMin=0;
|
|
sal_uIntPtr nObjNum=pObj->GetOrdNum();
|
|
SdrObject* pRestrict=GetMaxToTopObj(pObj);
|
|
if (pRestrict!=NULL) {
|
|
sal_uIntPtr nRestrict=pRestrict->GetOrdNum();
|
|
if (nRestrict<nMax) nMax=nRestrict;
|
|
}
|
|
pRestrict=GetMaxToBtmObj(pObj);
|
|
if (pRestrict!=NULL) {
|
|
sal_uIntPtr nRestrict=pRestrict->GetOrdNum();
|
|
if (nRestrict>nMin) nMin=nRestrict;
|
|
}
|
|
bToTopPossible=nObjNum<sal_uIntPtr(nMax-1);
|
|
bToBtmPossible=nObjNum>nMin;
|
|
} else { // multiple selection
|
|
sal_uIntPtr nm=0;
|
|
SdrObjList* pOL0=NULL;
|
|
long nPos0=-1;
|
|
while (!bToBtmPossible && nm<nAnz) { // check 'send to background'
|
|
SdrObject* pObj=GetMarkedObjectByIndex(nm);
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
if (pOL!=pOL0) {
|
|
nPos0=-1;
|
|
pOL0=pOL;
|
|
}
|
|
sal_uIntPtr nPos=pObj->GetOrdNum();
|
|
bToBtmPossible=nPos>sal_uIntPtr(nPos0+1);
|
|
nPos0=long(nPos);
|
|
nm++;
|
|
}
|
|
nm=nAnz;
|
|
pOL0=NULL;
|
|
nPos0=0x7FFFFFFF;
|
|
while (!bToTopPossible && nm>0) { // check 'bring to front'
|
|
nm--;
|
|
SdrObject* pObj=GetMarkedObjectByIndex(nm);
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
if (pOL!=pOL0) {
|
|
nPos0=pOL->GetObjCount();
|
|
pOL0=pOL;
|
|
}
|
|
sal_uIntPtr nPos=pObj->GetOrdNum();
|
|
bToTopPossible=nPos+1<sal_uIntPtr(nPos0);
|
|
nPos0=nPos;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Combine
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SdrEditView::ImpCopyAttributes(const SdrObject* pSource, SdrObject* pDest) const
|
|
{
|
|
if (pSource!=NULL) {
|
|
SdrObjList* pOL=pSource->GetSubList();
|
|
if (pOL!=NULL && !pSource->Is3DObj()) { // get first non-group object from group
|
|
SdrObjListIter aIter(*pOL,IM_DEEPNOGROUPS);
|
|
pSource=aIter.Next();
|
|
}
|
|
}
|
|
|
|
if(pSource && pDest)
|
|
{
|
|
SfxItemSet aSet(pMod->GetItemPool(),
|
|
SDRATTR_START, SDRATTR_NOTPERSIST_FIRST-1,
|
|
SDRATTR_NOTPERSIST_LAST+1, SDRATTR_END,
|
|
EE_ITEMS_START, EE_ITEMS_END,
|
|
0, 0);
|
|
|
|
aSet.Put(pSource->GetMergedItemSet());
|
|
|
|
pDest->ClearMergedItem();
|
|
pDest->SetMergedItemSet(aSet);
|
|
|
|
pDest->NbcSetLayer(pSource->GetLayer());
|
|
pDest->NbcSetStyleSheet(pSource->GetStyleSheet(), sal_True);
|
|
}
|
|
}
|
|
|
|
sal_Bool SdrEditView::ImpCanConvertForCombine1(const SdrObject* pObj) const
|
|
{
|
|
// new condition IsLine() to be able to combine simple Lines
|
|
sal_Bool bIsLine(sal_False);
|
|
|
|
const SdrPathObj* pPath = PTR_CAST(SdrPathObj,pObj);
|
|
|
|
if(pPath)
|
|
{
|
|
bIsLine = pPath->IsLine();
|
|
}
|
|
|
|
SdrObjTransformInfoRec aInfo;
|
|
pObj->TakeObjInfo(aInfo);
|
|
|
|
return (aInfo.bCanConvToPath || aInfo.bCanConvToPoly || bIsLine);
|
|
}
|
|
|
|
sal_Bool SdrEditView::ImpCanConvertForCombine(const SdrObject* pObj) const
|
|
{
|
|
SdrObjList* pOL = pObj->GetSubList();
|
|
|
|
if(pOL && !pObj->Is3DObj())
|
|
{
|
|
SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
|
|
|
|
while(aIter.IsMore())
|
|
{
|
|
SdrObject* pObj1 = aIter.Next();
|
|
|
|
// all members of a group have to be convertible
|
|
if(!ImpCanConvertForCombine1(pObj1))
|
|
{
|
|
return sal_False;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!ImpCanConvertForCombine1(pObj))
|
|
{
|
|
return sal_False;
|
|
}
|
|
}
|
|
|
|
return sal_True;
|
|
}
|
|
|
|
basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon1(const SdrObject* pObj, sal_Bool bCombine) const
|
|
{
|
|
basegfx::B2DPolyPolygon aRetval;
|
|
SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj);
|
|
|
|
if(bCombine && pPath && !pObj->GetOutlinerParaObject())
|
|
{
|
|
aRetval = pPath->GetPathPoly();
|
|
}
|
|
else
|
|
{
|
|
SdrObject* pConvObj = pObj->ConvertToPolyObj(bCombine, sal_False);
|
|
|
|
if(pConvObj)
|
|
{
|
|
SdrObjList* pOL = pConvObj->GetSubList();
|
|
|
|
if(pOL)
|
|
{
|
|
SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
|
|
|
|
while(aIter.IsMore())
|
|
{
|
|
SdrObject* pObj1 = aIter.Next();
|
|
pPath = PTR_CAST(SdrPathObj, pObj1);
|
|
|
|
if(pPath)
|
|
{
|
|
aRetval.append(pPath->GetPathPoly());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPath = PTR_CAST(SdrPathObj, pConvObj);
|
|
|
|
if(pPath)
|
|
{
|
|
aRetval = pPath->GetPathPoly();
|
|
}
|
|
}
|
|
|
|
SdrObject::Free( pConvObj );
|
|
}
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
|
|
basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon(const SdrObject* pObj, sal_Bool bCombine) const
|
|
{
|
|
SdrObjList* pOL = pObj->GetSubList();
|
|
|
|
if(pOL && !pObj->Is3DObj())
|
|
{
|
|
basegfx::B2DPolyPolygon aRetval;
|
|
SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
|
|
|
|
while(aIter.IsMore())
|
|
{
|
|
SdrObject* pObj1 = aIter.Next();
|
|
aRetval.append(ImpGetPolyPolygon1(pObj1, bCombine));
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
else
|
|
{
|
|
return ImpGetPolyPolygon1(pObj, bCombine);
|
|
}
|
|
}
|
|
|
|
basegfx::B2DPolygon SdrEditView::ImpCombineToSinglePolygon(const basegfx::B2DPolyPolygon& rPolyPolygon) const
|
|
{
|
|
const sal_uInt32 nPolyCount(rPolyPolygon.count());
|
|
|
|
if(0L == nPolyCount)
|
|
{
|
|
return basegfx::B2DPolygon();
|
|
}
|
|
else if(1L == nPolyCount)
|
|
{
|
|
return rPolyPolygon.getB2DPolygon(0L);
|
|
}
|
|
else
|
|
{
|
|
basegfx::B2DPolygon aRetval(rPolyPolygon.getB2DPolygon(0L));
|
|
|
|
for(sal_uInt32 a(1L); a < nPolyCount; a++)
|
|
{
|
|
basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
|
|
|
|
if(aRetval.count())
|
|
{
|
|
if(aCandidate.count())
|
|
{
|
|
const basegfx::B2DPoint aCA(aCandidate.getB2DPoint(0L));
|
|
const basegfx::B2DPoint aCB(aCandidate.getB2DPoint(aCandidate.count() - 1L));
|
|
const basegfx::B2DPoint aRA(aRetval.getB2DPoint(0L));
|
|
const basegfx::B2DPoint aRB(aRetval.getB2DPoint(aRetval.count() - 1L));
|
|
|
|
const double fRACA(basegfx::B2DVector(aCA - aRA).getLength());
|
|
const double fRACB(basegfx::B2DVector(aCB - aRA).getLength());
|
|
const double fRBCA(basegfx::B2DVector(aCA - aRB).getLength());
|
|
const double fRBCB(basegfx::B2DVector(aCB - aRB).getLength());
|
|
|
|
const double fSmallestRA(fRACA < fRACB ? fRACA : fRACB);
|
|
const double fSmallestRB(fRBCA < fRBCB ? fRBCA : fRBCB);
|
|
|
|
if(fSmallestRA < fSmallestRB)
|
|
{
|
|
// flip result
|
|
aRetval.flip();
|
|
}
|
|
|
|
const double fSmallestCA(fRACA < fRBCA ? fRACA : fRBCA);
|
|
const double fSmallestCB(fRACB < fRBCB ? fRACB : fRBCB);
|
|
|
|
if(fSmallestCB < fSmallestCA)
|
|
{
|
|
// flip candidate
|
|
aCandidate.flip();
|
|
}
|
|
|
|
// append candidate to retval
|
|
aRetval.append(aCandidate);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aRetval = aCandidate;
|
|
}
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
}
|
|
|
|
// for distribution dialog function
|
|
struct ImpDistributeEntry
|
|
{
|
|
SdrObject* mpObj;
|
|
sal_Int32 mnPos;
|
|
sal_Int32 mnLength;
|
|
};
|
|
|
|
typedef vector< ImpDistributeEntry*> ImpDistributeEntryList;
|
|
|
|
void SdrEditView::DistributeMarkedObjects()
|
|
{
|
|
sal_uInt32 nMark(GetMarkedObjectCount());
|
|
|
|
if(nMark > 2)
|
|
{
|
|
SfxItemSet aNewAttr(pMod->GetItemPool());
|
|
|
|
SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
|
|
if(pFact)
|
|
{
|
|
AbstractSvxDistributeDialog *pDlg = pFact->CreateSvxDistributeDialog(NULL, aNewAttr);
|
|
DBG_ASSERT(pDlg, "Dialogdiet fail!");
|
|
|
|
sal_uInt16 nResult = pDlg->Execute();
|
|
|
|
if(nResult == RET_OK)
|
|
{
|
|
SvxDistributeHorizontal eHor = pDlg->GetDistributeHor();
|
|
SvxDistributeVertical eVer = pDlg->GetDistributeVer();
|
|
ImpDistributeEntryList aEntryList;
|
|
ImpDistributeEntryList::iterator itEntryList;
|
|
sal_uInt32 nFullLength;
|
|
|
|
const bool bUndo = IsUndoEnabled();
|
|
if( bUndo )
|
|
BegUndo();
|
|
|
|
if(eHor != SvxDistributeHorizontalNone)
|
|
{
|
|
// build sorted entry list
|
|
nFullLength = 0L;
|
|
|
|
for( sal_uInt32 a = 0; a < nMark; a++ )
|
|
{
|
|
SdrMark* pMark = GetSdrMarkByIndex(a);
|
|
ImpDistributeEntry* pNew = new ImpDistributeEntry;
|
|
|
|
pNew->mpObj = pMark->GetMarkedSdrObj();
|
|
|
|
switch(eHor)
|
|
{
|
|
case SvxDistributeHorizontalLeft:
|
|
{
|
|
pNew->mnPos = pNew->mpObj->GetSnapRect().Left();
|
|
break;
|
|
}
|
|
case SvxDistributeHorizontalCenter:
|
|
{
|
|
pNew->mnPos = (pNew->mpObj->GetSnapRect().Right() + pNew->mpObj->GetSnapRect().Left()) / 2;
|
|
break;
|
|
}
|
|
case SvxDistributeHorizontalDistance:
|
|
{
|
|
pNew->mnLength = pNew->mpObj->GetSnapRect().GetWidth() + 1;
|
|
nFullLength += pNew->mnLength;
|
|
pNew->mnPos = (pNew->mpObj->GetSnapRect().Right() + pNew->mpObj->GetSnapRect().Left()) / 2;
|
|
break;
|
|
}
|
|
case SvxDistributeHorizontalRight:
|
|
{
|
|
pNew->mnPos = pNew->mpObj->GetSnapRect().Right();
|
|
break;
|
|
}
|
|
default: break;
|
|
}
|
|
|
|
for ( itEntryList = aEntryList.begin();
|
|
itEntryList < aEntryList.end() && (*itEntryList)->mnPos < pNew->mnPos;
|
|
++itEntryList )
|
|
{};
|
|
if ( itEntryList < aEntryList.end() )
|
|
aEntryList.insert( itEntryList, pNew );
|
|
else
|
|
aEntryList.push_back( pNew );
|
|
}
|
|
|
|
if(eHor == SvxDistributeHorizontalDistance)
|
|
{
|
|
// calculate room in-between
|
|
sal_Int32 nWidth = GetAllMarkedBoundRect().GetWidth() + 1;
|
|
double fStepWidth = ((double)nWidth - (double)nFullLength) / (double)(aEntryList.size() - 1);
|
|
double fStepStart = (double)aEntryList[ 0 ]->mnPos;
|
|
fStepStart += fStepWidth + (double)((aEntryList[ 0 ]->mnLength + aEntryList[ 1 ]->mnLength) / 2);
|
|
|
|
// move entries 1..n-1
|
|
for( size_t i = 1, n = aEntryList.size()-1; i < n; ++i )
|
|
{
|
|
ImpDistributeEntry* pCurr = aEntryList[ i ];
|
|
ImpDistributeEntry* pNext = aEntryList[ i + 1];
|
|
sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
|
|
pCurr->mpObj->Move(Size(nDelta, 0));
|
|
fStepStart += fStepWidth + (double)((pCurr->mnLength + pNext->mnLength) / 2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// calculate distances
|
|
sal_Int32 nWidth = aEntryList[ aEntryList.size() - 1 ]->mnPos - aEntryList[ 0 ]->mnPos;
|
|
double fStepWidth = (double)nWidth / (double)(aEntryList.size() - 1);
|
|
double fStepStart = (double)aEntryList[ 0 ]->mnPos;
|
|
fStepStart += fStepWidth;
|
|
|
|
// move entries 1..n-1
|
|
for( size_t i = 1 ; i < aEntryList.size()-1 ; ++i )
|
|
{
|
|
ImpDistributeEntry* pCurr = aEntryList[ i ];
|
|
sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
|
|
pCurr->mpObj->Move(Size(nDelta, 0));
|
|
fStepStart += fStepWidth;
|
|
}
|
|
}
|
|
|
|
// clear list
|
|
for ( size_t i = 0, n = aEntryList.size(); i < n; ++i )
|
|
delete aEntryList[ i ];
|
|
aEntryList.clear();
|
|
}
|
|
|
|
if(eVer != SvxDistributeVerticalNone)
|
|
{
|
|
// build sorted entry list
|
|
nFullLength = 0L;
|
|
|
|
for( sal_uInt32 a = 0; a < nMark; a++ )
|
|
{
|
|
SdrMark* pMark = GetSdrMarkByIndex(a);
|
|
ImpDistributeEntry* pNew = new ImpDistributeEntry;
|
|
|
|
pNew->mpObj = pMark->GetMarkedSdrObj();
|
|
|
|
switch(eVer)
|
|
{
|
|
case SvxDistributeVerticalTop:
|
|
{
|
|
pNew->mnPos = pNew->mpObj->GetSnapRect().Top();
|
|
break;
|
|
}
|
|
case SvxDistributeVerticalCenter:
|
|
{
|
|
pNew->mnPos = (pNew->mpObj->GetSnapRect().Bottom() + pNew->mpObj->GetSnapRect().Top()) / 2;
|
|
break;
|
|
}
|
|
case SvxDistributeVerticalDistance:
|
|
{
|
|
pNew->mnLength = pNew->mpObj->GetSnapRect().GetHeight() + 1;
|
|
nFullLength += pNew->mnLength;
|
|
pNew->mnPos = (pNew->mpObj->GetSnapRect().Bottom() + pNew->mpObj->GetSnapRect().Top()) / 2;
|
|
break;
|
|
}
|
|
case SvxDistributeVerticalBottom:
|
|
{
|
|
pNew->mnPos = pNew->mpObj->GetSnapRect().Bottom();
|
|
break;
|
|
}
|
|
default: break;
|
|
}
|
|
|
|
for ( itEntryList = aEntryList.begin();
|
|
itEntryList < aEntryList.end() && (*itEntryList)->mnPos < pNew->mnPos;
|
|
++itEntryList )
|
|
{};
|
|
if ( itEntryList < aEntryList.end() )
|
|
aEntryList.insert( itEntryList, pNew );
|
|
else
|
|
aEntryList.push_back( pNew );
|
|
}
|
|
|
|
if(eVer == SvxDistributeVerticalDistance)
|
|
{
|
|
// calculate room in-between
|
|
sal_Int32 nHeight = GetAllMarkedBoundRect().GetHeight() + 1;
|
|
double fStepWidth = ((double)nHeight - (double)nFullLength) / (double)(aEntryList.size() - 1);
|
|
double fStepStart = (double)aEntryList[ 0 ]->mnPos;
|
|
fStepStart += fStepWidth + (double)((aEntryList[ 0 ]->mnLength + aEntryList[ 1 ]->mnLength) / 2);
|
|
|
|
// move entries 1..n-1
|
|
for( size_t i = 1, n = aEntryList.size()-1; i < n; ++i)
|
|
{
|
|
ImpDistributeEntry* pCurr = aEntryList[ i ];
|
|
ImpDistributeEntry* pNext = aEntryList[ i + 1 ];
|
|
sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
|
|
pCurr->mpObj->Move(Size(0, nDelta));
|
|
fStepStart += fStepWidth + (double)((pCurr->mnLength + pNext->mnLength) / 2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// calculate distances
|
|
sal_Int32 nHeight = aEntryList[ aEntryList.size() - 1 ]->mnPos - aEntryList[ 0 ]->mnPos;
|
|
double fStepWidth = (double)nHeight / (double)(aEntryList.size() - 1);
|
|
double fStepStart = (double)aEntryList[ 0 ]->mnPos;
|
|
fStepStart += fStepWidth;
|
|
|
|
// move entries 1..n-1
|
|
for(size_t i = 1, n = aEntryList.size()-1; i < n; ++i)
|
|
{
|
|
ImpDistributeEntry* pCurr = aEntryList[ i ];
|
|
sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
|
|
pCurr->mpObj->Move(Size(0, nDelta));
|
|
fStepStart += fStepWidth;
|
|
}
|
|
}
|
|
|
|
// clear list
|
|
for ( size_t i = 0, n = aEntryList.size(); i < n; ++i )
|
|
delete aEntryList[ i ];
|
|
aEntryList.clear();
|
|
}
|
|
|
|
// UNDO-Comment and end of UNDO
|
|
SetUndoComment(ImpGetResStr(STR_DistributeMarkedObjects));
|
|
|
|
if( bUndo )
|
|
EndUndo();
|
|
}
|
|
|
|
delete(pDlg);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode)
|
|
{
|
|
// #i73441# check content
|
|
if(AreObjectsMarked())
|
|
{
|
|
SdrMarkList aRemove;
|
|
SortMarkedObjects();
|
|
|
|
const bool bUndo = IsUndoEnabled();
|
|
|
|
if( bUndo )
|
|
BegUndo();
|
|
|
|
sal_uInt32 nInsPos=0xFFFFFFFF;
|
|
const SdrObject* pAttrObj = NULL;
|
|
basegfx::B2DPolyPolygon aMergePolyPolygonA;
|
|
basegfx::B2DPolyPolygon aMergePolyPolygonB;
|
|
|
|
SdrObjList* pInsOL = NULL;
|
|
SdrPageView* pInsPV = NULL;
|
|
sal_Bool bFirstObjectComplete(sal_False);
|
|
|
|
// make sure selected objects are contour objects
|
|
// since now basegfx::tools::adaptiveSubdivide() is used, it is no longer
|
|
// necessary to use ConvertMarkedToPolyObj which will subdivide curves using the old
|
|
// mechanisms. In a next step the polygon clipper will even be able to clip curves...
|
|
// ConvertMarkedToPolyObj(sal_True);
|
|
ConvertMarkedToPathObj(sal_True);
|
|
OSL_ENSURE(AreObjectsMarked(), "no more objects selected after preparations (!)");
|
|
|
|
for(sal_uInt32 a=0;a<GetMarkedObjectCount();a++)
|
|
{
|
|
SdrMark* pM = GetSdrMarkByIndex(a);
|
|
SdrObject* pObj = pM->GetMarkedSdrObj();
|
|
|
|
if(ImpCanConvertForCombine(pObj))
|
|
{
|
|
if(!pAttrObj)
|
|
pAttrObj = pObj;
|
|
|
|
nInsPos = pObj->GetOrdNum() + 1;
|
|
pInsPV = pM->GetPageView();
|
|
pInsOL = pObj->GetObjList();
|
|
|
|
// #i76891# use single iteration from SJ here which works on SdrObjects and takes
|
|
// groups into account by itself
|
|
SdrObjListIter aIter(*pObj, IM_DEEPWITHGROUPS);
|
|
|
|
while(aIter.IsMore())
|
|
{
|
|
SdrObject* pCandidate = aIter.Next();
|
|
SdrPathObj* pPathObj = PTR_CAST(SdrPathObj, pCandidate);
|
|
if(pPathObj)
|
|
{
|
|
basegfx::B2DPolyPolygon aTmpPoly(pPathObj->GetPathPoly());
|
|
|
|
// #i76891# unfortunately ConvertMarkedToPathObj has converted all
|
|
// involved polygon data to curve segments, even if not necessary.
|
|
// It is better to try to reduce to more simple polygons.
|
|
aTmpPoly = basegfx::tools::simplifyCurveSegments(aTmpPoly);
|
|
|
|
// for each part polygon as preparation, remove self-intersections
|
|
// correct orientations and get rid of possible neutral polygons.
|
|
aTmpPoly = basegfx::tools::prepareForPolygonOperation(aTmpPoly);
|
|
|
|
if(!bFirstObjectComplete)
|
|
{
|
|
// #i111987# Also need to collect ORed source shape when more than
|
|
// a single polygon is involved
|
|
if(aMergePolyPolygonA.count())
|
|
{
|
|
aMergePolyPolygonA = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA, aTmpPoly);
|
|
}
|
|
else
|
|
{
|
|
aMergePolyPolygonA = aTmpPoly;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(aMergePolyPolygonB.count())
|
|
{
|
|
// to topologically correctly collect the 2nd polygon
|
|
// group it is necessary to OR the parts (each is seen as
|
|
// XOR-FillRule polygon and they are drawn over each-other)
|
|
aMergePolyPolygonB = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonB, aTmpPoly);
|
|
}
|
|
else
|
|
{
|
|
aMergePolyPolygonB = aTmpPoly;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// was there something added to the first polygon?
|
|
if(!bFirstObjectComplete && aMergePolyPolygonA.count())
|
|
{
|
|
bFirstObjectComplete = sal_True;
|
|
}
|
|
|
|
// move object to temporary delete list
|
|
aRemove.InsertEntry(SdrMark(pObj, pM->GetPageView()));
|
|
}
|
|
}
|
|
|
|
switch(eMode)
|
|
{
|
|
case SDR_MERGE_MERGE:
|
|
{
|
|
// merge all contained parts (OR)
|
|
static bool bTestXOR(false);
|
|
if(bTestXOR)
|
|
{
|
|
aMergePolyPolygonA = basegfx::tools::solvePolygonOperationXor(aMergePolyPolygonA, aMergePolyPolygonB);
|
|
}
|
|
else
|
|
{
|
|
aMergePolyPolygonA = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA, aMergePolyPolygonB);
|
|
}
|
|
break;
|
|
}
|
|
case SDR_MERGE_SUBSTRACT:
|
|
{
|
|
// Substract B from A
|
|
aMergePolyPolygonA = basegfx::tools::solvePolygonOperationDiff(aMergePolyPolygonA, aMergePolyPolygonB);
|
|
break;
|
|
}
|
|
case SDR_MERGE_INTERSECT:
|
|
{
|
|
// AND B and A
|
|
aMergePolyPolygonA = basegfx::tools::solvePolygonOperationAnd(aMergePolyPolygonA, aMergePolyPolygonB);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// #i73441# check insert list before taking actions
|
|
if(pInsOL)
|
|
{
|
|
SdrPathObj* pPath = new SdrPathObj(OBJ_PATHFILL, aMergePolyPolygonA);
|
|
ImpCopyAttributes(pAttrObj, pPath);
|
|
SdrInsertReason aReason(SDRREASON_VIEWCALL, pAttrObj);
|
|
pInsOL->InsertObject(pPath, nInsPos, &aReason);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath));
|
|
MarkObj(pPath, pInsPV, sal_False, sal_True);
|
|
}
|
|
|
|
aRemove.ForceSort();
|
|
switch(eMode)
|
|
{
|
|
case SDR_MERGE_MERGE:
|
|
{
|
|
SetUndoComment(
|
|
ImpGetResStr(STR_EditMergeMergePoly),
|
|
aRemove.GetMarkDescription());
|
|
break;
|
|
}
|
|
case SDR_MERGE_SUBSTRACT:
|
|
{
|
|
SetUndoComment(
|
|
ImpGetResStr(STR_EditMergeSubstractPoly),
|
|
aRemove.GetMarkDescription());
|
|
break;
|
|
}
|
|
case SDR_MERGE_INTERSECT:
|
|
{
|
|
SetUndoComment(
|
|
ImpGetResStr(STR_EditMergeIntersectPoly),
|
|
aRemove.GetMarkDescription());
|
|
break;
|
|
}
|
|
}
|
|
DeleteMarkedList(aRemove);
|
|
|
|
if( bUndo )
|
|
EndUndo();
|
|
}
|
|
}
|
|
|
|
void SdrEditView::CombineMarkedObjects(sal_Bool bNoPolyPoly)
|
|
{
|
|
// #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would
|
|
// create a 2nd Undo-action and Undo-Comment.
|
|
|
|
bool bUndo = IsUndoEnabled();
|
|
|
|
// Undo-String will be set later
|
|
if( bUndo )
|
|
BegUndo(String(), String(), bNoPolyPoly ? SDRREPFUNC_OBJ_COMBINE_ONEPOLY : SDRREPFUNC_OBJ_COMBINE_POLYPOLY);
|
|
|
|
// #105899# First, guarantee that all objects are converted to polyobjects,
|
|
// especially for SdrGrafObj with bitmap filling this is necessary to not
|
|
// loose the bitmap filling.
|
|
|
|
// #i12392#
|
|
// ConvertMarkedToPolyObj was too strong here, it will loose quality and
|
|
// information when curve objects are combined. This can be replaced by
|
|
// using ConvertMarkedToPathObj without changing the previous fix.
|
|
|
|
// #i21250#
|
|
// Instead of simply passing sal_True as LineToArea, use bNoPolyPoly as info
|
|
// if this command is a 'Combine' or a 'Connect' command. On Connect it's sal_True.
|
|
// To not concert line segments with a set line width to polygons in that case,
|
|
// use this info. Do not convert LineToArea on Connect commands.
|
|
// ConvertMarkedToPathObj(!bNoPolyPoly);
|
|
|
|
// This is used for Combine and Connect. In no case it is necessary to force
|
|
// the content to curve, but it is also not good to force to polygons. Thus,
|
|
// curve is the less information loosing one. Remember: This place is not
|
|
// used for merge.
|
|
// LineToArea is never necessary, both commands are able to take over the
|
|
// set line style and to display it correctly. Thus, i will use a
|
|
// ConvertMarkedToPathObj with a sal_False in any case. Only drawback is that
|
|
// simple polygons will be changed to curves, but with no information loss.
|
|
ConvertMarkedToPathObj(sal_False /* bLineToArea */);
|
|
|
|
// continue as before
|
|
basegfx::B2DPolyPolygon aPolyPolygon;
|
|
SdrObjList* pAktOL = 0L;
|
|
SdrMarkList aRemoveMerker;
|
|
|
|
SortMarkedObjects();
|
|
sal_uInt32 nInsPos(0xFFFFFFFF);
|
|
SdrObjList* pInsOL = 0L;
|
|
SdrPageView* pInsPV = 0L;
|
|
const sal_uInt32 nAnz(GetMarkedObjectCount());
|
|
const SdrObject* pAttrObj = 0L;
|
|
|
|
for(sal_uInt32 a(nAnz); a > 0L; )
|
|
{
|
|
a--;
|
|
SdrMark* pM = GetSdrMarkByIndex(a);
|
|
SdrObject* pObj = pM->GetMarkedSdrObj();
|
|
SdrObjList* pThisOL = pObj->GetObjList();
|
|
|
|
if(pAktOL != pThisOL)
|
|
{
|
|
pAktOL = pThisOL;
|
|
}
|
|
|
|
if(ImpCanConvertForCombine(pObj))
|
|
{
|
|
// remember objects to be able to copy attributes
|
|
pAttrObj = pObj;
|
|
|
|
// unfortunately ConvertMarkedToPathObj has converted all
|
|
// involved polygon data to curve segments, even if not necessary.
|
|
// It is better to try to reduce to more simple polygons.
|
|
basegfx::B2DPolyPolygon aTmpPoly(basegfx::tools::simplifyCurveSegments(ImpGetPolyPolygon(pObj, sal_True)));
|
|
aPolyPolygon.insert(0L, aTmpPoly);
|
|
|
|
if(!pInsOL)
|
|
{
|
|
nInsPos = pObj->GetOrdNum() + 1L;
|
|
pInsPV = pM->GetPageView();
|
|
pInsOL = pObj->GetObjList();
|
|
}
|
|
|
|
aRemoveMerker.InsertEntry(SdrMark(pObj, pM->GetPageView()));
|
|
}
|
|
}
|
|
|
|
if(bNoPolyPoly)
|
|
{
|
|
basegfx::B2DPolygon aCombinedPolygon(ImpCombineToSinglePolygon(aPolyPolygon));
|
|
aPolyPolygon.clear();
|
|
aPolyPolygon.append(aCombinedPolygon);
|
|
}
|
|
|
|
const sal_uInt32 nPolyCount(aPolyPolygon.count());
|
|
|
|
if(nPolyCount)
|
|
{
|
|
SdrObjKind eKind = OBJ_PATHFILL;
|
|
|
|
if(nPolyCount > 1L)
|
|
{
|
|
aPolyPolygon.setClosed(true);
|
|
}
|
|
else
|
|
{
|
|
// check for Polyline
|
|
const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0L));
|
|
const sal_uInt32 nPointCount(aPolygon.count());
|
|
|
|
if(nPointCount <= 2L)
|
|
{
|
|
eKind = OBJ_PATHLINE;
|
|
}
|
|
else
|
|
{
|
|
if(!aPolygon.isClosed())
|
|
{
|
|
const basegfx::B2DPoint aPointA(aPolygon.getB2DPoint(0L));
|
|
const basegfx::B2DPoint aPointB(aPolygon.getB2DPoint(nPointCount - 1L));
|
|
const double fDistance(basegfx::B2DVector(aPointB - aPointA).getLength());
|
|
const double fJoinTolerance(10.0);
|
|
|
|
if(fDistance < fJoinTolerance)
|
|
{
|
|
aPolyPolygon.setClosed(true);
|
|
}
|
|
else
|
|
{
|
|
eKind = OBJ_PATHLINE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SdrPathObj* pPath = new SdrPathObj(eKind,aPolyPolygon);
|
|
|
|
// attributes of the lowest object
|
|
ImpCopyAttributes(pAttrObj, pPath);
|
|
|
|
// If LineStyle of pAttrObj is XLINE_NONE force to XLINE_SOLID to make visible.
|
|
const XLineStyle eLineStyle = ((const XLineStyleItem&)pAttrObj->GetMergedItem(XATTR_LINESTYLE)).GetValue();
|
|
const XFillStyle eFillStyle = ((const XFillStyleItem&)pAttrObj->GetMergedItem(XATTR_FILLSTYLE)).GetValue();
|
|
|
|
// Take fill style/closed state of pAttrObj in account when deciding to change the line style
|
|
sal_Bool bIsClosedPathObj(pAttrObj->ISA(SdrPathObj) && ((SdrPathObj*)pAttrObj)->IsClosed());
|
|
|
|
if(XLINE_NONE == eLineStyle && (XFILL_NONE == eFillStyle || !bIsClosedPathObj))
|
|
{
|
|
pPath->SetMergedItem(XLineStyleItem(XLINE_SOLID));
|
|
}
|
|
|
|
SdrInsertReason aReason(SDRREASON_VIEWCALL,pAttrObj);
|
|
pInsOL->InsertObject(pPath,nInsPos,&aReason);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath));
|
|
|
|
// Here was a severe error: Without UnmarkAllObj, the new object was marked
|
|
// additionally to the two ones which are deleted below. As long as those are
|
|
// in the UNDO there is no problem, but as soon as they get deleted, the
|
|
// MarkList will contain deleted objects -> GPF.
|
|
UnmarkAllObj(pInsPV);
|
|
MarkObj(pPath, pInsPV, sal_False, sal_True);
|
|
}
|
|
|
|
// build an UndoComment from the objects actually used
|
|
aRemoveMerker.ForceSort(); // important for remove (see below)
|
|
if( bUndo )
|
|
SetUndoComment(ImpGetResStr(bNoPolyPoly?STR_EditCombine_OnePoly:STR_EditCombine_PolyPoly),aRemoveMerker.GetMarkDescription());
|
|
|
|
// remove objects actually used from the list
|
|
DeleteMarkedList(aRemoveMerker);
|
|
if( bUndo )
|
|
EndUndo();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Dismantle
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
sal_Bool SdrEditView::ImpCanDismantle(const basegfx::B2DPolyPolygon& rPpolyPolygon, sal_Bool bMakeLines) const
|
|
{
|
|
sal_Bool bCan(sal_False);
|
|
const sal_uInt32 nPolygonCount(rPpolyPolygon.count());
|
|
|
|
if(nPolygonCount >= 2L)
|
|
{
|
|
// #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
|
|
bCan = sal_True;
|
|
}
|
|
else if(bMakeLines && 1L == nPolygonCount)
|
|
{
|
|
// #i69172# ..or with at least 2 edges (curves or lines)
|
|
const basegfx::B2DPolygon aPolygon(rPpolyPolygon.getB2DPolygon(0L));
|
|
const sal_uInt32 nPointCount(aPolygon.count());
|
|
|
|
if(nPointCount > 2L)
|
|
{
|
|
bCan = sal_True;
|
|
}
|
|
}
|
|
|
|
return bCan;
|
|
}
|
|
|
|
sal_Bool SdrEditView::ImpCanDismantle(const SdrObject* pObj, sal_Bool bMakeLines) const
|
|
{
|
|
sal_Bool bOtherObjs(sal_False); // sal_True=objects other than PathObj's existent
|
|
sal_Bool bMin1PolyPoly(sal_False); // sal_True=at least 1 PolyPolygon with more than one Polygon existent
|
|
SdrObjList* pOL = pObj->GetSubList();
|
|
|
|
if(pOL)
|
|
{
|
|
// group object -- check all members if they're PathObjs
|
|
SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
|
|
|
|
while(aIter.IsMore() && !bOtherObjs)
|
|
{
|
|
const SdrObject* pObj1 = aIter.Next();
|
|
const SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj1);
|
|
|
|
if(pPath)
|
|
{
|
|
if(ImpCanDismantle(pPath->GetPathPoly(), bMakeLines))
|
|
{
|
|
bMin1PolyPoly = sal_True;
|
|
}
|
|
|
|
SdrObjTransformInfoRec aInfo;
|
|
pObj1->TakeObjInfo(aInfo);
|
|
|
|
if(!aInfo.bCanConvToPath)
|
|
{
|
|
// happens e. g. in the case of FontWork
|
|
bOtherObjs = sal_True;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bOtherObjs = sal_True;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj);
|
|
const SdrObjCustomShape* pCustomShape = PTR_CAST(SdrObjCustomShape, pObj);
|
|
|
|
// #i37011#
|
|
if(pPath)
|
|
{
|
|
if(ImpCanDismantle(pPath->GetPathPoly(),bMakeLines))
|
|
{
|
|
bMin1PolyPoly = sal_True;
|
|
}
|
|
|
|
SdrObjTransformInfoRec aInfo;
|
|
pObj->TakeObjInfo(aInfo);
|
|
|
|
// new condition IsLine() to be able to break simple Lines
|
|
if(!(aInfo.bCanConvToPath || aInfo.bCanConvToPoly) && !pPath->IsLine())
|
|
{
|
|
// happens e. g. in the case of FontWork
|
|
bOtherObjs = sal_True;
|
|
}
|
|
}
|
|
else if(pCustomShape)
|
|
{
|
|
if(bMakeLines)
|
|
{
|
|
// allow break command
|
|
bMin1PolyPoly = sal_True;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bOtherObjs = sal_True;
|
|
}
|
|
}
|
|
return bMin1PolyPoly && !bOtherObjs;
|
|
}
|
|
|
|
void SdrEditView::ImpDismantleOneObject(const SdrObject* pObj, SdrObjList& rOL, sal_uIntPtr& rPos, SdrPageView* pPV, sal_Bool bMakeLines)
|
|
{
|
|
const SdrPathObj* pSrcPath = PTR_CAST(SdrPathObj, pObj);
|
|
const SdrObjCustomShape* pCustomShape = PTR_CAST(SdrObjCustomShape, pObj);
|
|
|
|
const bool bUndo = IsUndoEnabled();
|
|
|
|
if(pSrcPath)
|
|
{
|
|
// #i74631# redesigned due to XpolyPolygon removal and explicit constructors
|
|
SdrObject* pLast = 0; // to be able to apply OutlinerParaObject
|
|
const basegfx::B2DPolyPolygon& rPolyPolygon(pSrcPath->GetPathPoly());
|
|
const sal_uInt32 nPolyCount(rPolyPolygon.count());
|
|
|
|
for(sal_uInt32 a(0); a < nPolyCount; a++)
|
|
{
|
|
const basegfx::B2DPolygon& rCandidate(rPolyPolygon.getB2DPolygon(a));
|
|
const sal_uInt32 nPointCount(rCandidate.count());
|
|
|
|
if(!bMakeLines || nPointCount < 2)
|
|
{
|
|
SdrPathObj* pPath = new SdrPathObj((SdrObjKind)pSrcPath->GetObjIdentifier(), basegfx::B2DPolyPolygon(rCandidate));
|
|
ImpCopyAttributes(pSrcPath, pPath);
|
|
pLast = pPath;
|
|
SdrInsertReason aReason(SDRREASON_VIEWCALL, pSrcPath);
|
|
rOL.InsertObject(pPath, rPos, &aReason);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, sal_True));
|
|
MarkObj(pPath, pPV, sal_False, sal_True);
|
|
rPos++;
|
|
}
|
|
else
|
|
{
|
|
const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
|
|
|
|
for(sal_uInt32 b(0); b < nLoopCount; b++)
|
|
{
|
|
SdrObjKind eKind(OBJ_PLIN);
|
|
basegfx::B2DPolygon aNewPolygon;
|
|
const sal_uInt32 nNextIndex((b + 1) % nPointCount);
|
|
|
|
aNewPolygon.append(rCandidate.getB2DPoint(b));
|
|
|
|
if(rCandidate.areControlPointsUsed())
|
|
{
|
|
aNewPolygon.appendBezierSegment(
|
|
rCandidate.getNextControlPoint(b),
|
|
rCandidate.getPrevControlPoint(nNextIndex),
|
|
rCandidate.getB2DPoint(nNextIndex));
|
|
eKind = OBJ_PATHLINE;
|
|
}
|
|
else
|
|
{
|
|
aNewPolygon.append(rCandidate.getB2DPoint(nNextIndex));
|
|
}
|
|
|
|
SdrPathObj* pPath = new SdrPathObj(eKind, basegfx::B2DPolyPolygon(aNewPolygon));
|
|
ImpCopyAttributes(pSrcPath, pPath);
|
|
pLast = pPath;
|
|
SdrInsertReason aReason(SDRREASON_VIEWCALL, pSrcPath);
|
|
rOL.InsertObject(pPath, rPos, &aReason);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, sal_True));
|
|
MarkObj(pPath, pPV, sal_False, sal_True);
|
|
rPos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pLast && pSrcPath->GetOutlinerParaObject())
|
|
{
|
|
pLast->SetOutlinerParaObject(new OutlinerParaObject(*pSrcPath->GetOutlinerParaObject()));
|
|
}
|
|
}
|
|
else if(pCustomShape)
|
|
{
|
|
if(bMakeLines)
|
|
{
|
|
// break up custom shape
|
|
const SdrObject* pReplacement = pCustomShape->GetSdrObjectFromCustomShape();
|
|
|
|
if(pReplacement)
|
|
{
|
|
SdrObject* pCandidate = pReplacement->Clone();
|
|
DBG_ASSERT(pCandidate, "SdrEditView::ImpDismantleOneObject: Could not clone SdrObject (!)");
|
|
pCandidate->SetModel(pCustomShape->GetModel());
|
|
|
|
if(((SdrShadowItem&)pCustomShape->GetMergedItem(SDRATTR_SHADOW)).GetValue())
|
|
{
|
|
if(pReplacement->ISA(SdrObjGroup))
|
|
{
|
|
pCandidate->SetMergedItem(SdrShadowItem(sal_True));
|
|
}
|
|
}
|
|
|
|
SdrInsertReason aReason(SDRREASON_VIEWCALL, pCustomShape);
|
|
rOL.InsertObject(pCandidate, rPos, &aReason);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pCandidate, true));
|
|
MarkObj(pCandidate, pPV, sal_False, sal_True);
|
|
|
|
if(pCustomShape->HasText() && !pCustomShape->IsTextPath())
|
|
{
|
|
// #i37011# also create a text object and add at rPos + 1
|
|
SdrTextObj* pTextObj = (SdrTextObj*)SdrObjFactory::MakeNewObject(
|
|
pCustomShape->GetObjInventor(), OBJ_TEXT, 0L, pCustomShape->GetModel());
|
|
|
|
// Copy text content
|
|
OutlinerParaObject* pParaObj = pCustomShape->GetOutlinerParaObject();
|
|
if(pParaObj)
|
|
{
|
|
pTextObj->NbcSetOutlinerParaObject(new OutlinerParaObject(*pParaObj));
|
|
}
|
|
|
|
// copy all attributes
|
|
SfxItemSet aTargetItemSet(pCustomShape->GetMergedItemSet());
|
|
|
|
// clear fill and line style
|
|
aTargetItemSet.Put(XLineStyleItem(XLINE_NONE));
|
|
aTargetItemSet.Put(XFillStyleItem(XFILL_NONE));
|
|
|
|
// get the text bounds and set at text object
|
|
Rectangle aTextBounds = pCustomShape->GetSnapRect();
|
|
if(pCustomShape->GetTextBounds(aTextBounds))
|
|
{
|
|
pTextObj->SetSnapRect(aTextBounds);
|
|
}
|
|
|
|
// if rotated, copy GeoStat, too.
|
|
const GeoStat& rSourceGeo = pCustomShape->GetGeoStat();
|
|
if(rSourceGeo.nDrehWink)
|
|
{
|
|
pTextObj->NbcRotate(
|
|
pCustomShape->GetSnapRect().Center(), rSourceGeo.nDrehWink,
|
|
rSourceGeo.nSin, rSourceGeo.nCos);
|
|
}
|
|
|
|
// set modified ItemSet at text object
|
|
pTextObj->SetMergedItemSet(aTargetItemSet);
|
|
|
|
// insert object
|
|
rOL.InsertObject(pTextObj, rPos + 1, &aReason);
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pTextObj, true));
|
|
MarkObj(pTextObj, pPV, sal_False, sal_True);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SdrEditView::DismantleMarkedObjects(sal_Bool bMakeLines)
|
|
{
|
|
//sal_uInt32 nCnt(0);
|
|
// temporary MarkList
|
|
SdrMarkList aRemoveMerker;
|
|
|
|
SortMarkedObjects();
|
|
|
|
const bool bUndo = IsUndoEnabled();
|
|
|
|
if( bUndo )
|
|
{
|
|
// comment is constructed later
|
|
BegUndo(String(), String(),
|
|
bMakeLines ? SDRREPFUNC_OBJ_DISMANTLE_LINES : SDRREPFUNC_OBJ_DISMANTLE_POLYS);
|
|
}
|
|
|
|
sal_uIntPtr nm;
|
|
sal_uIntPtr nAnz=GetMarkedObjectCount();
|
|
SdrObjList* pOL0=NULL;
|
|
for (nm=nAnz; nm>0;) {
|
|
nm--;
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
SdrPageView* pPV=pM->GetPageView();
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
if (pOL!=pOL0) { pOL0=pOL; pObj->GetOrdNum(); } // make sure OrdNums are correct!
|
|
if (ImpCanDismantle(pObj,bMakeLines)) {
|
|
aRemoveMerker.InsertEntry(SdrMark(pObj,pM->GetPageView()));
|
|
sal_uIntPtr nPos0=pObj->GetOrdNumDirect();
|
|
sal_uIntPtr nPos=nPos0+1;
|
|
SdrObjList* pSubList=pObj->GetSubList();
|
|
if (pSubList!=NULL && !pObj->Is3DObj()) {
|
|
SdrObjListIter aIter(*pSubList,IM_DEEPNOGROUPS);
|
|
while (aIter.IsMore()) {
|
|
const SdrObject* pObj1=aIter.Next();
|
|
ImpDismantleOneObject(pObj1,*pOL,nPos,pPV,bMakeLines);
|
|
}
|
|
} else {
|
|
ImpDismantleOneObject(pObj,*pOL,nPos,pPV,bMakeLines);
|
|
}
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj,sal_True));
|
|
pOL->RemoveObject(nPos0);
|
|
|
|
if( !bUndo )
|
|
SdrObject::Free(pObj);
|
|
}
|
|
}
|
|
|
|
if( bUndo )
|
|
{
|
|
// construct UndoComment from objects actually used
|
|
SetUndoComment(ImpGetResStr(bMakeLines?STR_EditDismantle_Lines:STR_EditDismantle_Polys),aRemoveMerker.GetMarkDescription());
|
|
// remove objects actually used from the list
|
|
EndUndo();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Group
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SdrEditView::GroupMarked(const SdrObject* pUserGrp)
|
|
{
|
|
if (AreObjectsMarked())
|
|
{
|
|
SortMarkedObjects();
|
|
|
|
const bool bUndo = IsUndoEnabled();
|
|
if( bUndo )
|
|
{
|
|
BegUndo(ImpGetResStr(STR_EditGroup),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_GROUP);
|
|
|
|
const sal_uIntPtr nAnz = GetMarkedObjectCount();
|
|
for(sal_uIntPtr nm = nAnz; nm>0; )
|
|
{
|
|
// add UndoActions for all affected objects
|
|
nm--;
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
SdrObject* pObj = pM->GetMarkedSdrObj();
|
|
std::vector< SdrUndoAction* > vConnectorUndoActions( CreateConnectorUndo( *pObj ) );
|
|
AddUndoActions( vConnectorUndoActions );
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject( *pObj ));
|
|
}
|
|
}
|
|
|
|
SdrMarkList aNewMark;
|
|
SdrPageView* pPV = GetSdrPageView();
|
|
|
|
if(pPV)
|
|
{
|
|
SdrObjList* pAktLst=pPV->GetObjList();
|
|
SdrObjList* pSrcLst=pAktLst;
|
|
SdrObjList* pSrcLst0=pSrcLst;
|
|
SdrPage* pPage=pPV->GetPage();
|
|
// make sure OrdNums are correct
|
|
if (pSrcLst->IsObjOrdNumsDirty())
|
|
pSrcLst->RecalcObjOrdNums();
|
|
SdrObject* pGrp=NULL;
|
|
SdrObject* pRefObj=NULL; // reference for InsertReason (-> anchors in Writer)
|
|
SdrObject* pRefObj1=NULL; // reference for InsertReason (-> anchors in Writer)
|
|
SdrObjList* pDstLst=NULL;
|
|
// if all selected objects come from foreign object lists.
|
|
// the group object is the last one in the list.
|
|
sal_uIntPtr nInsPos=pSrcLst->GetObjCount();
|
|
sal_Bool bNeedInsPos=sal_True;
|
|
for (sal_uIntPtr nm=GetMarkedObjectCount(); nm>0;)
|
|
{
|
|
nm--;
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
if (pM->GetPageView()==pPV)
|
|
{
|
|
if (pGrp==NULL)
|
|
{
|
|
if (pUserGrp!=NULL)
|
|
pGrp=pUserGrp->Clone();
|
|
if (pGrp==NULL)
|
|
pGrp=new SdrObjGroup;
|
|
pDstLst=pGrp->GetSubList();
|
|
DBG_ASSERT(pDstLst!=NULL,"Alleged group object doesn't return object list.");
|
|
}
|
|
SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
pSrcLst=pObj->GetObjList();
|
|
if (pSrcLst!=pSrcLst0)
|
|
{
|
|
if (pSrcLst->IsObjOrdNumsDirty())
|
|
pSrcLst->RecalcObjOrdNums();
|
|
}
|
|
sal_Bool bForeignList=pSrcLst!=pAktLst;
|
|
sal_Bool bGrouped=pSrcLst!=pPage;
|
|
if (!bForeignList && bNeedInsPos)
|
|
{
|
|
nInsPos=pObj->GetOrdNum(); // this way, all ObjOrdNum of the page are set
|
|
nInsPos++;
|
|
bNeedInsPos=sal_False;
|
|
}
|
|
pSrcLst->RemoveObject(pObj->GetOrdNumDirect());
|
|
if (!bForeignList)
|
|
nInsPos--; // correct InsertPos
|
|
SdrInsertReason aReason(SDRREASON_VIEWCALL);
|
|
pDstLst->InsertObject(pObj,0,&aReason);
|
|
GetMarkedObjectListWriteAccess().DeleteMark(nm);
|
|
if (pRefObj1==NULL)
|
|
pRefObj1=pObj; // the topmost visible object
|
|
if (!bGrouped)
|
|
{
|
|
if (pRefObj==NULL)
|
|
pRefObj=pObj; // the topmost visible non-group object
|
|
}
|
|
pSrcLst0=pSrcLst;
|
|
}
|
|
}
|
|
if (pRefObj==NULL)
|
|
pRefObj=pRefObj1;
|
|
if (pGrp!=NULL)
|
|
{
|
|
aNewMark.InsertEntry(SdrMark(pGrp,pPV));
|
|
sal_uIntPtr nAnz=pDstLst->GetObjCount();
|
|
SdrInsertReason aReason(SDRREASON_VIEWCALL,pRefObj);
|
|
pAktLst->InsertObject(pGrp,nInsPos,&aReason);
|
|
if( bUndo )
|
|
{
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pGrp,true)); // no recalculation!
|
|
for (sal_uIntPtr no=0; no<nAnz; no++)
|
|
{
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pDstLst->GetObj(no)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
GetMarkedObjectListWriteAccess().Merge(aNewMark);
|
|
MarkListHasChanged();
|
|
|
|
if( bUndo )
|
|
EndUndo();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Ungroup
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SdrEditView::UnGroupMarked()
|
|
{
|
|
SdrMarkList aNewMark;
|
|
|
|
const bool bUndo = IsUndoEnabled();
|
|
if( bUndo )
|
|
BegUndo(String(), String(), SDRREPFUNC_OBJ_UNGROUP);
|
|
|
|
sal_uIntPtr nCount=0;
|
|
XubString aName1;
|
|
XubString aName;
|
|
sal_Bool bNameOk=sal_False;
|
|
for (sal_uIntPtr nm=GetMarkedObjectCount(); nm>0;) {
|
|
nm--;
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
SdrObject* pGrp=pM->GetMarkedSdrObj();
|
|
SdrObjList* pSrcLst=pGrp->GetSubList();
|
|
if (pSrcLst!=NULL) {
|
|
nCount++;
|
|
if (nCount==1) {
|
|
pGrp->TakeObjNameSingul(aName); // retrieve name of group
|
|
pGrp->TakeObjNamePlural(aName1); // retrieve name of group
|
|
bNameOk=sal_True;
|
|
} else {
|
|
if (nCount==2) aName=aName1; // set plural name
|
|
if (bNameOk) {
|
|
XubString aStr;
|
|
pGrp->TakeObjNamePlural(aStr); // retrieve name of group
|
|
|
|
if(!aStr.Equals(aName))
|
|
bNameOk = sal_False;
|
|
}
|
|
}
|
|
sal_uIntPtr nDstCnt=pGrp->GetOrdNum();
|
|
SdrObjList* pDstLst=pM->GetPageView()->GetObjList();
|
|
|
|
// FIRST move contained objects to parent of group, so that
|
|
// the contained objects are NOT migrated to the UNDO-ItemPool
|
|
// when AddUndo(new SdrUndoDelObj(*pGrp)) is called.
|
|
sal_uIntPtr nAnz=pSrcLst->GetObjCount();
|
|
sal_uIntPtr no;
|
|
|
|
if( bUndo )
|
|
{
|
|
for (no=nAnz; no>0;)
|
|
{
|
|
no--;
|
|
SdrObject* pObj=pSrcLst->GetObj(no);
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject(*pObj));
|
|
}
|
|
}
|
|
for (no=0; no<nAnz; no++)
|
|
{
|
|
SdrObject* pObj=pSrcLst->RemoveObject(0);
|
|
SdrInsertReason aReason(SDRREASON_VIEWCALL,pGrp);
|
|
pDstLst->InsertObject(pObj,nDstCnt,&aReason);
|
|
if( bUndo )
|
|
AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pObj,true));
|
|
nDstCnt++;
|
|
// No SortCheck when inserting into MarkList, because that would
|
|
// provoke a RecalcOrdNums() each time because of pObj->GetOrdNum():
|
|
aNewMark.InsertEntry(SdrMark(pObj,pM->GetPageView()),sal_False);
|
|
}
|
|
|
|
if( bUndo )
|
|
{
|
|
// Now it is safe to add the delete-UNDO which triggers the
|
|
// MigrateItemPool now only for itself, not for the sub-objects.
|
|
// nDstCnt is right, because previous inserts move group
|
|
// object deeper and increase nDstCnt.
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pGrp));
|
|
}
|
|
pDstLst->RemoveObject(nDstCnt);
|
|
|
|
if( !bUndo )
|
|
SdrObject::Free(pGrp);
|
|
|
|
GetMarkedObjectListWriteAccess().DeleteMark(nm);
|
|
}
|
|
}
|
|
if (nCount!=0)
|
|
{
|
|
if (!bNameOk)
|
|
aName=ImpGetResStr(STR_ObjNamePluralGRUP); // Use the term "Group Objects," if different objects are grouped.
|
|
SetUndoComment(ImpGetResStr(STR_EditUngroup),aName);
|
|
}
|
|
|
|
if( bUndo )
|
|
EndUndo();
|
|
|
|
if (nCount!=0)
|
|
{
|
|
GetMarkedObjectListWriteAccess().Merge(aNewMark,sal_True); // Because of the sorting above, aNewMark is reversed
|
|
MarkListHasChanged();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ConvertToPoly
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
SdrObject* SdrEditView::ImpConvertOneObj(SdrObject* pObj, sal_Bool bPath, sal_Bool bLineToArea)
|
|
{
|
|
SdrObject* pNewObj = pObj->ConvertToPolyObj(bPath, bLineToArea);
|
|
if (pNewObj!=NULL)
|
|
{
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
DBG_ASSERT(pOL!=NULL,"ConvertTo: Object doesn't return object list");
|
|
if (pOL!=NULL)
|
|
{
|
|
const bool bUndo = IsUndoEnabled();
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoReplaceObject(*pObj,*pNewObj));
|
|
|
|
pOL->ReplaceObject(pNewObj,pObj->GetOrdNum());
|
|
|
|
if( !bUndo )
|
|
SdrObject::Free(pObj);
|
|
}
|
|
}
|
|
return pNewObj;
|
|
}
|
|
|
|
void SdrEditView::ImpConvertTo(sal_Bool bPath, sal_Bool bLineToArea)
|
|
{
|
|
sal_Bool bMrkChg=sal_False;
|
|
if (AreObjectsMarked()) {
|
|
sal_uIntPtr nMarkAnz=GetMarkedObjectCount();
|
|
sal_uInt16 nDscrID=0;
|
|
if(bLineToArea)
|
|
{
|
|
if(nMarkAnz == 1)
|
|
nDscrID = STR_EditConvToContour;
|
|
else
|
|
nDscrID = STR_EditConvToContours;
|
|
|
|
BegUndo(ImpGetResStr(nDscrID), GetDescriptionOfMarkedObjects());
|
|
}
|
|
else
|
|
{
|
|
if (bPath) {
|
|
if (nMarkAnz==1) nDscrID=STR_EditConvToCurve;
|
|
else nDscrID=STR_EditConvToCurves;
|
|
BegUndo(ImpGetResStr(nDscrID),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_CONVERTTOPATH);
|
|
} else {
|
|
if (nMarkAnz==1) nDscrID=STR_EditConvToPoly;
|
|
else nDscrID=STR_EditConvToPolys;
|
|
BegUndo(ImpGetResStr(nDscrID),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_CONVERTTOPOLY);
|
|
}
|
|
}
|
|
for (sal_uIntPtr nm=nMarkAnz; nm>0;) {
|
|
nm--;
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
SdrPageView* pPV=pM->GetPageView();
|
|
if (pObj->IsGroupObject() && !pObj->Is3DObj()) {
|
|
SdrObject* pGrp=pObj;
|
|
SdrObjListIter aIter(*pGrp,IM_DEEPNOGROUPS);
|
|
while (aIter.IsMore()) {
|
|
pObj=aIter.Next();
|
|
ImpConvertOneObj(pObj,bPath,bLineToArea);
|
|
}
|
|
} else {
|
|
SdrObject* pNewObj=ImpConvertOneObj(pObj,bPath,bLineToArea);
|
|
if (pNewObj!=NULL) {
|
|
bMrkChg=sal_True;
|
|
GetMarkedObjectListWriteAccess().ReplaceMark(SdrMark(pNewObj,pPV),nm);
|
|
}
|
|
}
|
|
}
|
|
EndUndo();
|
|
if (bMrkChg) AdjustMarkHdl();
|
|
if (bMrkChg) MarkListHasChanged();
|
|
}
|
|
}
|
|
|
|
void SdrEditView::ConvertMarkedToPathObj(sal_Bool bLineToArea)
|
|
{
|
|
ImpConvertTo(sal_True, bLineToArea);
|
|
}
|
|
|
|
void SdrEditView::ConvertMarkedToPolyObj(sal_Bool bLineToArea)
|
|
{
|
|
ImpConvertTo(sal_False, bLineToArea);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Metafile Import
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SdrEditView::DoImportMarkedMtf(SvdProgressInfo *pProgrInfo)
|
|
{
|
|
const bool bUndo = IsUndoEnabled();
|
|
|
|
if( bUndo )
|
|
BegUndo(String(), String(), SDRREPFUNC_OBJ_IMPORTMTF);
|
|
|
|
SortMarkedObjects();
|
|
SdrMarkList aForTheDescription;
|
|
SdrMarkList aNewMarked;
|
|
sal_uIntPtr nAnz=GetMarkedObjectCount();
|
|
|
|
for (sal_uIntPtr nm=nAnz; nm>0;)
|
|
{ // create Undo objects for all new objects
|
|
// check for cancellation between the metafiles
|
|
if( pProgrInfo != NULL )
|
|
{
|
|
pProgrInfo->SetNextObject();
|
|
if(!pProgrInfo->ReportActions(0))
|
|
break;
|
|
}
|
|
|
|
nm--;
|
|
SdrMark* pM=GetSdrMarkByIndex(nm);
|
|
SdrObject* pObj=pM->GetMarkedSdrObj();
|
|
SdrPageView* pPV=pM->GetPageView();
|
|
SdrObjList* pOL=pObj->GetObjList();
|
|
sal_uIntPtr nInsPos=pObj->GetOrdNum()+1;
|
|
SdrGrafObj* pGraf=PTR_CAST(SdrGrafObj,pObj);
|
|
SdrOle2Obj* pOle2=PTR_CAST(SdrOle2Obj,pObj);
|
|
sal_uIntPtr nInsAnz=0;
|
|
if (pGraf!=NULL && pGraf->HasGDIMetaFile())
|
|
{
|
|
ImpSdrGDIMetaFileImport aFilter(*pMod);
|
|
aFilter.SetScaleRect(pGraf->GetSnapRect());
|
|
aFilter.SetLayer(pObj->GetLayer());
|
|
nInsAnz=aFilter.DoImport(pGraf->GetTransformedGraphic().GetGDIMetaFile(),*pOL,nInsPos,pProgrInfo);
|
|
}
|
|
if ( pOle2!=NULL && pOle2->GetGraphic() )
|
|
{
|
|
ImpSdrGDIMetaFileImport aFilter(*pMod);
|
|
aFilter.SetScaleRect(pOle2->GetLogicRect());
|
|
aFilter.SetLayer(pObj->GetLayer());
|
|
nInsAnz=aFilter.DoImport(pOle2->GetGraphic()->GetGDIMetaFile(),*pOL,nInsPos,pProgrInfo);
|
|
}
|
|
if (nInsAnz!=0)
|
|
{
|
|
sal_uIntPtr nObj=nInsPos;
|
|
for (sal_uIntPtr i=0; i<nInsAnz; i++)
|
|
{
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pOL->GetObj(nObj)));
|
|
|
|
// update new MarkList
|
|
SdrMark aNewMark(pOL->GetObj(nObj), pPV);
|
|
aNewMarked.InsertEntry(aNewMark);
|
|
|
|
nObj++;
|
|
}
|
|
aForTheDescription.InsertEntry(*pM);
|
|
|
|
if( bUndo )
|
|
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
|
|
|
|
// remove object from selection and delete
|
|
GetMarkedObjectListWriteAccess().DeleteMark(TryToFindMarkedObject(pObj));
|
|
pOL->RemoveObject(nInsPos-1);
|
|
|
|
if( !bUndo )
|
|
SdrObject::Free(pObj);
|
|
}
|
|
}
|
|
|
|
if(aNewMarked.GetMarkCount())
|
|
{
|
|
// create new selection
|
|
for(sal_uIntPtr a(0); a < aNewMarked.GetMarkCount(); a++)
|
|
{
|
|
GetMarkedObjectListWriteAccess().InsertEntry(*aNewMarked.GetMark(a));
|
|
}
|
|
|
|
SortMarkedObjects();
|
|
}
|
|
|
|
if( bUndo )
|
|
{
|
|
SetUndoComment(ImpGetResStr(STR_EditImportMtf),aForTheDescription.GetMarkDescription());
|
|
EndUndo();
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|