update dev300-m58
[ooovba.git] / svx / source / cui / SpellDialog.cxx
blobbead9b97bf3b236250129986d7958628f3b3d92c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SpellDialog.cxx,v $
10 * $Revision: 1.24 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #ifdef SVX_DLLIMPLEMENTATION
35 #undef SVX_DLLIMPLEMENTATION
36 #endif
38 // include ---------------------------------------------------------------
40 #include <tools/ref.hxx>
41 #include <tools/shl.hxx>
42 #include <vcl/wrkwin.hxx>
43 #include <vcl/menu.hxx>
44 #include <vcl/msgbox.hxx>
45 #ifndef _SCRBAR_HXX //autogen
46 #include <vcl/scrbar.hxx>
47 #endif
48 #include <SpellAttrib.hxx>
49 #include <sfx2/dispatch.hxx>
50 #include <sfx2/bindings.hxx>
51 #include <svtools/undo.hxx>
52 #include <svtools/lingucfg.hxx>
53 #include <svtools/textdata.hxx>
54 #include <svtools/filter.hxx>
55 #include <unolingu.hxx>
56 #include <svx/splwrap.hxx>
57 #include <linguistic/lngprops.hxx>
58 #ifndef _LINGUISTIC_MISC_HHX_
59 #include <linguistic/misc.hxx>
60 #endif
61 #include <comphelper/processfactory.hxx>
62 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
63 #include <com/sun/star/lang/XServiceInfo.hpp>
64 #include <com/sun/star/lang/XServiceDisplayName.hpp>
65 #include <com/sun/star/linguistic2/SpellFailure.hpp>
66 #include <com/sun/star/frame/XStorable.hpp>
67 #include <sfx2/app.hxx>
68 #include <vcl/help.hxx>
69 #include <vcl/graph.hxx>
70 #include <osl/file.hxx>
71 #include <impgrf.hxx>
72 #include <svx/dialogs.hrc>
73 #include <helpid.hrc>
74 #include "SpellDialog.hrc"
78 #include "optitems.hxx"
79 #include <svx/svxenum.hxx>
80 #include <svx/SpellDialogChildWindow.hxx>
81 #include "SpellDialog.hxx"
82 //#include <svx/splwrap.hxx> // Der Wrapper
83 #include "dlgutil.hxx" // language
84 #include <svx/optlingu.hxx>
85 #include <svx/dialmgr.hxx>
86 #include "svxerr.hxx"
87 #include "treeopt.hxx"
89 using namespace ::com::sun::star;
90 using namespace ::com::sun::star::uno;
91 using namespace ::com::sun::star::beans;
92 using namespace ::com::sun::star::linguistic2;
94 #define C2U(cChar) ::rtl::OUString::createFromAscii(cChar)
95 // struct SpellDialog_Impl ---------------------------------------------
97 struct SpellDialog_Impl
99 Sequence< Reference< XDictionary > > aDics;
101 // -----------------------------------------------------------------------
102 //#define VENDOR_IMAGE_HEIGHT 44 //as specified
104 #define SPELLUNDO_CHANGE_LANGUAGE (TEXTUNDO_USER + 1)
105 #define SPELLUNDO_CHANGE_TEXTENGINE (TEXTUNDO_USER + 2)
106 #define SPELLUNDO_CHANGE_NEXTERROR (TEXTUNDO_USER + 3)
107 #define SPELLUNDO_CHANGE_ADD_TO_DICTIONARY (TEXTUNDO_USER + 4)
108 #define SPELLUNDO_CHANGE_GROUP (TEXTUNDO_USER + 5) //undo list
109 #define SPELLUNDO_MOVE_ERROREND (TEXTUNDO_USER + 6)
110 #define SPELLUNDO_UNDO_EDIT_MODE (TEXTUNDO_USER + 7)
111 #define SPELLUNDO_ADD_IGNORE_RULE (TEXTUNDO_USER + 8)
113 namespace svx{
114 class SpellUndoAction_Impl : public SfxUndoAction
116 USHORT m_nId;
117 const Link& m_rActionLink;
118 //undo of button enabling
119 bool m_bEnableChangePB;
120 bool m_bEnableChangeAllPB;
121 //undo of MarkNextError - used in change and change all, ignore and ignore all
122 long m_nNewErrorStart;
123 long m_nNewErrorEnd;
124 long m_nOldErrorStart;
125 long m_nOldErrorEnd;
126 bool m_bIsErrorLanguageSelected;
127 ::rtl::OUString m_sRuleId;
128 //undo of AddToDictionary
129 Reference<XDictionary> m_xDictionary;
130 ::rtl::OUString m_sAddedWord;
131 //move end of error - ::ChangeMarkedWord()
132 long m_nOffset;
134 public:
135 SpellUndoAction_Impl(USHORT nId, const Link& rActionLink) :
136 m_nId(nId),
137 m_rActionLink( rActionLink),
138 m_bEnableChangePB(false),
139 m_bEnableChangeAllPB(false),
140 m_nNewErrorStart(-1),
141 m_nNewErrorEnd(-1),
142 m_nOldErrorStart(-1),
143 m_nOldErrorEnd(-1),
144 m_bIsErrorLanguageSelected(false),
145 m_nOffset(0)
148 ~SpellUndoAction_Impl();
150 virtual void Undo();
151 virtual USHORT GetId() const;
153 void SetEnableChangePB(){m_bEnableChangePB = true;}
154 bool IsEnableChangePB(){return m_bEnableChangePB;}
156 void SetEnableChangeAllPB(){m_bEnableChangeAllPB = true;}
157 bool IsEnableChangeAllPB(){return m_bEnableChangeAllPB;}
159 void SetErrorMove(long nNewStart, long nNewEnd, long nOldStart, long nOldEnd)
161 m_nNewErrorStart = nNewStart;
162 m_nNewErrorEnd = nNewEnd;
163 m_nOldErrorStart = nOldStart;
164 m_nOldErrorEnd = nOldEnd;
166 long GetNewErrorStart() { return m_nNewErrorStart;}
167 long GetNewErrorEnd() { return m_nNewErrorEnd;}
168 long GetOldErrorStart() { return m_nOldErrorStart;}
169 long GetOldErrorEnd() { return m_nOldErrorEnd;}
171 void SetErrorLanguageSelected(bool bSet){ m_bIsErrorLanguageSelected = bSet;}
172 bool IsErrorLanguageSelected() const {return m_bIsErrorLanguageSelected;}
175 void SetDictionary(Reference<XDictionary> xDict) { m_xDictionary = xDict; }
176 Reference<XDictionary> GetDictionary() const {return m_xDictionary;}
177 void SetAddedWord(const ::rtl::OUString& rWord) {m_sAddedWord = rWord;}
178 const ::rtl::OUString& GetAddedWord() const { return m_sAddedWord;}
180 void SetOffset(long nSet) {m_nOffset = nSet;}
181 long GetOffset() const {return m_nOffset;}
183 void SetErrorType( const ::rtl::OUString& rId ) { m_sRuleId = rId; }
184 const ::rtl::OUString& GetErrorType() const { return m_sRuleId; }
187 }//namespace svx
188 using namespace ::svx;
189 /*-- 06.11.2003 12:16:02---------------------------------------------------
191 -----------------------------------------------------------------------*/
192 SpellUndoAction_Impl::~SpellUndoAction_Impl()
195 /*-- 06.11.2003 12:16:02---------------------------------------------------
197 -----------------------------------------------------------------------*/
198 void SpellUndoAction_Impl::Undo()
200 m_rActionLink.Call(this);
202 /*-- 06.11.2003 12:16:02---------------------------------------------------
204 -----------------------------------------------------------------------*/
205 USHORT SpellUndoAction_Impl::GetId()const
207 return m_nId;
210 // class SvxSpellCheckDialog ---------------------------------------------
212 SpellDialog::SpellDialog(
213 SpellDialogChildWindow* pChildWindow,
214 Window * pParent,
215 SfxBindings* _pBindings)
216 : SfxModelessDialog (_pBindings,
217 pChildWindow,
218 pParent,
219 SVX_RES(RID_SVXDLG_SPELLCHECK)),
221 aVendorImageFI ( this , SVX_RES( IMG_VENDOR ) ),
222 aLanguageFT ( this, SVX_RES( FT_LANGUAGE ) ),
223 aLanguageLB ( this, SVX_RES( LB_LANGUAGE ) ),
224 aNotInDictFT ( this, SVX_RES( FT_NOTINDICT ) ),
225 aSentenceED ( this, SVX_RES( ED_NEWWORD ) ),
226 aSuggestionFT ( this, SVX_RES( FT_SUGGESTION ) ),
227 aSuggestionLB ( this, SVX_RES( LB_SUGGESTION ) ),
229 aIgnorePB ( this, SVX_RES( PB_IGNORE ) ),
230 aIgnoreAllPB ( this, SVX_RES( PB_IGNOREALL ) ),
231 aIgnoreRulePB ( this, SVX_RES( PB_IGNORERULE ) ),
232 aAddToDictMB ( this, SVX_RES( MB_ADDTODICT ) ),
234 aChangePB ( this, SVX_RES( PB_CHANGE ) ),
235 aChangeAllPB ( this, SVX_RES( PB_CHANGEALL ) ),
236 aExplainPB ( this, SVX_RES( PB_EXPLAIN) ),
237 aAutoCorrPB ( this, SVX_RES( PB_AUTOCORR ) ),
239 aCheckGrammarCB ( this, SVX_RES( CB_CHECK_GRAMMAR ) ),
241 aHelpPB ( this, SVX_RES( PB_HELP ) ),
242 aOptionsPB ( this, SVX_RES( PB_OPTIONS ) ),
243 aUndoPB ( this, SVX_RES( PB_UNDO ) ),
244 aClosePB ( this, SVX_RES( PB_CLOSE ) ),
245 aBackgroundGB ( this, SVX_RES( GB_BACKGROUND ) ),
247 aVendorImage ( SVX_RES( IMG_DEFAULT_VENDOR ) ),
248 aVendorImageHC ( SVX_RES( IMG_DEFAULT_VENDOR_HC ) ),
250 aResumeST ( SVX_RES(ST_RESUME )),
251 aIgnoreOnceST ( aIgnorePB.GetText()),
252 aNoSuggestionsST( SVX_RES(ST_NOSUGGESTIONS)),
253 m_sTitleSpelling ( SVX_RES( ST_SPELLING ) ),
254 m_sTitleSpellingGrammar ( SVX_RES( ST_SPELLING_AND_GRAMMAR ) ),
255 m_sTitleSpellingGrammarVendor ( SVX_RES( ST_SPELLING_AND_GRAMMAR_VENDORNAME ) ),
256 aDialogUndoLink( LINK (this, SpellDialog, DialogUndoHdl)),
257 bModified( false ),
258 bFocusLocked( true ),
259 rParent ( *pChildWindow ),
260 nOldLang ( LANGUAGE_NONE )
262 FreeResource();
263 xSpell = LinguMgr::GetSpellChecker();
264 pImpl = new SpellDialog_Impl;
266 //HelpIds
267 aClosePB. SetHelpId(HID_SPLDLG_BUTTON_CLOSE );
268 aIgnorePB. SetHelpId(HID_SPLDLG_BUTTON_IGNORE );
269 aIgnoreAllPB. SetHelpId(HID_SPLDLG_BUTTON_IGNOREALL);
270 aIgnoreRulePB. SetHelpId(HID_SPLDLG_BUTTON_IGNORERULE);
271 aChangePB. SetHelpId(HID_SPLDLG_BUTTON_CHANGE );
272 aChangeAllPB. SetHelpId(HID_SPLDLG_BUTTON_CHANGEALL);
273 aExplainPB. SetHelpId(HID_SPLDLG_BUTTON_EXPLAIN );
274 Init_Impl();
276 // disable controls if service is missing
277 if (!xSpell.is())
278 Enable( sal_False );
280 Application::PostUserEvent( STATIC_LINK(
281 this, SpellDialog, InitHdl ) );
284 // -----------------------------------------------------------------------
286 SpellDialog::~SpellDialog()
288 // save possibly modified user-dictionaries
289 Reference< XDictionaryList > xDicList( SvxGetDictionaryList() );
290 if (xDicList.is())
292 linguistic::SaveDictionaries( xDicList );
295 delete aAddToDictMB.GetPopupMenu();
296 delete pImpl;
299 // -----------------------------------------------------------------------
301 void SpellDialog::Init_Impl()
303 // Handler initialisieren
304 aClosePB.SetClickHdl(LINK( this, SpellDialog, CancelHdl ) );
305 aChangePB.SetClickHdl(LINK( this, SpellDialog, ChangeHdl ) );
306 aChangeAllPB.SetClickHdl(LINK( this, SpellDialog, ChangeAllHdl ) );
307 aIgnorePB.SetClickHdl(LINK( this, SpellDialog, IgnoreHdl ) );
308 aIgnoreAllPB.SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
309 aIgnoreRulePB.SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
310 aUndoPB.SetClickHdl(LINK( this, SpellDialog, UndoHdl ) );
312 aAutoCorrPB.SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
313 aCheckGrammarCB.SetClickHdl( LINK( this, SpellDialog, CheckGrammarHdl ));
314 aOptionsPB .SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
316 aSuggestionLB.SetDoubleClickHdl( LINK( this, SpellDialog, ChangeHdl ) );
318 aSentenceED.SetModifyHdl(LINK ( this, SpellDialog, ModifyHdl) );
319 aAddToDictMB.SetSelectHdl(LINK ( this, SpellDialog, AddToDictionaryHdl ) );
320 aLanguageLB.SetSelectHdl(LINK( this, SpellDialog, LanguageSelectHdl ) );
322 // initialize language ListBox
323 aLanguageLB.SetLanguageList( LANG_LIST_SPELL_USED, FALSE, FALSE, TRUE );
325 // get current language
326 UpdateBoxes_Impl();
328 // fill dictionary PopupMenu
329 InitUserDicts();
331 aSentenceED.ClearModifyFlag();
332 SvxGetChangeAllList()->clear();
335 // -----------------------------------------------------------------------
337 void SpellDialog::UpdateBoxes_Impl()
339 sal_Int32 i;
340 aSuggestionLB.Clear();
342 const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
344 LanguageType nAltLanguage = LANGUAGE_NONE;
345 //String aAltWord;
346 Sequence< ::rtl::OUString > aNewWords;
347 bool bIsGrammarError = false;
348 if( pSpellErrorDescription )
350 nAltLanguage = SvxLocaleToLanguage( pSpellErrorDescription->aLocale );
351 //aAltWord = String( xAlt->getWord() );
352 aNewWords = pSpellErrorDescription->aSuggestions;
353 bIsGrammarError = pSpellErrorDescription->bIsGrammarError;
354 aExplainPB.SetExplanation(pSpellErrorDescription->sExplanation );
356 if( pSpellErrorDescription && pSpellErrorDescription->sDialogTitle.getLength() )
358 // use this function to apply the correct image to be used...
359 SetTitle_Impl( nAltLanguage );
360 // then change the title to the one to be actually used
361 SetText( pSpellErrorDescription->sDialogTitle );
363 else
364 SetTitle_Impl( nAltLanguage );
365 SetSelectedLang_Impl( nAltLanguage );
368 // Alternativen eintragen
369 const ::rtl::OUString *pNewWords = aNewWords.getConstArray();
370 const sal_Int32 nSize = aNewWords.getLength();
371 for ( i = 0; i < nSize; ++i )
373 String aTmp( pNewWords[i] );
374 if ( LISTBOX_ENTRY_NOTFOUND == aSuggestionLB.GetEntryPos( aTmp ) )
376 aSuggestionLB.InsertEntry( aTmp );
377 aSuggestionLB.SetEntryFlags(aSuggestionLB.GetEntryCount() - 1, LISTBOX_ENTRY_FLAG_MULTILINE);
380 if(!nSize)
381 aSuggestionLB.InsertEntry( aNoSuggestionsST );
382 aAutoCorrPB.Enable( nSize > 0 );
383 //aSentenceED.GrabFocus();
385 aSuggestionFT.Enable(nSize > 0);
386 aSuggestionLB.Enable(nSize > 0);
387 if( nSize )
389 aSuggestionLB.SelectEntryPos(0);
391 aChangePB.Enable( nSize > 0);
392 aChangeAllPB.Enable(nSize > 0);
393 bool bShowChangeAll = !bIsGrammarError;
394 aChangeAllPB.Show( bShowChangeAll );
395 aExplainPB.Show( !bShowChangeAll );
396 aLanguageLB.Enable( bShowChangeAll );
397 aIgnoreAllPB.Show( bShowChangeAll );
398 aAddToDictMB.Show( bShowChangeAll );
399 aIgnoreRulePB.Show( !bShowChangeAll );
400 aIgnoreRulePB.Enable(pSpellErrorDescription && pSpellErrorDescription->sRuleId.getLength());
401 aExplainPB.Enable( aExplainPB.HasExplanation() );
402 aAutoCorrPB.Show( bShowChangeAll && rParent.HasAutoCorrection() );
405 // -----------------------------------------------------------------------
407 void SpellDialog::SpellContinue_Impl(bool bUseSavedSentence)
409 //initially or after the last error of a sentence MarkNextError will fail
410 //then GetNextSentence() has to be called followed again by MarkNextError()
411 //MarkNextError is not initally called if the UndoEdit mode is active
412 bool bNextSentence = false;
413 if((!aSentenceED.IsUndoEditMode() && aSentenceED.MarkNextError()) ||
414 true == ( bNextSentence = GetNextSentence_Impl(bUseSavedSentence) && aSentenceED.MarkNextError()))
416 const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
417 if( pSpellErrorDescription )
419 UpdateBoxes_Impl();
420 Control* aControls[] =
422 &aNotInDictFT,
423 &aSentenceED,
424 &aLanguageFT,
427 sal_Int32 nIdx = 0;
430 aControls[nIdx]->Enable(sal_True);
432 while(aControls[++nIdx]);
436 if( bNextSentence )
438 //remove undo if a new sentence is active
439 aSentenceED.ResetUndo();
440 aUndoPB.Enable(FALSE);
444 /* -----------------10.09.2003 14:04-----------------
445 Initialize, asynchronous to prevent virtial calls
446 from a constructor
447 --------------------------------------------------*/
448 IMPL_STATIC_LINK( SpellDialog, InitHdl, SpellDialog *, EMPTYARG )
450 pThis->SetUpdateMode( sal_False );
451 //show or hide AutoCorrect depending on the modules abilities
452 pThis->aAutoCorrPB.Show(pThis->rParent.HasAutoCorrection());
453 pThis->SpellContinue_Impl();
454 pThis->aSentenceED.ResetUndo();
455 pThis->aUndoPB.Enable(FALSE);
457 pThis->LockFocusChanges(true);
458 if( pThis->aChangePB.IsEnabled() )
459 pThis->aChangePB.GrabFocus();
460 else if( pThis->aIgnorePB.IsEnabled() )
461 pThis->aIgnorePB.GrabFocus();
462 else if( pThis->aClosePB.IsEnabled() )
463 pThis->aClosePB.GrabFocus();
464 pThis->LockFocusChanges(false);
465 //show grammar CheckBox depending on the modules abilities
466 bool bHasGrammarChecking = pThis->rParent.HasGrammarChecking();
467 pThis->aCheckGrammarCB.Show( bHasGrammarChecking );
468 if( !bHasGrammarChecking )
470 //resize the dialog to hide the hidden area of the CheckBox
471 Size aBackSize = pThis->aBackgroundGB.GetSizePixel();
472 sal_Int32 nDiff = pThis->aBackgroundGB.GetPosPixel().Y() + aBackSize.Height()
473 - pThis->aCheckGrammarCB.GetPosPixel().Y();
474 aBackSize.Height() -= nDiff;
475 pThis->aBackgroundGB.SetSizePixel(aBackSize);
476 Button* aButtons[] = { &pThis->aHelpPB, &pThis->aOptionsPB, &pThis->aUndoPB, &pThis->aClosePB, 0 };
477 sal_Int32 nButton = 0;
478 while( aButtons[nButton])
480 Point aPos = aButtons[nButton]->GetPosPixel();
481 aPos.Y() -= nDiff;
482 aButtons[nButton]->SetPosPixel(aPos);
483 ++nButton;
485 Size aDlgSize = pThis->GetSizePixel();
486 aDlgSize.Height() -= nDiff;
487 pThis->SetSizePixel( aDlgSize );
489 else
491 if( SvtLinguConfig().HasAnyVendorImages() )
493 pThis->aVendorImageFI.Show();
494 Size aVendorSize = pThis->aVendorImageFI.GetSizePixel();
495 Size aImageSize = pThis->aVendorImageFI.GetImage().GetSizePixel();
496 if( aImageSize.Height() )
498 aVendorSize.Height() = aImageSize.Height();
499 if(aVendorSize.Width() < aImageSize.Width())
500 aVendorSize.Width() = aImageSize.Width();
501 pThis->aVendorImageFI.SetSizePixel( aVendorSize );
503 //aVendorSize.Height() = nDiff;
504 sal_Int32 nDiff = aVendorSize.Height();
505 pThis->aVendorImageFI.SetSizePixel(aVendorSize);
506 Control* aControls[] = {
507 &pThis->aLanguageFT,
508 &pThis->aLanguageLB,
509 &pThis->aNotInDictFT,
510 &pThis->aSentenceED,
511 &pThis->aSuggestionFT,
512 &pThis->aSuggestionLB,
513 &pThis->aIgnorePB,
514 &pThis->aIgnoreAllPB,
515 &pThis->aIgnoreRulePB,
516 &pThis->aAddToDictMB,
517 &pThis->aChangePB,
518 &pThis->aChangeAllPB,
519 &pThis->aExplainPB,
520 &pThis->aAutoCorrPB,
521 &pThis->aCheckGrammarCB,
522 &pThis->aHelpPB,
523 &pThis->aOptionsPB,
524 &pThis->aUndoPB,
525 &pThis->aClosePB,
526 &pThis->aBackgroundGB,
529 sal_Int32 nControl = 0;
530 while( aControls[nControl])
532 Point aPos = aControls[nControl]->GetPosPixel();
533 aPos.Y() += nDiff;
534 aControls[nControl]->SetPosPixel(aPos);
535 ++nControl;
537 Size aDlgSize = pThis->GetSizePixel();
538 aDlgSize.Height() += nDiff;
539 pThis->SetSizePixel( aDlgSize );
540 pThis->Invalidate();
543 pThis->aCheckGrammarCB.Check( pThis->rParent.IsGrammarChecking() );
544 pThis->SetUpdateMode( sal_True );
545 pThis->Show();
546 return 0;
549 // -----------------------------------------------------------------------
551 IMPL_LINK( SpellDialog, ExtClickHdl, Button *, pBtn )
553 if (&aOptionsPB == pBtn)
554 StartSpellOptDlg_Impl();
555 else if(&aAutoCorrPB == pBtn)
557 //get the currently selected wrong word
558 String sCurrentErrorText = aSentenceED.GetErrorText();
559 //get the wrong word from the XSpellAlternative
560 const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
561 if( pSpellErrorDescription )
563 String sWrong(pSpellErrorDescription->sErrorText);
564 //if the word has not been edited in the MultiLineEdit then
565 //the current suggestion should be used
566 //if it's not the 'no suggestions' entry
567 if(sWrong == sCurrentErrorText &&
568 aSuggestionLB.IsEnabled() && aSuggestionLB.GetSelectEntryCount() > 0 &&
569 aNoSuggestionsST != aSuggestionLB.GetSelectEntry())
571 sCurrentErrorText = aSuggestionLB.GetSelectEntry();
573 if(sWrong != sCurrentErrorText)
575 SvxPrepareAutoCorrect( sWrong, sCurrentErrorText );
576 LanguageType eLang = GetSelectedLang_Impl();
577 rParent.AddAutoCorrection( sWrong, sCurrentErrorText, eLang );
581 return 0;
583 // -----------------------------------------------------------------------
584 IMPL_LINK( SpellDialog, CheckGrammarHdl, CheckBox*, pBox )
586 rParent.SetGrammarChecking( pBox->IsChecked() );
587 Impl_Restore();
588 return 0;
591 void SpellDialog::StartSpellOptDlg_Impl()
593 sal_uInt16 aSpellInfos[] =
595 SID_ATTR_SPELL,SID_ATTR_SPELL,
596 SID_SPELL_MODIFIED, SID_SPELL_MODIFIED,
597 SID_AUTOSPELL_CHECK, SID_AUTOSPELL_CHECK,
600 SfxItemSet aSet( SFX_APP()->GetPool(), aSpellInfos);
601 aSet.Put(SfxSpellCheckItem( xSpell, SID_ATTR_SPELL ));
602 SfxSingleTabDialog* pDlg =
603 new SfxSingleTabDialog( this, aSet, RID_SFXPAGE_LINGU );
604 SfxTabPage* pPage = SvxLinguTabPage::Create( pDlg, aSet );
605 ( (SvxLinguTabPage*)pPage )->HideGroups( GROUP_MODULES );
606 pDlg->SetTabPage( pPage );
607 if(RET_OK == pDlg->Execute())
610 // Benutzerb"ucher anzeigen
611 InitUserDicts();
612 const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
613 if(pOutSet)
614 OfaTreeOptionsDialog::ApplyLanguageOptions(*pOutSet);
616 delete pDlg;
620 // -----------------------------------------------------------------------
622 IMPL_LINK( SpellDialog, ChangeHdl, Button *, EMPTYARG )
624 if(aSentenceED.IsUndoEditMode())
626 SpellContinue_Impl();
628 else
630 aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
631 String aString = aSentenceED.GetErrorText();
632 //dots are sometimes part of the spelled word but they are not necessarily part of the replacement
633 bool bDot = aString.Len() && aString.GetChar(aString.Len() - 1 ) == '.';
634 if(aSuggestionLB.IsEnabled() &&
635 aSuggestionLB.GetSelectEntryCount()>0 &&
636 aNoSuggestionsST != aSuggestionLB.GetSelectEntry())
637 aString = aSuggestionLB.GetSelectEntry();
638 if(bDot && (!aString.Len() || aString.GetChar(aString.Len() - 1 ) != '.'))
639 aString += '.';
641 aSentenceED.ChangeMarkedWord(aString, GetSelectedLang_Impl());
642 SpellContinue_Impl();
643 bModified = false;
644 aSentenceED.UndoActionEnd( SPELLUNDO_CHANGE_GROUP );
646 if(!aChangePB.IsEnabled())
647 aIgnorePB.GrabFocus();
648 return 1;
652 // -----------------------------------------------------------------------
654 IMPL_LINK( SpellDialog, ChangeAllHdl, Button *, EMPTYARG )
656 aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
657 // change the current word first
658 String aString = aSentenceED.GetErrorText();
659 if(aSuggestionLB.IsEnabled() &&
660 aSuggestionLB.GetSelectEntryCount()>0 &&
661 aNoSuggestionsST != aSuggestionLB.GetSelectEntry())
662 aString = aSuggestionLB.GetSelectEntry();
664 LanguageType eLang = GetSelectedLang_Impl();
666 // add new word to ChangeAll list
667 String aOldWord( aSentenceED.GetErrorText() );
668 SvxPrepareAutoCorrect( aOldWord, aString );
669 Reference<XDictionary> aXDictionary( SvxGetChangeAllList(), UNO_QUERY );
670 sal_uInt8 nAdded = linguistic::AddEntryToDic( aXDictionary,
671 aOldWord , sal_True,
672 aString, eLang );
674 if(nAdded == DIC_ERR_NONE)
676 SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
677 SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
678 pAction->SetDictionary(aXDictionary);
679 pAction->SetAddedWord(aOldWord);
680 aSentenceED.AddUndoAction(pAction);
683 aSentenceED.ChangeMarkedWord(aString, eLang);
684 SpellContinue_Impl();
685 bModified = false;
686 aSentenceED.UndoActionEnd( SPELLUNDO_CHANGE_GROUP );
687 return 1;
689 // -----------------------------------------------------------------------
691 IMPL_LINK( SpellDialog, IgnoreAllHdl, Button *, pButton )
693 aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
694 // add word to IgnoreAll list
695 Reference< XDictionary > aXDictionary( SvxGetIgnoreAllList(), UNO_QUERY );
696 //in case the error has been changed manually it has to be restored
697 aSentenceED.RestoreCurrentError();
698 if( pButton == &aIgnoreRulePB )
700 const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
703 if( pSpellErrorDescription && pSpellErrorDescription->xGrammarChecker.is() )
705 pSpellErrorDescription->xGrammarChecker->ignoreRule( pSpellErrorDescription->sRuleId,
706 pSpellErrorDescription->aLocale );
709 catch( const uno::Exception& )
713 else
715 String sErrorText(aSentenceED.GetErrorText());
716 sal_uInt8 nAdded = linguistic::AddEntryToDic( aXDictionary,
717 sErrorText, sal_False,
718 ::rtl::OUString(), LANGUAGE_NONE );
719 if(nAdded == DIC_ERR_NONE)
721 SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
722 SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
723 pAction->SetDictionary(aXDictionary);
724 pAction->SetAddedWord(sErrorText);
725 aSentenceED.AddUndoAction(pAction);
729 SpellContinue_Impl();
730 bModified = false;
731 aSentenceED.UndoActionEnd( SPELLUNDO_CHANGE_GROUP );
732 return 1;
734 /*-- 06.11.2003 11:24:08---------------------------------------------------
736 -----------------------------------------------------------------------*/
737 IMPL_LINK( SpellDialog, UndoHdl, Button*, EMPTYARG )
739 aSentenceED.Undo();
740 if(!aSentenceED.GetUndoActionCount())
741 aUndoPB.Enable(FALSE);
742 return 0;
744 /*-- 06.11.2003 12:19:15---------------------------------------------------
746 -----------------------------------------------------------------------*/
747 IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl*, pAction )
749 switch(pAction->GetId())
751 case SPELLUNDO_CHANGE_TEXTENGINE:
753 if(pAction->IsEnableChangePB())
754 aChangePB.Enable(FALSE);
755 if(pAction->IsEnableChangeAllPB())
756 aChangeAllPB.Enable(FALSE);
758 break;
759 case SPELLUNDO_CHANGE_NEXTERROR:
761 aSentenceED.MoveErrorMarkTo((USHORT)pAction->GetOldErrorStart(), (USHORT)pAction->GetOldErrorEnd(), false);
762 if(pAction->IsErrorLanguageSelected())
764 UpdateBoxes_Impl();
767 break;
768 case SPELLUNDO_CHANGE_ADD_TO_DICTIONARY:
770 if(pAction->GetDictionary().is())
771 pAction->GetDictionary()->remove(pAction->GetAddedWord());
773 break;
774 case SPELLUNDO_MOVE_ERROREND :
776 if(pAction->GetOffset() != 0)
777 aSentenceED.MoveErrorEnd(pAction->GetOffset());
779 break;
780 case SPELLUNDO_UNDO_EDIT_MODE :
782 //refill the dialog with the currently spelled sentence - throw away all changes
783 SpellContinue_Impl(true);
785 break;
786 case SPELLUNDO_ADD_IGNORE_RULE:
787 //undo of ignored rules is not supported
788 break;
791 return 0;
793 // -----------------------------------------------------------------------
794 void SpellDialog::Impl_Restore()
796 //clear the "ChangeAllList"
797 SvxGetChangeAllList()->clear();
798 //get a new sentence
799 aSentenceED.SetText(rtl::OUString());
800 aSentenceED.ResetModified();
801 SpellContinue_Impl();
802 aIgnorePB.SetText(aIgnoreOnceST);
805 IMPL_LINK( SpellDialog, IgnoreHdl, Button *, EMPTYARG )
807 if(aIgnorePB.GetText() == aResumeST)
809 Impl_Restore();
811 else
813 //in case the error has been changed manually it has to be restored
814 aSentenceED.RestoreCurrentError();
815 rParent.ApplyChangedSentence(aSentenceED.CreateSpellPortions(true));
816 aSentenceED.ResetModified();
818 // the word is being ignored
819 SpellContinue_Impl();
820 bModified = false;
822 return 1;
826 // -----------------------------------------------------------------------
828 sal_Bool SpellDialog::Close()
830 GetBindings().GetDispatcher()->
831 Execute(rParent.GetType(),
832 SFX_CALLMODE_ASYNCHRON|SFX_CALLMODE_RECORD);
833 return sal_True;
835 // -----------------------------------------------------------------------
837 void SpellDialog::SetSelectedLang_Impl( LanguageType nLang )
839 aLanguageLB.SelectLanguage( nLang );
842 // -----------------------------------------------------------------------
844 LanguageType SpellDialog::GetSelectedLang_Impl() const
846 INT16 nLang = aLanguageLB.GetSelectLanguage();
847 return nLang;
849 /* -----------------28.10.2003 14:27-----------------
851 --------------------------------------------------*/
852 IMPL_LINK(SpellDialog, LanguageSelectHdl, SvxLanguageBox*, pBox)
854 //if currently an error is selected then search for alternatives for
855 //this word and fill the alternatives ListBox accordingly
856 String sError = aSentenceED.GetErrorText();
857 aSuggestionLB.Clear();
858 if(sError.Len())
860 LanguageType eLanguage = pBox->GetSelectLanguage();
861 Reference <XSpellAlternatives> xAlt = xSpell->spell( sError, eLanguage,
862 Sequence< PropertyValue >() );
863 if( xAlt.is() )
864 aSentenceED.SetAlternatives( xAlt );
865 else
867 aSentenceED.ChangeMarkedWord( sError, eLanguage );
868 SpellContinue_Impl();
871 aSentenceED.AddUndoAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_LANGUAGE, aDialogUndoLink));
873 SpellDialog::UpdateBoxes_Impl();
874 return 0;
876 // -----------------------------------------------------------------------
878 void SpellDialog::SetLanguage( sal_uInt16 nLang )
880 /* [Beschreibung]
882 wenn die Sprache im Thesaurus umgestellt wurde,
883 muss auch hier die Sprache umgestellt werden.
887 SetTitle_Impl( nLang );
889 // den richtigen Eintrag finden, da sortiert
890 aLanguageLB.SelectLanguage( nLang );
892 /*-- 16.06.2008 11:27:02---------------------------------------------------
894 -----------------------------------------------------------------------*/
895 static Image lcl_GetImageFromPngUrl( const ::rtl::OUString &rFileUrl )
897 Image aRes;
898 ::rtl::OUString aTmp;
899 osl::FileBase::getSystemPathFromFileURL( rFileUrl, aTmp );
900 Graphic aGraphic;
901 const String aFilterName( RTL_CONSTASCII_USTRINGPARAM( IMP_PNG ) );
902 if( GRFILTER_OK == LoadGraphic( aTmp, aFilterName, aGraphic ) )
904 aRes = Image( aGraphic.GetBitmapEx() );
906 return aRes;
908 void SpellDialog::SetTitle_Impl(LanguageType nLang)
910 String sTitle( m_sTitleSpelling );
911 if( rParent.HasGrammarChecking() )
913 String sVendor;
914 const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
915 if( pSpellErrorDescription && pSpellErrorDescription->sServiceName.getLength() )
917 bool bHighContrast = GetDisplayBackground().GetColor().IsDark() != 0;
918 ::rtl::OUString sSuggestionImageUrl =
919 SvtLinguConfig().GetSpellAndGrammarDialogImage( pSpellErrorDescription->sServiceName, bHighContrast );
920 aVendorImageFI.SetImage( lcl_GetImageFromPngUrl( sSuggestionImageUrl ) );
921 uno::Reference< lang::XServiceDisplayName > xDisplayName( pSpellErrorDescription->xGrammarChecker, uno::UNO_QUERY );
922 if( xDisplayName.is() )
923 sVendor = xDisplayName->getServiceDisplayName( pSpellErrorDescription->aLocale );
925 else
927 bool bHighContrast = GetDisplayBackground().GetColor().IsDark() != 0;
928 aVendorImageFI.SetImage( bHighContrast ? aVendorImageHC : aVendorImage );
931 if( sVendor.Len() )
933 sTitle = m_sTitleSpellingGrammarVendor;
934 sTitle.SearchAndReplaceAscii( "$VendorName", sVendor );
936 else
938 //bool bHighContrast = GetDisplayBackground().GetColor().IsDark() != 0;
939 sTitle = m_sTitleSpellingGrammar;
942 sTitle.SearchAndReplaceAscii( "$LANGUAGE ($LOCATION)", ::GetLanguageString(nLang) );
943 SetText( sTitle );
945 /*-------------------------------------------------------------------------
947 -----------------------------------------------------------------------*/
948 void SpellDialog::InitUserDicts()
950 sal_uInt16 nLang = aLanguageLB.GetSelectLanguage();
952 const Reference< XDictionary > *pDic = 0;
954 // get list of dictionaries
955 Reference< XDictionaryList > xDicList( SvxGetDictionaryList() );
956 if (xDicList.is())
958 // add active, positive dictionary to dic-list (if not already done).
959 // This is to ensure that there is at least on dictionary to which
960 // words could be added.
961 Reference< XDictionary > xDic( SvxGetOrCreatePosDic( xDicList ) );
962 if (xDic.is())
963 xDic->setActive( sal_True );
965 pImpl->aDics = xDicList->getDictionaries();
968 // Benutzerbuecher anzeigen
969 const sal_Int32 nSize = pImpl->aDics.getLength();
970 pDic = pImpl->aDics.getConstArray();
971 sal_Int32 i;
972 delete aAddToDictMB.GetPopupMenu();
973 PopupMenu* pMenu = new PopupMenu;
974 for (i = 0; i < nSize; ++i )
976 Reference< XDictionary > xDic( pDic[i], UNO_QUERY );
977 if (!xDic.is() || SvxGetIgnoreAllList() == xDic)
978 continue;
980 // add only active and not read-only dictionaries to list
981 // from which to choose from
982 Reference< frame::XStorable > xStor( xDic, UNO_QUERY );
983 if ( xDic->isActive() && (!xStor.is() || !xStor->isReadonly()) )
985 sal_Bool bNegativ = xDic->getDictionaryType() == DictionaryType_NEGATIVE;
986 pMenu->InsertItem( (USHORT)i + 1, ::GetDicInfoStr( xDic->getName(),
987 SvxLocaleToLanguage( xDic->getLocale() ), bNegativ ) );
990 aAddToDictMB.SetPopupMenu(pMenu);
992 aAddToDictMB.Disable();
994 sal_uInt16 k;
995 for ( k = 0; k < pMenu->GetItemCount(); ++k )
997 sal_uInt16 nId = pMenu->GetItemId(k) - 1;
998 sal_Bool bFound = sal_False;
1000 const sal_uInt16 nDicLang = SvxLocaleToLanguage( pDic[nId]->getLocale() );
1001 const sal_Bool bDicNegativ =
1002 pDic[nId]->getDictionaryType() == DictionaryType_NEGATIVE;
1003 // Stimmt die Sprache "uberein, dann enable
1004 if ((nDicLang == nLang || nDicLang == LANGUAGE_NONE) && !bDicNegativ)
1005 bFound = sal_True;
1007 if (bFound)
1009 aAddToDictMB.Enable();
1010 break;
1014 /*-- 20.10.2003 15:31:06---------------------------------------------------
1016 -----------------------------------------------------------------------*/
1017 IMPL_LINK(SpellDialog, AddToDictionaryHdl, MenuButton*, pButton )
1019 aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
1020 USHORT nItem = pButton->GetCurItemId();
1022 //GetErrorText() returns the current error even if the text is already
1023 //manually changed
1024 String sNewWord= aSentenceED.GetErrorText();
1026 Reference< XDictionary > xDic( pImpl->aDics.getConstArray()[ nItem - 1 ], UNO_QUERY );
1027 sal_Int16 nAddRes = DIC_ERR_UNKNOWN;
1028 if (xDic.is())
1030 String sTmpTxt( sNewWord );
1031 sal_Bool bNegEntry = xDic->getDictionaryType() == DictionaryType_NEGATIVE;
1032 nAddRes = linguistic::AddEntryToDic( xDic, sTmpTxt, bNegEntry,
1033 ::rtl::OUString(), LANGUAGE_NONE );
1035 if(nAddRes == DIC_ERR_NONE)
1037 SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
1038 SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
1039 pAction->SetDictionary(xDic);
1040 pAction->SetAddedWord(sTmpTxt);
1041 aSentenceED.AddUndoAction(pAction);
1043 // failed because there is already an entry?
1044 if (DIC_ERR_NONE != nAddRes && xDic->getEntry( sTmpTxt ).is())
1045 nAddRes = DIC_ERR_NONE;
1047 if (DIC_ERR_NONE != nAddRes)
1049 SvxDicError( this, nAddRes );
1050 return 0; // Nicht weitermachen
1052 // nach dem Aufnehmen ggf. '='-Zeichen entfernen
1053 sNewWord.EraseAllChars( sal_Unicode( '=' ) );
1055 // go on
1056 SpellContinue_Impl();
1057 aSentenceED.UndoActionEnd( SPELLUNDO_CHANGE_GROUP );
1058 return 0;
1060 /*-------------------------------------------------------------------------
1062 -----------------------------------------------------------------------*/
1063 IMPL_LINK(SpellDialog, ModifyHdl, SentenceEditWindow_Impl*, pEd)
1065 if (&aSentenceED == pEd)
1067 bModified = true;
1068 aSuggestionLB.SetNoSelection();
1069 aSuggestionLB.Disable();
1070 String sNewText( aSentenceED.GetText() );
1071 aAutoCorrPB.Enable( sNewText != aSentenceED.GetText() );
1072 SpellUndoAction_Impl* pSpellAction = new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE, aDialogUndoLink);
1073 if(!aChangeAllPB.IsEnabled())
1075 aChangeAllPB.Enable();
1076 pSpellAction->SetEnableChangeAllPB();
1078 if(!aChangePB.IsEnabled())
1080 aChangePB.Enable();
1081 pSpellAction->SetEnableChangePB();
1083 aSentenceED.AddUndoAction(pSpellAction);
1085 return 0;
1087 /*-------------------------------------------------------------------------
1089 -----------------------------------------------------------------------*/
1090 IMPL_LINK(SpellDialog, CancelHdl, Button *, EMPTYARG )
1092 //apply changes first - if there are any
1093 if(aSentenceED.IsModified())
1095 rParent.ApplyChangedSentence(aSentenceED.CreateSpellPortions(false));
1097 Close();
1098 return 0;
1100 /*-------------------------------------------------------------------------
1102 -----------------------------------------------------------------------*/
1103 void SpellDialog::Paint( const Rectangle& rRect )
1105 ModelessDialog::Paint(rRect );
1106 Rectangle aRect(aBackgroundGB.GetPosPixel(), aBackgroundGB.GetSizePixel());
1107 DecorationView aDecoView( this );
1108 aDecoView.DrawButton( aRect, BUTTON_DRAW_NOFILL);
1110 /*-- 28.10.2003 13:26:39---------------------------------------------------
1112 -----------------------------------------------------------------------*/
1113 long SpellDialog::Notify( NotifyEvent& rNEvt )
1115 /* #i38338#
1116 * FIXME: LoseFocus and GetFocus are signals from vcl that
1117 * a window actually got/lost the focus, it never should be
1118 * forwarded from another window, that is simply wrong.
1119 * FIXME: overloading the virtual methods GetFocus and LoseFocus
1120 * in SpellDialogChildWindow by making them pure is at least questionable.
1121 * The only sensible thing would be to call the new Method differently,
1122 * e.g. DialogGot/LostFocus or so.
1124 if( IsVisible() && !bFocusLocked )
1126 if( rNEvt.GetType() == EVENT_GETFOCUS )
1128 //notify the child window of the focus change
1129 rParent.GetFocus();
1131 else if( rNEvt.GetType() == EVENT_LOSEFOCUS )
1133 //notify the child window of the focus change
1134 rParent.LoseFocus();
1137 return SfxModelessDialog::Notify(rNEvt);
1139 /* -----------------10.09.2003 08:26-----------------
1141 --------------------------------------------------*/
1142 void SpellDialog::InvalidateDialog()
1144 if( bFocusLocked )
1145 return;
1146 aIgnorePB.SetText(aResumeST);
1147 Window* aDisableArr[] =
1149 &aNotInDictFT,
1150 &aSentenceED,
1151 &aSuggestionFT,
1152 &aSuggestionLB,
1153 &aLanguageFT,
1154 &aLanguageLB,
1155 &aIgnoreAllPB,
1156 &aIgnoreRulePB,
1157 &aAddToDictMB,
1158 &aChangePB,
1159 &aChangeAllPB,
1160 &aAutoCorrPB,
1161 &aUndoPB,
1164 sal_Int16 i = 0;
1165 while(aDisableArr[i])
1167 aDisableArr[i]->Enable(FALSE);
1168 i++;
1170 SfxModelessDialog::Deactivate();
1173 /*-- 10.09.2003 08:35:56---------------------------------------------------
1175 -----------------------------------------------------------------------*/
1176 bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence)
1178 bool bRet = false;
1179 if(!bUseSavedSentence && aSentenceED.IsModified())
1181 rParent.ApplyChangedSentence(aSentenceED.CreateSpellPortions(false));
1183 aSentenceED.ResetModified();
1184 SpellPortions aSentence = bUseSavedSentence ? m_aSavedSentence : rParent.GetNextWrongSentence();
1185 if(!bUseSavedSentence)
1186 m_aSavedSentence = aSentence;
1187 bool bHasReplaced = false;
1188 while(aSentence.size())
1190 //apply all changes that are already part of the "ChangeAllList"
1191 //returns true if the list still contains errors after the changes have been applied
1193 if(!ApplyChangeAllList_Impl(aSentence, bHasReplaced))
1195 rParent.ApplyChangedSentence(aSentence);
1196 aSentence = rParent.GetNextWrongSentence();
1198 else
1199 break;
1202 if(aSentence.size())
1204 SpellPortions::iterator aStart = aSentence.begin();
1205 rtl::OUString sText;
1206 while(aStart != aSentence.end())
1208 // hidden text has to be ignored
1209 if(!aStart->bIsHidden)
1210 sText += aStart->sText;
1211 aStart++;
1213 aSentenceED.SetText(sText);
1214 aStart = aSentence.begin();
1215 sal_Int32 nStartPosition = 0;
1216 sal_Int32 nEndPosition = 0;
1218 while(aStart != aSentence.end())
1220 // hidden text has to be ignored
1221 if(!aStart->bIsHidden)
1223 nEndPosition += aStart->sText.getLength();
1224 if(aStart->xAlternatives.is())
1226 uno::Reference< container::XNamed > xNamed( aStart->xAlternatives, uno::UNO_QUERY );
1227 ::rtl::OUString sServiceName;
1228 if( xNamed.is() )
1229 sServiceName = xNamed->getName();
1230 SpellErrorDescription aDesc( false, aStart->xAlternatives->getWord(),
1231 aStart->xAlternatives->getLocale(), aStart->xAlternatives->getAlternatives(), 0, sServiceName);
1232 aSentenceED.SetAttrib( SpellErrorAttrib(aDesc), 0, (USHORT) nStartPosition, (USHORT) nEndPosition );
1234 else if(aStart->bIsGrammarError )
1236 uno::Reference< lang::XServiceInfo > xInfo( aStart->xGrammarChecker, uno::UNO_QUERY );
1237 SpellErrorDescription aDesc( true,
1238 aStart->sText,
1239 SvxCreateLocale( aStart->eLanguage ),
1240 aStart->aGrammarError.aSuggestions,
1241 aStart->xGrammarChecker,
1242 xInfo->getImplementationName(),
1243 &aStart->sDialogTitle,
1244 &aStart->aGrammarError.aFullComment,
1245 &aStart->aGrammarError.aRuleIdentifier );
1246 aSentenceED.SetAttrib( SpellErrorAttrib(aDesc), 0, (USHORT) nStartPosition, (USHORT) nEndPosition );
1248 if(aStart->bIsField)
1249 aSentenceED.SetAttrib( SpellBackgroundAttrib(COL_LIGHTGRAY), 0, (USHORT) nStartPosition, (USHORT) nEndPosition );
1250 aSentenceED.SetAttrib( SpellLanguageAttrib(aStart->eLanguage), 0, (USHORT) nStartPosition, (USHORT) nEndPosition );
1251 nStartPosition = nEndPosition;
1253 aStart++;
1255 //the edit field needs to be modified to apply the change from the ApplyChangeAllList
1256 if(!bHasReplaced)
1257 aSentenceED.ClearModifyFlag();
1258 aSentenceED.ResetUndo();
1259 aUndoPB.Enable(FALSE);
1260 bRet = nStartPosition > 0;
1262 return bRet;
1264 /*-- 12.11.2003 15:21:25---------------------------------------------------
1265 replace errrors that have a replacement in the ChangeAllList
1266 returns false if the result doesn't contain errors after the replacement
1267 -----------------------------------------------------------------------*/
1268 bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions& rSentence, bool &bHasReplaced)
1270 bHasReplaced = false;
1271 bool bRet = true;
1272 SpellPortions::iterator aStart = rSentence.begin();
1273 Reference<XDictionary> xChangeAll( SvxGetChangeAllList(), UNO_QUERY );
1274 if(!xChangeAll->getCount())
1275 return bRet;
1276 bRet = false;
1277 while(aStart != rSentence.end())
1279 if(aStart->xAlternatives.is())
1281 Reference<XDictionaryEntry> xEntry = xChangeAll->getEntry( aStart->sText );
1282 if(xEntry.is())
1284 aStart->sText = xEntry->getReplacementText();
1285 aStart->xAlternatives = 0;
1286 bHasReplaced = true;
1288 else
1289 bRet = true;
1291 else if( aStart->bIsGrammarError )
1292 bRet = true;
1293 aStart++;
1295 return bRet;
1297 /*-- 10.09.2003 10:40:21---------------------------------------------------
1299 -----------------------------------------------------------------------*/
1300 SentenceEditWindow_Impl::SentenceEditWindow_Impl( SpellDialog* pParent, const ResId& rResId ) :
1301 MultiLineEdit( pParent, rResId ),
1302 m_nErrorStart(0),
1303 m_nErrorEnd(0),
1304 m_bIsUndoEditMode(false)
1306 DisableSelectionOnFocus();
1308 /*-- 10.09.2003 10:40:11---------------------------------------------------
1310 -----------------------------------------------------------------------*/
1311 SentenceEditWindow_Impl::~SentenceEditWindow_Impl()
1314 /*-- 20.10.2003 13:42:34---------------------------------------------------
1315 The selection before inputting a key may have a range or not
1316 and it may be inside or outside of field or error attributes.
1317 A range may include the attribute partially, completely or together
1318 with surrounding text. It may also contain more than one attribute
1319 or no attribute at all.
1320 Depending on this starting conditions some actions are necessary:
1321 Attempts to delete a field are only allowed if the selection is the same
1322 as the field's selection. Otherwise the field has to be selected and the key
1323 input action has to be skipped.
1324 Input of text at the start of the field requires the field attribute to be
1325 corrected - it is not allowed to grow.
1327 In case of errors the appending of text should grow the error attribute because
1328 that is what the user usually wants to do.
1330 Backspace at the start of the attribute requires to find out if a field ends
1331 directly in front of the cursor position. In case of a field this attribute has to be
1332 selected otherwise the key input method is allowed.
1334 All changes outside of the error attributes switch the dialog mode to a "Undo edit" state that
1335 removes all visible attributes and switches off further attribute checks.
1336 Undo in this restarts the dialog with a current sentence newly presented.
1337 All changes to the sentence are undone including the ones before the "Undo edit state" has been reached
1339 We end up with 9 types of selection
1340 1 (LEFT_NO) - no range, start of attribute - can also be 3 at the same time
1341 2 (INSIDE_NO) - no range, inside of attribute
1342 3 (RIGHT_NO) - no range, end of attribute - can also be 1 at the same time
1343 4 (FULL) - range, same as attribute
1344 5 (INSIDE_YES) - range, inside of the attribute
1345 6 (BRACE)- range, from outside of the attribute to the inside or
1346 including the complete attribute and something outside,
1347 maybe more than one attribute
1348 7 (OUTSIDE_NO) - no range, not at an attribute
1349 8 (OUTSIDE_YES) - range, completely outside of all attributes
1351 What has to be done depending on the attribute type involved
1352 possible actions: UE - Undo edit mode
1353 CO - Continue, no additional action is required
1354 FS - Field has to be completely selected
1355 EX - The attribute has to be expanded to include the added text
1357 1 - backspace delete any other
1358 UE on field FS on error CO on field FS on error CO
1360 2 - on field FS on error C
1361 3 - backspace delete any other
1362 on field FS on error CO UE on field UE on error EX
1364 if 1 and 3 happen to apply both then backspace and other handling is 1 delete is 3
1366 4 - on field UE and on error CO
1367 5 - on field FS and on error CO
1368 6 - on field FS and on error UE
1369 7 - UE
1370 8 - UE
1371 -----------------------------------------------------------------------*/
1372 #define INVALID 0
1373 #define LEFT_NO 1
1374 #define INSIDE_NO 2
1375 #define RIGHT_NO 3
1376 #define FULL 4
1377 #define INSIDE_YES 5
1378 #define BRACE 6
1379 #define OUTSIDE_NO 7
1380 #define OUTSIDE_YES 8
1382 #define ACTION_UNDOEDIT 0
1383 #define ACTION_CONTINUE 1
1384 #define ACTION_SELECTFIELD 2
1385 #define ACTION_EXPAND 3
1387 long SentenceEditWindow_Impl::PreNotify( NotifyEvent& rNEvt )
1389 bool bChange = false;
1390 const TextCharAttrib* pErrorAttrib = 0;
1391 if(rNEvt.GetType() == EVENT_KEYINPUT)
1393 const KeyEvent& rKeyEvt = *rNEvt.GetKeyEvent();
1394 bChange = TextEngine::DoesKeyChangeText( rKeyEvt );
1395 if(bChange && !IsUndoEditMode() &&
1396 rKeyEvt.GetKeyCode().GetCode() != KEY_TAB)
1398 TextEngine* pTextEngine = GetTextEngine();
1399 TextView* pTextView = pTextEngine->GetActiveView();
1400 const TextSelection& rCurrentSelection = pTextView->GetSelection();
1401 //determine if the selection contains a field
1402 bool bHasField = false;
1403 bool bHasError = false;
1404 bool bHasFieldLeft = false;
1405 bool bHasErrorLeft = false;
1406 // bool bInsideAttr = false;
1408 bool bHasRange = rCurrentSelection.HasRange();
1409 sal_uInt8 nSelectionType = 0; // invalid type!
1411 TextPaM aCursor(rCurrentSelection.GetStart());
1412 const TextCharAttrib* pBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
1413 const TextCharAttrib* pErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
1414 const TextCharAttrib* pBackAttrLeft = 0;
1415 const TextCharAttrib* pErrorAttrLeft = 0;
1417 bHasField = pBackAttr != 0 && (bHasRange || pBackAttr->GetEnd() > aCursor.GetIndex());
1418 bHasError = pErrorAttr != 0 && (bHasRange || pErrorAttr->GetEnd() > aCursor.GetIndex());
1419 if(bHasRange)
1421 if(pBackAttr &&
1422 pBackAttr->GetStart() == rCurrentSelection.GetStart().GetIndex() &&
1423 pBackAttr->GetEnd() == rCurrentSelection.GetEnd().GetIndex())
1425 nSelectionType = FULL;
1427 else if(pErrorAttr &&
1428 pErrorAttr->GetStart() <= rCurrentSelection.GetStart().GetIndex() &&
1429 pErrorAttr->GetEnd() >= rCurrentSelection.GetEnd().GetIndex())
1431 nSelectionType = INSIDE_YES;
1433 else
1435 nSelectionType = bHasField||bHasError ? BRACE : OUTSIDE_NO;
1436 while(aCursor.GetIndex() < rCurrentSelection.GetEnd().GetIndex())
1438 ++aCursor.GetIndex();
1439 const TextCharAttrib* pIntBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
1440 const TextCharAttrib* pIntErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
1441 //if any attr has been found then BRACE
1442 if(pIntBackAttr || pIntErrorAttr)
1443 nSelectionType = BRACE;
1444 //the field has to be selected
1445 if(pIntBackAttr && !pBackAttr)
1446 pBackAttr = pIntBackAttr;
1447 bHasField |= pIntBackAttr != 0;
1451 else
1453 //no range selection: then 1 2 3 and 8 are possible
1454 const TextCharAttrib* pCurAttr = pBackAttr ? pBackAttr : pErrorAttr;
1455 if(pCurAttr)
1457 nSelectionType = pCurAttr->GetStart() == rCurrentSelection.GetStart().GetIndex() ?
1458 LEFT_NO : pCurAttr->GetEnd() == rCurrentSelection.GetEnd().GetIndex() ? RIGHT_NO : INSIDE_NO;
1460 else
1461 nSelectionType = OUTSIDE_NO;
1463 bHasFieldLeft = pBackAttr && pBackAttr->GetEnd() == aCursor.GetIndex();
1464 if(bHasFieldLeft)
1466 pBackAttrLeft = pBackAttr;
1467 pBackAttr = 0;
1469 bHasErrorLeft = pErrorAttr && pErrorAttr->GetEnd() == aCursor.GetIndex();
1470 if(bHasErrorLeft)
1472 pErrorAttrLeft = pErrorAttr;
1473 pErrorAttr = 0;
1476 //check previous position if this exists
1477 //that is a redundant in the case the the attribute found above already is on the left cursor side
1478 //but it's o.k. for two errors/fields side by side
1479 if(aCursor.GetIndex())
1481 --aCursor.GetIndex();
1482 pBackAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
1483 pErrorAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
1484 bHasFieldLeft = pBackAttrLeft !=0;
1485 bHasErrorLeft = pErrorAttrLeft != 0;
1486 // bInsideAttr = (bHasField || bHasError) && (bHasFieldLeft || bHasErrorLeft);
1487 ++aCursor.GetIndex();
1490 //Here we have to determine if the error found is the one currently active
1491 bool bIsErrorActive = (pErrorAttr && pErrorAttr->GetStart() == m_nErrorStart) ||
1492 (pErrorAttrLeft && pErrorAttrLeft->GetStart() == m_nErrorStart);
1494 DBG_ASSERT(nSelectionType != INVALID, "selection type not set!");
1496 const KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
1497 bool bDelete = rKeyCode.GetCode() == KEY_DELETE;
1498 bool bBackspace = rKeyCode.GetCode() == KEY_BACKSPACE;
1500 sal_Int8 nAction = ACTION_CONTINUE;
1501 // nAction = ACTION_UNDOEDIT
1502 // nAction = ACTION_SELECTFIELD
1503 // nAction = ACTION_EXPAND
1504 switch(nSelectionType)
1506 // 1 - backspace delete any other
1507 // UE on field FS on error CO on field FS on error CO
1508 case LEFT_NO :
1509 if(bBackspace)
1511 nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
1512 //to force the use of pBackAttrLeft
1513 pBackAttr = 0;
1515 else if(bDelete)
1516 nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1517 else
1518 nAction = bHasError && !aCursor.GetIndex() ? ACTION_CONTINUE :
1519 bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1520 break;
1521 // 2 - on field FS on error C
1522 case INSIDE_NO :
1523 nAction = bHasField ? ACTION_SELECTFIELD :
1524 bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1525 break;
1526 // 3 - backspace delete any other
1527 // on field FS on error CO UE on field UE on error EX
1528 case RIGHT_NO :
1529 if(bBackspace)
1530 nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1531 else if(bDelete)
1532 nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1533 else
1534 nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
1535 bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT;
1536 break;
1537 // 4 - on field UE and on error CO
1538 case FULL :
1539 nAction = bHasField ? ACTION_UNDOEDIT : ACTION_CONTINUE;
1540 break;
1541 // 5 - on field FS and on error CO
1542 case INSIDE_YES :
1543 nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1544 break;
1545 // 6 - on field FS and on error UE
1546 case BRACE :
1547 nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;;
1548 break;
1549 // 7 - UE
1550 // 8 - UE
1551 case OUTSIDE_NO :
1552 case OUTSIDE_YES:
1553 nAction = ACTION_UNDOEDIT;
1554 break;
1556 //save the current paragraph
1557 USHORT nCurrentLen = GetText().Len();
1558 if(nAction != ACTION_SELECTFIELD)
1559 pTextView->GetWindow()->KeyInput(rKeyEvt);
1560 else
1562 const TextCharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft;
1563 if(pCharAttr)
1565 TextPaM aStart(0, pCharAttr->GetStart());
1566 TextPaM aEnd(0, pCharAttr->GetEnd());
1567 TextSelection aNewSel(aStart, aEnd);
1568 pTextView->SetSelection( aNewSel);
1571 if(nAction == ACTION_EXPAND)
1573 DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error");
1574 //text has been added on the right and only the 'error attribute has to be corrected
1575 if(pErrorAttrLeft)
1577 TextAttrib* pNewError = pErrorAttrLeft->GetAttr().Clone();
1578 USHORT nStart = pErrorAttrLeft->GetStart();
1579 USHORT nEnd = pErrorAttrLeft->GetEnd();
1580 pTextEngine->RemoveAttrib( 0, *pErrorAttrLeft );
1581 SetAttrib( *pNewError, 0, nStart, ++nEnd );
1582 //only active errors move the mark
1583 if(bIsErrorActive)
1585 bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
1586 MoveErrorMarkTo(nStart, nEnd, bGrammar);
1588 delete pNewError;
1590 //text has been added on the left then the error attribute has to be expanded and the
1591 //field attribute on the right - if any - has to be contracted
1592 else if(pErrorAttr)
1594 //determine the change
1595 USHORT nAddedChars = GetText().Len() - nCurrentLen;
1597 TextAttrib* pNewError = pErrorAttr->GetAttr().Clone();
1598 USHORT nStart = pErrorAttr->GetStart();
1599 USHORT nEnd = pErrorAttr->GetEnd();
1600 pTextEngine->RemoveAttrib( 0, *pErrorAttr );
1601 nStart = nStart - (USHORT)nAddedChars;
1602 SetAttrib( *pNewError, 0, nStart - nAddedChars, nEnd );
1603 //only if the error is active the mark is moved here
1604 if(bIsErrorActive)
1606 bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
1607 MoveErrorMarkTo(nStart, nEnd, bGrammar);
1609 delete pNewError;
1611 if(pBackAttrLeft)
1613 TextAttrib* pNewBack = pBackAttrLeft->GetAttr().Clone();
1614 USHORT _nStart = pBackAttrLeft->GetStart();
1615 USHORT _nEnd = pBackAttrLeft->GetEnd();
1616 pTextEngine->RemoveAttrib( 0, *pBackAttrLeft );
1617 SetAttrib( *pNewBack, 0, _nStart, _nEnd - nAddedChars);
1618 delete pNewBack;
1622 else if(nAction == ACTION_UNDOEDIT)
1624 SetUndoEditMode(true);
1626 //make sure the error positions are correct after text changes
1627 //the old attribute may have been deleted
1628 //all changes inside of the current error leave the error attribute at the current
1629 //start position
1630 if(!IsUndoEditMode() && bIsErrorActive)
1632 const TextCharAttrib* pFontColor = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_FONTCOLOR );
1633 pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
1634 if(pFontColor && pErrorAttrib )
1636 m_nErrorStart = pFontColor->GetStart();
1637 m_nErrorEnd = pFontColor->GetEnd();
1638 if(pErrorAttrib->GetStart() != m_nErrorStart || pErrorAttrib->GetEnd() != m_nErrorEnd)
1640 TextAttrib* pNewError = pErrorAttrib->GetAttr().Clone();
1641 pTextEngine->RemoveAttrib( 0, *pErrorAttr );
1642 SetAttrib( *pNewError, 0, m_nErrorStart, m_nErrorEnd );
1643 delete pNewError;
1647 //this is not a modification anymore
1648 if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
1649 CallModifyLink();
1651 else
1652 bChange = false;
1654 long nRet = bChange ? 1 : MultiLineEdit::PreNotify(rNEvt);
1655 return nRet;
1657 /*-- 10.09.2003 13:38:14---------------------------------------------------
1659 -----------------------------------------------------------------------*/
1660 bool SentenceEditWindow_Impl::MarkNextError()
1662 ExtTextEngine* pTextEngine = GetTextEngine();
1663 USHORT nTextLen = pTextEngine->GetTextLen(0);
1664 if(m_nErrorEnd >= nTextLen - 1)
1665 return false;
1666 //if it's not already modified the modified flag has to be reset at the and of the marking
1667 bool bModified = IsModified();
1668 bool bRet = false;
1669 const USHORT nOldErrorStart = m_nErrorStart;
1670 const USHORT nOldErrorEnd = m_nErrorEnd;
1672 //create a cursor behind the end of the last error
1673 //- or at 0 at the start of the sentence
1674 TextPaM aCursor(0, m_nErrorEnd ? m_nErrorEnd + 1 : 0);
1675 //search for SpellErrorAttrib
1677 const TextCharAttrib* pNextError = 0;
1678 //iterate over the text and search for the next error that maybe has
1679 //to be replace by a ChangeAllList replacement
1680 bool bGrammarError = false;
1681 while(aCursor.GetIndex() < nTextLen)
1683 while(aCursor.GetIndex() < nTextLen &&
1684 0 == (pNextError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR)))
1686 ++aCursor.GetIndex();
1688 // maybe the error found here is already in the ChangeAllList and has to be replaced
1690 Reference<XDictionary> xChangeAll( SvxGetChangeAllList(), UNO_QUERY );
1691 Reference<XDictionaryEntry> xEntry;
1693 // Reference <XSpellAlternatives> xAlternatives;
1694 const SpellErrorDescription* pSpellErrorDescription = 0;
1695 if(pNextError)
1697 pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pNextError->GetAttr()).GetErrorDescription();
1698 bGrammarError = pSpellErrorDescription->bIsGrammarError;
1700 if(xChangeAll->getCount() && pSpellErrorDescription &&
1701 (xEntry = xChangeAll->getEntry( pSpellErrorDescription->sErrorText )).is())
1703 m_nErrorStart = pNextError->GetStart();
1704 m_nErrorEnd = pNextError->GetEnd();
1705 ChangeMarkedWord(xEntry->getReplacementText(),
1706 SvxLocaleToLanguage( pSpellErrorDescription->aLocale ));
1707 aCursor.GetIndex() = aCursor.GetIndex() + (USHORT)(xEntry->getReplacementText().getLength());
1709 else
1710 break;
1713 //if an attrib has been found search for the end of the error string
1714 if(aCursor.GetIndex() < nTextLen)
1716 m_nErrorStart = aCursor.GetIndex();
1717 m_nErrorEnd = pNextError->GetEnd();
1718 MoveErrorMarkTo(m_nErrorStart, m_nErrorEnd, bGrammarError);
1719 bRet = true;
1720 //add an undo action
1721 SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
1722 SPELLUNDO_CHANGE_NEXTERROR, GetSpellDialog()->aDialogUndoLink);
1723 pAction->SetErrorMove(m_nErrorStart, m_nErrorEnd, nOldErrorStart, nOldErrorEnd);
1724 const SpellErrorAttrib* pOldAttrib = static_cast<const SpellErrorAttrib*>(
1725 pTextEngine->FindAttrib( TextPaM(0, nOldErrorStart), TEXTATTR_SPELL_ERROR ));
1726 pAction->SetErrorLanguageSelected(pOldAttrib && pOldAttrib->GetErrorDescription().aSuggestions.getLength() &&
1727 SvxLocaleToLanguage( pOldAttrib->GetErrorDescription().aLocale) ==
1728 GetSpellDialog()->aLanguageLB.GetSelectLanguage());
1729 AddUndoAction(pAction);
1731 else
1732 m_nErrorStart = m_nErrorEnd = nTextLen;
1733 if( !bModified )
1734 ClearModifyFlag();
1735 SpellDialog* pSpellDialog = GetSpellDialog();
1736 pSpellDialog->aIgnorePB.Enable(bRet);
1737 pSpellDialog->aIgnoreAllPB.Enable(bRet);
1738 pSpellDialog->aAutoCorrPB.Enable(bRet);
1739 pSpellDialog->aAddToDictMB.Enable(bRet);
1740 return bRet;
1743 /*-- 06.11.2003 13:30:26---------------------------------------------------
1745 -----------------------------------------------------------------------*/
1746 void SentenceEditWindow_Impl::MoveErrorMarkTo(USHORT nStart, USHORT nEnd, bool bGrammarError)
1748 TextEngine* pTextEngine = GetTextEngine();
1749 pTextEngine->RemoveAttribs( 0, (USHORT)TEXTATTR_FONTCOLOR, TRUE );
1750 pTextEngine->RemoveAttribs( 0, (USHORT)TEXTATTR_FONTWEIGHT, TRUE );
1751 pTextEngine->SetAttrib( TextAttribFontWeight(WEIGHT_BOLD), 0, nStart, nEnd );
1752 pTextEngine->SetAttrib( TextAttribFontColor(bGrammarError ? COL_LIGHTBLUE : COL_LIGHTRED), 0, nStart, nEnd );
1753 m_nErrorStart = nStart;
1754 m_nErrorEnd = nEnd;
1757 /*-- 17.09.2003 10:13:08---------------------------------------------------
1759 -----------------------------------------------------------------------*/
1760 void SentenceEditWindow_Impl::ChangeMarkedWord(const String& rNewWord, LanguageType eLanguage)
1762 //calculate length changes
1763 long nDiffLen = rNewWord.Len() - m_nErrorEnd + m_nErrorStart;
1764 TextSelection aSel(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd));
1765 //Remove spell errror attribute
1766 ExtTextEngine* pTextEngine = GetTextEngine();
1767 pTextEngine->UndoActionStart( TEXTUNDO_INSERT );
1768 const TextCharAttrib* pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
1769 DBG_ASSERT(pErrorAttrib, "no error attribute found");
1770 // Reference <XSpellAlternatives> xAlternatives;
1771 const SpellErrorDescription* pSpellErrorDescription = 0;
1772 if(pErrorAttrib)
1774 pTextEngine->RemoveAttrib(0, *pErrorAttrib);
1775 pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pErrorAttrib->GetAttr()).GetErrorDescription();
1777 const TextCharAttrib* pBackAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_BACKGROUND );
1778 pTextEngine->ReplaceText( aSel, rNewWord );
1780 if(!m_nErrorStart)
1782 //attributes following an error at the start of the text are not moved but expanded from the
1783 //text engine - this is done to keep full-paragraph-attributes
1784 //in the current case that handling is not desired
1785 const TextCharAttrib* pLangAttrib =
1786 pTextEngine->FindCharAttrib(
1787 TextPaM(0, m_nErrorEnd), TEXTATTR_SPELL_LANGUAGE );
1788 USHORT nTextLen = pTextEngine->GetTextLen( 0 );
1789 if(pLangAttrib && !pLangAttrib->GetStart() && pLangAttrib->GetEnd() ==
1790 nTextLen)
1792 SpellLanguageAttrib aNewLangAttrib( static_cast<const SpellLanguageAttrib&>(pLangAttrib->GetAttr()).GetLanguage());
1793 pTextEngine->RemoveAttrib(0, *pLangAttrib);
1794 pTextEngine->SetAttrib( aNewLangAttrib, 0, (USHORT)(m_nErrorEnd + nDiffLen) , nTextLen );
1797 // undo expanded attributes!
1798 if( pBackAttrib && pBackAttrib->GetStart() < m_nErrorStart && pBackAttrib->GetEnd() == m_nErrorEnd + nDiffLen)
1800 TextAttrib* pNewBackground = pBackAttrib->GetAttr().Clone();
1801 USHORT nStart = pBackAttrib->GetStart();
1802 pTextEngine->RemoveAttrib(0, *pBackAttrib);
1803 pTextEngine->SetAttrib(*pNewBackground, 0, nStart, m_nErrorStart);
1804 delete pNewBackground;
1806 pTextEngine->SetModified(TRUE);
1808 //adjust end position
1809 long nEndTemp = m_nErrorEnd;
1810 nEndTemp += nDiffLen;
1811 m_nErrorEnd = (USHORT)nEndTemp;
1813 SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
1814 SPELLUNDO_MOVE_ERROREND, GetSpellDialog()->aDialogUndoLink);
1815 pAction->SetOffset(nDiffLen);
1816 AddUndoAction(pAction);
1817 if(pSpellErrorDescription)
1818 SetAttrib( SpellErrorAttrib(*pSpellErrorDescription), 0, m_nErrorStart, m_nErrorEnd );
1819 SetAttrib( SpellLanguageAttrib(eLanguage), 0, m_nErrorStart, m_nErrorEnd );
1820 pTextEngine->UndoActionEnd( TEXTUNDO_INSERT );
1822 /* -----------------08.10.2003 13:18-----------------
1824 --------------------------------------------------*/
1825 String SentenceEditWindow_Impl::GetErrorText() const
1827 return GetTextEngine()->GetText(TextSelection(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd) ));
1829 /*-- 26.06.2008 10:54:13---------------------------------------------------
1831 -----------------------------------------------------------------------*/
1832 const SpellErrorDescription* SentenceEditWindow_Impl::GetAlternatives()
1834 TextPaM aCursor(0, m_nErrorStart);
1835 const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
1836 GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
1837 return pAttrib ? &pAttrib->GetErrorDescription() : 0;
1839 /*-- 06.09.2004 10:50:32---------------------------------------------------
1841 -----------------------------------------------------------------------*/
1842 void SentenceEditWindow_Impl::RestoreCurrentError()
1844 TextPaM aCursor(0, m_nErrorStart);
1845 const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
1846 GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
1847 if( pAttrib )
1849 const SpellErrorDescription& rDesc = pAttrib->GetErrorDescription();
1850 if( !rDesc.sErrorText.equals( GetErrorText() ) )
1851 ChangeMarkedWord(rDesc.sErrorText, SvxLocaleToLanguage( rDesc.aLocale ));
1854 /*-- 28.10.2003 14:44:10---------------------------------------------------
1856 -----------------------------------------------------------------------*/
1857 void SentenceEditWindow_Impl::SetAlternatives( Reference< XSpellAlternatives> xAlt )
1859 TextPaM aCursor(0, m_nErrorStart);
1860 DBG_ASSERT(static_cast<const SpellErrorAttrib*>(
1861 GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR)), "no error set?");
1863 ::rtl::OUString aWord;
1864 lang::Locale aLocale;
1865 uno::Sequence< ::rtl::OUString > aAlts;
1866 ::rtl::OUString sServiceName;
1867 if (xAlt.is())
1869 aWord = xAlt->getWord();
1870 aLocale = xAlt->getLocale();
1871 aAlts = xAlt->getAlternatives();
1872 uno::Reference< container::XNamed > xNamed( xAlt, uno::UNO_QUERY );
1873 if (xNamed.is())
1874 sServiceName = xNamed->getName();
1876 SpellErrorDescription aDesc( false, aWord, aLocale, aAlts, 0, sServiceName);
1877 GetTextEngine()->SetAttrib( SpellErrorAttrib(aDesc), 0, m_nErrorStart, m_nErrorEnd );
1880 /*-- 10.09.2003 14:43:02---------------------------------------------------
1882 -----------------------------------------------------------------------*/
1883 void SentenceEditWindow_Impl::SetAttrib( const TextAttrib& rAttr, ULONG nPara, USHORT nStart, USHORT nEnd )
1885 GetTextEngine()->SetAttrib(rAttr, nPara, nStart, nEnd);
1887 /*-- 10.09.2003 14:43:02---------------------------------------------------
1889 -----------------------------------------------------------------------*/
1890 void SentenceEditWindow_Impl::SetText( const String& rStr )
1892 m_nErrorStart = m_nErrorEnd = 0;
1893 GetTextEngine()->SetText(rStr);
1894 // InitScrollBars();
1896 /*-- 08.10.2003 14:35:52---------------------------------------------------
1898 -----------------------------------------------------------------------*/
1899 struct LanguagePosition_Impl
1901 USHORT nPosition;
1902 LanguageType eLanguage;
1904 LanguagePosition_Impl(USHORT nPos, LanguageType eLang) :
1905 nPosition(nPos),
1906 eLanguage(eLang)
1909 typedef std::vector<LanguagePosition_Impl> LanguagePositions_Impl;
1911 void lcl_InsertBreakPosition_Impl(
1912 LanguagePositions_Impl& rBreakPositions, USHORT nInsert, LanguageType eLanguage)
1914 LanguagePositions_Impl::iterator aStart = rBreakPositions.begin();
1915 while(aStart != rBreakPositions.end())
1917 if(aStart->nPosition == nInsert)
1919 //the language of following starts has to overwrite
1920 //the one of previous ends
1921 aStart->eLanguage = eLanguage;
1922 return;
1924 else if(aStart->nPosition > nInsert)
1927 rBreakPositions.insert(aStart, LanguagePosition_Impl(nInsert, eLanguage));
1928 return;
1930 else
1931 ++aStart;
1933 rBreakPositions.push_back(LanguagePosition_Impl(nInsert, eLanguage));
1935 /*-- 17.09.2003 14:26:59---------------------------------------------------
1936 Returns the text in spell portions. Each portion contains text with an
1937 equal language and attribute. The spell alternatives are empty.
1938 -----------------------------------------------------------------------*/
1939 svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions( bool bSetIgnoreFlag ) const
1941 svx::SpellPortions aRet;
1942 ExtTextEngine* pTextEngine = GetTextEngine();
1943 const USHORT nTextLen = pTextEngine->GetTextLen(0);
1944 if(nTextLen)
1946 TextPaM aCursor(0, 0);
1947 LanguagePositions_Impl aBreakPositions;
1948 const TextCharAttrib* pLastLang = 0;
1949 const TextCharAttrib* pLastError = 0;
1950 LanguageType eLang = LANGUAGE_DONTKNOW;
1951 const TextCharAttrib* pError = 0;
1952 while(aCursor.GetIndex() < nTextLen)
1954 const TextCharAttrib* pLang = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_LANGUAGE);
1955 if(pLang && pLang != pLastLang)
1957 eLang = static_cast<const SpellLanguageAttrib&>(pLang->GetAttr()).GetLanguage();
1958 lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetStart(), eLang);
1959 lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetEnd(), eLang);
1960 pLastLang = pLang;
1962 pError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR);
1963 if(pError && pLastError != pError)
1965 lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetStart(), eLang);
1966 lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetEnd(), eLang);
1967 pLastError = pError;
1970 aCursor.GetIndex()++;
1973 if(nTextLen && aBreakPositions.empty())
1975 //if all content has been overwritten the attributes may have been removed, too
1976 svx::SpellPortion aPortion1;
1977 aPortion1.eLanguage = GetSpellDialog()->GetSelectedLang_Impl();
1978 aPortion1.sText = pTextEngine->GetText(
1979 TextSelection(TextPaM(0, 0), TextPaM(0, nTextLen)));
1981 aRet.push_back(aPortion1);
1984 else if(!aBreakPositions.empty())
1986 LanguagePositions_Impl::iterator aStart = aBreakPositions.begin();
1987 //start should always be Null
1988 eLang = aStart->eLanguage;
1989 USHORT nStart = aStart->nPosition;
1990 DBG_ASSERT(!nStart, "invalid start position - language attribute missing?");
1991 ++aStart;
1993 while(aStart != aBreakPositions.end())
1995 svx::SpellPortion aPortion1;
1996 aPortion1.eLanguage = eLang;
1997 aPortion1.sText = pTextEngine->GetText(
1998 TextSelection(TextPaM(0, nStart), TextPaM(0, aStart->nPosition)));
1999 if( bSetIgnoreFlag && m_nErrorStart == nStart )
2001 aPortion1.bIgnoreThisError = true;
2003 aRet.push_back(aPortion1);
2004 nStart = aStart->nPosition;
2005 eLang = aStart->eLanguage;
2006 ++aStart;
2010 // quick partly fix of #i71318. Correct fix needs to patch the TextEngine itself...
2011 // this one will only prevent text from disappearing. It may to not have the
2012 // correct language and will probably not spell checked...
2013 ULONG nPara = pTextEngine->GetParagraphCount();
2014 if (nPara > 1)
2016 String aLeftOverText;
2017 for (ULONG i = 1; i < nPara; ++i)
2019 aLeftOverText.AppendAscii( "\x0a" ); // the manual line break...
2020 aLeftOverText += pTextEngine->GetText(i);
2022 if (pError)
2023 { // we need to add a new portion containing the left-over text
2024 svx::SpellPortion aPortion2;
2025 aPortion2.eLanguage = eLang;
2026 aPortion2.sText = aLeftOverText;
2027 aRet.push_back( aPortion2 );
2029 else
2030 { // we just need to append the left-over text to the last portion (which had no errors)
2031 aRet[ aRet.size() - 1 ].sText += aLeftOverText;
2035 return aRet;
2038 /*-- 06.11.2003 11:30:10---------------------------------------------------
2040 -----------------------------------------------------------------------*/
2041 void SentenceEditWindow_Impl::Undo()
2043 SfxUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
2044 DBG_ASSERT(GetUndoActionCount(), "no undo actions available" );
2045 if(!GetUndoActionCount())
2046 return;
2047 bool bSaveUndoEdit = IsUndoEditMode();
2048 USHORT nId;
2049 //if the undo edit mode is active then undo all changes until the UNDO_EDIT_MODE action has been found
2052 nId = rUndoMgr.GetUndoActionId();
2053 rUndoMgr.Undo();
2054 }while(bSaveUndoEdit && SPELLUNDO_UNDO_EDIT_MODE != nId && GetUndoActionCount());
2056 if(bSaveUndoEdit || SPELLUNDO_CHANGE_GROUP == nId)
2057 GetSpellDialog()->UpdateBoxes_Impl();
2059 /*-- 06.11.2003 11:30:10---------------------------------------------------
2061 -----------------------------------------------------------------------*/
2062 void SentenceEditWindow_Impl::ResetUndo()
2064 GetTextEngine()->ResetUndo();
2066 /*-- 06.11.2003 12:30:41---------------------------------------------------
2068 -----------------------------------------------------------------------*/
2069 void SentenceEditWindow_Impl::AddUndoAction( SfxUndoAction *pAction, BOOL bTryMerg )
2071 SfxUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
2072 rUndoMgr.AddUndoAction(pAction, bTryMerg);
2073 GetSpellDialog()->aUndoPB.Enable();
2075 /*-- 06.11.2003 12:38:44---------------------------------------------------
2077 -----------------------------------------------------------------------*/
2078 USHORT SentenceEditWindow_Impl::GetUndoActionCount()
2080 return GetTextEngine()->GetUndoManager().GetUndoActionCount();
2083 /*-- 12.11.2003 12:12:38---------------------------------------------------
2085 -----------------------------------------------------------------------*/
2086 void SentenceEditWindow_Impl::UndoActionStart( USHORT nId )
2088 GetTextEngine()->UndoActionStart(nId);
2090 /*-- 12.11.2003 12:12:38---------------------------------------------------
2092 -----------------------------------------------------------------------*/
2093 void SentenceEditWindow_Impl::UndoActionEnd( USHORT nId )
2095 GetTextEngine()->UndoActionEnd(nId);
2097 /*-- 12.11.2003 12:12:38---------------------------------------------------
2099 -----------------------------------------------------------------------*/
2100 void SentenceEditWindow_Impl::MoveErrorEnd(long nOffset)
2102 if(nOffset > 0)
2103 m_nErrorEnd = m_nErrorEnd - (USHORT)nOffset;
2104 else
2105 m_nErrorEnd = m_nErrorEnd -(USHORT)- nOffset;
2107 /*-- 13.11.2003 15:15:19---------------------------------------------------
2109 -----------------------------------------------------------------------*/
2110 void SentenceEditWindow_Impl::SetUndoEditMode(bool bSet)
2112 DBG_ASSERT(!bSet || m_bIsUndoEditMode != bSet, "SetUndoEditMode with equal values?");
2113 m_bIsUndoEditMode = bSet;
2114 //disable all buttons except the Change
2115 SpellDialog* pSpellDialog = GetSpellDialog();
2116 Control* aControls[] =
2118 &pSpellDialog->aChangeAllPB,
2119 &pSpellDialog->aExplainPB,
2120 &pSpellDialog->aIgnoreAllPB,
2121 &pSpellDialog->aIgnoreRulePB,
2122 &pSpellDialog->aIgnorePB,
2123 &pSpellDialog->aSuggestionLB,
2124 &pSpellDialog->aSuggestionFT,
2125 &pSpellDialog->aLanguageFT,
2126 &pSpellDialog->aLanguageLB,
2127 &pSpellDialog->aAddToDictMB,
2128 &pSpellDialog->aAutoCorrPB,
2131 sal_Int32 nIdx = 0;
2134 aControls[nIdx]->Enable(sal_False);
2136 while(aControls[++nIdx]);
2138 //remove error marks
2139 TextEngine* pTextEngine = GetTextEngine();
2140 pTextEngine->RemoveAttribs( 0, (USHORT)TEXTATTR_FONTCOLOR, TRUE );
2141 pTextEngine->RemoveAttribs( 0, (USHORT)TEXTATTR_FONTWEIGHT, TRUE );
2143 //put the appropriate action on the Undo-stack
2144 SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
2145 SPELLUNDO_UNDO_EDIT_MODE, GetSpellDialog()->aDialogUndoLink);
2146 AddUndoAction(pAction);
2147 pSpellDialog->aChangePB.Enable();
2150 /*-- 30.06.2008 14:15:19---------------------------------------------------
2152 -----------------------------------------------------------------------*/
2153 ExplainButton::~ExplainButton()
2156 /*-- 30.06.2008 14:15:19---------------------------------------------------
2158 -----------------------------------------------------------------------*/
2159 void ExplainButton::RequestHelp( const HelpEvent& )
2161 Help::ShowBalloon( this, GetPosPixel(), m_sExplanation );
2164 void ExplainButton::Click()
2166 RequestHelp( HelpEvent() );