LibreOffice Module svtools (master) 1
popupmenucontrollerbase.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
21
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>
27
28#include <utility>
29#include <vcl/svapp.hxx>
30#include <osl/mutex.hxx>
33
34using namespace com::sun::star;
35using namespace css::uno;
36using namespace css::lang;
37using namespace css::frame;
38using namespace css::beans;
39using namespace css::util;
40
41namespace svt
42{
43
44namespace {
45
46struct PopupMenuControllerBaseDispatchInfo
47{
48 Reference< XDispatch > mxDispatch;
49 const URL maURL;
50 const Sequence< PropertyValue > maArgs;
51
52 PopupMenuControllerBaseDispatchInfo( const Reference< XDispatch >& xDispatch, URL aURL, const Sequence< PropertyValue >& rArgs )
53 : mxDispatch( xDispatch ), maURL(std::move( aURL )), maArgs( rArgs ) {}
54};
55
56}
57
58PopupMenuControllerBase::PopupMenuControllerBase( const Reference< XComponentContext >& xContext ) :
59 m_bInitialized( false )
60{
61 if ( xContext.is() )
62 m_xURLTransformer.set( util::URLTransformer::create( xContext ) );
63}
64
65PopupMenuControllerBase::~PopupMenuControllerBase()
66{
67}
68
69// protected function
70void PopupMenuControllerBase::resetPopupMenu( css::uno::Reference< css::awt::XPopupMenu > const & rPopupMenu )
71{
72 if ( rPopupMenu.is() && rPopupMenu->getItemCount() > 0 )
73 {
74 rPopupMenu->clear();
75 }
76}
77
78void PopupMenuControllerBase::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
79{
80 // Reset our members and set disposed flag
81 m_xFrame.clear();
82 m_xDispatch.clear();
83 m_xPopupMenu.clear();
84}
85
86// XServiceInfo
87sal_Bool SAL_CALL PopupMenuControllerBase::supportsService( const OUString& ServiceName )
88{
89 return cppu::supportsService(this, ServiceName);
90}
91
92// XEventListener
93void SAL_CALL PopupMenuControllerBase::disposing( const EventObject& )
94{
95 std::unique_lock aLock( m_aMutex );
96 m_xFrame.clear();
97 m_xDispatch.clear();
98 m_xPopupMenu.clear();
99}
100
101// XMenuListener
102void SAL_CALL PopupMenuControllerBase::itemHighlighted( const awt::MenuEvent& )
103{
104}
105
106void SAL_CALL PopupMenuControllerBase::itemSelected( const awt::MenuEvent& rEvent )
107{
108 std::unique_lock aLock( m_aMutex );
109 throwIfDisposed(aLock);
110
111 if( m_xPopupMenu.is() )
112 {
113 Sequence<PropertyValue> aArgs;
114 dispatchCommandImpl( aLock, m_xPopupMenu->getCommand( rEvent.MenuId ), aArgs, OUString() );
115 }
116}
117
118void PopupMenuControllerBase::dispatchCommand( const OUString& sCommandURL,
119 const css::uno::Sequence< css::beans::PropertyValue >& rArgs,
120 const OUString& sTarget )
121{
122 std::unique_lock aLock( m_aMutex );
123 throwIfDisposed(aLock);
124 dispatchCommandImpl(aLock, sCommandURL, rArgs, sTarget);
125}
126
127void PopupMenuControllerBase::dispatchCommandImpl( std::unique_lock<std::mutex>& /*rGuard*/,
128 const OUString& sCommandURL,
129 const css::uno::Sequence< css::beans::PropertyValue >& rArgs,
130 const OUString& sTarget )
131{
132
133 try
134 {
135 Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY_THROW );
136 URL aURL;
137 aURL.Complete = sCommandURL;
138 m_xURLTransformer->parseStrict( aURL );
139
140 Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( aURL, sTarget, 0 ), UNO_SET_THROW );
141
142 Application::PostUserEvent( LINK(nullptr, PopupMenuControllerBase, ExecuteHdl_Impl), new PopupMenuControllerBaseDispatchInfo( xDispatch, std::move(aURL), rArgs ) );
143
144 }
145 catch( Exception& )
146 {
147 }
148
149}
150
151IMPL_STATIC_LINK( PopupMenuControllerBase, ExecuteHdl_Impl, void*, p, void )
152{
153 PopupMenuControllerBaseDispatchInfo* pDispatchInfo = static_cast<PopupMenuControllerBaseDispatchInfo*>(p);
154 pDispatchInfo->mxDispatch->dispatch( pDispatchInfo->maURL, pDispatchInfo->maArgs );
155 delete pDispatchInfo;
156}
157
158void SAL_CALL PopupMenuControllerBase::itemActivated( const awt::MenuEvent& )
159{
160}
161
162void SAL_CALL PopupMenuControllerBase::itemDeactivated( const awt::MenuEvent& )
163{
164}
165
166void SAL_CALL PopupMenuControllerBase::updatePopupMenu()
167{
168 {
169 std::unique_lock aLock(m_aMutex);
170 throwIfDisposed(aLock);
171 }
172
173 updateCommand( m_aCommandURL );
174}
175
176void PopupMenuControllerBase::updateCommand( const OUString& rCommandURL )
177{
178 std::unique_lock aLock( m_aMutex );
179 Reference< XStatusListener > xStatusListener(this);
180 Reference< XDispatch > xDispatch( m_xDispatch );
182 aTargetURL.Complete = rCommandURL;
183 m_xURLTransformer->parseStrict( aTargetURL );
184 aLock.unlock();
185
186 // Add/remove status listener to get a status update once
187 if ( xDispatch.is() )
188 {
189 xDispatch->addStatusListener( xStatusListener, aTargetURL );
190 xDispatch->removeStatusListener( xStatusListener, aTargetURL );
191 }
192}
193
194
195// XDispatchProvider
196Reference< XDispatch > SAL_CALL
197PopupMenuControllerBase::queryDispatch(
198 const URL& /*aURL*/,
199 const OUString& /*sTarget*/,
200 sal_Int32 /*nFlags*/ )
201{
202 // must be implemented by subclass
203 std::unique_lock aLock( m_aMutex );
204 throwIfDisposed(aLock);
205
206 return Reference< XDispatch >();
207}
208
209Sequence< Reference< XDispatch > > SAL_CALL PopupMenuControllerBase::queryDispatches( const Sequence< DispatchDescriptor >& lDescriptor )
210{
211 // Create return list - which must have same size then the given descriptor
212 // It's not allowed to pack it!
213 {
214 std::unique_lock aLock(m_aMutex);
215 throwIfDisposed(aLock);
216 }
217
218 sal_Int32 nCount = lDescriptor.getLength();
219 uno::Sequence< uno::Reference< frame::XDispatch > > lDispatcher( nCount );
220
221 // Step over all descriptors and try to get any dispatcher for it.
222 std::transform(lDescriptor.begin(), lDescriptor.end(), lDispatcher.getArray(),
223 [this](const DispatchDescriptor& rDesc) -> uno::Reference< frame::XDispatch > {
224 return queryDispatch(rDesc.FeatureURL, rDesc.FrameName, rDesc.SearchFlags); });
225
226 return lDispatcher;
227}
228
229// XDispatch
230void SAL_CALL
231PopupMenuControllerBase::dispatch(
232 const URL& /*aURL*/,
233 const Sequence< PropertyValue >& /*seqProperties*/ )
234{
235 // must be implemented by subclass
236 std::unique_lock aLock( m_aMutex );
237 throwIfDisposed(aLock);
238}
239
240void SAL_CALL
241PopupMenuControllerBase::addStatusListener(
242 const Reference< XStatusListener >& xControl,
243 const URL& aURL )
244{
245 std::unique_lock aLock( m_aMutex );
246 throwIfDisposed(aLock);
247
248 bool bStatusUpdate( false );
249 maStatusListeners.addInterface( aLock, xControl );
250
251 if ( aURL.Complete.startsWith( m_aBaseURL ) )
252 bStatusUpdate = true;
253 aLock.unlock();
254
255 if ( bStatusUpdate )
256 {
257 // Dummy update for popup menu controllers
258 FeatureStateEvent aEvent;
259 aEvent.FeatureURL = aURL;
260 aEvent.IsEnabled = true;
261 aEvent.Requery = false;
262 aEvent.State = Any();
263 xControl->statusChanged( aEvent );
264 }
265}
266
267void SAL_CALL PopupMenuControllerBase::removeStatusListener(
268 const Reference< XStatusListener >& xControl,
269 const URL& /*aURL*/ )
270{
271 std::unique_lock aLock( m_aMutex );
272 maStatusListeners.removeInterface( aLock, xControl );
273}
274
275OUString PopupMenuControllerBase::determineBaseURL( std::u16string_view aURL )
276{
277 // Just use the main part of the URL for popup menu controllers
278 OUString aMainURL( "vnd.sun.star.popup:" );
279
280 size_t nSchemePart = aURL.find( ':' );
281 if (( nSchemePart != std::u16string_view::npos && nSchemePart > 0 ) &&
282 ( aURL.size() > ( nSchemePart+1 )))
283 {
284 size_t nQueryPart = aURL.find( '?', nSchemePart );
285 if ( nQueryPart != std::u16string_view::npos && nQueryPart > 0 )
286 aMainURL += aURL.substr( nSchemePart, nQueryPart-nSchemePart );
287 else if ( nQueryPart == std::u16string_view::npos )
288 aMainURL += aURL.substr( nSchemePart+1 );
289 }
290
291 return aMainURL;
292}
293
294// XInitialization
295void SAL_CALL PopupMenuControllerBase::initialize( const Sequence< Any >& aArguments )
296{
297 std::unique_lock aLock( m_aMutex );
298 initializeImpl(aLock, aArguments);
299}
300
301// XInitialization
302void PopupMenuControllerBase::initializeImpl( std::unique_lock<std::mutex>& /*rGuard*/, const Sequence< Any >& aArguments )
303{
304 bool bInitialized( m_bInitialized );
305 if ( bInitialized )
306 return;
307
308 PropertyValue aPropValue;
309 OUString aCommandURL;
310 Reference< XFrame > xFrame;
311
312 for ( const auto& rArgument : aArguments )
313 {
314 if ( rArgument >>= aPropValue )
315 {
316 if ( aPropValue.Name == "Frame" )
317 aPropValue.Value >>= xFrame;
318 else if ( aPropValue.Name == "CommandURL" )
319 aPropValue.Value >>= aCommandURL;
320 else if ( aPropValue.Name == "ModuleIdentifier" )
321 aPropValue.Value >>= m_aModuleName;
322 }
323 }
324
325 if ( xFrame.is() && !aCommandURL.isEmpty() )
326 {
328 m_aCommandURL = aCommandURL;
329 m_aBaseURL = determineBaseURL( aCommandURL );
330 m_bInitialized = true;
331 }
332}
333// XPopupMenuController
334void SAL_CALL PopupMenuControllerBase::setPopupMenu( const Reference< awt::XPopupMenu >& xPopupMenu )
335{
336 {
337 std::unique_lock aLock( m_aMutex );
338 throwIfDisposed(aLock);
339
340 if ( !m_xFrame.is() || m_xPopupMenu.is() )
341 return;
342
343 // Create popup menu on demand
344 SolarMutexGuard aSolarMutexGuard;
345
346 m_xPopupMenu = dynamic_cast<VCLXPopupMenu*>(xPopupMenu.get());
347 assert(bool(xPopupMenu) == bool(m_xPopupMenu) && "we only support VCLXPopupMenu");
348 m_xPopupMenu->addMenuListener( Reference< awt::XMenuListener >(this) );
349
350 Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
351
353 aTargetURL.Complete = m_aCommandURL;
354 m_xURLTransformer->parseStrict( aTargetURL );
355 m_xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
356
357 impl_setPopupMenu();
358 }
359 updatePopupMenu();
360}
361void PopupMenuControllerBase::impl_setPopupMenu()
362{
363}
364}
365
366/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::lang::XComponent > m_xFrame
css::uno::Reference< css::frame::XDispatch > m_xDispatch
static bool bInitialized
Definition: apearcfg.cxx:31
AnyEventRef aEvent
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
int nCount
Reference< XDispatch > xDispatch
URL aURL
void * p
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
IMPL_STATIC_LINK(PopupMenuControllerBase, ExecuteHdl_Impl, void *, p, void)
const URL maURL
const Sequence< PropertyValue > maArgs
Reference< XDispatch > mxDispatch
Reference< XFrame > xFrame
unsigned char sal_Bool
OUString aTargetURL