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