/* -*- 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 .
*/
/** Destructor * * Deletes all nodes whose pointer are in a dynamic array. This should be no * problem as nodes cannot be created outside this array and, thus, cannot be * part of multiple arrays.
*/
SwNodes::~SwNodes()
{
m_aOutlineNodes.clear();
void SwNodes::ChgNode( SwNodeIndex const & rDelPos, SwNodeOffset nSz,
SwNodeIndex& rInsPos, bool bNewFrames )
{ // no need for frames in the UndoArea
SwNodes& rNds = rInsPos.GetNodes(); const SwNode* pPrevInsNd = rNds[ rInsPos.GetIndex() -SwNodeOffset(1) ];
// declare all fields as invalid, updating will happen // in the idle-handler of the doc if( GetDoc().getIDocumentFieldsAccess().SetFieldsDirty( true, &rDelPos.GetNode(), nSz ) &&
&rNds.GetDoc() != &GetDoc() )
rNds.GetDoc().getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, SwNodeOffset(0) );
// NEVER include nodes from the RedLineArea
SwNodeOffset nNd = rInsPos.GetIndex(); boolconst bInsOutlineIdx = IsInsertOutline(rNds, nNd);
if( &rNds == this ) // if in the same node array -> move
{ // Move order: from front to back, so that new entries are added at // first position, thus, deletion position stays the same const SwNodeOffset nDiff(rDelPos.GetIndex() < rInsPos.GetIndex() ? 0 : 1);
for( SwNodeOffset n = rDelPos.GetIndex(); nSz; n += nDiff, --nSz )
{
SwNodeIndex aDelIdx( *this, n );
SwNode& rNd = aDelIdx.GetNode();
// #i57920# - correction of refactoring done by cws swnumtree: // - <SwTextNode::SetLevel( NO_NUMBERING ) is deprecated and // set <IsCounted> state of the text node to <false>, which // isn't correct here. if ( rNd.IsTextNode() )
{
SwTextNode* pTextNode = rNd.GetTextNode();
case RES_TXTATR_FTN: static_cast<SwFormatFootnote&>(pAttr->GetAttr())
.InvalidateFootnote(); break;
case RES_TXTATR_TOXMARK: static_cast<SwTOXMark&>(pAttr->GetAttr())
.InvalidateTOXMark(); break;
case RES_TXTATR_REFMARK: static_cast<SwFormatRefMark&>(pAttr->GetAttr())
.InvalidateRefMark(); break;
case RES_TXTATR_META: case RES_TXTATR_METAFIELD:
{
SwTextMeta *const pTextMeta(
static_txtattr_cast<SwTextMeta*>(pAttr)); // force removal of UNO object
pTextMeta->ChgTextNode(nullptr);
pTextMeta->ChgTextNode(pTextNd);
} break;
default: break;
}
}
}
if( RES_CONDTXTFMTCOLL == pTextNd->GetTextColl()->Which() )
pTextNd->ChkCondColl();
} else
{ // Moved into different Docs? Persist data again! if( pCNd->IsNoTextNode() && bRestPersData ) static_cast<SwNoTextNode*>(pCNd)->RestorePersistentData();
}
// reset Accessibility issue state
pCNd->resetAndQueueAccessibilityCheck();
}
}
}
// declare all fields as invalid, updating will happen // in the idle-handler of the doc
GetDoc().getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, SwNodeOffset(0) ); if( &rNds.GetDoc() != &GetDoc() )
rNds.GetDoc().getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, SwNodeOffset(0) );
// TODO: provide documentation /** move the node pointer * * Move the node pointer from "(inclusive) start position to (exclusive) end * position" to target position. * If the target is in front of the first or in the area between first and * last element to move, nothing happens. * If the area to move is empty or the end position is before the start * position, nothing happens. * * @param aRange range to move (excluding end node) * @return
*/ bool SwNodes::MoveNodes( const SwNodeRange& aRange, SwNodes & rNodes,
SwNode& rPos, bool bNewFrames )
{
SwNode * pCurrentNode; if( rPos.GetIndex() == SwNodeOffset(0) ||
( (pCurrentNode = &rPos)->GetStartNode() &&
!pCurrentNode->StartOfSectionIndex() )) returnfalse;
SwNodeRange aOrigInsPos( aIdx, SwNodeOffset(-1), aIdx ); // original insertion position
// call DelFrames/MakeFrames for the upmost SectionNode int nSectNdCnt = 0; bool bSaveNewFrames = bNewFrames;
// continue until everything has been moved while( aRg.aStart < aRg.aEnd )
{
pCurrentNode = &aRg.aEnd.GetNode(); switch( pCurrentNode->GetNodeType() )
{ case SwNodeType::End:
{ if( nInsPos ) // move everything until here
{ // delete and copy. CAUTION: all indices after // "aRg.aEnd+1" will be moved as well!
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames );
aIdx -= nInsPos;
nInsPos = SwNodeOffset(0);
}
if( bInsOutlineIdx && pCNd )
m_aOutlineNodes.insert( pCNd ); if( pTmpNd->IsTextNode() ) static_cast<SwTextNode*>(pTmpNd)->AddToList();
}
} else
{ // get StartNode // Even aIdx points to a startnode, we need the startnode // of the environment of aIdx (#i80941)
SwStartNode* pSttNode = aIdx.GetNode().m_pStartOfSection;
// get all boxes with content because their indices // pointing to the StartNodes need to be reset // (copying the array and deleting all found ones eases // searching)
SwNodeIndex aMvIdx( aRg.aEnd, 1 ); for( SwNodeOffset n(0); n < nInsPos; ++n )
{
SwNode* pNd = &aMvIdx.GetNode();
constbool bOutlNd = pNd->IsTextNode() && pNd->GetTextNode()->IsOutline(); // delete outline indices from old node array if( bOutlNd )
m_aOutlineNodes.erase( pNd );
// set correct indices in Start/EndNodes if( bInsOutlineIdx && bOutlNd ) // and put them into the new node array
rNodes.m_aOutlineNodes.insert( pNd ); elseif( pNd->IsStartNode() )
pSttNode = static_cast<SwStartNode*>(pNd); elseif( pNd->IsEndNode() )
{
pSttNode->m_pEndOfSection = static_cast<SwEndNode*>(pNd); if( pSttNode->IsSectionNode() ) static_cast<SwSectionNode*>(pSttNode)->NodesArrChgd();
pSttNode = pSttNode->m_pStartOfSection;
}
}
if (GetDoc().GetIDocumentUndoRedo().IsUndoNodes(rNodes))
{
SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat();
pTableFormat->GetNotifier().Broadcast(SfxHint(SfxHintId::Dying));
}
} if( bNewFrames )
{
pTableNd->MakeOwnFrames();
}
aIdx -= nInsPos;
nInsPos = SwNodeOffset(0);
} elseif( pSttNd->GetIndex() < aRg.aStart.GetIndex() )
{ // SectionNode: not the whole section will be moved, thus, // move only the ContentNodes // StartNode: create a new section at the given position do { // middle check loop if( !pSttNd->IsSectionNode() )
{ // create StartNode and EndNode at InsertPos
SwStartNode* pTmp = new SwStartNode( aIdx.GetNode(),
SwNodeType::Start, /*?? NodeType ??*/ SwNormalStartNode );
nLevel++; // put the index to StartNode on the stack
aSttNdStack.insert( aSttNdStack.begin() + nLevel, pTmp );
// create EndNode new SwEndNode( aIdx.GetNode(), *pTmp );
} elseif (GetDoc().GetIDocumentUndoRedo().IsUndoNodes(
rNodes))
{ // use placeholder in UndoNodes array new SwPlaceholderNode(aIdx.GetNode());
} else
{ // JP 18.5.2001 (Bug 70454) creating new section?
--aRg.aEnd; break;
}
--aRg.aEnd;
--aIdx;
} while( false );
} else
{ // move StartNode and EndNode in total
// if Start is exactly the Start of the area, // then the Node needs to be re-visited if( &aRg.aStart.GetNode() == pSttNd )
--aRg.aStart;
SwSectionNode* pSctNd = pSttNd->GetSectionNode(); if( bNewFrames && pSctNd )
{ // tdf#135056 skip over code in DelFrames() that moves // SwNodeIndex around because in case of nested // sections, m_pStartOfSection will point between // undo nodes-array and doc nodes-array
pSctNd->DelFrames(nullptr, true);
}
// this StartNode will be removed later
SwStartNode* pTmpSttNd = new SwStartNode( *this, nSttPos+1 );
pTmpSttNd->m_pStartOfSection = pSttNd->m_pStartOfSection;
nLevel++; // put the index pointing to the StartNode onto the stack
aSttNdStack.insert( aSttNdStack.begin() + nLevel, pSttNd );
// reset remaining indices if SectionNode if( pSctNd )
{
pSctNd->NodesArrChgd();
++nSectNdCnt; // tdf#132326 do not let frames survive in undo nodes if (!GetDoc().GetIDocumentUndoRedo().IsUndoNodes(rNodes))
{
bNewFrames = false;
}
}
}
} break;
case SwNodeType::Section: if( !nLevel &&
GetDoc().GetIDocumentUndoRedo().IsUndoNodes(rNodes))
{ // here, a SectionDummyNode needs to be inserted at the current position if( nInsPos ) // move everything until here
{ // delete and copy. CAUTION: all indices after // "aRg.aEnd+1" will be moved as well!
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames );
aIdx -= nInsPos;
nInsPos = SwNodeOffset(0);
} new SwPlaceholderNode(aIdx.GetNode());
--aRg.aEnd;
--aIdx; break;
}
[[fallthrough]]; case SwNodeType::Table: case SwNodeType::Start:
{ // empty section -> nothing to do // and only if it's a top level section if( !nInsPos && !nLevel )
{
--aRg.aEnd; break;
}
// also set correct StartNode for all decreased nodes while( aTmpSIdx < aTmpEIdx ) if( nullptr != (( pCurrentNode = &aTmpEIdx.GetNode())->GetEndNode()) )
aTmpEIdx = pCurrentNode->StartOfSectionIndex(); else
{
pCurrentNode->m_pStartOfSection = pTmpStt;
--aTmpEIdx;
}
--aIdx; // after the inserted StartNode
--aRg.aEnd; // before StartNode // copy array. CAUTION: all indices after // "aRg.aEnd+1" will be moved as well!
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames );
aIdx -= nInsPos+1;
nInsPos = SwNodeOffset(0);
} else// all nodes between StartNode and EndNode were moved
{
OSL_ENSURE( pCurrentNode == aSttNdStack[nLevel] ||
( pCurrentNode->IsStartNode() &&
aSttNdStack[nLevel]->IsSectionNode()), "wrong StartNode" );
case SwNodeType::Text: //Add special function to text node.
{ if( bNewFrames && pCurrentNode->GetContentNode() ) static_cast<SwContentNode*>(pCurrentNode)->DelFrames(nullptr);
pCurrentNode->m_pStartOfSection = aSttNdStack[ nLevel ];
nInsPos++;
--aRg.aEnd;
} break; case SwNodeType::Grf: case SwNodeType::Ole:
{ if( bNewFrames && pCurrentNode->GetContentNode() ) static_cast<SwContentNode*>(pCurrentNode)->DelFrames(nullptr);
// reset Accessibility issue state
pCurrentNode->resetAndQueueAccessibilityCheck();
} break;
case SwNodeType::PlaceHolder: if (GetDoc().GetIDocumentUndoRedo().IsUndoNodes(*this))
{ if( &rNodes == this ) // inside UndoNodesArray
{ // move everything
pCurrentNode->m_pStartOfSection = aSttNdStack[ nLevel ];
nInsPos++;
} else// move into "normal" node array
{ // than a SectionNode (start/end) is needed at the current // InsPos; if so skip it, otherwise ignore current node if( nInsPos ) // move everything until here
{ // delete and copy. CAUTION: all indices after // "aRg.aEnd+1" will be moved as well!
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames );
aIdx -= nInsPos;
nInsPos = SwNodeOffset(0);
}
SwNode* pTmpNd = &aIdx.GetNode(); if( pTmpNd->IsSectionNode() ||
pTmpNd->StartOfSectionNode()->IsSectionNode() )
--aIdx; // skip
}
} else {
assert(!"How can this node be in the node array?");
}
--aRg.aEnd; break;
default:
assert(!"Unknown node type"); break;
}
}
if( nInsPos ) // copy remaining rest
{ // rest should be ok
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames );
}
++aRg.aEnd; // again, exclusive end
// initialize numbering update
++aOrigInsPos.aStart; // Moved in same node array? Then call update top down! if( this == &rNodes &&
aRg.aEnd.GetIndex() >= aOrigInsPos.aStart.GetIndex() )
{
UpdateOutlineIdx( aOrigInsPos.aStart.GetNode() );
UpdateOutlineIdx( aRg.aEnd.GetNode() );
} else
{
UpdateOutlineIdx( aRg.aEnd.GetNode() );
rNodes.UpdateOutlineIdx( aOrigInsPos.aStart.GetNode() );
}
returntrue;
}
/** create a start/end section pair * * Other nodes might be in between. * * After this method call, the start node of pRange will be pointing to the * first node after the start section node and the end node will be the index * of the end section node. If this method is called multiple times with the * same input, multiple sections containing the previous ones will be created * (no content nodes between start or end node). * * @note Start and end node of the range must be on the same level but MUST * NOT be on the top level. * * @param [IN,OUT] pRange the range (excl. end) * @param eSttNdTyp type of the start node
*/ void SwNodes::SectionDown(SwNodeRange *pRange, SwStartNodeType eSttNdTyp )
{ if( pRange->aStart >= pRange->aEnd ||
pRange->aEnd >= Count() ||
!::CheckNodesRange(pRange->aStart.GetNode(), pRange->aEnd.GetNode(), false))
{ return;
}
// If the beginning of a range is before or at a start node position, so // delete it, otherwise empty S/E or E/S nodes would be created. // For other nodes, create a new start node.
SwNode * pCurrentNode = &pRange->aStart.GetNode();
SwNodeIndex aTmpIdx( *pCurrentNode->StartOfSectionNode() );
// If the end of a range is before or at a StartNode, so delete it, // otherwise empty S/E or E/S nodes would be created. // For other nodes, insert a new end node.
--pRange->aEnd; if( pRange->aEnd.GetNode().GetStartNode() )
DelNodes( pRange->aEnd ); else
{
++pRange->aEnd; // insert a new EndNode new SwEndNode( pRange->aEnd.GetNode(), *pRange->aStart.GetNode().GetStartNode() );
}
--pRange->aEnd;
SectionUpDown( aTmpIdx, pRange->aEnd );
}
/** increase level of the given range * * The range contained in pRange will be lifted to the next higher level. * This is done by adding an end node at pRange.start and a start node at * pRange.end. Furthermore all indices for this range will be updated. * * After this method call, the start node of pRange will be pointing to the * first node inside the lifted range and the end node will be pointing to the * last position inside the lifted range. * * @param [IN,OUT] pRange the range of nodes where the level should be increased
*/ void SwNodes::SectionUp(SwNodeRange *pRange)
{ if( pRange->aStart >= pRange->aEnd ||
pRange->aEnd >= Count() ||
!::CheckNodesRange(pRange->aStart.GetNode(), pRange->aEnd.GetNode(), false) ||
( HighestLevel( *this, *pRange ) <= 1 ))
{ return;
}
// If the beginning of a range is before or at a start node position, so // delete it, otherwise empty S/E or E/S nodes would be created. // For other nodes, create a new start node.
SwNode * pCurrentNode = &pRange->aStart.GetNode();
SwNodeIndex aIdx( *pCurrentNode->StartOfSectionNode() ); if( pCurrentNode->IsStartNode() ) // is StartNode itself
{
SwEndNode* pEndNd = pRange->aEnd.GetNode().GetEndNode(); if (pEndNd && pCurrentNode == pEndNd->m_pStartOfSection)
{ // there was a pairwise reset, adjust only those in the range
SwStartNode* pTmpSttNd = pCurrentNode->m_pStartOfSection;
RemoveNode( pRange->aStart.GetIndex(), SwNodeOffset(1), true );
RemoveNode( pRange->aEnd.GetIndex(), SwNodeOffset(1), true );
// If the end of a range is before or at a StartNode, so delete it, // otherwise empty S/E or E/S nodes would be created. // For other nodes, insert a new end node.
SwNodeIndex aTmpIdx( pRange->aEnd ); if( pRange->aEnd.GetNode().IsEndNode() )
DelNodes( pRange->aEnd ); else
{ new SwStartNode( pRange->aEnd.GetNode() ); /*?? which NodeType ??*/
aTmpIdx = *pRange->aEnd.GetNode().EndOfSectionNode();
--pRange->aEnd;
}
SectionUpDown( aIdx, aTmpIdx );
}
/** correct indices after movement * * Update all indices after movement so that the levels are consistent again. * * @param aStart index of the start node * @param aEnd index of the end point * * @see SwNodes::SectionUp * @see SwNodes::SectionDown
*/ void SwNodes::SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd )
{
SwNodeIndex aTmpIdx( aStart, +1 ); // array forms a stack, holding all StartOfSelections
SwStartNodePointers aSttNdStack;
SwStartNode* pTmp = aStart.GetNode().GetStartNode();
aSttNdStack.push_back( pTmp );
// loop until the first start node that needs to be change was found // (the indices are updated from the end node backwards to the start) for( ;; ++aTmpIdx )
{
SwNode * pCurrentNode = &aTmpIdx.GetNode();
pCurrentNode->m_pStartOfSection = aSttNdStack[ aSttNdStack.size()-1 ];
elseif( aTmpIdx < aEnd ) // too many StartNodes // if the end is not reached, yet, get the start of the section above
{
aSttNdStack.insert( aSttNdStack.begin(), pSttNd->m_pStartOfSection );
} else// finished, as soon as out of the range break;
}
}
}
/** delete nodes * * This is a specific implementation of a delete function for a variable array. * It is necessary as there might be inconsistencies after deleting start or * end nodes. This method can clean those up. * * @param rIndex position to delete at (unchanged afterwards) * @param nNodes number of nodes to delete (default: 1)
*/ void SwNodes::Delete(const SwNode &rIndex, SwNodeOffset nNodes)
{ int nLevel = 0; // level counter
SwNode * pCurrentNode;
SwNodeRange aRg( rIndex, SwNodeOffset(0), rIndex, nCnt-1 ); // check if [rIndex..rIndex + nCnt] is larger than the range if( ( !aRg.aStart.GetNode().StartOfSectionIndex() &&
!aRg.aStart.GetIndex() ) ||
!::CheckNodesRange(aRg.aStart.GetNode(), aRg.aEnd.GetNode(), false))
{ return;
}
// if aEnd is not on a ContentNode, search the previous one while( ( pCurrentNode = &aRg.aEnd.GetNode())->GetStartNode() ||
( pCurrentNode->GetEndNode() &&
!pCurrentNode->m_pStartOfSection->IsTableNode() ))
--aRg.aEnd;
nCnt = SwNodeOffset(0); //TODO: check/improve comment // increase start so that we are able to use "<" (using "<=" might cause // problems if aEnd == aStart and aEnd is deleted, so aEnd <= aStart)
--aRg.aStart;
/** get section level at the given position * * @note The first node in an array should always be a start node. * Because of this, there is a special treatment here based on the * assumption that this is true in this context as well. * * @param rIdx position of the node * @return section level at the given position
*/
sal_uInt16 SwNodes::GetSectionLevel(const SwNode &rIdx)
{ // special treatment for 1st Node if(rIdx.GetIndex() == SwNodeOffset(0)) return 1; // no recursion! This calls a SwNode::GetSectionLevel (missing "s") return rIdx.GetSectionLevel();
}
void SwNodes::GoStartOfSection(SwNodeIndex *pIdx)
{ // after the next start node
SwNodeIndex aTmp( *pIdx->GetNode().StartOfSectionNode(), +1 );
// If index points to no ContentNode, then go to one. // If there is no further available, do not change the index' position! while( !aTmp.GetNode().IsContentNode() )
{ // go from this StartNode (can only be one) to its end if( *pIdx <= aTmp ) return; // ERROR: already after the section
aTmp = aTmp.GetNode().EndOfSectionIndex()+1; if( *pIdx <= aTmp ) return; // ERROR: already after the section
}
(*pIdx) = aTmp; // is on a ContentNode
}
/** Delete a number of nodes * * @param rStart starting position in this nodes array * @param nCnt number of nodes to delete
*/ void SwNodes::DelNodes( const SwNodeIndex & rStart, SwNodeOffset nCnt )
{
SwNodeOffset nSttIdx = rStart.GetIndex();
if( !nSttIdx && nCnt == GetEndOfContent().GetIndex()+1 )
{ // The whole nodes array will be destroyed, you're in the Doc's DTOR! // The initial start/end nodes should be only destroyed in the SwNodes' DTOR!
SwNode* aEndNdArr[] = { m_pEndOfContent.get(),
m_pEndOfPostIts, m_pEndOfInserts,
m_pEndOfAutotext, m_pEndOfRedlines,
nullptr
};
/** Calculate the highest level in a range * * @param rNodes the nodes array * @param rRange the range to inspect * @return the highest level
*/
sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange )
{
HighLevel aPara( SwNodes::GetSectionLevel( rRange.aStart.GetNode() ));
rNodes.ForEach( rRange.aStart, rRange.aEnd, lcl_HighestLevel, &aPara ); return aPara.nTop;
}
/** move a range * * @param rPam the range to move * @param rPos to destination position in the given nodes array * @param rNodes the node array to move the range into
*/ void SwNodes::MoveRange( SwPaM & rPam, SwPosition & rPos, SwNodes& rNodes )
{ auto [pStart, pEnd] = rPam.StartEnd(); // SwPosition*
if( pSrcNd )
{ // if the first node is a TextNode, then there must // be also a TextNode in the NodesArray to store the content if( !pDestNd )
{
pDestNd = rNodes.MakeTextNode( rPos.GetNode(), pSrcNd->GetTextColl() );
--rPos.nNode;
rPos.nContent.Assign( pDestNd, 0 );
bCopyCollFormat = true;
}
bSplitDestNd = pDestNd->Len() > rPos.GetContentIndex() ||
pEnd->GetNode().IsTextNode();
// move the content into the new node bool bOneNd = pStart->GetNode() == pEnd->GetNode(); const sal_Int32 nLen =
( bOneNd ? std::min(pEnd->GetContentIndex(), pSrcNd->Len()) : pSrcNd->Len() )
- pStart->GetContentIndex();
if( bOneNd )
{ // Correct the PaM, because it might have happened that the move // went over the node borders (so the data might be in different nodes). // Also, a selection is invalidated.
pEnd->nContent = pStart->nContent;
rPam.DeleteMark();
GetDoc().GetDocShell()->Broadcast( SwFormatFieldHint( nullptr,
rNodes.IsDocNodes() ? SwFormatFieldHintWhich::INSERTED : SwFormatFieldHintWhich::REMOVED ) ); return;
}
++aSttIdx;
} elseif( pDestNd )
{ if( rPos.GetContentIndex() )
{ if( rPos.GetContentIndex() == pDestNd->Len() )
{
++rPos.nNode;
} elseif( rPos.GetContentIndex() )
{ // if the EndNode is split than correct the EndIdx constbool bCorrEnd = aEndIdx == rPos.nNode;
// if no text is attached to the TextNode, split it if( rNodes.IsDocNodes() )
{
SwDoc& rInsDoc = pDestNd->GetDoc();
::sw::UndoGuard const ug(rInsDoc.GetIDocumentUndoRedo());
rInsDoc.getIDocumentContentOperations().SplitNode( rPos, false );
} else
{
pDestNd->SplitContentNode(rPos, nullptr);
}
if ( bCorrEnd )
{
--aEndIdx;
}
}
} // at the end only an empty TextNode is left over
bSplitDestNd = true;
}
SwTextNode* const pEndSrcNd = aEndIdx.GetNode().GetTextNode(); if ( pEndSrcNd )
{ // at the end of this range a new TextNode will be created if( !bSplitDestNd )
{ if( rPos.GetNode() < rNodes.GetEndOfContent() )
{
++rPos.nNode;
}
if (pDestNd && pEnd->GetContentIndex())
{ // move the content into the new node
SwContentIndex aIdx( pEndSrcNd, 0 );
pEndSrcNd->CutText( pDestNd, rPos.nContent, aIdx,
pEnd->GetContentIndex());
}
if( aEndIdx != aSttIdx )
{ // move the nodes into the NodesArray const SwNodeOffset nSttDiff = aSttIdx.GetIndex() - pStart->GetNodeIndex();
SwNodeRange aRg( aSttIdx, aEndIdx );
MoveNodes( aRg, rNodes, rPos.GetNode() );
// if in the same node array, all indices are now at new positions (so correct them) if( &rNodes == this )
{
pStart->nNode = aRg.aEnd.GetIndex() - nSttDiff;
}
}
// if the StartNode was moved to whom the cursor pointed, so // the content must be registered in the current content! if ( pStart->GetNode() == GetEndOfContent() )
{ constbool bSuccess = GoPrevious( &pStart->nNode );
OSL_ENSURE( bSuccess, "Move() - no ContentNode here" );
}
pStart->nContent.Assign( pStart->GetNode().GetContentNode(),
pStart->GetContentIndex() ); // Correct the PaM, because it might have happened that the move // went over the node borders (so the data might be in different nodes). // Also, a selection is invalidated.
*pEnd = *pStart;
rPam.DeleteMark();
GetDoc().GetDocShell()->Broadcast( SwFormatFieldHint( nullptr,
rNodes.IsDocNodes() ? SwFormatFieldHintWhich::INSERTED : SwFormatFieldHintWhich::REMOVED ) );
}
if (SwNodeOffset(0) == nIsEndOfContent)
{ // if aEnd-1 points to no ContentNode, search previous one
--aRg.aEnd; // #i107142#: if aEnd is start node of a special section, do nothing. // Otherwise this could lead to crash: going through all previous // special section nodes and then one before the first. if (aRg.aEnd.GetNode().StartOfSectionIndex() != SwNodeOffset(0))
{ while( ((pCurrentNode = & aRg.aEnd.GetNode())->GetStartNode() &&
!pCurrentNode->IsSectionNode() ) ||
( pCurrentNode->IsEndNode() &&
SwNodeType::Start == pCurrentNode->m_pStartOfSection->GetNodeType()) )
{
--aRg.aEnd;
}
}
++aRg.aEnd;
}
// is there anything left to copy? if( aRg.aStart >= aRg.aEnd ) return;
// when inserting into the source range, nothing need to be done
assert(&aRg.aStart.GetNodes() == this);
assert(&aRg.aStart.GetNodes() == &aRg.aEnd.GetNodes());
--> --------------------
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.