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