docthemes: Save themes def. to a file when added to ColorSets
[LibreOffice.git] / sw / source / core / draw / dcontact.cxx
blobd37d125021092f15d21913ef4426bf827f3f8ef3
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 <drawdoc.hxx>
32 #include <fmtornt.hxx>
33 #include <viewimp.hxx>
34 #include <fmtsrnd.hxx>
35 #include <fmtanchr.hxx>
36 #include <node.hxx>
37 #include <fmtcntnt.hxx>
38 #include <fmtfsize.hxx>
39 #include <pam.hxx>
40 #include <pagefrm.hxx>
41 #include <rootfrm.hxx>
42 #include <frmtool.hxx>
43 #include <flyfrm.hxx>
44 #include <textboxhelper.hxx>
45 #include <frmfmt.hxx>
46 #include <fmtfollowtextflow.hxx>
47 #include <dflyobj.hxx>
48 #include <dcontact.hxx>
49 #include <unodraw.hxx>
50 #include <IDocumentDrawModelAccess.hxx>
51 #include <IDocumentLayoutAccess.hxx>
52 #include <IDocumentState.hxx>
53 #include <IDocumentUndoRedo.hxx>
54 #include <doc.hxx>
55 #include <hints.hxx>
56 #include <txtfrm.hxx>
57 #include <frameformats.hxx>
58 #include <sortedobjs.hxx>
59 #include <basegfx/matrix/b2dhommatrix.hxx>
60 #include <basegfx/matrix/b2dhommatrixtools.hxx>
61 #include <svx/sdr/contact/viewcontactofvirtobj.hxx>
62 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
63 #include <drawinglayer/geometry/viewinformation2d.hxx>
64 #include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
65 #include <com/sun/star/text/WritingMode2.hpp>
66 #include <calbck.hxx>
67 #include <algorithm>
68 #include <txtfly.hxx>
69 #include <sal/log.hxx>
71 using namespace ::com::sun::star;
73 namespace
75 /** unary function used to find a 'virtual' drawing object anchored at a given frame */
76 struct VirtObjAnchoredAtFramePred
78 const SwFrame* m_pAnchorFrame;
80 // #i26791# - compare with master frame
81 static const SwFrame* FindFrame(const SwFrame* pFrame)
83 if(!pFrame || !pFrame->IsContentFrame())
84 return pFrame;
85 auto pContentFrame = static_cast<const SwContentFrame*>(pFrame);
86 while(pContentFrame->IsFollow())
87 pContentFrame = pContentFrame->FindMaster();
88 return pContentFrame;
91 VirtObjAnchoredAtFramePred(const SwFrame* pAnchorFrame)
92 : m_pAnchorFrame(FindFrame(pAnchorFrame))
95 bool operator()(const rtl::Reference<SwDrawVirtObj>& rpDrawVirtObj)
97 return FindFrame(rpDrawVirtObj->GetAnchorFrame()) == m_pAnchorFrame;
102 void setContextWritingMode(SdrObject* pObj, SwFrame const * pAnchor)
104 if(!pObj || !pAnchor)
105 return;
106 short nWritingDirection =
107 pAnchor->IsVertical() ? text::WritingMode2::TB_RL :
108 pAnchor->IsRightToLeft() ? text::WritingMode2::RL_TB :
109 text::WritingMode2::LR_TB;
110 pObj->SetContextWritingMode(nWritingDirection);
114 /** The Get reverse way: seeks the format to the specified object.
115 * If the object is a SwVirtFlyDrawObj then the format of this
116 * will be acquired.
117 * Otherwise it is just a simple drawing object. This has a
118 * UserCall and is the client of the searched format.
120 SwFrameFormat *FindFrameFormat( SdrObject *pObj )
122 if (SwVirtFlyDrawObj* pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
123 return pFlyDrawObj->GetFormat();
125 if (SwContact* pContact = GetUserCall(pObj))
126 return pContact->GetFormat();
128 return nullptr;
131 bool HasWrap( const SdrObject* pObj )
133 if ( pObj )
135 const SwFrameFormat* pFormat = ::FindFrameFormat( pObj );
136 if ( pFormat )
138 return css::text::WrapTextMode_THROUGH != pFormat->GetSurround().GetSurround();
142 return false;
145 /// returns the BoundRect _inclusive_ distance of the object.
146 SwRect GetBoundRectOfAnchoredObj( const SdrObject* pObj )
148 SwRect aRet( pObj->GetCurrentBoundRect() );
149 // #i68520# - call cache of <SwAnchoredObject>
150 SwContact* pContact( GetUserCall( pObj ) );
151 if ( pContact )
153 const SwAnchoredObject* pAnchoredObj( pContact->GetAnchoredObj( pObj ) );
154 if ( pAnchoredObj )
156 aRet = pAnchoredObj->GetObjRectWithSpaces();
159 return aRet;
162 /// Returns the UserCall if applicable from the group object
163 SwContact* GetUserCall( const SdrObject* pObj )
165 for (; pObj; pObj = pObj->getParentSdrObjectFromSdrObject())
167 if (auto pUserCall = pObj->GetUserCall())
169 assert(dynamic_cast<SwContact*>(pUserCall)
170 && "<::GetUserCall(..)> - wrong type of found object user call.");
171 return static_cast<SwContact*>(pUserCall);
174 return nullptr;
177 /// Returns true if the SrdObject is a Marquee-Object (scrolling text)
178 bool IsMarqueeTextObj( const SdrObject& rObj )
180 if (SdrInventor::Default != rObj.GetObjInventor() ||
181 SdrObjKind::Text != rObj.GetObjIdentifier())
182 return false;
183 SdrTextAniKind eTKind = static_cast<const SdrTextObj&>(rObj).GetTextAniKind();
184 return ( SdrTextAniKind::Scroll == eTKind
185 || SdrTextAniKind::Alternate == eTKind || SdrTextAniKind::Slide == eTKind );
188 SwContact::SwContact( SwFrameFormat *pToRegisterIn ) :
189 SwClient( pToRegisterIn ),
190 mbInDTOR( false )
193 SwContact::~SwContact()
195 SetInDTOR();
199 void SwContact::SetInDTOR()
201 mbInDTOR = true;
204 /// method to move drawing object to corresponding visible layer
205 void SwContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
207 // #i46297# - notify background about the arriving of
208 // the object and invalidate its position.
209 const bool bNotify( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
211 MoveObjToLayer( true, _pDrawObj );
213 // #i46297#
214 if ( !bNotify )
215 return;
217 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
218 assert(pAnchoredObj);
219 ::setContextWritingMode( _pDrawObj, pAnchoredObj->GetAnchorFrameContainingAnchPos() );
220 // Note: as-character anchored objects aren't registered at a page frame and
221 // a notification of its background isn't needed.
222 if ( pAnchoredObj->GetPageFrame() )
224 ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
225 pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameArrive, true );
228 pAnchoredObj->InvalidateObjPos();
231 /// method to move drawing object to corresponding invisible layer - #i18447#
232 void SwContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
234 // #i46297# - notify background about the leaving of the object.
235 const bool bNotify( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
237 MoveObjToLayer( false, _pDrawObj );
239 // #i46297#
240 if ( bNotify )
242 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
243 assert(pAnchoredObj);
244 // Note: as-character anchored objects aren't registered at a page frame and
245 // a notification of its background isn't needed.
246 if (pAnchoredObj->GetPageFrame())
248 ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
249 pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameLeave, true );
254 /** method to move object to visible/invisible layer - #i18447#
256 implementation for the public method <MoveObjToVisibleLayer(..)>
257 and <MoveObjToInvisibleLayer(..)>
259 void SwContact::MoveObjToLayer( const bool _bToVisible,
260 SdrObject* _pDrawObj )
262 if ( !_pDrawObj )
264 OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing object!" );
265 return;
268 if ( !GetRegisteredIn() )
270 OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing frame format!" );
271 return;
274 const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
276 SdrLayerID nToHellLayerId =
277 _bToVisible ? rIDDMA.GetHellId() : rIDDMA.GetInvisibleHellId();
278 SdrLayerID nToHeavenLayerId =
279 _bToVisible ? rIDDMA.GetHeavenId() : rIDDMA.GetInvisibleHeavenId();
280 SdrLayerID nToControlLayerId =
281 _bToVisible ? rIDDMA.GetControlsId() : rIDDMA.GetInvisibleControlsId();
282 SdrLayerID nFromHellLayerId =
283 _bToVisible ? rIDDMA.GetInvisibleHellId() : rIDDMA.GetHellId();
284 SdrLayerID nFromHeavenLayerId =
285 _bToVisible ? rIDDMA.GetInvisibleHeavenId() : rIDDMA.GetHeavenId();
286 SdrLayerID nFromControlLayerId =
287 _bToVisible ? rIDDMA.GetInvisibleControlsId() : rIDDMA.GetControlsId();
289 if ( dynamic_cast<const SdrObjGroup*>( _pDrawObj) != nullptr )
291 // determine layer for group object
293 // proposed layer of a group object is the hell layer
294 SdrLayerID nNewLayerId = nToHellLayerId;
295 if ( ::CheckControlLayer( _pDrawObj ) )
297 // it has to be the control layer, if one of the member
298 // is a control
299 nNewLayerId = nToControlLayerId;
301 else if ( _pDrawObj->GetLayer() == rIDDMA.GetHeavenId() ||
302 _pDrawObj->GetLayer() == rIDDMA.GetInvisibleHeavenId() )
304 // it has to be the heaven layer, if method <GetLayer()> reveals
305 // a heaven layer
306 nNewLayerId = nToHeavenLayerId;
308 // set layer at group object, but do *not* broadcast and
309 // no propagation to the members.
310 // Thus, call <NbcSetLayer(..)> at super class
311 _pDrawObj->SdrObject::NbcSetLayer( nNewLayerId );
314 // call method recursively for group object members
315 const SdrObjList* pLst =
316 static_cast<SdrObjGroup*>(_pDrawObj)->GetSubList();
317 if ( pLst )
319 for (const rtl::Reference<SdrObject>& pObj : *pLst)
321 MoveObjToLayer( _bToVisible, pObj.get() );
325 else
327 const SdrLayerID nLayerIdOfObj = _pDrawObj->GetLayer();
328 if ( nLayerIdOfObj == nFromHellLayerId )
330 _pDrawObj->SetLayer( nToHellLayerId );
332 else if ( nLayerIdOfObj == nFromHeavenLayerId )
334 _pDrawObj->SetLayer( nToHeavenLayerId );
336 else if ( nLayerIdOfObj == nFromControlLayerId )
338 _pDrawObj->SetLayer( nToControlLayerId );
343 /// get minimum order number of anchored objects handled by with contact
344 sal_uInt32 SwContact::GetMinOrdNum() const
346 sal_uInt32 nMinOrdNum( SAL_MAX_UINT32 );
348 std::vector< SwAnchoredObject* > aObjs;
349 GetAnchoredObjs( aObjs );
351 while ( !aObjs.empty() )
353 sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
355 if ( nTmpOrdNum < nMinOrdNum )
357 nMinOrdNum = nTmpOrdNum;
360 aObjs.pop_back();
363 OSL_ENSURE( nMinOrdNum != SAL_MAX_UINT32,
364 "<SwContact::GetMinOrdNum()> - no order number found." );
365 return nMinOrdNum;
368 /// get maximum order number of anchored objects handled by with contact
369 sal_uInt32 SwContact::GetMaxOrdNum() const
371 sal_uInt32 nMaxOrdNum( 0 );
373 std::vector< SwAnchoredObject* > aObjs;
374 GetAnchoredObjs( aObjs );
376 while ( !aObjs.empty() )
378 sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
380 if ( nTmpOrdNum > nMaxOrdNum )
382 nMaxOrdNum = nTmpOrdNum;
385 aObjs.pop_back();
388 return nMaxOrdNum;
391 namespace
393 Point lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj, const bool bFollowTextFlow, sw::WW8AnchorConv& reConv)
395 switch(reConv)
397 case sw::WW8AnchorConv::CONV2PG:
399 bool bRelToTableCell(false);
400 Point aPos(pAnchoredObj->GetRelPosToPageFrame(bFollowTextFlow, bRelToTableCell));
401 if(bRelToTableCell)
402 reConv = sw::WW8AnchorConv::RELTOTABLECELL;
403 return aPos;
405 case sw::WW8AnchorConv::CONV2COL_OR_PARA:
406 return pAnchoredObj->GetRelPosToAnchorFrame();
407 case sw::WW8AnchorConv::CONV2CHAR:
408 return pAnchoredObj->GetRelPosToChar();
409 case sw::WW8AnchorConv::CONV2LINE:
410 return pAnchoredObj->GetRelPosToLine();
411 default: ;
413 return Point();
416 void SwContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
418 // this does not call SwClient::SwClientNotify and thus doesn't handle RES_OBJECTDYING as usual. Is this intentional?
419 if (rHint.GetId() == SfxHintId::SwFindSdrObject)
421 auto pFindSdrObjectHint = static_cast<const sw::FindSdrObjectHint*>(&rHint);
422 if(!pFindSdrObjectHint->m_rpObject)
423 pFindSdrObjectHint->m_rpObject = GetMaster();
425 else if (rHint.GetId() == SfxHintId::SwWW8AnchorConv)
427 auto pWW8AnchorConvHint = static_cast<const sw::WW8AnchorConvHint*>(&rHint);
428 // determine anchored object
429 SwAnchoredObject* pAnchoredObj(nullptr);
431 std::vector<SwAnchoredObject*> aAnchoredObjs;
432 GetAnchoredObjs(aAnchoredObjs);
433 if(!aAnchoredObjs.empty())
434 pAnchoredObj = aAnchoredObjs.front();
436 // no anchored object found. Thus, the needed layout information can't
437 // be determined. --> no conversion
438 if(!pAnchoredObj)
439 return;
440 // no conversion for anchored drawing object, which aren't attached to an
441 // anchor frame.
442 // This is the case for drawing objects, which are anchored inside a page
443 // header/footer of an *unused* page style.
444 if(dynamic_cast<SwAnchoredDrawObject*>(pAnchoredObj) && !pAnchoredObj->GetAnchorFrame())
445 return;
446 const bool bFollowTextFlow = static_cast<const SwFrameFormat&>(rMod).GetFollowTextFlow().GetValue();
447 sw::WW8AnchorConvResult& rResult(pWW8AnchorConvHint->m_rResult);
448 // No distinction between layout directions, because of missing
449 // information about WW8 in vertical layout.
450 rResult.m_aPos.setX(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eHoriConv).getX());
451 rResult.m_aPos.setY(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eVertConv).getY());
452 rResult.m_bConverted = true;
457 SwFlyDrawContact::SwFlyDrawContact(
458 SwFlyFrameFormat *pToRegisterIn,
459 SdrModel& rTargetModel)
460 : SwContact(pToRegisterIn),
461 mpMasterObj(new SwFlyDrawObj(rTargetModel))
463 // #i26791# - class <SwFlyDrawContact> contains the 'master'
464 // drawing object of type <SwFlyDrawObj> on its own.
465 mpMasterObj->SetOrdNum( 0xFFFFFFFE );
466 mpMasterObj->SetUserCall( this );
469 SwFlyDrawContact::~SwFlyDrawContact()
471 if ( mpMasterObj )
473 mpMasterObj->SetUserCall( nullptr );
474 if ( mpMasterObj->getSdrPageFromSdrObject() )
475 mpMasterObj->getSdrPageFromSdrObject()->RemoveObject( mpMasterObj->GetOrdNum() );
479 sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly,
480 SwFrame const& rAnchorFrame)
482 // maintain invariant that a shape's textbox immediately follows the shape
483 // also for the multiple SdrVirtObj created for shapes in header/footer
484 if (SwFrameFormat const*const pDrawFormat =
485 SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT))
487 // assume that the draw SdrVirtObj is always created before the flyframe one
488 if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
490 for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
492 if (pAnchoredObj->GetFrameFormat() == pDrawFormat)
494 return pAnchoredObj->GetDrawObj()->GetOrdNum() + 1;
498 // if called from AppendObjs(), this is a problem; if called from lcl_SetFlyFrameAttr() it's not
499 SAL_INFO("sw", "GetOrdNumForNewRef: cannot find SdrObject for text box's shape");
501 // search for another Writer fly frame registered at same frame format
502 SwIterator<SwFlyFrame,SwFormat> aIter(*GetFormat());
503 const SwFlyFrame* pFlyFrame(nullptr);
504 for(pFlyFrame = aIter.First(); pFlyFrame; pFlyFrame = aIter.Next())
506 if(pFlyFrame != pFly)
507 break;
510 if(pFlyFrame)
512 // another Writer fly frame found. Take its order number
513 return pFlyFrame->GetVirtDrawObj()->GetOrdNum();
515 // no other Writer fly frame found. Take order number of 'master' object
516 // #i35748# - use method <GetOrdNumDirect()> instead
517 // of method <GetOrdNum()> to avoid a recalculation of the order number,
518 // which isn't intended.
519 return GetMaster()->GetOrdNumDirect();
522 SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly,
523 SwFlyFrameFormat* pFormat, SwFrame const& rAnchorFrame)
525 // Find ContactObject from the Format. If there's already one, we just
526 // need to create a new Ref, else we create the Contact now.
528 IDocumentDrawModelAccess& rIDDMA = pFormat->getIDocumentDrawModelAccess();
529 SwFlyDrawContact* pContact = pFormat->GetOrCreateContact();
530 rtl::Reference<SwVirtFlyDrawObj> pDrawObj(
531 new SwVirtFlyDrawObj(
532 pContact->GetMaster()->getSdrModelFromSdrObject(),
533 *pContact->GetMaster(),
534 pFly));
535 pDrawObj->SetUserCall(pContact);
537 // The Reader creates the Masters and inserts them into the Page in
538 // order to transport the z-order.
539 // After creating the first Reference the Masters are removed from the
540 // List and are not important anymore.
541 SdrPage* pPg = pContact->GetMaster()->getSdrPageFromSdrObject();
542 if(nullptr != pPg)
544 const size_t nOrdNum = pContact->GetMaster()->GetOrdNum();
545 pPg->ReplaceObject(pDrawObj.get(), nOrdNum);
547 // #i27030# - insert new <SwVirtFlyDrawObj> instance
548 // into drawing page with correct order number
549 else
550 rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj.get(), pContact->GetOrdNumForNewRef(pFly, rAnchorFrame));
551 // #i38889# - assure, that new <SwVirtFlyDrawObj> instance
552 // is in a visible layer.
553 pContact->MoveObjToVisibleLayer(pDrawObj.get());
554 return pDrawObj.get();
557 // #i26791#
558 const SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(const SdrObject* pSdrObj) const
560 assert(pSdrObj);
561 assert(dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) != nullptr);
562 assert(GetUserCall(pSdrObj) == this &&
563 "<SwFlyDrawContact::GetAnchoredObj(..)> - provided object doesn't belong to this contact");
565 const SwAnchoredObject *const pRetAnchoredObj =
566 static_cast<const SwVirtFlyDrawObj*>(pSdrObj)->GetFlyFrame();
568 return pRetAnchoredObj;
571 SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
573 return const_cast<SwAnchoredObject *>(const_cast<SwFlyDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
576 SdrObject* SwFlyDrawContact::GetMaster()
578 return mpMasterObj.get();
582 * @note Overriding method to control Writer fly frames, which are linked, and
583 * to assure that all objects anchored at/inside the Writer fly frame are
584 * also made visible.
586 void SwFlyDrawContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
588 assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
590 if ( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
592 // nothing to do
593 return;
596 SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
598 // #i44464# - consider, that Writer fly frame content
599 // already exists - (e.g. WW8 document is inserted into an existing document).
600 if ( !pFlyFrame->Lower() )
602 pFlyFrame->InsertColumns();
603 pFlyFrame->Chain( pFlyFrame->AnchorFrame() );
604 pFlyFrame->InsertCnt();
606 if ( pFlyFrame->GetDrawObjs() )
608 for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
610 // #i28701# - consider type of objects in sorted object list.
611 SdrObject* pObj = i->DrawObj();
612 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
613 pContact->MoveObjToVisibleLayer( pObj );
617 // make fly frame visible
618 SwContact::MoveObjToVisibleLayer( _pDrawObj );
622 * @note Override method to control Writer fly frames, which are linked, and
623 * to assure that all objects anchored at/inside the Writer fly frame are
624 * also made invisible.
626 void SwFlyDrawContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
628 assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
630 if ( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
632 // nothing to do
633 return;
636 SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
638 pFlyFrame->Unchain();
639 pFlyFrame->DeleteCnt();
640 if ( pFlyFrame->GetDrawObjs() )
642 for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
644 // #i28701# - consider type of objects in sorted object list.
645 SdrObject* pObj = i->DrawObj();
646 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
647 pContact->MoveObjToInvisibleLayer( pObj );
651 // make fly frame invisible
652 SwContact::MoveObjToInvisibleLayer( _pDrawObj );
655 /// get data collection of anchored objects, handled by with contact
656 void SwFlyDrawContact::GetAnchoredObjs( std::vector<SwAnchoredObject*>& _roAnchoredObjs ) const
658 const SwFrameFormat* pFormat = GetFormat();
659 SwFlyFrame::GetAnchoredObjects( _roAnchoredObjs, *pFormat );
661 void SwFlyDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
663 SwContact::SwClientNotify(rMod, rHint);
664 if(rHint.GetId() == SfxHintId::SwGetZOrder)
666 auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint);
667 // #i11176#
668 // This also needs to work when no layout exists. Thus, for
669 // FlyFrames an alternative method is used now in that case.
670 auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
671 if (pFormat && pFormat->Which() == RES_FLYFRMFMT && !pFormat->getIDocumentLayoutAccess().GetCurrentViewShell())
672 pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
676 // SwDrawContact
678 bool CheckControlLayer( const SdrObject *pObj )
680 if ( SdrInventor::FmForm == pObj->GetObjInventor() )
681 return true;
682 if (const SdrObjGroup *pObjGroup = dynamic_cast<const SdrObjGroup*>(pObj))
684 const SdrObjList *pLst = pObjGroup->GetSubList();
685 for (const rtl::Reference<SdrObject>& pChildObj : *pLst)
687 if ( ::CheckControlLayer( pChildObj.get() ) )
689 // #i18447# - return correct value ;-)
690 return true;
694 return false;
697 SwDrawContact::SwDrawContact( SwFrameFormat* pToRegisterIn, SdrObject* pObj ) :
698 SwContact( pToRegisterIn ),
699 mbMasterObjCleared( false ),
700 mbDisconnectInProgress( false ),
701 mbUserCallActive( false ),
702 // Note: value of <meEventTypeOfCurrentUserCall> isn't of relevance, because
703 // <mbUserCallActive> is false.
704 meEventTypeOfCurrentUserCall( SdrUserCallType::MoveOnly )
706 // --> #i33909# - assure, that drawing object is inserted
707 // in the drawing page.
708 if ( !pObj->IsInserted() )
710 pToRegisterIn->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
711 InsertObject( pObj, pObj->GetOrdNumDirect() );
714 // Controls have to be always in the Control-Layer. This is also true for
715 // group objects, if they contain controls.
716 if ( ::CheckControlLayer( pObj ) )
718 // set layer of object to corresponding invisible layer.
719 pObj->SetLayer( pToRegisterIn->getIDocumentDrawModelAccess().GetInvisibleControlsId() );
722 // #i26791#
723 pObj->SetUserCall( this );
724 maAnchoredDrawObj.SetDrawObj( *pObj );
726 // if there already exists an SwXShape for the object, ensure it knows about us, and the SdrObject
727 // #i99056#
728 SwXShape::AddExistingShapeToFormat( *pObj );
731 SwDrawContact::~SwDrawContact()
733 SetInDTOR();
735 DisconnectFromLayout();
737 // remove 'master' from drawing page
738 RemoveMasterFromDrawPage();
740 // remove and destroy 'virtual' drawing objects.
741 RemoveAllVirtObjs();
743 if ( !mbMasterObjCleared )
744 maAnchoredDrawObj.ClearDrawObj();
747 void SwDrawContact::GetTextObjectsFromFormat(std::list<SdrTextObj*>& o_rTextObjects, SwDoc& rDoc)
749 for(sw::SpzFrameFormat* pFly: *rDoc.GetSpzFrameFormats())
751 if(pFly->Which() == RES_DRAWFRMFMT) // ie. SwDrawFrameFormat*
752 pFly->CallSwClientNotify(sw::CollectTextObjectsHint(o_rTextObjects));
756 // #i26791#
757 const SwAnchoredObject* SwDrawContact::GetAnchoredObj(const SdrObject* pSdrObj ) const
759 // handle default parameter value
760 if (!pSdrObj)
762 pSdrObj = GetMaster();
765 assert(pSdrObj);
766 assert(dynamic_cast<const SwDrawVirtObj*>(pSdrObj) != nullptr ||
767 dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
768 assert((GetUserCall(pSdrObj) == this ||
769 pSdrObj == GetMaster()) &&
770 "<SwDrawContact::GetAnchoredObj(..)> - provided object doesn't belongs to this contact" );
772 const SwAnchoredObject* pRetAnchoredObj = nullptr;
774 if (auto pVirtObj = dynamic_cast<const SwDrawVirtObj*>(pSdrObj))
776 pRetAnchoredObj = &(pVirtObj->GetAnchoredObj());
778 else
780 assert(dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
781 pRetAnchoredObj = &maAnchoredDrawObj;
784 return pRetAnchoredObj;
787 SwAnchoredObject* SwDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
789 return const_cast<SwAnchoredObject*>(const_cast<SwDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
792 SdrObject* SwDrawContact::GetMaster()
794 return !mbMasterObjCleared
795 ? maAnchoredDrawObj.DrawObj()
796 : nullptr;
799 const SwFrame* SwDrawContact::GetAnchorFrame( const SdrObject* _pDrawObj ) const
801 const SwFrame* pAnchorFrame = nullptr;
802 if ( !_pDrawObj ||
803 _pDrawObj == GetMaster() ||
804 ( !_pDrawObj->GetUserCall() &&
805 GetUserCall( _pDrawObj ) == this ) )
807 pAnchorFrame = maAnchoredDrawObj.GetAnchorFrame();
809 else
811 assert(dynamic_cast<SwDrawVirtObj const*>(_pDrawObj) != nullptr);
812 pAnchorFrame = static_cast<const SwDrawVirtObj*>(_pDrawObj)->GetAnchorFrame();
815 return pAnchorFrame;
818 SwFrame* SwDrawContact::GetAnchorFrame(SdrObject const *const pDrawObj)
820 return const_cast<SwFrame *>(const_cast<SwDrawContact const*>(this)->GetAnchorFrame(pDrawObj));
823 /** add a 'virtual' drawing object to drawing page.
825 SwDrawVirtObj* SwDrawContact::AddVirtObj(SwFrame const& rAnchorFrame)
827 maDrawVirtObjs.push_back(
828 new SwDrawVirtObj(
829 GetMaster()->getSdrModelFromSdrObject(),
830 *GetMaster(),
831 *this));
832 maDrawVirtObjs.back()->AddToDrawingPage(rAnchorFrame);
833 return maDrawVirtObjs.back().get();
836 /// remove 'virtual' drawing objects and destroy them.
837 void SwDrawContact::RemoveAllVirtObjs()
839 for(auto& rpDrawVirtObj : maDrawVirtObjs)
841 // remove and destroy 'virtual object'
842 rpDrawVirtObj->RemoveFromWriterLayout();
843 rpDrawVirtObj->RemoveFromDrawingPage();
844 // to break the reference cycle
845 rpDrawVirtObj->AnchoredObj().ClearDrawObj();
847 maDrawVirtObjs.clear();
851 /// get drawing object ('master' or 'virtual') by frame.
852 SdrObject* SwDrawContact::GetDrawObjectByAnchorFrame( const SwFrame& _rAnchorFrame )
854 SdrObject* pRetDrawObj = nullptr;
856 // #i26791# - compare master frames instead of direct frames
857 const SwFrame* pProposedAnchorFrame = &_rAnchorFrame;
858 if ( pProposedAnchorFrame->IsContentFrame() )
860 const SwContentFrame* pTmpFrame =
861 static_cast<const SwContentFrame*>( pProposedAnchorFrame );
862 while ( pTmpFrame->IsFollow() )
864 pTmpFrame = pTmpFrame->FindMaster();
866 pProposedAnchorFrame = pTmpFrame;
869 const SwFrame* pMasterObjAnchorFrame = GetAnchorFrame();
870 if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame->IsContentFrame() )
872 const SwContentFrame* pTmpFrame =
873 static_cast<const SwContentFrame*>( pMasterObjAnchorFrame );
874 while ( pTmpFrame->IsFollow() )
876 pTmpFrame = pTmpFrame->FindMaster();
878 pMasterObjAnchorFrame = pTmpFrame;
881 if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame == pProposedAnchorFrame )
883 pRetDrawObj = GetMaster();
885 else
887 const auto ppFoundVirtObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
888 VirtObjAnchoredAtFramePred(pProposedAnchorFrame)));
889 if(ppFoundVirtObj != maDrawVirtObjs.end())
890 pRetDrawObj = ppFoundVirtObj->get();
893 return pRetDrawObj;
896 void SwDrawContact::NotifyBackgroundOfAllVirtObjs(const tools::Rectangle* pOldBoundRect)
898 for(const auto& rpDrawVirtObj : maDrawVirtObjs)
900 SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
901 if ( pDrawVirtObj->GetAnchorFrame() )
903 // #i34640# - determine correct page frame
904 SwPageFrame* pPage = pDrawVirtObj->AnchoredObj().FindPageFrameOfAnchor();
905 if( pOldBoundRect && pPage )
907 SwRect aOldRect( *pOldBoundRect );
908 aOldRect.Pos() += pDrawVirtObj->GetOffset();
909 if( aOldRect.HasArea() )
910 ::Notify_Background( pDrawVirtObj, pPage,
911 aOldRect, PrepareHint::FlyFrameLeave,true);
913 // #i34640# - include spacing for wrapping
914 SwRect aRect( pDrawVirtObj->GetAnchoredObj().GetObjRectWithSpaces() );
915 if (aRect.HasArea() && pPage)
917 SwPageFrame* pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aRect, pPage )));
918 if ( pPg )
919 ::Notify_Background( pDrawVirtObj, pPg, aRect,
920 PrepareHint::FlyFrameArrive, true );
922 ::ClrContourCache( pDrawVirtObj );
927 /// local method to notify the background for a drawing object - #i26791#
928 static void lcl_NotifyBackgroundOfObj( SwDrawContact const & _rDrawContact,
929 const SdrObject& _rObj,
930 const tools::Rectangle* _pOldObjRect )
932 // #i34640#
933 SwAnchoredObject* pAnchoredObj =
934 const_cast<SwAnchoredObject*>(_rDrawContact.GetAnchoredObj( &_rObj ));
935 if ( !(pAnchoredObj && pAnchoredObj->GetAnchorFrame()) )
936 return;
938 // #i34640# - determine correct page frame
939 SwPageFrame* pPageFrame = pAnchoredObj->FindPageFrameOfAnchor();
940 if( _pOldObjRect && pPageFrame )
942 SwRect aOldRect( *_pOldObjRect );
943 if( aOldRect.HasArea() )
945 // #i34640# - determine correct page frame
946 SwPageFrame* pOldPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aOldRect, pPageFrame )));
947 ::Notify_Background( &_rObj, pOldPageFrame, aOldRect,
948 PrepareHint::FlyFrameLeave, true);
951 // #i34640# - include spacing for wrapping
952 SwRect aNewRect( pAnchoredObj->GetObjRectWithSpaces() );
953 if( aNewRect.HasArea() && pPageFrame )
955 pPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aNewRect, pPageFrame )));
956 ::Notify_Background( &_rObj, pPageFrame, aNewRect,
957 PrepareHint::FlyFrameArrive, true );
959 ClrContourCache( &_rObj );
962 void SwDrawContact::Changed( const SdrObject& rObj,
963 SdrUserCallType eType,
964 const tools::Rectangle& rOldBoundRect )
966 // #i26791# - no event handling, if existing <SwViewShell>
967 // is in construction
968 SwDoc* pDoc = GetFormat()->GetDoc();
969 if ( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() &&
970 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor() )
972 return;
975 // #i44339#
976 // no event handling, if document is in destruction.
977 // Exception: It's the SdrUserCallType::Delete event
978 if ( pDoc->IsInDtor() && eType != SdrUserCallType::Delete )
980 return;
983 //Put on Action, but not if presently anywhere an action runs.
984 bool bHasActions(true);
985 SwRootFrame *pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
986 if ( pTmpRoot && pTmpRoot->IsCallbackActionEnabled() )
988 SwViewShell* const pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
989 if ( pSh )
991 for(SwViewShell& rShell : pSh->GetRingContainer() )
993 if ( rShell.Imp()->IsAction() || rShell.Imp()->IsIdleAction() )
995 bHasActions = true;
996 break;
998 bHasActions = false;
1001 if(!bHasActions)
1002 pTmpRoot->StartAllAction();
1004 SdrObjUserCall::Changed( rObj, eType, rOldBoundRect );
1005 Changed_( rObj, eType, &rOldBoundRect ); //Attention, possibly suicidal!
1007 if(!bHasActions)
1008 pTmpRoot->EndAllAction();
1011 /// helper class for method <SwDrawContact::Changed_(..)> for handling nested
1012 /// <SdrObjUserCall> events
1013 class NestedUserCallHdl
1015 private:
1016 SwDrawContact* mpDrawContact;
1017 bool mbParentUserCallActive;
1018 SdrUserCallType meParentUserCallEventType;
1020 public:
1021 NestedUserCallHdl( SwDrawContact* _pDrawContact,
1022 SdrUserCallType _eEventType )
1023 : mpDrawContact( _pDrawContact ),
1024 mbParentUserCallActive( _pDrawContact->mbUserCallActive ),
1025 meParentUserCallEventType( _pDrawContact->meEventTypeOfCurrentUserCall )
1027 mpDrawContact->mbUserCallActive = true;
1028 mpDrawContact->meEventTypeOfCurrentUserCall = _eEventType;
1031 ~NestedUserCallHdl()
1033 if ( mpDrawContact )
1035 mpDrawContact->mbUserCallActive = mbParentUserCallActive;
1036 mpDrawContact->meEventTypeOfCurrentUserCall = meParentUserCallEventType;
1040 void DrawContactDeleted()
1042 mpDrawContact = nullptr;
1045 bool IsNestedUserCall() const
1047 return mbParentUserCallActive;
1050 void AssertNestedUserCall()
1052 if ( !IsNestedUserCall() )
1053 return;
1055 bool bTmpAssert( true );
1056 // Currently its known, that a nested event SdrUserCallType::Resize
1057 // could occur during parent user call SdrUserCallType::Inserted,
1058 // SdrUserCallType::Delete and SdrUserCallType::Resize for edge objects.
1059 // Also possible are nested SdrUserCallType::ChildResize events for
1060 // edge objects
1061 // Thus, assert all other combinations
1062 if ( ( meParentUserCallEventType == SdrUserCallType::Inserted ||
1063 meParentUserCallEventType == SdrUserCallType::Delete ||
1064 meParentUserCallEventType == SdrUserCallType::Resize ) &&
1065 mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::Resize )
1067 bTmpAssert = false;
1069 else if ( meParentUserCallEventType == SdrUserCallType::ChildResize &&
1070 mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::ChildResize )
1072 bTmpAssert = false;
1075 if ( bTmpAssert )
1077 OSL_FAIL( "<SwDrawContact::Changed_(..)> - unknown nested <UserCall> event. This is serious." );
1082 /// Notify the format's textbox that it should reconsider its position / size.
1083 static void lcl_textBoxSizeNotify(SwFrameFormat* pFormat)
1085 if (SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT))
1087 // Just notify the textbox that the size has changed, the actual object size is not interesting.
1088 SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aResizeSet(pFormat->GetDoc()->GetAttrPool());
1089 SwFormatFrameSize aSize;
1090 aResizeSet.Put(aSize);
1091 SwTextBoxHelper::syncFlyFrameAttr(*pFormat, aResizeSet, pFormat->FindRealSdrObject());
1095 // !!!ATTENTION!!! The object may commit suicide!!!
1097 void SwDrawContact::Changed_( const SdrObject& rObj,
1098 SdrUserCallType eType,
1099 const tools::Rectangle* pOldBoundRect )
1101 // suppress handling of nested <SdrObjUserCall> events
1102 NestedUserCallHdl aNestedUserCallHdl( this, eType );
1103 if ( aNestedUserCallHdl.IsNestedUserCall() )
1105 aNestedUserCallHdl.AssertNestedUserCall();
1106 return;
1108 // do *not* notify, if document is destructing
1109 // #i35912# - do *not* notify for as-character anchored
1110 // drawing objects.
1111 // #i35007#
1112 // improvement: determine as-character anchored object flag only once.
1113 const bool bAnchoredAsChar = ObjAnchoredAsChar();
1114 const bool bNotify = !(GetFormat()->GetDoc()->IsInDtor()) &&
1115 ( css::text::WrapTextMode_THROUGH != GetFormat()->GetSurround().GetSurround() ) &&
1116 !bAnchoredAsChar;
1117 switch( eType )
1119 case SdrUserCallType::Delete:
1121 if ( bNotify )
1123 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1124 // --> #i36181# - background of 'virtual'
1125 // drawing objects have also been notified.
1126 NotifyBackgroundOfAllVirtObjs( pOldBoundRect );
1128 DisconnectFromLayout( false );
1129 mbMasterObjCleared = true;
1130 delete this;
1131 // --> #i65784# Prevent memory corruption
1132 aNestedUserCallHdl.DrawContactDeleted();
1133 break;
1135 case SdrUserCallType::Inserted:
1137 if ( mbDisconnectInProgress )
1139 OSL_FAIL( "<SwDrawContact::Changed_(..)> - Insert event during disconnection from layout is invalid." );
1141 else
1143 ConnectToLayout();
1144 if ( bNotify )
1146 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1149 break;
1151 case SdrUserCallType::Removed:
1153 if ( bNotify )
1155 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1157 DisconnectFromLayout( false );
1158 break;
1160 case SdrUserCallType::ChildInserted :
1161 case SdrUserCallType::ChildRemoved :
1163 // --> #i113730#
1164 // force layer of controls for group objects containing control objects
1165 if(dynamic_cast< SdrObjGroup* >(maAnchoredDrawObj.DrawObj()))
1167 if(::CheckControlLayer(maAnchoredDrawObj.DrawObj()))
1169 const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
1170 const SdrLayerID aCurrentLayer(maAnchoredDrawObj.DrawObj()->GetLayer());
1171 const SdrLayerID aControlLayerID(rIDDMA.GetControlsId());
1172 const SdrLayerID aInvisibleControlLayerID(rIDDMA.GetInvisibleControlsId());
1174 if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID)
1176 if ( aCurrentLayer == rIDDMA.GetInvisibleHellId() ||
1177 aCurrentLayer == rIDDMA.GetInvisibleHeavenId() )
1179 maAnchoredDrawObj.DrawObj()->SetLayer(aInvisibleControlLayerID);
1181 else
1183 maAnchoredDrawObj.DrawObj()->SetLayer(aControlLayerID);
1188 [[fallthrough]];
1190 case SdrUserCallType::MoveOnly:
1191 case SdrUserCallType::Resize:
1192 case SdrUserCallType::ChildMoveOnly :
1193 case SdrUserCallType::ChildResize :
1194 case SdrUserCallType::ChildChangeAttr :
1195 case SdrUserCallType::ChildDelete :
1197 // #i31698# - improvement
1198 // get instance <SwAnchoredDrawObject> only once
1199 const SwAnchoredDrawObject* pAnchoredDrawObj =
1200 static_cast<const SwAnchoredDrawObject*>( GetAnchoredObj( &rObj ) );
1202 /* protect against NULL pointer dereferencing */
1203 if(!pAnchoredDrawObj)
1205 break;
1208 // #i26791# - adjust positioning and alignment attributes,
1209 // if positioning of drawing object isn't in progress.
1210 // #i53320# - no adjust of positioning attributes,
1211 // if drawing object isn't positioned.
1212 if ( !pAnchoredDrawObj->IsPositioningInProgress() &&
1213 !pAnchoredDrawObj->NotYetPositioned() )
1215 // #i34748# - If no last object rectangle is
1216 // provided by the anchored object, use parameter <pOldBoundRect>.
1217 const tools::Rectangle& aOldObjRect = pAnchoredDrawObj->GetLastObjRect()
1218 ? *(pAnchoredDrawObj->GetLastObjRect())
1219 : *pOldBoundRect;
1220 // #i79400#
1221 // always invalidate object rectangle inclusive spaces
1222 pAnchoredDrawObj->InvalidateObjRectWithSpaces();
1223 // #i41324# - notify background before
1224 // adjusting position
1225 if ( bNotify )
1227 // #i31573# - correction
1228 // background of given drawing object.
1229 lcl_NotifyBackgroundOfObj( *this, rObj, &aOldObjRect );
1231 // #i31698# - determine layout direction
1232 // via draw frame format.
1233 SwFrameFormat::tLayoutDir eLayoutDir =
1234 pAnchoredDrawObj->GetFrameFormat()->GetLayoutDir();
1235 // use geometry of drawing object
1236 tools::Rectangle aObjRect( rObj.GetSnapRect() );
1237 // If drawing object is a member of a group, the adjustment
1238 // of the positioning and the alignment attributes has to
1239 // be done for the top group object.
1240 if ( rObj.getParentSdrObjectFromSdrObject() )
1242 const SdrObject* pGroupObj = rObj.getParentSdrObjectFromSdrObject();
1243 while ( pGroupObj->getParentSdrObjectFromSdrObject() )
1245 pGroupObj = pGroupObj->getParentSdrObjectFromSdrObject();
1247 // use geometry of drawing object
1248 aObjRect = pGroupObj->GetSnapRect();
1250 SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::changeAnchor, GetFormat(), &const_cast<SdrObject&>(rObj));
1251 SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::syncTextBoxSize, GetFormat(), &const_cast<SdrObject&>(rObj));
1254 SwTwips nXPosDiff(0);
1255 SwTwips nYPosDiff(0);
1256 switch ( eLayoutDir )
1258 case SwFrameFormat::HORI_L2R:
1260 nXPosDiff = aObjRect.Left() - aOldObjRect.Left();
1261 nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1263 break;
1264 case SwFrameFormat::HORI_R2L:
1266 nXPosDiff = aOldObjRect.Right() - aObjRect.Right();
1267 nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1269 break;
1270 case SwFrameFormat::VERT_R2L:
1272 nXPosDiff = aObjRect.Top() - aOldObjRect.Top();
1273 nYPosDiff = aOldObjRect.Right() - aObjRect.Right();
1275 break;
1276 default:
1278 assert(!"<SwDrawContact::Changed_(..)> - unsupported layout direction");
1281 SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT> aSet( GetFormat()->GetDoc()->GetAttrPool() );
1282 const SwFormatVertOrient& rVert = GetFormat()->GetVertOrient();
1283 if ( nYPosDiff != 0 )
1285 if ( rVert.GetRelationOrient() == text::RelOrientation::CHAR ||
1286 rVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
1288 nYPosDiff = -nYPosDiff;
1290 aSet.Put( SwFormatVertOrient( rVert.GetPos()+nYPosDiff,
1291 text::VertOrientation::NONE,
1292 rVert.GetRelationOrient() ) );
1295 const SwFormatHoriOrient& rHori = GetFormat()->GetHoriOrient();
1296 if ( !bAnchoredAsChar && nXPosDiff != 0 )
1298 aSet.Put( SwFormatHoriOrient( rHori.GetPos()+nXPosDiff,
1299 text::HoriOrientation::NONE,
1300 rHori.GetRelationOrient() ) );
1303 if ( nYPosDiff ||
1304 ( !bAnchoredAsChar && nXPosDiff != 0 ) )
1306 GetFormat()->GetDoc()->SetFlyFrameAttr( *(GetFormat()), aSet );
1307 // keep new object rectangle, to avoid multiple
1308 // changes of the attributes by multiple event from
1309 // the drawing layer - e.g. group objects and its members
1310 // #i34748# - use new method
1311 // <SwAnchoredDrawObject::SetLastObjRect(..)>.
1312 const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)
1313 ->SetLastObjRect( aObjRect );
1315 else if ( aObjRect.GetSize() != aOldObjRect.GetSize() )
1317 InvalidateObjs_();
1318 // #i35007# - notify anchor frame
1319 // of as-character anchored object
1320 if ( bAnchoredAsChar )
1322 SwFrame* pAnchorFrame = const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)->AnchorFrame();
1323 if(pAnchorFrame)
1325 pAnchorFrame->Prepare( PrepareHint::FlyFrameAttributesChanged, GetFormat() );
1329 lcl_textBoxSizeNotify(GetFormat());
1331 else if (eType == SdrUserCallType::Resize)
1332 // Even if the bounding box of the shape didn't change,
1333 // notify about the size change, as an adjustment change
1334 // may affect the size of the underlying textbox.
1335 lcl_textBoxSizeNotify(GetFormat());
1338 // tdf#135198: keep text box together with its shape
1339 const SwPageFrame* rPageFrame = pAnchoredDrawObj->GetPageFrame();
1340 if (rPageFrame && rPageFrame->isFrameAreaPositionValid() && GetFormat()
1341 && GetFormat()->GetOtherTextBoxFormats())
1343 SwDoc* const pDoc = GetFormat()->GetDoc();
1345 // avoid Undo creation
1346 ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1348 // hide any artificial "changes" made by synchronizing the textbox position
1349 const bool bEnableSetModified = pDoc->getIDocumentState().IsEnableSetModified();
1350 pDoc->getIDocumentState().SetEnableSetModified(false);
1352 SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT, RES_ANCHOR, RES_ANCHOR>
1353 aSyncSet( pDoc->GetAttrPool() );
1354 aSyncSet.Put(GetFormat()->GetHoriOrient());
1355 bool bRelToTableCell(false);
1356 aSyncSet.Put(SwFormatVertOrient(pAnchoredDrawObj->GetRelPosToPageFrame(false, bRelToTableCell).getY(),
1357 text::VertOrientation::NONE,
1358 text::RelOrientation::PAGE_FRAME));
1359 aSyncSet.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, rPageFrame->GetPhyPageNum()));
1361 auto pSdrObj = const_cast<SdrObject*>(&rObj);
1362 if (pSdrObj != GetFormat()->FindRealSdrObject())
1364 SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aSet( pDoc->GetAttrPool() );
1366 aSet.Put(aSyncSet);
1367 aSet.Put(pSdrObj->GetMergedItem(RES_FRM_SIZE));
1368 SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSet, pSdrObj);
1370 SwTextBoxHelper::synchronizeGroupTextBoxProperty(
1371 &SwTextBoxHelper::changeAnchor, GetFormat(),
1372 GetFormat()->FindRealSdrObject());
1373 SwTextBoxHelper::synchronizeGroupTextBoxProperty(
1374 &SwTextBoxHelper::syncTextBoxSize, GetFormat(),
1375 GetFormat()->FindRealSdrObject());
1377 else
1378 SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSyncSet, GetFormat()->FindRealSdrObject());
1380 pDoc->getIDocumentState().SetEnableSetModified(bEnableSetModified);
1383 break;
1384 case SdrUserCallType::ChangeAttr:
1385 if ( bNotify )
1387 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1389 break;
1390 default:
1391 break;
1395 namespace
1397 const SwFormatAnchor* lcl_getAnchorFormat( const SfxPoolItem& _rItem )
1399 sal_uInt16 nWhich = _rItem.Which();
1400 const SwFormatAnchor* pAnchorFormat = nullptr;
1401 if ( RES_ANCHOR == nWhich )
1403 pAnchorFormat = &static_cast<const SwFormatAnchor&>(_rItem);
1405 return pAnchorFormat;
1407 const SwFormatAnchor* lcl_getAnchorFormat( const SwAttrSetChg& _rItem )
1409 return _rItem.GetChgSet()->GetItemIfSet( RES_ANCHOR, false );
1413 void SwDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
1415 SwClient::SwClientNotify(rMod, rHint); // needed as SwContact::SwClientNotify doesn't explicitly call SwClient::SwClientNotify
1416 SwContact::SwClientNotify(rMod, rHint);
1417 if(SfxHintId::SwRemoveUnoObject == rHint.GetId())
1419 // nothing to do
1420 // #i51474#
1421 GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
1423 else if(SfxHintId::SwFormatChange == rHint.GetId()
1424 || SfxHintId::SwUpdateAttr == rHint.GetId())
1426 // #i51474#
1427 GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
1429 else if (rHint.GetId() == SfxHintId::SwLegacyModify
1430 || rHint.GetId() == SfxHintId::SwAttrSetChange
1431 || rHint.GetId() == SfxHintId::SwObjectDying)
1433 SAL_WARN_IF(mbDisconnectInProgress, "sw.core", "<SwDrawContact::Modify(..)> called during disconnection.");
1435 const SwFormatAnchor* pNewAnchorFormat = nullptr;
1436 const SwFormatAnchor* pOldAnchorFormat = nullptr;
1437 if (rHint.GetId() == SfxHintId::SwLegacyModify)
1439 auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
1440 if (pLegacyHint->m_pNew)
1441 pNewAnchorFormat = lcl_getAnchorFormat(*pLegacyHint->m_pNew);
1442 if (pLegacyHint->m_pOld)
1443 pOldAnchorFormat = lcl_getAnchorFormat(*pLegacyHint->m_pOld);
1445 else if (rHint.GetId() == SfxHintId::SwAttrSetChange)
1447 auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
1448 if (pChangeHint->m_pNew)
1449 pNewAnchorFormat = lcl_getAnchorFormat(*pChangeHint->m_pNew);
1450 if (pChangeHint->m_pOld)
1451 pOldAnchorFormat = lcl_getAnchorFormat(*pChangeHint->m_pOld);
1454 if(pNewAnchorFormat)
1456 // Do not respond to a Reset Anchor!
1457 if(GetFormat()->GetAttrSet().GetItemState(RES_ANCHOR, false) == SfxItemState::SET)
1459 // no connect to layout during disconnection
1460 if(!mbDisconnectInProgress)
1462 // determine old object rectangle of 'master' drawing object
1463 // for notification
1464 const tools::Rectangle* pOldRect = nullptr;
1465 tools::Rectangle aOldRect;
1466 if(GetAnchorFrame())
1468 // --> #i36181# - include spacing in object
1469 // rectangle for notification.
1470 aOldRect = maAnchoredDrawObj.GetObjRectWithSpaces().SVRect();
1471 pOldRect = &aOldRect;
1473 // re-connect to layout due to anchor format change
1474 ConnectToLayout(pNewAnchorFormat);
1475 // notify background of drawing objects
1476 lcl_NotifyBackgroundOfObj(*this, *GetMaster(), pOldRect);
1477 NotifyBackgroundOfAllVirtObjs(pOldRect);
1479 if(!pOldAnchorFormat || (pOldAnchorFormat->GetAnchorId() != pNewAnchorFormat->GetAnchorId()))
1481 if(maAnchoredDrawObj.DrawObj())
1483 // --> #i102752#
1484 // assure that a ShapePropertyChangeNotifier exists
1485 maAnchoredDrawObj.DrawObj()->notifyShapePropertyChange(u"AnchorType"_ustr);
1487 else
1488 SAL_WARN("sw.core", "SwDrawContact::Modify: no draw object here?");
1492 else
1493 DisconnectFromLayout();
1495 // --> #i62875# - no further notification, if not connected to Writer layout
1496 else if ( maAnchoredDrawObj.GetAnchorFrame() &&
1497 maAnchoredDrawObj.GetDrawObj()->GetUserCall() )
1499 bool bUpdateSortedObjsList(false);
1500 if (rHint.GetId() == SfxHintId::SwLegacyModify)
1502 auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
1503 sal_uInt16 nWhich = pLegacyHint->m_pNew ? pLegacyHint->m_pNew->Which() : 0;
1504 switch(nWhich)
1506 case RES_UL_SPACE:
1507 case RES_LR_SPACE:
1508 case RES_HORI_ORIENT:
1509 case RES_VERT_ORIENT:
1510 case RES_FOLLOW_TEXT_FLOW: // #i28701# - add attribute 'Follow text flow'
1511 break;
1512 case RES_SURROUND:
1513 case RES_OPAQUE:
1514 case RES_WRAP_INFLUENCE_ON_OBJPOS:
1515 // --> #i28701# - on change of wrapping style, hell|heaven layer,
1516 // or wrapping style influence an update of the <SwSortedObjs> list,
1517 // the drawing object is registered in, has to be performed. This is triggered
1518 // by the 1st parameter of method call <InvalidateObjs_(..)>.
1519 bUpdateSortedObjsList = true;
1520 break;
1521 default:
1522 assert(!"<SwDraw Contact::Modify(..)> - unhandled attribute?");
1525 else if (rHint.GetId() == SfxHintId::SwAttrSetChange)
1527 // #i35443#
1528 auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
1529 auto pChgSet = pChangeHint->m_pNew ? pChangeHint->m_pNew->GetChgSet() : nullptr;
1530 if(pChgSet && (pChgSet->GetItemState(RES_SURROUND, false) == SfxItemState::SET ||
1531 pChgSet->GetItemState(RES_OPAQUE, false) == SfxItemState::SET ||
1532 pChgSet->GetItemState(RES_WRAP_INFLUENCE_ON_OBJPOS, false) == SfxItemState::SET))
1533 bUpdateSortedObjsList = true;
1535 lcl_NotifyBackgroundOfObj(*this, *GetMaster(), nullptr);
1536 NotifyBackgroundOfAllVirtObjs(nullptr);
1537 InvalidateObjs_(bUpdateSortedObjsList);
1540 // #i51474#
1541 GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
1543 else if (rHint.GetId() == SfxHintId::SwDrawFrameFormat)
1545 auto pDrawFrameFormatHint = static_cast<const sw::DrawFrameFormatHint*>(&rHint);
1546 switch(pDrawFrameFormatHint->m_eId)
1548 case sw::DrawFrameFormatHintId::DYING:
1549 delete this;
1550 break;
1551 case sw::DrawFrameFormatHintId::PREPPASTING:
1552 MoveObjToVisibleLayer(GetMaster());
1553 break;
1554 case sw::DrawFrameFormatHintId::PREP_INSERT_FLY:
1555 InsertMasterIntoDrawPage();
1556 // #i40845# - follow-up of #i35635#
1557 // move object to visible layer
1558 MoveObjToVisibleLayer(GetMaster());
1559 // tdf#135661 InsertMasterIntoDrawPage may have created a new
1560 // SwXShape with null m_pFormat; fix that
1561 SwXShape::AddExistingShapeToFormat(*GetMaster());
1562 break;
1563 case sw::DrawFrameFormatHintId::PREP_DELETE_FLY:
1564 RemoveMasterFromDrawPage();
1565 break;
1566 case sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS:
1567 case sw::DrawFrameFormatHintId::DELETE_FRAMES:
1568 DisconnectFromLayout();
1569 break;
1570 case sw::DrawFrameFormatHintId::MAKE_FRAMES:
1571 ConnectToLayout();
1572 break;
1573 case sw::DrawFrameFormatHintId::POST_RESTORE_FLY_ANCHOR:
1574 GetAnchoredObj(GetMaster())->MakeObjPos();
1575 break;
1576 default:
1580 else if (rHint.GetId() == SfxHintId::SwCheckDrawFrameFormatLayer)
1582 auto pCheckDrawFrameFormatLayerHint = static_cast<const sw::CheckDrawFrameFormatLayerHint*>(&rHint);
1583 *(pCheckDrawFrameFormatLayerHint->m_bCheckControlLayer) |= (GetMaster() && CheckControlLayer(GetMaster()));
1585 else if (rHint.GetId() == SfxHintId::SwContactChanged)
1587 auto pContactChangedHint = static_cast<const sw::ContactChangedHint*>(&rHint);
1588 if(!*pContactChangedHint->m_ppObject)
1589 *pContactChangedHint->m_ppObject = GetMaster();
1590 auto pObject = *pContactChangedHint->m_ppObject;
1591 Changed(*pObject, SdrUserCallType::Delete, pObject->GetLastBoundRect());
1593 else if (rHint.GetId() == SfxHintId::SwDrawFormatLayoutCopy)
1595 auto pDrawFormatLayoutCopyHint = static_cast<const sw::DrawFormatLayoutCopyHint*>(&rHint);
1596 const SwDrawFrameFormat& rFormat = static_cast<const SwDrawFrameFormat&>(rMod);
1597 rtl::Reference<SdrObject> xNewObj =
1598 pDrawFormatLayoutCopyHint->m_rDestDoc.CloneSdrObj(
1599 *GetMaster(),
1600 pDrawFormatLayoutCopyHint->m_rDestDoc.IsCopyIsMove() && &pDrawFormatLayoutCopyHint->m_rDestDoc == rFormat.GetDoc());
1601 new SwDrawContact(
1602 &pDrawFormatLayoutCopyHint->m_rDestFormat, xNewObj.get() );
1603 // #i49730# - notify draw frame format that position attributes are
1604 // already set, if the position attributes are already set at the
1605 // source draw frame format.
1606 if(rFormat.IsPosAttrSet())
1607 pDrawFormatLayoutCopyHint->m_rDestFormat.PosAttrSet();
1609 else if (rHint.GetId() == SfxHintId::SwRestoreFlyAnchor)
1611 auto pRestoreFlyAnchorHint = static_cast<const sw::RestoreFlyAnchorHint*>(&rHint);
1612 SdrObject* pObj = GetMaster();
1613 if(GetAnchorFrame() && !pObj->IsInserted())
1615 auto pDrawModel = const_cast<SwDrawFrameFormat&>(static_cast<const SwDrawFrameFormat&>(rMod)).GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1616 assert(pDrawModel);
1617 pDrawModel->GetPage(0)->InsertObject(pObj);
1619 pObj->SetRelativePos(pRestoreFlyAnchorHint->m_aPos);
1621 else if (rHint.GetId() == SfxHintId::SwCreatePortion)
1623 auto pCreatePortionHint = static_cast<const sw::CreatePortionHint*>(&rHint);
1624 if(*pCreatePortionHint->m_ppContact)
1625 return;
1626 *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
1627 if(!GetAnchorFrame())
1629 // No direct positioning needed any more
1630 ConnectToLayout();
1631 // Move object to visible layer
1632 MoveObjToVisibleLayer(GetMaster());
1635 else if (rHint.GetId() == SfxHintId::SwCollectTextObjects)
1637 auto pCollectTextObjectsHint = static_cast<const sw::CollectTextObjectsHint*>(&rHint);
1638 auto pSdrO = GetMaster();
1639 if(!pSdrO)
1640 return;
1641 if(dynamic_cast<const SdrObjGroup*>(pSdrO))
1643 SdrObjListIter aListIter(*pSdrO, SdrIterMode::DeepNoGroups);
1644 //iterate inside of a grouped object
1645 while(aListIter.IsMore())
1647 SdrTextObj* pTextObj = DynCastSdrTextObj(aListIter.Next());
1648 if(pTextObj && pTextObj->HasText())
1649 pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1652 else if(SdrTextObj* pTextObj = DynCastSdrTextObj(pSdrO))
1654 if(pTextObj->HasText())
1655 pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1658 else if (rHint.GetId() == SfxHintId::SwGetZOrder)
1660 auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint);
1661 auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
1662 if (pFormat && pFormat->Which() == RES_DRAWFRMFMT)
1663 pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
1665 else if (rHint.GetId() == SfxHintId::SwGetObjectConnected)
1667 auto pConnectedHint = static_cast<const sw::GetObjectConnectedHint*>(&rHint);
1668 pConnectedHint->m_risConnected |= (GetAnchorFrame() != nullptr);
1672 // #i26791#
1673 // #i28701# - added parameter <_bUpdateSortedObjsList>
1674 void SwDrawContact::InvalidateObjs_( const bool _bUpdateSortedObjsList )
1676 for(const auto& rpDrawVirtObj : maDrawVirtObjs)
1677 // invalidate position of existing 'virtual' drawing objects
1679 SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
1680 // #i33313# - invalidation only for connected
1681 // 'virtual' drawing objects
1682 if ( pDrawVirtObj->IsConnected() )
1684 pDrawVirtObj->AnchoredObj().InvalidateObjPos();
1685 // #i28701#
1686 if ( _bUpdateSortedObjsList )
1688 pDrawVirtObj->AnchoredObj().UpdateObjInSortedList();
1693 // invalidate position of 'master' drawing object
1694 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( nullptr );
1695 pAnchoredObj->InvalidateObjPos();
1696 // #i28701#
1697 if ( _bUpdateSortedObjsList )
1699 pAnchoredObj->UpdateObjInSortedList();
1703 void SwDrawContact::DisconnectFromLayout( bool _bMoveMasterToInvisibleLayer )
1705 mbDisconnectInProgress = true;
1707 // --> #i36181# - notify background of drawing object
1708 if ( _bMoveMasterToInvisibleLayer &&
1709 !(GetFormat()->GetDoc()->IsInDtor()) &&
1710 GetAnchorFrame() && !GetAnchorFrame()->IsInDtor() )
1712 const tools::Rectangle aOldRect( maAnchoredDrawObj.GetObjRectWithSpaces().SVRect() );
1713 lcl_NotifyBackgroundOfObj( *this, *GetMaster(), &aOldRect );
1714 NotifyBackgroundOfAllVirtObjs( &aOldRect );
1717 // remove 'virtual' drawing objects from writer
1718 // layout and from drawing page
1719 for(auto& rpVirtDrawObj : maDrawVirtObjs)
1721 rpVirtDrawObj->RemoveFromWriterLayout();
1722 rpVirtDrawObj->RemoveFromDrawingPage();
1725 if ( maAnchoredDrawObj.GetAnchorFrame() )
1727 maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1730 if ( _bMoveMasterToInvisibleLayer && GetMaster() && GetMaster()->IsInserted() )
1732 SdrViewIter::ForAllViews( GetMaster(),
1733 [this] (SdrView* pView)
1735 pView->MarkObj( GetMaster(), pView->GetSdrPageView(), true );
1738 // Instead of removing 'master' object from drawing page, move the
1739 // 'master' drawing object into the corresponding invisible layer.
1741 //static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess()->GetDrawModel()->GetPage(0)->
1742 // RemoveObject( GetMaster()->GetOrdNum() );
1743 // #i18447# - in order to consider group object correct
1744 // use new method <SwDrawContact::MoveObjToInvisibleLayer(..)>
1745 MoveObjToInvisibleLayer( GetMaster() );
1749 mbDisconnectInProgress = false;
1752 /// method to remove 'master' drawing object from drawing page.
1753 void SwDrawContact::RemoveMasterFromDrawPage()
1755 if ( GetMaster() )
1757 GetMaster()->SetUserCall( nullptr );
1758 if ( GetMaster()->IsInserted() )
1760 static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
1761 RemoveObject( GetMaster()->GetOrdNum() );
1766 // disconnect for a dedicated drawing object - could be 'master' or 'virtual'.
1767 // a 'master' drawing object will disconnect a 'virtual' drawing object
1768 // in order to take its place.
1769 // #i19919# - no special case, if drawing object isn't in
1770 // page header/footer, in order to get drawing objects in repeating table headers
1771 // also working.
1772 void SwDrawContact::DisconnectObjFromLayout( SdrObject* _pDrawObj )
1774 if ( auto pSwDrawVirtObj = dynamic_cast<SwDrawVirtObj*>( _pDrawObj) )
1776 pSwDrawVirtObj->RemoveFromWriterLayout();
1777 pSwDrawVirtObj->RemoveFromDrawingPage();
1779 else
1781 const auto ppVirtDrawObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
1782 [] (const rtl::Reference<SwDrawVirtObj>& pObj) { return pObj->IsConnected(); }));
1784 if(ppVirtDrawObj != maDrawVirtObjs.end())
1786 // replace found 'virtual' drawing object by 'master' drawing
1787 // object and disconnect the 'virtual' one
1788 SwDrawVirtObj* pDrawVirtObj(ppVirtDrawObj->get());
1789 SwFrame* pNewAnchorFrameOfMaster = pDrawVirtObj->AnchorFrame();
1790 // disconnect 'virtual' drawing object
1791 pDrawVirtObj->RemoveFromWriterLayout();
1792 pDrawVirtObj->RemoveFromDrawingPage();
1793 // disconnect 'master' drawing object from current frame
1794 GetAnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1795 // re-connect 'master' drawing object to frame of found 'virtual'
1796 // drawing object.
1797 pNewAnchorFrameOfMaster->AppendDrawObj( maAnchoredDrawObj );
1799 else
1801 // no connected 'virtual' drawing object found. Thus, disconnect
1802 // completely from layout.
1803 DisconnectFromLayout();
1808 static SwTextFrame* lcl_GetFlyInContentAnchor( SwTextFrame* _pProposedAnchorFrame,
1809 SwPosition const& rAnchorPos)
1811 SwTextFrame* pAct = _pProposedAnchorFrame;
1812 SwTextFrame* pTmp;
1813 TextFrameIndex const nTextOffset(_pProposedAnchorFrame->MapModelToViewPos(rAnchorPos));
1816 pTmp = pAct;
1817 pAct = pTmp->GetFollow();
1819 while (pAct && nTextOffset >= pAct->GetOffset());
1820 return pTmp;
1823 void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
1825 // *no* connect to layout during disconnection from layout.
1826 if ( mbDisconnectInProgress )
1828 OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> called during disconnection.");
1829 return;
1832 // --> #i33909# - *no* connect to layout, if 'master' drawing
1833 // object isn't inserted in the drawing page
1834 if ( !GetMaster()->IsInserted() )
1836 OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> - master drawing object not inserted -> no connect to layout. Please inform od@openoffice.org" );
1837 return;
1840 SwFrameFormat* pDrawFrameFormat = static_cast<SwFrameFormat*>(GetRegisteredIn());
1842 if( !pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell() )
1843 return;
1845 // remove 'virtual' drawing objects from writer
1846 // layout and from drawing page, and remove 'master' drawing object from
1847 // writer layout - 'master' object will remain in drawing page.
1848 DisconnectFromLayout( false );
1850 if ( !pAnch )
1852 pAnch = &(pDrawFrameFormat->GetAnchor());
1855 switch ( pAnch->GetAnchorId() )
1857 case RndStdIds::FLY_AT_PAGE:
1859 sal_uInt16 nPgNum = pAnch->GetPageNum();
1860 SwViewShell *pShell = pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell();
1861 if( !pShell )
1862 break;
1863 SwRootFrame* pRoot = pShell->GetLayout();
1864 SwPageFrame *pPage = static_cast<SwPageFrame*>(pRoot->Lower());
1866 for ( sal_uInt16 i = 1; i < nPgNum && pPage; ++i )
1868 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1871 if ( pPage )
1873 pPage->AppendDrawObj( maAnchoredDrawObj );
1875 else
1876 //Looks stupid but is allowed (compare SwFEShell::SetPageObjsNewPage)
1877 pRoot->SetAssertFlyPages();
1879 break;
1881 case RndStdIds::FLY_AT_CHAR:
1882 case RndStdIds::FLY_AT_PARA:
1883 case RndStdIds::FLY_AT_FLY:
1884 case RndStdIds::FLY_AS_CHAR:
1886 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1888 ClrContourCache( GetMaster() );
1890 // support drawing objects in header/footer,
1891 // but not control objects:
1892 // anchor at first found frame the 'master' object and
1893 // at the following frames 'virtual' drawing objects.
1894 // Note: method is similar to <SwFlyFrameFormat::MakeFrames(..)>
1895 sw::BroadcastingModify *pModify = nullptr;
1896 if( pAnch->GetAnchorNode() )
1898 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AT_FLY )
1900 SwNodeIndex aIdx( *pAnch->GetAnchorNode() );
1901 SwContentNode* pCNd = SwNodes::GoNext(&aIdx);
1902 if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
1903 pModify = pCNd;
1904 else
1906 const SwNode& rIdx = *pAnch->GetAnchorNode();
1907 for(sw::SpzFrameFormat* pFlyFormat :*(pDrawFrameFormat->GetDoc()->GetSpzFrameFormats()))
1909 if( pFlyFormat->GetContent().GetContentIdx() &&
1910 rIdx == pFlyFormat->GetContent().GetContentIdx()->GetNode() )
1912 pModify = pFlyFormat;
1913 break;
1918 else
1920 pModify = pAnch->GetAnchorNode()->GetContentNode();
1924 // #i29199# - It is possible, that
1925 // the anchor doesn't exist - E.g., reordering the
1926 // sub-documents in a master document.
1927 // Note: The anchor will be inserted later.
1928 if ( !pModify )
1930 // break to end of the current switch case.
1931 break;
1934 SwIterator<SwFrame, sw::BroadcastingModify, sw::IteratorMode::UnwrapMulti> aIter(*pModify);
1935 SwFrame* pAnchorFrameOfMaster = nullptr;
1936 for( SwFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1938 // append drawing object, if
1939 // (1) proposed anchor frame isn't a follow and...
1940 const bool bFollow = pFrame->IsContentFrame() && static_cast<SwContentFrame*>(pFrame)->IsFollow();
1941 if (bFollow)
1942 continue;
1944 // (2) drawing object isn't a control object to be anchored
1945 // in header/footer.
1946 const bool bControlInHF = ::CheckControlLayer(GetMaster()) && pFrame->FindFooterOrHeader();
1947 // tdf#129542 but make an exception for control objects so they can get added to just the first frame,
1948 // the Master Anchor Frame and not the others
1949 if (bControlInHF && pAnchorFrameOfMaster)
1950 continue;
1952 bool bAdd;
1953 if (RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId())
1954 bAdd = true;
1955 else
1957 assert(pFrame->IsTextFrame());
1958 bAdd = IsAnchoredObjShown(*static_cast<SwTextFrame*>(pFrame), *pAnch);
1961 if( bAdd )
1963 if ( RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId() && !pFrame->IsFlyFrame() )
1965 pFrame = pFrame->FindFlyFrame();
1966 assert(pFrame);
1969 // find correct follow for as character anchored objects
1970 if ((pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR) &&
1971 pFrame->IsTextFrame() )
1973 pFrame = lcl_GetFlyInContentAnchor(
1974 static_cast<SwTextFrame*>(pFrame),
1975 *pAnch->GetContentAnchor());
1978 if ( !pAnchorFrameOfMaster )
1980 // append 'master' drawing object
1981 pAnchorFrameOfMaster = pFrame;
1983 const SwFrameFormat* pFlyFormat = nullptr;
1984 if (!maAnchoredDrawObj.GetDrawObj()->IsGroupObject())
1986 pFlyFormat = SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_DRAWFRMFMT);
1989 if (pFlyFormat)
1991 // This is a master draw object and it has an associated fly format.
1992 // See if a fly frame is already inserted to the layout: if so, this
1993 // master draw object should be ordered directly before the fly one.
1994 if (const SwSortedObjs* pObjs = pFrame->GetDrawObjs())
1996 for (const SwAnchoredObject* pAnchoredObj : *pObjs)
1998 if (pAnchoredObj->GetFrameFormat() == pFlyFormat)
2000 SdrPage* pDrawPage = pAnchoredObj->GetDrawObj()->getSdrPageFromSdrObject();
2001 if (pDrawPage)
2003 sal_uInt32 nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
2004 if (maAnchoredDrawObj.GetDrawObj()->GetOrdNum() >= nOrdNum)
2006 pDrawPage->SetObjectOrdNum(maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect(), nOrdNum);
2008 else
2010 pDrawPage->SetObjectOrdNum(nOrdNum, maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect() + 1);
2012 break;
2019 pFrame->AppendDrawObj( maAnchoredDrawObj );
2021 else
2023 // append 'virtual' drawing object
2024 SwDrawVirtObj* pDrawVirtObj = AddVirtObj(*pFrame);
2025 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
2027 ClrContourCache( pDrawVirtObj );
2029 pFrame->AppendDrawObj( pDrawVirtObj->AnchoredObj() );
2031 pDrawVirtObj->ActionChanged();
2034 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
2036 pFrame->InvalidatePrt();
2041 break;
2042 default:
2043 assert(!"Unknown Anchor.");
2044 break;
2046 if ( GetAnchorFrame() )
2048 ::setContextWritingMode( maAnchoredDrawObj.DrawObj(), GetAnchorFrame() );
2049 // #i26791# - invalidate objects instead of direct positioning
2050 InvalidateObjs_();
2054 /// insert 'master' drawing object into drawing page
2055 void SwDrawContact::InsertMasterIntoDrawPage()
2057 if ( !GetMaster()->IsInserted() )
2059 GetFormat()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)
2060 ->InsertObject( GetMaster(), GetMaster()->GetOrdNumDirect() );
2062 GetMaster()->SetUserCall( this );
2065 SwPageFrame* SwDrawContact::FindPage( const SwRect &rRect )
2067 // --> #i28701# - use method <GetPageFrame()>
2068 SwPageFrame* pPg = GetPageFrame();
2069 if ( !pPg && GetAnchorFrame() )
2070 pPg = GetAnchorFrame()->FindPageFrame();
2071 if ( pPg )
2072 pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( rRect, pPg )));
2073 return pPg;
2076 void SwDrawContact::ChkPage()
2078 if ( mbDisconnectInProgress )
2080 OSL_FAIL( "<SwDrawContact::ChkPage()> called during disconnection." );
2081 return;
2084 // --> #i28701#
2085 // tdf#156287: use anchor page, not current bound rectangle's page,
2086 // because an object can't move to a page other than its anchor anyway
2087 SwPageFrame* pPg = ( maAnchoredDrawObj.GetAnchorFrame() &&
2088 maAnchoredDrawObj.GetAnchorFrame()->IsPageFrame() )
2089 ? GetPageFrame()
2090 : maAnchoredDrawObj.FindPageFrameOfAnchor();
2091 if ( GetPageFrame() == pPg )
2092 return;
2094 // if drawing object is anchor in header/footer a change of the page
2095 // is a dramatic change. Thus, completely re-connect to the layout
2096 if ( maAnchoredDrawObj.GetAnchorFrame() &&
2097 maAnchoredDrawObj.GetAnchorFrame()->FindFooterOrHeader() )
2099 ConnectToLayout();
2101 else
2103 // --> #i28701# - use methods <GetPageFrame()> and <SetPageFrame>
2104 maAnchoredDrawObj.RegisterAtPage(*pPg);
2105 maAnchoredDrawObj.SetPageFrame( pPg );
2109 // Important note:
2110 // method is called by method <SwDPage::ReplaceObject(..)>, which called its
2111 // corresponding superclass method <FmFormPage::ReplaceObject(..)>.
2112 // Note: 'master' drawing object *has* to be connected to layout triggered
2113 // by the caller of this, if method is called.
2114 void SwDrawContact::ChangeMasterObject(SdrObject* pNewMaster)
2116 DisconnectFromLayout( false );
2117 // consider 'virtual' drawing objects
2118 RemoveAllVirtObjs();
2120 GetMaster()->SetUserCall( nullptr );
2121 if(pNewMaster)
2122 maAnchoredDrawObj.SetDrawObj(*pNewMaster);
2123 else
2124 mbMasterObjCleared = true;
2125 GetMaster()->SetUserCall( this );
2127 InvalidateObjs_();
2130 /// get data collection of anchored objects, handled by with contact
2131 void SwDrawContact::GetAnchoredObjs(std::vector<SwAnchoredObject*>& o_rAnchoredObjs) const
2133 o_rAnchoredObjs.push_back(const_cast<SwAnchoredDrawObject*>(&maAnchoredDrawObj));
2135 for(auto& rpDrawVirtObj : maDrawVirtObjs)
2136 o_rAnchoredObjs.push_back(&rpDrawVirtObj->AnchoredObj());
2139 // AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed
2140 // since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj.
2141 // For paint, that offset is used by setting at the OutputDevice; for primitives this is
2142 // not possible since we have no OutputDevice, but define the geometry itself.
2144 namespace sdr::contact
2146 namespace {
2148 class VOCOfDrawVirtObj : public ViewObjectContactOfSdrObj
2150 protected:
2152 * This method is responsible for creating the graphical visualisation data which is
2153 * stored/cached in the local primitive. Default gets view-independent Primitive from
2154 * the ViewContact using ViewContact::getViewIndependentPrimitive2DContainer(), takes
2155 * care of visibility, handles glue and ghosted.
2157 * This method will not handle included hierarchies and not check geometric visibility.
2159 virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
2161 public:
2162 VOCOfDrawVirtObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
2163 : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
2168 class VCOfDrawVirtObj : public ViewContactOfVirtObj
2170 protected:
2171 /** Create an Object-Specific ViewObjectContact, set ViewContact and ObjectContact.
2173 * Always needs to return something. Default is to create a standard ViewObjectContact
2174 * containing the given ObjectContact and *this.
2176 virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
2178 public:
2179 /// basic constructor, used from SdrObject.
2180 explicit VCOfDrawVirtObj(SwDrawVirtObj& rObj)
2181 : ViewContactOfVirtObj(rObj)
2185 /// access to SwDrawVirtObj
2186 SwDrawVirtObj& GetSwDrawVirtObj() const
2188 return static_cast<SwDrawVirtObj&>(mrObject);
2193 } // end of namespace sdr::contact
2195 namespace sdr::contact
2197 /// recursively collect primitive data from given VOC with given offset
2198 static void impAddPrimitivesFromGroup(const ViewObjectContact& rVOC, const basegfx::B2DHomMatrix& rOffsetMatrix, const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DContainer& rxTarget)
2200 const sal_uInt32 nSubHierarchyCount(rVOC.GetViewContact().GetObjectCount());
2202 for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
2204 const ViewObjectContact& rCandidate(rVOC.GetViewContact().GetViewContact(a).GetViewObjectContact(rVOC.GetObjectContact()));
2206 if(rCandidate.GetViewContact().GetObjectCount())
2208 // is a group object itself, call recursively
2209 impAddPrimitivesFromGroup(rCandidate, rOffsetMatrix, rDisplayInfo, rxTarget);
2211 else
2213 // single object, add primitives; check model-view visibility
2214 if(rCandidate.isPrimitiveVisible(rDisplayInfo))
2216 drawinglayer::primitive2d::Primitive2DContainer aNewSequence(rCandidate.getPrimitive2DSequence(rDisplayInfo));
2218 if(!aNewSequence.empty())
2220 // get ranges
2221 const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(rCandidate.GetObjectContact().getViewInformation2D());
2222 const basegfx::B2DRange& aViewRange(rViewInformation2D.getViewport());
2223 basegfx::B2DRange aObjectRange(rCandidate.getObjectRange());
2225 // correct with virtual object's offset
2226 aObjectRange.transform(rOffsetMatrix);
2228 // check geometrical visibility (with offset)
2229 if(!aViewRange.overlaps(aObjectRange))
2231 // not visible, release
2232 aNewSequence.clear();
2236 if(!aNewSequence.empty())
2238 rxTarget.append(std::move(aNewSequence));
2245 void VOCOfDrawVirtObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
2247 // this may be called for painting where it's a precondition that
2248 // isPrimitiveVisible() is true, or for e.g. getObjectRange() (even
2249 // during layout) where there are no preconditions...
2250 // nasty corner case: override to clear page frame to disable the
2251 // sub-objects' anchor check, because their anchor is always on
2252 // the first page that the page style is applied to
2253 DisplayInfo aDisplayInfo(rDisplayInfo);
2254 aDisplayInfo.SetWriterPageFrame(basegfx::B2IRectangle());
2255 const VCOfDrawVirtObj& rVC = static_cast< const VCOfDrawVirtObj& >(GetViewContact());
2256 const SdrObject& rReferencedObject = rVC.GetSwDrawVirtObj().GetReferencedObj();
2257 drawinglayer::primitive2d::Primitive2DContainer xRetval;
2259 // create offset transformation
2260 basegfx::B2DHomMatrix aOffsetMatrix;
2261 const Point aLocalOffset(rVC.GetSwDrawVirtObj().GetOffset());
2263 if(aLocalOffset.X() || aLocalOffset.Y())
2265 aOffsetMatrix.set(0, 2, aLocalOffset.X());
2266 aOffsetMatrix.set(1, 2, aLocalOffset.Y());
2269 if(dynamic_cast<const SdrObjGroup*>( &rReferencedObject) != nullptr)
2271 // group object. Since the VOC/OC/VC hierarchy does not represent the
2272 // hierarchy virtual objects when they have group objects
2273 // (ViewContactOfVirtObj::GetObjectCount() returns null for that purpose)
2274 // to avoid multiple usages of VOCs (which would not work), the primitives
2275 // for the sub-hierarchy need to be collected here
2277 // Get the VOC of the referenced object (the Group) and fetch primitives from it
2278 const ViewObjectContact& rVOCOfRefObj = rReferencedObject.GetViewContact().GetViewObjectContact(GetObjectContact());
2279 impAddPrimitivesFromGroup(rVOCOfRefObj, aOffsetMatrix, aDisplayInfo, xRetval);
2281 else
2283 // single object, use method from referenced object to get the Primitive2DSequence
2284 rReferencedObject.GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
2287 if(!xRetval.empty())
2289 // create transform primitive
2290 xRetval = drawinglayer::primitive2d::Primitive2DContainer {
2291 new drawinglayer::primitive2d::TransformPrimitive2D(aOffsetMatrix, std::move(xRetval))
2295 rVisitor.visit(xRetval);
2298 ViewObjectContact& VCOfDrawVirtObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
2300 return *(new VOCOfDrawVirtObj(rObjectContact, *this));
2303 } // end of namespace sdr::contact
2305 /// implementation of class <SwDrawVirtObj>
2306 std::unique_ptr<sdr::contact::ViewContact> SwDrawVirtObj::CreateObjectSpecificViewContact()
2308 return std::make_unique<sdr::contact::VCOfDrawVirtObj>(*this);
2311 SwDrawVirtObj::SwDrawVirtObj(
2312 SdrModel& rSdrModel,
2313 SdrObject& _rNewObj,
2314 SwDrawContact& _rDrawContact)
2315 : SdrVirtObj(rSdrModel, _rNewObj ),
2316 mrDrawContact(_rDrawContact)
2318 // #i26791#
2319 maAnchoredDrawObj.SetDrawObj( *this );
2321 // #i35635# - set initial position out of sight
2322 NbcMove( Size( -16000, -16000 ) );
2325 SwDrawVirtObj::SwDrawVirtObj(
2326 SdrModel& rSdrModel,
2327 SwDrawVirtObj const & rSource)
2328 : SdrVirtObj(rSdrModel, rSource),
2329 mrDrawContact(rSource.mrDrawContact)
2331 // #i26791#
2332 maAnchoredDrawObj.SetDrawObj( *this );
2334 // #i35635# - set initial position out of sight
2335 NbcMove( Size( -16000, -16000 ) );
2337 // Note: Members <maAnchoredDrawObj> and <mrDrawContact>
2338 // haven't to be considered.
2341 SwDrawVirtObj::~SwDrawVirtObj()
2345 rtl::Reference<SdrObject> SwDrawVirtObj::CloneSdrObject(SdrModel& rTargetModel) const
2347 return new SwDrawVirtObj(rTargetModel, *this);
2350 const SwFrame* SwDrawVirtObj::GetAnchorFrame() const
2352 // #i26791# - use new member <maAnchoredDrawObj>
2353 return maAnchoredDrawObj.GetAnchorFrame();
2356 SwFrame* SwDrawVirtObj::AnchorFrame()
2358 // #i26791# - use new member <maAnchoredDrawObj>
2359 return maAnchoredDrawObj.AnchorFrame();
2362 void SwDrawVirtObj::RemoveFromWriterLayout()
2364 // remove contact object from frame for 'virtual' drawing object
2365 // #i26791# - use new member <maAnchoredDrawObj>
2366 if ( maAnchoredDrawObj.GetAnchorFrame() )
2368 maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
2372 void SwDrawVirtObj::AddToDrawingPage(SwFrame const& rAnchorFrame)
2374 // determine 'master'
2375 SdrObject* pOrgMasterSdrObj = mrDrawContact.GetMaster();
2377 // insert 'virtual' drawing object into page, set layer and user call.
2378 SdrPage* pDrawPg = pOrgMasterSdrObj->getSdrPageFromSdrObject();
2379 // default: insert before master object
2380 auto nOrdNum(GetReferencedObj().GetOrdNum());
2382 // maintain invariant that a shape's textbox immediately follows the shape
2383 // also for the multiple SdrDrawVirtObj created for shapes in header/footer
2384 if (SwFrameFormat const*const pFlyFormat =
2385 SwTextBoxHelper::getOtherTextBoxFormat(mrDrawContact.GetFormat(), RES_DRAWFRMFMT))
2387 // this is for the case when the flyframe SdrVirtObj is created before the draw one
2388 if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
2390 for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
2392 if (pAnchoredObj->GetFrameFormat() == pFlyFormat)
2394 assert(dynamic_cast<SwFlyFrame const*>(pAnchoredObj));
2396 if (pAnchoredObj->GetDrawObj()->GetOrdNum() >= GetReferencedObj().GetOrdNum())
2398 // This virtual draw object has an associated fly one, but the fly's index
2399 // is not below the masters, fix it up.
2400 if (pDrawPg)
2402 pDrawPg->SetObjectOrdNum(pAnchoredObj->GetDrawObj()->GetOrdNumDirect(), GetReferencedObj().GetOrdNum());
2406 nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
2407 // the master SdrObj should have the highest index
2408 assert(nOrdNum < GetReferencedObj().GetOrdNum());
2409 break;
2413 // this happens on initial insertion, the draw object is created first
2414 SAL_INFO_IF(GetReferencedObj().GetOrdNum() == nOrdNum, "sw", "AddToDrawingPage: cannot find SdrObject for text box's shape");
2417 // #i27030# - apply order number of referenced object
2418 if ( nullptr != pDrawPg )
2420 // #i27030# - apply order number of referenced object
2421 pDrawPg->InsertObject(this, nOrdNum);
2423 else
2425 pDrawPg = getSdrPageFromSdrObject();
2426 if ( pDrawPg )
2428 pDrawPg->SetObjectOrdNum(GetOrdNumDirect(), nOrdNum);
2430 else
2432 SetOrdNum(nOrdNum);
2435 SetUserCall( &mrDrawContact );
2438 void SwDrawVirtObj::RemoveFromDrawingPage()
2440 SetUserCall( nullptr );
2441 if ( getSdrPageFromSdrObject() )
2443 getSdrPageFromSdrObject()->RemoveObject( GetOrdNum() );
2447 /// Is 'virtual' drawing object connected to writer layout and to drawing layer?
2448 bool SwDrawVirtObj::IsConnected() const
2450 bool bRetVal = GetAnchorFrame() &&
2451 ( getSdrPageFromSdrObject() && GetUserCall() );
2453 return bRetVal;
2456 void SwDrawVirtObj::NbcSetAnchorPos(const Point& rPnt)
2458 SdrObject::NbcSetAnchorPos( rPnt );
2461 // #i97197#
2462 // the methods relevant for positioning
2464 const tools::Rectangle& SwDrawVirtObj::GetCurrentBoundRect() const
2466 if (getOutRectangle().IsEmpty())
2468 const_cast<SwDrawVirtObj*>(this)->RecalcBoundRect();
2471 return getOutRectangle();
2474 const tools::Rectangle& SwDrawVirtObj::GetLastBoundRect() const
2476 return getOutRectangle();
2479 Point SwDrawVirtObj::GetOffset() const
2481 // do NOT use IsEmpty() here, there is already a useful offset
2482 // in the position
2483 if (getOutRectangle() == tools::Rectangle())
2485 return Point();
2487 else
2489 return getOutRectangle().TopLeft() - GetReferencedObj().GetCurrentBoundRect().TopLeft();
2493 void SwDrawVirtObj::SetBoundRectDirty()
2495 // do nothing to not lose model information in aOutRect
2498 void SwDrawVirtObj::RecalcBoundRect()
2500 // #i26791# - switch order of calling <GetOffset()> and
2501 // <ReferencedObj().GetCurrentBoundRect()>, because <GetOffset()> calculates
2502 // its value by the 'BoundRect' of the referenced object.
2504 const Point aOffset(GetOffset());
2505 setOutRectangle(ReferencedObj().GetCurrentBoundRect() + aOffset);
2508 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeXorPoly() const
2510 basegfx::B2DPolyPolygon aRetval(mxRefObj->TakeXorPoly());
2511 aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2513 return aRetval;
2516 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeContour() const
2518 basegfx::B2DPolyPolygon aRetval(mxRefObj->TakeContour());
2519 aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2521 return aRetval;
2524 void SwDrawVirtObj::AddToHdlList(SdrHdlList& rHdlList) const
2526 SdrHdlList tmpList(nullptr);
2527 mxRefObj->AddToHdlList(tmpList);
2529 size_t cnt = tmpList.GetHdlCount();
2530 for(size_t i=0; i < cnt; ++i)
2532 SdrHdl* pHdl = tmpList.GetHdl(i);
2533 Point aP(pHdl->GetPos() + GetOffset());
2534 pHdl->SetPos(aP);
2536 tmpList.MoveTo(rHdlList);
2539 void SwDrawVirtObj::NbcMove(const Size& rSiz)
2541 SdrObject::NbcMove( rSiz );
2544 void SwDrawVirtObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
2546 mxRefObj->NbcResize(rRef - GetOffset(), xFact, yFact);
2547 SetBoundAndSnapRectsDirty();
2550 void SwDrawVirtObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
2552 mxRefObj->NbcRotate(rRef - GetOffset(), nAngle, sn, cs);
2553 SetBoundAndSnapRectsDirty();
2556 void SwDrawVirtObj::NbcMirror(const Point& rRef1, const Point& rRef2)
2558 mxRefObj->NbcMirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2559 SetBoundAndSnapRectsDirty();
2562 void SwDrawVirtObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
2564 mxRefObj->NbcShear(rRef - GetOffset(), nAngle, tn, bVShear);
2565 SetBoundAndSnapRectsDirty();
2568 void SwDrawVirtObj::Move(const Size& rSiz)
2570 SdrObject::Move( rSiz );
2573 void SwDrawVirtObj::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
2575 if(xFact.GetNumerator() != xFact.GetDenominator() || yFact.GetNumerator() != yFact.GetDenominator())
2577 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2578 mxRefObj->Resize(rRef - GetOffset(), xFact, yFact, bUnsetRelative);
2579 SetBoundAndSnapRectsDirty();
2580 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2584 void SwDrawVirtObj::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
2586 if(nAngle)
2588 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2589 mxRefObj->Rotate(rRef - GetOffset(), nAngle, sn, cs);
2590 SetBoundAndSnapRectsDirty();
2591 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2595 void SwDrawVirtObj::Mirror(const Point& rRef1, const Point& rRef2)
2597 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2598 mxRefObj->Mirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2599 SetBoundAndSnapRectsDirty();
2600 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2603 void SwDrawVirtObj::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
2605 if(nAngle)
2607 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2608 mxRefObj->Shear(rRef - GetOffset(), nAngle, tn, bVShear);
2609 SetBoundAndSnapRectsDirty();
2610 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2614 void SwDrawVirtObj::RecalcSnapRect()
2616 maSnapRect = mxRefObj->GetSnapRect();
2617 maSnapRect += GetOffset();
2620 const tools::Rectangle& SwDrawVirtObj::GetSnapRect() const
2622 const_cast<SwDrawVirtObj*>(this)->maSnapRect = mxRefObj->GetSnapRect();
2623 const_cast<SwDrawVirtObj*>(this)->maSnapRect += GetOffset();
2625 return maSnapRect;
2628 void SwDrawVirtObj::SetSnapRect(const tools::Rectangle& rRect)
2630 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2631 tools::Rectangle aR(rRect);
2632 aR -= GetOffset();
2633 mxRefObj->SetSnapRect(aR);
2634 SetBoundAndSnapRectsDirty();
2635 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2638 void SwDrawVirtObj::NbcSetSnapRect(const tools::Rectangle& rRect)
2640 tools::Rectangle aR(rRect);
2641 aR -= GetOffset();
2642 SetBoundAndSnapRectsDirty();
2643 mxRefObj->NbcSetSnapRect(aR);
2646 const tools::Rectangle& SwDrawVirtObj::GetLogicRect() const
2648 const_cast<SwDrawVirtObj*>(this)->maSnapRect = mxRefObj->GetLogicRect();
2649 const_cast<SwDrawVirtObj*>(this)->maSnapRect += GetOffset();
2651 return maSnapRect;
2654 void SwDrawVirtObj::SetLogicRect(const tools::Rectangle& rRect)
2656 tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
2657 tools::Rectangle aR(rRect);
2658 aR -= GetOffset();
2659 mxRefObj->SetLogicRect(aR);
2660 SetBoundAndSnapRectsDirty();
2661 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2664 void SwDrawVirtObj::NbcSetLogicRect(const tools::Rectangle& rRect, bool bAdaptTextMinSize)
2666 tools::Rectangle aR(rRect);
2667 aR -= GetOffset();
2668 mxRefObj->NbcSetLogicRect(aR, bAdaptTextMinSize);
2669 SetBoundAndSnapRectsDirty();
2672 Point SwDrawVirtObj::GetSnapPoint(sal_uInt32 i) const
2674 Point aP(mxRefObj->GetSnapPoint(i));
2675 aP += GetOffset();
2677 return aP;
2680 Point SwDrawVirtObj::GetPoint(sal_uInt32 i) const
2682 return mxRefObj->GetPoint(i) + GetOffset();
2685 void SwDrawVirtObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
2687 Point aP(rPnt);
2688 aP -= GetOffset();
2689 mxRefObj->SetPoint(aP, i);
2690 SetBoundAndSnapRectsDirty();
2693 bool SwDrawVirtObj::HasTextEdit() const
2695 return mxRefObj->HasTextEdit();
2698 // override 'layer' methods for 'virtual' drawing object to assure
2699 // that layer of 'virtual' object is the layer of the referenced object.
2700 SdrLayerID SwDrawVirtObj::GetLayer() const
2702 return GetReferencedObj().GetLayer();
2705 void SwDrawVirtObj::NbcSetLayer(SdrLayerID nLayer)
2707 ReferencedObj().NbcSetLayer( nLayer );
2708 SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2711 void SwDrawVirtObj::SetLayer(SdrLayerID nLayer)
2713 ReferencedObj().SetLayer( nLayer );
2714 SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2717 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */