Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <hintids.hxx>
21 :
22 : #include <svx/svxids.hrc>
23 : #include <editeng/langitem.hxx>
24 : #include <fmtinfmt.hxx>
25 : #include <txtatr.hxx>
26 : #include <txtinet.hxx>
27 : #include <editsh.hxx>
28 : #include <doc.hxx>
29 : #include <pam.hxx>
30 : #include <ndtxt.hxx>
31 : #include <acorrect.hxx>
32 : #include <shellio.hxx>
33 : #include <swundo.hxx>
34 : #include <viscrs.hxx>
35 :
36 : #include <editeng/acorrcfg.hxx>
37 :
38 : using namespace ::com::sun::star;
39 :
40 : class _PaMIntoCrsrShellRing
41 : {
42 : SwCrsrShell& rSh;
43 : SwPaM &rDelPam, &rCrsr;
44 : Ring *pPrevDelPam, *pPrevCrsr;
45 :
46 : void RemoveFromRing( SwPaM& rPam, Ring* pPrev );
47 : public:
48 : _PaMIntoCrsrShellRing( SwCrsrShell& rSh, SwPaM& rCrsr, SwPaM& rPam );
49 : ~_PaMIntoCrsrShellRing();
50 : };
51 :
52 0 : _PaMIntoCrsrShellRing::_PaMIntoCrsrShellRing( SwCrsrShell& rCSh,
53 : SwPaM& rShCrsr, SwPaM& rPam )
54 0 : : rSh( rCSh ), rDelPam( rPam ), rCrsr( rShCrsr )
55 : {
56 0 : SwPaM* pShCrsr = rSh._GetCrsr();
57 :
58 0 : pPrevDelPam = rDelPam.GetPrev();
59 0 : pPrevCrsr = rCrsr.GetPrev();
60 :
61 0 : rDelPam.MoveRingTo( pShCrsr );
62 0 : rCrsr.MoveRingTo( pShCrsr );
63 0 : }
64 :
65 0 : _PaMIntoCrsrShellRing::~_PaMIntoCrsrShellRing()
66 : {
67 : // and take out the Pam again:
68 0 : RemoveFromRing( rDelPam, pPrevDelPam );
69 0 : RemoveFromRing( rCrsr, pPrevCrsr );
70 0 : }
71 :
72 0 : void _PaMIntoCrsrShellRing::RemoveFromRing( SwPaM& rPam, Ring* pPrev )
73 : {
74 0 : Ring *p, *pNext = (Ring*)&rPam;
75 0 : do {
76 0 : p = pNext;
77 0 : pNext = p->GetNext();
78 0 : p->MoveTo( &rPam );
79 : } while( p != pPrev );
80 0 : }
81 :
82 0 : SwAutoCorrDoc::SwAutoCorrDoc( SwEditShell& rEditShell, SwPaM& rPam,
83 : sal_Unicode cIns )
84 : : rEditSh( rEditShell ), rCrsr( rPam ), pIdx( 0 )
85 : , m_nEndUndoCounter(0)
86 0 : , bUndoIdInitialized( cIns ? false : true )
87 : {
88 0 : }
89 :
90 0 : SwAutoCorrDoc::~SwAutoCorrDoc()
91 : {
92 0 : for (int i = 0; i < m_nEndUndoCounter; ++i)
93 : {
94 0 : rEditSh.EndUndo();
95 : }
96 0 : delete pIdx;
97 0 : }
98 :
99 0 : void SwAutoCorrDoc::DeleteSel( SwPaM& rDelPam )
100 : {
101 0 : SwDoc* pDoc = rEditSh.GetDoc();
102 0 : if( pDoc->IsAutoFmtRedline() )
103 : {
104 : // so that also the DelPam be moved, include it in the
105 : // Shell-Cursr-Ring !!
106 0 : _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, rDelPam );
107 0 : pDoc->DeleteAndJoin( rDelPam );
108 : }
109 : else
110 : {
111 0 : pDoc->DeleteRange( rDelPam );
112 : }
113 0 : }
114 :
115 0 : bool SwAutoCorrDoc::Delete( sal_Int32 nStt, sal_Int32 nEnd )
116 : {
117 0 : const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode;
118 0 : SwPaM aSel( rNd, nStt, rNd, nEnd );
119 0 : DeleteSel( aSel );
120 :
121 0 : if( bUndoIdInitialized )
122 0 : bUndoIdInitialized = true;
123 0 : return true;
124 : }
125 :
126 0 : bool SwAutoCorrDoc::Insert( sal_Int32 nPos, const OUString& rTxt )
127 : {
128 0 : SwPaM aPam( rCrsr.GetPoint()->nNode.GetNode(), nPos );
129 0 : rEditSh.GetDoc()->InsertString( aPam, rTxt );
130 0 : if( !bUndoIdInitialized )
131 : {
132 0 : bUndoIdInitialized = true;
133 0 : if( 1 == rTxt.getLength() )
134 : {
135 0 : rEditSh.StartUndo( UNDO_AUTOCORRECT );
136 0 : ++m_nEndUndoCounter;
137 : }
138 : }
139 0 : return true;
140 : }
141 :
142 0 : bool SwAutoCorrDoc::Replace( sal_Int32 nPos, const OUString& rTxt )
143 : {
144 0 : return ReplaceRange( nPos, rTxt.getLength(), rTxt );
145 : }
146 :
147 0 : bool SwAutoCorrDoc::ReplaceRange( sal_Int32 nPos, sal_Int32 nSourceLength, const OUString& rTxt )
148 : {
149 0 : SwPaM* pPam = &rCrsr;
150 0 : if( pPam->GetPoint()->nContent.GetIndex() != nPos )
151 : {
152 0 : pPam = new SwPaM( *rCrsr.GetPoint() );
153 0 : pPam->GetPoint()->nContent = nPos;
154 : }
155 :
156 0 : SwTxtNode * const pNd = pPam->GetNode()->GetTxtNode();
157 0 : if ( !pNd )
158 : {
159 0 : return false;
160 : }
161 :
162 : // text attributes with dummy characters must not be replaced!
163 0 : bool bDoReplace = true;
164 0 : sal_Int32 const nLen = rTxt.getLength();
165 0 : for ( sal_Int32 n = 0; n < nLen; ++n )
166 : {
167 0 : sal_Unicode const Char = pNd->GetTxt()[n + nPos];
168 0 : if ( ( CH_TXTATR_BREAKWORD == Char || CH_TXTATR_INWORD == Char )
169 0 : && pNd->GetTxtAttrForCharAt( n + nPos ) )
170 : {
171 0 : bDoReplace = false;
172 0 : break;
173 : }
174 : }
175 :
176 0 : if ( bDoReplace )
177 : {
178 0 : SwDoc* pDoc = rEditSh.GetDoc();
179 :
180 0 : if( pDoc->IsAutoFmtRedline() )
181 : {
182 0 : if (nPos == pNd->GetTxt().getLength()) // at the End do an Insert
183 : {
184 0 : pDoc->InsertString( *pPam, rTxt );
185 : }
186 : else
187 : {
188 0 : _PaMIntoCrsrShellRing aTmp( rEditSh, rCrsr, *pPam );
189 :
190 0 : pPam->SetMark();
191 0 : pPam->GetPoint()->nContent = std::min<sal_Int32>(
192 0 : pNd->GetTxt().getLength(), nPos + nSourceLength);
193 0 : pDoc->ReplaceRange( *pPam, rTxt, false );
194 0 : pPam->Exchange();
195 0 : pPam->DeleteMark();
196 : }
197 : }
198 : else
199 : {
200 0 : if( nSourceLength != rTxt.getLength() )
201 : {
202 0 : pPam->SetMark();
203 0 : pPam->GetPoint()->nContent = std::min<sal_Int32>(
204 0 : pNd->GetTxt().getLength(), nPos + nSourceLength);
205 0 : pDoc->ReplaceRange( *pPam, rTxt, false );
206 0 : pPam->Exchange();
207 0 : pPam->DeleteMark();
208 : }
209 : else
210 0 : pDoc->Overwrite( *pPam, rTxt );
211 : }
212 :
213 0 : if( bUndoIdInitialized )
214 : {
215 0 : bUndoIdInitialized = true;
216 0 : if( 1 == rTxt.getLength() )
217 : {
218 0 : rEditSh.StartUndo( UNDO_AUTOCORRECT );
219 0 : ++m_nEndUndoCounter;
220 : }
221 : }
222 : }
223 :
224 0 : if( pPam != &rCrsr )
225 0 : delete pPam;
226 :
227 0 : return true;
228 : }
229 :
230 0 : bool SwAutoCorrDoc::SetAttr( sal_Int32 nStt, sal_Int32 nEnd, sal_uInt16 nSlotId,
231 : SfxPoolItem& rItem )
232 : {
233 0 : const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode;
234 0 : SwPaM aPam( rNd, nStt, rNd, nEnd );
235 :
236 0 : SfxItemPool& rPool = rEditSh.GetDoc()->GetAttrPool();
237 0 : sal_uInt16 nWhich = rPool.GetWhich( nSlotId, false );
238 0 : if( nWhich )
239 : {
240 0 : rItem.SetWhich( nWhich );
241 :
242 0 : SfxItemSet aSet( rPool, aCharFmtSetRange );
243 0 : SetAllScriptItem( aSet, rItem );
244 :
245 0 : rEditSh.GetDoc()->SetFmtItemByAutoFmt( aPam, aSet );
246 :
247 0 : if( bUndoIdInitialized )
248 0 : bUndoIdInitialized = true;
249 : }
250 0 : return 0 != nWhich;
251 : }
252 :
253 0 : bool SwAutoCorrDoc::SetINetAttr( sal_Int32 nStt, sal_Int32 nEnd, const OUString& rURL )
254 : {
255 0 : const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode;
256 0 : SwPaM aPam( rNd, nStt, rNd, nEnd );
257 :
258 0 : SfxItemSet aSet( rEditSh.GetDoc()->GetAttrPool(),
259 0 : RES_TXTATR_INETFMT, RES_TXTATR_INETFMT );
260 0 : aSet.Put( SwFmtINetFmt( rURL, OUString() ));
261 0 : rEditSh.GetDoc()->SetFmtItemByAutoFmt( aPam, aSet );
262 0 : if( bUndoIdInitialized )
263 0 : bUndoIdInitialized = true;
264 0 : return true;
265 : }
266 :
267 : /** Return the text of a previous paragraph
268 : *
269 : * @param bAtNormalPos If <true> before the normal insert position; if <false> in which the
270 : * corrected word was inserted. (Doesn't need to be the same paragraph!)
271 : * @return text or 0, if previous paragraph does not exists or there are only blankness
272 : */
273 0 : OUString const* SwAutoCorrDoc::GetPrevPara(bool const bAtNormalPos)
274 : {
275 0 : OUString const* pStr(0);
276 :
277 0 : if( bAtNormalPos || !pIdx )
278 0 : pIdx = new SwNodeIndex( rCrsr.GetPoint()->nNode, -1 );
279 : else
280 0 : (*pIdx)--;
281 :
282 0 : SwTxtNode* pTNd = pIdx->GetNode().GetTxtNode();
283 0 : while (pTNd && !pTNd->GetTxt().getLength())
284 : {
285 0 : (*pIdx)--;
286 0 : pTNd = pIdx->GetNode().GetTxtNode();
287 : }
288 0 : if( pTNd && 0 == pTNd->GetAttrOutlineLevel() )
289 0 : pStr = & pTNd->GetTxt();
290 :
291 0 : if( bUndoIdInitialized )
292 0 : bUndoIdInitialized = true;
293 :
294 0 : return pStr;
295 : }
296 :
297 0 : bool SwAutoCorrDoc::ChgAutoCorrWord( sal_Int32& rSttPos, sal_Int32 nEndPos,
298 : SvxAutoCorrect& rACorrect,
299 : OUString* pPara )
300 : {
301 0 : if( bUndoIdInitialized )
302 0 : bUndoIdInitialized = true;
303 :
304 : // Found a beginning of a paragraph or a Blank,
305 : // search for the word Kuerzel (Shortcut) in the Auto
306 0 : SwTxtNode* pTxtNd = rCrsr.GetNode()->GetTxtNode();
307 : OSL_ENSURE( pTxtNd, "where is the TextNode?" );
308 :
309 0 : sal_Bool bRet = sal_False;
310 0 : if( nEndPos == rSttPos )
311 0 : return bRet;
312 :
313 0 : LanguageType eLang = GetLanguage(nEndPos, false);
314 0 : if(LANGUAGE_SYSTEM == eLang)
315 0 : eLang = GetAppLanguage();
316 0 : LanguageTag aLanguageTag( eLang);
317 :
318 : //JP 22.04.99: Bug 63883 - Special treatment for dots.
319 0 : bool bLastCharIsPoint = nEndPos < pTxtNd->GetTxt().getLength() &&
320 0 : ('.' == pTxtNd->GetTxt()[nEndPos]);
321 :
322 : const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList(
323 0 : pTxtNd->GetTxt(), rSttPos, nEndPos, *this, aLanguageTag );
324 0 : SwDoc* pDoc = rEditSh.GetDoc();
325 0 : if( pFnd )
326 : {
327 0 : const SwNodeIndex& rNd = rCrsr.GetPoint()->nNode;
328 0 : SwPaM aPam( rNd, rSttPos, rNd, nEndPos );
329 :
330 0 : if( pFnd->IsTextOnly() )
331 : {
332 : //JP 22.04.99: Bug 63883 - Special treatment for dots.
333 0 : if( !bLastCharIsPoint || pFnd->GetLong().isEmpty() ||
334 0 : '.' != pFnd->GetLong()[ pFnd->GetLong().getLength() - 1 ] )
335 : {
336 : // replace the selection
337 0 : pDoc->ReplaceRange( aPam, pFnd->GetLong(), false);
338 0 : bRet = sal_True;
339 : }
340 : }
341 : else
342 : {
343 0 : SwTextBlocks aTBlks( rACorrect.GetAutoCorrFileName( aLanguageTag, false, true ));
344 0 : sal_uInt16 nPos = aTBlks.GetIndex( pFnd->GetShort() );
345 0 : if( USHRT_MAX != nPos && aTBlks.BeginGetDoc( nPos ) )
346 : {
347 0 : DeleteSel( aPam );
348 0 : pDoc->DontExpandFmt( *aPam.GetPoint() );
349 :
350 0 : if( pPara )
351 : {
352 : OSL_ENSURE( !pIdx, "who has not deleted his Index?" );
353 0 : pIdx = new SwNodeIndex( rCrsr.GetPoint()->nNode, -1 );
354 : }
355 :
356 0 : SwDoc* pAutoDoc = aTBlks.GetDoc();
357 0 : SwNodeIndex aSttIdx( pAutoDoc->GetNodes().GetEndOfExtras(), 1 );
358 0 : SwCntntNode* pCntntNd = pAutoDoc->GetNodes().GoNext( &aSttIdx );
359 0 : SwPaM aCpyPam( aSttIdx );
360 :
361 0 : const SwTableNode* pTblNd = pCntntNd->FindTableNode();
362 0 : if( pTblNd )
363 : {
364 0 : aCpyPam.GetPoint()->nContent.Assign( 0, 0 );
365 0 : aCpyPam.GetPoint()->nNode = *pTblNd;
366 : }
367 0 : aCpyPam.SetMark();
368 :
369 : // then until the end of the Nodes Array
370 0 : aCpyPam.GetPoint()->nNode.Assign( pAutoDoc->GetNodes().GetEndOfContent(), -1 );
371 0 : pCntntNd = aCpyPam.GetCntntNode();
372 0 : aCpyPam.GetPoint()->nContent.Assign( pCntntNd, pCntntNd->Len() );
373 :
374 0 : SwDontExpandItem aExpItem;
375 0 : aExpItem.SaveDontExpandItems( *aPam.GetPoint() );
376 :
377 0 : pAutoDoc->CopyRange( aCpyPam, *aPam.GetPoint(), false );
378 :
379 0 : aExpItem.RestoreDontExpandItems( *aPam.GetPoint() );
380 :
381 0 : if( pPara )
382 : {
383 0 : ++(*pIdx);
384 0 : pTxtNd = pIdx->GetNode().GetTxtNode();
385 : }
386 0 : bRet = sal_True;
387 : }
388 0 : aTBlks.EndGetDoc();
389 0 : }
390 : }
391 :
392 0 : if( bRet && pPara && pTxtNd )
393 0 : *pPara = pTxtNd->GetTxt();
394 :
395 0 : return bRet;
396 : }
397 :
398 : // Called by the functions:
399 : // - FnCptlSttWrd
400 : // - FnCptlSttSntnc
401 : // after the exchange of characters. Then the words, if necessary, can be inserted
402 : // into the exception list.
403 0 : void SwAutoCorrDoc::SaveCpltSttWord( sal_uLong nFlag, sal_Int32 nPos,
404 : const OUString& rExceptWord,
405 : sal_Unicode cChar )
406 : {
407 0 : sal_uLong nNode = pIdx ? pIdx->GetIndex() : rCrsr.GetPoint()->nNode.GetIndex();
408 0 : LanguageType eLang = GetLanguage(nPos, false);
409 : rEditSh.GetDoc()->SetAutoCorrExceptWord( new SwAutoCorrExceptWord( nFlag,
410 0 : nNode, nPos, rExceptWord, cChar, eLang ));
411 0 : }
412 :
413 0 : LanguageType SwAutoCorrDoc::GetLanguage( sal_Int32 nPos, bool bPrevPara ) const
414 : {
415 0 : LanguageType eRet = LANGUAGE_SYSTEM;
416 :
417 0 : SwTxtNode* pNd = (( bPrevPara && pIdx )
418 : ? *pIdx
419 0 : : rCrsr.GetPoint()->nNode ).GetNode().GetTxtNode();
420 :
421 0 : if( pNd )
422 0 : eRet = pNd->GetLang( nPos, 0 );
423 0 : if(LANGUAGE_SYSTEM == eRet)
424 0 : eRet = GetAppLanguage();
425 0 : return eRet;
426 : }
427 :
428 0 : void SwAutoCorrExceptWord::CheckChar( const SwPosition& rPos, sal_Unicode cChr )
429 : {
430 : // test only if this is a improvement.
431 : // If yes, then add the word to the list.
432 0 : if( cChar == cChr && rPos.nNode.GetIndex() == nNode &&
433 0 : rPos.nContent.GetIndex() == nCntnt )
434 : {
435 : // get the current autocorrection:
436 0 : SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect();
437 :
438 : // then add to the list:
439 0 : if( CptlSttWrd & nFlags )
440 0 : pACorr->AddWrtSttException( sWord, eLanguage );
441 0 : else if( CptlSttSntnc & nFlags )
442 0 : pACorr->AddCplSttException( sWord, eLanguage );
443 : }
444 0 : }
445 :
446 0 : sal_Bool SwAutoCorrExceptWord::CheckDelChar( const SwPosition& rPos )
447 : {
448 0 : sal_Bool bRet = sal_False;
449 0 : if( !bDeleted && rPos.nNode.GetIndex() == nNode &&
450 0 : rPos.nContent.GetIndex() == nCntnt )
451 0 : bDeleted = bRet = sal_True;
452 0 : return bRet;
453 : }
454 :
455 0 : SwDontExpandItem::~SwDontExpandItem()
456 : {
457 0 : delete pDontExpItems;
458 0 : }
459 :
460 0 : void SwDontExpandItem::SaveDontExpandItems( const SwPosition& rPos )
461 : {
462 0 : const SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
463 0 : if( pTxtNd )
464 : {
465 0 : pDontExpItems = new SfxItemSet( ((SwDoc*)pTxtNd->GetDoc())->GetAttrPool(),
466 0 : aCharFmtSetRange );
467 0 : const sal_Int32 n = rPos.nContent.GetIndex();
468 0 : if( !pTxtNd->GetAttr( *pDontExpItems, n, n,
469 0 : n != pTxtNd->GetTxt().getLength() ))
470 0 : delete pDontExpItems, pDontExpItems = 0;
471 : }
472 0 : }
473 :
474 0 : void SwDontExpandItem::RestoreDontExpandItems( const SwPosition& rPos )
475 : {
476 0 : SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
477 0 : if( pTxtNd )
478 : {
479 0 : const sal_Int32 nStart = rPos.nContent.GetIndex();
480 0 : if( nStart == pTxtNd->GetTxt().getLength() )
481 0 : pTxtNd->FmtToTxtAttr( pTxtNd );
482 :
483 0 : if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() )
484 : {
485 0 : const sal_uInt16 nSize = pTxtNd->GetpSwpHints()->Count();
486 : sal_uInt16 n;
487 : sal_Int32 nAttrStart;
488 : const sal_Int32* pAttrEnd;
489 :
490 0 : for( n = 0; n < nSize; ++n )
491 : {
492 0 : SwTxtAttr* pHt = pTxtNd->GetpSwpHints()->GetTextHint( n );
493 0 : nAttrStart = *pHt->GetStart();
494 0 : if( nAttrStart > nStart ) // beyond the area
495 0 : break;
496 :
497 0 : if( 0 != ( pAttrEnd = pHt->End() ) &&
498 0 : ( ( nAttrStart < nStart &&
499 0 : ( pHt->DontExpand() ? nStart < *pAttrEnd
500 0 : : nStart <= *pAttrEnd )) ||
501 0 : ( nStart == nAttrStart &&
502 0 : ( nAttrStart == *pAttrEnd || !nStart ))) )
503 : {
504 : const SfxPoolItem* pItem;
505 0 : if( !pDontExpItems || SFX_ITEM_SET != pDontExpItems->
506 0 : GetItemState( pHt->Which(), false, &pItem ) ||
507 0 : *pItem != pHt->GetAttr() )
508 : {
509 : // The attribute was not previously set in this form in the
510 : // paragraph, so it can only be created through insert/copy
511 : // Because of that it is a candidate for DontExpand
512 0 : pHt->SetDontExpand( true );
513 : }
514 : }
515 : }
516 : }
517 : }
518 0 : }
519 :
520 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|