/* -*- 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 <cmdid.h>
#include <doc.hxx>
#include <IDocumentListsAccess.hxx>
#include <editeng/colritem.hxx>
#include <editeng/brushitem.hxx>
#include <editeng/lineitem.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/editeng.hxx>
#include <fmtanchr.hxx>
#include <fmtpdsc.hxx>
#include <hintids.hxx>
#include <istyleaccess.hxx>
#include <list.hxx>
#include <node.hxx>
#include <numrule.hxx>
#include <pagedesc.hxx>
#include <paratr.hxx>
#include <svl/whiter.hxx>
#include <svx/xtable.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;
if( nullptr != ( pCharFormat = const_cast<SwFormatDrop*>(static_cast<const SwFormatDrop*>(pItem))->GetCharFormat() )
&& 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#
SfxStringItem* pNewListIdItem( nullptr );
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 )
{
const OUString& sListId =
dynamic_cast<const SfxStringItem*>(pItem)->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 = 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 ) &&
nullptr != ( pPgDesc = static_cast<const SwFormatPageDesc*>(pItem)->GetPageDesc()) )
{
if( !tmpSet )
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( 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 );
}
// #i92811#
delete pNewListIdItem;
pNewListIdItem = nullptr;
}
}
#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: */
↑ V614 The 'tmpSet' smart pointer is utilized immediately after being declared or reset. It is suspicious that no value was assigned to it.
↑ V773 Visibility scope of the 'pSdrPool' pointer was exited without releasing the memory. A memory leak is possible.
↑ V547 Expression '!tmpSet' is always true.
↑ V522 There might be dereferencing of a potential null pointer.
↑ V522 There might be dereferencing of a potential null pointer 'pFormat'.