blob: c22c348f66a997e607f5fff370cc9c04f82534a3 [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 <tools/bigint.hxx>
#include <svx/xlnwtit.hxx>
#include <svl/style.hxx>
#include <svx/svdocapt.hxx>
#include <svx/xpool.hxx>
#include <svx/xpoly.hxx>
#include <svx/svdattrx.hxx>
#include <svx/svdpool.hxx>
#include <svx/svdetc.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdhdl.hxx>
#include <svx/svddrag.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdview.hxx> // fuer RectSnap
#include "svx/svdglob.hxx" // StringCache
#include "svx/svdstr.hrc" // Objektname
#include <svx/svdogrp.hxx>
#include <svx/svdpage.hxx>
#include <svx/xflhtit.hxx>
#include <svx/xflclit.hxx>
#include <svx/xfltrit.hxx>
#include <editeng/eeitem.hxx>
#include <svx/sdr/properties/captionproperties.hxx>
#include <vcl/salbtype.hxx> // FRound
#include <svx/sdr/contact/viewcontactofsdrcaptionobj.hxx>
#include <basegfx/tuple/b2dtuple.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/range/b2drange.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <svx/sdrhittesthelper.hxx>
// #i32599#
inline double ImplTwipsToMM(double fVal) { return (fVal * (127.0 / 72.0)); }
inline double ImplMMToTwips(double fVal) { return (fVal * (72.0 / 127.0)); }
////////////////////////////////////////////////////////////////////////////////////////////////////
enum EscDir {LKS,RTS,OBN,UNT};
class ImpCaptParams
{
public:
SdrCaptionType eType;
long nAngle;
long nGap;
long nEscRel;
long nEscAbs;
long nLineLen;
SdrCaptionEscDir eEscDir;
FASTBOOL bFitLineLen;
FASTBOOL bEscRel;
FASTBOOL bFixedAngle;
public:
ImpCaptParams()
{
eType =SDRCAPT_TYPE3;
bFixedAngle=sal_False;
nAngle =4500;
nGap =0;
eEscDir =SDRCAPT_ESCHORIZONTAL;
bEscRel =sal_True;
nEscRel =5000;
nEscAbs =0;
nLineLen =0;
bFitLineLen=sal_True;
}
void CalcEscPos(const Point& rTail, const Rectangle& rRect, Point& rPt, EscDir& rDir) const;
};
void ImpCaptParams::CalcEscPos(const Point& rTailPt, const Rectangle& rRect, Point& rPt, EscDir& rDir) const
{
Point aTl(rTailPt); // lokal kopieren wg. Performance
long nX,nY;
if (bEscRel) {
nX=rRect.Right()-rRect.Left();
nX=BigMulDiv(nX,nEscRel,10000);
nY=rRect.Bottom()-rRect.Top();
nY=BigMulDiv(nY,nEscRel,10000);
} else {
nX=nEscAbs;
nY=nEscAbs;
}
nX+=rRect.Left();
nY+=rRect.Top();
Point aBestPt;
EscDir eBestDir=LKS;
FASTBOOL bTryH=eEscDir==SDRCAPT_ESCBESTFIT;
if (!bTryH) {
if (eType!=SDRCAPT_TYPE1) {
bTryH=eEscDir==SDRCAPT_ESCHORIZONTAL;
} else {
bTryH=eEscDir==SDRCAPT_ESCVERTICAL;
}
}
FASTBOOL bTryV=eEscDir==SDRCAPT_ESCBESTFIT;
if (!bTryV) {
if (eType!=SDRCAPT_TYPE1) {
bTryV=eEscDir==SDRCAPT_ESCVERTICAL;
} else {
bTryV=eEscDir==SDRCAPT_ESCHORIZONTAL;
}
}
if (bTryH) {
Point aLft(rRect.Left()-nGap,nY);
Point aRgt(rRect.Right()+nGap,nY);
FASTBOOL bLft=(aTl.X()-aLft.X()<aRgt.X()-aTl.X());
if (bLft) {
eBestDir=LKS;
aBestPt=aLft;
} else {
eBestDir=RTS;
aBestPt=aRgt;
}
}
if (bTryV) {
Point aTop(nX,rRect.Top()-nGap);
Point aBtm(nX,rRect.Bottom()+nGap);
FASTBOOL bTop=(aTl.Y()-aTop.Y()<aBtm.Y()-aTl.Y());
Point aBest2;
EscDir eBest2;
if (bTop) {
eBest2=OBN;
aBest2=aTop;
} else {
eBest2=UNT;
aBest2=aBtm;
}
FASTBOOL bTakeIt=eEscDir!=SDRCAPT_ESCBESTFIT;
if (!bTakeIt) {
BigInt aHorX(aBestPt.X()-aTl.X()); aHorX*=aHorX;
BigInt aHorY(aBestPt.Y()-aTl.Y()); aHorY*=aHorY;
BigInt aVerX(aBest2.X()-aTl.X()); aVerX*=aVerX;
BigInt aVerY(aBest2.Y()-aTl.Y()); aVerY*=aVerY;
if (eType!=SDRCAPT_TYPE1) {
bTakeIt=aVerX+aVerY<aHorX+aHorY;
} else {
bTakeIt=aVerX+aVerY>=aHorX+aHorY;
}
}
if (bTakeIt) {
aBestPt=aBest2;
eBestDir=eBest2;
}
}
rPt=aBestPt;
rDir=eBestDir;
}
//////////////////////////////////////////////////////////////////////////////
// BaseProperties section
sdr::properties::BaseProperties* SdrCaptionObj::CreateObjectSpecificProperties()
{
return new sdr::properties::CaptionProperties(*this);
}
//////////////////////////////////////////////////////////////////////////////
// DrawContact section
sdr::contact::ViewContact* SdrCaptionObj::CreateObjectSpecificViewContact()
{
return new sdr::contact::ViewContactOfSdrCaptionObj(*this);
}
//////////////////////////////////////////////////////////////////////////////
TYPEINIT1(SdrCaptionObj,SdrRectObj);
SdrCaptionObj::SdrCaptionObj():
SdrRectObj(OBJ_TEXT),
aTailPoly(3), // Default Groesse: 3 Punkte = 2 Linien
mbSpecialTextBoxShadow(sal_False),
mbFixedTail(sal_False)
{
}
SdrCaptionObj::SdrCaptionObj(const Rectangle& rRect):
SdrRectObj(OBJ_TEXT,rRect),
aTailPoly(3), // Default Groesse: 3 Punkte = 2 Linien
mbSpecialTextBoxShadow(sal_False),
mbFixedTail(sal_False)
{
}
SdrCaptionObj::SdrCaptionObj(const Rectangle& rRect, const Point& rTail):
SdrRectObj(OBJ_TEXT,rRect),
aTailPoly(3), // Default Groesse: 3 Punkte = 2 Linien
mbSpecialTextBoxShadow(sal_False),
mbFixedTail(sal_False)
{
aTailPoly[0]=maFixedTailPos=rTail;
}
SdrCaptionObj::~SdrCaptionObj()
{
}
void SdrCaptionObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
{
rInfo.bRotateFreeAllowed=sal_False;
rInfo.bRotate90Allowed =sal_False;
rInfo.bMirrorFreeAllowed=sal_False;
rInfo.bMirror45Allowed =sal_False;
rInfo.bMirror90Allowed =sal_False;
rInfo.bTransparenceAllowed = sal_False;
rInfo.bGradientAllowed = sal_False;
rInfo.bShearAllowed =sal_False;
rInfo.bEdgeRadiusAllowed=sal_False;
rInfo.bCanConvToPath =sal_True;
rInfo.bCanConvToPoly =sal_True;
rInfo.bCanConvToPathLineToArea=sal_False;
rInfo.bCanConvToPolyLineToArea=sal_False;
rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
}
sal_uInt16 SdrCaptionObj::GetObjIdentifier() const
{
return sal_uInt16(OBJ_CAPTION);
}
void SdrCaptionObj::operator=(const SdrObject& rObj)
{
SdrRectObj::operator=(rObj);
aTailPoly=((SdrCaptionObj&)rObj).aTailPoly;
}
void SdrCaptionObj::TakeObjNameSingul(XubString& rName) const
{
rName=ImpGetResStr(STR_ObjNameSingulCAPTION);
String aName( GetName() );
if(aName.Len())
{
rName += sal_Unicode(' ');
rName += sal_Unicode('\'');
rName += aName;
rName += sal_Unicode('\'');
}
}
void SdrCaptionObj::TakeObjNamePlural(XubString& rName) const
{
rName=ImpGetResStr(STR_ObjNamePluralCAPTION);
}
basegfx::B2DPolyPolygon SdrCaptionObj::TakeXorPoly() const
{
basegfx::B2DPolyPolygon aPolyPoly(SdrRectObj::TakeXorPoly());
aPolyPoly.append(aTailPoly.getB2DPolygon());
return aPolyPoly;
}
sal_uInt32 SdrCaptionObj::GetHdlCount() const
{
sal_uInt32 nAnz1(SdrRectObj::GetHdlCount());
// sal_uInt32 nAnz2(aTailPoly.GetSize());
// Derzeit ist nur das Draggen des Schwanzendes implementiert
return nAnz1 + 1L;
}
SdrHdl* SdrCaptionObj::GetHdl(sal_uInt32 nHdlNum) const
{
const sal_uInt32 nRectHdlAnz(SdrRectObj::GetHdlCount());
if(nHdlNum < nRectHdlAnz)
{
return SdrRectObj::GetHdl(nHdlNum);
}
else
{
sal_uInt32 nPntNum(nHdlNum);
nPntNum -= nRectHdlAnz;
if(nPntNum < aTailPoly.GetSize())
{
SdrHdl* pHdl = new SdrHdl(aTailPoly.GetPoint((sal_uInt16)nPntNum), HDL_POLY);
pHdl->SetPolyNum(1L);
pHdl->SetPointNum(nPntNum);
return pHdl;
}
else
{
return 0L;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool SdrCaptionObj::hasSpecialDrag() const
{
return true;
}
bool SdrCaptionObj::beginSpecialDrag(SdrDragStat& rDrag) const
{
const SdrHdl* pHdl = rDrag.GetHdl();
rDrag.SetEndDragChangesAttributes(true);
rDrag.SetEndDragChangesGeoAndAttributes(true);
if(pHdl && 0 == pHdl->GetPolyNum())
{
return SdrRectObj::beginSpecialDrag(rDrag);
}
else
{
rDrag.SetOrtho8Possible(true);
if(!pHdl)
{
if (bMovProt)
return 0;
rDrag.SetNoSnap(true);
rDrag.SetActionRect(aRect);
Point aHit(rDrag.GetStart());
if(rDrag.GetPageView() && SdrObjectPrimitiveHit(*this, aHit, 0, *rDrag.GetPageView(), 0, false))
{
return true;
}
}
else
{
if((1 == pHdl->GetPolyNum()) && (0 == pHdl->GetPointNum()))
return true;
}
}
return false;
}
bool SdrCaptionObj::applySpecialDrag(SdrDragStat& rDrag)
{
const SdrHdl* pHdl = rDrag.GetHdl();
if(pHdl && 0 == pHdl->GetPolyNum())
{
const bool bRet(SdrRectObj::applySpecialDrag(rDrag));
ImpRecalcTail();
ActionChanged();
return bRet;
}
else
{
Point aDelt(rDrag.GetNow()-rDrag.GetStart());
if(!pHdl)
{
aRect.Move(aDelt.X(),aDelt.Y());
}
else
{
aTailPoly[0] += aDelt;
}
ImpRecalcTail();
ActionChanged();
return true;
}
}
String SdrCaptionObj::getSpecialDragComment(const SdrDragStat& rDrag) const
{
const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
if(bCreateComment)
{
return String();
}
else
{
const SdrHdl* pHdl = rDrag.GetHdl();
if(pHdl && 0 == pHdl->GetPolyNum())
{
return SdrRectObj::getSpecialDragComment(rDrag);
}
else
{
XubString aStr;
if(!pHdl)
{
ImpTakeDescriptionStr(STR_DragCaptFram, aStr);
}
else
{
ImpTakeDescriptionStr(STR_DragCaptTail, aStr);
}
return aStr;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void SdrCaptionObj::ImpGetCaptParams(ImpCaptParams& rPara) const
{
const SfxItemSet& rSet = GetObjectItemSet();
rPara.eType =((SdrCaptionTypeItem&) (rSet.Get(SDRATTR_CAPTIONTYPE ))).GetValue();
rPara.bFixedAngle=((SdrCaptionFixedAngleItem&)(rSet.Get(SDRATTR_CAPTIONANGLE ))).GetValue();
rPara.nAngle =((SdrCaptionAngleItem&) (rSet.Get(SDRATTR_CAPTIONFIXEDANGLE))).GetValue();
rPara.nGap =((SdrCaptionGapItem&) (rSet.Get(SDRATTR_CAPTIONGAP ))).GetValue();
rPara.eEscDir =((SdrCaptionEscDirItem&) (rSet.Get(SDRATTR_CAPTIONESCDIR ))).GetValue();
rPara.bEscRel =((SdrCaptionEscIsRelItem&) (rSet.Get(SDRATTR_CAPTIONESCISREL ))).GetValue();
rPara.nEscRel =((SdrCaptionEscRelItem&) (rSet.Get(SDRATTR_CAPTIONESCREL ))).GetValue();
rPara.nEscAbs =((SdrCaptionEscAbsItem&) (rSet.Get(SDRATTR_CAPTIONESCABS ))).GetValue();
rPara.nLineLen =((SdrCaptionLineLenItem&) (rSet.Get(SDRATTR_CAPTIONLINELEN ))).GetValue();
rPara.bFitLineLen=((SdrCaptionFitLineLenItem&)(rSet.Get(SDRATTR_CAPTIONFITLINELEN))).GetValue();
}
void SdrCaptionObj::ImpRecalcTail()
{
ImpCaptParams aPara;
ImpGetCaptParams(aPara);
ImpCalcTail(aPara,aTailPoly,aRect);
SetRectsDirty();
SetXPolyDirty();
}
// #i35971#
// SdrCaptionObj::ImpCalcTail1 does move the object(!). What a hack.
// I really wonder why this had not triggered problems before. I am
// sure there are some places where SetTailPos() is called at least
// twice or SetSnapRect after it again just to work around this.
// Changed this method to not do that.
// Also found why this has been done: For interactive dragging of the
// tail end pos for SDRCAPT_TYPE1. This sure was the simplest method
// to achieve this, for the cost to make a whole group of const methods
// of this object implicitly chainging the object's position.
void SdrCaptionObj::ImpCalcTail1(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
{
Polygon aPol(2);
Point aTl(rPoly[0]);
aPol[0] = aTl;
aPol[1] = aTl;
EscDir eEscDir;
Point aEscPos;
rPara.CalcEscPos(aTl, rRect, aEscPos, eEscDir);
aPol[1] = aEscPos;
if(eEscDir==LKS || eEscDir==RTS)
{
aPol[0].X() = aEscPos.X();
}
else
{
aPol[0].Y() = aEscPos.Y();
}
rPoly = aPol;
}
void SdrCaptionObj::ImpCalcTail2(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
{ // Gap/EscDir/EscPos/Angle
Polygon aPol(2);
Point aTl(rPoly[0]);
aPol[0]=aTl;
EscDir eEscDir;
Point aEscPos;
rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
aPol[1]=aEscPos;
if (!rPara.bFixedAngle) {
// fehlende Implementation
}
rPoly=aPol;
}
void SdrCaptionObj::ImpCalcTail3(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
{ // Gap/EscDir/EscPos/Angle/LineLen
Polygon aPol(3);
Point aTl(rPoly[0]);
aPol[0]=aTl;
EscDir eEscDir;
Point aEscPos;
rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
aPol[1]=aEscPos;
aPol[2]=aEscPos;
if (eEscDir==LKS || eEscDir==RTS) {
if (rPara.bFitLineLen) {
aPol[1].X()=(aTl.X()+aEscPos.X())/2;
} else {
if (eEscDir==LKS) aPol[1].X()-=rPara.nLineLen;
else aPol[1].X()+=rPara.nLineLen;
}
} else {
if (rPara.bFitLineLen) {
aPol[1].Y()=(aTl.Y()+aEscPos.Y())/2;
} else {
if (eEscDir==OBN) aPol[1].Y()-=rPara.nLineLen;
else aPol[1].Y()+=rPara.nLineLen;
}
}
if (!rPara.bFixedAngle) {
// fehlende Implementation
}
rPoly=aPol;
}
void SdrCaptionObj::ImpCalcTail4(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
{
ImpCalcTail3(rPara,rPoly,rRect);
}
void SdrCaptionObj::ImpCalcTail(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
{
switch (rPara.eType) {
case SDRCAPT_TYPE1: ImpCalcTail1(rPara,rPoly,rRect); break;
case SDRCAPT_TYPE2: ImpCalcTail2(rPara,rPoly,rRect); break;
case SDRCAPT_TYPE3: ImpCalcTail3(rPara,rPoly,rRect); break;
case SDRCAPT_TYPE4: ImpCalcTail4(rPara,rPoly,rRect); break;
}
}
FASTBOOL SdrCaptionObj::BegCreate(SdrDragStat& rStat)
{
if (aRect.IsEmpty()) return sal_False; // Create z.Zt. nur mit vorgegebenen Rect
ImpCaptParams aPara;
ImpGetCaptParams(aPara);
aRect.SetPos(rStat.GetNow());
aTailPoly[0]=rStat.GetStart();
ImpCalcTail(aPara,aTailPoly,aRect);
rStat.SetActionRect(aRect);
return sal_True;
}
FASTBOOL SdrCaptionObj::MovCreate(SdrDragStat& rStat)
{
ImpCaptParams aPara;
ImpGetCaptParams(aPara);
aRect.SetPos(rStat.GetNow());
ImpCalcTail(aPara,aTailPoly,aRect);
rStat.SetActionRect(aRect);
SetBoundRectDirty();
bSnapRectDirty=sal_True;
return sal_True;
}
FASTBOOL SdrCaptionObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
{
ImpCaptParams aPara;
ImpGetCaptParams(aPara);
aRect.SetPos(rStat.GetNow());
ImpCalcTail(aPara,aTailPoly,aRect);
SetRectsDirty();
return (eCmd==SDRCREATE_FORCEEND || rStat.GetPointAnz()>=2);
}
FASTBOOL SdrCaptionObj::BckCreate(SdrDragStat& /*rStat*/)
{
return sal_False;
}
void SdrCaptionObj::BrkCreate(SdrDragStat& /*rStat*/)
{
}
basegfx::B2DPolyPolygon SdrCaptionObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
{
basegfx::B2DPolyPolygon aRetval;
const basegfx::B2DRange aRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());
aRetval.append(basegfx::tools::createPolygonFromRect(aRange));
aRetval.append(aTailPoly.getB2DPolygon());
return aRetval;
}
Pointer SdrCaptionObj::GetCreatePointer() const
{
return Pointer(POINTER_DRAW_CAPTION);
}
void SdrCaptionObj::NbcMove(const Size& rSiz)
{
SdrRectObj::NbcMove(rSiz);
MovePoly(aTailPoly,rSiz);
if(mbFixedTail)
SetTailPos(GetFixedTailPos());
}
void SdrCaptionObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
{
SdrRectObj::NbcResize(rRef,xFact,yFact);
ResizePoly(aTailPoly,rRef,xFact,yFact);
ImpRecalcTail();
if(mbFixedTail)
SetTailPos(GetFixedTailPos());
}
void SdrCaptionObj::NbcSetRelativePos(const Point& rPnt)
{
Point aRelPos0(aTailPoly.GetPoint(0)-aAnchor);
Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
NbcMove(aSiz); // Der ruft auch das SetRectsDirty()
}
Point SdrCaptionObj::GetRelativePos() const
{
return aTailPoly.GetPoint(0)-aAnchor;
}
void SdrCaptionObj::NbcSetAnchorPos(const Point& rPnt)
{
SdrRectObj::NbcSetAnchorPos(rPnt);
// !!!!! fehlende Impl.
}
const Point& SdrCaptionObj::GetAnchorPos() const
{
// !!!!! fehlende Impl.
return SdrRectObj::GetAnchorPos();
}
void SdrCaptionObj::RecalcSnapRect()
{
SdrRectObj::RecalcSnapRect();
// #i32599#
// maSnapRect.Union(aTailPoly.GetBoundRect());
// !!!!! fehlende Impl.
}
const Rectangle& SdrCaptionObj::GetSnapRect() const
{
return SdrRectObj::GetSnapRect();
}
void SdrCaptionObj::NbcSetSnapRect(const Rectangle& rRect)
{
// #i32599#
// Move back to see the rectangle of the underlying SdrRectObj
// as the SnapRect, without the TailPos. That simplifies SnapRect
// handling again, if not allows it at all...
SdrRectObj::NbcSetSnapRect(rRect);
}
const Rectangle& SdrCaptionObj::GetLogicRect() const
{
return aRect;
}
void SdrCaptionObj::NbcSetLogicRect(const Rectangle& rRect)
{
SdrRectObj::NbcSetLogicRect(rRect);
ImpRecalcTail();
}
const Point& SdrCaptionObj::GetTailPos() const
{
return aTailPoly[0];
}
void SdrCaptionObj::SetTailPos(const Point& rPos)
{
if (aTailPoly.GetSize()==0 || aTailPoly[0]!=rPos) {
Rectangle aBoundRect0; if (pUserCall!=NULL) aBoundRect0=GetLastBoundRect();
// #110094#-14 SendRepaintBroadcast();
NbcSetTailPos(rPos);
SetChanged();
BroadcastObjectChange();
SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0);
}
}
void SdrCaptionObj::NbcSetTailPos(const Point& rPos)
{
aTailPoly[0]=rPos;
ImpRecalcTail();
}
sal_uInt32 SdrCaptionObj::GetSnapPointCount() const
{
// !!!!! fehlende Impl.
return 0L;
}
Point SdrCaptionObj::GetSnapPoint(sal_uInt32 /*i*/) const
{
// !!!!! fehlende Impl.
return Point(0,0);
}
void SdrCaptionObj::SetModel(SdrModel* pNewModel)
{
SdrRectObj::SetModel(pNewModel);
ImpRecalcTail();
}
void SdrCaptionObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
{
SdrRectObj::Notify(rBC,rHint);
ImpRecalcTail();
}
SdrObjGeoData* SdrCaptionObj::NewGeoData() const
{
return new SdrCaptObjGeoData;
}
void SdrCaptionObj::SaveGeoData(SdrObjGeoData& rGeo) const
{
SdrRectObj::SaveGeoData(rGeo);
SdrCaptObjGeoData& rCGeo=(SdrCaptObjGeoData&)rGeo;
rCGeo.aTailPoly=aTailPoly;
}
void SdrCaptionObj::RestGeoData(const SdrObjGeoData& rGeo)
{
SdrRectObj::RestGeoData(rGeo);
SdrCaptObjGeoData& rCGeo=(SdrCaptObjGeoData&)rGeo;
aTailPoly=rCGeo.aTailPoly;
}
SdrObject* SdrCaptionObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const
{ // #42334# - Convert implementiert
SdrObject* pRect=SdrRectObj::DoConvertToPolyObj(bBezier, bAddText);
SdrObject* pTail = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aTailPoly.getB2DPolygon()), sal_False, bBezier);
SdrObject* pRet=(pTail!=NULL) ? pTail : pRect;
if (pTail!=NULL && pRect!=NULL) {
FASTBOOL bInsRect=sal_True;
FASTBOOL bInsTail=sal_True;
SdrObjList* pOL=pTail->GetSubList();
if (pOL!=NULL) { pRet=pRect; bInsTail=sal_False; }
if (pOL==NULL) pOL=pRect->GetSubList();
if (pOL!=NULL) { pRet=pRect; bInsRect=sal_False; }
if (pOL==NULL) {
SdrObjGroup* pGrp=new SdrObjGroup;
pOL=pGrp->GetSubList();
pRet=pGrp;
}
if (bInsRect) pOL->NbcInsertObject(pRect);
if (bInsTail) pOL->NbcInsertObject(pTail,0);
}
return pRet;
}
// #i32599#
// Add own implementation for TRSetBaseGeometry to handle TailPos over changes.
void SdrCaptionObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
{
// break up matrix
basegfx::B2DTuple aScale;
basegfx::B2DTuple aTranslate;
double fRotate, fShearX;
rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
// #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
// in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
{
aScale.setX(fabs(aScale.getX()));
aScale.setY(fabs(aScale.getY()));
fRotate = fmod(fRotate + F_PI, F_2PI);
}
// force metric to pool metric
SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
if(eMapUnit != SFX_MAPUNIT_100TH_MM)
{
switch(eMapUnit)
{
case SFX_MAPUNIT_TWIP :
{
// position
aTranslate.setX(ImplMMToTwips(aTranslate.getX()));
aTranslate.setY(ImplMMToTwips(aTranslate.getY()));
// size
aScale.setX(ImplMMToTwips(aScale.getX()));
aScale.setY(ImplMMToTwips(aScale.getY()));
break;
}
default:
{
DBG_ERROR("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
}
}
}
// if anchor is used, make position relative to it
if( pModel->IsWriter() )
{
if(GetAnchorPos().X() || GetAnchorPos().Y())
{
aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
}
}
// build BaseRect
Point aPoint(FRound(aTranslate.getX()), FRound(aTranslate.getY()));
Rectangle aBaseRect(aPoint, Size(FRound(aScale.getX()), FRound(aScale.getY())));
// set BaseRect, but rescue TailPos over this call
const Point aTailPoint = GetTailPos();
SetSnapRect(aBaseRect);
SetTailPos(aTailPoint);
ImpRecalcTail();
}
// geometry access
basegfx::B2DPolygon SdrCaptionObj::getTailPolygon() const
{
return aTailPoly.getB2DPolygon();
}
// eof