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/util/URLTransformer.hpp>
29 #include <vcl/menu.hxx>
30 #include <vcl/svapp.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <osl/mutex.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <cppuhelper/supportsservice.hxx>
36 using namespace com::sun::star
;
37 using namespace com::sun::star::uno
;
38 using namespace com::sun::star::lang
;
39 using namespace com::sun::star::frame
;
40 using namespace com::sun::star::beans
;
41 using namespace com::sun::star::util
;
46 struct PopupMenuControllerBaseDispatchInfo
48 Reference
< XDispatch
> mxDispatch
;
50 const Sequence
< PropertyValue
> maArgs
;
52 PopupMenuControllerBaseDispatchInfo( const Reference
< XDispatch
>& xDispatch
, const URL
& rURL
, const Sequence
< PropertyValue
>& rArgs
)
53 : mxDispatch( xDispatch
), maURL( rURL
), maArgs( rArgs
) {}
56 PopupMenuControllerBase::PopupMenuControllerBase( const Reference
< XComponentContext
>& xContext
) :
57 ::comphelper::OBaseMutex(),
58 PopupMenuControllerBaseType(m_aMutex
),
59 m_bInitialized( false )
62 m_xURLTransformer
.set( util::URLTransformer::create( xContext
) );
65 PopupMenuControllerBase::~PopupMenuControllerBase()
70 void PopupMenuControllerBase::throwIfDisposed() throw ( RuntimeException
)
72 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
73 throw com::sun::star::lang::DisposedException();
77 void PopupMenuControllerBase::resetPopupMenu( com::sun::star::uno::Reference
< com::sun::star::awt::XPopupMenu
>& rPopupMenu
)
79 if ( rPopupMenu
.is() && rPopupMenu
->getItemCount() > 0 )
85 void SAL_CALL
PopupMenuControllerBase::disposing()
87 // Reset our members and set disposed flag
88 osl::MutexGuard
aLock( m_aMutex
);
95 sal_Bool SAL_CALL
PopupMenuControllerBase::supportsService( const OUString
& ServiceName
) throw (RuntimeException
)
97 return cppu::supportsService(this, ServiceName
);
101 void SAL_CALL
PopupMenuControllerBase::disposing( const EventObject
& ) throw ( RuntimeException
)
103 osl::MutexGuard
aLock( m_aMutex
);
106 m_xPopupMenu
.clear();
110 void SAL_CALL
PopupMenuControllerBase::itemHighlighted( const awt::MenuEvent
& ) throw (RuntimeException
)
114 void PopupMenuControllerBase::impl_select(const Reference
< XDispatch
>& _xDispatch
,const URL
& aURL
)
116 Sequence
<PropertyValue
> aArgs
;
117 OSL_ENSURE(_xDispatch
.is(),"PopupMenuControllerBase::impl_select: No dispatch");
118 if ( _xDispatch
.is() )
119 _xDispatch
->dispatch( aURL
, aArgs
);
122 void SAL_CALL
PopupMenuControllerBase::itemSelected( const awt::MenuEvent
& rEvent
) throw (RuntimeException
)
126 osl::MutexGuard
aLock( m_aMutex
);
128 if( m_xPopupMenu
.is() )
130 Sequence
<PropertyValue
> aArgs
;
131 dispatchCommand( m_xPopupMenu
->getCommand( rEvent
.MenuId
), aArgs
);
135 void PopupMenuControllerBase::dispatchCommand( const OUString
& sCommandURL
, const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& rArgs
)
137 osl::MutexGuard
aLock( m_aMutex
);
143 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY_THROW
);
145 aURL
.Complete
= sCommandURL
;
146 m_xURLTransformer
->parseStrict( aURL
);
148 Reference
< XDispatch
> xDispatch( xDispatchProvider
->queryDispatch( aURL
, OUString(), 0 ), UNO_QUERY_THROW
);
150 Application::PostUserEvent( STATIC_LINK(0, PopupMenuControllerBase
, ExecuteHdl_Impl
), new PopupMenuControllerBaseDispatchInfo( xDispatch
, aURL
, rArgs
) );
159 IMPL_STATIC_LINK_NOINSTANCE( PopupMenuControllerBase
, ExecuteHdl_Impl
, PopupMenuControllerBaseDispatchInfo
*, pDispatchInfo
)
161 pDispatchInfo
->mxDispatch
->dispatch( pDispatchInfo
->maURL
, pDispatchInfo
->maArgs
);
162 delete pDispatchInfo
;
166 void SAL_CALL
PopupMenuControllerBase::itemActivated( const awt::MenuEvent
& ) throw (RuntimeException
)
170 void SAL_CALL
PopupMenuControllerBase::itemDeactivated( const awt::MenuEvent
& ) throw (RuntimeException
)
174 void SAL_CALL
PopupMenuControllerBase::updatePopupMenu() throw ( ::com::sun::star::uno::RuntimeException
)
176 osl::ClearableMutexGuard
aLock( m_aMutex
);
180 updateCommand( m_aCommandURL
);
183 void SAL_CALL
PopupMenuControllerBase::updateCommand( const OUString
& rCommandURL
)
185 osl::ClearableMutexGuard
aLock( m_aMutex
);
186 Reference
< XStatusListener
> xStatusListener( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
187 Reference
< XDispatch
> xDispatch( m_xDispatch
);
189 aTargetURL
.Complete
= rCommandURL
;
190 m_xURLTransformer
->parseStrict( aTargetURL
);
193 // Add/remove status listener to get a status update once
194 if ( xDispatch
.is() )
196 xDispatch
->addStatusListener( xStatusListener
, aTargetURL
);
197 xDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
203 Reference
< XDispatch
> SAL_CALL
204 PopupMenuControllerBase::queryDispatch(
206 const OUString
& /*sTarget*/,
207 sal_Int32
/*nFlags*/ )
208 throw( RuntimeException
)
210 // must be implemented by subclass
211 osl::MutexGuard
aLock( m_aMutex
);
214 return Reference
< XDispatch
>();
217 Sequence
< Reference
< XDispatch
> > SAL_CALL
PopupMenuControllerBase::queryDispatches( const Sequence
< DispatchDescriptor
>& lDescriptor
) throw( RuntimeException
)
219 // Create return list - which must have same size then the given descriptor
220 // It's not allowed to pack it!
221 osl::ClearableMutexGuard
aLock( m_aMutex
);
225 sal_Int32 nCount
= lDescriptor
.getLength();
226 uno::Sequence
< uno::Reference
< frame::XDispatch
> > lDispatcher( nCount
);
228 // Step over all descriptors and try to get any dispatcher for it.
229 for( sal_Int32 i
=0; i
<nCount
; ++i
)
231 lDispatcher
[i
] = queryDispatch( lDescriptor
[i
].FeatureURL
,
232 lDescriptor
[i
].FrameName
,
233 lDescriptor
[i
].SearchFlags
);
241 PopupMenuControllerBase::dispatch(
243 const Sequence
< PropertyValue
>& /*seqProperties*/ )
244 throw( ::com::sun::star::uno::RuntimeException
)
246 // must be implemented by subclass
247 osl::MutexGuard
aLock( m_aMutex
);
252 PopupMenuControllerBase::addStatusListener(
253 const Reference
< XStatusListener
>& xControl
,
255 throw( ::com::sun::star::uno::RuntimeException
)
257 osl::ResettableMutexGuard
aLock( m_aMutex
);
261 bool bStatusUpdate( false );
262 rBHelper
.addListener( ::getCppuType( &xControl
), xControl
);
265 if ( aURL
.Complete
.startsWith( m_aBaseURL
) )
266 bStatusUpdate
= true;
271 // Dummy update for popup menu controllers
272 FeatureStateEvent aEvent
;
273 aEvent
.FeatureURL
= aURL
;
274 aEvent
.IsEnabled
= sal_True
;
275 aEvent
.Requery
= sal_False
;
276 aEvent
.State
= Any();
277 xControl
->statusChanged( aEvent
);
281 void SAL_CALL
PopupMenuControllerBase::removeStatusListener(
282 const Reference
< XStatusListener
>& xControl
,
283 const URL
& /*aURL*/ )
284 throw( ::com::sun::star::uno::RuntimeException
)
286 rBHelper
.removeListener( ::getCppuType( &xControl
), xControl
);
289 OUString
PopupMenuControllerBase::determineBaseURL( const OUString
& aURL
)
291 // Just use the main part of the URL for popup menu controllers
292 sal_Int32
nQueryPart( 0 );
293 sal_Int32
nSchemePart( 0 );
294 OUString
aMainURL( "vnd.sun.star.popup:" );
296 nSchemePart
= aURL
.indexOf( ':' );
297 if (( nSchemePart
> 0 ) &&
298 ( aURL
.getLength() > ( nSchemePart
+1 )))
300 nQueryPart
= aURL
.indexOf( '?', nSchemePart
);
301 if ( nQueryPart
> 0 )
302 aMainURL
+= aURL
.copy( nSchemePart
, nQueryPart
-nSchemePart
);
303 else if ( nQueryPart
== -1 )
304 aMainURL
+= aURL
.copy( nSchemePart
+1 );
311 void SAL_CALL
PopupMenuControllerBase::initialize( const Sequence
< Any
>& aArguments
) throw ( Exception
, RuntimeException
)
313 osl::MutexGuard
aLock( m_aMutex
);
315 sal_Bool
bInitalized( m_bInitialized
);
318 PropertyValue aPropValue
;
319 OUString aCommandURL
;
320 Reference
< XFrame
> xFrame
;
322 for ( int i
= 0; i
< aArguments
.getLength(); i
++ )
324 if ( aArguments
[i
] >>= aPropValue
)
326 if ( aPropValue
.Name
== "Frame" )
327 aPropValue
.Value
>>= xFrame
;
328 else if ( aPropValue
.Name
== "CommandURL" )
329 aPropValue
.Value
>>= aCommandURL
;
330 else if ( aPropValue
.Name
== "ModuleName" )
331 aPropValue
.Value
>>= m_aModuleName
;
335 if ( xFrame
.is() && !aCommandURL
.isEmpty() )
338 m_aCommandURL
= aCommandURL
;
339 m_aBaseURL
= determineBaseURL( aCommandURL
);
340 m_bInitialized
= true;
344 // XPopupMenuController
345 void SAL_CALL
PopupMenuControllerBase::setPopupMenu( const Reference
< awt::XPopupMenu
>& xPopupMenu
) throw ( RuntimeException
)
347 osl::MutexGuard
aLock( m_aMutex
);
350 if ( m_xFrame
.is() && !m_xPopupMenu
.is() )
352 // Create popup menu on demand
353 SolarMutexGuard aSolarMutexGuard
;
355 m_xPopupMenu
= xPopupMenu
;
356 m_xPopupMenu
->addMenuListener( Reference
< awt::XMenuListener
>( (OWeakObject
*)this, UNO_QUERY
));
358 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY
);
361 aTargetURL
.Complete
= m_aCommandURL
;
362 m_xURLTransformer
->parseStrict( aTargetURL
);
363 m_xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
370 void PopupMenuControllerBase::impl_setPopupMenu()
375 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */