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