diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/attr | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/attr')
-rw-r--r-- | sw/source/core/attr/BorderCacheOwner.cxx | 48 | ||||
-rw-r--r-- | sw/source/core/attr/calbck.cxx | 337 | ||||
-rw-r--r-- | sw/source/core/attr/cellatr.cxx | 182 | ||||
-rw-r--r-- | sw/source/core/attr/fmtfollowtextflow.cxx | 27 | ||||
-rw-r--r-- | sw/source/core/attr/fmtwrapinfluenceonobjpos.cxx | 174 | ||||
-rw-r--r-- | sw/source/core/attr/format.cxx | 792 | ||||
-rw-r--r-- | sw/source/core/attr/formatflysplit.cxx | 62 | ||||
-rw-r--r-- | sw/source/core/attr/formatwraptextatflystart.cxx | 46 | ||||
-rw-r--r-- | sw/source/core/attr/hints.cxx | 266 | ||||
-rw-r--r-- | sw/source/core/attr/swatrset.cxx | 583 |
10 files changed, 2517 insertions, 0 deletions
diff --git a/sw/source/core/attr/BorderCacheOwner.cxx b/sw/source/core/attr/BorderCacheOwner.cxx new file mode 100644 index 0000000000..dd71b69493 --- /dev/null +++ b/sw/source/core/attr/BorderCacheOwner.cxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include <BorderCacheOwner.hxx> + +#include <hintids.hxx> +#include <frame.hxx> +#include <swcache.hxx> + +using namespace sw; + +BorderCacheOwner::~BorderCacheOwner() +{ + if (m_bInCache) + SwFrame::GetCache().Delete(this); +} + +void BorderCacheOwner::InvalidateInSwCache(const sal_uInt16 nWhich) +{ + switch (nWhich) + { + case RES_OBJECTDYING: + case RES_FMT_CHG: + case RES_ATTRSET_CHG: + case RES_UL_SPACE: + case RES_MARGIN_FIRSTLINE: + case RES_MARGIN_TEXTLEFT: + case RES_MARGIN_RIGHT: + case RES_LR_SPACE: + case RES_BOX: + case RES_SHADOW: + case RES_FRM_SIZE: + case RES_KEEP: + case RES_BREAK: + if (m_bInCache) + { + SwFrame::GetCache().Delete(this); + m_bInCache = false; + } + } +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/attr/calbck.cxx b/sw/source/core/attr/calbck.cxx new file mode 100644 index 0000000000..871dff4347 --- /dev/null +++ b/sw/source/core/attr/calbck.cxx @@ -0,0 +1,337 @@ +/* -*- 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 <algorithm> +#include <format.hxx> +#include <hintids.hxx> +#include <hints.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <tools/debug.hxx> + +#ifdef DBG_UTIL +#include <sal/backtrace.hxx> +#endif + +namespace sw +{ + bool ListenerEntry::GetInfo(SfxPoolItem& rInfo) const + { return m_pToTell == nullptr || m_pToTell->GetInfo( rInfo ); } + void ListenerEntry::SwClientNotify(const SwModify& rModify, const SfxHint& rHint) + { + if (rHint.GetId() == SfxHintId::SwLegacyModify) + { + auto pLegacyHint = static_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->SwClientNotify(rModify, rHint); + } + else if (m_pToTell) + m_pToTell->SwClientNotify(rModify, rHint); + } +} + +sw::LegacyModifyHint::~LegacyModifyHint() {} + +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::optional<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 {}; + + 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 {}; + } + // 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 sw::ModifyChangedHint(pAbove); +} + +void SwClient::CheckRegistrationFormat(SwFormat& rOld) +{ + assert(GetRegisteredIn() == &rOld); + auto pNew = rOld.DerivedFrom(); + SAL_INFO("sw.core", "reparenting " << typeid(*this).name() << " at " << this << " from " << typeid(rOld).name() << " at " << &rOld << " to " << typeid(*pNew).name() << " at " << pNew); + assert(pNew); + pNew->Add(this); + const SwFormatChg aOldFormat(&rOld); + const SwFormatChg aNewFormat(pNew); + const sw::LegacyModifyHint aHint(&aOldFormat, &aNewFormat); + SwClientNotify(rOld, aHint); +} + +void SwClient::SwClientNotify(const SwModify&, const SfxHint& rHint) +{ + if (rHint.GetId() != SfxHintId::SwLegacyModify) + return; + auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint); + CheckRegistration(pLegacyHint->m_pOld); +}; + +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); +} + +SwModify::~SwModify() +{ + DBG_TESTSOLARMUTEX(); + OSL_ENSURE( !IsModifyLocked(), "Modify destroyed but locked." ); + + // notify all clients that they shall remove themselves + SwPtrMsgPoolItem aDyObject( RES_OBJECTDYING, this ); + SwModify::SwClientNotify(*this, sw::LegacyModifyHint(&aDyObject, &aDyObject)); + + const bool hasListenersOnDeath = m_pWriterListeners; + (void)hasListenersOnDeath; + while(m_pWriterListeners) + { + SAL_WARN("sw.core", "lost a client of type: " << typeid(*m_pWriterListeners).name() << " at " << m_pWriterListeners << " still registered on type: " << typeid(*this).name() << " at " << this << "."); + static_cast<SwClient*>(m_pWriterListeners)->CheckRegistration(&aDyObject); + } + assert(!hasListenersOnDeath); +} + +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(); +#ifdef DBG_UTIL + // You should not EVER use SwModify directly in new code: + // - Preexisting SwModifys should only ever be used via sw::BroadcastingModify. + // This includes sw::BroadcastMixin, which is the long-term target (without + // SwModify). + // - New classes should use sw::BroadcastMixin alone. + if(!dynamic_cast<sw::BroadcastingModify*>(this)) + { + auto pBT = sal::backtrace_get(20); + SAL_WARN("sw.core", "Modify that is not broadcasting used!\n" << sal::backtrace_to_string(pBT.get())); + } +#endif + + if(pDepend->m_pRegisteredIn == this) + return; + +#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; +} + +sw::WriterMultiListener::WriterMultiListener(SwClient& rToTell) + : m_rToTell(rToTell) +{} + +sw::WriterMultiListener::~WriterMultiListener() +{} + +void sw::WriterMultiListener::StartListening(SwModify* pDepend) +{ + EndListening(nullptr); + m_vDepends.emplace_back(&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) +{ + std::erase_if( + m_vDepends, + [&pBroadcaster](const ListenerEntry& aListener) + { + return aListener.GetRegisteredIn() == nullptr || aListener.GetRegisteredIn() == pBroadcaster; + }); +} + +void sw::WriterMultiListener::EndListeningAll() +{ + m_vDepends.clear(); +} + +sw::ClientIteratorBase* sw::ClientIteratorBase::s_pClientIters = nullptr; + +void SwModify::SwClientNotify(const SwModify&, const SfxHint& rHint) +{ + if (rHint.GetId() != SfxHintId::SwLegacyModify) + return; + + DBG_TESTSOLARMUTEX(); + if(IsModifyLocked()) + return; + + LockModify(); + CallSwClientNotify(rHint); + UnlockModify(); +} + +void SwModify::CallSwClientNotify( const SfxHint& rHint ) const +{ + DBG_TESTSOLARMUTEX(); + 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); +} + +void sw::ClientNotifyAttrChg(SwModify& rModify, const SwAttrSet& aSet, SwAttrSet& aOld, SwAttrSet& aNew) +{ + const SwAttrSetChg aChgOld(aSet, aOld); + const SwAttrSetChg aChgNew(aSet, aNew); + const sw::LegacyModifyHint aHint(&aChgOld, &aChgNew); + rModify.SwClientNotify(rModify, aHint); +} +/* 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 0000000000..69eb6b1dd3 --- /dev/null +++ b/sw/source/core/attr/cellatr.cxx @@ -0,0 +1,182 @@ +/* -*- 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/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 +{ + auto pTableBox = GetTableBox(); + return pTableBox ? pTableBox->GetSttNd() : nullptr; +} + +SwTableBox* SwTableBoxFormula::GetTableBox() +{ + assert(!m_pDefinedIn || dynamic_cast<SwTableBoxFormat*>(m_pDefinedIn)); + return m_pDefinedIn ? static_cast<SwTableBoxFormat*>(m_pDefinedIn)->GetTableBox() : nullptr; +} + +void SwTableBoxFormula::TryBoxNmToPtr() +{ + const SwNode* pNd = GetNodeOfFormula(); + if (!pNd || &pNd->GetNodes() != &pNd->GetDoc().GetNodes()) + return; + if(const SwTableNode* pTableNd = pNd->FindTableNode()) + { + BoxNmToPtr(&pTableNd->GetTable()); + } +} + +void SwTableBoxFormula::TryRelBoxNm() +{ + const SwNode* pNd = GetNodeOfFormula(); + if (!pNd || &pNd->GetNodes() != &pNd->GetDoc().GetNodes()) + return; + if(const SwTableNode* pTableNd = pNd->FindTableNode()) + { + ToRelBoxNm(&pTableNd->GetTable()); + } +} + +void SwTableBoxFormula::ToSplitMergeBoxNmWithHistory(SwTableFormulaUpdate& rUpdate, SwHistory* pHistory) +{ + if(!pHistory) + { + ToSplitMergeBoxNm(rUpdate); + return; + } + auto pNd = GetNodeOfFormula(); + // for a history record the unchanged formula is needed + SwTableBoxFormula aCopy(*this); + rUpdate.m_bModified = false; + ToSplitMergeBoxNm(rUpdate); + if(rUpdate.m_bModified) + { + // external rendering + aCopy.PtrToBoxNm(&pNd->FindTableNode()->GetTable()); + pHistory->AddPoolItem( + &aCopy, + &aCopy, + pNd->FindTableBoxStartNode()->GetIndex()); + } +} + +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 0000000000..5b42405373 --- /dev/null +++ b/sw/source/core/attr/fmtfollowtextflow.cxx @@ -0,0 +1,27 @@ +/* -*- 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> + +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 0000000000..8f9abd96c7 --- /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 +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatWrapInfluenceOnObjPos")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nWrapInfluenceOnPosition"), BAD_CAST(OString::number(mnWrapInfluenceOnPosition).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("mbAllowOverlap"), BAD_CAST(OString::boolean(mbAllowOverlap).getStr())); + (void)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 0000000000..6f2f076881 --- /dev/null +++ b/sw/source/core/attr/format.cxx @@ -0,0 +1,792 @@ +/* -*- 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 <DocumentSettingManager.hxx> //For SwFmt::getIDocumentSettingAccess() +#include <IDocumentTimerAccess.hxx> +#include <doc.hxx> +#include <fmtcolfunc.hxx> +#include <format.hxx> +#include <frmatr.hxx> +#include <hintids.hxx> +#include <hints.hxx> +#include <o3tl/unit_conversion.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <svl/grabbagitem.hxx> +#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx> +#include <svx/unobrushitemhelper.hxx> +#include <svx/xdef.hxx> +#include <utility> + +using namespace com::sun::star; + +SwFormat::SwFormat( SwAttrPool& rPool, const char* pFormatNm, + const WhichRangesContainer& 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_bAutoUpdateOnDirectFormat = 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, OUString aFormatNm, + const WhichRangesContainer& pWhichRanges, SwFormat* pDrvdFrame, + sal_uInt16 nFormatWhich ) : + m_aFormatName( std::move(aFormatNm) ), + m_aSet( rPool, pWhichRanges ), + m_nWhichId( nFormatWhich ), + m_nPoolFormatId( USHRT_MAX ), + m_nPoolHelpId( USHRT_MAX ), + m_nPoolHlpFileId( UCHAR_MAX ) +{ + m_bAutoUpdateOnDirectFormat = 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 ) : + sw::BorderCacheOwner(), + 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_bAutoUpdateOnDirectFormat = rFormat.m_bAutoUpdateOnDirectFormat; + + 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(); + + InvalidateInSwCache(RES_OBJECTDYING); + + // 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() ) + { + sw::ClientNotifyAttrChg(*this, m_aSet, aOld, aNew); + } + + 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_bAutoUpdateOnDirectFormat = rFormat.m_bAutoUpdateOnDirectFormat; + return *this; +} + +void SwFormat::SetFormatName( const OUString& rNewName, bool bBroadcast ) +{ + OSL_ENSURE( !IsDefault(), "SetName: Defaultformat" ); + if( bBroadcast ) + { + m_aFormatName = rNewName; + const sw::NameChanged aHint(m_aFormatName, rNewName); + SwClientNotify(*this, aHint); + } + 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 + InvalidateInSwCache(RES_ATTRSET_CHG); + InvalidateInSwFntCache(RES_ATTRSET_CHG); + + // 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 ); + SwClientNotify(*this, sw::LegacyModifyHint(&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()) + return; + + m_bFormatInDTOR = true; + + if(!DerivedFrom()) + { + SwFormat::ResetFormatAttr(RES_PAGEDESC); + SAL_WARN("sw.core", "~SwFormat: format still has clients on death, but parent format is missing: " << GetName()); + return; + } + SwIterator<SwClient,SwFormat> aIter(*this); + for(SwClient* pClient = aIter.First(); pClient; pClient = aIter.Next()) + pClient->CheckRegistrationFormat(*this); + assert(!HasWriterListeners()); +} + +void SwFormat::SwClientNotify(const SwModify&, const SfxHint& rHint) +{ + if (rHint.GetId() != SfxHintId::SwLegacyModify) + return; + auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint); + + std::optional<SwAttrSetChg> oOldClientChg, oNewClientChg; + std::optional<sw::LegacyModifyHint> oDependsHint(std::in_place, pLegacy->m_pOld, pLegacy->m_pNew); + const sal_uInt16 nWhich = pLegacy->GetWhich(); + InvalidateInSwCache(nWhich); + switch(nWhich) + { + case 0: + break; + case RES_OBJECTDYING: + { + // NB: this still notifies depends even if pLegacy->m_pNew is nullptr, which seems non-obvious + if(!pLegacy->m_pNew) + break; + // 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*>(pLegacy->m_pNew->StaticWhichCast(RES_OBJECTDYING).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: + { + // NB: this still notifies depends even if this condition is not met, which seems non-obvious + auto pOldAttrSetChg = static_cast<const SwAttrSetChg*>(pLegacy->m_pOld); + auto pNewAttrSetChg = static_cast<const SwAttrSetChg*>(pLegacy->m_pNew); + if (pOldAttrSetChg && pNewAttrSetChg && pOldAttrSetChg->GetTheChgdSet() != &m_aSet) + { + // pass only those that are not set... + oNewClientChg.emplace(*pNewAttrSetChg); + oNewClientChg->GetChgSet()->Differentiate(m_aSet); + if(oNewClientChg->Count()) // ... if any + { + oOldClientChg.emplace(*pOldAttrSetChg); + oOldClientChg->GetChgSet()->Differentiate(m_aSet); + oDependsHint.emplace(&*oOldClientChg, &*oNewClientChg); + } + else + oDependsHint.reset(); + } + 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 + // NB: this still notifies depends even if this condition is not met, which seems non-obvious + auto pOldFormatChg = static_cast<const SwFormatChg*>(pLegacy->m_pOld); + auto pNewFormatChg = static_cast<const SwFormatChg*>(pLegacy->m_pNew); + if(pOldFormatChg && pNewFormatChg && pOldFormatChg->pChangedFormat != this && pNewFormatChg->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 + SAL_WARN_IF(RES_PARATR_DROP != nWhich, "sw.core", "Hint was sent without sender"); + oDependsHint.reset(); + } + } + if(oDependsHint) + { + InvalidateInSwFntCache(oDependsHint->GetWhich()); + SwModify::SwClientNotify(*this, *oDependsHint); + } +} + +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) + ); + + InvalidateInSwCache(RES_ATTRSET_CHG); + InvalidateInSwFntCache(RES_ATTRSET_CHG); + + pDerFrom->Add( this ); + m_aSet.SetParent( &pDerFrom->m_aSet ); + + SwFormatChg aOldFormat( this ); + SwFormatChg aNewFormat( this ); + const sw::LegacyModifyHint aHint(&aOldFormat, &aNewFormat); + SwClientNotify(*this, aHint); + + 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 SvxBrushItem* pItem = nullptr; + SfxItemState eRet = m_aSet.GetItemState(RES_BACKGROUND, true, &pItem); + if (pItem) + rItem.reset(pItem->Clone()); + return eRet; +} + +bool SwFormat::SetFormatAttr( const SfxPoolItem& rAttr ) +{ + const sal_uInt16 nWhich = rAttr.Which(); + InvalidateInSwFntCache( nWhich ); + InvalidateInSwCache( 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)"); + SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aTempSet(*m_aSet.GetPool()); + const SvxBrushItem& rSource = rAttr.StaticWhichCast(RES_BACKGROUND); + + // 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); + sw::ClientNotifyAttrChg(*this, m_aSet, aOld, aNew); + } + } + + 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 ); + + sw::ClientNotifyAttrChg(*this, m_aSet, aOld, aNew); + } + } + return bRet; +} + +bool SwFormat::SetFormatAttr( const SfxItemSet& rSet ) +{ + if( !rSet.Count() ) + return false; + + InvalidateInSwCache(RES_ATTRSET_CHG); + InvalidateInSwFntCache(RES_ATTRSET_CHG); + + 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()) + { + if(const SvxBrushItem* pSource = aTempSet.GetItemIfSet(RES_BACKGROUND, false)) + { + // 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 + setSvxBrushItemAsFillAttributesToTargetSet(*pSource, 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); + sw::ClientNotifyAttrChg(*this, m_aSet, aOld, aNew); + } + } + + 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 ); + sw::ClientNotifyAttrChg(*this, m_aSet, aOld, aNew); + } + } + 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 + + for( sal_uInt16 n = nWhich1; n < nWhich2; ++n ) + InvalidateInSwFntCache( n ); + for( sal_uInt16 n = nWhich1; n < nWhich2 && IsInCache(); ++n ) + InvalidateInSwCache( 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 ) + sw::ClientNotifyAttrChg(*this, m_aSet, aOld, aNew); + return bRet; +} + +// #i73790# +sal_uInt16 SwFormat::ResetAllFormatAttr() +{ + if( !m_aSet.Count() ) + return 0; + + InvalidateInSwCache(RES_ATTRSET_CHG); + InvalidateInSwFntCache(RES_ATTRSET_CHG); + + // 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 ) + sw::ClientNotifyAttrChg(*this, m_aSet, aOld, aNew); + return aNew.Count(); +} + +void SwFormat::DelDiffs( const SfxItemSet& rSet ) +{ + if( !m_aSet.Count() ) + return; + + InvalidateInSwCache(RES_ATTRSET_CHG); + InvalidateInSwFntCache(RES_ATTRSET_CHG); + + // 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 ) + sw::ClientNotifyAttrChg(*this, m_aSet, aOld, aNew); +} + +void SwFormat::SetPageFormatToDefault() +{ + const sal_Int32 nSize = o3tl::convert(2, o3tl::Length::cm, o3tl::Length::twip); + SetFormatAttr(SvxLRSpaceItem(nSize, nSize, 0, RES_LR_SPACE)); + SetFormatAttr(SvxULSpaceItem(nSize, nSize, RES_UL_SPACE)); +} + +/** 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(); +} + +void SwFormat::RemoveAllUnos() +{ + SwPtrMsgPoolItem aMsgHint(RES_REMOVE_UNO_OBJECT, this); + SwClientNotify(*this, sw::LegacyModifyHint(&aMsgHint, &aMsgHint)); +} + +bool SwFormat::IsUsed() const +{ + auto pDoc = GetDoc(); + if(!pDoc) + return false; + bool isUsed = false; + sw::AutoFormatUsedHint aHint(isUsed, pDoc->GetNodes()); + CallSwClientNotify(aHint); + return isUsed; +} + +SwFormatsBase::~SwFormatsBase() +{} + +SwFormat* SwFormatsBase::FindFormatByName( const OUString& rName ) const +{ + SwFormat* pFnd = nullptr; + for( size_t n = 0; n < GetFormatCount(); ++n ) + { + // Does the Doc already contain the template? + if( GetFormat(n)->HasName( rName ) ) + { + pFnd = GetFormat(n); + break; + } + } + return pFnd; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/attr/formatflysplit.cxx b/sw/source/core/attr/formatflysplit.cxx new file mode 100644 index 0000000000..6bcfd74390 --- /dev/null +++ b/sw/source/core/attr/formatflysplit.cxx @@ -0,0 +1,62 @@ +/* -*- 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 <formatflysplit.hxx> + +#include <libxml/xmlwriter.h> + +SwFormatFlySplit::SwFormatFlySplit(bool bSplit) + : SfxBoolItem(RES_FLY_SPLIT, bSplit) +{ + // Once this pool item is true, a floating table (text frame + table inside it) is meant to + // split across multiple pages. + // + // The layout representation is the following: + // + // - We assume that the anchor type is at-para for such fly frames. + // + // - We also assume that AutoSize is true for such fly frames. + // + // - SwFlyAtContentFrame derives from SwFlowFrame to be able to split in general. + // + // - Both the master fly and the follow flys need an anchor. At the same time, we want all text + // of the anchor frame to be wrapped around the last follow fly frame, for Word compatibility. + // These are solved by splitting the anchor frame as many times as needed, always at + // TextFrameIndex 0. + // + // - The vertical offset is only considered on the master fly, all the follow flys ignore it, so + // they start at the top of a next page. +} + +SwFormatFlySplit* SwFormatFlySplit::Clone(SfxItemPool*) const +{ + return new SwFormatFlySplit(*this); +} + +void SwFormatFlySplit::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatFlySplit")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), + BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), + BAD_CAST(OString::boolean(GetValue()).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/attr/formatwraptextatflystart.cxx b/sw/source/core/attr/formatwraptextatflystart.cxx new file mode 100644 index 0000000000..88a17d5ade --- /dev/null +++ b/sw/source/core/attr/formatwraptextatflystart.cxx @@ -0,0 +1,46 @@ +/* -*- 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 <formatwraptextatflystart.hxx> + +#include <libxml/xmlwriter.h> + +SwFormatWrapTextAtFlyStart::SwFormatWrapTextAtFlyStart(bool bAtStart) + : SfxBoolItem(RES_WRAP_TEXT_AT_FLY_START, bAtStart) +{ + // Once this pool item is true, the text from the anchor text of the fly wraps an all pages, not + // only on the last page of the fly chain. +} + +SwFormatWrapTextAtFlyStart* SwFormatWrapTextAtFlyStart::Clone(SfxItemPool*) const +{ + return new SwFormatWrapTextAtFlyStart(*this); +} + +void SwFormatWrapTextAtFlyStart::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatWrapTextAtFlyStart")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), + BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), + BAD_CAST(OString::boolean(GetValue()).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + +/* 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 0000000000..641d738031 --- /dev/null +++ b/sw/source/core/attr/hints.cxx @@ -0,0 +1,266 @@ +/* -*- 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 <utility> +#include <vcl/outdev.hxx> +#include <osl/diagnose.h> + +SwFormatChg::SwFormatChg( SwFormat* pFormat ) + : SwMsgPoolItem( RES_FMT_CHG ), pChangedFormat( pFormat ) +{ +} + + + +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) +{ +} + +InsertText::InsertText(const sal_Int32 nP, const sal_Int32 nL, const bool isInFMCommand, const bool isInFMResult) + : SfxHint( SfxHintId::SwInsertText ) + , nPos( nP ), nLen( nL ) + , isInsideFieldmarkCommand(isInFMCommand) + , isInsideFieldmarkResult(isInFMResult) +{ +} + +DeleteText::DeleteText( const sal_Int32 nS, const sal_Int32 nL ) + : SfxHint( SfxHintId::SwDeleteText ), nStart( nS ), nLen( nL ) +{ +} + +DeleteChar::DeleteChar( const sal_Int32 nPos ) + : SfxHint( SfxHintId::SwDeleteChar ), m_nPos( nPos ) +{ +} + +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) +{ +} + +VirtPageNumHint::VirtPageNumHint(const SwPageFrame* pPg): + SfxHint(SfxHintId::SwVirtPageNumHint), + m_pPage(nullptr), + m_pOrigPage(pPg), + m_pFrame(nullptr), + m_bFound(false) +{ +} + +void AutoFormatUsedHint::CheckNode(const SwNode* pNode) const +{ + if(pNode && &pNode->GetNodes() == &m_rNodes) + SetUsed(); +} +} // 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(std::move( aW )) +{ +} + +SwTableFormulaUpdate::SwTableFormulaUpdate(const SwTable* pNewTable) + : m_pTable(pNewTable) + , m_nSplitLine(USHRT_MAX) + , m_eFlags(TBL_CALC) +{ + m_aData.pDelTable = nullptr; + m_bModified = m_bBehindSplitLine = false; + OSL_ENSURE( m_pTable, "No Table pointer" ); +} + +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& rItem ) const +{ + assert( SfxPoolItem::operator==(rItem)); (void)rItem; + // SwMsgPoolItem now knows operator== due to evtl. deeper + // ItemCompares using SfxPoolItem::areSame. No members, + // so always equal + return true; +} + +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 + +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() ) + { + SwNodeOffset 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 0000000000..fc4612757d --- /dev/null +++ b/sw/source/core/attr/swatrset.cxx @@ -0,0 +1,583 @@ +/* -*- 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 <o3tl/unit_conversion.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 SfxItemPool and EditEngine pool and add these in a chain. These + // belong us and will be removed/destroyed in removeAndDeleteSecondaryPools() used from + // the destructor + rtl::Reference<SfxItemPool> pSdrPool = new SdrItemPool(this); + + // #75371# change DefaultItems for the SdrEdgeObj distance items + // to TWIPS. + constexpr tools::Long nDefEdgeDist + = o3tl::convert(500, o3tl::Length::mm100, o3tl::Length::twip); + + pSdrPool->SetPoolDefaultItem(SdrEdgeNode1HorzDistItem(nDefEdgeDist)); + pSdrPool->SetPoolDefaultItem(SdrEdgeNode1VertDistItem(nDefEdgeDist)); + pSdrPool->SetPoolDefaultItem(SdrEdgeNode2HorzDistItem(nDefEdgeDist)); + pSdrPool->SetPoolDefaultItem(SdrEdgeNode2VertDistItem(nDefEdgeDist)); + + // #i33700# // Set shadow distance defaults as PoolDefaultItems + constexpr tools::Long nDefShadowDist + = o3tl::convert(300, o3tl::Length::mm100, o3tl::Length::twip); + pSdrPool->SetPoolDefaultItem(makeSdrShadowXDistItem(nDefShadowDist)); + pSdrPool->SetPoolDefaultItem(makeSdrShadowYDistItem(nDefShadowDist)); + + rtl::Reference<SfxItemPool> pEEgPool = EditEngine::CreatePool(); + + pSdrPool->SetSecondaryPool(pEEgPool.get()); + + if(GetFrozenIdRanges().empty()) + { + FreezeIdRanges(); + } + else + { + pSdrPool->FreezeIdRanges(); + } +} + +SwAttrPool::~SwAttrPool() +{ + // cleanup secondary pools + SfxItemPool *pSdrPool = GetSecondaryPool(); + // first delete the items, then break the linking + pSdrPool->Delete(); + SetSecondaryPool(nullptr); +} + +/// Notification callback +void SwAttrSet::changeCallback(const SfxPoolItem* pOld, const SfxPoolItem* pNew) const +{ + // will have no effect, return + if (nullptr == m_pOldSet && nullptr == m_pNewSet) + return; + + // at least one SfxPoolItem has to be provided, else this is an error + assert(nullptr != pOld || nullptr != pNew); + sal_uInt16 nWhich(0); + + if (nullptr != pOld) + { + // do not handle if an invalid item is involved + if (IsInvalidItem(pOld)) + return; + + // get WhichID from pOld + nWhich = pOld->Which(); + } + + if (nullptr != pNew) + { + // do not handle if an invalid item is involved + if (IsInvalidItem(pNew)) + return; + + if (0 == nWhich) + { + // get WhichID from pNew + nWhich = pNew->Which(); + } + } + + // all given items are valid. If we got no WhichID != 0 then + // pOld == pNew == nullptr or SfxVoidItem(0) and we have no + // valid input. Also not needed if !IsWhich (aka > SFX_WHICH_MAX) + if (0 == nWhich || !SfxItemPool::IsWhich(nWhich)) + return; + + if(m_pOldSet) + { + // old state shall be saved + if (nullptr == pOld) + { + // no old value given, generate default from WhichID + const SfxItemSet* pParent(GetParent()); + m_pOldSet->PutImpl(nullptr != pParent + ? pParent->Get(nWhich) + : GetPool()->GetDefaultItem(nWhich), nWhich, false); + } + else if (!IsInvalidItem(pOld)) + { + // set/remember old value + m_pOldSet->PutImpl(*pOld, nWhich, false); + } + } + + if(m_pNewSet) + { + // old state shall be saved + if (nullptr == pNew) + { + // no new value given, generate default from WhichID + const SfxItemSet* pParent(GetParent()); + m_pNewSet->PutImpl(nullptr != pParent + ? pParent->Get(nWhich) + : GetPool()->GetDefaultItem(nWhich), nWhich, false); + } + else if (!IsInvalidItem(pNew)) + { + // set/remember new value + m_pNewSet->PutImpl(*pNew, nWhich, false); + } + } +} + +SwAttrSet::SwAttrSet( SwAttrPool& rPool, sal_uInt16 nWh1, sal_uInt16 nWh2 ) + : SfxItemSet( rPool, nWh1, nWh2 ) + , m_pOldSet( nullptr ) + , m_pNewSet( nullptr ) + , m_aCallbackHolder(this) +{ +} + +SwAttrSet::SwAttrSet( SwAttrPool& rPool, const WhichRangesContainer& nWhichPairTable ) + : SfxItemSet( rPool, nWhichPairTable ) + , m_pOldSet( nullptr ) + , m_pNewSet( nullptr ) + , m_aCallbackHolder(this) +{ +} + +SwAttrSet::SwAttrSet( const SwAttrSet& rSet ) + : SfxItemSet( rSet ) + , m_pOldSet( nullptr ) + , m_pNewSet( nullptr ) + , m_aCallbackHolder(this) +{ +} + +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() )); +} + +SwAttrSet SwAttrSet::CloneAsValue( bool bItems ) const +{ + if (bItems) + return *this; + else + return SwAttrSet( *GetPool(), GetRanges() ); +} + +bool SwAttrSet::Put_BC( const SfxPoolItem& rAttr, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + // direct call when neither pOld nor pNew is set, no need for callback + if (nullptr == pOld && nullptr == pNew) + return nullptr != SfxItemSet::Put( rAttr ); + + m_pNewSet = pNew; + m_pOldSet = pOld; + setCallback(m_aCallbackHolder); + bool bRet = nullptr != SfxItemSet::Put( rAttr ); + clearCallback(); + m_pOldSet = m_pNewSet = nullptr; + return bRet; +} + +bool SwAttrSet::Put_BC( const SfxItemSet& rSet, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + // direct call when neither pOld nor pNew is set, no need for callback + if (nullptr == pOld && nullptr == pNew) + return SfxItemSet::Put( rSet ); + + m_pNewSet = pNew; + m_pOldSet = pOld; + setCallback(m_aCallbackHolder); + bool bRet = SfxItemSet::Put( rSet ); + clearCallback(); + m_pOldSet = m_pNewSet = nullptr; + return bRet; +} + +sal_uInt16 SwAttrSet::ClearItem_BC( sal_uInt16 nWhich, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + // direct call when neither pOld nor pNew is set, no need for callback + if (nullptr == pOld && nullptr == pNew) + return SfxItemSet::ClearItem( nWhich ); + + m_pNewSet = pNew; + m_pOldSet = pOld; + setCallback(m_aCallbackHolder); + sal_uInt16 nRet = SfxItemSet::ClearItem( nWhich ); + clearCallback(); + 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" ); + sal_uInt16 nRet = 0; + + // direct call when neither pOld nor pNew is set, no need for callback + if (nullptr == pOld && nullptr == pNew) + { + for( ; nWhich1 <= nWhich2; ++nWhich1 ) + nRet = nRet + SfxItemSet::ClearItem( nWhich1 ); + return nRet; + } + + m_pNewSet = pNew; + m_pOldSet = pOld; + setCallback(m_aCallbackHolder); + for( ; nWhich1 <= nWhich2; ++nWhich1 ) + nRet = nRet + SfxItemSet::ClearItem( nWhich1 ); + clearCallback(); + m_pOldSet = m_pNewSet = nullptr; + return nRet; +} + +int SwAttrSet::Intersect_BC( const SfxItemSet& rSet, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + // direct call when neither pOld nor pNew is set, no need for callback + if (nullptr == pOld && nullptr == pNew) + { + SfxItemSet::Intersect( rSet ); + return 0; // as below when neither pOld nor pNew is set + } + + m_pNewSet = pNew; + m_pOldSet = pOld; + setCallback(m_aCallbackHolder); + SfxItemSet::Intersect( rSet ); + clearCallback(); + m_pOldSet = m_pNewSet = nullptr; + return pNew ? pNew->Count() : pOld->Count(); +} + +/** 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 sw::BroadcastingModify* pModify ) +{ + bool bSet = false; + + const SwFormatPageDesc* pPageDescItem = GetItemIfSet( RES_PAGEDESC, false ); + if( pPageDescItem && + pPageDescItem->GetDefinedIn() != pModify ) + { + const_cast<SwFormatPageDesc&>(*pPageDescItem).ChgDefinedIn( pModify ); + bSet = true; + } + + if(SwFormatDrop* pFormatDrop = const_cast<SwFormatDrop*>(GetItemIfSet( RES_PARATR_DROP, false ))) + { + auto pDropDefiner = dynamic_cast<const sw::FormatDropDefiner*>(pModify); + // If CharFormat is set and it is set in different attribute pools then + // the CharFormat has to be copied. + SwCharFormat* pCharFormat = pFormatDrop->GetCharFormat(); + if(pCharFormat && GetPool() != pCharFormat->GetAttrSet().GetPool()) + { + pCharFormat = GetDoc()->CopyCharFormat(*pCharFormat); + pFormatDrop->SetCharFormat(pCharFormat); + } + pFormatDrop->ChgDefinedIn(pDropDefiner); + bSet = true; + } + + const SwTableBoxFormula* pBoxFormula = GetItemIfSet( RES_BOXATR_FORMULA, false ); + if( pBoxFormula && pBoxFormula->GetDefinedIn() != pModify ) + { + const_cast<SwTableBoxFormula&>(*pBoxFormula).ChgDefinedIn( pModify ); + bSet = true; + } + + return bSet; +} + +void SwAttrSet::CopyToModify( sw::BroadcastingModify& 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 SwDoc *pSrcDoc = GetDoc(); + SwDoc *pDstDoc = pCNd ? &pCNd->GetDoc() : pFormat->GetDoc(); + + // Does the NumRule has to be copied? + const SwNumRuleItem* pNumRuleItem; + if( pSrcDoc != pDstDoc && + (pNumRuleItem = GetItemIfSet( RES_PARATR_NUMRULE, false )) ) + { + const OUString& rNm = pNumRuleItem->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 + const SfxStringItem* pStrItem; + if ( pSrcDoc != pDstDoc && + pCNd && pCNd->IsTextNode() && + (pStrItem = GetItemIfSet( RES_PARATR_LIST_ID, false )) ) + { + 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::optional< SfxItemSet > tmpSet; + const SwFormatPageDesc* pPageDescItem; + if( pSrcDoc != pDstDoc && (pPageDescItem = GetItemIfSet( + RES_PAGEDESC, false ))) + { + const SwPageDesc* pPgDesc = pPageDescItem->GetPageDesc(); + if( pPgDesc ) + { + tmpSet.emplace(*this); + + SwPageDesc* pDstPgDesc = pDstDoc->FindPageDesc(pPgDesc->GetName()); + if( !pDstPgDesc ) + { + pDstPgDesc = pDstDoc->MakePageDesc(pPgDesc->GetName()); + pDstDoc->CopyPageDesc( *pPgDesc, *pDstPgDesc ); + } + SwFormatPageDesc aDesc( pDstPgDesc ); + aDesc.SetNumOffset( pPageDescItem->GetNumOffset() ); + tmpSet->Put( aDesc ); + } + } + + const SwFormatAnchor* pAnchorItem; + if( pSrcDoc != pDstDoc && (pAnchorItem = GetItemIfSet( RES_ANCHOR, false )) + && pAnchorItem->GetAnchorNode() != nullptr ) + { + if( !tmpSet ) + tmpSet.emplace( *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 ); + } + + const SwFormatAutoFormat* pAutoFormatItem; + if (pSrcDoc != pDstDoc && + (pAutoFormatItem = GetItemIfSet(RES_PARATR_LIST_AUTOFMT, false)) && + pAutoFormatItem->GetStyleHandle()) + { + SfxItemSet const& rAutoStyle(*pAutoFormatItem->GetStyleHandle()); + std::shared_ptr<SfxItemSet> const pNewSet( + rAutoStyle.SfxItemSet::Clone(true, &pDstDoc->GetAttrPool())); + + // fix up character style, it contains pointers to pSrcDoc + if (const SwFormatCharFormat* pCharFormatItem = pNewSet->GetItemIfSet(RES_TXTATR_CHARFMT, false)) + { + SwCharFormat *const pCopy(pDstDoc->CopyCharFormat(*pCharFormatItem->GetCharFormat())); + const_cast<SwFormatCharFormat&>(*pCharFormatItem).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.emplace(*this); + } + tmpSet->Put(item); + } + + if( tmpSet ) + { + if( pCNd ) + { + // #i92811# + if ( pNewListIdItem != nullptr ) + { + tmpSet->Put( std::move(pNewListIdItem) ); + } + pCNd->SetAttr( *tmpSet ); + } + else + { + pFormat->SetFormatAttr( *tmpSet ); + } + } + else if( pCNd ) + { + // #i92811# + if ( pNewListIdItem != nullptr ) + { + SfxItemSet aTmpSet( *this ); + aTmpSet.Put( std::move(pNewListIdItem) ); + pCNd->SetAttr( aTmpSet ); + } + else + { + pCNd->SetAttr( *this ); + } + } + else + { + pFormat->SetFormatAttr( *this ); + } + } + if (pCNd && pCNd->HasSwAttrSet()) + { + SfxWhichIter it(*this); + std::vector<sal_uInt16> toClear; + for (sal_uInt16 nWhich = it.FirstWhich(); nWhich != 0; nWhich = it.NextWhich()) + { + if (GetItemState(nWhich, false) != SfxItemState::SET + && pCNd->GetSwAttrSet().GetItemState(nWhich, false) == SfxItemState::SET) + { + toClear.emplace_back(nWhich); + } + } + if (!toClear.empty()) + { + pCNd->ResetAttr(toClear); + } + } + } +#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 WhichRangesContainer& pRange, const sal_uInt16 nId ) +{ + for(const auto& rPair : pRange) + { + if( rPair.first <= nId && nId <= rPair.second ) + return true; + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |