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