diff options
Diffstat (limited to 'sw/source/core/attr/swatrset.cxx')
-rw-r--r-- | sw/source/core/attr/swatrset.cxx | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/sw/source/core/attr/swatrset.cxx b/sw/source/core/attr/swatrset.cxx new file mode 100644 index 000000000..aa6d9f1ad --- /dev/null +++ b/sw/source/core/attr/swatrset.cxx @@ -0,0 +1,481 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> + +#include <cellatr.hxx> +#include <charfmt.hxx> +#include <fchrfmt.hxx> +#include <doc.hxx> +#include <IDocumentListsAccess.hxx> +#include <editeng/editeng.hxx> +#include <fmtanchr.hxx> +#include <fmtpdsc.hxx> +#include <fmtautofmt.hxx> +#include <hintids.hxx> +#include <list.hxx> +#include <node.hxx> +#include <numrule.hxx> +#include <pagedesc.hxx> +#include <paratr.hxx> +#include <osl/diagnose.h> +#include <svl/whiter.hxx> + +#include <svx/svdpool.hxx> +#include <svx/sxenditm.hxx> +#include <svx/sdsxyitm.hxx> + +SwAttrPool::SwAttrPool( SwDoc* pD ) + : SfxItemPool( "SWG", + POOLATTR_BEGIN, POOLATTR_END-1, + aSlotTab, &aAttrTab ), + m_pDoc( pD ) +{ + // create secondary pools immediately + createAndAddSecondaryPools(); +} + +SwAttrPool::~SwAttrPool() +{ + // cleanup secondary pools first + removeAndDeleteSecondaryPools(); +} + +void SwAttrPool::createAndAddSecondaryPools() +{ + const SfxItemPool* pCheckAlreadySet = GetSecondaryPool(); + + if(pCheckAlreadySet) + { + OSL_ENSURE(false, "SwAttrPool already has a secondary pool (!)"); + return; + } + + // create SfxItemPool and EditEngine pool and add these in a chain. These + // belong us and will be removed/destroyed in removeAndDeleteSecondaryPools() used from + // the destructor + SfxItemPool *pSdrPool = new SdrItemPool(this); + + // #75371# change DefaultItems for the SdrEdgeObj distance items + // to TWIPS. + // 1/100th mm in twips + const long nDefEdgeDist = (500 * 72) / 127; + + pSdrPool->SetPoolDefaultItem(SdrEdgeNode1HorzDistItem(nDefEdgeDist)); + pSdrPool->SetPoolDefaultItem(SdrEdgeNode1VertDistItem(nDefEdgeDist)); + pSdrPool->SetPoolDefaultItem(SdrEdgeNode2HorzDistItem(nDefEdgeDist)); + pSdrPool->SetPoolDefaultItem(SdrEdgeNode2VertDistItem(nDefEdgeDist)); + + // #i33700# // Set shadow distance defaults as PoolDefaultItems + pSdrPool->SetPoolDefaultItem(makeSdrShadowXDistItem((300 * 72) / 127)); + pSdrPool->SetPoolDefaultItem(makeSdrShadowYDistItem((300 * 72) / 127)); + + SfxItemPool *pEEgPool = EditEngine::CreatePool(); + + pSdrPool->SetSecondaryPool(pEEgPool); + + if(!GetFrozenIdRanges()) + { + FreezeIdRanges(); + } + else + { + pSdrPool->FreezeIdRanges(); + } +} + +void SwAttrPool::removeAndDeleteSecondaryPools() +{ + SfxItemPool *pSdrPool = GetSecondaryPool(); + + if(!pSdrPool) + { + OSL_ENSURE(false, "SwAttrPool has no secondary pool, it's missing (!)"); + return; + } + + SfxItemPool *pEEgPool = pSdrPool->GetSecondaryPool(); + + if(!pEEgPool) + { + OSL_ENSURE(false, "i don't accept additional pools"); + return; + } + + // first delete the items, then break the linking + pSdrPool->Delete(); + + SetSecondaryPool(nullptr); + pSdrPool->SetSecondaryPool(nullptr); + + // final cleanup of secondary pool(s) + SfxItemPool::Free(pSdrPool); + SfxItemPool::Free(pEEgPool); +} + +SwAttrSet::SwAttrSet( SwAttrPool& rPool, sal_uInt16 nWh1, sal_uInt16 nWh2 ) + : SfxItemSet( rPool, {{nWh1, nWh2}} ), m_pOldSet( nullptr ), m_pNewSet( nullptr ) +{ +} + +SwAttrSet::SwAttrSet( SwAttrPool& rPool, const sal_uInt16* nWhichPairTable ) + : SfxItemSet( rPool, nWhichPairTable ), m_pOldSet( nullptr ), m_pNewSet( nullptr ) +{ +} + +SwAttrSet::SwAttrSet( const SwAttrSet& rSet ) + : SfxItemSet( rSet ), m_pOldSet( nullptr ), m_pNewSet( nullptr ) +{ +} + +std::unique_ptr<SfxItemSet> SwAttrSet::Clone( bool bItems, SfxItemPool *pToPool ) const +{ + if ( pToPool && pToPool != GetPool() ) + { + SwAttrPool* pAttrPool = dynamic_cast< SwAttrPool* >(pToPool); + std::unique_ptr<SfxItemSet> pTmpSet; + if ( !pAttrPool ) + pTmpSet = SfxItemSet::Clone( bItems, pToPool ); + else + { + pTmpSet.reset(new SwAttrSet( *pAttrPool, GetRanges() )); + if ( bItems ) + { + SfxWhichIter aIter(*pTmpSet); + sal_uInt16 nWhich = aIter.FirstWhich(); + while ( nWhich ) + { + const SfxPoolItem* pItem; + if ( SfxItemState::SET == GetItemState( nWhich, false, &pItem ) ) + pTmpSet->Put( *pItem ); + nWhich = aIter.NextWhich(); + } + } + } + return pTmpSet; + } + else + return std::unique_ptr<SfxItemSet>( + bItems + ? new SwAttrSet( *this ) + : new SwAttrSet( *GetPool(), GetRanges() )); +} + +bool SwAttrSet::Put_BC( const SfxPoolItem& rAttr, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + m_pNewSet = pNew; + m_pOldSet = pOld; + bool bRet = nullptr != SfxItemSet::Put( rAttr ); + m_pOldSet = m_pNewSet = nullptr; + return bRet; +} + +bool SwAttrSet::Put_BC( const SfxItemSet& rSet, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + m_pNewSet = pNew; + m_pOldSet = pOld; + bool bRet = SfxItemSet::Put( rSet ); + m_pOldSet = m_pNewSet = nullptr; + return bRet; +} + +sal_uInt16 SwAttrSet::ClearItem_BC( sal_uInt16 nWhich, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + m_pNewSet = pNew; + m_pOldSet = pOld; + sal_uInt16 nRet = SfxItemSet::ClearItem( nWhich ); + m_pOldSet = m_pNewSet = nullptr; + return nRet; +} + +sal_uInt16 SwAttrSet::ClearItem_BC( sal_uInt16 nWhich1, sal_uInt16 nWhich2, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + OSL_ENSURE( nWhich1 <= nWhich2, "no valid range" ); + m_pNewSet = pNew; + m_pOldSet = pOld; + sal_uInt16 nRet = 0; + for( ; nWhich1 <= nWhich2; ++nWhich1 ) + nRet = nRet + SfxItemSet::ClearItem( nWhich1 ); + m_pOldSet = m_pNewSet = nullptr; + return nRet; +} + +int SwAttrSet::Intersect_BC( const SfxItemSet& rSet, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + m_pNewSet = pNew; + m_pOldSet = pOld; + SfxItemSet::Intersect( rSet ); + m_pOldSet = m_pNewSet = nullptr; + return pNew ? pNew->Count() : ( pOld ? pOld->Count() : 0 ); +} + +/// Notification callback +void SwAttrSet::Changed( const SfxPoolItem& rOld, const SfxPoolItem& rNew ) +{ + if( m_pOldSet ) + m_pOldSet->PutChgd( rOld ); + if( m_pNewSet ) + m_pNewSet->PutChgd( rNew ); +} + +/** special treatment for some attributes + + Set the Modify pointer (old pDefinedIn) for the following attributes: + - SwFormatDropCaps + - SwFormatPageDesc + + (Is called at inserts into formats/nodes) +*/ +bool SwAttrSet::SetModifyAtAttr( const SwModify* pModify ) +{ + bool bSet = false; + + const SfxPoolItem* pItem; + if( SfxItemState::SET == GetItemState( RES_PAGEDESC, false, &pItem ) && + static_cast<const SwFormatPageDesc*>(pItem)->GetDefinedIn() != pModify ) + { + const_cast<SwFormatPageDesc*>(static_cast<const SwFormatPageDesc*>(pItem))->ChgDefinedIn( pModify ); + bSet = true; + } + + if( SfxItemState::SET == GetItemState( RES_PARATR_DROP, false, &pItem ) && + static_cast<const SwFormatDrop*>(pItem)->GetDefinedIn() != pModify ) + { + // If CharFormat is set and it is set in different attribute pools then + // the CharFormat has to be copied. + SwCharFormat* pCharFormat = const_cast<SwFormatDrop*>(static_cast<const SwFormatDrop*>(pItem))->GetCharFormat(); + if( pCharFormat && GetPool() != pCharFormat->GetAttrSet().GetPool() ) + { + pCharFormat = GetDoc()->CopyCharFormat( *pCharFormat ); + const_cast<SwFormatDrop*>(static_cast<const SwFormatDrop*>(pItem))->SetCharFormat( pCharFormat ); + } + const_cast<SwFormatDrop*>(static_cast<const SwFormatDrop*>(pItem))->ChgDefinedIn( pModify ); + bSet = true; + } + + if( SfxItemState::SET == GetItemState( RES_BOXATR_FORMULA, false, &pItem ) && + static_cast<const SwTableBoxFormula*>(pItem)->GetDefinedIn() != pModify ) + { + const_cast<SwTableBoxFormula*>(static_cast<const SwTableBoxFormula*>(pItem))->ChgDefinedIn( pModify ); + bSet = true; + } + + return bSet; +} + +void SwAttrSet::CopyToModify( SwModify& rMod ) const +{ + // copy attributes across multiple documents if needed + SwContentNode* pCNd = dynamic_cast<SwContentNode*>( &rMod ); + SwFormat* pFormat = dynamic_cast<SwFormat*>( &rMod ); + + if( pCNd || pFormat ) + { + if( Count() ) + { + // #i92811# + std::unique_ptr<SfxStringItem> pNewListIdItem; + + const SfxPoolItem* pItem; + const SwDoc *pSrcDoc = GetDoc(); + SwDoc *pDstDoc = pCNd ? pCNd->GetDoc() : pFormat->GetDoc(); + + // Does the NumRule has to be copied? + if( pSrcDoc != pDstDoc && + SfxItemState::SET == GetItemState( RES_PARATR_NUMRULE, false, &pItem ) ) + { + const OUString& rNm = static_cast<const SwNumRuleItem*>(pItem)->GetValue(); + if( !rNm.isEmpty() ) + { + SwNumRule* pDestRule = pDstDoc->FindNumRulePtr( rNm ); + if( pDestRule ) + pDestRule->SetInvalidRule( true ); + else + pDstDoc->MakeNumRule( rNm, pSrcDoc->FindNumRulePtr( rNm ) ); + } + } + + // copy list and if needed also the corresponding list style + // for text nodes + if ( pSrcDoc != pDstDoc && + pCNd && pCNd->IsTextNode() && + GetItemState( RES_PARATR_LIST_ID, false, &pItem ) == SfxItemState::SET ) + { + auto pStrItem = dynamic_cast<const SfxStringItem*>(pItem); + assert(pStrItem); + const OUString& sListId = pStrItem->GetValue(); + if ( !sListId.isEmpty() && + !pDstDoc->getIDocumentListsAccess().getListByName( sListId ) ) + { + const SwList* pList = pSrcDoc->getIDocumentListsAccess().getListByName( sListId ); + // copy list style, if needed + const OUString& sDefaultListStyleName = + pList->GetDefaultListStyleName(); + // #i92811# + const SwNumRule* pDstDocNumRule = + pDstDoc->FindNumRulePtr( sDefaultListStyleName ); + if ( !pDstDocNumRule ) + { + pDstDoc->MakeNumRule( sDefaultListStyleName, + pSrcDoc->FindNumRulePtr( sDefaultListStyleName ) ); + } + else + { + const SwNumRule* pSrcDocNumRule = + pSrcDoc->FindNumRulePtr( sDefaultListStyleName ); + // If list id of text node equals the list style's + // default list id in the source document, the same + // should be hold in the destination document. + // Thus, create new list id item. + if (pSrcDocNumRule && sListId == pSrcDocNumRule->GetDefaultListId()) + { + pNewListIdItem.reset(new SfxStringItem ( + RES_PARATR_LIST_ID, + pDstDocNumRule->GetDefaultListId() )); + } + } + // check again, if list exist, because <SwDoc::MakeNumRule(..)> + // could have also created it. + if ( pNewListIdItem == nullptr && + !pDstDoc->getIDocumentListsAccess().getListByName( sListId ) ) + { + // copy list + pDstDoc->getIDocumentListsAccess().createList( sListId, sDefaultListStyleName ); + } + } + } + + std::unique_ptr< SfxItemSet > tmpSet; + + const SwPageDesc* pPgDesc; + if( pSrcDoc != pDstDoc && SfxItemState::SET == GetItemState( + RES_PAGEDESC, false, &pItem )) + { + pPgDesc = static_cast<const SwFormatPageDesc*>(pItem)->GetPageDesc(); + if( pPgDesc ) + { + tmpSet.reset(new SfxItemSet(*this)); + + SwPageDesc* pDstPgDesc = pDstDoc->FindPageDesc(pPgDesc->GetName()); + if( !pDstPgDesc ) + { + pDstPgDesc = pDstDoc->MakePageDesc(pPgDesc->GetName()); + pDstDoc->CopyPageDesc( *pPgDesc, *pDstPgDesc ); + } + SwFormatPageDesc aDesc( pDstPgDesc ); + aDesc.SetNumOffset( static_cast<const SwFormatPageDesc*>(pItem)->GetNumOffset() ); + tmpSet->Put( aDesc ); + } + } + + if( pSrcDoc != pDstDoc && SfxItemState::SET == GetItemState( RES_ANCHOR, false, &pItem ) + && static_cast< const SwFormatAnchor* >( pItem )->GetContentAnchor() != nullptr ) + { + if( !tmpSet ) + tmpSet.reset( new SfxItemSet( *this )); + // Anchors at any node position cannot be copied to another document, because the SwPosition + // would still point to the old document. It needs to be fixed up explicitly. + tmpSet->ClearItem( RES_ANCHOR ); + } + + if (pSrcDoc != pDstDoc && + SfxItemState::SET == GetItemState(RES_PARATR_LIST_AUTOFMT, false, &pItem)) + { + SfxItemSet const& rAutoStyle(*static_cast<SwFormatAutoFormat const&>(*pItem).GetStyleHandle()); + std::shared_ptr<SfxItemSet> const pNewSet( + rAutoStyle.SfxItemSet::Clone(true, &pDstDoc->GetAttrPool())); + + // fix up character style, it contains pointers to pSrcDoc + if (SfxItemState::SET == pNewSet->GetItemState(RES_TXTATR_CHARFMT, false, &pItem)) + { + auto const* pChar(static_cast<SwFormatCharFormat const*>(pItem)); + SwCharFormat *const pCopy(pDstDoc->CopyCharFormat(*pChar->GetCharFormat())); + const_cast<SwFormatCharFormat*>(pChar)->SetCharFormat(pCopy); + } + + SwFormatAutoFormat item(RES_PARATR_LIST_AUTOFMT); + // TODO: for ODF export we'd need to add it to the autostyle pool + item.SetStyleHandle(pNewSet); + if (!tmpSet) + { + tmpSet.reset(new SfxItemSet(*this)); + } + tmpSet->Put(item); + } + + if( tmpSet ) + { + if( pCNd ) + { + // #i92811# + if ( pNewListIdItem != nullptr ) + { + tmpSet->Put( *pNewListIdItem ); + } + pCNd->SetAttr( *tmpSet ); + } + else + { + pFormat->SetFormatAttr( *tmpSet ); + } + } + else if( pCNd ) + { + // #i92811# + if ( pNewListIdItem != nullptr ) + { + SfxItemSet aTmpSet( *this ); + aTmpSet.Put( *pNewListIdItem ); + pCNd->SetAttr( aTmpSet ); + } + else + { + pCNd->SetAttr( *this ); + } + } + else + { + pFormat->SetFormatAttr( *this ); + } + } + } +#if OSL_DEBUG_LEVEL > 0 + else + OSL_FAIL("neither Format nor ContentNode - no Attributes copied"); +#endif +} + +/// check if ID is in range of attribute set IDs +bool IsInRange( const sal_uInt16* pRange, const sal_uInt16 nId ) +{ + while( *pRange ) + { + if( *pRange <= nId && nId <= *(pRange+1) ) + return true; + pRange += 2; + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |