/************************************************************** * * 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 #include #include #include #include #include #include #include #include #include #include #include // fuer erzuegen / loeschen der Table-Frames #include #include #include #include #include #include #include // InvalidateTOXMark #include #include 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: // - state of the text node to , 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_INPUTFIELD: { SwTxtFld* pTxtFld = static_cast(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(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(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(); }