bump product version to 4.1.6.2
[LibreOffice.git] / framework / source / uielement / newmenucontroller.cxx
blob15c749548ef0196497d771425a6db44f1d80b3ae
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <uielement/newmenucontroller.hxx>
22 #include <threadhelp/resetableguard.hxx>
23 #include "services.h"
24 #include <classes/resource.hrc>
25 #include <classes/fwkresid.hxx>
26 #include <framework/bmkmenu.hxx>
27 #include <framework/imageproducer.hxx>
28 #include <framework/menuconfiguration.hxx>
30 #include <com/sun/star/awt/XDevice.hpp>
31 #include <com/sun/star/beans/PropertyValue.hpp>
32 #include <com/sun/star/awt/MenuItemStyle.hpp>
33 #include <com/sun/star/ui/ModuleUIConfigurationManagerSupplier.hpp>
34 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
35 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
36 #include <com/sun/star/frame/ModuleManager.hpp>
38 #include <vcl/svapp.hxx>
39 #include <vcl/i18nhelp.hxx>
40 #include <rtl/ustrbuf.hxx>
41 #include <cppuhelper/implbase1.hxx>
42 #include <osl/file.hxx>
43 #include <svtools/menuoptions.hxx>
44 #include <svtools/acceleratorexecute.hxx>
45 #include <unotools/moduleoptions.hxx>
46 #include <osl/mutex.hxx>
48 //_________________________________________________________________________________________________________________
49 // Defines
50 //_________________________________________________________________________________________________________________
52 using namespace com::sun::star::uno;
53 using namespace com::sun::star::lang;
54 using namespace com::sun::star::frame;
55 using namespace com::sun::star::beans;
56 using namespace com::sun::star::util;
57 using namespace com::sun::star::container;
58 using namespace com::sun::star::ui;
60 static const char SFX_REFERER_USER[] = "private:user";
62 namespace framework
65 DEFINE_XSERVICEINFO_MULTISERVICE ( NewMenuController ,
66 OWeakObject ,
67 SERVICENAME_POPUPMENUCONTROLLER ,
68 IMPLEMENTATIONNAME_NEWMENUCONTROLLER
71 DEFINE_INIT_SERVICE ( NewMenuController, {} )
73 void NewMenuController::setMenuImages( PopupMenu* pPopupMenu, sal_Bool bSetImages )
75 sal_uInt16 nItemCount = pPopupMenu->GetItemCount();
76 Image aImage;
77 Reference< XFrame > xFrame( m_xFrame );
79 for ( sal_uInt16 i = 0; i < nItemCount; i++ )
81 sal_uInt16 nItemId = pPopupMenu->GetItemId( sal::static_int_cast<sal_uInt16>( i ));
82 if ( nItemId != 0 )
84 if ( bSetImages )
86 sal_Bool bImageSet( sal_False );
87 OUString aImageId;
89 AddInfoForId::const_iterator pInfo = m_aAddInfoForItem.find( nItemId );
90 if ( pInfo != m_aAddInfoForItem.end() )
91 aImageId = pInfo->second.aImageId; // Retrieve image id for menu item
93 if ( !aImageId.isEmpty() )
95 aImage = GetImageFromURL( xFrame, aImageId, false );
96 if ( !!aImage )
98 bImageSet = sal_True;
99 pPopupMenu->SetItemImage( nItemId, aImage );
103 if ( !bImageSet )
105 String aCmd( pPopupMenu->GetItemCommand( nItemId ) );
106 if ( aCmd.Len() )
107 aImage = GetImageFromURL( xFrame, aCmd, false );
109 if ( !!aImage )
110 pPopupMenu->SetItemImage( nItemId, aImage );
113 else
114 pPopupMenu->SetItemImage( nItemId, aImage );
119 void NewMenuController::determineAndSetNewDocAccel( PopupMenu* pPopupMenu, const KeyCode& rKeyCode )
121 sal_uInt16 nCount( pPopupMenu->GetItemCount() );
122 sal_uInt16 nId( 0 );
123 sal_Bool bFound( sal_False );
124 OUString aCommand;
126 if ( !m_aEmptyDocURL.isEmpty() )
128 // Search for the empty document URL
130 for ( sal_uInt32 i = 0; i < sal_uInt32( nCount ); i++ )
132 nId = pPopupMenu->GetItemId( sal_uInt16( i ));
133 if ( nId != 0 && pPopupMenu->GetItemType( nId ) != MENUITEM_SEPARATOR )
135 aCommand = pPopupMenu->GetItemCommand( nId );
136 if ( aCommand.indexOf( m_aEmptyDocURL ) == 0 )
138 pPopupMenu->SetAccelKey( nId, rKeyCode );
139 bFound = sal_True;
140 break;
146 if ( !bFound )
148 // Search for the default module name
149 OUString aDefaultModuleName( SvtModuleOptions().GetDefaultModuleName() );
150 if ( !aDefaultModuleName.isEmpty() )
152 for ( sal_uInt32 i = 0; i < sal_uInt32( nCount ); i++ )
154 nId = pPopupMenu->GetItemId( sal_uInt16( i ));
155 if ( nId != 0 && pPopupMenu->GetItemType( nId ) != MENUITEM_SEPARATOR )
157 aCommand = pPopupMenu->GetItemCommand( nId );
158 if ( aCommand.indexOf( aDefaultModuleName ) >= 0 )
160 pPopupMenu->SetAccelKey( nId, rKeyCode );
161 break;
169 void NewMenuController::setAccelerators( PopupMenu* pPopupMenu )
171 if ( m_bModuleIdentified )
173 Reference< XAcceleratorConfiguration > xDocAccelCfg( m_xDocAcceleratorManager );
174 Reference< XAcceleratorConfiguration > xModuleAccelCfg( m_xModuleAcceleratorManager );
175 Reference< XAcceleratorConfiguration > xGlobalAccelCfg( m_xGlobalAcceleratorManager );
177 if ( !m_bAcceleratorCfg )
179 // Retrieve references on demand
180 m_bAcceleratorCfg = sal_True;
181 if ( !xDocAccelCfg.is() )
183 Reference< XController > xController = m_xFrame->getController();
184 Reference< XModel > xModel;
185 if ( xController.is() )
187 xModel = xController->getModel();
188 if ( xModel.is() )
190 Reference< XUIConfigurationManagerSupplier > xSupplier( xModel, UNO_QUERY );
191 if ( xSupplier.is() )
193 Reference< XUIConfigurationManager > xDocUICfgMgr( xSupplier->getUIConfigurationManager(), UNO_QUERY );
194 if ( xDocUICfgMgr.is() )
196 xDocAccelCfg = Reference< XAcceleratorConfiguration >( xDocUICfgMgr->getShortCutManager(), UNO_QUERY );
197 m_xDocAcceleratorManager = xDocAccelCfg;
204 if ( !xModuleAccelCfg.is() )
206 Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier =
207 ModuleUIConfigurationManagerSupplier::create( comphelper::getComponentContext(m_xServiceManager) );
208 Reference< XUIConfigurationManager > xUICfgMgr = xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleIdentifier );
209 if ( xUICfgMgr.is() )
211 xModuleAccelCfg = Reference< XAcceleratorConfiguration >( xUICfgMgr->getShortCutManager(), UNO_QUERY );
212 m_xModuleAcceleratorManager = xModuleAccelCfg;
216 if ( !xGlobalAccelCfg.is() )
218 xGlobalAccelCfg = GlobalAcceleratorConfiguration::create( comphelper::getComponentContext(m_xServiceManager) );
219 m_xGlobalAcceleratorManager = xGlobalAccelCfg;
223 KeyCode aEmptyKeyCode;
224 sal_uInt32 nItemCount( pPopupMenu->GetItemCount() );
225 std::vector< KeyCode > aMenuShortCuts;
226 std::vector< OUString > aCmds;
227 std::vector< sal_uInt32 > aIds;
228 for ( sal_uInt32 i = 0; i < nItemCount; i++ )
230 sal_uInt16 nId( pPopupMenu->GetItemId( sal_uInt16( i )));
231 if ( nId & ( pPopupMenu->GetItemType( nId ) != MENUITEM_SEPARATOR ))
233 aIds.push_back( nId );
234 aMenuShortCuts.push_back( aEmptyKeyCode );
235 aCmds.push_back( pPopupMenu->GetItemCommand( nId ));
239 sal_uInt32 nSeqCount( aIds.size() );
241 if ( m_bNewMenu )
242 nSeqCount+=1;
244 Sequence< OUString > aSeq( nSeqCount );
246 // Add a special command for our "New" menu.
247 if ( m_bNewMenu )
249 aSeq[nSeqCount-1] = m_aCommandURL;
250 aMenuShortCuts.push_back( aEmptyKeyCode );
253 const sal_uInt32 nCount = aCmds.size();
254 for ( sal_uInt32 i = 0; i < nCount; i++ )
255 aSeq[i] = aCmds[i];
257 if ( m_xGlobalAcceleratorManager.is() )
258 retrieveShortcutsFromConfiguration( xGlobalAccelCfg, aSeq, aMenuShortCuts );
259 if ( m_xModuleAcceleratorManager.is() )
260 retrieveShortcutsFromConfiguration( xModuleAccelCfg, aSeq, aMenuShortCuts );
261 if ( m_xDocAcceleratorManager.is() )
262 retrieveShortcutsFromConfiguration( xGlobalAccelCfg, aSeq, aMenuShortCuts );
264 const sal_uInt32 nCount2 = aIds.size();
265 for ( sal_uInt32 i = 0; i < nCount2; i++ )
266 pPopupMenu->SetAccelKey( sal_uInt16( aIds[i] ), aMenuShortCuts[i] );
268 // Special handling for "New" menu short-cut should be set at the
269 // document which will be opened using it.
270 if ( m_bNewMenu )
272 if ( aMenuShortCuts[nSeqCount-1] != aEmptyKeyCode )
273 determineAndSetNewDocAccel( pPopupMenu, aMenuShortCuts[nSeqCount-1] );
278 void NewMenuController::retrieveShortcutsFromConfiguration(
279 const Reference< XAcceleratorConfiguration >& rAccelCfg,
280 const Sequence< OUString >& rCommands,
281 std::vector< KeyCode >& aMenuShortCuts )
283 if ( rAccelCfg.is() )
287 com::sun::star::awt::KeyEvent aKeyEvent;
288 Sequence< Any > aSeqKeyCode = rAccelCfg->getPreferredKeyEventsForCommandList( rCommands );
289 for ( sal_Int32 i = 0; i < aSeqKeyCode.getLength(); i++ )
291 if ( aSeqKeyCode[i] >>= aKeyEvent )
292 aMenuShortCuts[i] = svt::AcceleratorExecute::st_AWTKey2VCLKey( aKeyEvent );
295 catch ( const IllegalArgumentException& )
301 NewMenuController::NewMenuController( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ) :
302 svt::PopupMenuControllerBase( xServiceManager ),
303 m_bShowImages( sal_True ),
304 m_bNewMenu( sal_False ),
305 m_bModuleIdentified( sal_False ),
306 m_bAcceleratorCfg( sal_False ),
307 m_aTargetFrame( "_default" )
311 NewMenuController::~NewMenuController()
315 // private function
316 void NewMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu >& rPopupMenu )
318 VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu );
319 PopupMenu* pVCLPopupMenu = 0;
321 SolarMutexGuard aSolarMutexGuard;
323 resetPopupMenu( rPopupMenu );
324 if ( pPopupMenu )
325 pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();
327 if ( pVCLPopupMenu )
329 MenuConfiguration aMenuCfg( comphelper::getComponentContext(m_xServiceManager) );
330 BmkMenu* pSubMenu( 0 );
332 if ( m_bNewMenu )
333 pSubMenu = (BmkMenu*)aMenuCfg.CreateBookmarkMenu( m_xFrame, BOOKMARK_NEWMENU );
334 else
335 pSubMenu = (BmkMenu*)aMenuCfg.CreateBookmarkMenu( m_xFrame, BOOKMARK_WIZARDMENU );
337 // copy entries as we have to use the provided popup menu
338 *pVCLPopupMenu = *pSubMenu;
340 Image aImage;
341 AddInfo aAddInfo;
343 // retrieve additional parameters from bookmark menu and
344 // store it in a boost::unordered_map.
345 for ( sal_uInt16 i = 0; i < pSubMenu->GetItemCount(); i++ )
347 sal_uInt16 nItemId = pSubMenu->GetItemId( sal::static_int_cast<sal_uInt16>( i ) );
348 if (( nItemId != 0 ) &&
349 ( pSubMenu->GetItemType( nItemId ) != MENUITEM_SEPARATOR ))
351 MenuConfiguration::Attributes* pBmkAttributes = (MenuConfiguration::Attributes *)(pSubMenu->GetUserValue( nItemId ));
352 if ( pBmkAttributes != 0 )
354 aAddInfo.aTargetFrame = pBmkAttributes->aTargetFrame;
355 aAddInfo.aImageId = pBmkAttributes->aImageId;
357 m_aAddInfoForItem.insert( AddInfoForId::value_type( nItemId, aAddInfo ));
362 if ( m_bShowImages )
363 setMenuImages( pVCLPopupMenu, m_bShowImages );
365 delete pSubMenu;
369 // XEventListener
370 void SAL_CALL NewMenuController::disposing( const EventObject& ) throw ( RuntimeException )
372 Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY );
374 osl::MutexGuard aLock( m_aMutex );
375 m_xFrame.clear();
376 m_xDispatch.clear();
377 m_xServiceManager.clear();
379 if ( m_xPopupMenu.is() )
380 m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY ));
381 m_xPopupMenu.clear();
384 // XStatusListener
385 void SAL_CALL NewMenuController::statusChanged( const FeatureStateEvent& ) throw ( RuntimeException )
389 // XMenuListener
390 void SAL_CALL NewMenuController::select( const css::awt::MenuEvent& rEvent ) throw (RuntimeException)
392 Reference< css::awt::XPopupMenu > xPopupMenu;
393 Reference< XDispatch > xDispatch;
394 Reference< XDispatchProvider > xDispatchProvider;
395 Reference< XMultiServiceFactory > xServiceManager;
396 Reference< XURLTransformer > xURLTransformer;
398 osl::ClearableMutexGuard aLock( m_aMutex );
399 xPopupMenu = m_xPopupMenu;
400 xDispatchProvider = Reference< XDispatchProvider >( m_xFrame, UNO_QUERY );
401 xServiceManager = m_xServiceManager;
402 xURLTransformer = m_xURLTransformer;
403 aLock.clear();
405 css::util::URL aTargetURL;
406 Sequence< PropertyValue > aArgsList( 1 );
408 if ( xPopupMenu.is() && xDispatchProvider.is() )
410 VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXPopupMenu::GetImplementation( xPopupMenu );
411 if ( pPopupMenu )
414 SolarMutexGuard aSolarMutexGuard;
415 PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();
416 aTargetURL.Complete = pVCLPopupMenu->GetItemCommand( rEvent.MenuId );
419 xURLTransformer->parseStrict( aTargetURL );
421 aArgsList[0].Name = OUString( "Referer" );
422 aArgsList[0].Value = makeAny( OUString(SFX_REFERER_USER ));
424 OUString aTargetFrame( m_aTargetFrame );
425 AddInfoForId::const_iterator pItem = m_aAddInfoForItem.find( rEvent.MenuId );
426 if ( pItem != m_aAddInfoForItem.end() )
427 aTargetFrame = pItem->second.aTargetFrame;
429 xDispatch = xDispatchProvider->queryDispatch( aTargetURL, aTargetFrame, 0 );
433 if ( xDispatch.is() )
435 // Call dispatch asychronously as we can be destroyed while dispatch is
436 // executed. VCL is not able to survive this as it wants to call listeners
437 // after select!!!
438 NewDocument* pNewDocument = new NewDocument;
439 pNewDocument->xDispatch = xDispatch;
440 pNewDocument->aTargetURL = aTargetURL;
441 pNewDocument->aArgSeq = aArgsList;
442 Application::PostUserEvent( STATIC_LINK(0, NewMenuController, ExecuteHdl_Impl), pNewDocument );
446 void SAL_CALL NewMenuController::activate( const css::awt::MenuEvent& ) throw (RuntimeException)
448 SolarMutexGuard aSolarMutexGuard;
449 if ( m_xFrame.is() && m_xPopupMenu.is() )
451 VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXPopupMenu::GetImplementation( m_xPopupMenu );
452 if ( pPopupMenu )
454 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
455 sal_Bool bShowImages( rSettings.GetUseImagesInMenus() );
457 PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();
459 if ( m_bShowImages != bShowImages )
461 m_bShowImages = bShowImages;
462 setMenuImages( pVCLPopupMenu, m_bShowImages );
465 setAccelerators( pVCLPopupMenu );
470 // XPopupMenuController
471 void NewMenuController::impl_setPopupMenu()
474 if ( m_xPopupMenu.is() )
475 fillPopupMenu( m_xPopupMenu );
477 // Identify module that we are attach to. It's our context that we need to know.
478 Reference< XModuleManager2 > xModuleManager = ModuleManager::create( comphelper::getComponentContext(m_xServiceManager) );
481 m_aModuleIdentifier = xModuleManager->identify( m_xFrame );
482 m_bModuleIdentified = sal_True;
484 if ( !m_aModuleIdentifier.isEmpty() )
486 Sequence< PropertyValue > aSeq;
488 if ( xModuleManager->getByName( m_aModuleIdentifier ) >>= aSeq )
490 for ( sal_Int32 y = 0; y < aSeq.getLength(); y++ )
492 if ( aSeq[y].Name == "ooSetupFactoryEmptyDocumentURL" )
494 aSeq[y].Value >>= m_aEmptyDocURL;
495 break;
501 catch ( const RuntimeException& )
503 throw;
505 catch ( const Exception& )
510 // XInitialization
511 void SAL_CALL NewMenuController::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException )
513 osl::MutexGuard aLock( m_aMutex );
515 sal_Bool bInitalized( m_bInitialized );
516 if ( !bInitalized )
518 svt::PopupMenuControllerBase::initialize( aArguments );
520 if ( m_bInitialized )
522 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
524 m_bShowImages = rSettings.GetUseImagesInMenus();
525 m_bNewMenu = m_aCommandURL.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ".uno:AddDirect" ) );
530 IMPL_STATIC_LINK_NOINSTANCE( NewMenuController, ExecuteHdl_Impl, NewDocument*, pNewDocument )
532 /* i62706: Don't catch all exceptions. We hide all problems here and are not able
533 to handle them on higher levels.
537 // Asynchronous execution as this can lead to our own destruction!
538 // Framework can recycle our current frame and the layout manager disposes all user interface
539 // elements if a component gets detached from its frame!
540 pNewDocument->xDispatch->dispatch( pNewDocument->aTargetURL, pNewDocument->aArgSeq );
541 delete pNewDocument;
542 return 0;
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */