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 32 #include <IShellCursorSupplier.hxx> 33 #include <txtftn.hxx> 34 #include <fmtanchr.hxx> 35 #include <ftnidx.hxx> 36 #include <frmfmt.hxx> 37 #include <doc.hxx> 38 #include <UndoManager.hxx> 39 #include <docary.hxx> 40 #include <swundo.hxx> // fuer die UndoIds 41 #include <pam.hxx> 42 #include <ndtxt.hxx> 43 #include <UndoCore.hxx> 44 #include <rolbck.hxx> 45 #include <ndnotxt.hxx> 46 #include <IMark.hxx> 47 #include <mvsave.hxx> 48 #include <redline.hxx> 49 #include <crossrefbookmark.hxx> 50 #include <undo.hrc> 51 #include <comcore.hrc> 52 #include <docsh.hxx> 53 54 class SwRedlineSaveData : public SwUndRng, public SwRedlineData, 55 private SwUndoSaveSection 56 { 57 public: 58 SwRedlineSaveData( SwComparePosition eCmpPos, 59 const SwPosition& rSttPos, const SwPosition& rEndPos, 60 SwRedline& rRedl, sal_Bool bCopyNext ); 61 ~SwRedlineSaveData(); 62 void RedlineToDoc( SwPaM& rPam ); 63 SwNodeIndex* GetMvSttIdx() const 64 { return SwUndoSaveSection::GetMvSttIdx(); } 65 66 #ifdef DBG_UTIL 67 sal_uInt16 nRedlineCount; 68 #endif 69 }; 70 71 SV_IMPL_PTRARR( SwRedlineSaveDatas, SwRedlineSaveDataPtr ) 72 73 74 //------------------------------------------------------------ 75 76 // Diese Klasse speichert den Pam als sal_uInt16's und kann diese wieder zu 77 78 // einem PaM zusammensetzen 79 SwUndRng::SwUndRng() 80 : nSttNode( 0 ), nEndNode( 0 ), nSttCntnt( 0 ), nEndCntnt( 0 ) 81 { 82 } 83 84 SwUndRng::SwUndRng( const SwPaM& rPam ) 85 { 86 SetValues( rPam ); 87 } 88 89 void SwUndRng::SetValues( const SwPaM& rPam ) 90 { 91 const SwPosition *pStt = rPam.Start(); 92 if( rPam.HasMark() ) 93 { 94 const SwPosition *pEnd = rPam.GetPoint() == pStt 95 ? rPam.GetMark() 96 : rPam.GetPoint(); 97 nEndNode = pEnd->nNode.GetIndex(); 98 nEndCntnt = pEnd->nContent.GetIndex(); 99 } 100 else 101 // keine Selektion !! 102 nEndNode = 0, nEndCntnt = STRING_MAXLEN; 103 104 nSttNode = pStt->nNode.GetIndex(); 105 nSttCntnt = pStt->nContent.GetIndex(); 106 } 107 108 void SwUndRng::SetPaM( SwPaM & rPam, sal_Bool bCorrToCntnt ) const 109 { 110 rPam.DeleteMark(); 111 rPam.GetPoint()->nNode = nSttNode; 112 SwNode* pNd = rPam.GetNode(); 113 if( pNd->IsCntntNode() ) 114 rPam.GetPoint()->nContent.Assign( pNd->GetCntntNode(), nSttCntnt ); 115 else if( bCorrToCntnt ) 116 rPam.Move( fnMoveForward, fnGoCntnt ); 117 else 118 rPam.GetPoint()->nContent.Assign( 0, 0 ); 119 120 if( !nEndNode && STRING_MAXLEN == nEndCntnt ) // keine Selection 121 return ; 122 123 rPam.SetMark(); 124 if( nSttNode == nEndNode && nSttCntnt == nEndCntnt ) 125 return; // nichts mehr zu tun 126 127 rPam.GetPoint()->nNode = nEndNode; 128 if( (pNd = rPam.GetNode())->IsCntntNode() ) 129 rPam.GetPoint()->nContent.Assign( pNd->GetCntntNode(), nEndCntnt ); 130 else if( bCorrToCntnt ) 131 rPam.Move( fnMoveBackward, fnGoCntnt ); 132 else 133 rPam.GetPoint()->nContent.Assign( 0, 0 ); 134 } 135 136 SwPaM & SwUndRng::AddUndoRedoPaM( 137 ::sw::UndoRedoContext & rContext, bool const bCorrToCntnt) const 138 { 139 SwPaM & rPaM( rContext.GetCursorSupplier().CreateNewShellCursor() ); 140 SetPaM( rPaM, bCorrToCntnt ); 141 return rPaM; 142 } 143 144 145 //------------------------------------------------------------ 146 147 148 void SwUndo::RemoveIdxFromSection( SwDoc& rDoc, sal_uLong nSttIdx, 149 sal_uLong* pEndIdx ) 150 { 151 SwNodeIndex aIdx( rDoc.GetNodes(), nSttIdx ); 152 SwNodeIndex aEndIdx( rDoc.GetNodes(), pEndIdx ? *pEndIdx 153 : aIdx.GetNode().EndOfSectionIndex() ); 154 SwPosition aPos( rDoc.GetNodes().GetEndOfPostIts() ); 155 rDoc.CorrAbs( aIdx, aEndIdx, aPos, sal_True ); 156 } 157 158 void SwUndo::RemoveIdxFromRange( SwPaM& rPam, sal_Bool bMoveNext ) 159 { 160 const SwPosition* pEnd = rPam.End(); 161 if( bMoveNext ) 162 { 163 if( pEnd != rPam.GetPoint() ) 164 rPam.Exchange(); 165 166 SwNodeIndex aStt( rPam.GetMark()->nNode ); 167 SwNodeIndex aEnd( rPam.GetPoint()->nNode ); 168 169 if( !rPam.Move( fnMoveForward ) ) 170 { 171 rPam.Exchange(); 172 if( !rPam.Move( fnMoveBackward ) ) 173 { 174 rPam.GetPoint()->nNode = rPam.GetDoc()->GetNodes().GetEndOfPostIts(); 175 rPam.GetPoint()->nContent.Assign( 0, 0 ); 176 } 177 } 178 179 rPam.GetDoc()->CorrAbs( aStt, aEnd, *rPam.GetPoint(), sal_True ); 180 } 181 else 182 rPam.GetDoc()->CorrAbs( rPam, *pEnd, sal_True ); 183 } 184 185 void SwUndo::RemoveIdxRel( sal_uLong nIdx, const SwPosition& rPos ) 186 { 187 // nur die Crsr verschieben; die Bookmarks/TOXMarks/.. werden vom 188 // entsp. JoinNext/JoinPrev erledigt! 189 SwNodeIndex aIdx( rPos.nNode.GetNode().GetNodes(), nIdx ); 190 ::PaMCorrRel( aIdx, rPos ); 191 } 192 193 SwUndo::SwUndo(SwUndoId const nId) 194 : m_nId(nId), nOrigRedlineMode(nsRedlineMode_t::REDLINE_NONE), 195 bCacheComment(true), pComment(NULL) 196 { 197 } 198 199 bool SwUndo::IsDelBox() const 200 { 201 return GetId() == UNDO_COL_DELETE || GetId() == UNDO_ROW_DELETE || 202 GetId() == UNDO_TABLE_DELBOX; 203 } 204 205 SwUndo::~SwUndo() 206 { 207 delete pComment; 208 } 209 210 211 class UndoRedoRedlineGuard 212 { 213 public: 214 UndoRedoRedlineGuard(::sw::UndoRedoContext & rContext, SwUndo & rUndo) 215 : m_rRedlineAccess(rContext.GetDoc()) 216 , m_eMode(m_rRedlineAccess.GetRedlineMode()) 217 { 218 RedlineMode_t const eTmpMode = 219 static_cast<RedlineMode_t>(rUndo.GetRedlineMode()); 220 if ((nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) != 221 (nsRedlineMode_t::REDLINE_SHOW_MASK & m_eMode)) 222 { 223 m_rRedlineAccess.SetRedlineMode( eTmpMode ); 224 } 225 m_rRedlineAccess.SetRedlineMode_intern( static_cast<RedlineMode_t>( 226 eTmpMode | nsRedlineMode_t::REDLINE_IGNORE) ); 227 } 228 ~UndoRedoRedlineGuard() 229 { 230 m_rRedlineAccess.SetRedlineMode(m_eMode); 231 } 232 private: 233 IDocumentRedlineAccess & m_rRedlineAccess; 234 RedlineMode_t const m_eMode; 235 }; 236 237 void SwUndo::Undo() 238 { 239 OSL_ENSURE(false, "SwUndo::Undo(): ERROR: must call Undo(context) instead"); 240 } 241 242 void SwUndo::Redo() 243 { 244 OSL_ENSURE(false, "SwUndo::Redo(): ERROR: must call Redo(context) instead"); 245 } 246 247 void SwUndo::UndoWithContext(SfxUndoContext & rContext) 248 { 249 ::sw::UndoRedoContext *const pContext( 250 dynamic_cast< ::sw::UndoRedoContext * >(& rContext)); 251 OSL_ASSERT(pContext); 252 if (!pContext) { return; } 253 UndoRedoRedlineGuard(*pContext, *this); 254 UndoImpl(*pContext); 255 } 256 257 void SwUndo::RedoWithContext(SfxUndoContext & rContext) 258 { 259 ::sw::UndoRedoContext *const pContext( 260 dynamic_cast< ::sw::UndoRedoContext * >(& rContext)); 261 OSL_ASSERT(pContext); 262 if (!pContext) { return; } 263 UndoRedoRedlineGuard(*pContext, *this); 264 RedoImpl(*pContext); 265 } 266 267 void SwUndo::Repeat(SfxRepeatTarget & rContext) 268 { 269 ::sw::RepeatContext *const pRepeatContext( 270 dynamic_cast< ::sw::RepeatContext * >(& rContext)); 271 OSL_ASSERT(pRepeatContext); 272 if (!pRepeatContext) { return; } 273 RepeatImpl(*pRepeatContext); 274 } 275 276 sal_Bool SwUndo::CanRepeat(SfxRepeatTarget & rContext) const 277 { 278 ::sw::RepeatContext *const pRepeatContext( 279 dynamic_cast< ::sw::RepeatContext * >(& rContext)); 280 OSL_ASSERT(pRepeatContext); 281 if (!pRepeatContext) { return false; } 282 return CanRepeatImpl(*pRepeatContext); 283 } 284 285 void SwUndo::RepeatImpl( ::sw::RepeatContext & ) 286 { 287 } 288 289 bool SwUndo::CanRepeatImpl( ::sw::RepeatContext & ) const 290 { 291 // return false; 292 return ((REPEAT_START <= GetId()) && (GetId() < REPEAT_END)); 293 } 294 295 String SwUndo::GetComment() const 296 { 297 String aResult; 298 299 if (bCacheComment) 300 { 301 if (! pComment) 302 { 303 pComment = new String(SW_RES(UNDO_BASE + GetId())); 304 305 SwRewriter aRewriter = GetRewriter(); 306 307 *pComment = aRewriter.Apply(*pComment); 308 } 309 310 aResult = *pComment; 311 } 312 else 313 { 314 aResult = String(SW_RES(UNDO_BASE + GetId())); 315 316 SwRewriter aRewriter = GetRewriter(); 317 318 aResult = aRewriter.Apply(aResult); 319 } 320 321 return aResult; 322 } 323 324 SwRewriter SwUndo::GetRewriter() const 325 { 326 SwRewriter aResult; 327 328 return aResult; 329 } 330 331 332 //------------------------------------------------------------ 333 334 SwUndoSaveCntnt::SwUndoSaveCntnt() 335 : pHistory( 0 ) 336 {} 337 338 SwUndoSaveCntnt::~SwUndoSaveCntnt() 339 { 340 delete pHistory; 341 } 342 343 // wird fuer das Loeschen von Inhalt benoetigt. Fuer das ReDo werden 344 // Inhalte in das UndoNodesArray verschoben. Diese Methoden fuegen 345 // am Ende eines TextNodes fuer die Attribute einen Trenner ein. 346 // Dadurch werden die Attribute nicht expandiert. 347 // MoveTo.. verschiebt aus dem NodesArray in das UndoNodesArray 348 // MoveFrom.. verschiebt aus dem UndoNodesArray in das NodesArray 349 350 // 2.8.93: ist pEndNdIdx angebenen, wird vom Undo/Redo -Ins/DelFly 351 // aufgerufen. Dann soll die gesamte Section verschoben werden. 352 353 void SwUndoSaveCntnt::MoveToUndoNds( SwPaM& rPaM, SwNodeIndex* pNodeIdx, 354 SwIndex* pCntIdx, sal_uLong* pEndNdIdx, xub_StrLen* pEndCntIdx ) 355 { 356 SwDoc& rDoc = *rPaM.GetDoc(); 357 ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); 358 359 SwNoTxtNode* pCpyNd = rPaM.GetNode()->GetNoTxtNode(); 360 361 // jetzt kommt das eigentliche Loeschen(Verschieben) 362 SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes(); 363 SwPosition aPos( pEndNdIdx ? rNds.GetEndOfPostIts() 364 : rNds.GetEndOfExtras() ); 365 aPos.nNode--; 366 367 const SwPosition* pStt = rPaM.Start(), *pEnd = rPaM.End(); 368 369 if( pCpyNd || pEndNdIdx || !aPos.nNode.GetNode().GetCntntNode() || 370 (!pStt->nContent.GetIndex() && (pStt->nNode != pEnd->nNode || 371 (!pStt->nNode.GetNode().GetCntntNode() || 372 pStt->nNode.GetNode().GetCntntNode()->Len() == 373 pEnd->nContent.GetIndex() ) ) ) ) 374 { 375 aPos.nNode++; 376 aPos.nContent = 0; 377 } 378 else 379 aPos.nNode.GetNode().GetCntntNode()->MakeEndIndex( &aPos.nContent ); 380 381 // als sal_uInt16 merken; die Indizies verschieben sich !! 382 sal_uLong nTmpMvNode = aPos.nNode.GetIndex(); 383 xub_StrLen nTmpMvCntnt = aPos.nContent.GetIndex(); 384 385 if( pCpyNd || pEndNdIdx ) 386 { 387 SwNodeRange aRg( pStt->nNode, 0, pEnd->nNode, 1 ); 388 rDoc.GetNodes()._MoveNodes( aRg, rNds, aPos.nNode, sal_False ); 389 aPos.nContent = 0; 390 aPos.nNode--; 391 } 392 else 393 { 394 rDoc.GetNodes().MoveRange( rPaM, aPos, rNds ); 395 396 SwTxtNode* pTxtNd = aPos.nNode.GetNode().GetTxtNode(); 397 if( pTxtNd ) // fuege einen Trenner fuer die Attribute ein ! 398 { 399 // weil aber beim Insert die Attribute angefasst/sprich 400 // aus dem Array geloescht und wieder eingefuegt werden, koennen 401 // dadurch Attribute verschwinden (z.B "Fett aus" von 10-20, 402 // "Fett an" von 12-15, dann wird durchs Insert/Delete das 403 // "Fett an" geloescht !! Ist hier aber nicht erwuenscht !!) 404 // DARUM: nicht die Hints anfassen, direct den String manipulieren 405 406 String& rStr = (String&)pTxtNd->GetTxt(); 407 // Zur Sicherheit lieber nur wenn wirklich am Ende steht 408 if( rStr.Len() == aPos.nContent.GetIndex() ) 409 { 410 rStr.Insert( ' ' ); 411 ++aPos.nContent; 412 } 413 else 414 { 415 pTxtNd->InsertText( sal_Unicode(' '), aPos.nContent, 416 IDocumentContentOperations::INS_NOHINTEXPAND ); 417 } 418 } 419 } 420 if( pEndNdIdx ) 421 *pEndNdIdx = aPos.nNode.GetIndex(); 422 if( pEndCntIdx ) 423 *pEndCntIdx = aPos.nContent.GetIndex(); 424 425 // alte Position 426 aPos.nNode = nTmpMvNode; 427 if( pNodeIdx ) 428 *pNodeIdx = aPos.nNode; 429 430 if( pCntIdx ) 431 { 432 SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode(); 433 if( pCNd ) 434 pCntIdx->Assign( pCNd, nTmpMvCntnt ); 435 else 436 pCntIdx->Assign( 0, 0 ); 437 } 438 } 439 440 void SwUndoSaveCntnt::MoveFromUndoNds( SwDoc& rDoc, sal_uLong nNodeIdx, 441 xub_StrLen nCntIdx, SwPosition& rInsPos, 442 sal_uLong* pEndNdIdx, xub_StrLen* pEndCntIdx ) 443 { 444 // jetzt kommt das wiederherstellen 445 SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes(); 446 if( nNodeIdx == rNds.GetEndOfPostIts().GetIndex() ) 447 return; // nichts gespeichert 448 449 ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); 450 451 SwPaM aPaM( rInsPos ); 452 if( pEndNdIdx ) // dann hole aus diesem den Bereich 453 aPaM.GetPoint()->nNode.Assign( rNds, *pEndNdIdx ); 454 else 455 { 456 aPaM.GetPoint()->nNode = rNds.GetEndOfExtras(); 457 GoInCntnt( aPaM, fnMoveBackward ); 458 } 459 460 SwTxtNode* pTxtNd = aPaM.GetNode()->GetTxtNode(); 461 if( !pEndNdIdx && pTxtNd ) // loesche den Trenner wieder 462 { 463 if( pEndCntIdx ) 464 aPaM.GetPoint()->nContent.Assign( pTxtNd, *pEndCntIdx ); 465 if( pTxtNd->GetTxt().Len() ) 466 { 467 GoInCntnt( aPaM, fnMoveBackward ); 468 pTxtNd->EraseText( aPaM.GetPoint()->nContent, 1 ); 469 } 470 471 aPaM.SetMark(); 472 aPaM.GetPoint()->nNode = nNodeIdx; 473 aPaM.GetPoint()->nContent.Assign( aPaM.GetCntntNode(), nCntIdx ); 474 475 _SaveRedlEndPosForRestore aRedlRest( rInsPos.nNode, rInsPos.nContent.GetIndex() ); 476 477 rNds.MoveRange( aPaM, rInsPos, rDoc.GetNodes() ); 478 479 // noch den letzen Node loeschen. 480 if( !aPaM.GetPoint()->nContent.GetIndex() || 481 ( aPaM.GetPoint()->nNode++ && // noch leere Nodes am Ende ?? 482 &rNds.GetEndOfExtras() != &aPaM.GetPoint()->nNode.GetNode() )) 483 { 484 aPaM.GetPoint()->nContent.Assign( 0, 0 ); 485 aPaM.SetMark(); 486 rNds.Delete( aPaM.GetPoint()->nNode, 487 rNds.GetEndOfExtras().GetIndex() - 488 aPaM.GetPoint()->nNode.GetIndex() ); 489 } 490 491 aRedlRest.Restore(); 492 } 493 else if( pEndNdIdx || !pTxtNd ) 494 { 495 SwNodeRange aRg( rNds, nNodeIdx, rNds, (pEndNdIdx 496 ? ((*pEndNdIdx) + 1) 497 : rNds.GetEndOfExtras().GetIndex() ) ); 498 rNds._MoveNodes( aRg, rDoc.GetNodes(), rInsPos.nNode, 0 == pEndNdIdx ); 499 500 } 501 else { 502 ASSERT( sal_False, "was ist es denn nun?" ); 503 } 504 } 505 506 // diese beiden Methoden bewegen den Point vom Pam zurueck/vor. Damit 507 // kann fuer ein Undo/Redo ein Bereich aufgespannt werden. (Der 508 // Point liegt dann vor dem manipuliertem Bereich !!) 509 // Das Flag gibt an, ob noch vorm Point Inhalt steht. 510 511 sal_Bool SwUndoSaveCntnt::MovePtBackward( SwPaM& rPam ) 512 { 513 rPam.SetMark(); 514 if( rPam.Move( fnMoveBackward )) 515 return sal_True; 516 517 // gibt es nach vorne keinen Inhalt mehr, so setze den Point einfach 518 // auf die vorherige Position (Node und Content, damit der Content 519 // abgemeldet wird !!) 520 rPam.GetPoint()->nNode--; 521 rPam.GetPoint()->nContent.Assign( 0, 0 ); 522 return sal_False; 523 } 524 525 void SwUndoSaveCntnt::MovePtForward( SwPaM& rPam, sal_Bool bMvBkwrd ) 526 { 527 // gab es noch Inhalt vor der Position ? 528 if( bMvBkwrd ) 529 rPam.Move( fnMoveForward ); 530 else 531 { // setzen Point auf die naechste Position 532 rPam.GetPoint()->nNode++; 533 SwCntntNode* pCNd = rPam.GetCntntNode(); 534 if( pCNd ) 535 pCNd->MakeStartIndex( &rPam.GetPoint()->nContent ); 536 else 537 rPam.Move( fnMoveForward ); 538 } 539 } 540 541 542 /* 543 JP 21.03.94: loesche alle Objecte, die ContentIndizies auf den ang. 544 Bereich besitzen. 545 Zur Zeit gibts folgende Objecte 546 - Fussnoten 547 - Flys 548 - Bookmarks 549 - Verzeichnisse 550 */ 551 // --> OD 2007-10-17 #i81002# - extending method: 552 // delete certain (not all) cross-reference bookmarks at text node of <rMark> 553 // and at text node of <rPoint>, if these text nodes aren't the same. 554 void SwUndoSaveCntnt::DelCntntIndex( const SwPosition& rMark, 555 const SwPosition& rPoint, 556 DelCntntType nDelCntntType ) 557 { 558 const SwPosition *pStt = rMark < rPoint ? &rMark : &rPoint, 559 *pEnd = &rMark == pStt ? &rPoint : &rMark; 560 561 SwDoc* pDoc = rMark.nNode.GetNode().GetDoc(); 562 563 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); 564 565 // 1. Fussnoten 566 if( nsDelCntntType::DELCNT_FTN & nDelCntntType ) 567 { 568 SwFtnIdxs& rFtnArr = pDoc->GetFtnIdxs(); 569 if( rFtnArr.Count() ) 570 { 571 const SwNode* pFtnNd; 572 sal_uInt16 nPos; 573 rFtnArr.SeekEntry( pStt->nNode, &nPos ); 574 SwTxtFtn* pSrch; 575 576 // loesche erstmal alle, die dahinter stehen 577 while( nPos < rFtnArr.Count() && ( pFtnNd = 578 &( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex() 579 <= pEnd->nNode.GetIndex() ) 580 { 581 xub_StrLen nFtnSttIdx = *pSrch->GetStart(); 582 if( (nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) 583 ? (&pEnd->nNode.GetNode() == pFtnNd ) 584 : (( &pStt->nNode.GetNode() == pFtnNd && 585 pStt->nContent.GetIndex() > nFtnSttIdx) || 586 ( &pEnd->nNode.GetNode() == pFtnNd && 587 nFtnSttIdx >= pEnd->nContent.GetIndex() )) ) 588 { 589 ++nPos; // weiter suchen 590 continue; 591 } 592 593 // es muss leider ein Index angelegt werden. Sonst knallts im 594 // TextNode, weil im DTOR der SwFtn dieser geloescht wird !! 595 SwTxtNode* pTxtNd = (SwTxtNode*)pFtnNd; 596 if( !pHistory ) 597 pHistory = new SwHistory; 598 SwTxtAttr* const pFtnHnt = 599 pTxtNd->GetTxtAttrForCharAt( nFtnSttIdx ); 600 ASSERT( pFtnHnt, "kein FtnAttribut" ); 601 SwIndex aIdx( pTxtNd, nFtnSttIdx ); 602 pHistory->Add( pFtnHnt, pTxtNd->GetIndex(), false ); 603 pTxtNd->EraseText( aIdx, 1 ); 604 } 605 606 while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )-> 607 GetTxtNode())->GetIndex() >= pStt->nNode.GetIndex() ) 608 { 609 xub_StrLen nFtnSttIdx = *pSrch->GetStart(); 610 if( !(nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType) && ( 611 ( &pStt->nNode.GetNode() == pFtnNd && 612 pStt->nContent.GetIndex() > nFtnSttIdx ) || 613 ( &pEnd->nNode.GetNode() == pFtnNd && 614 nFtnSttIdx >= pEnd->nContent.GetIndex() ))) 615 continue; // weiter suchen 616 617 // es muss leider ein Index angelegt werden. Sonst knallts im 618 // TextNode, weil im DTOR der SwFtn dieser geloescht wird !! 619 SwTxtNode* pTxtNd = (SwTxtNode*)pFtnNd; 620 if( !pHistory ) 621 pHistory = new SwHistory; 622 SwTxtAttr* const pFtnHnt = 623 pTxtNd->GetTxtAttrForCharAt( nFtnSttIdx ); 624 ASSERT( pFtnHnt, "kein FtnAttribut" ); 625 SwIndex aIdx( pTxtNd, nFtnSttIdx ); 626 pHistory->Add( pFtnHnt, pTxtNd->GetIndex(), false ); 627 pTxtNd->EraseText( aIdx, 1 ); 628 } 629 } 630 } 631 632 // 2. Flys 633 if( nsDelCntntType::DELCNT_FLY & nDelCntntType ) 634 { 635 sal_uInt16 nChainInsPos = pHistory ? pHistory->Count() : 0; 636 const SwSpzFrmFmts& rSpzArr = *pDoc->GetSpzFrmFmts(); 637 if( rSpzArr.Count() ) 638 { 639 const sal_Bool bDelFwrd = rMark.nNode.GetIndex() <= rPoint.nNode.GetIndex(); 640 SwFlyFrmFmt* pFmt; 641 const SwFmtAnchor* pAnchor; 642 sal_uInt16 n = rSpzArr.Count(); 643 const SwPosition* pAPos; 644 645 while( n && rSpzArr.Count() ) 646 { 647 pFmt = (SwFlyFrmFmt*)rSpzArr[--n]; 648 pAnchor = &pFmt->GetAnchor(); 649 switch( pAnchor->GetAnchorId() ) 650 { 651 case FLY_AS_CHAR: 652 if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) && 653 (( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) 654 ? ( pStt->nNode <= pAPos->nNode && 655 pAPos->nNode < pEnd->nNode ) 656 : ( *pStt <= *pAPos && *pAPos < *pEnd )) ) 657 { 658 if( !pHistory ) 659 pHistory = new SwHistory; 660 SwTxtNode *const pTxtNd = 661 pAPos->nNode.GetNode().GetTxtNode(); 662 SwTxtAttr* const pFlyHnt = pTxtNd->GetTxtAttrForCharAt( 663 pAPos->nContent.GetIndex()); 664 ASSERT( pFlyHnt, "kein FlyAttribut" ); 665 pHistory->Add( pFlyHnt, 0, false ); 666 // n wieder zurueck, damit nicht ein Format uebesprungen wird ! 667 n = n >= rSpzArr.Count() ? rSpzArr.Count() : n+1; 668 } 669 break; 670 case FLY_AT_PARA: 671 { 672 pAPos = pAnchor->GetCntntAnchor(); 673 if( pAPos ) 674 { 675 bool bTmp; 676 if( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) 677 bTmp = pStt->nNode <= pAPos->nNode && pAPos->nNode < pEnd->nNode; 678 else 679 { 680 if (bDelFwrd) 681 bTmp = rMark.nNode < pAPos->nNode && 682 pAPos->nNode <= rPoint.nNode; 683 else 684 bTmp = rPoint.nNode <= pAPos->nNode && 685 pAPos->nNode < rMark.nNode; 686 } 687 688 if (bTmp) 689 { 690 if( !pHistory ) 691 pHistory = new SwHistory; 692 693 // Moving the anchor? 694 if( !( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) && 695 ( rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex() ) ) 696 { 697 // Do not try to move the anchor to a table! 698 if( rMark.nNode.GetNode().GetTxtNode() ) 699 { 700 pHistory->Add( *pFmt ); 701 SwFmtAnchor aAnch( *pAnchor ); 702 SwPosition aPos( rMark.nNode ); 703 aAnch.SetAnchor( &aPos ); 704 pFmt->SetFmtAttr( aAnch ); 705 } 706 } 707 else 708 { 709 pHistory->Add( *pFmt, nChainInsPos ); 710 // n wieder zurueck, damit nicht ein 711 // Format uebesprungen wird ! 712 n = n >= rSpzArr.Count() ? 713 rSpzArr.Count() : n+1; 714 } 715 } 716 } 717 } 718 break; 719 case FLY_AT_CHAR: 720 if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) && 721 ( pStt->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode ) ) 722 { 723 if( !pHistory ) 724 pHistory = new SwHistory; 725 if (IsDestroyFrameAnchoredAtChar( 726 *pAPos, *pStt, *pEnd, nDelCntntType)) 727 { 728 pHistory->Add( *pFmt, nChainInsPos ); 729 n = n >= rSpzArr.Count() ? rSpzArr.Count() : n+1; 730 } 731 else if( !( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) ) 732 { 733 if( *pStt <= *pAPos && *pAPos < *pEnd ) 734 { 735 // These are the objects anchored 736 // between section start and end position 737 // Do not try to move the anchor to a table! 738 if( rMark.nNode.GetNode().GetTxtNode() ) 739 { 740 pHistory->Add( *pFmt ); 741 SwFmtAnchor aAnch( *pAnchor ); 742 aAnch.SetAnchor( &rMark ); 743 pFmt->SetFmtAttr( aAnch ); 744 } 745 } 746 } 747 } 748 break; 749 case FLY_AT_FLY: 750 751 if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) && 752 pStt->nNode == pAPos->nNode ) 753 { 754 if( !pHistory ) 755 pHistory = new SwHistory; 756 757 pHistory->Add( *pFmt, nChainInsPos ); 758 759 // n wieder zurueck, damit nicht ein Format uebesprungen wird ! 760 n = n >= rSpzArr.Count() ? rSpzArr.Count() : n+1; 761 } 762 break; 763 default: break; 764 } 765 } 766 } 767 } 768 769 // 3. Bookmarks 770 if( nsDelCntntType::DELCNT_BKM & nDelCntntType ) 771 { 772 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); 773 if( pMarkAccess->getMarksCount() ) 774 { 775 776 for( sal_uInt16 n = 0; n < pMarkAccess->getMarksCount(); ++n ) 777 { 778 // --> OD 2007-10-17 #i81002# 779 bool bSavePos = false; 780 bool bSaveOtherPos = false; 781 const ::sw::mark::IMark* pBkmk = (pMarkAccess->getMarksBegin() + n)->get(); 782 if( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) 783 { 784 if( pStt->nNode <= pBkmk->GetMarkPos().nNode && 785 pBkmk->GetMarkPos().nNode < pEnd->nNode ) 786 bSavePos = true; 787 if( pBkmk->IsExpanded() && 788 pStt->nNode <= pBkmk->GetOtherMarkPos().nNode && 789 pBkmk->GetOtherMarkPos().nNode < pEnd->nNode ) 790 bSaveOtherPos = true; 791 } 792 else 793 { 794 // --> OD 2009-08-06 #i92125# 795 bool bKeepCrossRefBkmk( false ); 796 { 797 if ( rMark.nNode == rPoint.nNode && 798 ( IDocumentMarkAccess::GetType(*pBkmk) == 799 IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK || 800 IDocumentMarkAccess::GetType(*pBkmk) == 801 IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK ) ) 802 { 803 bKeepCrossRefBkmk = true; 804 } 805 } 806 if ( !bKeepCrossRefBkmk ) 807 { 808 bool bMaybe = false; 809 if ( *pStt <= pBkmk->GetMarkPos() && pBkmk->GetMarkPos() <= *pEnd ) 810 { 811 if( pBkmk->GetMarkPos() == *pEnd || 812 ( *pStt == pBkmk->GetMarkPos() && pBkmk->IsExpanded() ) ) 813 bMaybe = true; 814 else 815 bSavePos = true; 816 } 817 if( pBkmk->IsExpanded() && 818 *pStt <= pBkmk->GetOtherMarkPos() && pBkmk->GetOtherMarkPos() <= *pEnd ) 819 { 820 if( bSavePos || bSaveOtherPos || 821 ( pBkmk->GetOtherMarkPos() < *pEnd && pBkmk->GetOtherMarkPos() > *pStt ) ) 822 { 823 if( bMaybe ) 824 bSavePos = true; 825 bSaveOtherPos = true; 826 } 827 } 828 } 829 // <-- 830 831 // --> OD 2007-10-17 #i81002# 832 const bool bDifferentTxtNodesAtMarkAndPoint( 833 rMark.nNode != rPoint.nNode && 834 rMark.nNode.GetNode().GetTxtNode() && 835 rPoint.nNode.GetNode().GetTxtNode() ); 836 // <-- 837 if( !bSavePos && !bSaveOtherPos && bDifferentTxtNodesAtMarkAndPoint && 838 dynamic_cast< const ::sw::mark::CrossRefBookmark* >(pBkmk)) 839 { 840 // delete cross-reference bookmark at <pStt>, if only part of 841 // <pEnd> text node content is deleted. 842 if( pStt->nNode == pBkmk->GetMarkPos().nNode && 843 pEnd->nContent.GetIndex() != 844 pEnd->nNode.GetNode().GetTxtNode()->Len() ) 845 { 846 bSavePos = true; 847 bSaveOtherPos = false; 848 } 849 // delete cross-reference bookmark at <pEnd>, if only part of 850 // <pStt> text node content is deleted. 851 else if( pEnd->nNode == pBkmk->GetMarkPos().nNode && 852 pStt->nContent.GetIndex() != 0 ) 853 { 854 bSavePos = true; 855 bSaveOtherPos = false; 856 } 857 } 858 } 859 if( bSavePos || bSaveOtherPos ) 860 { 861 if( !pHistory ) 862 pHistory = new SwHistory; 863 864 pHistory->Add( *pBkmk, bSavePos, bSaveOtherPos ); 865 if(bSavePos && 866 (bSaveOtherPos || !pBkmk->IsExpanded())) 867 { 868 pMarkAccess->deleteMark(pMarkAccess->getMarksBegin()+n); 869 n--; 870 } 871 } 872 } 873 } 874 } 875 } 876 877 878 // sicher eine vollstaendige Section im Undo-Nodes-Array 879 880 SwUndoSaveSection::SwUndoSaveSection() 881 : pMvStt( 0 ), pRedlSaveData( 0 ), nMvLen( 0 ), nStartPos( ULONG_MAX ) 882 { 883 } 884 885 SwUndoSaveSection::~SwUndoSaveSection() 886 { 887 if( pMvStt ) // loesche noch den Bereich aus dem UndoNodes Array 888 { 889 // SaveSection speichert den Inhalt in der PostIt-Section 890 SwNodes& rUNds = pMvStt->GetNode().GetNodes(); 891 rUNds.Delete( *pMvStt, nMvLen ); 892 893 delete pMvStt; 894 } 895 delete pRedlSaveData; 896 } 897 898 void SwUndoSaveSection::SaveSection( SwDoc* pDoc, const SwNodeIndex& rSttIdx ) 899 { 900 SwNodeRange aRg( rSttIdx.GetNode(), *rSttIdx.GetNode().EndOfSectionNode() ); 901 SaveSection( pDoc, aRg ); 902 } 903 904 905 void SwUndoSaveSection::SaveSection( SwDoc* , const SwNodeRange& rRange ) 906 { 907 SwPaM aPam( rRange.aStart, rRange.aEnd ); 908 909 // loesche alle Fussnoten / FlyFrames / Bookmarks / Verzeichnisse 910 DelCntntIndex( *aPam.GetMark(), *aPam.GetPoint() ); 911 912 pRedlSaveData = new SwRedlineSaveDatas; 913 if( !SwUndo::FillSaveData( aPam, *pRedlSaveData, sal_True, sal_True )) 914 delete pRedlSaveData, pRedlSaveData = 0; 915 916 nStartPos = rRange.aStart.GetIndex(); 917 918 aPam.GetPoint()->nNode--; 919 aPam.GetMark()->nNode++; 920 921 SwCntntNode* pCNd = aPam.GetCntntNode( sal_False ); 922 if( pCNd ) 923 aPam.GetMark()->nContent.Assign( pCNd, 0 ); 924 if( 0 != ( pCNd = aPam.GetCntntNode( sal_True )) ) 925 aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); 926 927 // Positionen als SwIndex merken, damit im DTOR dieser Bereich 928 // entfernt werden kann !! 929 sal_uLong nEnd; 930 pMvStt = new SwNodeIndex( rRange.aStart ); 931 MoveToUndoNds( aPam, pMvStt, 0, &nEnd, 0 ); 932 nMvLen = nEnd - pMvStt->GetIndex() + 1; 933 } 934 935 void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, SwNodeIndex* pIdx, 936 sal_uInt16 nSectType ) 937 { 938 if( ULONG_MAX != nStartPos ) // gab es ueberhaupt Inhalt ? 939 { 940 // ueberpruefe, ob der Inhalt an der alten Position steht 941 SwNodeIndex aSttIdx( pDoc->GetNodes(), nStartPos ); 942 OSL_ENSURE(!aSttIdx.GetNode().GetCntntNode(), 943 "RestoreSection(): Position on content node"); 944 945 // move den Inhalt aus dem UndoNodes-Array in den Fly 946 SwStartNode* pSttNd = pDoc->GetNodes().MakeEmptySection( aSttIdx, 947 (SwStartNodeType)nSectType ); 948 949 RestoreSection( pDoc, SwNodeIndex( *pSttNd->EndOfSectionNode() )); 950 951 if( pIdx ) 952 *pIdx = *pSttNd; 953 } 954 } 955 956 void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, const SwNodeIndex& rInsPos ) 957 { 958 if( ULONG_MAX != nStartPos ) // gab es ueberhaupt Inhalt ? 959 { 960 SwPosition aInsPos( rInsPos ); 961 sal_uLong nEnd = pMvStt->GetIndex() + nMvLen - 1; 962 MoveFromUndoNds( *pDoc, pMvStt->GetIndex(), 0, aInsPos, &nEnd, 0 ); 963 964 // Indizies wieder zerstoren, Inhalt ist aus dem UndoNodes-Array 965 // entfernt worden. 966 DELETEZ( pMvStt ); 967 nMvLen = 0; 968 969 if( pRedlSaveData ) 970 { 971 SwUndo::SetSaveData( *pDoc, *pRedlSaveData ); 972 delete pRedlSaveData, pRedlSaveData = 0; 973 } 974 } 975 } 976 977 // sicher und setze die RedlineDaten 978 979 SwRedlineSaveData::SwRedlineSaveData( SwComparePosition eCmpPos, 980 const SwPosition& rSttPos, 981 const SwPosition& rEndPos, 982 SwRedline& rRedl, 983 sal_Bool bCopyNext ) 984 : SwUndRng( rRedl ), 985 SwRedlineData( rRedl.GetRedlineData(), bCopyNext ) 986 { 987 ASSERT( POS_OUTSIDE == eCmpPos || 988 !rRedl.GetContentIdx(), "Redline mit Content" ); 989 990 switch( eCmpPos ) 991 { 992 case POS_OVERLAP_BEFORE: // Pos1 ueberlappt Pos2 am Anfang 993 nEndNode = rEndPos.nNode.GetIndex(); 994 nEndCntnt = rEndPos.nContent.GetIndex(); 995 break; 996 case POS_OVERLAP_BEHIND: // Pos1 ueberlappt Pos2 am Ende 997 nSttNode = rSttPos.nNode.GetIndex(); 998 nSttCntnt = rSttPos.nContent.GetIndex(); 999 break; 1000 1001 case POS_INSIDE: // Pos1 liegt vollstaendig in Pos2 1002 nSttNode = rSttPos.nNode.GetIndex(); 1003 nSttCntnt = rSttPos.nContent.GetIndex(); 1004 nEndNode = rEndPos.nNode.GetIndex(); 1005 nEndCntnt = rEndPos.nContent.GetIndex(); 1006 break; 1007 1008 case POS_OUTSIDE: // Pos2 liegt vollstaendig in Pos1 1009 if( rRedl.GetContentIdx() ) 1010 { 1011 // dann den Bereich ins UndoArray verschieben und merken 1012 SaveSection( rRedl.GetDoc(), *rRedl.GetContentIdx() ); 1013 rRedl.SetContentIdx( 0 ); 1014 } 1015 break; 1016 1017 case POS_EQUAL: // Pos1 ist genauso gross wie Pos2 1018 break; 1019 1020 default: 1021 ASSERT( !this, "keine gueltigen Daten!" ) 1022 } 1023 1024 #ifdef DBG_UTIL 1025 nRedlineCount = rSttPos.nNode.GetNode().GetDoc()->GetRedlineTbl().Count(); 1026 #endif 1027 } 1028 1029 SwRedlineSaveData::~SwRedlineSaveData() 1030 { 1031 } 1032 1033 void SwRedlineSaveData::RedlineToDoc( SwPaM& rPam ) 1034 { 1035 SwDoc& rDoc = *rPam.GetDoc(); 1036 SwRedline* pRedl = new SwRedline( *this, rPam ); 1037 1038 if( GetMvSttIdx() ) 1039 { 1040 SwNodeIndex aIdx( rDoc.GetNodes() ); 1041 RestoreSection( &rDoc, &aIdx, SwNormalStartNode ); 1042 if( GetHistory() ) 1043 GetHistory()->Rollback( &rDoc ); 1044 pRedl->SetContentIdx( &aIdx ); 1045 } 1046 SetPaM( *pRedl ); 1047 // erstmal die "alten" entfernen, damit im Append keine unerwarteten 1048 // Dinge passieren, wie z.B. eine Delete in eigenen Insert. Dann wird 1049 // naehmlich das gerade restaurierte wieder geloescht - nicht das gewollte 1050 rDoc.DeleteRedline( *pRedl, false, USHRT_MAX ); 1051 1052 RedlineMode_t eOld = rDoc.GetRedlineMode(); 1053 rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES)); 1054 //#i92154# let UI know about a new redline with comment 1055 if (rDoc.GetDocShell() && (pRedl->GetComment() != String(::rtl::OUString::createFromAscii(""))) ) 1056 rDoc.GetDocShell()->Broadcast(SwRedlineHint(pRedl,SWREDLINE_INSERTED)); 1057 // 1058 #if OSL_DEBUG_LEVEL > 0 1059 bool const bSuccess = 1060 #endif 1061 rDoc.AppendRedline( pRedl, true ); 1062 OSL_ENSURE(bSuccess, 1063 "SwRedlineSaveData::RedlineToDoc: insert redline failed"); 1064 rDoc.SetRedlineMode_intern( eOld ); 1065 } 1066 1067 sal_Bool SwUndo::FillSaveData( const SwPaM& rRange, SwRedlineSaveDatas& rSData, 1068 sal_Bool bDelRange, sal_Bool bCopyNext ) 1069 { 1070 if( rSData.Count() ) 1071 rSData.DeleteAndDestroy( 0, rSData.Count() ); 1072 1073 SwRedlineSaveData* pNewData; 1074 const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End(); 1075 const SwRedlineTbl& rTbl = rRange.GetDoc()->GetRedlineTbl(); 1076 sal_uInt16 n = 0; 1077 rRange.GetDoc()->GetRedline( *pStt, &n ); 1078 for( ; n < rTbl.Count(); ++n ) 1079 { 1080 SwRedline* pRedl = rTbl[ n ]; 1081 const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End(); 1082 1083 SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ); 1084 if( POS_BEFORE != eCmpPos && POS_BEHIND != eCmpPos && 1085 POS_COLLIDE_END != eCmpPos && POS_COLLIDE_START != eCmpPos ) 1086 { 1087 pNewData = new SwRedlineSaveData( eCmpPos, *pStt, *pEnd, 1088 *pRedl, bCopyNext ); 1089 rSData.Insert( pNewData, rSData.Count() ); 1090 } 1091 } 1092 if( rSData.Count() && bDelRange ) 1093 rRange.GetDoc()->DeleteRedline( rRange, false, USHRT_MAX ); 1094 return 0 != rSData.Count(); 1095 } 1096 1097 sal_Bool SwUndo::FillSaveDataForFmt( const SwPaM& rRange, SwRedlineSaveDatas& rSData ) 1098 { 1099 if( rSData.Count() ) 1100 rSData.DeleteAndDestroy( 0, rSData.Count() ); 1101 1102 SwRedlineSaveData* pNewData; 1103 const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End(); 1104 const SwRedlineTbl& rTbl = rRange.GetDoc()->GetRedlineTbl(); 1105 sal_uInt16 n = 0; 1106 rRange.GetDoc()->GetRedline( *pStt, &n ); 1107 for( ; n < rTbl.Count(); ++n ) 1108 { 1109 SwRedline* pRedl = rTbl[ n ]; 1110 if( nsRedlineType_t::REDLINE_FORMAT == pRedl->GetType() ) 1111 { 1112 const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End(); 1113 1114 SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ); 1115 if( POS_BEFORE != eCmpPos && POS_BEHIND != eCmpPos && 1116 POS_COLLIDE_END != eCmpPos && POS_COLLIDE_START != eCmpPos ) 1117 { 1118 pNewData = new SwRedlineSaveData( eCmpPos, *pStt, *pEnd, 1119 *pRedl, sal_True ); 1120 rSData.Insert( pNewData, rSData.Count() ); 1121 } 1122 1123 1124 } 1125 } 1126 return 0 != rSData.Count(); 1127 } 1128 1129 void SwUndo::SetSaveData( SwDoc& rDoc, const SwRedlineSaveDatas& rSData ) 1130 { 1131 RedlineMode_t eOld = rDoc.GetRedlineMode(); 1132 rDoc.SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); 1133 SwPaM aPam( rDoc.GetNodes().GetEndOfContent() ); 1134 1135 for( sal_uInt16 n = rSData.Count(); n; ) 1136 rSData[ --n ]->RedlineToDoc( aPam ); 1137 1138 // check redline count against count saved in RedlineSaveData object 1139 DBG_ASSERT( (rSData.Count() == 0) || 1140 (rSData[0]->nRedlineCount == rDoc.GetRedlineTbl().Count()), 1141 "redline count not restored properly" ); 1142 1143 rDoc.SetRedlineMode_intern( eOld ); 1144 } 1145 1146 sal_Bool SwUndo::HasHiddenRedlines( const SwRedlineSaveDatas& rSData ) 1147 { 1148 for( sal_uInt16 n = rSData.Count(); n; ) 1149 if( rSData[ --n ]->GetMvSttIdx() ) 1150 return sal_True; 1151 return sal_False; 1152 } 1153 1154 sal_Bool SwUndo::CanRedlineGroup( SwRedlineSaveDatas& rCurr, 1155 const SwRedlineSaveDatas& rCheck, sal_Bool bCurrIsEnd ) 1156 { 1157 sal_Bool bRet = sal_False; 1158 sal_uInt16 n; 1159 1160 if( rCurr.Count() == rCheck.Count() ) 1161 { 1162 bRet = sal_True; 1163 for( n = 0; n < rCurr.Count(); ++n ) 1164 { 1165 const SwRedlineSaveData& rSet = *rCurr[ n ]; 1166 const SwRedlineSaveData& rGet = *rCheck[ n ]; 1167 if( rSet.nSttNode != rGet.nSttNode || 1168 rSet.GetMvSttIdx() || rGet.GetMvSttIdx() || 1169 ( bCurrIsEnd ? rSet.nSttCntnt != rGet.nEndCntnt 1170 : rSet.nEndCntnt != rGet.nSttCntnt ) || 1171 !rGet.CanCombine( rSet ) ) 1172 { 1173 bRet = sal_False; 1174 break; 1175 } 1176 } 1177 1178 if( bRet ) 1179 for( n = 0; n < rCurr.Count(); ++n ) 1180 { 1181 SwRedlineSaveData& rSet = *rCurr[ n ]; 1182 const SwRedlineSaveData& rGet = *rCheck[ n ]; 1183 if( bCurrIsEnd ) 1184 rSet.nSttCntnt = rGet.nSttCntnt; 1185 else 1186 rSet.nEndCntnt = rGet.nEndCntnt; 1187 } 1188 } 1189 return bRet; 1190 } 1191 1192 // #111827# 1193 String ShortenString(const String & rStr, xub_StrLen nLength, const String & rFillStr) 1194 { 1195 ASSERT( nLength - rFillStr.Len() >= 2, "improper arguments") 1196 1197 String aResult; 1198 1199 if (rStr.Len() <= nLength) 1200 aResult = rStr; 1201 else 1202 { 1203 long nTmpLength = nLength - rFillStr.Len(); 1204 if ( nTmpLength < 2 ) 1205 nTmpLength = 2; 1206 1207 nLength = static_cast<xub_StrLen>(nTmpLength); 1208 1209 const xub_StrLen nFrontLen = nLength - nLength / 2; 1210 const xub_StrLen nBackLen = nLength - nFrontLen; 1211 1212 aResult += rStr.Copy(0, nFrontLen); 1213 aResult += rFillStr; 1214 aResult += rStr.Copy(rStr.Len() - nBackLen, nBackLen); 1215 } 1216 1217 return aResult; 1218 } 1219 1220 static bool lcl_IsSpecialCharacter(sal_Unicode nChar) 1221 { 1222 switch (nChar) 1223 { 1224 case CH_TXTATR_BREAKWORD: 1225 case CH_TXTATR_INWORD: 1226 case CH_TXTATR_TAB: 1227 case CH_TXTATR_NEWLINE: 1228 return true; 1229 1230 default: 1231 break; 1232 } 1233 1234 return false; 1235 } 1236 1237 static String lcl_DenotedPortion(String rStr, xub_StrLen nStart, 1238 xub_StrLen nEnd) 1239 { 1240 String aResult; 1241 1242 if (nEnd - nStart > 0) 1243 { 1244 sal_Unicode cLast = rStr.GetChar(nEnd - 1); 1245 if (lcl_IsSpecialCharacter(cLast)) 1246 { 1247 switch(cLast) 1248 { 1249 case CH_TXTATR_TAB: 1250 aResult += String(SW_RES(STR_UNDO_TABS)); 1251 1252 break; 1253 case CH_TXTATR_NEWLINE: 1254 aResult += String(SW_RES(STR_UNDO_NLS)); 1255 1256 break; 1257 1258 case CH_TXTATR_INWORD: 1259 case CH_TXTATR_BREAKWORD: 1260 aResult += UNDO_ARG2; 1261 1262 break; 1263 1264 } 1265 SwRewriter aRewriter; 1266 aRewriter.AddRule(UNDO_ARG1, 1267 String::CreateFromInt32(nEnd - nStart)); 1268 aResult = aRewriter.Apply(aResult); 1269 } 1270 else 1271 { 1272 aResult = String(SW_RES(STR_START_QUOTE)); 1273 aResult += rStr.Copy(nStart, nEnd - nStart); 1274 aResult += String(SW_RES(STR_END_QUOTE)); 1275 } 1276 } 1277 1278 return aResult; 1279 } 1280 1281 String DenoteSpecialCharacters(const String & rStr) 1282 { 1283 String aResult; 1284 1285 if (rStr.Len() > 0) 1286 { 1287 bool bStart = false; 1288 xub_StrLen nStart = 0; 1289 sal_Unicode cLast = 0; 1290 1291 for (xub_StrLen i = 0; i < rStr.Len(); i++) 1292 { 1293 if (lcl_IsSpecialCharacter(rStr.GetChar(i))) 1294 { 1295 if (cLast != rStr.GetChar(i)) 1296 bStart = true; 1297 1298 } 1299 else 1300 { 1301 if (lcl_IsSpecialCharacter(cLast)) 1302 bStart = true; 1303 } 1304 1305 if (bStart) 1306 { 1307 aResult += lcl_DenotedPortion(rStr, nStart, i); 1308 1309 nStart = i; 1310 bStart = false; 1311 } 1312 1313 cLast = rStr.GetChar(i); 1314 } 1315 1316 aResult += lcl_DenotedPortion(rStr, nStart, rStr.Len()); 1317 } 1318 else 1319 aResult = UNDO_ARG2; 1320 1321 return aResult; 1322 } 1323 1324 bool IsDestroyFrameAnchoredAtChar(SwPosition const & rAnchorPos, 1325 SwPosition const & rStart, SwPosition const & rEnd, 1326 DelCntntType const nDelCntntType) 1327 { 1328 1329 // Here we identified the objects to destroy: 1330 // - anchored between start and end of the selection 1331 // - anchored in start of the selection with "CheckNoContent" 1332 // - anchored in start of sel. and the selection start at pos 0 1333 return (rAnchorPos.nNode < rEnd.nNode) 1334 && ( (nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType) 1335 || (rStart.nNode < rAnchorPos.nNode) 1336 || !rStart.nContent.GetIndex() 1337 ); 1338 } 1339 1340