Add a comment to clarify what kind of inputs the class handles
[LibreOffice.git] / sw / source / core / draw / dview.cxx
blobc13daea7e47ae9d3c9cd757646d66eba9828ba14
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 <config_wasm_strip.h>
22 #include <hintids.hxx>
23 #include <svtools/optionsdrawinglayer.hxx>
24 #include <officecfg/Office/Common.hxx>
25 #include <svx/svdpage.hxx>
26 #include <svx/svdpagv.hxx>
27 #include <svx/fmmodel.hxx>
28 #include <sot/exchange.hxx>
29 #include <svx/sdrundomanager.hxx>
30 #include <tools/globname.hxx>
31 #include <editeng/outliner.hxx>
32 #include <osl/diagnose.h>
33 #include <com/sun/star/embed/EmbedMisc.hpp>
34 #include <com/sun/star/embed/XEmbeddedObject.hpp>
35 #include <unotools/configmgr.hxx>
37 #include <pagefrm.hxx>
38 #include <rootfrm.hxx>
39 #include <cntfrm.hxx>
40 #include <notxtfrm.hxx>
41 #include <flyfrm.hxx>
42 #include <frmfmt.hxx>
43 #include <dflyobj.hxx>
44 #include <dcontact.hxx>
45 #include <textboxhelper.hxx>
46 #include <viewsh.hxx>
47 #include <viewimp.hxx>
48 #include <dview.hxx>
49 #include <doc.hxx>
50 #include <mdiexp.hxx>
51 #include <ndole.hxx>
52 #include <ndgrf.hxx>
53 #include <fmtanchr.hxx>
54 #include <IDocumentUndoRedo.hxx>
55 #include <DocumentSettingManager.hxx>
56 #include <IDocumentLayoutAccess.hxx>
58 #include <com/sun/star/embed/Aspects.hpp>
60 #include <vector>
62 #include <sortedobjs.hxx>
64 using namespace com::sun::star;
66 namespace {
68 class SwSdrHdl : public SdrHdl
70 public:
71 SwSdrHdl(const Point& rPnt, bool bTopRight ) :
72 SdrHdl( rPnt, bTopRight ? SdrHdlKind::Anchor_TR : SdrHdlKind::Anchor ) {}
73 virtual bool IsFocusHdl() const override;
78 bool SwSdrHdl::IsFocusHdl() const
80 if( SdrHdlKind::Anchor == m_eKind || SdrHdlKind::Anchor_TR == m_eKind )
81 return true;
82 return SdrHdl::IsFocusHdl();
85 static const SwFrame *lcl_FindAnchor( const SdrObject *pObj, bool bAll )
87 const SwVirtFlyDrawObj *pVirt = dynamic_cast< const SwVirtFlyDrawObj *>( pObj );
88 if ( pVirt )
90 if ( bAll || !pVirt->GetFlyFrame()->IsFlyInContentFrame() )
91 return pVirt->GetFlyFrame()->GetAnchorFrame();
93 else
95 const SwDrawContact *pCont = static_cast<const SwDrawContact*>(GetUserCall(pObj));
96 if ( pCont )
97 return pCont->GetAnchorFrame( pObj );
99 return nullptr;
102 SwDrawView::SwDrawView(
103 SwViewShellImp& rI,
104 FmFormModel& rFmFormModel,
105 OutputDevice* pOutDev)
106 : FmFormView(rFmFormModel, pOutDev),
107 m_rImp( rI )
109 SetPageVisible( false );
110 SetBordVisible( false );
111 SetGridVisible( false );
112 SetHlplVisible( false );
113 SetGlueVisible( false );
114 SetFrameDragSingles();
115 SetSwapAsynchron();
117 EnableExtendedKeyInputDispatcher( false );
118 EnableExtendedMouseEventDispatcher( false );
120 SetHitTolerancePixel( GetMarkHdlSizePixel()/2 );
122 SetPrintPreview( rI.GetShell()->IsPreview() );
124 // #i73602# Use default from the configuration
125 SetBufferedOverlayAllowed(!comphelper::IsFuzzing() && officecfg::Office::Common::Drawinglayer::OverlayBuffer_Writer::get());
127 // #i74769#, #i75172# Use default from the configuration
128 SetBufferedOutputAllowed(!comphelper::IsFuzzing() && officecfg::Office::Common::Drawinglayer::OverlayBuffer_DrawImpress::get());
131 // #i99665#
132 bool SwDrawView::IsAntiAliasing()
134 return SvtOptionsDrawinglayer::IsAntiAliasing();
137 static SdrObject* impLocalHitCorrection(SdrObject* pRetval, const Point& rPnt, sal_uInt16 nTol, const SdrMarkList &rMrkList)
139 if(!nTol)
141 // the old method forced back to outer bounds test when nTol == 0, so
142 // do not try to correct when nTol is not set (used from HelpContent)
144 else
146 // rebuild logic from former SwVirtFlyDrawObj::CheckSdrObjectHit. This is needed since
147 // the SdrObject-specific CheckHit implementations are now replaced with primitives and
148 // 'tricks' like in the old implementation (e.g. using a view from a model-data class to
149 // detect if object is selected) are no longer valid.
150 // The standard primitive hit-test for SwVirtFlyDrawObj now is the outer bound. The old
151 // implementation reduced this excluding the inner bound when the object was not selected.
152 SwVirtFlyDrawObj* pSwVirtFlyDrawObj = dynamic_cast< SwVirtFlyDrawObj* >(pRetval);
154 if(pSwVirtFlyDrawObj)
156 SwFrame* pLower = pSwVirtFlyDrawObj->GetFlyFrame()->Lower();
157 if(pLower && pLower->IsNoTextFrame())
159 // the old method used IsNoTextFrame (should be for SW's own OLE and
160 // graphic's) to accept hit only based on outer bounds; nothing to do
162 else
164 // check if the object is selected in this view
165 const size_t nMarkCount(rMrkList.GetMarkCount());
166 bool bSelected(false);
168 for(size_t a = 0; !bSelected && a < nMarkCount; ++a)
170 if(pSwVirtFlyDrawObj == rMrkList.GetMark(a)->GetMarkedSdrObj())
172 bSelected = true;
176 if(!bSelected)
178 // when not selected, the object is not hit when hit position is inside
179 // inner range. Get and shrink inner range
180 basegfx::B2DRange aInnerBound(pSwVirtFlyDrawObj->getInnerBound());
182 aInnerBound.grow(-1.0 * nTol);
184 if(aInnerBound.isInside(basegfx::B2DPoint(rPnt.X(), rPnt.Y())))
186 // exclude this hit
187 pRetval = nullptr;
194 return pRetval;
197 SdrObject* SwDrawView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const
199 // call parent
200 SdrObject* pRetval = FmFormView::CheckSingleSdrObjectHit(rPnt, nTol, pObj, pPV, nOptions, pMVisLay);
202 if(pRetval)
204 // override to allow extra handling when picking SwVirtFlyDrawObj's
205 pRetval = impLocalHitCorrection(pRetval, rPnt, nTol, GetMarkedObjectList());
208 return pRetval;
211 /// Gets called every time the handles need to be build
212 void SwDrawView::AddCustomHdl()
214 const SdrMarkList &rMrkList = GetMarkedObjectList();
216 if(rMrkList.GetMarkCount() != 1)
217 return;
219 SdrObject *pObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
220 SwContact* pContact = ::GetUserCall( pObj );
221 if (!pContact)
222 return;
224 // make code robust
225 SwFrameFormat* pFrameFormat( ::FindFrameFormat( pObj ) );
226 if ( !pFrameFormat )
228 OSL_FAIL( "<SwDrawView::AddCustomHdl()> - missing frame format!" );
229 return;
231 const SwFormatAnchor &rAnchor = pFrameFormat->GetAnchor();
233 if (RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId())
234 return;
236 const SwFrame* pAnch = CalcAnchor();
237 if(nullptr == pAnch)
238 return;
240 Point aPos(m_aAnchorPoint);
242 if ( RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId() )
244 // #i28701# - use last character rectangle saved at object
245 // in order to avoid a format of the anchor frame
246 SwAnchoredObject* pAnchoredObj = pContact->GetAnchoredObj( pObj );
248 // Invalidate/recalc LastCharRect which can contain invalid frame offset because
249 // of later frame changes
250 pAnchoredObj->CheckCharRectAndTopOfLine(false);
252 SwRect aAutoPos = pAnchoredObj->GetLastCharRect();
253 if ( aAutoPos.Height() )
255 aPos = aAutoPos.Pos();
259 // add anchor handle:
260 std::unique_ptr<SdrHdl> hdl = std::make_unique<SwSdrHdl>( aPos, ( pAnch->IsVertical() && !pAnch->IsVertLR() ) ||
261 pAnch->IsRightToLeft() );
262 hdl->SetObjHdlNum(maHdlList.GetHdlCount());
263 maHdlList.AddHdl(std::move(hdl));
266 SdrObject* SwDrawView::GetMaxToTopObj( SdrObject* pObj ) const
268 if ( GetUserCall(pObj) )
270 const SwFrame *pAnch = ::lcl_FindAnchor( pObj, false );
271 if ( pAnch )
273 //The topmost Obj within the anchor must not be overtaken.
274 const SwFlyFrame *pFly = pAnch->FindFlyFrame();
275 if ( pFly )
277 const SwPageFrame *pPage = pFly->FindPageFrame();
278 if ( pPage->GetSortedObjs() )
280 size_t nOrdNum = 0;
281 for (SwAnchoredObject* i : *pPage->GetSortedObjs())
283 const SdrObject *pO = i->GetDrawObj();
285 if ( pO->GetOrdNumDirect() > nOrdNum )
287 const SwFrame *pTmpAnch = ::lcl_FindAnchor( pO, false );
288 if ( pFly->IsAnLower( pTmpAnch ) )
290 nOrdNum = pO->GetOrdNumDirect();
294 if ( nOrdNum )
296 SdrPage *pTmpPage = GetModel().GetPage( 0 );
297 ++nOrdNum;
298 if ( nOrdNum < pTmpPage->GetObjCount() )
300 return pTmpPage->GetObj( nOrdNum );
307 return nullptr;
310 SdrObject* SwDrawView::GetMaxToBtmObj(SdrObject* pObj) const
312 if ( GetUserCall(pObj) )
314 const SwFrame *pAnch = ::lcl_FindAnchor( pObj, false );
315 if ( pAnch )
317 //The Fly of the anchor must not be "flying under".
318 const SwFlyFrame *pFly = pAnch->FindFlyFrame();
319 if ( pFly )
321 SdrObject *pRet = const_cast<SdrObject*>(static_cast<SdrObject const *>(pFly->GetVirtDrawObj()));
322 return pRet != pObj ? pRet : nullptr;
326 return nullptr;
329 /// determine maximal order number for a 'child' object of given 'parent' object
330 sal_uInt32 SwDrawView::GetMaxChildOrdNum( const SwFlyFrame& _rParentObj,
331 const SdrObject* _pExclChildObj )
333 sal_uInt32 nMaxChildOrdNum = _rParentObj.GetDrawObj()->GetOrdNum();
335 const SdrPage* pDrawPage = _rParentObj.GetDrawObj()->getSdrPageFromSdrObject();
336 assert(pDrawPage && "<SwDrawView::GetMaxChildOrdNum(..) - missing drawing page at parent object - crash!");
338 const size_t nObjCount = pDrawPage->GetObjCount();
339 for ( size_t i = nObjCount-1; i > _rParentObj.GetDrawObj()->GetOrdNum() ; --i )
341 const SdrObject* pObj = pDrawPage->GetObj( i );
343 // Don't consider 'child' object <_pExclChildObj>
344 if ( pObj == _pExclChildObj )
346 continue;
349 if ( pObj->GetOrdNum() > nMaxChildOrdNum &&
350 _rParentObj.IsAnLower( lcl_FindAnchor( pObj, true ) ) )
352 nMaxChildOrdNum = pObj->GetOrdNum();
353 break;
357 return nMaxChildOrdNum;
360 /// method to move 'repeated' objects of the given moved object to the according level
361 void SwDrawView::MoveRepeatedObjs( const SwAnchoredObject& _rMovedAnchoredObj,
362 const std::vector<SdrObject*>& _rMovedChildObjs ) const
364 // determine 'repeated' objects of already moved object <_rMovedAnchoredObj>
365 std::vector<SwAnchoredObject*> aAnchoredObjs;
367 const SwContact* pContact = ::GetUserCall( _rMovedAnchoredObj.GetDrawObj() );
368 assert(pContact && "SwDrawView::MoveRepeatedObjs(..) - missing contact object -> crash.");
369 if (pContact)
370 pContact->GetAnchoredObjs( aAnchoredObjs );
373 // check, if 'repeated' objects exists.
374 if ( aAnchoredObjs.size() <= 1 )
375 return;
377 SdrPage* pDrawPage = GetModel().GetPage( 0 );
379 // move 'repeated' ones to the same order number as the already moved one.
380 const size_t nNewPos = _rMovedAnchoredObj.GetDrawObj()->GetOrdNum();
381 while ( !aAnchoredObjs.empty() )
383 SwAnchoredObject* pAnchoredObj = aAnchoredObjs.back();
384 if ( pAnchoredObj != &_rMovedAnchoredObj )
386 pDrawPage->SetObjectOrdNum( pAnchoredObj->GetDrawObj()->GetOrdNum(),
387 nNewPos );
388 pDrawPage->RecalcObjOrdNums();
389 // adjustments for accessibility API
390 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
391 if ( auto pTmpFlyFrame = pAnchoredObj->DynCastFlyFrame() )
393 m_rImp.DisposeAccessibleFrame( pTmpFlyFrame );
394 m_rImp.AddAccessibleFrame( pTmpFlyFrame );
396 else
398 m_rImp.DisposeAccessibleObj(pAnchoredObj->GetDrawObj(), true);
399 m_rImp.AddAccessibleObj( pAnchoredObj->GetDrawObj() );
401 #endif
403 aAnchoredObjs.pop_back();
406 // move 'repeated' ones of 'child' objects
407 for ( SdrObject* pChildObj : _rMovedChildObjs )
410 const SwContact* pContact = ::GetUserCall( pChildObj );
411 assert(pContact && "SwDrawView::MoveRepeatedObjs(..) - missing contact object -> crash.");
412 if (pContact)
413 pContact->GetAnchoredObjs( aAnchoredObjs );
415 // move 'repeated' ones to the same order number as the already moved one.
416 const size_t nTmpNewPos = pChildObj->GetOrdNum();
417 while ( !aAnchoredObjs.empty() )
419 SwAnchoredObject* pAnchoredObj = aAnchoredObjs.back();
420 if ( pAnchoredObj->GetDrawObj() != pChildObj )
422 pDrawPage->SetObjectOrdNum( pAnchoredObj->GetDrawObj()->GetOrdNum(),
423 nTmpNewPos );
424 pDrawPage->RecalcObjOrdNums();
425 // adjustments for accessibility API
426 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
427 if ( auto pTmpFlyFrame = pAnchoredObj->DynCastFlyFrame() )
429 m_rImp.DisposeAccessibleFrame( pTmpFlyFrame );
430 m_rImp.AddAccessibleFrame( pTmpFlyFrame );
432 else
434 m_rImp.DisposeAccessibleObj(pAnchoredObj->GetDrawObj(), true);
435 m_rImp.AddAccessibleObj( pAnchoredObj->GetDrawObj() );
437 #endif
439 aAnchoredObjs.pop_back();
444 // --> adjustment and re-factoring of method
445 void SwDrawView::ObjOrderChanged( SdrObject* pObj, size_t nOldPos,
446 size_t nNewPos )
448 // nothing to do for group members
449 if ( pObj->getParentSdrObjectFromSdrObject() )
451 return;
454 // determine drawing page and assure that the order numbers are correct.
455 SdrPage* pDrawPage = GetModel().GetPage( 0 );
456 if ( pDrawPage->IsObjOrdNumsDirty() )
457 pDrawPage->RecalcObjOrdNums();
458 const size_t nObjCount = pDrawPage->GetObjCount();
460 SwContact* pContact = ::GetUserCall( pObj );
461 if (!pContact)
462 return;
464 SwAnchoredObject* pMovedAnchoredObj = pContact->GetAnchoredObj( pObj );
465 const SwFlyFrame* pParentAnchoredObj =
466 pMovedAnchoredObj->GetAnchorFrame()->FindFlyFrame();
468 const bool bMovedForward = nOldPos < nNewPos;
470 // assure for a 'child' object, that it doesn't exceed the limits of its 'parent'
471 if ( pParentAnchoredObj )
473 if ( bMovedForward )
475 const size_t nMaxChildOrdNumWithoutMoved =
476 GetMaxChildOrdNum( *pParentAnchoredObj, pMovedAnchoredObj->GetDrawObj() );
477 if ( nNewPos > nMaxChildOrdNumWithoutMoved+1 )
479 // set position to the top of the 'child' object group
480 pDrawPage->SetObjectOrdNum( nNewPos, nMaxChildOrdNumWithoutMoved+1 );
481 nNewPos = nMaxChildOrdNumWithoutMoved+1;
484 else
486 const size_t nParentOrdNum = pParentAnchoredObj->GetDrawObj()->GetOrdNum();
487 if ( nNewPos < nParentOrdNum )
489 // set position to the bottom of the 'child' object group
490 pDrawPage->SetObjectOrdNum( nNewPos, nParentOrdNum );
491 nNewPos = nParentOrdNum;
494 if ( pDrawPage->IsObjOrdNumsDirty() )
495 pDrawPage->RecalcObjOrdNums();
498 // Assure, that object isn't positioned between 'repeated' ones
499 if ( ( bMovedForward && nNewPos < nObjCount - 1 ) ||
500 ( !bMovedForward && nNewPos > 0 ) )
502 const SdrObject* pTmpObj =
503 pDrawPage->GetObj( bMovedForward ? nNewPos - 1 : nNewPos + 1 );
504 if ( pTmpObj )
506 size_t nTmpNewPos( nNewPos );
507 if (const SwContact* pContact2 = ::GetUserCall( pTmpObj ))
509 if ( bMovedForward )
511 // move before the top 'repeated' object
512 const sal_uInt32 nTmpMaxOrdNum = pContact2->GetMaxOrdNum();
513 if ( nTmpMaxOrdNum > nNewPos )
514 nTmpNewPos = nTmpMaxOrdNum;
516 else
518 // move behind the bottom 'repeated' object
519 const sal_uInt32 nTmpMinOrdNum = pContact2->GetMinOrdNum();
520 if ( nTmpMinOrdNum < nNewPos )
521 nTmpNewPos = nTmpMinOrdNum;
524 if ( nTmpNewPos != nNewPos )
526 pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
527 nNewPos = nTmpNewPos;
528 pDrawPage->RecalcObjOrdNums();
533 // On move forward, assure that object is moved before its own children.
534 // Only Writer fly frames can have children.
535 if ( pMovedAnchoredObj->DynCastFlyFrame() &&
536 bMovedForward && nNewPos < nObjCount - 1 )
538 sal_uInt32 nMaxChildOrdNum =
539 GetMaxChildOrdNum( *static_cast<const SwFlyFrame*>(pMovedAnchoredObj) );
540 if ( nNewPos < nMaxChildOrdNum )
542 // determine position before the object before its top 'child' object
543 const SdrObject* pTmpObj = pDrawPage->GetObj( nMaxChildOrdNum );
544 if (SwContact* pContact2 = ::GetUserCall( pTmpObj ))
546 size_t nTmpNewPos = pContact2->GetMaxOrdNum() + 1;
547 if ( nTmpNewPos >= nObjCount )
549 --nTmpNewPos;
551 // assure, that determined position isn't between 'repeated' objects
552 pTmpObj = pDrawPage->GetObj( nTmpNewPos );
553 pContact2 = ::GetUserCall( pTmpObj );
554 if (pContact2)
556 nTmpNewPos = pContact2->GetMaxOrdNum();
557 // apply new position
558 pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
559 nNewPos = nTmpNewPos;
560 pDrawPage->RecalcObjOrdNums();
566 // Assure, that object isn't positioned between nested objects
567 if ( ( bMovedForward && nNewPos < nObjCount - 1 ) ||
568 ( !bMovedForward && nNewPos > 0 ) )
570 size_t nTmpNewPos( nNewPos );
571 const SwFrameFormat* pParentFrameFormat =
572 pParentAnchoredObj ? pParentAnchoredObj->GetFrameFormat() : nullptr;
573 const SdrObject* pTmpObj = pDrawPage->GetObj( nNewPos + 1 );
574 while ( pTmpObj )
576 // #i38563# - assure, that anchor frame exists.
577 // If object is anchored inside an invisible part of the document
578 // (e.g. page header, whose page style isn't applied, or hidden
579 // section), no anchor frame exists.
580 const SwFrame* pTmpAnchorFrame = lcl_FindAnchor( pTmpObj, true );
581 const SwFlyFrame* pTmpParentObj = pTmpAnchorFrame
582 ? pTmpAnchorFrame->FindFlyFrame() : nullptr;
583 if ( pTmpParentObj &&
584 pTmpParentObj->GetFrameFormat() != pParentFrameFormat )
586 if (const SwContact* pContact2 = ::GetUserCall( pTmpObj ))
588 if ( bMovedForward )
590 nTmpNewPos = pContact2->GetMaxOrdNum();
591 pTmpObj = pDrawPage->GetObj( nTmpNewPos + 1 );
593 else
595 nTmpNewPos = pContact2->GetMinOrdNum();
596 pTmpObj = pTmpParentObj->GetDrawObj();
600 else
601 break;
603 if ( nTmpNewPos != nNewPos )
605 pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
606 nNewPos = nTmpNewPos;
607 pDrawPage->RecalcObjOrdNums();
611 // setup collection of moved 'child' objects to move its 'repeated' objects.
612 std::vector< SdrObject* > aMovedChildObjs;
614 // move 'children' accordingly
615 if ( auto pFlyFrame = pMovedAnchoredObj->DynCastFlyFrame() )
617 // adjustments for accessibility API
618 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
619 m_rImp.DisposeAccessibleFrame( pFlyFrame );
620 m_rImp.AddAccessibleFrame( pFlyFrame );
621 #endif
623 const sal_uInt32 nChildNewPos = bMovedForward ? nNewPos : nNewPos+1;
624 size_t i = bMovedForward ? nOldPos : nObjCount-1;
627 SdrObject* pTmpObj = pDrawPage->GetObj( i );
628 if ( pTmpObj == pObj )
629 break;
631 // #i38563# - assure, that anchor frame exists.
632 // If object is anchored inside an invisible part of the document
633 // (e.g. page header, whose page style isn't applied, or hidden
634 // section), no anchor frame exists.
635 const SwFrame* pTmpAnchorFrame = lcl_FindAnchor( pTmpObj, true );
636 const SwFlyFrame* pTmpParentObj = pTmpAnchorFrame
637 ? pTmpAnchorFrame->FindFlyFrame() : nullptr;
638 if ( pTmpParentObj &&
639 ( ( pTmpParentObj == pFlyFrame ) ||
640 ( pFlyFrame->IsUpperOf( *pTmpParentObj ) ) ) )
642 // move child object.,
643 pDrawPage->SetObjectOrdNum( i, nChildNewPos );
644 pDrawPage->RecalcObjOrdNums();
645 // collect 'child' object
646 aMovedChildObjs.push_back( pTmpObj );
647 // adjustments for accessibility API
648 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
649 if ( auto pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj *>( pTmpObj ) )
651 const SwFlyFrame *pTmpFlyFrame = pFlyDrawObj->GetFlyFrame();
652 m_rImp.DisposeAccessibleFrame( pTmpFlyFrame );
653 m_rImp.AddAccessibleFrame( pTmpFlyFrame );
655 else
657 m_rImp.DisposeAccessibleObj(pTmpObj, true);
658 m_rImp.AddAccessibleObj( pTmpObj );
660 #endif
662 else
664 // adjust loop counter
665 if ( bMovedForward )
666 ++i;
667 else if (i > 0)
668 --i;
671 } while ( ( bMovedForward && i < ( nObjCount - aMovedChildObjs.size() ) ) ||
672 ( !bMovedForward && i > ( nNewPos + aMovedChildObjs.size() ) ) );
674 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
675 else
677 // adjustments for accessibility API
678 m_rImp.DisposeAccessibleObj(pObj, true);
679 m_rImp.AddAccessibleObj( pObj );
681 #endif
683 MoveRepeatedObjs( *pMovedAnchoredObj, aMovedChildObjs );
686 bool SwDrawView::TakeDragLimit( SdrDragMode eMode,
687 tools::Rectangle& rRect ) const
689 const SdrMarkList &rMrkList = GetMarkedObjectList();
690 bool bRet = false;
691 if( 1 == rMrkList.GetMarkCount() )
693 const SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
694 SwRect aRect;
695 if( ::CalcClipRect( pObj, aRect, eMode == SdrDragMode::Move ) )
697 rRect = aRect.SVRect();
698 bRet = true;
701 return bRet;
704 const SwFrame* SwDrawView::CalcAnchor()
706 const SdrMarkList &rMrkList = GetMarkedObjectList();
707 if ( rMrkList.GetMarkCount() != 1 )
708 return nullptr;
710 SdrObject* pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
712 //Search for paragraph bound objects, otherwise only the
713 //current anchor. Search only if we currently drag.
714 const SwFrame* pAnch = nullptr;
715 tools::Rectangle aMyRect;
716 auto pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj *>( pObj );
717 if ( pFlyDrawObj )
719 pAnch = pFlyDrawObj->GetFlyFrame()->GetAnchorFrame();
720 aMyRect = pFlyDrawObj->GetFlyFrame()->getFrameArea().SVRect();
722 else
724 // determine correct anchor position for 'virtual' drawing objects.
725 // #i26791#
726 if (SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj)))
728 pAnch = pContact->GetAnchorFrame( pObj );
729 if( !pAnch )
731 pContact->ConnectToLayout();
732 // determine correct anchor position for 'virtual' drawing objects.
733 // #i26791#
734 pAnch = pContact->GetAnchorFrame( pObj );
737 aMyRect = pObj->GetSnapRect();
740 const bool bTopRight = pAnch && ( ( pAnch->IsVertical() &&
741 !pAnch->IsVertLR() ) ||
742 pAnch->IsRightToLeft() );
743 const Point aMyPt = bTopRight ? aMyRect.TopRight() : aMyRect.TopLeft();
745 Point aPt;
746 if ( IsAction() )
748 if ( !TakeDragObjAnchorPos( aPt, bTopRight ) )
749 return nullptr;
751 else
753 tools::Rectangle aRect = pObj->GetSnapRect();
754 aPt = bTopRight ? aRect.TopRight() : aRect.TopLeft();
757 if ( aPt != aMyPt )
759 if ( pAnch && pAnch->IsContentFrame() )
761 // allow drawing objects in header/footer,
762 // but exclude control objects.
763 bool bBodyOnly = CheckControlLayer( pObj );
764 pAnch = ::FindAnchor( static_cast<const SwContentFrame*>(pAnch), aPt, bBodyOnly );
766 else if ( !pFlyDrawObj )
768 const SwRect aRect( aPt.getX(), aPt.getY(), 1, 1 );
770 if (SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj)))
772 if ( pContact->GetAnchorFrame( pObj ) &&
773 pContact->GetAnchorFrame( pObj )->IsPageFrame() )
774 pAnch = pContact->GetPageFrame();
775 else
776 pAnch = pContact->FindPage( aRect );
780 if( pAnch && !pAnch->IsProtected() )
781 m_aAnchorPoint = pAnch->GetFrameAnchorPos( ::HasWrap( pObj ) );
782 else
783 pAnch = nullptr;
784 return pAnch;
787 void SwDrawView::ShowDragAnchor()
789 SdrHdl* pHdl = maHdlList.GetHdl(SdrHdlKind::Anchor);
790 if ( ! pHdl )
791 pHdl = maHdlList.GetHdl(SdrHdlKind::Anchor_TR);
793 if(pHdl)
795 CalcAnchor();
796 pHdl->SetPos(m_aAnchorPoint);
800 void SwDrawView::MarkListHasChanged()
802 Imp().GetShell()->DrawSelChanged();
803 FmFormView::MarkListHasChanged();
806 // #i7672#
807 void SwDrawView::ModelHasChanged()
809 // The ModelHasChanged() call in DrawingLayer also updates
810 // an eventually active text edit view (OutlinerView). This also leads
811 // to newly setting the background color for that edit view. Thus,
812 // this method rescues the current background color if an OutlinerView
813 // exists and re-establishes it then. To be more safe, the OutlinerView
814 // will be fetched again (maybe textedit has ended).
815 OutlinerView* pView = GetTextEditOutlinerView();
816 Color aBackColor;
817 bool bColorWasSaved(false);
819 if(pView)
821 aBackColor = pView->GetBackgroundColor();
822 bColorWasSaved = true;
825 // call parent
826 FmFormView::ModelHasChanged();
828 if(bColorWasSaved)
830 pView = GetTextEditOutlinerView();
832 if(pView)
834 pView->SetBackgroundColor(aBackColor);
839 void SwDrawView::MakeVisible( const tools::Rectangle &rRect, vcl::Window & )
841 OSL_ENSURE( m_rImp.GetShell()->GetWin(), "MakeVisible, unknown Window");
842 m_rImp.GetShell()->MakeVisible( SwRect( rRect ) );
845 void SwDrawView::CheckPossibilities()
847 FmFormView::CheckPossibilities();
849 //In addition to the existing flags of the objects themselves,
850 //which are evaluated by the DrawingEngine, other circumstances
851 //lead to a protection.
852 //Objects that are anchored in frames need to be protected
853 //if the content of the frame is protected.
854 //OLE-Objects may themselves wish a resize protection (StarMath)
856 const SdrMarkList &rMrkList = GetMarkedObjectList();
857 bool bProtect = false;
858 bool bSzProtect = false;
859 bool bRotate(false);
861 for ( size_t i = 0; !bProtect && i < rMrkList.GetMarkCount(); ++i )
863 const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
864 const SwFrame *pFrame = nullptr;
865 if ( auto pVirtFlyDrawObj = dynamic_cast< const SwVirtFlyDrawObj *>( pObj ) )
867 const SwFlyFrame *pFly = pVirtFlyDrawObj->GetFlyFrame();
868 if ( pFly )
870 pFrame = pFly->GetAnchorFrame();
871 const SwFrame* pLower = pFly->Lower();
872 if ( pLower && pLower->IsNoTextFrame() )
874 const SwNoTextFrame *const pNTF(static_cast<const SwNoTextFrame*>(pLower));
875 const SwOLENode *const pOLENd = pNTF->GetNode()->GetOLENode();
876 const SwGrfNode *const pGrfNd = pNTF->GetNode()->GetGrfNode();
878 if ( pOLENd )
880 const uno::Reference < embed::XEmbeddedObject > xObj = const_cast< SwOLEObj& >(pOLENd->GetOLEObj()).GetOleRef();
882 if ( xObj.is() )
884 // --> improvement for the future, when more
885 // than one Writer fly frame can be selected.
887 // TODO/LATER: retrieve Aspect - from where?!
888 bSzProtect |= ( embed::EmbedMisc::EMBED_NEVERRESIZE & xObj->getStatus( embed::Aspects::MSOLE_CONTENT ) ) != 0;
890 // #i972: protect position if it is a Math object anchored 'as char' and baseline alignment is activated
891 SwDoc* pDoc = Imp().GetShell()->GetDoc();
892 const bool bProtectMathPos = SotExchange::IsMath( xObj->getClassID() )
893 && RndStdIds::FLY_AS_CHAR == pFly->GetFormat()->GetAnchor().GetAnchorId()
894 && pDoc->GetDocumentSettingManager().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT );
895 if (bProtectMathPos)
896 m_bMoveProtect = true;
899 else if(pGrfNd)
901 // RotGrfFlyFrame: GraphicNode allows rotation(s). The loop ew are in stops
902 // as soon as bMoveProtect is set, but since rotation is valid only with
903 // a single object selected this makes no difference
904 bRotate = true;
909 else
911 SwDrawContact *pC = static_cast<SwDrawContact*>(GetUserCall(pObj));
912 if ( pC )
913 pFrame = pC->GetAnchorFrame( pObj );
915 if ( pFrame )
916 bProtect = pFrame->IsProtected(); //Frames, areas etc.
918 SwFrameFormat* pFrameFormat( ::FindFrameFormat( const_cast<SdrObject*>(pObj) ) );
919 if ( !pFrameFormat )
921 OSL_FAIL( "<SwDrawView::CheckPossibilities()> - missing frame format" );
922 bProtect = true;
924 else if ((RndStdIds::FLY_AS_CHAR == pFrameFormat->GetAnchor().GetAnchorId()) &&
925 rMrkList.GetMarkCount() > 1 )
927 bProtect = true;
931 m_bMoveProtect |= bProtect;
932 m_bResizeProtect |= bProtect || bSzProtect;
934 // RotGrfFlyFrame: allow rotation when SwGrfNode is selected and not size protected
935 m_bRotateFreeAllowed |= bRotate && !bProtect;
936 m_bRotate90Allowed |= m_bRotateFreeAllowed;
939 /// replace marked <SwDrawVirtObj>-objects by its reference object for delete marked objects.
940 void SwDrawView::ReplaceMarkedDrawVirtObjs( SdrMarkView& _rMarkView )
942 SdrPageView* pDrawPageView = _rMarkView.GetSdrPageView();
943 const SdrMarkList& rMarkList = _rMarkView.GetMarkedObjectList();
945 if( !rMarkList.GetMarkCount() )
946 return;
948 // collect marked objects in a local data structure
949 std::vector<SdrObject*> aMarkedObjs;
950 for( size_t i = 0; i < rMarkList.GetMarkCount(); ++i )
952 SdrObject* pMarkedObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
953 aMarkedObjs.push_back( pMarkedObj );
955 // unmark all objects
956 _rMarkView.UnmarkAllObj();
957 // re-mark objects, but for marked <SwDrawVirtObj>-objects marked its
958 // reference object.
959 while ( !aMarkedObjs.empty() )
961 SdrObject* pMarkObj = aMarkedObjs.back();
962 if ( auto pVirtObj = dynamic_cast<SwDrawVirtObj *>( pMarkObj ) )
964 SdrObject* pRefObj = &(pVirtObj->ReferencedObj());
965 if ( !_rMarkView.IsObjMarked( pRefObj ) )
967 _rMarkView.MarkObj( pRefObj, pDrawPageView );
970 else
972 _rMarkView.MarkObj( pMarkObj, pDrawPageView );
975 aMarkedObjs.pop_back();
977 // sort marked list in order to assure consistent state in drawing layer
978 _rMarkView.GetMarkedObjectList().ForceSort();
981 SfxViewShell* SwDrawView::GetSfxViewShell() const
983 return m_rImp.GetShell()->GetSfxViewShell();
986 void SwDrawView::DeleteMarked()
988 SwDoc* pDoc = Imp().GetShell()->GetDoc();
989 SwRootFrame *pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
990 if ( pTmpRoot )
991 pTmpRoot->StartAllAction();
992 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
993 // replace marked <SwDrawVirtObj>-objects by its reference objects.
994 if (SdrPageView* pDrawPageView = m_rImp.GetPageView())
996 ReplaceMarkedDrawVirtObjs(pDrawPageView->GetView());
999 // Check what textboxes have to be deleted afterwards.
1000 const SdrMarkList& rMarkList = GetMarkedObjectList();
1001 std::vector<SwFrameFormat*> aTextBoxesToDelete;
1002 for (size_t i = 0; i < rMarkList.GetMarkCount(); ++i)
1004 SdrObject *pObject = rMarkList.GetMark(i)->GetMarkedSdrObj();
1005 SwContact* pContact = GetUserCall(pObject);
1006 if (pContact)
1008 SwFrameFormat* pFormat = pContact->GetFormat();
1009 if (pObject->getChildrenOfSdrObject())
1011 auto pChildTextBoxes = SwTextBoxHelper::CollectTextBoxes(pObject, pFormat);
1012 for (auto& rChildTextBox : pChildTextBoxes)
1013 aTextBoxesToDelete.push_back(rChildTextBox);
1015 else if (SwFrameFormat* pTextBox
1016 = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
1017 aTextBoxesToDelete.push_back(pTextBox);
1021 if ( pDoc->DeleteSelection( *this ) )
1023 FmFormView::DeleteMarked();
1024 ::FrameNotify( Imp().GetShell(), FLY_DRAG_END );
1027 // Only delete these now: earlier deletion would clear the mark list as well.
1028 // Delete in reverse order, assuming that the container is sorted by anchor positions.
1029 for (int i = aTextBoxesToDelete.size() - 1; i >= 0; --i)
1031 SwFrameFormat*& rpTextBox = aTextBoxesToDelete[i];
1032 pDoc->getIDocumentLayoutAccess().DelLayoutFormat(rpTextBox);
1035 pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
1036 if( pTmpRoot )
1037 pTmpRoot->EndAllAction();
1040 // Create a new view-local UndoManager manager for Writer
1041 std::unique_ptr<SdrUndoManager> SwDrawView::createLocalTextUndoManager()
1043 std::unique_ptr<SdrUndoManager> pUndoManager(new SdrUndoManager);
1044 pUndoManager->SetDocShell(SfxObjectShell::Current());
1045 return pUndoManager;
1048 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */