xref: /trunk/main/toolkit/source/controls/accessiblecontrolcontext.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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_toolkit.hxx"
30 #include <toolkit/controls/accessiblecontrolcontext.hxx>
31 #include <unotools/accessiblestatesethelper.hxx>
32 #include <com/sun/star/awt/XControl.hpp>
33 #include <com/sun/star/awt/XWindow.hpp>
34 #include <vcl/svapp.hxx>
35 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
36 #include <com/sun/star/accessibility/AccessibleRole.hpp>
37 #include <toolkit/helper/vclunohelper.hxx>
38 #include <vcl/window.hxx>
39 
40 //........................................................................
41 namespace toolkit
42 {
43 //........................................................................
44 
45     using ::comphelper::OContextEntryGuard;
46     using namespace ::com::sun::star;
47     using namespace ::com::sun::star::uno;
48     using namespace ::com::sun::star::lang;
49     using namespace ::com::sun::star::beans;
50     using namespace ::com::sun::star::accessibility;
51 
52     //====================================================================
53     //= OAccessibleControlContext
54     //====================================================================
55     //--------------------------------------------------------------------
56     OAccessibleControlContext::OAccessibleControlContext()
57         :OAccessibleControlContext_Base( )
58     {
59         // nothing to do here, we have a late ctor
60     }
61 
62     //--------------------------------------------------------------------
63     OAccessibleControlContext::~OAccessibleControlContext()
64     {
65         ensureDisposed();
66     }
67 
68     //--------------------------------------------------------------------
69     IMPLEMENT_FORWARD_XINTERFACE3( OAccessibleControlContext, OAccessibleControlContext_Base, OAccessibleImplementationAccess, OAccessibleControlContext_IBase )
70     IMPLEMENT_FORWARD_XTYPEPROVIDER3( OAccessibleControlContext, OAccessibleControlContext_Base, OAccessibleImplementationAccess, OAccessibleControlContext_IBase )
71         // (order matters: the first is the class name, the second is the class doing the ref counting)
72 
73     //--------------------------------------------------------------------
74     void OAccessibleControlContext::Init( const Reference< XAccessible >& _rxCreator ) SAL_THROW( ( Exception ) )
75     {
76         OContextEntryGuard aGuard( this );
77 
78         // retrieve the model of the control
79         OSL_ENSURE( !m_xControlModel.is(), "OAccessibleControlContext::Init: already know a control model....!???" );
80 
81         Reference< awt::XControl > xControl( _rxCreator, UNO_QUERY );
82         if ( xControl.is() )
83             m_xControlModel = m_xControlModel.query( xControl->getModel() );
84         OSL_ENSURE( m_xControlModel.is(), "OAccessibleControlContext::Init: invalid creator (no control, or control without model!" );
85         if ( !m_xControlModel.is() )
86             throw DisposedException();  // caught by the caller (the create method)
87 
88         // start listening at the model
89         startModelListening();
90 
91         // announce the XAccessible to our base class
92         OAccessibleControlContext_Base::lateInit( _rxCreator );
93     }
94 
95     //--------------------------------------------------------------------
96     OAccessibleControlContext* OAccessibleControlContext::create( const Reference< XAccessible >& _rxCreator ) SAL_THROW( ( ) )
97     {
98         OAccessibleControlContext* pNew = NULL;
99         try
100         {
101             pNew = new OAccessibleControlContext;
102             pNew->Init( _rxCreator );
103         }
104         catch( const Exception& )
105         {
106             OSL_ENSURE( sal_False, "OAccessibleControlContext::create: caught an exception from the late ctor!" );
107         }
108         return pNew;
109     }
110 
111     //--------------------------------------------------------------------
112     void OAccessibleControlContext::startModelListening( ) SAL_THROW( ( Exception ) )
113     {
114         Reference< XComponent > xModelComp( m_xControlModel, UNO_QUERY );
115         OSL_ENSURE( xModelComp.is(), "OAccessibleControlContext::startModelListening: invalid model!" );
116         if ( xModelComp.is() )
117             xModelComp->addEventListener( this );
118     }
119 
120     //--------------------------------------------------------------------
121     void OAccessibleControlContext::stopModelListening( ) SAL_THROW( ( Exception ) )
122     {
123         Reference< XComponent > xModelComp( m_xControlModel, UNO_QUERY );
124         OSL_ENSURE( xModelComp.is(), "OAccessibleControlContext::stopModelListening: invalid model!" );
125         if ( xModelComp.is() )
126             xModelComp->removeEventListener( this );
127     }
128 
129     //--------------------------------------------------------------------
130     sal_Int32 SAL_CALL OAccessibleControlContext::getAccessibleChildCount(  ) throw (RuntimeException)
131     {
132         // we do not have children
133         return 0;
134     }
135 
136     //--------------------------------------------------------------------
137     Reference< XAccessible > SAL_CALL OAccessibleControlContext::getAccessibleChild( sal_Int32 ) throw (IndexOutOfBoundsException, RuntimeException)
138     {
139         // we do not have children
140         throw IndexOutOfBoundsException();
141     }
142 
143     //--------------------------------------------------------------------
144     Reference< XAccessible > SAL_CALL OAccessibleControlContext::getAccessibleParent(  ) throw (RuntimeException)
145     {
146         OContextEntryGuard aGuard( this );
147         OSL_ENSURE( implGetForeignControlledParent().is(), "OAccessibleControlContext::getAccessibleParent: somebody forgot to set a parent!" );
148             // this parent of us is foreign controlled - somebody has to set it using the OAccessibleImplementationAccess
149             // class, before integrating our instance into an AccessibleDocumentModel
150         return implGetForeignControlledParent();
151     }
152 
153     //--------------------------------------------------------------------
154     sal_Int16 SAL_CALL OAccessibleControlContext::getAccessibleRole(  ) throw (RuntimeException)
155     {
156         return AccessibleRole::SHAPE;
157     }
158 
159     //--------------------------------------------------------------------
160     ::rtl::OUString SAL_CALL OAccessibleControlContext::getAccessibleDescription(  ) throw (RuntimeException)
161     {
162         OContextEntryGuard aGuard( this );
163         return getModelStringProperty( "HelpText" );
164     }
165 
166     //--------------------------------------------------------------------
167     ::rtl::OUString SAL_CALL OAccessibleControlContext::getAccessibleName(  ) throw (RuntimeException)
168     {
169         OContextEntryGuard aGuard( this );
170         return getModelStringProperty( "Name" );
171     }
172 
173     //--------------------------------------------------------------------
174     Reference< XAccessibleRelationSet > SAL_CALL OAccessibleControlContext::getAccessibleRelationSet(  ) throw (RuntimeException)
175     {
176         return NULL;
177     }
178 
179     //--------------------------------------------------------------------
180     Reference< XAccessibleStateSet > SAL_CALL OAccessibleControlContext::getAccessibleStateSet(  ) throw (RuntimeException)
181     {
182         ::osl::MutexGuard aGuard( GetMutex() );
183             // no OContextEntryGuard here, as we do not want to throw an exception in case we're not alive anymore
184 
185         ::utl::AccessibleStateSetHelper* pStateSet = NULL;
186         if ( isAlive() )
187         {
188             // no own states, only the ones which are foreign controlled
189             pStateSet = new ::utl::AccessibleStateSetHelper( implGetForeignControlledStates() );
190         }
191         else
192         {   // only the DEFUNC state if we're already disposed
193             pStateSet = new ::utl::AccessibleStateSetHelper;
194             pStateSet->AddState( AccessibleStateType::DEFUNC );
195         }
196         return pStateSet;
197     }
198 
199     //--------------------------------------------------------------------
200     void SAL_CALL OAccessibleControlContext::disposing( const EventObject&
201     #if OSL_DEBUG_LEVEL > 0
202     _rSource
203     #endif
204     ) throw ( RuntimeException )
205     {
206         OSL_ENSURE( Reference< XPropertySet >( _rSource.Source, UNO_QUERY ).get() == m_xControlModel.get(),
207             "OAccessibleControlContext::disposing: where did this come from?" );
208 
209         stopModelListening( );
210         m_xControlModel.clear();
211         m_xModelPropsInfo.clear();
212 
213         OAccessibleControlContext_Base::disposing();
214     }
215 
216     //--------------------------------------------------------------------
217     ::rtl::OUString OAccessibleControlContext::getModelStringProperty( const sal_Char* _pPropertyName )
218     {
219         ::rtl::OUString sReturn;
220         try
221         {
222             if ( !m_xModelPropsInfo.is() && m_xControlModel.is() )
223                 m_xModelPropsInfo = m_xControlModel->getPropertySetInfo();
224 
225             ::rtl::OUString sPropertyName( ::rtl::OUString::createFromAscii( _pPropertyName ) );
226             if ( m_xModelPropsInfo.is() && m_xModelPropsInfo->hasPropertyByName( sPropertyName ) )
227                 m_xControlModel->getPropertyValue( sPropertyName ) >>= sReturn;
228         }
229         catch( const Exception& )
230         {
231             OSL_ENSURE( sal_False, "OAccessibleControlContext::getModelStringProperty: caught an exception!" );
232         }
233         return sReturn;
234     }
235 
236     //--------------------------------------------------------------------
237     Window* OAccessibleControlContext::implGetWindow( Reference< awt::XWindow >* _pxUNOWindow ) const
238     {
239         Reference< awt::XControl > xControl( getAccessibleCreator(), UNO_QUERY );
240         Reference< awt::XWindow > xWindow;
241         if ( xControl.is() )
242             xWindow = xWindow.query( xControl->getPeer() );
243 
244         Window* pWindow = xWindow.is() ? VCLUnoHelper::GetWindow( xWindow ) : NULL;
245 
246         if ( _pxUNOWindow )
247             *_pxUNOWindow = xWindow;
248         return pWindow;
249     }
250 
251     //--------------------------------------------------------------------
252     awt::Rectangle SAL_CALL OAccessibleControlContext::implGetBounds(  ) throw (RuntimeException)
253     {
254         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
255             // want to do some VCL stuff here ...
256         OContextEntryGuard aGuard( this );
257 
258         OSL_ENSURE( sal_False, "OAccessibleControlContext::implGetBounds: performance issue: forced to calc the size myself!" );
259         // In design mode (and this is what this class is for), the surrounding shape (if any) should handle this call
260         // The problem is that in design mode, our size may not be correct (in the drawing layer, controls are
261         // positioned/sized for painting only), and that calculation of our position is expensive
262 
263         // what we know (or can obtain from somewhere):
264         // * the PosSize of our peer, relative to it's parent window
265         // * the parent window which the PosSize is relative to
266         // * our foreign controlled accessible parent
267         // from this info, we can determine the the position of our peer relative to the foreign parent
268 
269         // our control
270         Reference< awt::XWindow > xWindow;
271         Window* pVCLWindow = implGetWindow( &xWindow );
272 
273         awt::Rectangle aBounds( 0, 0, 0, 0 );
274         if ( xWindow.is() )
275         {
276             // ugly, but .... though the XWindow has a getPosSize, it is impossible to determine the
277             // parent which this position/size is relative to. This means we must tunnel UNO and ask the
278             // implementation
279             Window* pVCLParent = pVCLWindow ? pVCLWindow->GetParent() : NULL;
280 
281             // the relative location of the window
282             ::Point aWindowRelativePos( 0, 0);
283             if ( pVCLWindow )
284                 aWindowRelativePos = pVCLWindow->GetPosPixel();
285 
286             // the screnn position of the "window parent" of the control
287             ::Point aVCLParentScreenPos( 0, 0 );
288             if ( pVCLParent )
289                 aVCLParentScreenPos = pVCLParent->GetPosPixel();
290 
291             // the screen position of the "accessible parent" of the control
292             Reference< XAccessible > xParentAcc( implGetForeignControlledParent() );
293             Reference< XAccessibleComponent > xParentAccComponent;
294             if ( xParentAcc.is() )
295                 xParentAccComponent = xParentAccComponent.query( xParentAcc->getAccessibleContext() );
296             awt::Point aAccParentScreenPos( 0, 0 );
297             if ( xParentAccComponent.is() )
298                 aAccParentScreenPos = xParentAccComponent->getLocationOnScreen();
299 
300             // now the size of the control
301             aBounds = xWindow->getPosSize();
302 
303             // correct the pos
304             aBounds.X = aWindowRelativePos.X() + aVCLParentScreenPos.X() - aAccParentScreenPos.X;
305             aBounds.Y = aWindowRelativePos.Y() + aVCLParentScreenPos.Y() - aAccParentScreenPos.Y;
306         }
307 
308         return aBounds;
309     }
310 
311     //--------------------------------------------------------------------
312     Reference< XAccessible > SAL_CALL OAccessibleControlContext::getAccessibleAtPoint( const awt::Point& /* _rPoint */ ) throw (RuntimeException)
313     {
314         // no children at all
315         return NULL;
316     }
317 
318     //--------------------------------------------------------------------
319     void SAL_CALL OAccessibleControlContext::grabFocus(  ) throw (RuntimeException)
320     {
321         OSL_ENSURE( sal_False, "OAccessibleControlContext::grabFocus: !isFocusTraversable, but grabFocus!" );
322     }
323 
324     //--------------------------------------------------------------------
325     Any SAL_CALL OAccessibleControlContext::getAccessibleKeyBinding(  ) throw (RuntimeException)
326     {
327         // we do not have any key bindings to activate a UNO control in design mode
328         return Any();
329     }
330 
331     //--------------------------------------------------------------------
332     sal_Int32 SAL_CALL OAccessibleControlContext::getForeground(  ) throw (::com::sun::star::uno::RuntimeException)
333     {
334         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
335             // want to do some VCL stuff here ...
336         OContextEntryGuard aGuard( this );
337 
338         Window* pWindow = implGetWindow( );
339         sal_Int32 nColor = 0;
340         if ( pWindow )
341         {
342             if ( pWindow->IsControlForeground() )
343                 nColor = pWindow->GetControlForeground().GetColor();
344             else
345             {
346                 Font aFont;
347                 if ( pWindow->IsControlFont() )
348                     aFont = pWindow->GetControlFont();
349                 else
350                     aFont = pWindow->GetFont();
351                 nColor = aFont.GetColor().GetColor();
352             }
353         }
354         return nColor;
355     }
356 
357     //--------------------------------------------------------------------
358     sal_Int32 SAL_CALL OAccessibleControlContext::getBackground(  ) throw (::com::sun::star::uno::RuntimeException)
359     {
360         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
361             // want to do some VCL stuff here ...
362         OContextEntryGuard aGuard( this );
363 
364         Window* pWindow = implGetWindow( );
365         sal_Int32 nColor = 0;
366         if ( pWindow )
367         {
368             if ( pWindow->IsControlBackground() )
369                 nColor = pWindow->GetControlBackground().GetColor();
370             else
371                 nColor = pWindow->GetBackground().GetColor().GetColor();
372         }
373 
374         return nColor;
375     }
376 
377 //........................................................................
378 }   //namespace toolkit
379 //........................................................................
380 
381