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 #include "controllerframe.hxx"
29 #include "IController.hxx"
30 
31 /** === begin UNO includes === **/
32 #include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
33 #include <com/sun/star/awt/XTopWindow.hpp>
34 #include <com/sun/star/awt/XWindow2.hpp>
35 #include <com/sun/star/lang/DisposedException.hpp>
36 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
37 #include <com/sun/star/frame/XController2.hpp>
38 /** === end UNO includes === **/
39 
40 #include <cppuhelper/implbase1.hxx>
41 #include <rtl/ref.hxx>
42 #include <sfx2/objsh.hxx>
43 #include <tools/diagnose_ex.h>
44 #include <toolkit/helper/vclunohelper.hxx>
45 #include <vcl/window.hxx>
46 
47 //........................................................................
48 namespace dbaui
49 {
50 //........................................................................
51 
52 	/** === begin UNO using === **/
53 	using ::com::sun::star::uno::Reference;
54 	using ::com::sun::star::uno::XInterface;
55 	using ::com::sun::star::uno::UNO_QUERY;
56 	using ::com::sun::star::uno::UNO_QUERY_THROW;
57 	using ::com::sun::star::uno::UNO_SET_THROW;
58 	using ::com::sun::star::uno::Exception;
59 	using ::com::sun::star::uno::RuntimeException;
60 	using ::com::sun::star::uno::Any;
61 	using ::com::sun::star::uno::makeAny;
62     using ::com::sun::star::frame::XFrame;
63     using ::com::sun::star::frame::FrameAction;
64     using ::com::sun::star::frame::FrameAction_FRAME_ACTIVATED;
65     using ::com::sun::star::frame::FrameAction_FRAME_UI_ACTIVATED;
66     using ::com::sun::star::frame::FrameAction_FRAME_DEACTIVATING;
67     using ::com::sun::star::frame::FrameAction_FRAME_UI_DEACTIVATING;
68     using ::com::sun::star::frame::XModel;
69     using ::com::sun::star::frame::XController;
70     using ::com::sun::star::frame::XController2;
71     using ::com::sun::star::frame::XFramesSupplier;
72     using ::com::sun::star::sdb::XOfficeDatabaseDocument;
73     using ::com::sun::star::awt::XTopWindow;
74     using ::com::sun::star::awt::XTopWindowListener;
75     using ::com::sun::star::awt::XWindow2;
76     using ::com::sun::star::lang::DisposedException;
77     using ::com::sun::star::lang::EventObject;
78     using ::com::sun::star::document::XDocumentEventBroadcaster;
79     using ::com::sun::star::awt::XWindow;
80 	/** === end UNO using === **/
81 
82 	//====================================================================
83 	//= FrameWindowActivationListener
84 	//====================================================================
85     typedef ::cppu::WeakImplHelper1 <   XTopWindowListener
86                                     >   FrameWindowActivationListener_Base;
87     class FrameWindowActivationListener : public FrameWindowActivationListener_Base
88     {
89     public:
90         FrameWindowActivationListener( ControllerFrame_Data& _rData );
91 
92         void dispose();
93 
94     protected:
95         ~FrameWindowActivationListener();
96 
97         // XTopWindowListener
98         virtual void SAL_CALL windowOpened( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException);
99         virtual void SAL_CALL windowClosing( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException);
100         virtual void SAL_CALL windowClosed( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException);
101         virtual void SAL_CALL windowMinimized( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException);
102         virtual void SAL_CALL windowNormalized( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException);
103         virtual void SAL_CALL windowActivated( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException);
104         virtual void SAL_CALL windowDeactivated( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException);
105 
106         // XEventListener
107         virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException);
108 
109     private:
110         void impl_checkDisposed_throw() const;
111         void impl_registerOnFrameContainerWindow_nothrow( bool _bRegister );
112 
113     private:
114         ControllerFrame_Data*   m_pData;
115     };
116 
117 	//====================================================================
118 	//= ControllerFrame_Data
119 	//====================================================================
120     struct ControllerFrame_Data
121     {
122         ControllerFrame_Data( IController& _rController )
123             :m_rController( _rController )
124             ,m_xFrame()
125             ,m_xDocEventBroadcaster()
126             ,m_pListener()
127             ,m_bActive( false )
128             ,m_bIsTopLevelDocumentWindow( false )
129         {
130         }
131 
132         IController&                                        m_rController;
133         Reference< XFrame >                                 m_xFrame;
134         Reference< XDocumentEventBroadcaster >              m_xDocEventBroadcaster;
135         ::rtl::Reference< FrameWindowActivationListener >   m_pListener;
136         bool                                                m_bActive;
137         bool                                                m_bIsTopLevelDocumentWindow;
138     };
139 
140 	//====================================================================
141 	//= helper
142 	//====================================================================
143 	//--------------------------------------------------------------------
144     static void lcl_setFrame_nothrow( ControllerFrame_Data& _rData, const Reference< XFrame >& _rxFrame )
145     {
146         // release old listener
147         if ( _rData.m_pListener.get() )
148         {
149             _rData.m_pListener->dispose();
150             _rData.m_pListener = NULL;
151         }
152 
153         // remember new frame
154         _rData.m_xFrame = _rxFrame;
155 
156         // create new listener
157         if ( _rData.m_xFrame.is() )
158             _rData.m_pListener = new FrameWindowActivationListener( _rData );
159 
160         // at this point in time, we can assume the controller also has a model set, if it supports models
161         try
162         {
163             Reference< XController > xController( _rData.m_rController.getXController(), UNO_SET_THROW );
164             Reference< XModel > xModel( xController->getModel() );
165             if ( xModel.is() )
166                 _rData.m_xDocEventBroadcaster.set( xModel, UNO_QUERY );
167         }
168         catch( const Exception& )
169         {
170         	DBG_UNHANDLED_EXCEPTION();
171         }
172     }
173 
174 	//--------------------------------------------------------------------
175     static bool lcl_isActive_nothrow( const Reference< XFrame >& _rxFrame )
176     {
177         bool bIsActive = false;
178         try
179         {
180             if ( _rxFrame.is() )
181             {
182                 Reference< XWindow2 > xWindow( _rxFrame->getContainerWindow(), UNO_QUERY_THROW );
183                 bIsActive = xWindow->isActive();
184             }
185 
186         }
187         catch( const Exception& )
188         {
189         	DBG_UNHANDLED_EXCEPTION();
190         }
191         return bIsActive;
192     }
193 
194 	//--------------------------------------------------------------------
195     /** updates various global and local states with a new active component
196 
197         In particular, the following are updated
198             * the global working document (aka Basic's ThisComponent in the application
199             Basic), with our controller's model, or the controller itself if there is no such
200             model.
201     */
202     static void lcl_updateActiveComponents_nothrow( const ControllerFrame_Data& _rData )
203     {
204         try
205         {
206             Reference< XController > xCompController( _rData.m_rController.getXController() );
207             OSL_ENSURE( xCompController.is(), "lcl_updateActiveComponents_nothrow: can't do anything without a controller!" );
208             if ( !xCompController.is() )
209                 return;
210 
211             if ( _rData.m_bActive && _rData.m_bIsTopLevelDocumentWindow )
212             {
213                 // set the "current component" at the SfxObjectShell
214                 Reference< XModel > xModel( xCompController->getModel() );
215                 Reference< XInterface > xCurrentComponent;
216                 if ( xModel.is() )
217                     xCurrentComponent = xModel;
218                 else
219                     xCurrentComponent = xCompController;
220                 SfxObjectShell::SetCurrentComponent( xCurrentComponent );
221             }
222         }
223         catch( const Exception& )
224         {
225             DBG_UNHANDLED_EXCEPTION();
226         }
227     }
228 
229 	//--------------------------------------------------------------------
230     /** broadcasts the OnFocus resp. OnUnfocus event
231     */
232     static void lcl_notifyFocusChange_nothrow( ControllerFrame_Data& _rData, bool _bActive )
233     {
234         try
235         {
236             if ( _rData.m_xDocEventBroadcaster.is() )
237             {
238                 ::rtl::OUString sEventName( ::rtl::OUString::createFromAscii( _bActive ? "OnFocus" : "OnUnfocus" ) );
239                 Reference< XController2 > xController( _rData.m_rController.getXController(), UNO_QUERY_THROW );
240                 _rData.m_xDocEventBroadcaster->notifyDocumentEvent( sEventName, xController, Any() );
241             }
242         }
243         catch( const Exception& )
244         {
245         	DBG_UNHANDLED_EXCEPTION();
246         }
247     }
248 
249 	//--------------------------------------------------------------------
250     static void lcl_updateActive_nothrow( ControllerFrame_Data& _rData, bool _bActive )
251     {
252         if ( _rData.m_bActive == _bActive )
253             return;
254         _rData.m_bActive = _bActive;
255 
256         lcl_updateActiveComponents_nothrow( _rData );
257         lcl_notifyFocusChange_nothrow( _rData, _bActive );
258     }
259 
260 	//--------------------------------------------------------------------
261     FrameWindowActivationListener::FrameWindowActivationListener( ControllerFrame_Data& _rData )
262         :m_pData( &_rData )
263     {
264         impl_registerOnFrameContainerWindow_nothrow( true );
265     }
266 
267 	//--------------------------------------------------------------------
268     FrameWindowActivationListener::~FrameWindowActivationListener()
269     {
270     }
271 
272 	//--------------------------------------------------------------------
273     void FrameWindowActivationListener::dispose()
274     {
275         impl_registerOnFrameContainerWindow_nothrow( false );
276         m_pData = NULL;
277     }
278 
279 	//--------------------------------------------------------------------
280     void FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow( bool _bRegister )
281     {
282         OSL_ENSURE( m_pData && m_pData->m_xFrame.is(), "FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow: no frame!" );
283         if ( !m_pData || !m_pData->m_xFrame.is() )
284             return;
285 
286         try
287         {
288             void ( SAL_CALL XTopWindow::*pListenerAction )( const Reference< XTopWindowListener >& ) =
289                 _bRegister ? &XTopWindow::addTopWindowListener : &XTopWindow::removeTopWindowListener;
290 
291             const Reference< XWindow > xContainerWindow( m_pData->m_xFrame->getContainerWindow(), UNO_SET_THROW );
292             if ( _bRegister )
293             {
294                 const Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
295                 ENSURE_OR_THROW( pContainerWindow, "no Window implementation for the frame's container window!" );
296 
297                 /*const Window* pContainerParentWindow = pContainerWindow->GetParent();
298                 if ( pContainerParentWindow && ( pContainerParentWindow->GetType() == WINDOW_BORDERWINDOW ) )
299                     pContainerParentWindow = pContainerParentWindow->GetParent();
300                 m_pData->m_bIsTopLevelDocumentWindow = ( pContainerParentWindow == NULL );*/
301 
302                 m_pData->m_bIsTopLevelDocumentWindow = ( pContainerWindow->GetExtendedStyle() & WB_EXT_DOCUMENT ) != 0;
303             }
304 
305             const Reference< XTopWindow > xFrameContainer( xContainerWindow, UNO_QUERY );
306             if ( xFrameContainer.is() )
307                 (xFrameContainer.get()->*pListenerAction)( this );
308         }
309         catch( const Exception& )
310         {
311         	DBG_UNHANDLED_EXCEPTION();
312         }
313     }
314 
315     //--------------------------------------------------------------------
316     void FrameWindowActivationListener::impl_checkDisposed_throw() const
317     {
318         if ( !m_pData )
319             throw DisposedException( ::rtl::OUString(), *const_cast< FrameWindowActivationListener* >( this ) );
320     }
321 
322     //--------------------------------------------------------------------
323     void SAL_CALL FrameWindowActivationListener::windowOpened( const EventObject& /*_rEvent*/ ) throw (RuntimeException)
324     {
325         // not interested in
326     }
327 
328     //--------------------------------------------------------------------
329     void SAL_CALL FrameWindowActivationListener::windowClosing( const EventObject& /*_rEvent*/ ) throw (RuntimeException)
330     {
331         // not interested in
332     }
333 
334     //--------------------------------------------------------------------
335     void SAL_CALL FrameWindowActivationListener::windowClosed( const EventObject& /*_rEvent*/ ) throw (RuntimeException)
336     {
337         // not interested in
338     }
339 
340     //--------------------------------------------------------------------
341     void SAL_CALL FrameWindowActivationListener::windowMinimized( const EventObject& /*_rEvent*/ ) throw (RuntimeException)
342     {
343         // not interested in
344     }
345 
346     //--------------------------------------------------------------------
347     void SAL_CALL FrameWindowActivationListener::windowNormalized( const EventObject& /*_rEvent*/ ) throw (RuntimeException)
348     {
349         // not interested in
350     }
351 
352     //--------------------------------------------------------------------
353     void SAL_CALL FrameWindowActivationListener::windowActivated( const EventObject& /*_rEvent*/ ) throw (RuntimeException)
354     {
355         impl_checkDisposed_throw();
356         lcl_updateActive_nothrow( *m_pData, true );
357     }
358 
359     //--------------------------------------------------------------------
360     void SAL_CALL FrameWindowActivationListener::windowDeactivated( const EventObject& /*_rEvent*/ ) throw (RuntimeException)
361     {
362         impl_checkDisposed_throw();
363         lcl_updateActive_nothrow( *m_pData, false );
364     }
365 
366 	//--------------------------------------------------------------------
367     void SAL_CALL FrameWindowActivationListener::disposing( const EventObject& /*_rEvent*/ ) throw (RuntimeException)
368     {
369         dispose();
370     }
371 
372 	//====================================================================
373 	//= ControllerFrame
374 	//====================================================================
375 	//--------------------------------------------------------------------
376     ControllerFrame::ControllerFrame( IController& _rController )
377         :m_pData( new ControllerFrame_Data( _rController ) )
378     {
379     }
380 
381 	//--------------------------------------------------------------------
382     ControllerFrame::~ControllerFrame()
383     {
384     }
385 
386 	//--------------------------------------------------------------------
387     const Reference< XFrame >& ControllerFrame::attachFrame( const Reference< XFrame >& _rxFrame )
388     {
389         // set new frame, including listener handling
390         lcl_setFrame_nothrow( *m_pData, _rxFrame );
391 
392         // determine whether we're active
393         m_pData->m_bActive = lcl_isActive_nothrow( m_pData->m_xFrame );
394 
395         // update active component
396         if ( m_pData->m_bActive )
397         {
398             lcl_updateActiveComponents_nothrow( *m_pData );
399             lcl_notifyFocusChange_nothrow( *m_pData, true );
400         }
401 
402         return m_pData->m_xFrame;
403     }
404 
405 	//--------------------------------------------------------------------
406     const Reference< XFrame >& ControllerFrame::getFrame() const
407     {
408         return m_pData->m_xFrame;
409     }
410 
411 	//--------------------------------------------------------------------
412     bool ControllerFrame::isActive() const
413     {
414         return m_pData->m_bActive;
415     }
416 
417 	//--------------------------------------------------------------------
418     void ControllerFrame::frameAction( FrameAction _eAction )
419     {
420         bool bActive = m_pData->m_bActive;
421 
422         switch ( _eAction )
423         {
424             case FrameAction_FRAME_ACTIVATED:
425             case FrameAction_FRAME_UI_ACTIVATED:
426                 bActive = true;
427                 break;
428 
429             case FrameAction_FRAME_DEACTIVATING:
430             case FrameAction_FRAME_UI_DEACTIVATING:
431                 bActive = false;
432                 break;
433 
434             default:
435                 break;
436         }
437 
438         lcl_updateActive_nothrow( *m_pData, bActive );
439     }
440 
441 //........................................................................
442 } // namespace dbaui
443 //........................................................................
444