Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / sw / source / core / draw / dview.cxx
blob169febf96934b5ef80fd3f98186c2f986ef553f9
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 <hintids.hxx>
21 #include <editeng/protitem.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>
30 #include <swtypes.hxx>
31 #include <pagefrm.hxx>
32 #include <rootfrm.hxx>
33 #include <cntfrm.hxx>
34 #include <notxtfrm.hxx>
35 #include <flyfrm.hxx>
36 #include <frmfmt.hxx>
37 #include <dflyobj.hxx>
38 #include <dcontact.hxx>
39 #include <textboxhelper.hxx>
40 #include <frmatr.hxx>
41 #include <viewsh.hxx>
42 #include <viewimp.hxx>
43 #include <dview.hxx>
44 #include <dpage.hxx>
45 #include <doc.hxx>
46 #include <mdiexp.hxx>
47 #include <ndole.hxx>
48 #include <ndgrf.hxx>
49 #include <fmtanchr.hxx>
50 #include <shellres.hxx>
51 #include <IDocumentUndoRedo.hxx>
52 #include <DocumentSettingManager.hxx>
53 #include <IDocumentLayoutAccess.hxx>
55 #include <com/sun/star/embed/Aspects.hpp>
57 #include <vector>
59 #include <sortedobjs.hxx>
60 #include <flyfrms.hxx>
61 #include <UndoManager.hxx>
63 using namespace com::sun::star;
65 class SwSdrHdl : public SdrHdl
67 public:
68 SwSdrHdl(const Point& rPnt, bool bTopRight ) :
69 SdrHdl( rPnt, bTopRight ? SdrHdlKind::Anchor_TR : SdrHdlKind::Anchor ) {}
70 virtual bool IsFocusHdl() const override;
73 bool SwSdrHdl::IsFocusHdl() const
75 if( SdrHdlKind::Anchor == eKind || SdrHdlKind::Anchor_TR == eKind )
76 return true;
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;
84 if ( pVirt )
86 if ( bAll || !pVirt->GetFlyFrame()->IsFlyInContentFrame() )
87 return pVirt->GetFlyFrame()->GetAnchorFrame();
89 else
91 const SwDrawContact *pCont = static_cast<const SwDrawContact*>(GetUserCall(pObj));
92 if ( pCont )
93 return pCont->GetAnchorFrame( pObj );
95 return nullptr;
98 SwDrawView::SwDrawView(
99 SwViewShellImp& rI,
100 FmFormModel& rFmFormModel,
101 OutputDevice* pOutDev)
102 : FmFormView(rFmFormModel, pOutDev),
103 m_rImp( rI )
105 SetPageVisible( false );
106 SetBordVisible( false );
107 SetGridVisible( false );
108 SetHlplVisible( false );
109 SetGlueVisible( false );
110 SetFrameDragSingles();
111 SetSwapAsynchron();
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());
127 // #i99665#
128 bool SwDrawView::IsAntiAliasing() const
130 return getOptionsDrawinglayer().IsAntiAliasing();
133 SdrObject* impLocalHitCorrection(SdrObject* pRetval, const Point& rPnt, sal_uInt16 nTol, const SdrMarkList &rMrkList)
135 if(!nTol)
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)
140 else
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
157 else
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())
167 bSelected = true;
171 if(!bSelected)
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())))
181 // exclude this hit
182 pRetval = nullptr;
189 return pRetval;
192 SdrObject* SwDrawView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const
194 // call parent
195 SdrObject* pRetval = FmFormView::CheckSingleSdrObjectHit(rPnt, nTol, pObj, pPV, nOptions, pMVisLay);
197 if(pRetval)
199 // override to allow extra handling when picking SwVirtFlyDrawObj's
200 pRetval = impLocalHitCorrection(pRetval, rPnt, nTol, GetMarkedObjectList());
203 return pRetval;
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()))
212 return;
214 SdrObject *pObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
215 // make code robust
216 SwFrameFormat* pFrameFormat( ::FindFrameFormat( pObj ) );
217 if ( !pFrameFormat )
219 OSL_FAIL( "<SwDrawView::AddCustomHdl()> - missing frame format!" );
220 return;
222 const SwFormatAnchor &rAnchor = pFrameFormat->GetAnchor();
224 if (RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId())
225 return;
227 const SwFrame* pAnch;
228 if(nullptr == (pAnch = CalcAnchor()))
229 return;
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( new 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 );
255 if ( pAnch )
257 //The topmost Obj within the anchor must not be overtaken.
258 const SwFlyFrame *pFly = pAnch->FindFlyFrame();
259 if ( pFly )
261 const SwPageFrame *pPage = pFly->FindPageFrame();
262 if ( pPage->GetSortedObjs() )
264 size_t nOrdNum = 0;
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();
278 if ( nOrdNum )
280 SdrPage *pTmpPage = GetModel()->GetPage( 0 );
281 ++nOrdNum;
282 if ( nOrdNum < pTmpPage->GetObjCount() )
284 return pTmpPage->GetObj( nOrdNum );
291 return nullptr;
294 SdrObject* SwDrawView::GetMaxToBtmObj(SdrObject* pObj) const
296 if ( GetUserCall(pObj) )
298 const SwFrame *pAnch = ::lcl_FindAnchor( pObj, false );
299 if ( pAnch )
301 //The Fly of the anchor must not be "flying under".
302 const SwFlyFrame *pFly = pAnch->FindFlyFrame();
303 if ( pFly )
305 SdrObject *pRet = const_cast<SdrObject*>(static_cast<SdrObject const *>(pFly->GetVirtDrawObj()));
306 return pRet != pObj ? pRet : nullptr;
310 return 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()->GetPage();
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 )
331 continue;
334 if ( pObj->GetOrdNum() > nMaxChildOrdNum &&
335 _rParentObj.IsAnLower( lcl_FindAnchor( pObj, true ) ) )
337 nMaxChildOrdNum = pObj->GetOrdNum();
338 break;
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 )
360 SdrPage* pDrawPage = GetModel()->GetPage( 0 );
362 // move 'repeated' ones to the same order number as the already moved one.
363 const size_t nNewPos = _rMovedAnchoredObj.GetDrawObj()->GetOrdNum();
364 while ( !aAnchoredObjs.empty() )
366 SwAnchoredObject* pAnchoredObj = aAnchoredObjs.back();
367 if ( pAnchoredObj != &_rMovedAnchoredObj )
369 pDrawPage->SetObjectOrdNum( pAnchoredObj->GetDrawObj()->GetOrdNum(),
370 nNewPos );
371 pDrawPage->RecalcObjOrdNums();
372 // adjustments for accessibility API
373 if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) != nullptr )
375 const SwFlyFrame *pTmpFlyFrame = static_cast<SwFlyFrame*>(pAnchoredObj);
376 m_rImp.DisposeAccessibleFrame( pTmpFlyFrame );
377 m_rImp.AddAccessibleFrame( pTmpFlyFrame );
379 else
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 ( std::vector<SdrObject*>::const_iterator aObjIter = _rMovedChildObjs.begin();
390 aObjIter != _rMovedChildObjs.end(); ++aObjIter )
392 SdrObject* pChildObj = (*aObjIter);
394 const SwContact* pContact = ::GetUserCall( pChildObj );
395 assert(pContact && "SwDrawView::MoveRepeatedObjs(..) - missing contact object -> crash.");
396 pContact->GetAnchoredObjs( aAnchoredObjs );
398 // move 'repeated' ones to the same order number as the already moved one.
399 const size_t nTmpNewPos = pChildObj->GetOrdNum();
400 while ( !aAnchoredObjs.empty() )
402 SwAnchoredObject* pAnchoredObj = aAnchoredObjs.back();
403 if ( pAnchoredObj->GetDrawObj() != pChildObj )
405 pDrawPage->SetObjectOrdNum( pAnchoredObj->GetDrawObj()->GetOrdNum(),
406 nTmpNewPos );
407 pDrawPage->RecalcObjOrdNums();
408 // adjustments for accessibility API
409 if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) != nullptr )
411 const SwFlyFrame *pTmpFlyFrame = static_cast<SwFlyFrame*>(pAnchoredObj);
412 m_rImp.DisposeAccessibleFrame( pTmpFlyFrame );
413 m_rImp.AddAccessibleFrame( pTmpFlyFrame );
415 else
417 m_rImp.DisposeAccessibleObj(pAnchoredObj->GetDrawObj(), true);
418 m_rImp.AddAccessibleObj( pAnchoredObj->GetDrawObj() );
421 aAnchoredObjs.pop_back();
427 // --> adjustment and re-factoring of method
428 void SwDrawView::ObjOrderChanged( SdrObject* pObj, size_t nOldPos,
429 size_t nNewPos )
431 // nothing to do for group members
432 if ( pObj->GetUpGroup() )
434 return;
437 // determine drawing page and assure that the order numbers are correct.
438 SdrPage* pDrawPage = GetModel()->GetPage( 0 );
439 if ( pDrawPage->IsObjOrdNumsDirty() )
440 pDrawPage->RecalcObjOrdNums();
441 const size_t nObjCount = pDrawPage->GetObjCount();
443 SwAnchoredObject* pMovedAnchoredObj =
444 ::GetUserCall( pObj )->GetAnchoredObj( pObj );
445 const SwFlyFrame* pParentAnchoredObj =
446 pMovedAnchoredObj->GetAnchorFrame()->FindFlyFrame();
448 const bool bMovedForward = nOldPos < nNewPos;
450 // assure for a 'child' object, that it doesn't exceed the limits of its 'parent'
451 if ( pParentAnchoredObj )
453 if ( bMovedForward )
455 const size_t nMaxChildOrdNumWithoutMoved =
456 GetMaxChildOrdNum( *pParentAnchoredObj, pMovedAnchoredObj->GetDrawObj() );
457 if ( nNewPos > nMaxChildOrdNumWithoutMoved+1 )
459 // set position to the top of the 'child' object group
460 pDrawPage->SetObjectOrdNum( nNewPos, nMaxChildOrdNumWithoutMoved+1 );
461 nNewPos = nMaxChildOrdNumWithoutMoved+1;
464 else
466 const size_t nParentOrdNum = pParentAnchoredObj->GetDrawObj()->GetOrdNum();
467 if ( nNewPos < nParentOrdNum )
469 // set position to the bottom of the 'child' object group
470 pDrawPage->SetObjectOrdNum( nNewPos, nParentOrdNum );
471 nNewPos = nParentOrdNum;
474 if ( pDrawPage->IsObjOrdNumsDirty() )
475 pDrawPage->RecalcObjOrdNums();
478 // Assure, that object isn't positioned between 'repeated' ones
479 if ( ( bMovedForward && nNewPos < nObjCount - 1 ) ||
480 ( !bMovedForward && nNewPos > 0 ) )
482 const SdrObject* pTmpObj =
483 pDrawPage->GetObj( bMovedForward ? nNewPos - 1 : nNewPos + 1 );
484 if ( pTmpObj )
486 size_t nTmpNewPos( nNewPos );
487 if ( bMovedForward )
489 // move before the top 'repeated' object
490 const sal_uInt32 nTmpMaxOrdNum =
491 ::GetUserCall( pTmpObj )->GetMaxOrdNum();
492 if ( nTmpMaxOrdNum > nNewPos )
493 nTmpNewPos = nTmpMaxOrdNum;
495 else
497 // move behind the bottom 'repeated' object
498 const sal_uInt32 nTmpMinOrdNum =
499 ::GetUserCall( pTmpObj )->GetMinOrdNum();
500 if ( nTmpMinOrdNum < nNewPos )
501 nTmpNewPos = nTmpMinOrdNum;
503 if ( nTmpNewPos != nNewPos )
505 pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
506 nNewPos = nTmpNewPos;
507 pDrawPage->RecalcObjOrdNums();
512 // On move forward, assure that object is moved before its own children.
513 // Only Writer fly frames can have children.
514 if ( dynamic_cast< const SwFlyFrame *>( pMovedAnchoredObj ) != nullptr &&
515 bMovedForward && nNewPos < nObjCount - 1 )
517 sal_uInt32 nMaxChildOrdNum =
518 GetMaxChildOrdNum( *static_cast<const SwFlyFrame*>(pMovedAnchoredObj) );
519 if ( nNewPos < nMaxChildOrdNum )
521 // determine position before the object before its top 'child' object
522 const SdrObject* pTmpObj = pDrawPage->GetObj( nMaxChildOrdNum );
523 size_t nTmpNewPos = ::GetUserCall( pTmpObj )->GetMaxOrdNum() + 1;
524 if ( nTmpNewPos >= nObjCount )
526 --nTmpNewPos;
528 // assure, that determined position isn't between 'repeated' objects
529 pTmpObj = pDrawPage->GetObj( nTmpNewPos );
530 nTmpNewPos = ::GetUserCall( pTmpObj )->GetMaxOrdNum();
531 // apply new position
532 pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
533 nNewPos = nTmpNewPos;
534 pDrawPage->RecalcObjOrdNums();
538 // Assure, that object isn't positioned between nested objects
539 if ( ( bMovedForward && nNewPos < nObjCount - 1 ) ||
540 ( !bMovedForward && nNewPos > 0 ) )
542 size_t nTmpNewPos( nNewPos );
543 const SwFrameFormat* pParentFrameFormat =
544 pParentAnchoredObj ? &(pParentAnchoredObj->GetFrameFormat()) : nullptr;
545 const SdrObject* pTmpObj = pDrawPage->GetObj( nNewPos + 1 );
546 while ( pTmpObj )
548 // #i38563# - assure, that anchor frame exists.
549 // If object is anchored inside a invisible part of the document
550 // (e.g. page header, whose page style isn't applied, or hidden
551 // section), no anchor frame exists.
552 const SwFrame* pTmpAnchorFrame = lcl_FindAnchor( pTmpObj, true );
553 const SwFlyFrame* pTmpParentObj = pTmpAnchorFrame
554 ? pTmpAnchorFrame->FindFlyFrame() : nullptr;
555 if ( pTmpParentObj &&
556 &(pTmpParentObj->GetFrameFormat()) != pParentFrameFormat )
558 if ( bMovedForward )
560 nTmpNewPos = ::GetUserCall( pTmpObj )->GetMaxOrdNum();
561 pTmpObj = pDrawPage->GetObj( nTmpNewPos + 1 );
563 else
565 nTmpNewPos = ::GetUserCall( pTmpParentObj->GetDrawObj() )
566 ->GetMinOrdNum();
567 pTmpObj = pTmpParentObj->GetDrawObj();
570 else
571 break;
573 if ( nTmpNewPos != nNewPos )
575 pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
576 nNewPos = nTmpNewPos;
577 pDrawPage->RecalcObjOrdNums();
581 // setup collection of moved 'child' objects to move its 'repeated' objects.
582 std::vector< SdrObject* > aMovedChildObjs;
584 // move 'children' accordingly
585 if ( dynamic_cast< const SwFlyFrame *>( pMovedAnchoredObj ) != nullptr )
587 const SwFlyFrame* pFlyFrame = static_cast<SwFlyFrame*>(pMovedAnchoredObj);
589 // adjustments for accessibility API
590 m_rImp.DisposeAccessibleFrame( pFlyFrame );
591 m_rImp.AddAccessibleFrame( pFlyFrame );
593 const sal_uInt32 nChildNewPos = bMovedForward ? nNewPos : nNewPos+1;
594 size_t i = bMovedForward ? nOldPos : nObjCount-1;
597 SdrObject* pTmpObj = pDrawPage->GetObj( i );
598 if ( pTmpObj == pObj )
599 break;
601 // #i38563# - assure, that anchor frame exists.
602 // If object is anchored inside a invisible part of the document
603 // (e.g. page header, whose page style isn't applied, or hidden
604 // section), no anchor frame exists.
605 const SwFrame* pTmpAnchorFrame = lcl_FindAnchor( pTmpObj, true );
606 const SwFlyFrame* pTmpParentObj = pTmpAnchorFrame
607 ? pTmpAnchorFrame->FindFlyFrame() : nullptr;
608 if ( pTmpParentObj &&
609 ( ( pTmpParentObj == pFlyFrame ) ||
610 ( pFlyFrame->IsUpperOf( *pTmpParentObj ) ) ) )
612 // move child object.,
613 pDrawPage->SetObjectOrdNum( i, nChildNewPos );
614 pDrawPage->RecalcObjOrdNums();
615 // collect 'child' object
616 aMovedChildObjs.push_back( pTmpObj );
617 // adjustments for accessibility API
618 if ( dynamic_cast< const SwVirtFlyDrawObj *>( pTmpObj ) != nullptr )
620 const SwFlyFrame *pTmpFlyFrame =
621 static_cast<SwVirtFlyDrawObj*>(pTmpObj)->GetFlyFrame();
622 m_rImp.DisposeAccessibleFrame( pTmpFlyFrame );
623 m_rImp.AddAccessibleFrame( pTmpFlyFrame );
625 else
627 m_rImp.DisposeAccessibleObj(pTmpObj, true);
628 m_rImp.AddAccessibleObj( pTmpObj );
631 else
633 // adjust loop counter
634 if ( bMovedForward )
635 ++i;
636 else if ( !bMovedForward && i > 0 )
637 --i;
640 } while ( ( bMovedForward && i < ( nObjCount - aMovedChildObjs.size() ) ) ||
641 ( !bMovedForward && i > ( nNewPos + aMovedChildObjs.size() ) ) );
643 else
645 // adjustments for accessibility API
646 m_rImp.DisposeAccessibleObj(pObj, true);
647 m_rImp.AddAccessibleObj( pObj );
650 MoveRepeatedObjs( *pMovedAnchoredObj, aMovedChildObjs );
653 bool SwDrawView::TakeDragLimit( SdrDragMode eMode,
654 tools::Rectangle& rRect ) const
656 const SdrMarkList &rMrkList = GetMarkedObjectList();
657 bool bRet = false;
658 if( 1 == rMrkList.GetMarkCount() )
660 const SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
661 SwRect aRect;
662 if( ::CalcClipRect( pObj, aRect, eMode == SdrDragMode::Move ) )
664 rRect = aRect.SVRect();
665 bRet = true;
668 return bRet;
671 const SwFrame* SwDrawView::CalcAnchor()
673 const SdrMarkList &rMrkList = GetMarkedObjectList();
674 if ( rMrkList.GetMarkCount() != 1 )
675 return nullptr;
677 SdrObject* pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
679 //Search for paragraph bound objects, otherwise only the
680 //current anchor. Search only if we currently drag.
681 const SwFrame* pAnch;
682 tools::Rectangle aMyRect;
683 const bool bFly = dynamic_cast< const SwVirtFlyDrawObj *>( pObj ) != nullptr;
684 if ( bFly )
686 pAnch = static_cast<SwVirtFlyDrawObj*>(pObj)->GetFlyFrame()->GetAnchorFrame();
687 aMyRect = static_cast<SwVirtFlyDrawObj*>(pObj)->GetFlyFrame()->getFrameArea().SVRect();
689 else
691 SwDrawContact *pC = static_cast<SwDrawContact*>(GetUserCall(pObj));
692 // determine correct anchor position for 'virtual' drawing objects.
693 // #i26791#
694 pAnch = pC->GetAnchorFrame( pObj );
695 if( !pAnch )
697 pC->ConnectToLayout();
698 // determine correct anchor position for 'virtual' drawing objects.
699 // #i26791#
700 pAnch = pC->GetAnchorFrame( pObj );
702 aMyRect = pObj->GetSnapRect();
705 const bool bTopRight = pAnch && ( ( pAnch->IsVertical() &&
706 !pAnch->IsVertLR() ) ||
707 pAnch->IsRightToLeft() );
708 const Point aMyPt = bTopRight ? aMyRect.TopRight() : aMyRect.TopLeft();
710 Point aPt;
711 if ( IsAction() )
713 if ( !TakeDragObjAnchorPos( aPt, bTopRight ) )
714 return nullptr;
716 else
718 tools::Rectangle aRect = pObj->GetSnapRect();
719 aPt = bTopRight ? aRect.TopRight() : aRect.TopLeft();
722 if ( aPt != aMyPt )
724 if ( pAnch && pAnch->IsContentFrame() )
726 // allow drawing objects in header/footer,
727 // but exclude control objects.
728 bool bBodyOnly = CheckControlLayer( pObj );
729 pAnch = ::FindAnchor( static_cast<const SwContentFrame*>(pAnch), aPt, bBodyOnly );
731 else if ( !bFly )
733 const SwRect aRect( aPt.getX(), aPt.getY(), 1, 1 );
735 SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
736 if ( pContact->GetAnchorFrame( pObj ) &&
737 pContact->GetAnchorFrame( pObj )->IsPageFrame() )
738 pAnch = pContact->GetPageFrame();
739 else
740 pAnch = pContact->FindPage( aRect );
743 if( pAnch && !pAnch->IsProtected() )
744 m_aAnchorPoint = pAnch->GetFrameAnchorPos( ::HasWrap( pObj ) );
745 else
746 pAnch = nullptr;
747 return pAnch;
750 void SwDrawView::ShowDragAnchor()
752 SdrHdl* pHdl = maHdlList.GetHdl(SdrHdlKind::Anchor);
753 if ( ! pHdl )
754 pHdl = maHdlList.GetHdl(SdrHdlKind::Anchor_TR);
756 if(pHdl)
758 CalcAnchor();
759 pHdl->SetPos(m_aAnchorPoint);
763 void SwDrawView::MarkListHasChanged()
765 Imp().GetShell()->DrawSelChanged();
766 FmFormView::MarkListHasChanged();
769 // #i7672#
770 void SwDrawView::ModelHasChanged()
772 // The ModelHasChanged() call in DrawingLayer also updates
773 // a eventually active text edit view (OutlinerView). This also leads
774 // to newly setting the background color for that edit view. Thus,
775 // this method rescues the current background color if a OutlinerView
776 // exists and re-establishes it then. To be more safe, the OutlinerView
777 // will be fetched again (maybe textedit has ended).
778 OutlinerView* pView = GetTextEditOutlinerView();
779 Color aBackColor;
780 bool bColorWasSaved(false);
782 if(pView)
784 aBackColor = pView->GetBackgroundColor();
785 bColorWasSaved = true;
788 // call parent
789 FmFormView::ModelHasChanged();
791 if(bColorWasSaved)
793 pView = GetTextEditOutlinerView();
795 if(pView)
797 pView->SetBackgroundColor(aBackColor);
802 void SwDrawView::MakeVisible( const tools::Rectangle &rRect, vcl::Window & )
804 OSL_ENSURE( m_rImp.GetShell()->GetWin(), "MakeVisible, unknown Window");
805 m_rImp.GetShell()->MakeVisible( SwRect( rRect ) );
808 void SwDrawView::CheckPossibilities()
810 FmFormView::CheckPossibilities();
812 //In addition to the existing flags of the objects themselves,
813 //which are evaluated by the DrawingEngine, other circumstances
814 //lead to a protection.
815 //Objects that are anchored in frames need to be protected
816 //if the content of the frame is protected.
817 //OLE-Objects may themselves wish a resize protection (StarMath)
819 const SdrMarkList &rMrkList = GetMarkedObjectList();
820 bool bProtect = false;
821 bool bSzProtect = false;
822 bool bRotate(false);
824 for ( size_t i = 0; !bProtect && i < rMrkList.GetMarkCount(); ++i )
826 const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
827 const SwFrame *pFrame = nullptr;
828 if ( auto pVirtFlyDrawObj = dynamic_cast< const SwVirtFlyDrawObj *>( pObj ) )
830 const SwFlyFrame *pFly = pVirtFlyDrawObj->GetFlyFrame();
831 if ( pFly )
833 pFrame = pFly->GetAnchorFrame();
834 if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
836 const SwNoTextFrame *const pNTF(static_cast<const SwNoTextFrame*>(pFly->Lower()));
837 const SwOLENode *const pOLENd = pNTF->GetNode()->GetOLENode();
838 const SwGrfNode *const pGrfNd = pNTF->GetNode()->GetGrfNode();
840 if ( pOLENd )
842 const uno::Reference < embed::XEmbeddedObject > xObj = const_cast< SwOLEObj& >(pOLENd->GetOLEObj()).GetOleRef();
844 if ( xObj.is() )
846 // --> improvement for the future, when more
847 // than one Writer fly frame can be selected.
849 // TODO/LATER: retrieve Aspect - from where?!
850 bSzProtect |= ( embed::EmbedMisc::EMBED_NEVERRESIZE & xObj->getStatus( embed::Aspects::MSOLE_CONTENT ) ) != 0;
852 // #i972: protect position if it is a Math object anchored 'as char' and baseline alignment is activated
853 SwDoc* pDoc = Imp().GetShell()->GetDoc();
854 const bool bProtectMathPos = SotExchange::IsMath( xObj->getClassID() )
855 && RndStdIds::FLY_AS_CHAR == pFly->GetFormat()->GetAnchor().GetAnchorId()
856 && pDoc->GetDocumentSettingManager().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT );
857 if (bProtectMathPos)
858 bMoveProtect = true;
861 else if(pGrfNd)
863 // RotGrfFlyFrame: GraphicNode allows rotation(s). The loop ew are in stops
864 // as soon as bMoveProtect is set, but since rotation is valid only with
865 // a single object selected this makes no difference
866 bRotate = true;
871 else
873 SwDrawContact *pC = static_cast<SwDrawContact*>(GetUserCall(pObj));
874 if ( pC )
875 pFrame = pC->GetAnchorFrame( pObj );
877 if ( pFrame )
878 bProtect = pFrame->IsProtected(); //Frames, areas etc.
880 SwFrameFormat* pFrameFormat( ::FindFrameFormat( const_cast<SdrObject*>(pObj) ) );
881 if ( !pFrameFormat )
883 OSL_FAIL( "<SwDrawView::CheckPossibilities()> - missing frame format" );
884 bProtect = true;
886 else if ((RndStdIds::FLY_AS_CHAR == pFrameFormat->GetAnchor().GetAnchorId()) &&
887 rMrkList.GetMarkCount() > 1 )
889 bProtect = true;
893 bMoveProtect |= bProtect;
894 bResizeProtect |= bProtect || bSzProtect;
896 // RotGrfFlyFrame: allow rotation when SwGrfNode is selected and not size protected
897 bRotateFreeAllowed |= bRotate && !bProtect;
898 bRotate90Allowed |= bRotateFreeAllowed;
901 /// replace marked <SwDrawVirtObj>-objects by its reference object for delete marked objects.
902 void SwDrawView::ReplaceMarkedDrawVirtObjs( SdrMarkView& _rMarkView )
904 SdrPageView* pDrawPageView = _rMarkView.GetSdrPageView();
905 const SdrMarkList& rMarkList = _rMarkView.GetMarkedObjectList();
907 if( rMarkList.GetMarkCount() )
909 // collect marked objects in a local data structure
910 std::vector<SdrObject*> aMarkedObjs;
911 for( size_t i = 0; i < rMarkList.GetMarkCount(); ++i )
913 SdrObject* pMarkedObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
914 aMarkedObjs.push_back( pMarkedObj );
916 // unmark all objects
917 _rMarkView.UnmarkAllObj();
918 // re-mark objects, but for marked <SwDrawVirtObj>-objects marked its
919 // reference object.
920 while ( !aMarkedObjs.empty() )
922 SdrObject* pMarkObj = aMarkedObjs.back();
923 if ( dynamic_cast< const SwDrawVirtObj *>( pMarkObj ) != nullptr )
925 SdrObject* pRefObj = &(static_cast<SwDrawVirtObj*>(pMarkObj)->ReferencedObj());
926 if ( !_rMarkView.IsObjMarked( pRefObj ) )
928 _rMarkView.MarkObj( pRefObj, pDrawPageView );
931 else
933 _rMarkView.MarkObj( pMarkObj, pDrawPageView );
936 aMarkedObjs.pop_back();
938 // sort marked list in order to assure consistent state in drawing layer
939 _rMarkView.SortMarkedObjects();
943 SfxViewShell* SwDrawView::GetSfxViewShell() const
945 return m_rImp.GetShell()->GetSfxViewShell();
948 void SwDrawView::DeleteMarked()
950 SwDoc* pDoc = Imp().GetShell()->GetDoc();
951 SwRootFrame *pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
952 if ( pTmpRoot )
953 pTmpRoot->StartAllAction();
954 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
955 // replace marked <SwDrawVirtObj>-objects by its reference objects.
957 SdrPageView* pDrawPageView = m_rImp.GetPageView();
958 if ( pDrawPageView )
960 SdrMarkView* pMarkView = &(pDrawPageView->GetView());
961 if ( pMarkView )
963 ReplaceMarkedDrawVirtObjs( *pMarkView );
968 // Check what textboxes have to be deleted afterwards.
969 const SdrMarkList& rMarkList = GetMarkedObjectList();
970 std::vector<SwFrameFormat*> aTextBoxesToDelete;
971 for (size_t i = 0; i < rMarkList.GetMarkCount(); ++i)
973 SdrObject *pObject = rMarkList.GetMark(i)->GetMarkedSdrObj();
974 SwDrawContact* pDrawContact = static_cast<SwDrawContact*>(GetUserCall(pObject));
975 SwFrameFormat* pFormat = pDrawContact->GetFormat();
976 if (SwFrameFormat* pTextBox = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
977 aTextBoxesToDelete.push_back(pTextBox);
980 if ( pDoc->DeleteSelection( *this ) )
982 FmFormView::DeleteMarked();
983 ::FrameNotify( Imp().GetShell(), FLY_DRAG_END );
985 // Only delete these now: earlier deletion would clear the mark list as well.
986 for (std::vector<SwFrameFormat*>::iterator i = aTextBoxesToDelete.begin(); i != aTextBoxesToDelete.end(); ++i)
987 pDoc->getIDocumentLayoutAccess().DelLayoutFormat(*i);
989 pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
990 if( pTmpRoot )
991 pTmpRoot->EndAllAction();
994 // support enhanced text edit for draw objects
995 SdrUndoManager* SwDrawView::getSdrUndoManagerForEnhancedTextEdit() const
997 SwDoc* pDoc = Imp().GetShell()->GetDoc();
999 return pDoc ? dynamic_cast< SdrUndoManager* >(&(pDoc->GetUndoManager())) : nullptr;
1002 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */