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