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 #include <dispatch/menudispatcher.hxx>
35 #include <general.h>
36 #include <framework/menuconfiguration.hxx>
37 #include <framework/addonmenu.hxx>
38 #include <services.h>
39 
40 //_________________________________________________________________________________________________________________
41 //	interface includes
42 //_________________________________________________________________________________________________________________
43 #include <com/sun/star/frame/FrameSearchFlag.hpp>
44 #include <com/sun/star/awt/XToolkit.hpp>
45 #include <com/sun/star/awt/WindowAttribute.hpp>
46 #include <com/sun/star/awt/WindowDescriptor.hpp>
47 #include <com/sun/star/awt/PosSize.hpp>
48 #include <com/sun/star/awt/XWindowPeer.hpp>
49 #include <com/sun/star/beans/UnknownPropertyException.hpp>
50 #include <com/sun/star/lang/WrappedTargetException.hpp>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/container/XEnumeration.hpp>
53 #include <com/sun/star/util/XURLTransformer.hpp>
54 
55 #include <vcl/window.hxx>
56 #include <vcl/syswin.hxx>
57 #include <vcl/menu.hxx>
58 #include <vcl/svapp.hxx>
59 #include <tools/resmgr.hxx>
60 #include <tools/rcid.h>
61 #include <vos/mutex.hxx>
62 #include <toolkit/helper/vclunohelper.hxx>
63 #include <rtl/logfile.hxx>
64 
65 //_________________________________________________________________________________________________________________
66 //	includes of other projects
67 //_________________________________________________________________________________________________________________
68 
69 #include <ucbhelper/content.hxx>
70 
71 //_________________________________________________________________________________________________________________
72 //	namespace
73 //_________________________________________________________________________________________________________________
74 
75 namespace framework{
76 
77 using namespace ::com::sun::star                ;
78 using namespace ::com::sun::star::awt			;
79 using namespace ::com::sun::star::beans			;
80 using namespace ::com::sun::star::container		;
81 using namespace ::com::sun::star::frame			;
82 using namespace ::com::sun::star::lang			;
83 using namespace ::com::sun::star::uno			;
84 using namespace ::com::sun::star::util			;
85 using namespace ::cppu							;
86 using namespace ::osl							;
87 using namespace ::rtl							;
88 using namespace ::vos							;
89 
90 //_________________________________________________________________________________________________________________
91 //	non exported const
92 //_________________________________________________________________________________________________________________
93 
94 const sal_uInt16 SLOTID_MDIWINDOWLIST = 5610;
95 
96 //_________________________________________________________________________________________________________________
97 //	non exported definitions
98 //_________________________________________________________________________________________________________________
99 
100 //_________________________________________________________________________________________________________________
101 //	declarations
102 //_________________________________________________________________________________________________________________
103 
104 //*****************************************************************************************************************
105 //	constructor
106 //*****************************************************************************************************************
107 MenuDispatcher::MenuDispatcher(   const   uno::Reference< XMultiServiceFactory >&  xFactory    ,
108 									const	uno::Reference< XFrame >&				xOwner		)
109 		//	Init baseclasses first
110         :   ThreadHelpBase          ( &Application::GetSolarMutex()  )
111         ,   OWeakObject             (                                )
112         // Init member
113         ,   m_xOwnerWeak            ( xOwner                         )
114         ,   m_xFactory              ( xFactory                       )
115         ,   m_aListenerContainer    ( m_aLock.getShareableOslMutex() )
116         ,   m_bAlreadyDisposed      ( sal_False                      )
117         ,   m_bActivateListener     ( sal_False                      )
118         ,   m_pMenuManager          ( NULL                           )
119 {
120 	// Safe impossible cases
121 	// We need valid informations about ouer ownerfor work.
122     LOG_ASSERT( impldbg_checkParameter_MenuDispatcher( xFactory, xOwner ), "MenuDispatcher::MenuDispatcher()\nInvalid parameter detected!\n" )
123 
124 	m_bActivateListener = sal_True;
125 	xOwner->addFrameActionListener( uno::Reference< XFrameActionListener >( (OWeakObject *)this, UNO_QUERY ));
126 }
127 
128 //*****************************************************************************************************************
129 //	destructor
130 //*****************************************************************************************************************
131 MenuDispatcher::~MenuDispatcher()
132 {
133 	// Warn programmer if he forgot to dispose this instance.
134 	// We must release all our references ...
135 	// and a dtor isn't the best place to do that!
136 }
137 
138 //*****************************************************************************************************************
139 //	XInterface, XTypeProvider
140 //*****************************************************************************************************************
141 DEFINE_XINTERFACE_4     (   MenuDispatcher                     ,
142 							OWeakObject					  		,
143 							DIRECT_INTERFACE(	XTypeProvider	),
144 							DIRECT_INTERFACE(	XDispatch		),
145 							DIRECT_INTERFACE(	XEventListener	),
146 							DERIVED_INTERFACE(	XFrameActionListener, XEventListener )
147 						)
148 
149 DEFINE_XTYPEPROVIDER_4  (   MenuDispatcher     ,
150 							XTypeProvider		,
151 							XDispatch			,
152 							XEventListener		,
153 							XFrameActionListener
154 						)
155 
156 
157 //*****************************************************************************************************************
158 //	XDispatch
159 //*****************************************************************************************************************
160 void SAL_CALL MenuDispatcher::dispatch(    const   URL&                        /*aURL*/            ,
161 											const	Sequence< PropertyValue >&	/*seqProperties*/	) throw( RuntimeException )
162 {
163 }
164 
165 //*****************************************************************************************************************
166 //	XDispatch
167 //*****************************************************************************************************************
168 void SAL_CALL MenuDispatcher::addStatusListener(   const   uno::Reference< XStatusListener >&   xControl,
169 													const	URL&							aURL	) throw( RuntimeException )
170 {
171 	// Ready for multithreading
172 	ResetableGuard aGuard( m_aLock );
173 	// Safe impossible cases
174 	// Method not defined for all incoming parameter
175     LOG_ASSERT( impldbg_checkParameter_addStatusListener( xControl, aURL ), "MenuDispatcher::addStatusListener()\nInvalid parameter detected.\n" )
176 	// Add listener to container.
177 	m_aListenerContainer.addInterface( aURL.Complete, xControl );
178 }
179 
180 //*****************************************************************************************************************
181 //	XDispatch
182 //*****************************************************************************************************************
183 void SAL_CALL MenuDispatcher::removeStatusListener(    const   uno::Reference< XStatusListener >&   xControl,
184 														const	URL&							aURL	) throw( RuntimeException )
185 {
186 	// Ready for multithreading
187 	ResetableGuard aGuard( m_aLock );
188 	// Safe impossible cases
189 	// Method not defined for all incoming parameter
190     LOG_ASSERT( impldbg_checkParameter_removeStatusListener( xControl, aURL ), "MenuDispatcher::removeStatusListener()\nInvalid parameter detected.\n" )
191 	// Add listener to container.
192 	m_aListenerContainer.removeInterface( aURL.Complete, xControl );
193 }
194 
195 //*****************************************************************************************************************
196 //	 XFrameActionListener
197 //*****************************************************************************************************************
198 
199 void SAL_CALL MenuDispatcher::frameAction( const FrameActionEvent& aEvent ) throw ( RuntimeException )
200 {
201 	ResetableGuard aGuard( m_aLock );
202 
203 	if ( m_pMenuManager && aEvent.Action == FrameAction_FRAME_UI_ACTIVATED )
204 	{
205 		MenuBar* pMenuBar = (MenuBar *)m_pMenuManager->GetMenu();
206 		uno::Reference< XFrame > xFrame( m_xOwnerWeak.get(), UNO_QUERY );
207 		aGuard.unlock();
208 
209 		if ( xFrame.is() && pMenuBar )
210 		{
211 			uno::Reference< ::com::sun::star::awt::XWindow >xContainerWindow = xFrame->getContainerWindow();
212 
213 			OGuard aSolarGuard( Application::GetSolarMutex() );
214 			{
215 				Window* pWindow = VCLUnoHelper::GetWindow( xContainerWindow );
216 				while ( pWindow && !pWindow->IsSystemWindow() )
217 					pWindow = pWindow->GetParent();
218 
219 				if ( pWindow )
220 				{
221 					SystemWindow* pSysWindow = (SystemWindow *)pWindow;
222 					pSysWindow->SetMenuBar( pMenuBar );
223 				}
224 			}
225 		}
226 	}
227 	else if ( m_pMenuManager && aEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING )
228 	{
229 		if ( m_pMenuManager )
230 			impl_setMenuBar( NULL );
231 	}
232 }
233 
234 //*****************************************************************************************************************
235 //	 XEventListener
236 //*****************************************************************************************************************
237 void SAL_CALL MenuDispatcher::disposing( const EventObject& ) throw( RuntimeException )
238 {
239 	// Ready for multithreading
240 	ResetableGuard aGuard( m_aLock );
241 	// Safe impossible cases
242     LOG_ASSERT( !(m_bAlreadyDisposed==sal_True), "MenuDispatcher::disposing()\nObject already disposed .. don't call it again!\n" )
243 
244 	if( m_bAlreadyDisposed == sal_False )
245 	{
246 		m_bAlreadyDisposed = sal_True;
247 
248 		if ( m_bActivateListener )
249 		{
250 			uno::Reference< XFrame > xFrame( m_xOwnerWeak.get(), UNO_QUERY );
251 			if ( xFrame.is() )
252 			{
253 				xFrame->removeFrameActionListener( uno::Reference< XFrameActionListener >( (OWeakObject *)this, UNO_QUERY ));
254 				m_bActivateListener = sal_False;
255 				if ( m_pMenuManager )
256 				{
257 					EventObject aEventObj;
258 					aEventObj.Source = xFrame;
259 					m_pMenuManager->disposing( aEventObj );
260 				}
261 			}
262 		}
263 
264 		// Forget our factory.
265 		m_xFactory = uno::Reference< XMultiServiceFactory >();
266 
267 		// Remove our menu from system window if it is still there!
268 		if ( m_pMenuManager )
269 			impl_setMenuBar( NULL );
270 	}
271 }
272 
273 //*****************************************************************************************************************
274 //	private method
275 //
276 //
277 //*****************************************************************************************************************
278 void MenuDispatcher::impl_setAccelerators( Menu* pMenu, const Accelerator& aAccel )
279 {
280 	for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); ++nPos )
281 	{
282 		sal_uInt16     nId    = pMenu->GetItemId(nPos);
283         PopupMenu* pPopup = pMenu->GetPopupMenu(nId);
284         if ( pPopup )
285             impl_setAccelerators( (Menu *)pPopup, aAccel );
286         else if ( nId && !pMenu->GetPopupMenu(nId))
287 		{
288 			KeyCode aCode = aAccel.GetKeyCode( nId );
289 			if ( aCode.GetCode() )
290 			    pMenu->SetAccelKey( nId, aCode );
291 		}
292 	}
293 }
294 
295 //*****************************************************************************************************************
296 //	private method
297 //
298 //
299 //*****************************************************************************************************************
300 sal_Bool MenuDispatcher::impl_setMenuBar( MenuBar* pMenuBar, sal_Bool bMenuFromResource )
301 {
302 	uno::Reference< XFrame > xFrame( m_xOwnerWeak.get(), UNO_QUERY );
303 	if ( xFrame.is() )
304 	{
305 		uno::Reference< ::com::sun::star::awt::XWindow >xContainerWindow = xFrame->getContainerWindow();
306 		Window* pWindow = NULL;
307 
308 		// Use SolarMutex for threadsafe code too!
309 		OGuard aSolarGuard( Application::GetSolarMutex() );
310 		{
311 			pWindow = VCLUnoHelper::GetWindow( xContainerWindow );
312 			while ( pWindow && !pWindow->IsSystemWindow() )
313 				pWindow = pWindow->GetParent();
314 		}
315 
316 		if ( pWindow )
317 		{
318 			// Ready for multithreading
319 			ResetableGuard aGuard( m_aLock );
320 
321 			SystemWindow* pSysWindow = (SystemWindow *)pWindow;
322 
323 			if ( m_pMenuManager )
324 			{
325                 // remove old menu from our system window if it was set before
326                 if ( m_pMenuManager->GetMenu() == (Menu *)pSysWindow->GetMenuBar() )
327                     pSysWindow->SetMenuBar( NULL );
328 
329                 // remove listener before we destruct ourself, so we cannot be called back afterwards
330                 m_pMenuManager->RemoveListener();
331 
332                 SAL_STATIC_CAST( ::com::sun::star::uno::XInterface*, (OWeakObject*)m_pMenuManager )->release();
333 
334 				m_pMenuManager = 0;
335 			}
336 
337 			if ( pMenuBar != NULL )
338 			{
339                 sal_uInt16 nPos = pMenuBar->GetItemPos( SLOTID_MDIWINDOWLIST );
340                 if ( nPos != MENU_ITEM_NOTFOUND )
341                 {
342                     OUString aNoContext;
343 
344                     uno::Reference< XModel >			xModel;
345                     uno::Reference< XController >	xController( xFrame->getController(), UNO_QUERY );
346 
347                     if ( xController.is() )
348                         xModel = uno::Reference< XModel >( xController->getModel(), UNO_QUERY );
349 
350                     // retrieve addon popup menus and add them to our menu bar
351                     AddonMenuManager::MergeAddonPopupMenus( xFrame, xModel, nPos, pMenuBar );
352 
353                     // retrieve addon help menu items and add them to our help menu
354                     AddonMenuManager::MergeAddonHelpMenu( xFrame, pMenuBar );
355                 }
356 
357                 // set new menu on our system window and create new menu manager
358                 if ( bMenuFromResource )
359                 {
360                     // #110897#
361                     // m_pMenuManager = new MenuManager( xFrame, pMenuBar, sal_True, sal_False );
362                     m_pMenuManager = new MenuManager( m_xFactory, xFrame, pMenuBar, sal_True, sal_False );
363                 }
364                 else
365                 {
366                     // #110897#
367                     // m_pMenuManager = new MenuManager( xFrame, pMenuBar, sal_True, sal_True );
368                     m_pMenuManager = new MenuManager( m_xFactory, xFrame, pMenuBar, sal_True, sal_True );
369                 }
370 
371                 pSysWindow->SetMenuBar( pMenuBar );
372 			}
373 
374 			return sal_True;
375 		}
376 	}
377 
378 	return sal_False;
379 }
380 
381 IMPL_LINK( MenuDispatcher, Close_Impl, void*, EMPTYARG )
382 {
383 	css::uno::Reference < css::frame::XFrame > xFrame( m_xOwnerWeak.get(), css::uno::UNO_QUERY );
384 	if ( !xFrame.is() )
385 		return 0;
386 
387 	css::util::URL aURL;
388 	aURL.Complete = ::rtl::OUString::createFromAscii(".uno:CloseWin");
389 	css::uno::Reference< css::util::XURLTransformer >  xTrans ( m_xFactory->createInstance(
390 						SERVICENAME_URLTRANSFORMER ), css::uno::UNO_QUERY );
391 	if( xTrans.is() )
392 	{
393 		// Datei laden
394 		xTrans->parseStrict( aURL );
395 		uno::Reference< XDispatchProvider > xProv( xFrame, UNO_QUERY );
396 		if ( xProv.is() )
397 		{
398 			css::uno::Reference < css::frame::XDispatch > aDisp = xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
399 			if ( aDisp.is() )
400 				aDisp->dispatch( aURL, css::uno::Sequence < css::beans::PropertyValue>() );
401 		}
402 	}
403 
404 	return 0;
405 }
406 
407 
408 //_________________________________________________________________________________________________________________
409 //	debug methods
410 //_________________________________________________________________________________________________________________
411 
412 /*-----------------------------------------------------------------------------------------------------------------
413 	The follow methods checks the parameter for other functions. If a parameter or his value is non valid,
414 	we return "sal_False". (else sal_True) This mechanism is used to throw an ASSERT!
415 
416 	ATTENTION
417 
418 		If you miss a test for one of this parameters, contact the autor or add it himself !(?)
419 		But ... look for right testing! See using of this methods!
420 -----------------------------------------------------------------------------------------------------------------*/
421 
422 #ifdef ENABLE_ASSERTIONS
423 
424 //*****************************************************************************************************************
425 sal_Bool MenuDispatcher::impldbg_checkParameter_MenuDispatcher(   const   uno::Reference< XMultiServiceFactory >&  xFactory    ,
426 																		const	uno::Reference< XFrame >&				xOwner		)
427 {
428 	// Set default return value.
429 	sal_Bool bOK = sal_True;
430 	// Check parameter.
431 	if	(
432 			( &xFactory		==	NULL		)	||
433 			( &xOwner		==	NULL		)	||
434 			( xFactory.is()	==	sal_False	)	||
435 			( xOwner.is()	==	sal_False	)
436 		)
437 	{
438 		bOK = sal_False ;
439 	}
440 	// Return result of check.
441 	return bOK ;
442 }
443 
444 //*****************************************************************************************************************
445 // We need a valid URL. What is meaning with "register for nothing"?!
446 // xControl must correct to - nobody can advised otherwise!
447 sal_Bool MenuDispatcher::impldbg_checkParameter_addStatusListener( const   uno::Reference< XStatusListener >&   xControl,
448 																		const	URL&							aURL	)
449 {
450 	// Set default return value.
451 	sal_Bool bOK = sal_True;
452 	// Check parameter.
453 	if	(
454 			( &xControl					==	NULL	)	||
455 			( &aURL						==	NULL	)	||
456 			( aURL.Complete.getLength()	<	1		)
457 		)
458 	{
459 		bOK = sal_False ;
460 	}
461 	// Return result of check.
462 	return bOK ;
463 }
464 
465 //*****************************************************************************************************************
466 // The same goes for these case! We have added valid listener for correct URL only.
467 // We can't remove invalid listener for nothing!
468 sal_Bool MenuDispatcher::impldbg_checkParameter_removeStatusListener(  const   uno::Reference< XStatusListener >&   xControl,
469 																			const	URL&							aURL	)
470 {
471 	// Set default return value.
472 	sal_Bool bOK = sal_True;
473 	// Check parameter.
474 	if	(
475 			( &xControl					==	NULL	)	||
476 			( &aURL						==	NULL	)	||
477 			( aURL.Complete.getLength()	<	1		)
478 		)
479 	{
480 		bOK = sal_False ;
481 	}
482 	// Return result of check.
483 	return bOK ;
484 }
485 
486 #endif	//	#ifdef ENABLE_ASSERTIONS
487 
488 }		//	namespace framework
489