xref: /trunk/main/framework/source/dispatch/menudispatcher.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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