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