/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 SwAttrSet::Clone( bool bItems, SfxItemPool *pToPool ) const { if ( pToPool && pToPool != GetPool() ) { SwAttrPool* pAttrPool = dynamic_cast< SwAttrPool* >(pToPool); std::unique_ptr 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( 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(pItem)->GetDefinedIn() != pModify ) { const_cast(static_cast(pItem))->ChgDefinedIn( pModify ); bSet = true; } if( SfxItemState::SET == GetItemState( RES_PARATR_DROP, false, &pItem ) && static_cast(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(static_cast(pItem))->GetCharFormat(); if( pCharFormat && GetPool() != pCharFormat->GetAttrSet().GetPool() ) { pCharFormat = GetDoc()->CopyCharFormat( *pCharFormat ); const_cast(static_cast(pItem))->SetCharFormat( pCharFormat ); } const_cast(static_cast(pItem))->ChgDefinedIn( pModify ); bSet = true; } if( SfxItemState::SET == GetItemState( RES_BOXATR_FORMULA, false, &pItem ) && static_cast(pItem)->GetDefinedIn() != pModify ) { const_cast(static_cast(pItem))->ChgDefinedIn( pModify ); bSet = true; } return bSet; } void SwAttrSet::CopyToModify( SwModify& rMod ) const { // copy attributes across multiple documents if needed SwContentNode* pCNd = dynamic_cast( &rMod ); SwFormat* pFormat = dynamic_cast( &rMod ); if( pCNd || pFormat ) { if( Count() ) { // #i92811# std::unique_ptr 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(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(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 // 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(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(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(*pItem).GetStyleHandle()); std::shared_ptr 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(pItem)); SwCharFormat *const pCopy(pDstDoc->CopyCharFormat(*pChar->GetCharFormat())); const_cast(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: */