| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| |
| |
| #define _STD_VAR_ARRAYS |
| #include <hintids.hxx> |
| |
| #include <svx/svxids.hrc> |
| #include <editeng/langitem.hxx> |
| #include <fmtinfmt.hxx> |
| #include <txtatr.hxx> |
| #include <txtinet.hxx> |
| #include <editsh.hxx> |
| #include <doc.hxx> |
| #include <pam.hxx> |
| #include <ndtxt.hxx> |
| #include <acorrect.hxx> |
| #include <shellio.hxx> |
| #include <swundo.hxx> |
| #include <viscrs.hxx> |
| |
| #include <editeng/acorrcfg.hxx> |
| |
| using namespace ::com::sun::star; |
| |
| |
| class _PaMIntoCrsrShellRing |
| { |
| SwCrsrShell& rSh; |
| SwPaM &rDelPam, &rCrsr; |
| Ring *pPrevDelPam, *pPrevCrsr; |
| |
| void RemoveFromRing( SwPaM& rPam, Ring* pPrev ); |
| public: |
| _PaMIntoCrsrShellRing( SwCrsrShell& rSh, SwPaM& rCrsr, SwPaM& rPam ); |
| ~_PaMIntoCrsrShellRing(); |
| }; |
| |
| _PaMIntoCrsrShellRing::_PaMIntoCrsrShellRing( SwCrsrShell& rCSh, |
| SwPaM& rShCrsr, SwPaM& rPam ) |
| : rSh( rCSh ), rDelPam( rPam ), rCrsr( rShCrsr ) |
| { |
| SwPaM* pShCrsr = rSh._GetCrsr(); |
| |
| pPrevDelPam = rDelPam.GetPrev(); |
| pPrevCrsr = rCrsr.GetPrev(); |
| |
| rDelPam.MoveRingTo( pShCrsr ); |
| rCrsr.MoveRingTo( pShCrsr ); |
| } |
| _PaMIntoCrsrShellRing::~_PaMIntoCrsrShellRing() |
| { |
| // und den Pam wieder herausnehmen: |
| RemoveFromRing( rDelPam, pPrevDelPam ); |
| RemoveFromRing( rCrsr, pPrevCrsr ); |
| } |
| void _PaMIntoCrsrShellRing::RemoveFromRing( SwPaM& rPam, Ring* pPrev ) |
| { |
| Ring *p, *pNext = (Ring*)&rPam; |
| do { |
| p = pNext; |
| pNext = p->GetNext(); |
| p->MoveTo( &rPam ); |
| } while( p != pPrev ); |
| } |
| |
| |
| SwAutoCorrDoc::SwAutoCorrDoc( SwEditShell& rEditShell, SwPaM& rPam, |
| sal_Unicode cIns ) |
| : rEditSh( rEditShell ), rCrsr( rPam ), pIdx( 0 ) |
| , m_nEndUndoCounter(0) |
| , bUndoIdInitialized( cIns ? false : true ) |
| { |
| } |
| |
| |
| SwAutoCorrDoc::~SwAutoCorrDoc() |
| { |
| for (int i = 0; i < m_nEndUndoCounter; ++i) |
| { |
| rEditSh.EndUndo(); |
| } |
| delete pIdx; |
| } |
| |
| void SwAutoCorrDoc::DeleteSel( SwPaM& rDelPam ) |
| { |
| SwDoc* pDoc = rEditSh.GetDoc(); |
| if( pDoc->IsAutoFmtRedline() ) |
| { |
| // damit der DelPam auch verschoben wird, in den Shell-Cursr-Ring |
| // mit aufnehmen !! |
| _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, rDelPam ); |
| pDoc->DeleteAndJoin( rDelPam ); |
| } |
| else |
| { |
| pDoc->DeleteRange( rDelPam ); |
| } |
| } |
| |
| sal_Bool SwAutoCorrDoc::Delete( xub_StrLen nStt, xub_StrLen nEnd ) |
| { |
| const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode; |
| SwPaM aSel( rNd, nStt, rNd, nEnd ); |
| DeleteSel( aSel ); |
| |
| if( bUndoIdInitialized ) |
| bUndoIdInitialized = true; |
| return sal_True; |
| } |
| |
| |
| sal_Bool SwAutoCorrDoc::Insert( xub_StrLen nPos, const String& rTxt ) |
| { |
| SwPaM aPam( rCrsr.GetPoint()->nNode.GetNode(), nPos ); |
| rEditSh.GetDoc()->InsertString( aPam, rTxt ); |
| if( !bUndoIdInitialized ) |
| { |
| bUndoIdInitialized = true; |
| if( 1 == rTxt.Len() ) |
| { |
| rEditSh.StartUndo( UNDO_AUTOCORRECT ); |
| ++m_nEndUndoCounter; |
| } |
| } |
| return sal_True; |
| } |
| |
| |
| sal_Bool SwAutoCorrDoc::Replace( xub_StrLen nPos, const String& rTxt ) |
| { |
| return ReplaceRange( nPos, rTxt.Len(), rTxt ); |
| } |
| sal_Bool SwAutoCorrDoc::ReplaceRange( xub_StrLen nPos, xub_StrLen nSourceLength, const String& rTxt ) |
| { |
| SwPaM* pPam = &rCrsr; |
| if( pPam->GetPoint()->nContent.GetIndex() != nPos ) |
| { |
| pPam = new SwPaM( *rCrsr.GetPoint() ); |
| pPam->GetPoint()->nContent = nPos; |
| } |
| |
| SwTxtNode * const pNd = pPam->GetNode()->GetTxtNode(); |
| if ( !pNd ) |
| { |
| return sal_False; |
| } |
| |
| // text attributes with dummy characters must not be replaced! |
| bool bDoReplace = true; |
| xub_StrLen const nLen = rTxt.Len(); |
| for ( xub_StrLen n = 0; n < nLen; ++n ) |
| { |
| sal_Unicode const Char = pNd->GetTxt().GetChar( n + nPos ); |
| if ( ( CH_TXTATR_BREAKWORD == Char || CH_TXTATR_INWORD == Char ) |
| && pNd->GetTxtAttrForCharAt( n + nPos ) ) |
| { |
| bDoReplace = false; |
| break; |
| } |
| } |
| |
| if ( bDoReplace ) |
| { |
| SwDoc* pDoc = rEditSh.GetDoc(); |
| |
| // if( !pDoc->IsAutoFmtRedline() && |
| // pPam != &rCrsr ) // nur an akt. Position das Redline sichern |
| // pDoc->SetRedlineMode_intern( eOld | REDLINE_IGNORE ); |
| |
| if( pDoc->IsAutoFmtRedline() ) |
| { |
| if( nPos == pNd->GetTxt().Len() ) // am Ende erfolgt ein Insert |
| { |
| pDoc->InsertString( *pPam, rTxt ); |
| } |
| else |
| { |
| _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, *pPam ); |
| |
| pPam->SetMark(); |
| pPam->GetPoint()->nContent = Min( pNd->GetTxt().Len(), |
| xub_StrLen( nPos + nSourceLength )); |
| pDoc->ReplaceRange( *pPam, rTxt, false ); |
| pPam->Exchange(); |
| pPam->DeleteMark(); |
| } |
| } |
| else |
| { |
| if( nSourceLength != rTxt.Len() ) |
| { |
| pPam->SetMark(); |
| pPam->GetPoint()->nContent = Min( pNd->GetTxt().Len(), |
| xub_StrLen( nPos + nSourceLength )); |
| pDoc->ReplaceRange( *pPam, rTxt, false ); |
| pPam->Exchange(); |
| pPam->DeleteMark(); |
| } |
| else |
| pDoc->Overwrite( *pPam, rTxt ); |
| } |
| |
| // pDoc->SetRedlineMode_intern( eOld ); |
| if( bUndoIdInitialized ) |
| { |
| bUndoIdInitialized = true; |
| if( 1 == rTxt.Len() ) |
| { |
| rEditSh.StartUndo( UNDO_AUTOCORRECT ); |
| ++m_nEndUndoCounter; |
| } |
| } |
| } |
| |
| if( pPam != &rCrsr ) |
| delete pPam; |
| |
| return sal_True; |
| } |
| |
| |
| |
| sal_Bool SwAutoCorrDoc::SetAttr( xub_StrLen nStt, xub_StrLen nEnd, sal_uInt16 nSlotId, |
| SfxPoolItem& rItem ) |
| { |
| const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode; |
| SwPaM aPam( rNd, nStt, rNd, nEnd ); |
| |
| SfxItemPool& rPool = rEditSh.GetDoc()->GetAttrPool(); |
| sal_uInt16 nWhich = rPool.GetWhich( nSlotId, sal_False ); |
| if( nWhich ) |
| { |
| rItem.SetWhich( nWhich ); |
| |
| SfxItemSet aSet( rPool, aCharFmtSetRange ); |
| SetAllScriptItem( aSet, rItem ); |
| |
| rEditSh.GetDoc()->SetFmtItemByAutoFmt( aPam, aSet ); |
| |
| if( bUndoIdInitialized ) |
| bUndoIdInitialized = true; |
| } |
| return 0 != nWhich; |
| } |
| |
| |
| |
| sal_Bool SwAutoCorrDoc::SetINetAttr( xub_StrLen nStt, xub_StrLen nEnd, const String& rURL ) |
| { |
| const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode; |
| SwPaM aPam( rNd, nStt, rNd, nEnd ); |
| |
| SfxItemSet aSet( rEditSh.GetDoc()->GetAttrPool(), |
| RES_TXTATR_INETFMT, RES_TXTATR_INETFMT ); |
| aSet.Put( SwFmtINetFmt( rURL, aEmptyStr )); |
| rEditSh.GetDoc()->SetFmtItemByAutoFmt( aPam, aSet ); |
| if( bUndoIdInitialized ) |
| bUndoIdInitialized = true; |
| return sal_True; |
| } |
| |
| // returne den Text eines vorherigen Absatzes. |
| // Dieser darf nicht leer sein! |
| // Gibt es diesen nicht oder gibt es davor nur Leere, dann returne 0 |
| // Das Flag gibt an: |
| // sal_True: den, vor der normalen Einfuegeposition (sal_True) |
| // sal_False: den, in den das korrigierte Wort eingfuegt wurde. |
| // (Muss nicht der gleiche Absatz sein!!!!) |
| const String* SwAutoCorrDoc::GetPrevPara( sal_Bool bAtNormalPos ) |
| { |
| const String* pStr = 0; |
| |
| if( bAtNormalPos || !pIdx ) |
| pIdx = new SwNodeIndex( rCrsr.GetPoint()->nNode, -1 ); |
| else |
| (*pIdx)--; |
| |
| SwTxtNode* pTNd = pIdx->GetNode().GetTxtNode(); |
| while( pTNd && !pTNd->GetTxt().Len() ) |
| { |
| (*pIdx)--; |
| pTNd = pIdx->GetNode().GetTxtNode(); |
| } |
| //if( pTNd && NO_NUMBERING == pTNd->GetTxtColl()->GetOutlineLevel() ) |
| if( pTNd && 0 == pTNd->GetAttrOutlineLevel() )//#outline level,zhaojianwei |
| pStr = &pTNd->GetTxt(); |
| |
| if( bUndoIdInitialized ) |
| bUndoIdInitialized = true; |
| return pStr; |
| } |
| |
| |
| sal_Bool SwAutoCorrDoc::ChgAutoCorrWord( xub_StrLen & rSttPos, xub_StrLen nEndPos, |
| SvxAutoCorrect& rACorrect, |
| const String** ppPara ) |
| { |
| if( bUndoIdInitialized ) |
| bUndoIdInitialized = true; |
| |
| // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort |
| // Kuerzel im Auto |
| SwTxtNode* pTxtNd = rCrsr.GetNode()->GetTxtNode(); |
| ASSERT( pTxtNd, "wo ist denn der TextNode?" ); |
| |
| sal_Bool bRet = sal_False; |
| if( nEndPos == rSttPos ) |
| return bRet; |
| |
| LanguageType eLang = GetLanguage(nEndPos, sal_False); |
| if(LANGUAGE_SYSTEM == eLang) |
| eLang = (LanguageType)GetAppLanguage(); |
| |
| //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte. |
| sal_Bool bLastCharIsPoint = nEndPos < pTxtNd->GetTxt().Len() && |
| '.' == pTxtNd->GetTxt().GetChar( nEndPos ); |
| |
| const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList( |
| pTxtNd->GetTxt(), rSttPos, nEndPos, *this, eLang ); |
| SwDoc* pDoc = rEditSh.GetDoc(); |
| if( pFnd ) |
| { |
| const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode; |
| SwPaM aPam( rNd, rSttPos, rNd, nEndPos ); |
| |
| if( pFnd->IsTextOnly() ) |
| { |
| //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte. |
| if( !bLastCharIsPoint || !pFnd->GetLong().Len() || |
| '.' != pFnd->GetLong().GetChar( pFnd->GetLong().Len() - 1 ) ) |
| { |
| // replace the selection |
| pDoc->ReplaceRange( aPam, pFnd->GetLong(), false); |
| bRet = sal_True; |
| } |
| } |
| else |
| { |
| SwTextBlocks aTBlks( rACorrect.GetAutoCorrFileName( eLang, sal_False, sal_True )); |
| sal_uInt16 nPos = aTBlks.GetIndex( pFnd->GetShort() ); |
| if( USHRT_MAX != nPos && aTBlks.BeginGetDoc( nPos ) ) |
| { |
| DeleteSel( aPam ); |
| pDoc->DontExpandFmt( *aPam.GetPoint() ); |
| |
| if( ppPara ) |
| { |
| ASSERT( !pIdx, "wer hat seinen Index nicht geloescht?" ); |
| pIdx = new SwNodeIndex( rCrsr.GetPoint()->nNode, -1 ); |
| } |
| |
| // |
| SwDoc* pAutoDoc = aTBlks.GetDoc(); |
| SwNodeIndex aSttIdx( pAutoDoc->GetNodes().GetEndOfExtras(), 1 ); |
| SwCntntNode* pCntntNd = pAutoDoc->GetNodes().GoNext( &aSttIdx ); |
| SwPaM aCpyPam( aSttIdx ); |
| |
| const SwTableNode* pTblNd = pCntntNd->FindTableNode(); |
| if( pTblNd ) |
| { |
| aCpyPam.GetPoint()->nContent.Assign( 0, 0 ); |
| aCpyPam.GetPoint()->nNode = *pTblNd; |
| } |
| aCpyPam.SetMark(); |
| |
| // dann bis zum Ende vom Nodes Array |
| aCpyPam.GetPoint()->nNode.Assign( pAutoDoc->GetNodes().GetEndOfContent(), -1 ); |
| pCntntNd = aCpyPam.GetCntntNode(); |
| aCpyPam.GetPoint()->nContent.Assign( pCntntNd, pCntntNd->Len() ); |
| |
| SwDontExpandItem aExpItem; |
| aExpItem.SaveDontExpandItems( *aPam.GetPoint() ); |
| |
| pAutoDoc->CopyRange( aCpyPam, *aPam.GetPoint(), false ); |
| |
| aExpItem.RestoreDontExpandItems( *aPam.GetPoint() ); |
| |
| if( ppPara ) |
| { |
| (*pIdx)++; |
| pTxtNd = pIdx->GetNode().GetTxtNode(); |
| } |
| bRet = sal_True; |
| } |
| aTBlks.EndGetDoc(); |
| } |
| } |
| |
| if( bRet && ppPara && pTxtNd ) |
| *ppPara = &pTxtNd->GetTxt(); |
| |
| return bRet; |
| } |
| |
| |
| // wird nach dem austauschen der Zeichen von den Funktionen |
| // - FnCptlSttWrd |
| // - FnCptlSttSntnc |
| // gerufen. Dann koennen die Worte ggfs. in die Ausnahmelisten |
| // aufgenommen werden. |
| void SwAutoCorrDoc::SaveCpltSttWord( sal_uLong nFlag, xub_StrLen nPos, |
| const String& rExceptWord, |
| sal_Unicode cChar ) |
| { |
| sal_uLong nNode = pIdx ? pIdx->GetIndex() : rCrsr.GetPoint()->nNode.GetIndex(); |
| LanguageType eLang = GetLanguage(nPos, sal_False); |
| rEditSh.GetDoc()->SetAutoCorrExceptWord( new SwAutoCorrExceptWord( nFlag, |
| nNode, nPos, rExceptWord, cChar, eLang )); |
| } |
| |
| LanguageType SwAutoCorrDoc::GetLanguage( xub_StrLen nPos, sal_Bool bPrevPara ) const |
| { |
| LanguageType eRet = LANGUAGE_SYSTEM; |
| |
| SwTxtNode* pNd = (( bPrevPara && pIdx ) |
| ? *pIdx |
| : rCrsr.GetPoint()->nNode ).GetNode().GetTxtNode(); |
| |
| if( pNd ) |
| eRet = pNd->GetLang( nPos, 0 ); |
| if(LANGUAGE_SYSTEM == eRet) |
| eRet = (LanguageType)GetAppLanguage(); |
| return eRet; |
| } |
| |
| void SwAutoCorrExceptWord::CheckChar( const SwPosition& rPos, sal_Unicode cChr ) |
| { |
| // nur testen ob es eine Verbesserung ist. Wenn ja, dann das Wort |
| // in die Ausnahmeliste aufnehmen. |
| if( cChar == cChr && rPos.nNode.GetIndex() == nNode && |
| rPos.nContent.GetIndex() == nCntnt ) |
| { |
| // die akt. Autokorrektur besorgen: |
| SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get()->GetAutoCorrect(); |
| |
| // dann in die Liste aufnehmen: |
| if( CptlSttWrd & nFlags ) |
| pACorr->AddWrtSttException( sWord, eLanguage ); |
| else if( CptlSttSntnc & nFlags ) |
| pACorr->AddCplSttException( sWord, eLanguage ); |
| } |
| } |
| |
| |
| sal_Bool SwAutoCorrExceptWord::CheckDelChar( const SwPosition& rPos ) |
| { |
| sal_Bool bRet = sal_False; |
| if( !bDeleted && rPos.nNode.GetIndex() == nNode && |
| rPos.nContent.GetIndex() == nCntnt ) |
| bDeleted = bRet = sal_True; |
| return bRet; |
| } |
| |
| SwDontExpandItem::~SwDontExpandItem() |
| { |
| delete pDontExpItems; |
| } |
| |
| void SwDontExpandItem::SaveDontExpandItems( const SwPosition& rPos ) |
| { |
| const SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); |
| if( pTxtNd ) |
| { |
| pDontExpItems = new SfxItemSet( ((SwDoc*)pTxtNd->GetDoc())->GetAttrPool(), |
| aCharFmtSetRange ); |
| xub_StrLen n = rPos.nContent.GetIndex(); |
| if( !pTxtNd->GetAttr( *pDontExpItems, n, n, |
| n != pTxtNd->GetTxt().Len() )) |
| delete pDontExpItems, pDontExpItems = 0; |
| } |
| } |
| |
| void SwDontExpandItem::RestoreDontExpandItems( const SwPosition& rPos ) |
| { |
| SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); |
| if( pTxtNd ) |
| { |
| xub_StrLen nStart = rPos.nContent.GetIndex(); |
| if( nStart == pTxtNd->GetTxt().Len() ) |
| pTxtNd->FmtToTxtAttr( pTxtNd ); |
| |
| if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() ) |
| { |
| const sal_uInt16 nSize = pTxtNd->GetpSwpHints()->Count(); |
| sal_uInt16 n; |
| xub_StrLen nAttrStart; |
| const xub_StrLen* pAttrEnd; |
| |
| for( n = 0; n < nSize; ++n ) |
| { |
| SwTxtAttr* pHt = pTxtNd->GetpSwpHints()->GetTextHint( n ); |
| nAttrStart = *pHt->GetStart(); |
| if( nAttrStart > nStart ) // ueber den Bereich hinaus |
| break; |
| |
| if( 0 != ( pAttrEnd = pHt->End() ) && |
| ( ( nAttrStart < nStart && |
| ( pHt->DontExpand() ? nStart < *pAttrEnd |
| : nStart <= *pAttrEnd )) || |
| ( nStart == nAttrStart && |
| ( nAttrStart == *pAttrEnd || !nStart ))) ) |
| { |
| const SfxPoolItem* pItem; |
| if( !pDontExpItems || SFX_ITEM_SET != pDontExpItems-> |
| GetItemState( pHt->Which(), sal_False, &pItem ) || |
| *pItem != pHt->GetAttr() ) |
| { |
| // das Attribut war vorher nicht in dieser Form im Absatz |
| // gesetzt, also kann es nur durchs einfuegen/kopieren erzeugt |
| // worden sein. Damit ist es ein Kandiadat fuers DontExpand |
| pHt->SetDontExpand( sal_True ); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |