nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / core / draw / dcontact.cxx
blob82934ce74aa7b94919e470b148bc97addb3d35a3
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 <editeng/lrspitem.hxx>
23 #include <svx/svdpage.hxx>
24 #include <svx/svditer.hxx>
25 #include <svx/svdogrp.hxx>
26 #include <svx/svdotext.hxx>
27 #include <svx/svdmodel.hxx>
28 #include <svx/svdviter.hxx>
29 #include <svx/svdview.hxx>
30 #include <svx/sdr/contact/displayinfo.hxx>
31 #include <svx/sdr/contact/objectcontact.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 <docary.hxx>
60 #include <sortedobjs.hxx>
61 #include <basegfx/matrix/b2dhommatrix.hxx>
62 #include <basegfx/matrix/b2dhommatrixtools.hxx>
63 #include <svx/sdr/contact/viewcontactofvirtobj.hxx>
64 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
65 #include <drawinglayer/geometry/viewinformation2d.hxx>
66 #include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
67 #include <com/sun/star/text/WritingMode2.hpp>
68 #include <calbck.hxx>
69 #include <algorithm>
70 #include <txtfly.hxx>
71 #include <sal/log.hxx>
73 using namespace ::com::sun::star;
75 namespace
77 /** unary function used to find a 'virtual' drawing object anchored at a given frame */
78 struct VirtObjAnchoredAtFramePred
80 const SwFrame* m_pAnchorFrame;
82 // #i26791# - compare with master frame
83 static const SwFrame* FindFrame(const SwFrame* pFrame)
85 if(!pFrame || !pFrame->IsContentFrame())
86 return pFrame;
87 auto pContentFrame = static_cast<const SwContentFrame*>(pFrame);
88 while(pContentFrame->IsFollow())
89 pContentFrame = pContentFrame->FindMaster();
90 return pContentFrame;
93 VirtObjAnchoredAtFramePred(const SwFrame* pAnchorFrame)
94 : m_pAnchorFrame(FindFrame(pAnchorFrame))
97 bool operator()(const SwDrawVirtObjPtr& rpDrawVirtObj)
99 return FindFrame(rpDrawVirtObj->GetAnchorFrame()) == m_pAnchorFrame;
104 void setContextWritingMode(SdrObject* pObj, SwFrame const * pAnchor)
106 if(!pObj || !pAnchor)
107 return;
108 short nWritingDirection =
109 pAnchor->IsVertical() ? text::WritingMode2::TB_RL :
110 pAnchor->IsRightToLeft() ? text::WritingMode2::RL_TB :
111 text::WritingMode2::LR_TB;
112 pObj->SetContextWritingMode(nWritingDirection);
116 /** The Get reverse way: seeks the format to the specified object.
117 * If the object is a SwVirtFlyDrawObj then the format of this
118 * will be acquired.
119 * Otherwise it is just a simple drawing object. This has a
120 * UserCall and is the client of the searched format.
122 SwFrameFormat *FindFrameFormat( SdrObject *pObj )
124 SwFrameFormat* pRetval = nullptr;
126 if (SwVirtFlyDrawObj* pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
128 pRetval = pFlyDrawObj->GetFormat();
130 else
132 SwContact* pContact = GetUserCall(pObj);
133 if ( pContact )
135 pRetval = pContact->GetFormat();
138 return pRetval;
141 bool HasWrap( const SdrObject* pObj )
143 if ( pObj )
145 const SwFrameFormat* pFormat = ::FindFrameFormat( pObj );
146 if ( pFormat )
148 return css::text::WrapTextMode_THROUGH != pFormat->GetSurround().GetSurround();
152 return false;
155 /// returns the BoundRect _inclusive_ distance of the object.
156 SwRect GetBoundRectOfAnchoredObj( const SdrObject* pObj )
158 SwRect aRet( pObj->GetCurrentBoundRect() );
159 // #i68520# - call cache of <SwAnchoredObject>
160 SwContact* pContact( GetUserCall( pObj ) );
161 if ( pContact )
163 const SwAnchoredObject* pAnchoredObj( pContact->GetAnchoredObj( pObj ) );
164 if ( pAnchoredObj )
166 aRet = pAnchoredObj->GetObjRectWithSpaces();
169 return aRet;
172 /// Returns the UserCall if applicable from the group object
173 SwContact* GetUserCall( const SdrObject* pObj )
175 SdrObject *pTmp;
176 while ( !pObj->GetUserCall() && nullptr != (pTmp = pObj->getParentSdrObjectFromSdrObject()) )
177 pObj = pTmp;
178 assert((!pObj->GetUserCall() || nullptr != dynamic_cast<const SwContact*>(pObj->GetUserCall())) &&
179 "<::GetUserCall(..)> - wrong type of found object user call." );
180 return static_cast<SwContact*>(pObj->GetUserCall());
183 /// Returns true if the SrdObject is a Marquee-Object (scrolling text)
184 bool IsMarqueeTextObj( const SdrObject& rObj )
186 if (SdrInventor::Default != rObj.GetObjInventor() ||
187 OBJ_TEXT != rObj.GetObjIdentifier())
188 return false;
189 SdrTextAniKind eTKind = static_cast<const SdrTextObj&>(rObj).GetTextAniKind();
190 return ( SdrTextAniKind::Scroll == eTKind
191 || SdrTextAniKind::Alternate == eTKind || SdrTextAniKind::Slide == eTKind );
194 SwContact::SwContact( SwFrameFormat *pToRegisterIn ) :
195 SwClient( pToRegisterIn ),
196 mbInDTOR( false )
199 SwContact::~SwContact()
201 SetInDTOR();
205 void SwContact::SetInDTOR()
207 mbInDTOR = true;
210 /// method to move drawing object to corresponding visible layer
211 void SwContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
213 // #i46297# - notify background about the arriving of
214 // the object and invalidate its position.
215 const bool bNotify( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
217 MoveObjToLayer( true, _pDrawObj );
219 // #i46297#
220 if ( !bNotify )
221 return;
223 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
224 assert(pAnchoredObj);
225 ::setContextWritingMode( _pDrawObj, pAnchoredObj->GetAnchorFrameContainingAnchPos() );
226 // Note: as-character anchored objects aren't registered at a page frame and
227 // a notification of its background isn't needed.
228 if ( pAnchoredObj->GetPageFrame() )
230 ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
231 pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameArrive, true );
234 pAnchoredObj->InvalidateObjPos();
237 /// method to move drawing object to corresponding invisible layer - #i18447#
238 void SwContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
240 // #i46297# - notify background about the leaving of the object.
241 const bool bNotify( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
243 MoveObjToLayer( false, _pDrawObj );
245 // #i46297#
246 if ( bNotify )
248 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
249 assert(pAnchoredObj);
250 // Note: as-character anchored objects aren't registered at a page frame and
251 // a notification of its background isn't needed.
252 if (pAnchoredObj->GetPageFrame())
254 ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
255 pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameLeave, true );
260 /** method to move object to visible/invisible layer - #i18447#
262 implementation for the public method <MoveObjToVisibleLayer(..)>
263 and <MoveObjToInvisibleLayer(..)>
265 void SwContact::MoveObjToLayer( const bool _bToVisible,
266 SdrObject* _pDrawObj )
268 if ( !_pDrawObj )
270 OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing object!" );
271 return;
274 if ( !GetRegisteredIn() )
276 OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing frame format!" );
277 return;
280 const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
282 SdrLayerID nToHellLayerId =
283 _bToVisible ? rIDDMA.GetHellId() : rIDDMA.GetInvisibleHellId();
284 SdrLayerID nToHeavenLayerId =
285 _bToVisible ? rIDDMA.GetHeavenId() : rIDDMA.GetInvisibleHeavenId();
286 SdrLayerID nToControlLayerId =
287 _bToVisible ? rIDDMA.GetControlsId() : rIDDMA.GetInvisibleControlsId();
288 SdrLayerID nFromHellLayerId =
289 _bToVisible ? rIDDMA.GetInvisibleHellId() : rIDDMA.GetHellId();
290 SdrLayerID nFromHeavenLayerId =
291 _bToVisible ? rIDDMA.GetInvisibleHeavenId() : rIDDMA.GetHeavenId();
292 SdrLayerID nFromControlLayerId =
293 _bToVisible ? rIDDMA.GetInvisibleControlsId() : rIDDMA.GetControlsId();
295 if ( dynamic_cast<const SdrObjGroup*>( _pDrawObj) != nullptr )
297 // determine layer for group object
299 // proposed layer of a group object is the hell layer
300 SdrLayerID nNewLayerId = nToHellLayerId;
301 if ( ::CheckControlLayer( _pDrawObj ) )
303 // it has to be the control layer, if one of the member
304 // is a control
305 nNewLayerId = nToControlLayerId;
307 else if ( _pDrawObj->GetLayer() == rIDDMA.GetHeavenId() ||
308 _pDrawObj->GetLayer() == rIDDMA.GetInvisibleHeavenId() )
310 // it has to be the heaven layer, if method <GetLayer()> reveals
311 // a heaven layer
312 nNewLayerId = nToHeavenLayerId;
314 // set layer at group object, but do *not* broadcast and
315 // no propagation to the members.
316 // Thus, call <NbcSetLayer(..)> at super class
317 _pDrawObj->SdrObject::NbcSetLayer( nNewLayerId );
320 // call method recursively for group object members
321 const SdrObjList* pLst =
322 static_cast<SdrObjGroup*>(_pDrawObj)->GetSubList();
323 if ( pLst )
325 for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
327 MoveObjToLayer( _bToVisible, pLst->GetObj( i ) );
331 else
333 const SdrLayerID nLayerIdOfObj = _pDrawObj->GetLayer();
334 if ( nLayerIdOfObj == nFromHellLayerId )
336 _pDrawObj->SetLayer( nToHellLayerId );
338 else if ( nLayerIdOfObj == nFromHeavenLayerId )
340 _pDrawObj->SetLayer( nToHeavenLayerId );
342 else if ( nLayerIdOfObj == nFromControlLayerId )
344 _pDrawObj->SetLayer( nToControlLayerId );
349 /// get minimum order number of anchored objects handled by with contact
350 sal_uInt32 SwContact::GetMinOrdNum() const
352 sal_uInt32 nMinOrdNum( SAL_MAX_UINT32 );
354 std::vector< SwAnchoredObject* > aObjs;
355 GetAnchoredObjs( aObjs );
357 while ( !aObjs.empty() )
359 sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
361 if ( nTmpOrdNum < nMinOrdNum )
363 nMinOrdNum = nTmpOrdNum;
366 aObjs.pop_back();
369 OSL_ENSURE( nMinOrdNum != SAL_MAX_UINT32,
370 "<SwContact::GetMinOrdNum()> - no order number found." );
371 return nMinOrdNum;
374 /// get maximum order number of anchored objects handled by with contact
375 sal_uInt32 SwContact::GetMaxOrdNum() const
377 sal_uInt32 nMaxOrdNum( 0 );
379 std::vector< SwAnchoredObject* > aObjs;
380 GetAnchoredObjs( aObjs );
382 while ( !aObjs.empty() )
384 sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
386 if ( nTmpOrdNum > nMaxOrdNum )
388 nMaxOrdNum = nTmpOrdNum;
391 aObjs.pop_back();
394 return nMaxOrdNum;
397 namespace
399 Point lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj, const bool bFollowTextFlow, sw::WW8AnchorConv& reConv)
401 switch(reConv)
403 case sw::WW8AnchorConv::CONV2PG:
405 bool bRelToTableCell(false);
406 Point aPos(pAnchoredObj->GetRelPosToPageFrame(bFollowTextFlow, bRelToTableCell));
407 if(bRelToTableCell)
408 reConv = sw::WW8AnchorConv::RELTOTABLECELL;
409 return aPos;
411 case sw::WW8AnchorConv::CONV2COL_OR_PARA:
412 return pAnchoredObj->GetRelPosToAnchorFrame();
413 case sw::WW8AnchorConv::CONV2CHAR:
414 return pAnchoredObj->GetRelPosToChar();
415 case sw::WW8AnchorConv::CONV2LINE:
416 return pAnchoredObj->GetRelPosToLine();
417 default: ;
419 return Point();
422 void SwContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
424 // this does not call SwClient::SwClientNotify and thus doesn't handle RES_OBJECTDYING as usual. Is this intentional?
425 if (auto pFindSdrObjectHint = dynamic_cast<const sw::FindSdrObjectHint*>(&rHint))
427 if(!pFindSdrObjectHint->m_rpObject)
428 pFindSdrObjectHint->m_rpObject = GetMaster();
430 else if (auto pWW8AnchorConvHint = dynamic_cast<const sw::WW8AnchorConvHint*>(&rHint))
432 // determine anchored object
433 SwAnchoredObject* pAnchoredObj(nullptr);
435 std::vector<SwAnchoredObject*> aAnchoredObjs;
436 GetAnchoredObjs(aAnchoredObjs);
437 if(!aAnchoredObjs.empty())
438 pAnchoredObj = aAnchoredObjs.front();
440 // no anchored object found. Thus, the needed layout information can't
441 // be determined. --> no conversion
442 if(!pAnchoredObj)
443 return;
444 // no conversion for anchored drawing object, which aren't attached to an
445 // anchor frame.
446 // This is the case for drawing objects, which are anchored inside a page
447 // header/footer of an *unused* page style.
448 if(dynamic_cast<SwAnchoredDrawObject*>(pAnchoredObj) && !pAnchoredObj->GetAnchorFrame())
449 return;
450 const bool bFollowTextFlow = static_cast<const SwFrameFormat&>(rMod).GetFollowTextFlow().GetValue();
451 sw::WW8AnchorConvResult& rResult(pWW8AnchorConvHint->m_rResult);
452 // No distinction between layout directions, because of missing
453 // information about WW8 in vertical layout.
454 rResult.m_aPos.setX(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eHoriConv).getX());
455 rResult.m_aPos.setY(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eVertConv).getY());
456 rResult.m_bConverted = true;
461 SwFlyDrawContact::SwFlyDrawContact(
462 SwFlyFrameFormat *pToRegisterIn,
463 SdrModel& rTargetModel)
464 : SwContact(pToRegisterIn),
465 mpMasterObj(new SwFlyDrawObj(rTargetModel))
467 // #i26791# - class <SwFlyDrawContact> contains the 'master'
468 // drawing object of type <SwFlyDrawObj> on its own.
469 mpMasterObj->SetOrdNum( 0xFFFFFFFE );
470 mpMasterObj->SetUserCall( this );
473 SwFlyDrawContact::~SwFlyDrawContact()
475 if ( mpMasterObj )
477 mpMasterObj->SetUserCall( nullptr );
478 if ( mpMasterObj->getSdrPageFromSdrObject() )
479 mpMasterObj->getSdrPageFromSdrObject()->RemoveObject( mpMasterObj->GetOrdNum() );
483 sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly,
484 SwFrame const& rAnchorFrame)
486 // maintain invariant that a shape's textbox immediately follows the shape
487 // also for the multiple SdrVirtObj created for shapes in header/footer
488 if (SwFrameFormat const*const pDrawFormat =
489 SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT))
491 // assume that the draw SdrVirtObj is always created before the flyframe one
492 if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
494 for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
496 if (&pAnchoredObj->GetFrameFormat() == pDrawFormat)
498 return pAnchoredObj->GetDrawObj()->GetOrdNum() + 1;
502 // if called from AppendObjs(), this is a problem; if called from lcl_SetFlyFrameAttr() it's not
503 SAL_INFO("sw", "GetOrdNumForNewRef: cannot find SdrObject for text box's shape");
505 // search for another Writer fly frame registered at same frame format
506 SwIterator<SwFlyFrame,SwFormat> aIter(*GetFormat());
507 const SwFlyFrame* pFlyFrame(nullptr);
508 for(pFlyFrame = aIter.First(); pFlyFrame; pFlyFrame = aIter.Next())
510 if(pFlyFrame != pFly)
511 break;
514 if(pFlyFrame)
516 // another Writer fly frame found. Take its order number
517 return pFlyFrame->GetVirtDrawObj()->GetOrdNum();
519 // no other Writer fly frame found. Take order number of 'master' object
520 // #i35748# - use method <GetOrdNumDirect()> instead
521 // of method <GetOrdNum()> to avoid a recalculation of the order number,
522 // which isn't intended.
523 return GetMaster()->GetOrdNumDirect();
526 SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly,
527 SwFlyFrameFormat* pFormat, SwFrame const& rAnchorFrame)
529 // Find ContactObject from the Format. If there's already one, we just
530 // need to create a new Ref, else we create the Contact now.
532 IDocumentDrawModelAccess& rIDDMA = pFormat->getIDocumentDrawModelAccess();
533 SwFlyDrawContact* pContact = pFormat->GetOrCreateContact();
534 SwVirtFlyDrawObj* pDrawObj(
535 new SwVirtFlyDrawObj(
536 pContact->GetMaster()->getSdrModelFromSdrObject(),
537 *pContact->GetMaster(),
538 pFly));
539 pDrawObj->SetUserCall(pContact);
541 // The Reader creates the Masters and inserts them into the Page in
542 // order to transport the z-order.
543 // After creating the first Reference the Masters are removed from the
544 // List and are not important anymore.
545 SdrPage* pPg = pContact->GetMaster()->getSdrPageFromSdrObject();
546 if(nullptr != pPg)
548 const size_t nOrdNum = pContact->GetMaster()->GetOrdNum();
549 pPg->ReplaceObject(pDrawObj, nOrdNum);
551 // #i27030# - insert new <SwVirtFlyDrawObj> instance
552 // into drawing page with correct order number
553 else
554 rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj, pContact->GetOrdNumForNewRef(pFly, rAnchorFrame));
555 // #i38889# - assure, that new <SwVirtFlyDrawObj> instance
556 // is in a visible layer.
557 pContact->MoveObjToVisibleLayer(pDrawObj);
558 return pDrawObj;
561 // #i26791#
562 const SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(const SdrObject* pSdrObj) const
564 assert(pSdrObj);
565 assert(dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) != nullptr);
566 assert(GetUserCall(pSdrObj) == this &&
567 "<SwFlyDrawContact::GetAnchoredObj(..)> - provided object doesn't belong to this contact");
569 const SwAnchoredObject *const pRetAnchoredObj =
570 static_cast<const SwVirtFlyDrawObj*>(pSdrObj)->GetFlyFrame();
572 return pRetAnchoredObj;
575 SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
577 return const_cast<SwAnchoredObject *>(const_cast<SwFlyDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
580 SdrObject* SwFlyDrawContact::GetMaster()
582 return mpMasterObj.get();
586 * @note Overriding method to control Writer fly frames, which are linked, and
587 * to assure that all objects anchored at/inside the Writer fly frame are
588 * also made visible.
590 void SwFlyDrawContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
592 assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
594 if ( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
596 // nothing to do
597 return;
600 SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
602 // #i44464# - consider, that Writer fly frame content
603 // already exists - (e.g. WW8 document is inserted into an existing document).
604 if ( !pFlyFrame->Lower() )
606 pFlyFrame->InsertColumns();
607 pFlyFrame->Chain( pFlyFrame->AnchorFrame() );
608 pFlyFrame->InsertCnt();
610 if ( pFlyFrame->GetDrawObjs() )
612 for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
614 // #i28701# - consider type of objects in sorted object list.
615 SdrObject* pObj = i->DrawObj();
616 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
617 pContact->MoveObjToVisibleLayer( pObj );
621 // make fly frame visible
622 SwContact::MoveObjToVisibleLayer( _pDrawObj );
626 * @note Override method to control Writer fly frames, which are linked, and
627 * to assure that all objects anchored at/inside the Writer fly frame are
628 * also made invisible.
630 void SwFlyDrawContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
632 assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
634 if ( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
636 // nothing to do
637 return;
640 SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
642 pFlyFrame->Unchain();
643 pFlyFrame->DeleteCnt();
644 if ( pFlyFrame->GetDrawObjs() )
646 for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
648 // #i28701# - consider type of objects in sorted object list.
649 SdrObject* pObj = i->DrawObj();
650 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
651 pContact->MoveObjToInvisibleLayer( pObj );
655 // make fly frame invisible
656 SwContact::MoveObjToInvisibleLayer( _pDrawObj );
659 /// get data collection of anchored objects, handled by with contact
660 void SwFlyDrawContact::GetAnchoredObjs( std::vector<SwAnchoredObject*>& _roAnchoredObjs ) const
662 const SwFrameFormat* pFormat = GetFormat();
663 SwFlyFrame::GetAnchoredObjects( _roAnchoredObjs, *pFormat );
665 void SwFlyDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
667 SwContact::SwClientNotify(rMod, rHint);
668 if(auto pGetZOrdnerHint = dynamic_cast<const sw::GetZOrderHint*>(&rHint))
670 // #i11176#
671 // This also needs to work when no layout exists. Thus, for
672 // FlyFrames an alternative method is used now in that case.
673 auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
674 if (pFormat && pFormat->Which() == RES_FLYFRMFMT && !pFormat->getIDocumentLayoutAccess().GetCurrentViewShell())
675 pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
679 // SwDrawContact
681 bool CheckControlLayer( const SdrObject *pObj )
683 if ( SdrInventor::FmForm == pObj->GetObjInventor() )
684 return true;
685 if (const SdrObjGroup *pObjGroup = dynamic_cast<const SdrObjGroup*>(pObj))
687 const SdrObjList *pLst = pObjGroup->GetSubList();
688 for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
690 if ( ::CheckControlLayer( pLst->GetObj( i ) ) )
692 // #i18447# - return correct value ;-)
693 return true;
697 return false;
700 SwDrawContact::SwDrawContact( SwFrameFormat* pToRegisterIn, SdrObject* pObj ) :
701 SwContact( pToRegisterIn ),
702 maAnchoredDrawObj(),
703 mbMasterObjCleared( false ),
704 mbDisconnectInProgress( false ),
705 mbUserCallActive( false ),
706 // Note: value of <meEventTypeOfCurrentUserCall> isn't of relevance, because
707 // <mbUserCallActive> is false.
708 meEventTypeOfCurrentUserCall( SdrUserCallType::MoveOnly )
710 // --> #i33909# - assure, that drawing object is inserted
711 // in the drawing page.
712 if ( !pObj->IsInserted() )
714 pToRegisterIn->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
715 InsertObject( pObj, pObj->GetOrdNumDirect() );
718 // Controls have to be always in the Control-Layer. This is also true for
719 // group objects, if they contain controls.
720 if ( ::CheckControlLayer( pObj ) )
722 // set layer of object to corresponding invisible layer.
723 pObj->SetLayer( pToRegisterIn->getIDocumentDrawModelAccess().GetInvisibleControlsId() );
726 // #i26791#
727 pObj->SetUserCall( this );
728 maAnchoredDrawObj.SetDrawObj( *pObj );
730 // if there already exists an SwXShape for the object, ensure it knows about us, and the SdrObject
731 // #i99056#
732 SwXShape::AddExistingShapeToFormat( *pObj );
735 SwDrawContact::~SwDrawContact()
737 SetInDTOR();
739 DisconnectFromLayout();
741 // remove 'master' from drawing page
742 RemoveMasterFromDrawPage();
744 // remove and destroy 'virtual' drawing objects.
745 RemoveAllVirtObjs();
747 if ( !mbMasterObjCleared )
749 SdrObject* pObject = const_cast< SdrObject* >( maAnchoredDrawObj.GetDrawObj() );
750 SdrObject::Free( pObject );
754 void SwDrawContact::GetTextObjectsFromFormat(std::list<SdrTextObj*>& o_rTextObjects, SwDoc& rDoc)
756 for(auto& rpFly : *rDoc.GetSpzFrameFormats())
758 if(dynamic_cast<const SwDrawFrameFormat*>(rpFly))
759 rpFly->CallSwClientNotify(sw::CollectTextObjectsHint(o_rTextObjects));
763 // #i26791#
764 const SwAnchoredObject* SwDrawContact::GetAnchoredObj(const SdrObject* pSdrObj ) const
766 // handle default parameter value
767 if (!pSdrObj)
769 pSdrObj = GetMaster();
772 assert(pSdrObj);
773 assert(dynamic_cast<const SwDrawVirtObj*>(pSdrObj) != nullptr ||
774 dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
775 assert((GetUserCall(pSdrObj) == this ||
776 pSdrObj == GetMaster()) &&
777 "<SwDrawContact::GetAnchoredObj(..)> - provided object doesn't belongs to this contact" );
779 const SwAnchoredObject* pRetAnchoredObj = nullptr;
781 if (auto pVirtObj = dynamic_cast<const SwDrawVirtObj*>(pSdrObj))
783 pRetAnchoredObj = &(pVirtObj->GetAnchoredObj());
785 else
787 assert(dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
788 pRetAnchoredObj = &maAnchoredDrawObj;
791 return pRetAnchoredObj;
794 SwAnchoredObject* SwDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
796 return const_cast<SwAnchoredObject*>(const_cast<SwDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
799 SdrObject* SwDrawContact::GetMaster()
801 return !mbMasterObjCleared
802 ? maAnchoredDrawObj.DrawObj()
803 : nullptr;
806 const SwFrame* SwDrawContact::GetAnchorFrame( const SdrObject* _pDrawObj ) const
808 const SwFrame* pAnchorFrame = nullptr;
809 if ( !_pDrawObj ||
810 _pDrawObj == GetMaster() ||
811 ( !_pDrawObj->GetUserCall() &&
812 GetUserCall( _pDrawObj ) == this ) )
814 pAnchorFrame = maAnchoredDrawObj.GetAnchorFrame();
816 else
818 assert(dynamic_cast<SwDrawVirtObj const*>(_pDrawObj) != nullptr);
819 pAnchorFrame = static_cast<const SwDrawVirtObj*>(_pDrawObj)->GetAnchorFrame();
822 return pAnchorFrame;
825 SwFrame* SwDrawContact::GetAnchorFrame(SdrObject const *const pDrawObj)
827 return const_cast<SwFrame *>(const_cast<SwDrawContact const*>(this)->GetAnchorFrame(pDrawObj));
830 /** add a 'virtual' drawing object to drawing page.
832 SwDrawVirtObj* SwDrawContact::AddVirtObj(SwFrame const& rAnchorFrame)
834 maDrawVirtObjs.push_back(
835 SwDrawVirtObjPtr(
836 new SwDrawVirtObj(
837 GetMaster()->getSdrModelFromSdrObject(),
838 *GetMaster(),
839 *this)));
840 maDrawVirtObjs.back()->AddToDrawingPage(rAnchorFrame);
841 return maDrawVirtObjs.back().get();
844 /// remove 'virtual' drawing objects and destroy them.
845 void SwDrawContact::RemoveAllVirtObjs()
847 for(auto& rpDrawVirtObj : maDrawVirtObjs)
849 // remove and destroy 'virtual object'
850 rpDrawVirtObj->RemoveFromWriterLayout();
851 rpDrawVirtObj->RemoveFromDrawingPage();
853 maDrawVirtObjs.clear();
857 /// get drawing object ('master' or 'virtual') by frame.
858 SdrObject* SwDrawContact::GetDrawObjectByAnchorFrame( const SwFrame& _rAnchorFrame )
860 SdrObject* pRetDrawObj = nullptr;
862 // #i26791# - compare master frames instead of direct frames
863 const SwFrame* pProposedAnchorFrame = &_rAnchorFrame;
864 if ( pProposedAnchorFrame->IsContentFrame() )
866 const SwContentFrame* pTmpFrame =
867 static_cast<const SwContentFrame*>( pProposedAnchorFrame );
868 while ( pTmpFrame->IsFollow() )
870 pTmpFrame = pTmpFrame->FindMaster();
872 pProposedAnchorFrame = pTmpFrame;
875 const SwFrame* pMasterObjAnchorFrame = GetAnchorFrame();
876 if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame->IsContentFrame() )
878 const SwContentFrame* pTmpFrame =
879 static_cast<const SwContentFrame*>( pMasterObjAnchorFrame );
880 while ( pTmpFrame->IsFollow() )
882 pTmpFrame = pTmpFrame->FindMaster();
884 pMasterObjAnchorFrame = pTmpFrame;
887 if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame == pProposedAnchorFrame )
889 pRetDrawObj = GetMaster();
891 else
893 const auto ppFoundVirtObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
894 VirtObjAnchoredAtFramePred(pProposedAnchorFrame)));
895 if(ppFoundVirtObj != maDrawVirtObjs.end())
896 pRetDrawObj = ppFoundVirtObj->get();
899 return pRetDrawObj;
902 void SwDrawContact::NotifyBackgrdOfAllVirtObjs(const tools::Rectangle* pOldBoundRect)
904 for(const auto& rpDrawVirtObj : maDrawVirtObjs)
906 SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
907 if ( pDrawVirtObj->GetAnchorFrame() )
909 // #i34640# - determine correct page frame
910 SwPageFrame* pPage = pDrawVirtObj->AnchoredObj().FindPageFrameOfAnchor();
911 if( pOldBoundRect && pPage )
913 SwRect aOldRect( *pOldBoundRect );
914 aOldRect.Pos() += pDrawVirtObj->GetOffset();
915 if( aOldRect.HasArea() )
916 ::Notify_Background( pDrawVirtObj, pPage,
917 aOldRect, PrepareHint::FlyFrameLeave,true);
919 // #i34640# - include spacing for wrapping
920 SwRect aRect( pDrawVirtObj->GetAnchoredObj().GetObjRectWithSpaces() );
921 if (aRect.HasArea() && pPage)
923 SwPageFrame* pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aRect, pPage )));
924 if ( pPg )
925 ::Notify_Background( pDrawVirtObj, pPg, aRect,
926 PrepareHint::FlyFrameArrive, true );
928 ::ClrContourCache( pDrawVirtObj );
933 /// local method to notify the background for a drawing object - #i26791#
934 static void lcl_NotifyBackgroundOfObj( SwDrawContact const & _rDrawContact,
935 const SdrObject& _rObj,
936 const tools::Rectangle* _pOldObjRect )
938 // #i34640#
939 SwAnchoredObject* pAnchoredObj =
940 const_cast<SwAnchoredObject*>(_rDrawContact.GetAnchoredObj( &_rObj ));
941 if ( !(pAnchoredObj && pAnchoredObj->GetAnchorFrame()) )
942 return;
944 // #i34640# - determine correct page frame
945 SwPageFrame* pPageFrame = pAnchoredObj->FindPageFrameOfAnchor();
946 if( _pOldObjRect && pPageFrame )
948 SwRect aOldRect( *_pOldObjRect );
949 if( aOldRect.HasArea() )
951 // #i34640# - determine correct page frame
952 SwPageFrame* pOldPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aOldRect, pPageFrame )));
953 ::Notify_Background( &_rObj, pOldPageFrame, aOldRect,
954 PrepareHint::FlyFrameLeave, true);
957 // #i34640# - include spacing for wrapping
958 SwRect aNewRect( pAnchoredObj->GetObjRectWithSpaces() );
959 if( aNewRect.HasArea() && pPageFrame )
961 pPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aNewRect, pPageFrame )));
962 ::Notify_Background( &_rObj, pPageFrame, aNewRect,
963 PrepareHint::FlyFrameArrive, true );
965 ClrContourCache( &_rObj );
968 void SwDrawContact::Changed( const SdrObject& rObj,
969 SdrUserCallType eType,
970 const tools::Rectangle& rOldBoundRect )
972 // #i26791# - no event handling, if existing <SwViewShell>
973 // is in construction
974 SwDoc* pDoc = GetFormat()->GetDoc();
975 if ( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() &&
976 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor() )
978 return;
981 // #i44339#
982 // no event handling, if document is in destruction.
983 // Exception: It's the SdrUserCallType::Delete event
984 if ( pDoc->IsInDtor() && eType != SdrUserCallType::Delete )
986 return;
989 //Put on Action, but not if presently anywhere an action runs.
990 bool bHasActions(true);
991 SwRootFrame *pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
992 if ( pTmpRoot && pTmpRoot->IsCallbackActionEnabled() )
994 SwViewShell* const pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
995 if ( pSh )
997 for(SwViewShell& rShell : pSh->GetRingContainer() )
999 if ( rShell.Imp()->IsAction() || rShell.Imp()->IsIdleAction() )
1001 bHasActions = true;
1002 break;
1004 bHasActions = false;
1007 if(!bHasActions)
1008 pTmpRoot->StartAllAction();
1010 SdrObjUserCall::Changed( rObj, eType, rOldBoundRect );
1011 Changed_( rObj, eType, &rOldBoundRect ); //Attention, possibly suicidal!
1013 if(!bHasActions)
1014 pTmpRoot->EndAllAction();
1017 /// helper class for method <SwDrawContact::Changed_(..)> for handling nested
1018 /// <SdrObjUserCall> events
1019 class NestedUserCallHdl
1021 private:
1022 SwDrawContact* mpDrawContact;
1023 bool mbParentUserCallActive;
1024 SdrUserCallType meParentUserCallEventType;
1026 public:
1027 NestedUserCallHdl( SwDrawContact* _pDrawContact,
1028 SdrUserCallType _eEventType )
1029 : mpDrawContact( _pDrawContact ),
1030 mbParentUserCallActive( _pDrawContact->mbUserCallActive ),
1031 meParentUserCallEventType( _pDrawContact->meEventTypeOfCurrentUserCall )
1033 mpDrawContact->mbUserCallActive = true;
1034 mpDrawContact->meEventTypeOfCurrentUserCall = _eEventType;
1037 ~NestedUserCallHdl()
1039 if ( mpDrawContact )
1041 mpDrawContact->mbUserCallActive = mbParentUserCallActive;
1042 mpDrawContact->meEventTypeOfCurrentUserCall = meParentUserCallEventType;
1046 void DrawContactDeleted()
1048 mpDrawContact = nullptr;
1051 bool IsNestedUserCall() const
1053 return mbParentUserCallActive;
1056 void AssertNestedUserCall()
1058 if ( !IsNestedUserCall() )
1059 return;
1061 bool bTmpAssert( true );
1062 // Currently its known, that a nested event SdrUserCallType::Resize
1063 // could occur during parent user call SdrUserCallType::Inserted,
1064 // SdrUserCallType::Delete and SdrUserCallType::Resize for edge objects.
1065 // Also possible are nested SdrUserCallType::ChildResize events for
1066 // edge objects
1067 // Thus, assert all other combinations
1068 if ( ( meParentUserCallEventType == SdrUserCallType::Inserted ||
1069 meParentUserCallEventType == SdrUserCallType::Delete ||
1070 meParentUserCallEventType == SdrUserCallType::Resize ) &&
1071 mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::Resize )
1073 bTmpAssert = false;
1075 else if ( meParentUserCallEventType == SdrUserCallType::ChildResize &&
1076 mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::ChildResize )
1078 bTmpAssert = false;
1081 if ( bTmpAssert )
1083 OSL_FAIL( "<SwDrawContact::Changed_(..)> - unknown nested <UserCall> event. This is serious." );
1088 /// Notify the format's textbox that it should reconsider its position / size.
1089 static void lcl_textBoxSizeNotify(SwFrameFormat* pFormat)
1091 if (SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT))
1093 // Just notify the textbox that the size has changed, the actual object size is not interesting.
1094 SfxItemSet aResizeSet(pFormat->GetDoc()->GetAttrPool(), svl::Items<RES_FRM_SIZE, RES_FRM_SIZE>{});
1095 SwFormatFrameSize aSize;
1096 aResizeSet.Put(aSize);
1097 SwTextBoxHelper::syncFlyFrameAttr(*pFormat, aResizeSet);
1101 // !!!ATTENTION!!! The object may commit suicide!!!
1103 void SwDrawContact::Changed_( const SdrObject& rObj,
1104 SdrUserCallType eType,
1105 const tools::Rectangle* pOldBoundRect )
1107 // suppress handling of nested <SdrObjUserCall> events
1108 NestedUserCallHdl aNestedUserCallHdl( this, eType );
1109 if ( aNestedUserCallHdl.IsNestedUserCall() )
1111 aNestedUserCallHdl.AssertNestedUserCall();
1112 return;
1114 // do *not* notify, if document is destructing
1115 // #i35912# - do *not* notify for as-character anchored
1116 // drawing objects.
1117 // #i35007#
1118 // improvement: determine as-character anchored object flag only once.
1119 const bool bAnchoredAsChar = ObjAnchoredAsChar();
1120 const bool bNotify = !(GetFormat()->GetDoc()->IsInDtor()) &&
1121 ( css::text::WrapTextMode_THROUGH != GetFormat()->GetSurround().GetSurround() ) &&
1122 !bAnchoredAsChar;
1123 switch( eType )
1125 case SdrUserCallType::Delete:
1127 if ( bNotify )
1129 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1130 // --> #i36181# - background of 'virtual'
1131 // drawing objects have also been notified.
1132 NotifyBackgrdOfAllVirtObjs( pOldBoundRect );
1134 DisconnectFromLayout( false );
1135 mbMasterObjCleared = true;
1136 delete this;
1137 // --> #i65784# Prevent memory corruption
1138 aNestedUserCallHdl.DrawContactDeleted();
1139 break;
1141 case SdrUserCallType::Inserted:
1143 if ( mbDisconnectInProgress )
1145 OSL_FAIL( "<SwDrawContact::Changed_(..)> - Insert event during disconnection from layout is invalid." );
1147 else
1149 ConnectToLayout();
1150 if ( bNotify )
1152 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1155 break;
1157 case SdrUserCallType::Removed:
1159 if ( bNotify )
1161 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1163 DisconnectFromLayout( false );
1164 break;
1166 case SdrUserCallType::ChildInserted :
1167 case SdrUserCallType::ChildRemoved :
1169 // --> #i113730#
1170 // force layer of controls for group objects containing control objects
1171 if(dynamic_cast< SdrObjGroup* >(maAnchoredDrawObj.DrawObj()))
1173 if(::CheckControlLayer(maAnchoredDrawObj.DrawObj()))
1175 const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
1176 const SdrLayerID aCurrentLayer(maAnchoredDrawObj.DrawObj()->GetLayer());
1177 const SdrLayerID aControlLayerID(rIDDMA.GetControlsId());
1178 const SdrLayerID aInvisibleControlLayerID(rIDDMA.GetInvisibleControlsId());
1180 if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID)
1182 if ( aCurrentLayer == rIDDMA.GetInvisibleHellId() ||
1183 aCurrentLayer == rIDDMA.GetInvisibleHeavenId() )
1185 maAnchoredDrawObj.DrawObj()->SetLayer(aInvisibleControlLayerID);
1187 else
1189 maAnchoredDrawObj.DrawObj()->SetLayer(aControlLayerID);
1194 [[fallthrough]];
1196 case SdrUserCallType::MoveOnly:
1197 case SdrUserCallType::Resize:
1198 case SdrUserCallType::ChildMoveOnly :
1199 case SdrUserCallType::ChildResize :
1200 case SdrUserCallType::ChildChangeAttr :
1201 case SdrUserCallType::ChildDelete :
1203 // #i31698# - improvement
1204 // get instance <SwAnchoredDrawObject> only once
1205 const SwAnchoredDrawObject* pAnchoredDrawObj =
1206 static_cast<const SwAnchoredDrawObject*>( GetAnchoredObj( &rObj ) );
1208 /* protect against NULL pointer dereferencing */
1209 if(!pAnchoredDrawObj)
1211 break;
1214 // #i26791# - adjust positioning and alignment attributes,
1215 // if positioning of drawing object isn't in progress.
1216 // #i53320# - no adjust of positioning attributes,
1217 // if drawing object isn't positioned.
1218 if ( !pAnchoredDrawObj->IsPositioningInProgress() &&
1219 !pAnchoredDrawObj->NotYetPositioned() )
1221 // #i34748# - If no last object rectangle is
1222 // provided by the anchored object, use parameter <pOldBoundRect>.
1223 const tools::Rectangle& aOldObjRect = pAnchoredDrawObj->GetLastObjRect()
1224 ? *(pAnchoredDrawObj->GetLastObjRect())
1225 : *pOldBoundRect;
1226 // #i79400#
1227 // always invalidate object rectangle inclusive spaces
1228 pAnchoredDrawObj->InvalidateObjRectWithSpaces();
1229 // #i41324# - notify background before
1230 // adjusting position
1231 if ( bNotify )
1233 // #i31573# - correction
1234 // background of given drawing object.
1235 lcl_NotifyBackgroundOfObj( *this, rObj, &aOldObjRect );
1237 // #i31698# - determine layout direction
1238 // via draw frame format.
1239 SwFrameFormat::tLayoutDir eLayoutDir =
1240 pAnchoredDrawObj->GetFrameFormat().GetLayoutDir();
1241 // use geometry of drawing object
1242 SwRect aObjRect( rObj.GetSnapRect() );
1243 // If drawing object is a member of a group, the adjustment
1244 // of the positioning and the alignment attributes has to
1245 // be done for the top group object.
1246 if ( rObj.getParentSdrObjectFromSdrObject() )
1248 const SdrObject* pGroupObj = rObj.getParentSdrObjectFromSdrObject();
1249 while ( pGroupObj->getParentSdrObjectFromSdrObject() )
1251 pGroupObj = pGroupObj->getParentSdrObjectFromSdrObject();
1253 // use geometry of drawing object
1254 aObjRect = pGroupObj->GetSnapRect();
1256 SwTwips nXPosDiff(0);
1257 SwTwips nYPosDiff(0);
1258 switch ( eLayoutDir )
1260 case SwFrameFormat::HORI_L2R:
1262 nXPosDiff = aObjRect.Left() - aOldObjRect.Left();
1263 nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1265 break;
1266 case SwFrameFormat::HORI_R2L:
1268 nXPosDiff = aOldObjRect.Right() - aObjRect.Right();
1269 nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1271 break;
1272 case SwFrameFormat::VERT_R2L:
1274 nXPosDiff = aObjRect.Top() - aOldObjRect.Top();
1275 nYPosDiff = aOldObjRect.Right() - aObjRect.Right();
1277 break;
1278 default:
1280 assert(!"<SwDrawContact::Changed_(..)> - unsupported layout direction");
1283 SfxItemSet aSet( GetFormat()->GetDoc()->GetAttrPool(),
1284 svl::Items<RES_VERT_ORIENT, RES_HORI_ORIENT>{} );
1285 const SwFormatVertOrient& rVert = GetFormat()->GetVertOrient();
1286 if ( nYPosDiff != 0 )
1288 if ( rVert.GetRelationOrient() == text::RelOrientation::CHAR ||
1289 rVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
1291 nYPosDiff = -nYPosDiff;
1293 aSet.Put( SwFormatVertOrient( rVert.GetPos()+nYPosDiff,
1294 text::VertOrientation::NONE,
1295 rVert.GetRelationOrient() ) );
1298 const SwFormatHoriOrient& rHori = GetFormat()->GetHoriOrient();
1299 if ( !bAnchoredAsChar && nXPosDiff != 0 )
1301 aSet.Put( SwFormatHoriOrient( rHori.GetPos()+nXPosDiff,
1302 text::HoriOrientation::NONE,
1303 rHori.GetRelationOrient() ) );
1306 if ( nYPosDiff ||
1307 ( !bAnchoredAsChar && nXPosDiff != 0 ) )
1309 GetFormat()->GetDoc()->SetFlyFrameAttr( *(GetFormat()), aSet );
1310 // keep new object rectangle, to avoid multiple
1311 // changes of the attributes by multiple event from
1312 // the drawing layer - e.g. group objects and its members
1313 // #i34748# - use new method
1314 // <SwAnchoredDrawObject::SetLastObjRect(..)>.
1315 const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)
1316 ->SetLastObjRect( aObjRect.SVRect() );
1318 else if ( aObjRect.SSize() != aOldObjRect.GetSize() )
1320 InvalidateObjs_();
1321 // #i35007# - notify anchor frame
1322 // of as-character anchored object
1323 if ( bAnchoredAsChar )
1325 SwFrame* pAnchorFrame = const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)->AnchorFrame();
1326 if(pAnchorFrame)
1328 pAnchorFrame->Prepare( PrepareHint::FlyFrameAttributesChanged, GetFormat() );
1332 lcl_textBoxSizeNotify(GetFormat());
1334 else if (eType == SdrUserCallType::Resize)
1335 // Even if the bounding box of the shape didn't change,
1336 // notify about the size change, as an adjustment change
1337 // may affect the size of the underlying textbox.
1338 lcl_textBoxSizeNotify(GetFormat());
1341 // tdf#135198: keep text box together with its shape
1342 SwRect aObjRect(rObj.GetSnapRect());
1343 const SwPageFrame* rPageFrame = pAnchoredDrawObj->GetPageFrame();
1344 if (rPageFrame && rPageFrame->isFrameAreaPositionValid())
1346 SwDoc* const pDoc = GetFormat()->GetDoc();
1348 // avoid Undo creation
1349 ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1351 // hide any artificial "changes" made by synchronizing the textbox position
1352 const bool bEnableSetModified = pDoc->getIDocumentState().IsEnableSetModified();
1353 pDoc->getIDocumentState().SetEnableSetModified(false);
1355 SfxItemSet aSyncSet(pDoc->GetAttrPool(),
1356 svl::Items<RES_VERT_ORIENT, RES_ANCHOR>{});
1357 aSyncSet.Put(SwFormatVertOrient(aObjRect.Top() - rPageFrame->getFrameArea().Top(),
1358 text::VertOrientation::NONE,
1359 text::RelOrientation::PAGE_FRAME));
1360 aSyncSet.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, pAnchoredDrawObj->GetPageFrame()->GetPhyPageNum()));
1362 SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSyncSet);
1364 pDoc->getIDocumentState().SetEnableSetModified(bEnableSetModified);
1367 break;
1368 case SdrUserCallType::ChangeAttr:
1369 if ( bNotify )
1371 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1373 break;
1374 default:
1375 break;
1379 namespace
1381 const SwFormatAnchor* lcl_getAnchorFormat( const SfxPoolItem& _rItem )
1383 sal_uInt16 nWhich = _rItem.Which();
1384 const SwFormatAnchor* pAnchorFormat = nullptr;
1385 if ( RES_ATTRSET_CHG == nWhich )
1387 static_cast<const SwAttrSetChg&>(_rItem).GetChgSet()->
1388 GetItemState( RES_ANCHOR, false, reinterpret_cast<const SfxPoolItem**>(&pAnchorFormat) );
1390 else if ( RES_ANCHOR == nWhich )
1392 pAnchorFormat = &static_cast<const SwFormatAnchor&>(_rItem);
1394 return pAnchorFormat;
1398 void SwDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
1400 SwClient::SwClientNotify(rMod, rHint); // needed as SwContact::SwClientNotify doesn't explicitly call SwClient::SwClientNotify
1401 SwContact::SwClientNotify(rMod, rHint);
1402 if (auto pLegacyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
1404 SAL_WARN_IF(mbDisconnectInProgress, "sw.core", "<SwDrawContact::Modify(..)> called during disconnection.");
1406 const SfxPoolItem* pNew = pLegacyHint->m_pNew;
1407 sal_uInt16 nWhich = pNew ? pNew->Which() : 0;
1408 if(const SwFormatAnchor* pNewAnchorFormat = pNew ? lcl_getAnchorFormat(*pNew) : nullptr)
1410 // Do not respond to a Reset Anchor!
1411 if(GetFormat()->GetAttrSet().GetItemState(RES_ANCHOR, false) == SfxItemState::SET)
1413 // no connect to layout during disconnection
1414 if(!mbDisconnectInProgress)
1416 // determine old object rectangle of 'master' drawing object
1417 // for notification
1418 const tools::Rectangle* pOldRect = nullptr;
1419 tools::Rectangle aOldRect;
1420 if(GetAnchorFrame())
1422 // --> #i36181# - include spacing in object
1423 // rectangle for notification.
1424 aOldRect = maAnchoredDrawObj.GetObjRectWithSpaces().SVRect();
1425 pOldRect = &aOldRect;
1427 // re-connect to layout due to anchor format change
1428 ConnectToLayout(pNewAnchorFormat);
1429 // notify background of drawing objects
1430 lcl_NotifyBackgroundOfObj(*this, *GetMaster(), pOldRect);
1431 NotifyBackgrdOfAllVirtObjs(pOldRect);
1433 const SwFormatAnchor* pOldAnchorFormat = pLegacyHint->m_pOld ? lcl_getAnchorFormat(*pLegacyHint->m_pOld) : nullptr;
1434 if(!pOldAnchorFormat || (pOldAnchorFormat->GetAnchorId() != pNewAnchorFormat->GetAnchorId()))
1436 if(maAnchoredDrawObj.DrawObj())
1438 // --> #i102752#
1439 // assure that a ShapePropertyChangeNotifier exists
1440 maAnchoredDrawObj.DrawObj()->notifyShapePropertyChange(svx::ShapeProperty::TextDocAnchor);
1442 else
1443 SAL_WARN("sw.core", "SwDrawContact::Modify: no draw object here?");
1447 else
1448 DisconnectFromLayout();
1450 else if (nWhich == RES_REMOVE_UNO_OBJECT)
1451 {} // nothing to do
1452 // --> #i62875# - no further notification, if not connected to Writer layout
1453 else if ( maAnchoredDrawObj.GetAnchorFrame() &&
1454 maAnchoredDrawObj.GetDrawObj()->GetUserCall() )
1456 bool bUpdateSortedObjsList(false);
1457 switch(nWhich)
1459 case RES_UL_SPACE:
1460 case RES_LR_SPACE:
1461 case RES_HORI_ORIENT:
1462 case RES_VERT_ORIENT:
1463 case RES_FOLLOW_TEXT_FLOW: // #i28701# - add attribute 'Follow text flow'
1464 break;
1465 case RES_SURROUND:
1466 case RES_OPAQUE:
1467 case RES_WRAP_INFLUENCE_ON_OBJPOS:
1468 // --> #i28701# - on change of wrapping style, hell|heaven layer,
1469 // or wrapping style influence an update of the <SwSortedObjs> list,
1470 // the drawing object is registered in, has to be performed. This is triggered
1471 // by the 1st parameter of method call <InvalidateObjs_(..)>.
1472 bUpdateSortedObjsList = true;
1473 break;
1474 case RES_ATTRSET_CHG: // #i35443#
1476 auto pChgSet = static_cast<const SwAttrSetChg*>(pNew)->GetChgSet();
1477 if(pChgSet->GetItemState(RES_SURROUND, false) == SfxItemState::SET ||
1478 pChgSet->GetItemState(RES_OPAQUE, false) == SfxItemState::SET ||
1479 pChgSet->GetItemState(RES_WRAP_INFLUENCE_ON_OBJPOS, false) == SfxItemState::SET)
1480 bUpdateSortedObjsList = true;
1482 break;
1483 default:
1484 assert(!"<SwDraw Contact::Modify(..)> - unhandled attribute?");
1486 lcl_NotifyBackgroundOfObj(*this, *GetMaster(), nullptr);
1487 NotifyBackgrdOfAllVirtObjs(nullptr);
1488 InvalidateObjs_(bUpdateSortedObjsList);
1491 // #i51474#
1492 GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
1494 else if (auto pDrawFrameFormatHint = dynamic_cast<const sw::DrawFrameFormatHint*>(&rHint))
1496 switch(pDrawFrameFormatHint->m_eId)
1498 case sw::DrawFrameFormatHintId::DYING:
1499 delete this;
1500 break;
1501 case sw::DrawFrameFormatHintId::PREPPASTING:
1502 MoveObjToVisibleLayer(GetMaster());
1503 break;
1504 case sw::DrawFrameFormatHintId::PREP_INSERT_FLY:
1505 InsertMasterIntoDrawPage();
1506 // #i40845# - follow-up of #i35635#
1507 // move object to visible layer
1508 MoveObjToVisibleLayer(GetMaster());
1509 // tdf#135661 InsertMasterIntoDrawPage may have created a new
1510 // SwXShape with null m_pFormat; fix that
1511 SwXShape::AddExistingShapeToFormat(*GetMaster());
1512 break;
1513 case sw::DrawFrameFormatHintId::PREP_DELETE_FLY:
1514 RemoveMasterFromDrawPage();
1515 break;
1516 case sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS:
1517 case sw::DrawFrameFormatHintId::DELETE_FRAMES:
1518 DisconnectFromLayout();
1519 break;
1520 case sw::DrawFrameFormatHintId::MAKE_FRAMES:
1521 ConnectToLayout();
1522 break;
1523 case sw::DrawFrameFormatHintId::POST_RESTORE_FLY_ANCHOR:
1524 GetAnchoredObj(GetMaster())->MakeObjPos();
1525 break;
1526 default:
1530 else if (auto pCheckDrawFrameFormatLayerHint = dynamic_cast<const sw::CheckDrawFrameFormatLayerHint*>(&rHint))
1532 *(pCheckDrawFrameFormatLayerHint->m_bCheckControlLayer) |= (GetMaster() && CheckControlLayer(GetMaster()));
1534 else if (auto pContactChangedHint = dynamic_cast<const sw::ContactChangedHint*>(&rHint))
1536 if(!*pContactChangedHint->m_ppObject)
1537 *pContactChangedHint->m_ppObject = GetMaster();
1538 auto pObject = *pContactChangedHint->m_ppObject;
1539 Changed(*pObject, SdrUserCallType::Delete, pObject->GetLastBoundRect());
1541 else if (auto pDrawFormatLayoutCopyHint = dynamic_cast<const sw::DrawFormatLayoutCopyHint*>(&rHint))
1543 const SwDrawFrameFormat& rFormat = static_cast<const SwDrawFrameFormat&>(rMod);
1544 new SwDrawContact(
1545 &pDrawFormatLayoutCopyHint->m_rDestFormat,
1546 pDrawFormatLayoutCopyHint->m_rDestDoc.CloneSdrObj(
1547 *GetMaster(),
1548 pDrawFormatLayoutCopyHint->m_rDestDoc.IsCopyIsMove() && &pDrawFormatLayoutCopyHint->m_rDestDoc == rFormat.GetDoc()));
1549 // #i49730# - notify draw frame format that position attributes are
1550 // already set, if the position attributes are already set at the
1551 // source draw frame format.
1552 if(rFormat.IsPosAttrSet())
1553 pDrawFormatLayoutCopyHint->m_rDestFormat.PosAttrSet();
1555 else if (auto pRestoreFlyAnchorHint = dynamic_cast<const sw::RestoreFlyAnchorHint*>(&rHint))
1557 SdrObject* pObj = GetMaster();
1558 if(GetAnchorFrame() && !pObj->IsInserted())
1560 auto pDrawModel = const_cast<SwDrawFrameFormat&>(static_cast<const SwDrawFrameFormat&>(rMod)).GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1561 assert(pDrawModel);
1562 pDrawModel->GetPage(0)->InsertObject(pObj);
1564 pObj->SetRelativePos(pRestoreFlyAnchorHint->m_aPos);
1566 else if (auto pCreatePortionHint = dynamic_cast<const sw::CreatePortionHint*>(&rHint))
1568 if(*pCreatePortionHint->m_ppContact)
1569 return;
1570 *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
1571 if(!GetAnchorFrame())
1573 // No direct positioning needed any more
1574 ConnectToLayout();
1575 // Move object to visible layer
1576 MoveObjToVisibleLayer(GetMaster());
1579 else if (auto pCollectTextObjectsHint = dynamic_cast<const sw::CollectTextObjectsHint*>(&rHint))
1581 auto pSdrO = GetMaster();
1582 if(!pSdrO)
1583 return;
1584 if(dynamic_cast<const SdrObjGroup*>(pSdrO))
1586 SdrObjListIter aListIter(*pSdrO, SdrIterMode::DeepNoGroups);
1587 //iterate inside of a grouped object
1588 while(aListIter.IsMore())
1590 SdrObject* pSdrOElement = aListIter.Next();
1591 auto pTextObj = const_cast<SdrTextObj*>(dynamic_cast<const SdrTextObj*>(pSdrOElement));
1592 if(pTextObj && pTextObj->HasText())
1593 pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1596 else if(auto pTextObj = const_cast<SdrTextObj*>(dynamic_cast<const SdrTextObj*>(pSdrO)))
1598 if(pTextObj->HasText())
1599 pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1602 else if (auto pGetZOrdnerHint = dynamic_cast<const sw::GetZOrderHint*>(&rHint))
1604 auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
1605 if(pFormat->Which() == RES_DRAWFRMFMT)
1606 pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
1608 else if (auto pConnectedHint = dynamic_cast<const sw::GetObjectConnectedHint*>(&rHint))
1610 pConnectedHint->m_risConnected |= (GetAnchorFrame() != nullptr);
1614 // #i26791#
1615 // #i28701# - added parameter <_bUpdateSortedObjsList>
1616 void SwDrawContact::InvalidateObjs_( const bool _bUpdateSortedObjsList )
1618 for(const auto& rpDrawVirtObj : maDrawVirtObjs)
1619 // invalidate position of existing 'virtual' drawing objects
1621 SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
1622 // #i33313# - invalidation only for connected
1623 // 'virtual' drawing objects
1624 if ( pDrawVirtObj->IsConnected() )
1626 pDrawVirtObj->AnchoredObj().InvalidateObjPos();
1627 // #i28701#
1628 if ( _bUpdateSortedObjsList )
1630 pDrawVirtObj->AnchoredObj().UpdateObjInSortedList();
1635 // invalidate position of 'master' drawing object
1636 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( nullptr );
1637 pAnchoredObj->InvalidateObjPos();
1638 // #i28701#
1639 if ( _bUpdateSortedObjsList )
1641 pAnchoredObj->UpdateObjInSortedList();
1645 void SwDrawContact::DisconnectFromLayout( bool _bMoveMasterToInvisibleLayer )
1647 mbDisconnectInProgress = true;
1649 // --> #i36181# - notify background of drawing object
1650 if ( _bMoveMasterToInvisibleLayer &&
1651 !(GetFormat()->GetDoc()->IsInDtor()) &&
1652 GetAnchorFrame() && !GetAnchorFrame()->IsInDtor() )
1654 const tools::Rectangle aOldRect( maAnchoredDrawObj.GetObjRectWithSpaces().SVRect() );
1655 lcl_NotifyBackgroundOfObj( *this, *GetMaster(), &aOldRect );
1656 NotifyBackgrdOfAllVirtObjs( &aOldRect );
1659 // remove 'virtual' drawing objects from writer
1660 // layout and from drawing page
1661 for(auto& rpVirtDrawObj : maDrawVirtObjs)
1663 rpVirtDrawObj->RemoveFromWriterLayout();
1664 rpVirtDrawObj->RemoveFromDrawingPage();
1667 if ( maAnchoredDrawObj.GetAnchorFrame() )
1669 maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1672 if ( _bMoveMasterToInvisibleLayer && GetMaster() && GetMaster()->IsInserted() )
1674 SdrViewIter aIter( GetMaster() );
1675 for( SdrView* pView = aIter.FirstView(); pView;
1676 pView = aIter.NextView() )
1678 pView->MarkObj( GetMaster(), pView->GetSdrPageView(), true );
1681 // Instead of removing 'master' object from drawing page, move the
1682 // 'master' drawing object into the corresponding invisible layer.
1684 //static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess()->GetDrawModel()->GetPage(0)->
1685 // RemoveObject( GetMaster()->GetOrdNum() );
1686 // #i18447# - in order to consider group object correct
1687 // use new method <SwDrawContact::MoveObjToInvisibleLayer(..)>
1688 MoveObjToInvisibleLayer( GetMaster() );
1692 mbDisconnectInProgress = false;
1695 /// method to remove 'master' drawing object from drawing page.
1696 void SwDrawContact::RemoveMasterFromDrawPage()
1698 if ( GetMaster() )
1700 GetMaster()->SetUserCall( nullptr );
1701 if ( GetMaster()->IsInserted() )
1703 static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
1704 RemoveObject( GetMaster()->GetOrdNum() );
1709 // disconnect for a dedicated drawing object - could be 'master' or 'virtual'.
1710 // a 'master' drawing object will disconnect a 'virtual' drawing object
1711 // in order to take its place.
1712 // #i19919# - no special case, if drawing object isn't in
1713 // page header/footer, in order to get drawing objects in repeating table headers
1714 // also working.
1715 void SwDrawContact::DisconnectObjFromLayout( SdrObject* _pDrawObj )
1717 if ( auto pSwDrawVirtObj = dynamic_cast<SwDrawVirtObj*>( _pDrawObj) )
1719 pSwDrawVirtObj->RemoveFromWriterLayout();
1720 pSwDrawVirtObj->RemoveFromDrawingPage();
1722 else
1724 const auto ppVirtDrawObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
1725 [] (const SwDrawVirtObjPtr& pObj) { return pObj->IsConnected(); }));
1727 if(ppVirtDrawObj != maDrawVirtObjs.end())
1729 // replace found 'virtual' drawing object by 'master' drawing
1730 // object and disconnect the 'virtual' one
1731 SwDrawVirtObj* pDrawVirtObj(ppVirtDrawObj->get());
1732 SwFrame* pNewAnchorFrameOfMaster = pDrawVirtObj->AnchorFrame();
1733 // disconnect 'virtual' drawing object
1734 pDrawVirtObj->RemoveFromWriterLayout();
1735 pDrawVirtObj->RemoveFromDrawingPage();
1736 // disconnect 'master' drawing object from current frame
1737 GetAnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1738 // re-connect 'master' drawing object to frame of found 'virtual'
1739 // drawing object.
1740 pNewAnchorFrameOfMaster->AppendDrawObj( maAnchoredDrawObj );
1742 else
1744 // no connected 'virtual' drawing object found. Thus, disconnect
1745 // completely from layout.
1746 DisconnectFromLayout();
1751 static SwTextFrame* lcl_GetFlyInContentAnchor( SwTextFrame* _pProposedAnchorFrame,
1752 SwPosition const& rAnchorPos)
1754 SwTextFrame* pAct = _pProposedAnchorFrame;
1755 SwTextFrame* pTmp;
1756 TextFrameIndex const nTextOffset(_pProposedAnchorFrame->MapModelToViewPos(rAnchorPos));
1759 pTmp = pAct;
1760 pAct = pTmp->GetFollow();
1762 while (pAct && nTextOffset >= pAct->GetOffset());
1763 return pTmp;
1766 void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
1768 // *no* connect to layout during disconnection from layout.
1769 if ( mbDisconnectInProgress )
1771 OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> called during disconnection.");
1772 return;
1775 // --> #i33909# - *no* connect to layout, if 'master' drawing
1776 // object isn't inserted in the drawing page
1777 if ( !GetMaster()->IsInserted() )
1779 OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> - master drawing object not inserted -> no connect to layout. Please inform od@openoffice.org" );
1780 return;
1783 SwFrameFormat* pDrawFrameFormat = static_cast<SwFrameFormat*>(GetRegisteredIn());
1785 if( !pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell() )
1786 return;
1788 // remove 'virtual' drawing objects from writer
1789 // layout and from drawing page, and remove 'master' drawing object from
1790 // writer layout - 'master' object will remain in drawing page.
1791 DisconnectFromLayout( false );
1793 if ( !pAnch )
1795 pAnch = &(pDrawFrameFormat->GetAnchor());
1798 switch ( pAnch->GetAnchorId() )
1800 case RndStdIds::FLY_AT_PAGE:
1802 sal_uInt16 nPgNum = pAnch->GetPageNum();
1803 SwViewShell *pShell = pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell();
1804 if( !pShell )
1805 break;
1806 SwRootFrame* pRoot = pShell->GetLayout();
1807 SwPageFrame *pPage = static_cast<SwPageFrame*>(pRoot->Lower());
1809 for ( sal_uInt16 i = 1; i < nPgNum && pPage; ++i )
1811 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1814 if ( pPage )
1816 pPage->AppendDrawObj( maAnchoredDrawObj );
1818 else
1819 //Looks stupid but is allowed (compare SwFEShell::SetPageObjsNewPage)
1820 pRoot->SetAssertFlyPages();
1822 break;
1824 case RndStdIds::FLY_AT_CHAR:
1825 case RndStdIds::FLY_AT_PARA:
1826 case RndStdIds::FLY_AT_FLY:
1827 case RndStdIds::FLY_AS_CHAR:
1829 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1831 ClrContourCache( GetMaster() );
1833 // support drawing objects in header/footer,
1834 // but not control objects:
1835 // anchor at first found frame the 'master' object and
1836 // at the following frames 'virtual' drawing objects.
1837 // Note: method is similar to <SwFlyFrameFormat::MakeFrames(..)>
1838 sw::BroadcastingModify *pModify = nullptr;
1839 if( pAnch->GetContentAnchor() )
1841 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AT_FLY )
1843 SwNodeIndex aIdx( pAnch->GetContentAnchor()->nNode );
1844 SwContentNode* pCNd = pDrawFrameFormat->GetDoc()->GetNodes().GoNext( &aIdx );
1845 if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
1846 pModify = pCNd;
1847 else
1849 const SwNodeIndex& rIdx = pAnch->GetContentAnchor()->nNode;
1850 SwFrameFormats& rFormats = *(pDrawFrameFormat->GetDoc()->GetSpzFrameFormats());
1851 for( auto pFlyFormat : rFormats )
1853 if( pFlyFormat->GetContent().GetContentIdx() &&
1854 rIdx == *(pFlyFormat->GetContent().GetContentIdx()) )
1856 pModify = pFlyFormat;
1857 break;
1862 else
1864 pModify = pAnch->GetContentAnchor()->nNode.GetNode().GetContentNode();
1868 // #i29199# - It is possible, that
1869 // the anchor doesn't exist - E.g., reordering the
1870 // sub-documents in a master document.
1871 // Note: The anchor will be inserted later.
1872 if ( !pModify )
1874 // break to end of the current switch case.
1875 break;
1878 SwIterator<SwFrame, sw::BroadcastingModify, sw::IteratorMode::UnwrapMulti> aIter(*pModify);
1879 SwFrame* pAnchorFrameOfMaster = nullptr;
1880 for( SwFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1882 // append drawing object, if
1883 // (1) proposed anchor frame isn't a follow and...
1884 const bool bFollow = pFrame->IsContentFrame() && static_cast<SwContentFrame*>(pFrame)->IsFollow();
1885 if (bFollow)
1886 continue;
1888 // (2) drawing object isn't a control object to be anchored
1889 // in header/footer.
1890 const bool bControlInHF = ::CheckControlLayer(GetMaster()) && pFrame->FindFooterOrHeader();
1891 // tdf#129542 but make an exception for control objects so they can get added to just the first frame,
1892 // the Master Anchor Frame and not the others
1893 if (bControlInHF && pAnchorFrameOfMaster)
1894 continue;
1896 bool bAdd;
1897 if (RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId())
1898 bAdd = true;
1899 else
1901 assert(pFrame->IsTextFrame());
1902 bAdd = IsAnchoredObjShown(*static_cast<SwTextFrame*>(pFrame), *pAnch);
1905 if( bAdd )
1907 if ( RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId() && !pFrame->IsFlyFrame() )
1909 pFrame = pFrame->FindFlyFrame();
1910 assert(pFrame);
1913 // find correct follow for as character anchored objects
1914 if ((pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR) &&
1915 pFrame->IsTextFrame() )
1917 pFrame = lcl_GetFlyInContentAnchor(
1918 static_cast<SwTextFrame*>(pFrame),
1919 *pAnch->GetContentAnchor());
1922 if ( !pAnchorFrameOfMaster )
1924 // append 'master' drawing object
1925 pAnchorFrameOfMaster = pFrame;
1926 pFrame->AppendDrawObj( maAnchoredDrawObj );
1928 else
1930 // append 'virtual' drawing object
1931 SwDrawVirtObj* pDrawVirtObj = AddVirtObj(*pFrame);
1932 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1934 ClrContourCache( pDrawVirtObj );
1936 pFrame->AppendDrawObj( pDrawVirtObj->AnchoredObj() );
1938 pDrawVirtObj->ActionChanged();
1941 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1943 pFrame->InvalidatePrt();
1948 break;
1949 default:
1950 assert(!"Unknown Anchor.");
1951 break;
1953 if ( GetAnchorFrame() )
1955 ::setContextWritingMode( maAnchoredDrawObj.DrawObj(), GetAnchorFrame() );
1956 // #i26791# - invalidate objects instead of direct positioning
1957 InvalidateObjs_();
1961 /// insert 'master' drawing object into drawing page
1962 void SwDrawContact::InsertMasterIntoDrawPage()
1964 if ( !GetMaster()->IsInserted() )
1966 GetFormat()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)
1967 ->InsertObject( GetMaster(), GetMaster()->GetOrdNumDirect() );
1969 GetMaster()->SetUserCall( this );
1972 SwPageFrame* SwDrawContact::FindPage( const SwRect &rRect )
1974 // --> #i28701# - use method <GetPageFrame()>
1975 SwPageFrame* pPg = GetPageFrame();
1976 if ( !pPg && GetAnchorFrame() )
1977 pPg = GetAnchorFrame()->FindPageFrame();
1978 if ( pPg )
1979 pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( rRect, pPg )));
1980 return pPg;
1983 void SwDrawContact::ChkPage()
1985 if ( mbDisconnectInProgress )
1987 OSL_FAIL( "<SwDrawContact::ChkPage()> called during disconnection." );
1988 return;
1991 // --> #i28701#
1992 SwPageFrame* pPg = ( maAnchoredDrawObj.GetAnchorFrame() &&
1993 maAnchoredDrawObj.GetAnchorFrame()->IsPageFrame() )
1994 ? GetPageFrame()
1995 : FindPage( GetMaster()->GetCurrentBoundRect() );
1996 if ( GetPageFrame() == pPg )
1997 return;
1999 // if drawing object is anchor in header/footer a change of the page
2000 // is a dramatic change. Thus, completely re-connect to the layout
2001 if ( maAnchoredDrawObj.GetAnchorFrame() &&
2002 maAnchoredDrawObj.GetAnchorFrame()->FindFooterOrHeader() )
2004 ConnectToLayout();
2006 else
2008 // --> #i28701# - use methods <GetPageFrame()> and <SetPageFrame>
2009 if ( GetPageFrame() )
2010 GetPageFrame()->RemoveDrawObjFromPage( maAnchoredDrawObj );
2011 pPg->AppendDrawObjToPage( maAnchoredDrawObj );
2012 maAnchoredDrawObj.SetPageFrame( pPg );
2016 // Important note:
2017 // method is called by method <SwDPage::ReplaceObject(..)>, which called its
2018 // corresponding superclass method <FmFormPage::ReplaceObject(..)>.
2019 // Note: 'master' drawing object *has* to be connected to layout triggered
2020 // by the caller of this, if method is called.
2021 void SwDrawContact::ChangeMasterObject(SdrObject* pNewMaster)
2023 DisconnectFromLayout( false );
2024 // consider 'virtual' drawing objects
2025 RemoveAllVirtObjs();
2027 GetMaster()->SetUserCall( nullptr );
2028 if(pNewMaster)
2029 maAnchoredDrawObj.SetDrawObj(*pNewMaster);
2030 else
2031 mbMasterObjCleared = true;
2032 GetMaster()->SetUserCall( this );
2034 InvalidateObjs_();
2037 /// get data collection of anchored objects, handled by with contact
2038 void SwDrawContact::GetAnchoredObjs(std::vector<SwAnchoredObject*>& o_rAnchoredObjs) const
2040 o_rAnchoredObjs.push_back(const_cast<SwAnchoredDrawObject*>(&maAnchoredDrawObj));
2042 for(auto& rpDrawVirtObj : maDrawVirtObjs)
2043 o_rAnchoredObjs.push_back(&rpDrawVirtObj->AnchoredObj());
2046 // AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed
2047 // since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj.
2048 // For paint, that offset is used by setting at the OutputDevice; for primitives this is
2049 // not possible since we have no OutputDevice, but define the geometry itself.
2051 namespace sdr::contact
2053 namespace {
2055 class VOCOfDrawVirtObj : public ViewObjectContactOfSdrObj
2057 protected:
2059 * This method is responsible for creating the graphical visualisation data which is
2060 * stored/cached in the local primitive. Default gets view-independent Primitive from
2061 * the ViewContact using ViewContact::getViewIndependentPrimitive2DContainer(), takes
2062 * care of visibility, handles glue and ghosted.
2064 * This method will not handle included hierarchies and not check geometric visibility.
2066 virtual drawinglayer::primitive2d::Primitive2DContainer createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const override;
2068 public:
2069 VOCOfDrawVirtObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
2070 : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
2075 class VCOfDrawVirtObj : public ViewContactOfVirtObj
2077 protected:
2078 /** Create an Object-Specific ViewObjectContact, set ViewContact and ObjectContact.
2080 * Always needs to return something. Default is to create a standard ViewObjectContact
2081 * containing the given ObjectContact and *this.
2083 virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
2085 public:
2086 /// basic constructor, used from SdrObject.
2087 explicit VCOfDrawVirtObj(SwDrawVirtObj& rObj)
2088 : ViewContactOfVirtObj(rObj)
2092 /// access to SwDrawVirtObj
2093 SwDrawVirtObj& GetSwDrawVirtObj() const
2095 return static_cast<SwDrawVirtObj&>(mrObject);
2100 } // end of namespace sdr::contact
2102 namespace sdr::contact
2104 /// recursively collect primitive data from given VOC with given offset
2105 static void impAddPrimitivesFromGroup(const ViewObjectContact& rVOC, const basegfx::B2DHomMatrix& rOffsetMatrix, const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DContainer& rxTarget)
2107 const sal_uInt32 nSubHierarchyCount(rVOC.GetViewContact().GetObjectCount());
2109 for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
2111 const ViewObjectContact& rCandidate(rVOC.GetViewContact().GetViewContact(a).GetViewObjectContact(rVOC.GetObjectContact()));
2113 if(rCandidate.GetViewContact().GetObjectCount())
2115 // is a group object itself, call recursively
2116 impAddPrimitivesFromGroup(rCandidate, rOffsetMatrix, rDisplayInfo, rxTarget);
2118 else
2120 // single object, add primitives; check model-view visibility
2121 if(rCandidate.isPrimitiveVisible(rDisplayInfo))
2123 drawinglayer::primitive2d::Primitive2DContainer aNewSequence(rCandidate.getPrimitive2DSequence(rDisplayInfo));
2125 if(!aNewSequence.empty())
2127 // get ranges
2128 const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(rCandidate.GetObjectContact().getViewInformation2D());
2129 const basegfx::B2DRange aViewRange(rViewInformation2D.getViewport());
2130 basegfx::B2DRange aObjectRange(rCandidate.getObjectRange());
2132 // correct with virtual object's offset
2133 aObjectRange.transform(rOffsetMatrix);
2135 // check geometrical visibility (with offset)
2136 if(!aViewRange.overlaps(aObjectRange))
2138 // not visible, release
2139 aNewSequence.clear();
2143 if(!aNewSequence.empty())
2145 rxTarget.append(aNewSequence);
2152 drawinglayer::primitive2d::Primitive2DContainer VOCOfDrawVirtObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
2154 // tdf#91260 have already checked top-level one is on the right page
2155 assert(isPrimitiveVisible(rDisplayInfo));
2156 // nasty corner case: override to clear page frame to disable the
2157 // sub-objects' anchor check, because their anchor is always on
2158 // the first page that the page style is applied to
2159 DisplayInfo aDisplayInfo(rDisplayInfo);
2160 aDisplayInfo.SetWriterPageFrame(basegfx::B2IRectangle());
2161 const VCOfDrawVirtObj& rVC = static_cast< const VCOfDrawVirtObj& >(GetViewContact());
2162 const SdrObject& rReferencedObject = rVC.GetSwDrawVirtObj().GetReferencedObj();
2163 drawinglayer::primitive2d::Primitive2DContainer xRetval;
2165 // create offset transformation
2166 basegfx::B2DHomMatrix aOffsetMatrix;
2167 const Point aLocalOffset(rVC.GetSwDrawVirtObj().GetOffset());
2169 if(aLocalOffset.X() || aLocalOffset.Y())
2171 aOffsetMatrix.set(0, 2, aLocalOffset.X());
2172 aOffsetMatrix.set(1, 2, aLocalOffset.Y());
2175 if(dynamic_cast<const SdrObjGroup*>( &rReferencedObject) != nullptr)
2177 // group object. Since the VOC/OC/VC hierarchy does not represent the
2178 // hierarchy virtual objects when they have group objects
2179 // (ViewContactOfVirtObj::GetObjectCount() returns null for that purpose)
2180 // to avoid multiple usages of VOCs (which would not work), the primitives
2181 // for the sub-hierarchy need to be collected here
2183 // Get the VOC of the referenced object (the Group) and fetch primitives from it
2184 const ViewObjectContact& rVOCOfRefObj = rReferencedObject.GetViewContact().GetViewObjectContact(GetObjectContact());
2185 impAddPrimitivesFromGroup(rVOCOfRefObj, aOffsetMatrix, aDisplayInfo, xRetval);
2187 else
2189 // single object, use method from referenced object to get the Primitive2DSequence
2190 xRetval = rReferencedObject.GetViewContact().getViewIndependentPrimitive2DContainer();
2193 if(!xRetval.empty())
2195 // create transform primitive
2196 const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::TransformPrimitive2D(aOffsetMatrix, xRetval));
2197 xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
2200 return xRetval;
2203 ViewObjectContact& VCOfDrawVirtObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
2205 return *(new VOCOfDrawVirtObj(rObjectContact, *this));
2208 } // end of namespace sdr::contact
2210 /// implementation of class <SwDrawVirtObj>
2211 std::unique_ptr<sdr::contact::ViewContact> SwDrawVirtObj::CreateObjectSpecificViewContact()
2213 return std::make_unique<sdr::contact::VCOfDrawVirtObj>(*this);
2216 SwDrawVirtObj::SwDrawVirtObj(
2217 SdrModel& rSdrModel,
2218 SdrObject& _rNewObj,
2219 SwDrawContact& _rDrawContact)
2220 : SdrVirtObj(rSdrModel, _rNewObj ),
2221 maAnchoredDrawObj(),
2222 mrDrawContact(_rDrawContact)
2224 // #i26791#
2225 maAnchoredDrawObj.SetDrawObj( *this );
2227 // #i35635# - set initial position out of sight
2228 NbcMove( Size( -16000, -16000 ) );
2231 SwDrawVirtObj::~SwDrawVirtObj()
2235 SwDrawVirtObj& SwDrawVirtObj::operator=( const SwDrawVirtObj& rObj )
2237 SdrVirtObj::operator=(rObj);
2238 // Note: Members <maAnchoredDrawObj> and <mrDrawContact>
2239 // haven't to be considered.
2240 return *this;
2243 SwDrawVirtObj* SwDrawVirtObj::CloneSdrObject(SdrModel& rTargetModel) const
2245 SwDrawVirtObj* pObj = new SwDrawVirtObj(
2246 rTargetModel,
2247 rRefObj,
2248 mrDrawContact);
2250 pObj->operator=( *this );
2251 // Note: Member <maAnchoredDrawObj> hasn't to be considered.
2253 return pObj;
2256 const SwFrame* SwDrawVirtObj::GetAnchorFrame() const
2258 // #i26791# - use new member <maAnchoredDrawObj>
2259 return maAnchoredDrawObj.GetAnchorFrame();
2262 SwFrame* SwDrawVirtObj::AnchorFrame()
2264 // #i26791# - use new member <maAnchoredDrawObj>
2265 return maAnchoredDrawObj.AnchorFrame();
2268 void SwDrawVirtObj::RemoveFromWriterLayout()
2270 // remove contact object from frame for 'virtual' drawing object
2271 // #i26791# - use new member <maAnchoredDrawObj>
2272 if ( maAnchoredDrawObj.GetAnchorFrame() )
2274 maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
2278 void SwDrawVirtObj::AddToDrawingPage(SwFrame const& rAnchorFrame)
2280 // determine 'master'
2281 SdrObject* pOrgMasterSdrObj = mrDrawContact.GetMaster();
2283 // insert 'virtual' drawing object into page, set layer and user call.
2284 SdrPage* pDrawPg = pOrgMasterSdrObj->getSdrPageFromSdrObject();
2285 // default: insert before master object
2286 auto NOTM_nOrdNum(GetReferencedObj().GetOrdNum());
2288 // maintain invariant that a shape's textbox immediately follows the shape
2289 // also for the multiple SdrDrawVirtObj created for shapes in header/footer
2290 if (SwFrameFormat const*const pFlyFormat =
2291 SwTextBoxHelper::getOtherTextBoxFormat(mrDrawContact.GetFormat(), RES_DRAWFRMFMT))
2293 // this is for the case when the flyframe SdrVirtObj is created before the draw one
2294 if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
2296 for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
2298 if (&pAnchoredObj->GetFrameFormat() == pFlyFormat)
2300 assert(dynamic_cast<SwFlyFrame const*>(pAnchoredObj));
2301 NOTM_nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
2302 // the master SdrObj should have the highest index
2303 assert(NOTM_nOrdNum < GetReferencedObj().GetOrdNum());
2304 break;
2308 // this happens on initial insertion, the draw object is created first
2309 SAL_INFO_IF(GetReferencedObj().GetOrdNum() == NOTM_nOrdNum, "sw", "AddToDrawingPage: cannot find SdrObject for text box's shape");
2312 // #i27030# - apply order number of referenced object
2313 if ( nullptr != pDrawPg )
2315 // #i27030# - apply order number of referenced object
2316 pDrawPg->InsertObject(this, NOTM_nOrdNum);
2318 else
2320 pDrawPg = getSdrPageFromSdrObject();
2321 if ( pDrawPg )
2323 pDrawPg->SetObjectOrdNum(GetOrdNumDirect(), NOTM_nOrdNum);
2325 else
2327 SetOrdNum(NOTM_nOrdNum);
2330 SetUserCall( &mrDrawContact );
2333 void SwDrawVirtObj::RemoveFromDrawingPage()
2335 SetUserCall( nullptr );
2336 if ( getSdrPageFromSdrObject() )
2338 getSdrPageFromSdrObject()->RemoveObject( GetOrdNum() );
2342 /// Is 'virtual' drawing object connected to writer layout and to drawing layer?
2343 bool SwDrawVirtObj::IsConnected() const
2345 bool bRetVal = GetAnchorFrame() &&
2346 ( getSdrPageFromSdrObject() && GetUserCall() );
2348 return bRetVal;
2351 void SwDrawVirtObj::NbcSetAnchorPos(const Point& rPnt)
2353 SdrObject::NbcSetAnchorPos( rPnt );
2356 // #i97197#
2357 // the methods relevant for positioning
2359 const tools::Rectangle& SwDrawVirtObj::GetCurrentBoundRect() const
2361 if(aOutRect.IsEmpty())
2363 const_cast<SwDrawVirtObj*>(this)->RecalcBoundRect();
2366 return aOutRect;
2369 const tools::Rectangle& SwDrawVirtObj::GetLastBoundRect() const
2371 return aOutRect;
2374 Point SwDrawVirtObj::GetOffset() const
2376 // do NOT use IsEmpty() here, there is already a useful offset
2377 // in the position
2378 if(aOutRect == tools::Rectangle())
2380 return Point();
2382 else
2384 return aOutRect.TopLeft() - GetReferencedObj().GetCurrentBoundRect().TopLeft();
2388 void SwDrawVirtObj::SetBoundRectDirty()
2390 // do nothing to not lose model information in aOutRect
2393 void SwDrawVirtObj::RecalcBoundRect()
2395 // #i26791# - switch order of calling <GetOffset()> and
2396 // <ReferencedObj().GetCurrentBoundRect()>, because <GetOffset()> calculates
2397 // its value by the 'BoundRect' of the referenced object.
2399 const Point aOffset(GetOffset());
2400 aOutRect = ReferencedObj().GetCurrentBoundRect() + aOffset;
2403 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeXorPoly() const
2405 basegfx::B2DPolyPolygon aRetval(rRefObj.TakeXorPoly());
2406 aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2408 return aRetval;
2411 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeContour() const
2413 basegfx::B2DPolyPolygon aRetval(rRefObj.TakeContour());
2414 aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2416 return aRetval;
2419 void SwDrawVirtObj::AddToHdlList(SdrHdlList& rHdlList) const
2421 SdrHdlList tmpList(nullptr);
2422 rRefObj.AddToHdlList(tmpList);
2424 size_t cnt = tmpList.GetHdlCount();
2425 for(size_t i=0; i < cnt; ++i)
2427 SdrHdl* pHdl = tmpList.GetHdl(i);
2428 Point aP(pHdl->GetPos() + GetOffset());
2429 pHdl->SetPos(aP);
2431 tmpList.MoveTo(rHdlList);
2434 void SwDrawVirtObj::NbcMove(const Size& rSiz)
2436 SdrObject::NbcMove( rSiz );
2439 void SwDrawVirtObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
2441 rRefObj.NbcResize(rRef - GetOffset(), xFact, yFact);
2442 SetRectsDirty();
2445 void SwDrawVirtObj::NbcRotate(const Point& rRef, tools::Long nAngle, double sn, double cs)
2447 rRefObj.NbcRotate(rRef - GetOffset(), nAngle, sn, cs);
2448 SetRectsDirty();
2451 void SwDrawVirtObj::NbcMirror(const Point& rRef1, const Point& rRef2)
2453 rRefObj.NbcMirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2454 SetRectsDirty();
2457 void SwDrawVirtObj::NbcShear(const Point& rRef, tools::Long nAngle, double tn, bool bVShear)
2459 rRefObj.NbcShear(rRef - GetOffset(), nAngle, tn, bVShear);
2460 SetRectsDirty();
2463 void SwDrawVirtObj::Move(const Size& rSiz)
2465 SdrObject::Move( rSiz );
2468 void SwDrawVirtObj::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
2470 if(xFact.GetNumerator() != xFact.GetDenominator() || yFact.GetNumerator() != yFact.GetDenominator())
2472 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2473 rRefObj.Resize(rRef - GetOffset(), xFact, yFact, bUnsetRelative);
2474 SetRectsDirty();
2475 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2479 void SwDrawVirtObj::Rotate(const Point& rRef, tools::Long nAngle, double sn, double cs)
2481 if(nAngle)
2483 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2484 rRefObj.Rotate(rRef - GetOffset(), nAngle, sn, cs);
2485 SetRectsDirty();
2486 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2490 void SwDrawVirtObj::Mirror(const Point& rRef1, const Point& rRef2)
2492 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2493 rRefObj.Mirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2494 SetRectsDirty();
2495 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2498 void SwDrawVirtObj::Shear(const Point& rRef, tools::Long nAngle, double tn, bool bVShear)
2500 if(nAngle)
2502 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2503 rRefObj.Shear(rRef - GetOffset(), nAngle, tn, bVShear);
2504 SetRectsDirty();
2505 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2509 void SwDrawVirtObj::RecalcSnapRect()
2511 aSnapRect = rRefObj.GetSnapRect();
2512 aSnapRect += GetOffset();
2515 const tools::Rectangle& SwDrawVirtObj::GetSnapRect() const
2517 const_cast<SwDrawVirtObj*>(this)->aSnapRect = rRefObj.GetSnapRect();
2518 const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
2520 return aSnapRect;
2523 void SwDrawVirtObj::SetSnapRect(const tools::Rectangle& rRect)
2525 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2526 tools::Rectangle aR(rRect);
2527 aR -= GetOffset();
2528 rRefObj.SetSnapRect(aR);
2529 SetRectsDirty();
2530 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2533 void SwDrawVirtObj::NbcSetSnapRect(const tools::Rectangle& rRect)
2535 tools::Rectangle aR(rRect);
2536 aR -= GetOffset();
2537 SetRectsDirty();
2538 rRefObj.NbcSetSnapRect(aR);
2541 const tools::Rectangle& SwDrawVirtObj::GetLogicRect() const
2543 const_cast<SwDrawVirtObj*>(this)->aSnapRect = rRefObj.GetLogicRect();
2544 const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
2546 return aSnapRect;
2549 void SwDrawVirtObj::SetLogicRect(const tools::Rectangle& rRect)
2551 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2552 tools::Rectangle aR(rRect);
2553 aR -= GetOffset();
2554 rRefObj.SetLogicRect(aR);
2555 SetRectsDirty();
2556 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2559 void SwDrawVirtObj::NbcSetLogicRect(const tools::Rectangle& rRect)
2561 tools::Rectangle aR(rRect);
2562 aR -= GetOffset();
2563 rRefObj.NbcSetLogicRect(aR);
2564 SetRectsDirty();
2567 Point SwDrawVirtObj::GetSnapPoint(sal_uInt32 i) const
2569 Point aP(rRefObj.GetSnapPoint(i));
2570 aP += GetOffset();
2572 return aP;
2575 Point SwDrawVirtObj::GetPoint(sal_uInt32 i) const
2577 return rRefObj.GetPoint(i) + GetOffset();
2580 void SwDrawVirtObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
2582 Point aP(rPnt);
2583 aP -= GetOffset();
2584 rRefObj.SetPoint(aP, i);
2585 SetRectsDirty();
2588 bool SwDrawVirtObj::HasTextEdit() const
2590 return rRefObj.HasTextEdit();
2593 // override 'layer' methods for 'virtual' drawing object to assure
2594 // that layer of 'virtual' object is the layer of the referenced object.
2595 SdrLayerID SwDrawVirtObj::GetLayer() const
2597 return GetReferencedObj().GetLayer();
2600 void SwDrawVirtObj::NbcSetLayer(SdrLayerID nLayer)
2602 ReferencedObj().NbcSetLayer( nLayer );
2603 SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2606 void SwDrawVirtObj::SetLayer(SdrLayerID nLayer)
2608 ReferencedObj().SetLayer( nLayer );
2609 SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2612 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */