blob: af55e09e40b1ce8b7eeea9171587b97a7965cda8 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include <stdlib.h>
#include <node.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <pam.hxx>
#include <txtfld.hxx>
#include <fmtfld.hxx>
#include <hints.hxx>
#include <numrule.hxx>
#include <ndtxt.hxx>
#include <ndnotxt.hxx>
#include <swtable.hxx> // fuer erzuegen / loeschen der Table-Frames
#include <tblsel.hxx>
#include <section.hxx>
#include <ddefld.hxx>
#include <swddetbl.hxx>
#include <frame.hxx>
#include <txtatr.hxx>
#include <tox.hxx> // InvalidateTOXMark
#include <docsh.hxx>
#include <svl/smplhint.hxx>
extern sal_Bool CheckNodesRange( const SwNodeIndex& rStt,
const SwNodeIndex& rEnd, sal_Bool bChkSection );
SV_DECL_PTRARR(SwSttNdPtrs,SwStartNode*,2,2)
//#define JP_DEBUG
#ifdef JP_DEBUG
#include "shellio.hxx"
#endif
// Funktion zum bestimmen des hoechsten Levels innerhalb des Bereiches
sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange );
//-----------------------------------------------------------------------
/*******************************************************************
|* SwNodes::SwNodes
|*
|* Beschreibung
|* Konstruktor; legt die vier Grundsektions (PostIts,
|* Inserts, Icons, Inhalt) an
*******************************************************************/
SwNodes::SwNodes( SwDoc* pDocument )
: pRoot( 0 ), pMyDoc( pDocument )
{
bInNodesDel = bInDelUpdOutl = bInDelUpdNum = sal_False;
ASSERT( pMyDoc, "in welchem Doc stehe ich denn?" );
sal_uLong nPos = 0;
SwStartNode* pSttNd = new SwStartNode( *this, nPos++ );
pEndOfPostIts = new SwEndNode( *this, nPos++, *pSttNd );
SwStartNode* pTmp = new SwStartNode( *this, nPos++ );
pEndOfInserts = new SwEndNode( *this, nPos++, *pTmp );
pTmp = new SwStartNode( *this, nPos++ );
pTmp->pStartOfSection = pSttNd;
pEndOfAutotext = new SwEndNode( *this, nPos++, *pTmp );
pTmp = new SwStartNode( *this, nPos++ );
pTmp->pStartOfSection = pSttNd;
pEndOfRedlines = new SwEndNode( *this, nPos++, *pTmp );
pTmp = new SwStartNode( *this, nPos++ );
pTmp->pStartOfSection = pSttNd;
pEndOfContent = new SwEndNode( *this, nPos++, *pTmp );
pOutlineNds = new SwOutlineNodes;
}
/*******************************************************************
|*
|* SwNodes::~SwNodes
|*
|* Beschreibung
|* dtor, loescht alle Nodes, deren Pointer in diesem dynamischen
|* Array sind. Ist kein Problem, da Nodes ausserhalb dieses
|* Arrays nicht erzeugt werden koennen und somit auch nicht
|* in mehreren drin sein koennen
|*
|* Ersterstellung
|* VER0100 vb 901214
|*
|* Stand
|* VER0100 vb 901214
|*
*******************************************************************/
SwNodes::~SwNodes()
{
delete pOutlineNds;
{
SwNode *pNode;
SwNodeIndex aNdIdx( *this );
while( sal_True )
{
pNode = &aNdIdx.GetNode();
if( pNode == pEndOfContent )
break;
aNdIdx++;
delete pNode;
}
}
// jetzt muessen alle SwNodeIndizies abgemeldet sein!!!
delete pEndOfContent;
}
void SwNodes::ChgNode( SwNodeIndex& rDelPos, sal_uLong nSz,
SwNodeIndex& rInsPos, sal_Bool bNewFrms )
{
// im UndoBereich brauchen wir keine Frames
SwNodes& rNds = rInsPos.GetNodes();
const SwNode* pPrevInsNd = rNds[ rInsPos.GetIndex() -1 ];
//JP 03.02.99: alle Felder als invalide erklaeren, aktu. erfolgt im
// Idle-Handler des Docs
if( GetDoc()->SetFieldsDirty( sal_True, &rDelPos.GetNode(), nSz ) &&
rNds.GetDoc() != GetDoc() )
rNds.GetDoc()->SetFieldsDirty( true, NULL, 0 );
//JP 12.03.99: 63293 - Nodes vom RedlineBereich NIE aufnehmen
sal_uLong nNd = rInsPos.GetIndex();
sal_Bool bInsOutlineIdx = !(
rNds.GetEndOfRedlines().StartOfSectionNode()->GetIndex() < nNd &&
nNd < rNds.GetEndOfRedlines().GetIndex() );
if( &rNds == this ) // im gleichen Nodes-Array -> moven !!
{
// wird von vorne nach hinten gemovt, so wird nach vorne immer
// nachgeschoben, d.H. die Loeschposition ist immer gleich
sal_uInt16 nDiff = rDelPos.GetIndex() < rInsPos.GetIndex() ? 0 : 1;
for( sal_uLong n = rDelPos.GetIndex(); nSz; n += nDiff, --nSz )
{
SwNodeIndex aDelIdx( *this, n );
SwNode& rNd = aDelIdx.GetNode();
// --> OD 2005-11-16 #i57920#
// correction of refactoring done by cws swnumtree:
// - <SwTxtNode::SetLevel( NO_NUMBERING ) is deprecated and
// set <IsCounted> state of the text node to <false>, which
// isn't correct here.
if ( rNd.IsTxtNode() )
{
SwTxtNode* pTxtNode = rNd.GetTxtNode();
pTxtNode->RemoveFromList();
//if ( pTxtNode->GetTxtColl()->GetOutlineLevel() != NO_NUMBERING )//#outline level,zhaojianwei
if ( pTxtNode->GetAttrOutlineLevel() != 0 )//<-end,zhaojianwei
{
const SwNodePtr pSrch = (SwNodePtr)&rNd;
pOutlineNds->Remove( pSrch );
}
}
// <--
BigPtrArray::Move( aDelIdx.GetIndex(), rInsPos.GetIndex() );
if( rNd.IsTxtNode() )
{
SwTxtNode& rTxtNd = (SwTxtNode&)rNd;
rTxtNd.AddToList();
if( bInsOutlineIdx &&
//NO_NUMBERING != rTxtNd.GetTxtColl()->GetOutlineLevel() )//#outline level,zhaojianwei
0 != rTxtNd.GetAttrOutlineLevel() )//<-end,zhaojianwei
{
const SwNodePtr pSrch = (SwNodePtr)&rNd;
pOutlineNds->Insert( pSrch );
}
rTxtNd.InvalidateNumRule();
//FEATURE::CONDCOLL
if( RES_CONDTXTFMTCOLL == rTxtNd.GetTxtColl()->Which() )
rTxtNd.ChkCondColl();
//FEATURE::CONDCOLL
}
else if( rNd.IsCntntNode() )
((SwCntntNode&)rNd).InvalidateNumRule();
}
}
else
{
bool bSavePersData(GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(rNds));
bool bRestPersData(GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(*this));
SwDoc* pDestDoc = rNds.GetDoc() != GetDoc() ? rNds.GetDoc() : 0;
OSL_ENSURE(!pDestDoc, "SwNodes::ChgNode(): "
"the code to handle text fields here looks broken\n"
"if the target is in a different document.");
if( !bRestPersData && !bSavePersData && pDestDoc )
bSavePersData = bRestPersData = sal_True;
String sNumRule;
SwNodeIndex aInsPos( rInsPos );
for( sal_uLong n = 0; n < nSz; n++ )
{
SwNode* pNd = &rDelPos.GetNode();
// NoTextNode muessen ihre Persitenten Daten mitnehmen
if( pNd->IsNoTxtNode() )
{
if( bSavePersData )
((SwNoTxtNode*)pNd)->SavePersistentData();
}
else if( pNd->IsTxtNode() )
{
SwTxtNode* pTxtNd = (SwTxtNode*)pNd;
// loesche die Gliederungs-Indizies aus dem alten Nodes-Array
//if( NO_NUMBERING != pTxtNd->GetTxtColl()->GetOutlineLevel() )//#outline level,zhaojianwei
if( 0 != pTxtNd->GetAttrOutlineLevel() )//<-end,zhaojianwei
pOutlineNds->Remove( pNd );
// muss die Rule kopiere werden?
if( pDestDoc )
{
const SwNumRule* pNumRule = pTxtNd->GetNumRule();
if( pNumRule && sNumRule != pNumRule->GetName() )
{
sNumRule = pNumRule->GetName();
SwNumRule* pDestRule = pDestDoc->FindNumRulePtr( sNumRule );
if( pDestRule )
pDestRule->SetInvalidRule( sal_True );
else
pDestDoc->MakeNumRule( sNumRule, pNumRule );
}
}
else
// wenns ins UndoNodes-Array gemoved wird, sollten die
// Numerierungen auch aktualisiert werden.
pTxtNd->InvalidateNumRule();
pTxtNd->RemoveFromList();
}
RemoveNode( rDelPos.GetIndex(), 1, sal_False ); // Indizies verschieben !!
SwCntntNode * pCNd = pNd->GetCntntNode();
rNds.InsertNode( pNd, aInsPos );
if( pCNd )
{
SwTxtNode* pTxtNd = pCNd->GetTxtNode();
if( pTxtNd )
{
SwpHints * const pHts = pTxtNd->GetpSwpHints();
// setze die OultineNodes im neuen Nodes-Array
//if( bInsOutlineIdx && NO_NUMBERING != //#outline level,removed by zhaojianwei
// pTxtNd->GetTxtColl()->GetOutlineLevel() )
if( bInsOutlineIdx &&
0 != pTxtNd->GetAttrOutlineLevel() ) //#outline level,added by zhaojianwei
{
rNds.pOutlineNds->Insert( pTxtNd );
}
pTxtNd->AddToList();
// Sonderbehandlung fuer die Felder!
if( pHts && pHts->Count() )
{
// this looks fishy if pDestDoc != 0
bool const bToUndo = !pDestDoc &&
GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(rNds);
for( sal_uInt16 i = pHts->Count(); i; )
{
sal_uInt16 nDelMsg = 0;
SwTxtAttr * const pAttr = pHts->GetTextHint( --i );
switch ( pAttr->Which() )
{
case RES_TXTATR_FIELD:
case RES_TXTATR_ANNOTATION:
case RES_TXTATR_INPUTFIELD:
{
SwTxtFld* pTxtFld = static_cast<SwTxtFld*>(pAttr);
rNds.GetDoc()->InsDelFldInFldLst( !bToUndo, *pTxtFld );
const SwFieldType* pTyp = pTxtFld->GetFmtFld().GetField()->GetTyp();
if ( RES_POSTITFLD == pTyp->Which() )
{
rNds.GetDoc()->GetDocShell()->Broadcast(
SwFmtFldHint(
&pTxtFld->GetFmtFld(),
( pTxtFld->GetFmtFld().IsFldInDoc()
? SWFMTFLD_INSERTED
: SWFMTFLD_REMOVED ) ) );
}
else
if( RES_DDEFLD == pTyp->Which() )
{
if( bToUndo )
((SwDDEFieldType*)pTyp)->DecRefCnt();
else
((SwDDEFieldType*)pTyp)->IncRefCnt();
}
nDelMsg = RES_FIELD_DELETED;
}
break;
case RES_TXTATR_FTN:
nDelMsg = RES_FOOTNOTE_DELETED;
break;
case RES_TXTATR_TOXMARK:
static_cast<SwTOXMark&>(pAttr->GetAttr())
.InvalidateTOXMark();
break;
case RES_TXTATR_REFMARK:
nDelMsg = RES_REFMARK_DELETED;
break;
case RES_TXTATR_META:
case RES_TXTATR_METAFIELD:
{
SwTxtMeta *const pTxtMeta(
static_cast<SwTxtMeta*>(pAttr));
// force removal of UNO object
pTxtMeta->ChgTxtNode(0);
pTxtMeta->ChgTxtNode(pTxtNd);
}
break;
default:
break;
}
if( nDelMsg && bToUndo )
{
SwPtrMsgPoolItem aMsgHint( nDelMsg,
(void*)&pAttr->GetAttr() );
rNds.GetDoc()->GetUnoCallBack()->
ModifyNotification( &aMsgHint, &aMsgHint );
}
}
}
//FEATURE::CONDCOLL
if( RES_CONDTXTFMTCOLL == pTxtNd->GetTxtColl()->Which() )
pTxtNd->ChkCondColl();
//FEATURE::CONDCOLL
}
else
{
// in unterschiedliche Docs gemoved ?
// dann die Daten wieder persistent machen
if( pCNd->IsNoTxtNode() && bRestPersData )
((SwNoTxtNode*)pCNd)->RestorePersistentData();
}
}
}
}
//JP 03.02.99: alle Felder als invalide erklaeren, aktu. erfolgt im
// Idle-Handler des Docs
GetDoc()->SetFieldsDirty( true, NULL, 0 );
if( rNds.GetDoc() != GetDoc() )
rNds.GetDoc()->SetFieldsDirty( true, NULL, 0 );
if( bNewFrms )
bNewFrms = &GetDoc()->GetNodes() == (const SwNodes*)&rNds &&
GetDoc()->GetCurrentViewShell(); //swmod 071108//swmod 071225
if( bNewFrms )
{
// Frames besorgen:
SwNodeIndex aIdx( *pPrevInsNd, 1 );
SwNodeIndex aFrmNdIdx( aIdx );
SwNode* pFrmNd = rNds.FindPrvNxtFrmNode( aFrmNdIdx,
rNds[ rInsPos.GetIndex() - 1 ] );
if( !pFrmNd && aFrmNdIdx > rNds.GetEndOfExtras().GetIndex() )
{
ASSERT( !this, "ob das so richtig ist ??" );
aFrmNdIdx = rNds.GetEndOfContent();
pFrmNd = rNds.GoPrevSection( &aFrmNdIdx, sal_True, sal_False );
if( pFrmNd && !((SwCntntNode*)pFrmNd)->GetDepends() )
pFrmNd = 0;
#ifdef DBG_UTIL
if( !pFrmNd )
ASSERT( !this, "ChgNode() - kein FrameNode gefunden" );
#endif
}
if( pFrmNd )
while( aIdx != rInsPos )
{
SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
if( pCNd )
{
if( pFrmNd->IsTableNode() )
((SwTableNode*)pFrmNd)->MakeFrms( aIdx );
else if( pFrmNd->IsSectionNode() )
((SwSectionNode*)pFrmNd)->MakeFrms( aIdx );
else
((SwCntntNode*)pFrmNd)->MakeFrms( *pCNd );
pFrmNd = pCNd;
}
aIdx++;
}
}
}
/***********************************************************************
|*
|* SwNodes::Move
|*
|* Beschreibung
|* Move loescht die Node-Pointer ab und einschliesslich der Startposition
|* bis zu und ausschliesslich der Endposition und fuegt sie an
|* der vor der Zielposition ein.
|* Wenn das Ziel vor dem ersten oder dem letzten zu bewegenden Element oder
|* dazwischen liegt, geschieht nichts.
|* Wenn der zu bewegende Bereich leer ist oder das Ende vor
|* dem Anfang liegt, geschieht nichts.
|*
|* Allg.: aRange beschreibt den Bereich -exklusive- aEnd !!
|* ( 1.Node: aStart, letzer Node: aEnd-1 !! )
|*
|*
|*
***********************************************************************/
sal_Bool SwNodes::_MoveNodes( const SwNodeRange& aRange, SwNodes & rNodes,
const SwNodeIndex& aIndex, sal_Bool bNewFrms )
{
SwNode * pAktNode;
if( aIndex == 0 ||
( (pAktNode = &aIndex.GetNode())->GetStartNode() &&
!pAktNode->StartOfSectionIndex() ))
return sal_False;
SwNodeRange aRg( aRange );
// "einfache" StartNodes oder EndNodes ueberspringen
while( ND_STARTNODE == (pAktNode = &aRg.aStart.GetNode())->GetNodeType()
|| ( pAktNode->IsEndNode() &&
!pAktNode->pStartOfSection->IsSectionNode() ) )
aRg.aStart++;
aRg.aStart--;
// falls aEnd-1 auf keinem ContentNode steht, dann suche den vorherigen
aRg.aEnd--;
while( ( (( pAktNode = &aRg.aEnd.GetNode())->GetStartNode() &&
!pAktNode->IsSectionNode() ) ||
( pAktNode->IsEndNode() &&
ND_STARTNODE == pAktNode->pStartOfSection->GetNodeType()) ) &&
aRg.aEnd > aRg.aStart )
aRg.aEnd--;
// wird im selben Array's verschoben, dann ueberpruefe die Einfuegepos.
if( aRg.aStart >= aRg.aEnd )
return sal_False;
if( this == &rNodes )
{
if( ( aIndex.GetIndex()-1 >= aRg.aStart.GetIndex() &&
aIndex.GetIndex()-1 < aRg.aEnd.GetIndex()) ||
( aIndex.GetIndex()-1 == aRg.aEnd.GetIndex() ) )
return sal_False;
}
sal_uInt16 nLevel = 0; // Level-Counter
sal_uLong nInsPos = 0; // Cnt fuer das TmpArray
// das Array bildet einen Stack, es werden alle StartOfSelction's gesichert
SwSttNdPtrs aSttNdStack( 1, 5 );
// setze den Start-Index
SwNodeIndex aIdx( aIndex );
/*
--- JP 17.11.94: sollte ueberholt sein, wird im ChgNode schon erledigt!
sal_Bool bCorrNum = pSect && pSect->aStart.GetIndex() == aIdx.GetIndex();
*/
SwStartNode* pStartNode = aIdx.GetNode().pStartOfSection;
aSttNdStack.C40_INSERT( SwStartNode, pStartNode, 0 );
// aSttNdStack.Insert( rNodes[ aIdx ]->pStartOfSection, 0 );
SwNodeRange aOrigInsPos( aIdx, -1, aIdx ); // Originale Insert Pos
//JP 16.01.98: SectionNodes: DelFrms/MakeFrms beim obersten SectionNode!
sal_uInt16 nSectNdCnt = 0;
sal_Bool bSaveNewFrms = bNewFrms;
// Check that the range of nodes to move is valid.
// This is a very specific test that only checks that table nodes
// are completely covered by the range. Issue 121479 has a
// document for which this test fails.
SwNodeIndex aNodeIndex (aRg.aEnd);
while (aNodeIndex > aRg.aStart)
{
SwNode& rNode (aNodeIndex.GetNode());
if (rNode.GetNodeType() != ND_ENDNODE)
break;
SwStartNode* pStartNode = rNode.pStartOfSection;
if (pStartNode==NULL)
break;
if ( ! pStartNode->IsTableNode())
break;
aNodeIndex = *pStartNode;
if (aNodeIndex < aRg.aStart.GetIndex())
{
return sal_False;
}
--aNodeIndex;
}
// bis alles verschoben ist
while( aRg.aStart < aRg.aEnd )
switch( (pAktNode = &aRg.aEnd.GetNode())->GetNodeType() )
{
case ND_ENDNODE:
{
if( nInsPos ) // verschieb schon mal alle bis hier her
{
// loeschen und kopieren. ACHTUNG: die Indizies ab
// "aRg.aEnd+1" werden mit verschoben !!
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
aIdx -= nInsPos;
nInsPos = 0;
}
SwStartNode* pSttNd = pAktNode->pStartOfSection;
if( pSttNd->IsTableNode() )
{
SwTableNode* pTblNd = (SwTableNode*)pSttNd;
// dann bewege die gesamte Tabelle/den Bereich !!
nInsPos = (aRg.aEnd.GetIndex() -
pSttNd->GetIndex() )+1;
aRg.aEnd -= nInsPos;
//JP 12.03.99: 63293 - Nodes vom RedlineBereich NIE aufnehmen
sal_uLong nNd = aIdx.GetIndex();
sal_Bool bInsOutlineIdx = !( rNodes.GetEndOfRedlines().
StartOfSectionNode()->GetIndex() < nNd &&
nNd < rNodes.GetEndOfRedlines().GetIndex() );
if( bNewFrms )
// loesche erstmal die Frames
pTblNd->DelFrms();
if( &rNodes == this ) // in sich selbst moven ??
{
// dann bewege alle Start/End/ContentNodes. Loesche
// bei den ContentNodes auch die Frames !!
pTblNd->pStartOfSection = aIdx.GetNode().pStartOfSection;
for( sal_uLong n = 0; n < nInsPos; ++n )
{
SwNodeIndex aMvIdx( aRg.aEnd, 1 );
SwCntntNode* pCNd = 0;
SwNode* pTmpNd = &aMvIdx.GetNode();
if( pTmpNd->IsCntntNode() )
{
pCNd = (SwCntntNode*)pTmpNd;
if( pTmpNd->IsTxtNode() )
((SwTxtNode*)pTmpNd)->RemoveFromList();
// if( bNewFrms )
// pCNd->DelFrms();
// setze bei Start/EndNodes die richtigen Indizies
// loesche die Gliederungs-Indizies aus
// dem alten Nodes-Array
//if( pCNd->IsTxtNode() && NO_NUMBERING != //#outline level,zhaojianwei
// ((SwTxtNode*)pCNd)->GetTxtColl()->GetOutlineLevel() )
if( pCNd->IsTxtNode() && 0 !=
((SwTxtNode*)pCNd)->GetAttrOutlineLevel() )//<-end,by zhaojianwei
pOutlineNds->Remove( pCNd );
else
pCNd = 0;
}
// else if( bNewFrms && pTmpNd->IsSectionNode() )
// ((SwSectionNode*)pTmpNd)->DelFrms();
BigPtrArray::Move( aMvIdx.GetIndex(), aIdx.GetIndex() );
if( bInsOutlineIdx && pCNd )
pOutlineNds->Insert( pCNd );
if( pTmpNd->IsTxtNode() )
((SwTxtNode*)pTmpNd)->AddToList();
}
}
else
{
// StartNode holen
// Even aIdx points to a startnode, we need the startnode
// of the environment of aIdx (#i80941)
SwStartNode* pSttNode = aIdx.GetNode().pStartOfSection;
// Hole alle Boxen mit Inhalt. Deren Indizies auf die
// StartNodes muessen umgemeldet werden !!
// (Array kopieren und alle gefunden wieder loeschen;
// erleichtert das suchen!!)
SwNodeIndex aMvIdx( aRg.aEnd, 1 );
for( sal_uLong n = 0; n < nInsPos; ++n )
{
SwNode* pNd = &aMvIdx.GetNode();
/* if( bNewFrms )
{
if( pNd->IsCntntNode() )
((SwCntntNode*)pNd)->DelFrms();
else if( pNd->IsSectionNode() )
((SwSectionNode*)pNd)->DelFrms();
}
*/
//sal_Bool bOutlNd = pNd->IsTxtNode() && NO_NUMBERING !=//#outline level,zhaojianwei
// ((SwTxtNode*)pNd)->GetTxtColl()->GetOutlineLevel();
const bool bOutlNd = pNd->IsTxtNode() &&
0 != ((SwTxtNode*)pNd)->GetAttrOutlineLevel();//<-end,zhaojianwei
// loesche die Gliederungs-Indizies aus
// dem alten Nodes-Array
if( bOutlNd )
pOutlineNds->Remove( pNd );
RemoveNode( aMvIdx.GetIndex(), 1, sal_False );
pNd->pStartOfSection = pSttNode;
rNodes.InsertNode( pNd, aIdx );
// setze bei Start/EndNodes die richtigen Indizies
if( bInsOutlineIdx && bOutlNd )
// und setze sie im neuen Nodes-Array
rNodes.pOutlineNds->Insert( pNd );
else if( pNd->IsStartNode() )
pSttNode = (SwStartNode*)pNd;
else if( pNd->IsEndNode() )
{
pSttNode->pEndOfSection = (SwEndNode*)pNd;
if( pSttNode->IsSectionNode() )
((SwSectionNode*)pSttNode)->NodesArrChgd();
pSttNode = pSttNode->pStartOfSection;
}
}
if( pTblNd->GetTable().IsA( TYPE( SwDDETable ) ))
{
SwDDEFieldType* pTyp = ((SwDDETable&)pTblNd->
GetTable()).GetDDEFldType();
if( pTyp )
{
if( rNodes.IsDocNodes() )
pTyp->IncRefCnt();
else
pTyp->DecRefCnt();
}
}
if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(
rNodes))
{
SwFrmFmt* pTblFmt = pTblNd->GetTable().GetFrmFmt();
SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
pTblFmt );
pTblFmt->ModifyNotification( &aMsgHint, &aMsgHint );
}
}
if( bNewFrms )
{
SwNodeIndex aTmp( aIdx );
pTblNd->MakeFrms( &aTmp );
}
aIdx -= nInsPos;
nInsPos = 0;
}
else if( pSttNd->GetIndex() < aRg.aStart.GetIndex() )
{
// SectionNode: es wird nicht die gesamte Section
// verschoben, also bewege nur die
// ContentNodes
// StartNode: erzeuge an der Postion eine neue Section
do { // middle check loop
if( !pSttNd->IsSectionNode() )
{
// Start und EndNode an der InsertPos erzeugen
SwStartNode* pTmp = new SwStartNode( aIdx,
ND_STARTNODE,
/*?? welcher NodeTyp ??*/
SwNormalStartNode );
nLevel++; // den Index auf StartNode auf den Stack
aSttNdStack.C40_INSERT( SwStartNode, pTmp, nLevel );
// noch den EndNode erzeugen
new SwEndNode( aIdx, *pTmp );
}
else if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(
rNodes))
{
// im UndoNodes-Array spendieren wir einen
// Platzhalter
new SwNode( aIdx, ND_SECTIONDUMMY );
}
else
{
// JP 18.5.2001: neue Section anlegen?? Bug 70454
aRg.aEnd--;
break;
}
aRg.aEnd--;
aIdx--;
} while( sal_False );
}
else
{
// Start und EndNode komplett verschieben
// s. u. SwIndex aOldStt( pSttNd->theIndex );
//JP 21.05.97: sollte der Start genau der Start des Bereiches sein, so muss
// der Node auf jedenfall noch besucht werden!
if( &aRg.aStart.GetNode() == pSttNd )
--aRg.aStart;
SwSectionNode* pSctNd = pSttNd->GetSectionNode();
if( bNewFrms && pSctNd )
pSctNd->DelFrms();
RemoveNode( aRg.aEnd.GetIndex(), 1, sal_False ); // EndNode loeschen
sal_uLong nSttPos = pSttNd->GetIndex();
// dieser StartNode wird spaeter wieder entfernt!
SwStartNode* pTmpSttNd = new SwStartNode( *this, nSttPos+1 );
pTmpSttNd->pStartOfSection = pSttNd->pStartOfSection;
RemoveNode( nSttPos, 1, sal_False ); // SttNode loeschen
pSttNd->pStartOfSection = aIdx.GetNode().pStartOfSection;
rNodes.InsertNode( pSttNd, aIdx );
rNodes.InsertNode( pAktNode, aIdx );
aIdx--;
pSttNd->pEndOfSection = (SwEndNode*)pAktNode;
aRg.aEnd--;
nLevel++; // den Index auf StartNode auf den Stack
aSttNdStack.C40_INSERT( SwStartNode, pSttNd, nLevel );
// SectionNode muss noch ein paar Indizies ummelden
if( pSctNd )
{
pSctNd->NodesArrChgd();
++nSectNdCnt;
bNewFrms = sal_False;
}
}
}
break;
case ND_SECTIONNODE:
if( !nLevel &&
GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(rNodes))
{
// dann muss an der akt. InsPos ein SectionDummyNode
// eingefuegt werden
if( nInsPos ) // verschieb schon mal alle bis hier her
{
// loeschen und kopieren. ACHTUNG: die Indizies ab
// "aRg.aEnd+1" werden mit verschoben !!
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
aIdx -= nInsPos;
nInsPos = 0;
}
new SwNode( aIdx, ND_SECTIONDUMMY );
aRg.aEnd--;
aIdx--;
break;
}
// kein break !!
case ND_TABLENODE:
case ND_STARTNODE:
{
// Bug #78589# - empty section -> nothing to do
// and only if it's a top level section
if( !nInsPos && !nLevel )
{
aRg.aEnd--;
break;
}
if( !nLevel ) // es wird eine Stufe runter gestuft
{
// erzeuge die Runterstufung
SwNodeIndex aTmpSIdx( aOrigInsPos.aStart, 1 );
SwStartNode* pTmpStt = new SwStartNode( aTmpSIdx,
ND_STARTNODE,
((SwStartNode*)pAktNode)->GetStartNodeType() );
aTmpSIdx--;
SwNodeIndex aTmpEIdx( aOrigInsPos.aEnd );
new SwEndNode( aTmpEIdx, *pTmpStt );
aTmpEIdx--;
aTmpSIdx++;
// setze die StartOfSection richtig
aRg.aEnd++;
{
SwNodeIndex aCntIdx( aRg.aEnd );
for( sal_uLong n = 0; n < nInsPos; n++, aCntIdx++)
aCntIdx.GetNode().pStartOfSection = pTmpStt;
}
// Setze auch bei allen runtergestuften den richtigen StartNode
while( aTmpSIdx < aTmpEIdx )
if( 0 != (( pAktNode = &aTmpEIdx.GetNode())->GetEndNode()) )
aTmpEIdx = pAktNode->StartOfSectionIndex();
else
{
pAktNode->pStartOfSection = pTmpStt;
aTmpEIdx--;
}
aIdx--; // hinter den eingefuegten StartNode
aRg.aEnd--; // vor den StartNode
// kopiere jetzt das Array. ACHTUNG: die Indizies ab
// "aRg.aEnd+1" werden mit verschoben !!
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
aIdx -= nInsPos+1;
nInsPos = 0;
}
else // es wurden alle Nodes innerhalb eines
{ // Start- und End-Nodes verschoben
ASSERT( pAktNode == aSttNdStack[nLevel] ||
( pAktNode->IsStartNode() &&
aSttNdStack[nLevel]->IsSectionNode()),
"falscher StartNode" );
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
aIdx -= nInsPos+1; // vor den eingefuegten StartNode
nInsPos = 0;
// loesche nur noch den Pointer aus dem Nodes-Array.
// RemoveNode( aRg.aEnd.GetIndex(), 1, sal_False );
RemoveNode( aRg.aEnd.GetIndex(), 1, sal_True );
aRg.aEnd--;
SwSectionNode* pSectNd = aSttNdStack[ nLevel ]->GetSectionNode();
if( pSectNd && !--nSectNdCnt )
{
SwNodeIndex aTmp( *pSectNd );
pSectNd->MakeFrms( &aTmp );
bNewFrms = bSaveNewFrms;
}
aSttNdStack.Remove( nLevel ); // vom Stack loeschen
nLevel--;
}
// loesche alle entstehenden leeren Start-/End-Node-Paare
SwNode* pTmpNode = (*this)[ aRg.aEnd.GetIndex()+1 ]->GetEndNode();
if( pTmpNode && ND_STARTNODE == (pAktNode = &aRg.aEnd.GetNode())
->GetNodeType() && pAktNode->StartOfSectionIndex() &&
pTmpNode->StartOfSectionNode() == pAktNode )
{
DelNodes( aRg.aEnd, 2 );
aRg.aEnd--;
}
// aRg.aEnd--;
}
break;
case ND_TEXTNODE:
//Solution:Add special function to text node.
{
if( bNewFrms && pAktNode->GetCntntNode() )
((SwCntntNode*)pAktNode)->DelFrms( sal_False );
pAktNode->pStartOfSection = aSttNdStack[ nLevel ];
nInsPos++;
aRg.aEnd--;
}
break;
case ND_GRFNODE:
case ND_OLENODE:
{
if( bNewFrms && pAktNode->GetCntntNode() )
((SwCntntNode*)pAktNode)->DelFrms();
pAktNode->pStartOfSection = aSttNdStack[ nLevel ];
nInsPos++;
aRg.aEnd--;
}
break;
case ND_SECTIONDUMMY:
if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(*this))
{
if( &rNodes == this ) // innerhalb vom UndoNodesArray
{
// mit verschieben
pAktNode->pStartOfSection = aSttNdStack[ nLevel ];
nInsPos++;
}
else // in ein "normales" Nodes-Array verschieben
{
// dann muss an der akt. InsPos auch ein SectionNode
// (Start/Ende) stehen; dann diesen ueberspringen.
// Andernfalls nicht weiter beachten.
if( nInsPos ) // verschieb schon mal alle bis hier her
{
// loeschen und kopieren. ACHTUNG: die Indizies ab
// "aRg.aEnd+1" werden mit verschoben !!
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
aIdx -= nInsPos;
nInsPos = 0;
}
SwNode* pTmpNd = &aIdx.GetNode();
if( pTmpNd->IsSectionNode() ||
pTmpNd->StartOfSectionNode()->IsSectionNode() )
aIdx--; // ueberspringen
}
}
else {
ASSERT( sal_False, "wie kommt diser Node ins Nodes-Array??" );
}
aRg.aEnd--;
break;
default:
ASSERT( sal_False, "was ist das fuer ein Node??" );
break;
}
if( nInsPos ) // kopiere den Rest
{
// der Rest muesste so stimmen
SwNodeIndex aSwIndex( aRg.aEnd, 1 );
ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
}
aRg.aEnd++; // wieder exklusive Ende
// loesche alle leeren Start-/End-Node-Paare
if( ( pAktNode = &aRg.aStart.GetNode())->GetStartNode() &&
pAktNode->StartOfSectionIndex() &&
aRg.aEnd.GetNode().GetEndNode() )
DelNodes( aRg.aStart, 2 );
// rufe jetzt noch das Update fuer die Gliederung/Nummerierung auf
aOrigInsPos.aStart++;
// im gleichen Nodes-Array verschoben ??,
// dann von oben nach unten das Update aufrufen !!
if( this == &rNodes &&
aRg.aEnd.GetIndex() >= aOrigInsPos.aStart.GetIndex() )
{
UpdtOutlineIdx( aOrigInsPos.aStart.GetNode() );
UpdtOutlineIdx( aRg.aEnd.GetNode() );
}
else
{
UpdtOutlineIdx( aRg.aEnd.GetNode() );
rNodes.UpdtOutlineIdx( aOrigInsPos.aStart.GetNode() );
}
#ifdef JP_DEBUG
{
extern Writer* GetDebugWriter(const String&);
Writer* pWriter = GetDebugWriter(aEmptyStr);
if( pWriter )
{
int nError;
SvFileStream aStrm( "c:\\$$move.db", STREAM_WRITE );
SwWriter aWriter( aStrm, *pMyDoc );
aWriter.Write( &nError, pWriter );
}
}
#endif
return sal_True;
}
/*******************************************************************
|*
|* SwNodes::SectionDown
|*
|* Beschreibung
|* SectionDown() legt ein Paar von Start- und EndSection-Node
|* (andere Nodes koennen dazwischen liegen) an.
|*
|* Zustand des SRange beim Verlassen der Funktion: nStart ist der
|* Index des ersten Node hinter dem Start Section Node, nEnd ist
|* der Index des End Section Nodes. Beispiel: Wird Insert Section
|* mehrmals hintereinander aufgerufen, so werden mehrere
|* unmittelbar geschachtelte Sections (keine Content Nodes
|* zwischen Start- bzw. End Nodes) angelegt.
|*
|* Allg.: aRange beschreibt den Bereich -exklusive- aEnd !!
|* ( 1.Node: aStart, letzer Node: aEnd-1 !! )
|*
|* Parameter
|* SwRange &rRange
|* IO:
|* IN
|* rRange.aStart: Einfuegeposition des StartNodes
|* rRange.aEnd: Einfuegeposition des EndNodes
|* OUT
|* rRange.aStart: steht hinter dem eingefuegten Startnode
|* rRange.aEnd: steht auf dem eingefuegen Endnode
|*
|* Ausnahmen
|* 1. SRange-Anfang und SRange-Ende muessen auf dem gleichen Level sein
|* 2. duerfen nicht auf dem obersten Level sein
|* Ist dies nicht der Fall, wird die
|* Funktion durch Aufruf von ERR_RAISE verlassen.
|*
|* Debug-Funktionen
|* die Debugging Tools geben rRange beim Eintritt und beim
|* Verlassen der Funktion aus
|*
|* Ersterstellung
|* VER0100 vb 901214
|*
|* Stand
|* VER0100 vb 901214
|*
*******************************************************************/
void SwNodes::SectionDown(SwNodeRange *pRange, SwStartNodeType eSttNdTyp )
{
if( pRange->aStart >= pRange->aEnd ||
pRange->aEnd >= Count() ||
!CheckNodesRange( pRange->aStart, pRange->aEnd ))
return;
// Ist der Anfang vom Bereich vor oder auf einem EndNode, so loesche
// diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes enstehen.
// Bei anderen Nodes wird eine neuer StartNode eingefuegt
SwNode * pAktNode = &pRange->aStart.GetNode();
SwNodeIndex aTmpIdx( *pAktNode->StartOfSectionNode() );
if( pAktNode->GetEndNode() )
DelNodes( pRange->aStart, 1 ); // verhinder leere Section
else
{
// fuege einen neuen StartNode ein
SwNode* pSttNd = new SwStartNode( pRange->aStart, ND_STARTNODE, eSttNdTyp );
pRange->aStart = *pSttNd;
aTmpIdx = pRange->aStart;
}
// Ist das Ende vom Bereich vor oder auf einem StartNode, so loesche
// diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes enstehen
// Bei anderen Nodes wird eine neuer EndNode eingefuegt
pRange->aEnd--;
if( pRange->aEnd.GetNode().GetStartNode() )
DelNodes( pRange->aEnd, 1 );
else
{
pRange->aEnd++;
// fuege einen neuen EndNode ein
new SwEndNode( pRange->aEnd, *pRange->aStart.GetNode().GetStartNode() );
}
pRange->aEnd--;
SectionUpDown( aTmpIdx, pRange->aEnd );
}
/*******************************************************************
|*
|* SwNodes::SectionUp
|*
|* Beschreibung
|* Der von rRange umspannte Bereich wird auf die naechst hoehere
|* Ebene gehoben. Das geschieht dadurch, dass bei
|* rRange.aStart ein Endnode und bei rRange.aEnd ein
|* Startnode eingefuegt wird. Die Indices fuer den Bereich
|* innerhalb von rRange werden geupdated.
|*
|* Allg.: aRange beschreibt den Bereich -exklusive- aEnd !!
|* ( 1.Node: aStart, letzer Node: aEnd-1 !! )
|*
|* Parameter
|* SwRange &rRange
|* IO:
|* IN
|* rRange.aStart: Anfang des hoeher zubewegenden Bereiches
|* rRange.aEnd: der 1.Node hinter dem Bereich
|* OUT
|* rRange.aStart: an der ersten Position innerhalb des
|* hochbewegten Bereiches
|* rRange.aEnd: an der letzten Position innerhalb des
|* hochbewegten Bereiches
|*
|* Debug-Funktionen
|* die Debugging Tools geben rRange beim Eintritt und beim
|* Verlassen der Funktion aus
|*
|* Ersterstellung
|* VER0100 vb 901214
|*
|* Stand
|* VER0100 vb 901214
|*
*******************************************************************/
void SwNodes::SectionUp(SwNodeRange *pRange)
{
if( pRange->aStart >= pRange->aEnd ||
pRange->aEnd >= Count() ||
!CheckNodesRange( pRange->aStart, pRange->aEnd ) ||
!( HighestLevel( *this, *pRange ) > 1 ))
return;
// Ist der Anfang vom Bereich vor oder auf einem StartNode, so loesche
// diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes enstehen.
// Bei anderen Nodes wird eine neuer EndNode eingefuegt
SwNode * pAktNode = &pRange->aStart.GetNode();
SwNodeIndex aIdx( *pAktNode->StartOfSectionNode() );
if( pAktNode->IsStartNode() ) // selbst StartNode
{
SwEndNode* pEndNd = pRange->aEnd.GetNode().GetEndNode();
if( pAktNode == pEndNd->pStartOfSection )
{
// dann wurde paarig aufgehoben, also nur die im Berich neu anpassen
SwStartNode* pTmpSttNd = pAktNode->pStartOfSection;
RemoveNode( pRange->aStart.GetIndex(), 1, sal_True );
RemoveNode( pRange->aEnd.GetIndex(), 1, sal_True );
SwNodeIndex aTmpIdx( pRange->aStart );
while( aTmpIdx < pRange->aEnd )
{
pAktNode = &aTmpIdx.GetNode();
pAktNode->pStartOfSection = pTmpSttNd;
if( pAktNode->IsStartNode() )
aTmpIdx = pAktNode->EndOfSectionIndex() + 1;
else
aTmpIdx++;
}
return ;
}
DelNodes( pRange->aStart, 1 );
}
else if( aIdx == pRange->aStart.GetIndex()-1 ) // vor StartNode
DelNodes( aIdx, 1 );
else
new SwEndNode( pRange->aStart, *aIdx.GetNode().GetStartNode() );
// Ist das Ende vom Bereich vor oder auf einem StartNode, so loesche
// diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes entstehen
// Bei anderen Nodes wird eine neuer EndNode eingefuegt
SwNodeIndex aTmpIdx( pRange->aEnd );
if( pRange->aEnd.GetNode().IsEndNode() )
DelNodes( pRange->aEnd, 1 );
else
{
pAktNode = new SwStartNode( pRange->aEnd );
/*?? welcher NodeTyp ??*/
aTmpIdx = *pRange->aEnd.GetNode().EndOfSectionNode();
pRange->aEnd--;
}
SectionUpDown( aIdx, aTmpIdx );
}
/*************************************************************************
|*
|* SwNodes::SectionUpDown()
|*
|* Beschreibung
|* Methode setzt die Indizies die bei SectionUp oder SectionDwon
|* veraendert wurden wieder richtig, sodass die Ebenen wieder
|* Konsistent sind.
|*
|* Parameter
|* SwIndex & aStart StartNode !!!
|* SwIndex & aEnd EndPunkt
|*
|* Ersterstellung JP 23.04.91
|* Letzte Aenderung JP 23.04.91
|*
*************************************************************************/
void SwNodes::SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd )
{
SwNode * pAktNode;
SwNodeIndex aTmpIdx( aStart, +1 );
// das Array bildet einen Stack, es werden alle StartOfSelction's gesichert
SwSttNdPtrs aSttNdStack( 1, 5 );
SwStartNode* pTmp = aStart.GetNode().GetStartNode();
aSttNdStack.C40_INSERT( SwStartNode, pTmp, 0 );
// durchlaufe bis der erste zu aendernde Start-Node gefunden wurde
// ( Es wird vom eingefuegten EndNode bis nach vorne die Indexe gesetzt )
for( ;; aTmpIdx++ )
{
pAktNode = &aTmpIdx.GetNode();
pAktNode->pStartOfSection = aSttNdStack[ aSttNdStack.Count()-1 ];
if( pAktNode->GetStartNode() )
{
pTmp = (SwStartNode*)pAktNode;
aSttNdStack.C40_INSERT( SwStartNode, pTmp, aSttNdStack.Count() );
}
else if( pAktNode->GetEndNode() )
{
SwStartNode* pSttNd = aSttNdStack[ aSttNdStack.Count() - 1 ];
pSttNd->pEndOfSection = (SwEndNode*)pAktNode;
aSttNdStack.Remove( aSttNdStack.Count() - 1 );
if( aSttNdStack.Count() )
continue; // noch genuegend EndNodes auf dem Stack
else if( aTmpIdx < aEnd ) // Uebergewicht an StartNodes
// ist das Ende noch nicht erreicht, so hole den Start von
// der uebergeordneten Section
{
aSttNdStack.C40_INSERT( SwStartNode, pSttNd->pStartOfSection, 0 );
}
else // wenn ueber den Bereich hinaus, dann Ende
break;
}
}
}
/*******************************************************************
|*
|* SwNodes::Delete
|*
|* Beschreibung
|* Spezielle Implementierung der Delete-Funktion des
|* variablen Array. Diese spezielle Implementierung ist
|* notwendig, da durch das Loeschen von Start- bzw.
|* Endnodes Inkonsistenzen entstehen koennen. Diese werden
|* durch diese Funktion beseitigt.
|*
|* Parameter
|* IN
|* SwIndex &rIndex bezeichnet die Position, an der
|* geloescht wird
|* rIndex ist nach Aufruf der Funktion unveraendert (Kopie?!)
|* sal_uInt16 nNodes bezeichnet die Anzahl der zu loeschenden
|* Nodes; ist auf 1 defaulted
|*
|* Debug-Funktionen
|* geben beim Eintritt in die Funktion Position und Anzahl
|* der zu loeschenden Nodes aus.
|*
|* Ersterstellung
|* VER0100 vb 901214
|*
|* Stand
|* VER0100 vb 901214
|*
*******************************************************************/
void SwNodes::Delete(const SwNodeIndex &rIndex, sal_uLong nNodes)
{
sal_uInt16 nLevel = 0; // Level-Counter
SwNode * pAktNode;
sal_uLong nCnt = Count() - rIndex.GetIndex() - 1;
if( nCnt > nNodes ) nCnt = nNodes;
if( nCnt == 0 ) // keine Anzahl -> return
return;
SwNodeRange aRg( rIndex, 0, rIndex, nCnt-1 );
// ueberprufe ob rIndex..rIndex + nCnt ueber einen Bereich hinausragt !!
if( ( !aRg.aStart.GetNode().StartOfSectionIndex() &&
!aRg.aStart.GetIndex() ) ||
! CheckNodesRange( aRg.aStart, aRg.aEnd ) )
return;
// falls aEnd auf keinem ContentNode steht, dann suche den vorherigen
while( ( pAktNode = &aRg.aEnd.GetNode())->GetStartNode() ||
( pAktNode->GetEndNode() &&
!pAktNode->pStartOfSection->IsTableNode() ))
aRg.aEnd--;
nCnt = 0;
// Start erhoehen, damit auf < abgefragt wird. ( bei <= kann es zu
// Problemen fuehren; ist aEnd == aStart und wird aEnd geloscht,
// so ist aEnd <= aStart
aRg.aStart--;
sal_Bool bSaveInNodesDel = bInNodesDel;
bInNodesDel = sal_True;
sal_Bool bUpdateOutline = sal_False;
// bis alles geloescht ist
while( aRg.aStart < aRg.aEnd )
{
pAktNode = &aRg.aEnd.GetNode();
if( pAktNode->GetEndNode() )
{
// die gesamte Section loeschen ?
if( pAktNode->StartOfSectionIndex() > aRg.aStart.GetIndex() )
{
SwTableNode* pTblNd = pAktNode->pStartOfSection->GetTableNode();
if( pTblNd )
pTblNd->DelFrms();
SwNode *pNd, *pChkNd = pAktNode->pStartOfSection;
sal_uInt16 nIdxPos;
do {
pNd = &aRg.aEnd.GetNode();
if( pNd->IsTxtNode() )
{
//if( NO_NUMBERING != //#outline level,zhaojianwei
// ((SwTxtNode*)pNd)->GetTxtColl()->GetOutlineLevel() &&
if( 0 != ((SwTxtNode*)pNd)->GetAttrOutlineLevel() &&//<-end,zhaojianwei
pOutlineNds->Seek_Entry( pNd, &nIdxPos ))
{
// loesche die Gliederungs-Indizies.
pOutlineNds->Remove( nIdxPos );
bUpdateOutline = sal_True;
}
((SwTxtNode*)pNd)->InvalidateNumRule();
}
else if( pNd->IsEndNode() &&
pNd->pStartOfSection->IsTableNode() )
((SwTableNode*)pNd->pStartOfSection)->DelFrms();
aRg.aEnd--;
nCnt++;
} while( pNd != pChkNd );
}
else
{
RemoveNode( aRg.aEnd.GetIndex()+1, nCnt, sal_True ); // loesche
nCnt = 0;
aRg.aEnd--; // vor den EndNode
nLevel++;
}
}
else if( pAktNode->GetStartNode() ) // StartNode gefunden
{
if( nLevel == 0 ) // es wird eine Stufe runter gestuft
{
if( nCnt )
{
// loesche jetzt das Array
aRg.aEnd++;
RemoveNode( aRg.aEnd.GetIndex(), nCnt, sal_True );
nCnt = 0;
}
}
else // es werden alle Nodes Innerhalb eines Start- und
{ // End-Nodes geloescht, loesche mit Start/EndNode
RemoveNode( aRg.aEnd.GetIndex(), nCnt + 2, sal_True ); // loesche Array
nCnt = 0;
nLevel--;
}
// nach dem loeschen kann aEnd auf einem EndNode stehen
// loesche alle leeren Start-/End-Node-Paare
SwNode* pTmpNode = aRg.aEnd.GetNode().GetEndNode();
aRg.aEnd--;
while( pTmpNode &&
( pAktNode = &aRg.aEnd.GetNode())->GetStartNode() &&
pAktNode->StartOfSectionIndex() )
{
// loesche den EndNode und StartNode
DelNodes( aRg.aEnd, 2 );
pTmpNode = aRg.aEnd.GetNode().GetEndNode();
aRg.aEnd--;
}
}
else // normaler Node, also ins TmpArray einfuegen
{
SwTxtNode* pTxtNd = pAktNode->GetTxtNode();
if( pTxtNd )
{
if( pTxtNd->IsOutline())
{ // loesche die Gliederungs-Indizies.
pOutlineNds->Remove( pTxtNd );
bUpdateOutline = sal_True;
}
pTxtNd->InvalidateNumRule();
}
else if( pAktNode->IsCntntNode() )
((SwCntntNode*)pAktNode)->InvalidateNumRule();
aRg.aEnd--;
nCnt++;
}
}
aRg.aEnd++;
if( nCnt != 0 )
RemoveNode( aRg.aEnd.GetIndex(), nCnt, sal_True ); // loesche den Rest
// loesche alle leeren Start-/End-Node-Paare
while( aRg.aEnd.GetNode().GetEndNode() &&
( pAktNode = &aRg.aStart.GetNode())->GetStartNode() &&
pAktNode->StartOfSectionIndex() )
// aber ja keinen der heiligen 5.
{
DelNodes( aRg.aStart, 2 ); // loesche den Start- und EndNode
aRg.aStart--;
}
bInNodesDel = bSaveInNodesDel;
if( !bInNodesDel )
{
// rufe jetzt noch das Update fuer die Gliederung/Nummerierung auf
if( bUpdateOutline || bInDelUpdOutl )
{
UpdtOutlineIdx( aRg.aEnd.GetNode() );
bInDelUpdOutl = sal_False;
}
}
else
{
if( bUpdateOutline )
bInDelUpdOutl = sal_True;
}
}
/*******************************************************************
|*
|* SwNodes::GetSectionLevel
|*
|* Beschreibung
|* Die Funktion liefert den Sectionlevel an der durch
|* aIndex bezeichneten Position. Die Funktion ruft die
|* GetSectionlevel-Funktion des durch aIndex bezeichneten
|* Nodes. Diese ist eine virtuelle Funktion, die fuer
|* Endnodes speziell implementiert werden musste.
|* Die Sectionlevels werden ermittelt, indem rekursiv durch
|* die Nodesstruktur (jeweils zum naechsten theEndOfSection)
|* gegangen wird, bis die oberste Ebene erreicht ist
|* (theEndOfSection == 0)
|*
|* Parameter
|* aIndex bezeichnet die Position des Nodes, dessen
|* Sectionlevel ermittelt werden soll. Hier wird eine Kopie
|* uebergeben, da eine Veraenderung der Variablen in der
|* rufenden Funktion nicht wuenschenswert ist.
|*
|* Ausnahmen
|* Der erste Node im Array sollte immer ein Startnode sein.
|* Dieser erfaehrt in der Funktion SwNodes::GetSectionLevel()
|* eine Sonderbehandlung; es wird davon ausgegangen, dass der
|* erste Node auch ein Startnode ist.
|*
|* Ersterstellung
|* VER0100 vb 901214
|*
|* Stand
|* VER0100 vb 901214
|*
*******************************************************************/
sal_uInt16 SwNodes::GetSectionLevel(const SwNodeIndex &rIdx) const {
// Sonderbehandlung 1. Node
if(rIdx == 0) return 1;
/*
* Keine Rekursion! - hier wird das SwNode::GetSectionLevel
* aufgerufen
*/
return rIdx.GetNode().GetSectionLevel();
}
void SwNodes::GoStartOfSection(SwNodeIndex *pIdx) const
{
// hinter den naechsten Startnode
SwNodeIndex aTmp( *pIdx->GetNode().StartOfSectionNode(), +1 );
// steht der Index auf keinem ContentNode, dann gehe dahin. Ist aber
// kein weiterer vorhanden, dann lasse den Index an alter Pos stehen !!!
while( !aTmp.GetNode().IsCntntNode() )
{ // gehe vom StartNode ( es kann nur ein StartNode sein ! ) an sein
// Ende
if( *pIdx <= aTmp )
return; // FEHLER: Steht schon hinter der Sektion
aTmp = aTmp.GetNode().EndOfSectionIndex()+1;
if( *pIdx <= aTmp )
return; // FEHLER: Steht schon hinter der Sektion
}
(*pIdx) = aTmp; // steht auf einem ContentNode
}
void SwNodes::GoEndOfSection(SwNodeIndex *pIdx) const
{
// falls er vor einem Endnode steht --> nichts tun
if( !pIdx->GetNode().IsEndNode() )
(*pIdx) = *pIdx->GetNode().EndOfSectionNode();
}
SwCntntNode* SwNodes::GoNext(SwNodeIndex *pIdx) const
{
if( pIdx->GetIndex() >= Count() - 1 )
return 0;
SwNodeIndex aTmp(*pIdx, +1);
SwNode* pNd = 0;
while( aTmp < Count()-1 && 0 == ( pNd = &aTmp.GetNode())->IsCntntNode() )
aTmp++;
if( aTmp == Count()-1 )
pNd = 0;
else
(*pIdx) = aTmp;
return (SwCntntNode*)pNd;
}
SwCntntNode* SwNodes::GoPrevious(SwNodeIndex *pIdx) const
{
if( !pIdx->GetIndex() )
return 0;
SwNodeIndex aTmp( *pIdx, -1 );
SwNode* pNd = 0;
while( aTmp.GetIndex() && 0 == ( pNd = &aTmp.GetNode())->IsCntntNode() )
aTmp--;
if( !aTmp.GetIndex() )
pNd = 0;
else
(*pIdx) = aTmp;
return (SwCntntNode*)pNd;
}
/*************************************************************************
|*
|* sal_Bool SwNodes::CheckNodesRange()
|*
|* Beschreibung
|* Teste ob der uebergene SRange nicht ueber die Grenzen der
|* einzelnen Bereiche (PosIts, Autotext, Content, Icons und Inserts )
|* hinaus reicht.
|* Nach Wahrscheinlichkeit des Ranges sortiert.
|*
|* Alg.: Da festgelegt ist, das aRange.aEnd den 1.Node hinter dem Bereich
|* bezeichnet, wird hier auf aEnd <= End.. getestet !!
|*
|* Parameter SwIndex & Start-Index vom Bereich
|* SwIndex & End-Index vom Bereich
|* sal_Bool sal_True: Start+End in gleicher Section!
|* sal_False: Start+End in verschiedenen Sect.
|* Return-Wert sal_Bool sal_True: gueltiger SRange
|* sal_False: ungueltiger SRange
|*
|* Ersterstellung JP 23.04.91
|* Letzte Aenderung JP 18.06.92
|*
*************************************************************************/
inline int TstIdx( sal_uLong nSttIdx, sal_uLong nEndIdx, sal_uLong nStt, sal_uLong nEnd )
{
return nStt < nSttIdx && nEnd >= nSttIdx &&
nStt < nEndIdx && nEnd >= nEndIdx;
}
sal_Bool SwNodes::CheckNodesRange( const SwNodeIndex& rStt, const SwNodeIndex& rEnd ) const
{
sal_uLong nStt = rStt.GetIndex(), nEnd = rEnd.GetIndex();
if( TstIdx( nStt, nEnd, pEndOfContent->StartOfSectionIndex(),
pEndOfContent->GetIndex() )) return sal_True;
if( TstIdx( nStt, nEnd, pEndOfAutotext->StartOfSectionIndex(),
pEndOfAutotext->GetIndex() )) return sal_True;
if( TstIdx( nStt, nEnd, pEndOfPostIts->StartOfSectionIndex(),
pEndOfPostIts->GetIndex() )) return sal_True;
if( TstIdx( nStt, nEnd, pEndOfInserts->StartOfSectionIndex(),
pEndOfInserts->GetIndex() )) return sal_True;
if( TstIdx( nStt, nEnd, pEndOfRedlines->StartOfSectionIndex(),
pEndOfRedlines->GetIndex() )) return sal_True;
return sal_False; // liegt irgendwo dazwischen, FEHLER
}
/*************************************************************************
|*
|* void SwNodes::DelNodes()
|*
|* Beschreibung
|* Loesche aus den NodesArray ab einer Position entsprechend Node's.
|*
|* Parameter SwIndex & Der Startpunkt im Nodes-Array
|* sal_uInt16 die Anzahl
|*
|* Ersterstellung JP 23.04.91
|* Letzte Aenderung JP 23.04.91
|*
*************************************************************************/
void SwNodes::DelNodes( const SwNodeIndex & rStart, sal_uLong nCnt )
{
int bUpdateNum = 0;
sal_uLong nSttIdx = rStart.GetIndex();
if( !nSttIdx && nCnt == GetEndOfContent().GetIndex()+1 )
{
// es wird das gesamte Nodes-Array zerstoert, man ist im Doc DTOR!
// Die initialen Start-/End-Nodes duerfen nur im SwNodes-DTOR
// zerstoert werden!
SwNode* aEndNdArr[] = { pEndOfContent,
pEndOfPostIts, pEndOfInserts,
pEndOfAutotext, pEndOfRedlines,
0
};
SwNode** ppEndNdArr = aEndNdArr;
while( *ppEndNdArr )
{
nSttIdx = (*ppEndNdArr)->StartOfSectionIndex() + 1;
sal_uLong nEndIdx = (*ppEndNdArr)->GetIndex();
if( nSttIdx != nEndIdx )
RemoveNode( nSttIdx, nEndIdx - nSttIdx, sal_True );
++ppEndNdArr;
}
}
else
{
for( sal_uLong n = nSttIdx, nEnd = nSttIdx + nCnt; n < nEnd; ++n )
{
SwNode* pNd = (*this)[ n ];
if( pNd->IsTxtNode() &&
//NO_NUMBERING != ((SwTxtNode*)pNd)->GetTxtColl()->GetOutlineLevel() )//#outline level,zhaojianwei
0 != ((SwTxtNode*)pNd)->GetAttrOutlineLevel() ) //<-end,zhaojianwei
{ // loesche die Gliederungs-Indizies.
sal_uInt16 nIdxPos;
if( pOutlineNds->Seek_Entry( pNd, &nIdxPos ))
{
pOutlineNds->Remove( nIdxPos );
bUpdateNum = 1;
}
}
if( pNd->IsCntntNode() )
{
((SwCntntNode*)pNd)->InvalidateNumRule();
((SwCntntNode*)pNd)->DelFrms();
}
}
RemoveNode( nSttIdx, nCnt, sal_True );
// rufe noch das Update fuer die Gliederungsnumerierung auf
if( bUpdateNum )
UpdtOutlineIdx( rStart.GetNode() );
}
}
/*************************************************************************
|*
|* sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange )
|*
|* Beschreibung
|* Berechne den hoehsten Level innerhalb des Bereiches
|*
|* Parameter SwNodes & das Node-Array
|* SwNodeRange & der zu ueberpruefende Bereich
|* Return sal_uInt16 der hoechste Level
|*
|* Ersterstellung JP 24.04.91
|* Letzte Aenderung JP 24.04.91
|*
*************************************************************************/
struct HighLevel
{
sal_uInt16 nLevel, nTop;
HighLevel( sal_uInt16 nLv ) : nLevel( nLv ), nTop( nLv ) {}
};
sal_Bool _HighestLevel( const SwNodePtr& rpNode, void * pPara )
{
HighLevel * pHL = (HighLevel*)pPara;
if( rpNode->GetStartNode() )
pHL->nLevel++;
else if( rpNode->GetEndNode() )
pHL->nLevel--;
if( pHL->nTop > pHL->nLevel )
pHL->nTop = pHL->nLevel;
return sal_True;
}
sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange )
{
HighLevel aPara( rNodes.GetSectionLevel( rRange.aStart ));
rNodes.ForEach( rRange.aStart, rRange.aEnd, _HighestLevel, &aPara );
return aPara.nTop;
}
/*************************************************************************
|*
|* SwNodes::Move()
|*
|* Beschreibung
|* Parameter SwPaM& zu kopierender Bereich
|* SwNodes& in dieses Nodes-Array
|* SwPosition& auf diese Position im Nodes-Array
|* Ersterstellung JP 09.07.92
|* Letzte Aenderung JP 09.07.92
|*
*************************************************************************/
void SwNodes::MoveRange( SwPaM & rPam, SwPosition & rPos, SwNodes& rNodes )
{
SwPosition * const pStt = rPam.Start();
SwPosition * const pEnd = rPam.End();
if( !rPam.HasMark() || *pStt >= *pEnd )
return;
if( this == &rNodes && *pStt <= rPos && rPos < *pEnd )
return;
SwNodeIndex aEndIdx( pEnd->nNode );
SwNodeIndex aSttIdx( pStt->nNode );
SwTxtNode *const pSrcNd = aSttIdx.GetNode().GetTxtNode();
SwTxtNode * pDestNd = rPos.nNode.GetNode().GetTxtNode();
sal_Bool bSplitDestNd = sal_True;
sal_Bool bCopyCollFmt = pDestNd && !pDestNd->GetTxt().Len();
if( pSrcNd )
{
// ist der 1.Node ein TextNode, dann muss im NodesArray auch
// ein TextNode vorhanden sein, in den der Inhalt geschoben wird
if( !pDestNd )
{
pDestNd = rNodes.MakeTxtNode( rPos.nNode, pSrcNd->GetTxtColl() );
rPos.nNode--;
rPos.nContent.Assign( pDestNd, 0 );
bCopyCollFmt = sal_True;
}
bSplitDestNd = pDestNd->Len() > rPos.nContent.GetIndex() ||
pEnd->nNode.GetNode().IsTxtNode();
// verschiebe jetzt noch den Inhalt in den neuen Node
sal_Bool bOneNd = pStt->nNode == pEnd->nNode;
const xub_StrLen nLen =
( (bOneNd) ? pEnd->nContent.GetIndex() : pSrcNd->Len() )
- pStt->nContent.GetIndex();
if( !pEnd->nNode.GetNode().IsCntntNode() )
{
bOneNd = sal_True;
sal_uLong nSttNdIdx = pStt->nNode.GetIndex() + 1;
const sal_uLong nEndNdIdx = pEnd->nNode.GetIndex();
for( ; nSttNdIdx < nEndNdIdx; ++nSttNdIdx )
{
if( (*this)[ nSttNdIdx ]->IsCntntNode() )
{
bOneNd = sal_False;
break;
}
}
}
// das kopieren / setzen der Vorlagen darf erst nach
// dem Splitten erfolgen
if( !bOneNd && bSplitDestNd )
{
if( !rPos.nContent.GetIndex() )
{
bCopyCollFmt = sal_True;
}
if( rNodes.IsDocNodes() )
{
SwDoc* const pInsDoc = pDestNd->GetDoc();
::sw::UndoGuard const ug(pInsDoc->GetIDocumentUndoRedo());
pInsDoc->SplitNode( rPos, false );
}
else
{
pDestNd->SplitCntntNode( rPos );
}
if( rPos.nNode == aEndIdx )
{
aEndIdx--;
}
bSplitDestNd = sal_True;
pDestNd = rNodes[ rPos.nNode.GetIndex() - 1 ]->GetTxtNode();
if( nLen )
{
pSrcNd->CutText( pDestNd, SwIndex( pDestNd, pDestNd->Len()),
pStt->nContent, nLen );
}
}
else if ( nLen )
{
pSrcNd->CutText( pDestNd, rPos.nContent, pStt->nContent, nLen );
}
if( bCopyCollFmt )
{
SwDoc* const pInsDoc = pDestNd->GetDoc();
::sw::UndoGuard const undoGuard(pInsDoc->GetIDocumentUndoRedo());
pSrcNd->CopyCollFmt( *pDestNd );
bCopyCollFmt = sal_False;
}
if( bOneNd ) // das wars schon
{
// der PaM wird korrigiert, denn falls ueber Nodegrenzen verschoben
// wurde, so stehen sie in unterschieden Nodes. Auch die Selektion
// wird aufgehoben !
pEnd->nContent = pStt->nContent;
rPam.DeleteMark();
GetDoc()->GetDocShell()->Broadcast( SwFmtFldHint( 0,
rNodes.IsDocNodes() ? SWFMTFLD_INSERTED : SWFMTFLD_REMOVED ) );
return;
}
aSttIdx++;
}
else if( pDestNd )
{
if( rPos.nContent.GetIndex() )
{
if( rPos.nContent.GetIndex() == pDestNd->Len() )
{
rPos.nNode++;
}
else if( rPos.nContent.GetIndex() )
{
// falls im EndNode gesplittet wird, dann muss der EndIdx
// korrigiert werden !!
const bool bCorrEnd = aEndIdx == rPos.nNode;
// es wird kein Text an den TextNode angehaengt, also splitte ihn
if( rNodes.IsDocNodes() )
{
SwDoc* const pInsDoc = pDestNd->GetDoc();
::sw::UndoGuard const ug(pInsDoc->GetIDocumentUndoRedo());
pInsDoc->SplitNode( rPos, false );
}
else
{
pDestNd->SplitCntntNode( rPos );
}
pDestNd = rPos.nNode.GetNode().GetTxtNode();
if ( bCorrEnd )
{
aEndIdx--;
}
}
}
// am Ende steht noch ein leerer Text Node herum.
bSplitDestNd = sal_True;
}
SwTxtNode* const pEndSrcNd = aEndIdx.GetNode().GetTxtNode();
if ( pEndSrcNd )
{
{
// am Bereichsende entsteht ein neuer TextNode
if( !bSplitDestNd )
{
if( rPos.nNode < rNodes.GetEndOfContent().GetIndex() )
{
rPos.nNode++;
}
pDestNd =
rNodes.MakeTxtNode( rPos.nNode, pEndSrcNd->GetTxtColl() );
rPos.nNode--;
rPos.nContent.Assign( pDestNd, 0 );
}
else
{
pDestNd = rPos.nNode.GetNode().GetTxtNode();
}
if( pDestNd && pEnd->nContent.GetIndex() )
{
// verschiebe jetzt noch den Inhalt in den neuen Node
SwIndex aIdx( pEndSrcNd, 0 );
pEndSrcNd->CutText( pDestNd, rPos.nContent, aIdx,
pEnd->nContent.GetIndex());
}
if( bCopyCollFmt )
{
SwDoc* const pInsDoc = pDestNd->GetDoc();
::sw::UndoGuard const ug(pInsDoc->GetIDocumentUndoRedo());
pEndSrcNd->CopyCollFmt( *pDestNd );
}
}
}
else
{
if ( pSrcNd && aEndIdx.GetNode().IsCntntNode() )
{
aEndIdx++;
}
if( !bSplitDestNd )
{
rPos.nNode++;
rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), 0 );
}
}
if( aEndIdx != aSttIdx )
{
// verschiebe jetzt die Nodes in das NodesArary
const sal_uLong nSttDiff = aSttIdx.GetIndex() - pStt->nNode.GetIndex();
SwNodeRange aRg( aSttIdx, aEndIdx );
_MoveNodes( aRg, rNodes, rPos.nNode );
// falls ins gleiche Nodes-Array verschoben wurde, stehen die
// Indizies jetzt auch an der neuen Position !!!!
// (also alles wieder umsetzen)
if( &rNodes == this )
{
pStt->nNode = aRg.aEnd.GetIndex() - nSttDiff;
}
}
// falls der Start-Node verschoben wurde, in dem der Cursor stand, so
// muss der Content im akt. Content angemeldet werden !!!
if ( &pStt->nNode.GetNode() == &GetEndOfContent() )
{
const bool bSuccess = GoPrevious( &pStt->nNode );
ASSERT( bSuccess, "Move() - no ContentNode here" );
(void) bSuccess;
}
pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(),
pStt->nContent.GetIndex() );
// der PaM wird korrigiert, denn falls ueber Nodegrenzen verschoben
// wurde, so stehen sie in unterschielichen Nodes. Auch die Selektion
// wird aufgehoben !
*pEnd = *pStt;
rPam.DeleteMark();
GetDoc()->GetDocShell()->Broadcast( SwFmtFldHint( 0,
rNodes.IsDocNodes() ? SWFMTFLD_INSERTED : SWFMTFLD_REMOVED ) );
}
/*************************************************************************
|*
|* SwNodes::_Copy()
|*
|* Beschreibung
|* Parameter SwNodeRange& zu kopierender Bereich
|* SwDoc& in dieses Dokument
|* SwIndex& auf diese Position im Nodes-Array
|* Ersterstellung JP 11.11.92
|* Letzte Aenderung JP 11.11.92
|*
*************************************************************************/
inline sal_uInt8 MaxLvl( sal_uInt8 nMin, sal_uInt8 nMax, short nNew )
{
return (sal_uInt8)(nNew < nMin ? nMin : nNew > nMax ? nMax : nNew);
}
void SwNodes::_CopyNodes( const SwNodeRange& rRange,
const SwNodeIndex& rIndex, sal_Bool bNewFrms, sal_Bool bTblInsDummyNode ) const
{
SwDoc* pDoc = rIndex.GetNode().GetDoc();
SwNode * pAktNode;
if( rIndex == 0 ||
( (pAktNode = &rIndex.GetNode())->GetStartNode() &&
!pAktNode->StartOfSectionIndex() ))
return;
SwNodeRange aRg( rRange );
// "einfache" StartNodes oder EndNodes ueberspringen
while( ND_STARTNODE == (pAktNode = & aRg.aStart.GetNode())->GetNodeType()
|| ( pAktNode->IsEndNode() &&
!pAktNode->pStartOfSection->IsSectionNode() ) )
aRg.aStart++;
// falls aEnd-1 auf keinem ContentNode steht, dann suche den vorherigen
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() != 0)
{
while( ((pAktNode = & aRg.aEnd.GetNode())->GetStartNode() &&
!pAktNode->IsSectionNode() ) ||
( pAktNode->IsEndNode() &&
ND_STARTNODE == pAktNode->pStartOfSection->GetNodeType()) )
{
aRg.aEnd--;
}
}
aRg.aEnd++;
// wird im selben Array's verschoben, dann ueberpruefe die Einfuegepos.
if( aRg.aStart >= aRg.aEnd )
return;
// when inserting into the source range, nothing need to be done
DBG_ASSERT( &aRg.aStart.GetNodes() == this,
"aRg should use thisnodes array" );
DBG_ASSERT( &aRg.aStart.GetNodes() == &aRg.aEnd.GetNodes(),
"Range across different nodes arrays? You deserve punishment!");
if( &rIndex.GetNodes() == &aRg.aStart.GetNodes() &&
rIndex.GetIndex() >= aRg.aStart.GetIndex() &&
rIndex.GetIndex() < aRg.aEnd.GetIndex() )
return;
SwNodeIndex aInsPos( rIndex );
SwNodeIndex aOrigInsPos( rIndex, -1 ); // Originale Insert Pos
sal_uInt16 nLevel = 0; // Level-Counter
for( sal_uLong nNodeCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
nNodeCnt > 0; --nNodeCnt )
{
pAktNode = &aRg.aStart.GetNode();
switch( pAktNode->GetNodeType() )
{
case ND_TABLENODE:
// dann kopiere mal den TableNode
// Tabell in Fussnote kopieren ?
if( aInsPos < pDoc->GetNodes().GetEndOfInserts().GetIndex() &&
pDoc->GetNodes().GetEndOfInserts().StartOfSectionIndex()
< aInsPos.GetIndex() )
{
nNodeCnt -=
( pAktNode->EndOfSectionIndex() -
aRg.aStart.GetIndex() );
// dann alle Nodes der Tabelle in die akt. Zelle kopieren
// fuer den TabellenNode einen DummyNode einfuegen?
if( bTblInsDummyNode )
new SwNode( aInsPos, ND_SECTIONDUMMY );
for( aRg.aStart++; aRg.aStart.GetIndex() <
pAktNode->EndOfSectionIndex();
aRg.aStart++ )
{
// fuer den Box-StartNode einen DummyNode einfuegen?
if( bTblInsDummyNode )
new SwNode( aInsPos, ND_SECTIONDUMMY );
SwStartNode* pSttNd = aRg.aStart.GetNode().GetStartNode();
_CopyNodes( SwNodeRange( *pSttNd, + 1,
*pSttNd->EndOfSectionNode() ),
aInsPos, bNewFrms, sal_False );
// fuer den Box-EndNode einen DummyNode einfuegen?
if( bTblInsDummyNode )
new SwNode( aInsPos, ND_SECTIONDUMMY );
aRg.aStart = *pSttNd->EndOfSectionNode();
}
// fuer den TabellenEndNode einen DummyNode einfuegen?
if( bTblInsDummyNode )
new SwNode( aInsPos, ND_SECTIONDUMMY );
aRg.aStart = *pAktNode->EndOfSectionNode();
}
else
{
SwNodeIndex nStt( aInsPos, -1 );
SwTableNode* pTblNd = ((SwTableNode*)pAktNode)->
MakeCopy( pDoc, aInsPos );
nNodeCnt -= aInsPos.GetIndex() - nStt.GetIndex() -2;
aRg.aStart = pAktNode->EndOfSectionIndex();
if( bNewFrms && pTblNd )
{
nStt = aInsPos;
pTblNd->MakeFrms( &nStt );
}
}
break;
case ND_SECTIONNODE: // SectionNode
// If the end of the section is outside the copy range,
// the section node will skipped, not copied!
// If someone want to change this behaviour, he has to adjust the function
// lcl_NonCopyCount(..) in ndcopy.cxx which relies on it.
if( pAktNode->EndOfSectionIndex() < aRg.aEnd.GetIndex() )
{
// also der gesamte, lege einen neuen SectionNode an
SwNodeIndex nStt( aInsPos, -1 );
SwSectionNode* pSectNd = ((SwSectionNode*)pAktNode)->
MakeCopy( pDoc, aInsPos );
nNodeCnt -= aInsPos.GetIndex() - nStt.GetIndex() -2;
aRg.aStart = pAktNode->EndOfSectionIndex();
if( bNewFrms && pSectNd &&
!pSectNd->GetSection().IsHidden() )
pSectNd->MakeFrms( &nStt );
}
break;
case ND_STARTNODE: // StartNode gefunden
{
SwStartNode* pTmp = new SwStartNode( aInsPos, ND_STARTNODE,
((SwStartNode*)pAktNode)->GetStartNodeType() );
new SwEndNode( aInsPos, *pTmp );
aInsPos--;
nLevel++;
}
break;
case ND_ENDNODE:
if( nLevel ) // vollstaendige Section
{
--nLevel;
aInsPos++; // EndNode schon vorhanden
}
else if( !pAktNode->pStartOfSection->IsSectionNode() )
{
// erzeuge eine Section an der originalen InsertPosition
SwNodeRange aTmpRg( aOrigInsPos, 1, aInsPos );
pDoc->GetNodes().SectionDown( &aTmpRg,
pAktNode->pStartOfSection->GetStartNodeType() );
}
break;
case ND_TEXTNODE:
case ND_GRFNODE:
case ND_OLENODE:
{
SwCntntNode* pNew = ((SwCntntNode*)pAktNode)->MakeCopy(
pDoc, aInsPos );
if( !bNewFrms ) // dflt. werden die Frames immer angelegt
pNew->DelFrms();
}
break;
case ND_SECTIONDUMMY:
if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(*this))
{
// dann muss an der akt. InsPos auch ein SectionNode
// (Start/Ende) stehen; dann diesen ueberspringen.
// Andernfalls nicht weiter beachten.
SwNode *const pTmpNd = & aInsPos.GetNode();
if( pTmpNd->IsSectionNode() ||
pTmpNd->StartOfSectionNode()->IsSectionNode() )
aInsPos++; // ueberspringen
}
else {
ASSERT( sal_False, "wie kommt diser Node ins Nodes-Array??" );
}
break;
default:
ASSERT( sal_False, "weder Start-/End-/Content-Node, unbekannter Typ" );
}
aRg.aStart++;
}
#ifdef JP_DEBUG
{
extern Writer* GetDebugWriter(const String&);
Writer* pWriter = GetDebugWriter(aEmptyStr);
if( pWriter )
{
int nError;
SvFileStream aStrm( "c:\\$$copy.db", STREAM_WRITE );
SwWriter aWriter( aStrm, *pMyDoc );
aWriter.Write( &nError, pWriter );
}
}
#endif
}
void SwNodes::_DelDummyNodes( const SwNodeRange& rRg )
{
SwNodeIndex aIdx( rRg.aStart );
while( aIdx.GetIndex() < rRg.aEnd.GetIndex() )
{
if( ND_SECTIONDUMMY == aIdx.GetNode().GetNodeType() )
RemoveNode( aIdx.GetIndex(), 1, sal_True );
else
aIdx++;
}
}
SwStartNode* SwNodes::MakeEmptySection( const SwNodeIndex& rIdx,
SwStartNodeType eSttNdTyp )
{
SwStartNode* pSttNd = new SwStartNode( rIdx, ND_STARTNODE, eSttNdTyp );
new SwEndNode( rIdx, *pSttNd );
return pSttNd;
}
SwStartNode* SwNodes::MakeTextSection( const SwNodeIndex & rWhere,
SwStartNodeType eSttNdTyp,
SwTxtFmtColl *pColl,
SwAttrSet* pAutoAttr )
{
SwStartNode* pSttNd = new SwStartNode( rWhere, ND_STARTNODE, eSttNdTyp );
new SwEndNode( rWhere, *pSttNd );
MakeTxtNode( SwNodeIndex( rWhere, - 1 ), pColl, pAutoAttr );
return pSttNd;
}
// zum naechsten Content-Node, der nicht geschuetzt oder versteckt ist
// (beides auf sal_False ==> GoNext/GoPrevious!!!)
SwCntntNode* SwNodes::GoNextSection( SwNodeIndex * pIdx,
int bSkipHidden, int bSkipProtect ) const
{
int bFirst = sal_True;
SwNodeIndex aTmp( *pIdx );
const SwNode* pNd;
while( aTmp < Count() - 1 )
{
pNd = & aTmp.GetNode();
if (ND_SECTIONNODE == pNd->GetNodeType())
{
const SwSection& rSect = ((SwSectionNode*)pNd)->GetSection();
if( (bSkipHidden && rSect.IsHiddenFlag()) ||
(bSkipProtect && rSect.IsProtectFlag()) )
// dann diese Section ueberspringen
aTmp = *pNd->EndOfSectionNode();
bFirst = sal_False;
}
else if( bFirst )
{
bFirst = sal_False;
if( pNd->pStartOfSection->IsSectionNode() )
{
const SwSection& rSect = ((SwSectionNode*)pNd->
pStartOfSection)->GetSection();
if( (bSkipHidden && rSect.IsHiddenFlag()) ||
(bSkipProtect && rSect.IsProtectFlag()) )
// dann diese Section ueberspringen
aTmp = *pNd->EndOfSectionNode();
}
}
else if( ND_CONTENTNODE & pNd->GetNodeType() )
{
const SwSectionNode* pSectNd;
if( ( bSkipHidden || bSkipProtect ) &&
0 != (pSectNd = pNd->FindSectionNode() ) &&
( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) ||
( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) )
{
aTmp = *pSectNd->EndOfSectionNode();
}
else
{
(*pIdx) = aTmp;
return (SwCntntNode*)pNd;
}
}
aTmp++;
bFirst = sal_False;
}
return 0;
}
SwCntntNode* SwNodes::GoPrevSection( SwNodeIndex * pIdx,
int bSkipHidden, int bSkipProtect ) const
{
int bFirst = sal_True;
SwNodeIndex aTmp( *pIdx );
const SwNode* pNd;
while( aTmp > 0 )
{
pNd = & aTmp.GetNode();
if (ND_ENDNODE == pNd->GetNodeType())
{
if( pNd->pStartOfSection->IsSectionNode() )
{
const SwSection& rSect = ((SwSectionNode*)pNd->
pStartOfSection)->GetSection();
if( (bSkipHidden && rSect.IsHiddenFlag()) ||
(bSkipProtect && rSect.IsProtectFlag()) )
// dann diese Section ueberspringen
aTmp = *pNd->StartOfSectionNode();
}
bFirst = sal_False;
}
else if( bFirst )
{
bFirst = sal_False;
if( pNd->pStartOfSection->IsSectionNode() )
{
const SwSection& rSect = ((SwSectionNode*)pNd->
pStartOfSection)->GetSection();
if( (bSkipHidden && rSect.IsHiddenFlag()) ||
(bSkipProtect && rSect.IsProtectFlag()) )
// dann diese Section ueberspringen
aTmp = *pNd->StartOfSectionNode();
}
}
else if( ND_CONTENTNODE & pNd->GetNodeType() )
{
const SwSectionNode* pSectNd;
if( ( bSkipHidden || bSkipProtect ) &&
0 != (pSectNd = pNd->FindSectionNode() ) &&
( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) ||
( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) )
{
aTmp = *pSectNd;
}
else
{
(*pIdx) = aTmp;
return (SwCntntNode*)pNd;
}
}
aTmp--;
}
return 0;
}
// suche den vorhergehenden [/nachfolgenden ] ContentNode oder
// TabellenNode mit Frames. Wird kein Ende angeben, dann wird mit
// dem FrameIndex begonnen; ansonsten, wird mit dem vor rFrmIdx und
// dem hintern pEnd die Suche gestartet. Sollte kein gueltiger Node
// gefunden werden, wird 0 returnt. rFrmIdx zeigt auf dem Node mit
// Frames
SwNode* SwNodes::FindPrvNxtFrmNode( SwNodeIndex& rFrmIdx,
const SwNode* pEnd ) const
{
SwNode* pFrmNd = 0;
// habe wir gar kein Layout, vergiss es
if( GetDoc()->GetCurrentViewShell() ) //swmod 071108//swmod 071225
{
SwNode* pSttNd = &rFrmIdx.GetNode();
// wird in eine versteckte Section verschoben ??
SwSectionNode* pSectNd = pSttNd->IsSectionNode()
? pSttNd->StartOfSectionNode()->FindSectionNode()
: pSttNd->FindSectionNode();
if( !( pSectNd && pSectNd->GetSection().CalcHiddenFlag()/*IsHiddenFlag()*/ ) )
{
// #130650# in a table in table situation we have to assure that we don't leave the
// outer table cell when the inner table is looking for a PrvNxt...
SwTableNode* pTableNd = pSttNd->IsTableNode()
? pSttNd->StartOfSectionNode()->FindTableNode()
: pSttNd->FindTableNode();
SwNodeIndex aIdx( rFrmIdx );
SwNode* pNd;
if( pEnd )
{
aIdx--;
pNd = &aIdx.GetNode();
}
else
pNd = pSttNd;
if( ( pFrmNd = pNd )->IsCntntNode() )
rFrmIdx = aIdx;
// suche nach vorne/hinten nach einem Content Node
else if( 0 != ( pFrmNd = GoPrevSection( &aIdx, sal_True, sal_False )) &&
::CheckNodesRange( aIdx, rFrmIdx, sal_True ) &&
// nach vorne nie aus der Tabelle hinaus!
pFrmNd->FindTableNode() == pTableNd &&
// Bug 37652: nach hinten nie aus der Tabellenzelle hinaus!
(!pFrmNd->FindTableNode() || pFrmNd->FindTableBoxStartNode()
== pSttNd->FindTableBoxStartNode() ) &&
(!pSectNd || pSttNd->IsSectionNode() ||
pSectNd->GetIndex() < pFrmNd->GetIndex())
)
{
rFrmIdx = aIdx;
}
else
{
if( pEnd )
aIdx = pEnd->GetIndex() + 1;
else
aIdx = rFrmIdx;
// JP 19.09.93: aber nie die Section dafuer verlassen !!
if( ( pEnd && ( pFrmNd = &aIdx.GetNode())->IsCntntNode() ) ||
( 0 != ( pFrmNd = GoNextSection( &aIdx, sal_True, sal_False )) &&
::CheckNodesRange( aIdx, rFrmIdx, sal_True ) &&
( pFrmNd->FindTableNode() == pTableNd &&
// Bug 37652: nach hinten nie aus der Tabellenzelle hinaus!
(!pFrmNd->FindTableNode() || pFrmNd->FindTableBoxStartNode()
== pSttNd->FindTableBoxStartNode() ) ) &&
(!pSectNd || pSttNd->IsSectionNode() ||
pSectNd->EndOfSectionIndex() > pFrmNd->GetIndex())
))
{
//JP 18.02.99: Undo von Merge einer Tabelle mit der
// der vorherigen, wenn dahinter auch noch eine steht
// falls aber der Node in einer Tabelle steht, muss
// natuerlich dieser returnt werden, wenn der SttNode eine
// Section oder Tabelle ist!
SwTableNode* pTblNd;
if( pSttNd->IsTableNode() &&
0 != ( pTblNd = pFrmNd->FindTableNode() ) &&
// TABLE IN TABLE:
pTblNd != pSttNd->StartOfSectionNode()->FindTableNode() )
{
pFrmNd = pTblNd;
rFrmIdx = *pFrmNd;
}
else
rFrmIdx = aIdx;
}
else if( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsTableNode() )
{
pFrmNd = pNd->StartOfSectionNode();
rFrmIdx = *pFrmNd;
}
else
{
if( pEnd )
aIdx = pEnd->GetIndex() + 1;
else
aIdx = rFrmIdx.GetIndex() + 1;
if( (pFrmNd = &aIdx.GetNode())->IsTableNode() )
rFrmIdx = aIdx;
else
{
pFrmNd = 0;
// is there some sectionnodes before a tablenode?
while( aIdx.GetNode().IsSectionNode() )
{
const SwSection& rSect = aIdx.GetNode().
GetSectionNode()->GetSection();
if( rSect.IsHiddenFlag() )
aIdx = aIdx.GetNode().EndOfSectionIndex()+1;
else
aIdx++;
}
if( aIdx.GetNode().IsTableNode() )
{
rFrmIdx = aIdx;
pFrmNd = &aIdx.GetNode();
}
}
}
}
}
}
return pFrmNd;
}
void SwNodes::ForEach( const SwNodeIndex& rStart, const SwNodeIndex& rEnd,
FnForEach_SwNodes fnForEach, void* pArgs )
{
BigPtrArray::ForEach( rStart.GetIndex(), rEnd.GetIndex(),
(FnForEach) fnForEach, pArgs );
}
struct _TempBigPtrEntry : public BigPtrEntry
{
_TempBigPtrEntry() {}
};
void SwNodes::RemoveNode( sal_uLong nDelPos, sal_uLong nSz, sal_Bool bDel )
{
sal_uLong nEnd = nDelPos + nSz;
SwNode* pNew = (*this)[ nEnd ];
if( pRoot )
{
SwNodeIndex *p = pRoot;
while( p )
{
sal_uLong nIdx = p->GetIndex();
SwNodeIndex* pNext = p->pNext;
if( nDelPos <= nIdx && nIdx < nEnd )
(*p) = *pNew;
p = pNext;
}
p = pRoot->pPrev;
while( p )
{
sal_uLong nIdx = p->GetIndex();
SwNodeIndex* pPrev = p->pPrev;
if( nDelPos <= nIdx && nIdx < nEnd )
(*p) = *pNew;
p = pPrev;
}
}
{
for (sal_uLong nCnt = 0; nCnt < nSz; nCnt++)
{
SwTxtNode * pTxtNd = ((*this)[ nDelPos + nCnt ])->GetTxtNode();
if (pTxtNd)
{
// --> OD 2008-03-13 #refactorlists#
// pTxtNd->UnregisterNumber();
pTxtNd->RemoveFromList();
// <--
}
}
}
if( bDel )
{
sal_uLong nCnt = nSz;
SwNode *pDel = (*this)[ nDelPos+nCnt-1 ], *pPrev = (*this)[ nDelPos+nCnt-2 ];
// temp. Object setzen
//JP 24.08.98: muessten eigentlich einzeln removed werden, weil
// das Remove auch rekursiv gerufen werden kann, z.B. bei
// zeichengebundenen Rahmen. Da aber dabei viel zu viel
// ablaueft, wird hier ein temp. Objekt eingefuegt, das
// dann mit dem Remove wieder entfernt wird.
// siehe Bug 55406
_TempBigPtrEntry aTempEntry;
BigPtrEntry* pTempEntry = &aTempEntry;
while( nCnt-- )
{
delete pDel;
pDel = pPrev;
sal_uLong nPrevNdIdx = pPrev->GetIndex();
BigPtrArray::Replace( nPrevNdIdx+1, pTempEntry );
if( nCnt )
pPrev = (*this)[ nPrevNdIdx - 1 ];
}
nDelPos = pDel->GetIndex() + 1;
}
BigPtrArray::Remove( nDelPos, nSz );
}
void SwNodes::RegisterIndex( SwNodeIndex& rIdx )
{
if( !pRoot ) // noch keine Root gesetzt?
{
pRoot = &rIdx;
pRoot->pPrev = 0;
pRoot->pNext = 0;
}
else
{
// immer hinter die Root haengen
rIdx.pNext = pRoot->pNext;
pRoot->pNext = &rIdx;
rIdx.pPrev = pRoot;
if( rIdx.pNext )
rIdx.pNext->pPrev = &rIdx;
}
}
void SwNodes::DeRegisterIndex( SwNodeIndex& rIdx )
{
SwNodeIndex* pN = rIdx.pNext;
SwNodeIndex* pP = rIdx.pPrev;
if( pRoot == &rIdx )
pRoot = pP ? pP : pN;
if( pP )
pP->pNext = pN;
if( pN )
pN->pPrev = pP;
rIdx.pNext = 0;
rIdx.pPrev = 0;
}
void SwNodes::InsertNode( const SwNodePtr pNode,
const SwNodeIndex& rPos )
{
const ElementPtr pIns = pNode;
BigPtrArray::Insert( pIns, rPos.GetIndex() );
}
void SwNodes::InsertNode( const SwNodePtr pNode,
sal_uLong nPos )
{
const ElementPtr pIns = pNode;
BigPtrArray::Insert( pIns, nPos );
}
// ->#112139#
SwNode * SwNodes::DocumentSectionStartNode(SwNode * pNode) const
{
if (NULL != pNode)
{
SwNodeIndex aIdx(*pNode);
if (aIdx <= (*this)[0]->EndOfSectionIndex())
pNode = (*this)[0];
else
{
while ((*this)[0] != pNode->StartOfSectionNode())
pNode = pNode->StartOfSectionNode();
}
}
return pNode;
}
SwNode * SwNodes::DocumentSectionEndNode(SwNode * pNode) const
{
return DocumentSectionStartNode(pNode)->EndOfSectionNode();
}
//SwNode * SwNodes::operator[](int n) const
//{
// return operator[]((sal_uLong) n);
//}
// <-#112139#
sal_Bool SwNodes::IsDocNodes() const
{
return this == &pMyDoc->GetNodes();
}