1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
23 #include <classes/resource.hrc>
24 #include <classes/fwkresid.hxx>
25 #include <framework/bmkmenu.hxx>
26 #include <framework/imageproducer.hxx>
27 #include <framework/menuconfiguration.hxx>
29 #include <com/sun/star/awt/XDevice.hpp>
30 #include <com/sun/star/beans/PropertyValue.hpp>
31 #include <com/sun/star/awt/MenuItemStyle.hpp>
32 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
33 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
34 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
35 #include <com/sun/star/frame/ModuleManager.hpp>
37 #include <vcl/svapp.hxx>
38 #include <vcl/i18nhelp.hxx>
39 #include <vcl/settings.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>
47 #include <boost/scoped_ptr.hpp>
51 using namespace com::sun::star::uno
;
52 using namespace com::sun::star::lang
;
53 using namespace com::sun::star::frame
;
54 using namespace com::sun::star::beans
;
55 using namespace com::sun::star::util
;
56 using namespace com::sun::star::container
;
57 using namespace com::sun::star::ui
;
62 DEFINE_XSERVICEINFO_MULTISERVICE_2 ( NewMenuController
,
64 SERVICENAME_POPUPMENUCONTROLLER
,
65 IMPLEMENTATIONNAME_NEWMENUCONTROLLER
68 DEFINE_INIT_SERVICE ( NewMenuController
, {} )
70 void NewMenuController::setMenuImages( PopupMenu
* pPopupMenu
, bool bSetImages
)
72 sal_uInt16 nItemCount
= pPopupMenu
->GetItemCount();
74 Reference
< XFrame
> xFrame( m_xFrame
);
76 for ( sal_uInt16 i
= 0; i
< nItemCount
; i
++ )
78 sal_uInt16 nItemId
= pPopupMenu
->GetItemId( sal::static_int_cast
<sal_uInt16
>( i
));
83 bool bImageSet( false );
86 sal_uIntPtr nAttributePtr
= pPopupMenu
->GetUserValue(sal::static_int_cast
<sal_uInt16
>(i
));
87 MenuAttributes
* pAttributes
= reinterpret_cast<MenuAttributes
*>(nAttributePtr
);
89 aImageId
= pAttributes
->aImageId
;
91 if ( !aImageId
.isEmpty() )
93 aImage
= GetImageFromURL( xFrame
, aImageId
, false );
97 pPopupMenu
->SetItemImage( nItemId
, aImage
);
103 OUString
aCmd( pPopupMenu
->GetItemCommand( nItemId
) );
104 if ( !aCmd
.isEmpty() )
105 aImage
= GetImageFromURL( xFrame
, aCmd
, false );
108 pPopupMenu
->SetItemImage( nItemId
, aImage
);
112 pPopupMenu
->SetItemImage( nItemId
, aImage
);
117 void NewMenuController::determineAndSetNewDocAccel( PopupMenu
* pPopupMenu
, const vcl::KeyCode
& rKeyCode
)
119 sal_uInt16
nCount( pPopupMenu
->GetItemCount() );
121 bool bFound( false );
124 if ( !m_aEmptyDocURL
.isEmpty() )
126 // Search for the empty document URL
128 for ( sal_uInt32 i
= 0; i
< sal_uInt32( nCount
); i
++ )
130 nId
= pPopupMenu
->GetItemId( sal_uInt16( i
));
131 if ( nId
!= 0 && pPopupMenu
->GetItemType( nId
) != MenuItemType::SEPARATOR
)
133 aCommand
= pPopupMenu
->GetItemCommand( nId
);
134 if ( aCommand
.startsWith( m_aEmptyDocURL
) )
136 pPopupMenu
->SetAccelKey( nId
, rKeyCode
);
146 // Search for the default module name
147 OUString
aDefaultModuleName( SvtModuleOptions().GetDefaultModuleName() );
148 if ( !aDefaultModuleName
.isEmpty() )
150 for ( sal_uInt32 i
= 0; i
< sal_uInt32( nCount
); i
++ )
152 nId
= pPopupMenu
->GetItemId( sal_uInt16( i
));
153 if ( nId
!= 0 && pPopupMenu
->GetItemType( nId
) != MenuItemType::SEPARATOR
)
155 aCommand
= pPopupMenu
->GetItemCommand( nId
);
156 if ( aCommand
.indexOf( aDefaultModuleName
) >= 0 )
158 pPopupMenu
->SetAccelKey( nId
, rKeyCode
);
167 void NewMenuController::setAccelerators( PopupMenu
* pPopupMenu
)
169 if ( m_bModuleIdentified
)
171 Reference
< XAcceleratorConfiguration
> xDocAccelCfg( m_xDocAcceleratorManager
);
172 Reference
< XAcceleratorConfiguration
> xModuleAccelCfg( m_xModuleAcceleratorManager
);
173 Reference
< XAcceleratorConfiguration
> xGlobalAccelCfg( m_xGlobalAcceleratorManager
);
175 if ( !m_bAcceleratorCfg
)
177 // Retrieve references on demand
178 m_bAcceleratorCfg
= true;
179 if ( !xDocAccelCfg
.is() )
181 Reference
< XController
> xController
= m_xFrame
->getController();
182 Reference
< XModel
> xModel
;
183 if ( xController
.is() )
185 xModel
= xController
->getModel();
188 Reference
< XUIConfigurationManagerSupplier
> xSupplier( xModel
, UNO_QUERY
);
189 if ( xSupplier
.is() )
191 Reference
< XUIConfigurationManager
> xDocUICfgMgr( xSupplier
->getUIConfigurationManager(), UNO_QUERY
);
192 if ( xDocUICfgMgr
.is() )
194 xDocAccelCfg
= xDocUICfgMgr
->getShortCutManager();
195 m_xDocAcceleratorManager
= xDocAccelCfg
;
202 if ( !xModuleAccelCfg
.is() )
204 Reference
< XModuleUIConfigurationManagerSupplier
> xModuleCfgMgrSupplier
=
205 theModuleUIConfigurationManagerSupplier::get( m_xContext
);
206 Reference
< XUIConfigurationManager
> xUICfgMgr
= xModuleCfgMgrSupplier
->getUIConfigurationManager( m_aModuleIdentifier
);
207 if ( xUICfgMgr
.is() )
209 xModuleAccelCfg
= xUICfgMgr
->getShortCutManager();
210 m_xModuleAcceleratorManager
= xModuleAccelCfg
;
214 if ( !xGlobalAccelCfg
.is() )
216 xGlobalAccelCfg
= GlobalAcceleratorConfiguration::create( m_xContext
);
217 m_xGlobalAcceleratorManager
= xGlobalAccelCfg
;
221 vcl::KeyCode aEmptyKeyCode
;
222 sal_uInt32
nItemCount( pPopupMenu
->GetItemCount() );
223 std::vector
< vcl::KeyCode
> aMenuShortCuts
;
224 std::vector
< OUString
> aCmds
;
225 std::vector
< sal_uInt32
> aIds
;
226 for ( sal_uInt32 i
= 0; i
< nItemCount
; i
++ )
228 sal_uInt16
nId( pPopupMenu
->GetItemId( sal_uInt16( i
)));
229 if ( nId
&& ( pPopupMenu
->GetItemType( nId
) != MenuItemType::SEPARATOR
))
231 aIds
.push_back( nId
);
232 aMenuShortCuts
.push_back( aEmptyKeyCode
);
233 aCmds
.push_back( pPopupMenu
->GetItemCommand( nId
));
237 sal_uInt32
nSeqCount( aIds
.size() );
242 Sequence
< OUString
> aSeq( nSeqCount
);
244 // Add a special command for our "New" menu.
247 aSeq
[nSeqCount
-1] = m_aCommandURL
;
248 aMenuShortCuts
.push_back( aEmptyKeyCode
);
251 const sal_uInt32 nCount
= aCmds
.size();
252 for ( sal_uInt32 i
= 0; i
< nCount
; i
++ )
255 if ( m_xGlobalAcceleratorManager
.is() )
256 retrieveShortcutsFromConfiguration( xGlobalAccelCfg
, aSeq
, aMenuShortCuts
);
257 if ( m_xModuleAcceleratorManager
.is() )
258 retrieveShortcutsFromConfiguration( xModuleAccelCfg
, aSeq
, aMenuShortCuts
);
259 if ( m_xDocAcceleratorManager
.is() )
260 retrieveShortcutsFromConfiguration( xGlobalAccelCfg
, aSeq
, aMenuShortCuts
);
262 const sal_uInt32 nCount2
= aIds
.size();
263 for ( sal_uInt32 i
= 0; i
< nCount2
; i
++ )
264 pPopupMenu
->SetAccelKey( sal_uInt16( aIds
[i
] ), aMenuShortCuts
[i
] );
266 // Special handling for "New" menu short-cut should be set at the
267 // document which will be opened using it.
270 if ( aMenuShortCuts
[nSeqCount
-1] != aEmptyKeyCode
)
271 determineAndSetNewDocAccel( pPopupMenu
, aMenuShortCuts
[nSeqCount
-1] );
276 void NewMenuController::retrieveShortcutsFromConfiguration(
277 const Reference
< XAcceleratorConfiguration
>& rAccelCfg
,
278 const Sequence
< OUString
>& rCommands
,
279 std::vector
< vcl::KeyCode
>& aMenuShortCuts
)
281 if ( rAccelCfg
.is() )
285 com::sun::star::awt::KeyEvent aKeyEvent
;
286 Sequence
< Any
> aSeqKeyCode
= rAccelCfg
->getPreferredKeyEventsForCommandList( rCommands
);
287 for ( sal_Int32 i
= 0; i
< aSeqKeyCode
.getLength(); i
++ )
289 if ( aSeqKeyCode
[i
] >>= aKeyEvent
)
290 aMenuShortCuts
[i
] = svt::AcceleratorExecute::st_AWTKey2VCLKey( aKeyEvent
);
293 catch ( const IllegalArgumentException
& )
299 NewMenuController::NewMenuController( const ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XComponentContext
>& xContext
) :
300 svt::PopupMenuControllerBase( xContext
),
301 m_bShowImages( true ),
303 m_bModuleIdentified( false ),
304 m_bAcceleratorCfg( false ),
305 m_aTargetFrame( "_default" ),
306 m_xContext( xContext
)
310 NewMenuController::~NewMenuController()
315 void NewMenuController::fillPopupMenu( Reference
< css::awt::XPopupMenu
>& rPopupMenu
)
317 VCLXPopupMenu
* pPopupMenu
= static_cast<VCLXPopupMenu
*>(VCLXMenu::GetImplementation( rPopupMenu
));
318 PopupMenu
* pVCLPopupMenu
= 0;
320 SolarMutexGuard aSolarMutexGuard
;
322 resetPopupMenu( rPopupMenu
);
324 pVCLPopupMenu
= static_cast<PopupMenu
*>(pPopupMenu
->GetMenu());
328 MenuConfiguration
aMenuCfg( m_xContext
);
329 boost::scoped_ptr
<BmkMenu
> pSubMenu
;
332 pSubMenu
.reset(static_cast<BmkMenu
*>(aMenuCfg
.CreateBookmarkMenu( m_xFrame
, BOOKMARK_NEWMENU
)));
334 pSubMenu
.reset(static_cast<BmkMenu
*>(aMenuCfg
.CreateBookmarkMenu( m_xFrame
, BOOKMARK_WIZARDMENU
)));
336 // copy entries as we have to use the provided popup menu
337 *pVCLPopupMenu
= *pSubMenu
;
341 // retrieve additional parameters from bookmark menu and
342 // store it in a unordered_map.
343 for ( sal_uInt16 i
= 0; i
< pSubMenu
->GetItemCount(); i
++ )
345 sal_uInt16 nItemId
= pSubMenu
->GetItemId( sal::static_int_cast
<sal_uInt16
>( i
) );
346 if (( nItemId
!= 0 ) &&
347 ( pSubMenu
->GetItemType( nItemId
) != MenuItemType::SEPARATOR
))
349 sal_uIntPtr nAttributePtr
= pSubMenu
->GetUserValue(nItemId
);
352 MenuAttributes
* pAttributes
= reinterpret_cast<MenuAttributes
*>(nAttributePtr
);
353 pAttributes
->acquire();
354 pVCLPopupMenu
->SetUserValue(nItemId
, nAttributePtr
, MenuAttributes::ReleaseAttribute
);
360 setMenuImages( pVCLPopupMenu
, m_bShowImages
);
365 void SAL_CALL
NewMenuController::disposing( const EventObject
& ) throw ( RuntimeException
, std::exception
)
367 Reference
< css::awt::XMenuListener
> xHolder(( OWeakObject
*)this, UNO_QUERY
);
369 osl::MutexGuard
aLock( m_aMutex
);
374 if ( m_xPopupMenu
.is() )
375 m_xPopupMenu
->removeMenuListener( Reference
< css::awt::XMenuListener
>(( OWeakObject
*)this, UNO_QUERY
));
376 m_xPopupMenu
.clear();
380 void SAL_CALL
NewMenuController::statusChanged( const FeatureStateEvent
& ) throw ( RuntimeException
, std::exception
)
385 void SAL_CALL
NewMenuController::itemSelected( const css::awt::MenuEvent
& rEvent
) throw (RuntimeException
, std::exception
)
387 Reference
< css::awt::XPopupMenu
> xPopupMenu
;
388 Reference
< XDispatch
> xDispatch
;
389 Reference
< XDispatchProvider
> xDispatchProvider
;
390 Reference
< XComponentContext
> xContext
;
391 Reference
< XURLTransformer
> xURLTransformer
;
393 osl::ClearableMutexGuard
aLock( m_aMutex
);
394 xPopupMenu
= m_xPopupMenu
;
395 xDispatchProvider
= Reference
< XDispatchProvider
>( m_xFrame
, UNO_QUERY
);
396 xContext
= m_xContext
;
397 xURLTransformer
= m_xURLTransformer
;
400 css::util::URL aTargetURL
;
401 Sequence
< PropertyValue
> aArgsList( 1 );
403 if ( xPopupMenu
.is() && xDispatchProvider
.is() )
405 VCLXPopupMenu
* pPopupMenu
= static_cast<VCLXPopupMenu
*>(VCLXPopupMenu::GetImplementation( xPopupMenu
));
408 OUString
aTargetFrame( m_aTargetFrame
);
411 SolarMutexGuard aSolarMutexGuard
;
412 PopupMenu
* pVCLPopupMenu
= static_cast<PopupMenu
*>(pPopupMenu
->GetMenu());
413 aTargetURL
.Complete
= pVCLPopupMenu
->GetItemCommand(rEvent
.MenuId
);
414 sal_uIntPtr nAttributePtr
= pVCLPopupMenu
->GetUserValue(rEvent
.MenuId
);
415 MenuAttributes
* pAttributes
= reinterpret_cast<MenuAttributes
*>(nAttributePtr
);
417 aTargetFrame
= pAttributes
->aTargetFrame
;
420 xURLTransformer
->parseStrict( aTargetURL
);
422 aArgsList
[0].Name
= "Referer";
423 aArgsList
[0].Value
= makeAny( OUString( "private:user" ));
425 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, aTargetFrame
, 0 );
429 if ( xDispatch
.is() )
431 // Call dispatch asychronously as we can be destroyed while dispatch is
432 // executed. VCL is not able to survive this as it wants to call listeners
434 NewDocument
* pNewDocument
= new NewDocument
;
435 pNewDocument
->xDispatch
= xDispatch
;
436 pNewDocument
->aTargetURL
= aTargetURL
;
437 pNewDocument
->aArgSeq
= aArgsList
;
438 Application::PostUserEvent( LINK(0, NewMenuController
, ExecuteHdl_Impl
), pNewDocument
);
442 void SAL_CALL
NewMenuController::itemActivated( const css::awt::MenuEvent
& ) throw (RuntimeException
, std::exception
)
444 SolarMutexGuard aSolarMutexGuard
;
445 if ( m_xFrame
.is() && m_xPopupMenu
.is() )
447 VCLXPopupMenu
* pPopupMenu
= static_cast<VCLXPopupMenu
*>(VCLXPopupMenu::GetImplementation( m_xPopupMenu
));
450 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
451 bool bShowImages( rSettings
.GetUseImagesInMenus() );
453 PopupMenu
* pVCLPopupMenu
= static_cast<PopupMenu
*>(pPopupMenu
->GetMenu());
455 if ( m_bShowImages
!= bShowImages
)
457 m_bShowImages
= bShowImages
;
458 setMenuImages( pVCLPopupMenu
, m_bShowImages
);
461 setAccelerators( pVCLPopupMenu
);
466 // XPopupMenuController
467 void NewMenuController::impl_setPopupMenu()
470 if ( m_xPopupMenu
.is() )
471 fillPopupMenu( m_xPopupMenu
);
473 // Identify module that we are attach to. It's our context that we need to know.
474 Reference
< XModuleManager2
> xModuleManager
= ModuleManager::create( m_xContext
);
477 m_aModuleIdentifier
= xModuleManager
->identify( m_xFrame
);
478 m_bModuleIdentified
= true;
480 if ( !m_aModuleIdentifier
.isEmpty() )
482 Sequence
< PropertyValue
> aSeq
;
484 if ( xModuleManager
->getByName( m_aModuleIdentifier
) >>= aSeq
)
486 for ( sal_Int32 y
= 0; y
< aSeq
.getLength(); y
++ )
488 if ( aSeq
[y
].Name
== "ooSetupFactoryEmptyDocumentURL" )
490 aSeq
[y
].Value
>>= m_aEmptyDocURL
;
497 catch ( const RuntimeException
& )
501 catch ( const Exception
& )
507 void SAL_CALL
NewMenuController::initialize( const Sequence
< Any
>& aArguments
) throw ( Exception
, RuntimeException
, std::exception
)
509 osl::MutexGuard
aLock( m_aMutex
);
511 bool bInitalized( m_bInitialized
);
514 svt::PopupMenuControllerBase::initialize( aArguments
);
516 if ( m_bInitialized
)
518 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
520 m_bShowImages
= rSettings
.GetUseImagesInMenus();
521 m_bNewMenu
= m_aCommandURL
== ".uno:AddDirect";
526 IMPL_STATIC_LINK( NewMenuController
, ExecuteHdl_Impl
, NewDocument
*, pNewDocument
)
528 /* i62706: Don't catch all exceptions. We hide all problems here and are not able
529 to handle them on higher levels.
533 // Asynchronous execution as this can lead to our own destruction!
534 // Framework can recycle our current frame and the layout manager disposes all user interface
535 // elements if a component gets detached from its frame!
536 pNewDocument
->xDispatch
->dispatch( pNewDocument
->aTargetURL
, pNewDocument
->aArgSeq
);
543 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */