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 <dispatch/popupmenudispatcher.hxx>
21 : #include <general.h>
22 : #include <framework/menuconfiguration.hxx>
23 : #include <framework/addonmenu.hxx>
24 : #include <services.h>
25 : #include <properties.h>
26 :
27 : #include <com/sun/star/frame/FrameSearchFlag.hpp>
28 : #include <com/sun/star/awt/WindowAttribute.hpp>
29 : #include <com/sun/star/awt/WindowDescriptor.hpp>
30 : #include <com/sun/star/awt/PosSize.hpp>
31 : #include <com/sun/star/awt/XWindowPeer.hpp>
32 : #include <com/sun/star/beans/UnknownPropertyException.hpp>
33 : #include <com/sun/star/lang/WrappedTargetException.hpp>
34 : #include <com/sun/star/beans/XPropertySet.hpp>
35 : #include <com/sun/star/container/XEnumeration.hpp>
36 : #include <com/sun/star/uri/UriReferenceFactory.hpp>
37 :
38 : #include <comphelper/componentcontext.hxx>
39 : #include <ucbhelper/content.hxx>
40 : #include <osl/mutex.hxx>
41 : #include <rtl/ustrbuf.hxx>
42 : #include <vcl/svapp.hxx>
43 :
44 : namespace framework{
45 :
46 : using namespace ::com::sun::star ;
47 : using namespace ::com::sun::star::awt ;
48 : using namespace ::com::sun::star::beans ;
49 : using namespace ::com::sun::star::container ;
50 : using namespace ::com::sun::star::frame ;
51 : using namespace ::com::sun::star::lang ;
52 : using namespace ::com::sun::star::uno ;
53 : using namespace ::com::sun::star::util ;
54 : using namespace ::cppu ;
55 : using namespace ::osl ;
56 : using namespace ::rtl ;
57 :
58 : const char* PROTOCOL_VALUE = "vnd.sun.star.popup:";
59 : const sal_Int32 PROTOCOL_LENGTH = 19;
60 :
61 : //*****************************************************************************************************************
62 : // constructor
63 : //*****************************************************************************************************************
64 0 : PopupMenuDispatcher::PopupMenuDispatcher(
65 : const uno::Reference< XComponentContext >& xContext )
66 : // Init baseclasses first
67 0 : : ThreadHelpBase ( &Application::GetSolarMutex() )
68 : , OWeakObject ( )
69 : // Init member
70 : , m_xContext ( xContext )
71 0 : , m_aListenerContainer ( m_aLock.getShareableOslMutex() )
72 : , m_bAlreadyDisposed ( sal_False )
73 0 : , m_bActivateListener ( sal_False )
74 : {
75 0 : }
76 :
77 : //*****************************************************************************************************************
78 : // destructor
79 : //*****************************************************************************************************************
80 0 : PopupMenuDispatcher::~PopupMenuDispatcher()
81 : {
82 : // Warn programmer if he forgot to dispose this instance.
83 : // We must release all our references ...
84 : // and a dtor isn't the best place to do that!
85 0 : }
86 :
87 : //*****************************************************************************************************************
88 : // XInterface, XTypeProvider
89 : //*****************************************************************************************************************
90 0 : DEFINE_XINTERFACE_7 ( PopupMenuDispatcher ,
91 : ::cppu::OWeakObject ,
92 : DIRECT_INTERFACE( XTypeProvider ),
93 : DIRECT_INTERFACE( XServiceInfo ),
94 : DIRECT_INTERFACE( XDispatchProvider ),
95 : DIRECT_INTERFACE( XDispatch ),
96 : DIRECT_INTERFACE( XEventListener ),
97 : DIRECT_INTERFACE( XInitialization ),
98 : DERIVED_INTERFACE( XFrameActionListener, XEventListener )
99 : )
100 :
101 0 : DEFINE_XTYPEPROVIDER_7 ( PopupMenuDispatcher ,
102 : XTypeProvider ,
103 : XServiceInfo ,
104 : XDispatchProvider ,
105 : XDispatch ,
106 : XEventListener ,
107 : XInitialization ,
108 : XFrameActionListener
109 : )
110 :
111 0 : ::rtl::OUString SAL_CALL PopupMenuDispatcher::getImplementationName() throw( css::uno::RuntimeException )
112 : {
113 0 : return impl_getStaticImplementationName();
114 : }
115 :
116 0 : sal_Bool SAL_CALL PopupMenuDispatcher::supportsService( const ::rtl::OUString& sServiceName )
117 : throw( css::uno::RuntimeException )
118 : {
119 0 : return ::comphelper::findValue(getSupportedServiceNames(), sServiceName, sal_True).getLength() != 0;
120 : }
121 :
122 0 : css::uno::Sequence< ::rtl::OUString > SAL_CALL PopupMenuDispatcher::getSupportedServiceNames()
123 : throw( css::uno::RuntimeException )
124 : {
125 0 : return impl_getStaticSupportedServiceNames();
126 : }
127 :
128 0 : css::uno::Sequence< ::rtl::OUString > PopupMenuDispatcher::impl_getStaticSupportedServiceNames()
129 : {
130 0 : css::uno::Sequence< ::rtl::OUString > seqServiceNames( 1 );
131 0 : seqServiceNames.getArray() [0] = SERVICENAME_PROTOCOLHANDLER;
132 0 : return seqServiceNames;
133 : }
134 :
135 0 : ::rtl::OUString PopupMenuDispatcher::impl_getStaticImplementationName()
136 : {
137 0 : return IMPLEMENTATIONNAME_POPUPMENUDISPATCHER;
138 : }
139 :
140 : css::uno::Reference< css::uno::XInterface >
141 0 : SAL_CALL PopupMenuDispatcher::impl_createInstance( const css::uno::Reference< css::lang::XMultiServiceFactory >& xServiceManager )
142 : throw( css::uno::Exception )
143 : {
144 : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework","Ocke.Janssen@sun.com",U2B(IMPLEMENTATIONNAME_POPUPMENUDISPATCHER).getStr());
145 : /* create new instance of service */
146 0 : PopupMenuDispatcher* pClass = new PopupMenuDispatcher( comphelper::getComponentContext(xServiceManager) );
147 : /* hold it alive by increasing his ref count!!! */
148 0 : css::uno::Reference< css::uno::XInterface > xService( static_cast< ::cppu::OWeakObject* >(pClass), css::uno::UNO_QUERY );
149 : /* initialize new service instance ... he can use his own refcount ... we hold it! */
150 0 : pClass->impl_initService();
151 : /* return new created service as reference */
152 0 : return xService;
153 : }
154 :
155 : css::uno::Reference< css::lang::XSingleServiceFactory >
156 0 : PopupMenuDispatcher::impl_createFactory( const css::uno::Reference< css::lang::XMultiServiceFactory >& xServiceManager )
157 : {
158 : css::uno::Reference< css::lang::XSingleServiceFactory > xReturn (
159 : cppu::createSingleFactory ( xServiceManager,
160 : PopupMenuDispatcher::impl_getStaticImplementationName() ,
161 : PopupMenuDispatcher::impl_createInstance ,
162 : PopupMenuDispatcher::impl_getStaticSupportedServiceNames() )
163 0 : );
164 0 : return xReturn;
165 : }
166 :
167 0 : DEFINE_INIT_SERVICE(PopupMenuDispatcher,
168 : {
169 : /*Attention
170 : I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
171 : to create a new instance of this class by our own supported service factory.
172 : see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
173 : */
174 : }
175 : )
176 :
177 : //*****************************************************************************************************************
178 : // XInitialization
179 : //*****************************************************************************************************************
180 0 : void SAL_CALL PopupMenuDispatcher::initialize(
181 : const css::uno::Sequence< css::uno::Any >& lArguments )
182 : throw( css::uno::Exception, css::uno::RuntimeException)
183 : {
184 0 : css::uno::Reference< css::frame::XFrame > xFrame;
185 :
186 : /* SAFE { */
187 0 : WriteGuard aWriteLock(m_aLock);
188 :
189 0 : for (int a=0; a<lArguments.getLength(); ++a)
190 : {
191 0 : if (a==0)
192 : {
193 0 : lArguments[a] >>= xFrame;
194 0 : m_xWeakFrame = xFrame;
195 :
196 0 : m_bActivateListener = sal_True;
197 : uno::Reference< css::frame::XFrameActionListener > xFrameActionListener(
198 0 : (OWeakObject *)this, css::uno::UNO_QUERY );
199 0 : xFrame->addFrameActionListener( xFrameActionListener );
200 : }
201 : }
202 :
203 0 : aWriteLock.unlock();
204 : /* } SAFE */
205 0 : }
206 :
207 : //*****************************************************************************************************************
208 : // XDispatchProvider
209 : //*****************************************************************************************************************
210 : css::uno::Reference< css::frame::XDispatch >
211 0 : SAL_CALL PopupMenuDispatcher::queryDispatch(
212 : const css::util::URL& rURL ,
213 : const ::rtl::OUString& sTarget ,
214 : sal_Int32 nFlags )
215 : throw( css::uno::RuntimeException )
216 : {
217 0 : css::uno::Reference< css::frame::XDispatch > xDispatch;
218 :
219 0 : if ( rURL.Complete.compareToAscii( PROTOCOL_VALUE, PROTOCOL_LENGTH ) == 0 )
220 : {
221 : // --- SAFE ---
222 0 : ResetableGuard aGuard( m_aLock );
223 0 : impl_RetrievePopupControllerQuery();
224 0 : impl_CreateUriRefFactory();
225 :
226 0 : css::uno::Reference< css::container::XNameAccess > xPopupCtrlQuery( m_xPopupCtrlQuery );
227 0 : css::uno::Reference< css::uri::XUriReferenceFactory > xUriRefFactory( m_xUriRefFactory );
228 0 : aGuard.unlock();
229 : // --- SAFE ---
230 :
231 0 : if ( xPopupCtrlQuery.is() )
232 : {
233 : try
234 : {
235 : // Just use the main part of the URL for popup menu controllers
236 0 : sal_Int32 nQueryPart( 0 );
237 0 : sal_Int32 nSchemePart( 0 );
238 0 : rtl::OUString aBaseURL( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.popup:" ));
239 0 : rtl::OUString aURL( rURL.Complete );
240 :
241 0 : nSchemePart = aURL.indexOf( ':' );
242 0 : if (( nSchemePart > 0 ) &&
243 0 : ( aURL.getLength() > ( nSchemePart+1 )))
244 : {
245 0 : nQueryPart = aURL.indexOf( '?', nSchemePart );
246 0 : if ( nQueryPart > 0 )
247 0 : aBaseURL += aURL.copy( nSchemePart+1, nQueryPart-(nSchemePart+1) );
248 0 : else if ( nQueryPart == -1 )
249 0 : aBaseURL += aURL.copy( nSchemePart+1 );
250 : }
251 :
252 0 : css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider;
253 :
254 : // Find popup menu controller using the base URL
255 0 : xPopupCtrlQuery->getByName( aBaseURL ) >>= xDispatchProvider;
256 0 : aGuard.unlock();
257 :
258 : // Ask popup menu dispatch provider for dispatch object
259 0 : if ( xDispatchProvider.is() )
260 0 : xDispatch = xDispatchProvider->queryDispatch( rURL, sTarget, nFlags );
261 : }
262 0 : catch ( const RuntimeException& )
263 : {
264 0 : throw;
265 : }
266 0 : catch ( const Exception& )
267 : {
268 : }
269 0 : }
270 : }
271 0 : return xDispatch;
272 : }
273 :
274 : css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL
275 0 : PopupMenuDispatcher::queryDispatches(
276 : const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor )
277 : throw( css::uno::RuntimeException )
278 : {
279 0 : sal_Int32 nCount = lDescriptor.getLength();
280 0 : css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount );
281 0 : for( sal_Int32 i=0; i<nCount; ++i )
282 : {
283 0 : lDispatcher[i] = this->queryDispatch(
284 0 : lDescriptor[i].FeatureURL,
285 0 : lDescriptor[i].FrameName,
286 0 : lDescriptor[i].SearchFlags);
287 : }
288 0 : return lDispatcher;
289 : }
290 :
291 : //*****************************************************************************************************************
292 : // XDispatch
293 : //*****************************************************************************************************************
294 : void
295 0 : SAL_CALL PopupMenuDispatcher::dispatch(
296 : const URL& /*aURL*/ ,
297 : const Sequence< PropertyValue >& /*seqProperties*/ )
298 : throw( RuntimeException )
299 : {
300 0 : }
301 :
302 : //*****************************************************************************************************************
303 : // XDispatch
304 : //*****************************************************************************************************************
305 : void
306 0 : SAL_CALL PopupMenuDispatcher::addStatusListener(
307 : const uno::Reference< XStatusListener >& xControl,
308 : const URL& aURL )
309 : throw( RuntimeException )
310 : {
311 : // Ready for multithreading
312 0 : ResetableGuard aGuard( m_aLock );
313 : // Safe impossible cases
314 : // Add listener to container.
315 0 : m_aListenerContainer.addInterface( aURL.Complete, xControl );
316 0 : }
317 :
318 : //*****************************************************************************************************************
319 : // XDispatch
320 : //*****************************************************************************************************************
321 : void
322 0 : SAL_CALL PopupMenuDispatcher::removeStatusListener(
323 : const uno::Reference< XStatusListener >& xControl,
324 : const URL& aURL )
325 : throw( RuntimeException )
326 : {
327 : // Ready for multithreading
328 0 : ResetableGuard aGuard( m_aLock );
329 : // Safe impossible cases
330 : // Add listener to container.
331 0 : m_aListenerContainer.removeInterface( aURL.Complete, xControl );
332 0 : }
333 :
334 : //*****************************************************************************************************************
335 : // XFrameActionListener
336 : //*****************************************************************************************************************
337 :
338 : void
339 0 : SAL_CALL PopupMenuDispatcher::frameAction(
340 : const FrameActionEvent& aEvent )
341 : throw ( RuntimeException )
342 : {
343 0 : ResetableGuard aGuard( m_aLock );
344 :
345 0 : if (( aEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING ) ||
346 : ( aEvent.Action == css::frame::FrameAction_COMPONENT_ATTACHED ))
347 : {
348 : // Reset query reference to requery it again next time
349 0 : m_xPopupCtrlQuery.clear();
350 0 : }
351 0 : }
352 :
353 : //*****************************************************************************************************************
354 : // XEventListener
355 : //*****************************************************************************************************************
356 : void
357 0 : SAL_CALL PopupMenuDispatcher::disposing( const EventObject& ) throw( RuntimeException )
358 : {
359 : // Ready for multithreading
360 0 : ResetableGuard aGuard( m_aLock );
361 : // Safe impossible cases
362 : LOG_ASSERT( !(m_bAlreadyDisposed==sal_True), "MenuDispatcher::disposing()\nObject already disposed .. don't call it again!\n" )
363 :
364 0 : if( m_bAlreadyDisposed == sal_False )
365 : {
366 0 : m_bAlreadyDisposed = sal_True;
367 :
368 0 : if ( m_bActivateListener )
369 : {
370 0 : uno::Reference< XFrame > xFrame( m_xWeakFrame.get(), UNO_QUERY );
371 0 : if ( xFrame.is() )
372 : {
373 0 : xFrame->removeFrameActionListener( uno::Reference< XFrameActionListener >( (OWeakObject *)this, UNO_QUERY ));
374 0 : m_bActivateListener = sal_False;
375 0 : }
376 : }
377 :
378 : // Forget our factory.
379 0 : m_xContext = uno::Reference< XComponentContext >();
380 0 : }
381 0 : }
382 :
383 0 : void PopupMenuDispatcher::impl_RetrievePopupControllerQuery()
384 : {
385 0 : if ( !m_xPopupCtrlQuery.is() )
386 : {
387 0 : css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
388 0 : css::uno::Reference< css::frame::XFrame > xFrame( m_xWeakFrame );
389 :
390 0 : if ( xFrame.is() )
391 : {
392 0 : css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, css::uno::UNO_QUERY );
393 0 : if ( xPropSet.is() )
394 : {
395 : try
396 : {
397 0 : xPropSet->getPropertyValue( FRAME_PROPNAME_LAYOUTMANAGER ) >>= xLayoutManager;
398 :
399 0 : if ( xLayoutManager.is() )
400 : {
401 0 : css::uno::Reference< css::ui::XUIElement > xMenuBar;
402 0 : rtl::OUString aMenuBar( RTL_CONSTASCII_USTRINGPARAM( "private:resource/menubar/menubar" ));
403 0 : xMenuBar = xLayoutManager->getElement( aMenuBar );
404 :
405 : m_xPopupCtrlQuery = css::uno::Reference< css::container::XNameAccess >(
406 0 : xMenuBar, css::uno::UNO_QUERY );
407 : }
408 : }
409 0 : catch ( const css::uno::RuntimeException& )
410 : {
411 0 : throw;
412 : }
413 0 : catch ( const css::uno::Exception& )
414 : {
415 : }
416 0 : }
417 0 : }
418 : }
419 0 : }
420 :
421 0 : void PopupMenuDispatcher::impl_CreateUriRefFactory()
422 : {
423 0 : if ( !m_xUriRefFactory.is() )
424 : {
425 0 : m_xUriRefFactory = css::uri::UriReferenceFactory::create( m_xContext );
426 : }
427 0 : }
428 :
429 : } // namespace framework
430 :
431 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|