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 #include <string.h> // fuer strchr() 28 #include <hintids.hxx> 29 30 #include <vcl/sound.hxx> 31 #include <editeng/cscoitem.hxx> 32 #include <editeng/brkitem.hxx> 33 #include <linguistic/lngprops.hxx> 34 #include <com/sun/star/beans/XPropertySet.hpp> 35 #include <com/sun/star/i18n/WordType.hdl> 36 #include <unotools/charclass.hxx> 37 #include <unotools/transliterationwrapper.hxx> 38 #include <fmtanchr.hxx> 39 #include <fmtcntnt.hxx> 40 #include <fmtpdsc.hxx> 41 #include <txtftn.hxx> 42 #include <acorrect.hxx> // Autokorrektur 43 #include <IMark.hxx> // fuer SwBookmark 44 #include <cntfrm.hxx> // fuers Spell 45 #include <crsrsh.hxx> 46 #include <doc.hxx> 47 #include <UndoManager.hxx> 48 #include <docsh.hxx> 49 #include <docary.hxx> 50 #include <doctxm.hxx> // beim Move: Verzeichnisse korrigieren 51 #include <ftnidx.hxx> 52 #include <ftninfo.hxx> 53 #include <mdiexp.hxx> // Statusanzeige 54 #include <mvsave.hxx> // Strukturen zum Sichern beim Move/Delete 55 #include <ndtxt.hxx> 56 #include <pam.hxx> 57 #include <redline.hxx> 58 #include <rootfrm.hxx> // fuers UpdateFtn 59 #include <splargs.hxx> // fuer Spell 60 #include <swtable.hxx> 61 #include <swundo.hxx> // fuer die UndoIds 62 #include <txtfrm.hxx> 63 #include <hints.hxx> 64 #include <UndoSplitMove.hxx> 65 #include <UndoRedline.hxx> 66 #include <UndoOverwrite.hxx> 67 #include <UndoInsert.hxx> 68 #include <UndoDelete.hxx> 69 #include <breakit.hxx> 70 #include <hhcwrp.hxx> 71 #include <breakit.hxx> 72 #include <vcl/msgbox.hxx> 73 #include "comcore.hrc" 74 #include "editsh.hxx" 75 #include <unoflatpara.hxx> 76 #include <SwGrammarMarkUp.hxx> 77 78 #include <vector> 79 80 using ::rtl::OUString; 81 using namespace ::com::sun::star; 82 using namespace ::com::sun::star::linguistic2; 83 using namespace ::com::sun::star::i18n; 84 85 //using namespace ::utl; 86 #ifndef S2U 87 #define S2U(rString) OUString::createFromAscii(rString) 88 #endif 89 90 struct _SaveRedline 91 { 92 SwRedline* pRedl; 93 sal_uInt32 nStt, nEnd; 94 xub_StrLen nSttCnt, nEndCnt; 95 96 _SaveRedline( SwRedline* pR, const SwNodeIndex& rSttIdx ) 97 : pRedl( pR ) 98 { 99 const SwPosition* pStt = pR->Start(), 100 * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark(); 101 sal_uInt32 nSttIdx = rSttIdx.GetIndex(); 102 nStt = pStt->nNode.GetIndex() - nSttIdx; 103 nSttCnt = pStt->nContent.GetIndex(); 104 if( pR->HasMark() ) 105 { 106 nEnd = pEnd->nNode.GetIndex() - nSttIdx; 107 nEndCnt = pEnd->nContent.GetIndex(); 108 } 109 110 pRedl->GetPoint()->nNode = 0; 111 pRedl->GetPoint()->nContent.Assign( 0, 0 ); 112 pRedl->GetMark()->nNode = 0; 113 pRedl->GetMark()->nContent.Assign( 0, 0 ); 114 } 115 116 _SaveRedline( SwRedline* pR, const SwPosition& rPos ) 117 : pRedl( pR ) 118 { 119 const SwPosition* pStt = pR->Start(), 120 * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark(); 121 sal_uInt32 nSttIdx = rPos.nNode.GetIndex(); 122 nStt = pStt->nNode.GetIndex() - nSttIdx; 123 nSttCnt = pStt->nContent.GetIndex(); 124 if( nStt == 0 ) 125 nSttCnt = nSttCnt - rPos.nContent.GetIndex(); 126 if( pR->HasMark() ) 127 { 128 nEnd = pEnd->nNode.GetIndex() - nSttIdx; 129 nEndCnt = pEnd->nContent.GetIndex(); 130 if( nEnd == 0 ) 131 nEndCnt = nEndCnt - rPos.nContent.GetIndex(); 132 } 133 134 pRedl->GetPoint()->nNode = 0; 135 pRedl->GetPoint()->nContent.Assign( 0, 0 ); 136 pRedl->GetMark()->nNode = 0; 137 pRedl->GetMark()->nContent.Assign( 0, 0 ); 138 } 139 140 void SetPos( sal_uInt32 nInsPos ) 141 { 142 pRedl->GetPoint()->nNode = nInsPos + nStt; 143 pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt ); 144 if( pRedl->HasMark() ) 145 { 146 pRedl->GetMark()->nNode = nInsPos + nEnd; 147 pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt ); 148 } 149 } 150 151 void SetPos( const SwPosition& aPos ) 152 { 153 pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt; 154 pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) ); 155 if( pRedl->HasMark() ) 156 { 157 pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd; 158 pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) ); 159 } 160 } 161 }; 162 163 SV_DECL_PTRARR_DEL( _SaveRedlines, _SaveRedline*, 0, 4 ) 164 165 SV_IMPL_VARARR( _SaveFlyArr, _SaveFly ) 166 SV_IMPL_PTRARR( _SaveRedlines, _SaveRedline* ) 167 168 bool lcl_MayOverwrite( const SwTxtNode *pNode, const xub_StrLen nPos ) 169 { 170 sal_Unicode cChr = pNode->GetTxt().GetChar( nPos ); 171 return !( ( CH_TXTATR_BREAKWORD == cChr || CH_TXTATR_INWORD == cChr ) && 172 (0 != pNode->GetTxtAttrForCharAt( nPos ) ) ); 173 } 174 175 void lcl_SkipAttr( const SwTxtNode *pNode, SwIndex &rIdx, xub_StrLen &rStart ) 176 { 177 if( !lcl_MayOverwrite( pNode, rStart ) ) 178 { 179 // ueberspringe alle SonderAttribute 180 do { 181 // "Beep" bei jedem ausgelassenen 182 Sound::Beep(SOUND_ERROR); 183 rIdx++; 184 } while( (rStart = rIdx.GetIndex()) < pNode->GetTxt().Len() 185 && !lcl_MayOverwrite(pNode, rStart) ); 186 } 187 } 188 189 // ----------------------------------------------------------------- 190 191 void _RestFlyInRange( _SaveFlyArr & rArr, const SwNodeIndex& rSttIdx, 192 const SwNodeIndex* pInsertPos ) 193 { 194 SwPosition aPos( rSttIdx ); 195 for( sal_uInt16 n = 0; n < rArr.Count(); ++n ) 196 { 197 // neuen Anker anlegen 198 _SaveFly& rSave = rArr[n]; 199 SwFrmFmt* pFmt = rSave.pFrmFmt; 200 201 if( rSave.bInsertPosition ) 202 { 203 if( pInsertPos != NULL ) 204 aPos.nNode = *pInsertPos; 205 else 206 aPos.nNode = rSttIdx.GetIndex(); 207 } 208 else 209 aPos.nNode = rSttIdx.GetIndex() + rSave.nNdDiff; 210 211 aPos.nContent.Assign( 0, 0 ); 212 SwFmtAnchor aAnchor( pFmt->GetAnchor() ); 213 aAnchor.SetAnchor( &aPos ); 214 pFmt->GetDoc()->GetSpzFrmFmts()->Insert( 215 pFmt, pFmt->GetDoc()->GetSpzFrmFmts()->Count() ); 216 pFmt->SetFmtAttr( aAnchor ); 217 SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode(); 218 if( pCNd && pCNd->getLayoutFrm( pFmt->GetDoc()->GetCurrentLayout(), 0, 0, sal_False ) ) 219 pFmt->MakeFrms(); 220 } 221 } 222 223 void _SaveFlyInRange( const SwNodeRange& rRg, _SaveFlyArr& rArr ) 224 { 225 SwSpzFrmFmts& rFmts = *rRg.aStart.GetNode().GetDoc()->GetSpzFrmFmts(); 226 for( sal_uInt16 n = 0; n < rFmts.Count(); ++n ) 227 { 228 SwFrmFmt *const pFmt = static_cast<SwFrmFmt*>(rFmts[n]); 229 SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); 230 SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); 231 if (pAPos && 232 ((FLY_AT_PARA == pAnchor->GetAnchorId()) || 233 (FLY_AT_CHAR == pAnchor->GetAnchorId())) && 234 rRg.aStart <= pAPos->nNode && pAPos->nNode < rRg.aEnd ) 235 { 236 _SaveFly aSave( pAPos->nNode.GetIndex() - rRg.aStart.GetIndex(), 237 pFmt, sal_False ); 238 rArr.Insert( aSave, rArr.Count()); 239 pFmt->DelFrms(); 240 rFmts.Remove( n--, 1 ); 241 } 242 } 243 } 244 245 void _SaveFlyInRange( const SwPaM& rPam, const SwNodeIndex& rInsPos, 246 _SaveFlyArr& rArr, bool bMoveAllFlys ) 247 { 248 SwSpzFrmFmts& rFmts = *rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrmFmts(); 249 SwFrmFmt* pFmt; 250 const SwFmtAnchor* pAnchor; 251 252 const SwPosition* pPos = rPam.Start(); 253 const SwNodeIndex& rSttNdIdx = pPos->nNode; 254 short nSttOff = (!bMoveAllFlys && rSttNdIdx.GetNode().IsCntntNode() && 255 pPos->nContent.GetIndex()) ? 1 : 0; 256 257 pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint(); 258 const SwNodeIndex& rEndNdIdx = pPos->nNode; 259 short nOff = ( bMoveAllFlys || ( rEndNdIdx.GetNode().IsCntntNode() && 260 pPos->nContent == rEndNdIdx.GetNode().GetCntntNode()->Len() )) 261 ? 0 : 1; 262 263 const SwNodeIndex* pCntntIdx; 264 265 for( sal_uInt16 n = 0; n < rFmts.Count(); ++n ) 266 { 267 sal_Bool bInsPos = sal_False; 268 pFmt = (SwFrmFmt*)rFmts[n]; 269 pAnchor = &pFmt->GetAnchor(); 270 const SwPosition* pAPos = pAnchor->GetCntntAnchor(); 271 if (pAPos && 272 ((FLY_AT_PARA == pAnchor->GetAnchorId()) || 273 (FLY_AT_CHAR == pAnchor->GetAnchorId())) && 274 // nicht verschieben, wenn die InsPos im CntntBereich vom Fly ist 275 ( 0 == ( pCntntIdx = pFmt->GetCntnt().GetCntntIdx() ) || 276 !( *pCntntIdx < rInsPos && 277 rInsPos < pCntntIdx->GetNode().EndOfSectionIndex() )) ) 278 { 279 if( !bMoveAllFlys && rEndNdIdx == pAPos->nNode ) 280 { 281 // wenn nur teil vom EndNode oder der EndNode und SttNode 282 // identisch sind, chaos::Anchor nicht anfassen 283 if( rSttNdIdx != pAPos->nNode ) 284 { 285 // Anker nur an Anfang/Ende haengen 286 SwPosition aPos( rSttNdIdx ); 287 SwFmtAnchor aAnchor( *pAnchor ); 288 aAnchor.SetAnchor( &aPos ); 289 pFmt->SetFmtAttr( aAnchor ); 290 // ((SwFmtAnchor*)pAnchor)->SetAnchor( &aPos ); 291 } 292 } 293 else if( ( rSttNdIdx.GetIndex() + nSttOff <= pAPos->nNode.GetIndex() 294 && pAPos->nNode.GetIndex() <= rEndNdIdx.GetIndex() - nOff ) || 295 0 != ( bInsPos = rInsPos == pAPos->nNode )) 296 297 { 298 _SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(), 299 pFmt, bInsPos ); 300 rArr.Insert( aSave, rArr.Count()); 301 pFmt->DelFrms(); 302 rFmts.Remove( n--, 1 ); 303 } 304 } 305 } 306 } 307 308 // ----------------------------------------------------------------- 309 310 // loesche und verschiebe alle "Fly's am Absatz", die in der SSelection 311 // liegen. Steht am SPoint ein Fly, wird dieser auf den Mark verschoben. 312 313 void DelFlyInRange( const SwNodeIndex& rMkNdIdx, 314 const SwNodeIndex& rPtNdIdx ) 315 { 316 const sal_Bool bDelFwrd = rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex(); 317 318 SwDoc* pDoc = rMkNdIdx.GetNode().GetDoc(); 319 SwSpzFrmFmts& rTbl = *pDoc->GetSpzFrmFmts(); 320 for ( sal_uInt16 i = rTbl.Count(); i; ) 321 { 322 SwFrmFmt *pFmt = rTbl[--i]; 323 const SwFmtAnchor &rAnch = pFmt->GetAnchor(); 324 SwPosition const*const pAPos = rAnch.GetCntntAnchor(); 325 if (pAPos && 326 ((rAnch.GetAnchorId() == FLY_AT_PARA) || 327 (rAnch.GetAnchorId() == FLY_AT_CHAR)) && 328 ( bDelFwrd 329 ? rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx 330 : rPtNdIdx <= pAPos->nNode && pAPos->nNode < rMkNdIdx )) 331 { 332 // nur den Anker verschieben ?? 333 if( rPtNdIdx == pAPos->nNode ) 334 { 335 SwFmtAnchor aAnch( pFmt->GetAnchor() ); 336 SwPosition aPos( rMkNdIdx ); 337 aAnch.SetAnchor( &aPos ); 338 pFmt->SetFmtAttr( aAnch ); 339 } 340 else 341 { 342 // wird der Fly geloescht muss auch im seinem Inhalt alle 343 // Flys geloescht werden !! 344 const SwFmtCntnt &rCntnt = pFmt->GetCntnt(); 345 if( rCntnt.GetCntntIdx() ) 346 { 347 DelFlyInRange( *rCntnt.GetCntntIdx(), 348 SwNodeIndex( *rCntnt.GetCntntIdx()-> 349 GetNode().EndOfSectionNode() )); 350 // Position kann sich verschoben haben ! 351 if( i > rTbl.Count() ) 352 i = rTbl.Count(); 353 else if( pFmt != rTbl[i] ) 354 i = rTbl.GetPos( pFmt ); 355 } 356 357 pDoc->DelLayoutFmt( pFmt ); 358 359 // --> FME 2004-10-06 #117913# DelLayoutFmt can also 360 // trigger the deletion of objects. 361 if( i > rTbl.Count() ) 362 i = rTbl.Count(); 363 // <-- 364 } 365 } 366 } 367 } 368 369 370 bool lcl_SaveFtn( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd, 371 const SwNodeIndex& rInsPos, 372 SwFtnIdxs& rFtnArr, SwFtnIdxs& rSaveArr, 373 const SwIndex* pSttCnt = 0, const SwIndex* pEndCnt = 0 ) 374 { 375 bool bUpdateFtn = sal_False; 376 const SwNodes& rNds = rInsPos.GetNodes(); 377 const bool bDelFtn = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() && 378 rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex(); 379 const bool bSaveFtn = !bDelFtn && 380 rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex(); 381 if( rFtnArr.Count() ) 382 { 383 384 sal_uInt16 nPos; 385 rFtnArr.SeekEntry( rSttNd, &nPos ); 386 SwTxtFtn* pSrch; 387 const SwNode* pFtnNd; 388 389 // loesche/sicher erstmal alle, die dahinter stehen 390 while( nPos < rFtnArr.Count() && ( pFtnNd = 391 &( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex() 392 <= rEndNd.GetIndex() ) 393 { 394 xub_StrLen nFtnSttIdx = *pSrch->GetStart(); 395 if( ( pEndCnt && pSttCnt ) 396 ? (( &rSttNd.GetNode() == pFtnNd && 397 pSttCnt->GetIndex() > nFtnSttIdx) || 398 ( &rEndNd.GetNode() == pFtnNd && 399 nFtnSttIdx >= pEndCnt->GetIndex() )) 400 : ( &rEndNd.GetNode() == pFtnNd )) 401 { 402 ++nPos; // weiter suchen 403 } 404 else 405 { 406 // dann weg damit 407 if( bDelFtn ) 408 { 409 SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode(); 410 SwIndex aIdx( &rTxtNd, nFtnSttIdx ); 411 rTxtNd.EraseText( aIdx, 1 ); 412 } 413 else 414 { 415 pSrch->DelFrms(0); 416 rFtnArr.Remove( nPos ); 417 if( bSaveFtn ) 418 rSaveArr.Insert( pSrch ); 419 } 420 bUpdateFtn = sal_True; 421 } 422 } 423 424 while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )-> 425 GetTxtNode())->GetIndex() >= rSttNd.GetIndex() ) 426 { 427 xub_StrLen nFtnSttIdx = *pSrch->GetStart(); 428 if( !pEndCnt || !pSttCnt || 429 !( (( &rSttNd.GetNode() == pFtnNd && 430 pSttCnt->GetIndex() > nFtnSttIdx ) || 431 ( &rEndNd.GetNode() == pFtnNd && 432 nFtnSttIdx >= pEndCnt->GetIndex() )) )) 433 { 434 if( bDelFtn ) 435 { 436 // dann weg damit 437 SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode(); 438 SwIndex aIdx( &rTxtNd, nFtnSttIdx ); 439 rTxtNd.EraseText( aIdx, 1 ); 440 } 441 else 442 { 443 pSrch->DelFrms(0); 444 rFtnArr.Remove( nPos ); 445 if( bSaveFtn ) 446 rSaveArr.Insert( pSrch ); 447 } 448 bUpdateFtn = sal_True; 449 } 450 } 451 } 452 // When moving from redline section into document content section, e.g. 453 // after loading a document with (delete-)redlines, the footnote array 454 // has to be adjusted... (#i70572) 455 if( bSaveFtn ) 456 { 457 SwNodeIndex aIdx( rSttNd ); 458 while( aIdx < rEndNd ) // Check the moved section 459 { 460 SwNode* pNode = &aIdx.GetNode(); 461 if( pNode->IsTxtNode() ) // Looking for text nodes... 462 { 463 SwpHints *pHints = 464 static_cast<SwTxtNode*>(pNode)->GetpSwpHints(); 465 if( pHints && pHints->HasFtn() ) //...with footnotes 466 { 467 bUpdateFtn = sal_True; // Heureka 468 sal_uInt16 nCount = pHints->Count(); 469 for( sal_uInt16 i = 0; i < nCount; ++i ) 470 { 471 SwTxtAttr *pAttr = pHints->GetTextHint( i ); 472 if ( pAttr->Which() == RES_TXTATR_FTN ) 473 { 474 rSaveArr.Insert( static_cast<SwTxtFtn*>(pAttr) ); 475 } 476 } 477 } 478 } 479 ++aIdx; 480 } 481 } 482 return bUpdateFtn; 483 } 484 485 void lcl_SaveRedlines( const SwPaM& aPam, _SaveRedlines& rArr ) 486 { 487 SwDoc* pDoc = aPam.GetNode()->GetDoc(); 488 489 const SwPosition* pStart = aPam.Start(); 490 const SwPosition* pEnd = aPam.End(); 491 492 // get first relevant redline 493 sal_uInt16 nCurrentRedline; 494 pDoc->GetRedline( *pStart, &nCurrentRedline ); 495 if( nCurrentRedline > 0) 496 nCurrentRedline--; 497 498 // redline mode REDLINE_IGNORE|REDLINE_ON; save old mode 499 RedlineMode_t eOld = pDoc->GetRedlineMode(); 500 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); 501 502 // iterate over relevant redlines and decide for each whether it should 503 // be saved, or split + saved 504 SwRedlineTbl& rRedlineTable = const_cast<SwRedlineTbl&>( pDoc->GetRedlineTbl() ); 505 for( ; nCurrentRedline < rRedlineTable.Count(); nCurrentRedline++ ) 506 { 507 SwRedline* pCurrent = rRedlineTable[ nCurrentRedline ]; 508 SwComparePosition eCompare = 509 ComparePosition( *pCurrent->Start(), *pCurrent->End(), 510 *pStart, *pEnd); 511 512 // we must save this redline if it overlaps aPam 513 // (we may have to split it, too) 514 if( eCompare == POS_OVERLAP_BEHIND || 515 eCompare == POS_OVERLAP_BEFORE || 516 eCompare == POS_OUTSIDE || 517 eCompare == POS_INSIDE || 518 eCompare == POS_EQUAL ) 519 { 520 rRedlineTable.Remove( nCurrentRedline-- ); 521 522 // split beginning, if necessary 523 if( eCompare == POS_OVERLAP_BEFORE || 524 eCompare == POS_OUTSIDE ) 525 { 526 527 SwRedline* pNewRedline = new SwRedline( *pCurrent ); 528 *pNewRedline->End() = *pStart; 529 *pCurrent->Start() = *pStart; 530 pDoc->AppendRedline( pNewRedline, true ); 531 } 532 533 // split end, if necessary 534 if( eCompare == POS_OVERLAP_BEHIND || 535 eCompare == POS_OUTSIDE ) 536 { 537 SwRedline* pNewRedline = new SwRedline( *pCurrent ); 538 *pNewRedline->Start() = *pEnd; 539 *pCurrent->End() = *pEnd; 540 pDoc->AppendRedline( pNewRedline, true ); 541 } 542 543 // save the current redline 544 _SaveRedline* pSave = new _SaveRedline( pCurrent, *pStart ); 545 rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() ); 546 } 547 } 548 549 // restore old redline mode 550 pDoc->SetRedlineMode_intern( eOld ); 551 } 552 553 void lcl_RestoreRedlines( SwDoc* pDoc, const SwPosition& rPos, _SaveRedlines& rArr ) 554 { 555 RedlineMode_t eOld = pDoc->GetRedlineMode(); 556 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); 557 558 for( sal_uInt16 n = 0; n < rArr.Count(); ++n ) 559 { 560 _SaveRedline* pSave = rArr[ n ]; 561 pSave->SetPos( rPos ); 562 pDoc->AppendRedline( pSave->pRedl, true ); 563 } 564 565 pDoc->SetRedlineMode_intern( eOld ); 566 } 567 568 569 void lcl_SaveRedlines( const SwNodeRange& rRg, _SaveRedlines& rArr ) 570 { 571 SwDoc* pDoc = rRg.aStart.GetNode().GetDoc(); 572 sal_uInt16 nRedlPos; 573 SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--; 574 aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetCntntNode(), 0 ); 575 if( pDoc->GetRedline( aSrchPos, &nRedlPos ) && nRedlPos ) 576 --nRedlPos; 577 else if( nRedlPos >= pDoc->GetRedlineTbl().Count() ) 578 return ; 579 580 RedlineMode_t eOld = pDoc->GetRedlineMode(); 581 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); 582 SwRedlineTbl& rRedlTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl(); 583 584 do { 585 SwRedline* pTmp = rRedlTbl[ nRedlPos ]; 586 587 const SwPosition* pRStt = pTmp->Start(), 588 * pREnd = pTmp->GetMark() == pRStt 589 ? pTmp->GetPoint() : pTmp->GetMark(); 590 591 if( pRStt->nNode < rRg.aStart ) 592 { 593 if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd ) 594 { 595 // Kopie erzeugen und Ende vom Original ans Ende des 596 // MoveBereiches setzen. Die Kopie wird mit verschoben 597 SwRedline* pNewRedl = new SwRedline( *pTmp ); 598 SwPosition* pTmpPos = pNewRedl->Start(); 599 pTmpPos->nNode = rRg.aStart; 600 pTmpPos->nContent.Assign( 601 pTmpPos->nNode.GetNode().GetCntntNode(), 0 ); 602 603 _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart ); 604 // rArr.Insert( pSave, rArr.Count() ); 605 rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() ); 606 607 pTmpPos = pTmp->End(); 608 pTmpPos->nNode = rRg.aEnd; 609 pTmpPos->nContent.Assign( 610 pTmpPos->nNode.GetNode().GetCntntNode(), 0 ); 611 } 612 else if( pREnd->nNode == rRg.aStart ) 613 { 614 SwPosition* pTmpPos = pTmp->End(); 615 pTmpPos->nNode = rRg.aEnd; 616 pTmpPos->nContent.Assign( 617 pTmpPos->nNode.GetNode().GetCntntNode(), 0 ); 618 } 619 } 620 else if( pRStt->nNode < rRg.aEnd ) 621 { 622 rRedlTbl.Remove( nRedlPos-- ); 623 if( pREnd->nNode < rRg.aEnd || 624 ( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) ) 625 { 626 // gesamt verschieben 627 _SaveRedline* pSave = new _SaveRedline( pTmp, rRg.aStart ); 628 // rArr.Insert( pSave, rArr.Count() ); 629 rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() ); 630 } 631 else 632 { 633 // aufsplitten 634 SwRedline* pNewRedl = new SwRedline( *pTmp ); 635 SwPosition* pTmpPos = pNewRedl->End(); 636 pTmpPos->nNode = rRg.aEnd; 637 pTmpPos->nContent.Assign( 638 pTmpPos->nNode.GetNode().GetCntntNode(), 0 ); 639 640 _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart ); 641 // rArr.Insert( pSave, rArr.Count() ); 642 rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() ); 643 644 pTmpPos = pTmp->Start(); 645 pTmpPos->nNode = rRg.aEnd; 646 pTmpPos->nContent.Assign( 647 pTmpPos->nNode.GetNode().GetCntntNode(), 0 ); 648 pDoc->AppendRedline( pTmp, true ); 649 } 650 } 651 else 652 break; 653 654 } while( ++nRedlPos < pDoc->GetRedlineTbl().Count() ); 655 pDoc->SetRedlineMode_intern( eOld ); 656 } 657 658 void lcl_RestoreRedlines( SwDoc* pDoc, sal_uInt32 nInsPos, _SaveRedlines& rArr ) 659 { 660 RedlineMode_t eOld = pDoc->GetRedlineMode(); 661 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); 662 663 for( sal_uInt16 n = 0; n < rArr.Count(); ++n ) 664 { 665 _SaveRedline* pSave = rArr[ n ]; 666 pSave->SetPos( nInsPos ); 667 pDoc->AppendRedline( pSave->pRedl, true ); 668 } 669 670 pDoc->SetRedlineMode_intern( eOld ); 671 } 672 673 // ------------------------------------------------------------------------ 674 // #i59534: Redo of insertion of multiple text nodes runs into trouble 675 // because of unnecessary expanded redlines 676 // From now on this class saves the redline positions of all redlines which ends exact at the 677 // insert position (node _and_ content index) 678 679 _SaveRedlEndPosForRestore::_SaveRedlEndPosForRestore( const SwNodeIndex& rInsIdx, xub_StrLen nCnt ) 680 : pSavArr( 0 ), pSavIdx( 0 ), nSavCntnt( nCnt ) 681 { 682 SwNode& rNd = rInsIdx.GetNode(); 683 SwDoc* pDest = rNd.GetDoc(); 684 if( pDest->GetRedlineTbl().Count() ) 685 { 686 sal_uInt16 nFndPos; 687 const SwPosition* pEnd; 688 SwPosition aSrcPos( rInsIdx, SwIndex( rNd.GetCntntNode(), nCnt )); 689 const SwRedline* pRedl = pDest->GetRedline( aSrcPos, &nFndPos ); 690 while( nFndPos-- && *( pEnd = ( pRedl = 691 pDest->GetRedlineTbl()[ nFndPos ] )->End() ) == aSrcPos && *pRedl->Start() < aSrcPos ) 692 { 693 if( !pSavArr ) 694 { 695 pSavArr = new SvPtrarr( 2, 2 ); 696 pSavIdx = new SwNodeIndex( rInsIdx, -1 ); 697 } 698 void* p = (void*)pEnd; 699 pSavArr->Insert( p, pSavArr->Count() ); 700 } 701 } 702 } 703 704 _SaveRedlEndPosForRestore::~_SaveRedlEndPosForRestore() 705 { 706 if( pSavArr ) 707 { 708 delete pSavArr; 709 delete pSavIdx; 710 } 711 } 712 713 void _SaveRedlEndPosForRestore::_Restore() 714 { 715 (*pSavIdx)++; 716 SwCntntNode* pNode = pSavIdx->GetNode().GetCntntNode(); 717 // If there's no content node at the remembered position, we will not restore the old position 718 // This may happen if a table (or section?) will be inserted. 719 if( pNode ) 720 { 721 SwPosition aPos( *pSavIdx, SwIndex( pNode, nSavCntnt )); 722 for( sal_uInt16 n = pSavArr->Count(); n; ) 723 *((SwPosition*)pSavArr->GetObject( --n )) = aPos; 724 } 725 } 726 727 728 // ------------------------------------------------------------------------ 729 730 // Loeschen einer vollstaendigen Section des NodesArray. 731 // Der uebergebene Node steht irgendwo in der gewuenschten Section 732 void SwDoc::DeleteSection( SwNode *pNode ) 733 { 734 ASSERT( pNode, "Kein Node uebergeben." ); 735 SwStartNode* pSttNd = pNode->IsStartNode() ? (SwStartNode*)pNode 736 : pNode->StartOfSectionNode(); 737 SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() ); 738 739 // dann loesche mal alle Fly's, text::Bookmarks, ... 740 DelFlyInRange( aSttIdx, aEndIdx ); 741 DeleteRedline( *pSttNd, true, USHRT_MAX ); 742 _DelBookmarks(aSttIdx, aEndIdx); 743 744 { 745 // alle Crsr/StkCrsr/UnoCrsr aus dem Loeschbereich verschieben 746 SwNodeIndex aMvStt( aSttIdx, 1 ); 747 CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), sal_True ); 748 } 749 750 GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 ); 751 } 752 753 754 void SwDoc::SetModified(SwPaM &rPaM) 755 { 756 SwDataChanged aTmp( rPaM, 0 ); 757 SetModified(); 758 } 759 760 /************************************************************************* 761 * SwDoc::Overwrite() 762 ************************************************************************/ 763 764 bool SwDoc::Overwrite( const SwPaM &rRg, const String &rStr ) 765 { 766 SwPosition& rPt = *(SwPosition*)rRg.GetPoint(); 767 if( pACEWord ) // Aufnahme in die Autokorrektur 768 { 769 if( 1 == rStr.Len() ) 770 pACEWord->CheckChar( rPt, rStr.GetChar( 0 ) ); 771 delete pACEWord, pACEWord = 0; 772 } 773 774 SwTxtNode *pNode = rPt.nNode.GetNode().GetTxtNode(); 775 if(!pNode) 776 return sal_False; 777 778 if (GetIDocumentUndoRedo().DoesUndo()) 779 { 780 GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called 781 } 782 783 sal_uInt16 nOldAttrCnt = pNode->GetpSwpHints() 784 ? pNode->GetpSwpHints()->Count() : 0; 785 SwDataChanged aTmp( rRg, 0 ); 786 SwIndex& rIdx = rPt.nContent; 787 xub_StrLen nStart = 0; 788 789 sal_Unicode c; 790 String aStr; 791 792 sal_Bool bOldExpFlg = pNode->IsIgnoreDontExpand(); 793 pNode->SetIgnoreDontExpand( sal_True ); 794 795 for( xub_StrLen nCnt = 0; nCnt < rStr.Len(); ++nCnt ) 796 { 797 // hinter das Zeichen (zum aufspannen der Attribute !!) 798 nStart = rIdx.GetIndex(); 799 if ( nStart < pNode->GetTxt().Len() ) 800 { 801 lcl_SkipAttr( pNode, rIdx, nStart ); 802 } 803 c = rStr.GetChar( nCnt ); 804 if (GetIDocumentUndoRedo().DoesUndo()) 805 { 806 bool bMerged(false); 807 if (GetIDocumentUndoRedo().DoesGroupUndo()) 808 { 809 SwUndo *const pUndo = GetUndoManager().GetLastUndo(); 810 SwUndoOverwrite *const pUndoOW( 811 dynamic_cast<SwUndoOverwrite *>(pUndo) ); 812 if (pUndoOW) 813 { 814 // if CanGrouping() returns true it's already merged 815 bMerged = pUndoOW->CanGrouping( this, rPt, c ); 816 } 817 } 818 if (!bMerged) 819 { 820 SwUndo *const pUndoOW( new SwUndoOverwrite(this, rPt, c) ); 821 GetIDocumentUndoRedo().AppendUndo(pUndoOW); 822 } 823 } 824 else 825 { 826 // hinter das Zeichen (zum Aufspannen der Attribute !!) 827 if( nStart < pNode->GetTxt().Len() ) 828 rIdx++; 829 pNode->InsertText( c, rIdx, INS_EMPTYEXPAND ); 830 if( nStart+1 < rIdx.GetIndex() ) 831 { 832 rIdx = nStart; 833 pNode->EraseText( rIdx, 1 ); 834 rIdx++; 835 } 836 } 837 } 838 pNode->SetIgnoreDontExpand( bOldExpFlg ); 839 840 sal_uInt16 nNewAttrCnt = pNode->GetpSwpHints() 841 ? pNode->GetpSwpHints()->Count() : 0; 842 if( nOldAttrCnt != nNewAttrCnt ) 843 { 844 SwUpdateAttr aHint( 0, 0, 0 ); 845 pNode->ModifyBroadcast( 0, &aHint, TYPE( SwCrsrShell ) ); 846 } 847 848 if (!GetIDocumentUndoRedo().DoesUndo() && 849 !IsIgnoreRedline() && GetRedlineTbl().Count()) 850 { 851 SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() ); 852 DeleteRedline( aPam, true, USHRT_MAX ); 853 } 854 else if( IsRedlineOn() ) 855 { 856 // FIXME: this redline is WRONG: there is no DELETE, and the skipped 857 // characters are also included in aPam 858 SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() ); 859 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true); 860 } 861 862 SetModified(); 863 return sal_True; 864 } 865 866 867 bool SwDoc::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags ) 868 { 869 SwNodeIndex aIdx( rPaM.Start()->nNode ); 870 sal_Bool bJoinTxt = aIdx.GetNode().IsTxtNode(); 871 sal_Bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode; 872 aIdx--; // vor den Move Bereich !! 873 874 bool bRet = MoveRange( rPaM, rPos, eMvFlags ); 875 if( bRet && !bOneNode ) 876 { 877 if( bJoinTxt ) 878 aIdx++; 879 SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode(); 880 SwNodeIndex aNxtIdx( aIdx ); 881 if( pTxtNd && pTxtNd->CanJoinNext( &aNxtIdx ) ) 882 { 883 { // Block wegen SwIndex in den Node !! 884 CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex( pTxtNd, 885 pTxtNd->GetTxt().Len() ) ), 0, sal_True ); 886 } 887 pTxtNd->JoinNext(); 888 } 889 } 890 return bRet; 891 } 892 893 // mst: it seems that this is mostly used by SwDoc internals; the only 894 // way to call this from the outside seems to be the special case in 895 // SwDoc::CopyRange (but i have not managed to actually hit that case) 896 bool SwDoc::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags ) 897 { 898 // keine Moves-Abfangen 899 const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End(); 900 if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd)) 901 return false; 902 903 // sicher die absatzgebundenen Flys, damit sie verschoben werden koennen. 904 _SaveFlyArr aSaveFlyArr; 905 _SaveFlyInRange( rPaM, rPos.nNode, aSaveFlyArr, 0 != ( DOC_MOVEALLFLYS & eMvFlags ) ); 906 907 // save redlines (if DOC_MOVEREDLINES is used) 908 _SaveRedlines aSaveRedl( 0, 4 ); 909 if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() ) 910 { 911 lcl_SaveRedlines( rPaM, aSaveRedl ); 912 913 // #i17764# unfortunately, code below relies on undos being 914 // in a particular order, and presence of bookmarks 915 // will change this order. Hence, we delete bookmarks 916 // here without undo. 917 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); 918 _DelBookmarks( 919 pStt->nNode, 920 pEnd->nNode, 921 NULL, 922 &pStt->nContent, 923 &pEnd->nContent); 924 } 925 926 927 int bUpdateFtn = sal_False; 928 SwFtnIdxs aTmpFntIdx; 929 930 // falls Undo eingeschaltet, erzeuge das UndoMove-Objekt 931 SwUndoMove * pUndoMove = 0; 932 if (GetIDocumentUndoRedo().DoesUndo()) 933 { 934 GetIDocumentUndoRedo().ClearRedo(); 935 pUndoMove = new SwUndoMove( rPaM, rPos ); 936 pUndoMove->SetMoveRedlines( eMvFlags == DOC_MOVEREDLINES ); 937 } 938 else 939 { 940 bUpdateFtn = lcl_SaveFtn( pStt->nNode, pEnd->nNode, rPos.nNode, 941 GetFtnIdxs(), aTmpFntIdx, 942 &pStt->nContent, &pEnd->nContent ); 943 } 944 945 sal_Bool bSplit = sal_False; 946 SwPaM aSavePam( rPos, rPos ); 947 948 // stelle den SPoint an den Anfang vom Bereich (Definition) 949 if( rPaM.GetPoint() == pEnd ) 950 rPaM.Exchange(); 951 952 // in der EditShell wird nach dem Move ein JoinNext erzeugt, wenn 953 // vor und nach dem Move ein Text-Node steht. 954 SwTxtNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTxtNode(); 955 sal_Bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode; 956 957 // werden ein oder mehr TextNodes bewegt, so wird 958 // im SwNodes::Move ein SplitNode erzeugt. Dieser Updated aber nicht 959 // den Cursor. Um das zu verhindern, wird hier ein TextNode angelegt, 960 // um die Updaterei der Indizies zu erhalten. Nach dem Move wird 961 // evt. der Node geloescht. 962 963 SwTxtNode * pTNd = rPos.nNode.GetNode().GetTxtNode(); 964 if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode && 965 ( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam )) ) 966 { 967 bSplit = sal_True; 968 xub_StrLen nMkCntnt = rPaM.GetMark()->nContent.GetIndex(); 969 970 SvULongs aBkmkArr( 15, 15 ); 971 _SaveCntntIdx( this, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), 972 aBkmkArr, SAVEFLY_SPLIT ); 973 974 pTNd = static_cast<SwTxtNode*>(pTNd->SplitCntntNode( rPos )); 975 976 if( aBkmkArr.Count() ) 977 _RestoreCntntIdx( this, aBkmkArr, rPos.nNode.GetIndex()-1, 0, sal_True ); 978 979 // jetzt noch den Pam berichtigen !! 980 if( rPos.nNode == rPaM.GetMark()->nNode ) 981 { 982 rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1; 983 rPaM.GetMark()->nContent.Assign( pTNd, nMkCntnt ); 984 } 985 } 986 987 // setze den Pam um einen "Inhalt" zurueck; dadurch steht er immer 988 // ausserhalb des manipulierten Bereiches. Falls kein Inhalt mehr vor- 989 // handen, dann auf den StartNode (es ist immer einer vorhanden !!!) 990 sal_Bool bNullCntnt = !aSavePam.Move( fnMoveBackward, fnGoCntnt ); 991 if( bNullCntnt ) 992 { 993 aSavePam.GetPoint()->nNode--; 994 } 995 996 // kopiere alle Bookmarks, die im Move Bereich stehen in ein 997 // Array, das alle Angaben auf die Position als Offset speichert. 998 // Die neue Zuordung erfolgt nach dem Moven. 999 ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks; 1000 _DelBookmarks( 1001 pStt->nNode, 1002 pEnd->nNode, 1003 &aSaveBkmks, 1004 &pStt->nContent, 1005 &pEnd->nContent); 1006 1007 // falls durch die vorherigen Loeschungen (z.B. der Fussnoten) kein 1008 // Bereich mehr existiert, ist das immernoch ein gueltiger Move! 1009 if( *rPaM.GetPoint() != *rPaM.GetMark() ) 1010 { 1011 // now do the actual move 1012 GetNodes().MoveRange( rPaM, rPos, GetNodes() ); 1013 1014 // after a MoveRange() the Mark is deleted 1015 if ( rPaM.HasMark() ) // => no Move occurred! 1016 { 1017 delete pUndoMove; 1018 return false; 1019 } 1020 } 1021 else 1022 rPaM.DeleteMark(); 1023 1024 ASSERT( *aSavePam.GetMark() == rPos || 1025 ( aSavePam.GetMark()->nNode.GetNode().GetCntntNode() == NULL ), 1026 "PaM wurde nicht verschoben, am Anfang/Ende keine ContentNodes?" ); 1027 *aSavePam.GetMark() = rPos; 1028 1029 rPaM.SetMark(); // um den neuen Bereich eine Sel. aufspannen 1030 pTNd = aSavePam.GetNode()->GetTxtNode(); 1031 if (GetIDocumentUndoRedo().DoesUndo()) 1032 { 1033 // korrigiere erstmal den Content vom SavePam 1034 if( bNullCntnt ) 1035 { 1036 aSavePam.GetPoint()->nContent = 0; 1037 } 1038 1039 // die Methode SwEditShell::Move() fuegt nach dem Move den Text-Node 1040 // zusammen, in dem der rPaM steht. Wurde der Inhalt nach hinten 1041 // geschoben und liegt der SPoint vom SavePam im naechsten Node, so 1042 // muss beim Speichern vom Undo-Object das beachtet werden !! 1043 SwTxtNode * pPamTxtNd = 0; 1044 1045 // wird ans SwUndoMove weitergegeben, das dann beim Undo JoinNext 1046 // aufruft. (falls es hier nicht moeglich ist). 1047 sal_Bool bJoin = bSplit && pTNd; 1048 bCorrSavePam = bCorrSavePam && 1049 0 != ( pPamTxtNd = rPaM.GetNode()->GetTxtNode() ) 1050 && pPamTxtNd->CanJoinNext() 1051 && (*rPaM.GetPoint() <= *aSavePam.GetPoint()); 1052 1053 // muessen am SavePam 2 Nodes zusammengefasst werden ?? 1054 if( bJoin && pTNd->CanJoinNext() ) 1055 { 1056 pTNd->JoinNext(); 1057 // kein temp. sdbcx::Index bei && 1058 // es sollten wohl nur die Indexwerte verglichen werden. 1059 if( bCorrSavePam && rPaM.GetPoint()->nNode.GetIndex()+1 == 1060 aSavePam.GetPoint()->nNode.GetIndex() ) 1061 { 1062 aSavePam.GetPoint()->nContent += pPamTxtNd->Len(); 1063 } 1064 bJoin = sal_False; 1065 } 1066 // else if( !bCorrSavePam && !pSavePam->Move( fnMoveForward, fnGoCntnt )) 1067 else if ( !aSavePam.Move( fnMoveForward, fnGoCntnt ) ) 1068 { 1069 aSavePam.GetPoint()->nNode++; 1070 } 1071 1072 // zwischen SPoint und GetMark steht jetzt der neu eingefuegte Bereich 1073 pUndoMove->SetDestRange( aSavePam, *rPaM.GetPoint(), 1074 bJoin, bCorrSavePam ); 1075 GetIDocumentUndoRedo().AppendUndo( pUndoMove ); 1076 } 1077 else 1078 { 1079 bool bRemove = true; 1080 // muessen am SavePam 2 Nodes zusammengefasst werden ?? 1081 if( bSplit && pTNd ) 1082 { 1083 if( pTNd->CanJoinNext()) 1084 { 1085 // --> OD 2009-08-20 #i100466# 1086 // Always join next, because <pTNd> has to stay as it is. 1087 // A join previous from its next would more or less delete <pTNd> 1088 pTNd->JoinNext(); 1089 // <-- 1090 bRemove = false; 1091 } 1092 } 1093 if( bNullCntnt ) 1094 { 1095 aSavePam.GetPoint()->nNode++; 1096 aSavePam.GetPoint()->nContent.Assign( aSavePam.GetCntntNode(), 0 ); 1097 } 1098 else if( bRemove ) // No move forward after joining with next paragraph 1099 { 1100 aSavePam.Move( fnMoveForward, fnGoCntnt ); 1101 } 1102 } 1103 1104 // setze jetzt wieder die text::Bookmarks in das Dokument 1105 *rPaM.GetMark() = *aSavePam.Start(); 1106 for( 1107 ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin(); 1108 pBkmk != aSaveBkmks.end(); 1109 ++pBkmk) 1110 pBkmk->SetInDoc( 1111 this, 1112 rPaM.GetMark()->nNode, 1113 &rPaM.GetMark()->nContent); 1114 *rPaM.GetPoint() = *aSavePam.End(); 1115 1116 // verschiebe die Flys an die neue Position 1117 _RestFlyInRange( aSaveFlyArr, rPaM.Start()->nNode, &(rPos.nNode) ); 1118 1119 // restore redlines (if DOC_MOVEREDLINES is used) 1120 if( aSaveRedl.Count() ) 1121 { 1122 lcl_RestoreRedlines( this, *aSavePam.Start(), aSaveRedl ); 1123 } 1124 1125 if( bUpdateFtn ) 1126 { 1127 if( aTmpFntIdx.Count() ) 1128 { 1129 GetFtnIdxs().Insert( &aTmpFntIdx ); 1130 aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() ); 1131 } 1132 1133 GetFtnIdxs().UpdateAllFtn(); 1134 } 1135 1136 SetModified(); 1137 return true; 1138 } 1139 1140 bool SwDoc::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos, 1141 SwMoveFlags eMvFlags ) 1142 { 1143 // bewegt alle Nodes an die neue Position. Dabei werden die 1144 // text::Bookmarks mit verschoben !! (zur Zeit ohne Undo) 1145 1146 // falls durchs Move Fussnoten in den Sonderbereich kommen sollten, 1147 // dann entferne sie jetzt. 1148 //JP 13.07.95: 1149 // ansonsten bei allen Fussnoten, die verschoben werden, die Frames 1150 // loeschen und nach dem Move wieder aufbauen lassen (Fussnoten koennen 1151 // die Seite wechseln). Zusaetzlich muss natuerlich die Sortierung 1152 // der FtnIdx-Array wieder korrigiert werden. 1153 1154 int bUpdateFtn = sal_False; 1155 SwFtnIdxs aTmpFntIdx; 1156 1157 SwUndoMove* pUndo = 0; 1158 if ((DOC_CREATEUNDOOBJ & eMvFlags ) && GetIDocumentUndoRedo().DoesUndo()) 1159 { 1160 pUndo = new SwUndoMove( this, rRange, rPos ); 1161 } 1162 else 1163 { 1164 bUpdateFtn = lcl_SaveFtn( rRange.aStart, rRange.aEnd, rPos, 1165 GetFtnIdxs(), aTmpFntIdx ); 1166 } 1167 1168 _SaveRedlines aSaveRedl( 0, 4 ); 1169 SvPtrarr aSavRedlInsPosArr( 0, 4 ); 1170 if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() ) 1171 { 1172 lcl_SaveRedlines( rRange, aSaveRedl ); 1173 1174 // suche alle Redlines, die an der InsPos aufhoeren. Diese muessen 1175 // nach dem Move wieder an die "alte" Position verschoben werden 1176 sal_uInt16 nRedlPos = GetRedlinePos( rPos.GetNode(), USHRT_MAX ); 1177 if( USHRT_MAX != nRedlPos ) 1178 { 1179 const SwPosition *pRStt, *pREnd; 1180 do { 1181 SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ]; 1182 pRStt = pTmp->Start(); 1183 pREnd = pTmp->End(); 1184 if( pREnd->nNode == rPos && pRStt->nNode < rPos ) 1185 { 1186 void* p = pTmp; 1187 aSavRedlInsPosArr.Insert( p, aSavRedlInsPosArr.Count() ); 1188 } 1189 } while( pRStt->nNode < rPos && ++nRedlPos < GetRedlineTbl().Count()); 1190 } 1191 } 1192 1193 // kopiere alle Bookmarks, die im Move Bereich stehen in ein 1194 // Array, das alle Angaben auf die Position als Offset speichert. 1195 // Die neue Zuordung erfolgt nach dem Moven. 1196 ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks; 1197 _DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks); 1198 1199 // sicher die absatzgebundenen Flys, damit verschoben werden koennen. 1200 _SaveFlyArr aSaveFlyArr; 1201 if( GetSpzFrmFmts()->Count() ) 1202 _SaveFlyInRange( rRange, aSaveFlyArr ); 1203 1204 // vor die Position setzen, damit er nicht weitergeschoben wird 1205 SwNodeIndex aIdx( rPos, -1 ); 1206 1207 SwNodeIndex* pSaveInsPos = 0; 1208 if( pUndo ) 1209 pSaveInsPos = new SwNodeIndex( rRange.aStart, -1 ); 1210 1211 // verschiebe die Nodes 1212 sal_Bool bNoDelFrms = 0 != (DOC_NO_DELFRMS & eMvFlags); 1213 if( GetNodes()._MoveNodes( rRange, GetNodes(), rPos, !bNoDelFrms ) ) 1214 { 1215 aIdx++; // wieder auf alte Position 1216 if( pSaveInsPos ) 1217 (*pSaveInsPos)++; 1218 } 1219 else 1220 { 1221 aIdx = rRange.aStart; 1222 delete pUndo, pUndo = 0; 1223 } 1224 1225 // verschiebe die Flys an die neue Position 1226 if( aSaveFlyArr.Count() ) 1227 _RestFlyInRange( aSaveFlyArr, aIdx, NULL ); 1228 1229 // setze jetzt wieder die text::Bookmarks in das Dokument 1230 for( 1231 ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin(); 1232 pBkmk != aSaveBkmks.end(); 1233 ++pBkmk) 1234 pBkmk->SetInDoc(this, aIdx); 1235 1236 if( aSavRedlInsPosArr.Count() ) 1237 { 1238 SwNode* pNewNd = &aIdx.GetNode(); 1239 for( sal_uInt16 n = 0; n < aSavRedlInsPosArr.Count(); ++n ) 1240 { 1241 SwRedline* pTmp = (SwRedline*)aSavRedlInsPosArr[ n ]; 1242 if( USHRT_MAX != GetRedlineTbl().GetPos( pTmp ) ) 1243 { 1244 SwPosition* pEnd = pTmp->End(); 1245 pEnd->nNode = aIdx; 1246 pEnd->nContent.Assign( pNewNd->GetCntntNode(), 0 ); 1247 } 1248 } 1249 } 1250 1251 if( aSaveRedl.Count() ) 1252 lcl_RestoreRedlines( this, aIdx.GetIndex(), aSaveRedl ); 1253 1254 if( pUndo ) 1255 { 1256 pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos ); 1257 GetIDocumentUndoRedo().AppendUndo(pUndo); 1258 } 1259 1260 if( pSaveInsPos ) 1261 delete pSaveInsPos; 1262 1263 if( bUpdateFtn ) 1264 { 1265 if( aTmpFntIdx.Count() ) 1266 { 1267 GetFtnIdxs().Insert( &aTmpFntIdx ); 1268 aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() ); 1269 } 1270 1271 GetFtnIdxs().UpdateAllFtn(); 1272 } 1273 1274 SetModified(); 1275 return sal_True; 1276 } 1277 1278 /* #107318# Convert list of ranges of whichIds to a corresponding list 1279 of whichIds*/ 1280 SvUShorts * lcl_RangesToUShorts(sal_uInt16 * pRanges) 1281 { 1282 SvUShorts * pResult = new SvUShorts(); 1283 1284 int i = 0; 1285 while (pRanges[i] != 0) 1286 { 1287 ASSERT(pRanges[i+1] != 0, "malformed ranges"); 1288 1289 for (sal_uInt16 j = pRanges[i]; j < pRanges[i+1]; j++) 1290 pResult->Insert(j, pResult->Count()); 1291 1292 i += 2; 1293 } 1294 1295 return pResult; 1296 } 1297 1298 bool lcl_StrLenOverFlow( const SwPaM& rPam ) 1299 { 1300 // If we try to merge two paragraph we have to test if afterwards 1301 // the string doesn't exceed the allowed string length 1302 bool bRet = false; 1303 if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode ) 1304 { 1305 const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End(); 1306 const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode(); 1307 if( (0 != pEndNd) && pStt->nNode.GetNode().IsTxtNode() ) 1308 { 1309 sal_uInt64 nSum = pStt->nContent.GetIndex() + 1310 pEndNd->GetTxt().Len() - pEnd->nContent.GetIndex(); 1311 if( nSum > STRING_LEN ) 1312 bRet = true; 1313 } 1314 } 1315 return bRet; 1316 } 1317 1318 void lcl_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev ) 1319 { 1320 rJoinTxt = sal_False; 1321 rJoinPrev = sal_False; 1322 if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode ) 1323 { 1324 const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End(); 1325 SwTxtNode *pSttNd = pStt->nNode.GetNode().GetTxtNode(); 1326 if( pSttNd ) 1327 { 1328 SwTxtNode *pEndNd = pEnd->nNode.GetNode().GetTxtNode(); 1329 rJoinTxt = 0 != pEndNd; 1330 if( rJoinTxt ) 1331 { 1332 bool bExchange = pStt == rPam.GetPoint(); 1333 if( !pStt->nContent.GetIndex() && 1334 pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex() ) 1335 bExchange = !bExchange; 1336 if( bExchange ) 1337 rPam.Exchange(); 1338 rJoinPrev = rPam.GetPoint() == pStt; 1339 ASSERT( !pStt->nContent.GetIndex() && 1340 pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex() 1341 ? rPam.GetPoint()->nNode < rPam.GetMark()->nNode 1342 : rPam.GetPoint()->nNode > rPam.GetMark()->nNode, 1343 "lcl_GetJoinFlags"); 1344 } 1345 } 1346 } 1347 } 1348 1349 void lcl_JoinText( SwPaM& rPam, sal_Bool bJoinPrev ) 1350 { 1351 SwNodeIndex aIdx( rPam.GetPoint()->nNode ); 1352 SwTxtNode *pTxtNd = aIdx.GetNode().GetTxtNode(); 1353 SwNodeIndex aOldIdx( aIdx ); 1354 SwTxtNode *pOldTxtNd = pTxtNd; 1355 1356 if( pTxtNd && pTxtNd->CanJoinNext( &aIdx ) ) 1357 { 1358 SwDoc* pDoc = rPam.GetDoc(); 1359 if( bJoinPrev ) 1360 { 1361 // N.B.: we do not need to handle xmlids in this case, because 1362 // it is only invoked if one paragraph is completely empty 1363 // (see lcl_GetJoinFlags) 1364 { 1365 // falls PageBreaks geloescht / gesetzt werden, darf das 1366 // nicht in die Undo-History aufgenommen werden !! 1367 // (das loeschen vom Node geht auch am Undo vorbei !!!) 1368 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); 1369 1370 /* PageBreaks, PageDesc, ColumnBreaks */ 1371 // Sollte an der Logik zum Kopieren der PageBreak's ... 1372 // etwas geaendert werden, muss es auch im SwUndoDelete 1373 // geandert werden. Dort wird sich das AUTO-PageBreak 1374 // aus dem GetMarkNode kopiert.!!! 1375 1376 /* Der GetMarkNode */ 1377 if( ( pTxtNd = aIdx.GetNode().GetTxtNode())->HasSwAttrSet() ) 1378 { 1379 const SfxPoolItem* pItem; 1380 if( SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState( 1381 RES_BREAK, sal_False, &pItem ) ) 1382 pTxtNd->ResetAttr( RES_BREAK ); 1383 if( pTxtNd->HasSwAttrSet() && 1384 SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState( 1385 RES_PAGEDESC, sal_False, &pItem ) ) 1386 pTxtNd->ResetAttr( RES_PAGEDESC ); 1387 } 1388 1389 /* Der PointNode */ 1390 if( pOldTxtNd->HasSwAttrSet() ) 1391 { 1392 const SfxPoolItem* pItem; 1393 SfxItemSet aSet( pDoc->GetAttrPool(), aBreakSetRange ); 1394 const SfxItemSet* pSet = pOldTxtNd->GetpSwAttrSet(); 1395 if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, 1396 sal_False, &pItem ) ) 1397 aSet.Put( *pItem ); 1398 if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC, 1399 sal_False, &pItem ) ) 1400 aSet.Put( *pItem ); 1401 if( aSet.Count() ) 1402 pTxtNd->SetAttr( aSet ); 1403 } 1404 pOldTxtNd->FmtToTxtAttr( pTxtNd ); 1405 1406 SvULongs aBkmkArr( 15, 15 ); 1407 ::_SaveCntntIdx( pDoc, aOldIdx.GetIndex(), 1408 pOldTxtNd->Len(), aBkmkArr ); 1409 1410 SwIndex aAlphaIdx(pTxtNd); 1411 pOldTxtNd->CutText( pTxtNd, aAlphaIdx, SwIndex(pOldTxtNd), 1412 pOldTxtNd->Len() ); 1413 SwPosition aAlphaPos( aIdx, aAlphaIdx ); 1414 pDoc->CorrRel( rPam.GetPoint()->nNode, aAlphaPos, 0, sal_True ); 1415 1416 // verschiebe noch alle Bookmarks/TOXMarks 1417 if( aBkmkArr.Count() ) 1418 ::_RestoreCntntIdx( pDoc, aBkmkArr, aIdx.GetIndex() ); 1419 1420 // falls der uebergebene PaM nicht im Crsr-Ring steht, 1421 // gesondert behandeln (z.B. Aufruf aus dem Auto-Format) 1422 if( pOldTxtNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() ) 1423 rPam.GetBound( sal_True ) = aAlphaPos; 1424 if( pOldTxtNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() ) 1425 rPam.GetBound( sal_False ) = aAlphaPos; 1426 } 1427 // jetzt nur noch den Node loeschen 1428 pDoc->GetNodes().Delete( aOldIdx, 1 ); 1429 } 1430 else 1431 { 1432 SwTxtNode* pDelNd = aIdx.GetNode().GetTxtNode(); 1433 if( pTxtNd->Len() ) 1434 pDelNd->FmtToTxtAttr( pTxtNd ); 1435 else 1436 { 1437 /* #107318# This case was missed: 1438 1439 <something></something> <-- pTxtNd 1440 <other>ccc</other> <-- pDelNd 1441 1442 <something> and <other> are paragraph 1443 attributes. The attribute <something> stayed if not 1444 overwritten by an attribute in "ccc". Fixed by 1445 first resetting all character attributes in first 1446 paragraph (pTxtNd). 1447 */ 1448 SvUShorts * pShorts = 1449 lcl_RangesToUShorts(aCharFmtSetRange); 1450 pTxtNd->ResetAttr(*pShorts); 1451 delete pShorts; 1452 1453 if( pDelNd->HasSwAttrSet() ) 1454 { 1455 // nur die Zeichenattribute kopieren 1456 SfxItemSet aTmpSet( pDoc->GetAttrPool(), aCharFmtSetRange ); 1457 aTmpSet.Put( *pDelNd->GetpSwAttrSet() ); 1458 pTxtNd->SetAttr( aTmpSet ); 1459 } 1460 } 1461 1462 pDoc->CorrRel( aIdx, *rPam.GetPoint(), 0, sal_True ); 1463 // --> OD 2009-08-20 #i100466# 1464 // adjust given <rPam>, if it does not belong to the cursors 1465 if ( pDelNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() ) 1466 { 1467 rPam.GetBound( sal_True ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) ); 1468 } 1469 if( pDelNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() ) 1470 { 1471 rPam.GetBound( sal_False ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) ); 1472 } 1473 // <-- 1474 pTxtNd->JoinNext(); 1475 } 1476 } 1477 } 1478 1479 static void 1480 lcl_CalcBreaks( ::std::vector<xub_StrLen> & rBreaks, SwPaM const & rPam ) 1481 { 1482 SwTxtNode const * const pTxtNode( 1483 rPam.End()->nNode.GetNode().GetTxtNode() ); 1484 if (!pTxtNode) 1485 return; // left-overlap only possible at end of selection... 1486 1487 const xub_StrLen nStart(rPam.Start()->nContent.GetIndex()); 1488 const xub_StrLen nEnd (rPam.End ()->nContent.GetIndex()); 1489 if (nEnd == pTxtNode->Len()) 1490 return; // paragraph selected until the end 1491 1492 for (xub_StrLen i = nStart; i < nEnd; ++i) 1493 { 1494 const sal_Unicode c(pTxtNode->GetTxt().GetChar(i)); 1495 if ((CH_TXTATR_INWORD == c) || (CH_TXTATR_BREAKWORD == c)) 1496 { 1497 SwTxtAttr const * const pAttr( pTxtNode->GetTxtAttrForCharAt(i) ); 1498 if (pAttr && pAttr->GetEnd() && (*pAttr->GetEnd() > nEnd)) 1499 { 1500 ASSERT(pAttr->HasDummyChar(), "GetTxtAttrForCharAt broken?"); 1501 rBreaks.push_back(i); 1502 } 1503 } 1504 } 1505 } 1506 1507 bool lcl_DoWithBreaks(SwDoc & rDoc, SwPaM & rPam, 1508 bool (SwDoc::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false) 1509 { 1510 ::std::vector<xub_StrLen> Breaks; 1511 1512 lcl_CalcBreaks(Breaks, rPam); 1513 1514 if (!Breaks.size()) 1515 { 1516 return (rDoc.*pFunc)(rPam, bForceJoinNext); 1517 } 1518 1519 // N.B.: deletion must be split into several parts if the text node 1520 // contains a text attribute with end and with dummy character 1521 // and the selection does not contain the text attribute completely, 1522 // but overlaps its start (left), where the dummy character is. 1523 1524 SwPosition const & rSelectionEnd( *rPam.End() ); 1525 1526 bool bRet( true ); 1527 // iterate from end to start, to avoid invalidating the offsets! 1528 ::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() ); 1529 SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node! 1530 SwPosition & rEnd( *aPam.End() ); 1531 SwPosition & rStart( *aPam.Start() ); 1532 1533 while (iter != Breaks.rend()) 1534 { 1535 rStart.nContent = *iter + 1; 1536 if (rEnd.nContent > rStart.nContent) // check if part is empty 1537 { 1538 bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext); 1539 } 1540 rEnd.nContent = *iter; 1541 ++iter; 1542 } 1543 1544 rStart = *rPam.Start(); // set to original start 1545 if (rEnd.nContent > rStart.nContent) // check if part is empty 1546 { 1547 bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext); 1548 } 1549 1550 return bRet; 1551 } 1552 1553 1554 bool SwDoc::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool ) 1555 { 1556 ASSERT( IsRedlineOn(), "DeleteAndJoinWithRedline: redline off" ); 1557 1558 { 1559 SwUndoRedlineDelete* pUndo = 0; 1560 RedlineMode_t eOld = GetRedlineMode(); 1561 checkRedlining(eOld); 1562 if (GetIDocumentUndoRedo().DoesUndo()) 1563 { 1564 1565 //JP 06.01.98: MUSS noch optimiert werden!!! 1566 SetRedlineMode( 1567 (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE )); 1568 1569 GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); 1570 pUndo = new SwUndoRedlineDelete( rPam, UNDO_DELETE ); 1571 GetIDocumentUndoRedo().AppendUndo(pUndo); 1572 } 1573 if( *rPam.GetPoint() != *rPam.GetMark() ) 1574 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, rPam ), true); 1575 SetModified(); 1576 1577 if( pUndo ) 1578 { 1579 GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); 1580 // ??? why the hell is the AppendUndo not below the 1581 // CanGrouping, so this hideous cleanup wouldn't be necessary? 1582 // bah, this is redlining, probably changing this would break it... 1583 if (GetIDocumentUndoRedo().DoesGroupUndo()) 1584 { 1585 SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() ); 1586 SwUndoRedlineDelete *const pUndoRedlineDel( 1587 dynamic_cast<SwUndoRedlineDelete*>(pLastUndo) ); 1588 if (pUndoRedlineDel) 1589 { 1590 bool const bMerged = pUndoRedlineDel->CanGrouping(*pUndo); 1591 if (bMerged) 1592 { 1593 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); 1594 SwUndo const*const pDeleted = 1595 GetUndoManager().RemoveLastUndo(); 1596 OSL_ENSURE(pDeleted == pUndo, 1597 "DeleteAndJoinWithRedlineImpl: " 1598 "undo removed is not undo inserted?"); 1599 delete pDeleted; 1600 } 1601 } 1602 } 1603 //JP 06.01.98: MUSS noch optimiert werden!!! 1604 SetRedlineMode( eOld ); 1605 } 1606 return true; 1607 } 1608 } 1609 1610 bool SwDoc::DeleteAndJoinImpl( SwPaM & rPam, 1611 const bool bForceJoinNext ) 1612 { 1613 sal_Bool bJoinTxt, bJoinPrev; 1614 lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev ); 1615 // --> OD 2009-08-20 #i100466# 1616 if ( bForceJoinNext ) 1617 { 1618 bJoinPrev = sal_False; 1619 } 1620 // <-- 1621 { 1622 bool const bSuccess( DeleteRangeImpl( rPam ) ); 1623 if (!bSuccess) 1624 return false; 1625 } 1626 1627 if( bJoinTxt ) 1628 { 1629 lcl_JoinText( rPam, bJoinPrev ); 1630 } 1631 1632 return true; 1633 } 1634 1635 bool SwDoc::DeleteRangeImpl(SwPaM & rPam, const bool) 1636 { 1637 // move all cursors out of the deleted range. 1638 // but first copy the given PaM, because it could be a cursor that 1639 // would be moved! 1640 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() ); 1641 ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() ); 1642 1643 bool const bSuccess( DeleteRangeImplImpl( aDelPam ) ); 1644 if (bSuccess) 1645 { // now copy position from temp copy to given PaM 1646 *rPam.GetPoint() = *aDelPam.GetPoint(); 1647 } 1648 1649 return bSuccess; 1650 } 1651 1652 bool SwDoc::DeleteRangeImplImpl(SwPaM & rPam) 1653 { 1654 SwPosition *pStt = (SwPosition*)rPam.Start(), *pEnd = (SwPosition*)rPam.End(); 1655 1656 if( !rPam.HasMark() || *pStt >= *pEnd ) 1657 return false; 1658 1659 if( pACEWord ) 1660 { 1661 // ggfs. das gesicherte Word fuer die Ausnahme 1662 if( pACEWord->IsDeleted() || pStt->nNode != pEnd->nNode || 1663 pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() || 1664 !pACEWord->CheckDelChar( *pStt )) 1665 delete pACEWord, pACEWord = 0; 1666 } 1667 1668 { 1669 // loesche alle leeren TextHints an der Mark-Position 1670 SwTxtNode* pTxtNd = rPam.GetMark()->nNode.GetNode().GetTxtNode(); 1671 SwpHints* pHts; 1672 if( pTxtNd && 0 != ( pHts = pTxtNd->GetpSwpHints()) && pHts->Count() ) 1673 { 1674 const xub_StrLen *pEndIdx; 1675 xub_StrLen nMkCntPos = rPam.GetMark()->nContent.GetIndex(); 1676 for( sal_uInt16 n = pHts->Count(); n; ) 1677 { 1678 const SwTxtAttr* pAttr = (*pHts)[ --n ]; 1679 if( nMkCntPos > *pAttr->GetStart() ) 1680 break; 1681 1682 if( nMkCntPos == *pAttr->GetStart() && 1683 0 != (pEndIdx = pAttr->GetEnd()) && 1684 *pEndIdx == *pAttr->GetStart() ) 1685 pTxtNd->DestroyAttr( pHts->Cut( n ) ); 1686 } 1687 } 1688 } 1689 1690 { 1691 // Bug 26675: DataChanged vorm loeschen verschicken, dann bekommt 1692 // man noch mit, welche Objecte sich im Bereich befinden. 1693 // Danach koennen sie vor/hinter der Position befinden. 1694 SwDataChanged aTmp( rPam, 0 ); 1695 } 1696 1697 1698 if (GetIDocumentUndoRedo().DoesUndo()) 1699 { 1700 GetIDocumentUndoRedo().ClearRedo(); 1701 bool bMerged(false); 1702 if (GetIDocumentUndoRedo().DoesGroupUndo()) 1703 { 1704 SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() ); 1705 SwUndoDelete *const pUndoDelete( 1706 dynamic_cast<SwUndoDelete *>(pLastUndo) ); 1707 if (pUndoDelete) 1708 { 1709 bMerged = pUndoDelete->CanGrouping( this, rPam ); 1710 // if CanGrouping() returns true it's already merged 1711 } 1712 } 1713 if (!bMerged) 1714 { 1715 GetIDocumentUndoRedo().AppendUndo( new SwUndoDelete( rPam ) ); 1716 } 1717 1718 SetModified(); 1719 1720 return true; 1721 } 1722 1723 if( !IsIgnoreRedline() && GetRedlineTbl().Count() ) 1724 DeleteRedline( rPam, true, USHRT_MAX ); 1725 1726 // loesche und verschiebe erstmal alle "Fly's am Absatz", die in der 1727 // Selection liegen 1728 DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode); 1729 _DelBookmarks( 1730 pStt->nNode, 1731 pEnd->nNode, 1732 NULL, 1733 &pStt->nContent, 1734 &pEnd->nContent); 1735 1736 SwNodeIndex aSttIdx( pStt->nNode ); 1737 SwCntntNode * pCNd = aSttIdx.GetNode().GetCntntNode(); 1738 1739 do { // middle checked loop! 1740 if( pCNd ) 1741 { 1742 SwTxtNode * pStartTxtNode( pCNd->GetTxtNode() ); 1743 if ( pStartTxtNode ) 1744 { 1745 // verschiebe jetzt noch den Inhalt in den neuen Node 1746 sal_Bool bOneNd = pStt->nNode == pEnd->nNode; 1747 xub_StrLen nLen = ( bOneNd ? pEnd->nContent.GetIndex() 1748 : pCNd->Len() ) 1749 - pStt->nContent.GetIndex(); 1750 1751 // falls schon leer, dann nicht noch aufrufen 1752 if( nLen ) 1753 { 1754 pStartTxtNode->EraseText( pStt->nContent, nLen ); 1755 1756 if( !pStartTxtNode->Len() ) 1757 { 1758 // METADATA: remove reference if empty (consider node deleted) 1759 pStartTxtNode->RemoveMetadataReference(); 1760 } 1761 } 1762 1763 if( bOneNd ) // das wars schon 1764 break; 1765 1766 aSttIdx++; 1767 } 1768 else 1769 { 1770 // damit beim loeschen keine Indizies mehr angemeldet sind, 1771 // wird hier der SwPaM aus dem Content entfernt !! 1772 pStt->nContent.Assign( 0, 0 ); 1773 } 1774 } 1775 1776 pCNd = pEnd->nNode.GetNode().GetCntntNode(); 1777 if( pCNd ) 1778 { 1779 SwTxtNode * pEndTxtNode( pCNd->GetTxtNode() ); 1780 if( pEndTxtNode ) 1781 { 1782 // falls schon leer, dann nicht noch aufrufen 1783 if( pEnd->nContent.GetIndex() ) 1784 { 1785 SwIndex aIdx( pCNd, 0 ); 1786 pEndTxtNode->EraseText( aIdx, pEnd->nContent.GetIndex() ); 1787 1788 if( !pEndTxtNode->Len() ) 1789 { 1790 // METADATA: remove reference if empty (consider node deleted) 1791 pEndTxtNode->RemoveMetadataReference(); 1792 } 1793 } 1794 } 1795 else 1796 { 1797 // damit beim Loeschen keine Indizies mehr angemeldet sind, 1798 // wird hier der SwPaM aus dem Content entfernt !! 1799 pEnd->nContent.Assign( 0, 0 ); 1800 } 1801 } 1802 1803 // if the end is not a content node, delete it as well 1804 sal_uInt32 nEnde = pEnd->nNode.GetIndex(); 1805 if( pCNd == NULL ) 1806 nEnde++; 1807 1808 if( aSttIdx != nEnde ) 1809 { 1810 // loesche jetzt die Nodes in das NodesArary 1811 GetNodes().Delete( aSttIdx, nEnde - aSttIdx.GetIndex() ); 1812 } 1813 1814 // falls der Node geloescht wurde, in dem der Cursor stand, so 1815 // muss der Content im akt. Content angemeldet werden !!! 1816 pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(), 1817 pStt->nContent.GetIndex() ); 1818 1819 // der PaM wird korrigiert, denn falls ueber Nodegrenzen geloescht 1820 // wurde, so stehen sie in unterschieden Nodes. Auch die Selektion 1821 // wird aufgehoben ! 1822 *pEnd = *pStt; 1823 rPam.DeleteMark(); 1824 1825 } while( sal_False ); 1826 1827 if( !IsIgnoreRedline() && GetRedlineTbl().Count() ) 1828 CompressRedlines(); 1829 SetModified(); 1830 1831 return true; 1832 } 1833 1834 // OD 2009-08-20 #i100466# 1835 // Add handling of new optional parameter <bForceJoinNext> 1836 bool SwDoc::DeleteAndJoin( SwPaM & rPam, 1837 const bool bForceJoinNext ) 1838 { 1839 if ( lcl_StrLenOverFlow( rPam ) ) 1840 return false; 1841 1842 return lcl_DoWithBreaks( *this, rPam, (IsRedlineOn()) 1843 ? &SwDoc::DeleteAndJoinWithRedlineImpl 1844 : &SwDoc::DeleteAndJoinImpl, 1845 bForceJoinNext ); 1846 } 1847 1848 bool SwDoc::DeleteRange( SwPaM & rPam ) 1849 { 1850 return lcl_DoWithBreaks( *this, rPam, &SwDoc::DeleteRangeImpl ); 1851 } 1852 1853 1854 void lcl_syncGrammarError( SwTxtNode &rTxtNode, linguistic2::ProofreadingResult& rResult, 1855 xub_StrLen /*nBeginGrammarCheck*/, const ModelToViewHelper::ConversionMap* pConversionMap ) 1856 { 1857 if( rTxtNode.IsGrammarCheckDirty() ) 1858 return; 1859 SwGrammarMarkUp* pWrong = rTxtNode.GetGrammarCheck(); 1860 linguistic2::SingleProofreadingError* pArray = rResult.aErrors.getArray(); 1861 sal_uInt16 i, j = 0; 1862 if( pWrong ) 1863 { 1864 for( i = 0; i < rResult.aErrors.getLength(); ++i ) 1865 { 1866 const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i]; 1867 xub_StrLen nStart = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos; 1868 xub_StrLen nEnd = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos; 1869 if( i != j ) 1870 pArray[j] = pArray[i]; 1871 if( pWrong->LookForEntry( nStart, nEnd ) ) 1872 ++j; 1873 } 1874 } 1875 if( rResult.aErrors.getLength() > j ) 1876 rResult.aErrors.realloc( j ); 1877 } 1878 1879 1880 uno::Any SwDoc::Spell( SwPaM& rPaM, 1881 uno::Reference< XSpellChecker1 > &xSpeller, 1882 sal_uInt16* pPageCnt, sal_uInt16* pPageSt, 1883 bool bGrammarCheck, 1884 SwConversionArgs *pConvArgs ) const 1885 { 1886 SwPosition* pSttPos = rPaM.Start(), *pEndPos = rPaM.End(); 1887 uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() ); 1888 1889 SwSpellArgs *pSpellArgs = 0; 1890 //SwConversionArgs *pConvArgs = 0; 1891 if (pConvArgs) 1892 { 1893 pConvArgs->SetStart(pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent); 1894 pConvArgs->SetEnd( pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent ); 1895 } 1896 else 1897 pSpellArgs = new SwSpellArgs( xSpeller, 1898 pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent, 1899 pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent, 1900 bGrammarCheck ); 1901 1902 sal_uLong nCurrNd = pSttPos->nNode.GetIndex(); 1903 sal_uLong nEndNd = pEndPos->nNode.GetIndex(); 1904 1905 uno::Any aRet; 1906 if( nCurrNd <= nEndNd ) 1907 { 1908 SwCntntFrm* pCntFrm; 1909 sal_Bool bGoOn = sal_True; 1910 while( bGoOn ) 1911 { 1912 SwNode* pNd = GetNodes()[ nCurrNd ]; 1913 switch( pNd->GetNodeType() ) 1914 { 1915 case ND_TEXTNODE: 1916 if( 0 != ( pCntFrm = ((SwTxtNode*)pNd)->getLayoutFrm( GetCurrentLayout() )) ) 1917 { 1918 // geschutze Cellen/Flys ueberspringen, ausgeblendete 1919 //ebenfalls 1920 if( pCntFrm->IsProtected() ) 1921 { 1922 nCurrNd = pNd->EndOfSectionIndex(); 1923 } 1924 else if( !((SwTxtFrm*)pCntFrm)->IsHiddenNow() ) 1925 { 1926 if( pPageCnt && *pPageCnt && pPageSt ) 1927 { 1928 sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum(); 1929 if( !*pPageSt ) 1930 { 1931 *pPageSt = nPageNr; 1932 if( *pPageCnt < *pPageSt ) 1933 *pPageCnt = *pPageSt; 1934 } 1935 long nStat; 1936 if( nPageNr >= *pPageSt ) 1937 nStat = nPageNr - *pPageSt + 1; 1938 else 1939 nStat = nPageNr + *pPageCnt - *pPageSt + 1; 1940 ::SetProgressState( nStat, (SwDocShell*)GetDocShell() ); 1941 } 1942 //Spell() changes the pSpellArgs in case an error is found 1943 xub_StrLen nBeginGrammarCheck = 0; 1944 xub_StrLen nEndGrammarCheck = 0; 1945 if( pSpellArgs && pSpellArgs->bIsGrammarCheck) 1946 { 1947 nBeginGrammarCheck = pSpellArgs->pStartNode == pNd ? pSpellArgs->pStartIdx->GetIndex() : 0; 1948 // if grammar checking starts inside of a sentence the start position has to be adjusted 1949 if( nBeginGrammarCheck ) 1950 { 1951 SwIndex aStartIndex( dynamic_cast< SwTxtNode* >( pNd ), nBeginGrammarCheck ); 1952 SwPosition aStart( *pNd, aStartIndex ); 1953 SwCursor aCrsr(aStart, 0, false); 1954 SwPosition aOrigPos = *aCrsr.GetPoint(); 1955 aCrsr.GoSentence( SwCursor::START_SENT ); 1956 if( aOrigPos != *aCrsr.GetPoint() ) 1957 { 1958 nBeginGrammarCheck = aCrsr.GetPoint()->nContent.GetIndex(); 1959 } 1960 } 1961 nEndGrammarCheck = pSpellArgs->pEndNode == pNd ? pSpellArgs->pEndIdx->GetIndex() : ((SwTxtNode*)pNd)->GetTxt().Len(); 1962 } 1963 1964 xub_StrLen nSpellErrorPosition = ((SwTxtNode*)pNd)->GetTxt().Len(); 1965 if( (!pConvArgs && 1966 ((SwTxtNode*)pNd)->Spell( pSpellArgs )) || 1967 ( pConvArgs && 1968 ((SwTxtNode*)pNd)->Convert( *pConvArgs ))) 1969 { 1970 // Abbrechen und Position merken 1971 pSttPos->nNode = nCurrNd; 1972 pEndPos->nNode = nCurrNd; 1973 nCurrNd = nEndNd; 1974 if( pSpellArgs ) 1975 nSpellErrorPosition = pSpellArgs->pStartIdx->GetIndex() > pSpellArgs->pEndIdx->GetIndex() ? 1976 pSpellArgs->pEndIdx->GetIndex() : 1977 pSpellArgs->pStartIdx->GetIndex(); 1978 } 1979 1980 1981 if( pSpellArgs && pSpellArgs->bIsGrammarCheck ) 1982 { 1983 uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( GetGCIterator() ); 1984 if (xGCIterator.is()) 1985 { 1986 String aText( ((SwTxtNode*)pNd)->GetTxt().Copy( nBeginGrammarCheck, nEndGrammarCheck - nBeginGrammarCheck ) ); 1987 uno::Reference< lang::XComponent > xDoc( ((SwDocShell*)GetDocShell())->GetBaseModel(), uno::UNO_QUERY ); 1988 // Expand the string: 1989 rtl::OUString aExpandText; 1990 const ModelToViewHelper::ConversionMap* pConversionMap = 1991 ((SwTxtNode*)pNd)->BuildConversionMap( aExpandText ); 1992 // get XFlatParagraph to use... 1993 uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *((SwTxtNode*)pNd), aExpandText, pConversionMap ); 1994 1995 // get error position of cursor in XFlatParagraph 1996 sal_Int32 nGrammarErrorPosInText; 1997 linguistic2::ProofreadingResult aResult; 1998 sal_Int32 nGrammarErrors; 1999 do 2000 { 2001 nGrammarErrorPosInText = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nBeginGrammarCheck ); 2002 aResult = xGCIterator->checkSentenceAtPosition( 2003 xDoc, xFlatPara, aExpandText, lang::Locale(), nBeginGrammarCheck, -1, -1 ); 2004 2005 lcl_syncGrammarError( *((SwTxtNode*)pNd), aResult, nBeginGrammarCheck, pConversionMap ); 2006 2007 // get suggestions to use for the specific error position 2008 nGrammarErrors = aResult.aErrors.getLength(); 2009 // if grammar checking doesn't have any progress then quit 2010 if( aResult.nStartOfNextSentencePosition <= nBeginGrammarCheck ) 2011 break; 2012 // prepare next iteration 2013 nBeginGrammarCheck = (xub_StrLen)aResult.nStartOfNextSentencePosition; 2014 } 2015 while( nSpellErrorPosition > aResult.nBehindEndOfSentencePosition && !nGrammarErrors && aResult.nBehindEndOfSentencePosition < nEndGrammarCheck ); 2016 2017 if( nGrammarErrors > 0 && nSpellErrorPosition >= aResult.nBehindEndOfSentencePosition ) 2018 { 2019 aRet <<= aResult; 2020 //put the cursor to the current error 2021 const linguistic2::SingleProofreadingError &rError = aResult.aErrors[0]; 2022 nCurrNd = pNd->GetIndex(); 2023 pSttPos->nNode = nCurrNd; 2024 pEndPos->nNode = nCurrNd; 2025 pSpellArgs->pStartNode = ((SwTxtNode*)pNd); 2026 pSpellArgs->pEndNode = ((SwTxtNode*)pNd); 2027 pSpellArgs->pStartIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos ); 2028 pSpellArgs->pEndIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos ); 2029 nCurrNd = nEndNd; 2030 } 2031 } 2032 } 2033 } 2034 } 2035 break; 2036 case ND_SECTIONNODE: 2037 if( ( ((SwSectionNode*)pNd)->GetSection().IsProtect() || 2038 ((SwSectionNode*)pNd)->GetSection().IsHidden() ) ) 2039 nCurrNd = pNd->EndOfSectionIndex(); 2040 break; 2041 case ND_ENDNODE: 2042 { 2043 break; 2044 } 2045 } 2046 2047 bGoOn = nCurrNd < nEndNd; 2048 ++nCurrNd; 2049 } 2050 } 2051 2052 if( !aRet.hasValue() ) 2053 { 2054 if (pConvArgs) 2055 aRet <<= pConvArgs->aConvText; 2056 else 2057 aRet <<= pSpellArgs->xSpellAlt; 2058 } 2059 delete pSpellArgs; 2060 2061 return aRet; 2062 } 2063 2064 class SwHyphArgs : public SwInterHyphInfo 2065 { 2066 const SwNode *pStart; 2067 const SwNode *pEnd; 2068 SwNode *pNode; 2069 sal_uInt16 *pPageCnt; 2070 sal_uInt16 *pPageSt; 2071 2072 sal_uInt32 nNode; 2073 xub_StrLen nPamStart; 2074 xub_StrLen nPamLen; 2075 2076 public: 2077 SwHyphArgs( const SwPaM *pPam, const Point &rPoint, 2078 sal_uInt16* pPageCount, sal_uInt16* pPageStart ); 2079 void SetPam( SwPaM *pPam ) const; 2080 inline void SetNode( SwNode *pNew ) { pNode = pNew; } 2081 inline const SwNode *GetNode() const { return pNode; } 2082 inline void SetRange( const SwNode *pNew ); 2083 inline void NextNode() { ++nNode; } 2084 inline sal_uInt16 *GetPageCnt() { return pPageCnt; } 2085 inline sal_uInt16 *GetPageSt() { return pPageSt; } 2086 }; 2087 2088 SwHyphArgs::SwHyphArgs( const SwPaM *pPam, const Point &rCrsrPos, 2089 sal_uInt16* pPageCount, sal_uInt16* pPageStart ) 2090 : SwInterHyphInfo( rCrsrPos ), pNode(0), 2091 pPageCnt( pPageCount ), pPageSt( pPageStart ) 2092 { 2093 // Folgende Bedingungen muessen eingehalten werden: 2094 // 1) es gibt mindestens eine Selektion 2095 // 2) SPoint() == Start() 2096 ASSERT( pPam->HasMark(), "SwDoc::Hyphenate: blowing in the wind"); 2097 ASSERT( *pPam->GetPoint() <= *pPam->GetMark(), 2098 "SwDoc::Hyphenate: New York, New York"); 2099 2100 const SwPosition *pPoint = pPam->GetPoint(); 2101 nNode = pPoint->nNode.GetIndex(); 2102 2103 // Start einstellen 2104 pStart = pPoint->nNode.GetNode().GetTxtNode(); 2105 nPamStart = pPoint->nContent.GetIndex(); 2106 2107 // Ende und Laenge einstellen. 2108 const SwPosition *pMark = pPam->GetMark(); 2109 pEnd = pMark->nNode.GetNode().GetTxtNode(); 2110 nPamLen = pMark->nContent.GetIndex(); 2111 if( pPoint->nNode == pMark->nNode ) 2112 nPamLen = nPamLen - pPoint->nContent.GetIndex(); 2113 } 2114 2115 inline void SwHyphArgs::SetRange( const SwNode *pNew ) 2116 { 2117 nStart = pStart == pNew ? nPamStart : 0; 2118 nLen = pEnd == pNew ? nPamLen : STRING_NOTFOUND; 2119 } 2120 2121 void SwHyphArgs::SetPam( SwPaM *pPam ) const 2122 { 2123 if( !pNode ) 2124 *pPam->GetPoint() = *pPam->GetMark(); 2125 else 2126 { 2127 pPam->GetPoint()->nNode = nNode; 2128 pPam->GetPoint()->nContent.Assign( pNode->GetCntntNode(), nWordStart ); 2129 pPam->GetMark()->nNode = nNode; 2130 pPam->GetMark()->nContent.Assign( pNode->GetCntntNode(), 2131 nWordStart + nWordLen ); 2132 ASSERT( nNode == pNode->GetIndex(), 2133 "SwHyphArgs::SetPam: Pam desaster" ); 2134 } 2135 } 2136 2137 // liefert sal_True zurueck, wenn es weitergehen soll. 2138 sal_Bool lcl_HyphenateNode( const SwNodePtr& rpNd, void* pArgs ) 2139 { 2140 // Hyphenate liefert sal_True zurueck, wenn eine Trennstelle anliegt 2141 // und stellt pPam ein. 2142 SwTxtNode *pNode = rpNd->GetTxtNode(); 2143 SwHyphArgs *pHyphArgs = (SwHyphArgs*)pArgs; 2144 if( pNode ) 2145 { 2146 SwCntntFrm* pCntFrm = pNode->getLayoutFrm( pNode->GetDoc()->GetCurrentLayout() ); 2147 if( pCntFrm && !((SwTxtFrm*)pCntFrm)->IsHiddenNow() ) 2148 { 2149 sal_uInt16 *pPageSt = pHyphArgs->GetPageSt(); 2150 sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt(); 2151 if( pPageCnt && *pPageCnt && pPageSt ) 2152 { 2153 sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum(); 2154 if( !*pPageSt ) 2155 { 2156 *pPageSt = nPageNr; 2157 if( *pPageCnt < *pPageSt ) 2158 *pPageCnt = *pPageSt; 2159 } 2160 long nStat = nPageNr >= *pPageSt ? nPageNr - *pPageSt + 1 2161 : nPageNr + *pPageCnt - *pPageSt + 1; 2162 ::SetProgressState( nStat, (SwDocShell*)pNode->GetDoc()->GetDocShell() ); 2163 } 2164 pHyphArgs->SetRange( rpNd ); 2165 if( pNode->Hyphenate( *pHyphArgs ) ) 2166 { 2167 pHyphArgs->SetNode( rpNd ); 2168 return sal_False; 2169 } 2170 } 2171 } 2172 pHyphArgs->NextNode(); 2173 return sal_True; 2174 } 2175 2176 uno::Reference< XHyphenatedWord > SwDoc::Hyphenate( 2177 SwPaM *pPam, const Point &rCrsrPos, 2178 sal_uInt16* pPageCnt, sal_uInt16* pPageSt ) 2179 { 2180 ASSERT(this == pPam->GetDoc(), "SwDoc::Hyphenate: strangers in the night"); 2181 2182 if( *pPam->GetPoint() > *pPam->GetMark() ) 2183 pPam->Exchange(); 2184 2185 SwHyphArgs aHyphArg( pPam, rCrsrPos, pPageCnt, pPageSt ); 2186 SwNodeIndex aTmpIdx( pPam->GetMark()->nNode, 1 ); 2187 GetNodes().ForEach( pPam->GetPoint()->nNode, aTmpIdx, 2188 lcl_HyphenateNode, &aHyphArg ); 2189 aHyphArg.SetPam( pPam ); 2190 return aHyphArg.GetHyphWord(); // will be set by lcl_HyphenateNode 2191 } 2192 2193 2194 sal_Bool lcl_GetTokenToParaBreak( String& rStr, String& rRet, sal_Bool bRegExpRplc ) 2195 { 2196 sal_Bool bRet = sal_False; 2197 if( bRegExpRplc ) 2198 { 2199 xub_StrLen nPos = 0; 2200 String sPara( String::CreateFromAscii( 2201 RTL_CONSTASCII_STRINGPARAM( "\\n" ))); 2202 while( STRING_NOTFOUND != ( nPos = rStr.Search( sPara, nPos )) ) 2203 { 2204 // wurde das escaped? 2205 if( nPos && '\\' == rStr.GetChar( nPos-1 )) 2206 { 2207 if( ++nPos >= rStr.Len() ) 2208 break; 2209 } 2210 else 2211 { 2212 rRet = rStr.Copy( 0, nPos ); 2213 rStr.Erase( 0, nPos + sPara.Len() ); 2214 bRet = sal_True; 2215 break; 2216 } 2217 } 2218 } 2219 if( !bRet ) 2220 { 2221 rRet = rStr; 2222 rStr.Erase(); 2223 } 2224 return bRet; 2225 } 2226 2227 bool SwDoc::ReplaceRange( SwPaM& rPam, const String& rStr, 2228 const bool bRegExReplace ) 2229 { 2230 // unfortunately replace works slightly differently from delete, 2231 // so we cannot use lcl_DoWithBreaks here... 2232 2233 ::std::vector<xub_StrLen> Breaks; 2234 2235 SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() ); 2236 aPam.Normalize(sal_False); 2237 if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode) 2238 { 2239 aPam.Move(fnMoveBackward); 2240 } 2241 ASSERT((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?"); 2242 2243 lcl_CalcBreaks(Breaks, aPam); 2244 2245 while (!Breaks.empty() // skip over prefix of dummy chars 2246 && (aPam.GetMark()->nContent.GetIndex() == *Breaks.begin()) ) 2247 { 2248 // skip! 2249 ++aPam.GetMark()->nContent; // always in bounds if Breaks valid 2250 Breaks.erase(Breaks.begin()); 2251 } 2252 *rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix 2253 2254 if (!Breaks.size()) 2255 { 2256 return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam! 2257 } 2258 2259 // N.B.: deletion must be split into several parts if the text node 2260 // contains a text attribute with end and with dummy character 2261 // and the selection does not contain the text attribute completely, 2262 // but overlaps its start (left), where the dummy character is. 2263 2264 bool bRet( true ); 2265 // iterate from end to start, to avoid invalidating the offsets! 2266 ::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() ); 2267 ASSERT(aPam.GetPoint() == aPam.End(), "wrong!"); 2268 SwPosition & rEnd( *aPam.End() ); 2269 SwPosition & rStart( *aPam.Start() ); 2270 2271 // set end of temp pam to original end (undo Move backward above) 2272 rEnd = *rPam.End(); 2273 // after first deletion, rEnd will point into the original text node again! 2274 2275 while (iter != Breaks.rend()) 2276 { 2277 rStart.nContent = *iter + 1; 2278 if (rEnd.nContent != rStart.nContent) // check if part is empty 2279 { 2280 bRet &= (IsRedlineOn()) 2281 ? DeleteAndJoinWithRedlineImpl(aPam) 2282 : DeleteAndJoinImpl(aPam, false); 2283 } 2284 rEnd.nContent = *iter; 2285 ++iter; 2286 } 2287 2288 rStart = *rPam.Start(); // set to original start 2289 ASSERT(rEnd.nContent > rStart.nContent, "replace part empty!"); 2290 if (rEnd.nContent > rStart.nContent) // check if part is empty 2291 { 2292 bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace); 2293 } 2294 2295 rPam = aPam; // update original pam (is this required?) 2296 2297 return bRet; 2298 } 2299 2300 // N.B.: it is possible to call Replace with a PaM that spans 2 paragraphs: 2301 // search with regex for "$", then replace _all_ 2302 bool SwDoc::ReplaceRangeImpl( SwPaM& rPam, const String& rStr, 2303 const bool bRegExReplace ) 2304 { 2305 if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() ) 2306 return false; 2307 2308 sal_Bool bJoinTxt, bJoinPrev; 2309 lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev ); 2310 2311 { 2312 // dann eine Kopie vom Cursor erzeugen um alle Pams aus den 2313 // anderen Sichten aus dem Loeschbereich zu verschieben 2314 // ABER NICHT SICH SELBST !! 2315 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() ); 2316 ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() ); 2317 2318 SwPosition *pStt = (SwPosition*)aDelPam.Start(), 2319 *pEnd = (SwPosition*)aDelPam.End(); 2320 ASSERT( pStt->nNode == pEnd->nNode || 2321 ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && 2322 !pEnd->nContent.GetIndex() ), 2323 "invalid range: Point and Mark on different nodes" ); 2324 sal_Bool bOneNode = pStt->nNode == pEnd->nNode; 2325 2326 // eigenes Undo ???? 2327 String sRepl( rStr ); 2328 SwTxtNode* pTxtNd = pStt->nNode.GetNode().GetTxtNode(); 2329 xub_StrLen nStt = pStt->nContent.GetIndex(), 2330 nEnd = bOneNode ? pEnd->nContent.GetIndex() 2331 : pTxtNd->GetTxt().Len(); 2332 2333 SwDataChanged aTmp( aDelPam, 0 ); 2334 2335 if( IsRedlineOn() ) 2336 { 2337 RedlineMode_t eOld = GetRedlineMode(); 2338 checkRedlining(eOld); 2339 if (GetIDocumentUndoRedo().DoesUndo()) 2340 { 2341 GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); 2342 2343 // Bug 68584 - if any Redline will change (split!) the node 2344 const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK ); 2345 2346 //JP 06.01.98: MUSS noch optimiert werden!!! 2347 SetRedlineMode( 2348 (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE )); 2349 2350 *aDelPam.GetPoint() = pBkmk->GetMarkPos(); 2351 if(pBkmk->IsExpanded()) 2352 *aDelPam.GetMark() = pBkmk->GetOtherMarkPos(); 2353 getIDocumentMarkAccess()->deleteMark(pBkmk); 2354 pStt = aDelPam.Start(); 2355 pTxtNd = pStt->nNode.GetNode().GetTxtNode(); 2356 nStt = pStt->nContent.GetIndex(); 2357 } 2358 2359 if( sRepl.Len() ) 2360 { 2361 // Attribute des 1. Zeichens ueber den ReplaceText setzen 2362 SfxItemSet aSet( GetAttrPool(), 2363 RES_CHRATR_BEGIN, RES_TXTATR_WITHEND_END - 1, 2364 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1, 2365 0 ); 2366 pTxtNd->GetAttr( aSet, nStt+1, nStt+1 ); 2367 2368 aSet.ClearItem( RES_TXTATR_REFMARK ); 2369 aSet.ClearItem( RES_TXTATR_TOXMARK ); 2370 aSet.ClearItem( RES_TXTATR_CJK_RUBY ); 2371 aSet.ClearItem( RES_TXTATR_INETFMT ); 2372 aSet.ClearItem( RES_TXTATR_META ); 2373 aSet.ClearItem( RES_TXTATR_METAFIELD ); 2374 2375 if( aDelPam.GetPoint() != aDelPam.End() ) 2376 aDelPam.Exchange(); 2377 2378 // das Ende merken 2379 SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 ); 2380 xub_StrLen nPtCnt = aDelPam.GetPoint()->nContent.GetIndex(); 2381 2382 sal_Bool bFirst = sal_True; 2383 String sIns; 2384 while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) ) 2385 { 2386 InsertString( aDelPam, sIns ); 2387 if( bFirst ) 2388 { 2389 SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 ); 2390 xub_StrLen nMkCnt = aDelPam.GetMark()->nContent.GetIndex(); 2391 2392 SplitNode( *aDelPam.GetPoint(), false ); 2393 2394 aMkNd++; 2395 aDelPam.GetMark()->nNode = aMkNd; 2396 aDelPam.GetMark()->nContent.Assign( 2397 aMkNd.GetNode().GetCntntNode(), nMkCnt ); 2398 bFirst = sal_False; 2399 } 2400 else 2401 SplitNode( *aDelPam.GetPoint(), false ); 2402 } 2403 if( sIns.Len() ) 2404 { 2405 InsertString( aDelPam, sIns ); 2406 } 2407 2408 SwPaM aTmpRange( *aDelPam.GetPoint() ); 2409 aTmpRange.SetMark(); 2410 2411 aPtNd++; 2412 aDelPam.GetPoint()->nNode = aPtNd; 2413 aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetCntntNode(), 2414 nPtCnt); 2415 *aTmpRange.GetMark() = *aDelPam.GetPoint(); 2416 2417 RstTxtAttrs( aTmpRange ); 2418 InsertItemSet( aTmpRange, aSet, 0 ); 2419 } 2420 2421 if (GetIDocumentUndoRedo().DoesUndo()) 2422 { 2423 SwUndo *const pUndoRD = 2424 new SwUndoRedlineDelete( aDelPam, UNDO_REPLACE ); 2425 GetIDocumentUndoRedo().AppendUndo(pUndoRD); 2426 } 2427 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDelPam ), true); 2428 2429 *rPam.GetMark() = *aDelPam.GetMark(); 2430 if (GetIDocumentUndoRedo().DoesUndo()) 2431 { 2432 *aDelPam.GetPoint() = *rPam.GetPoint(); 2433 GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); 2434 2435 // Bug 68584 - if any Redline will change (split!) the node 2436 const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK ); 2437 2438 SwIndex& rIdx = aDelPam.GetPoint()->nContent; 2439 rIdx.Assign( 0, 0 ); 2440 aDelPam.GetMark()->nContent = rIdx; 2441 rPam.GetPoint()->nNode = 0; 2442 rPam.GetPoint()->nContent = rIdx; 2443 *rPam.GetMark() = *rPam.GetPoint(); 2444 //JP 06.01.98: MUSS noch optimiert werden!!! 2445 SetRedlineMode( eOld ); 2446 2447 *rPam.GetPoint() = pBkmk->GetMarkPos(); 2448 if(pBkmk->IsExpanded()) 2449 *rPam.GetMark() = pBkmk->GetOtherMarkPos(); 2450 getIDocumentMarkAccess()->deleteMark(pBkmk); 2451 } 2452 bJoinTxt = sal_False; 2453 } 2454 else 2455 { 2456 if( !IsIgnoreRedline() && GetRedlineTbl().Count() ) 2457 DeleteRedline( aDelPam, true, USHRT_MAX ); 2458 2459 SwUndoReplace* pUndoRpl = 0; 2460 bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo(); 2461 if (bDoesUndo) 2462 { 2463 pUndoRpl = new SwUndoReplace(aDelPam, sRepl, bRegExReplace); 2464 GetIDocumentUndoRedo().AppendUndo(pUndoRpl); 2465 } 2466 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); 2467 2468 if( aDelPam.GetPoint() != pStt ) 2469 aDelPam.Exchange(); 2470 2471 SwNodeIndex aPtNd( pStt->nNode, -1 ); 2472 xub_StrLen nPtCnt = pStt->nContent.GetIndex(); 2473 2474 // die Werte nochmal setzen, falls schohn Rahmen oder Fussnoten 2475 // auf dem Text entfernt wurden! 2476 nStt = nPtCnt; 2477 nEnd = bOneNode ? pEnd->nContent.GetIndex() 2478 : pTxtNd->GetTxt().Len(); 2479 2480 sal_Bool bFirst = sal_True; 2481 String sIns; 2482 while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) ) 2483 { 2484 if( !bFirst || nStt == pTxtNd->GetTxt().Len() ) 2485 { 2486 InsertString( aDelPam, sIns ); 2487 } 2488 else if( nStt < nEnd || sIns.Len() ) 2489 { 2490 pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns ); 2491 } 2492 SplitNode( *pStt, false); 2493 bFirst = sal_False; 2494 } 2495 2496 if( bFirst || sIns.Len() ) 2497 { 2498 if( !bFirst || nStt == pTxtNd->GetTxt().Len() ) 2499 { 2500 InsertString( aDelPam, sIns ); 2501 } 2502 else if( nStt < nEnd || sIns.Len() ) 2503 { 2504 pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns ); 2505 } 2506 } 2507 2508 *rPam.GetMark() = *aDelPam.GetMark(); 2509 2510 aPtNd++; 2511 rPam.GetMark()->nNode = aPtNd; 2512 rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetCntntNode(), 2513 nPtCnt ); 2514 2515 if ( bJoinTxt && !bJoinPrev ) 2516 { 2517 rPam.Move( fnMoveBackward ); 2518 } 2519 2520 if( pUndoRpl ) 2521 { 2522 pUndoRpl->SetEnd(rPam); 2523 } 2524 } 2525 } 2526 2527 if( bJoinTxt ) 2528 lcl_JoinText( rPam, bJoinPrev ); 2529 2530 SetModified(); 2531 return true; 2532 } 2533 2534 // speicher die akt. Werte fuer die automatische Aufnahme von Ausnahmen 2535 // in die Autokorrektur 2536 void SwDoc::SetAutoCorrExceptWord( SwAutoCorrExceptWord* pNew ) 2537 { 2538 if( pACEWord && pNew != pACEWord ) 2539 delete pACEWord; 2540 pACEWord = pNew; 2541 } 2542 2543 bool SwDoc::DelFullPara( SwPaM& rPam ) 2544 { 2545 const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End(); 2546 const SwNode* pNd = &rStt.nNode.GetNode(); 2547 sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() - 2548 pNd->StartOfSectionIndex(); 2549 sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex(); 2550 2551 if ( nSectDiff-2 <= nNodeDiff || IsRedlineOn() || 2552 /* #i9185# Prevent getting the node after the end node (see below) */ 2553 rEnd.nNode.GetIndex() + 1 == GetNodes().Count() ) 2554 { 2555 return sal_False; 2556 } 2557 2558 // harte SeitenUmbrueche am nachfolgenden Node verschieben 2559 sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False; 2560 2561 /* #i9185# This whould lead to a segmentation fault if not catched 2562 above. */ 2563 sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1; 2564 SwTableNode *const pTblNd = GetNodes()[ nNextNd ]->GetTableNode(); 2565 2566 if( pTblNd && pNd->IsCntntNode() ) 2567 { 2568 SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt(); 2569 //JP 24.08.98: will man wirklich den PageDesc/Break vom 2570 // nachfolgen Absatz ueberbuegeln? 2571 // const SwAttrSet& rAttrSet = pTableFmt->GetAttrSet(); 2572 // if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) && 2573 // SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK )) 2574 { 2575 const SfxPoolItem *pItem; 2576 const SfxItemSet* pSet = ((SwCntntNode*)pNd)->GetpSwAttrSet(); 2577 if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC, 2578 sal_False, &pItem ) ) 2579 { 2580 pTableFmt->SetFmtAttr( *pItem ); 2581 bSavePageDesc = sal_True; 2582 } 2583 2584 if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, 2585 sal_False, &pItem ) ) 2586 { 2587 pTableFmt->SetFmtAttr( *pItem ); 2588 bSavePageBreak = sal_True; 2589 } 2590 } 2591 } 2592 2593 bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo(); 2594 if( bDoesUndo ) 2595 { 2596 if( !rPam.HasMark() ) 2597 rPam.SetMark(); 2598 else if( rPam.GetPoint() == &rStt ) 2599 rPam.Exchange(); 2600 rPam.GetPoint()->nNode++; 2601 2602 SwCntntNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetCntntNode(); 2603 rPam.GetPoint()->nContent.Assign( pTmpNode, 0 ); 2604 bool bGoNext = (0 == pTmpNode); 2605 pTmpNode = rPam.GetMark()->nNode.GetNode().GetCntntNode(); 2606 rPam.GetMark()->nContent.Assign( pTmpNode, 0 ); 2607 2608 GetIDocumentUndoRedo().ClearRedo(); 2609 2610 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() ); 2611 { 2612 SwPosition aTmpPos( *aDelPam.GetPoint() ); 2613 if( bGoNext ) 2614 { 2615 pTmpNode = GetNodes().GoNext( &aTmpPos.nNode ); 2616 aTmpPos.nContent.Assign( pTmpNode, 0 ); 2617 } 2618 ::PaMCorrAbs( aDelPam, aTmpPos ); 2619 } 2620 2621 SwUndoDelete* pUndo = new SwUndoDelete( aDelPam, sal_True ); 2622 2623 *rPam.GetPoint() = *aDelPam.GetPoint(); 2624 pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc ); 2625 GetIDocumentUndoRedo().AppendUndo(pUndo); 2626 } 2627 else 2628 { 2629 SwNodeRange aRg( rStt.nNode, rEnd.nNode ); 2630 if( rPam.GetPoint() != &rEnd ) 2631 rPam.Exchange(); 2632 2633 // versuche hinters Ende zu verschieben 2634 if( !rPam.Move( fnMoveForward, fnGoNode ) ) 2635 { 2636 // na gut, dann an den Anfang 2637 rPam.Exchange(); 2638 if( !rPam.Move( fnMoveBackward, fnGoNode )) 2639 { 2640 ASSERT( sal_False, "kein Node mehr vorhanden" ); 2641 return sal_False; 2642 } 2643 } 2644 // move bookmarks, redlines etc. 2645 if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this 2646 { 2647 CorrAbs( aRg.aStart, *rPam.GetPoint(), 0, sal_True ); 2648 } 2649 else 2650 { 2651 CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), sal_True ); 2652 } 2653 2654 // was ist mit Fly's ?? 2655 { 2656 // stehen noch FlyFrames rum, loesche auch diese 2657 for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n ) 2658 { 2659 SwFrmFmt* pFly = (*GetSpzFrmFmts())[n]; 2660 const SwFmtAnchor* pAnchor = &pFly->GetAnchor(); 2661 SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); 2662 if (pAPos && 2663 ((FLY_AT_PARA == pAnchor->GetAnchorId()) || 2664 (FLY_AT_CHAR == pAnchor->GetAnchorId())) && 2665 aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd ) 2666 { 2667 DelLayoutFmt( pFly ); 2668 --n; 2669 } 2670 } 2671 } 2672 2673 SwCntntNode *pTmpNode = rPam.GetBound( sal_True ).nNode.GetNode().GetCntntNode(); 2674 rPam.GetBound( sal_True ).nContent.Assign( pTmpNode, 0 ); 2675 pTmpNode = rPam.GetBound( sal_False ).nNode.GetNode().GetCntntNode(); 2676 rPam.GetBound( sal_False ).nContent.Assign( pTmpNode, 0 ); 2677 GetNodes().Delete( aRg.aStart, nNodeDiff+1 ); 2678 } 2679 rPam.DeleteMark(); 2680 SetModified(); 2681 2682 return sal_True; 2683 } 2684 2685 2686 void SwDoc::TransliterateText( 2687 const SwPaM& rPaM, 2688 utl::TransliterationWrapper& rTrans ) 2689 { 2690 SwUndoTransliterate *const pUndo = (GetIDocumentUndoRedo().DoesUndo()) 2691 ? new SwUndoTransliterate( rPaM, rTrans ) 2692 : 0; 2693 2694 const SwPosition* pStt = rPaM.Start(), 2695 * pEnd = rPaM.End(); 2696 sal_uLong nSttNd = pStt->nNode.GetIndex(), 2697 nEndNd = pEnd->nNode.GetIndex(); 2698 xub_StrLen nSttCnt = pStt->nContent.GetIndex(), 2699 nEndCnt = pEnd->nContent.GetIndex(); 2700 2701 SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode(); 2702 if( pStt == pEnd && pTNd ) // no selection? 2703 { 2704 // set current word as 'area of effect' 2705 2706 Boundary aBndry; 2707 if( pBreakIt->GetBreakIter().is() ) 2708 aBndry = pBreakIt->GetBreakIter()->getWordBoundary( 2709 pTNd->GetTxt(), nSttCnt, 2710 pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ), 2711 WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/, 2712 sal_True ); 2713 2714 if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos ) 2715 { 2716 nSttCnt = (xub_StrLen)aBndry.startPos; 2717 nEndCnt = (xub_StrLen)aBndry.endPos; 2718 } 2719 } 2720 2721 if( nSttNd != nEndNd ) // is more than one text node involved? 2722 { 2723 // iterate over all effected text nodes, the first and the last one 2724 // may be incomplete because the selection starts and/or ends there 2725 2726 SwNodeIndex aIdx( pStt->nNode ); 2727 if( nSttCnt ) 2728 { 2729 aIdx++; 2730 if( pTNd ) 2731 pTNd->TransliterateText( rTrans, nSttCnt, pTNd->GetTxt().Len(), pUndo ); 2732 } 2733 2734 for( ; aIdx.GetIndex() < nEndNd; aIdx++ ) 2735 { 2736 if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() )) 2737 pTNd->TransliterateText( rTrans, 0, pTNd->GetTxt().Len(), pUndo ); 2738 } 2739 2740 if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() )) 2741 pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo ); 2742 } 2743 else if( pTNd && nSttCnt < nEndCnt ) 2744 pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo ); 2745 2746 if( pUndo ) 2747 { 2748 if( pUndo->HasData() ) 2749 { 2750 GetIDocumentUndoRedo().AppendUndo(pUndo); 2751 } 2752 else 2753 delete pUndo; 2754 } 2755 SetModified(); 2756 } 2757 2758 2759 #define MAX_REDLINE_COUNT 250 2760 // ----------------------------------------------------------------------------- 2761 void SwDoc::checkRedlining(RedlineMode_t& _rReadlineMode) 2762 { 2763 const SwRedlineTbl& rRedlineTbl = GetRedlineTbl(); 2764 SwEditShell* pEditShell = GetEditShell(); 2765 Window* pParent = pEditShell ? pEditShell->GetWin() : NULL; 2766 if ( pParent && !mbReadlineChecked && rRedlineTbl.Count() > MAX_REDLINE_COUNT 2767 && !((_rReadlineMode & nsRedlineMode_t::REDLINE_SHOW_DELETE) == nsRedlineMode_t::REDLINE_SHOW_DELETE) ) 2768 { 2769 WarningBox aWarning( pParent,SW_RES(MSG_DISABLE_READLINE_QUESTION)); 2770 sal_uInt16 nResult = aWarning.Execute(); 2771 mbReadlineChecked = sal_True; 2772 if ( nResult == RET_YES ) 2773 { 2774 sal_Int32 nMode = (sal_Int32)_rReadlineMode; 2775 nMode |= nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE; 2776 _rReadlineMode = (RedlineMode_t)nMode; 2777 } 2778 } 2779 } 2780 // ----------------------------------------------------------------------------- 2781 2782 void SwDoc::CountWords( const SwPaM& rPaM, SwDocStat& rStat ) const 2783 { 2784 // This is a modified version of SwDoc::TransliterateText 2785 const SwPosition* pStt = rPaM.Start(); 2786 const SwPosition* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark() 2787 : rPaM.GetPoint(); 2788 2789 const sal_uLong nSttNd = pStt->nNode.GetIndex(); 2790 const sal_uLong nEndNd = pEnd->nNode.GetIndex(); 2791 2792 const xub_StrLen nSttCnt = pStt->nContent.GetIndex(); 2793 const xub_StrLen nEndCnt = pEnd->nContent.GetIndex(); 2794 2795 const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode(); 2796 if( pStt == pEnd && pTNd ) // no region ? 2797 { 2798 // do nothing 2799 return; 2800 } 2801 2802 if( nSttNd != nEndNd ) 2803 { 2804 SwNodeIndex aIdx( pStt->nNode ); 2805 if( nSttCnt ) 2806 { 2807 aIdx++; 2808 if( pTNd ) 2809 pTNd->CountWords( rStat, nSttCnt, pTNd->GetTxt().Len() ); 2810 } 2811 2812 for( ; aIdx.GetIndex() < nEndNd; aIdx++ ) 2813 if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() )) 2814 pTNd->CountWords( rStat, 0, pTNd->GetTxt().Len() ); 2815 2816 if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() )) 2817 pTNd->CountWords( rStat, 0, nEndCnt ); 2818 } 2819 else if( pTNd && nSttCnt < nEndCnt ) 2820 pTNd->CountWords( rStat, nSttCnt, nEndCnt ); 2821 } 2822 2823 void SwDoc::RemoveLeadingWhiteSpace(const SwPosition & rPos ) 2824 { 2825 const SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode(); 2826 if ( pTNd ) 2827 { 2828 const String& rTxt = pTNd->GetTxt(); 2829 xub_StrLen nIdx = 0; 2830 sal_Unicode cCh; 2831 while( nIdx < rTxt.Len() && 2832 ( '\t' == ( cCh = rTxt.GetChar( nIdx ) ) || 2833 ( ' ' == cCh ) ) ) 2834 ++nIdx; 2835 2836 if ( nIdx > 0 ) 2837 { 2838 SwPaM aPam(rPos); 2839 aPam.GetPoint()->nContent = 0; 2840 aPam.SetMark(); 2841 aPam.GetMark()->nContent = nIdx; 2842 DeleteRange( aPam ); 2843 } 2844 } 2845 } 2846