1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <svl/itemiter.hxx>
22 #include <svx/svdobj.hxx>
23 #include <svx/svdmark.hxx>
24 #include <osl/diagnose.h>
25 #include <fmtfsize.hxx>
26 #include <fmtornt.hxx>
27 #include <dcontact.hxx>
30 #include <IDocumentUndoRedo.hxx>
31 #include <IDocumentDrawModelAccess.hxx>
32 #include <IDocumentState.hxx>
33 #include <IDocumentLayoutAccess.hxx>
34 #include <ndindex.hxx>
35 #include <drawdoc.hxx>
36 #include <fmtcntnt.hxx>
37 #include <fmtanchr.hxx>
38 #include <fmtflcnt.hxx>
40 #include <notxtfrm.hxx>
41 #include <pagefrm.hxx>
42 #include <rootfrm.hxx>
44 #include <textboxhelper.hxx>
45 #include <txatbase.hxx>
50 #include <crstate.hxx>
51 #include <UndoCore.hxx>
52 #include <UndoAttribute.hxx>
53 #include <fmtcnct.hxx>
54 #include <dflyobj.hxx>
55 #include <undoflystrattr.hxx>
57 #include <frameformats.hxx>
59 #include <svx/xbtmpit.hxx>
60 #include <svx/xflftrit.hxx>
61 #include <svx/xlndsit.hxx>
62 #include <svx/xlnstit.hxx>
63 #include <svx/xlnedit.hxx>
64 #include <svx/xflhtit.hxx>
65 #include <formatflysplit.hxx>
67 using namespace ::com::sun::star
;
69 size_t SwDoc::GetFlyCount( FlyCntType eType
, bool bIgnoreTextBoxes
) const
72 const SwNodeIndex
* pIdx
;
74 for(sw::SpzFrameFormat
* pFlyFormat
: *GetSpzFrameFormats())
76 if (bIgnoreTextBoxes
&& SwTextBoxHelper::isTextBox(pFlyFormat
, RES_FLYFRMFMT
))
79 if( RES_FLYFRMFMT
!= pFlyFormat
->Which() )
81 pIdx
= pFlyFormat
->GetContent().GetContentIdx();
82 if( pIdx
&& pIdx
->GetNodes().IsDocNodes() )
84 const SwNode
* pNd
= GetNodes()[ pIdx
->GetIndex() + 1 ];
89 if(!pNd
->IsNoTextNode())
94 if( pNd
->IsGrfNode() )
111 /// @attention If you change this, also update SwXFrameEnumeration in unocoll.
112 SwFrameFormat
* SwDoc::GetFlyNum( size_t nIdx
, FlyCntType eType
, bool bIgnoreTextBoxes
)
114 SwFrameFormat
* pRetFormat
= nullptr;
115 const SwNodeIndex
* pIdx
;
118 for(sw::SpzFrameFormat
* pFlyFormat
: *GetSpzFrameFormats())
120 if (bIgnoreTextBoxes
&& SwTextBoxHelper::isTextBox(pFlyFormat
, RES_FLYFRMFMT
))
123 if( RES_FLYFRMFMT
!= pFlyFormat
->Which() )
125 pIdx
= pFlyFormat
->GetContent().GetContentIdx();
126 if( pIdx
&& pIdx
->GetNodes().IsDocNodes() )
128 const SwNode
* pNd
= GetNodes()[ pIdx
->GetIndex() + 1 ];
132 if( !pNd
->IsNoTextNode() && nIdx
== nCount
++)
133 pRetFormat
= pFlyFormat
;
136 if(pNd
->IsGrfNode() && nIdx
== nCount
++ )
137 pRetFormat
= pFlyFormat
;
140 if(pNd
->IsOLENode() && nIdx
== nCount
++)
141 pRetFormat
= pFlyFormat
;
145 pRetFormat
= pFlyFormat
;
152 std::vector
<SwFrameFormat
const*> SwDoc::GetFlyFrameFormats(
153 FlyCntType
const eType
, bool const bIgnoreTextBoxes
)
155 std::vector
<SwFrameFormat
const*> ret
;
156 ret
.reserve(GetSpzFrameFormats()->size());
158 for(sw::SpzFrameFormat
* pFlyFormat
: *GetSpzFrameFormats())
160 if (bIgnoreTextBoxes
&& SwTextBoxHelper::isTextBox(pFlyFormat
, RES_FLYFRMFMT
))
165 if (RES_FLYFRMFMT
!= pFlyFormat
->Which())
170 SwNodeIndex
const*const pIdx(pFlyFormat
->GetContent().GetContentIdx());
171 if (pIdx
&& pIdx
->GetNodes().IsDocNodes())
173 SwNode
const*const pNd
= GetNodes()[ pIdx
->GetIndex() + 1 ];
177 if (!pNd
->IsNoTextNode())
178 ret
.push_back(pFlyFormat
);
181 if (pNd
->IsGrfNode())
182 ret
.push_back(pFlyFormat
);
185 if (pNd
->IsOLENode())
186 ret
.push_back(pFlyFormat
);
189 ret
.push_back(pFlyFormat
);
197 static Point
lcl_FindAnchorLayPos( SwDoc
& rDoc
, const SwFormatAnchor
& rAnch
,
198 const SwFrameFormat
* pFlyFormat
)
201 if( rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell() )
202 switch( rAnch
.GetAnchorId() )
204 case RndStdIds::FLY_AS_CHAR
:
205 if( pFlyFormat
&& rAnch
.GetAnchorNode() )
207 const SwFrame
* pOld
= static_cast<const SwFlyFrameFormat
*>(pFlyFormat
)->GetFrame( &aRet
);
209 aRet
= pOld
->getFrameArea().Pos();
213 case RndStdIds::FLY_AT_PARA
:
214 case RndStdIds::FLY_AT_CHAR
: // LAYER_IMPL
215 if( rAnch
.GetAnchorNode() )
217 const SwContentNode
* pNd
= rAnch
.GetAnchorNode()->GetContentNode();
218 std::pair
<Point
, bool> const tmp(aRet
, false);
219 const SwFrame
* pOld
= pNd
? pNd
->getLayoutFrame(rDoc
.getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp
) : nullptr;
221 aRet
= pOld
->getFrameArea().Pos();
225 case RndStdIds::FLY_AT_FLY
: // LAYER_IMPL
226 if( rAnch
.GetAnchorNode() )
228 const SwFlyFrameFormat
* pFormat
= static_cast<SwFlyFrameFormat
*>(rAnch
.GetAnchorNode()->
230 const SwFrame
* pOld
= pFormat
? pFormat
->GetFrame( &aRet
) : nullptr;
232 aRet
= pOld
->getFrameArea().Pos();
236 case RndStdIds::FLY_AT_PAGE
:
238 sal_uInt16 nPgNum
= rAnch
.GetPageNum();
239 const SwPageFrame
*pPage
= static_cast<SwPageFrame
*>(rDoc
.getIDocumentLayoutAccess().GetCurrentLayout()->Lower());
240 for( sal_uInt16 i
= 1; (i
<= nPgNum
) && pPage
; ++i
,
241 pPage
=static_cast<const SwPageFrame
*>(pPage
->GetNext()) )
244 aRet
= pPage
->getFrameArea().Pos();
256 #define IGNOREANCHOR 1
257 #define DONTMAKEFRMS 2
259 sal_Int8
SwDoc::SetFlyFrameAnchor( SwFrameFormat
& rFormat
, SfxItemSet
& rSet
, bool bNewFrames
)
261 // Changing anchors is almost always allowed.
262 // Exception: Paragraph and character bound frames must not become
263 // page bound, if they are located in the header or footer.
264 const SwFormatAnchor
&rOldAnch
= rFormat
.GetAnchor();
265 const RndStdIds nOld
= rOldAnch
.GetAnchorId();
267 SwFormatAnchor
aNewAnch( rSet
.Get( RES_ANCHOR
) );
268 RndStdIds nNew
= aNewAnch
.GetAnchorId();
270 // Is the new anchor valid?
271 if( !aNewAnch
.GetAnchorNode() && (RndStdIds::FLY_AT_FLY
== nNew
||
272 (RndStdIds::FLY_AT_PARA
== nNew
) || (RndStdIds::FLY_AS_CHAR
== nNew
) ||
273 (RndStdIds::FLY_AT_CHAR
== nNew
) ))
281 Point
aOldAnchorPos( ::lcl_FindAnchorLayPos( *this, rOldAnch
, &rFormat
));
282 Point
aNewAnchorPos( ::lcl_FindAnchorLayPos( *this, aNewAnch
, nullptr ));
284 // Destroy the old Frames.
285 // The Views are hidden implicitly, so hiding them another time would be
289 if ( RndStdIds::FLY_AS_CHAR
== nOld
)
291 // We need to handle InContents in a special way:
292 // The TextAttribut needs to be destroyed which, unfortunately, also
293 // destroys the format. To avoid that, we disconnect the format from
295 SwNode
*pAnchorNode
= rOldAnch
.GetAnchorNode();
296 SwTextNode
*pTextNode
= pAnchorNode
->GetTextNode();
297 OSL_ENSURE( pTextNode
->HasHints(), "Missing FlyInCnt-Hint." );
298 const sal_Int32 nIdx
= rOldAnch
.GetAnchorContentOffset();
299 SwTextAttr
* const pHint
=
300 pTextNode
->GetTextAttrForCharAt( nIdx
, RES_TXTATR_FLYCNT
);
301 OSL_ENSURE( pHint
&& pHint
->Which() == RES_TXTATR_FLYCNT
,
302 "Missing FlyInCnt-Hint." );
303 OSL_ENSURE( pHint
&& pHint
->GetFlyCnt().GetFrameFormat() == &rFormat
,
304 "Wrong TextFlyCnt-Hint." );
306 const_cast<SwFormatFlyCnt
&>(pHint
->GetFlyCnt()).SetFlyFormat();
308 // They are disconnected. We now have to destroy the attribute.
309 pTextNode
->DeleteAttributes( RES_TXTATR_FLYCNT
, nIdx
, nIdx
);
312 // We can finally set the attribute. It needs to be the first one!
313 // Undo depends on it!
314 rFormat
.SetFormatAttr( aNewAnch
);
316 // Correct the position
319 case RndStdIds::FLY_AS_CHAR
:
320 // If no position attributes are received, we have to make sure
321 // that no forbidden automatic alignment is left.
323 SwNode
*pAnchorNode
= aNewAnch
.GetAnchorNode();
324 SwTextNode
*pNd
= pAnchorNode
->GetTextNode();
325 OSL_ENSURE( pNd
, "Cursor does not point to TextNode." );
327 SwFormatFlyCnt
aFormat( static_cast<SwFlyFrameFormat
*>(&rFormat
) );
328 pNd
->InsertItem( aFormat
, aNewAnch
.GetAnchorContentOffset(), 0 );
331 if( SfxItemState::SET
!= rSet
.GetItemState( RES_VERT_ORIENT
, false ))
333 SwFormatVertOrient
aOldV( rFormat
.GetVertOrient() );
335 switch( aOldV
.GetVertOrient() )
337 case text::VertOrientation::LINE_TOP
: aOldV
.SetVertOrient( text::VertOrientation::TOP
); break;
338 case text::VertOrientation::LINE_CENTER
: aOldV
.SetVertOrient( text::VertOrientation::CENTER
); break;
339 case text::VertOrientation::LINE_BOTTOM
: aOldV
.SetVertOrient( text::VertOrientation::BOTTOM
); break;
340 case text::VertOrientation::NONE
: aOldV
.SetVertOrient( text::VertOrientation::CENTER
); break;
349 case RndStdIds::FLY_AT_PARA
:
350 case RndStdIds::FLY_AT_CHAR
: // LAYER_IMPL
351 case RndStdIds::FLY_AT_FLY
: // LAYER_IMPL
352 case RndStdIds::FLY_AT_PAGE
:
354 // If only the anchor type has changed (char -> para -> page) and the absolute position
355 // is unchanged even though there is a new relative orientation
356 // (likely because the old orientation was not valid for the new anchor type),
357 // then adjust the position to account for the moved anchor position.
358 const SwFormatHoriOrient
* pHoriOrientItem
= rSet
.GetItemIfSet( RES_HORI_ORIENT
, false );
360 SwFormatHoriOrient
aOldH( rFormat
.GetHoriOrient() );
361 bool bPutOldH(false);
363 if (text::HoriOrientation::NONE
== aOldH
.GetHoriOrient() && pHoriOrientItem
364 && text::HoriOrientation::NONE
== pHoriOrientItem
->GetHoriOrient()
365 && aOldH
.GetPos() == pHoriOrientItem
->GetPos())
367 SwTwips nPos
= (RndStdIds::FLY_AS_CHAR
== nOld
) ? 0 : aOldH
.GetPos();
368 nPos
+= aOldAnchorPos
.getX() - aNewAnchorPos
.getX();
370 assert(aOldH
.GetRelationOrient() != pHoriOrientItem
->GetRelationOrient());
371 aOldH
.SetRelationOrient(pHoriOrientItem
->GetRelationOrient());
373 aOldH
.SetPos( nPos
);
376 if (nNew
== RndStdIds::FLY_AT_PAGE
)
378 sal_Int16
nRelOrient(pHoriOrientItem
379 ? pHoriOrientItem
->GetRelationOrient()
380 : aOldH
.GetRelationOrient());
381 if (sw::GetAtPageRelOrientation(nRelOrient
, false))
383 SAL_INFO("sw.ui", "fixing horizontal RelOrientation for at-page anchor");
384 aOldH
.SetRelationOrient(nRelOrient
);
393 const SwFormatVertOrient
* pVertOrientItem
= rSet
.GetItemIfSet( RES_VERT_ORIENT
, false );
394 SwFormatVertOrient
aOldV( rFormat
.GetVertOrient() );
396 if (text::VertOrientation::NONE
== aOldV
.GetVertOrient() && pVertOrientItem
397 && text::VertOrientation::NONE
== pVertOrientItem
->GetVertOrient()
398 && aOldV
.GetPos() == pVertOrientItem
->GetPos())
400 SwTwips nPos
= (RndStdIds::FLY_AS_CHAR
== nOld
) ? 0 : aOldV
.GetPos();
401 nPos
+= aOldAnchorPos
.getY() - aNewAnchorPos
.getY();
403 assert(aOldV
.GetRelationOrient() != pVertOrientItem
->GetRelationOrient());
404 aOldV
.SetRelationOrient(pVertOrientItem
->GetRelationOrient());
406 aOldV
.SetPos( nPos
);
416 rFormat
.MakeFrames();
422 lcl_SetFlyFrameAttr(SwDoc
& rDoc
,
423 sal_Int8 (SwDoc::*pSetFlyFrameAnchor
)(SwFrameFormat
&, SfxItemSet
&, bool),
424 SwFrameFormat
& rFlyFormat
, SfxItemSet
& rSet
)
426 // #i32968# Inserting columns in the frame causes MakeFrameFormat to put two
427 // objects of type SwUndoFrameFormat on the undo stack. We don't want them.
428 ::sw::UndoGuard
const undoGuard(rDoc
.GetIDocumentUndoRedo());
430 // Is the anchor attribute included?
431 // If so, we pass it to a special method, which returns true
432 // if the Fly needs to be created anew, because we e.g change the FlyType.
433 sal_Int8
const nMakeFrames
=
434 (SfxItemState::SET
== rSet
.GetItemState( RES_ANCHOR
, false ))
435 ? (rDoc
.*pSetFlyFrameAnchor
)( rFlyFormat
, rSet
, false )
438 const SfxPoolItem
* pItem
;
439 SfxItemIter
aIter( rSet
);
440 SfxItemSet
aTmpSet( rDoc
.GetAttrPool(), aFrameFormatSetRange
);
441 const SfxPoolItem
* pItemIter
= aIter
.GetCurItem();
443 switch(pItemIter
->Which())
450 OSL_FAIL( "Unknown Fly attribute." );
453 rSet
.ClearItem(pItemIter
->Which());
456 if( DONTMAKEFRMS
!= nMakeFrames
)
460 if( !IsInvalidItem(pItemIter
) && ( SfxItemState::SET
!=
461 rFlyFormat
.GetAttrSet().GetItemState(pItemIter
->Which(), true, &pItem
) ||
462 *pItem
!= *pItemIter
))
463 aTmpSet
.Put(*pItemIter
);
467 pItemIter
= aIter
.NextItem();
469 } while (pItemIter
&& (0 != pItemIter
->Which()));
471 if( aTmpSet
.Count() )
472 rFlyFormat
.SetFormatAttr( aTmpSet
);
474 if( MAKEFRMS
== nMakeFrames
)
475 rFlyFormat
.MakeFrames();
477 return aTmpSet
.Count() || MAKEFRMS
== nMakeFrames
;
480 void SwDoc::CheckForUniqueItemForLineFillNameOrIndex(SfxItemSet
& rSet
)
482 SwDrawModel
* pDrawModel
= getIDocumentDrawModelAccess().GetOrCreateDrawModel();
483 SfxItemIter
aIter(rSet
);
485 for (const SfxPoolItem
* pItem
= aIter
.GetCurItem(); pItem
; pItem
= aIter
.NextItem())
487 if (IsInvalidItem(pItem
))
489 std::unique_ptr
<SfxPoolItem
> pResult
;
491 switch(pItem
->Which())
493 case XATTR_FILLBITMAP
:
495 pResult
= pItem
->StaticWhichCast(XATTR_FILLBITMAP
).checkForUniqueItem(pDrawModel
);
500 pResult
= pItem
->StaticWhichCast(XATTR_LINEDASH
).checkForUniqueItem(pDrawModel
);
503 case XATTR_LINESTART
:
505 pResult
= pItem
->StaticWhichCast(XATTR_LINESTART
).checkForUniqueItem(pDrawModel
);
510 pResult
= pItem
->StaticWhichCast(XATTR_LINEEND
).checkForUniqueItem(pDrawModel
);
513 case XATTR_FILLGRADIENT
:
515 pResult
= pItem
->StaticWhichCast(XATTR_FILLGRADIENT
).checkForUniqueItem(pDrawModel
);
518 case XATTR_FILLFLOATTRANSPARENCE
:
520 pResult
= pItem
->StaticWhichCast(XATTR_FILLFLOATTRANSPARENCE
).checkForUniqueItem(pDrawModel
);
523 case XATTR_FILLHATCH
:
525 pResult
= pItem
->StaticWhichCast(XATTR_FILLHATCH
).checkForUniqueItem(pDrawModel
);
532 rSet
.Put(std::move(pResult
));
537 bool SwDoc::SetFlyFrameAttr( SwFrameFormat
& rFlyFormat
, SfxItemSet
& rSet
)
542 SwDocModifyAndUndoGuard
guard(rFlyFormat
);
544 bool const bRet
= lcl_SetFlyFrameAttr(*this, &SwDoc::SetFlyFrameAnchor
, rFlyFormat
, rSet
);
546 //SwTextBoxHelper::syncFlyFrameAttr(rFlyFormat, rSet);
552 void SwDoc::SetFlyFrameTitle( SwFlyFrameFormat
& rFlyFrameFormat
,
553 const OUString
& sNewTitle
)
555 if ( rFlyFrameFormat
.GetObjTitle() == sNewTitle
)
560 ::sw::DrawUndoGuard
const drawUndoGuard(GetIDocumentUndoRedo());
562 if (GetIDocumentUndoRedo().DoesUndo())
564 GetIDocumentUndoRedo().AppendUndo( std::make_unique
<SwUndoFlyStrAttr
>( rFlyFrameFormat
,
565 SwUndoId::FLYFRMFMT_TITLE
,
566 rFlyFrameFormat
.GetObjTitle(),
570 rFlyFrameFormat
.SetObjTitle( sNewTitle
, true );
572 getIDocumentState().SetModified();
575 void SwDoc::SetFlyFrameDescription( SwFlyFrameFormat
& rFlyFrameFormat
,
576 const OUString
& sNewDescription
)
578 if ( rFlyFrameFormat
.GetObjDescription() == sNewDescription
)
583 ::sw::DrawUndoGuard
const drawUndoGuard(GetIDocumentUndoRedo());
585 if (GetIDocumentUndoRedo().DoesUndo())
587 GetIDocumentUndoRedo().AppendUndo( std::make_unique
<SwUndoFlyStrAttr
>( rFlyFrameFormat
,
588 SwUndoId::FLYFRMFMT_DESCRIPTION
,
589 rFlyFrameFormat
.GetObjDescription(),
593 rFlyFrameFormat
.SetObjDescription( sNewDescription
, true );
595 getIDocumentState().SetModified();
598 void SwDoc::SetFlyFrameDecorative(SwFlyFrameFormat
& rFlyFrameFormat
,
599 bool const isDecorative
)
601 if (rFlyFrameFormat
.GetAttrSet().Get(RES_DECORATIVE
).GetValue() == isDecorative
)
606 ::sw::DrawUndoGuard
const drawUndoGuard(GetIDocumentUndoRedo());
608 if (GetIDocumentUndoRedo().DoesUndo())
610 GetIDocumentUndoRedo().AppendUndo(
611 std::make_unique
<SwUndoFlyDecorative
>(rFlyFrameFormat
, isDecorative
));
614 rFlyFrameFormat
.SetObjDecorative(isDecorative
);
616 getIDocumentState().SetModified();
620 bool SwDoc::SetFrameFormatToFly( SwFrameFormat
& rFormat
, SwFrameFormat
& rNewFormat
,
621 SfxItemSet
* pSet
, bool bKeepOrient
)
623 bool bChgAnchor
= false, bFrameSz
= false;
625 const SwFormatFrameSize
aFrameSz( rFormat
.GetFrameSize() );
627 SwUndoSetFlyFormat
* pUndo
= nullptr;
628 bool const bUndo
= GetIDocumentUndoRedo().DoesUndo();
631 pUndo
= new SwUndoSetFlyFormat( rFormat
, rNewFormat
);
632 GetIDocumentUndoRedo().AppendUndo(std::unique_ptr
<SwUndo
>(pUndo
));
635 // #i32968# Inserting columns in the section causes MakeFrameFormat to put
636 // 2 objects of type SwUndoFrameFormat on the undo stack. We don't want them.
637 ::sw::UndoGuard
const undoGuard(GetIDocumentUndoRedo());
639 // Set the column first, or we'll have trouble with
640 //Set/Reset/Synch. and so on
641 if( SfxItemState::SET
!= rNewFormat
.GetAttrSet().GetItemState( RES_COL
))
642 rFormat
.ResetFormatAttr( RES_COL
);
644 if( rFormat
.DerivedFrom() != &rNewFormat
)
646 rFormat
.SetDerivedFrom( &rNewFormat
);
648 // 1. If not automatic = ignore; else = dispose
650 if( SfxItemState::SET
== rNewFormat
.GetAttrSet().GetItemState( RES_FRM_SIZE
, false ))
652 rFormat
.ResetFormatAttr( RES_FRM_SIZE
);
656 const SfxItemSet
* pAsk
= pSet
;
657 if( !pAsk
) pAsk
= &rNewFormat
.GetAttrSet();
658 const SwFormatAnchor
* pFormatAnchor
= pAsk
->GetItemIfSet( RES_ANCHOR
, false );
660 && pFormatAnchor
->GetAnchorId() !=
661 rFormat
.GetAnchor().GetAnchorId() )
664 bChgAnchor
= MAKEFRMS
== SetFlyFrameAnchor( rFormat
, *pSet
, false );
667 // Needs to have the FlyFormat range, because we set attributes in it,
668 // in SetFlyFrameAnchor.
669 SfxItemSet
aFlySet( *rNewFormat
.GetAttrSet().GetPool(),
670 rNewFormat
.GetAttrSet().GetRanges() );
671 aFlySet
.Put( *pFormatAnchor
);
672 bChgAnchor
= MAKEFRMS
== SetFlyFrameAnchor( rFormat
, aFlySet
, false);
677 // Only reset vertical and horizontal orientation, if we have automatic alignment
678 // set in the template. Otherwise use the old value.
679 // If we update the frame template the Fly should NOT lose its orientation (which
680 // is not being updated!).
681 // text::HoriOrientation::NONE and text::VertOrientation::NONE are allowed now
684 rFormat
.ResetFormatAttr(RES_VERT_ORIENT
);
685 rFormat
.ResetFormatAttr(RES_HORI_ORIENT
);
688 rFormat
.ResetFormatAttr( RES_PRINT
, RES_SURROUND
);
689 rFormat
.ResetFormatAttr( RES_LR_SPACE
, RES_UL_SPACE
);
690 rFormat
.ResetFormatAttr( RES_BACKGROUND
, RES_COL
);
691 rFormat
.ResetFormatAttr( RES_EDIT_IN_READONLY
);
694 rFormat
.SetFormatAttr( aFrameSz
);
697 rFormat
.MakeFrames();
700 pUndo
->EndListeningAll();
702 getIDocumentState().SetModified();
707 void SwDoc::GetGrfNms( const SwFlyFrameFormat
& rFormat
, OUString
* pGrfName
,
710 SwNodeIndex
aIdx( *rFormat
.GetContent().GetContentIdx(), 1 );
711 const SwGrfNode
* pGrfNd
= aIdx
.GetNode().GetGrfNode();
712 if( pGrfNd
&& pGrfNd
->IsLinkedFile() )
713 pGrfNd
->GetFileFilterNms( pGrfName
, pFltName
);
716 bool SwDoc::ChgAnchor( const SdrMarkList
& _rMrkList
,
717 RndStdIds _eAnchorType
,
718 const bool _bSameOnly
,
719 const bool _bPosCorr
)
721 OSL_ENSURE( getIDocumentLayoutAccess().GetCurrentLayout(), "No layout!" );
723 if ( !_rMrkList
.GetMarkCount() ||
724 _rMrkList
.GetMark( 0 )->GetMarkedSdrObj()->getParentSdrObjectFromSdrObject() )
729 GetIDocumentUndoRedo().StartUndo( SwUndoId::INSATTR
, nullptr );
731 bool bUnmark
= false;
732 for ( size_t i
= 0; i
< _rMrkList
.GetMarkCount(); ++i
)
734 SdrObject
* pObj
= _rMrkList
.GetMark( i
)->GetMarkedSdrObj();
735 if ( dynamic_cast<const SwVirtFlyDrawObj
*>( pObj
) == nullptr )
737 SwDrawContact
* pContact
= static_cast<SwDrawContact
*>(GetUserCall(pObj
));
739 // consider, that drawing object has
740 // no user call. E.g.: a 'virtual' drawing object is disconnected by
741 // the anchor type change of the 'master' drawing object.
742 // Continue with next selected object and assert, if this isn't excepted.
745 #if OSL_DEBUG_LEVEL > 0
746 auto pSwDrawVirtObj
= dynamic_cast<SwDrawVirtObj
*>( pObj
);
747 bool bNoUserCallExcepted
= pSwDrawVirtObj
&& !pSwDrawVirtObj
->IsConnected();
748 OSL_ENSURE( bNoUserCallExcepted
, "SwDoc::ChgAnchor(..) - no contact at selected drawing object" );
754 const SwFrame
* pOldAnchorFrame
= pContact
->GetAnchorFrame( pObj
);
755 const SwFrame
* pNewAnchorFrame
= pOldAnchorFrame
;
758 // Instead of only keeping the index position for an as-character
759 // anchored object the complete <SwPosition> is kept, because the
760 // anchor index position could be moved, if the object again is
761 // anchored as character.
762 std::optional
<SwPosition
> oOldAsCharAnchorPos
;
763 const RndStdIds eOldAnchorType
= pContact
->GetAnchorId();
764 if ( !_bSameOnly
&& eOldAnchorType
== RndStdIds::FLY_AS_CHAR
)
766 oOldAsCharAnchorPos
.emplace(*pContact
->GetAnchorFormat().GetContentAnchor());
770 _eAnchorType
= eOldAnchorType
;
772 SwFormatAnchor
aNewAnch( _eAnchorType
);
773 SwAnchoredObject
*pAnchoredObj
= pContact
->GetAnchoredObj(pObj
);
774 tools::Rectangle
aObjRect(pAnchoredObj
->GetObjRect().SVRect());
775 const Point
aPt( aObjRect
.TopLeft() );
777 switch ( _eAnchorType
)
779 case RndStdIds::FLY_AT_PARA
:
780 case RndStdIds::FLY_AT_CHAR
:
782 const Point aNewPoint
= ( pOldAnchorFrame
->IsVertical() ||
783 pOldAnchorFrame
->IsRightToLeft() )
784 ? aObjRect
.TopRight()
787 // allow drawing objects in header/footer
788 pNewAnchorFrame
= ::FindAnchor( pOldAnchorFrame
, aNewPoint
);
789 if ( pNewAnchorFrame
->IsTextFrame() && static_cast<const SwTextFrame
*>(pNewAnchorFrame
)->IsFollow() )
791 pNewAnchorFrame
= static_cast<const SwTextFrame
*>(pNewAnchorFrame
)->FindMaster();
793 if ( pNewAnchorFrame
->IsProtected() )
795 pNewAnchorFrame
= nullptr;
799 SwPosition
aPos( pNewAnchorFrame
->IsTextFrame()
800 ? *static_cast<SwTextFrame
const*>(pNewAnchorFrame
)->GetTextNodeForParaProps()
801 : *static_cast<SwNoTextFrame
const*>(pNewAnchorFrame
)->GetNode() );
803 aNewAnch
.SetType( _eAnchorType
);
804 aNewAnch
.SetAnchor( &aPos
);
809 case RndStdIds::FLY_AT_FLY
: // LAYER_IMPL
811 // Search the closest SwFlyFrame starting from the upper left corner.
814 SwCursorMoveState
aState( CursorMoveState::SetOnlyText
);
815 SwPosition
aPos( GetNodes() );
817 aPoint
.setX(aPoint
.getX() - 1);
818 getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( &aPos
, aPoint
, &aState
);
819 // consider that drawing objects can be in
820 // header/footer. Thus, <GetFrame()> by left-top-corner
821 std::pair
<Point
, bool> const tmp(aPt
, false);
822 pTextFrame
= aPos
.GetNode().
823 GetContentNode()->getLayoutFrame(
824 getIDocumentLayoutAccess().GetCurrentLayout(),
827 const SwFrame
*pTmp
= ::FindAnchor( pTextFrame
, aPt
);
828 pNewAnchorFrame
= pTmp
->FindFlyFrame();
829 if( pNewAnchorFrame
&& !pNewAnchorFrame
->IsProtected() )
831 const SwFrameFormat
*pTmpFormat
= static_cast<const SwFlyFrame
*>(pNewAnchorFrame
)->GetFormat();
832 const SwFormatContent
& rContent
= pTmpFormat
->GetContent();
833 SwPosition
aPos( *rContent
.GetContentIdx() );
834 aNewAnch
.SetAnchor( &aPos
);
838 aNewAnch
.SetType( RndStdIds::FLY_AT_PAGE
);
841 case RndStdIds::FLY_AT_PAGE
:
843 pNewAnchorFrame
= getIDocumentLayoutAccess().GetCurrentLayout()->Lower();
844 while ( pNewAnchorFrame
&& !pNewAnchorFrame
->getFrameArea().Contains( aPt
) )
845 pNewAnchorFrame
= pNewAnchorFrame
->GetNext();
846 if ( !pNewAnchorFrame
)
849 aNewAnch
.SetPageNum( static_cast<const SwPageFrame
*>(pNewAnchorFrame
)->GetPhyPageNum());
852 case RndStdIds::FLY_AS_CHAR
:
853 if( _bSameOnly
) // Change of position/size
855 if( !pOldAnchorFrame
)
857 pContact
->ConnectToLayout();
858 pOldAnchorFrame
= pContact
->GetAnchorFrame();
860 const_cast<SwTextFrame
*>(static_cast<const SwTextFrame
*>(pOldAnchorFrame
))->Prepare();
862 else // Change of anchors
864 // allow drawing objects in header/footer
865 pNewAnchorFrame
= ::FindAnchor( pOldAnchorFrame
, aPt
);
866 if( pNewAnchorFrame
->IsProtected() )
868 pNewAnchorFrame
= nullptr;
872 bUnmark
= ( 0 != i
);
874 aPoint
.setX(aPoint
.getX() - 1); // Do not load in the DrawObj!
875 aNewAnch
.SetType( RndStdIds::FLY_AS_CHAR
);
876 assert(pNewAnchorFrame
->IsTextFrame()); // because AS_CHAR
877 SwTextFrame
const*const pFrame(
878 static_cast<SwTextFrame
const*>(pNewAnchorFrame
));
879 SwPosition
aPos( *pFrame
->GetTextNodeForParaProps() );
880 if ( pNewAnchorFrame
->getFrameArea().Contains( aPoint
) )
882 // We need to find a TextNode, because only there we can anchor a
883 // content-bound DrawObject.
884 SwCursorMoveState
aState( CursorMoveState::SetOnlyText
);
885 getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( &aPos
, aPoint
, &aState
);
889 if ( pNewAnchorFrame
->getFrameArea().Bottom() < aPt
.Y() )
891 aPos
= pFrame
->MapViewToModelPos(TextFrameIndex(0));
895 aPos
= pFrame
->MapViewToModelPos(
896 TextFrameIndex(pFrame
->GetText().getLength()));
899 aNewAnch
.SetAnchor( &aPos
);
900 SetAttr( aNewAnch
, *pContact
->GetFormat() );
901 // #i26791# - adjust vertical positioning to 'center to
903 SetAttr( SwFormatVertOrient( 0, text::VertOrientation::CENTER
, text::RelOrientation::FRAME
), *pContact
->GetFormat() );
904 SwTextNode
*pNd
= aPos
.GetNode().GetTextNode();
905 OSL_ENSURE( pNd
, "Cursor not positioned at TextNode." );
907 SwFormatFlyCnt
aFormat( pContact
->GetFormat() );
908 pNd
->InsertItem( aFormat
, aPos
.GetContentIndex(), 0 );
910 // Has a textbox attached to the format? Sync it as well!
911 if (pContact
->GetFormat() && pContact
->GetFormat()->GetOtherTextBoxFormats())
913 SwTextBoxHelper::synchronizeGroupTextBoxProperty(
914 SwTextBoxHelper::changeAnchor
, pContact
->GetFormat(), pObj
);
919 OSL_ENSURE( false, "unexpected AnchorId." );
922 if ( (RndStdIds::FLY_AS_CHAR
!= _eAnchorType
) &&
924 ( !_bSameOnly
|| pNewAnchorFrame
!= pOldAnchorFrame
) )
926 // #i26791# - Direct object positioning no longer needed. Apply
927 // of attributes (method call <SetAttr(..)>) takes care of the
928 // invalidation of the object position.
931 // #i33313# - consider not connected 'virtual' drawing
933 auto pSwDrawVirtObj
= dynamic_cast<SwDrawVirtObj
*>( pObj
);
934 if ( pSwDrawVirtObj
&& !pSwDrawVirtObj
->IsConnected() )
936 SwRect
aNewObjRect( aObjRect
);
937 static_cast<SwAnchoredDrawObject
*>(pContact
->GetAnchoredObj( nullptr ))
938 ->AdjustPositioningAttr( pNewAnchorFrame
,
943 static_cast<SwAnchoredDrawObject
*>(pContact
->GetAnchoredObj( pObj
))
944 ->AdjustPositioningAttr( pNewAnchorFrame
);
947 if (aNewAnch
.GetAnchorId() == RndStdIds::FLY_AT_PAGE
)
949 SwFormatHoriOrient
item(pContact
->GetFormat()->GetHoriOrient());
950 sal_Int16
nRelOrient(item
.GetRelationOrient());
951 if (sw::GetAtPageRelOrientation(nRelOrient
, false))
953 SAL_INFO("sw.ui", "fixing horizontal RelOrientation for at-page anchor");
954 item
.SetRelationOrient(nRelOrient
);
955 SetAttr(item
, *pContact
->GetFormat());
958 // tdf#136385 set the anchor last - otherwise it messes up the
959 // position in SwDrawContact::Changed_() callback
960 SetAttr(aNewAnch
, *pContact
->GetFormat());
963 // we have changed the anchoring attributes, and those are used to
964 // order the object in its sorted list, so update its position
965 pAnchoredObj
->UpdateObjInSortedList();
968 if (oOldAsCharAnchorPos
)
970 if ( pNewAnchorFrame
)
972 // We need to handle InContents in a special way:
973 // The TextAttribut needs to be destroyed which, unfortunately, also
974 // destroys the format. To avoid that, we disconnect the format from
976 const sal_Int32
nIndx( oOldAsCharAnchorPos
->GetContentIndex() );
977 SwTextNode
* pTextNode( oOldAsCharAnchorPos
->GetNode().GetTextNode() );
978 assert(pTextNode
&& "<SwDoc::ChgAnchor(..)> - missing previous anchor text node for as-character anchored object");
979 SwTextAttr
* const pHint
=
980 pTextNode
->GetTextAttrForCharAt( nIndx
, RES_TXTATR_FLYCNT
);
981 assert(pHint
&& "Missing FlyInCnt-Hint.");
982 const_cast<SwFormatFlyCnt
&>(pHint
->GetFlyCnt()).SetFlyFormat();
984 // They are disconnected. We now have to destroy the attribute.
985 pTextNode
->DeleteAttributes( RES_TXTATR_FLYCNT
, nIndx
, nIndx
);
991 GetIDocumentUndoRedo().EndUndo( SwUndoId::END
, nullptr );
992 getIDocumentState().SetModified();
997 SwChainRet
SwDoc::Chainable( const SwFrameFormat
&rSource
, const SwFrameFormat
&rDest
)
999 // The Source must not yet have a Follow.
1000 const SwFormatChain
&rOldChain
= rSource
.GetChain();
1001 if ( rOldChain
.GetNext() )
1002 return SwChainRet::SOURCE_CHAINED
;
1004 // Target must not be equal to Source and we also must not have a closed chain.
1005 const SwFrameFormat
*pFormat
= &rDest
;
1007 if( pFormat
== &rSource
)
1008 return SwChainRet::SELF
;
1009 pFormat
= pFormat
->GetChain().GetNext();
1010 } while ( pFormat
);
1012 // There must not be a chaining from outside to inside or the other way around.
1013 if( rDest
.IsLowerOf( rSource
) || rSource
.IsLowerOf( rDest
) )
1014 return SwChainRet::SELF
;
1016 // The Target must not yet have a Master.
1017 const SwFormatChain
&rChain
= rDest
.GetChain();
1018 if( rChain
.GetPrev() )
1019 return SwChainRet::IS_IN_CHAIN
;
1021 // Split flys are incompatible with chaining.
1022 const SwFormatFlySplit
& rOldSplit
= rSource
.GetFlySplit();
1023 if (rOldSplit
.GetValue())
1025 return SwChainRet::SOURCE_CHAINED
;
1027 const SwFormatFlySplit
& rNewSplit
= rDest
.GetFlySplit();
1028 if (rNewSplit
.GetValue())
1030 return SwChainRet::IS_IN_CHAIN
;
1033 // Target must be empty.
1034 const SwNodeIndex
* pCntIdx
= rDest
.GetContent().GetContentIdx();
1036 return SwChainRet::NOT_FOUND
;
1038 SwNodeIndex
aNxtIdx( *pCntIdx
, 1 );
1039 const SwTextNode
* pTextNd
= aNxtIdx
.GetNode().GetTextNode();
1041 return SwChainRet::NOT_FOUND
;
1043 const SwNodeOffset nFlySttNd
= pCntIdx
->GetIndex();
1044 if( SwNodeOffset(2) != ( pCntIdx
->GetNode().EndOfSectionIndex() - nFlySttNd
) ||
1045 pTextNd
->GetText().getLength() )
1047 return SwChainRet::NOT_EMPTY
;
1050 for(sw::SpzFrameFormat
* pSpzFrameFm
: *GetSpzFrameFormats())
1052 const SwFormatAnchor
& rAnchor
= pSpzFrameFm
->GetAnchor();
1053 // #i20622# - to-frame anchored objects are allowed.
1054 if ( (rAnchor
.GetAnchorId() != RndStdIds::FLY_AT_PARA
) &&
1055 (rAnchor
.GetAnchorId() != RndStdIds::FLY_AT_CHAR
) )
1057 if ( nullptr == rAnchor
.GetAnchorNode() )
1059 SwNodeOffset nTstSttNd
= rAnchor
.GetAnchorNode()->GetIndex();
1060 if( nFlySttNd
<= nTstSttNd
&& nTstSttNd
< nFlySttNd
+ SwNodeOffset(2) )
1062 return SwChainRet::NOT_EMPTY
;
1066 // We also need to consider the right area.
1067 // Both Flys need to be located in the same area (Body, Header/Footer, Fly).
1068 // If the Source is not the selected frame, it's enough to find a suitable
1069 // one. e.g. if it's requested by the API.
1071 // both in the same fly, header, footer or on the page?
1072 const SwFormatAnchor
&rSrcAnchor
= rSource
.GetAnchor(),
1073 &rDstAnchor
= rDest
.GetAnchor();
1074 SwNodeOffset nEndOfExtras
= GetNodes().GetEndOfExtras().GetIndex();
1075 bool bAllowed
= false;
1076 if ( RndStdIds::FLY_AT_PAGE
== rSrcAnchor
.GetAnchorId() )
1078 if ( (RndStdIds::FLY_AT_PAGE
== rDstAnchor
.GetAnchorId()) ||
1079 ( rDstAnchor
.GetAnchorNode() &&
1080 rDstAnchor
.GetAnchorNode()->GetIndex() > nEndOfExtras
))
1083 else if( rSrcAnchor
.GetAnchorNode() && rDstAnchor
.GetAnchorNode() )
1085 const SwNode
&rSrcNd
= *rSrcAnchor
.GetAnchorNode(),
1086 &rDstNd
= *rDstAnchor
.GetAnchorNode();
1087 const SwStartNode
* pSttNd
= nullptr;
1088 if( rSrcNd
== rDstNd
||
1090 nullptr != ( pSttNd
= rSrcNd
.FindFlyStartNode() ) &&
1091 pSttNd
== rDstNd
.FindFlyStartNode() ) ||
1093 nullptr != ( pSttNd
= rSrcNd
.FindFooterStartNode() ) &&
1094 pSttNd
== rDstNd
.FindFooterStartNode() ) ||
1096 nullptr != ( pSttNd
= rSrcNd
.FindHeaderStartNode() ) &&
1097 pSttNd
== rDstNd
.FindHeaderStartNode() ) ||
1098 ( !pSttNd
&& rDstNd
.GetIndex() > nEndOfExtras
&&
1099 rSrcNd
.GetIndex() > nEndOfExtras
))
1103 return bAllowed
? SwChainRet::OK
: SwChainRet::WRONG_AREA
;
1106 SwChainRet
SwDoc::Chain( SwFrameFormat
&rSource
, const SwFrameFormat
&rDest
)
1108 SwChainRet nErr
= Chainable( rSource
, rDest
);
1109 if ( nErr
== SwChainRet::OK
)
1111 GetIDocumentUndoRedo().StartUndo( SwUndoId::CHAINE
, nullptr );
1113 SwFlyFrameFormat
& rDestFormat
= const_cast<SwFlyFrameFormat
&>(static_cast<const SwFlyFrameFormat
&>(rDest
));
1115 // Attach Follow to the Master.
1116 SwFormatChain aChain
= rDestFormat
.GetChain();
1117 aChain
.SetPrev( &static_cast<SwFlyFrameFormat
&>(rSource
) );
1118 SetAttr( aChain
, rDestFormat
);
1120 SfxItemSetFixed
<RES_FRM_SIZE
, RES_FRM_SIZE
,
1121 RES_CHAIN
, RES_CHAIN
> aSet( GetAttrPool() );
1123 // Attach Follow to the Master.
1124 aChain
.SetPrev( &static_cast<SwFlyFrameFormat
&>(rSource
) );
1125 SetAttr( aChain
, rDestFormat
);
1127 // Attach Master to the Follow.
1128 // Make sure that the Master has a fixed height.
1129 aChain
= rSource
.GetChain();
1130 aChain
.SetNext( &rDestFormat
);
1133 SwFormatFrameSize
aSize( rSource
.GetFrameSize() );
1134 if ( aSize
.GetHeightSizeType() != SwFrameSize::Fixed
)
1136 SwFlyFrame
*pFly
= SwIterator
<SwFlyFrame
,SwFormat
>( rSource
).First();
1138 aSize
.SetHeight( pFly
->getFrameArea().Height() );
1139 aSize
.SetHeightSizeType( SwFrameSize::Fixed
);
1142 SetAttr( aSet
, rSource
);
1144 GetIDocumentUndoRedo().EndUndo( SwUndoId::CHAINE
, nullptr );
1149 void SwDoc::Unchain( SwFrameFormat
&rFormat
)
1151 SwFormatChain
aChain( rFormat
.GetChain() );
1152 if ( aChain
.GetNext() )
1154 GetIDocumentUndoRedo().StartUndo( SwUndoId::UNCHAIN
, nullptr );
1155 SwFrameFormat
*pFollow
= aChain
.GetNext();
1156 aChain
.SetNext( nullptr );
1157 SetAttr( aChain
, rFormat
);
1158 aChain
= pFollow
->GetChain();
1159 aChain
.SetPrev( nullptr );
1160 SetAttr( aChain
, *pFollow
);
1161 GetIDocumentUndoRedo().EndUndo( SwUndoId::UNCHAIN
, nullptr );
1165 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */