diff options
Diffstat (limited to 'sw/source/uibase/lingu/olmenu.cxx')
-rw-r--r-- | sw/source/uibase/lingu/olmenu.cxx | 885 |
1 files changed, 885 insertions, 0 deletions
diff --git a/sw/source/uibase/lingu/olmenu.cxx b/sw/source/uibase/lingu/olmenu.cxx new file mode 100644 index 0000000000..acf06f2e41 --- /dev/null +++ b/sw/source/uibase/lingu/olmenu.cxx @@ -0,0 +1,885 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <SwRewriter.hxx> +#include <cmdid.h> +#include <strings.hrc> +#include <doc.hxx> +#include <edtwin.hxx> +#include <helpids.h> +#include <langhelper.hxx> +#include <bitmaps.hlst> +#include <olmenu.hxx> +#include <swmodule.hxx> +#include <swtypes.hxx> +#include <swundo.hxx> +#include <utility> +#include <view.hxx> +#include <wrtsh.hxx> + +#include <comphelper/lok.hxx> +#include <comphelper/anytostring.hxx> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <editeng/acorrcfg.hxx> +#include <editeng/svxacorr.hxx> +#include <editeng/splwrap.hxx> +#include <editeng/unolingu.hxx> +#include <editeng/editview.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <linguistic/misc.hxx> +#include <rtl/string.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/itemset.hxx> +#include <svl/languageoptions.hxx> +#include <svl/stritem.hxx> +#include <svl/voiditem.hxx> +#include <svtools/langtab.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/linguprops.hxx> +#include <vcl/settings.hxx> +#include <osl/diagnose.h> + +#include <map> + +#include <com/sun/star/document/XDocumentLanguages.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/linguistic2/XLanguageGuessing.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/system/SystemShellExecuteFlags.hpp> +#include <com/sun/star/system/SystemShellExecute.hpp> +#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> + +using namespace ::com::sun::star; + +/// @returns : the language for the selected text that is set for the +/// specified attribute (script type). +/// If there are more than one languages used LANGUAGE_DONTKNOW will be returned. +/// @param nLangWhichId : one of +/// RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE, +/// @returns: the language in use for the selected text. +/// 'In use' means the language(s) matching the script type(s) of the +/// selected text. Or in other words, the language a spell checker would use. +/// If there is more than one language LANGUAGE_DONTKNOW will be returned. +// check if nScriptType includes the script type associated to nLang +static bool lcl_checkScriptType( SvtScriptType nScriptType, LanguageType nLang ) +{ + return bool(nScriptType & SvtLanguageOptions::GetScriptTypeOfLanguage( nLang )); +} + +void SwSpellPopup::fillLangPopupMenu( + PopupMenu *pPopupMenu, + sal_uInt16 nLangItemIdStart, + const uno::Sequence< OUString >& aSeq, + SwWrtShell* pWrtSh, + std::map< sal_Int16, OUString > &rLangTable ) +{ + if (!pPopupMenu) + return; + + // set of languages to be displayed in the sub menus + std::set< OUString > aLangItems; + + OUString aCurLang( aSeq[0] ); + SvtScriptType nScriptType = static_cast<SvtScriptType>(aSeq[1].toInt32()); + OUString aKeyboardLang( aSeq[2] ); + OUString aGuessedTextLang( aSeq[3] ); + + if (!aCurLang.isEmpty() && + LANGUAGE_DONTKNOW != SvtLanguageTable::GetLanguageType( aCurLang )) + aLangItems.insert( aCurLang ); + + //2--System + const AllSettings& rAllSettings = Application::GetSettings(); + LanguageType rSystemLanguage = rAllSettings.GetLanguageTag().getLanguageType(); + if (rSystemLanguage != LANGUAGE_DONTKNOW) + { + if (lcl_checkScriptType( nScriptType, rSystemLanguage )) + aLangItems.insert( SvtLanguageTable::GetLanguageString(rSystemLanguage) ); + } + + //3--UI + LanguageType rUILanguage = rAllSettings.GetUILanguageTag().getLanguageType(); + if (rUILanguage != LANGUAGE_DONTKNOW) + { + if (lcl_checkScriptType(nScriptType, rUILanguage )) + aLangItems.insert( SvtLanguageTable::GetLanguageString(rUILanguage) ); + } + + //4--guessed language + if (!aGuessedTextLang.isEmpty()) + { + if (lcl_checkScriptType(nScriptType, SvtLanguageTable::GetLanguageType(aGuessedTextLang))) + aLangItems.insert( aGuessedTextLang ); + } + + //5--keyboard language + if (!aKeyboardLang.isEmpty()) + { + if (lcl_checkScriptType(nScriptType, SvtLanguageTable::GetLanguageType(aKeyboardLang))) + aLangItems.insert( aKeyboardLang ); + } + + //6--all languages used in current document + uno::Reference< css::frame::XModel > xModel; + uno::Reference< css::frame::XController > xController = pWrtSh->GetView().GetViewFrame().GetFrame().GetFrameInterface()->getController(); + if ( xController.is() ) + xModel = xController->getModel(); + uno::Reference< document::XDocumentLanguages > xDocumentLanguages( xModel, uno::UNO_QUERY ); + /*the description of nScriptType flags + LATIN : 0x0001 + ASIAN : 0x0002 + COMPLEX: 0x0004 + */ + const sal_Int16 nMaxCount = 7; + if (xDocumentLanguages.is()) + { + const uno::Sequence< lang::Locale > rLocales( xDocumentLanguages->getDocumentLanguages( static_cast<sal_Int16>(nScriptType), nMaxCount ) ); + for (const lang::Locale& rLocale : rLocales) + { + if (aLangItems.size() == size_t(nMaxCount)) + break; + if (lcl_checkScriptType( nScriptType, SvtLanguageTable::GetLanguageType( rLocale.Language ))) + aLangItems.insert( rLocale.Language ); + } + } + + sal_uInt16 nItemId = nLangItemIdStart; + for (const OUString& aEntryText : aLangItems) + { + if (aEntryText != SvtLanguageTable::GetLanguageString( LANGUAGE_NONE ) && + aEntryText != "*" && // multiple languages in current selection + !aEntryText.isEmpty()) // 'no language found' from language guessing + { + OSL_ENSURE( nLangItemIdStart <= nItemId && nItemId <= nLangItemIdStart + MN_MAX_NUM_LANG, + "nItemId outside of expected range!" ); + pPopupMenu->InsertItem( nItemId, aEntryText, MenuItemBits::RADIOCHECK ); + if (aEntryText == aCurLang) + { + //make a check mark for the current language + pPopupMenu->CheckItem( nItemId ); + } + rLangTable[ nItemId ] = aEntryText; + ++nItemId; + } + } + + pPopupMenu->InsertItem( nLangItemIdStart + MN_NONE_OFFSET, SwResId( STR_LANGSTATUS_NONE ), MenuItemBits::RADIOCHECK ); + if ( SvtLanguageTable::GetLanguageString( LANGUAGE_NONE ) == aCurLang ) + pPopupMenu->CheckItem( nLangItemIdStart + MN_NONE_OFFSET ); + + pPopupMenu->InsertItem( nLangItemIdStart + MN_RESET_OFFSET, SwResId( STR_RESET_TO_DEFAULT_LANGUAGE ) ); + pPopupMenu->InsertItem( nLangItemIdStart + MN_MORE_OFFSET, SwResId( STR_LANGSTATUS_MORE ) ); +} + +SwSpellPopup::SwSpellPopup( + SwWrtShell* pWrtSh, + uno::Reference< linguistic2::XSpellAlternatives > xAlt, + const OUString &rParaText) + : m_aBuilder(nullptr, AllSettings::GetUIRootDir(), "modules/swriter/ui/spellmenu.ui", "") + , m_xPopupMenu(m_aBuilder.get_menu(u"menu")) + , m_nIgnoreWordId(m_xPopupMenu->GetItemId(u"ignoreall")) + , m_nAddMenuId(m_xPopupMenu->GetItemId(u"addmenu")) + , m_nAddId(m_xPopupMenu->GetItemId(u"add")) + , m_nSpellDialogId(m_xPopupMenu->GetItemId(u"spelldialog")) + , m_nCorrectMenuId(m_xPopupMenu->GetItemId(u"correctmenu")) + , m_nCorrectDialogId(m_xPopupMenu->GetItemId(u"correctdialog")) + , m_nLangSelectionMenuId(m_xPopupMenu->GetItemId(u"langselection")) + , m_nLangParaMenuId(m_xPopupMenu->GetItemId(u"langpara")) + , m_nRedlineAcceptId(m_xPopupMenu->GetItemId(u"accept")) + , m_nRedlineRejectId(m_xPopupMenu->GetItemId(u"reject")) + , m_nRedlineNextId(m_xPopupMenu->GetItemId(u"next")) + , m_nRedlinePrevId(m_xPopupMenu->GetItemId(u"prev")) + , m_pSh( pWrtSh ) + , m_xSpellAlt(std::move(xAlt)) + , m_bGrammarResults(false) +{ + OSL_ENSURE(m_xSpellAlt.is(), "no spelling alternatives available"); + + m_xPopupMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics); + bool bUseImagesInMenus = Application::GetSettings().GetStyleSettings().GetUseImagesInMenus(); + + m_nCheckedLanguage = LANGUAGE_NONE; + css::uno::Sequence< OUString > aSuggestions; + if (m_xSpellAlt.is()) + { + m_nCheckedLanguage = LanguageTag( m_xSpellAlt->getLocale() ).getLanguageType(); + aSuggestions = m_xSpellAlt->getAlternatives(); + } + sal_Int16 nStringCount = static_cast< sal_Int16 >( aSuggestions.getLength() ); + + SvtLinguConfig aCfg; + + PopupMenu *pMenu = m_xPopupMenu->GetPopupMenu(m_nCorrectMenuId); + pMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics); + bool bEnable = false; + if( nStringCount ) + { + Image aImage; + OUString aSuggestionImageUrl; + + if (bUseImagesInMenus) + { + uno::Reference< container::XNamed > xNamed( m_xSpellAlt, uno::UNO_QUERY ); + if (xNamed.is()) + { + aSuggestionImageUrl = aCfg.GetSpellAndGrammarContextSuggestionImage( xNamed->getName() ); + aImage = Image( aSuggestionImageUrl ); + } + } + + m_xPopupMenu->InsertSeparator({}, 0); + bEnable = true; + sal_uInt16 nAutoCorrItemId = MN_AUTOCORR_START; + sal_uInt16 nItemId = MN_SUGGESTION_START; + for (sal_uInt16 i = 0; i < nStringCount; ++i) + { + const OUString aEntry = aSuggestions[ i ]; + m_xPopupMenu->InsertItem(nItemId, aEntry, MenuItemBits::NONE, {}, i); + m_xPopupMenu->SetHelpId(nItemId, HID_LINGU_REPLACE); + if (!aSuggestionImageUrl.isEmpty()) + m_xPopupMenu->SetItemImage(nItemId, aImage); + + pMenu->InsertItem( nAutoCorrItemId, aEntry ); + pMenu->SetHelpId( nAutoCorrItemId, HID_LINGU_AUTOCORR); + + ++nAutoCorrItemId; + ++nItemId; + } + } + + uno::Reference< frame::XFrame > xFrame = pWrtSh->GetView().GetViewFrame().GetFrame().GetFrameInterface(); + OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame)); + + { + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:SpellingAndGrammarDialog", aModuleName); + m_xPopupMenu->SetItemText(m_nSpellDialogId, + vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties)); + } + { + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:AutoCorrectDlg", aModuleName); + m_xPopupMenu->SetItemText(m_nCorrectDialogId, + vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties)); + } + + sal_uInt16 nItemPos = m_xPopupMenu->GetItemPos(m_nIgnoreWordId); + OUString aIgnoreSelection( SwResId( STR_IGNORE_SELECTION ) ); + m_xPopupMenu->InsertItem(MN_IGNORE_SELECTION, aIgnoreSelection, MenuItemBits::NONE, {}, nItemPos); + m_xPopupMenu->SetHelpId(MN_IGNORE_SELECTION, HID_LINGU_IGNORE_SELECTION); + + m_xPopupMenu->EnableItem(m_nCorrectMenuId, bEnable); + + uno::Reference< linguistic2::XLanguageGuessing > xLG = SW_MOD()->GetLanguageGuesser(); + LanguageType nGuessLangWord = LANGUAGE_NONE; + LanguageType nGuessLangPara = LANGUAGE_NONE; + if (m_xSpellAlt.is() && xLG.is()) + { + nGuessLangWord = EditView::CheckLanguage( m_xSpellAlt->getWord(), ::GetSpellChecker(), xLG, false ); + nGuessLangPara = EditView::CheckLanguage( rParaText, ::GetSpellChecker(), xLG, true ); + } + if (nGuessLangWord != LANGUAGE_NONE || nGuessLangPara != LANGUAGE_NONE) + { + // make sure LANGUAGE_NONE gets not used as menu entry + if (nGuessLangWord == LANGUAGE_NONE) + nGuessLangWord = nGuessLangPara; + if (nGuessLangPara == LANGUAGE_NONE) + nGuessLangPara = nGuessLangWord; + } + + pMenu = m_xPopupMenu->GetPopupMenu(m_nAddMenuId); + pMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics); //! necessary to retrieve the correct dictionary name in 'Execute' below + uno::Reference< linguistic2::XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() ); + sal_uInt16 nItemId = MN_DICTIONARIES_START; + if (xDicList.is()) + { + // add the default positive dictionary to dic-list (if not already done). + // This is to ensure that there is at least one dictionary to which + // words could be added. + uno::Reference< linguistic2::XDictionary > xDic( LinguMgr::GetStandardDic() ); + if (xDic.is()) + xDic->setActive( true ); + + m_aDics = xDicList->getDictionaries(); + + for( const uno::Reference< linguistic2::XDictionary >& rDic : std::as_const(m_aDics) ) + { + uno::Reference< linguistic2::XDictionary > xDicTmp = rDic; + if (!xDicTmp.is() || LinguMgr::GetIgnoreAllList() == xDicTmp) + continue; + + uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY ); + LanguageType nActLanguage = LanguageTag( xDicTmp->getLocale() ).getLanguageType(); + if( xDicTmp->isActive() + && xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE + && (m_nCheckedLanguage == nActLanguage || LANGUAGE_NONE == nActLanguage ) + && (!xStor.is() || !xStor->isReadonly()) ) + { + // the extra 1 is because of the (possible) external + // linguistic entry above + pMenu->InsertItem( nItemId, xDicTmp->getName() ); + m_aDicNameSingle = xDicTmp->getName(); + + if (bUseImagesInMenus) + { + uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY ); + if (xSvcInfo.is()) + { + OUString aDictionaryImageUrl( aCfg.GetSpellAndGrammarContextDictionaryImage( + xSvcInfo->getImplementationName() ) ); + if (!aDictionaryImageUrl.isEmpty()) + { + Image aImage( aDictionaryImageUrl ); + pMenu->SetItemImage( nItemId, aImage ); + } + } + } + + ++nItemId; + } + } + } + m_xPopupMenu->EnableItem(m_nAddMenuId, (nItemId - MN_DICTIONARIES_START) > 1); + m_xPopupMenu->EnableItem(m_nAddId, (nItemId - MN_DICTIONARIES_START) == 1); + + //ADD NEW LANGUAGE MENU ITEM + + OUString aScriptTypesInUse( OUString::number( static_cast<int>(pWrtSh->GetScriptType()) ) ); + + // get keyboard language + OUString aKeyboardLang; + SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin(); + LanguageType nLang = rEditWin.GetInputLanguage(); + if (nLang != LANGUAGE_DONTKNOW && nLang != LANGUAGE_SYSTEM) + aKeyboardLang = SvtLanguageTable::GetLanguageString( nLang ); + + // get the language that is in use + OUString aCurrentLang("*"); + nLang = SwLangHelper::GetCurrentLanguage( *pWrtSh ); + if (nLang != LANGUAGE_DONTKNOW) + aCurrentLang = SvtLanguageTable::GetLanguageString( nLang ); + + // build sequence for status value + uno::Sequence< OUString > aSeq{ aCurrentLang, + aScriptTypesInUse, + aKeyboardLang, + SvtLanguageTable::GetLanguageString(nGuessLangWord) }; + + pMenu = m_xPopupMenu->GetPopupMenu(m_nLangSelectionMenuId); + fillLangPopupMenu( pMenu, MN_SET_LANGUAGE_SELECTION_START, aSeq, pWrtSh, m_aLangTable_Text ); + m_xPopupMenu->EnableItem(m_nLangSelectionMenuId); + + pMenu = m_xPopupMenu->GetPopupMenu(m_nLangParaMenuId); + fillLangPopupMenu( pMenu, MN_SET_LANGUAGE_PARAGRAPH_START, aSeq, pWrtSh, m_aLangTable_Paragraph ); + m_xPopupMenu->EnableItem(m_nLangParaMenuId); + + if (bUseImagesInMenus) + m_xPopupMenu->SetItemImage(m_nSpellDialogId, + vcl::CommandInfoProvider::GetImageForCommand(".uno:SpellingAndGrammarDialog", xFrame)); + + checkRedline(); + m_xPopupMenu->RemoveDisabledEntries( true ); + + InitItemCommands(aSuggestions); +} + +SwSpellPopup::SwSpellPopup( + SwWrtShell *pWrtSh, + const linguistic2::ProofreadingResult &rResult, + sal_Int32 nErrorInResult, + const uno::Sequence< OUString > &rSuggestions, + const OUString &rParaText ) + : m_aBuilder(nullptr, AllSettings::GetUIRootDir(), "modules/swriter/ui/spellmenu.ui", "") + , m_xPopupMenu(m_aBuilder.get_menu(u"menu")) + , m_nIgnoreWordId(m_xPopupMenu->GetItemId(u"ignoreall")) + , m_nAddMenuId(m_xPopupMenu->GetItemId(u"addmenu")) + , m_nAddId(m_xPopupMenu->GetItemId(u"add")) + , m_nSpellDialogId(m_xPopupMenu->GetItemId(u"spelldialog")) + , m_nCorrectMenuId(m_xPopupMenu->GetItemId(u"correctmenu")) + , m_nCorrectDialogId(m_xPopupMenu->GetItemId(u"correctdialog")) + , m_nLangSelectionMenuId(m_xPopupMenu->GetItemId(u"langselection")) + , m_nLangParaMenuId(m_xPopupMenu->GetItemId(u"langpara")) + , m_nRedlineAcceptId(m_xPopupMenu->GetItemId(u"accept")) + , m_nRedlineRejectId(m_xPopupMenu->GetItemId(u"reject")) + , m_nRedlineNextId(m_xPopupMenu->GetItemId(u"next")) + , m_nRedlinePrevId(m_xPopupMenu->GetItemId(u"prev")) + , m_pSh(pWrtSh) + , m_bGrammarResults(true) +{ + m_nCheckedLanguage = LanguageTag::convertToLanguageType( rResult.aLocale ); + bool bUseImagesInMenus = Application::GetSettings().GetStyleSettings().GetUseImagesInMenus(); + + sal_uInt16 nPos = 0; + OUString aMessageText( rResult.aErrors[ nErrorInResult ].aShortComment ); + m_xPopupMenu->InsertSeparator({}, nPos++); + m_xPopupMenu->InsertItem(MN_SHORT_COMMENT, aMessageText, MenuItemBits::NOSELECT, {}, nPos++); + if (bUseImagesInMenus) + m_xPopupMenu->SetItemImage(MN_SHORT_COMMENT, Image(StockImage::Yes, BMP_INFO_16)); + + // Add an item to show detailed infos if the FullCommentURL property is defined + const beans::PropertyValues aProperties = rResult.aErrors[ nErrorInResult ].aProperties; + for ( const auto& rProp : aProperties ) + { + if ( rProp.Name == "FullCommentURL" ) + { + uno::Any aValue = rProp.Value; + aValue >>= m_sExplanationLink; + + if ( !m_sExplanationLink.isEmpty( ) ) + break; + } + } + + if ( !m_sExplanationLink.isEmpty( ) ) + { + m_xPopupMenu->InsertItem(MN_EXPLANATION_LINK, SwResId(STR_EXPLANATION_LINK), MenuItemBits::TEXT | MenuItemBits::HELP, {}, nPos++); + } + + m_xPopupMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics); + + m_xPopupMenu->InsertSeparator({}, nPos++); + if ( rSuggestions.hasElements() ) // suggestions available... + { + Image aImage; + OUString aSuggestionImageUrl; + + if (bUseImagesInMenus) + { + uno::Reference< lang::XServiceInfo > xInfo( rResult.xProofreader, uno::UNO_QUERY ); + if (xInfo.is()) + { + aSuggestionImageUrl = SvtLinguConfig().GetSpellAndGrammarContextSuggestionImage( xInfo->getImplementationName() ); + aImage = Image( aSuggestionImageUrl ); + } + } + + sal_uInt16 nItemId = MN_SUGGESTION_START; + for (const OUString& aEntry : std::as_const(rSuggestions)) + { + m_xPopupMenu->InsertItem(nItemId, aEntry, MenuItemBits::NONE, {}, nPos++); + m_xPopupMenu->SetHelpId(nItemId, HID_LINGU_REPLACE); + if (!aSuggestionImageUrl.isEmpty()) + m_xPopupMenu->SetItemImage(nItemId, aImage); + + ++nItemId; + } + m_xPopupMenu->InsertSeparator({}, nPos++); + } + + uno::Reference< frame::XFrame > xFrame = pWrtSh->GetView().GetViewFrame().GetFrame().GetFrameInterface(); + OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame)); + + OUString aIgnoreSelection( SwResId( STR_IGNORE_SELECTION ) ); + auto aCommandProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:SpellingAndGrammarDialog", aModuleName); + m_xPopupMenu->SetItemText(m_nSpellDialogId, + vcl::CommandInfoProvider::GetPopupLabelForCommand(aCommandProperties)); + sal_uInt16 nItemPos = m_xPopupMenu->GetItemPos(m_nIgnoreWordId); + m_xPopupMenu->InsertItem(MN_IGNORE_SELECTION, aIgnoreSelection, MenuItemBits::NONE, {}, nItemPos); + m_xPopupMenu->SetHelpId(MN_IGNORE_SELECTION, HID_LINGU_IGNORE_SELECTION); + + m_xPopupMenu->EnableItem(m_nCorrectMenuId, false); + m_xPopupMenu->EnableItem(m_nCorrectDialogId, false); + + uno::Reference< linguistic2::XLanguageGuessing > xLG = SW_MOD()->GetLanguageGuesser(); + LanguageType nGuessLangWord = LANGUAGE_NONE; + LanguageType nGuessLangPara = LANGUAGE_NONE; + if (xLG.is()) + { + nGuessLangPara = EditView::CheckLanguage( rParaText, ::GetSpellChecker(), xLG, true ); + } + if (nGuessLangWord != LANGUAGE_NONE || nGuessLangPara != LANGUAGE_NONE) + { + // make sure LANGUAGE_NONE gets not used as menu entry + if (nGuessLangWord == LANGUAGE_NONE) + nGuessLangWord = nGuessLangPara; + if (nGuessLangPara == LANGUAGE_NONE) + nGuessLangPara = nGuessLangWord; + } + + m_xPopupMenu->EnableItem(m_nAddMenuId, false); + m_xPopupMenu->EnableItem(m_nAddId, false); + + //ADD NEW LANGUAGE MENU ITEM + + OUString aScriptTypesInUse( OUString::number( static_cast<int>(pWrtSh->GetScriptType()) ) ); + + // get keyboard language + OUString aKeyboardLang; + SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin(); + LanguageType nLang = rEditWin.GetInputLanguage(); + if (nLang != LANGUAGE_DONTKNOW && nLang != LANGUAGE_SYSTEM) + aKeyboardLang = SvtLanguageTable::GetLanguageString( nLang ); + + // get the language that is in use + OUString aCurrentLang("*"); + nLang = SwLangHelper::GetCurrentLanguage( *pWrtSh ); + if (nLang != LANGUAGE_DONTKNOW) + aCurrentLang = SvtLanguageTable::GetLanguageString( nLang ); + + // build sequence for status value + uno::Sequence< OUString > aSeq{ aCurrentLang, + aScriptTypesInUse, + aKeyboardLang, + SvtLanguageTable::GetLanguageString(nGuessLangWord) }; + + PopupMenu *pMenu = m_xPopupMenu->GetPopupMenu(m_nLangSelectionMenuId); + fillLangPopupMenu( pMenu, MN_SET_LANGUAGE_SELECTION_START, aSeq, pWrtSh, m_aLangTable_Text ); + m_xPopupMenu->EnableItem(m_nLangSelectionMenuId); + + pMenu = m_xPopupMenu->GetPopupMenu(m_nLangParaMenuId); + fillLangPopupMenu( pMenu, MN_SET_LANGUAGE_PARAGRAPH_START, aSeq, pWrtSh, m_aLangTable_Paragraph ); + m_xPopupMenu->EnableItem(m_nLangParaMenuId); + + if (bUseImagesInMenus) + m_xPopupMenu->SetItemImage(m_nSpellDialogId, + vcl::CommandInfoProvider::GetImageForCommand(".uno:SpellingAndGrammarDialog", xFrame)); + + checkRedline(); + m_xPopupMenu->RemoveDisabledEntries(true); + + SvtLinguConfig().SetProperty( UPN_IS_GRAMMAR_INTERACTIVE, uno::Any( true )); + + InitItemCommands(rSuggestions); +} + +SwSpellPopup::~SwSpellPopup() {} + +void SwSpellPopup::InitItemCommands(const css::uno::Sequence< OUString >& aSuggestions) +{ + if (!comphelper::LibreOfficeKit::isActive()) + return; + + // None is added only for LOK, it means there is no need to execute anything + m_xPopupMenu->SetItemCommand(MN_SHORT_COMMENT, ".uno:None"); + m_xPopupMenu->SetItemCommand(m_nSpellDialogId, ".uno:SpellingAndGrammarDialog"); + if(m_bGrammarResults) + m_xPopupMenu->SetItemCommand(m_nIgnoreWordId, ".uno:SpellCheckIgnoreAll?Type:string=Grammar"); + else + m_xPopupMenu->SetItemCommand(m_nIgnoreWordId, ".uno:SpellCheckIgnoreAll?Type:string=Spelling"); + if(m_bGrammarResults) + m_xPopupMenu->SetItemCommand(MN_IGNORE_SELECTION, ".uno:SpellCheckIgnore?Type:string=Grammar"); + else + m_xPopupMenu->SetItemCommand(MN_IGNORE_SELECTION, ".uno:SpellCheckIgnore?Type:string=Spelling"); + + for(int i = 0; i < aSuggestions.getLength(); ++i) + { + sal_uInt16 nItemId = MN_SUGGESTION_START + i; + OUString sCommandString = ".uno:SpellCheckApplySuggestion?ApplyRule:string="; + if(m_bGrammarResults) + sCommandString += "Grammar_"; + else if (m_xSpellAlt.is()) + sCommandString += "Spelling_"; + sCommandString += m_xPopupMenu->GetItemText(nItemId); + m_xPopupMenu->SetItemCommand(nItemId, sCommandString); + } + + PopupMenu *pMenu = m_xPopupMenu->GetPopupMenu(m_nLangSelectionMenuId); + m_xPopupMenu->SetItemCommand(m_nLangSelectionMenuId, ".uno:SetSelectionLanguageMenu"); + if(pMenu) + { + for (const auto& item : m_aLangTable_Text) + { + OUString sCommandString = ".uno:LanguageStatus?Language:string=Current_" + item.second; + pMenu->SetItemCommand(item.first, sCommandString); + } + + pMenu->SetItemCommand(MN_SET_SELECTION_NONE, ".uno:LanguageStatus?Language:string=Current_LANGUAGE_NONE"); + pMenu->SetItemCommand(MN_SET_SELECTION_RESET, ".uno:LanguageStatus?Language:string=Current_RESET_LANGUAGES"); + pMenu->SetItemCommand(MN_SET_SELECTION_MORE, ".uno:FontDialog?Page:string=font"); + } + + pMenu = m_xPopupMenu->GetPopupMenu(m_nLangParaMenuId); + m_xPopupMenu->SetItemCommand(m_nLangParaMenuId, ".uno:SetParagraphLanguageMenu"); + if(pMenu) + { + for (const auto& item : m_aLangTable_Paragraph) + { + OUString sCommandString = ".uno:LanguageStatus?Language:string=Paragraph_" + item.second; + pMenu->SetItemCommand(item.first, sCommandString); + } + + pMenu->SetItemCommand(MN_SET_PARA_NONE, ".uno:LanguageStatus?Language:string=Paragraph_LANGUAGE_NONE"); + pMenu->SetItemCommand(MN_SET_PARA_RESET, ".uno:LanguageStatus?Language:string=Paragraph_RESET_LANGUAGES"); + pMenu->SetItemCommand(MN_SET_PARA_MORE, ".uno:FontDialogForParagraph"); + } +} + +void SwSpellPopup::checkRedline() +{ + // Let SwView::GetState() already has the logic on when to disable the + // accept/reject and the next/prev change items, let it do the decision. + + // Build an item set that contains a void item for each menu entry. The + // WhichId of each item is set, so SwView may clear it. + static const sal_uInt16 pRedlineIds[] = { + FN_REDLINE_ACCEPT_DIRECT, + FN_REDLINE_REJECT_DIRECT, + FN_REDLINE_NEXT_CHANGE, + FN_REDLINE_PREV_CHANGE + }; + SwDoc *pDoc = m_pSh->GetDoc(); + SfxItemSetFixed<FN_REDLINE_ACCEPT_DIRECT, FN_REDLINE_PREV_CHANGE> aSet(pDoc->GetAttrPool()); + for (sal_uInt16 nWhich : pRedlineIds) + { + aSet.Put(SfxVoidItem(nWhich)); + } + m_pSh->GetView().GetState(aSet); + + // Enable/disable items based on if the which id of the void items are + // cleared or not. + for (sal_uInt16 nWhich : pRedlineIds) + { + sal_uInt16 nId(0); + if (nWhich == FN_REDLINE_ACCEPT_DIRECT) + nId = m_nRedlineAcceptId; + else if (nWhich == FN_REDLINE_REJECT_DIRECT) + nId = m_nRedlineRejectId; + else if (nWhich == FN_REDLINE_NEXT_CHANGE) + nId = m_nRedlineNextId; + else if (nWhich == FN_REDLINE_PREV_CHANGE) + nId = m_nRedlinePrevId; + m_xPopupMenu->EnableItem(nId, aSet.Get(nWhich).Which() != 0); + } +} + +void SwSpellPopup::Execute( const tools::Rectangle& rWordPos, vcl::Window* pWin ) +{ + sal_uInt16 nRet = m_xPopupMenu->Execute(pWin, pWin->LogicToPixel(rWordPos)); + Execute( nRet ); +} + +void SwSpellPopup::Execute( sal_uInt16 nId ) +{ + if (nId == USHRT_MAX) + return; + + if (/*m_bGrammarResults && */nId == MN_SHORT_COMMENT) + return; // nothing to do since it is the error message (short comment) + + if (MN_SUGGESTION_START <= nId && nId <= MN_SUGGESTION_END) + { + OUString sApplyRule(""); + if(m_bGrammarResults) + sApplyRule += "Grammar_"; + else if (m_xSpellAlt.is()) + sApplyRule += "Spelling_"; + sApplyRule += m_xPopupMenu->GetItemText(nId); + + SfxStringItem aApplyItem(FN_PARAM_1, sApplyRule); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_SPELLCHECK_APPLY_SUGGESTION, SfxCallMode::SYNCHRON, { &aApplyItem }); + } + else if(MN_AUTOCORR_START <= nId && nId <= MN_AUTOCORR_END) + { + if (m_xSpellAlt.is()) + { + bool bOldIns = m_pSh->IsInsMode(); + m_pSh->SetInsMode(); + + PopupMenu* pMenu = m_xPopupMenu->GetPopupMenu(m_nCorrectMenuId); + assert(pMenu); + OUString aTmp( pMenu->GetItemText(nId) ); + OUString aOrig( m_xSpellAlt->getWord() ); + + // if original word has a trailing . (likely the end of a sentence) + // and the replacement text hasn't, then add it to the replacement + if (!aTmp.isEmpty() && !aOrig.isEmpty() && + aOrig.endsWith(".") && /* !IsAlphaNumeric ??*/ + !aTmp.endsWith(".")) + { + aTmp += "."; + } + + SwRewriter aRewriter; + + aRewriter.AddRule(UndoArg1, m_pSh->GetCursorDescr()); + aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS)); + + OUString aTmpStr = SwResId(STR_START_QUOTE) + + aTmp + SwResId(STR_END_QUOTE); + aRewriter.AddRule(UndoArg3, aTmpStr); + + m_pSh->StartUndo(SwUndoId::UI_REPLACE, &aRewriter); + m_pSh->StartAction(); + + m_pSh->Replace(aTmp, false); + + /* #102505# EndAction/EndUndo moved down since insertion + of temporary auto correction is now undoable two and + must reside in the same undo group.*/ + + // record only if it's NOT already present in autocorrection + SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect(); + + OUString aOrigWord( m_xSpellAlt->getWord() ) ; + OUString aNewWord( pMenu->GetItemText(nId) ); + SvxPrepareAutoCorrect( aOrigWord, aNewWord ); + + pACorr->PutText( aOrigWord, aNewWord, m_nCheckedLanguage ); + + /* #102505# EndAction/EndUndo moved down since insertion + of temporary auto correction is now undoable two and + must reside in the same undo group.*/ + m_pSh->EndAction(); + m_pSh->EndUndo(); + + m_pSh->SetInsMode( bOldIns ); + } + } + else if (nId == m_nSpellDialogId) + { + m_pSh->Left(SwCursorSkipMode::Chars, false, 1, false ); + { + m_pSh->GetView().GetViewFrame().GetDispatcher()-> + Execute( FN_SPELL_GRAMMAR_DIALOG, SfxCallMode::ASYNCHRON ); + } + } + else if (nId == m_nCorrectDialogId) + { + m_pSh->GetView().GetViewFrame().GetDispatcher()->Execute( SID_AUTO_CORRECT_DLG, SfxCallMode::ASYNCHRON ); + } + else if (nId == MN_IGNORE_SELECTION) + { + SfxStringItem aIgnoreString(FN_PARAM_1, m_bGrammarResults ? OUString("Grammar") : OUString("Spelling")); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_SPELLCHECK_IGNORE, SfxCallMode::SYNCHRON, { &aIgnoreString }); + } + else if (nId == m_nIgnoreWordId) + { + SfxStringItem aIgnoreString(FN_PARAM_1, m_bGrammarResults ? OUString("Grammar") : OUString("Spelling")); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_SPELLCHECK_IGNORE_ALL, SfxCallMode::SYNCHRON, { &aIgnoreString }); + } + else if ((MN_DICTIONARIES_START <= nId && nId <= MN_DICTIONARIES_END) || nId == m_nAddId) + { + OUString sWord( m_xSpellAlt->getWord() ); + OUString aDicName; + + if (MN_DICTIONARIES_START <= nId && nId <= MN_DICTIONARIES_END) + { + PopupMenu *pMenu = m_xPopupMenu->GetPopupMenu(m_nAddMenuId); + aDicName = pMenu->GetItemText(nId); + } + else + aDicName = m_aDicNameSingle; + + uno::Reference< linguistic2::XDictionary > xDic; + uno::Reference< linguistic2::XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() ); + if (xDicList.is()) + xDic = xDicList->getDictionaryByName( aDicName ); + + if (xDic.is()) + { + linguistic::DictionaryError nAddRes = linguistic::AddEntryToDic(xDic, sWord, false, OUString()); + // save modified user-dictionary if it is persistent + uno::Reference< frame::XStorable > xSavDic( xDic, uno::UNO_QUERY ); + if (xSavDic.is()) + xSavDic->store(); + + if (linguistic::DictionaryError::NONE != nAddRes && !xDic->getEntry(sWord).is()) + { + SvxDicError(m_pSh->GetView().GetFrameWeld(), nAddRes); + } + } + } + else if ( nId == MN_EXPLANATION_LINK && !m_sExplanationLink.isEmpty() ) + { + try + { + uno::Reference< css::system::XSystemShellExecute > xSystemShellExecute( + css::system::SystemShellExecute::create( ::comphelper::getProcessComponentContext() ) ); + xSystemShellExecute->execute( m_sExplanationLink, OUString(), + css::system::SystemShellExecuteFlags::URIS_ONLY ); + } + catch (const uno::Exception&) + { + uno::Any exc( ::cppu::getCaughtException() ); + OUString msg( ::comphelper::anyToString( exc ) ); + const SolarMutexGuard guard; + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_pSh->GetView().GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, msg)); + xBox->set_title("Explanations"); + xBox->run(); + } + } + else if (nId == m_nRedlineAcceptId || nId == m_nRedlineRejectId + || nId == m_nRedlineNextId || nId == m_nRedlinePrevId) + { + if (nId == m_nRedlineAcceptId) + nId = FN_REDLINE_ACCEPT_DIRECT; + else if (nId == m_nRedlineRejectId) + nId = FN_REDLINE_REJECT_DIRECT; + else if (nId == m_nRedlineNextId) + nId = FN_REDLINE_NEXT_CHANGE; + else if (nId == m_nRedlinePrevId) + nId = FN_REDLINE_PREV_CHANGE; + // Let SwView::Execute() handle the redline actions. + SfxRequest aReq(m_pSh->GetView().GetViewFrame(), nId); + m_pSh->GetView().Execute(aReq); + } + else + { + if (MN_SET_LANGUAGE_SELECTION_START <= nId && nId <= MN_SET_LANGUAGE_SELECTION_END) + { + SfxStringItem aLangString(SID_LANGUAGE_STATUS, "Current_" + m_aLangTable_Text[nId]); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS, SfxCallMode::SYNCHRON, { &aLangString }); + } + else if (nId == MN_SET_SELECTION_NONE) + { + SfxStringItem aLangString(SID_LANGUAGE_STATUS, "Current_LANGUAGE_NONE"); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS, SfxCallMode::SYNCHRON, { &aLangString }); + } + else if (nId == MN_SET_SELECTION_RESET) + { + SfxStringItem aLangString(SID_LANGUAGE_STATUS, "Current_RESET_LANGUAGES"); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS, SfxCallMode::SYNCHRON, { &aLangString }); + } + else if (nId == MN_SET_SELECTION_MORE) + { + SfxStringItem aDlgString(FN_PARAM_1, "font"); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_CHAR_DLG, SfxCallMode::SYNCHRON, { &aDlgString }); + } + else if (MN_SET_LANGUAGE_PARAGRAPH_START <= nId && nId <= MN_SET_LANGUAGE_PARAGRAPH_END) + { + SfxStringItem aLangString(SID_LANGUAGE_STATUS, "Paragraph_" + m_aLangTable_Paragraph[nId]); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS, SfxCallMode::SYNCHRON, { &aLangString }); + } + else if (nId == MN_SET_PARA_NONE) + { + SfxStringItem aLangString(SID_LANGUAGE_STATUS, "Paragraph_LANGUAGE_NONE"); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS, SfxCallMode::SYNCHRON, { &aLangString }); + } + else if (nId == MN_SET_PARA_RESET) + { + SfxStringItem aLangString(SID_LANGUAGE_STATUS, "Paragraph_RESET_LANGUAGES"); + m_pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS, SfxCallMode::SYNCHRON, { &aLangString }); + } + else if (nId == MN_SET_PARA_MORE) + { + m_pSh->GetView().GetViewFrame().GetDispatcher()->Execute( SID_CHAR_DLG_FOR_PARAGRAPH ); + } + } + + m_pSh->EnterStdMode(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |