xref: /AOO41X/main/editeng/source/editeng/edtspell.cxx (revision 4d7c9de063a797b8b4f3d45e3561e82ad1f8ef1f)
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_editeng.hxx"
26 
27 #include <vcl/wrkwin.hxx>
28 #include <vcl/dialog.hxx>
29 #include <vcl/msgbox.hxx>
30 #include <vcl/svapp.hxx>
31 
32 #include <impedit.hxx>
33 #include <editeng/editview.hxx>
34 #include <editeng/editeng.hxx>
35 #include <edtspell.hxx>
36 #include <editeng/flditem.hxx>
37 #include <editeng/fontitem.hxx>
38 #include <svl/intitem.hxx>
39 #include <svl/eitem.hxx>
40 #include <editeng/unolingu.hxx>
41 #include <linguistic/lngprops.hxx>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 
44 using ::rtl::OUString;
45 using namespace com::sun::star::uno;
46 using namespace com::sun::star::beans;
47 using namespace com::sun::star::linguistic2;
48 
49 
EditSpellWrapper(Window * _pWin,Reference<XSpellChecker1> & xChecker,sal_Bool bIsStart,sal_Bool bIsAllRight,EditView * pView)50 EditSpellWrapper::EditSpellWrapper( Window* _pWin,
51         Reference< XSpellChecker1 >  &xChecker,
52         sal_Bool bIsStart, sal_Bool bIsAllRight, EditView* pView ) :
53     SvxSpellWrapper( _pWin, xChecker, bIsStart, bIsAllRight )
54 {
55     DBG_ASSERT( pView, "Es muss eine View uebergeben werden!" );
56     // IgnoreList behalten, ReplaceList loeschen...
57     if (SvxGetChangeAllList().is())
58         SvxGetChangeAllList()->clear();
59     pEditView = pView;
60 }
61 
SpellStart(SvxSpellArea eArea)62 void __EXPORT EditSpellWrapper::SpellStart( SvxSpellArea eArea )
63 {
64     ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
65     SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
66 
67     if ( eArea == SVX_SPELL_BODY_START )
68     {
69         // Wird gerufen, wenn
70         // a) Spell-Forwad ist am Ende angekomment und soll von vorne beginnen
71         // IsEndDone() liefert auch sal_True, wenn Rueckwaerts-Spelling am Ende gestartet wird!
72         if ( IsEndDone() )
73         {
74             pSpellInfo->bSpellToEnd = sal_False;
75             pSpellInfo->aSpellTo = pSpellInfo->aSpellStart;
76             pEditView->GetImpEditView()->SetEditSelection(
77                     pImpEE->GetEditDoc().GetStartPaM() );
78         }
79         else
80         {
81             pSpellInfo->bSpellToEnd = sal_True;
82             pSpellInfo->aSpellTo = pImpEE->CreateEPaM(
83                     pImpEE->GetEditDoc().GetStartPaM() );
84         }
85     }
86     else if ( eArea == SVX_SPELL_BODY_END )
87     {
88         // Wird gerufen, wenn
89         // a) Spell-Forwad wird gestartet
90         // IsStartDone() liefert auch sal_True, wenn Vorwaerts-Spelling am Anfang gestartet wird!
91         if ( !IsStartDone() )
92         {
93             pSpellInfo->bSpellToEnd = sal_True;
94             pSpellInfo->aSpellTo = pImpEE->CreateEPaM(
95                     pImpEE->GetEditDoc().GetEndPaM() );
96         }
97         else
98         {
99             pSpellInfo->bSpellToEnd = sal_False;
100             pSpellInfo->aSpellTo = pSpellInfo->aSpellStart;
101             pEditView->GetImpEditView()->SetEditSelection(
102                     pImpEE->GetEditDoc().GetEndPaM() );
103         }
104     }
105     else if ( eArea == SVX_SPELL_BODY )
106     {
107         ;   // Wird ueber SpellNextDocument von App gehandelt
108 
109         // pSpellInfo->bSpellToEnd = sal_True;
110         // pSpellInfo->aSpellTo = pImpEE->CreateEPaM( pImpEE->GetEditDoc().GetEndPaM() );
111     }
112     else
113     {
114         DBG_ERROR( "SpellStart: Unknown Area!" );
115     }
116 }
117 
SpellContinue()118 sal_Bool EditSpellWrapper::SpellContinue()
119 {
120     SetLast( pEditView->GetImpEditEngine()->ImpSpell( pEditView ) );
121     return GetLast().is();
122 }
123 
SpellEnd()124 void __EXPORT EditSpellWrapper::SpellEnd()
125 {
126     // Base class will show language errors...
127     SvxSpellWrapper::SpellEnd();
128 }
129 
HasOtherCnt()130 sal_Bool __EXPORT EditSpellWrapper::HasOtherCnt()
131 {
132     return sal_False;
133 }
134 
SpellMore()135 sal_Bool __EXPORT EditSpellWrapper::SpellMore()
136 {
137     ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
138     SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
139     sal_Bool bMore = sal_False;
140     if ( pSpellInfo->bMultipleDoc )
141     {
142         bMore = pImpEE->GetEditEnginePtr()->SpellNextDocument();
143         SetCurTextObj( pImpEE->GetEditEnginePtr()->GetCurTextObj() );
144         if ( bMore )
145         {
146             // Der Text wurde in diese Engine getreten, bei Rueckwaerts
147             // muss die Selektion hinten sein.
148             Reference< XPropertySet >  xProp( SvxGetLinguPropertySet() );
149             pEditView->GetImpEditView()->SetEditSelection(
150                         pImpEE->GetEditDoc().GetStartPaM() );
151         }
152     }
153     return bMore;
154 }
155 
ScrollArea()156 void __EXPORT EditSpellWrapper::ScrollArea()
157 {
158     // Keine weitere Aktion noetig...
159     // Es sei denn, der Bereich soll in die Mitte gescrollt werden,
160     // und nicht irgendwo stehen.
161 }
162 
ReplaceAll(const String & rNewText,sal_Int16)163 void __EXPORT EditSpellWrapper::ReplaceAll( const String &rNewText,
164             sal_Int16 )
165 {
166     // Wird gerufen, wenn Wort in ReplaceList des SpellCheckers
167     pEditView->InsertText( rNewText );
168     CheckSpellTo();
169 }
170 
ChangeWord(const String & rNewWord,const sal_uInt16)171 void __EXPORT EditSpellWrapper::ChangeWord( const String& rNewWord,
172             const sal_uInt16 )
173 {
174     // Wird gerufen, wenn Wort Button Change
175     // bzw. intern von mir bei ChangeAll
176 
177     // Wenn Punkt hinterm Wort, wird dieser nicht mitgegeben.
178     // Falls '"' => PreStripped.
179     String aNewWord( rNewWord );
180     pEditView->InsertText( aNewWord );
181     CheckSpellTo();
182 }
183 
ChangeThesWord(const String & rNewWord)184 void __EXPORT EditSpellWrapper::ChangeThesWord( const String& rNewWord )
185 {
186     pEditView->InsertText( rNewWord );
187     CheckSpellTo();
188 }
189 
AutoCorrect(const String &,const String &)190 void __EXPORT EditSpellWrapper::AutoCorrect( const String&, const String& )
191 {
192 }
193 
CheckSpellTo()194 void EditSpellWrapper::CheckSpellTo()
195 {
196     ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
197     SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
198     EditPaM aPaM( pEditView->GetImpEditView()->GetEditSelection().Max() );
199     EPaM aEPaM = pImpEE->CreateEPaM( aPaM );
200     if ( aEPaM.nPara == pSpellInfo->aSpellTo.nPara )
201     {
202         // prueffen, ob SpellToEnd noch gueltiger Index, falls in dem Absatz
203         // ersetzt wurde.
204         if ( pSpellInfo->aSpellTo.nIndex > aPaM.GetNode()->Len() )
205             pSpellInfo->aSpellTo.nIndex = aPaM.GetNode()->Len();
206     }
207 }
208 
209 //////////////////////////////////////////////////////////////////////
210 
211 SV_IMPL_VARARR( WrongRanges, WrongRange );
212 
WrongList()213 WrongList::WrongList()
214 {
215     nInvalidStart = 0;
216     nInvalidEnd = 0xFFFF;
217 }
218 
~WrongList()219 WrongList::~WrongList()
220 {
221 }
222 
MarkInvalid(sal_uInt16 nS,sal_uInt16 nE)223 void WrongList::MarkInvalid( sal_uInt16 nS, sal_uInt16 nE )
224 {
225     if ( ( nInvalidStart == NOT_INVALID ) || ( nInvalidStart > nS ) )
226         nInvalidStart = nS;
227     if ( nInvalidEnd < nE )
228         nInvalidEnd = nE;
229 }
230 
TextInserted(sal_uInt16 nPos,sal_uInt16 nNew,sal_Bool bPosIsSep)231 void WrongList::TextInserted( sal_uInt16 nPos, sal_uInt16 nNew, sal_Bool bPosIsSep )
232 {
233     if ( !IsInvalid() )
234     {
235         nInvalidStart = nPos;
236         nInvalidEnd = nPos+nNew;
237     }
238     else
239     {
240         if ( nInvalidStart > nPos )
241             nInvalidStart = nPos;
242         if ( nInvalidEnd >= nPos )
243             nInvalidEnd = nInvalidEnd + nNew;
244         else
245             nInvalidEnd = nPos+nNew;
246     }
247 
248     for ( sal_uInt16 n = 0; n < Count(); n++ )
249     {
250         WrongRange& rWrong = GetObject( n );
251         sal_Bool bRefIsValid = sal_True;
252         if ( rWrong.nEnd >= nPos )
253         {
254             // Alle Wrongs hinter der Einfuegeposition verschieben...
255             if ( rWrong.nStart > nPos )
256             {
257                 rWrong.nStart = rWrong.nStart + nNew;
258                 rWrong.nEnd = rWrong.nEnd + nNew;
259             }
260             // 1: Startet davor, geht bis nPos...
261             else if ( rWrong.nEnd == nPos )
262             {
263                 // Sollte bei einem Blank unterbunden werden!
264                 if ( !bPosIsSep )
265                     rWrong.nEnd = rWrong.nEnd + nNew;
266             }
267             // 2: Startet davor, geht hinter Pos...
268             else if ( ( rWrong.nStart < nPos ) && ( rWrong.nEnd > nPos ) )
269             {
270                 rWrong.nEnd = rWrong.nEnd + nNew;
271                 // Bei einem Trenner das Wrong entfernen und neu pruefen
272                 if ( bPosIsSep )
273                 {
274                     // Wrong aufteilen...
275                     WrongRange aNewWrong( rWrong.nStart, nPos );
276                     rWrong.nStart = nPos+1;
277                     Insert( aNewWrong, n );
278                     bRefIsValid = sal_False;    // Referenz nach Insert nicht mehr gueltig, der andere wurde davor an dessen Position eingefuegt
279                     n++; // Diesen nicht nochmal...
280                 }
281             }
282             // 3: Attribut startet auf Pos...
283             else if ( rWrong.nStart == nPos )
284             {
285                 rWrong.nEnd = rWrong.nEnd + nNew;
286                 if ( bPosIsSep )
287                     rWrong.nStart++;
288             }
289         }
290         DBG_ASSERT( !bRefIsValid || ( rWrong.nStart < rWrong.nEnd ),
291                 "TextInserted, WrongRange: Start >= End?!" );
292     }
293 
294     DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
295 }
296 
TextDeleted(sal_uInt16 nPos,sal_uInt16 nDeleted)297 void WrongList::TextDeleted( sal_uInt16 nPos, sal_uInt16 nDeleted )
298 {
299     sal_uInt16 nEndChanges = nPos+nDeleted;
300     if ( !IsInvalid() )
301     {
302         sal_uInt16 nNewInvalidStart = nPos ? nPos - 1 : 0;
303         nInvalidStart = nNewInvalidStart;
304         nInvalidEnd = nNewInvalidStart + 1;
305     }
306     else
307     {
308         if ( nInvalidStart > nPos )
309             nInvalidStart = nPos;
310         if ( nInvalidEnd > nPos )
311         {
312             if ( nInvalidEnd > nEndChanges )
313                 nInvalidEnd = nInvalidEnd - nDeleted;
314             else
315                 nInvalidEnd = nPos+1;
316         }
317     }
318 
319     for ( sal_uInt16 n = 0; n < Count(); n++ )
320     {
321         WrongRange& rWrong = GetObject( n );
322         sal_Bool bDelWrong = sal_False;
323         if ( rWrong.nEnd >= nPos )
324         {
325             // Alles Wrongs hinter der Einfuegeposition verschieben...
326             if ( rWrong.nStart >= nEndChanges )
327             {
328                 rWrong.nStart = rWrong.nStart - nDeleted;
329                 rWrong.nEnd = rWrong.nEnd - nDeleted;
330             }
331             // 1. Innenliegende Wrongs loeschen...
332             else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd <= nEndChanges ) )
333             {
334                 bDelWrong = sal_True;
335             }
336             // 2. Wrong beginnt davor, endet drinnen oder dahinter...
337             else if ( ( rWrong.nStart <= nPos ) && ( rWrong.nEnd > nPos ) )
338             {
339                 if ( rWrong.nEnd <= nEndChanges )   // endet drinnen
340                     rWrong.nEnd = nPos;
341                 else
342                     rWrong.nEnd = rWrong.nEnd - nDeleted; // endet dahinter
343             }
344             // 3. Wrong beginnt drinnen, endet dahinter...
345             else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd > nEndChanges ) )
346             {
347                 rWrong.nStart = nEndChanges;
348                 rWrong.nStart = rWrong.nStart - nDeleted;
349                 rWrong.nEnd = rWrong.nEnd - nDeleted;
350             }
351         }
352         DBG_ASSERT( rWrong.nStart < rWrong.nEnd,
353                 "TextInserted, WrongRange: Start >= End?!" );
354         if ( bDelWrong )
355         {
356             Remove( n, 1 );
357             n--;
358         }
359     }
360 
361     DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
362 }
363 
NextWrong(sal_uInt16 & rnStart,sal_uInt16 & rnEnd) const364 sal_Bool WrongList::NextWrong( sal_uInt16& rnStart, sal_uInt16& rnEnd ) const
365 {
366     /*
367         rnStart enthaelt die Startposition, wird ggf. auf Wrong-Start korrigiert
368         rnEnd braucht nicht inizialisiert sein.
369     */
370     for ( sal_uInt16 n = 0; n < Count(); n++ )
371     {
372         WrongRange& rWrong = GetObject( n );
373         if ( rWrong.nEnd > rnStart )
374         {
375             rnStart = rWrong.nStart;
376             rnEnd = rWrong.nEnd;
377             return sal_True;
378         }
379     }
380     return sal_False;
381 }
382 
HasWrong(sal_uInt16 nStart,sal_uInt16 nEnd) const383 sal_Bool WrongList::HasWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const
384 {
385     for ( sal_uInt16 n = 0; n < Count(); n++ )
386     {
387         WrongRange& rWrong = GetObject( n );
388         if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd == nEnd ) )
389             return sal_True;
390         else if ( rWrong.nStart >= nStart )
391             break;
392     }
393     return sal_False;
394 }
395 
HasAnyWrong(sal_uInt16 nStart,sal_uInt16 nEnd) const396 sal_Bool WrongList::HasAnyWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const
397 {
398     for ( sal_uInt16 n = 0; n < Count(); n++ )
399     {
400         WrongRange& rWrong = GetObject( n );
401         if ( ( rWrong.nEnd >= nStart ) && ( rWrong.nStart < nEnd ) )
402             return sal_True;
403         else if ( rWrong.nStart >= nEnd )
404             break;
405     }
406     return sal_False;
407 }
408 
ClearWrongs(sal_uInt16 nStart,sal_uInt16 nEnd,const ContentNode * pNode)409 void WrongList::ClearWrongs( sal_uInt16 nStart, sal_uInt16 nEnd,
410             const ContentNode* pNode )
411 {
412     for ( sal_uInt16 n = 0; n < Count(); n++ )
413     {
414         WrongRange& rWrong = GetObject( n );
415         if ( ( rWrong.nEnd > nStart ) && ( rWrong.nStart < nEnd ) )
416         {
417             if ( rWrong.nEnd > nEnd )   // // Laeuft raus
418             {
419                 rWrong.nStart = nEnd;
420                 // Blanks?
421                 while ( ( rWrong.nStart < pNode->Len() ) &&
422                             ( ( pNode->GetChar( rWrong.nStart ) == ' ' ) ||
423                               ( pNode->IsFeature( rWrong.nStart ) ) ) )
424                 {
425                     rWrong.nStart++;
426                 }
427             }
428             else
429             {
430                 Remove( n, 1 );
431                 n--;
432             }
433         }
434     }
435 
436     DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
437 }
438 
InsertWrong(sal_uInt16 nStart,sal_uInt16 nEnd,sal_Bool bClearRange)439 void WrongList::InsertWrong( sal_uInt16 nStart, sal_uInt16 nEnd,
440             sal_Bool bClearRange )
441 {
442     sal_uInt16 nPos = Count();
443     for ( sal_uInt16 n = 0; n < Count(); n++ )
444     {
445         WrongRange& rWrong = GetObject( n );
446         if ( rWrong.nStart >= nStart )
447         {
448             nPos = n;
449             if ( bClearRange )
450             {
451                 // Es kann eigentlich nur Passieren, dass der Wrong genau
452                 // hier beginnt und weiter rauslauft, aber nicht, dass hier
453                 // mehrere im Bereich liegen...
454                 // Genau im Bereich darf keiner liegen, sonst darf diese Methode
455                 // garnicht erst gerufen werden!
456                 DBG_ASSERT( ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) )
457                                 || ( rWrong.nStart > nEnd ), "InsertWrong: RangeMismatch!" );
458                 if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) )
459                     rWrong.nStart = nEnd+1;
460             }
461             break;
462         }
463     }
464     Insert( WrongRange( nStart, nEnd ), nPos );
465 
466     DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
467 }
468 
MarkWrongsInvalid()469 void WrongList::MarkWrongsInvalid()
470 {
471     if ( Count() )
472         MarkInvalid( GetObject( 0 ).nStart, GetObject( Count()-1 ).nEnd );
473 }
474 
Clone() const475 WrongList*  WrongList::Clone() const
476 {
477     WrongList* pNew = new WrongList;
478     for ( sal_uInt16 n = 0; n < Count(); n++ )
479     {
480         WrongRange& rWrong = GetObject( n );
481         pNew->Insert( rWrong, pNew->Count() );
482     }
483 
484     return pNew;
485 }
486 
487 // #i102062#
operator ==(const WrongList & rCompare) const488 bool WrongList::operator==(const WrongList& rCompare) const
489 {
490     // cleck direct members
491     if(GetInvalidStart() != rCompare.GetInvalidStart()
492         || GetInvalidEnd() != rCompare.GetInvalidEnd()
493         || Count() != rCompare.Count())
494     {
495         return false;
496     }
497 
498     for(sal_uInt16 a(0); a < Count(); a++)
499     {
500         const WrongRange& rCandA(GetObject(a));
501         const WrongRange& rCandB(rCompare.GetObject(a));
502 
503         if(rCandA.nStart != rCandB.nStart
504             || rCandA.nEnd != rCandB.nEnd)
505         {
506             return false;
507         }
508     }
509 
510     return true;
511 }
512 
513 #ifdef DBG_UTIL
DbgIsBuggy() const514 sal_Bool WrongList::DbgIsBuggy() const
515 {
516     // Pruefen, ob sich Bereiche ueberlappen
517     sal_Bool bError = sal_False;
518     for ( sal_uInt16 _nA = 0; !bError && ( _nA < Count() ); _nA++ )
519     {
520         WrongRange& rWrong = GetObject( _nA );
521         for ( sal_uInt16 nB = _nA+1; !bError && ( nB < Count() ); nB++ )
522         {
523             WrongRange& rNextWrong = GetObject( nB );
524             // 1) Start davor, End hinterm anderen Start
525             if (   ( rWrong.nStart <= rNextWrong.nStart )
526                 && ( rWrong.nEnd >= rNextWrong.nStart ) )
527                 bError = sal_True;
528             // 2) Start hinter anderen Start, aber noch vorm anderen End
529             else if (   ( rWrong.nStart >= rNextWrong.nStart)
530                      && ( rWrong.nStart <= rNextWrong.nEnd ) )
531                 bError = sal_True;
532         }
533     }
534     return bError;
535 }
536 #endif
537 
538 //////////////////////////////////////////////////////////////////////
539 
EdtAutoCorrDoc(ImpEditEngine * pE,ContentNode * pN,sal_uInt16 nCrsr,xub_Unicode cIns)540 EdtAutoCorrDoc::EdtAutoCorrDoc( ImpEditEngine* pE, ContentNode* pN,
541             sal_uInt16 nCrsr, xub_Unicode cIns )
542 {
543     pImpEE = pE;
544     pCurNode = pN;
545     nCursor = nCrsr;
546 
547     bUndoAction = sal_False;
548     bAllowUndoAction = cIns ? sal_True : sal_False;
549 }
550 
~EdtAutoCorrDoc()551 EdtAutoCorrDoc::~EdtAutoCorrDoc()
552 {
553     if ( bUndoAction )
554         pImpEE->UndoActionEnd( EDITUNDO_INSERT );
555 }
556 
Delete(sal_uInt16 nStt,sal_uInt16 nEnd)557 sal_Bool EdtAutoCorrDoc::Delete( sal_uInt16 nStt, sal_uInt16 nEnd )
558 {
559     EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
560     pImpEE->ImpDeleteSelection( aSel );
561     DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" );
562     nCursor -= ( nEnd-nStt );
563     bAllowUndoAction = sal_False;
564     return sal_True;
565 }
566 
Insert(sal_uInt16 nPos,const String & rTxt)567 sal_Bool EdtAutoCorrDoc::Insert( sal_uInt16 nPos, const String& rTxt )
568 {
569     EditSelection aSel = EditPaM( pCurNode, nPos );
570     pImpEE->ImpInsertText( aSel, rTxt );
571     DBG_ASSERT( nCursor >= nPos, "Cursor mitten im Geschehen ?!" );
572     nCursor = nCursor + rTxt.Len();
573 
574     if ( bAllowUndoAction && ( rTxt.Len() == 1 ) )
575         ImplStartUndoAction();
576     bAllowUndoAction = sal_False;
577 
578     return sal_True;
579 }
580 
Replace(sal_uInt16 nPos,const String & rTxt)581 sal_Bool EdtAutoCorrDoc::Replace( sal_uInt16 nPos, const String& rTxt )
582 {
583     return ReplaceRange( nPos, rTxt.Len(), rTxt );
584 }
585 
ReplaceRange(xub_StrLen nPos,xub_StrLen nSourceLength,const String & rTxt)586 sal_Bool EdtAutoCorrDoc::ReplaceRange( xub_StrLen nPos, xub_StrLen nSourceLength, const String& rTxt )
587 {
588     // Eigentlich ein Replace einfuehren => Entspr. UNDO
589     sal_uInt16 nEnd = nPos+nSourceLength;
590     if ( nEnd > pCurNode->Len() )
591         nEnd = pCurNode->Len();
592 
593     // #i5925# First insert new text behind to be deleted text, for keeping attributes.
594     pImpEE->ImpInsertText( EditSelection( EditPaM( pCurNode, nEnd ) ), rTxt );
595     pImpEE->ImpDeleteSelection( EditSelection( EditPaM( pCurNode, nPos ), EditPaM( pCurNode, nEnd ) ) );
596 
597     if ( nPos == nCursor )
598         nCursor = nCursor + rTxt.Len();
599 
600     if ( bAllowUndoAction && ( rTxt.Len() == 1 ) )
601         ImplStartUndoAction();
602 
603     bAllowUndoAction = sal_False;
604 
605     return sal_True;
606 }
607 
SetAttr(sal_uInt16 nStt,sal_uInt16 nEnd,sal_uInt16 nSlotId,SfxPoolItem & rItem)608 sal_Bool EdtAutoCorrDoc::SetAttr( sal_uInt16 nStt, sal_uInt16 nEnd,
609             sal_uInt16 nSlotId, SfxPoolItem& rItem )
610 {
611     SfxItemPool* pPool = &pImpEE->GetEditDoc().GetItemPool();
612     while ( pPool->GetSecondaryPool() &&
613             !pPool->GetName().EqualsAscii( "EditEngineItemPool" ) )
614     {
615         pPool = pPool->GetSecondaryPool();
616 
617     }
618     sal_uInt16 nWhich = pPool->GetWhich( nSlotId );
619     if ( nWhich )
620     {
621         rItem.SetWhich( nWhich );
622 
623         SfxItemSet aSet( pImpEE->GetEmptyItemSet() );
624         aSet.Put( rItem );
625 
626         EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
627         aSel.Max().SetIndex( nEnd );    // ???
628         pImpEE->SetAttribs( aSel, aSet, ATTRSPECIAL_EDGE );
629         bAllowUndoAction = sal_False;
630     }
631     return sal_True;
632 }
633 
SetINetAttr(sal_uInt16 nStt,sal_uInt16 nEnd,const String & rURL)634 sal_Bool EdtAutoCorrDoc::SetINetAttr( sal_uInt16 nStt, sal_uInt16 nEnd,
635             const String& rURL )
636 {
637     // Aus dem Text ein Feldbefehl machen...
638     EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
639     String aText = pImpEE->GetSelected( aSel );
640     aSel = pImpEE->ImpDeleteSelection( aSel );
641     DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" );
642     nCursor -= ( nEnd-nStt );
643     SvxFieldItem aField( SvxURLField( rURL, aText, SVXURLFORMAT_REPR ),
644                                       EE_FEATURE_FIELD  );
645     pImpEE->InsertField( aSel, aField );
646     nCursor++;
647     pImpEE->UpdateFields();
648     bAllowUndoAction = sal_False;
649     return sal_True;
650 }
651 
HasSymbolChars(sal_uInt16 nStt,sal_uInt16 nEnd)652 sal_Bool EdtAutoCorrDoc::HasSymbolChars( sal_uInt16 nStt, sal_uInt16 nEnd )
653 {
654     sal_uInt16 nScriptType = pImpEE->GetScriptType( EditPaM( pCurNode, nStt ) );
655     sal_uInt16 nScriptFontInfoItemId = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType );
656 
657     CharAttribArray& rAttribs = pCurNode->GetCharAttribs().GetAttribs();
658     sal_uInt16 nAttrs = rAttribs.Count();
659     for ( sal_uInt16 n = 0; n < nAttrs; n++ )
660     {
661         EditCharAttrib* pAttr = rAttribs.GetObject( n );
662         if ( pAttr->GetStart() >= nEnd )
663             return sal_False;
664 
665         if ( ( pAttr->Which() == nScriptFontInfoItemId ) &&
666                 ( ((SvxFontItem*)pAttr->GetItem())->GetCharSet() == RTL_TEXTENCODING_SYMBOL ) )
667         {
668             // Pruefen, ob das Attribt im Bereich liegt...
669             if ( pAttr->GetEnd() >= nStt )
670                 return sal_True;
671         }
672     }
673     return sal_False;
674 }
675 
GetPrevPara(sal_Bool)676 const String* EdtAutoCorrDoc::GetPrevPara( sal_Bool )
677 {
678     // Vorherigen Absatz zurueck geben, damit ermittel werden kann,
679     // ob es sich beim aktuellen Wort um einen Satzanfang handelt.
680 
681     bAllowUndoAction = sal_False;   // Jetzt nicht mehr...
682 
683     ContentList& rNodes = pImpEE->GetEditDoc();
684     sal_uInt16 nPos = rNodes.GetPos( pCurNode );
685 
686     // Sonderbehandlung: Bullet => Absatzanfang => einfach NULL returnen...
687     const SfxBoolItem& rBulletState = (const SfxBoolItem&)
688             pImpEE->GetParaAttrib( nPos, EE_PARA_BULLETSTATE );
689     sal_Bool bBullet = rBulletState.GetValue() ? sal_True : sal_False;
690     if ( !bBullet && ( pImpEE->aStatus.GetControlWord() & EE_CNTRL_OUTLINER ) )
691     {
692         // Der Outliner hat im Gliederungsmodus auf Ebene 0 immer ein Bullet.
693         const SfxInt16Item& rLevel = (const SfxInt16Item&)
694                 pImpEE->GetParaAttrib( nPos, EE_PARA_OUTLLEVEL );
695         if ( rLevel.GetValue() == 0 )
696             bBullet = sal_True;
697     }
698     if ( bBullet )
699         return NULL;
700 
701     for ( sal_uInt16 n = nPos; n; )
702     {
703         n--;
704         ContentNode* pNode = rNodes[n];
705         if ( pNode->Len() )
706             return pNode;
707     }
708     return NULL;
709 
710 }
711 
ChgAutoCorrWord(sal_uInt16 & rSttPos,sal_uInt16 nEndPos,SvxAutoCorrect & rACorrect,const String ** ppPara)712 sal_Bool EdtAutoCorrDoc::ChgAutoCorrWord( sal_uInt16& rSttPos,
713             sal_uInt16 nEndPos, SvxAutoCorrect& rACorrect,
714             const String** ppPara )
715 {
716     // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
717     // Kuerzel im Auto
718 
719     bAllowUndoAction = sal_False;   // Jetzt nicht mehr...
720 
721     String aShort( pCurNode->Copy( rSttPos, nEndPos - rSttPos ) );
722     sal_Bool bRet = sal_False;
723 
724     if( !aShort.Len() )
725         return bRet;
726 
727     LanguageType eLang = pImpEE->GetLanguage( EditPaM( pCurNode, rSttPos+1 ) );
728     const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList( *pCurNode, rSttPos, nEndPos, *this, eLang );
729     if( pFnd && pFnd->IsTextOnly() )
730     {
731         // dann mal ersetzen
732         EditSelection aSel( EditPaM( pCurNode, rSttPos ),
733                             EditPaM( pCurNode, nEndPos ) );
734         aSel = pImpEE->ImpDeleteSelection( aSel );
735         DBG_ASSERT( nCursor >= nEndPos, "Cursor mitten im Geschehen ?!" );
736         nCursor -= ( nEndPos-rSttPos );
737         pImpEE->ImpInsertText( aSel, pFnd->GetLong() );
738         nCursor = nCursor + pFnd->GetLong().Len();
739         if( ppPara )
740             *ppPara = pCurNode;
741         bRet = sal_True;
742     }
743 
744     return bRet;
745 }
746 
GetLanguage(sal_uInt16 nPos,sal_Bool) const747 LanguageType EdtAutoCorrDoc::GetLanguage( sal_uInt16 nPos, sal_Bool ) const
748 {
749     return pImpEE->GetLanguage( EditPaM( pCurNode, nPos+1 ) );
750 }
751 
ImplStartUndoAction()752 void EdtAutoCorrDoc::ImplStartUndoAction()
753 {
754     sal_uInt16 nPara = pImpEE->GetEditDoc().GetPos( pCurNode );
755     ESelection aSel( nPara, nCursor, nPara, nCursor );
756     pImpEE->UndoActionStart( EDITUNDO_INSERT, aSel );
757     bUndoAction = sal_True;
758     bAllowUndoAction = sal_False;
759 }
760 
761