1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: newmenucontroller.cxx,v $
10 * $Revision: 1.12.40.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
33 #include <uielement/newmenucontroller.hxx>
35 //_________________________________________________________________________________________________________________
37 //_________________________________________________________________________________________________________________
38 #include <threadhelp/resetableguard.hxx>
40 #ifndef __FRAMEWORK_CLASSES_RESOURCE_HRC_
41 #include <classes/resource.hrc>
43 #include <classes/fwkresid.hxx>
44 #include <classes/bmkmenu.hxx>
45 #include <helper/imageproducer.hxx>
46 #include <xml/menuconfiguration.hxx>
48 //_________________________________________________________________________________________________________________
50 //_________________________________________________________________________________________________________________
51 #include <com/sun/star/awt/XDevice.hpp>
52 #include <com/sun/star/beans/PropertyValue.hpp>
53 #include <com/sun/star/awt/MenuItemStyle.hpp>
54 #include <com/sun/star/ui/XModuleUIConfigurationManagerSupplier.hpp>
55 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
56 #include <com/sun/star/frame/XModuleManager.hpp>
57 #include <com/sun/star/container/XNameAccess.hpp>
58 #include <com/sun/star/document/CorruptedFilterConfigurationException.hpp>
60 //_________________________________________________________________________________________________________________
61 // includes of other projects
62 //_________________________________________________________________________________________________________________
63 #include <vcl/svapp.hxx>
64 #include <vcl/i18nhelp.hxx>
65 #include <tools/urlobj.hxx>
66 #include <rtl/ustrbuf.hxx>
67 #include <cppuhelper/implbase1.hxx>
68 #include <osl/file.hxx>
69 #include <svtools/menuoptions.hxx>
70 #include <svtools/acceleratorexecute.hxx>
71 #include <svtools/moduleoptions.hxx>
72 #include <dispatch/uieventloghelper.hxx>
74 //_________________________________________________________________________________________________________________
76 //_________________________________________________________________________________________________________________
79 using namespace com::sun::star::uno
;
80 using namespace com::sun::star::lang
;
81 using namespace com::sun::star::frame
;
82 using namespace com::sun::star::beans
;
83 using namespace com::sun::star::util
;
84 using namespace com::sun::star::container
;
85 using namespace com::sun::star::ui
;
87 static const char SFX_REFERER_USER
[] = "private:user";
92 DEFINE_XSERVICEINFO_MULTISERVICE ( NewMenuController
,
94 SERVICENAME_POPUPMENUCONTROLLER
,
95 IMPLEMENTATIONNAME_NEWMENUCONTROLLER
98 DEFINE_INIT_SERVICE ( NewMenuController
, {} )
100 void NewMenuController::setMenuImages( PopupMenu
* pPopupMenu
, sal_Bool bSetImages
, sal_Bool bHiContrast
)
102 USHORT nItemCount
= pPopupMenu
->GetItemCount();
104 Reference
< XFrame
> xFrame( m_xFrame
);
106 for ( USHORT i
= 0; i
< nItemCount
; i
++ )
108 USHORT nItemId
= pPopupMenu
->GetItemId( sal::static_int_cast
<USHORT
>( i
));
113 sal_Bool
bImageSet( sal_False
);
114 ::rtl::OUString aImageId
;
116 AddInfoForId::const_iterator pInfo
= m_aAddInfoForItem
.find( nItemId
);
117 if ( pInfo
!= m_aAddInfoForItem
.end() )
118 aImageId
= pInfo
->second
.aImageId
; // Retrieve image id for menu item
120 if ( aImageId
.getLength() > 0 )
122 aImage
= GetImageFromURL( xFrame
, aImageId
, FALSE
, bHiContrast
);
125 bImageSet
= sal_True
;
126 pPopupMenu
->SetItemImage( nItemId
, aImage
);
132 String
aCmd( pPopupMenu
->GetItemCommand( nItemId
) );
134 aImage
= GetImageFromURL( xFrame
, aCmd
, FALSE
, bHiContrast
);
137 pPopupMenu
->SetItemImage( nItemId
, aImage
);
141 pPopupMenu
->SetItemImage( nItemId
, aImage
);
146 void NewMenuController::determineAndSetNewDocAccel( PopupMenu
* pPopupMenu
, const KeyCode
& rKeyCode
)
148 USHORT
nCount( pPopupMenu
->GetItemCount() );
150 sal_Bool
bFound( sal_False
);
151 rtl::OUString aCommand
;
153 if ( m_aEmptyDocURL
.getLength() > 0 )
155 // Search for the empty document URL
157 for ( sal_uInt32 i
= 0; i
< sal_uInt32( nCount
); i
++ )
159 nId
= pPopupMenu
->GetItemId( USHORT( i
));
160 if ( nId
!= 0 && pPopupMenu
->GetItemType( nId
) != MENUITEM_SEPARATOR
)
162 aCommand
= pPopupMenu
->GetItemCommand( nId
);
163 if ( aCommand
.indexOf( m_aEmptyDocURL
) == 0 )
165 pPopupMenu
->SetAccelKey( nId
, rKeyCode
);
175 // Search for the default module name
176 rtl::OUString
aDefaultModuleName( SvtModuleOptions().GetDefaultModuleName() );
177 if ( aDefaultModuleName
.getLength() > 0 )
179 for ( sal_uInt32 i
= 0; i
< sal_uInt32( nCount
); i
++ )
181 nId
= pPopupMenu
->GetItemId( USHORT( i
));
182 if ( nId
!= 0 && pPopupMenu
->GetItemType( nId
) != MENUITEM_SEPARATOR
)
184 aCommand
= pPopupMenu
->GetItemCommand( nId
);
185 if ( aCommand
.indexOf( aDefaultModuleName
) >= 0 )
187 pPopupMenu
->SetAccelKey( nId
, rKeyCode
);
196 void NewMenuController::setAccelerators( PopupMenu
* pPopupMenu
)
198 if ( m_bModuleIdentified
)
200 Reference
< XAcceleratorConfiguration
> xDocAccelCfg( m_xDocAcceleratorManager
);
201 Reference
< XAcceleratorConfiguration
> xModuleAccelCfg( m_xModuleAcceleratorManager
);
202 Reference
< XAcceleratorConfiguration
> xGlobalAccelCfg( m_xGlobalAcceleratorManager
);
204 if ( !m_bAcceleratorCfg
)
206 // Retrieve references on demand
207 m_bAcceleratorCfg
= sal_True
;
208 if ( !xDocAccelCfg
.is() )
210 Reference
< XController
> xController
= m_xFrame
->getController();
211 Reference
< XModel
> xModel
;
212 if ( xController
.is() )
214 xModel
= xController
->getModel();
217 Reference
< XUIConfigurationManagerSupplier
> xSupplier( xModel
, UNO_QUERY
);
218 if ( xSupplier
.is() )
220 Reference
< XUIConfigurationManager
> xDocUICfgMgr( xSupplier
->getUIConfigurationManager(), UNO_QUERY
);
221 if ( xDocUICfgMgr
.is() )
223 xDocAccelCfg
= Reference
< XAcceleratorConfiguration
>( xDocUICfgMgr
->getShortCutManager(), UNO_QUERY
);
224 m_xDocAcceleratorManager
= xDocAccelCfg
;
231 if ( !xModuleAccelCfg
.is() )
233 Reference
< XModuleUIConfigurationManagerSupplier
> xModuleCfgMgrSupplier( m_xServiceManager
->createInstance(
234 SERVICENAME_MODULEUICONFIGURATIONMANAGERSUPPLIER
),
236 Reference
< XUIConfigurationManager
> xUICfgMgr
= xModuleCfgMgrSupplier
->getUIConfigurationManager( m_aModuleIdentifier
);
237 if ( xUICfgMgr
.is() )
239 xModuleAccelCfg
= Reference
< XAcceleratorConfiguration
>( xUICfgMgr
->getShortCutManager(), UNO_QUERY
);
240 m_xModuleAcceleratorManager
= xModuleAccelCfg
;
244 if ( !xGlobalAccelCfg
.is() )
246 xGlobalAccelCfg
= Reference
< XAcceleratorConfiguration
>( m_xServiceManager
->createInstance(
247 SERVICENAME_GLOBALACCELERATORCONFIGURATION
),
249 m_xGlobalAcceleratorManager
= xGlobalAccelCfg
;
253 KeyCode aEmptyKeyCode
;
254 sal_uInt32
nItemCount( pPopupMenu
->GetItemCount() );
255 std::vector
< KeyCode
> aMenuShortCuts
;
256 std::vector
< rtl::OUString
> aCmds
;
257 std::vector
< sal_uInt32
> aIds
;
258 for ( sal_uInt32 i
= 0; i
< nItemCount
; i
++ )
260 USHORT
nId( pPopupMenu
->GetItemId( USHORT( i
)));
261 if ( nId
& ( pPopupMenu
->GetItemType( nId
) != MENUITEM_SEPARATOR
))
263 aIds
.push_back( nId
);
264 aMenuShortCuts
.push_back( aEmptyKeyCode
);
265 aCmds
.push_back( pPopupMenu
->GetItemCommand( nId
));
269 sal_uInt32
nSeqCount( aIds
.size() );
274 Sequence
< rtl::OUString
> aSeq( nSeqCount
);
276 // Add a special command for our "New" menu.
279 aSeq
[nSeqCount
-1] = m_aCommandURL
;
280 aMenuShortCuts
.push_back( aEmptyKeyCode
);
283 const sal_uInt32 nCount
= aCmds
.size();
284 for ( sal_uInt32 i
= 0; i
< nCount
; i
++ )
287 if ( m_xGlobalAcceleratorManager
.is() )
288 retrieveShortcutsFromConfiguration( xGlobalAccelCfg
, aSeq
, aMenuShortCuts
);
289 if ( m_xModuleAcceleratorManager
.is() )
290 retrieveShortcutsFromConfiguration( xModuleAccelCfg
, aSeq
, aMenuShortCuts
);
291 if ( m_xDocAcceleratorManager
.is() )
292 retrieveShortcutsFromConfiguration( xGlobalAccelCfg
, aSeq
, aMenuShortCuts
);
294 const sal_uInt32 nCount2
= aIds
.size();
295 for ( sal_uInt32 i
= 0; i
< nCount2
; i
++ )
296 pPopupMenu
->SetAccelKey( USHORT( aIds
[i
] ), aMenuShortCuts
[i
] );
298 // Special handling for "New" menu short-cut should be set at the
299 // document which will be opened using it.
302 if ( aMenuShortCuts
[nSeqCount
-1] != aEmptyKeyCode
)
303 determineAndSetNewDocAccel( pPopupMenu
, aMenuShortCuts
[nSeqCount
-1] );
308 void NewMenuController::retrieveShortcutsFromConfiguration(
309 const Reference
< XAcceleratorConfiguration
>& rAccelCfg
,
310 const Sequence
< rtl::OUString
>& rCommands
,
311 std::vector
< KeyCode
>& aMenuShortCuts
)
313 if ( rAccelCfg
.is() )
317 com::sun::star::awt::KeyEvent aKeyEvent
;
318 Sequence
< Any
> aSeqKeyCode
= rAccelCfg
->getPreferredKeyEventsForCommandList( rCommands
);
319 for ( sal_Int32 i
= 0; i
< aSeqKeyCode
.getLength(); i
++ )
321 if ( aSeqKeyCode
[i
] >>= aKeyEvent
)
322 aMenuShortCuts
[i
] = svt::AcceleratorExecute::st_AWTKey2VCLKey( aKeyEvent
);
325 catch ( IllegalArgumentException
& )
331 NewMenuController::NewMenuController( const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
>& xServiceManager
) :
332 PopupMenuControllerBase( xServiceManager
),
333 m_bShowImages( sal_True
),
334 m_bHiContrast( sal_False
),
335 m_bNewMenu( sal_False
),
336 m_bModuleIdentified( sal_False
),
337 m_bAcceleratorCfg( sal_False
),
338 m_aTargetFrame( RTL_CONSTASCII_USTRINGPARAM( "_default" ))
342 NewMenuController::~NewMenuController()
347 void NewMenuController::fillPopupMenu( Reference
< css::awt::XPopupMenu
>& rPopupMenu
)
349 VCLXPopupMenu
* pPopupMenu
= (VCLXPopupMenu
*)VCLXMenu::GetImplementation( rPopupMenu
);
350 PopupMenu
* pVCLPopupMenu
= 0;
352 vos::OGuard
aSolarMutexGuard( Application::GetSolarMutex() );
354 resetPopupMenu( rPopupMenu
);
356 pVCLPopupMenu
= (PopupMenu
*)pPopupMenu
->GetMenu();
360 MenuConfiguration
aMenuCfg( m_xServiceManager
);
361 BmkMenu
* pSubMenu( 0 );
364 pSubMenu
= (BmkMenu
*)aMenuCfg
.CreateBookmarkMenu( m_xFrame
, BOOKMARK_NEWMENU
);
366 pSubMenu
= (BmkMenu
*)aMenuCfg
.CreateBookmarkMenu( m_xFrame
, BOOKMARK_WIZARDMENU
);
368 // copy entries as we have to use the provided popup menu
369 *pVCLPopupMenu
= *pSubMenu
;
374 // retrieve additional parameters from bookmark menu and
375 // store it in a hash_map.
376 for ( USHORT i
= 0; i
< pSubMenu
->GetItemCount(); i
++ )
378 USHORT nItemId
= pSubMenu
->GetItemId( sal::static_int_cast
<USHORT
>( i
) );
379 if (( nItemId
!= 0 ) &&
380 ( pSubMenu
->GetItemType( nItemId
) != MENUITEM_SEPARATOR
))
382 MenuConfiguration::Attributes
* pBmkAttributes
= (MenuConfiguration::Attributes
*)(pSubMenu
->GetUserValue( nItemId
));
383 if ( pBmkAttributes
!= 0 )
385 aAddInfo
.aTargetFrame
= pBmkAttributes
->aTargetFrame
;
386 aAddInfo
.aImageId
= pBmkAttributes
->aImageId
;
388 m_aAddInfoForItem
.insert( AddInfoForId::value_type( nItemId
, aAddInfo
));
394 setMenuImages( pVCLPopupMenu
, m_bShowImages
, m_bHiContrast
);
401 void SAL_CALL
NewMenuController::disposing( const EventObject
& ) throw ( RuntimeException
)
403 Reference
< css::awt::XMenuListener
> xHolder(( OWeakObject
*)this, UNO_QUERY
);
405 ResetableGuard
aLock( m_aLock
);
408 m_xServiceManager
.clear();
410 if ( m_xPopupMenu
.is() )
411 m_xPopupMenu
->removeMenuListener( Reference
< css::awt::XMenuListener
>(( OWeakObject
*)this, UNO_QUERY
));
412 m_xPopupMenu
.clear();
416 void SAL_CALL
NewMenuController::statusChanged( const FeatureStateEvent
& ) throw ( RuntimeException
)
421 void SAL_CALL
NewMenuController::select( const css::awt::MenuEvent
& rEvent
) throw (RuntimeException
)
423 Reference
< css::awt::XPopupMenu
> xPopupMenu
;
424 Reference
< XDispatch
> xDispatch
;
425 Reference
< XDispatchProvider
> xDispatchProvider
;
426 Reference
< XMultiServiceFactory
> xServiceManager
;
427 Reference
< XURLTransformer
> xURLTransformer
;
429 ResetableGuard
aLock( m_aLock
);
430 xPopupMenu
= m_xPopupMenu
;
431 xDispatchProvider
= Reference
< XDispatchProvider
>( m_xFrame
, UNO_QUERY
);
432 xServiceManager
= m_xServiceManager
;
433 xURLTransformer
= m_xURLTransformer
;
436 css::util::URL aTargetURL
;
437 Sequence
< PropertyValue
> aArgsList( 1 );
439 if ( xPopupMenu
.is() && xDispatchProvider
.is() )
441 VCLXPopupMenu
* pPopupMenu
= (VCLXPopupMenu
*)VCLXPopupMenu::GetImplementation( xPopupMenu
);
445 vos::OGuard
aSolarMutexGuard( Application::GetSolarMutex() );
446 PopupMenu
* pVCLPopupMenu
= (PopupMenu
*)pPopupMenu
->GetMenu();
447 aTargetURL
.Complete
= pVCLPopupMenu
->GetItemCommand( rEvent
.MenuId
);
450 xURLTransformer
->parseStrict( aTargetURL
);
452 aArgsList
[0].Name
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Referer" ));
453 aArgsList
[0].Value
= makeAny( ::rtl::OUString::createFromAscii( SFX_REFERER_USER
));
455 rtl::OUString
aTargetFrame( m_aTargetFrame
);
456 AddInfoForId::const_iterator pItem
= m_aAddInfoForItem
.find( rEvent
.MenuId
);
457 if ( pItem
!= m_aAddInfoForItem
.end() )
458 aTargetFrame
= pItem
->second
.aTargetFrame
;
460 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, aTargetFrame
, 0 );
464 if ( xDispatch
.is() )
466 // Call dispatch asychronously as we can be destroyed while dispatch is
467 // executed. VCL is not able to survive this as it wants to call listeners
469 NewDocument
* pNewDocument
= new NewDocument
;
470 pNewDocument
->xDispatch
= xDispatch
;
471 pNewDocument
->aTargetURL
= aTargetURL
;
472 pNewDocument
->aArgSeq
= aArgsList
;
473 if(::comphelper::UiEventsLogger::isEnabled()) //#i88653#
474 UiEventLogHelper(::rtl::OUString::createFromAscii("NewMenuController")).log(m_xServiceManager
, m_xFrame
, aTargetURL
, aArgsList
);
475 Application::PostUserEvent( STATIC_LINK(0, NewMenuController
, ExecuteHdl_Impl
), pNewDocument
);
479 void SAL_CALL
NewMenuController::activate( const css::awt::MenuEvent
& ) throw (RuntimeException
)
481 vos::OGuard
aSolarMutexGuard( Application::GetSolarMutex() );
482 if ( m_xFrame
.is() && m_xPopupMenu
.is() )
484 VCLXPopupMenu
* pPopupMenu
= (VCLXPopupMenu
*)VCLXPopupMenu::GetImplementation( m_xPopupMenu
);
487 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
488 sal_Bool
bShowImages( rSettings
.GetUseImagesInMenus() );
489 sal_Bool
bHiContrast( rSettings
.GetHighContrastMode() );
491 PopupMenu
* pVCLPopupMenu
= (PopupMenu
*)pPopupMenu
->GetMenu();
493 if (( m_bShowImages
!= bShowImages
) ||
494 ( m_bHiContrast
!= bHiContrast
))
496 m_bShowImages
= bShowImages
;
497 m_bHiContrast
= bHiContrast
;
499 setMenuImages( pVCLPopupMenu
, m_bShowImages
, m_bHiContrast
);
502 setAccelerators( pVCLPopupMenu
);
507 // XPopupMenuController
508 void NewMenuController::impl_setPopupMenu()
511 if ( m_xPopupMenu
.is() )
512 fillPopupMenu( m_xPopupMenu
);
514 // Identify module that we are attach to. It's our context that we need to know.
515 Reference
< XModuleManager
> xModuleManager( m_xServiceManager
->createInstance( SERVICENAME_MODULEMANAGER
),UNO_QUERY
);
516 if ( xModuleManager
.is() )
520 m_aModuleIdentifier
= xModuleManager
->identify( m_xFrame
);
521 m_bModuleIdentified
= sal_True
;
523 Reference
< XNameAccess
> xNameAccess( xModuleManager
, UNO_QUERY
);
524 if (( m_aModuleIdentifier
.getLength() > 0 ) && xNameAccess
.is() )
526 Sequence
< PropertyValue
> aSeq
;
528 if ( xNameAccess
->getByName( m_aModuleIdentifier
) >>= aSeq
)
530 for ( sal_Int32 y
= 0; y
< aSeq
.getLength(); y
++ )
532 if ( aSeq
[y
].Name
.equalsAscii("ooSetupFactoryEmptyDocumentURL") )
534 aSeq
[y
].Value
>>= m_aEmptyDocURL
;
541 catch ( RuntimeException
& e
)
552 void SAL_CALL
NewMenuController::initialize( const Sequence
< Any
>& aArguments
) throw ( Exception
, RuntimeException
)
554 ResetableGuard
aLock( m_aLock
);
556 sal_Bool
bInitalized( m_bInitialized
);
559 PopupMenuControllerBase::initialize( aArguments
);
561 if ( m_bInitialized
)
563 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
565 m_bShowImages
= rSettings
.GetUseImagesInMenus();
566 m_bHiContrast
= rSettings
.GetHighContrastMode();
568 m_bNewMenu
= m_aCommandURL
.equalsAscii( ".uno:AddDirect" );
573 IMPL_STATIC_LINK_NOINSTANCE( NewMenuController
, ExecuteHdl_Impl
, NewDocument
*, pNewDocument
)
575 /* i62706: Don't catch all exceptions. We hide all problems here and are not able
576 to handle them on higher levels.
580 // Asynchronous execution as this can lead to our own destruction!
581 // Framework can recycle our current frame and the layout manager disposes all user interface
582 // elements if a component gets detached from its frame!
583 pNewDocument
->xDispatch
->dispatch( pNewDocument
->aTargetURL
, pNewDocument
->aArgSeq
);
586 catch (const ::com::sun::star::document::CorruptedFilterConfigurationException& exFilters)
590 catch (const Exception& )