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