framework/Library_fwk.mk | 1 framework/source/uielement/menubarmanager.cxx | 7 framework/source/uielement/thesaurusmenucontroller.cxx | 218 ++++++++++ framework/source/uielement/uicommanddescription.cxx | 12 framework/util/fwk.component | 4 officecfg/registry/data/org/openoffice/Office/UI/Controller.xcu | 11 officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu | 8 officecfg/registry/schema/org/openoffice/Office/UI/Commands.xcs | 5 sfx2/sdi/sfx.sdi | 2 9 files changed, 266 insertions(+), 2 deletions(-)
New commits: commit a133053f94f7c5b05f4354bb4977c2250b470a8a Author: Maxim Monastirsky <[email protected]> Date: Wed Nov 11 15:01:52 2015 +0200 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 diff --git a/framework/Library_fwk.mk b/framework/Library_fwk.mk index d07f8b9..3efd330 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 0000000..b9457d7 --- /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 <comphelper/processfactory.hxx> +#include <svl/lngmisc.hxx> +#include <svtools/popupmenucontrollerbase.hxx> +#include <unotools/lingucfg.hxx> +#include <vcl/image.hxx> +#include <vcl/menu.hxx> + +#include <com/sun/star/frame/theUICommandDescription.hpp> +#include <com/sun/star/linguistic2/LinguServiceManager.hpp> + +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 ad16782..e1744fc 100644 --- a/framework/util/fwk.component +++ b/framework/util/fwk.component @@ -204,4 +204,8 @@ constructor="com_sun_star_comp_framework_SubToolBarController_get_implementation"> <service name="com.sun.star.frame.ToolbarController"/> </implementation> + <implementation name="com.sun.star.comp.framework.ThesaurusMenuController" + constructor="com_sun_star_comp_framework_ThesaurusMenuController_get_implementation"> + <service name="com.sun.star.frame.PopupMenuController"/> + </implementation> </component> diff --git a/officecfg/registry/data/org/openoffice/Office/UI/Controller.xcu b/officecfg/registry/data/org/openoffice/Office/UI/Controller.xcu index 5e885fd..c4f6711 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 @@ <value>com.sun.star.comp.framework.SaveAsMenuController</value> </prop> </node> + <node oor:name="c17" oor:op="replace"> + <prop oor:name="Command"> + <value>.uno:ThesaurusFromContext</value> + </prop> + <prop oor:name="Module"> + <value/> + </prop> + <prop oor:name="Controller"> + <value>com.sun.star.comp.framework.ThesaurusMenuController</value> + </prop> + </node> </node> <node oor:name="ToolBar"> <node oor:name="ZoomToolBox" oor:op="replace"> diff --git a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu index 161b46c..cab5cbe 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 @@ <value>1</value> </prop> </node> + <node oor:name=".uno:ThesaurusFromContext" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Synony~ms</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> </node> <node oor:name="Popups"> <node oor:name=".uno:HelpMenu" oor:op="replace"> diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi index e207e8b..f151bc7 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; commit 737555eb2ff5f4f90b9794784e1ac8f0451b9b97 Author: Maxim Monastirsky <[email protected]> Date: Wed Oct 28 14:21:03 2015 +0200 tdf#93837 Add a new PopupLabel property Some commands in context menus use different labels than in the menu bar. In the old resource format those labels are defined in the resource file itself. Note that the menu xml has the menu:label attribute, but we can't use it because it lacks localization support, and as such useful only for user customization. The order of consideration now is: 1. Label - Used if Context/PopupLabel isn't defined. (It's also used as the base for toolbar tooltips.) 2. ContextLabel - Overrides Label when in menu or context menu. Useful to drop the context, e.g. "Insert Image" should be only "Image" under "Insert" menu. If exists, that's what returned when asking for the "Label" property, instead of the full label. 3. PopupLabel - Overrides Label/ContextLabel when in context menu. Used to give items in a context menu different labels than in the main menu, e.g. "Paste Special" from the main menu turns to "More Options" when in context menu. It doesn't affect the Label property, and should be asked separately. Change-Id: I7408fc2bfb8d384b0f1a72a78b8c5d7c50de38da diff --git a/framework/source/uielement/menubarmanager.cxx b/framework/source/uielement/menubarmanager.cxx index 2c0db7b..399c667 100644 --- a/framework/source/uielement/menubarmanager.cxx +++ b/framework/source/uielement/menubarmanager.cxx @@ -1096,6 +1096,13 @@ bool MenuBarManager::MustBeHidden( PopupMenu* pPopupMenu, const Reference< XURLT OUString MenuBarManager::RetrieveLabelFromCommand(const OUString& rCmdURL) { + if ( !m_bHasMenuBar ) + { + // This is a context menu, prefer "PopupLabel" over "Label". + OUString aPopupLabel = framework::RetrieveLabelFromCommand(rCmdURL, m_xContext, m_xUICommandLabels,m_xFrame,m_aModuleIdentifier,m_bModuleIdentified,"PopupLabel"); + if ( !aPopupLabel.isEmpty() ) + return aPopupLabel; + } return framework::RetrieveLabelFromCommand(rCmdURL, m_xContext, m_xUICommandLabels,m_xFrame,m_aModuleIdentifier,m_bModuleIdentified,"Label"); } diff --git a/framework/source/uielement/uicommanddescription.cxx b/framework/source/uielement/uicommanddescription.cxx index de99a7b..3f6bc54 100644 --- a/framework/source/uielement/uicommanddescription.cxx +++ b/framework/source/uielement/uicommanddescription.cxx @@ -59,11 +59,13 @@ static const char CONFIGURATION_CMD_ELEMENT_ACCESS[] = "/UserInterface/Comman static const char CONFIGURATION_POP_ELEMENT_ACCESS[] = "/UserInterface/Popups"; static const char CONFIGURATION_PROPERTY_LABEL[] = "Label"; static const char CONFIGURATION_PROPERTY_CONTEXT_LABEL[] = "ContextLabel"; +static const char CONFIGURATION_PROPERTY_POPUP_LABEL[] = "PopupLabel"; // Property names of the resulting Property Set static const char PROPSET_LABEL[] = "Label"; static const char PROPSET_NAME[] = "Name"; static const char PROPSET_POPUP[] = "Popup"; +static const char PROPSET_POPUPLABEL[] = "PopupLabel"; static const char PROPSET_PROPERTIES[] = "Properties"; // Special resource URLs to retrieve additional information @@ -123,6 +125,7 @@ class ConfigurationAccess_UICommand : // Order is necessary for right initializa OUString aLabel; OUString aContextLabel; OUString aCommandName; + OUString aPopupLabel; bool bPopup : 1, bCommandNameCreated : 1; sal_Int32 nProperties; @@ -151,9 +154,11 @@ class ConfigurationAccess_UICommand : // Order is necessary for right initializa OUString m_aConfigPopupAccess; OUString m_aPropUILabel; OUString m_aPropUIContextLabel; + OUString m_aPropUIPopupLabel; OUString m_aPropLabel; OUString m_aPropName; OUString m_aPropPopup; + OUString m_aPropPopupLabel; OUString m_aPropProperties; OUString m_aPrivateResourceURL; Reference< XNameAccess > m_xGenericUICommands; @@ -178,9 +183,11 @@ ConfigurationAccess_UICommand::ConfigurationAccess_UICommand( const OUString& aM m_aConfigPopupAccess( CONFIGURATION_ROOT_ACCESS ), m_aPropUILabel( CONFIGURATION_PROPERTY_LABEL ), m_aPropUIContextLabel( CONFIGURATION_PROPERTY_CONTEXT_LABEL ), + m_aPropUIPopupLabel( CONFIGURATION_PROPERTY_POPUP_LABEL ), m_aPropLabel( PROPSET_LABEL ), m_aPropName( PROPSET_NAME ), m_aPropPopup( PROPSET_POPUP ), + m_aPropPopupLabel( PROPSET_POPUPLABEL ), m_aPropProperties( PROPSET_PROPERTIES ), m_aPrivateResourceURL( PRIVATE_RESOURCE_URL ), m_xGenericUICommands( rGenericUICommands ), @@ -299,7 +306,7 @@ Any ConfigurationAccess_UICommand::getSequenceFromCache( const OUString& aComman if ( !pIter->second.bCommandNameCreated ) fillInfoFromResult( pIter->second, pIter->second.aLabel ); - Sequence< PropertyValue > aPropSeq( 4 ); + Sequence< PropertyValue > aPropSeq( 5 ); aPropSeq[0].Name = m_aPropLabel; aPropSeq[0].Value = !pIter->second.aContextLabel.isEmpty() ? makeAny( pIter->second.aContextLabel ): makeAny( pIter->second.aLabel ); @@ -309,6 +316,8 @@ Any ConfigurationAccess_UICommand::getSequenceFromCache( const OUString& aComman aPropSeq[2].Value <<= pIter->second.bPopup; aPropSeq[3].Name = m_aPropProperties; aPropSeq[3].Value <<= pIter->second.nProperties; + aPropSeq[4].Name = m_aPropPopupLabel; + aPropSeq[4].Value <<= pIter->second.aPopupLabel; return makeAny( aPropSeq ); } @@ -335,6 +344,7 @@ void ConfigurationAccess_UICommand::impl_fill(const Reference< XNameAccess >& _x aCmdToInfo.bPopup = _bPopup; xNameAccess->getByName( m_aPropUILabel ) >>= aCmdToInfo.aLabel; xNameAccess->getByName( m_aPropUIContextLabel ) >>= aCmdToInfo.aContextLabel; + xNameAccess->getByName( m_aPropUIPopupLabel ) >>= aCmdToInfo.aPopupLabel; xNameAccess->getByName( m_aPropProperties ) >>= aCmdToInfo.nProperties; m_aCmdInfoCache.insert( CommandToInfoCache::value_type( aNameSeq[i], aCmdToInfo )); diff --git a/officecfg/registry/schema/org/openoffice/Office/UI/Commands.xcs b/officecfg/registry/schema/org/openoffice/Office/UI/Commands.xcs index f5e1224..85460d2 100644 --- a/officecfg/registry/schema/org/openoffice/Office/UI/Commands.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/UI/Commands.xcs @@ -36,6 +36,11 @@ <desc>A localized text that describes the identifier of a command in a structured menu. </desc> </info> </prop> + <prop oor:name="PopupLabel" oor:type="xs:string" oor:localized="true"> + <info> + <desc>A localized text that describes the identifier of a command in a popup menu.</desc> + </info> + </prop> <prop oor:name="Properties" oor:type="xs:int" oor:nillable="false"> <info> <desc> _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
