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