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