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: contextmenuhelper.cxx,v $
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_svtools.hxx"
34 #include "contextmenuhelper.hxx"
35 #include <svtools/menuoptions.hxx>
36 #include <svtools/miscopt.hxx>
38 #include <com/sun/star/frame/XDispatch.hpp>
39 #include <com/sun/star/frame/XDispatchProvider.hpp>
40 #include <com/sun/star/frame/XModuleManager.hpp>
41 #include <com/sun/star/frame/XStatusListener.hpp>
42 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
43 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
44 #include <com/sun/star/ui/XUIConfigurationManager.hpp>
45 #include <com/sun/star/ui/XModuleUIConfigurationManagerSupplier.hpp>
46 #include <com/sun/star/ui/ImageType.hpp>
47 #include <com/sun/star/beans/PropertyValue.hpp>
49 #include <osl/conditn.hxx>
50 #include <cppuhelper/weak.hxx>
51 #include <comphelper/processfactory.hxx>
52 #include <vos/mutex.hxx>
53 #include <vcl/svapp.hxx>
54 #include <vcl/image.hxx>
55 #include <toolkit/unohlp.hxx>
56 #include <toolkit/awt/vclxwindow.hxx>
57 #include <toolkit/awt/vclxmenu.hxx>
59 using namespace ::com::sun::star
;
64 // internal helper class to retrieve status updates
65 class StateEventHelper
: public ::com::sun::star::frame::XStatusListener
,
66 public ::cppu::OWeakObject
69 StateEventHelper( const uno::Reference
< frame::XDispatchProvider
>& xDispatchProvider
,
70 const uno::Reference
< util::XURLTransformer
>& xURLTransformer
,
71 const rtl::OUString
& aCommandURL
);
72 virtual ~StateEventHelper();
74 bool isCommandEnabled();
77 virtual uno::Any SAL_CALL
queryInterface( const uno::Type
& aType
) throw ( uno::RuntimeException
);
78 virtual void SAL_CALL
acquire() throw ();
79 virtual void SAL_CALL
release() throw ();
82 virtual void SAL_CALL
disposing(const lang::EventObject
& Source
) throw( uno::RuntimeException
);
85 virtual void SAL_CALL
statusChanged(const frame::FeatureStateEvent
& Event
) throw( uno::RuntimeException
);
89 StateEventHelper( const StateEventHelper
& );
90 StateEventHelper
& operator=( const StateEventHelper
& );
92 bool m_bCurrentCommandEnabled
;
93 ::rtl::OUString m_aCommandURL
;
94 uno::Reference
< frame::XDispatchProvider
> m_xDispatchProvider
;
95 uno::Reference
< util::XURLTransformer
> m_xURLTransformer
;
96 osl::Condition m_aCondition
;
99 StateEventHelper::StateEventHelper(
100 const uno::Reference
< frame::XDispatchProvider
>& xDispatchProvider
,
101 const uno::Reference
< util::XURLTransformer
>& xURLTransformer
,
102 const rtl::OUString
& rCommandURL
) :
103 m_bCurrentCommandEnabled( true ),
104 m_aCommandURL( rCommandURL
),
105 m_xDispatchProvider( xDispatchProvider
),
106 m_xURLTransformer( xURLTransformer
)
108 m_aCondition
.reset();
111 StateEventHelper::~StateEventHelper()
114 uno::Any SAL_CALL
StateEventHelper::queryInterface(
115 const uno::Type
& aType
)
116 throw ( uno::RuntimeException
)
118 uno::Any a
= ::cppu::queryInterface(
120 SAL_STATIC_CAST( XStatusListener
*, this ));
125 return ::cppu::OWeakObject::queryInterface( aType
);
128 void SAL_CALL
StateEventHelper::acquire()
131 ::cppu::OWeakObject::acquire();
134 void SAL_CALL
StateEventHelper::release()
137 ::cppu::OWeakObject::release();
140 void SAL_CALL
StateEventHelper::disposing(
141 const lang::EventObject
& )
142 throw ( uno::RuntimeException
)
144 vos::OGuard
aSolarGuard( Application::GetSolarMutex() );
145 m_xDispatchProvider
.clear();
146 m_xURLTransformer
.clear();
150 void SAL_CALL
StateEventHelper::statusChanged(
151 const frame::FeatureStateEvent
& Event
)
152 throw ( uno::RuntimeException
)
154 vos::OGuard
aSolarGuard( Application::GetSolarMutex() );
155 m_bCurrentCommandEnabled
= Event
.IsEnabled
;
159 bool StateEventHelper::isCommandEnabled()
161 // Be sure that we cannot die during condition wait
162 uno::Reference
< frame::XStatusListener
> xSelf(
163 SAL_STATIC_CAST( frame::XStatusListener
*, this ));
165 uno::Reference
< frame::XDispatch
> xDispatch
;
166 util::URL aTargetURL
;
168 vos::OGuard
aSolarGuard( Application::GetSolarMutex() );
169 if ( m_xDispatchProvider
.is() && m_xURLTransformer
.is() )
171 ::rtl::OUString
aSelf( RTL_CONSTASCII_USTRINGPARAM( "_self" ));
173 aTargetURL
.Complete
= m_aCommandURL
;
174 m_xURLTransformer
->parseStrict( aTargetURL
);
178 xDispatch
= m_xDispatchProvider
->queryDispatch( aTargetURL
, aSelf
, 0 );
180 catch ( uno::RuntimeException
& )
184 catch ( uno::Exception
& )
190 bool bResult( false );
191 if ( xDispatch
.is() )
195 // add/remove ourself to retrieve status by callback
196 xDispatch
->addStatusListener( xSelf
, aTargetURL
);
197 xDispatch
->removeStatusListener( xSelf
, aTargetURL
);
202 catch ( uno::RuntimeException
& )
206 catch ( uno::Exception
& )
210 vos::OGuard
aSolarGuard( Application::GetSolarMutex() );
211 bResult
= m_bCurrentCommandEnabled
;
217 /*************************************************************************/
221 uno::Reference
< frame::XDispatch
> xDispatch
;
222 util::URL aTargetURL
;
223 uno::Sequence
< beans::PropertyValue
> aArgs
;
226 static const PopupMenu
* lcl_FindPopupFromItemId( const PopupMenu
* pPopupMenu
, sal_uInt16 nItemId
)
230 sal_uInt16 nCount
= pPopupMenu
->GetItemCount();
231 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
233 sal_uInt16 nId
= pPopupMenu
->GetItemId( i
);
234 if ( nId
== nItemId
)
238 const PopupMenu
* pResult( 0 );
240 const PopupMenu
* pSubPopup
= pPopupMenu
->GetPopupMenu( i
);
242 pResult
= lcl_FindPopupFromItemId( pSubPopup
, nItemId
);
252 static ::rtl::OUString
lcl_GetItemCommandRecursive( const PopupMenu
* pPopupMenu
, sal_uInt16 nItemId
)
254 const PopupMenu
* pPopup
= lcl_FindPopupFromItemId( pPopupMenu
, nItemId
);
256 return pPopup
->GetItemCommand( nItemId
);
258 return ::rtl::OUString();
261 /*************************************************************************/
263 ContextMenuHelper::ContextMenuHelper(
264 const uno::Reference
< frame::XFrame
>& xFrame
,
265 bool bAutoRefresh
) :
266 m_xWeakFrame( xFrame
),
267 m_aSelf( RTL_CONSTASCII_USTRINGPARAM( "_self" )),
268 m_bAutoRefresh( bAutoRefresh
),
269 m_bUICfgMgrAssociated( false )
273 ContextMenuHelper::~ContextMenuHelper()
278 ContextMenuHelper::completeAndExecute(
280 PopupMenu
& rPopupMenu
)
282 vos::OGuard
aSolarGuard( Application::GetSolarMutex() );
284 associateUIConfigurationManagers();
285 completeMenuProperties( &rPopupMenu
);
286 executePopupMenu( aPos
, &rPopupMenu
);
291 ContextMenuHelper::completeAndExecute(
293 const uno::Reference
< awt::XPopupMenu
>& xPopupMenu
)
295 vos::OGuard
aSolarGuard( Application::GetSolarMutex() );
297 VCLXMenu
* pXMenu
= VCLXMenu::GetImplementation( xPopupMenu
);
300 PopupMenu
* pPopupMenu
= dynamic_cast< PopupMenu
* >( pXMenu
->GetMenu() );
301 // as dynamic_cast can return zero check pointer
304 associateUIConfigurationManagers();
305 completeMenuProperties( pPopupMenu
);
306 executePopupMenu( aPos
, pPopupMenu
);
312 uno::Reference
< awt::XPopupMenu
>
313 ContextMenuHelper::create(
314 const ::rtl::OUString
& /*aPopupMenuResourceId*/ )
316 // NOT IMPLEMENTED YET!
317 return uno::Reference
< awt::XPopupMenu
>();
321 ContextMenuHelper::createAndExecute(
322 const Point
& /*aPos*/,
323 const ::rtl::OUString
& /*aPopupMenuResourceId*/ )
325 // NOT IMPLEMENTED YET!
332 ContextMenuHelper::executePopupMenu(
338 uno::Reference
< frame::XFrame
> xFrame( m_xWeakFrame
);
341 uno::Reference
< awt::XWindow
> xWindow( xFrame
->getContainerWindow() );
344 Window
* pParent
= VCLUnoHelper::GetWindow( xWindow
);
345 sal_uInt16 nResult
= pMenu
->Execute( pParent
, rPos
);
349 ::rtl::OUString aCommand
= lcl_GetItemCommandRecursive( pMenu
, nResult
);
350 if ( aCommand
.getLength() > 0 )
351 dispatchCommand( xFrame
, aCommand
);
359 ContextMenuHelper::dispatchCommand(
360 const uno::Reference
< ::frame::XFrame
>& rFrame
,
361 const ::rtl::OUString
& aCommandURL
)
363 if ( !m_xURLTransformer
.is() )
365 m_xURLTransformer
= uno::Reference
< util::XURLTransformer
>(
366 ::comphelper::getProcessServiceFactory()->createInstance(
367 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
368 "com.sun.star.util.URLTransformer" ))),
372 util::URL aTargetURL
;
373 uno::Reference
< frame::XDispatch
> xDispatch
;
374 if ( m_xURLTransformer
.is() )
376 aTargetURL
.Complete
= aCommandURL
;
377 m_xURLTransformer
->parseStrict( aTargetURL
);
379 uno::Reference
< frame::XDispatchProvider
> xDispatchProvider(
380 rFrame
, uno::UNO_QUERY
);
381 if ( xDispatchProvider
.is() )
385 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, m_aSelf
, 0 );
387 catch ( uno::RuntimeException
& )
391 catch ( uno::Exception
& )
397 if ( xDispatch
.is() )
399 ExecuteInfo
* pExecuteInfo
= new ExecuteInfo
;
400 pExecuteInfo
->xDispatch
= xDispatch
;
401 pExecuteInfo
->aTargetURL
= aTargetURL
;
402 pExecuteInfo
->aArgs
= m_aDefaultArgs
;
404 Application::PostUserEvent( STATIC_LINK(0, ContextMenuHelper
, ExecuteHdl_Impl
), pExecuteInfo
);
411 // retrieves and stores references to our user-interface
412 // configuration managers, like image manager, ui command
413 // description manager.
415 ContextMenuHelper::associateUIConfigurationManagers()
417 uno::Reference
< frame::XFrame
> xFrame( m_xWeakFrame
);
418 if ( !m_bUICfgMgrAssociated
&& xFrame
.is() )
420 // clear current state
421 m_xDocImageMgr
.clear();
422 m_xModuleImageMgr
.clear();
423 m_xUICommandLabels
.clear();
427 uno::Reference
< frame::XController
> xController
;
428 uno::Reference
< frame::XModel
> xModel
;
429 xController
= xFrame
->getController();
430 if ( xController
.is() )
431 xModel
= xController
->getModel();
435 // retrieve document image manager form model
436 uno::Reference
< ui::XUIConfigurationManagerSupplier
> xSupplier( xModel
, uno::UNO_QUERY
);
437 if ( xSupplier
.is() )
439 uno::Reference
< ui::XUIConfigurationManager
> xDocUICfgMgr(
440 xSupplier
->getUIConfigurationManager(), uno::UNO_QUERY
);
441 m_xDocImageMgr
= uno::Reference
< ui::XImageManager
>(
442 xDocUICfgMgr
->getImageManager(), uno::UNO_QUERY
);
446 uno::Reference
< frame::XModuleManager
> xModuleManager(
447 ::comphelper::getProcessServiceFactory()->createInstance(
448 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
449 "com.sun.star.frame.ModuleManager" ))),
452 uno::Reference
< ui::XImageManager
> xModuleImageManager
;
453 rtl::OUString aModuleId
;
454 if ( xModuleManager
.is() )
456 // retrieve module image manager
457 aModuleId
= xModuleManager
->identify( xFrame
);
459 uno::Reference
< ui::XModuleUIConfigurationManagerSupplier
> xModuleCfgMgrSupplier(
460 ::comphelper::getProcessServiceFactory()->createInstance(
461 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
462 "com.sun.star.ui.ModuleUIConfigurationManagerSupplier" ))),
464 if ( xModuleCfgMgrSupplier
.is() )
466 uno::Reference
< ui::XUIConfigurationManager
> xUICfgMgr(
467 xModuleCfgMgrSupplier
->getUIConfigurationManager( aModuleId
));
468 if ( xUICfgMgr
.is() )
470 m_xModuleImageMgr
= uno::Reference
< ui::XImageManager
>(
471 xUICfgMgr
->getImageManager(), uno::UNO_QUERY
);
476 uno::Reference
< container::XNameAccess
> xNameAccess(
477 ::comphelper::getProcessServiceFactory()->createInstance(
478 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
479 "com.sun.star.frame.UICommandDescription" ))),
481 if ( xNameAccess
.is() )
485 uno::Any a
= xNameAccess
->getByName( aModuleId
);
486 a
>>= m_xUICommandLabels
;
488 catch ( container::NoSuchElementException
& )
493 catch ( uno::RuntimeException
& )
497 catch ( uno::Exception
& )
499 m_bUICfgMgrAssociated
= true;
502 m_bUICfgMgrAssociated
= true;
509 ContextMenuHelper::getImageFromCommandURL(
510 const ::rtl::OUString
& aCmdURL
,
511 bool bHiContrast
) const
514 sal_Int16
nImageType( ui::ImageType::COLOR_NORMAL
|
515 ui::ImageType::SIZE_DEFAULT
);
517 nImageType
|= ui::ImageType::COLOR_HIGHCONTRAST
;
519 uno::Sequence
< uno::Reference
< graphic::XGraphic
> > aGraphicSeq
;
520 uno::Sequence
< ::rtl::OUString
> aImageCmdSeq( 1 );
521 aImageCmdSeq
[0] = aCmdURL
;
523 if ( m_xDocImageMgr
.is() )
527 aGraphicSeq
= m_xDocImageMgr
->getImages( nImageType
, aImageCmdSeq
);
528 uno::Reference
< graphic::XGraphic
> xGraphic
= aGraphicSeq
[0];
529 aImage
= Image( xGraphic
);
534 catch ( uno::RuntimeException
& )
538 catch ( uno::Exception
& )
543 if ( m_xModuleImageMgr
.is() )
547 aGraphicSeq
= m_xModuleImageMgr
->getImages( nImageType
, aImageCmdSeq
);
548 uno::Reference
< ::com::sun::star::graphic::XGraphic
> xGraphic
= aGraphicSeq
[0];
549 aImage
= Image( xGraphic
);
554 catch ( uno::RuntimeException
& )
558 catch ( uno::Exception
& )
567 ContextMenuHelper::getLabelFromCommandURL(
568 const ::rtl::OUString
& aCmdURL
) const
570 ::rtl::OUString aLabel
;
572 if ( m_xUICommandLabels
.is() )
576 if ( aCmdURL
.getLength() > 0 )
579 uno::Sequence
< beans::PropertyValue
> aPropSeq
;
580 uno::Any
a( m_xUICommandLabels
->getByName( aCmdURL
));
581 if ( a
>>= aPropSeq
)
583 for ( sal_Int32 i
= 0; i
< aPropSeq
.getLength(); i
++ )
585 if ( aPropSeq
[i
].Name
.equalsAscii( "Label" ))
587 aPropSeq
[i
].Value
>>= aStr
;
595 catch ( uno::RuntimeException
& )
598 catch ( uno::Exception
& )
607 ContextMenuHelper::completeMenuProperties(
610 // Retrieve some settings necessary to display complete context
612 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
613 bool bShowMenuImages( rSettings
.GetUseImagesInMenus() );
614 bool bIsHiContrast( rSettings
.GetMenuColor().IsDark() );
618 uno::Reference
< frame::XFrame
> xFrame( m_xWeakFrame
);
619 uno::Reference
< frame::XDispatchProvider
> xDispatchProvider( xFrame
, uno::UNO_QUERY
);
621 if ( !m_xURLTransformer
.is() )
623 m_xURLTransformer
= uno::Reference
< util::XURLTransformer
>(
624 ::comphelper::getProcessServiceFactory()->createInstance(
625 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
626 "com.sun.star.util.URLTransformer" ))),
630 for ( sal_uInt16 nPos
= 0; nPos
< pMenu
->GetItemCount(); nPos
++ )
632 sal_uInt16 nId
= pMenu
->GetItemId( nPos
);
633 PopupMenu
* pPopupMenu
= pMenu
->GetPopupMenu( nId
);
635 completeMenuProperties( pPopupMenu
);
636 if ( pMenu
->GetItemType( nPos
) != MENUITEM_SEPARATOR
)
638 ::rtl::OUString
aCmdURL( pMenu
->GetItemCommand( nId
));
640 if ( bShowMenuImages
)
643 if ( aCmdURL
.getLength() > 0 )
644 aImage
= getImageFromCommandURL( aCmdURL
, bIsHiContrast
);
645 pMenu
->SetItemImage( nId
, aImage
);
648 pMenu
->SetItemImage( nId
, Image() );
650 if ( pMenu
->GetItemText( nId
).Len() == 0 )
652 ::rtl::OUString
aLabel( getLabelFromCommandURL( aCmdURL
));
653 pMenu
->SetItemText( nId
, aLabel
);
656 // Use helper to retrieve state of the command URL
657 StateEventHelper
* pHelper
= new StateEventHelper(
662 uno::Reference
< frame::XStatusListener
> xHelper( pHelper
);
663 pMenu
->EnableItem( nId
, pHelper
->isCommandEnabled() );
670 IMPL_STATIC_LINK_NOINSTANCE( ContextMenuHelper
, ExecuteHdl_Impl
, ExecuteInfo
*, pExecuteInfo
)
672 // Release solar mutex to prevent deadlocks with clipboard thread
673 const sal_uInt32 nRef
= Application::ReleaseSolarMutex();
676 // Asynchronous execution as this can lead to our own destruction while we are
677 // on the stack. Stack unwinding would access the destroyed context menu.
678 pExecuteInfo
->xDispatch
->dispatch( pExecuteInfo
->aTargetURL
, pExecuteInfo
->aArgs
);
680 catch ( uno::Exception
& )
684 // Acquire solar mutex again
685 Application::AcquireSolarMutex( nRef
);