update dev300-m58
[ooovba.git] / sw / source / core / edit / acorrect.cxx
blobede1df3978e3f1196ed3065716b1022b6e5010ae
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: acorrect.cxx,v $
10 * $Revision: 1.17 $
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>
40 #endif
41 #include <svx/langitem.hxx>
42 #include <fmtinfmt.hxx>
43 #include <txtatr.hxx>
44 #include <txtinet.hxx>
45 #include <fmthbsh.hxx>
46 #include <editsh.hxx>
47 #include <doc.hxx>
48 #include <pam.hxx>
49 #include <ndtxt.hxx>
50 #include <acorrect.hxx>
51 #include <shellio.hxx>
52 #include <swundo.hxx>
53 #include <viscrs.hxx>
55 #include <svx/acorrcfg.hxx>
57 using namespace ::com::sun::star;
60 class _PaMIntoCrsrShellRing
62 SwCrsrShell& rSh;
63 SwPaM &rDelPam, &rCrsr;
64 Ring *pPrevDelPam, *pPrevCrsr;
66 void RemoveFromRing( SwPaM& rPam, Ring* pPrev );
67 public:
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;
93 do {
94 p = pNext;
95 pNext = p->GetNext();
96 p->MoveTo( &rPam );
97 } while( p != pPrev );
101 SwAutoCorrDoc::SwAutoCorrDoc( SwEditShell& rEditShell, SwPaM& rPam,
102 sal_Unicode cIns )
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 );
114 delete pIdx;
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
123 // mit aufnehmen !!
124 _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, rDelPam );
125 pDoc->DeleteAndJoin( rDelPam );
127 else
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 );
135 DeleteSel( aSel );
137 if( bUndoIdInitialized )
138 bUndoIdInitialized = true;
139 return 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 );
153 return TRUE;
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;
166 BOOL bChg = TRUE;
167 SwTxtNode* pNd = pPam->GetNode()->GetTxtNode();
168 if( pNd )
170 // TextAttribute ohne Ende duerfen nie ersetzt werden!
171 sal_Unicode cChr;
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 ) )
177 bChg = FALSE;
178 break;
182 if( bChg )
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 );
194 else
196 _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, *pPam );
198 pPam->SetMark();
199 pPam->GetPoint()->nContent = Min( pNd->GetTxt().Len(),
200 xub_StrLen( nPos + rTxt.Len() ));
201 pDoc->Replace( *pPam, rTxt, FALSE );
202 pPam->Exchange();
203 pPam->DeleteMark();
206 else
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 );
218 if( pPam != &rCrsr )
219 delete pPam;
221 return TRUE;
226 BOOL SwAutoCorrDoc::SetAttr( xub_StrLen nStt, xub_StrLen nEnd, USHORT nSlotId,
227 SfxPoolItem& rItem )
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 );
234 if( nWhich )
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;
246 return 0 != nWhich;
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;
262 return 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
268 // Das Flag gibt an:
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 );
278 else
279 (*pIdx)--;
281 SwTxtNode* pTNd = pIdx->GetNode().GetTxtNode();
282 while( pTNd && !pTNd->GetTxt().Len() )
284 (*pIdx)--;
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;
293 return pStr;
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
305 // Kuerzel im Auto
306 SwTxtNode* pTxtNd = rCrsr.GetNode()->GetTxtNode();
307 ASSERT( pTxtNd, "wo ist denn der TextNode?" );
309 BOOL bRet = FALSE;
310 if( nEndPos == rSttPos )
311 return bRet;
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();
324 if( pFnd )
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);
337 bRet = TRUE;
340 else
342 SwTextBlocks aTBlks( rACorrect.GetAutoCorrFileName( eLang, FALSE, TRUE ));
343 USHORT nPos = aTBlks.GetIndex( pFnd->GetShort() );
344 if( USHRT_MAX != nPos && aTBlks.BeginGetDoc( nPos ) )
346 DeleteSel( aPam );
347 pDoc->DontExpandFmt( *aPam.GetPoint() );
349 if( ppPara )
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();
362 if( pTblNd )
364 aCpyPam.GetPoint()->nContent.Assign( 0, 0 );
365 aCpyPam.GetPoint()->nNode = *pTblNd;
367 aCpyPam.SetMark();
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() );
381 if( ppPara )
383 (*pIdx)++;
384 pTxtNd = pIdx->GetNode().GetTxtNode();
386 bRet = TRUE;
388 aTBlks.EndGetDoc();
392 if( bRet && ppPara && pTxtNd )
393 *ppPara = &pTxtNd->GetTxt();
395 return bRet;
399 // wird nach dem austauschen der Zeichen von den Funktionen
400 // - FnCptlSttWrd
401 // - FnCptlSttSntnc
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,
406 sal_Unicode cChar )
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 )
419 ? *pIdx
420 : rCrsr.GetPoint()->nNode ).GetNode().GetTxtNode();
422 if( pNd )
423 eRet = pNd->GetLang( nPos, 0 );
424 if(LANGUAGE_SYSTEM == eRet)
425 eRet = (LanguageType)GetAppLanguage();
426 return eRet;
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 )
450 BOOL bRet = FALSE;
451 if( !bDeleted && rPos.nNode.GetIndex() == nNode &&
452 rPos.nContent.GetIndex() == nCntnt )
453 bDeleted = bRet = TRUE;
454 return bRet;
457 SwDontExpandItem::~SwDontExpandItem()
459 delete pDontExpItems;
462 void SwDontExpandItem::SaveDontExpandItems( const SwPosition& rPos )
464 const SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
465 if( pTxtNd )
467 pDontExpItems = new SfxItemSet( ((SwDoc*)pTxtNd->GetDoc())->GetAttrPool(),
468 aCharFmtSetRange );
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();
479 if( pTxtNd )
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();
488 USHORT n;
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
497 break;
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 );