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