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