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