summaryrefslogtreecommitdiff
path: root/svtools/source/uno/contextmenuhelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svtools/source/uno/contextmenuhelper.cxx')
-rw-r--r--svtools/source/uno/contextmenuhelper.cxx687
1 files changed, 687 insertions, 0 deletions
diff --git a/svtools/source/uno/contextmenuhelper.cxx b/svtools/source/uno/contextmenuhelper.cxx
new file mode 100644
index 000000000000..9eb36cf18a45
--- /dev/null
+++ b/svtools/source/uno/contextmenuhelper.cxx
@@ -0,0 +1,687 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include "contextmenuhelper.hxx"
+#include <svtools/menuoptions.hxx>
+#include <svtools/miscopt.hxx>
+
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XModuleManager.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/XUIConfigurationManager.hpp>
+#include <com/sun/star/ui/XModuleUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/ImageType.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <osl/conditn.hxx>
+#include <cppuhelper/weak.hxx>
+#include <comphelper/processfactory.hxx>
+#include <vos/mutex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/image.hxx>
+#include <toolkit/unohlp.hxx>
+#include <toolkit/awt/vclxwindow.hxx>
+#include <toolkit/awt/vclxmenu.hxx>
+
+using namespace ::com::sun::star;
+
+namespace svt
+{
+
+// internal helper class to retrieve status updates
+class StateEventHelper : public ::com::sun::star::frame::XStatusListener,
+ public ::cppu::OWeakObject
+{
+ public:
+ StateEventHelper( const uno::Reference< frame::XDispatchProvider >& xDispatchProvider,
+ const uno::Reference< util::XURLTransformer >& xURLTransformer,
+ const rtl::OUString& aCommandURL );
+ virtual ~StateEventHelper();
+
+ bool isCommandEnabled();
+
+ // XInterface
+ virtual uno::Any SAL_CALL queryInterface( const uno::Type& aType ) throw ( uno::RuntimeException);
+ virtual void SAL_CALL acquire() throw ();
+ virtual void SAL_CALL release() throw ();
+
+ // XEventListener
+ virtual void SAL_CALL disposing(const lang::EventObject& Source) throw( uno::RuntimeException );
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged(const frame::FeatureStateEvent& Event) throw( uno::RuntimeException );
+
+ private:
+ StateEventHelper();
+ StateEventHelper( const StateEventHelper& );
+ StateEventHelper& operator=( const StateEventHelper& );
+
+ bool m_bCurrentCommandEnabled;
+ ::rtl::OUString m_aCommandURL;
+ uno::Reference< frame::XDispatchProvider > m_xDispatchProvider;
+ uno::Reference< util::XURLTransformer > m_xURLTransformer;
+ osl::Condition m_aCondition;
+};
+
+StateEventHelper::StateEventHelper(
+ const uno::Reference< frame::XDispatchProvider >& xDispatchProvider,
+ const uno::Reference< util::XURLTransformer >& xURLTransformer,
+ const rtl::OUString& rCommandURL ) :
+ m_bCurrentCommandEnabled( true ),
+ m_aCommandURL( rCommandURL ),
+ m_xDispatchProvider( xDispatchProvider ),
+ m_xURLTransformer( xURLTransformer )
+{
+ m_aCondition.reset();
+}
+
+StateEventHelper::~StateEventHelper()
+{}
+
+uno::Any SAL_CALL StateEventHelper::queryInterface(
+ const uno::Type& aType )
+throw ( uno::RuntimeException )
+{
+ uno::Any a = ::cppu::queryInterface(
+ aType,
+ SAL_STATIC_CAST( XStatusListener*, this ));
+
+ if( a.hasValue() )
+ return a;
+
+ return ::cppu::OWeakObject::queryInterface( aType );
+}
+
+void SAL_CALL StateEventHelper::acquire()
+throw ()
+{
+ ::cppu::OWeakObject::acquire();
+}
+
+void SAL_CALL StateEventHelper::release()
+throw ()
+{
+ ::cppu::OWeakObject::release();
+}
+
+void SAL_CALL StateEventHelper::disposing(
+ const lang::EventObject& )
+throw ( uno::RuntimeException )
+{
+ vos::OGuard aSolarGuard( Application::GetSolarMutex() );
+ m_xDispatchProvider.clear();
+ m_xURLTransformer.clear();
+ m_aCondition.set();
+}
+
+void SAL_CALL StateEventHelper::statusChanged(
+ const frame::FeatureStateEvent& Event )
+throw ( uno::RuntimeException )
+{
+ vos::OGuard aSolarGuard( Application::GetSolarMutex() );
+ m_bCurrentCommandEnabled = Event.IsEnabled;
+ m_aCondition.set();
+}
+
+bool StateEventHelper::isCommandEnabled()
+{
+ // Be sure that we cannot die during condition wait
+ uno::Reference< frame::XStatusListener > xSelf(
+ SAL_STATIC_CAST( frame::XStatusListener*, this ));
+
+ uno::Reference< frame::XDispatch > xDispatch;
+ util::URL aTargetURL;
+ {
+ vos::OGuard aSolarGuard( Application::GetSolarMutex() );
+ if ( m_xDispatchProvider.is() && m_xURLTransformer.is() )
+ {
+ ::rtl::OUString aSelf( RTL_CONSTASCII_USTRINGPARAM( "_self" ));
+
+ aTargetURL.Complete = m_aCommandURL;
+ m_xURLTransformer->parseStrict( aTargetURL );
+
+ try
+ {
+ xDispatch = m_xDispatchProvider->queryDispatch( aTargetURL, aSelf, 0 );
+ }
+ catch ( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ }
+
+ bool bResult( false );
+ if ( xDispatch.is() )
+ {
+ try
+ {
+ // add/remove ourself to retrieve status by callback
+ xDispatch->addStatusListener( xSelf, aTargetURL );
+ xDispatch->removeStatusListener( xSelf, aTargetURL );
+
+ // wait for anwser
+ m_aCondition.wait();
+ }
+ catch ( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ vos::OGuard aSolarGuard( Application::GetSolarMutex() );
+ bResult = m_bCurrentCommandEnabled;
+ }
+
+ return bResult;
+}
+
+/*************************************************************************/
+
+struct ExecuteInfo
+{
+ uno::Reference< frame::XDispatch > xDispatch;
+ util::URL aTargetURL;
+ uno::Sequence< beans::PropertyValue > aArgs;
+};
+
+static const PopupMenu* lcl_FindPopupFromItemId( const PopupMenu* pPopupMenu, sal_uInt16 nItemId )
+{
+ if ( pPopupMenu )
+ {
+ sal_uInt16 nCount = pPopupMenu->GetItemCount();
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ sal_uInt16 nId = pPopupMenu->GetItemId( i );
+ if ( nId == nItemId )
+ return pPopupMenu;
+ else
+ {
+ const PopupMenu* pResult( 0 );
+
+ const PopupMenu* pSubPopup = pPopupMenu->GetPopupMenu( i );
+ if ( pPopupMenu )
+ pResult = lcl_FindPopupFromItemId( pSubPopup, nItemId );
+ if ( pResult != 0 )
+ return pResult;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static ::rtl::OUString lcl_GetItemCommandRecursive( const PopupMenu* pPopupMenu, sal_uInt16 nItemId )
+{
+ const PopupMenu* pPopup = lcl_FindPopupFromItemId( pPopupMenu, nItemId );
+ if ( pPopup )
+ return pPopup->GetItemCommand( nItemId );
+ else
+ return ::rtl::OUString();
+}
+
+/*************************************************************************/
+
+ContextMenuHelper::ContextMenuHelper(
+ const uno::Reference< frame::XFrame >& xFrame,
+ bool bAutoRefresh ) :
+ m_xWeakFrame( xFrame ),
+ m_aSelf( RTL_CONSTASCII_USTRINGPARAM( "_self" )),
+ m_bAutoRefresh( bAutoRefresh ),
+ m_bUICfgMgrAssociated( false )
+{
+}
+
+ContextMenuHelper::~ContextMenuHelper()
+{
+}
+
+void
+ContextMenuHelper::completeAndExecute(
+ const Point& aPos,
+ PopupMenu& rPopupMenu )
+{
+ vos::OGuard aSolarGuard( Application::GetSolarMutex() );
+
+ associateUIConfigurationManagers();
+ completeMenuProperties( &rPopupMenu );
+ executePopupMenu( aPos, &rPopupMenu );
+ resetAssociations();
+}
+
+void
+ContextMenuHelper::completeAndExecute(
+ const Point& aPos,
+ const uno::Reference< awt::XPopupMenu >& xPopupMenu )
+{
+ vos::OGuard aSolarGuard( Application::GetSolarMutex() );
+
+ VCLXMenu* pXMenu = VCLXMenu::GetImplementation( xPopupMenu );
+ if ( pXMenu )
+ {
+ PopupMenu* pPopupMenu = dynamic_cast< PopupMenu* >( pXMenu->GetMenu() );
+ // as dynamic_cast can return zero check pointer
+ if ( pPopupMenu )
+ {
+ associateUIConfigurationManagers();
+ completeMenuProperties( pPopupMenu );
+ executePopupMenu( aPos, pPopupMenu );
+ resetAssociations();
+ }
+ }
+}
+
+uno::Reference< awt::XPopupMenu >
+ContextMenuHelper::create(
+ const ::rtl::OUString& /*aPopupMenuResourceId*/ )
+{
+ // NOT IMPLEMENTED YET!
+ return uno::Reference< awt::XPopupMenu >();
+}
+
+bool
+ContextMenuHelper::createAndExecute(
+ const Point& /*aPos*/,
+ const ::rtl::OUString& /*aPopupMenuResourceId*/ )
+{
+ // NOT IMPLEMENTED YET!
+ return false;
+}
+
+// private member
+
+void
+ContextMenuHelper::executePopupMenu(
+ const Point& rPos,
+ PopupMenu* pMenu )
+{
+ if ( pMenu )
+ {
+ uno::Reference< frame::XFrame > xFrame( m_xWeakFrame );
+ if ( xFrame.is() )
+ {
+ uno::Reference< awt::XWindow > xWindow( xFrame->getContainerWindow() );
+ if ( xWindow.is() )
+ {
+ Window* pParent = VCLUnoHelper::GetWindow( xWindow );
+ sal_uInt16 nResult = pMenu->Execute( pParent, rPos );
+
+ if ( nResult > 0 )
+ {
+ ::rtl::OUString aCommand = lcl_GetItemCommandRecursive( pMenu, nResult );
+ if ( aCommand.getLength() > 0 )
+ dispatchCommand( xFrame, aCommand );
+ }
+ }
+ }
+ }
+}
+
+bool
+ContextMenuHelper::dispatchCommand(
+ const uno::Reference< ::frame::XFrame >& rFrame,
+ const ::rtl::OUString& aCommandURL )
+{
+ if ( !m_xURLTransformer.is() )
+ {
+ m_xURLTransformer = uno::Reference< util::XURLTransformer >(
+ ::comphelper::getProcessServiceFactory()->createInstance(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.util.URLTransformer" ))),
+ uno::UNO_QUERY );
+ }
+
+ util::URL aTargetURL;
+ uno::Reference< frame::XDispatch > xDispatch;
+ if ( m_xURLTransformer.is() )
+ {
+ aTargetURL.Complete = aCommandURL;
+ m_xURLTransformer->parseStrict( aTargetURL );
+
+ uno::Reference< frame::XDispatchProvider > xDispatchProvider(
+ rFrame, uno::UNO_QUERY );
+ if ( xDispatchProvider.is() )
+ {
+ try
+ {
+ xDispatch = xDispatchProvider->queryDispatch( aTargetURL, m_aSelf, 0 );
+ }
+ catch ( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ }
+
+ if ( xDispatch.is() )
+ {
+ ExecuteInfo* pExecuteInfo = new ExecuteInfo;
+ pExecuteInfo->xDispatch = xDispatch;
+ pExecuteInfo->aTargetURL = aTargetURL;
+ pExecuteInfo->aArgs = m_aDefaultArgs;
+
+ Application::PostUserEvent( STATIC_LINK(0, ContextMenuHelper , ExecuteHdl_Impl), pExecuteInfo );
+ return true;
+ }
+
+ return false;
+}
+
+// retrieves and stores references to our user-interface
+// configuration managers, like image manager, ui command
+// description manager.
+bool
+ContextMenuHelper::associateUIConfigurationManagers()
+{
+ uno::Reference< frame::XFrame > xFrame( m_xWeakFrame );
+ if ( !m_bUICfgMgrAssociated && xFrame.is() )
+ {
+ // clear current state
+ m_xDocImageMgr.clear();
+ m_xModuleImageMgr.clear();
+ m_xUICommandLabels.clear();
+
+ try
+ {
+ uno::Reference < frame::XController > xController;
+ uno::Reference < frame::XModel > xModel;
+ xController = xFrame->getController();
+ if ( xController.is() )
+ xModel = xController->getModel();
+
+ if ( xModel.is() )
+ {
+ // retrieve document image manager form model
+ uno::Reference< ui::XUIConfigurationManagerSupplier > xSupplier( xModel, uno::UNO_QUERY );
+ if ( xSupplier.is() )
+ {
+ uno::Reference< ui::XUIConfigurationManager > xDocUICfgMgr(
+ xSupplier->getUIConfigurationManager(), uno::UNO_QUERY );
+ m_xDocImageMgr = uno::Reference< ui::XImageManager >(
+ xDocUICfgMgr->getImageManager(), uno::UNO_QUERY );
+ }
+ }
+
+ uno::Reference< frame::XModuleManager > xModuleManager(
+ ::comphelper::getProcessServiceFactory()->createInstance(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.frame.ModuleManager" ))),
+ uno::UNO_QUERY );
+
+ uno::Reference< ui::XImageManager > xModuleImageManager;
+ rtl::OUString aModuleId;
+ if ( xModuleManager.is() )
+ {
+ // retrieve module image manager
+ aModuleId = xModuleManager->identify( xFrame );
+
+ uno::Reference< ui::XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier(
+ ::comphelper::getProcessServiceFactory()->createInstance(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.ui.ModuleUIConfigurationManagerSupplier" ))),
+ uno::UNO_QUERY );
+ if ( xModuleCfgMgrSupplier.is() )
+ {
+ uno::Reference< ui::XUIConfigurationManager > xUICfgMgr(
+ xModuleCfgMgrSupplier->getUIConfigurationManager( aModuleId ));
+ if ( xUICfgMgr.is() )
+ {
+ m_xModuleImageMgr = uno::Reference< ui::XImageManager >(
+ xUICfgMgr->getImageManager(), uno::UNO_QUERY );
+ }
+ }
+ }
+
+ uno::Reference< container::XNameAccess > xNameAccess(
+ ::comphelper::getProcessServiceFactory()->createInstance(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.frame.UICommandDescription" ))),
+ uno::UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+ try
+ {
+ uno::Any a = xNameAccess->getByName( aModuleId );
+ a >>= m_xUICommandLabels;
+ }
+ catch ( container::NoSuchElementException& )
+ {
+ }
+ }
+ }
+ catch ( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( uno::Exception& )
+ {
+ m_bUICfgMgrAssociated = true;
+ return false;
+ }
+ m_bUICfgMgrAssociated = true;
+ }
+
+ return true;
+}
+
+Image
+ContextMenuHelper::getImageFromCommandURL(
+ const ::rtl::OUString& aCmdURL,
+ bool bHiContrast ) const
+{
+ Image aImage;
+ sal_Int16 nImageType( ui::ImageType::COLOR_NORMAL|
+ ui::ImageType::SIZE_DEFAULT );
+ if ( bHiContrast )
+ nImageType |= ui::ImageType::COLOR_HIGHCONTRAST;
+
+ uno::Sequence< uno::Reference< graphic::XGraphic > > aGraphicSeq;
+ uno::Sequence< ::rtl::OUString > aImageCmdSeq( 1 );
+ aImageCmdSeq[0] = aCmdURL;
+
+ if ( m_xDocImageMgr.is() )
+ {
+ try
+ {
+ aGraphicSeq = m_xDocImageMgr->getImages( nImageType, aImageCmdSeq );
+ uno::Reference< graphic::XGraphic > xGraphic = aGraphicSeq[0];
+ aImage = Image( xGraphic );
+
+ if ( !!aImage )
+ return aImage;
+ }
+ catch ( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ if ( m_xModuleImageMgr.is() )
+ {
+ try
+ {
+ aGraphicSeq = m_xModuleImageMgr->getImages( nImageType, aImageCmdSeq );
+ uno::Reference< ::com::sun::star::graphic::XGraphic > xGraphic = aGraphicSeq[0];
+ aImage = Image( xGraphic );
+
+ if ( !!aImage )
+ return aImage;
+ }
+ catch ( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ return aImage;
+}
+
+rtl::OUString
+ContextMenuHelper::getLabelFromCommandURL(
+ const ::rtl::OUString& aCmdURL ) const
+{
+ ::rtl::OUString aLabel;
+
+ if ( m_xUICommandLabels.is() )
+ {
+ try
+ {
+ if ( aCmdURL.getLength() > 0 )
+ {
+ rtl::OUString aStr;
+ uno::Sequence< beans::PropertyValue > aPropSeq;
+ uno::Any a( m_xUICommandLabels->getByName( aCmdURL ));
+ if ( a >>= aPropSeq )
+ {
+ for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
+ {
+ if ( aPropSeq[i].Name.equalsAscii( "Label" ))
+ {
+ aPropSeq[i].Value >>= aStr;
+ break;
+ }
+ }
+ }
+ aLabel = aStr;
+ }
+ }
+ catch ( uno::RuntimeException& )
+ {
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ return aLabel;
+}
+
+void
+ContextMenuHelper::completeMenuProperties(
+ Menu* pMenu )
+{
+ // Retrieve some settings necessary to display complete context
+ // menu correctly.
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ bool bShowMenuImages( rSettings.GetUseImagesInMenus() );
+ bool bIsHiContrast( rSettings.GetHighContrastMode() );
+
+ if ( pMenu )
+ {
+ uno::Reference< frame::XFrame > xFrame( m_xWeakFrame );
+ uno::Reference< frame::XDispatchProvider > xDispatchProvider( xFrame, uno::UNO_QUERY );
+
+ if ( !m_xURLTransformer.is() )
+ {
+ m_xURLTransformer = uno::Reference< util::XURLTransformer >(
+ ::comphelper::getProcessServiceFactory()->createInstance(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.util.URLTransformer" ))),
+ uno::UNO_QUERY );
+ }
+
+ for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
+ {
+ sal_uInt16 nId = pMenu->GetItemId( nPos );
+ PopupMenu* pPopupMenu = pMenu->GetPopupMenu( nId );
+ if ( pPopupMenu )
+ completeMenuProperties( pPopupMenu );
+ if ( pMenu->GetItemType( nPos ) != MENUITEM_SEPARATOR )
+ {
+ ::rtl::OUString aCmdURL( pMenu->GetItemCommand( nId ));
+
+ if ( bShowMenuImages )
+ {
+ Image aImage;
+ if ( aCmdURL.getLength() > 0 )
+ aImage = getImageFromCommandURL( aCmdURL, bIsHiContrast );
+ pMenu->SetItemImage( nId, aImage );
+ }
+ else
+ pMenu->SetItemImage( nId, Image() );
+
+ if ( pMenu->GetItemText( nId ).Len() == 0 )
+ {
+ ::rtl::OUString aLabel( getLabelFromCommandURL( aCmdURL ));
+ pMenu->SetItemText( nId, aLabel );
+ }
+
+ // Use helper to retrieve state of the command URL
+ StateEventHelper* pHelper = new StateEventHelper(
+ xDispatchProvider,
+ m_xURLTransformer,
+ aCmdURL );
+
+ uno::Reference< frame::XStatusListener > xHelper( pHelper );
+ pMenu->EnableItem( nId, pHelper->isCommandEnabled() );
+ }
+ }
+ }
+}
+
+
+IMPL_STATIC_LINK_NOINSTANCE( ContextMenuHelper, ExecuteHdl_Impl, ExecuteInfo*, pExecuteInfo )
+{
+ // Release solar mutex to prevent deadlocks with clipboard thread
+ const sal_uInt32 nRef = Application::ReleaseSolarMutex();
+ try
+ {
+ // Asynchronous execution as this can lead to our own destruction while we are
+ // on the stack. Stack unwinding would access the destroyed context menu.
+ pExecuteInfo->xDispatch->dispatch( pExecuteInfo->aTargetURL, pExecuteInfo->aArgs );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ // Acquire solar mutex again
+ Application::AcquireSolarMutex( nRef );
+ delete pExecuteInfo;
+ return 0;
+}
+
+} // namespace svt