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