tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / svtools / source / uno / popupmenucontrollerbase.cxx
blobab6bee1a0555586e0c692fd34ec0cac9fe3161d3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <utility>
29 #include <vcl/svapp.hxx>
30 #include <osl/mutex.hxx>
31 #include <cppuhelper/supportsservice.hxx>
32 #include <toolkit/awt/vclxmenu.hxx>
34 using namespace com::sun::star;
35 using namespace css::uno;
36 using namespace css::lang;
37 using namespace css::frame;
38 using namespace css::beans;
39 using namespace css::util;
41 namespace svt
44 namespace {
46 struct PopupMenuControllerBaseDispatchInfo
48 Reference< XDispatch > mxDispatch;
49 const URL maURL;
50 const Sequence< PropertyValue > maArgs;
52 PopupMenuControllerBaseDispatchInfo( const Reference< XDispatch >& xDispatch, URL aURL, const Sequence< PropertyValue >& rArgs )
53 : mxDispatch( xDispatch ), maURL(std::move( aURL )), maArgs( rArgs ) {}
58 PopupMenuControllerBase::PopupMenuControllerBase( const Reference< XComponentContext >& xContext ) :
59 m_bInitialized( false )
61 if ( xContext.is() )
62 m_xURLTransformer.set( util::URLTransformer::create( xContext ) );
65 PopupMenuControllerBase::~PopupMenuControllerBase()
69 // protected function
70 void PopupMenuControllerBase::resetPopupMenu( css::uno::Reference< css::awt::XPopupMenu > const & rPopupMenu )
72 if ( rPopupMenu.is() && rPopupMenu->getItemCount() > 0 )
74 rPopupMenu->clear();
78 void PopupMenuControllerBase::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
80 // Reset our members and set disposed flag
81 m_xFrame.clear();
82 m_xDispatch.clear();
83 m_xPopupMenu.clear();
86 // XServiceInfo
87 sal_Bool SAL_CALL PopupMenuControllerBase::supportsService( const OUString& ServiceName )
89 return cppu::supportsService(this, ServiceName);
92 // XEventListener
93 void SAL_CALL PopupMenuControllerBase::disposing( const EventObject& )
95 std::unique_lock aLock( m_aMutex );
96 m_xFrame.clear();
97 m_xDispatch.clear();
98 m_xPopupMenu.clear();
101 // XMenuListener
102 void SAL_CALL PopupMenuControllerBase::itemHighlighted( const awt::MenuEvent& )
106 void SAL_CALL PopupMenuControllerBase::itemSelected( const awt::MenuEvent& rEvent )
108 std::unique_lock aLock( m_aMutex );
109 throwIfDisposed(aLock);
111 if( m_xPopupMenu.is() )
113 Sequence<PropertyValue> aArgs;
114 dispatchCommandImpl( aLock, m_xPopupMenu->getCommand( rEvent.MenuId ), aArgs, OUString() );
118 void PopupMenuControllerBase::dispatchCommand( const OUString& sCommandURL,
119 const css::uno::Sequence< css::beans::PropertyValue >& rArgs,
120 const OUString& sTarget )
122 std::unique_lock aLock( m_aMutex );
123 throwIfDisposed(aLock);
124 dispatchCommandImpl(aLock, sCommandURL, rArgs, sTarget);
127 void 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 )
135 Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY_THROW );
136 URL aURL;
137 aURL.Complete = sCommandURL;
138 m_xURLTransformer->parseStrict( aURL );
140 Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( aURL, sTarget, 0 ), UNO_SET_THROW );
142 Application::PostUserEvent( LINK(nullptr, PopupMenuControllerBase, ExecuteHdl_Impl), new PopupMenuControllerBaseDispatchInfo( xDispatch, std::move(aURL), rArgs ) );
145 catch( Exception& )
151 IMPL_STATIC_LINK( PopupMenuControllerBase, ExecuteHdl_Impl, void*, p, void )
153 PopupMenuControllerBaseDispatchInfo* pDispatchInfo = static_cast<PopupMenuControllerBaseDispatchInfo*>(p);
154 pDispatchInfo->mxDispatch->dispatch( pDispatchInfo->maURL, pDispatchInfo->maArgs );
155 delete pDispatchInfo;
158 void SAL_CALL PopupMenuControllerBase::itemActivated( const awt::MenuEvent& )
162 void SAL_CALL PopupMenuControllerBase::itemDeactivated( const awt::MenuEvent& )
166 void SAL_CALL PopupMenuControllerBase::updatePopupMenu()
169 std::unique_lock aLock(m_aMutex);
170 throwIfDisposed(aLock);
173 updateCommand( m_aCommandURL );
176 void PopupMenuControllerBase::updateCommand( const OUString& rCommandURL )
178 std::unique_lock aLock( m_aMutex );
179 Reference< XStatusListener > xStatusListener(this);
180 Reference< XDispatch > xDispatch( m_xDispatch );
181 URL aTargetURL;
182 aTargetURL.Complete = rCommandURL;
183 m_xURLTransformer->parseStrict( aTargetURL );
184 aLock.unlock();
186 // Add/remove status listener to get a status update once
187 if ( xDispatch.is() )
189 xDispatch->addStatusListener( xStatusListener, aTargetURL );
190 xDispatch->removeStatusListener( xStatusListener, aTargetURL );
195 // XDispatchProvider
196 Reference< XDispatch > SAL_CALL
197 PopupMenuControllerBase::queryDispatch(
198 const URL& /*aURL*/,
199 const OUString& /*sTarget*/,
200 sal_Int32 /*nFlags*/ )
202 // must be implemented by subclass
203 std::unique_lock aLock( m_aMutex );
204 throwIfDisposed(aLock);
206 return Reference< XDispatch >();
209 Sequence< Reference< XDispatch > > SAL_CALL PopupMenuControllerBase::queryDispatches( const Sequence< DispatchDescriptor >& lDescriptor )
211 // Create return list - which must have same size then the given descriptor
212 // It's not allowed to pack it!
214 std::unique_lock aLock(m_aMutex);
215 throwIfDisposed(aLock);
218 sal_Int32 nCount = lDescriptor.getLength();
219 uno::Sequence< uno::Reference< frame::XDispatch > > lDispatcher( nCount );
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); });
226 return lDispatcher;
229 // XDispatch
230 void SAL_CALL
231 PopupMenuControllerBase::dispatch(
232 const URL& /*aURL*/,
233 const Sequence< PropertyValue >& /*seqProperties*/ )
235 // must be implemented by subclass
236 std::unique_lock aLock( m_aMutex );
237 throwIfDisposed(aLock);
240 void SAL_CALL
241 PopupMenuControllerBase::addStatusListener(
242 const Reference< XStatusListener >& xControl,
243 const URL& aURL )
245 std::unique_lock aLock( m_aMutex );
246 throwIfDisposed(aLock);
248 bool bStatusUpdate( false );
249 maStatusListeners.addInterface( aLock, xControl );
251 if ( aURL.Complete.startsWith( m_aBaseURL ) )
252 bStatusUpdate = true;
253 aLock.unlock();
255 if ( bStatusUpdate )
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 );
267 void SAL_CALL PopupMenuControllerBase::removeStatusListener(
268 const Reference< XStatusListener >& xControl,
269 const URL& /*aURL*/ )
271 std::unique_lock aLock( m_aMutex );
272 maStatusListeners.removeInterface( aLock, xControl );
275 OUString PopupMenuControllerBase::determineBaseURL( std::u16string_view aURL )
277 // Just use the main part of the URL for popup menu controllers
278 OUString aMainURL( u"vnd.sun.star.popup:"_ustr );
280 size_t nSchemePart = aURL.find( ':' );
281 if (( nSchemePart != std::u16string_view::npos && nSchemePart > 0 ) &&
282 ( aURL.size() > ( nSchemePart+1 )))
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 );
291 return aMainURL;
294 // XInitialization
295 void SAL_CALL PopupMenuControllerBase::initialize( const Sequence< Any >& aArguments )
297 std::unique_lock aLock( m_aMutex );
298 initializeImpl(aLock, aArguments);
301 // XInitialization
302 void PopupMenuControllerBase::initializeImpl( std::unique_lock<std::mutex>& /*rGuard*/, const Sequence< Any >& aArguments )
304 bool bInitialized( m_bInitialized );
305 if ( bInitialized )
306 return;
308 PropertyValue aPropValue;
309 OUString aCommandURL;
310 Reference< XFrame > xFrame;
312 for ( const auto& rArgument : aArguments )
314 if ( rArgument >>= aPropValue )
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;
325 if ( xFrame.is() && !aCommandURL.isEmpty() )
327 m_xFrame = std::move(xFrame);
328 m_aCommandURL = aCommandURL;
329 m_aBaseURL = determineBaseURL( aCommandURL );
330 m_bInitialized = true;
333 // XPopupMenuController
334 void SAL_CALL PopupMenuControllerBase::setPopupMenu( const Reference< awt::XPopupMenu >& xPopupMenu )
337 std::unique_lock aLock( m_aMutex );
338 throwIfDisposed(aLock);
340 if ( !m_xFrame.is() || m_xPopupMenu.is() )
341 return;
343 // Create popup menu on demand
344 SolarMutexGuard aSolarMutexGuard;
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) );
350 Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
352 URL aTargetURL;
353 aTargetURL.Complete = m_aCommandURL;
354 m_xURLTransformer->parseStrict( aTargetURL );
355 m_xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
357 impl_setPopupMenu(aLock);
359 updatePopupMenu();
362 void PopupMenuControllerBase::impl_setPopupMenu(std::unique_lock<std::mutex>& /*rGuard*/)
368 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */