/* -*- 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 .
*/
// #i21457# - new implementation of local method <lcl_IsInSameTableBox(..)>. // Method now determines the previous/next on its own. Thus, it can be controlled, // for which previous/next is checked, if it's visible. staticbool lcl_IsInSameTableBox(const SwNode& _rNd, constbool _bPrev)
{ const SwTableNode* pTableNd = _rNd.FindTableNode(); if ( !pTableNd )
{ returntrue;
}
// determine index to be checked. Its assumed that a previous/next exist.
SwNodeIndex aChkIdx( _rNd );
// determine index of previous/next - skip hidden ones, which are // inside the table. // If found one is before/after table, this one isn't in the same // table box as <_rNd>. for(;;)
{ if ( _bPrev
? !SwNodes::GoPrevSection( &aChkIdx, false, false )
: !SwNodes::GoNextSection( &aChkIdx, false, false ) )
{
OSL_FAIL( " - no previous/next!" ); returnfalse;
}
// check, if found one isn't inside a hidden section, which // is also inside the table.
SwSectionNode* pSectNd = aChkIdx.GetNode().FindSectionNode(); if ( !pSectNd ||
pSectNd->GetIndex() < pTableNd->GetIndex() ||
!pSectNd->GetSection().IsHiddenFlag() )
{ break;
}
}
// Find the Box's StartNode const SwTableSortBoxes& rSortBoxes = pTableNd->GetTable().GetTabSortBoxes();
SwNodeOffset nIdx = _rNd.GetIndex(); for (size_t n = 0; n < rSortBoxes.size(); ++n)
{ const SwStartNode* pNd = rSortBoxes[ n ]->GetSttNd(); if ( pNd->GetIndex() < nIdx && nIdx < pNd->EndOfSectionIndex() )
{ // The other index needs to be within the same Section
nIdx = aChkIdx.GetIndex(); return pNd->GetIndex() < nIdx && nIdx < pNd->EndOfSectionIndex();
}
}
SwSection *
SwDoc::InsertSwSection(SwPaM const& rRange, SwSectionData & rNewData,
std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode, sw::ParagraphBreakMode> const*const pTOXBaseAndMode,
SfxItemSet const*const pAttr, boolconst bUpdate)
{ const SwNode* pPrvNd = nullptr;
sal_uInt16 nRegionRet = 0; if( rRange.HasMark() )
{
nRegionRet = IsInsRegionAvailable( rRange, &pPrvNd ); if( 0 == nRegionRet )
{ // demoted to info because this is called from SwXTextSection::attach, // so it could be invalid input
SAL_INFO("sw.core" , "InsertSwSection: rRange overlaps other sections"); return nullptr;
}
}
// See if the whole Document should be hidden, which we currently are not able to do. if (rNewData.IsHidden() && rRange.HasMark())
{ auto [pStart, pEnd] = rRange.StartEnd(); // SwPosition* if( !pStart->GetContentIndex() &&
pEnd->GetNode().GetContentNode()->Len() ==
pEnd->GetContentIndex() )
{
::lcl_CheckEmptyLayFrame(
rNewData,
pStart->GetNode(),
pEnd->GetNode() );
}
}
// Is a Condition set? if (rNewData.IsHidden() && !rNewData.GetCondition().isEmpty())
{ // The calculate up to that position
SwCalc aCalc( *this ); if( ! IsInReading() )
{
getIDocumentFieldsAccess().FieldsToCalc(aCalc, pNewSectNode->GetIndex(), SAL_MAX_INT32);
}
SwSection& rNewSect = pNewSectNode->GetSection();
rNewSect.SetCondHidden( aCalc.Calculate( rNewSect.GetCondition() ).GetBool() );
}
// A ClearRedo could result in a recursive call of this function and delete some section // formats, thus the position inside the SectionFormatTable could have changed
itFormatPos = std::find( mpSectionFormatTable->begin(), mpSectionFormatTable->end(), pFormat );
// WARNING: First remove from the array and then delete, // as the Section DTOR tries to delete it's format itself.
mpSectionFormatTable->erase( itFormatPos );
if( bOnlyAttrChg )
{ if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo(
MakeUndoUpdateSection( *pFormat, true ) );
} // #i32968# Inserting columns in the section causes MakeFrameFormat // to put two objects of type SwUndoFrameFormat on the undo stack. // We don't want them.
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
pFormat->SetFormatAttr( *pAttr );
getIDocumentState().SetModified();
} return;
}
// Test if the whole Content Section (Document/TableBox/Fly) should be hidden, // which we're currently not able to do. const SwNodeIndex* pIdx = nullptr;
{ if (rNewData.IsHidden())
{
pIdx = pFormat->GetContent().GetContentIdx(); if (pIdx)
{ const SwSectionNode* pSectNd =
pIdx->GetNode().GetSectionNode(); if (pSectNd)
{
::lcl_CheckEmptyLayFrame( rNewData,
*pSectNd, *pSectNd->EndOfSectionNode() );
}
}
}
}
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo(MakeUndoUpdateSection(*pFormat, false));
} // #i32968# Inserting columns in the section causes MakeFrameFormat to put two // objects of type SwUndoFrameFormat on the undo stack. We don't want them.
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
// The LinkFileName could only consist of separators
OUString sCompareString = OUStringChar(sfx2::cTokenSeparator) + OUStringChar(sfx2::cTokenSeparator); constbool bUpdate =
(!pSection->IsLinkType() && rNewData.IsLinkType())
|| (!rNewData.GetLinkFileName().isEmpty()
&& (rNewData.GetLinkFileName() != sCompareString)
&& (rNewData.GetLinkFileName() != pSection->GetLinkFileName()));
/// In SwSection::operator=(..) class member m_bCondHiddenFlag is always set to true. /// IMHO this have to be changed, but I can't estimate the consequences: /// Either it is set to true using corresponding method <SwSection.SetCondHidden(..)>, /// or it is set to the value of SwSection which is assigned to it. /// Discussion with AMA results that the adjustment to the assignment operator /// could be very risky.
pSection->SetSectionData(rNewData);
// Is a Condition set if( pSection->IsHidden() && !pSection->GetCondition().isEmpty() )
{ // Then calculate up to that position
SwCalc aCalc( *this ); if( !pIdx )
pIdx = pFormat->GetContent().GetContentIdx();
getIDocumentFieldsAccess().FieldsToCalc(aCalc, pIdx->GetIndex(), SAL_MAX_INT32);
/// Because on using SwSection::operator=() to set up <pSection> /// with <rNewData> and the above given note, the hidden condition flag /// has to be set to false, if hidden condition flag of <pFormat->GetSection()> /// (SwSection before the changes) is false (already saved in <bOldCondHidden>) /// and new calculated condition is true. /// This is necessary, because otherwise the <SetCondHidden> would have /// no effect. bool bCalculatedCondHidden =
aCalc.Calculate( pSection->GetCondition() ).GetBool(); if ( bCalculatedCondHidden && !bOldCondHidden )
{
pSection->SetCondHidden( false );
}
pSection->SetCondHidden( bCalculatedCondHidden );
}
// Delete all succeeding Footnotes while (nPos < rFootnoteArr.size())
{
SwTextFootnote* pSrch = rFootnoteArr[nPos]; if (SwTextFootnote_GetIndex(pSrch) > nEnd) break; // If the Nodes are not deleted, they need to deregister at the Pages // (delete Frames) or else they will remain there (Undo does not delete them!)
pSrch->DelFrames(nullptr);
++nPos;
}
while (nPos > 0)
{
nPos--;
SwTextFootnote* pSrch = rFootnoteArr[nPos]; if (SwTextFootnote_GetIndex(pSrch) < nStt) break; // If the Nodes are not deleted, they need to deregister at the Pages // (delete Frames) or else they will remain there (Undo does not delete them!)
pSrch->DelFrames(nullptr);
}
}
SwSectionNode *const pSectNd = new SwSectionNode(aInsPos.GetNode(), rSectionFormat, pTOXBase);
if (lcl_IsTOXSection(rSectionData))
{ // We're inserting a ToX. Make sure that if a redline ends right before the ToX start, then // that end now doesn't cross a section start node.
SwRedlineTable& rRedlines = GetDoc().getIDocumentRedlineAccess().GetRedlineTable(); for (SwRedlineTable::size_type nIndex = 0; nIndex < rRedlines.size(); ++nIndex)
{
SwRangeRedline* pRedline = rRedlines[nIndex]; if ( RedlineType::Delete != pRedline->GetType() ||
!pRedline->HasMark() || pRedline->GetMark()->GetNode() != aInsPos.GetNode() )
{ continue;
}
// The redline ends at the new section content start, so it originally ended before the // section start: move it back.
SwPaM aRedlineEnd(*pRedline->GetMark());
aRedlineEnd.Move(fnMoveBackward);
*pRedline->GetMark() = *aRedlineEnd.GetPoint(); break;
}
}
if( pEndNd )
{ // Special case for the Reader/Writer if( *pEndNd != GetEndOfContent() )
aInsPos = pEndNd->GetIndex()+1; // #i58710: We created a RTF document with a section break inside a table cell // We are not able to handle a section start inside a table and the section end outside. const SwNode* pLastNode = pSectNd->StartOfSectionNode()->EndOfSectionNode(); if( aInsPos > pLastNode->GetIndex() )
aInsPos = pLastNode->GetIndex(); // Another way round: if the section starts outside a table but the end is inside... // aInsPos is at the moment the Position where my EndNode will be inserted const SwStartNode* pStartNode = aInsPos.GetNode().StartOfSectionNode(); // This StartNode should be in front of me, but if not, I want to survive
SwNodeOffset nMyIndex = pSectNd->GetIndex(); if( pStartNode->GetIndex() > nMyIndex ) // Suspicious!
{ const SwNode* pTemp; do
{
pTemp = pStartNode; // pTemp is a suspicious one
pStartNode = pStartNode->StartOfSectionNode();
} while( pStartNode->GetIndex() > nMyIndex );
pTemp = pTemp->EndOfSectionNode(); // If it starts behind me but ends behind my end... if( pTemp->GetIndex() >= aInsPos.GetIndex() )
aInsPos = pTemp->GetIndex()+1; // ...I have to correct my end position
}
} else
{
SwTextNode* pCpyTNd = rNd.GetTextNode(); if( pCpyTNd )
{
SwTextNode* pTNd = new SwTextNode( aInsPos.GetNode(), pCpyTNd->GetTextColl() ); if( pCpyTNd->HasSwAttrSet() )
{ // Move PageDesc/Break to the first Node of the section const SfxItemSet& rSet = *pCpyTNd->GetpSwAttrSet(); if( SfxItemState::SET == rSet.GetItemState( RES_BREAK ) ||
SfxItemState::SET == rSet.GetItemState( RES_PAGEDESC ))
{
SfxItemSet aSet( rSet ); if( bInsAtStart )
pCpyTNd->ResetAttr( RES_PAGEDESC, RES_BREAK ); else
{
aSet.ClearItem( RES_PAGEDESC );
aSet.ClearItem( RES_BREAK );
}
pTNd->SetAttr( aSet );
} else
pTNd->SetAttr( rSet );
} // Do not forget to create the Frame!
pCpyTNd->MakeFramesForAdjacentContentNode(*pTNd);
} else new SwTextNode( aInsPos.GetNode(), GetDoc().GetDfltTextFormatColl() );
} new SwEndNode( aInsPos.GetNode(), *pSectNd );
// We could optimize this, by not removing already contained Frames and recreating them, // but by simply rewiring them bool bInsFrame = bCreateFrames && !pSectNd->GetSection().IsHiddenFlag() &&
GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
std::optional<SwNode2LayoutSaveUpperFrames> oNode2Layout; if( bInsFrame )
{ if( !pSectNd->GetNodes().FindPrvNxtFrameNode( *pSectNd, pSectNd->EndOfSectionNode() ) ) // Collect all Uppers
oNode2Layout.emplace(*pSectNd);
}
// Set the right StartNode for all in this Area
SwNodeOffset nEnd = pSectNd->EndOfSectionIndex();
SwNodeOffset nStart = pSectNd->GetIndex()+1;
SwNodeOffset nSkipIdx = NODE_OFFSET_MAX; for( SwNodeOffset n = nStart; n < nEnd; ++n )
{
SwNode* pNd = (*this)[n];
// Attach all Sections in the NodeSection underneath the new one if( NODE_OFFSET_MAX == nSkipIdx )
pNd->m_pStartOfSection = pSectNd; elseif( n >= nSkipIdx )
nSkipIdx = NODE_OFFSET_MAX;
if( pNd->IsStartNode() )
{ // Make up the Format's nesting if( pNd->IsSectionNode() )
{ static_cast<SwSectionNode*>(pNd)->GetSection().GetFormat()->
SetDerivedFrom( pSectFormat ); static_cast<SwSectionNode*>(pNd)->DelFrames();
n = pNd->EndOfSectionIndex();
} else
{ if( pNd->IsTableNode() ) static_cast<SwTableNode*>(pNd)->DelFrames();
// ugly hack to make m_pSection const static SwSectionFormat &
lcl_initParent(SwSectionNode & rThis, SwSectionFormat & rFormat)
{
SwSectionNode *const pParent =
rThis.StartOfSectionNode()->FindSectionNode(); if( pParent )
{ // Register the Format at the right Parent
rFormat.SetDerivedFrom( pParent->GetSection().GetFormat() );
} return rFormat;
}
SwSectionNode::SwSectionNode(const SwNode& rWhere,
SwSectionFormat & rFormat, SwTOXBase const*const pTOXBase)
: SwStartNode( rWhere, SwNodeType::Section )
, m_pSection( pTOXBase
? new SwTOXBaseSection(*pTOXBase, lcl_initParent(*this, rFormat))
: new SwSection( SectionType::Content, rFormat.GetName(),
lcl_initParent(*this, rFormat) ) )
{ // Set the connection from Format to Node // Suppress Modify; no one's interested anyway
rFormat.LockModify();
rFormat.SetFormatAttr( SwFormatContent( this ) );
rFormat.UnlockModify();
}
SwSectionNode::~SwSectionNode()
{ // mba: test if iteration works as clients will be removed in callback // use hint which allows to specify, if the content shall be saved or not
m_pSection->GetFormat()->CallSwClientNotify( SwSectionFrameMoveAndDeleteHint( true ) );
SwSectionFormat* pFormat = m_pSection->GetFormat(); if( pFormat )
{ // Remove the Attribute, because the Section deletes it's Format // and it will neutralize the Section, if the Content Attribute is set
pFormat->LockModify();
pFormat->ResetFormatAttr( RES_CNTNT );
pFormat->UnlockModify();
}
}
// Creates all Document Views for the preceding Node. // The created ContentFrames are attached to the corresponding Layout void SwSectionNode::MakeFramesForAdjacentContentNode(const SwNodeIndex & rIdx)
{ // Take my successive or preceding ContentFrame
SwNodes& rNds = GetNodes(); if( !(rNds.IsDocNodes() && rNds.GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell()) ) return;
// Assure that node is not inside a table, which is inside the // found section. if ( pS )
{
SwTableNode* pTableNode = rIdx.GetNode().FindTableNode(); if ( pTableNode &&
pTableNode->GetIndex() > pS->GetIndex() )
{
pS = nullptr;
}
}
// if the node is in a section, the sectionframe now // has to be created... // boolean to control <Init()> of a new section frame. bool bInitNewSect = false; if( pS )
{
SwSectionFrame *pSct = new SwSectionFrame( pS->GetSection(), pFrame ); // prepare <Init()> of new section frame.
bInitNewSect = true;
SwLayoutFrame* pUp = pSct; while( pUp->Lower() ) // for columned sections
{
OSL_ENSURE( pUp->Lower()->IsLayoutFrame(),"Who's in there?" );
pUp = static_cast<SwLayoutFrame*>(pUp->Lower());
}
pNew->Paste( pUp ); // #i27138# // notify accessibility paragraphs objects about changed // CONTENT_FLOWS_FROM/_TO relation. // Relation CONTENT_FLOWS_FROM for next paragraph will change // and relation CONTENT_FLOWS_TO for previous paragraph will change. #if !ENABLE_WASM_STRIP_ACCESSIBILITY if ( pNew->IsTextFrame() )
{
SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() ); if ( pViewShell && pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() )
{ auto pNext = pNew->FindNextCnt( true ); auto pPrev = pNew->FindPrevCnt();
pViewShell->InvalidateAccessibleParaFlowRelation(
pNext ? pNext->DynCastTextFrame() : nullptr,
pPrev ? pPrev->DynCastTextFrame() : nullptr );
}
} #endif
pNew = pSct;
}
// If a Node got Frames attached before or after if ( rIdx < GetIndex() ) // the new one precedes me
pNew->Paste( pFrame->GetUpper(), pFrame ); else // the new one succeeds me
pNew->Paste( pFrame->GetUpper(), pFrame->GetNext() ); // #i27138# // notify accessibility paragraphs objects about changed // CONTENT_FLOWS_FROM/_TO relation. // Relation CONTENT_FLOWS_FROM for next paragraph will change // and relation CONTENT_FLOWS_TO for previous paragraph will change. #if !ENABLE_WASM_STRIP_ACCESSIBILITY if ( pNew->IsTextFrame() )
{
SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() ); if ( pViewShell && pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() )
{ auto pNext = pNew->FindNextCnt( true ); auto pPrev = pNew->FindPrevCnt();
pViewShell->InvalidateAccessibleParaFlowRelation(
pNext ? pNext->DynCastTextFrame() : nullptr,
pPrev ? pPrev->DynCastTextFrame() : nullptr );
}
} #endif if ( bInitNewSect ) static_cast<SwSectionFrame*>(pNew)->Init();
}
}
}
// Create a new SectionFrame for every occurrence in the Layout and insert before // the corresponding ContentFrame void SwSectionNode::MakeOwnFrames(SwNodeIndex* pIdxBehind, const SwNodeIndex* pEndIdx)
{
assert(pIdxBehind && "no Index");
SwNodes& rNds = GetNodes();
SwDoc& rDoc = rNds.GetDoc();
// Update our Flag
m_pSection->m_Data.SetHiddenFlag(true);
// If the Area is within a Fly or TableBox, we can only hide it if // there is more Content which has Frames. // Or else the Fly/TableBox Frame does not have a Lower! if (bForce) return;
SwNodeRange aRg( *this, SwNodeOffset(+1), *EndOfSectionNode() ); // Where am I?
rNds.Copy_( aRg, aInsPos.GetNode(), false );
// Delete all Frames from the copied Area. They are created when creating // the SectionFrames.
pSectNd->DelFrames();
// Copy the Links/Server if( pNewSect->IsLinkType() ) // Add the Link
pNewSect->CreateLink( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() ? LinkCreateType::Connect : LinkCreateType::NONE );
// If we copy from the Undo as Server, enter it again if (m_pSection->IsServer()
&& rDoc.GetIDocumentUndoRedo().IsUndoNodes(rNds))
{
pNewSect->SetRefObject( m_pSection->GetObject() );
rDoc.getIDocumentLinksAdministration().GetLinkManager().InsertServer( pNewSect->GetObject() );
}
// METADATA: copy xml:id; must be done after insertion of node
pSectFormat->RegisterAsCopyOf(*GetSection().GetFormat());
pFormat->LockModify();
pFormat->SetFormatAttr( SwFormatContent( this ));
pFormat->UnlockModify();
SwSectionNode* pSectNd = StartOfSectionNode()->FindSectionNode(); // set the correct parent from the new section
pFormat->SetDerivedFrom( pSectNd ? pSectNd->GetSection().GetFormat()
: rDoc.GetDfltFrameFormat() );
// Set the right StartNode for all in this Area
SwNodeOffset nStart = GetIndex()+1, nEnd = EndOfSectionIndex(); for( SwNodeOffset n = nStart; n < nEnd; ++n )
{ // Make up the Format's nesting
pSectNd = rNds[ n ]->GetSectionNode(); if( nullptr != pSectNd )
{
pSectNd->GetSection().GetFormat()->SetDerivedFrom( pFormat );
n = pSectNd->EndOfSectionIndex();
}
}
// Moving Nodes to the UndoNodes array? if( rNds.IsDocNodes() )
{
OSL_ENSURE( &rDoc == &GetDoc(), "Moving to different Documents?" ); if( m_pSection->IsLinkType() ) // Remove the Link
m_pSection->CreateLink( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() ? LinkCreateType::Connect : LinkCreateType::NONE );
if (m_pSection->IsServer())
rDoc.getIDocumentLinksAdministration().GetLinkManager().InsertServer( m_pSection->GetObject() );
} else
{ if (SectionType::Content != m_pSection->GetType()
&& m_pSection->IsConnected())
{
rDoc.getIDocumentLinksAdministration().GetLinkManager().Remove( &m_pSection->GetBaseLink() );
} if (m_pSection->IsServer())
rDoc.getIDocumentLinksAdministration().GetLinkManager().RemoveServer( m_pSection->GetObject() );
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.