466 lines
15 KiB
C++
466 lines
15 KiB
C++
/* -*- 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 <uielement/newmenucontroller.hxx>
|
|
#include <menuconfiguration.hxx>
|
|
|
|
#include <services.h>
|
|
|
|
#include <com/sun/star/awt/MenuItemType.hpp>
|
|
#include <com/sun/star/beans/PropertyValue.hpp>
|
|
#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
|
|
#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
|
|
#include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
|
|
#include <com/sun/star/frame/ModuleManager.hpp>
|
|
#include <com/sun/star/frame/XFrame.hpp>
|
|
#include <com/sun/star/util/XURLTransformer.hpp>
|
|
|
|
#include <comphelper/propertyvalue.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/commandinfoprovider.hxx>
|
|
#include <svtools/acceleratorexecute.hxx>
|
|
#include <svtools/imagemgr.hxx>
|
|
#include <toolkit/awt/vclxmenu.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <unotools/dynamicmenuoptions.hxx>
|
|
#include <osl/mutex.hxx>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
|
|
// Defines
|
|
constexpr OUString aSlotNewDocDirect = u".uno:AddDirect"_ustr;
|
|
constexpr OUStringLiteral aSlotAutoPilot = u".uno:AutoPilotMenu";
|
|
|
|
using namespace com::sun::star::uno;
|
|
using namespace com::sun::star::lang;
|
|
using namespace com::sun::star::frame;
|
|
using namespace com::sun::star::beans;
|
|
using namespace com::sun::star::util;
|
|
using namespace com::sun::star::ui;
|
|
|
|
namespace framework
|
|
{
|
|
|
|
OUString SAL_CALL NewMenuController::getImplementationName()
|
|
{
|
|
return u"com.sun.star.comp.framework.NewMenuController"_ustr;
|
|
}
|
|
|
|
sal_Bool SAL_CALL NewMenuController::supportsService( const OUString& sServiceName )
|
|
{
|
|
return cppu::supportsService(this, sServiceName);
|
|
}
|
|
|
|
css::uno::Sequence< OUString > SAL_CALL NewMenuController::getSupportedServiceNames()
|
|
{
|
|
return { SERVICENAME_POPUPMENUCONTROLLER };
|
|
}
|
|
|
|
void NewMenuController::setMenuImages( PopupMenu* pPopupMenu, bool bSetImages )
|
|
{
|
|
sal_uInt16 nItemCount = pPopupMenu->GetItemCount();
|
|
Reference< XFrame > xFrame( m_xFrame );
|
|
|
|
for ( sal_uInt16 i = 0; i < nItemCount; i++ )
|
|
{
|
|
sal_uInt16 nItemId = pPopupMenu->GetItemId( i );
|
|
if ( nItemId != 0 )
|
|
{
|
|
if ( bSetImages )
|
|
{
|
|
OUString aImageId;
|
|
OUString aCmd( pPopupMenu->GetItemCommand( nItemId ) );
|
|
void* nAttributePtr = pPopupMenu->GetUserValue( nItemId );
|
|
MenuAttributes* pAttributes = static_cast<MenuAttributes *>(nAttributePtr);
|
|
if (pAttributes)
|
|
aImageId = pAttributes->aImageId;
|
|
|
|
INetURLObject aURLObj( aImageId.isEmpty() ? aCmd : aImageId );
|
|
Image aImage = SvFileInformationManager::GetImageNoDefault( aURLObj );
|
|
if ( !aImage )
|
|
aImage = vcl::CommandInfoProvider::GetImageForCommand(aCmd, xFrame);
|
|
|
|
if ( !!aImage )
|
|
pPopupMenu->SetItemImage( nItemId, aImage );
|
|
}
|
|
else
|
|
pPopupMenu->SetItemImage( nItemId, Image() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void NewMenuController::determineAndSetNewDocAccel(const css::awt::KeyEvent& rKeyCode)
|
|
{
|
|
sal_uInt16 nCount(m_xPopupMenu->getItemCount());
|
|
sal_uInt16 nId( 0 );
|
|
OUString aCommand;
|
|
|
|
if ( !m_aEmptyDocURL.isEmpty() )
|
|
{
|
|
// Search for the empty document URL
|
|
|
|
for ( sal_uInt16 i = 0; i < nCount; i++ )
|
|
{
|
|
if (m_xPopupMenu->getItemType(i) != css::awt::MenuItemType_SEPARATOR)
|
|
{
|
|
nId = m_xPopupMenu->getItemId(i);
|
|
aCommand = m_xPopupMenu->getCommand(nId);
|
|
if ( aCommand.startsWith( m_aEmptyDocURL ) )
|
|
{
|
|
m_xPopupMenu->setAcceleratorKeyEvent(nId, rKeyCode);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void NewMenuController::setAccelerators()
|
|
{
|
|
if ( !m_bModuleIdentified )
|
|
return;
|
|
|
|
Reference< XAcceleratorConfiguration > xDocAccelCfg( m_xDocAcceleratorManager );
|
|
Reference< XAcceleratorConfiguration > xModuleAccelCfg( m_xModuleAcceleratorManager );
|
|
Reference< XAcceleratorConfiguration > xGlobalAccelCfg( m_xGlobalAcceleratorManager );
|
|
|
|
if ( !m_bAcceleratorCfg )
|
|
{
|
|
// Retrieve references on demand
|
|
m_bAcceleratorCfg = true;
|
|
if ( !xDocAccelCfg.is() )
|
|
{
|
|
Reference< XController > xController = m_xFrame->getController();
|
|
Reference< XModel > xModel;
|
|
if ( xController.is() )
|
|
{
|
|
xModel = xController->getModel();
|
|
if ( xModel.is() )
|
|
{
|
|
Reference< XUIConfigurationManagerSupplier > xSupplier( xModel, UNO_QUERY );
|
|
if ( xSupplier.is() )
|
|
{
|
|
Reference< XUIConfigurationManager > xDocUICfgMgr = xSupplier->getUIConfigurationManager();
|
|
if ( xDocUICfgMgr.is() )
|
|
{
|
|
xDocAccelCfg = xDocUICfgMgr->getShortCutManager();
|
|
m_xDocAcceleratorManager = xDocAccelCfg;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !xModuleAccelCfg.is() )
|
|
{
|
|
Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier =
|
|
theModuleUIConfigurationManagerSupplier::get( m_xContext );
|
|
Reference< XUIConfigurationManager > xUICfgMgr = xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleIdentifier );
|
|
if ( xUICfgMgr.is() )
|
|
{
|
|
xModuleAccelCfg = xUICfgMgr->getShortCutManager();
|
|
m_xModuleAcceleratorManager = xModuleAccelCfg;
|
|
}
|
|
}
|
|
|
|
if ( !xGlobalAccelCfg.is() )
|
|
{
|
|
xGlobalAccelCfg = GlobalAcceleratorConfiguration::create( m_xContext );
|
|
m_xGlobalAcceleratorManager = xGlobalAccelCfg;
|
|
}
|
|
}
|
|
|
|
vcl::KeyCode aEmptyKeyCode;
|
|
sal_uInt16 nItemCount(m_xPopupMenu->getItemCount());
|
|
std::vector< vcl::KeyCode > aMenuShortCuts;
|
|
std::vector< OUString > aCmds;
|
|
std::vector< sal_uInt16 > aIds;
|
|
for ( sal_uInt16 i = 0; i < nItemCount; i++ )
|
|
{
|
|
if (m_xPopupMenu->getItemType(i) != css::awt::MenuItemType_SEPARATOR)
|
|
{
|
|
sal_uInt16 nId(m_xPopupMenu->getItemId(i));
|
|
aIds.push_back( nId );
|
|
aMenuShortCuts.push_back( aEmptyKeyCode );
|
|
aCmds.push_back(m_xPopupMenu->getCommand(nId));
|
|
}
|
|
}
|
|
|
|
sal_uInt32 nSeqCount( aIds.size() );
|
|
|
|
if ( m_bNewMenu )
|
|
nSeqCount+=1;
|
|
|
|
Sequence< OUString > aSeq( nSeqCount );
|
|
auto aSeqRange = asNonConstRange(aSeq);
|
|
|
|
// Add a special command for our "New" menu.
|
|
if ( m_bNewMenu )
|
|
{
|
|
aSeqRange[nSeqCount-1] = m_aCommandURL;
|
|
aMenuShortCuts.push_back( aEmptyKeyCode );
|
|
}
|
|
|
|
const sal_uInt32 nCount = aCmds.size();
|
|
for ( sal_uInt32 i = 0; i < nCount; i++ )
|
|
aSeqRange[i] = aCmds[i];
|
|
|
|
if ( m_xGlobalAcceleratorManager.is() )
|
|
retrieveShortcutsFromConfiguration( xGlobalAccelCfg, aSeq, aMenuShortCuts );
|
|
if ( m_xModuleAcceleratorManager.is() )
|
|
retrieveShortcutsFromConfiguration( xModuleAccelCfg, aSeq, aMenuShortCuts );
|
|
if ( m_xDocAcceleratorManager.is() )
|
|
retrieveShortcutsFromConfiguration( xDocAccelCfg, aSeq, aMenuShortCuts );
|
|
|
|
const sal_uInt32 nCount2 = aIds.size();
|
|
for ( sal_uInt32 i = 0; i < nCount2; i++ )
|
|
m_xPopupMenu->setAcceleratorKeyEvent(aIds[i], svt::AcceleratorExecute::st_VCLKey2AWTKey(aMenuShortCuts[i]));
|
|
|
|
// Special handling for "New" menu short-cut should be set at the
|
|
// document which will be opened using it.
|
|
if ( m_bNewMenu )
|
|
{
|
|
if ( aMenuShortCuts[nSeqCount-1] != aEmptyKeyCode )
|
|
determineAndSetNewDocAccel(svt::AcceleratorExecute::st_VCLKey2AWTKey(aMenuShortCuts[nSeqCount-1]));
|
|
}
|
|
}
|
|
|
|
// static
|
|
void NewMenuController::retrieveShortcutsFromConfiguration(
|
|
const Reference< XAcceleratorConfiguration >& rAccelCfg,
|
|
const Sequence< OUString >& rCommands,
|
|
std::vector< vcl::KeyCode >& aMenuShortCuts )
|
|
{
|
|
if ( !rAccelCfg.is() )
|
|
return;
|
|
|
|
try
|
|
{
|
|
css::awt::KeyEvent aKeyEvent;
|
|
Sequence< Any > aSeqKeyCode = rAccelCfg->getPreferredKeyEventsForCommandList( rCommands );
|
|
for ( sal_Int32 i = 0; i < aSeqKeyCode.getLength(); i++ )
|
|
{
|
|
if ( aSeqKeyCode[i] >>= aKeyEvent )
|
|
aMenuShortCuts[i] = svt::AcceleratorExecute::st_AWTKey2VCLKey( aKeyEvent );
|
|
}
|
|
}
|
|
catch ( const IllegalArgumentException& )
|
|
{
|
|
}
|
|
}
|
|
|
|
NewMenuController::NewMenuController( const css::uno::Reference< css::uno::XComponentContext >& xContext ) :
|
|
svt::PopupMenuControllerBase( xContext ),
|
|
m_bShowImages( true ),
|
|
m_bNewMenu( false ),
|
|
m_bModuleIdentified( false ),
|
|
m_bAcceleratorCfg( false ),
|
|
m_aTargetFrame( u"_default"_ustr ),
|
|
m_xContext( xContext )
|
|
{
|
|
}
|
|
|
|
NewMenuController::~NewMenuController()
|
|
{
|
|
}
|
|
|
|
// private function
|
|
void NewMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu > const & rPopupMenu )
|
|
{
|
|
VCLXPopupMenu* pPopupMenu = static_cast<VCLXPopupMenu *>(dynamic_cast<VCLXMenu*>( rPopupMenu.get() ));
|
|
PopupMenu* pVCLPopupMenu = nullptr;
|
|
|
|
SolarMutexGuard aSolarMutexGuard;
|
|
|
|
resetPopupMenu( rPopupMenu );
|
|
if ( pPopupMenu )
|
|
pVCLPopupMenu = static_cast<PopupMenu *>(pPopupMenu->GetMenu());
|
|
|
|
if ( !pVCLPopupMenu )
|
|
return;
|
|
|
|
Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
|
|
URL aTargetURL;
|
|
aTargetURL.Complete = m_bNewMenu ? aSlotNewDocDirect : OUString(aSlotAutoPilot);
|
|
m_xURLTransformer->parseStrict( aTargetURL );
|
|
Reference< XDispatch > xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
|
|
if(xMenuItemDispatch == nullptr)
|
|
return;
|
|
|
|
const std::vector< SvtDynMenuEntry > aDynamicMenuEntries =
|
|
SvtDynamicMenuOptions::GetMenu( m_bNewMenu ? EDynamicMenuType::NewMenu : EDynamicMenuType::WizardMenu );
|
|
|
|
sal_uInt16 nItemId = 1;
|
|
|
|
for ( const auto& aDynamicMenuEntry : aDynamicMenuEntries )
|
|
{
|
|
if ( aDynamicMenuEntry.sTitle.isEmpty() && aDynamicMenuEntry.sURL.isEmpty() )
|
|
continue;
|
|
|
|
if ( aDynamicMenuEntry.sURL == "private:separator" )
|
|
rPopupMenu->insertSeparator(-1);
|
|
else
|
|
{
|
|
rPopupMenu->insertItem(nItemId, aDynamicMenuEntry.sTitle, 0, -1);
|
|
rPopupMenu->setCommand(nItemId, aDynamicMenuEntry.sURL);
|
|
|
|
void* nAttributePtr = MenuAttributes::CreateAttribute( aDynamicMenuEntry.sTargetName, aDynamicMenuEntry.sImageIdentifier );
|
|
pPopupMenu->setUserValue(nItemId, nAttributePtr, MenuAttributes::ReleaseAttribute);
|
|
|
|
nItemId++;
|
|
}
|
|
}
|
|
|
|
if ( m_bShowImages )
|
|
setMenuImages( pVCLPopupMenu, m_bShowImages );
|
|
}
|
|
|
|
// XEventListener
|
|
void SAL_CALL NewMenuController::disposing( const EventObject& )
|
|
{
|
|
Reference< css::awt::XMenuListener > xHolder(this);
|
|
|
|
std::unique_lock aLock( m_aMutex );
|
|
m_xFrame.clear();
|
|
m_xDispatch.clear();
|
|
m_xContext.clear();
|
|
|
|
if ( m_xPopupMenu.is() )
|
|
m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(this) );
|
|
m_xPopupMenu.clear();
|
|
}
|
|
|
|
// XStatusListener
|
|
void SAL_CALL NewMenuController::statusChanged( const FeatureStateEvent& Event )
|
|
{
|
|
Event.State >>= m_aEmptyDocURL;
|
|
}
|
|
|
|
// XMenuListener
|
|
void SAL_CALL NewMenuController::itemSelected( const css::awt::MenuEvent& rEvent )
|
|
{
|
|
Reference< css::awt::XPopupMenu > xPopupMenu;
|
|
Reference< XComponentContext > xContext;
|
|
|
|
{
|
|
std::unique_lock aLock(m_aMutex);
|
|
xPopupMenu = m_xPopupMenu;
|
|
xContext = m_xContext;
|
|
}
|
|
|
|
if ( !xPopupMenu.is() )
|
|
return;
|
|
|
|
VCLXPopupMenu* pPopupMenu = static_cast<VCLXPopupMenu *>(dynamic_cast<VCLXMenu*>( xPopupMenu.get() ));
|
|
if ( !pPopupMenu )
|
|
return;
|
|
|
|
OUString aURL;
|
|
OUString aTargetFrame( m_aTargetFrame );
|
|
|
|
{
|
|
SolarMutexGuard aSolarMutexGuard;
|
|
aURL = pPopupMenu->getCommand(rEvent.MenuId);
|
|
void* nAttributePtr = pPopupMenu->getUserValue(rEvent.MenuId);
|
|
MenuAttributes* pAttributes = static_cast<MenuAttributes *>(nAttributePtr);
|
|
if (pAttributes)
|
|
aTargetFrame = pAttributes->aTargetFrame;
|
|
}
|
|
|
|
Sequence< PropertyValue > aArgsList{ comphelper::makePropertyValue(u"Referer"_ustr,
|
|
u"private:user"_ustr) };
|
|
|
|
dispatchCommand( aURL, aArgsList, aTargetFrame );
|
|
}
|
|
|
|
void SAL_CALL NewMenuController::itemActivated( const css::awt::MenuEvent& )
|
|
{
|
|
SolarMutexGuard aSolarMutexGuard;
|
|
if ( !(m_xFrame.is() && m_xPopupMenu.is()) )
|
|
return;
|
|
|
|
const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
|
|
bool bShowImages( rSettings.GetUseImagesInMenus() );
|
|
OUString aIconTheme( rSettings.DetermineIconTheme() );
|
|
|
|
PopupMenu* pVCLPopupMenu = static_cast<PopupMenu *>(m_xPopupMenu->GetMenu());
|
|
|
|
if ( m_bShowImages != bShowImages || m_aIconTheme != aIconTheme )
|
|
{
|
|
m_bShowImages = bShowImages;
|
|
m_aIconTheme = aIconTheme;
|
|
setMenuImages( pVCLPopupMenu, m_bShowImages );
|
|
}
|
|
|
|
setAccelerators();
|
|
}
|
|
|
|
// XPopupMenuController
|
|
void NewMenuController::impl_setPopupMenu(std::unique_lock<std::mutex>& /*rGuard*/)
|
|
{
|
|
|
|
if ( m_xPopupMenu.is() )
|
|
fillPopupMenu( m_xPopupMenu );
|
|
|
|
// Identify module that we are attach to. It's our context that we need to know.
|
|
Reference< XModuleManager2 > xModuleManager = ModuleManager::create( m_xContext );
|
|
try
|
|
{
|
|
m_aModuleIdentifier = xModuleManager->identify( m_xFrame );
|
|
m_bModuleIdentified = true;
|
|
}
|
|
catch ( const RuntimeException& )
|
|
{
|
|
throw;
|
|
}
|
|
catch ( const Exception& )
|
|
{
|
|
}
|
|
}
|
|
|
|
// XInitialization
|
|
void NewMenuController::initializeImpl( std::unique_lock<std::mutex>& rGuard, const Sequence< Any >& aArguments )
|
|
{
|
|
bool bInitialized( m_bInitialized );
|
|
if ( bInitialized )
|
|
return;
|
|
|
|
svt::PopupMenuControllerBase::initializeImpl( rGuard, aArguments );
|
|
|
|
if ( m_bInitialized )
|
|
{
|
|
const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
|
|
|
|
m_bShowImages = rSettings.GetUseImagesInMenus();
|
|
m_aIconTheme = rSettings.DetermineIconTheme();
|
|
m_bNewMenu = m_aCommandURL == aSlotNewDocDirect;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
|
|
framework_NewMenuController_get_implementation(
|
|
css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
|
|
{
|
|
return cppu::acquire(new framework::NewMenuController(context));
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|