1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <SwRewriter.hxx>
22 #include <strings.hrc>
26 #include <langhelper.hxx>
27 #include <bitmaps.hlst>
29 #include <swmodule.hxx>
30 #include <swtypes.hxx>
36 #include <comphelper/lok.hxx>
37 #include <comphelper/anytostring.hxx>
38 #include <comphelper/processfactory.hxx>
39 #include <cppuhelper/exc_hlp.hxx>
40 #include <editeng/acorrcfg.hxx>
41 #include <editeng/svxacorr.hxx>
42 #include <editeng/splwrap.hxx>
43 #include <editeng/unolingu.hxx>
44 #include <editeng/editview.hxx>
45 #include <i18nlangtag/languagetag.hxx>
46 #include <linguistic/misc.hxx>
47 #include <rtl/string.hxx>
48 #include <vcl/commandinfoprovider.hxx>
49 #include <vcl/svapp.hxx>
50 #include <vcl/weld.hxx>
51 #include <sfx2/dispatch.hxx>
52 #include <sfx2/request.hxx>
53 #include <sfx2/viewfrm.hxx>
54 #include <svl/itemset.hxx>
55 #include <svl/languageoptions.hxx>
56 #include <svl/stritem.hxx>
57 #include <svtools/langtab.hxx>
58 #include <unotools/lingucfg.hxx>
59 #include <unotools/linguprops.hxx>
60 #include <vcl/settings.hxx>
61 #include <osl/diagnose.h>
65 #include <com/sun/star/document/XDocumentLanguages.hpp>
66 #include <com/sun/star/frame/XFrame.hpp>
67 #include <com/sun/star/frame/XStorable.hpp>
68 #include <com/sun/star/lang/XServiceInfo.hpp>
69 #include <com/sun/star/linguistic2/XLanguageGuessing.hpp>
70 #include <com/sun/star/uno/Any.hxx>
71 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
72 #include <com/sun/star/system/SystemShellExecute.hpp>
73 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
75 using namespace ::com::sun::star
;
77 /// @returns : the language for the selected text that is set for the
78 /// specified attribute (script type).
79 /// If there are more than one languages used LANGUAGE_DONTKNOW will be returned.
80 /// @param nLangWhichId : one of
81 /// RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
82 /// @returns: the language in use for the selected text.
83 /// 'In use' means the language(s) matching the script type(s) of the
84 /// selected text. Or in other words, the language a spell checker would use.
85 /// If there is more than one language LANGUAGE_DONTKNOW will be returned.
86 // check if nScriptType includes the script type associated to nLang
87 static bool lcl_checkScriptType( SvtScriptType nScriptType
, LanguageType nLang
)
89 return bool(nScriptType
& SvtLanguageOptions::GetScriptTypeOfLanguage( nLang
));
92 void SwSpellPopup::fillLangPopupMenu(
93 PopupMenu
*pPopupMenu
,
94 sal_uInt16 nLangItemIdStart
,
95 const uno::Sequence
< OUString
>& aSeq
,
97 std::map
< sal_Int16
, OUString
> &rLangTable
)
102 // set of languages to be displayed in the sub menus
103 std::set
< OUString
> aLangItems
;
105 OUString
aCurLang( aSeq
[0] );
106 SvtScriptType nScriptType
= static_cast<SvtScriptType
>(aSeq
[1].toInt32());
107 OUString
aKeyboardLang( aSeq
[2] );
108 OUString
aGuessedTextLang( aSeq
[3] );
110 if (!aCurLang
.isEmpty() &&
111 LANGUAGE_DONTKNOW
!= SvtLanguageTable::GetLanguageType( aCurLang
))
112 aLangItems
.insert( aCurLang
);
115 const AllSettings
& rAllSettings
= Application::GetSettings();
116 LanguageType rSystemLanguage
= rAllSettings
.GetLanguageTag().getLanguageType();
117 if (rSystemLanguage
!= LANGUAGE_DONTKNOW
)
119 if (lcl_checkScriptType( nScriptType
, rSystemLanguage
))
120 aLangItems
.insert( SvtLanguageTable::GetLanguageString(rSystemLanguage
) );
124 LanguageType rUILanguage
= rAllSettings
.GetUILanguageTag().getLanguageType();
125 if (rUILanguage
!= LANGUAGE_DONTKNOW
)
127 if (lcl_checkScriptType(nScriptType
, rUILanguage
))
128 aLangItems
.insert( SvtLanguageTable::GetLanguageString(rUILanguage
) );
131 //4--guessed language
132 if (!aGuessedTextLang
.isEmpty())
134 if (lcl_checkScriptType(nScriptType
, SvtLanguageTable::GetLanguageType(aGuessedTextLang
)))
135 aLangItems
.insert( aGuessedTextLang
);
138 //5--keyboard language
139 if (!aKeyboardLang
.isEmpty())
141 if (lcl_checkScriptType(nScriptType
, SvtLanguageTable::GetLanguageType(aKeyboardLang
)))
142 aLangItems
.insert( aKeyboardLang
);
145 //6--all languages used in current document
146 uno::Reference
< css::frame::XModel
> xModel
;
147 uno::Reference
< css::frame::XController
> xController
= pWrtSh
->GetView().GetViewFrame().GetFrame().GetFrameInterface()->getController();
148 if ( xController
.is() )
149 xModel
= xController
->getModel();
150 uno::Reference
< document::XDocumentLanguages
> xDocumentLanguages( xModel
, uno::UNO_QUERY
);
151 /*the description of nScriptType flags
156 const sal_Int16 nMaxCount
= 7;
157 if (xDocumentLanguages
.is())
159 const uno::Sequence
< lang::Locale
> rLocales( xDocumentLanguages
->getDocumentLanguages( static_cast<sal_Int16
>(nScriptType
), nMaxCount
) );
160 for (const lang::Locale
& rLocale
: rLocales
)
162 if (aLangItems
.size() == size_t(nMaxCount
))
164 if (lcl_checkScriptType( nScriptType
, SvtLanguageTable::GetLanguageType( rLocale
.Language
)))
165 aLangItems
.insert( rLocale
.Language
);
169 sal_uInt16 nItemId
= nLangItemIdStart
;
170 for (const OUString
& aEntryText
: aLangItems
)
172 if (aEntryText
!= SvtLanguageTable::GetLanguageString( LANGUAGE_NONE
) &&
173 aEntryText
!= "*" && // multiple languages in current selection
174 !aEntryText
.isEmpty()) // 'no language found' from language guessing
176 OSL_ENSURE( nLangItemIdStart
<= nItemId
&& nItemId
<= nLangItemIdStart
+ MN_MAX_NUM_LANG
,
177 "nItemId outside of expected range!" );
178 pPopupMenu
->InsertItem( nItemId
, aEntryText
, MenuItemBits::RADIOCHECK
);
179 if (aEntryText
== aCurLang
)
181 //make a check mark for the current language
182 pPopupMenu
->CheckItem( nItemId
);
184 rLangTable
[ nItemId
] = aEntryText
;
189 pPopupMenu
->InsertItem( nLangItemIdStart
+ MN_NONE_OFFSET
, SwResId( STR_LANGSTATUS_NONE
), MenuItemBits::RADIOCHECK
);
190 if ( SvtLanguageTable::GetLanguageString( LANGUAGE_NONE
) == aCurLang
)
191 pPopupMenu
->CheckItem( nLangItemIdStart
+ MN_NONE_OFFSET
);
193 pPopupMenu
->InsertItem( nLangItemIdStart
+ MN_RESET_OFFSET
, SwResId( STR_RESET_TO_DEFAULT_LANGUAGE
) );
194 pPopupMenu
->InsertItem( nLangItemIdStart
+ MN_MORE_OFFSET
, SwResId( STR_LANGSTATUS_MORE
) );
197 SwSpellPopup::SwSpellPopup(
199 uno::Reference
< linguistic2::XSpellAlternatives
> xAlt
,
200 const OUString
&rParaText
)
201 : m_aBuilder(nullptr, AllSettings::GetUIRootDir(), "modules/swriter/ui/spellmenu.ui", "")
202 , m_xPopupMenu(m_aBuilder
.get_menu(u
"menu"))
203 , m_nIgnoreWordId(m_xPopupMenu
->GetItemId(u
"ignoreall"))
204 , m_nAddMenuId(m_xPopupMenu
->GetItemId(u
"addmenu"))
205 , m_nAddId(m_xPopupMenu
->GetItemId(u
"add"))
206 , m_nSpellDialogId(m_xPopupMenu
->GetItemId(u
"spelldialog"))
207 , m_nCorrectMenuId(m_xPopupMenu
->GetItemId(u
"correctmenu"))
208 , m_nCorrectDialogId(m_xPopupMenu
->GetItemId(u
"correctdialog"))
209 , m_nLangSelectionMenuId(m_xPopupMenu
->GetItemId(u
"langselection"))
210 , m_nLangParaMenuId(m_xPopupMenu
->GetItemId(u
"langpara"))
211 , m_nRedlineAcceptId(m_xPopupMenu
->GetItemId(u
"accept"))
212 , m_nRedlineRejectId(m_xPopupMenu
->GetItemId(u
"reject"))
213 , m_nRedlineNextId(m_xPopupMenu
->GetItemId(u
"next"))
214 , m_nRedlinePrevId(m_xPopupMenu
->GetItemId(u
"prev"))
216 , m_xSpellAlt(std::move(xAlt
))
217 , m_bGrammarResults(false)
219 OSL_ENSURE(m_xSpellAlt
.is(), "no spelling alternatives available");
221 m_xPopupMenu
->SetMenuFlags(MenuFlags::NoAutoMnemonics
);
222 bool bUseImagesInMenus
= Application::GetSettings().GetStyleSettings().GetUseImagesInMenus();
224 m_nCheckedLanguage
= LANGUAGE_NONE
;
225 css::uno::Sequence
< OUString
> aSuggestions
;
226 if (m_xSpellAlt
.is())
228 m_nCheckedLanguage
= LanguageTag( m_xSpellAlt
->getLocale() ).getLanguageType();
229 aSuggestions
= m_xSpellAlt
->getAlternatives();
231 sal_Int16 nStringCount
= static_cast< sal_Int16
>( aSuggestions
.getLength() );
235 PopupMenu
*pMenu
= m_xPopupMenu
->GetPopupMenu(m_nCorrectMenuId
);
236 pMenu
->SetMenuFlags(MenuFlags::NoAutoMnemonics
);
237 bool bEnable
= false;
241 OUString aSuggestionImageUrl
;
243 if (bUseImagesInMenus
)
245 uno::Reference
< container::XNamed
> xNamed( m_xSpellAlt
, uno::UNO_QUERY
);
248 aSuggestionImageUrl
= aCfg
.GetSpellAndGrammarContextSuggestionImage( xNamed
->getName() );
249 aImage
= Image( aSuggestionImageUrl
);
253 m_xPopupMenu
->InsertSeparator({}, 0);
255 sal_uInt16 nAutoCorrItemId
= MN_AUTOCORR_START
;
256 sal_uInt16 nItemId
= MN_SUGGESTION_START
;
257 for (sal_uInt16 i
= 0; i
< nStringCount
; ++i
)
259 const OUString aEntry
= aSuggestions
[ i
];
260 m_xPopupMenu
->InsertItem(nItemId
, aEntry
, MenuItemBits::NONE
, {}, i
);
261 m_xPopupMenu
->SetHelpId(nItemId
, HID_LINGU_REPLACE
);
262 if (!aSuggestionImageUrl
.isEmpty())
263 m_xPopupMenu
->SetItemImage(nItemId
, aImage
);
265 pMenu
->InsertItem( nAutoCorrItemId
, aEntry
);
266 pMenu
->SetHelpId( nAutoCorrItemId
, HID_LINGU_AUTOCORR
);
273 uno::Reference
< frame::XFrame
> xFrame
= pWrtSh
->GetView().GetViewFrame().GetFrame().GetFrameInterface();
274 OUString
aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame
));
277 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(".uno:SpellingAndGrammarDialog", aModuleName
);
278 m_xPopupMenu
->SetItemText(m_nSpellDialogId
,
279 vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties
));
282 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(".uno:AutoCorrectDlg", aModuleName
);
283 m_xPopupMenu
->SetItemText(m_nCorrectDialogId
,
284 vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties
));
287 sal_uInt16 nItemPos
= m_xPopupMenu
->GetItemPos(m_nIgnoreWordId
);
288 OUString
aIgnoreSelection( SwResId( STR_IGNORE_SELECTION
) );
289 m_xPopupMenu
->InsertItem(MN_IGNORE_SELECTION
, aIgnoreSelection
, MenuItemBits::NONE
, {}, nItemPos
);
290 m_xPopupMenu
->SetHelpId(MN_IGNORE_SELECTION
, HID_LINGU_IGNORE_SELECTION
);
292 m_xPopupMenu
->EnableItem(m_nCorrectMenuId
, bEnable
);
294 uno::Reference
< linguistic2::XLanguageGuessing
> xLG
= SW_MOD()->GetLanguageGuesser();
295 LanguageType nGuessLangWord
= LANGUAGE_NONE
;
296 LanguageType nGuessLangPara
= LANGUAGE_NONE
;
297 if (m_xSpellAlt
.is() && xLG
.is())
299 nGuessLangWord
= EditView::CheckLanguage( m_xSpellAlt
->getWord(), ::GetSpellChecker(), xLG
, false );
300 nGuessLangPara
= EditView::CheckLanguage( rParaText
, ::GetSpellChecker(), xLG
, true );
302 if (nGuessLangWord
!= LANGUAGE_NONE
|| nGuessLangPara
!= LANGUAGE_NONE
)
304 // make sure LANGUAGE_NONE gets not used as menu entry
305 if (nGuessLangWord
== LANGUAGE_NONE
)
306 nGuessLangWord
= nGuessLangPara
;
307 if (nGuessLangPara
== LANGUAGE_NONE
)
308 nGuessLangPara
= nGuessLangWord
;
311 pMenu
= m_xPopupMenu
->GetPopupMenu(m_nAddMenuId
);
312 pMenu
->SetMenuFlags(MenuFlags::NoAutoMnemonics
); //! necessary to retrieve the correct dictionary name in 'Execute' below
313 uno::Reference
< linguistic2::XSearchableDictionaryList
> xDicList( LinguMgr::GetDictionaryList() );
314 sal_uInt16 nItemId
= MN_DICTIONARIES_START
;
317 // add the default positive dictionary to dic-list (if not already done).
318 // This is to ensure that there is at least one dictionary to which
319 // words could be added.
320 uno::Reference
< linguistic2::XDictionary
> xDic( LinguMgr::GetStandardDic() );
322 xDic
->setActive( true );
324 m_aDics
= xDicList
->getDictionaries();
326 for( const uno::Reference
< linguistic2::XDictionary
>& rDic
: std::as_const(m_aDics
) )
328 uno::Reference
< linguistic2::XDictionary
> xDicTmp
= rDic
;
329 if (!xDicTmp
.is() || LinguMgr::GetIgnoreAllList() == xDicTmp
)
332 uno::Reference
< frame::XStorable
> xStor( xDicTmp
, uno::UNO_QUERY
);
333 LanguageType nActLanguage
= LanguageTag( xDicTmp
->getLocale() ).getLanguageType();
334 if( xDicTmp
->isActive()
335 && xDicTmp
->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
336 && (m_nCheckedLanguage
== nActLanguage
|| LANGUAGE_NONE
== nActLanguage
)
337 && (!xStor
.is() || !xStor
->isReadonly()) )
339 // the extra 1 is because of the (possible) external
340 // linguistic entry above
341 pMenu
->InsertItem( nItemId
, xDicTmp
->getName() );
342 m_aDicNameSingle
= xDicTmp
->getName();
344 if (bUseImagesInMenus
)
346 uno::Reference
< lang::XServiceInfo
> xSvcInfo( xDicTmp
, uno::UNO_QUERY
);
349 OUString
aDictionaryImageUrl( aCfg
.GetSpellAndGrammarContextDictionaryImage(
350 xSvcInfo
->getImplementationName() ) );
351 if (!aDictionaryImageUrl
.isEmpty())
353 Image
aImage( aDictionaryImageUrl
);
354 pMenu
->SetItemImage( nItemId
, aImage
);
363 m_xPopupMenu
->EnableItem(m_nAddMenuId
, (nItemId
- MN_DICTIONARIES_START
) > 1);
364 m_xPopupMenu
->EnableItem(m_nAddId
, (nItemId
- MN_DICTIONARIES_START
) == 1);
366 //ADD NEW LANGUAGE MENU ITEM
368 OUString
aScriptTypesInUse( OUString::number( static_cast<int>(pWrtSh
->GetScriptType()) ) );
370 // get keyboard language
371 OUString aKeyboardLang
;
372 SwEditWin
& rEditWin
= pWrtSh
->GetView().GetEditWin();
373 LanguageType nLang
= rEditWin
.GetInputLanguage();
374 if (nLang
!= LANGUAGE_DONTKNOW
&& nLang
!= LANGUAGE_SYSTEM
)
375 aKeyboardLang
= SvtLanguageTable::GetLanguageString( nLang
);
377 // get the language that is in use
378 OUString
aCurrentLang("*");
379 nLang
= SwLangHelper::GetCurrentLanguage( *pWrtSh
);
380 if (nLang
!= LANGUAGE_DONTKNOW
)
381 aCurrentLang
= SvtLanguageTable::GetLanguageString( nLang
);
383 // build sequence for status value
384 uno::Sequence
< OUString
> aSeq
{ aCurrentLang
,
387 SvtLanguageTable::GetLanguageString(nGuessLangWord
) };
389 pMenu
= m_xPopupMenu
->GetPopupMenu(m_nLangSelectionMenuId
);
390 fillLangPopupMenu( pMenu
, MN_SET_LANGUAGE_SELECTION_START
, aSeq
, pWrtSh
, m_aLangTable_Text
);
391 m_xPopupMenu
->EnableItem(m_nLangSelectionMenuId
);
393 pMenu
= m_xPopupMenu
->GetPopupMenu(m_nLangParaMenuId
);
394 fillLangPopupMenu( pMenu
, MN_SET_LANGUAGE_PARAGRAPH_START
, aSeq
, pWrtSh
, m_aLangTable_Paragraph
);
395 m_xPopupMenu
->EnableItem(m_nLangParaMenuId
);
397 if (bUseImagesInMenus
)
398 m_xPopupMenu
->SetItemImage(m_nSpellDialogId
,
399 vcl::CommandInfoProvider::GetImageForCommand(".uno:SpellingAndGrammarDialog", xFrame
));
402 m_xPopupMenu
->RemoveDisabledEntries( true );
404 InitItemCommands(aSuggestions
);
407 SwSpellPopup::SwSpellPopup(
409 const linguistic2::ProofreadingResult
&rResult
,
410 sal_Int32 nErrorInResult
,
411 const uno::Sequence
< OUString
> &rSuggestions
,
412 const OUString
&rParaText
)
413 : m_aBuilder(nullptr, AllSettings::GetUIRootDir(), "modules/swriter/ui/spellmenu.ui", "")
414 , m_xPopupMenu(m_aBuilder
.get_menu(u
"menu"))
415 , m_nIgnoreWordId(m_xPopupMenu
->GetItemId(u
"ignoreall"))
416 , m_nAddMenuId(m_xPopupMenu
->GetItemId(u
"addmenu"))
417 , m_nAddId(m_xPopupMenu
->GetItemId(u
"add"))
418 , m_nSpellDialogId(m_xPopupMenu
->GetItemId(u
"spelldialog"))
419 , m_nCorrectMenuId(m_xPopupMenu
->GetItemId(u
"correctmenu"))
420 , m_nCorrectDialogId(m_xPopupMenu
->GetItemId(u
"correctdialog"))
421 , m_nLangSelectionMenuId(m_xPopupMenu
->GetItemId(u
"langselection"))
422 , m_nLangParaMenuId(m_xPopupMenu
->GetItemId(u
"langpara"))
423 , m_nRedlineAcceptId(m_xPopupMenu
->GetItemId(u
"accept"))
424 , m_nRedlineRejectId(m_xPopupMenu
->GetItemId(u
"reject"))
425 , m_nRedlineNextId(m_xPopupMenu
->GetItemId(u
"next"))
426 , m_nRedlinePrevId(m_xPopupMenu
->GetItemId(u
"prev"))
428 , m_bGrammarResults(true)
430 m_nCheckedLanguage
= LanguageTag::convertToLanguageType( rResult
.aLocale
);
431 bool bUseImagesInMenus
= Application::GetSettings().GetStyleSettings().GetUseImagesInMenus();
434 OUString
aMessageText( rResult
.aErrors
[ nErrorInResult
].aShortComment
);
435 m_xPopupMenu
->InsertSeparator({}, nPos
++);
436 m_xPopupMenu
->InsertItem(MN_SHORT_COMMENT
, aMessageText
, MenuItemBits::NOSELECT
, {}, nPos
++);
437 if (bUseImagesInMenus
)
438 m_xPopupMenu
->SetItemImage(MN_SHORT_COMMENT
, Image(StockImage::Yes
, BMP_INFO_16
));
440 // Add an item to show detailed infos if the FullCommentURL property is defined
441 const beans::PropertyValues aProperties
= rResult
.aErrors
[ nErrorInResult
].aProperties
;
442 for ( const auto& rProp
: aProperties
)
444 if ( rProp
.Name
== "FullCommentURL" )
446 uno::Any aValue
= rProp
.Value
;
447 aValue
>>= m_sExplanationLink
;
449 if ( !m_sExplanationLink
.isEmpty( ) )
454 if ( !m_sExplanationLink
.isEmpty( ) )
456 m_xPopupMenu
->InsertItem(MN_EXPLANATION_LINK
, SwResId(STR_EXPLANATION_LINK
), MenuItemBits::TEXT
| MenuItemBits::HELP
, {}, nPos
++);
459 m_xPopupMenu
->SetMenuFlags(MenuFlags::NoAutoMnemonics
);
461 m_xPopupMenu
->InsertSeparator({}, nPos
++);
462 if ( rSuggestions
.hasElements() ) // suggestions available...
465 OUString aSuggestionImageUrl
;
467 if (bUseImagesInMenus
)
469 uno::Reference
< lang::XServiceInfo
> xInfo( rResult
.xProofreader
, uno::UNO_QUERY
);
472 aSuggestionImageUrl
= SvtLinguConfig().GetSpellAndGrammarContextSuggestionImage( xInfo
->getImplementationName() );
473 aImage
= Image( aSuggestionImageUrl
);
477 sal_uInt16 nItemId
= MN_SUGGESTION_START
;
478 for (const OUString
& aEntry
: std::as_const(rSuggestions
))
480 m_xPopupMenu
->InsertItem(nItemId
, aEntry
, MenuItemBits::NONE
, {}, nPos
++);
481 m_xPopupMenu
->SetHelpId(nItemId
, HID_LINGU_REPLACE
);
482 if (!aSuggestionImageUrl
.isEmpty())
483 m_xPopupMenu
->SetItemImage(nItemId
, aImage
);
487 m_xPopupMenu
->InsertSeparator({}, nPos
++);
490 uno::Reference
< frame::XFrame
> xFrame
= pWrtSh
->GetView().GetViewFrame().GetFrame().GetFrameInterface();
491 OUString
aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame
));
493 OUString
aIgnoreSelection( SwResId( STR_IGNORE_SELECTION
) );
494 auto aCommandProperties
= vcl::CommandInfoProvider::GetCommandProperties(".uno:SpellingAndGrammarDialog", aModuleName
);
495 m_xPopupMenu
->SetItemText(m_nSpellDialogId
,
496 vcl::CommandInfoProvider::GetPopupLabelForCommand(aCommandProperties
));
497 sal_uInt16 nItemPos
= m_xPopupMenu
->GetItemPos(m_nIgnoreWordId
);
498 m_xPopupMenu
->InsertItem(MN_IGNORE_SELECTION
, aIgnoreSelection
, MenuItemBits::NONE
, {}, nItemPos
);
499 m_xPopupMenu
->SetHelpId(MN_IGNORE_SELECTION
, HID_LINGU_IGNORE_SELECTION
);
501 m_xPopupMenu
->EnableItem(m_nCorrectMenuId
, false);
502 m_xPopupMenu
->EnableItem(m_nCorrectDialogId
, false);
504 uno::Reference
< linguistic2::XLanguageGuessing
> xLG
= SW_MOD()->GetLanguageGuesser();
505 LanguageType nGuessLangWord
= LANGUAGE_NONE
;
506 LanguageType nGuessLangPara
= LANGUAGE_NONE
;
509 nGuessLangPara
= EditView::CheckLanguage( rParaText
, ::GetSpellChecker(), xLG
, true );
511 if (nGuessLangWord
!= LANGUAGE_NONE
|| nGuessLangPara
!= LANGUAGE_NONE
)
513 // make sure LANGUAGE_NONE gets not used as menu entry
514 if (nGuessLangWord
== LANGUAGE_NONE
)
515 nGuessLangWord
= nGuessLangPara
;
516 if (nGuessLangPara
== LANGUAGE_NONE
)
517 nGuessLangPara
= nGuessLangWord
;
520 m_xPopupMenu
->EnableItem(m_nAddMenuId
, false);
521 m_xPopupMenu
->EnableItem(m_nAddId
, false);
523 //ADD NEW LANGUAGE MENU ITEM
525 OUString
aScriptTypesInUse( OUString::number( static_cast<int>(pWrtSh
->GetScriptType()) ) );
527 // get keyboard language
528 OUString aKeyboardLang
;
529 SwEditWin
& rEditWin
= pWrtSh
->GetView().GetEditWin();
530 LanguageType nLang
= rEditWin
.GetInputLanguage();
531 if (nLang
!= LANGUAGE_DONTKNOW
&& nLang
!= LANGUAGE_SYSTEM
)
532 aKeyboardLang
= SvtLanguageTable::GetLanguageString( nLang
);
534 // get the language that is in use
535 OUString
aCurrentLang("*");
536 nLang
= SwLangHelper::GetCurrentLanguage( *pWrtSh
);
537 if (nLang
!= LANGUAGE_DONTKNOW
)
538 aCurrentLang
= SvtLanguageTable::GetLanguageString( nLang
);
540 // build sequence for status value
541 uno::Sequence
< OUString
> aSeq
{ aCurrentLang
,
544 SvtLanguageTable::GetLanguageString(nGuessLangWord
) };
546 PopupMenu
*pMenu
= m_xPopupMenu
->GetPopupMenu(m_nLangSelectionMenuId
);
547 fillLangPopupMenu( pMenu
, MN_SET_LANGUAGE_SELECTION_START
, aSeq
, pWrtSh
, m_aLangTable_Text
);
548 m_xPopupMenu
->EnableItem(m_nLangSelectionMenuId
);
550 pMenu
= m_xPopupMenu
->GetPopupMenu(m_nLangParaMenuId
);
551 fillLangPopupMenu( pMenu
, MN_SET_LANGUAGE_PARAGRAPH_START
, aSeq
, pWrtSh
, m_aLangTable_Paragraph
);
552 m_xPopupMenu
->EnableItem(m_nLangParaMenuId
);
554 if (bUseImagesInMenus
)
555 m_xPopupMenu
->SetItemImage(m_nSpellDialogId
,
556 vcl::CommandInfoProvider::GetImageForCommand(".uno:SpellingAndGrammarDialog", xFrame
));
559 m_xPopupMenu
->RemoveDisabledEntries(true);
561 SvtLinguConfig().SetProperty( UPN_IS_GRAMMAR_INTERACTIVE
, uno::Any( true ));
563 InitItemCommands(rSuggestions
);
566 SwSpellPopup::~SwSpellPopup() {}
568 void SwSpellPopup::InitItemCommands(const css::uno::Sequence
< OUString
>& aSuggestions
)
570 if (!comphelper::LibreOfficeKit::isActive())
573 // None is added only for LOK, it means there is no need to execute anything
574 m_xPopupMenu
->SetItemCommand(MN_SHORT_COMMENT
, ".uno:None");
575 m_xPopupMenu
->SetItemCommand(m_nSpellDialogId
, ".uno:SpellingAndGrammarDialog");
576 if(m_bGrammarResults
)
577 m_xPopupMenu
->SetItemCommand(m_nIgnoreWordId
, ".uno:SpellCheckIgnoreAll?Type:string=Grammar");
579 m_xPopupMenu
->SetItemCommand(m_nIgnoreWordId
, ".uno:SpellCheckIgnoreAll?Type:string=Spelling");
580 if(m_bGrammarResults
)
581 m_xPopupMenu
->SetItemCommand(MN_IGNORE_SELECTION
, ".uno:SpellCheckIgnore?Type:string=Grammar");
583 m_xPopupMenu
->SetItemCommand(MN_IGNORE_SELECTION
, ".uno:SpellCheckIgnore?Type:string=Spelling");
585 for(int i
= 0; i
< aSuggestions
.getLength(); ++i
)
587 sal_uInt16 nItemId
= MN_SUGGESTION_START
+ i
;
588 OUString sCommandString
= ".uno:SpellCheckApplySuggestion?ApplyRule:string=";
589 if(m_bGrammarResults
)
590 sCommandString
+= "Grammar_";
591 else if (m_xSpellAlt
.is())
592 sCommandString
+= "Spelling_";
593 sCommandString
+= m_xPopupMenu
->GetItemText(nItemId
);
594 m_xPopupMenu
->SetItemCommand(nItemId
, sCommandString
);
597 PopupMenu
*pMenu
= m_xPopupMenu
->GetPopupMenu(m_nLangSelectionMenuId
);
598 m_xPopupMenu
->SetItemCommand(m_nLangSelectionMenuId
, ".uno:SetSelectionLanguageMenu");
601 for (const auto& item
: m_aLangTable_Text
)
603 OUString sCommandString
= ".uno:LanguageStatus?Language:string=Current_" + item
.second
;
604 pMenu
->SetItemCommand(item
.first
, sCommandString
);
607 pMenu
->SetItemCommand(MN_SET_SELECTION_NONE
, ".uno:LanguageStatus?Language:string=Current_LANGUAGE_NONE");
608 pMenu
->SetItemCommand(MN_SET_SELECTION_RESET
, ".uno:LanguageStatus?Language:string=Current_RESET_LANGUAGES");
609 pMenu
->SetItemCommand(MN_SET_SELECTION_MORE
, ".uno:FontDialog?Page:string=font");
612 pMenu
= m_xPopupMenu
->GetPopupMenu(m_nLangParaMenuId
);
613 m_xPopupMenu
->SetItemCommand(m_nLangParaMenuId
, ".uno:SetParagraphLanguageMenu");
616 for (const auto& item
: m_aLangTable_Paragraph
)
618 OUString sCommandString
= ".uno:LanguageStatus?Language:string=Paragraph_" + item
.second
;
619 pMenu
->SetItemCommand(item
.first
, sCommandString
);
622 pMenu
->SetItemCommand(MN_SET_PARA_NONE
, ".uno:LanguageStatus?Language:string=Paragraph_LANGUAGE_NONE");
623 pMenu
->SetItemCommand(MN_SET_PARA_RESET
, ".uno:LanguageStatus?Language:string=Paragraph_RESET_LANGUAGES");
624 pMenu
->SetItemCommand(MN_SET_PARA_MORE
, ".uno:FontDialogForParagraph");
628 void SwSpellPopup::checkRedline()
630 // Let SwView::GetState() already has the logic on when to disable the
631 // accept/reject and the next/prev change items, let it do the decision.
633 // Build an item set that contains a void item for each menu entry. The
634 // WhichId of each item is set, so SwView may clear it.
635 static const sal_uInt16 pRedlineIds
[] = {
636 FN_REDLINE_ACCEPT_DIRECT
,
637 FN_REDLINE_REJECT_DIRECT
,
638 FN_REDLINE_NEXT_CHANGE
,
639 FN_REDLINE_PREV_CHANGE
641 SwDoc
*pDoc
= m_pSh
->GetDoc();
642 SfxItemSetFixed
<FN_REDLINE_ACCEPT_DIRECT
, FN_REDLINE_PREV_CHANGE
> aSet(pDoc
->GetAttrPool());
643 for (sal_uInt16 nWhich
: pRedlineIds
)
645 aSet
.Put(SfxVoidItem(nWhich
));
647 m_pSh
->GetView().GetState(aSet
);
649 // Enable/disable items based on if the which id of the void items are
651 for (sal_uInt16 nWhich
: pRedlineIds
)
654 if (nWhich
== FN_REDLINE_ACCEPT_DIRECT
)
655 nId
= m_nRedlineAcceptId
;
656 else if (nWhich
== FN_REDLINE_REJECT_DIRECT
)
657 nId
= m_nRedlineRejectId
;
658 else if (nWhich
== FN_REDLINE_NEXT_CHANGE
)
659 nId
= m_nRedlineNextId
;
660 else if (nWhich
== FN_REDLINE_PREV_CHANGE
)
661 nId
= m_nRedlinePrevId
;
662 m_xPopupMenu
->EnableItem(nId
, aSet
.Get(nWhich
).Which() != 0);
666 void SwSpellPopup::Execute( const tools::Rectangle
& rWordPos
, vcl::Window
* pWin
)
668 sal_uInt16 nRet
= m_xPopupMenu
->Execute(pWin
, pWin
->LogicToPixel(rWordPos
));
672 void SwSpellPopup::Execute( sal_uInt16 nId
)
674 if (nId
== USHRT_MAX
)
677 if (/*m_bGrammarResults && */nId
== MN_SHORT_COMMENT
)
678 return; // nothing to do since it is the error message (short comment)
680 if (MN_SUGGESTION_START
<= nId
&& nId
<= MN_SUGGESTION_END
)
682 OUString
sApplyRule("");
683 if(m_bGrammarResults
)
684 sApplyRule
+= "Grammar_";
685 else if (m_xSpellAlt
.is())
686 sApplyRule
+= "Spelling_";
687 sApplyRule
+= m_xPopupMenu
->GetItemText(nId
);
689 SfxStringItem
aApplyItem(FN_PARAM_1
, sApplyRule
);
690 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_SPELLCHECK_APPLY_SUGGESTION
, SfxCallMode::SYNCHRON
, { &aApplyItem
});
692 else if(MN_AUTOCORR_START
<= nId
&& nId
<= MN_AUTOCORR_END
)
694 if (m_xSpellAlt
.is())
696 bool bOldIns
= m_pSh
->IsInsMode();
699 PopupMenu
* pMenu
= m_xPopupMenu
->GetPopupMenu(m_nCorrectMenuId
);
701 OUString
aTmp( pMenu
->GetItemText(nId
) );
702 OUString
aOrig( m_xSpellAlt
->getWord() );
704 // if original word has a trailing . (likely the end of a sentence)
705 // and the replacement text hasn't, then add it to the replacement
706 if (!aTmp
.isEmpty() && !aOrig
.isEmpty() &&
707 aOrig
.endsWith(".") && /* !IsAlphaNumeric ??*/
713 SwRewriter aRewriter
;
715 aRewriter
.AddRule(UndoArg1
, m_pSh
->GetCursorDescr());
716 aRewriter
.AddRule(UndoArg2
, SwResId(STR_YIELDS
));
718 OUString aTmpStr
= SwResId(STR_START_QUOTE
) +
719 aTmp
+ SwResId(STR_END_QUOTE
);
720 aRewriter
.AddRule(UndoArg3
, aTmpStr
);
722 m_pSh
->StartUndo(SwUndoId::UI_REPLACE
, &aRewriter
);
723 m_pSh
->StartAction();
725 m_pSh
->Replace(aTmp
, false);
727 /* #102505# EndAction/EndUndo moved down since insertion
728 of temporary auto correction is now undoable two and
729 must reside in the same undo group.*/
731 // record only if it's NOT already present in autocorrection
732 SvxAutoCorrect
* pACorr
= SvxAutoCorrCfg::Get().GetAutoCorrect();
734 OUString
aOrigWord( m_xSpellAlt
->getWord() ) ;
735 OUString
aNewWord( pMenu
->GetItemText(nId
) );
736 SvxPrepareAutoCorrect( aOrigWord
, aNewWord
);
738 pACorr
->PutText( aOrigWord
, aNewWord
, m_nCheckedLanguage
);
740 /* #102505# EndAction/EndUndo moved down since insertion
741 of temporary auto correction is now undoable two and
742 must reside in the same undo group.*/
746 m_pSh
->SetInsMode( bOldIns
);
749 else if (nId
== m_nSpellDialogId
)
751 m_pSh
->Left(SwCursorSkipMode::Chars
, false, 1, false );
753 m_pSh
->GetView().GetViewFrame().GetDispatcher()->
754 Execute( FN_SPELL_GRAMMAR_DIALOG
, SfxCallMode::ASYNCHRON
);
757 else if (nId
== m_nCorrectDialogId
)
759 m_pSh
->GetView().GetViewFrame().GetDispatcher()->Execute( SID_AUTO_CORRECT_DLG
, SfxCallMode::ASYNCHRON
);
761 else if (nId
== MN_IGNORE_SELECTION
)
763 SfxStringItem
aIgnoreString(FN_PARAM_1
, m_bGrammarResults
? OUString("Grammar") : OUString("Spelling"));
764 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_SPELLCHECK_IGNORE
, SfxCallMode::SYNCHRON
, { &aIgnoreString
});
766 else if (nId
== m_nIgnoreWordId
)
768 SfxStringItem
aIgnoreString(FN_PARAM_1
, m_bGrammarResults
? OUString("Grammar") : OUString("Spelling"));
769 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_SPELLCHECK_IGNORE_ALL
, SfxCallMode::SYNCHRON
, { &aIgnoreString
});
771 else if ((MN_DICTIONARIES_START
<= nId
&& nId
<= MN_DICTIONARIES_END
) || nId
== m_nAddId
)
773 OUString
sWord( m_xSpellAlt
->getWord() );
776 if (MN_DICTIONARIES_START
<= nId
&& nId
<= MN_DICTIONARIES_END
)
778 PopupMenu
*pMenu
= m_xPopupMenu
->GetPopupMenu(m_nAddMenuId
);
779 aDicName
= pMenu
->GetItemText(nId
);
782 aDicName
= m_aDicNameSingle
;
784 uno::Reference
< linguistic2::XDictionary
> xDic
;
785 uno::Reference
< linguistic2::XSearchableDictionaryList
> xDicList( LinguMgr::GetDictionaryList() );
787 xDic
= xDicList
->getDictionaryByName( aDicName
);
791 linguistic::DictionaryError nAddRes
= linguistic::AddEntryToDic(xDic
, sWord
, false, OUString());
792 // save modified user-dictionary if it is persistent
793 uno::Reference
< frame::XStorable
> xSavDic( xDic
, uno::UNO_QUERY
);
797 if (linguistic::DictionaryError::NONE
!= nAddRes
&& !xDic
->getEntry(sWord
).is())
799 SvxDicError(m_pSh
->GetView().GetFrameWeld(), nAddRes
);
803 else if ( nId
== MN_EXPLANATION_LINK
&& !m_sExplanationLink
.isEmpty() )
807 uno::Reference
< css::system::XSystemShellExecute
> xSystemShellExecute(
808 css::system::SystemShellExecute::create( ::comphelper::getProcessComponentContext() ) );
809 xSystemShellExecute
->execute( m_sExplanationLink
, OUString(),
810 css::system::SystemShellExecuteFlags::URIS_ONLY
);
812 catch (const uno::Exception
&)
814 uno::Any
exc( ::cppu::getCaughtException() );
815 OUString
msg( ::comphelper::anyToString( exc
) );
816 const SolarMutexGuard guard
;
817 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(m_pSh
->GetView().GetFrameWeld(),
818 VclMessageType::Warning
, VclButtonsType::Ok
, msg
));
819 xBox
->set_title("Explanations");
823 else if (nId
== m_nRedlineAcceptId
|| nId
== m_nRedlineRejectId
824 || nId
== m_nRedlineNextId
|| nId
== m_nRedlinePrevId
)
826 if (nId
== m_nRedlineAcceptId
)
827 nId
= FN_REDLINE_ACCEPT_DIRECT
;
828 else if (nId
== m_nRedlineRejectId
)
829 nId
= FN_REDLINE_REJECT_DIRECT
;
830 else if (nId
== m_nRedlineNextId
)
831 nId
= FN_REDLINE_NEXT_CHANGE
;
832 else if (nId
== m_nRedlinePrevId
)
833 nId
= FN_REDLINE_PREV_CHANGE
;
834 // Let SwView::Execute() handle the redline actions.
835 SfxRequest
aReq(m_pSh
->GetView().GetViewFrame(), nId
);
836 m_pSh
->GetView().Execute(aReq
);
840 if (MN_SET_LANGUAGE_SELECTION_START
<= nId
&& nId
<= MN_SET_LANGUAGE_SELECTION_END
)
842 SfxStringItem
aLangString(SID_LANGUAGE_STATUS
, "Current_" + m_aLangTable_Text
[nId
]);
843 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS
, SfxCallMode::SYNCHRON
, { &aLangString
});
845 else if (nId
== MN_SET_SELECTION_NONE
)
847 SfxStringItem
aLangString(SID_LANGUAGE_STATUS
, "Current_LANGUAGE_NONE");
848 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS
, SfxCallMode::SYNCHRON
, { &aLangString
});
850 else if (nId
== MN_SET_SELECTION_RESET
)
852 SfxStringItem
aLangString(SID_LANGUAGE_STATUS
, "Current_RESET_LANGUAGES");
853 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS
, SfxCallMode::SYNCHRON
, { &aLangString
});
855 else if (nId
== MN_SET_SELECTION_MORE
)
857 SfxStringItem
aDlgString(FN_PARAM_1
, "font");
858 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_CHAR_DLG
, SfxCallMode::SYNCHRON
, { &aDlgString
});
860 else if (MN_SET_LANGUAGE_PARAGRAPH_START
<= nId
&& nId
<= MN_SET_LANGUAGE_PARAGRAPH_END
)
862 SfxStringItem
aLangString(SID_LANGUAGE_STATUS
, "Paragraph_" + m_aLangTable_Paragraph
[nId
]);
863 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS
, SfxCallMode::SYNCHRON
, { &aLangString
});
865 else if (nId
== MN_SET_PARA_NONE
)
867 SfxStringItem
aLangString(SID_LANGUAGE_STATUS
, "Paragraph_LANGUAGE_NONE");
868 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS
, SfxCallMode::SYNCHRON
, { &aLangString
});
870 else if (nId
== MN_SET_PARA_RESET
)
872 SfxStringItem
aLangString(SID_LANGUAGE_STATUS
, "Paragraph_RESET_LANGUAGES");
873 m_pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS
, SfxCallMode::SYNCHRON
, { &aLangString
});
875 else if (nId
== MN_SET_PARA_MORE
)
877 m_pSh
->GetView().GetViewFrame().GetDispatcher()->Execute( SID_CHAR_DLG_FOR_PARAGRAPH
);
881 m_pSh
->EnterStdMode();
884 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */