Update ooo320-m1
[ooovba.git] / svtools / source / uno / contextmenuhelper.cxx
blob90365cee36ac75ad5f9d701d3ff7bba05afcc590
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: contextmenuhelper.cxx,v $
10 * $Revision: 1.5 $
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;
61 namespace svt
64 // internal helper class to retrieve status updates
65 class StateEventHelper : public ::com::sun::star::frame::XStatusListener,
66 public ::cppu::OWeakObject
68 public:
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();
76 // XInterface
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 ();
81 // XEventListener
82 virtual void SAL_CALL disposing(const lang::EventObject& Source) throw( uno::RuntimeException );
84 // XStatusListener
85 virtual void SAL_CALL statusChanged(const frame::FeatureStateEvent& Event) throw( uno::RuntimeException );
87 private:
88 StateEventHelper();
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(
119 aType,
120 SAL_STATIC_CAST( XStatusListener*, this ));
122 if( a.hasValue() )
123 return a;
125 return ::cppu::OWeakObject::queryInterface( aType );
128 void SAL_CALL StateEventHelper::acquire()
129 throw ()
131 ::cppu::OWeakObject::acquire();
134 void SAL_CALL StateEventHelper::release()
135 throw ()
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();
147 m_aCondition.set();
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;
156 m_aCondition.set();
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& )
182 throw;
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 );
199 // wait for anwser
200 m_aCondition.wait();
202 catch ( uno::RuntimeException& )
204 throw;
206 catch ( uno::Exception& )
210 vos::OGuard aSolarGuard( Application::GetSolarMutex() );
211 bResult = m_bCurrentCommandEnabled;
214 return bResult;
217 /*************************************************************************/
219 struct ExecuteInfo
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 )
228 if ( pPopupMenu )
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 )
235 return pPopupMenu;
236 else
238 const PopupMenu* pResult( 0 );
240 const PopupMenu* pSubPopup = pPopupMenu->GetPopupMenu( i );
241 if ( pPopupMenu )
242 pResult = lcl_FindPopupFromItemId( pSubPopup, nItemId );
243 if ( pResult != 0 )
244 return pResult;
249 return NULL;
252 static ::rtl::OUString lcl_GetItemCommandRecursive( const PopupMenu* pPopupMenu, sal_uInt16 nItemId )
254 const PopupMenu* pPopup = lcl_FindPopupFromItemId( pPopupMenu, nItemId );
255 if ( pPopup )
256 return pPopup->GetItemCommand( nItemId );
257 else
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()
277 void
278 ContextMenuHelper::completeAndExecute(
279 const Point& aPos,
280 PopupMenu& rPopupMenu )
282 vos::OGuard aSolarGuard( Application::GetSolarMutex() );
284 associateUIConfigurationManagers();
285 completeMenuProperties( &rPopupMenu );
286 executePopupMenu( aPos, &rPopupMenu );
287 resetAssociations();
290 void
291 ContextMenuHelper::completeAndExecute(
292 const Point& aPos,
293 const uno::Reference< awt::XPopupMenu >& xPopupMenu )
295 vos::OGuard aSolarGuard( Application::GetSolarMutex() );
297 VCLXMenu* pXMenu = VCLXMenu::GetImplementation( xPopupMenu );
298 if ( pXMenu )
300 PopupMenu* pPopupMenu = dynamic_cast< PopupMenu* >( pXMenu->GetMenu() );
301 // as dynamic_cast can return zero check pointer
302 if ( pPopupMenu )
304 associateUIConfigurationManagers();
305 completeMenuProperties( pPopupMenu );
306 executePopupMenu( aPos, pPopupMenu );
307 resetAssociations();
312 uno::Reference< awt::XPopupMenu >
313 ContextMenuHelper::create(
314 const ::rtl::OUString& /*aPopupMenuResourceId*/ )
316 // NOT IMPLEMENTED YET!
317 return uno::Reference< awt::XPopupMenu >();
320 bool
321 ContextMenuHelper::createAndExecute(
322 const Point& /*aPos*/,
323 const ::rtl::OUString& /*aPopupMenuResourceId*/ )
325 // NOT IMPLEMENTED YET!
326 return false;
329 // private member
331 void
332 ContextMenuHelper::executePopupMenu(
333 const Point& rPos,
334 PopupMenu* pMenu )
336 if ( pMenu )
338 uno::Reference< frame::XFrame > xFrame( m_xWeakFrame );
339 if ( xFrame.is() )
341 uno::Reference< awt::XWindow > xWindow( xFrame->getContainerWindow() );
342 if ( xWindow.is() )
344 Window* pParent = VCLUnoHelper::GetWindow( xWindow );
345 sal_uInt16 nResult = pMenu->Execute( pParent, rPos );
347 if ( nResult > 0 )
349 ::rtl::OUString aCommand = lcl_GetItemCommandRecursive( pMenu, nResult );
350 if ( aCommand.getLength() > 0 )
351 dispatchCommand( xFrame, aCommand );
358 bool
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" ))),
369 uno::UNO_QUERY );
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& )
389 throw;
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 );
405 return true;
408 return false;
411 // retrieves and stores references to our user-interface
412 // configuration managers, like image manager, ui command
413 // description manager.
414 bool
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();
433 if ( xModel.is() )
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" ))),
450 uno::UNO_QUERY );
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" ))),
463 uno::UNO_QUERY );
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" ))),
480 uno::UNO_QUERY );
481 if ( xNameAccess.is() )
485 uno::Any a = xNameAccess->getByName( aModuleId );
486 a >>= m_xUICommandLabels;
488 catch ( container::NoSuchElementException& )
493 catch ( uno::RuntimeException& )
495 throw;
497 catch ( uno::Exception& )
499 m_bUICfgMgrAssociated = true;
500 return false;
502 m_bUICfgMgrAssociated = true;
505 return true;
508 Image
509 ContextMenuHelper::getImageFromCommandURL(
510 const ::rtl::OUString& aCmdURL,
511 bool bHiContrast ) const
513 Image aImage;
514 sal_Int16 nImageType( ui::ImageType::COLOR_NORMAL|
515 ui::ImageType::SIZE_DEFAULT );
516 if ( bHiContrast )
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 );
531 if ( !!aImage )
532 return aImage;
534 catch ( uno::RuntimeException& )
536 throw;
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 );
551 if ( !!aImage )
552 return aImage;
554 catch ( uno::RuntimeException& )
556 throw;
558 catch ( uno::Exception& )
563 return aImage;
566 rtl::OUString
567 ContextMenuHelper::getLabelFromCommandURL(
568 const ::rtl::OUString& aCmdURL ) const
570 ::rtl::OUString aLabel;
572 if ( m_xUICommandLabels.is() )
576 if ( aCmdURL.getLength() > 0 )
578 rtl::OUString aStr;
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;
588 break;
592 aLabel = aStr;
595 catch ( uno::RuntimeException& )
598 catch ( uno::Exception& )
603 return aLabel;
606 void
607 ContextMenuHelper::completeMenuProperties(
608 Menu* pMenu )
610 // Retrieve some settings necessary to display complete context
611 // menu correctly.
612 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
613 bool bShowMenuImages( rSettings.GetUseImagesInMenus() );
614 bool bIsHiContrast( rSettings.GetMenuColor().IsDark() );
616 if ( pMenu )
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" ))),
627 uno::UNO_QUERY );
630 for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
632 sal_uInt16 nId = pMenu->GetItemId( nPos );
633 PopupMenu* pPopupMenu = pMenu->GetPopupMenu( nId );
634 if ( pPopupMenu )
635 completeMenuProperties( pPopupMenu );
636 if ( pMenu->GetItemType( nPos ) != MENUITEM_SEPARATOR )
638 ::rtl::OUString aCmdURL( pMenu->GetItemCommand( nId ));
640 if ( bShowMenuImages )
642 Image aImage;
643 if ( aCmdURL.getLength() > 0 )
644 aImage = getImageFromCommandURL( aCmdURL, bIsHiContrast );
645 pMenu->SetItemImage( nId, aImage );
647 else
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(
658 xDispatchProvider,
659 m_xURLTransformer,
660 aCmdURL );
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 );
686 delete pExecuteInfo;
687 return 0;
690 } // namespace svt