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()
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(tools::Long nOldStart, tools::Long nOldEnd)
124  {
125  m_nOldErrorStart = nOldStart;
126  m_nOldErrorEnd = nOldEnd;
127  }
128  tools::Long GetOldErrorStart() const { return m_nOldErrorStart;}
129  tools::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(tools::Long nSet) {m_nOffset = nSet;}
140  tools::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 
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_toggled( 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  };
369  for (weld::Widget* pWidget : aControls)
370  pWidget->set_sensitive(true);
371  }
372  if( bNextSentence )
373  {
374  //remove undo if a new sentence is active
375  m_xSentenceED->ResetUndo();
376  m_xUndoPB->set_sensitive(false);
377  }
378 }
379 /* Initialize, asynchronous to prevent virtual calls
380  from a constructor
381  */
382 IMPL_LINK_NOARG( SpellDialog, InitHdl, void*, void)
383 {
384  m_xDialog->freeze();
385  //show or hide AutoCorrect depending on the modules abilities
386  m_xAutoCorrPB->set_visible(rParent.HasAutoCorrection());
387  SpellContinue_Impl(nullptr);
388  m_xSentenceED->ResetUndo();
389  m_xUndoPB->set_sensitive(false);
390 
391  // get current language
392  UpdateBoxes_Impl();
393 
394  // fill dictionary PopupMenu
395  InitUserDicts();
396 
397  LockFocusChanges(true);
398  if(m_xSentenceED->IsEnabled())
399  m_xSentenceED->GrabFocus();
400  else if( m_xChangePB->get_sensitive() )
401  m_xChangePB->grab_focus();
402  else if( m_xIgnorePB->get_sensitive() )
403  m_xIgnorePB->grab_focus();
404  else if( m_xClosePB->get_sensitive() )
405  m_xClosePB->grab_focus();
406  LockFocusChanges(false);
407  //show grammar CheckBox depending on the modules abilities
408  m_xCheckGrammarCB->set_active(rParent.IsGrammarChecking());
409  m_xDialog->thaw();
410 };
411 
412 IMPL_LINK( SpellDialog, ExtClickHdl, weld::Button&, rBtn, void )
413 {
414  if (m_xOptionsPB.get() == &rBtn)
415  StartSpellOptDlg_Impl();
416  else if (m_xAutoCorrPB.get() == &rBtn)
417  {
418  //get the currently selected wrong word
419  OUString sCurrentErrorText = m_xSentenceED->GetErrorText();
420  //get the wrong word from the XSpellAlternative
421  SpellErrorDescription aSpellErrorDescription;
422  bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
423  if (bSpellErrorDescription)
424  {
425  OUString sWrong(aSpellErrorDescription.sErrorText);
426  //if the word has not been edited in the MultiLineEdit then
427  //the current suggestion should be used
428  //if it's not the 'no suggestions' entry
429  if(sWrong == sCurrentErrorText &&
430  m_xSuggestionLB->get_sensitive() && m_xSuggestionLB->get_selected_index() != -1 &&
431  m_sNoSuggestionsST != m_xSuggestionLB->get_selected_text())
432  {
433  sCurrentErrorText = m_xSuggestionLB->get_selected_text();
434  }
435  if(sWrong != sCurrentErrorText)
436  {
437  SvxPrepareAutoCorrect( sWrong, sCurrentErrorText );
438  LanguageType eLang = GetSelectedLang_Impl();
439  rParent.AddAutoCorrection( sWrong, sCurrentErrorText, eLang );
440  //correct the word immediately
441  ChangeHdl(*m_xAutoCorrPB);
442  }
443  }
444  }
445 }
446 
447 IMPL_LINK_NOARG(SpellDialog, CheckGrammarHdl, weld::Toggleable&, 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 /* tdf#132822 start an undo group in ctor and close it in the dtor. This can
509  then be passed to SpellContinue_Impl which can delete it in advance of its
510  natural scope to force closing the undo group if SpellContinue_Impl needs to
511  fetch a new paragraph and discard all undo information which can only be
512  done properly if there are no open undo groups */
514 {
515 private:
516  SentenceEditWindow_Impl& m_rSentenceED;
517 public:
518  UndoChangeGroupGuard(SentenceEditWindow_Impl& rSentenceED)
519  : m_rSentenceED(rSentenceED)
520  {
521  m_rSentenceED.UndoActionStart(SPELLUNDO_CHANGE_GROUP);
522  }
524  {
525  m_rSentenceED.UndoActionEnd();
526  }
527 };
528 
529 IMPL_LINK_NOARG(SpellDialog, ChangeHdl, weld::Button&, void)
530 {
531  if (m_xSentenceED->IsUndoEditMode())
532  {
533  SpellContinue_Impl();
534  }
535  else
536  {
537  auto xGuard(std::make_unique<UndoChangeGroupGuard>(*m_xSentenceED));
538  OUString aString = getReplacementString();
539  m_xSentenceED->ChangeMarkedWord(aString, GetSelectedLang_Impl());
540  SpellContinue_Impl(&xGuard);
541  }
542  if(!m_xChangePB->get_sensitive())
543  m_xIgnorePB->grab_focus();
544 }
545 
546 IMPL_LINK_NOARG(SpellDialog, ChangeAllHdl, weld::Button&, void)
547 {
548  auto xGuard(std::make_unique<UndoChangeGroupGuard>(*m_xSentenceED));
549  OUString aString = getReplacementString();
550  LanguageType eLang = GetSelectedLang_Impl();
551 
552  // add new word to ChangeAll list
553  OUString aOldWord( m_xSentenceED->GetErrorText() );
554  SvxPrepareAutoCorrect( aOldWord, aString );
555  Reference<XDictionary> aXDictionary = LinguMgr::GetChangeAllList();
556  DictionaryError nAdded = AddEntryToDic( aXDictionary,
557  aOldWord, true,
558  aString );
559 
560  if(nAdded == DictionaryError::NONE)
561  {
562  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
563  SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
564  pAction->SetDictionary(aXDictionary);
565  pAction->SetAddedWord(aOldWord);
566  m_xSentenceED->AddUndoAction(std::move(pAction));
567  }
568 
569  m_xSentenceED->ChangeMarkedWord(aString, eLang);
570  SpellContinue_Impl(&xGuard);
571 }
572 
573 IMPL_LINK( SpellDialog, IgnoreAllHdl, weld::Button&, rButton, void )
574 {
575  auto xGuard(std::make_unique<UndoChangeGroupGuard>(*m_xSentenceED));
576  // add word to IgnoreAll list
577  Reference< XDictionary > aXDictionary = LinguMgr::GetIgnoreAllList();
578  //in case the error has been changed manually it has to be restored
579  m_xSentenceED->RestoreCurrentError();
580  if (&rButton == m_xIgnoreRulePB.get())
581  {
582  SpellErrorDescription aSpellErrorDescription;
583  bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
584  try
585  {
586  if( bSpellErrorDescription && aSpellErrorDescription.xGrammarChecker.is() )
587  {
588  aSpellErrorDescription.xGrammarChecker->ignoreRule(aSpellErrorDescription.sRuleId,
589  aSpellErrorDescription.aLocale);
590  // refresh the layout (workaround to launch a dictionary event)
591  aXDictionary->setActive(false);
592  aXDictionary->setActive(true);
593  }
594  }
595  catch( const uno::Exception& )
596  {
597  }
598  }
599  else
600  {
601  OUString sErrorText(m_xSentenceED->GetErrorText());
602  DictionaryError nAdded = AddEntryToDic( aXDictionary,
603  sErrorText, false,
604  OUString() );
605  if (nAdded == DictionaryError::NONE)
606  {
607  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
608  SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
609  pAction->SetDictionary(aXDictionary);
610  pAction->SetAddedWord(sErrorText);
611  m_xSentenceED->AddUndoAction(std::move(pAction));
612  }
613  }
614 
615  SpellContinue_Impl(&xGuard);
616 }
617 
618 IMPL_LINK_NOARG(SpellDialog, UndoHdl, weld::Button&, void)
619 {
620  m_xSentenceED->Undo();
621  if(!m_xSentenceED->GetUndoActionCount())
622  m_xUndoPB->set_sensitive(false);
623 }
624 
625 
626 IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl&, rAction, void )
627 {
628  switch(rAction.GetId())
629  {
631  {
632  if(rAction.IsEnableChangePB())
633  m_xChangePB->set_sensitive(false);
634  if(rAction.IsEnableChangeAllPB())
635  m_xChangeAllPB->set_sensitive(false);
636  }
637  break;
639  {
640  m_xSentenceED->MoveErrorMarkTo(static_cast<sal_Int32>(rAction.GetOldErrorStart()),
641  static_cast<sal_Int32>(rAction.GetOldErrorEnd()),
642  false);
643  if(rAction.IsErrorLanguageSelected())
644  {
645  UpdateBoxes_Impl();
646  }
647  }
648  break;
650  {
651  if(rAction.GetDictionary().is())
652  rAction.GetDictionary()->remove(rAction.GetAddedWord());
653  }
654  break;
656  {
657  if(rAction.GetOffset() != 0)
658  m_xSentenceED->MoveErrorEnd(rAction.GetOffset());
659  }
660  break;
662  {
663  //refill the dialog with the currently spelled sentence - throw away all changes
664  SpellContinue_Impl(nullptr, true);
665  }
666  break;
668  //undo of ignored rules is not supported
669  break;
670  }
671 }
672 
673 void SpellDialog::Impl_Restore(bool bUseSavedSentence)
674 {
675  //clear the "ChangeAllList"
676  LinguMgr::GetChangeAllList()->clear();
677  //get a new sentence
678  m_xSentenceED->SetText(OUString());
679  m_xSentenceED->ResetModified();
680  //Resolves: fdo#39348 refill the dialog with the currently spelled sentence
681  SpellContinue_Impl(nullptr, bUseSavedSentence);
682  m_xIgnorePB->set_label(m_sIgnoreOnceST);
683 }
684 
685 IMPL_LINK_NOARG(SpellDialog, IgnoreHdl, weld::Button&, void)
686 {
687  if (m_sResumeST == m_xIgnorePB->get_label())
688  {
689  Impl_Restore(false);
690  }
691  else
692  {
693  //in case the error has been changed manually it has to be restored,
694  // since the users choice now was to ignore the error
695  m_xSentenceED->RestoreCurrentError();
696 
697  // the word is being ignored
698  SpellContinue_Impl(nullptr, false, true);
699  }
700 }
701 
703 {
704  if (IsClosing())
705  return;
706 
707  // We have to call ToggleChildWindow directly; calling SfxDispatcher's
708  // Execute() does not work here when we are in a document with protected
709  // section - in that case, the cursor can move from the editable field to
710  // the protected area, and the slots get disabled because of
711  // SfxDisableFlags::SwOnProtectedCursor (see FN_SPELL_GRAMMAR_DIALOG in .sdi).
712  SfxViewFrame* pViewFrame = SfxViewFrame::Current();
713  if (pViewFrame)
714  pViewFrame->ToggleChildWindow(rParent.GetType());
715 }
716 
718 {
719  LanguageType nLang = m_xLanguageLB->get_active_id();
720  return nLang;
721 }
722 
723 IMPL_LINK_NOARG(SpellDialog, LanguageSelectHdl, weld::ComboBox&, void)
724 {
725  //If selected language changes, then add->list should be regenerated to
726  //match
727  InitUserDicts();
728 
729  //if currently an error is selected then search for alternatives for
730  //this word and fill the alternatives ListBox accordingly
731  OUString sError = m_xSentenceED->GetErrorText();
732  m_xSuggestionLB->clear();
733  if (!sError.isEmpty())
734  {
735  LanguageType eLanguage = m_xLanguageLB->get_active_id();
736  Reference <XSpellAlternatives> xAlt = xSpell->spell( sError, static_cast<sal_uInt16>(eLanguage),
737  Sequence< PropertyValue >() );
738  if( xAlt.is() )
739  m_xSentenceED->SetAlternatives( xAlt );
740  else
741  {
742  m_xSentenceED->ChangeMarkedWord( sError, eLanguage );
743  SpellContinue_Impl();
744  }
745 
746  m_xSentenceED->AddUndoAction(std::make_unique<SpellUndoAction_Impl>(SPELLUNDO_CHANGE_LANGUAGE, aDialogUndoLink));
747  }
749 }
750 
752 {
754  sTitle = sTitle.replaceFirst( "$LANGUAGE ($LOCATION)", SvtLanguageTable::GetLanguageString(nLang) );
755  m_xDialog->set_title(m_xDialog->strip_mnemonic(sTitle));
756 }
757 
759 {
760  const LanguageType nLang = m_xLanguageLB->get_active_id();
761 
762  const Reference< XDictionary > *pDic = nullptr;
763 
764  // get list of dictionaries
765  Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
766  if (xDicList.is())
767  {
768  // add active, positive dictionary to dic-list (if not already done).
769  // This is to ensure that there is at least on dictionary to which
770  // words could be added.
771  Reference< XDictionary > xDic( LinguMgr::GetStandardDic() );
772  if (xDic.is())
773  xDic->setActive( true );
774 
775  pImpl->aDics = xDicList->getDictionaries();
776  }
777 
778  SvtLinguConfig aCfg;
779 
780  // list suitable dictionaries
781  bool bEnable = false;
782  const sal_Int32 nSize = pImpl->aDics.getLength();
783  pDic = pImpl->aDics.getConstArray();
784  m_xAddToDictMB->clear();
785  sal_uInt16 nItemId = 1; // menu items should be enumerated from 1 and not 0
786  for (sal_Int32 i = 0; i < nSize; ++i)
787  {
788  uno::Reference< linguistic2::XDictionary > xDicTmp = pDic[i];
789  if (!xDicTmp.is() || LinguMgr::GetIgnoreAllList() == xDicTmp)
790  continue;
791 
792  uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY );
793  LanguageType nActLanguage = LanguageTag( xDicTmp->getLocale() ).getLanguageType();
794  if( xDicTmp->isActive()
795  && xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
796  && (nLang == nActLanguage || LANGUAGE_NONE == nActLanguage )
797  && (!xStor.is() || !xStor->isReadonly()) )
798  {
799  bEnable = true;
800 
801  OUString aDictionaryImageUrl;
802  uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY );
803  if (xSvcInfo.is())
804  {
805  aDictionaryImageUrl = aCfg.GetSpellAndGrammarContextDictionaryImage(
806  xSvcInfo->getImplementationName());
807  }
808 
809  m_xAddToDictMB->append_item(OUString::number(nItemId), xDicTmp->getName(), aDictionaryImageUrl);
810 
811  ++nItemId;
812  }
813  }
814  m_xAddToDictMB->set_sensitive( bEnable );
815  m_xAddToDictPB->set_sensitive( bEnable );
816 
817  int nDicts = nItemId-1;
818 
819  m_xAddToDictMB->set_visible(nDicts > 1 && !comphelper::LibreOfficeKit::isActive());
820  m_xAddToDictPB->set_visible(nDicts <= 1 && !comphelper::LibreOfficeKit::isActive());
821 
822  return nDicts;
823 }
824 
825 IMPL_LINK_NOARG(SpellDialog, AddToDictClickHdl, weld::Button&, void)
826 {
827  AddToDictionaryExecute(OString::number(1));
828 }
829 
830 IMPL_LINK(SpellDialog, AddToDictSelectHdl, const OString&, rIdent, void)
831 {
832  AddToDictionaryExecute(rIdent);
833 }
834 
835 void SpellDialog::AddToDictionaryExecute(const OString& rItemId)
836 {
837  auto xGuard(std::make_unique<UndoChangeGroupGuard>(*m_xSentenceED));
838 
839  //GetErrorText() returns the current error even if the text is already
840  //manually changed
841  const OUString aNewWord = m_xSentenceED->GetErrorText();
842 
843  OUString aDicName(m_xAddToDictMB->get_item_label(rItemId));
844 
845  uno::Reference< linguistic2::XDictionary > xDic;
846  uno::Reference< linguistic2::XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
847  if (xDicList.is())
848  xDic = xDicList->getDictionaryByName( aDicName );
849 
850  DictionaryError nAddRes = DictionaryError::UNKNOWN;
851  if (xDic.is())
852  {
853  nAddRes = AddEntryToDic( xDic, aNewWord, false, OUString() );
854  // save modified user-dictionary if it is persistent
855  uno::Reference< frame::XStorable > xSavDic( xDic, uno::UNO_QUERY );
856  if (xSavDic.is())
857  xSavDic->store();
858 
859  if (nAddRes == DictionaryError::NONE)
860  {
861  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
863  pAction->SetDictionary( xDic );
864  pAction->SetAddedWord( aNewWord );
865  m_xSentenceED->AddUndoAction( std::move(pAction) );
866  }
867  // failed because there is already an entry?
868  if (DictionaryError::NONE != nAddRes && xDic->getEntry( aNewWord ).is())
869  nAddRes = DictionaryError::NONE;
870  }
871  if (DictionaryError::NONE != nAddRes)
872  {
873  SvxDicError(m_xDialog.get(), nAddRes);
874  return; // don't continue
875  }
876 
877  // go on
878  SpellContinue_Impl(&xGuard);
879 }
880 
881 IMPL_LINK_NOARG(SpellDialog, ModifyHdl, LinkParamNone*, void)
882 {
883  m_xSuggestionLB->unselect_all();
884  m_xSuggestionLB->set_sensitive(false);
885  m_xAutoCorrPB->set_sensitive(false);
886  std::unique_ptr<SpellUndoAction_Impl> pSpellAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE, aDialogUndoLink));
887  if(!m_xChangeAllPB->get_sensitive())
888  {
889  m_xChangeAllPB->set_sensitive(true);
890  pSpellAction->SetEnableChangeAllPB();
891  }
892  if(!m_xChangePB->get_sensitive())
893  {
894  m_xChangePB->set_sensitive(true);
895  pSpellAction->SetEnableChangePB();
896  }
897  m_xSentenceED->AddUndoAction(std::move(pSpellAction));
898 }
899 
900 IMPL_LINK_NOARG(SpellDialog, CancelHdl, weld::Button&, void)
901 {
902  //apply changes and ignored text parts first - if there are any
903  if (m_xSentenceED->IsModified())
904  {
905  rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), false);
906  }
907  Close();
908 }
909 
911 {
912  /* #i38338#
913  * FIXME: LoseFocus and GetFocus are signals from vcl that
914  * a window actually got/lost the focus, it never should be
915  * forwarded from another window, that is simply wrong.
916  * FIXME: overriding the virtual methods GetFocus and LoseFocus
917  * in SpellDialogChildWindow by making them pure is at least questionable.
918  * The only sensible thing would be to call the new Method differently,
919  * e.g. DialogGot/LostFocus or so.
920  */
921  if (!m_xDialog->get_visible() || bFocusLocked)
922  return;
923 
924  if (m_xDialog->has_toplevel_focus())
925  {
926  //notify the child window of the focus change
927  rParent.GetFocus();
928  }
929  else
930  {
931  //notify the child window of the focus change
932  rParent.LoseFocus();
933  }
934 }
935 
937 {
940 }
941 
943 {
946 }
947 
949 {
950  if( bFocusLocked )
951  return;
952  m_xIgnorePB->set_label(m_sResumeST);
953  weld::Widget* aDisableArr[] =
954  {
955  m_xNotInDictFT.get(),
956  m_xSentenceED->GetDrawingArea(),
957  m_xSuggestionFT.get(),
958  m_xSuggestionLB.get(),
959  m_xLanguageFT.get(),
960  m_xLanguageLB->get_widget(),
961  m_xIgnoreAllPB.get(),
962  m_xIgnoreRulePB.get(),
963  m_xAddToDictMB.get(),
964  m_xAddToDictPB.get(),
965  m_xChangePB.get(),
966  m_xChangeAllPB.get(),
967  m_xAutoCorrPB.get(),
968  m_xUndoPB.get()
969  };
970  for (weld::Widget* pWidget : aDisableArr)
971  pWidget->set_sensitive(false);
972 
974 }
975 
976 bool SpellDialog::GetNextSentence_Impl(std::unique_ptr<UndoChangeGroupGuard>* pGuard, bool bUseSavedSentence, bool bRecheck)
977 {
978  bool bRet = false;
979  if(!bUseSavedSentence)
980  {
981  //apply changes and ignored text parts
982  rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), bRecheck);
983  }
984  m_xSentenceED->ResetIgnoreErrorsAt();
985  m_xSentenceED->ResetModified();
986  SpellPortions aSentence = bUseSavedSentence ? m_aSavedSentence : rParent.GetNextWrongSentence( bRecheck );
987  if(!bUseSavedSentence)
988  m_aSavedSentence = aSentence;
989  bool bHasReplaced = false;
990  while(!aSentence.empty())
991  {
992  //apply all changes that are already part of the "ChangeAllList"
993  //returns true if the list still contains errors after the changes have been applied
994 
995  if(!ApplyChangeAllList_Impl(aSentence, bHasReplaced))
996  {
997  rParent.ApplyChangedSentence(aSentence, bRecheck);
998  aSentence = rParent.GetNextWrongSentence( bRecheck );
999  }
1000  else
1001  break;
1002  }
1003 
1004  if(!aSentence.empty())
1005  {
1006  OUStringBuffer sText;
1007  for (auto const& elem : aSentence)
1008  {
1009  // hidden text has to be ignored
1010  if(!elem.bIsHidden)
1011  sText.append(elem.sText);
1012  }
1013  // tdf#132822 fire undo-stack UndoActionEnd to close undo stack because we're about to throw away the paragraph entirely
1014  if (pGuard)
1015  pGuard->reset();
1016  m_xSentenceED->SetText(sText.makeStringAndClear());
1017  sal_Int32 nStartPosition = 0;
1018  sal_Int32 nEndPosition = 0;
1019 
1020  for (auto const& elem : aSentence)
1021  {
1022  // hidden text has to be ignored
1023  if(!elem.bIsHidden)
1024  {
1025  nEndPosition += elem.sText.getLength();
1026  if(elem.xAlternatives.is())
1027  {
1028  SpellErrorDescription aDesc( false, elem.xAlternatives->getWord(),
1029  elem.xAlternatives->getLocale(), elem.xAlternatives->getAlternatives(), nullptr);
1030  SfxGrabBagItem aSpellErrorDescription(EE_CHAR_GRABBAG);
1031  aSpellErrorDescription.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
1032  m_xSentenceED->SetAttrib(aSpellErrorDescription, nStartPosition, nEndPosition);
1033  }
1034  else if(elem.bIsGrammarError )
1035  {
1036  beans::PropertyValues aProperties = elem.aGrammarError.aProperties;
1037  OUString sFullCommentURL;
1038  sal_Int32 i = 0;
1039  while ( sFullCommentURL.isEmpty() && i < aProperties.getLength() )
1040  {
1041  if ( aProperties[i].Name == "FullCommentURL" )
1042  {
1043  uno::Any aValue = aProperties[i].Value;
1044  aValue >>= sFullCommentURL;
1045  }
1046  ++i;
1047  }
1048 
1049  SpellErrorDescription aDesc( true,
1050  elem.sText,
1051  LanguageTag::convertToLocale( elem.eLanguage ),
1052  elem.aGrammarError.aSuggestions,
1053  elem.xGrammarChecker,
1054  &elem.sDialogTitle,
1055  &elem.aGrammarError.aFullComment,
1056  &elem.aGrammarError.aRuleIdentifier,
1057  &sFullCommentURL );
1058 
1059  SfxGrabBagItem aSpellErrorDescriptionItem(EE_CHAR_GRABBAG);
1060  aSpellErrorDescriptionItem.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
1061  m_xSentenceED->SetAttrib(aSpellErrorDescriptionItem, nStartPosition, nEndPosition);
1062  }
1063 
1064  if (elem.bIsField)
1065  m_xSentenceED->SetAttrib(SvxColorItem(COL_LIGHTGRAY, EE_CHAR_BKGCOLOR), nStartPosition, nEndPosition);
1066  m_xSentenceED->SetAttrib(SvxLanguageItem(elem.eLanguage, EE_CHAR_LANGUAGE), nStartPosition, nEndPosition);
1067  nStartPosition = nEndPosition;
1068  }
1069  }
1070  //the edit field needs to be modified to apply the change from the ApplyChangeAllList
1071  if(!bHasReplaced)
1072  m_xSentenceED->ClearModifyFlag();
1073  m_xSentenceED->ResetUndo();
1074  m_xUndoPB->set_sensitive(false);
1075  bRet = nStartPosition > 0;
1076  }
1077  return bRet;
1078 }
1079 /*-------------------------------------------------------------------------
1080  replace errors that have a replacement in the ChangeAllList
1081  returns false if the result doesn't contain errors after the replacement
1082  -----------------------------------------------------------------------*/
1083 bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions& rSentence, bool &bHasReplaced)
1084 {
1085  bHasReplaced = false;
1086  bool bRet = true;
1087  Reference<XDictionary> xChangeAll = LinguMgr::GetChangeAllList();
1088  if(!xChangeAll->getCount())
1089  return bRet;
1090  bRet = false;
1091  for (auto & elem : rSentence)
1092  {
1093  if(elem.xAlternatives.is())
1094  {
1095  const OUString &rString = elem.sText;
1096 
1097  Reference<XDictionaryEntry> xEntry = xChangeAll->getEntry(rString);
1098 
1099  if(xEntry.is())
1100  {
1101  elem.sText = getDotReplacementString(rString, xEntry->getReplacementText());
1102  elem.xAlternatives = nullptr;
1103  bHasReplaced = true;
1104  }
1105  else
1106  bRet = true;
1107  }
1108  else if( elem.bIsGrammarError )
1109  bRet = true;
1110  }
1111  return bRet;
1112 }
1113 
1115  : m_pSpellDialog(nullptr)
1116  , m_pToolbar(nullptr)
1117  , m_nErrorStart(0)
1118  , m_nErrorEnd(0)
1119  , m_bIsUndoEditMode(false)
1120 {
1121 }
1122 
1124 {
1125  Size aSize(pDrawingArea->get_approximate_digit_width() * 60,
1126  pDrawingArea->get_text_height() * 6);
1127  pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
1128  WeldEditView::SetDrawingArea(pDrawingArea);
1129  // tdf#132288 don't merge equal adjacent attributes
1130  m_xEditEngine->DisableAttributeExpanding();
1131 }
1132 
1134 {
1135 }
1136 
1137 namespace
1138 {
1139  const EECharAttrib* FindCharAttrib(int nPosition, sal_uInt16 nWhich, std::vector<EECharAttrib>& rAttribList)
1140  {
1141  for (auto it = rAttribList.rbegin(); it != rAttribList.rend(); ++it)
1142  {
1143  const auto& rTextAtr = *it;
1144  if (rTextAtr.pAttr->Which() != nWhich)
1145  continue;
1146  if (rTextAtr.nStart <= nPosition && rTextAtr.nEnd >= nPosition)
1147  {
1148  return &rTextAtr;
1149  }
1150  }
1151 
1152  return nullptr;
1153  }
1154 
1155  void ExtractErrorDescription(const EECharAttrib& rEECharAttrib, SpellErrorDescription& rSpellErrorDescription)
1156  {
1157  css::uno::Sequence<css::uno::Any> aSequence;
1158  static_cast<const SfxGrabBagItem*>(rEECharAttrib.pAttr)->GetGrabBag().find("SpellErrorDescription")->second >>= aSequence;
1159  rSpellErrorDescription.fromSequence(aSequence);
1160  }
1161 }
1162 
1163 /*-------------------------------------------------------------------------
1164  The selection before inputting a key may have a range or not
1165  and it may be inside or outside of field or error attributes.
1166  A range may include the attribute partially, completely or together
1167  with surrounding text. It may also contain more than one attribute
1168  or no attribute at all.
1169  Depending on this starting conditions some actions are necessary:
1170  Attempts to delete a field are only allowed if the selection is the same
1171  as the field's selection. Otherwise the field has to be selected and the key
1172  input action has to be skipped.
1173  Input of text at the start of the field requires the field attribute to be
1174  corrected - it is not allowed to grow.
1175 
1176  In case of errors the appending of text should grow the error attribute because
1177  that is what the user usually wants to do.
1178 
1179  Backspace at the start of the attribute requires to find out if a field ends
1180  directly in front of the cursor position. In case of a field this attribute has to be
1181  selected otherwise the key input method is allowed.
1182 
1183  All changes outside of the error attributes switch the dialog mode to a "Undo edit" state that
1184  removes all visible attributes and switches off further attribute checks.
1185  Undo in this restarts the dialog with a current sentence newly presented.
1186  All changes to the sentence are undone including the ones before the "Undo edit state" has been reached
1187 
1188  We end up with 9 types of selection
1189  1 (LEFT_NO) - no range, start of attribute - can also be 3 at the same time
1190  2 (INSIDE_NO) - no range, inside of attribute
1191  3 (RIGHT_NO) - no range, end of attribute - can also be 1 at the same time
1192  4 (FULL) - range, same as attribute
1193  5 (INSIDE_YES) - range, inside of the attribute
1194  6 (BRACE)- range, from outside of the attribute to the inside or
1195  including the complete attribute and something outside,
1196  maybe more than one attribute
1197  7 (OUTSIDE_NO) - no range, not at an attribute
1198  8 (OUTSIDE_YES) - range, completely outside of all attributes
1199 
1200  What has to be done depending on the attribute type involved
1201  possible actions: UE - Undo edit mode
1202  CO - Continue, no additional action is required
1203  FS - Field has to be completely selected
1204  EX - The attribute has to be expanded to include the added text
1205 
1206  1 - backspace delete any other
1207  UE on field FS on error CO on field FS on error CO
1208 
1209  2 - on field FS on error C
1210  3 - backspace delete any other
1211  on field FS on error CO UE on field UE on error EX
1212 
1213  if 1 and 3 happen to apply both then backspace and other handling is 1 delete is 3
1214 
1215  4 - on field UE and on error CO
1216  5 - on field FS and on error CO
1217  6 - on field FS and on error UE
1218  7 - UE
1219  8 - UE
1220  -----------------------------------------------------------------------*/
1221 #define INVALID 0
1222 #define LEFT_NO 1
1223 #define INSIDE_NO 2
1224 #define RIGHT_NO 3
1225 #define FULL 4
1226 #define INSIDE_YES 5
1227 #define BRACE 6
1228 #define OUTSIDE_NO 7
1229 #define OUTSIDE_YES 8
1230 
1231 #define ACTION_UNDOEDIT 0
1232 #define ACTION_CONTINUE 1
1233 #define ACTION_SELECTFIELD 2
1234 #define ACTION_EXPAND 3
1235 
1237 {
1238  if (rKeyEvt.GetKeyCode().GetCode() == KEY_TAB)
1239  return false;
1240 
1241  bool bConsumed = false;
1242 
1243  bool bChange = TextEngine::DoesKeyChangeText( rKeyEvt );
1244  if (bChange && !IsUndoEditMode())
1245  {
1246  bConsumed = true;
1247 
1248  ESelection aCurrentSelection(m_xEditView->GetSelection());
1249  aCurrentSelection.Adjust();
1250 
1251  //determine if the selection contains a field
1252  bool bHasFieldLeft = false;
1253  bool bHasErrorLeft = false;
1254 
1255  bool bHasRange = aCurrentSelection.HasRange();
1256  sal_uInt8 nSelectionType = 0; // invalid type!
1257 
1258  std::vector<EECharAttrib> aAttribList;
1259  m_xEditEngine->GetCharAttribs(0, aAttribList);
1260 
1261  auto nCursor = aCurrentSelection.nStartPos;
1262  const EECharAttrib* pBackAttr = FindCharAttrib(nCursor, EE_CHAR_BKGCOLOR, aAttribList);
1263  const EECharAttrib* pErrorAttr = FindCharAttrib(nCursor, EE_CHAR_GRABBAG, aAttribList);
1264  const EECharAttrib* pBackAttrLeft = nullptr;
1265  const EECharAttrib* pErrorAttrLeft = nullptr;
1266 
1267  bool bHasField = pBackAttr != nullptr && (bHasRange || pBackAttr->nEnd > nCursor);
1268  bool bHasError = pErrorAttr != nullptr && (bHasRange || pErrorAttr->nEnd > nCursor);
1269  if (bHasRange)
1270  {
1271  if (pBackAttr &&
1272  pBackAttr->nStart == aCurrentSelection.nStartPos &&
1273  pBackAttr->nEnd == aCurrentSelection.nEndPos)
1274  {
1275  nSelectionType = FULL;
1276  }
1277  else if (pErrorAttr &&
1278  pErrorAttr->nStart <= aCurrentSelection.nStartPos &&
1279  pErrorAttr->nEnd >= aCurrentSelection.nEndPos)
1280  {
1281  nSelectionType = INSIDE_YES;
1282  }
1283  else
1284  {
1285  nSelectionType = bHasField||bHasError ? BRACE : OUTSIDE_NO;
1286  while (nCursor < aCurrentSelection.nEndPos)
1287  {
1288  ++nCursor;
1289  const EECharAttrib* pIntBackAttr = FindCharAttrib(nCursor, EE_CHAR_BKGCOLOR, aAttribList);
1290  const EECharAttrib* pIntErrorAttr = FindCharAttrib(nCursor, EE_CHAR_GRABBAG, aAttribList);
1291  //if any attr has been found then BRACE
1292  if (pIntBackAttr || pIntErrorAttr)
1293  nSelectionType = BRACE;
1294  //the field has to be selected
1295  if (pIntBackAttr && !pBackAttr)
1296  pBackAttr = pIntBackAttr;
1297  bHasField |= pIntBackAttr != nullptr;
1298  }
1299  }
1300  }
1301  else
1302  {
1303  //no range selection: then 1 2 3 and 8 are possible
1304  const EECharAttrib* pCurAttr = pBackAttr ? pBackAttr : pErrorAttr;
1305  if (pCurAttr)
1306  {
1307  nSelectionType = pCurAttr->nStart == aCurrentSelection.nStartPos ?
1308  LEFT_NO : pCurAttr->nEnd == aCurrentSelection.nEndPos ? RIGHT_NO : INSIDE_NO;
1309  }
1310  else
1311  nSelectionType = OUTSIDE_NO;
1312 
1313  bHasFieldLeft = pBackAttr && pBackAttr->nEnd == nCursor;
1314  if(bHasFieldLeft)
1315  {
1316  pBackAttrLeft = pBackAttr;
1317  pBackAttr = nullptr;
1318  }
1319  bHasErrorLeft = pErrorAttr && pErrorAttr->nEnd == nCursor;
1320  if(bHasErrorLeft)
1321  {
1322  pErrorAttrLeft = pErrorAttr;
1323  pErrorAttr = nullptr;
1324  }
1325 
1326  //check previous position if this exists
1327  //that is a redundant in the case the attribute found above already is on the left cursor side
1328  //but it's o.k. for two errors/fields side by side
1329  if (nCursor)
1330  {
1331  --nCursor;
1332  pBackAttrLeft = FindCharAttrib(nCursor, EE_CHAR_BKGCOLOR, aAttribList);
1333  pErrorAttrLeft = FindCharAttrib(nCursor, EE_CHAR_GRABBAG, aAttribList);
1334  bHasFieldLeft = pBackAttrLeft !=nullptr;
1335  bHasErrorLeft = pErrorAttrLeft != nullptr;
1336  ++nCursor;
1337  }
1338  }
1339  //Here we have to determine if the error found is the one currently active
1340  bool bIsErrorActive = (pErrorAttr && pErrorAttr->nStart == m_nErrorStart) ||
1341  (pErrorAttrLeft && pErrorAttrLeft->nStart == m_nErrorStart);
1342 
1343  SAL_WARN_IF(
1344  nSelectionType == INVALID, "cui.dialogs",
1345  "selection type not set");
1346 
1347  const vcl::KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
1348  bool bDelete = rKeyCode.GetCode() == KEY_DELETE;
1349  bool bBackspace = rKeyCode.GetCode() == KEY_BACKSPACE;
1350 
1351  sal_Int8 nAction = ACTION_CONTINUE;
1352  switch(nSelectionType)
1353  {
1354 // 1 - backspace delete any other
1355 // UE on field FS on error CO on field FS on error CO
1356  case LEFT_NO :
1357  if(bBackspace)
1358  {
1359  nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
1360  //to force the use of pBackAttrLeft
1361  pBackAttr = nullptr;
1362  }
1363  else if(bDelete)
1364  nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1365  else
1366  nAction = bHasError && !nCursor ? ACTION_CONTINUE :
1367  bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1368  break;
1369 // 2 - on field FS on error C
1370  case INSIDE_NO :
1371  nAction = bHasField ? ACTION_SELECTFIELD :
1372  bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1373  break;
1374 // 3 - backspace delete any other
1375 // on field FS on error CO UE on field UE on error EX
1376  case RIGHT_NO :
1377  if(bBackspace)
1378  nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1379  else if(bDelete)
1380  nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1381  else
1382  nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
1383  bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT;
1384  break;
1385 // 4 - on field UE and on error CO
1386  case FULL :
1387  nAction = ACTION_UNDOEDIT;
1388  break;
1389 // 5 - on field FS and on error CO
1390  case INSIDE_YES :
1391  nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1392  break;
1393 // 6 - on field FS and on error UE
1394  case BRACE :
1395  nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
1396  break;
1397 // 7 - UE
1398 // 8 - UE
1399  case OUTSIDE_NO :
1400  case OUTSIDE_YES:
1401  nAction = ACTION_UNDOEDIT;
1402  break;
1403  }
1404  //save the current paragraph
1405  sal_Int32 nCurrentLen = m_xEditEngine->GetText().getLength();
1406  if (nAction != ACTION_SELECTFIELD)
1407  {
1408  m_xEditView->PostKeyEvent(rKeyEvt);
1409  }
1410  else
1411  {
1412  const EECharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft;
1413  if (pCharAttr)
1414  m_xEditView->SetSelection(ESelection(0, pCharAttr->nStart, 0, pCharAttr->nEnd));
1415  }
1416  if(nAction == ACTION_EXPAND)
1417  {
1418  DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error");
1419  //text has been added on the right and only the 'error attribute has to be corrected
1420  if (pErrorAttrLeft)
1421  {
1422  SpellErrorDescription aSpellErrorDescription;
1423  ExtractErrorDescription(*pErrorAttrLeft, aSpellErrorDescription);
1424 
1425  std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrLeft->pAttr->Clone());
1426  sal_Int32 nStart = pErrorAttrLeft->nStart;
1427  sal_Int32 nEnd = pErrorAttrLeft->nEnd + 1;
1428  m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
1429  SetAttrib(*xNewError, nStart, nEnd);
1430  //only active errors move the mark
1431  if (bIsErrorActive)
1432  {
1433  bool bGrammar = aSpellErrorDescription.bIsGrammarError;
1434  MoveErrorMarkTo(nStart, nEnd, bGrammar);
1435  }
1436  }
1437  //text has been added on the left then the error attribute has to be expanded and the
1438  //field attribute on the right - if any - has to be contracted
1439  else if (pErrorAttr)
1440  {
1441  SpellErrorDescription aSpellErrorDescription;
1442  ExtractErrorDescription(*pErrorAttr, aSpellErrorDescription);
1443 
1444  //determine the change
1445  sal_Int32 nAddedChars = m_xEditEngine->GetText().getLength() - nCurrentLen;
1446 
1447  std::unique_ptr<SfxPoolItem> xNewError(pErrorAttr->pAttr->Clone());
1448  sal_Int32 nStart = pErrorAttr->nStart + nAddedChars;
1449  sal_Int32 nEnd = pErrorAttr->nEnd + nAddedChars;
1450  m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
1451  nStart = pErrorAttr->nStart;
1452  SetAttrib(*xNewError, nStart, nEnd);
1453  //only if the error is active the mark is moved here
1454  if (bIsErrorActive)
1455  {
1456  bool bGrammar = aSpellErrorDescription.bIsGrammarError;
1457  MoveErrorMarkTo(nStart, nEnd, bGrammar);
1458  }
1459  xNewError.reset();
1460 
1461  if (pBackAttrLeft)
1462  {
1463  std::unique_ptr<SfxPoolItem> xNewBack(pBackAttrLeft->pAttr->Clone());
1464  sal_Int32 _nStart = pBackAttrLeft->nStart + nAddedChars;
1465  sal_Int32 _nEnd = pBackAttrLeft->nEnd + nAddedChars;
1466  m_xEditEngine->RemoveAttribs(ESelection(0, _nStart, 0, _nEnd), false, EE_CHAR_BKGCOLOR);
1467  _nStart = pBackAttrLeft->nStart;
1468  SetAttrib(*xNewBack, _nStart, _nEnd);
1469  }
1470  }
1471  }
1472  else if(nAction == ACTION_UNDOEDIT)
1473  {
1474  SetUndoEditMode(true);
1475  }
1476  //make sure the error positions are correct after text changes
1477  //the old attribute may have been deleted
1478  //all changes inside of the current error leave the error attribute at the current
1479  //start position
1480  if (!IsUndoEditMode() && bIsErrorActive)
1481  {
1482  const EECharAttrib* pFontColor = FindCharAttrib(nCursor, EE_CHAR_COLOR, aAttribList);
1483  const EECharAttrib* pErrorAttrib = FindCharAttrib(m_nErrorStart, EE_CHAR_GRABBAG, aAttribList);
1484  if (pFontColor && pErrorAttrib)
1485  {
1486  m_nErrorStart = pFontColor->nStart;
1487  m_nErrorEnd = pFontColor->nEnd;
1488  if (pErrorAttrib->nStart != m_nErrorStart || pErrorAttrib->nEnd != m_nErrorEnd)
1489  {
1490  std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrib->pAttr->Clone());
1491  assert(pErrorAttr);
1492  m_xEditEngine->RemoveAttribs(ESelection(0, pErrorAttr->nStart, 0, pErrorAttr->nEnd), false, EE_CHAR_GRABBAG);
1493  SetAttrib(*xNewError, m_nErrorStart, m_nErrorEnd);
1494  }
1495  }
1496  }
1497  //this is not a modification anymore
1498  if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
1499  CallModifyLink();
1500  }
1501  else
1502  bConsumed = m_xEditView->PostKeyEvent(rKeyEvt);
1503 
1504  return bConsumed;
1505 }
1506 
1508 {
1509  m_pToolbar = pToolbar;
1511 }
1512 
1513 IMPL_LINK(SentenceEditWindow_Impl, ToolbarHdl, const OString&, rCurItemId, void)
1514 {
1515  if (rCurItemId == "paste")
1516  {
1517  m_xEditView->Paste();
1518  CallModifyLink();
1519  }
1520  else if (rCurItemId == "insert")
1521  {
1522  if (auto pImplFncGetSpecialChars = vcl::GetGetSpecialCharsFunction())
1523  {
1524  OUString aChars = pImplFncGetSpecialChars(GetDrawingArea(), m_xEditEngine->GetStandardFont(0));
1525  if (!aChars.isEmpty())
1526  {
1527  ESelection aCurrentSelection(m_xEditView->GetSelection());
1528  m_xEditEngine->QuickInsertText(aChars, aCurrentSelection);
1529  CallModifyLink();
1530  }
1531  }
1532  }
1533 }
1534 
1535 bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError, const css::uno::Reference<css::linguistic2::XSpellChecker1>& xSpell )
1536 {
1537  if (bIgnoreCurrentError)
1538  m_aIgnoreErrorsAt.insert( m_nErrorStart );
1539 
1540  const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);
1541 
1542  if (m_nErrorEnd >= nTextLen - 1)
1543  return false;
1544  //if it's not already modified the modified flag has to be reset at the end of the marking
1545  bool bModified = IsModified();
1546  bool bRet = false;
1547  const sal_Int32 nOldErrorStart = m_nErrorStart;
1548  const sal_Int32 nOldErrorEnd = m_nErrorEnd;
1549 
1550  //create a cursor behind the end of the last error
1551  //- or at 0 at the start of the sentence
1552  sal_Int32 nCursor(m_nErrorEnd ? m_nErrorEnd + 1 : 0);
1553 
1554  //search for SpellErrorDescription
1555  SpellErrorDescription aSpellErrorDescription;
1556 
1557  std::vector<EECharAttrib> aAttribList;
1558  m_xEditEngine->GetCharAttribs(0, aAttribList);
1559 
1560  //iterate over the text and search for the next error that maybe has
1561  //to be replace by a ChangeAllList replacement
1562  bool bGrammarError = false;
1563  while (nCursor < nTextLen)
1564  {
1565  const SpellErrorDescription* pSpellErrorDescription = nullptr;
1566  const EECharAttrib* pEECharAttrib = nullptr;
1567 
1568  sal_Int32 nMinPos = nTextLen + 1;
1569  for (const auto& rTextAtr : aAttribList)
1570  {
1571  if (rTextAtr.pAttr->Which() != EE_CHAR_GRABBAG)
1572  continue;
1573  if (rTextAtr.nEnd > nCursor && rTextAtr.nStart < nMinPos)
1574  {
1575  nMinPos = rTextAtr.nStart;
1576  pEECharAttrib = &rTextAtr;
1577  }
1578  }
1579 
1580  if (pEECharAttrib)
1581  {
1582  ExtractErrorDescription(*pEECharAttrib, aSpellErrorDescription);
1583 
1584  bGrammarError = aSpellErrorDescription.bIsGrammarError;
1585  m_nErrorStart = pEECharAttrib->nStart;
1586  m_nErrorEnd = pEECharAttrib->nEnd;
1587 
1588  pSpellErrorDescription = &aSpellErrorDescription;
1589  }
1590 
1591  nCursor = std::max(nCursor, nMinPos); // move forward if possible
1592 
1593  // maybe the error found here is already in the ChangeAllList and has to be replaced
1594  Reference<XDictionary> xChangeAll = LinguMgr::GetChangeAllList();
1595  Reference<XDictionaryEntry> xEntry;
1596 
1597  if (xChangeAll->getCount() && pSpellErrorDescription &&
1598  (xEntry = xChangeAll->getEntry( pSpellErrorDescription->sErrorText )).is())
1599  {
1600  OUString sReplacement(getDotReplacementString(GetErrorText(), xEntry->getReplacementText()));
1601 
1602  int nLenChange = ChangeMarkedWord(sReplacement, LanguageTag::convertToLanguageType(pSpellErrorDescription->aLocale));
1603 
1604  nCursor += sReplacement.getLength();
1605 
1606  if (nLenChange)
1607  m_xEditEngine->GetCharAttribs(0, aAttribList);
1608  // maybe the error found here is already added to the dictionary and has to be ignored
1609  }
1610  else if(pSpellErrorDescription && !bGrammarError &&
1611  xSpell->isValid(GetErrorText(),
1612  static_cast<sal_uInt16>(LanguageTag::convertToLanguageType( pSpellErrorDescription->aLocale )),
1613  Sequence< PropertyValue >() ))
1614  {
1615  ++nCursor;
1616  }
1617  else
1618  break;
1619  }
1620 
1621  //if an attrib has been found search for the end of the error string
1622  if (nCursor < nTextLen)
1623  {
1624  MoveErrorMarkTo(nCursor, m_nErrorEnd, bGrammarError);
1625  bRet = true;
1626  //add an undo action
1627  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
1628  SPELLUNDO_CHANGE_NEXTERROR, GetSpellDialog()->aDialogUndoLink));
1629  pAction->SetErrorMove(nOldErrorStart, nOldErrorEnd);
1630 
1631  if (GetErrorDescription(aSpellErrorDescription, nOldErrorStart))
1632  {
1633  pAction->SetErrorLanguageSelected(aSpellErrorDescription.aSuggestions.hasElements() &&
1634  LanguageTag(aSpellErrorDescription.aLocale).getLanguageType() == GetSpellDialog()->m_xLanguageLB->get_active_id());
1635  }
1636  else
1637  pAction->SetErrorLanguageSelected(false);
1638 
1639  AddUndoAction(std::move(pAction));
1640  }
1641  else
1642  m_nErrorStart = m_nErrorEnd = nTextLen;
1643  if( !bModified )
1644  ClearModifyFlag();
1645  SpellDialog* pSpellDialog = GetSpellDialog();
1646  pSpellDialog->m_xIgnorePB->set_sensitive(bRet);
1647  pSpellDialog->m_xIgnoreAllPB->set_sensitive(bRet);
1648  pSpellDialog->m_xAutoCorrPB->set_sensitive(bRet);
1649  pSpellDialog->m_xAddToDictMB->set_sensitive(bRet);
1650  pSpellDialog->m_xAddToDictPB->set_sensitive(bRet);
1651  return bRet;
1652 }
1653 
1654 void SentenceEditWindow_Impl::MoveErrorMarkTo(sal_Int32 nStart, sal_Int32 nEnd, bool bGrammarError)
1655 {
1656  ESelection aAll(0, 0, 0, EE_TEXTPOS_ALL);
1657  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_COLOR);
1658  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT);
1659  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CJK);
1660  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CTL);
1661 
1662  SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
1663  aSet.Put(SvxColorItem(bGrammarError ? COL_LIGHTBLUE : COL_LIGHTRED, EE_CHAR_COLOR));
1667 
1668  m_xEditEngine->QuickSetAttribs(aSet, ESelection(0, nStart, 0, nEnd));
1669 
1670  // Set the selection so the editview will autoscroll to make this visible
1671  // unless (tdf#133958) the selection already overlaps this range
1672  ESelection aCurrentSelection = m_xEditView->GetSelection();
1673  aCurrentSelection.Adjust();
1674  bool bCurrentSelectionInRange = nStart <= aCurrentSelection.nEndPos && aCurrentSelection.nStartPos <= nEnd;
1675  if (!bCurrentSelectionInRange)
1676  {
1677  m_xEditView->SetSelection(ESelection(0, nStart));
1678  }
1679 
1680  Invalidate();
1681 
1682  m_nErrorStart = nStart;
1683  m_nErrorEnd = nEnd;
1684 }
1685 
1686 int SentenceEditWindow_Impl::ChangeMarkedWord(const OUString& rNewWord, LanguageType eLanguage)
1687 {
1688  std::vector<EECharAttrib> aAttribList;
1689  m_xEditEngine->GetCharAttribs(0, aAttribList);
1690 
1691  //calculate length changes
1692  auto nDiffLen = rNewWord.getLength() - m_nErrorEnd + m_nErrorStart;
1693  //Remove spell error attribute
1694  m_xEditEngine->UndoActionStart(SPELLUNDO_MOVE_ERROREND);
1695  const EECharAttrib* pErrorAttrib = FindCharAttrib(m_nErrorStart, EE_CHAR_GRABBAG, aAttribList);
1696  DBG_ASSERT(pErrorAttrib, "no error attribute found");
1697  bool bSpellErrorDescription = false;
1698  SpellErrorDescription aSpellErrorDescription;
1699  if (pErrorAttrib)
1700  {
1701  ExtractErrorDescription(*pErrorAttrib, aSpellErrorDescription);
1702  m_xEditEngine->RemoveAttribs(ESelection(0, pErrorAttrib->nStart, 0, pErrorAttrib->nEnd), false, EE_CHAR_GRABBAG);
1703  bSpellErrorDescription = true;
1704  }
1705 
1706  const EECharAttrib* pBackAttrib = FindCharAttrib(m_nErrorStart, EE_CHAR_BKGCOLOR, aAttribList);
1707 
1708  ESelection aSel(0, m_nErrorStart, 0, m_nErrorEnd);
1709  m_xEditEngine->QuickInsertText(rNewWord, aSel);
1710 
1711  const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);
1712 
1713  if (nDiffLen)
1714  m_xEditEngine->GetCharAttribs(0, aAttribList);
1715 
1716  if (!m_nErrorStart)
1717  {
1718  //attributes following an error at the start of the text are not moved but expanded from the
1719  //text engine - this is done to keep full-paragraph-attributes
1720  //in the current case that handling is not desired
1721  const EECharAttrib* pLangAttrib = FindCharAttrib(m_nErrorEnd, EE_CHAR_LANGUAGE, aAttribList);
1722 
1723  if (pLangAttrib && !pLangAttrib->nStart && pLangAttrib->nEnd == nTextLen)
1724  {
1725  LanguageType eNewLanguage = static_cast<const SvxLanguageItem*>(pLangAttrib->pAttr)->GetLanguage();
1726  m_xEditEngine->RemoveAttribs(ESelection(0, pLangAttrib->nStart, 0, pLangAttrib->nEnd), false, EE_CHAR_LANGUAGE);
1727  SetAttrib(SvxLanguageItem(eNewLanguage, EE_CHAR_LANGUAGE), m_nErrorEnd + nDiffLen, nTextLen);
1728  }
1729  }
1730 
1731  // undo expanded attributes!
1732  if (pBackAttrib && pBackAttrib->nStart < m_nErrorStart && pBackAttrib->nEnd == m_nErrorEnd + nDiffLen)
1733  {
1734  std::unique_ptr<SfxPoolItem> xNewBackground(pBackAttrib->pAttr->Clone());
1735  const sal_Int32 nStart = pBackAttrib->nStart;
1736 
1737  m_xEditEngine->RemoveAttribs(ESelection(0, pBackAttrib->nStart, 0, pBackAttrib->nEnd), false, EE_CHAR_BKGCOLOR);
1738 
1739  SetAttrib(*xNewBackground, nStart, m_nErrorStart);
1740  }
1741  m_xEditEngine->SetModified();
1742 
1743  //adjust end position
1744  tools::Long nEndTemp = m_nErrorEnd;
1745  nEndTemp += nDiffLen;
1746  m_nErrorEnd = static_cast<sal_Int32>(nEndTemp);
1747 
1748  std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
1749  SPELLUNDO_MOVE_ERROREND, GetSpellDialog()->aDialogUndoLink));
1750  pAction->SetOffset(nDiffLen);
1751  AddUndoAction(std::move(pAction));
1752  if (bSpellErrorDescription)
1753  {
1754  SfxGrabBagItem aSpellErrorDescriptionItem(EE_CHAR_GRABBAG);
1755  aSpellErrorDescriptionItem.GetGrabBag()["SpellErrorDescription"] <<= aSpellErrorDescription.toSequence();
1756  SetAttrib(aSpellErrorDescriptionItem, m_nErrorStart, m_nErrorEnd);
1757  }
1758  SetAttrib(SvxLanguageItem(eLanguage, EE_CHAR_LANGUAGE), m_nErrorStart, m_nErrorEnd);
1759  m_xEditEngine->UndoActionEnd();
1760 
1761  Invalidate();
1762 
1763  return nDiffLen;
1764 }
1765 
1767 {
1768  return m_xEditEngine->GetText(ESelection(0, m_nErrorStart, 0, m_nErrorEnd));
1769 }
1770 
1771 bool SentenceEditWindow_Impl::GetErrorDescription(SpellErrorDescription& rSpellErrorDescription, sal_Int32 nPosition)
1772 {
1773  std::vector<EECharAttrib> aAttribList;
1774  m_xEditEngine->GetCharAttribs(0, aAttribList);
1775 
1776  if (const EECharAttrib* pEECharAttrib = FindCharAttrib(nPosition, EE_CHAR_GRABBAG, aAttribList))
1777  {
1778  ExtractErrorDescription(*pEECharAttrib, rSpellErrorDescription);
1779  return true;
1780  }
1781 
1782  return false;
1783 }
1784 
1786 {
1787  return GetErrorDescription(rSpellErrorDescription, m_nErrorStart);
1788 }
1789 
1791 {
1792  SpellErrorDescription aSpellErrorDescription;
1793  if (GetErrorDescription(aSpellErrorDescription, m_nErrorStart))
1794  {
1795  if (aSpellErrorDescription.sErrorText != GetErrorText() )
1796  ChangeMarkedWord(aSpellErrorDescription.sErrorText, LanguageTag::convertToLanguageType(aSpellErrorDescription.aLocale));
1797  }
1798 }
1799 
1800 void SentenceEditWindow_Impl::SetAlternatives( const Reference< XSpellAlternatives>& xAlt )
1801 {
1802  OUString aWord;
1803  lang::Locale aLocale;
1804  uno::Sequence< OUString > aAlts;
1805  if (xAlt.is())
1806  {
1807  aWord = xAlt->getWord();
1808  aLocale = xAlt->getLocale();
1809  aAlts = xAlt->getAlternatives();
1810  }
1811  SpellErrorDescription aDesc( false, aWord, aLocale, aAlts, nullptr);
1812  SfxGrabBagItem aSpellErrorDescription(EE_CHAR_GRABBAG);
1813  aSpellErrorDescription.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
1814  SetAttrib(aSpellErrorDescription, m_nErrorStart, m_nErrorEnd);
1815 }
1816 
1817 void SentenceEditWindow_Impl::SetAttrib(const SfxPoolItem& rItem, sal_Int32 nStart, sal_Int32 nEnd)
1818 {
1819  SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
1820  aSet.Put(rItem);
1821  m_xEditEngine->QuickSetAttribs(aSet, ESelection(0, nStart, 0, nEnd));
1822  Invalidate();
1823 }
1824 
1825 void SentenceEditWindow_Impl::SetText( const OUString& rStr )
1826 {
1827  m_nErrorStart = m_nErrorEnd = 0;
1828  m_xEditEngine->SetText(rStr);
1829 }
1830 
1831 namespace {
1832 
1833 struct LanguagePosition_Impl
1834 {
1835  sal_Int32 nPosition;
1836  LanguageType eLanguage;
1837 
1838  LanguagePosition_Impl(sal_Int32 nPos, LanguageType eLang) :
1839  nPosition(nPos),
1840  eLanguage(eLang)
1841  {}
1842 };
1843 
1844 }
1845 
1846 typedef std::vector<LanguagePosition_Impl> LanguagePositions_Impl;
1847 
1849  LanguagePositions_Impl& rBreakPositions, sal_Int32 nInsert, LanguageType eLanguage)
1850 {
1851  LanguagePositions_Impl::iterator aStart = rBreakPositions.begin();
1852  while(aStart != rBreakPositions.end())
1853  {
1854  if(aStart->nPosition == nInsert)
1855  {
1856  //the language of following starts has to overwrite
1857  //the one of previous ends
1858  aStart->eLanguage = eLanguage;
1859  return;
1860  }
1861  else if(aStart->nPosition > nInsert)
1862  {
1863 
1864  rBreakPositions.insert(aStart, LanguagePosition_Impl(nInsert, eLanguage));
1865  return;
1866  }
1867  else
1868  ++aStart;
1869  }
1870  rBreakPositions.emplace_back(nInsert, eLanguage);
1871 }
1872 
1873 /*-------------------------------------------------------------------------
1874  Returns the text in spell portions. Each portion contains text with an
1875  equal language and attribute. The spell alternatives are empty.
1876  -----------------------------------------------------------------------*/
1878 {
1879  svx::SpellPortions aRet;
1880 
1881  const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);
1882 
1883  std::vector<EECharAttrib> aAttribList;
1884  m_xEditEngine->GetCharAttribs(0, aAttribList);
1885 
1886  if (nTextLen)
1887  {
1888  int nCursor(0);
1889  LanguagePositions_Impl aBreakPositions;
1890  const EECharAttrib* pLastLang = nullptr;
1891  const EECharAttrib* pLastError = nullptr;
1893  const EECharAttrib* pError = nullptr;
1894  while (nCursor < nTextLen)
1895  {
1896  const EECharAttrib* pLang = FindCharAttrib(nCursor, EE_CHAR_LANGUAGE, aAttribList);
1897  if(pLang && pLang != pLastLang)
1898  {
1899  eLang = static_cast<const SvxLanguageItem*>(pLang->pAttr)->GetLanguage();
1900  lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->nStart, eLang);
1901  lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->nEnd, eLang);
1902  pLastLang = pLang;
1903  }
1904  pError = FindCharAttrib(nCursor, EE_CHAR_GRABBAG, aAttribList);
1905  if (pError && pLastError != pError)
1906  {
1907  lcl_InsertBreakPosition_Impl(aBreakPositions, pError->nStart, eLang);
1908  lcl_InsertBreakPosition_Impl(aBreakPositions, pError->nEnd, eLang);
1909  pLastError = pError;
1910 
1911  }
1912  ++nCursor;
1913  }
1914 
1915  if (aBreakPositions.empty())
1916  {
1917  //if all content has been overwritten the attributes may have been removed, too
1918  svx::SpellPortion aPortion1;
1920 
1921  aPortion1.sText = m_xEditEngine->GetText(ESelection(0, 0, 0, nTextLen));
1922 
1923  aRet.push_back(aPortion1);
1924  }
1925  else
1926  {
1927  LanguagePositions_Impl::iterator aStart = aBreakPositions.begin();
1928  //start should always be Null
1929  eLang = aStart->eLanguage;
1930  sal_Int32 nStart = aStart->nPosition;
1931  DBG_ASSERT(!nStart, "invalid start position - language attribute missing?");
1932  ++aStart;
1933 
1934  while(aStart != aBreakPositions.end())
1935  {
1936  svx::SpellPortion aPortion1;
1937  aPortion1.eLanguage = eLang;
1938 
1939  aPortion1.sText = m_xEditEngine->GetText(ESelection(0, nStart, 0, aStart->nPosition));
1940 
1941  bool bIsIgnoreError = m_aIgnoreErrorsAt.find( nStart ) != m_aIgnoreErrorsAt.end();
1942  if( bIsIgnoreError )
1943  {
1944  aPortion1.bIgnoreThisError = true;
1945  }
1946  aRet.push_back(aPortion1);
1947  nStart = aStart->nPosition;
1948  eLang = aStart->eLanguage;
1949  ++aStart;
1950  }
1951  }
1952 
1953  // quick partly fix of #i71318. Correct fix needs to patch the EditEngine itself...
1954  // this one will only prevent text from disappearing. It may to not have the
1955  // correct language and will probably not spell checked...
1956  const sal_uInt32 nPara = m_xEditEngine->GetParagraphCount();
1957  if (nPara > 1)
1958  {
1959  OUStringBuffer aLeftOverText;
1960  for (sal_uInt32 i = 1; i < nPara; ++i)
1961  {
1962  aLeftOverText.append("\x0a"); // the manual line break...
1963  aLeftOverText.append(m_xEditEngine->GetText(i));
1964  }
1965  if (pError)
1966  { // we need to add a new portion containing the left-over text
1967  svx::SpellPortion aPortion2;
1968  aPortion2.eLanguage = eLang;
1969  aPortion2.sText = aLeftOverText.makeStringAndClear();
1970  aRet.push_back( aPortion2 );
1971  }
1972  else
1973  { // we just need to append the left-over text to the last portion (which had no errors)
1974  aRet[ aRet.size() - 1 ].sText += aLeftOverText;
1975  }
1976  }
1977  }
1978 
1979  return aRet;
1980 }
1981 
1983 {
1984  SfxUndoManager& rUndoMgr = m_xEditEngine->GetUndoManager();
1985  DBG_ASSERT(GetUndoActionCount(), "no undo actions available" );
1986  if(!GetUndoActionCount())
1987  return;
1988  bool bSaveUndoEdit = IsUndoEditMode();
1989  SpellUndoAction_Impl* pUndoAction;
1990  //if the undo edit mode is active then undo all changes until the UNDO_EDIT_MODE action has been found
1991  do
1992  {
1993  pUndoAction = static_cast<SpellUndoAction_Impl*>(rUndoMgr.GetUndoAction());
1994  rUndoMgr.Undo();
1995  }while(bSaveUndoEdit && SPELLUNDO_UNDO_EDIT_MODE != pUndoAction->GetId() && GetUndoActionCount());
1996 
1997  if(bSaveUndoEdit || SPELLUNDO_CHANGE_GROUP == pUndoAction->GetId())
1999 }
2000 
2002 {
2003  SfxUndoManager& rUndo = m_xEditEngine->GetUndoManager();
2004  rUndo.Clear();
2005 }
2006 
2007 void SentenceEditWindow_Impl::AddUndoAction( std::unique_ptr<SfxUndoAction> pAction )
2008 {
2009  SfxUndoManager& rUndoMgr = m_xEditEngine->GetUndoManager();
2010  rUndoMgr.AddUndoAction(std::move(pAction));
2011  GetSpellDialog()->m_xUndoPB->set_sensitive(true);
2012 }
2013 
2015 {
2016  return m_xEditEngine->GetUndoManager().GetUndoActionCount();
2017 }
2018 
2020 {
2021  m_xEditEngine->UndoActionStart(nId);
2022 }
2023 
2025 {
2026  m_xEditEngine->UndoActionEnd();
2027 }
2028 
2030 {
2031  // Shouldn't we always add the real signed value instead???
2032  if(nOffset > 0)
2033  m_nErrorEnd = m_nErrorEnd - static_cast<sal_Int32>(nOffset);
2034  else
2035  m_nErrorEnd = m_nErrorEnd - static_cast<sal_Int32>(-nOffset);
2036 }
2037 
2038 
2040 {
2041  DBG_ASSERT(!bSet || m_bIsUndoEditMode != bSet, "SetUndoEditMode with equal values?");
2042  m_bIsUndoEditMode = bSet;
2043  //disable all buttons except the Change
2044  SpellDialog* pSpellDialog = GetSpellDialog();
2045  weld::Widget* aControls[] =
2046  {
2047  pSpellDialog->m_xChangeAllPB.get(),
2048  pSpellDialog->m_xExplainFT.get(),
2049  pSpellDialog->m_xIgnoreAllPB.get(),
2050  pSpellDialog->m_xIgnoreRulePB.get(),
2051  pSpellDialog->m_xIgnorePB.get(),
2052  pSpellDialog->m_xSuggestionLB.get(),
2053  pSpellDialog->m_xSuggestionFT.get(),
2054  pSpellDialog->m_xLanguageFT.get(),
2055  pSpellDialog->m_xLanguageLB->get_widget(),
2056  pSpellDialog->m_xAddToDictMB.get(),
2057  pSpellDialog->m_xAddToDictPB.get(),
2058  pSpellDialog->m_xAutoCorrPB.get()
2059  };
2060  for (weld::Widget* pWidget : aControls)
2061  pWidget->set_sensitive(false);
2062 
2063  //remove error marks
2064  ESelection aAll(0, 0, 0, EE_TEXTPOS_ALL);
2065  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_COLOR);
2066  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT);
2067  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CJK);
2068  m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CTL);
2069  Invalidate();
2070 
2071  //put the appropriate action on the Undo-stack
2072  AddUndoAction( std::make_unique<SpellUndoAction_Impl>(
2073  SPELLUNDO_UNDO_EDIT_MODE, GetSpellDialog()->aDialogUndoLink) );
2074  pSpellDialog->m_xChangePB->set_sensitive(true);
2075 }
2076 
2077 /* 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
tools::Long GetOldErrorEnd() 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)
long Long
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:911
tools::Long GetOffset() const
#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:49
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)
void SetErrorMove(tools::Long nOldStart, tools::Long nOldEnd)
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
virtual sal_uInt32 GetId() const override
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
static bool DoesKeyChangeText(const KeyEvent &rKeyEvent)
tools::Long GetOldErrorStart() const
static css::uno::Reference< css::linguistic2::XSearchableDictionaryList > GetDictionaryList()
void SetOffset(tools::Long nSet)
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)
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTRED
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)
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
constexpr TypedWhichId< SvxColorItem > EE_CHAR_BKGCOLOR(EE_CHAR_START+32)
#define GROUP_MODULES
Definition: optlingu.hxx:41
std::unique_ptr< weld::LinkButton > m_xExplainLink
static css::uno::Reference< css::linguistic2::XSpellChecker1 > GetSpellChecker()
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:1251
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)
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)
LanguageType GetSelectedLang_Impl() const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
#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
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)
void MoveErrorEnd(tools::Long nOffset)
Close
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
#define OUTSIDE_YES
static OUString GetLanguageString(const LanguageType eType)
#define ACTION_SELECTFIELD
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTBLUE
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:60
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
#define LEFT_NO
css::uno::Reference< css::linguistic2::XSpellChecker1 > xSpell
SentenceEditWindow_Impl & m_rSentenceED
virtual float get_approximate_digit_width() const =0
UndoChangeGroupGuard(SentenceEditWindow_Impl &rSentenceED)
constexpr sal_uInt16 KEY_TAB
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)
bool m_bDetectedRangeSegmentation false
sal_Int32 nStartPos