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