1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <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 <doc.hxx>
54 #include <hints.hxx>
55 #include <txtfrm.hxx>
56 #include <docary.hxx>
57 #include <sortedobjs.hxx>
58 #include <basegfx/matrix/b2dhommatrix.hxx>
59 #include <basegfx/matrix/b2dhommatrixtools.hxx>
60 #include <svx/sdr/contact/viewcontactofvirtobj.hxx>
61 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
62 #include <drawinglayer/geometry/viewinformation2d.hxx>
63 #include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
64 #include <com/sun/star/text/WritingMode2.hpp>
65 #include <calbck.hxx>
66 #include <algorithm>
67 #include <txtfly.hxx>
68 #include <sal/log.hxx>
69
70 using namespace ::com::sun::star;
71
72 namespace
73 {
74 /** unary function used to find a 'virtual' drawing object anchored at a given frame */
75 struct VirtObjAnchoredAtFramePred
76 {
77 const SwFrame* m_pAnchorFrame;
78
79 // #i26791# - compare with master frame
FindFrame__anon0a18b0040111::VirtObjAnchoredAtFramePred80 static const SwFrame* FindFrame(const SwFrame* pFrame)
81 {
82 if(!pFrame || !pFrame->IsContentFrame())
83 return pFrame;
84 auto pContentFrame = static_cast<const SwContentFrame*>(pFrame);
85 while(pContentFrame->IsFollow())
86 pContentFrame = pContentFrame->FindMaster();
87 return pContentFrame;
88 }
89
VirtObjAnchoredAtFramePred__anon0a18b0040111::VirtObjAnchoredAtFramePred90 VirtObjAnchoredAtFramePred(const SwFrame* pAnchorFrame)
91 : m_pAnchorFrame(FindFrame(pAnchorFrame))
92 {}
93
operator ()__anon0a18b0040111::VirtObjAnchoredAtFramePred94 bool operator()(const SwDrawVirtObjPtr& rpDrawVirtObj)
95 {
96 return FindFrame(rpDrawVirtObj->GetAnchorFrame()) == m_pAnchorFrame;
97 }
98 };
99 }
100
setContextWritingMode(SdrObject * pObj,SwFrame const * pAnchor)101 void setContextWritingMode(SdrObject* pObj, SwFrame const * pAnchor)
102 {
103 if(!pObj || !pAnchor)
104 return;
105 short nWritingDirection =
106 pAnchor->IsVertical() ? text::WritingMode2::TB_RL :
107 pAnchor->IsRightToLeft() ? text::WritingMode2::RL_TB :
108 text::WritingMode2::LR_TB;
109 pObj->SetContextWritingMode(nWritingDirection);
110 }
111
112
113 /** The Get reverse way: seeks the format to the specified object.
114 * If the object is a SwVirtFlyDrawObj then the format of this
115 * will be acquired.
116 * Otherwise it is just a simple drawing object. This has a
117 * UserCall and is the client of the searched format.
118 */
FindFrameFormat(SdrObject * pObj)119 SwFrameFormat *FindFrameFormat( SdrObject *pObj )
120 {
121 SwFrameFormat* pRetval = nullptr;
122
123 if (SwVirtFlyDrawObj* pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
124 {
125 pRetval = pFlyDrawObj->GetFormat();
126 }
127 else
128 {
129 SwContact* pContact = GetUserCall(pObj);
130 if ( pContact )
131 {
132 pRetval = pContact->GetFormat();
133 }
134 }
135 return pRetval;
136 }
137
HasWrap(const SdrObject * pObj)138 bool HasWrap( const SdrObject* pObj )
139 {
140 if ( pObj )
141 {
142 const SwFrameFormat* pFormat = ::FindFrameFormat( pObj );
143 if ( pFormat )
144 {
145 return css::text::WrapTextMode_THROUGH != pFormat->GetSurround().GetSurround();
146 }
147 }
148
149 return false;
150 }
151
152 /// returns the BoundRect _inclusive_ distance of the object.
GetBoundRectOfAnchoredObj(const SdrObject * pObj)153 SwRect GetBoundRectOfAnchoredObj( const SdrObject* pObj )
154 {
155 SwRect aRet( pObj->GetCurrentBoundRect() );
156 // #i68520# - call cache of <SwAnchoredObject>
157 SwContact* pContact( GetUserCall( pObj ) );
158 if ( pContact )
159 {
160 const SwAnchoredObject* pAnchoredObj( pContact->GetAnchoredObj( pObj ) );
161 if ( pAnchoredObj )
162 {
163 aRet = pAnchoredObj->GetObjRectWithSpaces();
164 }
165 }
166 return aRet;
167 }
168
169 /// Returns the UserCall if applicable from the group object
GetUserCall(const SdrObject * pObj)170 SwContact* GetUserCall( const SdrObject* pObj )
171 {
172 SdrObject *pTmp;
173 while ( !pObj->GetUserCall() && nullptr != (pTmp = pObj->getParentSdrObjectFromSdrObject()) )
174 pObj = pTmp;
175 assert((!pObj->GetUserCall() || nullptr != dynamic_cast<const SwContact*>(pObj->GetUserCall())) &&
176 "<::GetUserCall(..)> - wrong type of found object user call." );
177 return static_cast<SwContact*>(pObj->GetUserCall());
178 }
179
180 /// Returns true if the SrdObject is a Marquee-Object (scrolling text)
IsMarqueeTextObj(const SdrObject & rObj)181 bool IsMarqueeTextObj( const SdrObject& rObj )
182 {
183 SdrTextAniKind eTKind;
184 return SdrInventor::Default == rObj.GetObjInventor() &&
185 OBJ_TEXT == rObj.GetObjIdentifier() &&
186 ( SdrTextAniKind::Scroll == ( eTKind = static_cast<const SdrTextObj&>(rObj).GetTextAniKind())
187 || SdrTextAniKind::Alternate == eTKind || SdrTextAniKind::Slide == eTKind );
188 }
189
SwContact(SwFrameFormat * pToRegisterIn)190 SwContact::SwContact( SwFrameFormat *pToRegisterIn ) :
191 SwClient( pToRegisterIn ),
192 mbInDTOR( false )
193 {}
194
~SwContact()195 SwContact::~SwContact()
196 {
197 SetInDTOR();
198 }
199
200
SetInDTOR()201 void SwContact::SetInDTOR()
202 {
203 mbInDTOR = true;
204 }
205
206 /// method to move drawing object to corresponding visible layer
MoveObjToVisibleLayer(SdrObject * _pDrawObj)207 void SwContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
208 {
209 // #i46297# - notify background about the arriving of
210 // the object and invalidate its position.
211 const bool bNotify( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
212
213 MoveObjToLayer( true, _pDrawObj );
214
215 // #i46297#
216 if ( bNotify )
217 {
218 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
219 assert(pAnchoredObj);
220 ::setContextWritingMode( _pDrawObj, pAnchoredObj->GetAnchorFrameContainingAnchPos() );
221 // Note: as-character anchored objects aren't registered at a page frame and
222 // a notification of its background isn't needed.
223 if ( pAnchoredObj->GetPageFrame() )
224 {
225 ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
226 pAnchoredObj->GetObjRect(), PREP_FLY_ARRIVE, true );
227 }
228
229 pAnchoredObj->InvalidateObjPos();
230 }
231 }
232
233 /// method to move drawing object to corresponding invisible layer - #i18447#
MoveObjToInvisibleLayer(SdrObject * _pDrawObj)234 void SwContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
235 {
236 // #i46297# - notify background about the leaving of the object.
237 const bool bNotify( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
238
239 MoveObjToLayer( false, _pDrawObj );
240
241 // #i46297#
242 if ( bNotify )
243 {
244 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
245 assert(pAnchoredObj);
246 // Note: as-character anchored objects aren't registered at a page frame and
247 // a notification of its background isn't needed.
248 if (pAnchoredObj->GetPageFrame())
249 {
250 ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
251 pAnchoredObj->GetObjRect(), PREP_FLY_LEAVE, true );
252 }
253 }
254 }
255
256 /** method to move object to visible/invisible layer - #i18447#
257
258 implementation for the public method <MoveObjToVisibleLayer(..)>
259 and <MoveObjToInvisibleLayer(..)>
260 */
MoveObjToLayer(const bool _bToVisible,SdrObject * _pDrawObj)261 void SwContact::MoveObjToLayer( const bool _bToVisible,
262 SdrObject* _pDrawObj )
263 {
264 if ( !_pDrawObj )
265 {
266 OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing object!" );
267 return;
268 }
269
270 if ( !GetRegisteredIn() )
271 {
272 OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing frame format!" );
273 return;
274 }
275
276 const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
277
278 SdrLayerID nToHellLayerId =
279 _bToVisible ? rIDDMA.GetHellId() : rIDDMA.GetInvisibleHellId();
280 SdrLayerID nToHeavenLayerId =
281 _bToVisible ? rIDDMA.GetHeavenId() : rIDDMA.GetInvisibleHeavenId();
282 SdrLayerID nToControlLayerId =
283 _bToVisible ? rIDDMA.GetControlsId() : rIDDMA.GetInvisibleControlsId();
284 SdrLayerID nFromHellLayerId =
285 _bToVisible ? rIDDMA.GetInvisibleHellId() : rIDDMA.GetHellId();
286 SdrLayerID nFromHeavenLayerId =
287 _bToVisible ? rIDDMA.GetInvisibleHeavenId() : rIDDMA.GetHeavenId();
288 SdrLayerID nFromControlLayerId =
289 _bToVisible ? rIDDMA.GetInvisibleControlsId() : rIDDMA.GetControlsId();
290
291 if ( dynamic_cast<const SdrObjGroup*>( _pDrawObj) != nullptr )
292 {
293 // determine layer for group object
294 {
295 // proposed layer of a group object is the hell layer
296 SdrLayerID nNewLayerId = nToHellLayerId;
297 if ( ::CheckControlLayer( _pDrawObj ) )
298 {
299 // it has to be the control layer, if one of the member
300 // is a control
301 nNewLayerId = nToControlLayerId;
302 }
303 else if ( _pDrawObj->GetLayer() == rIDDMA.GetHeavenId() ||
304 _pDrawObj->GetLayer() == rIDDMA.GetInvisibleHeavenId() )
305 {
306 // it has to be the heaven layer, if method <GetLayer()> reveals
307 // a heaven layer
308 nNewLayerId = nToHeavenLayerId;
309 }
310 // set layer at group object, but do *not* broadcast and
311 // no propagation to the members.
312 // Thus, call <NbcSetLayer(..)> at super class
313 _pDrawObj->SdrObject::NbcSetLayer( nNewLayerId );
314 }
315
316 // call method recursively for group object members
317 const SdrObjList* pLst =
318 static_cast<SdrObjGroup*>(_pDrawObj)->GetSubList();
319 if ( pLst )
320 {
321 for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
322 {
323 MoveObjToLayer( _bToVisible, pLst->GetObj( i ) );
324 }
325 }
326 }
327 else
328 {
329 const SdrLayerID nLayerIdOfObj = _pDrawObj->GetLayer();
330 if ( nLayerIdOfObj == nFromHellLayerId )
331 {
332 _pDrawObj->SetLayer( nToHellLayerId );
333 }
334 else if ( nLayerIdOfObj == nFromHeavenLayerId )
335 {
336 _pDrawObj->SetLayer( nToHeavenLayerId );
337 }
338 else if ( nLayerIdOfObj == nFromControlLayerId )
339 {
340 _pDrawObj->SetLayer( nToControlLayerId );
341 }
342 }
343 }
344
345 /// get minimum order number of anchored objects handled by with contact
GetMinOrdNum() const346 sal_uInt32 SwContact::GetMinOrdNum() const
347 {
348 sal_uInt32 nMinOrdNum( SAL_MAX_UINT32 );
349
350 std::vector< SwAnchoredObject* > aObjs;
351 GetAnchoredObjs( aObjs );
352
353 while ( !aObjs.empty() )
354 {
355 sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
356
357 if ( nTmpOrdNum < nMinOrdNum )
358 {
359 nMinOrdNum = nTmpOrdNum;
360 }
361
362 aObjs.pop_back();
363 }
364
365 OSL_ENSURE( nMinOrdNum != SAL_MAX_UINT32,
366 "<SwContact::GetMinOrdNum()> - no order number found." );
367 return nMinOrdNum;
368 }
369
370 /// get maximum order number of anchored objects handled by with contact
GetMaxOrdNum() const371 sal_uInt32 SwContact::GetMaxOrdNum() const
372 {
373 sal_uInt32 nMaxOrdNum( 0 );
374
375 std::vector< SwAnchoredObject* > aObjs;
376 GetAnchoredObjs( aObjs );
377
378 while ( !aObjs.empty() )
379 {
380 sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
381
382 if ( nTmpOrdNum > nMaxOrdNum )
383 {
384 nMaxOrdNum = nTmpOrdNum;
385 }
386
387 aObjs.pop_back();
388 }
389
390 return nMaxOrdNum;
391 }
392
393 namespace
394 {
lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj,const bool bFollowTextFlow,sw::WW8AnchorConv & reConv)395 Point lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj, const bool bFollowTextFlow, sw::WW8AnchorConv& reConv)
396 {
397 switch(reConv)
398 {
399 case sw::WW8AnchorConv::CONV2PG:
400 {
401 bool bRelToTableCell(false);
402 Point aPos(pAnchoredObj->GetRelPosToPageFrame(bFollowTextFlow, bRelToTableCell));
403 if(bRelToTableCell)
404 reConv = sw::WW8AnchorConv::RELTOTABLECELL;
405 return aPos;
406 }
407 case sw::WW8AnchorConv::CONV2COL_OR_PARA:
408 return pAnchoredObj->GetRelPosToAnchorFrame();
409 case sw::WW8AnchorConv::CONV2CHAR:
410 return pAnchoredObj->GetRelPosToChar();
411 case sw::WW8AnchorConv::CONV2LINE:
412 return pAnchoredObj->GetRelPosToLine();
413 default: ;
414 }
415 return Point();
416 }
417 }
SwClientNotify(const SwModify & rMod,const SfxHint & rHint)418 void SwContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
419 {
420 // this does not call SwClient::SwClientNotify and thus doesn't handle RES_OBJECTDYING as usual. Is this intentional?
421 if (auto pFindSdrObjectHint = dynamic_cast<const sw::FindSdrObjectHint*>(&rHint))
422 {
423 if(!pFindSdrObjectHint->m_rpObject)
424 pFindSdrObjectHint->m_rpObject = GetMaster();
425 }
426 else if (auto pWW8AnchorConvHint = dynamic_cast<const sw::WW8AnchorConvHint*>(&rHint))
427 {
428 // determine anchored object
429 SwAnchoredObject* pAnchoredObj(nullptr);
430 {
431 std::vector<SwAnchoredObject*> aAnchoredObjs;
432 GetAnchoredObjs(aAnchoredObjs);
433 if(!aAnchoredObjs.empty())
434 pAnchoredObj = aAnchoredObjs.front();
435 }
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;
453 }
454 }
455
456
SwFlyDrawContact(SwFlyFrameFormat * pToRegisterIn,SdrModel & rTargetModel)457 SwFlyDrawContact::SwFlyDrawContact(
458 SwFlyFrameFormat *pToRegisterIn,
459 SdrModel& rTargetModel)
460 : SwContact(pToRegisterIn),
461 mpMasterObj(new SwFlyDrawObj(rTargetModel))
462 {
463 // #i26791# - class <SwFlyDrawContact> contains the 'master'
464 // drawing object of type <SwFlyDrawObj> on its own.
465 mpMasterObj->SetOrdNum( 0xFFFFFFFE );
466 mpMasterObj->SetUserCall( this );
467 }
468
~SwFlyDrawContact()469 SwFlyDrawContact::~SwFlyDrawContact()
470 {
471 if ( mpMasterObj )
472 {
473 mpMasterObj->SetUserCall( nullptr );
474 if ( mpMasterObj->getSdrPageFromSdrObject() )
475 mpMasterObj->getSdrPageFromSdrObject()->RemoveObject( mpMasterObj->GetOrdNum() );
476 }
477 }
478
GetOrdNumForNewRef(const SwFlyFrame * pFly)479 sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly)
480 {
481 // search for another Writer fly frame registered at same frame format
482 SwIterator<SwFlyFrame,SwFormat> aIter(*GetFormat());
483 const SwFlyFrame* pFlyFrame(nullptr);
484 for(pFlyFrame = aIter.First(); pFlyFrame; pFlyFrame = aIter.Next())
485 {
486 if(pFlyFrame != pFly)
487 break;
488 }
489
490 if(pFlyFrame)
491 {
492 // another Writer fly frame found. Take its order number
493 return pFlyFrame->GetVirtDrawObj()->GetOrdNum();
494 }
495 // no other Writer fly frame found. Take order number of 'master' object
496 // #i35748# - use method <GetOrdNumDirect()> instead
497 // of method <GetOrdNum()> to avoid a recalculation of the order number,
498 // which isn't intended.
499 return GetMaster()->GetOrdNumDirect();
500 }
501
CreateNewRef(SwFlyFrame * pFly,SwFlyFrameFormat * pFormat)502 SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly, SwFlyFrameFormat* pFormat)
503 {
504 // Find ContactObject from the Format. If there's already one, we just
505 // need to create a new Ref, else we create the Contact now.
506
507 IDocumentDrawModelAccess& rIDDMA = pFormat->getIDocumentDrawModelAccess();
508 SwFlyDrawContact* pContact = pFormat->GetOrCreateContact();
509 SwVirtFlyDrawObj* pDrawObj(
510 new SwVirtFlyDrawObj(
511 pContact->GetMaster()->getSdrModelFromSdrObject(),
512 *pContact->GetMaster(),
513 pFly));
514 pDrawObj->SetUserCall(pContact);
515
516 // The Reader creates the Masters and inserts them into the Page in
517 // order to transport the z-order.
518 // After creating the first Reference the Masters are removed from the
519 // List and are not important anymore.
520 SdrPage* pPg(nullptr);
521 if(nullptr != (pPg = pContact->GetMaster()->getSdrPageFromSdrObject()))
522 {
523 const size_t nOrdNum = pContact->GetMaster()->GetOrdNum();
524 pPg->ReplaceObject(pDrawObj, nOrdNum);
525 }
526 // #i27030# - insert new <SwVirtFlyDrawObj> instance
527 // into drawing page with correct order number
528 else
529 rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj, pContact->GetOrdNumForNewRef(pFly));
530 // #i38889# - assure, that new <SwVirtFlyDrawObj> instance
531 // is in a visible layer.
532 pContact->MoveObjToVisibleLayer(pDrawObj);
533 return pDrawObj;
534 }
535
536 // #i26791#
GetAnchoredObj(const SdrObject * pSdrObj) const537 const SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(const SdrObject* pSdrObj) const
538 {
539 assert(pSdrObj);
540 assert(dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) != nullptr);
541 assert(GetUserCall(pSdrObj) == this &&
542 "<SwFlyDrawContact::GetAnchoredObj(..)> - provided object doesn't belong to this contact");
543
544 const SwAnchoredObject *const pRetAnchoredObj =
545 static_cast<const SwVirtFlyDrawObj*>(pSdrObj)->GetFlyFrame();
546
547 return pRetAnchoredObj;
548 }
549
GetAnchoredObj(SdrObject * const pSdrObj)550 SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
551 {
552 return const_cast<SwAnchoredObject *>(const_cast<SwFlyDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
553 }
554
GetMaster()555 SdrObject* SwFlyDrawContact::GetMaster()
556 {
557 return mpMasterObj.get();
558 }
559
560 /**
561 * @note Overriding method to control Writer fly frames, which are linked, and
562 * to assure that all objects anchored at/inside the Writer fly frame are
563 * also made visible.
564 */
MoveObjToVisibleLayer(SdrObject * _pDrawObj)565 void SwFlyDrawContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
566 {
567 assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
568
569 if ( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
570 {
571 // nothing to do
572 return;
573 }
574
575 SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
576
577 // #i44464# - consider, that Writer fly frame content
578 // already exists - (e.g. WW8 document is inserted into an existing document).
579 if ( !pFlyFrame->Lower() )
580 {
581 pFlyFrame->InsertColumns();
582 pFlyFrame->Chain( pFlyFrame->AnchorFrame() );
583 pFlyFrame->InsertCnt();
584 }
585 if ( pFlyFrame->GetDrawObjs() )
586 {
587 for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
588 {
589 // #i28701# - consider type of objects in sorted object list.
590 SdrObject* pObj = i->DrawObj();
591 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
592 pContact->MoveObjToVisibleLayer( pObj );
593 }
594 }
595
596 // make fly frame visible
597 SwContact::MoveObjToVisibleLayer( _pDrawObj );
598 }
599
600 /**
601 * @note Override method to control Writer fly frames, which are linked, and
602 * to assure that all objects anchored at/inside the Writer fly frame are
603 * also made invisible.
604 */
MoveObjToInvisibleLayer(SdrObject * _pDrawObj)605 void SwFlyDrawContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
606 {
607 assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
608
609 if ( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
610 {
611 // nothing to do
612 return;
613 }
614
615 SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
616
617 pFlyFrame->Unchain();
618 pFlyFrame->DeleteCnt();
619 if ( pFlyFrame->GetDrawObjs() )
620 {
621 for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
622 {
623 // #i28701# - consider type of objects in sorted object list.
624 SdrObject* pObj = i->DrawObj();
625 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
626 pContact->MoveObjToInvisibleLayer( pObj );
627 }
628 }
629
630 // make fly frame invisible
631 SwContact::MoveObjToInvisibleLayer( _pDrawObj );
632 }
633
634 /// get data collection of anchored objects, handled by with contact
GetAnchoredObjs(std::vector<SwAnchoredObject * > & _roAnchoredObjs) const635 void SwFlyDrawContact::GetAnchoredObjs( std::vector<SwAnchoredObject*>& _roAnchoredObjs ) const
636 {
637 const SwFrameFormat* pFormat = GetFormat();
638 SwFlyFrame::GetAnchoredObjects( _roAnchoredObjs, *pFormat );
639 }
SwClientNotify(const SwModify & rMod,const SfxHint & rHint)640 void SwFlyDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
641 {
642 SwContact::SwClientNotify(rMod, rHint);
643 if(auto pGetZOrdnerHint = dynamic_cast<const sw::GetZOrderHint*>(&rHint))
644 {
645 // #i11176#
646 // This also needs to work when no layout exists. Thus, for
647 // FlyFrames an alternative method is used now in that case.
648 auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
649 if (pFormat && pFormat->Which() == RES_FLYFRMFMT && !pFormat->getIDocumentLayoutAccess().GetCurrentViewShell())
650 pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
651 }
652 }
653
654 // SwDrawContact
655
CheckControlLayer(const SdrObject * pObj)656 bool CheckControlLayer( const SdrObject *pObj )
657 {
658 if ( SdrInventor::FmForm == pObj->GetObjInventor() )
659 return true;
660 if (const SdrObjGroup *pObjGroup = dynamic_cast<const SdrObjGroup*>(pObj))
661 {
662 const SdrObjList *pLst = pObjGroup->GetSubList();
663 for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
664 {
665 if ( ::CheckControlLayer( pLst->GetObj( i ) ) )
666 {
667 // #i18447# - return correct value ;-)
668 return true;
669 }
670 }
671 }
672 return false;
673 }
674
SwDrawContact(SwFrameFormat * pToRegisterIn,SdrObject * pObj)675 SwDrawContact::SwDrawContact( SwFrameFormat* pToRegisterIn, SdrObject* pObj ) :
676 SwContact( pToRegisterIn ),
677 maAnchoredDrawObj(),
678 mbMasterObjCleared( false ),
679 mbDisconnectInProgress( false ),
680 mbUserCallActive( false ),
681 // Note: value of <meEventTypeOfCurrentUserCall> isn't of relevance, because
682 // <mbUserCallActive> is false.
683 meEventTypeOfCurrentUserCall( SdrUserCallType::MoveOnly )
684 {
685 // --> #i33909# - assure, that drawing object is inserted
686 // in the drawing page.
687 if ( !pObj->IsInserted() )
688 {
689 pToRegisterIn->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
690 InsertObject( pObj, pObj->GetOrdNumDirect() );
691 }
692
693 // Controls have to be always in the Control-Layer. This is also true for
694 // group objects, if they contain controls.
695 if ( ::CheckControlLayer( pObj ) )
696 {
697 // set layer of object to corresponding invisible layer.
698 pObj->SetLayer( pToRegisterIn->getIDocumentDrawModelAccess().GetInvisibleControlsId() );
699 }
700
701 // #i26791#
702 pObj->SetUserCall( this );
703 maAnchoredDrawObj.SetDrawObj( *pObj );
704
705 // if there already exists an SwXShape for the object, ensure it knows about us, and the SdrObject
706 // #i99056#
707 SwXShape::AddExistingShapeToFormat( *pObj );
708 }
709
~SwDrawContact()710 SwDrawContact::~SwDrawContact()
711 {
712 SetInDTOR();
713
714 DisconnectFromLayout();
715
716 // remove 'master' from drawing page
717 RemoveMasterFromDrawPage();
718
719 // remove and destroy 'virtual' drawing objects.
720 RemoveAllVirtObjs();
721
722 if ( !mbMasterObjCleared )
723 {
724 SdrObject* pObject = const_cast< SdrObject* >( maAnchoredDrawObj.GetDrawObj() );
725 SdrObject::Free( pObject );
726 }
727 }
728
GetTextObjectsFromFormat(std::list<SdrTextObj * > & o_rTextObjects,SwDoc * pDoc)729 void SwDrawContact::GetTextObjectsFromFormat(std::list<SdrTextObj*>& o_rTextObjects, SwDoc* pDoc)
730 {
731 for(auto& rpFly : *pDoc->GetSpzFrameFormats())
732 {
733 if(dynamic_cast<const SwDrawFrameFormat*>(rpFly))
734 rpFly->CallSwClientNotify(sw::CollectTextObjectsHint(o_rTextObjects));
735 }
736 }
737
738 // #i26791#
GetAnchoredObj(const SdrObject * pSdrObj) const739 const SwAnchoredObject* SwDrawContact::GetAnchoredObj(const SdrObject* pSdrObj ) const
740 {
741 // handle default parameter value
742 if (!pSdrObj)
743 {
744 pSdrObj = GetMaster();
745 }
746
747 assert(pSdrObj);
748 assert(dynamic_cast<const SwDrawVirtObj*>(pSdrObj) != nullptr ||
749 dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
750 assert((GetUserCall(pSdrObj) == this ||
751 pSdrObj == GetMaster()) &&
752 "<SwDrawContact::GetAnchoredObj(..)> - provided object doesn't belongs to this contact" );
753
754 const SwAnchoredObject* pRetAnchoredObj = nullptr;
755
756 if (auto pVirtObj = dynamic_cast<const SwDrawVirtObj*>(pSdrObj))
757 {
758 pRetAnchoredObj = &(pVirtObj->GetAnchoredObj());
759 }
760 else
761 {
762 assert(dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
763 pRetAnchoredObj = &maAnchoredDrawObj;
764 }
765
766 return pRetAnchoredObj;
767 }
768
GetAnchoredObj(SdrObject * const pSdrObj)769 SwAnchoredObject* SwDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
770 {
771 return const_cast<SwAnchoredObject*>(const_cast<SwDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
772 }
773
GetMaster()774 SdrObject* SwDrawContact::GetMaster()
775 {
776 return !mbMasterObjCleared
777 ? maAnchoredDrawObj.DrawObj()
778 : nullptr;
779 }
780
GetAnchorFrame(const SdrObject * _pDrawObj) const781 const SwFrame* SwDrawContact::GetAnchorFrame( const SdrObject* _pDrawObj ) const
782 {
783 const SwFrame* pAnchorFrame = nullptr;
784 if ( !_pDrawObj ||
785 _pDrawObj == GetMaster() ||
786 ( !_pDrawObj->GetUserCall() &&
787 GetUserCall( _pDrawObj ) == this ) )
788 {
789 pAnchorFrame = maAnchoredDrawObj.GetAnchorFrame();
790 }
791 else
792 {
793 assert(dynamic_cast<SwDrawVirtObj const*>(_pDrawObj) != nullptr);
794 pAnchorFrame = static_cast<const SwDrawVirtObj*>(_pDrawObj)->GetAnchorFrame();
795 }
796
797 return pAnchorFrame;
798 }
799
GetAnchorFrame(SdrObject const * const pDrawObj)800 SwFrame* SwDrawContact::GetAnchorFrame(SdrObject const *const pDrawObj)
801 {
802 return const_cast<SwFrame *>(const_cast<SwDrawContact const*>(this)->GetAnchorFrame(pDrawObj));
803 }
804
805 /** add a 'virtual' drawing object to drawing page.
806 */
AddVirtObj()807 SwDrawVirtObj* SwDrawContact::AddVirtObj()
808 {
809 maDrawVirtObjs.push_back(
810 SwDrawVirtObjPtr(
811 new SwDrawVirtObj(
812 GetMaster()->getSdrModelFromSdrObject(),
813 *GetMaster(),
814 *this)));
815 maDrawVirtObjs.back()->AddToDrawingPage();
816 return maDrawVirtObjs.back().get();
817 }
818
819 /// remove 'virtual' drawing objects and destroy them.
RemoveAllVirtObjs()820 void SwDrawContact::RemoveAllVirtObjs()
821 {
822 for(auto& rpDrawVirtObj : maDrawVirtObjs)
823 {
824 // remove and destroy 'virtual object'
825 rpDrawVirtObj->RemoveFromWriterLayout();
826 rpDrawVirtObj->RemoveFromDrawingPage();
827 }
828 maDrawVirtObjs.clear();
829 }
830
831
832 /// get drawing object ('master' or 'virtual') by frame.
GetDrawObjectByAnchorFrame(const SwFrame & _rAnchorFrame)833 SdrObject* SwDrawContact::GetDrawObjectByAnchorFrame( const SwFrame& _rAnchorFrame )
834 {
835 SdrObject* pRetDrawObj = nullptr;
836
837 // #i26791# - compare master frames instead of direct frames
838 const SwFrame* pProposedAnchorFrame = &_rAnchorFrame;
839 if ( pProposedAnchorFrame->IsContentFrame() )
840 {
841 const SwContentFrame* pTmpFrame =
842 static_cast<const SwContentFrame*>( pProposedAnchorFrame );
843 while ( pTmpFrame->IsFollow() )
844 {
845 pTmpFrame = pTmpFrame->FindMaster();
846 }
847 pProposedAnchorFrame = pTmpFrame;
848 }
849
850 const SwFrame* pMasterObjAnchorFrame = GetAnchorFrame();
851 if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame->IsContentFrame() )
852 {
853 const SwContentFrame* pTmpFrame =
854 static_cast<const SwContentFrame*>( pMasterObjAnchorFrame );
855 while ( pTmpFrame->IsFollow() )
856 {
857 pTmpFrame = pTmpFrame->FindMaster();
858 }
859 pMasterObjAnchorFrame = pTmpFrame;
860 }
861
862 if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame == pProposedAnchorFrame )
863 {
864 pRetDrawObj = GetMaster();
865 }
866 else
867 {
868 const auto ppFoundVirtObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
869 VirtObjAnchoredAtFramePred(pProposedAnchorFrame)));
870 if(ppFoundVirtObj != maDrawVirtObjs.end())
871 pRetDrawObj = ppFoundVirtObj->get();
872 }
873
874 return pRetDrawObj;
875 }
876
NotifyBackgrdOfAllVirtObjs(const tools::Rectangle * pOldBoundRect)877 void SwDrawContact::NotifyBackgrdOfAllVirtObjs(const tools::Rectangle* pOldBoundRect)
878 {
879 for(const auto& rpDrawVirtObj : maDrawVirtObjs)
880 {
881 SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
882 if ( pDrawVirtObj->GetAnchorFrame() )
883 {
884 // #i34640# - determine correct page frame
885 SwPageFrame* pPage = pDrawVirtObj->AnchoredObj().FindPageFrameOfAnchor();
886 if( pOldBoundRect && pPage )
887 {
888 SwRect aOldRect( *pOldBoundRect );
889 aOldRect.Pos() += pDrawVirtObj->GetOffset();
890 if( aOldRect.HasArea() )
891 ::Notify_Background( pDrawVirtObj, pPage,
892 aOldRect, PREP_FLY_LEAVE,true);
893 }
894 // #i34640# - include spacing for wrapping
895 SwRect aRect( pDrawVirtObj->GetAnchoredObj().GetObjRectWithSpaces() );
896 if (aRect.HasArea() && pPage)
897 {
898 SwPageFrame* pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aRect, pPage )));
899 if ( pPg )
900 ::Notify_Background( pDrawVirtObj, pPg, aRect,
901 PREP_FLY_ARRIVE, true );
902 }
903 ::ClrContourCache( pDrawVirtObj );
904 }
905 }
906 }
907
908 /// local method to notify the background for a drawing object - #i26791#
lcl_NotifyBackgroundOfObj(SwDrawContact const & _rDrawContact,const SdrObject & _rObj,const tools::Rectangle * _pOldObjRect)909 static void lcl_NotifyBackgroundOfObj( SwDrawContact const & _rDrawContact,
910 const SdrObject& _rObj,
911 const tools::Rectangle* _pOldObjRect )
912 {
913 // #i34640#
914 SwAnchoredObject* pAnchoredObj =
915 const_cast<SwAnchoredObject*>(_rDrawContact.GetAnchoredObj( &_rObj ));
916 if ( pAnchoredObj && pAnchoredObj->GetAnchorFrame() )
917 {
918 // #i34640# - determine correct page frame
919 SwPageFrame* pPageFrame = pAnchoredObj->FindPageFrameOfAnchor();
920 if( _pOldObjRect && pPageFrame )
921 {
922 SwRect aOldRect( *_pOldObjRect );
923 if( aOldRect.HasArea() )
924 {
925 // #i34640# - determine correct page frame
926 SwPageFrame* pOldPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aOldRect, pPageFrame )));
927 ::Notify_Background( &_rObj, pOldPageFrame, aOldRect,
928 PREP_FLY_LEAVE, true);
929 }
930 }
931 // #i34640# - include spacing for wrapping
932 SwRect aNewRect( pAnchoredObj->GetObjRectWithSpaces() );
933 if( aNewRect.HasArea() && pPageFrame )
934 {
935 pPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aNewRect, pPageFrame )));
936 ::Notify_Background( &_rObj, pPageFrame, aNewRect,
937 PREP_FLY_ARRIVE, true );
938 }
939 ClrContourCache( &_rObj );
940 }
941 }
942
Changed(const SdrObject & rObj,SdrUserCallType eType,const tools::Rectangle & rOldBoundRect)943 void SwDrawContact::Changed( const SdrObject& rObj,
944 SdrUserCallType eType,
945 const tools::Rectangle& rOldBoundRect )
946 {
947 // #i26791# - no event handling, if existing <SwViewShell>
948 // is in construction
949 SwDoc* pDoc = GetFormat()->GetDoc();
950 if ( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() &&
951 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor() )
952 {
953 return;
954 }
955
956 // #i44339#
957 // no event handling, if document is in destruction.
958 // Exception: It's the SdrUserCallType::Delete event
959 if ( pDoc->IsInDtor() && eType != SdrUserCallType::Delete )
960 {
961 return;
962 }
963
964 //Put on Action, but not if presently anywhere an action runs.
965 bool bHasActions(true);
966 SwRootFrame *pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
967 if ( pTmpRoot && pTmpRoot->IsCallbackActionEnabled() )
968 {
969 SwViewShell* const pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
970 if ( pSh )
971 {
972 for(SwViewShell& rShell : pSh->GetRingContainer() )
973 {
974 if ( rShell.Imp()->IsAction() || rShell.Imp()->IsIdleAction() )
975 {
976 bHasActions = true;
977 break;
978 }
979 bHasActions = false;
980 }
981 }
982 if(!bHasActions)
983 pTmpRoot->StartAllAction();
984 }
985 SdrObjUserCall::Changed( rObj, eType, rOldBoundRect );
986 Changed_( rObj, eType, &rOldBoundRect ); //Attention, possibly suicidal!
987
988 if(!bHasActions)
989 pTmpRoot->EndAllAction();
990 }
991
992 /// helper class for method <SwDrawContact::Changed_(..)> for handling nested
993 /// <SdrObjUserCall> events
994 class NestedUserCallHdl
995 {
996 private:
997 SwDrawContact* mpDrawContact;
998 bool const mbParentUserCallActive;
999 SdrUserCallType const meParentUserCallEventType;
1000
1001 public:
NestedUserCallHdl(SwDrawContact * _pDrawContact,SdrUserCallType _eEventType)1002 NestedUserCallHdl( SwDrawContact* _pDrawContact,
1003 SdrUserCallType _eEventType )
1004 : mpDrawContact( _pDrawContact ),
1005 mbParentUserCallActive( _pDrawContact->mbUserCallActive ),
1006 meParentUserCallEventType( _pDrawContact->meEventTypeOfCurrentUserCall )
1007 {
1008 mpDrawContact->mbUserCallActive = true;
1009 mpDrawContact->meEventTypeOfCurrentUserCall = _eEventType;
1010 }
1011
~NestedUserCallHdl()1012 ~NestedUserCallHdl()
1013 {
1014 if ( mpDrawContact )
1015 {
1016 mpDrawContact->mbUserCallActive = mbParentUserCallActive;
1017 mpDrawContact->meEventTypeOfCurrentUserCall = meParentUserCallEventType;
1018 }
1019 }
1020
DrawContactDeleted()1021 void DrawContactDeleted()
1022 {
1023 mpDrawContact = nullptr;
1024 }
1025
IsNestedUserCall() const1026 bool IsNestedUserCall() const
1027 {
1028 return mbParentUserCallActive;
1029 }
1030
AssertNestedUserCall()1031 void AssertNestedUserCall()
1032 {
1033 if ( IsNestedUserCall() )
1034 {
1035 bool bTmpAssert( true );
1036 // Currently its known, that a nested event SdrUserCallType::Resize
1037 // could occur during parent user call SdrUserCallType::Inserted,
1038 // SdrUserCallType::Delete and SdrUserCallType::Resize for edge objects.
1039 // Also possible are nested SdrUserCallType::ChildResize events for
1040 // edge objects
1041 // Thus, assert all other combinations
1042 if ( ( meParentUserCallEventType == SdrUserCallType::Inserted ||
1043 meParentUserCallEventType == SdrUserCallType::Delete ||
1044 meParentUserCallEventType == SdrUserCallType::Resize ) &&
1045 mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::Resize )
1046 {
1047 bTmpAssert = false;
1048 }
1049 else if ( meParentUserCallEventType == SdrUserCallType::ChildResize &&
1050 mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::ChildResize )
1051 {
1052 bTmpAssert = false;
1053 }
1054
1055 if ( bTmpAssert )
1056 {
1057 OSL_FAIL( "<SwDrawContact::Changed_(..)> - unknown nested <UserCall> event. This is serious." );
1058 }
1059 }
1060 }
1061 };
1062
1063 /// Notify the format's textbox that it should reconsider its position / size.
lcl_textBoxSizeNotify(SwFrameFormat * pFormat)1064 static void lcl_textBoxSizeNotify(SwFrameFormat* pFormat)
1065 {
1066 if (SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT))
1067 {
1068 // Just notify the textbox that the size has changed, the actual object size is not interesting.
1069 SfxItemSet aResizeSet(pFormat->GetDoc()->GetAttrPool(), svl::Items<RES_FRM_SIZE, RES_FRM_SIZE>{});
1070 SwFormatFrameSize aSize;
1071 aResizeSet.Put(aSize);
1072 SwTextBoxHelper::syncFlyFrameAttr(*pFormat, aResizeSet);
1073 }
1074 }
1075
1076 // !!!ATTENTION!!! The object may commit suicide!!!
1077
Changed_(const SdrObject & rObj,SdrUserCallType eType,const tools::Rectangle * pOldBoundRect)1078 void SwDrawContact::Changed_( const SdrObject& rObj,
1079 SdrUserCallType eType,
1080 const tools::Rectangle* pOldBoundRect )
1081 {
1082 // suppress handling of nested <SdrObjUserCall> events
1083 NestedUserCallHdl aNestedUserCallHdl( this, eType );
1084 if ( aNestedUserCallHdl.IsNestedUserCall() )
1085 {
1086 aNestedUserCallHdl.AssertNestedUserCall();
1087 return;
1088 }
1089 // do *not* notify, if document is destructing
1090 // #i35912# - do *not* notify for as-character anchored
1091 // drawing objects.
1092 // #i35007#
1093 // improvement: determine as-character anchored object flag only once.
1094 const bool bAnchoredAsChar = ObjAnchoredAsChar();
1095 const bool bNotify = !(GetFormat()->GetDoc()->IsInDtor()) &&
1096 ( css::text::WrapTextMode_THROUGH != GetFormat()->GetSurround().GetSurround() ) &&
1097 !bAnchoredAsChar;
1098 switch( eType )
1099 {
1100 case SdrUserCallType::Delete:
1101 {
1102 if ( bNotify )
1103 {
1104 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1105 // --> #i36181# - background of 'virtual'
1106 // drawing objects have also been notified.
1107 NotifyBackgrdOfAllVirtObjs( pOldBoundRect );
1108 }
1109 DisconnectFromLayout( false );
1110 mbMasterObjCleared = true;
1111 delete this;
1112 // --> #i65784# Prevent memory corruption
1113 aNestedUserCallHdl.DrawContactDeleted();
1114 break;
1115 }
1116 case SdrUserCallType::Inserted:
1117 {
1118 if ( mbDisconnectInProgress )
1119 {
1120 OSL_FAIL( "<SwDrawContact::Changed_(..)> - Insert event during disconnection from layout is invalid." );
1121 }
1122 else
1123 {
1124 ConnectToLayout();
1125 if ( bNotify )
1126 {
1127 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1128 }
1129 }
1130 break;
1131 }
1132 case SdrUserCallType::Removed:
1133 {
1134 if ( bNotify )
1135 {
1136 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1137 }
1138 DisconnectFromLayout( false );
1139 break;
1140 }
1141 case SdrUserCallType::ChildInserted :
1142 case SdrUserCallType::ChildRemoved :
1143 {
1144 // --> #i113730#
1145 // force layer of controls for group objects containing control objects
1146 if(dynamic_cast< SdrObjGroup* >(maAnchoredDrawObj.DrawObj()))
1147 {
1148 if(::CheckControlLayer(maAnchoredDrawObj.DrawObj()))
1149 {
1150 const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
1151 const SdrLayerID aCurrentLayer(maAnchoredDrawObj.DrawObj()->GetLayer());
1152 const SdrLayerID aControlLayerID(rIDDMA.GetControlsId());
1153 const SdrLayerID aInvisibleControlLayerID(rIDDMA.GetInvisibleControlsId());
1154
1155 if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID)
1156 {
1157 if ( aCurrentLayer == rIDDMA.GetInvisibleHellId() ||
1158 aCurrentLayer == rIDDMA.GetInvisibleHeavenId() )
1159 {
1160 maAnchoredDrawObj.DrawObj()->SetLayer(aInvisibleControlLayerID);
1161 }
1162 else
1163 {
1164 maAnchoredDrawObj.DrawObj()->SetLayer(aControlLayerID);
1165 }
1166 }
1167 }
1168 }
1169 [[fallthrough]];
1170 }
1171 case SdrUserCallType::MoveOnly:
1172 case SdrUserCallType::Resize:
1173 case SdrUserCallType::ChildMoveOnly :
1174 case SdrUserCallType::ChildResize :
1175 case SdrUserCallType::ChildChangeAttr :
1176 case SdrUserCallType::ChildDelete :
1177 {
1178 // #i31698# - improvement
1179 // get instance <SwAnchoredDrawObject> only once
1180 const SwAnchoredDrawObject* pAnchoredDrawObj =
1181 static_cast<const SwAnchoredDrawObject*>( GetAnchoredObj( &rObj ) );
1182
1183 /* protect against NULL pointer dereferencing */
1184 if(!pAnchoredDrawObj)
1185 {
1186 break;
1187 }
1188
1189 // #i26791# - adjust positioning and alignment attributes,
1190 // if positioning of drawing object isn't in progress.
1191 // #i53320# - no adjust of positioning attributes,
1192 // if drawing object isn't positioned.
1193 if ( !pAnchoredDrawObj->IsPositioningInProgress() &&
1194 !pAnchoredDrawObj->NotYetPositioned() )
1195 {
1196 // #i34748# - If no last object rectangle is
1197 // provided by the anchored object, use parameter <pOldBoundRect>.
1198 const tools::Rectangle& aOldObjRect = pAnchoredDrawObj->GetLastObjRect()
1199 ? *(pAnchoredDrawObj->GetLastObjRect())
1200 : *pOldBoundRect;
1201 // #i79400#
1202 // always invalidate object rectangle inclusive spaces
1203 pAnchoredDrawObj->InvalidateObjRectWithSpaces();
1204 // #i41324# - notify background before
1205 // adjusting position
1206 if ( bNotify )
1207 {
1208 // #i31573# - correction
1209 // background of given drawing object.
1210 lcl_NotifyBackgroundOfObj( *this, rObj, &aOldObjRect );
1211 }
1212 // #i31698# - determine layout direction
1213 // via draw frame format.
1214 SwFrameFormat::tLayoutDir eLayoutDir =
1215 pAnchoredDrawObj->GetFrameFormat().GetLayoutDir();
1216 // use geometry of drawing object
1217 SwRect aObjRect( rObj.GetSnapRect() );
1218 // If drawing object is a member of a group, the adjustment
1219 // of the positioning and the alignment attributes has to
1220 // be done for the top group object.
1221 if ( rObj.getParentSdrObjectFromSdrObject() )
1222 {
1223 const SdrObject* pGroupObj = rObj.getParentSdrObjectFromSdrObject();
1224 while ( pGroupObj->getParentSdrObjectFromSdrObject() )
1225 {
1226 pGroupObj = pGroupObj->getParentSdrObjectFromSdrObject();
1227 }
1228 // use geometry of drawing object
1229 aObjRect = pGroupObj->GetSnapRect();
1230 }
1231 SwTwips nXPosDiff(0);
1232 SwTwips nYPosDiff(0);
1233 switch ( eLayoutDir )
1234 {
1235 case SwFrameFormat::HORI_L2R:
1236 {
1237 nXPosDiff = aObjRect.Left() - aOldObjRect.Left();
1238 nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1239 }
1240 break;
1241 case SwFrameFormat::HORI_R2L:
1242 {
1243 nXPosDiff = aOldObjRect.Right() - aObjRect.Right();
1244 nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1245 }
1246 break;
1247 case SwFrameFormat::VERT_R2L:
1248 {
1249 nXPosDiff = aObjRect.Top() - aOldObjRect.Top();
1250 nYPosDiff = aOldObjRect.Right() - aObjRect.Right();
1251 }
1252 break;
1253 default:
1254 {
1255 assert(!"<SwDrawContact::Changed_(..)> - unsupported layout direction");
1256 }
1257 }
1258 SfxItemSet aSet( GetFormat()->GetDoc()->GetAttrPool(),
1259 svl::Items<RES_VERT_ORIENT, RES_HORI_ORIENT>{} );
1260 const SwFormatVertOrient& rVert = GetFormat()->GetVertOrient();
1261 if ( nYPosDiff != 0 )
1262 {
1263
1264 if ( rVert.GetRelationOrient() == text::RelOrientation::CHAR ||
1265 rVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
1266 {
1267 nYPosDiff = -nYPosDiff;
1268 }
1269 aSet.Put( SwFormatVertOrient( rVert.GetPos()+nYPosDiff,
1270 text::VertOrientation::NONE,
1271 rVert.GetRelationOrient() ) );
1272 }
1273
1274 const SwFormatHoriOrient& rHori = GetFormat()->GetHoriOrient();
1275 if ( !bAnchoredAsChar && nXPosDiff != 0 )
1276 {
1277 aSet.Put( SwFormatHoriOrient( rHori.GetPos()+nXPosDiff,
1278 text::HoriOrientation::NONE,
1279 rHori.GetRelationOrient() ) );
1280 }
1281
1282 if ( nYPosDiff ||
1283 ( !bAnchoredAsChar && nXPosDiff != 0 ) )
1284 {
1285 GetFormat()->GetDoc()->SetFlyFrameAttr( *(GetFormat()), aSet );
1286 // keep new object rectangle, to avoid multiple
1287 // changes of the attributes by multiple event from
1288 // the drawing layer - e.g. group objects and its members
1289 // #i34748# - use new method
1290 // <SwAnchoredDrawObject::SetLastObjRect(..)>.
1291 const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)
1292 ->SetLastObjRect( aObjRect.SVRect() );
1293 }
1294 else if ( aObjRect.SSize() != aOldObjRect.GetSize() )
1295 {
1296 InvalidateObjs_();
1297 // #i35007# - notify anchor frame
1298 // of as-character anchored object
1299 if ( bAnchoredAsChar )
1300 {
1301 SwFrame* pAnchorFrame = const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)->AnchorFrame();
1302 if(pAnchorFrame)
1303 {
1304 pAnchorFrame->Prepare( PREP_FLY_ATTR_CHG, GetFormat() );
1305 }
1306 }
1307
1308 lcl_textBoxSizeNotify(GetFormat());
1309 }
1310 else if (eType == SdrUserCallType::Resize)
1311 // Even if the bounding box of the shape didn't change,
1312 // notify about the size change, as an adjustment change
1313 // may affect the size of the underlying textbox.
1314 lcl_textBoxSizeNotify(GetFormat());
1315 }
1316 }
1317 break;
1318 case SdrUserCallType::ChangeAttr:
1319 if ( bNotify )
1320 {
1321 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1322 }
1323 break;
1324 default:
1325 break;
1326 }
1327 }
1328
1329 namespace
1330 {
lcl_getAnchorFormat(const SfxPoolItem & _rItem)1331 const SwFormatAnchor* lcl_getAnchorFormat( const SfxPoolItem& _rItem )
1332 {
1333 sal_uInt16 nWhich = _rItem.Which();
1334 const SwFormatAnchor* pAnchorFormat = nullptr;
1335 if ( RES_ATTRSET_CHG == nWhich )
1336 {
1337 static_cast<const SwAttrSetChg&>(_rItem).GetChgSet()->
1338 GetItemState( RES_ANCHOR, false, reinterpret_cast<const SfxPoolItem**>(&pAnchorFormat) );
1339 }
1340 else if ( RES_ANCHOR == nWhich )
1341 {
1342 pAnchorFormat = &static_cast<const SwFormatAnchor&>(_rItem);
1343 }
1344 return pAnchorFormat;
1345 }
1346 }
1347
SwClientNotify(const SwModify & rMod,const SfxHint & rHint)1348 void SwDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
1349 {
1350 SwClient::SwClientNotify(rMod, rHint); // needed as SwContact::SwClientNotify doesn't explicitly call SwClient::SwClientNotify
1351 SwContact::SwClientNotify(rMod, rHint);
1352 if (auto pLegacyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
1353 {
1354 SAL_WARN_IF(mbDisconnectInProgress, "sw.core", "<SwDrawContact::Modify(..)> called during disconnection.");
1355
1356 const SfxPoolItem* pNew = pLegacyHint->m_pNew;
1357 sal_uInt16 nWhich = pNew ? pNew->Which() : 0;
1358 if(const SwFormatAnchor* pNewAnchorFormat = pNew ? lcl_getAnchorFormat(*pNew) : nullptr)
1359 {
1360 // Do not respond to a Reset Anchor!
1361 if(GetFormat()->GetAttrSet().GetItemState(RES_ANCHOR, false) == SfxItemState::SET)
1362 {
1363 // no connect to layout during disconnection
1364 if(!mbDisconnectInProgress)
1365 {
1366 // determine old object rectangle of 'master' drawing object
1367 // for notification
1368 const tools::Rectangle* pOldRect = nullptr;
1369 tools::Rectangle aOldRect;
1370 if(GetAnchorFrame())
1371 {
1372 // --> #i36181# - include spacing in object
1373 // rectangle for notification.
1374 aOldRect = maAnchoredDrawObj.GetObjRectWithSpaces().SVRect();
1375 pOldRect = &aOldRect;
1376 }
1377 // re-connect to layout due to anchor format change
1378 ConnectToLayout(pNewAnchorFormat);
1379 // notify background of drawing objects
1380 lcl_NotifyBackgroundOfObj(*this, *GetMaster(), pOldRect);
1381 NotifyBackgrdOfAllVirtObjs(pOldRect);
1382
1383 const SwFormatAnchor* pOldAnchorFormat = pLegacyHint->m_pOld ? lcl_getAnchorFormat(*pLegacyHint->m_pOld) : nullptr;
1384 if(!pOldAnchorFormat || (pOldAnchorFormat->GetAnchorId() != pNewAnchorFormat->GetAnchorId()))
1385 {
1386 if(maAnchoredDrawObj.DrawObj())
1387 {
1388 // --> #i102752#
1389 // assure that a ShapePropertyChangeNotifier exists
1390 maAnchoredDrawObj.DrawObj()->notifyShapePropertyChange(svx::ShapeProperty::TextDocAnchor);
1391 }
1392 else
1393 SAL_WARN("sw.core", "SwDrawContact::Modify: no draw object here?");
1394 }
1395 }
1396 }
1397 else
1398 DisconnectFromLayout();
1399 }
1400 else if (nWhich == RES_REMOVE_UNO_OBJECT)
1401 {} // nothing to do
1402 // --> #i62875# - no further notification, if not connected to Writer layout
1403 else if ( maAnchoredDrawObj.GetAnchorFrame() &&
1404 maAnchoredDrawObj.GetDrawObj()->GetUserCall() )
1405 {
1406 bool bUpdateSortedObjsList(false);
1407 switch(nWhich)
1408 {
1409 case RES_UL_SPACE:
1410 case RES_LR_SPACE:
1411 case RES_HORI_ORIENT:
1412 case RES_VERT_ORIENT:
1413 case RES_FOLLOW_TEXT_FLOW: // #i28701# - add attribute 'Follow text flow'
1414 break;
1415 case RES_SURROUND:
1416 case RES_OPAQUE:
1417 case RES_WRAP_INFLUENCE_ON_OBJPOS:
1418 // --> #i28701# - on change of wrapping style, hell|heaven layer,
1419 // or wrapping style influence an update of the <SwSortedObjs> list,
1420 // the drawing object is registered in, has to be performed. This is triggered
1421 // by the 1st parameter of method call <InvalidateObjs_(..)>.
1422 bUpdateSortedObjsList = true;
1423 break;
1424 case RES_ATTRSET_CHG: // #i35443#
1425 {
1426 auto pChgSet = static_cast<const SwAttrSetChg*>(pNew)->GetChgSet();
1427 if(pChgSet->GetItemState(RES_SURROUND, false) == SfxItemState::SET ||
1428 pChgSet->GetItemState(RES_OPAQUE, false) == SfxItemState::SET ||
1429 pChgSet->GetItemState(RES_WRAP_INFLUENCE_ON_OBJPOS, false) == SfxItemState::SET)
1430 bUpdateSortedObjsList = true;
1431 }
1432 break;
1433 default:
1434 assert(!"<SwDraw Contact::Modify(..)> - unhandled attribute?");
1435 }
1436 lcl_NotifyBackgroundOfObj(*this, *GetMaster(), nullptr);
1437 NotifyBackgrdOfAllVirtObjs(nullptr);
1438 InvalidateObjs_(bUpdateSortedObjsList);
1439 }
1440
1441 // #i51474#
1442 GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
1443 }
1444 else if (auto pDrawFrameFormatHint = dynamic_cast<const sw::DrawFrameFormatHint*>(&rHint))
1445 {
1446 switch(pDrawFrameFormatHint->m_eId)
1447 {
1448 case sw::DrawFrameFormatHintId::DYING:
1449 delete this;
1450 break;
1451 case sw::DrawFrameFormatHintId::PREPPASTING:
1452 MoveObjToVisibleLayer(GetMaster());
1453 break;
1454 case sw::DrawFrameFormatHintId::PREP_INSERT_FLY:
1455 InsertMasterIntoDrawPage();
1456 // #i40845# - follow-up of #i35635#
1457 // move object to visible layer
1458 MoveObjToVisibleLayer(GetMaster());
1459 // tdf#135661 InsertMasterIntoDrawPage may have created a new
1460 // SwXShape with null m_pFormat; fix that
1461 SwXShape::AddExistingShapeToFormat(*GetMaster());
1462 break;
1463 case sw::DrawFrameFormatHintId::PREP_DELETE_FLY:
1464 RemoveMasterFromDrawPage();
1465 break;
1466 case sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS:
1467 case sw::DrawFrameFormatHintId::DELETE_FRAMES:
1468 DisconnectFromLayout();
1469 break;
1470 case sw::DrawFrameFormatHintId::MAKE_FRAMES:
1471 ConnectToLayout();
1472 break;
1473 case sw::DrawFrameFormatHintId::POST_RESTORE_FLY_ANCHOR:
1474 GetAnchoredObj(GetMaster())->MakeObjPos();
1475 break;
1476 default:
1477 ;
1478 }
1479 }
1480 else if (auto pCheckDrawFrameFormatLayerHint = dynamic_cast<const sw::CheckDrawFrameFormatLayerHint*>(&rHint))
1481 {
1482 *(pCheckDrawFrameFormatLayerHint->m_bCheckControlLayer) |= (GetMaster() && CheckControlLayer(GetMaster()));
1483 }
1484 else if (auto pContactChangedHint = dynamic_cast<const sw::ContactChangedHint*>(&rHint))
1485 {
1486 if(!*pContactChangedHint->m_ppObject)
1487 *pContactChangedHint->m_ppObject = GetMaster();
1488 auto pObject = *pContactChangedHint->m_ppObject;
1489 Changed(*pObject, SdrUserCallType::Delete, pObject->GetLastBoundRect());
1490 }
1491 else if (auto pDrawFormatLayoutCopyHint = dynamic_cast<const sw::DrawFormatLayoutCopyHint*>(&rHint))
1492 {
1493 const SwDrawFrameFormat& rFormat = static_cast<const SwDrawFrameFormat&>(rMod);
1494 new SwDrawContact(
1495 &pDrawFormatLayoutCopyHint->m_rDestFormat,
1496 pDrawFormatLayoutCopyHint->m_rDestDoc.CloneSdrObj(
1497 *GetMaster(),
1498 pDrawFormatLayoutCopyHint->m_rDestDoc.IsCopyIsMove() && &pDrawFormatLayoutCopyHint->m_rDestDoc == rFormat.GetDoc()));
1499 // #i49730# - notify draw frame format that position attributes are
1500 // already set, if the position attributes are already set at the
1501 // source draw frame format.
1502 if(rFormat.IsPosAttrSet())
1503 pDrawFormatLayoutCopyHint->m_rDestFormat.PosAttrSet();
1504 }
1505 else if (auto pRestoreFlyAnchorHint = dynamic_cast<const sw::RestoreFlyAnchorHint*>(&rHint))
1506 {
1507 SdrObject* pObj = GetMaster();
1508 if(GetAnchorFrame() && !pObj->IsInserted())
1509 {
1510 auto pDrawModel = const_cast<SwDrawFrameFormat&>(static_cast<const SwDrawFrameFormat&>(rMod)).GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1511 assert(pDrawModel);
1512 pDrawModel->GetPage(0)->InsertObject(pObj);
1513 }
1514 pObj->SetRelativePos(pRestoreFlyAnchorHint->m_aPos);
1515 }
1516 else if (auto pCreatePortionHint = dynamic_cast<const sw::CreatePortionHint*>(&rHint))
1517 {
1518 if(*pCreatePortionHint->m_ppContact)
1519 return;
1520 *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
1521 if(!GetAnchorFrame())
1522 {
1523 // No direct positioning needed any more
1524 ConnectToLayout();
1525 // Move object to visible layer
1526 MoveObjToVisibleLayer(GetMaster());
1527 }
1528 }
1529 else if (auto pCollectTextObjectsHint = dynamic_cast<const sw::CollectTextObjectsHint*>(&rHint))
1530 {
1531 auto pSdrO = GetMaster();
1532 if(!pSdrO)
1533 return;
1534 if(dynamic_cast<const SdrObjGroup*>(pSdrO))
1535 {
1536 SdrObjListIter aListIter(*pSdrO, SdrIterMode::DeepNoGroups);
1537 //iterate inside of a grouped object
1538 while(aListIter.IsMore())
1539 {
1540 SdrObject* pSdrOElement = aListIter.Next();
1541 auto pTextObj = const_cast<SdrTextObj*>(dynamic_cast<const SdrTextObj*>(pSdrOElement));
1542 if(pTextObj && pTextObj->HasText())
1543 pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1544 }
1545 }
1546 else if(auto pTextObj = const_cast<SdrTextObj*>(dynamic_cast<const SdrTextObj*>(pSdrO)))
1547 {
1548 if(pTextObj->HasText())
1549 pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1550 }
1551 }
1552 else if (auto pGetZOrdnerHint = dynamic_cast<const sw::GetZOrderHint*>(&rHint))
1553 {
1554 auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
1555 if(pFormat->Which() == RES_DRAWFRMFMT)
1556 pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
1557 }
1558 else if (auto pConnectedHint = dynamic_cast<const sw::GetObjectConnectedHint*>(&rHint))
1559 {
1560 pConnectedHint->m_risConnected |= (GetAnchorFrame() != nullptr);
1561 }
1562 }
1563
1564 // #i26791#
1565 // #i28701# - added parameter <_bUpdateSortedObjsList>
InvalidateObjs_(const bool _bUpdateSortedObjsList)1566 void SwDrawContact::InvalidateObjs_( const bool _bUpdateSortedObjsList )
1567 {
1568 for(const auto& rpDrawVirtObj : maDrawVirtObjs)
1569 // invalidate position of existing 'virtual' drawing objects
1570 {
1571 SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
1572 // #i33313# - invalidation only for connected
1573 // 'virtual' drawing objects
1574 if ( pDrawVirtObj->IsConnected() )
1575 {
1576 pDrawVirtObj->AnchoredObj().InvalidateObjPos();
1577 // #i28701#
1578 if ( _bUpdateSortedObjsList )
1579 {
1580 pDrawVirtObj->AnchoredObj().UpdateObjInSortedList();
1581 }
1582 }
1583 }
1584
1585 // invalidate position of 'master' drawing object
1586 SwAnchoredObject* pAnchoredObj = GetAnchoredObj( nullptr );
1587 pAnchoredObj->InvalidateObjPos();
1588 // #i28701#
1589 if ( _bUpdateSortedObjsList )
1590 {
1591 pAnchoredObj->UpdateObjInSortedList();
1592 }
1593 }
1594
DisconnectFromLayout(bool _bMoveMasterToInvisibleLayer)1595 void SwDrawContact::DisconnectFromLayout( bool _bMoveMasterToInvisibleLayer )
1596 {
1597 mbDisconnectInProgress = true;
1598
1599 // --> #i36181# - notify background of drawing object
1600 if ( _bMoveMasterToInvisibleLayer &&
1601 !(GetFormat()->GetDoc()->IsInDtor()) &&
1602 GetAnchorFrame() && !GetAnchorFrame()->IsInDtor() )
1603 {
1604 const tools::Rectangle aOldRect( maAnchoredDrawObj.GetObjRectWithSpaces().SVRect() );
1605 lcl_NotifyBackgroundOfObj( *this, *GetMaster(), &aOldRect );
1606 NotifyBackgrdOfAllVirtObjs( &aOldRect );
1607 }
1608
1609 // remove 'virtual' drawing objects from writer
1610 // layout and from drawing page
1611 for(auto& rpVirtDrawObj : maDrawVirtObjs)
1612 {
1613 rpVirtDrawObj->RemoveFromWriterLayout();
1614 rpVirtDrawObj->RemoveFromDrawingPage();
1615 }
1616
1617 if ( maAnchoredDrawObj.GetAnchorFrame() )
1618 {
1619 maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1620 }
1621
1622 if ( _bMoveMasterToInvisibleLayer && GetMaster() && GetMaster()->IsInserted() )
1623 {
1624 SdrViewIter aIter( GetMaster() );
1625 for( SdrView* pView = aIter.FirstView(); pView;
1626 pView = aIter.NextView() )
1627 {
1628 pView->MarkObj( GetMaster(), pView->GetSdrPageView(), true );
1629 }
1630
1631 // Instead of removing 'master' object from drawing page, move the
1632 // 'master' drawing object into the corresponding invisible layer.
1633 {
1634 //static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess()->GetDrawModel()->GetPage(0)->
1635 // RemoveObject( GetMaster()->GetOrdNum() );
1636 // #i18447# - in order to consider group object correct
1637 // use new method <SwDrawContact::MoveObjToInvisibleLayer(..)>
1638 MoveObjToInvisibleLayer( GetMaster() );
1639 }
1640 }
1641
1642 mbDisconnectInProgress = false;
1643 }
1644
1645 /// method to remove 'master' drawing object from drawing page.
RemoveMasterFromDrawPage()1646 void SwDrawContact::RemoveMasterFromDrawPage()
1647 {
1648 if ( GetMaster() )
1649 {
1650 GetMaster()->SetUserCall( nullptr );
1651 if ( GetMaster()->IsInserted() )
1652 {
1653 static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
1654 RemoveObject( GetMaster()->GetOrdNum() );
1655 }
1656 }
1657 }
1658
1659 // disconnect for a dedicated drawing object - could be 'master' or 'virtual'.
1660 // a 'master' drawing object will disconnect a 'virtual' drawing object
1661 // in order to take its place.
1662 // #i19919# - no special case, if drawing object isn't in
1663 // page header/footer, in order to get drawing objects in repeating table headers
1664 // also working.
DisconnectObjFromLayout(SdrObject * _pDrawObj)1665 void SwDrawContact::DisconnectObjFromLayout( SdrObject* _pDrawObj )
1666 {
1667 if ( dynamic_cast<const SwDrawVirtObj*>( _pDrawObj) != nullptr )
1668 {
1669 SwDrawVirtObj* pDrawVirtObj = static_cast<SwDrawVirtObj*>(_pDrawObj);
1670 pDrawVirtObj->RemoveFromWriterLayout();
1671 pDrawVirtObj->RemoveFromDrawingPage();
1672 }
1673 else
1674 {
1675 const auto ppVirtDrawObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
1676 [] (const SwDrawVirtObjPtr& pObj) { return pObj->IsConnected(); }));
1677
1678 if(ppVirtDrawObj != maDrawVirtObjs.end())
1679 {
1680 // replace found 'virtual' drawing object by 'master' drawing
1681 // object and disconnect the 'virtual' one
1682 SwDrawVirtObj* pDrawVirtObj(ppVirtDrawObj->get());
1683 SwFrame* pNewAnchorFrameOfMaster = pDrawVirtObj->AnchorFrame();
1684 // disconnect 'virtual' drawing object
1685 pDrawVirtObj->RemoveFromWriterLayout();
1686 pDrawVirtObj->RemoveFromDrawingPage();
1687 // disconnect 'master' drawing object from current frame
1688 GetAnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1689 // re-connect 'master' drawing object to frame of found 'virtual'
1690 // drawing object.
1691 pNewAnchorFrameOfMaster->AppendDrawObj( maAnchoredDrawObj );
1692 }
1693 else
1694 {
1695 // no connected 'virtual' drawing object found. Thus, disconnect
1696 // completely from layout.
1697 DisconnectFromLayout();
1698 }
1699 }
1700 }
1701
lcl_GetFlyInContentAnchor(SwTextFrame * _pProposedAnchorFrame,SwPosition const & rAnchorPos)1702 static SwTextFrame* lcl_GetFlyInContentAnchor( SwTextFrame* _pProposedAnchorFrame,
1703 SwPosition const& rAnchorPos)
1704 {
1705 SwTextFrame* pAct = _pProposedAnchorFrame;
1706 SwTextFrame* pTmp;
1707 TextFrameIndex const nTextOffset(_pProposedAnchorFrame->MapModelToViewPos(rAnchorPos));
1708 do
1709 {
1710 pTmp = pAct;
1711 pAct = pTmp->GetFollow();
1712 }
1713 while (pAct && nTextOffset >= pAct->GetOfst());
1714 return pTmp;
1715 }
1716
ConnectToLayout(const SwFormatAnchor * pAnch)1717 void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
1718 {
1719 // *no* connect to layout during disconnection from layout.
1720 if ( mbDisconnectInProgress )
1721 {
1722 OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> called during disconnection.");
1723 return;
1724 }
1725
1726 // --> #i33909# - *no* connect to layout, if 'master' drawing
1727 // object isn't inserted in the drawing page
1728 if ( !GetMaster()->IsInserted() )
1729 {
1730 OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> - master drawing object not inserted -> no connect to layout. Please inform od@openoffice.org" );
1731 return;
1732 }
1733
1734 SwFrameFormat* pDrawFrameFormat = static_cast<SwFrameFormat*>(GetRegisteredIn());
1735
1736 if( !pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell() )
1737 return;
1738
1739 // remove 'virtual' drawing objects from writer
1740 // layout and from drawing page, and remove 'master' drawing object from
1741 // writer layout - 'master' object will remain in drawing page.
1742 DisconnectFromLayout( false );
1743
1744 if ( !pAnch )
1745 {
1746 pAnch = &(pDrawFrameFormat->GetAnchor());
1747 }
1748
1749 switch ( pAnch->GetAnchorId() )
1750 {
1751 case RndStdIds::FLY_AT_PAGE:
1752 {
1753 sal_uInt16 nPgNum = pAnch->GetPageNum();
1754 SwViewShell *pShell = pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell();
1755 if( !pShell )
1756 break;
1757 SwRootFrame* pRoot = pShell->GetLayout();
1758 SwPageFrame *pPage = static_cast<SwPageFrame*>(pRoot->Lower());
1759
1760 for ( sal_uInt16 i = 1; i < nPgNum && pPage; ++i )
1761 {
1762 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1763 }
1764
1765 if ( pPage )
1766 {
1767 pPage->AppendDrawObj( maAnchoredDrawObj );
1768 }
1769 else
1770 //Looks stupid but is allowed (compare SwFEShell::SetPageObjsNewPage)
1771 pRoot->SetAssertFlyPages();
1772 }
1773 break;
1774
1775 case RndStdIds::FLY_AT_CHAR:
1776 case RndStdIds::FLY_AT_PARA:
1777 case RndStdIds::FLY_AT_FLY:
1778 case RndStdIds::FLY_AS_CHAR:
1779 {
1780 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1781 {
1782 ClrContourCache( GetMaster() );
1783 }
1784 // support drawing objects in header/footer,
1785 // but not control objects:
1786 // anchor at first found frame the 'master' object and
1787 // at the following frames 'virtual' drawing objects.
1788 // Note: method is similar to <SwFlyFrameFormat::MakeFrames(..)>
1789 SwModify *pModify = nullptr;
1790 if( pAnch->GetContentAnchor() )
1791 {
1792 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AT_FLY )
1793 {
1794 SwNodeIndex aIdx( pAnch->GetContentAnchor()->nNode );
1795 SwContentNode* pCNd = pDrawFrameFormat->GetDoc()->GetNodes().GoNext( &aIdx );
1796 if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
1797 pModify = pCNd;
1798 else
1799 {
1800 const SwNodeIndex& rIdx = pAnch->GetContentAnchor()->nNode;
1801 SwFrameFormats& rFormats = *(pDrawFrameFormat->GetDoc()->GetSpzFrameFormats());
1802 for( auto pFlyFormat : rFormats )
1803 {
1804 if( pFlyFormat->GetContent().GetContentIdx() &&
1805 rIdx == *(pFlyFormat->GetContent().GetContentIdx()) )
1806 {
1807 pModify = pFlyFormat;
1808 break;
1809 }
1810 }
1811 }
1812 }
1813 else
1814 {
1815 pModify = pAnch->GetContentAnchor()->nNode.GetNode().GetContentNode();
1816 }
1817 }
1818
1819 // #i29199# - It is possible, that
1820 // the anchor doesn't exist - E.g., reordering the
1821 // sub-documents in a master document.
1822 // Note: The anchor will be inserted later.
1823 if ( !pModify )
1824 {
1825 // break to end of the current switch case.
1826 break;
1827 }
1828
1829 SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti> aIter(*pModify);
1830 SwFrame* pAnchorFrameOfMaster = nullptr;
1831 for( SwFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1832 {
1833 // append drawing object, if
1834 // (1) proposed anchor frame isn't a follow and
1835 // (2) drawing object isn't a control object to be anchored
1836 // in header/footer.
1837 bool bAdd = ( !pFrame->IsContentFrame() ||
1838 !static_cast<SwContentFrame*>(pFrame)->IsFollow() ) &&
1839 ( !::CheckControlLayer( GetMaster() ) ||
1840 !pFrame->FindFooterOrHeader() );
1841
1842 if (bAdd && RndStdIds::FLY_AT_FLY != pAnch->GetAnchorId())
1843 {
1844 assert(pFrame->IsTextFrame());
1845 bAdd = IsAnchoredObjShown(*static_cast<SwTextFrame*>(pFrame), *pAnch);
1846 }
1847
1848 if( bAdd )
1849 {
1850 if ( RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId() && !pFrame->IsFlyFrame() )
1851 {
1852 pFrame = pFrame->FindFlyFrame();
1853 assert(pFrame);
1854 }
1855
1856 // find correct follow for as character anchored objects
1857 if ((pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR) &&
1858 pFrame->IsTextFrame() )
1859 {
1860 pFrame = lcl_GetFlyInContentAnchor(
1861 static_cast<SwTextFrame*>(pFrame),
1862 *pAnch->GetContentAnchor());
1863 }
1864
1865 if ( !pAnchorFrameOfMaster )
1866 {
1867 // append 'master' drawing object
1868 pAnchorFrameOfMaster = pFrame;
1869 pFrame->AppendDrawObj( maAnchoredDrawObj );
1870 }
1871 else
1872 {
1873 // append 'virtual' drawing object
1874 SwDrawVirtObj* pDrawVirtObj = AddVirtObj();
1875 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1876 {
1877 ClrContourCache( pDrawVirtObj );
1878 }
1879 pFrame->AppendDrawObj( pDrawVirtObj->AnchoredObj() );
1880
1881 pDrawVirtObj->ActionChanged();
1882 }
1883
1884 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1885 {
1886 pFrame->InvalidatePrt();
1887 }
1888 }
1889 }
1890 }
1891 break;
1892 default:
1893 assert(!"Unknown Anchor.");
1894 break;
1895 }
1896 if ( GetAnchorFrame() )
1897 {
1898 ::setContextWritingMode( maAnchoredDrawObj.DrawObj(), GetAnchorFrame() );
1899 // #i26791# - invalidate objects instead of direct positioning
1900 InvalidateObjs_();
1901 }
1902 }
1903
1904 /// insert 'master' drawing object into drawing page
InsertMasterIntoDrawPage()1905 void SwDrawContact::InsertMasterIntoDrawPage()
1906 {
1907 if ( !GetMaster()->IsInserted() )
1908 {
1909 GetFormat()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)
1910 ->InsertObject( GetMaster(), GetMaster()->GetOrdNumDirect() );
1911 }
1912 GetMaster()->SetUserCall( this );
1913 }
1914
FindPage(const SwRect & rRect)1915 SwPageFrame* SwDrawContact::FindPage( const SwRect &rRect )
1916 {
1917 // --> #i28701# - use method <GetPageFrame()>
1918 SwPageFrame* pPg = GetPageFrame();
1919 if ( !pPg && GetAnchorFrame() )
1920 pPg = GetAnchorFrame()->FindPageFrame();
1921 if ( pPg )
1922 pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( rRect, pPg )));
1923 return pPg;
1924 }
1925
ChkPage()1926 void SwDrawContact::ChkPage()
1927 {
1928 if ( mbDisconnectInProgress )
1929 {
1930 OSL_FAIL( "<SwDrawContact::ChkPage()> called during disconnection." );
1931 return;
1932 }
1933
1934 // --> #i28701#
1935 SwPageFrame* pPg = ( maAnchoredDrawObj.GetAnchorFrame() &&
1936 maAnchoredDrawObj.GetAnchorFrame()->IsPageFrame() )
1937 ? GetPageFrame()
1938 : FindPage( GetMaster()->GetCurrentBoundRect() );
1939 if ( GetPageFrame() != pPg )
1940 {
1941 // if drawing object is anchor in header/footer a change of the page
1942 // is a dramatic change. Thus, completely re-connect to the layout
1943 if ( maAnchoredDrawObj.GetAnchorFrame() &&
1944 maAnchoredDrawObj.GetAnchorFrame()->FindFooterOrHeader() )
1945 {
1946 ConnectToLayout();
1947 }
1948 else
1949 {
1950 // --> #i28701# - use methods <GetPageFrame()> and <SetPageFrame>
1951 if ( GetPageFrame() )
1952 GetPageFrame()->RemoveDrawObjFromPage( maAnchoredDrawObj );
1953 pPg->AppendDrawObjToPage( maAnchoredDrawObj );
1954 maAnchoredDrawObj.SetPageFrame( pPg );
1955 }
1956 }
1957 }
1958
1959 // Important note:
1960 // method is called by method <SwDPage::ReplaceObject(..)>, which called its
1961 // corresponding superclass method <FmFormPage::ReplaceObject(..)>.
1962 // Note: 'master' drawing object *has* to be connected to layout triggered
1963 // by the caller of this, if method is called.
ChangeMasterObject(SdrObject * pNewMaster)1964 void SwDrawContact::ChangeMasterObject(SdrObject* pNewMaster)
1965 {
1966 DisconnectFromLayout( false );
1967 // consider 'virtual' drawing objects
1968 RemoveAllVirtObjs();
1969
1970 GetMaster()->SetUserCall( nullptr );
1971 if(pNewMaster)
1972 maAnchoredDrawObj.SetDrawObj(*pNewMaster);
1973 else
1974 mbMasterObjCleared = true;
1975 GetMaster()->SetUserCall( this );
1976
1977 InvalidateObjs_();
1978 }
1979
1980 /// get data collection of anchored objects, handled by with contact
GetAnchoredObjs(std::vector<SwAnchoredObject * > & o_rAnchoredObjs) const1981 void SwDrawContact::GetAnchoredObjs(std::vector<SwAnchoredObject*>& o_rAnchoredObjs) const
1982 {
1983 o_rAnchoredObjs.push_back(const_cast<SwAnchoredDrawObject*>(&maAnchoredDrawObj));
1984
1985 for(auto& rpDrawVirtObj : maDrawVirtObjs)
1986 o_rAnchoredObjs.push_back(&rpDrawVirtObj->AnchoredObj());
1987 }
1988
1989 // AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed
1990 // since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj.
1991 // For paint, that offset is used by setting at the OutputDevice; for primitives this is
1992 // not possible since we have no OutputDevice, but define the geometry itself.
1993
1994 namespace sdr
1995 {
1996 namespace contact
1997 {
1998 class VOCOfDrawVirtObj : public ViewObjectContactOfSdrObj
1999 {
2000 protected:
2001 /**
2002 * This method is responsible for creating the graphical visualisation data which is
2003 * stored/cached in the local primitive. Default gets view-independent Primitive from
2004 * the ViewContact using ViewContact::getViewIndependentPrimitive2DContainer(), takes
2005 * care of visibility, handles glue and ghosted.
2006 *
2007 * This method will not handle included hierarchies and not check geometric visibility.
2008 */
2009 virtual drawinglayer::primitive2d::Primitive2DContainer createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const override;
2010
2011 public:
VOCOfDrawVirtObj(ObjectContact & rObjectContact,ViewContact & rViewContact)2012 VOCOfDrawVirtObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
2013 : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
2014 {
2015 }
2016 };
2017
2018 class VCOfDrawVirtObj : public ViewContactOfVirtObj
2019 {
2020 protected:
2021 /** Create an Object-Specific ViewObjectContact, set ViewContact and ObjectContact.
2022 *
2023 * Always needs to return something. Default is to create a standard ViewObjectContact
2024 * containing the given ObjectContact and *this.
2025 */
2026 virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
2027
2028 public:
2029 /// basic constructor, used from SdrObject.
VCOfDrawVirtObj(SwDrawVirtObj & rObj)2030 explicit VCOfDrawVirtObj(SwDrawVirtObj& rObj)
2031 : ViewContactOfVirtObj(rObj)
2032 {
2033 }
2034
2035 /// access to SwDrawVirtObj
GetSwDrawVirtObj() const2036 SwDrawVirtObj& GetSwDrawVirtObj() const
2037 {
2038 return static_cast<SwDrawVirtObj&>(mrObject);
2039 }
2040 };
2041 } // end of namespace contact
2042 } // end of namespace sdr
2043
2044 namespace sdr
2045 {
2046 namespace contact
2047 {
2048 /// recursively collect primitive data from given VOC with given offset
impAddPrimitivesFromGroup(const ViewObjectContact & rVOC,const basegfx::B2DHomMatrix & rOffsetMatrix,const DisplayInfo & rDisplayInfo,drawinglayer::primitive2d::Primitive2DContainer & rxTarget)2049 static void impAddPrimitivesFromGroup(const ViewObjectContact& rVOC, const basegfx::B2DHomMatrix& rOffsetMatrix, const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DContainer& rxTarget)
2050 {
2051 const sal_uInt32 nSubHierarchyCount(rVOC.GetViewContact().GetObjectCount());
2052
2053 for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
2054 {
2055 const ViewObjectContact& rCandidate(rVOC.GetViewContact().GetViewContact(a).GetViewObjectContact(rVOC.GetObjectContact()));
2056
2057 if(rCandidate.GetViewContact().GetObjectCount())
2058 {
2059 // is a group object itself, call recursively
2060 impAddPrimitivesFromGroup(rCandidate, rOffsetMatrix, rDisplayInfo, rxTarget);
2061 }
2062 else
2063 {
2064 // single object, add primitives; check model-view visibility
2065 if(rCandidate.isPrimitiveVisible(rDisplayInfo))
2066 {
2067 drawinglayer::primitive2d::Primitive2DContainer aNewSequence(rCandidate.getPrimitive2DSequence(rDisplayInfo));
2068
2069 if(!aNewSequence.empty())
2070 {
2071 // get ranges
2072 const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(rCandidate.GetObjectContact().getViewInformation2D());
2073 const basegfx::B2DRange aViewRange(rViewInformation2D.getViewport());
2074 basegfx::B2DRange aObjectRange(rCandidate.getObjectRange());
2075
2076 // correct with virtual object's offset
2077 aObjectRange.transform(rOffsetMatrix);
2078
2079 // check geometrical visibility (with offset)
2080 if(!aViewRange.overlaps(aObjectRange))
2081 {
2082 // not visible, release
2083 aNewSequence.clear();
2084 }
2085 }
2086
2087 if(!aNewSequence.empty())
2088 {
2089 rxTarget.append(aNewSequence);
2090 }
2091 }
2092 }
2093 }
2094 }
2095
createPrimitive2DSequence(const DisplayInfo & rDisplayInfo) const2096 drawinglayer::primitive2d::Primitive2DContainer VOCOfDrawVirtObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
2097 {
2098 // tdf#91260 have already checked top-level one is on the right page
2099 assert(isPrimitiveVisible(rDisplayInfo));
2100 // nasty corner case: override to clear page frame to disable the
2101 // sub-objects' anchor check, because their anchor is always on
2102 // the first page that the page style is applied to
2103 DisplayInfo aDisplayInfo(rDisplayInfo);
2104 aDisplayInfo.SetWriterPageFrame(basegfx::B2IRectangle());
2105 const VCOfDrawVirtObj& rVC = static_cast< const VCOfDrawVirtObj& >(GetViewContact());
2106 const SdrObject& rReferencedObject = rVC.GetSwDrawVirtObj().GetReferencedObj();
2107 drawinglayer::primitive2d::Primitive2DContainer xRetval;
2108
2109 // create offset transformation
2110 basegfx::B2DHomMatrix aOffsetMatrix;
2111 const Point aLocalOffset(rVC.GetSwDrawVirtObj().GetOffset());
2112
2113 if(aLocalOffset.X() || aLocalOffset.Y())
2114 {
2115 aOffsetMatrix.set(0, 2, aLocalOffset.X());
2116 aOffsetMatrix.set(1, 2, aLocalOffset.Y());
2117 }
2118
2119 if(dynamic_cast<const SdrObjGroup*>( &rReferencedObject) != nullptr)
2120 {
2121 // group object. Since the VOC/OC/VC hierarchy does not represent the
2122 // hierarchy virtual objects when they have group objects
2123 // (ViewContactOfVirtObj::GetObjectCount() returns null for that purpose)
2124 // to avoid multiple usages of VOCs (which would not work), the primitives
2125 // for the sub-hierarchy need to be collected here
2126
2127 // Get the VOC of the referenced object (the Group) and fetch primitives from it
2128 const ViewObjectContact& rVOCOfRefObj = rReferencedObject.GetViewContact().GetViewObjectContact(GetObjectContact());
2129 impAddPrimitivesFromGroup(rVOCOfRefObj, aOffsetMatrix, aDisplayInfo, xRetval);
2130 }
2131 else
2132 {
2133 // single object, use method from referenced object to get the Primitive2DSequence
2134 xRetval = rReferencedObject.GetViewContact().getViewIndependentPrimitive2DContainer();
2135 }
2136
2137 if(!xRetval.empty())
2138 {
2139 // create transform primitive
2140 const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::TransformPrimitive2D(aOffsetMatrix, xRetval));
2141 xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
2142 }
2143
2144 return xRetval;
2145 }
2146
CreateObjectSpecificViewObjectContact(ObjectContact & rObjectContact)2147 ViewObjectContact& VCOfDrawVirtObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
2148 {
2149 return *(new VOCOfDrawVirtObj(rObjectContact, *this));
2150 }
2151
2152 } // end of namespace contact
2153 } // end of namespace sdr
2154
2155 /// implementation of class <SwDrawVirtObj>
CreateObjectSpecificViewContact()2156 std::unique_ptr<sdr::contact::ViewContact> SwDrawVirtObj::CreateObjectSpecificViewContact()
2157 {
2158 return std::make_unique<sdr::contact::VCOfDrawVirtObj>(*this);
2159 }
2160
SwDrawVirtObj(SdrModel & rSdrModel,SdrObject & _rNewObj,SwDrawContact & _rDrawContact)2161 SwDrawVirtObj::SwDrawVirtObj(
2162 SdrModel& rSdrModel,
2163 SdrObject& _rNewObj,
2164 SwDrawContact& _rDrawContact)
2165 : SdrVirtObj(rSdrModel, _rNewObj ),
2166 maAnchoredDrawObj(),
2167 mrDrawContact(_rDrawContact)
2168 {
2169 // #i26791#
2170 maAnchoredDrawObj.SetDrawObj( *this );
2171
2172 // #i35635# - set initial position out of sight
2173 NbcMove( Size( -16000, -16000 ) );
2174 }
2175
~SwDrawVirtObj()2176 SwDrawVirtObj::~SwDrawVirtObj()
2177 {
2178 }
2179
operator =(const SwDrawVirtObj & rObj)2180 SwDrawVirtObj& SwDrawVirtObj::operator=( const SwDrawVirtObj& rObj )
2181 {
2182 SdrVirtObj::operator=(rObj);
2183 // Note: Members <maAnchoredDrawObj> and <mrDrawContact>
2184 // haven't to be considered.
2185 return *this;
2186 }
2187
CloneSdrObject(SdrModel & rTargetModel) const2188 SwDrawVirtObj* SwDrawVirtObj::CloneSdrObject(SdrModel& rTargetModel) const
2189 {
2190 SwDrawVirtObj* pObj = new SwDrawVirtObj(
2191 rTargetModel,
2192 rRefObj,
2193 mrDrawContact);
2194
2195 pObj->operator=( *this );
2196 // Note: Member <maAnchoredDrawObj> hasn't to be considered.
2197
2198 return pObj;
2199 }
2200
GetAnchorFrame() const2201 const SwFrame* SwDrawVirtObj::GetAnchorFrame() const
2202 {
2203 // #i26791# - use new member <maAnchoredDrawObj>
2204 return maAnchoredDrawObj.GetAnchorFrame();
2205 }
2206
AnchorFrame()2207 SwFrame* SwDrawVirtObj::AnchorFrame()
2208 {
2209 // #i26791# - use new member <maAnchoredDrawObj>
2210 return maAnchoredDrawObj.AnchorFrame();
2211 }
2212
RemoveFromWriterLayout()2213 void SwDrawVirtObj::RemoveFromWriterLayout()
2214 {
2215 // remove contact object from frame for 'virtual' drawing object
2216 // #i26791# - use new member <maAnchoredDrawObj>
2217 if ( maAnchoredDrawObj.GetAnchorFrame() )
2218 {
2219 maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
2220 }
2221 }
2222
AddToDrawingPage()2223 void SwDrawVirtObj::AddToDrawingPage()
2224 {
2225 // determine 'master'
2226 SdrObject* pOrgMasterSdrObj = mrDrawContact.GetMaster();
2227
2228 // insert 'virtual' drawing object into page, set layer and user call.
2229 SdrPage* pDrawPg;
2230 // #i27030# - apply order number of referenced object
2231 if ( nullptr != ( pDrawPg = pOrgMasterSdrObj->getSdrPageFromSdrObject() ) )
2232 {
2233 // #i27030# - apply order number of referenced object
2234 pDrawPg->InsertObject( this, GetReferencedObj().GetOrdNum() );
2235 }
2236 else
2237 {
2238 pDrawPg = getSdrPageFromSdrObject();
2239 if ( pDrawPg )
2240 {
2241 pDrawPg->SetObjectOrdNum( GetOrdNumDirect(),
2242 GetReferencedObj().GetOrdNum() );
2243 }
2244 else
2245 {
2246 SetOrdNum( GetReferencedObj().GetOrdNum() );
2247 }
2248 }
2249 SetUserCall( &mrDrawContact );
2250 }
2251
RemoveFromDrawingPage()2252 void SwDrawVirtObj::RemoveFromDrawingPage()
2253 {
2254 SetUserCall( nullptr );
2255 if ( getSdrPageFromSdrObject() )
2256 {
2257 getSdrPageFromSdrObject()->RemoveObject( GetOrdNum() );
2258 }
2259 }
2260
2261 /// Is 'virtual' drawing object connected to writer layout and to drawing layer?
IsConnected() const2262 bool SwDrawVirtObj::IsConnected() const
2263 {
2264 bool bRetVal = GetAnchorFrame() &&
2265 ( getSdrPageFromSdrObject() && GetUserCall() );
2266
2267 return bRetVal;
2268 }
2269
NbcSetAnchorPos(const Point & rPnt)2270 void SwDrawVirtObj::NbcSetAnchorPos(const Point& rPnt)
2271 {
2272 SdrObject::NbcSetAnchorPos( rPnt );
2273 }
2274
2275 // #i97197#
2276 // the methods relevant for positioning
2277
GetCurrentBoundRect() const2278 const tools::Rectangle& SwDrawVirtObj::GetCurrentBoundRect() const
2279 {
2280 if(aOutRect.IsEmpty())
2281 {
2282 const_cast<SwDrawVirtObj*>(this)->RecalcBoundRect();
2283 }
2284
2285 return aOutRect;
2286 }
2287
GetLastBoundRect() const2288 const tools::Rectangle& SwDrawVirtObj::GetLastBoundRect() const
2289 {
2290 return aOutRect;
2291 }
2292
GetOffset() const2293 Point SwDrawVirtObj::GetOffset() const
2294 {
2295 // do NOT use IsEmpty() here, there is already a useful offset
2296 // in the position
2297 if(aOutRect == tools::Rectangle())
2298 {
2299 return Point();
2300 }
2301 else
2302 {
2303 return aOutRect.TopLeft() - GetReferencedObj().GetCurrentBoundRect().TopLeft();
2304 }
2305 }
2306
SetBoundRectDirty()2307 void SwDrawVirtObj::SetBoundRectDirty()
2308 {
2309 // do nothing to not lose model information in aOutRect
2310 }
2311
RecalcBoundRect()2312 void SwDrawVirtObj::RecalcBoundRect()
2313 {
2314 // #i26791# - switch order of calling <GetOffset()> and
2315 // <ReferencedObj().GetCurrentBoundRect()>, because <GetOffset()> calculates
2316 // its value by the 'BoundRect' of the referenced object.
2317
2318 const Point aOffset(GetOffset());
2319 aOutRect = ReferencedObj().GetCurrentBoundRect() + aOffset;
2320 }
2321
TakeXorPoly() const2322 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeXorPoly() const
2323 {
2324 basegfx::B2DPolyPolygon aRetval(rRefObj.TakeXorPoly());
2325 aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2326
2327 return aRetval;
2328 }
2329
TakeContour() const2330 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeContour() const
2331 {
2332 basegfx::B2DPolyPolygon aRetval(rRefObj.TakeContour());
2333 aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2334
2335 return aRetval;
2336 }
2337
AddToHdlList(SdrHdlList & rHdlList) const2338 void SwDrawVirtObj::AddToHdlList(SdrHdlList& rHdlList) const
2339 {
2340 SdrHdlList tmpList(nullptr);
2341 rRefObj.AddToHdlList(tmpList);
2342
2343 size_t cnt = tmpList.GetHdlCount();
2344 for(size_t i=0; i < cnt; ++i)
2345 {
2346 SdrHdl* pHdl = tmpList.GetHdl(i);
2347 Point aP(pHdl->GetPos() + GetOffset());
2348 pHdl->SetPos(aP);
2349 }
2350 tmpList.MoveTo(rHdlList);
2351 }
2352
NbcMove(const Size & rSiz)2353 void SwDrawVirtObj::NbcMove(const Size& rSiz)
2354 {
2355 SdrObject::NbcMove( rSiz );
2356 }
2357
NbcResize(const Point & rRef,const Fraction & xFact,const Fraction & yFact)2358 void SwDrawVirtObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
2359 {
2360 rRefObj.NbcResize(rRef - GetOffset(), xFact, yFact);
2361 SetRectsDirty();
2362 }
2363
NbcRotate(const Point & rRef,long nAngle,double sn,double cs)2364 void SwDrawVirtObj::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
2365 {
2366 rRefObj.NbcRotate(rRef - GetOffset(), nAngle, sn, cs);
2367 SetRectsDirty();
2368 }
2369
NbcMirror(const Point & rRef1,const Point & rRef2)2370 void SwDrawVirtObj::NbcMirror(const Point& rRef1, const Point& rRef2)
2371 {
2372 rRefObj.NbcMirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2373 SetRectsDirty();
2374 }
2375
NbcShear(const Point & rRef,long nAngle,double tn,bool bVShear)2376 void SwDrawVirtObj::NbcShear(const Point& rRef, long nAngle, double tn, bool bVShear)
2377 {
2378 rRefObj.NbcShear(rRef - GetOffset(), nAngle, tn, bVShear);
2379 SetRectsDirty();
2380 }
2381
Move(const Size & rSiz)2382 void SwDrawVirtObj::Move(const Size& rSiz)
2383 {
2384 SdrObject::Move( rSiz );
2385 }
2386
Resize(const Point & rRef,const Fraction & xFact,const Fraction & yFact,bool bUnsetRelative)2387 void SwDrawVirtObj::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
2388 {
2389 if(xFact.GetNumerator() != xFact.GetDenominator() || yFact.GetNumerator() != yFact.GetDenominator())
2390 {
2391 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2392 rRefObj.Resize(rRef - GetOffset(), xFact, yFact, bUnsetRelative);
2393 SetRectsDirty();
2394 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2395 }
2396 }
2397
Rotate(const Point & rRef,long nAngle,double sn,double cs)2398 void SwDrawVirtObj::Rotate(const Point& rRef, long nAngle, double sn, double cs)
2399 {
2400 if(nAngle)
2401 {
2402 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2403 rRefObj.Rotate(rRef - GetOffset(), nAngle, sn, cs);
2404 SetRectsDirty();
2405 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2406 }
2407 }
2408
Mirror(const Point & rRef1,const Point & rRef2)2409 void SwDrawVirtObj::Mirror(const Point& rRef1, const Point& rRef2)
2410 {
2411 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2412 rRefObj.Mirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2413 SetRectsDirty();
2414 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2415 }
2416
Shear(const Point & rRef,long nAngle,double tn,bool bVShear)2417 void SwDrawVirtObj::Shear(const Point& rRef, long nAngle, double tn, bool bVShear)
2418 {
2419 if(nAngle)
2420 {
2421 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2422 rRefObj.Shear(rRef - GetOffset(), nAngle, tn, bVShear);
2423 SetRectsDirty();
2424 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2425 }
2426 }
2427
RecalcSnapRect()2428 void SwDrawVirtObj::RecalcSnapRect()
2429 {
2430 aSnapRect = rRefObj.GetSnapRect();
2431 aSnapRect += GetOffset();
2432 }
2433
GetSnapRect() const2434 const tools::Rectangle& SwDrawVirtObj::GetSnapRect() const
2435 {
2436 const_cast<SwDrawVirtObj*>(this)->aSnapRect = rRefObj.GetSnapRect();
2437 const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
2438
2439 return aSnapRect;
2440 }
2441
SetSnapRect(const tools::Rectangle & rRect)2442 void SwDrawVirtObj::SetSnapRect(const tools::Rectangle& rRect)
2443 {
2444 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2445 tools::Rectangle aR(rRect);
2446 aR -= GetOffset();
2447 rRefObj.SetSnapRect(aR);
2448 SetRectsDirty();
2449 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2450 }
2451
NbcSetSnapRect(const tools::Rectangle & rRect)2452 void SwDrawVirtObj::NbcSetSnapRect(const tools::Rectangle& rRect)
2453 {
2454 tools::Rectangle aR(rRect);
2455 aR -= GetOffset();
2456 SetRectsDirty();
2457 rRefObj.NbcSetSnapRect(aR);
2458 }
2459
GetLogicRect() const2460 const tools::Rectangle& SwDrawVirtObj::GetLogicRect() const
2461 {
2462 const_cast<SwDrawVirtObj*>(this)->aSnapRect = rRefObj.GetLogicRect();
2463 const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
2464
2465 return aSnapRect;
2466 }
2467
SetLogicRect(const tools::Rectangle & rRect)2468 void SwDrawVirtObj::SetLogicRect(const tools::Rectangle& rRect)
2469 {
2470 tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2471 tools::Rectangle aR(rRect);
2472 aR -= GetOffset();
2473 rRefObj.SetLogicRect(aR);
2474 SetRectsDirty();
2475 SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2476 }
2477
NbcSetLogicRect(const tools::Rectangle & rRect)2478 void SwDrawVirtObj::NbcSetLogicRect(const tools::Rectangle& rRect)
2479 {
2480 tools::Rectangle aR(rRect);
2481 aR -= GetOffset();
2482 rRefObj.NbcSetLogicRect(aR);
2483 SetRectsDirty();
2484 }
2485
GetSnapPoint(sal_uInt32 i) const2486 Point SwDrawVirtObj::GetSnapPoint(sal_uInt32 i) const
2487 {
2488 Point aP(rRefObj.GetSnapPoint(i));
2489 aP += GetOffset();
2490
2491 return aP;
2492 }
2493
GetPoint(sal_uInt32 i) const2494 Point SwDrawVirtObj::GetPoint(sal_uInt32 i) const
2495 {
2496 return rRefObj.GetPoint(i) + GetOffset();
2497 }
2498
NbcSetPoint(const Point & rPnt,sal_uInt32 i)2499 void SwDrawVirtObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
2500 {
2501 Point aP(rPnt);
2502 aP -= GetOffset();
2503 rRefObj.SetPoint(aP, i);
2504 SetRectsDirty();
2505 }
2506
HasTextEdit() const2507 bool SwDrawVirtObj::HasTextEdit() const
2508 {
2509 return rRefObj.HasTextEdit();
2510 }
2511
2512 // override 'layer' methods for 'virtual' drawing object to assure
2513 // that layer of 'virtual' object is the layer of the referenced object.
GetLayer() const2514 SdrLayerID SwDrawVirtObj::GetLayer() const
2515 {
2516 return GetReferencedObj().GetLayer();
2517 }
2518
NbcSetLayer(SdrLayerID nLayer)2519 void SwDrawVirtObj::NbcSetLayer(SdrLayerID nLayer)
2520 {
2521 ReferencedObj().NbcSetLayer( nLayer );
2522 SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2523 }
2524
SetLayer(SdrLayerID nLayer)2525 void SwDrawVirtObj::SetLayer(SdrLayerID nLayer)
2526 {
2527 ReferencedObj().SetLayer( nLayer );
2528 SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2529 }
2530
2531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2532