1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: acorrect.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #define _STD_VAR_ARRAYS
36 #include <hintids.hxx>
38 #ifndef _SVX_SVXIDS_HRC
39 #include <svx/svxids.hrc>
41 #include <svx/langitem.hxx>
42 #include <fmtinfmt.hxx>
44 #include <txtinet.hxx>
45 #include <fmthbsh.hxx>
50 #include <acorrect.hxx>
51 #include <shellio.hxx>
55 #include <svx/acorrcfg.hxx>
57 using namespace ::com::sun::star
;
60 class _PaMIntoCrsrShellRing
63 SwPaM
&rDelPam
, &rCrsr
;
64 Ring
*pPrevDelPam
, *pPrevCrsr
;
66 void RemoveFromRing( SwPaM
& rPam
, Ring
* pPrev
);
68 _PaMIntoCrsrShellRing( SwCrsrShell
& rSh
, SwPaM
& rCrsr
, SwPaM
& rPam
);
69 ~_PaMIntoCrsrShellRing();
72 _PaMIntoCrsrShellRing::_PaMIntoCrsrShellRing( SwCrsrShell
& rCSh
,
73 SwPaM
& rShCrsr
, SwPaM
& rPam
)
74 : rSh( rCSh
), rDelPam( rPam
), rCrsr( rShCrsr
)
76 SwPaM
* pShCrsr
= rSh
._GetCrsr();
78 pPrevDelPam
= rDelPam
.GetPrev();
79 pPrevCrsr
= rCrsr
.GetPrev();
81 rDelPam
.MoveRingTo( pShCrsr
);
82 rCrsr
.MoveRingTo( pShCrsr
);
84 _PaMIntoCrsrShellRing::~_PaMIntoCrsrShellRing()
86 // und den Pam wieder herausnehmen:
87 RemoveFromRing( rDelPam
, pPrevDelPam
);
88 RemoveFromRing( rCrsr
, pPrevCrsr
);
90 void _PaMIntoCrsrShellRing::RemoveFromRing( SwPaM
& rPam
, Ring
* pPrev
)
92 Ring
*p
, *pNext
= (Ring
*)&rPam
;
97 } while( p
!= pPrev
);
101 SwAutoCorrDoc::SwAutoCorrDoc( SwEditShell
& rEditShell
, SwPaM
& rPam
,
103 : rEditSh( rEditShell
), rCrsr( rPam
), pIdx( 0 ),
104 nUndoId( UNDO_EMPTY
),
105 bUndoIdInitialized( cIns
? false : true )
110 SwAutoCorrDoc::~SwAutoCorrDoc()
112 if( UNDO_EMPTY
!= nUndoId
)
113 rEditSh
.EndUndo( nUndoId
);
117 void SwAutoCorrDoc::DeleteSel( SwPaM
& rDelPam
)
119 SwDoc
* pDoc
= rEditSh
.GetDoc();
120 if( pDoc
->IsAutoFmtRedline() )
122 // damit der DelPam auch verschoben wird, in den Shell-Cursr-Ring
124 _PaMIntoCrsrShellRing
aTmp( rEditSh
, rCrsr
, rDelPam
);
125 pDoc
->DeleteAndJoin( rDelPam
);
128 pDoc
->Delete( rDelPam
);
131 BOOL
SwAutoCorrDoc::Delete( xub_StrLen nStt
, xub_StrLen nEnd
)
133 const SwNodeIndex
& rNd
= rCrsr
.GetPoint()->nNode
;
134 SwPaM
aSel( rNd
, nStt
, rNd
, nEnd
);
137 if( bUndoIdInitialized
)
138 bUndoIdInitialized
= true;
143 BOOL
SwAutoCorrDoc::Insert( xub_StrLen nPos
, const String
& rTxt
)
145 SwPaM
aPam( rCrsr
.GetPoint()->nNode
.GetNode(), nPos
);
146 rEditSh
.GetDoc()->Insert( aPam
, rTxt
, true );
147 if( !bUndoIdInitialized
)
149 bUndoIdInitialized
= true;
150 if( 1 == rTxt
.Len() )
151 rEditSh
.StartUndo( nUndoId
= UNDO_AUTOCORRECT
);
157 BOOL
SwAutoCorrDoc::Replace( xub_StrLen nPos
, const String
& rTxt
)
159 SwPaM
* pPam
= &rCrsr
;
160 if( pPam
->GetPoint()->nContent
.GetIndex() != nPos
)
162 pPam
= new SwPaM( *rCrsr
.GetPoint() );
163 pPam
->GetPoint()->nContent
= nPos
;
167 SwTxtNode
* pNd
= pPam
->GetNode()->GetTxtNode();
170 // TextAttribute ohne Ende duerfen nie ersetzt werden!
172 for( xub_StrLen n
= 0, nLen
= rTxt
.Len(); n
< nLen
; ++n
)
173 if( ( CH_TXTATR_BREAKWORD
== (cChr
= pNd
->GetTxt().
174 GetChar( n
+ nPos
)) || CH_TXTATR_INWORD
== cChr
) &&
175 pNd
->GetTxtAttr( n
+ nPos
) )
184 SwDoc
* pDoc
= rEditSh
.GetDoc();
186 // if( !pDoc->IsAutoFmtRedline() &&
187 // pPam != &rCrsr ) // nur an akt. Position das Redline sichern
188 // pDoc->SetRedlineMode_intern( eOld | REDLINE_IGNORE );
190 if( pDoc
->IsAutoFmtRedline() )
192 if( nPos
== pNd
->GetTxt().Len() ) // am Ende erfolgt ein Insert
193 pDoc
->Insert( *pPam
, rTxt
, true );
196 _PaMIntoCrsrShellRing
aTmp( rEditSh
, rCrsr
, *pPam
);
199 pPam
->GetPoint()->nContent
= Min( pNd
->GetTxt().Len(),
200 xub_StrLen( nPos
+ rTxt
.Len() ));
201 pDoc
->Replace( *pPam
, rTxt
, FALSE
);
207 pDoc
->Overwrite( *pPam
, rTxt
);
209 // pDoc->SetRedlineMode_intern( eOld );
210 if( bUndoIdInitialized
)
212 bUndoIdInitialized
= true;
213 if( 1 == rTxt
.Len() )
214 rEditSh
.StartUndo( nUndoId
= UNDO_AUTOCORRECT
);
226 BOOL
SwAutoCorrDoc::SetAttr( xub_StrLen nStt
, xub_StrLen nEnd
, USHORT nSlotId
,
229 const SwNodeIndex
& rNd
= rCrsr
.GetPoint()->nNode
;
230 SwPaM
aPam( rNd
, nStt
, rNd
, nEnd
);
232 SfxItemPool
& rPool
= rEditSh
.GetDoc()->GetAttrPool();
233 USHORT nWhich
= rPool
.GetWhich( nSlotId
, FALSE
);
236 rItem
.SetWhich( nWhich
);
238 SfxItemSet
aSet( rPool
, aCharFmtSetRange
);
239 SetAllScriptItem( aSet
, rItem
);
241 rEditSh
.GetDoc()->SetFmtItemByAutoFmt( aPam
, aSet
);
243 if( bUndoIdInitialized
)
244 bUndoIdInitialized
= true;
251 BOOL
SwAutoCorrDoc::SetINetAttr( xub_StrLen nStt
, xub_StrLen nEnd
, const String
& rURL
)
253 const SwNodeIndex
& rNd
= rCrsr
.GetPoint()->nNode
;
254 SwPaM
aPam( rNd
, nStt
, rNd
, nEnd
);
256 SfxItemSet
aSet( rEditSh
.GetDoc()->GetAttrPool(),
257 RES_TXTATR_INETFMT
, RES_TXTATR_INETFMT
);
258 aSet
.Put( SwFmtINetFmt( rURL
, aEmptyStr
));
259 rEditSh
.GetDoc()->SetFmtItemByAutoFmt( aPam
, aSet
);
260 if( bUndoIdInitialized
)
261 bUndoIdInitialized
= true;
265 // returne den Text eines vorherigen Absatzes.
266 // Dieser darf nicht leer sein!
267 // Gibt es diesen nicht oder gibt es davor nur Leere, dann returne 0
269 // TRUE: den, vor der normalen Einfuegeposition (TRUE)
270 // FALSE: den, in den das korrigierte Wort eingfuegt wurde.
271 // (Muss nicht der gleiche Absatz sein!!!!)
272 const String
* SwAutoCorrDoc::GetPrevPara( BOOL bAtNormalPos
)
274 const String
* pStr
= 0;
276 if( bAtNormalPos
|| !pIdx
)
277 pIdx
= new SwNodeIndex( rCrsr
.GetPoint()->nNode
, -1 );
281 SwTxtNode
* pTNd
= pIdx
->GetNode().GetTxtNode();
282 while( pTNd
&& !pTNd
->GetTxt().Len() )
285 pTNd
= pIdx
->GetNode().GetTxtNode();
287 //if( pTNd && NO_NUMBERING == pTNd->GetTxtColl()->GetOutlineLevel() )
288 if( pTNd
&& 0 == pTNd
->GetAttrOutlineLevel() )//#outline level,zhaojianwei
289 pStr
= &pTNd
->GetTxt();
291 if( bUndoIdInitialized
)
292 bUndoIdInitialized
= true;
297 BOOL
SwAutoCorrDoc::ChgAutoCorrWord( xub_StrLen
& rSttPos
, xub_StrLen nEndPos
,
298 SvxAutoCorrect
& rACorrect
,
299 const String
** ppPara
)
301 if( bUndoIdInitialized
)
302 bUndoIdInitialized
= true;
304 // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
306 SwTxtNode
* pTxtNd
= rCrsr
.GetNode()->GetTxtNode();
307 ASSERT( pTxtNd
, "wo ist denn der TextNode?" );
310 if( nEndPos
== rSttPos
)
313 LanguageType eLang
= GetLanguage(nEndPos
, FALSE
);
314 if(LANGUAGE_SYSTEM
== eLang
)
315 eLang
= (LanguageType
)GetAppLanguage();
317 //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte.
318 BOOL bLastCharIsPoint
= nEndPos
< pTxtNd
->GetTxt().Len() &&
319 '.' == pTxtNd
->GetTxt().GetChar( nEndPos
);
321 const SvxAutocorrWord
* pFnd
= rACorrect
.SearchWordsInList(
322 pTxtNd
->GetTxt(), rSttPos
, nEndPos
, *this, eLang
);
323 SwDoc
* pDoc
= rEditSh
.GetDoc();
326 const SwNodeIndex
& rNd
= rCrsr
.GetPoint()->nNode
;
327 SwPaM
aPam( rNd
, rSttPos
, rNd
, nEndPos
);
329 if( pFnd
->IsTextOnly() )
331 //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte.
332 if( !bLastCharIsPoint
|| !pFnd
->GetLong().Len() ||
333 '.' != pFnd
->GetLong().GetChar( pFnd
->GetLong().Len() - 1 ) )
335 // replace the selection
336 pDoc
->Replace( aPam
, pFnd
->GetLong(), false);
342 SwTextBlocks
aTBlks( rACorrect
.GetAutoCorrFileName( eLang
, FALSE
, TRUE
));
343 USHORT nPos
= aTBlks
.GetIndex( pFnd
->GetShort() );
344 if( USHRT_MAX
!= nPos
&& aTBlks
.BeginGetDoc( nPos
) )
347 pDoc
->DontExpandFmt( *aPam
.GetPoint() );
351 ASSERT( !pIdx
, "wer hat seinen Index nicht geloescht?" );
352 pIdx
= new SwNodeIndex( rCrsr
.GetPoint()->nNode
, -1 );
356 SwDoc
* pAutoDoc
= aTBlks
.GetDoc();
357 SwNodeIndex
aSttIdx( pAutoDoc
->GetNodes().GetEndOfExtras(), 1 );
358 SwCntntNode
* pCntntNd
= pAutoDoc
->GetNodes().GoNext( &aSttIdx
);
359 SwPaM
aCpyPam( aSttIdx
);
361 const SwTableNode
* pTblNd
= pCntntNd
->FindTableNode();
364 aCpyPam
.GetPoint()->nContent
.Assign( 0, 0 );
365 aCpyPam
.GetPoint()->nNode
= *pTblNd
;
369 // dann bis zum Ende vom Nodes Array
370 aCpyPam
.GetPoint()->nNode
.Assign( pAutoDoc
->GetNodes().GetEndOfContent(), -1 );
371 pCntntNd
= aCpyPam
.GetCntntNode();
372 aCpyPam
.GetPoint()->nContent
.Assign( pCntntNd
, pCntntNd
->Len() );
374 SwDontExpandItem aExpItem
;
375 aExpItem
.SaveDontExpandItems( *aPam
.GetPoint() );
377 pAutoDoc
->Copy( aCpyPam
, *aPam
.GetPoint(), false );
379 aExpItem
.RestoreDontExpandItems( *aPam
.GetPoint() );
384 pTxtNd
= pIdx
->GetNode().GetTxtNode();
392 if( bRet
&& ppPara
&& pTxtNd
)
393 *ppPara
= &pTxtNd
->GetTxt();
399 // wird nach dem austauschen der Zeichen von den Funktionen
402 // gerufen. Dann koennen die Worte ggfs. in die Ausnahmelisten
403 // aufgenommen werden.
404 void SwAutoCorrDoc::SaveCpltSttWord( ULONG nFlag
, xub_StrLen nPos
,
405 const String
& rExceptWord
,
408 ULONG nNode
= pIdx
? pIdx
->GetIndex() : rCrsr
.GetPoint()->nNode
.GetIndex();
409 LanguageType eLang
= GetLanguage(nPos
, FALSE
);
410 rEditSh
.GetDoc()->SetAutoCorrExceptWord( new SwAutoCorrExceptWord( nFlag
,
411 nNode
, nPos
, rExceptWord
, cChar
, eLang
));
414 LanguageType
SwAutoCorrDoc::GetLanguage( xub_StrLen nPos
, BOOL bPrevPara
) const
416 LanguageType eRet
= LANGUAGE_SYSTEM
;
418 SwTxtNode
* pNd
= (( bPrevPara
&& pIdx
)
420 : rCrsr
.GetPoint()->nNode
).GetNode().GetTxtNode();
423 eRet
= pNd
->GetLang( nPos
, 0 );
424 if(LANGUAGE_SYSTEM
== eRet
)
425 eRet
= (LanguageType
)GetAppLanguage();
429 void SwAutoCorrExceptWord::CheckChar( const SwPosition
& rPos
, sal_Unicode cChr
)
431 // nur testen ob es eine Verbesserung ist. Wenn ja, dann das Wort
432 // in die Ausnahmeliste aufnehmen.
433 if( cChar
== cChr
&& rPos
.nNode
.GetIndex() == nNode
&&
434 rPos
.nContent
.GetIndex() == nCntnt
)
436 // die akt. Autokorrektur besorgen:
437 SvxAutoCorrect
* pACorr
= SvxAutoCorrCfg::Get()->GetAutoCorrect();
439 // dann in die Liste aufnehmen:
440 if( CptlSttWrd
& nFlags
)
441 pACorr
->AddWrtSttException( sWord
, eLanguage
);
442 else if( CptlSttSntnc
& nFlags
)
443 pACorr
->AddCplSttException( sWord
, eLanguage
);
448 BOOL
SwAutoCorrExceptWord::CheckDelChar( const SwPosition
& rPos
)
451 if( !bDeleted
&& rPos
.nNode
.GetIndex() == nNode
&&
452 rPos
.nContent
.GetIndex() == nCntnt
)
453 bDeleted
= bRet
= TRUE
;
457 SwDontExpandItem::~SwDontExpandItem()
459 delete pDontExpItems
;
462 void SwDontExpandItem::SaveDontExpandItems( const SwPosition
& rPos
)
464 const SwTxtNode
* pTxtNd
= rPos
.nNode
.GetNode().GetTxtNode();
467 pDontExpItems
= new SfxItemSet( ((SwDoc
*)pTxtNd
->GetDoc())->GetAttrPool(),
469 xub_StrLen n
= rPos
.nContent
.GetIndex();
470 if( !pTxtNd
->GetAttr( *pDontExpItems
, n
, n
,
471 n
!= pTxtNd
->GetTxt().Len() ))
472 delete pDontExpItems
, pDontExpItems
= 0;
476 void SwDontExpandItem::RestoreDontExpandItems( const SwPosition
& rPos
)
478 SwTxtNode
* pTxtNd
= rPos
.nNode
.GetNode().GetTxtNode();
481 xub_StrLen nStart
= rPos
.nContent
.GetIndex();
482 if( nStart
== pTxtNd
->GetTxt().Len() )
483 pTxtNd
->FmtToTxtAttr( pTxtNd
);
485 if( pTxtNd
->GetpSwpHints() && pTxtNd
->GetpSwpHints()->Count() )
487 const USHORT nSize
= pTxtNd
->GetpSwpHints()->Count();
489 xub_StrLen nAttrStart
;
490 const xub_StrLen
* pAttrEnd
;
492 for( n
= 0; n
< nSize
; ++n
)
494 SwTxtAttr
* pHt
= pTxtNd
->GetpSwpHints()->GetTextHint( n
);
495 nAttrStart
= *pHt
->GetStart();
496 if( nAttrStart
> nStart
) // ueber den Bereich hinaus
499 if( 0 != ( pAttrEnd
= pHt
->GetEnd() ) &&
500 ( ( nAttrStart
< nStart
&&
501 ( pHt
->DontExpand() ? nStart
< *pAttrEnd
502 : nStart
<= *pAttrEnd
)) ||
503 ( nStart
== nAttrStart
&&
504 ( nAttrStart
== *pAttrEnd
|| !nStart
))) )
506 const SfxPoolItem
* pItem
;
507 if( !pDontExpItems
|| SFX_ITEM_SET
!= pDontExpItems
->
508 GetItemState( pHt
->Which(), FALSE
, &pItem
) ||
509 *pItem
!= pHt
->GetAttr() )
511 // das Attribut war vorher nicht in dieser Form im Absatz
512 // gesetzt, also kann es nur durchs einfuegen/kopieren erzeugt
513 // worden sein. Damit ist es ein Kandiadat fuers DontExpand
514 pHt
->SetDontExpand( TRUE
);