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