Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / draw / dcontact.cxx
blob456241b660c0879d3131194ce90b152ac691f405
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <hintids.hxx>
22 #include <svx/svdpage.hxx>
23 #include <svx/svditer.hxx>
24 #include <svx/svdogrp.hxx>
25 #include <svx/svdotext.hxx>
26 #include <svx/svdmodel.hxx>
27 #include <svx/svdviter.hxx>
28 #include <svx/svdview.hxx>
29 #include <svx/sdr/contact/displayinfo.hxx>
30 #include <svx/sdr/contact/objectcontact.hxx>
31 #include <svx/shapepropertynotifier.hxx>
32 #include <drawdoc.hxx>
33 #include <fmtornt.hxx>
34 #include <viewimp.hxx>
35 #include <fmtsrnd.hxx>
36 #include <fmtanchr.hxx>
37 #include <node.hxx>
38 #include <fmtcntnt.hxx>
39 #include <fmtfsize.hxx>
40 #include <pam.hxx>
41 #include <pagefrm.hxx>
42 #include <rootfrm.hxx>
43 #include <frmtool.hxx>
44 #include <flyfrm.hxx>
45 #include <textboxhelper.hxx>
46 #include <frmfmt.hxx>
47 #include <fmtfollowtextflow.hxx>
48 #include <dflyobj.hxx>
49 #include <dcontact.hxx>
50 #include <unodraw.hxx>
51 #include <IDocumentDrawModelAccess.hxx>
52 #include <IDocumentLayoutAccess.hxx>
53 #include <IDocumentState.hxx>
54 #include <IDocumentUndoRedo.hxx>
55 #include <doc.hxx>
56 #include <hints.hxx>
57 #include <txtfrm.hxx>
58 #include <frameformats.hxx>
59 #include <sortedobjs.hxx>
60 #include <basegfx/matrix/b2dhommatrix.hxx>
61 #include <basegfx/matrix/b2dhommatrixtools.hxx>
62 #include <svx/sdr/contact/viewcontactofvirtobj.hxx>
63 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
64 #include <drawinglayer/geometry/viewinformation2d.hxx>
65 #include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
66 #include <com/sun/star/text/WritingMode2.hpp>
67 #include <calbck.hxx>
68 #include <algorithm>
69 #include <txtfly.hxx>
70 #include <sal/log.hxx>
72 using namespace ::com::sun::star;
74 namespace
76 /** unary function used to find a 'virtual' drawing object anchored at a given frame */
77 struct VirtObjAnchoredAtFramePred
79 const SwFrame* m_pAnchorFrame;
81 // #i26791# - compare with master frame
82 static const SwFrame* FindFrame(const SwFrame* pFrame)
84 if(!pFrame || !pFrame->IsContentFrame())
85 return pFrame;
86 auto pContentFrame = static_cast<const SwContentFrame*>(pFrame);
87 while(pContentFrame->IsFollow())
88 pContentFrame = pContentFrame->FindMaster();
89 return pContentFrame;
92 VirtObjAnchoredAtFramePred(const SwFrame* pAnchorFrame)
93 : m_pAnchorFrame(FindFrame(pAnchorFrame))
96 bool operator()(const rtl::Reference<SwDrawVirtObj>& rpDrawVirtObj)
98 return FindFrame(rpDrawVirtObj->GetAnchorFrame()) == m_pAnchorFrame;
103 void setContextWritingMode(SdrObject* pObj, SwFrame const * pAnchor)
105 if(!pObj || !pAnchor)
106 return;
107 short nWritingDirection =
108 pAnchor->IsVertical() ? text::WritingMode2::TB_RL :
109 pAnchor->IsRightToLeft() ? text::WritingMode2::RL_TB :
110 text::WritingMode2::LR_TB;
111 pObj->SetContextWritingMode(nWritingDirection);
115 /** The Get reverse way: seeks the format to the specified object.
116 * If the object is a SwVirtFlyDrawObj then the format of this
117 * will be acquired.
118 * Otherwise it is just a simple drawing object. This has a
119 * UserCall and is the client of the searched format.
121 SwFrameFormat *FindFrameFormat( SdrObject *pObj )
123 SwFrameFormat* pRetval = nullptr;
125 if (SwVirtFlyDrawObj* pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
127 pRetval = pFlyDrawObj->GetFormat();
129 else
131 SwContact* pContact = GetUserCall(pObj);
132 if ( pContact )
134 pRetval = pContact->GetFormat();
137 return pRetval;
140 bool HasWrap( const SdrObject* pObj )
142 if ( pObj )
144 const SwFrameFormat* pFormat = ::FindFrameFormat( pObj );
145 if ( pFormat )
147 return css::text::WrapTextMode_THROUGH != pFormat->GetSurround().GetSurround();
151 return false;
154 /// returns the BoundRect _inclusive_ distance of the object.
155 SwRect GetBoundRectOfAnchoredObj( const SdrObject* pObj )
157 SwRect aRet( pObj->GetCurrentBoundRect() );
158 // #i68520# - call cache of <SwAnchoredObject>
159 SwContact* pContact( GetUserCall( pObj ) );
160 if ( pContact )
162 const SwAnchoredObject* pAnchoredObj( pContact->GetAnchoredObj( pObj ) );
163 if ( pAnchoredObj )
165 aRet = pAnchoredObj->GetObjRectWithSpaces();
168 return aRet;
171 /// Returns the UserCall if applicable from the group object
172 SwContact* GetUserCall( const SdrObject* pObj )
174 SdrObject *pTmp;
175 while ( !pObj->GetUserCall() && nullptr != (pTmp = pObj->getParentSdrObjectFromSdrObject()) )
176 pObj = pTmp;
177 assert((!pObj->GetUserCall() || nullptr != dynamic_cast<const SwContact*>(pObj->GetUserCall())) &&
178 "<::GetUserCall(..)> - wrong type of found object user call." );
179 return static_cast<SwContact*>(pObj->GetUserCall());
182 /// Returns true if the SrdObject is a Marquee-Object (scrolling text)
183 bool IsMarqueeTextObj( const SdrObject& rObj )
185 if (SdrInventor::Default != rObj.GetObjInventor() ||
186 SdrObjKind::Text != rObj.GetObjIdentifier())
187 return false;
188 SdrTextAniKind eTKind = static_cast<const SdrTextObj&>(rObj).GetTextAniKind();
189 return ( SdrTextAniKind::Scroll == eTKind
190 || SdrTextAniKind::Alternate == eTKind || SdrTextAniKind::Slide == eTKind );
193 SwContact::SwContact( SwFrameFormat *pToRegisterIn ) :
194 SwClient( pToRegisterIn ),
195 mbInDTOR( false )
198 SwContact::~SwContact()
200 SetInDTOR();
204 void SwContact::SetInDTOR()
206 mbInDTOR = true;
209 /// method to move drawing object to corresponding visible layer
210 void SwContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
212 // #i46297# - notify background about the arriving of
213 // the object and invalidate its position.
214 const bool bNotify( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
216 MoveObjToLayer( true, _pDrawObj );
218 // #i46297#
219 if ( !bNotify )
220 return;
222 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
223 assert(pAnchoredObj);
224 ::setContextWritingMode( _pDrawObj, pAnchoredObj->GetAnchorFrameContainingAnchPos() );
225 // Note: as-character anchored objects aren't registered at a page frame and
226 // a notification of its background isn't needed.
227 if ( pAnchoredObj->GetPageFrame() )
229 ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
230 pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameArrive, true );
233 pAnchoredObj->InvalidateObjPos();
236 /// method to move drawing object to corresponding invisible layer - #i18447#
237 void SwContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
239 // #i46297# - notify background about the leaving of the object.
240 const bool bNotify( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
242 MoveObjToLayer( false, _pDrawObj );
244 // #i46297#
245 if ( bNotify )
247 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
248 assert(pAnchoredObj);
249 // Note: as-character anchored objects aren't registered at a page frame and
250 // a notification of its background isn't needed.
251 if (pAnchoredObj->GetPageFrame())
253 ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
254 pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameLeave, true );
259 /** method to move object to visible/invisible layer - #i18447#
261 implementation for the public method <MoveObjToVisibleLayer(..)>
262 and <MoveObjToInvisibleLayer(..)>
264 void SwContact::MoveObjToLayer( const bool _bToVisible,
265 SdrObject* _pDrawObj )
267 if ( !_pDrawObj )
269 OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing object!" );
270 return;
273 if ( !GetRegisteredIn() )
275 OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing frame format!" );
276 return;
279 const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
281 SdrLayerID nToHellLayerId =
282 _bToVisible ? rIDDMA.GetHellId() : rIDDMA.GetInvisibleHellId();
283 SdrLayerID nToHeavenLayerId =
284 _bToVisible ? rIDDMA.GetHeavenId() : rIDDMA.GetInvisibleHeavenId();
285 SdrLayerID nToControlLayerId =
286 _bToVisible ? rIDDMA.GetControlsId() : rIDDMA.GetInvisibleControlsId();
287 SdrLayerID nFromHellLayerId =
288 _bToVisible ? rIDDMA.GetInvisibleHellId() : rIDDMA.GetHellId();
289 SdrLayerID nFromHeavenLayerId =
290 _bToVisible ? rIDDMA.GetInvisibleHeavenId() : rIDDMA.GetHeavenId();
291 SdrLayerID nFromControlLayerId =
292 _bToVisible ? rIDDMA.GetInvisibleControlsId() : rIDDMA.GetControlsId();
294 if ( dynamic_cast<const SdrObjGroup*>( _pDrawObj) != nullptr )
296 // determine layer for group object
298 // proposed layer of a group object is the hell layer
299 SdrLayerID nNewLayerId = nToHellLayerId;
300 if ( ::CheckControlLayer( _pDrawObj ) )
302 // it has to be the control layer, if one of the member
303 // is a control
304 nNewLayerId = nToControlLayerId;
306 else if ( _pDrawObj->GetLayer() == rIDDMA.GetHeavenId() ||
307 _pDrawObj->GetLayer() == rIDDMA.GetInvisibleHeavenId() )
309 // it has to be the heaven layer, if method <GetLayer()> reveals
310 // a heaven layer
311 nNewLayerId = nToHeavenLayerId;
313 // set layer at group object, but do *not* broadcast and
314 // no propagation to the members.
315 // Thus, call <NbcSetLayer(..)> at super class
316 _pDrawObj->SdrObject::NbcSetLayer( nNewLayerId );
319 // call method recursively for group object members
320 const SdrObjList* pLst =
321 static_cast<SdrObjGroup*>(_pDrawObj)->GetSubList();
322 if ( pLst )
324 for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
326 MoveObjToLayer( _bToVisible, pLst->GetObj( i ) );
330 else
332 const SdrLayerID nLayerIdOfObj = _pDrawObj->GetLayer();
333 if ( nLayerIdOfObj == nFromHellLayerId )
335 _pDrawObj->SetLayer( nToHellLayerId );
337 else if ( nLayerIdOfObj == nFromHeavenLayerId )
339 _pDrawObj->SetLayer( nToHeavenLayerId );
341 else if ( nLayerIdOfObj == nFromControlLayerId )
343 _pDrawObj->SetLayer( nToControlLayerId );
348 /// get minimum order number of anchored objects handled by with contact
349 sal_uInt32 SwContact::GetMinOrdNum() const
351 sal_uInt32 nMinOrdNum( SAL_MAX_UINT32 );
353 std::vector< SwAnchoredObject* > aObjs;
354 GetAnchoredObjs( aObjs );
356 while ( !aObjs.empty() )
358 sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
360 if ( nTmpOrdNum < nMinOrdNum )
362 nMinOrdNum = nTmpOrdNum;
365 aObjs.pop_back();
368 OSL_ENSURE( nMinOrdNum != SAL_MAX_UINT32,
369 "<SwContact::GetMinOrdNum()> - no order number found." );
370 return nMinOrdNum;
373 /// get maximum order number of anchored objects handled by with contact
374 sal_uInt32 SwContact::GetMaxOrdNum() const
376 sal_uInt32 nMaxOrdNum( 0 );
378 std::vector< SwAnchoredObject* > aObjs;
379 GetAnchoredObjs( aObjs );
381 while ( !aObjs.empty() )
383 sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
385 if ( nTmpOrdNum > nMaxOrdNum )
387 nMaxOrdNum = nTmpOrdNum;
390 aObjs.pop_back();
393 return nMaxOrdNum;
396 namespace
398 Point lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj, const bool bFollowTextFlow, sw::WW8AnchorConv& reConv)
400 switch(reConv)
402 case sw::WW8AnchorConv::CONV2PG:
404 bool bRelToTableCell(false);
405 Point aPos(pAnchoredObj->GetRelPosToPageFrame(bFollowTextFlow, bRelToTableCell));
406 if(bRelToTableCell)
407 reConv = sw::WW8AnchorConv::RELTOTABLECELL;
408 return aPos;
410 case sw::WW8AnchorConv::CONV2COL_OR_PARA:
411 return pAnchoredObj->GetRelPosToAnchorFrame();
412 case sw::WW8AnchorConv::CONV2CHAR:
413 return pAnchoredObj->GetRelPosToChar();
414 case sw::WW8AnchorConv::CONV2LINE:
415 return pAnchoredObj->GetRelPosToLine();
416 default: ;
418 return Point();
421 void SwContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
423 // this does not call SwClient::SwClientNotify and thus doesn't handle RES_OBJECTDYING as usual. Is this intentional?
424 if (rHint.GetId() == SfxHintId::SwFindSdrObject)
426 auto pFindSdrObjectHint = static_cast<const sw::FindSdrObjectHint*>(&rHint);
427 if(!pFindSdrObjectHint->m_rpObject)
428 pFindSdrObjectHint->m_rpObject = GetMaster();
430 else if (rHint.GetId() == SfxHintId::SwWW8AnchorConv)
432 auto pWW8AnchorConvHint = static_cast<const sw::WW8AnchorConvHint*>(&rHint);
433 // determine anchored object
434 SwAnchoredObject* pAnchoredObj(nullptr);
436 std::vector<SwAnchoredObject*> aAnchoredObjs;
437 GetAnchoredObjs(aAnchoredObjs);
438 if(!aAnchoredObjs.empty())
439 pAnchoredObj = aAnchoredObjs.front();
441 // no anchored object found. Thus, the needed layout information can't
442 // be determined. --> no conversion
443 if(!pAnchoredObj)
444 return;
445 // no conversion for anchored drawing object, which aren't attached to an
446 // anchor frame.
447 // This is the case for drawing objects, which are anchored inside a page
448 // header/footer of an *unused* page style.
449 if(dynamic_cast<SwAnchoredDrawObject*>(pAnchoredObj) && !pAnchoredObj->GetAnchorFrame())
450 return;
451 const bool bFollowTextFlow = static_cast<const SwFrameFormat&>(rMod).GetFollowTextFlow().GetValue();
452 sw::WW8AnchorConvResult& rResult(pWW8AnchorConvHint->m_rResult);
453 // No distinction between layout directions, because of missing
454 // information about WW8 in vertical layout.
455 rResult.m_aPos.setX(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eHoriConv).getX());
456 rResult.m_aPos.setY(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eVertConv).getY());
457 rResult.m_bConverted = true;
462 SwFlyDrawContact::SwFlyDrawContact(
463 SwFlyFrameFormat *pToRegisterIn,
464 SdrModel& rTargetModel)
465 : SwContact(pToRegisterIn),
466 mpMasterObj(new SwFlyDrawObj(rTargetModel))
468 // #i26791# - class <SwFlyDrawContact> contains the 'master'
469 // drawing object of type <SwFlyDrawObj> on its own.
470 mpMasterObj->SetOrdNum( 0xFFFFFFFE );
471 mpMasterObj->SetUserCall( this );
474 SwFlyDrawContact::~SwFlyDrawContact()
476 if ( mpMasterObj )
478 mpMasterObj->SetUserCall( nullptr );
479 if ( mpMasterObj->getSdrPageFromSdrObject() )
480 mpMasterObj->getSdrPageFromSdrObject()->RemoveObject( mpMasterObj->GetOrdNum() );
484 sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly,
485 SwFrame const& rAnchorFrame)
487 // maintain invariant that a shape's textbox immediately follows the shape
488 // also for the multiple SdrVirtObj created for shapes in header/footer
489 if (SwFrameFormat const*const pDrawFormat =
490 SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT))
492 // assume that the draw SdrVirtObj is always created before the flyframe one
493 if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
495 for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
497 if (&pAnchoredObj->GetFrameFormat() == pDrawFormat)
499 return pAnchoredObj->GetDrawObj()->GetOrdNum() + 1;
503 // if called from AppendObjs(), this is a problem; if called from lcl_SetFlyFrameAttr() it's not
504 SAL_INFO("sw", "GetOrdNumForNewRef: cannot find SdrObject for text box's shape");
506 // search for another Writer fly frame registered at same frame format
507 SwIterator<SwFlyFrame,SwFormat> aIter(*GetFormat());
508 const SwFlyFrame* pFlyFrame(nullptr);
509 for(pFlyFrame = aIter.First(); pFlyFrame; pFlyFrame = aIter.Next())
511 if(pFlyFrame != pFly)
512 break;
515 if(pFlyFrame)
517 // another Writer fly frame found. Take its order number
518 return pFlyFrame->GetVirtDrawObj()->GetOrdNum();
520 // no other Writer fly frame found. Take order number of 'master' object
521 // #i35748# - use method <GetOrdNumDirect()> instead
522 // of method <GetOrdNum()> to avoid a recalculation of the order number,
523 // which isn't intended.
524 return GetMaster()->GetOrdNumDirect();
527 SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly,
528 SwFlyFrameFormat* pFormat, SwFrame const& rAnchorFrame)
530 // Find ContactObject from the Format. If there's already one, we just
531 // need to create a new Ref, else we create the Contact now.
533 IDocumentDrawModelAccess& rIDDMA = pFormat->getIDocumentDrawModelAccess();
534 SwFlyDrawContact* pContact = pFormat->GetOrCreateContact();
535 rtl::Reference<SwVirtFlyDrawObj> pDrawObj(
536 new SwVirtFlyDrawObj(
537 pContact->GetMaster()->getSdrModelFromSdrObject(),
538 *pContact->GetMaster(),
539 pFly));
540 pDrawObj->SetUserCall(pContact);
542 // The Reader creates the Masters and inserts them into the Page in
543 // order to transport the z-order.
544 // After creating the first Reference the Masters are removed from the
545 // List and are not important anymore.
546 SdrPage* pPg = pContact->GetMaster()->getSdrPageFromSdrObject();
547 if(nullptr != pPg)
549 const size_t nOrdNum = pContact->GetMaster()->GetOrdNum();
550 pPg->ReplaceObject(pDrawObj.get(), nOrdNum);
552 // #i27030# - insert new <SwVirtFlyDrawObj> instance
553 // into drawing page with correct order number
554 else
555 rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj.get(), pContact->GetOrdNumForNewRef(pFly, rAnchorFrame));
556 // #i38889# - assure, that new <SwVirtFlyDrawObj> instance
557 // is in a visible layer.
558 pContact->MoveObjToVisibleLayer(pDrawObj.get());
559 return pDrawObj.get();
562 // #i26791#
563 const SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(const SdrObject* pSdrObj) const
565 assert(pSdrObj);
566 assert(dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) != nullptr);
567 assert(GetUserCall(pSdrObj) == this &&
568 "<SwFlyDrawContact::GetAnchoredObj(..)> - provided object doesn't belong to this contact");
570 const SwAnchoredObject *const pRetAnchoredObj =
571 static_cast<const SwVirtFlyDrawObj*>(pSdrObj)->GetFlyFrame();
573 return pRetAnchoredObj;
576 SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
578 return const_cast<SwAnchoredObject *>(const_cast<SwFlyDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
581 SdrObject* SwFlyDrawContact::GetMaster()
583 return mpMasterObj.get();
587 * @note Overriding method to control Writer fly frames, which are linked, and
588 * to assure that all objects anchored at/inside the Writer fly frame are
589 * also made visible.
591 void SwFlyDrawContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
593 assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
595 if ( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
597 // nothing to do
598 return;
601 SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
603 // #i44464# - consider, that Writer fly frame content
604 // already exists - (e.g. WW8 document is inserted into an existing document).
605 if ( !pFlyFrame->Lower() )
607 pFlyFrame->InsertColumns();
608 pFlyFrame->Chain( pFlyFrame->AnchorFrame() );
609 pFlyFrame->InsertCnt();
611 if ( pFlyFrame->GetDrawObjs() )
613 for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
615 // #i28701# - consider type of objects in sorted object list.
616 SdrObject* pObj = i->DrawObj();
617 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
618 pContact->MoveObjToVisibleLayer( pObj );
622 // make fly frame visible
623 SwContact::MoveObjToVisibleLayer( _pDrawObj );
627 * @note Override method to control Writer fly frames, which are linked, and
628 * to assure that all objects anchored at/inside the Writer fly frame are
629 * also made invisible.
631 void SwFlyDrawContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
633 assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
635 if ( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
637 // nothing to do
638 return;
641 SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
643 pFlyFrame->Unchain();
644 pFlyFrame->DeleteCnt();
645 if ( pFlyFrame->GetDrawObjs() )
647 for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
649 // #i28701# - consider type of objects in sorted object list.
650 SdrObject* pObj = i->DrawObj();
651 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
652 pContact->MoveObjToInvisibleLayer( pObj );
656 // make fly frame invisible
657 SwContact::MoveObjToInvisibleLayer( _pDrawObj );
660 /// get data collection of anchored objects, handled by with contact
661 void SwFlyDrawContact::GetAnchoredObjs( std::vector<SwAnchoredObject*>& _roAnchoredObjs ) const
663 const SwFrameFormat* pFormat = GetFormat();
664 SwFlyFrame::GetAnchoredObjects( _roAnchoredObjs, *pFormat );
666 void SwFlyDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
668 SwContact::SwClientNotify(rMod, rHint);
669 if(rHint.GetId() == SfxHintId::SwGetZOrder)
671 auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint);
672 // #i11176#
673 // This also needs to work when no layout exists. Thus, for
674 // FlyFrames an alternative method is used now in that case.
675 auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
676 if (pFormat && pFormat->Which() == RES_FLYFRMFMT && !pFormat->getIDocumentLayoutAccess().GetCurrentViewShell())
677 pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
681 // SwDrawContact
683 bool CheckControlLayer( const SdrObject *pObj )
685 if ( SdrInventor::FmForm == pObj->GetObjInventor() )
686 return true;
687 if (const SdrObjGroup *pObjGroup = dynamic_cast<const SdrObjGroup*>(pObj))
689 const SdrObjList *pLst = pObjGroup->GetSubList();
690 for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
692 if ( ::CheckControlLayer( pLst->GetObj( i ) ) )
694 // #i18447# - return correct value ;-)
695 return true;
699 return false;
702 SwDrawContact::SwDrawContact( SwFrameFormat* pToRegisterIn, SdrObject* pObj ) :
703 SwContact( pToRegisterIn ),
704 mbMasterObjCleared( false ),
705 mbDisconnectInProgress( false ),
706 mbUserCallActive( false ),
707 // Note: value of <meEventTypeOfCurrentUserCall> isn't of relevance, because
708 // <mbUserCallActive> is false.
709 meEventTypeOfCurrentUserCall( SdrUserCallType::MoveOnly )
711 // --> #i33909# - assure, that drawing object is inserted
712 // in the drawing page.
713 if ( !pObj->IsInserted() )
715 pToRegisterIn->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
716 InsertObject( pObj, pObj->GetOrdNumDirect() );
719 // Controls have to be always in the Control-Layer. This is also true for
720 // group objects, if they contain controls.
721 if ( ::CheckControlLayer( pObj ) )
723 // set layer of object to corresponding invisible layer.
724 pObj->SetLayer( pToRegisterIn->getIDocumentDrawModelAccess().GetInvisibleControlsId() );
727 // #i26791#
728 pObj->SetUserCall( this );
729 maAnchoredDrawObj.SetDrawObj( *pObj );
731 // if there already exists an SwXShape for the object, ensure it knows about us, and the SdrObject
732 // #i99056#
733 SwXShape::AddExistingShapeToFormat( *pObj );
736 SwDrawContact::~SwDrawContact()
738 SetInDTOR();
740 DisconnectFromLayout();
742 // remove 'master' from drawing page
743 RemoveMasterFromDrawPage();
745 // remove and destroy 'virtual' drawing objects.
746 RemoveAllVirtObjs();
748 if ( !mbMasterObjCleared )
749 maAnchoredDrawObj.ClearDrawObj();
752 void SwDrawContact::GetTextObjectsFromFormat(std::list<SdrTextObj*>& o_rTextObjects, SwDoc& rDoc)
754 for(sw::SpzFrameFormat* pFly: *rDoc.GetSpzFrameFormats())
756 if(dynamic_cast<const SwDrawFrameFormat*>(pFly))
757 pFly->CallSwClientNotify(sw::CollectTextObjectsHint(o_rTextObjects));
761 // #i26791#
762 const SwAnchoredObject* SwDrawContact::GetAnchoredObj(const SdrObject* pSdrObj ) const
764 // handle default parameter value
765 if (!pSdrObj)
767 pSdrObj = GetMaster();
770 assert(pSdrObj);
771 assert(dynamic_cast<const SwDrawVirtObj*>(pSdrObj) != nullptr ||
772 dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
773 assert((GetUserCall(pSdrObj) == this ||
774 pSdrObj == GetMaster()) &&
775 "<SwDrawContact::GetAnchoredObj(..)> - provided object doesn't belongs to this contact" );
777 const SwAnchoredObject* pRetAnchoredObj = nullptr;
779 if (auto pVirtObj = dynamic_cast<const SwDrawVirtObj*>(pSdrObj))
781 pRetAnchoredObj = &(pVirtObj->GetAnchoredObj());
783 else
785 assert(dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
786 pRetAnchoredObj = &maAnchoredDrawObj;
789 return pRetAnchoredObj;
792 SwAnchoredObject* SwDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
794 return const_cast<SwAnchoredObject*>(const_cast<SwDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
797 SdrObject* SwDrawContact::GetMaster()
799 return !mbMasterObjCleared
800 ? maAnchoredDrawObj.DrawObj()
801 : nullptr;
804 const SwFrame* SwDrawContact::GetAnchorFrame( const SdrObject* _pDrawObj ) const
806 const SwFrame* pAnchorFrame = nullptr;
807 if ( !_pDrawObj ||
808 _pDrawObj == GetMaster() ||
809 ( !_pDrawObj->GetUserCall() &&
810 GetUserCall( _pDrawObj ) == this ) )
812 pAnchorFrame = maAnchoredDrawObj.GetAnchorFrame();
814 else
816 assert(dynamic_cast<SwDrawVirtObj const*>(_pDrawObj) != nullptr);
817 pAnchorFrame = static_cast<const SwDrawVirtObj*>(_pDrawObj)->GetAnchorFrame();
820 return pAnchorFrame;
823 SwFrame* SwDrawContact::GetAnchorFrame(SdrObject const *const pDrawObj)
825 return const_cast<SwFrame *>(const_cast<SwDrawContact const*>(this)->GetAnchorFrame(pDrawObj));
828 /** add a 'virtual' drawing object to drawing page.
830 SwDrawVirtObj* SwDrawContact::AddVirtObj(SwFrame const& rAnchorFrame)
832 maDrawVirtObjs.push_back(
833 new SwDrawVirtObj(
834 GetMaster()->getSdrModelFromSdrObject(),
835 *GetMaster(),
836 *this));
837 maDrawVirtObjs.back()->AddToDrawingPage(rAnchorFrame);
838 return maDrawVirtObjs.back().get();
841 /// remove 'virtual' drawing objects and destroy them.
842 void SwDrawContact::RemoveAllVirtObjs()
844 for(auto& rpDrawVirtObj : maDrawVirtObjs)
846 // remove and destroy 'virtual object'
847 rpDrawVirtObj->RemoveFromWriterLayout();
848 rpDrawVirtObj->RemoveFromDrawingPage();
849 // to break the reference cycle
850 rpDrawVirtObj->AnchoredObj().ClearDrawObj();
852 maDrawVirtObjs.clear();
856 /// get drawing object ('master' or 'virtual') by frame.
857 SdrObject* SwDrawContact::GetDrawObjectByAnchorFrame( const SwFrame& _rAnchorFrame )
859 SdrObject* pRetDrawObj = nullptr;
861 // #i26791# - compare master frames instead of direct frames
862 const SwFrame* pProposedAnchorFrame = &_rAnchorFrame;
863 if ( pProposedAnchorFrame->IsContentFrame() )
865 const SwContentFrame* pTmpFrame =
866 static_cast<const SwContentFrame*>( pProposedAnchorFrame );
867 while ( pTmpFrame->IsFollow() )
869 pTmpFrame = pTmpFrame->FindMaster();
871 pProposedAnchorFrame = pTmpFrame;
874 const SwFrame* pMasterObjAnchorFrame = GetAnchorFrame();
875 if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame->IsContentFrame() )
877 const SwContentFrame* pTmpFrame =
878 static_cast<const SwContentFrame*>( pMasterObjAnchorFrame );
879 while ( pTmpFrame->IsFollow() )
881 pTmpFrame = pTmpFrame->FindMaster();
883 pMasterObjAnchorFrame = pTmpFrame;
886 if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame == pProposedAnchorFrame )
888 pRetDrawObj = GetMaster();
890 else
892 const auto ppFoundVirtObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
893 VirtObjAnchoredAtFramePred(pProposedAnchorFrame)));
894 if(ppFoundVirtObj != maDrawVirtObjs.end())
895 pRetDrawObj = ppFoundVirtObj->get();
898 return pRetDrawObj;
901 void SwDrawContact::NotifyBackgroundOfAllVirtObjs(const tools::Rectangle* pOldBoundRect)
903 for(const auto& rpDrawVirtObj : maDrawVirtObjs)
905 SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
906 if ( pDrawVirtObj->GetAnchorFrame() )
908 // #i34640# - determine correct page frame
909 SwPageFrame* pPage = pDrawVirtObj->AnchoredObj().FindPageFrameOfAnchor();
910 if( pOldBoundRect && pPage )
912 SwRect aOldRect( *pOldBoundRect );
913 aOldRect.Pos() += pDrawVirtObj->GetOffset();
914 if( aOldRect.HasArea() )
915 ::Notify_Background( pDrawVirtObj, pPage,
916 aOldRect, PrepareHint::FlyFrameLeave,true);
918 // #i34640# - include spacing for wrapping
919 SwRect aRect( pDrawVirtObj->GetAnchoredObj().GetObjRectWithSpaces() );
920 if (aRect.HasArea() && pPage)
922 SwPageFrame* pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aRect, pPage )));
923 if ( pPg )
924 ::Notify_Background( pDrawVirtObj, pPg, aRect,
925 PrepareHint::FlyFrameArrive, true );
927 ::ClrContourCache( pDrawVirtObj );
932 /// local method to notify the background for a drawing object - #i26791#
933 static void lcl_NotifyBackgroundOfObj( SwDrawContact const & _rDrawContact,
934 const SdrObject& _rObj,
935 const tools::Rectangle* _pOldObjRect )
937 // #i34640#
938 SwAnchoredObject* pAnchoredObj =
939 const_cast<SwAnchoredObject*>(_rDrawContact.GetAnchoredObj( &_rObj ));
940 if ( !(pAnchoredObj && pAnchoredObj->GetAnchorFrame()) )
941 return;
943 // #i34640# - determine correct page frame
944 SwPageFrame* pPageFrame = pAnchoredObj->FindPageFrameOfAnchor();
945 if( _pOldObjRect && pPageFrame )
947 SwRect aOldRect( *_pOldObjRect );
948 if( aOldRect.HasArea() )
950 // #i34640# - determine correct page frame
951 SwPageFrame* pOldPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aOldRect, pPageFrame )));
952 ::Notify_Background( &_rObj, pOldPageFrame, aOldRect,
953 PrepareHint::FlyFrameLeave, true);
956 // #i34640# - include spacing for wrapping
957 SwRect aNewRect( pAnchoredObj->GetObjRectWithSpaces() );
958 if( aNewRect.HasArea() && pPageFrame )
960 pPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aNewRect, pPageFrame )));
961 ::Notify_Background( &_rObj, pPageFrame, aNewRect,
962 PrepareHint::FlyFrameArrive, true );
964 ClrContourCache( &_rObj );
967 void SwDrawContact::Changed( const SdrObject& rObj,
968 SdrUserCallType eType,
969 const tools::Rectangle& rOldBoundRect )
971 // #i26791# - no event handling, if existing <SwViewShell>
972 // is in construction
973 SwDoc* pDoc = GetFormat()->GetDoc();
974 if ( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() &&
975 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor() )
977 return;
980 // #i44339#
981 // no event handling, if document is in destruction.
982 // Exception: It's the SdrUserCallType::Delete event
983 if ( pDoc->IsInDtor() && eType != SdrUserCallType::Delete )
985 return;
988 //Put on Action, but not if presently anywhere an action runs.
989 bool bHasActions(true);
990 SwRootFrame *pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
991 if ( pTmpRoot && pTmpRoot->IsCallbackActionEnabled() )
993 SwViewShell* const pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
994 if ( pSh )
996 for(SwViewShell& rShell : pSh->GetRingContainer() )
998 if ( rShell.Imp()->IsAction() || rShell.Imp()->IsIdleAction() )
1000 bHasActions = true;
1001 break;
1003 bHasActions = false;
1006 if(!bHasActions)
1007 pTmpRoot->StartAllAction();
1009 SdrObjUserCall::Changed( rObj, eType, rOldBoundRect );
1010 Changed_( rObj, eType, &rOldBoundRect ); //Attention, possibly suicidal!
1012 if(!bHasActions)
1013 pTmpRoot->EndAllAction();
1016 /// helper class for method <SwDrawContact::Changed_(..)> for handling nested
1017 /// <SdrObjUserCall> events
1018 class NestedUserCallHdl
1020 private:
1021 SwDrawContact* mpDrawContact;
1022 bool mbParentUserCallActive;
1023 SdrUserCallType meParentUserCallEventType;
1025 public:
1026 NestedUserCallHdl( SwDrawContact* _pDrawContact,
1027 SdrUserCallType _eEventType )
1028 : mpDrawContact( _pDrawContact ),
1029 mbParentUserCallActive( _pDrawContact->mbUserCallActive ),
1030 meParentUserCallEventType( _pDrawContact->meEventTypeOfCurrentUserCall )
1032 mpDrawContact->mbUserCallActive = true;
1033 mpDrawContact->meEventTypeOfCurrentUserCall = _eEventType;
1036 ~NestedUserCallHdl()
1038 if ( mpDrawContact )
1040 mpDrawContact->mbUserCallActive = mbParentUserCallActive;
1041 mpDrawContact->meEventTypeOfCurrentUserCall = meParentUserCallEventType;
1045 void DrawContactDeleted()
1047 mpDrawContact = nullptr;
1050 bool IsNestedUserCall() const
1052 return mbParentUserCallActive;
1055 void AssertNestedUserCall()
1057 if ( !IsNestedUserCall() )
1058 return;
1060 bool bTmpAssert( true );
1061 // Currently its known, that a nested event SdrUserCallType::Resize
1062 // could occur during parent user call SdrUserCallType::Inserted,
1063 // SdrUserCallType::Delete and SdrUserCallType::Resize for edge objects.
1064 // Also possible are nested SdrUserCallType::ChildResize events for
1065 // edge objects
1066 // Thus, assert all other combinations
1067 if ( ( meParentUserCallEventType == SdrUserCallType::Inserted ||
1068 meParentUserCallEventType == SdrUserCallType::Delete ||
1069 meParentUserCallEventType == SdrUserCallType::Resize ) &&
1070 mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::Resize )
1072 bTmpAssert = false;
1074 else if ( meParentUserCallEventType == SdrUserCallType::ChildResize &&
1075 mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::ChildResize )
1077 bTmpAssert = false;
1080 if ( bTmpAssert )
1082 OSL_FAIL( "<SwDrawContact::Changed_(..)> - unknown nested <UserCall> event. This is serious." );
1087 /// Notify the format's textbox that it should reconsider its position / size.
1088 static void lcl_textBoxSizeNotify(SwFrameFormat* pFormat)
1090 if (SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT))
1092 // Just notify the textbox that the size has changed, the actual object size is not interesting.
1093 SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aResizeSet(pFormat->GetDoc()->GetAttrPool());
1094 SwFormatFrameSize aSize;
1095 aResizeSet.Put(aSize);
1096 SwTextBoxHelper::syncFlyFrameAttr(*pFormat, aResizeSet, pFormat->FindRealSdrObject());
1100 // !!!ATTENTION!!! The object may commit suicide!!!
1102 void SwDrawContact::Changed_( const SdrObject& rObj,
1103 SdrUserCallType eType,
1104 const tools::Rectangle* pOldBoundRect )
1106 // suppress handling of nested <SdrObjUserCall> events
1107 NestedUserCallHdl aNestedUserCallHdl( this, eType );
1108 if ( aNestedUserCallHdl.IsNestedUserCall() )
1110 aNestedUserCallHdl.AssertNestedUserCall();
1111 return;
1113 // do *not* notify, if document is destructing
1114 // #i35912# - do *not* notify for as-character anchored
1115 // drawing objects.
1116 // #i35007#
1117 // improvement: determine as-character anchored object flag only once.
1118 const bool bAnchoredAsChar = ObjAnchoredAsChar();
1119 const bool bNotify = !(GetFormat()->GetDoc()->IsInDtor()) &&
1120 ( css::text::WrapTextMode_THROUGH != GetFormat()->GetSurround().GetSurround() ) &&
1121 !bAnchoredAsChar;
1122 switch( eType )
1124 case SdrUserCallType::Delete:
1126 if ( bNotify )
1128 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1129 // --> #i36181# - background of 'virtual'
1130 // drawing objects have also been notified.
1131 NotifyBackgroundOfAllVirtObjs( pOldBoundRect );
1133 DisconnectFromLayout( false );
1134 mbMasterObjCleared = true;
1135 delete this;
1136 // --> #i65784# Prevent memory corruption
1137 aNestedUserCallHdl.DrawContactDeleted();
1138 break;
1140 case SdrUserCallType::Inserted:
1142 if ( mbDisconnectInProgress )
1144 OSL_FAIL( "<SwDrawContact::Changed_(..)> - Insert event during disconnection from layout is invalid." );
1146 else
1148 ConnectToLayout();
1149 if ( bNotify )
1151 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1154 break;
1156 case SdrUserCallType::Removed:
1158 if ( bNotify )
1160 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1162 DisconnectFromLayout( false );
1163 break;
1165 case SdrUserCallType::ChildInserted :
1166 case SdrUserCallType::ChildRemoved :
1168 // --> #i113730#
1169 // force layer of controls for group objects containing control objects
1170 if(dynamic_cast< SdrObjGroup* >(maAnchoredDrawObj.DrawObj()))
1172 if(::CheckControlLayer(maAnchoredDrawObj.DrawObj()))
1174 const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
1175 const SdrLayerID aCurrentLayer(maAnchoredDrawObj.DrawObj()->GetLayer());
1176 const SdrLayerID aControlLayerID(rIDDMA.GetControlsId());
1177 const SdrLayerID aInvisibleControlLayerID(rIDDMA.GetInvisibleControlsId());
1179 if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID)
1181 if ( aCurrentLayer == rIDDMA.GetInvisibleHellId() ||
1182 aCurrentLayer == rIDDMA.GetInvisibleHeavenId() )
1184 maAnchoredDrawObj.DrawObj()->SetLayer(aInvisibleControlLayerID);
1186 else
1188 maAnchoredDrawObj.DrawObj()->SetLayer(aControlLayerID);
1193 [[fallthrough]];
1195 case SdrUserCallType::MoveOnly:
1196 case SdrUserCallType::Resize:
1197 case SdrUserCallType::ChildMoveOnly :
1198 case SdrUserCallType::ChildResize :
1199 case SdrUserCallType::ChildChangeAttr :
1200 case SdrUserCallType::ChildDelete :
1202 // #i31698# - improvement
1203 // get instance <SwAnchoredDrawObject> only once
1204 const SwAnchoredDrawObject* pAnchoredDrawObj =
1205 static_cast<const SwAnchoredDrawObject*>( GetAnchoredObj( &rObj ) );
1207 /* protect against NULL pointer dereferencing */
1208 if(!pAnchoredDrawObj)
1210 break;
1213 // #i26791# - adjust positioning and alignment attributes,
1214 // if positioning of drawing object isn't in progress.
1215 // #i53320# - no adjust of positioning attributes,
1216 // if drawing object isn't positioned.
1217 if ( !pAnchoredDrawObj->IsPositioningInProgress() &&
1218 !pAnchoredDrawObj->NotYetPositioned() )
1220 // #i34748# - If no last object rectangle is
1221 // provided by the anchored object, use parameter <pOldBoundRect>.
1222 const tools::Rectangle& aOldObjRect = pAnchoredDrawObj->GetLastObjRect()
1223 ? *(pAnchoredDrawObj->GetLastObjRect())
1224 : *pOldBoundRect;
1225 // #i79400#
1226 // always invalidate object rectangle inclusive spaces
1227 pAnchoredDrawObj->InvalidateObjRectWithSpaces();
1228 // #i41324# - notify background before
1229 // adjusting position
1230 if ( bNotify )
1232 // #i31573# - correction
1233 // background of given drawing object.
1234 lcl_NotifyBackgroundOfObj( *this, rObj, &aOldObjRect );
1236 // #i31698# - determine layout direction
1237 // via draw frame format.
1238 SwFrameFormat::tLayoutDir eLayoutDir =
1239 pAnchoredDrawObj->GetFrameFormat().GetLayoutDir();
1240 // use geometry of drawing object
1241 tools::Rectangle aObjRect( rObj.GetSnapRect() );
1242 // If drawing object is a member of a group, the adjustment
1243 // of the positioning and the alignment attributes has to
1244 // be done for the top group object.
1245 if ( rObj.getParentSdrObjectFromSdrObject() )
1247 const SdrObject* pGroupObj = rObj.getParentSdrObjectFromSdrObject();
1248 while ( pGroupObj->getParentSdrObjectFromSdrObject() )
1250 pGroupObj = pGroupObj->getParentSdrObjectFromSdrObject();
1252 // use geometry of drawing object
1253 aObjRect = pGroupObj->GetSnapRect();
1255 SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::changeAnchor, GetFormat(), &const_cast<SdrObject&>(rObj));
1256 SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::syncTextBoxSize, GetFormat(), &const_cast<SdrObject&>(rObj));
1259 SwTwips nXPosDiff(0);
1260 SwTwips nYPosDiff(0);
1261 switch ( eLayoutDir )
1263 case SwFrameFormat::HORI_L2R:
1265 nXPosDiff = aObjRect.Left() - aOldObjRect.Left();
1266 nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1268 break;
1269 case SwFrameFormat::HORI_R2L:
1271 nXPosDiff = aOldObjRect.Right() - aObjRect.Right();
1272 nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1274 break;
1275 case SwFrameFormat::VERT_R2L:
1277 nXPosDiff = aObjRect.Top() - aOldObjRect.Top();
1278 nYPosDiff = aOldObjRect.Right() - aObjRect.Right();
1280 break;
1281 default:
1283 assert(!"<SwDrawContact::Changed_(..)> - unsupported layout direction");
1286 SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT> aSet( GetFormat()->GetDoc()->GetAttrPool() );
1287 const SwFormatVertOrient& rVert = GetFormat()->GetVertOrient();
1288 if ( nYPosDiff != 0 )
1290 if ( rVert.GetRelationOrient() == text::RelOrientation::CHAR ||
1291 rVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
1293 nYPosDiff = -nYPosDiff;
1295 aSet.Put( SwFormatVertOrient( rVert.GetPos()+nYPosDiff,
1296 text::VertOrientation::NONE,
1297 rVert.GetRelationOrient() ) );
1300 const SwFormatHoriOrient& rHori = GetFormat()->GetHoriOrient();
1301 if ( !bAnchoredAsChar && nXPosDiff != 0 )
1303 aSet.Put( SwFormatHoriOrient( rHori.GetPos()+nXPosDiff,
1304 text::HoriOrientation::NONE,
1305 rHori.GetRelationOrient() ) );
1308 if ( nYPosDiff ||
1309 ( !bAnchoredAsChar && nXPosDiff != 0 ) )
1311 GetFormat()->GetDoc()->SetFlyFrameAttr( *(GetFormat()), aSet );
1312 // keep new object rectangle, to avoid multiple
1313 // changes of the attributes by multiple event from
1314 // the drawing layer - e.g. group objects and its members
1315 // #i34748# - use new method
1316 // <SwAnchoredDrawObject::SetLastObjRect(..)>.
1317 const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)
1318 ->SetLastObjRect( aObjRect );
1320 else if ( aObjRect.GetSize() != aOldObjRect.GetSize() )
1322 InvalidateObjs_();
1323 // #i35007# - notify anchor frame
1324 // of as-character anchored object
1325 if ( bAnchoredAsChar )
1327 SwFrame* pAnchorFrame = const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)->AnchorFrame();
1328 if(pAnchorFrame)
1330 pAnchorFrame->Prepare( PrepareHint::FlyFrameAttributesChanged, GetFormat() );
1334 lcl_textBoxSizeNotify(GetFormat());
1336 else if (eType == SdrUserCallType::Resize)
1337 // Even if the bounding box of the shape didn't change,
1338 // notify about the size change, as an adjustment change
1339 // may affect the size of the underlying textbox.
1340 lcl_textBoxSizeNotify(GetFormat());
1343 // tdf#135198: keep text box together with its shape
1344 const SwPageFrame* rPageFrame = pAnchoredDrawObj->GetPageFrame();
1345 if (rPageFrame && rPageFrame->isFrameAreaPositionValid() && GetFormat()
1346 && GetFormat()->GetOtherTextBoxFormats())
1348 SwDoc* const pDoc = GetFormat()->GetDoc();
1350 // avoid Undo creation
1351 ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1353 // hide any artificial "changes" made by synchronizing the textbox position
1354 const bool bEnableSetModified = pDoc->getIDocumentState().IsEnableSetModified();
1355 pDoc->getIDocumentState().SetEnableSetModified(false);
1357 SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT, RES_ANCHOR, RES_ANCHOR>
1358 aSyncSet( pDoc->GetAttrPool() );
1359 aSyncSet.Put(GetFormat()->GetHoriOrient());
1360 bool bRelToTableCell(false);
1361 aSyncSet.Put(SwFormatVertOrient(pAnchoredDrawObj->GetRelPosToPageFrame(false, bRelToTableCell).getY(),
1362 text::VertOrientation::NONE,
1363 text::RelOrientation::PAGE_FRAME));
1364 aSyncSet.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, rPageFrame->GetPhyPageNum()));
1366 auto pSdrObj = const_cast<SdrObject*>(&rObj);
1367 if (pSdrObj != GetFormat()->FindRealSdrObject())
1369 SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aSet( pDoc->GetAttrPool() );
1371 aSet.Put(aSyncSet);
1372 aSet.Put(pSdrObj->GetMergedItem(RES_FRM_SIZE));
1373 SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSet, pSdrObj);
1375 SwTextBoxHelper::synchronizeGroupTextBoxProperty(
1376 &SwTextBoxHelper::changeAnchor, GetFormat(),
1377 GetFormat()->FindRealSdrObject());
1378 SwTextBoxHelper::synchronizeGroupTextBoxProperty(
1379 &SwTextBoxHelper::syncTextBoxSize, GetFormat(),
1380 GetFormat()->FindRealSdrObject());
1382 else
1383 SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSyncSet, GetFormat()->FindRealSdrObject());
1385 pDoc->getIDocumentState().SetEnableSetModified(bEnableSetModified);
1388 break;
1389 case SdrUserCallType::ChangeAttr:
1390 if ( bNotify )
1392 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1394 break;
1395 default:
1396 break;
1400 namespace
1402 const SwFormatAnchor* lcl_getAnchorFormat( const SfxPoolItem& _rItem )
1404 sal_uInt16 nWhich = _rItem.Which();
1405 const SwFormatAnchor* pAnchorFormat = nullptr;
1406 if ( RES_ATTRSET_CHG == nWhich )
1408 pAnchorFormat = static_cast<const SwAttrSetChg&>(_rItem).GetChgSet()->
1409 GetItemIfSet( RES_ANCHOR, false );
1411 else if ( RES_ANCHOR == nWhich )
1413 pAnchorFormat = &static_cast<const SwFormatAnchor&>(_rItem);
1415 return pAnchorFormat;
1419 void SwDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
1421 SwClient::SwClientNotify(rMod, rHint); // needed as SwContact::SwClientNotify doesn't explicitly call SwClient::SwClientNotify
1422 SwContact::SwClientNotify(rMod, rHint);
1423 if (rHint.GetId() == SfxHintId::SwLegacyModify)
1425 auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
1426 SAL_WARN_IF(mbDisconnectInProgress, "sw.core", "<SwDrawContact::Modify(..)> called during disconnection.");
1428 const SfxPoolItem* pNew = pLegacyHint->m_pNew;
1429 sal_uInt16 nWhich = pNew ? pNew->Which() : 0;
1430 if(const SwFormatAnchor* pNewAnchorFormat = pNew ? lcl_getAnchorFormat(*pNew) : nullptr)
1432 // Do not respond to a Reset Anchor!
1433 if(GetFormat()->GetAttrSet().GetItemState(RES_ANCHOR, false) == SfxItemState::SET)
1435 // no connect to layout during disconnection
1436 if(!mbDisconnectInProgress)
1438 // determine old object rectangle of 'master' drawing object
1439 // for notification
1440 const tools::Rectangle* pOldRect = nullptr;
1441 tools::Rectangle aOldRect;
1442 if(GetAnchorFrame())
1444 // --> #i36181# - include spacing in object
1445 // rectangle for notification.
1446 aOldRect = maAnchoredDrawObj.GetObjRectWithSpaces().SVRect();
1447 pOldRect = &aOldRect;
1449 // re-connect to layout due to anchor format change
1450 ConnectToLayout(pNewAnchorFormat);
1451 // notify background of drawing objects
1452 lcl_NotifyBackgroundOfObj(*this, *GetMaster(), pOldRect);
1453 NotifyBackgroundOfAllVirtObjs(pOldRect);
1455 const SwFormatAnchor* pOldAnchorFormat = pLegacyHint->m_pOld ? lcl_getAnchorFormat(*pLegacyHint->m_pOld) : nullptr;
1456 if(!pOldAnchorFormat || (pOldAnchorFormat->GetAnchorId() != pNewAnchorFormat->GetAnchorId()))
1458 if(maAnchoredDrawObj.DrawObj())
1460 // --> #i102752#
1461 // assure that a ShapePropertyChangeNotifier exists
1462 maAnchoredDrawObj.DrawObj()->notifyShapePropertyChange(svx::ShapePropertyProviderId::TextDocAnchor);
1464 else
1465 SAL_WARN("sw.core", "SwDrawContact::Modify: no draw object here?");
1469 else
1470 DisconnectFromLayout();
1472 else if (nWhich == RES_REMOVE_UNO_OBJECT)
1473 {} // nothing to do
1474 // --> #i62875# - no further notification, if not connected to Writer layout
1475 else if ( maAnchoredDrawObj.GetAnchorFrame() &&
1476 maAnchoredDrawObj.GetDrawObj()->GetUserCall() )
1478 bool bUpdateSortedObjsList(false);
1479 switch(nWhich)
1481 case RES_UL_SPACE:
1482 case RES_LR_SPACE:
1483 case RES_HORI_ORIENT:
1484 case RES_VERT_ORIENT:
1485 case RES_FOLLOW_TEXT_FLOW: // #i28701# - add attribute 'Follow text flow'
1486 break;
1487 case RES_SURROUND:
1488 case RES_OPAQUE:
1489 case RES_WRAP_INFLUENCE_ON_OBJPOS:
1490 // --> #i28701# - on change of wrapping style, hell|heaven layer,
1491 // or wrapping style influence an update of the <SwSortedObjs> list,
1492 // the drawing object is registered in, has to be performed. This is triggered
1493 // by the 1st parameter of method call <InvalidateObjs_(..)>.
1494 bUpdateSortedObjsList = true;
1495 break;
1496 case RES_ATTRSET_CHG: // #i35443#
1498 auto pChgSet = static_cast<const SwAttrSetChg*>(pNew)->GetChgSet();
1499 if(pChgSet->GetItemState(RES_SURROUND, false) == SfxItemState::SET ||
1500 pChgSet->GetItemState(RES_OPAQUE, false) == SfxItemState::SET ||
1501 pChgSet->GetItemState(RES_WRAP_INFLUENCE_ON_OBJPOS, false) == SfxItemState::SET)
1502 bUpdateSortedObjsList = true;
1504 break;
1505 default:
1506 assert(!"<SwDraw Contact::Modify(..)> - unhandled attribute?");
1508 lcl_NotifyBackgroundOfObj(*this, *GetMaster(), nullptr);
1509 NotifyBackgroundOfAllVirtObjs(nullptr);
1510 InvalidateObjs_(bUpdateSortedObjsList);
1513 // #i51474#
1514 GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
1516 else if (rHint.GetId() == SfxHintId::SwDrawFrameFormat)
1518 auto pDrawFrameFormatHint = static_cast<const sw::DrawFrameFormatHint*>(&rHint);
1519 switch(pDrawFrameFormatHint->m_eId)
1521 case sw::DrawFrameFormatHintId::DYING:
1522 delete this;
1523 break;
1524 case sw::DrawFrameFormatHintId::PREPPASTING:
1525 MoveObjToVisibleLayer(GetMaster());
1526 break;
1527 case sw::DrawFrameFormatHintId::PREP_INSERT_FLY:
1528 InsertMasterIntoDrawPage();
1529 // #i40845# - follow-up of #i35635#
1530 // move object to visible layer
1531 MoveObjToVisibleLayer(GetMaster());
1532 // tdf#135661 InsertMasterIntoDrawPage may have created a new
1533 // SwXShape with null m_pFormat; fix that
1534 SwXShape::AddExistingShapeToFormat(*GetMaster());
1535 break;
1536 case sw::DrawFrameFormatHintId::PREP_DELETE_FLY:
1537 RemoveMasterFromDrawPage();
1538 break;
1539 case sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS:
1540 case sw::DrawFrameFormatHintId::DELETE_FRAMES:
1541 DisconnectFromLayout();
1542 break;
1543 case sw::DrawFrameFormatHintId::MAKE_FRAMES:
1544 ConnectToLayout();
1545 break;
1546 case sw::DrawFrameFormatHintId::POST_RESTORE_FLY_ANCHOR:
1547 GetAnchoredObj(GetMaster())->MakeObjPos();
1548 break;
1549 default:
1553 else if (rHint.GetId() == SfxHintId::SwCheckDrawFrameFormatLayer)
1555 auto pCheckDrawFrameFormatLayerHint = static_cast<const sw::CheckDrawFrameFormatLayerHint*>(&rHint);
1556 *(pCheckDrawFrameFormatLayerHint->m_bCheckControlLayer) |= (GetMaster() && CheckControlLayer(GetMaster()));
1558 else if (rHint.GetId() == SfxHintId::SwContactChanged)
1560 auto pContactChangedHint = static_cast<const sw::ContactChangedHint*>(&rHint);
1561 if(!*pContactChangedHint->m_ppObject)
1562 *pContactChangedHint->m_ppObject = GetMaster();
1563 auto pObject = *pContactChangedHint->m_ppObject;
1564 Changed(*pObject, SdrUserCallType::Delete, pObject->GetLastBoundRect());
1566 else if (rHint.GetId() == SfxHintId::SwDrawFormatLayoutCopy)
1568 auto pDrawFormatLayoutCopyHint = static_cast<const sw::DrawFormatLayoutCopyHint*>(&rHint);
1569 const SwDrawFrameFormat& rFormat = static_cast<const SwDrawFrameFormat&>(rMod);
1570 rtl::Reference<SdrObject> xNewObj =
1571 pDrawFormatLayoutCopyHint->m_rDestDoc.CloneSdrObj(
1572 *GetMaster(),
1573 pDrawFormatLayoutCopyHint->m_rDestDoc.IsCopyIsMove() && &pDrawFormatLayoutCopyHint->m_rDestDoc == rFormat.GetDoc());
1574 new SwDrawContact(
1575 &pDrawFormatLayoutCopyHint->m_rDestFormat, xNewObj.get() );
1576 // #i49730# - notify draw frame format that position attributes are
1577 // already set, if the position attributes are already set at the
1578 // source draw frame format.
1579 if(rFormat.IsPosAttrSet())
1580 pDrawFormatLayoutCopyHint->m_rDestFormat.PosAttrSet();
1582 else if (rHint.GetId() == SfxHintId::SwRestoreFlyAnchor)
1584 auto pRestoreFlyAnchorHint = static_cast<const sw::RestoreFlyAnchorHint*>(&rHint);
1585 SdrObject* pObj = GetMaster();
1586 if(GetAnchorFrame() && !pObj->IsInserted())
1588 auto pDrawModel = const_cast<SwDrawFrameFormat&>(static_cast<const SwDrawFrameFormat&>(rMod)).GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1589 assert(pDrawModel);
1590 pDrawModel->GetPage(0)->InsertObject(pObj);
1592 pObj->SetRelativePos(pRestoreFlyAnchorHint->m_aPos);
1594 else if (rHint.GetId() == SfxHintId::SwCreatePortion)
1596 auto pCreatePortionHint = static_cast<const sw::CreatePortionHint*>(&rHint);
1597 if(*pCreatePortionHint->m_ppContact)
1598 return;
1599 *pCreatePortionHint->m_ppContact = this; // This is kind of ridiculous: the FrameFormat doesn't even hold a pointer to the contact itself, but here we are leaking it out randomly
1600 if(!GetAnchorFrame())
1602 // No direct positioning needed any more
1603 ConnectToLayout();
1604 // Move object to visible layer
1605 MoveObjToVisibleLayer(GetMaster());
1608 else if (rHint.GetId() == SfxHintId::SwCollectTextObjects)
1610 auto pCollectTextObjectsHint = static_cast<const sw::CollectTextObjectsHint*>(&rHint);
1611 auto pSdrO = GetMaster();
1612 if(!pSdrO)
1613 return;
1614 if(dynamic_cast<const SdrObjGroup*>(pSdrO))
1616 SdrObjListIter aListIter(*pSdrO, SdrIterMode::DeepNoGroups);
1617 //iterate inside of a grouped object
1618 while(aListIter.IsMore())
1620 SdrTextObj* pTextObj = DynCastSdrTextObj(aListIter.Next());
1621 if(pTextObj && pTextObj->HasText())
1622 pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1625 else if(SdrTextObj* pTextObj = DynCastSdrTextObj(pSdrO))
1627 if(pTextObj->HasText())
1628 pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1631 else if (rHint.GetId() == SfxHintId::SwGetZOrder)
1633 auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint);
1634 auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
1635 if (pFormat && pFormat->Which() == RES_DRAWFRMFMT)
1636 pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
1638 else if (rHint.GetId() == SfxHintId::SwGetObjectConnected)
1640 auto pConnectedHint = static_cast<const sw::GetObjectConnectedHint*>(&rHint);
1641 pConnectedHint->m_risConnected |= (GetAnchorFrame() != nullptr);
1645 // #i26791#
1646 // #i28701# - added parameter <_bUpdateSortedObjsList>
1647 void SwDrawContact::InvalidateObjs_( const bool _bUpdateSortedObjsList )
1649 for(const auto& rpDrawVirtObj : maDrawVirtObjs)
1650 // invalidate position of existing 'virtual' drawing objects
1652 SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
1653 // #i33313# - invalidation only for connected
1654 // 'virtual' drawing objects
1655 if ( pDrawVirtObj->IsConnected() )
1657 pDrawVirtObj->AnchoredObj().InvalidateObjPos();
1658 // #i28701#
1659 if ( _bUpdateSortedObjsList )
1661 pDrawVirtObj->AnchoredObj().UpdateObjInSortedList();
1666 // invalidate position of 'master' drawing object
1667 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( nullptr );
1668 pAnchoredObj->InvalidateObjPos();
1669 // #i28701#
1670 if ( _bUpdateSortedObjsList )
1672 pAnchoredObj->UpdateObjInSortedList();
1676 void SwDrawContact::DisconnectFromLayout( bool _bMoveMasterToInvisibleLayer )
1678 mbDisconnectInProgress = true;
1680 // --> #i36181# - notify background of drawing object
1681 if ( _bMoveMasterToInvisibleLayer &&
1682 !(GetFormat()->GetDoc()->IsInDtor()) &&
1683 GetAnchorFrame() && !GetAnchorFrame()->IsInDtor() )
1685 const tools::Rectangle aOldRect( maAnchoredDrawObj.GetObjRectWithSpaces().SVRect() );
1686 lcl_NotifyBackgroundOfObj( *this, *GetMaster(), &aOldRect );
1687 NotifyBackgroundOfAllVirtObjs( &aOldRect );
1690 // remove 'virtual' drawing objects from writer
1691 // layout and from drawing page
1692 for(auto& rpVirtDrawObj : maDrawVirtObjs)
1694 rpVirtDrawObj->RemoveFromWriterLayout();
1695 rpVirtDrawObj->RemoveFromDrawingPage();
1698 if ( maAnchoredDrawObj.GetAnchorFrame() )
1700 maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1703 if ( _bMoveMasterToInvisibleLayer && GetMaster() && GetMaster()->IsInserted() )
1705 SdrViewIter aIter( GetMaster() );
1706 for( SdrView* pView = aIter.FirstView(); pView;
1707 pView = aIter.NextView() )
1709 pView->MarkObj( GetMaster(), pView->GetSdrPageView(), true );
1712 // Instead of removing 'master' object from drawing page, move the
1713 // 'master' drawing object into the corresponding invisible layer.
1715 //static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess()->GetDrawModel()->GetPage(0)->
1716 // RemoveObject( GetMaster()->GetOrdNum() );
1717 // #i18447# - in order to consider group object correct
1718 // use new method <SwDrawContact::MoveObjToInvisibleLayer(..)>
1719 MoveObjToInvisibleLayer( GetMaster() );
1723 mbDisconnectInProgress = false;
1726 /// method to remove 'master' drawing object from drawing page.
1727 void SwDrawContact::RemoveMasterFromDrawPage()
1729 if ( GetMaster() )
1731 GetMaster()->SetUserCall( nullptr );
1732 if ( GetMaster()->IsInserted() )
1734 static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
1735 RemoveObject( GetMaster()->GetOrdNum() );
1740 // disconnect for a dedicated drawing object - could be 'master' or 'virtual'.
1741 // a 'master' drawing object will disconnect a 'virtual' drawing object
1742 // in order to take its place.
1743 // #i19919# - no special case, if drawing object isn't in
1744 // page header/footer, in order to get drawing objects in repeating table headers
1745 // also working.
1746 void SwDrawContact::DisconnectObjFromLayout( SdrObject* _pDrawObj )
1748 if ( auto pSwDrawVirtObj = dynamic_cast<SwDrawVirtObj*>( _pDrawObj) )
1750 pSwDrawVirtObj->RemoveFromWriterLayout();
1751 pSwDrawVirtObj->RemoveFromDrawingPage();
1753 else
1755 const auto ppVirtDrawObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
1756 [] (const rtl::Reference<SwDrawVirtObj>& pObj) { return pObj->IsConnected(); }));
1758 if(ppVirtDrawObj != maDrawVirtObjs.end())
1760 // replace found 'virtual' drawing object by 'master' drawing
1761 // object and disconnect the 'virtual' one
1762 SwDrawVirtObj* pDrawVirtObj(ppVirtDrawObj->get());
1763 SwFrame* pNewAnchorFrameOfMaster = pDrawVirtObj->AnchorFrame();
1764 // disconnect 'virtual' drawing object
1765 pDrawVirtObj->RemoveFromWriterLayout();
1766 pDrawVirtObj->RemoveFromDrawingPage();
1767 // disconnect 'master' drawing object from current frame
1768 GetAnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1769 // re-connect 'master' drawing object to frame of found 'virtual'
1770 // drawing object.
1771 pNewAnchorFrameOfMaster->AppendDrawObj( maAnchoredDrawObj );
1773 else
1775 // no connected 'virtual' drawing object found. Thus, disconnect
1776 // completely from layout.
1777 DisconnectFromLayout();
1782 static SwTextFrame* lcl_GetFlyInContentAnchor( SwTextFrame* _pProposedAnchorFrame,
1783 SwPosition const& rAnchorPos)
1785 SwTextFrame* pAct = _pProposedAnchorFrame;
1786 SwTextFrame* pTmp;
1787 TextFrameIndex const nTextOffset(_pProposedAnchorFrame->MapModelToViewPos(rAnchorPos));
1790 pTmp = pAct;
1791 pAct = pTmp->GetFollow();
1793 while (pAct && nTextOffset >= pAct->GetOffset());
1794 return pTmp;
1797 void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
1799 // *no* connect to layout during disconnection from layout.
1800 if ( mbDisconnectInProgress )
1802 OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> called during disconnection.");
1803 return;
1806 // --> #i33909# - *no* connect to layout, if 'master' drawing
1807 // object isn't inserted in the drawing page
1808 if ( !GetMaster()->IsInserted() )
1810 OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> - master drawing object not inserted -> no connect to layout. Please inform od@openoffice.org" );
1811 return;
1814 SwFrameFormat* pDrawFrameFormat = static_cast<SwFrameFormat*>(GetRegisteredIn());
1816 if( !pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell() )
1817 return;
1819 // remove 'virtual' drawing objects from writer
1820 // layout and from drawing page, and remove 'master' drawing object from
1821 // writer layout - 'master' object will remain in drawing page.
1822 DisconnectFromLayout( false );
1824 if ( !pAnch )
1826 pAnch = &(pDrawFrameFormat->GetAnchor());
1829 switch ( pAnch->GetAnchorId() )
1831 case RndStdIds::FLY_AT_PAGE:
1833 sal_uInt16 nPgNum = pAnch->GetPageNum();
1834 SwViewShell *pShell = pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell();
1835 if( !pShell )
1836 break;
1837 SwRootFrame* pRoot = pShell->GetLayout();
1838 SwPageFrame *pPage = static_cast<SwPageFrame*>(pRoot->Lower());
1840 for ( sal_uInt16 i = 1; i < nPgNum && pPage; ++i )
1842 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1845 if ( pPage )
1847 pPage->AppendDrawObj( maAnchoredDrawObj );
1849 else
1850 //Looks stupid but is allowed (compare SwFEShell::SetPageObjsNewPage)
1851 pRoot->SetAssertFlyPages();
1853 break;
1855 case RndStdIds::FLY_AT_CHAR:
1856 case RndStdIds::FLY_AT_PARA:
1857 case RndStdIds::FLY_AT_FLY:
1858 case RndStdIds::FLY_AS_CHAR:
1860 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1862 ClrContourCache( GetMaster() );
1864 // support drawing objects in header/footer,
1865 // but not control objects:
1866 // anchor at first found frame the 'master' object and
1867 // at the following frames 'virtual' drawing objects.
1868 // Note: method is similar to <SwFlyFrameFormat::MakeFrames(..)>
1869 sw::BroadcastingModify *pModify = nullptr;
1870 if( pAnch->GetAnchorNode() )
1872 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AT_FLY )
1874 SwNodeIndex aIdx( *pAnch->GetAnchorNode() );
1875 SwContentNode* pCNd = pDrawFrameFormat->GetDoc()->GetNodes().GoNext( &aIdx );
1876 if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
1877 pModify = pCNd;
1878 else
1880 const SwNode& rIdx = *pAnch->GetAnchorNode();
1881 for(sw::SpzFrameFormat* pFlyFormat :*(pDrawFrameFormat->GetDoc()->GetSpzFrameFormats()))
1883 if( pFlyFormat->GetContent().GetContentIdx() &&
1884 rIdx == pFlyFormat->GetContent().GetContentIdx()->GetNode() )
1886 pModify = pFlyFormat;
1887 break;
1892 else
1894 pModify = pAnch->GetAnchorNode()->GetContentNode();
1898 // #i29199# - It is possible, that
1899 // the anchor doesn't exist - E.g., reordering the
1900 // sub-documents in a master document.
1901 // Note: The anchor will be inserted later.
1902 if ( !pModify )
1904 // break to end of the current switch case.
1905 break;
1908 SwIterator<SwFrame, sw::BroadcastingModify, sw::IteratorMode::UnwrapMulti> aIter(*pModify);
1909 SwFrame* pAnchorFrameOfMaster = nullptr;
1910 for( SwFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1912 // append drawing object, if
1913 // (1) proposed anchor frame isn't a follow and...
1914 const bool bFollow = pFrame->IsContentFrame() && static_cast<SwContentFrame*>(pFrame)->IsFollow();
1915 if (bFollow)
1916 continue;
1918 // (2) drawing object isn't a control object to be anchored
1919 // in header/footer.
1920 const bool bControlInHF = ::CheckControlLayer(GetMaster()) && pFrame->FindFooterOrHeader();
1921 // tdf#129542 but make an exception for control objects so they can get added to just the first frame,
1922 // the Master Anchor Frame and not the others
1923 if (bControlInHF && pAnchorFrameOfMaster)
1924 continue;
1926 bool bAdd;
1927 if (RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId())
1928 bAdd = true;
1929 else
1931 assert(pFrame->IsTextFrame());
1932 bAdd = IsAnchoredObjShown(*static_cast<SwTextFrame*>(pFrame), *pAnch);
1935 if( bAdd )
1937 if ( RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId() && !pFrame->IsFlyFrame() )
1939 pFrame = pFrame->FindFlyFrame();
1940 assert(pFrame);
1943 // find correct follow for as character anchored objects
1944 if ((pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR) &&
1945 pFrame->IsTextFrame() )
1947 pFrame = lcl_GetFlyInContentAnchor(
1948 static_cast<SwTextFrame*>(pFrame),
1949 *pAnch->GetContentAnchor());
1952 if ( !pAnchorFrameOfMaster )
1954 // append 'master' drawing object
1955 pAnchorFrameOfMaster = pFrame;
1957 const SwFrameFormat* pFlyFormat = nullptr;
1958 if (!maAnchoredDrawObj.GetDrawObj()->IsGroupObject())
1960 pFlyFormat = SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_DRAWFRMFMT);
1963 if (pFlyFormat)
1965 // This is a master draw object and it has an associated fly format.
1966 // See if a fly frame is already inserted to the layout: if so, this
1967 // master draw object should be ordered directly before the fly one.
1968 if (const SwSortedObjs* pObjs = pFrame->GetDrawObjs())
1970 for (const SwAnchoredObject* pAnchoredObj : *pObjs)
1972 if (&pAnchoredObj->GetFrameFormat() == pFlyFormat)
1974 SdrPage* pDrawPage = pAnchoredObj->GetDrawObj()->getSdrPageFromSdrObject();
1975 if (pDrawPage)
1977 sal_uInt32 nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
1978 if (maAnchoredDrawObj.GetDrawObj()->GetOrdNum() >= nOrdNum)
1980 pDrawPage->SetObjectOrdNum(maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect(), nOrdNum);
1982 else
1984 pDrawPage->SetObjectOrdNum(nOrdNum, maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect() + 1);
1986 break;
1993 pFrame->AppendDrawObj( maAnchoredDrawObj );
1995 else
1997 // append 'virtual' drawing object
1998 SwDrawVirtObj* pDrawVirtObj = AddVirtObj(*pFrame);
1999 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
2001 ClrContourCache( pDrawVirtObj );
2003 pFrame->AppendDrawObj( pDrawVirtObj->AnchoredObj() );
2005 pDrawVirtObj->ActionChanged();
2008 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
2010 pFrame->InvalidatePrt();
2015 break;
2016 default:
2017 assert(!"Unknown Anchor.");
2018 break;
2020 if ( GetAnchorFrame() )
2022 ::setContextWritingMode( maAnchoredDrawObj.DrawObj(), GetAnchorFrame() );
2023 // #i26791# - invalidate objects instead of direct positioning
2024 InvalidateObjs_();
2028 /// insert 'master' drawing object into drawing page
2029 void SwDrawContact::InsertMasterIntoDrawPage()
2031 if ( !GetMaster()->IsInserted() )
2033 GetFormat()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)
2034 ->InsertObject( GetMaster(), GetMaster()->GetOrdNumDirect() );
2036 GetMaster()->SetUserCall( this );
2039 SwPageFrame* SwDrawContact::FindPage( const SwRect &rRect )
2041 // --> #i28701# - use method <GetPageFrame()>
2042 SwPageFrame* pPg = GetPageFrame();
2043 if ( !pPg && GetAnchorFrame() )
2044 pPg = GetAnchorFrame()->FindPageFrame();
2045 if ( pPg )
2046 pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( rRect, pPg )));
2047 return pPg;
2050 void SwDrawContact::ChkPage()
2052 if ( mbDisconnectInProgress )
2054 OSL_FAIL( "<SwDrawContact::ChkPage()> called during disconnection." );
2055 return;
2058 // --> #i28701#
2059 SwPageFrame* pPg = ( maAnchoredDrawObj.GetAnchorFrame() &&
2060 maAnchoredDrawObj.GetAnchorFrame()->IsPageFrame() )
2061 ? GetPageFrame()
2062 : FindPage( SwRect(GetMaster()->GetCurrentBoundRect()) );
2063 if ( GetPageFrame() == pPg )
2064 return;
2066 // if drawing object is anchor in header/footer a change of the page
2067 // is a dramatic change. Thus, completely re-connect to the layout
2068 if ( maAnchoredDrawObj.GetAnchorFrame() &&
2069 maAnchoredDrawObj.GetAnchorFrame()->FindFooterOrHeader() )
2071 ConnectToLayout();
2073 else
2075 // --> #i28701# - use methods <GetPageFrame()> and <SetPageFrame>
2076 if ( GetPageFrame() )
2077 GetPageFrame()->RemoveDrawObjFromPage( maAnchoredDrawObj );
2078 pPg->AppendDrawObjToPage( maAnchoredDrawObj );
2079 maAnchoredDrawObj.SetPageFrame( pPg );
2083 // Important note:
2084 // method is called by method <SwDPage::ReplaceObject(..)>, which called its
2085 // corresponding superclass method <FmFormPage::ReplaceObject(..)>.
2086 // Note: 'master' drawing object *has* to be connected to layout triggered
2087 // by the caller of this, if method is called.
2088 void SwDrawContact::ChangeMasterObject(SdrObject* pNewMaster)
2090 DisconnectFromLayout( false );
2091 // consider 'virtual' drawing objects
2092 RemoveAllVirtObjs();
2094 GetMaster()->SetUserCall( nullptr );
2095 if(pNewMaster)
2096 maAnchoredDrawObj.SetDrawObj(*pNewMaster);
2097 else
2098 mbMasterObjCleared = true;
2099 GetMaster()->SetUserCall( this );
2101 InvalidateObjs_();
2104 /// get data collection of anchored objects, handled by with contact
2105 void SwDrawContact::GetAnchoredObjs(std::vector<SwAnchoredObject*>& o_rAnchoredObjs) const
2107 o_rAnchoredObjs.push_back(const_cast<SwAnchoredDrawObject*>(&maAnchoredDrawObj));
2109 for(auto& rpDrawVirtObj : maDrawVirtObjs)
2110 o_rAnchoredObjs.push_back(&rpDrawVirtObj->AnchoredObj());
2113 // AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed
2114 // since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj.
2115 // For paint, that offset is used by setting at the OutputDevice; for primitives this is
2116 // not possible since we have no OutputDevice, but define the geometry itself.
2118 namespace sdr::contact
2120 namespace {
2122 class VOCOfDrawVirtObj : public ViewObjectContactOfSdrObj
2124 protected:
2126 * This method is responsible for creating the graphical visualisation data which is
2127 * stored/cached in the local primitive. Default gets view-independent Primitive from
2128 * the ViewContact using ViewContact::getViewIndependentPrimitive2DContainer(), takes
2129 * care of visibility, handles glue and ghosted.
2131 * This method will not handle included hierarchies and not check geometric visibility.
2133 virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
2135 public:
2136 VOCOfDrawVirtObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
2137 : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
2142 class VCOfDrawVirtObj : public ViewContactOfVirtObj
2144 protected:
2145 /** Create an Object-Specific ViewObjectContact, set ViewContact and ObjectContact.
2147 * Always needs to return something. Default is to create a standard ViewObjectContact
2148 * containing the given ObjectContact and *this.
2150 virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
2152 public:
2153 /// basic constructor, used from SdrObject.
2154 explicit VCOfDrawVirtObj(SwDrawVirtObj& rObj)
2155 : ViewContactOfVirtObj(rObj)
2159 /// access to SwDrawVirtObj
2160 SwDrawVirtObj& GetSwDrawVirtObj() const
2162 return static_cast<SwDrawVirtObj&>(mrObject);
2167 } // end of namespace sdr::contact
2169 namespace sdr::contact
2171 /// recursively collect primitive data from given VOC with given offset
2172 static void impAddPrimitivesFromGroup(const ViewObjectContact& rVOC, const basegfx::B2DHomMatrix& rOffsetMatrix, const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DContainer& rxTarget)
2174 const sal_uInt32 nSubHierarchyCount(rVOC.GetViewContact().GetObjectCount());
2176 for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
2178 const ViewObjectContact& rCandidate(rVOC.GetViewContact().GetViewContact(a).GetViewObjectContact(rVOC.GetObjectContact()));
2180 if(rCandidate.GetViewContact().GetObjectCount())
2182 // is a group object itself, call recursively
2183 impAddPrimitivesFromGroup(rCandidate, rOffsetMatrix, rDisplayInfo, rxTarget);
2185 else
2187 // single object, add primitives; check model-view visibility
2188 if(rCandidate.isPrimitiveVisible(rDisplayInfo))
2190 drawinglayer::primitive2d::Primitive2DContainer aNewSequence(rCandidate.getPrimitive2DSequence(rDisplayInfo));
2192 if(!aNewSequence.empty())
2194 // get ranges
2195 const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(rCandidate.GetObjectContact().getViewInformation2D());
2196 const basegfx::B2DRange& aViewRange(rViewInformation2D.getViewport());
2197 basegfx::B2DRange aObjectRange(rCandidate.getObjectRange());
2199 // correct with virtual object's offset
2200 aObjectRange.transform(rOffsetMatrix);
2202 // check geometrical visibility (with offset)
2203 if(!aViewRange.overlaps(aObjectRange))
2205 // not visible, release
2206 aNewSequence.clear();
2210 if(!aNewSequence.empty())
2212 rxTarget.append(aNewSequence);
2219 void VOCOfDrawVirtObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
2221 // tdf#91260 have already checked top-level one is on the right page
2222 assert(isPrimitiveVisible(rDisplayInfo));
2223 // nasty corner case: override to clear page frame to disable the
2224 // sub-objects' anchor check, because their anchor is always on
2225 // the first page that the page style is applied to
2226 DisplayInfo aDisplayInfo(rDisplayInfo);
2227 aDisplayInfo.SetWriterPageFrame(basegfx::B2IRectangle());
2228 const VCOfDrawVirtObj& rVC = static_cast< const VCOfDrawVirtObj& >(GetViewContact());
2229 const SdrObject& rReferencedObject = rVC.GetSwDrawVirtObj().GetReferencedObj();
2230 drawinglayer::primitive2d::Primitive2DContainer xRetval;
2232 // create offset transformation
2233 basegfx::B2DHomMatrix aOffsetMatrix;
2234 const Point aLocalOffset(rVC.GetSwDrawVirtObj().GetOffset());
2236 if(aLocalOffset.X() || aLocalOffset.Y())
2238 aOffsetMatrix.set(0, 2, aLocalOffset.X());
2239 aOffsetMatrix.set(1, 2, aLocalOffset.Y());
2242 if(dynamic_cast<const SdrObjGroup*>( &rReferencedObject) != nullptr)
2244 // group object. Since the VOC/OC/VC hierarchy does not represent the
2245 // hierarchy virtual objects when they have group objects
2246 // (ViewContactOfVirtObj::GetObjectCount() returns null for that purpose)
2247 // to avoid multiple usages of VOCs (which would not work), the primitives
2248 // for the sub-hierarchy need to be collected here
2250 // Get the VOC of the referenced object (the Group) and fetch primitives from it
2251 const ViewObjectContact& rVOCOfRefObj = rReferencedObject.GetViewContact().GetViewObjectContact(GetObjectContact());
2252 impAddPrimitivesFromGroup(rVOCOfRefObj, aOffsetMatrix, aDisplayInfo, xRetval);
2254 else
2256 // single object, use method from referenced object to get the Primitive2DSequence
2257 rReferencedObject.GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
2260 if(!xRetval.empty())
2262 // create transform primitive
2263 drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::TransformPrimitive2D(aOffsetMatrix, std::move(xRetval)));
2264 xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
2267 rVisitor.visit(xRetval);
2270 ViewObjectContact& VCOfDrawVirtObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
2272 return *(new VOCOfDrawVirtObj(rObjectContact, *this));
2275 } // end of namespace sdr::contact
2277 /// implementation of class <SwDrawVirtObj>
2278 std::unique_ptr<sdr::contact::ViewContact> SwDrawVirtObj::CreateObjectSpecificViewContact()
2280 return std::make_unique<sdr::contact::VCOfDrawVirtObj>(*this);
2283 SwDrawVirtObj::SwDrawVirtObj(
2284 SdrModel& rSdrModel,
2285 SdrObject& _rNewObj,
2286 SwDrawContact& _rDrawContact)
2287 : SdrVirtObj(rSdrModel, _rNewObj ),
2288 mrDrawContact(_rDrawContact)
2290 // #i26791#
2291 maAnchoredDrawObj.SetDrawObj( *this );
2293 // #i35635# - set initial position out of sight
2294 NbcMove( Size( -16000, -16000 ) );
2297 SwDrawVirtObj::SwDrawVirtObj(
2298 SdrModel& rSdrModel,
2299 SwDrawVirtObj const & rSource)
2300 : SdrVirtObj(rSdrModel, rSource),
2301 mrDrawContact(rSource.mrDrawContact)
2303 // #i26791#
2304 maAnchoredDrawObj.SetDrawObj( *this );
2306 // #i35635# - set initial position out of sight
2307 NbcMove( Size( -16000, -16000 ) );
2309 // Note: Members <maAnchoredDrawObj> and <mrDrawContact>
2310 // haven't to be considered.
2313 SwDrawVirtObj::~SwDrawVirtObj()
2317 rtl::Reference<SdrObject> SwDrawVirtObj::CloneSdrObject(SdrModel& rTargetModel) const
2319 return new SwDrawVirtObj(rTargetModel, *this);
2322 const SwFrame* SwDrawVirtObj::GetAnchorFrame() const
2324 // #i26791# - use new member <maAnchoredDrawObj>
2325 return maAnchoredDrawObj.GetAnchorFrame();
2328 SwFrame* SwDrawVirtObj::AnchorFrame()
2330 // #i26791# - use new member <maAnchoredDrawObj>
2331 return maAnchoredDrawObj.AnchorFrame();
2334 void SwDrawVirtObj::RemoveFromWriterLayout()
2336 // remove contact object from frame for 'virtual' drawing object
2337 // #i26791# - use new member <maAnchoredDrawObj>
2338 if ( maAnchoredDrawObj.GetAnchorFrame() )
2340 maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
2344 void SwDrawVirtObj::AddToDrawingPage(SwFrame const& rAnchorFrame)
2346 // determine 'master'
2347 SdrObject* pOrgMasterSdrObj = mrDrawContact.GetMaster();
2349 // insert 'virtual' drawing object into page, set layer and user call.
2350 SdrPage* pDrawPg = pOrgMasterSdrObj->getSdrPageFromSdrObject();
2351 // default: insert before master object
2352 auto nOrdNum(GetReferencedObj().GetOrdNum());
2354 // maintain invariant that a shape's textbox immediately follows the shape
2355 // also for the multiple SdrDrawVirtObj created for shapes in header/footer
2356 if (SwFrameFormat const*const pFlyFormat =
2357 SwTextBoxHelper::getOtherTextBoxFormat(mrDrawContact.GetFormat(), RES_DRAWFRMFMT))
2359 // this is for the case when the flyframe SdrVirtObj is created before the draw one
2360 if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
2362 for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
2364 if (&pAnchoredObj->GetFrameFormat() == pFlyFormat)
2366 assert(dynamic_cast<SwFlyFrame const*>(pAnchoredObj));
2368 if (pAnchoredObj->GetDrawObj()->GetOrdNum() >= GetReferencedObj().GetOrdNum())
2370 // This virtual draw object has an associated fly one, but the fly's index
2371 // is not below the masters, fix it up.
2372 if (pDrawPg)
2374 pDrawPg->SetObjectOrdNum(pAnchoredObj->GetDrawObj()->GetOrdNumDirect(), GetReferencedObj().GetOrdNum());
2378 nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
2379 // the master SdrObj should have the highest index
2380 assert(nOrdNum < GetReferencedObj().GetOrdNum());
2381 break;
2385 // this happens on initial insertion, the draw object is created first
2386 SAL_INFO_IF(GetReferencedObj().GetOrdNum() == nOrdNum, "sw", "AddToDrawingPage: cannot find SdrObject for text box's shape");
2389 // #i27030# - apply order number of referenced object
2390 if ( nullptr != pDrawPg )
2392 // #i27030# - apply order number of referenced object
2393 pDrawPg->InsertObject(this, nOrdNum);
2395 else
2397 pDrawPg = getSdrPageFromSdrObject();
2398 if ( pDrawPg )
2400 pDrawPg->SetObjectOrdNum(GetOrdNumDirect(), nOrdNum);
2402 else
2404 SetOrdNum(nOrdNum);
2407 SetUserCall( &mrDrawContact );
2410 void SwDrawVirtObj::RemoveFromDrawingPage()
2412 SetUserCall( nullptr );
2413 if ( getSdrPageFromSdrObject() )
2415 getSdrPageFromSdrObject()->RemoveObject( GetOrdNum() );
2419 /// Is 'virtual' drawing object connected to writer layout and to drawing layer?
2420 bool SwDrawVirtObj::IsConnected() const
2422 bool bRetVal = GetAnchorFrame() &&
2423 ( getSdrPageFromSdrObject() && GetUserCall() );
2425 return bRetVal;
2428 void SwDrawVirtObj::NbcSetAnchorPos(const Point& rPnt)
2430 SdrObject::NbcSetAnchorPos( rPnt );
2433 // #i97197#
2434 // the methods relevant for positioning
2436 const tools::Rectangle& SwDrawVirtObj::GetCurrentBoundRect() const
2438 if (getOutRectangle().IsEmpty())
2440 const_cast<SwDrawVirtObj*>(this)->RecalcBoundRect();
2443 return getOutRectangle();
2446 const tools::Rectangle& SwDrawVirtObj::GetLastBoundRect() const
2448 return getOutRectangle();
2451 Point SwDrawVirtObj::GetOffset() const
2453 // do NOT use IsEmpty() here, there is already a useful offset
2454 // in the position
2455 if (getOutRectangle() == tools::Rectangle())
2457 return Point();
2459 else
2461 return getOutRectangle().TopLeft() - GetReferencedObj().GetCurrentBoundRect().TopLeft();
2465 void SwDrawVirtObj::SetBoundRectDirty()
2467 // do nothing to not lose model information in aOutRect
2470 void SwDrawVirtObj::RecalcBoundRect()
2472 // #i26791# - switch order of calling <GetOffset()> and
2473 // <ReferencedObj().GetCurrentBoundRect()>, because <GetOffset()> calculates
2474 // its value by the 'BoundRect' of the referenced object.
2476 const Point aOffset(GetOffset());
2477 setOutRectangle(ReferencedObj().GetCurrentBoundRect() + aOffset);
2480 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeXorPoly() const
2482 basegfx::B2DPolyPolygon aRetval(mxRefObj->TakeXorPoly());
2483 aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2485 return aRetval;
2488 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeContour() const
2490 basegfx::B2DPolyPolygon aRetval(mxRefObj->TakeContour());
2491 aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2493 return aRetval;
2496 void SwDrawVirtObj::AddToHdlList(SdrHdlList& rHdlList) const
2498 SdrHdlList tmpList(nullptr);
2499 mxRefObj->AddToHdlList(tmpList);
2501 size_t cnt = tmpList.GetHdlCount();
2502 for(size_t i=0; i < cnt; ++i)
2504 SdrHdl* pHdl = tmpList.GetHdl(i);
2505 Point aP(pHdl->GetPos() + GetOffset());
2506 pHdl->SetPos(aP);
2508 tmpList.MoveTo(rHdlList);
2511 void SwDrawVirtObj::NbcMove(const Size& rSiz)
2513 SdrObject::NbcMove( rSiz );
2516 void SwDrawVirtObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
2518 mxRefObj->NbcResize(rRef - GetOffset(), xFact, yFact);
2519 SetBoundAndSnapRectsDirty();
2522 void SwDrawVirtObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
2524 mxRefObj->NbcRotate(rRef - GetOffset(), nAngle, sn, cs);
2525 SetBoundAndSnapRectsDirty();
2528 void SwDrawVirtObj::NbcMirror(const Point& rRef1, const Point& rRef2)
2530 mxRefObj->NbcMirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2531 SetBoundAndSnapRectsDirty();
2534 void SwDrawVirtObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
2536 mxRefObj->NbcShear(rRef - GetOffset(), nAngle, tn, bVShear);
2537 SetBoundAndSnapRectsDirty();
2540 void SwDrawVirtObj::Move(const Size& rSiz)
2542 SdrObject::Move( rSiz );
2545 void SwDrawVirtObj::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
2547 if(xFact.GetNumerator() != xFact.GetDenominator() || yFact.GetNumerator() != yFact.GetDenominator())
2549 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2550 mxRefObj->Resize(rRef - GetOffset(), xFact, yFact, bUnsetRelative);
2551 SetBoundAndSnapRectsDirty();
2552 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2556 void SwDrawVirtObj::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
2558 if(nAngle)
2560 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2561 mxRefObj->Rotate(rRef - GetOffset(), nAngle, sn, cs);
2562 SetBoundAndSnapRectsDirty();
2563 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2567 void SwDrawVirtObj::Mirror(const Point& rRef1, const Point& rRef2)
2569 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2570 mxRefObj->Mirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2571 SetBoundAndSnapRectsDirty();
2572 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2575 void SwDrawVirtObj::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
2577 if(nAngle)
2579 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2580 mxRefObj->Shear(rRef - GetOffset(), nAngle, tn, bVShear);
2581 SetBoundAndSnapRectsDirty();
2582 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2586 void SwDrawVirtObj::RecalcSnapRect()
2588 aSnapRect = mxRefObj->GetSnapRect();
2589 aSnapRect += GetOffset();
2592 const tools::Rectangle& SwDrawVirtObj::GetSnapRect() const
2594 const_cast<SwDrawVirtObj*>(this)->aSnapRect = mxRefObj->GetSnapRect();
2595 const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
2597 return aSnapRect;
2600 void SwDrawVirtObj::SetSnapRect(const tools::Rectangle& rRect)
2602 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2603 tools::Rectangle aR(rRect);
2604 aR -= GetOffset();
2605 mxRefObj->SetSnapRect(aR);
2606 SetBoundAndSnapRectsDirty();
2607 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2610 void SwDrawVirtObj::NbcSetSnapRect(const tools::Rectangle& rRect)
2612 tools::Rectangle aR(rRect);
2613 aR -= GetOffset();
2614 SetBoundAndSnapRectsDirty();
2615 mxRefObj->NbcSetSnapRect(aR);
2618 const tools::Rectangle& SwDrawVirtObj::GetLogicRect() const
2620 const_cast<SwDrawVirtObj*>(this)->aSnapRect = mxRefObj->GetLogicRect();
2621 const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
2623 return aSnapRect;
2626 void SwDrawVirtObj::SetLogicRect(const tools::Rectangle& rRect)
2628 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2629 tools::Rectangle aR(rRect);
2630 aR -= GetOffset();
2631 mxRefObj->SetLogicRect(aR);
2632 SetBoundAndSnapRectsDirty();
2633 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2636 void SwDrawVirtObj::NbcSetLogicRect(const tools::Rectangle& rRect)
2638 tools::Rectangle aR(rRect);
2639 aR -= GetOffset();
2640 mxRefObj->NbcSetLogicRect(aR);
2641 SetBoundAndSnapRectsDirty();
2644 Point SwDrawVirtObj::GetSnapPoint(sal_uInt32 i) const
2646 Point aP(mxRefObj->GetSnapPoint(i));
2647 aP += GetOffset();
2649 return aP;
2652 Point SwDrawVirtObj::GetPoint(sal_uInt32 i) const
2654 return mxRefObj->GetPoint(i) + GetOffset();
2657 void SwDrawVirtObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
2659 Point aP(rPnt);
2660 aP -= GetOffset();
2661 mxRefObj->SetPoint(aP, i);
2662 SetBoundAndSnapRectsDirty();
2665 bool SwDrawVirtObj::HasTextEdit() const
2667 return mxRefObj->HasTextEdit();
2670 // override 'layer' methods for 'virtual' drawing object to assure
2671 // that layer of 'virtual' object is the layer of the referenced object.
2672 SdrLayerID SwDrawVirtObj::GetLayer() const
2674 return GetReferencedObj().GetLayer();
2677 void SwDrawVirtObj::NbcSetLayer(SdrLayerID nLayer)
2679 ReferencedObj().NbcSetLayer( nLayer );
2680 SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2683 void SwDrawVirtObj::SetLayer(SdrLayerID nLayer)
2685 ReferencedObj().SetLayer( nLayer );
2686 SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2689 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */