Files
loongoffice/sw/source/core/docnode/section.cxx
Miklos Vajna 5b49927760 sw doc model xml dump: show section names
The one in SwSectionData seems to the section name visible on the UI.
SwSectionFormat also has a name, but it looks like even the UI doesn't
bother with maintaining that on section rename, so that's not really
used anywhere, and only that was visible in the dump previously.

Change-Id: I9a7444561cee0e42d23eaf06cb4d53171603c0df
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145259
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
2023-01-10 14:02:26 +00:00

1520 lines
52 KiB
C++

/* -*- 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 <osl/diagnose.h>
#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 <ftnidx.hxx>
#include <doctxm.hxx>
#include <fmteiro.hxx>
#include <unosection.hxx>
#include <calbck.hxx>
#include <fmtclds.hxx>
#include <algorithm>
#include <utility>
#include "ndsect.hxx"
using namespace ::com::sun::star;
namespace {
class SwIntrnlSectRefLink : public SwBaseLink
{
SwSectionFormat& m_rSectFormat;
public:
SwIntrnlSectRefLink(SwSectionFormat& rFormat, SfxLinkUpdateMode nUpdateType)
: SwBaseLink(nUpdateType, SotClipboardFormatId::RTF)
, m_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( SwNodeOffset nSttNd, SwNodeOffset nEndNd ) const override;
SwSectionNode* GetSectNode()
{
const SwNode* pSectNd( GetAnchor() );
return const_cast<SwSectionNode*>( pSectNd->GetSectionNode() );
}
};
}
SwSectionData::SwSectionData(SectionType const eType, OUString aName)
: m_eType(eType)
, m_sSectionName(std::move(aName))
, 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
}
void SwSectionData::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwSectionData"));
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("section-name"), BAD_CAST(m_sSectionName.toUtf8().getStr()));
(void)xmlTextWriterEndElement(pWriter);
}
SwSection::SwSection(
SectionType const eType, OUString const& rName, SwSectionFormat & rFormat)
: SwClient(& rFormat)
, m_Data(eType, rName)
{
StartListening(rFormat.GetNotifier());
SwSection *const pParentSect = GetParent();
if( pParentSect )
{
// edit in readonly sections
m_Data.SetEditInReadonlyFlag( pParentSect->IsEditInReadonlyFlag() );
}
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
SvtListener::EndListeningAll();
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
pFormat->RemoveAllUnos();
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 )
return;
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
const sw::SectionHidden aHint;
pFormat->CallSwClientNotify(aHint);
// 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
const sw::SectionHidden aHint(false);
pFormat->CallSwClientNotify(aHint);
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::SwClientNotify(const SwModify&, const SfxHint& rHint)
{
Notify(rHint);
}
void SwSection::Notify(SfxHint const& rHint)
{
if (rHint.GetId() == SfxHintId::SwSectionHidden)
{
auto rSectionHidden = static_cast<const sw::SectionHidden&>(rHint);
m_Data.SetHiddenFlag(rSectionHidden.m_isHidden || (m_Data.IsHidden() && m_Data.IsCondHidden()));
return;
} else if (rHint.GetId() != SfxHintId::SwLegacyModify)
return;
auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
auto pOld = pLegacy->m_pOld;
auto pNew = pLegacy->m_pNew;
bool bUpdateFootnote = false;
switch(pLegacy->GetWhich())
{
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();
if( const SvxProtectItem* pItem = pNewSet->GetItemIfSet(
RES_PROTECT, false ) )
{
m_Data.SetProtectFlag( pItem->IsContentProtected() );
pNewSet->ClearItem( RES_PROTECT );
pOldSet->ClearItem( RES_PROTECT );
}
// --> edit in readonly sections
if( const SwFormatEditInReadonly* pItem = pNewSet->GetItemIfSet(
RES_EDIT_IN_READONLY, false ) )
{
m_Data.SetEditInReadonlyFlag(pItem->GetValue());
pNewSet->ClearItem( RES_EDIT_IN_READONLY );
pOldSet->ClearItem( RES_EDIT_IN_READONLY );
}
if( SfxItemState::SET == pNewSet->GetItemState(
RES_FTN_AT_TXTEND, false ) ||
SfxItemState::SET == pNewSet->GetItemState(
RES_END_AT_TXTEND, false ))
{
bUpdateFootnote = true;
}
if( !pNewSet->Count() )
return;
}
break;
case RES_PROTECT:
if( pNew )
{
bool bNewFlag =
static_cast<const SvxProtectItem*>(pNew)->IsContentProtected();
// this used to inherit the flag from the parent, but then there is
// no way to turn it off in an inner section
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_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(*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() )
return;
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, SwNodeOffset(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();
}
SwNodeOffset nEnd = pSectNd->EndOfSectionIndex();
SwNodeOffset nStart = pSectNd->GetIndex()+1;
sw_DeleteFootnote( pSectNd, nStart, nEnd );
}
if( !pIdx )
return;
// 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->CallSwClientNotify(sw::LegacyModifyHint(&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::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
{
if (rHint.GetId() == SfxHintId::SwSectionHidden)
{
auto rSectionHidden = static_cast<const sw::SectionHidden&>(rHint);
auto pSect = GetSection();
if(!pSect || rSectionHidden.m_isHidden == pSect->IsHiddenFlag()) // already at target state, skipping.
return;
GetNotifier().Broadcast(rSectionHidden);
return;
} else if (rHint.GetId() != SfxHintId::SwLegacyModify)
return;
auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
sal_uInt16 nWhich = pLegacy->GetWhich();
auto pOld = pLegacy->m_pOld;
auto pNew = pLegacy->m_pNew;
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 ))
{
GetNotifier().Broadcast(sw::LegacyModifyHint(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 ) )
{
GetNotifier().Broadcast(sw::LegacyModifyHint(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 ))
{
GetNotifier().Broadcast(sw::LegacyModifyHint(pItem, pItem));
pNewSet->ClearItem( RES_FTN_AT_TXTEND );
pOldSet->ClearItem( RES_FTN_AT_TXTEND );
}
if( SfxItemState::SET == pNewSet->GetItemState(
RES_END_AT_TXTEND, false, &pItem ))
{
GetNotifier().Broadcast(sw::LegacyModifyHint(pItem, 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:
GetNotifier().Broadcast(sw::LegacyModifyHint(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!
GetNotifier().Broadcast(sw::LegacyModifyHint(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::SwClientNotify(rMod, rHint);
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::SwClientNotify(rMod, rHint);
UpdateParent();
return;
}
break;
}
SwFrameFormat::SwClientNotify(rMod, rHint);
if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
{ // invalidate cached uno object
SetXTextSection(nullptr);
}
}
void SwSectionFormat::SetXTextSection(rtl::Reference<SwXTextSection> const& xTextSection)
{
m_wXTextSection = xTextSection.get();
}
// 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 sw::BroadcastingModify::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() )
return;
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;
const SwSection* pSection = GetSection();
const SvxProtectItem* pProtect = &GetProtect();
// edit in readonly sections
const SwFormatEditInReadonly* pEditInReadonly = &GetEditInReadonly();
bool bIsHidden = pSection->IsHidden();
if(GetRegisteredIn())
{
const SwSection* pPS = GetParentSection();
pProtect = &pPS->GetFormat()->GetProtect();
pEditInReadonly = &pPS->GetFormat()->GetEditInReadonly();
bIsHidden = pPS->IsHiddenFlag();
}
if(!pProtect->IsContentProtected() != !pSection->IsProtectFlag())
CallSwClientNotify(sw::LegacyModifyHint(pProtect, pProtect));
// edit in readonly sections
if(!pEditInReadonly->GetValue() != !pSection->IsEditInReadonlyFlag())
CallSwClientNotify(sw::LegacyModifyHint(pEditInReadonly, pEditInReadonly));
if(bIsHidden == pSection->IsHiddenFlag())
{
const sw::SectionHidden aHint(bIsHidden);
CallSwClientNotify(aHint);
}
}
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->GetNode());
}
// 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 = SwXTextSection::CreateXTextSection(this,
SectionType::ToxHeader == pSection->GetType());
}
return xMeta;
}
bool SwSectionFormat::supportsFullDrawingLayerFillAttributeSet() const
{
return false;
}
void SwSectionFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwSectionFormat"));
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("name"), BAD_CAST(GetName().toUtf8().getStr()));
GetAttrSet().dumpAsXml(pWriter);
(void)xmlTextWriterEndElement(pWriter);
}
void SwSectionFormats::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwSectionFormats"));
for (size_t i = 0; i < size(); ++i)
GetFormat(i)->dumpAsXml(pWriter);
(void)xmlTextWriterEndElement(pWriter);
}
// Method to break section links inside a linked section
static void lcl_BreakSectionLinksInSect( const SwSectionNode& rSectNd )
{
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( const SwBaseLink& rUpdLnk, SwSectionNode& rSectNd )
{
SwDoc& rDoc = rSectNd.GetDoc();
SwDocShell* pDShell = rDoc.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 = rDoc.getIDocumentLinksAdministration().GetLinkManager().GetLinks();
for( auto n = rLnks.size(); n; )
{
::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]);
if( pLnk == &rUpdLnk )
continue;
if( sfx2::SvBaseLinkObjectType::ClientFile != pLnk->GetObjType() )
continue;
SwBaseLink* pBLink = dynamic_cast<SwBaseLink*>( pLnk );
if( pBLink && pBLink->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 = m_rSectFormat.GetSectionNode();
SwDoc* pDoc = m_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() );
pDoc->GetNodes().MakeTextNode( aIdx.GetNode(),
pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ) );
if( pESh )
pESh->StartAllAction();
else if( pVSh )
pVSh->StartAction();
SwPosition aPos( aIdx, SwNodeOffset(-1) );
SwDoc::CorrAbs( aIdx, aEndIdx, aPos, true );
pPam = new SwPaM( aPos );
// Delete everything succeeding it
--aIdx;
DelFlyInRange( aIdx.GetNode(), aEndIdx.GetNode() );
DelBookmarks(aIdx.GetNode(), aEndIdx.GetNode());
++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()->GetNode(), -1 );
std::optional<SwNodeRange> oCpyRg;
if( xDocSh->GetMedium() &&
rSection.GetLinkFilePassword().isEmpty() )
{
if( const SfxStringItem* pItem = xDocSh->GetMedium()->GetItemSet()->
GetItemIfSet( SID_PASSWORD, false ) )
rSection.SetLinkFilePassword( 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();
}
}
SwNode& rInsPos = pPam->GetPoint()->GetNode();
SwPaM* pCpyPam = nullptr;
if( !bRecursion &&
pSrcDoc->GetDocumentLinksAdministrationManager().SelectServerObj( sRange, pCpyPam, oCpyRg )
&& pCpyPam )
{
if( pSrcDoc != pDoc ||
pCpyPam->Start()->GetNode() > rInsPos ||
rInsPos >= pCpyPam->End()->GetNode() )
{
pSrcDoc->getIDocumentContentOperations().CopyRange(*pCpyPam, *pPam->GetPoint(), SwCopyFlags::CheckPosInFly);
}
delete pCpyPam;
}
if( oCpyRg && pSrcDoc == pDoc &&
oCpyRg->aStart < rInsPos && rInsPos < oCpyRg->aEnd.GetNode() )
{
oCpyRg.reset();
}
}
else if( pSrcDoc != pDoc )
oCpyRg.emplace( pSrcDoc->GetNodes().GetEndOfExtras(), SwNodeOffset(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( oCpyRg )
{
SwNode& rInsPos = pPam->GetPoint()->GetNode();
bool bCreateFrame = rInsPos <= pDoc->GetNodes().GetEndOfExtras() ||
rInsPos.FindTableNode();
SwTableNumFormatMerge aTNFM( *pSrcDoc, *pDoc );
pSrcDoc->GetDocumentContentOperationsManager().CopyWithFlyInFly(*oCpyRg, rInsPos, nullptr, bCreateFrame);
++aSave;
if( !bCreateFrame )
::MakeFrames( pDoc, aSave.GetNode(), rInsPos );
// Delete last Node, only if it was copied successfully
// (the Section contains more than one Node)
if( SwNodeOffset(2) < pSectNd->EndOfSectionIndex() - pSectNd->GetIndex() )
{
aSave = rInsPos;
pPam->Move( fnMoveBackward, GoInNode );
pPam->SetMark(); // Rewire both SwPositions
pDoc->CorrAbs( aSave.GetNode(), *pPam->GetPoint(), 0, true );
pDoc->GetNodes().Delete( aSave );
}
oCpyRg.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 = m_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] == &m_rSectFormat)
{
SwViewShell* pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
SwEditShell* pESh = pDoc->GetEditShell();
if( pESh )
pESh->StartAllAction();
else
pSh->StartAction();
SwSectionData aSectionData(*m_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 = m_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(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() );
}
void SwSection::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwSection"));
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("registered-in"), "%p",
GetRegisteredIn());
m_Data.dumpAsXml(pWriter);
(void)xmlTextWriterEndElement(pWriter);
}
const SwNode* SwIntrnlSectRefLink::GetAnchor() const { return m_rSectFormat.GetSectionNode(); }
bool SwIntrnlSectRefLink::IsInRange( SwNodeOffset nSttNd, SwNodeOffset nEndNd ) const
{
SwStartNode* pSttNd = m_rSectFormat.GetSectionNode();
return pSttNd &&
nSttNd < pSttNd->GetIndex() &&
pSttNd->EndOfSectionIndex() < nEndNd;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */