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