1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sw.hxx" 26 27 28 #define _STD_VAR_ARRAYS 29 #include <hintids.hxx> 30 31 #include <svx/svxids.hrc> 32 #include <editeng/langitem.hxx> 33 #include <fmtinfmt.hxx> 34 #include <txtatr.hxx> 35 #include <txtinet.hxx> 36 #include <editsh.hxx> 37 #include <doc.hxx> 38 #include <pam.hxx> 39 #include <ndtxt.hxx> 40 #include <acorrect.hxx> 41 #include <shellio.hxx> 42 #include <swundo.hxx> 43 #include <viscrs.hxx> 44 45 #include <editeng/acorrcfg.hxx> 46 47 using namespace ::com::sun::star; 48 49 50 class _PaMIntoCrsrShellRing 51 { 52 SwCrsrShell& rSh; 53 SwPaM &rDelPam, &rCrsr; 54 Ring *pPrevDelPam, *pPrevCrsr; 55 56 void RemoveFromRing( SwPaM& rPam, Ring* pPrev ); 57 public: 58 _PaMIntoCrsrShellRing( SwCrsrShell& rSh, SwPaM& rCrsr, SwPaM& rPam ); 59 ~_PaMIntoCrsrShellRing(); 60 }; 61 62 _PaMIntoCrsrShellRing::_PaMIntoCrsrShellRing( SwCrsrShell& rCSh, 63 SwPaM& rShCrsr, SwPaM& rPam ) 64 : rSh( rCSh ), rDelPam( rPam ), rCrsr( rShCrsr ) 65 { 66 SwPaM* pShCrsr = rSh._GetCrsr(); 67 68 pPrevDelPam = rDelPam.GetPrev(); 69 pPrevCrsr = rCrsr.GetPrev(); 70 71 rDelPam.MoveRingTo( pShCrsr ); 72 rCrsr.MoveRingTo( pShCrsr ); 73 } 74 _PaMIntoCrsrShellRing::~_PaMIntoCrsrShellRing() 75 { 76 // und den Pam wieder herausnehmen: 77 RemoveFromRing( rDelPam, pPrevDelPam ); 78 RemoveFromRing( rCrsr, pPrevCrsr ); 79 } 80 void _PaMIntoCrsrShellRing::RemoveFromRing( SwPaM& rPam, Ring* pPrev ) 81 { 82 Ring *p, *pNext = (Ring*)&rPam; 83 do { 84 p = pNext; 85 pNext = p->GetNext(); 86 p->MoveTo( &rPam ); 87 } while( p != pPrev ); 88 } 89 90 91 SwAutoCorrDoc::SwAutoCorrDoc( SwEditShell& rEditShell, SwPaM& rPam, 92 sal_Unicode cIns ) 93 : rEditSh( rEditShell ), rCrsr( rPam ), pIdx( 0 ) 94 , m_nEndUndoCounter(0) 95 , bUndoIdInitialized( cIns ? false : true ) 96 { 97 } 98 99 100 SwAutoCorrDoc::~SwAutoCorrDoc() 101 { 102 for (int i = 0; i < m_nEndUndoCounter; ++i) 103 { 104 rEditSh.EndUndo(); 105 } 106 delete pIdx; 107 } 108 109 void SwAutoCorrDoc::DeleteSel( SwPaM& rDelPam ) 110 { 111 SwDoc* pDoc = rEditSh.GetDoc(); 112 if( pDoc->IsAutoFmtRedline() ) 113 { 114 // damit der DelPam auch verschoben wird, in den Shell-Cursr-Ring 115 // mit aufnehmen !! 116 _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, rDelPam ); 117 pDoc->DeleteAndJoin( rDelPam ); 118 } 119 else 120 { 121 pDoc->DeleteRange( rDelPam ); 122 } 123 } 124 125 sal_Bool SwAutoCorrDoc::Delete( xub_StrLen nStt, xub_StrLen nEnd ) 126 { 127 const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode; 128 SwPaM aSel( rNd, nStt, rNd, nEnd ); 129 DeleteSel( aSel ); 130 131 if( bUndoIdInitialized ) 132 bUndoIdInitialized = true; 133 return sal_True; 134 } 135 136 137 sal_Bool SwAutoCorrDoc::Insert( xub_StrLen nPos, const String& rTxt ) 138 { 139 SwPaM aPam( rCrsr.GetPoint()->nNode.GetNode(), nPos ); 140 rEditSh.GetDoc()->InsertString( aPam, rTxt ); 141 if( !bUndoIdInitialized ) 142 { 143 bUndoIdInitialized = true; 144 if( 1 == rTxt.Len() ) 145 { 146 rEditSh.StartUndo( UNDO_AUTOCORRECT ); 147 ++m_nEndUndoCounter; 148 } 149 } 150 return sal_True; 151 } 152 153 154 sal_Bool SwAutoCorrDoc::Replace( xub_StrLen nPos, const String& rTxt ) 155 { 156 return ReplaceRange( nPos, rTxt.Len(), rTxt ); 157 } 158 sal_Bool SwAutoCorrDoc::ReplaceRange( xub_StrLen nPos, xub_StrLen nSourceLength, const String& rTxt ) 159 { 160 SwPaM* pPam = &rCrsr; 161 if( pPam->GetPoint()->nContent.GetIndex() != nPos ) 162 { 163 pPam = new SwPaM( *rCrsr.GetPoint() ); 164 pPam->GetPoint()->nContent = nPos; 165 } 166 167 SwTxtNode * const pNd = pPam->GetNode()->GetTxtNode(); 168 if ( !pNd ) 169 { 170 return sal_False; 171 } 172 173 // text attributes with dummy characters must not be replaced! 174 bool bDoReplace = true; 175 xub_StrLen const nLen = rTxt.Len(); 176 for ( xub_StrLen n = 0; n < nLen; ++n ) 177 { 178 sal_Unicode const Char = pNd->GetTxt().GetChar( n + nPos ); 179 if ( ( CH_TXTATR_BREAKWORD == Char || CH_TXTATR_INWORD == Char ) 180 && pNd->GetTxtAttrForCharAt( n + nPos ) ) 181 { 182 bDoReplace = false; 183 break; 184 } 185 } 186 187 if ( bDoReplace ) 188 { 189 SwDoc* pDoc = rEditSh.GetDoc(); 190 191 // if( !pDoc->IsAutoFmtRedline() && 192 // pPam != &rCrsr ) // nur an akt. Position das Redline sichern 193 // pDoc->SetRedlineMode_intern( eOld | REDLINE_IGNORE ); 194 195 if( pDoc->IsAutoFmtRedline() ) 196 { 197 if( nPos == pNd->GetTxt().Len() ) // am Ende erfolgt ein Insert 198 { 199 pDoc->InsertString( *pPam, rTxt ); 200 } 201 else 202 { 203 _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, *pPam ); 204 205 pPam->SetMark(); 206 pPam->GetPoint()->nContent = Min( pNd->GetTxt().Len(), 207 xub_StrLen( nPos + nSourceLength )); 208 pDoc->ReplaceRange( *pPam, rTxt, false ); 209 pPam->Exchange(); 210 pPam->DeleteMark(); 211 } 212 } 213 else 214 { 215 if( nSourceLength != rTxt.Len() ) 216 { 217 pPam->SetMark(); 218 pPam->GetPoint()->nContent = Min( pNd->GetTxt().Len(), 219 xub_StrLen( nPos + nSourceLength )); 220 pDoc->ReplaceRange( *pPam, rTxt, false ); 221 pPam->Exchange(); 222 pPam->DeleteMark(); 223 } 224 else 225 pDoc->Overwrite( *pPam, rTxt ); 226 } 227 228 // pDoc->SetRedlineMode_intern( eOld ); 229 if( bUndoIdInitialized ) 230 { 231 bUndoIdInitialized = true; 232 if( 1 == rTxt.Len() ) 233 { 234 rEditSh.StartUndo( UNDO_AUTOCORRECT ); 235 ++m_nEndUndoCounter; 236 } 237 } 238 } 239 240 if( pPam != &rCrsr ) 241 delete pPam; 242 243 return sal_True; 244 } 245 246 247 248 sal_Bool SwAutoCorrDoc::SetAttr( xub_StrLen nStt, xub_StrLen nEnd, sal_uInt16 nSlotId, 249 SfxPoolItem& rItem ) 250 { 251 const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode; 252 SwPaM aPam( rNd, nStt, rNd, nEnd ); 253 254 SfxItemPool& rPool = rEditSh.GetDoc()->GetAttrPool(); 255 sal_uInt16 nWhich = rPool.GetWhich( nSlotId, sal_False ); 256 if( nWhich ) 257 { 258 rItem.SetWhich( nWhich ); 259 260 SfxItemSet aSet( rPool, aCharFmtSetRange ); 261 SetAllScriptItem( aSet, rItem ); 262 263 rEditSh.GetDoc()->SetFmtItemByAutoFmt( aPam, aSet ); 264 265 if( bUndoIdInitialized ) 266 bUndoIdInitialized = true; 267 } 268 return 0 != nWhich; 269 } 270 271 272 273 sal_Bool SwAutoCorrDoc::SetINetAttr( xub_StrLen nStt, xub_StrLen nEnd, const String& rURL ) 274 { 275 const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode; 276 SwPaM aPam( rNd, nStt, rNd, nEnd ); 277 278 SfxItemSet aSet( rEditSh.GetDoc()->GetAttrPool(), 279 RES_TXTATR_INETFMT, RES_TXTATR_INETFMT ); 280 aSet.Put( SwFmtINetFmt( rURL, aEmptyStr )); 281 rEditSh.GetDoc()->SetFmtItemByAutoFmt( aPam, aSet ); 282 if( bUndoIdInitialized ) 283 bUndoIdInitialized = true; 284 return sal_True; 285 } 286 287 // returne den Text eines vorherigen Absatzes. 288 // Dieser darf nicht leer sein! 289 // Gibt es diesen nicht oder gibt es davor nur Leere, dann returne 0 290 // Das Flag gibt an: 291 // sal_True: den, vor der normalen Einfuegeposition (sal_True) 292 // sal_False: den, in den das korrigierte Wort eingfuegt wurde. 293 // (Muss nicht der gleiche Absatz sein!!!!) 294 const String* SwAutoCorrDoc::GetPrevPara( sal_Bool bAtNormalPos ) 295 { 296 const String* pStr = 0; 297 298 if( bAtNormalPos || !pIdx ) 299 pIdx = new SwNodeIndex( rCrsr.GetPoint()->nNode, -1 ); 300 else 301 (*pIdx)--; 302 303 SwTxtNode* pTNd = pIdx->GetNode().GetTxtNode(); 304 while( pTNd && !pTNd->GetTxt().Len() ) 305 { 306 (*pIdx)--; 307 pTNd = pIdx->GetNode().GetTxtNode(); 308 } 309 //if( pTNd && NO_NUMBERING == pTNd->GetTxtColl()->GetOutlineLevel() ) 310 if( pTNd && 0 == pTNd->GetAttrOutlineLevel() )//#outline level,zhaojianwei 311 pStr = &pTNd->GetTxt(); 312 313 if( bUndoIdInitialized ) 314 bUndoIdInitialized = true; 315 return pStr; 316 } 317 318 319 sal_Bool SwAutoCorrDoc::ChgAutoCorrWord( xub_StrLen & rSttPos, xub_StrLen nEndPos, 320 SvxAutoCorrect& rACorrect, 321 const String** ppPara ) 322 { 323 if( bUndoIdInitialized ) 324 bUndoIdInitialized = true; 325 326 // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort 327 // Kuerzel im Auto 328 SwTxtNode* pTxtNd = rCrsr.GetNode()->GetTxtNode(); 329 ASSERT( pTxtNd, "wo ist denn der TextNode?" ); 330 331 sal_Bool bRet = sal_False; 332 if( nEndPos == rSttPos ) 333 return bRet; 334 335 LanguageType eLang = GetLanguage(nEndPos, sal_False); 336 if(LANGUAGE_SYSTEM == eLang) 337 eLang = (LanguageType)GetAppLanguage(); 338 339 //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte. 340 sal_Bool bLastCharIsPoint = nEndPos < pTxtNd->GetTxt().Len() && 341 '.' == pTxtNd->GetTxt().GetChar( nEndPos ); 342 343 const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList( 344 pTxtNd->GetTxt(), rSttPos, nEndPos, *this, eLang ); 345 SwDoc* pDoc = rEditSh.GetDoc(); 346 if( pFnd ) 347 { 348 const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode; 349 SwPaM aPam( rNd, rSttPos, rNd, nEndPos ); 350 351 if( pFnd->IsTextOnly() ) 352 { 353 //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte. 354 if( !bLastCharIsPoint || !pFnd->GetLong().Len() || 355 '.' != pFnd->GetLong().GetChar( pFnd->GetLong().Len() - 1 ) ) 356 { 357 // replace the selection 358 pDoc->ReplaceRange( aPam, pFnd->GetLong(), false); 359 bRet = sal_True; 360 } 361 } 362 else 363 { 364 SwTextBlocks aTBlks( rACorrect.GetAutoCorrFileName( eLang, sal_False, sal_True )); 365 sal_uInt16 nPos = aTBlks.GetIndex( pFnd->GetShort() ); 366 if( USHRT_MAX != nPos && aTBlks.BeginGetDoc( nPos ) ) 367 { 368 DeleteSel( aPam ); 369 pDoc->DontExpandFmt( *aPam.GetPoint() ); 370 371 if( ppPara ) 372 { 373 ASSERT( !pIdx, "wer hat seinen Index nicht geloescht?" ); 374 pIdx = new SwNodeIndex( rCrsr.GetPoint()->nNode, -1 ); 375 } 376 377 // 378 SwDoc* pAutoDoc = aTBlks.GetDoc(); 379 SwNodeIndex aSttIdx( pAutoDoc->GetNodes().GetEndOfExtras(), 1 ); 380 SwCntntNode* pCntntNd = pAutoDoc->GetNodes().GoNext( &aSttIdx ); 381 SwPaM aCpyPam( aSttIdx ); 382 383 const SwTableNode* pTblNd = pCntntNd->FindTableNode(); 384 if( pTblNd ) 385 { 386 aCpyPam.GetPoint()->nContent.Assign( 0, 0 ); 387 aCpyPam.GetPoint()->nNode = *pTblNd; 388 } 389 aCpyPam.SetMark(); 390 391 // dann bis zum Ende vom Nodes Array 392 aCpyPam.GetPoint()->nNode.Assign( pAutoDoc->GetNodes().GetEndOfContent(), -1 ); 393 pCntntNd = aCpyPam.GetCntntNode(); 394 aCpyPam.GetPoint()->nContent.Assign( pCntntNd, pCntntNd->Len() ); 395 396 SwDontExpandItem aExpItem; 397 aExpItem.SaveDontExpandItems( *aPam.GetPoint() ); 398 399 pAutoDoc->CopyRange( aCpyPam, *aPam.GetPoint(), false ); 400 401 aExpItem.RestoreDontExpandItems( *aPam.GetPoint() ); 402 403 if( ppPara ) 404 { 405 (*pIdx)++; 406 pTxtNd = pIdx->GetNode().GetTxtNode(); 407 } 408 bRet = sal_True; 409 } 410 aTBlks.EndGetDoc(); 411 } 412 } 413 414 if( bRet && ppPara && pTxtNd ) 415 *ppPara = &pTxtNd->GetTxt(); 416 417 return bRet; 418 } 419 420 421 // wird nach dem austauschen der Zeichen von den Funktionen 422 // - FnCptlSttWrd 423 // - FnCptlSttSntnc 424 // gerufen. Dann koennen die Worte ggfs. in die Ausnahmelisten 425 // aufgenommen werden. 426 void SwAutoCorrDoc::SaveCpltSttWord( sal_uLong nFlag, xub_StrLen nPos, 427 const String& rExceptWord, 428 sal_Unicode cChar ) 429 { 430 sal_uLong nNode = pIdx ? pIdx->GetIndex() : rCrsr.GetPoint()->nNode.GetIndex(); 431 LanguageType eLang = GetLanguage(nPos, sal_False); 432 rEditSh.GetDoc()->SetAutoCorrExceptWord( new SwAutoCorrExceptWord( nFlag, 433 nNode, nPos, rExceptWord, cChar, eLang )); 434 } 435 436 LanguageType SwAutoCorrDoc::GetLanguage( xub_StrLen nPos, sal_Bool bPrevPara ) const 437 { 438 LanguageType eRet = LANGUAGE_SYSTEM; 439 440 SwTxtNode* pNd = (( bPrevPara && pIdx ) 441 ? *pIdx 442 : rCrsr.GetPoint()->nNode ).GetNode().GetTxtNode(); 443 444 if( pNd ) 445 eRet = pNd->GetLang( nPos, 0 ); 446 if(LANGUAGE_SYSTEM == eRet) 447 eRet = (LanguageType)GetAppLanguage(); 448 return eRet; 449 } 450 451 void SwAutoCorrExceptWord::CheckChar( const SwPosition& rPos, sal_Unicode cChr ) 452 { 453 // nur testen ob es eine Verbesserung ist. Wenn ja, dann das Wort 454 // in die Ausnahmeliste aufnehmen. 455 if( cChar == cChr && rPos.nNode.GetIndex() == nNode && 456 rPos.nContent.GetIndex() == nCntnt ) 457 { 458 // die akt. Autokorrektur besorgen: 459 SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get()->GetAutoCorrect(); 460 461 // dann in die Liste aufnehmen: 462 if( CptlSttWrd & nFlags ) 463 pACorr->AddWrtSttException( sWord, eLanguage ); 464 else if( CptlSttSntnc & nFlags ) 465 pACorr->AddCplSttException( sWord, eLanguage ); 466 } 467 } 468 469 470 sal_Bool SwAutoCorrExceptWord::CheckDelChar( const SwPosition& rPos ) 471 { 472 sal_Bool bRet = sal_False; 473 if( !bDeleted && rPos.nNode.GetIndex() == nNode && 474 rPos.nContent.GetIndex() == nCntnt ) 475 bDeleted = bRet = sal_True; 476 return bRet; 477 } 478 479 SwDontExpandItem::~SwDontExpandItem() 480 { 481 delete pDontExpItems; 482 } 483 484 void SwDontExpandItem::SaveDontExpandItems( const SwPosition& rPos ) 485 { 486 const SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); 487 if( pTxtNd ) 488 { 489 pDontExpItems = new SfxItemSet( ((SwDoc*)pTxtNd->GetDoc())->GetAttrPool(), 490 aCharFmtSetRange ); 491 xub_StrLen n = rPos.nContent.GetIndex(); 492 if( !pTxtNd->GetAttr( *pDontExpItems, n, n, 493 n != pTxtNd->GetTxt().Len() )) 494 delete pDontExpItems, pDontExpItems = 0; 495 } 496 } 497 498 void SwDontExpandItem::RestoreDontExpandItems( const SwPosition& rPos ) 499 { 500 SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); 501 if( pTxtNd ) 502 { 503 xub_StrLen nStart = rPos.nContent.GetIndex(); 504 if( nStart == pTxtNd->GetTxt().Len() ) 505 pTxtNd->FmtToTxtAttr( pTxtNd ); 506 507 if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() ) 508 { 509 const sal_uInt16 nSize = pTxtNd->GetpSwpHints()->Count(); 510 sal_uInt16 n; 511 xub_StrLen nAttrStart; 512 const xub_StrLen* pAttrEnd; 513 514 for( n = 0; n < nSize; ++n ) 515 { 516 SwTxtAttr* pHt = pTxtNd->GetpSwpHints()->GetTextHint( n ); 517 nAttrStart = *pHt->GetStart(); 518 if( nAttrStart > nStart ) // ueber den Bereich hinaus 519 break; 520 521 if( 0 != ( pAttrEnd = pHt->GetEnd() ) && 522 ( ( nAttrStart < nStart && 523 ( pHt->DontExpand() ? nStart < *pAttrEnd 524 : nStart <= *pAttrEnd )) || 525 ( nStart == nAttrStart && 526 ( nAttrStart == *pAttrEnd || !nStart ))) ) 527 { 528 const SfxPoolItem* pItem; 529 if( !pDontExpItems || SFX_ITEM_SET != pDontExpItems-> 530 GetItemState( pHt->Which(), sal_False, &pItem ) || 531 *pItem != pHt->GetAttr() ) 532 { 533 // das Attribut war vorher nicht in dieser Form im Absatz 534 // gesetzt, also kann es nur durchs einfuegen/kopieren erzeugt 535 // worden sein. Damit ist es ein Kandiadat fuers DontExpand 536 pHt->SetDontExpand( sal_True ); 537 } 538 } 539 } 540 } 541 } 542 } 543 544 545