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 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