xref: /trunk/main/cui/source/dialogs/SpellDialog.cxx (revision 2ee96f1c)
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_cui.hxx"
26 
27 // include ---------------------------------------------------------------
28 
29 #include <tools/ref.hxx>
30 #include <tools/shl.hxx>
31 #include <vcl/wrkwin.hxx>
32 #include <vcl/menu.hxx>
33 #include <vcl/msgbox.hxx>
34 #include <vcl/scrbar.hxx>
35 #include <SpellAttrib.hxx>
36 #include <sfx2/dispatch.hxx>
37 #include <sfx2/bindings.hxx>
38 #include <svl/undo.hxx>
39 #include <unotools/lingucfg.hxx>
40 #include <svtools/textdata.hxx>
41 #include <svtools/filter.hxx>
42 #include <editeng/unolingu.hxx>
43 #include <editeng/splwrap.hxx>
44 #include <linguistic/lngprops.hxx>
45 #include <linguistic/misc.hxx>
46 #include <comphelper/processfactory.hxx>
47 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
48 #include <com/sun/star/lang/XServiceInfo.hpp>
49 #include <com/sun/star/lang/XServiceDisplayName.hpp>
50 #include <com/sun/star/linguistic2/SpellFailure.hpp>
51 #include <com/sun/star/frame/XStorable.hpp>
52 #include <sfx2/app.hxx>
53 #include <vcl/help.hxx>
54 #include <vcl/graph.hxx>
55 #include <osl/file.hxx>
56 #include <cuires.hrc>
57 #include <helpid.hrc>
58 #include "SpellDialog.hrc"
59 #include <editeng/optitems.hxx>
60 #include <editeng/svxenum.hxx>
61 #include <svx/SpellDialogChildWindow.hxx>
62 #include "SpellDialog.hxx"
63 #include <svx/dlgutil.hxx>
64 #include "optlingu.hxx"
65 #include <dialmgr.hxx>
66 #include <svx/svxerr.hxx>
67 #include "treeopt.hxx"
68 #include <svtools/langtab.hxx>
69 
70 using namespace ::com::sun::star;
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::beans;
73 using namespace ::com::sun::star::linguistic2;
74 
75 using ::rtl::OUString;
76 
77 #define C2U(cChar) 					::rtl::OUString::createFromAscii(cChar)
78 // struct SpellDialog_Impl ---------------------------------------------
79 
80 struct SpellDialog_Impl
81 {
82 	Sequence< Reference< XDictionary >  >	aDics;
83 };
84 // -----------------------------------------------------------------------
85 //#define VENDOR_IMAGE_HEIGHT 44 //as specified
86 
87 #define SPELLUNDO_START                     200
88 
89 #define SPELLUNDO_CHANGE_LANGUAGE           (SPELLUNDO_START + 1)
90 #define SPELLUNDO_CHANGE_TEXTENGINE         (SPELLUNDO_START + 2)
91 #define SPELLUNDO_CHANGE_NEXTERROR          (SPELLUNDO_START + 3)
92 #define SPELLUNDO_CHANGE_ADD_TO_DICTIONARY  (SPELLUNDO_START + 4)
93 #define SPELLUNDO_CHANGE_GROUP              (SPELLUNDO_START + 5) //undo list
94 #define SPELLUNDO_MOVE_ERROREND             (SPELLUNDO_START + 6)
95 #define SPELLUNDO_UNDO_EDIT_MODE            (SPELLUNDO_START + 7)
96 #define SPELLUNDO_ADD_IGNORE_RULE           (SPELLUNDO_START + 8)
97 
98 namespace svx{
99 class SpellUndoAction_Impl : public SfxUndoAction
100 {
101     sal_uInt16          m_nId;
102     const Link&     m_rActionLink;
103     //undo of button enabling
104     bool            m_bEnableChangePB;
105     bool            m_bEnableChangeAllPB;
106     //undo of MarkNextError - used in change and change all, ignore and ignore all
107     long            m_nNewErrorStart;
108     long            m_nNewErrorEnd;
109     long            m_nOldErrorStart;
110     long            m_nOldErrorEnd;
111     bool            m_bIsErrorLanguageSelected;
112     ::rtl::OUString m_sRuleId;
113     //undo of AddToDictionary
114     Reference<XDictionary>  m_xDictionary;
115     ::rtl::OUString                m_sAddedWord;
116     //move end of error - ::ChangeMarkedWord()
117     long            m_nOffset;
118 
119 public:
120     SpellUndoAction_Impl(sal_uInt16 nId, const Link& rActionLink) :
121         m_nId(nId),
122         m_rActionLink( rActionLink),
123         m_bEnableChangePB(false),
124         m_bEnableChangeAllPB(false),
125         m_nNewErrorStart(-1),
126         m_nNewErrorEnd(-1),
127         m_nOldErrorStart(-1),
128         m_nOldErrorEnd(-1),
129         m_bIsErrorLanguageSelected(false),
130         m_nOffset(0)
131         {}
132 
133     ~SpellUndoAction_Impl();
134 
135     virtual void            Undo();
136     virtual sal_uInt16          GetId() const;
137 
138     void                    SetEnableChangePB(){m_bEnableChangePB = true;}
139     bool                    IsEnableChangePB(){return m_bEnableChangePB;}
140 
141     void                    SetEnableChangeAllPB(){m_bEnableChangeAllPB = true;}
142     bool                    IsEnableChangeAllPB(){return m_bEnableChangeAllPB;}
143 
144     void                    SetErrorMove(long nNewStart, long nNewEnd, long nOldStart, long nOldEnd)
145                                 {
146                                         m_nNewErrorStart = nNewStart;
147                                         m_nNewErrorEnd  = nNewEnd;
148                                         m_nOldErrorStart = nOldStart;
149                                         m_nOldErrorEnd = nOldEnd;
150                                 }
151     long                    GetNewErrorStart() { return m_nNewErrorStart;}
152     long                    GetNewErrorEnd() { return m_nNewErrorEnd;}
153     long                    GetOldErrorStart() { return m_nOldErrorStart;}
154     long                    GetOldErrorEnd() { return m_nOldErrorEnd;}
155 
156     void                    SetErrorLanguageSelected(bool bSet){ m_bIsErrorLanguageSelected = bSet;}
157     bool                    IsErrorLanguageSelected() const {return m_bIsErrorLanguageSelected;}
158 
159 
160     void                    SetDictionary(Reference<XDictionary> xDict) { m_xDictionary = xDict; }
161     Reference<XDictionary>  GetDictionary() const {return m_xDictionary;}
162     void                    SetAddedWord(const ::rtl::OUString& rWord) {m_sAddedWord = rWord;}
163     const ::rtl::OUString&         GetAddedWord() const { return m_sAddedWord;}
164 
165     void                    SetOffset(long nSet) {m_nOffset = nSet;}
166     long                    GetOffset() const {return m_nOffset;}
167 
168     void                    SetErrorType( const ::rtl::OUString& rId ) { m_sRuleId = rId; }
169     const ::rtl::OUString&  GetErrorType() const { return m_sRuleId; }
170 
171 };
172 }//namespace svx
173 using namespace ::svx;
174 /*-- 06.11.2003 12:16:02---------------------------------------------------
175 
176   -----------------------------------------------------------------------*/
177 SpellUndoAction_Impl::~SpellUndoAction_Impl()
178 {
179 }
180 /*-- 06.11.2003 12:16:02---------------------------------------------------
181 
182   -----------------------------------------------------------------------*/
183 void SpellUndoAction_Impl::Undo()
184 {
185     m_rActionLink.Call(this);
186 }
187 /*-- 06.11.2003 12:16:02---------------------------------------------------
188 
189   -----------------------------------------------------------------------*/
190 sal_uInt16 SpellUndoAction_Impl::GetId()const
191 {
192     return m_nId;
193 }
194 
195 // class SvxSpellCheckDialog ---------------------------------------------
196 
197 SpellDialog::SpellDialog(
198         SpellDialogChildWindow* pChildWindow,
199         Window * pParent,
200         SfxBindings* _pBindings)
201             : SfxModelessDialog (_pBindings,
202                                     pChildWindow,
203                                     pParent,
204                                     CUI_RES(RID_SVXDLG_SPELLCHECK)),
205 
206     aVendorImageFI  ( this , CUI_RES( IMG_VENDOR ) ),
207     aLanguageFT     ( this, CUI_RES( FT_LANGUAGE ) ),
208     aLanguageLB     ( this, CUI_RES( LB_LANGUAGE ) ),
209     aNotInDictFT    ( this, CUI_RES( FT_NOTINDICT ) ),
210     aSentenceED      ( this, CUI_RES( ED_NEWWORD ) ),
211     aSuggestionFT   ( this, CUI_RES( FT_SUGGESTION ) ),
212     aSuggestionLB   ( this, CUI_RES( LB_SUGGESTION ) ),
213 
214     aIgnorePB       ( this, CUI_RES( PB_IGNORE ) ),
215     aIgnoreAllPB    ( this, CUI_RES( PB_IGNOREALL ) ),
216     aIgnoreRulePB   ( this, CUI_RES( PB_IGNORERULE ) ),
217     aAddToDictMB    ( this, CUI_RES( MB_ADDTODICT ) ),
218 
219     aChangePB       ( this, CUI_RES( PB_CHANGE ) ),
220     aChangeAllPB    ( this, CUI_RES( PB_CHANGEALL ) ),
221     aExplainPB      ( this, CUI_RES( PB_EXPLAIN) ),
222     aAutoCorrPB     ( this, CUI_RES( PB_AUTOCORR ) ),
223 
224     aCheckGrammarCB ( this, CUI_RES( CB_CHECK_GRAMMAR ) ),
225 
226     aHelpPB         ( this, CUI_RES( PB_HELP ) ),
227     aOptionsPB      ( this, CUI_RES( PB_OPTIONS ) ),
228     aUndoPB         ( this, CUI_RES( PB_UNDO ) ),
229     aClosePB        ( this, CUI_RES( PB_CLOSE ) ),
230     aBackgroundGB   ( this, CUI_RES( GB_BACKGROUND ) ),
231 
232     aVendorImage    ( CUI_RES( IMG_DEFAULT_VENDOR ) ),
233     aVendorImageHC  ( CUI_RES( IMG_DEFAULT_VENDOR_HC ) ),
234 
235     aResumeST       ( CUI_RES(ST_RESUME )),
236     aIgnoreOnceST   ( aIgnorePB.GetText()),
237     aNoSuggestionsST( CUI_RES(ST_NOSUGGESTIONS)),
238     m_sTitleSpelling              ( CUI_RES( ST_SPELLING                        ) ),
239     m_sTitleSpellingGrammar       ( CUI_RES( ST_SPELLING_AND_GRAMMAR            ) ),
240     m_sTitleSpellingGrammarVendor ( CUI_RES( ST_SPELLING_AND_GRAMMAR_VENDORNAME ) ),
241     aDialogUndoLink( LINK (this, SpellDialog, DialogUndoHdl)),
242     bModified( false ),
243     bFocusLocked( true ),
244     rParent         ( *pChildWindow ),
245     nOldLang        ( LANGUAGE_NONE )
246 {
247     FreeResource();
248     xSpell = LinguMgr::GetSpellChecker();
249     pImpl = new SpellDialog_Impl;
250 
251     //HelpIds
252     aClosePB.       SetHelpId(HID_SPLDLG_BUTTON_CLOSE    );
253     aIgnorePB.      SetHelpId(HID_SPLDLG_BUTTON_IGNORE   );
254     aIgnoreAllPB.   SetHelpId(HID_SPLDLG_BUTTON_IGNOREALL);
255     aIgnoreRulePB.  SetHelpId(HID_SPLDLG_BUTTON_IGNORERULE);
256     aChangePB.      SetHelpId(HID_SPLDLG_BUTTON_CHANGE   );
257     aChangeAllPB.   SetHelpId(HID_SPLDLG_BUTTON_CHANGEALL);
258     aExplainPB.     SetHelpId(HID_SPLDLG_BUTTON_EXPLAIN );
259 	Init_Impl();
260 
261 	// disable controls if service is missing
262 	if (!xSpell.is())
263 		Enable( sal_False );
264 
265     Application::PostUserEvent( STATIC_LINK(
266                         this, SpellDialog, InitHdl ) );
267 }
268 
269 // -----------------------------------------------------------------------
270 
271 SpellDialog::~SpellDialog()
272 {
273     // save possibly modified user-dictionaries
274     Reference< XDictionaryList >  xDicList( SvxGetDictionaryList() );
275     if (xDicList.is())
276     {
277         linguistic::SaveDictionaries( xDicList );
278     }
279 
280     delete aAddToDictMB.GetPopupMenu();
281     delete pImpl;
282 }
283 
284 // -----------------------------------------------------------------------
285 
286 void SpellDialog::Init_Impl()
287 {
288 	// Handler initialisieren
289     aClosePB.SetClickHdl(LINK( this, SpellDialog, CancelHdl ) );
290     aChangePB.SetClickHdl(LINK( this, SpellDialog, ChangeHdl ) );
291     aChangeAllPB.SetClickHdl(LINK( this, SpellDialog, ChangeAllHdl ) );
292     aIgnorePB.SetClickHdl(LINK( this, SpellDialog, IgnoreHdl ) );
293     aIgnoreAllPB.SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
294     aIgnoreRulePB.SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
295     aUndoPB.SetClickHdl(LINK( this, SpellDialog, UndoHdl ) );
296 
297     aAutoCorrPB.SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
298     aCheckGrammarCB.SetClickHdl( LINK( this, SpellDialog, CheckGrammarHdl ));
299     aOptionsPB .SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
300 
301     aSuggestionLB.SetDoubleClickHdl( LINK( this, SpellDialog, ChangeHdl ) );
302 
303     aSentenceED.SetModifyHdl(LINK ( this, SpellDialog, ModifyHdl) );
304     aAddToDictMB.SetSelectHdl(LINK ( this, SpellDialog, AddToDictionaryHdl ) );
305     aLanguageLB.SetSelectHdl(LINK( this, SpellDialog, LanguageSelectHdl ) );
306 
307     // initialize language ListBox
308     aLanguageLB.SetLanguageList( LANG_LIST_SPELL_USED, sal_False, sal_False, sal_True );
309 
310     // get current language
311 	UpdateBoxes_Impl();
312 
313     // fill dictionary PopupMenu
314 	InitUserDicts();
315 
316     aSentenceED.ClearModifyFlag();
317 	SvxGetChangeAllList()->clear();
318 }
319 
320 // -----------------------------------------------------------------------
321 
322 void SpellDialog::UpdateBoxes_Impl()
323 {
324     sal_Int32 i;
325     aSuggestionLB.Clear();
326 
327     const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
328 
329 	LanguageType nAltLanguage = LANGUAGE_NONE;
330     //String      aAltWord;
331 	Sequence< ::rtl::OUString >	aNewWords;
332     bool bIsGrammarError = false;
333     if( pSpellErrorDescription )
334 	{
335         nAltLanguage    = SvxLocaleToLanguage( pSpellErrorDescription->aLocale );
336         //aAltWord       = String( xAlt->getWord() );
337         aNewWords       = pSpellErrorDescription->aSuggestions;
338         bIsGrammarError = pSpellErrorDescription->bIsGrammarError;
339         aExplainPB.SetExplanation(pSpellErrorDescription->sExplanation );
340 	}
341     if( pSpellErrorDescription && pSpellErrorDescription->sDialogTitle.getLength() )
342     {
343         // use this function to apply the correct image to be used...
344         SetTitle_Impl( nAltLanguage );
345         // then change the title to the one to be actually used
346         SetText( pSpellErrorDescription->sDialogTitle );
347     }
348     else
349         SetTitle_Impl( nAltLanguage );
350 	SetSelectedLang_Impl( nAltLanguage );
351 
352 
353 	// Alternativen eintragen
354 	const ::rtl::OUString *pNewWords = aNewWords.getConstArray();
355 	const sal_Int32 nSize = aNewWords.getLength();
356 	for ( i = 0; i < nSize; ++i )
357 	{
358 		String aTmp( pNewWords[i] );
359         if ( LISTBOX_ENTRY_NOTFOUND == aSuggestionLB.GetEntryPos( aTmp ) )
360         {
361             aSuggestionLB.InsertEntry( aTmp );
362             aSuggestionLB.SetEntryFlags(aSuggestionLB.GetEntryCount() - 1, LISTBOX_ENTRY_FLAG_MULTILINE);
363         }
364 	}
365     if(!nSize)
366         aSuggestionLB.InsertEntry( aNoSuggestionsST );
367     aAutoCorrPB.Enable( nSize > 0 );
368     //aSentenceED.GrabFocus();
369 
370     aSuggestionFT.Enable(nSize > 0);
371     aSuggestionLB.Enable(nSize > 0);
372     if( nSize )
373 	{
374         aSuggestionLB.SelectEntryPos(0);
375 	}
376     aChangePB.Enable( nSize > 0);
377     aChangeAllPB.Enable(nSize > 0);
378     bool bShowChangeAll = !bIsGrammarError;
379     aChangeAllPB.Show( bShowChangeAll );
380     aExplainPB.Show( !bShowChangeAll );
381     aLanguageLB.Enable( bShowChangeAll );
382     aIgnoreAllPB.Show( bShowChangeAll );
383     aAddToDictMB.Show( bShowChangeAll );
384     aIgnoreRulePB.Show( !bShowChangeAll );
385     aIgnoreRulePB.Enable(pSpellErrorDescription && pSpellErrorDescription->sRuleId.getLength());
386     aExplainPB.Enable( aExplainPB.HasExplanation() );
387     aAutoCorrPB.Show( bShowChangeAll && rParent.HasAutoCorrection() );
388 
389 }
390 // -----------------------------------------------------------------------
391 
392 void SpellDialog::SpellContinue_Impl(bool bUseSavedSentence, bool bIgnoreCurrentError )
393 {
394     //initially or after the last error of a sentence MarkNextError will fail
395     //then GetNextSentence() has to be called followed again by MarkNextError()
396 	//MarkNextError is not initally called if the UndoEdit mode is active
397     bool bNextSentence = false;
398     if((!aSentenceED.IsUndoEditMode() && aSentenceED.MarkNextError( bIgnoreCurrentError )) ||
399             true == ( bNextSentence = GetNextSentence_Impl(bUseSavedSentence, aSentenceED.IsUndoEditMode()) && aSentenceED.MarkNextError( false )))
400     {
401         const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
402         if( pSpellErrorDescription )
403         {
404 			UpdateBoxes_Impl();
405             Control* aControls[] =
406             {
407                 &aNotInDictFT,
408                 &aSentenceED,
409                 &aLanguageFT,
410                 0
411             };
412             sal_Int32 nIdx = 0;
413             do
414             {
415                 aControls[nIdx]->Enable(sal_True);
416             }
417             while(aControls[++nIdx]);
418 
419 
420         }
421         if( bNextSentence )
422         {
423             //remove undo if a new sentence is active
424             aSentenceED.ResetUndo();
425             aUndoPB.Enable(sal_False);
426         }
427     }
428 }
429 /* -----------------10.09.2003 14:04-----------------
430     Initialize, asynchronous to prevent virtial calls
431     from a constructor
432  --------------------------------------------------*/
433 IMPL_STATIC_LINK( SpellDialog, InitHdl, SpellDialog *, EMPTYARG )
434 {
435     pThis->SetUpdateMode( sal_False );
436     //show or hide AutoCorrect depending on the modules abilities
437     pThis->aAutoCorrPB.Show(pThis->rParent.HasAutoCorrection());
438     pThis->SpellContinue_Impl();
439     pThis->aSentenceED.ResetUndo();
440     pThis->aUndoPB.Enable(sal_False);
441 
442     pThis->LockFocusChanges(true);
443     if( pThis->aChangePB.IsEnabled() )
444         pThis->aChangePB.GrabFocus();
445     else if( pThis->aIgnorePB.IsEnabled() )
446         pThis->aIgnorePB.GrabFocus();
447     else if( pThis->aClosePB.IsEnabled() )
448         pThis->aClosePB.GrabFocus();
449     pThis->LockFocusChanges(false);
450     //show grammar CheckBox depending on the modules abilities
451     bool bHasGrammarChecking = pThis->rParent.HasGrammarChecking();
452     pThis->aCheckGrammarCB.Show( bHasGrammarChecking );
453     if( !bHasGrammarChecking )
454     {
455         //resize the dialog to hide the hidden area of the CheckBox
456         Size aBackSize = pThis->aBackgroundGB.GetSizePixel();
457         sal_Int32 nDiff = pThis->aBackgroundGB.GetPosPixel().Y() + aBackSize.Height()
458                             - pThis->aCheckGrammarCB.GetPosPixel().Y();
459         aBackSize.Height() -= nDiff;
460         pThis->aBackgroundGB.SetSizePixel(aBackSize);
461         Button* aButtons[] = { &pThis->aHelpPB, &pThis->aOptionsPB, &pThis->aUndoPB, &pThis->aClosePB, 0 };
462         sal_Int32 nButton = 0;
463         while( aButtons[nButton])
464         {
465             Point aPos = aButtons[nButton]->GetPosPixel();
466             aPos.Y() -= nDiff;
467             aButtons[nButton]->SetPosPixel(aPos);
468             ++nButton;
469         }
470         Size aDlgSize = pThis->GetSizePixel();
471         aDlgSize.Height() -= nDiff;
472         pThis->SetSizePixel( aDlgSize );
473     }
474     else
475     {
476         if( SvtLinguConfig().HasVendorImages( "SpellAndGrammarDialogImage" ) )
477         {
478             pThis->aVendorImageFI.Show();
479             Size aVendorSize = pThis->aVendorImageFI.GetSizePixel();
480             Size aImageSize = pThis->aVendorImageFI.GetImage().GetSizePixel();
481             if( aImageSize.Height() )
482             {
483                 aVendorSize.Height() = aImageSize.Height();
484                 if(aVendorSize.Width() < aImageSize.Width())
485                     aVendorSize.Width() = aImageSize.Width();
486                 pThis->aVendorImageFI.SetSizePixel( aVendorSize );
487             }
488             //aVendorSize.Height() = nDiff;
489             sal_Int32 nDiff = aVendorSize.Height();
490             pThis->aVendorImageFI.SetSizePixel(aVendorSize);
491             Control* aControls[] = {
492                 &pThis->aLanguageFT,
493                 &pThis->aLanguageLB,
494                 &pThis->aNotInDictFT,
495                 &pThis->aSentenceED,
496                 &pThis->aSuggestionFT,
497                 &pThis->aSuggestionLB,
498                 &pThis->aIgnorePB,
499                 &pThis->aIgnoreAllPB,
500                 &pThis->aIgnoreRulePB,
501                 &pThis->aAddToDictMB,
502                 &pThis->aChangePB,
503                 &pThis->aChangeAllPB,
504                 &pThis->aExplainPB,
505                 &pThis->aAutoCorrPB,
506                 &pThis->aCheckGrammarCB,
507                 &pThis->aHelpPB,
508                 &pThis->aOptionsPB,
509                 &pThis->aUndoPB,
510                 &pThis->aClosePB,
511                 &pThis->aBackgroundGB,
512                 0
513             };
514             sal_Int32 nControl = 0;
515             while( aControls[nControl])
516             {
517                 Point aPos = aControls[nControl]->GetPosPixel();
518                 aPos.Y() += nDiff;
519                 aControls[nControl]->SetPosPixel(aPos);
520                 ++nControl;
521             }
522             Size aDlgSize = pThis->GetSizePixel();
523             aDlgSize.Height() += nDiff;
524             pThis->SetSizePixel( aDlgSize );
525             pThis->Invalidate();
526         }
527     }
528     pThis->aCheckGrammarCB.Check( pThis->rParent.IsGrammarChecking() );
529     pThis->SetUpdateMode( sal_True );
530     pThis->Show();
531     return 0;
532 };
533 
534 // -----------------------------------------------------------------------
535 
536 IMPL_LINK( SpellDialog, ExtClickHdl, Button *, pBtn )
537 {
538     if (&aOptionsPB == pBtn)
539 		StartSpellOptDlg_Impl();
540     else if(&aAutoCorrPB == pBtn)
541     {
542         //get the currently selected wrong word
543         String sCurrentErrorText = aSentenceED.GetErrorText();
544         //get the wrong word from the XSpellAlternative
545         const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
546         if( pSpellErrorDescription )
547         {
548             String sWrong(pSpellErrorDescription->sErrorText);
549             //if the word has not been edited in the MultiLineEdit then
550             //the current suggestion should be used
551             //if it's not the 'no suggestions' entry
552             if(sWrong == sCurrentErrorText &&
553                     aSuggestionLB.IsEnabled() && aSuggestionLB.GetSelectEntryCount() > 0 &&
554                     aNoSuggestionsST != aSuggestionLB.GetSelectEntry())
555             {
556                 sCurrentErrorText = aSuggestionLB.GetSelectEntry();
557             }
558             if(sWrong != sCurrentErrorText)
559             {
560                 SvxPrepareAutoCorrect( sWrong, sCurrentErrorText );
561                 LanguageType eLang = GetSelectedLang_Impl();
562                 rParent.AddAutoCorrection( sWrong, sCurrentErrorText, eLang );
563             }
564         }
565     }
566 	return 0;
567 }
568 // -----------------------------------------------------------------------
569 IMPL_LINK( SpellDialog, CheckGrammarHdl, CheckBox*, pBox )
570 {
571     rParent.SetGrammarChecking( pBox->IsChecked() );
572     Impl_Restore();
573     return 0;
574 }
575 
576 void SpellDialog::StartSpellOptDlg_Impl()
577 {
578     sal_uInt16 aSpellInfos[] =
579     {
580         SID_ATTR_SPELL,SID_ATTR_SPELL,
581         SID_SPELL_MODIFIED, SID_SPELL_MODIFIED,
582         SID_AUTOSPELL_CHECK, SID_AUTOSPELL_CHECK,
583         0
584     };
585     SfxItemSet aSet( SFX_APP()->GetPool(), aSpellInfos);
586     aSet.Put(SfxSpellCheckItem( xSpell, SID_ATTR_SPELL ));
587 	SfxSingleTabDialog* pDlg =
588 		new SfxSingleTabDialog( this, aSet, RID_SFXPAGE_LINGU );
589 	SfxTabPage* pPage = SvxLinguTabPage::Create( pDlg, aSet );
590 	( (SvxLinguTabPage*)pPage )->HideGroups( GROUP_MODULES );
591 	pDlg->SetTabPage( pPage );
592 	if(RET_OK == pDlg->Execute())
593 	{
594 
595     	// Benutzerb"ucher anzeigen
596 	    InitUserDicts();
597         const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
598         if(pOutSet)
599             OfaTreeOptionsDialog::ApplyLanguageOptions(*pOutSet);
600     }
601 	delete pDlg;
602 
603 }
604 
605 // -----------------------------------------------------------------------
606 
607 IMPL_LINK( SpellDialog, ChangeHdl, Button *, EMPTYARG )
608 {
609     if(aSentenceED.IsUndoEditMode())
610     {
611         SpellContinue_Impl();
612     }
613     else
614     {
615         aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
616         String aString = aSentenceED.GetErrorText();
617         //dots are sometimes part of the spelled word but they are not necessarily part of the replacement
618         bool bDot = aString.Len() && aString.GetChar(aString.Len() - 1 ) == '.';
619         if(aSuggestionLB.IsEnabled() &&
620                 aSuggestionLB.GetSelectEntryCount()>0 &&
621                 aNoSuggestionsST != aSuggestionLB.GetSelectEntry())
622             aString = aSuggestionLB.GetSelectEntry();
623         if(bDot && (!aString.Len() || aString.GetChar(aString.Len() - 1 ) != '.'))
624             aString += '.';
625 
626         aSentenceED.ChangeMarkedWord(aString, GetSelectedLang_Impl());
627         SpellContinue_Impl();
628         bModified = false;
629         aSentenceED.UndoActionEnd();
630     }
631     if(!aChangePB.IsEnabled())
632         aIgnorePB.GrabFocus();
633     return 1;
634 }
635 
636 
637 // -----------------------------------------------------------------------
638 
639 IMPL_LINK( SpellDialog, ChangeAllHdl, Button *, EMPTYARG )
640 {
641     aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
642     // change the current word first
643     String aString = aSentenceED.GetErrorText();
644     if(aSuggestionLB.IsEnabled() &&
645             aSuggestionLB.GetSelectEntryCount()>0 &&
646             aNoSuggestionsST != aSuggestionLB.GetSelectEntry())
647         aString = aSuggestionLB.GetSelectEntry();
648 
649     LanguageType eLang = GetSelectedLang_Impl();
650 
651 	// add new word to ChangeAll list
652     String  aOldWord( aSentenceED.GetErrorText() );
653     SvxPrepareAutoCorrect( aOldWord, aString );
654     Reference<XDictionary> aXDictionary( SvxGetChangeAllList(), UNO_QUERY );
655     sal_uInt8 nAdded = linguistic::AddEntryToDic( aXDictionary,
656             aOldWord , sal_True,
657             aString, eLang );
658 
659     if(nAdded == DIC_ERR_NONE)
660     {
661         SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
662                         SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
663         pAction->SetDictionary(aXDictionary);
664         pAction->SetAddedWord(aOldWord);
665         aSentenceED.AddUndoAction(pAction);
666     }
667 
668     aSentenceED.ChangeMarkedWord(aString, eLang);
669 	SpellContinue_Impl();
670     bModified = false;
671     aSentenceED.UndoActionEnd();
672     return 1;
673 }
674 // -----------------------------------------------------------------------
675 
676 IMPL_LINK( SpellDialog, IgnoreAllHdl, Button *, pButton )
677 {
678     aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
679     // add word to IgnoreAll list
680     Reference< XDictionary > aXDictionary( SvxGetIgnoreAllList(), UNO_QUERY );
681     //in case the error has been changed manually it has to be restored
682     aSentenceED.RestoreCurrentError();
683     if( pButton == &aIgnoreRulePB )
684     {
685         const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
686         try
687         {
688             if( pSpellErrorDescription && pSpellErrorDescription->xGrammarChecker.is() )
689             {
690                 pSpellErrorDescription->xGrammarChecker->ignoreRule( pSpellErrorDescription->sRuleId,
691                     pSpellErrorDescription->aLocale );
692             }
693         }
694         catch( const uno::Exception& )
695         {
696         }
697     }
698     else
699     {
700         String sErrorText(aSentenceED.GetErrorText());
701         sal_uInt8 nAdded = linguistic::AddEntryToDic( aXDictionary,
702             sErrorText, sal_False,
703             ::rtl::OUString(), LANGUAGE_NONE );
704         if(nAdded == DIC_ERR_NONE)
705         {
706             SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
707                             SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
708             pAction->SetDictionary(aXDictionary);
709             pAction->SetAddedWord(sErrorText);
710             aSentenceED.AddUndoAction(pAction);
711         }
712     }
713 
714 	SpellContinue_Impl();
715     bModified = false;
716     aSentenceED.UndoActionEnd();
717     return 1;
718 }
719 /*-- 06.11.2003 11:24:08---------------------------------------------------
720 
721   -----------------------------------------------------------------------*/
722 IMPL_LINK( SpellDialog, UndoHdl, Button*, EMPTYARG )
723 {
724     aSentenceED.Undo();
725     if(!aSentenceED.GetUndoActionCount())
726         aUndoPB.Enable(sal_False);
727     return 0;
728 }
729 /*-- 06.11.2003 12:19:15---------------------------------------------------
730 
731   -----------------------------------------------------------------------*/
732 IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl*, pAction )
733 {
734     switch(pAction->GetId())
735     {
736         case SPELLUNDO_CHANGE_TEXTENGINE:
737         {
738             if(pAction->IsEnableChangePB())
739                 aChangePB.Enable(sal_False);
740             if(pAction->IsEnableChangeAllPB())
741                 aChangeAllPB.Enable(sal_False);
742         }
743         break;
744         case SPELLUNDO_CHANGE_NEXTERROR:
745         {
746             aSentenceED.MoveErrorMarkTo((sal_uInt16)pAction->GetOldErrorStart(), (sal_uInt16)pAction->GetOldErrorEnd(), false);
747             if(pAction->IsErrorLanguageSelected())
748             {
749                 UpdateBoxes_Impl();
750             }
751         }
752         break;
753         case SPELLUNDO_CHANGE_ADD_TO_DICTIONARY:
754         {
755             if(pAction->GetDictionary().is())
756                 pAction->GetDictionary()->remove(pAction->GetAddedWord());
757         }
758         break;
759         case SPELLUNDO_MOVE_ERROREND :
760         {
761             if(pAction->GetOffset() != 0)
762                 aSentenceED.MoveErrorEnd(pAction->GetOffset());
763         }
764         break;
765         case SPELLUNDO_UNDO_EDIT_MODE :
766         {
767             //refill the dialog with the currently spelled sentence - throw away all changes
768             SpellContinue_Impl(true);
769         }
770         break;
771         case SPELLUNDO_ADD_IGNORE_RULE:
772             //undo of ignored rules is not supported
773         break;
774     }
775 
776     return 0;
777 }
778 // -----------------------------------------------------------------------
779 void SpellDialog::Impl_Restore()
780 {
781     //clear the "ChangeAllList"
782     SvxGetChangeAllList()->clear();
783     //get a new sentence
784     aSentenceED.SetText(rtl::OUString());
785     aSentenceED.ResetModified();
786     SpellContinue_Impl();
787     aIgnorePB.SetText(aIgnoreOnceST);
788 }
789 
790 IMPL_LINK( SpellDialog, IgnoreHdl, Button *, EMPTYARG )
791 {
792     if(aIgnorePB.GetText() == aResumeST)
793     {
794         Impl_Restore();
795     }
796     else
797     {
798         //in case the error has been changed manually it has to be restored,
799         // since the users choice now was to ignore the error
800         aSentenceED.RestoreCurrentError();
801 
802         // the word is being ignored
803         SpellContinue_Impl( false, true );
804     }
805 	return 1;
806 }
807 
808 
809 // -----------------------------------------------------------------------
810 
811 sal_Bool SpellDialog::Close()
812 {
813     GetBindings().GetDispatcher()->
814         Execute(rParent.GetType(),
815         SFX_CALLMODE_ASYNCHRON|SFX_CALLMODE_RECORD);
816     return sal_True;
817 }
818 // -----------------------------------------------------------------------
819 
820 void SpellDialog::SetSelectedLang_Impl( LanguageType nLang )
821 {
822     aLanguageLB.SelectLanguage( nLang );
823 }
824 
825 // -----------------------------------------------------------------------
826 
827 LanguageType SpellDialog::GetSelectedLang_Impl() const
828 {
829     sal_Int16 nLang = aLanguageLB.GetSelectLanguage();
830 	return nLang;
831 }
832 /* -----------------28.10.2003 14:27-----------------
833 
834  --------------------------------------------------*/
835 IMPL_LINK(SpellDialog, LanguageSelectHdl, SvxLanguageBox*, pBox)
836 {
837     //if currently an error is selected then search for alternatives for
838     //this word and fill the alternatives ListBox accordingly
839     String sError = aSentenceED.GetErrorText();
840     aSuggestionLB.Clear();
841     if(sError.Len())
842     {
843         LanguageType eLanguage = pBox->GetSelectLanguage();
844         Reference <XSpellAlternatives> xAlt = xSpell->spell( sError, eLanguage,
845                                             Sequence< PropertyValue >() );
846         if( xAlt.is() )
847             aSentenceED.SetAlternatives( xAlt );
848         else
849         {
850             aSentenceED.ChangeMarkedWord( sError, eLanguage );
851             SpellContinue_Impl();
852         }
853 
854          aSentenceED.AddUndoAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_LANGUAGE, aDialogUndoLink));
855     }
856     SpellDialog::UpdateBoxes_Impl();
857     return 0;
858 }
859 // -----------------------------------------------------------------------
860 
861 void SpellDialog::SetLanguage( sal_uInt16 nLang )
862 
863 /*	[Beschreibung]
864 
865 	wenn die Sprache im Thesaurus umgestellt wurde,
866 	muss auch hier die Sprache umgestellt werden.
867 */
868 
869 {
870     SetTitle_Impl( nLang );
871 
872 	// den richtigen Eintrag finden, da sortiert
873     aLanguageLB.SelectLanguage( nLang );
874 }
875 /*-- 16.06.2008 11:27:02---------------------------------------------------
876 
877   -----------------------------------------------------------------------*/
878 static Image lcl_GetImageFromPngUrl( const ::rtl::OUString &rFileUrl )
879 {
880     Image aRes;
881     ::rtl::OUString aTmp;
882     osl::FileBase::getSystemPathFromFileURL( rFileUrl, aTmp );
883     Graphic aGraphic;
884     const String aFilterName( RTL_CONSTASCII_USTRINGPARAM( IMP_PNG ) );
885     if( GRFILTER_OK == GraphicFilter::LoadGraphic( aTmp, aFilterName, aGraphic ) )
886     {
887         aRes = Image( aGraphic.GetBitmapEx() );
888     }
889     return aRes;
890 }
891 void SpellDialog::SetTitle_Impl(LanguageType nLang)
892 {
893     String sTitle( m_sTitleSpelling );
894     if( rParent.HasGrammarChecking() )
895     {
896         String sVendor;
897         const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
898         if( pSpellErrorDescription && pSpellErrorDescription->sServiceName.getLength() )
899         {
900             bool bHighContrast = GetSettings().GetStyleSettings().GetHighContrastMode();
901             ::rtl::OUString sSuggestionImageUrl =
902                 SvtLinguConfig().GetSpellAndGrammarDialogImage( pSpellErrorDescription->sServiceName, bHighContrast );
903             aVendorImageFI.SetImage( lcl_GetImageFromPngUrl( sSuggestionImageUrl ) );
904             uno::Reference< lang::XServiceDisplayName > xDisplayName( pSpellErrorDescription->xGrammarChecker, uno::UNO_QUERY );
905             if( xDisplayName.is() )
906                 sVendor = xDisplayName->getServiceDisplayName( pSpellErrorDescription->aLocale );
907         }
908         else
909         {
910             bool bHighContrast = GetSettings().GetStyleSettings().GetHighContrastMode();
911             aVendorImageFI.SetImage( bHighContrast ? aVendorImageHC : aVendorImage );
912         }
913 
914         if( sVendor.Len() )
915         {
916             sTitle = m_sTitleSpellingGrammarVendor;
917             sTitle.SearchAndReplaceAscii( "$VendorName", sVendor );
918         }
919         else
920         {
921             //bool bHighContrast = GetSettings().GetStyleSettings().GetHighContrastMode();
922             sTitle = m_sTitleSpellingGrammar;
923         }
924     }
925     sTitle.SearchAndReplaceAscii( "$LANGUAGE ($LOCATION)", SvtLanguageTable::GetLanguageString(nLang) );
926     SetText( sTitle );
927 }
928 /*-------------------------------------------------------------------------
929 
930   -----------------------------------------------------------------------*/
931 void SpellDialog::InitUserDicts()
932 {
933     const LanguageType nLang = aLanguageLB.GetSelectLanguage();
934 
935 	const Reference< XDictionary >  *pDic = 0;
936 
937     // get list of dictionaries
938     Reference< XDictionaryList >  xDicList( SvxGetDictionaryList() );
939     if (xDicList.is())
940     {
941         // add active, positive dictionary to dic-list (if not already done).
942         // This is to ensure that there is at least on dictionary to which
943         // words could be added.
944         Reference< XDictionary >  xDic( SvxGetOrCreatePosDic( xDicList ) );
945         if (xDic.is())
946             xDic->setActive( sal_True );
947 
948         pImpl->aDics = xDicList->getDictionaries();
949     }
950 
951     SvtLinguConfig aCfg;
952     const bool bHC = Application::GetSettings().GetStyleSettings().GetHighContrastMode();
953 
954     // list suitable dictionaries
955     bool bEnable = false;
956     const sal_Int32 nSize = pImpl->aDics.getLength();
957     pDic = pImpl->aDics.getConstArray();
958     delete aAddToDictMB.GetPopupMenu();
959     PopupMenu* pMenu = new PopupMenu;
960     pMenu->SetMenuFlags(MENU_FLAG_NOAUTOMNEMONICS);
961     sal_uInt16 nItemId = 1;     // menu items should be enumerated from 1 and not 0
962     for (sal_Int32 i = 0; i < nSize; ++i)
963     {
964         uno::Reference< linguistic2::XDictionary >  xDicTmp( pDic[i], uno::UNO_QUERY );
965         if (!xDicTmp.is() || SvxGetIgnoreAllList() == xDicTmp)
966             continue;
967 
968         uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY );
969         LanguageType nActLanguage = SvxLocaleToLanguage( xDicTmp->getLocale() );
970         if( xDicTmp->isActive()
971             &&  xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
972             && (nLang == nActLanguage || LANGUAGE_NONE == nActLanguage )
973             && (!xStor.is() || !xStor->isReadonly()) )
974         {
975             pMenu->InsertItem( nItemId, xDicTmp->getName() );
976             bEnable = sal_True;
977 
978             uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY );
979             if (xSvcInfo.is())
980             {
981                 OUString aDictionaryImageUrl( aCfg.GetSpellAndGrammarContextDictionaryImage(
982                         xSvcInfo->getImplementationName(), bHC) );
983                 if (aDictionaryImageUrl.getLength() > 0)
984                 {
985                     Image aImage( lcl_GetImageFromPngUrl( aDictionaryImageUrl ) );
986                     pMenu->SetItemImage( nItemId, aImage );
987                 }
988             }
989 
990             ++nItemId;
991         }
992     }
993     aAddToDictMB.SetPopupMenu(pMenu);
994     aAddToDictMB.Enable( bEnable );
995 }
996 /*-- 20.10.2003 15:31:06---------------------------------------------------
997 
998   -----------------------------------------------------------------------*/
999 IMPL_LINK(SpellDialog, AddToDictionaryHdl, MenuButton*, pButton )
1000 {
1001     aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
1002 
1003     //GetErrorText() returns the current error even if the text is already
1004     //manually changed
1005     const String aNewWord= aSentenceED.GetErrorText();
1006 
1007     sal_uInt16 nItemId = pButton->GetCurItemId();
1008     PopupMenu *pMenu = pButton->GetPopupMenu();
1009     String aDicName ( pMenu->GetItemText( nItemId ) );
1010 
1011     uno::Reference< linguistic2::XDictionary >      xDic;
1012     uno::Reference< linguistic2::XDictionaryList >  xDicList( SvxGetDictionaryList() );
1013     if (xDicList.is())
1014         xDic = xDicList->getDictionaryByName( aDicName );
1015 
1016     sal_Int16 nAddRes = DIC_ERR_UNKNOWN;
1017     if (xDic.is())
1018     {
1019         nAddRes = linguistic::AddEntryToDic( xDic, aNewWord, sal_False, OUString(), LANGUAGE_NONE );
1020         // save modified user-dictionary if it is persistent
1021         uno::Reference< frame::XStorable >  xSavDic( xDic, uno::UNO_QUERY );
1022         if (xSavDic.is())
1023             xSavDic->store();
1024 
1025         if (nAddRes == DIC_ERR_NONE)
1026         {
1027             SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
1028                             SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
1029             pAction->SetDictionary( xDic );
1030             pAction->SetAddedWord( aNewWord );
1031             aSentenceED.AddUndoAction( pAction );
1032         }
1033         // failed because there is already an entry?
1034         if (DIC_ERR_NONE != nAddRes && xDic->getEntry( aNewWord ).is())
1035             nAddRes = DIC_ERR_NONE;
1036     }
1037     if (DIC_ERR_NONE != nAddRes)
1038     {
1039         SvxDicError( this, nAddRes );
1040         return 0;   // Nicht weitermachen
1041     }
1042 
1043     // go on
1044     SpellContinue_Impl();
1045     aSentenceED.UndoActionEnd();
1046     return 0;
1047 }
1048 /*-------------------------------------------------------------------------
1049 
1050   -----------------------------------------------------------------------*/
1051 IMPL_LINK(SpellDialog, ModifyHdl, SentenceEditWindow_Impl*, pEd)
1052 {
1053     if (&aSentenceED == pEd)
1054 	{
1055         bModified = true;
1056         aSuggestionLB.SetNoSelection();
1057         aSuggestionLB.Disable();
1058         String sNewText( aSentenceED.GetText() );
1059         aAutoCorrPB.Enable( sNewText != aSentenceED.GetText() );
1060         SpellUndoAction_Impl* pSpellAction = new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE, aDialogUndoLink);
1061         if(!aChangeAllPB.IsEnabled())
1062         {
1063             aChangeAllPB.Enable();
1064             pSpellAction->SetEnableChangeAllPB();
1065         }
1066         if(!aChangePB.IsEnabled())
1067         {
1068             aChangePB.Enable();
1069             pSpellAction->SetEnableChangePB();
1070         }
1071         aSentenceED.AddUndoAction(pSpellAction);
1072 	}
1073 	return 0;
1074 };
1075 /*-------------------------------------------------------------------------
1076 
1077   -----------------------------------------------------------------------*/
1078 IMPL_LINK(SpellDialog, CancelHdl, Button *, EMPTYARG )
1079 {
1080     //apply changes and ignored text parts first - if there are any
1081     rParent.ApplyChangedSentence(aSentenceED.CreateSpellPortions(true), false);
1082     Close();
1083 	return 0;
1084 }
1085 /*-------------------------------------------------------------------------
1086 
1087   -----------------------------------------------------------------------*/
1088 void SpellDialog::Paint( const Rectangle& rRect )
1089 {
1090     ModelessDialog::Paint(rRect );
1091     Rectangle aRect(aBackgroundGB.GetPosPixel(), aBackgroundGB.GetSizePixel());
1092     DecorationView aDecoView( this );
1093     aDecoView.DrawButton( aRect, BUTTON_DRAW_NOFILL);
1094 }
1095 /*-- 28.10.2003 13:26:39---------------------------------------------------
1096 
1097   -----------------------------------------------------------------------*/
1098 long SpellDialog::Notify( NotifyEvent& rNEvt )
1099 {
1100     /* #i38338#
1101     *   FIXME: LoseFocus and GetFocus are signals from vcl that
1102     *   a window actually got/lost the focus, it never should be
1103     *   forwarded from another window, that is simply wrong.
1104     *   FIXME: overloading the virtual methods GetFocus and LoseFocus
1105     *   in SpellDialogChildWindow by making them pure is at least questionable.
1106     *   The only sensible thing would be to call the new Method differently,
1107     *   e.g. DialogGot/LostFocus or so.
1108     */
1109     if( IsVisible() && !bFocusLocked )
1110     {
1111         if( rNEvt.GetType() ==  EVENT_GETFOCUS )
1112         {
1113             //notify the child window of the focus change
1114             rParent.GetFocus();
1115         }
1116         else if( rNEvt.GetType() == EVENT_LOSEFOCUS )
1117         {
1118             //notify the child window of the focus change
1119             rParent.LoseFocus();
1120         }
1121     }
1122     return SfxModelessDialog::Notify(rNEvt);
1123 }
1124 /* -----------------10.09.2003 08:26-----------------
1125 
1126  --------------------------------------------------*/
1127 void SpellDialog::InvalidateDialog()
1128 {
1129     if( bFocusLocked )
1130         return;
1131     aIgnorePB.SetText(aResumeST);
1132     Window* aDisableArr[] =
1133             {
1134                 &aNotInDictFT,
1135                 &aSentenceED,
1136                 &aSuggestionFT,
1137                 &aSuggestionLB,
1138                 &aLanguageFT,
1139                 &aLanguageLB,
1140                 &aIgnoreAllPB,
1141                 &aIgnoreRulePB,
1142                 &aAddToDictMB,
1143                 &aChangePB,
1144                 &aChangeAllPB,
1145                 &aAutoCorrPB,
1146                 &aUndoPB,
1147                 0
1148             };
1149     sal_Int16 i = 0;
1150 	while(aDisableArr[i])
1151     {
1152         aDisableArr[i]->Enable(sal_False);
1153         i++;
1154     }
1155     SfxModelessDialog::Deactivate();
1156 }
1157 
1158 /*-- 10.09.2003 08:35:56---------------------------------------------------
1159 
1160   -----------------------------------------------------------------------*/
1161 bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence, bool bRecheck)
1162 {
1163     bool bRet = false;
1164     if(!bUseSavedSentence /*&& aSentenceED.IsModified()*/)
1165     {
1166         //apply changes and ignored text parts
1167         rParent.ApplyChangedSentence(aSentenceED.CreateSpellPortions(true), bRecheck);
1168     }
1169     aSentenceED.ResetIgnoreErrorsAt();
1170     aSentenceED.ResetModified();
1171     SpellPortions aSentence = bUseSavedSentence ? m_aSavedSentence : rParent.GetNextWrongSentence( bRecheck );
1172     if(!bUseSavedSentence)
1173         m_aSavedSentence = aSentence;
1174     bool bHasReplaced = false;
1175     while(aSentence.size())
1176     {
1177         //apply all changes that are already part of the "ChangeAllList"
1178         //returns true if the list still contains errors after the changes have been applied
1179 
1180         if(!ApplyChangeAllList_Impl(aSentence, bHasReplaced))
1181         {
1182             rParent.ApplyChangedSentence(aSentence, bRecheck);
1183 			aSentence = rParent.GetNextWrongSentence( bRecheck );
1184         }
1185 		else
1186             break;
1187     }
1188 
1189     if(aSentence.size())
1190     {
1191         SpellPortions::iterator aStart = aSentence.begin();
1192         rtl::OUString sText;
1193         while(aStart != aSentence.end())
1194         {
1195             // hidden text has to be ignored
1196             if(!aStart->bIsHidden)
1197                 sText += aStart->sText;
1198             aStart++;
1199         }
1200         aSentenceED.SetText(sText);
1201         aStart = aSentence.begin();
1202         sal_Int32 nStartPosition = 0;
1203         sal_Int32 nEndPosition = 0;
1204 
1205         while(aStart != aSentence.end())
1206         {
1207             // hidden text has to be ignored
1208             if(!aStart->bIsHidden)
1209             {
1210                 nEndPosition += aStart->sText.getLength();
1211                 if(aStart->xAlternatives.is())
1212                 {
1213                     uno::Reference< container::XNamed > xNamed( aStart->xAlternatives, uno::UNO_QUERY );
1214                     ::rtl::OUString sServiceName;
1215                     if( xNamed.is() )
1216                         sServiceName = xNamed->getName();
1217                     SpellErrorDescription aDesc( false, aStart->xAlternatives->getWord(),
1218                                     aStart->xAlternatives->getLocale(), aStart->xAlternatives->getAlternatives(), 0, sServiceName);
1219                     aSentenceED.SetAttrib( SpellErrorAttrib(aDesc), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
1220                 }
1221                 else if(aStart->bIsGrammarError )
1222                 {
1223                     uno::Reference< lang::XServiceInfo > xInfo( aStart->xGrammarChecker, uno::UNO_QUERY );
1224                     SpellErrorDescription aDesc( true,
1225                         aStart->sText,
1226 						SvxCreateLocale( aStart->eLanguage ),
1227                         aStart->aGrammarError.aSuggestions,
1228                         aStart->xGrammarChecker,
1229                         xInfo->getImplementationName(),
1230                         &aStart->sDialogTitle,
1231                         &aStart->aGrammarError.aFullComment,
1232                         &aStart->aGrammarError.aRuleIdentifier );
1233                     aSentenceED.SetAttrib( SpellErrorAttrib(aDesc), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
1234                 }
1235                 if(aStart->bIsField)
1236                     aSentenceED.SetAttrib( SpellBackgroundAttrib(COL_LIGHTGRAY), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
1237                 aSentenceED.SetAttrib( SpellLanguageAttrib(aStart->eLanguage), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
1238                 nStartPosition = nEndPosition;
1239             }
1240             aStart++;
1241         }
1242         //the edit field needs to be modified to apply the change from the ApplyChangeAllList
1243         if(!bHasReplaced)
1244             aSentenceED.ClearModifyFlag();
1245         aSentenceED.ResetUndo();
1246         aUndoPB.Enable(sal_False);
1247         bRet = nStartPosition > 0;
1248     }
1249     return bRet;
1250 }
1251 /*-- 12.11.2003 15:21:25---------------------------------------------------
1252     replace errrors that have a replacement in the ChangeAllList
1253     returns false if the result doesn't contain errors after the replacement
1254   -----------------------------------------------------------------------*/
1255 bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions& rSentence, bool &bHasReplaced)
1256 {
1257     bHasReplaced = false;
1258     bool bRet = true;
1259     SpellPortions::iterator aStart = rSentence.begin();
1260     Reference<XDictionary> xChangeAll( SvxGetChangeAllList(), UNO_QUERY );
1261     if(!xChangeAll->getCount())
1262         return bRet;
1263     bRet = false;
1264     while(aStart != rSentence.end())
1265     {
1266         if(aStart->xAlternatives.is())
1267         {
1268             Reference<XDictionaryEntry> xEntry = xChangeAll->getEntry( aStart->sText );
1269             if(xEntry.is())
1270             {
1271                 aStart->sText = xEntry->getReplacementText();
1272                 aStart->xAlternatives = 0;
1273                 bHasReplaced = true;
1274             }
1275             else
1276                 bRet = true;
1277         }
1278         else if( aStart->bIsGrammarError )
1279             bRet = true;
1280         aStart++;
1281     }
1282     return bRet;
1283 }
1284 /*-- 10.09.2003 10:40:21---------------------------------------------------
1285 
1286   -----------------------------------------------------------------------*/
1287 SentenceEditWindow_Impl::SentenceEditWindow_Impl( SpellDialog* pParent, const ResId& rResId ) :
1288     MultiLineEdit( pParent, rResId ),
1289     m_nErrorStart(0),
1290     m_nErrorEnd(0),
1291     m_bIsUndoEditMode(false)
1292 {
1293     DisableSelectionOnFocus();
1294 }
1295 /*-- 10.09.2003 10:40:11---------------------------------------------------
1296 
1297   -----------------------------------------------------------------------*/
1298 SentenceEditWindow_Impl::~SentenceEditWindow_Impl()
1299 {
1300 }
1301 /*-- 20.10.2003 13:42:34---------------------------------------------------
1302     The selection before inputting a key may have a range or not
1303     and it may be inside or outside of field or error attributes.
1304     A range may include the attribute partially, completely or together
1305     with surrounding text. It may also contain more than one attribute
1306     or no attribute at all.
1307     Depending on this starting conditions some actions are necessary:
1308     Attempts to delete a field are only allowed if the selection is the same
1309     as the field's selection. Otherwise the field has to be selected and the key
1310     input action has to be skipped.
1311     Input of text at the start of the field requires the field attribute to be
1312     corrected - it is not allowed to grow.
1313 
1314     In case of errors the appending of text should grow the error attribute because
1315     that is what the user usually wants to do.
1316 
1317     Backspace at the start of the attribute requires to find out if a field ends
1318     directly in front of the cursor position. In case of a field this attribute has to be
1319     selected otherwise the key input method is allowed.
1320 
1321     All changes outside of the error attributes switch the dialog mode to a "Undo edit" state that
1322     removes all visible attributes and switches off further attribute checks.
1323     Undo in this restarts the dialog with a current sentence newly presented.
1324     All changes to the sentence are undone including the ones before the "Undo edit state" has been reached
1325 
1326     We end up with 9 types of selection
1327     1 (LEFT_NO)     - no range, start of attribute - can also be 3 at the same time
1328     2 (INSIDE_NO)   - no range, inside of attribute
1329     3 (RIGHT_NO)    - no range, end of attribute - can also be 1 at the same time
1330     4 (FULL)        - range, same as attribute
1331     5 (INSIDE_YES)  - range, inside of the attribute
1332     6 (BRACE)- range, from outside of the attribute to the inside or
1333                 including the complete attribute and something outside,
1334                 maybe more than one attribute
1335     7 (OUTSIDE_NO)  - no range, not at an attribute
1336     8 (OUTSIDE_YES) - range, completely outside of all attributes
1337 
1338     What has to be done depending on the attribute type involved
1339     possible actions:   UE - Undo edit mode
1340                         CO - Continue, no additional action is required
1341                         FS - Field has to be completely selected
1342                         EX - The attribute has to be expanded to include the added text
1343 
1344     1 - backspace                   delete                      any other
1345         UE                          on field FS on error CO     on field FS on error CO
1346 
1347     2 - on field FS on error C
1348     3 - backspace                   delete                      any other
1349         on field FS on error CO     UE                          on field UE on error EX
1350 
1351     if 1 and 3 happen to apply both then backspace and other handling is 1 delete is 3
1352 
1353     4 - on field UE and on error CO
1354     5 - on field FS and on error CO
1355     6 - on field FS and on error UE
1356     7 - UE
1357     8 - UE
1358   -----------------------------------------------------------------------*/
1359 #define     INVALID     0
1360 #define     LEFT_NO     1
1361 #define     INSIDE_NO   2
1362 #define     RIGHT_NO    3
1363 #define     FULL        4
1364 #define     INSIDE_YES  5
1365 #define     BRACE       6
1366 #define     OUTSIDE_NO  7
1367 #define     OUTSIDE_YES 8
1368 
1369 #define ACTION_UNDOEDIT    0
1370 #define ACTION_CONTINUE    1
1371 #define ACTION_SELECTFIELD 2
1372 #define ACTION_EXPAND      3
1373 
1374 long SentenceEditWindow_Impl::PreNotify( NotifyEvent& rNEvt )
1375 {
1376     bool bChange = false;
1377     const TextCharAttrib*  pErrorAttrib = 0;
1378     if(rNEvt.GetType() == EVENT_KEYINPUT)
1379     {
1380         const KeyEvent& rKeyEvt = *rNEvt.GetKeyEvent();
1381         bChange = TextEngine::DoesKeyChangeText( rKeyEvt );
1382         if(bChange && !IsUndoEditMode() &&
1383             rKeyEvt.GetKeyCode().GetCode() != KEY_TAB)
1384         {
1385             TextEngine* pTextEngine = GetTextEngine();
1386             TextView* pTextView = pTextEngine->GetActiveView();
1387             const TextSelection& rCurrentSelection = pTextView->GetSelection();
1388             //determine if the selection contains a field
1389             bool bHasField = false;
1390             bool bHasError = false;
1391             bool bHasFieldLeft = false;
1392             bool bHasErrorLeft = false;
1393 //            bool bInsideAttr = false;
1394 
1395             bool bHasRange = rCurrentSelection.HasRange();
1396             sal_uInt8 nSelectionType = 0; // invalid type!
1397 
1398             TextPaM aCursor(rCurrentSelection.GetStart());
1399             const TextCharAttrib* pBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
1400             const TextCharAttrib* pErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
1401             const TextCharAttrib* pBackAttrLeft = 0;
1402             const TextCharAttrib* pErrorAttrLeft = 0;
1403 
1404             bHasField = pBackAttr != 0 && (bHasRange || pBackAttr->GetEnd() > aCursor.GetIndex());
1405             bHasError = pErrorAttr != 0 && (bHasRange || pErrorAttr->GetEnd() > aCursor.GetIndex());
1406             if(bHasRange)
1407             {
1408                 if(pBackAttr &&
1409                         pBackAttr->GetStart() == rCurrentSelection.GetStart().GetIndex() &&
1410                         pBackAttr->GetEnd() == rCurrentSelection.GetEnd().GetIndex())
1411                 {
1412                     nSelectionType = FULL;
1413                 }
1414                 else if(pErrorAttr &&
1415                         pErrorAttr->GetStart() <= rCurrentSelection.GetStart().GetIndex() &&
1416                         pErrorAttr->GetEnd() >= rCurrentSelection.GetEnd().GetIndex())
1417                 {
1418                     nSelectionType = INSIDE_YES;
1419                 }
1420                 else
1421                 {
1422                     nSelectionType = bHasField||bHasError ? BRACE : OUTSIDE_NO;
1423                     while(aCursor.GetIndex() < rCurrentSelection.GetEnd().GetIndex())
1424                     {
1425                         ++aCursor.GetIndex();
1426                         const TextCharAttrib* pIntBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
1427                         const TextCharAttrib* pIntErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
1428                         //if any attr has been found then BRACE
1429                         if(pIntBackAttr || pIntErrorAttr)
1430                             nSelectionType = BRACE;
1431                         //the field has to be selected
1432                         if(pIntBackAttr && !pBackAttr)
1433                             pBackAttr = pIntBackAttr;
1434                         bHasField |= pIntBackAttr != 0;
1435                     }
1436                 }
1437             }
1438             else
1439             {
1440                 //no range selection: then 1 2 3 and 8 are possible
1441                 const TextCharAttrib* pCurAttr = pBackAttr ? pBackAttr : pErrorAttr;
1442                 if(pCurAttr)
1443                 {
1444                     nSelectionType = pCurAttr->GetStart() == rCurrentSelection.GetStart().GetIndex() ?
1445                             LEFT_NO : pCurAttr->GetEnd() == rCurrentSelection.GetEnd().GetIndex() ? RIGHT_NO : INSIDE_NO;
1446                 }
1447                 else
1448                     nSelectionType = OUTSIDE_NO;
1449 
1450                 bHasFieldLeft = pBackAttr && pBackAttr->GetEnd() == aCursor.GetIndex();
1451 				if(bHasFieldLeft)
1452 				{
1453 					pBackAttrLeft = pBackAttr;
1454 					pBackAttr = 0;
1455 				}
1456                 bHasErrorLeft = pErrorAttr && pErrorAttr->GetEnd() == aCursor.GetIndex();
1457 				if(bHasErrorLeft)
1458 				{
1459 					pErrorAttrLeft = pErrorAttr;
1460 					pErrorAttr = 0;
1461 				}
1462 
1463                 //check previous position if this exists
1464 				//that is a redundant in the case the the attribute found above already is on the left cursor side
1465 				//but it's o.k. for two errors/fields side by side
1466                 if(aCursor.GetIndex())
1467                 {
1468                     --aCursor.GetIndex();
1469                     pBackAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
1470                     pErrorAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
1471                     bHasFieldLeft = pBackAttrLeft !=0;
1472                     bHasErrorLeft = pErrorAttrLeft != 0;
1473 //                    bInsideAttr = (bHasField || bHasError) && (bHasFieldLeft || bHasErrorLeft);
1474                     ++aCursor.GetIndex();
1475                 }
1476             }
1477 			//Here we have to determine if the error found is the one currently active
1478 			bool bIsErrorActive = (pErrorAttr && pErrorAttr->GetStart() == m_nErrorStart) ||
1479 					(pErrorAttrLeft && pErrorAttrLeft->GetStart() == m_nErrorStart);
1480 
1481             DBG_ASSERT(nSelectionType != INVALID, "selection type not set!");
1482 
1483             const KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
1484             bool bDelete = rKeyCode.GetCode() == KEY_DELETE;
1485             bool bBackspace = rKeyCode.GetCode() == KEY_BACKSPACE;
1486 
1487             sal_Int8 nAction = ACTION_CONTINUE;
1488 //            nAction = ACTION_UNDOEDIT
1489 //            nAction = ACTION_SELECTFIELD
1490 //            nAction = ACTION_EXPAND
1491             switch(nSelectionType)
1492             {
1493 //    1 - backspace                   delete                      any other
1494 //        UE                          on field FS on error CO     on field FS on error CO
1495                 case LEFT_NO    :
1496                     if(bBackspace)
1497                     {
1498                         nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
1499                         //to force the use of pBackAttrLeft
1500                         pBackAttr = 0;
1501                     }
1502                     else if(bDelete)
1503 						nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1504 					else
1505 						nAction = bHasError && !aCursor.GetIndex() ? ACTION_CONTINUE :
1506 							bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1507                 break;
1508 //    2 - on field FS on error C
1509                 case INSIDE_NO  :
1510                     nAction =  bHasField ? ACTION_SELECTFIELD :
1511                         bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1512                 break;
1513 //    3 - backspace                   delete                      any other
1514 //        on field FS on error CO     UE                          on field UE on error EX
1515                 case RIGHT_NO   :
1516                     if(bBackspace)
1517                         nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1518                     else if(bDelete)
1519 						nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1520 					else
1521 						nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
1522 							bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT;
1523                 break;
1524 //    4 - on field UE and on error CO
1525                 case FULL       :
1526                     nAction = bHasField ? ACTION_UNDOEDIT : ACTION_CONTINUE;
1527                 break;
1528 //    5 - on field FS and on error CO
1529                 case INSIDE_YES :
1530                     nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1531                 break;
1532 //    6 - on field FS and on error UE
1533                 case BRACE      :
1534                     nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;;
1535                 break;
1536 //    7 - UE
1537 //    8 - UE
1538                 case OUTSIDE_NO :
1539                 case OUTSIDE_YES:
1540                     nAction = ACTION_UNDOEDIT;
1541                 break;
1542             }
1543 			//save the current paragraph
1544 			sal_uInt16 nCurrentLen = GetText().Len();
1545             if(nAction != ACTION_SELECTFIELD)
1546                 pTextView->GetWindow()->KeyInput(rKeyEvt);
1547             else
1548             {
1549                 const TextCharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft;
1550                 if(pCharAttr)
1551                 {
1552                     TextPaM aStart(0, pCharAttr->GetStart());
1553                     TextPaM aEnd(0, pCharAttr->GetEnd());
1554                     TextSelection aNewSel(aStart, aEnd);
1555                     pTextView->SetSelection( aNewSel);
1556                 }
1557             }
1558             if(nAction == ACTION_EXPAND)
1559             {
1560                 DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error");
1561                 //text has been added on the right and only the 'error attribute has to be corrected
1562 				if(pErrorAttrLeft)
1563                 {
1564                     TextAttrib* pNewError =  pErrorAttrLeft->GetAttr().Clone();
1565                     sal_uInt16 nStart = pErrorAttrLeft->GetStart();
1566                     sal_uInt16 nEnd = pErrorAttrLeft->GetEnd();
1567                     pTextEngine->RemoveAttrib( 0, *pErrorAttrLeft );
1568                     SetAttrib( *pNewError, 0, nStart, ++nEnd );
1569                     //only active errors move the mark
1570 					if(bIsErrorActive)
1571                     {
1572                         bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
1573                         MoveErrorMarkTo(nStart, nEnd, bGrammar);
1574                     }
1575                     delete pNewError;
1576                 }
1577 				//text has been added on the left then the error attribute has to be expanded and the
1578 				//field attribute on the right - if any - has to be contracted
1579 				else if(pErrorAttr)
1580 				{
1581 					//determine the change
1582 					sal_uInt16 nAddedChars = GetText().Len() - nCurrentLen;
1583 
1584                     TextAttrib* pNewError =  pErrorAttr->GetAttr().Clone();
1585                     sal_uInt16 nStart = pErrorAttr->GetStart();
1586                     sal_uInt16 nEnd = pErrorAttr->GetEnd();
1587                     pTextEngine->RemoveAttrib( 0, *pErrorAttr );
1588                     nStart = nStart - (sal_uInt16)nAddedChars;
1589 					SetAttrib( *pNewError, 0, nStart - nAddedChars, nEnd );
1590                     //only if the error is active the mark is moved here
1591 					if(bIsErrorActive)
1592                     {
1593                         bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
1594                         MoveErrorMarkTo(nStart, nEnd, bGrammar);
1595                     }
1596                     delete pNewError;
1597 
1598 					if(pBackAttrLeft)
1599 					{
1600 						TextAttrib* pNewBack =  pBackAttrLeft->GetAttr().Clone();
1601                         sal_uInt16 _nStart = pBackAttrLeft->GetStart();
1602                         sal_uInt16 _nEnd = pBackAttrLeft->GetEnd();
1603 						pTextEngine->RemoveAttrib( 0, *pBackAttrLeft );
1604                         SetAttrib( *pNewBack, 0, _nStart, _nEnd - nAddedChars);
1605 						delete pNewBack;
1606 					}
1607 				}
1608             }
1609             else if(nAction == ACTION_UNDOEDIT)
1610             {
1611                 SetUndoEditMode(true);
1612             }
1613             //make sure the error positions are correct after text changes
1614             //the old attribute may have been deleted
1615             //all changes inside of the current error leave the error attribute at the current
1616             //start position
1617             if(!IsUndoEditMode() && bIsErrorActive)
1618             {
1619                 const TextCharAttrib* pFontColor = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_FONTCOLOR );
1620                 pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
1621                 if(pFontColor && pErrorAttrib )
1622                 {
1623                     m_nErrorStart = pFontColor->GetStart();
1624                     m_nErrorEnd = pFontColor->GetEnd();
1625                     if(pErrorAttrib->GetStart() != m_nErrorStart || pErrorAttrib->GetEnd() != m_nErrorEnd)
1626                     {
1627                         TextAttrib* pNewError =  pErrorAttrib->GetAttr().Clone();
1628                         pTextEngine->RemoveAttrib( 0, *pErrorAttr );
1629                         SetAttrib( *pNewError, 0, m_nErrorStart, m_nErrorEnd );
1630                         delete pNewError;
1631                     }
1632                 }
1633             }
1634             //this is not a modification anymore
1635 			if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
1636 				CallModifyLink();
1637         }
1638 		else
1639 			bChange = false;
1640     }
1641     long nRet = bChange ? 1 : MultiLineEdit::PreNotify(rNEvt);
1642     return nRet;
1643 }
1644 /*-- 10.09.2003 13:38:14---------------------------------------------------
1645 
1646   -----------------------------------------------------------------------*/
1647 bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError )
1648 {
1649     if (bIgnoreCurrentError)
1650         m_aIgnoreErrorsAt.insert( m_nErrorStart );
1651     ExtTextEngine* pTextEngine = GetTextEngine();
1652     sal_uInt16 nTextLen = pTextEngine->GetTextLen(0);
1653     if(m_nErrorEnd >= nTextLen - 1)
1654         return false;
1655 	//if it's not already modified the modified flag has to be reset at the and of the marking
1656     bool bModified = IsModified();
1657     bool bRet = false;
1658     const sal_uInt16 nOldErrorStart = m_nErrorStart;
1659     const sal_uInt16 nOldErrorEnd   = m_nErrorEnd;
1660 
1661     //create a cursor behind the end of the last error
1662 	//- or at 0 at the start of the sentence
1663     TextPaM aCursor(0, m_nErrorEnd ? m_nErrorEnd + 1 : 0);
1664     //search for SpellErrorAttrib
1665 
1666     const TextCharAttrib* pNextError = 0;
1667     //iterate over the text and search for the next error that maybe has
1668     //to be replace by a ChangeAllList replacement
1669     bool bGrammarError = false;
1670     while(aCursor.GetIndex() < nTextLen)
1671     {
1672         while(aCursor.GetIndex() < nTextLen &&
1673                 0 == (pNextError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR)))
1674         {
1675             ++aCursor.GetIndex();
1676         }
1677         // maybe the error found here is already in the ChangeAllList and has to be replaced
1678 
1679         Reference<XDictionary> xChangeAll( SvxGetChangeAllList(), UNO_QUERY );
1680         Reference<XDictionaryEntry> xEntry;
1681 
1682 //        Reference <XSpellAlternatives> xAlternatives;
1683         const SpellErrorDescription* pSpellErrorDescription = 0;
1684         if(pNextError)
1685         {
1686             pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pNextError->GetAttr()).GetErrorDescription();
1687             bGrammarError = pSpellErrorDescription->bIsGrammarError;
1688         }
1689         if(xChangeAll->getCount() && pSpellErrorDescription &&
1690                 (xEntry = xChangeAll->getEntry( pSpellErrorDescription->sErrorText )).is())
1691         {
1692             m_nErrorStart = pNextError->GetStart();
1693             m_nErrorEnd = pNextError->GetEnd();
1694             ChangeMarkedWord(xEntry->getReplacementText(),
1695                     SvxLocaleToLanguage( pSpellErrorDescription->aLocale ));
1696             aCursor.GetIndex() = aCursor.GetIndex() + (sal_uInt16)(xEntry->getReplacementText().getLength());
1697         }
1698 		else
1699 			break;
1700     }
1701 
1702     //if an attrib has been found search for the end of the error string
1703     if(aCursor.GetIndex() < nTextLen)
1704     {
1705         m_nErrorStart = aCursor.GetIndex();
1706         m_nErrorEnd = pNextError->GetEnd();
1707         MoveErrorMarkTo(m_nErrorStart, m_nErrorEnd, bGrammarError);
1708         bRet = true;
1709 		//add an undo action
1710         SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
1711                 SPELLUNDO_CHANGE_NEXTERROR, GetSpellDialog()->aDialogUndoLink);
1712         pAction->SetErrorMove(m_nErrorStart, m_nErrorEnd, nOldErrorStart, nOldErrorEnd);
1713         const SpellErrorAttrib* pOldAttrib = static_cast<const SpellErrorAttrib*>(
1714                 pTextEngine->FindAttrib( TextPaM(0, nOldErrorStart), TEXTATTR_SPELL_ERROR ));
1715         pAction->SetErrorLanguageSelected(pOldAttrib && pOldAttrib->GetErrorDescription().aSuggestions.getLength() &&
1716                 SvxLocaleToLanguage( pOldAttrib->GetErrorDescription().aLocale) ==
1717                                         GetSpellDialog()->aLanguageLB.GetSelectLanguage());
1718         AddUndoAction(pAction);
1719     }
1720     else
1721         m_nErrorStart = m_nErrorEnd = nTextLen;
1722     if( !bModified )
1723         ClearModifyFlag();
1724     SpellDialog* pSpellDialog = GetSpellDialog();
1725     pSpellDialog->aIgnorePB.Enable(bRet);
1726     pSpellDialog->aIgnoreAllPB.Enable(bRet);
1727     pSpellDialog->aAutoCorrPB.Enable(bRet);
1728     pSpellDialog->aAddToDictMB.Enable(bRet);
1729 	return bRet;
1730 }
1731 
1732 /*-- 06.11.2003 13:30:26---------------------------------------------------
1733 
1734   -----------------------------------------------------------------------*/
1735 void SentenceEditWindow_Impl::MoveErrorMarkTo(sal_uInt16 nStart, sal_uInt16 nEnd, bool bGrammarError)
1736 {
1737     TextEngine* pTextEngine = GetTextEngine();
1738     pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTCOLOR, sal_True );
1739     pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTWEIGHT, sal_True );
1740     pTextEngine->SetAttrib( TextAttribFontWeight(WEIGHT_BOLD), 0, nStart, nEnd );
1741     pTextEngine->SetAttrib( TextAttribFontColor(bGrammarError ? COL_LIGHTBLUE : COL_LIGHTRED), 0, nStart, nEnd );
1742     m_nErrorStart = nStart;
1743     m_nErrorEnd = nEnd;
1744 }
1745 
1746 /*-- 17.09.2003 10:13:08---------------------------------------------------
1747 
1748   -----------------------------------------------------------------------*/
1749 void SentenceEditWindow_Impl::ChangeMarkedWord(const String& rNewWord, LanguageType eLanguage)
1750 {
1751     //calculate length changes
1752     long nDiffLen = rNewWord.Len() - m_nErrorEnd + m_nErrorStart;
1753     TextSelection aSel(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd));
1754     //Remove spell errror attribute
1755     ExtTextEngine* pTextEngine = GetTextEngine();
1756     pTextEngine->UndoActionStart();
1757     const TextCharAttrib*  pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
1758     DBG_ASSERT(pErrorAttrib, "no error attribute found");
1759 //  Reference <XSpellAlternatives> xAlternatives;
1760     const SpellErrorDescription* pSpellErrorDescription = 0;
1761     if(pErrorAttrib)
1762 	{
1763         pTextEngine->RemoveAttrib(0, *pErrorAttrib);
1764         pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pErrorAttrib->GetAttr()).GetErrorDescription();
1765 	}
1766     const TextCharAttrib*  pBackAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_BACKGROUND );
1767     pTextEngine->ReplaceText( aSel, rNewWord );
1768     //
1769     if(!m_nErrorStart)
1770     {
1771         //attributes following an error at the start of the text are not moved but expanded from the
1772         //text engine - this is done to keep full-paragraph-attributes
1773         //in the current case that handling is not desired
1774         const TextCharAttrib*  pLangAttrib =
1775                 pTextEngine->FindCharAttrib(
1776                     TextPaM(0, m_nErrorEnd), TEXTATTR_SPELL_LANGUAGE );
1777         sal_uInt16 nTextLen = pTextEngine->GetTextLen( 0 );
1778         if(pLangAttrib && !pLangAttrib->GetStart() && pLangAttrib->GetEnd() ==
1779             nTextLen)
1780         {
1781             SpellLanguageAttrib aNewLangAttrib( static_cast<const SpellLanguageAttrib&>(pLangAttrib->GetAttr()).GetLanguage());
1782             pTextEngine->RemoveAttrib(0, *pLangAttrib);
1783             pTextEngine->SetAttrib( aNewLangAttrib, 0, (sal_uInt16)(m_nErrorEnd + nDiffLen) , nTextLen );
1784         }
1785     }
1786 	// undo expanded attributes!
1787 	if( pBackAttrib && pBackAttrib->GetStart() < m_nErrorStart && pBackAttrib->GetEnd() == m_nErrorEnd + nDiffLen)
1788 	{
1789 		TextAttrib* pNewBackground = pBackAttrib->GetAttr().Clone();
1790         sal_uInt16 nStart = pBackAttrib->GetStart();
1791 		pTextEngine->RemoveAttrib(0, *pBackAttrib);
1792 		pTextEngine->SetAttrib(*pNewBackground, 0, nStart, m_nErrorStart);
1793 		delete pNewBackground;
1794 	}
1795     pTextEngine->SetModified(sal_True);
1796 
1797     //adjust end position
1798     long nEndTemp = m_nErrorEnd;
1799     nEndTemp += nDiffLen;
1800     m_nErrorEnd = (sal_uInt16)nEndTemp;
1801 
1802     SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
1803                     SPELLUNDO_MOVE_ERROREND, GetSpellDialog()->aDialogUndoLink);
1804     pAction->SetOffset(nDiffLen);
1805     AddUndoAction(pAction);
1806     if(pSpellErrorDescription)
1807         SetAttrib( SpellErrorAttrib(*pSpellErrorDescription), 0, m_nErrorStart, m_nErrorEnd );
1808     SetAttrib( SpellLanguageAttrib(eLanguage), 0, m_nErrorStart, m_nErrorEnd );
1809     pTextEngine->UndoActionEnd();
1810 }
1811 /* -----------------08.10.2003 13:18-----------------
1812 
1813  --------------------------------------------------*/
1814 String SentenceEditWindow_Impl::GetErrorText() const
1815 {
1816     return GetTextEngine()->GetText(TextSelection(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd) ));
1817 }
1818 /*-- 26.06.2008 10:54:13---------------------------------------------------
1819 
1820   -----------------------------------------------------------------------*/
1821 const SpellErrorDescription* SentenceEditWindow_Impl::GetAlternatives()
1822 {
1823     TextPaM aCursor(0, m_nErrorStart);
1824     const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
1825             GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
1826     return pAttrib ? &pAttrib->GetErrorDescription() : 0;
1827 }
1828 /*-- 06.09.2004 10:50:32---------------------------------------------------
1829 
1830   -----------------------------------------------------------------------*/
1831 void SentenceEditWindow_Impl::RestoreCurrentError()
1832 {
1833     TextPaM aCursor(0, m_nErrorStart);
1834     const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
1835             GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
1836     if( pAttrib )
1837     {
1838         const SpellErrorDescription& rDesc = pAttrib->GetErrorDescription();
1839         if( !rDesc.sErrorText.equals( GetErrorText() ) )
1840             ChangeMarkedWord(rDesc.sErrorText, SvxLocaleToLanguage( rDesc.aLocale ));
1841     }
1842 }
1843 /*-- 28.10.2003 14:44:10---------------------------------------------------
1844 
1845   -----------------------------------------------------------------------*/
1846 void SentenceEditWindow_Impl::SetAlternatives( Reference< XSpellAlternatives> xAlt )
1847 {
1848     TextPaM aCursor(0, m_nErrorStart);
1849     DBG_ASSERT(static_cast<const SpellErrorAttrib*>(
1850             GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR)), "no error set?");
1851 
1852 	::rtl::OUString	aWord;
1853 	lang::Locale	aLocale;
1854 	uno::Sequence< ::rtl::OUString >	aAlts;
1855     ::rtl::OUString sServiceName;
1856 	if (xAlt.is())
1857 	{
1858 		aWord	= xAlt->getWord();
1859 		aLocale	= xAlt->getLocale();
1860 		aAlts	= xAlt->getAlternatives();
1861         uno::Reference< container::XNamed > xNamed( xAlt, uno::UNO_QUERY );
1862 		if (xNamed.is())
1863 			sServiceName = xNamed->getName();
1864 	}
1865     SpellErrorDescription aDesc( false, aWord, aLocale, aAlts, 0, sServiceName);
1866     GetTextEngine()->SetAttrib( SpellErrorAttrib(aDesc), 0, m_nErrorStart, m_nErrorEnd );
1867 }
1868 
1869 /*-- 10.09.2003 14:43:02---------------------------------------------------
1870 
1871   -----------------------------------------------------------------------*/
1872 void SentenceEditWindow_Impl::SetAttrib( const TextAttrib& rAttr, sal_uLong nPara, sal_uInt16 nStart, sal_uInt16 nEnd )
1873 {
1874     GetTextEngine()->SetAttrib(rAttr, nPara, nStart, nEnd);
1875 }
1876 /*-- 10.09.2003 14:43:02---------------------------------------------------
1877 
1878   -----------------------------------------------------------------------*/
1879 void SentenceEditWindow_Impl::SetText( const String& rStr )
1880 {
1881     m_nErrorStart = m_nErrorEnd = 0;
1882     GetTextEngine()->SetText(rStr);
1883 //    InitScrollBars();
1884 }
1885 /*-- 08.10.2003 14:35:52---------------------------------------------------
1886 
1887   -----------------------------------------------------------------------*/
1888 struct LanguagePosition_Impl
1889 {
1890     sal_uInt16          nPosition;
1891     LanguageType    eLanguage;
1892 
1893     LanguagePosition_Impl(sal_uInt16 nPos, LanguageType eLang) :
1894         nPosition(nPos),
1895         eLanguage(eLang)
1896         {}
1897 };
1898 typedef std::vector<LanguagePosition_Impl> LanguagePositions_Impl;
1899 
1900 void lcl_InsertBreakPosition_Impl(
1901         LanguagePositions_Impl& rBreakPositions, sal_uInt16 nInsert, LanguageType eLanguage)
1902 {
1903     LanguagePositions_Impl::iterator aStart = rBreakPositions.begin();
1904     while(aStart != rBreakPositions.end())
1905     {
1906         if(aStart->nPosition == nInsert)
1907 		{
1908             //the language of following starts has to overwrite
1909 			//the one of previous ends
1910 			aStart->eLanguage = eLanguage;
1911 			return;
1912 		}
1913         else if(aStart->nPosition > nInsert)
1914         {
1915 
1916             rBreakPositions.insert(aStart, LanguagePosition_Impl(nInsert, eLanguage));
1917             return;
1918         }
1919         else
1920             ++aStart;
1921     }
1922     rBreakPositions.push_back(LanguagePosition_Impl(nInsert, eLanguage));
1923 }
1924 /*-- 17.09.2003 14:26:59---------------------------------------------------
1925     Returns the text in spell portions. Each portion contains text with an
1926     equal language and attribute. The spell alternatives are empty.
1927   -----------------------------------------------------------------------*/
1928 svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions( bool bSetIgnoreFlag ) const
1929 {
1930     svx::SpellPortions aRet;
1931     ExtTextEngine* pTextEngine = GetTextEngine();
1932     const sal_uInt16 nTextLen = pTextEngine->GetTextLen(0);
1933     if(nTextLen)
1934     {
1935         TextPaM aCursor(0, 0);
1936         LanguagePositions_Impl aBreakPositions;
1937         const TextCharAttrib* pLastLang = 0;
1938         const TextCharAttrib* pLastError = 0;
1939         LanguageType eLang = LANGUAGE_DONTKNOW;
1940 		const TextCharAttrib* pError = 0;
1941         while(aCursor.GetIndex() < nTextLen)
1942         {
1943             const TextCharAttrib* pLang = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_LANGUAGE);
1944             if(pLang && pLang != pLastLang)
1945             {
1946                 eLang = static_cast<const SpellLanguageAttrib&>(pLang->GetAttr()).GetLanguage();
1947                 lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetStart(), eLang);
1948                 lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetEnd(), eLang);
1949                 pLastLang = pLang;
1950             }
1951             pError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR);
1952             if(pError && pLastError != pError)
1953             {
1954                 lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetStart(), eLang);
1955                 lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetEnd(), eLang);
1956                 pLastError = pError;
1957 
1958             }
1959             aCursor.GetIndex()++;
1960         }
1961         //
1962         if(nTextLen && aBreakPositions.empty())
1963         {
1964             //if all content has been overwritten the attributes may have been removed, too
1965             svx::SpellPortion aPortion1;
1966             aPortion1.eLanguage = GetSpellDialog()->GetSelectedLang_Impl();
1967             aPortion1.sText = pTextEngine->GetText(
1968                         TextSelection(TextPaM(0, 0), TextPaM(0, nTextLen)));
1969 
1970             aRet.push_back(aPortion1);
1971 
1972         }
1973         else if(!aBreakPositions.empty())
1974         {
1975             LanguagePositions_Impl::iterator aStart = aBreakPositions.begin();
1976             //start should always be Null
1977             eLang = aStart->eLanguage;
1978             sal_uInt16 nStart = aStart->nPosition;
1979             DBG_ASSERT(!nStart, "invalid start position - language attribute missing?");
1980             ++aStart;
1981 
1982             while(aStart != aBreakPositions.end())
1983             {
1984                 svx::SpellPortion aPortion1;
1985                 aPortion1.eLanguage = eLang;
1986                 aPortion1.sText = pTextEngine->GetText(
1987                             TextSelection(TextPaM(0, nStart), TextPaM(0, aStart->nPosition)));
1988                 bool bIsIgnoreError = m_aIgnoreErrorsAt.find( nStart ) != m_aIgnoreErrorsAt.end();
1989                 if( bSetIgnoreFlag && bIsIgnoreError /*m_nErrorStart == nStart*/ )
1990                 {
1991                     aPortion1.bIgnoreThisError = true;
1992                 }
1993                 aRet.push_back(aPortion1);
1994                 nStart = aStart->nPosition;
1995                 eLang = aStart->eLanguage;
1996                 ++aStart;
1997             }
1998         }
1999 
2000 		// quick partly fix of #i71318. Correct fix needs to patch the TextEngine itself...
2001 		// this one will only prevent text from disappearing. It may to not have the
2002 		// correct language and will probably not spell checked...
2003 		sal_uLong nPara = pTextEngine->GetParagraphCount();
2004 		if (nPara > 1)
2005 		{
2006 			String aLeftOverText;
2007 			for (sal_uLong i = 1;  i < nPara;  ++i)
2008 			{
2009 				aLeftOverText.AppendAscii( "\x0a" );	// the manual line break...
2010 				aLeftOverText += pTextEngine->GetText(i);
2011 			}
2012 			if (pError)
2013 			{	// we need to add a new portion containing the left-over text
2014 				svx::SpellPortion aPortion2;
2015 				aPortion2.eLanguage = eLang;
2016 				aPortion2.sText = aLeftOverText;
2017 				aRet.push_back( aPortion2 );
2018 			}
2019 			else
2020 			{	// we just need to append the left-over text to the last portion (which had no errors)
2021 				aRet[ aRet.size() - 1 ].sText += aLeftOverText;
2022 			}
2023 		}
2024    }
2025     return aRet;
2026 }
2027 
2028 /*-- 06.11.2003 11:30:10---------------------------------------------------
2029 
2030   -----------------------------------------------------------------------*/
2031 void SentenceEditWindow_Impl::Undo()
2032 {
2033     ::svl::IUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
2034     DBG_ASSERT(GetUndoActionCount(), "no undo actions available" );
2035     if(!GetUndoActionCount())
2036         return;
2037     bool bSaveUndoEdit = IsUndoEditMode();
2038     sal_uInt16 nId;
2039     //if the undo edit mode is active then undo all changes until the UNDO_EDIT_MODE action has been found
2040     do
2041     {
2042         nId = rUndoMgr.GetUndoActionId();
2043         rUndoMgr.Undo();
2044     }while(bSaveUndoEdit && SPELLUNDO_UNDO_EDIT_MODE != nId && GetUndoActionCount());
2045 
2046     if(bSaveUndoEdit || SPELLUNDO_CHANGE_GROUP == nId)
2047         GetSpellDialog()->UpdateBoxes_Impl();
2048 }
2049 /*-- 06.11.2003 11:30:10---------------------------------------------------
2050 
2051   -----------------------------------------------------------------------*/
2052 void SentenceEditWindow_Impl::ResetUndo()
2053 {
2054     GetTextEngine()->ResetUndo();
2055 }
2056 /*-- 06.11.2003 12:30:41---------------------------------------------------
2057 
2058   -----------------------------------------------------------------------*/
2059 void SentenceEditWindow_Impl::AddUndoAction( SfxUndoAction *pAction, sal_Bool bTryMerg )
2060 {
2061     ::svl::IUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
2062     rUndoMgr.AddUndoAction(pAction, bTryMerg);
2063     GetSpellDialog()->aUndoPB.Enable();
2064 }
2065 /*-- 06.11.2003 12:38:44---------------------------------------------------
2066 
2067   -----------------------------------------------------------------------*/
2068 sal_uInt16 SentenceEditWindow_Impl::GetUndoActionCount()
2069 {
2070     return GetTextEngine()->GetUndoManager().GetUndoActionCount();
2071 }
2072 
2073 /*-- 12.11.2003 12:12:38---------------------------------------------------
2074 
2075   -----------------------------------------------------------------------*/
2076 void SentenceEditWindow_Impl::UndoActionStart( sal_uInt16 nId )
2077 {
2078     GetTextEngine()->UndoActionStart(nId);
2079 }
2080 /*-- 12.11.2003 12:12:38---------------------------------------------------
2081 
2082   -----------------------------------------------------------------------*/
2083 void SentenceEditWindow_Impl::UndoActionEnd()
2084 {
2085     GetTextEngine()->UndoActionEnd();
2086 }
2087 /*-- 12.11.2003 12:12:38---------------------------------------------------
2088 
2089   -----------------------------------------------------------------------*/
2090 void SentenceEditWindow_Impl::MoveErrorEnd(long nOffset)
2091 {
2092     if(nOffset > 0)
2093         m_nErrorEnd = m_nErrorEnd - (sal_uInt16)nOffset;
2094     else
2095         m_nErrorEnd = m_nErrorEnd -(sal_uInt16)- nOffset;
2096 }
2097 /*-- 13.11.2003 15:15:19---------------------------------------------------
2098 
2099   -----------------------------------------------------------------------*/
2100 void  SentenceEditWindow_Impl::SetUndoEditMode(bool bSet)
2101 {
2102     DBG_ASSERT(!bSet || m_bIsUndoEditMode != bSet, "SetUndoEditMode with equal values?");
2103     m_bIsUndoEditMode = bSet;
2104     //disable all buttons except the Change
2105     SpellDialog* pSpellDialog = GetSpellDialog();
2106     Control* aControls[] =
2107     {
2108         &pSpellDialog->aChangeAllPB,
2109         &pSpellDialog->aExplainPB,
2110         &pSpellDialog->aIgnoreAllPB,
2111         &pSpellDialog->aIgnoreRulePB,
2112         &pSpellDialog->aIgnorePB,
2113         &pSpellDialog->aSuggestionLB,
2114         &pSpellDialog->aSuggestionFT,
2115         &pSpellDialog->aLanguageFT,
2116         &pSpellDialog->aLanguageLB,
2117         &pSpellDialog->aAddToDictMB,
2118         &pSpellDialog->aAutoCorrPB,
2119         0
2120     };
2121     sal_Int32 nIdx = 0;
2122     do
2123     {
2124         aControls[nIdx]->Enable(sal_False);
2125     }
2126     while(aControls[++nIdx]);
2127 
2128     //remove error marks
2129     TextEngine* pTextEngine = GetTextEngine();
2130     pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTCOLOR, sal_True );
2131     pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTWEIGHT, sal_True );
2132 
2133     //put the appropriate action on the Undo-stack
2134     SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
2135                         SPELLUNDO_UNDO_EDIT_MODE, GetSpellDialog()->aDialogUndoLink);
2136     AddUndoAction(pAction);
2137     pSpellDialog->aChangePB.Enable();
2138 }
2139 
2140 /*-- 30.06.2008 14:15:19---------------------------------------------------
2141 
2142   -----------------------------------------------------------------------*/
2143 ExplainButton::~ExplainButton()
2144 {
2145 }
2146 /*-- 30.06.2008 14:15:19---------------------------------------------------
2147 
2148   -----------------------------------------------------------------------*/
2149 void ExplainButton::RequestHelp( const HelpEvent& )
2150 {
2151     Help::ShowBalloon( this, GetPosPixel(), m_sExplanation );
2152 }
2153 
2154 void ExplainButton::Click()
2155 {
2156     RequestHelp( HelpEvent() );
2157 }
2158