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 <hintids.hxx>
21 #include <svx/svdpage.hxx>
22 #include <svx/svdpagv.hxx>
23 #include <svx/fmmodel.hxx>
24 #include <sot/exchange.hxx>
25 #include <svx/sdrundomanager.hxx>
26 #include <tools/globname.hxx>
27 #include <editeng/outliner.hxx>
28 #include <com/sun/star/embed/EmbedMisc.hpp>
29 #include <com/sun/star/embed/XEmbeddedObject.hpp>
31 #include <pagefrm.hxx>
32 #include <rootfrm.hxx>
34 #include <notxtfrm.hxx>
37 #include <dflyobj.hxx>
38 #include <dcontact.hxx>
39 #include <textboxhelper.hxx>
41 #include <viewimp.hxx>
47 #include <fmtanchr.hxx>
48 #include <IDocumentUndoRedo.hxx>
49 #include <DocumentSettingManager.hxx>
50 #include <IDocumentLayoutAccess.hxx>
52 #include <com/sun/star/embed/Aspects.hpp>
56 #include <sortedobjs.hxx>
57 #include <UndoManager.hxx>
59 using namespace com::sun::star
;
63 class SwSdrHdl
: public SdrHdl
66 SwSdrHdl(const Point
& rPnt
, bool bTopRight
) :
67 SdrHdl( rPnt
, bTopRight
? SdrHdlKind::Anchor_TR
: SdrHdlKind::Anchor
) {}
68 virtual bool IsFocusHdl() const override
;
73 bool SwSdrHdl::IsFocusHdl() const
75 if( SdrHdlKind::Anchor
== eKind
|| SdrHdlKind::Anchor_TR
== eKind
)
77 return SdrHdl::IsFocusHdl();
80 static const SwFrame
*lcl_FindAnchor( const SdrObject
*pObj
, bool bAll
)
82 const SwVirtFlyDrawObj
*pVirt
= dynamic_cast< const SwVirtFlyDrawObj
*>( pObj
) != nullptr ?
83 static_cast<const SwVirtFlyDrawObj
*>(pObj
) : nullptr;
86 if ( bAll
|| !pVirt
->GetFlyFrame()->IsFlyInContentFrame() )
87 return pVirt
->GetFlyFrame()->GetAnchorFrame();
91 const SwDrawContact
*pCont
= static_cast<const SwDrawContact
*>(GetUserCall(pObj
));
93 return pCont
->GetAnchorFrame( pObj
);
98 SwDrawView::SwDrawView(
100 FmFormModel
& rFmFormModel
,
101 OutputDevice
* pOutDev
)
102 : FmFormView(rFmFormModel
, pOutDev
),
105 SetPageVisible( false );
106 SetBordVisible( false );
107 SetGridVisible( false );
108 SetHlplVisible( false );
109 SetGlueVisible( false );
110 SetFrameDragSingles();
113 EnableExtendedKeyInputDispatcher( false );
114 EnableExtendedMouseEventDispatcher( false );
116 SetHitTolerancePixel( GetMarkHdlSizePixel()/2 );
118 SetPrintPreview( rI
.GetShell()->IsPreview() );
120 // #i73602# Use default from the configuration
121 SetBufferedOverlayAllowed(getOptionsDrawinglayer().IsOverlayBuffer_Writer());
123 // #i74769#, #i75172# Use default from the configuration
124 SetBufferedOutputAllowed(getOptionsDrawinglayer().IsPaintBuffer_Writer());
128 bool SwDrawView::IsAntiAliasing() const
130 return getOptionsDrawinglayer().IsAntiAliasing();
133 static SdrObject
* impLocalHitCorrection(SdrObject
* pRetval
, const Point
& rPnt
, sal_uInt16 nTol
, const SdrMarkList
&rMrkList
)
137 // the old method forced back to outer bounds test when nTol == 0, so
138 // do not try to correct when nTol is not set (used from HelpContent)
142 // rebuild logic from former SwVirtFlyDrawObj::CheckSdrObjectHit. This is needed since
143 // the SdrObject-specific CheckHit implementations are now replaced with primitives and
144 // 'tricks' like in the old implementation (e.g. using a view from a model-data class to
145 // detect if object is selected) are no longer valid.
146 // The standard primitive hit-test for SwVirtFlyDrawObj now is the outer bound. The old
147 // implementation reduced this excluding the inner bound when the object was not selected.
148 SwVirtFlyDrawObj
* pSwVirtFlyDrawObj
= dynamic_cast< SwVirtFlyDrawObj
* >(pRetval
);
150 if(pSwVirtFlyDrawObj
)
152 if(pSwVirtFlyDrawObj
->GetFlyFrame()->Lower() && pSwVirtFlyDrawObj
->GetFlyFrame()->Lower()->IsNoTextFrame())
154 // the old method used IsNoTextFrame (should be for SW's own OLE and
155 // graphic's) to accept hit only based on outer bounds; nothing to do
159 // check if the object is selected in this view
160 const size_t nMarkCount(rMrkList
.GetMarkCount());
161 bool bSelected(false);
163 for(size_t a
= 0; !bSelected
&& a
< nMarkCount
; ++a
)
165 if(pSwVirtFlyDrawObj
== rMrkList
.GetMark(a
)->GetMarkedSdrObj())
173 // when not selected, the object is not hit when hit position is inside
174 // inner range. Get and shrink inner range
175 basegfx::B2DRange
aInnerBound(pSwVirtFlyDrawObj
->getInnerBound());
177 aInnerBound
.grow(-1.0 * nTol
);
179 if(aInnerBound
.isInside(basegfx::B2DPoint(rPnt
.X(), rPnt
.Y())))
192 SdrObject
* SwDrawView::CheckSingleSdrObjectHit(const Point
& rPnt
, sal_uInt16 nTol
, SdrObject
* pObj
, SdrPageView
* pPV
, SdrSearchOptions nOptions
, const SdrLayerIDSet
* pMVisLay
) const
195 SdrObject
* pRetval
= FmFormView::CheckSingleSdrObjectHit(rPnt
, nTol
, pObj
, pPV
, nOptions
, pMVisLay
);
199 // override to allow extra handling when picking SwVirtFlyDrawObj's
200 pRetval
= impLocalHitCorrection(pRetval
, rPnt
, nTol
, GetMarkedObjectList());
206 /// Gets called every time the handles need to be build
207 void SwDrawView::AddCustomHdl()
209 const SdrMarkList
&rMrkList
= GetMarkedObjectList();
211 if(rMrkList
.GetMarkCount() != 1 || !GetUserCall(rMrkList
.GetMark( 0 )->GetMarkedSdrObj()))
214 SdrObject
*pObj
= rMrkList
.GetMark(0)->GetMarkedSdrObj();
216 SwFrameFormat
* pFrameFormat( ::FindFrameFormat( pObj
) );
219 OSL_FAIL( "<SwDrawView::AddCustomHdl()> - missing frame format!" );
222 const SwFormatAnchor
&rAnchor
= pFrameFormat
->GetAnchor();
224 if (RndStdIds::FLY_AS_CHAR
== rAnchor
.GetAnchorId())
227 const SwFrame
* pAnch
= CalcAnchor();
231 Point
aPos(m_aAnchorPoint
);
233 if ( RndStdIds::FLY_AT_CHAR
== rAnchor
.GetAnchorId() )
235 // #i28701# - use last character rectangle saved at object
236 // in order to avoid a format of the anchor frame
237 SwAnchoredObject
* pAnchoredObj
= ::GetUserCall( pObj
)->GetAnchoredObj( pObj
);
238 SwRect aAutoPos
= pAnchoredObj
->GetLastCharRect();
239 if ( aAutoPos
.Height() )
241 aPos
= aAutoPos
.Pos();
245 // add anchor handle:
246 maHdlList
.AddHdl( std::make_unique
<SwSdrHdl
>( aPos
, ( pAnch
->IsVertical() && !pAnch
->IsVertLR() ) ||
247 pAnch
->IsRightToLeft() ) );
250 SdrObject
* SwDrawView::GetMaxToTopObj( SdrObject
* pObj
) const
252 if ( GetUserCall(pObj
) )
254 const SwFrame
*pAnch
= ::lcl_FindAnchor( pObj
, false );
257 //The topmost Obj within the anchor must not be overtaken.
258 const SwFlyFrame
*pFly
= pAnch
->FindFlyFrame();
261 const SwPageFrame
*pPage
= pFly
->FindPageFrame();
262 if ( pPage
->GetSortedObjs() )
265 for (SwAnchoredObject
* i
: *pPage
->GetSortedObjs())
267 const SdrObject
*pO
= i
->GetDrawObj();
269 if ( pO
->GetOrdNumDirect() > nOrdNum
)
271 const SwFrame
*pTmpAnch
= ::lcl_FindAnchor( pO
, false );
272 if ( pFly
->IsAnLower( pTmpAnch
) )
274 nOrdNum
= pO
->GetOrdNumDirect();
280 SdrPage
*pTmpPage
= GetModel()->GetPage( 0 );
282 if ( nOrdNum
< pTmpPage
->GetObjCount() )
284 return pTmpPage
->GetObj( nOrdNum
);
294 SdrObject
* SwDrawView::GetMaxToBtmObj(SdrObject
* pObj
) const
296 if ( GetUserCall(pObj
) )
298 const SwFrame
*pAnch
= ::lcl_FindAnchor( pObj
, false );
301 //The Fly of the anchor must not be "flying under".
302 const SwFlyFrame
*pFly
= pAnch
->FindFlyFrame();
305 SdrObject
*pRet
= const_cast<SdrObject
*>(static_cast<SdrObject
const *>(pFly
->GetVirtDrawObj()));
306 return pRet
!= pObj
? pRet
: nullptr;
313 /// determine maximal order number for a 'child' object of given 'parent' object
314 sal_uInt32
SwDrawView::GetMaxChildOrdNum( const SwFlyFrame
& _rParentObj
,
315 const SdrObject
* _pExclChildObj
)
317 sal_uInt32 nMaxChildOrdNum
= _rParentObj
.GetDrawObj()->GetOrdNum();
319 const SdrPage
* pDrawPage
= _rParentObj
.GetDrawObj()->getSdrPageFromSdrObject();
320 OSL_ENSURE( pDrawPage
,
321 "<SwDrawView::GetMaxChildOrdNum(..) - missing drawing page at parent object - crash!" );
323 const size_t nObjCount
= pDrawPage
->GetObjCount();
324 for ( size_t i
= nObjCount
-1; i
> _rParentObj
.GetDrawObj()->GetOrdNum() ; --i
)
326 const SdrObject
* pObj
= pDrawPage
->GetObj( i
);
328 // Don't consider 'child' object <_pExclChildObj>
329 if ( pObj
== _pExclChildObj
)
334 if ( pObj
->GetOrdNum() > nMaxChildOrdNum
&&
335 _rParentObj
.IsAnLower( lcl_FindAnchor( pObj
, true ) ) )
337 nMaxChildOrdNum
= pObj
->GetOrdNum();
342 return nMaxChildOrdNum
;
345 /// method to move 'repeated' objects of the given moved object to the according level
346 void SwDrawView::MoveRepeatedObjs( const SwAnchoredObject
& _rMovedAnchoredObj
,
347 const std::vector
<SdrObject
*>& _rMovedChildObjs
) const
349 // determine 'repeated' objects of already moved object <_rMovedAnchoredObj>
350 std::vector
<SwAnchoredObject
*> aAnchoredObjs
;
352 const SwContact
* pContact
= ::GetUserCall( _rMovedAnchoredObj
.GetDrawObj() );
353 assert(pContact
&& "SwDrawView::MoveRepeatedObjs(..) - missing contact object -> crash.");
354 pContact
->GetAnchoredObjs( aAnchoredObjs
);
357 // check, if 'repeated' objects exists.
358 if ( aAnchoredObjs
.size() <= 1 )
361 SdrPage
* pDrawPage
= GetModel()->GetPage( 0 );
363 // move 'repeated' ones to the same order number as the already moved one.
364 const size_t nNewPos
= _rMovedAnchoredObj
.GetDrawObj()->GetOrdNum();
365 while ( !aAnchoredObjs
.empty() )
367 SwAnchoredObject
* pAnchoredObj
= aAnchoredObjs
.back();
368 if ( pAnchoredObj
!= &_rMovedAnchoredObj
)
370 pDrawPage
->SetObjectOrdNum( pAnchoredObj
->GetDrawObj()->GetOrdNum(),
372 pDrawPage
->RecalcObjOrdNums();
373 // adjustments for accessibility API
374 if ( auto pTmpFlyFrame
= dynamic_cast<SwFlyFrame
*>( pAnchoredObj
) )
376 m_rImp
.DisposeAccessibleFrame( pTmpFlyFrame
);
377 m_rImp
.AddAccessibleFrame( pTmpFlyFrame
);
381 m_rImp
.DisposeAccessibleObj(pAnchoredObj
->GetDrawObj(), true);
382 m_rImp
.AddAccessibleObj( pAnchoredObj
->GetDrawObj() );
385 aAnchoredObjs
.pop_back();
388 // move 'repeated' ones of 'child' objects
389 for ( SdrObject
* pChildObj
: _rMovedChildObjs
)
392 const SwContact
* pContact
= ::GetUserCall( pChildObj
);
393 assert(pContact
&& "SwDrawView::MoveRepeatedObjs(..) - missing contact object -> crash.");
394 pContact
->GetAnchoredObjs( aAnchoredObjs
);
396 // move 'repeated' ones to the same order number as the already moved one.
397 const size_t nTmpNewPos
= pChildObj
->GetOrdNum();
398 while ( !aAnchoredObjs
.empty() )
400 SwAnchoredObject
* pAnchoredObj
= aAnchoredObjs
.back();
401 if ( pAnchoredObj
->GetDrawObj() != pChildObj
)
403 pDrawPage
->SetObjectOrdNum( pAnchoredObj
->GetDrawObj()->GetOrdNum(),
405 pDrawPage
->RecalcObjOrdNums();
406 // adjustments for accessibility API
407 if ( auto pTmpFlyFrame
= dynamic_cast<SwFlyFrame
*>( pAnchoredObj
) )
409 m_rImp
.DisposeAccessibleFrame( pTmpFlyFrame
);
410 m_rImp
.AddAccessibleFrame( pTmpFlyFrame
);
414 m_rImp
.DisposeAccessibleObj(pAnchoredObj
->GetDrawObj(), true);
415 m_rImp
.AddAccessibleObj( pAnchoredObj
->GetDrawObj() );
418 aAnchoredObjs
.pop_back();
423 // --> adjustment and re-factoring of method
424 void SwDrawView::ObjOrderChanged( SdrObject
* pObj
, size_t nOldPos
,
427 // nothing to do for group members
428 if ( pObj
->getParentSdrObjectFromSdrObject() )
433 // determine drawing page and assure that the order numbers are correct.
434 SdrPage
* pDrawPage
= GetModel()->GetPage( 0 );
435 if ( pDrawPage
->IsObjOrdNumsDirty() )
436 pDrawPage
->RecalcObjOrdNums();
437 const size_t nObjCount
= pDrawPage
->GetObjCount();
439 SwAnchoredObject
* pMovedAnchoredObj
=
440 ::GetUserCall( pObj
)->GetAnchoredObj( pObj
);
441 const SwFlyFrame
* pParentAnchoredObj
=
442 pMovedAnchoredObj
->GetAnchorFrame()->FindFlyFrame();
444 const bool bMovedForward
= nOldPos
< nNewPos
;
446 // assure for a 'child' object, that it doesn't exceed the limits of its 'parent'
447 if ( pParentAnchoredObj
)
451 const size_t nMaxChildOrdNumWithoutMoved
=
452 GetMaxChildOrdNum( *pParentAnchoredObj
, pMovedAnchoredObj
->GetDrawObj() );
453 if ( nNewPos
> nMaxChildOrdNumWithoutMoved
+1 )
455 // set position to the top of the 'child' object group
456 pDrawPage
->SetObjectOrdNum( nNewPos
, nMaxChildOrdNumWithoutMoved
+1 );
457 nNewPos
= nMaxChildOrdNumWithoutMoved
+1;
462 const size_t nParentOrdNum
= pParentAnchoredObj
->GetDrawObj()->GetOrdNum();
463 if ( nNewPos
< nParentOrdNum
)
465 // set position to the bottom of the 'child' object group
466 pDrawPage
->SetObjectOrdNum( nNewPos
, nParentOrdNum
);
467 nNewPos
= nParentOrdNum
;
470 if ( pDrawPage
->IsObjOrdNumsDirty() )
471 pDrawPage
->RecalcObjOrdNums();
474 // Assure, that object isn't positioned between 'repeated' ones
475 if ( ( bMovedForward
&& nNewPos
< nObjCount
- 1 ) ||
476 ( !bMovedForward
&& nNewPos
> 0 ) )
478 const SdrObject
* pTmpObj
=
479 pDrawPage
->GetObj( bMovedForward
? nNewPos
- 1 : nNewPos
+ 1 );
482 size_t nTmpNewPos( nNewPos
);
485 // move before the top 'repeated' object
486 const sal_uInt32 nTmpMaxOrdNum
=
487 ::GetUserCall( pTmpObj
)->GetMaxOrdNum();
488 if ( nTmpMaxOrdNum
> nNewPos
)
489 nTmpNewPos
= nTmpMaxOrdNum
;
493 // move behind the bottom 'repeated' object
494 const sal_uInt32 nTmpMinOrdNum
=
495 ::GetUserCall( pTmpObj
)->GetMinOrdNum();
496 if ( nTmpMinOrdNum
< nNewPos
)
497 nTmpNewPos
= nTmpMinOrdNum
;
499 if ( nTmpNewPos
!= nNewPos
)
501 pDrawPage
->SetObjectOrdNum( nNewPos
, nTmpNewPos
);
502 nNewPos
= nTmpNewPos
;
503 pDrawPage
->RecalcObjOrdNums();
508 // On move forward, assure that object is moved before its own children.
509 // Only Writer fly frames can have children.
510 if ( dynamic_cast< const SwFlyFrame
*>( pMovedAnchoredObj
) != nullptr &&
511 bMovedForward
&& nNewPos
< nObjCount
- 1 )
513 sal_uInt32 nMaxChildOrdNum
=
514 GetMaxChildOrdNum( *static_cast<const SwFlyFrame
*>(pMovedAnchoredObj
) );
515 if ( nNewPos
< nMaxChildOrdNum
)
517 // determine position before the object before its top 'child' object
518 const SdrObject
* pTmpObj
= pDrawPage
->GetObj( nMaxChildOrdNum
);
519 size_t nTmpNewPos
= ::GetUserCall( pTmpObj
)->GetMaxOrdNum() + 1;
520 if ( nTmpNewPos
>= nObjCount
)
524 // assure, that determined position isn't between 'repeated' objects
525 pTmpObj
= pDrawPage
->GetObj( nTmpNewPos
);
526 nTmpNewPos
= ::GetUserCall( pTmpObj
)->GetMaxOrdNum();
527 // apply new position
528 pDrawPage
->SetObjectOrdNum( nNewPos
, nTmpNewPos
);
529 nNewPos
= nTmpNewPos
;
530 pDrawPage
->RecalcObjOrdNums();
534 // Assure, that object isn't positioned between nested objects
535 if ( ( bMovedForward
&& nNewPos
< nObjCount
- 1 ) ||
536 ( !bMovedForward
&& nNewPos
> 0 ) )
538 size_t nTmpNewPos( nNewPos
);
539 const SwFrameFormat
* pParentFrameFormat
=
540 pParentAnchoredObj
? &(pParentAnchoredObj
->GetFrameFormat()) : nullptr;
541 const SdrObject
* pTmpObj
= pDrawPage
->GetObj( nNewPos
+ 1 );
544 // #i38563# - assure, that anchor frame exists.
545 // If object is anchored inside an invisible part of the document
546 // (e.g. page header, whose page style isn't applied, or hidden
547 // section), no anchor frame exists.
548 const SwFrame
* pTmpAnchorFrame
= lcl_FindAnchor( pTmpObj
, true );
549 const SwFlyFrame
* pTmpParentObj
= pTmpAnchorFrame
550 ? pTmpAnchorFrame
->FindFlyFrame() : nullptr;
551 if ( pTmpParentObj
&&
552 &(pTmpParentObj
->GetFrameFormat()) != pParentFrameFormat
)
556 nTmpNewPos
= ::GetUserCall( pTmpObj
)->GetMaxOrdNum();
557 pTmpObj
= pDrawPage
->GetObj( nTmpNewPos
+ 1 );
561 nTmpNewPos
= ::GetUserCall( pTmpParentObj
->GetDrawObj() )
563 pTmpObj
= pTmpParentObj
->GetDrawObj();
569 if ( nTmpNewPos
!= nNewPos
)
571 pDrawPage
->SetObjectOrdNum( nNewPos
, nTmpNewPos
);
572 nNewPos
= nTmpNewPos
;
573 pDrawPage
->RecalcObjOrdNums();
577 // setup collection of moved 'child' objects to move its 'repeated' objects.
578 std::vector
< SdrObject
* > aMovedChildObjs
;
580 // move 'children' accordingly
581 if ( auto pFlyFrame
= dynamic_cast< SwFlyFrame
*>( pMovedAnchoredObj
) )
583 // adjustments for accessibility API
584 m_rImp
.DisposeAccessibleFrame( pFlyFrame
);
585 m_rImp
.AddAccessibleFrame( pFlyFrame
);
587 const sal_uInt32 nChildNewPos
= bMovedForward
? nNewPos
: nNewPos
+1;
588 size_t i
= bMovedForward
? nOldPos
: nObjCount
-1;
591 SdrObject
* pTmpObj
= pDrawPage
->GetObj( i
);
592 if ( pTmpObj
== pObj
)
595 // #i38563# - assure, that anchor frame exists.
596 // If object is anchored inside an invisible part of the document
597 // (e.g. page header, whose page style isn't applied, or hidden
598 // section), no anchor frame exists.
599 const SwFrame
* pTmpAnchorFrame
= lcl_FindAnchor( pTmpObj
, true );
600 const SwFlyFrame
* pTmpParentObj
= pTmpAnchorFrame
601 ? pTmpAnchorFrame
->FindFlyFrame() : nullptr;
602 if ( pTmpParentObj
&&
603 ( ( pTmpParentObj
== pFlyFrame
) ||
604 ( pFlyFrame
->IsUpperOf( *pTmpParentObj
) ) ) )
606 // move child object.,
607 pDrawPage
->SetObjectOrdNum( i
, nChildNewPos
);
608 pDrawPage
->RecalcObjOrdNums();
609 // collect 'child' object
610 aMovedChildObjs
.push_back( pTmpObj
);
611 // adjustments for accessibility API
612 if ( auto pFlyDrawObj
= dynamic_cast<SwVirtFlyDrawObj
*>( pTmpObj
) )
614 const SwFlyFrame
*pTmpFlyFrame
= pFlyDrawObj
->GetFlyFrame();
615 m_rImp
.DisposeAccessibleFrame( pTmpFlyFrame
);
616 m_rImp
.AddAccessibleFrame( pTmpFlyFrame
);
620 m_rImp
.DisposeAccessibleObj(pTmpObj
, true);
621 m_rImp
.AddAccessibleObj( pTmpObj
);
626 // adjust loop counter
633 } while ( ( bMovedForward
&& i
< ( nObjCount
- aMovedChildObjs
.size() ) ) ||
634 ( !bMovedForward
&& i
> ( nNewPos
+ aMovedChildObjs
.size() ) ) );
638 // adjustments for accessibility API
639 m_rImp
.DisposeAccessibleObj(pObj
, true);
640 m_rImp
.AddAccessibleObj( pObj
);
643 MoveRepeatedObjs( *pMovedAnchoredObj
, aMovedChildObjs
);
646 bool SwDrawView::TakeDragLimit( SdrDragMode eMode
,
647 tools::Rectangle
& rRect
) const
649 const SdrMarkList
&rMrkList
= GetMarkedObjectList();
651 if( 1 == rMrkList
.GetMarkCount() )
653 const SdrObject
*pObj
= rMrkList
.GetMark( 0 )->GetMarkedSdrObj();
655 if( ::CalcClipRect( pObj
, aRect
, eMode
== SdrDragMode::Move
) )
657 rRect
= aRect
.SVRect();
664 const SwFrame
* SwDrawView::CalcAnchor()
666 const SdrMarkList
&rMrkList
= GetMarkedObjectList();
667 if ( rMrkList
.GetMarkCount() != 1 )
670 SdrObject
* pObj
= rMrkList
.GetMark( 0 )->GetMarkedSdrObj();
672 //Search for paragraph bound objects, otherwise only the
673 //current anchor. Search only if we currently drag.
674 const SwFrame
* pAnch
;
675 tools::Rectangle aMyRect
;
676 auto pFlyDrawObj
= dynamic_cast<SwVirtFlyDrawObj
*>( pObj
);
679 pAnch
= pFlyDrawObj
->GetFlyFrame()->GetAnchorFrame();
680 aMyRect
= pFlyDrawObj
->GetFlyFrame()->getFrameArea().SVRect();
684 SwDrawContact
*pC
= static_cast<SwDrawContact
*>(GetUserCall(pObj
));
685 // determine correct anchor position for 'virtual' drawing objects.
687 pAnch
= pC
->GetAnchorFrame( pObj
);
690 pC
->ConnectToLayout();
691 // determine correct anchor position for 'virtual' drawing objects.
693 pAnch
= pC
->GetAnchorFrame( pObj
);
695 aMyRect
= pObj
->GetSnapRect();
698 const bool bTopRight
= pAnch
&& ( ( pAnch
->IsVertical() &&
699 !pAnch
->IsVertLR() ) ||
700 pAnch
->IsRightToLeft() );
701 const Point aMyPt
= bTopRight
? aMyRect
.TopRight() : aMyRect
.TopLeft();
706 if ( !TakeDragObjAnchorPos( aPt
, bTopRight
) )
711 tools::Rectangle aRect
= pObj
->GetSnapRect();
712 aPt
= bTopRight
? aRect
.TopRight() : aRect
.TopLeft();
717 if ( pAnch
&& pAnch
->IsContentFrame() )
719 // allow drawing objects in header/footer,
720 // but exclude control objects.
721 bool bBodyOnly
= CheckControlLayer( pObj
);
722 pAnch
= ::FindAnchor( static_cast<const SwContentFrame
*>(pAnch
), aPt
, bBodyOnly
);
724 else if ( !pFlyDrawObj
)
726 const SwRect
aRect( aPt
.getX(), aPt
.getY(), 1, 1 );
728 SwDrawContact
* pContact
= static_cast<SwDrawContact
*>(GetUserCall(pObj
));
729 if ( pContact
->GetAnchorFrame( pObj
) &&
730 pContact
->GetAnchorFrame( pObj
)->IsPageFrame() )
731 pAnch
= pContact
->GetPageFrame();
733 pAnch
= pContact
->FindPage( aRect
);
736 if( pAnch
&& !pAnch
->IsProtected() )
737 m_aAnchorPoint
= pAnch
->GetFrameAnchorPos( ::HasWrap( pObj
) );
743 void SwDrawView::ShowDragAnchor()
745 SdrHdl
* pHdl
= maHdlList
.GetHdl(SdrHdlKind::Anchor
);
747 pHdl
= maHdlList
.GetHdl(SdrHdlKind::Anchor_TR
);
752 pHdl
->SetPos(m_aAnchorPoint
);
756 void SwDrawView::MarkListHasChanged()
758 Imp().GetShell()->DrawSelChanged();
759 FmFormView::MarkListHasChanged();
763 void SwDrawView::ModelHasChanged()
765 // The ModelHasChanged() call in DrawingLayer also updates
766 // an eventually active text edit view (OutlinerView). This also leads
767 // to newly setting the background color for that edit view. Thus,
768 // this method rescues the current background color if an OutlinerView
769 // exists and re-establishes it then. To be more safe, the OutlinerView
770 // will be fetched again (maybe textedit has ended).
771 OutlinerView
* pView
= GetTextEditOutlinerView();
773 bool bColorWasSaved(false);
777 aBackColor
= pView
->GetBackgroundColor();
778 bColorWasSaved
= true;
782 FmFormView::ModelHasChanged();
786 pView
= GetTextEditOutlinerView();
790 pView
->SetBackgroundColor(aBackColor
);
795 void SwDrawView::MakeVisible( const tools::Rectangle
&rRect
, vcl::Window
& )
797 OSL_ENSURE( m_rImp
.GetShell()->GetWin(), "MakeVisible, unknown Window");
798 m_rImp
.GetShell()->MakeVisible( SwRect( rRect
) );
801 void SwDrawView::CheckPossibilities()
803 FmFormView::CheckPossibilities();
805 //In addition to the existing flags of the objects themselves,
806 //which are evaluated by the DrawingEngine, other circumstances
807 //lead to a protection.
808 //Objects that are anchored in frames need to be protected
809 //if the content of the frame is protected.
810 //OLE-Objects may themselves wish a resize protection (StarMath)
812 const SdrMarkList
&rMrkList
= GetMarkedObjectList();
813 bool bProtect
= false;
814 bool bSzProtect
= false;
817 for ( size_t i
= 0; !bProtect
&& i
< rMrkList
.GetMarkCount(); ++i
)
819 const SdrObject
*pObj
= rMrkList
.GetMark( i
)->GetMarkedSdrObj();
820 const SwFrame
*pFrame
= nullptr;
821 if ( auto pVirtFlyDrawObj
= dynamic_cast< const SwVirtFlyDrawObj
*>( pObj
) )
823 const SwFlyFrame
*pFly
= pVirtFlyDrawObj
->GetFlyFrame();
826 pFrame
= pFly
->GetAnchorFrame();
827 if ( pFly
->Lower() && pFly
->Lower()->IsNoTextFrame() )
829 const SwNoTextFrame
*const pNTF(static_cast<const SwNoTextFrame
*>(pFly
->Lower()));
830 const SwOLENode
*const pOLENd
= pNTF
->GetNode()->GetOLENode();
831 const SwGrfNode
*const pGrfNd
= pNTF
->GetNode()->GetGrfNode();
835 const uno::Reference
< embed::XEmbeddedObject
> xObj
= const_cast< SwOLEObj
& >(pOLENd
->GetOLEObj()).GetOleRef();
839 // --> improvement for the future, when more
840 // than one Writer fly frame can be selected.
842 // TODO/LATER: retrieve Aspect - from where?!
843 bSzProtect
|= ( embed::EmbedMisc::EMBED_NEVERRESIZE
& xObj
->getStatus( embed::Aspects::MSOLE_CONTENT
) ) != 0;
845 // #i972: protect position if it is a Math object anchored 'as char' and baseline alignment is activated
846 SwDoc
* pDoc
= Imp().GetShell()->GetDoc();
847 const bool bProtectMathPos
= SotExchange::IsMath( xObj
->getClassID() )
848 && RndStdIds::FLY_AS_CHAR
== pFly
->GetFormat()->GetAnchor().GetAnchorId()
849 && pDoc
->GetDocumentSettingManager().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT
);
851 m_bMoveProtect
= true;
856 // RotGrfFlyFrame: GraphicNode allows rotation(s). The loop ew are in stops
857 // as soon as bMoveProtect is set, but since rotation is valid only with
858 // a single object selected this makes no difference
866 SwDrawContact
*pC
= static_cast<SwDrawContact
*>(GetUserCall(pObj
));
868 pFrame
= pC
->GetAnchorFrame( pObj
);
871 bProtect
= pFrame
->IsProtected(); //Frames, areas etc.
873 SwFrameFormat
* pFrameFormat( ::FindFrameFormat( const_cast<SdrObject
*>(pObj
) ) );
876 OSL_FAIL( "<SwDrawView::CheckPossibilities()> - missing frame format" );
879 else if ((RndStdIds::FLY_AS_CHAR
== pFrameFormat
->GetAnchor().GetAnchorId()) &&
880 rMrkList
.GetMarkCount() > 1 )
886 m_bMoveProtect
|= bProtect
;
887 m_bResizeProtect
|= bProtect
|| bSzProtect
;
889 // RotGrfFlyFrame: allow rotation when SwGrfNode is selected and not size protected
890 m_bRotateFreeAllowed
|= bRotate
&& !bProtect
;
891 m_bRotate90Allowed
|= m_bRotateFreeAllowed
;
894 /// replace marked <SwDrawVirtObj>-objects by its reference object for delete marked objects.
895 void SwDrawView::ReplaceMarkedDrawVirtObjs( SdrMarkView
& _rMarkView
)
897 SdrPageView
* pDrawPageView
= _rMarkView
.GetSdrPageView();
898 const SdrMarkList
& rMarkList
= _rMarkView
.GetMarkedObjectList();
900 if( !rMarkList
.GetMarkCount() )
903 // collect marked objects in a local data structure
904 std::vector
<SdrObject
*> aMarkedObjs
;
905 for( size_t i
= 0; i
< rMarkList
.GetMarkCount(); ++i
)
907 SdrObject
* pMarkedObj
= rMarkList
.GetMark( i
)->GetMarkedSdrObj();
908 aMarkedObjs
.push_back( pMarkedObj
);
910 // unmark all objects
911 _rMarkView
.UnmarkAllObj();
912 // re-mark objects, but for marked <SwDrawVirtObj>-objects marked its
914 while ( !aMarkedObjs
.empty() )
916 SdrObject
* pMarkObj
= aMarkedObjs
.back();
917 if ( auto pVirtObj
= dynamic_cast<SwDrawVirtObj
*>( pMarkObj
) )
919 SdrObject
* pRefObj
= &(pVirtObj
->ReferencedObj());
920 if ( !_rMarkView
.IsObjMarked( pRefObj
) )
922 _rMarkView
.MarkObj( pRefObj
, pDrawPageView
);
927 _rMarkView
.MarkObj( pMarkObj
, pDrawPageView
);
930 aMarkedObjs
.pop_back();
932 // sort marked list in order to assure consistent state in drawing layer
933 _rMarkView
.SortMarkedObjects();
936 SfxViewShell
* SwDrawView::GetSfxViewShell() const
938 return m_rImp
.GetShell()->GetSfxViewShell();
941 void SwDrawView::DeleteMarked()
943 SwDoc
* pDoc
= Imp().GetShell()->GetDoc();
944 SwRootFrame
*pTmpRoot
= pDoc
->getIDocumentLayoutAccess().GetCurrentLayout();
946 pTmpRoot
->StartAllAction();
947 pDoc
->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY
, nullptr);
948 // replace marked <SwDrawVirtObj>-objects by its reference objects.
949 if (SdrPageView
* pDrawPageView
= m_rImp
.GetPageView())
951 ReplaceMarkedDrawVirtObjs(pDrawPageView
->GetView());
954 // Check what textboxes have to be deleted afterwards.
955 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
956 std::vector
<SwFrameFormat
*> aTextBoxesToDelete
;
957 for (size_t i
= 0; i
< rMarkList
.GetMarkCount(); ++i
)
959 SdrObject
*pObject
= rMarkList
.GetMark(i
)->GetMarkedSdrObj();
960 SwContact
* pContact
= GetUserCall(pObject
);
961 SwFrameFormat
* pFormat
= pContact
->GetFormat();
962 if (SwFrameFormat
* pTextBox
= SwTextBoxHelper::getOtherTextBoxFormat(pFormat
, RES_DRAWFRMFMT
))
963 aTextBoxesToDelete
.push_back(pTextBox
);
966 if ( pDoc
->DeleteSelection( *this ) )
968 FmFormView::DeleteMarked();
969 ::FrameNotify( Imp().GetShell(), FLY_DRAG_END
);
972 // Only delete these now: earlier deletion would clear the mark list as well.
973 // Delete in reverse order, assuming that the container is sorted by anchor positions.
974 for (int i
= aTextBoxesToDelete
.size() - 1; i
>= 0; --i
)
976 SwFrameFormat
*& rpTextBox
= aTextBoxesToDelete
[i
];
977 pDoc
->getIDocumentLayoutAccess().DelLayoutFormat(rpTextBox
);
980 pDoc
->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY
, nullptr);
982 pTmpRoot
->EndAllAction();
985 // support enhanced text edit for draw objects
986 SdrUndoManager
* SwDrawView::getSdrUndoManagerForEnhancedTextEdit() const
988 SwDoc
* pDoc
= Imp().GetShell()->GetDoc();
990 return pDoc
? dynamic_cast< SdrUndoManager
* >(&(pDoc
->GetUndoManager())) : nullptr;
993 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */