sc: factor out some more code
[LibreOffice.git] / sw / source / core / frmedt / fefly1.cxx
blobf8e68a65a00156eefe5b30b4466868cd1becd308
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
21 #include <o3tl/any.hxx>
22 #include <svl/itemiter.hxx>
23 #include <vcl/imapobj.hxx>
24 #include <editeng/protitem.hxx>
25 #include <svx/svdogrp.hxx>
26 #include <svx/svdouno.hxx>
27 #include <tools/globname.hxx>
28 #include <sot/exchange.hxx>
29 #include <com/sun/star/form/FormButtonType.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/embed/XEmbeddedObject.hpp>
32 #include <comphelper/types.hxx>
33 #include <osl/diagnose.h>
34 #include <comphelper/scopeguard.hxx>
35 #include <fmtanchr.hxx>
36 #include <fmtcntnt.hxx>
37 #include <fmtornt.hxx>
38 #include <fmturl.hxx>
39 #include <fmtfsize.hxx>
40 #include <fesh.hxx>
41 #include <rootfrm.hxx>
42 #include <pagefrm.hxx>
43 #include <cntfrm.hxx>
44 #include <txtfrm.hxx>
45 #include <viewimp.hxx>
46 #include <viscrs.hxx>
47 #include <doc.hxx>
48 #include <IDocumentDrawModelAccess.hxx>
49 #include <IDocumentUndoRedo.hxx>
50 #include <IDocumentState.hxx>
51 #include <IDocumentLayoutAccess.hxx>
52 #include <IDocumentRedlineAccess.hxx>
53 #include <redline.hxx>
54 #include <dview.hxx>
55 #include <dflyobj.hxx>
56 #include <dcontact.hxx>
57 #include <frmfmt.hxx>
58 #include <flyfrm.hxx>
59 #include <ndtxt.hxx>
60 #include <swtable.hxx>
61 #include <ndgrf.hxx>
62 #include <flyfrms.hxx>
63 #include <fldbas.hxx>
64 #include <fmtfld.hxx>
65 #include <swundo.hxx>
66 #include <txatbase.hxx>
67 #include <frame.hxx>
68 #include <notxtfrm.hxx>
69 #include <HandleAnchorNodeChg.hxx>
70 #include <frmatr.hxx>
71 #include <fmtsrnd.hxx>
72 #include <ndole.hxx>
73 #include <fefly.hxx>
74 #include <fmtcnct.hxx>
75 #include <frameformats.hxx>
76 #include <textboxhelper.hxx>
79 using namespace ::com::sun::star;
81 // Based on the request, changes to the specific layouts will be made, to
82 // fit to the format
83 static bool lcl_SetNewFlyPos( const SwNode& rNode, SwFormatAnchor& rAnchor,
84 const Point& rPt )
86 bool bRet = false;
87 const SwStartNode* pStNode = rNode.FindFlyStartNode();
88 if( pStNode )
90 SwPosition aPos( *pStNode );
91 rAnchor.SetAnchor( &aPos );
92 bRet = true;
94 else
96 const SwContentNode *pCntNd = rNode.GetContentNode();
97 std::pair<Point, bool> const tmp(rPt, false);
98 const SwContentFrame* pCFrame = pCntNd ? pCntNd->getLayoutFrame(
99 pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
100 nullptr, &tmp) : nullptr;
101 const SwPageFrame *pPg = pCFrame ? pCFrame->FindPageFrame() : nullptr;
103 rAnchor.SetPageNum( pPg ? pPg->GetPhyPageNum() : 1 );
104 rAnchor.SetType( RndStdIds::FLY_AT_PAGE );
106 return bRet;
109 static bool lcl_FindAnchorPos(
110 SwDoc& rDoc,
111 const Point& rPt,
112 const SwFrame& rFrame,
113 SfxItemSet& rSet )
115 bool bRet = true;
116 SwFormatAnchor aNewAnch( rSet.Get( RES_ANCHOR ) );
117 RndStdIds nNew = aNewAnch.GetAnchorId();
118 const SwFrame *pNewAnch;
120 //determine new anchor
121 Point aTmpPnt( rPt );
122 switch( nNew )
124 case RndStdIds::FLY_AS_CHAR: // also include this?
125 case RndStdIds::FLY_AT_PARA:
126 case RndStdIds::FLY_AT_CHAR: // LAYER_IMPL
128 // starting from the upper-left corner of the Fly,
129 // search nearest ContentFrame
130 const SwFrame* pFrame = rFrame.IsFlyFrame() ? static_cast<const SwFlyFrame&>(rFrame).GetAnchorFrame()
131 : &rFrame;
132 pNewAnch = ::FindAnchor( pFrame, aTmpPnt );
133 if( pNewAnch->IsProtected() )
135 bRet = false;
136 break;
138 SwPosition aPos( pNewAnch->IsTextFrame()
139 ? *static_cast<SwTextFrame const*>(pNewAnch)->GetTextNodeForParaProps()
140 : *static_cast<const SwNoTextFrame*>(pNewAnch)->GetNode() );
141 if ((RndStdIds::FLY_AT_CHAR == nNew) || (RndStdIds::FLY_AS_CHAR == nNew))
143 // textnode should be found, as only in those
144 // a content bound frame can be anchored
145 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
146 aTmpPnt.setX(aTmpPnt.getX() - 1); // do not land in the fly!
147 if( !pNewAnch->GetModelPositionForViewPoint( &aPos, aTmpPnt, &aState ) )
149 assert(pNewAnch->IsTextFrame()); // because AT_CHAR/AS_CHAR
150 SwTextFrame const*const pTextFrame(
151 static_cast<SwTextFrame const*>(pNewAnch));
152 if( pNewAnch->getFrameArea().Bottom() < aTmpPnt.Y() )
154 aPos = pTextFrame->MapViewToModelPos(TextFrameIndex(0));
156 else
158 aPos = pTextFrame->MapViewToModelPos(
159 TextFrameIndex(pTextFrame->GetText().getLength()));
162 else
164 if ( SwCursorShell::PosInsideInputField( aPos ) )
166 aPos.SetContent( SwCursorShell::StartOfInputFieldAtPos( aPos ) );
170 aNewAnch.SetAnchor( &aPos );
172 break;
174 case RndStdIds::FLY_AT_FLY: // LAYER_IMPL
176 // starting from the upper-left corner of the Fly
177 // search nearest SwFlyFrame
178 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
179 SwPosition aPos( rDoc.GetNodes() );
180 aTmpPnt.setX(aTmpPnt.getX() - 1); // do not land in the fly!
181 rDoc.getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( &aPos, aTmpPnt, &aState );
182 pNewAnch = ::FindAnchor(
183 aPos.GetNode().GetContentNode()->getLayoutFrame(rFrame.getRootFrame(), nullptr, nullptr),
184 aTmpPnt )->FindFlyFrame();
186 if( pNewAnch && &rFrame != pNewAnch && !pNewAnch->IsProtected() )
188 aPos.Assign( *static_cast<const SwFlyFrame*>(pNewAnch)->GetFormat()->GetContent().
189 GetContentIdx() );
190 aNewAnch.SetAnchor( &aPos );
191 break;
195 nNew = RndStdIds::FLY_AT_PAGE;
196 aNewAnch.SetType( nNew );
197 [[fallthrough]];
199 case RndStdIds::FLY_AT_PAGE:
200 pNewAnch = rFrame.FindPageFrame();
201 aNewAnch.SetPageNum( pNewAnch->GetPhyPageNum() );
202 break;
204 default:
205 OSL_ENSURE( false, "Wrong Id for new anchor." );
208 rSet.Put( aNewAnch );
209 return bRet;
212 //! also used in unoframe.cxx
214 bool sw_ChkAndSetNewAnchor(
215 const SwFlyFrame& rFly,
216 SfxItemSet& rSet )
218 const SwFrameFormat& rFormat = *rFly.GetFormat();
219 const SwFormatAnchor &rOldAnch = rFormat.GetAnchor();
220 const RndStdIds nOld = rOldAnch.GetAnchorId();
222 RndStdIds nNew = rSet.Get( RES_ANCHOR ).GetAnchorId();
224 if( nOld == nNew )
225 return false;
227 SwDoc* pDoc = const_cast<SwDoc*>(rFormat.GetDoc());
229 #if OSL_DEBUG_LEVEL > 0
230 OSL_ENSURE( !(nNew == RndStdIds::FLY_AT_PAGE &&
231 (RndStdIds::FLY_AT_PARA==nOld || RndStdIds::FLY_AT_CHAR==nOld || RndStdIds::FLY_AS_CHAR==nOld ) &&
232 pDoc->IsInHeaderFooter( *rOldAnch.GetAnchorNode() )),
233 "forbidden anchor change in Head/Foot." );
234 #endif
236 return ::lcl_FindAnchorPos( *pDoc, rFly.getFrameArea().Pos(), rFly, rSet );
239 void SwFEShell::SelectFlyFrame( SwFlyFrame& rFrame )
241 CurrShell aCurr( this );
243 // The frame is new, thus select it.
244 // !! Always select the frame, if it's not selected.
245 // - it could be a new "old" one because the anchor was changed
246 // - "old" frames have had to be selected previously otherwise they could
247 // not have been changed
248 // The frames should not be selected by the document position, because
249 // it should have been selected!
250 SwViewShellImp *pImpl = Imp();
251 if( !GetWin() )
252 return;
254 OSL_ENSURE( rFrame.IsFlyFrame(), "SelectFlyFrame wants a Fly" );
256 // nothing to be done if the Fly already was selected
257 if (GetSelectedFlyFrame() == &rFrame)
258 return;
260 // assure the anchor is drawn
261 if( rFrame.IsFlyInContentFrame() && rFrame.GetAnchorFrame() )
262 rFrame.GetAnchorFrame()->SetCompletePaint();
264 if( pImpl->GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0 )
265 pImpl->GetDrawView()->UnmarkAll();
267 pImpl->GetDrawView()->MarkObj( rFrame.GetVirtDrawObj(),
268 pImpl->GetPageView() );
270 rFrame.SelectionHasChanged(this);
272 KillPams();
273 ClearMark();
274 SelFlyGrabCursor();
277 void SwFEShell::UnfloatFlyFrame()
279 GetIDocumentUndoRedo().StartUndo(SwUndoId::DELLAYFMT, nullptr);
280 comphelper::ScopeGuard g([this]
281 { GetIDocumentUndoRedo().EndUndo(SwUndoId::DELLAYFMT, nullptr); });
283 SwFlyFrame* pFly = GetSelectedFlyFrame();
284 if (!pFly)
286 return;
289 SwFrameFormat* pFlyFormat = pFly->GetFrameFormat();
290 const SwFormatContent& rContent = pFlyFormat->GetContent();
291 const SwNodeIndex* pFlyStart = rContent.GetContentIdx();
292 if (!pFlyStart)
294 return;
297 const SwEndNode* pFlyEnd = pFlyStart->GetNode().EndOfSectionNode();
298 if (!pFlyEnd)
300 return;
303 // Create an empty paragraph after the table, so the frame's SwNodes section is non-empty after
304 // MoveNodeRange(). Undo would ensure it's non-empty and then node offsets won't match.
305 IDocumentContentOperations& rIDCO = GetDoc()->getIDocumentContentOperations();
307 SwNodeIndex aInsertIndex(*pFlyEnd);
308 --aInsertIndex;
309 SwPosition aInsertPos(aInsertIndex);
310 StartAllAction();
311 rIDCO.AppendTextNode(aInsertPos);
312 // Make sure that a layout frame is created for the node, so the fly frame is not deleted,
313 // during MoveNodeRange(), either.
314 EndAllAction();
317 SwNodeRange aRange(pFlyStart->GetNode(), SwNodeOffset(1), *pFlyEnd, SwNodeOffset(-1));
318 const SwFormatAnchor& rAnchor = pFlyFormat->GetAnchor();
319 SwNode* pAnchor = rAnchor.GetAnchorNode();
320 if (!pAnchor)
322 return;
325 // Move the content outside of the text frame.
326 SwNodeIndex aInsertPos(*pAnchor);
327 rIDCO.MoveNodeRange(aRange, aInsertPos.GetNode(), SwMoveFlags::CREATEUNDOOBJ);
329 // Remove the fly frame frame.
330 IDocumentLayoutAccess& rIDLA = pFlyFormat->getIDocumentLayoutAccess();
331 rIDLA.DelLayoutFormat(pFlyFormat);
334 // Get selected fly
335 SwFlyFrame* SwFEShell::GetSelectedFlyFrame() const
337 if ( Imp()->HasDrawView() )
339 // A Fly is only accessible if it is selected
340 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
341 if( rMrkList.GetMarkCount() != 1 )
342 return nullptr;
344 SdrObject *pO = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
346 SwVirtFlyDrawObj *pFlyObj = dynamic_cast<SwVirtFlyDrawObj*>(pO);
348 return pFlyObj ? pFlyObj->GetFlyFrame() : nullptr;
350 return nullptr;
353 // Get current fly in which the cursor is positioned
354 SwFlyFrame* SwFEShell::GetCurrFlyFrame(const bool bCalcFrame) const
356 SwContentFrame *pContent = GetCurrFrame(bCalcFrame);
357 return pContent ? pContent->FindFlyFrame() : nullptr;
360 // Get selected fly, but if none Get current fly in which the cursor is positioned
361 SwFlyFrame* SwFEShell::GetSelectedOrCurrFlyFrame() const
363 SwFlyFrame *pFly = GetSelectedFlyFrame();
364 if (pFly)
365 return pFly;
366 return GetCurrFlyFrame();
369 // Returns non-null pointer, if the current Fly could be anchored to another one (so it is inside)
370 const SwFrameFormat* SwFEShell::IsFlyInFly()
372 CurrShell aCurr( this );
374 if ( !Imp()->HasDrawView() )
375 return nullptr;
377 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
378 if ( !rMrkList.GetMarkCount() )
380 SwFlyFrame *pFly = GetCurrFlyFrame(false);
381 if (!pFly)
382 return nullptr;
383 return pFly->GetFormat();
385 else if ( rMrkList.GetMarkCount() != 1 )
386 return nullptr;
388 SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
389 SwContact* pContact = GetUserCall( pObj );
390 if (!pContact)
391 return nullptr;
393 SwFrameFormat *pFormat = FindFrameFormat( pObj );
394 if( pFormat && RndStdIds::FLY_AT_FLY == pFormat->GetAnchor().GetAnchorId() )
396 const SwFrame* pFly;
397 if (SwVirtFlyDrawObj* pFlyObj = dynamic_cast<SwVirtFlyDrawObj *>(pObj))
399 pFly = pFlyObj->GetFlyFrame()->GetAnchorFrame();
401 else
403 pFly = static_cast<SwDrawContact*>(pContact)->GetAnchorFrame(pObj);
406 assert(pFly && "IsFlyInFly: Where's my anchor?");
407 OSL_ENSURE( pFly->IsFlyFrame(), "IsFlyInFly: Funny anchor!" );
408 return static_cast<const SwFlyFrame*>(pFly)->GetFormat();
411 Point aTmpPos = pObj->GetCurrentBoundRect().TopLeft();
413 SwFrame *pTextFrame;
415 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
416 SwNodeIndex aSwNodeIndex( GetDoc()->GetNodes() );
417 SwPosition aPos( aSwNodeIndex );
418 Point aPoint( aTmpPos );
419 aPoint.setX(aPoint.getX() - 1); //do not land in the fly!!
420 GetLayout()->GetModelPositionForViewPoint( &aPos, aPoint, &aState );
421 // determine text frame by left-top-corner of object
422 SwContentNode *pNd = aPos.GetNode().GetContentNode();
423 std::pair<Point, bool> const tmp(aTmpPos, false);
424 pTextFrame = pNd ? pNd->getLayoutFrame(GetLayout(), nullptr, &tmp) : nullptr;
426 const SwFrame *pTmp = pTextFrame ? ::FindAnchor(pTextFrame, aTmpPos) : nullptr;
427 const SwFlyFrame *pFly = pTmp ? pTmp->FindFlyFrame() : nullptr;
428 if( pFly )
429 return pFly->GetFormat();
430 return nullptr;
433 void SwFEShell::SetFlyPos( const Point& rAbsPos )
435 CurrShell aCurr( this );
437 // Determine reference point in document coordinates
438 SwFlyFrame *pFly = GetCurrFlyFrame(false);
439 if (!pFly)
440 return;
442 //SwSaveHdl aSaveX( Imp() );
444 // Set an anchor starting from the absolute position for paragraph bound Flys
445 // Anchor and new RelPos will be calculated and set by the Fly
446 if ( pFly->IsFlyAtContentFrame() )
448 if(pFly->IsFlyFreeFrame() && static_cast< SwFlyFreeFrame* >(pFly)->isTransformableSwFrame())
450 // RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used),
451 // we need to correct the absolute position (rAbsPos) which was created in
452 // transformed coordinates to untransformed state
453 TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(pFly)->getTransformableSwFrame());
454 const SwRect aUntransformedFrameArea(pTransformableSwFrame->getUntransformedFrameArea());
455 const Point aNewAbsPos(
456 rAbsPos.X() + aUntransformedFrameArea.Left() - pFly->getFrameArea().Left(),
457 rAbsPos.Y() + aUntransformedFrameArea.Top() - pFly->getFrameArea().Top());
458 static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos(aNewAbsPos);
460 else
462 static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos( rAbsPos );
465 else
467 const SwFrame *pAnch = pFly->GetAnchorFrame();
468 Point aOrient( pAnch->getFrameArea().Pos() );
470 if ( pFly->IsFlyInContentFrame() )
471 aOrient.setX(rAbsPos.getX());
473 // calculate RelPos.
474 aOrient.setX(rAbsPos.getX() - aOrient.getX());
475 aOrient.setY(rAbsPos.getY() - aOrient.getY());
476 pFly->ChgRelPos( aOrient );
478 CallChgLnk(); // call the AttrChangeNotify on the UI-side.
481 Point SwFEShell::FindAnchorPos( const Point& rAbsPos, bool bMoveIt )
483 Point aRet;
485 CurrShell aCurr( this );
487 if ( !Imp()->HasDrawView() )
488 return aRet;
490 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
491 if (rMrkList.GetMarkCount() != 1)
492 return aRet;
494 SdrObject* pObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
496 SwContact* pContact = ::GetUserCall( pObj );
497 if (!pContact)
498 return aRet;
500 assert(pObj);
502 // #i28701#
503 SwAnchoredObject* pAnchoredObj = pContact->GetAnchoredObj( pObj );
504 SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat();
505 const RndStdIds nAnchorId = pFormat->GetAnchor().GetAnchorId();
507 if ( RndStdIds::FLY_AS_CHAR == nAnchorId )
508 return aRet;
510 bool bFlyFrame = dynamic_cast<SwVirtFlyDrawObj *>(pObj) != nullptr;
512 bool bTextBox = false;
513 if (pFormat->Which() == RES_DRAWFRMFMT)
515 bTextBox = SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, pObj);
518 SwFlyFrame* pFly = nullptr;
519 const SwFrame* pFooterOrHeader = nullptr;
521 if( bFlyFrame )
523 // Calculate reference point in document coordinates
524 SwContentFrame *pContent = GetCurrFrame( false );
525 if( !pContent )
526 return aRet;
527 pFly = pContent->FindFlyFrame();
528 if ( !pFly )
529 return aRet;
530 const SwFrame* pOldAnch = pFly->GetAnchorFrame();
531 if( !pOldAnch )
532 return aRet;
533 if ( RndStdIds::FLY_AT_PAGE != nAnchorId )
535 pFooterOrHeader = pContent->FindFooterOrHeader();
538 else if (bTextBox)
540 auto pFlyFormat
541 = dynamic_cast<const SwFlyFrameFormat*>(SwTextBoxHelper::getOtherTextBoxFormat(
542 pFormat, RES_DRAWFRMFMT, pObj));
543 if (pFlyFormat)
545 pFly = pFlyFormat->GetFrame();
549 // set <pFooterOrHeader> also for drawing
550 // objects, but not for control objects.
551 // Necessary for moving 'anchor symbol' at the user interface inside header/footer.
552 else if ( !::CheckControlLayer( pObj ) )
554 SwContentFrame *pContent = GetCurrFrame( false );
555 if( !pContent )
556 return aRet;
557 pFooterOrHeader = pContent->FindFooterOrHeader();
560 // Search nearest SwFlyFrame starting from the upper-left corner
561 // of the fly
562 SwContentFrame *pTextFrame = nullptr;
564 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
565 SwPosition aPos( GetDoc()->GetNodes().GetEndOfExtras() );
566 Point aTmpPnt( rAbsPos );
567 GetLayout()->GetModelPositionForViewPoint( &aPos, aTmpPnt, &aState );
568 if (aPos.GetNode() != GetDoc()->GetNodes().GetEndOfExtras()
569 && (nAnchorId != RndStdIds::FLY_AT_CHAR || !PosInsideInputField(aPos)))
571 SwContentNode* pCNode = aPos.GetNode().GetContentNode();
572 assert(pCNode);
573 pTextFrame = pCNode->getLayoutFrame(GetLayout(), &aPos, nullptr);
576 const SwFrame *pNewAnch = nullptr;
577 if( pTextFrame != nullptr )
579 if ( RndStdIds::FLY_AT_PAGE == nAnchorId )
581 pNewAnch = pTextFrame->FindPageFrame();
583 else
585 pNewAnch = ::FindAnchor( pTextFrame, rAbsPos );
587 if( RndStdIds::FLY_AT_FLY == nAnchorId ) // LAYER_IMPL
589 pNewAnch = pNewAnch->FindFlyFrame();
594 if( pNewAnch && !pNewAnch->IsProtected() )
596 const SwFlyFrame* pCheck = (bFlyFrame || bTextBox) ? pNewAnch->FindFlyFrame() : nullptr;
597 // If we land inside the frame, make sure
598 // that the frame does not land inside its own content
599 while( pCheck )
601 if( pCheck == pFly )
602 break;
603 const SwFrame *pTmp = pCheck->GetAnchorFrame();
604 pCheck = pTmp ? pTmp->FindFlyFrame() : nullptr;
607 // Do not switch from header/footer to another area,
608 // do not switch to a header/footer
609 if( !pCheck &&
610 pFooterOrHeader == pNewAnch->FindFooterOrHeader() )
612 aRet = pNewAnch->GetFrameAnchorPos( ::HasWrap( pObj ) );
614 if ( bMoveIt || (nAnchorId == RndStdIds::FLY_AT_CHAR) )
616 SwFormatAnchor aAnch( pFormat->GetAnchor() );
617 switch ( nAnchorId )
619 case RndStdIds::FLY_AT_PARA:
621 SwPosition pos(pTextFrame->IsTextFrame()
622 ? *static_cast<SwTextFrame const*>(pTextFrame)->GetTextNodeForParaProps()
623 : *static_cast<const SwNoTextFrame*>(pTextFrame)->GetNode());
624 aAnch.SetAnchor( &pos );
625 break;
627 case RndStdIds::FLY_AT_PAGE:
629 aAnch.SetPageNum( static_cast<const SwPageFrame*>(pNewAnch)->
630 GetPhyPageNum() );
631 break;
634 case RndStdIds::FLY_AT_FLY:
636 SwPosition aPos( *static_cast<const SwFlyFrame*>(pNewAnch)->GetFormat()->
637 GetContent().GetContentIdx() );
638 aAnch.SetAnchor( &aPos );
639 break;
642 case RndStdIds::FLY_AT_CHAR:
644 SwPosition pos = *aAnch.GetContentAnchor();
645 Point aTmpPnt( rAbsPos );
646 if( pTextFrame->GetModelPositionForViewPoint( &pos, aTmpPnt ) )
648 SwRect aTmpRect;
649 pTextFrame->GetCharRect( aTmpRect, pos );
650 aRet = aTmpRect.Pos();
652 else
654 pos = static_cast<SwTextFrame const*>(pTextFrame)->MapViewToModelPos(TextFrameIndex(0));
656 aAnch.SetAnchor( &pos );
657 break;
659 default:
660 break;
664 if( bMoveIt )
666 StartAllAction();
667 // --> handle change of anchor node:
668 // if count of the anchor frame also change, the fly frames have to be
669 // re-created. Thus, delete all fly frames except the <this> before the
670 // anchor attribute is change and re-create them afterwards.
672 std::unique_ptr<SwHandleAnchorNodeChg> pHandleAnchorNodeChg;
673 SwFlyFrameFormat* pFlyFrameFormat( dynamic_cast<SwFlyFrameFormat*>(pFormat) );
674 if ( pFlyFrameFormat )
676 pHandleAnchorNodeChg.reset(
677 new SwHandleAnchorNodeChg( *pFlyFrameFormat, aAnch ));
679 pFormat->GetDoc()->SetAttr( aAnch, *pFormat );
680 if (SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT,
681 pObj))
683 if (SdrObjList* pObjList = pObj->getChildrenOfSdrObject())
685 for (const rtl::Reference<SdrObject>& pChild : *pObjList)
686 SwTextBoxHelper::changeAnchor(pFormat, pChild.get());
688 else
689 SwTextBoxHelper::syncFlyFrameAttr(
690 *pFormat, pFormat->GetAttrSet(), pObj);
693 // #i28701# - no call of method
694 // <CheckCharRectAndTopOfLine()> for to-character anchored
695 // Writer fly frame needed. This method call can cause a
696 // format of the anchor frame, which is no longer intended.
697 // Instead clear the anchor character rectangle and
698 // the top of line values for all to-character anchored objects.
699 pAnchoredObj->ClearCharRectAndTopOfLine();
700 EndAllAction();
704 SwRect aTmpRect( aRet, rAbsPos );
705 if( aTmpRect.HasArea() )
706 MakeVisible( aTmpRect );
707 #if OSL_DEBUG_LEVEL > 0
708 //TODO: That doesn't seem to be intended
709 if( COL_TRANSPARENT != GetOut()->GetLineColor() )
711 OSL_FAIL( "Hey, Joe: Where's my Null Pen?" );
712 GetOut()->SetLineColor( COL_TRANSPARENT );
714 #endif
718 return aRet;
721 const SwFrameFormat *SwFEShell::NewFlyFrame( const SfxItemSet& rSet, bool bAnchValid,
722 SwFrameFormat *pParent )
724 CurrShell aCurr( this );
725 StartAllAction();
727 SwPaM* pCursor = GetCursor();
728 const Point aPt( GetCursorDocPos() );
730 SwSelBoxes aBoxes;
731 bool bMoveContent = true;
732 if( IsTableMode() )
734 GetTableSel( *this, aBoxes );
735 if( !aBoxes.empty() )
737 // Cursor should be removed from the removal area.
738 // Always put it after/on the table; via the
739 // document position they will be set to the old
740 // position
741 ParkCursor( *aBoxes[0]->GetSttNd() );
743 // #i127787# pCurrentCursor will be deleted in ParkCursor,
744 // we better get the current pCurrentCursor instead of working with the
745 // deleted one:
746 pCursor = GetCursor();
748 else
749 bMoveContent = false;
751 else if( !pCursor->HasMark() && !pCursor->IsMultiSelection() )
752 bMoveContent = false;
754 const SwPosition& rPos = *pCursor->Start();
756 SwFormatAnchor& rAnch = const_cast<SwFormatAnchor&>(rSet.Get( RES_ANCHOR ));
757 RndStdIds eRndId = rAnch.GetAnchorId();
758 switch( eRndId )
760 case RndStdIds::FLY_AT_PAGE:
761 if( !rAnch.GetPageNum() ) //HotFix: Bug in UpdateByExample
762 rAnch.SetPageNum( 1 );
763 break;
765 case RndStdIds::FLY_AT_FLY:
766 case RndStdIds::FLY_AT_PARA:
767 case RndStdIds::FLY_AT_CHAR:
768 case RndStdIds::FLY_AS_CHAR:
769 if( !bAnchValid )
771 if( RndStdIds::FLY_AT_FLY != eRndId )
773 rAnch.SetAnchor( &rPos );
775 else if( lcl_SetNewFlyPos( rPos.GetNode(), rAnch, aPt ) )
777 eRndId = RndStdIds::FLY_AT_PAGE;
780 break;
782 default:
783 OSL_ENSURE( false, "What is the purpose of this Fly?" );
784 break;
787 SwFlyFrameFormat *pRet;
788 if( bMoveContent )
790 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::INSLAYFMT, nullptr );
791 std::unique_ptr<SwFormatAnchor> pOldAnchor;
792 bool bHOriChgd = false, bVOriChgd = false;
793 std::shared_ptr<SwFormatVertOrient> aOldV;
794 std::shared_ptr<SwFormatHoriOrient> aOldH;
796 if ( RndStdIds::FLY_AT_PAGE != eRndId )
798 // First as with page link. Paragraph/character link on if
799 // everything was shifted. Then the position is valid!
800 // JP 13.05.98: if necessary also convert the horizontal/vertical
801 // orientation, to prevent correction during re-anchoring
802 pOldAnchor.reset(new SwFormatAnchor( rAnch ));
803 const_cast<SfxItemSet&>(rSet).Put( SwFormatAnchor( RndStdIds::FLY_AT_PAGE, 1 ) );
805 const SwFormatHoriOrient* pHoriOrientItem;
806 if( (pHoriOrientItem = rSet.GetItemIfSet( RES_HORI_ORIENT, false ))
807 && text::HoriOrientation::NONE == pHoriOrientItem->GetHoriOrient() )
809 bHOriChgd = true;
810 aOldH.reset(pHoriOrientItem->Clone());
811 const_cast<SfxItemSet&>(rSet).Put( SwFormatHoriOrient( 0, text::HoriOrientation::LEFT ) );
813 const SwFormatVertOrient* pVertOrientItem;
814 if( (pVertOrientItem = rSet.GetItemIfSet( RES_VERT_ORIENT, false ))
815 && text::VertOrientation::NONE == pVertOrientItem->GetVertOrient() )
817 bVOriChgd = true;
818 aOldV.reset(pVertOrientItem->Clone());
819 const_cast<SfxItemSet&>(rSet).Put( SwFormatVertOrient( 0, text::VertOrientation::TOP ) );
823 pRet = GetDoc()->MakeFlyAndMove( *pCursor, rSet, &aBoxes, pParent );
825 KillPams();
827 if( pOldAnchor )
829 if( pRet )
831 // calculate new position
832 // JP 24.03.97: also go via page links
833 // anchor should not lie in the shifted area
834 pRet->DelFrames();
836 const SwFrame* pAnch = ::FindAnchor( GetLayout(), aPt );
837 SwPosition aPos( pAnch->IsTextFrame()
838 ? *static_cast<SwTextFrame const*>(pAnch)->GetTextNodeForParaProps()
839 : *static_cast<const SwNoTextFrame*>(pAnch)->GetNode() );
841 if ( RndStdIds::FLY_AS_CHAR == eRndId )
843 assert(pAnch->IsTextFrame());
844 aPos = static_cast<SwTextFrame const*>(pAnch)->MapViewToModelPos(TextFrameIndex(0));
846 pOldAnchor->SetAnchor( &aPos );
848 // shifting of table selection is not Undo-capable. therefore
849 // changing the anchors should not be recorded
850 bool const bDoesUndo =
851 GetDoc()->GetIDocumentUndoRedo().DoesUndo();
852 SwUndoId nLastUndoId(SwUndoId::EMPTY);
853 if (bDoesUndo &&
854 GetDoc()->GetIDocumentUndoRedo().GetLastUndoInfo(nullptr,
855 & nLastUndoId))
857 if (SwUndoId::INSLAYFMT == nLastUndoId)
859 GetDoc()->GetIDocumentUndoRedo().DoUndo(false);
863 const_cast<SfxItemSet&>(rSet).Put( std::move(pOldAnchor) );
865 if( bHOriChgd )
866 const_cast<SfxItemSet&>(rSet).Put( *aOldH );
867 if( bVOriChgd )
868 const_cast<SfxItemSet&>(rSet).Put( *aOldV );
870 GetDoc()->SetFlyFrameAttr( *pRet, const_cast<SfxItemSet&>(rSet) );
871 GetDoc()->GetIDocumentUndoRedo().DoUndo(bDoesUndo);
874 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::INSLAYFMT, nullptr );
876 else
877 /* If called from a shell try to propagate an
878 existing adjust item from rPos to the content node of the
879 new frame. */
880 pRet = GetDoc()->MakeFlySection( eRndId, &rPos, &rSet, pParent, true );
882 if( pRet )
884 SwFlyFrame* pFrame = pRet->GetFrame( &aPt );
885 if( pFrame )
886 SelectFlyFrame( *pFrame );
887 else
889 GetLayout()->SetAssertFlyPages();
890 pRet = nullptr;
893 EndAllActionAndCall();
895 return pRet;
898 namespace
900 /// If pCursor points to an as-char anchored graphic node, then set the node's anchor position on
901 /// pAnchor and rPam.
902 bool SetAnchorOnGrfNodeForAsChar(SwShellCursor *pCursor, SwFormatAnchor* pAnchor, std::optional<SwPaM>& rPam)
904 const SwPosition* pPoint = pCursor->GetPoint();
905 if (pAnchor->GetAnchorId() != RndStdIds::FLY_AS_CHAR)
907 return false;
910 if (!pPoint->GetNode().IsGrfNode())
912 return false;
915 SwFrameFormat* pFrameFormat = pPoint->GetNode().GetFlyFormat();
916 if (!pFrameFormat)
918 return false;
921 const SwPosition* pContentAnchor = pFrameFormat->GetAnchor().GetContentAnchor();
922 if (!pContentAnchor)
924 return false;
927 SwPosition aPosition(*pContentAnchor);
928 ++aPosition.nContent;
929 pAnchor->SetAnchor(&aPosition);
930 rPam.emplace(aPosition);
931 return true;
935 void SwFEShell::Insert( const OUString& rGrfName, const OUString& rFltName,
936 const Graphic* pGraphic,
937 const SfxItemSet* pFlyAttrSet )
939 SwFlyFrameFormat* pFormat = nullptr;
940 CurrShell aCurr( this );
941 StartAllAction();
942 SwShellCursor *pStartCursor = dynamic_cast<SwShellCursor*>(GetCursor());
943 SwShellCursor *pCursor = pStartCursor;
946 if (!pCursor)
947 break;
949 // Has the anchor not been set or been set incompletely?
950 std::optional<SwPaM> oPam;
951 if( pFlyAttrSet )
953 if( const SwFormatAnchor* pItem = pFlyAttrSet->GetItemIfSet( RES_ANCHOR, false ) )
955 SwFormatAnchor* pAnchor = const_cast<SwFormatAnchor*>(pItem);
956 switch( pAnchor->GetAnchorId())
958 case RndStdIds::FLY_AT_PARA:
959 case RndStdIds::FLY_AT_CHAR: // LAYER_IMPL
960 case RndStdIds::FLY_AS_CHAR:
961 if( !pAnchor->GetAnchorNode() )
963 if (SetAnchorOnGrfNodeForAsChar(pCursor, pAnchor, oPam))
965 // Don't anchor the image on the previous image, rather insert them next
966 // to each other.
967 break;
970 pAnchor->SetAnchor( pCursor->GetPoint() );
972 break;
973 case RndStdIds::FLY_AT_FLY:
974 if( !pAnchor->GetAnchorNode() )
976 lcl_SetNewFlyPos( pCursor->GetPointNode(),
977 *pAnchor, GetCursorDocPos() );
979 break;
980 case RndStdIds::FLY_AT_PAGE:
981 if( !pAnchor->GetPageNum() )
983 pAnchor->SetPageNum( pCursor->GetPageNum(
984 true, &pCursor->GetPtPos() ) );
986 break;
987 default :
988 break;
992 pFormat = GetDoc()->getIDocumentContentOperations().InsertGraphic(
993 oPam.has_value() ? *oPam : *pCursor, rGrfName,
994 rFltName, pGraphic,
995 pFlyAttrSet,
996 nullptr, nullptr );
997 OSL_ENSURE(pFormat, "IDocumentContentOperations::InsertGraphic failed.");
999 pCursor = pCursor->GetNext();
1000 } while( pCursor != pStartCursor );
1002 EndAllAction();
1004 if( !pFormat )
1005 return;
1007 const Point aPt( GetCursorDocPos() );
1008 SwFlyFrame* pFrame = pFormat->GetFrame( &aPt );
1010 if( pFrame )
1012 // add a redline to the anchor point at tracked insertion of picture
1013 if ( IsRedlineOn() )
1015 const SwPosition & rPos(*pFormat->GetAnchor().GetContentAnchor());
1016 SwPaM aPaM(rPos.GetNode(), rPos.GetContentIndex(),
1017 rPos.GetNode(), rPos.GetContentIndex() + 1);
1018 GetDoc()->getIDocumentRedlineAccess().AppendRedline(
1019 new SwRangeRedline( RedlineType::Insert, aPaM ), true);
1022 // fdo#36681: Invalidate the content and layout to refresh
1023 // the picture anchoring properly
1024 SwPageFrame* pPageFrame = pFrame->FindPageFrameOfAnchor();
1025 pPageFrame->InvalidateFlyLayout();
1026 pPageFrame->InvalidateContent();
1028 SelectFlyFrame( *pFrame );
1030 else
1031 GetLayout()->SetAssertFlyPages();
1034 SwFlyFrameFormat* SwFEShell::InsertObject( const svt::EmbeddedObjectRef& xObj,
1035 SfxItemSet* pFlyAttrSet )
1037 SwFlyFrameFormat* pFormat = nullptr;
1038 CurrShell aCurr( this );
1039 StartAllAction();
1041 for(const SwPaM& rPaM : GetCursor()->GetRingContainer())
1043 pFormat = GetDoc()->getIDocumentContentOperations().InsertEmbObject(
1044 rPaM, xObj, pFlyAttrSet );
1045 OSL_ENSURE(pFormat, "IDocumentContentOperations::InsertEmbObject failed.");
1048 EndAllAction();
1050 if( pFormat )
1052 const Point aPt( GetCursorDocPos() );
1053 SwFlyFrame* pFrame = pFormat->GetFrame( &aPt );
1055 if( pFrame )
1056 SelectFlyFrame( *pFrame );
1057 else
1058 GetLayout()->SetAssertFlyPages();
1061 return pFormat;
1064 void SwFEShell::InsertDrawObj( SdrObject& rDrawObj,
1065 const Point& rInsertPosition )
1067 CurrShell aCurr( this );
1069 SfxItemSet rFlyAttrSet( GetDoc()->GetAttrPool(), aFrameFormatSetRange );
1070 rFlyAttrSet.Put( SwFormatAnchor( RndStdIds::FLY_AT_PARA ));
1071 // #i89920#
1072 rFlyAttrSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) );
1073 rDrawObj.SetLayer( getIDocumentDrawModelAccess().GetHeavenId() );
1075 // find anchor position
1076 SwPaM aPam( mxDoc->GetNodes() );
1078 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
1079 Point aTmpPt( rInsertPosition );
1080 GetLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aTmpPt, &aState );
1081 const SwFrame* pFrame = aPam.GetPointContentNode()->getLayoutFrame(GetLayout(), nullptr, nullptr);
1082 const Point aRelPos( rInsertPosition.X() - pFrame->getFrameArea().Left(),
1083 rInsertPosition.Y() - pFrame->getFrameArea().Top() );
1084 rDrawObj.SetRelativePos( aRelPos );
1085 ::lcl_FindAnchorPos( *GetDoc(), rInsertPosition, *pFrame, rFlyAttrSet );
1087 // insert drawing object into the document creating a new <SwDrawFrameFormat> instance
1088 SwDrawFrameFormat* pFormat = GetDoc()->getIDocumentContentOperations().InsertDrawObj( aPam, rDrawObj, rFlyAttrSet );
1090 // move object to visible layer
1091 SwContact* pContact = static_cast<SwContact*>(rDrawObj.GetUserCall());
1092 if ( pContact )
1094 pContact->MoveObjToVisibleLayer( &rDrawObj );
1097 if (pFormat)
1099 pFormat->SetFormatName(rDrawObj.GetName());
1100 // select drawing object
1101 Imp()->GetDrawView()->MarkObj( &rDrawObj, Imp()->GetPageView() );
1103 else
1105 GetLayout()->SetAssertFlyPages();
1109 void SwFEShell::GetPageObjs( std::vector<SwFrameFormat*>& rFillArr )
1111 rFillArr.clear();
1113 for(sw::SpzFrameFormat* pFormat : *mxDoc->GetSpzFrameFormats() )
1115 if (RndStdIds::FLY_AT_PAGE == pFormat->GetAnchor().GetAnchorId())
1117 rFillArr.push_back( pFormat );
1122 void SwFEShell::SetPageObjsNewPage( std::vector<SwFrameFormat*>& rFillArr )
1124 if( rFillArr.empty() )
1125 return;
1127 StartAllAction();
1128 StartUndo();
1130 SwRootFrame* pTmpRootFrame = GetLayout();
1131 sal_uInt16 nMaxPage = pTmpRootFrame->GetPageNum();
1132 bool bTmpAssert = false;
1133 for( auto pFormat : rFillArr )
1135 if (mxDoc->GetSpzFrameFormats()->IsAlive(static_cast<sw::SpzFrameFormat*>(pFormat)))
1137 // FlyFormat is still valid, therefore process
1139 SwFormatAnchor aNewAnchor( pFormat->GetAnchor() );
1140 if (RndStdIds::FLY_AT_PAGE != aNewAnchor.GetAnchorId())
1141 // Anchor has been changed, therefore: do not change!
1142 continue;
1143 sal_uInt16 nNewPage = aNewAnchor.GetPageNum() + 1;
1144 if (nNewPage > nMaxPage)
1146 if ( RES_DRAWFRMFMT == pFormat->Which() )
1147 pFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS));
1148 else
1149 pFormat->DelFrames();
1150 bTmpAssert = true;
1152 aNewAnchor.SetPageNum(nNewPage);
1153 mxDoc->SetAttr( aNewAnchor, *pFormat );
1157 if( bTmpAssert )
1158 pTmpRootFrame->SetAssertFlyPages();
1160 EndUndo();
1161 EndAllAction();
1164 // All attributes in the "baskets" will be filled with the attributes of the
1165 // current FlyFrames. Attributes which cannot be filled due to being at the
1166 // wrong place or which are ambiguous (multiple selections) will be removed.
1167 bool SwFEShell::GetFlyFrameAttr( SfxItemSet &rSet ) const
1169 SwFlyFrame *pFly = GetSelectedOrCurrFlyFrame();
1170 if (!pFly)
1172 OSL_ENSURE( false, "GetFlyFrameAttr, no Fly selected." );
1173 return false;
1176 CurrShell aCurr( const_cast<SwFEShell*>(this) );
1178 if( !rSet.Set( pFly->GetFormat()->GetAttrSet() ) )
1179 return false;
1181 // now examine all attributes. Remove forbidden attributes, then
1182 // get all remaining attributes and enter them
1184 if( const SwFormatAnchor* pAnchor = rSet.GetItemIfSet( RES_ANCHOR, false ) )
1186 RndStdIds eType = pAnchor->GetAnchorId();
1188 if ( RndStdIds::FLY_AT_PAGE != eType )
1190 // OD 12.11.2003 #i22341# - content anchor of anchor item is needed.
1191 // Thus, don't overwrite anchor item by default constructed anchor item.
1192 if ( RndStdIds::FLY_AS_CHAR == eType )
1194 rSet.ClearItem( RES_OPAQUE );
1195 rSet.ClearItem( RES_SURROUND );
1199 rSet.SetParent( pFly->GetFormat()->GetAttrSet().GetParent() );
1200 // attributes must be removed
1201 rSet.ClearItem( RES_FILL_ORDER );
1202 rSet.ClearItem( RES_CNTNT );
1203 //MA: remove first (Template by example etc.)
1204 rSet.ClearItem( RES_CHAIN );
1205 return true;
1208 // Attributes of the current fly will change.
1209 bool SwFEShell::SetFlyFrameAttr( SfxItemSet& rSet )
1211 CurrShell aCurr( this );
1212 bool bRet = false;
1214 if( rSet.Count() )
1216 SwFlyFrame *pFly = GetSelectedOrCurrFlyFrame();
1217 OSL_ENSURE(pFly, "SetFlyFrameAttr, no Fly selected.");
1218 if (pFly)
1220 StartAllAction();
1221 const Point aPt( pFly->getFrameArea().Pos() );
1223 if( SfxItemState::SET == rSet.GetItemState( RES_ANCHOR, false ))
1224 sw_ChkAndSetNewAnchor( *pFly, rSet );
1225 SwFlyFrameFormat* pFlyFormat = pFly->GetFormat();
1227 if( GetDoc()->SetFlyFrameAttr( *pFlyFormat, rSet ))
1229 bRet = true;
1230 SwFlyFrame* pFrame = pFlyFormat->GetFrame( &aPt );
1231 if( pFrame )
1232 SelectFlyFrame( *pFrame );
1233 else
1234 GetLayout()->SetAssertFlyPages();
1237 EndAllActionAndCall();
1240 return bRet;
1243 SfxItemSetFixed<RES_VERT_ORIENT, RES_ANCHOR> SwFEShell::makeItemSetFromFormatAnchor(SfxItemPool& rPool, const SwFormatAnchor &rAnchor)
1245 // The set also includes VERT/HORI_ORIENT, because the align
1246 // shall be changed in FEShell::SetFlyFrameAttr/SetFlyFrameAnchor,
1247 // possibly as a result of the anchor change.
1248 SfxItemSetFixed<RES_VERT_ORIENT, RES_ANCHOR> aSet(rPool);
1249 aSet.Put(rAnchor);
1250 return aSet;
1253 bool SwFEShell::SetDrawingAttr( SfxItemSet& rSet )
1255 bool bRet = false;
1256 CurrShell aCurr( this );
1257 if ( !rSet.Count() ||
1258 !Imp()->HasDrawView() )
1259 return bRet;
1261 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1262 if ( rMrkList.GetMarkCount() != 1 )
1263 return bRet;
1265 StartUndo();
1266 SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
1267 SwFrameFormat *pFormat = FindFrameFormat( pObj );
1268 StartAllAction();
1269 if( SfxItemState::SET == rSet.GetItemState( RES_ANCHOR, false ))
1271 RndStdIds nNew = rSet.Get( RES_ANCHOR ).GetAnchorId();
1272 if ( nNew != pFormat->GetAnchor().GetAnchorId() )
1274 ChgAnchor( nNew );
1275 // #i26791# - clear anchor attribute in item set,
1276 // because method <ChgAnchor(..)> takes care of it.
1277 rSet.ClearItem( RES_ANCHOR );
1281 if( GetDoc()->SetFlyFrameAttr( *pFormat, rSet ))
1283 bRet = true;
1284 SelectObj( Point(), 0, pObj );
1286 EndAllActionAndCall();
1287 EndUndo();
1288 return bRet;
1291 // Reset attributes contained in the set.
1292 void SwFEShell::ResetFlyFrameAttr( const SfxItemSet* pSet )
1294 CurrShell aCurr( this );
1296 SwFlyFrame *pFly = GetSelectedOrCurrFlyFrame();
1297 OSL_ENSURE( pFly, "SetFlyFrameAttr, no Fly selected." );
1298 if( !pFly )
1299 return;
1301 StartAllAction();
1303 SfxItemIter aIter( *pSet );
1304 for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
1306 if( !IsInvalidItem( pItem ) )
1308 sal_uInt16 nWhich = pItem->Which();
1309 if( RES_ANCHOR != nWhich && RES_CHAIN != nWhich && RES_CNTNT != nWhich )
1310 pFly->GetFormat()->ResetFormatAttr( nWhich );
1314 EndAllActionAndCall();
1315 GetDoc()->getIDocumentState().SetModified();
1318 // Returns frame-format if frame, otherwise 0
1319 SwFrameFormat* SwFEShell::GetSelectedFrameFormat() const
1321 SwFrameFormat* pRet = nullptr;
1322 SwLayoutFrame *pFly = GetSelectedFlyFrame();
1323 if( pFly && ( pRet = static_cast<SwFrameFormat*>(pFly->GetFormat()->DerivedFrom()) ) ==
1324 GetDoc()->GetDfltFrameFormat() )
1325 pRet = nullptr;
1326 return pRet;
1329 void SwFEShell::SetFrameFormat( SwFrameFormat *pNewFormat, bool bKeepOrient, Point const * pDocPos )
1331 SwFlyFrame *pFly = nullptr;
1332 if(pDocPos)
1334 const SwFrameFormat* pFormat = GetFormatFromObj( *pDocPos );
1336 if (const SwFlyFrameFormat* pFlyFormat = dynamic_cast<const SwFlyFrameFormat*>(pFormat))
1337 pFly = pFlyFormat->GetFrame();
1339 else
1340 pFly = GetSelectedFlyFrame();
1341 OSL_ENSURE( pFly, "SetFrameFormat: no frame" );
1342 if( !pFly )
1343 return;
1345 StartAllAction();
1346 CurrShell aCurr( this );
1348 SwFlyFrameFormat* pFlyFormat = pFly->GetFormat();
1349 const Point aPt( pFly->getFrameArea().Pos() );
1351 std::optional<SfxItemSet> oSet;
1352 const SfxPoolItem* pItem;
1353 if( SfxItemState::SET == pNewFormat->GetItemState( RES_ANCHOR, false, &pItem ))
1355 oSet.emplace( GetDoc()->GetAttrPool(), aFrameFormatSetRange );
1356 oSet->Put( *pItem );
1357 if( !sw_ChkAndSetNewAnchor( *pFly, *oSet ))
1359 oSet.reset();
1363 if( GetDoc()->SetFrameFormatToFly( *pFlyFormat, *pNewFormat, oSet ? &*oSet : nullptr, bKeepOrient ))
1365 SwFlyFrame* pFrame = pFlyFormat->GetFrame( &aPt );
1366 if( pFrame )
1367 SelectFlyFrame( *pFrame );
1368 else
1369 GetLayout()->SetAssertFlyPages();
1371 oSet.reset();
1373 EndAllActionAndCall();
1376 const SwFrameFormat* SwFEShell::GetFlyFrameFormat() const
1378 const SwFlyFrame* pFly = GetSelectedOrCurrFlyFrame();
1379 if (pFly)
1380 return pFly->GetFormat();
1381 return nullptr;
1384 SwFrameFormat* SwFEShell::GetFlyFrameFormat()
1386 SwFlyFrame* pFly = GetSelectedOrCurrFlyFrame();
1387 if (pFly)
1388 return pFly->GetFormat();
1389 return nullptr;
1392 SwRect SwFEShell::GetFlyRect() const
1394 SwFlyFrame *pFly = GetCurrFlyFrame(false);
1395 if (!pFly)
1397 SwRect aRect;
1398 return aRect;
1400 else
1401 return pFly->getFrameArea();
1404 SwRect SwFEShell::GetObjRect() const
1406 if( Imp()->HasDrawView() )
1407 return SwRect(Imp()->GetDrawView()->GetAllMarkedRect());
1408 else
1410 SwRect aRect;
1411 return aRect;
1415 void SwFEShell::SetObjRect( const SwRect& rRect )
1417 if ( Imp()->HasDrawView() )
1419 Imp()->GetDrawView()->SetAllMarkedRect( rRect.SVRect() );
1420 CallChgLnk(); // call AttrChangeNotify on the UI-side.
1424 Size SwFEShell::RequestObjectResize( const SwRect &rRect, const uno::Reference < embed::XEmbeddedObject >& xObj )
1426 Size aResult;
1428 SwFlyFrame *pFly = FindFlyFrame( xObj );
1429 if ( !pFly )
1431 aResult = rRect.SSize();
1432 return aResult;
1435 aResult = pFly->getFramePrintArea().SSize();
1437 bool bPosProt = pFly->GetFormat()->GetProtect().IsPosProtected();
1438 bool bSizeProt = pFly->GetFormat()->GetProtect().IsSizeProtected();
1440 StartAllAction();
1442 // MA we do not allow to clip the Fly, as the OLE server can
1443 // request various wishes. Clipping is done via the formatting.
1444 // Correct display is done by scaling.
1445 // Scaling is done by SwNoTextFrame::Format by calling
1446 // SwWrtShell::CalcAndSetScale()
1447 if ( rRect.SSize() != pFly->getFramePrintArea().SSize() && !bSizeProt )
1449 Size aSz( rRect.SSize() );
1451 //JP 28.02.2001: Task 74707 - ask for fly in fly with automatic size
1453 const SwFrame* pAnchor;
1454 const SwFormatFrameSize& rFrameSz = pFly->GetFormat()->GetFrameSize();
1455 if (m_bCheckForOLEInCaption &&
1456 0 != rFrameSz.GetWidthPercent() &&
1457 nullptr != (pAnchor = pFly->GetAnchorFrame()) &&
1458 pAnchor->IsTextFrame() &&
1459 !pAnchor->GetNext() && !pAnchor->GetPrev() &&
1460 pAnchor->GetUpper()->IsFlyFrame())
1462 // search for a sequence field:
1463 sw::MergedAttrIter iter(*static_cast<SwTextFrame const*>(pAnchor));
1464 for (SwTextAttr const* pHint = iter.NextAttr(); pHint; pHint = iter.NextAttr())
1466 const SfxPoolItem* pItem = &pHint->GetAttr();
1467 if( RES_TXTATR_FIELD == pItem->Which()
1468 && SwFieldTypesEnum::Sequence == static_cast<const SwFormatField*>(pItem)->GetField()->GetTypeId() )
1470 // sequence field found
1471 SwFlyFrame* pChgFly = const_cast<SwFlyFrame*>(static_cast<const SwFlyFrame*>(pAnchor->GetUpper()));
1472 // calculate the changed size:
1473 // width must change, height can change
1474 Size aNewSz( aSz.Width() + pChgFly->getFrameArea().Width() -
1475 pFly->getFramePrintArea().Width(), aSz.Height() );
1477 SwFrameFormat *pFormat = pChgFly->GetFormat();
1478 SwFormatFrameSize aFrameSz( pFormat->GetFrameSize() );
1479 aFrameSz.SetWidth( aNewSz.Width() );
1480 if( SwFrameSize::Minimum != aFrameSz.GetHeightSizeType() )
1482 aNewSz.AdjustHeight(pChgFly->getFrameArea().Height() -
1483 pFly->getFramePrintArea().Height() );
1484 if( std::abs( aNewSz.Height() - pChgFly->getFrameArea().Height()) > 1 )
1485 aFrameSz.SetHeight( aNewSz.Height() );
1487 // via Doc for the Undo!
1488 pFormat->GetDoc()->SetAttr( aFrameSz, *pFormat );
1489 break;
1494 // set the new Size at the fly themself
1495 if ( !pFly->getFramePrintArea().IsEmpty() )
1497 aSz.AdjustWidth(pFly->getFrameArea().Width() - pFly->getFramePrintArea().Width() );
1498 aSz.AdjustHeight(pFly->getFrameArea().Height()- pFly->getFramePrintArea().Height() );
1500 aResult = pFly->ChgSize( aSz );
1502 // if the object changes, the contour is outside the object
1503 SwFrame* pLower = pFly->Lower();
1504 assert(pLower && pLower->IsNoTextFrame());
1505 SwNoTextNode *pNd = static_cast<SwNoTextFrame*>(pLower)->GetNode()->GetNoTextNode();
1506 assert(pNd);
1507 pNd->SetContour( nullptr );
1508 ClrContourCache();
1511 // if only the size is to be adjusted, a position is transported with
1512 // allocated values
1513 Point aPt( pFly->getFramePrintArea().Pos() );
1514 aPt += pFly->getFrameArea().Pos();
1515 if ( rRect.Top() != LONG_MIN && rRect.Pos() != aPt && !bPosProt )
1517 aPt = rRect.Pos();
1518 aPt.setX(aPt.getX() - pFly->getFramePrintArea().Left());
1519 aPt.setY(aPt.getY() - pFly->getFramePrintArea().Top());
1521 // in case of paragraph-bound Flys, starting from the new position,
1522 // a new anchor is to be set. The anchor and the new RelPos are
1523 // calculated by the Fly and set
1524 if( pFly->IsFlyAtContentFrame() )
1525 static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos( aPt );
1526 else
1528 const SwFrameFormat *pFormat = pFly->GetFormat();
1529 const SwFormatVertOrient &rVert = pFormat->GetVertOrient();
1530 const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient();
1531 const tools::Long lXDiff = aPt.getX() - pFly->getFrameArea().Left();
1532 const tools::Long lYDiff = aPt.getY() - pFly->getFrameArea().Top();
1533 const Point aTmp( rHori.GetPos() + lXDiff,
1534 rVert.GetPos() + lYDiff );
1535 pFly->ChgRelPos( aTmp );
1539 SwFlyFrameFormat *pFlyFrameFormat = pFly->GetFormat();
1540 OSL_ENSURE( pFlyFrameFormat, "fly frame format missing!" );
1541 if ( pFlyFrameFormat )
1542 pFlyFrameFormat->SetLastFlyFramePrtRectPos( pFly->getFramePrintArea().Pos() ); //stores the value of last Prt rect
1544 EndAllAction();
1546 return aResult;
1549 SwFrameFormat* SwFEShell::WizardGetFly()
1551 // do not search the Fly via the layout. Now we can delete a frame
1552 // without a valid layout. ( e.g. for the wizards )
1553 sw::SpzFrameFormats& rSpzArr = *mxDoc->GetSpzFrameFormats();
1554 if( !rSpzArr.empty() )
1556 SwNode& rCursorNd = GetCursor()->GetPoint()->GetNode();
1557 if( rCursorNd > mxDoc->GetNodes().GetEndOfExtras() )
1558 // Cursor is in the body area!
1559 return nullptr;
1561 for( auto pFormat : rSpzArr )
1563 const SwNodeIndex* pIdx = pFormat->GetContent( false ).GetContentIdx();
1564 SwStartNode* pSttNd;
1565 if( pIdx &&
1566 nullptr != ( pSttNd = pIdx->GetNode().GetStartNode() ) &&
1567 *pSttNd < rCursorNd &&
1568 rCursorNd < *pSttNd->EndOfSectionNode() )
1570 // found: return immediately
1571 return pFormat;
1575 return nullptr;
1578 void SwFEShell::SetFlyName( const OUString& rName )
1580 SwLayoutFrame *pFly = GetSelectedFlyFrame();
1581 if( pFly )
1582 GetDoc()->SetFlyName( *static_cast<SwFlyFrameFormat*>(pFly->GetFormat()), rName );
1583 else {
1584 OSL_ENSURE( false, "no FlyFrame selected" );
1588 OUString SwFEShell::GetFlyName() const
1590 SwLayoutFrame *pFly = GetSelectedFlyFrame();
1591 if( pFly )
1592 return pFly->GetFormat()->GetName();
1594 OSL_ENSURE( false, "no FlyFrame selected" );
1595 return OUString();
1598 uno::Reference < embed::XEmbeddedObject > SwFEShell::GetOleRef() const
1600 uno::Reference < embed::XEmbeddedObject > xObj;
1601 SwFlyFrame * pFly = GetSelectedFlyFrame();
1602 SwFrame* pLower = pFly ? pFly->Lower() : nullptr;
1603 if (pLower && pLower->IsNoTextFrame())
1605 SwOLENode *pNd = static_cast<SwNoTextFrame*>(pLower)->GetNode()->GetOLENode();
1606 if (pNd)
1607 xObj = pNd->GetOLEObj().GetOleRef();
1609 return xObj;
1612 OUString SwFEShell::GetUniqueGrfName() const
1614 return GetDoc()->GetUniqueGrfName();
1617 const SwFrameFormat* SwFEShell::IsURLGrfAtPos( const Point& rPt, OUString* pURL,
1618 OUString *pTargetFrameName,
1619 OUString *pDescription ) const
1621 if( !Imp()->HasDrawView() )
1622 return nullptr;
1624 SdrPageView* pPV;
1625 const SwFrameFormat* pRet = nullptr;
1626 SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
1628 const auto nOld = pDView->GetHitTolerancePixel();
1629 pDView->SetHitTolerancePixel( 2 );
1631 SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO);
1632 SwVirtFlyDrawObj* pFlyObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
1633 if (pFlyObj)
1635 SwFlyFrame *pFly = pFlyObj->GetFlyFrame();
1636 const SwFormatURL &rURL = pFly->GetFormat()->GetURL();
1637 if( !rURL.GetURL().isEmpty() || rURL.GetMap() )
1639 bool bSetTargetFrameName = pTargetFrameName != nullptr;
1640 bool bSetDescription = pDescription != nullptr;
1641 if ( rURL.GetMap() )
1643 IMapObject *pObject = pFly->GetFormat()->GetIMapObject( rPt, pFly );
1644 if ( pObject && !pObject->GetURL().isEmpty() )
1646 if( pURL )
1647 *pURL = pObject->GetURL();
1648 if ( bSetTargetFrameName && !pObject->GetTarget().isEmpty() )
1650 bSetTargetFrameName = false;
1651 *pTargetFrameName = pObject->GetTarget();
1653 if ( bSetDescription )
1655 bSetDescription = false;
1656 *pDescription = pObject->GetAltText();
1658 pRet = pFly->GetFormat();
1661 else
1663 if( pURL )
1665 *pURL = rURL.GetURL();
1666 if( rURL.IsServerMap() )
1668 // append the relative pixel position !!
1669 Point aPt( rPt );
1670 aPt -= pFly->getFrameArea().Pos();
1671 // without MapMode-Offset, without Offset, o ... !!!!!
1672 aPt = GetOut()->LogicToPixel(
1673 aPt, MapMode( MapUnit::MapTwip ) );
1674 *pURL = *pURL + "?" + OUString::number( aPt.getX() )
1675 + "," + OUString::number(aPt.getY() );
1678 pRet = pFly->GetFormat();
1680 if ( bSetTargetFrameName )
1681 *pTargetFrameName = rURL.GetTargetFrameName();
1682 if ( bSetDescription )
1683 *pDescription = pFly->GetFormat()->GetName();
1686 pDView->SetHitTolerancePixel( nOld );
1687 return pRet;
1690 const Graphic *SwFEShell::GetGrfAtPos( const Point &rPt,
1691 OUString &rName, bool &rbLink ) const
1693 if( !Imp()->HasDrawView() )
1694 return nullptr;
1696 SdrPageView* pPV;
1697 SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
1699 SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV);
1700 SwVirtFlyDrawObj* pFlyObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
1701 if (pFlyObj)
1703 SwFlyFrame *pFly = pFlyObj->GetFlyFrame();
1704 SwFrame* pLower = pFly->Lower();
1705 if ( pLower && pLower->IsNoTextFrame() )
1707 SwGrfNode *const pNd = static_cast<SwNoTextFrame*>(pLower)->GetNode()->GetGrfNode();
1708 if ( pNd )
1710 if ( pNd->IsGrfLink() )
1712 // halfway ready graphic?
1713 ::sfx2::SvLinkSource* pLnkObj = pNd->GetLink()->GetObj();
1714 if( pLnkObj && pLnkObj->IsPending() )
1715 return nullptr;
1716 rbLink = true;
1719 pNd->GetFileFilterNms( &rName, nullptr );
1720 if ( rName.isEmpty() )
1721 rName = pFly->GetFormat()->GetName();
1722 return &pNd->GetGrf(true);
1726 return nullptr;
1729 const SwFrameFormat* SwFEShell::GetFormatFromObj( const Point& rPt, SwRect** pRectToFill ) const
1731 SwFrameFormat* pRet = nullptr;
1733 if( Imp()->HasDrawView() )
1735 SdrPageView* pPView;
1737 SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
1739 const auto nOld = pDView->GetHitTolerancePixel();
1740 // tolerance for Drawing-SS
1741 pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
1743 SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
1744 if (pObj)
1746 // first check it:
1747 if (SwVirtFlyDrawObj* pFlyObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
1748 pRet = pFlyObj->GetFormat();
1749 else if ( pObj->GetUserCall() ) //not for group objects
1750 pRet = static_cast<SwDrawContact*>(pObj->GetUserCall())->GetFormat();
1751 if(pRet && pRectToFill)
1752 **pRectToFill = SwRect(pObj->GetCurrentBoundRect());
1754 pDView->SetHitTolerancePixel( nOld );
1756 return pRet;
1759 // returns a format too, if the point is over the text of any fly
1760 const SwFrameFormat* SwFEShell::GetFormatFromAnyObj( const Point& rPt ) const
1762 const SwFrameFormat* pRet = GetFormatFromObj( rPt );
1763 if( !pRet || RES_FLYFRMFMT == pRet->Which() )
1765 SwPosition aPos( *GetCursor()->GetPoint() );
1766 Point aPt( rPt );
1767 GetLayout()->GetModelPositionForViewPoint( &aPos, aPt );
1768 SwContentNode *pNd = aPos.GetNode().GetContentNode();
1769 std::pair<Point, bool> const tmp(rPt, false);
1770 SwFrame* pFrame = pNd->getLayoutFrame(GetLayout(), nullptr, &tmp)->FindFlyFrame();
1771 pRet = pFrame ? static_cast<SwLayoutFrame*>(pFrame)->GetFormat() : nullptr;
1773 return pRet;
1776 ObjCntType SwFEShell::GetObjCntType( const SdrObject& rObj )
1778 ObjCntType eType = OBJCNT_NONE;
1780 // investigate 'master' drawing object, if method
1781 // is called for a 'virtual' drawing object.
1782 const SdrObject* pInvestigatedObj;
1783 if (const SwDrawVirtObj* pDrawVirtObj = dynamic_cast<const SwDrawVirtObj*>( &rObj))
1785 pInvestigatedObj = &(pDrawVirtObj->GetReferencedObj());
1787 else
1789 pInvestigatedObj = &rObj;
1792 if( SdrInventor::FmForm == pInvestigatedObj->GetObjInventor() )
1794 eType = OBJCNT_CONTROL;
1795 uno::Reference< awt::XControlModel > xModel =
1796 static_cast<const SdrUnoObj&>(*pInvestigatedObj).GetUnoControlModel();
1797 if( xModel.is() )
1799 uno::Any aVal;
1800 OUString sName(u"ButtonType"_ustr);
1801 uno::Reference< beans::XPropertySet > xSet(xModel, uno::UNO_QUERY);
1803 uno::Reference< beans::XPropertySetInfo > xInfo = xSet->getPropertySetInfo();
1804 if(xInfo->hasPropertyByName( sName ))
1806 aVal = xSet->getPropertyValue( sName );
1807 if( aVal.hasValue() && form::FormButtonType_URL == *o3tl::doAccess<form::FormButtonType>(aVal) )
1808 eType = OBJCNT_URLBUTTON;
1812 else if (const SwVirtFlyDrawObj *pFlyObj = dynamic_cast<const SwVirtFlyDrawObj*>(pInvestigatedObj))
1814 const SwFlyFrame *pFly = pFlyObj->GetFlyFrame();
1815 const SwFrame* pLower = pFly->Lower();
1816 if ( pLower && pLower->IsNoTextFrame() )
1818 if (static_cast<const SwNoTextFrame*>(pLower)->GetNode()->GetGrfNode())
1819 eType = OBJCNT_GRF;
1820 else
1821 eType = OBJCNT_OLE;
1823 else
1824 eType = OBJCNT_FLY;
1826 else if ( dynamic_cast<const SdrObjGroup*>( pInvestigatedObj) != nullptr )
1828 SwDrawContact* pDrawContact( dynamic_cast<SwDrawContact*>(GetUserCall( pInvestigatedObj ) ) );
1829 if ( !pDrawContact )
1831 OSL_FAIL( "<SwFEShell::GetObjCntType(..)> - missing draw contact object" );
1832 eType = OBJCNT_NONE;
1834 else
1836 SwFrameFormat* pFrameFormat( pDrawContact->GetFormat() );
1837 if ( !pFrameFormat )
1839 OSL_FAIL( "<SwFEShell::GetObjCntType(..)> - missing frame format" );
1840 eType = OBJCNT_NONE;
1842 else if ( RndStdIds::FLY_AS_CHAR != pFrameFormat->GetAnchor().GetAnchorId() )
1844 eType = OBJCNT_GROUPOBJ;
1848 else
1849 eType = OBJCNT_SIMPLE;
1850 return eType;
1853 ObjCntType SwFEShell::GetObjCntType( const Point &rPt, SdrObject *&rpObj ) const
1855 ObjCntType eType = OBJCNT_NONE;
1857 if( Imp()->HasDrawView() )
1859 SdrPageView* pPView;
1861 SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
1863 const auto nOld = pDView->GetHitTolerancePixel();
1864 // tolerance for Drawing-SS
1865 pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
1867 SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
1868 if (pObj)
1870 rpObj = pObj;
1871 eType = GetObjCntType( *rpObj );
1874 pDView->SetHitTolerancePixel( nOld );
1876 return eType;
1879 ObjCntType SwFEShell::GetObjCntTypeOfSelection() const
1881 ObjCntType eType = OBJCNT_NONE;
1883 if( Imp()->HasDrawView() )
1885 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1886 for( size_t i = 0, nE = rMrkList.GetMarkCount(); i < nE; ++i )
1888 SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
1889 if( !pObj )
1890 continue;
1891 ObjCntType eTmp = GetObjCntType( *pObj );
1892 if( !i )
1894 eType = eTmp;
1896 else if( eTmp != eType )
1898 eType = OBJCNT_DONTCARE;
1899 // once DontCare, always DontCare!
1900 break;
1904 return eType;
1907 void SwFEShell::ReplaceSdrObj( const OUString& rGrfName, const Graphic* pGrf )
1909 CurrShell aCurr( this );
1911 const SdrMarkList *pMrkList;
1912 if( !(Imp()->HasDrawView() && 1 ==
1913 ( pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList())->GetMarkCount()) )
1914 return;
1916 SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
1917 assert(pObj);
1918 SwFrameFormat *pFormat = FindFrameFormat( pObj );
1920 // store attributes, then set the graphic
1921 SfxItemSet aFrameSet( mxDoc->GetAttrPool(),
1922 pFormat->GetAttrSet().GetRanges() );
1923 aFrameSet.Set( pFormat->GetAttrSet() );
1925 // set size and position?
1926 if( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
1928 // then let's do it:
1929 const tools::Rectangle &rBound = pObj->GetSnapRect();
1930 Point aRelPos( pObj->GetRelativePos() );
1932 const tools::Long nWidth = rBound.Right() - rBound.Left();
1933 const tools::Long nHeight= rBound.Bottom() - rBound.Top();
1934 aFrameSet.Put( SwFormatFrameSize( SwFrameSize::Minimum,
1935 std::max( nWidth, tools::Long(MINFLY) ),
1936 std::max( nHeight, tools::Long(MINFLY) )));
1938 if( SfxItemState::SET != aFrameSet.GetItemState( RES_HORI_ORIENT ))
1939 aFrameSet.Put( SwFormatHoriOrient( aRelPos.getX(), text::HoriOrientation::NONE, text::RelOrientation::FRAME ));
1941 if( SfxItemState::SET != aFrameSet.GetItemState( RES_VERT_ORIENT ))
1942 aFrameSet.Put( SwFormatVertOrient( aRelPos.getY(), text::VertOrientation::NONE, text::RelOrientation::FRAME ));
1946 pObj->GetOrdNum();
1948 StartAllAction();
1949 StartUndo();
1951 // delete "Sdr-Object", insert the graphic instead
1952 DelSelectedObj();
1954 GetDoc()->getIDocumentContentOperations().InsertGraphic(
1955 *GetCursor(), rGrfName, u""_ustr, pGrf, &aFrameSet, nullptr, nullptr);
1957 EndUndo();
1958 EndAllAction();
1961 static sal_uInt16 SwFormatGetPageNum(const SwFlyFrameFormat * pFormat)
1963 assert(pFormat != nullptr && "invalid argument");
1965 SwFlyFrame * pFrame = pFormat->GetFrame();
1967 sal_uInt16 aResult;
1969 if (pFrame != nullptr)
1970 aResult = pFrame->GetPhyPageNum();
1971 else
1972 aResult = pFormat->GetAnchor().GetPageNum();
1974 return aResult;
1977 void SwFEShell::GetConnectableFrameFormats(SwFrameFormat & rFormat,
1978 std::u16string_view rReference,
1979 bool bSuccessors,
1980 std::vector< OUString > & aPrevPageVec,
1981 std::vector< OUString > & aThisPageVec,
1982 std::vector< OUString > & aNextPageVec,
1983 std::vector< OUString > & aRestVec)
1985 StartAction();
1987 SwFormatChain rChain = rFormat.GetChain();
1988 SwFrameFormat * pOldChainNext = rChain.GetNext();
1989 SwFrameFormat * pOldChainPrev = rChain.GetPrev();
1991 if (pOldChainNext)
1992 mxDoc->Unchain(rFormat);
1994 if (pOldChainPrev)
1995 mxDoc->Unchain(*pOldChainPrev);
1997 /* potential successors resp. predecessors */
1998 std::vector<const SwFrameFormat *> aTmpSpzArray = mxDoc->GetFlyFrameFormats(FLYCNTTYPE_FRM, false);
2000 for (auto it = aTmpSpzArray.begin(); it != aTmpSpzArray.end(); ++it)
2003 pFormat is a potential successor of rFormat if it is chainable after
2004 rFormat.
2006 pFormat is a potential predecessor of rFormat if rFormat is chainable
2007 after pFormat.
2010 SwChainRet nChainState;
2012 if (bSuccessors)
2013 nChainState = mxDoc->Chainable(rFormat, **it);
2014 else
2015 nChainState = mxDoc->Chainable(**it, rFormat);
2017 if (nChainState != SwChainRet::OK)
2018 *it = nullptr;
2020 std::erase(aTmpSpzArray, nullptr);
2022 if (!aTmpSpzArray.empty())
2024 aPrevPageVec.clear();
2025 aThisPageVec.clear();
2026 aNextPageVec.clear();
2027 aRestVec.clear();
2029 /* number of page rFormat resides on */
2030 sal_uInt16 nPageNum = SwFormatGetPageNum(static_cast<SwFlyFrameFormat *>(&rFormat));
2032 for (const auto& rpFormat : aTmpSpzArray)
2034 const OUString aString = rpFormat->GetName();
2036 /* rFormat is not a valid successor or predecessor of
2037 itself */
2038 if (aString != rReference && aString != rFormat.GetName())
2040 sal_uInt16 nNum1 =
2041 SwFormatGetPageNum(static_cast<const SwFlyFrameFormat *>(rpFormat));
2043 if (nNum1 == nPageNum -1)
2044 aPrevPageVec.push_back(aString);
2045 else if (nNum1 == nPageNum)
2046 aThisPageVec.push_back(aString);
2047 else if (nNum1 == nPageNum + 1)
2048 aNextPageVec.push_back(aString);
2049 else
2050 aRestVec.push_back(aString);
2056 if (pOldChainNext)
2057 mxDoc->Chain(rFormat, *pOldChainNext);
2059 if (pOldChainPrev)
2060 mxDoc->Chain(*pOldChainPrev, rFormat);
2062 EndAction();
2065 // #i73249#
2066 OUString SwFEShell::GetObjTitle() const
2068 if ( Imp()->HasDrawView() )
2070 const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
2071 if ( pMrkList->GetMarkCount() == 1 )
2073 const SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
2074 const SwFrameFormat* pFormat = FindFrameFormat( pObj );
2075 if ( pFormat->Which() == RES_FLYFRMFMT )
2077 return static_cast<const SwFlyFrameFormat*>(pFormat)->GetObjTitle();
2079 return pObj->GetTitle();
2083 return OUString();
2086 void SwFEShell::SetObjTitle( const OUString& rTitle )
2088 if ( !Imp()->HasDrawView() )
2089 return;
2091 const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
2092 if ( pMrkList->GetMarkCount() != 1 )
2093 return;
2095 SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
2096 SwFrameFormat* pFormat = FindFrameFormat( pObj );
2097 if ( pFormat->Which() == RES_FLYFRMFMT )
2099 GetDoc()->SetFlyFrameTitle( dynamic_cast<SwFlyFrameFormat&>(*pFormat),
2100 rTitle );
2102 else
2104 pObj->SetTitle( rTitle );
2108 OUString SwFEShell::GetObjDescription() const
2110 if ( Imp()->HasDrawView() )
2112 const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
2113 if ( pMrkList->GetMarkCount() == 1 )
2115 const SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
2116 const SwFrameFormat* pFormat = FindFrameFormat( pObj );
2117 if ( pFormat->Which() == RES_FLYFRMFMT )
2119 return dynamic_cast<const SwFlyFrameFormat&>(*pFormat).GetObjDescription();
2121 return pObj->GetDescription();
2125 return OUString();
2128 void SwFEShell::SetObjDescription( const OUString& rDescription )
2130 if ( !Imp()->HasDrawView() )
2131 return;
2133 const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
2134 if ( pMrkList->GetMarkCount() != 1 )
2135 return;
2137 SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
2138 SwFrameFormat* pFormat = FindFrameFormat( pObj );
2139 if ( pFormat->Which() == RES_FLYFRMFMT )
2141 GetDoc()->SetFlyFrameDescription(dynamic_cast<SwFlyFrameFormat&>(*pFormat),
2142 rDescription);
2144 else
2146 pObj->SetDescription( rDescription );
2150 bool SwFEShell::IsObjDecorative() const
2152 if (!Imp()->HasDrawView())
2154 return false;
2157 SdrMarkList const& rMarkList(Imp()->GetDrawView()->GetMarkedObjectList());
2158 if (rMarkList.GetMarkCount() != 1)
2160 return false;
2163 SdrObject const*const pObj(rMarkList.GetMark(0)->GetMarkedSdrObj());
2164 SwFrameFormat const*const pFormat(FindFrameFormat(pObj));
2165 if (pFormat->Which() == RES_FLYFRMFMT)
2167 return dynamic_cast<const SwFlyFrameFormat&>(*pFormat).GetAttrSet().Get(RES_DECORATIVE).GetValue();
2169 return pObj->IsDecorative();
2172 void SwFEShell::SetObjDecorative(bool const isDecorative)
2174 if (!Imp()->HasDrawView())
2176 return;
2179 SdrMarkList const& rMarkList(Imp()->GetDrawView()->GetMarkedObjectList());
2180 if (rMarkList.GetMarkCount() != 1)
2182 return;
2185 SdrObject *const pObj(rMarkList.GetMark(0)->GetMarkedSdrObj());
2186 SwFrameFormat *const pFormat(FindFrameFormat(pObj));
2187 if (pFormat->Which() == RES_FLYFRMFMT)
2189 GetDoc()->SetFlyFrameDecorative(dynamic_cast<SwFlyFrameFormat&>(*pFormat),
2190 isDecorative);
2192 else
2194 pObj->SetDecorative(isDecorative);
2199 void SwFEShell::AlignFormulaToBaseline( const uno::Reference < embed::XEmbeddedObject >& xObj )
2201 #if OSL_DEBUG_LEVEL > 0
2202 SvGlobalName aCLSID( xObj->getClassID() );
2203 const bool bStarMath = ( SotExchange::IsMath( aCLSID ) != 0 );
2204 OSL_ENSURE( bStarMath, "AlignFormulaToBaseline should only be called for Math objects" );
2206 if ( !bStarMath )
2207 return;
2208 #endif
2210 SwFlyFrame * pFly = FindFlyFrame( xObj );
2211 OSL_ENSURE( pFly , "No fly frame!" );
2212 SwFrameFormat * pFrameFormat = pFly ? pFly->GetFormat() : nullptr;
2214 // baseline to baseline alignment should only be applied to formulas anchored as char
2215 if ( !pFly || !pFrameFormat || RndStdIds::FLY_AS_CHAR != pFrameFormat->GetAnchor().GetAnchorId() )
2216 return;
2218 // get baseline from Math object
2219 uno::Any aBaseline;
2220 if( svt::EmbeddedObjectRef::TryRunningState( xObj ) )
2222 uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY );
2223 if ( xSet.is() )
2227 aBaseline = xSet->getPropertyValue(u"BaseLine"_ustr);
2229 catch ( uno::Exception& )
2231 OSL_FAIL( "Baseline could not be retrieved from Starmath!" );
2236 sal_Int32 nBaseline = ::comphelper::getINT32(aBaseline);
2237 nBaseline = o3tl::toTwips( nBaseline, o3tl::Length::mm100 );
2239 OSL_ENSURE( nBaseline > 0, "Wrong value of Baseline while retrieving from Starmath!" );
2240 //nBaseline must be moved by aPrt position
2241 const SwFlyFrameFormat *pFlyFrameFormat = pFly->GetFormat();
2242 OSL_ENSURE( pFlyFrameFormat, "fly frame format missing!" );
2243 if ( pFlyFrameFormat )
2244 nBaseline += pFlyFrameFormat->GetLastFlyFramePrtRectPos().Y();
2246 const SwFormatVertOrient &rVert = pFrameFormat->GetVertOrient();
2247 SwFormatVertOrient aVert( rVert );
2248 aVert.SetPos( -nBaseline );
2249 aVert.SetVertOrient( css::text::VertOrientation::NONE );
2251 pFrameFormat->LockModify();
2252 pFrameFormat->SetFormatAttr( aVert );
2253 pFrameFormat->UnlockModify();
2254 pFly->InvalidatePos();
2258 void SwFEShell::AlignAllFormulasToBaseline()
2260 StartAllAction();
2262 SwStartNode *pStNd;
2263 SwNodeIndex aIdx( *GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
2264 while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
2266 ++aIdx;
2267 SwOLENode *pOleNode = aIdx.GetNode().GetOLENode();
2268 if ( pOleNode )
2270 const uno::Reference < embed::XEmbeddedObject > & xObj( pOleNode->GetOLEObj().GetOleRef() );
2271 if (xObj.is())
2273 SvGlobalName aCLSID( xObj->getClassID() );
2274 if ( SotExchange::IsMath( aCLSID ) )
2275 AlignFormulaToBaseline( xObj );
2279 aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
2282 EndAllAction();
2285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */