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 .
22 #include <cellatr.hxx>
23 #include <charfmt.hxx>
24 #include <fchrfmt.hxx>
26 #include <IDocumentListsAccess.hxx>
27 #include <editeng/editeng.hxx>
28 #include <fmtanchr.hxx>
29 #include <fmtpdsc.hxx>
30 #include <fmtautofmt.hxx>
31 #include <hintids.hxx>
34 #include <numrule.hxx>
35 #include <pagedesc.hxx>
37 #include <o3tl/unit_conversion.hxx>
38 #include <osl/diagnose.h>
39 #include <svl/whiter.hxx>
41 #include <svx/svdpool.hxx>
42 #include <svx/sxenditm.hxx>
43 #include <svx/sdsxyitm.hxx>
45 SwAttrPool::SwAttrPool( SwDoc
* pD
)
47 POOLATTR_BEGIN
, POOLATTR_END
-1,
48 aSlotTab
, &aAttrTab
),
51 // create SfxItemPool and EditEngine pool and add these in a chain. These
52 // belong us and will be removed/destroyed in removeAndDeleteSecondaryPools() used from
54 rtl::Reference
<SfxItemPool
> pSdrPool
= new SdrItemPool(this);
56 // #75371# change DefaultItems for the SdrEdgeObj distance items
58 constexpr tools::Long nDefEdgeDist
59 = o3tl::convert(500, o3tl::Length::mm100
, o3tl::Length::twip
);
61 pSdrPool
->SetPoolDefaultItem(SdrEdgeNode1HorzDistItem(nDefEdgeDist
));
62 pSdrPool
->SetPoolDefaultItem(SdrEdgeNode1VertDistItem(nDefEdgeDist
));
63 pSdrPool
->SetPoolDefaultItem(SdrEdgeNode2HorzDistItem(nDefEdgeDist
));
64 pSdrPool
->SetPoolDefaultItem(SdrEdgeNode2VertDistItem(nDefEdgeDist
));
66 // #i33700# // Set shadow distance defaults as PoolDefaultItems
67 constexpr tools::Long nDefShadowDist
68 = o3tl::convert(300, o3tl::Length::mm100
, o3tl::Length::twip
);
69 pSdrPool
->SetPoolDefaultItem(makeSdrShadowXDistItem(nDefShadowDist
));
70 pSdrPool
->SetPoolDefaultItem(makeSdrShadowYDistItem(nDefShadowDist
));
72 rtl::Reference
<SfxItemPool
> pEEgPool
= EditEngine::CreatePool();
74 pSdrPool
->SetSecondaryPool(pEEgPool
.get());
76 if(GetFrozenIdRanges().empty())
82 pSdrPool
->FreezeIdRanges();
86 SwAttrPool::~SwAttrPool()
88 // cleanup secondary pools
89 SfxItemPool
*pSdrPool
= GetSecondaryPool();
90 // first delete the items, then break the linking
92 SetSecondaryPool(nullptr);
95 SwAttrSet::SwAttrSet( SwAttrPool
& rPool
, sal_uInt16 nWh1
, sal_uInt16 nWh2
)
96 : SfxItemSet( rPool
, nWh1
, nWh2
), m_pOldSet( nullptr ), m_pNewSet( nullptr )
100 SwAttrSet::SwAttrSet( SwAttrPool
& rPool
, const WhichRangesContainer
& nWhichPairTable
)
101 : SfxItemSet( rPool
, nWhichPairTable
)
102 , m_pOldSet( nullptr ), m_pNewSet( nullptr )
106 SwAttrSet::SwAttrSet( const SwAttrSet
& rSet
)
107 : SfxItemSet( rSet
), m_pOldSet( nullptr ), m_pNewSet( nullptr )
111 std::unique_ptr
<SfxItemSet
> SwAttrSet::Clone( bool bItems
, SfxItemPool
*pToPool
) const
113 if ( pToPool
&& pToPool
!= GetPool() )
115 SwAttrPool
* pAttrPool
= dynamic_cast< SwAttrPool
* >(pToPool
);
116 std::unique_ptr
<SfxItemSet
> pTmpSet
;
118 pTmpSet
= SfxItemSet::Clone( bItems
, pToPool
);
121 pTmpSet
.reset(new SwAttrSet( *pAttrPool
, GetRanges() ));
124 SfxWhichIter
aIter(*pTmpSet
);
125 sal_uInt16 nWhich
= aIter
.FirstWhich();
128 const SfxPoolItem
* pItem
;
129 if ( SfxItemState::SET
== GetItemState( nWhich
, false, &pItem
) )
130 pTmpSet
->Put( *pItem
);
131 nWhich
= aIter
.NextWhich();
138 return std::unique_ptr
<SfxItemSet
>(
140 ? new SwAttrSet( *this )
141 : new SwAttrSet( *GetPool(), GetRanges() ));
144 bool SwAttrSet::Put_BC( const SfxPoolItem
& rAttr
,
145 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
149 bool bRet
= nullptr != SfxItemSet::Put( rAttr
);
150 m_pOldSet
= m_pNewSet
= nullptr;
154 bool SwAttrSet::Put_BC( const SfxItemSet
& rSet
,
155 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
159 bool bRet
= SfxItemSet::Put( rSet
);
160 m_pOldSet
= m_pNewSet
= nullptr;
164 sal_uInt16
SwAttrSet::ClearItem_BC( sal_uInt16 nWhich
,
165 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
169 sal_uInt16 nRet
= SfxItemSet::ClearItem( nWhich
);
170 m_pOldSet
= m_pNewSet
= nullptr;
174 sal_uInt16
SwAttrSet::ClearItem_BC( sal_uInt16 nWhich1
, sal_uInt16 nWhich2
,
175 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
177 OSL_ENSURE( nWhich1
<= nWhich2
, "no valid range" );
181 for( ; nWhich1
<= nWhich2
; ++nWhich1
)
182 nRet
= nRet
+ SfxItemSet::ClearItem( nWhich1
);
183 m_pOldSet
= m_pNewSet
= nullptr;
187 int SwAttrSet::Intersect_BC( const SfxItemSet
& rSet
,
188 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
192 SfxItemSet::Intersect( rSet
);
193 m_pOldSet
= m_pNewSet
= nullptr;
194 return pNew
? pNew
->Count() : ( pOld
? pOld
->Count() : 0 );
197 /// Notification callback
198 void SwAttrSet::Changed( const SfxPoolItem
& rOld
, const SfxPoolItem
& rNew
)
201 m_pOldSet
->PutChgd( rOld
);
203 m_pNewSet
->PutChgd( rNew
);
206 /** special treatment for some attributes
208 Set the Modify pointer (old pDefinedIn) for the following attributes:
212 (Is called at inserts into formats/nodes)
214 bool SwAttrSet::SetModifyAtAttr( const sw::BroadcastingModify
* pModify
)
218 const SwFormatPageDesc
* pPageDescItem
= GetItemIfSet( RES_PAGEDESC
, false );
220 pPageDescItem
->GetDefinedIn() != pModify
)
222 const_cast<SwFormatPageDesc
&>(*pPageDescItem
).ChgDefinedIn( pModify
);
226 if(SwFormatDrop
* pFormatDrop
= const_cast<SwFormatDrop
*>(GetItemIfSet( RES_PARATR_DROP
, false )))
228 auto pDropDefiner
= dynamic_cast<const sw::FormatDropDefiner
*>(pModify
);
229 // If CharFormat is set and it is set in different attribute pools then
230 // the CharFormat has to be copied.
231 SwCharFormat
* pCharFormat
= pFormatDrop
->GetCharFormat();
232 if(pCharFormat
&& GetPool() != pCharFormat
->GetAttrSet().GetPool())
234 pCharFormat
= GetDoc()->CopyCharFormat(*pCharFormat
);
235 pFormatDrop
->SetCharFormat(pCharFormat
);
237 pFormatDrop
->ChgDefinedIn(pDropDefiner
);
241 const SwTableBoxFormula
* pBoxFormula
= GetItemIfSet( RES_BOXATR_FORMULA
, false );
242 if( pBoxFormula
&& pBoxFormula
->GetDefinedIn() != pModify
)
244 const_cast<SwTableBoxFormula
&>(*pBoxFormula
).ChgDefinedIn( pModify
);
251 void SwAttrSet::CopyToModify( sw::BroadcastingModify
& rMod
) const
253 // copy attributes across multiple documents if needed
254 SwContentNode
* pCNd
= dynamic_cast<SwContentNode
*>( &rMod
);
255 SwFormat
* pFormat
= dynamic_cast<SwFormat
*>( &rMod
);
257 if( pCNd
|| pFormat
)
262 std::unique_ptr
<SfxStringItem
> pNewListIdItem
;
264 const SwDoc
*pSrcDoc
= GetDoc();
265 SwDoc
*pDstDoc
= pCNd
? &pCNd
->GetDoc() : pFormat
->GetDoc();
267 // Does the NumRule has to be copied?
268 const SwNumRuleItem
* pNumRuleItem
;
269 if( pSrcDoc
!= pDstDoc
&&
270 (pNumRuleItem
= GetItemIfSet( RES_PARATR_NUMRULE
, false )) )
272 const OUString
& rNm
= pNumRuleItem
->GetValue();
275 SwNumRule
* pDestRule
= pDstDoc
->FindNumRulePtr( rNm
);
277 pDestRule
->SetInvalidRule( true );
279 pDstDoc
->MakeNumRule( rNm
, pSrcDoc
->FindNumRulePtr( rNm
) );
283 // copy list and if needed also the corresponding list style
285 const SfxStringItem
* pStrItem
;
286 if ( pSrcDoc
!= pDstDoc
&&
287 pCNd
&& pCNd
->IsTextNode() &&
288 (pStrItem
= GetItemIfSet( RES_PARATR_LIST_ID
, false )) )
290 const OUString
& sListId
= pStrItem
->GetValue();
291 if ( !sListId
.isEmpty() &&
292 !pDstDoc
->getIDocumentListsAccess().getListByName( sListId
) )
294 const SwList
* pList
= pSrcDoc
->getIDocumentListsAccess().getListByName( sListId
);
295 // copy list style, if needed
296 const OUString
& sDefaultListStyleName
=
297 pList
->GetDefaultListStyleName();
299 const SwNumRule
* pDstDocNumRule
=
300 pDstDoc
->FindNumRulePtr( sDefaultListStyleName
);
301 if ( !pDstDocNumRule
)
303 pDstDoc
->MakeNumRule( sDefaultListStyleName
,
304 pSrcDoc
->FindNumRulePtr( sDefaultListStyleName
) );
308 const SwNumRule
* pSrcDocNumRule
=
309 pSrcDoc
->FindNumRulePtr( sDefaultListStyleName
);
310 // If list id of text node equals the list style's
311 // default list id in the source document, the same
312 // should be hold in the destination document.
313 // Thus, create new list id item.
314 if (pSrcDocNumRule
&& sListId
== pSrcDocNumRule
->GetDefaultListId())
316 pNewListIdItem
.reset(new SfxStringItem (
318 pDstDocNumRule
->GetDefaultListId() ));
321 // check again, if list exist, because <SwDoc::MakeNumRule(..)>
322 // could have also created it.
323 if ( pNewListIdItem
== nullptr &&
324 !pDstDoc
->getIDocumentListsAccess().getListByName( sListId
) )
327 pDstDoc
->getIDocumentListsAccess().createList( sListId
, sDefaultListStyleName
);
332 std::optional
< SfxItemSet
> tmpSet
;
333 const SwFormatPageDesc
* pPageDescItem
;
334 if( pSrcDoc
!= pDstDoc
&& (pPageDescItem
= GetItemIfSet(
335 RES_PAGEDESC
, false )))
337 const SwPageDesc
* pPgDesc
= pPageDescItem
->GetPageDesc();
340 tmpSet
.emplace(*this);
342 SwPageDesc
* pDstPgDesc
= pDstDoc
->FindPageDesc(pPgDesc
->GetName());
345 pDstPgDesc
= pDstDoc
->MakePageDesc(pPgDesc
->GetName());
346 pDstDoc
->CopyPageDesc( *pPgDesc
, *pDstPgDesc
);
348 SwFormatPageDesc
aDesc( pDstPgDesc
);
349 aDesc
.SetNumOffset( pPageDescItem
->GetNumOffset() );
350 tmpSet
->Put( aDesc
);
354 const SwFormatAnchor
* pAnchorItem
;
355 if( pSrcDoc
!= pDstDoc
&& (pAnchorItem
= GetItemIfSet( RES_ANCHOR
, false ))
356 && pAnchorItem
->GetAnchorNode() != nullptr )
359 tmpSet
.emplace( *this );
360 // Anchors at any node position cannot be copied to another document, because the SwPosition
361 // would still point to the old document. It needs to be fixed up explicitly.
362 tmpSet
->ClearItem( RES_ANCHOR
);
365 const SwFormatAutoFormat
* pAutoFormatItem
;
366 if (pSrcDoc
!= pDstDoc
&&
367 (pAutoFormatItem
= GetItemIfSet(RES_PARATR_LIST_AUTOFMT
, false)) &&
368 pAutoFormatItem
->GetStyleHandle())
370 SfxItemSet
const& rAutoStyle(*pAutoFormatItem
->GetStyleHandle());
371 std::shared_ptr
<SfxItemSet
> const pNewSet(
372 rAutoStyle
.SfxItemSet::Clone(true, &pDstDoc
->GetAttrPool()));
374 // fix up character style, it contains pointers to pSrcDoc
375 if (const SwFormatCharFormat
* pCharFormatItem
= pNewSet
->GetItemIfSet(RES_TXTATR_CHARFMT
, false))
377 SwCharFormat
*const pCopy(pDstDoc
->CopyCharFormat(*pCharFormatItem
->GetCharFormat()));
378 const_cast<SwFormatCharFormat
&>(*pCharFormatItem
).SetCharFormat(pCopy
);
381 SwFormatAutoFormat
item(RES_PARATR_LIST_AUTOFMT
);
382 // TODO: for ODF export we'd need to add it to the autostyle pool
383 item
.SetStyleHandle(pNewSet
);
386 tmpSet
.emplace(*this);
396 if ( pNewListIdItem
!= nullptr )
398 tmpSet
->Put( std::move(pNewListIdItem
) );
400 pCNd
->SetAttr( *tmpSet
);
404 pFormat
->SetFormatAttr( *tmpSet
);
410 if ( pNewListIdItem
!= nullptr )
412 SfxItemSet
aTmpSet( *this );
413 aTmpSet
.Put( std::move(pNewListIdItem
) );
414 pCNd
->SetAttr( aTmpSet
);
418 pCNd
->SetAttr( *this );
423 pFormat
->SetFormatAttr( *this );
426 if (pCNd
&& pCNd
->HasSwAttrSet())
428 SfxWhichIter
it(*this);
429 std::vector
<sal_uInt16
> toClear
;
430 for (sal_uInt16 nWhich
= it
.FirstWhich(); nWhich
!= 0; nWhich
= it
.NextWhich())
432 if (GetItemState(nWhich
, false) != SfxItemState::SET
433 && pCNd
->GetSwAttrSet().GetItemState(nWhich
, false) == SfxItemState::SET
)
435 toClear
.emplace_back(nWhich
);
438 if (!toClear
.empty())
440 pCNd
->ResetAttr(toClear
);
444 #if OSL_DEBUG_LEVEL > 0
446 OSL_FAIL("neither Format nor ContentNode - no Attributes copied");
450 /// check if ID is in range of attribute set IDs
451 bool IsInRange( const WhichRangesContainer
& pRange
, const sal_uInt16 nId
)
453 for(const auto& rPair
: pRange
)
455 if( rPair
.first
<= nId
&& nId
<= rPair
.second
)
461 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */