Line data Source code
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 :
20 : #include <svtools/popupmenucontrollerbase.hxx>
21 :
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>
28 :
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>
35 :
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;
42 :
43 : namespace svt
44 : {
45 :
46 0 : struct PopupMenuControllerBaseDispatchInfo
47 : {
48 : Reference< XDispatch > mxDispatch;
49 : const URL maURL;
50 : const Sequence< PropertyValue > maArgs;
51 :
52 0 : PopupMenuControllerBaseDispatchInfo( const Reference< XDispatch >& xDispatch, const URL& rURL, const Sequence< PropertyValue >& rArgs )
53 0 : : mxDispatch( xDispatch ), maURL( rURL ), maArgs( rArgs ) {}
54 : };
55 :
56 636 : PopupMenuControllerBase::PopupMenuControllerBase( const Reference< XComponentContext >& xContext ) :
57 : ::comphelper::OBaseMutex(),
58 : PopupMenuControllerBaseType(m_aMutex),
59 636 : m_bInitialized( false )
60 : {
61 636 : if ( xContext.is() )
62 636 : m_xURLTransformer.set( util::URLTransformer::create( xContext ) );
63 636 : }
64 :
65 636 : PopupMenuControllerBase::~PopupMenuControllerBase()
66 : {
67 636 : }
68 :
69 : // protected function
70 1241 : void PopupMenuControllerBase::throwIfDisposed() throw ( RuntimeException )
71 : {
72 1241 : if (rBHelper.bDisposed || rBHelper.bInDispose)
73 0 : throw com::sun::star::lang::DisposedException();
74 1241 : }
75 :
76 : // protected function
77 607 : void PopupMenuControllerBase::resetPopupMenu( com::sun::star::uno::Reference< com::sun::star::awt::XPopupMenu >& rPopupMenu )
78 : {
79 607 : if ( rPopupMenu.is() && rPopupMenu->getItemCount() > 0 )
80 : {
81 0 : rPopupMenu->clear();
82 : }
83 607 : }
84 :
85 636 : void SAL_CALL PopupMenuControllerBase::disposing()
86 : {
87 : // Reset our members and set disposed flag
88 636 : osl::MutexGuard aLock( m_aMutex );
89 636 : m_xFrame.clear();
90 636 : m_xDispatch.clear();
91 636 : m_xPopupMenu.clear();
92 636 : }
93 :
94 : // XServiceInfo
95 0 : sal_Bool SAL_CALL PopupMenuControllerBase::supportsService( const OUString& ServiceName ) throw (RuntimeException, std::exception)
96 : {
97 0 : return cppu::supportsService(this, ServiceName);
98 : }
99 :
100 : // XEventListener
101 0 : void SAL_CALL PopupMenuControllerBase::disposing( const EventObject& ) throw ( RuntimeException, std::exception )
102 : {
103 0 : osl::MutexGuard aLock( m_aMutex );
104 0 : m_xFrame.clear();
105 0 : m_xDispatch.clear();
106 0 : m_xPopupMenu.clear();
107 0 : }
108 :
109 : // XMenuListener
110 0 : void SAL_CALL PopupMenuControllerBase::itemHighlighted( const awt::MenuEvent& ) throw (RuntimeException, std::exception)
111 : {
112 0 : }
113 :
114 0 : void PopupMenuControllerBase::impl_select(const Reference< XDispatch >& _xDispatch,const URL& aURL)
115 : {
116 0 : Sequence<PropertyValue> aArgs;
117 : OSL_ENSURE(_xDispatch.is(),"PopupMenuControllerBase::impl_select: No dispatch");
118 0 : if ( _xDispatch.is() )
119 0 : _xDispatch->dispatch( aURL, aArgs );
120 0 : }
121 :
122 0 : void SAL_CALL PopupMenuControllerBase::itemSelected( const awt::MenuEvent& rEvent ) throw (RuntimeException, std::exception)
123 : {
124 0 : throwIfDisposed();
125 :
126 0 : osl::MutexGuard aLock( m_aMutex );
127 :
128 0 : if( m_xPopupMenu.is() )
129 : {
130 0 : Sequence<PropertyValue> aArgs;
131 0 : dispatchCommand( m_xPopupMenu->getCommand( rEvent.MenuId ), aArgs );
132 0 : }
133 0 : }
134 :
135 0 : void PopupMenuControllerBase::dispatchCommand( const OUString& sCommandURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs )
136 : {
137 0 : osl::MutexGuard aLock( m_aMutex );
138 :
139 0 : throwIfDisposed();
140 :
141 : try
142 : {
143 0 : Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY_THROW );
144 0 : URL aURL;
145 0 : aURL.Complete = sCommandURL;
146 0 : m_xURLTransformer->parseStrict( aURL );
147 :
148 0 : Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( aURL, OUString(), 0 ), UNO_QUERY_THROW );
149 :
150 0 : Application::PostUserEvent( LINK(0, PopupMenuControllerBase, ExecuteHdl_Impl), new PopupMenuControllerBaseDispatchInfo( xDispatch, aURL, rArgs ) );
151 :
152 : }
153 0 : catch( Exception& )
154 : {
155 0 : }
156 :
157 0 : }
158 :
159 0 : IMPL_STATIC_LINK( PopupMenuControllerBase, ExecuteHdl_Impl, PopupMenuControllerBaseDispatchInfo*, pDispatchInfo )
160 : {
161 0 : pDispatchInfo->mxDispatch->dispatch( pDispatchInfo->maURL, pDispatchInfo->maArgs );
162 0 : delete pDispatchInfo;
163 0 : return 0;
164 : }
165 :
166 0 : void SAL_CALL PopupMenuControllerBase::itemActivated( const awt::MenuEvent& ) throw (RuntimeException, std::exception)
167 : {
168 0 : }
169 :
170 0 : void SAL_CALL PopupMenuControllerBase::itemDeactivated( const awt::MenuEvent& ) throw (RuntimeException, std::exception)
171 : {
172 0 : }
173 :
174 620 : void SAL_CALL PopupMenuControllerBase::updatePopupMenu() throw ( ::com::sun::star::uno::RuntimeException, std::exception )
175 : {
176 620 : osl::ClearableMutexGuard aLock( m_aMutex );
177 620 : throwIfDisposed();
178 620 : aLock.clear();
179 :
180 620 : updateCommand( m_aCommandURL );
181 620 : }
182 :
183 620 : void SAL_CALL PopupMenuControllerBase::updateCommand( const OUString& rCommandURL )
184 : {
185 620 : osl::ClearableMutexGuard aLock( m_aMutex );
186 1240 : Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY );
187 1240 : Reference< XDispatch > xDispatch( m_xDispatch );
188 1240 : URL aTargetURL;
189 620 : aTargetURL.Complete = rCommandURL;
190 620 : m_xURLTransformer->parseStrict( aTargetURL );
191 620 : aLock.clear();
192 :
193 : // Add/remove status listener to get a status update once
194 620 : if ( xDispatch.is() )
195 : {
196 611 : xDispatch->addStatusListener( xStatusListener, aTargetURL );
197 611 : xDispatch->removeStatusListener( xStatusListener, aTargetURL );
198 620 : }
199 620 : }
200 :
201 :
202 : // XDispatchProvider
203 : Reference< XDispatch > SAL_CALL
204 0 : PopupMenuControllerBase::queryDispatch(
205 : const URL& /*aURL*/,
206 : const OUString& /*sTarget*/,
207 : sal_Int32 /*nFlags*/ )
208 : throw( RuntimeException, std::exception )
209 : {
210 : // must be implemented by subclass
211 0 : osl::MutexGuard aLock( m_aMutex );
212 0 : throwIfDisposed();
213 :
214 0 : return Reference< XDispatch >();
215 : }
216 :
217 0 : Sequence< Reference< XDispatch > > SAL_CALL PopupMenuControllerBase::queryDispatches( const Sequence< DispatchDescriptor >& lDescriptor ) throw( RuntimeException, std::exception )
218 : {
219 : // Create return list - which must have same size then the given descriptor
220 : // It's not allowed to pack it!
221 0 : osl::ClearableMutexGuard aLock( m_aMutex );
222 0 : throwIfDisposed();
223 0 : aLock.clear();
224 :
225 0 : sal_Int32 nCount = lDescriptor.getLength();
226 0 : uno::Sequence< uno::Reference< frame::XDispatch > > lDispatcher( nCount );
227 :
228 : // Step over all descriptors and try to get any dispatcher for it.
229 0 : for( sal_Int32 i=0; i<nCount; ++i )
230 : {
231 0 : lDispatcher[i] = queryDispatch( lDescriptor[i].FeatureURL ,
232 0 : lDescriptor[i].FrameName ,
233 0 : lDescriptor[i].SearchFlags );
234 : }
235 :
236 0 : return lDispatcher;
237 : }
238 :
239 : // XDispatch
240 : void SAL_CALL
241 0 : PopupMenuControllerBase::dispatch(
242 : const URL& /*aURL*/,
243 : const Sequence< PropertyValue >& /*seqProperties*/ )
244 : throw( ::com::sun::star::uno::RuntimeException, std::exception )
245 : {
246 : // must be implemented by subclass
247 0 : osl::MutexGuard aLock( m_aMutex );
248 0 : throwIfDisposed();
249 0 : }
250 :
251 : void SAL_CALL
252 0 : PopupMenuControllerBase::addStatusListener(
253 : const Reference< XStatusListener >& xControl,
254 : const URL& aURL )
255 : throw( ::com::sun::star::uno::RuntimeException, std::exception )
256 : {
257 0 : osl::ResettableMutexGuard aLock( m_aMutex );
258 0 : throwIfDisposed();
259 0 : aLock.clear();
260 :
261 0 : bool bStatusUpdate( false );
262 0 : rBHelper.addListener( cppu::UnoType<decltype(xControl)>::get(), xControl );
263 :
264 0 : aLock.reset();
265 0 : if ( aURL.Complete.startsWith( m_aBaseURL ) )
266 0 : bStatusUpdate = true;
267 0 : aLock.clear();
268 :
269 0 : if ( bStatusUpdate )
270 : {
271 : // Dummy update for popup menu controllers
272 0 : FeatureStateEvent aEvent;
273 0 : aEvent.FeatureURL = aURL;
274 0 : aEvent.IsEnabled = sal_True;
275 0 : aEvent.Requery = sal_False;
276 0 : aEvent.State = Any();
277 0 : xControl->statusChanged( aEvent );
278 0 : }
279 0 : }
280 :
281 0 : void SAL_CALL PopupMenuControllerBase::removeStatusListener(
282 : const Reference< XStatusListener >& xControl,
283 : const URL& /*aURL*/ )
284 : throw( ::com::sun::star::uno::RuntimeException, std::exception )
285 : {
286 0 : rBHelper.removeListener( cppu::UnoType<decltype(xControl)>::get(), xControl );
287 0 : }
288 :
289 609 : OUString PopupMenuControllerBase::determineBaseURL( const OUString& aURL )
290 : {
291 : // Just use the main part of the URL for popup menu controllers
292 609 : sal_Int32 nQueryPart( 0 );
293 609 : sal_Int32 nSchemePart( 0 );
294 609 : OUString aMainURL( "vnd.sun.star.popup:" );
295 :
296 609 : nSchemePart = aURL.indexOf( ':' );
297 1218 : if (( nSchemePart > 0 ) &&
298 609 : ( aURL.getLength() > ( nSchemePart+1 )))
299 : {
300 609 : nQueryPart = aURL.indexOf( '?', nSchemePart );
301 609 : if ( nQueryPart > 0 )
302 0 : aMainURL += aURL.copy( nSchemePart, nQueryPart-nSchemePart );
303 609 : else if ( nQueryPart == -1 )
304 609 : aMainURL += aURL.copy( nSchemePart+1 );
305 : }
306 :
307 609 : return aMainURL;
308 : }
309 :
310 : // XInitialization
311 617 : void SAL_CALL PopupMenuControllerBase::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException, std::exception )
312 : {
313 617 : osl::MutexGuard aLock( m_aMutex );
314 :
315 617 : bool bInitalized( m_bInitialized );
316 617 : if ( !bInitalized )
317 : {
318 617 : PropertyValue aPropValue;
319 1234 : OUString aCommandURL;
320 1234 : Reference< XFrame > xFrame;
321 :
322 2444 : for ( int i = 0; i < aArguments.getLength(); i++ )
323 : {
324 1827 : if ( aArguments[i] >>= aPropValue )
325 : {
326 1827 : if ( aPropValue.Name == "Frame" )
327 609 : aPropValue.Value >>= xFrame;
328 1218 : else if ( aPropValue.Name == "CommandURL" )
329 609 : aPropValue.Value >>= aCommandURL;
330 609 : else if ( aPropValue.Name == "ModuleName" )
331 0 : aPropValue.Value >>= m_aModuleName;
332 : }
333 : }
334 :
335 617 : if ( xFrame.is() && !aCommandURL.isEmpty() )
336 : {
337 609 : m_xFrame = xFrame;
338 609 : m_aCommandURL = aCommandURL;
339 609 : m_aBaseURL = determineBaseURL( aCommandURL );
340 609 : m_bInitialized = true;
341 617 : }
342 617 : }
343 617 : }
344 : // XPopupMenuController
345 615 : void SAL_CALL PopupMenuControllerBase::setPopupMenu( const Reference< awt::XPopupMenu >& xPopupMenu ) throw ( RuntimeException, std::exception )
346 : {
347 615 : osl::MutexGuard aLock( m_aMutex );
348 615 : throwIfDisposed();
349 :
350 615 : if ( m_xFrame.is() && !m_xPopupMenu.is() )
351 : {
352 : // Create popup menu on demand
353 608 : SolarMutexGuard aSolarMutexGuard;
354 :
355 608 : m_xPopupMenu = xPopupMenu;
356 608 : m_xPopupMenu->addMenuListener( Reference< awt::XMenuListener >( static_cast<OWeakObject*>(this), UNO_QUERY ));
357 :
358 1216 : Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
359 :
360 1216 : URL aTargetURL;
361 608 : aTargetURL.Complete = m_aCommandURL;
362 608 : m_xURLTransformer->parseStrict( aTargetURL );
363 608 : m_xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
364 :
365 608 : impl_setPopupMenu();
366 :
367 1216 : updatePopupMenu();
368 615 : }
369 615 : }
370 2 : void PopupMenuControllerBase::impl_setPopupMenu()
371 : {
372 2 : }
373 : }
374 :
375 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|