diff options
Diffstat (limited to 'sw/source/core/docnode/nodes.cxx')
-rw-r--r-- | sw/source/core/docnode/nodes.cxx | 2508 |
1 files changed, 2508 insertions, 0 deletions
diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx new file mode 100644 index 000000000000..dbd0f4194bf8 --- /dev/null +++ b/sw/source/core/docnode/nodes.cxx @@ -0,0 +1,2508 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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) + + +// 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; + + OSL_ENSURE( 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 +|* +*******************************************************************/ + +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(); + + // #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->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 && + 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( 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(); + // OultineNodes set the new nodes in the array + 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: + { + SwTxtFld* pTxtFld = + static_cast<SwTxtFld*>(pAttr); + rNds.GetDoc()->InsDelFldInFldLst( !bToUndo, *pTxtFld ); + + const SwFieldType* pTyp = pTxtFld->GetFld().GetFld()->GetTyp(); + if ( RES_POSTITFLD == pTyp->Which() ) + { + rNds.GetDoc()->GetDocShell()->Broadcast( SwFmtFldHint( &pTxtFld->GetFld(), pTxtFld->GetFld().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() ) + { + OSL_ENSURE( !this, "ob das so richtig ist ??" ); + aFrmNdIdx = rNds.GetEndOfContent(); + pFrmNd = rNds.GoPrevSection( &aFrmNdIdx, sal_True, sal_False ); + if( pFrmNd && !((SwCntntNode*)pFrmNd)->GetDepends() ) + pFrmNd = 0; + +#if OSL_DEBUG_LEVEL > 1 + if( !pFrmNd ) + OSL_ENSURE( !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 ); + + SwStartNode* pStartNode = aIdx.GetNode().pStartOfSection; + aSttNdStack.C40_INSERT( SwStartNode, pStartNode, 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; + + // 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(); + + // setze bei Start/EndNodes die richtigen Indizies + // loesche die Gliederungs-Indizies aus + // dem alten Nodes-Array + if( pCNd->IsTxtNode() && 0 != + ((SwTxtNode*)pCNd)->GetAttrOutlineLevel() )//<-end,by zhaojianwei + pOutlineNds->Remove( pCNd ); + else + pCNd = 0; + } + + 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(); + + 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: + { + // 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 + OSL_ENSURE( 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_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--; + } + } + break; + + case ND_TEXTNODE: + 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 { + OSL_FAIL( "wie kommt diser Node ins Nodes-Array??" ); + } + aRg.aEnd--; + break; + + default: + OSL_FAIL( "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() ); + } + + 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 +|* +*******************************************************************/ +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 +|* +*******************************************************************/ +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 +|* +*************************************************************************/ +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. +|* +*******************************************************************/ +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( 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. +|* +*******************************************************************/ +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 +|* +*************************************************************************/ + +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 +|* +*************************************************************************/ +void SwNodes::DelNodes( const SwNodeIndex & rStart, sal_uLong nCnt ) +{ + 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 + { + int bUpdateNum = 0; + for( sal_uLong n = nSttIdx, nEnd = nSttIdx + nCnt; n < nEnd; ++n ) + { + SwNode* pNd = (*this)[ n ]; + + if( pNd->IsTxtNode() && + 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 +|* +*************************************************************************/ + +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 +|* +*************************************************************************/ +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 ); + OSL_ENSURE( 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 +|* +*************************************************************************/ + +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() ) + { + sal_uLong nDistance = + ( pAktNode->EndOfSectionIndex() - + aRg.aStart.GetIndex() ); + if (nDistance < nNodeCnt) + nNodeCnt -= nDistance; + else + nNodeCnt = 1; + + // 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 ); + sal_uLong nDistance = aInsPos.GetIndex() - nStt.GetIndex() - 2; + if (nDistance < nNodeCnt) + nNodeCnt -= nDistance; + else + nNodeCnt = 1; + + 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 ); + + sal_uLong nDistance = aInsPos.GetIndex() - nStt.GetIndex() - 2; + if (nDistance < nNodeCnt) + nNodeCnt -= nDistance; + else + nNodeCnt = 1; + 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 { + OSL_FAIL( "wie kommt diser Node ins Nodes-Array??" ); + } + break; + + default: + OSL_FAIL( "weder Start-/End-/Content-Node, unbekannter Typ" ); + } + aRg.aStart++; + } +} + +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()*/ ) ) + { + // 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) + { + 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(); +} + +sal_Bool SwNodes::IsDocNodes() const +{ + return this == &pMyDoc->GetNodes(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |