diff options
Diffstat (limited to 'framework/source/uielement/newmenucontroller.cxx')
-rw-r--r-- | framework/source/uielement/newmenucontroller.cxx | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/framework/source/uielement/newmenucontroller.cxx b/framework/source/uielement/newmenucontroller.cxx new file mode 100644 index 000000000000..786795ff1d14 --- /dev/null +++ b/framework/source/uielement/newmenucontroller.cxx @@ -0,0 +1,596 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <uielement/newmenucontroller.hxx> + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ +#include <threadhelp/resetableguard.hxx> +#include "services.h" +#ifndef __FRAMEWORK_CLASSES_RESOURCE_HRC_ +#include <classes/resource.hrc> +#endif +#include <classes/fwkresid.hxx> +#include <classes/bmkmenu.hxx> +#include <helper/imageproducer.hxx> +#include <xml/menuconfiguration.hxx> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ +#include <com/sun/star/awt/XDevice.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/awt/MenuItemStyle.hpp> +#include <com/sun/star/ui/XModuleUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/frame/XModuleManager.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/document/CorruptedFilterConfigurationException.hpp> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ +#include <vcl/svapp.hxx> +#include <vcl/i18nhelp.hxx> +#include <tools/urlobj.hxx> +#include <rtl/ustrbuf.hxx> +#include <cppuhelper/implbase1.hxx> +#include <osl/file.hxx> +#include <svtools/menuoptions.hxx> +#include <svtools/acceleratorexecute.hxx> +#include <unotools/moduleoptions.hxx> +#include <dispatch/uieventloghelper.hxx> +#include <vos/mutex.hxx> + +//_________________________________________________________________________________________________________________ +// Defines +//_________________________________________________________________________________________________________________ +// + +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::container; +using namespace com::sun::star::ui; + +static const char SFX_REFERER_USER[] = "private:user"; + +namespace framework +{ + +DEFINE_XSERVICEINFO_MULTISERVICE ( NewMenuController , + OWeakObject , + SERVICENAME_POPUPMENUCONTROLLER , + IMPLEMENTATIONNAME_NEWMENUCONTROLLER + ) + +DEFINE_INIT_SERVICE ( NewMenuController, {} ) + +void NewMenuController::setMenuImages( PopupMenu* pPopupMenu, sal_Bool bSetImages, sal_Bool bHiContrast ) +{ + USHORT nItemCount = pPopupMenu->GetItemCount(); + Image aImage; + Reference< XFrame > xFrame( m_xFrame ); + + for ( USHORT i = 0; i < nItemCount; i++ ) + { + USHORT nItemId = pPopupMenu->GetItemId( sal::static_int_cast<USHORT>( i )); + if ( nItemId != 0 ) + { + if ( bSetImages ) + { + sal_Bool bImageSet( sal_False ); + ::rtl::OUString aImageId; + + AddInfoForId::const_iterator pInfo = m_aAddInfoForItem.find( nItemId ); + if ( pInfo != m_aAddInfoForItem.end() ) + aImageId = pInfo->second.aImageId; // Retrieve image id for menu item + + if ( aImageId.getLength() > 0 ) + { + aImage = GetImageFromURL( xFrame, aImageId, FALSE, bHiContrast ); + if ( !!aImage ) + { + bImageSet = sal_True; + pPopupMenu->SetItemImage( nItemId, aImage ); + } + } + + if ( !bImageSet ) + { + String aCmd( pPopupMenu->GetItemCommand( nItemId ) ); + if ( aCmd.Len() ) + aImage = GetImageFromURL( xFrame, aCmd, FALSE, bHiContrast ); + + if ( !!aImage ) + pPopupMenu->SetItemImage( nItemId, aImage ); + } + } + else + pPopupMenu->SetItemImage( nItemId, aImage ); + } + } +} + +void NewMenuController::determineAndSetNewDocAccel( PopupMenu* pPopupMenu, const KeyCode& rKeyCode ) +{ + USHORT nCount( pPopupMenu->GetItemCount() ); + USHORT nId( 0 ); + sal_Bool bFound( sal_False ); + rtl::OUString aCommand; + + if ( m_aEmptyDocURL.getLength() > 0 ) + { + // Search for the empty document URL + + for ( sal_uInt32 i = 0; i < sal_uInt32( nCount ); i++ ) + { + nId = pPopupMenu->GetItemId( USHORT( i )); + if ( nId != 0 && pPopupMenu->GetItemType( nId ) != MENUITEM_SEPARATOR ) + { + aCommand = pPopupMenu->GetItemCommand( nId ); + if ( aCommand.indexOf( m_aEmptyDocURL ) == 0 ) + { + pPopupMenu->SetAccelKey( nId, rKeyCode ); + bFound = sal_True; + break; + } + } + } + } + + if ( !bFound ) + { + // Search for the default module name + rtl::OUString aDefaultModuleName( SvtModuleOptions().GetDefaultModuleName() ); + if ( aDefaultModuleName.getLength() > 0 ) + { + for ( sal_uInt32 i = 0; i < sal_uInt32( nCount ); i++ ) + { + nId = pPopupMenu->GetItemId( USHORT( i )); + if ( nId != 0 && pPopupMenu->GetItemType( nId ) != MENUITEM_SEPARATOR ) + { + aCommand = pPopupMenu->GetItemCommand( nId ); + if ( aCommand.indexOf( aDefaultModuleName ) >= 0 ) + { + pPopupMenu->SetAccelKey( nId, rKeyCode ); + break; + } + } + } + } + } +} + +void NewMenuController::setAccelerators( PopupMenu* pPopupMenu ) +{ + if ( m_bModuleIdentified ) + { + Reference< XAcceleratorConfiguration > xDocAccelCfg( m_xDocAcceleratorManager ); + Reference< XAcceleratorConfiguration > xModuleAccelCfg( m_xModuleAcceleratorManager ); + Reference< XAcceleratorConfiguration > xGlobalAccelCfg( m_xGlobalAcceleratorManager ); + + if ( !m_bAcceleratorCfg ) + { + // Retrieve references on demand + m_bAcceleratorCfg = sal_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(), UNO_QUERY ); + if ( xDocUICfgMgr.is() ) + { + xDocAccelCfg = Reference< XAcceleratorConfiguration >( xDocUICfgMgr->getShortCutManager(), UNO_QUERY ); + m_xDocAcceleratorManager = xDocAccelCfg; + } + } + } + } + } + + if ( !xModuleAccelCfg.is() ) + { + Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier( m_xServiceManager->createInstance( + SERVICENAME_MODULEUICONFIGURATIONMANAGERSUPPLIER ), + UNO_QUERY ); + Reference< XUIConfigurationManager > xUICfgMgr = xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleIdentifier ); + if ( xUICfgMgr.is() ) + { + xModuleAccelCfg = Reference< XAcceleratorConfiguration >( xUICfgMgr->getShortCutManager(), UNO_QUERY ); + m_xModuleAcceleratorManager = xModuleAccelCfg; + } + } + + if ( !xGlobalAccelCfg.is() ) + { + xGlobalAccelCfg = Reference< XAcceleratorConfiguration >( m_xServiceManager->createInstance( + SERVICENAME_GLOBALACCELERATORCONFIGURATION ), + UNO_QUERY ); + m_xGlobalAcceleratorManager = xGlobalAccelCfg; + } + } + + KeyCode aEmptyKeyCode; + sal_uInt32 nItemCount( pPopupMenu->GetItemCount() ); + std::vector< KeyCode > aMenuShortCuts; + std::vector< rtl::OUString > aCmds; + std::vector< sal_uInt32 > aIds; + for ( sal_uInt32 i = 0; i < nItemCount; i++ ) + { + USHORT nId( pPopupMenu->GetItemId( USHORT( i ))); + if ( nId & ( pPopupMenu->GetItemType( nId ) != MENUITEM_SEPARATOR )) + { + aIds.push_back( nId ); + aMenuShortCuts.push_back( aEmptyKeyCode ); + aCmds.push_back( pPopupMenu->GetItemCommand( nId )); + } + } + + sal_uInt32 nSeqCount( aIds.size() ); + + if ( m_bNewMenu ) + nSeqCount+=1; + + Sequence< rtl::OUString > aSeq( nSeqCount ); + + // Add a special command for our "New" menu. + if ( m_bNewMenu ) + { + aSeq[nSeqCount-1] = m_aCommandURL; + aMenuShortCuts.push_back( aEmptyKeyCode ); + } + + const sal_uInt32 nCount = aCmds.size(); + for ( sal_uInt32 i = 0; i < nCount; i++ ) + aSeq[i] = aCmds[i]; + + if ( m_xGlobalAcceleratorManager.is() ) + retrieveShortcutsFromConfiguration( xGlobalAccelCfg, aSeq, aMenuShortCuts ); + if ( m_xModuleAcceleratorManager.is() ) + retrieveShortcutsFromConfiguration( xModuleAccelCfg, aSeq, aMenuShortCuts ); + if ( m_xDocAcceleratorManager.is() ) + retrieveShortcutsFromConfiguration( xGlobalAccelCfg, aSeq, aMenuShortCuts ); + + const sal_uInt32 nCount2 = aIds.size(); + for ( sal_uInt32 i = 0; i < nCount2; i++ ) + pPopupMenu->SetAccelKey( USHORT( aIds[i] ), 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( pPopupMenu, aMenuShortCuts[nSeqCount-1] ); + } + } +} + +void NewMenuController::retrieveShortcutsFromConfiguration( + const Reference< XAcceleratorConfiguration >& rAccelCfg, + const Sequence< rtl::OUString >& rCommands, + std::vector< KeyCode >& aMenuShortCuts ) +{ + if ( rAccelCfg.is() ) + { + try + { + com::sun::star::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 ( IllegalArgumentException& ) + { + } + } +} + +NewMenuController::NewMenuController( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ) : + svt::PopupMenuControllerBase( xServiceManager ), + m_bShowImages( sal_True ), + m_bHiContrast( sal_False ), + m_bNewMenu( sal_False ), + m_bModuleIdentified( sal_False ), + m_bAcceleratorCfg( sal_False ), + m_aTargetFrame( RTL_CONSTASCII_USTRINGPARAM( "_default" )) +{ +} + +NewMenuController::~NewMenuController() +{ +} + +// private function +void NewMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu >& rPopupMenu ) +{ + VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu ); + PopupMenu* pVCLPopupMenu = 0; + + vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); + + resetPopupMenu( rPopupMenu ); + if ( pPopupMenu ) + pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu(); + + if ( pVCLPopupMenu ) + { + MenuConfiguration aMenuCfg( m_xServiceManager ); + BmkMenu* pSubMenu( 0 ); + + if ( m_bNewMenu ) + pSubMenu = (BmkMenu*)aMenuCfg.CreateBookmarkMenu( m_xFrame, BOOKMARK_NEWMENU ); + else + pSubMenu = (BmkMenu*)aMenuCfg.CreateBookmarkMenu( m_xFrame, BOOKMARK_WIZARDMENU ); + + // copy entries as we have to use the provided popup menu + *pVCLPopupMenu = *pSubMenu; + + Image aImage; + AddInfo aAddInfo; + + // retrieve additional parameters from bookmark menu and + // store it in a hash_map. + for ( USHORT i = 0; i < pSubMenu->GetItemCount(); i++ ) + { + USHORT nItemId = pSubMenu->GetItemId( sal::static_int_cast<USHORT>( i ) ); + if (( nItemId != 0 ) && + ( pSubMenu->GetItemType( nItemId ) != MENUITEM_SEPARATOR )) + { + MenuConfiguration::Attributes* pBmkAttributes = (MenuConfiguration::Attributes *)(pSubMenu->GetUserValue( nItemId )); + if ( pBmkAttributes != 0 ) + { + aAddInfo.aTargetFrame = pBmkAttributes->aTargetFrame; + aAddInfo.aImageId = pBmkAttributes->aImageId; + + m_aAddInfoForItem.insert( AddInfoForId::value_type( nItemId, aAddInfo )); + } + } + } + + if ( m_bShowImages ) + setMenuImages( pVCLPopupMenu, m_bShowImages, m_bHiContrast ); + + delete pSubMenu; + } +} + +// XEventListener +void SAL_CALL NewMenuController::disposing( const EventObject& ) throw ( RuntimeException ) +{ + Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY ); + + osl::MutexGuard aLock( m_aMutex ); + m_xFrame.clear(); + m_xDispatch.clear(); + m_xServiceManager.clear(); + + if ( m_xPopupMenu.is() ) + m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY )); + m_xPopupMenu.clear(); +} + +// XStatusListener +void SAL_CALL NewMenuController::statusChanged( const FeatureStateEvent& ) throw ( RuntimeException ) +{ +} + +// XMenuListener +void SAL_CALL NewMenuController::select( const css::awt::MenuEvent& rEvent ) throw (RuntimeException) +{ + Reference< css::awt::XPopupMenu > xPopupMenu; + Reference< XDispatch > xDispatch; + Reference< XDispatchProvider > xDispatchProvider; + Reference< XMultiServiceFactory > xServiceManager; + Reference< XURLTransformer > xURLTransformer; + + osl::ClearableMutexGuard aLock( m_aMutex ); + xPopupMenu = m_xPopupMenu; + xDispatchProvider = Reference< XDispatchProvider >( m_xFrame, UNO_QUERY ); + xServiceManager = m_xServiceManager; + xURLTransformer = m_xURLTransformer; + aLock.clear(); + + css::util::URL aTargetURL; + Sequence< PropertyValue > aArgsList( 1 ); + + if ( xPopupMenu.is() && xDispatchProvider.is() ) + { + VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXPopupMenu::GetImplementation( xPopupMenu ); + if ( pPopupMenu ) + { + { + vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); + PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu(); + aTargetURL.Complete = pVCLPopupMenu->GetItemCommand( rEvent.MenuId ); + } + + xURLTransformer->parseStrict( aTargetURL ); + + aArgsList[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Referer" )); + aArgsList[0].Value = makeAny( ::rtl::OUString::createFromAscii( SFX_REFERER_USER )); + + rtl::OUString aTargetFrame( m_aTargetFrame ); + AddInfoForId::const_iterator pItem = m_aAddInfoForItem.find( rEvent.MenuId ); + if ( pItem != m_aAddInfoForItem.end() ) + aTargetFrame = pItem->second.aTargetFrame; + + xDispatch = xDispatchProvider->queryDispatch( aTargetURL, aTargetFrame, 0 ); + } + } + + if ( xDispatch.is() ) + { + // Call dispatch asychronously as we can be destroyed while dispatch is + // executed. VCL is not able to survive this as it wants to call listeners + // after select!!! + NewDocument* pNewDocument = new NewDocument; + pNewDocument->xDispatch = xDispatch; + pNewDocument->aTargetURL = aTargetURL; + pNewDocument->aArgSeq = aArgsList; + if(::comphelper::UiEventsLogger::isEnabled()) //#i88653# + UiEventLogHelper(::rtl::OUString::createFromAscii("NewMenuController")).log(m_xServiceManager, m_xFrame, aTargetURL, aArgsList); + Application::PostUserEvent( STATIC_LINK(0, NewMenuController, ExecuteHdl_Impl), pNewDocument ); + } +} + +void SAL_CALL NewMenuController::activate( const css::awt::MenuEvent& ) throw (RuntimeException) +{ + vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); + if ( m_xFrame.is() && m_xPopupMenu.is() ) + { + VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXPopupMenu::GetImplementation( m_xPopupMenu ); + if ( pPopupMenu ) + { + const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); + sal_Bool bShowImages( rSettings.GetUseImagesInMenus() ); + sal_Bool bHiContrast( rSettings.GetHighContrastMode() ); + + PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu(); + + if (( m_bShowImages != bShowImages ) || + ( m_bHiContrast != bHiContrast )) + { + m_bShowImages = bShowImages; + m_bHiContrast = bHiContrast; + + setMenuImages( pVCLPopupMenu, m_bShowImages, m_bHiContrast ); + } + + setAccelerators( pVCLPopupMenu ); + } + } +} + +// XPopupMenuController +void NewMenuController::impl_setPopupMenu() +{ + + if ( m_xPopupMenu.is() ) + fillPopupMenu( m_xPopupMenu ); + + // Identify module that we are attach to. It's our context that we need to know. + Reference< XModuleManager > xModuleManager( m_xServiceManager->createInstance( SERVICENAME_MODULEMANAGER ),UNO_QUERY ); + if ( xModuleManager.is() ) + { + try + { + m_aModuleIdentifier = xModuleManager->identify( m_xFrame ); + m_bModuleIdentified = sal_True; + + Reference< XNameAccess > xNameAccess( xModuleManager, UNO_QUERY ); + if (( m_aModuleIdentifier.getLength() > 0 ) && xNameAccess.is() ) + { + Sequence< PropertyValue > aSeq; + + if ( xNameAccess->getByName( m_aModuleIdentifier ) >>= aSeq ) + { + for ( sal_Int32 y = 0; y < aSeq.getLength(); y++ ) + { + if ( aSeq[y].Name.equalsAscii("ooSetupFactoryEmptyDocumentURL") ) + { + aSeq[y].Value >>= m_aEmptyDocURL; + break; + } + } + } + } + } + catch ( RuntimeException& e ) + { + throw e; + } + catch ( Exception& ) + { + } + } +} + +// XInitialization +void SAL_CALL NewMenuController::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException ) +{ + osl::MutexGuard aLock( m_aMutex ); + + sal_Bool bInitalized( m_bInitialized ); + if ( !bInitalized ) + { + svt::PopupMenuControllerBase::initialize( aArguments ); + + if ( m_bInitialized ) + { + const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); + + m_bShowImages = rSettings.GetUseImagesInMenus(); + m_bHiContrast = rSettings.GetHighContrastMode(); + + m_bNewMenu = m_aCommandURL.equalsAscii( ".uno:AddDirect" ); + } + } +} + +IMPL_STATIC_LINK_NOINSTANCE( NewMenuController, ExecuteHdl_Impl, NewDocument*, pNewDocument ) +{ +/* i62706: Don't catch all exceptions. We hide all problems here and are not able + to handle them on higher levels. + try + { +*/ + // Asynchronous execution as this can lead to our own destruction! + // Framework can recycle our current frame and the layout manager disposes all user interface + // elements if a component gets detached from its frame! + pNewDocument->xDispatch->dispatch( pNewDocument->aTargetURL, pNewDocument->aArgSeq ); +/* + } + catch (const ::com::sun::star::document::CorruptedFilterConfigurationException& exFilters) + { + throw exFilters; + } + catch (const Exception& ) + { + } +*/ + delete pNewDocument; + return 0; +} + +} |