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/beans/PropertyValue.hpp>
23 #include <com/sun/star/frame/XDispatchProvider.hpp>
24 #include <com/sun/star/frame/XFrame.hpp>
25 #include <com/sun/star/lang/DisposedException.hpp>
26 #include <com/sun/star/util/URLTransformer.hpp>
28 #include <vcl/svapp.hxx>
29 #include <osl/mutex.hxx>
30 #include <cppuhelper/supportsservice.hxx>
32 using namespace com::sun::star
;
33 using namespace css::uno
;
34 using namespace css::lang
;
35 using namespace css::frame
;
36 using namespace css::beans
;
37 using namespace css::util
;
44 struct PopupMenuControllerBaseDispatchInfo
46 Reference
< XDispatch
> mxDispatch
;
48 const Sequence
< PropertyValue
> maArgs
;
50 PopupMenuControllerBaseDispatchInfo( const Reference
< XDispatch
>& xDispatch
, const URL
& rURL
, const Sequence
< PropertyValue
>& rArgs
)
51 : mxDispatch( xDispatch
), maURL( rURL
), maArgs( rArgs
) {}
56 PopupMenuControllerBase::PopupMenuControllerBase( const Reference
< XComponentContext
>& xContext
) :
58 PopupMenuControllerBaseType(m_aMutex
),
59 m_bInitialized( false )
62 m_xURLTransformer
.set( util::URLTransformer::create( xContext
) );
65 PopupMenuControllerBase::~PopupMenuControllerBase()
70 void PopupMenuControllerBase::throwIfDisposed()
72 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
73 throw css::lang::DisposedException();
77 void PopupMenuControllerBase::resetPopupMenu( css::uno::Reference
< css::awt::XPopupMenu
> const & 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
)
97 return cppu::supportsService(this, ServiceName
);
101 void SAL_CALL
PopupMenuControllerBase::disposing( const EventObject
& )
103 osl::MutexGuard
aLock( m_aMutex
);
106 m_xPopupMenu
.clear();
110 void SAL_CALL
PopupMenuControllerBase::itemHighlighted( const awt::MenuEvent
& )
114 void SAL_CALL
PopupMenuControllerBase::itemSelected( const awt::MenuEvent
& rEvent
)
118 osl::MutexGuard
aLock( m_aMutex
);
120 if( m_xPopupMenu
.is() )
122 Sequence
<PropertyValue
> aArgs
;
123 dispatchCommand( m_xPopupMenu
->getCommand( rEvent
.MenuId
), aArgs
);
127 void PopupMenuControllerBase::dispatchCommand( const OUString
& sCommandURL
,
128 const css::uno::Sequence
< css::beans::PropertyValue
>& rArgs
,
129 const OUString
& sTarget
)
131 osl::MutexGuard
aLock( m_aMutex
);
137 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY_THROW
);
139 aURL
.Complete
= sCommandURL
;
140 m_xURLTransformer
->parseStrict( aURL
);
142 Reference
< XDispatch
> xDispatch( xDispatchProvider
->queryDispatch( aURL
, sTarget
, 0 ), UNO_SET_THROW
);
144 Application::PostUserEvent( LINK(nullptr, PopupMenuControllerBase
, ExecuteHdl_Impl
), new PopupMenuControllerBaseDispatchInfo( xDispatch
, aURL
, rArgs
) );
153 IMPL_STATIC_LINK( PopupMenuControllerBase
, ExecuteHdl_Impl
, void*, p
, void )
155 PopupMenuControllerBaseDispatchInfo
* pDispatchInfo
= static_cast<PopupMenuControllerBaseDispatchInfo
*>(p
);
156 pDispatchInfo
->mxDispatch
->dispatch( pDispatchInfo
->maURL
, pDispatchInfo
->maArgs
);
157 delete pDispatchInfo
;
160 void SAL_CALL
PopupMenuControllerBase::itemActivated( const awt::MenuEvent
& )
164 void SAL_CALL
PopupMenuControllerBase::itemDeactivated( const awt::MenuEvent
& )
168 void SAL_CALL
PopupMenuControllerBase::updatePopupMenu()
171 osl::MutexGuard
aLock(m_aMutex
);
175 updateCommand( m_aCommandURL
);
178 void PopupMenuControllerBase::updateCommand( const OUString
& rCommandURL
)
180 osl::ClearableMutexGuard
aLock( m_aMutex
);
181 Reference
< XStatusListener
> xStatusListener( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
182 Reference
< XDispatch
> xDispatch( m_xDispatch
);
184 aTargetURL
.Complete
= rCommandURL
;
185 m_xURLTransformer
->parseStrict( aTargetURL
);
188 // Add/remove status listener to get a status update once
189 if ( xDispatch
.is() )
191 xDispatch
->addStatusListener( xStatusListener
, aTargetURL
);
192 xDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
198 Reference
< XDispatch
> SAL_CALL
199 PopupMenuControllerBase::queryDispatch(
201 const OUString
& /*sTarget*/,
202 sal_Int32
/*nFlags*/ )
204 // must be implemented by subclass
205 osl::MutexGuard
aLock( m_aMutex
);
208 return Reference
< XDispatch
>();
211 Sequence
< Reference
< XDispatch
> > SAL_CALL
PopupMenuControllerBase::queryDispatches( const Sequence
< DispatchDescriptor
>& lDescriptor
)
213 // Create return list - which must have same size then the given descriptor
214 // It's not allowed to pack it!
216 osl::MutexGuard
aLock(m_aMutex
);
220 sal_Int32 nCount
= lDescriptor
.getLength();
221 uno::Sequence
< uno::Reference
< frame::XDispatch
> > lDispatcher( nCount
);
223 // Step over all descriptors and try to get any dispatcher for it.
224 std::transform(lDescriptor
.begin(), lDescriptor
.end(), lDispatcher
.begin(),
225 [this](const DispatchDescriptor
& rDesc
) -> uno::Reference
< frame::XDispatch
> {
226 return queryDispatch(rDesc
.FeatureURL
, rDesc
.FrameName
, rDesc
.SearchFlags
); });
233 PopupMenuControllerBase::dispatch(
235 const Sequence
< PropertyValue
>& /*seqProperties*/ )
237 // must be implemented by subclass
238 osl::MutexGuard
aLock( m_aMutex
);
243 PopupMenuControllerBase::addStatusListener(
244 const Reference
< XStatusListener
>& xControl
,
247 osl::ResettableMutexGuard
aLock( m_aMutex
);
251 bool bStatusUpdate( false );
252 rBHelper
.addListener( cppu::UnoType
<decltype(xControl
)>::get(), xControl
);
255 if ( aURL
.Complete
.startsWith( m_aBaseURL
) )
256 bStatusUpdate
= true;
261 // Dummy update for popup menu controllers
262 FeatureStateEvent aEvent
;
263 aEvent
.FeatureURL
= aURL
;
264 aEvent
.IsEnabled
= true;
265 aEvent
.Requery
= false;
266 aEvent
.State
= Any();
267 xControl
->statusChanged( aEvent
);
271 void SAL_CALL
PopupMenuControllerBase::removeStatusListener(
272 const Reference
< XStatusListener
>& xControl
,
273 const URL
& /*aURL*/ )
275 rBHelper
.removeListener( cppu::UnoType
<decltype(xControl
)>::get(), xControl
);
278 OUString
PopupMenuControllerBase::determineBaseURL( const OUString
& aURL
)
280 // Just use the main part of the URL for popup menu controllers
281 sal_Int32
nSchemePart( 0 );
282 OUString
aMainURL( "vnd.sun.star.popup:" );
284 nSchemePart
= aURL
.indexOf( ':' );
285 if (( nSchemePart
> 0 ) &&
286 ( aURL
.getLength() > ( nSchemePart
+1 )))
288 sal_Int32 nQueryPart
= aURL
.indexOf( '?', nSchemePart
);
289 if ( nQueryPart
> 0 )
290 aMainURL
+= aURL
.subView( nSchemePart
, nQueryPart
-nSchemePart
);
291 else if ( nQueryPart
== -1 )
292 aMainURL
+= aURL
.subView( nSchemePart
+1 );
299 void SAL_CALL
PopupMenuControllerBase::initialize( const Sequence
< Any
>& aArguments
)
301 osl::MutexGuard
aLock( m_aMutex
);
303 bool bInitalized( m_bInitialized
);
307 PropertyValue aPropValue
;
308 OUString aCommandURL
;
309 Reference
< XFrame
> xFrame
;
311 for ( const auto& rArgument
: aArguments
)
313 if ( rArgument
>>= aPropValue
)
315 if ( aPropValue
.Name
== "Frame" )
316 aPropValue
.Value
>>= xFrame
;
317 else if ( aPropValue
.Name
== "CommandURL" )
318 aPropValue
.Value
>>= aCommandURL
;
319 else if ( aPropValue
.Name
== "ModuleIdentifier" )
320 aPropValue
.Value
>>= m_aModuleName
;
324 if ( xFrame
.is() && !aCommandURL
.isEmpty() )
327 m_aCommandURL
= aCommandURL
;
328 m_aBaseURL
= determineBaseURL( aCommandURL
);
329 m_bInitialized
= true;
332 // XPopupMenuController
333 void SAL_CALL
PopupMenuControllerBase::setPopupMenu( const Reference
< awt::XPopupMenu
>& xPopupMenu
)
335 osl::MutexGuard
aLock( m_aMutex
);
338 if ( !m_xFrame
.is() || m_xPopupMenu
.is() )
341 // Create popup menu on demand
342 SolarMutexGuard aSolarMutexGuard
;
344 m_xPopupMenu
= xPopupMenu
;
345 m_xPopupMenu
->addMenuListener( Reference
< awt::XMenuListener
>( static_cast<OWeakObject
*>(this), UNO_QUERY
));
347 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY
);
350 aTargetURL
.Complete
= m_aCommandURL
;
351 m_xURLTransformer
->parseStrict( aTargetURL
);
352 m_xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
358 void PopupMenuControllerBase::impl_setPopupMenu()
363 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */