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