diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sw/source/core/attr | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/attr')
-rw-r--r-- | sw/source/core/attr/calbck.cxx | 381 | ||||
-rw-r--r-- | sw/source/core/attr/cellatr.cxx | 226 | ||||
-rw-r--r-- | sw/source/core/attr/fmtfollowtextflow.cxx | 30 | ||||
-rw-r--r-- | sw/source/core/attr/fmtwrapinfluenceonobjpos.cxx | 174 | ||||
-rw-r--r-- | sw/source/core/attr/format.cxx | 803 | ||||
-rw-r--r-- | sw/source/core/attr/hints.cxx | 270 | ||||
-rw-r--r-- | sw/source/core/attr/swatrset.cxx | 481 |
7 files changed, 2365 insertions, 0 deletions
diff --git a/sw/source/core/attr/calbck.cxx b/sw/source/core/attr/calbck.cxx new file mode 100644 index 000000000..cef9b02b0 --- /dev/null +++ b/sw/source/core/attr/calbck.cxx @@ -0,0 +1,381 @@ +/* -*- 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 <frame.hxx> +#include <hintids.hxx> +#include <hints.hxx> +#include <swcache.hxx> +#include <swfntcch.hxx> +#include <tools/debug.hxx> +#include <sal/log.hxx> +#include <algorithm> + +namespace sw +{ + bool ListenerEntry::GetInfo(SfxPoolItem& rInfo) const + { return m_pToTell == nullptr || m_pToTell->GetInfo( rInfo ); } + void ListenerEntry::Modify(const SfxPoolItem *const pOldValue, + const SfxPoolItem *const pNewValue) + { + SwClientNotify(*GetRegisteredIn(), sw::LegacyModifyHint(pOldValue, pNewValue)); + } + void ListenerEntry::SwClientNotify(const SwModify& rModify, const SfxHint& rHint) + { + if (auto pLegacyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint)) + { + if (pLegacyHint->m_pNew && pLegacyHint->m_pNew->Which() == RES_OBJECTDYING) + { + auto pModifyChanged = CheckRegistration(pLegacyHint->m_pOld); + if (pModifyChanged) + m_pToTell->SwClientNotify(rModify, *pModifyChanged); + } + else if (m_pToTell) + m_pToTell->SwClientNotifyCall(rModify, rHint); + } + else if (m_pToTell) + m_pToTell->SwClientNotifyCall(rModify, rHint); + } +} + +sw::LegacyModifyHint::~LegacyModifyHint() {} +sw::ModifyChangedHint::~ModifyChangedHint() {} + +SwClient::SwClient(SwClient&& o) noexcept + : m_pRegisteredIn(nullptr) +{ + if(o.m_pRegisteredIn) + { + o.m_pRegisteredIn->Add(this); + o.EndListeningAll(); + } +} + +SwClient::~SwClient() +{ + if(GetRegisteredIn()) + DBG_TESTSOLARMUTEX(); + OSL_ENSURE( !m_pRegisteredIn || m_pRegisteredIn->HasWriterListeners(), "SwModify still known, but Client already disconnected!" ); + if( m_pRegisteredIn && m_pRegisteredIn->HasWriterListeners() ) + m_pRegisteredIn->Remove( this ); +} + +std::unique_ptr<sw::ModifyChangedHint> SwClient::CheckRegistration( const SfxPoolItem* pOld ) +{ + DBG_TESTSOLARMUTEX(); + // this method only handles notification about dying SwModify objects + if( !pOld || pOld->Which() != RES_OBJECTDYING ) + return nullptr; + + assert(dynamic_cast<const SwPtrMsgPoolItem*>(pOld)); + const SwPtrMsgPoolItem* pDead = static_cast<const SwPtrMsgPoolItem*>(pOld); + if(pDead->pObject != m_pRegisteredIn) + { + // we should only care received death notes from objects we are following + return nullptr; + } + // I've got a notification from the object I know + SwModify* pAbove = m_pRegisteredIn->GetRegisteredIn(); + if(pAbove) + { + // if the dying object itself was listening at an SwModify, I take over + // adding myself to pAbove will automatically remove me from my current pRegisteredIn + pAbove->Add(this); + } + else + { + // destroy connection + EndListeningAll(); + } + return std::unique_ptr<sw::ModifyChangedHint>(new sw::ModifyChangedHint(pAbove)); +} + +void SwClient::SwClientNotify(const SwModify&, const SfxHint& rHint) +{ + if (auto pLegacyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint)) + { + Modify(pLegacyHint->m_pOld, pLegacyHint->m_pNew); + } +}; + +void SwClient::StartListeningToSameModifyAs(const SwClient& other) +{ + if(other.m_pRegisteredIn) + other.m_pRegisteredIn->Add(this); + else + EndListeningAll(); +} + +void SwClient::EndListeningAll() +{ + if(m_pRegisteredIn) + m_pRegisteredIn->Remove(this); +} + +void SwClient::Modify(SfxPoolItem const*const pOldValue, SfxPoolItem const*const /*pNewValue*/) +{ + CheckRegistration( pOldValue ); +} + +void SwModify::SetInDocDTOR() +{ + // If the document gets destroyed anyway, just tell clients to + // forget me so that they don't try to get removed from my list + // later when they also get destroyed + SwIterator<SwClient,SwModify> aIter(*this); + for(SwClient* pClient = aIter.First(); pClient; pClient = aIter.Next()) + pClient->m_pRegisteredIn = nullptr; + m_pWriterListeners = nullptr; +} + +SwModify::~SwModify() +{ + DBG_TESTSOLARMUTEX(); + OSL_ENSURE( !IsModifyLocked(), "Modify destroyed but locked." ); + + if ( IsInCache() ) + SwFrame::GetCache().Delete( this ); + + if ( IsInSwFntCache() ) + pSwFontCache->Delete( this ); + + // notify all clients that they shall remove themselves + SwPtrMsgPoolItem aDyObject( RES_OBJECTDYING, this ); + NotifyClients( &aDyObject, &aDyObject ); + + // remove all clients that have not done themselves + // mba: possibly a hotfix for forgotten base class calls?! + while( m_pWriterListeners ) + static_cast<SwClient*>(m_pWriterListeners)->CheckRegistration( &aDyObject ); +} + +void SwModify::NotifyClients( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue ) +{ + DBG_TESTSOLARMUTEX(); + if ( IsInCache() || IsInSwFntCache() ) + { + const sal_uInt16 nWhich = pOldValue ? pOldValue->Which() : + pNewValue ? pNewValue->Which() : 0; + CheckCaching( nWhich ); + } + + if ( !m_pWriterListeners || IsModifyLocked() ) + return; + + LockModify(); + + // mba: WTF?! + if( !pOldValue ) + { + m_bLockClientList = true; + } + else + { + switch( pOldValue->Which() ) + { + case RES_OBJECTDYING: + case RES_REMOVE_UNO_OBJECT: + m_bLockClientList = static_cast<const SwPtrMsgPoolItem*>(pOldValue)->pObject != this; + break; + + default: + m_bLockClientList = true; + } + } + + ModifyBroadcast( pOldValue, pNewValue ); + m_bLockClientList = false; + UnlockModify(); +} + +bool SwModify::GetInfo( SfxPoolItem& rInfo ) const +{ + if(!m_pWriterListeners) + return true; + SwIterator<SwClient,SwModify> aIter(*this); + for(SwClient* pClient = aIter.First(); pClient; pClient = aIter.Next()) + if(!pClient->GetInfo( rInfo )) + return false; + return true; +} + +void SwModify::Add( SwClient* pDepend ) +{ + DBG_TESTSOLARMUTEX(); + OSL_ENSURE( !m_bLockClientList, "Client inserted while in Modify" ); + + if(pDepend->m_pRegisteredIn != this ) + { +#if OSL_DEBUG_LEVEL > 0 + if(sw::ClientIteratorBase::s_pClientIters) + { + for(auto& rIter : sw::ClientIteratorBase::s_pClientIters->GetRingContainer()) + { + SAL_WARN_IF(&rIter.m_rRoot == m_pWriterListeners, "sw.core", "a " << typeid(*pDepend).name() << " client added as listener to a " << typeid(*this).name() << " during client iteration."); + } + } +#endif + // deregister new client in case it is already registered elsewhere + if( pDepend->m_pRegisteredIn != nullptr ) + pDepend->m_pRegisteredIn->Remove( pDepend ); + + if( !m_pWriterListeners ) + { + // first client added + m_pWriterListeners = pDepend; + m_pWriterListeners->m_pLeft = nullptr; + m_pWriterListeners->m_pRight = nullptr; + } + else + { + // append client + pDepend->m_pRight = m_pWriterListeners->m_pRight; + m_pWriterListeners->m_pRight = pDepend; + pDepend->m_pLeft = m_pWriterListeners; + if( pDepend->m_pRight ) + pDepend->m_pRight->m_pLeft = pDepend; + } + + // connect client to me + pDepend->m_pRegisteredIn = this; + } +} + +SwClient* SwModify::Remove( SwClient* pDepend ) +{ + DBG_TESTSOLARMUTEX(); + assert(pDepend->m_pRegisteredIn == this); + + // SwClient is my listener + // remove it from my list + ::sw::WriterListener* pR = pDepend->m_pRight; + ::sw::WriterListener* pL = pDepend->m_pLeft; + if( m_pWriterListeners == pDepend ) + m_pWriterListeners = pL ? pL : pR; + + if( pL ) + pL->m_pRight = pR; + if( pR ) + pR->m_pLeft = pL; + + // update ClientIterators + if(sw::ClientIteratorBase::s_pClientIters) + { + for(auto& rIter : sw::ClientIteratorBase::s_pClientIters->GetRingContainer()) + { + if (&rIter.m_rRoot == this && + (rIter.m_pCurrent == pDepend || rIter.m_pPosition == pDepend)) + { + // if object being removed is the current or next object in an + // iterator, advance this iterator + rIter.m_pPosition = pR; + } + } + } + pDepend->m_pLeft = nullptr; + pDepend->m_pRight = nullptr; + pDepend->m_pRegisteredIn = nullptr; + return pDepend; +} + +void SwModify::CheckCaching( const sal_uInt16 nWhich ) +{ + if( isCHRATR( nWhich ) ) + { + SetInSwFntCache( false ); + } + else + { + switch( nWhich ) + { + case RES_OBJECTDYING: + case RES_FMT_CHG: + case RES_ATTRSET_CHG: + SetInSwFntCache( false ); + [[fallthrough]]; + case RES_UL_SPACE: + case RES_LR_SPACE: + case RES_BOX: + case RES_SHADOW: + case RES_FRM_SIZE: + case RES_KEEP: + case RES_BREAK: + if( IsInCache() ) + { + SwFrame::GetCache().Delete( this ); + SetInCache( false ); + } + break; + } + } +} + +sw::WriterMultiListener::WriterMultiListener(SwClient& rToTell) + : m_rToTell(rToTell) +{} + +sw::WriterMultiListener::~WriterMultiListener() +{} + +void sw::WriterMultiListener::StartListening(SwModify* pDepend) +{ + EndListening(nullptr); + m_vDepends.emplace_back(ListenerEntry(&m_rToTell, pDepend)); +} + + +bool sw::WriterMultiListener::IsListeningTo(const SwModify* const pBroadcaster) const +{ + return std::any_of(m_vDepends.begin(), m_vDepends.end(), + [&pBroadcaster](const ListenerEntry& aListener) + { + return aListener.GetRegisteredIn() == pBroadcaster; + }); +} + +void sw::WriterMultiListener::EndListening(SwModify* pBroadcaster) +{ + m_vDepends.erase( + std::remove_if( m_vDepends.begin(), m_vDepends.end(), + [&pBroadcaster](const ListenerEntry& aListener) + { + return aListener.GetRegisteredIn() == nullptr || aListener.GetRegisteredIn() == pBroadcaster; + }), + m_vDepends.end()); +} + +void sw::WriterMultiListener::EndListeningAll() +{ + m_vDepends.clear(); +} + +sw::ClientIteratorBase* sw::ClientIteratorBase::s_pClientIters = nullptr; + +void SwModify::CallSwClientNotify( const SfxHint& rHint ) const +{ + SwIterator<SwClient,SwModify> aIter(*this); + for(SwClient* pClient = aIter.First(); pClient; pClient = aIter.Next()) + pClient->SwClientNotify( *this, rHint ); +} + +void sw::BroadcastingModify::CallSwClientNotify(const SfxHint& rHint) const +{ + SwModify::CallSwClientNotify(rHint); + const_cast<BroadcastingModify*>(this)->GetNotifier().Broadcast(rHint); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/attr/cellatr.cxx b/sw/source/core/attr/cellatr.cxx new file mode 100644 index 000000000..a0a459ed8 --- /dev/null +++ b/sw/source/core/attr/cellatr.cxx @@ -0,0 +1,226 @@ +/* -*- 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 <calc.hxx> +#include <cellatr.hxx> +#include <doc.hxx> +#include <float.h> +#include <hintids.hxx> +#include <hints.hxx> +#include <node.hxx> +#include <rolbck.hxx> +#include <rtl/math.hxx> +#include <rtl/ustring.hxx> +#include <calbck.hxx> +#include <swtable.hxx> + +// The % SV_COUNTRY_LANGUAGE_OFFSET result checks if nFormat is a mere built-in +// @ Text format of *any* locale and if so uses the default text format. Text +// is text, the locale doesn't matter for Writer's number formatting purposes. +// The advantage is that this is the pool's default item value and some places +// benefit from this special treatment in that they don't have to handle/store +// attribute specifics, especially when writing a document. +SwTableBoxNumFormat::SwTableBoxNumFormat( sal_uInt32 nFormat ) + : SfxUInt32Item( RES_BOXATR_FORMAT, + (((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == getSwDefaultTextFormat()) ? + getSwDefaultTextFormat() : nFormat)) +{ +} + +bool SwTableBoxNumFormat::operator==( const SfxPoolItem& rAttr ) const +{ + assert(SfxPoolItem::operator==(rAttr)); + return GetValue() == static_cast<const SwTableBoxNumFormat&>(rAttr).GetValue(); +} + +SwTableBoxNumFormat* SwTableBoxNumFormat::Clone( SfxItemPool* ) const +{ + return new SwTableBoxNumFormat( GetValue() ); +} + +SwTableBoxFormula::SwTableBoxFormula( const OUString& rFormula ) + : SfxPoolItem( RES_BOXATR_FORMULA ), + SwTableFormula( rFormula ), + m_pDefinedIn( nullptr ) +{ +} + +bool SwTableBoxFormula::operator==( const SfxPoolItem& rAttr ) const +{ + assert(SfxPoolItem::operator==(rAttr)); + return GetFormula() == static_cast<const SwTableBoxFormula&>(rAttr).GetFormula() && + m_pDefinedIn == static_cast<const SwTableBoxFormula&>(rAttr).m_pDefinedIn; +} + +SwTableBoxFormula* SwTableBoxFormula::Clone( SfxItemPool* ) const +{ + // switch to external rendering + SwTableBoxFormula* pNew = new SwTableBoxFormula( GetFormula() ); + pNew->SwTableFormula::operator=( *this ); + return pNew; +} + +/** Get node type of the node containing this formula + + E.g. TextField -> TextNode, or + BoxAttribute -> BoxStartNode + + Caution: Must override when inheriting. +*/ +const SwNode* SwTableBoxFormula::GetNodeOfFormula() const +{ + const SwNode* pRet = nullptr; + if( m_pDefinedIn ) + { + SwTableBox* pBox = SwIterator<SwTableBox,SwModify>( *m_pDefinedIn ).First(); + if( pBox ) + pRet = pBox->GetSttNd(); + } + return pRet; +} + +SwTableBox* SwTableBoxFormula::GetTableBox() +{ + SwTableBox* pBox = nullptr; + if( m_pDefinedIn ) + pBox = SwIterator<SwTableBox,SwModify>( *m_pDefinedIn ).First(); + return pBox; +} + +void SwTableBoxFormula::ChangeState( const SfxPoolItem* pItem ) +{ + if( !m_pDefinedIn ) + return ; + + SwTableFormulaUpdate* pUpdateField; + if( !pItem || RES_TABLEFML_UPDATE != pItem->Which() ) + { + // reset value flag + ChgValid( false ); + return ; + } + + pUpdateField = const_cast<SwTableFormulaUpdate*>(static_cast<const SwTableFormulaUpdate*>(pItem)); + + // detect table that contains this attribute + const SwTableNode* pTableNd; + const SwNode* pNd = GetNodeOfFormula(); + if (!pNd || &pNd->GetNodes() != &pNd->GetDoc()->GetNodes()) + return; + pTableNd = pNd->FindTableNode(); + if( pTableNd != nullptr ) + { + switch( pUpdateField->m_eFlags ) + { + case TBL_CALC: + // reset value flag + ChgValid( false ); + break; + case TBL_BOXNAME: + if( &pTableNd->GetTable() == pUpdateField->m_pTable ) + // use external rendering + PtrToBoxNm( pUpdateField->m_pTable ); + break; + case TBL_BOXPTR: + // internal rendering + BoxNmToPtr( &pTableNd->GetTable() ); + break; + case TBL_RELBOXNAME: + if( &pTableNd->GetTable() == pUpdateField->m_pTable ) + // relative rendering + ToRelBoxNm( pUpdateField->m_pTable ); + break; + + case TBL_SPLITTBL: + if( &pTableNd->GetTable() == pUpdateField->m_pTable ) + { + sal_uInt16 nLnPos = SwTableFormula::GetLnPosInTable( + pTableNd->GetTable(), GetTableBox() ); + pUpdateField->m_bBehindSplitLine = USHRT_MAX != nLnPos && + pUpdateField->m_nSplitLine <= nLnPos; + } + else + pUpdateField->m_bBehindSplitLine = false; + [[fallthrough]]; + case TBL_MERGETBL: + if( pUpdateField->m_pHistory ) + { + // for a history record the unchanged formula is needed + SwTableBoxFormula aCopy( *this ); + pUpdateField->m_bModified = false; + ToSplitMergeBoxNm( *pUpdateField ); + + if( pUpdateField->m_bModified ) + { + // external rendering + aCopy.PtrToBoxNm( &pTableNd->GetTable() ); + pUpdateField->m_pHistory->Add( + &aCopy, + &aCopy, + pNd->FindTableBoxStartNode()->GetIndex()); + } + } + else + ToSplitMergeBoxNm( *pUpdateField ); + break; + } + } +} + +void SwTableBoxFormula::Calc( SwTableCalcPara& rCalcPara, double& rValue ) +{ + if( !rCalcPara.m_rCalc.IsCalcError() ) + { + // create pointers from box names + BoxNmToPtr( rCalcPara.m_pTable ); + const OUString sFormula( MakeFormula( rCalcPara )); + if( !rCalcPara.m_rCalc.IsCalcError() ) + rValue = rCalcPara.m_rCalc.Calculate( sFormula ).GetDouble(); + else + rValue = DBL_MAX; + ChgValid( !rCalcPara.IsStackOverflow() ); // value is now valid again + } +} + +SwTableBoxValue::SwTableBoxValue() + : SfxPoolItem( RES_BOXATR_VALUE ), m_nValue( 0 ) +{ +} + +SwTableBoxValue::SwTableBoxValue( const double nVal ) + : SfxPoolItem( RES_BOXATR_VALUE ), m_nValue( nVal ) +{ +} + +bool SwTableBoxValue::operator==( const SfxPoolItem& rAttr ) const +{ + assert(SfxPoolItem::operator==(rAttr)); + SwTableBoxValue const& rOther( static_cast<SwTableBoxValue const&>(rAttr) ); + // items with NaN should be equal to enable pooling + return std::isnan( m_nValue ) + ? std::isnan( rOther.m_nValue ) + : ( m_nValue == rOther.m_nValue ); +} + +SwTableBoxValue* SwTableBoxValue::Clone( SfxItemPool* ) const +{ + return new SwTableBoxValue( m_nValue ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/attr/fmtfollowtextflow.cxx b/sw/source/core/attr/fmtfollowtextflow.cxx new file mode 100644 index 000000000..8b04869af --- /dev/null +++ b/sw/source/core/attr/fmtfollowtextflow.cxx @@ -0,0 +1,30 @@ +/* -*- 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 <fmtfollowtextflow.hxx> +#include <unomid.h> + +#include <sal/log.hxx> + +SwFormatFollowTextFlow* SwFormatFollowTextFlow::Clone( SfxItemPool * ) const +{ + return new SwFormatFollowTextFlow(*this); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/attr/fmtwrapinfluenceonobjpos.cxx b/sw/source/core/attr/fmtwrapinfluenceonobjpos.cxx new file mode 100644 index 000000000..21ceec2f0 --- /dev/null +++ b/sw/source/core/attr/fmtwrapinfluenceonobjpos.cxx @@ -0,0 +1,174 @@ +/* -*- 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 <fmtwrapinfluenceonobjpos.hxx> +#include <unomid.h> +#include <osl/diagnose.h> +#include <libxml/xmlwriter.h> +#include <sal/log.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +SwFormatWrapInfluenceOnObjPos::SwFormatWrapInfluenceOnObjPos( sal_Int16 _nWrapInfluenceOnPosition ) + : SfxPoolItem( RES_WRAP_INFLUENCE_ON_OBJPOS ), + mnWrapInfluenceOnPosition( _nWrapInfluenceOnPosition ) +{ +} + +SwFormatWrapInfluenceOnObjPos::~SwFormatWrapInfluenceOnObjPos() +{ +} + +bool SwFormatWrapInfluenceOnObjPos::operator==( const SfxPoolItem& rAttr ) const +{ + assert(SfxPoolItem::operator==(rAttr)); + const SwFormatWrapInfluenceOnObjPos& rAttribute + = static_cast<const SwFormatWrapInfluenceOnObjPos&>(rAttr); + return (mnWrapInfluenceOnPosition == rAttribute.GetWrapInfluenceOnObjPos() + && mbAllowOverlap == rAttribute.mbAllowOverlap + && mnOverlapVertOffset == rAttribute.mnOverlapVertOffset); +} + +SwFormatWrapInfluenceOnObjPos* SwFormatWrapInfluenceOnObjPos::Clone( SfxItemPool * ) const +{ + return new SwFormatWrapInfluenceOnObjPos(*this); +} + +bool SwFormatWrapInfluenceOnObjPos::QueryValue( Any& rVal, sal_uInt8 nMemberId ) const +{ + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + if( nMemberId == MID_WRAP_INFLUENCE ) + { + rVal <<= GetWrapInfluenceOnObjPos(); + } + else if( nMemberId == MID_ALLOW_OVERLAP ) + { + rVal <<= GetAllowOverlap(); + } + else + { + OSL_FAIL( "<SwFormatWrapInfluenceOnObjPos::QueryValue()> - unknown MemberId" ); + bRet = false; + } + return bRet; +} + +bool SwFormatWrapInfluenceOnObjPos::PutValue( const Any& rVal, sal_uInt8 nMemberId ) +{ + nMemberId &= ~CONVERT_TWIPS; + bool bRet = false; + + if( nMemberId == MID_WRAP_INFLUENCE ) + { + sal_Int16 nNewWrapInfluence = 0; + rVal >>= nNewWrapInfluence; + // #i35017# - constant names have changed and <ITERATIVE> has been added + if ( nNewWrapInfluence == text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE || + nNewWrapInfluence == text::WrapInfluenceOnPosition::ONCE_CONCURRENT || + nNewWrapInfluence == text::WrapInfluenceOnPosition::ITERATIVE ) + { + SetWrapInfluenceOnObjPos( nNewWrapInfluence ); + bRet = true; + } + else + { + OSL_FAIL( "<SwFormatWrapInfluenceOnObjPos::PutValue(..)> - invalid attribute value" ); + } + } + else if( nMemberId == MID_ALLOW_OVERLAP ) + { + bool bAllowOverlap = true; + if (rVal >>= bAllowOverlap) + { + SetAllowOverlap(bAllowOverlap); + bRet = true; + } + else + { + SAL_WARN("sw.core", "SwFormatWrapInfluenceOnObjPos::PutValue: invalid AllowOverlap type"); + } + } + else + { + OSL_FAIL( "<SwFormatWrapInfluenceOnObjPos::PutValue(..)> - unknown MemberId" ); + } + return bRet; +} + +void SwFormatWrapInfluenceOnObjPos::SetWrapInfluenceOnObjPos( sal_Int16 _nWrapInfluenceOnPosition ) +{ + // #i35017# - constant names have changed and consider new value <ITERATIVE> + if ( _nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE || + _nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ONCE_CONCURRENT || + _nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ITERATIVE ) + { + mnWrapInfluenceOnPosition = _nWrapInfluenceOnPosition; + } + else + { + OSL_FAIL( "<SwFormatWrapInfluenceOnObjPos::SetWrapInfluenceOnObjPos(..)> - invalid attribute value" ); + } +} + +// #i35017# - add parameter <_bIterativeAsOnceConcurrent> to control, if +// value <ITERATIVE> has to be treated as <ONCE_CONCURRENT> +sal_Int16 SwFormatWrapInfluenceOnObjPos::GetWrapInfluenceOnObjPos( + const bool _bIterativeAsOnceConcurrent ) const +{ + sal_Int16 nWrapInfluenceOnPosition( mnWrapInfluenceOnPosition ); + + if ( _bIterativeAsOnceConcurrent && + nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ITERATIVE ) + { + nWrapInfluenceOnPosition = text::WrapInfluenceOnPosition::ONCE_CONCURRENT; + } + + return nWrapInfluenceOnPosition; +} + +void SwFormatWrapInfluenceOnObjPos::SetAllowOverlap(bool bAllowOverlap) +{ + mbAllowOverlap = bAllowOverlap; +} + +bool SwFormatWrapInfluenceOnObjPos::GetAllowOverlap() const +{ + return mbAllowOverlap; +} + +void SwFormatWrapInfluenceOnObjPos::SetOverlapVertOffset(SwTwips nOverlapVertOffset) +{ + mnOverlapVertOffset = nOverlapVertOffset; +} + +SwTwips SwFormatWrapInfluenceOnObjPos::GetOverlapVertOffset() const { return mnOverlapVertOffset; } + +void SwFormatWrapInfluenceOnObjPos::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatWrapInfluenceOnObjPos")); + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nWrapInfluenceOnPosition"), BAD_CAST(OString::number(mnWrapInfluenceOnPosition).getStr())); + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("mbAllowOverlap"), BAD_CAST(OString::boolean(mbAllowOverlap).getStr())); + xmlTextWriterEndElement(pWriter); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/attr/format.cxx b/sw/source/core/attr/format.cxx new file mode 100644 index 000000000..a69dbf125 --- /dev/null +++ b/sw/source/core/attr/format.cxx @@ -0,0 +1,803 @@ +/* -*- 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 <doc.hxx> +#include <DocumentSettingManager.hxx> //For SwFmt::getIDocumentSettingAccess() +#include <IDocumentTimerAccess.hxx> +#include <fmtcolfunc.hxx> +#include <frame.hxx> +#include <format.hxx> +#include <hintids.hxx> +#include <hints.hxx> +#include <swcache.hxx> +#include <frmatr.hxx> +#include <svl/grabbagitem.hxx> +#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx> +#include <svx/unobrushitemhelper.hxx> +#include <svx/xdef.hxx> +#include <sal/log.hxx> + +using namespace com::sun::star; + + +SwFormat::SwFormat( SwAttrPool& rPool, const char* pFormatNm, + const sal_uInt16* pWhichRanges, SwFormat *pDrvdFrame, + sal_uInt16 nFormatWhich ) : + m_aFormatName( OUString::createFromAscii(pFormatNm) ), + m_aSet( rPool, pWhichRanges ), + m_nWhichId( nFormatWhich ), + m_nPoolFormatId( USHRT_MAX ), + m_nPoolHelpId( USHRT_MAX ), + m_nPoolHlpFileId( UCHAR_MAX ) +{ + m_bAutoUpdateFormat = false; // LAYER_IMPL + m_bAutoFormat = true; + m_bFormatInDTOR = m_bHidden = false; + + if( pDrvdFrame ) + { + pDrvdFrame->Add(this); + m_aSet.SetParent( &pDrvdFrame->m_aSet ); + } +} + +SwFormat::SwFormat( SwAttrPool& rPool, const OUString& rFormatNm, + const sal_uInt16* pWhichRanges, SwFormat* pDrvdFrame, + sal_uInt16 nFormatWhich ) : + m_aFormatName( rFormatNm ), + m_aSet( rPool, pWhichRanges ), + m_nWhichId( nFormatWhich ), + m_nPoolFormatId( USHRT_MAX ), + m_nPoolHelpId( USHRT_MAX ), + m_nPoolHlpFileId( UCHAR_MAX ) +{ + m_bAutoUpdateFormat = false; // LAYER_IMPL + m_bAutoFormat = true; + m_bFormatInDTOR = m_bHidden = false; + + if( pDrvdFrame ) + { + pDrvdFrame->Add(this); + m_aSet.SetParent( &pDrvdFrame->m_aSet ); + } +} + +SwFormat::SwFormat( const SwFormat& rFormat ) : + m_aFormatName( rFormat.m_aFormatName ), + m_aSet( rFormat.m_aSet ), + m_nWhichId( rFormat.m_nWhichId ), + m_nPoolFormatId( rFormat.GetPoolFormatId() ), + m_nPoolHelpId( rFormat.GetPoolHelpId() ), + m_nPoolHlpFileId( rFormat.GetPoolHlpFileId() ) +{ + m_bFormatInDTOR = false; // LAYER_IMPL + m_bAutoFormat = rFormat.m_bAutoFormat; + m_bHidden = rFormat.m_bHidden; + m_bAutoUpdateFormat = rFormat.m_bAutoUpdateFormat; + + if( auto pDerived = rFormat.DerivedFrom() ) + { + pDerived->Add(this); + m_aSet.SetParent( &pDerived->m_aSet ); + } + // a few special treatments for attributes + m_aSet.SetModifyAtAttr( this ); +} + +SwFormat &SwFormat::operator=(const SwFormat& rFormat) +{ + if(this == &rFormat) + return *this; + + m_nWhichId = rFormat.m_nWhichId; + m_nPoolFormatId = rFormat.GetPoolFormatId(); + m_nPoolHelpId = rFormat.GetPoolHelpId(); + m_nPoolHlpFileId = rFormat.GetPoolHlpFileId(); + + if ( IsInCache() ) + { + SwFrame::GetCache().Delete( this ); + SetInCache( false ); + } + SetInSwFntCache( false ); + + // copy only array with attributes delta + SwAttrSet aOld( *m_aSet.GetPool(), m_aSet.GetRanges() ), + aNew( *m_aSet.GetPool(), m_aSet.GetRanges() ); + m_aSet.Intersect_BC( rFormat.m_aSet, &aOld, &aNew ); + (void)m_aSet.Put_BC( rFormat.m_aSet, &aOld, &aNew ); + + // a few special treatments for attributes + m_aSet.SetModifyAtAttr( this ); + + // create PoolItem attribute for Modify + if( aOld.Count() ) + { + SwAttrSetChg aChgOld( m_aSet, aOld ); + SwAttrSetChg aChgNew( m_aSet, aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // send all modified ones + } + + if(GetRegisteredIn() != rFormat.GetRegisteredIn()) + { + StartListeningToSameModifyAs(rFormat); + m_aSet.SetParent( GetRegisteredIn() + ? &rFormat.m_aSet + : nullptr); + } + + m_bAutoFormat = rFormat.m_bAutoFormat; + m_bHidden = rFormat.m_bHidden; + m_bAutoUpdateFormat = rFormat.m_bAutoUpdateFormat; + return *this; +} + +void SwFormat::SetName( const OUString& rNewName, bool bBroadcast ) +{ + OSL_ENSURE( !IsDefault(), "SetName: Defaultformat" ); + if( bBroadcast ) + { + SwStringMsgPoolItem aOld( RES_NAME_CHANGED, m_aFormatName ); + SwStringMsgPoolItem aNew( RES_NAME_CHANGED, rNewName ); + m_aFormatName = rNewName; + ModifyNotification( &aOld, &aNew ); + } + else + { + m_aFormatName = rNewName; + } +} + +/** Copy attributes + + This function is called in every Copy-Ctor for copying the attributes. + The latter can be only copied as soon as the derived class exists since + for setting them the Which() function is called and that has the default + value of 0 in the base class and is then overridden by the derived class. + + If we copy over multiple documents then the new document has to be provided + in which <this> is defined. Currently this is important for DropCaps + because that contains data that needs to be copied deeply. +*/ +void SwFormat::CopyAttrs( const SwFormat& rFormat ) +{ + // copy only array with attributes delta + if ( IsInCache() ) + { + SwFrame::GetCache().Delete( this ); + SetInCache( false ); + } + SetInSwFntCache( false ); + + // special treatments for some attributes + SwAttrSet* pChgSet = const_cast<SwAttrSet*>(&rFormat.m_aSet); + + // copy only array with attributes delta + if( pChgSet->GetPool() != m_aSet.GetPool() ) + pChgSet->CopyToModify( *this ); + else + { + SwAttrSet aOld( *m_aSet.GetPool(), m_aSet.GetRanges() ), + aNew( *m_aSet.GetPool(), m_aSet.GetRanges() ); + + if ( m_aSet.Put_BC( *pChgSet, &aOld, &aNew ) ) + { + // a few special treatments for attributes + m_aSet.SetModifyAtAttr( this ); + + SwAttrSetChg aChgOld( m_aSet, aOld ); + SwAttrSetChg aChgNew( m_aSet, aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // send all modified ones + } + } + + if( pChgSet != &rFormat.m_aSet ) // was a Set created? + delete pChgSet; +} + +SwFormat::~SwFormat() +{ + // This happens at an ObjectDying message. Thus put all dependent + // ones on DerivedFrom. + if( HasWriterListeners() ) + { + m_bFormatInDTOR = true; + + SwFormat* pParentFormat = DerivedFrom(); + if( !pParentFormat ) + { + SAL_WARN( + "sw.core", + "~SwFormat: parent format missing from: " << GetName() ); + } + else + { + SwFormatChg aOldFormat( this ); + SwFormatChg aNewFormat( pParentFormat ); + SwIterator<SwClient,SwFormat> aIter(*this); + for(SwClient* pClient = aIter.First(); pClient && pParentFormat; pClient = aIter.Next()) + { + SAL_INFO("sw.core", "reparenting " << typeid(*pClient).name() << " at " << pClient << " from " << typeid(*this).name() << " at " << this << " to " << typeid(*pParentFormat).name() << " at " << pParentFormat); + pParentFormat->Add( pClient ); + pClient->ModifyNotification( &aOldFormat, &aNewFormat ); + } + } + } +} + +void SwFormat::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue ) +{ + bool bContinue = true; // true = pass on to dependent ones + + sal_uInt16 nWhich = pOldValue ? pOldValue->Which() : + pNewValue ? pNewValue->Which() : 0 ; + switch( nWhich ) + { + case 0: break; // Which-Id of 0? + + case RES_OBJECTDYING: + if (pNewValue) + { + // If the dying object is the parent format of this format so + // attach this to the parent of the parent + SwFormat* pFormat = static_cast<SwFormat*>(static_cast<const SwPtrMsgPoolItem*>(pNewValue)->pObject); + + // do not move if this is the topmost format + if( GetRegisteredIn() && GetRegisteredIn() == pFormat ) + { + if( pFormat->GetRegisteredIn() ) + { + // if parent so register in new parent + pFormat->DerivedFrom()->Add( this ); + m_aSet.SetParent( &DerivedFrom()->m_aSet ); + } + else + { + // otherwise de-register at least from dying one + EndListeningAll(); + m_aSet.SetParent( nullptr ); + } + } + } + break; + case RES_ATTRSET_CHG: + if (pOldValue && pNewValue && static_cast<const SwAttrSetChg*>(pOldValue)->GetTheChgdSet() != &m_aSet) + { + // pass only those that are not set + SwAttrSetChg aOld( *static_cast<const SwAttrSetChg*>(pOldValue) ); + SwAttrSetChg aNew( *static_cast<const SwAttrSetChg*>(pNewValue) ); + + aOld.GetChgSet()->Differentiate( m_aSet ); + aNew.GetChgSet()->Differentiate( m_aSet ); + + if( aNew.Count() ) + NotifyClients( &aOld, &aNew ); + bContinue = false; + } + break; + case RES_FMT_CHG: + // if the format parent will be moved so register my attribute set at + // the new one + + // skip my own Modify + if ( pOldValue && pNewValue && + static_cast<const SwFormatChg*>(pOldValue)->pChangedFormat != this && + static_cast<const SwFormatChg*>(pNewValue)->pChangedFormat == GetRegisteredIn() ) + { + // attach Set to new parent + m_aSet.SetParent( DerivedFrom() ? &DerivedFrom()->m_aSet : nullptr ); + } + break; + default: + { + // attribute is defined in this format + if( SfxItemState::SET == m_aSet.GetItemState( nWhich, false )) + { + // DropCaps might come into this block + OSL_ENSURE( RES_PARATR_DROP == nWhich, "Modify was sent without sender" ); + bContinue = false; + } + } + } + + if( bContinue ) + { + // walk over all dependent formats + NotifyClients( pOldValue, pNewValue ); + } +} + +bool SwFormat::SetDerivedFrom(SwFormat *pDerFrom) +{ + if ( pDerFrom ) + { + const SwFormat* pFormat = pDerFrom; + while ( pFormat != nullptr ) + { + if ( pFormat == this ) + return false; + + pFormat=pFormat->DerivedFrom(); + } + } + else + { + // nothing provided, search for Dflt format + pDerFrom = this; + while ( pDerFrom->DerivedFrom() ) + pDerFrom = pDerFrom->DerivedFrom(); + } + if ( (pDerFrom == DerivedFrom()) || (pDerFrom == this) ) + return false; + + assert( Which()==pDerFrom->Which() + || (Which()==RES_CONDTXTFMTCOLL && pDerFrom->Which()==RES_TXTFMTCOLL) + || (Which()==RES_TXTFMTCOLL && pDerFrom->Which()==RES_CONDTXTFMTCOLL) + || (Which()==RES_FLYFRMFMT && pDerFrom->Which()==RES_FRMFMT) + ); + + if ( IsInCache() ) + { + SwFrame::GetCache().Delete( this ); + SetInCache( false ); + } + SetInSwFntCache( false ); + + pDerFrom->Add( this ); + m_aSet.SetParent( &pDerFrom->m_aSet ); + + SwFormatChg aOldFormat( this ); + SwFormatChg aNewFormat( this ); + ModifyNotification( &aOldFormat, &aNewFormat ); + + return true; +} + +bool SwFormat::supportsFullDrawingLayerFillAttributeSet() const +{ + return false; +} + +const SfxPoolItem& SwFormat::GetFormatAttr( sal_uInt16 nWhich, bool bInParents ) const +{ + if (RES_BACKGROUND == nWhich && supportsFullDrawingLayerFillAttributeSet()) + { + // FALLBACKBREAKHERE should not be used; instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] + SAL_INFO("sw.core", "Do no longer use SvxBrushItem, instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] FillAttributes or makeBackgroundBrushItem (simple fallback is in place and used)"); + static std::unique_ptr<SvxBrushItem> aSvxBrushItem; //(std::make_shared<SvxBrushItem>(RES_BACKGROUND)); + + // fill the local static SvxBrushItem from the current ItemSet so that + // the fill attributes [XATTR_FILL_FIRST .. XATTR_FILL_LAST] are used + // as good as possible to create a fallback representation and return that + aSvxBrushItem = getSvxBrushItemFromSourceSet(m_aSet, RES_BACKGROUND, bInParents); + + return *aSvxBrushItem; + } + + return m_aSet.Get( nWhich, bInParents ); +} + +SfxItemState SwFormat::GetItemState( sal_uInt16 nWhich, bool bSrchInParent, const SfxPoolItem **ppItem ) const +{ + if (RES_BACKGROUND == nWhich && supportsFullDrawingLayerFillAttributeSet()) + { + // FALLBACKBREAKHERE should not be used; instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] + SAL_INFO("sw.core", "Do no longer use SvxBrushItem, instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] FillAttributes or SwFormat::GetBackgroundStat (simple fallback is in place and used)"); + const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFill = getSdrAllFillAttributesHelper(); + + // check if the new fill attributes are used + if(aFill && aFill->isUsed()) + { + // if yes, fill the local SvxBrushItem using the new fill attributes + // as good as possible to have an instance for the pointer to point + // to and return as state that it is set + static std::unique_ptr<SvxBrushItem> aSvxBrushItem; //(RES_BACKGROUND); + + aSvxBrushItem = getSvxBrushItemFromSourceSet(m_aSet, RES_BACKGROUND, bSrchInParent); + if( ppItem ) + *ppItem = aSvxBrushItem.get(); + + return SfxItemState::SET; + } + + // if not, reset pointer and return SfxItemState::DEFAULT to signal that + // the item is not set + if( ppItem ) + *ppItem = nullptr; + + return SfxItemState::DEFAULT; + } + + return m_aSet.GetItemState( nWhich, bSrchInParent, ppItem ); +} + +SfxItemState SwFormat::GetBackgroundState(std::unique_ptr<SvxBrushItem>& rItem) const +{ + if (supportsFullDrawingLayerFillAttributeSet()) + { + // FALLBACKBREAKHERE should not be used; instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] + const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFill = getSdrAllFillAttributesHelper(); + + // check if the new fill attributes are used + if(aFill && aFill->isUsed()) + { + // if yes, fill the local SvxBrushItem using the new fill attributes + // as good as possible to have an instance for the pointer to point + // to and return as state that it is set + rItem = getSvxBrushItemFromSourceSet(m_aSet, RES_BACKGROUND); + return SfxItemState::SET; + } + + // if not return SfxItemState::DEFAULT to signal that the item is not set + return SfxItemState::DEFAULT; + } + + const SfxPoolItem* pItem = nullptr; + SfxItemState eRet = m_aSet.GetItemState(RES_BACKGROUND, true, &pItem); + if (pItem) + rItem.reset(static_cast<SvxBrushItem*>(pItem->Clone())); + return eRet; +} + +bool SwFormat::SetFormatAttr( const SfxPoolItem& rAttr ) +{ + if ( IsInCache() || IsInSwFntCache() ) + { + const sal_uInt16 nWhich = rAttr.Which(); + CheckCaching( nWhich ); + } + + bool bRet = false; + + if (RES_BACKGROUND == rAttr.Which() && supportsFullDrawingLayerFillAttributeSet()) + { + // FALLBACKBREAKHERE should not be used; instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] + SAL_INFO("sw.core", "Do no longer use SvxBrushItem, instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] FillAttributes (simple fallback is in place and used)"); + SfxItemSet aTempSet(*m_aSet.GetPool(), svl::Items<XATTR_FILL_FIRST, XATTR_FILL_LAST>{}); + const SvxBrushItem& rSource = static_cast< const SvxBrushItem& >(rAttr); + + // fill a local ItemSet with the attributes corresponding as good as possible + // to the new fill properties [XATTR_FILL_FIRST .. XATTR_FILL_LAST] and set these + // as ItemSet + setSvxBrushItemAsFillAttributesToTargetSet(rSource, aTempSet); + + if(IsModifyLocked()) + { + bRet = m_aSet.Put( aTempSet ); + if( bRet ) + { + m_aSet.SetModifyAtAttr( this ); + } + } + else + { + SwAttrSet aOld(*m_aSet.GetPool(), m_aSet.GetRanges()), aNew(*m_aSet.GetPool(), m_aSet.GetRanges()); + + bRet = m_aSet.Put_BC(aTempSet, &aOld, &aNew); + + if(bRet) + { + m_aSet.SetModifyAtAttr(this); + + SwAttrSetChg aChgOld(m_aSet, aOld); + SwAttrSetChg aChgNew(m_aSet, aNew); + + ModifyNotification(&aChgOld, &aChgNew); + } + } + + return bRet; + } + + // if Modify is locked then no modifications will be sent; + // but call Modify always for FrameFormats + const sal_uInt16 nFormatWhich = Which(); + if( IsModifyLocked() || + ( !HasWriterListeners() && + (RES_GRFFMTCOLL == nFormatWhich || + RES_TXTFMTCOLL == nFormatWhich ) ) ) + { + bRet = nullptr != m_aSet.Put( rAttr ); + if( bRet ) + m_aSet.SetModifyAtAttr( this ); + // #i71574# + if ( nFormatWhich == RES_TXTFMTCOLL && rAttr.Which() == RES_PARATR_NUMRULE ) + { + TextFormatCollFunc::CheckTextFormatCollForDeletionOfAssignmentToOutlineStyle( this ); + } + } + else + { + // copy only array with attributes delta + SwAttrSet aOld( *m_aSet.GetPool(), m_aSet.GetRanges() ), + aNew( *m_aSet.GetPool(), m_aSet.GetRanges() ); + + bRet = m_aSet.Put_BC( rAttr, &aOld, &aNew ); + if( bRet ) + { + // some special treatments for attributes + m_aSet.SetModifyAtAttr( this ); + + SwAttrSetChg aChgOld( m_aSet, aOld ); + SwAttrSetChg aChgNew( m_aSet, aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // send all modified ones + } + } + return bRet; +} + +bool SwFormat::SetFormatAttr( const SfxItemSet& rSet ) +{ + if( !rSet.Count() ) + return false; + + if ( IsInCache() ) + { + SwFrame::GetCache().Delete( this ); + SetInCache( false ); + } + SetInSwFntCache( false ); + + bool bRet = false; + + // Use local copy to be able to apply needed changes, e.g. call + // CheckForUniqueItemForLineFillNameOrIndex which is needed for NameOrIndex stuff + SfxItemSet aTempSet(rSet); + + // Need to check for unique item for DrawingLayer items of type NameOrIndex + // and evtl. correct that item to ensure unique names for that type. This call may + // modify/correct entries inside of the given SfxItemSet + if(GetDoc()) + { + GetDoc()->CheckForUniqueItemForLineFillNameOrIndex(aTempSet); + } + + if (supportsFullDrawingLayerFillAttributeSet()) + { + const SfxPoolItem* pSource = nullptr; + + if(SfxItemState::SET == aTempSet.GetItemState(RES_BACKGROUND, false, &pSource)) + { + // FALLBACKBREAKHERE should not be used; instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] + SAL_INFO("sw.core", "Do no longer use SvxBrushItem, instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] FillAttributes (simple fallback is in place and used)"); + + // copy all items to be set anyways to a local ItemSet with is also prepared for the new + // fill attribute ranges [XATTR_FILL_FIRST .. XATTR_FILL_LAST]. Add the attributes + // corresponding as good as possible to the new fill properties and set the whole ItemSet + const SvxBrushItem& rSource(static_cast< const SvxBrushItem& >(*pSource)); + setSvxBrushItemAsFillAttributesToTargetSet(rSource, aTempSet); + + if(IsModifyLocked()) + { + bRet = m_aSet.Put( aTempSet ); + if( bRet ) + { + m_aSet.SetModifyAtAttr( this ); + } + } + else + { + SwAttrSet aOld(*m_aSet.GetPool(), m_aSet.GetRanges()), aNew(*m_aSet.GetPool(), m_aSet.GetRanges()); + + bRet = m_aSet.Put_BC(aTempSet, &aOld, &aNew); + + if(bRet) + { + m_aSet.SetModifyAtAttr(this); + + SwAttrSetChg aChgOld(m_aSet, aOld); + SwAttrSetChg aChgNew(m_aSet, aNew); + + ModifyNotification(&aChgOld, &aChgNew); + } + } + + return bRet; + } + } + + // if Modify is locked then no modifications will be sent; + // but call Modify always for FrameFormats + const sal_uInt16 nFormatWhich = Which(); + if ( IsModifyLocked() || + ( !HasWriterListeners() && + ( RES_GRFFMTCOLL == nFormatWhich || + RES_TXTFMTCOLL == nFormatWhich ) ) ) + { + bRet = m_aSet.Put( aTempSet ); + if( bRet ) + m_aSet.SetModifyAtAttr( this ); + // #i71574# + if ( nFormatWhich == RES_TXTFMTCOLL ) + { + TextFormatCollFunc::CheckTextFormatCollForDeletionOfAssignmentToOutlineStyle( this ); + } + } + else + { + SwAttrSet aOld( *m_aSet.GetPool(), m_aSet.GetRanges() ), + aNew( *m_aSet.GetPool(), m_aSet.GetRanges() ); + bRet = m_aSet.Put_BC( aTempSet, &aOld, &aNew ); + if( bRet ) + { + // some special treatments for attributes + m_aSet.SetModifyAtAttr( this ); + SwAttrSetChg aChgOld( m_aSet, aOld ); + SwAttrSetChg aChgNew( m_aSet, aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // send all modified ones + } + } + return bRet; +} + +// remove Hint using nWhich from array with delta +bool SwFormat::ResetFormatAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 ) +{ + if( !m_aSet.Count() ) + return false; + + if( !nWhich2 || nWhich2 < nWhich1 ) + nWhich2 = nWhich1; // then set to 1st ID, only this item + + if ( IsInCache() || IsInSwFntCache() ) + { + for( sal_uInt16 n = nWhich1; n < nWhich2; ++n ) + CheckCaching( n ); + } + + // if Modify is locked then no modifications will be sent + if( IsModifyLocked() ) + return 0 != (( nWhich2 == nWhich1 ) + ? m_aSet.ClearItem( nWhich1 ) + : m_aSet.ClearItem_BC( nWhich1, nWhich2 )); + + SwAttrSet aOld( *m_aSet.GetPool(), m_aSet.GetRanges() ), + aNew( *m_aSet.GetPool(), m_aSet.GetRanges() ); + bool bRet = 0 != m_aSet.ClearItem_BC( nWhich1, nWhich2, &aOld, &aNew ); + if( bRet ) + { + SwAttrSetChg aChgOld( m_aSet, aOld ); + SwAttrSetChg aChgNew( m_aSet, aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // send all modified ones + } + return bRet; +} + +// #i73790# +sal_uInt16 SwFormat::ResetAllFormatAttr() +{ + if( !m_aSet.Count() ) + return 0; + + if ( IsInCache() ) + { + SwFrame::GetCache().Delete( this ); + SetInCache( false ); + } + SetInSwFntCache( false ); + + // if Modify is locked then no modifications will be sent + if( IsModifyLocked() ) + return m_aSet.ClearItem(); + + SwAttrSet aOld( *m_aSet.GetPool(), m_aSet.GetRanges() ), + aNew( *m_aSet.GetPool(), m_aSet.GetRanges() ); + bool bRet = 0 != m_aSet.ClearItem_BC( 0, &aOld, &aNew ); + if( bRet ) + { + SwAttrSetChg aChgOld( m_aSet, aOld ); + SwAttrSetChg aChgNew( m_aSet, aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // send all modified ones + } + return aNew.Count(); +} + +void SwFormat::DelDiffs( const SfxItemSet& rSet ) +{ + if( !m_aSet.Count() ) + return; + + if ( IsInCache() ) + { + SwFrame::GetCache().Delete( this ); + SetInCache( false ); + } + SetInSwFntCache( false ); + + // if Modify is locked then no modifications will be sent + if( IsModifyLocked() ) + { + m_aSet.Intersect( rSet ); + return; + } + + SwAttrSet aOld( *m_aSet.GetPool(), m_aSet.GetRanges() ), + aNew( *m_aSet.GetPool(), m_aSet.GetRanges() ); + bool bRet = 0 != m_aSet.Intersect_BC( rSet, &aOld, &aNew ); + if( bRet ) + { + SwAttrSetChg aChgOld( m_aSet, aOld ); + SwAttrSetChg aChgNew( m_aSet, aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // send all modified ones + } +} + +/** SwFormat::IsBackgroundTransparent + + Virtual method to determine, if background of format is transparent. + Default implementation returns false. Thus, subclasses have to override + method, if the specific subclass can have a transparent background. + + @return false, default implementation +*/ +bool SwFormat::IsBackgroundTransparent() const +{ + return false; +} + +/* + * Document Interface Access + */ +const IDocumentSettingAccess& SwFormat::getIDocumentSettingAccess() const { return GetDoc()->GetDocumentSettingManager(); } +const IDocumentDrawModelAccess& SwFormat::getIDocumentDrawModelAccess() const { return GetDoc()->getIDocumentDrawModelAccess(); } +IDocumentDrawModelAccess& SwFormat::getIDocumentDrawModelAccess() { return GetDoc()->getIDocumentDrawModelAccess(); } +const IDocumentLayoutAccess& SwFormat::getIDocumentLayoutAccess() const { return GetDoc()->getIDocumentLayoutAccess(); } +IDocumentLayoutAccess& SwFormat::getIDocumentLayoutAccess() { return GetDoc()->getIDocumentLayoutAccess(); } +IDocumentTimerAccess& SwFormat::getIDocumentTimerAccess() { return GetDoc()->getIDocumentTimerAccess(); } +IDocumentFieldsAccess& SwFormat::getIDocumentFieldsAccess() { return GetDoc()->getIDocumentFieldsAccess(); } +IDocumentChartDataProviderAccess& SwFormat::getIDocumentChartDataProviderAccess() { return GetDoc()->getIDocumentChartDataProviderAccess(); } + +void SwFormat::GetGrabBagItem(uno::Any& rVal) const +{ + if (m_pGrabBagItem) + m_pGrabBagItem->QueryValue(rVal); + else + rVal <<= uno::Sequence<beans::PropertyValue>(); +} + +void SwFormat::SetGrabBagItem(const uno::Any& rVal) +{ + if (!m_pGrabBagItem) + m_pGrabBagItem = std::make_shared<SfxGrabBagItem>(); + + m_pGrabBagItem->PutValue(rVal, 0); +} + +std::unique_ptr<SvxBrushItem> SwFormat::makeBackgroundBrushItem(bool bInP) const +{ + if (supportsFullDrawingLayerFillAttributeSet()) + { + // FALLBACKBREAKHERE should not be used; instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] + SAL_INFO("sw.core", "Do no longer use SvxBrushItem, instead use [XATTR_FILL_FIRST .. XATTR_FILL_LAST] FillAttributes (simple fallback is in place and used)"); + + // fill the local static SvxBrushItem from the current ItemSet so that + // the fill attributes [XATTR_FILL_FIRST .. XATTR_FILL_LAST] are used + // as good as possible to create a fallback representation and return that + return getSvxBrushItemFromSourceSet(m_aSet, RES_BACKGROUND, bInP); + } + + return std::unique_ptr<SvxBrushItem>(m_aSet.GetBackground(bInP).Clone()); +} + +drawinglayer::attribute::SdrAllFillAttributesHelperPtr SwFormat::getSdrAllFillAttributesHelper() const +{ + return drawinglayer::attribute::SdrAllFillAttributesHelperPtr(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/attr/hints.cxx b/sw/source/core/attr/hints.cxx new file mode 100644 index 000000000..b8d626e1b --- /dev/null +++ b/sw/source/core/attr/hints.cxx @@ -0,0 +1,270 @@ +/* -*- 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 <com/sun/star/i18n/ScriptType.hpp> +#include <hintids.hxx> +#include <hints.hxx> +#include <ndtxt.hxx> +#include <swtypes.hxx> +#include <svl/languageoptions.hxx> +#include <vcl/outdev.hxx> +#include <osl/diagnose.h> + +SwFormatChg::SwFormatChg( SwFormat* pFormat ) + : SwMsgPoolItem( RES_FMT_CHG ), pChangedFormat( pFormat ) +{ +} + +SwInsText::SwInsText( sal_Int32 nP, sal_Int32 nL ) + : SwMsgPoolItem( RES_INS_TXT ), nPos( nP ), nLen( nL ) +{ +} + +SwDelChr::SwDelChr( sal_Int32 nP ) + : SwMsgPoolItem( RES_DEL_CHR ), nPos( nP ) +{ +} + +SwDelText::SwDelText( sal_Int32 nS, sal_Int32 nL ) + : SwMsgPoolItem( RES_DEL_TXT ), nStart( nS ), nLen( nL ) +{ +} + +namespace sw { + +MoveText::MoveText(SwTextNode *const pD, sal_Int32 const nD, sal_Int32 const nS, sal_Int32 const nL) + : pDestNode(pD), nDestStart(nD), nSourceStart(nS), nLen(nL) +{ +} + +RedlineDelText::RedlineDelText(sal_Int32 const nS, sal_Int32 const nL) + : nStart(nS), nLen(nL) +{ +} + +RedlineUnDelText::RedlineUnDelText(sal_Int32 const nS, sal_Int32 const nL) + : nStart(nS), nLen(nL) +{ +} + +} // namespace sw + +SwUpdateAttr::SwUpdateAttr( sal_Int32 nS, sal_Int32 nE, sal_uInt16 nW ) + : SwMsgPoolItem( RES_UPDATE_ATTR ), m_nStart( nS ), m_nEnd( nE ), m_nWhichAttr( nW ) +{ +} + +SwUpdateAttr::SwUpdateAttr( sal_Int32 nS, sal_Int32 nE, sal_uInt16 nW, std::vector<sal_uInt16> aW ) + : SwMsgPoolItem( RES_UPDATE_ATTR ), m_nStart( nS ), m_nEnd( nE ), m_nWhichAttr( nW ), m_aWhichFmtAttrs( aW ) +{ +} + +SwRefMarkFieldUpdate::SwRefMarkFieldUpdate( OutputDevice* pOutput ) + : SwMsgPoolItem( RES_REFMARKFLD_UPDATE ), + pOut( pOutput ) +{ + OSL_ENSURE( pOut, "No OutputDevice pointer" ); +} + +SwDocPosUpdate::SwDocPosUpdate( const SwTwips nDcPos ) + : SwMsgPoolItem( RES_DOCPOS_UPDATE ), nDocPos(nDcPos) +{ +} + +SwTableFormulaUpdate::SwTableFormulaUpdate( const SwTable* pNewTable ) + : SwMsgPoolItem( RES_TABLEFML_UPDATE ), + m_pTable( pNewTable ), m_pHistory( nullptr ), m_nSplitLine( USHRT_MAX ), + m_eFlags( TBL_CALC ) +{ + m_aData.pDelTable = nullptr; + m_bModified = m_bBehindSplitLine = false; + OSL_ENSURE( m_pTable, "No Table pointer" ); +} + +SwAutoFormatGetDocNode::SwAutoFormatGetDocNode( const SwNodes* pNds ) + : SwMsgPoolItem( RES_AUTOFMT_DOCNODE ), pNodes( pNds ) +{ +} + +SwAttrSetChg::SwAttrSetChg( const SwAttrSet& rTheSet, SwAttrSet& rSet ) + : SwMsgPoolItem( RES_ATTRSET_CHG ), + m_bDelSet( false ), + m_pChgSet( &rSet ), + m_pTheChgdSet( &rTheSet ) +{ +} + +SwAttrSetChg::SwAttrSetChg( const SwAttrSetChg& rChgSet ) + : SwMsgPoolItem( RES_ATTRSET_CHG ), + m_bDelSet( true ), + m_pTheChgdSet( rChgSet.m_pTheChgdSet ) +{ + m_pChgSet = new SwAttrSet( *rChgSet.m_pChgSet ); +} + +SwAttrSetChg::~SwAttrSetChg() +{ + if( m_bDelSet ) + delete m_pChgSet; +} + +#ifdef DBG_UTIL +void SwAttrSetChg::ClearItem( sal_uInt16 nWhch ) +{ + OSL_ENSURE( m_bDelSet, "The Set may not be changed!" ); + m_pChgSet->ClearItem( nWhch ); +} +#endif + +SwMsgPoolItem::SwMsgPoolItem( sal_uInt16 nWhch ) + : SfxPoolItem( nWhch ) +{ +} + +bool SwMsgPoolItem::operator==( const SfxPoolItem& ) const +{ + assert( false && "SwMsgPoolItem knows no ==" ); + return false; +} + +SwMsgPoolItem* SwMsgPoolItem::Clone( SfxItemPool* ) const +{ + OSL_FAIL( "SwMsgPoolItem knows no Clone" ); + return nullptr; +} + +#if OSL_DEBUG_LEVEL > 0 +const SfxPoolItem* GetDfltAttr( sal_uInt16 nWhich ) +{ + OSL_ASSERT( nWhich < POOLATTR_END && nWhich >= POOLATTR_BEGIN ); + + SfxPoolItem *pHt = aAttrTab[ nWhich - POOLATTR_BEGIN ]; + OSL_ENSURE( pHt, "GetDfltFormatAttr(): Dflt == 0" ); + return pHt; +} +#else +const SfxPoolItem* GetDfltAttr( sal_uInt16 nWhich ) +{ + return aAttrTab[ nWhich - POOLATTR_BEGIN ]; +} +#endif + +SwCondCollCondChg::SwCondCollCondChg( SwFormat *pFormat ) + : SwMsgPoolItem( RES_CONDCOLL_CONDCHG ), pChangedFormat( pFormat ) +{ +} + +SwVirtPageNumInfo::SwVirtPageNumInfo( const SwPageFrame *pPg ) : + SwMsgPoolItem( RES_VIRTPAGENUM_INFO ), m_pPage( nullptr ), m_pOrigPage( pPg ), m_pFrame( nullptr ) +{ +} + +SwFindNearestNode::SwFindNearestNode( const SwNode& rNd ) + : SwMsgPoolItem( RES_FINDNEARESTNODE ), m_pNode( &rNd ), m_pFound( nullptr ) +{ +} + +void SwFindNearestNode::CheckNode( const SwNode& rNd ) +{ + if( &m_pNode->GetNodes() == &rNd.GetNodes() ) + { + sal_uLong nIdx = rNd.GetIndex(); + if( nIdx < m_pNode->GetIndex() && + ( !m_pFound || nIdx > m_pFound->GetIndex() ) && + nIdx > rNd.GetNodes().GetEndOfExtras().GetIndex() ) + m_pFound = &rNd; + } +} + +sal_uInt16 GetWhichOfScript( sal_uInt16 nWhich, sal_uInt16 nScript ) +{ + static const sal_uInt16 aLangMap[3] = + { RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE }; + static const sal_uInt16 aFontMap[3] = + { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT}; + static const sal_uInt16 aFontSizeMap[3] = + { RES_CHRATR_FONTSIZE, RES_CHRATR_CJK_FONTSIZE, RES_CHRATR_CTL_FONTSIZE }; + static const sal_uInt16 aWeightMap[3] = + { RES_CHRATR_WEIGHT, RES_CHRATR_CJK_WEIGHT, RES_CHRATR_CTL_WEIGHT}; + static const sal_uInt16 aPostureMap[3] = + { RES_CHRATR_POSTURE, RES_CHRATR_CJK_POSTURE, RES_CHRATR_CTL_POSTURE}; + + const sal_uInt16* pM; + switch( nWhich ) + { + case RES_CHRATR_LANGUAGE: + case RES_CHRATR_CJK_LANGUAGE: + case RES_CHRATR_CTL_LANGUAGE: + pM = aLangMap; + break; + + case RES_CHRATR_FONT: + case RES_CHRATR_CJK_FONT: + case RES_CHRATR_CTL_FONT: + pM = aFontMap; + break; + + case RES_CHRATR_FONTSIZE: + case RES_CHRATR_CJK_FONTSIZE: + case RES_CHRATR_CTL_FONTSIZE: + pM = aFontSizeMap; + break; + + case RES_CHRATR_WEIGHT: + case RES_CHRATR_CJK_WEIGHT: + case RES_CHRATR_CTL_WEIGHT: + pM = aWeightMap; + break; + + case RES_CHRATR_POSTURE: + case RES_CHRATR_CJK_POSTURE: + case RES_CHRATR_CTL_POSTURE: + pM = aPostureMap; + break; + + default: + pM = nullptr; + } + + sal_uInt16 nRet; + if( pM ) + { + using namespace ::com::sun::star; + { + if( i18n::ScriptType::WEAK == nScript ) + nScript = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() ); + switch( nScript) + { + case i18n::ScriptType::COMPLEX: + ++pM; + [[fallthrough]]; + case i18n::ScriptType::ASIAN: + ++pM; + [[fallthrough]]; + default: + nRet = *pM; + } + } + } + else + nRet = nWhich; + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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: */ |