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