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 <osl/diagnose.h>
38 #include <svl/whiter.hxx>
40 #include <svx/svdpool.hxx>
41 #include <svx/sxenditm.hxx>
42 #include <svx/sdsxyitm.hxx>
44 SwAttrPool::SwAttrPool( SwDoc
* pD
)
46 POOLATTR_BEGIN
, POOLATTR_END
-1,
47 aSlotTab
, &aAttrTab
),
50 // create secondary pools immediately
51 createAndAddSecondaryPools();
54 SwAttrPool::~SwAttrPool()
56 // cleanup secondary pools first
57 removeAndDeleteSecondaryPools();
60 void SwAttrPool::createAndAddSecondaryPools()
62 const SfxItemPool
* pCheckAlreadySet
= GetSecondaryPool();
66 OSL_ENSURE(false, "SwAttrPool already has a secondary pool (!)");
70 // create SfxItemPool and EditEngine pool and add these in a chain. These
71 // belong us and will be removed/destroyed in removeAndDeleteSecondaryPools() used from
73 SfxItemPool
*pSdrPool
= new SdrItemPool(this);
75 // #75371# change DefaultItems for the SdrEdgeObj distance items
77 // 1/100th mm in twips
78 const tools::Long nDefEdgeDist
= (500 * 72) / 127;
80 pSdrPool
->SetPoolDefaultItem(SdrEdgeNode1HorzDistItem(nDefEdgeDist
));
81 pSdrPool
->SetPoolDefaultItem(SdrEdgeNode1VertDistItem(nDefEdgeDist
));
82 pSdrPool
->SetPoolDefaultItem(SdrEdgeNode2HorzDistItem(nDefEdgeDist
));
83 pSdrPool
->SetPoolDefaultItem(SdrEdgeNode2VertDistItem(nDefEdgeDist
));
85 // #i33700# // Set shadow distance defaults as PoolDefaultItems
86 pSdrPool
->SetPoolDefaultItem(makeSdrShadowXDistItem((300 * 72) / 127));
87 pSdrPool
->SetPoolDefaultItem(makeSdrShadowYDistItem((300 * 72) / 127));
89 SfxItemPool
*pEEgPool
= EditEngine::CreatePool();
91 pSdrPool
->SetSecondaryPool(pEEgPool
);
93 if(!GetFrozenIdRanges())
99 pSdrPool
->FreezeIdRanges();
103 void SwAttrPool::removeAndDeleteSecondaryPools()
105 SfxItemPool
*pSdrPool
= GetSecondaryPool();
109 OSL_ENSURE(false, "SwAttrPool has no secondary pool, it's missing (!)");
113 SfxItemPool
*pEEgPool
= pSdrPool
->GetSecondaryPool();
117 OSL_ENSURE(false, "i don't accept additional pools");
121 // first delete the items, then break the linking
124 SetSecondaryPool(nullptr);
125 pSdrPool
->SetSecondaryPool(nullptr);
127 // final cleanup of secondary pool(s)
128 SfxItemPool::Free(pSdrPool
);
129 SfxItemPool::Free(pEEgPool
);
132 SwAttrSet::SwAttrSet( SwAttrPool
& rPool
, sal_uInt16 nWh1
, sal_uInt16 nWh2
)
133 : SfxItemSet( rPool
, {{nWh1
, nWh2
}} ), m_pOldSet( nullptr ), m_pNewSet( nullptr )
137 SwAttrSet::SwAttrSet( SwAttrPool
& rPool
, const sal_uInt16
* nWhichPairTable
)
138 : SfxItemSet( rPool
, nWhichPairTable
), m_pOldSet( nullptr ), m_pNewSet( nullptr )
142 SwAttrSet::SwAttrSet( const SwAttrSet
& rSet
)
143 : SfxItemSet( rSet
), m_pOldSet( nullptr ), m_pNewSet( nullptr )
147 std::unique_ptr
<SfxItemSet
> SwAttrSet::Clone( bool bItems
, SfxItemPool
*pToPool
) const
149 if ( pToPool
&& pToPool
!= GetPool() )
151 SwAttrPool
* pAttrPool
= dynamic_cast< SwAttrPool
* >(pToPool
);
152 std::unique_ptr
<SfxItemSet
> pTmpSet
;
154 pTmpSet
= SfxItemSet::Clone( bItems
, pToPool
);
157 pTmpSet
.reset(new SwAttrSet( *pAttrPool
, GetRanges() ));
160 SfxWhichIter
aIter(*pTmpSet
);
161 sal_uInt16 nWhich
= aIter
.FirstWhich();
164 const SfxPoolItem
* pItem
;
165 if ( SfxItemState::SET
== GetItemState( nWhich
, false, &pItem
) )
166 pTmpSet
->Put( *pItem
);
167 nWhich
= aIter
.NextWhich();
174 return std::unique_ptr
<SfxItemSet
>(
176 ? new SwAttrSet( *this )
177 : new SwAttrSet( *GetPool(), GetRanges() ));
180 bool SwAttrSet::Put_BC( const SfxPoolItem
& rAttr
,
181 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
185 bool bRet
= nullptr != SfxItemSet::Put( rAttr
);
186 m_pOldSet
= m_pNewSet
= nullptr;
190 bool SwAttrSet::Put_BC( const SfxItemSet
& rSet
,
191 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
195 bool bRet
= SfxItemSet::Put( rSet
);
196 m_pOldSet
= m_pNewSet
= nullptr;
200 sal_uInt16
SwAttrSet::ClearItem_BC( sal_uInt16 nWhich
,
201 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
205 sal_uInt16 nRet
= SfxItemSet::ClearItem( nWhich
);
206 m_pOldSet
= m_pNewSet
= nullptr;
210 sal_uInt16
SwAttrSet::ClearItem_BC( sal_uInt16 nWhich1
, sal_uInt16 nWhich2
,
211 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
213 OSL_ENSURE( nWhich1
<= nWhich2
, "no valid range" );
217 for( ; nWhich1
<= nWhich2
; ++nWhich1
)
218 nRet
= nRet
+ SfxItemSet::ClearItem( nWhich1
);
219 m_pOldSet
= m_pNewSet
= nullptr;
223 int SwAttrSet::Intersect_BC( const SfxItemSet
& rSet
,
224 SwAttrSet
* pOld
, SwAttrSet
* pNew
)
228 SfxItemSet::Intersect( rSet
);
229 m_pOldSet
= m_pNewSet
= nullptr;
230 return pNew
? pNew
->Count() : ( pOld
? pOld
->Count() : 0 );
233 /// Notification callback
234 void SwAttrSet::Changed( const SfxPoolItem
& rOld
, const SfxPoolItem
& rNew
)
237 m_pOldSet
->PutChgd( rOld
);
239 m_pNewSet
->PutChgd( rNew
);
242 /** special treatment for some attributes
244 Set the Modify pointer (old pDefinedIn) for the following attributes:
248 (Is called at inserts into formats/nodes)
250 bool SwAttrSet::SetModifyAtAttr( const sw::BroadcastingModify
* pModify
)
254 const SfxPoolItem
* pItem
;
255 if( SfxItemState::SET
== GetItemState( RES_PAGEDESC
, false, &pItem
) &&
256 static_cast<const SwFormatPageDesc
*>(pItem
)->GetDefinedIn() != pModify
)
258 const_cast<SwFormatPageDesc
*>(static_cast<const SwFormatPageDesc
*>(pItem
))->ChgDefinedIn( pModify
);
262 if( SfxItemState::SET
== GetItemState( RES_PARATR_DROP
, false, &pItem
) &&
263 static_cast<const SwFormatDrop
*>(pItem
)->GetDefinedIn() != pModify
)
265 // If CharFormat is set and it is set in different attribute pools then
266 // the CharFormat has to be copied.
267 SwCharFormat
* pCharFormat
= const_cast<SwFormatDrop
*>(static_cast<const SwFormatDrop
*>(pItem
))->GetCharFormat();
268 if( pCharFormat
&& GetPool() != pCharFormat
->GetAttrSet().GetPool() )
270 pCharFormat
= GetDoc()->CopyCharFormat( *pCharFormat
);
271 const_cast<SwFormatDrop
*>(static_cast<const SwFormatDrop
*>(pItem
))->SetCharFormat( pCharFormat
);
273 const_cast<SwFormatDrop
*>(static_cast<const SwFormatDrop
*>(pItem
))->ChgDefinedIn( pModify
);
277 if( SfxItemState::SET
== GetItemState( RES_BOXATR_FORMULA
, false, &pItem
) &&
278 static_cast<const SwTableBoxFormula
*>(pItem
)->GetDefinedIn() != pModify
)
280 const_cast<SwTableBoxFormula
*>(static_cast<const SwTableBoxFormula
*>(pItem
))->ChgDefinedIn( pModify
);
287 void SwAttrSet::CopyToModify( sw::BroadcastingModify
& rMod
) const
289 // copy attributes across multiple documents if needed
290 SwContentNode
* pCNd
= dynamic_cast<SwContentNode
*>( &rMod
);
291 SwFormat
* pFormat
= dynamic_cast<SwFormat
*>( &rMod
);
293 if( pCNd
|| pFormat
)
298 std::unique_ptr
<SfxStringItem
> pNewListIdItem
;
300 const SfxPoolItem
* pItem
;
301 const SwDoc
*pSrcDoc
= GetDoc();
302 SwDoc
*pDstDoc
= pCNd
? &pCNd
->GetDoc() : pFormat
->GetDoc();
304 // Does the NumRule has to be copied?
305 if( pSrcDoc
!= pDstDoc
&&
306 SfxItemState::SET
== GetItemState( RES_PARATR_NUMRULE
, false, &pItem
) )
308 const OUString
& rNm
= static_cast<const SwNumRuleItem
*>(pItem
)->GetValue();
311 SwNumRule
* pDestRule
= pDstDoc
->FindNumRulePtr( rNm
);
313 pDestRule
->SetInvalidRule( true );
315 pDstDoc
->MakeNumRule( rNm
, pSrcDoc
->FindNumRulePtr( rNm
) );
319 // copy list and if needed also the corresponding list style
321 if ( pSrcDoc
!= pDstDoc
&&
322 pCNd
&& pCNd
->IsTextNode() &&
323 GetItemState( RES_PARATR_LIST_ID
, false, &pItem
) == SfxItemState::SET
)
325 auto pStrItem
= dynamic_cast<const SfxStringItem
*>(pItem
);
327 const OUString
& sListId
= pStrItem
->GetValue();
328 if ( !sListId
.isEmpty() &&
329 !pDstDoc
->getIDocumentListsAccess().getListByName( sListId
) )
331 const SwList
* pList
= pSrcDoc
->getIDocumentListsAccess().getListByName( sListId
);
332 // copy list style, if needed
333 const OUString
& sDefaultListStyleName
=
334 pList
->GetDefaultListStyleName();
336 const SwNumRule
* pDstDocNumRule
=
337 pDstDoc
->FindNumRulePtr( sDefaultListStyleName
);
338 if ( !pDstDocNumRule
)
340 pDstDoc
->MakeNumRule( sDefaultListStyleName
,
341 pSrcDoc
->FindNumRulePtr( sDefaultListStyleName
) );
345 const SwNumRule
* pSrcDocNumRule
=
346 pSrcDoc
->FindNumRulePtr( sDefaultListStyleName
);
347 // If list id of text node equals the list style's
348 // default list id in the source document, the same
349 // should be hold in the destination document.
350 // Thus, create new list id item.
351 if (pSrcDocNumRule
&& sListId
== pSrcDocNumRule
->GetDefaultListId())
353 pNewListIdItem
.reset(new SfxStringItem (
355 pDstDocNumRule
->GetDefaultListId() ));
358 // check again, if list exist, because <SwDoc::MakeNumRule(..)>
359 // could have also created it.
360 if ( pNewListIdItem
== nullptr &&
361 !pDstDoc
->getIDocumentListsAccess().getListByName( sListId
) )
364 pDstDoc
->getIDocumentListsAccess().createList( sListId
, sDefaultListStyleName
);
369 std::unique_ptr
< SfxItemSet
> tmpSet
;
371 if( pSrcDoc
!= pDstDoc
&& SfxItemState::SET
== GetItemState(
372 RES_PAGEDESC
, false, &pItem
))
374 const SwPageDesc
* pPgDesc
= static_cast<const SwFormatPageDesc
*>(pItem
)->GetPageDesc();
377 tmpSet
.reset(new SfxItemSet(*this));
379 SwPageDesc
* pDstPgDesc
= pDstDoc
->FindPageDesc(pPgDesc
->GetName());
382 pDstPgDesc
= pDstDoc
->MakePageDesc(pPgDesc
->GetName());
383 pDstDoc
->CopyPageDesc( *pPgDesc
, *pDstPgDesc
);
385 SwFormatPageDesc
aDesc( pDstPgDesc
);
386 aDesc
.SetNumOffset( static_cast<const SwFormatPageDesc
*>(pItem
)->GetNumOffset() );
387 tmpSet
->Put( aDesc
);
391 if( pSrcDoc
!= pDstDoc
&& SfxItemState::SET
== GetItemState( RES_ANCHOR
, false, &pItem
)
392 && static_cast< const SwFormatAnchor
* >( pItem
)->GetContentAnchor() != nullptr )
395 tmpSet
.reset( new SfxItemSet( *this ));
396 // Anchors at any node position cannot be copied to another document, because the SwPosition
397 // would still point to the old document. It needs to be fixed up explicitly.
398 tmpSet
->ClearItem( RES_ANCHOR
);
401 if (pSrcDoc
!= pDstDoc
&&
402 SfxItemState::SET
== GetItemState(RES_PARATR_LIST_AUTOFMT
, false, &pItem
))
404 SfxItemSet
const& rAutoStyle(*static_cast<SwFormatAutoFormat
const&>(*pItem
).GetStyleHandle());
405 std::shared_ptr
<SfxItemSet
> const pNewSet(
406 rAutoStyle
.SfxItemSet::Clone(true, &pDstDoc
->GetAttrPool()));
408 // fix up character style, it contains pointers to pSrcDoc
409 if (SfxItemState::SET
== pNewSet
->GetItemState(RES_TXTATR_CHARFMT
, false, &pItem
))
411 auto const* pChar(static_cast<SwFormatCharFormat
const*>(pItem
));
412 SwCharFormat
*const pCopy(pDstDoc
->CopyCharFormat(*pChar
->GetCharFormat()));
413 const_cast<SwFormatCharFormat
*>(pChar
)->SetCharFormat(pCopy
);
416 SwFormatAutoFormat
item(RES_PARATR_LIST_AUTOFMT
);
417 // TODO: for ODF export we'd need to add it to the autostyle pool
418 item
.SetStyleHandle(pNewSet
);
421 tmpSet
.reset(new SfxItemSet(*this));
431 if ( pNewListIdItem
!= nullptr )
433 tmpSet
->Put( *pNewListIdItem
);
435 pCNd
->SetAttr( *tmpSet
);
439 pFormat
->SetFormatAttr( *tmpSet
);
445 if ( pNewListIdItem
!= nullptr )
447 SfxItemSet
aTmpSet( *this );
448 aTmpSet
.Put( *pNewListIdItem
);
449 pCNd
->SetAttr( aTmpSet
);
453 pCNd
->SetAttr( *this );
458 pFormat
->SetFormatAttr( *this );
462 #if OSL_DEBUG_LEVEL > 0
464 OSL_FAIL("neither Format nor ContentNode - no Attributes copied");
468 /// check if ID is in range of attribute set IDs
469 bool IsInRange( const sal_uInt16
* pRange
, const sal_uInt16 nId
)
473 if( *pRange
<= nId
&& nId
<= *(pRange
+1) )
480 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */