summaryrefslogtreecommitdiffstats
path: root/sw/source/uibase/lingu/olmenu.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sw/source/uibase/lingu/olmenu.cxx
parentInitial commit. (diff)
downloadlibreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz
libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/uibase/lingu/olmenu.cxx')
-rw-r--r--sw/source/uibase/lingu/olmenu.cxx885
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 000000000..27d4b19ff
--- /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 <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 <svtools/langtab.hxx>
+#include <unotools/lingucfg.hxx>
+#include <unotools/linguprops.hxx>
+#include <vcl/settings.hxx>
+
+#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,
+ const uno::Reference< linguistic2::XSpellAlternatives > &xAlt,
+ const OUString &rParaText)
+ : m_aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/swriter/ui/spellmenu.ui", "")
+ , m_xPopupMenu(m_aBuilder.get_menu("menu"))
+ , m_nIgnoreWordId(m_xPopupMenu->GetItemId("ignoreall"))
+ , m_nAddMenuId(m_xPopupMenu->GetItemId("addmenu"))
+ , m_nAddId(m_xPopupMenu->GetItemId("add"))
+ , m_nSpellDialogId(m_xPopupMenu->GetItemId("spelldialog"))
+ , m_nCorrectMenuId(m_xPopupMenu->GetItemId("correctmenu"))
+ , m_nCorrectDialogId(m_xPopupMenu->GetItemId("correctdialog"))
+ , m_nLangSelectionMenuId(m_xPopupMenu->GetItemId("langselection"))
+ , m_nLangParaMenuId(m_xPopupMenu->GetItemId("langpara"))
+ , m_nRedlineAcceptId(m_xPopupMenu->GetItemId("accept"))
+ , m_nRedlineRejectId(m_xPopupMenu->GetItemId("reject"))
+ , m_nRedlineNextId(m_xPopupMenu->GetItemId("next"))
+ , m_nRedlinePrevId(m_xPopupMenu->GetItemId("prev"))
+ , m_pSh( pWrtSh )
+ , m_xSpellAlt(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(OString(), 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, OString(), 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, OString(), 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( 4 );
+ aSeq[0] = aCurrentLang;
+ aSeq[1] = aScriptTypesInUse;
+ aSeq[2] = aKeyboardLang;
+ aSeq[3] = 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, 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, VclBuilderContainer::getUIRootDir(), "modules/swriter/ui/spellmenu.ui", "")
+ , m_xPopupMenu(m_aBuilder.get_menu("menu"))
+ , m_nIgnoreWordId(m_xPopupMenu->GetItemId("ignoreall"))
+ , m_nAddMenuId(m_xPopupMenu->GetItemId("addmenu"))
+ , m_nAddId(m_xPopupMenu->GetItemId("add"))
+ , m_nSpellDialogId(m_xPopupMenu->GetItemId("spelldialog"))
+ , m_nCorrectMenuId(m_xPopupMenu->GetItemId("correctmenu"))
+ , m_nCorrectDialogId(m_xPopupMenu->GetItemId("correctdialog"))
+ , m_nLangSelectionMenuId(m_xPopupMenu->GetItemId("langselection"))
+ , m_nLangParaMenuId(m_xPopupMenu->GetItemId("langpara"))
+ , m_nRedlineAcceptId(m_xPopupMenu->GetItemId("accept"))
+ , m_nRedlineRejectId(m_xPopupMenu->GetItemId("reject"))
+ , m_nRedlineNextId(m_xPopupMenu->GetItemId("next"))
+ , m_nRedlinePrevId(m_xPopupMenu->GetItemId("prev"))
+ , m_pSh(pWrtSh)
+ , m_sExplanationLink()
+ , 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(OString(), nPos++);
+ m_xPopupMenu->InsertItem(MN_SHORT_COMMENT, aMessageText, MenuItemBits::NOSELECT, OString(), 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, OString(), nPos++);
+ }
+
+ m_xPopupMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics);
+
+ m_xPopupMenu->InsertSeparator(OString(), 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, OString(), nPos++);
+ m_xPopupMenu->SetHelpId(nItemId, HID_LINGU_REPLACE);
+ if (!aSuggestionImageUrl.isEmpty())
+ m_xPopupMenu->SetItemImage(nItemId, aImage);
+
+ ++nItemId;
+ }
+ m_xPopupMenu->InsertSeparator(OString(), 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, OString(), 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( 4 );
+ aSeq[0] = aCurrentLang;
+ aSeq[1] = aScriptTypesInUse;
+ aSeq[2] = aKeyboardLang;
+ aSeq[3] = 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, true);
+
+ SvtLinguConfig().SetProperty( UPN_IS_GRAMMAR_INTERACTIVE, uno::makeAny( true ));
+
+ InitItemCommands(rSuggestions);
+}
+
+SwSpellPopup::~SwSpellPopup() {}
+
+void SwSpellPopup::InitItemCommands(const css::uno::Sequence< OUString >& aSuggestions)
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // 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();
+ SfxItemSet aSet(pDoc->GetAttrPool(), svl::Items<FN_REDLINE_ACCEPT_DIRECT, FN_REDLINE_PREV_CHANGE>{});
+ 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(CRSR_SKIP_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: */