summaryrefslogtreecommitdiffstats
path: root/sw/source/core/docnode/section.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/docnode/section.cxx')
-rw-r--r--sw/source/core/docnode/section.cxx1594
1 files changed, 1594 insertions, 0 deletions
diff --git a/sw/source/core/docnode/section.cxx b/sw/source/core/docnode/section.cxx
new file mode 100644
index 000000000..c1f078429
--- /dev/null
+++ b/sw/source/core/docnode/section.cxx
@@ -0,0 +1,1594 @@
+/* -*- 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 <libxml/xmlstring.h>
+#include <libxml/xmlwriter.h>
+#include <stdlib.h>
+#include <hintids.hxx>
+#include <sot/exchange.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/docfile.hxx>
+#include <editeng/protitem.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <docary.hxx>
+#include <fmtcntnt.hxx>
+#include <fmtpdsc.hxx>
+#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <DocumentLinksAdministrationManager.hxx>
+#include <DocumentContentOperationsManager.hxx>
+#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentStylePoolAccess.hxx>
+#include <IDocumentState.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <node.hxx>
+#include <pam.hxx>
+#include <frmatr.hxx>
+#include <frmtool.hxx>
+#include <editsh.hxx>
+#include <hints.hxx>
+#include <docsh.hxx>
+#include <ndtxt.hxx>
+#include <section.hxx>
+#include <swserv.hxx>
+#include <shellio.hxx>
+#include <poolfmt.hxx>
+#include <swbaslnk.hxx>
+#include <mvsave.hxx>
+#include <fmtftntx.hxx>
+#include <ftnidx.hxx>
+#include <doctxm.hxx>
+#include <fmteiro.hxx>
+#include <unosection.hxx>
+#include <calbck.hxx>
+#include <fmtclds.hxx>
+#include <algorithm>
+#include "ndsect.hxx"
+
+using namespace ::com::sun::star;
+
+namespace {
+
+class SwIntrnlSectRefLink : public SwBaseLink
+{
+ SwSectionFormat& rSectFormat;
+public:
+ SwIntrnlSectRefLink( SwSectionFormat& rFormat, SfxLinkUpdateMode nUpdateType )
+ : SwBaseLink( nUpdateType, SotClipboardFormatId::RTF ),
+ rSectFormat( rFormat )
+ {}
+
+ virtual void Closed() override;
+ virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
+ const OUString& rMimeType, const css::uno::Any & rValue ) override;
+
+ virtual const SwNode* GetAnchor() const override;
+ virtual bool IsInRange( sal_uLong nSttNd, sal_uLong nEndNd ) const override;
+
+ SwSectionNode* GetSectNode()
+ {
+ const SwNode* pSectNd( GetAnchor() );
+ return const_cast<SwSectionNode*>( dynamic_cast<const SwSectionNode*>( pSectNd ) );
+ }
+};
+
+}
+
+SwSectionData::SwSectionData(SectionType const eType, OUString const& rName)
+ : m_eType(eType)
+ , m_sSectionName(rName)
+ , m_bHiddenFlag(false)
+ , m_bProtectFlag(false)
+ , m_bEditInReadonlyFlag(false) // edit in readonly sections
+ , m_bHidden(false)
+ , m_bCondHiddenFlag(true)
+ , m_bConnectFlag(true)
+{
+}
+
+// this must have the same semantics as operator=()
+SwSectionData::SwSectionData(SwSection const& rSection)
+ : m_eType(rSection.GetType())
+ , m_sSectionName(rSection.GetSectionName())
+ , m_sCondition(rSection.GetCondition())
+ , m_sLinkFileName(rSection.GetLinkFileName())
+ , m_sLinkFilePassword(rSection.GetLinkFilePassword())
+ , m_Password(rSection.GetPassword())
+ , m_bHiddenFlag(rSection.IsHiddenFlag())
+ , m_bProtectFlag(rSection.IsProtect())
+ // edit in readonly sections
+ , m_bEditInReadonlyFlag(rSection.IsEditInReadonly())
+ , m_bHidden(rSection.IsHidden())
+ , m_bCondHiddenFlag(true)
+ , m_bConnectFlag(rSection.IsConnectFlag())
+{
+}
+
+// this must have the same semantics as operator=()
+SwSectionData::SwSectionData(SwSectionData const& rOther)
+ : m_eType(rOther.m_eType)
+ , m_sSectionName(rOther.m_sSectionName)
+ , m_sCondition(rOther.m_sCondition)
+ , m_sLinkFileName(rOther.m_sLinkFileName)
+ , m_sLinkFilePassword(rOther.m_sLinkFilePassword)
+ , m_Password(rOther.m_Password)
+ , m_bHiddenFlag(rOther.m_bHiddenFlag)
+ , m_bProtectFlag(rOther.m_bProtectFlag)
+ // edit in readonly sections
+ , m_bEditInReadonlyFlag(rOther.m_bEditInReadonlyFlag)
+ , m_bHidden(rOther.m_bHidden)
+ , m_bCondHiddenFlag(true)
+ , m_bConnectFlag(rOther.m_bConnectFlag)
+{
+}
+
+// the semantics here are weird for reasons of backward compatibility
+SwSectionData & SwSectionData::operator= (SwSectionData const& rOther)
+{
+ m_eType = rOther.m_eType;
+ m_sSectionName = rOther.m_sSectionName;
+ m_sCondition = rOther.m_sCondition;
+ m_sLinkFileName = rOther.m_sLinkFileName;
+ m_sLinkFilePassword = rOther.m_sLinkFilePassword;
+ m_bConnectFlag = rOther.m_bConnectFlag;
+ m_Password = rOther.m_Password;
+
+ m_bEditInReadonlyFlag = rOther.m_bEditInReadonlyFlag;
+ m_bProtectFlag = rOther.m_bProtectFlag;
+
+ m_bHidden = rOther.m_bHidden;
+ // FIXME: old code did not assign m_bHiddenFlag ?
+ // FIXME: why should m_bCondHiddenFlag always default to true?
+ m_bCondHiddenFlag = true;
+
+ return *this;
+}
+
+// the semantics here are weird for reasons of backward compatibility
+bool SwSectionData::operator==(SwSectionData const& rOther) const
+{
+ return (m_eType == rOther.m_eType)
+ && (m_sSectionName == rOther.m_sSectionName)
+ && (m_sCondition == rOther.m_sCondition)
+ && (m_bHidden == rOther.m_bHidden)
+ && (m_bProtectFlag == rOther.m_bProtectFlag)
+ && (m_bEditInReadonlyFlag == rOther.m_bEditInReadonlyFlag)
+ && (m_sLinkFileName == rOther.m_sLinkFileName)
+ && (m_sLinkFilePassword == rOther.m_sLinkFilePassword)
+ && (m_Password == rOther.m_Password);
+ // FIXME: old code ignored m_bCondHiddenFlag m_bHiddenFlag m_bConnectFlag
+}
+
+OUString SwSectionData::CollapseWhiteSpaces(const OUString& sName)
+{
+ const sal_Int32 nLen = sName.getLength();
+ const sal_Unicode cRef = ' ';
+ OUStringBuffer aBuf(nLen+1);
+ for (sal_Int32 i = 0; i<nLen; )
+ {
+ const sal_Unicode cCur = sName[i++];
+ aBuf.append(cCur);
+ if (cCur!=cRef)
+ continue;
+ while (i<nLen && sName[i]==cRef)
+ ++i;
+ }
+ return aBuf.makeStringAndClear();
+}
+
+SwSection::SwSection(
+ SectionType const eType, OUString const& rName, SwSectionFormat & rFormat)
+ : SwClient(& rFormat)
+ , m_Data(eType, rName)
+{
+ SwSection *const pParentSect = GetParent();
+ if( pParentSect )
+ {
+ if( pParentSect->IsHiddenFlag() )
+ {
+ SetHidden();
+ }
+
+ m_Data.SetProtectFlag( pParentSect->IsProtectFlag() );
+ // edit in readonly sections
+ m_Data.SetEditInReadonlyFlag( pParentSect->IsEditInReadonlyFlag() );
+ }
+
+ if (!m_Data.IsProtectFlag())
+ {
+ m_Data.SetProtectFlag( rFormat.GetProtect().IsContentProtected() );
+ }
+
+ if (!m_Data.IsEditInReadonlyFlag()) // edit in readonly sections
+ {
+ m_Data.SetEditInReadonlyFlag( rFormat.GetEditInReadonly().GetValue() );
+ }
+}
+
+SwSection::~SwSection()
+{
+ SwSectionFormat* pFormat = GetFormat();
+ if( !pFormat )
+ return;
+
+ SwDoc* pDoc = pFormat->GetDoc();
+ if( pDoc->IsInDtor() )
+ {
+ // We reattach our Format to the default FrameFormat
+ // to not get any dependencies
+ if( pFormat->DerivedFrom() != pDoc->GetDfltFrameFormat() )
+ pFormat->RegisterToFormat( *pDoc->GetDfltFrameFormat() );
+ }
+ else
+ {
+ pFormat->Remove( this ); // remove
+
+ if (SectionType::Content != m_Data.GetType())
+ {
+ pDoc->getIDocumentLinksAdministration().GetLinkManager().Remove( m_RefLink.get() );
+ }
+
+ if (m_RefObj.is())
+ {
+ pDoc->getIDocumentLinksAdministration().GetLinkManager().RemoveServer( m_RefObj.get() );
+ }
+
+ // If the Section is the last Client in the Format we can delete it
+ SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, pFormat );
+ pFormat->ModifyNotification( &aMsgHint, &aMsgHint );
+ if( !pFormat->HasWriterListeners() )
+ {
+ // Do not add to the Undo. This should've happened earlier.
+ ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
+ pDoc->DelSectionFormat( pFormat );
+ }
+ }
+ if (m_RefObj.is())
+ {
+ m_RefObj->Closed();
+ }
+}
+
+void SwSection::SetSectionData(SwSectionData const& rData)
+{
+ bool const bOldHidden( m_Data.IsHidden() );
+ m_Data = rData;
+ // The next two may actually overwrite the m_Data.m_bProtect or EditInReadonly Flag
+ // in Modify, which should result in same flag value as the old code!
+ SetProtect(m_Data.IsProtectFlag());
+ SetEditInReadonly(m_Data.IsEditInReadonlyFlag());
+ if (bOldHidden != m_Data.IsHidden()) // check if changed...
+ {
+ ImplSetHiddenFlag(m_Data.IsHidden(), m_Data.IsCondHidden());
+ }
+}
+
+bool SwSection::DataEquals(SwSectionData const& rCmp) const
+{
+ // note that the old code compared the flags of the parameter with the
+ // format attributes of this; the following mess should do the same...
+ (void) GetLinkFileName(); // updates m_sLinkFileName
+ bool const bProtect(m_Data.IsProtectFlag());
+ bool const bEditInReadonly(m_Data.IsEditInReadonlyFlag());
+ m_Data.SetProtectFlag(IsProtect());
+ m_Data.SetEditInReadonlyFlag(IsEditInReadonly());
+ bool const bResult( m_Data == rCmp );
+ m_Data.SetProtectFlag(bProtect);
+ m_Data.SetEditInReadonlyFlag(bEditInReadonly);
+ return bResult;
+}
+
+void SwSection::ImplSetHiddenFlag(bool const bTmpHidden, bool const bCondition)
+{
+ SwSectionFormat* pFormat = GetFormat();
+ OSL_ENSURE(pFormat, "ImplSetHiddenFlag: no format?");
+ if( pFormat )
+ {
+ const bool bHide = bTmpHidden && bCondition;
+
+ if (bHide) // should be hidden
+ {
+ if (!m_Data.IsHiddenFlag()) // is not hidden
+ {
+ // Is the Parent hidden?
+ // This should be shown by the bHiddenFlag.
+
+ // Tell all Children that they are hidden
+ SwMsgPoolItem aMsgItem( RES_SECTION_HIDDEN );
+ pFormat->ModifyNotification( &aMsgItem, &aMsgItem );
+
+ // Delete all Frames
+ pFormat->DelFrames();
+ }
+ }
+ else if (m_Data.IsHiddenFlag()) // show Nodes again
+ {
+ // Show all Frames (Child Sections are accounted for by MakeFrames)
+ // Only if the Parent Section is not restricting us!
+ SwSection* pParentSect = pFormat->GetParentSection();
+ if( !pParentSect || !pParentSect->IsHiddenFlag() )
+ {
+ // Tell all Children that the Parent is not hidden anymore
+ SwMsgPoolItem aMsgItem( RES_SECTION_NOT_HIDDEN );
+ pFormat->ModifyNotification( &aMsgItem, &aMsgItem );
+
+ pFormat->MakeFrames();
+ }
+ }
+ }
+}
+
+bool SwSection::CalcHiddenFlag() const
+{
+ const SwSection* pSect = this;
+ do {
+ if( pSect->IsHidden() && pSect->IsCondHidden() )
+ return true;
+ } while( nullptr != ( pSect = pSect->GetParent()) );
+
+ return false;
+}
+
+bool SwSection::IsProtect() const
+{
+ SwSectionFormat const *const pFormat( GetFormat() );
+ OSL_ENSURE(pFormat, "SwSection::IsProtect: no format?");
+ return pFormat
+ ? pFormat->GetProtect().IsContentProtected()
+ : IsProtectFlag();
+}
+
+// edit in readonly sections
+bool SwSection::IsEditInReadonly() const
+{
+ SwSectionFormat const *const pFormat( GetFormat() );
+ OSL_ENSURE(pFormat, "SwSection::IsEditInReadonly: no format?");
+ return pFormat
+ ? pFormat->GetEditInReadonly().GetValue()
+ : IsEditInReadonlyFlag();
+}
+
+void SwSection::SetHidden(bool const bFlag)
+{
+ if (!m_Data.IsHidden() == !bFlag)
+ return;
+
+ m_Data.SetHidden(bFlag);
+ ImplSetHiddenFlag(bFlag, m_Data.IsCondHidden());
+}
+
+void SwSection::SetProtect(bool const bFlag)
+{
+ SwSectionFormat *const pFormat( GetFormat() );
+ OSL_ENSURE(pFormat, "SwSection::SetProtect: no format?");
+ if (pFormat)
+ {
+ SvxProtectItem aItem( RES_PROTECT );
+ aItem.SetContentProtect( bFlag );
+ pFormat->SetFormatAttr( aItem );
+ // note: this will call m_Data.SetProtectFlag via Modify!
+ }
+ else
+ {
+ m_Data.SetProtectFlag(bFlag);
+ }
+}
+
+// edit in readonly sections
+void SwSection::SetEditInReadonly(bool const bFlag)
+{
+ SwSectionFormat *const pFormat( GetFormat() );
+ OSL_ENSURE(pFormat, "SwSection::SetEditInReadonly: no format?");
+ if (pFormat)
+ {
+ SwFormatEditInReadonly aItem;
+ aItem.SetValue( bFlag );
+ pFormat->SetFormatAttr( aItem );
+ // note: this will call m_Data.SetEditInReadonlyFlag via Modify!
+ }
+ else
+ {
+ m_Data.SetEditInReadonlyFlag(bFlag);
+ }
+}
+
+void SwSection::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
+{
+ bool bUpdateFootnote = false;
+ switch( pOld ? pOld->Which() : pNew ? pNew->Which() : 0 )
+ {
+ case RES_ATTRSET_CHG:
+ if (pNew && pOld)
+ {
+ SfxItemSet* pNewSet = const_cast<SwAttrSetChg*>(static_cast<const SwAttrSetChg*>(pNew))->GetChgSet();
+ SfxItemSet* pOldSet = const_cast<SwAttrSetChg*>(static_cast<const SwAttrSetChg*>(pOld))->GetChgSet();
+ const SfxPoolItem* pItem;
+
+ if( SfxItemState::SET == pNewSet->GetItemState(
+ RES_PROTECT, false, &pItem ) )
+ {
+ m_Data.SetProtectFlag( static_cast<SvxProtectItem const*>(pItem)
+ ->IsContentProtected() );
+ pNewSet->ClearItem( RES_PROTECT );
+ pOldSet->ClearItem( RES_PROTECT );
+ }
+
+ // --> edit in readonly sections
+ if( SfxItemState::SET == pNewSet->GetItemState(
+ RES_EDIT_IN_READONLY, false, &pItem ) )
+ {
+ m_Data.SetEditInReadonlyFlag(
+ static_cast<SwFormatEditInReadonly const*>(pItem)->GetValue());
+ pNewSet->ClearItem( RES_EDIT_IN_READONLY );
+ pOldSet->ClearItem( RES_EDIT_IN_READONLY );
+ }
+
+ if( SfxItemState::SET == pNewSet->GetItemState(
+ RES_FTN_AT_TXTEND, false, &pItem ) ||
+ SfxItemState::SET == pNewSet->GetItemState(
+ RES_END_AT_TXTEND, false, &pItem ))
+ {
+ bUpdateFootnote = true;
+ }
+
+ if( !pNewSet->Count() )
+ return;
+ }
+ break;
+
+ case RES_PROTECT:
+ if( pNew )
+ {
+ bool bNewFlag =
+ static_cast<const SvxProtectItem*>(pNew)->IsContentProtected();
+ if( !bNewFlag )
+ {
+ // Switching off: See if there is protection transferred
+ // by the Parents
+ const SwSection* pSect = this;
+ do {
+ if( pSect->IsProtect() )
+ {
+ bNewFlag = true;
+ break;
+ }
+ pSect = pSect->GetParent();
+ } while (pSect);
+ }
+
+ m_Data.SetProtectFlag( bNewFlag );
+ }
+ return;
+ // edit in readonly sections
+ case RES_EDIT_IN_READONLY:
+ if( pNew )
+ {
+ const bool bNewFlag =
+ static_cast<const SwFormatEditInReadonly*>(pNew)->GetValue();
+ m_Data.SetEditInReadonlyFlag( bNewFlag );
+ }
+ return;
+
+ case RES_SECTION_HIDDEN:
+ m_Data.SetHiddenFlag(true);
+ return;
+
+ case RES_SECTION_NOT_HIDDEN:
+ m_Data.SetHiddenFlag( m_Data.IsHidden() && m_Data.IsCondHidden() );
+ return;
+
+ case RES_COL:
+ // Is handled by the Layout, if appropriate
+ break;
+
+ case RES_FTN_AT_TXTEND:
+ if( pNew && pOld )
+ {
+ bUpdateFootnote = true;
+ }
+ break;
+
+ case RES_END_AT_TXTEND:
+ if( pNew && pOld )
+ {
+ bUpdateFootnote = true;
+ }
+ break;
+
+ default:
+ CheckRegistration( pOld );
+ break;
+ }
+
+ if( bUpdateFootnote )
+ {
+ SwSectionNode* pSectNd = GetFormat()->GetSectionNode();
+ if( pSectNd )
+ pSectNd->GetDoc()->GetFootnoteIdxs().UpdateFootnote(SwNodeIndex( *pSectNd ));
+ }
+}
+
+void SwSection::SetRefObject( SwServerObject* pObj )
+{
+ m_RefObj = pObj;
+}
+
+void SwSection::SetCondHidden(bool const bFlag)
+{
+ if (!m_Data.IsCondHidden() == !bFlag)
+ return;
+
+ m_Data.SetCondHidden(bFlag);
+ ImplSetHiddenFlag(m_Data.IsHidden(), bFlag);
+}
+
+// Set/remove the linked FileName
+OUString const & SwSection::GetLinkFileName() const
+{
+ if (m_RefLink.is())
+ {
+ OUString sTmp;
+ switch (m_Data.GetType())
+ {
+ case SectionType::DdeLink:
+ sTmp = m_RefLink->GetLinkSourceName();
+ break;
+
+ case SectionType::FileLink:
+ {
+ OUString sRange;
+ OUString sFilter;
+ if (m_RefLink->GetLinkManager() &&
+ sfx2::LinkManager::GetDisplayNames(
+ m_RefLink.get(), nullptr, &sTmp, &sRange, &sFilter ))
+ {
+ sTmp += OUStringChar(sfx2::cTokenSeparator) + sFilter
+ + OUStringChar(sfx2::cTokenSeparator) + sRange;
+ }
+ else if( GetFormat() && !GetFormat()->GetSectionNode() )
+ {
+ // If the Section is in the UndoNodesArray, the LinkManager
+ // does not contain the Link, thus it cannot be queried for it.
+ // Thus return the current Name.
+ return m_Data.GetLinkFileName();
+ }
+ }
+ break;
+ default: break;
+ }
+ m_Data.SetLinkFileName(sTmp);
+ }
+ return m_Data.GetLinkFileName();
+}
+
+void SwSection::SetLinkFileName(const OUString& rNew)
+{
+ if (m_RefLink.is())
+ {
+ m_RefLink->SetLinkSourceName( rNew );
+ }
+ m_Data.SetLinkFileName(rNew);
+}
+
+// If it was a Linked Section, we need to make all Child Links visible
+void SwSection::MakeChildLinksVisible( const SwSectionNode& rSectNd )
+{
+ const SwNode* pNd;
+ const ::sfx2::SvBaseLinks& rLnks = rSectNd.GetDoc()->getIDocumentLinksAdministration().GetLinkManager().GetLinks();
+ for( auto n = rLnks.size(); n; )
+ {
+ sfx2::SvBaseLink& rBLnk = *rLnks[--n];
+ if (!rBLnk.IsVisible() && dynamic_cast<const SwBaseLink*>(&rBLnk) != nullptr
+ && nullptr != (pNd = static_cast<SwBaseLink&>(rBLnk).GetAnchor()))
+ {
+ pNd = pNd->StartOfSectionNode(); // If it's a SectionNode
+ const SwSectionNode* pParent;
+ while( nullptr != ( pParent = pNd->FindSectionNode() ) &&
+ ( SectionType::Content == pParent->GetSection().GetType()
+ || pNd == &rSectNd ))
+ pNd = pParent->StartOfSectionNode();
+
+ // It's within a normal Section, so show again
+ if( !pParent )
+ rBLnk.SetVisible(true);
+ }
+ }
+}
+
+const SwTOXBase* SwSection::GetTOXBase() const
+{
+ const SwTOXBase* pRet = nullptr;
+ if( SectionType::ToxContent == GetType() )
+ pRet = dynamic_cast<const SwTOXBaseSection*>(this);
+ return pRet;
+}
+
+SwSectionFormat::SwSectionFormat( SwFrameFormat* pDrvdFrame, SwDoc *pDoc )
+ : SwFrameFormat( pDoc->GetAttrPool(), OUString(), pDrvdFrame )
+{
+ LockModify();
+ SetFormatAttr( *GetDfltAttr( RES_COL ) );
+ UnlockModify();
+}
+
+SwSectionFormat::~SwSectionFormat()
+{
+ if( !GetDoc()->IsInDtor() )
+ {
+ SwSectionNode* pSectNd;
+ const SwNodeIndex* pIdx = GetContent( false ).GetContentIdx();
+ if( pIdx && &GetDoc()->GetNodes() == &pIdx->GetNodes() &&
+ nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
+ {
+ SwSection& rSect = pSectNd->GetSection();
+ // If it was a linked Section, we need to make all Child Links
+ // visible again
+ if( rSect.IsConnected() )
+ SwSection::MakeChildLinksVisible( *pSectNd );
+
+ // Check whether we need to be visible, before deleting the Nodes
+ if( rSect.IsHiddenFlag() )
+ {
+ SwSection* pParentSect = rSect.GetParent();
+ if( !pParentSect || !pParentSect->IsHiddenFlag() )
+ {
+ // Make Nodes visible again
+ rSect.SetHidden(false);
+ }
+ }
+ // mba: test iteration; objects are removed while iterating
+ // use hint which allows to specify, if the content shall be saved or not
+ CallSwClientNotify( SwSectionFrameMoveAndDeleteHint( true ) );
+
+ // Raise the Section up
+ SwNodeRange aRg( *pSectNd, 0, *pSectNd->EndOfSectionNode() );
+ GetDoc()->GetNodes().SectionUp( &aRg );
+ }
+ LockModify();
+ ResetFormatAttr( RES_CNTNT );
+ UnlockModify();
+ }
+}
+
+SwSection * SwSectionFormat::GetSection() const
+{
+ return SwIterator<SwSection,SwSectionFormat>( *this ).First();
+}
+
+// Do not destroy all Frames in aDepend (Frames are recognized with a dynamic_cast).
+void SwSectionFormat::DelFrames()
+{
+ SwSectionNode* pSectNd;
+ const SwNodeIndex* pIdx = GetContent(false).GetContentIdx();
+ if( pIdx && &GetDoc()->GetNodes() == &pIdx->GetNodes() &&
+ nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
+ {
+ // First delete the <SwSectionFrame> of the <SwSectionFormat> instance
+ // mba: test iteration as objects are removed in iteration
+ // use hint which allows to specify, if the content shall be saved or not
+ CallSwClientNotify( SwSectionFrameMoveAndDeleteHint( false ) );
+
+ // Then delete frames of the nested <SwSectionFormat> instances
+ SwIterator<SwSectionFormat,SwSectionFormat> aIter( *this );
+ SwSectionFormat *pLast = aIter.First();
+ while ( pLast )
+ {
+ pLast->DelFrames();
+ pLast = aIter.Next();
+ }
+
+ sal_uLong nEnd = pSectNd->EndOfSectionIndex();
+ sal_uLong nStart = pSectNd->GetIndex()+1;
+ sw_DeleteFootnote( pSectNd, nStart, nEnd );
+ }
+ if( pIdx )
+ {
+ // Send Hint for PageDesc. Actually the Layout contained in the
+ // Paste of the Frame itself would need to do this. But that leads
+ // to subsequent errors, which we'd need to solve at run-time.
+ SwNodeIndex aNextNd( *pIdx );
+ SwContentNode* pCNd = GetDoc()->GetNodes().GoNextSection( &aNextNd, true, false );
+ if( pCNd )
+ {
+ const SfxPoolItem& rItem = pCNd->GetSwAttrSet().Get( RES_PAGEDESC );
+ pCNd->ModifyNotification( &rItem, &rItem );
+ }
+ }
+}
+
+// Create the Views
+void SwSectionFormat::MakeFrames()
+{
+ SwSectionNode* pSectNd;
+ const SwNodeIndex* pIdx = GetContent(false).GetContentIdx();
+
+ if( pIdx && &GetDoc()->GetNodes() == &pIdx->GetNodes() &&
+ nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
+ {
+ SwNodeIndex aIdx( *pIdx );
+ pSectNd->MakeOwnFrames( &aIdx );
+ }
+}
+
+void SwSectionFormat::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
+{
+ bool bClients = false;
+ sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
+ switch( nWhich )
+ {
+ case RES_ATTRSET_CHG:
+ if (HasWriterListeners() && pOld && pNew)
+ {
+ SfxItemSet* pNewSet = const_cast<SwAttrSetChg*>(static_cast<const SwAttrSetChg*>(pNew))->GetChgSet();
+ SfxItemSet* pOldSet = const_cast<SwAttrSetChg*>(static_cast<const SwAttrSetChg*>(pOld))->GetChgSet();
+ const SfxPoolItem *pItem;
+ if( SfxItemState::SET == pNewSet->GetItemState(
+ RES_PROTECT, false, &pItem ))
+ {
+ ModifyBroadcast( pItem, pItem );
+ pNewSet->ClearItem( RES_PROTECT );
+ pOldSet->ClearItem( RES_PROTECT );
+ }
+
+ // --> edit in readonly sections
+ if( SfxItemState::SET == pNewSet->GetItemState(
+ RES_EDIT_IN_READONLY, false, &pItem ) )
+ {
+ ModifyBroadcast( pItem, pItem );
+ pNewSet->ClearItem( RES_EDIT_IN_READONLY );
+ pOldSet->ClearItem( RES_EDIT_IN_READONLY );
+ }
+
+ if( SfxItemState::SET == pNewSet->GetItemState(
+ RES_FTN_AT_TXTEND, false, &pItem ))
+ {
+ ModifyBroadcast( &pOldSet->Get( RES_FTN_AT_TXTEND ), pItem );
+ pNewSet->ClearItem( RES_FTN_AT_TXTEND );
+ pOldSet->ClearItem( RES_FTN_AT_TXTEND );
+ }
+ if( SfxItemState::SET == pNewSet->GetItemState(
+ RES_END_AT_TXTEND, false, &pItem ))
+ {
+ ModifyBroadcast( &pOldSet->Get( RES_END_AT_TXTEND ), pItem );
+ pNewSet->ClearItem( RES_END_AT_TXTEND );
+ pOldSet->ClearItem( RES_END_AT_TXTEND );
+ }
+ if( !static_cast<const SwAttrSetChg*>(pOld)->GetChgSet()->Count() )
+ return;
+ }
+ break;
+
+ case RES_FTN_AT_TXTEND:
+ case RES_END_AT_TXTEND : bClients = true;
+ [[fallthrough]];
+ case RES_SECTION_HIDDEN:
+ case RES_SECTION_NOT_HIDDEN:
+ {
+ SwSection* pSect = GetSection();
+ if( pSect && ( bClients || ( RES_SECTION_HIDDEN == nWhich ?
+ !pSect->IsHiddenFlag() : pSect->IsHiddenFlag() ) ) )
+ {
+ ModifyBroadcast( pOld, pNew );
+ }
+ }
+ return ;
+
+ case RES_PROTECT:
+ case RES_EDIT_IN_READONLY: // edit in readonly sections
+ // Pass through these Messages until the End of the tree!
+ if( HasWriterListeners() )
+ {
+ ModifyBroadcast( pOld, pNew );
+ }
+ return; // That's it!
+
+ case RES_OBJECTDYING:
+ if( !GetDoc()->IsInDtor() && pOld &&
+ static_cast<const SwPtrMsgPoolItem *>(pOld)->pObject == static_cast<void*>(GetRegisteredIn()) )
+ {
+ // My Parents will be destroyed, so get the Parent's Parent
+ // and update
+ SwFrameFormat::Modify( pOld, pNew ); // Rewire first!
+ UpdateParent();
+ return;
+ }
+ break;
+
+ case RES_FMT_CHG:
+ if( !GetDoc()->IsInDtor() &&
+ static_cast<const SwFormatChg*>(pNew)->pChangedFormat == static_cast<void*>(GetRegisteredIn()) &&
+ dynamic_cast<const SwSectionFormat*>(static_cast<const SwFormatChg*>(pNew)->pChangedFormat) != nullptr )
+ {
+ // My Parent will be changed, thus I need to update
+ SwFrameFormat::Modify( pOld, pNew ); // Rewire first!
+ UpdateParent();
+ return;
+ }
+ break;
+ }
+ SwFrameFormat::Modify( pOld, pNew );
+
+ if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
+ { // invalidate cached uno object
+ SetXTextSection(uno::Reference<text::XTextSection>(nullptr));
+ }
+}
+
+// Get info from the Format
+bool SwSectionFormat::GetInfo( SfxPoolItem& rInfo ) const
+{
+ switch( rInfo.Which() )
+ {
+ case RES_FINDNEARESTNODE:
+ if( GetFormatAttr( RES_PAGEDESC ).GetPageDesc() )
+ {
+ const SwSectionNode* pNd = GetSectionNode();
+ if( pNd )
+ static_cast<SwFindNearestNode&>(rInfo).CheckNode( *pNd );
+ }
+ return true;
+
+ case RES_CONTENT_VISIBLE:
+ {
+ SwFrame* pFrame = SwIterator<SwFrame,SwFormat>(*this).First();
+ // if the current section has no own frame search for the children
+ if(!pFrame)
+ {
+ SwIterator<SwSectionFormat,SwSectionFormat> aFormatIter(*this);
+ SwSectionFormat* pChild = aFormatIter.First();
+ while(pChild && !pFrame)
+ {
+ pFrame = SwIterator<SwFrame,SwFormat>(*pChild).First();
+ pChild = aFormatIter.Next();
+ }
+ }
+ static_cast<SwPtrMsgPoolItem&>(rInfo).pObject = pFrame;
+ }
+ return false;
+ }
+ return SwModify::GetInfo( rInfo );
+}
+
+static bool lcl_SectionCmpPos( const SwSection *pFirst, const SwSection *pSecond)
+{
+ const SwSectionFormat* pFSectFormat = pFirst->GetFormat();
+ const SwSectionFormat* pSSectFormat = pSecond->GetFormat();
+ OSL_ENSURE( pFSectFormat && pSSectFormat &&
+ pFSectFormat->GetContent(false).GetContentIdx() &&
+ pSSectFormat->GetContent(false).GetContentIdx(),
+ "Invalid sections" );
+ return pFSectFormat->GetContent(false).GetContentIdx()->GetIndex() <
+ pSSectFormat->GetContent(false).GetContentIdx()->GetIndex();
+}
+
+// get all Sections that have been derived from this one
+void SwSectionFormat::GetChildSections( SwSections& rArr,
+ SectionSort eSort,
+ bool bAllSections ) const
+{
+ rArr.clear();
+
+ if( HasWriterListeners() )
+ {
+ SwIterator<SwSectionFormat,SwSectionFormat> aIter(*this);
+ const SwNodeIndex* pIdx;
+ for( SwSectionFormat* pLast = aIter.First(); pLast; pLast = aIter.Next() )
+ if( bAllSections ||
+ ( nullptr != ( pIdx = pLast->GetContent(false).
+ GetContentIdx()) && &pIdx->GetNodes() == &GetDoc()->GetNodes() ))
+ {
+ SwSection* pDummy = pLast->GetSection();
+ rArr.push_back( pDummy );
+ }
+
+ // Do we need any sorting?
+ if( 1 < rArr.size() )
+ switch( eSort )
+ {
+ case SectionSort::Pos:
+ std::sort( rArr.begin(), rArr.end(), lcl_SectionCmpPos );
+ break;
+ case SectionSort::Not: break;
+ }
+ }
+}
+
+// See whether the Section is within the Nodes or the UndoNodes array
+bool SwSectionFormat::IsInNodesArr() const
+{
+ const SwNodeIndex* pIdx = GetContent(false).GetContentIdx();
+ return pIdx && &pIdx->GetNodes() == &GetDoc()->GetNodes();
+}
+
+// Parent was changed
+void SwSectionFormat::UpdateParent()
+{
+ if( !HasWriterListeners() )
+ return;
+
+ SwSection* pSection = nullptr;
+ const SvxProtectItem* pProtect(nullptr);
+ // edit in readonly sections
+ const SwFormatEditInReadonly* pEditInReadonly = nullptr;
+ bool bIsHidden = false;
+
+ SwIterator<SwClient,SwSectionFormat> aIter(*this);
+ for(SwClient* pLast = aIter.First(); pLast; pLast = aIter.Next())
+ {
+ if( dynamic_cast<const SwSectionFormat*>(pLast) != nullptr )
+ {
+ if( !pSection )
+ {
+ pSection = GetSection();
+ if( GetRegisteredIn() )
+ {
+ const SwSection* pPS = GetParentSection();
+ pProtect = &pPS->GetFormat()->GetProtect();
+ // edit in readonly sections
+ pEditInReadonly = &pPS->GetFormat()->GetEditInReadonly();
+ bIsHidden = pPS->IsHiddenFlag();
+ }
+ else
+ {
+ pProtect = &GetProtect();
+ // edit in readonly sections
+ pEditInReadonly = &GetEditInReadonly();
+ bIsHidden = pSection->IsHidden();
+ }
+ }
+ if (!pProtect->IsContentProtected() !=
+ !pSection->IsProtectFlag())
+ {
+ pLast->ModifyNotification( static_cast<SfxPoolItem const *>(pProtect),
+ static_cast<SfxPoolItem const *>(pProtect) );
+ }
+
+ // edit in readonly sections
+ if (!pEditInReadonly->GetValue() !=
+ !pSection->IsEditInReadonlyFlag())
+ {
+ pLast->ModifyNotification( static_cast<SfxPoolItem const *>(pEditInReadonly),
+ static_cast<SfxPoolItem const *>(pEditInReadonly) );
+ }
+
+ if( bIsHidden == pSection->IsHiddenFlag() )
+ {
+ SwMsgPoolItem aMsgItem( static_cast<sal_uInt16>(bIsHidden
+ ? RES_SECTION_HIDDEN
+ : RES_SECTION_NOT_HIDDEN ) );
+ pLast->ModifyNotification( &aMsgItem, &aMsgItem );
+ }
+ }
+ else if( !pSection &&
+ dynamic_cast<const SwSection*>(pLast) != nullptr )
+ {
+ pSection = static_cast<SwSection*>(pLast);
+ if( GetRegisteredIn() )
+ {
+ const SwSection* pPS = GetParentSection();
+ pProtect = &pPS->GetFormat()->GetProtect();
+ // edit in readonly sections
+ pEditInReadonly = &pPS->GetFormat()->GetEditInReadonly();
+ bIsHidden = pPS->IsHiddenFlag();
+ }
+ else
+ {
+ pProtect = &GetProtect();
+ // edit in readonly sections
+ pEditInReadonly = &GetEditInReadonly();
+ bIsHidden = pSection->IsHidden();
+ }
+ }
+ }
+}
+
+SwSectionNode* SwSectionFormat::GetSectionNode()
+{
+ const SwNodeIndex* pIdx = GetContent(false).GetContentIdx();
+ if( pIdx && ( &pIdx->GetNodes() == &GetDoc()->GetNodes() ))
+ return pIdx->GetNode().GetSectionNode();
+ return nullptr;
+}
+
+// Is this Section valid for the GlobalDocument?
+const SwSection* SwSectionFormat::GetGlobalDocSection() const
+{
+ const SwSectionNode* pNd = GetSectionNode();
+ if( pNd &&
+ ( SectionType::FileLink == pNd->GetSection().GetType() ||
+ SectionType::ToxContent == pNd->GetSection().GetType() ) &&
+ pNd->GetIndex() > pNd->GetNodes().GetEndOfExtras().GetIndex() &&
+ !pNd->StartOfSectionNode()->IsSectionNode() &&
+ !pNd->StartOfSectionNode()->FindSectionNode() )
+ return &pNd->GetSection();
+ return nullptr;
+}
+
+// sw::Metadatable
+::sfx2::IXmlIdRegistry& SwSectionFormat::GetRegistry()
+{
+ return GetDoc()->GetXmlIdRegistry();
+}
+
+bool SwSectionFormat::IsInClipboard() const
+{
+ return GetDoc()->IsClipBoard();
+}
+
+bool SwSectionFormat::IsInUndo() const
+{
+ return !IsInNodesArr();
+}
+
+bool SwSectionFormat::IsInContent() const
+{
+ SwNodeIndex const*const pIdx = GetContent(false).GetContentIdx();
+ OSL_ENSURE(pIdx, "SwSectionFormat::IsInContent: no index?");
+ return pIdx == nullptr || !GetDoc()->IsInHeaderFooter(*pIdx);
+}
+
+// n.b.: if the section format represents an index, then there is both a
+// SwXDocumentIndex and a SwXTextSection instance for this single core object.
+// these two can both implement XMetadatable and forward to the same core
+// section format. but here only one UNO object can be returned,
+// so always return the text section.
+uno::Reference< rdf::XMetadatable >
+SwSectionFormat::MakeUnoObject()
+{
+ uno::Reference<rdf::XMetadatable> xMeta;
+ SwSection *const pSection( GetSection() );
+ if (pSection)
+ {
+ xMeta.set( SwXTextSection::CreateXTextSection(this,
+ SectionType::ToxHeader == pSection->GetType()),
+ uno::UNO_QUERY );
+ }
+ return xMeta;
+}
+
+bool SwSectionFormat::supportsFullDrawingLayerFillAttributeSet() const
+{
+ return false;
+}
+
+void SwSectionFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ xmlTextWriterStartElement(pWriter, BAD_CAST("SwSectionFormat"));
+ xmlTextWriterWriteAttribute(pWriter, BAD_CAST("name"), BAD_CAST(GetName().toUtf8().getStr()));
+ GetAttrSet().dumpAsXml(pWriter);
+ xmlTextWriterEndElement(pWriter);
+}
+
+void SwSectionFormats::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ xmlTextWriterStartElement(pWriter, BAD_CAST("SwSectionFormats"));
+ for (size_t i = 0; i < size(); ++i)
+ GetFormat(i)->dumpAsXml(pWriter);
+ xmlTextWriterEndElement(pWriter);
+}
+
+// Method to break section links inside a linked section
+static void lcl_BreakSectionLinksInSect( const SwSectionNode& rSectNd )
+{
+ if ( !rSectNd.GetDoc() )
+ {
+ OSL_FAIL( "method <lcl_RemoveSectionLinksInSect(..)> - no Doc at SectionNode" );
+ return;
+ }
+
+ if ( !rSectNd.GetSection().IsConnected() )
+ {
+ OSL_FAIL( "method <lcl_RemoveSectionLinksInSect(..)> - no Link at Section of SectionNode" );
+ return;
+ }
+ const ::sfx2::SvBaseLink* pOwnLink( &(rSectNd.GetSection().GetBaseLink() ) );
+ const ::sfx2::SvBaseLinks& rLnks = rSectNd.GetDoc()->getIDocumentLinksAdministration().GetLinkManager().GetLinks();
+ for ( auto n = rLnks.size(); n > 0; )
+ {
+ SwIntrnlSectRefLink* pSectLnk = dynamic_cast<SwIntrnlSectRefLink*>(&(*rLnks[ --n ]));
+ if ( pSectLnk && pSectLnk != pOwnLink &&
+ pSectLnk->IsInRange( rSectNd.GetIndex(), rSectNd.EndOfSectionIndex() ) )
+ {
+ // break the link of the corresponding section.
+ // the link is also removed from the link manager
+ SwSectionNode* pSectNode = pSectLnk->GetSectNode();
+ assert(pSectNode);
+ pSectNode->GetSection().BreakLink();
+
+ // for robustness, because link is removed from the link manager
+ if ( n > rLnks.size() )
+ {
+ n = rLnks.size();
+ }
+ }
+ }
+}
+
+static void lcl_UpdateLinksInSect( SwBaseLink& rUpdLnk, SwSectionNode& rSectNd )
+{
+ SwDoc* pDoc = rSectNd.GetDoc();
+ SwDocShell* pDShell = pDoc->GetDocShell();
+ if( !pDShell || !pDShell->GetMedium() )
+ return ;
+
+ const OUString sName( pDShell->GetMedium()->GetName() );
+ const OUString sMimeType( SotExchange::GetFormatMimeType( SotClipboardFormatId::SIMPLE_FILE ));
+ uno::Any aValue;
+ aValue <<= sName; // Arbitrary name
+
+ const ::sfx2::SvBaseLinks& rLnks = pDoc->getIDocumentLinksAdministration().GetLinkManager().GetLinks();
+ for( auto n = rLnks.size(); n; )
+ {
+ SwBaseLink* pBLink;
+
+ ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]);
+ if( pLnk != &rUpdLnk &&
+ sfx2::SvBaseLinkObjectType::ClientFile == pLnk->GetObjType() &&
+ dynamic_cast< const SwBaseLink *>( pLnk ) != nullptr &&
+ ( pBLink = static_cast<SwBaseLink*>(pLnk) )->IsInRange( rSectNd.GetIndex(),
+ rSectNd.EndOfSectionIndex() ) )
+ {
+ // It's in the Section, so update. But only if it's not in the same File!
+ OUString sFName;
+ sfx2::LinkManager::GetDisplayNames( pBLink, nullptr, &sFName );
+ if( sFName != sName )
+ {
+ pBLink->DataChanged( sMimeType, aValue );
+
+ // If needed find the Link pointer to avoid skipping one or calling one twice
+ if( n >= rLnks.size() && 0 != ( n = rLnks.size() ))
+ --n;
+
+ if( n && pLnk != &(*rLnks[ n ]) )
+ {
+ // Find - it can only precede it!
+ while( n )
+ if( pLnk == &(*rLnks[ --n ] ) )
+ break;
+ }
+ }
+ }
+ }
+}
+
+::sfx2::SvBaseLink::UpdateResult SwIntrnlSectRefLink::DataChanged(
+ const OUString& rMimeType, const uno::Any & rValue )
+{
+ SwSectionNode* pSectNd = rSectFormat.GetSectionNode();
+ SwDoc* pDoc = rSectFormat.GetDoc();
+
+ SotClipboardFormatId nDataFormat = SotExchange::GetFormatIdFromMimeType( rMimeType );
+
+ if( !pSectNd || !pDoc || pDoc->IsInDtor() || ChkNoDataFlag() ||
+ sfx2::LinkManager::RegisterStatusInfoId() == nDataFormat )
+ {
+ // Should we be in the Undo already?
+ return SUCCESS;
+ }
+
+ // #i38810# - Due to possible existing signatures, the
+ // document has to be modified after updating a link.
+ pDoc->getIDocumentState().SetModified();
+ // set additional flag that links have been updated, in order to check this
+ // during load.
+ pDoc->getIDocumentLinksAdministration().SetLinksUpdated( true );
+
+ // Always switch off Undo
+ bool const bWasUndo = pDoc->GetIDocumentUndoRedo().DoesUndo();
+ pDoc->GetIDocumentUndoRedo().DoUndo(false);
+ bool bWasVisibleLinks = pDoc->getIDocumentLinksAdministration().IsVisibleLinks();
+ pDoc->getIDocumentLinksAdministration().SetVisibleLinks( false );
+
+ SwPaM* pPam;
+ SwViewShell* pVSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
+ SwEditShell* pESh = pDoc->GetEditShell();
+ pDoc->getIDocumentFieldsAccess().LockExpFields();
+ {
+ // Insert an empty TextNode at the Section's start
+ SwNodeIndex aIdx( *pSectNd, +1 );
+ SwNodeIndex aEndIdx( *pSectNd->EndOfSectionNode() );
+ SwTextNode* pNewNd = pDoc->GetNodes().MakeTextNode( aIdx,
+ pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ) );
+
+ if( pESh )
+ pESh->StartAllAction();
+ else if( pVSh )
+ pVSh->StartAction();
+
+ SwPosition aPos( aIdx, SwIndex( pNewNd, 0 ));
+ --aPos.nNode;
+ SwDoc::CorrAbs( aIdx, aEndIdx, aPos, true );
+
+ pPam = new SwPaM( aPos );
+
+ // Delete everything succeeding it
+ --aIdx;
+ DelFlyInRange( aIdx, aEndIdx );
+ DelBookmarks(aIdx, aEndIdx);
+ ++aIdx;
+
+ pDoc->GetNodes().Delete( aIdx, aEndIdx.GetIndex() - aIdx.GetIndex() );
+ }
+
+ SwSection& rSection = pSectNd->GetSection();
+ rSection.SetConnectFlag(false);
+
+ Reader* pRead = nullptr;
+ switch( nDataFormat )
+ {
+ case SotClipboardFormatId::STRING:
+ pRead = ReadAscii;
+ break;
+
+ case SotClipboardFormatId::RICHTEXT:
+ case SotClipboardFormatId::RTF:
+ pRead = SwReaderWriter::GetRtfReader();
+ break;
+
+ case SotClipboardFormatId::SIMPLE_FILE:
+ if ( rValue.hasValue() )
+ {
+ OUString sFileName;
+ if ( !(rValue >>= sFileName) )
+ break;
+ OUString sFilter;
+ OUString sRange;
+ sfx2::LinkManager::GetDisplayNames( this, nullptr, &sFileName,
+ &sRange, &sFilter );
+
+ RedlineFlags eOldRedlineFlags = RedlineFlags::NONE;
+ SfxObjectShellRef xDocSh;
+ SfxObjectShellLock xLockRef;
+ int nRet;
+ if( sFileName.isEmpty() )
+ {
+ xDocSh = pDoc->GetDocShell();
+ nRet = 1;
+ }
+ else
+ {
+ nRet = SwFindDocShell( xDocSh, xLockRef, sFileName,
+ rSection.GetLinkFilePassword(),
+ sFilter, 0, pDoc->GetDocShell() );
+ if( nRet )
+ {
+ SwDoc* pSrcDoc = static_cast<SwDocShell*>( xDocSh.get() )->GetDoc();
+ eOldRedlineFlags = pSrcDoc->getIDocumentRedlineAccess().GetRedlineFlags();
+ pSrcDoc->getIDocumentRedlineAccess().SetRedlineFlags( RedlineFlags::ShowInsert );
+ }
+ }
+
+ if( nRet )
+ {
+ rSection.SetConnectFlag();
+
+ SwNodeIndex aSave( pPam->GetPoint()->nNode, -1 );
+ std::unique_ptr<SwNodeRange> pCpyRg;
+
+ if( xDocSh->GetMedium() &&
+ rSection.GetLinkFilePassword().isEmpty() )
+ {
+ const SfxPoolItem* pItem;
+ if( SfxItemState::SET == xDocSh->GetMedium()->GetItemSet()->
+ GetItemState( SID_PASSWORD, false, &pItem ) )
+ rSection.SetLinkFilePassword(
+ static_cast<const SfxStringItem*>(pItem)->GetValue() );
+ }
+
+ SwDoc* pSrcDoc = static_cast<SwDocShell*>( xDocSh.get() )->GetDoc();
+
+ if( !sRange.isEmpty() )
+ {
+ // Catch recursion
+ bool bRecursion = false;
+ if( pSrcDoc == pDoc )
+ {
+ tools::SvRef<SwServerObject> refObj( static_cast<SwServerObject*>(
+ pDoc->getIDocumentLinksAdministration().CreateLinkSource( sRange )));
+ if( refObj.is() )
+ {
+ bRecursion = refObj->IsLinkInServer( this ) ||
+ ChkNoDataFlag();
+ }
+ }
+
+ SwNodeIndex& rInsPos = pPam->GetPoint()->nNode;
+
+ SwPaM* pCpyPam = nullptr;
+ if( !bRecursion &&
+ pSrcDoc->GetDocumentLinksAdministrationManager().SelectServerObj( sRange, pCpyPam, pCpyRg )
+ && pCpyPam )
+ {
+ if( pSrcDoc != pDoc ||
+ pCpyPam->Start()->nNode > rInsPos ||
+ rInsPos >= pCpyPam->End()->nNode )
+ {
+ pSrcDoc->getIDocumentContentOperations().CopyRange(*pCpyPam, *pPam->GetPoint(), SwCopyFlags::CheckPosInFly);
+ }
+ delete pCpyPam;
+ }
+ if( pCpyRg && pSrcDoc == pDoc &&
+ pCpyRg->aStart < rInsPos && rInsPos < pCpyRg->aEnd )
+ {
+ pCpyRg.reset();
+ }
+ }
+ else if( pSrcDoc != pDoc )
+ pCpyRg.reset(new SwNodeRange( pSrcDoc->GetNodes().GetEndOfExtras(), 2,
+ pSrcDoc->GetNodes().GetEndOfContent() ));
+
+ // #i81653#
+ // Update links of extern linked document or extern linked
+ // document section, if section is protected.
+ if ( pSrcDoc != pDoc &&
+ rSection.IsProtectFlag() )
+ {
+ pSrcDoc->getIDocumentLinksAdministration().GetLinkManager().UpdateAllLinks( false, false, nullptr );
+ }
+
+ if( pCpyRg )
+ {
+ SwNodeIndex& rInsPos = pPam->GetPoint()->nNode;
+ bool bCreateFrame = rInsPos.GetIndex() <=
+ pDoc->GetNodes().GetEndOfExtras().GetIndex() ||
+ rInsPos.GetNode().FindTableNode();
+
+ SwTableNumFormatMerge aTNFM( *pSrcDoc, *pDoc );
+
+ pSrcDoc->GetDocumentContentOperationsManager().CopyWithFlyInFly(*pCpyRg, rInsPos, nullptr, bCreateFrame);
+ ++aSave;
+
+ if( !bCreateFrame )
+ ::MakeFrames( pDoc, aSave, rInsPos );
+
+ // Delete last Node, only if it was copied successfully
+ // (the Section contains more than one Node)
+ if( 2 < pSectNd->EndOfSectionIndex() - pSectNd->GetIndex() )
+ {
+ aSave = rInsPos;
+ pPam->Move( fnMoveBackward, GoInNode );
+ pPam->SetMark(); // Rewire both SwPositions
+
+ pDoc->CorrAbs( aSave, *pPam->GetPoint(), 0, true );
+ pDoc->GetNodes().Delete( aSave );
+ }
+ pCpyRg.reset();
+ }
+
+ lcl_BreakSectionLinksInSect( *pSectNd );
+
+ // Update all Links in this Section
+ lcl_UpdateLinksInSect( *this, *pSectNd );
+ }
+ if( xDocSh.is() )
+ {
+ if( 2 == nRet )
+ xDocSh->DoClose();
+ else if( static_cast<SwDocShell*>( xDocSh.get() )->GetDoc() )
+ static_cast<SwDocShell*>( xDocSh.get() )->GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags(
+ eOldRedlineFlags );
+ }
+ }
+ break;
+ default: break;
+ }
+
+ // Only create DDE if Shell is available!
+ uno::Sequence< sal_Int8 > aSeq;
+ if( pRead && rValue.hasValue() && ( rValue >>= aSeq ) )
+ {
+ if( pESh )
+ {
+ pESh->Push();
+ SwPaM* pCursor = pESh->GetCursor();
+ *pCursor->GetPoint() = *pPam->GetPoint();
+ delete pPam;
+ pPam = pCursor;
+ }
+
+ SvMemoryStream aStrm( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(),
+ StreamMode::READ );
+ aStrm.Seek( 0 );
+
+ // TODO/MBA: it's impossible to set a BaseURL here!
+ SwReader aTmpReader( aStrm, OUString(), pDoc->GetDocShell()->GetMedium()->GetBaseURL(), *pPam );
+
+ if( ! aTmpReader.Read( *pRead ).IsError() )
+ {
+ rSection.SetConnectFlag();
+ }
+
+ if( pESh )
+ {
+ pESh->Pop(SwCursorShell::PopMode::DeleteCurrent);
+ pPam = nullptr; // pam was deleted earlier
+ }
+ }
+
+ // remove all undo actions and turn undo on again
+ pDoc->GetIDocumentUndoRedo().DelAllUndoObj();
+ pDoc->GetIDocumentUndoRedo().DoUndo(bWasUndo);
+ pDoc->getIDocumentLinksAdministration().SetVisibleLinks( bWasVisibleLinks );
+
+ pDoc->getIDocumentFieldsAccess().UnlockExpFields();
+ if( !pDoc->getIDocumentFieldsAccess().IsExpFieldsLocked() )
+ pDoc->getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
+
+ if( pESh )
+ pESh->EndAllAction();
+ else if( pVSh )
+ pVSh->EndAction();
+ delete pPam; // Was created at the start
+
+ return SUCCESS;
+}
+
+void SwIntrnlSectRefLink::Closed()
+{
+ SwDoc* pDoc = rSectFormat.GetDoc();
+ if( pDoc && !pDoc->IsInDtor() )
+ {
+ // Advise says goodbye: mark the Section as not protected
+ // and change the Flag
+ const SwSectionFormats& rFormats = pDoc->GetSections();
+ for( auto n = rFormats.size(); n; )
+ if( rFormats[ --n ] == &rSectFormat )
+ {
+ SwViewShell* pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
+ SwEditShell* pESh = pDoc->GetEditShell();
+
+ if( pESh )
+ pESh->StartAllAction();
+ else
+ pSh->StartAction();
+
+ SwSectionData aSectionData(*rSectFormat.GetSection());
+ aSectionData.SetType( SectionType::Content );
+ aSectionData.SetLinkFileName( OUString() );
+ aSectionData.SetProtectFlag( false );
+ // edit in readonly sections
+ aSectionData.SetEditInReadonlyFlag( false );
+
+ aSectionData.SetConnectFlag( false );
+
+ pDoc->UpdateSection( n, aSectionData );
+
+ // Make all Links within the Section visible again
+ SwSectionNode* pSectNd = rSectFormat.GetSectionNode();
+ if( pSectNd )
+ SwSection::MakeChildLinksVisible( *pSectNd );
+
+ if( pESh )
+ pESh->EndAllAction();
+ else
+ pSh->EndAction();
+ break;
+ }
+ }
+ SvBaseLink::Closed();
+}
+
+void SwSection::CreateLink( LinkCreateType eCreateType )
+{
+ SwSectionFormat* pFormat = GetFormat();
+ OSL_ENSURE(pFormat, "SwSection::CreateLink: no format?");
+ if (!pFormat || (SectionType::Content == m_Data.GetType()))
+ return ;
+
+ SfxLinkUpdateMode nUpdateType = SfxLinkUpdateMode::ALWAYS;
+
+ if (!m_RefLink.is())
+ {
+ // create BaseLink
+ m_RefLink = new SwIntrnlSectRefLink( *pFormat, nUpdateType );
+ }
+ else
+ {
+ pFormat->GetDoc()->getIDocumentLinksAdministration().GetLinkManager().Remove( m_RefLink.get() );
+ }
+
+ SwIntrnlSectRefLink *const pLnk =
+ static_cast<SwIntrnlSectRefLink*>( m_RefLink.get() );
+
+ const OUString sCmd(SwSectionData::CollapseWhiteSpaces(m_Data.GetLinkFileName()));
+ pLnk->SetUpdateMode( nUpdateType );
+ pLnk->SetVisible( pFormat->GetDoc()->getIDocumentLinksAdministration().IsVisibleLinks() );
+
+ switch (m_Data.GetType())
+ {
+ case SectionType::DdeLink:
+ pLnk->SetLinkSourceName( sCmd );
+ pFormat->GetDoc()->getIDocumentLinksAdministration().GetLinkManager().InsertDDELink( pLnk );
+ break;
+ case SectionType::FileLink:
+ {
+ pLnk->SetContentType( SotClipboardFormatId::SIMPLE_FILE );
+ sal_Int32 nIndex = 0;
+ const OUString sFile(sCmd.getToken( 0, sfx2::cTokenSeparator, nIndex ));
+ const OUString sFltr(sCmd.getToken( 0, sfx2::cTokenSeparator, nIndex ));
+ const OUString sRange(sCmd.getToken( 0, sfx2::cTokenSeparator, nIndex ));
+ pFormat->GetDoc()->getIDocumentLinksAdministration().GetLinkManager().InsertFileLink( *pLnk,
+ static_cast<sfx2::SvBaseLinkObjectType>(m_Data.GetType()),
+ sFile,
+ ( !sFltr.isEmpty() ? &sFltr : nullptr ),
+ ( !sRange.isEmpty() ? &sRange : nullptr ) );
+ }
+ break;
+ default:
+ OSL_ENSURE( false, "What kind of Link is this?" );
+ }
+
+ switch( eCreateType )
+ {
+ case LinkCreateType::Connect: // Connect Link right away
+ pLnk->Connect();
+ break;
+
+ case LinkCreateType::Update: // Connect Link and update
+ pLnk->Update();
+ break;
+ case LinkCreateType::NONE: break;
+ }
+}
+
+void SwSection::BreakLink()
+{
+ const SectionType eCurrentType( GetType() );
+ if ( eCurrentType == SectionType::Content ||
+ eCurrentType == SectionType::ToxHeader ||
+ eCurrentType == SectionType::ToxContent )
+ {
+ // nothing to do
+ return;
+ }
+
+ // Release link, if it exists
+ if (m_RefLink.is())
+ {
+ SwSectionFormat *const pFormat( GetFormat() );
+ OSL_ENSURE(pFormat, "SwSection::BreakLink: no format?");
+ if (pFormat)
+ {
+ pFormat->GetDoc()->getIDocumentLinksAdministration().GetLinkManager().Remove( m_RefLink.get() );
+ }
+ m_RefLink.clear();
+ }
+ // change type
+ SetType( SectionType::Content );
+ // reset linked file data
+ SetLinkFileName( OUString() );
+ SetLinkFilePassword( OUString() );
+}
+
+const SwNode* SwIntrnlSectRefLink::GetAnchor() const
+{
+ return rSectFormat.GetSectionNode();
+}
+
+bool SwIntrnlSectRefLink::IsInRange( sal_uLong nSttNd, sal_uLong nEndNd ) const
+{
+ SwStartNode* pSttNd = rSectFormat.GetSectionNode();
+ return pSttNd &&
+ nSttNd < pSttNd->GetIndex() &&
+ pSttNd->EndOfSectionIndex() < nEndNd;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */