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>
49 #include <acorrect.hxx>
50 #include <shellio.hxx>
54 #include <svx/acorrcfg.hxx>
56 using namespace ::com::sun::star
;
59 class _PaMIntoCrsrShellRing
62 SwPaM
&rDelPam
, &rCrsr
;
63 Ring
*pPrevDelPam
, *pPrevCrsr
;
65 void RemoveFromRing( SwPaM
& rPam
, Ring
* pPrev
);
67 _PaMIntoCrsrShellRing( SwCrsrShell
& rSh
, SwPaM
& rCrsr
, SwPaM
& rPam
);
68 ~_PaMIntoCrsrShellRing();
71 _PaMIntoCrsrShellRing::_PaMIntoCrsrShellRing( SwCrsrShell
& rCSh
,
72 SwPaM
& rShCrsr
, SwPaM
& rPam
)
73 : rSh( rCSh
), rDelPam( rPam
), rCrsr( rShCrsr
)
75 SwPaM
* pShCrsr
= rSh
._GetCrsr();
77 pPrevDelPam
= rDelPam
.GetPrev();
78 pPrevCrsr
= rCrsr
.GetPrev();
80 rDelPam
.MoveRingTo( pShCrsr
);
81 rCrsr
.MoveRingTo( pShCrsr
);
83 _PaMIntoCrsrShellRing::~_PaMIntoCrsrShellRing()
85 // und den Pam wieder herausnehmen:
86 RemoveFromRing( rDelPam
, pPrevDelPam
);
87 RemoveFromRing( rCrsr
, pPrevCrsr
);
89 void _PaMIntoCrsrShellRing::RemoveFromRing( SwPaM
& rPam
, Ring
* pPrev
)
91 Ring
*p
, *pNext
= (Ring
*)&rPam
;
96 } while( p
!= pPrev
);
100 SwAutoCorrDoc::SwAutoCorrDoc( SwEditShell
& rEditShell
, SwPaM
& rPam
,
102 : rEditSh( rEditShell
), rCrsr( rPam
), pIdx( 0 ),
103 nUndoId( UNDO_EMPTY
),
104 bUndoIdInitialized( cIns
? false : true )
109 SwAutoCorrDoc::~SwAutoCorrDoc()
111 if( UNDO_EMPTY
!= nUndoId
)
112 rEditSh
.EndUndo( nUndoId
);
116 void SwAutoCorrDoc::DeleteSel( SwPaM
& rDelPam
)
118 SwDoc
* pDoc
= rEditSh
.GetDoc();
119 if( pDoc
->IsAutoFmtRedline() )
121 // damit der DelPam auch verschoben wird, in den Shell-Cursr-Ring
123 _PaMIntoCrsrShellRing
aTmp( rEditSh
, rCrsr
, rDelPam
);
124 pDoc
->DeleteAndJoin( rDelPam
);
128 pDoc
->DeleteRange( rDelPam
);
132 BOOL
SwAutoCorrDoc::Delete( xub_StrLen nStt
, xub_StrLen nEnd
)
134 const SwNodeIndex
& rNd
= rCrsr
.GetPoint()->nNode
;
135 SwPaM
aSel( rNd
, nStt
, rNd
, nEnd
);
138 if( bUndoIdInitialized
)
139 bUndoIdInitialized
= true;
144 BOOL
SwAutoCorrDoc::Insert( xub_StrLen nPos
, const String
& rTxt
)
146 SwPaM
aPam( rCrsr
.GetPoint()->nNode
.GetNode(), nPos
);
147 rEditSh
.GetDoc()->InsertString( aPam
, rTxt
);
148 if( !bUndoIdInitialized
)
150 bUndoIdInitialized
= true;
151 if( 1 == rTxt
.Len() )
152 rEditSh
.StartUndo( nUndoId
= UNDO_AUTOCORRECT
);
158 BOOL
SwAutoCorrDoc::Replace( xub_StrLen nPos
, const String
& rTxt
)
160 SwPaM
* pPam
= &rCrsr
;
161 if( pPam
->GetPoint()->nContent
.GetIndex() != nPos
)
163 pPam
= new SwPaM( *rCrsr
.GetPoint() );
164 pPam
->GetPoint()->nContent
= nPos
;
167 SwTxtNode
* const pNd
= pPam
->GetNode()->GetTxtNode();
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
)
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
) )
189 SwDoc
* pDoc
= rEditSh
.GetDoc();
191 // if( !pDoc->IsAutoFmtRedline() &&
192 // pPam != &rCrsr ) // nur an akt. Position das Redline sichern
193 // pDoc->SetRedlineMode_intern( eOld | REDLINE_IGNORE );
195 if( pDoc
->IsAutoFmtRedline() )
197 if( nPos
== pNd
->GetTxt().Len() ) // am Ende erfolgt ein Insert
199 pDoc
->InsertString( *pPam
, rTxt
);
203 _PaMIntoCrsrShellRing
aTmp( rEditSh
, rCrsr
, *pPam
);
206 pPam
->GetPoint()->nContent
= Min( pNd
->GetTxt().Len(),
207 xub_StrLen( nPos
+ rTxt
.Len() ));
208 pDoc
->ReplaceRange( *pPam
, rTxt
, false );
214 pDoc
->Overwrite( *pPam
, rTxt
);
216 // pDoc->SetRedlineMode_intern( eOld );
217 if( bUndoIdInitialized
)
219 bUndoIdInitialized
= true;
220 if( 1 == rTxt
.Len() )
221 rEditSh
.StartUndo( nUndoId
= UNDO_AUTOCORRECT
);
233 BOOL
SwAutoCorrDoc::SetAttr( xub_StrLen nStt
, xub_StrLen nEnd
, USHORT nSlotId
,
236 const SwNodeIndex
& rNd
= rCrsr
.GetPoint()->nNode
;
237 SwPaM
aPam( rNd
, nStt
, rNd
, nEnd
);
239 SfxItemPool
& rPool
= rEditSh
.GetDoc()->GetAttrPool();
240 USHORT nWhich
= rPool
.GetWhich( nSlotId
, FALSE
);
243 rItem
.SetWhich( nWhich
);
245 SfxItemSet
aSet( rPool
, aCharFmtSetRange
);
246 SetAllScriptItem( aSet
, rItem
);
248 rEditSh
.GetDoc()->SetFmtItemByAutoFmt( aPam
, aSet
);
250 if( bUndoIdInitialized
)
251 bUndoIdInitialized
= true;
258 BOOL
SwAutoCorrDoc::SetINetAttr( xub_StrLen nStt
, xub_StrLen nEnd
, const String
& rURL
)
260 const SwNodeIndex
& rNd
= rCrsr
.GetPoint()->nNode
;
261 SwPaM
aPam( rNd
, nStt
, rNd
, nEnd
);
263 SfxItemSet
aSet( rEditSh
.GetDoc()->GetAttrPool(),
264 RES_TXTATR_INETFMT
, RES_TXTATR_INETFMT
);
265 aSet
.Put( SwFmtINetFmt( rURL
, aEmptyStr
));
266 rEditSh
.GetDoc()->SetFmtItemByAutoFmt( aPam
, aSet
);
267 if( bUndoIdInitialized
)
268 bUndoIdInitialized
= true;
272 // returne den Text eines vorherigen Absatzes.
273 // Dieser darf nicht leer sein!
274 // Gibt es diesen nicht oder gibt es davor nur Leere, dann returne 0
276 // TRUE: den, vor der normalen Einfuegeposition (TRUE)
277 // FALSE: den, in den das korrigierte Wort eingfuegt wurde.
278 // (Muss nicht der gleiche Absatz sein!!!!)
279 const String
* SwAutoCorrDoc::GetPrevPara( BOOL bAtNormalPos
)
281 const String
* pStr
= 0;
283 if( bAtNormalPos
|| !pIdx
)
284 pIdx
= new SwNodeIndex( rCrsr
.GetPoint()->nNode
, -1 );
288 SwTxtNode
* pTNd
= pIdx
->GetNode().GetTxtNode();
289 while( pTNd
&& !pTNd
->GetTxt().Len() )
292 pTNd
= pIdx
->GetNode().GetTxtNode();
294 //if( pTNd && NO_NUMBERING == pTNd->GetTxtColl()->GetOutlineLevel() )
295 if( pTNd
&& 0 == pTNd
->GetAttrOutlineLevel() )//#outline level,zhaojianwei
296 pStr
= &pTNd
->GetTxt();
298 if( bUndoIdInitialized
)
299 bUndoIdInitialized
= true;
304 BOOL
SwAutoCorrDoc::ChgAutoCorrWord( xub_StrLen
& rSttPos
, xub_StrLen nEndPos
,
305 SvxAutoCorrect
& rACorrect
,
306 const String
** ppPara
)
308 if( bUndoIdInitialized
)
309 bUndoIdInitialized
= true;
311 // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
313 SwTxtNode
* pTxtNd
= rCrsr
.GetNode()->GetTxtNode();
314 ASSERT( pTxtNd
, "wo ist denn der TextNode?" );
317 if( nEndPos
== rSttPos
)
320 LanguageType eLang
= GetLanguage(nEndPos
, FALSE
);
321 if(LANGUAGE_SYSTEM
== eLang
)
322 eLang
= (LanguageType
)GetAppLanguage();
324 //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte.
325 BOOL bLastCharIsPoint
= nEndPos
< pTxtNd
->GetTxt().Len() &&
326 '.' == pTxtNd
->GetTxt().GetChar( nEndPos
);
328 const SvxAutocorrWord
* pFnd
= rACorrect
.SearchWordsInList(
329 pTxtNd
->GetTxt(), rSttPos
, nEndPos
, *this, eLang
);
330 SwDoc
* pDoc
= rEditSh
.GetDoc();
333 const SwNodeIndex
& rNd
= rCrsr
.GetPoint()->nNode
;
334 SwPaM
aPam( rNd
, rSttPos
, rNd
, nEndPos
);
336 if( pFnd
->IsTextOnly() )
338 //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte.
339 if( !bLastCharIsPoint
|| !pFnd
->GetLong().Len() ||
340 '.' != pFnd
->GetLong().GetChar( pFnd
->GetLong().Len() - 1 ) )
342 // replace the selection
343 pDoc
->ReplaceRange( aPam
, pFnd
->GetLong(), false);
349 SwTextBlocks
aTBlks( rACorrect
.GetAutoCorrFileName( eLang
, FALSE
, TRUE
));
350 USHORT nPos
= aTBlks
.GetIndex( pFnd
->GetShort() );
351 if( USHRT_MAX
!= nPos
&& aTBlks
.BeginGetDoc( nPos
) )
354 pDoc
->DontExpandFmt( *aPam
.GetPoint() );
358 ASSERT( !pIdx
, "wer hat seinen Index nicht geloescht?" );
359 pIdx
= new SwNodeIndex( rCrsr
.GetPoint()->nNode
, -1 );
363 SwDoc
* pAutoDoc
= aTBlks
.GetDoc();
364 SwNodeIndex
aSttIdx( pAutoDoc
->GetNodes().GetEndOfExtras(), 1 );
365 SwCntntNode
* pCntntNd
= pAutoDoc
->GetNodes().GoNext( &aSttIdx
);
366 SwPaM
aCpyPam( aSttIdx
);
368 const SwTableNode
* pTblNd
= pCntntNd
->FindTableNode();
371 aCpyPam
.GetPoint()->nContent
.Assign( 0, 0 );
372 aCpyPam
.GetPoint()->nNode
= *pTblNd
;
376 // dann bis zum Ende vom Nodes Array
377 aCpyPam
.GetPoint()->nNode
.Assign( pAutoDoc
->GetNodes().GetEndOfContent(), -1 );
378 pCntntNd
= aCpyPam
.GetCntntNode();
379 aCpyPam
.GetPoint()->nContent
.Assign( pCntntNd
, pCntntNd
->Len() );
381 SwDontExpandItem aExpItem
;
382 aExpItem
.SaveDontExpandItems( *aPam
.GetPoint() );
384 pAutoDoc
->CopyRange( aCpyPam
, *aPam
.GetPoint(), false );
386 aExpItem
.RestoreDontExpandItems( *aPam
.GetPoint() );
391 pTxtNd
= pIdx
->GetNode().GetTxtNode();
399 if( bRet
&& ppPara
&& pTxtNd
)
400 *ppPara
= &pTxtNd
->GetTxt();
406 // wird nach dem austauschen der Zeichen von den Funktionen
409 // gerufen. Dann koennen die Worte ggfs. in die Ausnahmelisten
410 // aufgenommen werden.
411 void SwAutoCorrDoc::SaveCpltSttWord( ULONG nFlag
, xub_StrLen nPos
,
412 const String
& rExceptWord
,
415 ULONG nNode
= pIdx
? pIdx
->GetIndex() : rCrsr
.GetPoint()->nNode
.GetIndex();
416 LanguageType eLang
= GetLanguage(nPos
, FALSE
);
417 rEditSh
.GetDoc()->SetAutoCorrExceptWord( new SwAutoCorrExceptWord( nFlag
,
418 nNode
, nPos
, rExceptWord
, cChar
, eLang
));
421 LanguageType
SwAutoCorrDoc::GetLanguage( xub_StrLen nPos
, BOOL bPrevPara
) const
423 LanguageType eRet
= LANGUAGE_SYSTEM
;
425 SwTxtNode
* pNd
= (( bPrevPara
&& pIdx
)
427 : rCrsr
.GetPoint()->nNode
).GetNode().GetTxtNode();
430 eRet
= pNd
->GetLang( nPos
, 0 );
431 if(LANGUAGE_SYSTEM
== eRet
)
432 eRet
= (LanguageType
)GetAppLanguage();
436 void SwAutoCorrExceptWord::CheckChar( const SwPosition
& rPos
, sal_Unicode cChr
)
438 // nur testen ob es eine Verbesserung ist. Wenn ja, dann das Wort
439 // in die Ausnahmeliste aufnehmen.
440 if( cChar
== cChr
&& rPos
.nNode
.GetIndex() == nNode
&&
441 rPos
.nContent
.GetIndex() == nCntnt
)
443 // die akt. Autokorrektur besorgen:
444 SvxAutoCorrect
* pACorr
= SvxAutoCorrCfg::Get()->GetAutoCorrect();
446 // dann in die Liste aufnehmen:
447 if( CptlSttWrd
& nFlags
)
448 pACorr
->AddWrtSttException( sWord
, eLanguage
);
449 else if( CptlSttSntnc
& nFlags
)
450 pACorr
->AddCplSttException( sWord
, eLanguage
);
455 BOOL
SwAutoCorrExceptWord::CheckDelChar( const SwPosition
& rPos
)
458 if( !bDeleted
&& rPos
.nNode
.GetIndex() == nNode
&&
459 rPos
.nContent
.GetIndex() == nCntnt
)
460 bDeleted
= bRet
= TRUE
;
464 SwDontExpandItem::~SwDontExpandItem()
466 delete pDontExpItems
;
469 void SwDontExpandItem::SaveDontExpandItems( const SwPosition
& rPos
)
471 const SwTxtNode
* pTxtNd
= rPos
.nNode
.GetNode().GetTxtNode();
474 pDontExpItems
= new SfxItemSet( ((SwDoc
*)pTxtNd
->GetDoc())->GetAttrPool(),
476 xub_StrLen n
= rPos
.nContent
.GetIndex();
477 if( !pTxtNd
->GetAttr( *pDontExpItems
, n
, n
,
478 n
!= pTxtNd
->GetTxt().Len() ))
479 delete pDontExpItems
, pDontExpItems
= 0;
483 void SwDontExpandItem::RestoreDontExpandItems( const SwPosition
& rPos
)
485 SwTxtNode
* pTxtNd
= rPos
.nNode
.GetNode().GetTxtNode();
488 xub_StrLen nStart
= rPos
.nContent
.GetIndex();
489 if( nStart
== pTxtNd
->GetTxt().Len() )
490 pTxtNd
->FmtToTxtAttr( pTxtNd
);
492 if( pTxtNd
->GetpSwpHints() && pTxtNd
->GetpSwpHints()->Count() )
494 const USHORT nSize
= pTxtNd
->GetpSwpHints()->Count();
496 xub_StrLen nAttrStart
;
497 const xub_StrLen
* pAttrEnd
;
499 for( n
= 0; n
< nSize
; ++n
)
501 SwTxtAttr
* pHt
= pTxtNd
->GetpSwpHints()->GetTextHint( n
);
502 nAttrStart
= *pHt
->GetStart();
503 if( nAttrStart
> nStart
) // ueber den Bereich hinaus
506 if( 0 != ( pAttrEnd
= pHt
->GetEnd() ) &&
507 ( ( nAttrStart
< nStart
&&
508 ( pHt
->DontExpand() ? nStart
< *pAttrEnd
509 : nStart
<= *pAttrEnd
)) ||
510 ( nStart
== nAttrStart
&&
511 ( nAttrStart
== *pAttrEnd
|| !nStart
))) )
513 const SfxPoolItem
* pItem
;
514 if( !pDontExpItems
|| SFX_ITEM_SET
!= pDontExpItems
->
515 GetItemState( pHt
->Which(), FALSE
, &pItem
) ||
516 *pItem
!= pHt
->GetAttr() )
518 // das Attribut war vorher nicht in dieser Form im Absatz
519 // gesetzt, also kann es nur durchs einfuegen/kopieren erzeugt
520 // worden sein. Damit ist es ein Kandiadat fuers DontExpand
521 pHt
->SetDontExpand( TRUE
);