summaryrefslogtreecommitdiffstats
path: root/sw/source/core/attr
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sw/source/core/attr
parentInitial commit. (diff)
downloadlibreoffice-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.cxx381
-rw-r--r--sw/source/core/attr/cellatr.cxx226
-rw-r--r--sw/source/core/attr/fmtfollowtextflow.cxx30
-rw-r--r--sw/source/core/attr/fmtwrapinfluenceonobjpos.cxx174
-rw-r--r--sw/source/core/attr/format.cxx803
-rw-r--r--sw/source/core/attr/hints.cxx270
-rw-r--r--sw/source/core/attr/swatrset.cxx481
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: */