tdf#161332 sw: fix missing selection of floating table
[LibreOffice.git] / sw / source / core / frmedt / feshview.cxx
blobc10a87110d8e82c9e36ffb94f873481fd55b3af7
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 <svx/constructhelper.hxx>
22 #include <svx/strings.hrc>
23 #include <svx/sdrobjectfilter.hxx>
24 #include <svx/svddrgmt.hxx>
25 #include <svx/svditer.hxx>
26 #include <svx/svdobj.hxx>
27 #include <svx/svdouno.hxx>
28 #include <svx/svdogrp.hxx>
29 #include <svx/svdocirc.hxx>
30 #include <svx/svdopath.hxx>
31 #include <svx/sxciaitm.hxx>
32 #include <svx/svdocapt.hxx>
33 #include <svx/xlnwtit.hxx>
34 #include <svx/xlnstwit.hxx>
35 #include <svx/xlnedwit.hxx>
36 #include <svx/xlnedit.hxx>
37 #include <svx/xlnstit.hxx>
38 #include <svx/svdomeas.hxx>
39 #include <svx/sdtagitm.hxx>
40 #include <svx/sdtacitm.hxx>
41 #include <svx/sdtaaitm.hxx>
42 #include <editeng/opaqitem.hxx>
43 #include <editeng/protitem.hxx>
44 #include <svx/svdpage.hxx>
45 #include <svx/svdpagv.hxx>
46 #include <svx/dialmgr.hxx>
47 #include <tools/globname.hxx>
48 #include <sot/exchange.hxx>
49 #include <IDocumentDrawModelAccess.hxx>
50 #include <IDocumentSettingAccess.hxx>
51 #include <DocumentSettingManager.hxx>
52 #include <IDocumentState.hxx>
53 #include <IDocumentLayoutAccess.hxx>
54 #include <drawdoc.hxx>
55 #include <textboxhelper.hxx>
56 #include <frmfmt.hxx>
57 #include <frmatr.hxx>
58 #include <frmtool.hxx>
59 #include <fmtfsize.hxx>
60 #include <fmtanchr.hxx>
61 #include <fmtornt.hxx>
62 #include <fmtsrnd.hxx>
63 #include <fmtcntnt.hxx>
64 #include <fmtflcnt.hxx>
65 #include <fmtcnct.hxx>
66 #include <swmodule.hxx>
67 #include <fesh.hxx>
68 #include <rootfrm.hxx>
69 #include <pagefrm.hxx>
70 #include <sectfrm.hxx>
71 #include <rowfrm.hxx>
72 #include <doc.hxx>
73 #include <IDocumentUndoRedo.hxx>
74 #include <dview.hxx>
75 #include <dflyobj.hxx>
76 #include <dcontact.hxx>
77 #include <viewimp.hxx>
78 #include <flyfrm.hxx>
79 #include <pam.hxx>
80 #include <ndole.hxx>
81 #include <ndgrf.hxx>
82 #include <ndtxt.hxx>
83 #include <viewopt.hxx>
84 #include <swundo.hxx>
85 #include <notxtfrm.hxx>
86 #include <txtfrm.hxx>
87 #include <mdiexp.hxx>
88 #include <sortedobjs.hxx>
89 #include <HandleAnchorNodeChg.hxx>
90 #include <basegfx/polygon/b2dpolygon.hxx>
91 #include <comphelper/lok.hxx>
92 #include <sfx2/lokhelper.hxx>
93 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
94 #include <calbck.hxx>
95 #include <flyfrms.hxx>
96 #include <basegfx/polygon/b2dpolygontools.hxx>
97 #include <svx/svxids.hrc>
98 #include <osl/diagnose.h>
100 #include <com/sun/star/embed/EmbedMisc.hpp>
101 #include <com/sun/star/embed/Aspects.hpp>
102 #include <com/sun/star/embed/XEmbeddedObject.hpp>
104 #include <svx/srchdlg.hxx>
106 #define SCROLLVAL 75
108 using namespace com::sun::star;
110 SwFlyFrame *GetFlyFromMarked( const SdrMarkList *pLst, SwViewShell *pSh )
112 if ( !pLst )
113 pLst = pSh->HasDrawView() ? &pSh->Imp()->GetDrawView()->GetMarkedObjectList():nullptr;
115 if ( pLst && pLst->GetMarkCount() == 1 )
117 SdrObject *pO = pLst->GetMark( 0 )->GetMarkedSdrObj();
118 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pO))
119 return pVirtO->GetFlyFrame();
121 return nullptr;
124 static void lcl_GrabCursor( SwFEShell* pSh, SwFlyFrame* pOldSelFly, SwFrameFormat* pNewDrawFormat = nullptr)
126 const SwFrameFormat *pFlyFormat = pSh->SelFlyGrabCursor();
127 if( pFlyFormat && !pSh->ActionPend() &&
128 (!pOldSelFly || pOldSelFly->GetFormat() != pFlyFormat) )
130 // now call set macro if applicable
131 pSh->GetFlyMacroLnk().Call( static_cast<const SwFlyFrameFormat*>(pFlyFormat) );
132 // if a dialog was started inside a macro, then
133 // MouseButtonUp arrives at macro and not to us. Therefore
134 // flag is always set here and will never be switched to
135 // respective Shell !!!!!!!
137 g_bNoInterrupt = false;
139 else if( !pFlyFormat || RES_DRAWFRMFMT == pFlyFormat->Which() )
141 // --> assure consistent cursor
142 pSh->KillPams();
143 pSh->ClearMark();
144 if (pNewDrawFormat)
146 // If we selected a draw shape format, move the cursor to its anchor position.
147 // SetCursor() may pick something inside, which is not wanted: code later assumes that
148 // the cursor is at the anchor point if a shape is selected.
149 const SwPosition* pContentAnchor = pNewDrawFormat->GetAnchor().GetContentAnchor();
150 if (pContentAnchor)
152 pSh->SetSelection(SwPaM(*pContentAnchor));
155 else
157 pSh->SetCursor( pSh->Imp()->GetDrawView()->GetAllMarkedRect().TopLeft(), true);
162 bool SwFEShell::SelectObj( const Point& rPt, sal_uInt8 nFlag, SdrObject *pObj )
164 SwDrawView *pDView = Imp()->GetDrawView();
165 if(!pDView)
166 return false;
167 CurrShell aCurr( this );
168 StartAction(); // action is necessary to assure only one AttrChgdNotify
169 // (e.g. due to Unmark->MarkListHasChgd) arrives
171 const SdrMarkList &rMrkList = pDView->GetMarkedObjectList();
172 const bool bHadSelection = rMrkList.GetMarkCount();
173 const bool bAddSelect = 0 != (SW_ADD_SELECT & nFlag);
174 const bool bEnterGroup = 0 != (SW_ENTER_GROUP & nFlag);
175 SwFlyFrame* pOldSelFly = nullptr;
176 const Point aOldPos( pDView->GetAllMarkedRect().TopLeft() );
178 if( bHadSelection )
180 // call Unmark when !bAddSelect or if fly was selected
181 bool bUnmark = !bAddSelect;
183 if ( rMrkList.GetMarkCount() == 1 )
185 // if fly was selected, deselect it first
186 pOldSelFly = ::GetFlyFromMarked( &rMrkList, this );
187 if ( pOldSelFly )
189 const sal_uInt16 nType = GetCntType();
190 if( nType != CNT_TXT || (SW_LEAVE_FRAME & nFlag) ||
191 ( pOldSelFly->GetFormat()->GetProtect().IsContentProtected()
192 && !IsReadOnlyAvailable() ))
194 // If a fly is deselected, which contains graphic, OLE or
195 // otherwise, the cursor should be removed from it.
196 // Similar if a fly with protected content is deselected.
197 // For simplicity we put the cursor next to the upper-left
198 // corner.
199 Point aPt( pOldSelFly->getFrameArea().Pos() );
200 aPt.setX(aPt.getX() - 1);
201 bool bUnLockView = !IsViewLocked();
202 LockView( true );
203 SetCursor( aPt, true );
204 if( bUnLockView )
205 LockView( false );
207 if ( nType & CNT_GRF &&
208 static_cast<SwNoTextFrame*>(pOldSelFly->Lower())->HasAnimation() )
210 GetWin()->Invalidate( pOldSelFly->getFrameArea().SVRect() );
213 // Cancel crop mode
214 if ( SdrDragMode::Crop == GetDragMode() )
215 SetDragMode( SdrDragMode::Move );
217 bUnmark = true;
220 if ( bUnmark )
222 pDView->UnmarkAll();
223 if (pOldSelFly)
224 pOldSelFly->SelectionHasChanged(this);
227 else
229 KillPams();
230 ClearMark();
233 if ( pObj )
235 OSL_ENSURE( !bEnterGroup, "SW_ENTER_GROUP is not supported" );
236 pDView->MarkObj( pObj, Imp()->GetPageView() );
238 else
240 // tolerance limit of Drawing-SS
241 const auto nHdlSizePixel = Imp()->GetDrawView()->GetMarkHdlSizePixel();
242 const short nMinMove = static_cast<short>(GetOut()->PixelToLogic(Size(nHdlSizePixel/2, 0)).Width());
243 pDView->MarkObj( rPt, nMinMove, bAddSelect, bEnterGroup );
246 const bool bRet = 0 != rMrkList.GetMarkCount();
248 if ( rMrkList.GetMarkCount() > 1 )
250 // It sucks if Drawing objects were selected and now
251 // additionally a fly is selected.
252 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
254 SdrObject *pTmpObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
255 bool bForget = dynamic_cast<const SwVirtFlyDrawObj*>( pTmpObj) != nullptr;
256 if( bForget )
258 pDView->UnmarkAll();
259 pDView->MarkObj( pTmpObj, Imp()->GetPageView(), bAddSelect, bEnterGroup );
260 break;
265 if (rMrkList.GetMarkCount() == 1)
267 SwFlyFrame* pSelFly = ::GetFlyFromMarked(&rMrkList, this);
268 if (pSelFly && pSelFly->IsFlySplitAllowed())
270 auto pMaster = static_cast<SwFlyAtContentFrame*>(pSelFly);
271 while (pMaster->IsFollow())
273 pMaster = pMaster->GetPrecede();
275 if (pMaster != pSelFly)
277 // A follow fly frame is selected, select the master instead. Selection of a follow
278 // would not be ideal, since one can't customize its vertical position (always
279 // starts at the top of the page).
280 pDView->UnmarkAll();
281 pDView->MarkObj(pMaster->DrawObj(), Imp()->GetPageView(), bAddSelect, bEnterGroup);
286 if ( rMrkList.GetMarkCount() == 1 )
288 SwFlyFrame *pSelFly = ::GetFlyFromMarked( &rMrkList, this );
289 if (pSelFly)
290 pSelFly->SelectionHasChanged(this);
293 SwFrameFormat* pNewDrawFormat = nullptr;
294 if (!(nFlag & SW_ALLOW_TEXTBOX))
296 // If the fly frame is a textbox of a shape, then select the shape instead.
297 for (size_t i = 0; i < rMrkList.GetMarkCount(); ++i)
299 SdrObject* pObject = rMrkList.GetMark(i)->GetMarkedSdrObj();
300 SwContact* pContact = GetUserCall(pObject);
301 if (!pContact)
303 continue;
306 SwFrameFormat* pFormat = pContact->GetFormat();
307 if (SwFrameFormat* pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT))
309 SdrObject* pShape = pShapeFormat->FindSdrObject();
310 pDView->UnmarkAll();
311 pDView->MarkObj(pShape, Imp()->GetPageView(), bAddSelect, bEnterGroup);
312 // Remember that this frame format was marked for selection.
313 pNewDrawFormat = pShapeFormat;
314 break;
319 if ( bRet )
321 ::lcl_GrabCursor(this, pOldSelFly, pNewDrawFormat);
322 if ( GetCntType() & CNT_GRF )
324 const SwFlyFrame *pTmp = GetFlyFromMarked( &rMrkList, this );
325 OSL_ENSURE( pTmp, "Graphic without Fly" );
326 if ( pTmp && static_cast<const SwNoTextFrame*>(pTmp->Lower())->HasAnimation() )
327 static_cast<const SwNoTextFrame*>(pTmp->Lower())->StopAnimation( GetOut() );
330 else if ( !pOldSelFly && bHadSelection )
331 SetCursor( aOldPos, true);
333 if( bRet || !bHadSelection )
334 CallChgLnk();
336 // update status line
337 ::FrameNotify( this, bRet ? FLY_DRAG_START : FLY_DRAG_END );
339 EndAction();
340 return bRet;
344 * Description: MoveAnchor( nDir ) looked for an another Anchor for
345 * the selected drawing object (or fly frame) in the given direction.
346 * An object "as character" doesn't moves anyway.
347 * A page bounded object could move to the previous/next page with up/down,
348 * an object bounded "at paragraph" moves to the previous/next paragraph, too.
349 * An object bounded "at character" moves to the previous/next paragraph
350 * with up/down and to the previous/next character with left/right.
351 * If the anchor for at paragraph/character bounded objects has vertical or
352 * right_to_left text direction, the directions for up/down/left/right will
353 * interpreted accordingly.
354 * An object bounded "at fly" takes the center of the actual anchor and looks
355 * for the nearest fly frame in the given direction.
358 static bool LessX( Point const & aPt1, Point const & aPt2, bool bOld )
360 return aPt1.getX() < aPt2.getX()
361 || ( aPt1.getX() == aPt2.getX()
362 && ( aPt1.getY() < aPt2.getY()
363 || ( aPt1.getY() == aPt2.getY() && bOld ) ) );
365 static bool LessY( Point const & aPt1, Point const & aPt2, bool bOld )
367 return aPt1.getY() < aPt2.getY()
368 || ( aPt1.getY() == aPt2.getY()
369 && ( aPt1.getX() < aPt2.getX()
370 || ( aPt1.getX() == aPt2.getX() && bOld ) ) );
373 bool SwFEShell::MoveAnchor( SwMove nDir )
375 if (!Imp()->GetDrawView())
376 return false;
377 const SdrMarkList& pMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
378 if (1 != pMrkList.GetMarkCount())
379 return false;
381 SdrObject *pObj = pMrkList.GetMark( 0 )->GetMarkedSdrObj();
382 SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
383 if (!pContact)
384 return false;
386 SwFrame* pOld;
387 SwFlyFrame* pFly = nullptr;
388 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
390 pFly = pVirtO->GetFlyFrame();
391 pOld = pFly->AnchorFrame();
393 else
394 pOld = pContact->GetAnchorFrame( pObj );
395 bool bRet = false;
396 if( pOld )
398 SwFrame* pNew = pOld;
399 // #i28701#
400 SwAnchoredObject* pAnchoredObj = pContact->GetAnchoredObj( pObj );
401 SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat();
402 SwFormatAnchor aAnch( pFormat->GetAnchor() );
403 RndStdIds nAnchorId = aAnch.GetAnchorId();
404 if ( RndStdIds::FLY_AS_CHAR == nAnchorId )
405 return false;
406 if( pOld->IsVertical() )
408 if( pOld->IsTextFrame() )
410 switch( nDir ) {
411 case SwMove::UP: nDir = SwMove::LEFT; break;
412 case SwMove::DOWN: nDir = SwMove::RIGHT; break;
413 case SwMove::LEFT: nDir = SwMove::DOWN; break;
414 case SwMove::RIGHT: nDir = SwMove::UP; break;
416 if( pOld->IsRightToLeft() )
418 if( nDir == SwMove::LEFT )
419 nDir = SwMove::RIGHT;
420 else if( nDir == SwMove::RIGHT )
421 nDir = SwMove::LEFT;
425 switch ( nAnchorId ) {
426 case RndStdIds::FLY_AT_PAGE:
428 OSL_ENSURE( pOld->IsPageFrame(), "Wrong anchor, page expected." );
429 if( SwMove::UP == nDir )
430 pNew = pOld->GetPrev();
431 else if( SwMove::DOWN == nDir )
432 pNew = pOld->GetNext();
433 if( pNew && pNew != pOld )
435 aAnch.SetPageNum( static_cast<SwPageFrame*>(pNew)->GetPhyPageNum() );
436 bRet = true;
438 break;
440 case RndStdIds::FLY_AT_CHAR:
442 OSL_ENSURE(pOld->IsTextFrame(), "Wrong anchor, text frame expected.");
443 if( SwMove::LEFT == nDir || SwMove::RIGHT == nDir )
445 SwPosition pos = *aAnch.GetContentAnchor();
446 SwTextFrame *const pOldFrame(static_cast<SwTextFrame*>(pOld));
447 TextFrameIndex const nAct(pOldFrame->MapModelToViewPos(pos));
448 if( SwMove::LEFT == nDir )
450 bRet = true;
451 if( nAct )
453 pos = pOldFrame->MapViewToModelPos(nAct - TextFrameIndex(1));
455 else
456 nDir = SwMove::UP;
458 else
460 TextFrameIndex const nMax(pOldFrame->GetText().getLength());
461 if( nAct < nMax )
463 bRet = true;
464 pos = pOldFrame->MapViewToModelPos(nAct + TextFrameIndex(1));
466 else
467 nDir = SwMove::DOWN;
469 if( pos != *aAnch.GetContentAnchor())
470 aAnch.SetAnchor( &pos );
472 [[fallthrough]];
474 case RndStdIds::FLY_AT_PARA:
476 OSL_ENSURE(pOld->IsTextFrame(), "Wrong anchor, text frame expected.");
477 if( SwMove::UP == nDir )
478 pNew = pOld->FindPrev();
479 else if( SwMove::DOWN == nDir )
480 pNew = pOld->FindNext();
481 if( pNew && pNew != pOld && pNew->IsContentFrame() )
483 SwTextFrame *const pNewFrame(static_cast<SwTextFrame*>(pNew));
484 SwPosition const pos = pNewFrame->MapViewToModelPos(
485 TextFrameIndex(
486 (bRet && pNewFrame->GetText().getLength() != 0)
487 ? pNewFrame->GetText().getLength() - 1
488 : 0));
489 aAnch.SetAnchor( &pos );
490 bRet = true;
492 else if( SwMove::UP == nDir || SwMove::DOWN == nDir )
493 bRet = false;
494 break;
496 case RndStdIds::FLY_AT_FLY:
498 OSL_ENSURE( pOld->IsFlyFrame(), "Wrong anchor, fly frame expected.");
499 SwPageFrame* pPage = pOld->FindPageFrame();
500 OSL_ENSURE( pPage, "Where's my page?" );
501 SwFlyFrame* pNewFly = nullptr;
502 if( pPage->GetSortedObjs() )
504 bool bOld = false;
505 Point aCenter( pOld->getFrameArea().Left() + pOld->getFrameArea().Width()/2,
506 pOld->getFrameArea().Top() + pOld->getFrameArea().Height()/2 );
507 Point aBest;
508 for(SwAnchoredObject* pAnchObj : *pPage->GetSortedObjs())
510 if( auto pTmp = pAnchObj->DynCastFlyFrame() )
512 if( pTmp == pOld )
513 bOld = true;
514 else
516 const SwFlyFrame* pCheck = pFly ? pTmp : nullptr;
517 while( pCheck )
519 if( pCheck == pFly )
520 break;
521 const SwFrame *pNxt = pCheck->GetAnchorFrame();
522 pCheck = pNxt ? pNxt->FindFlyFrame() : nullptr;
524 if( pCheck || pTmp->IsProtected() )
525 continue;
526 Point aNew( pTmp->getFrameArea().Left() +
527 pTmp->getFrameArea().Width()/2,
528 pTmp->getFrameArea().Top() +
529 pTmp->getFrameArea().Height()/2 );
530 bool bAccept = false;
531 switch( nDir ) {
532 case SwMove::RIGHT:
534 bAccept = LessX( aCenter, aNew, bOld )
535 && ( !pNewFly ||
536 LessX( aNew, aBest, false ) );
537 break;
539 case SwMove::LEFT:
541 bAccept = LessX( aNew, aCenter, !bOld )
542 && ( !pNewFly ||
543 LessX( aBest, aNew, true ) );
544 break;
546 case SwMove::UP:
548 bAccept = LessY( aNew, aCenter, !bOld )
549 && ( !pNewFly ||
550 LessY( aBest, aNew, true ) );
551 break;
553 case SwMove::DOWN:
555 bAccept = LessY( aCenter, aNew, bOld )
556 && ( !pNewFly ||
557 LessY( aNew, aBest, false ) );
558 break;
561 if( bAccept )
563 pNewFly = pTmp;
564 aBest = aNew;
571 if( pNewFly )
573 SwPosition aPos( *pNewFly->GetFormat()->
574 GetContent().GetContentIdx());
575 aAnch.SetAnchor( &aPos );
576 bRet = true;
578 break;
580 default: break;
582 if( bRet )
584 StartAllAction();
585 // --> handle change of anchor node:
586 // if count of the anchor frame also change, the fly frames have to be
587 // re-created. Thus, delete all fly frames except the <this> before the
588 // anchor attribute is change and re-create them afterwards.
590 std::unique_ptr<SwHandleAnchorNodeChg> pHandleAnchorNodeChg;
591 SwFlyFrameFormat* pFlyFrameFormat( dynamic_cast<SwFlyFrameFormat*>(pFormat) );
592 if ( pFlyFrameFormat )
594 pHandleAnchorNodeChg.reset(
595 new SwHandleAnchorNodeChg( *pFlyFrameFormat, aAnch ));
597 pFormat->GetDoc()->SetAttr( aAnch, *pFormat );
599 // #i28701# - no call of method
600 // <CheckCharRectAndTopOfLine()> for to-character anchored
601 // Writer fly frame needed. This method call can cause a
602 // format of the anchor frame, which is no longer intended.
603 // Instead clear the anchor character rectangle and
604 // the top of line values for all to-character anchored objects.
605 pAnchoredObj->ClearCharRectAndTopOfLine();
606 EndAllAction();
609 return bRet;
612 const SdrMarkList* SwFEShell::GetMarkList_() const
614 const SdrMarkList* pMarkList = nullptr;
615 if( Imp()->GetDrawView() != nullptr )
616 pMarkList = &Imp()->GetDrawView()->GetMarkedObjectList();
617 return pMarkList;
620 FrameTypeFlags SwFEShell::GetSelFrameType() const
622 FrameTypeFlags eType;
624 // get marked frame list, and check if anything is selected
625 const SdrMarkList* pMarkList = GetMarkList_();
626 if( pMarkList == nullptr || pMarkList->GetMarkCount() == 0 )
627 eType = FrameTypeFlags::NONE;
628 else
630 // obtain marked item as fly frame; if no fly frame, it must
631 // be a draw object
632 const SwFlyFrame* pFly = ::GetFlyFromMarked(pMarkList, const_cast<SwFEShell*>(this));
633 if ( pFly != nullptr )
635 if( pFly->IsFlyLayFrame() )
636 eType = FrameTypeFlags::FLY_FREE;
637 else if( pFly->IsFlyAtContentFrame() )
638 eType = FrameTypeFlags::FLY_ATCNT;
639 else
641 OSL_ENSURE( pFly->IsFlyInContentFrame(), "New frametype?" );
642 eType = FrameTypeFlags::FLY_INCNT;
645 else
646 eType = FrameTypeFlags::DRAWOBJ;
649 return eType;
652 // does the draw selection contain a control?
653 bool SwFEShell::IsSelContainsControl() const
655 bool bRet = false;
657 // basically, copy the mechanism from GetSelFrameType(), but call
658 // CheckControl... if you get a drawing object
659 const SdrMarkList* pMarkList = GetMarkList_();
660 if( pMarkList != nullptr && pMarkList->GetMarkCount() == 1 )
662 // if we have one marked object, get the SdrObject and check
663 // whether it contains a control
664 const SdrObject* pSdrObject = pMarkList->GetMark( 0 )->GetMarkedSdrObj();
665 bRet = pSdrObject && ::CheckControlLayer( pSdrObject );
667 return bRet;
670 void SwFEShell::ScrollTo( const Point &rPt )
672 const SwRect aRect( rPt, rPt );
673 if ( IsScrollMDI( this, aRect ) &&
674 (!Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() ||
675 Imp()->IsDragPossible( rPt )) )
677 ScrollMDI( this, aRect, SCROLLVAL, SCROLLVAL );
681 void SwFEShell::SetDragMode( SdrDragMode eDragMode )
683 if ( Imp()->HasDrawView() )
684 Imp()->GetDrawView()->SetDragMode( eDragMode );
687 SdrDragMode SwFEShell::GetDragMode() const
689 SdrDragMode nRet = SdrDragMode(0);
690 if ( Imp()->HasDrawView() )
692 nRet = Imp()->GetDrawView()->GetDragMode();
694 return nRet;
697 void SwFEShell::StartCropImage()
699 if ( !Imp()->HasDrawView() )
701 return;
703 SdrView *pView = Imp()->GetDrawView();
704 if (!pView) return;
706 const SdrMarkList &rMarkList = pView->GetMarkedObjectList();
707 if( 0 == rMarkList.GetMarkCount() ) {
708 // No object selected
709 return;
712 // If more than a single SwVirtFlyDrawObj is selected, select only the first SwVirtFlyDrawObj
713 if ( rMarkList.GetMarkCount() > 1 )
715 for ( size_t i = 0; i < rMarkList.GetMarkCount(); ++i )
717 SdrObject *pTmpObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
718 bool bForget = dynamic_cast<const SwVirtFlyDrawObj*>( pTmpObj) != nullptr;
719 if( bForget )
721 pView->UnmarkAll();
722 pView->MarkObj( pTmpObj, Imp()->GetPageView() );
723 break;
728 // Activate CROP mode
729 pView->SetEditMode( SdrViewEditMode::Edit );
730 SetDragMode( SdrDragMode::Crop );
733 void SwFEShell::BeginDrag( const Point* pPt, bool bIsShift)
735 SdrView *pView = Imp()->GetDrawView();
736 if ( pView && pView->GetMarkedObjectList().GetMarkCount() != 0 )
738 m_pChainFrom.reset();
739 m_pChainTo.reset();
740 SdrHdl* pHdl = pView->PickHandle( *pPt );
741 if (pView->BegDragObj( *pPt, nullptr, pHdl ))
742 pView->GetDragMethod()->SetShiftPressed( bIsShift );
743 ::FrameNotify( this );
747 void SwFEShell::Drag( const Point *pPt, bool )
749 OSL_ENSURE( Imp()->HasDrawView(), "Drag without DrawView?" );
750 if ( HasDrawViewDrag() )
752 ScrollTo( *pPt );
753 Imp()->GetDrawView()->MovDragObj( *pPt );
754 Imp()->GetDrawView()->ShowDragAnchor();
755 ::FrameNotify( this );
759 void SwFEShell::EndDrag()
761 OSL_ENSURE( Imp()->HasDrawView(), "EndDrag without DrawView?" );
762 SdrView *pView = Imp()->GetDrawView();
763 if ( !pView->IsDragObj() )
764 return;
766 for(SwViewShell& rSh : GetRingContainer())
767 rSh.StartAction();
769 StartUndo( SwUndoId::START );
771 // #50778# Bug during dragging: In StartAction a HideShowXor is called.
772 // In EndDragObj() this is reversed, for no reason and even wrong.
773 // To restore consistency we should bring up the Xor again.
775 // Reanimation from the hack #50778 to fix bug #97057
776 // May be not the best solution, but the one with lowest risc at the moment.
777 // pView->ShowShownXor( GetOut() );
779 pView->EndDragObj();
781 // DrawUndo on to flyframes are not stored
782 // The flys change the flag.
783 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
784 ChgAnchor( RndStdIds::FLY_AT_PARA, true );
786 EndUndo( SwUndoId::END );
788 for(SwViewShell& rSh : GetRingContainer())
790 rSh.EndAction();
791 if( auto pCursorShell = dynamic_cast<SwCursorShell *>(&rSh) )
792 pCursorShell->CallChgLnk();
795 GetDoc()->getIDocumentState().SetModified();
796 ::FrameNotify( this );
799 void SwFEShell::BreakDrag()
801 OSL_ENSURE( Imp()->HasDrawView(), "BreakDrag without DrawView?" );
802 if( HasDrawViewDrag() )
803 Imp()->GetDrawView()->BrkDragObj();
804 SetChainMarker();
807 // If a fly is selected, pulls the crsr in the first ContentFrame
808 const SwFrameFormat* SwFEShell::SelFlyGrabCursor()
810 if ( Imp()->HasDrawView() )
812 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
813 SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
815 if( pFly )
817 SwContentFrame *pCFrame = pFly->ContainsContent();
818 if ( pCFrame )
820 // --> assure, that the cursor is consistent.
821 KillPams();
822 ClearMark();
823 SwPaM *pCursor = GetCursor();
825 if (pCFrame->IsTextFrame())
827 *pCursor->GetPoint() = static_cast<SwTextFrame *>(pCFrame)
828 ->MapViewToModelPos(TextFrameIndex(0));
830 else
832 assert(pCFrame->IsNoTextFrame());
833 SwContentNode *const pCNode = static_cast<SwNoTextFrame *>(pCFrame)->GetNode();
834 pCursor->GetPoint()->Assign(*pCNode);
837 SwRect& rChrRect = const_cast<SwRect&>(GetCharRect());
838 rChrRect = pFly->getFramePrintArea();
839 rChrRect.Pos() += pFly->getFrameArea().Pos();
840 GetCursorDocPos() = rChrRect.Pos();
842 return pFly->GetFormat();
845 return nullptr;
848 // Selection to above/below (Z-Order)
849 static void lcl_NotifyNeighbours( const SdrMarkList *pLst )
851 // Rules for evasion have changed.
852 // 1. The environment of the fly and everything inside should be notified
853 // 2. The content of the frame itself has to be notified
854 // 3. Frames displaced by the frame have to be notified
855 // 4. Also Drawing objects can displace frames
856 for( size_t j = 0; j < pLst->GetMarkCount(); ++j )
858 SwPageFrame *pPage;
859 bool bCheckNeighbours = false;
860 sal_Int16 aHori = text::HoriOrientation::NONE;
861 SwRect aRect;
862 SdrObject *pO = pLst->GetMark( j )->GetMarkedSdrObj();
863 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pO))
865 SwFlyFrame *pFly = pVirtO->GetFlyFrame();
867 const SwFormatHoriOrient &rHori = pFly->GetFormat()->GetHoriOrient();
868 aHori = rHori.GetHoriOrient();
869 if( text::HoriOrientation::NONE != aHori && text::HoriOrientation::CENTER != aHori &&
870 pFly->IsFlyAtContentFrame() )
872 bCheckNeighbours = true;
873 pFly->InvalidatePos();
874 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFly);
875 aFrm.Pos().AdjustY(1 );
878 pPage = pFly->FindPageFrame();
879 aRect = pFly->getFrameArea();
881 else
883 SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pO));
884 if (!pContact)
885 continue;
887 SwFrame* pAnch = pContact->GetAnchorFrame( pO );
888 if( !pAnch )
889 continue;
890 pPage = pAnch->FindPageFrame();
891 // #i68520# - naming changed
892 aRect = GetBoundRectOfAnchoredObj( pO );
895 const size_t nCount = pPage->GetSortedObjs() ? pPage->GetSortedObjs()->size() : 0;
896 for ( size_t i = 0; i < nCount; ++i )
898 SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
899 SwFlyFrame* pAct = pAnchoredObj->DynCastFlyFrame();
900 if ( !pAct )
901 continue;
903 SwRect aTmpCalcPnt( pAct->getFramePrintArea() );
904 aTmpCalcPnt += pAct->getFrameArea().Pos();
905 if ( aRect.Overlaps( aTmpCalcPnt ) )
907 SwContentFrame *pCnt = pAct->ContainsContent();
908 while ( pCnt )
910 aTmpCalcPnt = pCnt->getFramePrintArea();
911 aTmpCalcPnt += pCnt->getFrameArea().Pos();
912 if ( aRect.Overlaps( aTmpCalcPnt ) )
913 static_cast<SwFrame*>(pCnt)->Prepare( PrepareHint::FlyFrameAttributesChanged );
914 pCnt = pCnt->GetNextContentFrame();
917 if ( bCheckNeighbours && pAct->IsFlyAtContentFrame() )
919 const SwFormatHoriOrient &rH = pAct->GetFormat()->GetHoriOrient();
920 if ( rH.GetHoriOrient() == aHori &&
921 pAct->getFrameArea().Top() <= aRect.Bottom() &&
922 pAct->getFrameArea().Bottom() >= aRect.Top() )
924 pAct->InvalidatePos();
925 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pAct);
926 aFrm.Pos().AdjustY(1 );
933 void SwFEShell::SetLineEnds(SfxItemSet& rAttr, SdrObject const & rObj, sal_uInt16 nSlotId)
935 ConstructHelper::SetLineEnds(rAttr, rObj, nSlotId, 100);
938 void SwFEShell::SelectionToTop( bool bTop )
940 OSL_ENSURE( Imp()->HasDrawView(), "SelectionToTop without DrawView?" );
941 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
942 OSL_ENSURE( rMrkList.GetMarkCount(), "No object selected." );
944 SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
945 if ( pFly && pFly->IsFlyInContentFrame() )
946 return;
948 StartAllAction();
949 if ( bTop )
950 Imp()->GetDrawView()->PutMarkedToTop();
951 else
952 Imp()->GetDrawView()->MovMarkedToTop();
953 ::lcl_NotifyNeighbours( &rMrkList );
955 // Does the selection contain a textbox?
956 for (size_t i = 0; i < rMrkList.GetMarkCount(); i++)
957 if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
958 // Get the textbox-shape
959 if (auto pFormat = FindFrameFormat(pObj))
961 // If it has not textframe skip...
962 if (!SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, pObj))
963 continue;
964 // If it has a textframe so it is a textbox, get its page
965 if (auto pDrwModel
966 = pFormat->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel())
967 // Not really understood why everything is on page 0...
968 // but it is easier to handle sdrobjects, that's true
969 if (auto pPage = pDrwModel->GetPage(0))
971 // nShift: it means how many layers the pObj have to be shifted up,
972 // in order not to interfere with other shapes and textboxes.
973 // Situations:
974 // - The next shape has textframe: This shape have to shifted with
975 // two layers.
976 // - The next shape has not got textframe: This shape have to be
977 // shifted only one layer up.
978 // - The next shape is null:
979 // - This shape is already at heaven: Only the textframe have
980 // to be adjusted.
981 sal_uInt32 nShift = 0;
982 // Get the one level higher object (note: can be nullptr!)
983 const auto pNextObj = pPage->SetObjectOrdNum(pObj->GetOrdNum() + 1, pObj->GetOrdNum() + 1);
984 // If there is a higher object (not null)...
985 if (pNextObj)
987 // One level shift is necessary
988 nShift++;
989 // If this object is a textbox, two level increasing needed
990 // (one for the shape and one for the frame)
991 if (auto pNextFormat = FindFrameFormat(pNextObj))
992 if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT, pNextObj)
993 || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
994 nShift++;
996 // Set the new z-order.
997 pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() + nShift);
999 // The shape is on the right level, correct the layer of the frame
1000 SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat, pObj);
1003 GetDoc()->getIDocumentState().SetModified();
1004 EndAllAction();
1007 void SwFEShell::SelectionToBottom( bool bBottom )
1009 OSL_ENSURE( Imp()->HasDrawView(), "SelectionToBottom without DrawView?" );
1010 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1011 OSL_ENSURE( rMrkList.GetMarkCount(), "No object selected." );
1013 SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
1014 if ( pFly && pFly->IsFlyInContentFrame() )
1015 return;
1017 StartAllAction();
1018 if ( bBottom )
1019 Imp()->GetDrawView()->PutMarkedToBtm();
1020 else
1021 Imp()->GetDrawView()->MovMarkedToBtm();
1022 ::lcl_NotifyNeighbours( &rMrkList );
1024 // If the selection has textbox
1025 for(size_t i = 0; i < rMrkList.GetMarkCount(); i++)
1026 if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
1027 // Get the shape of the textbox
1028 if (auto pFormat = FindFrameFormat(pObj))
1030 // If the shape has not textframes skip.
1031 if (!SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, pObj))
1032 continue;
1033 // If has, move the shape to correct level with...
1034 if (auto pDrwModel
1035 = pFormat->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel())
1036 if (auto pPage = pDrwModel->GetPage(0))
1038 const auto pNextObj = pPage->SetObjectOrdNum(pObj->GetOrdNum() - 1, pObj->GetOrdNum() - 1);
1039 // If there is a lower object (not null)...
1040 if (pNextObj)
1042 // If the lower has no textframe, just do nothing, else move by one lower
1043 if (auto pNextFormat = FindFrameFormat(pNextObj))
1044 if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT, pNextObj)
1045 || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
1046 pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() - 1);
1049 // And set correct layer for the selected textbox.
1050 SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat, pObj);
1053 GetDoc()->getIDocumentState().SetModified();
1054 EndAllAction();
1057 // Object above/below the document? 2 Controls, 1 Heaven, 0 Hell,
1058 // SDRLAYER_NOTFOUND Ambiguous
1059 SdrLayerID SwFEShell::GetLayerId() const
1061 if ( !Imp()->HasDrawView() )
1062 return SDRLAYER_NOTFOUND;
1064 SdrLayerID nRet = SDRLAYER_NOTFOUND;
1065 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1066 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
1068 const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
1069 if( !pObj )
1070 continue;
1071 if ( nRet == SDRLAYER_NOTFOUND )
1072 nRet = pObj->GetLayer();
1073 else if ( nRet != pObj->GetLayer() )
1075 return SDRLAYER_NOTFOUND;
1078 return nRet;
1081 // Object above/below the document
1082 // Note: only visible objects can be marked. Thus, objects with invisible
1083 // layer IDs have not to be considered.
1084 // If <SwFEShell> exists, layout exists!!
1085 void SwFEShell::ChangeOpaque( SdrLayerID nLayerId )
1087 if ( !Imp()->HasDrawView() )
1088 return;
1090 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1091 const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess();
1092 // correct type of <nControls>
1093 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
1095 SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
1096 if( !pObj )
1097 continue;
1098 // or group objects containing controls.
1099 // --> #i113730#
1100 // consider that a member of a drawing group has been selected.
1101 const SwContact* pContact = ::GetUserCall( pObj );
1102 OSL_ENSURE( pContact && pContact->GetMaster(), "<SwFEShell::ChangeOpaque(..)> - missing contact or missing master object at contact!" );
1103 const bool bControlObj = ( pContact && pContact->GetMaster() )
1104 ? ::CheckControlLayer( pContact->GetMaster() )
1105 : ::CheckControlLayer( pObj );
1106 if ( !bControlObj && pObj->GetLayer() != nLayerId )
1108 pObj->SetLayer( nLayerId );
1109 InvalidateWindows( SwRect( pObj->GetCurrentBoundRect() ) );
1110 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
1112 SwFormat *pFormat = pVirtO->GetFlyFrame()->GetFormat();
1113 SvxOpaqueItem aOpa( pFormat->GetOpaque() );
1114 aOpa.SetValue( nLayerId == rIDDMA.GetHellId() );
1115 pFormat->SetFormatAttr( aOpa );
1116 // If pObj has textframe, put its textframe to the right level
1117 if (auto pTextBx = FindFrameFormat(pObj))
1118 SwTextBoxHelper::DoTextBoxZOrderCorrection(pTextBx, pObj);
1122 GetDoc()->getIDocumentState().SetModified();
1125 void SwFEShell::SelectionToHeaven()
1127 ChangeOpaque( getIDocumentDrawModelAccess().GetHeavenId() );
1130 void SwFEShell::SelectionToHell()
1132 ChangeOpaque( getIDocumentDrawModelAccess().GetHellId() );
1135 size_t SwFEShell::IsObjSelected() const
1137 if ( IsFrameSelected() || !Imp()->HasDrawView() )
1138 return 0;
1140 return Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount();
1143 bool SwFEShell::IsFrameSelected() const
1145 if ( !Imp()->HasDrawView() )
1146 return false;
1147 else
1148 return nullptr != ::GetFlyFromMarked( &Imp()->GetDrawView()->GetMarkedObjectList(),
1149 const_cast<SwFEShell*>(this) );
1152 bool SwFEShell::IsObjSelected( const SdrObject& rObj ) const
1154 if ( IsFrameSelected() || !Imp()->HasDrawView() )
1155 return false;
1156 else
1157 return Imp()->GetDrawView()->IsObjMarked( &rObj );
1160 bool SwFEShell::IsRotationOfSwGrfNodePossible() const
1162 // RotGrfFlyFrame: check if RotationMode is possible
1163 const SdrView *pSdrView = Imp()->GetDrawView();
1165 if(pSdrView)
1167 const SdrMarkList& rList(pSdrView->GetMarkedObjectList());
1169 if(1 == rList.GetMarkCount())
1171 const SwVirtFlyDrawObj* pVirtFlyDraw(dynamic_cast< const SwVirtFlyDrawObj* >(rList.GetMark(0)->GetMarkedSdrObj()));
1173 if(nullptr != pVirtFlyDraw)
1175 return pVirtFlyDraw->ContainsSwGrfNode();
1180 return false;
1183 bool SwFEShell::IsObjSameLevelWithMarked(const SdrObject* pObj) const
1185 if (pObj)
1187 const SdrMarkList& aMarkList = Imp()->GetDrawView()->GetMarkedObjectList();
1188 if (aMarkList.GetMarkCount() == 0)
1190 return true;
1192 SdrMark* pM=aMarkList.GetMark(0);
1193 if (pM)
1195 SdrObject* pMarkObj = pM->GetMarkedSdrObj();
1196 if (pMarkObj && pMarkObj->getParentSdrObjectFromSdrObject() == pObj->getParentSdrObjectFromSdrObject())
1197 return true;
1200 return false;
1203 void SwFEShell::EndTextEdit()
1205 // Terminate the TextEditMode. If required (default if the object
1206 // does not contain any more text and does not carry attributes) the object
1207 // is deleted. All other objects marked are preserved.
1209 OSL_ENSURE( Imp()->HasDrawView() && Imp()->GetDrawView()->IsTextEdit(),
1210 "EndTextEdit a no Object" );
1212 StartAllAction();
1213 SdrView *pView = Imp()->GetDrawView();
1214 SdrObject *pObj = pView->GetTextEditObject();
1215 SdrObjUserCall* pUserCall = GetUserCall(pObj);
1216 if( nullptr != pUserCall )
1218 SdrObject *pTmp = static_cast<SwContact*>(pUserCall)->GetMaster();
1219 if( !pTmp )
1220 pTmp = pObj;
1221 pUserCall->Changed( *pTmp, SdrUserCallType::Resize, pTmp->GetLastBoundRect() );
1223 if ( !pObj->getParentSdrObjectFromSdrObject() )
1225 if ( SdrEndTextEditKind::ShouldBeDeleted == pView->SdrEndTextEdit(true) )
1227 if ( pView->GetMarkedObjectList().GetMarkCount() > 1 )
1229 SdrMarkList aSave( pView->GetMarkedObjectList() );
1230 aSave.DeleteMark( aSave.FindObject( pObj ) );
1231 if ( aSave.GetMarkCount() )
1233 pView->UnmarkAll();
1234 pView->MarkObj( pObj, Imp()->GetPageView() );
1236 DelSelectedObj();
1237 for ( size_t i = 0; i < aSave.GetMarkCount(); ++i )
1238 pView->MarkObj( aSave.GetMark( i )->GetMarkedSdrObj(), Imp()->GetPageView() );
1240 else
1241 DelSelectedObj();
1244 else
1245 pView->SdrEndTextEdit();
1247 if (comphelper::LibreOfficeKit::isActive())
1248 SfxLokHelper::notifyOtherViews(GetSfxViewShell(), LOK_CALLBACK_VIEW_LOCK, "rectangle", "EMPTY"_ostr);
1250 EndAllAction();
1253 bool SwFEShell::IsInsideSelectedObj( const Point &rPt )
1255 if( Imp()->HasDrawView() )
1257 SwDrawView *pDView = Imp()->GetDrawView();
1259 if( pDView->GetMarkedObjectList().GetMarkCount() &&
1260 pDView->IsMarkedObjHit( rPt ) )
1262 return true;
1265 return false;
1268 bool SwFEShell::IsObjSelectable( const Point& rPt )
1270 CurrShell aCurr(this);
1271 SwDrawView *pDView = Imp()->GetDrawView();
1272 bool bRet = false;
1273 if( pDView )
1275 SdrPageView* pPV;
1276 const auto nOld = pDView->GetHitTolerancePixel();
1277 pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
1279 bRet = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE) != nullptr;
1280 pDView->SetHitTolerancePixel( nOld );
1282 return bRet;
1285 SdrObject* SwFEShell::GetObjAt( const Point& rPt )
1287 SdrObject* pRet = nullptr;
1288 CurrShell aCurr(this);
1289 SwDrawView *pDView = Imp()->GetDrawView();
1290 if( pDView )
1292 SdrPageView* pPV;
1293 const auto nOld = pDView->GetHitTolerancePixel();
1294 pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
1296 pRet = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE);
1297 pDView->SetHitTolerancePixel( nOld );
1299 return pRet;
1302 // Test if there is an object at that position and if it should be selected.
1303 bool SwFEShell::ShouldObjectBeSelected(const Point& rPt, bool *pSelectFrameInsteadOfCroppedImage)
1305 CurrShell aCurr(this);
1306 SwDrawView *pDrawView = Imp()->GetDrawView();
1307 bool bRet(false);
1309 if(pDrawView)
1311 SdrPageView* pPV;
1312 const auto nOld(pDrawView->GetHitTolerancePixel());
1313 sal_uInt16 nHitTol = pDrawView->getHitTolLog();
1315 pDrawView->SetHitTolerancePixel(pDrawView->GetMarkHdlSizePixel()/2);
1316 SdrObject* pObj = pDrawView->PickObj(rPt, nHitTol, pPV, SdrSearchOptions::PICKMARKABLE);
1317 pDrawView->SetHitTolerancePixel(nOld);
1319 if (pObj)
1321 bRet = true;
1322 const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess();
1323 // #i89920#
1324 // Do not select object in background which is overlapping this text
1325 // at the given position.
1326 bool bObjInBackground( false );
1328 if ( pObj->GetLayer() == rIDDMA.GetHellId() )
1330 if (const SwContact* pContact = ::GetUserCall( pObj ))
1332 const SwAnchoredObject* pAnchoredObj = pContact->GetAnchoredObj( pObj );
1333 const SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat();
1334 const SwFormatSurround& rSurround = pFormat->GetSurround();
1335 if ( rSurround.GetSurround() == css::text::WrapTextMode_THROUGH )
1337 bObjInBackground = true;
1342 if ( bObjInBackground )
1344 const SwPageFrame* pPageFrame = GetLayout()->GetPageAtPos( rPt );
1345 if( pPageFrame )
1347 const SwContentFrame* pContentFrame( pPageFrame->ContainsContent() );
1348 while ( pContentFrame )
1350 if ( pContentFrame->UnionFrame().Contains( rPt ) )
1352 const SwTextFrame* pTextFrame = pContentFrame->DynCastTextFrame();
1353 if ( pTextFrame )
1355 SwPosition aPos(GetDoc()->GetNodes());
1356 Point aTmpPt( rPt );
1357 if (pTextFrame->GetKeyCursorOfst(&aPos, aTmpPt))
1359 SwRect aCursorCharRect;
1360 if (pTextFrame->GetCharRect(aCursorCharRect,
1361 aPos))
1363 if ( aCursorCharRect.Overlaps( SwRect( pObj->GetLastBoundRect() ) ) )
1365 bRet = false;
1370 else
1372 bRet = false;
1374 break;
1377 pContentFrame = pContentFrame->GetNextContentFrame();
1382 // Don't select header / footer objects in body edition and vice-versa
1383 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
1384 if (pContact && !pContact->ObjAnchoredAtPage() )
1386 const SwNode& rAnchorNode = pContact->GetAnchorNode();
1387 bool bInHdrFtr = GetDoc()->IsInHeaderFooter( rAnchorNode );
1388 if (IsHeaderFooterEdit() != bInHdrFtr)
1390 bRet = false;
1394 if ( bRet )
1396 const SdrPage* pPage = rIDDMA.GetDrawModel()->GetPage(0);
1397 for(auto it = pPage->begin() + pObj->GetOrdNum() + 1; it != pPage->end(); ++it)
1399 SdrObject *pCandidate = it->get();
1401 SwVirtFlyDrawObj* pDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pCandidate);
1402 if (pDrawObj && pDrawObj->GetCurrentBoundRect().Contains(rPt))
1404 bRet = false;
1405 break;
1410 // within table row, where image cropped by the fixed table row height,
1411 // click position must be in the cell, where the image anchored as character
1412 if ( bRet && pContact && pContact->ObjAnchoredAsChar() )
1414 if ( const SwTableBox *pBox = pContact->GetAnchorNode().GetTableBox() )
1416 SwIterator<SwRowFrame, SwFormat> aIter( *pBox->GetUpper()->GetFrameFormat() );
1417 bool bContainsClickPosition = false;
1418 for (SwRowFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
1420 const SwRect& rRect = pFrame->getFrameArea();
1421 // click inside the cell which contains the cropped image
1422 if ( rRect.Contains( rPt ) )
1424 // click next to the right cell border
1425 if ( pSelectFrameInsteadOfCroppedImage &&
1426 !rRect.Contains( Point(rPt.X() + 2 * nHitTol, rPt.Y()) ) )
1428 *pSelectFrameInsteadOfCroppedImage = true;
1430 bContainsClickPosition = true;
1431 break;
1433 else if ( pSelectFrameInsteadOfCroppedImage && (
1434 // Click outside of the right border
1435 rRect.Contains( Point(rPt.X() - 2 * nHitTol, rPt.Y()) ) ||
1436 // or handle the right border of bottom cells covered by the cropped
1437 // image instead putting the cursor inside the cell (see tdf#160842).
1438 // Click inside the same table, or outside its right border
1439 ( pFrame->GetUpper() && pFrame->GetUpper()->getFrameArea().Contains(
1440 Point(rPt.X() - 2 * nHitTol, rPt.Y()) ) &&
1441 // and the click inside is next to the right table border
1442 !rRect.Contains( Point(rPt.X() + 2 * nHitTol, rRect.Bottom()) )
1443 ) ) )
1445 *pSelectFrameInsteadOfCroppedImage = true;
1446 bContainsClickPosition = true;
1449 if ( !bContainsClickPosition )
1450 bRet = false;
1456 return bRet;
1460 * If an object was selected, we assume its upper-left corner
1461 * otherwise the middle of the current CharRects.
1462 * Does the object include a control or groups,
1463 * which comprise only controls
1465 static bool lcl_IsControlGroup( const SdrObject *pObj )
1467 bool bRet = false;
1468 if(dynamic_cast<const SdrUnoObj*>( pObj) != nullptr)
1469 bRet = true;
1470 else if( auto pObjGroup = dynamic_cast<const SdrObjGroup*>( pObj) )
1472 bRet = true;
1473 const SdrObjList *pLst = pObjGroup->GetSubList();
1474 for (const rtl::Reference<SdrObject>& pChildObj : *pLst)
1475 if( !::lcl_IsControlGroup( pChildObj.get() ) )
1476 return false;
1478 return bRet;
1481 namespace
1483 class MarkableObjectsOnly : public svx::ISdrObjectFilter
1485 public:
1486 explicit MarkableObjectsOnly( SdrPageView* i_pPV )
1487 :m_pPV( i_pPV )
1491 virtual bool includeObject( const SdrObject& i_rObject ) const override
1493 return m_pPV && m_pPV->GetView().IsObjMarkable( &i_rObject, m_pPV );
1496 private:
1497 SdrPageView* m_pPV;
1501 const SdrObject* SwFEShell::GetBestObject(bool bNext, GotoObjFlags eType, bool bFlat,
1502 const svx::ISdrObjectFilter* pFilter,
1503 bool* pbWrapped)
1505 if (pbWrapped)
1506 *pbWrapped = false;
1508 if( !Imp()->HasDrawView() )
1509 return nullptr;
1511 const SdrObject *pBest = nullptr,
1512 *pTop = nullptr;
1514 const tools::Long nTmp = bNext ? LONG_MAX : 0;
1515 Point aBestPos( nTmp, nTmp );
1516 Point aTopPos( nTmp, nTmp );
1517 Point aCurPos;
1518 Point aPos;
1519 bool bNoDraw((GotoObjFlags::DrawAny & eType) == GotoObjFlags::NONE);
1520 bool bNoFly((GotoObjFlags::FlyAny & eType) == GotoObjFlags::NONE);
1522 if( !bNoFly && bNoDraw )
1524 SwFlyFrame *pFly = GetCurrFrame( false )->FindFlyFrame();
1525 if( pFly )
1526 pBest = pFly->GetVirtDrawObj();
1528 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1529 SdrPageView* pPV = Imp()->GetDrawView()->GetSdrPageView();
1531 MarkableObjectsOnly aDefaultFilter( pPV );
1532 if ( !pFilter )
1533 pFilter = &aDefaultFilter;
1535 if( !pBest || rMrkList.GetMarkCount() == 1 )
1537 // Determine starting point
1538 SdrObjList* pList = nullptr;
1539 if ( rMrkList.GetMarkCount() )
1541 const SdrObject* pStartObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
1542 if( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>( pStartObj) )
1543 aPos = pVirtFlyDrawObj->GetFlyFrame()->getFrameArea().Pos();
1544 else
1545 aPos = pStartObj->GetSnapRect().TopLeft();
1547 // If an object inside a group is selected, we want to
1548 // iterate over the group members.
1549 if ( ! pStartObj->GetUserCall() )
1550 pList = pStartObj->getParentSdrObjListFromSdrObject();
1552 else
1554 // If no object is selected, we check if we just entered a group.
1555 // In this case we want to iterate over the group members.
1556 aPos = GetCharRect().Center();
1557 const SdrObject* pStartObj = pPV ? pPV->GetCurrentGroup() : nullptr;
1558 if ( dynamic_cast<const SdrObjGroup*>( pStartObj) )
1559 pList = pStartObj->GetSubList();
1562 if ( ! pList )
1564 // Here we are if
1565 // A No object has been selected and no group has been entered or
1566 // B An object has been selected and it is not inside a group
1567 pList = getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 );
1570 OSL_ENSURE( pList, "No object list to iterate" );
1572 SdrObjListIter aObjIter( pList, bFlat ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups );
1573 while ( aObjIter.IsMore() )
1575 SdrObject* pObj = aObjIter.Next();
1576 SwVirtFlyDrawObj *pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
1577 if( ( bNoFly && pVirtO ) ||
1578 ( bNoDraw && !pVirtO ) ||
1579 // Ignore TextBoxes of draw shapes here, so that
1580 // SwFEShell::SelectObj() won't jump back on this list, meaning
1581 // we never jump to the next draw shape.
1582 (pVirtO && pVirtO->IsTextBox()) ||
1583 ( eType == GotoObjFlags::DrawSimple && lcl_IsControlGroup( pObj ) ) ||
1584 ( eType == GotoObjFlags::DrawControl && !lcl_IsControlGroup( pObj ) ) ||
1585 !pFilter->includeObject( *pObj ) )
1586 continue;
1587 if (pVirtO)
1589 SwFlyFrame *pFly = pVirtO->GetFlyFrame();
1590 if( GotoObjFlags::FlyAny != ( GotoObjFlags::FlyAny & eType ) )
1592 switch ( eType )
1594 case GotoObjFlags::FlyFrame:
1595 if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
1596 continue;
1597 break;
1598 case GotoObjFlags::FlyGrf:
1599 if ( pFly->Lower() &&
1600 (!pFly->Lower()->IsNoTextFrame() ||
1601 !static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetGrfNode()))
1602 continue;
1603 break;
1604 case GotoObjFlags::FlyOLE:
1605 if ( pFly->Lower() &&
1606 (!pFly->Lower()->IsNoTextFrame() ||
1607 !static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetOLENode()))
1608 continue;
1609 break;
1610 default: break;
1613 aCurPos = pFly->getFrameArea().Pos();
1615 else
1616 aCurPos = pObj->GetSnapRect().TopLeft();
1618 // Special case if another object is on same Y.
1619 if( aCurPos != aPos && // only when it is not me
1620 aCurPos.getY() == aPos.getY() && // Y positions equal
1621 (bNext? (aCurPos.getX() > aPos.getX()) : // lies next to me
1622 (aCurPos.getX() < aPos.getX())) ) // " reverse
1624 aBestPos = Point( nTmp, nTmp );
1625 SdrObjListIter aTmpIter( pList, bFlat ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups );
1626 while ( aTmpIter.IsMore() )
1628 SdrObject* pTmpObj = aTmpIter.Next();
1629 pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pTmpObj);
1630 if( ( bNoFly && pVirtO ) || ( bNoDraw && !pVirtO ) )
1631 continue;
1632 if (pVirtO)
1634 aCurPos = pVirtO->GetFlyFrame()->getFrameArea().Pos();
1636 else
1637 aCurPos = pTmpObj->GetCurrentBoundRect().TopLeft();
1639 if( aCurPos != aPos && aCurPos.Y() == aPos.Y() &&
1640 (bNext? (aCurPos.getX() > aPos.getX()) : // lies next to me
1641 (aCurPos.getX() < aPos.getX())) && // " reverse
1642 (bNext? (aCurPos.getX() < aBestPos.getX()) : // better as best
1643 (aCurPos.getX() > aBestPos.getX())) ) // " reverse
1645 aBestPos = aCurPos;
1646 pBest = pTmpObj;
1649 break;
1652 if( (
1653 (bNext? (aPos.getY() < aCurPos.getY()) : // only below me
1654 (aPos.getY() > aCurPos.getY())) && // " reverse
1655 (bNext? (aBestPos.getY() > aCurPos.getY()) : // closer below
1656 (aBestPos.getY() < aCurPos.getY()))
1657 ) || // " reverse
1658 (aBestPos.getY() == aCurPos.getY() &&
1659 (bNext? (aBestPos.getX() > aCurPos.getX()) : // further left
1660 (aBestPos.getX() < aCurPos.getX())))) // " reverse
1663 aBestPos = aCurPos;
1664 pBest = pObj;
1667 if( (bNext? (aTopPos.getY() > aCurPos.getY()) : // higher as best
1668 (aTopPos.getY() < aCurPos.getY())) || // " reverse
1669 (aTopPos.getY() == aCurPos.getY() &&
1670 (bNext? (aTopPos.getX() > aCurPos.getX()) : // further left
1671 (aTopPos.getX() < aCurPos.getX())))) // " reverse
1673 aTopPos = aCurPos;
1674 pTop = pObj;
1677 // unfortunately nothing found
1678 if( bNext ? (aBestPos.getX() == LONG_MAX) : (aBestPos.getX() == 0) )
1680 pBest = pTop;
1681 if (pbWrapped && pBest)
1682 *pbWrapped = true;
1686 return pBest;
1689 bool SwFEShell::GotoObj( bool bNext, GotoObjFlags eType )
1691 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
1693 bool bWrapped(false);
1694 const SdrObject* pBest = GetBestObject(bNext, eType, true, nullptr, &bWrapped);
1696 if ( !pBest )
1698 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
1699 return false;
1702 const SwVirtFlyDrawObj *pVirtO = dynamic_cast<const SwVirtFlyDrawObj*>(pBest);
1703 if (pVirtO)
1705 const SwRect& rFrame = pVirtO->GetFlyFrame()->getFrameArea();
1706 SelectObj( rFrame.Pos(), 0, const_cast<SdrObject*>(pBest) );
1707 if( !ActionPend() )
1708 MakeVisible( rFrame );
1710 else
1712 SelectObj( Point(), 0, const_cast<SdrObject*>(pBest) );
1713 if( !ActionPend() )
1714 MakeVisible( SwRect(pBest->GetCurrentBoundRect()) );
1716 CallChgLnk();
1718 if (bWrapped)
1719 SvxSearchDialogWrapper::SetSearchLabel(bNext ? SearchLabel::EndWrapped :
1720 SearchLabel::StartWrapped);
1722 return true;
1725 bool SwFEShell::BeginCreate( SdrObjKind eSdrObjectKind, const Point &rPos )
1727 bool bRet = false;
1729 if ( !Imp()->HasDrawView() )
1730 Imp()->MakeDrawView();
1732 if ( GetPageNumber( rPos ) )
1734 Imp()->GetDrawView()->SetCurrentObj( eSdrObjectKind );
1735 if ( eSdrObjectKind == SdrObjKind::Caption )
1736 bRet = Imp()->GetDrawView()->BegCreateCaptionObj(
1737 rPos, Size( lMinBorder - MINFLY, lMinBorder - MINFLY ),
1738 GetOut() );
1739 else
1740 bRet = Imp()->GetDrawView()->BegCreateObj( rPos, GetOut() );
1742 if ( bRet )
1744 ::FrameNotify( this, FLY_DRAG_START );
1746 return bRet;
1749 bool SwFEShell::BeginCreate( SdrObjKind eSdrObjectKind, SdrInventor eObjInventor,
1750 const Point &rPos )
1752 bool bRet = false;
1754 if ( !Imp()->HasDrawView() )
1755 Imp()->MakeDrawView();
1757 if ( GetPageNumber( rPos ) )
1759 Imp()->GetDrawView()->SetCurrentObj( eSdrObjectKind, eObjInventor );
1760 bRet = Imp()->GetDrawView()->BegCreateObj( rPos, GetOut() );
1762 if ( bRet )
1763 ::FrameNotify( this, FLY_DRAG_START );
1764 return bRet;
1767 void SwFEShell::MoveCreate( const Point &rPos )
1769 OSL_ENSURE( Imp()->HasDrawView(), "MoveCreate without DrawView?" );
1770 if ( GetPageNumber( rPos ) )
1772 ScrollTo( rPos );
1773 Imp()->GetDrawView()->MovCreateObj( rPos );
1774 ::FrameNotify( this );
1778 bool SwFEShell::EndCreate( SdrCreateCmd eSdrCreateCmd )
1780 // To assure undo-object from the DrawEngine is not stored,
1781 // (we create our own undo-object!), temporarily switch-off Undo
1782 OSL_ENSURE( Imp()->HasDrawView(), "EndCreate without DrawView?" );
1783 if( !Imp()->GetDrawView()->IsGroupEntered() )
1785 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
1787 bool bCreate = Imp()->GetDrawView()->EndCreateObj( eSdrCreateCmd );
1788 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
1790 if ( !bCreate )
1792 ::FrameNotify( this, FLY_DRAG_END );
1793 return false;
1796 if ( eSdrCreateCmd == SdrCreateCmd::NextPoint )
1798 ::FrameNotify( this );
1799 return true;
1801 return ImpEndCreate();
1804 bool SwFEShell::ImpEndCreate()
1806 if (Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() == 0)
1807 return false;
1809 SdrObject& rSdrObj = *Imp()->GetDrawView()->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
1811 if( rSdrObj.GetSnapRect().IsEmpty() )
1813 // preferably we forget the object, only gives problems
1814 Imp()->GetDrawView()->DeleteMarked();
1815 Imp()->GetDrawView()->UnmarkAll();
1816 ::FrameNotify( this, FLY_DRAG_END );
1817 return false;
1820 if( rSdrObj.getParentSdrObjectFromSdrObject() )
1822 Point aTmpPos( rSdrObj.GetSnapRect().TopLeft() );
1823 Point aNewAnchor( rSdrObj.getParentSdrObjectFromSdrObject()->GetAnchorPos() );
1824 // OD 2004-04-05 #i26791# - direct object positioning for group members
1825 rSdrObj.NbcSetRelativePos( aTmpPos - aNewAnchor );
1826 rSdrObj.NbcSetAnchorPos( aNewAnchor );
1827 ::FrameNotify( this );
1828 return true;
1831 LockPaint(LockPaintReason::EndSdrCreate);
1832 StartAllAction();
1834 Imp()->GetDrawView()->UnmarkAll();
1836 const tools::Rectangle &rBound = rSdrObj.GetSnapRect();
1837 Point aPt( rBound.TopRight() );
1839 // default for controls character bound, otherwise paragraph bound.
1840 SwFormatAnchor aAnch;
1841 const SwFrame *pAnch = nullptr;
1842 bool bCharBound = false;
1843 if( dynamic_cast<const SdrUnoObj*>( &rSdrObj) != nullptr )
1845 SwPosition aPos( GetDoc()->GetNodes() );
1846 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
1847 Point aPoint( aPt.getX(), aPt.getY() + rBound.GetHeight()/2 );
1848 GetLayout()->GetModelPositionForViewPoint( &aPos, aPoint, &aState );
1850 // characterbinding not allowed in readonly-content
1851 if( !aPos.GetNode().IsProtect() )
1853 std::pair<Point, bool> const tmp(aPoint, true);
1854 pAnch = aPos.GetNode().GetContentNode()->getLayoutFrame(GetLayout(), &aPos, &tmp);
1855 SwRect aTmp;
1856 pAnch->GetCharRect( aTmp, aPos );
1858 // The crsr should not be too far away
1859 bCharBound = true;
1860 constexpr tools::Long constTwips_1cm = o3tl::toTwips(1, o3tl::Length::cm);
1861 tools::Rectangle aRect( aTmp.SVRect() );
1862 // Extend by 1 cm in each direction
1863 aRect.AdjustLeft(-constTwips_1cm);
1864 aRect.AdjustTop(-constTwips_1cm);
1865 aRect.AdjustRight(constTwips_1cm);
1866 aRect.AdjustBottom(constTwips_1cm);
1868 if( !aRect.Overlaps( rBound ) && !::GetHtmlMode( GetDoc()->GetDocShell() ))
1869 bCharBound = false;
1871 // anchor in header/footer also not allowed.
1872 if( bCharBound )
1873 bCharBound = !GetDoc()->IsInHeaderFooter( aPos.GetNode() );
1875 if( bCharBound )
1877 aAnch.SetType( RndStdIds::FLY_AS_CHAR );
1878 aAnch.SetAnchor( &aPos );
1883 if( !bCharBound )
1885 // allow native drawing objects in header/footer.
1886 // Thus, set <bBodyOnly> to <false> for these objects using value
1887 // of <nIdent> - value <0xFFFF> indicates control objects, which aren't
1888 // allowed in header/footer.
1889 //bool bBodyOnly = OBJ_NONE != nIdent;
1890 bool bBodyOnly = SdrInventor::Default != rSdrObj.GetObjInventor();
1891 bool bAtPage = false;
1892 const SwFrame* pPage = nullptr;
1893 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
1894 Point aPoint( aPt );
1895 SwPosition aPos( GetDoc()->GetNodes() );
1896 GetLayout()->GetModelPositionForViewPoint( &aPos, aPoint, &aState );
1898 // do not set in ReadnOnly-content
1899 if (aPos.GetNode().IsProtect())
1901 // then only page bound. Or should we
1902 // search the next not-readonly position?
1903 bAtPage = true;
1906 SwContentNode* pCNode = aPos.GetNode().GetContentNode();
1907 std::pair<Point, bool> const tmp(aPoint, false);
1908 pAnch = pCNode ? pCNode->getLayoutFrame(GetLayout(), nullptr, &tmp) : nullptr;
1909 if (!pAnch)
1911 // Hidden content. Anchor to the page instead
1912 bAtPage = true;
1915 if( !bAtPage )
1917 const SwFlyFrame *pTmp = pAnch->FindFlyFrame();
1918 if( pTmp )
1920 const SwFrame* pTmpFrame = pAnch;
1921 SwRect aBound( rBound );
1922 while( pTmp )
1924 if( pTmp->getFrameArea().Contains( aBound ) )
1926 if( !bBodyOnly || !pTmp->FindFooterOrHeader() )
1927 pPage = pTmpFrame;
1928 break;
1930 pTmp = pTmp->GetAnchorFrame()
1931 ? pTmp->GetAnchorFrame()->FindFlyFrame()
1932 : nullptr;
1933 pTmpFrame = pTmp;
1937 if( !pPage )
1938 pPage = pAnch->FindPageFrame();
1940 // Always via FindAnchor, to assure the frame will be bound
1941 // to the previous. With GetCrsOfst we can also reach the next. THIS IS WRONG.
1942 pAnch = ::FindAnchor( pPage, aPt, bBodyOnly );
1943 if (pAnch->IsTextFrame())
1945 std::pair<SwTextNode const*, sal_Int32> const pos(
1946 static_cast<SwTextFrame const*>(pAnch)->MapViewToModel(TextFrameIndex(0)));
1947 aPos.Assign( *pos.first );
1949 else
1951 aPos.Assign( *static_cast<const SwNoTextFrame*>(pAnch)->GetNode() );
1954 // do not set in ReadnOnly-content
1955 if( aPos.GetNode().IsProtect() )
1956 // then only page bound. Or should we
1957 // search the next not-readonly position?
1958 bAtPage = true;
1959 else
1961 aAnch.SetType( RndStdIds::FLY_AT_PARA );
1962 aAnch.SetAnchor( &aPos );
1966 if( bAtPage )
1968 pPage = pAnch ? pAnch->FindPageFrame() : GetLayout()->GetPageAtPos(aPoint);
1970 aAnch.SetType( RndStdIds::FLY_AT_PAGE );
1971 aAnch.SetPageNum( pPage->GetPhyPageNum() );
1972 pAnch = pPage; // page becomes an anchor
1976 SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE,
1977 RES_SURROUND, RES_ANCHOR> aSet( GetDoc()->GetAttrPool() );
1978 aSet.Put( aAnch );
1980 // OD 2004-03-30 #i26791# - determine relative object position
1981 SwTwips nXOffset;
1982 SwTwips nYOffset = rBound.Top() - pAnch->getFrameArea().Top();
1984 if( pAnch->IsVertical() )
1986 nXOffset = nYOffset;
1987 nYOffset = pAnch->getFrameArea().Left()+pAnch->getFrameArea().Width()-rBound.Right();
1989 else if( pAnch->IsRightToLeft() )
1990 nXOffset = pAnch->getFrameArea().Left()+pAnch->getFrameArea().Width()-rBound.Right();
1991 else
1992 nXOffset = rBound.Left() - pAnch->getFrameArea().Left();
1993 if (pAnch->IsTextFrame())
1995 const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnch);
1996 if (pTmp->IsFollow())
1998 do {
1999 pTmp = pTmp->FindMaster();
2000 OSL_ENSURE(pTmp, "Where's my Master?");
2001 // OD 2004-03-30 #i26791# - correction: add frame area height
2002 // of master frames.
2003 nYOffset += pTmp->IsVertical() ?
2004 pTmp->getFrameArea().Width() : pTmp->getFrameArea().Height();
2005 } while (pTmp->IsFollow());
2008 nYOffset -= pTmp->GetBaseVertOffsetForFly(false);
2012 if (SdrInventor::Default == rSdrObj.GetObjInventor() && rSdrObj.GetObjIdentifier() == SdrObjKind::NewFrame)
2014 // For OBJ_NONE a fly is inserted.
2015 const tools::Long nWidth = rBound.Right() - rBound.Left();
2016 const tools::Long nHeight= rBound.Bottom() - rBound.Top();
2017 aSet.Put( SwFormatFrameSize( SwFrameSize::Minimum, std::max( nWidth, tools::Long(MINFLY) ),
2018 std::max( nHeight, tools::Long(MINFLY) )));
2020 SwFormatHoriOrient aHori( nXOffset, text::HoriOrientation::NONE, text::RelOrientation::FRAME );
2021 SwFormatVertOrient aVert( nYOffset, text::VertOrientation::NONE, text::RelOrientation::FRAME );
2022 aSet.Put( SwFormatSurround( css::text::WrapTextMode_PARALLEL ) );
2023 aSet.Put( aHori );
2024 aSet.Put( aVert );
2026 // Quickly store the square
2027 const SwRect aFlyRect( rBound );
2029 // Throw away generated object, now the fly can nicely
2030 // via the available SS be generated.
2031 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false); // see above
2032 // #i52858# - method name changed
2033 SdrPage *pPg = getIDocumentDrawModelAccess().GetOrCreateDrawModel()->GetPage( 0 );
2034 if( !pPg )
2036 SdrModel* pTmpSdrModel = getIDocumentDrawModelAccess().GetDrawModel();
2037 auto pNewPage = pTmpSdrModel->AllocPage( false );
2038 pTmpSdrModel->InsertPage( pNewPage.get() );
2039 pPg = pNewPage.get();
2041 pPg->RecalcObjOrdNums();
2042 pPg->RemoveObject( rSdrObj.GetOrdNumDirect() );
2043 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
2045 SwFlyFrame* pFlyFrame;
2046 if( NewFlyFrame( aSet, true ) &&
2047 ::GetHtmlMode( GetDoc()->GetDocShell() ) &&
2048 nullptr != ( pFlyFrame = GetSelectedFlyFrame() ))
2050 SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT> aHtmlSet( GetDoc()->GetAttrPool() );
2051 // horizontal orientation:
2052 const bool bLeftFrame = aFlyRect.Left() <
2053 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Left(),
2054 bLeftPrt = aFlyRect.Left() + aFlyRect.Width() <
2055 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width()/2;
2056 if( bLeftFrame || bLeftPrt )
2058 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
2059 aHori.SetRelationOrient( bLeftFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
2061 else
2063 const bool bRightFrame = aFlyRect.Left() >
2064 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width();
2065 aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
2066 aHori.SetRelationOrient( bRightFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
2068 aHtmlSet.Put( aHori );
2069 aVert.SetVertOrient( text::VertOrientation::TOP );
2070 aVert.SetRelationOrient( text::RelOrientation::PRINT_AREA );
2071 aHtmlSet.Put( aVert );
2073 GetDoc()->SetAttr( aHtmlSet, *pFlyFrame->GetFormat() );
2076 else
2078 if (rSdrObj.GetName().isEmpty())
2080 bool bRestore = GetDoc()->GetIDocumentUndoRedo().DoesDrawUndo();
2081 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
2082 rSdrObj.MakeNameUnique();
2083 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(bRestore);
2086 aSet.Put( aAnch );
2087 aSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) );
2088 // OD 2004-03-30 #i26791# - set horizontal position
2089 SwFormatHoriOrient aHori( nXOffset, text::HoriOrientation::NONE, text::RelOrientation::FRAME );
2090 aSet.Put( aHori );
2091 // OD 2004-03-30 #i26791# - set vertical position
2092 if( pAnch->IsTextFrame() && static_cast<const SwTextFrame*>(pAnch)->IsFollow() )
2094 const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnch);
2095 do {
2096 pTmp = pTmp->FindMaster();
2097 assert(pTmp && "Where's my Master?");
2098 nYOffset += pTmp->IsVertical() ?
2099 pTmp->getFramePrintArea().Width() : pTmp->getFramePrintArea().Height();
2100 } while ( pTmp->IsFollow() );
2102 SwFormatVertOrient aVert( nYOffset, text::VertOrientation::NONE, text::RelOrientation::FRAME );
2103 aSet.Put( aVert );
2104 SwDrawFrameFormat* pFormat = static_cast<SwDrawFrameFormat*>(getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::DRAW_OBJECT, &aSet ));
2105 // #i36010# - set layout direction of the position
2106 pFormat->SetPositionLayoutDir(
2107 text::PositionLayoutDir::PositionInLayoutDirOfAnchor );
2108 // #i44344#, #i44681# - positioning attributes already set
2109 pFormat->PosAttrSet();
2110 pFormat->SetFormatName(rSdrObj.GetName());
2112 SwDrawContact *pContact = new SwDrawContact( pFormat, &rSdrObj );
2113 // #i35635#
2114 pContact->MoveObjToVisibleLayer( &rSdrObj );
2115 if( bCharBound )
2117 OSL_ENSURE( aAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR, "wrong AnchorType" );
2118 SwTextNode *pNd = aAnch.GetAnchorNode()->GetTextNode();
2119 SwFormatFlyCnt aFormat( pFormat );
2120 pNd->InsertItem(aFormat,
2121 aAnch.GetAnchorContentOffset(), 0 );
2122 SwFormatVertOrient aVertical( pFormat->GetVertOrient() );
2123 aVertical.SetVertOrient( text::VertOrientation::LINE_CENTER );
2124 pFormat->SetFormatAttr( aVertical );
2126 if( pAnch->IsTextFrame() && static_cast<const SwTextFrame*>(pAnch)->IsFollow() )
2128 const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnch);
2129 do {
2130 pTmp = pTmp->FindMaster();
2131 assert(pTmp && "Where's my Master?");
2132 } while( pTmp->IsFollow() );
2133 pAnch = pTmp;
2136 pContact->ConnectToLayout();
2138 // mark object at frame the object is inserted at.
2140 SdrObject* pMarkObj = pContact->GetDrawObjectByAnchorFrame( *pAnch );
2141 if ( pMarkObj )
2143 Imp()->GetDrawView()->MarkObj( pMarkObj, Imp()->GetPageView() );
2145 else
2147 Imp()->GetDrawView()->MarkObj( &rSdrObj, Imp()->GetPageView() );
2152 GetDoc()->getIDocumentState().SetModified();
2154 KillPams();
2155 EndAllActionAndCall();
2156 UnlockPaint();
2157 return true;
2160 void SwFEShell::BreakCreate()
2162 OSL_ENSURE( Imp()->HasDrawView(), "BreakCreate without DrawView?" );
2163 Imp()->GetDrawView()->BrkCreateObj();
2164 ::FrameNotify( this, FLY_DRAG_END );
2167 bool SwFEShell::IsDrawCreate() const
2169 return Imp()->HasDrawView() && Imp()->GetDrawView()->IsCreateObj();
2172 bool SwFEShell::BeginMark( const Point &rPos )
2174 if ( !Imp()->HasDrawView() )
2175 Imp()->MakeDrawView();
2177 if ( GetPageNumber( rPos ) )
2179 SwDrawView* pDView = Imp()->GetDrawView();
2181 if (pDView->HasMarkablePoints())
2182 return pDView->BegMarkPoints( rPos );
2183 else
2185 pDView->BegMarkObj( rPos );
2186 return true;
2189 else
2190 return false;
2193 void SwFEShell::MoveMark( const Point &rPos )
2195 OSL_ENSURE( Imp()->HasDrawView(), "MoveMark without DrawView?" );
2197 if ( GetPageNumber( rPos ) )
2199 ScrollTo( rPos );
2200 SwDrawView* pDView = Imp()->GetDrawView();
2202 if (pDView->IsInsObjPoint())
2203 pDView->MovInsObjPoint( rPos );
2204 else if (pDView->IsMarkPoints())
2205 pDView->MovMarkPoints( rPos );
2206 else
2207 pDView->MovAction( rPos );
2211 bool SwFEShell::EndMark()
2213 bool bRet = false;
2214 OSL_ENSURE( Imp()->HasDrawView(), "EndMark without DrawView?" );
2216 if (Imp()->GetDrawView()->IsMarkObj())
2218 bRet = Imp()->GetDrawView()->EndMarkObj();
2220 if ( bRet )
2222 bool bShowHdl = false;
2223 SwDrawView* pDView = Imp()->GetDrawView();
2224 // frames are not selected this way, except when
2225 // it is only one frame
2226 SdrMarkList &rMrkList = const_cast<SdrMarkList&>(pDView->GetMarkedObjectList());
2227 SwFlyFrame* pOldSelFly = ::GetFlyFromMarked( &rMrkList, this );
2229 if ( rMrkList.GetMarkCount() > 1 )
2230 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2232 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2233 if( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) != nullptr )
2235 if ( !bShowHdl )
2237 bShowHdl = true;
2239 rMrkList.DeleteMark( i );
2240 --i; // no exceptions
2244 if( bShowHdl )
2246 pDView->MarkListHasChanged();
2247 pDView->AdjustMarkHdl();
2250 if ( rMrkList.GetMarkCount() )
2251 ::lcl_GrabCursor(this, pOldSelFly);
2252 else
2253 bRet = false;
2255 if ( bRet )
2256 ::FrameNotify( this, FLY_DRAG_START );
2258 else
2260 if (Imp()->GetDrawView()->IsMarkPoints())
2261 bRet = Imp()->GetDrawView()->EndMarkPoints();
2264 SetChainMarker();
2265 return bRet;
2268 RndStdIds SwFEShell::GetAnchorId() const
2270 RndStdIds nRet = RndStdIds(SHRT_MAX);
2271 if ( Imp()->HasDrawView() )
2273 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2274 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2276 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2277 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) != nullptr )
2279 nRet = RndStdIds::UNKNOWN;
2280 break;
2282 if (SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj)))
2284 RndStdIds nId = pContact->GetFormat()->GetAnchor().GetAnchorId();
2285 if (nRet == RndStdIds(SHRT_MAX))
2286 nRet = nId;
2287 else if (nRet != nId)
2289 nRet = RndStdIds::UNKNOWN;
2290 break;
2295 if ( nRet == RndStdIds(SHRT_MAX) )
2296 nRet = RndStdIds::UNKNOWN;
2297 return nRet;
2300 void SwFEShell::ChgAnchor( RndStdIds eAnchorId, bool bSameOnly, bool bPosCorr )
2302 OSL_ENSURE( Imp()->HasDrawView(), "ChgAnchor without DrawView?" );
2303 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2304 if( rMrkList.GetMarkCount() &&
2305 !rMrkList.GetMark( 0 )->GetMarkedSdrObj()->getParentSdrObjectFromSdrObject() )
2307 StartAllAction();
2309 if( GetDoc()->ChgAnchor( rMrkList, eAnchorId, bSameOnly, bPosCorr ))
2310 Imp()->GetDrawView()->UnmarkAll();
2312 EndAllAction();
2314 ::FrameNotify( this );
2318 void SwFEShell::DelSelectedObj()
2320 OSL_ENSURE( Imp()->HasDrawView(), "DelSelectedObj(), no DrawView available" );
2321 if ( Imp()->HasDrawView() )
2323 StartAllAction();
2324 Imp()->GetDrawView()->DeleteMarked();
2325 EndAllAction();
2326 ::FrameNotify( this, FLY_DRAG_END );
2330 // For the statusline to request the current conditions
2331 Size SwFEShell::GetObjSize() const
2333 tools::Rectangle aRect;
2334 if ( Imp()->HasDrawView() )
2336 if ( Imp()->GetDrawView()->IsAction() )
2337 Imp()->GetDrawView()->TakeActionRect( aRect );
2338 else
2339 aRect = Imp()->GetDrawView()->GetAllMarkedRect();
2341 return aRect.GetSize();
2344 Point SwFEShell::GetAnchorObjDiff() const
2346 const SdrView *pView = Imp()->GetDrawView();
2347 assert(pView && "GetAnchorObjDiff without DrawView?");
2349 tools::Rectangle aRect;
2350 if ( Imp()->GetDrawView()->IsAction() )
2351 Imp()->GetDrawView()->TakeActionRect( aRect );
2352 else
2353 aRect = Imp()->GetDrawView()->GetAllMarkedRect();
2355 Point aRet( aRect.TopLeft() );
2357 if ( IsFrameSelected() )
2359 SwFlyFrame *pFly = GetSelectedFlyFrame();
2360 aRet -= pFly->GetAnchorFrame()->getFrameArea().Pos();
2362 else
2364 const SdrObject *pObj = pView->GetMarkedObjectList().GetMarkCount() == 1 ?
2365 pView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj() : nullptr;
2366 if ( pObj )
2367 aRet -= pObj->GetAnchorPos();
2370 return aRet;
2373 Point SwFEShell::GetObjAbsPos() const
2375 OSL_ENSURE( Imp()->GetDrawView(), "GetObjAbsPos() without DrawView?" );
2376 return Imp()->GetDrawView()->GetDragStat().GetActionRect().TopLeft();
2379 bool SwFEShell::IsGroupSelected(bool bAllowDiagams)
2381 if ( IsObjSelected() )
2383 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2384 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2386 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2387 // consider 'virtual' drawing objects.
2388 // Thus, use corresponding method instead of checking type.
2389 if ( pObj->IsGroupObject() &&
2390 // --> #i38505# No ungroup allowed for 3d objects
2391 !pObj->Is3DObj() && GetUserCall(pObj) &&
2392 RndStdIds::FLY_AS_CHAR != static_cast<SwDrawContact*>(GetUserCall(pObj))->
2393 GetFormat()->GetAnchor().GetAnchorId() )
2395 if(!bAllowDiagams)
2397 // Don't allow enter Diagrams
2398 if(pObj->isDiagram())
2400 return false;
2404 return true;
2408 return false;
2411 namespace
2413 bool HasSuitableGroupingAnchor(const SdrObject* pObj)
2415 bool bSuitable = true;
2416 SwFrameFormat* pFrameFormat(::FindFrameFormat(const_cast<SdrObject*>(pObj)));
2417 if (!pFrameFormat)
2419 OSL_FAIL( "<HasSuitableGroupingAnchor> - missing frame format" );
2420 bSuitable = false;
2422 else if (RndStdIds::FLY_AS_CHAR == pFrameFormat->GetAnchor().GetAnchorId())
2424 bSuitable = false;
2426 return bSuitable;
2430 // Change return type.
2431 // Adjustments for drawing objects in header/footer:
2432 // allow group, only if all selected objects are in the same header/footer
2433 // or not in header/footer.
2434 bool SwFEShell::IsGroupAllowed() const
2436 bool bIsGroupAllowed = false;
2437 if ( IsObjSelected() > 1 )
2439 bIsGroupAllowed = true;
2440 const SdrObject* pUpGroup = nullptr;
2441 const SwFrame* pHeaderFooterFrame = nullptr;
2442 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2443 for ( size_t i = 0; bIsGroupAllowed && i < rMrkList.GetMarkCount(); ++i )
2445 const SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2446 if ( i )
2447 bIsGroupAllowed = pObj->getParentSdrObjectFromSdrObject() == pUpGroup;
2448 else
2449 pUpGroup = pObj->getParentSdrObjectFromSdrObject();
2451 if ( bIsGroupAllowed )
2452 bIsGroupAllowed = HasSuitableGroupingAnchor(pObj);
2454 // check, if all selected objects are in the
2455 // same header/footer or not in header/footer.
2456 if ( bIsGroupAllowed )
2458 const SwFrame* pAnchorFrame = nullptr;
2459 if ( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>( pObj) )
2461 const SwFlyFrame* pFlyFrame = pVirtFlyDrawObj->GetFlyFrame();
2462 if ( pFlyFrame )
2464 pAnchorFrame = pFlyFrame->GetAnchorFrame();
2467 else
2469 SwDrawContact* pDrawContact = static_cast<SwDrawContact*>(GetUserCall( pObj ));
2470 if ( pDrawContact )
2472 pAnchorFrame = pDrawContact->GetAnchorFrame( pObj );
2475 if ( pAnchorFrame )
2477 if ( i )
2479 bIsGroupAllowed =
2480 ( pAnchorFrame->FindFooterOrHeader() == pHeaderFooterFrame );
2482 else
2484 pHeaderFooterFrame = pAnchorFrame->FindFooterOrHeader();
2491 return bIsGroupAllowed;
2494 bool SwFEShell::IsUnGroupAllowed() const
2496 bool bIsUnGroupAllowed = false;
2498 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2499 for (size_t i = 0; i < rMrkList.GetMarkCount(); ++i)
2501 const SdrObject* pObj = rMrkList.GetMark(i)->GetMarkedSdrObj();
2502 bIsUnGroupAllowed = HasSuitableGroupingAnchor(pObj);
2503 if (!bIsUnGroupAllowed)
2504 break;
2507 return bIsUnGroupAllowed;
2510 // The group gets the anchor and the contactobject of the first in the selection
2511 void SwFEShell::GroupSelection()
2513 if ( IsGroupAllowed() )
2515 StartAllAction();
2516 StartUndo( SwUndoId::START );
2518 GetDoc()->GroupSelection( *Imp()->GetDrawView() );
2520 EndUndo( SwUndoId::END );
2521 EndAllAction();
2525 // The individual objects get a copy of the anchor and the contactobject of the group
2526 void SwFEShell::UnGroupSelection()
2528 if ( IsGroupSelected(true) )
2530 StartAllAction();
2531 StartUndo( SwUndoId::START );
2533 GetDoc()->UnGroupSelection( *Imp()->GetDrawView() );
2535 EndUndo( SwUndoId::END );
2536 EndAllAction();
2540 void SwFEShell::MirrorSelection( bool bHorizontal )
2542 SdrView *pView = Imp()->GetDrawView();
2543 if ( IsObjSelected() && pView->IsMirrorAllowed() )
2545 if ( bHorizontal )
2546 pView->MirrorAllMarkedHorizontal();
2547 else
2548 pView->MirrorAllMarkedVertical();
2552 // jump to named frame (Graphic/OLE)
2554 bool SwFEShell::GotoFly( const OUString& rName, FlyCntType eType, bool bSelFrame )
2556 bool bRet = false;
2557 static SwNodeType const aChkArr[ 4 ] = {
2558 /* FLYCNTTYPE_ALL */ SwNodeType::NONE,
2559 /* FLYCNTTYPE_FRM */ SwNodeType::Text,
2560 /* FLYCNTTYPE_GRF */ SwNodeType::Grf,
2561 /* FLYCNTTYPE_OLE */ SwNodeType::Ole
2564 const SwFlyFrameFormat* pFlyFormat = mxDoc->FindFlyByName( rName, aChkArr[ eType]);
2565 if( pFlyFormat )
2567 CurrShell aCurr( this );
2569 SwFlyFrame* pFrame = SwIterator<SwFlyFrame,SwFormat>( *pFlyFormat ).First();
2570 if( pFrame )
2572 if( bSelFrame )
2574 // first make visible, to get a11y events in proper order
2575 if (!ActionPend())
2576 MakeVisible( pFrame->getFrameArea() );
2577 SelectObj( pFrame->getFrameArea().Pos(), 0, pFrame->GetVirtDrawObj() );
2579 else
2581 SwContentFrame *pCFrame = pFrame->ContainsContent();
2582 if ( pCFrame )
2584 ClearMark();
2585 SwPaM* pCursor = GetCursor();
2587 if (pCFrame->IsTextFrame())
2589 *pCursor->GetPoint() = static_cast<SwTextFrame *>(pCFrame)
2590 ->MapViewToModelPos(TextFrameIndex(0));
2592 else
2594 assert(pCFrame->IsNoTextFrame());
2595 SwContentNode *const pCNode = static_cast<SwNoTextFrame *>(pCFrame)->GetNode();
2597 pCursor->GetPoint()->Assign(*pCNode);
2600 SwRect& rChrRect = const_cast<SwRect&>(GetCharRect());
2601 rChrRect = pFrame->getFramePrintArea();
2602 rChrRect.Pos() += pFrame->getFrameArea().Pos();
2603 GetCursorDocPos() = rChrRect.Pos();
2606 bRet = true;
2609 return bRet;
2612 size_t SwFEShell::GetFlyCount( FlyCntType eType, bool bIgnoreTextBoxes ) const
2614 return GetDoc()->GetFlyCount(eType, bIgnoreTextBoxes);
2617 std::vector<SwFrameFormat const*> SwFEShell::GetFlyFrameFormats(
2618 FlyCntType const eType, bool const bIgnoreTextBoxes)
2620 return GetDoc()->GetFlyFrameFormats(eType, bIgnoreTextBoxes);
2623 // show the current selected object
2624 void SwFEShell::MakeSelVisible()
2626 if ( Imp()->HasDrawView() &&
2627 Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() )
2629 GetCurrFrame(); // just to trigger formatting in case the selected object is not formatted.
2630 MakeVisible( SwRect(Imp()->GetDrawView()->GetAllMarkedRect()) );
2632 else
2633 SwCursorShell::MakeSelVisible();
2636 // how is the selected object protected?
2637 FlyProtectFlags SwFEShell::IsSelObjProtected( FlyProtectFlags eType ) const
2639 FlyProtectFlags nChk = FlyProtectFlags::NONE;
2640 const bool bParent(eType & FlyProtectFlags::Parent);
2641 if( Imp()->HasDrawView() )
2643 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2644 for( size_t i = rMrkList.GetMarkCount(); i; )
2646 SdrObject *pObj = rMrkList.GetMark( --i )->GetMarkedSdrObj();
2647 if (!pObj)
2649 continue;
2652 if( !bParent )
2654 nChk |= ( pObj->IsMoveProtect() ? FlyProtectFlags::Pos : FlyProtectFlags::NONE ) |
2655 ( pObj->IsResizeProtect()? FlyProtectFlags::Size : FlyProtectFlags::NONE );
2657 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
2659 SwFlyFrame *pFly = pVirtO->GetFlyFrame();
2660 if ( (FlyProtectFlags::Content & eType) && pFly->GetFormat()->GetProtect().IsContentProtected() )
2661 nChk |= FlyProtectFlags::Content;
2663 if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
2665 SwOLENode *pNd = static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetOLENode();
2666 uno::Reference < embed::XEmbeddedObject > xObj( pNd ? pNd->GetOLEObj().GetOleRef() : nullptr );
2667 if ( xObj.is() )
2669 // TODO/LATER: use correct aspect
2670 const bool bNeverResize = (embed::EmbedMisc::EMBED_NEVERRESIZE & xObj->getStatus( embed::Aspects::MSOLE_CONTENT ));
2671 if ( ( (FlyProtectFlags::Content & eType) || (FlyProtectFlags::Size & eType) ) && bNeverResize )
2673 nChk |= FlyProtectFlags::Size;
2674 nChk |= FlyProtectFlags::Fixed;
2677 // set FlyProtectFlags::Pos if it is a Math object anchored 'as char' and baseline alignment is activated
2678 const bool bProtectMathPos = SotExchange::IsMath( xObj->getClassID() )
2679 && RndStdIds::FLY_AS_CHAR == pFly->GetFormat()->GetAnchor().GetAnchorId()
2680 && mxDoc->GetDocumentSettingManager().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT );
2681 if ((FlyProtectFlags::Pos & eType) && bProtectMathPos)
2682 nChk |= FlyProtectFlags::Pos;
2686 nChk &= eType;
2687 if( nChk == eType )
2688 return eType;
2690 const SwFrame* pAnch;
2691 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
2692 pAnch = pVirtO->GetFlyFrame()->GetAnchorFrame();
2693 else
2695 SwDrawContact* pTmp = static_cast<SwDrawContact*>(GetUserCall(pObj));
2696 pAnch = pTmp ? pTmp->GetAnchorFrame( pObj ) : nullptr;
2698 if( pAnch && pAnch->IsProtected() )
2699 return eType;
2702 return nChk;
2705 bool SwFEShell::GetObjAttr( SfxItemSet &rSet ) const
2707 if ( !IsObjSelected() )
2708 return false;
2710 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2711 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2713 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2714 SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
2715 OSL_ENSURE( pContact, "<SwFEShell::GetObjAttr(..)> - missing <pContact>." );
2716 if ( pContact )
2718 if ( i )
2719 rSet.MergeValues( pContact->GetFormat()->GetAttrSet() );
2720 else
2721 rSet.Put( pContact->GetFormat()->GetAttrSet() );
2724 return true;
2727 void SwFEShell::SetObjAttr( const SfxItemSet& rSet )
2729 CurrShell aCurr( this );
2731 if ( !rSet.Count() )
2733 OSL_ENSURE( false, "SetObjAttr, empty set." );
2734 return;
2737 StartAllAction();
2738 StartUndo( SwUndoId::INSATTR );
2740 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2741 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2743 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2744 if (SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj)))
2745 GetDoc()->SetAttr( rSet, *pContact->GetFormat() );
2748 EndUndo( SwUndoId::INSATTR );
2749 EndAllActionAndCall();
2750 GetDoc()->getIDocumentState().SetModified();
2753 bool SwFEShell::IsAlignPossible() const
2755 return Imp()->GetDrawView()->IsAlignPossible();
2758 void SwFEShell::CheckUnboundObjects()
2760 CurrShell aCurr( this );
2762 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2763 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2765 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2766 if ( !GetUserCall(pObj) )
2768 const tools::Rectangle &rBound = pObj->GetSnapRect();
2769 const Point aPt( rBound.TopLeft() );
2770 const SwFrame *pPage = GetLayout()->Lower();
2771 const SwFrame *pLast = pPage;
2772 while ( pPage && !pPage->getFrameArea().Contains( aPt ) )
2774 if ( aPt.Y() > pPage->getFrameArea().Bottom() )
2775 pLast = pPage;
2776 pPage = pPage->GetNext();
2778 if ( !pPage )
2779 pPage = pLast;
2780 OSL_ENSURE( pPage, "Page not found." );
2782 SwFormatAnchor aAnch;
2784 const SwContentFrame *const pAnch = ::FindAnchor(pPage, aPt, true);
2785 SwPosition aPos( pAnch->IsTextFrame()
2786 ? *static_cast<SwTextFrame const*>(pAnch)->GetTextNodeForParaProps()
2787 : *static_cast<SwNoTextFrame const*>(pAnch)->GetNode() );
2788 aAnch.SetType( RndStdIds::FLY_AT_PARA );
2789 aAnch.SetAnchor( &aPos );
2790 const_cast<SwRect&>(GetCharRect()).Pos() = aPt;
2793 // First the action here, to assure GetCharRect delivers current values.
2794 StartAllAction();
2796 SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE,
2797 RES_SURROUND, RES_ANCHOR> aSet( GetAttrPool() );
2798 aSet.Put( aAnch );
2799 aSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) );
2800 SwFrameFormat* pFormat = getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::DRAW_OBJECT, &aSet );
2802 SwDrawContact *pContact = new SwDrawContact(
2803 static_cast<SwDrawFrameFormat*>(pFormat), pObj );
2805 // #i35635#
2806 pContact->MoveObjToVisibleLayer( pObj );
2807 pContact->ConnectToLayout();
2809 EndAllAction();
2814 void SwFEShell::SetCalcFieldValueHdl(Outliner* pOutliner)
2816 GetDoc()->SetCalcFieldValueHdl(pOutliner);
2819 SwChainRet SwFEShell::Chainable( SwRect &rRect, const SwFrameFormat &rSource,
2820 const Point &rPt ) const
2822 rRect.Clear();
2824 // The source is not allowed to have a follow.
2825 const SwFormatChain &rChain = rSource.GetChain();
2826 if ( rChain.GetNext() )
2827 return SwChainRet::SOURCE_CHAINED;
2829 SwChainRet nRet = SwChainRet::NOT_FOUND;
2830 if( Imp()->HasDrawView() )
2832 SdrPageView* pPView;
2833 SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
2834 const auto nOld = pDView->GetHitTolerancePixel();
2835 pDView->SetHitTolerancePixel( 0 );
2836 SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
2837 SwVirtFlyDrawObj* pDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
2838 if (pDrawObj)
2840 SwFlyFrame *pFly = pDrawObj->GetFlyFrame();
2841 rRect = pFly->getFrameArea();
2843 // Target and source should not be equal and the list
2844 // should not be cyclic
2845 SwFrameFormat *pFormat = pFly->GetFormat();
2846 nRet = GetDoc()->Chainable(rSource, *pFormat);
2848 pDView->SetHitTolerancePixel( nOld );
2850 return nRet;
2853 void SwFEShell::Chain( SwFrameFormat &rSource, const SwFrameFormat &rDest )
2855 GetDoc()->Chain(rSource, rDest);
2858 SwChainRet SwFEShell::Chain( SwFrameFormat &rSource, const Point &rPt )
2860 SwRect aDummy;
2861 SwChainRet nErr = Chainable( aDummy, rSource, rPt );
2862 if ( nErr == SwChainRet::OK )
2864 StartAllAction();
2865 SdrPageView* pPView;
2866 SwDrawView *pDView = Imp()->GetDrawView();
2867 const auto nOld = pDView->GetHitTolerancePixel();
2868 pDView->SetHitTolerancePixel( 0 );
2869 SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
2870 pDView->SetHitTolerancePixel( nOld );
2871 SwFlyFrame *pFly = static_cast<SwVirtFlyDrawObj*>(pObj)->GetFlyFrame();
2873 SwFlyFrameFormat *pFormat = pFly->GetFormat();
2874 GetDoc()->Chain(rSource, *pFormat);
2875 EndAllAction();
2876 SetChainMarker();
2878 return nErr;
2881 void SwFEShell::Unchain( SwFrameFormat &rFormat )
2883 StartAllAction();
2884 GetDoc()->Unchain(rFormat);
2885 EndAllAction();
2888 void SwFEShell::HideChainMarker()
2890 m_pChainFrom.reset();
2891 m_pChainTo.reset();
2894 void SwFEShell::SetChainMarker()
2896 bool bDelFrom = true,
2897 bDelTo = true;
2898 if ( IsFrameSelected() )
2900 SwFlyFrame *pFly = GetSelectedFlyFrame();
2902 if ( pFly->GetPrevLink() )
2904 bDelFrom = false;
2905 const SwFrame *pPre = pFly->GetPrevLink();
2907 Point aStart( pPre->getFrameArea().Right(), pPre->getFrameArea().Bottom());
2908 Point aEnd(pFly->getFrameArea().Pos());
2910 if (!m_pChainFrom)
2912 m_pChainFrom.reset(
2913 new SdrDropMarkerOverlay( *GetDrawView(), aStart, aEnd ));
2916 if ( pFly->GetNextLink() )
2918 bDelTo = false;
2919 const SwFlyFrame *pNxt = pFly->GetNextLink();
2921 Point aStart( pFly->getFrameArea().Right(), pFly->getFrameArea().Bottom());
2922 Point aEnd(pNxt->getFrameArea().Pos());
2924 if (!m_pChainTo)
2926 m_pChainTo.reset(
2927 new SdrDropMarkerOverlay( *GetDrawView(), aStart, aEnd ));
2932 if ( bDelFrom )
2934 m_pChainFrom.reset();
2937 if ( bDelTo )
2939 m_pChainTo.reset();
2943 tools::Long SwFEShell::GetSectionWidth( SwFormat const & rFormat ) const
2945 SwFrame *pFrame = GetCurrFrame();
2946 // Is the cursor at this moment in a SectionFrame?
2947 if( pFrame && pFrame->IsInSct() )
2949 SwSectionFrame* pSect = pFrame->FindSctFrame();
2952 // Is it the right one?
2953 if( pSect->KnowsFormat( rFormat ) )
2954 return pSect->getFrameArea().Width();
2955 // for nested areas
2956 pSect = pSect->GetUpper()->FindSctFrame();
2958 while( pSect );
2960 SwIterator<SwSectionFrame,SwFormat> aIter( rFormat );
2961 for ( SwSectionFrame* pSct = aIter.First(); pSct; pSct = aIter.Next() )
2963 if( !pSct->IsFollow() )
2965 return pSct->getFrameArea().Width();
2968 return 0;
2971 void SwFEShell::CreateDefaultShape( SdrObjKind eSdrObjectKind, const tools::Rectangle& rRect,
2972 sal_uInt16 nSlotId)
2974 SdrView* pDrawView = GetDrawView();
2975 SdrModel& rDrawModel = pDrawView->GetModel();
2976 rtl::Reference<SdrObject> pObj = SdrObjFactory::MakeNewObject(
2977 rDrawModel,
2978 SdrInventor::Default,
2979 eSdrObjectKind);
2981 if(pObj)
2983 tools::Rectangle aRect(rRect);
2984 if(SdrObjKind::CircleArc == eSdrObjectKind || SdrObjKind::CircleCut == eSdrObjectKind)
2986 // force quadratic
2987 if(aRect.GetWidth() > aRect.GetHeight())
2989 aRect = tools::Rectangle(
2990 Point(aRect.Left() + ((aRect.GetWidth() - aRect.GetHeight()) / 2), aRect.Top()),
2991 Size(aRect.GetHeight(), aRect.GetHeight()));
2993 else
2995 aRect = tools::Rectangle(
2996 Point(aRect.Left(), aRect.Top() + ((aRect.GetHeight() - aRect.GetWidth()) / 2)),
2997 Size(aRect.GetWidth(), aRect.GetWidth()));
3000 pObj->SetLogicRect(aRect);
3002 Point aStart = aRect.TopLeft();
3003 Point aEnd = aRect.BottomRight();
3005 if(dynamic_cast<const SdrCircObj*>( pObj.get()) != nullptr)
3007 SfxItemSet aAttr(rDrawModel.GetItemPool());
3008 aAttr.Put(makeSdrCircStartAngleItem(9000_deg100));
3009 aAttr.Put(makeSdrCircEndAngleItem(0_deg100));
3010 pObj->SetMergedItemSet(aAttr);
3012 else if(auto pPathObj = dynamic_cast<SdrPathObj*>( pObj.get()))
3014 basegfx::B2DPolyPolygon aPoly;
3016 switch(eSdrObjectKind)
3018 case SdrObjKind::PathLine:
3019 case SdrObjKind::PathFill:
3021 basegfx::B2DPolygon aInnerPoly;
3023 aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Bottom()));
3025 const basegfx::B2DPoint aCenterBottom(aRect.Center().getX(), aRect.Bottom());
3026 aInnerPoly.appendBezierSegment(
3027 aCenterBottom,
3028 aCenterBottom,
3029 basegfx::B2DPoint(aRect.Center().getX(), aRect.Center().getY()));
3031 const basegfx::B2DPoint aCenterTop(aRect.Center().getX(), aRect.Top());
3032 aInnerPoly.appendBezierSegment(
3033 aCenterTop,
3034 aCenterTop,
3035 basegfx::B2DPoint(aRect.Right(), aRect.Top()));
3037 aInnerPoly.setClosed(true);
3038 aPoly.append(aInnerPoly);
3040 break;
3041 case SdrObjKind::FreehandLine:
3042 case SdrObjKind::FreehandFill:
3044 basegfx::B2DPolygon aInnerPoly;
3046 aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Bottom()));
3048 aInnerPoly.appendBezierSegment(
3049 basegfx::B2DPoint(aRect.Left(), aRect.Top()),
3050 basegfx::B2DPoint(aRect.Center().getX(), aRect.Top()),
3051 basegfx::B2DPoint(aRect.Center().getX(), aRect.Center().getY()));
3053 aInnerPoly.appendBezierSegment(
3054 basegfx::B2DPoint(aRect.Center().getX(), aRect.Bottom()),
3055 basegfx::B2DPoint(aRect.Right(), aRect.Bottom()),
3056 basegfx::B2DPoint(aRect.Right(), aRect.Top()));
3058 aInnerPoly.append(basegfx::B2DPoint(aRect.Right(), aRect.Bottom()));
3059 aInnerPoly.setClosed(true);
3060 aPoly.append(aInnerPoly);
3062 break;
3063 case SdrObjKind::Polygon:
3064 case SdrObjKind::PolyLine:
3066 basegfx::B2DPolygon aInnerPoly;
3067 sal_Int32 nWdt(aRect.GetWidth());
3068 sal_Int32 nHgt(aRect.GetHeight());
3070 aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Bottom()));
3071 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 30) / 100, aRect.Top() + (nHgt * 70) / 100));
3072 aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Top() + (nHgt * 15) / 100));
3073 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 65) / 100, aRect.Top()));
3074 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + nWdt, aRect.Top() + (nHgt * 30) / 100));
3075 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 80) / 100, aRect.Top() + (nHgt * 50) / 100));
3076 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 80) / 100, aRect.Top() + (nHgt * 75) / 100));
3077 aInnerPoly.append(basegfx::B2DPoint(aRect.Bottom(), aRect.Right()));
3079 if(SdrObjKind::PolyLine == eSdrObjectKind)
3081 aInnerPoly.append(basegfx::B2DPoint(aRect.Center().getX(), aRect.Bottom()));
3083 else
3085 aInnerPoly.setClosed(true);
3088 aPoly.append(aInnerPoly);
3090 break;
3091 case SdrObjKind::Line :
3093 sal_Int32 nYMiddle((aRect.Top() + aRect.Bottom()) / 2);
3094 basegfx::B2DPolygon aTempPoly;
3095 aTempPoly.append(basegfx::B2DPoint(aRect.TopLeft().getX(), nYMiddle));
3096 aTempPoly.append(basegfx::B2DPoint(aRect.BottomRight().getX(), nYMiddle));
3097 aPoly.append(aTempPoly);
3099 SfxItemSet aAttr(pObj->getSdrModelFromSdrObject().GetItemPool());
3100 SetLineEnds(aAttr, *pObj, nSlotId);
3101 pObj->SetMergedItemSet(aAttr);
3103 break;
3104 default:
3105 break;
3108 pPathObj->SetPathPoly(aPoly);
3110 else if(auto pMeasureObj = dynamic_cast<SdrMeasureObj*>( pObj.get()))
3112 sal_Int32 nYMiddle((aRect.Top() + aRect.Bottom()) / 2);
3113 pMeasureObj->SetPoint(Point(aStart.X(), nYMiddle), 0);
3114 pMeasureObj->SetPoint(Point(aEnd.X(), nYMiddle), 1);
3116 SfxItemSet aAttr(pObj->getSdrModelFromSdrObject().GetItemPool());
3117 SetLineEnds(aAttr, *pObj, nSlotId);
3118 pObj->SetMergedItemSet(aAttr);
3120 else if(auto pCaptionObj = dynamic_cast<SdrCaptionObj*>( pObj.get()))
3122 bool bVerticalText = ( SID_DRAW_TEXT_VERTICAL == nSlotId ||
3123 SID_DRAW_CAPTION_VERTICAL == nSlotId );
3124 pCaptionObj->SetVerticalWriting(bVerticalText);
3125 if(bVerticalText)
3127 SfxItemSet aSet(pObj->GetMergedItemSet());
3128 aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER));
3129 aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
3130 pObj->SetMergedItemSet(aSet);
3133 pCaptionObj->SetLogicRect(aRect);
3134 pCaptionObj->SetTailPos(
3135 aRect.TopLeft() - Point(aRect.GetWidth() / 2, aRect.GetHeight() / 2));
3137 else if(auto pText = DynCastSdrTextObj( pObj.get()))
3139 pText->SetLogicRect(aRect);
3141 bool bVertical = (SID_DRAW_TEXT_VERTICAL == nSlotId);
3142 bool bMarquee = (SID_DRAW_TEXT_MARQUEE == nSlotId);
3144 pText->SetVerticalWriting(bVertical);
3146 if(bVertical)
3148 SfxItemSet aSet(rDrawModel.GetItemPool());
3149 aSet.Put(makeSdrTextAutoGrowWidthItem(true));
3150 aSet.Put(makeSdrTextAutoGrowHeightItem(false));
3151 aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP));
3152 aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
3153 pText->SetMergedItemSet(aSet);
3156 if(bMarquee)
3158 SfxItemSetFixed<SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST> aSet(rDrawModel.GetItemPool());
3159 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
3160 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
3161 aSet.Put( SdrTextAniKindItem( SdrTextAniKind::Slide ) );
3162 aSet.Put( SdrTextAniDirectionItem( SdrTextAniDirection::Left ) );
3163 aSet.Put( SdrTextAniCountItem( 1 ) );
3164 aSet.Put( SdrTextAniAmountItem( static_cast<sal_Int16>(GetWin()->PixelToLogic(Size(2,1)).Width())) );
3165 pObj->SetMergedItemSetAndBroadcast(aSet);
3168 SdrPageView* pPageView = pDrawView->GetSdrPageView();
3169 SdrCreateView::SetupObjLayer(pPageView, pDrawView->GetActiveLayer(), pObj.get());
3170 // switch undo off or this combined with ImpEndCreate will cause two undos
3171 // see comment made in SwFEShell::EndCreate (we create our own undo-object!)
3172 const bool bUndo(GetDoc()->GetIDocumentUndoRedo().DoesUndo());
3173 GetDoc()->GetIDocumentUndoRedo().DoUndo(false);
3174 pDrawView->InsertObjectAtView(pObj.get(), *pPageView);
3175 GetDoc()->GetIDocumentUndoRedo().DoUndo(bUndo);
3177 ImpEndCreate();
3180 /** SwFEShell::GetShapeBackground
3181 method determines background color of the page the selected drawing
3182 object is on and returns this color.
3183 If no color is found, because no drawing object is selected or ...,
3184 color COL_BLACK (default color on constructing object of class Color)
3185 is returned.
3187 @returns an object of class Color
3189 Color SwFEShell::GetShapeBackground() const
3191 Color aRetColor;
3193 // check, if a draw view exists
3194 OSL_ENSURE( Imp()->GetDrawView(), "wrong usage of SwFEShell::GetShapeBackground - no draw view!");
3195 if( Imp()->GetDrawView() )
3197 // determine list of selected objects
3198 const SdrMarkList* pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
3199 // check, if exactly one object is selected.
3200 OSL_ENSURE( pMrkList->GetMarkCount() == 1, "wrong usage of SwFEShell::GetShapeBackground - no selected object!");
3201 if ( pMrkList->GetMarkCount() == 1)
3203 // get selected object
3204 const SdrObject *pSdrObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
3205 // check, if selected object is a shape (drawing object)
3206 OSL_ENSURE( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) == nullptr, "wrong usage of SwFEShell::GetShapeBackground - selected object is not a drawing object!");
3207 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) == nullptr )
3209 if (SwDrawContact* pDrawContact = static_cast<SwDrawContact*>(GetUserCall(pSdrObj)))
3211 // determine page frame of the frame the shape is anchored.
3212 const SwFrame * pAnchorFrame = pDrawContact->GetAnchorFrame(pSdrObj);
3213 OSL_ENSURE(pAnchorFrame, "inconsistent model - no anchor at shape!");
3214 if (pAnchorFrame)
3216 const SwPageFrame* pPageFrame = pAnchorFrame->FindPageFrame();
3217 OSL_ENSURE(pPageFrame, "inconsistent model - no page!");
3218 if (pPageFrame)
3220 aRetColor = pPageFrame->GetDrawBackgroundColor();
3228 return aRetColor;
3231 /** Is default horizontal text direction for selected drawing object right-to-left
3232 Because drawing objects only painted for each page only, the default
3233 horizontal text direction of a drawing object is given by the corresponding
3234 page property.
3236 @returns boolean, indicating, if the horizontal text direction of the
3237 page, the selected drawing object is on, is right-to-left.
3239 bool SwFEShell::IsShapeDefaultHoriTextDirR2L() const
3241 // check, if a draw view exists
3242 OSL_ENSURE(Imp()->GetDrawView(), "wrong usage of SwFEShell::GetShapeBackground - no draw view!");
3243 if (!Imp()->GetDrawView())
3244 return false;
3246 // determine list of selected objects
3247 const SdrMarkList& rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
3249 // check, if exactly one object is selected.
3250 OSL_ENSURE(rMrkList.GetMarkCount() == 1, "wrong usage of SwFEShell::GetShapeBackground - no selected object!");
3251 if (rMrkList.GetMarkCount() != 1)
3252 return false;
3254 // get selected object
3255 const SdrObject *pSdrObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
3257 // check, if selected object is a shape (drawing object)
3258 OSL_ENSURE(dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) == nullptr, "wrong usage of SwFEShell::GetShapeBackground - selected object is not a drawing object!");
3259 if (dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) != nullptr)
3260 return false;
3262 // determine page frame of the frame the shape is anchored.
3263 const SwContact* pContact = GetUserCall(pSdrObj);
3264 OSL_ENSURE(pContact, "<SwFEShell::IsShapeDefaultHoriTextDirR2L(..)> - missing contact!");
3265 if (!pContact)
3266 return false;
3268 const SwFrame* pAnchorFrame = static_cast<const SwDrawContact*>(pContact)->GetAnchorFrame(pSdrObj);
3269 OSL_ENSURE(pAnchorFrame, "inconsistent model - no anchor at shape!");
3270 if (!pAnchorFrame)
3271 return false;
3273 const SwPageFrame* pPageFrame = pAnchorFrame->FindPageFrame();
3274 OSL_ENSURE(pPageFrame, "inconsistent model - no page!");
3275 if (!pPageFrame)
3276 return false;
3278 return pPageFrame->IsRightToLeft();
3281 Point SwFEShell::GetRelativePagePosition(const Point& rDocPos)
3283 Point aRet(-1, -1);
3284 const SwFrame *pPage = GetLayout()->Lower();
3285 while ( pPage && !pPage->getFrameArea().Contains( rDocPos ) )
3287 pPage = pPage->GetNext();
3289 if(pPage)
3291 aRet = rDocPos - pPage->getFrameArea().TopLeft();
3293 return aRet;
3296 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */