1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
40 #include <notxtfrm.hxx>
43 #include <dflyobj.hxx>
44 #include <dcontact.hxx>
45 #include <textboxhelper.hxx>
47 #include <viewimp.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>
62 #include <sortedobjs.hxx>
64 using namespace com::sun::star
;
68 class SwSdrHdl
: public SdrHdl
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
)
82 return SdrHdl::IsFocusHdl();
85 static const SwFrame
*lcl_FindAnchor( const SdrObject
*pObj
, bool bAll
)
87 const SwVirtFlyDrawObj
*pVirt
= dynamic_cast< const SwVirtFlyDrawObj
*>( pObj
);
90 if ( bAll
|| !pVirt
->GetFlyFrame()->IsFlyInContentFrame() )
91 return pVirt
->GetFlyFrame()->GetAnchorFrame();
95 const SwDrawContact
*pCont
= static_cast<const SwDrawContact
*>(GetUserCall(pObj
));
97 return pCont
->GetAnchorFrame( pObj
);
102 SwDrawView::SwDrawView(
104 FmFormModel
& rFmFormModel
,
105 OutputDevice
* pOutDev
)
106 : FmFormView(rFmFormModel
, pOutDev
),
109 SetPageVisible( false );
110 SetBordVisible( false );
111 SetGridVisible( false );
112 SetHlplVisible( false );
113 SetGlueVisible( false );
114 SetFrameDragSingles();
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());
132 bool SwDrawView::IsAntiAliasing()
134 return SvtOptionsDrawinglayer::IsAntiAliasing();
137 static SdrObject
* impLocalHitCorrection(SdrObject
* pRetval
, const Point
& rPnt
, sal_uInt16 nTol
, const SdrMarkList
&rMrkList
)
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)
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
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())
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())))
197 SdrObject
* SwDrawView::CheckSingleSdrObjectHit(const Point
& rPnt
, sal_uInt16 nTol
, SdrObject
* pObj
, SdrPageView
* pPV
, SdrSearchOptions nOptions
, const SdrLayerIDSet
* pMVisLay
) const
200 SdrObject
* pRetval
= FmFormView::CheckSingleSdrObjectHit(rPnt
, nTol
, pObj
, pPV
, nOptions
, pMVisLay
);
204 // override to allow extra handling when picking SwVirtFlyDrawObj's
205 pRetval
= impLocalHitCorrection(pRetval
, rPnt
, nTol
, GetMarkedObjectList());
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)
219 SdrObject
*pObj
= rMrkList
.GetMark(0)->GetMarkedSdrObj();
220 SwContact
* pContact
= ::GetUserCall( pObj
);
225 SwFrameFormat
* pFrameFormat( ::FindFrameFormat( pObj
) );
228 OSL_FAIL( "<SwDrawView::AddCustomHdl()> - missing frame format!" );
231 const SwFormatAnchor
&rAnchor
= pFrameFormat
->GetAnchor();
233 if (RndStdIds::FLY_AS_CHAR
== rAnchor
.GetAnchorId())
236 const SwFrame
* pAnch
= CalcAnchor();
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 );
273 //The topmost Obj within the anchor must not be overtaken.
274 const SwFlyFrame
*pFly
= pAnch
->FindFlyFrame();
277 const SwPageFrame
*pPage
= pFly
->FindPageFrame();
278 if ( pPage
->GetSortedObjs() )
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();
296 SdrPage
*pTmpPage
= GetModel().GetPage( 0 );
298 if ( nOrdNum
< pTmpPage
->GetObjCount() )
300 return pTmpPage
->GetObj( nOrdNum
);
310 SdrObject
* SwDrawView::GetMaxToBtmObj(SdrObject
* pObj
) const
312 if ( GetUserCall(pObj
) )
314 const SwFrame
*pAnch
= ::lcl_FindAnchor( pObj
, false );
317 //The Fly of the anchor must not be "flying under".
318 const SwFlyFrame
*pFly
= pAnch
->FindFlyFrame();
321 SdrObject
*pRet
= const_cast<SdrObject
*>(static_cast<SdrObject
const *>(pFly
->GetVirtDrawObj()));
322 return pRet
!= pObj
? pRet
: 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
)
349 if ( pObj
->GetOrdNum() > nMaxChildOrdNum
&&
350 _rParentObj
.IsAnLower( lcl_FindAnchor( pObj
, true ) ) )
352 nMaxChildOrdNum
= pObj
->GetOrdNum();
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.");
370 pContact
->GetAnchoredObjs( aAnchoredObjs
);
373 // check, if 'repeated' objects exists.
374 if ( aAnchoredObjs
.size() <= 1 )
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(),
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
);
398 m_rImp
.DisposeAccessibleObj(pAnchoredObj
->GetDrawObj(), true);
399 m_rImp
.AddAccessibleObj( pAnchoredObj
->GetDrawObj() );
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.");
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(),
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
);
434 m_rImp
.DisposeAccessibleObj(pAnchoredObj
->GetDrawObj(), true);
435 m_rImp
.AddAccessibleObj( pAnchoredObj
->GetDrawObj() );
439 aAnchoredObjs
.pop_back();
444 // --> adjustment and re-factoring of method
445 void SwDrawView::ObjOrderChanged( SdrObject
* pObj
, size_t nOldPos
,
448 // nothing to do for group members
449 if ( pObj
->getParentSdrObjectFromSdrObject() )
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
);
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
)
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;
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 );
506 size_t nTmpNewPos( nNewPos
);
507 if (const SwContact
* pContact2
= ::GetUserCall( pTmpObj
))
511 // move before the top 'repeated' object
512 const sal_uInt32 nTmpMaxOrdNum
= pContact2
->GetMaxOrdNum();
513 if ( nTmpMaxOrdNum
> nNewPos
)
514 nTmpNewPos
= nTmpMaxOrdNum
;
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
)
551 // assure, that determined position isn't between 'repeated' objects
552 pTmpObj
= pDrawPage
->GetObj( nTmpNewPos
);
553 pContact2
= ::GetUserCall( pTmpObj
);
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 );
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
))
590 nTmpNewPos
= pContact2
->GetMaxOrdNum();
591 pTmpObj
= pDrawPage
->GetObj( nTmpNewPos
+ 1 );
595 nTmpNewPos
= pContact2
->GetMinOrdNum();
596 pTmpObj
= pTmpParentObj
->GetDrawObj();
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
);
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
)
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
);
657 m_rImp
.DisposeAccessibleObj(pTmpObj
, true);
658 m_rImp
.AddAccessibleObj( pTmpObj
);
664 // adjust loop counter
671 } while ( ( bMovedForward
&& i
< ( nObjCount
- aMovedChildObjs
.size() ) ) ||
672 ( !bMovedForward
&& i
> ( nNewPos
+ aMovedChildObjs
.size() ) ) );
674 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
677 // adjustments for accessibility API
678 m_rImp
.DisposeAccessibleObj(pObj
, true);
679 m_rImp
.AddAccessibleObj( pObj
);
683 MoveRepeatedObjs( *pMovedAnchoredObj
, aMovedChildObjs
);
686 bool SwDrawView::TakeDragLimit( SdrDragMode eMode
,
687 tools::Rectangle
& rRect
) const
689 const SdrMarkList
&rMrkList
= GetMarkedObjectList();
691 if( 1 == rMrkList
.GetMarkCount() )
693 const SdrObject
*pObj
= rMrkList
.GetMark( 0 )->GetMarkedSdrObj();
695 if( ::CalcClipRect( pObj
, aRect
, eMode
== SdrDragMode::Move
) )
697 rRect
= aRect
.SVRect();
704 const SwFrame
* SwDrawView::CalcAnchor()
706 const SdrMarkList
&rMrkList
= GetMarkedObjectList();
707 if ( rMrkList
.GetMarkCount() != 1 )
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
);
719 pAnch
= pFlyDrawObj
->GetFlyFrame()->GetAnchorFrame();
720 aMyRect
= pFlyDrawObj
->GetFlyFrame()->getFrameArea().SVRect();
724 // determine correct anchor position for 'virtual' drawing objects.
726 if (SwDrawContact
* pContact
= static_cast<SwDrawContact
*>(GetUserCall(pObj
)))
728 pAnch
= pContact
->GetAnchorFrame( pObj
);
731 pContact
->ConnectToLayout();
732 // determine correct anchor position for 'virtual' drawing objects.
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();
748 if ( !TakeDragObjAnchorPos( aPt
, bTopRight
) )
753 tools::Rectangle aRect
= pObj
->GetSnapRect();
754 aPt
= bTopRight
? aRect
.TopRight() : aRect
.TopLeft();
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();
776 pAnch
= pContact
->FindPage( aRect
);
780 if( pAnch
&& !pAnch
->IsProtected() )
781 m_aAnchorPoint
= pAnch
->GetFrameAnchorPos( ::HasWrap( pObj
) );
787 void SwDrawView::ShowDragAnchor()
789 SdrHdl
* pHdl
= maHdlList
.GetHdl(SdrHdlKind::Anchor
);
791 pHdl
= maHdlList
.GetHdl(SdrHdlKind::Anchor_TR
);
796 pHdl
->SetPos(m_aAnchorPoint
);
800 void SwDrawView::MarkListHasChanged()
802 Imp().GetShell()->DrawSelChanged();
803 FmFormView::MarkListHasChanged();
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();
817 bool bColorWasSaved(false);
821 aBackColor
= pView
->GetBackgroundColor();
822 bColorWasSaved
= true;
826 FmFormView::ModelHasChanged();
830 pView
= GetTextEditOutlinerView();
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;
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();
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();
880 const uno::Reference
< embed::XEmbeddedObject
> xObj
= const_cast< SwOLEObj
& >(pOLENd
->GetOLEObj()).GetOleRef();
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
);
896 m_bMoveProtect
= true;
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
911 SwDrawContact
*pC
= static_cast<SwDrawContact
*>(GetUserCall(pObj
));
913 pFrame
= pC
->GetAnchorFrame( pObj
);
916 bProtect
= pFrame
->IsProtected(); //Frames, areas etc.
918 SwFrameFormat
* pFrameFormat( ::FindFrameFormat( const_cast<SdrObject
*>(pObj
) ) );
921 OSL_FAIL( "<SwDrawView::CheckPossibilities()> - missing frame format" );
924 else if ((RndStdIds::FLY_AS_CHAR
== pFrameFormat
->GetAnchor().GetAnchorId()) &&
925 rMrkList
.GetMarkCount() > 1 )
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() )
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
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
);
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();
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
);
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);
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: */