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