xref: /AOO41X/main/sw/source/core/edit/acorrect.cxx (revision 69a743679e823ad8f875be547552acb607b8ada5)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #define _STD_VAR_ARRAYS
29 #include <hintids.hxx>
30 
31 #include <svx/svxids.hrc>
32 #include <editeng/langitem.hxx>
33 #include <fmtinfmt.hxx>
34 #include <txtatr.hxx>
35 #include <txtinet.hxx>
36 #include <editsh.hxx>
37 #include <doc.hxx>
38 #include <pam.hxx>
39 #include <ndtxt.hxx>
40 #include <acorrect.hxx>
41 #include <shellio.hxx>
42 #include <swundo.hxx>
43 #include <viscrs.hxx>
44 
45 #include <editeng/acorrcfg.hxx>
46 
47 using namespace ::com::sun::star;
48 
49 
50 class _PaMIntoCrsrShellRing
51 {
52     SwCrsrShell& rSh;
53     SwPaM &rDelPam, &rCrsr;
54     Ring *pPrevDelPam, *pPrevCrsr;
55 
56     void RemoveFromRing( SwPaM& rPam, Ring* pPrev );
57 public:
58     _PaMIntoCrsrShellRing( SwCrsrShell& rSh, SwPaM& rCrsr, SwPaM& rPam );
59     ~_PaMIntoCrsrShellRing();
60 };
61 
_PaMIntoCrsrShellRing(SwCrsrShell & rCSh,SwPaM & rShCrsr,SwPaM & rPam)62 _PaMIntoCrsrShellRing::_PaMIntoCrsrShellRing( SwCrsrShell& rCSh,
63                                             SwPaM& rShCrsr, SwPaM& rPam )
64     : rSh( rCSh ), rDelPam( rPam ), rCrsr( rShCrsr )
65 {
66     SwPaM* pShCrsr = rSh._GetCrsr();
67 
68     pPrevDelPam = rDelPam.GetPrev();
69     pPrevCrsr = rCrsr.GetPrev();
70 
71     rDelPam.MoveRingTo( pShCrsr );
72     rCrsr.MoveRingTo( pShCrsr );
73 }
~_PaMIntoCrsrShellRing()74 _PaMIntoCrsrShellRing::~_PaMIntoCrsrShellRing()
75 {
76     // und den Pam wieder herausnehmen:
77     RemoveFromRing( rDelPam, pPrevDelPam );
78     RemoveFromRing( rCrsr, pPrevCrsr );
79 }
RemoveFromRing(SwPaM & rPam,Ring * pPrev)80 void _PaMIntoCrsrShellRing::RemoveFromRing( SwPaM& rPam, Ring* pPrev )
81 {
82     Ring *p, *pNext = (Ring*)&rPam;
83     do {
84         p = pNext;
85         pNext = p->GetNext();
86         p->MoveTo( &rPam );
87     } while( p != pPrev );
88 }
89 
90 
SwAutoCorrDoc(SwEditShell & rEditShell,SwPaM & rPam,sal_Unicode cIns)91 SwAutoCorrDoc::SwAutoCorrDoc( SwEditShell& rEditShell, SwPaM& rPam,
92                                 sal_Unicode cIns )
93     : rEditSh( rEditShell ), rCrsr( rPam ), pIdx( 0 )
94     , m_nEndUndoCounter(0)
95     , bUndoIdInitialized( cIns ? false : true )
96 {
97 }
98 
99 
~SwAutoCorrDoc()100 SwAutoCorrDoc::~SwAutoCorrDoc()
101 {
102     for (int i = 0; i < m_nEndUndoCounter; ++i)
103     {
104         rEditSh.EndUndo();
105     }
106     delete pIdx;
107 }
108 
DeleteSel(SwPaM & rDelPam)109 void SwAutoCorrDoc::DeleteSel( SwPaM& rDelPam )
110 {
111     SwDoc* pDoc = rEditSh.GetDoc();
112     if( pDoc->IsAutoFmtRedline() )
113     {
114         // damit der DelPam auch verschoben wird, in den Shell-Cursr-Ring
115         // mit aufnehmen !!
116         _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, rDelPam );
117         pDoc->DeleteAndJoin( rDelPam );
118     }
119     else
120     {
121         pDoc->DeleteRange( rDelPam );
122     }
123 }
124 
Delete(xub_StrLen nStt,xub_StrLen nEnd)125 sal_Bool SwAutoCorrDoc::Delete( xub_StrLen nStt, xub_StrLen nEnd )
126 {
127     const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode;
128     SwPaM aSel( rNd, nStt, rNd, nEnd );
129     DeleteSel( aSel );
130 
131     if( bUndoIdInitialized )
132         bUndoIdInitialized = true;
133     return sal_True;
134 }
135 
136 
Insert(xub_StrLen nPos,const String & rTxt)137 sal_Bool SwAutoCorrDoc::Insert( xub_StrLen nPos, const String& rTxt )
138 {
139     SwPaM aPam( rCrsr.GetPoint()->nNode.GetNode(), nPos );
140     rEditSh.GetDoc()->InsertString( aPam, rTxt );
141     if( !bUndoIdInitialized )
142     {
143         bUndoIdInitialized = true;
144         if( 1 == rTxt.Len() )
145         {
146             rEditSh.StartUndo( UNDO_AUTOCORRECT );
147             ++m_nEndUndoCounter;
148         }
149     }
150     return sal_True;
151 }
152 
153 
Replace(xub_StrLen nPos,const String & rTxt)154 sal_Bool SwAutoCorrDoc::Replace( xub_StrLen nPos, const String& rTxt )
155 {
156     return ReplaceRange( nPos, rTxt.Len(), rTxt );
157 }
ReplaceRange(xub_StrLen nPos,xub_StrLen nSourceLength,const String & rTxt)158 sal_Bool SwAutoCorrDoc::ReplaceRange( xub_StrLen nPos, xub_StrLen nSourceLength, const String& rTxt )
159 {
160     SwPaM* pPam = &rCrsr;
161     if( pPam->GetPoint()->nContent.GetIndex() != nPos )
162     {
163         pPam = new SwPaM( *rCrsr.GetPoint() );
164         pPam->GetPoint()->nContent = nPos;
165     }
166 
167     SwTxtNode * const pNd = pPam->GetNode()->GetTxtNode();
168     if ( !pNd )
169     {
170         return sal_False;
171     }
172 
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 )
177     {
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 ) )
181         {
182             bDoReplace = false;
183             break;
184         }
185     }
186 
187     if ( bDoReplace )
188     {
189         SwDoc* pDoc = rEditSh.GetDoc();
190 
191 //      if( !pDoc->IsAutoFmtRedline() &&
192 //          pPam != &rCrsr )    // nur an akt. Position das Redline sichern
193 //          pDoc->SetRedlineMode_intern( eOld | REDLINE_IGNORE );
194 
195         if( pDoc->IsAutoFmtRedline() )
196         {
197             if( nPos == pNd->GetTxt().Len() )       // am Ende erfolgt ein Insert
198             {
199                 pDoc->InsertString( *pPam, rTxt );
200             }
201             else
202             {
203                 _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, *pPam );
204 
205                 pPam->SetMark();
206                 pPam->GetPoint()->nContent = Min( pNd->GetTxt().Len(),
207                                               xub_StrLen( nPos + nSourceLength ));
208                 pDoc->ReplaceRange( *pPam, rTxt, false );
209                 pPam->Exchange();
210                 pPam->DeleteMark();
211             }
212         }
213         else
214         {
215             if( nSourceLength != rTxt.Len() )
216             {
217                 pPam->SetMark();
218                 pPam->GetPoint()->nContent = Min( pNd->GetTxt().Len(),
219                                               xub_StrLen( nPos + nSourceLength ));
220                 pDoc->ReplaceRange( *pPam, rTxt, false );
221                 pPam->Exchange();
222                 pPam->DeleteMark();
223             }
224             else
225                 pDoc->Overwrite( *pPam, rTxt );
226         }
227 
228 //      pDoc->SetRedlineMode_intern( eOld );
229         if( bUndoIdInitialized )
230         {
231             bUndoIdInitialized = true;
232             if( 1 == rTxt.Len() )
233             {
234                 rEditSh.StartUndo( UNDO_AUTOCORRECT );
235                 ++m_nEndUndoCounter;
236             }
237         }
238     }
239 
240     if( pPam != &rCrsr )
241         delete pPam;
242 
243     return sal_True;
244 }
245 
246 
247 
SetAttr(xub_StrLen nStt,xub_StrLen nEnd,sal_uInt16 nSlotId,SfxPoolItem & rItem)248 sal_Bool SwAutoCorrDoc::SetAttr( xub_StrLen nStt, xub_StrLen nEnd, sal_uInt16 nSlotId,
249                                         SfxPoolItem& rItem )
250 {
251     const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode;
252     SwPaM aPam( rNd, nStt, rNd, nEnd );
253 
254     SfxItemPool& rPool = rEditSh.GetDoc()->GetAttrPool();
255     sal_uInt16 nWhich = rPool.GetWhich( nSlotId, sal_False );
256     if( nWhich )
257     {
258         rItem.SetWhich( nWhich );
259 
260         SfxItemSet aSet( rPool, aCharFmtSetRange );
261         SetAllScriptItem( aSet, rItem );
262 
263         rEditSh.GetDoc()->SetFmtItemByAutoFmt( aPam, aSet );
264 
265         if( bUndoIdInitialized )
266             bUndoIdInitialized = true;
267     }
268     return 0 != nWhich;
269 }
270 
271 
272 
SetINetAttr(xub_StrLen nStt,xub_StrLen nEnd,const String & rURL)273 sal_Bool SwAutoCorrDoc::SetINetAttr( xub_StrLen nStt, xub_StrLen nEnd, const String& rURL )
274 {
275     const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode;
276     SwPaM aPam( rNd, nStt, rNd, nEnd );
277 
278     SfxItemSet aSet( rEditSh.GetDoc()->GetAttrPool(),
279                         RES_TXTATR_INETFMT, RES_TXTATR_INETFMT );
280     aSet.Put( SwFmtINetFmt( rURL, aEmptyStr ));
281     rEditSh.GetDoc()->SetFmtItemByAutoFmt( aPam, aSet );
282     if( bUndoIdInitialized )
283         bUndoIdInitialized = true;
284     return sal_True;
285 }
286 
287     // returne den Text eines vorherigen Absatzes.
288     // Dieser darf nicht leer sein!
289     // Gibt es diesen nicht oder gibt es davor nur Leere, dann returne 0
290     // Das Flag gibt an:
291     //      sal_True: den, vor der normalen Einfuegeposition (sal_True)
292     //      sal_False: den, in den das korrigierte Wort eingfuegt wurde.
293     //              (Muss nicht der gleiche Absatz sein!!!!)
GetPrevPara(sal_Bool bAtNormalPos)294 const String* SwAutoCorrDoc::GetPrevPara( sal_Bool bAtNormalPos )
295 {
296     const String* pStr = 0;
297 
298     if( bAtNormalPos || !pIdx )
299         pIdx = new SwNodeIndex( rCrsr.GetPoint()->nNode, -1 );
300     else
301         (*pIdx)--;
302 
303     SwTxtNode* pTNd = pIdx->GetNode().GetTxtNode();
304     while( pTNd && !pTNd->GetTxt().Len() )
305     {
306         (*pIdx)--;
307         pTNd = pIdx->GetNode().GetTxtNode();
308     }
309     //if( pTNd && NO_NUMBERING == pTNd->GetTxtColl()->GetOutlineLevel() )
310     if( pTNd && 0 == pTNd->GetAttrOutlineLevel() )//#outline level,zhaojianwei
311         pStr = &pTNd->GetTxt();
312 
313     if( bUndoIdInitialized )
314         bUndoIdInitialized = true;
315     return pStr;
316 }
317 
318 
ChgAutoCorrWord(xub_StrLen & rSttPos,xub_StrLen nEndPos,SvxAutoCorrect & rACorrect,const String ** ppPara)319 sal_Bool SwAutoCorrDoc::ChgAutoCorrWord( xub_StrLen & rSttPos, xub_StrLen nEndPos,
320                                             SvxAutoCorrect& rACorrect,
321                                             const String** ppPara )
322 {
323     if( bUndoIdInitialized )
324         bUndoIdInitialized = true;
325 
326     // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
327     // Kuerzel im Auto
328     SwTxtNode* pTxtNd = rCrsr.GetNode()->GetTxtNode();
329     ASSERT( pTxtNd, "wo ist denn der TextNode?" );
330 
331     sal_Bool bRet = sal_False;
332     if( nEndPos == rSttPos )
333         return bRet;
334 
335     LanguageType eLang = GetLanguage(nEndPos, sal_False);
336     if(LANGUAGE_SYSTEM == eLang)
337         eLang = (LanguageType)GetAppLanguage();
338 
339     //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte.
340     sal_Bool bLastCharIsPoint = nEndPos < pTxtNd->GetTxt().Len() &&
341                             '.' == pTxtNd->GetTxt().GetChar( nEndPos );
342 
343     const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList(
344                                 pTxtNd->GetTxt(), rSttPos, nEndPos, *this, eLang );
345     SwDoc* pDoc = rEditSh.GetDoc();
346     if( pFnd )
347     {
348         const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode;
349         SwPaM aPam( rNd, rSttPos, rNd, nEndPos );
350 
351         if( pFnd->IsTextOnly() )
352         {
353             //JP 22.04.99: Bug 63883 - Sonderbehandlung fuer Punkte.
354             if( !bLastCharIsPoint || !pFnd->GetLong().Len() ||
355                 '.' != pFnd->GetLong().GetChar( pFnd->GetLong().Len() - 1 ) )
356             {
357                 // replace the selection
358                 pDoc->ReplaceRange( aPam, pFnd->GetLong(), false);
359                 bRet = sal_True;
360             }
361         }
362         else
363         {
364             SwTextBlocks aTBlks( rACorrect.GetAutoCorrFileName( eLang, sal_False, sal_True ));
365             sal_uInt16 nPos = aTBlks.GetIndex( pFnd->GetShort() );
366             if( USHRT_MAX != nPos && aTBlks.BeginGetDoc( nPos ) )
367             {
368                 DeleteSel( aPam );
369                 pDoc->DontExpandFmt( *aPam.GetPoint() );
370 
371                 if( ppPara )
372                 {
373                     ASSERT( !pIdx, "wer hat seinen Index nicht geloescht?" );
374                     pIdx = new SwNodeIndex( rCrsr.GetPoint()->nNode, -1 );
375                 }
376 
377                 //
378                 SwDoc* pAutoDoc = aTBlks.GetDoc();
379                 SwNodeIndex aSttIdx( pAutoDoc->GetNodes().GetEndOfExtras(), 1 );
380                 SwCntntNode* pCntntNd = pAutoDoc->GetNodes().GoNext( &aSttIdx );
381                 SwPaM aCpyPam( aSttIdx );
382 
383                 const SwTableNode* pTblNd = pCntntNd->FindTableNode();
384                 if( pTblNd )
385                 {
386                     aCpyPam.GetPoint()->nContent.Assign( 0, 0 );
387                     aCpyPam.GetPoint()->nNode = *pTblNd;
388                 }
389                 aCpyPam.SetMark();
390 
391                 // dann bis zum Ende vom Nodes Array
392                 aCpyPam.GetPoint()->nNode.Assign( pAutoDoc->GetNodes().GetEndOfContent(), -1 );
393                 pCntntNd = aCpyPam.GetCntntNode();
394                 aCpyPam.GetPoint()->nContent.Assign( pCntntNd, pCntntNd->Len() );
395 
396                 SwDontExpandItem aExpItem;
397                 aExpItem.SaveDontExpandItems( *aPam.GetPoint() );
398 
399                 pAutoDoc->CopyRange( aCpyPam, *aPam.GetPoint(), false );
400 
401                 aExpItem.RestoreDontExpandItems( *aPam.GetPoint() );
402 
403                 if( ppPara )
404                 {
405                     (*pIdx)++;
406                     pTxtNd = pIdx->GetNode().GetTxtNode();
407                 }
408                 bRet = sal_True;
409             }
410             aTBlks.EndGetDoc();
411         }
412     }
413 
414     if( bRet && ppPara && pTxtNd )
415         *ppPara = &pTxtNd->GetTxt();
416 
417     return bRet;
418 }
419 
420 
421     // wird nach dem austauschen der Zeichen von den Funktionen
422     //  - FnCptlSttWrd
423     //  - FnCptlSttSntnc
424     // gerufen. Dann koennen die Worte ggfs. in die Ausnahmelisten
425     // aufgenommen werden.
SaveCpltSttWord(sal_uLong nFlag,xub_StrLen nPos,const String & rExceptWord,sal_Unicode cChar)426 void SwAutoCorrDoc::SaveCpltSttWord( sal_uLong nFlag, xub_StrLen nPos,
427                                             const String& rExceptWord,
428                                             sal_Unicode cChar )
429 {
430     sal_uLong nNode = pIdx ? pIdx->GetIndex() : rCrsr.GetPoint()->nNode.GetIndex();
431     LanguageType eLang = GetLanguage(nPos, sal_False);
432     rEditSh.GetDoc()->SetAutoCorrExceptWord( new SwAutoCorrExceptWord( nFlag,
433                                         nNode, nPos, rExceptWord, cChar, eLang ));
434 }
435 
GetLanguage(xub_StrLen nPos,sal_Bool bPrevPara) const436 LanguageType SwAutoCorrDoc::GetLanguage( xub_StrLen nPos, sal_Bool bPrevPara ) const
437 {
438     LanguageType eRet = LANGUAGE_SYSTEM;
439 
440     SwTxtNode* pNd = (( bPrevPara && pIdx )
441                             ? *pIdx
442                             : rCrsr.GetPoint()->nNode ).GetNode().GetTxtNode();
443 
444     if( pNd )
445         eRet = pNd->GetLang( nPos, 0 );
446     if(LANGUAGE_SYSTEM == eRet)
447         eRet = (LanguageType)GetAppLanguage();
448     return eRet;
449 }
450 
CheckChar(const SwPosition & rPos,sal_Unicode cChr)451 void SwAutoCorrExceptWord::CheckChar( const SwPosition& rPos, sal_Unicode cChr )
452 {
453     // nur testen ob es eine Verbesserung ist. Wenn ja, dann das Wort
454     // in die Ausnahmeliste aufnehmen.
455     if( cChar == cChr && rPos.nNode.GetIndex() == nNode &&
456         rPos.nContent.GetIndex() == nCntnt )
457     {
458         // die akt. Autokorrektur besorgen:
459         SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get()->GetAutoCorrect();
460 
461         // dann in die Liste aufnehmen:
462         if( CptlSttWrd & nFlags )
463             pACorr->AddWrtSttException( sWord, eLanguage );
464         else if( CptlSttSntnc & nFlags )
465             pACorr->AddCplSttException( sWord, eLanguage );
466     }
467 }
468 
469 
CheckDelChar(const SwPosition & rPos)470 sal_Bool SwAutoCorrExceptWord::CheckDelChar( const SwPosition& rPos )
471 {
472     sal_Bool bRet = sal_False;
473     if( !bDeleted && rPos.nNode.GetIndex() == nNode &&
474         rPos.nContent.GetIndex() == nCntnt )
475         bDeleted = bRet = sal_True;
476     return bRet;
477 }
478 
~SwDontExpandItem()479 SwDontExpandItem::~SwDontExpandItem()
480 {
481     delete pDontExpItems;
482 }
483 
SaveDontExpandItems(const SwPosition & rPos)484 void SwDontExpandItem::SaveDontExpandItems( const SwPosition& rPos )
485 {
486     const SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
487     if( pTxtNd )
488     {
489         pDontExpItems = new SfxItemSet( ((SwDoc*)pTxtNd->GetDoc())->GetAttrPool(),
490                                             aCharFmtSetRange );
491         xub_StrLen n = rPos.nContent.GetIndex();
492         if( !pTxtNd->GetAttr( *pDontExpItems, n, n,
493                                 n != pTxtNd->GetTxt().Len() ))
494             delete pDontExpItems, pDontExpItems = 0;
495     }
496 }
497 
RestoreDontExpandItems(const SwPosition & rPos)498 void SwDontExpandItem::RestoreDontExpandItems( const SwPosition& rPos )
499 {
500     SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
501     if( pTxtNd )
502     {
503         xub_StrLen nStart = rPos.nContent.GetIndex();
504         if( nStart == pTxtNd->GetTxt().Len() )
505             pTxtNd->FmtToTxtAttr( pTxtNd );
506 
507         if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() )
508         {
509             const sal_uInt16 nSize = pTxtNd->GetpSwpHints()->Count();
510             sal_uInt16 n;
511             xub_StrLen nAttrStart;
512             const xub_StrLen* pAttrEnd;
513 
514             for( n = 0; n < nSize; ++n )
515             {
516                 SwTxtAttr* pHt = pTxtNd->GetpSwpHints()->GetTextHint( n );
517                 nAttrStart = *pHt->GetStart();
518                 if( nAttrStart > nStart )       // ueber den Bereich hinaus
519                     break;
520 
521                 if( 0 != ( pAttrEnd = pHt->End() ) &&
522                     ( ( nAttrStart < nStart &&
523                         ( pHt->DontExpand() ? nStart < *pAttrEnd
524                                             : nStart <= *pAttrEnd )) ||
525                       ( nStart == nAttrStart &&
526                         ( nAttrStart == *pAttrEnd || !nStart ))) )
527                 {
528                     const SfxPoolItem* pItem;
529                     if( !pDontExpItems || SFX_ITEM_SET != pDontExpItems->
530                         GetItemState( pHt->Which(), sal_False, &pItem ) ||
531                         *pItem != pHt->GetAttr() )
532                     {
533                         // das Attribut war vorher nicht in dieser Form im Absatz
534                         // gesetzt, also kann es nur durchs einfuegen/kopieren erzeugt
535                         // worden sein. Damit ist es ein Kandiadat fuers DontExpand
536                         pHt->SetDontExpand( sal_True );
537                     }
538                 }
539             }
540         }
541     }
542 }
543 
544 
545