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