1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sw.hxx" 26 27 #include <UndoSplitMove.hxx> 28 29 #include <doc.hxx> 30 #include <IDocumentUndoRedo.hxx> 31 #include <pam.hxx> 32 #include <swundo.hxx> // fuer die UndoIds 33 #include <ndtxt.hxx> 34 #include <UndoCore.hxx> 35 #include <rolbck.hxx> 36 37 38 // MOVE 39 40 SwUndoMove::SwUndoMove( const SwPaM& rRange, const SwPosition& rMvPos ) 41 : SwUndo( UNDO_MOVE ), SwUndRng( rRange ), 42 nMvDestNode( rMvPos.nNode.GetIndex() ), 43 nMvDestCntnt( rMvPos.nContent.GetIndex() ), 44 bMoveRedlines( false ) 45 { 46 bMoveRange = bJoinNext = bJoinPrev = sal_False; 47 48 // StartNode vorm loeschen von Fussnoten besorgen! 49 SwDoc* pDoc = rRange.GetDoc(); 50 SwTxtNode* pTxtNd = pDoc->GetNodes()[ nSttNode ]->GetTxtNode(); 51 SwTxtNode* pEndTxtNd = pDoc->GetNodes()[ nEndNode ]->GetTxtNode(); 52 53 pHistory = new SwHistory; 54 55 if( pTxtNd ) 56 { 57 pHistory->Add( pTxtNd->GetTxtColl(), nSttNode, ND_TEXTNODE ); 58 if ( pTxtNd->GetpSwpHints() ) 59 { 60 pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nSttNode, 61 0, pTxtNd->GetTxt().Len(), false ); 62 } 63 if( pTxtNd->HasSwAttrSet() ) 64 pHistory->CopyFmtAttr( *pTxtNd->GetpSwAttrSet(), nSttNode ); 65 } 66 if( pEndTxtNd && pEndTxtNd != pTxtNd ) 67 { 68 pHistory->Add( pEndTxtNd->GetTxtColl(), nEndNode, ND_TEXTNODE ); 69 if ( pEndTxtNd->GetpSwpHints() ) 70 { 71 pHistory->CopyAttr( pEndTxtNd->GetpSwpHints(), nEndNode, 72 0, pEndTxtNd->GetTxt().Len(), false ); 73 } 74 if( pEndTxtNd->HasSwAttrSet() ) 75 pHistory->CopyFmtAttr( *pEndTxtNd->GetpSwAttrSet(), nEndNode ); 76 } 77 78 pTxtNd = rMvPos.nNode.GetNode().GetTxtNode(); 79 if (0 != pTxtNd) 80 { 81 pHistory->Add( pTxtNd->GetTxtColl(), nMvDestNode, ND_TEXTNODE ); 82 if ( pTxtNd->GetpSwpHints() ) 83 { 84 pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nMvDestNode, 85 0, pTxtNd->GetTxt().Len(), false ); 86 } 87 if( pTxtNd->HasSwAttrSet() ) 88 pHistory->CopyFmtAttr( *pTxtNd->GetpSwAttrSet(), nMvDestNode ); 89 } 90 91 92 nFtnStt = pHistory->Count(); 93 DelFtn( rRange ); 94 95 if( pHistory && !pHistory->Count() ) 96 DELETEZ( pHistory ); 97 } 98 99 100 SwUndoMove::SwUndoMove( SwDoc* pDoc, const SwNodeRange& rRg, 101 const SwNodeIndex& rMvPos ) 102 : SwUndo( UNDO_MOVE ), 103 nMvDestNode( rMvPos.GetIndex() ), 104 bMoveRedlines( false ) 105 { 106 bMoveRange = sal_True; 107 bJoinNext = bJoinPrev = sal_False; 108 109 nSttCntnt = nEndCntnt = nMvDestCntnt = STRING_MAXLEN; 110 111 nSttNode = rRg.aStart.GetIndex(); 112 nEndNode = rRg.aEnd.GetIndex(); 113 114 // DelFtn( rRange ); 115 116 // wird aus dem CntntBereich in den Sonderbereich verschoben ? 117 sal_uLong nCntntStt = pDoc->GetNodes().GetEndOfAutotext().GetIndex(); 118 if( nMvDestNode < nCntntStt && rRg.aStart.GetIndex() > nCntntStt ) 119 { 120 // loesche alle Fussnoten. Diese sind dort nicht erwuenscht. 121 SwPosition aPtPos( rRg.aEnd ); 122 SwCntntNode* pCNd = rRg.aEnd.GetNode().GetCntntNode(); 123 if( pCNd ) 124 aPtPos.nContent.Assign( pCNd, pCNd->Len() ); 125 SwPosition aMkPos( rRg.aStart ); 126 if( 0 != ( pCNd = aMkPos.nNode.GetNode().GetCntntNode() )) 127 aMkPos.nContent.Assign( pCNd, 0 ); 128 129 DelCntntIndex( aMkPos, aPtPos, nsDelCntntType::DELCNT_FTN ); 130 131 if( pHistory && !pHistory->Count() ) 132 DELETEZ( pHistory ); 133 } 134 135 nFtnStt = 0; 136 } 137 138 139 140 void SwUndoMove::SetDestRange( const SwPaM& rRange, 141 const SwPosition& rInsPos, 142 sal_Bool bJoin, sal_Bool bCorrPam ) 143 { 144 const SwPosition *pStt = rRange.Start(), 145 *pEnd = rRange.GetPoint() == pStt 146 ? rRange.GetMark() 147 : rRange.GetPoint(); 148 149 nDestSttNode = pStt->nNode.GetIndex(); 150 nDestSttCntnt = pStt->nContent.GetIndex(); 151 nDestEndNode = pEnd->nNode.GetIndex(); 152 nDestEndCntnt = pEnd->nContent.GetIndex(); 153 154 nInsPosNode = rInsPos.nNode.GetIndex(); 155 nInsPosCntnt = rInsPos.nContent.GetIndex(); 156 157 if( bCorrPam ) 158 { 159 nDestSttNode--; 160 nDestEndNode--; 161 } 162 163 bJoinNext = nDestSttNode != nDestEndNode && 164 pStt->nNode.GetNode().GetTxtNode() && 165 pEnd->nNode.GetNode().GetTxtNode(); 166 bJoinPrev = bJoin; 167 } 168 169 170 void SwUndoMove::SetDestRange( const SwNodeIndex& rStt, 171 const SwNodeIndex& rEnd, 172 const SwNodeIndex& rInsPos ) 173 { 174 nDestSttNode = rStt.GetIndex(); 175 nDestEndNode = rEnd.GetIndex(); 176 if( nDestSttNode > nDestEndNode ) 177 { 178 nDestSttNode = nDestEndNode; 179 nDestEndNode = rStt.GetIndex(); 180 } 181 nInsPosNode = rInsPos.GetIndex(); 182 183 nDestSttCntnt = nDestEndCntnt = nInsPosCntnt = STRING_MAXLEN; 184 } 185 186 187 void SwUndoMove::UndoImpl(::sw::UndoRedoContext & rContext) 188 { 189 SwDoc *const pDoc = & rContext.GetDoc(); 190 191 // Block, damit aus diesem gesprungen werden kann 192 do { 193 // erzeuge aus den Werten die Insert-Position und den Bereich 194 SwNodeIndex aIdx( pDoc->GetNodes(), nDestSttNode ); 195 196 if( bMoveRange ) 197 { 198 // nur ein Move mit SwRange 199 SwNodeRange aRg( aIdx, aIdx ); 200 aRg.aEnd = nDestEndNode; 201 aIdx = nInsPosNode; 202 bool bSuccess = pDoc->MoveNodeRange( aRg, aIdx, 203 IDocumentContentOperations::DOC_MOVEDEFAULT ); 204 if (!bSuccess) 205 break; 206 } 207 else 208 { 209 SwPaM aPam( aIdx.GetNode(), nDestSttCntnt, 210 *pDoc->GetNodes()[ nDestEndNode ], nDestEndCntnt ); 211 212 // #i17764# if redlines are to be moved, we may not remove them before 213 // pDoc->Move gets a chance to handle them 214 if( ! bMoveRedlines ) 215 RemoveIdxFromRange( aPam, sal_False ); 216 217 SwPosition aPos( *pDoc->GetNodes()[ nInsPosNode] ); 218 SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode(); 219 aPos.nContent.Assign( pCNd, nInsPosCntnt ); 220 221 if( pCNd->HasSwAttrSet() ) 222 pCNd->ResetAllAttr(); 223 224 if( pCNd->IsTxtNode() && ((SwTxtNode*)pCNd)->GetpSwpHints() ) 225 ((SwTxtNode*)pCNd)->ClearSwpHintsArr( false ); 226 227 // an der InsertPos erstmal alle Attribute entfernen, 228 const bool bSuccess = pDoc->MoveRange( aPam, aPos, (bMoveRedlines) 229 ? IDocumentContentOperations::DOC_MOVEREDLINES 230 : IDocumentContentOperations::DOC_MOVEDEFAULT ); 231 if (!bSuccess) 232 break; 233 234 aPam.Exchange(); 235 aPam.DeleteMark(); 236 // pDoc->ResetAttr( aPam, sal_False ); 237 if( aPam.GetNode()->IsCntntNode() ) 238 aPam.GetNode()->GetCntntNode()->ResetAllAttr(); 239 // der Pam wird jetzt aufgegeben. 240 } 241 242 SwTxtNode* pTxtNd = aIdx.GetNode().GetTxtNode(); 243 if( bJoinNext ) 244 { 245 { 246 RemoveIdxRel( aIdx.GetIndex() + 1, SwPosition( aIdx, 247 SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ) ) ); 248 } 249 // sind keine Pams mehr im naechsten TextNode 250 pTxtNd->JoinNext(); 251 } 252 253 if( bJoinPrev && pTxtNd->CanJoinPrev( &aIdx ) ) 254 { 255 // ?? sind keine Pams mehr im naechsten TextNode ?? 256 pTxtNd = aIdx.GetNode().GetTxtNode(); 257 { 258 RemoveIdxRel( aIdx.GetIndex() + 1, SwPosition( aIdx, 259 SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ) ) ); 260 } 261 pTxtNd->JoinNext(); 262 } 263 264 } while( sal_False ); 265 266 if( pHistory ) 267 { 268 if( nFtnStt != pHistory->Count() ) 269 pHistory->Rollback( pDoc, nFtnStt ); 270 pHistory->TmpRollback( pDoc, 0 ); 271 pHistory->SetTmpEnd( pHistory->Count() ); 272 } 273 274 // setze noch den Cursor auf den Undo-Bereich 275 if( !bMoveRange ) 276 { 277 AddUndoRedoPaM(rContext); 278 } 279 } 280 281 282 void SwUndoMove::RedoImpl(::sw::UndoRedoContext & rContext) 283 { 284 SwPaM *const pPam = & AddUndoRedoPaM(rContext); 285 SwDoc & rDoc = rContext.GetDoc(); 286 287 SwNodes& rNds = rDoc.GetNodes(); 288 SwNodeIndex aIdx( rNds, nMvDestNode ); 289 290 if( bMoveRange ) 291 { 292 // nur ein Move mit SwRange 293 SwNodeRange aRg( rNds, nSttNode, rNds, nEndNode ); 294 rDoc.MoveNodeRange( aRg, aIdx, (bMoveRedlines) 295 ? IDocumentContentOperations::DOC_MOVEREDLINES 296 : IDocumentContentOperations::DOC_MOVEDEFAULT ); 297 } 298 else 299 { 300 SwPaM aPam( *pPam->GetPoint() ); 301 SetPaM( aPam ); 302 SwPosition aMvPos( aIdx, SwIndex( aIdx.GetNode().GetCntntNode(), 303 nMvDestCntnt )); 304 305 DelFtn( aPam ); 306 RemoveIdxFromRange( aPam, sal_False ); 307 308 aIdx = aPam.Start()->nNode; 309 sal_Bool bJoinTxt = aIdx.GetNode().IsTxtNode(); 310 311 aIdx--; 312 rDoc.MoveRange( aPam, aMvPos, 313 IDocumentContentOperations::DOC_MOVEDEFAULT ); 314 315 if( nSttNode != nEndNode && bJoinTxt ) 316 { 317 aIdx++; 318 SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode(); 319 if( pTxtNd && pTxtNd->CanJoinNext() ) 320 { 321 { 322 RemoveIdxRel( aIdx.GetIndex() + 1, SwPosition( aIdx, 323 SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ) ) ); 324 } 325 pTxtNd->JoinNext(); 326 } 327 } 328 *pPam->GetPoint() = *aPam.GetPoint(); 329 pPam->SetMark(); 330 *pPam->GetMark() = *aPam.GetMark(); 331 } 332 } 333 334 335 void SwUndoMove::DelFtn( const SwPaM& rRange ) 336 { 337 // wird aus dem CntntBereich in den Sonderbereich verschoben ? 338 SwDoc* pDoc = rRange.GetDoc(); 339 sal_uLong nCntntStt = pDoc->GetNodes().GetEndOfAutotext().GetIndex(); 340 if( nMvDestNode < nCntntStt && 341 rRange.GetPoint()->nNode.GetIndex() >= nCntntStt ) 342 { 343 // loesche alle Fussnoten. Diese sind dort nicht erwuenscht. 344 DelCntntIndex( *rRange.GetMark(), *rRange.GetPoint(), 345 nsDelCntntType::DELCNT_FTN ); 346 347 if( pHistory && !pHistory->Count() ) 348 delete pHistory, pHistory = 0; 349 } 350 } 351 352