LibreOffice Module svx (master)  1
svdoedge.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <svx/dialmgr.hxx>
21 #include <svx/strings.hrc>
22 
25 #include <svl/hint.hxx>
26 #include <rtl/ustrbuf.hxx>
27 
30 #include <svx/sdrhittesthelper.hxx>
31 #include <svx/svddrag.hxx>
32 #include <svx/svddrgmt.hxx>
33 #include <svx/svdhdl.hxx>
34 #include <svx/svdmodel.hxx>
35 #include <svx/svdoedge.hxx>
36 #include <svx/svdopath.hxx>
37 #include <svx/svdpage.hxx>
38 #include <svx/svdpagv.hxx>
39 #include <svx/svdtrans.hxx>
40 #include <svx/svdview.hxx>
41 #include <svx/sxekitm.hxx>
42 #include <svx/sxelditm.hxx>
43 #include <svx/sxenditm.hxx>
44 #include <svx/xpoly.hxx>
45 #include <vcl/ptrstyle.hxx>
46 
48 {
49  pObj=nullptr;
50  nConId=0;
51  bBestConn=true;
52  bBestVertex=true;
53  bAutoVertex=false;
54  bAutoCorner=false;
55 }
56 
58 {
59  bool bRet = false;
60  if (pObj!=nullptr) { // one object has to be docked already!
61  if (bAutoVertex) {
63  bRet = true;
64  } else if (bAutoCorner) {
66  bRet = true;
67  } else {
68  const SdrGluePointList* pGPL=pObj->GetGluePointList();
69  if (pGPL!=nullptr) {
70  sal_uInt16 nNum=pGPL->FindGluePoint(nConId);
71  if (nNum!=SDRGLUEPOINT_NOTFOUND) {
72  rGP=(*pGPL)[nNum];
73  bRet = true;
74  }
75  }
76  }
77  }
78  if (bRet) {
79  Point aPt(rGP.GetAbsolutePos(*pObj));
80  aPt+=aObjOfs;
81  rGP.SetPos(aPt);
82  }
83  return bRet;
84 }
85 
87 {
88  switch (eLineCode) {
94  } // switch
95  return aMiddleLine;
96 }
97 
98 sal_uInt16 SdrEdgeInfoRec::ImpGetPolyIdx(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const
99 {
100  switch (eLineCode) {
101  case SdrEdgeLineCode::Obj1Line2 : return 1;
102  case SdrEdgeLineCode::Obj1Line3 : return 2;
103  case SdrEdgeLineCode::Obj2Line2 : return rXP.GetPointCount()-3;
104  case SdrEdgeLineCode::Obj2Line3 : return rXP.GetPointCount()-4;
106  } // switch
107  return 0;
108 }
109 
110 bool SdrEdgeInfoRec::ImpIsHorzLine(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const
111 {
112  sal_uInt16 nIdx=ImpGetPolyIdx(eLineCode,rXP);
113  bool bHorz=nAngle1==0 || nAngle1==18000;
114  if (eLineCode==SdrEdgeLineCode::Obj2Line2 || eLineCode==SdrEdgeLineCode::Obj2Line3) {
115  nIdx=rXP.GetPointCount()-nIdx;
116  bHorz=nAngle2==0 || nAngle2==18000;
117  }
118  if ((nIdx & 1)==1) bHorz=!bHorz;
119  return bHorz;
120 }
121 
122 void SdrEdgeInfoRec::ImpSetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon& rXP, long nVal)
123 {
124  Point& rPt=ImpGetLineOffsetPoint(eLineCode);
125  if (ImpIsHorzLine(eLineCode,rXP)) rPt.setY(nVal );
126  else rPt.setX(nVal );
127 }
128 
130 {
131  const Point& rPt = const_cast<SdrEdgeInfoRec*>(this)->ImpGetLineOffsetPoint(eLineCode);
132  if (ImpIsHorzLine(eLineCode,rXP))
133  return rPt.Y();
134  else
135  return rPt.X();
136 }
137 
138 
139 // BaseProperties section
140 
141 std::unique_ptr<sdr::properties::BaseProperties> SdrEdgeObj::CreateObjectSpecificProperties()
142 {
143  return std::make_unique<sdr::properties::ConnectorProperties>(*this);
144 }
145 
146 
147 // DrawContact section
148 
149 std::unique_ptr<sdr::contact::ViewContact> SdrEdgeObj::CreateObjectSpecificViewContact()
150 {
151  return std::make_unique<sdr::contact::ViewContactOfSdrEdgeObj>(*this);
152 }
153 
154 
156 : SdrTextObj(rSdrModel),
157  nNotifyingCount(0),
158  bEdgeTrackDirty(false),
159  bEdgeTrackUserDefined(false),
160  // Default is to allow default connects
161  mbSuppressDefaultConnect(false),
162  mbBoundRectCalculationRunning(false),
163  mbSuppressed(false)
164 {
165  bClosedObj=false;
166  bIsEdge=true;
167  pEdgeTrack.reset(new XPolygon);
168 }
169 
171 {
174 }
175 
176 void SdrEdgeObj::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
177 {
178  // call parent
179  SdrTextObj::handlePageChange(pOldPage, pNewPage);
180 
181  if(nullptr != GetConnection(true).GetObject() || nullptr != GetConnection(false).GetObject())
182  {
183  // check broadcasters; when we are not inserted we do not need broadcasters
184  // TTTT not yet added, but keep hint to do this here
185  // mpCon1->ownerPageChange();
186  // mpCon2->ownerPageChange();
187  }
188 }
189 
191 {
192  const SfxItemSet& rSet = GetObjectItemSet();
193  SdrEdgeKind eKind = rSet.Get(SDRATTR_EDGEKIND).GetValue();
194  sal_Int32 nVal1 = rSet.Get(SDRATTR_EDGELINE1DELTA).GetValue();
195  sal_Int32 nVal2 = rSet.Get(SDRATTR_EDGELINE2DELTA).GetValue();
196  sal_Int32 nVal3 = rSet.Get(SDRATTR_EDGELINE3DELTA).GetValue();
197 
198  if(eKind == SdrEdgeKind::OrthoLines || eKind == SdrEdgeKind::Bezier)
199  {
200  sal_Int32 nVals[3] = { nVal1, nVal2, nVal3 };
201  sal_uInt16 n = 0;
202 
203  if(aEdgeInfo.nObj1Lines >= 2 && n < 3)
204  {
206  n++;
207  }
208 
209  if(aEdgeInfo.nObj1Lines >= 3 && n < 3)
210  {
212  n++;
213  }
214 
215  if(aEdgeInfo.nMiddleLine != 0xFFFF && n < 3)
216  {
218  n++;
219  }
220 
221  if(aEdgeInfo.nObj2Lines >= 3 && n < 3)
222  {
224  n++;
225  }
226 
227  if(aEdgeInfo.nObj2Lines >= 2 && n < 3)
228  {
230  n++;
231  }
232  }
233  else if(eKind == SdrEdgeKind::ThreeLines)
234  {
235  bool bHor1 = aEdgeInfo.nAngle1 == 0 || aEdgeInfo.nAngle1 == 18000;
236  bool bHor2 = aEdgeInfo.nAngle2 == 0 || aEdgeInfo.nAngle2 == 18000;
237 
238  if(bHor1)
239  {
240  aEdgeInfo.aObj1Line2.setX( nVal1 );
241  }
242  else
243  {
244  aEdgeInfo.aObj1Line2.setY( nVal1 );
245  }
246 
247  if(bHor2)
248  {
249  aEdgeInfo.aObj2Line2.setX( nVal2 );
250  }
251  else
252  {
253  aEdgeInfo.aObj2Line2.setY( nVal2 );
254  }
255  }
256 
258 }
259 
261 {
262  const SfxItemSet& rSet = GetObjectItemSet();
263  SdrEdgeKind eKind = rSet.Get(SDRATTR_EDGEKIND).GetValue();
264  sal_Int32 nValCnt = rSet.Get(SDRATTR_EDGELINEDELTACOUNT).GetValue();
265  sal_Int32 nVal1 = rSet.Get(SDRATTR_EDGELINE1DELTA).GetValue();
266  sal_Int32 nVal2 = rSet.Get(SDRATTR_EDGELINE2DELTA).GetValue();
267  sal_Int32 nVal3 = rSet.Get(SDRATTR_EDGELINE3DELTA).GetValue();
268  sal_Int32 nVals[3] = { nVal1, nVal2, nVal3 };
269  sal_uInt16 n = 0;
270 
271  if(eKind == SdrEdgeKind::OrthoLines || eKind == SdrEdgeKind::Bezier)
272  {
273  if(aEdgeInfo.nObj1Lines >= 2 && n < 3)
274  {
276  n++;
277  }
278 
279  if(aEdgeInfo.nObj1Lines >= 3 && n < 3)
280  {
282  n++;
283  }
284 
285  if(aEdgeInfo.nMiddleLine != 0xFFFF && n < 3)
286  {
288  n++;
289  }
290 
291  if(aEdgeInfo.nObj2Lines >= 3 && n < 3)
292  {
294  n++;
295  }
296 
297  if(aEdgeInfo.nObj2Lines >= 2 && n < 3)
298  {
300  n++;
301  }
302  }
303  else if(eKind == SdrEdgeKind::ThreeLines)
304  {
305  bool bHor1 = aEdgeInfo.nAngle1 == 0 || aEdgeInfo.nAngle1 == 18000;
306  bool bHor2 = aEdgeInfo.nAngle2 == 0 || aEdgeInfo.nAngle2 == 18000;
307 
308  n = 2;
309  nVals[0] = bHor1 ? aEdgeInfo.aObj1Line2.X() : aEdgeInfo.aObj1Line2.Y();
310  nVals[1] = bHor2 ? aEdgeInfo.aObj2Line2.X() : aEdgeInfo.aObj2Line2.Y();
311  }
312 
313  if(!(n != nValCnt || nVals[0] != nVal1 || nVals[1] != nVal2 || nVals[2] != nVal3))
314  return;
315 
316  // Here no more notifying is necessary, just local changes are OK.
317  if(n != nValCnt)
318  {
320  }
321 
322  if(nVals[0] != nVal1)
323  {
325  }
326 
327  if(nVals[1] != nVal2)
328  {
330  }
331 
332  if(nVals[2] != nVal3)
333  {
335  }
336 
337  if(n < 3)
338  {
340  }
341 
342  if(n < 2)
343  {
345  }
346 
347  if(n < 1)
348  {
350  }
351 }
352 
354 {
355  // #i54102# allow rotation, mirror and shear
356  rInfo.bRotateFreeAllowed = true;
357  rInfo.bRotate90Allowed = true;
358  rInfo.bMirrorFreeAllowed = true;
359  rInfo.bMirror45Allowed = true;
360  rInfo.bMirror90Allowed = true;
361  rInfo.bTransparenceAllowed = false;
362  rInfo.bShearAllowed = true;
363  rInfo.bEdgeRadiusAllowed = false;
364  bool bCanConv=!HasText() || ImpCanConvTextToCurve();
365  rInfo.bCanConvToPath=bCanConv;
366  rInfo.bCanConvToPoly=bCanConv;
368 }
369 
371 {
372  return sal_uInt16(OBJ_EDGE);
373 }
374 
376 {
377  if(bEdgeTrackDirty)
378  {
379  const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
380  }
381 
383 }
384 
386 {
387  if(bEdgeTrackDirty)
388  {
389  const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
390  }
391 
392  return SdrTextObj::GetSnapRect();
393 }
394 
396 {
397  maSnapRect=pEdgeTrack->GetBoundRect();
398 }
399 
401 {
402  rRect=GetSnapRect();
403 }
404 
406 {
407  Point aPt;
408  sal_uInt16 nPointCount=pEdgeTrack->GetPointCount();
409  if (nPointCount>0)
410  {
411  Point aOfs = GetSnapRect().Center();
412  if (nNum==2 && GetConnectedNode(true)==nullptr) aPt=(*pEdgeTrack)[0];
413  else if (nNum==3 && GetConnectedNode(false)==nullptr) aPt=(*pEdgeTrack)[nPointCount-1];
414  else {
415  if ((nPointCount & 1) ==1) {
416  aPt=(*pEdgeTrack)[nPointCount/2];
417  } else {
418  Point aPt1((*pEdgeTrack)[nPointCount/2-1]);
419  Point aPt2((*pEdgeTrack)[nPointCount/2]);
420  aPt1+=aPt2;
421  aPt1.setX( aPt1.X() / 2 );
422  aPt1.setY( aPt1.Y() / 2 );
423  aPt=aPt1;
424  }
425  }
426  aPt-=aOfs;
427  }
428  SdrGluePoint aGP(aPt);
429  aGP.SetPercent(false);
430  return aGP;
431 }
432 
434 {
435  return GetVertexGluePoint(nNum);
436 }
437 
439 {
440  return nullptr; // no user defined glue points for connectors
441 }
442 
444 {
445  return nullptr; // no user defined glue points for connectors
446 }
447 
448 void SdrEdgeObj::ConnectToNode(bool bTail1, SdrObject* pObj)
449 {
450  SdrObjConnection& rCon=GetConnection(bTail1);
451  DisconnectFromNode(bTail1);
452  if (pObj!=nullptr) {
453  pObj->AddListener(*this);
454  rCon.pObj=pObj;
455 
456  // #i120437# If connection is set, reset bEdgeTrackUserDefined
457  bEdgeTrackUserDefined = false;
458 
460  }
461 }
462 
464 {
465  SdrObjConnection& rCon=GetConnection(bTail1);
466  if (rCon.pObj!=nullptr) {
467  rCon.pObj->RemoveListener(*this);
468  rCon.pObj=nullptr;
469  }
470 }
471 
473 {
474  SdrObject* pObj(GetConnection(bTail1).pObj);
475 
476  if(nullptr != pObj
477  && (pObj->getSdrPageFromSdrObject() != getSdrPageFromSdrObject() || !pObj->IsInserted()))
478  {
479  pObj = nullptr;
480  }
481 
482  return pObj;
483 }
484 
485 bool SdrEdgeObj::CheckNodeConnection(bool bTail1) const
486 {
487  bool bRet = false;
488  const SdrObjConnection& rCon=GetConnection(bTail1);
489  sal_uInt16 nPointCount=pEdgeTrack->GetPointCount();
490 
491  if(nullptr != rCon.pObj && rCon.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject() && 0 != nPointCount)
492  {
493  const SdrGluePointList* pGPL=rCon.pObj->GetGluePointList();
494  sal_uInt16 nGluePointCnt=pGPL==nullptr ? 0 : pGPL->GetCount();
495  sal_uInt16 nGesAnz=nGluePointCnt+8;
496  Point aTail(bTail1 ? (*pEdgeTrack)[0] : (*pEdgeTrack)[sal_uInt16(nPointCount-1)]);
497  for (sal_uInt16 i=0; i<nGesAnz && !bRet; i++) {
498  if (i<nGluePointCnt) { // UserDefined
499  bRet=aTail==(*pGPL)[i].GetAbsolutePos(*rCon.pObj);
500  } else if (i<nGluePointCnt+4) { // Vertex
501  SdrGluePoint aPt(rCon.pObj->GetVertexGluePoint(i-nGluePointCnt));
502  bRet=aTail==aPt.GetAbsolutePos(*rCon.pObj);
503  } else { // Corner
504  SdrGluePoint aPt(rCon.pObj->GetCornerGluePoint(i-nGluePointCnt-4));
505  bRet=aTail==aPt.GetAbsolutePos(*rCon.pObj);
506  }
507  }
508  }
509  return bRet;
510 }
511 
512 void SdrEdgeObj::ImpSetTailPoint(bool bTail1, const Point& rPt)
513 {
514  sal_uInt16 nPointCount=pEdgeTrack->GetPointCount();
515  if (nPointCount==0) {
516  (*pEdgeTrack)[0]=rPt;
517  (*pEdgeTrack)[1]=rPt;
518  } else if (nPointCount==1) {
519  if (!bTail1) (*pEdgeTrack)[1]=rPt;
520  else { (*pEdgeTrack)[1]=(*pEdgeTrack)[0]; (*pEdgeTrack)[0]=rPt; }
521  } else {
522  if (!bTail1) (*pEdgeTrack)[sal_uInt16(nPointCount-1)]=rPt;
523  else (*pEdgeTrack)[0]=rPt;
524  }
526  SetRectsDirty();
527 }
528 
530 {
531  if ( !bEdgeTrackUserDefined || !getSdrModelFromSdrObject().isLocked() )
532  bEdgeTrackDirty = true;
533 }
534 
536 {
537  if (bEdgeTrackDirty && getSdrModelFromSdrObject().isLocked())
538  {
540  }
541 }
542 
544 {
545  // #i120437# if bEdgeTrackUserDefined, do not recalculate
547  {
548  return;
549  }
550 
551  // #i120437# also not when model locked during import, but remember
552  if(getSdrModelFromSdrObject().isLocked())
553  {
554  mbSuppressed = true;
555  return;
556  }
557 
558  // #i110649#
560  {
561  // This object is involved into another ImpRecalcEdgeTrack() call
562  // from another SdrEdgeObj. Do not calculate again to avoid loop.
563  // Also, do not change bEdgeTrackDirty so that it gets recalculated
564  // later at the first non-looping call.
565  }
566  else
567  {
568  // To not run in a depth loop, use a coloring algorithm on
569  // SdrEdgeObj BoundRect calculations
571 
572  if(mbSuppressed)
573  {
574  // #i123048# If layouting was ever suppressed, it needs to be done once
575  // and the attr need to be set at EdgeInfo, else these attr *will be lost*
576  // in the following call to ImpSetEdgeInfoToAttr() since they were never
577  // set before (!)
580  mbSuppressed = false;
581  }
582 
583  tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetCurrentBoundRect();
584  SetRectsDirty();
586  ImpSetEdgeInfoToAttr(); // copy values from aEdgeInfo into the pool
587  bEdgeTrackDirty=false;
588 
589  // Only redraw here, no object change
590  ActionChanged();
591 
593 
595  }
596 }
597 
599 {
600  if (pObj==nullptr) return SdrEscapeDirection::ALL;
601  tools::Rectangle aR(pObj->GetSnapRect());
602  long dxl=rPt.X()-aR.Left();
603  long dyo=rPt.Y()-aR.Top();
604  long dxr=aR.Right()-rPt.X();
605  long dyu=aR.Bottom()-rPt.Y();
606  bool bxMitt=std::abs(dxl-dxr)<2;
607  bool byMitt=std::abs(dyo-dyu)<2;
608  long dx=std::min(dxl,dxr);
609  long dy=std::min(dyo,dyu);
610  bool bDiag=std::abs(dx-dy)<2;
611  if (bxMitt && byMitt) return SdrEscapeDirection::ALL; // in the center
612  if (bDiag) { // diagonally
614  if (byMitt) nRet|=SdrEscapeDirection::VERT;
615  if (bxMitt) nRet|=SdrEscapeDirection::HORZ;
616  if (dxl<dxr) { // left
619  } else { // right
622  }
623  return nRet;
624  }
625  if (dx<dy) { // horizontal
626  if (bxMitt) return SdrEscapeDirection::HORZ;
627  if (dxl<dxr) return SdrEscapeDirection::LEFT;
628  else return SdrEscapeDirection::RIGHT;
629  } else { // vertical
630  if (byMitt) return SdrEscapeDirection::VERT;
631  if (dyo<dyu) return SdrEscapeDirection::TOP;
632  else return SdrEscapeDirection::BOTTOM;
633  }
634 }
635 
636 XPolygon SdrEdgeObj::ImpCalcObjToCenter(const Point& rStPt, long nEscAngle, const tools::Rectangle& rRect, const Point& rMeeting)
637 {
638  XPolygon aXP;
639  aXP.Insert(XPOLY_APPEND,rStPt,PolyFlags::Normal);
640  bool bRts=nEscAngle==0;
641  bool bObn=nEscAngle==9000;
642  bool bLks=nEscAngle==18000;
643  bool bUnt=nEscAngle==27000;
644 
645  Point aP1(rStPt); // mandatory difference first,...
646  if (bLks) aP1.setX(rRect.Left() );
647  if (bRts) aP1.setX(rRect.Right() );
648  if (bObn) aP1.setY(rRect.Top() );
649  if (bUnt) aP1.setY(rRect.Bottom() );
650 
651  Point aP2(aP1); // ...now increase to Meeting height, if necessary
652  if (bLks && rMeeting.X()<=aP2.X()) aP2.setX(rMeeting.X() );
653  if (bRts && rMeeting.X()>=aP2.X()) aP2.setX(rMeeting.X() );
654  if (bObn && rMeeting.Y()<=aP2.Y()) aP2.setY(rMeeting.Y() );
655  if (bUnt && rMeeting.Y()>=aP2.Y()) aP2.setY(rMeeting.Y() );
656  aXP.Insert(XPOLY_APPEND,aP2,PolyFlags::Normal);
657 
658  Point aP3(aP2);
659  if ((bLks && rMeeting.X()>aP2.X()) || (bRts && rMeeting.X()<aP2.X())) { // around
660  if (rMeeting.Y()<aP2.Y()) {
661  aP3.setY(rRect.Top() );
662  if (rMeeting.Y()<aP3.Y()) aP3.setY(rMeeting.Y() );
663  } else {
664  aP3.setY(rRect.Bottom() );
665  if (rMeeting.Y()>aP3.Y()) aP3.setY(rMeeting.Y() );
666  }
667  aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
668  if (aP3.Y()!=rMeeting.Y()) {
669  aP3.setX(rMeeting.X() );
670  aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
671  }
672  }
673  if ((bObn && rMeeting.Y()>aP2.Y()) || (bUnt && rMeeting.Y()<aP2.Y())) { // around
674  if (rMeeting.X()<aP2.X()) {
675  aP3.setX(rRect.Left() );
676  if (rMeeting.X()<aP3.X()) aP3.setX(rMeeting.X() );
677  } else {
678  aP3.setX(rRect.Right() );
679  if (rMeeting.X()>aP3.X()) aP3.setX(rMeeting.X() );
680  }
681  aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
682  if (aP3.X()!=rMeeting.X()) {
683  aP3.setY(rMeeting.Y() );
684  aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
685  }
686  }
687 #ifdef DBG_UTIL
688  if (aXP.GetPointCount()>4) {
689  OSL_FAIL("SdrEdgeObj::ImpCalcObjToCenter(): Polygon has more than 4 points!");
690  }
691 #endif
692  return aXP;
693 }
694 
696 {
697  Point aPt1,aPt2;
698  SdrGluePoint aGP1,aGP2;
700  tools::Rectangle aBoundRect1;
701  tools::Rectangle aBoundRect2;
702  tools::Rectangle aBewareRect1;
703  tools::Rectangle aBewareRect2;
704  // first, get the old corner points
705  if (rTrack0.GetPointCount()!=0) {
706  aPt1=rTrack0[0];
707  sal_uInt16 nSiz=rTrack0.GetPointCount();
708  nSiz--;
709  aPt2=rTrack0[nSiz];
710  } else {
711  if (!aOutRect.IsEmpty()) {
712  aPt1=aOutRect.TopLeft();
713  aPt2=aOutRect.BottomRight();
714  }
715  }
716 
717  // #i54102# To allow interactive preview, do also if not inserted
718  const bool bCon1(nullptr != rCon1.pObj && rCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
719  const bool bCon2(nullptr != rCon2.pObj && rCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
720  const SfxItemSet& rSet = GetObjectItemSet();
721 
722  if (bCon1)
723  {
724  if (rCon1.pObj==static_cast<SdrObject const *>(this))
725  {
726  // check, just in case
727  aBoundRect1=aOutRect;
728  }
729  else
730  {
731  aBoundRect1 = rCon1.pObj->GetCurrentBoundRect();
732  }
733 
734  aBoundRect1.Move(rCon1.aObjOfs.X(),rCon1.aObjOfs.Y());
735  aBewareRect1=aBoundRect1;
736  sal_Int32 nH = rSet.Get(SDRATTR_EDGENODE1HORZDIST).GetValue();
737  sal_Int32 nV = rSet.Get(SDRATTR_EDGENODE1VERTDIST).GetValue();
738  aBewareRect1.AdjustLeft( -nH );
739  aBewareRect1.AdjustRight(nH );
740  aBewareRect1.AdjustTop( -nV );
741  aBewareRect1.AdjustBottom(nV );
742  }
743  else
744  {
745  aBoundRect1=tools::Rectangle(aPt1,aPt1);
746  aBoundRect1.Move(rCon1.aObjOfs.X(),rCon1.aObjOfs.Y());
747  aBewareRect1=aBoundRect1;
748  }
749 
750  if (bCon2)
751  {
752  if (rCon2.pObj==static_cast<SdrObject const *>(this))
753  { // check, just in case
754  aBoundRect2=aOutRect;
755  }
756  else
757  {
758  aBoundRect2 = rCon2.pObj->GetCurrentBoundRect();
759  }
760 
761  aBoundRect2.Move(rCon2.aObjOfs.X(),rCon2.aObjOfs.Y());
762  aBewareRect2=aBoundRect2;
763  sal_Int32 nH = rSet.Get(SDRATTR_EDGENODE2HORZDIST).GetValue();
764  sal_Int32 nV = rSet.Get(SDRATTR_EDGENODE2VERTDIST).GetValue();
765  aBewareRect2.AdjustLeft( -nH );
766  aBewareRect2.AdjustRight(nH );
767  aBewareRect2.AdjustTop( -nV );
768  aBewareRect2.AdjustBottom(nV );
769  }
770  else
771  {
772  aBoundRect2=tools::Rectangle(aPt2,aPt2);
773  aBoundRect2.Move(rCon2.aObjOfs.X(),rCon2.aObjOfs.Y());
774  aBewareRect2=aBoundRect2;
775  }
776 
777  XPolygon aBestXP;
778  sal_uIntPtr nBestQual=0xFFFFFFFF;
779  SdrEdgeInfoRec aBestInfo;
780  bool bAuto1=bCon1 && rCon1.bBestVertex;
781  bool bAuto2=bCon2 && rCon2.bBestVertex;
782  if (bAuto1) rCon1.bAutoVertex=true;
783  if (bAuto2) rCon2.bAutoVertex=true;
784  sal_uInt16 nBestAuto1=0;
785  sal_uInt16 nBestAuto2=0;
786  sal_uInt16 nCount1=bAuto1 ? 4 : 1;
787  sal_uInt16 nCount2=bAuto2 ? 4 : 1;
788 
789  for (sal_uInt16 nNum1=0; nNum1<nCount1; nNum1++)
790  {
791  if (bAuto1) rCon1.nConId=nNum1;
792  if (bCon1 && rCon1.TakeGluePoint(aGP1))
793  {
794  aPt1=aGP1.GetPos();
795  nEsc1=aGP1.GetEscDir();
796  if (nEsc1==SdrEscapeDirection::SMART) nEsc1=ImpCalcEscAngle(rCon1.pObj,aPt1-rCon1.aObjOfs);
797  }
798  for (sal_uInt16 nNum2=0; nNum2<nCount2; nNum2++)
799  {
800  if (bAuto2) rCon2.nConId=nNum2;
801  if (bCon2 && rCon2.TakeGluePoint(aGP2))
802  {
803  aPt2=aGP2.GetPos();
804  nEsc2=aGP2.GetEscDir();
805  if (nEsc2==SdrEscapeDirection::SMART) nEsc2=ImpCalcEscAngle(rCon2.pObj,aPt2-rCon2.aObjOfs);
806  }
807  for (long nA1=0; nA1<36000; nA1+=9000)
808  {
810  for (long nA2=0; nA2<36000; nA2+=9000)
811  {
813  if ((nEsc1&nE1) && (nEsc2&nE2))
814  {
815  sal_uIntPtr nQual=0;
816  SdrEdgeInfoRec aInfo;
817  if (pInfo!=nullptr) aInfo=*pInfo;
818  XPolygon aXP(ImpCalcEdgeTrack(aPt1,nA1,aBoundRect1,aBewareRect1,aPt2,nA2,aBoundRect2,aBewareRect2,&nQual,&aInfo));
819  if (nQual<nBestQual)
820  {
821  aBestXP=aXP;
822  nBestQual=nQual;
823  aBestInfo=aInfo;
824  nBestAuto1=nNum1;
825  nBestAuto2=nNum2;
826  }
827  }
828  }
829  }
830  }
831  }
832  if (bAuto1) rCon1.nConId=nBestAuto1;
833  if (bAuto2) rCon2.nConId=nBestAuto2;
834  if (pInfo!=nullptr) *pInfo=aBestInfo;
835  return aBestXP;
836 }
837 
838 XPolygon SdrEdgeObj::ImpCalcEdgeTrack(const Point& rPt1, long nAngle1, const tools::Rectangle& rBoundRect1, const tools::Rectangle& rBewareRect1,
839  const Point& rPt2, long nAngle2, const tools::Rectangle& rBoundRect2, const tools::Rectangle& rBewareRect2,
840  sal_uIntPtr* pnQuality, SdrEdgeInfoRec* pInfo) const
841 {
842  SdrEdgeKind eKind=GetObjectItem(SDRATTR_EDGEKIND).GetValue();
843  bool bRts1=nAngle1==0;
844  bool bObn1=nAngle1==9000;
845  bool bLks1=nAngle1==18000;
846  bool bUnt1=nAngle1==27000;
847  bool bHor1=bLks1 || bRts1;
848  bool bVer1=bObn1 || bUnt1;
849  bool bRts2=nAngle2==0;
850  bool bObn2=nAngle2==9000;
851  bool bLks2=nAngle2==18000;
852  bool bUnt2=nAngle2==27000;
853  bool bHor2=bLks2 || bRts2;
854  bool bVer2=bObn2 || bUnt2;
855  bool bInfo=pInfo!=nullptr;
856  if (bInfo) {
857  pInfo->nAngle1=nAngle1;
858  pInfo->nAngle2=nAngle2;
859  pInfo->nObj1Lines=1;
860  pInfo->nObj2Lines=1;
861  pInfo->nMiddleLine=0xFFFF;
862  }
863  Point aPt1(rPt1);
864  Point aPt2(rPt2);
865  tools::Rectangle aBoundRect1 (rBoundRect1 );
866  tools::Rectangle aBoundRect2 (rBoundRect2 );
867  tools::Rectangle aBewareRect1(rBewareRect1);
868  tools::Rectangle aBewareRect2(rBewareRect2);
869  Point aMeeting((aPt1.X()+aPt2.X()+1)/2,(aPt1.Y()+aPt2.Y()+1)/2);
870  if (eKind==SdrEdgeKind::OneLine) {
871  XPolygon aXP(2);
872  aXP[0]=rPt1;
873  aXP[1]=rPt2;
874  if (pnQuality!=nullptr) {
875  *pnQuality=std::abs(rPt1.X()-rPt2.X())+std::abs(rPt1.Y()-rPt2.Y());
876  }
877  return aXP;
878  } else if (eKind==SdrEdgeKind::ThreeLines) {
879  XPolygon aXP(4);
880  aXP[0]=rPt1;
881  aXP[1]=rPt1;
882  aXP[2]=rPt2;
883  aXP[3]=rPt2;
884  if (bRts1) aXP[1].setX(aBewareRect1.Right() ); //+=500;
885  if (bObn1) aXP[1].setY(aBewareRect1.Top() ); //-=500;
886  if (bLks1) aXP[1].setX(aBewareRect1.Left() ); //-=500;
887  if (bUnt1) aXP[1].setY(aBewareRect1.Bottom() ); //+=500;
888  if (bRts2) aXP[2].setX(aBewareRect2.Right() ); //+=500;
889  if (bObn2) aXP[2].setY(aBewareRect2.Top() ); //-=500;
890  if (bLks2) aXP[2].setX(aBewareRect2.Left() ); //-=500;
891  if (bUnt2) aXP[2].setY(aBewareRect2.Bottom() ); //+=500;
892  if (pnQuality!=nullptr) {
893  long nQ=std::abs(aXP[1].X()-aXP[0].X())+std::abs(aXP[1].Y()-aXP[0].Y());
894  nQ+=std::abs(aXP[2].X()-aXP[1].X())+std::abs(aXP[2].Y()-aXP[1].Y());
895  nQ+=std::abs(aXP[3].X()-aXP[2].X())+std::abs(aXP[3].Y()-aXP[2].Y());
896  *pnQuality=nQ;
897  }
898  if (bInfo) {
899  pInfo->nObj1Lines=2;
900  pInfo->nObj2Lines=2;
901  if (bHor1) {
902  aXP[1].AdjustX(pInfo->aObj1Line2.X() );
903  } else {
904  aXP[1].AdjustY(pInfo->aObj1Line2.Y() );
905  }
906  if (bHor2) {
907  aXP[2].AdjustX(pInfo->aObj2Line2.X() );
908  } else {
909  aXP[2].AdjustY(pInfo->aObj2Line2.Y() );
910  }
911  }
912  return aXP;
913  }
914  sal_uInt16 nIntersections=0;
915  {
916  Point aC1(aBewareRect1.Center());
917  Point aC2(aBewareRect2.Center());
918  if (aBewareRect1.Left()<=aBewareRect2.Right() && aBewareRect1.Right()>=aBewareRect2.Left()) {
919  // overlapping on the x axis
920  long n1=std::max(aBewareRect1.Left(),aBewareRect2.Left());
921  long n2=std::min(aBewareRect1.Right(),aBewareRect2.Right());
922  aMeeting.setX((n1+n2+1)/2 );
923  } else {
924  // otherwise the center point of the empty space
925  if (aC1.X()<aC2.X()) {
926  aMeeting.setX((aBewareRect1.Right()+aBewareRect2.Left()+1)/2 );
927  } else {
928  aMeeting.setX((aBewareRect1.Left()+aBewareRect2.Right()+1)/2 );
929  }
930  }
931  if (aBewareRect1.Top()<=aBewareRect2.Bottom() && aBewareRect1.Bottom()>=aBewareRect2.Top()) {
932  // overlapping on the x axis
933  long n1=std::max(aBewareRect1.Top(),aBewareRect2.Top());
934  long n2=std::min(aBewareRect1.Bottom(),aBewareRect2.Bottom());
935  aMeeting.setY((n1+n2+1)/2 );
936  } else {
937  // otherwise the center point of the empty space
938  if (aC1.Y()<aC2.Y()) {
939  aMeeting.setY((aBewareRect1.Bottom()+aBewareRect2.Top()+1)/2 );
940  } else {
941  aMeeting.setY((aBewareRect1.Top()+aBewareRect2.Bottom()+1)/2 );
942  }
943  }
944  // Here, there are three cases:
945  // 1. both go into the same direction
946  // 2. both go into opposite directions
947  // 3. one is vertical, the other is horizontal
948  long nXMin=std::min(aBewareRect1.Left(),aBewareRect2.Left());
949  long nXMax=std::max(aBewareRect1.Right(),aBewareRect2.Right());
950  long nYMin=std::min(aBewareRect1.Top(),aBewareRect2.Top());
951  long nYMax=std::max(aBewareRect1.Bottom(),aBewareRect2.Bottom());
952  bool bBewareOverlap=aBewareRect1.Right()>aBewareRect2.Left() && aBewareRect1.Left()<aBewareRect2.Right() &&
953  aBewareRect1.Bottom()>aBewareRect2.Top() && aBewareRect1.Top()<aBewareRect2.Bottom();
954  unsigned nMainCase=3;
955  if (nAngle1==nAngle2) nMainCase=1;
956  else if ((bHor1 && bHor2) || (bVer1 && bVer2)) nMainCase=2;
957  if (nMainCase==1) { // case 1 (both go in one direction) is possible
958  if (bVer1) aMeeting.setX((aPt1.X()+aPt2.X()+1)/2 ); // Here, this is better than
959  if (bHor1) aMeeting.setY((aPt1.Y()+aPt2.Y()+1)/2 ); // using center point of empty space
960  // bX1Ok means that the vertical exiting Obj1 doesn't conflict with Obj2, ...
961  bool bX1Ok=aPt1.X()<=aBewareRect2.Left() || aPt1.X()>=aBewareRect2.Right();
962  bool bX2Ok=aPt2.X()<=aBewareRect1.Left() || aPt2.X()>=aBewareRect1.Right();
963  bool bY1Ok=aPt1.Y()<=aBewareRect2.Top() || aPt1.Y()>=aBewareRect2.Bottom();
964  bool bY2Ok=aPt2.Y()<=aBewareRect1.Top() || aPt2.Y()>=aBewareRect1.Bottom();
965  if (bLks1 && (bY1Ok || aBewareRect1.Left()<aBewareRect2.Right()) && (bY2Ok || aBewareRect2.Left()<aBewareRect1.Right())) {
966  aMeeting.setX(nXMin );
967  }
968  if (bRts1 && (bY1Ok || aBewareRect1.Right()>aBewareRect2.Left()) && (bY2Ok || aBewareRect2.Right()>aBewareRect1.Left())) {
969  aMeeting.setX(nXMax );
970  }
971  if (bObn1 && (bX1Ok || aBewareRect1.Top()<aBewareRect2.Bottom()) && (bX2Ok || aBewareRect2.Top()<aBewareRect1.Bottom())) {
972  aMeeting.setY(nYMin );
973  }
974  if (bUnt1 && (bX1Ok || aBewareRect1.Bottom()>aBewareRect2.Top()) && (bX2Ok || aBewareRect2.Bottom()>aBewareRect1.Top())) {
975  aMeeting.setY(nYMax );
976  }
977  } else if (nMainCase==2) {
978  // case 2:
979  if (bHor1) { // both horizontal
980  /* 9 sub-cases:
981  (legend: line exits to the left (-|), right (|-))
982 
983  2.1: Facing; overlap only on y axis
984  * * *
985  |--| *
986  * * *
987 
988  2.2, 2.3: Facing, offset vertically; no overlap on either
989  axis
990  |- * * * * *
991  * -| * * -| *
992  * * * , * * *
993 
994  2.4, 2.5: One below the other; overlap only on y axis
995  * |- * * * *
996  * -| * * -| *
997  * * * , * |- *
998 
999  2.6, 2.7: Not facing, offset vertically; no overlap on either
1000  axis
1001  * * |- * * *
1002  * -| * * -| *
1003  * * * , * * |-
1004 
1005  2.8: Not facing; overlap only on y axis
1006  * * *
1007  * -| |-
1008  * * *
1009 
1010  2.9: The objects's BewareRects overlap on x and y axis
1011 
1012  These cases, with some modifications are also valid for
1013  horizontal line exits.
1014  Cases 2.1 through 2.7 are covered well enough with the
1015  default meetings. Only for cases 2.8 and 2.9 do we determine
1016  special meeting points here.
1017  */
1018 
1019  // normalization; be aR1 the one exiting to the right,
1020  // be aR2 the one exiting to the left
1021  tools::Rectangle aBewR1(bRts1 ? aBewareRect1 : aBewareRect2);
1022  tools::Rectangle aBewR2(bRts1 ? aBewareRect2 : aBewareRect1);
1023  tools::Rectangle aBndR1(bRts1 ? aBoundRect1 : aBoundRect2);
1024  tools::Rectangle aBndR2(bRts1 ? aBoundRect2 : aBoundRect1);
1025  if (aBewR1.Bottom()>aBewR2.Top() && aBewR1.Top()<aBewR2.Bottom()) {
1026  // overlap on y axis; cases 2.1, 2.8, 2.9
1027  if (aBewR1.Right()>aBewR2.Left()) {
1028  /* Cases 2.8, 2.9:
1029  Case 2.8: always going around on the outside
1030  (bDirect=false).
1031 
1032  Case 2.9 could also be a direct connection (in the
1033  case that the BewareRects overlap only slightly and
1034  the BoundRects don't overlap at all and if the
1035  line exits would otherwise violate the respective
1036  other object's BewareRect).
1037  */
1038  bool bCase29Direct = false;
1039  bool bCase29=aBewR1.Right()>aBewR2.Left();
1040  if (aBndR1.Right()<=aBndR2.Left()) { // case 2.9 without BoundRect overlap
1041  if ((aPt1.Y()>aBewareRect2.Top() && aPt1.Y()<aBewareRect2.Bottom()) ||
1042  (aPt2.Y()>aBewareRect1.Top() && aPt2.Y()<aBewareRect1.Bottom())) {
1043  bCase29Direct = true;
1044  }
1045  }
1046  if (!bCase29Direct) {
1047  bool bObenLang=std::abs(nYMin-aMeeting.Y())<=std::abs(nYMax-aMeeting.Y());
1048  if (bObenLang) {
1049  aMeeting.setY(nYMin );
1050  } else {
1051  aMeeting.setY(nYMax );
1052  }
1053  if (bCase29) {
1054  // now make sure that the surrounded object
1055  // isn't traversed
1056  if ((aBewR1.Center().Y()<aBewR2.Center().Y()) != bObenLang) {
1057  aMeeting.setX(aBewR2.Right() );
1058  } else {
1059  aMeeting.setX(aBewR1.Left() );
1060  }
1061  }
1062  } else {
1063  // We need a direct connection (3-line Z connection),
1064  // because we have to violate the BewareRects.
1065  // Use rule of three to scale down the BewareRects.
1066  long nWant1=aBewR1.Right()-aBndR1.Right(); // distance at Obj1
1067  long nWant2=aBndR2.Left()-aBewR2.Left(); // distance at Obj2
1068  long nSpace=aBndR2.Left()-aBndR1.Right(); // available space
1069  long nGet1=BigMulDiv(nWant1,nSpace,nWant1+nWant2);
1070  long nGet2=nSpace-nGet1;
1071  if (bRts1) { // revert normalization
1072  aBewareRect1.AdjustRight(nGet1-nWant1 );
1073  aBewareRect2.AdjustLeft( -(nGet2-nWant2) );
1074  } else {
1075  aBewareRect2.AdjustRight(nGet1-nWant1 );
1076  aBewareRect1.AdjustLeft( -(nGet2-nWant2) );
1077  }
1078  nIntersections++; // lower quality
1079  }
1080  }
1081  }
1082  } else if (bVer1) { // both horizontal
1083  tools::Rectangle aBewR1(bUnt1 ? aBewareRect1 : aBewareRect2);
1084  tools::Rectangle aBewR2(bUnt1 ? aBewareRect2 : aBewareRect1);
1085  tools::Rectangle aBndR1(bUnt1 ? aBoundRect1 : aBoundRect2);
1086  tools::Rectangle aBndR2(bUnt1 ? aBoundRect2 : aBoundRect1);
1087  if (aBewR1.Right()>aBewR2.Left() && aBewR1.Left()<aBewR2.Right()) {
1088  // overlap on y axis; cases 2.1, 2.8, 2.9
1089  if (aBewR1.Bottom()>aBewR2.Top()) {
1090  /* Cases 2.8, 2.9
1091  Case 2.8 always going around on the outside (bDirect=false).
1092 
1093  Case 2.9 could also be a direct connection (in the
1094  case that the BewareRects overlap only slightly and
1095  the BoundRects don't overlap at all and if the
1096  line exits would otherwise violate the respective
1097  other object's BewareRect).
1098  */
1099  bool bCase29Direct = false;
1100  bool bCase29=aBewR1.Bottom()>aBewR2.Top();
1101  if (aBndR1.Bottom()<=aBndR2.Top()) { // case 2.9 without BoundRect overlap
1102  if ((aPt1.X()>aBewareRect2.Left() && aPt1.X()<aBewareRect2.Right()) ||
1103  (aPt2.X()>aBewareRect1.Left() && aPt2.X()<aBewareRect1.Right())) {
1104  bCase29Direct = true;
1105  }
1106  }
1107  if (!bCase29Direct) {
1108  bool bLinksLang=std::abs(nXMin-aMeeting.X())<=std::abs(nXMax-aMeeting.X());
1109  if (bLinksLang) {
1110  aMeeting.setX(nXMin );
1111  } else {
1112  aMeeting.setX(nXMax );
1113  }
1114  if (bCase29) {
1115  // now make sure that the surrounded object
1116  // isn't traversed
1117  if ((aBewR1.Center().X()<aBewR2.Center().X()) != bLinksLang) {
1118  aMeeting.setY(aBewR2.Bottom() );
1119  } else {
1120  aMeeting.setY(aBewR1.Top() );
1121  }
1122  }
1123  } else {
1124  // We need a direct connection (3-line Z connection),
1125  // because we have to violate the BewareRects.
1126  // Use rule of three to scale down the BewareRects.
1127  long nWant1=aBewR1.Bottom()-aBndR1.Bottom(); // difference at Obj1
1128  long nWant2=aBndR2.Top()-aBewR2.Top(); // difference at Obj2
1129  long nSpace=aBndR2.Top()-aBndR1.Bottom(); // available space
1130  long nGet1=BigMulDiv(nWant1,nSpace,nWant1+nWant2);
1131  long nGet2=nSpace-nGet1;
1132  if (bUnt1) { // revert normalization
1133  aBewareRect1.AdjustBottom(nGet1-nWant1 );
1134  aBewareRect2.AdjustTop( -(nGet2-nWant2) );
1135  } else {
1136  aBewareRect2.AdjustBottom(nGet1-nWant1 );
1137  aBewareRect1.AdjustTop( -(nGet2-nWant2) );
1138  }
1139  nIntersections++; // lower quality
1140  }
1141  }
1142  }
1143  }
1144  } else if (nMainCase==3) { // case 3: one horizontal, the other vertical
1145  /* legend:
1146  The line exits to the:
1147  -| left
1148 
1149  |- right
1150 
1151  _|_ top
1152 
1153  T bottom
1154 
1155  * . * . * -- no overlap, at most might touch
1156  . . . . . -- overlap
1157  * . |- . * -- same height
1158  . . . . . -- overlap
1159  * . * . * -- no overlap, at most might touch
1160 
1161  Overall, there are 96 possible constellations, some of these can't even
1162  be unambiguously assigned to a certain case/method of handling.
1163 
1164 
1165  3.1: All those constellations that are covered reasonably well
1166  by the default MeetingPoint (20+12).
1167 
1168  T T T . _|_ _|_ . T T T these 12 * . * T * * . * . * * T * . * * . * . *
1169  . . . . _|_ _|_ . . . . constellations . . . . . . . . . T . . . . . T . . . .
1170  * . |- . * * . -| . * are covered * . |- . _|_ * . |- . T _|_ . -| . * T . -| . *
1171  . . . . T T . . . . only in . . . . _|_ . . . . . _|_ . . . . . . . . .
1172  _|__|__|_ . T T . _|__|__|_ part: * . * _|_ * * . * . * * _|_ * . * * . * . *
1173 
1174  The last 16 of these cases can be excluded, if the objects face each other openly.
1175 
1176 
1177  3.2: The objects face each other openly, thus a connection using only two lines is possible (4+20);
1178  This case is priority #1.
1179  * . * . T T . * . * these 20 * . * T * * T * . * * . * . * * . * . *
1180  . . . . . . . . . . constellations . . . T T T T . . . . . . . . . . . . .
1181  * . |- . * * . -| . * are covered * . |-_|__|_ _|__|_-| . * * . |- T T T T -| . *
1182  . . . . . . . . . . only in . . . _|__|_ _|__|_ . . . . . . . . . . . . .
1183  * . * . _|_ _|_ . * . * part: * . * _|_ * * _|_ * . * * . * . * * . * . *
1184 
1185  3.3: The line exits point away from the other object or miss its back (52+4).
1186  _|__|__|__|_ * * _|__|__|__|_ * . . . * * . * . * these 4 * . * . * * . * . *
1187  _|__|__|__|_ . . _|__|__|__|_ T T T . . . . T T T constellations . . . T . . T . . .
1188  _|__|_ |- . * * . -| _|__|_ T T |- . * * . -| T T are covered * . |- . * * . -| . *
1189  _|__|__|_ . . . . _|__|__|_ T T T T . . T T T T only in . . . _|_ . . _|_ . . .
1190  * . * . * * . * . * T T T T * * T T T T part: * . * . * * . * . *
1191  */
1192 
1193  // case 3.2
1194  tools::Rectangle aTmpR1(aBewareRect1);
1195  tools::Rectangle aTmpR2(aBewareRect2);
1196  if (bBewareOverlap) {
1197  // overlapping BewareRects: use BoundRects for checking for case 3.2
1198  aTmpR1=aBoundRect1;
1199  aTmpR2=aBoundRect2;
1200  }
1201  if ((((bRts1 && aTmpR1.Right ()<=aPt2.X()) || (bLks1 && aTmpR1.Left()>=aPt2.X())) &&
1202  ((bUnt2 && aTmpR2.Bottom()<=aPt1.Y()) || (bObn2 && aTmpR2.Top ()>=aPt1.Y()))) ||
1203  (((bRts2 && aTmpR2.Right ()<=aPt1.X()) || (bLks2 && aTmpR2.Left()>=aPt1.X())) &&
1204  ((bUnt1 && aTmpR1.Bottom()<=aPt2.Y()) || (bObn1 && aTmpR1.Top ()>=aPt2.Y())))) {
1205  // case 3.2 applies: connector with only 2 lines
1206  if (bHor1) {
1207  aMeeting.setX(aPt2.X() );
1208  aMeeting.setY(aPt1.Y() );
1209  } else {
1210  aMeeting.setX(aPt1.X() );
1211  aMeeting.setY(aPt2.Y() );
1212  }
1213  // in the case of overlapping BewareRects:
1214  aBewareRect1=aTmpR1;
1215  aBewareRect2=aTmpR2;
1216  } else if ((((bRts1 && aBewareRect1.Right ()>aBewareRect2.Left ()) ||
1217  (bLks1 && aBewareRect1.Left ()<aBewareRect2.Right ())) &&
1218  ((bUnt2 && aBewareRect2.Bottom()>aBewareRect1.Top ()) ||
1219  (bObn2 && aBewareRect2.Top ()<aBewareRect1.Bottom()))) ||
1220  (((bRts2 && aBewareRect2.Right ()>aBewareRect1.Left ()) ||
1221  (bLks2 && aBewareRect2.Left ()<aBewareRect1.Right ())) &&
1222  ((bUnt1 && aBewareRect1.Bottom()>aBewareRect2.Top ()) ||
1223  (bObn1 && aBewareRect1.Top ()<aBewareRect2.Bottom())))) {
1224  // case 3.3
1225  if (bRts1 || bRts2) { aMeeting.setX(nXMax ); }
1226  if (bLks1 || bLks2) { aMeeting.setX(nXMin ); }
1227  if (bUnt1 || bUnt2) { aMeeting.setY(nYMax ); }
1228  if (bObn1 || bObn2) { aMeeting.setY(nYMin ); }
1229  }
1230  }
1231  }
1232 
1233  XPolygon aXP1(ImpCalcObjToCenter(aPt1,nAngle1,aBewareRect1,aMeeting));
1234  XPolygon aXP2(ImpCalcObjToCenter(aPt2,nAngle2,aBewareRect2,aMeeting));
1235  sal_uInt16 nXP1Cnt=aXP1.GetPointCount();
1236  sal_uInt16 nXP2Cnt=aXP2.GetPointCount();
1237  if (bInfo) {
1238  pInfo->nObj1Lines=nXP1Cnt; if (nXP1Cnt>1) pInfo->nObj1Lines--;
1239  pInfo->nObj2Lines=nXP2Cnt; if (nXP2Cnt>1) pInfo->nObj2Lines--;
1240  }
1241  Point aEP1(aXP1[nXP1Cnt-1]);
1242  Point aEP2(aXP2[nXP2Cnt-1]);
1243  bool bInsMeetingPoint=aEP1.X()!=aEP2.X() && aEP1.Y()!=aEP2.Y();
1244  bool bHorzE1=aEP1.Y()==aXP1[nXP1Cnt-2].Y(); // is last line of XP1 horizontal?
1245  bool bHorzE2=aEP2.Y()==aXP2[nXP2Cnt-2].Y(); // is last line of XP2 horizontal?
1246  if (aEP1==aEP2 && ((bHorzE1 && bHorzE2 && aEP1.Y()==aEP2.Y()) || (!bHorzE1 && !bHorzE2 && aEP1.X()==aEP2.X()))) {
1247  // special casing 'I' connectors
1248  nXP1Cnt--; aXP1.Remove(nXP1Cnt,1);
1249  nXP2Cnt--; aXP2.Remove(nXP2Cnt,1);
1250  }
1251  if (bInsMeetingPoint) {
1252  aXP1.Insert(XPOLY_APPEND,aMeeting,PolyFlags::Normal);
1253  if (bInfo) {
1254  // Inserting a MeetingPoint adds 2 new lines,
1255  // either might become the center line.
1256  if (pInfo->nObj1Lines==pInfo->nObj2Lines) {
1257  pInfo->nObj1Lines++;
1258  pInfo->nObj2Lines++;
1259  } else {
1260  if (pInfo->nObj1Lines>pInfo->nObj2Lines) {
1261  pInfo->nObj2Lines++;
1262  pInfo->nMiddleLine=nXP1Cnt-1;
1263  } else {
1264  pInfo->nObj1Lines++;
1265  pInfo->nMiddleLine=nXP1Cnt;
1266  }
1267  }
1268  }
1269  } else if (bInfo && aEP1!=aEP2 && nXP1Cnt+nXP2Cnt>=4) {
1270  // By connecting both ends, another line is added, this becomes the center line.
1271  pInfo->nMiddleLine=nXP1Cnt-1;
1272  }
1273  sal_uInt16 nNum=aXP2.GetPointCount();
1274  if (aXP1[nXP1Cnt-1]==aXP2[nXP2Cnt-1] && nXP1Cnt>1 && nXP2Cnt>1) nNum--;
1275  while (nNum>0) {
1276  nNum--;
1277  aXP1.Insert(XPOLY_APPEND,aXP2[nNum],PolyFlags::Normal);
1278  }
1279  sal_uInt16 nPointCount=aXP1.GetPointCount();
1280  char cForm;
1281  if (bInfo || pnQuality!=nullptr) {
1282  if (nPointCount==2) cForm='I';
1283  else if (nPointCount==3) cForm='L';
1284  else if (nPointCount==4) { // Z or U
1285  if (nAngle1==nAngle2) cForm='U';
1286  else cForm='Z';
1287  } else if (nPointCount==6) { // S or C or ...
1288  if (nAngle1!=nAngle2) {
1289  // For type S, line 2 has the same direction as line 4.
1290  // For type C, the opposite is true.
1291  Point aP1(aXP1[1]);
1292  Point aP2(aXP1[2]);
1293  Point aP3(aXP1[3]);
1294  Point aP4(aXP1[4]);
1295  if (aP1.Y()==aP2.Y()) { // else both lines are horizontal
1296  if ((aP1.X()<aP2.X())==(aP3.X()<aP4.X())) cForm='S';
1297  else cForm='C';
1298  } else { // else both lines are vertical
1299  if ((aP1.Y()<aP2.Y())==(aP3.Y()<aP4.Y())) cForm='S';
1300  else cForm='C';
1301  }
1302  } else cForm='4'; // else is case 3 with 5 lines
1303  } else cForm='?';
1304  // more shapes:
1305  if (bInfo) {
1306  if (cForm=='I' || cForm=='L' || cForm=='Z' || cForm=='U') {
1307  pInfo->nObj1Lines=1;
1308  pInfo->nObj2Lines=1;
1309  if (cForm=='Z' || cForm=='U') {
1310  pInfo->nMiddleLine=1;
1311  } else {
1312  pInfo->nMiddleLine=0xFFFF;
1313  }
1314  } else if (cForm=='S' || cForm=='C') {
1315  pInfo->nObj1Lines=2;
1316  pInfo->nObj2Lines=2;
1317  pInfo->nMiddleLine=2;
1318  }
1319  }
1320  }
1321  else
1322  {
1323  cForm = 0;
1324  }
1325  if (pnQuality!=nullptr) {
1326  sal_uIntPtr nQual=0;
1327  sal_uIntPtr nQual0=nQual; // prevent overruns
1328  bool bOverflow = false;
1329  Point aPt0(aXP1[0]);
1330  for (sal_uInt16 nPntNum=1; nPntNum<nPointCount; nPntNum++) {
1331  Point aPt1b(aXP1[nPntNum]);
1332  nQual+=std::abs(aPt1b.X()-aPt0.X())+std::abs(aPt1b.Y()-aPt0.Y());
1333  if (nQual<nQual0) bOverflow = true;
1334  nQual0=nQual;
1335  aPt0=aPt1b;
1336  }
1337 
1338  sal_uInt16 nTmp=nPointCount;
1339  if (cForm=='Z') {
1340  nTmp=2; // Z shape with good quality (nTmp=2 instead of 4)
1341  sal_uIntPtr n1=std::abs(aXP1[1].X()-aXP1[0].X())+std::abs(aXP1[1].Y()-aXP1[0].Y());
1342  sal_uIntPtr n2=std::abs(aXP1[2].X()-aXP1[1].X())+std::abs(aXP1[2].Y()-aXP1[1].Y());
1343  sal_uIntPtr n3=std::abs(aXP1[3].X()-aXP1[2].X())+std::abs(aXP1[3].Y()-aXP1[2].Y());
1344  // try to make lines lengths similar
1345  sal_uIntPtr nBesser=0;
1346  n1+=n3;
1347  n3=n2/4;
1348  if (n1>=n2) nBesser=6;
1349  else if (n1>=3*n3) nBesser=4;
1350  else if (n1>=2*n3) nBesser=2;
1351  if (aXP1[0].Y()!=aXP1[1].Y()) nBesser++; // vertical starting line gets a plus (for H/V-Prio)
1352  if (nQual>nBesser) nQual-=nBesser; else nQual=0;
1353  }
1354  if (nTmp>=3) {
1355  nQual0=nQual;
1356  nQual+=static_cast<sal_uIntPtr>(nTmp)*0x01000000;
1357  if (nQual<nQual0 || nTmp>15) bOverflow = true;
1358  }
1359  if (nPointCount>=2) { // check exit angle again
1360  Point aP1(aXP1[1]); aP1-=aXP1[0];
1361  Point aP2(aXP1[nPointCount-2]); aP2-=aXP1[nPointCount-1];
1362  long nAng1=0; if (aP1.X()<0) nAng1=18000; if (aP1.Y()>0) nAng1=27000;
1363  if (aP1.Y()<0) nAng1=9000;
1364  if (aP1.X()!=0 && aP1.Y()!=0) nAng1=1; // slant?!
1365  long nAng2=0; if (aP2.X()<0) nAng2=18000; if (aP2.Y()>0) nAng2=27000;
1366  if (aP2.Y()<0) nAng2=9000;
1367  if (aP2.X()!=0 && aP2.Y()!=0) nAng2=1; // slant?!
1368  if (nAng1!=nAngle1) nIntersections++;
1369  if (nAng2!=nAngle2) nIntersections++;
1370  }
1371 
1372  // For the quality check, use the original Rects and at the same time
1373  // check whether one them was scaled down for the calculation of the
1374  // Edges (e. g. case 2.9)
1375  aBewareRect1=rBewareRect1;
1376  aBewareRect2=rBewareRect2;
1377 
1378  for (sal_uInt16 i=0; i<nPointCount; i++) {
1379  Point aPt1b(aXP1[i]);
1380  bool b1=aPt1b.X()>aBewareRect1.Left() && aPt1b.X()<aBewareRect1.Right() &&
1381  aPt1b.Y()>aBewareRect1.Top() && aPt1b.Y()<aBewareRect1.Bottom();
1382  bool b2=aPt1b.X()>aBewareRect2.Left() && aPt1b.X()<aBewareRect2.Right() &&
1383  aPt1b.Y()>aBewareRect2.Top() && aPt1b.Y()<aBewareRect2.Bottom();
1384  sal_uInt16 nInt0=nIntersections;
1385  if (i==0 || i==nPointCount-1) {
1386  if (b1 && b2) nIntersections++;
1387  } else {
1388  if (b1) nIntersections++;
1389  if (b2) nIntersections++;
1390  }
1391  // check for overlaps
1392  if (i>0 && nInt0==nIntersections) {
1393  if (aPt0.Y()==aPt1b.Y()) { // horizontal line
1394  if (aPt0.Y()>aBewareRect1.Top() && aPt0.Y()<aBewareRect1.Bottom() &&
1395  ((aPt0.X()<=aBewareRect1.Left() && aPt1b.X()>=aBewareRect1.Right()) ||
1396  (aPt1b.X()<=aBewareRect1.Left() && aPt0.X()>=aBewareRect1.Right()))) nIntersections++;
1397  if (aPt0.Y()>aBewareRect2.Top() && aPt0.Y()<aBewareRect2.Bottom() &&
1398  ((aPt0.X()<=aBewareRect2.Left() && aPt1b.X()>=aBewareRect2.Right()) ||
1399  (aPt1b.X()<=aBewareRect2.Left() && aPt0.X()>=aBewareRect2.Right()))) nIntersections++;
1400  } else { // vertical line
1401  if (aPt0.X()>aBewareRect1.Left() && aPt0.X()<aBewareRect1.Right() &&
1402  ((aPt0.Y()<=aBewareRect1.Top() && aPt1b.Y()>=aBewareRect1.Bottom()) ||
1403  (aPt1b.Y()<=aBewareRect1.Top() && aPt0.Y()>=aBewareRect1.Bottom()))) nIntersections++;
1404  if (aPt0.X()>aBewareRect2.Left() && aPt0.X()<aBewareRect2.Right() &&
1405  ((aPt0.Y()<=aBewareRect2.Top() && aPt1b.Y()>=aBewareRect2.Bottom()) ||
1406  (aPt1b.Y()<=aBewareRect2.Top() && aPt0.Y()>=aBewareRect2.Bottom()))) nIntersections++;
1407  }
1408  }
1409  aPt0=aPt1b;
1410  }
1411  if (nPointCount<=1) nIntersections++;
1412  nQual0=nQual;
1413  nQual+=static_cast<sal_uIntPtr>(nIntersections)*0x10000000;
1414  if (nQual<nQual0 || nIntersections>15) bOverflow = true;
1415 
1416  if (bOverflow || nQual==0xFFFFFFFF) nQual=0xFFFFFFFE;
1417  *pnQuality=nQual;
1418  }
1419  if (bInfo) { // now apply line offsets to aXP1
1420  if (pInfo->nMiddleLine!=0xFFFF) {
1421  sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::MiddleLine,aXP1);
1422  if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::MiddleLine,aXP1)) {
1423  aXP1[nIdx].AdjustY(pInfo->aMiddleLine.Y() );
1424  aXP1[nIdx+1].AdjustY(pInfo->aMiddleLine.Y() );
1425  } else {
1426  aXP1[nIdx].AdjustX(pInfo->aMiddleLine.X() );
1427  aXP1[nIdx+1].AdjustX(pInfo->aMiddleLine.X() );
1428  }
1429  }
1430  if (pInfo->nObj1Lines>=2) {
1431  sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj1Line2,aXP1);
1432  if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj1Line2,aXP1)) {
1433  aXP1[nIdx].AdjustY(pInfo->aObj1Line2.Y() );
1434  aXP1[nIdx+1].AdjustY(pInfo->aObj1Line2.Y() );
1435  } else {
1436  aXP1[nIdx].AdjustX(pInfo->aObj1Line2.X() );
1437  aXP1[nIdx+1].AdjustX(pInfo->aObj1Line2.X() );
1438  }
1439  }
1440  if (pInfo->nObj1Lines>=3) {
1441  sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj1Line3,aXP1);
1442  if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj1Line3,aXP1)) {
1443  aXP1[nIdx].AdjustY(pInfo->aObj1Line3.Y() );
1444  aXP1[nIdx+1].AdjustY(pInfo->aObj1Line3.Y() );
1445  } else {
1446  aXP1[nIdx].AdjustX(pInfo->aObj1Line3.X() );
1447  aXP1[nIdx+1].AdjustX(pInfo->aObj1Line3.X() );
1448  }
1449  }
1450  if (pInfo->nObj2Lines>=2) {
1451  sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj2Line2,aXP1);
1452  if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj2Line2,aXP1)) {
1453  aXP1[nIdx].AdjustY(pInfo->aObj2Line2.Y() );
1454  aXP1[nIdx+1].AdjustY(pInfo->aObj2Line2.Y() );
1455  } else {
1456  aXP1[nIdx].AdjustX(pInfo->aObj2Line2.X() );
1457  aXP1[nIdx+1].AdjustX(pInfo->aObj2Line2.X() );
1458  }
1459  }
1460  if (pInfo->nObj2Lines>=3) {
1461  sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj2Line3,aXP1);
1462  if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj2Line3,aXP1)) {
1463  aXP1[nIdx].AdjustY(pInfo->aObj2Line3.Y() );
1464  aXP1[nIdx+1].AdjustY(pInfo->aObj2Line3.Y() );
1465  } else {
1466  aXP1[nIdx].AdjustX(pInfo->aObj2Line3.X() );
1467  aXP1[nIdx+1].AdjustX(pInfo->aObj2Line3.X() );
1468  }
1469  }
1470  }
1471  // make the connector a bezier curve, if appropriate
1472  if (eKind==SdrEdgeKind::Bezier && nPointCount>2) {
1473  Point* pPt1=&aXP1[0];
1474  Point* pPt2=&aXP1[1];
1475  Point* pPt3=&aXP1[nPointCount-2];
1476  Point* pPt4=&aXP1[nPointCount-1];
1477  long dx1=pPt2->X()-pPt1->X();
1478  long dy1=pPt2->Y()-pPt1->Y();
1479  long dx2=pPt3->X()-pPt4->X();
1480  long dy2=pPt3->Y()-pPt4->Y();
1481  if (cForm=='L') { // nPointCount==3
1482  aXP1.SetFlags(1,PolyFlags::Control);
1483  Point aPt3(*pPt2);
1484  aXP1.Insert(2,aPt3,PolyFlags::Control);
1485  nPointCount=aXP1.GetPointCount();
1486  pPt2=&aXP1[1];
1487  pPt3=&aXP1[nPointCount-2];
1488  pPt2->AdjustX( -(dx1/3) );
1489  pPt2->AdjustY( -(dy1/3) );
1490  pPt3->AdjustX( -(dx2/3) );
1491  pPt3->AdjustY( -(dy2/3) );
1492  } else if (nPointCount>=4 && nPointCount<=6) { // Z or U or ...
1493  // To all others, the end points of the original lines become control
1494  // points for now. Thus, we need to do some more work for nPointCount>4!
1495  aXP1.SetFlags(1,PolyFlags::Control);
1496  aXP1.SetFlags(nPointCount-2,PolyFlags::Control);
1497  // distance x1.5
1498  pPt2->AdjustX(dx1/2 );
1499  pPt2->AdjustY(dy1/2 );
1500  pPt3->AdjustX(dx2/2 );
1501  pPt3->AdjustY(dy2/2 );
1502  if (nPointCount==5) {
1503  // add a control point before and after center
1504  Point aCenter(aXP1[2]);
1505  long dx1b=aCenter.X()-aXP1[1].X();
1506  long dy1b=aCenter.Y()-aXP1[1].Y();
1507  long dx2b=aCenter.X()-aXP1[3].X();
1508  long dy2b=aCenter.Y()-aXP1[3].Y();
1509  aXP1.Insert(2,aCenter,PolyFlags::Control);
1510  aXP1.SetFlags(3,PolyFlags::Symmetric);
1511  aXP1.Insert(4,aCenter,PolyFlags::Control);
1512  aXP1[2].AdjustX( -(dx1b/2) );
1513  aXP1[2].AdjustY( -(dy1b/2) );
1514  aXP1[3].AdjustX( -((dx1b+dx2b)/4) );
1515  aXP1[3].AdjustY( -((dy1b+dy2b)/4) );
1516  aXP1[4].AdjustX( -(dx2b/2) );
1517  aXP1[4].AdjustY( -(dy2b/2) );
1518  }
1519  if (nPointCount==6) {
1520  Point aPt1b(aXP1[2]);
1521  Point aPt2b(aXP1[3]);
1522  aXP1.Insert(2,aPt1b,PolyFlags::Control);
1523  aXP1.Insert(5,aPt2b,PolyFlags::Control);
1524  long dx=aPt1b.X()-aPt2b.X();
1525  long dy=aPt1b.Y()-aPt2b.Y();
1526  aXP1[3].AdjustX( -(dx/2) );
1527  aXP1[3].AdjustY( -(dy/2) );
1528  aXP1.SetFlags(3,PolyFlags::Symmetric);
1529  aXP1.Remove(4,1); // because it's identical with aXP1[3]
1530  }
1531  }
1532  }
1533  return aXP1;
1534 }
1535 
1536 /*
1537 There could be a maximum of 64 different developments with 5 lines, a
1538 maximum of 32 developments with 4 lines, a maximum of 16 developments with
1539 3 lines, a maximum of 8 developments with 2 lines.
1540 This gives us a total of 124 possibilities.
1541 Normalized for the 1st exit angle to the right, there remain 31 possibilities.
1542 Now, normalizing away the vertical mirroring, we get to a total of 16
1543 characteristic developments with 1 through 5 lines:
1544 
1545 1 line (type "I") --
1546 
1547 2 lines (type "L") __|
1548 
1549 3 lines (type "U") __ (type "Z") _
1550  __| _|
1551  _ _
1552 4 lines #1 _| #2 | | #3 |_ #4 | |
1553  _| _| _| _|
1554  Of these, #1 is implausible, #2 is a rotated version of #3. This leaves
1555  #2 (from now on referred to as 4.1) and #4 (from now on referred to as 4.2).
1556  _ _
1557 5 lines #1 _| #2 _| #3 ___ #4 _
1558  _| _| _| _| _| |_
1559  _ _ _
1560  #5 |_ #6 |_ #7 _| | #8 ____
1561  _| _| _| |_ _|
1562  Of these, 5.1, 5.2, 5.4 and 5.5 are implausible, 5.7 is a reversed version
1563  of 5.3. This leaves 5.3 (type "4"), 5.6 (type "S") and 5.8 (type "C").
1564 
1565 We now have discerned the 9 basic types to cover all 400 possible constellations
1566 of object positions and exit angles. 4 of the 9 types have got a center
1567 line (CL). The number of object margins per object varies between 0 and 3:
1568 
1569  CL O1 O2 Note
1570 "I": n 0 0
1571 "L": n 0 0
1572 "U": n 0-1 0-1
1573 "Z": y 0 0
1574 4.2: y 0 1 = U+1, respectively 1+U
1575 4.4: n 0-2 0-2 = Z+1
1576 "4": y 0 2 = Z+2
1577 "S": y 1 1 = 1+Z+1
1578 "C": n 0-3 0-3 = 1+U+1
1579 */
1580 
1582 {
1583  const SfxHintId nId = rHint.GetId();
1584  bool bDataChg=nId==SfxHintId::DataChanged;
1585  bool bDying=nId==SfxHintId::Dying;
1586  bool bObj1=aCon1.pObj!=nullptr && aCon1.pObj->GetBroadcaster()==&rBC;
1587  bool bObj2=aCon2.pObj!=nullptr && aCon2.pObj->GetBroadcaster()==&rBC;
1588  if (bDying && (bObj1 || bObj2)) {
1589  // catch Dying, so AttrObj doesn't start broadcasting
1590  // about an alleged change of template
1591  if (bObj1) aCon1.pObj=nullptr;
1592  if (bObj2) aCon2.pObj=nullptr;
1593  return;
1594  }
1595  if ( bObj1 || bObj2 )
1596  {
1597  bEdgeTrackUserDefined = false;
1598  }
1599  SdrTextObj::Notify(rBC,rHint);
1600  if (nNotifyingCount!=0)return;
1601 
1602 // a locking flag
1603  nNotifyingCount++;
1604  const SdrHint* pSdrHint = ( rHint.GetId() == SfxHintId::ThisIsAnSdrHint ? static_cast<const SdrHint*>(&rHint) : nullptr );
1605 
1606  if (bDataChg) { // StyleSheet changed
1607  ImpSetAttrToEdgeInfo(); // when changing templates, copy values from Pool to aEdgeInfo
1608  }
1609  if (bDataChg ||
1612  (pSdrHint && pSdrHint->GetKind()==SdrHintKind::ObjectRemoved))
1613  {
1614  // broadcasting only, if on the same page
1615  tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetCurrentBoundRect();
1617 
1618  // only redraw here, object hasn't actually changed
1619  ActionChanged();
1620 
1622  }
1623  nNotifyingCount--;
1624 }
1625 
1630 {
1631  if( nullptr != aCon1.pObj )
1632  {
1633  SfxHint aHint( SfxHintId::DataChanged );
1634  Notify( *const_cast<SfxBroadcaster*>(aCon1.pObj->GetBroadcaster()), aHint );
1635  }
1636 
1637  if( nullptr != aCon2.pObj )
1638  {
1639  SfxHint aHint( SfxHintId::DataChanged );
1640  Notify( *const_cast<SfxBroadcaster*>(aCon2.pObj->GetBroadcaster()), aHint );
1641  }
1642 }
1643 
1645 {
1646  return CloneHelper< SdrEdgeObj >(rTargetModel);
1647 }
1648 
1650 {
1651  if( this == &rObj )
1652  return *this;
1653  SdrTextObj::operator=(rObj);
1654  *pEdgeTrack =*rObj.pEdgeTrack;
1656  aCon1 =rObj.aCon1;
1657  aCon2 =rObj.aCon2;
1658  aCon1.pObj=nullptr;
1659  aCon2.pObj=nullptr;
1660  aEdgeInfo=rObj.aEdgeInfo;
1661  return *this;
1662 }
1663 
1665 {
1666  OUStringBuffer sName(SvxResId(STR_ObjNameSingulEDGE));
1667 
1668  OUString aName(GetName());
1669  if (!aName.isEmpty())
1670  {
1671  sName.append(' ');
1672  sName.append('\'');
1673  sName.append(aName);
1674  sName.append('\'');
1675  }
1676  return sName.makeStringAndClear();
1677 }
1678 
1680 {
1681  return SvxResId(STR_ObjNamePluralEDGE);
1682 }
1683 
1685 {
1686  basegfx::B2DPolyPolygon aPolyPolygon;
1687 
1688  if (bEdgeTrackDirty)
1689  {
1690  const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
1691  }
1692 
1693  if(pEdgeTrack)
1694  {
1695  aPolyPolygon.append(pEdgeTrack->getB2DPolygon());
1696  }
1697 
1698  return aPolyPolygon;
1699 }
1700 
1702 {
1703  if ( !rPoly.count() )
1704  {
1705  bEdgeTrackDirty = true;
1706  bEdgeTrackUserDefined = false;
1707  }
1708  else
1709  {
1710  *pEdgeTrack = XPolygon( rPoly.getB2DPolygon( 0 ) );
1711  bEdgeTrackDirty = false;
1712  bEdgeTrackUserDefined = true;
1713 
1714  // #i110629# also set aRect and maSnapeRect depending on pEdgeTrack
1715  const tools::Rectangle aPolygonBounds(pEdgeTrack->GetBoundRect());
1716  maRect = aPolygonBounds;
1717  maSnapRect = aPolygonBounds;
1718  }
1719 }
1720 
1722 {
1723  basegfx::B2DPolyPolygon aPolyPolygon;
1724 
1725  if (bEdgeTrackDirty)
1726  const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
1727 
1728  aPolyPolygon.append( pEdgeTrack->getB2DPolygon() );
1729 
1730  return aPolyPolygon;
1731 }
1732 
1733 sal_uInt32 SdrEdgeObj::GetHdlCount() const
1734 {
1735  SdrEdgeKind eKind=GetObjectItem(SDRATTR_EDGEKIND).GetValue();
1736  sal_uInt32 nHdlCnt(0);
1737  sal_uInt32 nPointCount(pEdgeTrack->GetPointCount());
1738 
1739  if(nPointCount)
1740  {
1741  nHdlCnt = 2;
1742  if ((eKind==SdrEdgeKind::OrthoLines || eKind==SdrEdgeKind::Bezier) && nPointCount >= 4)
1743  {
1744  sal_uInt32 nO1(aEdgeInfo.nObj1Lines > 0 ? aEdgeInfo.nObj1Lines - 1 : 0);
1745  sal_uInt32 nO2(aEdgeInfo.nObj2Lines > 0 ? aEdgeInfo.nObj2Lines - 1 : 0);
1746  sal_uInt32 nM(aEdgeInfo.nMiddleLine != 0xFFFF ? 1 : 0);
1747  nHdlCnt += nO1 + nO2 + nM;
1748  }
1749  else if (eKind==SdrEdgeKind::ThreeLines && nPointCount == 4)
1750  {
1751  if(GetConnectedNode(true))
1752  nHdlCnt++;
1753 
1754  if(GetConnectedNode(false))
1755  nHdlCnt++;
1756  }
1757  }
1758 
1759  return nHdlCnt;
1760 }
1761 
1763 {
1764  sal_uInt32 nPointCount(pEdgeTrack->GetPointCount());
1765  if (nPointCount==0)
1766  return;
1767 
1768  {
1769  std::unique_ptr<SdrHdl> pHdl(new ImpEdgeHdl((*pEdgeTrack)[0],SdrHdlKind::Poly));
1770  if (aCon1.pObj!=nullptr && aCon1.bBestVertex) pHdl->Set1PixMore();
1771  pHdl->SetPointNum(0);
1772  rHdlList.AddHdl(std::move(pHdl));
1773  }
1774  {
1775  std::unique_ptr<SdrHdl> pHdl(new ImpEdgeHdl((*pEdgeTrack)[sal_uInt16(nPointCount-1)],SdrHdlKind::Poly));
1776  if (aCon2.pObj!=nullptr && aCon2.bBestVertex) pHdl->Set1PixMore();
1777  pHdl->SetPointNum(1);
1778  rHdlList.AddHdl(std::move(pHdl));
1779  }
1780  {
1781  SdrEdgeKind eKind=GetObjectItem(SDRATTR_EDGEKIND).GetValue();
1782  if ((eKind==SdrEdgeKind::OrthoLines || eKind==SdrEdgeKind::Bezier) && nPointCount >= 4)
1783  {
1784  sal_uInt32 nO1(aEdgeInfo.nObj1Lines > 0 ? aEdgeInfo.nObj1Lines - 1 : 0);
1785  sal_uInt32 nO2(aEdgeInfo.nObj2Lines > 0 ? aEdgeInfo.nObj2Lines - 1 : 0);
1786  sal_uInt32 nM(aEdgeInfo.nMiddleLine != 0xFFFF ? 1 : 0);
1787  for(sal_uInt32 i = 0; i < (nO1 + nO2 + nM); ++i)
1788  {
1789  sal_Int32 nPt(0);
1790  sal_uInt32 nNum = i;
1791  std::unique_ptr<ImpEdgeHdl> pHdl(new ImpEdgeHdl(Point(),SdrHdlKind::Poly));
1792  if (nNum<nO1) {
1793  nPt=nNum+1;
1794  if (nNum==0) pHdl->SetLineCode(SdrEdgeLineCode::Obj1Line2);
1795  if (nNum==1) pHdl->SetLineCode(SdrEdgeLineCode::Obj1Line3);
1796  } else {
1797  nNum=nNum-nO1;
1798  if (nNum<nO2) {
1799  nPt=nPointCount-3-nNum;
1800  if (nNum==0) pHdl->SetLineCode(SdrEdgeLineCode::Obj2Line2);
1801  if (nNum==1) pHdl->SetLineCode(SdrEdgeLineCode::Obj2Line3);
1802  } else {
1803  nNum=nNum-nO2;
1804  if (nNum<nM) {
1805  nPt=aEdgeInfo.nMiddleLine;
1806  pHdl->SetLineCode(SdrEdgeLineCode::MiddleLine);
1807  }
1808  }
1809  }
1810  if (nPt>0) {
1811  Point aPos((*pEdgeTrack)[static_cast<sal_uInt16>(nPt)]);
1812  aPos+=(*pEdgeTrack)[static_cast<sal_uInt16>(nPt)+1];
1813  aPos.setX( aPos.X() / 2 );
1814  aPos.setY( aPos.Y() / 2 );
1815  pHdl->SetPos(aPos);
1816  pHdl->SetPointNum(i + 2);
1817  rHdlList.AddHdl(std::move(pHdl));
1818  }
1819  }
1820  }
1821  else if (eKind==SdrEdgeKind::ThreeLines && nPointCount == 4)
1822  {
1823  if(GetConnectedNode(true))
1824  {
1825  Point aPos((*pEdgeTrack)[1]);
1826  std::unique_ptr<ImpEdgeHdl> pHdl(new ImpEdgeHdl(aPos,SdrHdlKind::Poly));
1827  pHdl->SetLineCode(SdrEdgeLineCode::Obj1Line2);
1828  pHdl->SetPointNum(2);
1829  rHdlList.AddHdl(std::move(pHdl));
1830  }
1831  if(GetConnectedNode(false))
1832  {
1833  Point aPos((*pEdgeTrack)[2]);
1834  std::unique_ptr<ImpEdgeHdl> pHdl(new ImpEdgeHdl(aPos,SdrHdlKind::Poly));
1835  pHdl->SetLineCode(SdrEdgeLineCode::Obj2Line2);
1836  pHdl->SetPointNum(3);
1837  rHdlList.AddHdl(std::move(pHdl));
1838  }
1839  }
1840  }
1841 }
1842 
1844 {
1845  return true;
1846 }
1847 
1849 {
1850  // use Clone operator
1852 
1853  // copy connections for clone, SdrEdgeObj::operator= does not do this
1854  pRetval->ConnectToNode(true, GetConnectedNode(true));
1855  pRetval->ConnectToNode(false, GetConnectedNode(false));
1856 
1857  return SdrObjectUniquePtr(pRetval);
1858 }
1859 
1861 {
1862  if(!rDrag.GetHdl())
1863  return false;
1864 
1865  rDrag.SetEndDragChangesAttributes(true);
1866 
1867  if(rDrag.GetHdl()->GetPointNum() < 2)
1868  {
1869  rDrag.SetNoSnap();
1870  }
1871 
1872  return true;
1873 }
1874 
1876 {
1877  SdrEdgeObj* pOriginalEdge = dynamic_cast< SdrEdgeObj* >(rDragStat.GetHdl()->GetObj());
1878  const bool bOriginalEdgeModified(pOriginalEdge == this);
1879 
1880  if(!bOriginalEdgeModified && pOriginalEdge)
1881  {
1882  // copy connections when clone is modified. This is needed because
1883  // as preparation to this modification the data from the original object
1884  // was copied to the clone using the operator=. As can be seen there,
1885  // that operator does not copy the connections (for good reason)
1886  ConnectToNode(true, pOriginalEdge->GetConnection(true).GetObject());
1887  ConnectToNode(false, pOriginalEdge->GetConnection(false).GetObject());
1888  }
1889 
1890  if(rDragStat.GetHdl()->GetPointNum() < 2)
1891  {
1892  // start or end point connector drag
1893  const bool bDragA(0 == rDragStat.GetHdl()->GetPointNum());
1894  const Point aPointNow(rDragStat.GetNow());
1895 
1896  rDragStat.SetEndDragChangesGeoAndAttributes(true);
1897 
1898  if(rDragStat.GetPageView())
1899  {
1900  SdrObjConnection* pDraggedOne(bDragA ? &aCon1 : &aCon2);
1901 
1902  // clear connection
1903  DisconnectFromNode(bDragA);
1904 
1905  // look for new connection
1906  ImpFindConnector(aPointNow, *rDragStat.GetPageView(), *pDraggedOne, pOriginalEdge);
1907 
1908  if(pDraggedOne->pObj)
1909  {
1910  // if found, officially connect to it; ImpFindConnector only
1911  // sets pObj hard
1912  SdrObject* pNewConnection = pDraggedOne->pObj;
1913  pDraggedOne->pObj = nullptr;
1914  ConnectToNode(bDragA, pNewConnection);
1915  }
1916 
1917  if(rDragStat.GetView() && !bOriginalEdgeModified)
1918  {
1919  // show IA helper, but only do this during IA, so not when the original
1920  // Edge gets modified in the last call
1921  rDragStat.GetView()->SetConnectMarker(*pDraggedOne);
1922  }
1923  }
1924 
1925  if(pEdgeTrack)
1926  {
1927  // change pEdgeTrack to modified position
1928  if(bDragA)
1929  {
1930  (*pEdgeTrack)[0] = aPointNow;
1931  }
1932  else
1933  {
1934  (*pEdgeTrack)[sal_uInt16(pEdgeTrack->GetPointCount()-1)] = aPointNow;
1935  }
1936  }
1937 
1938  // reset edge info's offsets, this is an end point drag
1944  }
1945  else
1946  {
1947  // control point connector drag
1948  const ImpEdgeHdl* pEdgeHdl = static_cast<const ImpEdgeHdl*>(rDragStat.GetHdl());
1949  const SdrEdgeLineCode eLineCode = pEdgeHdl->GetLineCode();
1950  const Point aDist(rDragStat.GetNow() - rDragStat.GetStart());
1951  sal_Int32 nDist(pEdgeHdl->IsHorzDrag() ? aDist.X() : aDist.Y());
1952 
1953  nDist += aEdgeInfo.ImpGetLineOffset(eLineCode, *pEdgeTrack);
1954  aEdgeInfo.ImpSetLineOffset(eLineCode, *pEdgeTrack, nDist);
1955  }
1956 
1957  // force recalculation of EdgeTrack
1959  bEdgeTrackDirty=false;
1960 
1961  // save EdgeInfos and mark object as user modified
1963  bEdgeTrackUserDefined = false;
1964 
1965  SetRectsDirty();
1966 
1967  if(bOriginalEdgeModified && rDragStat.GetView())
1968  {
1969  // hide connect marker helper again when original gets changed.
1970  // This happens at the end of the interaction
1971  rDragStat.GetView()->HideConnectMarker();
1972  }
1973 
1974  return true;
1975 }
1976 
1978 {
1979  const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
1980 
1981  if(bCreateComment)
1982  {
1983  return OUString();
1984  }
1985  else
1986  {
1987  return ImpGetDescriptionStr(STR_DragEdgeTail);
1988  }
1989 }
1990 
1991 
1992 basegfx::B2DPolygon SdrEdgeObj::ImplAddConnectorOverlay(SdrDragMethod& rDragMethod, bool bTail1, bool bTail2, bool bDetail) const
1993 {
1994  basegfx::B2DPolygon aResult;
1995 
1996  if(bDetail)
1997  {
1998  SdrObjConnection aMyCon1(aCon1);
1999  SdrObjConnection aMyCon2(aCon2);
2000 
2001  if (bTail1)
2002  {
2003  const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aMyCon1.aObjOfs.X(), aMyCon1.aObjOfs.Y()));
2004  aMyCon1.aObjOfs.setX( basegfx::fround(aTemp.getX()) );
2005  aMyCon1.aObjOfs.setY( basegfx::fround(aTemp.getY()) );
2006  }
2007 
2008  if (bTail2)
2009  {
2010  const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aMyCon2.aObjOfs.X(), aMyCon2.aObjOfs.Y()));
2011  aMyCon2.aObjOfs.setX( basegfx::fround(aTemp.getX()) );
2012  aMyCon2.aObjOfs.setY( basegfx::fround(aTemp.getY()) );
2013  }
2014 
2015  SdrEdgeInfoRec aInfo(aEdgeInfo);
2016  XPolygon aXP(ImpCalcEdgeTrack(*pEdgeTrack, aMyCon1, aMyCon2, &aInfo));
2017 
2018  if(aXP.GetPointCount())
2019  {
2020  aResult = aXP.getB2DPolygon();
2021  }
2022  }
2023  else
2024  {
2025  Point aPt1((*pEdgeTrack)[0]);
2026  Point aPt2((*pEdgeTrack)[sal_uInt16(pEdgeTrack->GetPointCount() - 1)]);
2027 
2028  if (aCon1.pObj && (aCon1.bBestConn || aCon1.bBestVertex))
2029  aPt1 = aCon1.pObj->GetSnapRect().Center();
2030 
2031  if (aCon2.pObj && (aCon2.bBestConn || aCon2.bBestVertex))
2032  aPt2 = aCon2.pObj->GetSnapRect().Center();
2033 
2034  if (bTail1)
2035  {
2036  const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aPt1.X(), aPt1.Y()));
2037  aPt1.setX( basegfx::fround(aTemp.getX()) );
2038  aPt1.setY( basegfx::fround(aTemp.getY()) );
2039  }
2040 
2041  if (bTail2)
2042  {
2043  const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aPt2.X(), aPt2.Y()));
2044  aPt2.setX( basegfx::fround(aTemp.getX()) );
2045  aPt2.setY( basegfx::fround(aTemp.getY()) );
2046  }
2047 
2048  aResult.append(basegfx::B2DPoint(aPt1.X(), aPt1.Y()));
2049  aResult.append(basegfx::B2DPoint(aPt2.X(), aPt2.Y()));
2050  }
2051 
2052  return aResult;
2053 }
2054 
2056 {
2057  rDragStat.SetNoSnap();
2058  pEdgeTrack->SetPointCount(2);
2059  (*pEdgeTrack)[0]=rDragStat.GetStart();
2060  (*pEdgeTrack)[1]=rDragStat.GetNow();
2061  if (rDragStat.GetPageView()!=nullptr) {
2062  ImpFindConnector(rDragStat.GetStart(),*rDragStat.GetPageView(),aCon1,this);
2063  ConnectToNode(true,aCon1.pObj);
2064  }
2066  return true;
2067 }
2068 
2070 {
2071  sal_uInt16 nMax=pEdgeTrack->GetPointCount();
2072  (*pEdgeTrack)[nMax-1]=rDragStat.GetNow();
2073  if (rDragStat.GetPageView()!=nullptr) {
2074  ImpFindConnector(rDragStat.GetNow(),*rDragStat.GetPageView(),aCon2,this);
2075  rDragStat.GetView()->SetConnectMarker(aCon2);
2076  }
2078  bSnapRectDirty=true;
2079  ConnectToNode(false,aCon2.pObj);
2081  bEdgeTrackDirty=false;
2082  return true;
2083 }
2084 
2086 {
2087  bool bOk=(eCmd==SdrCreateCmd::ForceEnd || rDragStat.GetPointCount()>=2);
2088  if (bOk) {
2089  ConnectToNode(true,aCon1.pObj);
2090  ConnectToNode(false,aCon2.pObj);
2091  if (rDragStat.GetView()!=nullptr) {
2092  rDragStat.GetView()->HideConnectMarker();
2093  }
2094  ImpSetEdgeInfoToAttr(); // copy values from aEdgeInfo into the pool
2095  }
2096  SetRectsDirty();
2097  return bOk;
2098 }
2099 
2101 {
2102  if (rDragStat.GetView()!=nullptr) {
2103  rDragStat.GetView()->HideConnectMarker();
2104  }
2105  return false;
2106 }
2107 
2109 {
2110  if (rDragStat.GetView()!=nullptr) {
2111  rDragStat.GetView()->HideConnectMarker();
2112  }
2113 }
2114 
2116 {
2117  basegfx::B2DPolyPolygon aRetval;
2118  aRetval.append(pEdgeTrack->getB2DPolygon());
2119  return aRetval;
2120 }
2121 
2123 {
2124  return PointerStyle::DrawConnect;
2125 }
2126 
2127 bool SdrEdgeObj::ImpFindConnector(const Point& rPt, const SdrPageView& rPV, SdrObjConnection& rCon, const SdrEdgeObj* pThis, OutputDevice* pOut)
2128 {
2129  rCon.ResetVars();
2130  if (pOut==nullptr) pOut=rPV.GetView().GetFirstOutputDevice();
2131  if (pOut==nullptr) return false;
2132  SdrObjList* pOL=rPV.GetObjList();
2133  const SdrLayerIDSet& rVisLayer=rPV.GetVisibleLayers();
2134  // sensitive area of connectors is twice as large as the one of the handles
2135  sal_uInt16 nMarkHdSiz=rPV.GetView().GetMarkHdlSizePixel();
2136  Size aHalfConSiz(nMarkHdSiz,nMarkHdSiz);
2137  aHalfConSiz=pOut->PixelToLogic(aHalfConSiz);
2138  tools::Rectangle aMouseRect(rPt,rPt);
2139  aMouseRect.AdjustLeft( -(aHalfConSiz.Width()) );
2140  aMouseRect.AdjustTop( -(aHalfConSiz.Height()) );
2141  aMouseRect.AdjustRight(aHalfConSiz.Width() );
2142  aMouseRect.AdjustBottom(aHalfConSiz.Height() );
2143  sal_uInt16 nBoundHitTol=static_cast<sal_uInt16>(aHalfConSiz.Width())/2; if (nBoundHitTol==0) nBoundHitTol=1;
2144  size_t no=pOL->GetObjCount();
2145  bool bFnd = false;
2146  SdrObjConnection aTestCon;
2147 
2148  while (no>0 && !bFnd) {
2149  // issue: group objects on different layers return LayerID=0!
2150  no--;
2151  SdrObject* pObj=pOL->GetObj(no);
2152  if (rVisLayer.IsSet(pObj->GetLayer()) && pObj->IsVisible() && // only visible objects
2153  (pThis==nullptr || pObj!=static_cast<SdrObject const *>(pThis))) // don't connect it to itself
2154  {
2155  tools::Rectangle aObjBound(pObj->GetCurrentBoundRect());
2156  if (aObjBound.IsOver(aMouseRect)) {
2157  aTestCon.ResetVars();
2158  bool bEdge=dynamic_cast<const SdrEdgeObj *>(pObj) != nullptr; // no BestCon for Edge
2159  // User-defined connectors have absolute priority.
2160  // After those come Vertex, Corner and center (Best), all prioritized equally.
2161  // Finally, a HitTest for the object.
2162  const SdrGluePointList* pGPL=pObj->GetGluePointList();
2163  sal_uInt16 nGluePointCnt=pGPL==nullptr ? 0 : pGPL->GetCount();
2164  sal_uInt16 nGesAnz=nGluePointCnt+9;
2165  bool bUserFnd = false;
2166  sal_uIntPtr nBestDist=0xFFFFFFFF;
2167  for (sal_uInt16 i=0; i<nGesAnz; i++)
2168  {
2169  bool bUser=i<nGluePointCnt;
2170  bool bVertex=i>=nGluePointCnt+0 && i<nGluePointCnt+4;
2171  bool bCorner=i>=nGluePointCnt+4 && i<nGluePointCnt+8;
2172  bool bCenter=i==nGluePointCnt+8;
2173  bool bOk = false;
2174  Point aConPos;
2175  sal_uInt16 nConNum=i;
2176  if (bUser) {
2177  const SdrGluePoint& rGP=(*pGPL)[nConNum];
2178  aConPos=rGP.GetAbsolutePos(*pObj);
2179  nConNum=rGP.GetId();
2180  bOk = true;
2181  } else if (bVertex && !bUserFnd) {
2182  nConNum=nConNum-nGluePointCnt;
2183  SdrGluePoint aPt(pObj->GetVertexGluePoint(nConNum));
2184  aConPos=aPt.GetAbsolutePos(*pObj);
2185  bOk = true;
2186  } else if (bCorner && !bUserFnd) {
2187  nConNum-=nGluePointCnt+4;
2188  i+=3;
2189  }
2190  else if (bCenter && !bUserFnd && !bEdge)
2191  {
2192  // Suppress default connect at object center
2193  if(!pThis || !pThis->GetSuppressDefaultConnect())
2194  {
2195  // not the edges!
2196  nConNum=0;
2197  aConPos=aObjBound.Center();
2198  bOk = true;
2199  }
2200  }
2201  if (bOk && aMouseRect.IsInside(aConPos)) {
2202  if (bUser) bUserFnd = true;
2203  bFnd = true;
2204  sal_uIntPtr nDist=static_cast<sal_uIntPtr>(std::abs(aConPos.X()-rPt.X()))+static_cast<sal_uIntPtr>(std::abs(aConPos.Y()-rPt.Y()));
2205  if (nDist<nBestDist) {
2206  nBestDist=nDist;
2207  aTestCon.pObj=pObj;
2208  aTestCon.nConId=nConNum;
2209  aTestCon.bAutoCorner=bCorner;
2210  aTestCon.bAutoVertex=bVertex;
2211  aTestCon.bBestConn=false; // bCenter;
2212  aTestCon.bBestVertex=bCenter;
2213  }
2214  }
2215  }
2216  // if no connector is hit, try HitTest again, for BestConnector (=bCenter)
2217  if(!bFnd &&
2218  !bEdge &&
2219  SdrObjectPrimitiveHit(*pObj, rPt, nBoundHitTol, rPV, &rVisLayer, false))
2220  {
2221  // Suppress default connect at object inside bound
2222  if(!pThis || !pThis->GetSuppressDefaultConnect())
2223  {
2224  bFnd = true;
2225  aTestCon.pObj=pObj;
2226  aTestCon.bBestConn=true;
2227  }
2228  }
2229  if (bFnd) {
2230  aMouseRect.AdjustLeft( -nBoundHitTol );
2231  aMouseRect.AdjustTop( -nBoundHitTol );
2232  aMouseRect.AdjustRight(nBoundHitTol );
2233  aMouseRect.AdjustBottom(nBoundHitTol );
2234  }
2235 
2236  }
2237  }
2238  }
2239  rCon=aTestCon;
2240  return bFnd;
2241 }
2242 
2244 {
2245  const tools::Rectangle aOld(GetSnapRect());
2246 
2247  if(aOld == rRect)
2248  return;
2249 
2250  if (maRect.IsEmpty() && 0 == pEdgeTrack->GetPointCount())
2251  {
2252  // #i110629# When initializing, do not scale on empty Rectangle; this
2253  // will mirror the underlying text object (!)
2254  maRect = rRect;
2255  maSnapRect = rRect;
2256  }
2257  else
2258  {
2259  long nMulX = rRect.Right() - rRect.Left();
2260  long nDivX = aOld.Right() - aOld.Left();
2261  long nMulY = rRect.Bottom() - rRect.Top();
2262  long nDivY = aOld.Bottom() - aOld.Top();
2263  if ( nDivX == 0 ) { nMulX = 1; nDivX = 1; }
2264  if ( nDivY == 0 ) { nMulY = 1; nDivY = 1; }
2265  Fraction aX(nMulX, nDivX);
2266  Fraction aY(nMulY, nDivY);
2267  NbcResize(aOld.TopLeft(), aX, aY);
2268  NbcMove(Size(rRect.Left() - aOld.Left(), rRect.Top() - aOld.Top()));
2269  }
2270 }
2271 
2272 void SdrEdgeObj::NbcMove(const Size& rSiz)
2273 {
2274  SdrTextObj::NbcMove(rSiz);
2275  MoveXPoly(*pEdgeTrack,rSiz);
2276 }
2277 
2278 void SdrEdgeObj::NbcResize(const Point& rRefPnt, const Fraction& aXFact, const Fraction& aYFact)
2279 {
2280  SdrTextObj::NbcResize(rRefPnt,aXFact,aXFact);
2281  ResizeXPoly(*pEdgeTrack,rRefPnt,aXFact,aYFact);
2282 
2283  // if resize is not from paste, forget user distances
2284  if (!getSdrModelFromSdrObject().IsPasteResize())
2285  {
2291  }
2292 }
2293 
2294 // #i54102# added rotation support
2295 void SdrEdgeObj::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
2296 {
2298  {
2299  // #i120437# special handling when track is imported, apply
2300  // transformation directly to imported track.
2301  SdrTextObj::NbcRotate(rRef, nAngle, sn, cs);
2302  RotateXPoly(*pEdgeTrack, rRef, sn, cs);
2303  }
2304  else
2305  {
2306  // handle start and end point if not connected
2307  const bool bCon1(nullptr != aCon1.pObj && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2308  const bool bCon2(nullptr != aCon2.pObj && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2309 
2310  if(!bCon1 && pEdgeTrack)
2311  {
2312  RotatePoint((*pEdgeTrack)[0],rRef,sn,cs);
2314  }
2315 
2316  if(!bCon2 && pEdgeTrack)
2317  {
2318  sal_uInt16 nPointCount = pEdgeTrack->GetPointCount();
2319  RotatePoint((*pEdgeTrack)[sal_uInt16(nPointCount-1)],rRef,sn,cs);
2321  }
2322  }
2323 }
2324 
2325 // #i54102# added mirror support
2326 void SdrEdgeObj::NbcMirror(const Point& rRef1, const Point& rRef2)
2327 {
2329  {
2330  // #i120437# special handling when track is imported, apply
2331  // transformation directly to imported track.
2332  SdrTextObj::NbcMirror(rRef1, rRef2);
2333  MirrorXPoly(*pEdgeTrack, rRef1, rRef2);
2334  }
2335  else
2336  {
2337  // handle start and end point if not connected
2338  const bool bCon1(nullptr != aCon1.pObj && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2339  const bool bCon2(nullptr != aCon2.pObj && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2340 
2341  if(!bCon1 && pEdgeTrack)
2342  {
2343  MirrorPoint((*pEdgeTrack)[0],rRef1,rRef2);
2345  }
2346 
2347  if(!bCon2 && pEdgeTrack)
2348  {
2349  sal_uInt16 nPointCount = pEdgeTrack->GetPointCount();
2350  MirrorPoint((*pEdgeTrack)[sal_uInt16(nPointCount-1)],rRef1,rRef2);
2352  }
2353  }
2354 }
2355 
2356 // #i54102# added shear support
2357 void SdrEdgeObj::NbcShear(const Point& rRef, long nAngle, double tn, bool bVShear)
2358 {
2360  {
2361  // #i120437# special handling when track is imported, apply
2362  // transformation directly to imported track.
2363  SdrTextObj::NbcShear(rRef, nAngle, tn, bVShear);
2364  ShearXPoly(*pEdgeTrack, rRef, tn, bVShear);
2365  }
2366  else
2367  {
2368  // handle start and end point if not connected
2369  const bool bCon1(nullptr != aCon1.pObj && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2370  const bool bCon2(nullptr != aCon2.pObj && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2371 
2372  if(!bCon1 && pEdgeTrack)
2373  {
2374  ShearPoint((*pEdgeTrack)[0],rRef,tn,bVShear);
2376  }
2377 
2378  if(!bCon2 && pEdgeTrack)
2379  {
2380  sal_uInt16 nPointCount = pEdgeTrack->GetPointCount();
2381  ShearPoint((*pEdgeTrack)[sal_uInt16(nPointCount-1)],rRef,tn,bVShear);
2383  }
2384  }
2385 }
2386 
2387 SdrObjectUniquePtr SdrEdgeObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
2388 {
2389  basegfx::B2DPolyPolygon aPolyPolygon;
2390  aPolyPolygon.append(pEdgeTrack->getB2DPolygon());
2391  SdrObjectUniquePtr pRet = ImpConvertMakeObj(aPolyPolygon, false, bBezier);
2392 
2393  if(bAddText)
2394  {
2395  pRet = ImpConvertAddText(std::move(pRet), bBezier);
2396  }
2397 
2398  return pRet;
2399 }
2400 
2402 {
2403  return 2;
2404 }
2405 
2406 Point SdrEdgeObj::GetSnapPoint(sal_uInt32 i) const
2407 {
2408  const_cast<SdrEdgeObj*>(this)->ImpUndirtyEdgeTrack();
2409  sal_uInt16 nCount=pEdgeTrack->GetPointCount();
2410  if (i==0) return (*pEdgeTrack)[0];
2411  else return (*pEdgeTrack)[nCount-1];
2412 }
2413 
2415 {
2416  return false;
2417 }
2418 
2419 sal_uInt32 SdrEdgeObj::GetPointCount() const
2420 {
2421  return 0;
2422 }
2423 
2424 Point SdrEdgeObj::GetPoint(sal_uInt32 i) const
2425 {
2426  const_cast<SdrEdgeObj*>(this)->ImpUndirtyEdgeTrack();
2427  sal_uInt16 nCount=pEdgeTrack->GetPointCount();
2428  if (0 == i)
2429  return (*pEdgeTrack)[0];
2430  else
2431  return (*pEdgeTrack)[nCount-1];
2432 }
2433 
2434 void SdrEdgeObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
2435 {
2436  // TODO: Need an implementation to connect differently.
2438  sal_uInt16 nCount=pEdgeTrack->GetPointCount();
2439  if (0 == i)
2440  (*pEdgeTrack)[0]=rPnt;
2441  if (1 == i)
2442  (*pEdgeTrack)[nCount-1]=rPnt;
2444  SetRectsDirty();
2445 }
2446 
2448  : pEdgeTrack(new XPolygon)
2449  , bEdgeTrackDirty(false)
2450  , bEdgeTrackUserDefined(false)
2451 {
2452 }
2453 
2455 {
2456 }
2457 
2459 {
2460  return new SdrEdgeObjGeoData;
2461 }
2462 
2464 {
2466  SdrEdgeObjGeoData& rEGeo=static_cast<SdrEdgeObjGeoData&>(rGeo);
2467  rEGeo.aCon1 =aCon1;
2468  rEGeo.aCon2 =aCon2;
2469  *rEGeo.pEdgeTrack =*pEdgeTrack;
2472  rEGeo.aEdgeInfo =aEdgeInfo;
2473 }
2474 
2476 {
2478  const SdrEdgeObjGeoData& rEGeo=static_cast<const SdrEdgeObjGeoData&>(rGeo);
2479  if (aCon1.pObj!=rEGeo.aCon1.pObj) {
2480  if (aCon1.pObj!=nullptr) aCon1.pObj->RemoveListener(*this);
2481  aCon1=rEGeo.aCon1;
2482  if (aCon1.pObj!=nullptr) aCon1.pObj->AddListener(*this);
2483  }
2484  else
2485  aCon1=rEGeo.aCon1;
2486 
2487  if (aCon2.pObj!=rEGeo.aCon2.pObj) {
2488  if (aCon2.pObj!=nullptr) aCon2.pObj->RemoveListener(*this);
2489  aCon2=rEGeo.aCon2;
2490  if (aCon2.pObj!=nullptr) aCon2.pObj->AddListener(*this);
2491  }
2492  else
2493  aCon2=rEGeo.aCon2;
2494 
2495  *pEdgeTrack =*rEGeo.pEdgeTrack;
2498  aEdgeInfo =rEGeo.aEdgeInfo;
2499 }
2500 
2501 Point SdrEdgeObj::GetTailPoint( bool bTail ) const
2502 {
2503  if( pEdgeTrack && pEdgeTrack->GetPointCount()!=0)
2504  {
2505  const XPolygon& rTrack0 = *pEdgeTrack;
2506  if(bTail)
2507  {
2508  return rTrack0[0];
2509  }
2510  else
2511  {
2512  const sal_uInt16 nSiz = rTrack0.GetPointCount() - 1;
2513  return rTrack0[nSiz];
2514  }
2515  }
2516  else
2517  {
2518  if(bTail)
2519  return aOutRect.TopLeft();
2520  else
2521  return aOutRect.BottomRight();
2522  }
2523 
2524 }
2525 
2526 void SdrEdgeObj::SetTailPoint( bool bTail, const Point& rPt )
2527 {
2528  ImpSetTailPoint( bTail, rPt );
2529  SetChanged();
2530 }
2531 
2537 void SdrEdgeObj::setGluePointIndex( bool bTail, sal_Int32 nIndex /* = -1 */ )
2538 {
2539  tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetCurrentBoundRect();
2540 
2541  SdrObjConnection& rConn1 = GetConnection( bTail );
2542 
2543  rConn1.SetAutoVertex( nIndex >= 0 && nIndex <= 3 );
2544  rConn1.SetBestConnection( nIndex < 0 );
2545  rConn1.SetBestVertex( nIndex < 0 );
2546 
2547  if( nIndex > 3 )
2548  {
2549  nIndex -= 3; // the start api index is 0, whereas the implementation in svx starts from 1
2550 
2551  // for user defined glue points we have
2552  // to get the id for this index first
2553  const SdrGluePointList* pList = rConn1.GetObject() ? rConn1.GetObject()->GetGluePointList() : nullptr;
2554  if( pList == nullptr || SDRGLUEPOINT_NOTFOUND == pList->FindGluePoint(static_cast<sal_uInt16>(nIndex)) )
2555  return;
2556  }
2557  else if( nIndex < 0 )
2558  {
2559  nIndex = 0;
2560  }
2561 
2562  rConn1.SetConnectorId( static_cast<sal_uInt16>(nIndex) );
2563 
2564  SetChanged();
2565  SetRectsDirty();
2567 }
2568 
2571 sal_Int32 SdrEdgeObj::getGluePointIndex( bool bTail )
2572 {
2573  SdrObjConnection& rConn1 = GetConnection( bTail );
2574  sal_Int32 nId = -1;
2575  if( !rConn1.IsBestConnection() )
2576  {
2577  nId = rConn1.GetConnectorId();
2578  if( !rConn1.IsAutoVertex() )
2579  nId += 3; // the start api index is 0, whereas the implementation in svx starts from 1
2580  }
2581  return nId;
2582 }
2583 
2584 // Implementation was missing; edge track needs to be invalidated additionally.
2585 void SdrEdgeObj::NbcSetAnchorPos(const Point& rPnt)
2586 {
2587  // call parent functionality
2589 
2590  // Additionally, invalidate edge track
2592 }
2593 
2595 {
2596  // use base method from SdrObject, it's not rotatable and
2597  // a call to GetSnapRect() is used. That's what we need for Connector.
2598  return SdrObject::TRGetBaseGeometry(rMatrix, rPolyPolygon);
2599 }
2600 
2602 {
2603  // where appropriate take care for existing connections. For now, just use the
2604  // implementation from SdrObject.
2605  SdrObject::TRSetBaseGeometry(rMatrix, rPolyPolygon);
2606 }
2607 
2608 // for geometry access
2610 {
2611  if(bEdgeTrackDirty)
2612  {
2613  const_cast< SdrEdgeObj* >(this)->ImpRecalcEdgeTrack();
2614  }
2615 
2616  if(pEdgeTrack)
2617  {
2618  return pEdgeTrack->getB2DPolygon();
2619  }
2620  else
2621  {
2622  return ::basegfx::B2DPolygon();
2623  }
2624 }
2625 
2626 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Point TopLeft() const
virtual void ClearObjectItemDirect(const sal_uInt16 nWhich)=0
virtual void NbcSetAnchorPos(const Point &rPnt) override
Definition: svdoedge.cxx:2585
long ImpGetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon &rXP) const
Definition: svdoedge.cxx:129
virtual OUString TakeObjNameSingul() const override
Definition: svdoedge.cxx:1664
Point aMiddleLine
Definition: svdoedge.hxx:84
Point aObj2Line2
Definition: svdoedge.hxx:82
virtual bool BegCreate(SdrDragStat &rStat) override
Every object must be able to create itself interactively.
Definition: svdoedge.cxx:2055
SfxHintId
virtual void NbcResize(const Point &rRef, const Fraction &xFact, const Fraction &yFact) override
Definition: svdotxtr.cxx:102
void ShearXPoly(XPolygon &rPoly, const Point &rRef, double tn, bool bVShear)
Definition: svdtrans.cxx:154
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
Utility class SdrObjConnection.
Definition: svdoedge.hxx:38
SdrPageView * GetPageView() const
Definition: svddrag.hxx:88
SdrHintKind GetKind() const
Definition: svdmodel.hxx:123
virtual SdrGluePoint GetCornerGluePoint(sal_uInt16 nNum) const override
Definition: svdoedge.cxx:433
virtual const tools::Rectangle & GetCurrentBoundRect() const
Definition: svdobj.cxx:854
void ImpRecalcEdgeTrack()
Definition: svdoedge.cxx:543
virtual void SetObjectItemDirect(const SfxPoolItem &rItem)=0
virtual ~SdrEdgeObj() override
Definition: svdoedge.cxx:170
void ShearPoint(Point &rPnt, const Point &rRef, double tn, bool bVShear=false)
Definition: svdtrans.hxx:122
void SetAutoVertex(bool rB)
Definition: svdoedge.hxx:61
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
SdrObjUserCall * pUserCall
Definition: svdobj.hxx:927
virtual const SdrGluePointList * GetGluePointList() const override
Definition: svdoedge.cxx:438
virtual bool IsPolyObj() const override
Definition: svdoedge.cxx:2414
SdrObjConnection aCon2
Definition: svdoedge.hxx:115
void ImpSetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon &rXP, long nVal)
Definition: svdoedge.cxx:122
::basegfx::B2DPolygon getEdgeTrack() const
Definition: svdoedge.cxx:2609
const Point & GetStart() const
Definition: svddrag.hxx:92
SdrEscapeDirection
Definition: svdglue.hxx:35
SdrView & GetView()
Definition: svdpagv.hxx:135
int n1
virtual SdrObjectUniquePtr DoConvertToPolyObj(bool bBezier, bool bAddText) const override
Definition: svdoedge.cxx:2387
sal_uInt16 nNotifyingCount
Definition: svdoedge.hxx:145
void ResizeXPoly(XPolygon &rPoly, const Point &rRef, const Fraction &xFact, const Fraction &yFact)
Definition: svdtrans.cxx:72
sal_uInt16 nMiddleLine
Definition: svdoedge.hxx:91
Utility class SdrEdgeInfoRec.
Definition: svdoedge.hxx:74
sal_uInt16 nObj2Lines
Definition: svdoedge.hxx:90
virtual basegfx::B2DPolyPolygon TakeCreatePoly(const SdrDragStat &rDrag) const override
Polygon dragged by the user when creating the object.
Definition: svdoedge.cxx:2115
bool ImpCanConvTextToCurve() const
Definition: svdotxtr.cxx:424
constexpr TypedWhichId< SdrEdgeNode1HorzDistItem > SDRATTR_EDGENODE1HORZDIST(SDRATTR_EDGE_FIRST+1)
bool IsHorzDrag() const
Definition: svdhdl.cxx:1692
SdrMetricItem makeSdrEdgeLine3DeltaItem(long nVal)
Definition: sxelditm.hxx:42
std::unique_ptr< XPolygon > pEdgeTrack
Definition: svdoedge.hxx:116
double getX() const
sal_Int64 n
SdrObject * GetObj(size_t nNum) const
Definition: svdpage.cxx:758
bool IsInserted() const
Definition: svdobj.hxx:794
size_t GetObjCount() const
Definition: svdpage.cxx:752
sal_uInt32 GetPointNum() const
Definition: svdhdl.hxx:222
virtual void SetBoundRectDirty()
Definition: svdobj.cxx:310
bool bEdgeTrackUserDefined
Definition: svdoedge.hxx:118
virtual bool MovCreate(SdrDragStat &rStat) override
Definition: svdoedge.cxx:2069
sal_Int16 nId
void ImpSetEdgeInfoToAttr()
Definition: svdoedge.cxx:260
virtual bool TRGetBaseGeometry(basegfx::B2DHomMatrix &rMatrix, basegfx::B2DPolyPolygon &rPolyPolygon) const override
Definition: svdoedge.cxx:2594
SdrEdgeInfoRec aEdgeInfo
Definition: svdoedge.hxx:146
double getY() const
SdrObject * GetObj() const
Definition: svdhdl.hxx:203
constexpr TypedWhichId< SdrEdgeNode2VertDistItem > SDRATTR_EDGENODE2VERTDIST(SDRATTR_EDGE_FIRST+4)
SdrObjectUniquePtr ImpConvertAddText(SdrObjectUniquePtr pObj, bool bBezier) const
Definition: svdotxtr.cxx:463
virtual void NbcSetSnapRect(const tools::Rectangle &rRect) override
Definition: svdoedge.cxx:2243
const SfxBroadcaster * GetBroadcaster() const
Definition: svdobj.cxx:627
OLE object.
Definition: svdobj.hxx:139
void ResetVars()
Definition: svdoedge.cxx:47
virtual OUString TakeObjNamePlural() const override
Definition: svdoedge.cxx:1679
virtual std::unique_ptr< sdr::properties::BaseProperties > CreateObjectSpecificProperties() override
Definition: svdoedge.cxx:141
sal_uInt16 GetCount() const
Definition: svdglue.hxx:125
virtual sdr::properties::BaseProperties & GetProperties() const
Definition: svdobj.cxx:204
virtual const tools::Rectangle & GetSnapRect() const override
Definition: svdoattr.cxx:48
All geometrical data of an arbitrary object for use in undo/redo.
Definition: svdobj.hxx:227
bool bEdgeTrackUserDefined
Definition: svdoedge.hxx:149
void AddListener(SfxListener &rListener)
Definition: svdobj.cxx:606
SfxHintId GetId() const
basegfx::B2DPolygon ImplAddConnectorOverlay(SdrDragMethod &rDragMethod, bool bTail1, bool bTail2, bool bDetail) const
Definition: svdoedge.cxx:1992
constexpr TypedWhichId< SdrEdgeLineDeltaCountItem > SDRATTR_EDGELINEDELTACOUNT(SDRATTR_EDGE_FIRST+7)
virtual bool HasText() const override
Definition: svdotxat.cxx:412
void ConnectToNode(bool bTail1, SdrObject *pObj) override
Definition: svdoedge.cxx:448
virtual std::unique_ptr< sdr::contact::ViewContact > CreateObjectSpecificViewContact() override
Definition: svdoedge.cxx:149
virtual void BrkCreate(SdrDragStat &rStat) override
Definition: svdoedge.cxx:2108
bool bEdgeTrackDirty
Definition: svdoedge.hxx:148
bool bSnapRectDirty
Definition: svdobj.hxx:932
virtual void NbcMirror(const Point &rRef1, const Point &rRef2) override
Definition: svdotxtr.cxx:232
virtual const tools::Rectangle & GetSnapRect() const
Definition: svdobj.cxx:1598
void ImpUndirtyEdgeTrack()
Definition: svdoedge.cxx:535
bool IsVisible() const
Definition: svdobj.hxx:806
bool IsEmpty() const
sal_uInt16 GetConnectorId() const
Definition: svdoedge.hxx:66
sal_uInt16 GetId() const
Definition: svdglue.hxx:86
Provides information about various ZObject properties.
Definition: svdobj.hxx:249
const SdrHdl * GetHdl() const
Definition: svddrag.hxx:101
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
constexpr TypedWhichId< SdrEdgeKindItem > SDRATTR_EDGEKIND(SDRATTR_EDGE_FIRST+0)
basegfx::B2DPolyPolygon GetEdgeTrackPath() const
Definition: svdoedge.cxx:1721
void ImpSetTailPoint(bool bTail1, const Point &rPt)
Definition: svdoedge.cxx:512
int n2
Point aObj2Line3
Definition: svdoedge.hxx:83
virtual basegfx::B2DHomMatrix getCurrentTransformation()
Definition: svddrgmt.cxx:660
tools::Long Left() const
SdrPage * getSdrPageFromSdrObject() const
Definition: svdobj.cxx:263
virtual SdrGluePoint GetVertexGluePoint(sal_uInt16 nNum) const
Definition: svdobj.cxx:2167
OUString SvxResId(const char *pId)
Definition: dialmgr.cxx:28
virtual PointerStyle GetCreatePointer() const override
get the cursor/pointer that signals creating this object
Definition: svdoedge.cxx:2122
#define X
virtual void SaveGeoData(SdrObjGeoData &rGeo) const override
Definition: svdotext.cxx:1440
int nCount
tools::Long Bottom() const
const SfxItemSet & GetObjectItemSet() const
Definition: svdobj.cxx:1885
virtual void NbcSetPoint(const Point &rPnt, sal_uInt32 i) override
Definition: svdoedge.cxx:2434
SdrObject * SdrObjectPrimitiveHit(const SdrObject &rObject, const Point &rPnt, sal_uInt16 nTol, const SdrPageView &rSdrPageView, const SdrLayerIDSet *pVisiLayer, bool bTextOnly, drawinglayer::primitive2d::Primitive2DContainer *pHitContainer)
tools::Rectangle maRect
Definition: svdotext.hxx:182
SdrEdgeObj & operator=(const SdrEdgeObj &rObj)
Definition: svdoedge.cxx:1649
void setGluePointIndex(bool bTail, sal_Int32 nId=-1)
this method is used by the api to set a glue point for a connection nId == -1 : The best default poin...
Definition: svdoedge.cxx:2537
bool bClosedObj
Definition: svdobj.hxx:945
void ImpSetAttrToEdgeInfo()
Definition: svdoedge.cxx:190
virtual void NbcRotate(const Point &rRef, long nAngle, double sn, double cs) override
Definition: svdoedge.cxx:2295
SdrObjConnection aCon1
Definition: svdoedge.hxx:114
OutputDevice * GetFirstOutputDevice() const
Definition: svdpntv.cxx:87
bool TakeGluePoint(SdrGluePoint &rGP) const
Definition: svdoedge.cxx:57
Utility class SdrEdgeObjGeoData.
Definition: svdoedge.hxx:111
tools::Rectangle maSnapRect
Definition: svdoattr.hxx:42
SdrObject * GetObject() const
Definition: svdoedge.hxx:67
#define XPOLY_APPEND
Definition: xpoly.hxx:37
SdrEdgeLineCode
Definition: svdoedge.hxx:71
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
void setX(tools::Long x)
B2IRange fround(const B2DRange &rRange)
bool ImpIsHorzLine(SdrEdgeLineCode eLineCode, const XPolygon &rXP) const
Definition: svdoedge.cxx:110
SdrEdgeObj(SdrModel &rSdrModel)
Definition: svdoedge.cxx:155
SdrObject * GetConnectedNode(bool bTail1) const override
Definition: svdoedge.cxx:472
virtual SdrEdgeObj * CloneSdrObject(SdrModel &rTargetModel) const override
Definition: svdoedge.cxx:1644
virtual const tools::Rectangle & GetCurrentBoundRect() const override
Definition: svdoedge.cxx:375
virtual bool BckCreate(SdrDragStat &rStat) override
Definition: svdoedge.cxx:2100
SdrEscapeDirection GetEscDir() const
Definition: svdglue.hxx:84
void SetBestVertex(bool rB)
Definition: svdoedge.hxx:60
SdrObjList * GetObjList() const
Return current List.
Definition: svdpagv.hxx:174
virtual void NbcMirror(const Point &rRef1, const Point &rRef2) override
Definition: svdoedge.cxx:2326
constexpr TypedWhichId< SdrMetricItem > SDRATTR_EDGELINE3DELTA(SDRATTR_EDGE_FIRST+10)
Point BottomRight() const
const SfxPoolItem & GetObjectItem(const sal_uInt16 nWhich) const
Definition: svdobj.cxx:1920
constexpr TypedWhichId< SdrEdgeNode2HorzDistItem > SDRATTR_EDGENODE2HORZDIST(SDRATTR_EDGE_FIRST+3)
const SdrLayerIDSet & GetVisibleLayers() const
Definition: svdpagv.hxx:215
void SetNoSnap(bool bOn=true)
Definition: svddrag.hxx:121
virtual void handlePageChange(SdrPage *pOldPage, SdrPage *pNewPage) override
Definition: svdotext.cxx:442
void SetEndDragChangesGeoAndAttributes(bool bOn)
Definition: svddrag.hxx:135
virtual const SdrGluePointList * GetGluePointList() const
Definition: svdobj.cxx:2204
bool mbSuppressed
Definition: svdoedge.hxx:164
virtual void TakeUnrotatedSnapRect(tools::Rectangle &rRect) const override
Definition: svdoedge.cxx:400
virtual SdrGluePointList * ForceGluePointList() override
Definition: svdoedge.cxx:443
SdrEdgeLineCode GetLineCode() const
Definition: svdhdl.hxx:397
int i
void MirrorXPoly(XPolygon &rPoly, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:138
#define SDRGLUEPOINT_NOTFOUND
Definition: svdglue.hxx:116
virtual Point GetPoint(sal_uInt32 i) const override
Definition: svdoedge.cxx:2424
constexpr TypedWhichId< SdrEdgeNode1VertDistItem > SDRATTR_EDGENODE1VERTDIST(SDRATTR_EDGE_FIRST+2)
Point GetTailPoint(bool bTail) const
Definition: svdoedge.cxx:2501
OUString sName
SdrObject * GetCreateObj() const
Definition: svdcrtv.hxx:116
sal_uInt16 nObj1Lines
Definition: svdoedge.hxx:89
virtual void handlePageChange(SdrPage *pOldPage, SdrPage *pNewPage) override
Definition: svdoedge.cxx:176
virtual void TRSetBaseGeometry(const basegfx::B2DHomMatrix &rMatrix, const basegfx::B2DPolyPolygon &rPolyPolygon)
Definition: svdobj.cxx:2915
tools::Rectangle aOutRect
Definition: svdobj.hxx:925
void DisconnectFromNode(bool bTail1) override
Definition: svdoedge.cxx:463
SdrPathObjUniquePtr ImpConvertMakeObj(const basegfx::B2DPolyPolygon &rPolyPolygon, bool bClosed, bool bBezier) const
Definition: svdotxtr.cxx:429
void ImpDirtyEdgeTrack()
Definition: svdoedge.cxx:529
sal_Int32 GetPointCount() const
Definition: svddrag.hxx:91
void MirrorPoint(Point &rPnt, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:104
SdrTextObj & operator=(const SdrTextObj &rObj)
Definition: svdotext.cxx:1007
void ActionChanged() const
Definition: svdobj.cxx:257
SdrView * GetView() const
Definition: svddrag.hxx:86
virtual ~SdrEdgeObjGeoData() override
Definition: svdoedge.cxx:2454
basegfx::B2DPolygon getB2DPolygon() const
Definition: _xpoly.cxx:815
tools::Long Width() const
virtual bool hasSpecialDrag() const override
The standard transformations (Move,Resize,Rotate,Mirror,Shear) are taken over by the View (TakeXorPol...
Definition: svdoedge.cxx:1843
SdrEdgeKind
Definition: sxekitm.hxx:26
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:273
virtual void NbcResize(const Point &rRefPnt, const Fraction &aXFact, const Fraction &aYFact) override
Definition: svdoedge.cxx:2278
void SetPercent(bool bOn)
Definition: svdglue.hxx:89
SdrObjConnection aCon2
Definition: svdoedge.hxx:142
bool IsInside(const Point &rPOINT) const
Point aObj1Line3
Definition: svdoedge.hxx:81
void SetConnectorId(sal_uInt16 nId)
Definition: svdoedge.hxx:62
virtual basegfx::B2DPolyPolygon TakeXorPoly() const override
The Xor-Polygon is required by the View to drag the object.
Definition: svdoedge.cxx:1684
virtual void NbcMove(const Size &rSiz) override
The methods Move, Resize, Rotate, Mirror, Shear, SetSnapRect and SetLogicRect call the corresponding ...
Definition: svdotxtr.cxx:94
void Reformat()
updates edges that are connected to the edges of this object as if the connected objects send a repai...
Definition: svdoedge.cxx:1629
bool IsAutoVertex() const
Definition: svdoedge.hxx:65
void SetEndDragChangesAttributes(bool bOn)
Definition: svddrag.hxx:133
void SetTailPoint(bool bTail, const Point &rPt)
Definition: svdoedge.cxx:2526
virtual bool beginSpecialDrag(SdrDragStat &rDrag) const override
Definition: svdoedge.cxx:1860
virtual sal_uInt32 GetSnapPointCount() const override
snap to special points of an Object (polygon points, center of circle)
Definition: svdoedge.cxx:2401
bool CheckNodeConnection(bool bTail1) const
Definition: svdoedge.cxx:485
static bool ImpFindConnector(const Point &rPt, const SdrPageView &rPV, SdrObjConnection &rCon, const SdrEdgeObj *pThis, OutputDevice *pOut=nullptr)
Definition: svdoedge.cxx:2127
tools::Long Top() const
Abstract DrawObject.
Definition: svdobj.hxx:313
void SetBestConnection(bool rB)
Definition: svdoedge.hxx:59
virtual void NbcMove(const Size &aSize) override
The methods Move, Resize, Rotate, Mirror, Shear, SetSnapRect and SetLogicRect call the corresponding ...
Definition: svdoedge.cxx:2272
SdrObjConnection & GetConnection(bool bTail1)
Definition: svdoedge.hxx:197
virtual void TRSetBaseGeometry(const basegfx::B2DHomMatrix &rMatrix, const basegfx::B2DPolyPolygon &rPolyPolygon) override
Definition: svdoedge.cxx:2601
Point & ImpGetLineOffsetPoint(SdrEdgeLineCode eLineCode)
Definition: svdoedge.cxx:86
Point GetAbsolutePos(const SdrObject &rObj) const
Definition: svdglue.cxx:47
OUString GetName() const
Definition: svdobj.cxx:698
#define Y
virtual sal_uInt32 GetHdlCount() const override
Via GetHdlCount the number of Handles can be retrieved.
Definition: svdoedge.cxx:1733
long BigMulDiv(long nVal, long nMul, long nDiv)
Definition: svdtrans.cxx:559
virtual SdrObjectUniquePtr getFullDragClone() const override
Definition: svdoedge.cxx:1848
sal_uInt16 FindGluePoint(sal_uInt16 nId) const
Definition: svdglue.cxx:331
SdrMetricItem makeSdrEdgeLine1DeltaItem(long nVal)
Definition: sxelditm.hxx:34
virtual SdrLayerID GetLayer() const
Definition: svdobj.cxx:577
tools::Long AdjustTop(tools::Long nVertMoveDelta)
Point PixelToLogic(const Point &rDevicePt) const
SdrEdgeInfoRec aEdgeInfo
Definition: svdoedge.hxx:119
virtual const tools::Rectangle & GetSnapRect() const override
Definition: svdoedge.cxx:385
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
friend class ImpEdgeHdl
Definition: svdoedge.hxx:135
bool IsSet(SdrLayerID a) const
Definition: svdsob.hxx:66
void Insert(sal_uInt16 nPos, const Point &rPt, PolyFlags eFlags)
Definition: _xpoly.cxx:352
sal_uInt16 nConId
Definition: svdoedge.hxx:46
virtual SdrGluePoint GetCornerGluePoint(sal_uInt16 nNum) const
Definition: svdobj.cxx:2188
void RotatePoint(Point &rPnt, const Point &rRef, double sn, double cs)
Definition: svdtrans.hxx:114
virtual SdrObjGeoData * NewGeoData() const override
A derived class must override these 3 methods if it has own geometric data that must be saved for Und...
Definition: svdoedge.cxx:2458
sal_uInt32 count() const
virtual void RestGeoData(const SdrObjGeoData &rGeo) override
Definition: svdotext.cxx:1448
std::unique_ptr< XPolygon > pEdgeTrack
Definition: svdoedge.hxx:144
void Remove(sal_uInt16 nPos, sal_uInt16 nCount)
Definition: _xpoly.cxx:376
XPolygon ImpCalcEdgeTrack(const XPolygon &rTrack0, SdrObjConnection &rCon1, SdrObjConnection &rCon2, SdrEdgeInfoRec *pInfo) const
Definition: svdoedge.cxx:695
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Detects when a stylesheet is changed.
Definition: svdoattr.cxx:60
virtual void TakeObjInfo(SdrObjTransformInfoRec &rInfo) const override
Definition: svdoedge.cxx:353
virtual sal_uInt32 GetPointCount() const override
Definition: svdoedge.cxx:2419
virtual void AddToHdlList(SdrHdlList &rHdlList) const override
Definition: svdoedge.cxx:1762
virtual void SaveGeoData(SdrObjGeoData &rGeo) const override
Definition: svdoedge.cxx:2463
OUString ImpGetDescriptionStr(const char *pStrCacheID) const
Definition: svdobj.cxx:1038
virtual bool applySpecialDrag(SdrDragStat &rDrag) override
Definition: svdoedge.cxx:1875
void SetFlags(sal_uInt16 nPos, PolyFlags eFlags)
set the flags for the point at the given position
Definition: _xpoly.cxx:459
OUString aName
virtual OUString getSpecialDragComment(const SdrDragStat &rDrag) const override
Definition: svdoedge.cxx:1977
virtual sal_uInt16 GetObjIdentifier() const override
Definition: svdoedge.cxx:370
bool IsBestConnection() const
Definition: svdoedge.hxx:64
void RemoveListener(SfxListener &rListener)
Definition: svdobj.cxx:617
tools::Long Height() const
SdrObjConnection aCon1
Definition: svdoedge.hxx:141
SdrMetricItem makeSdrEdgeLine2DeltaItem(long nVal)
Definition: sxelditm.hxx:38
virtual void RestGeoData(const SdrObjGeoData &rGeo) override
Definition: svdoedge.cxx:2475
std::unique_ptr< SdrObject, SdrObjectFreeOp > SdrObjectUniquePtr
Definition: svdobj.hxx:115
constexpr TypedWhichId< SdrMetricItem > SDRATTR_EDGELINE1DELTA(SDRATTR_EDGE_FIRST+8)
const Point & GetPos() const
Definition: svdglue.hxx:82
const Point & GetNow() const
Definition: svddrag.hxx:95
static XPolygon ImpCalcObjToCenter(const Point &rStPt, long nEscAngle, const tools::Rectangle &rRect, const Point &rCenter)
Definition: svdoedge.cxx:636
PointerStyle
bool mbBoundRectCalculationRunning
Definition: svdoedge.hxx:160
virtual void SetRectsDirty(bool bNotMyself=false, bool bRecursive=true)
Definition: svdobj.cxx:435
void SetConnectMarker(const SdrObjConnection &rCon)
Definition: svdcrtv.cxx:269
void SetEdgeTrackDirty()
Definition: svdoedge.hxx:210
sal_uInt16 ImpGetPolyIdx(SdrEdgeLineCode eLineCode, const XPolygon &rXP) const
Definition: svdoedge.cxx:98
sal_uInt16 GetMarkHdlSizePixel() const
Definition: svdmrkv.cxx:1975
virtual void NbcShear(const Point &rRef, long nAngle, double tn, bool bVShear) override
Definition: svdoedge.cxx:2357
void Move(tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta)
constexpr TypedWhichId< SdrMetricItem > SDRATTR_EDGELINE2DELTA(SDRATTR_EDGE_FIRST+9)
void SetEdgeTrackPath(const basegfx::B2DPolyPolygon &rPoly)
Definition: svdoedge.cxx:1701
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Detects when a stylesheet is changed.
Definition: svdoedge.cxx:1581
void RotateXPoly(XPolygon &rPoly, const Point &rRef, double sn, double cs)
Definition: svdtrans.cxx:88
sal_Int32 getGluePointIndex(bool bTail)
this method is used by the api to return a glue point id for a connection.
Definition: svdoedge.cxx:2571
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
static SdrEscapeDirection ImpCalcEscAngle(SdrObject const *pObj, const Point &aPt2)
Definition: svdoedge.cxx:598
virtual void NbcSetAnchorPos(const Point &rPnt)
Definition: svdobj.cxx:1571
bool LineGeometryUsageIsNecessary() const
Definition: svdobj.cxx:962
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:365
virtual SdrGluePoint GetVertexGluePoint(sal_uInt16 nNum) const override
Definition: svdoedge.cxx:405
virtual void NbcRotate(const Point &rRef, long nAngle, double sn, double cs) override
Definition: svdotxtr.cxx:186
virtual bool TRGetBaseGeometry(basegfx::B2DHomMatrix &rMatrix, basegfx::B2DPolyPolygon &rPolyPolygon) const
Definition: svdobj.cxx:2888
SdrCreateCmd
Definition: svdtypes.hxx:27
sal_uInt16 GetPointCount() const
Definition: _xpoly.cxx:346
virtual void SetChanged()
Definition: svdobj.cxx:929
virtual void NbcShear(const Point &rRef, long nAngle, double tn, bool bVShear) override
Definition: svdotxtr.cxx:210
void MoveXPoly(XPolygon &rPoly, const Size &S)
Definition: svdtrans.cxx:32
bool bIsEdge
Definition: svdobj.hxx:946
Point aObj1Line2
Definition: svdoedge.hxx:80
tools::Long Right() const
void SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle &rBoundRect) const
Definition: svdobj.cxx:2655
void SetPos(const Point &rNewPos)
Definition: svdglue.hxx:83
bool GetSuppressDefaultConnect() const
Definition: svdoedge.hxx:169
Point Center() const
void AddHdl(std::unique_ptr< SdrHdl > pHdl)
Definition: svdhdl.cxx:2289
virtual bool EndCreate(SdrDragStat &rStat, SdrCreateCmd eCmd) override
Definition: svdoedge.cxx:2085
void HideConnectMarker()
Definition: svdcrtv.cxx:292
Utility class SdrEdgeObj.
Definition: svdoedge.hxx:128
SdrObject * pObj
Definition: svdoedge.hxx:45
virtual void RecalcSnapRect() override
Snap is not done on the BoundRect but if possible on logic coordinates (i.e.
Definition: svdoedge.cxx:395
virtual Point GetSnapPoint(sal_uInt32 i) const override
Definition: svdoedge.cxx:2406