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 
27 
28 #include <com/sun/star/accessibility/AccessibleRole.hpp>
29 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
30 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
31 #include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
32 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
33 #include <toolkit/awt/vclxaccessiblecomponent.hxx>
34 #include <toolkit/helper/externallock.hxx>
35 #include <toolkit/awt/vclxwindow.hxx>
36 #include <toolkit/helper/convert.hxx>
37 #include <toolkit/awt/vclxfont.hxx>
38 #include <vcl/dialog.hxx>
39 #include <vcl/window.hxx>
40 //IAccessibility2 Implementation 2009-----
41 //Solution:Need methods in Edit.
42 #include <vcl/edit.hxx>
43 //-----IAccessibility2 Implementation 2009
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 //IAccessibility2 Implementation 2009-----
449 		Window *pLabeledBy = pWindow->GetAccessibleRelationLabeledBy();
450 //-----IAccessibility2 Implementation 2009
451 		if ( pLabeledBy && pLabeledBy != pWindow )
452 		{
453 			uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
454 			aSequence[0] = pLabeledBy->GetAccessible();
455 			rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::LABELED_BY, aSequence ) );
456 		}
457 
458 		Window* pLabelFor = pWindow->GetAccessibleRelationLabelFor();
459 		if ( pLabelFor && pLabelFor != pWindow )
460 		{
461 			uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
462 			aSequence[0] = pLabelFor->GetAccessible();
463 			rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::LABEL_FOR, aSequence ) );
464 		}
465 //IAccessibility2 Implementation 2009-----
466 		Window* pMemberOf = pWindow->GetAccessibleRelationMemberOf();
467 		if ( pMemberOf && pMemberOf != pWindow )
468 		{
469 			uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
470 			aSequence[0] = pMemberOf->GetAccessible();
471 			rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) );
472 		}
473 		uno::Sequence< uno::Reference< uno::XInterface > > aFlowToSequence = pWindow->GetAccFlowToSequence();
474 		if( aFlowToSequence.getLength() > 0 )
475 		{
476 			rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aFlowToSequence ) );
477 		}
478 //-----IAccessibility2 Implementation 2009
479 	}
480 }
481 
482 void VCLXAccessibleComponent::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet )
483 {
484 	Window* pWindow = GetWindow();
485 	if ( pWindow )
486 	{
487 		if ( pWindow->IsVisible() )
488 		{
489 			rStateSet.AddState( accessibility::AccessibleStateType::VISIBLE );
490 			rStateSet.AddState( accessibility::AccessibleStateType::SHOWING );
491 		}
492 		else
493 		{
494 			rStateSet.AddState( accessibility::AccessibleStateType::INVALID );
495 		}
496 
497 		if ( pWindow->IsEnabled() )
498         {
499 			rStateSet.AddState( accessibility::AccessibleStateType::ENABLED );
500             rStateSet.AddState( accessibility::AccessibleStateType::SENSITIVE );
501         }
502 
503         if ( pWindow->HasChildPathFocus() &&
504              ( getAccessibleRole() == accessibility::AccessibleRole::FRAME ||
505                getAccessibleRole() == accessibility::AccessibleRole::ALERT ||
506                getAccessibleRole() == accessibility::AccessibleRole::DIALOG ) )  // #i18891#
507 			rStateSet.AddState( accessibility::AccessibleStateType::ACTIVE );
508 
509         // #104290# MT: This way, a ComboBox doesn't get state FOCUSED.
510         // I also don't understand
511         // a) why WINDOW_FIRSTCHILD is used here (which btw is a border window in the case of a combo box)
512         // b) why HasFocus() is nout "enough" for a compound control
513         /*
514 		Window* pChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
515 		if ( ( !pWindow->IsCompoundControl() && pWindow->HasFocus() ) ||
516 		     ( pWindow->IsCompoundControl() && pChild && pChild->HasFocus() ) )
517 			rStateSet.AddState( accessibility::AccessibleStateType::FOCUSED );
518 	    */
519 		if ( pWindow->HasFocus() || ( pWindow->IsCompoundControl() && pWindow->HasChildPathFocus() ) )
520 			rStateSet.AddState( accessibility::AccessibleStateType::FOCUSED );
521 
522 		if ( pWindow->IsWait() )
523 			rStateSet.AddState( accessibility::AccessibleStateType::BUSY );
524 
525 		if ( pWindow->GetStyle() & WB_SIZEABLE )
526 			rStateSet.AddState( accessibility::AccessibleStateType::RESIZABLE );
527 //IAccessibility2 Implementation 2009-----
528 		// 6. frame doesn't have MOVABLE state
529 		// 10. for password text, where is the sensitive state?
530 		if( ( getAccessibleRole() == accessibility::AccessibleRole::FRAME ||getAccessibleRole() == accessibility::AccessibleRole::DIALOG )&& pWindow->GetStyle() & WB_MOVEABLE )
531 			rStateSet.AddState( accessibility::AccessibleStateType::MOVEABLE );
532 //-----IAccessibility2 Implementation 2009
533         if( pWindow->IsDialog() )
534         {
535             Dialog *pDlg = static_cast< Dialog* >( pWindow );
536             if( pDlg->IsInExecute() )
537 			    rStateSet.AddState( accessibility::AccessibleStateType::MODAL );
538         }
539 //IAccessibility2 Implementation 2009-----
540         //Solution:If a combobox or list's edit child isn't read-only,EDITABLE state
541         //         should be set.
542 		if( pWindow && pWindow->GetType() == WINDOW_COMBOBOX )
543 		{
544 			if( !( pWindow->GetStyle() & WB_READONLY) ||
545 			    !((Edit*)pWindow)->IsReadOnly() )
546 					rStateSet.AddState( accessibility::AccessibleStateType::EDITABLE );
547 		}
548 
549 		Window* pChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
550 
551 		while( pWindow && pChild )
552 		{
553 			Window* pWinTemp = pChild->GetWindow( WINDOW_FIRSTCHILD );
554 			if( pWinTemp && pWinTemp->GetType() == WINDOW_EDIT )
555 			{
556 				if( !( pWinTemp->GetStyle() & WB_READONLY) ||
557 					!((Edit*)pWinTemp)->IsReadOnly() )
558 					rStateSet.AddState( accessibility::AccessibleStateType::EDITABLE );
559 				break;
560 			}
561 			if( pChild->GetType() == WINDOW_EDIT )
562 			{
563 				if( !( pChild->GetStyle() & WB_READONLY) ||
564 					!((Edit*)pChild)->IsReadOnly())
565 					rStateSet.AddState( accessibility::AccessibleStateType::EDITABLE );
566 				break;
567 			}
568 			pChild = pChild->GetWindow( WINDOW_NEXT );
569 		}
570 //-----IAccessibility2 Implementation 2009
571 	}
572 	else
573 	{
574 		rStateSet.AddState( accessibility::AccessibleStateType::DEFUNC );
575 	}
576 
577 /*
578 
579 MUST BE SET FROM DERIVED CLASSES:
580 
581 CHECKED
582 COLLAPSED
583 EXPANDED
584 EXPANDABLE
585 EDITABLE
586 FOCUSABLE
587 HORIZONTAL
588 VERTICAL
589 ICONIFIED
590 MULTILINE
591 MULTI_SELECTABLE
592 PRESSED
593 SELECTABLE
594 SELECTED
595 SINGLE_LINE
596 TRANSIENT
597 
598 	*/
599 }
600 
601 
602 // accessibility::XAccessibleContext
603 sal_Int32 VCLXAccessibleComponent::getAccessibleChildCount() throw (uno::RuntimeException)
604 {
605 	OExternalLockGuard aGuard( this );
606 
607 	sal_Int32 nChildren = 0;
608 	if ( GetWindow() )
609 		nChildren = GetWindow()->GetAccessibleChildWindowCount();
610 
611 	return nChildren;
612 }
613 
614 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getAccessibleChild( sal_Int32 i ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
615 {
616 	OExternalLockGuard aGuard( this );
617 
618 	if ( i >= getAccessibleChildCount() )
619 		throw lang::IndexOutOfBoundsException();
620 
621 	uno::Reference< accessibility::XAccessible > xAcc;
622 	if ( GetWindow() )
623 	{
624 		Window* pChild = GetWindow()->GetAccessibleChildWindow( (sal_uInt16)i );
625 		if ( pChild )
626 			xAcc = pChild->GetAccessible();
627 	}
628 
629 	return xAcc;
630 }
631 
632 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getVclParent() const
633 {
634 	uno::Reference< accessibility::XAccessible > xAcc;
635 	if ( GetWindow() )
636 	{
637 		Window* pParent = GetWindow()->GetAccessibleParentWindow();
638 		if ( pParent )
639 			xAcc = pParent->GetAccessible();
640 	}
641 	return xAcc;
642 }
643 
644 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getAccessibleParent(	) throw (uno::RuntimeException)
645 {
646 	OExternalLockGuard aGuard( this );
647 
648 	uno::Reference< accessibility::XAccessible > xAcc( implGetForeignControlledParent() );
649 	if ( !xAcc.is() )
650 		// we do _not_ have a foreign-controlled parent -> default to our VCL parent
651 		xAcc = getVclParent();
652 
653 	return xAcc;
654 }
655 
656 sal_Int32 VCLXAccessibleComponent::getAccessibleIndexInParent(	) throw (uno::RuntimeException)
657 {
658 	OExternalLockGuard aGuard( this );
659 
660 	sal_Int32 nIndex = -1;
661 
662 	uno::Reference< accessibility::XAccessible > xAcc( implGetForeignControlledParent() );
663 	if ( xAcc.is() )
664 	{	// we _do_ have a foreign-controlled parent -> use the base class' implementation,
665 		// which goes the UNO way
666 		nIndex = AccessibleExtendedComponentHelper_BASE::getAccessibleIndexInParent( );
667 	}
668 	else
669 	{
670 		if ( GetWindow() )
671 		{
672 			Window* pParent = GetWindow()->GetAccessibleParentWindow();
673 			if ( pParent )
674 			{
675                 /*
676 				for ( sal_uInt16 n = pParent->GetAccessibleChildWindowCount(); n; )
677 				{
678 					Window* pChild = pParent->GetAccessibleChildWindow( --n );
679 					if ( pChild == GetWindow() )
680 					{
681 						nIndex = n;
682 						break;
683 					}
684 				}
685                 */
686                 //	Iterate over all the parent's children and search for this object.
687                 // this should be compatible with the code in SVX
688                 uno::Reference< accessibility::XAccessible > xParentAcc( pParent->GetAccessible() );
689                 if ( xParentAcc.is() )
690                 {
691                     uno::Reference< accessibility::XAccessibleContext > xParentContext ( xParentAcc->getAccessibleContext() );
692                     if ( xParentContext.is() )
693                     {
694                         sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
695                         for ( sal_Int32 i=0; i<nChildCount; i++ )
696                         {
697                             uno::Reference< accessibility::XAccessible > xChild( xParentContext->getAccessibleChild(i) );
698                             if ( xChild.is() )
699                             {
700                                 uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
701 	                            if ( xChildContext == (accessibility::XAccessibleContext*) this )
702                                 {
703                                     nIndex = i;
704                                     break;
705                                 }
706                             }
707                         }
708                     }
709                 }
710 			}
711 		}
712 	}
713 	return nIndex;
714 }
715 
716 sal_Int16 VCLXAccessibleComponent::getAccessibleRole(  ) throw (uno::RuntimeException)
717 {
718 	OExternalLockGuard aGuard( this );
719 
720 	sal_Int16 nRole = 0;
721 
722 	if ( GetWindow() )
723 		nRole = GetWindow()->GetAccessibleRole();
724 
725 	return nRole;
726 }
727 
728 ::rtl::OUString VCLXAccessibleComponent::getAccessibleDescription(	) throw (uno::RuntimeException)
729 {
730 	OExternalLockGuard aGuard( this );
731 
732 	::rtl::OUString aDescription;
733 
734 	if ( GetWindow() )
735 		aDescription = GetWindow()->GetAccessibleDescription();
736 
737 	return aDescription;
738 }
739 
740 ::rtl::OUString VCLXAccessibleComponent::getAccessibleName(  ) throw (uno::RuntimeException)
741 {
742 	OExternalLockGuard aGuard( this );
743 
744 	::rtl::OUString aName;
745 	if ( GetWindow() )
746 	{
747 		aName = GetWindow()->GetAccessibleName();
748 #if OSL_DEBUG_LEVEL > 1
749 		aName += String( RTL_CONSTASCII_USTRINGPARAM( " (Type = " ) );
750 		aName += String::CreateFromInt32( GetWindow()->GetType() );
751 		aName += String( RTL_CONSTASCII_USTRINGPARAM( ")" ) );
752 #endif
753 	}
754 	return aName;
755 }
756 
757 uno::Reference< accessibility::XAccessibleRelationSet > VCLXAccessibleComponent::getAccessibleRelationSet(	) throw (uno::RuntimeException)
758 {
759 	OExternalLockGuard aGuard( this );
760 
761     utl::AccessibleRelationSetHelper* pRelationSetHelper = new utl::AccessibleRelationSetHelper;
762 	uno::Reference< accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper;
763 	FillAccessibleRelationSet( *pRelationSetHelper );
764     return xSet;
765 }
766 
767 uno::Reference< accessibility::XAccessibleStateSet > VCLXAccessibleComponent::getAccessibleStateSet(  ) throw (uno::RuntimeException)
768 {
769 	OExternalLockGuard aGuard( this );
770 
771 	utl::AccessibleStateSetHelper* pStateSetHelper = new utl::AccessibleStateSetHelper;
772 	uno::Reference< accessibility::XAccessibleStateSet > xSet = pStateSetHelper;
773 	FillAccessibleStateSet( *pStateSetHelper );
774 	return xSet;
775 }
776 
777 lang::Locale VCLXAccessibleComponent::getLocale() throw (accessibility::IllegalAccessibleComponentStateException, uno::RuntimeException)
778 {
779 	OExternalLockGuard aGuard( this );
780 
781 	return Application::GetSettings().GetLocale();
782 }
783 
784 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getAccessibleAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException)
785 {
786 	OExternalLockGuard aGuard( this );
787 
788     uno::Reference< accessibility::XAccessible > xChild;
789 	for ( sal_uInt32 i = 0, nCount = getAccessibleChildCount(); i < nCount; ++i )
790 	{
791 		uno::Reference< accessibility::XAccessible > xAcc = getAccessibleChild( i );
792 		if ( xAcc.is() )
793 		{
794 			uno::Reference< accessibility::XAccessibleComponent > xComp( xAcc->getAccessibleContext(), uno::UNO_QUERY );
795 			if ( xComp.is() )
796 			{
797 				Rectangle aRect = VCLRectangle( xComp->getBounds() );
798 				Point aPos = VCLPoint( rPoint );
799 				if ( aRect.IsInside( aPos ) )
800 				{
801 					xChild = xAcc;
802 					break;
803 				}
804 			}
805 		}
806 	}
807 
808 	return xChild;
809 }
810 
811 // accessibility::XAccessibleComponent
812 awt::Rectangle VCLXAccessibleComponent::implGetBounds() throw (uno::RuntimeException)
813 {
814 	awt::Rectangle aBounds ( 0, 0, 0, 0 );
815 
816 	Window* pWindow = GetWindow();
817 	if ( pWindow )
818 	{
819 		Rectangle aRect = pWindow->GetWindowExtentsRelative( NULL );
820 		aBounds = AWTRectangle( aRect );
821 		Window* pParent = pWindow->GetAccessibleParentWindow();
822 		if ( pParent )
823 		{
824 			Rectangle aParentRect = pParent->GetWindowExtentsRelative( NULL );
825 			awt::Point aParentScreenLoc = AWTPoint( aParentRect.TopLeft() );
826 			aBounds.X -= aParentScreenLoc.X;
827 			aBounds.Y -= aParentScreenLoc.Y;
828 		}
829 	}
830 
831 	uno::Reference< accessibility::XAccessible > xParent( implGetForeignControlledParent() );
832 	if ( xParent.is() )
833 	{	// hmm, we can't rely on our VCL coordinates, as in the Accessibility Hierarchy, somebody gave
834 		// us a parent which is different from our VCL parent
835 		// (actually, we did not check if it's really different ...)
836 
837 		// the screen location of the foreign parent
838 		uno::Reference< accessibility::XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY );
839 		DBG_ASSERT( xParentComponent.is(), "VCLXAccessibleComponent::implGetBounds: invalid (foreign) parent component!" );
840 
841 		awt::Point aScreenLocForeign( 0, 0 );
842 		if ( xParentComponent.is() )
843 			aScreenLocForeign = xParentComponent->getLocationOnScreen();
844 
845 		// the screen location of the VCL parent
846 		xParent = getVclParent();
847 		if ( xParent.is() )
848 			xParentComponent = xParentComponent.query( xParent->getAccessibleContext() );
849 
850 		awt::Point aScreenLocVCL( 0, 0 );
851 		if ( xParentComponent.is() )
852 			aScreenLocVCL = xParentComponent->getLocationOnScreen();
853 
854 		// the difference between them
855 		awt::Size aOffset( aScreenLocVCL.X - aScreenLocForeign.X, aScreenLocVCL.Y - aScreenLocForeign.Y );
856 		// move the bounds
857 		aBounds.X += aOffset.Width;
858 		aBounds.Y += aOffset.Height;
859 	}
860 
861 	return aBounds;
862 }
863 
864 awt::Point VCLXAccessibleComponent::getLocationOnScreen(  ) throw (uno::RuntimeException)
865 {
866 	OExternalLockGuard aGuard( this );
867 
868 	awt::Point aPos;
869 	if ( GetWindow() )
870 	{
871 		Rectangle aRect = GetWindow()->GetWindowExtentsRelative( NULL );
872 		aPos.X = aRect.Left();
873 		aPos.Y = aRect.Top();
874 	}
875 
876 	return aPos;
877 }
878 
879 void VCLXAccessibleComponent::grabFocus(  ) throw (uno::RuntimeException)
880 {
881 	OExternalLockGuard aGuard( this );
882 
883 	uno::Reference< accessibility::XAccessibleStateSet > xStates = getAccessibleStateSet();
884 	if ( mxWindow.is() && xStates.is() && xStates->contains( accessibility::AccessibleStateType::FOCUSABLE ) )
885 		mxWindow->setFocus();
886 }
887 
888 sal_Int32 SAL_CALL VCLXAccessibleComponent::getForeground(	) throw (uno::RuntimeException)
889 {
890 	OExternalLockGuard aGuard( this );
891 
892 	sal_Int32 nColor = 0;
893 	Window* pWindow = GetWindow();
894 	if ( pWindow )
895 	{
896 		if ( pWindow->IsControlForeground() )
897 			nColor = pWindow->GetControlForeground().GetColor();
898 		else
899 		{
900 			Font aFont;
901 			if ( pWindow->IsControlFont() )
902 				aFont = pWindow->GetControlFont();
903 			else
904 				aFont = pWindow->GetFont();
905 			nColor = aFont.GetColor().GetColor();
906 //IAccessibility2 Implementation 2009-----
907 			if ( nColor == COL_AUTO)
908 				nColor = pWindow->GetTextColor().GetColor();
909 //-----IAccessibility2 Implementation 2009
910 		}
911 	}
912 
913 	return nColor;
914 }
915 
916 sal_Int32 SAL_CALL VCLXAccessibleComponent::getBackground(	) throw (uno::RuntimeException)
917 {
918 	OExternalLockGuard aGuard( this );
919 
920 	sal_Int32 nColor = 0;
921 	Window* pWindow = GetWindow();
922 	if ( pWindow )
923 	{
924 		if ( pWindow->IsControlBackground() )
925 			nColor = pWindow->GetControlBackground().GetColor();
926 		else
927 			nColor = pWindow->GetBackground().GetColor().GetColor();
928 	}
929 
930 	return nColor;
931 }
932 
933 // XAccessibleExtendedComponent
934 
935 uno::Reference< awt::XFont > SAL_CALL VCLXAccessibleComponent::getFont(  ) throw (uno::RuntimeException)
936 {
937 	OExternalLockGuard aGuard( this );
938 
939 	uno::Reference< awt::XFont > xFont;
940 	Window* pWindow = GetWindow();
941 	if ( pWindow )
942 	{
943 		uno::Reference< awt::XDevice > xDev( pWindow->GetComponentInterface(), uno::UNO_QUERY );
944 		if ( xDev.is() )
945 		{
946 			Font aFont;
947 			if ( pWindow->IsControlFont() )
948 				aFont = pWindow->GetControlFont();
949 			else
950 				aFont = pWindow->GetFont();
951 			VCLXFont* pVCLXFont = new VCLXFont;
952 			pVCLXFont->Init( *xDev.get(), aFont );
953 			xFont = pVCLXFont;
954 		}
955 	}
956 
957 	return xFont;
958 }
959 
960 ::rtl::OUString SAL_CALL VCLXAccessibleComponent::getTitledBorderText(	) throw (uno::RuntimeException)
961 {
962 	OExternalLockGuard aGuard( this );
963 
964 	::rtl::OUString sRet;
965 	if ( GetWindow() )
966 		sRet = GetWindow()->GetText();
967 
968 	return sRet;
969 }
970 
971 ::rtl::OUString SAL_CALL VCLXAccessibleComponent::getToolTipText(  ) throw (uno::RuntimeException)
972 {
973 	OExternalLockGuard aGuard( this );
974 
975 	::rtl::OUString sRet;
976 	if ( GetWindow() )
977 		sRet = GetWindow()->GetQuickHelpText();
978 
979 	return sRet;
980 }
981 
982