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