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 :
45 : #include <ucbhelper/content.hxx>
46 :
47 : namespace framework{
48 :
49 : using namespace ::com::sun::star;
50 : using namespace ::com::sun::star::awt;
51 : using namespace ::com::sun::star::beans;
52 : using namespace ::com::sun::star::container;
53 : using namespace ::com::sun::star::frame;
54 : using namespace ::com::sun::star::lang;
55 : using namespace ::com::sun::star::uno;
56 : using namespace ::com::sun::star::util;
57 : using namespace ::cppu;
58 :
59 : const sal_uInt16 SLOTID_MDIWINDOWLIST = 5610;
60 :
61 : static bool impldbg_checkParameter_MenuDispatcher ( const css::uno::Reference< css::uno::XComponentContext >& xContext ,
62 : const css::uno::Reference< css::frame::XFrame >& xOwner );
63 : static bool impldbg_checkParameter_addStatusListener ( const css::uno::Reference< css::frame::XStatusListener >& xControl ,
64 : const css::util::URL& aURL );
65 : static bool impldbg_checkParameter_removeStatusListener ( const css::uno::Reference< css::frame::XStatusListener >& xControl ,
66 : const css::util::URL& aURL );
67 :
68 : // constructor
69 :
70 0 : MenuDispatcher::MenuDispatcher( const uno::Reference< XComponentContext >& xContext ,
71 : const uno::Reference< XFrame >& xOwner )
72 : : m_xOwnerWeak ( xOwner )
73 : , m_xContext ( xContext )
74 : , m_aListenerContainer ( m_mutex )
75 : , m_bAlreadyDisposed ( false )
76 : , m_bActivateListener ( false )
77 0 : , m_pMenuManager ( NULL )
78 : {
79 : // Safe impossible cases
80 : // We need valid information about our owner for work.
81 : SAL_WARN_IF( !impldbg_checkParameter_MenuDispatcher( xContext, xOwner ), "fwk", "MenuDispatcher::MenuDispatcher()\nInvalid parameter detected!" );
82 :
83 0 : m_bActivateListener = true;
84 0 : xOwner->addFrameActionListener( uno::Reference< XFrameActionListener >( (OWeakObject *)this, UNO_QUERY ));
85 0 : }
86 :
87 : // destructor
88 :
89 0 : MenuDispatcher::~MenuDispatcher()
90 : {
91 : // Warn programmer if he forgot to dispose this instance.
92 : // We must release all our references ...
93 : // and a dtor isn't the best place to do that!
94 0 : }
95 :
96 : // XDispatch
97 :
98 0 : void SAL_CALL MenuDispatcher::dispatch( const URL& /*aURL*/ ,
99 : const Sequence< PropertyValue >& /*seqProperties*/ ) throw( RuntimeException, std::exception )
100 : {
101 0 : }
102 :
103 : // XDispatch
104 :
105 0 : void SAL_CALL MenuDispatcher::addStatusListener( const uno::Reference< XStatusListener >& xControl,
106 : const URL& aURL ) throw( RuntimeException, std::exception )
107 : {
108 0 : SolarMutexGuard g;
109 : // Safe impossible cases
110 : // Method not defined for all incoming parameter
111 : SAL_WARN_IF( !impldbg_checkParameter_addStatusListener( xControl, aURL ), "fwk", "MenuDispatcher::addStatusListener(): Invalid parameter detected." );
112 : // Add listener to container.
113 0 : m_aListenerContainer.addInterface( aURL.Complete, xControl );
114 0 : }
115 :
116 : // XDispatch
117 :
118 0 : void SAL_CALL MenuDispatcher::removeStatusListener( const uno::Reference< XStatusListener >& xControl,
119 : const URL& aURL ) throw( RuntimeException, std::exception )
120 : {
121 0 : SolarMutexGuard g;
122 : // Safe impossible cases
123 : // Method not defined for all incoming parameter
124 : SAL_WARN_IF( !impldbg_checkParameter_removeStatusListener( xControl, aURL ), "fwk", "MenuDispatcher::removeStatusListener(): Invalid parameter detected." );
125 : // Add listener to container.
126 0 : m_aListenerContainer.removeInterface( aURL.Complete, xControl );
127 0 : }
128 :
129 : // XFrameActionListener
130 :
131 0 : void SAL_CALL MenuDispatcher::frameAction( const FrameActionEvent& aEvent ) throw ( RuntimeException, std::exception )
132 : {
133 0 : SolarMutexResettableGuard aGuard;
134 :
135 0 : if ( m_pMenuManager && aEvent.Action == FrameAction_FRAME_UI_ACTIVATED )
136 : {
137 0 : MenuBar* pMenuBar = (MenuBar *)m_pMenuManager->GetMenu();
138 0 : uno::Reference< XFrame > xFrame( m_xOwnerWeak.get(), UNO_QUERY );
139 0 : aGuard.clear();
140 :
141 0 : if ( xFrame.is() && pMenuBar )
142 : {
143 0 : uno::Reference< ::com::sun::star::awt::XWindow >xContainerWindow = xFrame->getContainerWindow();
144 :
145 0 : aGuard.reset();
146 : {
147 0 : Window* pWindow = VCLUnoHelper::GetWindow( xContainerWindow );
148 0 : while ( pWindow && !pWindow->IsSystemWindow() )
149 0 : pWindow = pWindow->GetParent();
150 :
151 0 : if ( pWindow )
152 : {
153 0 : SystemWindow* pSysWindow = (SystemWindow *)pWindow;
154 0 : pSysWindow->SetMenuBar( pMenuBar );
155 : }
156 0 : }
157 0 : }
158 : }
159 0 : else if ( m_pMenuManager && aEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING )
160 : {
161 0 : if ( m_pMenuManager )
162 0 : impl_setMenuBar( NULL );
163 0 : }
164 0 : }
165 :
166 : // XEventListener
167 0 : void SAL_CALL MenuDispatcher::disposing( const EventObject& ) throw( RuntimeException, std::exception )
168 : {
169 0 : SolarMutexGuard g;
170 : // Safe impossible cases
171 : SAL_WARN_IF( m_bAlreadyDisposed, "fwk", "MenuDispatcher::disposing(): Object already disposed .. don't call it again!" );
172 :
173 0 : if( m_bAlreadyDisposed == false )
174 : {
175 0 : m_bAlreadyDisposed = true;
176 :
177 0 : if ( m_bActivateListener )
178 : {
179 0 : uno::Reference< XFrame > xFrame( m_xOwnerWeak.get(), UNO_QUERY );
180 0 : if ( xFrame.is() )
181 : {
182 0 : xFrame->removeFrameActionListener( uno::Reference< XFrameActionListener >( (OWeakObject *)this, UNO_QUERY ));
183 0 : m_bActivateListener = false;
184 0 : if ( m_pMenuManager )
185 : {
186 0 : EventObject aEventObj;
187 0 : aEventObj.Source = xFrame;
188 0 : m_pMenuManager->disposing( aEventObj );
189 : }
190 0 : }
191 : }
192 :
193 : // Forget our factory.
194 0 : m_xContext = uno::Reference< XComponentContext >();
195 :
196 : // Remove our menu from system window if it is still there!
197 0 : if ( m_pMenuManager )
198 0 : impl_setMenuBar( NULL );
199 0 : }
200 0 : }
201 :
202 : // private method
203 :
204 0 : void MenuDispatcher::impl_setAccelerators( Menu* pMenu, const Accelerator& aAccel )
205 : {
206 0 : for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); ++nPos )
207 : {
208 0 : sal_uInt16 nId = pMenu->GetItemId(nPos);
209 0 : ::PopupMenu* pPopup = pMenu->GetPopupMenu(nId);
210 0 : if ( pPopup )
211 0 : impl_setAccelerators( (Menu *)pPopup, aAccel );
212 0 : else if ( nId && !pMenu->GetPopupMenu(nId))
213 : {
214 0 : KeyCode aCode = aAccel.GetKeyCode( nId );
215 0 : if ( aCode.GetCode() )
216 0 : pMenu->SetAccelKey( nId, aCode );
217 : }
218 : }
219 0 : }
220 :
221 : // private method
222 :
223 0 : bool MenuDispatcher::impl_setMenuBar( MenuBar* pMenuBar, bool bMenuFromResource )
224 : {
225 0 : uno::Reference< XFrame > xFrame( m_xOwnerWeak.get(), UNO_QUERY );
226 0 : if ( xFrame.is() )
227 : {
228 0 : uno::Reference< ::com::sun::star::awt::XWindow >xContainerWindow = xFrame->getContainerWindow();
229 0 : Window* pWindow = NULL;
230 :
231 0 : SolarMutexGuard aSolarGuard;
232 : {
233 0 : pWindow = VCLUnoHelper::GetWindow( xContainerWindow );
234 0 : while ( pWindow && !pWindow->IsSystemWindow() )
235 0 : pWindow = pWindow->GetParent();
236 : }
237 :
238 0 : if ( pWindow )
239 : {
240 0 : SystemWindow* pSysWindow = (SystemWindow *)pWindow;
241 :
242 0 : if ( m_pMenuManager )
243 : {
244 : // remove old menu from our system window if it was set before
245 0 : if ( m_pMenuManager->GetMenu() == (Menu *)pSysWindow->GetMenuBar() )
246 0 : pSysWindow->SetMenuBar( NULL );
247 :
248 : // remove listener before we destruct ourself, so we cannot be called back afterwards
249 0 : m_pMenuManager->RemoveListener();
250 :
251 0 : (static_cast< ::com::sun::star::uno::XInterface* >((OWeakObject*)m_pMenuManager))->release();
252 :
253 0 : m_pMenuManager = 0;
254 : }
255 :
256 0 : if ( pMenuBar != NULL )
257 : {
258 0 : sal_uInt16 nPos = pMenuBar->GetItemPos( SLOTID_MDIWINDOWLIST );
259 0 : if ( nPos != MENU_ITEM_NOTFOUND )
260 : {
261 0 : uno::Reference< XModel > xModel;
262 0 : uno::Reference< XController > xController( xFrame->getController(), UNO_QUERY );
263 :
264 0 : if ( xController.is() )
265 0 : xModel = uno::Reference< XModel >( xController->getModel(), UNO_QUERY );
266 :
267 : // retrieve addon popup menus and add them to our menu bar
268 0 : AddonMenuManager::MergeAddonPopupMenus( xFrame, xModel, nPos, pMenuBar );
269 :
270 : // retrieve addon help menu items and add them to our help menu
271 0 : AddonMenuManager::MergeAddonHelpMenu( xFrame, pMenuBar );
272 : }
273 :
274 : // set new menu on our system window and create new menu manager
275 0 : if ( bMenuFromResource )
276 : {
277 0 : m_pMenuManager = new MenuManager( m_xContext, xFrame, pMenuBar, true, false );
278 : }
279 : else
280 : {
281 0 : m_pMenuManager = new MenuManager( m_xContext, xFrame, pMenuBar, true, true );
282 : }
283 :
284 0 : pSysWindow->SetMenuBar( pMenuBar );
285 : }
286 :
287 0 : return true;
288 0 : }
289 : }
290 :
291 0 : return false;
292 : }
293 :
294 0 : static bool impldbg_checkParameter_MenuDispatcher( const uno::Reference< XComponentContext >& xContext ,
295 : const uno::Reference< XFrame >& xOwner )
296 : {
297 0 : return xContext.is() && xOwner.is();
298 : }
299 :
300 : // We need a valid URL. What is meaning with "register for nothing"?!
301 : // xControl must correct to - nobody can advised otherwise!
302 0 : static bool impldbg_checkParameter_addStatusListener( const uno::Reference< XStatusListener >& xControl,
303 : const URL& aURL )
304 : {
305 : // Set default return value.
306 0 : bool bOK = true;
307 : // Check parameter.
308 0 : if (
309 0 : ( &xControl == NULL ) ||
310 0 : ( &aURL == NULL ) ||
311 0 : ( aURL.Complete.isEmpty() )
312 : )
313 : {
314 0 : bOK = false;
315 : }
316 : // Return result of check.
317 0 : return bOK;
318 : }
319 :
320 : // The same goes for these case! We have added valid listener for correct URL only.
321 : // We can't remove invalid listener for nothing!
322 0 : static bool impldbg_checkParameter_removeStatusListener( const uno::Reference< XStatusListener >& xControl,
323 : const URL& aURL )
324 : {
325 : // Set default return value.
326 0 : bool bOK = true;
327 : // Check parameter.
328 0 : if (
329 0 : ( &xControl == NULL ) ||
330 0 : ( &aURL == NULL ) ||
331 0 : ( aURL.Complete.isEmpty() )
332 : )
333 : {
334 0 : bOK = false;
335 : }
336 : // Return result of check.
337 0 : return bOK;
338 : }
339 :
340 : } // namespace framework
341 :
342 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|