1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 //#include "precompiled_framework.hxx"
30 
31 //_________________________________________________________________________________________________________________
32 //	my own includes
33 //_________________________________________________________________________________________________________________
34 
35 #include <dispatch/popupmenudispatcher.hxx>
36 #include <general.h>
37 #include <framework/menuconfiguration.hxx>
38 #include <framework/addonmenu.hxx>
39 #include <services.h>
40 #include <properties.h>
41 
42 //_________________________________________________________________________________________________________________
43 //	interface includes
44 //_________________________________________________________________________________________________________________
45 #include <com/sun/star/frame/FrameSearchFlag.hpp>
46 #include <com/sun/star/awt/XToolkit.hpp>
47 #include <com/sun/star/awt/WindowAttribute.hpp>
48 #include <com/sun/star/awt/WindowDescriptor.hpp>
49 #include <com/sun/star/awt/PosSize.hpp>
50 #include <com/sun/star/awt/XWindowPeer.hpp>
51 #include <com/sun/star/beans/UnknownPropertyException.hpp>
52 #include <com/sun/star/lang/WrappedTargetException.hpp>
53 #include <com/sun/star/beans/XPropertySet.hpp>
54 #include <com/sun/star/container/XEnumeration.hpp>
55 
56 //_________________________________________________________________________________________________________________
57 //	includes of other projects
58 //_________________________________________________________________________________________________________________
59 
60 #include <ucbhelper/content.hxx>
61 #include <vos/mutex.hxx>
62 #include <rtl/ustrbuf.hxx>
63 #include <vcl/svapp.hxx>
64 
65 //_________________________________________________________________________________________________________________
66 //	namespace
67 //_________________________________________________________________________________________________________________
68 
69 namespace framework{
70 
71 using namespace ::com::sun::star				;
72 using namespace ::com::sun::star::awt			;
73 using namespace ::com::sun::star::beans			;
74 using namespace ::com::sun::star::container		;
75 using namespace ::com::sun::star::frame			;
76 using namespace ::com::sun::star::lang			;
77 using namespace ::com::sun::star::uno			;
78 using namespace ::com::sun::star::util			;
79 using namespace ::cppu							;
80 using namespace ::osl							;
81 using namespace ::rtl							;
82 using namespace ::vos							;
83 
84 //_________________________________________________________________________________________________________________
85 //	non exported const
86 //_________________________________________________________________________________________________________________
87 const char*     PROTOCOL_VALUE      = "vnd.sun.star.popup:";
88 const sal_Int32 PROTOCOL_LENGTH     = 19;
89 
90 //_________________________________________________________________________________________________________________
91 //	non exported definitions
92 //_________________________________________________________________________________________________________________
93 
94 //_________________________________________________________________________________________________________________
95 //	declarations
96 //_________________________________________________________________________________________________________________
97 
98 //*****************************************************************************************************************
99 //	constructor
100 //*****************************************************************************************************************
101 PopupMenuDispatcher::PopupMenuDispatcher(
102     const uno::Reference< XMultiServiceFactory >& xFactory )
103 		//	Init baseclasses first
104         :   ThreadHelpBase          ( &Application::GetSolarMutex()  )
105         ,   OWeakObject             (                                )
106         // Init member
107         ,   m_xFactory              ( xFactory                       )
108         ,   m_aListenerContainer    ( m_aLock.getShareableOslMutex() )
109         ,   m_bAlreadyDisposed      ( sal_False                      )
110         ,   m_bActivateListener     ( sal_False                      )
111 {
112 }
113 
114 //*****************************************************************************************************************
115 //	destructor
116 //*****************************************************************************************************************
117 PopupMenuDispatcher::~PopupMenuDispatcher()
118 {
119 	// Warn programmer if he forgot to dispose this instance.
120 	// We must release all our references ...
121 	// and a dtor isn't the best place to do that!
122 }
123 
124 //*****************************************************************************************************************
125 //	XInterface, XTypeProvider
126 //*****************************************************************************************************************
127 DEFINE_XINTERFACE_7     ( PopupMenuDispatcher                                     ,
128                           ::cppu::OWeakObject					  		          ,
129                           DIRECT_INTERFACE( XTypeProvider	                      ),
130                           DIRECT_INTERFACE( XServiceInfo                          ),
131                           DIRECT_INTERFACE( XDispatchProvider                     ),
132                           DIRECT_INTERFACE( XDispatch		                      ),
133                           DIRECT_INTERFACE( XEventListener                        ),
134                           DIRECT_INTERFACE( XInitialization                       ),
135                           DERIVED_INTERFACE( XFrameActionListener, XEventListener )
136 						)
137 
138 DEFINE_XTYPEPROVIDER_7  (   PopupMenuDispatcher ,
139 							XTypeProvider		,
140                             XServiceInfo        ,
141                             XDispatchProvider   ,
142 							XDispatch			,
143 							XEventListener		,
144                             XInitialization     ,
145 							XFrameActionListener
146 						)
147 
148 DEFINE_XSERVICEINFO_MULTISERVICE( PopupMenuDispatcher                    ,
149                                   ::cppu::OWeakObject                    ,
150                                   SERVICENAME_PROTOCOLHANDLER            ,
151                                   IMPLEMENTATIONNAME_POPUPMENUDISPATCHER )
152 
153 DEFINE_INIT_SERVICE(PopupMenuDispatcher,
154 {
155     /*Attention
156     I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
157     to create a new instance of this class by our own supported service factory.
158     see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
159     */
160 }
161 )
162 
163 //*****************************************************************************************************************
164 //	XInitialization
165 //*****************************************************************************************************************
166 void SAL_CALL PopupMenuDispatcher::initialize(
167     const css::uno::Sequence< css::uno::Any >& lArguments )
168 throw( css::uno::Exception, css::uno::RuntimeException)
169 {
170     css::uno::Reference< css::frame::XFrame > xFrame;
171 
172     /* SAFE { */
173     WriteGuard aWriteLock(m_aLock);
174 
175     for (int a=0; a<lArguments.getLength(); ++a)
176     {
177         if (a==0)
178         {
179             lArguments[a] >>= xFrame;
180             m_xWeakFrame = xFrame;
181 
182 	        m_bActivateListener = sal_True;
183             uno::Reference< css::frame::XFrameActionListener > xFrameActionListener(
184                 (OWeakObject *)this, css::uno::UNO_QUERY );
185             xFrame->addFrameActionListener( xFrameActionListener );
186         }
187     }
188 
189     aWriteLock.unlock();
190     /* } SAFE */
191 }
192 
193 //*****************************************************************************************************************
194 //	XDispatchProvider
195 //*****************************************************************************************************************
196 css::uno::Reference< css::frame::XDispatch >
197 SAL_CALL PopupMenuDispatcher::queryDispatch(
198     const css::util::URL&  rURL    ,
199     const ::rtl::OUString& sTarget ,
200     sal_Int32              nFlags  )
201 throw( css::uno::RuntimeException )
202 {
203     css::uno::Reference< css::frame::XDispatch > xDispatch;
204 
205     if ( rURL.Complete.compareToAscii( PROTOCOL_VALUE, PROTOCOL_LENGTH ) == 0 )
206     {
207         // --- SAFE ---
208 	    ResetableGuard aGuard( m_aLock );
209         impl_RetrievePopupControllerQuery();
210         impl_CreateUriRefFactory();
211 
212         css::uno::Reference< css::container::XNameAccess > xPopupCtrlQuery( m_xPopupCtrlQuery );
213         css::uno::Reference< css::uri::XUriReferenceFactory > xUriRefFactory( m_xUriRefFactory );
214         aGuard.unlock();
215         // --- SAFE ---
216 
217         if ( xPopupCtrlQuery.is() )
218         {
219             try
220             {
221                 // Just use the main part of the URL for popup menu controllers
222                 sal_Int32     nQueryPart( 0 );
223                 sal_Int32     nSchemePart( 0 );
224                 rtl::OUString aBaseURL( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.popup:" ));
225                 rtl::OUString aURL( rURL.Complete );
226 
227                 nSchemePart = aURL.indexOf( ':' );
228                 if (( nSchemePart > 0 ) &&
229                     ( aURL.getLength() > ( nSchemePart+1 )))
230                 {
231                     nQueryPart  = aURL.indexOf( '?', nSchemePart );
232                     if ( nQueryPart > 0 )
233                         aBaseURL += aURL.copy( nSchemePart+1, nQueryPart-(nSchemePart+1) );
234                     else if ( nQueryPart == -1 )
235                         aBaseURL += aURL.copy( nSchemePart+1 );
236                 }
237 
238                 css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider;
239 
240                 // Find popup menu controller using the base URL
241                 xPopupCtrlQuery->getByName( aBaseURL ) >>= xDispatchProvider;
242                 aGuard.unlock();
243 
244                 // Ask popup menu dispatch provider for dispatch object
245                 if ( xDispatchProvider.is() )
246                     xDispatch = xDispatchProvider->queryDispatch( rURL, sTarget, nFlags );
247             }
248             catch ( RuntimeException& )
249             {
250                 throw;
251             }
252             catch ( Exception& )
253             {
254             }
255         }
256     }
257     return xDispatch;
258 }
259 
260 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL
261 PopupMenuDispatcher::queryDispatches(
262     const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor )
263 throw( css::uno::RuntimeException )
264 {
265     sal_Int32 nCount = lDescriptor.getLength();
266     css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount );
267     for( sal_Int32 i=0; i<nCount; ++i )
268     {
269         lDispatcher[i] = this->queryDispatch(
270                             lDescriptor[i].FeatureURL,
271                             lDescriptor[i].FrameName,
272                             lDescriptor[i].SearchFlags);
273     }
274     return lDispatcher;
275 }
276 
277 //*****************************************************************************************************************
278 //	XDispatch
279 //*****************************************************************************************************************
280 void
281 SAL_CALL PopupMenuDispatcher::dispatch(
282     const URL&                        /*aURL*/            ,
283 	const Sequence< PropertyValue >&  /*seqProperties*/	)
284 throw( RuntimeException )
285 {
286 }
287 
288 //*****************************************************************************************************************
289 //	XDispatch
290 //*****************************************************************************************************************
291 void
292 SAL_CALL PopupMenuDispatcher::addStatusListener(
293     const uno::Reference< XStatusListener >& xControl,
294 	const URL&							aURL	)
295 throw( RuntimeException )
296 {
297 	// Ready for multithreading
298 	ResetableGuard aGuard( m_aLock );
299 	// Safe impossible cases
300 	// Add listener to container.
301 	m_aListenerContainer.addInterface( aURL.Complete, xControl );
302 }
303 
304 //*****************************************************************************************************************
305 //	XDispatch
306 //*****************************************************************************************************************
307 void
308 SAL_CALL PopupMenuDispatcher::removeStatusListener(
309     const uno::Reference< XStatusListener >& xControl,
310 	const URL&							aURL	)
311 throw( RuntimeException )
312 {
313 	// Ready for multithreading
314 	ResetableGuard aGuard( m_aLock );
315 	// Safe impossible cases
316 	// Add listener to container.
317 	m_aListenerContainer.removeInterface( aURL.Complete, xControl );
318 }
319 
320 //*****************************************************************************************************************
321 //	 XFrameActionListener
322 //*****************************************************************************************************************
323 
324 void
325 SAL_CALL PopupMenuDispatcher::frameAction(
326     const FrameActionEvent& aEvent )
327 throw ( RuntimeException )
328 {
329 	ResetableGuard aGuard( m_aLock );
330 
331 	if (( aEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING ) ||
332         ( aEvent.Action == css::frame::FrameAction_COMPONENT_ATTACHED  ))
333 	{
334         // Reset query reference to requery it again next time
335         m_xPopupCtrlQuery.clear();
336 	}
337 }
338 
339 //*****************************************************************************************************************
340 //	 XEventListener
341 //*****************************************************************************************************************
342 void
343 SAL_CALL PopupMenuDispatcher::disposing( const EventObject& ) throw( RuntimeException )
344 {
345 	// Ready for multithreading
346 	ResetableGuard aGuard( m_aLock );
347 	// Safe impossible cases
348     LOG_ASSERT( !(m_bAlreadyDisposed==sal_True), "MenuDispatcher::disposing()\nObject already disposed .. don't call it again!\n" )
349 
350 	if( m_bAlreadyDisposed == sal_False )
351 	{
352 		m_bAlreadyDisposed = sal_True;
353 
354 		if ( m_bActivateListener )
355 		{
356 			uno::Reference< XFrame > xFrame( m_xWeakFrame.get(), UNO_QUERY );
357 			if ( xFrame.is() )
358 			{
359 				xFrame->removeFrameActionListener( uno::Reference< XFrameActionListener >( (OWeakObject *)this, UNO_QUERY ));
360 				m_bActivateListener = sal_False;
361 			}
362 		}
363 
364 		// Forget our factory.
365 		m_xFactory = uno::Reference< XMultiServiceFactory >();
366 	}
367 }
368 
369 void PopupMenuDispatcher::impl_RetrievePopupControllerQuery()
370 {
371     if ( !m_xPopupCtrlQuery.is() )
372     {
373         css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
374         css::uno::Reference< css::frame::XFrame > xFrame( m_xWeakFrame );
375 
376         if ( xFrame.is() )
377         {
378             css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, css::uno::UNO_QUERY );
379             if ( xPropSet.is() )
380             {
381                 try
382                 {
383                     xPropSet->getPropertyValue( FRAME_PROPNAME_LAYOUTMANAGER ) >>= xLayoutManager;
384 
385                     if ( xLayoutManager.is() )
386                     {
387                         css::uno::Reference< css::ui::XUIElement > xMenuBar;
388                         rtl::OUString aMenuBar( RTL_CONSTASCII_USTRINGPARAM( "private:resource/menubar/menubar" ));
389                         xMenuBar = xLayoutManager->getElement( aMenuBar );
390 
391                         m_xPopupCtrlQuery = css::uno::Reference< css::container::XNameAccess >(
392                                                 xMenuBar, css::uno::UNO_QUERY );
393                     }
394                 }
395                 catch ( css::uno::RuntimeException& )
396                 {
397                     throw;
398                 }
399                 catch ( css::uno::Exception& )
400                 {
401                 }
402             }
403         }
404     }
405 }
406 
407 void PopupMenuDispatcher::impl_CreateUriRefFactory()
408 {
409     if ( !m_xUriRefFactory.is() )
410     {
411         rtl::OUString aUriRefFactoryService(
412             RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.uri.UriReferenceFactory" ));
413 
414         m_xUriRefFactory = css::uno::Reference< css::uri::XUriReferenceFactory >(
415                                 m_xFactory->createInstance( aUriRefFactoryService ),
416                                 css::uno::UNO_QUERY);
417 
418     }
419 }
420 
421 }		//	namespace framework
422