xref: /aoo41x/main/svx/source/svdraw/svdocapt.cxx (revision a5258243)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 #include <tools/bigint.hxx>
31 #include <svx/xlnwtit.hxx>
32 #include <svl/style.hxx>
33 #include <svx/svdocapt.hxx>
34 #include <svx/xpool.hxx>
35 #include <svx/xpoly.hxx>
36 #include <svx/svdattrx.hxx>
37 #include <svx/svdpool.hxx>
38 #include <svx/svdetc.hxx>
39 #include <svx/svdtrans.hxx>
40 #include <svx/svdhdl.hxx>
41 #include <svx/svddrag.hxx>
42 #include <svx/svdmodel.hxx>
43 #include <svx/svdview.hxx>   // fuer RectSnap
44 #include "svx/svdglob.hxx"   // StringCache
45 #include "svx/svdstr.hrc"    // Objektname
46 #include <svx/svdogrp.hxx>
47 #include <svx/svdpage.hxx>
48 #include <svx/xflhtit.hxx>
49 #include <svx/xflclit.hxx>
50 #include <svx/xfltrit.hxx>
51 #include <editeng/eeitem.hxx>
52 #include <svx/sdr/properties/captionproperties.hxx>
53 #include <vcl/salbtype.hxx>		// FRound
54 #include <svx/sdr/contact/viewcontactofsdrcaptionobj.hxx>
55 #include <basegfx/tuple/b2dtuple.hxx>
56 #include <basegfx/matrix/b2dhommatrix.hxx>
57 #include <basegfx/polygon/b2dpolygon.hxx>
58 #include <basegfx/range/b2drange.hxx>
59 #include <basegfx/polygon/b2dpolygontools.hxx>
60 #include <svx/sdrhittesthelper.hxx>
61 
62 // #i32599#
63 inline double ImplTwipsToMM(double fVal) { return (fVal * (127.0 / 72.0)); }
64 inline double ImplMMToTwips(double fVal) { return (fVal * (72.0 / 127.0)); }
65 
66 ////////////////////////////////////////////////////////////////////////////////////////////////////
67 
68 enum EscDir {LKS,RTS,OBN,UNT};
69 
70 class ImpCaptParams
71 {
72 public:
73 	SdrCaptionType				eType;
74 	long						nAngle;
75 	long						nGap;
76 	long						nEscRel;
77 	long						nEscAbs;
78 	long						nLineLen;
79 	SdrCaptionEscDir			eEscDir;
80 	FASTBOOL					bFitLineLen;
81 	FASTBOOL					bEscRel;
82 	FASTBOOL					bFixedAngle;
83 
84 public:
85 	ImpCaptParams()
86 	{
87 		eType      =SDRCAPT_TYPE3;
88 		bFixedAngle=sal_False;
89 		nAngle     =4500;
90 		nGap       =0;
91 		eEscDir    =SDRCAPT_ESCHORIZONTAL;
92 		bEscRel    =sal_True;
93 		nEscRel    =5000;
94 		nEscAbs    =0;
95 		nLineLen   =0;
96 		bFitLineLen=sal_True;
97 	}
98 	void CalcEscPos(const Point& rTail, const Rectangle& rRect, Point& rPt, EscDir& rDir) const;
99 };
100 
101 void ImpCaptParams::CalcEscPos(const Point& rTailPt, const Rectangle& rRect, Point& rPt, EscDir& rDir) const
102 {
103 	Point aTl(rTailPt); // lokal kopieren wg. Performance
104 	long nX,nY;
105 	if (bEscRel) {
106 		nX=rRect.Right()-rRect.Left();
107 		nX=BigMulDiv(nX,nEscRel,10000);
108 		nY=rRect.Bottom()-rRect.Top();
109 		nY=BigMulDiv(nY,nEscRel,10000);
110 	} else {
111 		nX=nEscAbs;
112 		nY=nEscAbs;
113 	}
114 	nX+=rRect.Left();
115 	nY+=rRect.Top();
116 	Point  aBestPt;
117 	EscDir eBestDir=LKS;
118 	FASTBOOL bTryH=eEscDir==SDRCAPT_ESCBESTFIT;
119 	if (!bTryH) {
120 		if (eType!=SDRCAPT_TYPE1) {
121 			bTryH=eEscDir==SDRCAPT_ESCHORIZONTAL;
122 		} else {
123 			bTryH=eEscDir==SDRCAPT_ESCVERTICAL;
124 		}
125 	}
126 	FASTBOOL bTryV=eEscDir==SDRCAPT_ESCBESTFIT;
127 	if (!bTryV) {
128 		if (eType!=SDRCAPT_TYPE1) {
129 			bTryV=eEscDir==SDRCAPT_ESCVERTICAL;
130 		} else {
131 			bTryV=eEscDir==SDRCAPT_ESCHORIZONTAL;
132 		}
133 	}
134 
135 	if (bTryH) {
136 		Point aLft(rRect.Left()-nGap,nY);
137 		Point aRgt(rRect.Right()+nGap,nY);
138 		FASTBOOL bLft=(aTl.X()-aLft.X()<aRgt.X()-aTl.X());
139 		if (bLft) {
140 			eBestDir=LKS;
141 			aBestPt=aLft;
142 		} else {
143 			eBestDir=RTS;
144 			aBestPt=aRgt;
145 		}
146 	}
147 	if (bTryV) {
148 		Point aTop(nX,rRect.Top()-nGap);
149 		Point aBtm(nX,rRect.Bottom()+nGap);
150 		FASTBOOL bTop=(aTl.Y()-aTop.Y()<aBtm.Y()-aTl.Y());
151 		Point aBest2;
152 		EscDir eBest2;
153 		if (bTop) {
154 			eBest2=OBN;
155 			aBest2=aTop;
156 		} else {
157 			eBest2=UNT;
158 			aBest2=aBtm;
159 		}
160 		FASTBOOL bTakeIt=eEscDir!=SDRCAPT_ESCBESTFIT;
161 		if (!bTakeIt) {
162 			BigInt aHorX(aBestPt.X()-aTl.X()); aHorX*=aHorX;
163 			BigInt aHorY(aBestPt.Y()-aTl.Y()); aHorY*=aHorY;
164 			BigInt aVerX(aBest2.X()-aTl.X());  aVerX*=aVerX;
165 			BigInt aVerY(aBest2.Y()-aTl.Y());  aVerY*=aVerY;
166 			if (eType!=SDRCAPT_TYPE1) {
167 				bTakeIt=aVerX+aVerY<aHorX+aHorY;
168 			} else {
169 				bTakeIt=aVerX+aVerY>=aHorX+aHorY;
170 			}
171 		}
172 		if (bTakeIt) {
173 			aBestPt=aBest2;
174 			eBestDir=eBest2;
175 		}
176 	}
177 	rPt=aBestPt;
178 	rDir=eBestDir;
179 }
180 
181 //////////////////////////////////////////////////////////////////////////////
182 // BaseProperties section
183 
184 sdr::properties::BaseProperties* SdrCaptionObj::CreateObjectSpecificProperties()
185 {
186 	return new sdr::properties::CaptionProperties(*this);
187 }
188 
189 //////////////////////////////////////////////////////////////////////////////
190 // DrawContact section
191 
192 sdr::contact::ViewContact* SdrCaptionObj::CreateObjectSpecificViewContact()
193 {
194 	return new sdr::contact::ViewContactOfSdrCaptionObj(*this);
195 }
196 
197 //////////////////////////////////////////////////////////////////////////////
198 
199 TYPEINIT1(SdrCaptionObj,SdrRectObj);
200 
201 SdrCaptionObj::SdrCaptionObj():
202 	SdrRectObj(OBJ_TEXT),
203 	aTailPoly(3),  // Default Groesse: 3 Punkte = 2 Linien
204 	mbSpecialTextBoxShadow(sal_False),
205 	mbFixedTail(sal_False)
206 {
207 }
208 
209 SdrCaptionObj::SdrCaptionObj(const Rectangle& rRect):
210 	SdrRectObj(OBJ_TEXT,rRect),
211 	aTailPoly(3),  // Default Groesse: 3 Punkte = 2 Linien
212 	mbSpecialTextBoxShadow(sal_False),
213 	mbFixedTail(sal_False)
214 {
215 }
216 
217 SdrCaptionObj::SdrCaptionObj(const Rectangle& rRect, const Point& rTail):
218 	SdrRectObj(OBJ_TEXT,rRect),
219 	aTailPoly(3),  // Default Groesse: 3 Punkte = 2 Linien
220 	mbSpecialTextBoxShadow(sal_False),
221 	mbFixedTail(sal_False)
222 {
223 	aTailPoly[0]=maFixedTailPos=rTail;
224 }
225 
226 SdrCaptionObj::~SdrCaptionObj()
227 {
228 }
229 
230 void SdrCaptionObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
231 {
232 	rInfo.bRotateFreeAllowed=sal_False;
233 	rInfo.bRotate90Allowed  =sal_False;
234 	rInfo.bMirrorFreeAllowed=sal_False;
235 	rInfo.bMirror45Allowed  =sal_False;
236 	rInfo.bMirror90Allowed  =sal_False;
237 	rInfo.bTransparenceAllowed = sal_False;
238 	rInfo.bGradientAllowed = sal_False;
239 	rInfo.bShearAllowed     =sal_False;
240 	rInfo.bEdgeRadiusAllowed=sal_False;
241 	rInfo.bCanConvToPath    =sal_True;
242 	rInfo.bCanConvToPoly    =sal_True;
243 	rInfo.bCanConvToPathLineToArea=sal_False;
244 	rInfo.bCanConvToPolyLineToArea=sal_False;
245 	rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
246 }
247 
248 sal_uInt16 SdrCaptionObj::GetObjIdentifier() const
249 {
250 	return sal_uInt16(OBJ_CAPTION);
251 }
252 
253 void SdrCaptionObj::operator=(const SdrObject& rObj)
254 {
255 	SdrRectObj::operator=(rObj);
256 	aTailPoly=((SdrCaptionObj&)rObj).aTailPoly;
257 }
258 
259 void SdrCaptionObj::TakeObjNameSingul(XubString& rName) const
260 {
261 	rName=ImpGetResStr(STR_ObjNameSingulCAPTION);
262 
263 	String aName( GetName() );
264 	if(aName.Len())
265 	{
266 		rName += sal_Unicode(' ');
267 		rName += sal_Unicode('\'');
268 		rName += aName;
269 		rName += sal_Unicode('\'');
270 	}
271 }
272 
273 void SdrCaptionObj::TakeObjNamePlural(XubString& rName) const
274 {
275 	rName=ImpGetResStr(STR_ObjNamePluralCAPTION);
276 }
277 
278 basegfx::B2DPolyPolygon SdrCaptionObj::TakeXorPoly() const
279 {
280 	basegfx::B2DPolyPolygon aPolyPoly(SdrRectObj::TakeXorPoly());
281 	aPolyPoly.append(aTailPoly.getB2DPolygon());
282 
283 	return aPolyPoly;
284 }
285 
286 sal_uInt32 SdrCaptionObj::GetHdlCount() const
287 {
288 	sal_uInt32 nAnz1(SdrRectObj::GetHdlCount());
289 	// sal_uInt32 nAnz2(aTailPoly.GetSize());
290 	// Derzeit ist nur das Draggen des Schwanzendes implementiert
291 	return nAnz1 + 1L;
292 }
293 
294 SdrHdl* SdrCaptionObj::GetHdl(sal_uInt32 nHdlNum) const
295 {
296 	const sal_uInt32 nRectHdlAnz(SdrRectObj::GetHdlCount());
297 
298 	if(nHdlNum < nRectHdlAnz)
299 	{
300 		return SdrRectObj::GetHdl(nHdlNum);
301 	}
302 	else
303 	{
304 		sal_uInt32 nPntNum(nHdlNum);
305 		nPntNum -= nRectHdlAnz;
306 
307 		if(nPntNum < aTailPoly.GetSize())
308 		{
309 			SdrHdl* pHdl = new SdrHdl(aTailPoly.GetPoint((sal_uInt16)nPntNum), HDL_POLY);
310 			pHdl->SetPolyNum(1L);
311 			pHdl->SetPointNum(nPntNum);
312 			return pHdl;
313 		}
314 		else
315 		{
316 			return 0L;
317 		}
318 	}
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////////////////////////
322 
323 bool SdrCaptionObj::hasSpecialDrag() const
324 {
325 	return true;
326 }
327 
328 bool SdrCaptionObj::beginSpecialDrag(SdrDragStat& rDrag) const
329 {
330 	const SdrHdl* pHdl = rDrag.GetHdl();
331 	rDrag.SetEndDragChangesAttributes(true);
332 	rDrag.SetEndDragChangesGeoAndAttributes(true);
333 
334 	if(pHdl && 0 == pHdl->GetPolyNum())
335     {
336 		return SdrRectObj::beginSpecialDrag(rDrag);
337 	}
338     else
339     {
340 		rDrag.SetOrtho8Possible(true);
341 
342         if(!pHdl)
343         {
344 			if (bMovProt)
345                 return 0;
346 
347 			rDrag.SetNoSnap(true);
348 			rDrag.SetActionRect(aRect);
349 
350             Point aHit(rDrag.GetStart());
351 
352             if(rDrag.GetPageView() && SdrObjectPrimitiveHit(*this, aHit, 0, *rDrag.GetPageView(), 0, false))
353             {
354                 return true;
355             }
356 		}
357         else
358         {
359 			if((1 == pHdl->GetPolyNum()) && (0 == pHdl->GetPointNum()))
360                 return true;
361 		}
362 	}
363 
364     return false;
365 }
366 
367 bool SdrCaptionObj::applySpecialDrag(SdrDragStat& rDrag)
368 {
369 	const SdrHdl* pHdl = rDrag.GetHdl();
370 
371     if(pHdl && 0 == pHdl->GetPolyNum())
372     {
373 		const bool bRet(SdrRectObj::applySpecialDrag(rDrag));
374         ImpRecalcTail();
375 	    ActionChanged();
376 
377         return bRet;
378 	}
379     else
380     {
381 		Point aDelt(rDrag.GetNow()-rDrag.GetStart());
382 
383         if(!pHdl)
384         {
385 			aRect.Move(aDelt.X(),aDelt.Y());
386 		}
387         else
388         {
389 			aTailPoly[0] += aDelt;
390 		}
391 
392         ImpRecalcTail();
393 	    ActionChanged();
394 
395         return true;
396 	}
397 }
398 
399 String SdrCaptionObj::getSpecialDragComment(const SdrDragStat& rDrag) const
400 {
401     const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
402 
403     if(bCreateComment)
404     {
405         return String();
406     }
407     else
408     {
409         const SdrHdl* pHdl = rDrag.GetHdl();
410 
411         if(pHdl && 0 == pHdl->GetPolyNum())
412         {
413 		    return SdrRectObj::getSpecialDragComment(rDrag);
414 	    }
415         else
416         {
417 		    XubString aStr;
418 
419             if(!pHdl)
420             {
421 			    ImpTakeDescriptionStr(STR_DragCaptFram, aStr);
422 		    }
423             else
424             {
425 			    ImpTakeDescriptionStr(STR_DragCaptTail, aStr);
426 		    }
427 
428             return aStr;
429 	    }
430     }
431 }
432 
433 ////////////////////////////////////////////////////////////////////////////////////////////////////
434 
435 void SdrCaptionObj::ImpGetCaptParams(ImpCaptParams& rPara) const
436 {
437 	const SfxItemSet& rSet = GetObjectItemSet();
438 	rPara.eType      =((SdrCaptionTypeItem&)      (rSet.Get(SDRATTR_CAPTIONTYPE      ))).GetValue();
439 	rPara.bFixedAngle=((SdrCaptionFixedAngleItem&)(rSet.Get(SDRATTR_CAPTIONANGLE     ))).GetValue();
440 	rPara.nAngle     =((SdrCaptionAngleItem&)     (rSet.Get(SDRATTR_CAPTIONFIXEDANGLE))).GetValue();
441 	rPara.nGap       =((SdrCaptionGapItem&)       (rSet.Get(SDRATTR_CAPTIONGAP       ))).GetValue();
442 	rPara.eEscDir    =((SdrCaptionEscDirItem&)    (rSet.Get(SDRATTR_CAPTIONESCDIR    ))).GetValue();
443 	rPara.bEscRel    =((SdrCaptionEscIsRelItem&)  (rSet.Get(SDRATTR_CAPTIONESCISREL  ))).GetValue();
444 	rPara.nEscRel    =((SdrCaptionEscRelItem&)    (rSet.Get(SDRATTR_CAPTIONESCREL    ))).GetValue();
445 	rPara.nEscAbs    =((SdrCaptionEscAbsItem&)    (rSet.Get(SDRATTR_CAPTIONESCABS    ))).GetValue();
446 	rPara.nLineLen   =((SdrCaptionLineLenItem&)   (rSet.Get(SDRATTR_CAPTIONLINELEN   ))).GetValue();
447 	rPara.bFitLineLen=((SdrCaptionFitLineLenItem&)(rSet.Get(SDRATTR_CAPTIONFITLINELEN))).GetValue();
448 }
449 
450 void SdrCaptionObj::ImpRecalcTail()
451 {
452 	ImpCaptParams aPara;
453 	ImpGetCaptParams(aPara);
454 	ImpCalcTail(aPara,aTailPoly,aRect);
455 	SetRectsDirty();
456 	SetXPolyDirty();
457 }
458 
459 // #i35971#
460 // SdrCaptionObj::ImpCalcTail1 does move the object(!). What a hack.
461 // I really wonder why this had not triggered problems before. I am
462 // sure there are some places where SetTailPos() is called at least
463 // twice or SetSnapRect after it again just to work around this.
464 // Changed this method to not do that.
465 // Also found why this has been done: For interactive dragging of the
466 // tail end pos for SDRCAPT_TYPE1. This sure was the simplest method
467 // to achieve this, for the cost to make a whole group of const methods
468 // of this object implicitly chainging the object's position.
469 void SdrCaptionObj::ImpCalcTail1(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
470 {
471 	Polygon aPol(2);
472 	Point aTl(rPoly[0]);
473 
474 	aPol[0] = aTl;
475 	aPol[1] = aTl;
476 
477 	EscDir eEscDir;
478 	Point aEscPos;
479 
480 	rPara.CalcEscPos(aTl, rRect, aEscPos, eEscDir);
481 	aPol[1] = aEscPos;
482 
483 	if(eEscDir==LKS || eEscDir==RTS)
484 	{
485 		aPol[0].X() = aEscPos.X();
486 	}
487 	else
488 	{
489 		aPol[0].Y() = aEscPos.Y();
490 	}
491 
492 	rPoly = aPol;
493 }
494 
495 void SdrCaptionObj::ImpCalcTail2(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
496 { // Gap/EscDir/EscPos/Angle
497 	Polygon aPol(2);
498 	Point aTl(rPoly[0]);
499 	aPol[0]=aTl;
500 
501 	EscDir eEscDir;
502 	Point aEscPos;
503 	rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
504 	aPol[1]=aEscPos;
505 
506 	if (!rPara.bFixedAngle) {
507 		// fehlende Implementation
508 	}
509 	rPoly=aPol;
510 }
511 
512 void SdrCaptionObj::ImpCalcTail3(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
513 { // Gap/EscDir/EscPos/Angle/LineLen
514 	Polygon aPol(3);
515 	Point aTl(rPoly[0]);
516 	aPol[0]=aTl;
517 
518 	EscDir eEscDir;
519 	Point aEscPos;
520 	rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
521 	aPol[1]=aEscPos;
522 	aPol[2]=aEscPos;
523 
524 	if (eEscDir==LKS || eEscDir==RTS) {
525 		if (rPara.bFitLineLen) {
526 			aPol[1].X()=(aTl.X()+aEscPos.X())/2;
527 		} else {
528 			if (eEscDir==LKS) aPol[1].X()-=rPara.nLineLen;
529 			else aPol[1].X()+=rPara.nLineLen;
530 		}
531 	} else {
532 		if (rPara.bFitLineLen) {
533 			aPol[1].Y()=(aTl.Y()+aEscPos.Y())/2;
534 		} else {
535 			if (eEscDir==OBN) aPol[1].Y()-=rPara.nLineLen;
536 			else aPol[1].Y()+=rPara.nLineLen;
537 		}
538 	}
539 	if (!rPara.bFixedAngle) {
540 		// fehlende Implementation
541 	}
542 	rPoly=aPol;
543 }
544 
545 void SdrCaptionObj::ImpCalcTail4(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
546 {
547 	ImpCalcTail3(rPara,rPoly,rRect);
548 }
549 
550 void SdrCaptionObj::ImpCalcTail(const ImpCaptParams& rPara, Polygon& rPoly, Rectangle& rRect) const
551 {
552 	switch (rPara.eType) {
553 		case SDRCAPT_TYPE1: ImpCalcTail1(rPara,rPoly,rRect); break;
554 		case SDRCAPT_TYPE2: ImpCalcTail2(rPara,rPoly,rRect); break;
555 		case SDRCAPT_TYPE3: ImpCalcTail3(rPara,rPoly,rRect); break;
556 		case SDRCAPT_TYPE4: ImpCalcTail4(rPara,rPoly,rRect); break;
557 	}
558 }
559 
560 FASTBOOL SdrCaptionObj::BegCreate(SdrDragStat& rStat)
561 {
562 	if (aRect.IsEmpty()) return sal_False; // Create z.Zt. nur mit vorgegebenen Rect
563 
564 	ImpCaptParams aPara;
565 	ImpGetCaptParams(aPara);
566 	aRect.SetPos(rStat.GetNow());
567 	aTailPoly[0]=rStat.GetStart();
568 	ImpCalcTail(aPara,aTailPoly,aRect);
569 	rStat.SetActionRect(aRect);
570 	return sal_True;
571 }
572 
573 FASTBOOL SdrCaptionObj::MovCreate(SdrDragStat& rStat)
574 {
575 	ImpCaptParams aPara;
576 	ImpGetCaptParams(aPara);
577 	aRect.SetPos(rStat.GetNow());
578 	ImpCalcTail(aPara,aTailPoly,aRect);
579 	rStat.SetActionRect(aRect);
580 	SetBoundRectDirty();
581 	bSnapRectDirty=sal_True;
582 	return sal_True;
583 }
584 
585 FASTBOOL SdrCaptionObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
586 {
587 	ImpCaptParams aPara;
588 	ImpGetCaptParams(aPara);
589 	aRect.SetPos(rStat.GetNow());
590 	ImpCalcTail(aPara,aTailPoly,aRect);
591 	SetRectsDirty();
592 	return (eCmd==SDRCREATE_FORCEEND || rStat.GetPointAnz()>=2);
593 }
594 
595 FASTBOOL SdrCaptionObj::BckCreate(SdrDragStat& /*rStat*/)
596 {
597 	return sal_False;
598 }
599 
600 void SdrCaptionObj::BrkCreate(SdrDragStat& /*rStat*/)
601 {
602 }
603 
604 basegfx::B2DPolyPolygon SdrCaptionObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
605 {
606 	basegfx::B2DPolyPolygon aRetval;
607 	const basegfx::B2DRange aRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());
608 	aRetval.append(basegfx::tools::createPolygonFromRect(aRange));
609 	aRetval.append(aTailPoly.getB2DPolygon());
610 	return aRetval;
611 }
612 
613 Pointer SdrCaptionObj::GetCreatePointer() const
614 {
615 	return Pointer(POINTER_DRAW_CAPTION);
616 }
617 
618 void SdrCaptionObj::NbcMove(const Size& rSiz)
619 {
620 	SdrRectObj::NbcMove(rSiz);
621 	MovePoly(aTailPoly,rSiz);
622     if(mbFixedTail)
623         SetTailPos(GetFixedTailPos());
624 }
625 
626 void SdrCaptionObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
627 {
628 	SdrRectObj::NbcResize(rRef,xFact,yFact);
629 	ResizePoly(aTailPoly,rRef,xFact,yFact);
630 	ImpRecalcTail();
631     if(mbFixedTail)
632         SetTailPos(GetFixedTailPos());
633 }
634 
635 void SdrCaptionObj::NbcSetRelativePos(const Point& rPnt)
636 {
637 	Point aRelPos0(aTailPoly.GetPoint(0)-aAnchor);
638 	Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
639 	NbcMove(aSiz); // Der ruft auch das SetRectsDirty()
640 }
641 
642 Point SdrCaptionObj::GetRelativePos() const
643 {
644 	return aTailPoly.GetPoint(0)-aAnchor;
645 }
646 
647 void SdrCaptionObj::NbcSetAnchorPos(const Point& rPnt)
648 {
649 	SdrRectObj::NbcSetAnchorPos(rPnt);
650 	// !!!!! fehlende Impl.
651 }
652 
653 const Point& SdrCaptionObj::GetAnchorPos() const
654 {
655 	// !!!!! fehlende Impl.
656 	return SdrRectObj::GetAnchorPos();
657 }
658 
659 void SdrCaptionObj::RecalcSnapRect()
660 {
661 	SdrRectObj::RecalcSnapRect();
662 	// #i32599#
663 	// maSnapRect.Union(aTailPoly.GetBoundRect());
664 	// !!!!! fehlende Impl.
665 }
666 
667 const Rectangle& SdrCaptionObj::GetSnapRect() const
668 {
669 	return SdrRectObj::GetSnapRect();
670 }
671 
672 void SdrCaptionObj::NbcSetSnapRect(const Rectangle& rRect)
673 {
674 	// #i32599#
675 	// Move back to see the rectangle of the underlying SdrRectObj
676 	// as the SnapRect, without the TailPos. That simplifies SnapRect
677 	// handling again, if not allows it at all...
678 	SdrRectObj::NbcSetSnapRect(rRect);
679 }
680 
681 const Rectangle& SdrCaptionObj::GetLogicRect() const
682 {
683 	return aRect;
684 }
685 
686 void SdrCaptionObj::NbcSetLogicRect(const Rectangle& rRect)
687 {
688 	SdrRectObj::NbcSetLogicRect(rRect);
689 	ImpRecalcTail();
690 }
691 
692 const Point& SdrCaptionObj::GetTailPos() const
693 {
694 	return aTailPoly[0];
695 }
696 
697 void SdrCaptionObj::SetTailPos(const Point& rPos)
698 {
699 	if (aTailPoly.GetSize()==0 || aTailPoly[0]!=rPos) {
700 		Rectangle aBoundRect0; if (pUserCall!=NULL) aBoundRect0=GetLastBoundRect();
701 		// #110094#-14 SendRepaintBroadcast();
702 		NbcSetTailPos(rPos);
703 		SetChanged();
704 		BroadcastObjectChange();
705 		SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0);
706 	}
707 }
708 
709 void SdrCaptionObj::NbcSetTailPos(const Point& rPos)
710 {
711 	aTailPoly[0]=rPos;
712 	ImpRecalcTail();
713 }
714 
715 sal_uInt32 SdrCaptionObj::GetSnapPointCount() const
716 {
717 	// !!!!! fehlende Impl.
718 	return 0L;
719 }
720 
721 Point SdrCaptionObj::GetSnapPoint(sal_uInt32 /*i*/) const
722 {
723 	// !!!!! fehlende Impl.
724 	return Point(0,0);
725 }
726 
727 void SdrCaptionObj::SetModel(SdrModel* pNewModel)
728 {
729 	SdrRectObj::SetModel(pNewModel);
730 	ImpRecalcTail();
731 }
732 
733 void SdrCaptionObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
734 {
735 	SdrRectObj::Notify(rBC,rHint);
736 	ImpRecalcTail();
737 }
738 
739 SdrObjGeoData* SdrCaptionObj::NewGeoData() const
740 {
741 	return new SdrCaptObjGeoData;
742 }
743 
744 void SdrCaptionObj::SaveGeoData(SdrObjGeoData& rGeo) const
745 {
746 	SdrRectObj::SaveGeoData(rGeo);
747 	SdrCaptObjGeoData& rCGeo=(SdrCaptObjGeoData&)rGeo;
748 	rCGeo.aTailPoly=aTailPoly;
749 }
750 
751 void SdrCaptionObj::RestGeoData(const SdrObjGeoData& rGeo)
752 {
753 	SdrRectObj::RestGeoData(rGeo);
754 	SdrCaptObjGeoData& rCGeo=(SdrCaptObjGeoData&)rGeo;
755 	aTailPoly=rCGeo.aTailPoly;
756 }
757 
758 SdrObject* SdrCaptionObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const
759 { // #42334# - Convert implementiert
760 	SdrObject* pRect=SdrRectObj::DoConvertToPolyObj(bBezier, bAddText);
761 	SdrObject* pTail = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aTailPoly.getB2DPolygon()), sal_False, bBezier);
762 	SdrObject* pRet=(pTail!=NULL) ? pTail : pRect;
763 	if (pTail!=NULL && pRect!=NULL) {
764 		FASTBOOL bInsRect=sal_True;
765 		FASTBOOL bInsTail=sal_True;
766 		SdrObjList* pOL=pTail->GetSubList();
767 		if (pOL!=NULL) { pRet=pRect; bInsTail=sal_False; }
768 		if (pOL==NULL) pOL=pRect->GetSubList();
769 		if (pOL!=NULL) { pRet=pRect; bInsRect=sal_False; }
770 		if (pOL==NULL) {
771 			SdrObjGroup* pGrp=new SdrObjGroup;
772 			pOL=pGrp->GetSubList();
773 			pRet=pGrp;
774 		}
775 		if (bInsRect) pOL->NbcInsertObject(pRect);
776 		if (bInsTail) pOL->NbcInsertObject(pTail,0);
777 	}
778 	return pRet;
779 }
780 
781 // #i32599#
782 // Add own implementation for TRSetBaseGeometry to handle TailPos over changes.
783 void SdrCaptionObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
784 {
785 	// break up matrix
786 	basegfx::B2DTuple aScale;
787 	basegfx::B2DTuple aTranslate;
788 	double fRotate, fShearX;
789 	rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
790 
791 	// #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
792 	// in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
793 	if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
794 	{
795 		aScale.setX(fabs(aScale.getX()));
796 		aScale.setY(fabs(aScale.getY()));
797 		fRotate = fmod(fRotate + F_PI, F_2PI);
798 	}
799 
800 	// force metric to pool metric
801 	SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
802 	if(eMapUnit != SFX_MAPUNIT_100TH_MM)
803 	{
804 		switch(eMapUnit)
805 		{
806 			case SFX_MAPUNIT_TWIP :
807 			{
808 				// position
809 				aTranslate.setX(ImplMMToTwips(aTranslate.getX()));
810 				aTranslate.setY(ImplMMToTwips(aTranslate.getY()));
811 
812 				// size
813 				aScale.setX(ImplMMToTwips(aScale.getX()));
814 				aScale.setY(ImplMMToTwips(aScale.getY()));
815 
816 				break;
817 			}
818 			default:
819 			{
820 				DBG_ERROR("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
821 			}
822 		}
823 	}
824 
825 	// if anchor is used, make position relative to it
826 	if( pModel->IsWriter() )
827 	{
828 		if(GetAnchorPos().X() || GetAnchorPos().Y())
829 		{
830 			aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
831 		}
832 	}
833 
834 	// build BaseRect
835 	Point aPoint(FRound(aTranslate.getX()), FRound(aTranslate.getY()));
836 	Rectangle aBaseRect(aPoint, Size(FRound(aScale.getX()), FRound(aScale.getY())));
837 
838 	// set BaseRect, but rescue TailPos over this call
839 	const Point aTailPoint = GetTailPos();
840 	SetSnapRect(aBaseRect);
841 	SetTailPos(aTailPoint);
842 	ImpRecalcTail();
843 }
844 
845 // geometry access
846 basegfx::B2DPolygon SdrCaptionObj::getTailPolygon() const
847 {
848 	return aTailPoly.getB2DPolygon();
849 }
850 
851 // eof
852