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