blob: b86064d6a55164dc4e58faa0caf7b1c8163c492f [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"
#include <svx/svdedtv.hxx>
#include <editeng/outliner.hxx>
#include <svx/svdundo.hxx>
#include <svx/svdogrp.hxx> // fuer's Gruppieren
#include <svx/svdopath.hxx> // fuer CombineObjects
#include <svx/svdpage.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svditer.hxx>
#include <svx/svdograf.hxx> // fuer Possibilities
#include <svx/svdoole2.hxx> // und Mtf-Import
#include "svx/svdstr.hrc" // Namen aus der 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> //CHINA001
#include <svx/dialogs.hrc> //CHINA001
#include <svx/svdoashp.hxx>
#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
#include <svx/svdlegacy.hxx>
#include <svx/svdview.hxx>
#include <svx/obj3d.hxx>
////////////////////////////////////////////////////////////////////////////////////////////////////
SdrObject* SdrEditView::GetMaxToTopObj(SdrObject* /*pObj*/) const
{
return 0;
}
SdrObject* SdrEditView::GetMaxToBtmObj(SdrObject* /*pObj*/) const
{
return 0;
}
void SdrEditView::ObjOrderChanged(SdrObject* /*pObj*/, sal_uInt32 /*nOldPos*/, sal_uInt32 /*nNewPos*/)
{
}
void SdrEditView::MovMarkedToTop()
{
if(areSdrObjectsSelected())
{
const bool bUndo(IsUndoEnabled());
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
clearSdrObjectSelection(); // TTTT: check if this works
if( bUndo )
{
BegUndo(ImpGetResStr(STR_EditMovToTop), getSelectionDescription(aSelection), SDRREPFUNC_OBJ_MOVTOTOP);
}
sal_uInt32 nm(0);
SdrObjList* pOL0 = 0;
sal_uInt32 nNewPos(0);
for(nm = aSelection.size(); nm > 0;)
{
nm--;
SdrObject* pObj = aSelection[nm];
SdrObjList* pOL = pObj->getParentOfSdrObject();
if (pOL!=pOL0)
{
nNewPos = sal_uInt32(pOL->GetObjCount() - 1);
pOL0=pOL;
}
const sal_uInt32 nNowPos(pObj->GetNavigationPosition());
sal_uInt32 nCmpPos(nNowPos + 1);
SdrObject* pMaxObj=GetMaxToTopObj(pObj);
if(pMaxObj)
{
sal_uInt32 nMaxPos(pMaxObj->GetNavigationPosition());
if(nMaxPos)
{
nMaxPos--;
}
if (nNewPos>nMaxPos)
{
nNewPos=nMaxPos; // diesen nicht ueberholen.
}
if (nNewPos<nNowPos)
{
nNewPos=nNowPos; // aber dabei auch nicht in die falsche Richtung schieben
}
}
bool bEnd(false);
const basegfx::B2DRange aBoundRange(pObj->getObjectRange(getAsSdrView()));
while (nCmpPos<nNewPos && !bEnd)
{
SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
if(!pCmpObj)
{
DBG_ERROR("MovMarkedToTop(): Vergleichsobjekt nicht gefunden");
bEnd = true;
}
else if (pCmpObj==pMaxObj)
{
nNewPos=nCmpPos;
nNewPos--;
bEnd = true;
}
else if(aBoundRange.overlaps(pCmpObj->getObjectRange(getAsSdrView())))
{
nNewPos=nCmpPos;
bEnd = true;
}
else
{
nCmpPos++;
}
}
if (nNowPos!=nNewPos)
{
pOL->SetNavigationPosition(nNowPos, nNewPos);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
}
ObjOrderChanged(pObj,nNowPos,nNewPos);
}
nNewPos--;
}
if( bUndo )
{
EndUndo();
}
setSdrObjectSelection(aSelection); // TTTT: check if this works
}
}
void SdrEditView::MovMarkedToBtm()
{
if(areSdrObjectsSelected())
{
const bool bUndo(IsUndoEnabled());
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
clearSdrObjectSelection(); // TTTT: check if this works
if( bUndo )
{
BegUndo(ImpGetResStr(STR_EditMovToBtm), getSelectionDescription(aSelection), SDRREPFUNC_OBJ_MOVTOBTM);
}
sal_uInt32 nm(0);
SdrObjList* pOL0 = 0;
sal_uInt32 nNewPos(0);
for(nm = 0; nm < aSelection.size(); nm++)
{
SdrObject* pObj = aSelection[nm];
SdrObjList* pOL = pObj->getParentOfSdrObject();
if (pOL!=pOL0)
{
nNewPos=0;
pOL0=pOL;
}
const sal_uInt32 nNowPos(pObj->GetNavigationPosition());
sal_uInt32 nCmpPos(nNowPos);
if(nCmpPos > 0)
{
nCmpPos--;
}
SdrObject* pMaxObj=GetMaxToBtmObj(pObj);
if(pMaxObj)
{
sal_uInt32 nMinPos(pMaxObj->GetNavigationPosition() + 1);
if (nNewPos<nMinPos)
{
nNewPos=nMinPos; // diesen nicht ueberholen.
}
if (nNewPos>nNowPos)
{
nNewPos=nNowPos; // aber dabei auch nicht in die falsche Richtung schieben
}
}
bool bEnd(false);
const basegfx::B2DRange aBoundRange(pObj->getObjectRange(getAsSdrView()));
// nNewPos ist an dieser Stelle noch die maximale Position,
// an der das Obj hinruecken darf, ohne seinen Vorgaenger
// (Mehrfachselektion) zu ueberholen.
while (nCmpPos>nNewPos && !bEnd)
{
SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
if(!pCmpObj)
{
DBG_ERROR("MovMarkedToBtm(): Vergleichsobjekt nicht gefunden");
bEnd = true;
}
else if (pCmpObj==pMaxObj)
{
nNewPos=nCmpPos;
nNewPos++;
bEnd = true;
}
else if(aBoundRange.overlaps(pCmpObj->getObjectRange(getAsSdrView())))
{
nNewPos=nCmpPos;
bEnd = true;
}
else
{
nCmpPos--;
}
}
if (nNowPos!=nNewPos)
{
pOL->SetNavigationPosition(nNowPos, nNewPos);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
}
ObjOrderChanged(pObj,nNowPos,nNewPos);
}
nNewPos++;
}
if(bUndo)
{
EndUndo();
}
setSdrObjectSelection(aSelection); // TTTT: check if this works
}
}
void SdrEditView::PutMarkedToTop()
{
PutMarkedInFrontOfObj(0);
}
void SdrEditView::PutMarkedInFrontOfObj(const SdrObject* pRefObj)
{
if(areSdrObjectsSelected())
{
const bool bUndo(IsUndoEnabled());
SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
if(bUndo)
{
BegUndo(ImpGetResStr(STR_EditPutToTop), getSelectionDescription(aSelection), SDRREPFUNC_OBJ_PUTTOTOP);
}
if(pRefObj)
{
// Damit "Vor das Objekt" auch funktioniert wenn die
// markierten Objekte bereits vor dem Objekt stehen
const bool bWasSelected(isSdrObjectSelected(*pRefObj));
if(bWasSelected)
{
removeSdrObjectFromSelection(*pRefObj);
}
PutMarkedToBtm();
if(bWasSelected)
{
addSdrObjectToSelection(*pRefObj);
}
}
// selection was changed, re-fetch
aSelection = getSelectedSdrObjectVectorFromSdrMarkView();
clearSdrObjectSelection(); // TTTT: check if this works
sal_uInt32 nm(0);
SdrObjList* pOL0 = 0;
sal_uInt32 nNewPos(0);
for(nm = aSelection.size(); nm > 0;)
{
nm--;
SdrObject* pObj = aSelection[nm];
if (pObj!=pRefObj)
{
SdrObjList* pOL = pObj->getParentOfSdrObject();
if (pOL!=pOL0)
{
nNewPos = sal_uInt32(pOL->GetObjCount() - 1);
pOL0=pOL;
}
const sal_uInt32 nNowPos(pObj->GetNavigationPosition());
SdrObject* pMaxObj=GetMaxToTopObj(pObj);
if(pMaxObj)
{
sal_uInt32 nMaxOrd(pMaxObj->GetNavigationPosition()); // geht leider nicht anders
if (nMaxOrd>0)
{
nMaxOrd--;
}
if (nNewPos>nMaxOrd)
{
nNewPos=nMaxOrd; // nicht ueberholen.
}
if (nNewPos<nNowPos)
{
nNewPos=nNowPos; // aber dabei auch nicht in die falsche Richtung schieben
}
}
if(pRefObj)
{
if(pRefObj->getParentOfSdrObject() == pObj->getParentOfSdrObject())
{
const sal_uInt32 nMaxOrd(pRefObj->GetNavigationPosition()); // geht leider nicht anders
if (nNewPos>nMaxOrd)
{
nNewPos=nMaxOrd; // nicht ueberholen.
}
if (nNewPos<nNowPos)
{
nNewPos=nNowPos; // aber dabei auch nicht in die falsche Richtung schieben
}
}
else
{
nNewPos=nNowPos; // andere PageView, also nicht veraendern
}
}
if (nNowPos!=nNewPos)
{
pOL->SetNavigationPosition(nNowPos, nNewPos);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj, nNowPos, nNewPos));
}
ObjOrderChanged(pObj,nNowPos,nNewPos);
}
nNewPos--;
}
}
if( bUndo )
{
EndUndo();
}
setSdrObjectSelection(aSelection); // TTTT: check if this works
}
}
void SdrEditView::PutMarkedToBtm()
{
PutMarkedBehindObj(0);
}
void SdrEditView::PutMarkedBehindObj(const SdrObject* pRefObj)
{
if(areSdrObjectsSelected())
{
const bool bUndo(IsUndoEnabled());
SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
if( bUndo )
{
BegUndo(ImpGetResStr(STR_EditPutToBtm), getSelectionDescription(aSelection), SDRREPFUNC_OBJ_PUTTOBTM);
}
if(pRefObj)
{
// Damit "Hinter das Objekt" auch funktioniert wenn die
// markierten Objekte bereits hinter dem Objekt stehen
const bool bWasSelected(isSdrObjectSelected(*pRefObj));
if(bWasSelected)
{
removeSdrObjectFromSelection(*pRefObj);
}
PutMarkedToTop();
if(bWasSelected)
{
addSdrObjectToSelection(*pRefObj);
}
}
// selection was changed, re-fetch
aSelection = getSelectedSdrObjectVectorFromSdrMarkView();
clearSdrObjectSelection(); // TTTT: check if this works
sal_uInt32 nm(0);
SdrObjList* pOL0 = 0;
sal_uInt32 nNewPos(0);
for(nm = 0; nm < aSelection.size(); nm++)
{
SdrObject* pObj = aSelection[nm];
if(pObj != pRefObj)
{
SdrObjList* pOL = pObj->getParentOfSdrObject();
if(pOL != pOL0)
{
nNewPos=0;
pOL0=pOL;
}
const sal_uInt32 nNowPos(pObj->GetNavigationPosition());
SdrObject* pMinObj=GetMaxToBtmObj(pObj);
if(pMinObj)
{
const sal_uInt32 nMinOrd(pMinObj->GetNavigationPosition() + 1); // geht leider nicht anders
if(nNewPos < nMinOrd)
{
nNewPos = nMinOrd; // nicht ueberholen.
}
if(nNewPos > nNowPos)
{
nNewPos = nNowPos; // aber dabei auch nicht in die falsche Richtung schieben
}
}
if(pRefObj)
{
if(pRefObj->getParentOfSdrObject() == pObj->getParentOfSdrObject())
{
const sal_uInt32 nMinOrd(pRefObj->GetNavigationPosition()); // geht leider nicht anders
if(nNewPos < nMinOrd)
{
nNewPos = nMinOrd; // nicht ueberholen.
}
if(nNewPos > nNowPos)
{
nNewPos = nNowPos; // aber dabei auch nicht in die falsche Richtung schieben
}
}
else
{
nNewPos=nNowPos; // andere PageView, also nicht veraendern
}
}
if(nNowPos != nNewPos)
{
pOL->SetNavigationPosition(nNowPos, nNewPos);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj, nNowPos, nNewPos));
}
ObjOrderChanged(pObj,nNowPos,nNewPos);
}
nNewPos++;
}
}
if(bUndo)
{
EndUndo();
}
setSdrObjectSelection(aSelection); // TTTT: check if this works
}
}
void SdrEditView::ReverseOrderOfMarked()
{
if(areSdrObjectsSelected())
{
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
clearSdrObjectSelection(); // TTTT: check if this works
const bool bUndo(IsUndoEnabled());
if(bUndo)
{
BegUndo(ImpGetResStr(STR_EditRevOrder), getSelectionDescription(aSelection), SDRREPFUNC_OBJ_REVORDER);
}
sal_uInt32 a(0);
sal_uInt32 b(aSelection.size() - 1);
while(a < b)
{
SdrObject* pObj1 = aSelection[a];
SdrObject* pObj2 = aSelection[b];
if(pObj1 && pObj2)
{
SdrObjList* pOL = pObj1->getParentOfSdrObject();
if(pOL && pOL == pObj2->getParentOfSdrObject())
{
const sal_uInt32 nTargetPos1(pObj2->GetNavigationPosition());
const sal_uInt32 nTargetPos2(pObj1->GetNavigationPosition());
if(bUndo)
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj1, pObj1->GetNavigationPosition(), nTargetPos1));
}
pOL->SetNavigationPosition(pObj1->GetNavigationPosition(), nTargetPos1);
// check if 2nd move is not needed; may be the case when the list
// has already correctly changed by 1st operation
if(pObj2->GetNavigationPosition() != nTargetPos2)
{
if(bUndo)
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj2, pObj2->GetNavigationPosition(), nTargetPos2));
}
pOL->SetNavigationPosition(pObj2->GetNavigationPosition(), nTargetPos2);
}
}
else
{
OSL_ENSURE(false, "ReverseOrderOfMarked: objects with different parent in selection (!)");
}
}
else
{
OSL_ENSURE(false, "ReverseOrderOfMarked: selection contains NULL-SdrObjects (!)");
}
a++;
b--;
}
if(bUndo)
{
EndUndo();
}
setSdrObjectSelection(aSelection); // TTTT: check if this works
}
}
void SdrEditView::ImpCheckToTopBtmPossible()
{
if(areSdrObjectsSelected())
{
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
if(1 == aSelection.size())
{
// Sonderbehandlung fuer Einzelmarkierung
SdrObject* pObj = aSelection[0];
SdrObjList* pOL = pObj->getParentOfSdrObject();
sal_uInt32 nMax(pOL->GetObjCount());
sal_uInt32 nMin(0);
const sal_uInt32 nObjNum(pObj->GetNavigationPosition());
SdrObject* pRestrict=GetMaxToTopObj(pObj);
if(pRestrict)
{
const sal_uInt32 nRestrict(pRestrict->GetNavigationPosition());
if(nRestrict < nMax)
{
nMax = nRestrict;
}
}
pRestrict=GetMaxToBtmObj(pObj);
if(pRestrict)
{
const sal_uInt32 nRestrict(pRestrict->GetNavigationPosition());
if(nRestrict > nMin)
{
nMin = nRestrict;
}
}
mbToTopPossible = nObjNum < sal_uInt32(nMax - 1);
mbToBtmPossible = nObjNum > nMin;
}
else
{
// Mehrfachselektion
sal_uInt32 nm(0);
SdrObjList* pOL0 = 0;
sal_Int32 nPos0(-1);
while(!mbToBtmPossible && nm < aSelection.size())
{
// 'nach hinten' checken
SdrObject* pObj = aSelection[nm];
SdrObjList* pOL = pObj->getParentOfSdrObject();
if(pOL != pOL0)
{
nPos0=-1;
pOL0=pOL;
}
const sal_uInt32 nPos(pObj->GetNavigationPosition());
mbToBtmPossible = (nPos > sal_uInt32(nPos0 + 1));
nPos0 = sal_Int32(nPos);
nm++;
}
nm = aSelection.size();
pOL0 = 0;
nPos0=0x7FFFFFFF;
while(!mbToTopPossible && nm > 0)
{
// 'nach vorn' checken
nm--;
SdrObject* pObj = aSelection[nm];
SdrObjList* pOL = pObj->getParentOfSdrObject();
if(pOL != pOL0)
{
nPos0=pOL->GetObjCount();
pOL0=pOL;
}
const sal_uInt32 nPos(pObj->GetNavigationPosition());
mbToTopPossible = (nPos + 1 < sal_uInt32(nPos0));
nPos0=nPos;
}
}
}
}
void SdrEditView::ImpCopyAttributes(const SdrObject* pSource, SdrObject* pDest) const
{
if(pSource)
{
SdrObjList* pOL = pSource->getChildrenOfSdrObject();
if(pOL && !dynamic_cast< const E3dObject* >(pSource))
{
// erstes Nichtgruppenobjekt aus der Gruppe holen
SdrObjListIter aIter(*pOL,IM_DEEPNOGROUPS);
pSource=aIter.Next();
}
}
if(pSource && pDest)
{
SfxItemSet aSet(pDest->GetObjectItemPool(),
SDRATTR_START, SDRATTR_NOTPERSIST_FIRST-1,
SDRATTR_NOTPERSIST_LAST+1, SDRATTR_END,
EE_ITEMS_START, EE_ITEMS_END,
0, 0); // #52757#, #52762#
aSet.Put(pSource->GetMergedItemSet());
pDest->ClearMergedItem();
pDest->SetMergedItemSet(aSet);
pDest->SetLayer(pSource->GetLayer());
pDest->SetStyleSheet(pSource->GetStyleSheet(), true);
}
}
bool SdrEditView::ImpCanConvertForCombine1(const SdrObject* pObj) const
{
// #69711 : new condition isLine() to be able to combine simple Lines
bool bIsLine(false);
const SdrPathObj* pPath = dynamic_cast< const SdrPathObj* >(pObj);
if(pPath)
{
bIsLine = pPath->isLine();
}
SdrObjTransformInfoRec aInfo;
pObj->TakeObjInfo(aInfo);
return (aInfo.mbCanConvToPath || aInfo.mbCanConvToPoly || bIsLine);
}
bool SdrEditView::ImpCanConvertForCombine(const SdrObject* pObj) const
{
SdrObjList* pOL = pObj->getChildrenOfSdrObject();
if(pOL && !dynamic_cast< const E3dObject* >(pObj))
{
SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
while(aIter.IsMore())
{
SdrObject* pObj1 = aIter.Next();
// Es muessen alle Member einer Gruppe konvertierbar sein
if(!ImpCanConvertForCombine1(pObj1))
{
return false;
}
}
}
else
{
if(!ImpCanConvertForCombine1(pObj))
{
return false;
}
}
return true;
}
basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon1(const SdrObject* pObj, bool bCombine) const
{
basegfx::B2DPolyPolygon aRetval;
const SdrPathObj* pPath = dynamic_cast< const SdrPathObj* >(pObj);
if(bCombine && pPath && !pObj->GetOutlinerParaObject())
{
aRetval = pPath->getB2DPolyPolygonInObjectCoordinates();
}
else
{
SdrObject* pConvObj = pObj->ConvertToPolyObj(bCombine, false);
if(pConvObj)
{
SdrObjList* pOL = pConvObj->getChildrenOfSdrObject();
if(pOL)
{
SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
while(aIter.IsMore())
{
SdrObject* pObj1 = aIter.Next();
pPath = dynamic_cast< SdrPathObj* >(pObj1);
if(pPath)
{
aRetval.append(pPath->getB2DPolyPolygonInObjectCoordinates());
}
}
}
else
{
pPath = dynamic_cast< SdrPathObj* >(pConvObj);
if(pPath)
{
aRetval = pPath->getB2DPolyPolygonInObjectCoordinates();
}
}
deleteSdrObjectSafeAndClearPointer( pConvObj );
}
}
return aRetval;
}
basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon(const SdrObject* pObj, bool bCombine) const
{
SdrObjList* pOL = pObj->getChildrenOfSdrObject();
if(pOL && !dynamic_cast< const E3dObject* >(pObj))
{
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(!nPolyCount)
{
return basegfx::B2DPolygon();
}
else if(1 == nPolyCount)
{
return rPolyPolygon.getB2DPolygon(0);
}
else
{
basegfx::B2DPolygon aRetval(rPolyPolygon.getB2DPolygon(0));
for(sal_uInt32 a(1); 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;
double mfPosition;
double mfWidth;
// for ::std::sort
bool operator<(const ImpDistributeEntry& rComp) const
{
return (mfPosition < rComp.mfPosition);
}
};
// moved to stl vector, double and transformations
// TTTT: check changes
typedef ::std::vector< ImpDistributeEntry* > ImpDistributeEntryVector;
void SdrEditView::DistributeMarkedObjects()
{
if(areSdrObjectsSelected())
{
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
if(aSelection.size() > 2)
{
SfxItemSet aNewAttr(getSdrModelFromSdrView().GetItemPool());
SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
if(pFact)
{
AbstractSvxDistributeDialog *pDlg = pFact->CreateSvxDistributeDialog(0, aNewAttr);
DBG_ASSERT(pDlg, "Dialogdiet fail!");//CHINA001
const sal_uInt16 nResult(pDlg->Execute());
if(RET_OK == nResult)
{
clearSdrObjectSelection();
const SvxDistributeHorizontal eHor(pDlg->GetDistributeHor());
const SvxDistributeVertical eVer(pDlg->GetDistributeVer());
sal_uInt32 a(0);
double fFullLength(0.0);
const bool bUndo(IsUndoEnabled());
if( bUndo )
{
BegUndo();
}
if(eHor != SvxDistributeHorizontalNone)
{
// build sorted entry list
ImpDistributeEntryVector aEntries;
aEntries.reserve(aSelection.size());
fFullLength = 0.0;
for(a = 0; a < aSelection.size(); a++)
{
ImpDistributeEntry* pNew = new ImpDistributeEntry;
pNew->mpObj = aSelection[a];
const basegfx::B2DRange aOldObjSnapRange(sdr::legacy::GetSnapRange(*pNew->mpObj));
switch(eHor)
{
case SvxDistributeHorizontalLeft:
{
pNew->mfPosition = aOldObjSnapRange.getMinX();
break;
}
case SvxDistributeHorizontalCenter:
{
pNew->mfPosition = aOldObjSnapRange.getCenterX();
break;
}
case SvxDistributeHorizontalDistance:
{
pNew->mfWidth = aOldObjSnapRange.getWidth();
fFullLength += pNew->mfWidth;
pNew->mfPosition = aOldObjSnapRange.getCenterX();
break;
}
case SvxDistributeHorizontalRight:
{
pNew->mfPosition = aOldObjSnapRange.getMaxX();
break;
}
default: break;
}
aEntries.push_back(pNew);
}
// sort by mfPosition
::std::sort(aEntries.begin(), aEntries.end());
if(eHor == SvxDistributeHorizontalDistance)
{
// calc room in-between
const double fWidth(sdr::legacy::GetAllObjBoundRange(getSelectedSdrObjectVectorFromSdrMarkView()).getWidth());
const double fStepWidth((fWidth - fFullLength) / (double)(aEntries.size() - 1));
double fStepStart(aEntries[0]->mfPosition);
fStepStart += fStepWidth + ((aEntries[0]->mfWidth + aEntries[1]->mfWidth) * 0.5);
// move entries 1..n-1
for(a = 1; a < aEntries.size() - 1; a++)
{
ImpDistributeEntry* pCurr = aEntries[a];
ImpDistributeEntry* pNext = aEntries[a + 1];
const double fDelta((fStepStart + 0.5) - pCurr->mfPosition);
if(bUndo)
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
}
sdr::legacy::transformSdrObject(
*pCurr->mpObj,
basegfx::tools::createTranslateB2DHomMatrix(fDelta, 0.0));
fStepStart += fStepWidth + ((pCurr->mfWidth + pNext->mfWidth) * 0.5);
}
}
else
{
// calc distances
const double fWidth(aEntries[aEntries.size() - 1]->mfPosition - aEntries[0]->mfPosition);
const double fStepWidth(fWidth / (double)(aEntries.size() - 1));
double fStepStart(aEntries[0]->mfPosition);
fStepStart += fStepWidth;
// move entries 1..n-1
for(a = 1 ; a < aEntries.size() - 1; a++)
{
ImpDistributeEntry* pCurr = aEntries[a];
const double fDelta((fStepStart + 0.5) - pCurr->mfPosition);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
}
sdr::legacy::transformSdrObject(
*pCurr->mpObj,
basegfx::tools::createTranslateB2DHomMatrix(fDelta, 0.0));
fStepStart += fStepWidth;
}
}
for(a = 0; a < aEntries.size(); a++)
{
delete aEntries[a];
}
}
if(eVer != SvxDistributeVerticalNone)
{
// build sorted entry list
ImpDistributeEntryVector aEntries;
aEntries.reserve(aSelection.size());
fFullLength = 0.0;
for(a = 0; a < aSelection.size(); a++)
{
ImpDistributeEntry* pNew = new ImpDistributeEntry;
pNew->mpObj = aSelection[a];
const basegfx::B2DRange aOldObjSnapRange(sdr::legacy::GetSnapRange(*pNew->mpObj));
switch(eVer)
{
case SvxDistributeVerticalTop:
{
pNew->mfPosition = aOldObjSnapRange.getMinY();
break;
}
case SvxDistributeVerticalCenter:
{
pNew->mfPosition = aOldObjSnapRange.getCenterY();
break;
}
case SvxDistributeVerticalDistance:
{
pNew->mfWidth = aOldObjSnapRange.getHeight();
fFullLength += pNew->mfWidth;
pNew->mfPosition = aOldObjSnapRange.getCenterY();
break;
}
case SvxDistributeVerticalBottom:
{
pNew->mfPosition = aOldObjSnapRange.getMaxY();
break;
}
default: break;
}
aEntries.push_back(pNew);
}
// sort by mfPosition
::std::sort(aEntries.begin(), aEntries.end());
if(eVer == SvxDistributeVerticalDistance)
{
// calc room in-between
const double fHeight(sdr::legacy::GetAllObjBoundRange(getSelectedSdrObjectVectorFromSdrMarkView()).getHeight());
const double fStepWidth((fHeight - fFullLength) / (double)(aEntries.size() - 1));
double fStepStart(aEntries[0]->mfPosition);
fStepStart += fStepWidth + ((aEntries[0]->mfWidth + aEntries[1]->mfWidth) * 0.5);
// move entries 1..n-1
for(a = 1; a < aEntries.size() - 1; a++)
{
ImpDistributeEntry* pCurr = aEntries[a];
ImpDistributeEntry* pNext = aEntries[a + 1];
const double fDelta((fStepStart + 0.5) - pCurr->mfPosition);
if(bUndo)
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
}
sdr::legacy::transformSdrObject(
*pCurr->mpObj,
basegfx::tools::createTranslateB2DHomMatrix(0.0, fDelta));
fStepStart += fStepWidth + ((pCurr->mfWidth + pNext->mfWidth) * 0.5);
}
}
else
{
// calc distances
const double fHeight(aEntries[aEntries.size() - 1]->mfPosition - aEntries[0]->mfPosition);
const double fStepWidth(fHeight / (double)(aEntries.size() - 1));
double fStepStart(aEntries[0]->mfPosition);
fStepStart += fStepWidth;
// move entries 1..n-1
for(a = 1; a < aEntries.size() - 1; a++)
{
ImpDistributeEntry* pCurr = aEntries[a];
const double fDelta((fStepStart + 0.5) - pCurr->mfPosition);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
}
sdr::legacy::transformSdrObject(
*pCurr->mpObj,
basegfx::tools::createTranslateB2DHomMatrix(0.0, fDelta));
fStepStart += fStepWidth;
}
}
for(a = 0; a < aEntries.size(); a++)
{
delete aEntries[a];
}
}
// UNDO-Comment and end of UNDO
SetUndoComment(ImpGetResStr(STR_DistributeMarkedObjects));
if( bUndo )
{
EndUndo();
}
setSdrObjectSelection(aSelection); // TTTT: check if this works
}
delete(pDlg);
}
}
}
}
void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode)
{
if(areSdrObjectsSelected())
{
const bool bUndo(IsUndoEnabled());
if( bUndo )
{
BegUndo();
}
sal_uInt32 nInsPos(0xFFFFFFFF);
const SdrObject* pAttrObj = 0;
basegfx::B2DPolyPolygon aMergePolyPolygonA;
basegfx::B2DPolyPolygon aMergePolyPolygonB;
SdrObjList* pInsOL = 0;
bool bFirstObjectComplete(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(true);
ConvertMarkedToPathObj(true);
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
OSL_ENSURE(aSelection.size(), "no more objects selected after preparations (!)");
SdrObjectVector aRemove;
clearSdrObjectSelection();
for(sal_uInt32 a(0); a < aSelection.size(); a++)
{
SdrObject* pObj = aSelection[a];
if(ImpCanConvertForCombine(pObj))
{
if(!pAttrObj)
{
pAttrObj = pObj;
}
nInsPos = pObj->GetNavigationPosition() + 1;
pInsOL = pObj->getParentOfSdrObject();
// #i76891# use single iter 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 = dynamic_cast< SdrPathObj* >(pCandidate);
if(pPathObj)
{
basegfx::B2DPolyPolygon aTmpPoly(pPathObj->getB2DPolyPolygonInObjectCoordinates());
// #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 evtl. 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 poly?
if(!bFirstObjectComplete && aMergePolyPolygonA.count())
{
bFirstObjectComplete = true;
}
// move object to temporary delete list
aRemove.push_back(pObj);
}
}
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(getSdrModelFromSdrView(), aMergePolyPolygonA);
ImpCopyAttributes(pAttrObj, pPath);
pInsOL->InsertObjectToSdrObjList(*pPath, nInsPos);
if(bUndo)
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pPath));
}
MarkObj(*pPath, false );
}
else
{
setSdrObjectSelection(aSelection);
}
// sort as if selection to get comment identical to behaviour before selection change
sortSdrObjectSelection(aRemove);
switch(eMode)
{
case SDR_MERGE_MERGE:
{
SetUndoComment(
ImpGetResStr(STR_EditMergeMergePoly),
getSelectionDescription(aRemove));
break;
}
case SDR_MERGE_SUBSTRACT:
{
SetUndoComment(
ImpGetResStr(STR_EditMergeSubstractPoly),
getSelectionDescription(aRemove));
break;
}
case SDR_MERGE_INTERSECT:
{
SetUndoComment(
ImpGetResStr(STR_EditMergeIntersectPoly),
getSelectionDescription(aRemove));
break;
}
}
deleteSdrObjectsWithUndo(aRemove);
if( bUndo )
{
EndUndo();
}
}
}
void SdrEditView::CombineMarkedObjects(bool bNoPolyPoly)
{
if(areSdrObjectsSelected())
{
// #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would
// create a 2nd Undo-action and Undo-Comment.
const 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 true as LineToArea, use bNoPolyPoly as info
// if this command is a 'Combine' or a 'Connect' command. On Connect it's 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);
// #114310#
// 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 false in any case. Only drawback is that
// simple polygons will be changed to curves, but with no information loss.
ConvertMarkedToPathObj(false /* bLineToArea */);
// continue as before
basegfx::B2DPolyPolygon aPolyPolygon;
SdrObjList* pAktOL = 0;
SdrObjectVector aRemoveMerker;
sal_uInt32 nInsPos(0xFFFFFFFF);
SdrObjList* pInsOL = 0;
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
const SdrObject* pAttrObj = 0;
clearSdrObjectSelection();
for(sal_uInt32 a(aSelection.size()); a > 0;)
{
a--;
SdrObject* pObj = aSelection[a];
SdrObjList* pThisOL = pObj->getParentOfSdrObject();
if(pAktOL != pThisOL)
{
pAktOL = pThisOL;
}
if(ImpCanConvertForCombine(pObj))
{
// Obj merken fuer Attribute kopieren
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, true)));
aPolyPolygon.insert(0, aTmpPoly);
if(!pInsOL)
{
nInsPos = pObj->GetNavigationPosition() + 1L;
pInsOL = pObj->getParentOfSdrObject();
}
aRemoveMerker.push_back(pObj);
}
}
if(bNoPolyPoly)
{
basegfx::B2DPolygon aCombinedPolygon(ImpCombineToSinglePolygon(aPolyPolygon));
aPolyPolygon.clear();
aPolyPolygon.append(aCombinedPolygon);
}
const sal_uInt32 nPolyCount(aPolyPolygon.count());
if(nPolyCount)
{
if(nPolyCount > 1L)
{
aPolyPolygon.setClosed(true);
}
else
{
// auf Polyline Checken
const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0L));
const sal_uInt32 nPointCount(aPolygon.count());
if(nPointCount > 2)
{
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);
}
}
}
}
SdrPathObj* pPath = new SdrPathObj(getSdrModelFromSdrView(), aPolyPolygon);
// Attribute des untersten Objekts
ImpCopyAttributes(pAttrObj, pPath);
// #100408# 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();
// #110635#
// Take fill style/closed state of pAttrObj in account when deciding to change the line style
const SdrPathObj* pSdrPathObj = dynamic_cast< const SdrPathObj* >(pAttrObj);
const bool bIsClosedPathObj(pSdrPathObj && pSdrPathObj->isClosed());
if(XLINE_NONE == eLineStyle && (XFILL_NONE == eFillStyle || !bIsClosedPathObj))
{
pPath->SetMergedItem(XLineStyleItem(XLINE_SOLID));
}
pInsOL->InsertObjectToSdrObjList(*pPath,nInsPos);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pPath));
}
// #111111#
// Here was a severe error: Without UnmarkAllObj, the new object was marked
// additionally to the two ones which are deleted below. As sal_Int32 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();
MarkObj(*pPath, false );
}
else
{
setSdrObjectSelection(aSelection);
}
// sort as if selection to get comment identical to behaviour before selection change
sortSdrObjectSelection(aRemoveMerker);
if( bUndo )
{
SetUndoComment(
ImpGetResStr(bNoPolyPoly ? STR_EditCombine_OnePoly : STR_EditCombine_PolyPoly),
getSelectionDescription(aRemoveMerker));
}
// die tatsaechlich verwendeten Objekte aus der Liste entfernen
deleteSdrObjectsWithUndo(aRemoveMerker);
if( bUndo )
{
EndUndo();
}
}
}
bool SdrEditView::ImpCanDismantle(const basegfx::B2DPolyPolygon& rPpolyPolygon, bool bMakeLines) const
{
bool bCan(false);
const sal_uInt32 nPolygonCount(rPpolyPolygon.count());
if(nPolygonCount >= 2)
{
// #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
bCan = true;
}
else if(bMakeLines && 1 == 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 > 2)
{
bCan = true;
}
}
return bCan;
}
bool SdrEditView::ImpCanDismantle(const SdrObject* pObj, bool bMakeLines) const
{
bool bOtherObjs(false); // true=andere Objekte ausser PathObj's vorhanden
bool bMin1PolyPoly(false); // true=mind. 1 PolyPolygon mit mehr als ein Polygon vorhanden
SdrObjList* pOL = pObj->getChildrenOfSdrObject();
if(pOL)
{
// Aha, Gruppenobjekt. Also alle Member ansehen.
// Alle muessen PathObjs sein !
SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
while(aIter.IsMore() && !bOtherObjs)
{
const SdrObject* pObj1 = aIter.Next();
const SdrPathObj* pPath = dynamic_cast< const SdrPathObj* >( pObj1);
if(pPath)
{
if(ImpCanDismantle(pPath->getB2DPolyPolygonInObjectCoordinates(), bMakeLines))
{
bMin1PolyPoly = true;
}
SdrObjTransformInfoRec aInfo;
pObj1->TakeObjInfo(aInfo);
if(!aInfo.mbCanConvToPath)
{
// Passiert z.B. im Falle Fontwork (Joe, 28-11-95)
bOtherObjs = true;
}
}
else
{
bOtherObjs = true;
}
}
}
else
{
const SdrPathObj* pPath = dynamic_cast< const SdrPathObj* >(pObj);
const SdrObjCustomShape* pCustomShape = dynamic_cast< const SdrObjCustomShape* >(pObj);
// #i37011#
if(pPath)
{
if(ImpCanDismantle(pPath->getB2DPolyPolygonInObjectCoordinates(), bMakeLines))
{
bMin1PolyPoly = true;
}
SdrObjTransformInfoRec aInfo;
pObj->TakeObjInfo(aInfo);
// #69711 : new condition isLine() to be able to break simple Lines
if(!(aInfo.mbCanConvToPath || aInfo.mbCanConvToPoly) && !pPath->isLine())
{
// Passiert z.B. im Falle Fontwork (Joe, 28-11-95)
bOtherObjs = true;
}
}
else if(pCustomShape)
{
if(bMakeLines)
{
// allow break command
bMin1PolyPoly = true;
}
}
else
{
bOtherObjs = true;
}
}
return bMin1PolyPoly && !bOtherObjs;
}
void SdrEditView::ImpDismantleOneObject(const SdrObject* pObj, SdrObjList& rOL, sal_uInt32& rPos, bool bMakeLines)
{
const SdrPathObj* pSrcPath = dynamic_cast< const SdrPathObj* >(pObj);
const SdrObjCustomShape* pCustomShape = dynamic_cast< const SdrObjCustomShape* >(pObj);
const bool bUndo(IsUndoEnabled());
if(pSrcPath)
{
// #i74631# redesigned due to XpolyPolygon removal and explicit constructors
SdrObject* pLast = 0; // fuer die Zuweisung des OutlinerParaObject
const basegfx::B2DPolyPolygon aPolyPolygon(pSrcPath->getB2DPolyPolygonInObjectCoordinates());
const sal_uInt32 nPolyCount(aPolyPolygon.count());
for(sal_uInt32 a(0); a < nPolyCount; a++)
{
const basegfx::B2DPolygon& rCandidate(aPolyPolygon.getB2DPolygon(a));
const sal_uInt32 nPointCount(rCandidate.count());
if(!bMakeLines || nPointCount < 2)
{
SdrPathObj* pPath = new SdrPathObj(getSdrModelFromSdrView(), basegfx::B2DPolyPolygon(rCandidate));
ImpCopyAttributes(pSrcPath, pPath);
pLast = pPath;
rOL.InsertObjectToSdrObjList(*pPath, rPos);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pPath));
}
MarkObj(*pPath, false );
rPos++;
}
else
{
const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
for(sal_uInt32 b(0); b < nLoopCount; b++)
{
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));
}
else
{
aNewPolygon.append(rCandidate.getB2DPoint(nNextIndex));
}
SdrPathObj* pPath = new SdrPathObj(getSdrModelFromSdrView(), basegfx::B2DPolyPolygon(aNewPolygon));
ImpCopyAttributes(pSrcPath, pPath);
pLast = pPath;
rOL.InsertObjectToSdrObjList(*pPath, rPos);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pPath));
}
MarkObj(*pPath, false );
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->CloneSdrObject();
DBG_ASSERT(pCandidate, "SdrEditView::ImpDismantleOneObject: Could not clone SdrObject (!)");
//pCandidate->SetModel(pCustomShape->GetModel());
if(((SdrOnOffItem&)pCustomShape->GetMergedItem(SDRATTR_SHADOW)).GetValue())
{
if(dynamic_cast< const SdrObjGroup* >(pReplacement))
{
pCandidate->SetMergedItem(SdrOnOffItem(SDRATTR_SHADOW, true));
}
}
rOL.InsertObjectToSdrObjList(*pCandidate, rPos);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pCandidate));
}
MarkObj(*pCandidate, false );
if(pCustomShape->HasText() && !pCustomShape->IsTextPath())
{
// #i37011# also create a text object and add at rPos + 1
SdrTextObj* pTextObj = (SdrTextObj*)SdrObjFactory::MakeNewObject(
getSdrModelFromSdrView(),
SdrObjectCreationInfo(OBJ_TEXT, pCustomShape->GetObjInventor()));
// Copy text content
OutlinerParaObject* pParaObj = pCustomShape->GetOutlinerParaObject();
if(pParaObj)
{
pTextObj->SetOutlinerParaObject(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));
// create transformation for text object.
// TTTT: Need to check text border distances handling
const basegfx::B2DRange aRawUnitTextRange(pCustomShape->getRawUnifiedTextRange());
// get TopLeft and BottomRight when applying current objects scale and translate,
// but leave out rot and shear TTTT need to check mirroring
const basegfx::B2DHomMatrix aJustScaleTranslate(
basegfx::tools::createScaleTranslateB2DHomMatrix(
pCustomShape->getSdrObjectScale(),
pCustomShape->getSdrObjectTranslate()));
const basegfx::B2DPoint aTopLeft(aJustScaleTranslate * aRawUnitTextRange.getMinimum());
const basegfx::B2DPoint aBottomRight(aJustScaleTranslate * aRawUnitTextRange.getMaximum());
// aBottomRight may now be top/left of aTopLeft containing the evtl. applied
// mirroring. Use it to create scale for the traget transformation. Also use
// already created TopLeft as translation
const basegfx::B2DHomMatrix aTextTransform(
basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
aBottomRight - aTopLeft,
pCustomShape->getSdrObjectShearX(),
pCustomShape->getSdrObjectRotate(),
aTopLeft));
// set new transformation to text object
pTextObj->setSdrObjectTransformation(aTextTransform);
// set modified ItemSet at text object
pTextObj->SetMergedItemSet(aTargetItemSet);
// insert object
rOL.InsertObjectToSdrObjList(*pTextObj, rPos + 1);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pTextObj));
}
MarkObj(*pTextObj, false );
}
}
}
}
}
void SdrEditView::DismantleMarkedObjects(bool bMakeLines)
{
if(areSdrObjectsSelected())
{
// Temporaere Marklist
SdrObjectVector aRemoveMerker;
const bool bUndo(IsUndoEnabled());
if( bUndo )
{
// Der Comment wird spaeter zusammengebaut
BegUndo(String(), String(),
bMakeLines ? SDRREPFUNC_OBJ_DISMANTLE_LINES : SDRREPFUNC_OBJ_DISMANTLE_POLYS);
}
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
clearSdrObjectSelection();
sal_uInt32 nm(0);
SdrObjList* pOL0 = 0;
for(nm = aSelection.size(); nm > 0;)
{
nm--;
SdrObject* pObj = aSelection[nm];
SdrObjList* pOL = pObj->getParentOfSdrObject();
if(pOL != pOL0)
{
pOL0 = pOL;
}
if(ImpCanDismantle(pObj, bMakeLines))
{
aRemoveMerker.push_back(pObj);
const sal_uInt32 nPos0(pObj->GetNavigationPosition());
sal_uInt32 nPos(nPos0 + 1);
SdrObjList* pSubList = pObj->getChildrenOfSdrObject();
if(pSubList && !dynamic_cast< const E3dObject* >(pObj))
{
SdrObjListIter aIter(*pSubList,IM_DEEPNOGROUPS);
while(aIter.IsMore())
{
const SdrObject* pObj1=aIter.Next();
ImpDismantleOneObject(pObj1, *pOL, nPos, bMakeLines);
}
}
else
{
ImpDismantleOneObject(pObj, *pOL, nPos, bMakeLines);
}
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
}
pOL->RemoveObjectFromSdrObjList(nPos0);
if( !bUndo )
{
deleteSdrObjectSafeAndClearPointer(pObj);
}
}
}
if( bUndo )
{
// UndoComment aus den tatsaechlich verwendeten Objekten zusammenbauen
const String aDescription(getSelectionDescription(aRemoveMerker));
SetUndoComment(ImpGetResStr(bMakeLines ? STR_EditDismantle_Lines : STR_EditDismantle_Polys), aDescription);
// die tatsaechlich verwendeten Objekten aus der Liste entfernen
EndUndo();
}
}
}
void SdrEditView::GroupMarked(const SdrObject* pUserGrp)
{
if(areSdrObjectsSelected())
{
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
const bool bUndo(IsUndoEnabled());
clearSdrObjectSelection();
if( bUndo )
{
BegUndo(ImpGetResStr(STR_EditGroup), getSelectionDescription(aSelection), SDRREPFUNC_OBJ_GROUP);
for(sal_uInt32 nm(aSelection.size()); nm > 0;)
{
// UndoActions fuer alle betroffenen Objekte anlegen
nm--;
SdrObject* pObj = aSelection[nm];
std::vector< SdrUndoAction* > vConnectorUndoActions( CreateConnectorUndo( *pObj ) );
AddUndoActions( vConnectorUndoActions );
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoRemoveObject( *pObj ));
}
}
SdrObjectVector aNewMark;
SdrPageView* pSdrPageView = GetSdrPageView();
if(pSdrPageView)
{
SdrObjList* pAktLst = pSdrPageView->GetCurrentObjectList();
SdrObjList* pSrcLst=pAktLst;
SdrObjList* pSrcLst0=pSrcLst;
SdrPage& rPage = pSdrPageView->getSdrPageFromSdrPageView();
SdrObject* pGrp = 0;
SdrObject* pRefObj = 0; // Referenz fuer InsertReason (-> rumankern im Writer)
SdrObject* pRefObj1 = 0; // Referenz fuer InsertReason (-> rumankern im Writer)
SdrObjList* pDstLst = 0;
// Falls alle markierten Objekte aus Fremden Obj-Listen
// kommen, kommt das Gruppenobjekt an das Ende der Liste.
sal_uInt32 nInsPos(pSrcLst->GetObjCount());
bool bNeedInsPos(true);
for(sal_uInt32 nm(aSelection.size()); nm > 0;)
{
nm--;
if(!pGrp)
{
if(pUserGrp)
{
pGrp = pUserGrp->CloneSdrObject();
}
if(!pGrp)
{
pGrp = new SdrObjGroup(getSdrModelFromSdrView());
}
pDstLst = pGrp->getChildrenOfSdrObject();
DBG_ASSERT(pDstLst!=0,"Angebliches Gruppenobjekt liefert keine Objektliste");
}
SdrObject* pObj = aSelection[nm];
pSrcLst = pObj->getParentOfSdrObject();
const bool bForeignList(pSrcLst != pAktLst);
const bool bGrouped(pSrcLst != &rPage);
if (!bForeignList && bNeedInsPos)
{
nInsPos = pObj->GetNavigationPosition(); // ua, damit sind alle ObjOrdNum der Page gesetzt
nInsPos++;
bNeedInsPos = false;
}
pSrcLst->RemoveObjectFromSdrObjList(pObj->GetNavigationPosition());
if (!bForeignList)
{
nInsPos--; // InsertPos korregieren
}
pDstLst->InsertObjectToSdrObjList(*pObj, 0);
removeSdrObjectFromSelection(*pObj);
if(!pRefObj1)
{
pRefObj1=pObj; // Das oberste sichtbare Objekt
}
if (!bGrouped)
{
if(!pRefObj)
{
pRefObj=pObj; // Das oberste sichtbare nicht gruppierte Objekt
}
}
pSrcLst0 = pSrcLst;
}
if(!pRefObj)
{
pRefObj=pRefObj1;
}
if(pGrp)
{
aNewMark.push_back(pGrp);
pAktLst->InsertObjectToSdrObjList(*pGrp, nInsPos);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pGrp));
const sal_uInt32 nAnz(pDstLst->GetObjCount());
for(sal_uInt32 no(0); no < nAnz; no++)
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoInsertObject(*pDstLst->GetObj(no)));
}
}
}
}
if(aNewMark.size())
{
setSdrObjectSelection(aNewMark); // TTTT should be the same, check grouping
}
else
{
setSdrObjectSelection(aSelection); // TTTT: set old selection
}
if( bUndo )
{
EndUndo();
}
}
}
void SdrEditView::UnGroupMarked()
{
if(areSdrObjectsSelected() && GetSdrPageView())
{
SdrObjList* pDstLst = GetSdrPageView()->GetCurrentObjectList();
if(pDstLst)
{
const bool bUndo(IsUndoEnabled());
if( bUndo )
{
BegUndo(String(), String(), SDRREPFUNC_OBJ_UNGROUP);
}
sal_uInt32 nCount(0);
XubString aName1;
XubString aName;
bool bNameOk(false);
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
SdrObjectVector aNewMark;
clearSdrObjectSelection();
for(sal_uInt32 nm(aSelection.size()); nm > 0;)
{
nm--;
SdrObject* pGrp = aSelection[nm];
SdrObjList* pSrcLst = pGrp->getChildrenOfSdrObject();
if(pSrcLst)
{
nCount++;
if(1 == nCount)
{
pGrp->TakeObjNameSingul(aName); // Bezeichnung der Gruppe holen
pGrp->TakeObjNamePlural(aName1); // Bezeichnung der Gruppe holen
bNameOk = true;
}
else
{
if(2 == nCount)
{
aName = aName1; // Pluralname setzen
}
if(bNameOk)
{
XubString aStr;
pGrp->TakeObjNamePlural(aStr); // Bezeichnung der Gruppe holen
if(!aStr.Equals(aName))
{
bNameOk = false;
}
}
}
// 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.
const sal_uInt32 nAnz(pSrcLst->GetObjCount());
sal_uInt32 nDstCnt(pGrp->GetNavigationPosition());
sal_uInt32 no;
if( bUndo )
{
for (no=nAnz; no>0;)
{
no--;
SdrObject* pObj=pSrcLst->GetObj(no);
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoRemoveObject(*pObj));
}
}
for (no=0; no<nAnz; no++)
{
SdrObject* pObj = pSrcLst->RemoveObjectFromSdrObjList(0);
pDstLst->InsertObjectToSdrObjList(*pObj, nDstCnt);
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoInsertObject(*pObj));
}
nDstCnt++;
// Kein SortCheck beim einfuegen in die MarkList, denn das
// wuerde wg. pObj->GetNavigationPosition() jedesmal ein RecalcOrdNums()
// provozieren:
aNewMark.push_back(pObj);
}
if( bUndo )
{
// nDstCnt is right, because previous inserts move group
// object deeper and increase nDstCnt.
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoDeleteObject(*pGrp));
}
pDstLst->RemoveObjectFromSdrObjList(nDstCnt);
removeSdrObjectFromSelection(*pGrp);
if(!bUndo)
{
deleteSdrObjectSafeAndClearPointer(pGrp);
}
}
}
if(nCount)
{
if (!bNameOk)
{
aName=ImpGetResStr(STR_ObjNamePluralGRUP); // Oberbegriff Gruppenobjekte verwenden, wenn verschiedene Objekte.
}
SetUndoComment(ImpGetResStr(STR_EditUngroup),aName);
}
if( bUndo )
{
EndUndo();
}
if(!aNewMark.empty())
{
setSdrObjectSelection(aNewMark); // TTTT: check if this is the same
}
else
{
setSdrObjectSelection(aSelection);
}
}
}
}
SdrObject* SdrEditView::ImpConvertOneObj(SdrObject* pObj, bool bPath, bool bLineToArea)
{
SdrObject* pNewObj = pObj->ConvertToPolyObj(bPath, bLineToArea);
if(pNewObj)
{
SdrObjList* pOL = pObj->getParentOfSdrObject();
DBG_ASSERT(pOL!=0,"ConvertTo: Obj liefert keine ObjList");
if(pOL)
{
const bool bUndo(IsUndoEnabled());
if( bUndo )
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoReplaceObject(*pObj, *pNewObj));
}
pOL->ReplaceObjectInSdrObjList(*pNewObj, pObj->GetNavigationPosition());
if( !bUndo )
{
deleteSdrObjectSafeAndClearPointer(pObj);
}
}
}
return pNewObj;
}
void SdrEditView::ImpConvertTo(bool bPath, bool bLineToArea)
{
bool bModChg(false);
if(areSdrObjectsSelected())
{
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
sal_uInt16 nDscrID(0);
clearSdrObjectSelection();
if(bLineToArea)
{
if(1 == aSelection.size())
{
nDscrID = STR_EditConvToContour;
}
else
{
nDscrID = STR_EditConvToContours;
}
BegUndo(ImpGetResStr(nDscrID), getSelectionDescription(aSelection));
}
else
{
if(bPath)
{
if(1 == aSelection.size())
{
nDscrID = STR_EditConvToCurve;
}
else
{
nDscrID = STR_EditConvToCurves;
}
BegUndo(ImpGetResStr(nDscrID), getSelectionDescription(aSelection), SDRREPFUNC_OBJ_CONVERTTOPATH);
}
else
{
if(1 == aSelection.size())
{
nDscrID = STR_EditConvToPoly;
}
else
{
nDscrID = STR_EditConvToPolys;
}
BegUndo(ImpGetResStr(nDscrID), getSelectionDescription(aSelection), SDRREPFUNC_OBJ_CONVERTTOPOLY);
}
}
SdrObjectVector aNewSelection;
for(sal_uInt32 nm(aSelection.size()); nm > 0;)
{
nm--;
SdrObject* pObj = aSelection[nm];
if(pObj->getChildrenOfSdrObject() && !dynamic_cast< const E3dObject* >(pObj))
{
SdrObject* pGrp=pObj;
SdrObjListIter aIter(*pGrp,IM_DEEPNOGROUPS);
while(aIter.IsMore())
{
pObj=aIter.Next();
if(ImpConvertOneObj(pObj, bPath, bLineToArea))
{
bModChg = true;
}
}
}
else
{
SdrObject* pNewObj=ImpConvertOneObj(pObj,bPath,bLineToArea);
if(pNewObj)
{
bModChg = true;
aNewSelection.push_back(pNewObj);
}
}
}
EndUndo();
if(!aNewSelection.empty())
{
setSdrObjectSelection(aNewSelection); // TTTT check if it's the same
}
else
{
setSdrObjectSelection(aSelection);
}
}
}
void SdrEditView::ConvertMarkedToPathObj(bool bLineToArea)
{
ImpConvertTo(true, bLineToArea);
}
void SdrEditView::ConvertMarkedToPolyObj(bool bLineToArea)
{
ImpConvertTo(false, bLineToArea);
}
void SdrEditView::DoImportMarkedMtf(SvdProgressInfo *pProgrInfo)
{
if(areSdrObjectsSelected())
{
const bool bUndo(IsUndoEnabled());
const SdrObjectVector aSelection(getSelectedSdrObjectVectorFromSdrMarkView());
SdrObjectVector aNewMarked;
if(bUndo)
{
BegUndo(
ImpGetResStr(STR_EditImportMtf),
getSelectionDescription(aSelection),
SDRREPFUNC_OBJ_IMPORTMTF);
}
clearSdrObjectSelection();
for(sal_uInt32 nm(aSelection.size()); nm > 0;)
{
// Undo Objekte fuer alle neuen Objekte erzeugen
// zwischen den Metafiles auf Abbruch testen
if(pProgrInfo)
{
pProgrInfo->SetNextObject();
if(!pProgrInfo->ReportActions(0))
{
break;
}
}
nm--;
SdrObject* pObj = aSelection[nm];
SdrObjList* pOL = pObj->getParentOfSdrObject();
const sal_uInt32 nInsPos(pObj->GetNavigationPosition() + 1);
SdrGrafObj* pGraf = dynamic_cast< SdrGrafObj* >(pObj);
SdrOle2Obj* pOle2 = dynamic_cast< SdrOle2Obj* >(pObj);
sal_uInt32 nInsAnz(0);
GDIMetaFile aMetaFile;
basegfx::B2DHomMatrix aObjectTransform;
if(pGraf && (pGraf->HasGDIMetaFile() || pGraf->isEmbeddedSvg()))
{
if(pGraf->HasGDIMetaFile())
{
aMetaFile = pGraf->GetTransformedGraphic(
SDRGRAFOBJ_TRANSFORMATTR_COLOR|SDRGRAFOBJ_TRANSFORMATTR_MIRROR).GetGDIMetaFile();
}
else if(pGraf->isEmbeddedSvg())
{
aMetaFile = pGraf->getMetafileFromEmbeddedSvg();
}
if(aMetaFile.GetActionCount())
{
aObjectTransform = pObj->getSdrObjectTransformation();
}
}
if(pOle2 && pOle2->GetGraphic())
{
aMetaFile = pOle2->GetGraphic()->GetGDIMetaFile();
if(aMetaFile.GetActionCount())
{
aObjectTransform = pOle2->getSdrObjectTransformation();
}
}
// TTTT: ObjectTransform probably needs to be adapted, e.g. when metafile
// already contains rotations, it should be removed
if(aMetaFile.GetActionCount())
{
ImpSdrGDIMetaFileImport aFilter(getSdrModelFromSdrView(), pObj->GetLayer(), aObjectTransform);
nInsAnz = aFilter.DoImport(aMetaFile, *pOL, nInsPos, pProgrInfo);
}
if(nInsAnz)
{
for(sal_uInt32 i(0), nObj(nInsPos); i < nInsAnz; i++, nObj++)
{
SdrObject* pCandidate = pOL->GetObj(nObj);
if(bUndo)
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pCandidate));
}
// add to new selection
aNewMarked.push_back(pCandidate);
}
if(bUndo)
{
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
}
// remove object
pOL->RemoveObjectFromSdrObjList(nInsPos - 1);
if(!bUndo)
{
// if no undo, delete object
deleteSdrObjectSafeAndClearPointer(pObj);
}
}
else
{
// keep unchanged object in new selection
aNewMarked.push_back(pObj);
}
}
if(!aNewMarked.empty())
{
setSdrObjectSelection(aNewMarked); // TTTT check for equality
}
if(bUndo)
{
EndUndo();
}
}
}
//////////////////////////////////////////////////////////////////////////////
// eof