1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/wrkwin.hxx>
21 #include <vcl/menu.hxx>
22 #include <vcl/layout.hxx>
23 #include <vcl/scrbar.hxx>
24 #include <vcl/settings.hxx>
25 #include <SpellAttrib.hxx>
26 #include <sfx2/dispatch.hxx>
27 #include <sfx2/bindings.hxx>
28 #include <svl/undo.hxx>
29 #include <unotools/lingucfg.hxx>
30 #include <vcl/textdata.hxx>
31 #include <vcl/graphicfilter.hxx>
32 #include <editeng/unolingu.hxx>
33 #include <editeng/splwrap.hxx>
34 #include <linguistic/lngprops.hxx>
35 #include <linguistic/misc.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/lang/XServiceInfo.hpp>
39 #include <com/sun/star/lang/XServiceDisplayName.hpp>
40 #include <com/sun/star/linguistic2/SpellFailure.hpp>
41 #include <com/sun/star/frame/XStorable.hpp>
42 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
43 #include <com/sun/star/system/SystemShellExecute.hpp>
44 #include <sfx2/app.hxx>
45 #include <vcl/help.hxx>
46 #include <vcl/graph.hxx>
47 #include <vcl/builderfactory.hxx>
48 #include <osl/file.hxx>
50 #include <editeng/optitems.hxx>
51 #include <editeng/svxenum.hxx>
52 #include <svx/SpellDialogChildWindow.hxx>
53 #include "SpellDialog.hxx"
54 #include <svx/dlgutil.hxx>
55 #include "optlingu.hxx"
56 #include <dialmgr.hxx>
57 #include <svx/svxerr.hxx>
58 #include "treeopt.hxx"
59 #include <svtools/langtab.hxx>
60 #include <comphelper/anytostring.hxx>
61 #include <cppuhelper/exc_hlp.hxx>
62 #include <boost/scoped_ptr.hpp>
64 using namespace ::com::sun::star
;
65 using namespace ::com::sun::star::uno
;
66 using namespace ::com::sun::star::beans
;
67 using namespace ::com::sun::star::linguistic2
;
68 using namespace linguistic
;
71 // struct SpellDialog_Impl ---------------------------------------------
73 struct SpellDialog_Impl
75 Sequence
< Reference
< XDictionary
> > aDics
;
79 #define SPELLUNDO_START 200
81 #define SPELLUNDO_CHANGE_LANGUAGE (SPELLUNDO_START + 1)
82 #define SPELLUNDO_CHANGE_TEXTENGINE (SPELLUNDO_START + 2)
83 #define SPELLUNDO_CHANGE_NEXTERROR (SPELLUNDO_START + 3)
84 #define SPELLUNDO_CHANGE_ADD_TO_DICTIONARY (SPELLUNDO_START + 4)
85 #define SPELLUNDO_CHANGE_GROUP (SPELLUNDO_START + 5) //undo list
86 #define SPELLUNDO_MOVE_ERROREND (SPELLUNDO_START + 6)
87 #define SPELLUNDO_UNDO_EDIT_MODE (SPELLUNDO_START + 7)
88 #define SPELLUNDO_ADD_IGNORE_RULE (SPELLUNDO_START + 8)
91 class SpellUndoAction_Impl
: public SfxUndoAction
94 const Link
<>& m_rActionLink
;
95 //undo of button enabling
96 bool m_bEnableChangePB
;
97 bool m_bEnableChangeAllPB
;
98 //undo of MarkNextError - used in change and change all, ignore and ignore all
99 long m_nNewErrorStart
;
101 long m_nOldErrorStart
;
103 bool m_bIsErrorLanguageSelected
;
104 //undo of AddToDictionary
105 Reference
<XDictionary
> m_xDictionary
;
106 OUString m_sAddedWord
;
107 //move end of error - ::ChangeMarkedWord()
111 SpellUndoAction_Impl(sal_uInt16 nId
, const Link
<>& rActionLink
) :
113 m_rActionLink( rActionLink
),
114 m_bEnableChangePB(false),
115 m_bEnableChangeAllPB(false),
116 m_nNewErrorStart(-1),
118 m_nOldErrorStart(-1),
120 m_bIsErrorLanguageSelected(false),
124 virtual ~SpellUndoAction_Impl();
126 virtual void Undo() SAL_OVERRIDE
;
127 virtual sal_uInt16
GetId() const SAL_OVERRIDE
;
129 void SetEnableChangePB(){m_bEnableChangePB
= true;}
130 bool IsEnableChangePB(){return m_bEnableChangePB
;}
132 void SetEnableChangeAllPB(){m_bEnableChangeAllPB
= true;}
133 bool IsEnableChangeAllPB(){return m_bEnableChangeAllPB
;}
135 void SetErrorMove(long nNewStart
, long nNewEnd
, long nOldStart
, long nOldEnd
)
137 m_nNewErrorStart
= nNewStart
;
138 m_nNewErrorEnd
= nNewEnd
;
139 m_nOldErrorStart
= nOldStart
;
140 m_nOldErrorEnd
= nOldEnd
;
142 long GetOldErrorStart() { return m_nOldErrorStart
;}
143 long GetOldErrorEnd() { return m_nOldErrorEnd
;}
145 void SetErrorLanguageSelected(bool bSet
){ m_bIsErrorLanguageSelected
= bSet
;}
146 bool IsErrorLanguageSelected() const {return m_bIsErrorLanguageSelected
;}
148 void SetDictionary(Reference
<XDictionary
> xDict
) { m_xDictionary
= xDict
; }
149 Reference
<XDictionary
> GetDictionary() const {return m_xDictionary
;}
150 void SetAddedWord(const OUString
& rWord
) {m_sAddedWord
= rWord
;}
151 const OUString
& GetAddedWord() const { return m_sAddedWord
;}
153 void SetOffset(long nSet
) {m_nOffset
= nSet
;}
154 long GetOffset() const {return m_nOffset
;}
157 using namespace ::svx
;
160 SpellUndoAction_Impl::~SpellUndoAction_Impl()
165 void SpellUndoAction_Impl::Undo()
167 m_rActionLink
.Call(this);
171 sal_uInt16
SpellUndoAction_Impl::GetId()const
176 // class SvxSpellCheckDialog ---------------------------------------------
178 SpellDialog::SpellDialog(SpellDialogChildWindow
* pChildWindow
,
179 vcl::Window
* pParent
, SfxBindings
* _pBindings
)
180 : SfxModelessDialog (_pBindings
, pChildWindow
,
181 pParent
, "SpellingDialog", "cui/ui/spellingdialog.ui")
182 , aDialogUndoLink(LINK (this, SpellDialog
, DialogUndoHdl
))
185 , rParent(*pChildWindow
)
187 m_sTitleSpellingGrammar
= GetText();
188 m_sTitleSpelling
= get
<FixedText
>("alttitleft")->GetText();
190 // fdo#68794 set initial title for cases where no text has been processed
191 // yet to show its language attributes
192 OUString sTitle
= rParent
.HasGrammarChecking() ? m_sTitleSpellingGrammar
: m_sTitleSpelling
;
193 SetText(sTitle
.replaceFirst("$LANGUAGE ($LOCATION)", ""));
195 m_sResumeST
= get
<FixedText
>("resumeft")->GetText();
196 m_sNoSuggestionsST
= get
<FixedText
>("nosuggestionsft")->GetText();
198 get(m_pLanguageFT
, "languageft");
199 get(m_pLanguageLB
, "languagelb");
200 get(m_pExplainFT
, "explain");
201 get(m_pExplainLink
, "explainlink");
202 get(m_pNotInDictFT
, "notindictft");
203 get(m_pSentenceED
, "sentence");
204 Size
aEdSize(LogicToPixel(Size(197, 48), MAP_APPFONT
));
205 m_pSentenceED
->set_width_request(aEdSize
.Width());
206 m_pSentenceED
->set_height_request(aEdSize
.Height());
207 get(m_pSuggestionFT
, "suggestionsft");
208 get(m_pSuggestionLB
, "suggestionslb");
209 m_pSuggestionLB
->SetDropDownLineCount(5);
210 m_pSuggestionLB
->set_width_request(aEdSize
.Width());
211 get(m_pIgnorePB
, "ignore");
212 m_sIgnoreOnceST
= m_pIgnorePB
->GetText();
213 get(m_pIgnoreAllPB
, "ignoreall");
214 get(m_pIgnoreRulePB
, "ignorerule");
215 get(m_pAddToDictPB
, "add");
216 get(m_pAddToDictMB
, "addmb");
217 m_pAddToDictMB
->SetHelpId(m_pAddToDictPB
->GetHelpId());
218 get(m_pChangePB
, "change");
219 get(m_pChangeAllPB
, "changeall");
220 get(m_pAutoCorrPB
, "autocorrect");
221 get(m_pCheckGrammarCB
, "checkgrammar");
222 get(m_pOptionsPB
, "options");
223 get(m_pUndoPB
, "undo");
224 get(m_pClosePB
, "close");
225 xSpell
= LinguMgr::GetSpellChecker();
226 pImpl
= new SpellDialog_Impl
;
228 const StyleSettings
& rSettings
= GetSettings().GetStyleSettings();
229 Color aCol
= rSettings
.GetHelpColor();
230 Wallpaper
aWall( aCol
);
231 m_pExplainLink
->SetBackground( aWall
);
232 m_pExplainFT
->SetBackground( aWall
);
236 // disable controls if service is missing
239 //InitHdl wants to use virtual methods, so it
240 //can't be called during the ctor, so init
241 //it on next event cycle post-ctor
242 Application::PostUserEvent(
243 LINK( this, SpellDialog
, InitHdl
), NULL
, true );
248 SpellDialog::~SpellDialog()
253 void SpellDialog::dispose()
257 // save possibly modified user-dictionaries
258 Reference
< XSearchableDictionaryList
> xDicList( SvxGetDictionaryList() );
260 SaveDictionaries( xDicList
);
265 m_pLanguageFT
.clear();
266 m_pLanguageLB
.clear();
267 m_pExplainFT
.clear();
268 m_pExplainLink
.clear();
269 m_pNotInDictFT
.clear();
270 m_pSentenceED
.clear();
271 m_pSuggestionFT
.clear();
272 m_pSuggestionLB
.clear();
274 m_pIgnoreAllPB
.clear();
275 m_pIgnoreRulePB
.clear();
276 m_pAddToDictPB
.clear();
277 m_pAddToDictMB
.clear();
279 m_pChangeAllPB
.clear();
280 m_pAutoCorrPB
.clear();
281 m_pCheckGrammarCB
.clear();
282 m_pOptionsPB
.clear();
285 SfxModelessDialog::dispose();
288 void SpellDialog::Init_Impl()
290 // initialize handler
291 m_pClosePB
->SetClickHdl(LINK( this, SpellDialog
, CancelHdl
) );
292 m_pChangePB
->SetClickHdl(LINK( this, SpellDialog
, ChangeHdl
) );
293 m_pChangeAllPB
->SetClickHdl(LINK( this, SpellDialog
, ChangeAllHdl
) );
294 m_pIgnorePB
->SetClickHdl(LINK( this, SpellDialog
, IgnoreHdl
) );
295 m_pIgnoreAllPB
->SetClickHdl(LINK( this, SpellDialog
, IgnoreAllHdl
) );
296 m_pIgnoreRulePB
->SetClickHdl(LINK( this, SpellDialog
, IgnoreAllHdl
) );
297 m_pUndoPB
->SetClickHdl(LINK( this, SpellDialog
, UndoHdl
) );
299 m_pAutoCorrPB
->SetClickHdl( LINK( this, SpellDialog
, ExtClickHdl
) );
300 m_pCheckGrammarCB
->SetClickHdl( LINK( this, SpellDialog
, CheckGrammarHdl
));
301 m_pOptionsPB
->SetClickHdl( LINK( this, SpellDialog
, ExtClickHdl
) );
303 m_pSuggestionLB
->SetDoubleClickHdl( LINK( this, SpellDialog
, ChangeHdl
) );
305 m_pSentenceED
->SetModifyHdl(LINK ( this, SpellDialog
, ModifyHdl
) );
307 m_pAddToDictMB
->SetSelectHdl(LINK ( this, SpellDialog
, AddToDictSelectHdl
) );
308 m_pAddToDictPB
->SetClickHdl(LINK ( this, SpellDialog
, AddToDictClickHdl
) );
310 m_pLanguageLB
->SetSelectHdl(LINK( this, SpellDialog
, LanguageSelectHdl
) );
312 m_pExplainLink
->SetClickHdl( LINK( this, SpellDialog
, HandleHyperlink
) );
314 // initialize language ListBox
315 m_pLanguageLB
->SetLanguageList( SvxLanguageListFlags::SPELL_USED
, false, false, true );
317 m_pSentenceED
->ClearModifyFlag();
318 SvxGetChangeAllList()->clear();
323 void SpellDialog::UpdateBoxes_Impl()
326 m_pSuggestionLB
->Clear();
328 const SpellErrorDescription
* pSpellErrorDescription
= m_pSentenceED
->GetAlternatives();
330 LanguageType nAltLanguage
= LANGUAGE_NONE
;
331 Sequence
< OUString
> aNewWords
;
332 bool bIsGrammarError
= false;
333 if( pSpellErrorDescription
)
335 nAltLanguage
= LanguageTag::convertToLanguageType( pSpellErrorDescription
->aLocale
);
336 aNewWords
= pSpellErrorDescription
->aSuggestions
;
337 bIsGrammarError
= pSpellErrorDescription
->bIsGrammarError
;
338 m_pExplainLink
->SetURL( pSpellErrorDescription
->sExplanationURL
);
339 m_pExplainFT
->SetText( pSpellErrorDescription
->sExplanation
);
341 if( pSpellErrorDescription
&& !pSpellErrorDescription
->sDialogTitle
.isEmpty() )
343 // use this function to apply the correct image to be used...
344 SetTitle_Impl( nAltLanguage
);
345 // then change the title to the one to be actually used
346 SetText( pSpellErrorDescription
->sDialogTitle
);
349 SetTitle_Impl( nAltLanguage
);
350 SetSelectedLang_Impl( nAltLanguage
);
351 int nDicts
= InitUserDicts();
353 // enter alternatives
354 const OUString
*pNewWords
= aNewWords
.getConstArray();
355 const sal_Int32 nSize
= aNewWords
.getLength();
356 for ( i
= 0; i
< nSize
; ++i
)
358 OUString
aTmp( pNewWords
[i
] );
359 if ( LISTBOX_ENTRY_NOTFOUND
== m_pSuggestionLB
->GetEntryPos( aTmp
) )
361 m_pSuggestionLB
->InsertEntry( aTmp
);
362 m_pSuggestionLB
->SetEntryFlags(m_pSuggestionLB
->GetEntryCount() - 1, ListBoxEntryFlags::MultiLine
);
366 m_pSuggestionLB
->InsertEntry(m_sNoSuggestionsST
);
367 m_pAutoCorrPB
->Enable( nSize
> 0 );
369 m_pSuggestionFT
->Enable(nSize
> 0);
370 m_pSuggestionLB
->Enable(nSize
> 0);
373 m_pSuggestionLB
->SelectEntryPos(0);
375 m_pChangePB
->Enable( nSize
> 0);
376 m_pChangeAllPB
->Enable(nSize
> 0);
377 bool bShowChangeAll
= !bIsGrammarError
;
378 m_pChangeAllPB
->Show( bShowChangeAll
);
379 m_pExplainFT
->Show( !bShowChangeAll
);
380 m_pLanguageLB
->Enable( bShowChangeAll
);
381 m_pIgnoreAllPB
->Show( bShowChangeAll
);
383 m_pAddToDictMB
->Show( bShowChangeAll
&& nDicts
> 1);
384 m_pAddToDictPB
->Show( bShowChangeAll
&& nDicts
<= 1);
385 m_pIgnoreRulePB
->Show( !bShowChangeAll
);
386 m_pIgnoreRulePB
->Enable(pSpellErrorDescription
&& !pSpellErrorDescription
->sRuleId
.isEmpty());
387 m_pAutoCorrPB
->Show( bShowChangeAll
&& rParent
.HasAutoCorrection() );
389 bool bOldShowGrammar
= m_pCheckGrammarCB
->IsVisible();
390 bool bOldShowExplain
= m_pExplainLink
->IsVisible();
392 m_pCheckGrammarCB
->Show(rParent
.HasGrammarChecking());
393 m_pExplainLink
->Show(!m_pExplainLink
->GetURL().isEmpty());
394 if (m_pExplainFT
->GetText().isEmpty())
396 m_pExplainFT
->Hide();
397 m_pExplainLink
->Hide();
400 if (bOldShowExplain
!= (bool) m_pExplainLink
->IsVisible() || bOldShowGrammar
!= (bool) m_pCheckGrammarCB
->IsVisible())
401 setOptimalLayoutSize();
405 void SpellDialog::SpellContinue_Impl(bool bUseSavedSentence
, bool bIgnoreCurrentError
)
407 //initially or after the last error of a sentence MarkNextError will fail
408 //then GetNextSentence() has to be called followed again by MarkNextError()
409 //MarkNextError is not initially called if the UndoEdit mode is active
410 bool bNextSentence
= false;
411 if((!m_pSentenceED
->IsUndoEditMode() && m_pSentenceED
->MarkNextError( bIgnoreCurrentError
, xSpell
)) ||
412 ( bNextSentence
= GetNextSentence_Impl(bUseSavedSentence
, m_pSentenceED
->IsUndoEditMode()) && m_pSentenceED
->MarkNextError( false, xSpell
)))
414 const SpellErrorDescription
* pSpellErrorDescription
= m_pSentenceED
->GetAlternatives();
415 if( pSpellErrorDescription
)
418 Control
* aControls
[] =
428 aControls
[nIdx
]->Enable(true);
430 while(aControls
[++nIdx
]);
435 //remove undo if a new sentence is active
436 m_pSentenceED
->ResetUndo();
437 m_pUndoPB
->Enable(false);
441 /* Initialize, asynchronous to prevent virtial calls
444 IMPL_LINK( SpellDialog
, InitHdl
, SpellDialog
*, )
446 SetUpdateMode( false );
447 //show or hide AutoCorrect depending on the modules abilities
448 m_pAutoCorrPB
->Show(rParent
.HasAutoCorrection());
449 SpellContinue_Impl();
450 m_pSentenceED
->ResetUndo();
451 m_pUndoPB
->Enable(false);
453 // get current language
456 // fill dictionary PopupMenu
459 LockFocusChanges(true);
460 if( m_pChangePB
->IsEnabled() )
461 m_pChangePB
->GrabFocus();
462 else if( m_pIgnorePB
->IsEnabled() )
463 m_pIgnorePB
->GrabFocus();
464 else if( m_pClosePB
->IsEnabled() )
465 m_pClosePB
->GrabFocus();
466 LockFocusChanges(false);
467 //show grammar CheckBox depending on the modules abilities
468 m_pCheckGrammarCB
->Check( rParent
.IsGrammarChecking() );
469 SetUpdateMode( true );
476 IMPL_LINK( SpellDialog
, ExtClickHdl
, Button
*, pBtn
)
478 if (m_pOptionsPB
== pBtn
)
479 StartSpellOptDlg_Impl();
480 else if (m_pAutoCorrPB
== pBtn
)
482 //get the currently selected wrong word
483 OUString sCurrentErrorText
= m_pSentenceED
->GetErrorText();
484 //get the wrong word from the XSpellAlternative
485 const SpellErrorDescription
* pSpellErrorDescription
= m_pSentenceED
->GetAlternatives();
486 if( pSpellErrorDescription
)
488 OUString
sWrong(pSpellErrorDescription
->sErrorText
);
489 //if the word has not been edited in the MultiLineEdit then
490 //the current suggestion should be used
491 //if it's not the 'no suggestions' entry
492 if(sWrong
== sCurrentErrorText
&&
493 m_pSuggestionLB
->IsEnabled() && m_pSuggestionLB
->GetSelectEntryCount() > 0 &&
494 !m_sNoSuggestionsST
.equals(m_pSuggestionLB
->GetSelectEntry()))
496 sCurrentErrorText
= m_pSuggestionLB
->GetSelectEntry();
498 if(sWrong
!= sCurrentErrorText
)
500 SvxPrepareAutoCorrect( sWrong
, sCurrentErrorText
);
501 LanguageType eLang
= GetSelectedLang_Impl();
502 rParent
.AddAutoCorrection( sWrong
, sCurrentErrorText
, eLang
);
509 IMPL_LINK( SpellDialog
, CheckGrammarHdl
, CheckBox
*, pBox
)
511 rParent
.SetGrammarChecking( pBox
->IsChecked() );
516 void SpellDialog::StartSpellOptDlg_Impl()
518 sal_uInt16 aSpellInfos
[] =
520 SID_ATTR_SPELL
,SID_ATTR_SPELL
,
521 SID_SPELL_MODIFIED
, SID_SPELL_MODIFIED
,
522 SID_AUTOSPELL_CHECK
, SID_AUTOSPELL_CHECK
,
525 SfxItemSet
aSet( SfxGetpApp()->GetPool(), aSpellInfos
);
526 aSet
.Put(SfxSpellCheckItem( xSpell
, SID_ATTR_SPELL
));
527 VclPtr
<SfxSingleTabDialog
> pDlg(
528 VclPtr
<SfxSingleTabDialog
>::Create(this, aSet
, "SpellOptionsDialog", "cui/ui/spelloptionsdialog.ui"));
529 VclPtr
<SfxTabPage
> pPage
= SvxLinguTabPage::Create( pDlg
->get_content_area(), &aSet
);
530 static_cast<SvxLinguTabPage
*>(pPage
.get())->HideGroups( GROUP_MODULES
);
531 pDlg
->SetTabPage( pPage
);
532 if(RET_OK
== pDlg
->Execute())
535 const SfxItemSet
* pOutSet
= pDlg
->GetOutputItemSet();
537 OfaTreeOptionsDialog::ApplyLanguageOptions(*pOutSet
);
543 OUString
getDotReplacementString(const OUString
&rErrorText
, const OUString
&rSuggestedReplacement
)
545 OUString aString
= rErrorText
;
547 //dots are sometimes part of the spelled word but they are not necessarily part of the replacement
548 bool bDot
= aString
.endsWith(".");
550 aString
= rSuggestedReplacement
;
552 if(bDot
&& (aString
.isEmpty() || !aString
.endsWith(".")))
560 OUString
SpellDialog::getReplacementString() const
562 OUString sOrigString
= m_pSentenceED
->GetErrorText();
564 OUString
sReplacement(sOrigString
);
566 if(m_pSuggestionLB
->IsEnabled() &&
567 m_pSuggestionLB
->GetSelectEntryCount()>0 &&
568 !m_sNoSuggestionsST
.equals(m_pSuggestionLB
->GetSelectEntry()))
569 sReplacement
= m_pSuggestionLB
->GetSelectEntry();
571 return getDotReplacementString(sOrigString
, sReplacement
);
576 IMPL_LINK_NOARG(SpellDialog
, ChangeHdl
)
578 if(m_pSentenceED
->IsUndoEditMode())
580 SpellContinue_Impl();
584 m_pSentenceED
->UndoActionStart( SPELLUNDO_CHANGE_GROUP
);
585 OUString aString
= getReplacementString();
586 m_pSentenceED
->ChangeMarkedWord(aString
, GetSelectedLang_Impl());
587 SpellContinue_Impl();
589 m_pSentenceED
->UndoActionEnd();
591 if(!m_pChangePB
->IsEnabled())
592 m_pIgnorePB
->GrabFocus();
598 IMPL_LINK_NOARG(SpellDialog
, ChangeAllHdl
)
600 m_pSentenceED
->UndoActionStart( SPELLUNDO_CHANGE_GROUP
);
601 OUString aString
= getReplacementString();
602 LanguageType eLang
= GetSelectedLang_Impl();
604 // add new word to ChangeAll list
605 OUString
aOldWord( m_pSentenceED
->GetErrorText() );
606 SvxPrepareAutoCorrect( aOldWord
, aString
);
607 Reference
<XDictionary
> aXDictionary( SvxGetChangeAllList(), UNO_QUERY
);
608 DictionaryError nAdded
= AddEntryToDic( aXDictionary
,
612 if(nAdded
== DictionaryError::NONE
)
614 SpellUndoAction_Impl
* pAction
= new SpellUndoAction_Impl(
615 SPELLUNDO_CHANGE_ADD_TO_DICTIONARY
, aDialogUndoLink
);
616 pAction
->SetDictionary(aXDictionary
);
617 pAction
->SetAddedWord(aOldWord
);
618 m_pSentenceED
->AddUndoAction(pAction
);
621 m_pSentenceED
->ChangeMarkedWord(aString
, eLang
);
622 SpellContinue_Impl();
624 m_pSentenceED
->UndoActionEnd();
629 IMPL_LINK( SpellDialog
, IgnoreAllHdl
, Button
*, pButton
)
631 m_pSentenceED
->UndoActionStart( SPELLUNDO_CHANGE_GROUP
);
632 // add word to IgnoreAll list
633 Reference
< XDictionary
> aXDictionary( SvxGetIgnoreAllList(), UNO_QUERY
);
634 //in case the error has been changed manually it has to be restored
635 m_pSentenceED
->RestoreCurrentError();
636 if (pButton
== m_pIgnoreRulePB
)
638 const SpellErrorDescription
* pSpellErrorDescription
= m_pSentenceED
->GetAlternatives();
641 if( pSpellErrorDescription
&& pSpellErrorDescription
->xGrammarChecker
.is() )
643 pSpellErrorDescription
->xGrammarChecker
->ignoreRule( pSpellErrorDescription
->sRuleId
,
644 pSpellErrorDescription
->aLocale
);
645 // refresh the layout (workaround to launch a dictionary event)
646 aXDictionary
->setActive(sal_False
);
647 aXDictionary
->setActive(sal_True
);
650 catch( const uno::Exception
& )
656 OUString
sErrorText(m_pSentenceED
->GetErrorText());
657 DictionaryError nAdded
= AddEntryToDic( aXDictionary
,
659 OUString(), LANGUAGE_NONE
);
660 if(nAdded
== DictionaryError::NONE
)
662 SpellUndoAction_Impl
* pAction
= new SpellUndoAction_Impl(
663 SPELLUNDO_CHANGE_ADD_TO_DICTIONARY
, aDialogUndoLink
);
664 pAction
->SetDictionary(aXDictionary
);
665 pAction
->SetAddedWord(sErrorText
);
666 m_pSentenceED
->AddUndoAction(pAction
);
670 SpellContinue_Impl();
672 m_pSentenceED
->UndoActionEnd();
677 IMPL_LINK_NOARG(SpellDialog
, UndoHdl
)
679 m_pSentenceED
->Undo();
680 if(!m_pSentenceED
->GetUndoActionCount())
681 m_pUndoPB
->Enable(false);
686 IMPL_LINK( SpellDialog
, DialogUndoHdl
, SpellUndoAction_Impl
*, pAction
)
688 switch(pAction
->GetId())
690 case SPELLUNDO_CHANGE_TEXTENGINE
:
692 if(pAction
->IsEnableChangePB())
693 m_pChangePB
->Enable(false);
694 if(pAction
->IsEnableChangeAllPB())
695 m_pChangeAllPB
->Enable(false);
698 case SPELLUNDO_CHANGE_NEXTERROR
:
700 m_pSentenceED
->MoveErrorMarkTo((sal_uInt16
)pAction
->GetOldErrorStart(), (sal_uInt16
)pAction
->GetOldErrorEnd(), false);
701 if(pAction
->IsErrorLanguageSelected())
707 case SPELLUNDO_CHANGE_ADD_TO_DICTIONARY
:
709 if(pAction
->GetDictionary().is())
710 pAction
->GetDictionary()->remove(pAction
->GetAddedWord());
713 case SPELLUNDO_MOVE_ERROREND
:
715 if(pAction
->GetOffset() != 0)
716 m_pSentenceED
->MoveErrorEnd(pAction
->GetOffset());
719 case SPELLUNDO_UNDO_EDIT_MODE
:
721 //refill the dialog with the currently spelled sentence - throw away all changes
722 SpellContinue_Impl(true);
725 case SPELLUNDO_ADD_IGNORE_RULE
:
726 //undo of ignored rules is not supported
733 void SpellDialog::Impl_Restore()
735 //clear the "ChangeAllList"
736 SvxGetChangeAllList()->clear();
738 m_pSentenceED
->SetText(OUString());
739 m_pSentenceED
->ResetModified();
740 //Resolves: fdo#39348 refill the dialog with the currently spelled sentence
741 SpellContinue_Impl(true);
742 m_pIgnorePB
->SetText(m_sIgnoreOnceST
);
745 IMPL_LINK_NOARG(SpellDialog
, IgnoreHdl
)
747 if (m_sResumeST
.equals(m_pIgnorePB
->GetText()))
753 //in case the error has been changed manually it has to be restored,
754 // since the users choice now was to ignore the error
755 m_pSentenceED
->RestoreCurrentError();
757 // the word is being ignored
758 SpellContinue_Impl( false, true );
765 bool SpellDialog::Close()
767 // We have to call ToggleChildWindow directly; calling SfxDispatcher's
768 // Execute() does not work here when we are in a document with protected
769 // section - in that case, the cursor can move from the editable field to
770 // the protected area, and the slots get disabled because of
771 // SW_DISABLE_ON_PROTECTED_CURSOR (see FN_SPELL_GRAMMAR_DIALOG in .sdi).
772 SfxViewFrame::Current()->ToggleChildWindow(rParent
.GetType());
778 void SpellDialog::SetSelectedLang_Impl( LanguageType nLang
)
780 m_pLanguageLB
->SelectLanguage( nLang
);
785 LanguageType
SpellDialog::GetSelectedLang_Impl() const
787 sal_Int16 nLang
= m_pLanguageLB
->GetSelectLanguage();
792 IMPL_LINK(SpellDialog
, LanguageSelectHdl
, SvxLanguageBox
*, pBox
)
794 //If selected language changes, then add->list should be regenerated to
798 //if currently an error is selected then search for alternatives for
799 //this word and fill the alternatives ListBox accordingly
800 OUString sError
= m_pSentenceED
->GetErrorText();
801 m_pSuggestionLB
->Clear();
802 if(!sError
.isEmpty())
804 LanguageType eLanguage
= pBox
->GetSelectLanguage();
805 Reference
<XSpellAlternatives
> xAlt
= xSpell
->spell( sError
, eLanguage
,
806 Sequence
< PropertyValue
>() );
808 m_pSentenceED
->SetAlternatives( xAlt
);
811 m_pSentenceED
->ChangeMarkedWord( sError
, eLanguage
);
812 SpellContinue_Impl();
815 m_pSentenceED
->AddUndoAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_LANGUAGE
, aDialogUndoLink
));
817 SpellDialog::UpdateBoxes_Impl();
822 void SpellDialog::SetLanguage( sal_uInt16 nLang
)
825 If the language has been changed in thesaurus,
826 it must be changed here, too.
829 SetTitle_Impl( nLang
);
830 m_pLanguageLB
->SelectLanguage( nLang
);
833 void SpellDialog::SetTitle_Impl(LanguageType nLang
)
835 OUString sTitle
= rParent
.HasGrammarChecking() ? m_sTitleSpellingGrammar
: m_sTitleSpelling
;
836 sTitle
= sTitle
.replaceFirst( "$LANGUAGE ($LOCATION)", SvtLanguageTable::GetLanguageString(nLang
) );
840 int SpellDialog::InitUserDicts()
842 const LanguageType nLang
= m_pLanguageLB
->GetSelectLanguage();
844 const Reference
< XDictionary
> *pDic
= 0;
846 // get list of dictionaries
847 Reference
< XSearchableDictionaryList
> xDicList( SvxGetDictionaryList() );
850 // add active, positive dictionary to dic-list (if not already done).
851 // This is to ensure that there is at least on dictionary to which
852 // words could be added.
853 Reference
< XDictionary
> xDic( SvxGetOrCreatePosDic( xDicList
) );
855 xDic
->setActive( sal_True
);
857 pImpl
->aDics
= xDicList
->getDictionaries();
862 // list suitable dictionaries
863 bool bEnable
= false;
864 const sal_Int32 nSize
= pImpl
->aDics
.getLength();
865 pDic
= pImpl
->aDics
.getConstArray();
866 PopupMenu
* pMenu
= m_pAddToDictMB
->GetPopupMenu();
869 pMenu
->SetMenuFlags(MenuFlags::NoAutoMnemonics
);
870 sal_uInt16 nItemId
= 1; // menu items should be enumerated from 1 and not 0
871 for (sal_Int32 i
= 0; i
< nSize
; ++i
)
873 uno::Reference
< linguistic2::XDictionary
> xDicTmp( pDic
[i
], uno::UNO_QUERY
);
874 if (!xDicTmp
.is() || SvxGetIgnoreAllList() == xDicTmp
)
877 uno::Reference
< frame::XStorable
> xStor( xDicTmp
, uno::UNO_QUERY
);
878 LanguageType nActLanguage
= LanguageTag( xDicTmp
->getLocale() ).getLanguageType();
879 if( xDicTmp
->isActive()
880 && xDicTmp
->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
881 && (nLang
== nActLanguage
|| LANGUAGE_NONE
== nActLanguage
)
882 && (!xStor
.is() || !xStor
->isReadonly()) )
884 pMenu
->InsertItem( nItemId
, xDicTmp
->getName() );
887 uno::Reference
< lang::XServiceInfo
> xSvcInfo( xDicTmp
, uno::UNO_QUERY
);
890 OUString
aDictionaryImageUrl( aCfg
.GetSpellAndGrammarContextDictionaryImage(
891 xSvcInfo
->getImplementationName()) );
892 if (!aDictionaryImageUrl
.isEmpty())
894 Image
aImage( aDictionaryImageUrl
);
895 pMenu
->SetItemImage( nItemId
, aImage
);
902 m_pAddToDictMB
->Enable( bEnable
);
903 m_pAddToDictPB
->Enable( bEnable
);
905 int nDicts
= nItemId
-1;
907 m_pAddToDictMB
->Show( nDicts
> 1 );
908 m_pAddToDictPB
->Show( nDicts
<= 1 );
914 IMPL_LINK(SpellDialog
, AddToDictClickHdl
, PushButton
*, )
916 return AddToDictionaryExecute(1, m_pAddToDictMB
->GetPopupMenu());
920 IMPL_LINK_TYPED(SpellDialog
, AddToDictSelectHdl
, MenuButton
*, pButton
, void )
922 AddToDictionaryExecute(pButton
->GetCurItemId(), pButton
->GetPopupMenu());
926 int SpellDialog::AddToDictionaryExecute( sal_uInt16 nItemId
, PopupMenu
*pMenu
)
928 m_pSentenceED
->UndoActionStart( SPELLUNDO_CHANGE_GROUP
);
930 //GetErrorText() returns the current error even if the text is already
932 const OUString aNewWord
= m_pSentenceED
->GetErrorText();
934 OUString
aDicName ( pMenu
->GetItemText( nItemId
) );
936 uno::Reference
< linguistic2::XDictionary
> xDic
;
937 uno::Reference
< linguistic2::XSearchableDictionaryList
> xDicList( SvxGetDictionaryList() );
939 xDic
= xDicList
->getDictionaryByName( aDicName
);
941 DictionaryError nAddRes
= DictionaryError::UNKNOWN
;
944 nAddRes
= AddEntryToDic( xDic
, aNewWord
, false, OUString(), LANGUAGE_NONE
);
945 // save modified user-dictionary if it is persistent
946 uno::Reference
< frame::XStorable
> xSavDic( xDic
, uno::UNO_QUERY
);
950 if (nAddRes
== DictionaryError::NONE
)
952 SpellUndoAction_Impl
* pAction
= new SpellUndoAction_Impl(
953 SPELLUNDO_CHANGE_ADD_TO_DICTIONARY
, aDialogUndoLink
);
954 pAction
->SetDictionary( xDic
);
955 pAction
->SetAddedWord( aNewWord
);
956 m_pSentenceED
->AddUndoAction( pAction
);
958 // failed because there is already an entry?
959 if (DictionaryError::NONE
!= nAddRes
&& xDic
->getEntry( aNewWord
).is())
960 nAddRes
= DictionaryError::NONE
;
962 if (DictionaryError::NONE
!= nAddRes
)
964 SvxDicError( this, nAddRes
);
965 return 0; // don't continue
969 SpellContinue_Impl();
970 m_pSentenceED
->UndoActionEnd();
975 IMPL_LINK(SpellDialog
, ModifyHdl
, SentenceEditWindow_Impl
*, pEd
)
977 if (m_pSentenceED
== pEd
)
980 m_pSuggestionLB
->SetNoSelection();
981 m_pSuggestionLB
->Disable();
982 OUString
sNewText( m_pSentenceED
->GetText() );
983 m_pAutoCorrPB
->Enable( sNewText
!= m_pSentenceED
->GetText() );
984 SpellUndoAction_Impl
* pSpellAction
= new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE
, aDialogUndoLink
);
985 if(!m_pChangeAllPB
->IsEnabled())
987 m_pChangeAllPB
->Enable();
988 pSpellAction
->SetEnableChangeAllPB();
990 if(!m_pChangePB
->IsEnabled())
992 m_pChangePB
->Enable();
993 pSpellAction
->SetEnableChangePB();
995 m_pSentenceED
->AddUndoAction(pSpellAction
);
1001 IMPL_LINK_NOARG(SpellDialog
, CancelHdl
)
1003 //apply changes and ignored text parts first - if there are any
1004 rParent
.ApplyChangedSentence(m_pSentenceED
->CreateSpellPortions(true), false);
1010 bool SpellDialog::Notify( NotifyEvent
& rNEvt
)
1013 * FIXME: LoseFocus and GetFocus are signals from vcl that
1014 * a window actually got/lost the focus, it never should be
1015 * forwarded from another window, that is simply wrong.
1016 * FIXME: overriding the virtual methods GetFocus and LoseFocus
1017 * in SpellDialogChildWindow by making them pure is at least questionable.
1018 * The only sensible thing would be to call the new Method differently,
1019 * e.g. DialogGot/LostFocus or so.
1021 if( IsVisible() && !bFocusLocked
)
1023 if( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
1025 //notify the child window of the focus change
1028 else if( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
1030 //notify the child window of the focus change
1031 rParent
.LoseFocus();
1034 return SfxModelessDialog::Notify(rNEvt
);
1038 void SpellDialog::InvalidateDialog()
1042 m_pIgnorePB
->SetText(m_sResumeST
);
1043 vcl::Window
* aDisableArr
[] =
1062 while(aDisableArr
[i
])
1064 aDisableArr
[i
]->Enable(false);
1067 SfxModelessDialog::Deactivate();
1071 bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence
, bool bRecheck
)
1074 if(!bUseSavedSentence
)
1076 //apply changes and ignored text parts
1077 rParent
.ApplyChangedSentence(m_pSentenceED
->CreateSpellPortions(true), bRecheck
);
1079 m_pSentenceED
->ResetIgnoreErrorsAt();
1080 m_pSentenceED
->ResetModified();
1081 SpellPortions aSentence
= bUseSavedSentence
? m_aSavedSentence
: rParent
.GetNextWrongSentence( bRecheck
);
1082 if(!bUseSavedSentence
)
1083 m_aSavedSentence
= aSentence
;
1084 bool bHasReplaced
= false;
1085 while(!aSentence
.empty())
1087 //apply all changes that are already part of the "ChangeAllList"
1088 //returns true if the list still contains errors after the changes have been applied
1090 if(!ApplyChangeAllList_Impl(aSentence
, bHasReplaced
))
1092 rParent
.ApplyChangedSentence(aSentence
, bRecheck
);
1093 aSentence
= rParent
.GetNextWrongSentence( bRecheck
);
1099 if(!aSentence
.empty())
1101 SpellPortions::iterator aStart
= aSentence
.begin();
1103 while(aStart
!= aSentence
.end())
1105 // hidden text has to be ignored
1106 if(!aStart
->bIsHidden
)
1107 sText
+= aStart
->sText
;
1110 m_pSentenceED
->SetText(sText
);
1111 aStart
= aSentence
.begin();
1112 sal_Int32 nStartPosition
= 0;
1113 sal_Int32 nEndPosition
= 0;
1115 while(aStart
!= aSentence
.end())
1117 // hidden text has to be ignored
1118 if(!aStart
->bIsHidden
)
1120 nEndPosition
+= aStart
->sText
.getLength();
1121 if(aStart
->xAlternatives
.is())
1123 uno::Reference
< container::XNamed
> xNamed( aStart
->xAlternatives
, uno::UNO_QUERY
);
1124 OUString sServiceName
;
1126 sServiceName
= xNamed
->getName();
1127 SpellErrorDescription
aDesc( false, aStart
->xAlternatives
->getWord(),
1128 aStart
->xAlternatives
->getLocale(), aStart
->xAlternatives
->getAlternatives(), 0, sServiceName
);
1129 m_pSentenceED
->SetAttrib( SpellErrorAttrib(aDesc
), 0, (sal_uInt16
) nStartPosition
, (sal_uInt16
) nEndPosition
);
1131 else if(aStart
->bIsGrammarError
)
1133 beans::PropertyValues aProperties
= aStart
->aGrammarError
.aProperties
;
1134 OUString sFullCommentURL
;
1136 while ( sFullCommentURL
.isEmpty() && i
< aProperties
.getLength() )
1138 if ( aProperties
[i
].Name
== "FullCommentURL" )
1140 uno::Any aValue
= aProperties
[i
].Value
;
1141 aValue
>>= sFullCommentURL
;
1146 uno::Reference
< lang::XServiceInfo
> xInfo( aStart
->xGrammarChecker
, uno::UNO_QUERY
);
1147 SpellErrorDescription
aDesc( true,
1149 LanguageTag::convertToLocale( aStart
->eLanguage
),
1150 aStart
->aGrammarError
.aSuggestions
,
1151 aStart
->xGrammarChecker
,
1152 xInfo
->getImplementationName(),
1153 &aStart
->sDialogTitle
,
1154 &aStart
->aGrammarError
.aFullComment
,
1155 &aStart
->aGrammarError
.aRuleIdentifier
,
1157 m_pSentenceED
->SetAttrib( SpellErrorAttrib(aDesc
), 0, (sal_uInt16
) nStartPosition
, (sal_uInt16
) nEndPosition
);
1159 if(aStart
->bIsField
)
1160 m_pSentenceED
->SetAttrib( SpellBackgroundAttrib(COL_LIGHTGRAY
), 0, (sal_uInt16
) nStartPosition
, (sal_uInt16
) nEndPosition
);
1161 m_pSentenceED
->SetAttrib( SpellLanguageAttrib(aStart
->eLanguage
), 0, (sal_uInt16
) nStartPosition
, (sal_uInt16
) nEndPosition
);
1162 nStartPosition
= nEndPosition
;
1166 //the edit field needs to be modified to apply the change from the ApplyChangeAllList
1168 m_pSentenceED
->ClearModifyFlag();
1169 m_pSentenceED
->ResetUndo();
1170 m_pUndoPB
->Enable(false);
1171 bRet
= nStartPosition
> 0;
1175 /*-------------------------------------------------------------------------
1176 replace errors that have a replacement in the ChangeAllList
1177 returns false if the result doesn't contain errors after the replacement
1178 -----------------------------------------------------------------------*/
1179 bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions
& rSentence
, bool &bHasReplaced
)
1181 bHasReplaced
= false;
1183 SpellPortions::iterator aStart
= rSentence
.begin();
1184 Reference
<XDictionary
> xChangeAll( SvxGetChangeAllList(), UNO_QUERY
);
1185 if(!xChangeAll
->getCount())
1188 while(aStart
!= rSentence
.end())
1190 if(aStart
->xAlternatives
.is())
1192 const OUString
&rString
= aStart
->sText
;
1194 Reference
<XDictionaryEntry
> xEntry
= xChangeAll
->getEntry(rString
);
1198 aStart
->sText
= getDotReplacementString(rString
, xEntry
->getReplacementText());
1199 aStart
->xAlternatives
= 0;
1200 bHasReplaced
= true;
1205 else if( aStart
->bIsGrammarError
)
1213 SentenceEditWindow_Impl::SentenceEditWindow_Impl(vcl::Window
* pParent
, WinBits nBits
)
1214 : VclMultiLineEdit(pParent
, nBits
)
1217 , m_bIsUndoEditMode(false)
1219 DisableSelectionOnFocus();
1222 VCL_BUILDER_DECL_FACTORY(SentenceEditWindow
)
1225 rRet
= VclPtr
<SentenceEditWindow_Impl
>::Create(pParent
, WB_BORDER
|WB_VSCROLL
|WB_IGNORETAB
);
1229 /*-------------------------------------------------------------------------
1230 The selection before inputting a key may have a range or not
1231 and it may be inside or outside of field or error attributes.
1232 A range may include the attribute partially, completely or together
1233 with surrounding text. It may also contain more than one attribute
1234 or no attribute at all.
1235 Depending on this starting conditions some actions are necessary:
1236 Attempts to delete a field are only allowed if the selection is the same
1237 as the field's selection. Otherwise the field has to be selected and the key
1238 input action has to be skipped.
1239 Input of text at the start of the field requires the field attribute to be
1240 corrected - it is not allowed to grow.
1242 In case of errors the appending of text should grow the error attribute because
1243 that is what the user usually wants to do.
1245 Backspace at the start of the attribute requires to find out if a field ends
1246 directly in front of the cursor position. In case of a field this attribute has to be
1247 selected otherwise the key input method is allowed.
1249 All changes outside of the error attributes switch the dialog mode to a "Undo edit" state that
1250 removes all visible attributes and switches off further attribute checks.
1251 Undo in this restarts the dialog with a current sentence newly presented.
1252 All changes to the sentence are undone including the ones before the "Undo edit state" has been reached
1254 We end up with 9 types of selection
1255 1 (LEFT_NO) - no range, start of attribute - can also be 3 at the same time
1256 2 (INSIDE_NO) - no range, inside of attribute
1257 3 (RIGHT_NO) - no range, end of attribute - can also be 1 at the same time
1258 4 (FULL) - range, same as attribute
1259 5 (INSIDE_YES) - range, inside of the attribute
1260 6 (BRACE)- range, from outside of the attribute to the inside or
1261 including the complete attribute and something outside,
1262 maybe more than one attribute
1263 7 (OUTSIDE_NO) - no range, not at an attribute
1264 8 (OUTSIDE_YES) - range, completely outside of all attributes
1266 What has to be done depending on the attribute type involved
1267 possible actions: UE - Undo edit mode
1268 CO - Continue, no additional action is required
1269 FS - Field has to be completely selected
1270 EX - The attribute has to be expanded to include the added text
1272 1 - backspace delete any other
1273 UE on field FS on error CO on field FS on error CO
1275 2 - on field FS on error C
1276 3 - backspace delete any other
1277 on field FS on error CO UE on field UE on error EX
1279 if 1 and 3 happen to apply both then backspace and other handling is 1 delete is 3
1281 4 - on field UE and on error CO
1282 5 - on field FS and on error CO
1283 6 - on field FS and on error UE
1286 -----------------------------------------------------------------------*/
1292 #define INSIDE_YES 5
1294 #define OUTSIDE_NO 7
1295 #define OUTSIDE_YES 8
1297 #define ACTION_UNDOEDIT 0
1298 #define ACTION_CONTINUE 1
1299 #define ACTION_SELECTFIELD 2
1300 #define ACTION_EXPAND 3
1302 bool SentenceEditWindow_Impl::PreNotify( NotifyEvent
& rNEvt
)
1304 bool bChange
= false;
1305 if(rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
)
1307 const KeyEvent
& rKeyEvt
= *rNEvt
.GetKeyEvent();
1308 bChange
= TextEngine::DoesKeyChangeText( rKeyEvt
);
1309 if(bChange
&& !IsUndoEditMode() &&
1310 rKeyEvt
.GetKeyCode().GetCode() != KEY_TAB
)
1312 TextEngine
* pTextEngine
= GetTextEngine();
1313 TextView
* pTextView
= pTextEngine
->GetActiveView();
1314 const TextSelection
& rCurrentSelection
= pTextView
->GetSelection();
1315 //determine if the selection contains a field
1316 bool bHasField
= false;
1317 bool bHasError
= false;
1318 bool bHasFieldLeft
= false;
1319 bool bHasErrorLeft
= false;
1321 bool bHasRange
= rCurrentSelection
.HasRange();
1322 sal_uInt8 nSelectionType
= 0; // invalid type!
1324 TextPaM
aCursor(rCurrentSelection
.GetStart());
1325 const TextCharAttrib
* pBackAttr
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_SPELL_BACKGROUND
);
1326 const TextCharAttrib
* pErrorAttr
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_SPELL_ERROR
);
1327 const TextCharAttrib
* pBackAttrLeft
= 0;
1328 const TextCharAttrib
* pErrorAttrLeft
= 0;
1330 bHasField
= pBackAttr
!= 0 && (bHasRange
|| pBackAttr
->GetEnd() > aCursor
.GetIndex());
1331 bHasError
= pErrorAttr
!= 0 && (bHasRange
|| pErrorAttr
->GetEnd() > aCursor
.GetIndex());
1335 pBackAttr
->GetStart() == rCurrentSelection
.GetStart().GetIndex() &&
1336 pBackAttr
->GetEnd() == rCurrentSelection
.GetEnd().GetIndex())
1338 nSelectionType
= FULL
;
1340 else if(pErrorAttr
&&
1341 pErrorAttr
->GetStart() <= rCurrentSelection
.GetStart().GetIndex() &&
1342 pErrorAttr
->GetEnd() >= rCurrentSelection
.GetEnd().GetIndex())
1344 nSelectionType
= INSIDE_YES
;
1348 nSelectionType
= bHasField
||bHasError
? BRACE
: OUTSIDE_NO
;
1349 while(aCursor
.GetIndex() < rCurrentSelection
.GetEnd().GetIndex())
1351 ++aCursor
.GetIndex();
1352 const TextCharAttrib
* pIntBackAttr
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_SPELL_BACKGROUND
);
1353 const TextCharAttrib
* pIntErrorAttr
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_SPELL_ERROR
);
1354 //if any attr has been found then BRACE
1355 if(pIntBackAttr
|| pIntErrorAttr
)
1356 nSelectionType
= BRACE
;
1357 //the field has to be selected
1358 if(pIntBackAttr
&& !pBackAttr
)
1359 pBackAttr
= pIntBackAttr
;
1360 bHasField
|= pIntBackAttr
!= 0;
1366 //no range selection: then 1 2 3 and 8 are possible
1367 const TextCharAttrib
* pCurAttr
= pBackAttr
? pBackAttr
: pErrorAttr
;
1370 nSelectionType
= pCurAttr
->GetStart() == rCurrentSelection
.GetStart().GetIndex() ?
1371 LEFT_NO
: pCurAttr
->GetEnd() == rCurrentSelection
.GetEnd().GetIndex() ? RIGHT_NO
: INSIDE_NO
;
1374 nSelectionType
= OUTSIDE_NO
;
1376 bHasFieldLeft
= pBackAttr
&& pBackAttr
->GetEnd() == aCursor
.GetIndex();
1379 pBackAttrLeft
= pBackAttr
;
1382 bHasErrorLeft
= pErrorAttr
&& pErrorAttr
->GetEnd() == aCursor
.GetIndex();
1385 pErrorAttrLeft
= pErrorAttr
;
1389 //check previous position if this exists
1390 //that is a redundant in the case the attribute found above already is on the left cursor side
1391 //but it's o.k. for two errors/fields side by side
1392 if(aCursor
.GetIndex())
1394 --aCursor
.GetIndex();
1395 pBackAttrLeft
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_SPELL_BACKGROUND
);
1396 pErrorAttrLeft
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_SPELL_ERROR
);
1397 bHasFieldLeft
= pBackAttrLeft
!=0;
1398 bHasErrorLeft
= pErrorAttrLeft
!= 0;
1399 ++aCursor
.GetIndex();
1402 //Here we have to determine if the error found is the one currently active
1403 bool bIsErrorActive
= (pErrorAttr
&& pErrorAttr
->GetStart() == m_nErrorStart
) ||
1404 (pErrorAttrLeft
&& pErrorAttrLeft
->GetStart() == m_nErrorStart
);
1407 nSelectionType
== INVALID
, "cui.dialogs",
1408 "selection type not set");
1410 const vcl::KeyCode
& rKeyCode
= rKeyEvt
.GetKeyCode();
1411 bool bDelete
= rKeyCode
.GetCode() == KEY_DELETE
;
1412 bool bBackspace
= rKeyCode
.GetCode() == KEY_BACKSPACE
;
1414 sal_Int8 nAction
= ACTION_CONTINUE
;
1415 switch(nSelectionType
)
1417 // 1 - backspace delete any other
1418 // UE on field FS on error CO on field FS on error CO
1422 nAction
= bHasFieldLeft
? ACTION_SELECTFIELD
: ACTION_UNDOEDIT
;
1423 //to force the use of pBackAttrLeft
1427 nAction
= bHasField
? ACTION_SELECTFIELD
: ACTION_CONTINUE
;
1429 nAction
= bHasError
&& !aCursor
.GetIndex() ? ACTION_CONTINUE
:
1430 bHasError
? ACTION_EXPAND
: bHasErrorLeft
? ACTION_CONTINUE
: ACTION_UNDOEDIT
;
1432 // 2 - on field FS on error C
1434 nAction
= bHasField
? ACTION_SELECTFIELD
:
1435 bIsErrorActive
? ACTION_CONTINUE
: ACTION_UNDOEDIT
;
1437 // 3 - backspace delete any other
1438 // on field FS on error CO UE on field UE on error EX
1441 nAction
= bHasFieldLeft
? ACTION_SELECTFIELD
: ACTION_CONTINUE
;
1443 nAction
= bHasFieldLeft
&& bHasError
? ACTION_CONTINUE
: ACTION_UNDOEDIT
;
1445 nAction
= bHasFieldLeft
&& bHasError
? ACTION_EXPAND
:
1446 bHasError
? ACTION_CONTINUE
: bHasErrorLeft
? ACTION_EXPAND
:ACTION_UNDOEDIT
;
1448 // 4 - on field UE and on error CO
1450 nAction
= ACTION_UNDOEDIT
;
1452 // 5 - on field FS and on error CO
1454 nAction
= bHasField
? ACTION_SELECTFIELD
: ACTION_CONTINUE
;
1456 // 6 - on field FS and on error UE
1458 nAction
= bHasField
? ACTION_SELECTFIELD
: ACTION_UNDOEDIT
;;
1464 nAction
= ACTION_UNDOEDIT
;
1467 //save the current paragraph
1468 sal_Int32 nCurrentLen
= GetText().getLength();
1469 if(nAction
!= ACTION_SELECTFIELD
)
1470 pTextView
->GetWindow()->KeyInput(rKeyEvt
);
1473 const TextCharAttrib
* pCharAttr
= pBackAttr
? pBackAttr
: pBackAttrLeft
;
1476 TextPaM
aStart(0, pCharAttr
->GetStart());
1477 TextPaM
aEnd(0, pCharAttr
->GetEnd());
1478 TextSelection
aNewSel(aStart
, aEnd
);
1479 pTextView
->SetSelection( aNewSel
);
1482 if(nAction
== ACTION_EXPAND
)
1484 DBG_ASSERT(pErrorAttrLeft
|| pErrorAttr
, "where is the error");
1485 //text has been added on the right and only the 'error attribute has to be corrected
1488 boost::scoped_ptr
<TextAttrib
> pNewError(pErrorAttrLeft
->GetAttr().Clone());
1489 sal_uInt16 nStart
= pErrorAttrLeft
->GetStart();
1490 sal_uInt16 nEnd
= pErrorAttrLeft
->GetEnd();
1491 pTextEngine
->RemoveAttrib( 0, *pErrorAttrLeft
);
1492 SetAttrib( *pNewError
, 0, nStart
, ++nEnd
);
1493 //only active errors move the mark
1496 bool bGrammar
= static_cast<const SpellErrorAttrib
&>(*pNewError
).GetErrorDescription().bIsGrammarError
;
1497 MoveErrorMarkTo(nStart
, nEnd
, bGrammar
);
1500 //text has been added on the left then the error attribute has to be expanded and the
1501 //field attribute on the right - if any - has to be contracted
1504 //determine the change
1505 sal_Int32 nAddedChars
= GetText().getLength() - nCurrentLen
;
1507 boost::scoped_ptr
<TextAttrib
> pNewError(pErrorAttr
->GetAttr().Clone());
1508 sal_Int32 nStart
= pErrorAttr
->GetStart();
1509 sal_Int32 nEnd
= pErrorAttr
->GetEnd();
1510 pTextEngine
->RemoveAttrib( 0, *pErrorAttr
);
1511 nStart
= nStart
- nAddedChars
;
1512 SetAttrib( *pNewError
, 0, nStart
- nAddedChars
, nEnd
);
1513 //only if the error is active the mark is moved here
1516 bool bGrammar
= static_cast<const SpellErrorAttrib
&>(*pNewError
).GetErrorDescription().bIsGrammarError
;
1517 MoveErrorMarkTo(nStart
, nEnd
, bGrammar
);
1523 boost::scoped_ptr
<TextAttrib
> pNewBack(pBackAttrLeft
->GetAttr().Clone());
1524 sal_uInt16 _nStart
= pBackAttrLeft
->GetStart();
1525 sal_uInt16 _nEnd
= pBackAttrLeft
->GetEnd();
1526 pTextEngine
->RemoveAttrib( 0, *pBackAttrLeft
);
1527 SetAttrib( *pNewBack
, 0, _nStart
, _nEnd
- nAddedChars
);
1531 else if(nAction
== ACTION_UNDOEDIT
)
1533 SetUndoEditMode(true);
1535 //make sure the error positions are correct after text changes
1536 //the old attribute may have been deleted
1537 //all changes inside of the current error leave the error attribute at the current
1539 if(!IsUndoEditMode() && bIsErrorActive
)
1541 const TextCharAttrib
* pFontColor
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_FONTCOLOR
);
1542 const TextCharAttrib
* pErrorAttrib
= pTextEngine
->FindCharAttrib( TextPaM(0, m_nErrorStart
), TEXTATTR_SPELL_ERROR
);
1543 if(pFontColor
&& pErrorAttrib
)
1545 m_nErrorStart
= pFontColor
->GetStart();
1546 m_nErrorEnd
= pFontColor
->GetEnd();
1547 if(pErrorAttrib
->GetStart() != m_nErrorStart
|| pErrorAttrib
->GetEnd() != m_nErrorEnd
)
1549 boost::scoped_ptr
<TextAttrib
> pNewError(pErrorAttrib
->GetAttr().Clone());
1550 pTextEngine
->RemoveAttrib( 0, *pErrorAttr
);
1551 SetAttrib( *pNewError
, 0, m_nErrorStart
, m_nErrorEnd
);
1555 //this is not a modification anymore
1556 if(nAction
!= ACTION_SELECTFIELD
&& !m_bIsUndoEditMode
)
1562 return bChange
|| VclMultiLineEdit::PreNotify(rNEvt
);
1566 bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError
, com::sun::star::uno::Reference
<com::sun::star::linguistic2::XSpellChecker1
> xSpell
)
1568 if (bIgnoreCurrentError
)
1569 m_aIgnoreErrorsAt
.insert( m_nErrorStart
);
1570 ExtTextEngine
* pTextEngine
= GetTextEngine();
1571 sal_uInt16 nTextLen
= pTextEngine
->GetTextLen(0);
1572 if(m_nErrorEnd
>= nTextLen
- 1)
1574 //if it's not already modified the modified flag has to be reset at the end of the marking
1575 bool bModified
= IsModified();
1577 const sal_uInt16 nOldErrorStart
= m_nErrorStart
;
1578 const sal_uInt16 nOldErrorEnd
= m_nErrorEnd
;
1580 //create a cursor behind the end of the last error
1581 //- or at 0 at the start of the sentence
1582 TextPaM
aCursor(0, m_nErrorEnd
? m_nErrorEnd
+ 1 : 0);
1583 //search for SpellErrorAttrib
1585 const TextCharAttrib
* pNextError
= 0;
1586 //iterate over the text and search for the next error that maybe has
1587 //to be replace by a ChangeAllList replacement
1588 bool bGrammarError
= false;
1589 while(aCursor
.GetIndex() < nTextLen
)
1591 while(aCursor
.GetIndex() < nTextLen
&&
1592 0 == (pNextError
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_SPELL_ERROR
)))
1594 ++aCursor
.GetIndex();
1596 // maybe the error found here is already in the ChangeAllList and has to be replaced
1598 Reference
<XDictionary
> xChangeAll( SvxGetChangeAllList(), UNO_QUERY
);
1599 Reference
<XDictionaryEntry
> xEntry
;
1601 const SpellErrorDescription
* pSpellErrorDescription
= 0;
1604 pSpellErrorDescription
= &static_cast<const SpellErrorAttrib
&>(pNextError
->GetAttr()).GetErrorDescription();
1605 bGrammarError
= pSpellErrorDescription
->bIsGrammarError
;
1606 m_nErrorStart
= pNextError
->GetStart();
1607 m_nErrorEnd
= pNextError
->GetEnd();
1609 if(xChangeAll
->getCount() && pSpellErrorDescription
&&
1610 (xEntry
= xChangeAll
->getEntry( pSpellErrorDescription
->sErrorText
)).is())
1613 OUString
sReplacement(getDotReplacementString(GetErrorText(), xEntry
->getReplacementText()));
1615 ChangeMarkedWord(sReplacement
, LanguageTag::convertToLanguageType( pSpellErrorDescription
->aLocale
));
1617 aCursor
.GetIndex() = aCursor
.GetIndex() + (sal_uInt16
)(xEntry
->getReplacementText().getLength());
1618 // maybe the error found here is already added to the dictionary and has to be ignored
1619 } else if(pSpellErrorDescription
&& !bGrammarError
&& xSpell
->isValid( GetErrorText(), LanguageTag::convertToLanguageType( pSpellErrorDescription
->aLocale
), Sequence
< PropertyValue
>() )) {
1620 aCursor
.GetIndex() = aCursor
.GetIndex() + 1;
1626 //if an attrib has been found search for the end of the error string
1627 if(aCursor
.GetIndex() < nTextLen
)
1629 m_nErrorStart
= aCursor
.GetIndex();
1630 m_nErrorEnd
= pNextError
->GetEnd();
1631 MoveErrorMarkTo(m_nErrorStart
, m_nErrorEnd
, bGrammarError
);
1633 //add an undo action
1634 SpellUndoAction_Impl
* pAction
= new SpellUndoAction_Impl(
1635 SPELLUNDO_CHANGE_NEXTERROR
, GetSpellDialog()->aDialogUndoLink
);
1636 pAction
->SetErrorMove(m_nErrorStart
, m_nErrorEnd
, nOldErrorStart
, nOldErrorEnd
);
1637 const SpellErrorAttrib
* pOldAttrib
= static_cast<const SpellErrorAttrib
*>(
1638 pTextEngine
->FindAttrib( TextPaM(0, nOldErrorStart
), TEXTATTR_SPELL_ERROR
));
1639 pAction
->SetErrorLanguageSelected(pOldAttrib
&& pOldAttrib
->GetErrorDescription().aSuggestions
.getLength() &&
1640 LanguageTag( pOldAttrib
->GetErrorDescription().aLocale
).getLanguageType() ==
1641 GetSpellDialog()->m_pLanguageLB
->GetSelectLanguage());
1642 AddUndoAction(pAction
);
1645 m_nErrorStart
= m_nErrorEnd
= nTextLen
;
1648 SpellDialog
* pSpellDialog
= GetSpellDialog();
1649 pSpellDialog
->m_pIgnorePB
->Enable(bRet
);
1650 pSpellDialog
->m_pIgnoreAllPB
->Enable(bRet
);
1651 pSpellDialog
->m_pAutoCorrPB
->Enable(bRet
);
1652 pSpellDialog
->m_pAddToDictMB
->Enable(bRet
);
1653 pSpellDialog
->m_pAddToDictPB
->Enable(bRet
);
1658 void SentenceEditWindow_Impl::MoveErrorMarkTo(sal_uInt16 nStart
, sal_uInt16 nEnd
, bool bGrammarError
)
1660 TextEngine
* pTextEngine
= GetTextEngine();
1661 pTextEngine
->RemoveAttribs( 0, (sal_uInt16
)TEXTATTR_FONTCOLOR
, true );
1662 pTextEngine
->RemoveAttribs( 0, (sal_uInt16
)TEXTATTR_FONTWEIGHT
, true );
1663 pTextEngine
->SetAttrib( TextAttribFontWeight(WEIGHT_BOLD
), 0, nStart
, nEnd
);
1664 pTextEngine
->SetAttrib( TextAttribFontColor(bGrammarError
? COL_LIGHTBLUE
: COL_LIGHTRED
), 0, nStart
, nEnd
);
1665 m_nErrorStart
= nStart
;
1670 void SentenceEditWindow_Impl::ChangeMarkedWord(const OUString
& rNewWord
, LanguageType eLanguage
)
1672 //calculate length changes
1673 long nDiffLen
= rNewWord
.getLength() - m_nErrorEnd
+ m_nErrorStart
;
1674 TextSelection
aSel(TextPaM(0, m_nErrorStart
), TextPaM(0, m_nErrorEnd
));
1675 //Remove spell error attribute
1676 ExtTextEngine
* pTextEngine
= GetTextEngine();
1677 pTextEngine
->UndoActionStart();
1678 const TextCharAttrib
* pErrorAttrib
= pTextEngine
->FindCharAttrib( TextPaM(0, m_nErrorStart
), TEXTATTR_SPELL_ERROR
);
1679 DBG_ASSERT(pErrorAttrib
, "no error attribute found");
1680 const SpellErrorDescription
* pSpellErrorDescription
= 0;
1683 pTextEngine
->RemoveAttrib(0, *pErrorAttrib
);
1684 pSpellErrorDescription
= &static_cast<const SpellErrorAttrib
&>(pErrorAttrib
->GetAttr()).GetErrorDescription();
1686 const TextCharAttrib
* pBackAttrib
= pTextEngine
->FindCharAttrib( TextPaM(0, m_nErrorStart
), TEXTATTR_SPELL_BACKGROUND
);
1687 pTextEngine
->ReplaceText( aSel
, rNewWord
);
1691 //attributes following an error at the start of the text are not moved but expanded from the
1692 //text engine - this is done to keep full-paragraph-attributes
1693 //in the current case that handling is not desired
1694 const TextCharAttrib
* pLangAttrib
=
1695 pTextEngine
->FindCharAttrib(
1696 TextPaM(0, m_nErrorEnd
), TEXTATTR_SPELL_LANGUAGE
);
1697 sal_uInt16 nTextLen
= pTextEngine
->GetTextLen( 0 );
1698 if(pLangAttrib
&& !pLangAttrib
->GetStart() && pLangAttrib
->GetEnd() ==
1701 SpellLanguageAttrib
aNewLangAttrib( static_cast<const SpellLanguageAttrib
&>(pLangAttrib
->GetAttr()).GetLanguage());
1702 pTextEngine
->RemoveAttrib(0, *pLangAttrib
);
1703 pTextEngine
->SetAttrib( aNewLangAttrib
, 0, (sal_uInt16
)(m_nErrorEnd
+ nDiffLen
) , nTextLen
);
1706 // undo expanded attributes!
1707 if( pBackAttrib
&& pBackAttrib
->GetStart() < m_nErrorStart
&& pBackAttrib
->GetEnd() == m_nErrorEnd
+ nDiffLen
)
1709 boost::scoped_ptr
<TextAttrib
> pNewBackground(pBackAttrib
->GetAttr().Clone());
1710 sal_uInt16 nStart
= pBackAttrib
->GetStart();
1711 pTextEngine
->RemoveAttrib(0, *pBackAttrib
);
1712 pTextEngine
->SetAttrib(*pNewBackground
, 0, nStart
, m_nErrorStart
);
1714 pTextEngine
->SetModified(true);
1716 //adjust end position
1717 long nEndTemp
= m_nErrorEnd
;
1718 nEndTemp
+= nDiffLen
;
1719 m_nErrorEnd
= (sal_uInt16
)nEndTemp
;
1721 SpellUndoAction_Impl
* pAction
= new SpellUndoAction_Impl(
1722 SPELLUNDO_MOVE_ERROREND
, GetSpellDialog()->aDialogUndoLink
);
1723 pAction
->SetOffset(nDiffLen
);
1724 AddUndoAction(pAction
);
1725 if(pSpellErrorDescription
)
1726 SetAttrib( SpellErrorAttrib(*pSpellErrorDescription
), 0, m_nErrorStart
, m_nErrorEnd
);
1727 SetAttrib( SpellLanguageAttrib(eLanguage
), 0, m_nErrorStart
, m_nErrorEnd
);
1728 pTextEngine
->UndoActionEnd();
1732 OUString
SentenceEditWindow_Impl::GetErrorText() const
1734 return GetTextEngine()->GetText(TextSelection(TextPaM(0, m_nErrorStart
), TextPaM(0, m_nErrorEnd
) ));
1738 const SpellErrorDescription
* SentenceEditWindow_Impl::GetAlternatives()
1740 TextPaM
aCursor(0, m_nErrorStart
);
1741 const SpellErrorAttrib
* pAttrib
= static_cast<const SpellErrorAttrib
*>(
1742 GetTextEngine()->FindAttrib( aCursor
, TEXTATTR_SPELL_ERROR
));
1743 return pAttrib
? &pAttrib
->GetErrorDescription() : 0;
1747 void SentenceEditWindow_Impl::RestoreCurrentError()
1749 TextPaM
aCursor(0, m_nErrorStart
);
1750 const SpellErrorAttrib
* pAttrib
= static_cast<const SpellErrorAttrib
*>(
1751 GetTextEngine()->FindAttrib( aCursor
, TEXTATTR_SPELL_ERROR
));
1754 const SpellErrorDescription
& rDesc
= pAttrib
->GetErrorDescription();
1755 if( !rDesc
.sErrorText
.equals( GetErrorText() ) )
1756 ChangeMarkedWord(rDesc
.sErrorText
, LanguageTag::convertToLanguageType( rDesc
.aLocale
));
1761 void SentenceEditWindow_Impl::SetAlternatives( Reference
< XSpellAlternatives
> xAlt
)
1763 TextPaM
aCursor(0, m_nErrorStart
);
1764 DBG_ASSERT(static_cast<const SpellErrorAttrib
*>(
1765 GetTextEngine()->FindAttrib( aCursor
, TEXTATTR_SPELL_ERROR
)), "no error set?");
1768 lang::Locale aLocale
;
1769 uno::Sequence
< OUString
> aAlts
;
1770 OUString sServiceName
;
1773 aWord
= xAlt
->getWord();
1774 aLocale
= xAlt
->getLocale();
1775 aAlts
= xAlt
->getAlternatives();
1776 uno::Reference
< container::XNamed
> xNamed( xAlt
, uno::UNO_QUERY
);
1778 sServiceName
= xNamed
->getName();
1780 SpellErrorDescription
aDesc( false, aWord
, aLocale
, aAlts
, 0, sServiceName
);
1781 GetTextEngine()->SetAttrib( SpellErrorAttrib(aDesc
), 0, m_nErrorStart
, m_nErrorEnd
);
1785 void SentenceEditWindow_Impl::SetAttrib( const TextAttrib
& rAttr
, sal_uLong nPara
, sal_uInt16 nStart
, sal_uInt16 nEnd
)
1787 GetTextEngine()->SetAttrib(rAttr
, nPara
, nStart
, nEnd
);
1791 void SentenceEditWindow_Impl::SetText( const OUString
& rStr
)
1793 m_nErrorStart
= m_nErrorEnd
= 0;
1794 GetTextEngine()->SetText(rStr
);
1798 struct LanguagePosition_Impl
1800 sal_uInt16 nPosition
;
1801 LanguageType eLanguage
;
1803 LanguagePosition_Impl(sal_uInt16 nPos
, LanguageType eLang
) :
1808 typedef std::vector
<LanguagePosition_Impl
> LanguagePositions_Impl
;
1810 static void lcl_InsertBreakPosition_Impl(
1811 LanguagePositions_Impl
& rBreakPositions
, sal_uInt16 nInsert
, LanguageType eLanguage
)
1813 LanguagePositions_Impl::iterator aStart
= rBreakPositions
.begin();
1814 while(aStart
!= rBreakPositions
.end())
1816 if(aStart
->nPosition
== nInsert
)
1818 //the language of following starts has to overwrite
1819 //the one of previous ends
1820 aStart
->eLanguage
= eLanguage
;
1823 else if(aStart
->nPosition
> nInsert
)
1826 rBreakPositions
.insert(aStart
, LanguagePosition_Impl(nInsert
, eLanguage
));
1832 rBreakPositions
.push_back(LanguagePosition_Impl(nInsert
, eLanguage
));
1834 /*-------------------------------------------------------------------------
1835 Returns the text in spell portions. Each portion contains text with an
1836 equal language and attribute. The spell alternatives are empty.
1837 -----------------------------------------------------------------------*/
1838 svx::SpellPortions
SentenceEditWindow_Impl::CreateSpellPortions( bool bSetIgnoreFlag
) const
1840 svx::SpellPortions aRet
;
1841 ExtTextEngine
* pTextEngine
= GetTextEngine();
1842 const sal_uInt16 nTextLen
= pTextEngine
->GetTextLen(0);
1845 TextPaM
aCursor(0, 0);
1846 LanguagePositions_Impl aBreakPositions
;
1847 const TextCharAttrib
* pLastLang
= 0;
1848 const TextCharAttrib
* pLastError
= 0;
1849 LanguageType eLang
= LANGUAGE_DONTKNOW
;
1850 const TextCharAttrib
* pError
= 0;
1851 while(aCursor
.GetIndex() < nTextLen
)
1853 const TextCharAttrib
* pLang
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_SPELL_LANGUAGE
);
1854 if(pLang
&& pLang
!= pLastLang
)
1856 eLang
= static_cast<const SpellLanguageAttrib
&>(pLang
->GetAttr()).GetLanguage();
1857 lcl_InsertBreakPosition_Impl(aBreakPositions
, pLang
->GetStart(), eLang
);
1858 lcl_InsertBreakPosition_Impl(aBreakPositions
, pLang
->GetEnd(), eLang
);
1861 pError
= pTextEngine
->FindCharAttrib( aCursor
, TEXTATTR_SPELL_ERROR
);
1862 if(pError
&& pLastError
!= pError
)
1864 lcl_InsertBreakPosition_Impl(aBreakPositions
, pError
->GetStart(), eLang
);
1865 lcl_InsertBreakPosition_Impl(aBreakPositions
, pError
->GetEnd(), eLang
);
1866 pLastError
= pError
;
1869 aCursor
.GetIndex()++;
1872 if(nTextLen
&& aBreakPositions
.empty())
1874 //if all content has been overwritten the attributes may have been removed, too
1875 svx::SpellPortion aPortion1
;
1876 aPortion1
.eLanguage
= GetSpellDialog()->GetSelectedLang_Impl();
1877 aPortion1
.sText
= pTextEngine
->GetText(
1878 TextSelection(TextPaM(0, 0), TextPaM(0, nTextLen
)));
1880 aRet
.push_back(aPortion1
);
1883 else if(!aBreakPositions
.empty())
1885 LanguagePositions_Impl::iterator aStart
= aBreakPositions
.begin();
1886 //start should always be Null
1887 eLang
= aStart
->eLanguage
;
1888 sal_uInt16 nStart
= aStart
->nPosition
;
1889 DBG_ASSERT(!nStart
, "invalid start position - language attribute missing?");
1892 while(aStart
!= aBreakPositions
.end())
1894 svx::SpellPortion aPortion1
;
1895 aPortion1
.eLanguage
= eLang
;
1896 aPortion1
.sText
= pTextEngine
->GetText(
1897 TextSelection(TextPaM(0, nStart
), TextPaM(0, aStart
->nPosition
)));
1898 bool bIsIgnoreError
= m_aIgnoreErrorsAt
.find( nStart
) != m_aIgnoreErrorsAt
.end();
1899 if( bSetIgnoreFlag
&& bIsIgnoreError
)
1901 aPortion1
.bIgnoreThisError
= true;
1903 aRet
.push_back(aPortion1
);
1904 nStart
= aStart
->nPosition
;
1905 eLang
= aStart
->eLanguage
;
1910 // quick partly fix of #i71318. Correct fix needs to patch the TextEngine itself...
1911 // this one will only prevent text from disappearing. It may to not have the
1912 // correct language and will probably not spell checked...
1913 sal_uLong nPara
= pTextEngine
->GetParagraphCount();
1916 OUString aLeftOverText
;
1917 for (sal_uLong i
= 1; i
< nPara
; ++i
)
1919 aLeftOverText
+= "\x0a"; // the manual line break...
1920 aLeftOverText
+= pTextEngine
->GetText(i
);
1923 { // we need to add a new portion containing the left-over text
1924 svx::SpellPortion aPortion2
;
1925 aPortion2
.eLanguage
= eLang
;
1926 aPortion2
.sText
= aLeftOverText
;
1927 aRet
.push_back( aPortion2
);
1930 { // we just need to append the left-over text to the last portion (which had no errors)
1931 aRet
[ aRet
.size() - 1 ].sText
+= aLeftOverText
;
1939 void SentenceEditWindow_Impl::Undo()
1941 ::svl::IUndoManager
& rUndoMgr
= GetTextEngine()->GetUndoManager();
1942 DBG_ASSERT(GetUndoActionCount(), "no undo actions available" );
1943 if(!GetUndoActionCount())
1945 bool bSaveUndoEdit
= IsUndoEditMode();
1947 //if the undo edit mode is active then undo all changes until the UNDO_EDIT_MODE action has been found
1950 nId
= rUndoMgr
.GetUndoActionId();
1952 }while(bSaveUndoEdit
&& SPELLUNDO_UNDO_EDIT_MODE
!= nId
&& GetUndoActionCount());
1954 if(bSaveUndoEdit
|| SPELLUNDO_CHANGE_GROUP
== nId
)
1955 GetSpellDialog()->UpdateBoxes_Impl();
1959 void SentenceEditWindow_Impl::ResetUndo()
1961 GetTextEngine()->ResetUndo();
1965 void SentenceEditWindow_Impl::AddUndoAction( SfxUndoAction
*pAction
, bool bTryMerg
)
1967 ::svl::IUndoManager
& rUndoMgr
= GetTextEngine()->GetUndoManager();
1968 rUndoMgr
.AddUndoAction(pAction
, bTryMerg
);
1969 GetSpellDialog()->m_pUndoPB
->Enable();
1973 sal_uInt16
SentenceEditWindow_Impl::GetUndoActionCount()
1975 return GetTextEngine()->GetUndoManager().GetUndoActionCount();
1979 void SentenceEditWindow_Impl::UndoActionStart( sal_uInt16 nId
)
1981 GetTextEngine()->UndoActionStart(nId
);
1985 void SentenceEditWindow_Impl::UndoActionEnd()
1987 GetTextEngine()->UndoActionEnd();
1991 void SentenceEditWindow_Impl::MoveErrorEnd(long nOffset
)
1994 m_nErrorEnd
= m_nErrorEnd
- (sal_uInt16
)nOffset
;
1996 m_nErrorEnd
= m_nErrorEnd
-(sal_uInt16
)- nOffset
;
2000 void SentenceEditWindow_Impl::SetUndoEditMode(bool bSet
)
2002 DBG_ASSERT(!bSet
|| m_bIsUndoEditMode
!= bSet
, "SetUndoEditMode with equal values?");
2003 m_bIsUndoEditMode
= bSet
;
2004 //disable all buttons except the Change
2005 SpellDialog
* pSpellDialog
= GetSpellDialog();
2006 Control
* aControls
[] =
2008 pSpellDialog
->m_pChangeAllPB
,
2009 pSpellDialog
->m_pExplainFT
,
2010 pSpellDialog
->m_pIgnoreAllPB
,
2011 pSpellDialog
->m_pIgnoreRulePB
,
2012 pSpellDialog
->m_pIgnorePB
,
2013 pSpellDialog
->m_pSuggestionLB
,
2014 pSpellDialog
->m_pSuggestionFT
,
2015 pSpellDialog
->m_pLanguageFT
,
2016 pSpellDialog
->m_pLanguageLB
,
2017 pSpellDialog
->m_pAddToDictMB
,
2018 pSpellDialog
->m_pAddToDictPB
,
2019 pSpellDialog
->m_pAutoCorrPB
,
2025 aControls
[nIdx
]->Enable(false);
2027 while(aControls
[++nIdx
]);
2029 //remove error marks
2030 TextEngine
* pTextEngine
= GetTextEngine();
2031 pTextEngine
->RemoveAttribs( 0, (sal_uInt16
)TEXTATTR_FONTCOLOR
, true );
2032 pTextEngine
->RemoveAttribs( 0, (sal_uInt16
)TEXTATTR_FONTWEIGHT
, true );
2034 //put the appropriate action on the Undo-stack
2035 SpellUndoAction_Impl
* pAction
= new SpellUndoAction_Impl(
2036 SPELLUNDO_UNDO_EDIT_MODE
, GetSpellDialog()->aDialogUndoLink
);
2037 AddUndoAction(pAction
);
2038 pSpellDialog
->m_pChangePB
->Enable();
2041 IMPL_LINK( SpellDialog
, HandleHyperlink
, FixedHyperlink
*, pHyperlink
)
2043 OUString sURL
=pHyperlink
->GetURL();
2044 OUString sTitle
=GetText();
2046 if ( sURL
.isEmpty() ) // Nothing to do, when the URL is empty
2050 uno::Reference
< com::sun::star::system::XSystemShellExecute
> xSystemShellExecute(
2051 com::sun::star::system::SystemShellExecute::create(::comphelper::getProcessComponentContext()) );
2052 xSystemShellExecute
->execute( sURL
, OUString(), com::sun::star::system::SystemShellExecuteFlags::URIS_ONLY
);
2054 catch ( uno::Exception
& )
2056 uno::Any
exc( ::cppu::getCaughtException() );
2057 OUString
msg( ::comphelper::anyToString( exc
) );
2058 const SolarMutexGuard guard
;
2059 ScopedVclPtrInstance
< MessageDialog
> aErrorBox(nullptr, msg
);
2060 aErrorBox
->SetText(sTitle
);
2061 aErrorBox
->Execute();
2067 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */