/* -*- 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);
}
}
else if (m_Data.IsHiddenFlag()) // show Nodes again
{
// Show all Frames
// 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);
}
}
}
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:
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 = SwNodes::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:
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();
}
bool SwSectionFormat::IsVisible() const
{
if(SwFrameFormat::IsVisible())
return true;
SwIterator<SwSectionFormat,SwSectionFormat> aFormatIter(*this);
for(SwSectionFormat* pChild = aFormatIter.First(); pChild; pChild = aFormatIter.Next())
if(pChild->IsVisible())
return true;
return false;
}
// Get info from the Format
bool SwSectionFormat::GetInfo(SwFindNearestNode& rInfo) const
{
if(GetFormatAttr( RES_PAGEDESC ).GetPageDesc())
{
const SwSectionNode* pNd = GetSectionNode();
if(pNd)
rInfo.CheckNode(*pNd);
}
return true;
}
static bool lcl_SectionCmpPos( const SwSection *pFirst, const SwSection *pSecond)
{
const SwSectionFormat* pFSectFormat = pFirst->GetFormat();
const SwSectionFormat* pSSectFormat = pSecond->GetFormat();
assert( 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()
{
rtl::Reference<SwXTextSection> 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"));
SwFormat::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, u""_ustr );
}
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;
}
if (SwDocShell* pShell = pDoc->GetDocShell())
{
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(), pShell->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: */
↑ V773 The 'pPam' pointer was assigned values twice without releasing the memory. A memory leak is possible.
↑ V1053 Calling the 'ResetFormatAttr' virtual function in the destructor may lead to unexpected result at runtime.
↑ V1019 Compound assignment expression 'rValue >>= aSeq' is used inside condition.