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 "svtools/popupmenucontrollerbase.hxx"
22 #include <com/sun/star/awt/XDevice.hpp>
23 #include <com/sun/star/beans/PropertyValue.hpp>
24 #include <com/sun/star/awt/MenuItemStyle.hpp>
25 #include <com/sun/star/frame/XDispatchProvider.hpp>
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <com/sun/star/awt/XMenuExtended.hpp>
28 #include <com/sun/star/util/URLTransformer.hpp>
30 #include <vcl/menu.hxx>
31 #include <vcl/svapp.hxx>
32 #include <rtl/ustrbuf.hxx>
33 #include <rtl/logfile.hxx>
34 #include <osl/mutex.hxx>
35 #include <comphelper/processfactory.hxx>
37 //_________________________________________________________________________________________________________________
39 //_________________________________________________________________________________________________________________
43 using namespace com::sun::star
;
44 using namespace com::sun::star::uno
;
45 using namespace com::sun::star::lang
;
46 using namespace com::sun::star::frame
;
47 using namespace com::sun::star::beans
;
48 using namespace com::sun::star::util
;
53 struct PopupMenuControllerBaseDispatchInfo
55 Reference
< XDispatch
> mxDispatch
;
57 const Sequence
< PropertyValue
> maArgs
;
59 PopupMenuControllerBaseDispatchInfo( const Reference
< XDispatch
>& xDispatch
, const URL
& rURL
, const Sequence
< PropertyValue
>& rArgs
)
60 : mxDispatch( xDispatch
), maURL( rURL
), maArgs( rArgs
) {}
63 PopupMenuControllerBase::PopupMenuControllerBase( const Reference
< XMultiServiceFactory
>& xServiceManager
) :
64 ::comphelper::OBaseMutex(),
65 PopupMenuControllerBaseType(m_aMutex
),
66 m_bInitialized( false ),
67 m_xServiceManager( xServiceManager
)
69 if ( m_xServiceManager
.is() )
70 m_xURLTransformer
.set( util::URLTransformer::create( ::comphelper::getComponentContext(m_xServiceManager
) ) );
73 PopupMenuControllerBase::~PopupMenuControllerBase()
78 void PopupMenuControllerBase::throwIfDisposed() throw ( RuntimeException
)
80 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
81 throw com::sun::star::lang::DisposedException();
85 void PopupMenuControllerBase::resetPopupMenu( com::sun::star::uno::Reference
< com::sun::star::awt::XPopupMenu
>& rPopupMenu
)
87 if ( rPopupMenu
.is() && rPopupMenu
->getItemCount() > 0 )
89 VCLXPopupMenu
* pPopupMenu
= (VCLXPopupMenu
*)VCLXMenu::GetImplementation( rPopupMenu
);
92 SolarMutexGuard aSolarMutexGuard
;
94 PopupMenu
* pVCLPopupMenu
= (PopupMenu
*)pPopupMenu
->GetMenu();
95 pVCLPopupMenu
->Clear();
100 void SAL_CALL
PopupMenuControllerBase::disposing()
102 // Reset our members and set disposed flag
103 osl::MutexGuard
aLock( m_aMutex
);
106 m_xPopupMenu
.clear();
107 m_xServiceManager
.clear();
112 sal_Bool SAL_CALL
PopupMenuControllerBase::supportsService( const OUString
& ServiceName
) throw (RuntimeException
)
114 const Sequence
< OUString
> aSNL( getSupportedServiceNames() );
115 const OUString
* pArray
= aSNL
.getConstArray();
117 for( sal_Int32 i
= 0; i
< aSNL
.getLength(); i
++ )
118 if( pArray
[i
] == ServiceName
)
125 void SAL_CALL
PopupMenuControllerBase::disposing( const EventObject
& ) throw ( RuntimeException
)
127 osl::MutexGuard
aLock( m_aMutex
);
130 m_xPopupMenu
.clear();
134 void SAL_CALL
PopupMenuControllerBase::highlight( const awt::MenuEvent
& ) throw (RuntimeException
)
138 void PopupMenuControllerBase::impl_select(const Reference
< XDispatch
>& _xDispatch
,const URL
& aURL
)
140 Sequence
<PropertyValue
> aArgs
;
141 OSL_ENSURE(_xDispatch
.is(),"PopupMenuControllerBase::impl_select: No dispatch");
142 if ( _xDispatch
.is() )
143 _xDispatch
->dispatch( aURL
, aArgs
);
146 void SAL_CALL
PopupMenuControllerBase::select( const awt::MenuEvent
& rEvent
) throw (RuntimeException
)
150 osl::MutexGuard
aLock( m_aMutex
);
152 Reference
< awt::XMenuExtended
> xExtMenu( m_xPopupMenu
, UNO_QUERY
);
155 Sequence
<PropertyValue
> aArgs
;
156 dispatchCommand( xExtMenu
->getCommand( rEvent
.MenuId
), aArgs
);
160 void PopupMenuControllerBase::dispatchCommand( const OUString
& sCommandURL
, const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& rArgs
)
162 osl::MutexGuard
aLock( m_aMutex
);
168 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY_THROW
);
170 aURL
.Complete
= sCommandURL
;
171 m_xURLTransformer
->parseStrict( aURL
);
173 Reference
< XDispatch
> xDispatch( xDispatchProvider
->queryDispatch( aURL
, OUString(), 0 ), UNO_QUERY_THROW
);
175 Application::PostUserEvent( STATIC_LINK(0, PopupMenuControllerBase
, ExecuteHdl_Impl
), new PopupMenuControllerBaseDispatchInfo( xDispatch
, aURL
, rArgs
) );
184 IMPL_STATIC_LINK_NOINSTANCE( PopupMenuControllerBase
, ExecuteHdl_Impl
, PopupMenuControllerBaseDispatchInfo
*, pDispatchInfo
)
186 pDispatchInfo
->mxDispatch
->dispatch( pDispatchInfo
->maURL
, pDispatchInfo
->maArgs
);
187 delete pDispatchInfo
;
191 void SAL_CALL
PopupMenuControllerBase::activate( const awt::MenuEvent
& ) throw (RuntimeException
)
195 void SAL_CALL
PopupMenuControllerBase::deactivate( const awt::MenuEvent
& ) throw (RuntimeException
)
199 void SAL_CALL
PopupMenuControllerBase::updatePopupMenu() throw ( ::com::sun::star::uno::RuntimeException
)
201 osl::ClearableMutexGuard
aLock( m_aMutex
);
205 updateCommand( m_aCommandURL
);
208 void SAL_CALL
PopupMenuControllerBase::updateCommand( const OUString
& rCommandURL
)
210 osl::ClearableMutexGuard
aLock( m_aMutex
);
211 Reference
< XStatusListener
> xStatusListener( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
212 Reference
< XDispatch
> xDispatch( m_xDispatch
);
214 aTargetURL
.Complete
= rCommandURL
;
215 m_xURLTransformer
->parseStrict( aTargetURL
);
218 // Add/remove status listener to get a status update once
219 if ( xDispatch
.is() )
221 xDispatch
->addStatusListener( xStatusListener
, aTargetURL
);
222 xDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
228 Reference
< XDispatch
> SAL_CALL
229 PopupMenuControllerBase::queryDispatch(
231 const OUString
& /*sTarget*/,
232 sal_Int32
/*nFlags*/ )
233 throw( RuntimeException
)
235 // must be implemented by subclass
236 osl::MutexGuard
aLock( m_aMutex
);
239 return Reference
< XDispatch
>();
242 Sequence
< Reference
< XDispatch
> > SAL_CALL
PopupMenuControllerBase::queryDispatches( const Sequence
< DispatchDescriptor
>& lDescriptor
) throw( RuntimeException
)
244 // Create return list - which must have same size then the given descriptor
245 // It's not allowed to pack it!
246 osl::ClearableMutexGuard
aLock( m_aMutex
);
250 sal_Int32 nCount
= lDescriptor
.getLength();
251 uno::Sequence
< uno::Reference
< frame::XDispatch
> > lDispatcher( nCount
);
253 // Step over all descriptors and try to get any dispatcher for it.
254 for( sal_Int32 i
=0; i
<nCount
; ++i
)
256 lDispatcher
[i
] = queryDispatch( lDescriptor
[i
].FeatureURL
,
257 lDescriptor
[i
].FrameName
,
258 lDescriptor
[i
].SearchFlags
);
266 PopupMenuControllerBase::dispatch(
268 const Sequence
< PropertyValue
>& /*seqProperties*/ )
269 throw( ::com::sun::star::uno::RuntimeException
)
271 // must be implemented by subclass
272 osl::MutexGuard
aLock( m_aMutex
);
277 PopupMenuControllerBase::addStatusListener(
278 const Reference
< XStatusListener
>& xControl
,
280 throw( ::com::sun::star::uno::RuntimeException
)
282 osl::ResettableMutexGuard
aLock( m_aMutex
);
286 bool bStatusUpdate( false );
287 rBHelper
.addListener( ::getCppuType( &xControl
), xControl
);
290 if ( aURL
.Complete
.indexOf( m_aBaseURL
) == 0 )
291 bStatusUpdate
= true;
296 // Dummy update for popup menu controllers
297 FeatureStateEvent aEvent
;
298 aEvent
.FeatureURL
= aURL
;
299 aEvent
.IsEnabled
= sal_True
;
300 aEvent
.Requery
= sal_False
;
301 aEvent
.State
= Any();
302 xControl
->statusChanged( aEvent
);
306 void SAL_CALL
PopupMenuControllerBase::removeStatusListener(
307 const Reference
< XStatusListener
>& xControl
,
308 const URL
& /*aURL*/ )
309 throw( ::com::sun::star::uno::RuntimeException
)
311 rBHelper
.removeListener( ::getCppuType( &xControl
), xControl
);
314 OUString
PopupMenuControllerBase::determineBaseURL( const OUString
& aURL
)
316 // Just use the main part of the URL for popup menu controllers
317 sal_Int32
nQueryPart( 0 );
318 sal_Int32
nSchemePart( 0 );
319 OUString
aMainURL( "vnd.sun.star.popup:" );
321 nSchemePart
= aURL
.indexOf( ':' );
322 if (( nSchemePart
> 0 ) &&
323 ( aURL
.getLength() > ( nSchemePart
+1 )))
325 nQueryPart
= aURL
.indexOf( '?', nSchemePart
);
326 if ( nQueryPart
> 0 )
327 aMainURL
+= aURL
.copy( nSchemePart
, nQueryPart
-nSchemePart
);
328 else if ( nQueryPart
== -1 )
329 aMainURL
+= aURL
.copy( nSchemePart
+1 );
336 void SAL_CALL
PopupMenuControllerBase::initialize( const Sequence
< Any
>& aArguments
) throw ( Exception
, RuntimeException
)
338 osl::MutexGuard
aLock( m_aMutex
);
340 sal_Bool
bInitalized( m_bInitialized
);
343 PropertyValue aPropValue
;
344 OUString aCommandURL
;
345 Reference
< XFrame
> xFrame
;
347 for ( int i
= 0; i
< aArguments
.getLength(); i
++ )
349 if ( aArguments
[i
] >>= aPropValue
)
351 if ( aPropValue
.Name
== "Frame" )
352 aPropValue
.Value
>>= xFrame
;
353 else if ( aPropValue
.Name
== "CommandURL" )
354 aPropValue
.Value
>>= aCommandURL
;
355 else if ( aPropValue
.Name
== "ModuleName" )
356 aPropValue
.Value
>>= m_aModuleName
;
360 if ( xFrame
.is() && !aCommandURL
.isEmpty() )
363 m_aCommandURL
= aCommandURL
;
364 m_aBaseURL
= determineBaseURL( aCommandURL
);
365 m_bInitialized
= true;
369 // XPopupMenuController
370 void SAL_CALL
PopupMenuControllerBase::setPopupMenu( const Reference
< awt::XPopupMenu
>& xPopupMenu
) throw ( RuntimeException
)
372 osl::MutexGuard
aLock( m_aMutex
);
375 if ( m_xFrame
.is() && !m_xPopupMenu
.is() )
377 // Create popup menu on demand
378 SolarMutexGuard aSolarMutexGuard
;
380 m_xPopupMenu
= xPopupMenu
;
381 m_xPopupMenu
->addMenuListener( Reference
< awt::XMenuListener
>( (OWeakObject
*)this, UNO_QUERY
));
383 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY
);
386 aTargetURL
.Complete
= m_aCommandURL
;
387 m_xURLTransformer
->parseStrict( aTargetURL
);
388 m_xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
395 void PopupMenuControllerBase::impl_setPopupMenu()
400 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */