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