LibreOffice Module cui (master)  1
SpellDialog.cxx
Go to the documentation of this file.
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 <memory>
21 #include "SpellAttrib.hxx"
22 #include <sfx2/bindings.hxx>
23 #include <sfx2/sfxsids.hrc>
24 #include <sfx2/viewfrm.hxx>
25 #include <svl/grabbagitem.hxx>
26 #include <svl/undo.hxx>
27 #include <tools/debug.hxx>
28 #include <unotools/lingucfg.hxx>
29 #include <editeng/colritem.hxx>
30 #include <editeng/eeitem.hxx>
31 #include <editeng/langitem.hxx>
32 #include <editeng/splwrap.hxx>
33 #include <editeng/unolingu.hxx>
34 #include <editeng/wghtitem.hxx>
35 #include <linguistic/misc.hxx>
36 #include <com/sun/star/lang/XServiceInfo.hpp>
37 #include <com/sun/star/frame/XStorable.hpp>
38 #include <com/sun/star/linguistic2/XDictionary.hpp>
39 #include <com/sun/star/linguistic2/XSpellAlternatives.hpp>
40 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
41 #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
42 #include <sfx2/app.hxx>
43 #include <vcl/edit.hxx>
44 #include <vcl/event.hxx>
45 #include <vcl/svapp.hxx>
46 #include <vcl/texteng.hxx>
47 #include <vcl/weld.hxx>
49 #include <SpellDialog.hxx>
50 #include <optlingu.hxx>
51 #include <treeopt.hxx>
52 #include <svtools/langtab.hxx>
53 #include <sal/log.hxx>
55 
56 using namespace ::com::sun::star;
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::beans;
59 using namespace ::com::sun::star::linguistic2;
60 using namespace linguistic;
61 
62 
63 // struct SpellDialog_Impl ---------------------------------------------
64 
66 {
67  Sequence< Reference< XDictionary > > aDics;
68 };
69 
70 
71 #define SPELLUNDO_START 200
72 
73 #define SPELLUNDO_CHANGE_LANGUAGE (SPELLUNDO_START + 1)
74 #define SPELLUNDO_CHANGE_TEXTENGINE (SPELLUNDO_START + 2)
75 #define SPELLUNDO_CHANGE_NEXTERROR (SPELLUNDO_START + 3)
76 #define SPELLUNDO_CHANGE_ADD_TO_DICTIONARY (SPELLUNDO_START + 4)
77 #define SPELLUNDO_CHANGE_GROUP (SPELLUNDO_START + 5) //undo list
78 #define SPELLUNDO_MOVE_ERROREND (SPELLUNDO_START + 6)
79 #define SPELLUNDO_UNDO_EDIT_MODE (SPELLUNDO_START + 7)
80 #define SPELLUNDO_ADD_IGNORE_RULE (SPELLUNDO_START + 8)
81 
82 namespace svx{
84 {
85  sal_uInt16 m_nId;
87  //undo of button enabling
90  //undo of MarkNextError - used in change and change all, ignore and ignore all
94  //undo of AddToDictionary
95  Reference<XDictionary> m_xDictionary;
96  OUString m_sAddedWord;
97  //move end of error - ::ChangeMarkedWord()
98  long m_nOffset;
99 
100 public:
101  SpellUndoAction_Impl(sal_uInt16 nId, const Link<SpellUndoAction_Impl&,void>& rActionLink) :
102  m_nId(nId),
103  m_rActionLink( rActionLink),
104  m_bEnableChangePB(false),
105  m_bEnableChangeAllPB(false),
106  m_nOldErrorStart(-1),
107  m_nOldErrorEnd(-1),
108  m_bIsErrorLanguageSelected(false),
109  m_nOffset(0)
110  {}
111 
112  virtual void Undo() override;
113  sal_uInt16 GetId() const;
114 
115  void SetEnableChangePB(){m_bEnableChangePB = true;}
116  bool IsEnableChangePB() const {return m_bEnableChangePB;}
117 
118  void SetEnableChangeAllPB(){m_bEnableChangeAllPB = true;}
119  bool IsEnableChangeAllPB() const {return m_bEnableChangeAllPB;}
120 
121  void SetErrorMove(long nOldStart, long nOldEnd)
122  {
123  m_nOldErrorStart = nOldStart;
124  m_nOldErrorEnd = nOldEnd;
125  }
126  long GetOldErrorStart() const { return m_nOldErrorStart;}
127  long GetOldErrorEnd() const { return m_nOldErrorEnd;}
128 
129  void SetErrorLanguageSelected(bool bSet){ m_bIsErrorLanguageSelected = bSet;}
130  bool IsErrorLanguageSelected() const {return m_bIsErrorLanguageSelected;}
131 
132  void SetDictionary(const Reference<XDictionary>& xDict) { m_xDictionary = xDict; }
133  const Reference<XDictionary>& GetDictionary() const { return m_xDictionary; }
134  void SetAddedWord(const OUString& rWord) {m_sAddedWord = rWord;}
135  const OUString& GetAddedWord() const { return m_sAddedWord;}
136 
137  void SetOffset(long nSet) {m_nOffset = nSet;}
138  long GetOffset() const {return m_nOffset;}
139 };
140 }//namespace svx
141 using namespace ::svx;
142 
143 void SpellUndoAction_Impl::Undo()
144 {
145  m_rActionLink.Call(*this);
146 }
147 
148 
149 sal_uInt16 SpellUndoAction_Impl::GetId()const
150 {
151  return m_nId;
152 }
153 
154 // class SvxSpellCheckDialog ---------------------------------------------
155 
156 SpellDialog::SpellDialog(SpellDialogChildWindow* pChildWindow,
157  weld::Window * pParent, SfxBindings* _pBindings)
158  : SfxModelessDialogController (_pBindings, pChildWindow,
159  pParent, "cui/ui/spellingdialog.ui", "SpellingDialog")
160  , aDialogUndoLink(LINK (this, SpellDialog, DialogUndoHdl))
161  , bFocusLocked(true)
162  , rParent(*pChildWindow)
163  , pImpl( new SpellDialog_Impl )
164  , m_xAltTitle(m_xBuilder->weld_label("alttitleft"))
165  , m_xResumeFT(m_xBuilder->weld_label("resumeft"))
166  , m_xNoSuggestionsFT(m_xBuilder->weld_label("nosuggestionsft"))
167  , m_xLanguageFT(m_xBuilder->weld_label("languageft"))
168  , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("languagelb")))
169  , m_xExplainFT(m_xBuilder->weld_label("explain"))
170  , m_xExplainLink(m_xBuilder->weld_link_button("explainlink"))
171  , m_xNotInDictFT(m_xBuilder->weld_label("notindictft"))
172  , m_xSentenceED(new SentenceEditWindow_Impl)
173  , m_xSuggestionFT(m_xBuilder->weld_label("suggestionsft"))
174  , m_xSuggestionLB(m_xBuilder->weld_tree_view("suggestionslb"))
175  , m_xIgnorePB(m_xBuilder->weld_button("ignore"))
176  , m_xIgnoreAllPB(m_xBuilder->weld_button("ignoreall"))
177  , m_xIgnoreRulePB(m_xBuilder->weld_button("ignorerule"))
178  , m_xAddToDictPB(m_xBuilder->weld_button("add"))
179  , m_xAddToDictMB(m_xBuilder->weld_menu_button("addmb"))
180  , m_xChangePB(m_xBuilder->weld_button("change"))
181  , m_xChangeAllPB(m_xBuilder->weld_button("changeall"))
182  , m_xAutoCorrPB(m_xBuilder->weld_button("autocorrect"))
183  , m_xCheckGrammarCB(m_xBuilder->weld_check_button("checkgrammar"))
184  , m_xOptionsPB(m_xBuilder->weld_button("options"))
185  , m_xUndoPB(m_xBuilder->weld_button("undo"))
186  , m_xClosePB(m_xBuilder->weld_button("close"))
187  , m_xToolbar(m_xBuilder->weld_toolbar("toolbar"))
188  , m_xSentenceEDWeld(new weld::CustomWeld(*m_xBuilder, "sentence", *m_xSentenceED))
189 {
190  m_xSentenceED->SetSpellDialog(this);
191  m_xSentenceED->Init(m_xToolbar.get());
192 
193  m_sTitleSpellingGrammar = m_xDialog->get_title();
194  m_sTitleSpelling = m_xAltTitle->get_label();
195 
196  // fdo#68794 set initial title for cases where no text has been processed
197  // yet to show its language attributes
199  m_xDialog->set_title(m_xDialog->strip_mnemonic(sTitle.replaceFirst("$LANGUAGE ($LOCATION)", "")));
200 
201  m_sResumeST = m_xResumeFT->get_label();
202  m_sNoSuggestionsST = m_xNoSuggestionsFT->strip_mnemonic(m_xNoSuggestionsFT->get_label());
203 
204  Size aEdSize(m_xSuggestionLB->get_approximate_digit_width() * 60,
205  m_xSuggestionLB->get_height_rows(6));
206  m_xSuggestionLB->set_size_request(aEdSize.Width(), -1);
207  m_sIgnoreOnceST = m_xIgnorePB->get_label();
208  m_xAddToDictMB->set_help_id(m_xAddToDictPB->get_help_id());
210 
211  Init_Impl();
212 
213  // disable controls if service is missing
214  m_xDialog->set_sensitive(xSpell.is());
215 
216  //InitHdl wants to use virtual methods, so it
217  //can't be called during the ctor, so init
218  //it on next event cycle post-ctor
220 }
221 
223 {
224  if (pImpl)
225  {
226  // save possibly modified user-dictionaries
227  Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
228  if (xDicList.is())
229  SaveDictionaries( xDicList );
230 
231  pImpl.reset();
232  }
233 }
234 
236 {
237  // initialize handler
238  m_xClosePB->connect_clicked(LINK( this, SpellDialog, CancelHdl ) );
239  m_xChangePB->connect_clicked(LINK( this, SpellDialog, ChangeHdl ) );
240  m_xChangeAllPB->connect_clicked(LINK( this, SpellDialog, ChangeAllHdl ) );
241  m_xIgnorePB->connect_clicked(LINK( this, SpellDialog, IgnoreHdl ) );
242  m_xIgnoreAllPB->connect_clicked(LINK( this, SpellDialog, IgnoreAllHdl ) );
243  m_xIgnoreRulePB->connect_clicked(LINK( this, SpellDialog, IgnoreAllHdl ) );
244  m_xUndoPB->connect_clicked(LINK( this, SpellDialog, UndoHdl ) );
245 
246  m_xAutoCorrPB->connect_clicked( LINK( this, SpellDialog, ExtClickHdl ) );
247  m_xCheckGrammarCB->connect_clicked( LINK( this, SpellDialog, CheckGrammarHdl ));
248  m_xOptionsPB->connect_clicked( LINK( this, SpellDialog, ExtClickHdl ) );
249 
250  m_xSuggestionLB->connect_row_activated( LINK( this, SpellDialog, DoubleClickChangeHdl ) );
251 
252  m_xSentenceED->SetModifyHdl(LINK ( this, SpellDialog, ModifyHdl) );
253 
254  m_xAddToDictMB->connect_selected(LINK ( this, SpellDialog, AddToDictSelectHdl ) );
255  m_xAddToDictPB->connect_clicked(LINK ( this, SpellDialog, AddToDictClickHdl ) );
256 
257  m_xLanguageLB->connect_changed(LINK( this, SpellDialog, LanguageSelectHdl ) );
258 
259  // initialize language ListBox
260  m_xLanguageLB->SetLanguageList(SvxLanguageListFlags::SPELL_USED, false, false, true);
261 
262  m_xSentenceED->ClearModifyFlag();
263  LinguMgr::GetChangeAllList()->clear();
264 }
265 
266 void SpellDialog::UpdateBoxes_Impl(bool bCallFromSelectHdl)
267 {
268  sal_Int32 i;
269  m_xSuggestionLB->clear();
270 
271  SpellErrorDescription aSpellErrorDescription;
272  bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
273 
274  LanguageType nAltLanguage = LANGUAGE_NONE;
275  Sequence< OUString > aNewWords;
276  bool bIsGrammarError = false;
277  if( bSpellErrorDescription )
278  {
279  nAltLanguage = LanguageTag::convertToLanguageType( aSpellErrorDescription.aLocale );
280  aNewWords = aSpellErrorDescription.aSuggestions;
281  bIsGrammarError = aSpellErrorDescription.bIsGrammarError;
282  m_xExplainLink->set_uri( aSpellErrorDescription.sExplanationURL );
283  m_xExplainFT->set_label( aSpellErrorDescription.sExplanation );
284  }
285  if( bSpellErrorDescription && !aSpellErrorDescription.sDialogTitle.isEmpty() )
286  {
287  // use this function to apply the correct image to be used...
288  SetTitle_Impl( nAltLanguage );
289  // then change the title to the one to be actually used
290  m_xDialog->set_title(m_xDialog->strip_mnemonic(aSpellErrorDescription.sDialogTitle));
291  }
292  else
293  SetTitle_Impl( nAltLanguage );
294  if( !bCallFromSelectHdl )
295  m_xLanguageLB->set_active_id( nAltLanguage );
296  int nDicts = InitUserDicts();
297 
298  // enter alternatives
299  const OUString *pNewWords = aNewWords.getConstArray();
300  const sal_Int32 nSize = aNewWords.getLength();
301  for ( i = 0; i < nSize; ++i )
302  {
303  OUString aTmp( pNewWords[i] );
304  if (m_xSuggestionLB->find_text(aTmp) == -1)
305  m_xSuggestionLB->append_text(aTmp);
306  }
307  if(!nSize)
308  m_xSuggestionLB->append_text(m_sNoSuggestionsST);
309  m_xAutoCorrPB->set_sensitive( nSize > 0 );
310 
311  m_xSuggestionFT->set_sensitive(nSize > 0);
312  m_xSuggestionLB->set_sensitive(nSize > 0);
313  if( nSize )
314  {
315  m_xSuggestionLB->select(0);
316  }
317  m_xChangePB->set_sensitive( nSize > 0);
318  m_xChangeAllPB->set_sensitive(nSize > 0);
319  bool bShowChangeAll = !bIsGrammarError;
320  m_xChangeAllPB->set_visible( bShowChangeAll );
321  m_xExplainFT->set_visible( !bShowChangeAll );
322  m_xLanguageLB->set_sensitive( bShowChangeAll );
323  m_xIgnoreAllPB->set_visible( bShowChangeAll );
324 
325  m_xAddToDictMB->set_visible( bShowChangeAll && nDicts > 1);
326  m_xAddToDictPB->set_visible( bShowChangeAll && nDicts <= 1);
327  m_xIgnoreRulePB->set_visible( !bShowChangeAll );
328  m_xIgnoreRulePB->set_sensitive(bSpellErrorDescription && !aSpellErrorDescription.sRuleId.isEmpty());
329  m_xAutoCorrPB->set_visible( bShowChangeAll && rParent.HasAutoCorrection() );
330 
331  bool bOldShowGrammar = m_xCheckGrammarCB->get_visible();
332  bool bOldShowExplain = m_xExplainLink->get_visible();
333 
335  m_xExplainLink->set_visible(!m_xExplainLink->get_uri().isEmpty());
336  if (m_xExplainFT->get_label().isEmpty())
337  {
338  m_xExplainFT->hide();
339  m_xExplainLink->hide();
340  }
341 
342  if (bOldShowExplain != m_xExplainLink->get_visible() || bOldShowGrammar != m_xCheckGrammarCB->get_visible())
343  m_xDialog->resize_to_request();
344 }
345 
346 void SpellDialog::SpellContinue_Impl(bool bUseSavedSentence, bool bIgnoreCurrentError )
347 {
348  //initially or after the last error of a sentence MarkNextError will fail
349  //then GetNextSentence() has to be called followed again by MarkNextError()
350  //MarkNextError is not initially called if the UndoEdit mode is active
351  bool bNextSentence = false;
352  if((!m_xSentenceED->IsUndoEditMode() && m_xSentenceED->MarkNextError( bIgnoreCurrentError, xSpell )) ||
353  ( bNextSentence = GetNextSentence_Impl(bUseSavedSentence, m_xSentenceED->IsUndoEditMode()) && m_xSentenceED->MarkNextError( false, xSpell )))
354  {
355  SpellErrorDescription aSpellErrorDescription;
356  bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
357  if (bSpellErrorDescription)
358  {
360  weld::Widget* aControls[] =
361  {
362  m_xNotInDictFT.get(),
363  m_xSentenceED->GetDrawingArea(),
364  m_xLanguageFT.get(),
365  nullptr
366  };
367  sal_Int32 nIdx = 0;
368  do
369  {
370  aControls[nIdx]->set_sensitive(true);
371  }
372  while(aControls[++nIdx]);
373 
374  }
375  if( bNextSentence )
376  {
377  //remove undo if a new sentence is active
378  m_xSentenceED->ResetUndo();
379  m_xUndoPB->set_sensitive(false);
380  }
381  }
382 }
383 /* Initialize, asynchronous to prevent virtual calls
384  from a constructor
385  */
386 IMPL_LINK_NOARG( SpellDialog, InitHdl, void*, void)
387 {
388  m_xDialog->freeze();
389  //show or hide AutoCorrect depending on the modules abilities
390  m_xAutoCorrPB->set_visible(rParent.HasAutoCorrection());
391  SpellContinue_Impl();
392  m_xSentenceED->ResetUndo();
393  m_xUndoPB->set_sensitive(false);
394 
395  // get current language
396  UpdateBoxes_Impl();
397 
398  // fill dictionary PopupMenu
399  InitUserDicts();
400 
401  LockFocusChanges(true);
402  if( m_xChangePB->get_sensitive() )
403  m_xChangePB->grab_focus();
404  else if( m_xIgnorePB->get_sensitive() )
405  m_xIgnorePB->grab_focus();
406  else if( m_xClosePB->get_sensitive() )
407  m_xClosePB->grab_focus();
408  LockFocusChanges(false);
409  //show grammar CheckBox depending on the modules abilities
410  m_xCheckGrammarCB->set_active(rParent.IsGrammarChecking());
411  m_xDialog->thaw();
412 };
413 
414 IMPL_LINK( SpellDialog, ExtClickHdl, weld::Button&, rBtn, void )
415 {
416  if (m_xOptionsPB.get() == &rBtn)
417  StartSpellOptDlg_Impl();
418  else if (m_xAutoCorrPB.get() == &rBtn)
419  {
420  //get the currently selected wrong word
421  OUString sCurrentErrorText = m_xSentenceED->GetErrorText();
422  //get the wrong word from the XSpellAlternative
423  SpellErrorDescription aSpellErrorDescription;
424  bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
425  if (bSpellErrorDescription)
426  {
427  OUString sWrong(aSpellErrorDescription.sErrorText);
428  //if the word has not been edited in the MultiLineEdit then
429  //the current suggestion should be used
430  //if it's not the 'no suggestions' entry
431  if(sWrong == sCurrentErrorText &&
432  m_xSuggestionLB->get_sensitive() && m_xSuggestionLB->get_selected_index() != -1 &&
433  m_sNoSuggestionsST != m_xSuggestionLB->get_selected_text())
434  {
435  sCurrentErrorText = m_xSuggestionLB->get_selected_text();
436  }
437  if(sWrong != sCurrentErrorText)
438  {
439  SvxPrepareAutoCorrect( sWrong, sCurrentErrorText );
440  LanguageType eLang = GetSelectedLang_Impl();
441  rParent.AddAutoCorrection( sWrong, sCurrentErrorText, eLang );
442  }
443  }
444  }
445 }
446 
447 IMPL_LINK_NOARG(SpellDialog, CheckGrammarHdl, weld::Button&, void)
448 {
449  rParent.SetGrammarChecking(m_xCheckGrammarCB->get_active());
450  Impl_Restore(true);
451 }
452 
454 {
456  SfxSingleTabDialogController aDlg(m_xDialog.get(), &aSet, "cui/ui/spelloptionsdialog.ui", "SpellOptionsDialog");
457 
458  std::unique_ptr<SfxTabPage> xPage = SvxLinguTabPage::Create(aDlg.get_content_area(), &aDlg, &aSet);
459  static_cast<SvxLinguTabPage*>(xPage.get())->HideGroups( GROUP_MODULES );
460  aDlg.SetTabPage(std::move(xPage));
461  if (RET_OK == aDlg.run())
462  {
463  InitUserDicts();
464  const SfxItemSet* pOutSet = aDlg.GetOutputItemSet();
465  if(pOutSet)
467  }
468 }
469 
470 namespace
471 {
472  OUString getDotReplacementString(const OUString &rErrorText, const OUString &rSuggestedReplacement)
473  {
474  OUString aString = rErrorText;
475 
476  //dots are sometimes part of the spelled word but they are not necessarily part of the replacement
477  bool bDot = aString.endsWith(".");
478 
479  aString = rSuggestedReplacement;
480 
481  if(bDot && (aString.isEmpty() || !aString.endsWith(".")))
482  aString += ".";
483 
484  return aString;
485  }
486 }
487 
489 {
490  OUString sOrigString = m_xSentenceED->GetErrorText();
491 
492  OUString sReplacement(sOrigString);
493 
494  if(m_xSuggestionLB->get_sensitive() &&
495  m_xSuggestionLB->get_selected_index() != -1 &&
496  m_sNoSuggestionsST != m_xSuggestionLB->get_selected_text())
497  sReplacement = m_xSuggestionLB->get_selected_text();
498 
499  return getDotReplacementString(sOrigString, sReplacement);
500 }
501 
502 IMPL_LINK_NOARG(SpellDialog, DoubleClickChangeHdl, weld::TreeView&, bool)
503 {
504  ChangeHdl(*m_xChangePB);
505  return true;
506 }
507 
508 IMPL_LINK_NOARG(SpellDialog, ChangeHdl, weld::Button&, void)
509 {
510  if (m_xSentenceED->IsUndoEditMode())
511  {
512  SpellContinue_Impl();
513  }
514  else
515  {
516  m_xSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
517  OUString aString = getReplacementString();
518  m_xSentenceED->ChangeMarkedWord(aString, GetSelectedLang_Impl());
519  SpellContinue_Impl();
520  m_xSentenceED->UndoActionEnd();
521  }
522  if(!m_xChangePB->get_sensitive())
523  m_xIgnorePB->grab_focus();
524 }
525 
526 IMPL_LINK_NOARG(SpellDialog, ChangeAllHdl, weld::Button&, void)
527 {
528  m_xSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
529  OUString aString = getReplacementString();
530  LanguageType eLang = GetSelectedLang_Impl();
531 
532  // add new word to ChangeAll list
533  OUString aOldWord( m_xSentenceED->GetErrorText() );
534  SvxPrepareAutoCorrect( aOldWord, aString );
535  Reference<XDictionary> aXDictionary = LinguMgr::GetChangeAllList();
536  DictionaryError nAdded = AddEntryToDic( aXDictionary,
537  aOldWord, true,
538  aString );
539 
540  if(nAdded == DictionaryError::NONE)
541  {
542  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
543  SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
544  pAction->SetDictionary(aXDictionary);
545  pAction->SetAddedWord(aOldWord);
546  m_xSentenceED->AddUndoAction(std::move(pAction));
547  }
548 
549  m_xSentenceED->ChangeMarkedWord(aString, eLang);
550  SpellContinue_Impl();
551  m_xSentenceED->UndoActionEnd();
552 }
553 
554 IMPL_LINK( SpellDialog, IgnoreAllHdl, weld::Button&, rButton, void )
555 {
556  m_xSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
557  // add word to IgnoreAll list
558  Reference< XDictionary > aXDictionary = LinguMgr::GetIgnoreAllList();
559  //in case the error has been changed manually it has to be restored
560  m_xSentenceED->RestoreCurrentError();
561  if (&rButton == m_xIgnoreRulePB.get())
562  {
563  SpellErrorDescription aSpellErrorDescription;
564  bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
565  try
566  {
567  if( bSpellErrorDescription && aSpellErrorDescription.xGrammarChecker.is() )
568  {
569  aSpellErrorDescription.xGrammarChecker->ignoreRule(aSpellErrorDescription.sRuleId,
570  aSpellErrorDescription.aLocale);
571  // refresh the layout (workaround to launch a dictionary event)
572  aXDictionary->setActive(false);
573  aXDictionary->setActive(true);
574  }
575  }
576  catch( const uno::Exception& )
577  {
578  }
579  }
580  else
581  {
582  OUString sErrorText(m_xSentenceED->GetErrorText());
583  DictionaryError nAdded = AddEntryToDic( aXDictionary,
584  sErrorText, false,
585  OUString() );
586  if (nAdded == DictionaryError::NONE)
587  {
588  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
589  SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
590  pAction->SetDictionary(aXDictionary);
591  pAction->SetAddedWord(sErrorText);
592  m_xSentenceED->AddUndoAction(std::move(pAction));
593  }
594  }
595 
596  SpellContinue_Impl();
597  m_xSentenceED->UndoActionEnd();
598 }
599 
600 IMPL_LINK_NOARG(SpellDialog, UndoHdl, weld::Button&, void)
601 {
602  m_xSentenceED->Undo();
603  if(!m_xSentenceED->GetUndoActionCount())
604  m_xUndoPB->set_sensitive(false);
605 }
606 
607 
608 IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl&, rAction, void )
609 {
610  switch(rAction.GetId())
611  {
613  {
614  if(rAction.IsEnableChangePB())
615  m_xChangePB->set_sensitive(false);
616  if(rAction.IsEnableChangeAllPB())
617  m_xChangeAllPB->set_sensitive(false);
618  }
619  break;
621  {
622  m_xSentenceED->MoveErrorMarkTo(static_cast<sal_Int32>(rAction.GetOldErrorStart()),
623  static_cast<sal_Int32>(rAction.GetOldErrorEnd()),
624  false);
625  if(rAction.IsErrorLanguageSelected())
626  {
627  UpdateBoxes_Impl();
628  }
629  }
630  break;
632  {
633  if(rAction.GetDictionary().is())
634  rAction.GetDictionary()->remove(rAction.GetAddedWord());
635  }
636  break;
638  {
639  if(rAction.GetOffset() != 0)
640  m_xSentenceED->MoveErrorEnd(rAction.GetOffset());
641  }
642  break;
644  {
645  //refill the dialog with the currently spelled sentence - throw away all changes
646  SpellContinue_Impl(true);
647  }
648  break;
650  //undo of ignored rules is not supported
651  break;
652  }
653 }
654 
655 void SpellDialog::Impl_Restore(bool bUseSavedSentence)
656 {
657  //clear the "ChangeAllList"
658  LinguMgr::GetChangeAllList()->clear();
659  //get a new sentence
660  m_xSentenceED->SetText(OUString());
661  m_xSentenceED->ResetModified();
662  //Resolves: fdo#39348 refill the dialog with the currently spelled sentence
663  SpellContinue_Impl(bUseSavedSentence);
664  m_xIgnorePB->set_label(m_sIgnoreOnceST);
665 }
666 
667 IMPL_LINK_NOARG(SpellDialog, IgnoreHdl, weld::Button&, void)
668 {
669  if (m_sResumeST == m_xIgnorePB->get_label())
670  {
671  Impl_Restore(false);
672  }
673  else
674  {
675  //in case the error has been changed manually it has to be restored,
676  // since the users choice now was to ignore the error
677  m_xSentenceED->RestoreCurrentError();
678 
679  // the word is being ignored
680  SpellContinue_Impl( false, true );
681  }
682 }
683 
685 {
686  if (IsClosing())
687  return;
688 
689  // We have to call ToggleChildWindow directly; calling SfxDispatcher's
690  // Execute() does not work here when we are in a document with protected
691  // section - in that case, the cursor can move from the editable field to
692  // the protected area, and the slots get disabled because of
693  // SfxDisableFlags::SwOnProtectedCursor (see FN_SPELL_GRAMMAR_DIALOG in .sdi).
694  SfxViewFrame* pViewFrame = SfxViewFrame::Current();
695  if (pViewFrame)
696  pViewFrame->ToggleChildWindow(rParent.GetType());
697 }
698 
700 {
701  LanguageType nLang = m_xLanguageLB->get_active_id();
702  return nLang;
703 }
704 
705 IMPL_LINK_NOARG(SpellDialog, LanguageSelectHdl, weld::ComboBox&, void)
706 {
707  //If selected language changes, then add->list should be regenerated to
708  //match
709  InitUserDicts();
710 
711  //if currently an error is selected then search for alternatives for
712  //this word and fill the alternatives ListBox accordingly
713  OUString sError = m_xSentenceED->GetErrorText();
714  m_xSuggestionLB->clear();
715  if (!sError.isEmpty())
716  {
717  LanguageType eLanguage = m_xLanguageLB->get_active_id();
718  Reference <XSpellAlternatives> xAlt = xSpell->spell( sError, static_cast<sal_uInt16>(eLanguage),
720  if( xAlt.is() )
721  m_xSentenceED->SetAlternatives( xAlt );
722  else
723  {
724  m_xSentenceED->ChangeMarkedWord( sError, eLanguage );
725  SpellContinue_Impl();
726  }
727 
728  m_xSentenceED->AddUndoAction(std::make_unique<SpellUndoAction_Impl>(SPELLUNDO_CHANGE_LANGUAGE, aDialogUndoLink));
729  }
731 }
732 
734 {
736  sTitle = sTitle.replaceFirst( "$LANGUAGE ($LOCATION)", SvtLanguageTable::GetLanguageString(nLang) );
737  m_xDialog->set_title(m_xDialog->strip_mnemonic(sTitle));
738 }
739 
741 {
742  const LanguageType nLang = m_xLanguageLB->get_active_id();
743 
744  const Reference< XDictionary > *pDic = nullptr;
745 
746  // get list of dictionaries
747  Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
748  if (xDicList.is())
749  {
750  // add active, positive dictionary to dic-list (if not already done).
751  // This is to ensure that there is at least on dictionary to which
752  // words could be added.
753  Reference< XDictionary > xDic( LinguMgr::GetStandardDic() );
754  if (xDic.is())
755  xDic->setActive( true );
756 
757  pImpl->aDics = xDicList->getDictionaries();
758  }
759 
760  SvtLinguConfig aCfg;
761 
762  // list suitable dictionaries
763  bool bEnable = false;
764  const sal_Int32 nSize = pImpl->aDics.getLength();
765  pDic = pImpl->aDics.getConstArray();
766  m_xAddToDictMB->clear();
767  sal_uInt16 nItemId = 1; // menu items should be enumerated from 1 and not 0
768  for (sal_Int32 i = 0; i < nSize; ++i)
769  {
770  uno::Reference< linguistic2::XDictionary > xDicTmp = pDic[i];
771  if (!xDicTmp.is() || LinguMgr::GetIgnoreAllList() == xDicTmp)
772  continue;
773 
774  uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY );
775  LanguageType nActLanguage = LanguageTag( xDicTmp->getLocale() ).getLanguageType();
776  if( xDicTmp->isActive()
777  && xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
778  && (nLang == nActLanguage || LANGUAGE_NONE == nActLanguage )
779  && (!xStor.is() || !xStor->isReadonly()) )
780  {
781  bEnable = true;
782 
783  OUString aDictionaryImageUrl;
784  uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY );
785  if (xSvcInfo.is())
786  {
787  aDictionaryImageUrl = aCfg.GetSpellAndGrammarContextDictionaryImage(
788  xSvcInfo->getImplementationName());
789  }
790 
791  m_xAddToDictMB->append_item(OUString::number(nItemId), xDicTmp->getName(), aDictionaryImageUrl);
792 
793  ++nItemId;
794  }
795  }
796  m_xAddToDictMB->set_sensitive( bEnable );
797  m_xAddToDictPB->set_sensitive( bEnable );
798 
799  int nDicts = nItemId-1;
800 
801  m_xAddToDictMB->set_visible( nDicts > 1 );
802  m_xAddToDictPB->set_visible( nDicts <= 1 );
803 
804  return nDicts;
805 }
806 
807 IMPL_LINK_NOARG(SpellDialog, AddToDictClickHdl, weld::Button&, void)
808 {
809  AddToDictionaryExecute(OString::number(1));
810 }
811 
812 IMPL_LINK(SpellDialog, AddToDictSelectHdl, const OString&, rIdent, void)
813 {
814  AddToDictionaryExecute(rIdent);
815 }
816 
817 void SpellDialog::AddToDictionaryExecute(const OString& rItemId)
818 {
819  m_xSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
820 
821  //GetErrorText() returns the current error even if the text is already
822  //manually changed
823  const OUString aNewWord = m_xSentenceED->GetErrorText();
824 
825  OUString aDicName(m_xAddToDictMB->get_item_label(rItemId));
826 
827  uno::Reference< linguistic2::XDictionary > xDic;
828  uno::Reference< linguistic2::XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
829  if (xDicList.is())
830  xDic = xDicList->getDictionaryByName( aDicName );
831 
832  DictionaryError nAddRes = DictionaryError::UNKNOWN;
833  if (xDic.is())
834  {
835  nAddRes = AddEntryToDic( xDic, aNewWord, false, OUString() );
836  // save modified user-dictionary if it is persistent
837  uno::Reference< frame::XStorable > xSavDic( xDic, uno::UNO_QUERY );
838  if (xSavDic.is())
839  xSavDic->store();
840 
841  if (nAddRes == DictionaryError::NONE)
842  {
843  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
845  pAction->SetDictionary( xDic );
846  pAction->SetAddedWord( aNewWord );
847  m_xSentenceED->AddUndoAction( std::move(pAction) );
848  }
849  // failed because there is already an entry?
850  if (DictionaryError::NONE != nAddRes && xDic->getEntry( aNewWord ).is())
851  nAddRes = DictionaryError::NONE;
852  }
853  if (DictionaryError::NONE != nAddRes)
854  {
855  SvxDicError(m_xDialog.get(), nAddRes);
856  return; // don't continue
857  }
858 
859  // go on
861  m_xSentenceED->UndoActionEnd();
862 }
863 
864 IMPL_LINK_NOARG(SpellDialog, ModifyHdl, LinkParamNone*, void)
865 {
866  m_xSuggestionLB->unselect_all();
867  m_xSuggestionLB->set_sensitive(false);
868  m_xAutoCorrPB->set_sensitive(false);
869  std::unique_ptr<SpellUndoAction_Impl> pSpellAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE, aDialogUndoLink));
870  if(!m_xChangeAllPB->get_sensitive())
871  {
872  m_xChangeAllPB->set_sensitive(true);
873  pSpellAction->SetEnableChangeAllPB();
874  }
875  if(!m_xChangePB->get_sensitive())
876  {
877  m_xChangePB->set_sensitive(true);
878  pSpellAction->SetEnableChangePB();
879  }
880  m_xSentenceED->AddUndoAction(std::move(pSpellAction));
881 }
882 
883 IMPL_LINK_NOARG(SpellDialog, CancelHdl, weld::Button&, void)
884 {
885  //apply changes and ignored text parts first - if there are any
886  rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), false);
887  Close();
888 }
889 
891 {
892  /* #i38338#
893  * FIXME: LoseFocus and GetFocus are signals from vcl that
894  * a window actually got/lost the focus, it never should be
895  * forwarded from another window, that is simply wrong.
896  * FIXME: overriding the virtual methods GetFocus and LoseFocus
897  * in SpellDialogChildWindow by making them pure is at least questionable.
898  * The only sensible thing would be to call the new Method differently,
899  * e.g. DialogGot/LostFocus or so.
900  */
901  if (m_xDialog->get_visible() && !bFocusLocked)
902  {
903  if (m_xDialog->has_toplevel_focus())
904  {
905  //notify the child window of the focus change
906  rParent.GetFocus();
907  }
908  else
909  {
910  //notify the child window of the focus change
911  rParent.LoseFocus();
912  }
913  }
914 }
915 
917 {
920 }
921 
923 {
926 }
927 
929 {
930  if( bFocusLocked )
931  return;
932  m_xIgnorePB->set_label(m_sResumeST);
933  weld::Widget* aDisableArr[] =
934  {
935  m_xNotInDictFT.get(),
936  m_xSentenceED->GetDrawingArea(),
937  m_xSuggestionFT.get(),
938  m_xSuggestionLB.get(),
939  m_xLanguageFT.get(),
940  m_xLanguageLB->get_widget(),
941  m_xIgnoreAllPB.get(),
942  m_xIgnoreRulePB.get(),
943  m_xAddToDictMB.get(),
944  m_xAddToDictPB.get(),
945  m_xChangePB.get(),
946  m_xChangeAllPB.get(),
947  m_xAutoCorrPB.get(),
948  m_xUndoPB.get(),
949  nullptr
950  };
951  sal_Int16 i = 0;
952  while(aDisableArr[i])
953  {
954  aDisableArr[i]->set_sensitive(false);
955  i++;
956  }
958 }
959 
960 bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence, bool bRecheck)
961 {
962  bool bRet = false;
963  if(!bUseSavedSentence)
964  {
965  //apply changes and ignored text parts
966  rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), bRecheck);
967  }
968  m_xSentenceED->ResetIgnoreErrorsAt();
969  m_xSentenceED->ResetModified();
970  SpellPortions aSentence = bUseSavedSentence ? m_aSavedSentence : rParent.GetNextWrongSentence( bRecheck );
971  if(!bUseSavedSentence)
972  m_aSavedSentence = aSentence;
973  bool bHasReplaced = false;
974  while(!aSentence.empty())
975  {
976  //apply all changes that are already part of the "ChangeAllList"
977  //returns true if the list still contains errors after the changes have been applied
978 
979  if(!ApplyChangeAllList_Impl(aSentence, bHasReplaced))
980  {
981  rParent.ApplyChangedSentence(aSentence, bRecheck);
982  aSentence = rParent.GetNextWrongSentence( bRecheck );
983  }
984  else
985  break;
986  }
987 
988  if(!aSentence.empty())
989  {
990  OUStringBuffer sText;
991  for (auto const& elem : aSentence)
992  {
993  // hidden text has to be ignored
994  if(!elem.bIsHidden)
995  sText.append(elem.sText);
996  }
997  m_xSentenceED->SetText(sText.makeStringAndClear());
998  sal_Int32 nStartPosition = 0;
999  sal_Int32 nEndPosition = 0;
1000 
1001  for (auto const& elem : aSentence)
1002  {
1003  // hidden text has to be ignored
1004  if(!elem.bIsHidden)
1005  {
1006  nEndPosition += elem.sText.getLength();
1007  if(elem.xAlternatives.is())
1008  {
1009  uno::Reference< container::XNamed > xNamed( elem.xAlternatives, uno::UNO_QUERY );
1010  OUString sServiceName;
1011  if( xNamed.is() )
1012  sServiceName = xNamed->getName();
1013  SpellErrorDescription aDesc( false, elem.xAlternatives->getWord(),
1014  elem.xAlternatives->getLocale(), elem.xAlternatives->getAlternatives(), nullptr);
1015  SfxGrabBagItem aSpellErrorDescription(EE_CHAR_GRABBAG);
1016  aSpellErrorDescription.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
1017  m_xSentenceED->SetAttrib(aSpellErrorDescription, nStartPosition, nEndPosition);
1018  }
1019  else if(elem.bIsGrammarError )
1020  {
1021  beans::PropertyValues aProperties = elem.aGrammarError.aProperties;
1022  OUString sFullCommentURL;
1023  sal_Int32 i = 0;
1024  while ( sFullCommentURL.isEmpty() && i < aProperties.getLength() )
1025  {
1026  if ( aProperties[i].Name == "FullCommentURL" )
1027  {
1028  uno::Any aValue = aProperties[i].Value;
1029  aValue >>= sFullCommentURL;
1030  }
1031  ++i;
1032  }
1033 
1034  SpellErrorDescription aDesc( true,
1035  elem.sText,
1036  LanguageTag::convertToLocale( elem.eLanguage ),
1037  elem.aGrammarError.aSuggestions,
1038  elem.xGrammarChecker,
1039  &elem.sDialogTitle,
1040  &elem.aGrammarError.aFullComment,
1041  &elem.aGrammarError.aRuleIdentifier,
1042  &sFullCommentURL );
1043 
1044  SfxGrabBagItem aSpellErrorDescriptionItem(EE_CHAR_GRABBAG);
1045  aSpellErrorDescriptionItem.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
1046  m_xSentenceED->SetAttrib(aSpellErrorDescriptionItem, nStartPosition, nEndPosition);
1047  }
1048 
1049  if (elem.bIsField)
1050  m_xSentenceED->SetAttrib(SvxBackgroundColorItem(COL_LIGHTGRAY, EE_CHAR_BKGCOLOR), nStartPosition, nEndPosition);
1051  m_xSentenceED->SetAttrib(SvxLanguageItem(elem.eLanguage, EE_CHAR_LANGUAGE), nStartPosition, nEndPosition);
1052  nStartPosition = nEndPosition;
1053  }
1054  }
1055  //the edit field needs to be modified to apply the change from the ApplyChangeAllList
1056  if(!bHasReplaced)
1057  m_xSentenceED->ClearModifyFlag();
1058  m_xSentenceED->ResetUndo();
1059  m_xUndoPB->set_sensitive(false);
1060  bRet = nStartPosition > 0;
1061  }
1062  return bRet;
1063 }
1064 /*-------------------------------------------------------------------------
1065  replace errors that have a replacement in the ChangeAllList
1066  returns false if the result doesn't contain errors after the replacement
1067  -----------------------------------------------------------------------*/
1068 bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions& rSentence, bool &bHasReplaced)
1069 {
1070  bHasReplaced = false;
1071  bool bRet = true;
1072  Reference<XDictionary> xChangeAll = LinguMgr::GetChangeAllList();
1073  if(!xChangeAll->getCount())
1074  return bRet;
1075  bRet = false;
1076  for (auto & elem : rSentence)
1077  {
1078  if(elem.xAlternatives.is())
1079  {
1080  const OUString &rString = elem.sText;
1081 
1082  Reference<XDictionaryEntry> xEntry = xChangeAll->getEntry(rString);
1083 
1084  if(xEntry.is())
1085  {
1086  elem.sText = getDotReplacementString(rString, xEntry->getReplacementText());
1087  elem.xAlternatives = nullptr;
1088  bHasReplaced = true;
1089  }
1090  else
1091  bRet = true;
1092  }
1093  else if( elem.bIsGrammarError )
1094  bRet = true;
1095  }
1096  return bRet;
1097 }
1098 
1100  : m_pSpellDialog(nullptr)
1101  , m_pToolbar(nullptr)
1102  , m_nErrorStart(0)
1103  , m_nErrorEnd(0)
1104  , m_bIsUndoEditMode(false)
1105 {
1106 }
1107 
1109 {
1110  Size aSize(pDrawingArea->get_approximate_digit_width() * 60,
1111  pDrawingArea->get_text_height() * 6);
1112  pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
1113  WeldEditView::SetDrawingArea(pDrawingArea);
1114 }
1115 
1117 {
1118 }
1119 
1120 namespace
1121 {
1122  const EECharAttrib* FindCharAttrib(int nStartPosition, int nEndPosition, sal_uInt16 nWhich, std::vector<EECharAttrib>& rAttribList)
1123  {
1124  for (const auto& rTextAtr : rAttribList)
1125  {
1126  if (rTextAtr.pAttr->Which() != nWhich)
1127  continue;
1128  if (rTextAtr.nStart <= nStartPosition && rTextAtr.nEnd >= nEndPosition)
1129  {
1130  return &rTextAtr;
1131  }
1132  }
1133 
1134  return nullptr;
1135  }
1136 
1137  void ExtractErrorDescription(const EECharAttrib& rEECharAttrib, SpellErrorDescription& rSpellErrorDescription)
1138  {
1139  css::uno::Sequence<css::uno::Any> aSequence;
1140  static_cast<const SfxGrabBagItem*>(rEECharAttrib.pAttr)->GetGrabBag().find("SpellErrorDescription")->second >>= aSequence;
1141  rSpellErrorDescription.fromSequence(aSequence);
1142  }
1143 }
1144 
1145 /*-------------------------------------------------------------------------
1146  The selection before inputting a key may have a range or not
1147  and it may be inside or outside of field or error attributes.
1148  A range may include the attribute partially, completely or together
1149  with surrounding text. It may also contain more than one attribute
1150  or no attribute at all.
1151  Depending on this starting conditions some actions are necessary:
1152  Attempts to delete a field are only allowed if the selection is the same
1153  as the field's selection. Otherwise the field has to be selected and the key
1154  input action has to be skipped.
1155  Input of text at the start of the field requires the field attribute to be
1156  corrected - it is not allowed to grow.
1157 
1158  In case of errors the appending of text should grow the error attribute because
1159  that is what the user usually wants to do.
1160 
1161  Backspace at the start of the attribute requires to find out if a field ends
1162  directly in front of the cursor position. In case of a field this attribute has to be
1163  selected otherwise the key input method is allowed.
1164 
1165  All changes outside of the error attributes switch the dialog mode to a "Undo edit" state that
1166  removes all visible attributes and switches off further attribute checks.
1167  Undo in this restarts the dialog with a current sentence newly presented.
1168  All changes to the sentence are undone including the ones before the "Undo edit state" has been reached
1169 
1170  We end up with 9 types of selection
1171  1 (LEFT_NO) - no range, start of attribute - can also be 3 at the same time
1172  2 (INSIDE_NO) - no range, inside of attribute
1173  3 (RIGHT_NO) - no range, end of attribute - can also be 1 at the same time
1174  4 (FULL) - range, same as attribute
1175  5 (INSIDE_YES) - range, inside of the attribute
1176  6 (BRACE)- range, from outside of the attribute to the inside or
1177  including the complete attribute and something outside,
1178  maybe more than one attribute
1179  7 (OUTSIDE_NO) - no range, not at an attribute
1180  8 (OUTSIDE_YES) - range, completely outside of all attributes
1181 
1182  What has to be done depending on the attribute type involved
1183  possible actions: UE - Undo edit mode
1184  CO - Continue, no additional action is required
1185  FS - Field has to be completely selected
1186  EX - The attribute has to be expanded to include the added text
1187 
1188  1 - backspace delete any other
1189  UE on field FS on error CO on field FS on error CO
1190 
1191  2 - on field FS on error C
1192  3 - backspace delete any other
1193  on field FS on error CO UE on field UE on error EX
1194 
1195  if 1 and 3 happen to apply both then backspace and other handling is 1 delete is 3
1196 
1197  4 - on field UE and on error CO
1198  5 - on field FS and on error CO
1199  6 - on field FS and on error UE
1200  7 - UE
1201  8 - UE
1202  -----------------------------------------------------------------------*/
1203 #define INVALID 0
1204 #define LEFT_NO 1
1205 #define INSIDE_NO 2
1206 #define RIGHT_NO 3
1207 #define FULL 4
1208 #define INSIDE_YES 5
1209 #define BRACE 6
1210 #define OUTSIDE_NO 7
1211 #define OUTSIDE_YES 8
1212 
1213 #define ACTION_UNDOEDIT 0
1214 #define ACTION_CONTINUE 1
1215 #define ACTION_SELECTFIELD 2
1216 #define ACTION_EXPAND 3
1217 
1219 {
1220  if (rKeyEvt.GetKeyCode().GetCode() == KEY_TAB)
1221  return false;
1222 
1223  bool bConsumed = false;
1224 
1225  bool bChange = TextEngine::DoesKeyChangeText( rKeyEvt );
1226  if (bChange && !IsUndoEditMode())
1227  {
1228  bConsumed = true;
1229 
1230  ESelection aCurrentSelection(m_xEditView->GetSelection());
1231  aCurrentSelection.Adjust();
1232 
1233  //determine if the selection contains a field
1234  bool bHasFieldLeft = false;
1235  bool bHasErrorLeft = false;
1236 
1237  bool bHasRange = aCurrentSelection.HasRange();
1238  sal_uInt8 nSelectionType = 0; // invalid type!
1239 
1240  std::vector<EECharAttrib> aAttribList;
1241  m_xEditEngine->GetCharAttribs(0, aAttribList);
1242 
1243  auto nCursor = aCurrentSelection.nStartPos;
1244  const EECharAttrib* pBackAttr = FindCharAttrib(nCursor, nCursor, EE_CHAR_BKGCOLOR, aAttribList);
1245  const EECharAttrib* pErrorAttr = FindCharAttrib(nCursor, nCursor, EE_CHAR_GRABBAG, aAttribList);
1246  const EECharAttrib* pBackAttrLeft = nullptr;
1247  const EECharAttrib* pErrorAttrLeft = nullptr;
1248 
1249  bool bHasField = pBackAttr != nullptr && (bHasRange || pBackAttr->nEnd > nCursor);
1250  bool bHasError = pErrorAttr != nullptr && (bHasRange || pErrorAttr->nEnd > nCursor);
1251  if (bHasRange)
1252  {
1253  if (pBackAttr &&
1254  pBackAttr->nStart == aCurrentSelection.nStartPos &&
1255  pBackAttr->nEnd == aCurrentSelection.nEndPos)
1256  {
1257  nSelectionType = FULL;
1258  }
1259  else if (pErrorAttr &&
1260  pErrorAttr->nStart <= aCurrentSelection.nStartPos &&
1261  pErrorAttr->nEnd >= aCurrentSelection.nEndPos)
1262  {
1263  nSelectionType = INSIDE_YES;
1264  }
1265  else
1266  {
1267  nSelectionType = bHasField||bHasError ? BRACE : OUTSIDE_NO;
1268  while (nCursor < aCurrentSelection.nEndPos)
1269  {
1270  ++nCursor;
1271  const EECharAttrib* pIntBackAttr = FindCharAttrib(nCursor, nCursor, EE_CHAR_BKGCOLOR, aAttribList);
1272  const EECharAttrib* pIntErrorAttr = FindCharAttrib(nCursor, nCursor, EE_CHAR_GRABBAG, aAttribList);
1273  //if any attr has been found then BRACE
1274  if (pIntBackAttr || pIntErrorAttr)
1275  nSelectionType = BRACE;
1276  //the field has to be selected
1277  if (pIntBackAttr && !pBackAttr)
1278  pBackAttr = pIntBackAttr;
1279  bHasField |= pIntBackAttr != nullptr;
1280  }
1281  }
1282  }
1283  else
1284  {
1285  //no range selection: then 1 2 3 and 8 are possible
1286  const EECharAttrib* pCurAttr = pBackAttr ? pBackAttr : pErrorAttr;
1287  if (pCurAttr)
1288  {
1289  nSelectionType = pCurAttr->nStart == aCurrentSelection.nStartPos ?
1290  LEFT_NO : pCurAttr->nEnd == aCurrentSelection.nEndPos ? RIGHT_NO : INSIDE_NO;
1291  }
1292  else
1293  nSelectionType = OUTSIDE_NO;
1294 
1295  bHasFieldLeft = pBackAttr && pBackAttr->nEnd == nCursor;
1296  if(bHasFieldLeft)
1297  {
1298  pBackAttrLeft = pBackAttr;
1299  pBackAttr = nullptr;
1300  }
1301  bHasErrorLeft = pErrorAttr && pErrorAttr->nEnd == nCursor;
1302  if(bHasErrorLeft)
1303  {
1304  pErrorAttrLeft = pErrorAttr;
1305  pErrorAttr = nullptr;
1306  }
1307 
1308  //check previous position if this exists
1309  //that is a redundant in the case the attribute found above already is on the left cursor side
1310  //but it's o.k. for two errors/fields side by side
1311  if (nCursor)
1312  {
1313  --nCursor;
1314  pBackAttrLeft = FindCharAttrib(nCursor, nCursor, EE_CHAR_BKGCOLOR, aAttribList);
1315  pErrorAttrLeft = FindCharAttrib(nCursor, nCursor, EE_CHAR_GRABBAG, aAttribList);
1316  bHasFieldLeft = pBackAttrLeft !=nullptr;
1317  bHasErrorLeft = pErrorAttrLeft != nullptr;
1318  ++nCursor;
1319  }
1320  }
1321  //Here we have to determine if the error found is the one currently active
1322  bool bIsErrorActive = (pErrorAttr && pErrorAttr->nStart == m_nErrorStart) ||
1323  (pErrorAttrLeft && pErrorAttrLeft->nStart == m_nErrorStart);
1324 
1325  SAL_WARN_IF(
1326  nSelectionType == INVALID, "cui.dialogs",
1327  "selection type not set");
1328 
1329  const vcl::KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
1330  bool bDelete = rKeyCode.GetCode() == KEY_DELETE;
1331  bool bBackspace = rKeyCode.GetCode() == KEY_BACKSPACE;
1332 
1333  sal_Int8 nAction = ACTION_CONTINUE;
1334  switch(nSelectionType)
1335  {
1336 // 1 - backspace delete any other
1337 // UE on field FS on error CO on field FS on error CO
1338  case LEFT_NO :
1339  if(bBackspace)
1340  {
1341  nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
1342  //to force the use of pBackAttrLeft
1343  pBackAttr = nullptr;
1344  }
1345  else if(bDelete)
1346  nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1347  else
1348  nAction = bHasError && !nCursor ? ACTION_CONTINUE :
1349  bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1350  break;
1351 // 2 - on field FS on error C
1352  case INSIDE_NO :
1353  nAction = bHasField ? ACTION_SELECTFIELD :
1354  bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1355  break;
1356 // 3 - backspace delete any other
1357 // on field FS on error CO UE on field UE on error EX
1358  case RIGHT_NO :
1359  if(bBackspace)
1360  nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1361  else if(bDelete)
1362  nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1363  else
1364  nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
1365  bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT;
1366  break;
1367 // 4 - on field UE and on error CO
1368  case FULL :
1369  nAction = ACTION_UNDOEDIT;
1370  break;
1371 // 5 - on field FS and on error CO
1372  case INSIDE_YES :
1373  nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1374  break;
1375 // 6 - on field FS and on error UE
1376  case BRACE :
1377  nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
1378  break;
1379 // 7 - UE
1380 // 8 - UE
1381  case OUTSIDE_NO :
1382  case OUTSIDE_YES:
1383  nAction = ACTION_UNDOEDIT;
1384  break;
1385  }
1386  //save the current paragraph
1387  sal_Int32 nCurrentLen = m_xEditEngine->GetText().getLength();
1388  if (nAction != ACTION_SELECTFIELD)
1389  {
1390  m_xEditView->PostKeyEvent(rKeyEvt);
1391  }
1392  else
1393  {
1394  const EECharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft;
1395  if (pCharAttr)
1396  m_xEditView->SetSelection(ESelection(0, pCharAttr->nStart, 0, pCharAttr->nEnd));
1397  }
1398  if(nAction == ACTION_EXPAND)
1399  {
1400  DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error");
1401  //text has been added on the right and only the 'error attribute has to be corrected
1402  if (pErrorAttrLeft)
1403  {
1404  SpellErrorDescription aSpellErrorDescription;
1405  ExtractErrorDescription(*pErrorAttrLeft, aSpellErrorDescription);
1406 
1407  std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrLeft->pAttr->Clone());
1408  sal_Int32 nStart = pErrorAttrLeft->nStart;
1409  sal_Int32 nEnd = pErrorAttrLeft->nEnd + 1;
1410  m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
1411  SetAttrib(*xNewError, nStart, nEnd);
1412  //only active errors move the mark
1413  if (bIsErrorActive)
1414  {
1415  bool bGrammar = aSpellErrorDescription.bIsGrammarError;
1416  MoveErrorMarkTo(nStart, nEnd, bGrammar);
1417  }
1418  }
1419  //text has been added on the left then the error attribute has to be expanded and the
1420  //field attribute on the right - if any - has to be contracted
1421  else if (pErrorAttr)
1422  {
1423  SpellErrorDescription aSpellErrorDescription;
1424  ExtractErrorDescription(*pErrorAttr, aSpellErrorDescription);
1425 
1426  //determine the change
1427  sal_Int32 nAddedChars = m_xEditEngine->GetText().getLength() - nCurrentLen;
1428 
1429  std::unique_ptr<SfxPoolItem> xNewError(pErrorAttr->pAttr->Clone());
1430  sal_Int32 nStart = pErrorAttr->nStart + nAddedChars;
1431  sal_Int32 nEnd = pErrorAttr->nEnd + nAddedChars;
1432  m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
1433  nStart = pErrorAttr->nStart;
1434  SetAttrib(*xNewError, nStart, nEnd);
1435  //only if the error is active the mark is moved here
1436  if (bIsErrorActive)
1437  {
1438  bool bGrammar = aSpellErrorDescription.bIsGrammarError;
1439  MoveErrorMarkTo(nStart, nEnd, bGrammar);
1440  }
1441  xNewError.reset();
1442 
1443  if (pBackAttrLeft)
1444  {
1445  std::unique_ptr<SfxPoolItem> xNewBack(pBackAttrLeft->pAttr->Clone());
1446  sal_Int32 _nStart = pBackAttrLeft->nStart + nAddedChars;
1447  sal_Int32 _nEnd = pBackAttrLeft->nEnd + nAddedChars;
1448  m_xEditEngine->RemoveAttribs(ESelection(0, _nStart, 0, _nEnd), false, EE_CHAR_BKGCOLOR);
1449  _nStart = pBackAttrLeft->nStart;
1450  SetAttrib(*xNewBack, _nStart, _nEnd);
1451  }
1452  }
1453  }
1454  else if(nAction == ACTION_UNDOEDIT)
1455  {
1456  SetUndoEditMode(true);
1457  }
1458  //make sure the error positions are correct after text changes
1459  //the old attribute may have been deleted
1460  //all changes inside of the current error leave the error attribute at the current
1461  //start position
1462  if (!IsUndoEditMode() && bIsErrorActive)
1463  {
1464  const EECharAttrib* pFontColor = FindCharAttrib(nCursor, nCursor, EE_CHAR_COLOR, aAttribList);
1465  const EECharAttrib* pErrorAttrib = FindCharAttrib(m_nErrorStart, m_nErrorStart, EE_CHAR_GRABBAG, aAttribList);
1466  if (pFontColor && pErrorAttrib)
1467  {
1468  m_nErrorStart = pFontColor->nStart;
1469  m_nErrorEnd = pFontColor->nEnd;
1470  if (pErrorAttrib->nStart != m_nErrorStart || pErrorAttrib->nEnd != m_nErrorEnd)
1471  {
1472  std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrib->pAttr->Clone());
1473  assert(pErrorAttr);
1474  m_xEditEngine->RemoveAttribs(ESelection(0, pErrorAttr->nStart, 0, pErrorAttr->nEnd), false, EE_CHAR_GRABBAG);
1475  SetAttrib(*xNewError, m_nErrorStart, m_nErrorEnd);
1476  }
1477  }
1478  }
1479  //this is not a modification anymore
1480  if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
1481  CallModifyLink();
1482  }
1483  else
1484  bConsumed = m_xEditView->PostKeyEvent(rKeyEvt);
1485 
1486  return bConsumed;
1487 }
1488 
1490 {
1491  m_pToolbar = pToolbar;
1493 }
1494 
1495 IMPL_LINK(SentenceEditWindow_Impl, ToolbarHdl, const OString&, rCurItemId, void)
1496 {
1497  if (rCurItemId == "paste")
1498  {
1499  m_xEditView->Paste();
1500  CallModifyLink();
1501  }
1502  else if (rCurItemId == "insert")
1503  {
1505  {
1506  OUString aChars = Edit::GetGetSpecialCharsFunction()(GetDrawingArea(), m_xEditEngine->GetStandardFont(0));
1507  if (!aChars.isEmpty())
1508  {
1509  ESelection aCurrentSelection(m_xEditView->GetSelection());
1510  m_xEditEngine->QuickInsertText(aChars, aCurrentSelection);
1511  CallModifyLink();
1512  }
1513  }
1514  }
1515 }
1516 
1517 bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError, const css::uno::Reference<css::linguistic2::XSpellChecker1>& xSpell )
1518 {
1519  if (bIgnoreCurrentError)
1520  m_aIgnoreErrorsAt.insert( m_nErrorStart );
1521 
1522  const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);
1523 
1524  if (m_nErrorEnd >= nTextLen - 1)
1525  return false;
1526  //if it's not already modified the modified flag has to be reset at the end of the marking
1527  bool bModified = IsModified();
1528  bool bRet = false;
1529  const sal_Int32 nOldErrorStart = m_nErrorStart;
1530  const sal_Int32 nOldErrorEnd = m_nErrorEnd;
1531 
1532  //create a cursor behind the end of the last error
1533  //- or at 0 at the start of the sentence
1534  sal_Int32 nCursor(m_nErrorEnd ? m_nErrorEnd + 1 : 0);
1535 
1536  //search for SpellErrorDescription
1537  SpellErrorDescription aSpellErrorDescription;
1538 
1539  std::vector<EECharAttrib> aAttribList;
1540  m_xEditEngine->GetCharAttribs(0, aAttribList);
1541 
1542  //iterate over the text and search for the next error that maybe has
1543  //to be replace by a ChangeAllList replacement
1544  bool bGrammarError = false;
1545  while (nCursor < nTextLen)
1546  {
1547  const SpellErrorDescription* pSpellErrorDescription = nullptr;
1548  const EECharAttrib* pEECharAttrib = nullptr;
1549 
1550  sal_Int32 nMinPos = nTextLen + 1;
1551  for (const auto& rTextAtr : aAttribList)
1552  {
1553  if (rTextAtr.pAttr->Which() != EE_CHAR_GRABBAG)
1554  continue;
1555  if (rTextAtr.nEnd > nCursor && rTextAtr.nStart < nMinPos)
1556  {
1557  nMinPos = rTextAtr.nStart;
1558  pEECharAttrib = &rTextAtr;
1559  }
1560  }
1561 
1562  if (pEECharAttrib)
1563  {
1564  ExtractErrorDescription(*pEECharAttrib, aSpellErrorDescription);
1565 
1566  bGrammarError = aSpellErrorDescription.bIsGrammarError;
1567  m_nErrorStart = pEECharAttrib->nStart;
1568  m_nErrorEnd = pEECharAttrib->nEnd;
1569 
1570  pSpellErrorDescription = &aSpellErrorDescription;
1571  }
1572 
1573  nCursor = std::max(nCursor, nMinPos); // move forward if possible
1574 
1575  // maybe the error found here is already in the ChangeAllList and has to be replaced
1576  Reference<XDictionary> xChangeAll = LinguMgr::GetChangeAllList();
1577  Reference<XDictionaryEntry> xEntry;
1578 
1579  if (xChangeAll->getCount() && pSpellErrorDescription &&
1580  (xEntry = xChangeAll->getEntry( pSpellErrorDescription->sErrorText )).is())
1581  {
1582  OUString sReplacement(getDotReplacementString(GetErrorText(), xEntry->getReplacementText()));
1583 
1584  int nLenChange = ChangeMarkedWord(sReplacement, LanguageTag::convertToLanguageType(pSpellErrorDescription->aLocale));
1585 
1586  nCursor += sReplacement.getLength();
1587 
1588  if (nLenChange)
1589  m_xEditEngine->GetCharAttribs(0, aAttribList);
1590  // maybe the error found here is already added to the dictionary and has to be ignored
1591  }
1592  else if(pSpellErrorDescription && !bGrammarError &&
1593  xSpell->isValid(GetErrorText(),
1594  static_cast<sal_uInt16>(LanguageTag::convertToLanguageType( pSpellErrorDescription->aLocale )),
1596  {
1597  ++nCursor;
1598  }
1599  else
1600  break;
1601  }
1602 
1603  //if an attrib has been found search for the end of the error string
1604  if (nCursor < nTextLen)
1605  {
1606  MoveErrorMarkTo(nCursor, m_nErrorEnd, bGrammarError);
1607  bRet = true;
1608  //add an undo action
1609  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
1610  SPELLUNDO_CHANGE_NEXTERROR, GetSpellDialog()->aDialogUndoLink));
1611  pAction->SetErrorMove(nOldErrorStart, nOldErrorEnd);
1612 
1613  if (GetErrorDescription(aSpellErrorDescription, nOldErrorStart))
1614  {
1615  pAction->SetErrorLanguageSelected(aSpellErrorDescription.aSuggestions.hasElements() &&
1616  LanguageTag(aSpellErrorDescription.aLocale).getLanguageType() == GetSpellDialog()->m_xLanguageLB->get_active_id());
1617  }
1618  else
1619  pAction->SetErrorLanguageSelected(false);
1620 
1621  AddUndoAction(std::move(pAction));
1622  }
1623  else
1624  m_nErrorStart = m_nErrorEnd = nTextLen;
1625  if( !bModified )
1626  ClearModifyFlag();
1627  SpellDialog* pSpellDialog = GetSpellDialog();
1628  pSpellDialog->m_xIgnorePB->set_sensitive(bRet);
1629  pSpellDialog->m_xIgnoreAllPB->set_sensitive(bRet);
1630  pSpellDialog->m_xAutoCorrPB->set_sensitive(bRet);
1631  pSpellDialog->m_xAddToDictMB->set_sensitive(bRet);
1632  pSpellDialog->m_xAddToDictPB->set_sensitive(bRet);
1633  return bRet;
1634 }
1635 
1636 void SentenceEditWindow_Impl::MoveErrorMarkTo(sal_Int32 nStart, sal_Int32 nEnd, bool bGrammarError)
1637 {
1638  ESelection aAll(0, 0, 0, EE_TEXTPOS_ALL);
1639  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_COLOR);
1640  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT);
1641  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CJK);
1642  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CTL);
1643 
1644  SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
1645  aSet.Put(SvxColorItem(bGrammarError ? COL_LIGHTBLUE : COL_LIGHTRED, EE_CHAR_COLOR));
1649 
1650  m_xEditEngine->QuickSetAttribs(aSet, ESelection(0, nStart, 0, nEnd));
1651  // so the editview will autoscroll to make this visible
1652  m_xEditView->SetSelection(ESelection(0, nStart));
1653  Invalidate();
1654 
1655  m_nErrorStart = nStart;
1656  m_nErrorEnd = nEnd;
1657 }
1658 
1659 int SentenceEditWindow_Impl::ChangeMarkedWord(const OUString& rNewWord, LanguageType eLanguage)
1660 {
1661  std::vector<EECharAttrib> aAttribList;
1662  m_xEditEngine->GetCharAttribs(0, aAttribList);
1663 
1664  //calculate length changes
1665  auto nDiffLen = rNewWord.getLength() - m_nErrorEnd + m_nErrorStart;
1666  //Remove spell error attribute
1667  m_xEditEngine->UndoActionStart(SPELLUNDO_MOVE_ERROREND);
1668  const EECharAttrib* pErrorAttrib = FindCharAttrib(m_nErrorStart, m_nErrorStart, EE_CHAR_GRABBAG, aAttribList);
1669  DBG_ASSERT(pErrorAttrib, "no error attribute found");
1670  bool bSpellErrorDescription = false;
1671  SpellErrorDescription aSpellErrorDescription;
1672  if (pErrorAttrib)
1673  {
1674  ExtractErrorDescription(*pErrorAttrib, aSpellErrorDescription);
1675  m_xEditEngine->RemoveAttribs(ESelection(0, pErrorAttrib->nStart, 0, pErrorAttrib->nEnd), false, EE_CHAR_GRABBAG);
1676  bSpellErrorDescription = true;
1677  }
1678 
1679  const EECharAttrib* pBackAttrib = FindCharAttrib(m_nErrorStart, m_nErrorStart, EE_CHAR_BKGCOLOR, aAttribList);
1680 
1681  ESelection aSel(0, m_nErrorStart, 0, m_nErrorEnd);
1682  m_xEditEngine->QuickInsertText(rNewWord, aSel);
1683 
1684  const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);
1685 
1686  if (nDiffLen)
1687  m_xEditEngine->GetCharAttribs(0, aAttribList);
1688 
1689  if (!m_nErrorStart)
1690  {
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 EECharAttrib* pLangAttrib = FindCharAttrib(m_nErrorEnd, m_nErrorEnd, EE_CHAR_LANGUAGE, aAttribList);
1695 
1696  if (pLangAttrib && !pLangAttrib->nStart && pLangAttrib->nEnd == nTextLen)
1697  {
1698  LanguageType eNewLanguage = static_cast<const SvxLanguageItem*>(pLangAttrib->pAttr)->GetLanguage();
1699  m_xEditEngine->RemoveAttribs(ESelection(0, pLangAttrib->nStart, 0, pLangAttrib->nEnd), false, EE_CHAR_LANGUAGE);
1700  SetAttrib(SvxLanguageItem(eNewLanguage, EE_CHAR_LANGUAGE), m_nErrorEnd + nDiffLen, nTextLen);
1701  }
1702  }
1703 
1704  // undo expanded attributes!
1705  if (pBackAttrib && pBackAttrib->nStart < m_nErrorStart && pBackAttrib->nEnd == m_nErrorEnd + nDiffLen)
1706  {
1707  std::unique_ptr<SfxPoolItem> xNewBackground(pBackAttrib->pAttr->Clone());
1708  const sal_Int32 nStart = pBackAttrib->nStart;
1709 
1710  m_xEditEngine->RemoveAttribs(ESelection(0, pBackAttrib->nStart, 0, pBackAttrib->nEnd), false, EE_CHAR_BKGCOLOR);
1711 
1712  SetAttrib(*xNewBackground, nStart, m_nErrorStart);
1713  }
1714  m_xEditEngine->SetModified();
1715 
1716  //adjust end position
1717  long nEndTemp = m_nErrorEnd;
1718  nEndTemp += nDiffLen;
1719  m_nErrorEnd = static_cast<sal_Int32>(nEndTemp);
1720 
1721  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
1722  SPELLUNDO_MOVE_ERROREND, GetSpellDialog()->aDialogUndoLink));
1723  pAction->SetOffset(nDiffLen);
1724  AddUndoAction(std::move(pAction));
1725  if (bSpellErrorDescription)
1726  {
1727  SfxGrabBagItem aSpellErrorDescriptionItem(EE_CHAR_GRABBAG);
1728  aSpellErrorDescriptionItem.GetGrabBag()["SpellErrorDescription"] <<= aSpellErrorDescription.toSequence();
1729  SetAttrib(aSpellErrorDescriptionItem, m_nErrorStart, m_nErrorEnd);
1730  }
1731  SetAttrib(SvxLanguageItem(eLanguage, EE_CHAR_LANGUAGE), m_nErrorStart, m_nErrorEnd);
1732  m_xEditEngine->UndoActionEnd();
1733 
1734  Invalidate();
1735 
1736  return nDiffLen;
1737 }
1738 
1740 {
1741  return m_xEditEngine->GetText(ESelection(0, m_nErrorStart, 0, m_nErrorEnd));
1742 }
1743 
1744 bool SentenceEditWindow_Impl::GetErrorDescription(SpellErrorDescription& rSpellErrorDescription, sal_Int32 nPosition)
1745 {
1746  std::vector<EECharAttrib> aAttribList;
1747  m_xEditEngine->GetCharAttribs(0, aAttribList);
1748 
1749  if (const EECharAttrib* pEECharAttrib = FindCharAttrib(nPosition, nPosition, EE_CHAR_GRABBAG, aAttribList))
1750  {
1751  ExtractErrorDescription(*pEECharAttrib, rSpellErrorDescription);
1752  return true;
1753  }
1754 
1755  return false;
1756 }
1757 
1759 {
1760  return GetErrorDescription(rSpellErrorDescription, m_nErrorStart);
1761 }
1762 
1764 {
1765  SpellErrorDescription aSpellErrorDescription;
1766  if (GetErrorDescription(aSpellErrorDescription, m_nErrorStart))
1767  {
1768  if (aSpellErrorDescription.sErrorText != GetErrorText() )
1769  ChangeMarkedWord(aSpellErrorDescription.sErrorText, LanguageTag::convertToLanguageType(aSpellErrorDescription.aLocale));
1770  }
1771 }
1772 
1773 void SentenceEditWindow_Impl::SetAlternatives( const Reference< XSpellAlternatives>& xAlt )
1774 {
1775  OUString aWord;
1776  lang::Locale aLocale;
1777  uno::Sequence< OUString > aAlts;
1778  OUString sServiceName;
1779  if (xAlt.is())
1780  {
1781  aWord = xAlt->getWord();
1782  aLocale = xAlt->getLocale();
1783  aAlts = xAlt->getAlternatives();
1784  uno::Reference< container::XNamed > xNamed( xAlt, uno::UNO_QUERY );
1785  if (xNamed.is())
1786  sServiceName = xNamed->getName();
1787  }
1788  SpellErrorDescription aDesc( false, aWord, aLocale, aAlts, nullptr);
1789  SfxGrabBagItem aSpellErrorDescription(EE_CHAR_GRABBAG);
1790  aSpellErrorDescription.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
1791  SetAttrib(aSpellErrorDescription, m_nErrorStart, m_nErrorEnd);
1792 }
1793 
1794 void SentenceEditWindow_Impl::SetAttrib(const SfxPoolItem& rItem, sal_Int32 nStart, sal_Int32 nEnd)
1795 {
1796  SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
1797  aSet.Put(rItem);
1798  m_xEditEngine->QuickSetAttribs(aSet, ESelection(0, nStart, 0, nEnd));
1799  Invalidate();
1800 }
1801 
1802 void SentenceEditWindow_Impl::SetText( const OUString& rStr )
1803 {
1804  m_nErrorStart = m_nErrorEnd = 0;
1805  m_xEditEngine->SetText(rStr);
1806 }
1807 
1809 {
1810  sal_Int32 nPosition;
1812 
1813  LanguagePosition_Impl(sal_Int32 nPos, LanguageType eLang) :
1814  nPosition(nPos),
1815  eLanguage(eLang)
1816  {}
1817 };
1818 typedef std::vector<LanguagePosition_Impl> LanguagePositions_Impl;
1819 
1821  LanguagePositions_Impl& rBreakPositions, sal_Int32 nInsert, LanguageType eLanguage)
1822 {
1823  LanguagePositions_Impl::iterator aStart = rBreakPositions.begin();
1824  while(aStart != rBreakPositions.end())
1825  {
1826  if(aStart->nPosition == nInsert)
1827  {
1828  //the language of following starts has to overwrite
1829  //the one of previous ends
1830  aStart->eLanguage = eLanguage;
1831  return;
1832  }
1833  else if(aStart->nPosition > nInsert)
1834  {
1835 
1836  rBreakPositions.insert(aStart, LanguagePosition_Impl(nInsert, eLanguage));
1837  return;
1838  }
1839  else
1840  ++aStart;
1841  }
1842  rBreakPositions.emplace_back(nInsert, eLanguage);
1843 }
1844 
1845 /*-------------------------------------------------------------------------
1846  Returns the text in spell portions. Each portion contains text with an
1847  equal language and attribute. The spell alternatives are empty.
1848  -----------------------------------------------------------------------*/
1850 {
1851  svx::SpellPortions aRet;
1852 
1853  const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);
1854 
1855  std::vector<EECharAttrib> aAttribList;
1856  m_xEditEngine->GetCharAttribs(0, aAttribList);
1857 
1858  if (nTextLen)
1859  {
1860  int nCursor(0);
1861  LanguagePositions_Impl aBreakPositions;
1862  const EECharAttrib* pLastLang = nullptr;
1863  const EECharAttrib* pLastError = nullptr;
1865  const EECharAttrib* pError = nullptr;
1866  while (nCursor < nTextLen)
1867  {
1868  const EECharAttrib* pLang = FindCharAttrib(nCursor, nCursor, EE_CHAR_LANGUAGE, aAttribList);
1869  if(pLang && pLang != pLastLang)
1870  {
1871  eLang = static_cast<const SvxLanguageItem*>(pLang->pAttr)->GetLanguage();
1872  lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->nStart, eLang);
1873  lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->nEnd, eLang);
1874  pLastLang = pLang;
1875  }
1876  pError = FindCharAttrib(nCursor, nCursor, EE_CHAR_GRABBAG, aAttribList);
1877  if (pError && pLastError != pError)
1878  {
1879  lcl_InsertBreakPosition_Impl(aBreakPositions, pError->nStart, eLang);
1880  lcl_InsertBreakPosition_Impl(aBreakPositions, pError->nEnd, eLang);
1881  pLastError = pError;
1882 
1883  }
1884  ++nCursor;
1885  }
1886 
1887  if (aBreakPositions.empty())
1888  {
1889  //if all content has been overwritten the attributes may have been removed, too
1890  svx::SpellPortion aPortion1;
1892 
1893  aPortion1.sText = m_xEditEngine->GetText(ESelection(0, 0, 0, nTextLen));
1894 
1895  aRet.push_back(aPortion1);
1896  }
1897  else
1898  {
1899  LanguagePositions_Impl::iterator aStart = aBreakPositions.begin();
1900  //start should always be Null
1901  eLang = aStart->eLanguage;
1902  sal_Int32 nStart = aStart->nPosition;
1903  DBG_ASSERT(!nStart, "invalid start position - language attribute missing?");
1904  ++aStart;
1905 
1906  while(aStart != aBreakPositions.end())
1907  {
1908  svx::SpellPortion aPortion1;
1909  aPortion1.eLanguage = eLang;
1910 
1911  aPortion1.sText = m_xEditEngine->GetText(ESelection(0, nStart, 0, aStart->nPosition));
1912 
1913  bool bIsIgnoreError = m_aIgnoreErrorsAt.find( nStart ) != m_aIgnoreErrorsAt.end();
1914  if( bIsIgnoreError )
1915  {
1916  aPortion1.bIgnoreThisError = true;
1917  }
1918  aRet.push_back(aPortion1);
1919  nStart = aStart->nPosition;
1920  eLang = aStart->eLanguage;
1921  ++aStart;
1922  }
1923  }
1924 
1925  // quick partly fix of #i71318. Correct fix needs to patch the EditEngine itself...
1926  // this one will only prevent text from disappearing. It may to not have the
1927  // correct language and will probably not spell checked...
1928  const sal_uInt32 nPara = m_xEditEngine->GetParagraphCount();
1929  if (nPara > 1)
1930  {
1931  OUStringBuffer aLeftOverText;
1932  for (sal_uInt32 i = 1; i < nPara; ++i)
1933  {
1934  aLeftOverText.append("\x0a"); // the manual line break...
1935  aLeftOverText.append(m_xEditEngine->GetText(i));
1936  }
1937  if (pError)
1938  { // we need to add a new portion containing the left-over text
1939  svx::SpellPortion aPortion2;
1940  aPortion2.eLanguage = eLang;
1941  aPortion2.sText = aLeftOverText.makeStringAndClear();
1942  aRet.push_back( aPortion2 );
1943  }
1944  else
1945  { // we just need to append the left-over text to the last portion (which had no errors)
1946  aRet[ aRet.size() - 1 ].sText += aLeftOverText;
1947  }
1948  }
1949  }
1950 
1951  return aRet;
1952 }
1953 
1955 {
1956  SfxUndoManager& rUndoMgr = m_xEditEngine->GetUndoManager();
1957  DBG_ASSERT(GetUndoActionCount(), "no undo actions available" );
1958  if(!GetUndoActionCount())
1959  return;
1960  bool bSaveUndoEdit = IsUndoEditMode();
1961  SpellUndoAction_Impl* pUndoAction;
1962  //if the undo edit mode is active then undo all changes until the UNDO_EDIT_MODE action has been found
1963  do
1964  {
1965  pUndoAction = static_cast<SpellUndoAction_Impl*>(rUndoMgr.GetUndoAction());
1966  rUndoMgr.Undo();
1967  }while(bSaveUndoEdit && SPELLUNDO_UNDO_EDIT_MODE != pUndoAction->GetId() && GetUndoActionCount());
1968 
1969  if(bSaveUndoEdit || SPELLUNDO_CHANGE_GROUP == pUndoAction->GetId())
1971 }
1972 
1974 {
1975  SfxUndoManager& rUndo = m_xEditEngine->GetUndoManager();
1976  rUndo.Clear();
1977 }
1978 
1979 void SentenceEditWindow_Impl::AddUndoAction( std::unique_ptr<SfxUndoAction> pAction )
1980 {
1981  SfxUndoManager& rUndoMgr = m_xEditEngine->GetUndoManager();
1982  rUndoMgr.AddUndoAction(std::move(pAction));
1983  GetSpellDialog()->m_xUndoPB->set_sensitive(true);
1984 }
1985 
1987 {
1988  return m_xEditEngine->GetUndoManager().GetUndoActionCount();
1989 }
1990 
1992 {
1993  m_xEditEngine->UndoActionStart(nId);
1994 }
1995 
1997 {
1998  m_xEditEngine->UndoActionEnd();
1999 }
2000 
2002 {
2003  // Shouldn't we always add the real signed value instead???
2004  if(nOffset > 0)
2005  m_nErrorEnd = m_nErrorEnd - static_cast<sal_Int32>(nOffset);
2006  else
2007  m_nErrorEnd = m_nErrorEnd - static_cast<sal_Int32>(-nOffset);
2008 }
2009 
2010 
2012 {
2013  DBG_ASSERT(!bSet || m_bIsUndoEditMode != bSet, "SetUndoEditMode with equal values?");
2014  m_bIsUndoEditMode = bSet;
2015  //disable all buttons except the Change
2016  SpellDialog* pSpellDialog = GetSpellDialog();
2017  weld::Widget* aControls[] =
2018  {
2019  pSpellDialog->m_xChangeAllPB.get(),
2020  pSpellDialog->m_xExplainFT.get(),
2021  pSpellDialog->m_xIgnoreAllPB.get(),
2022  pSpellDialog->m_xIgnoreRulePB.get(),
2023  pSpellDialog->m_xIgnorePB.get(),
2024  pSpellDialog->m_xSuggestionLB.get(),
2025  pSpellDialog->m_xSuggestionFT.get(),
2026  pSpellDialog->m_xLanguageFT.get(),
2027  pSpellDialog->m_xLanguageLB->get_widget(),
2028  pSpellDialog->m_xAddToDictMB.get(),
2029  pSpellDialog->m_xAddToDictPB.get(),
2030  pSpellDialog->m_xAutoCorrPB.get(),
2031  nullptr
2032  };
2033  sal_Int32 nIdx = 0;
2034  do
2035  {
2036  aControls[nIdx]->set_sensitive(false);
2037  }
2038  while(aControls[++nIdx]);
2039 
2040  //remove error marks
2041  ESelection aAll(0, 0, 0, EE_TEXTPOS_ALL);
2042  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_COLOR);
2043  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT);
2044  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CJK);
2045  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CTL);
2046  Invalidate();
2047 
2048  //put the appropriate action on the Undo-stack
2049  AddUndoAction( std::make_unique<SpellUndoAction_Impl>(
2050  SPELLUNDO_UNDO_EDIT_MODE, GetSpellDialog()->aDialogUndoLink) );
2051  pSpellDialog->m_xChangePB->set_sensitive(true);
2052 }
2053 
2054 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nEnd
SpellUndoAction_Impl(sal_uInt16 nId, const Link< SpellUndoAction_Impl &, void > &rActionLink)
SfxUndoAction * GetUndoAction(size_t nNo=0) const
css::uno::Sequence< css::uno::Any > toSequence() const
Definition: SpellAttrib.hxx:88
#define ACTION_CONTINUE
void Adjust()
std::unique_ptr< weld::Label > m_xResumeFT
#define LANGUAGE_NONE
#define BRACE
virtual bool HasGrammarChecking()
#define ACTION_EXPAND
#define KEY_BACKSPACE
std::unique_ptr< weld::Label > m_xExplainFT
virtual void GetFocus()=0
std::unique_ptr< weld::TreeView > m_xSuggestionLB
#define KEY_DELETE
#define SPELLUNDO_CHANGE_ADD_TO_DICTIONARY
Definition: SpellDialog.cxx:76
virtual void SetDrawingArea(weld::DrawingArea *pDrawingArea) override
sal_Int32 nStart
OUString m_sResumeST
std::unique_ptr< SvxLanguageBox > m_xLanguageLB
#define FULL
#define KEY_TAB
#define EE_CHAR_LANGUAGE
std::unique_ptr< weld::Label > m_xNotInDictFT
signed char sal_Int8
virtual SfxPoolItem * Clone(SfxItemPool *pPool=nullptr) const =0
LanguageType getLanguageType(bool bResolveSystem=true) const
#define SPELLUNDO_MOVE_ERROREND
Definition: SpellDialog.cxx:78
std::unique_ptr< SpellDialog_Impl > pImpl
static LanguageType convertToLanguageType(const css::lang::Locale &rLocale, bool bResolveSystem=true)
void AddToDictionaryExecute(const OString &rItemId)
IMPL_LINK_NOARG(ClassificationDialog, OnAsyncExpandHdl, void *, void)
std::unique_ptr< weld::Label > m_xSuggestionFT
css::uno::Sequence< OUString > aSuggestions
Definition: SpellAttrib.hxx:37
static std::unique_ptr< SfxTabPage > Create(weld::Container *pPage, weld::DialogController *pController, const SfxItemSet *rSet)
Definition: optlingu.cxx:903
#define SPELLUNDO_CHANGE_LANGUAGE
Definition: SpellDialog.cxx:73
#define EE_CHAR_WEIGHT_CTL
void SetTitle_Impl(LanguageType nLang)
void AddUndoAction(std::unique_ptr< SfxUndoAction > pAction)
std::set< sal_Int32 > m_aIgnoreErrorsAt
Definition: SpellDialog.hxx:52
std::unique_ptr< weld::Button > m_xOptionsPB
virtual void Deactivate() override
const SfxPoolItem * pAttr
bool GetErrorDescription(SpellErrorDescription &rSpellErrorDescription, sal_Int32 nPosition)
OUString getReplacementString() const
static css::uno::Reference< css::linguistic2::XDictionary > GetStandardDic()
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
bool GetNextSentence_Impl(bool bUseSavedSentence, bool bRechek)
Retrieves the next sentence.
sal_uInt16 GetCode() const
void ToplevelFocusChanged()
void Init(weld::Toolbar *pToolbar)
constexpr::Color COL_LIGHTRED(0xFF, 0x00, 0x00)
OUString GetErrorText() const
OUString Name
constexpr::Color COL_LIGHTGRAY(0xC0, 0xC0, 0xC0)
bool SaveDictionaries(const uno::Reference< XSearchableDictionaryList > &xDicList)
const Link< SpellUndoAction_Impl &, void > & m_rActionLink
Definition: SpellDialog.cxx:86
virtual void SetDrawingArea(weld::DrawingArea *pDrawingArea) override
virtual bool Undo()
OUString m_sIgnoreOnceST
void SetText(const OUString &rStr)
SfxApplication * SfxGetpApp()
std::unique_ptr< weld::Button > m_xIgnoreAllPB
virtual bool HasAutoCorrection()
WEIGHT_BOLD
void ToggleChildWindow(sal_uInt16)
std::unique_ptr< weld::Label > m_xNoSuggestionsFT
svx::SpellPortions CreateSpellPortions() const
std::unique_ptr< weld::Button > m_xIgnoreRulePB
std::unique_ptr< weld::Button > m_xAutoCorrPB
virtual void Deactivate() override
std::unique_ptr< weld::Button > m_xAddToDictPB
#define EE_CHAR_WEIGHT_CJK
svx::SpellDialogChildWindow & rParent
static bool DoesKeyChangeText(const KeyEvent &rKeyEvent)
static css::uno::Reference< css::linguistic2::XSearchableDictionaryList > GetDictionaryList()
std::unique_ptr< weld::Label > m_xLanguageFT
OUString GetSpellAndGrammarContextDictionaryImage(const OUString &rServiceImplName) const
#define EE_CHAR_BKGCOLOR
static css::uno::Reference< css::linguistic2::XDictionary > GetIgnoreAllList()
void UndoActionStart(sal_uInt16 nId)
virtual bool KeyInput(const KeyEvent &rKEvt) override
std::unique_ptr< weld::Button > m_xUndoPB
std::vector< SpellPortion > SpellPortions
static css::uno::Reference< css::linguistic2::XDictionary > GetChangeAllList()
sal_uInt16 GetId() const
#define INVALID
short SvxDicError(weld::Window *pParent, linguistic::DictionaryError nError)
long GetOldErrorEnd() const
virtual void Close() override
virtual void LoseFocus()=0
std::unique_ptr< weld::CheckButton > m_xCheckGrammarCB
std::unique_ptr< weld::Toolbar > m_xToolbar
virtual void AddUndoAction(std::unique_ptr< SfxUndoAction > pAction, bool bTryMerg=false)
std::unique_ptr< weld::Button > m_xIgnorePB
OUString m_sTitleSpellingGrammar
#define GROUP_MODULES
Definition: optlingu.hxx:42
std::unique_ptr< weld::LinkButton > m_xExplainLink
static css::uno::Reference< css::linguistic2::XSpellChecker1 > GetSpellChecker()
void MoveErrorEnd(long nOffset)
const Reference< XDictionary > & GetDictionary() const
#define DBG_ASSERT(sCon, aError)
bool IsEnableChangeAllPB() const
OUString m_sTitleSpelling
LanguageType GetLanguage(SwWrtShell &rSh, sal_uInt16 nLangWhichId)
std::unique_ptr< weld::Button > m_xClosePB
Link< SpellUndoAction_Impl &, void > aDialogUndoLink
static void ApplyLanguageOptions(const SfxItemSet &rSet)
Definition: treeopt.cxx:1210
LanguagePosition_Impl(sal_Int32 nPos, LanguageType eLang)
virtual void Activate() override
int i
virtual void Clear()
std::vector< LanguagePosition_Impl > LanguagePositions_Impl
std::unique_ptr< SentenceEditWindow_Impl > m_xSentenceED
size_t GetUndoActionCount() const
#define INSIDE_YES
virtual SpellPortions GetNextWrongSentence(bool bRecheck)=0
std::unique_ptr< weld::Button > m_xChangeAllPB
Object Value
void Impl_Restore(bool bUseSavedSentence)
const std::map< OUString, css::uno::Any > & GetGrabBag() const
#define EE_CHAR_COLOR
#define LANGUAGE_DONTKNOW
std::unique_ptr< EditView > m_xEditView
IMPL_LINK(ClassificationDialog, SelectClassificationHdl, weld::ComboBox &, rBox, void)
void UpdateBoxes_Impl(bool bCallFromSelectHdl=false)
static bool ApplyChangeAllList_Impl(SpellPortions &rSentence, bool &bHasReplaced)
Corrects all errors that have been selected to be changed always.
virtual ~SentenceEditWindow_Impl() override
void SvxPrepareAutoCorrect(OUString &rOldText, const OUString &rNewText)
bool IsEnableChangePB() const
Sequence< Reference< XDictionary > > aDics
Definition: SpellDialog.cxx:67
#define SPELLUNDO_ADD_IGNORE_RULE
Definition: SpellDialog.cxx:80
const OUString & GetAddedWord() const
#define ACTION_UNDOEDIT
#define SPELLUNDO_UNDO_EDIT_MODE
Definition: SpellDialog.cxx:79
void SetDictionary(const Reference< XDictionary > &xDict)
long GetOldErrorStart() const
LanguageType GetSelectedLang_Impl() const
#define SPELLUNDO_CHANGE_GROUP
Definition: SpellDialog.cxx:77
const vcl::KeyCode & GetKeyCode() const
virtual void Activate() override
OUString m_sNoSuggestionsST
void SetAlternatives(const css::uno::Reference< css::linguistic2::XSpellAlternatives > &)
static SfxViewFrame * Current()
bool GetAlternatives(SpellErrorDescription &rDesc)
#define OUTSIDE_NO
int ChangeMarkedWord(const OUString &rNewWord, LanguageType eLanguage)
#define SAL_WARN_IF(condition, area, stream)
DictionaryError AddEntryToDic(uno::Reference< XDictionary > const &rxDic, const OUString &rWord, bool bIsNeg, const OUString &rRplcTxt, bool bStripDot)
virtual void ApplyChangedSentence(const SpellPortions &rChanged, bool bRecheck)=0
unsigned char sal_uInt8
void SetOffset(long nSet)
#define EE_CHAR_WEIGHT
void SpellContinue_Impl(bool UseSavedSentence=false, bool bIgnoreCurrentError=false)
std::unique_ptr< weld::MenuButton > m_xAddToDictMB
#define SPELLUNDO_CHANGE_NEXTERROR
Definition: SpellDialog.cxx:75
bool MarkNextError(bool bIgnoreCurrentError, const css::uno::Reference< css::linguistic2::XSpellChecker1 > &)
css::lang::Locale aLocale
Definition: SpellAttrib.hxx:35
std::unique_ptr< weld::Label > m_xAltTitle
static FncGetSpecialChars GetGetSpecialCharsFunction()
void SetAttrib(const SfxPoolItem &rItem, sal_Int32 nStart, sal_Int32 nEnd)
RET_OK
virtual int get_text_height() const =0
#define SPELLUNDO_CHANGE_TEXTENGINE
Definition: SpellDialog.cxx:74
void MoveErrorMarkTo(sal_Int32 nErrorStart, sal_Int32 nErrorEnd, bool bGrammar)
static void lcl_InsertBreakPosition_Impl(LanguagePositions_Impl &rBreakPositions, sal_Int32 nInsert, LanguageType eLanguage)
void SetAddedWord(const OUString &rWord)
DictionaryError
Reference< XDictionary > m_xDictionary
Definition: SpellDialog.cxx:95
void SetErrorMove(long nOldStart, long nOldEnd)
#define OUTSIDE_YES
static OUString GetLanguageString(const LanguageType eType)
constexpr::Color COL_LIGHTBLUE(0x00, 0x00, 0xFF)
#define ACTION_SELECTFIELD
svx::SpellPortions m_aSavedSentence
void connect_clicked(const Link< const OString &, void > &rLink)
std::unique_ptr< EditEngine > m_xEditEngine
SpellDialog * GetSpellDialog() const
Definition: SpellDialog.hxx:63
#define EE_CHAR_GRABBAG
LanguageType eLanguage
#define INSIDE_NO
void SetErrorLanguageSelected(bool bSet)
void StartSpellOptDlg_Impl()
std::unique_ptr< weld::Button > m_xChangePB
virtual void set_size_request(int nWidth, int nHeight)=0
bool IsErrorLanguageSelected() const
#define RIGHT_NO
virtual ~SpellDialog() override
#define EE_TEXTPOS_ALL
#define LEFT_NO
css::uno::Reference< css::linguistic2::XSpellChecker1 > xSpell
virtual float get_approximate_digit_width() const =0
const sal_Char sServiceName[]
virtual void set_sensitive(bool sensitive)=0
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)