xref: /aoo41x/main/sw/source/core/edit/acorrect.cxx (revision 69a74367)
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