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