1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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 <basegfx/polygon/b2dpolygontools.hxx>
94 #include <svx/svxids.hrc>
95 #include <osl/diagnose.h>
96 
97 #include <com/sun/star/embed/EmbedMisc.hpp>
98 #include <com/sun/star/embed/Aspects.hpp>
99 #include <com/sun/star/embed/XEmbeddedObject.hpp>
100 
101 #include <svx/srchdlg.hxx>
102 
103 #define SCROLLVAL 75
104 
105 using namespace com::sun::star;
106 
107 /**
108  * set line starts and ends for the object to be created
109  */
110 
111 namespace {
112 
getPolygon(const char * pResId,const SdrModel & rModel)113 ::basegfx::B2DPolyPolygon getPolygon(const char* pResId, const SdrModel& rModel)
114 {
115     ::basegfx::B2DPolyPolygon aRetval;
116     XLineEndListRef pLineEndList(rModel.GetLineEndList());
117 
118     if( pLineEndList.is() )
119     {
120         OUString aArrowName( SvxResId(pResId) );
121         tools::Long nCount = pLineEndList->Count();
122         tools::Long nIndex;
123         for( nIndex = 0; nIndex < nCount; nIndex++ )
124         {
125             const XLineEndEntry* pEntry = pLineEndList->GetLineEnd(nIndex);
126             if( pEntry->GetName() == aArrowName )
127             {
128                 aRetval = pEntry->GetLineEnd();
129                 break;
130             }
131         }
132     }
133 
134     return aRetval;
135 }
136 
137 }
138 
GetFlyFromMarked(const SdrMarkList * pLst,SwViewShell * pSh)139 SwFlyFrame *GetFlyFromMarked( const SdrMarkList *pLst, SwViewShell *pSh )
140 {
141     if ( !pLst )
142         pLst = pSh->HasDrawView() ? &pSh->Imp()->GetDrawView()->GetMarkedObjectList():nullptr;
143 
144     if ( pLst && pLst->GetMarkCount() == 1 )
145     {
146         SdrObject *pO = pLst->GetMark( 0 )->GetMarkedSdrObj();
147         if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pO))
148             return pVirtO->GetFlyFrame();
149     }
150     return nullptr;
151 }
152 
lcl_GrabCursor(SwFEShell * pSh,SwFlyFrame * pOldSelFly)153 static void lcl_GrabCursor( SwFEShell* pSh, SwFlyFrame* pOldSelFly)
154 {
155     const SwFrameFormat *pFlyFormat = pSh->SelFlyGrabCursor();
156     if( pFlyFormat && !pSh->ActionPend() &&
157                         (!pOldSelFly || pOldSelFly->GetFormat() != pFlyFormat) )
158     {
159         // now call set macro if applicable
160         pSh->GetFlyMacroLnk().Call( static_cast<const SwFlyFrameFormat*>(pFlyFormat) );
161         // if a dialog was started inside a macro, then
162         // MouseButtonUp arrives at macro and not to us. Therefore
163         // flag is always set here and will never be switched to
164         // respective Shell !!!!!!!
165 
166         g_bNoInterrupt = false;
167     }
168     else if( !pFlyFormat || RES_DRAWFRMFMT == pFlyFormat->Which() )
169     {
170         // --> assure consistent cursor
171         pSh->KillPams();
172         pSh->ClearMark();
173         pSh->SetCursor( pSh->Imp()->GetDrawView()->GetAllMarkedRect().TopLeft(), true);
174     }
175 }
176 
SelectObj(const Point & rPt,sal_uInt8 nFlag,SdrObject * pObj)177 bool SwFEShell::SelectObj( const Point& rPt, sal_uInt8 nFlag, SdrObject *pObj )
178 {
179     SwDrawView *pDView = Imp()->GetDrawView();
180     if(!pDView)
181         return false;
182     CurrShell aCurr( this );
183     StartAction();    // action is necessary to assure only one AttrChgdNotify
184                       // (e.g. due to Unmark->MarkListHasChgd) arrives
185 
186     const SdrMarkList &rMrkList = pDView->GetMarkedObjectList();
187     const bool bHadSelection = rMrkList.GetMarkCount();
188     const bool bAddSelect = 0 != (SW_ADD_SELECT & nFlag);
189     const bool bEnterGroup = 0 != (SW_ENTER_GROUP & nFlag);
190     SwFlyFrame* pOldSelFly = nullptr;
191     const Point aOldPos( pDView->GetAllMarkedRect().TopLeft() );
192 
193     if( bHadSelection )
194     {
195         // call Unmark when !bAddSelect or if fly was selected
196         bool bUnmark = !bAddSelect;
197 
198         if ( rMrkList.GetMarkCount() == 1 )
199         {
200             // if fly was selected, deselect it first
201             pOldSelFly = ::GetFlyFromMarked( &rMrkList, this );
202             if ( pOldSelFly )
203             {
204                 const sal_uInt16 nType = GetCntType();
205                 if( nType != CNT_TXT || (SW_LEAVE_FRAME & nFlag) ||
206                     ( pOldSelFly->GetFormat()->GetProtect().IsContentProtected()
207                      && !IsReadOnlyAvailable() ))
208                 {
209                     // If a fly is deselected, which contains graphic, OLE or
210                     // otherwise, the cursor should be removed from it.
211                     // Similar if a fly with protected content is deselected.
212                     // For simplicity we put the cursor next to the upper-left
213                     // corner.
214                     Point aPt( pOldSelFly->getFrameArea().Pos() );
215                     aPt.setX(aPt.getX() - 1);
216                     bool bUnLockView = !IsViewLocked();
217                     LockView( true );
218                     SetCursor( aPt, true );
219                     if( bUnLockView )
220                         LockView( false );
221                 }
222                 if ( nType & CNT_GRF &&
223                      static_cast<SwNoTextFrame*>(pOldSelFly->Lower())->HasAnimation() )
224                 {
225                     GetWin()->Invalidate( pOldSelFly->getFrameArea().SVRect() );
226                 }
227 
228                 // Cancel crop mode
229                 if ( SdrDragMode::Crop == GetDragMode() )
230                     SetDragMode( SdrDragMode::Move );
231 
232                 bUnmark = true;
233             }
234         }
235         if ( bUnmark )
236         {
237             pDView->UnmarkAll();
238             if (pOldSelFly)
239                 pOldSelFly->SelectionHasChanged(this);
240         }
241     }
242     else
243     {
244         KillPams();
245         ClearMark();
246     }
247 
248     if ( pObj )
249     {
250         OSL_ENSURE( !bEnterGroup, "SW_ENTER_GROUP is not supported" );
251         pDView->MarkObj( pObj, Imp()->GetPageView() );
252     }
253     else
254     {
255         // tolerance limit of Drawing-SS
256         const auto nHdlSizePixel = Imp()->GetDrawView()->GetMarkHdlSizePixel();
257         const short nMinMove = static_cast<short>(GetOut()->PixelToLogic(Size(nHdlSizePixel/2, 0)).Width());
258         pDView->MarkObj( rPt, nMinMove, bAddSelect, bEnterGroup );
259     }
260 
261     const bool bRet = 0 != rMrkList.GetMarkCount();
262 
263     if ( rMrkList.GetMarkCount() > 1 )
264     {
265         // It sucks if Drawing objects were selected and now
266         // additionally a fly is selected.
267         for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
268         {
269             SdrObject *pTmpObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
270             bool bForget = dynamic_cast<const SwVirtFlyDrawObj*>( pTmpObj) !=  nullptr;
271             if( bForget )
272             {
273                 pDView->UnmarkAll();
274                 pDView->MarkObj( pTmpObj, Imp()->GetPageView(), bAddSelect, bEnterGroup );
275                 break;
276             }
277         }
278     }
279 
280     if ( rMrkList.GetMarkCount() == 1 )
281     {
282         SwFlyFrame *pSelFly = ::GetFlyFromMarked( &rMrkList, this );
283         if (pSelFly)
284             pSelFly->SelectionHasChanged(this);
285     }
286 
287     if (!(nFlag & SW_ALLOW_TEXTBOX))
288     {
289         // If the fly frame is a textbox of a shape, then select the shape instead.
290         for (size_t i = 0; i < rMrkList.GetMarkCount(); ++i)
291         {
292             SdrObject* pObject = rMrkList.GetMark(i)->GetMarkedSdrObj();
293             SwContact* pContact = GetUserCall(pObject);
294             if (!pContact)
295             {
296                 continue;
297             }
298 
299             SwFrameFormat* pFormat = pContact->GetFormat();
300             if (SwFrameFormat* pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT))
301             {
302                 SdrObject* pShape = pShapeFormat->FindSdrObject();
303                 pDView->UnmarkAll();
304                 pDView->MarkObj(pShape, Imp()->GetPageView(), bAddSelect, bEnterGroup);
305                 break;
306             }
307         }
308     }
309 
310     if ( bRet )
311     {
312         ::lcl_GrabCursor(this, pOldSelFly);
313         if ( GetCntType() & CNT_GRF )
314         {
315             const SwFlyFrame *pTmp = GetFlyFromMarked( &rMrkList, this );
316             OSL_ENSURE( pTmp, "Graphic without Fly" );
317             if ( static_cast<const SwNoTextFrame*>(pTmp->Lower())->HasAnimation() )
318                 static_cast<const SwNoTextFrame*>(pTmp->Lower())->StopAnimation( GetOut() );
319         }
320     }
321     else if ( !pOldSelFly && bHadSelection )
322         SetCursor( aOldPos, true);
323 
324     if( bRet || !bHadSelection )
325         CallChgLnk();
326 
327     // update status line
328     ::FrameNotify( this, bRet ? FLY_DRAG_START : FLY_DRAG_END );
329 
330     EndAction();
331     return bRet;
332 }
333 
334 /*
335  *  Description: MoveAnchor( nDir ) looked for an another Anchor for
336  *  the selected drawing object (or fly frame) in the given direction.
337  *  An object "as character" doesn't moves anyway.
338  *  A page bounded object could move to the previous/next page with up/down,
339  *  an object bounded "at paragraph" moves to the previous/next paragraph, too.
340  *  An object bounded "at character" moves to the previous/next paragraph
341  *  with up/down and to the previous/next character with left/right.
342  *  If the anchor for at paragraph/character bounded objects has vertical or
343  *  right_to_left text direction, the directions for up/down/left/right will
344  *  interpreted accordingly.
345  *  An object bounded "at fly" takes the center of the actual anchor and looks
346  *  for the nearest fly frame in the given direction.
347  */
348 
LessX(Point const & aPt1,Point const & aPt2,bool bOld)349 static bool LessX( Point const & aPt1, Point const & aPt2, bool bOld )
350 {
351     return aPt1.getX() < aPt2.getX()
352             || ( aPt1.getX() == aPt2.getX()
353                 && ( aPt1.getY() < aPt2.getY()
354                     || ( aPt1.getY() == aPt2.getY() && bOld ) ) );
355 }
LessY(Point const & aPt1,Point const & aPt2,bool bOld)356 static bool LessY( Point const & aPt1, Point const & aPt2, bool bOld )
357 {
358     return aPt1.getY() < aPt2.getY()
359             || ( aPt1.getY() == aPt2.getY()
360                 && ( aPt1.getX() < aPt2.getX()
361                     || ( aPt1.getX() == aPt2.getX() && bOld ) ) );
362 }
363 
MoveAnchor(SwMove nDir)364 bool SwFEShell::MoveAnchor( SwMove nDir )
365 {
366     if (!Imp()->GetDrawView())
367         return false;
368     const SdrMarkList& pMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
369     if (1 != pMrkList.GetMarkCount())
370         return false;
371     SwFrame* pOld;
372     SwFlyFrame* pFly = nullptr;
373     SdrObject *pObj = pMrkList.GetMark( 0 )->GetMarkedSdrObj();
374     if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
375     {
376         pFly = pVirtO->GetFlyFrame();
377         pOld = pFly->AnchorFrame();
378     }
379     else
380         pOld = static_cast<SwDrawContact*>(GetUserCall(pObj))->GetAnchorFrame( pObj );
381     bool bRet = false;
382     if( pOld )
383     {
384         SwFrame* pNew = pOld;
385         // #i28701#
386         SwAnchoredObject* pAnchoredObj = ::GetUserCall( pObj )->GetAnchoredObj( pObj );
387         SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat();
388         SwFormatAnchor aAnch( rFormat.GetAnchor() );
389         RndStdIds nAnchorId = aAnch.GetAnchorId();
390         if ( RndStdIds::FLY_AS_CHAR == nAnchorId )
391             return false;
392         if( pOld->IsVertical() )
393         {
394             if( pOld->IsTextFrame() )
395             {
396                 switch( nDir ) {
397                     case SwMove::UP: nDir = SwMove::LEFT; break;
398                     case SwMove::DOWN: nDir = SwMove::RIGHT; break;
399                     case SwMove::LEFT: nDir = SwMove::DOWN; break;
400                     case SwMove::RIGHT: nDir = SwMove::UP; break;
401                 }
402                 if( pOld->IsRightToLeft() )
403                 {
404                     if( nDir == SwMove::LEFT )
405                         nDir = SwMove::RIGHT;
406                     else if( nDir == SwMove::RIGHT )
407                         nDir = SwMove::LEFT;
408                 }
409             }
410         }
411         switch ( nAnchorId ) {
412             case RndStdIds::FLY_AT_PAGE:
413             {
414                 OSL_ENSURE( pOld->IsPageFrame(), "Wrong anchor, page expected." );
415                 if( SwMove::UP == nDir )
416                     pNew = pOld->GetPrev();
417                 else if( SwMove::DOWN == nDir )
418                     pNew = pOld->GetNext();
419                 if( pNew && pNew != pOld )
420                 {
421                     aAnch.SetPageNum( static_cast<SwPageFrame*>(pNew)->GetPhyPageNum() );
422                     bRet = true;
423                 }
424                 break;
425             }
426             case RndStdIds::FLY_AT_CHAR:
427             {
428                 OSL_ENSURE(pOld->IsTextFrame(), "Wrong anchor, text frame expected.");
429                 if( SwMove::LEFT == nDir || SwMove::RIGHT == nDir )
430                 {
431                     SwPosition pos = *aAnch.GetContentAnchor();
432                     SwTextFrame *const pOldFrame(static_cast<SwTextFrame*>(pOld));
433                     TextFrameIndex const nAct(pOldFrame->MapModelToViewPos(pos));
434                     if( SwMove::LEFT == nDir )
435                     {
436                         bRet = true;
437                         if( nAct )
438                         {
439                             pos = pOldFrame->MapViewToModelPos(nAct - TextFrameIndex(1));
440                         }
441                         else
442                             nDir = SwMove::UP;
443                     }
444                     else
445                     {
446                         TextFrameIndex const nMax(pOldFrame->GetText().getLength());
447                         if( nAct < nMax )
448                         {
449                             bRet = true;
450                             pos = pOldFrame->MapViewToModelPos(nAct + TextFrameIndex(1));
451                         }
452                         else
453                             nDir = SwMove::DOWN;
454                     }
455                     if( pos != *aAnch.GetContentAnchor())
456                         aAnch.SetAnchor( &pos );
457                 }
458                 [[fallthrough]];
459             }
460             case RndStdIds::FLY_AT_PARA:
461             {
462                 OSL_ENSURE(pOld->IsTextFrame(), "Wrong anchor, text frame expected.");
463                 if( SwMove::UP == nDir )
464                     pNew = pOld->FindPrev();
465                 else if( SwMove::DOWN == nDir )
466                     pNew = pOld->FindNext();
467                 if( pNew && pNew != pOld && pNew->IsContentFrame() )
468                 {
469                     SwTextFrame *const pNewFrame(static_cast<SwTextFrame*>(pNew));
470                     SwPosition const pos = pNewFrame->MapViewToModelPos(
471                         TextFrameIndex(
472                             (bRet && pNewFrame->GetText().getLength() != 0)
473                                 ? pNewFrame->GetText().getLength() - 1
474                                 : 0));
475                     aAnch.SetAnchor( &pos );
476                     bRet = true;
477                 }
478                 else if( SwMove::UP == nDir || SwMove::DOWN == nDir )
479                     bRet = false;
480                 break;
481             }
482             case RndStdIds::FLY_AT_FLY:
483             {
484                 OSL_ENSURE( pOld->IsFlyFrame(), "Wrong anchor, fly frame expected.");
485                 SwPageFrame* pPage = pOld->FindPageFrame();
486                 OSL_ENSURE( pPage, "Where's my page?" );
487                 SwFlyFrame* pNewFly = nullptr;
488                 if( pPage->GetSortedObjs() )
489                 {
490                     bool bOld = false;
491                     Point aCenter( pOld->getFrameArea().Left() + pOld->getFrameArea().Width()/2,
492                                    pOld->getFrameArea().Top() + pOld->getFrameArea().Height()/2 );
493                     Point aBest;
494                     for(SwAnchoredObject* pAnchObj : *pPage->GetSortedObjs())
495                     {
496                         if( auto pTmp = dynamic_cast<SwFlyFrame*>( pAnchObj) )
497                         {
498                             if( pTmp == pOld )
499                                 bOld = true;
500                             else
501                             {
502                                 const SwFlyFrame* pCheck = pFly ? pTmp : nullptr;
503                                 while( pCheck )
504                                 {
505                                     if( pCheck == pFly )
506                                         break;
507                                     const SwFrame *pNxt = pCheck->GetAnchorFrame();
508                                     pCheck = pNxt ? pNxt->FindFlyFrame() : nullptr;
509                                 }
510                                 if( pCheck || pTmp->IsProtected() )
511                                     continue;
512                                 Point aNew( pTmp->getFrameArea().Left() +
513                                             pTmp->getFrameArea().Width()/2,
514                                             pTmp->getFrameArea().Top() +
515                                             pTmp->getFrameArea().Height()/2 );
516                                 bool bAccept = false;
517                                 switch( nDir ) {
518                                     case SwMove::RIGHT:
519                                     {
520                                         bAccept = LessX( aCenter, aNew, bOld )
521                                              && ( !pNewFly ||
522                                              LessX( aNew, aBest, false ) );
523                                         break;
524                                     }
525                                     case SwMove::LEFT:
526                                     {
527                                         bAccept = LessX( aNew, aCenter, !bOld )
528                                              && ( !pNewFly ||
529                                              LessX( aBest, aNew, true ) );
530                                         break;
531                                     }
532                                     case SwMove::UP:
533                                     {
534                                         bAccept = LessY( aNew, aCenter, !bOld )
535                                              && ( !pNewFly ||
536                                              LessY( aBest, aNew, true ) );
537                                         break;
538                                     }
539                                     case SwMove::DOWN:
540                                     {
541                                         bAccept = LessY( aCenter, aNew, bOld )
542                                              && ( !pNewFly ||
543                                              LessY( aNew, aBest, false ) );
544                                         break;
545                                     }
546                                 }
547                                 if( bAccept )
548                                 {
549                                     pNewFly = pTmp;
550                                     aBest = aNew;
551                                 }
552                             }
553                         }
554                     }
555                 }
556 
557                 if( pNewFly )
558                 {
559                     SwPosition aPos( *pNewFly->GetFormat()->
560                                         GetContent().GetContentIdx());
561                     aAnch.SetAnchor( &aPos );
562                     bRet = true;
563                 }
564                 break;
565             }
566             default: break;
567         }
568         if( bRet )
569         {
570             StartAllAction();
571             // --> handle change of anchor node:
572             // if count of the anchor frame also change, the fly frames have to be
573             // re-created. Thus, delete all fly frames except the <this> before the
574             // anchor attribute is change and re-create them afterwards.
575             {
576                 std::unique_ptr<SwHandleAnchorNodeChg, o3tl::default_delete<SwHandleAnchorNodeChg>> pHandleAnchorNodeChg;
577                 SwFlyFrameFormat* pFlyFrameFormat( dynamic_cast<SwFlyFrameFormat*>(&rFormat) );
578                 if ( pFlyFrameFormat )
579                 {
580                     pHandleAnchorNodeChg.reset(
581                         new SwHandleAnchorNodeChg( *pFlyFrameFormat, aAnch ));
582                 }
583                 rFormat.GetDoc()->SetAttr( aAnch, rFormat );
584             }
585             // #i28701# - no call of method
586             // <CheckCharRectAndTopOfLine()> for to-character anchored
587             // Writer fly frame needed. This method call can cause a
588             // format of the anchor frame, which is no longer intended.
589                     // Instead clear the anchor character rectangle and
590                     // the top of line values for all to-character anchored objects.
591             pAnchoredObj->ClearCharRectAndTopOfLine();
592             EndAllAction();
593         }
594     }
595     return bRet;
596 }
597 
GetMarkList_() const598 const SdrMarkList* SwFEShell::GetMarkList_() const
599 {
600     const SdrMarkList* pMarkList = nullptr;
601     if( Imp()->GetDrawView() != nullptr )
602         pMarkList = &Imp()->GetDrawView()->GetMarkedObjectList();
603     return pMarkList;
604 }
605 
GetSelFrameType() const606 FrameTypeFlags SwFEShell::GetSelFrameType() const
607 {
608     FrameTypeFlags eType;
609 
610     // get marked frame list, and check if anything is selected
611     const SdrMarkList* pMarkList = GetMarkList_();
612     if( pMarkList == nullptr  ||  pMarkList->GetMarkCount() == 0 )
613         eType = FrameTypeFlags::NONE;
614     else
615     {
616         // obtain marked item as fly frame; if no fly frame, it must
617         // be a draw object
618         const SwFlyFrame* pFly = ::GetFlyFromMarked(pMarkList, const_cast<SwFEShell*>(this));
619         if ( pFly != nullptr )
620         {
621             if( pFly->IsFlyLayFrame() )
622                 eType = FrameTypeFlags::FLY_FREE;
623             else if( pFly->IsFlyAtContentFrame() )
624                 eType = FrameTypeFlags::FLY_ATCNT;
625             else
626             {
627                 OSL_ENSURE( pFly->IsFlyInContentFrame(), "New frametype?" );
628                 eType = FrameTypeFlags::FLY_INCNT;
629             }
630         }
631         else
632             eType = FrameTypeFlags::DRAWOBJ;
633     }
634 
635     return eType;
636 }
637 
638 // does the draw selection contain a control?
IsSelContainsControl() const639 bool SwFEShell::IsSelContainsControl() const
640 {
641     bool bRet = false;
642 
643     // basically, copy the mechanism from GetSelFrameType(), but call
644     // CheckControl... if you get a drawing object
645     const SdrMarkList* pMarkList = GetMarkList_();
646     if( pMarkList != nullptr  &&  pMarkList->GetMarkCount() == 1 )
647     {
648         // if we have one marked object, get the SdrObject and check
649         // whether it contains a control
650         const SdrObject* pSdrObject = pMarkList->GetMark( 0 )->GetMarkedSdrObj();
651         bRet = pSdrObject && ::CheckControlLayer( pSdrObject );
652     }
653     return bRet;
654 }
655 
ScrollTo(const Point & rPt)656 void SwFEShell::ScrollTo( const Point &rPt )
657 {
658     const SwRect aRect( rPt, rPt );
659     if ( IsScrollMDI( this, aRect ) &&
660          (!Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() ||
661           Imp()->IsDragPossible( rPt )) )
662     {
663         ScrollMDI( this, aRect, SCROLLVAL, SCROLLVAL );
664     }
665 }
666 
SetDragMode(SdrDragMode eDragMode)667 void SwFEShell::SetDragMode( SdrDragMode eDragMode )
668 {
669     if ( Imp()->HasDrawView() )
670         Imp()->GetDrawView()->SetDragMode( eDragMode );
671 }
672 
GetDragMode() const673 SdrDragMode SwFEShell::GetDragMode() const
674 {
675     SdrDragMode nRet = SdrDragMode(0);
676     if ( Imp()->HasDrawView() )
677     {
678         nRet = Imp()->GetDrawView()->GetDragMode();
679     }
680     return nRet;
681 }
682 
StartCropImage()683 void SwFEShell::StartCropImage()
684 {
685     if ( !Imp()->HasDrawView() )
686     {
687         return;
688     }
689     SdrView *pView = Imp()->GetDrawView();
690     if (!pView) return;
691 
692     const SdrMarkList &rMarkList = pView->GetMarkedObjectList();
693     if( 0 == rMarkList.GetMarkCount() ) {
694         // No object selected
695         return;
696     }
697 
698     // If more than a single SwVirtFlyDrawObj is selected, select only the first SwVirtFlyDrawObj
699     if ( rMarkList.GetMarkCount() > 1 )
700     {
701         for ( size_t i = 0; i < rMarkList.GetMarkCount(); ++i )
702         {
703             SdrObject *pTmpObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
704             bool bForget = dynamic_cast<const SwVirtFlyDrawObj*>( pTmpObj) !=  nullptr;
705             if( bForget )
706             {
707                 pView->UnmarkAll();
708                 pView->MarkObj( pTmpObj, Imp()->GetPageView() );
709                 break;
710             }
711         }
712     }
713 
714     // Activate CROP mode
715     pView->SetEditMode( SdrViewEditMode::Edit );
716     SetDragMode( SdrDragMode::Crop );
717 }
718 
BeginDrag(const Point * pPt,bool bIsShift)719 void SwFEShell::BeginDrag( const Point* pPt, bool bIsShift)
720 {
721     SdrView *pView = Imp()->GetDrawView();
722     if ( pView && pView->AreObjectsMarked() )
723     {
724         m_pChainFrom.reset();
725         m_pChainTo.reset();
726         SdrHdl* pHdl = pView->PickHandle( *pPt );
727         if (pView->BegDragObj( *pPt, nullptr, pHdl ))
728             pView->GetDragMethod()->SetShiftPressed( bIsShift );
729         ::FrameNotify( this );
730     }
731 }
732 
Drag(const Point * pPt,bool)733 void SwFEShell::Drag( const Point *pPt, bool )
734 {
735     OSL_ENSURE( Imp()->HasDrawView(), "Drag without DrawView?" );
736     if ( HasDrawViewDrag() )
737     {
738         ScrollTo( *pPt );
739         Imp()->GetDrawView()->MovDragObj( *pPt );
740         Imp()->GetDrawView()->ShowDragAnchor();
741         ::FrameNotify( this );
742     }
743 }
744 
EndDrag()745 void SwFEShell::EndDrag()
746 {
747     OSL_ENSURE( Imp()->HasDrawView(), "EndDrag without DrawView?" );
748     SdrView *pView = Imp()->GetDrawView();
749     if ( !pView->IsDragObj() )
750         return;
751 
752     for(SwViewShell& rSh : GetRingContainer())
753         rSh.StartAction();
754 
755     StartUndo( SwUndoId::START );
756 
757     // #50778# Bug during dragging: In StartAction a HideShowXor is called.
758     // In EndDragObj() this is reversed, for no reason and even wrong.
759     // To restore consistency we should bring up the Xor again.
760 
761     // Reanimation from the hack #50778 to fix bug #97057
762     // May be not the best solution, but the one with lowest risc at the moment.
763     // pView->ShowShownXor( GetOut() );
764 
765     pView->EndDragObj();
766 
767     // DrawUndo on to flyframes are not stored
768     //             The flys change the flag.
769     GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
770     ChgAnchor( RndStdIds::FLY_AT_PARA, true );
771 
772     EndUndo( SwUndoId::END );
773 
774     for(SwViewShell& rSh : GetRingContainer())
775     {
776         rSh.EndAction();
777         if( auto pCursorShell = dynamic_cast<SwCursorShell *>(&rSh) )
778             pCursorShell->CallChgLnk();
779     }
780 
781     GetDoc()->getIDocumentState().SetModified();
782     ::FrameNotify( this );
783 }
784 
BreakDrag()785 void SwFEShell::BreakDrag()
786 {
787     OSL_ENSURE( Imp()->HasDrawView(), "BreakDrag without DrawView?" );
788     if( HasDrawViewDrag() )
789         Imp()->GetDrawView()->BrkDragObj();
790     SetChainMarker();
791 }
792 
793 // If a fly is selected, pulls the crsr in the first ContentFrame
SelFlyGrabCursor()794 const SwFrameFormat* SwFEShell::SelFlyGrabCursor()
795 {
796     if ( Imp()->HasDrawView() )
797     {
798         const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
799         SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
800 
801         if( pFly )
802         {
803             SwContentFrame *pCFrame = pFly->ContainsContent();
804             if ( pCFrame )
805             {
806                 // --> assure, that the cursor is consistent.
807                 KillPams();
808                 ClearMark();
809                 SwPaM       *pCursor  = GetCursor();
810 
811                 if (pCFrame->IsTextFrame())
812                 {
813                     *pCursor->GetPoint() = static_cast<SwTextFrame *>(pCFrame)
814                         ->MapViewToModelPos(TextFrameIndex(0));
815                 }
816                 else
817                 {
818                     assert(pCFrame->IsNoTextFrame());
819                     SwContentNode *const pCNode = static_cast<SwNoTextFrame *>(pCFrame)->GetNode();
820                     pCursor->GetPoint()->nNode = *pCNode;
821                     pCursor->GetPoint()->nContent.Assign( pCNode, 0 );
822                 }
823 
824                 SwRect& rChrRect = const_cast<SwRect&>(GetCharRect());
825                 rChrRect = pFly->getFramePrintArea();
826                 rChrRect.Pos() += pFly->getFrameArea().Pos();
827                 GetCursorDocPos() = rChrRect.Pos();
828             }
829             return pFly->GetFormat();
830         }
831     }
832     return nullptr;
833 }
834 
835 // Selection to above/below (Z-Order)
lcl_NotifyNeighbours(const SdrMarkList * pLst)836 static void lcl_NotifyNeighbours( const SdrMarkList *pLst )
837 {
838     // Rules for evasion have changed.
839     // 1. The environment of the fly and everything inside should be notified
840     // 2. The content of the frame itself has to be notified
841     // 3. Frames displaced by the frame have to be notified
842     // 4. Also Drawing objects can displace frames
843     for( size_t j = 0; j < pLst->GetMarkCount(); ++j )
844     {
845         SwPageFrame *pPage;
846         bool bCheckNeighbours = false;
847         sal_Int16 aHori = text::HoriOrientation::NONE;
848         SwRect aRect;
849         SdrObject *pO = pLst->GetMark( j )->GetMarkedSdrObj();
850         if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pO))
851         {
852             SwFlyFrame *pFly = pVirtO->GetFlyFrame();
853 
854             const SwFormatHoriOrient &rHori = pFly->GetFormat()->GetHoriOrient();
855             aHori = rHori.GetHoriOrient();
856             if( text::HoriOrientation::NONE != aHori && text::HoriOrientation::CENTER != aHori &&
857                 pFly->IsFlyAtContentFrame() )
858             {
859                 bCheckNeighbours = true;
860                 pFly->InvalidatePos();
861                 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFly);
862                 aFrm.Pos().AdjustY(1 );
863             }
864 
865             pPage = pFly->FindPageFrame();
866             aRect = pFly->getFrameArea();
867         }
868         else
869         {
870             SwFrame* pAnch = static_cast<SwDrawContact*>( GetUserCall(pO) )->GetAnchorFrame( pO );
871             if( !pAnch )
872                 continue;
873             pPage = pAnch->FindPageFrame();
874             // #i68520# - naming changed
875             aRect = GetBoundRectOfAnchoredObj( pO );
876         }
877 
878         const size_t nCount = pPage->GetSortedObjs() ? pPage->GetSortedObjs()->size() : 0;
879         for ( size_t i = 0; i < nCount; ++i )
880         {
881             SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
882             SwFlyFrame* pAct = dynamic_cast<SwFlyFrame*>(pAnchoredObj);
883             if ( !pAct )
884                 continue;
885 
886             SwRect aTmpCalcPnt( pAct->getFramePrintArea() );
887             aTmpCalcPnt += pAct->getFrameArea().Pos();
888             if ( aRect.IsOver( aTmpCalcPnt ) )
889             {
890                 SwContentFrame *pCnt = pAct->ContainsContent();
891                 while ( pCnt )
892                 {
893                     aTmpCalcPnt = pCnt->getFramePrintArea();
894                     aTmpCalcPnt += pCnt->getFrameArea().Pos();
895                     if ( aRect.IsOver( aTmpCalcPnt ) )
896                         static_cast<SwFrame*>(pCnt)->Prepare( PrepareHint::FlyFrameAttributesChanged );
897                     pCnt = pCnt->GetNextContentFrame();
898                 }
899             }
900             if ( bCheckNeighbours && pAct->IsFlyAtContentFrame() )
901             {
902                 const SwFormatHoriOrient &rH = pAct->GetFormat()->GetHoriOrient();
903                 if ( rH.GetHoriOrient() == aHori &&
904                      pAct->getFrameArea().Top()    <= aRect.Bottom() &&
905                      pAct->getFrameArea().Bottom() >= aRect.Top() )
906                 {
907                     pAct->InvalidatePos();
908                     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pAct);
909                     aFrm.Pos().AdjustY(1 );
910                 }
911             }
912         }
913     }
914 }
915 
SetLineEnds(SfxItemSet & rAttr,SdrObject const & rObj,sal_uInt16 nSlotId)916 void SwFEShell::SetLineEnds(SfxItemSet& rAttr, SdrObject const & rObj, sal_uInt16 nSlotId)
917 {
918     SdrModel& rModel(rObj.getSdrModelFromSdrObject());
919 
920     if ( !(nSlotId == SID_LINE_ARROW_START      ||
921           nSlotId == SID_LINE_ARROW_END        ||
922           nSlotId == SID_LINE_ARROWS           ||
923           nSlotId == SID_LINE_ARROW_CIRCLE     ||
924           nSlotId == SID_LINE_CIRCLE_ARROW     ||
925           nSlotId == SID_LINE_ARROW_SQUARE     ||
926           nSlotId == SID_LINE_SQUARE_ARROW     ||
927           nSlotId == SID_DRAW_MEASURELINE) )
928         return;
929 
930     // set attributes of line start and ends
931 
932     // arrowhead
933     ::basegfx::B2DPolyPolygon aArrow( getPolygon( RID_SVXSTR_ARROW, rModel ) );
934     if( !aArrow.count() )
935     {
936         ::basegfx::B2DPolygon aNewArrow;
937         aNewArrow.append(::basegfx::B2DPoint(10.0, 0.0));
938         aNewArrow.append(::basegfx::B2DPoint(0.0, 30.0));
939         aNewArrow.append(::basegfx::B2DPoint(20.0, 30.0));
940         aNewArrow.setClosed(true);
941         aArrow.append(aNewArrow);
942     }
943 
944     // Circles
945     ::basegfx::B2DPolyPolygon aCircle( getPolygon( RID_SVXSTR_CIRCLE, rModel ) );
946     if( !aCircle.count() )
947     {
948         ::basegfx::B2DPolygon aNewCircle = ::basegfx::utils::createPolygonFromEllipse(::basegfx::B2DPoint(0.0, 0.0), 250.0, 250.0);
949         aNewCircle.setClosed(true);
950         aCircle.append(aNewCircle);
951     }
952 
953     // Square
954     ::basegfx::B2DPolyPolygon aSquare( getPolygon( RID_SVXSTR_SQUARE, rModel ) );
955     if( !aSquare.count() )
956     {
957         ::basegfx::B2DPolygon aNewSquare;
958         aNewSquare.append(::basegfx::B2DPoint(0.0, 0.0));
959         aNewSquare.append(::basegfx::B2DPoint(10.0, 0.0));
960         aNewSquare.append(::basegfx::B2DPoint(10.0, 10.0));
961         aNewSquare.append(::basegfx::B2DPoint(0.0, 10.0));
962         aNewSquare.setClosed(true);
963         aSquare.append(aNewSquare);
964     }
965 
966     SfxItemSet aSet( rModel.GetItemPool() );
967     tools::Long nWidth = 100; // (1/100th mm)
968 
969     // determine line width and calculate with it the line end width
970     if( aSet.GetItemState( XATTR_LINEWIDTH ) != SfxItemState::DONTCARE )
971     {
972         tools::Long nValue = aSet.Get( XATTR_LINEWIDTH ).GetValue();
973         if( nValue > 0 )
974             nWidth = nValue * 3;
975     }
976 
977     switch (nSlotId)
978     {
979         case SID_LINE_ARROWS:
980         case SID_DRAW_MEASURELINE:
981         {
982             // connector with arrow ends
983             rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
984             rAttr.Put(XLineStartWidthItem(nWidth));
985             rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
986             rAttr.Put(XLineEndWidthItem(nWidth));
987         }
988         break;
989 
990         case SID_LINE_ARROW_START:
991         case SID_LINE_ARROW_CIRCLE:
992         case SID_LINE_ARROW_SQUARE:
993         {
994             // connector with arrow start
995             rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
996             rAttr.Put(XLineStartWidthItem(nWidth));
997         }
998         break;
999 
1000         case SID_LINE_ARROW_END:
1001         case SID_LINE_CIRCLE_ARROW:
1002         case SID_LINE_SQUARE_ARROW:
1003         {
1004             // connector with arrow end
1005             rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
1006             rAttr.Put(XLineEndWidthItem(nWidth));
1007         }
1008         break;
1009     }
1010 
1011     // and again, for the still missing ends
1012     switch (nSlotId)
1013     {
1014         case SID_LINE_ARROW_CIRCLE:
1015         {
1016             // circle end
1017             rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
1018             rAttr.Put(XLineEndWidthItem(nWidth));
1019         }
1020         break;
1021 
1022         case SID_LINE_CIRCLE_ARROW:
1023         {
1024             // circle start
1025             rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
1026             rAttr.Put(XLineStartWidthItem(nWidth));
1027         }
1028         break;
1029 
1030         case SID_LINE_ARROW_SQUARE:
1031         {
1032             // square end
1033             rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_SQUARE), aSquare));
1034             rAttr.Put(XLineEndWidthItem(nWidth));
1035         }
1036         break;
1037 
1038         case SID_LINE_SQUARE_ARROW:
1039         {
1040             // square start
1041             rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_SQUARE), aSquare));
1042             rAttr.Put(XLineStartWidthItem(nWidth));
1043         }
1044         break;
1045     }
1046 
1047 }
1048 
SelectionToTop(bool bTop)1049 void SwFEShell::SelectionToTop( bool bTop )
1050 {
1051     OSL_ENSURE( Imp()->HasDrawView(), "SelectionToTop without DrawView?" );
1052     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1053     OSL_ENSURE( rMrkList.GetMarkCount(), "No object selected." );
1054 
1055     SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
1056     if ( pFly && pFly->IsFlyInContentFrame() )
1057         return;
1058 
1059     StartAllAction();
1060     if ( bTop )
1061         Imp()->GetDrawView()->PutMarkedToTop();
1062     else
1063         Imp()->GetDrawView()->MovMarkedToTop();
1064     ::lcl_NotifyNeighbours( &rMrkList );
1065 
1066     // Does the selection contain a textbox?
1067     for (size_t i = 0; i < rMrkList.GetMarkCount(); i++)
1068         if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
1069             // Get the textbox-shape
1070             if (auto pFormat = FindFrameFormat(pObj))
1071             {
1072                 // If it has not textframe skip...
1073                 if (!SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(pFormat))
1074                     continue;
1075                 // If it has a textframe so it is a textbox, get its page
1076                 if (auto pDrwModel
1077                     = pFormat->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel())
1078                     // Not really understood why everything is on page 0...
1079                     // but it is easier to handle sdrobjects, that's true
1080                     if (auto pPage = pDrwModel->GetPage(0))
1081                     {
1082                         // nShift: it means how many layers the pObj have to be shifted up,
1083                         // in order not to interfere with other shapes and textboxes.
1084                         // Situations:
1085                         // - The next shape has textframe: This shape have to shifted with
1086                         //   two layers.
1087                         // - The next shape has not got textframe: This shape have to be
1088                         //   shifted only one layer up.
1089                         // - The next shape is null:
1090                         //      - This shape is already at heaven: Only the textframe have
1091                         //        to be adjusted.
1092                         sal_uInt32 nShift = 0;
1093                         // Get the one level higher object (note: can be nullptr!)
1094                         const auto pNextObj = pPage->SetObjectOrdNum(pObj->GetOrdNum() + 1, pObj->GetOrdNum() + 1);
1095                         // If there is a higher object (not null)...
1096                         if (pNextObj)
1097                         {
1098                             // One level shift is necessary
1099                             nShift++;
1100                             // If this object is a textbox, two level increasing needed
1101                             // (one for the shape and one for the frame)
1102                             if (auto pNextFormat = FindFrameFormat(pNextObj))
1103                                 if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT)
1104                                     || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
1105                                     nShift++;
1106                         }
1107                         // Set the new z-order.
1108                         pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() + nShift);
1109                     }
1110                 // The shape is on the right level, correct the layer of the frame
1111                 SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat);
1112             }
1113 
1114     GetDoc()->getIDocumentState().SetModified();
1115     EndAllAction();
1116 }
1117 
SelectionToBottom(bool bBottom)1118 void SwFEShell::SelectionToBottom( bool bBottom )
1119 {
1120     OSL_ENSURE( Imp()->HasDrawView(), "SelectionToBottom without DrawView?" );
1121     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1122     OSL_ENSURE( rMrkList.GetMarkCount(), "No object selected." );
1123 
1124     SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
1125     if ( pFly && pFly->IsFlyInContentFrame() )
1126         return;
1127 
1128     StartAllAction();
1129     if ( bBottom )
1130         Imp()->GetDrawView()->PutMarkedToBtm();
1131     else
1132         Imp()->GetDrawView()->MovMarkedToBtm();
1133     ::lcl_NotifyNeighbours( &rMrkList );
1134 
1135     // If the selection has textbox
1136     for(size_t i = 0; i < rMrkList.GetMarkCount(); i++)
1137         if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
1138             // Get the shape of the textbox
1139             if (auto pFormat = FindFrameFormat(pObj))
1140             {
1141                 // If the shape has not textframes skip.
1142                 if (!SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(pFormat))
1143                     continue;
1144                 // If has, move the shape to correct level with...
1145                 if (auto pDrwModel
1146                     = pFormat->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel())
1147                     if (auto pPage = pDrwModel->GetPage(0))
1148                     {
1149                         const auto pNextObj = pPage->SetObjectOrdNum(pObj->GetOrdNum() - 1, pObj->GetOrdNum() - 1);
1150                         // If there is a lower object (not null)...
1151                         if (pNextObj)
1152                         {
1153                             // If the lower has no textframe, just do nothing, else move by one lower
1154                             if (auto pNextFormat = FindFrameFormat(pNextObj))
1155                                 if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT)
1156                                     || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
1157                                     pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() - 1);
1158                         }
1159                     }
1160                 // And set correct layer for the selected textbox.
1161                 SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat);
1162             }
1163 
1164     GetDoc()->getIDocumentState().SetModified();
1165     EndAllAction();
1166 }
1167 
1168 // Object above/below the document? 2 Controls, 1 Heaven, 0 Hell,
1169 // SDRLAYER_NOTFOUND Ambiguous
GetLayerId() const1170 SdrLayerID SwFEShell::GetLayerId() const
1171 {
1172     if ( !Imp()->HasDrawView() )
1173         return SDRLAYER_NOTFOUND;
1174 
1175     SdrLayerID nRet = SDRLAYER_NOTFOUND;
1176     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1177     for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
1178     {
1179         const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
1180         if( !pObj )
1181             continue;
1182         if ( nRet == SDRLAYER_NOTFOUND )
1183             nRet = pObj->GetLayer();
1184         else if ( nRet != pObj->GetLayer() )
1185         {
1186             return SDRLAYER_NOTFOUND;
1187         }
1188     }
1189     return nRet;
1190 }
1191 
1192 // Object above/below the document
1193 // Note: only visible objects can be marked. Thus, objects with invisible
1194 //       layer IDs have not to be considered.
1195 //       If <SwFEShell> exists, layout exists!!
ChangeOpaque(SdrLayerID nLayerId)1196 void SwFEShell::ChangeOpaque( SdrLayerID nLayerId )
1197 {
1198     if ( !Imp()->HasDrawView() )
1199         return;
1200 
1201     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1202     const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess();
1203     // correct type of <nControls>
1204     for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
1205     {
1206         SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
1207         if( !pObj )
1208             continue;
1209         // or group objects containing controls.
1210         // --> #i113730#
1211         // consider that a member of a drawing group has been selected.
1212         const SwContact* pContact = ::GetUserCall( pObj );
1213         OSL_ENSURE( pContact && pContact->GetMaster(), "<SwFEShell::ChangeOpaque(..)> - missing contact or missing master object at contact!" );
1214         const bool bControlObj = ( pContact && pContact->GetMaster() )
1215                                  ? ::CheckControlLayer( pContact->GetMaster() )
1216                                  : ::CheckControlLayer( pObj );
1217         if ( !bControlObj && pObj->GetLayer() != nLayerId )
1218         {
1219             pObj->SetLayer( nLayerId );
1220             InvalidateWindows( SwRect( pObj->GetCurrentBoundRect() ) );
1221             if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
1222             {
1223                 SwFormat *pFormat = pVirtO->GetFlyFrame()->GetFormat();
1224                 SvxOpaqueItem aOpa( pFormat->GetOpaque() );
1225                 aOpa.SetValue(  nLayerId == rIDDMA.GetHellId() );
1226                 pFormat->SetFormatAttr( aOpa );
1227                 // If pObj has textframe, put its textframe to the right level
1228                 if (auto pTextBx = FindFrameFormat(pObj))
1229                     SwTextBoxHelper::DoTextBoxZOrderCorrection(pTextBx);
1230             }
1231         }
1232     }
1233     GetDoc()->getIDocumentState().SetModified();
1234 }
1235 
SelectionToHeaven()1236 void SwFEShell::SelectionToHeaven()
1237 {
1238     ChangeOpaque( getIDocumentDrawModelAccess().GetHeavenId() );
1239 }
1240 
SelectionToHell()1241 void SwFEShell::SelectionToHell()
1242 {
1243     ChangeOpaque( getIDocumentDrawModelAccess().GetHellId() );
1244 }
1245 
IsObjSelected() const1246 size_t SwFEShell::IsObjSelected() const
1247 {
1248     if ( IsFrameSelected() || !Imp()->HasDrawView() )
1249         return 0;
1250 
1251     return Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount();
1252 }
1253 
IsFrameSelected() const1254 bool SwFEShell::IsFrameSelected() const
1255 {
1256     if ( !Imp()->HasDrawView() )
1257         return false;
1258     else
1259         return nullptr != ::GetFlyFromMarked( &Imp()->GetDrawView()->GetMarkedObjectList(),
1260                                         const_cast<SwFEShell*>(this) );
1261 }
1262 
IsObjSelected(const SdrObject & rObj) const1263 bool SwFEShell::IsObjSelected( const SdrObject& rObj ) const
1264 {
1265     if ( IsFrameSelected() || !Imp()->HasDrawView() )
1266         return false;
1267     else
1268         return Imp()->GetDrawView()->IsObjMarked( &rObj );
1269 }
1270 
IsRotationOfSwGrfNodePossible() const1271 bool SwFEShell::IsRotationOfSwGrfNodePossible() const
1272 {
1273     // RotGrfFlyFrame: check if RotationMode is possible
1274     const SdrView *pSdrView = Imp()->GetDrawView();
1275 
1276     if(pSdrView)
1277     {
1278         const SdrMarkList& rList(pSdrView->GetMarkedObjectList());
1279 
1280         if(1 == rList.GetMarkCount())
1281         {
1282             const SwVirtFlyDrawObj* pVirtFlyDraw(dynamic_cast< const SwVirtFlyDrawObj* >(rList.GetMark(0)->GetMarkedSdrObj()));
1283 
1284             if(nullptr != pVirtFlyDraw)
1285             {
1286                 return pVirtFlyDraw->ContainsSwGrfNode();
1287             }
1288         }
1289     }
1290 
1291     return false;
1292 }
1293 
IsObjSameLevelWithMarked(const SdrObject * pObj) const1294 bool SwFEShell::IsObjSameLevelWithMarked(const SdrObject* pObj) const
1295 {
1296     if (pObj)
1297     {
1298         const SdrMarkList& aMarkList = Imp()->GetDrawView()->GetMarkedObjectList();
1299         if (aMarkList.GetMarkCount() == 0)
1300         {
1301             return true;
1302         }
1303         SdrMark* pM=aMarkList.GetMark(0);
1304         if (pM)
1305         {
1306             SdrObject* pMarkObj = pM->GetMarkedSdrObj();
1307             if (pMarkObj && pMarkObj->getParentSdrObjectFromSdrObject() == pObj->getParentSdrObjectFromSdrObject())
1308                 return true;
1309         }
1310     }
1311     return false;
1312 }
1313 
EndTextEdit()1314 void SwFEShell::EndTextEdit()
1315 {
1316     // Terminate the TextEditMode. If required (default if the object
1317     // does not contain any more text and does not carry attributes) the object
1318     // is deleted. All other objects marked are preserved.
1319 
1320     OSL_ENSURE( Imp()->HasDrawView() && Imp()->GetDrawView()->IsTextEdit(),
1321             "EndTextEdit a no Object" );
1322 
1323     StartAllAction();
1324     SdrView *pView = Imp()->GetDrawView();
1325     SdrObject *pObj = pView->GetTextEditObject();
1326     SdrObjUserCall* pUserCall = GetUserCall(pObj);
1327     if( nullptr != pUserCall )
1328     {
1329         SdrObject *pTmp = static_cast<SwContact*>(pUserCall)->GetMaster();
1330         if( !pTmp )
1331             pTmp = pObj;
1332         pUserCall->Changed( *pTmp, SdrUserCallType::Resize, pTmp->GetLastBoundRect() );
1333     }
1334     if ( !pObj->getParentSdrObjectFromSdrObject() )
1335     {
1336         if ( SdrEndTextEditKind::ShouldBeDeleted == pView->SdrEndTextEdit(true) )
1337         {
1338             if ( pView->GetMarkedObjectList().GetMarkCount() > 1 )
1339             {
1340                 SdrMarkList aSave( pView->GetMarkedObjectList() );
1341                 aSave.DeleteMark( aSave.FindObject( pObj ) );
1342                 if ( aSave.GetMarkCount() )
1343                 {
1344                     pView->UnmarkAll();
1345                     pView->MarkObj( pObj, Imp()->GetPageView() );
1346                 }
1347                 DelSelectedObj();
1348                 for ( size_t i = 0; i < aSave.GetMarkCount(); ++i )
1349                     pView->MarkObj( aSave.GetMark( i )->GetMarkedSdrObj(), Imp()->GetPageView() );
1350             }
1351             else
1352                 DelSelectedObj();
1353         }
1354     }
1355     else
1356         pView->SdrEndTextEdit();
1357 
1358     if (comphelper::LibreOfficeKit::isActive())
1359         SfxLokHelper::notifyOtherViews(GetSfxViewShell(), LOK_CALLBACK_VIEW_LOCK, "rectangle", "EMPTY");
1360 
1361     EndAllAction();
1362 }
1363 
IsInsideSelectedObj(const Point & rPt)1364 bool SwFEShell::IsInsideSelectedObj( const Point &rPt )
1365 {
1366     if( Imp()->HasDrawView() )
1367     {
1368         SwDrawView *pDView = Imp()->GetDrawView();
1369 
1370         if( pDView->GetMarkedObjectList().GetMarkCount() &&
1371             pDView->IsMarkedObjHit( rPt ) )
1372         {
1373             return true;
1374         }
1375     }
1376     return false;
1377 }
1378 
IsObjSelectable(const Point & rPt)1379 bool SwFEShell::IsObjSelectable( const Point& rPt )
1380 {
1381     CurrShell aCurr(this);
1382     SwDrawView *pDView = Imp()->GetDrawView();
1383     bool bRet = false;
1384     if( pDView )
1385     {
1386         SdrPageView* pPV;
1387         const auto nOld = pDView->GetHitTolerancePixel();
1388         pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
1389 
1390         bRet = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE) != nullptr;
1391         pDView->SetHitTolerancePixel( nOld );
1392     }
1393     return bRet;
1394 }
1395 
GetObjAt(const Point & rPt)1396 SdrObject* SwFEShell::GetObjAt( const Point& rPt )
1397 {
1398     SdrObject* pRet = nullptr;
1399     CurrShell aCurr(this);
1400     SwDrawView *pDView = Imp()->GetDrawView();
1401     if( pDView )
1402     {
1403         SdrPageView* pPV;
1404         const auto nOld = pDView->GetHitTolerancePixel();
1405         pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
1406 
1407         pRet = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE);
1408         pDView->SetHitTolerancePixel( nOld );
1409     }
1410     return pRet;
1411 }
1412 
1413 // Test if there is an object at that position and if it should be selected.
ShouldObjectBeSelected(const Point & rPt)1414 bool SwFEShell::ShouldObjectBeSelected(const Point& rPt)
1415 {
1416     CurrShell aCurr(this);
1417     SwDrawView *pDrawView = Imp()->GetDrawView();
1418     bool bRet(false);
1419 
1420     if(pDrawView)
1421     {
1422         SdrPageView* pPV;
1423         const auto nOld(pDrawView->GetHitTolerancePixel());
1424 
1425         pDrawView->SetHitTolerancePixel(pDrawView->GetMarkHdlSizePixel()/2);
1426         SdrObject* pObj = pDrawView->PickObj(rPt, pDrawView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE);
1427         pDrawView->SetHitTolerancePixel(nOld);
1428 
1429         if (pObj)
1430         {
1431             bRet = true;
1432             const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess();
1433             // #i89920#
1434             // Do not select object in background which is overlapping this text
1435             // at the given position.
1436             bool bObjInBackground( false );
1437             {
1438                 if ( pObj->GetLayer() == rIDDMA.GetHellId() )
1439                 {
1440                     const SwAnchoredObject* pAnchoredObj = ::GetUserCall( pObj )->GetAnchoredObj( pObj );
1441                     const SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat();
1442                     const SwFormatSurround& rSurround = rFormat.GetSurround();
1443                     if ( rSurround.GetSurround() == css::text::WrapTextMode_THROUGH )
1444                     {
1445                         bObjInBackground = true;
1446                     }
1447                 }
1448             }
1449             if ( bObjInBackground )
1450             {
1451                 const SwPageFrame* pPageFrame = GetLayout()->GetPageAtPos( rPt );
1452                 if( pPageFrame )
1453                 {
1454                     const SwContentFrame* pContentFrame( pPageFrame->ContainsContent() );
1455                     while ( pContentFrame )
1456                     {
1457                         if ( pContentFrame->UnionFrame().IsInside( rPt ) )
1458                         {
1459                             const SwTextFrame* pTextFrame =
1460                                     dynamic_cast<const SwTextFrame*>(pContentFrame);
1461                             if ( pTextFrame )
1462                             {
1463                                 SwPosition aPos(GetDoc()->GetNodes());
1464                                 Point aTmpPt( rPt );
1465                                 if (pTextFrame->GetKeyCursorOfst(&aPos, aTmpPt))
1466                                 {
1467                                     SwRect aCursorCharRect;
1468                                     if (pTextFrame->GetCharRect(aCursorCharRect,
1469                                                 aPos))
1470                                     {
1471                                         if ( aCursorCharRect.IsOver( SwRect( pObj->GetLastBoundRect() ) ) )
1472                                         {
1473                                             bRet = false;
1474                                         }
1475                                     }
1476                                 }
1477                             }
1478                             else
1479                             {
1480                                 bRet = false;
1481                             }
1482                             break;
1483                         }
1484 
1485                         pContentFrame = pContentFrame->GetNextContentFrame();
1486                     }
1487                 }
1488             }
1489 
1490             // Don't select header / footer objects in body edition and vice-versa
1491             SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
1492             if (pContact && !pContact->ObjAnchoredAtPage() )
1493             {
1494                 const SwPosition& rPos = pContact->GetContentAnchor();
1495                 bool bInHdrFtr = GetDoc()->IsInHeaderFooter( rPos.nNode );
1496                 if (IsHeaderFooterEdit() != bInHdrFtr)
1497                 {
1498                     bRet = false;
1499                 }
1500             }
1501 
1502             if ( bRet )
1503             {
1504                 const SdrPage* pPage = rIDDMA.GetDrawModel()->GetPage(0);
1505                 for(size_t a = pObj->GetOrdNum()+1; bRet && a < pPage->GetObjCount(); ++a)
1506                 {
1507                     SdrObject *pCandidate = pPage->GetObj(a);
1508 
1509                     SwVirtFlyDrawObj* pDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pCandidate);
1510                     if (pDrawObj && pDrawObj->GetCurrentBoundRect().IsInside(rPt))
1511                     {
1512                         bRet = false;
1513                     }
1514                 }
1515             }
1516         }
1517     }
1518 
1519     return bRet;
1520 }
1521 
1522 /*
1523  * If an object was selected, we assume its upper-left corner
1524  * otherwise the middle of the current CharRects.
1525  * Does the object include a control or groups,
1526  * which comprise only controls
1527  */
lcl_IsControlGroup(const SdrObject * pObj)1528 static bool lcl_IsControlGroup( const SdrObject *pObj )
1529 {
1530     bool bRet = false;
1531     if(dynamic_cast<const SdrUnoObj*>( pObj) !=  nullptr)
1532         bRet = true;
1533     else if( auto pObjGroup = dynamic_cast<const SdrObjGroup*>( pObj) )
1534     {
1535         bRet = true;
1536         const SdrObjList *pLst = pObjGroup->GetSubList();
1537         for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
1538             if( !::lcl_IsControlGroup( pLst->GetObj( i ) ) )
1539                 return false;
1540     }
1541     return bRet;
1542 }
1543 
1544 namespace
1545 {
1546     class MarkableObjectsOnly : public svx::ISdrObjectFilter
1547     {
1548     public:
MarkableObjectsOnly(SdrPageView * i_pPV)1549         explicit MarkableObjectsOnly( SdrPageView* i_pPV )
1550             :m_pPV( i_pPV )
1551         {
1552         }
1553 
includeObject(const SdrObject & i_rObject) const1554         virtual bool    includeObject( const SdrObject& i_rObject ) const override
1555         {
1556             return m_pPV && m_pPV->GetView().IsObjMarkable( &i_rObject, m_pPV );
1557         }
1558 
1559     private:
1560         SdrPageView*    m_pPV;
1561     };
1562 }
1563 
GetBestObject(bool bNext,GotoObjFlags eType,bool bFlat,const svx::ISdrObjectFilter * pFilter)1564 const SdrObject* SwFEShell::GetBestObject( bool bNext, GotoObjFlags eType, bool bFlat, const svx::ISdrObjectFilter* pFilter )
1565 {
1566     if( !Imp()->HasDrawView() )
1567         return nullptr;
1568 
1569     const SdrObject *pBest  = nullptr,
1570                     *pTop   = nullptr;
1571 
1572     const tools::Long nTmp = bNext ? LONG_MAX : 0;
1573     Point aBestPos( nTmp, nTmp );
1574     Point aTopPos(  nTmp, nTmp );
1575     Point aCurPos;
1576     Point aPos;
1577     bool bNoDraw((GotoObjFlags::DrawAny & eType) == GotoObjFlags::NONE);
1578     bool bNoFly((GotoObjFlags::FlyAny & eType) == GotoObjFlags::NONE);
1579 
1580     if( !bNoFly && bNoDraw )
1581     {
1582         SwFlyFrame *pFly = GetCurrFrame( false )->FindFlyFrame();
1583         if( pFly )
1584             pBest = pFly->GetVirtDrawObj();
1585     }
1586     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1587     SdrPageView* pPV = Imp()->GetDrawView()->GetSdrPageView();
1588 
1589     MarkableObjectsOnly aDefaultFilter( pPV );
1590     if ( !pFilter )
1591         pFilter = &aDefaultFilter;
1592 
1593     if( !pBest || rMrkList.GetMarkCount() == 1 )
1594     {
1595         // Determine starting point
1596         SdrObjList* pList = nullptr;
1597         if ( rMrkList.GetMarkCount() )
1598         {
1599             const SdrObject* pStartObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
1600             if( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>( pStartObj) )
1601                 aPos = pVirtFlyDrawObj->GetFlyFrame()->getFrameArea().Pos();
1602             else
1603                 aPos = pStartObj->GetSnapRect().TopLeft();
1604 
1605             // If an object inside a group is selected, we want to
1606             // iterate over the group members.
1607             if ( ! pStartObj->GetUserCall() )
1608                 pList = pStartObj->getParentSdrObjListFromSdrObject();
1609         }
1610         else
1611         {
1612             // If no object is selected, we check if we just entered a group.
1613             // In this case we want to iterate over the group members.
1614             aPos = GetCharRect().Center();
1615             const SdrObject* pStartObj = pPV ? pPV->GetCurrentGroup() : nullptr;
1616             if ( dynamic_cast<const SdrObjGroup*>( pStartObj) )
1617                 pList = pStartObj->GetSubList();
1618         }
1619 
1620         if ( ! pList )
1621         {
1622             // Here we are if
1623             // A  No object has been selected and no group has been entered or
1624             // B  An object has been selected and it is not inside a group
1625             pList = getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 );
1626         }
1627 
1628         OSL_ENSURE( pList, "No object list to iterate" );
1629 
1630         SdrObjListIter aObjIter( pList, bFlat ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups );
1631         while ( aObjIter.IsMore() )
1632         {
1633             SdrObject* pObj = aObjIter.Next();
1634             SwVirtFlyDrawObj *pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
1635             if( ( bNoFly && pVirtO ) ||
1636                 ( bNoDraw && !pVirtO ) ||
1637                 // Ignore TextBoxes of draw shapes here, so that
1638                 // SwFEShell::SelectObj() won't jump back on this list, meaning
1639                 // we never jump to the next draw shape.
1640                 (pVirtO && pVirtO->IsTextBox()) ||
1641                 ( eType == GotoObjFlags::DrawSimple && lcl_IsControlGroup( pObj ) ) ||
1642                 ( eType == GotoObjFlags::DrawControl && !lcl_IsControlGroup( pObj ) ) ||
1643                 !pFilter->includeObject( *pObj ) )
1644                 continue;
1645             if (pVirtO)
1646             {
1647                 SwFlyFrame *pFly = pVirtO->GetFlyFrame();
1648                 if( GotoObjFlags::FlyAny != ( GotoObjFlags::FlyAny & eType ) )
1649                 {
1650                     switch ( eType )
1651                     {
1652                         case GotoObjFlags::FlyFrame:
1653                             if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
1654                                 continue;
1655                         break;
1656                         case GotoObjFlags::FlyGrf:
1657                             if ( pFly->Lower() &&
1658                                 (!pFly->Lower()->IsNoTextFrame() ||
1659                                  !static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetGrfNode()))
1660                                 continue;
1661                         break;
1662                         case GotoObjFlags::FlyOLE:
1663                             if ( pFly->Lower() &&
1664                                 (!pFly->Lower()->IsNoTextFrame() ||
1665                                  !static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetOLENode()))
1666                                 continue;
1667                         break;
1668                         default: break;
1669                     }
1670                 }
1671                 aCurPos = pFly->getFrameArea().Pos();
1672             }
1673             else
1674                 aCurPos = pObj->GetSnapRect().TopLeft();
1675 
1676             // Special case if another object is on same Y.
1677             if( aCurPos != aPos &&          // only when it is not me
1678                 aCurPos.getY() == aPos.getY() &&  // Y positions equal
1679                 (bNext? (aCurPos.getX() > aPos.getX()) :  // lies next to me
1680                         (aCurPos.getX() < aPos.getX())) ) // " reverse
1681             {
1682                 aBestPos = Point( nTmp, nTmp );
1683                 SdrObjListIter aTmpIter( pList, bFlat ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups );
1684                 while ( aTmpIter.IsMore() )
1685                 {
1686                     SdrObject* pTmpObj = aTmpIter.Next();
1687                     pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pTmpObj);
1688                     if( ( bNoFly && pVirtO ) || ( bNoDraw && !pVirtO ) )
1689                         continue;
1690                     if (pVirtO)
1691                     {
1692                         aCurPos = pVirtO->GetFlyFrame()->getFrameArea().Pos();
1693                     }
1694                     else
1695                         aCurPos = pTmpObj->GetCurrentBoundRect().TopLeft();
1696 
1697                     if( aCurPos != aPos && aCurPos.Y() == aPos.Y() &&
1698                         (bNext? (aCurPos.getX() > aPos.getX()) :  // lies next to me
1699                                 (aCurPos.getX() < aPos.getX())) &&    // " reverse
1700                         (bNext? (aCurPos.getX() < aBestPos.getX()) :  // better as best
1701                                 (aCurPos.getX() > aBestPos.getX())) ) // " reverse
1702                     {
1703                         aBestPos = aCurPos;
1704                         pBest = pTmpObj;
1705                     }
1706                 }
1707                 break;
1708             }
1709 
1710             if( (
1711                 (bNext? (aPos.getY() < aCurPos.getY()) :          // only below me
1712                         (aPos.getY() > aCurPos.getY())) &&        // " reverse
1713                 (bNext? (aBestPos.getY() > aCurPos.getY()) :      // closer below
1714                         (aBestPos.getY() < aCurPos.getY()))
1715                     ) ||    // " reverse
1716                         (aBestPos.getY() == aCurPos.getY() &&
1717                 (bNext? (aBestPos.getX() > aCurPos.getX()) :      // further left
1718                         (aBestPos.getX() < aCurPos.getX()))))     // " reverse
1719 
1720             {
1721                 aBestPos = aCurPos;
1722                 pBest = pObj;
1723             }
1724 
1725             if( (bNext? (aTopPos.getY() > aCurPos.getY()) :       // higher as best
1726                         (aTopPos.getY() < aCurPos.getY())) ||     // " reverse
1727                         (aTopPos.getY() == aCurPos.getY() &&
1728                 (bNext? (aTopPos.getX() > aCurPos.getX()) :       // further left
1729                         (aTopPos.getX() < aCurPos.getX()))))      // " reverse
1730             {
1731                 aTopPos = aCurPos;
1732                 pTop = pObj;
1733             }
1734         }
1735         // unfortunately nothing found
1736         if( bNext ? (aBestPos.getX() == LONG_MAX) : (aBestPos.getX() == 0) )
1737         {
1738             pBest = pTop;
1739             SvxSearchDialogWrapper::SetSearchLabel( bNext ? SearchLabel::EndWrapped : SearchLabel::StartWrapped );
1740         }
1741     }
1742 
1743     return pBest;
1744 }
1745 
GotoObj(bool bNext,GotoObjFlags eType)1746 bool SwFEShell::GotoObj( bool bNext, GotoObjFlags eType )
1747 {
1748     SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
1749 
1750     const SdrObject* pBest = GetBestObject( bNext, eType );
1751 
1752     if ( !pBest )
1753     {
1754         SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
1755         return false;
1756     }
1757 
1758     const SwVirtFlyDrawObj *pVirtO = dynamic_cast<const SwVirtFlyDrawObj*>(pBest);
1759     if (pVirtO)
1760     {
1761         const SwRect& rFrame = pVirtO->GetFlyFrame()->getFrameArea();
1762         SelectObj( rFrame.Pos(), 0, const_cast<SdrObject*>(pBest) );
1763         if( !ActionPend() )
1764             MakeVisible( rFrame );
1765     }
1766     else
1767     {
1768         SelectObj( Point(), 0, const_cast<SdrObject*>(pBest) );
1769         if( !ActionPend() )
1770             MakeVisible( SwRect(pBest->GetCurrentBoundRect()) );
1771     }
1772     CallChgLnk();
1773     return true;
1774 }
1775 
BeginCreate(SdrObjKind eSdrObjectKind,const Point & rPos)1776 bool SwFEShell::BeginCreate( SdrObjKind eSdrObjectKind, const Point &rPos )
1777 {
1778     bool bRet = false;
1779 
1780     if ( !Imp()->HasDrawView() )
1781         Imp()->MakeDrawView();
1782 
1783     if ( GetPageNumber( rPos ) )
1784     {
1785         Imp()->GetDrawView()->SetCurrentObj( eSdrObjectKind );
1786         if ( eSdrObjectKind == OBJ_CAPTION )
1787             bRet = Imp()->GetDrawView()->BegCreateCaptionObj(
1788                         rPos, Size( lMinBorder - MINFLY, lMinBorder - MINFLY ),
1789                         GetOut() );
1790         else
1791             bRet = Imp()->GetDrawView()->BegCreateObj( rPos, GetOut() );
1792     }
1793     if ( bRet )
1794     {
1795         ::FrameNotify( this, FLY_DRAG_START );
1796     }
1797     return bRet;
1798 }
1799 
BeginCreate(SdrObjKind eSdrObjectKind,SdrInventor eObjInventor,const Point & rPos)1800 bool SwFEShell::BeginCreate( SdrObjKind eSdrObjectKind, SdrInventor eObjInventor,
1801                              const Point &rPos )
1802 {
1803     bool bRet = false;
1804 
1805     if ( !Imp()->HasDrawView() )
1806         Imp()->MakeDrawView();
1807 
1808     if ( GetPageNumber( rPos ) )
1809     {
1810         Imp()->GetDrawView()->SetCurrentObj( eSdrObjectKind, eObjInventor );
1811         bRet = Imp()->GetDrawView()->BegCreateObj( rPos, GetOut() );
1812     }
1813     if ( bRet )
1814         ::FrameNotify( this, FLY_DRAG_START );
1815     return bRet;
1816 }
1817 
MoveCreate(const Point & rPos)1818 void SwFEShell::MoveCreate( const Point &rPos )
1819 {
1820     OSL_ENSURE( Imp()->HasDrawView(), "MoveCreate without DrawView?" );
1821     if ( GetPageNumber( rPos ) )
1822     {
1823         ScrollTo( rPos );
1824         Imp()->GetDrawView()->MovCreateObj( rPos );
1825         ::FrameNotify( this );
1826     }
1827 }
1828 
EndCreate(SdrCreateCmd eSdrCreateCmd)1829 bool SwFEShell::EndCreate( SdrCreateCmd eSdrCreateCmd )
1830 {
1831     // To assure undo-object from the DrawEngine is not stored,
1832     // (we create our own undo-object!), temporarily switch-off Undo
1833     OSL_ENSURE( Imp()->HasDrawView(), "EndCreate without DrawView?" );
1834     if( !Imp()->GetDrawView()->IsGroupEntered() )
1835     {
1836         GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
1837     }
1838     bool bCreate = Imp()->GetDrawView()->EndCreateObj( eSdrCreateCmd );
1839     GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
1840 
1841     if ( !bCreate )
1842     {
1843         ::FrameNotify( this, FLY_DRAG_END );
1844         return false;
1845     }
1846 
1847     if ( eSdrCreateCmd == SdrCreateCmd::NextPoint )
1848     {
1849         ::FrameNotify( this );
1850         return true;
1851     }
1852     return ImpEndCreate();
1853 }
1854 
ImpEndCreate()1855 bool SwFEShell::ImpEndCreate()
1856 {
1857     OSL_ENSURE( Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1,
1858             "New object not selected." );
1859 
1860     SdrObject& rSdrObj = *Imp()->GetDrawView()->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
1861 
1862     if( rSdrObj.GetSnapRect().IsEmpty() )
1863     {
1864         // preferably we forget the object, only gives problems
1865         Imp()->GetDrawView()->DeleteMarked();
1866         Imp()->GetDrawView()->UnmarkAll();
1867         ::FrameNotify( this, FLY_DRAG_END );
1868         return false;
1869     }
1870 
1871     if( rSdrObj.getParentSdrObjectFromSdrObject() )
1872     {
1873         Point aTmpPos( rSdrObj.GetSnapRect().TopLeft() );
1874         Point aNewAnchor( rSdrObj.getParentSdrObjectFromSdrObject()->GetAnchorPos() );
1875         // OD 2004-04-05 #i26791# - direct object positioning for group members
1876         rSdrObj.NbcSetRelativePos( aTmpPos - aNewAnchor );
1877         rSdrObj.NbcSetAnchorPos( aNewAnchor );
1878         ::FrameNotify( this );
1879         return true;
1880     }
1881 
1882     LockPaint();
1883     StartAllAction();
1884 
1885     Imp()->GetDrawView()->UnmarkAll();
1886 
1887     const tools::Rectangle &rBound = rSdrObj.GetSnapRect();
1888     Point aPt( rBound.TopRight() );
1889 
1890     // alien identifier should end up on defaults
1891     // duplications possible!!
1892     sal_uInt16 nIdent = SdrInventor::Default == rSdrObj.GetObjInventor()
1893                         ? rSdrObj.GetObjIdentifier()
1894                         : 0xFFFF;
1895 
1896     // default for controls character bound, otherwise paragraph bound.
1897     SwFormatAnchor aAnch;
1898     const SwFrame *pAnch = nullptr;
1899     bool bCharBound = false;
1900     if( dynamic_cast<const SdrUnoObj*>( &rSdrObj) !=  nullptr )
1901     {
1902         SwPosition aPos( GetDoc()->GetNodes() );
1903         SwCursorMoveState aState( CursorMoveState::SetOnlyText );
1904         Point aPoint( aPt.getX(), aPt.getY() + rBound.GetHeight()/2 );
1905         GetLayout()->GetModelPositionForViewPoint( &aPos, aPoint, &aState );
1906 
1907         // characterbinding not allowed in readonly-content
1908         if( !aPos.nNode.GetNode().IsProtect() )
1909         {
1910             std::pair<Point, bool> const tmp(aPoint, true);
1911             pAnch = aPos.nNode.GetNode().GetContentNode()->getLayoutFrame(GetLayout(), &aPos, &tmp);
1912             SwRect aTmp;
1913             pAnch->GetCharRect( aTmp, aPos );
1914 
1915             // The crsr should not be too far away
1916             bCharBound = true;
1917             tools::Rectangle aRect( aTmp.SVRect() );
1918             aRect.AdjustLeft( -(MM50*2) );
1919             aRect.AdjustTop( -(MM50*2) );
1920             aRect.AdjustRight(MM50*2 );
1921             aRect.AdjustBottom(MM50*2 );
1922 
1923             if( !aRect.IsOver( rBound ) && !::GetHtmlMode( GetDoc()->GetDocShell() ))
1924                 bCharBound = false;
1925 
1926             // anchor in header/footer also not allowed.
1927             if( bCharBound )
1928                 bCharBound = !GetDoc()->IsInHeaderFooter( aPos.nNode );
1929 
1930             if( bCharBound )
1931             {
1932                 aAnch.SetType( RndStdIds::FLY_AS_CHAR );
1933                 aAnch.SetAnchor( &aPos );
1934             }
1935         }
1936     }
1937 
1938     if( !bCharBound )
1939     {
1940         // allow native drawing objects in header/footer.
1941         // Thus, set <bBodyOnly> to <false> for these objects using value
1942         // of <nIdent> - value <0xFFFF> indicates control objects, which aren't
1943         // allowed in header/footer.
1944         //bool bBodyOnly = OBJ_NONE != nIdent;
1945         bool bBodyOnly = 0xFFFF == nIdent;
1946         bool bAtPage = false;
1947         const SwFrame* pPage = nullptr;
1948         SwCursorMoveState aState( CursorMoveState::SetOnlyText );
1949         Point aPoint( aPt );
1950         SwPosition aPos( GetDoc()->GetNodes() );
1951         GetLayout()->GetModelPositionForViewPoint( &aPos, aPoint, &aState );
1952 
1953         // do not set in ReadnOnly-content
1954         if (aPos.nNode.GetNode().IsProtect())
1955         {
1956             // then only page bound. Or should we
1957             // search the next not-readonly position?
1958             bAtPage = true;
1959         }
1960 
1961         SwContentNode* pCNode = aPos.nNode.GetNode().GetContentNode();
1962         std::pair<Point, bool> const tmp(aPoint, false);
1963         pAnch = pCNode ? pCNode->getLayoutFrame(GetLayout(), nullptr, &tmp) : nullptr;
1964         if (!pAnch)
1965         {
1966             // Hidden content. Anchor to the page instead
1967             bAtPage = true;
1968         }
1969 
1970         if( !bAtPage )
1971         {
1972             const SwFlyFrame *pTmp = pAnch->FindFlyFrame();
1973             if( pTmp )
1974             {
1975                 const SwFrame* pTmpFrame = pAnch;
1976                 SwRect aBound( rBound );
1977                 while( pTmp )
1978                 {
1979                     if( pTmp->getFrameArea().IsInside( aBound ) )
1980                     {
1981                         if( !bBodyOnly || !pTmp->FindFooterOrHeader() )
1982                             pPage = pTmpFrame;
1983                         break;
1984                     }
1985                     pTmp = pTmp->GetAnchorFrame()
1986                                 ? pTmp->GetAnchorFrame()->FindFlyFrame()
1987                                 : nullptr;
1988                     pTmpFrame = pTmp;
1989                 }
1990             }
1991 
1992             if( !pPage )
1993                 pPage = pAnch->FindPageFrame();
1994 
1995             // Always via FindAnchor, to assure the frame will be bound
1996             // to the previous. With GetCrsOfst we can also reach the next. THIS IS WRONG.
1997             pAnch = ::FindAnchor( pPage, aPt, bBodyOnly );
1998             if (pAnch->IsTextFrame())
1999             {
2000                 std::pair<SwTextNode const*, sal_Int32> const pos(
2001                     static_cast<SwTextFrame const*>(pAnch)->MapViewToModel(TextFrameIndex(0)));
2002                 aPos.nNode = *pos.first;
2003             }
2004             else
2005             {
2006                 aPos.nNode = *static_cast<const SwNoTextFrame*>(pAnch)->GetNode();
2007             }
2008 
2009             // do not set in ReadnOnly-content
2010             if( aPos.nNode.GetNode().IsProtect() )
2011                 // then only page bound. Or should we
2012                 // search the next not-readonly position?
2013                 bAtPage = true;
2014             else
2015             {
2016                 aAnch.SetType( RndStdIds::FLY_AT_PARA );
2017                 aAnch.SetAnchor( &aPos );
2018             }
2019         }
2020 
2021         if( bAtPage )
2022         {
2023             pPage = pAnch ? pAnch->FindPageFrame() : GetLayout()->GetPageAtPos(aPoint);
2024 
2025             aAnch.SetType( RndStdIds::FLY_AT_PAGE );
2026             aAnch.SetPageNum( pPage->GetPhyPageNum() );
2027             pAnch = pPage;      // page becomes an anchor
2028         }
2029     }
2030 
2031     SfxItemSet aSet( GetDoc()->GetAttrPool(), svl::Items<RES_FRM_SIZE, RES_FRM_SIZE,
2032                                             RES_SURROUND, RES_ANCHOR>{} );
2033     aSet.Put( aAnch );
2034 
2035     // OD 2004-03-30 #i26791# - determine relative object position
2036     SwTwips nXOffset;
2037     SwTwips nYOffset = rBound.Top() - pAnch->getFrameArea().Top();
2038     {
2039         if( pAnch->IsVertical() )
2040         {
2041             nXOffset = nYOffset;
2042             nYOffset = pAnch->getFrameArea().Left()+pAnch->getFrameArea().Width()-rBound.Right();
2043         }
2044         else if( pAnch->IsRightToLeft() )
2045             nXOffset = pAnch->getFrameArea().Left()+pAnch->getFrameArea().Width()-rBound.Right();
2046         else
2047             nXOffset = rBound.Left() - pAnch->getFrameArea().Left();
2048         if (pAnch->IsTextFrame())
2049         {
2050             const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnch);
2051             if (pTmp->IsFollow())
2052             {
2053                 do {
2054                     pTmp = pTmp->FindMaster();
2055                     OSL_ENSURE(pTmp, "Where's my Master?");
2056                     // OD 2004-03-30 #i26791# - correction: add frame area height
2057                     // of master frames.
2058                     nYOffset += pTmp->IsVertical() ?
2059                                 pTmp->getFrameArea().Width() : pTmp->getFrameArea().Height();
2060                 } while (pTmp->IsFollow());
2061             }
2062 
2063             nYOffset -= pTmp->GetBaseVertOffsetForFly(false);
2064         }
2065     }
2066 
2067     if( OBJ_NONE == nIdent )
2068     {
2069         // For OBJ_NONE a fly is inserted.
2070         const tools::Long nWidth = rBound.Right()  - rBound.Left();
2071         const tools::Long nHeight= rBound.Bottom() - rBound.Top();
2072         aSet.Put( SwFormatFrameSize( SwFrameSize::Minimum, std::max( nWidth,  tools::Long(MINFLY) ),
2073                                               std::max( nHeight, tools::Long(MINFLY) )));
2074 
2075         SwFormatHoriOrient aHori( nXOffset, text::HoriOrientation::NONE, text::RelOrientation::FRAME );
2076         SwFormatVertOrient aVert( nYOffset, text::VertOrientation::NONE, text::RelOrientation::FRAME );
2077         aSet.Put( SwFormatSurround( css::text::WrapTextMode_PARALLEL ) );
2078         aSet.Put( aHori );
2079         aSet.Put( aVert );
2080 
2081         // Quickly store the square
2082         const SwRect aFlyRect( rBound );
2083 
2084         // Throw away generated object, now the fly can nicely
2085         // via the available SS be generated.
2086         GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false); // see above
2087         // #i52858# - method name changed
2088         SdrPage *pPg = getIDocumentDrawModelAccess().GetOrCreateDrawModel()->GetPage( 0 );
2089         if( !pPg )
2090         {
2091             SdrModel* pTmpSdrModel = getIDocumentDrawModelAccess().GetDrawModel();
2092             auto pNewPage = pTmpSdrModel->AllocPage( false );
2093             pTmpSdrModel->InsertPage( pNewPage.get() );
2094             pPg = pNewPage.get();
2095         }
2096         pPg->RecalcObjOrdNums();
2097         SdrObject* pRemovedObject = pPg->RemoveObject( rSdrObj.GetOrdNumDirect() );
2098         SdrObject::Free( pRemovedObject );
2099         GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
2100 
2101         SwFlyFrame* pFlyFrame;
2102         if( NewFlyFrame( aSet, true ) &&
2103             ::GetHtmlMode( GetDoc()->GetDocShell() ) &&
2104             nullptr != ( pFlyFrame = GetSelectedFlyFrame() ))
2105         {
2106             SfxItemSet aHtmlSet( GetDoc()->GetAttrPool(), svl::Items<RES_VERT_ORIENT, RES_HORI_ORIENT>{} );
2107             // horizontal orientation:
2108             const bool bLeftFrame = aFlyRect.Left() <
2109                                       pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Left(),
2110                            bLeftPrt = aFlyRect.Left() + aFlyRect.Width() <
2111                                       pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width()/2;
2112             if( bLeftFrame || bLeftPrt )
2113             {
2114                 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
2115                 aHori.SetRelationOrient( bLeftFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
2116             }
2117             else
2118             {
2119                 const bool bRightFrame = aFlyRect.Left() >
2120                                            pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width();
2121                 aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
2122                 aHori.SetRelationOrient( bRightFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
2123             }
2124             aHtmlSet.Put( aHori );
2125             aVert.SetVertOrient( text::VertOrientation::TOP );
2126             aVert.SetRelationOrient( text::RelOrientation::PRINT_AREA );
2127             aHtmlSet.Put( aVert );
2128 
2129             GetDoc()->SetAttr( aHtmlSet, *pFlyFrame->GetFormat() );
2130         }
2131     }
2132     else
2133     {
2134         if (rSdrObj.GetName().isEmpty())
2135         {
2136             bool bRestore = GetDoc()->GetIDocumentUndoRedo().DoesDrawUndo();
2137             GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
2138             rSdrObj.MakeNameUnique();
2139             GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(bRestore);
2140         }
2141 
2142         aSet.Put( aAnch );
2143         aSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) );
2144         // OD 2004-03-30 #i26791# - set horizontal position
2145         SwFormatHoriOrient aHori( nXOffset, text::HoriOrientation::NONE, text::RelOrientation::FRAME );
2146         aSet.Put( aHori );
2147         // OD 2004-03-30 #i26791# - set vertical position
2148         if( pAnch->IsTextFrame() && static_cast<const SwTextFrame*>(pAnch)->IsFollow() )
2149         {
2150             const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnch);
2151             do {
2152                 pTmp = pTmp->FindMaster();
2153                 assert(pTmp && "Where's my Master?");
2154                 nYOffset += pTmp->IsVertical() ?
2155                             pTmp->getFramePrintArea().Width() : pTmp->getFramePrintArea().Height();
2156             } while ( pTmp->IsFollow() );
2157         }
2158         SwFormatVertOrient aVert( nYOffset, text::VertOrientation::NONE, text::RelOrientation::FRAME );
2159         aSet.Put( aVert );
2160         SwDrawFrameFormat* pFormat = static_cast<SwDrawFrameFormat*>(getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::DRAW_OBJECT, &aSet ));
2161         // #i36010# - set layout direction of the position
2162         pFormat->SetPositionLayoutDir(
2163             text::PositionLayoutDir::PositionInLayoutDirOfAnchor );
2164         // #i44344#, #i44681# - positioning attributes already set
2165         pFormat->PosAttrSet();
2166         pFormat->SetName(rSdrObj.GetName());
2167 
2168         SwDrawContact *pContact = new SwDrawContact( pFormat, &rSdrObj );
2169         // #i35635#
2170         pContact->MoveObjToVisibleLayer( &rSdrObj );
2171         if( bCharBound )
2172         {
2173             OSL_ENSURE( aAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR, "wrong AnchorType" );
2174             SwTextNode *pNd = aAnch.GetContentAnchor()->nNode.GetNode().GetTextNode();
2175             SwFormatFlyCnt aFormat( pFormat );
2176             pNd->InsertItem(aFormat,
2177                             aAnch.GetContentAnchor()->nContent.GetIndex(), 0 );
2178             SwFormatVertOrient aVertical( pFormat->GetVertOrient() );
2179             aVertical.SetVertOrient( text::VertOrientation::LINE_CENTER );
2180             pFormat->SetFormatAttr( aVertical );
2181         }
2182         if( pAnch->IsTextFrame() && static_cast<const SwTextFrame*>(pAnch)->IsFollow() )
2183         {
2184             const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnch);
2185             do {
2186                 pTmp = pTmp->FindMaster();
2187                 OSL_ENSURE( pTmp, "Where's my Master?" );
2188             } while( pTmp->IsFollow() );
2189             pAnch = pTmp;
2190         }
2191 
2192         pContact->ConnectToLayout();
2193 
2194         // mark object at frame the object is inserted at.
2195         {
2196             SdrObject* pMarkObj = pContact->GetDrawObjectByAnchorFrame( *pAnch );
2197             if ( pMarkObj )
2198             {
2199                 Imp()->GetDrawView()->MarkObj( pMarkObj, Imp()->GetPageView() );
2200             }
2201             else
2202             {
2203                 Imp()->GetDrawView()->MarkObj( &rSdrObj, Imp()->GetPageView() );
2204             }
2205         }
2206     }
2207 
2208     GetDoc()->getIDocumentState().SetModified();
2209 
2210     KillPams();
2211     EndAllActionAndCall();
2212     UnlockPaint();
2213     return true;
2214 }
2215 
BreakCreate()2216 void SwFEShell::BreakCreate()
2217 {
2218     OSL_ENSURE( Imp()->HasDrawView(), "BreakCreate without DrawView?" );
2219     Imp()->GetDrawView()->BrkCreateObj();
2220     ::FrameNotify( this, FLY_DRAG_END );
2221 }
2222 
IsDrawCreate() const2223 bool SwFEShell::IsDrawCreate() const
2224 {
2225     return Imp()->HasDrawView() && Imp()->GetDrawView()->IsCreateObj();
2226 }
2227 
BeginMark(const Point & rPos)2228 bool SwFEShell::BeginMark( const Point &rPos )
2229 {
2230     if ( !Imp()->HasDrawView() )
2231         Imp()->MakeDrawView();
2232 
2233     if ( GetPageNumber( rPos ) )
2234     {
2235         SwDrawView* pDView = Imp()->GetDrawView();
2236 
2237         if (pDView->HasMarkablePoints())
2238             return pDView->BegMarkPoints( rPos );
2239         else
2240         {
2241             pDView->BegMarkObj( rPos );
2242             return true;
2243         }
2244     }
2245     else
2246         return false;
2247 }
2248 
MoveMark(const Point & rPos)2249 void SwFEShell::MoveMark( const Point &rPos )
2250 {
2251     OSL_ENSURE( Imp()->HasDrawView(), "MoveMark without DrawView?" );
2252 
2253     if ( GetPageNumber( rPos ) )
2254     {
2255         ScrollTo( rPos );
2256         SwDrawView* pDView = Imp()->GetDrawView();
2257 
2258         if (pDView->IsInsObjPoint())
2259             pDView->MovInsObjPoint( rPos );
2260         else if (pDView->IsMarkPoints())
2261             pDView->MovMarkPoints( rPos );
2262         else
2263             pDView->MovAction( rPos );
2264     }
2265 }
2266 
EndMark()2267 bool SwFEShell::EndMark()
2268 {
2269     bool bRet = false;
2270     OSL_ENSURE( Imp()->HasDrawView(), "EndMark without DrawView?" );
2271 
2272     if (Imp()->GetDrawView()->IsMarkObj())
2273     {
2274         bRet = Imp()->GetDrawView()->EndMarkObj();
2275 
2276         if ( bRet )
2277         {
2278             bool bShowHdl = false;
2279             SwDrawView* pDView = Imp()->GetDrawView();
2280             // frames are not selected this way, except when
2281             // it is only one frame
2282             SdrMarkList &rMrkList = const_cast<SdrMarkList&>(pDView->GetMarkedObjectList());
2283             SwFlyFrame* pOldSelFly = ::GetFlyFromMarked( &rMrkList, this );
2284 
2285             if ( rMrkList.GetMarkCount() > 1 )
2286                 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2287                 {
2288                     SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2289                     if( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) !=  nullptr )
2290                     {
2291                         if ( !bShowHdl )
2292                         {
2293                             bShowHdl = true;
2294                         }
2295                         rMrkList.DeleteMark( i );
2296                         --i;    // no exceptions
2297                     }
2298                 }
2299 
2300             if( bShowHdl )
2301             {
2302                 pDView->MarkListHasChanged();
2303                 pDView->AdjustMarkHdl();
2304             }
2305 
2306             if ( rMrkList.GetMarkCount() )
2307                 ::lcl_GrabCursor(this, pOldSelFly);
2308             else
2309                 bRet = false;
2310         }
2311         if ( bRet )
2312             ::FrameNotify( this, FLY_DRAG_START );
2313     }
2314     else
2315     {
2316         if (Imp()->GetDrawView()->IsMarkPoints())
2317             bRet = Imp()->GetDrawView()->EndMarkPoints();
2318     }
2319 
2320     SetChainMarker();
2321     return bRet;
2322 }
2323 
GetAnchorId() const2324 RndStdIds SwFEShell::GetAnchorId() const
2325 {
2326     RndStdIds nRet = RndStdIds(SHRT_MAX);
2327     if ( Imp()->HasDrawView() )
2328     {
2329         const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2330         for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2331         {
2332             SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2333             if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) != nullptr )
2334             {
2335                 nRet = RndStdIds::UNKNOWN;
2336                 break;
2337             }
2338             SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
2339             RndStdIds nId = pContact->GetFormat()->GetAnchor().GetAnchorId();
2340             if ( nRet == RndStdIds(SHRT_MAX) )
2341                 nRet = nId;
2342             else if ( nRet != nId )
2343             {
2344                 nRet = RndStdIds::UNKNOWN;
2345                 break;
2346             }
2347         }
2348     }
2349     if ( nRet == RndStdIds(SHRT_MAX) )
2350         nRet = RndStdIds::UNKNOWN;
2351     return nRet;
2352 }
2353 
ChgAnchor(RndStdIds eAnchorId,bool bSameOnly,bool bPosCorr)2354 void SwFEShell::ChgAnchor( RndStdIds eAnchorId, bool bSameOnly, bool bPosCorr )
2355 {
2356     OSL_ENSURE( Imp()->HasDrawView(), "ChgAnchor without DrawView?" );
2357     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2358     if( rMrkList.GetMarkCount() &&
2359         !rMrkList.GetMark( 0 )->GetMarkedSdrObj()->getParentSdrObjectFromSdrObject() )
2360     {
2361         StartAllAction();
2362 
2363         if( GetDoc()->ChgAnchor( rMrkList, eAnchorId, bSameOnly, bPosCorr ))
2364             Imp()->GetDrawView()->UnmarkAll();
2365 
2366         EndAllAction();
2367 
2368         ::FrameNotify( this );
2369     }
2370 }
2371 
DelSelectedObj()2372 void SwFEShell::DelSelectedObj()
2373 {
2374     OSL_ENSURE( Imp()->HasDrawView(), "DelSelectedObj(), no DrawView available" );
2375     if ( Imp()->HasDrawView() )
2376     {
2377         StartAllAction();
2378         Imp()->GetDrawView()->DeleteMarked();
2379         EndAllAction();
2380         ::FrameNotify( this, FLY_DRAG_END );
2381     }
2382 }
2383 
2384 // For the statusline to request the current conditions
GetObjSize() const2385 Size SwFEShell::GetObjSize() const
2386 {
2387     tools::Rectangle aRect;
2388     if ( Imp()->HasDrawView() )
2389     {
2390         if ( Imp()->GetDrawView()->IsAction() )
2391             Imp()->GetDrawView()->TakeActionRect( aRect );
2392         else
2393             aRect = Imp()->GetDrawView()->GetAllMarkedRect();
2394     }
2395     return aRect.GetSize();
2396 }
2397 
GetAnchorObjDiff() const2398 Point SwFEShell::GetAnchorObjDiff() const
2399 {
2400     const SdrView *pView = Imp()->GetDrawView();
2401     OSL_ENSURE( pView, "GetAnchorObjDiff without DrawView?" );
2402 
2403     tools::Rectangle aRect;
2404     if ( Imp()->GetDrawView()->IsAction() )
2405         Imp()->GetDrawView()->TakeActionRect( aRect );
2406     else
2407         aRect = Imp()->GetDrawView()->GetAllMarkedRect();
2408 
2409     Point aRet( aRect.TopLeft() );
2410 
2411     if ( IsFrameSelected() )
2412     {
2413         SwFlyFrame *pFly = GetSelectedFlyFrame();
2414         aRet -= pFly->GetAnchorFrame()->getFrameArea().Pos();
2415     }
2416     else
2417     {
2418         const SdrObject *pObj = pView->GetMarkedObjectList().GetMarkCount() == 1 ?
2419                                 pView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj() : nullptr;
2420         if ( pObj )
2421             aRet -= pObj->GetAnchorPos();
2422     }
2423 
2424     return aRet;
2425 }
2426 
GetObjAbsPos() const2427 Point SwFEShell::GetObjAbsPos() const
2428 {
2429     OSL_ENSURE( Imp()->GetDrawView(), "GetObjAbsPos() without DrawView?" );
2430     return Imp()->GetDrawView()->GetDragStat().GetActionRect().TopLeft();
2431 }
2432 
IsGroupSelected()2433 bool SwFEShell::IsGroupSelected()
2434 {
2435     if ( IsObjSelected() )
2436     {
2437         const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2438         for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2439         {
2440             SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2441             // consider 'virtual' drawing objects.
2442             // Thus, use corresponding method instead of checking type.
2443             if ( pObj->IsGroupObject() &&
2444                  // --> #i38505# No ungroup allowed for 3d objects
2445                  !pObj->Is3DObj() &&
2446                  RndStdIds::FLY_AS_CHAR != static_cast<SwDrawContact*>(GetUserCall(pObj))->
2447                                       GetFormat()->GetAnchor().GetAnchorId() )
2448             {
2449                 return true;
2450             }
2451         }
2452     }
2453     return false;
2454 }
2455 
2456 namespace
2457 {
HasSuitableGroupingAnchor(const SdrObject * pObj)2458     bool HasSuitableGroupingAnchor(const SdrObject* pObj)
2459     {
2460         bool bSuitable = true;
2461         SwFrameFormat* pFrameFormat(::FindFrameFormat(const_cast<SdrObject*>(pObj)));
2462         if (!pFrameFormat)
2463         {
2464             OSL_FAIL( "<HasSuitableGroupingAnchor> - missing frame format" );
2465             bSuitable = false;
2466         }
2467         else if (RndStdIds::FLY_AS_CHAR == pFrameFormat->GetAnchor().GetAnchorId())
2468         {
2469             bSuitable = false;
2470         }
2471         return bSuitable;
2472     }
2473 }
2474 
2475 // Change return type.
2476 // Adjustments for drawing objects in header/footer:
2477 //      allow group, only if all selected objects are in the same header/footer
2478 //      or not in header/footer.
IsGroupAllowed() const2479 bool SwFEShell::IsGroupAllowed() const
2480 {
2481     bool bIsGroupAllowed = false;
2482     if ( IsObjSelected() > 1 )
2483     {
2484         bIsGroupAllowed = true;
2485         const SdrObject* pUpGroup = nullptr;
2486         const SwFrame* pHeaderFooterFrame = nullptr;
2487         const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2488         for ( size_t i = 0; bIsGroupAllowed && i < rMrkList.GetMarkCount(); ++i )
2489         {
2490             const SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2491             if ( i )
2492                 bIsGroupAllowed = pObj->getParentSdrObjectFromSdrObject() == pUpGroup;
2493             else
2494                 pUpGroup = pObj->getParentSdrObjectFromSdrObject();
2495 
2496             if ( bIsGroupAllowed )
2497                 bIsGroupAllowed = HasSuitableGroupingAnchor(pObj);
2498 
2499             // check, if all selected objects are in the
2500             // same header/footer or not in header/footer.
2501             if ( bIsGroupAllowed )
2502             {
2503                 const SwFrame* pAnchorFrame = nullptr;
2504                 if ( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>( pObj) )
2505                 {
2506                     const SwFlyFrame* pFlyFrame = pVirtFlyDrawObj->GetFlyFrame();
2507                     if ( pFlyFrame )
2508                     {
2509                         pAnchorFrame = pFlyFrame->GetAnchorFrame();
2510                     }
2511                 }
2512                 else
2513                 {
2514                     SwDrawContact* pDrawContact = static_cast<SwDrawContact*>(GetUserCall( pObj ));
2515                     if ( pDrawContact )
2516                     {
2517                         pAnchorFrame = pDrawContact->GetAnchorFrame( pObj );
2518                     }
2519                 }
2520                 if ( pAnchorFrame )
2521                 {
2522                     if ( i )
2523                     {
2524                         bIsGroupAllowed =
2525                             ( pAnchorFrame->FindFooterOrHeader() == pHeaderFooterFrame );
2526                     }
2527                     else
2528                     {
2529                         pHeaderFooterFrame = pAnchorFrame->FindFooterOrHeader();
2530                     }
2531                 }
2532             }
2533         }
2534     }
2535 
2536     return bIsGroupAllowed;
2537 }
2538 
IsUnGroupAllowed() const2539 bool SwFEShell::IsUnGroupAllowed() const
2540 {
2541     bool bIsUnGroupAllowed = false;
2542 
2543     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2544     for (size_t i = 0; i < rMrkList.GetMarkCount(); ++i)
2545     {
2546         const SdrObject* pObj = rMrkList.GetMark(i)->GetMarkedSdrObj();
2547         bIsUnGroupAllowed = HasSuitableGroupingAnchor(pObj);
2548         if (!bIsUnGroupAllowed)
2549             break;
2550     }
2551 
2552     return bIsUnGroupAllowed;
2553 }
2554 
2555 // The group gets the anchor and the contactobject of the first in the selection
GroupSelection()2556 void SwFEShell::GroupSelection()
2557 {
2558     if ( IsGroupAllowed() )
2559     {
2560         StartAllAction();
2561         StartUndo( SwUndoId::START );
2562 
2563         GetDoc()->GroupSelection( *Imp()->GetDrawView() );
2564 
2565         EndUndo( SwUndoId::END );
2566         EndAllAction();
2567     }
2568 }
2569 
2570 // The individual objects get a copy of the anchor and the contactobject of the group
UnGroupSelection()2571 void SwFEShell::UnGroupSelection()
2572 {
2573     if ( IsGroupSelected() )
2574     {
2575         StartAllAction();
2576         StartUndo( SwUndoId::START );
2577 
2578         GetDoc()->UnGroupSelection( *Imp()->GetDrawView() );
2579 
2580         EndUndo( SwUndoId::END );
2581         EndAllAction();
2582     }
2583 }
2584 
MirrorSelection(bool bHorizontal)2585 void SwFEShell::MirrorSelection( bool bHorizontal )
2586 {
2587     SdrView *pView = Imp()->GetDrawView();
2588     if ( IsObjSelected() && pView->IsMirrorAllowed() )
2589     {
2590         if ( bHorizontal )
2591             pView->MirrorAllMarkedHorizontal();
2592         else
2593             pView->MirrorAllMarkedVertical();
2594     }
2595 }
2596 
2597 // jump to named frame (Graphic/OLE)
2598 
GotoFly(const OUString & rName,FlyCntType eType,bool bSelFrame)2599 bool SwFEShell::GotoFly( const OUString& rName, FlyCntType eType, bool bSelFrame )
2600 {
2601     bool bRet = false;
2602     static SwNodeType const aChkArr[ 4 ] = {
2603              /* FLYCNTTYPE_ALL */   SwNodeType::NONE,
2604              /* FLYCNTTYPE_FRM */   SwNodeType::Text,
2605              /* FLYCNTTYPE_GRF */   SwNodeType::Grf,
2606              /* FLYCNTTYPE_OLE */   SwNodeType::Ole
2607             };
2608 
2609     const SwFlyFrameFormat* pFlyFormat = mxDoc->FindFlyByName( rName, aChkArr[ eType]);
2610     if( pFlyFormat )
2611     {
2612         CurrShell aCurr( this );
2613 
2614         SwFlyFrame* pFrame = SwIterator<SwFlyFrame,SwFormat>( *pFlyFormat ).First();
2615         if( pFrame )
2616         {
2617             if( bSelFrame )
2618             {
2619                 // first make visible, to get a11y events in proper order
2620                 if (!ActionPend())
2621                     MakeVisible( pFrame->getFrameArea() );
2622                 SelectObj( pFrame->getFrameArea().Pos(), 0, pFrame->GetVirtDrawObj() );
2623             }
2624             else
2625             {
2626                 SwContentFrame *pCFrame = pFrame->ContainsContent();
2627                 if ( pCFrame )
2628                 {
2629                     ClearMark();
2630                     SwPaM* pCursor = GetCursor();
2631 
2632                     if (pCFrame->IsTextFrame())
2633                     {
2634                         *pCursor->GetPoint() = static_cast<SwTextFrame *>(pCFrame)
2635                             ->MapViewToModelPos(TextFrameIndex(0));
2636                     }
2637                     else
2638                     {
2639                         assert(pCFrame->IsNoTextFrame());
2640                         SwContentNode *const pCNode = static_cast<SwNoTextFrame *>(pCFrame)->GetNode();
2641 
2642                         pCursor->GetPoint()->nNode = *pCNode;
2643                         pCursor->GetPoint()->nContent.Assign( pCNode, 0 );
2644                     }
2645 
2646                     SwRect& rChrRect = const_cast<SwRect&>(GetCharRect());
2647                     rChrRect = pFrame->getFramePrintArea();
2648                     rChrRect.Pos() += pFrame->getFrameArea().Pos();
2649                     GetCursorDocPos() = rChrRect.Pos();
2650                 }
2651             }
2652             bRet = true;
2653         }
2654     }
2655     return bRet;
2656 }
2657 
GetFlyCount(FlyCntType eType,bool bIgnoreTextBoxes) const2658 size_t SwFEShell::GetFlyCount( FlyCntType eType, bool bIgnoreTextBoxes ) const
2659 {
2660     return GetDoc()->GetFlyCount(eType, bIgnoreTextBoxes);
2661 }
2662 
GetFlyNum(size_t nIdx,FlyCntType eType,bool bIgnoreTextBoxes) const2663 const SwFrameFormat*  SwFEShell::GetFlyNum(size_t nIdx, FlyCntType eType, bool bIgnoreTextBoxes ) const
2664 {
2665     return GetDoc()->GetFlyNum(nIdx, eType, bIgnoreTextBoxes);
2666 }
2667 
GetFlyFrameFormats(FlyCntType const eType,bool const bIgnoreTextBoxes)2668 std::vector<SwFrameFormat const*> SwFEShell::GetFlyFrameFormats(
2669         FlyCntType const eType, bool const bIgnoreTextBoxes)
2670 {
2671     return GetDoc()->GetFlyFrameFormats(eType, bIgnoreTextBoxes);
2672 }
2673 
2674 // show the current selected object
MakeSelVisible()2675 void SwFEShell::MakeSelVisible()
2676 {
2677     if ( Imp()->HasDrawView() &&
2678          Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() )
2679     {
2680         GetCurrFrame(); // just to trigger formatting in case the selected object is not formatted.
2681         MakeVisible( SwRect(Imp()->GetDrawView()->GetAllMarkedRect()) );
2682     }
2683     else
2684         SwCursorShell::MakeSelVisible();
2685 }
2686 
2687 // how is the selected object protected?
IsSelObjProtected(FlyProtectFlags eType) const2688 FlyProtectFlags SwFEShell::IsSelObjProtected( FlyProtectFlags eType ) const
2689 {
2690     FlyProtectFlags nChk = FlyProtectFlags::NONE;
2691     const bool bParent(eType & FlyProtectFlags::Parent);
2692     if( Imp()->HasDrawView() )
2693     {
2694         const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2695         for( size_t i = rMrkList.GetMarkCount(); i; )
2696         {
2697             SdrObject *pObj = rMrkList.GetMark( --i )->GetMarkedSdrObj();
2698             if( !bParent )
2699             {
2700                 nChk |= ( pObj->IsMoveProtect() ? FlyProtectFlags::Pos : FlyProtectFlags::NONE ) |
2701                         ( pObj->IsResizeProtect()? FlyProtectFlags::Size : FlyProtectFlags::NONE );
2702 
2703                 if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
2704                 {
2705                     SwFlyFrame *pFly = pVirtO->GetFlyFrame();
2706                     if ( (FlyProtectFlags::Content & eType) && pFly->GetFormat()->GetProtect().IsContentProtected() )
2707                         nChk |= FlyProtectFlags::Content;
2708 
2709                     if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
2710                     {
2711                         SwOLENode *pNd = static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetOLENode();
2712                         uno::Reference < embed::XEmbeddedObject > xObj( pNd ? pNd->GetOLEObj().GetOleRef() : nullptr );
2713                         if ( xObj.is() )
2714                         {
2715                             // TODO/LATER: use correct aspect
2716                             const bool bNeverResize = (embed::EmbedMisc::EMBED_NEVERRESIZE & xObj->getStatus( embed::Aspects::MSOLE_CONTENT ));
2717                             if ( ( (FlyProtectFlags::Content & eType) || (FlyProtectFlags::Size & eType) ) && bNeverResize )
2718                             {
2719                                 nChk |= FlyProtectFlags::Size;
2720                                 nChk |= FlyProtectFlags::Fixed;
2721                             }
2722 
2723                             // set FlyProtectFlags::Pos if it is a Math object anchored 'as char' and baseline alignment is activated
2724                             const bool bProtectMathPos = SotExchange::IsMath( xObj->getClassID() )
2725                                     && RndStdIds::FLY_AS_CHAR == pFly->GetFormat()->GetAnchor().GetAnchorId()
2726                                     && mxDoc->GetDocumentSettingManager().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT );
2727                             if ((FlyProtectFlags::Pos & eType) && bProtectMathPos)
2728                                 nChk |= FlyProtectFlags::Pos;
2729                         }
2730                     }
2731                 }
2732                 nChk &= eType;
2733                 if( nChk == eType )
2734                     return eType;
2735             }
2736             const SwFrame* pAnch;
2737             if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
2738                 pAnch = pVirtO->GetFlyFrame()->GetAnchorFrame();
2739             else
2740             {
2741                 SwDrawContact* pTmp = static_cast<SwDrawContact*>(GetUserCall(pObj));
2742                 pAnch = pTmp ? pTmp->GetAnchorFrame( pObj ) : nullptr;
2743             }
2744             if( pAnch && pAnch->IsProtected() )
2745                 return eType;
2746         }
2747     }
2748     return nChk;
2749 }
2750 
GetObjAttr(SfxItemSet & rSet) const2751 bool SwFEShell::GetObjAttr( SfxItemSet &rSet ) const
2752 {
2753     if ( !IsObjSelected() )
2754         return false;
2755 
2756     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2757     for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2758     {
2759         SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2760         SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
2761         // --> make code robust
2762         OSL_ENSURE( pContact, "<SwFEShell::GetObjAttr(..)> - missing <pContact>." );
2763         if ( pContact )
2764         {
2765             if ( i )
2766                 rSet.MergeValues( pContact->GetFormat()->GetAttrSet() );
2767             else
2768                 rSet.Put( pContact->GetFormat()->GetAttrSet() );
2769         }
2770     }
2771     return true;
2772 }
2773 
SetObjAttr(const SfxItemSet & rSet)2774 void SwFEShell::SetObjAttr( const SfxItemSet& rSet )
2775 {
2776     CurrShell aCurr( this );
2777 
2778     if ( !rSet.Count() )
2779     {
2780         OSL_ENSURE( false, "SetObjAttr, empty set." );
2781         return;
2782     }
2783 
2784     StartAllAction();
2785     StartUndo( SwUndoId::INSATTR );
2786 
2787     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2788     for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2789     {
2790         SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2791         SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
2792         GetDoc()->SetAttr( rSet, *pContact->GetFormat() );
2793     }
2794 
2795     EndUndo( SwUndoId::INSATTR );
2796     EndAllActionAndCall();
2797     GetDoc()->getIDocumentState().SetModified();
2798 }
2799 
IsAlignPossible() const2800 bool SwFEShell::IsAlignPossible() const
2801 {
2802     return Imp()->GetDrawView()->IsAlignPossible();
2803 }
2804 
CheckUnboundObjects()2805 void SwFEShell::CheckUnboundObjects()
2806 {
2807     CurrShell aCurr( this );
2808 
2809     const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
2810     for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
2811     {
2812         SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
2813         if ( !GetUserCall(pObj) )
2814         {
2815             const tools::Rectangle &rBound = pObj->GetSnapRect();
2816             const Point aPt( rBound.TopLeft() );
2817             const SwFrame *pPage = GetLayout()->Lower();
2818             const SwFrame *pLast = pPage;
2819             while ( pPage && !pPage->getFrameArea().IsInside( aPt ) )
2820             {
2821                 if ( aPt.Y() > pPage->getFrameArea().Bottom() )
2822                     pLast = pPage;
2823                 pPage = pPage->GetNext();
2824             }
2825             if ( !pPage )
2826                 pPage = pLast;
2827             OSL_ENSURE( pPage, "Page not found." );
2828 
2829             SwFormatAnchor aAnch;
2830             {
2831             const SwContentFrame *const pAnch = ::FindAnchor(pPage, aPt, true);
2832             SwPosition aPos( pAnch->IsTextFrame()
2833                 ? *static_cast<SwTextFrame const*>(pAnch)->GetTextNodeForParaProps()
2834                 : *static_cast<SwNoTextFrame const*>(pAnch)->GetNode() );
2835             aAnch.SetType( RndStdIds::FLY_AT_PARA );
2836             aAnch.SetAnchor( &aPos );
2837             const_cast<SwRect&>(GetCharRect()).Pos() = aPt;
2838             }
2839 
2840             // First the action here, to assure GetCharRect delivers current values.
2841             StartAllAction();
2842 
2843             SfxItemSet aSet( GetAttrPool(), svl::Items<RES_FRM_SIZE, RES_FRM_SIZE,
2844                                             RES_SURROUND, RES_ANCHOR>{} );
2845             aSet.Put( aAnch );
2846             aSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) );
2847             SwFrameFormat* pFormat = getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::DRAW_OBJECT, &aSet );
2848 
2849             SwDrawContact *pContact = new SwDrawContact(
2850                                             static_cast<SwDrawFrameFormat*>(pFormat), pObj );
2851 
2852             // #i35635#
2853             pContact->MoveObjToVisibleLayer( pObj );
2854             pContact->ConnectToLayout();
2855 
2856             EndAllAction();
2857         }
2858     }
2859 }
2860 
SetCalcFieldValueHdl(Outliner * pOutliner)2861 void SwFEShell::SetCalcFieldValueHdl(Outliner* pOutliner)
2862 {
2863     GetDoc()->SetCalcFieldValueHdl(pOutliner);
2864 }
2865 
Chainable(SwRect & rRect,const SwFrameFormat & rSource,const Point & rPt) const2866 SwChainRet SwFEShell::Chainable( SwRect &rRect, const SwFrameFormat &rSource,
2867                             const Point &rPt ) const
2868 {
2869     rRect.Clear();
2870 
2871     // The source is not allowed to have a follow.
2872     const SwFormatChain &rChain = rSource.GetChain();
2873     if ( rChain.GetNext() )
2874         return SwChainRet::SOURCE_CHAINED;
2875 
2876     SwChainRet nRet = SwChainRet::NOT_FOUND;
2877     if( Imp()->HasDrawView() )
2878     {
2879         SdrPageView* pPView;
2880         SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
2881         const auto nOld = pDView->GetHitTolerancePixel();
2882         pDView->SetHitTolerancePixel( 0 );
2883         SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
2884         SwVirtFlyDrawObj* pDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
2885         if (pDrawObj)
2886         {
2887             SwFlyFrame *pFly = pDrawObj->GetFlyFrame();
2888             rRect = pFly->getFrameArea();
2889 
2890             // Target and source should not be equal and the list
2891             // should not be cyclic
2892             SwFrameFormat *pFormat = pFly->GetFormat();
2893             nRet = GetDoc()->Chainable(rSource, *pFormat);
2894         }
2895         pDView->SetHitTolerancePixel( nOld );
2896     }
2897     return nRet;
2898 }
2899 
Chain(SwFrameFormat & rSource,const SwFrameFormat & rDest)2900 void SwFEShell::Chain( SwFrameFormat &rSource, const SwFrameFormat &rDest )
2901 {
2902     GetDoc()->Chain(rSource, rDest);
2903 }
2904 
Chain(SwFrameFormat & rSource,const Point & rPt)2905 SwChainRet SwFEShell::Chain( SwFrameFormat &rSource, const Point &rPt )
2906 {
2907     SwRect aDummy;
2908     SwChainRet nErr = Chainable( aDummy, rSource, rPt );
2909     if ( nErr == SwChainRet::OK )
2910     {
2911         StartAllAction();
2912         SdrPageView* pPView;
2913         SwDrawView *pDView = Imp()->GetDrawView();
2914         const auto nOld = pDView->GetHitTolerancePixel();
2915         pDView->SetHitTolerancePixel( 0 );
2916         SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
2917         pDView->SetHitTolerancePixel( nOld );
2918         SwFlyFrame *pFly = static_cast<SwVirtFlyDrawObj*>(pObj)->GetFlyFrame();
2919 
2920         SwFlyFrameFormat *pFormat = pFly->GetFormat();
2921         GetDoc()->Chain(rSource, *pFormat);
2922         EndAllAction();
2923         SetChainMarker();
2924     }
2925     return nErr;
2926 }
2927 
Unchain(SwFrameFormat & rFormat)2928 void SwFEShell::Unchain( SwFrameFormat &rFormat )
2929 {
2930     StartAllAction();
2931     GetDoc()->Unchain(rFormat);
2932     EndAllAction();
2933 }
2934 
HideChainMarker()2935 void SwFEShell::HideChainMarker()
2936 {
2937     m_pChainFrom.reset();
2938     m_pChainTo.reset();
2939 }
2940 
SetChainMarker()2941 void SwFEShell::SetChainMarker()
2942 {
2943     bool bDelFrom = true,
2944          bDelTo   = true;
2945     if ( IsFrameSelected() )
2946     {
2947         SwFlyFrame *pFly = GetSelectedFlyFrame();
2948 
2949         if ( pFly->GetPrevLink() )
2950         {
2951             bDelFrom = false;
2952             const SwFrame *pPre = pFly->GetPrevLink();
2953 
2954             Point aStart( pPre->getFrameArea().Right(), pPre->getFrameArea().Bottom());
2955             Point aEnd(pFly->getFrameArea().Pos());
2956 
2957             if (!m_pChainFrom)
2958             {
2959                 m_pChainFrom.reset(
2960                     new SdrDropMarkerOverlay( *GetDrawView(), aStart, aEnd ));
2961             }
2962         }
2963         if ( pFly->GetNextLink() )
2964         {
2965             bDelTo = false;
2966             const SwFlyFrame *pNxt = pFly->GetNextLink();
2967 
2968             Point aStart( pFly->getFrameArea().Right(), pFly->getFrameArea().Bottom());
2969             Point aEnd(pNxt->getFrameArea().Pos());
2970 
2971             if (!m_pChainTo)
2972             {
2973                 m_pChainTo.reset(
2974                     new SdrDropMarkerOverlay( *GetDrawView(), aStart, aEnd ));
2975             }
2976         }
2977     }
2978 
2979     if ( bDelFrom )
2980     {
2981         m_pChainFrom.reset();
2982     }
2983 
2984     if ( bDelTo )
2985     {
2986         m_pChainTo.reset();
2987     }
2988 }
2989 
GetSectionWidth(SwFormat const & rFormat) const2990 tools::Long SwFEShell::GetSectionWidth( SwFormat const & rFormat ) const
2991 {
2992     SwFrame *pFrame = GetCurrFrame();
2993     // Is the cursor at this moment in a SectionFrame?
2994     if( pFrame && pFrame->IsInSct() )
2995     {
2996         SwSectionFrame* pSect = pFrame->FindSctFrame();
2997         do
2998         {
2999             // Is it the right one?
3000             if( pSect->KnowsFormat( rFormat ) )
3001                 return pSect->getFrameArea().Width();
3002             // for nested areas
3003             pSect = pSect->GetUpper()->FindSctFrame();
3004         }
3005         while( pSect );
3006     }
3007     SwIterator<SwSectionFrame,SwFormat> aIter( rFormat );
3008     for ( SwSectionFrame* pSct = aIter.First(); pSct; pSct = aIter.Next() )
3009     {
3010         if( !pSct->IsFollow() )
3011         {
3012             return pSct->getFrameArea().Width();
3013         }
3014     }
3015     return 0;
3016 }
3017 
CreateDefaultShape(SdrObjKind eSdrObjectKind,const tools::Rectangle & rRect,sal_uInt16 nSlotId)3018 void SwFEShell::CreateDefaultShape( SdrObjKind eSdrObjectKind, const tools::Rectangle& rRect,
3019                 sal_uInt16 nSlotId)
3020 {
3021     SdrView* pDrawView = GetDrawView();
3022     SdrModel* pDrawModel = pDrawView->GetModel();
3023     SdrObject* pObj = SdrObjFactory::MakeNewObject(
3024         *pDrawModel,
3025         SdrInventor::Default,
3026         eSdrObjectKind);
3027 
3028     if(pObj)
3029     {
3030         tools::Rectangle aRect(rRect);
3031         if(OBJ_CARC == eSdrObjectKind || OBJ_CCUT == eSdrObjectKind)
3032         {
3033             // force quadratic
3034             if(aRect.GetWidth() > aRect.GetHeight())
3035             {
3036                 aRect = tools::Rectangle(
3037                     Point(aRect.Left() + ((aRect.GetWidth() - aRect.GetHeight()) / 2), aRect.Top()),
3038                     Size(aRect.GetHeight(), aRect.GetHeight()));
3039             }
3040             else
3041             {
3042                 aRect = tools::Rectangle(
3043                     Point(aRect.Left(), aRect.Top() + ((aRect.GetHeight() - aRect.GetWidth()) / 2)),
3044                     Size(aRect.GetWidth(), aRect.GetWidth()));
3045             }
3046         }
3047         pObj->SetLogicRect(aRect);
3048 
3049         Point aStart = aRect.TopLeft();
3050         Point aEnd = aRect.BottomRight();
3051 
3052         if(dynamic_cast<const SdrCircObj*>( pObj) !=  nullptr)
3053         {
3054             SfxItemSet aAttr(pDrawModel->GetItemPool());
3055             aAttr.Put(makeSdrCircStartAngleItem(9000_deg100));
3056             aAttr.Put(makeSdrCircEndAngleItem(0_deg100));
3057             pObj->SetMergedItemSet(aAttr);
3058         }
3059         else if(auto pPathObj = dynamic_cast<SdrPathObj*>( pObj))
3060         {
3061             basegfx::B2DPolyPolygon aPoly;
3062 
3063             switch(eSdrObjectKind)
3064             {
3065                 case OBJ_PATHLINE:
3066                 case OBJ_PATHFILL:
3067                 {
3068                     basegfx::B2DPolygon aInnerPoly;
3069 
3070                     aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Bottom()));
3071 
3072                     const basegfx::B2DPoint aCenterBottom(aRect.Center().getX(), aRect.Bottom());
3073                     aInnerPoly.appendBezierSegment(
3074                         aCenterBottom,
3075                         aCenterBottom,
3076                         basegfx::B2DPoint(aRect.Center().getX(), aRect.Center().getY()));
3077 
3078                     const basegfx::B2DPoint aCenterTop(aRect.Center().getX(), aRect.Top());
3079                     aInnerPoly.appendBezierSegment(
3080                         aCenterTop,
3081                         aCenterTop,
3082                         basegfx::B2DPoint(aRect.Right(), aRect.Top()));
3083 
3084                     aInnerPoly.setClosed(true);
3085                     aPoly.append(aInnerPoly);
3086                 }
3087                 break;
3088                 case OBJ_FREELINE:
3089                 case OBJ_FREEFILL:
3090                 {
3091                     basegfx::B2DPolygon aInnerPoly;
3092 
3093                     aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Bottom()));
3094 
3095                     aInnerPoly.appendBezierSegment(
3096                         basegfx::B2DPoint(aRect.Left(), aRect.Top()),
3097                         basegfx::B2DPoint(aRect.Center().getX(), aRect.Top()),
3098                         basegfx::B2DPoint(aRect.Center().getX(), aRect.Center().getY()));
3099 
3100                     aInnerPoly.appendBezierSegment(
3101                         basegfx::B2DPoint(aRect.Center().getX(), aRect.Bottom()),
3102                         basegfx::B2DPoint(aRect.Right(), aRect.Bottom()),
3103                         basegfx::B2DPoint(aRect.Right(), aRect.Top()));
3104 
3105                     aInnerPoly.append(basegfx::B2DPoint(aRect.Right(), aRect.Bottom()));
3106                     aInnerPoly.setClosed(true);
3107                     aPoly.append(aInnerPoly);
3108                 }
3109                 break;
3110                 case OBJ_POLY:
3111                 case OBJ_PLIN:
3112                 {
3113                     basegfx::B2DPolygon aInnerPoly;
3114                     sal_Int32 nWdt(aRect.GetWidth());
3115                     sal_Int32 nHgt(aRect.GetHeight());
3116 
3117                     aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Bottom()));
3118                     aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 30) / 100, aRect.Top() + (nHgt * 70) / 100));
3119                     aInnerPoly.append(basegfx::B2DPoint(aRect.Left(), aRect.Top() + (nHgt * 15) / 100));
3120                     aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 65) / 100, aRect.Top()));
3121                     aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + nWdt, aRect.Top() + (nHgt * 30) / 100));
3122                     aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 80) / 100, aRect.Top() + (nHgt * 50) / 100));
3123                     aInnerPoly.append(basegfx::B2DPoint(aRect.Left() + (nWdt * 80) / 100, aRect.Top() + (nHgt * 75) / 100));
3124                     aInnerPoly.append(basegfx::B2DPoint(aRect.Bottom(), aRect.Right()));
3125 
3126                     if(OBJ_PLIN == eSdrObjectKind)
3127                     {
3128                         aInnerPoly.append(basegfx::B2DPoint(aRect.Center().getX(), aRect.Bottom()));
3129                     }
3130                     else
3131                     {
3132                         aInnerPoly.setClosed(true);
3133                     }
3134 
3135                     aPoly.append(aInnerPoly);
3136                 }
3137                 break;
3138                 case OBJ_LINE :
3139                 {
3140                     sal_Int32 nYMiddle((aRect.Top() + aRect.Bottom()) / 2);
3141                     basegfx::B2DPolygon aTempPoly;
3142                     aTempPoly.append(basegfx::B2DPoint(aRect.TopLeft().getX(), nYMiddle));
3143                     aTempPoly.append(basegfx::B2DPoint(aRect.BottomRight().getX(), nYMiddle));
3144                     aPoly.append(aTempPoly);
3145 
3146                     SfxItemSet aAttr(pObj->getSdrModelFromSdrObject().GetItemPool());
3147                     SetLineEnds(aAttr, *pObj, nSlotId);
3148                     pObj->SetMergedItemSet(aAttr);
3149                 }
3150                 break;
3151                 default:
3152                 break;
3153             }
3154 
3155             pPathObj->SetPathPoly(aPoly);
3156         }
3157         else if(auto pMeasureObj = dynamic_cast<SdrMeasureObj*>( pObj))
3158         {
3159             sal_Int32 nYMiddle((aRect.Top() + aRect.Bottom()) / 2);
3160             pMeasureObj->SetPoint(Point(aStart.X(), nYMiddle), 0);
3161             pMeasureObj->SetPoint(Point(aEnd.X(), nYMiddle), 1);
3162 
3163             SfxItemSet aAttr(pObj->getSdrModelFromSdrObject().GetItemPool());
3164             SetLineEnds(aAttr, *pObj, nSlotId);
3165             pObj->SetMergedItemSet(aAttr);
3166         }
3167         else if(auto pCaptionObj = dynamic_cast<SdrCaptionObj*>( pObj))
3168         {
3169             bool bVerticalText = ( SID_DRAW_TEXT_VERTICAL == nSlotId ||
3170                                             SID_DRAW_CAPTION_VERTICAL == nSlotId );
3171             pCaptionObj->SetVerticalWriting(bVerticalText);
3172             if(bVerticalText)
3173             {
3174                 SfxItemSet aSet(pObj->GetMergedItemSet());
3175                 aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER));
3176                 aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
3177                 pObj->SetMergedItemSet(aSet);
3178             }
3179 
3180             pCaptionObj->SetLogicRect(aRect);
3181             pCaptionObj->SetTailPos(
3182                 aRect.TopLeft() - Point(aRect.GetWidth() / 2, aRect.GetHeight() / 2));
3183         }
3184         else if(auto pText = dynamic_cast<SdrTextObj*>( pObj))
3185         {
3186             pText->SetLogicRect(aRect);
3187 
3188             bool bVertical = (SID_DRAW_TEXT_VERTICAL == nSlotId);
3189             bool bMarquee = (SID_DRAW_TEXT_MARQUEE == nSlotId);
3190 
3191             pText->SetVerticalWriting(bVertical);
3192 
3193             if(bVertical)
3194             {
3195                 SfxItemSet aSet(pDrawModel->GetItemPool());
3196                 aSet.Put(makeSdrTextAutoGrowWidthItem(true));
3197                 aSet.Put(makeSdrTextAutoGrowHeightItem(false));
3198                 aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP));
3199                 aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
3200                 pText->SetMergedItemSet(aSet);
3201             }
3202 
3203             if(bMarquee)
3204             {
3205                 SfxItemSet aSet(pDrawModel->GetItemPool(), svl::Items<SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST>{});
3206                 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
3207                 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
3208                 aSet.Put( SdrTextAniKindItem( SdrTextAniKind::Slide ) );
3209                 aSet.Put( SdrTextAniDirectionItem( SdrTextAniDirection::Left ) );
3210                 aSet.Put( SdrTextAniCountItem( 1 ) );
3211                 aSet.Put( SdrTextAniAmountItem( static_cast<sal_Int16>(GetWin()->PixelToLogic(Size(2,1)).Width())) );
3212                 pObj->SetMergedItemSetAndBroadcast(aSet);
3213             }
3214         }
3215         SdrPageView* pPageView = pDrawView->GetSdrPageView();
3216         SdrCreateView::SetupObjLayer(pPageView, pDrawView->GetActiveLayer(), pObj);
3217         // switch undo off or this combined with ImpEndCreate will cause two undos
3218         // see comment made in SwFEShell::EndCreate (we create our own undo-object!)
3219         const bool bUndo(GetDoc()->GetIDocumentUndoRedo().DoesUndo());
3220         GetDoc()->GetIDocumentUndoRedo().DoUndo(false);
3221         pDrawView->InsertObjectAtView(pObj, *pPageView);
3222         GetDoc()->GetIDocumentUndoRedo().DoUndo(bUndo);
3223     }
3224     ImpEndCreate();
3225 }
3226 
3227 /** SwFEShell::GetShapeBackground
3228     method determines background color of the page the selected drawing
3229     object is on and returns this color.
3230     If no color is found, because no drawing object is selected or ...,
3231     color COL_BLACK (default color on constructing object of class Color)
3232     is returned.
3233 
3234     @returns an object of class Color
3235 */
GetShapeBackground() const3236 Color SwFEShell::GetShapeBackground() const
3237 {
3238     Color aRetColor;
3239 
3240     // check, if a draw view exists
3241     OSL_ENSURE( Imp()->GetDrawView(), "wrong usage of SwFEShell::GetShapeBackground - no draw view!");
3242     if( Imp()->GetDrawView() )
3243     {
3244         // determine list of selected objects
3245         const SdrMarkList* pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
3246         // check, if exactly one object is selected.
3247         OSL_ENSURE( pMrkList->GetMarkCount() == 1, "wrong usage of SwFEShell::GetShapeBackground - no selected object!");
3248         if ( pMrkList->GetMarkCount() == 1)
3249         {
3250             // get selected object
3251             const SdrObject *pSdrObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
3252             // check, if selected object is a shape (drawing object)
3253             OSL_ENSURE( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) ==  nullptr, "wrong usage of SwFEShell::GetShapeBackground - selected object is not a drawing object!");
3254             if ( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) ==  nullptr )
3255             {
3256                 // determine page frame of the frame the shape is anchored.
3257                 const SwFrame* pAnchorFrame =
3258                         static_cast<SwDrawContact*>(GetUserCall(pSdrObj))->GetAnchorFrame( pSdrObj );
3259                 OSL_ENSURE( pAnchorFrame, "inconsistent model - no anchor at shape!");
3260                 if ( pAnchorFrame )
3261                 {
3262                     const SwPageFrame* pPageFrame = pAnchorFrame->FindPageFrame();
3263                     OSL_ENSURE( pPageFrame, "inconsistent model - no page!");
3264                     if ( pPageFrame )
3265                     {
3266                         aRetColor = pPageFrame->GetDrawBackgroundColor();
3267                     }
3268                 }
3269             }
3270         }
3271     }
3272 
3273     return aRetColor;
3274 }
3275 
3276 /** Is default horizontal text direction for selected drawing object right-to-left
3277     Because drawing objects only painted for each page only, the default
3278     horizontal text direction of a drawing object is given by the corresponding
3279     page property.
3280 
3281     @returns boolean, indicating, if the horizontal text direction of the
3282     page, the selected drawing object is on, is right-to-left.
3283 */
IsShapeDefaultHoriTextDirR2L() const3284 bool SwFEShell::IsShapeDefaultHoriTextDirR2L() const
3285 {
3286     bool bRet = false;
3287 
3288     // check, if a draw view exists
3289     OSL_ENSURE( Imp()->GetDrawView(), "wrong usage of SwFEShell::GetShapeBackground - no draw view!");
3290     if( Imp()->GetDrawView() )
3291     {
3292         // determine list of selected objects
3293         const SdrMarkList* pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
3294         // check, if exactly one object is selected.
3295         OSL_ENSURE( pMrkList->GetMarkCount() == 1, "wrong usage of SwFEShell::GetShapeBackground - no selected object!");
3296         if ( pMrkList->GetMarkCount() == 1)
3297         {
3298             // get selected object
3299             const SdrObject *pSdrObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
3300             // check, if selected object is a shape (drawing object)
3301             OSL_ENSURE( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) ==  nullptr, "wrong usage of SwFEShell::GetShapeBackground - selected object is not a drawing object!");
3302             if ( dynamic_cast<const SwVirtFlyDrawObj*>( pSdrObj) ==  nullptr )
3303             {
3304                 // determine page frame of the frame the shape is anchored.
3305                 const SwFrame* pAnchorFrame =
3306                         static_cast<SwDrawContact*>(GetUserCall(pSdrObj))->GetAnchorFrame( pSdrObj );
3307                 OSL_ENSURE( pAnchorFrame, "inconsistent model - no anchor at shape!");
3308                 if ( pAnchorFrame )
3309                 {
3310                     const SwPageFrame* pPageFrame = pAnchorFrame->FindPageFrame();
3311                     OSL_ENSURE( pPageFrame, "inconsistent model - no page!");
3312                     if ( pPageFrame )
3313                     {
3314                         bRet = pPageFrame->IsRightToLeft();
3315                     }
3316                 }
3317             }
3318         }
3319     }
3320 
3321     return bRet;
3322 }
3323 
GetRelativePagePosition(const Point & rDocPos)3324 Point SwFEShell::GetRelativePagePosition(const Point& rDocPos)
3325 {
3326     Point aRet(-1, -1);
3327     const SwFrame *pPage = GetLayout()->Lower();
3328     while ( pPage && !pPage->getFrameArea().IsInside( rDocPos ) )
3329     {
3330         pPage = pPage->GetNext();
3331     }
3332     if(pPage)
3333     {
3334         aRet = rDocPos - pPage->getFrameArea().TopLeft();
3335     }
3336     return aRet;
3337 }
3338 
3339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3340