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 <UndoRedline.hxx> 28 29 #include <hintids.hxx> 30 #include <unotools/charclass.hxx> 31 #include <doc.hxx> 32 #include <swundo.hxx> // fuer die UndoIds 33 #include <pam.hxx> 34 #include <ndtxt.hxx> 35 #include <UndoCore.hxx> 36 #include <UndoDelete.hxx> 37 #include <rolbck.hxx> 38 #include <redline.hxx> 39 #include <docary.hxx> 40 #include <sortopt.hxx> 41 42 extern void lcl_JoinText( SwPaM& rPam, sal_Bool bJoinPrev ); 43 extern void lcl_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev ); 44 45 //------------------------------------------------------------------ 46 47 SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange ) 48 : SwUndo( UNDO_REDLINE ), SwUndRng( rRange ), 49 pRedlData( 0 ), pRedlSaveData( 0 ), nUserId( nUsrId ), 50 bHiddenRedlines( sal_False ) 51 { 52 // Redline beachten 53 SwDoc& rDoc = *rRange.GetDoc(); 54 if( rDoc.IsRedlineOn() ) 55 { 56 switch( nUserId ) 57 { 58 case UNDO_DELETE: 59 case UNDO_REPLACE: 60 pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_DELETE, rDoc.GetRedlineAuthor() ); 61 break; 62 default: 63 ; 64 } 65 SetRedlineMode( rDoc.GetRedlineMode() ); 66 } 67 68 sal_uLong nEndExtra = rDoc.GetNodes().GetEndOfExtras().GetIndex(); 69 70 pRedlSaveData = new SwRedlineSaveDatas; 71 if( !FillSaveData( rRange, *pRedlSaveData, sal_False, 72 UNDO_REJECT_REDLINE != nUserId )) 73 delete pRedlSaveData, pRedlSaveData = 0; 74 else 75 { 76 bHiddenRedlines = HasHiddenRedlines( *pRedlSaveData ); 77 if( bHiddenRedlines ) // dann muessen die NodeIndizies 78 { // vom SwUndRng korrigiert werden 79 nEndExtra -= rDoc.GetNodes().GetEndOfExtras().GetIndex(); 80 nSttNode -= nEndExtra; 81 nEndNode -= nEndExtra; 82 } 83 } 84 } 85 86 SwUndoRedline::~SwUndoRedline() 87 { 88 delete pRedlData; 89 delete pRedlSaveData; 90 } 91 92 sal_uInt16 SwUndoRedline::GetRedlSaveCount() const 93 { 94 return pRedlSaveData ? pRedlSaveData->Count() : 0; 95 } 96 97 98 void SwUndoRedline::UndoImpl(::sw::UndoRedoContext & rContext) 99 { 100 SwDoc *const pDoc = & rContext.GetDoc(); 101 SwPaM & rPam( AddUndoRedoPaM(rContext) ); 102 103 UndoRedlineImpl(*pDoc, rPam); 104 105 if( pRedlSaveData ) 106 { 107 sal_uLong nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex(); 108 SetSaveData( *pDoc, *pRedlSaveData ); 109 if( bHiddenRedlines ) 110 { 111 pRedlSaveData->DeleteAndDestroy( 0, pRedlSaveData->Count() ); 112 113 nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex() - nEndExtra; 114 nSttNode += nEndExtra; 115 nEndNode += nEndExtra; 116 } 117 SetPaM(rPam, true); 118 } 119 } 120 121 122 void SwUndoRedline::RedoImpl(::sw::UndoRedoContext & rContext) 123 { 124 SwDoc *const pDoc = & rContext.GetDoc(); 125 RedlineMode_t eOld = pDoc->GetRedlineMode(); 126 pDoc->SetRedlineMode_intern((RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); 127 128 SwPaM & rPam( AddUndoRedoPaM(rContext) ); 129 if( pRedlSaveData && bHiddenRedlines ) 130 { 131 sal_uLong nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex(); 132 FillSaveData(rPam, *pRedlSaveData, sal_False, 133 UNDO_REJECT_REDLINE != nUserId ); 134 135 nEndExtra -= pDoc->GetNodes().GetEndOfExtras().GetIndex(); 136 nSttNode -= nEndExtra; 137 nEndNode -= nEndExtra; 138 } 139 140 RedoRedlineImpl(*pDoc, rPam); 141 142 SetPaM(rPam, true); 143 pDoc->SetRedlineMode_intern( eOld ); 144 } 145 146 void SwUndoRedline::UndoRedlineImpl(SwDoc &, SwPaM &) 147 { 148 } 149 150 // default: remove redlines 151 void SwUndoRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) 152 { 153 rDoc.DeleteRedline(rPam, true, USHRT_MAX); 154 } 155 156 157 // SwUndoRedlineDelete /////////////////////////////////////////////////// 158 159 SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUsrId ) 160 : SwUndoRedline( nUsrId = (nUsrId ? nUsrId : UNDO_DELETE), rRange ), 161 bCanGroup( sal_False ), bIsDelim( sal_False ), bIsBackspace( sal_False ) 162 { 163 const SwTxtNode* pTNd; 164 if( UNDO_DELETE == nUserId && 165 nSttNode == nEndNode && nSttCntnt + 1 == nEndCntnt && 166 0 != (pTNd = rRange.GetNode()->GetTxtNode()) ) 167 { 168 sal_Unicode cCh = pTNd->GetTxt().GetChar( nSttCntnt ); 169 if( CH_TXTATR_BREAKWORD != cCh && CH_TXTATR_INWORD != cCh ) 170 { 171 bCanGroup = sal_True; 172 bIsDelim = !GetAppCharClass().isLetterNumeric( pTNd->GetTxt(), 173 nSttCntnt ); 174 bIsBackspace = nSttCntnt == rRange.GetPoint()->nContent.GetIndex(); 175 } 176 } 177 178 bCacheComment = false; 179 } 180 181 void SwUndoRedlineDelete::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) 182 { 183 rDoc.DeleteRedline(rPam, true, USHRT_MAX); 184 } 185 186 void SwUndoRedlineDelete::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) 187 { 188 if (rPam.GetPoint() != rPam.GetMark()) 189 { 190 rDoc.AppendRedline( new SwRedline(*pRedlData, rPam), sal_False ); 191 } 192 } 193 194 sal_Bool SwUndoRedlineDelete::CanGrouping( const SwUndoRedlineDelete& rNext ) 195 { 196 sal_Bool bRet = sal_False; 197 if( UNDO_DELETE == nUserId && nUserId == rNext.nUserId && 198 bCanGroup == rNext.bCanGroup && 199 bIsDelim == rNext.bIsDelim && 200 bIsBackspace == rNext.bIsBackspace && 201 nSttNode == nEndNode && 202 rNext.nSttNode == nSttNode && 203 rNext.nEndNode == nEndNode ) 204 { 205 int bIsEnd = 0; 206 if( rNext.nSttCntnt == nEndCntnt ) 207 bIsEnd = 1; 208 else if( rNext.nEndCntnt == nSttCntnt ) 209 bIsEnd = -1; 210 211 if( bIsEnd && 212 (( !pRedlSaveData && !rNext.pRedlSaveData ) || 213 ( pRedlSaveData && rNext.pRedlSaveData && 214 SwUndo::CanRedlineGroup( *pRedlSaveData, 215 *rNext.pRedlSaveData, 1 != bIsEnd ) 216 ))) 217 { 218 if( 1 == bIsEnd ) 219 nEndCntnt = rNext.nEndCntnt; 220 else 221 nSttCntnt = rNext.nSttCntnt; 222 bRet = sal_True; 223 } 224 } 225 return bRet; 226 } 227 228 /* */ 229 230 SwUndoRedlineSort::SwUndoRedlineSort( const SwPaM& rRange, 231 const SwSortOptions& rOpt ) 232 : SwUndoRedline( UNDO_SORT_TXT, rRange ), 233 pOpt( new SwSortOptions( rOpt ) ), 234 nSaveEndNode( nEndNode ), nOffset( 0 ), nSaveEndCntnt( nEndCntnt ) 235 { 236 } 237 238 SwUndoRedlineSort::~SwUndoRedlineSort() 239 { 240 delete pOpt; 241 } 242 243 void SwUndoRedlineSort::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) 244 { 245 // rPam contains the sorted range 246 // aSaveRange contains copied (i.e. original) range 247 248 SwPosition *const pStart = rPam.Start(); 249 SwPosition *const pEnd = rPam.End(); 250 251 SwNodeIndex aPrevIdx( pStart->nNode, -1 ); 252 sal_uLong nOffsetTemp = pEnd->nNode.GetIndex() - pStart->nNode.GetIndex(); 253 254 if( 0 == ( nsRedlineMode_t::REDLINE_SHOW_DELETE & rDoc.GetRedlineMode()) ) 255 { 256 // die beiden Redline Objecte suchen und diese dann anzeigen lassen, 257 // damit die Nodes wieder uebereinstimmen! 258 // das Geloeschte ist versteckt, also suche das INSERT 259 // Redline Object. Dahinter steht das Geloeschte 260 sal_uInt16 nFnd = rDoc.GetRedlinePos( 261 *rDoc.GetNodes()[ nSttNode + 1 ], 262 nsRedlineType_t::REDLINE_INSERT ); 263 ASSERT( USHRT_MAX != nFnd && nFnd+1 < rDoc.GetRedlineTbl().Count(), 264 "kein Insert Object gefunden" ); 265 ++nFnd; 266 rDoc.GetRedlineTbl()[nFnd]->Show( 1 ); 267 } 268 269 { 270 SwPaM aTmp( *rPam.GetMark() ); 271 aTmp.GetMark()->nContent = 0; 272 aTmp.SetMark(); 273 aTmp.GetPoint()->nNode = nSaveEndNode; 274 aTmp.GetPoint()->nContent.Assign( aTmp.GetCntntNode(), nSaveEndCntnt ); 275 rDoc.DeleteRedline( aTmp, true, USHRT_MAX ); 276 } 277 278 rDoc.DelFullPara(rPam); 279 280 SwPaM *const pPam = & rPam; 281 pPam->DeleteMark(); 282 pPam->GetPoint()->nNode.Assign( aPrevIdx.GetNode(), +1 ); 283 SwCntntNode* pCNd = pPam->GetCntntNode(); 284 pPam->GetPoint()->nContent.Assign(pCNd, 0 ); 285 pPam->SetMark(); 286 287 pPam->GetPoint()->nNode += nOffsetTemp; 288 pCNd = pPam->GetCntntNode(); 289 pPam->GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); 290 291 SetValues( *pPam ); 292 293 SetPaM(rPam); 294 } 295 296 void SwUndoRedlineSort::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) 297 { 298 SwPaM* pPam = &rPam; 299 SwPosition* pStart = pPam->Start(); 300 SwPosition* pEnd = pPam->End(); 301 302 SwNodeIndex aPrevIdx( pStart->nNode, -1 ); 303 sal_uLong nOffsetTemp = pEnd->nNode.GetIndex() - pStart->nNode.GetIndex(); 304 xub_StrLen nCntStt = pStart->nContent.GetIndex(); 305 306 rDoc.SortText(rPam, *pOpt); 307 308 pPam->DeleteMark(); 309 pPam->GetPoint()->nNode.Assign( aPrevIdx.GetNode(), +1 ); 310 SwCntntNode* pCNd = pPam->GetCntntNode(); 311 xub_StrLen nLen = pCNd->Len(); 312 if( nLen > nCntStt ) 313 nLen = nCntStt; 314 pPam->GetPoint()->nContent.Assign(pCNd, nLen ); 315 pPam->SetMark(); 316 317 pPam->GetPoint()->nNode += nOffsetTemp; 318 pCNd = pPam->GetCntntNode(); 319 pPam->GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); 320 321 SetValues( rPam ); 322 323 SetPaM( rPam ); 324 rPam.GetPoint()->nNode = nSaveEndNode; 325 rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), nSaveEndCntnt ); 326 } 327 328 void SwUndoRedlineSort::RepeatImpl(::sw::RepeatContext & rContext) 329 { 330 rContext.GetDoc().SortText( rContext.GetRepeatPaM(), *pOpt ); 331 } 332 333 void SwUndoRedlineSort::SetSaveRange( const SwPaM& rRange ) 334 { 335 const SwPosition& rPos = *rRange.End(); 336 nSaveEndNode = rPos.nNode.GetIndex(); 337 nSaveEndCntnt = rPos.nContent.GetIndex(); 338 } 339 340 void SwUndoRedlineSort::SetOffset( const SwNodeIndex& rIdx ) 341 { 342 nOffset = rIdx.GetIndex() - nSttNode; 343 } 344 345 // SwUndoAcceptRedline /////////////////////////////////////////////////// 346 347 SwUndoAcceptRedline::SwUndoAcceptRedline( const SwPaM& rRange ) 348 : SwUndoRedline( UNDO_ACCEPT_REDLINE, rRange ) 349 { 350 } 351 352 void SwUndoAcceptRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) 353 { 354 rDoc.AcceptRedline(rPam, false); 355 } 356 357 void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext & rContext) 358 { 359 rContext.GetDoc().AcceptRedline(rContext.GetRepeatPaM(), true); 360 } 361 362 SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange ) 363 : SwUndoRedline( UNDO_REJECT_REDLINE, rRange ) 364 { 365 } 366 367 void SwUndoRejectRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) 368 { 369 rDoc.RejectRedline(rPam, false); 370 } 371 372 void SwUndoRejectRedline::RepeatImpl(::sw::RepeatContext & rContext) 373 { 374 rContext.GetDoc().RejectRedline(rContext.GetRepeatPaM(), true); 375 } 376 377 // SwUndoCompDoc ///////////////////////////////////////////////////////// 378 379 SwUndoCompDoc::SwUndoCompDoc( const SwPaM& rRg, sal_Bool bIns ) 380 : SwUndo( UNDO_COMPAREDOC ), SwUndRng( rRg ), pRedlData( 0 ), 381 pUnDel( 0 ), pUnDel2( 0 ), pRedlSaveData( 0 ), bInsert( bIns ) 382 { 383 SwDoc* pDoc = (SwDoc*)rRg.GetDoc(); 384 if( pDoc->IsRedlineOn() ) 385 { 386 RedlineType_t eTyp = bInsert ? nsRedlineType_t::REDLINE_INSERT : nsRedlineType_t::REDLINE_DELETE; 387 pRedlData = new SwRedlineData( eTyp, pDoc->GetRedlineAuthor() ); 388 SetRedlineMode( pDoc->GetRedlineMode() ); 389 } 390 } 391 392 SwUndoCompDoc::SwUndoCompDoc( const SwRedline& rRedl ) 393 : SwUndo( UNDO_COMPAREDOC ), SwUndRng( rRedl ), pRedlData( 0 ), 394 pUnDel( 0 ), pUnDel2( 0 ), pRedlSaveData( 0 ), 395 // fuers MergeDoc wird aber der jeweils umgekehrte Zweig benoetigt! 396 bInsert( nsRedlineType_t::REDLINE_DELETE == rRedl.GetType() ) 397 { 398 SwDoc* pDoc = (SwDoc*)rRedl.GetDoc(); 399 if( pDoc->IsRedlineOn() ) 400 { 401 pRedlData = new SwRedlineData( rRedl.GetRedlineData() ); 402 SetRedlineMode( pDoc->GetRedlineMode() ); 403 } 404 405 pRedlSaveData = new SwRedlineSaveDatas; 406 if( !FillSaveData( rRedl, *pRedlSaveData, sal_False, sal_True )) 407 delete pRedlSaveData, pRedlSaveData = 0; 408 } 409 410 SwUndoCompDoc::~SwUndoCompDoc() 411 { 412 delete pRedlData; 413 delete pUnDel; 414 delete pUnDel2; 415 delete pRedlSaveData; 416 } 417 418 void SwUndoCompDoc::UndoImpl(::sw::UndoRedoContext & rContext) 419 { 420 SwDoc *const pDoc = & rContext.GetDoc(); 421 SwPaM *const pPam( & AddUndoRedoPaM(rContext) ); 422 423 if( !bInsert ) 424 { 425 // die Redlines loeschen 426 RedlineMode_t eOld = pDoc->GetRedlineMode(); 427 pDoc->SetRedlineMode_intern((RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON)); 428 429 pDoc->DeleteRedline( *pPam, true, USHRT_MAX ); 430 431 pDoc->SetRedlineMode_intern( eOld ); 432 433 //per definition Point is end (in SwUndRng!) 434 SwCntntNode* pCSttNd = pPam->GetCntntNode( sal_False ); 435 SwCntntNode* pCEndNd = pPam->GetCntntNode( sal_True ); 436 437 // if start- and end-content is zero, then the doc-compare moves 438 // complete nodes into the current doc. And then the selection 439 // must be from end to start, so the delete join into the right 440 // direction. 441 if( !nSttCntnt && !nEndCntnt ) 442 pPam->Exchange(); 443 444 sal_Bool bJoinTxt, bJoinPrev; 445 ::lcl_GetJoinFlags( *pPam, bJoinTxt, bJoinPrev ); 446 447 pUnDel = new SwUndoDelete( *pPam, sal_False ); 448 449 if( bJoinTxt ) 450 ::lcl_JoinText( *pPam, bJoinPrev ); 451 452 if( pCSttNd && !pCEndNd) 453 { 454 // #112139# Do not step behind the end of content. 455 SwNode * pTmp = pPam->GetNode(sal_True); 456 if (pTmp) 457 { 458 SwNode * pEnd = pDoc->GetNodes().DocumentSectionEndNode(pTmp); 459 460 if (pTmp != pEnd) 461 { 462 pPam->SetMark(); 463 pPam->GetPoint()->nNode++; 464 pPam->GetBound( sal_True ).nContent.Assign( 0, 0 ); 465 pPam->GetBound( sal_False ).nContent.Assign( 0, 0 ); 466 pUnDel2 = new SwUndoDelete( *pPam, sal_True ); 467 } 468 } 469 } 470 pPam->DeleteMark(); 471 } 472 else 473 { 474 if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) 475 { 476 pDoc->DeleteRedline( *pPam, true, USHRT_MAX ); 477 478 if( pRedlSaveData ) 479 SetSaveData( *pDoc, *pRedlSaveData ); 480 } 481 SetPaM(*pPam, true); 482 } 483 } 484 485 void SwUndoCompDoc::RedoImpl(::sw::UndoRedoContext & rContext) 486 { 487 SwDoc *const pDoc = & rContext.GetDoc(); 488 SwPaM *const pPam( & AddUndoRedoPaM(rContext) ); 489 490 if( bInsert ) 491 { 492 if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) 493 { 494 SwRedline* pTmp = new SwRedline( *pRedlData, *pPam ); 495 ((SwRedlineTbl&)pDoc->GetRedlineTbl()).Insert( pTmp ); 496 pTmp->InvalidateRange(); 497 498 /* 499 SwRedlineMode eOld = pDoc->GetRedlineMode(); 500 pDoc->SetRedlineMode_intern( eOld & ~REDLINE_IGNORE ); 501 pDoc->AppendRedline( new SwRedline( *pRedlData, *pPam )); 502 pDoc->SetRedlineMode_intern( eOld ); 503 */ 504 } 505 else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && 506 pDoc->GetRedlineTbl().Count() ) 507 pDoc->SplitRedline( *pPam ); 508 } 509 else 510 { 511 // SwRedlineMode eOld = pDoc->GetRedlineMode(); 512 // pDoc->SetRedlineMode_intern( ( eOld & ~REDLINE_IGNORE) | REDLINE_ON ); 513 514 if( pUnDel2 ) 515 { 516 pUnDel2->UndoImpl(rContext); 517 delete pUnDel2, pUnDel2 = 0; 518 } 519 pUnDel->UndoImpl(rContext); 520 delete pUnDel, pUnDel = 0; 521 522 SetPaM( *pPam ); 523 524 SwRedline* pTmp = new SwRedline( *pRedlData, *pPam ); 525 ((SwRedlineTbl&)pDoc->GetRedlineTbl()).Insert( pTmp ); 526 if (pTmp) // #i19649# 527 pTmp->InvalidateRange(); 528 529 // pDoc->SetRedlineMode_intern( eOld ); 530 } 531 532 SetPaM(*pPam, true); 533 } 534 535