merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / edit / acorrect.cxx
blob29b3968c3403e4ede76df0bc9a1445716864c8a6
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 <editsh.hxx>
46 #include <doc.hxx>
47 #include <pam.hxx>
48 #include <ndtxt.hxx>
49 #include <acorrect.hxx>
50 #include <shellio.hxx>
51 #include <swundo.hxx>
52 #include <viscrs.hxx>
54 #include <svx/acorrcfg.hxx>
56 using namespace ::com::sun::star;
59 class _PaMIntoCrsrShellRing
61 SwCrsrShell& rSh;
62 SwPaM &rDelPam, &rCrsr;
63 Ring *pPrevDelPam, *pPrevCrsr;
65 void RemoveFromRing( SwPaM& rPam, Ring* pPrev );
66 public:
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;
92 do {
93 p = pNext;
94 pNext = p->GetNext();
95 p->MoveTo( &rPam );
96 } while( p != pPrev );
100 SwAutoCorrDoc::SwAutoCorrDoc( SwEditShell& rEditShell, SwPaM& rPam,
101 sal_Unicode cIns )
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 );
113 delete pIdx;
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
122 // mit aufnehmen !!
123 _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, rDelPam );
124 pDoc->DeleteAndJoin( rDelPam );
126 else
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 );
136 DeleteSel( aSel );
138 if( bUndoIdInitialized )
139 bUndoIdInitialized = true;
140 return 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 );
154 return TRUE;
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();
168 if ( !pNd )
170 return FALSE;
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 ) )
182 bDoReplace = false;
183 break;
187 if ( bDoReplace )
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 );
201 else
203 _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, *pPam );
205 pPam->SetMark();
206 pPam->GetPoint()->nContent = Min( pNd->GetTxt().Len(),
207 xub_StrLen( nPos + rTxt.Len() ));
208 pDoc->ReplaceRange( *pPam, rTxt, false );
209 pPam->Exchange();
210 pPam->DeleteMark();
213 else
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 );
225 if( pPam != &rCrsr )
226 delete pPam;
228 return TRUE;
233 BOOL SwAutoCorrDoc::SetAttr( xub_StrLen nStt, xub_StrLen nEnd, USHORT nSlotId,
234 SfxPoolItem& rItem )
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 );
241 if( nWhich )
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;
253 return 0 != nWhich;
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;
269 return 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
275 // Das Flag gibt an:
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 );
285 else
286 (*pIdx)--;
288 SwTxtNode* pTNd = pIdx->GetNode().GetTxtNode();
289 while( pTNd && !pTNd->GetTxt().Len() )
291 (*pIdx)--;
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;
300 return pStr;
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
312 // Kuerzel im Auto
313 SwTxtNode* pTxtNd = rCrsr.GetNode()->GetTxtNode();
314 ASSERT( pTxtNd, "wo ist denn der TextNode?" );
316 BOOL bRet = FALSE;
317 if( nEndPos == rSttPos )
318 return bRet;
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();
331 if( pFnd )
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);
344 bRet = TRUE;
347 else
349 SwTextBlocks aTBlks( rACorrect.GetAutoCorrFileName( eLang, FALSE, TRUE ));
350 USHORT nPos = aTBlks.GetIndex( pFnd->GetShort() );
351 if( USHRT_MAX != nPos && aTBlks.BeginGetDoc( nPos ) )
353 DeleteSel( aPam );
354 pDoc->DontExpandFmt( *aPam.GetPoint() );
356 if( ppPara )
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();
369 if( pTblNd )
371 aCpyPam.GetPoint()->nContent.Assign( 0, 0 );
372 aCpyPam.GetPoint()->nNode = *pTblNd;
374 aCpyPam.SetMark();
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() );
388 if( ppPara )
390 (*pIdx)++;
391 pTxtNd = pIdx->GetNode().GetTxtNode();
393 bRet = TRUE;
395 aTBlks.EndGetDoc();
399 if( bRet && ppPara && pTxtNd )
400 *ppPara = &pTxtNd->GetTxt();
402 return bRet;
406 // wird nach dem austauschen der Zeichen von den Funktionen
407 // - FnCptlSttWrd
408 // - FnCptlSttSntnc
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,
413 sal_Unicode cChar )
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 )
426 ? *pIdx
427 : rCrsr.GetPoint()->nNode ).GetNode().GetTxtNode();
429 if( pNd )
430 eRet = pNd->GetLang( nPos, 0 );
431 if(LANGUAGE_SYSTEM == eRet)
432 eRet = (LanguageType)GetAppLanguage();
433 return eRet;
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 )
457 BOOL bRet = FALSE;
458 if( !bDeleted && rPos.nNode.GetIndex() == nNode &&
459 rPos.nContent.GetIndex() == nCntnt )
460 bDeleted = bRet = TRUE;
461 return bRet;
464 SwDontExpandItem::~SwDontExpandItem()
466 delete pDontExpItems;
469 void SwDontExpandItem::SaveDontExpandItems( const SwPosition& rPos )
471 const SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
472 if( pTxtNd )
474 pDontExpItems = new SfxItemSet( ((SwDoc*)pTxtNd->GetDoc())->GetAttrPool(),
475 aCharFmtSetRange );
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();
486 if( pTxtNd )
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();
495 USHORT n;
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
504 break;
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 );