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 
31 
32 #include <com/sun/star/accessibility/AccessibleRole.hpp>
33 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
34 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
35 #include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
36 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
37 #include <toolkit/awt/vclxaccessiblecomponent.hxx>
38 #include <toolkit/helper/externallock.hxx>
39 #include <toolkit/awt/vclxwindow.hxx>
40 #include <toolkit/helper/convert.hxx>
41 #include <toolkit/awt/vclxfont.hxx>
42 #include <vcl/dialog.hxx>
43 #include <vcl/window.hxx>
44 #include <tools/debug.hxx>
45 #include <unotools/accessiblestatesethelper.hxx>
46 #include <unotools/accessiblerelationsethelper.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/menu.hxx>
49 
50 #ifndef VCLEVENT_WINDOW_FRAMETITLECHANGED
51 #define VCLEVENT_WINDOW_FRAMETITLECHANGED   1018    // pData = XubString* = oldTitle
52 #endif
53 
54 using namespace ::com::sun::star;
55 using namespace ::comphelper;
56 
57 
58 DBG_NAME(VCLXAccessibleComponent)
59 
60 
61 //	----------------------------------------------------
62 //	class VCLXAccessibleComponent
63 //	----------------------------------------------------
64 VCLXAccessibleComponent::VCLXAccessibleComponent( VCLXWindow* pVCLXindow )
65 	: AccessibleExtendedComponentHelper_BASE( new VCLExternalSolarLock() )
66 	, OAccessibleImplementationAccess( )
67 {
68 	DBG_CTOR( VCLXAccessibleComponent, 0 );
69 	mpVCLXindow = pVCLXindow;
70 	mxWindow = pVCLXindow;
71 
72 	m_pSolarLock = static_cast< VCLExternalSolarLock* >( getExternalLock( ) );
73 
74 	DBG_ASSERT( pVCLXindow->GetWindow(), "VCLXAccessibleComponent - no window!" );
75 	if ( pVCLXindow->GetWindow() )
76     {
77 	  pVCLXindow->GetWindow()->AddEventListener( LINK( this, VCLXAccessibleComponent, WindowEventListener ) );
78 	  pVCLXindow->GetWindow()->AddChildEventListener( LINK( this, VCLXAccessibleComponent, WindowChildEventListener ) );
79     }
80 
81 	// announce the XAccessible of our creator to the base class
82 	lateInit( pVCLXindow );
83 }
84 
85 VCLXAccessibleComponent::~VCLXAccessibleComponent()
86 {
87 	DBG_DTOR( VCLXAccessibleComponent, 0 );
88 
89     ensureDisposed();
90 
91 	if ( mpVCLXindow && mpVCLXindow->GetWindow() )
92     {
93 		mpVCLXindow->GetWindow()->RemoveEventListener( LINK( this, VCLXAccessibleComponent, WindowEventListener ) );
94 		mpVCLXindow->GetWindow()->RemoveChildEventListener( LINK( this, VCLXAccessibleComponent, WindowChildEventListener ) );
95     }
96 
97 	delete m_pSolarLock;
98 	m_pSolarLock = NULL;
99 	// This is not completely safe. If we assume that the base class dtor calls some method which
100 	// uses this lock, the we crash. However, as the base class' dtor does not have a chance to call _out_
101 	// virtual methods, this is no problem as long as the base class is safe, i.e. does not use the external
102 	// lock from within it's dtor. At the moment, we _know_ the base class is safe in this respect, so
103 	// let's assume it keeps this way.
104 	// @see OAccessibleContextHelper::OAccessibleContextHelper( IMutex* )
105 }
106 
107 IMPLEMENT_FORWARD_XINTERFACE3( VCLXAccessibleComponent, AccessibleExtendedComponentHelper_BASE, OAccessibleImplementationAccess, VCLXAccessibleComponent_BASE )
108 IMPLEMENT_FORWARD_XTYPEPROVIDER3( VCLXAccessibleComponent, AccessibleExtendedComponentHelper_BASE, OAccessibleImplementationAccess, VCLXAccessibleComponent_BASE )
109 
110 ::rtl::OUString VCLXAccessibleComponent::getImplementationName() throw (uno::RuntimeException)
111 {
112 	return ::rtl::OUString::createFromAscii( "com.sun.star.comp.toolkit.AccessibleWindow" );
113 }
114 
115 sal_Bool VCLXAccessibleComponent::supportsService( const ::rtl::OUString& rServiceName ) throw (uno::RuntimeException)
116 {
117 	uno::Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() );
118 	const ::rtl::OUString* pNames = aNames.getConstArray();
119 	const ::rtl::OUString* pEnd = pNames + aNames.getLength();
120 	for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames )
121 		;
122 
123 	return pNames != pEnd;
124 }
125 
126 uno::Sequence< ::rtl::OUString > VCLXAccessibleComponent::getSupportedServiceNames() throw (uno::RuntimeException)
127 {
128 	uno::Sequence< ::rtl::OUString > aNames(1);
129 	aNames[0] = ::rtl::OUString::createFromAscii( "com.sun.star.awt.AccessibleWindow" );
130 	return aNames;
131 }
132 
133 IMPL_LINK( VCLXAccessibleComponent, WindowEventListener, VclSimpleEvent*, pEvent )
134 {
135 	DBG_CHKTHIS(VCLXAccessibleComponent,0);
136 
137 	DBG_ASSERT( pEvent && pEvent->ISA( VclWindowEvent ), "Unknown WindowEvent!" );
138 
139         /* Ignore VCLEVENT_WINDOW_ENDPOPUPMODE, because the UNO accessibility wrapper
140          * might have been destroyed by the previous VCLEventListener (if no AT tool
141          * is running), e.g. sub-toolbars in impress.
142          */
143 	if ( pEvent && pEvent->ISA( VclWindowEvent ) && mxWindow.is() /* #122218# */ && (pEvent->GetId() != VCLEVENT_WINDOW_ENDPOPUPMODE) )
144 	{
145 		DBG_ASSERT( ((VclWindowEvent*)pEvent)->GetWindow(), "Window???" );
146         if( !((VclWindowEvent*)pEvent)->GetWindow()->IsAccessibilityEventsSuppressed() || ( pEvent->GetId() == VCLEVENT_OBJECT_DYING ) )
147 		{
148 		    ProcessWindowEvent( *(VclWindowEvent*)pEvent );
149 		}
150 	}
151 	return 0;
152 }
153 
154 IMPL_LINK( VCLXAccessibleComponent, WindowChildEventListener, VclSimpleEvent*, pEvent )
155 {
156 	DBG_CHKTHIS(VCLXAccessibleComponent,0);
157 
158     DBG_ASSERT( pEvent && pEvent->ISA( VclWindowEvent ), "Unknown WindowEvent!" );
159 	if ( pEvent && pEvent->ISA( VclWindowEvent ) && mxWindow.is() /* #i68079# */ )
160 	{
161 		DBG_ASSERT( ((VclWindowEvent*)pEvent)->GetWindow(), "Window???" );
162         if( !((VclWindowEvent*)pEvent)->GetWindow()->IsAccessibilityEventsSuppressed() )
163 		{
164 			// #103087# to prevent an early release of the component
165 			uno::Reference< accessibility::XAccessibleContext > xTmp = this;
166 
167 		    ProcessWindowChildEvent( *(VclWindowEvent*)pEvent );
168 		}
169 	}
170 	return 0;
171 }
172 
173 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::GetChildAccessible( const VclWindowEvent& rVclWindowEvent )
174 {
175     // checks if the data in the window event is our direct child
176     // and returns its accessible
177 
178     // MT: Change this later, normaly a show/hide event shouldn't have the Window* in pData.
179     Window* pChildWindow = (Window *) rVclWindowEvent.GetData();
180     if( pChildWindow && GetWindow() == pChildWindow->GetAccessibleParentWindow() )
181         return pChildWindow->GetAccessible( rVclWindowEvent.GetId() == VCLEVENT_WINDOW_SHOW );
182     else
183         return uno::Reference< accessibility::XAccessible > ();
184 }
185 
186 void VCLXAccessibleComponent::ProcessWindowChildEvent( const VclWindowEvent& rVclWindowEvent )
187 {
188 	uno::Any aOldValue, aNewValue;
189     uno::Reference< accessibility::XAccessible > xAcc;
190 
191 	switch ( rVclWindowEvent.GetId() )
192 	{
193         case VCLEVENT_WINDOW_SHOW:  // send create on show for direct accessible children
194         {
195             xAcc = GetChildAccessible( rVclWindowEvent );
196             if( xAcc.is() )
197             {
198                 aNewValue <<= xAcc;
199                 NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue );
200             }
201         }
202         break;
203         case VCLEVENT_WINDOW_HIDE:  // send destroy on hide for direct accessible children
204         {
205             xAcc = GetChildAccessible( rVclWindowEvent );
206             if( xAcc.is() )
207             {
208                 aOldValue <<= xAcc;
209                 NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue );
210             }
211         }
212         break;
213 	}
214 }
215 
216 void VCLXAccessibleComponent::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
217 {
218 	uno::Any aOldValue, aNewValue;
219 
220 	Window* pAccWindow = rVclWindowEvent.GetWindow();
221 	DBG_ASSERT( pAccWindow, "VCLXAccessibleComponent::ProcessWindowEvent - Window?" );
222 
223 	switch ( rVclWindowEvent.GetId() )
224 	{
225         case VCLEVENT_OBJECT_DYING:
226         {
227 		    pAccWindow->RemoveEventListener( LINK( this, VCLXAccessibleComponent, WindowEventListener ) );
228 		    pAccWindow->RemoveChildEventListener( LINK( this, VCLXAccessibleComponent, WindowChildEventListener ) );
229 	        mxWindow.clear();
230 	        mpVCLXindow = NULL;
231         }
232         break;
233         //
234         // dont handle CHILDCREATED events here
235         // they are handled separately as child events, see ProcessWindowChildEvent above
236         //
237         /*
238         case VCLEVENT_WINDOW_CHILDCREATED:
239         {
240             Window* pWindow = (Window*) rVclWindowEvent.GetData();
241             DBG_ASSERT( pWindow, "VCLEVENT_WINDOW_CHILDCREATED - Window=?" );
242             aNewValue <<= pWindow->GetAccessible();
243             NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue );
244         }
245         break;
246         */
247         case VCLEVENT_WINDOW_CHILDDESTROYED:
248         {
249             Window* pWindow = (Window*) rVclWindowEvent.GetData();
250             DBG_ASSERT( pWindow, "VCLEVENT_WINDOW_CHILDDESTROYED - Window=?" );
251             if ( pWindow->GetAccessible( sal_False ).is() )
252             {
253                 aOldValue <<= pWindow->GetAccessible( sal_False );
254                 NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue );
255             }
256         }
257         break;
258 
259         //
260         // show and hide will be handled as child events only and are
261         // responsible for sending create/destroy events, see ProcessWindowChildEvent above
262         //
263         /*
264 		case VCLEVENT_WINDOW_SHOW:
265 		{
266 			aNewValue <<= accessibility::AccessibleStateType::VISIBLE;
267 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
268 
269 			aNewValue <<= accessibility::AccessibleStateType::SHOWING;
270 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
271 
272 			aNewValue.clear();
273 			aOldValue <<= accessibility::AccessibleStateType::INVALID;
274 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
275 		}
276 		break;
277 		case VCLEVENT_WINDOW_HIDE:
278 		{
279 			aOldValue <<= accessibility::AccessibleStateType::VISIBLE;
280 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
281 
282 			aOldValue <<= accessibility::AccessibleStateType::SHOWING;
283 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
284 
285 			aOldValue.clear();
286 			aNewValue <<= accessibility::AccessibleStateType::INVALID;
287 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
288 		}
289 		break;
290         */
291 		case VCLEVENT_WINDOW_ACTIVATE:
292 		{
293             // avoid notification if a child frame is already active
294             // only one frame may be active at a given time
295             if ( !pAccWindow->HasActiveChildFrame() &&
296                  ( getAccessibleRole() == accessibility::AccessibleRole::FRAME ||
297                    getAccessibleRole() == accessibility::AccessibleRole::ALERT ||
298                    getAccessibleRole() == accessibility::AccessibleRole::DIALOG ) )  // #i18891#
299             {
300 			    aNewValue <<= accessibility::AccessibleStateType::ACTIVE;
301 			    NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
302             }
303 		}
304 		break;
305 		case VCLEVENT_WINDOW_DEACTIVATE:
306 		{
307             if ( getAccessibleRole() == accessibility::AccessibleRole::FRAME ||
308                  getAccessibleRole() == accessibility::AccessibleRole::ALERT ||
309                  getAccessibleRole() == accessibility::AccessibleRole::DIALOG )  // #i18891#
310             {
311                 aOldValue <<= accessibility::AccessibleStateType::ACTIVE;
312                 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
313             }
314 		}
315 		break;
316 		case VCLEVENT_WINDOW_GETFOCUS:
317 		case VCLEVENT_CONTROL_GETFOCUS:
318 		{
319             if( (pAccWindow->IsCompoundControl() && rVclWindowEvent.GetId() == VCLEVENT_CONTROL_GETFOCUS) ||
320                 (!pAccWindow->IsCompoundControl() && rVclWindowEvent.GetId() == VCLEVENT_WINDOW_GETFOCUS) )
321             {
322                 // if multiple listeners were registered it is possible that the
323                 // focus was changed during event processing (eg SfxTopWindow )
324                 // #106082# allow ChildPathFocus only for CompoundControls, for windows the focus must be in the window itself
325                 if( (pAccWindow->IsCompoundControl() && pAccWindow->HasChildPathFocus()) ||
326                     (!pAccWindow->IsCompoundControl() && pAccWindow->HasFocus()) )
327                 {
328 			        aNewValue <<= accessibility::AccessibleStateType::FOCUSED;
329 			        NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
330                 }
331             }
332 		}
333 		break;
334 		case VCLEVENT_WINDOW_LOSEFOCUS:
335 		case VCLEVENT_CONTROL_LOSEFOCUS:
336 		{
337             if( (pAccWindow->IsCompoundControl() && rVclWindowEvent.GetId() == VCLEVENT_CONTROL_LOSEFOCUS) ||
338                 (!pAccWindow->IsCompoundControl() && rVclWindowEvent.GetId() == VCLEVENT_WINDOW_LOSEFOCUS) )
339             {
340 			    aOldValue <<= accessibility::AccessibleStateType::FOCUSED;
341 			    NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
342             }
343 		}
344 		break;
345         case VCLEVENT_WINDOW_FRAMETITLECHANGED:
346         {
347             ::rtl::OUString aOldName( *((::rtl::OUString*) rVclWindowEvent.GetData()) );
348             ::rtl::OUString aNewName( getAccessibleName() );
349 			aOldValue <<= aOldName;
350             aNewValue <<= aNewName;
351 			NotifyAccessibleEvent( accessibility::AccessibleEventId::NAME_CHANGED, aOldValue, aNewValue );
352         }
353         break;
354 		case VCLEVENT_WINDOW_ENABLED:
355 		{
356 			aNewValue <<= accessibility::AccessibleStateType::ENABLED;
357 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
358             aNewValue <<= accessibility::AccessibleStateType::SENSITIVE;
359             NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
360 		}
361 		break;
362 		case VCLEVENT_WINDOW_DISABLED:
363 		{
364             aOldValue <<= accessibility::AccessibleStateType::SENSITIVE;
365 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
366 
367             aOldValue <<= accessibility::AccessibleStateType::ENABLED;
368             NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
369 		}
370 		break;
371 		case VCLEVENT_WINDOW_MOVE:
372 		case VCLEVENT_WINDOW_RESIZE:
373 		{
374 			NotifyAccessibleEvent( accessibility::AccessibleEventId::BOUNDRECT_CHANGED, aOldValue, aNewValue );
375 		}
376 		break;
377 		case VCLEVENT_WINDOW_MENUBARADDED:
378 		{
379             MenuBar* pMenuBar = (MenuBar*) rVclWindowEvent.GetData();
380 			if ( pMenuBar )
381 			{
382 				uno::Reference< accessibility::XAccessible > xChild( pMenuBar->GetAccessible() );
383 				if ( xChild.is() )
384 				{
385 					aNewValue <<= xChild;
386 					NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue );
387 				}
388 			}
389 		}
390 		break;
391 		case VCLEVENT_WINDOW_MENUBARREMOVED:
392 		{
393             MenuBar* pMenuBar = (MenuBar*) rVclWindowEvent.GetData();
394 			if ( pMenuBar )
395 			{
396 				uno::Reference< accessibility::XAccessible > xChild( pMenuBar->GetAccessible() );
397 				if ( xChild.is() )
398 				{
399 					aOldValue <<= xChild;
400 					NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue );
401 				}
402 			}
403 		}
404 		break;
405 		case VCLEVENT_WINDOW_MINIMIZE:
406 		{
407 			aNewValue <<= accessibility::AccessibleStateType::ICONIFIED;
408 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
409 		}
410 		break;
411 		case VCLEVENT_WINDOW_NORMALIZE:
412 		{
413 			aOldValue <<= accessibility::AccessibleStateType::ICONIFIED;
414 			NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
415 		}
416 		break;
417 		default:
418 		{
419 		}
420 		break;
421 	}
422 }
423 
424 void VCLXAccessibleComponent::disposing()
425 {
426 	if ( mpVCLXindow && mpVCLXindow->GetWindow() )
427     {
428 		mpVCLXindow->GetWindow()->RemoveEventListener( LINK( this, VCLXAccessibleComponent, WindowEventListener ) );
429 		mpVCLXindow->GetWindow()->RemoveChildEventListener( LINK( this, VCLXAccessibleComponent, WindowChildEventListener ) );
430     }
431 
432 	AccessibleExtendedComponentHelper_BASE::disposing();
433 
434 	mxWindow.clear();
435 	mpVCLXindow = NULL;
436 }
437 
438 Window* VCLXAccessibleComponent::GetWindow() const
439 {
440 	return GetVCLXWindow() ? GetVCLXWindow()->GetWindow() : NULL;
441 }
442 
443 void VCLXAccessibleComponent::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet )
444 {
445 	Window* pWindow = GetWindow();
446 	if ( pWindow )
447 	{
448 		Window *pLabeledBy = pWindow->GetAccessibleRelationLabeledBy();
449 		if ( pLabeledBy && pLabeledBy != pWindow )
450 		{
451 			uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
452 			aSequence[0] = pLabeledBy->GetAccessible();
453 			rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::LABELED_BY, aSequence ) );
454 		}
455 
456 		Window* pLabelFor = pWindow->GetAccessibleRelationLabelFor();
457 		if ( pLabelFor && pLabelFor != pWindow )
458 		{
459 			uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
460 			aSequence[0] = pLabelFor->GetAccessible();
461 			rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::LABEL_FOR, aSequence ) );
462 		}
463 	}
464 }
465 
466 void VCLXAccessibleComponent::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet )
467 {
468 	Window* pWindow = GetWindow();
469 	if ( pWindow )
470 	{
471 		if ( pWindow->IsVisible() )
472 		{
473 			rStateSet.AddState( accessibility::AccessibleStateType::VISIBLE );
474 			rStateSet.AddState( accessibility::AccessibleStateType::SHOWING );
475 		}
476 		else
477 		{
478 			rStateSet.AddState( accessibility::AccessibleStateType::INVALID );
479 		}
480 
481 		if ( pWindow->IsEnabled() )
482         {
483 			rStateSet.AddState( accessibility::AccessibleStateType::ENABLED );
484             rStateSet.AddState( accessibility::AccessibleStateType::SENSITIVE );
485         }
486 
487         if ( pWindow->HasChildPathFocus() &&
488              ( getAccessibleRole() == accessibility::AccessibleRole::FRAME ||
489                getAccessibleRole() == accessibility::AccessibleRole::ALERT ||
490                getAccessibleRole() == accessibility::AccessibleRole::DIALOG ) )  // #i18891#
491 			rStateSet.AddState( accessibility::AccessibleStateType::ACTIVE );
492 
493         // #104290# MT: This way, a ComboBox doesn't get state FOCUSED.
494         // I also don't understand
495         // a) why WINDOW_FIRSTCHILD is used here (which btw is a border window in the case of a combo box)
496         // b) why HasFocus() is nout "enough" for a compound control
497         /*
498 		Window* pChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
499 		if ( ( !pWindow->IsCompoundControl() && pWindow->HasFocus() ) ||
500 		     ( pWindow->IsCompoundControl() && pChild && pChild->HasFocus() ) )
501 			rStateSet.AddState( accessibility::AccessibleStateType::FOCUSED );
502 	    */
503 		if ( pWindow->HasFocus() || ( pWindow->IsCompoundControl() && pWindow->HasChildPathFocus() ) )
504 			rStateSet.AddState( accessibility::AccessibleStateType::FOCUSED );
505 
506 		if ( pWindow->IsWait() )
507 			rStateSet.AddState( accessibility::AccessibleStateType::BUSY );
508 
509 		if ( pWindow->GetStyle() & WB_SIZEABLE )
510 			rStateSet.AddState( accessibility::AccessibleStateType::RESIZABLE );
511 
512         if( pWindow->IsDialog() )
513         {
514             Dialog *pDlg = static_cast< Dialog* >( pWindow );
515             if( pDlg->IsInExecute() )
516 			    rStateSet.AddState( accessibility::AccessibleStateType::MODAL );
517         }
518 	}
519 	else
520 	{
521 		rStateSet.AddState( accessibility::AccessibleStateType::DEFUNC );
522 	}
523 
524 /*
525 
526 MUST BE SET FROM DERIVED CLASSES:
527 
528 CHECKED
529 COLLAPSED
530 EXPANDED
531 EXPANDABLE
532 EDITABLE
533 FOCUSABLE
534 HORIZONTAL
535 VERTICAL
536 ICONIFIED
537 MULTILINE
538 MULTI_SELECTABLE
539 PRESSED
540 SELECTABLE
541 SELECTED
542 SINGLE_LINE
543 TRANSIENT
544 
545 	*/
546 }
547 
548 
549 // accessibility::XAccessibleContext
550 sal_Int32 VCLXAccessibleComponent::getAccessibleChildCount() throw (uno::RuntimeException)
551 {
552 	OExternalLockGuard aGuard( this );
553 
554 	sal_Int32 nChildren = 0;
555 	if ( GetWindow() )
556 		nChildren = GetWindow()->GetAccessibleChildWindowCount();
557 
558 	return nChildren;
559 }
560 
561 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getAccessibleChild( sal_Int32 i ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
562 {
563 	OExternalLockGuard aGuard( this );
564 
565 	if ( i >= getAccessibleChildCount() )
566 		throw lang::IndexOutOfBoundsException();
567 
568 	uno::Reference< accessibility::XAccessible > xAcc;
569 	if ( GetWindow() )
570 	{
571 		Window* pChild = GetWindow()->GetAccessibleChildWindow( (sal_uInt16)i );
572 		if ( pChild )
573 			xAcc = pChild->GetAccessible();
574 	}
575 
576 	return xAcc;
577 }
578 
579 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getVclParent() const
580 {
581 	uno::Reference< accessibility::XAccessible > xAcc;
582 	if ( GetWindow() )
583 	{
584 		Window* pParent = GetWindow()->GetAccessibleParentWindow();
585 		if ( pParent )
586 			xAcc = pParent->GetAccessible();
587 	}
588 	return xAcc;
589 }
590 
591 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getAccessibleParent(	) throw (uno::RuntimeException)
592 {
593 	OExternalLockGuard aGuard( this );
594 
595 	uno::Reference< accessibility::XAccessible > xAcc( implGetForeignControlledParent() );
596 	if ( !xAcc.is() )
597 		// we do _not_ have a foreign-controlled parent -> default to our VCL parent
598 		xAcc = getVclParent();
599 
600 	return xAcc;
601 }
602 
603 sal_Int32 VCLXAccessibleComponent::getAccessibleIndexInParent(	) throw (uno::RuntimeException)
604 {
605 	OExternalLockGuard aGuard( this );
606 
607 	sal_Int32 nIndex = -1;
608 
609 	uno::Reference< accessibility::XAccessible > xAcc( implGetForeignControlledParent() );
610 	if ( xAcc.is() )
611 	{	// we _do_ have a foreign-controlled parent -> use the base class' implementation,
612 		// which goes the UNO way
613 		nIndex = AccessibleExtendedComponentHelper_BASE::getAccessibleIndexInParent( );
614 	}
615 	else
616 	{
617 		if ( GetWindow() )
618 		{
619 			Window* pParent = GetWindow()->GetAccessibleParentWindow();
620 			if ( pParent )
621 			{
622                 /*
623 				for ( sal_uInt16 n = pParent->GetAccessibleChildWindowCount(); n; )
624 				{
625 					Window* pChild = pParent->GetAccessibleChildWindow( --n );
626 					if ( pChild == GetWindow() )
627 					{
628 						nIndex = n;
629 						break;
630 					}
631 				}
632                 */
633                 //	Iterate over all the parent's children and search for this object.
634                 // this should be compatible with the code in SVX
635                 uno::Reference< accessibility::XAccessible > xParentAcc( pParent->GetAccessible() );
636                 if ( xParentAcc.is() )
637                 {
638                     uno::Reference< accessibility::XAccessibleContext > xParentContext ( xParentAcc->getAccessibleContext() );
639                     if ( xParentContext.is() )
640                     {
641                         sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
642                         for ( sal_Int32 i=0; i<nChildCount; i++ )
643                         {
644                             uno::Reference< accessibility::XAccessible > xChild( xParentContext->getAccessibleChild(i) );
645                             if ( xChild.is() )
646                             {
647                                 uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
648 	                            if ( xChildContext == (accessibility::XAccessibleContext*) this )
649                                 {
650                                     nIndex = i;
651                                     break;
652                                 }
653                             }
654                         }
655                     }
656                 }
657 			}
658 		}
659 	}
660 	return nIndex;
661 }
662 
663 sal_Int16 VCLXAccessibleComponent::getAccessibleRole(  ) throw (uno::RuntimeException)
664 {
665 	OExternalLockGuard aGuard( this );
666 
667 	sal_Int16 nRole = 0;
668 
669 	if ( GetWindow() )
670 		nRole = GetWindow()->GetAccessibleRole();
671 
672 	return nRole;
673 }
674 
675 ::rtl::OUString VCLXAccessibleComponent::getAccessibleDescription(	) throw (uno::RuntimeException)
676 {
677 	OExternalLockGuard aGuard( this );
678 
679 	::rtl::OUString aDescription;
680 
681 	if ( GetWindow() )
682 		aDescription = GetWindow()->GetAccessibleDescription();
683 
684 	return aDescription;
685 }
686 
687 ::rtl::OUString VCLXAccessibleComponent::getAccessibleName(  ) throw (uno::RuntimeException)
688 {
689 	OExternalLockGuard aGuard( this );
690 
691 	::rtl::OUString aName;
692 	if ( GetWindow() )
693 	{
694 		aName = GetWindow()->GetAccessibleName();
695 #if OSL_DEBUG_LEVEL > 1
696 		aName += String( RTL_CONSTASCII_USTRINGPARAM( " (Type = " ) );
697 		aName += String::CreateFromInt32( GetWindow()->GetType() );
698 		aName += String( RTL_CONSTASCII_USTRINGPARAM( ")" ) );
699 #endif
700 	}
701 	return aName;
702 }
703 
704 uno::Reference< accessibility::XAccessibleRelationSet > VCLXAccessibleComponent::getAccessibleRelationSet(	) throw (uno::RuntimeException)
705 {
706 	OExternalLockGuard aGuard( this );
707 
708     utl::AccessibleRelationSetHelper* pRelationSetHelper = new utl::AccessibleRelationSetHelper;
709 	uno::Reference< accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper;
710 	FillAccessibleRelationSet( *pRelationSetHelper );
711     return xSet;
712 }
713 
714 uno::Reference< accessibility::XAccessibleStateSet > VCLXAccessibleComponent::getAccessibleStateSet(  ) throw (uno::RuntimeException)
715 {
716 	OExternalLockGuard aGuard( this );
717 
718 	utl::AccessibleStateSetHelper* pStateSetHelper = new utl::AccessibleStateSetHelper;
719 	uno::Reference< accessibility::XAccessibleStateSet > xSet = pStateSetHelper;
720 	FillAccessibleStateSet( *pStateSetHelper );
721 	return xSet;
722 }
723 
724 lang::Locale VCLXAccessibleComponent::getLocale() throw (accessibility::IllegalAccessibleComponentStateException, uno::RuntimeException)
725 {
726 	OExternalLockGuard aGuard( this );
727 
728 	return Application::GetSettings().GetLocale();
729 }
730 
731 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getAccessibleAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException)
732 {
733 	OExternalLockGuard aGuard( this );
734 
735     uno::Reference< accessibility::XAccessible > xChild;
736 	for ( sal_uInt32 i = 0, nCount = getAccessibleChildCount(); i < nCount; ++i )
737 	{
738 		uno::Reference< accessibility::XAccessible > xAcc = getAccessibleChild( i );
739 		if ( xAcc.is() )
740 		{
741 			uno::Reference< accessibility::XAccessibleComponent > xComp( xAcc->getAccessibleContext(), uno::UNO_QUERY );
742 			if ( xComp.is() )
743 			{
744 				Rectangle aRect = VCLRectangle( xComp->getBounds() );
745 				Point aPos = VCLPoint( rPoint );
746 				if ( aRect.IsInside( aPos ) )
747 				{
748 					xChild = xAcc;
749 					break;
750 				}
751 			}
752 		}
753 	}
754 
755 	return xChild;
756 }
757 
758 // accessibility::XAccessibleComponent
759 awt::Rectangle VCLXAccessibleComponent::implGetBounds() throw (uno::RuntimeException)
760 {
761 	awt::Rectangle aBounds ( 0, 0, 0, 0 );
762 
763 	Window* pWindow = GetWindow();
764 	if ( pWindow )
765 	{
766 		Rectangle aRect = pWindow->GetWindowExtentsRelative( NULL );
767 		aBounds = AWTRectangle( aRect );
768 		Window* pParent = pWindow->GetAccessibleParentWindow();
769 		if ( pParent )
770 		{
771 			Rectangle aParentRect = pParent->GetWindowExtentsRelative( NULL );
772 			awt::Point aParentScreenLoc = AWTPoint( aParentRect.TopLeft() );
773 			aBounds.X -= aParentScreenLoc.X;
774 			aBounds.Y -= aParentScreenLoc.Y;
775 		}
776 	}
777 
778 	uno::Reference< accessibility::XAccessible > xParent( implGetForeignControlledParent() );
779 	if ( xParent.is() )
780 	{	// hmm, we can't rely on our VCL coordinates, as in the Accessibility Hierarchy, somebody gave
781 		// us a parent which is different from our VCL parent
782 		// (actually, we did not check if it's really different ...)
783 
784 		// the screen location of the foreign parent
785 		uno::Reference< accessibility::XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY );
786 		DBG_ASSERT( xParentComponent.is(), "VCLXAccessibleComponent::implGetBounds: invalid (foreign) parent component!" );
787 
788 		awt::Point aScreenLocForeign( 0, 0 );
789 		if ( xParentComponent.is() )
790 			aScreenLocForeign = xParentComponent->getLocationOnScreen();
791 
792 		// the screen location of the VCL parent
793 		xParent = getVclParent();
794 		if ( xParent.is() )
795 			xParentComponent = xParentComponent.query( xParent->getAccessibleContext() );
796 
797 		awt::Point aScreenLocVCL( 0, 0 );
798 		if ( xParentComponent.is() )
799 			aScreenLocVCL = xParentComponent->getLocationOnScreen();
800 
801 		// the difference between them
802 		awt::Size aOffset( aScreenLocVCL.X - aScreenLocForeign.X, aScreenLocVCL.Y - aScreenLocForeign.Y );
803 		// move the bounds
804 		aBounds.X += aOffset.Width;
805 		aBounds.Y += aOffset.Height;
806 	}
807 
808 	return aBounds;
809 }
810 
811 awt::Point VCLXAccessibleComponent::getLocationOnScreen(  ) throw (uno::RuntimeException)
812 {
813 	OExternalLockGuard aGuard( this );
814 
815 	awt::Point aPos;
816 	if ( GetWindow() )
817 	{
818 		Rectangle aRect = GetWindow()->GetWindowExtentsRelative( NULL );
819 		aPos.X = aRect.Left();
820 		aPos.Y = aRect.Top();
821 	}
822 
823 	return aPos;
824 }
825 
826 void VCLXAccessibleComponent::grabFocus(  ) throw (uno::RuntimeException)
827 {
828 	OExternalLockGuard aGuard( this );
829 
830 	uno::Reference< accessibility::XAccessibleStateSet > xStates = getAccessibleStateSet();
831 	if ( mxWindow.is() && xStates.is() && xStates->contains( accessibility::AccessibleStateType::FOCUSABLE ) )
832 		mxWindow->setFocus();
833 }
834 
835 sal_Int32 SAL_CALL VCLXAccessibleComponent::getForeground(	) throw (uno::RuntimeException)
836 {
837 	OExternalLockGuard aGuard( this );
838 
839 	sal_Int32 nColor = 0;
840 	Window* pWindow = GetWindow();
841 	if ( pWindow )
842 	{
843 		if ( pWindow->IsControlForeground() )
844 			nColor = pWindow->GetControlForeground().GetColor();
845 		else
846 		{
847 			Font aFont;
848 			if ( pWindow->IsControlFont() )
849 				aFont = pWindow->GetControlFont();
850 			else
851 				aFont = pWindow->GetFont();
852 			nColor = aFont.GetColor().GetColor();
853 		}
854 	}
855 
856 	return nColor;
857 }
858 
859 sal_Int32 SAL_CALL VCLXAccessibleComponent::getBackground(	) throw (uno::RuntimeException)
860 {
861 	OExternalLockGuard aGuard( this );
862 
863 	sal_Int32 nColor = 0;
864 	Window* pWindow = GetWindow();
865 	if ( pWindow )
866 	{
867 		if ( pWindow->IsControlBackground() )
868 			nColor = pWindow->GetControlBackground().GetColor();
869 		else
870 			nColor = pWindow->GetBackground().GetColor().GetColor();
871 	}
872 
873 	return nColor;
874 }
875 
876 // XAccessibleExtendedComponent
877 
878 uno::Reference< awt::XFont > SAL_CALL VCLXAccessibleComponent::getFont(  ) throw (uno::RuntimeException)
879 {
880 	OExternalLockGuard aGuard( this );
881 
882 	uno::Reference< awt::XFont > xFont;
883 	Window* pWindow = GetWindow();
884 	if ( pWindow )
885 	{
886 		uno::Reference< awt::XDevice > xDev( pWindow->GetComponentInterface(), uno::UNO_QUERY );
887 		if ( xDev.is() )
888 		{
889 			Font aFont;
890 			if ( pWindow->IsControlFont() )
891 				aFont = pWindow->GetControlFont();
892 			else
893 				aFont = pWindow->GetFont();
894 			VCLXFont* pVCLXFont = new VCLXFont;
895 			pVCLXFont->Init( *xDev.get(), aFont );
896 			xFont = pVCLXFont;
897 		}
898 	}
899 
900 	return xFont;
901 }
902 
903 ::rtl::OUString SAL_CALL VCLXAccessibleComponent::getTitledBorderText(	) throw (uno::RuntimeException)
904 {
905 	OExternalLockGuard aGuard( this );
906 
907 	::rtl::OUString sRet;
908 	if ( GetWindow() )
909 		sRet = GetWindow()->GetText();
910 
911 	return sRet;
912 }
913 
914 ::rtl::OUString SAL_CALL VCLXAccessibleComponent::getToolTipText(  ) throw (uno::RuntimeException)
915 {
916 	OExternalLockGuard aGuard( this );
917 
918 	::rtl::OUString sRet;
919 	if ( GetWindow() )
920 		sRet = GetWindow()->GetQuickHelpText();
921 
922 	return sRet;
923 }
924 
925