From a133053f94f7c5b05f4354bb4977c2250b470a8a Mon Sep 17 00:00:00 2001 From: Maxim Monastirsky Date: Wed, 11 Nov 2015 15:01:52 +0200 Subject: tdf#93837 Create Thesaurus popup menu controller The old context menu implementation adds the thesaurus sub-menu by manipulating the menu at runtime, which isn't a good idea in general. Since it's a sub-menu anyway, better to have it as a separate controller, so it can be added to the xml, and users could decide if they want it, and where. Most of the code adapted from sfx2 (menu/mnumgr.cxx, menu/thessubmenu.cxx), hence the Apache-based license header. Change-Id: I4f533fcdd5d6480fae8ebcf53ec7c69675025adb --- framework/Library_fwk.mk | 1 + .../source/uielement/thesaurusmenucontroller.cxx | 218 +++++++++++++++++++++ framework/util/fwk.component | 4 + .../data/org/openoffice/Office/UI/Controller.xcu | 11 ++ .../org/openoffice/Office/UI/GenericCommands.xcu | 8 + sfx2/sdi/sfx.sdi | 2 +- 6 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 framework/source/uielement/thesaurusmenucontroller.cxx diff --git a/framework/Library_fwk.mk b/framework/Library_fwk.mk index d07f8b97e37f..3efd33067caa 100644 --- a/framework/Library_fwk.mk +++ b/framework/Library_fwk.mk @@ -153,6 +153,7 @@ $(eval $(call gb_Library_add_exception_objects,fwk,\ framework/source/uielement/statusbarwrapper \ framework/source/uielement/statusindicatorinterfacewrapper \ framework/source/uielement/subtoolbarcontroller \ + framework/source/uielement/thesaurusmenucontroller \ framework/source/uielement/togglebuttontoolbarcontroller \ framework/source/uielement/toolbarmanager \ framework/source/uielement/toolbarmerger \ diff --git a/framework/source/uielement/thesaurusmenucontroller.cxx b/framework/source/uielement/thesaurusmenucontroller.cxx new file mode 100644 index 000000000000..b9457d72e1c9 --- /dev/null +++ b/framework/source/uielement/thesaurusmenucontroller.cxx @@ -0,0 +1,218 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +#include +#include + +class ThesaurusMenuController : public svt::PopupMenuControllerBase +{ +public: + explicit ThesaurusMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual ~ThesaurusMenuController(); + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) throw ( css::uno::RuntimeException, std::exception ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() throw ( css::uno::RuntimeException, std::exception ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() throw ( css::uno::RuntimeException, std::exception ) override; + +private: + virtual void impl_setPopupMenu() override; + void getMeanings( std::vector< OUString >& rSynonyms, const OUString& rWord, const css::lang::Locale& rLocale, size_t nMaxSynonms ); + OUString getThesImplName( const css::lang::Locale& rLocale ) const; + css::uno::Reference< css::linguistic2::XLinguServiceManager2 > m_xLinguServiceManager; + css::uno::Reference< css::linguistic2::XThesaurus > m_xThesaurus; + OUString m_aLastWord; +}; + +namespace { + +OUString RetrieveLabelFromCommand( const OUString& rCmdURL, const OUString& rModuleName ) +{ + if ( rCmdURL.isEmpty() || rModuleName.isEmpty() ) + return OUString(); + + css::uno::Any a; + css::uno::Sequence< css::beans::PropertyValue > aPropSeq; + try + { + css::uno::Reference< css::container::XNameAccess > const xNameAccess( + css::frame::theUICommandDescription::get( comphelper::getProcessComponentContext() ), css::uno::UNO_QUERY_THROW ); + a = xNameAccess->getByName( rModuleName ); + css::uno::Reference< css::container::XNameAccess > xUICommandLabels; + a >>= xUICommandLabels; + a = xUICommandLabels->getByName( rCmdURL ); + a >>= aPropSeq; + } + catch ( const css::uno::Exception& ) + { + SAL_WARN( "fwk.uielement", "Failed to get label for command " << rCmdURL ); + } + + OUString aLabel; + for ( const auto& aProp : aPropSeq ) + { + if ( aProp.Name == "Label" ) + { + aProp.Value >>= aLabel; + } + else if ( aProp.Name == "PopupLabel" ) + { + OUString aStr; + if ( ( aProp.Value >>= aStr ) && !aStr.isEmpty() ) + return aStr; + } + } + return aLabel; +} + +} + +ThesaurusMenuController::ThesaurusMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ) : + svt::PopupMenuControllerBase( rxContext ), + m_xLinguServiceManager( css::linguistic2::LinguServiceManager::create( rxContext ) ), + m_xThesaurus( m_xLinguServiceManager->getThesaurus() ) +{ +} + +ThesaurusMenuController::~ThesaurusMenuController() +{ +} + +void ThesaurusMenuController::statusChanged( const css::frame::FeatureStateEvent& rEvent ) + throw ( css::uno::RuntimeException, std::exception ) +{ + rEvent.State >>= m_aLastWord; + m_xPopupMenu->clear(); + if ( rEvent.IsEnabled ) + impl_setPopupMenu(); +} + +void ThesaurusMenuController::impl_setPopupMenu() +{ + OUString aText = m_aLastWord.getToken(0, '#'); + OUString aIsoLang = m_aLastWord.getToken(1, '#'); + if ( aText.isEmpty() || aIsoLang.isEmpty() ) + return; + + std::vector< OUString > aSynonyms; + css::lang::Locale aLocale = LanguageTag::convertToLocale( aIsoLang ); + getMeanings( aSynonyms, aText, aLocale, 7 /*max number of synonyms to retrieve*/ ); + + VCLXMenu* pAwtMenu = VCLXMenu::GetImplementation( m_xPopupMenu ); + Menu* pVCLMenu = pAwtMenu->GetMenu(); + pVCLMenu->SetMenuFlags( MenuFlags::NoAutoMnemonics ); + if ( aSynonyms.size() > 0 ) + { + SvtLinguConfig aCfg; + Image aImage; + OUString aThesImplName( getThesImplName( aLocale ) ); + OUString aSynonymsImageUrl( aCfg.GetSynonymsContextImage( aThesImplName ) ); + if ( !aThesImplName.isEmpty() && !aSynonymsImageUrl.isEmpty() ) + aImage = Image( aSynonymsImageUrl ); + + for ( const auto& aSynonym : aSynonyms ) + { + const sal_uInt16 nId = pVCLMenu->GetItemCount() + 1; + OUString aItemText( linguistic::GetThesaurusReplaceText( aSynonym ) ); + pVCLMenu->InsertItem( nId, aItemText ); + pVCLMenu->SetItemCommand( nId, ".uno:ThesaurusFromContext?WordReplace:string=" + aItemText ); + + if ( !aSynonymsImageUrl.isEmpty() ) + pVCLMenu->SetItemImage( nId, aImage ); + } + + pVCLMenu->InsertSeparator(); + OUString aThesaurusDialogCmd( ".uno:ThesaurusDialog" ); + pVCLMenu->InsertItem( 100, RetrieveLabelFromCommand( aThesaurusDialogCmd, m_aModuleName ) ); + pVCLMenu->SetItemCommand( 100, aThesaurusDialogCmd ); + } +} + +void ThesaurusMenuController::getMeanings( std::vector< OUString >& rSynonyms, const OUString& rWord, + const css::lang::Locale& rLocale, size_t nMaxSynonms ) +{ + rSynonyms.clear(); + if ( m_xThesaurus.is() && m_xThesaurus->hasLocale( rLocale ) && !rWord.isEmpty() && nMaxSynonms > 0 ) + { + try + { + const css::uno::Sequence< css::uno::Reference< css::linguistic2::XMeaning > > aMeaningSeq( + m_xThesaurus->queryMeanings( rWord, rLocale, css::uno::Sequence< css::beans::PropertyValue >() ) ); + + for ( const auto& xMeaning : aMeaningSeq ) + { + const css::uno::Sequence< OUString > aSynonymSeq( xMeaning->querySynonyms() ); + for ( const auto& aSynonym : aSynonymSeq ) + { + rSynonyms.push_back( aSynonym ); + if ( rSynonyms.size() == nMaxSynonms ) + return; + } + } + } + catch ( const css::uno::Exception& ) + { + SAL_WARN( "fwk.uielement", "Failed to get synonyms" ); + } + } +} + +OUString ThesaurusMenuController::getThesImplName( const css::lang::Locale& rLocale ) const +{ + css::uno::Sequence< OUString > aServiceNames = + m_xLinguServiceManager->getConfiguredServices( "com.sun.star.linguistic2.Thesaurus", rLocale ); + SAL_WARN_IF( aServiceNames.getLength() > 1, "fwk.uielement", "Only one thesaurus is allowed per locale, but found more!" ); + if ( aServiceNames.getLength() == 1 ) + return aServiceNames[0]; + + return OUString(); +} + +OUString ThesaurusMenuController::getImplementationName() + throw ( css::uno::RuntimeException, std::exception ) +{ + return OUString( "com.sun.star.comp.framework.ThesaurusMenuController" ); +} + +css::uno::Sequence< OUString > ThesaurusMenuController::getSupportedServiceNames() + throw ( css::uno::RuntimeException, std::exception ) +{ + css::uno::Sequence< OUString > aRet( 1 ); + aRet[0] = "com.sun.star.frame.PopupMenuController"; + return aRet; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL +com_sun_star_comp_framework_ThesaurusMenuController_get_implementation( + css::uno::XComponentContext* xContext, + css::uno::Sequence< css::uno::Any > const & ) +{ + return cppu::acquire( new ThesaurusMenuController( xContext ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/util/fwk.component b/framework/util/fwk.component index ad1678222417..e1744fc808a6 100644 --- a/framework/util/fwk.component +++ b/framework/util/fwk.component @@ -204,4 +204,8 @@ constructor="com_sun_star_comp_framework_SubToolBarController_get_implementation"> + + + diff --git a/officecfg/registry/data/org/openoffice/Office/UI/Controller.xcu b/officecfg/registry/data/org/openoffice/Office/UI/Controller.xcu index 5e885fd81b89..c4f67118098e 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/Controller.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/Controller.xcu @@ -185,6 +185,17 @@ com.sun.star.comp.framework.SaveAsMenuController + + + .uno:ThesaurusFromContext + + + + + + com.sun.star.comp.framework.ThesaurusMenuController + + diff --git a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu index 161b46cee76c..cab5cbe01bd0 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu @@ -5632,6 +5632,14 @@ 1 + + + Synony~ms + + + 1 + + diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi index e207e8b45b53..f151bc78fd9c 100644 --- a/sfx2/sdi/sfx.sdi +++ b/sfx2/sdi/sfx.sdi @@ -7802,7 +7802,7 @@ SfxInt16Item ThesaurusFromContext SID_THES /* config: */ AccelConfig = FALSE, - MenuConfig = FALSE, + MenuConfig = TRUE, StatusBarConfig = FALSE, ToolBoxConfig = FALSE, GroupId = GID_TEXT; -- cgit v1.2.3