android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / frmedt / feshview.cxx
blobeefb9d6d0643797f3abd3d117c521e9af30d33eb
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/strings.hrc>
22 #include <svx/sdrobjectfilter.hxx>
23 #include <svx/svddrgmt.hxx>
24 #include <svx/svditer.hxx>
25 #include <svx/svdobj.hxx>
26 #include <svx/svdouno.hxx>
27 #include <svx/svdogrp.hxx>
28 #include <svx/svdocirc.hxx>
29 #include <svx/svdopath.hxx>
30 #include <svx/sxciaitm.hxx>
31 #include <svx/svdocapt.hxx>
32 #include <svx/xlnwtit.hxx>
33 #include <svx/xlnstwit.hxx>
34 #include <svx/xlnedwit.hxx>
35 #include <svx/xlnedit.hxx>
36 #include <svx/xlnstit.hxx>
37 #include <svx/svdomeas.hxx>
38 #include <svx/sdtagitm.hxx>
39 #include <svx/sdtacitm.hxx>
40 #include <svx/sdtaaitm.hxx>
41 #include <editeng/opaqitem.hxx>
42 #include <editeng/protitem.hxx>
43 #include <svx/svdpage.hxx>
44 #include <svx/svdpagv.hxx>
45 #include <svx/dialmgr.hxx>
46 #include <tools/globname.hxx>
47 #include <sot/exchange.hxx>
48 #include <IDocumentDrawModelAccess.hxx>
49 #include <IDocumentSettingAccess.hxx>
50 #include <DocumentSettingManager.hxx>
51 #include <IDocumentState.hxx>
52 #include <IDocumentLayoutAccess.hxx>
53 #include <drawdoc.hxx>
54 #include <textboxhelper.hxx>
55 #include <frmfmt.hxx>
56 #include <frmatr.hxx>
57 #include <frmtool.hxx>
58 #include <fmtfsize.hxx>
59 #include <fmtanchr.hxx>
60 #include <fmtornt.hxx>
61 #include <fmtsrnd.hxx>
62 #include <fmtcntnt.hxx>
63 #include <fmtflcnt.hxx>
64 #include <fmtcnct.hxx>
65 #include <swmodule.hxx>
66 #include <fesh.hxx>
67 #include <rootfrm.hxx>
68 #include <pagefrm.hxx>
69 #include <sectfrm.hxx>
70 #include <doc.hxx>
71 #include <IDocumentUndoRedo.hxx>
72 #include <dview.hxx>
73 #include <dflyobj.hxx>
74 #include <dcontact.hxx>
75 #include <viewimp.hxx>
76 #include <flyfrm.hxx>
77 #include <pam.hxx>
78 #include <ndole.hxx>
79 #include <ndgrf.hxx>
80 #include <ndtxt.hxx>
81 #include <viewopt.hxx>
82 #include <swundo.hxx>
83 #include <notxtfrm.hxx>
84 #include <txtfrm.hxx>
85 #include <mdiexp.hxx>
86 #include <sortedobjs.hxx>
87 #include <HandleAnchorNodeChg.hxx>
88 #include <basegfx/polygon/b2dpolygon.hxx>
89 #include <comphelper/lok.hxx>
90 #include <sfx2/lokhelper.hxx>
91 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
92 #include <calbck.hxx>
93 #include <flyfrms.hxx>
94 #include <basegfx/polygon/b2dpolygontools.hxx>
95 #include <svx/svxids.hrc>
96 #include <osl/diagnose.h>
98 #include <com/sun/star/embed/EmbedMisc.hpp>
99 #include <com/sun/star/embed/Aspects.hpp>
100 #include <com/sun/star/embed/XEmbeddedObject.hpp>
102 #include <svx/srchdlg.hxx>
104 #define SCROLLVAL 75
106 using namespace com::sun::star;
109 * set line starts and ends for the object to be created
112 namespace {
114 ::basegfx::B2DPolyPolygon getPolygon(TranslateId pResId, const SdrModel& rModel)
116 ::basegfx::B2DPolyPolygon aRetval;
117 XLineEndListRef pLineEndList(rModel.GetLineEndList());
119 if( pLineEndList.is() )
121 OUString aArrowName( SvxResId(pResId) );
122 tools::Long nCount = pLineEndList->Count();
123 tools::Long nIndex;
124 for( nIndex = 0; nIndex < nCount; nIndex++ )
126 const XLineEndEntry* pEntry = pLineEndList->GetLineEnd(nIndex);
127 if( pEntry->GetName() == aArrowName )
129 aRetval = pEntry->GetLineEnd();
130 break;
135 return aRetval;
140 SwFlyFrame *GetFlyFromMarked( const SdrMarkList *pLst, SwViewShell *pSh )
142 if ( !pLst )
143 pLst = pSh->HasDrawView() ? &pSh->Imp()->GetDrawView()->GetMarkedObjectList():nullptr;
145 if ( pLst && pLst->GetMarkCount() == 1 )
147 SdrObject *pO = pLst->GetMark( 0 )->GetMarkedSdrObj();
148 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pO))
149 return pVirtO->GetFlyFrame();
151 return nullptr;
154 static void lcl_GrabCursor( SwFEShell* pSh, SwFlyFrame* pOldSelFly, SwFrameFormat* pNewDrawFormat = nullptr)
156 const SwFrameFormat *pFlyFormat = pSh->SelFlyGrabCursor();
157 if( pFlyFormat && !pSh->ActionPend() &&
158 (!pOldSelFly || pOldSelFly->GetFormat() != pFlyFormat) )
160 // now call set macro if applicable
161 pSh->GetFlyMacroLnk().Call( static_cast<const SwFlyFrameFormat*>(pFlyFormat) );
162 // if a dialog was started inside a macro, then
163 // MouseButtonUp arrives at macro and not to us. Therefore
164 // flag is always set here and will never be switched to
165 // respective Shell !!!!!!!
167 g_bNoInterrupt = false;
169 else if( !pFlyFormat || RES_DRAWFRMFMT == pFlyFormat->Which() )
171 // --> assure consistent cursor
172 pSh->KillPams();
173 pSh->ClearMark();
174 if (pNewDrawFormat)
176 // If we selected a draw shape format, move the cursor to its anchor position.
177 // SetCursor() may pick something inside, which is not wanted: code later assumes that
178 // the cursor is at the anchor point if a shape is selected.
179 const SwPosition* pContentAnchor = pNewDrawFormat->GetAnchor().GetContentAnchor();
180 if (pContentAnchor)
182 pSh->SetSelection(SwPaM(*pContentAnchor));
185 else
187 pSh->SetCursor( pSh->Imp()->GetDrawView()->GetAllMarkedRect().TopLeft(), true);
192 bool SwFEShell::SelectObj( const Point& rPt, sal_uInt8 nFlag, SdrObject *pObj )
194 SwDrawView *pDView = Imp()->GetDrawView();
195 if(!pDView)
196 return false;
197 CurrShell aCurr( this );
198 StartAction(); // action is necessary to assure only one AttrChgdNotify
199 // (e.g. due to Unmark->MarkListHasChgd) arrives
201 const SdrMarkList &rMrkList = pDView->GetMarkedObjectList();
202 const bool bHadSelection = rMrkList.GetMarkCount();
203 const bool bAddSelect = 0 != (SW_ADD_SELECT & nFlag);
204 const bool bEnterGroup = 0 != (SW_ENTER_GROUP & nFlag);
205 SwFlyFrame* pOldSelFly = nullptr;
206 const Point aOldPos( pDView->GetAllMarkedRect().TopLeft() );
208 if( bHadSelection )
210 // call Unmark when !bAddSelect or if fly was selected
211 bool bUnmark = !bAddSelect;
213 if ( rMrkList.GetMarkCount() == 1 )
215 // if fly was selected, deselect it first
216 pOldSelFly = ::GetFlyFromMarked( &rMrkList, this );
217 if ( pOldSelFly )
219 const sal_uInt16 nType = GetCntType();
220 if( nType != CNT_TXT || (SW_LEAVE_FRAME & nFlag) ||
221 ( pOldSelFly->GetFormat()->GetProtect().IsContentProtected()
222 && !IsReadOnlyAvailable() ))
224 // If a fly is deselected, which contains graphic, OLE or
225 // otherwise, the cursor should be removed from it.
226 // Similar if a fly with protected content is deselected.
227 // For simplicity we put the cursor next to the upper-left
228 // corner.
229 Point aPt( pOldSelFly->getFrameArea().Pos() );
230 aPt.setX(aPt.getX() - 1);
231 bool bUnLockView = !IsViewLocked();
232 LockView( true );
233 SetCursor( aPt, true );
234 if( bUnLockView )
235 LockView( false );
237 if ( nType & CNT_GRF &&
238 static_cast<SwNoTextFrame*>(pOldSelFly->Lower())->HasAnimation() )
240 GetWin()->Invalidate( pOldSelFly->getFrameArea().SVRect() );
243 // Cancel crop mode
244 if ( SdrDragMode::Crop == GetDragMode() )
245 SetDragMode( SdrDragMode::Move );
247 bUnmark = true;
250 if ( bUnmark )
252 pDView->UnmarkAll();
253 if (pOldSelFly)
254 pOldSelFly->SelectionHasChanged(this);
257 else
259 KillPams();
260 ClearMark();
263 if ( pObj )
265 OSL_ENSURE( !bEnterGroup, "SW_ENTER_GROUP is not supported" );
266 pDView->MarkObj( pObj, Imp()->GetPageView() );
268 else
270 // tolerance limit of Drawing-SS
271 const auto nHdlSizePixel = Imp()->GetDrawView()->GetMarkHdlSizePixel();
272 const short nMinMove = static_cast<short>(GetOut()->PixelToLogic(Size(nHdlSizePixel/2, 0)).Width());
273 pDView->MarkObj( rPt, nMinMove, bAddSelect, bEnterGroup );
276 const bool bRet = 0 != rMrkList.GetMarkCount();
278 if ( rMrkList.GetMarkCount() > 1 )
280 // It sucks if Drawing objects were selected and now
281 // additionally a fly is selected.
282 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
284 SdrObject *pTmpObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
285 bool bForget = dynamic_cast<const SwVirtFlyDrawObj*>( pTmpObj) != nullptr;
286 if( bForget )
288 pDView->UnmarkAll();
289 pDView->MarkObj( pTmpObj, Imp()->GetPageView(), bAddSelect, bEnterGroup );
290 break;
295 if (rMrkList.GetMarkCount() == 1)
297 SwFlyFrame* pSelFly = ::GetFlyFromMarked(&rMrkList, this);
298 if (pSelFly && pSelFly->IsFlySplitAllowed())
300 auto pMaster = static_cast<SwFlyAtContentFrame*>(pSelFly);
301 while (pMaster->IsFollow())
303 pMaster = pMaster->GetPrecede();
305 if (pMaster != pSelFly)
307 // A follow fly frame is selected, select the master instead. Selection of a follow
308 // would not be ideal, since one can't customize its vertical position (always
309 // starts at the top of the page).
310 pDView->UnmarkAll();
311 pDView->MarkObj(pMaster->DrawObj(), Imp()->GetPageView(), bAddSelect, bEnterGroup);
316 if ( rMrkList.GetMarkCount() == 1 )
318 SwFlyFrame *pSelFly = ::GetFlyFromMarked( &rMrkList, this );
319 if (pSelFly)
320 pSelFly->SelectionHasChanged(this);
323 SwFrameFormat* pNewDrawFormat = nullptr;
324 if (!(nFlag & SW_ALLOW_TEXTBOX))
326 // If the fly frame is a textbox of a shape, then select the shape instead.
327 for (size_t i = 0; i < rMrkList.GetMarkCount(); ++i)
329 SdrObject* pObject = rMrkList.GetMark(i)->GetMarkedSdrObj();
330 SwContact* pContact = GetUserCall(pObject);
331 if (!pContact)
333 continue;
336 SwFrameFormat* pFormat = pContact->GetFormat();
337 if (SwFrameFormat* pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT))
339 SdrObject* pShape = pShapeFormat->FindSdrObject();
340 pDView->UnmarkAll();
341 pDView->MarkObj(pShape, Imp()->GetPageView(), bAddSelect, bEnterGroup);
342 // Remember that this frame format was marked for selection.
343 pNewDrawFormat = pShapeFormat;
344 break;
349 if ( bRet )
351 ::lcl_GrabCursor(this, pOldSelFly, pNewDrawFormat);
352 if ( GetCntType() & CNT_GRF )
354 const SwFlyFrame *pTmp = GetFlyFromMarked( &rMrkList, this );
355 OSL_ENSURE( pTmp, "Graphic without Fly" );
356 if ( pTmp && static_cast<const SwNoTextFrame*>(pTmp->Lower())->HasAnimation() )
357 static_cast<const SwNoTextFrame*>(pTmp->Lower())->StopAnimation( GetOut() );
360 else if ( !pOldSelFly && bHadSelection )
361 SetCursor( aOldPos, true);
363 if( bRet || !bHadSelection )
364 CallChgLnk();
366 // update status line
367 ::FrameNotify( this, bRet ? FLY_DRAG_START : FLY_DRAG_END );
369 EndAction();
370 return bRet;
374 * Description: MoveAnchor( nDir ) looked for an another Anchor for
375 * the selected drawing object (or fly frame) in the given direction.
376 * An object "as character" doesn't moves anyway.
377 * A page bounded object could move to the previous/next page with up/down,
378 * an object bounded "at paragraph" moves to the previous/next paragraph, too.
379 * An object bounded "at character" moves to the previous/next paragraph
380 * with up/down and to the previous/next character with left/right.
381 * If the anchor for at paragraph/character bounded objects has vertical or
382 * right_to_left text direction, the directions for up/down/left/right will
383 * interpreted accordingly.
384 * An object bounded "at fly" takes the center of the actual anchor and looks
385 * for the nearest fly frame in the given direction.
388 static bool LessX( Point const & aPt1, Point const & aPt2, bool bOld )
390 return aPt1.getX() < aPt2.getX()
391 || ( aPt1.getX() == aPt2.getX()
392 && ( aPt1.getY() < aPt2.getY()
393 || ( aPt1.getY() == aPt2.getY() && bOld ) ) );
395 static bool LessY( Point const & aPt1, Point const & aPt2, bool bOld )
397 return aPt1.getY() < aPt2.getY()
398 || ( aPt1.getY() == aPt2.getY()
399 && ( aPt1.getX() < aPt2.getX()
400 || ( aPt1.getX() == aPt2.getX() && bOld ) ) );
403 bool SwFEShell::MoveAnchor( SwMove nDir )
405 if (!Imp()->GetDrawView())
406 return false;
407 const SdrMarkList& pMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
408 if (1 != pMrkList.GetMarkCount())
409 return false;
410 SwFrame* pOld;
411 SwFlyFrame* pFly = nullptr;
412 SdrObject *pObj = pMrkList.GetMark( 0 )->GetMarkedSdrObj();
413 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
415 pFly = pVirtO->GetFlyFrame();
416 pOld = pFly->AnchorFrame();
418 else
419 pOld = static_cast<SwDrawContact*>(GetUserCall(pObj))->GetAnchorFrame( pObj );
420 bool bRet = false;
421 if( pOld )
423 SwFrame* pNew = pOld;
424 // #i28701#
425 SwAnchoredObject* pAnchoredObj = ::GetUserCall( pObj )->GetAnchoredObj( pObj );
426 SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat();
427 SwFormatAnchor aAnch( rFormat.GetAnchor() );
428 RndStdIds nAnchorId = aAnch.GetAnchorId();
429 if ( RndStdIds::FLY_AS_CHAR == nAnchorId )
430 return false;
431 if( pOld->IsVertical() )
433 if( pOld->IsTextFrame() )
435 switch( nDir ) {
436 case SwMove::UP: nDir = SwMove::LEFT; break;
437 case SwMove::DOWN: nDir = SwMove::RIGHT; break;
438 case SwMove::LEFT: nDir = SwMove::DOWN; break;
439 case SwMove::RIGHT: nDir = SwMove::UP; break;
441 if( pOld->IsRightToLeft() )
443 if( nDir == SwMove::LEFT )
444 nDir = SwMove::RIGHT;
445 else if( nDir == SwMove::RIGHT )
446 nDir = SwMove::LEFT;
450 switch ( nAnchorId ) {
451 case RndStdIds::FLY_AT_PAGE:
453 OSL_ENSURE( pOld->IsPageFrame(), "Wrong anchor, page expected." );
454 if( SwMove::UP == nDir )
455 pNew = pOld->GetPrev();
456 else if( SwMove::DOWN == nDir )
457 pNew = pOld->GetNext();
458 if( pNew && pNew != pOld )
460 aAnch.SetPageNum( static_cast<SwPageFrame*>(pNew)->GetPhyPageNum() );
461 bRet = true;
463 break;
465 case RndStdIds::FLY_AT_CHAR:
467 OSL_ENSURE(pOld->IsTextFrame(), "Wrong anchor, text frame expected.");
468 if( SwMove::LEFT == nDir || SwMove::RIGHT == nDir )
470 SwPosition pos = *aAnch.GetContentAnchor();
471 SwTextFrame *const pOldFrame(static_cast<SwTextFrame*>(pOld));
472 TextFrameIndex const nAct(pOldFrame->MapModelToViewPos(pos));
473 if( SwMove::LEFT == nDir )
475 bRet = true;
476 if( nAct )
478 pos = pOldFrame->MapViewToModelPos(nAct - TextFrameIndex(1));
480 else
481 nDir = SwMove::UP;
483 else
485 TextFrameIndex const nMax(pOldFrame->GetText().getLength());
486 if( nAct < nMax )
488 bRet = true;
489 pos = pOldFrame->MapViewToModelPos(nAct + TextFrameIndex(1));
491 else
492 nDir = SwMove::DOWN;
494 if( pos != *aAnch.GetContentAnchor())
495 aAnch.SetAnchor( &pos );
497 [[fallthrough]];
499 case RndStdIds::FLY_AT_PARA:
501 OSL_ENSURE(pOld->IsTextFrame(), "Wrong anchor, text frame expected.");
502 if( SwMove::UP == nDir )
503 pNew = pOld->FindPrev();
504 else if( SwMove::DOWN == nDir )
505 pNew = pOld->FindNext();
506 if( pNew && pNew != pOld && pNew->IsContentFrame() )
508 SwTextFrame *const pNewFrame(static_cast<SwTextFrame*>(pNew));
509 SwPosition const pos = pNewFrame->MapViewToModelPos(
510 TextFrameIndex(
511 (bRet && pNewFrame->GetText().getLength() != 0)
512 ? pNewFrame->GetText().getLength() - 1
513 : 0));
514 aAnch.SetAnchor( &pos );
515 bRet = true;
517 else if( SwMove::UP == nDir || SwMove::DOWN == nDir )
518 bRet = false;
519 break;
521 case RndStdIds::FLY_AT_FLY:
523 OSL_ENSURE( pOld->IsFlyFrame(), "Wrong anchor, fly frame expected.");
524 SwPageFrame* pPage = pOld->FindPageFrame();
525 OSL_ENSURE( pPage, "Where's my page?" );
526 SwFlyFrame* pNewFly = nullptr;
527 if( pPage->GetSortedObjs() )
529 bool bOld = false;
530 Point aCenter( pOld->getFrameArea().Left() + pOld->getFrameArea().Width()/2,
531 pOld->getFrameArea().Top() + pOld->getFrameArea().Height()/2 );
532 Point aBest;
533 for(SwAnchoredObject* pAnchObj : *pPage->GetSortedObjs())
535 if( auto pTmp = pAnchObj->DynCastFlyFrame() )
537 if( pTmp == pOld )
538 bOld = true;
539 else
541 const SwFlyFrame* pCheck = pFly ? pTmp : nullptr;
542 while( pCheck )
544 if( pCheck == pFly )
545 break;
546 const SwFrame *pNxt = pCheck->GetAnchorFrame();
547 pCheck = pNxt ? pNxt->FindFlyFrame() : nullptr;
549 if( pCheck || pTmp->IsProtected() )
550 continue;
551 Point aNew( pTmp->getFrameArea().Left() +
552 pTmp->getFrameArea().Width()/2,
553 pTmp->getFrameArea().Top() +
554 pTmp->getFrameArea().Height()/2 );
555 bool bAccept = false;
556 switch( nDir ) {
557 case SwMove::RIGHT:
559 bAccept = LessX( aCenter, aNew, bOld )
560 && ( !pNewFly ||
561 LessX( aNew, aBest, false ) );
562 break;
564 case SwMove::LEFT:
566 bAccept = LessX( aNew, aCenter, !bOld )
567 && ( !pNewFly ||
568 LessX( aBest, aNew, true ) );
569 break;
571 case SwMove::UP:
573 bAccept = LessY( aNew, aCenter, !bOld )
574 && ( !pNewFly ||
575 LessY( aBest, aNew, true ) );
576 break;
578 case SwMove::DOWN:
580 bAccept = LessY( aCenter, aNew, bOld )
581 && ( !pNewFly ||
582 LessY( aNew, aBest, false ) );
583 break;
586 if( bAccept )
588 pNewFly = pTmp;
589 aBest = aNew;
596 if( pNewFly )
598 SwPosition aPos( *pNewFly->GetFormat()->
599 GetContent().GetContentIdx());
600 aAnch.SetAnchor( &aPos );
601 bRet = true;
603 break;
605 default: break;
607 if( bRet )
609 StartAllAction();
610 // --> handle change of anchor node:
611 // if count of the anchor frame also change, the fly frames have to be
612 // re-created. Thus, delete all fly frames except the <this> before the
613 // anchor attribute is change and re-create them afterwards.
615 std::unique_ptr<SwHandleAnchorNodeChg> pHandleAnchorNodeChg;
616 SwFlyFrameFormat* pFlyFrameFormat( dynamic_cast<SwFlyFrameFormat*>(&rFormat) );
617 if ( pFlyFrameFormat )
619 pHandleAnchorNodeChg.reset(
620 new SwHandleAnchorNodeChg( *pFlyFrameFormat, aAnch ));
622 rFormat.GetDoc()->SetAttr( aAnch, rFormat );
624 // #i28701# - no call of method
625 // <CheckCharRectAndTopOfLine()> for to-character anchored
626 // Writer fly frame needed. This method call can cause a
627 // format of the anchor frame, which is no longer intended.
628 // Instead clear the anchor character rectangle and
629 // the top of line values for all to-character anchored objects.
630 pAnchoredObj->ClearCharRectAndTopOfLine();
631 EndAllAction();
634 return bRet;
637 const SdrMarkList* SwFEShell::GetMarkList_() const
639 const SdrMarkList* pMarkList = nullptr;
640 if( Imp()->GetDrawView() != nullptr )
641 pMarkList = &Imp()->GetDrawView()->GetMarkedObjectList();
642 return pMarkList;
645 FrameTypeFlags SwFEShell::GetSelFrameType() const
647 FrameTypeFlags eType;
649 // get marked frame list, and check if anything is selected
650 const SdrMarkList* pMarkList = GetMarkList_();
651 if( pMarkList == nullptr || pMarkList->GetMarkCount() == 0 )
652 eType = FrameTypeFlags::NONE;
653 else
655 // obtain marked item as fly frame; if no fly frame, it must
656 // be a draw object
657 const SwFlyFrame* pFly = ::GetFlyFromMarked(pMarkList, const_cast<SwFEShell*>(this));
658 if ( pFly != nullptr )
660 if( pFly->IsFlyLayFrame() )
661 eType = FrameTypeFlags::FLY_FREE;
662 else if( pFly->IsFlyAtContentFrame() )
663 eType = FrameTypeFlags::FLY_ATCNT;
664 else
666 OSL_ENSURE( pFly->IsFlyInContentFrame(), "New frametype?" );
667 eType = FrameTypeFlags::FLY_INCNT;
670 else
671 eType = FrameTypeFlags::DRAWOBJ;
674 return eType;
677 // does the draw selection contain a control?
678 bool SwFEShell::IsSelContainsControl() const
680 bool bRet = false;
682 // basically, copy the mechanism from GetSelFrameType(), but call
683 // CheckControl... if you get a drawing object
684 const SdrMarkList* pMarkList = GetMarkList_();
685 if( pMarkList != nullptr && pMarkList->GetMarkCount() == 1 )
687 // if we have one marked object, get the SdrObject and check
688 // whether it contains a control
689 const SdrObject* pSdrObject = pMarkList->GetMark( 0 )->GetMarkedSdrObj();
690 bRet = pSdrObject && ::CheckControlLayer( pSdrObject );
692 return bRet;
695 void SwFEShell::ScrollTo( const Point &rPt )
697 const SwRect aRect( rPt, rPt );
698 if ( IsScrollMDI( this, aRect ) &&
699 (!Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() ||
700 Imp()->IsDragPossible( rPt )) )
702 ScrollMDI( this, aRect, SCROLLVAL, SCROLLVAL );
706 void SwFEShell::SetDragMode( SdrDragMode eDragMode )
708 if ( Imp()->HasDrawView() )
709 Imp()->GetDrawView()->SetDragMode( eDragMode );
712 SdrDragMode SwFEShell::GetDragMode() const
714 SdrDragMode nRet = SdrDragMode(0);
715 if ( Imp()->HasDrawView() )
717 nRet = Imp()->GetDrawView()->GetDragMode();
719 return nRet;
722 void SwFEShell::StartCropImage()
724 if ( !Imp()->HasDrawView() )
726 return;
728 SdrView *pView = Imp()->GetDrawView();
729 if (!pView) return;
731 const SdrMarkList &rMarkList = pView->GetMarkedObjectList();
732 if( 0 == rMarkList.GetMarkCount() ) {
733 // No object selected
734 return;
737 // If more than a single SwVirtFlyDrawObj is selected, select only the first SwVirtFlyDrawObj
738 if ( rMarkList.GetMarkCount() > 1 )
740 for ( size_t i = 0; i < rMarkList.GetMarkCount(); ++i )
742 SdrObject *pTmpObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
743 bool bForget = dynamic_cast<const SwVirtFlyDrawObj*>( pTmpObj) != nullptr;
744 if( bForget )
746 pView->UnmarkAll();
747 pView->MarkObj( pTmpObj, Imp()->GetPageView() );
748 break;
753 // Activate CROP mode
754 pView->SetEditMode( SdrViewEditMode::Edit );
755 SetDragMode( SdrDragMode::Crop );
758 void SwFEShell::BeginDrag( const Point* pPt, bool bIsShift)
760 SdrView *pView = Imp()->GetDrawView();
761 if ( pView && pView->AreObjectsMarked() )
763 m_pChainFrom.reset();
764 m_pChainTo.reset();
765 SdrHdl* pHdl = pView->PickHandle( *pPt );
766 if (pView->BegDragObj( *pPt, nullptr, pHdl ))
767 pView->GetDragMethod()->SetShiftPressed( bIsShift );
768 ::FrameNotify( this );
772 void SwFEShell::Drag( const Point *pPt, bool )
774 OSL_ENSURE( Imp()->HasDrawView(), "Drag without DrawView?" );
775 if ( HasDrawViewDrag() )
777 ScrollTo( *pPt );
778 Imp()->GetDrawView()->MovDragObj( *pPt );
779 Imp()->GetDrawView()->ShowDragAnchor();
780 ::FrameNotify( this );
784 void SwFEShell::EndDrag()
786 OSL_ENSURE( Imp()->HasDrawView(), "EndDrag without DrawView?" );
787 SdrView *pView = Imp()->GetDrawView();
788 if ( !pView->IsDragObj() )
789 return;
791 for(SwViewShell& rSh : GetRingContainer())
792 rSh.StartAction();
794 StartUndo( SwUndoId::START );
796 // #50778# Bug during dragging: In StartAction a HideShowXor is called.
797 // In EndDragObj() this is reversed, for no reason and even wrong.
798 // To restore consistency we should bring up the Xor again.
800 // Reanimation from the hack #50778 to fix bug #97057
801 // May be not the best solution, but the one with lowest risc at the moment.
802 // pView->ShowShownXor( GetOut() );
804 pView->EndDragObj();
806 // DrawUndo on to flyframes are not stored
807 // The flys change the flag.
808 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
809 ChgAnchor( RndStdIds::FLY_AT_PARA, true );
811 EndUndo( SwUndoId::END );
813 for(SwViewShell& rSh : GetRingContainer())
815 rSh.EndAction();
816 if( auto pCursorShell = dynamic_cast<SwCursorShell *>(&rSh) )
817 pCursorShell->CallChgLnk();
820 GetDoc()->getIDocumentState().SetModified();
821 ::FrameNotify( this );
824 void SwFEShell::BreakDrag()
826 OSL_ENSURE( Imp()->HasDrawView(), "BreakDrag without DrawView?" );
827 if( HasDrawViewDrag() )
828 Imp()->GetDrawView()->BrkDragObj();
829 SetChainMarker();
832 // If a fly is selected, pulls the crsr in the first ContentFrame
833 const SwFrameFormat* SwFEShell::SelFlyGrabCursor()
835 if ( Imp()->HasDrawView() )
837 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
838 SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
840 if( pFly )
842 SwContentFrame *pCFrame = pFly->ContainsContent();
843 if ( pCFrame )
845 // --> assure, that the cursor is consistent.
846 KillPams();
847 ClearMark();
848 SwPaM *pCursor = GetCursor();
850 if (pCFrame->IsTextFrame())
852 *pCursor->GetPoint() = static_cast<SwTextFrame *>(pCFrame)
853 ->MapViewToModelPos(TextFrameIndex(0));
855 else
857 assert(pCFrame->IsNoTextFrame());
858 SwContentNode *const pCNode = static_cast<SwNoTextFrame *>(pCFrame)->GetNode();
859 pCursor->GetPoint()->Assign(*pCNode);
862 SwRect& rChrRect = const_cast<SwRect&>(GetCharRect());
863 rChrRect = pFly->getFramePrintArea();
864 rChrRect.Pos() += pFly->getFrameArea().Pos();
865 GetCursorDocPos() = rChrRect.Pos();
867 return pFly->GetFormat();
870 return nullptr;
873 // Selection to above/below (Z-Order)
874 static void lcl_NotifyNeighbours( const SdrMarkList *pLst )
876 // Rules for evasion have changed.
877 // 1. The environment of the fly and everything inside should be notified
878 // 2. The content of the frame itself has to be notified
879 // 3. Frames displaced by the frame have to be notified
880 // 4. Also Drawing objects can displace frames
881 for( size_t j = 0; j < pLst->GetMarkCount(); ++j )
883 SwPageFrame *pPage;
884 bool bCheckNeighbours = false;
885 sal_Int16 aHori = text::HoriOrientation::NONE;
886 SwRect aRect;
887 SdrObject *pO = pLst->GetMark( j )->GetMarkedSdrObj();
888 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pO))
890 SwFlyFrame *pFly = pVirtO->GetFlyFrame();
892 const SwFormatHoriOrient &rHori = pFly->GetFormat()->GetHoriOrient();
893 aHori = rHori.GetHoriOrient();
894 if( text::HoriOrientation::NONE != aHori && text::HoriOrientation::CENTER != aHori &&
895 pFly->IsFlyAtContentFrame() )
897 bCheckNeighbours = true;
898 pFly->InvalidatePos();
899 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFly);
900 aFrm.Pos().AdjustY(1 );
903 pPage = pFly->FindPageFrame();
904 aRect = pFly->getFrameArea();
906 else
908 SwFrame* pAnch = static_cast<SwDrawContact*>( GetUserCall(pO) )->GetAnchorFrame( pO );
909 if( !pAnch )
910 continue;
911 pPage = pAnch->FindPageFrame();
912 // #i68520# - naming changed
913 aRect = GetBoundRectOfAnchoredObj( pO );
916 const size_t nCount = pPage->GetSortedObjs() ? pPage->GetSortedObjs()->size() : 0;
917 for ( size_t i = 0; i < nCount; ++i )
919 SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
920 SwFlyFrame* pAct = pAnchoredObj->DynCastFlyFrame();
921 if ( !pAct )
922 continue;
924 SwRect aTmpCalcPnt( pAct->getFramePrintArea() );
925 aTmpCalcPnt += pAct->getFrameArea().Pos();
926 if ( aRect.Overlaps( aTmpCalcPnt ) )
928 SwContentFrame *pCnt = pAct->ContainsContent();
929 while ( pCnt )
931 aTmpCalcPnt = pCnt->getFramePrintArea();
932 aTmpCalcPnt += pCnt->getFrameArea().Pos();
933 if ( aRect.Overlaps( aTmpCalcPnt ) )
934 static_cast<SwFrame*>(pCnt)->Prepare( PrepareHint::FlyFrameAttributesChanged );
935 pCnt = pCnt->GetNextContentFrame();
938 if ( bCheckNeighbours && pAct->IsFlyAtContentFrame() )
940 const SwFormatHoriOrient &rH = pAct->GetFormat()->GetHoriOrient();
941 if ( rH.GetHoriOrient() == aHori &&
942 pAct->getFrameArea().Top() <= aRect.Bottom() &&
943 pAct->getFrameArea().Bottom() >= aRect.Top() )
945 pAct->InvalidatePos();
946 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pAct);
947 aFrm.Pos().AdjustY(1 );
954 void SwFEShell::SetLineEnds(SfxItemSet& rAttr, SdrObject const & rObj, sal_uInt16 nSlotId)
956 SdrModel& rModel(rObj.getSdrModelFromSdrObject());
958 if ( !(nSlotId == SID_LINE_ARROW_START ||
959 nSlotId == SID_LINE_ARROW_END ||
960 nSlotId == SID_LINE_ARROWS ||
961 nSlotId == SID_LINE_ARROW_CIRCLE ||
962 nSlotId == SID_LINE_CIRCLE_ARROW ||
963 nSlotId == SID_LINE_ARROW_SQUARE ||
964 nSlotId == SID_LINE_SQUARE_ARROW ||
965 nSlotId == SID_DRAW_MEASURELINE) )
966 return;
968 // set attributes of line start and ends
970 // arrowhead
971 ::basegfx::B2DPolyPolygon aArrow( getPolygon( RID_SVXSTR_ARROW, rModel ) );
972 if( !aArrow.count() )
974 ::basegfx::B2DPolygon aNewArrow;
975 aNewArrow.append(::basegfx::B2DPoint(10.0, 0.0));
976 aNewArrow.append(::basegfx::B2DPoint(0.0, 30.0));
977 aNewArrow.append(::basegfx::B2DPoint(20.0, 30.0));
978 aNewArrow.setClosed(true);
979 aArrow.append(aNewArrow);
982 // Circles
983 ::basegfx::B2DPolyPolygon aCircle( getPolygon( RID_SVXSTR_CIRCLE, rModel ) );
984 if( !aCircle.count() )
986 ::basegfx::B2DPolygon aNewCircle = ::basegfx::utils::createPolygonFromEllipse(::basegfx::B2DPoint(0.0, 0.0), 250.0, 250.0);
987 aNewCircle.setClosed(true);
988 aCircle.append(aNewCircle);
991 // Square
992 ::basegfx::B2DPolyPolygon aSquare( getPolygon( RID_SVXSTR_SQUARE, rModel ) );
993 if( !aSquare.count() )
995 ::basegfx::B2DPolygon aNewSquare;
996 aNewSquare.append(::basegfx::B2DPoint(0.0, 0.0));
997 aNewSquare.append(::basegfx::B2DPoint(10.0, 0.0));
998 aNewSquare.append(::basegfx::B2DPoint(10.0, 10.0));
999 aNewSquare.append(::basegfx::B2DPoint(0.0, 10.0));
1000 aNewSquare.setClosed(true);
1001 aSquare.append(aNewSquare);
1004 SfxItemSet aSet( rModel.GetItemPool() );
1005 tools::Long nWidth = 100; // (1/100th mm)
1007 // determine line width and calculate with it the line end width
1008 if( aSet.GetItemState( XATTR_LINEWIDTH ) != SfxItemState::DONTCARE )
1010 tools::Long nValue = aSet.Get( XATTR_LINEWIDTH ).GetValue();
1011 if( nValue > 0 )
1012 nWidth = nValue * 3;
1015 switch (nSlotId)
1017 case SID_LINE_ARROWS:
1018 case SID_DRAW_MEASURELINE:
1020 // connector with arrow ends
1021 rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
1022 rAttr.Put(XLineStartWidthItem(nWidth));
1023 rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
1024 rAttr.Put(XLineEndWidthItem(nWidth));
1026 break;
1028 case SID_LINE_ARROW_START:
1029 case SID_LINE_ARROW_CIRCLE:
1030 case SID_LINE_ARROW_SQUARE:
1032 // connector with arrow start
1033 rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
1034 rAttr.Put(XLineStartWidthItem(nWidth));
1036 break;
1038 case SID_LINE_ARROW_END:
1039 case SID_LINE_CIRCLE_ARROW:
1040 case SID_LINE_SQUARE_ARROW:
1042 // connector with arrow end
1043 rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
1044 rAttr.Put(XLineEndWidthItem(nWidth));
1046 break;
1049 // and again, for the still missing ends
1050 switch (nSlotId)
1052 case SID_LINE_ARROW_CIRCLE:
1054 // circle end
1055 rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
1056 rAttr.Put(XLineEndWidthItem(nWidth));
1058 break;
1060 case SID_LINE_CIRCLE_ARROW:
1062 // circle start
1063 rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
1064 rAttr.Put(XLineStartWidthItem(nWidth));
1066 break;
1068 case SID_LINE_ARROW_SQUARE:
1070 // square end
1071 rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_SQUARE), aSquare));
1072 rAttr.Put(XLineEndWidthItem(nWidth));
1074 break;
1076 case SID_LINE_SQUARE_ARROW:
1078 // square start
1079 rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_SQUARE), aSquare));
1080 rAttr.Put(XLineStartWidthItem(nWidth));
1082 break;
1087 void SwFEShell::SelectionToTop( bool bTop )
1089 OSL_ENSURE( Imp()->HasDrawView(), "SelectionToTop without DrawView?" );
1090 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1091 OSL_ENSURE( rMrkList.GetMarkCount(), "No object selected." );
1093 SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
1094 if ( pFly && pFly->IsFlyInContentFrame() )
1095 return;
1097 StartAllAction();
1098 if ( bTop )
1099 Imp()->GetDrawView()->PutMarkedToTop();
1100 else
1101 Imp()->GetDrawView()->MovMarkedToTop();
1102 ::lcl_NotifyNeighbours( &rMrkList );
1104 // Does the selection contain a textbox?
1105 for (size_t i = 0; i < rMrkList.GetMarkCount(); i++)
1106 if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
1107 // Get the textbox-shape
1108 if (auto pFormat = FindFrameFormat(pObj))
1110 // If it has not textframe skip...
1111 if (!SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, pObj))
1112 continue;
1113 // If it has a textframe so it is a textbox, get its page
1114 if (auto pDrwModel
1115 = pFormat->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel())
1116 // Not really understood why everything is on page 0...
1117 // but it is easier to handle sdrobjects, that's true
1118 if (auto pPage = pDrwModel->GetPage(0))
1120 // nShift: it means how many layers the pObj have to be shifted up,
1121 // in order not to interfere with other shapes and textboxes.
1122 // Situations:
1123 // - The next shape has textframe: This shape have to shifted with
1124 // two layers.
1125 // - The next shape has not got textframe: This shape have to be
1126 // shifted only one layer up.
1127 // - The next shape is null:
1128 // - This shape is already at heaven: Only the textframe have
1129 // to be adjusted.
1130 sal_uInt32 nShift = 0;
1131 // Get the one level higher object (note: can be nullptr!)
1132 const auto pNextObj = pPage->SetObjectOrdNum(pObj->GetOrdNum() + 1, pObj->GetOrdNum() + 1);
1133 // If there is a higher object (not null)...
1134 if (pNextObj)
1136 // One level shift is necessary
1137 nShift++;
1138 // If this object is a textbox, two level increasing needed
1139 // (one for the shape and one for the frame)
1140 if (auto pNextFormat = FindFrameFormat(pNextObj))
1141 if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT, pNextObj)
1142 || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
1143 nShift++;
1145 // Set the new z-order.
1146 pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() + nShift);
1148 // The shape is on the right level, correct the layer of the frame
1149 SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat, pObj);
1152 GetDoc()->getIDocumentState().SetModified();
1153 EndAllAction();
1156 void SwFEShell::SelectionToBottom( bool bBottom )
1158 OSL_ENSURE( Imp()->HasDrawView(), "SelectionToBottom without DrawView?" );
1159 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1160 OSL_ENSURE( rMrkList.GetMarkCount(), "No object selected." );
1162 SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
1163 if ( pFly && pFly->IsFlyInContentFrame() )
1164 return;
1166 StartAllAction();
1167 if ( bBottom )
1168 Imp()->GetDrawView()->PutMarkedToBtm();
1169 else
1170 Imp()->GetDrawView()->MovMarkedToBtm();
1171 ::lcl_NotifyNeighbours( &rMrkList );
1173 // If the selection has textbox
1174 for(size_t i = 0; i < rMrkList.GetMarkCount(); i++)
1175 if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
1176 // Get the shape of the textbox
1177 if (auto pFormat = FindFrameFormat(pObj))
1179 // If the shape has not textframes skip.
1180 if (!SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, pObj))
1181 continue;
1182 // If has, move the shape to correct level with...
1183 if (auto pDrwModel
1184 = pFormat->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel())
1185 if (auto pPage = pDrwModel->GetPage(0))
1187 const auto pNextObj = pPage->SetObjectOrdNum(pObj->GetOrdNum() - 1, pObj->GetOrdNum() - 1);
1188 // If there is a lower object (not null)...
1189 if (pNextObj)
1191 // If the lower has no textframe, just do nothing, else move by one lower
1192 if (auto pNextFormat = FindFrameFormat(pNextObj))
1193 if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT, pNextObj)
1194 || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
1195 pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() - 1);
1198 // And set correct layer for the selected textbox.
1199 SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat, pObj);
1202 GetDoc()->getIDocumentState().SetModified();
1203 EndAllAction();
1206 // Object above/below the document? 2 Controls, 1 Heaven, 0 Hell,
1207 // SDRLAYER_NOTFOUND Ambiguous
1208 SdrLayerID SwFEShell::GetLayerId() const
1210 if ( !Imp()->HasDrawView() )
1211 return SDRLAYER_NOTFOUND;
1213 SdrLayerID nRet = SDRLAYER_NOTFOUND;
1214 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1215 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
1217 const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
1218 if( !pObj )
1219 continue;
1220 if ( nRet == SDRLAYER_NOTFOUND )
1221 nRet = pObj->GetLayer();
1222 else if ( nRet != pObj->GetLayer() )
1224 return SDRLAYER_NOTFOUND;
1227 return nRet;
1230 // Object above/below the document
1231 // Note: only visible objects can be marked. Thus, objects with invisible
1232 // layer IDs have not to be considered.
1233 // If <SwFEShell> exists, layout exists!!
1234 void SwFEShell::ChangeOpaque( SdrLayerID nLayerId )
1236 if ( !Imp()->HasDrawView() )
1237 return;
1239 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1240 const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess();
1241 // correct type of <nControls>
1242 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
1244 SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
1245 if( !pObj )
1246 continue;
1247 // or group objects containing controls.
1248 // --> #i113730#
1249 // consider that a member of a drawing group has been selected.
1250 const SwContact* pContact = ::GetUserCall( pObj );
1251 OSL_ENSURE( pContact && pContact->GetMaster(), "<SwFEShell::ChangeOpaque(..)> - missing contact or missing master object at contact!" );
1252 const bool bControlObj = ( pContact && pContact->GetMaster() )
1253 ? ::CheckControlLayer( pContact->GetMaster() )
1254 : ::CheckControlLayer( pObj );
1255 if ( !bControlObj && pObj->GetLayer() != nLayerId )
1257 pObj->SetLayer( nLayerId );
1258 InvalidateWindows( SwRect( pObj->GetCurrentBoundRect() ) );
1259 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
1261 SwFormat *pFormat = pVirtO->GetFlyFrame()->GetFormat();
1262 SvxOpaqueItem aOpa( pFormat->GetOpaque() );
1263 aOpa.SetValue( nLayerId == rIDDMA.GetHellId() );
1264 pFormat->SetFormatAttr( aOpa );
1265 // If pObj has textframe, put its textframe to the right level
1266 if (auto pTextBx = FindFrameFormat(pObj))
1267 SwTextBoxHelper::DoTextBoxZOrderCorrection(pTextBx, pObj);
1271 GetDoc()->getIDocumentState().SetModified();
1274 void SwFEShell::SelectionToHeaven()
1276 ChangeOpaque( getIDocumentDrawModelAccess().GetHeavenId() );
1279 void SwFEShell::SelectionToHell()
1281 ChangeOpaque( getIDocumentDrawModelAccess().GetHellId() );
1284 size_t SwFEShell::IsObjSelected() const
1286 if ( IsFrameSelected() || !Imp()->HasDrawView() )
1287 return 0;
1289 return Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount();
1292 bool SwFEShell::IsFrameSelected() const
1294 if ( !Imp()->HasDrawView() )
1295 return false;
1296 else
1297 return nullptr != ::GetFlyFromMarked( &Imp()->GetDrawView()->GetMarkedObjectList(),
1298 const_cast<SwFEShell*>(this) );
1301 bool SwFEShell::IsObjSelected( const SdrObject& rObj ) const
1303 if ( IsFrameSelected() || !Imp()->HasDrawView() )
1304 return false;
1305 else
1306 return Imp()->GetDrawView()->IsObjMarked( &rObj );
1309 bool SwFEShell::IsRotationOfSwGrfNodePossible() const
1311 // RotGrfFlyFrame: check if RotationMode is possible
1312 const SdrView *pSdrView = Imp()->GetDrawView();
1314 if(pSdrView)
1316 const SdrMarkList& rList(pSdrView->GetMarkedObjectList());
1318 if(1 == rList.GetMarkCount())
1320 const SwVirtFlyDrawObj* pVirtFlyDraw(dynamic_cast< const SwVirtFlyDrawObj* >(rList.GetMark(0)->GetMarkedSdrObj()));
1322 if(nullptr != pVirtFlyDraw)
1324 return pVirtFlyDraw->ContainsSwGrfNode();
1329 return false;
1332 bool SwFEShell::IsObjSameLevelWithMarked(const SdrObject* pObj) const
1334 if (pObj)
1336 const SdrMarkList& aMarkList = Imp()->GetDrawView()->GetMarkedObjectList();
1337 if (aMarkList.GetMarkCount() == 0)
1339 return true;
1341 SdrMark* pM=aMarkList.GetMark(0);
1342 if (pM)
1344 SdrObject* pMarkObj = pM->GetMarkedSdrObj();
1345 if (pMarkObj && pMarkObj->getParentSdrObjectFromSdrObject() == pObj->getParentSdrObjectFromSdrObject())
1346 return true;
1349 return false;
1352 void SwFEShell::EndTextEdit()
1354 // Terminate the TextEditMode. If required (default if the object
1355 // does not contain any more text and does not carry attributes) the object
1356 // is deleted. All other objects marked are preserved.
1358 OSL_ENSURE( Imp()->HasDrawView() && Imp()->GetDrawView()->IsTextEdit(),
1359 "EndTextEdit a no Object" );
1361 StartAllAction();
1362 SdrView *pView = Imp()->GetDrawView();
1363 SdrObject *pObj = pView->GetTextEditObject();
1364 SdrObjUserCall* pUserCall = GetUserCall(pObj);
1365 if( nullptr != pUserCall )
1367 SdrObject *pTmp = static_cast<SwContact*>(pUserCall)->GetMaster();
1368 if( !pTmp )
1369 pTmp = pObj;
1370 pUserCall->Changed( *pTmp, SdrUserCallType::Resize, pTmp->GetLastBoundRect() );
1372 if ( !pObj->getParentSdrObjectFromSdrObject() )
1374 if ( SdrEndTextEditKind::ShouldBeDeleted == pView->SdrEndTextEdit(true) )
1376 if ( pView->GetMarkedObjectList().GetMarkCount() > 1 )
1378 SdrMarkList aSave( pView->GetMarkedObjectList() );
1379 aSave.DeleteMark( aSave.FindObject( pObj ) );
1380 if ( aSave.GetMarkCount() )
1382 pView->UnmarkAll();
1383 pView->MarkObj( pObj, Imp()->GetPageView() );
1385 DelSelectedObj();
1386 for ( size_t i = 0; i < aSave.GetMarkCount(); ++i )
1387 pView->MarkObj( aSave.GetMark( i )->GetMarkedSdrObj(), Imp()->GetPageView() );
1389 else
1390 DelSelectedObj();
1393 else
1394 pView->SdrEndTextEdit();
1396 if (comphelper::LibreOfficeKit::isActive())
1397 SfxLokHelper::notifyOtherViews(GetSfxViewShell(), LOK_CALLBACK_VIEW_LOCK, "rectangle", "EMPTY");
1399 EndAllAction();
1402 bool SwFEShell::IsInsideSelectedObj( const Point &rPt )
1404 if( Imp()->HasDrawView() )
1406 SwDrawView *pDView = Imp()->GetDrawView();
1408 if( pDView->GetMarkedObjectList().GetMarkCount() &&
1409 pDView->IsMarkedObjHit( rPt ) )
1411 return true;
1414 return false;
1417 bool SwFEShell::IsObjSelectable( const Point& rPt )
1419 CurrShell aCurr(this);
1420 SwDrawView *pDView = Imp()->GetDrawView();
1421 bool bRet = false;
1422 if( pDView )
1424 SdrPageView* pPV;
1425 const auto nOld = pDView->GetHitTolerancePixel();
1426 pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
1428 bRet = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE) != nullptr;
1429 pDView->SetHitTolerancePixel( nOld );
1431 return bRet;
1434 SdrObject* SwFEShell::GetObjAt( const Point& rPt )
1436 SdrObject* pRet = nullptr;
1437 CurrShell aCurr(this);
1438 SwDrawView *pDView = Imp()->GetDrawView();
1439 if( pDView )
1441 SdrPageView* pPV;
1442 const auto nOld = pDView->GetHitTolerancePixel();
1443 pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
1445 pRet = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE);
1446 pDView->SetHitTolerancePixel( nOld );
1448 return pRet;
1451 // Test if there is an object at that position and if it should be selected.
1452 bool SwFEShell::ShouldObjectBeSelected(const Point& rPt)
1454 CurrShell aCurr(this);
1455 SwDrawView *pDrawView = Imp()->GetDrawView();
1456 bool bRet(false);
1458 if(pDrawView)
1460 SdrPageView* pPV;
1461 const auto nOld(pDrawView->GetHitTolerancePixel());
1463 pDrawView->SetHitTolerancePixel(pDrawView->GetMarkHdlSizePixel()/2);
1464 SdrObject* pObj = pDrawView->PickObj(rPt, pDrawView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE);
1465 pDrawView->SetHitTolerancePixel(nOld);
1467 if (pObj)
1469 bRet = true;
1470 const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess();
1471 // #i89920#
1472 // Do not select object in background which is overlapping this text
1473 // at the given position.
1474 bool bObjInBackground( false );
1476 if ( pObj->GetLayer() == rIDDMA.GetHellId() )
1478 const SwAnchoredObject* pAnchoredObj = ::GetUserCall( pObj )->GetAnchoredObj( pObj );
1479 const SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat();
1480 const SwFormatSurround& rSurround = rFormat.GetSurround();
1481 if ( rSurround.GetSurround() == css::text::WrapTextMode_THROUGH )
1483 bObjInBackground = true;
1487 if ( bObjInBackground )
1489 const SwPageFrame* pPageFrame = GetLayout()->GetPageAtPos( rPt );
1490 if( pPageFrame )
1492 const SwContentFrame* pContentFrame( pPageFrame->ContainsContent() );
1493 while ( pContentFrame )
1495 if ( pContentFrame->UnionFrame().Contains( rPt ) )
1497 const SwTextFrame* pTextFrame = pContentFrame->DynCastTextFrame();
1498 if ( pTextFrame )
1500 SwPosition aPos(GetDoc()->GetNodes());
1501 Point aTmpPt( rPt );
1502 if (pTextFrame->GetKeyCursorOfst(&aPos, aTmpPt))
1504 SwRect aCursorCharRect;
1505 if (pTextFrame->GetCharRect(aCursorCharRect,
1506 aPos))
1508 if ( aCursorCharRect.Overlaps( SwRect( pObj->GetLastBoundRect() ) ) )
1510 bRet = false;
1515 else
1517 bRet = false;
1519 break;
1522 pContentFrame = pContentFrame->GetNextContentFrame();
1527 // Don't select header / footer objects in body edition and vice-versa
1528 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
1529 if (pContact && !pContact->ObjAnchoredAtPage() )
1531 const SwNode& rAnchorNode = pContact->GetAnchorNode();
1532 bool bInHdrFtr = GetDoc()->IsInHeaderFooter( rAnchorNode );
1533 if (IsHeaderFooterEdit() != bInHdrFtr)
1535 bRet = false;
1539 if ( bRet )
1541 const SdrPage* pPage = rIDDMA.GetDrawModel()->GetPage(0);
1542 for(size_t a = pObj->GetOrdNum()+1; bRet && a < pPage->GetObjCount(); ++a)
1544 SdrObject *pCandidate = pPage->GetObj(a);
1546 SwVirtFlyDrawObj* pDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pCandidate);
1547 if (pDrawObj && pDrawObj->GetCurrentBoundRect().Contains(rPt))
1549 bRet = false;
1556 return bRet;
1560 * If an object was selected, we assume its upper-left corner
1561 * otherwise the middle of the current CharRects.
1562 * Does the object include a control or groups,
1563 * which comprise only controls
1565 static bool lcl_IsControlGroup( const SdrObject *pObj )
1567 bool bRet = false;
1568 if(dynamic_cast<const SdrUnoObj*>( pObj) != nullptr)
1569 bRet = true;
1570 else if( auto pObjGroup = dynamic_cast<const SdrObjGroup*>( pObj) )
1572 bRet = true;
1573 const SdrObjList *pLst = pObjGroup->GetSubList();
1574 for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
1575 if( !::lcl_IsControlGroup( pLst->GetObj( i ) ) )
1576 return false;
1578 return bRet;
1581 namespace
1583 class MarkableObjectsOnly : public svx::ISdrObjectFilter
1585 public:
1586 explicit MarkableObjectsOnly( SdrPageView* i_pPV )
1587 :m_pPV( i_pPV )
1591 virtual bool includeObject( const SdrObject& i_rObject ) const override
1593 return m_pPV && m_pPV->GetView().IsObjMarkable( &i_rObject, m_pPV );
1596 private:
1597 SdrPageView* m_pPV;
1601 const SdrObject* SwFEShell::GetBestObject(bool bNext, GotoObjFlags eType, bool bFlat,
1602 const svx::ISdrObjectFilter* pFilter,
1603 bool* pbWrapped)
1605 if (pbWrapped)
1606 *pbWrapped = false;
1608 if( !Imp()->HasDrawView() )
1609 return nullptr;
1611 const SdrObject *pBest = nullptr,
1612 *pTop = nullptr;
1614 const tools::Long nTmp = bNext ? LONG_MAX : 0;
1615 Point aBestPos( nTmp, nTmp );
1616 Point aTopPos( nTmp, nTmp );
1617 Point aCurPos;
1618 Point aPos;
1619 bool bNoDraw((GotoObjFlags::DrawAny & eType) == GotoObjFlags::NONE);
1620 bool bNoFly((GotoObjFlags::FlyAny & eType) == GotoObjFlags::NONE);
1622 if( !bNoFly && bNoDraw )
1624 SwFlyFrame *pFly = GetCurrFrame( false )->FindFlyFrame();
1625 if( pFly )
1626 pBest = pFly->GetVirtDrawObj();
1628 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1629 SdrPageView* pPV = Imp()->GetDrawView()->GetSdrPageView();
1631 MarkableObjectsOnly aDefaultFilter( pPV );
1632 if ( !pFilter )
1633 pFilter = &aDefaultFilter;
1635 if( !pBest || rMrkList.GetMarkCount() == 1 )
1637 // Determine starting point
1638 SdrObjList* pList = nullptr;
1639 if ( rMrkList.GetMarkCount() )
1641 const SdrObject* pStartObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
1642 if( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>( pStartObj) )
1643 aPos = pVirtFlyDrawObj->GetFlyFrame()->getFrameArea().Pos();
1644 else
1645 aPos = pStartObj->GetSnapRect().TopLeft();
1647 // If an object inside a group is selected, we want to
1648 // iterate over the group members.
1649 if ( ! pStartObj->GetUserCall() )
1650 pList = pStartObj->getParentSdrObjListFromSdrObject();
1652 else
1654 // If no object is selected, we check if we just entered a group.
1655 // In this case we want to iterate over the group members.
1656 aPos = GetCharRect().Center();
1657 const SdrObject* pStartObj = pPV ? pPV->GetCurrentGroup() : nullptr;
1658 if ( dynamic_cast<const SdrObjGroup*>( pStartObj) )
1659 pList = pStartObj->GetSubList();
1662 if ( ! pList )
1664 // Here we are if
1665 // A No object has been selected and no group has been entered or
1666 // B An object has been selected and it is not inside a group
1667 pList = getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 );
1670 OSL_ENSURE( pList, "No object list to iterate" );
1672 SdrObjListIter aObjIter( pList, bFlat ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups );
1673 while ( aObjIter.IsMore() )
1675 SdrObject* pObj = aObjIter.Next();
1676 SwVirtFlyDrawObj *pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
1677 if( ( bNoFly && pVirtO ) ||
1678 ( bNoDraw && !pVirtO ) ||
1679 // Ignore TextBoxes of draw shapes here, so that
1680 // SwFEShell::SelectObj() won't jump back on this list, meaning
1681 // we never jump to the next draw shape.
1682 (pVirtO && pVirtO->IsTextBox()) ||
1683 ( eType == GotoObjFlags::DrawSimple && lcl_IsControlGroup( pObj ) ) ||
1684 ( eType == GotoObjFlags::DrawControl && !lcl_IsControlGroup( pObj ) ) ||
1685 !pFilter->includeObject( *pObj ) )
1686 continue;
1687 if (pVirtO)
1689 SwFlyFrame *pFly = pVirtO->GetFlyFrame();
1690 if( GotoObjFlags::FlyAny != ( GotoObjFlags::FlyAny & eType ) )
1692 switch ( eType )
1694 case GotoObjFlags::FlyFrame:
1695 if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
1696 continue;
1697 break;
1698 case GotoObjFlags::FlyGrf:
1699 if ( pFly->Lower() &&
1700 (!pFly->Lower()->IsNoTextFrame() ||
1701 !static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetGrfNode()))
1702 continue;
1703 break;
1704 case GotoObjFlags::FlyOLE:
1705 if ( pFly->Lower() &&
1706 (!pFly->Lower()->IsNoTextFrame() ||
1707 !static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetOLENode()))
1708 continue;
1709 break;
1710 default: break;
1713 aCurPos = pFly->getFrameArea().Pos();
1715 else
1716 aCurPos = pObj->GetSnapRect().TopLeft();
1718 // Special case if another object is on same Y.
1719 if( aCurPos != aPos && // only when it is not me
1720 aCurPos.getY() == aPos.getY() && // Y positions equal
1721 (bNext? (aCurPos.getX() > aPos.getX()) : // lies next to me
1722 (aCurPos.getX() < aPos.getX())) ) // " reverse
1724 aBestPos = Point( nTmp, nTmp );
1725 SdrObjListIter aTmpIter( pList, bFlat ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups );
1726 while ( aTmpIter.IsMore() )
1728 SdrObject* pTmpObj = aTmpIter.Next();
1729 pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pTmpObj);
1730 if( ( bNoFly && pVirtO ) || ( bNoDraw && !pVirtO ) )
1731 continue;
1732 if (pVirtO)
1734 aCurPos = pVirtO->GetFlyFrame()->getFrameArea().Pos();
1736 else
1737 aCurPos = pTmpObj->GetCurrentBoundRect().TopLeft();
1739 if( aCurPos != aPos && aCurPos.Y() == aPos.Y() &&
1740 (bNext? (aCurPos.getX() > aPos.getX()) : // lies next to me
1741 (aCurPos.getX() < aPos.getX())) && // " reverse
1742 (bNext? (aCurPos.getX() < aBestPos.getX()) : // better as best
1743 (aCurPos.getX() > aBestPos.getX())) ) // " reverse
1745 aBestPos = aCurPos;
1746 pBest = pTmpObj;
1749 break;
1752 if( (
1753 (bNext? (aPos.getY() < aCurPos.getY()) : // only below me
1754 (aPos.getY() > aCurPos.getY())) && // " reverse
1755 (bNext? (aBestPos.getY() > aCurPos.getY()) : // closer below
1756 (aBestPos.getY() < aCurPos.getY()))
1757 ) || // " reverse
1758 (aBestPos.getY() == aCurPos.getY() &&
1759 (bNext? (aBestPos.getX() > aCurPos.getX()) : // further left
1760 (aBestPos.getX() < aCurPos.getX())))) // " reverse
1763 aBestPos = aCurPos;
1764 pBest = pObj;
1767 if( (bNext? (aTopPos.getY() > aCurPos.getY()) : // higher as best
1768 (aTopPos.getY() < aCurPos.getY())) || // " reverse
1769 (aTopPos.getY() == aCurPos.getY() &&
1770 (bNext? (aTopPos.getX() > aCurPos.getX()) : // further left
1771 (aTopPos.getX() < aCurPos.getX())))) // " reverse
1773 aTopPos = aCurPos;
1774 pTop = pObj;
1777 // unfortunately nothing found
1778 if( bNext ? (aBestPos.getX() == LONG_MAX) : (aBestPos.getX() == 0) )
1780 pBest = pTop;
1781 if (pbWrapped && pBest)
1782 *pbWrapped = true;
1786 return pBest;
1789 bool SwFEShell::GotoObj( bool bNext, GotoObjFlags eType )
1791 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
1793 bool bWrapped(false);
1794 const SdrObject* pBest = GetBestObject(bNext, eType, true, nullptr, &bWrapped);
1796 if ( !pBest )
1798 SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
1799 return false;
1802 const SwVirtFlyDrawObj *pVirtO = dynamic_cast<const SwVirtFlyDrawObj*>(pBest);
1803 if (pVirtO)
1805 const SwRect& rFrame = pVirtO->GetFlyFrame()->getFrameArea();
1806 SelectObj( rFrame.Pos(), 0, const_cast<SdrObject*>(pBest) );
1807 if( !ActionPend() )
1808 MakeVisible( rFrame );
1810 else
1812 SelectObj( Point(), 0, const_cast<SdrObject*>(pBest) );
1813 if( !ActionPend() )
1814 MakeVisible( SwRect(pBest->GetCurrentBoundRect()) );
1816 CallChgLnk();
1818 if (bWrapped)
1819 SvxSearchDialogWrapper::SetSearchLabel(bNext ? SearchLabel::EndWrapped :
1820 SearchLabel::StartWrapped);
1822 return true;
1825 bool SwFEShell::BeginCreate( SdrObjKind eSdrObjectKind, const Point &rPos )
1827 bool bRet = false;
1829 if ( !Imp()->HasDrawView() )
1830 Imp()->MakeDrawView();
1832 if ( GetPageNumber( rPos ) )
1834 Imp()->GetDrawView()->SetCurrentObj( eSdrObjectKind );
1835 if ( eSdrObjectKind == SdrObjKind::Caption )
1836 bRet = Imp()->GetDrawView()->BegCreateCaptionObj(
1837 rPos, Size( lMinBorder - MINFLY, lMinBorder - MINFLY ),
1838 GetOut() );
1839 else
1840 bRet = Imp()->GetDrawView()->BegCreateObj( rPos, GetOut() );
1842 if ( bRet )
1844 ::FrameNotify( this, FLY_DRAG_START );
1846 return bRet;
1849 bool SwFEShell::BeginCreate( SdrObjKind eSdrObjectKind, SdrInventor eObjInventor,
1850 const Point &rPos )
1852 bool bRet = false;
1854 if ( !Imp()->HasDrawView() )
1855 Imp()->MakeDrawView();
1857 if ( GetPageNumber( rPos ) )
1859 Imp()->GetDrawView()->SetCurrentObj( eSdrObjectKind, eObjInventor );
1860 bRet = Imp()->GetDrawView()->BegCreateObj( rPos, GetOut() );
1862 if ( bRet )
1863 ::FrameNotify( this, FLY_DRAG_START );
1864 return bRet;
1867 void SwFEShell::MoveCreate( const Point &rPos )
1869 OSL_ENSURE( Imp()->HasDrawView(), "MoveCreate without DrawView?" );
1870 if ( GetPageNumber( rPos ) )
1872 ScrollTo( rPos );
1873 Imp()->GetDrawView()->MovCreateObj( rPos );
1874 ::FrameNotify( this );
1878 bool SwFEShell::EndCreate( SdrCreateCmd eSdrCreateCmd )
1880 // To assure undo-object from the DrawEngine is not stored,
1881 // (we create our own undo-object!), temporarily switch-off Undo
1882 OSL_ENSURE( Imp()->HasDrawView(), "EndCreate without DrawView?" );
1883 if( !Imp()->GetDrawView()->IsGroupEntered() )
1885 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
1887 bool bCreate = Imp()->GetDrawView()->EndCreateObj( eSdrCreateCmd );
1888 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
1890 if ( !bCreate )
1892 ::FrameNotify( this, FLY_DRAG_END );
1893 return false;
1896 if ( eSdrCreateCmd == SdrCreateCmd::NextPoint )
1898 ::FrameNotify( this );
1899 return true;
1901 return ImpEndCreate();
1904 bool SwFEShell::ImpEndCreate()
1906 if (Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() == 0)
1907 return false;
1909 SdrObject& rSdrObj = *Imp()->GetDrawView()->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
1911 if( rSdrObj.GetSnapRect().IsEmpty() )
1913 // preferably we forget the object, only gives problems
1914 Imp()->GetDrawView()->DeleteMarked();
1915 Imp()->GetDrawView()->UnmarkAll();
1916 ::FrameNotify( this, FLY_DRAG_END );
1917 return false;
1920 if( rSdrObj.getParentSdrObjectFromSdrObject() )
1922 Point aTmpPos( rSdrObj.GetSnapRect().TopLeft() );
1923 Point aNewAnchor( rSdrObj.getParentSdrObjectFromSdrObject()->GetAnchorPos() );
1924 // OD 2004-04-05 #i26791# - direct object positioning for group members
1925 rSdrObj.NbcSetRelativePos( aTmpPos - aNewAnchor );
1926 rSdrObj.NbcSetAnchorPos( aNewAnchor );
1927 ::FrameNotify( this );
1928 return true;
1931 LockPaint(LockPaintReason::EndSdrCreate);
1932 StartAllAction();
1934 Imp()->GetDrawView()->UnmarkAll();
1936 const tools::Rectangle &rBound = rSdrObj.GetSnapRect();
1937 Point aPt( rBound.TopRight() );
1939 // default for controls character bound, otherwise paragraph bound.
1940 SwFormatAnchor aAnch;
1941 const SwFrame *pAnch = nullptr;
1942 bool bCharBound = false;
1943 if( dynamic_cast<const SdrUnoObj*>( &rSdrObj) != nullptr )
1945 SwPosition aPos( GetDoc()->GetNodes() );
1946 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
1947 Point aPoint( aPt.getX(), aPt.getY() + rBound.GetHeight()/2 );
1948 GetLayout()->GetModelPositionForViewPoint( &aPos, aPoint, &aState );
1950 // characterbinding not allowed in readonly-content
1951 if( !aPos.GetNode().IsProtect() )
1953 std::pair<Point, bool> const tmp(aPoint, true);
1954 pAnch = aPos.GetNode().GetContentNode()->getLayoutFrame(GetLayout(), &aPos, &tmp);
1955 SwRect aTmp;
1956 pAnch->GetCharRect( aTmp, aPos );
1958 // The crsr should not be too far away
1959 bCharBound = true;
1960 constexpr tools::Long constTwips_1cm = o3tl::toTwips(1, o3tl::Length::cm);
1961 tools::Rectangle aRect( aTmp.SVRect() );
1962 // Extend by 1 cm in each direction
1963 aRect.AdjustLeft(-constTwips_1cm);
1964 aRect.AdjustTop(-constTwips_1cm);
1965 aRect.AdjustRight(constTwips_1cm);
1966 aRect.AdjustBottom(constTwips_1cm);
1968 if( !aRect.Overlaps( rBound ) && !::GetHtmlMode( GetDoc()->GetDocShell() ))
1969 bCharBound = false;
1971 // anchor in header/footer also not allowed.
1972 if( bCharBound )
1973 bCharBound = !GetDoc()->IsInHeaderFooter( aPos.GetNode() );
1975 if( bCharBound )
1977 aAnch.SetType( RndStdIds::FLY_AS_CHAR );
1978 aAnch.SetAnchor( &aPos );
1983 if( !bCharBound )
1985 // allow native drawing objects in header/footer.
1986 // Thus, set <bBodyOnly> to <false> for these objects using value
1987 // of <nIdent> - value <0xFFFF> indicates control objects, which aren't
1988 // allowed in header/footer.
1989 //bool bBodyOnly = OBJ_NONE != nIdent;
1990 bool bBodyOnly = SdrInventor::Default != rSdrObj.GetObjInventor();
1991 bool bAtPage = false;
1992 const SwFrame* pPage = nullptr;
1993 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
1994 Point aPoint( aPt );
1995 SwPosition aPos( GetDoc()->GetNodes() );
1996 GetLayout()->GetModelPositionForViewPoint( &aPos, aPoint, &aState );
1998 // do not set in ReadnOnly-content
1999 if (aPos.GetNode().IsProtect())
2001 // then only page bound. Or should we
2002 // search the next not-readonly position?
2003 bAtPage = true;
2006 SwContentNode* pCNode = aPos.GetNode().GetContentNode();
2007 std::pair<Point, bool> const tmp(aPoint, false);
2008 pAnch = pCNode ? pCNode->getLayoutFrame(GetLayout(), nullptr, &tmp) : nullptr;
2009 if (!pAnch)
2011 // Hidden content. Anchor to the page instead
2012 bAtPage = true;
2015 if( !bAtPage )
2017 const SwFlyFrame *pTmp = pAnch->FindFlyFrame();
2018 if( pTmp )
2020 const SwFrame* pTmpFrame = pAnch;
2021 SwRect aBound( rBound );
2022 while( pTmp )
2024 if( pTmp->getFrameArea().Contains( aBound ) )
2026 if( !bBodyOnly || !pTmp->FindFooterOrHeader() )
2027 pPage = pTmpFrame;
2028 break;
2030 pTmp = pTmp->GetAnchorFrame()
2031 ? pTmp->GetAnchorFrame()->FindFlyFrame()
2032 : nullptr;
2033 pTmpFrame = pTmp;
2037 if( !pPage )
2038 pPage = pAnch->FindPageFrame();
2040 // Always via FindAnchor, to assure the frame will be bound
2041 // to the previous. With GetCrsOfst we can also reach the next. THIS IS WRONG.
2042 pAnch = ::FindAnchor( pPage, aPt, bBodyOnly );
2043 if (pAnch->IsTextFrame())
2045 std::pair<SwTextNode const*, sal_Int32> const pos(
2046 static_cast<SwTextFrame const*>(pAnch)->MapViewToModel(TextFrameIndex(0)));
2047 aPos.Assign( *pos.first );
2049 else
2051 aPos.Assign( *static_cast<const SwNoTextFrame*>(pAnch)->GetNode() );
2054 // do not set in ReadnOnly-content
2055 if( aPos.GetNode().IsProtect() )
2056 // then only page bound. Or should we
2057 // search the next not-readonly position?
2058 bAtPage = true;
2059 else
2061 aAnch.SetType( RndStdIds::FLY_AT_PARA );
2062 aAnch.SetAnchor( &aPos );
2066 if( bAtPage )
2068 pPage = pAnch ? pAnch->FindPageFrame() : GetLayout()->GetPageAtPos(aPoint);
2070 aAnch.SetType( RndStdIds::FLY_AT_PAGE );
2071 aAnch.SetPageNum( pPage->GetPhyPageNum() );
2072 pAnch = pPage; // page becomes an anchor
2076 SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE,
2077 RES_SURROUND, RES_ANCHOR> aSet( GetDoc()->GetAttrPool() );
2078 aSet.Put( aAnch );
2080 // OD 2004-03-30 #i26791# - determine relative object position
2081 SwTwips nXOffset;
2082 SwTwips nYOffset = rBound.Top() - pAnch->getFrameArea().Top();
2084 if( pAnch->IsVertical() )
2086 nXOffset = nYOffset;
2087 nYOffset = pAnch->getFrameArea().Left()+pAnch->getFrameArea().Width()-rBound.Right();
2089 else if( pAnch->IsRightToLeft() )
2090 nXOffset = pAnch->getFrameArea().Left()+pAnch->getFrameArea().Width()-rBound.Right();
2091 else
2092 nXOffset = rBound.Left() - pAnch->getFrameArea().Left();
2093 if (pAnch->IsTextFrame())
2095 const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnch);
2096 if (pTmp->IsFollow())
2098 do {
2099 pTmp = pTmp->FindMaster();
2100 OSL_ENSURE(pTmp, "Where's my Master?");
2101 // OD 2004-03-30 #i26791# - correction: add frame area height
2102 // of master frames.
2103 nYOffset += pTmp->IsVertical() ?
2104 pTmp->getFrameArea().Width() : pTmp->getFrameArea().Height();
2105 } while (pTmp->IsFollow());
2108 nYOffset -= pTmp->GetBaseVertOffsetForFly(false);
2112 if (SdrInventor::Default == rSdrObj.GetObjInventor() && rSdrObj.GetObjIdentifier() == SdrObjKind::NewFrame)
2114 // For OBJ_NONE a fly is inserted.
2115 const tools::Long nWidth = rBound.Right() - rBound.Left();
2116 const tools::Long nHeight= rBound.Bottom() - rBound.Top();
2117 aSet.Put( SwFormatFrameSize( SwFrameSize::Minimum, std::max( nWidth, tools::Long(MINFLY) ),
2118 std::max( nHeight, tools::Long(MINFLY) )));
2120 SwFormatHoriOrient aHori( nXOffset, text::HoriOrientation::NONE, text::RelOrientation::FRAME );
2121 SwFormatVertOrient aVert( nYOffset, text::VertOrientation::NONE, text::RelOrientation::FRAME );
2122 aSet.Put( SwFormatSurround( css::text::WrapTextMode_PARALLEL ) );
2123 aSet.Put( aHori );
2124 aSet.Put( aVert );
2126 // Quickly store the square
2127 const SwRect aFlyRect( rBound );
2129 // Throw away generated object, now the fly can nicely
2130 // via the available SS be generated.
2131 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false); // see above
2132 // #i52858# - method name changed
2133 SdrPage *pPg = getIDocumentDrawModelAccess().GetOrCreateDrawModel()->GetPage( 0 );
2134 if( !pPg )
2136 SdrModel* pTmpSdrModel = getIDocumentDrawModelAccess().GetDrawModel();
2137 auto pNewPage = pTmpSdrModel->AllocPage( false );
2138 pTmpSdrModel->InsertPage( pNewPage.get() );
2139 pPg = pNewPage.get();
2141 pPg->RecalcObjOrdNums();
2142 pPg->RemoveObject( rSdrObj.GetOrdNumDirect() );
2143 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
2145 SwFlyFrame* pFlyFrame;
2146 if( NewFlyFrame( aSet, true ) &&
2147 ::GetHtmlMode( GetDoc()->GetDocShell() ) &&
2148 nullptr != ( pFlyFrame = GetSelectedFlyFrame() ))
2150 SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT> aHtmlSet( GetDoc()->GetAttrPool() );
2151 // horizontal orientation:
2152 const bool bLeftFrame = aFlyRect.Left() <
2153 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Left(),
2154 bLeftPrt = aFlyRect.Left() + aFlyRect.Width() <
2155 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width()/2;
2156 if( bLeftFrame || bLeftPrt )
2158 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
2159 aHori.SetRelationOrient( bLeftFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
2161 else
2163 const bool bRightFrame = aFlyRect.Left() >
2164 pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width();
2165 aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
2166 aHori.SetRelationOrient( bRightFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
2168 aHtmlSet.Put( aHori );
2169 aVert.SetVertOrient( text::VertOrientation::TOP );
2170 aVert.SetRelationOrient( text::RelOrientation::PRINT_AREA );
2171 aHtmlSet.Put( aVert );
2173 GetDoc()->SetAttr( aHtmlSet, *pFlyFrame->GetFormat() );
2176 else
2178 if (rSdrObj.GetName().isEmpty())
2180 bool bRestore = GetDoc()->GetIDocumentUndoRedo().DoesDrawUndo();
2181 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
2182 rSdrObj.MakeNameUnique();
2183 GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(bRestore);
2186 aSet.Put( aAnch );
2187 aSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) );
2188 // OD 2004-03-30 #i26791# - set horizontal position
2189 SwFormatHoriOrient aHori( nXOffset, text::HoriOrientation::NONE, text::RelOrientation::FRAME );
2190 aSet.Put( aHori );
2191 // OD 2004-03-30 #i26791# - set vertical position
2192 if( pAnch->IsTextFrame() && static_cast<const SwTextFrame*>(pAnch)->IsFollow() )
2194 const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnch);
2195 do {
2196 pTmp = pTmp->FindMaster();
2197 assert(pTmp && "Where's my Master?");
2198 nYOffset += pTmp->IsVertical() ?
2199 pTmp->getFramePrintArea().Width() : pTmp->getFramePrintArea().Height();
2200 } while ( pTmp->IsFollow() );
2202 SwFormatVertOrient aVert( nYOffset, text::VertOrientation::NONE, text::RelOrientation::FRAME );
2203 aSet.Put( aVert );
2204 SwDrawFrameFormat* pFormat = static_cast<SwDrawFrameFormat*>(getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::DRAW_OBJECT, &aSet ));
2205 // #i36010# - set layout direction of the position
2206 pFormat->SetPositionLayoutDir(
2207 text::PositionLayoutDir::PositionInLayoutDirOfAnchor );
2208 // #i44344#, #i44681# - positioning attributes already set
2209 pFormat->PosAttrSet();
2210 pFormat->SetFormatName(rSdrObj.GetName());
2212 SwDrawContact *pContact = new SwDrawContact( pFormat, &rSdrObj );
2213 // #i35635#
2214 pContact->MoveObjToVisibleLayer( &rSdrObj );
2215 if( bCharBound )
2217 OSL_ENSURE( aAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR, "wrong AnchorType" );
2218 SwTextNode *pNd = aAnch.GetAnchorNode()->GetTextNode();
2219 SwFormatFlyCnt aFormat( pFormat );
2220 pNd->InsertItem(aFormat,
2221 aAnch.GetAnchorContentOffset(), 0 );
2222 SwFormatVertOrient aVertical( pFormat->GetVertOrient() );
2223 aVertical.SetVertOrient( text::VertOrientation::LINE_CENTER );
2224 pFormat->SetFormatAttr( aVertical );
2226 if( pAnch->IsTextFrame() && static_cast<const SwTextFrame*>(pAnch)->IsFollow() )
2228 const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnch);
2229 do {
2230 pTmp = pTmp->FindMaster();
2231 OSL_ENSURE( pTmp, "Where's my Master?" );
2232 } while( pTmp->IsFollow() );
2233 pAnch = pTmp;
2236 pContact->ConnectToLayout();
2238 // mark object at frame the object is inserted at.
2240 SdrObject* pMarkObj = pContact->GetDrawObjectByAnchorFrame( *pAnch );
2241 if ( pMarkObj )
2243 Imp()->GetDrawView()->MarkObj( pMarkObj, Imp()->GetPageView() );
2245 else
2247 Imp()->GetDrawView()->MarkObj( &rSdrObj, Imp()->GetPageView() );
2252 GetDoc()->getIDocumentState().SetModified();
2254 KillPams();
2255 EndAllActionAndCall();
2256 UnlockPaint();
2257 return true;
2260 void SwFEShell::BreakCreate()
2262 OSL_ENSURE( Imp()->HasDrawView(), "BreakCreate without DrawView?" );
2263 Imp()->GetDrawView()->BrkCreateObj();
2264 ::FrameNotify( this, FLY_DRAG_END );
2267 bool SwFEShell::IsDrawCreate() const
2269 return Imp()->HasDrawView() && Imp()->GetDrawView()->IsCreateObj();
2272 bool SwFEShell::BeginMark( const Point &rPos )
2274 if ( !Imp()->HasDrawView() )
2275 Imp()->MakeDrawView();
2277 if ( GetPageNumber( rPos ) )
2279 SwDrawView* pDView = Imp()->GetDrawView();
2281 if (pDView->HasMarkablePoints())
2282 return pDView->BegMarkPoints( rPos );
2283 else
2285 pDView->BegMarkObj( rPos );
2286 return true;
2289 else
2290 return false;
2293 void SwFEShell::MoveMark( const Point &rPos )
2295 OSL_ENSURE( Imp()->HasDrawView(), "MoveMark without DrawView?" );
2297 if ( GetPageNumber( rPos ) )
2299 ScrollTo( rPos );
2300 SwDrawView* pDView = Imp()->GetDrawView();
2302 if (pDView->IsInsObjPoint())
2303 pDView->MovInsObjPoint( rPos );
2304 else if (pDView->IsMarkPoints())
2305 pDView->MovMarkPoints( rPos );
2306 else
2307 pDView->MovAction( rPos );
2311 bool SwFEShell::EndMark()
2313 bool bRet = false;
2314 OSL_ENSURE( Imp()->HasDrawView(), "EndMark without DrawView?" );
2316 if (Imp()->GetDrawView()->IsMarkObj())
2318 bRet = Imp()->GetDrawView()->EndMarkObj();
2320 if ( bRet )
2322 bool bShowHdl = false;
2323 SwDrawView* pDView = Imp()->GetDrawView();
2324 // frames are not selected this way, except when
2325 // it is only one frame
2326 SdrMarkList &rMrkList = const_cast<SdrMarkList&>(pDView->GetMarkedObjectList());
2327 SwFlyFrame* pOldSelFly = ::GetFlyFromMarked( &rMrkList, this );
2329 if ( rMrkList.GetMarkCount() > 1 )
2330 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2332 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2333 if( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) != nullptr )
2335 if ( !bShowHdl )
2337 bShowHdl = true;
2339 rMrkList.DeleteMark( i );
2340 --i; // no exceptions
2344 if( bShowHdl )
2346 pDView->MarkListHasChanged();
2347 pDView->AdjustMarkHdl();
2350 if ( rMrkList.GetMarkCount() )
2351 ::lcl_GrabCursor(this, pOldSelFly);
2352 else
2353 bRet = false;
2355 if ( bRet )
2356 ::FrameNotify( this, FLY_DRAG_START );
2358 else
2360 if (Imp()->GetDrawView()->IsMarkPoints())
2361 bRet = Imp()->GetDrawView()->EndMarkPoints();
2364 SetChainMarker();
2365 return bRet;
2368 RndStdIds SwFEShell::GetAnchorId() const
2370 RndStdIds nRet = RndStdIds(SHRT_MAX);
2371 if ( Imp()->HasDrawView() )
2373 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2374 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2376 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2377 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) != nullptr )
2379 nRet = RndStdIds::UNKNOWN;
2380 break;
2382 SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
2383 RndStdIds nId = pContact->GetFormat()->GetAnchor().GetAnchorId();
2384 if ( nRet == RndStdIds(SHRT_MAX) )
2385 nRet = nId;
2386 else if ( nRet != nId )
2388 nRet = RndStdIds::UNKNOWN;
2389 break;
2393 if ( nRet == RndStdIds(SHRT_MAX) )
2394 nRet = RndStdIds::UNKNOWN;
2395 return nRet;
2398 void SwFEShell::ChgAnchor( RndStdIds eAnchorId, bool bSameOnly, bool bPosCorr )
2400 OSL_ENSURE( Imp()->HasDrawView(), "ChgAnchor without DrawView?" );
2401 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2402 if( rMrkList.GetMarkCount() &&
2403 !rMrkList.GetMark( 0 )->GetMarkedSdrObj()->getParentSdrObjectFromSdrObject() )
2405 StartAllAction();
2407 if( GetDoc()->ChgAnchor( rMrkList, eAnchorId, bSameOnly, bPosCorr ))
2408 Imp()->GetDrawView()->UnmarkAll();
2410 EndAllAction();
2412 ::FrameNotify( this );
2416 void SwFEShell::DelSelectedObj()
2418 OSL_ENSURE( Imp()->HasDrawView(), "DelSelectedObj(), no DrawView available" );
2419 if ( Imp()->HasDrawView() )
2421 StartAllAction();
2422 Imp()->GetDrawView()->DeleteMarked();
2423 EndAllAction();
2424 ::FrameNotify( this, FLY_DRAG_END );
2428 // For the statusline to request the current conditions
2429 Size SwFEShell::GetObjSize() const
2431 tools::Rectangle aRect;
2432 if ( Imp()->HasDrawView() )
2434 if ( Imp()->GetDrawView()->IsAction() )
2435 Imp()->GetDrawView()->TakeActionRect( aRect );
2436 else
2437 aRect = Imp()->GetDrawView()->GetAllMarkedRect();
2439 return aRect.GetSize();
2442 Point SwFEShell::GetAnchorObjDiff() const
2444 const SdrView *pView = Imp()->GetDrawView();
2445 OSL_ENSURE( pView, "GetAnchorObjDiff without DrawView?" );
2447 tools::Rectangle aRect;
2448 if ( Imp()->GetDrawView()->IsAction() )
2449 Imp()->GetDrawView()->TakeActionRect( aRect );
2450 else
2451 aRect = Imp()->GetDrawView()->GetAllMarkedRect();
2453 Point aRet( aRect.TopLeft() );
2455 if ( IsFrameSelected() )
2457 SwFlyFrame *pFly = GetSelectedFlyFrame();
2458 aRet -= pFly->GetAnchorFrame()->getFrameArea().Pos();
2460 else
2462 const SdrObject *pObj = pView->GetMarkedObjectList().GetMarkCount() == 1 ?
2463 pView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj() : nullptr;
2464 if ( pObj )
2465 aRet -= pObj->GetAnchorPos();
2468 return aRet;
2471 Point SwFEShell::GetObjAbsPos() const
2473 OSL_ENSURE( Imp()->GetDrawView(), "GetObjAbsPos() without DrawView?" );
2474 return Imp()->GetDrawView()->GetDragStat().GetActionRect().TopLeft();
2477 bool SwFEShell::IsGroupSelected(bool bAllowDiagams)
2479 if ( IsObjSelected() )
2481 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2482 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2484 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2485 // consider 'virtual' drawing objects.
2486 // Thus, use corresponding method instead of checking type.
2487 if ( pObj->IsGroupObject() &&
2488 // --> #i38505# No ungroup allowed for 3d objects
2489 !pObj->Is3DObj() &&
2490 RndStdIds::FLY_AS_CHAR != static_cast<SwDrawContact*>(GetUserCall(pObj))->
2491 GetFormat()->GetAnchor().GetAnchorId() )
2493 if(!bAllowDiagams)
2495 // Don't allow enter Diagrams
2496 if(pObj->isDiagram())
2498 return false;
2502 return true;
2506 return false;
2509 namespace
2511 bool HasSuitableGroupingAnchor(const SdrObject* pObj)
2513 bool bSuitable = true;
2514 SwFrameFormat* pFrameFormat(::FindFrameFormat(const_cast<SdrObject*>(pObj)));
2515 if (!pFrameFormat)
2517 OSL_FAIL( "<HasSuitableGroupingAnchor> - missing frame format" );
2518 bSuitable = false;
2520 else if (RndStdIds::FLY_AS_CHAR == pFrameFormat->GetAnchor().GetAnchorId())
2522 bSuitable = false;
2524 return bSuitable;
2528 // Change return type.
2529 // Adjustments for drawing objects in header/footer:
2530 // allow group, only if all selected objects are in the same header/footer
2531 // or not in header/footer.
2532 bool SwFEShell::IsGroupAllowed() const
2534 bool bIsGroupAllowed = false;
2535 if ( IsObjSelected() > 1 )
2537 bIsGroupAllowed = true;
2538 const SdrObject* pUpGroup = nullptr;
2539 const SwFrame* pHeaderFooterFrame = nullptr;
2540 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2541 for ( size_t i = 0; bIsGroupAllowed && i < rMrkList.GetMarkCount(); ++i )
2543 const SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2544 if ( i )
2545 bIsGroupAllowed = pObj->getParentSdrObjectFromSdrObject() == pUpGroup;
2546 else
2547 pUpGroup = pObj->getParentSdrObjectFromSdrObject();
2549 if ( bIsGroupAllowed )
2550 bIsGroupAllowed = HasSuitableGroupingAnchor(pObj);
2552 // check, if all selected objects are in the
2553 // same header/footer or not in header/footer.
2554 if ( bIsGroupAllowed )
2556 const SwFrame* pAnchorFrame = nullptr;
2557 if ( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>( pObj) )
2559 const SwFlyFrame* pFlyFrame = pVirtFlyDrawObj->GetFlyFrame();
2560 if ( pFlyFrame )
2562 pAnchorFrame = pFlyFrame->GetAnchorFrame();
2565 else
2567 SwDrawContact* pDrawContact = static_cast<SwDrawContact*>(GetUserCall( pObj ));
2568 if ( pDrawContact )
2570 pAnchorFrame = pDrawContact->GetAnchorFrame( pObj );
2573 if ( pAnchorFrame )
2575 if ( i )
2577 bIsGroupAllowed =
2578 ( pAnchorFrame->FindFooterOrHeader() == pHeaderFooterFrame );
2580 else
2582 pHeaderFooterFrame = pAnchorFrame->FindFooterOrHeader();
2589 return bIsGroupAllowed;
2592 bool SwFEShell::IsUnGroupAllowed() const
2594 bool bIsUnGroupAllowed = false;
2596 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2597 for (size_t i = 0; i < rMrkList.GetMarkCount(); ++i)
2599 const SdrObject* pObj = rMrkList.GetMark(i)->GetMarkedSdrObj();
2600 bIsUnGroupAllowed = HasSuitableGroupingAnchor(pObj);
2601 if (!bIsUnGroupAllowed)
2602 break;
2605 return bIsUnGroupAllowed;
2608 // The group gets the anchor and the contactobject of the first in the selection
2609 void SwFEShell::GroupSelection()
2611 if ( IsGroupAllowed() )
2613 StartAllAction();
2614 StartUndo( SwUndoId::START );
2616 GetDoc()->GroupSelection( *Imp()->GetDrawView() );
2618 EndUndo( SwUndoId::END );
2619 EndAllAction();
2623 // The individual objects get a copy of the anchor and the contactobject of the group
2624 void SwFEShell::UnGroupSelection()
2626 if ( IsGroupSelected(true) )
2628 StartAllAction();
2629 StartUndo( SwUndoId::START );
2631 GetDoc()->UnGroupSelection( *Imp()->GetDrawView() );
2633 EndUndo( SwUndoId::END );
2634 EndAllAction();
2638 void SwFEShell::MirrorSelection( bool bHorizontal )
2640 SdrView *pView = Imp()->GetDrawView();
2641 if ( IsObjSelected() && pView->IsMirrorAllowed() )
2643 if ( bHorizontal )
2644 pView->MirrorAllMarkedHorizontal();
2645 else
2646 pView->MirrorAllMarkedVertical();
2650 // jump to named frame (Graphic/OLE)
2652 bool SwFEShell::GotoFly( const OUString& rName, FlyCntType eType, bool bSelFrame )
2654 bool bRet = false;
2655 static SwNodeType const aChkArr[ 4 ] = {
2656 /* FLYCNTTYPE_ALL */ SwNodeType::NONE,
2657 /* FLYCNTTYPE_FRM */ SwNodeType::Text,
2658 /* FLYCNTTYPE_GRF */ SwNodeType::Grf,
2659 /* FLYCNTTYPE_OLE */ SwNodeType::Ole
2662 const SwFlyFrameFormat* pFlyFormat = mxDoc->FindFlyByName( rName, aChkArr[ eType]);
2663 if( pFlyFormat )
2665 CurrShell aCurr( this );
2667 SwFlyFrame* pFrame = SwIterator<SwFlyFrame,SwFormat>( *pFlyFormat ).First();
2668 if( pFrame )
2670 if( bSelFrame )
2672 // first make visible, to get a11y events in proper order
2673 if (!ActionPend())
2674 MakeVisible( pFrame->getFrameArea() );
2675 SelectObj( pFrame->getFrameArea().Pos(), 0, pFrame->GetVirtDrawObj() );
2677 else
2679 SwContentFrame *pCFrame = pFrame->ContainsContent();
2680 if ( pCFrame )
2682 ClearMark();
2683 SwPaM* pCursor = GetCursor();
2685 if (pCFrame->IsTextFrame())
2687 *pCursor->GetPoint() = static_cast<SwTextFrame *>(pCFrame)
2688 ->MapViewToModelPos(TextFrameIndex(0));
2690 else
2692 assert(pCFrame->IsNoTextFrame());
2693 SwContentNode *const pCNode = static_cast<SwNoTextFrame *>(pCFrame)->GetNode();
2695 pCursor->GetPoint()->Assign(*pCNode);
2698 SwRect& rChrRect = const_cast<SwRect&>(GetCharRect());
2699 rChrRect = pFrame->getFramePrintArea();
2700 rChrRect.Pos() += pFrame->getFrameArea().Pos();
2701 GetCursorDocPos() = rChrRect.Pos();
2704 bRet = true;
2707 return bRet;
2710 size_t SwFEShell::GetFlyCount( FlyCntType eType, bool bIgnoreTextBoxes ) const
2712 return GetDoc()->GetFlyCount(eType, bIgnoreTextBoxes);
2715 const SwFrameFormat* SwFEShell::GetFlyNum(size_t nIdx, FlyCntType eType, bool bIgnoreTextBoxes ) const
2717 return GetDoc()->GetFlyNum(nIdx, eType, bIgnoreTextBoxes);
2720 std::vector<SwFrameFormat const*> SwFEShell::GetFlyFrameFormats(
2721 FlyCntType const eType, bool const bIgnoreTextBoxes)
2723 return GetDoc()->GetFlyFrameFormats(eType, bIgnoreTextBoxes);
2726 // show the current selected object
2727 void SwFEShell::MakeSelVisible()
2729 if ( Imp()->HasDrawView() &&
2730 Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() )
2732 GetCurrFrame(); // just to trigger formatting in case the selected object is not formatted.
2733 MakeVisible( SwRect(Imp()->GetDrawView()->GetAllMarkedRect()) );
2735 else
2736 SwCursorShell::MakeSelVisible();
2739 // how is the selected object protected?
2740 FlyProtectFlags SwFEShell::IsSelObjProtected( FlyProtectFlags eType ) const
2742 FlyProtectFlags nChk = FlyProtectFlags::NONE;
2743 const bool bParent(eType & FlyProtectFlags::Parent);
2744 if( Imp()->HasDrawView() )
2746 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2747 for( size_t i = rMrkList.GetMarkCount(); i; )
2749 SdrObject *pObj = rMrkList.GetMark( --i )->GetMarkedSdrObj();
2750 if (!pObj)
2752 continue;
2755 if( !bParent )
2757 nChk |= ( pObj->IsMoveProtect() ? FlyProtectFlags::Pos : FlyProtectFlags::NONE ) |
2758 ( pObj->IsResizeProtect()? FlyProtectFlags::Size : FlyProtectFlags::NONE );
2760 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
2762 SwFlyFrame *pFly = pVirtO->GetFlyFrame();
2763 if ( (FlyProtectFlags::Content & eType) && pFly->GetFormat()->GetProtect().IsContentProtected() )
2764 nChk |= FlyProtectFlags::Content;
2766 if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
2768 SwOLENode *pNd = static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetOLENode();
2769 uno::Reference < embed::XEmbeddedObject > xObj( pNd ? pNd->GetOLEObj().GetOleRef() : nullptr );
2770 if ( xObj.is() )
2772 // TODO/LATER: use correct aspect
2773 const bool bNeverResize = (embed::EmbedMisc::EMBED_NEVERRESIZE & xObj->getStatus( embed::Aspects::MSOLE_CONTENT ));
2774 if ( ( (FlyProtectFlags::Content & eType) || (FlyProtectFlags::Size & eType) ) && bNeverResize )
2776 nChk |= FlyProtectFlags::Size;
2777 nChk |= FlyProtectFlags::Fixed;
2780 // set FlyProtectFlags::Pos if it is a Math object anchored 'as char' and baseline alignment is activated
2781 const bool bProtectMathPos = SotExchange::IsMath( xObj->getClassID() )
2782 && RndStdIds::FLY_AS_CHAR == pFly->GetFormat()->GetAnchor().GetAnchorId()
2783 && mxDoc->GetDocumentSettingManager().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT );
2784 if ((FlyProtectFlags::Pos & eType) && bProtectMathPos)
2785 nChk |= FlyProtectFlags::Pos;
2789 nChk &= eType;
2790 if( nChk == eType )
2791 return eType;
2793 const SwFrame* pAnch;
2794 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
2795 pAnch = pVirtO->GetFlyFrame()->GetAnchorFrame();
2796 else
2798 SwDrawContact* pTmp = static_cast<SwDrawContact*>(GetUserCall(pObj));
2799 pAnch = pTmp ? pTmp->GetAnchorFrame( pObj ) : nullptr;
2801 if( pAnch && pAnch->IsProtected() )
2802 return eType;
2805 return nChk;
2808 bool SwFEShell::GetObjAttr( SfxItemSet &rSet ) const
2810 if ( !IsObjSelected() )
2811 return false;
2813 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2814 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2816 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2817 SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
2818 // --> make code robust
2819 OSL_ENSURE( pContact, "<SwFEShell::GetObjAttr(..)> - missing <pContact>." );
2820 if ( pContact )
2822 if ( i )
2823 rSet.MergeValues( pContact->GetFormat()->GetAttrSet() );
2824 else
2825 rSet.Put( pContact->GetFormat()->GetAttrSet() );
2828 return true;
2831 void SwFEShell::SetObjAttr( const SfxItemSet& rSet )
2833 CurrShell aCurr( this );
2835 if ( !rSet.Count() )
2837 OSL_ENSURE( false, "SetObjAttr, empty set." );
2838 return;
2841 StartAllAction();
2842 StartUndo( SwUndoId::INSATTR );
2844 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2845 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2847 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2848 SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
2849 GetDoc()->SetAttr( rSet, *pContact->GetFormat() );
2852 EndUndo( SwUndoId::INSATTR );
2853 EndAllActionAndCall();
2854 GetDoc()->getIDocumentState().SetModified();
2857 bool SwFEShell::IsAlignPossible() const
2859 return Imp()->GetDrawView()->IsAlignPossible();
2862 void SwFEShell::CheckUnboundObjects()
2864 CurrShell aCurr( this );
2866 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2867 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2869 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2870 if ( !GetUserCall(pObj) )
2872 const tools::Rectangle &rBound = pObj->GetSnapRect();
2873 const Point aPt( rBound.TopLeft() );
2874 const SwFrame *pPage = GetLayout()->Lower();
2875 const SwFrame *pLast = pPage;
2876 while ( pPage && !pPage->getFrameArea().Contains( aPt ) )
2878 if ( aPt.Y() > pPage->getFrameArea().Bottom() )
2879 pLast = pPage;
2880 pPage = pPage->GetNext();
2882 if ( !pPage )
2883 pPage = pLast;
2884 OSL_ENSURE( pPage, "Page not found." );
2886 SwFormatAnchor aAnch;
2888 const SwContentFrame *const pAnch = ::FindAnchor(pPage, aPt, true);
2889 SwPosition aPos( pAnch->IsTextFrame()
2890 ? *static_cast<SwTextFrame const*>(pAnch)->GetTextNodeForParaProps()
2891 : *static_cast<SwNoTextFrame const*>(pAnch)->GetNode() );
2892 aAnch.SetType( RndStdIds::FLY_AT_PARA );
2893 aAnch.SetAnchor( &aPos );
2894 const_cast<SwRect&>(GetCharRect()).Pos() = aPt;
2897 // First the action here, to assure GetCharRect delivers current values.
2898 StartAllAction();
2900 SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE,
2901 RES_SURROUND, RES_ANCHOR> aSet( GetAttrPool() );
2902 aSet.Put( aAnch );
2903 aSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) );
2904 SwFrameFormat* pFormat = getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::DRAW_OBJECT, &aSet );
2906 SwDrawContact *pContact = new SwDrawContact(
2907 static_cast<SwDrawFrameFormat*>(pFormat), pObj );
2909 // #i35635#
2910 pContact->MoveObjToVisibleLayer( pObj );
2911 pContact->ConnectToLayout();
2913 EndAllAction();
2918 void SwFEShell::SetCalcFieldValueHdl(Outliner* pOutliner)
2920 GetDoc()->SetCalcFieldValueHdl(pOutliner);
2923 SwChainRet SwFEShell::Chainable( SwRect &rRect, const SwFrameFormat &rSource,
2924 const Point &rPt ) const
2926 rRect.Clear();
2928 // The source is not allowed to have a follow.
2929 const SwFormatChain &rChain = rSource.GetChain();
2930 if ( rChain.GetNext() )
2931 return SwChainRet::SOURCE_CHAINED;
2933 SwChainRet nRet = SwChainRet::NOT_FOUND;
2934 if( Imp()->HasDrawView() )
2936 SdrPageView* pPView;
2937 SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
2938 const auto nOld = pDView->GetHitTolerancePixel();
2939 pDView->SetHitTolerancePixel( 0 );
2940 SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
2941 SwVirtFlyDrawObj* pDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
2942 if (pDrawObj)
2944 SwFlyFrame *pFly = pDrawObj->GetFlyFrame();
2945 rRect = pFly->getFrameArea();
2947 // Target and source should not be equal and the list
2948 // should not be cyclic
2949 SwFrameFormat *pFormat = pFly->GetFormat();
2950 nRet = GetDoc()->Chainable(rSource, *pFormat);
2952 pDView->SetHitTolerancePixel( nOld );
2954 return nRet;
2957 void SwFEShell::Chain( SwFrameFormat &rSource, const SwFrameFormat &rDest )
2959 GetDoc()->Chain(rSource, rDest);
2962 SwChainRet SwFEShell::Chain( SwFrameFormat &rSource, const Point &rPt )
2964 SwRect aDummy;
2965 SwChainRet nErr = Chainable( aDummy, rSource, rPt );
2966 if ( nErr == SwChainRet::OK )
2968 StartAllAction();
2969 SdrPageView* pPView;
2970 SwDrawView *pDView = Imp()->GetDrawView();
2971 const auto nOld = pDView->GetHitTolerancePixel();
2972 pDView->SetHitTolerancePixel( 0 );
2973 SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
2974 pDView->SetHitTolerancePixel( nOld );
2975 SwFlyFrame *pFly = static_cast<SwVirtFlyDrawObj*>(pObj)->GetFlyFrame();
2977 SwFlyFrameFormat *pFormat = pFly->GetFormat();
2978 GetDoc()->Chain(rSource, *pFormat);
2979 EndAllAction();
2980 SetChainMarker();
2982 return nErr;
2985 void SwFEShell::Unchain( SwFrameFormat &rFormat )
2987 StartAllAction();
2988 GetDoc()->Unchain(rFormat);
2989 EndAllAction();
2992 void SwFEShell::HideChainMarker()
2994 m_pChainFrom.reset();
2995 m_pChainTo.reset();
2998 void SwFEShell::SetChainMarker()
3000 bool bDelFrom = true,
3001 bDelTo = true;
3002 if ( IsFrameSelected() )
3004 SwFlyFrame *pFly = GetSelectedFlyFrame();
3006 if ( pFly->GetPrevLink() )
3008 bDelFrom = false;
3009 const SwFrame *pPre = pFly->GetPrevLink();
3011 Point aStart( pPre->getFrameArea().Right(), pPre->getFrameArea().Bottom());
3012 Point aEnd(pFly->getFrameArea().Pos());
3014 if (!m_pChainFrom)
3016 m_pChainFrom.reset(
3017 new SdrDropMarkerOverlay( *GetDrawView(), aStart, aEnd ));
3020 if ( pFly->GetNextLink() )
3022 bDelTo = false;
3023 const SwFlyFrame *pNxt = pFly->GetNextLink();
3025 Point aStart( pFly->getFrameArea().Right(), pFly->getFrameArea().Bottom());
3026 Point aEnd(pNxt->getFrameArea().Pos());
3028 if (!m_pChainTo)
3030 m_pChainTo.reset(
3031 new SdrDropMarkerOverlay( *GetDrawView(), aStart, aEnd ));
3036 if ( bDelFrom )
3038 m_pChainFrom.reset();
3041 if ( bDelTo )
3043 m_pChainTo.reset();
3047 tools::Long SwFEShell::GetSectionWidth( SwFormat const & rFormat ) const
3049 SwFrame *pFrame = GetCurrFrame();
3050 // Is the cursor at this moment in a SectionFrame?
3051 if( pFrame && pFrame->IsInSct() )
3053 SwSectionFrame* pSect = pFrame->FindSctFrame();
3056 // Is it the right one?
3057 if( pSect->KnowsFormat( rFormat ) )
3058 return pSect->getFrameArea().Width();
3059 // for nested areas
3060 pSect = pSect->GetUpper()->FindSctFrame();
3062 while( pSect );
3064 SwIterator<SwSectionFrame,SwFormat> aIter( rFormat );
3065 for ( SwSectionFrame* pSct = aIter.First(); pSct; pSct = aIter.Next() )
3067 if( !pSct->IsFollow() )
3069 return pSct->getFrameArea().Width();
3072 return 0;
3075 void SwFEShell::CreateDefaultShape( SdrObjKind eSdrObjectKind, const tools::Rectangle& rRect,
3076 sal_uInt16 nSlotId)
3078 SdrView* pDrawView = GetDrawView();
3079 SdrModel& rDrawModel = pDrawView->GetModel();
3080 rtl::Reference<SdrObject> pObj = SdrObjFactory::MakeNewObject(
3081 rDrawModel,
3082 SdrInventor::Default,
3083 eSdrObjectKind);
3085 if(pObj)
3087 tools::Rectangle aRect(rRect);
3088 if(SdrObjKind::CircleArc == eSdrObjectKind || SdrObjKind::CircleCut == eSdrObjectKind)
3090 // force quadratic
3091 if(aRect.GetWidth() > aRect.GetHeight())
3093 aRect = tools::Rectangle(
3094 Point(aRect.Left() + ((aRect.GetWidth() - aRect.GetHeight()) / 2), aRect.Top()),
3095 Size(aRect.GetHeight(), aRect.GetHeight()));
3097 else
3099 aRect = tools::Rectangle(
3100 Point(aRect.Left(), aRect.Top() + ((aRect.GetHeight() - aRect.GetWidth()) / 2)),
3101 Size(aRect.GetWidth(), aRect.GetWidth()));
3104 pObj->SetLogicRect(aRect);
3106 Point aStart = aRect.TopLeft();
3107 Point aEnd = aRect.BottomRight();
3109 if(dynamic_cast<const SdrCircObj*>( pObj.get()) != nullptr)
3111 SfxItemSet aAttr(rDrawModel.GetItemPool());
3112 aAttr.Put(makeSdrCircStartAngleItem(9000_deg100));
3113 aAttr.Put(makeSdrCircEndAngleItem(0_deg100));
3114 pObj->SetMergedItemSet(aAttr);
3116 else if(auto pPathObj = dynamic_cast<SdrPathObj*>( pObj.get()))
3118 basegfx::B2DPolyPolygon aPoly;
3120 switch(eSdrObjectKind)
3122 case SdrObjKind::PathLine:
3123 case SdrObjKind::PathFill:
3125 basegfx::B2DPolygon aInnerPoly;
3127 aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Bottom()));
3129 const basegfx::B2DPoint aCenterBottom(aRect.Center().getX(), aRect.Bottom());
3130 aInnerPoly.appendBezierSegment(
3131 aCenterBottom,
3132 aCenterBottom,
3133 basegfx::B2DPoint(aRect.Center().getX(), aRect.Center().getY()));
3135 const basegfx::B2DPoint aCenterTop(aRect.Center().getX(), aRect.Top());
3136 aInnerPoly.appendBezierSegment(
3137 aCenterTop,
3138 aCenterTop,
3139 basegfx::B2DPoint(aRect.Right(), aRect.Top()));
3141 aInnerPoly.setClosed(true);
3142 aPoly.append(aInnerPoly);
3144 break;
3145 case SdrObjKind::FreehandLine:
3146 case SdrObjKind::FreehandFill:
3148 basegfx::B2DPolygon aInnerPoly;
3150 aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Bottom()));
3152 aInnerPoly.appendBezierSegment(
3153 basegfx::B2DPoint(aRect.Left(), aRect.Top()),
3154 basegfx::B2DPoint(aRect.Center().getX(), aRect.Top()),
3155 basegfx::B2DPoint(aRect.Center().getX(), aRect.Center().getY()));
3157 aInnerPoly.appendBezierSegment(
3158 basegfx::B2DPoint(aRect.Center().getX(), aRect.Bottom()),
3159 basegfx::B2DPoint(aRect.Right(), aRect.Bottom()),
3160 basegfx::B2DPoint(aRect.Right(), aRect.Top()));
3162 aInnerPoly.append(basegfx::B2DPoint(aRect.Right(), aRect.Bottom()));
3163 aInnerPoly.setClosed(true);
3164 aPoly.append(aInnerPoly);
3166 break;
3167 case SdrObjKind::Polygon:
3168 case SdrObjKind::PolyLine:
3170 basegfx::B2DPolygon aInnerPoly;
3171 sal_Int32 nWdt(aRect.GetWidth());
3172 sal_Int32 nHgt(aRect.GetHeight());
3174 aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Bottom()));
3175 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 30) / 100, aRect.Top() + (nHgt * 70) / 100));
3176 aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Top() + (nHgt * 15) / 100));
3177 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 65) / 100, aRect.Top()));
3178 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + nWdt, aRect.Top() + (nHgt * 30) / 100));
3179 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 80) / 100, aRect.Top() + (nHgt * 50) / 100));
3180 aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 80) / 100, aRect.Top() + (nHgt * 75) / 100));
3181 aInnerPoly.append(basegfx::B2DPoint(aRect.Bottom(), aRect.Right()));
3183 if(SdrObjKind::PolyLine == eSdrObjectKind)
3185 aInnerPoly.append(basegfx::B2DPoint(aRect.Center().getX(), aRect.Bottom()));
3187 else
3189 aInnerPoly.setClosed(true);
3192 aPoly.append(aInnerPoly);
3194 break;
3195 case SdrObjKind::Line :
3197 sal_Int32 nYMiddle((aRect.Top() + aRect.Bottom()) / 2);
3198 basegfx::B2DPolygon aTempPoly;
3199 aTempPoly.append(basegfx::B2DPoint(aRect.TopLeft().getX(), nYMiddle));
3200 aTempPoly.append(basegfx::B2DPoint(aRect.BottomRight().getX(), nYMiddle));
3201 aPoly.append(aTempPoly);
3203 SfxItemSet aAttr(pObj->getSdrModelFromSdrObject().GetItemPool());
3204 SetLineEnds(aAttr, *pObj, nSlotId);
3205 pObj->SetMergedItemSet(aAttr);
3207 break;
3208 default:
3209 break;
3212 pPathObj->SetPathPoly(aPoly);
3214 else if(auto pMeasureObj = dynamic_cast<SdrMeasureObj*>( pObj.get()))
3216 sal_Int32 nYMiddle((aRect.Top() + aRect.Bottom()) / 2);
3217 pMeasureObj->SetPoint(Point(aStart.X(), nYMiddle), 0);
3218 pMeasureObj->SetPoint(Point(aEnd.X(), nYMiddle), 1);
3220 SfxItemSet aAttr(pObj->getSdrModelFromSdrObject().GetItemPool());
3221 SetLineEnds(aAttr, *pObj, nSlotId);
3222 pObj->SetMergedItemSet(aAttr);
3224 else if(auto pCaptionObj = dynamic_cast<SdrCaptionObj*>( pObj.get()))
3226 bool bVerticalText = ( SID_DRAW_TEXT_VERTICAL == nSlotId ||
3227 SID_DRAW_CAPTION_VERTICAL == nSlotId );
3228 pCaptionObj->SetVerticalWriting(bVerticalText);
3229 if(bVerticalText)
3231 SfxItemSet aSet(pObj->GetMergedItemSet());
3232 aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER));
3233 aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
3234 pObj->SetMergedItemSet(aSet);
3237 pCaptionObj->SetLogicRect(aRect);
3238 pCaptionObj->SetTailPos(
3239 aRect.TopLeft() - Point(aRect.GetWidth() / 2, aRect.GetHeight() / 2));
3241 else if(auto pText = DynCastSdrTextObj( pObj.get()))
3243 pText->SetLogicRect(aRect);
3245 bool bVertical = (SID_DRAW_TEXT_VERTICAL == nSlotId);
3246 bool bMarquee = (SID_DRAW_TEXT_MARQUEE == nSlotId);
3248 pText->SetVerticalWriting(bVertical);
3250 if(bVertical)
3252 SfxItemSet aSet(rDrawModel.GetItemPool());
3253 aSet.Put(makeSdrTextAutoGrowWidthItem(true));
3254 aSet.Put(makeSdrTextAutoGrowHeightItem(false));
3255 aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP));
3256 aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
3257 pText->SetMergedItemSet(aSet);
3260 if(bMarquee)
3262 SfxItemSetFixed<SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST> aSet(rDrawModel.GetItemPool());
3263 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
3264 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
3265 aSet.Put( SdrTextAniKindItem( SdrTextAniKind::Slide ) );
3266 aSet.Put( SdrTextAniDirectionItem( SdrTextAniDirection::Left ) );
3267 aSet.Put( SdrTextAniCountItem( 1 ) );
3268 aSet.Put( SdrTextAniAmountItem( static_cast<sal_Int16>(GetWin()->PixelToLogic(Size(2,1)).Width())) );
3269 pObj->SetMergedItemSetAndBroadcast(aSet);
3272 SdrPageView* pPageView = pDrawView->GetSdrPageView();
3273 SdrCreateView::SetupObjLayer(pPageView, pDrawView->GetActiveLayer(), pObj.get());
3274 // switch undo off or this combined with ImpEndCreate will cause two undos
3275 // see comment made in SwFEShell::EndCreate (we create our own undo-object!)
3276 const bool bUndo(GetDoc()->GetIDocumentUndoRedo().DoesUndo());
3277 GetDoc()->GetIDocumentUndoRedo().DoUndo(false);
3278 pDrawView->InsertObjectAtView(pObj.get(), *pPageView);
3279 GetDoc()->GetIDocumentUndoRedo().DoUndo(bUndo);
3281 ImpEndCreate();
3284 /** SwFEShell::GetShapeBackground
3285 method determines background color of the page the selected drawing
3286 object is on and returns this color.
3287 If no color is found, because no drawing object is selected or ...,
3288 color COL_BLACK (default color on constructing object of class Color)
3289 is returned.
3291 @returns an object of class Color
3293 Color SwFEShell::GetShapeBackground() const
3295 Color aRetColor;
3297 // check, if a draw view exists
3298 OSL_ENSURE( Imp()->GetDrawView(), "wrong usage of SwFEShell::GetShapeBackground - no draw view!");
3299 if( Imp()->GetDrawView() )
3301 // determine list of selected objects
3302 const SdrMarkList* pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
3303 // check, if exactly one object is selected.
3304 OSL_ENSURE( pMrkList->GetMarkCount() == 1, "wrong usage of SwFEShell::GetShapeBackground - no selected object!");
3305 if ( pMrkList->GetMarkCount() == 1)
3307 // get selected object
3308 const SdrObject *pSdrObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
3309 // check, if selected object is a shape (drawing object)
3310 OSL_ENSURE( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) == nullptr, "wrong usage of SwFEShell::GetShapeBackground - selected object is not a drawing object!");
3311 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) == nullptr )
3313 // determine page frame of the frame the shape is anchored.
3314 const SwFrame* pAnchorFrame =
3315 static_cast<SwDrawContact*>(GetUserCall(pSdrObj))->GetAnchorFrame( pSdrObj );
3316 OSL_ENSURE( pAnchorFrame, "inconsistent model - no anchor at shape!");
3317 if ( pAnchorFrame )
3319 const SwPageFrame* pPageFrame = pAnchorFrame->FindPageFrame();
3320 OSL_ENSURE( pPageFrame, "inconsistent model - no page!");
3321 if ( pPageFrame )
3323 aRetColor = pPageFrame->GetDrawBackgroundColor();
3330 return aRetColor;
3333 /** Is default horizontal text direction for selected drawing object right-to-left
3334 Because drawing objects only painted for each page only, the default
3335 horizontal text direction of a drawing object is given by the corresponding
3336 page property.
3338 @returns boolean, indicating, if the horizontal text direction of the
3339 page, the selected drawing object is on, is right-to-left.
3341 bool SwFEShell::IsShapeDefaultHoriTextDirR2L() const
3343 bool bRet = false;
3345 // check, if a draw view exists
3346 OSL_ENSURE( Imp()->GetDrawView(), "wrong usage of SwFEShell::GetShapeBackground - no draw view!");
3347 if( Imp()->GetDrawView() )
3349 // determine list of selected objects
3350 const SdrMarkList* pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
3351 // check, if exactly one object is selected.
3352 OSL_ENSURE( pMrkList->GetMarkCount() == 1, "wrong usage of SwFEShell::GetShapeBackground - no selected object!");
3353 if ( pMrkList->GetMarkCount() == 1)
3355 // get selected object
3356 const SdrObject *pSdrObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
3357 // check, if selected object is a shape (drawing object)
3358 OSL_ENSURE( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) == nullptr, "wrong usage of SwFEShell::GetShapeBackground - selected object is not a drawing object!");
3359 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) == nullptr )
3361 // determine page frame of the frame the shape is anchored.
3362 const SwContact* pContact = GetUserCall(pSdrObj);
3363 OSL_ENSURE( pContact, "<SwFEShell::IsShapeDefaultHoriTextDirR2L(..)> - missing contact!" );
3364 if (!pContact)
3365 return false;
3366 const SwFrame* pAnchorFrame = static_cast<const SwDrawContact*>(pContact)->GetAnchorFrame( pSdrObj );
3367 OSL_ENSURE( pAnchorFrame, "inconsistent model - no anchor at shape!");
3368 if ( pAnchorFrame )
3370 const SwPageFrame* pPageFrame = pAnchorFrame->FindPageFrame();
3371 OSL_ENSURE( pPageFrame, "inconsistent model - no page!");
3372 if ( pPageFrame )
3374 bRet = pPageFrame->IsRightToLeft();
3381 return bRet;
3384 Point SwFEShell::GetRelativePagePosition(const Point& rDocPos)
3386 Point aRet(-1, -1);
3387 const SwFrame *pPage = GetLayout()->Lower();
3388 while ( pPage && !pPage->getFrameArea().Contains( rDocPos ) )
3390 pPage = pPage->GetNext();
3392 if(pPage)
3394 aRet = rDocPos - pPage->getFrameArea().TopLeft();
3396 return aRet;
3399 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */