xref: /trunk/main/toolkit/source/awt/vclxaccessiblecomponent.cxx (revision ffad8df045fe8db79e3e50f731c1fa6ab6501c83)
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 // COL_AUTO is not very meaningful for AT
908             if ( nColor == (sal_Int32)COL_AUTO)
909                 nColor = pWindow->GetTextColor().GetColor();
910 //-----IAccessibility2 Implementation 2009
911         }
912     }
913 
914     return nColor;
915 }
916 
917 sal_Int32 SAL_CALL VCLXAccessibleComponent::getBackground(  ) throw (uno::RuntimeException)
918 {
919     OExternalLockGuard aGuard( this );
920 
921     sal_Int32 nColor = 0;
922     Window* pWindow = GetWindow();
923     if ( pWindow )
924     {
925         if ( pWindow->IsControlBackground() )
926             nColor = pWindow->GetControlBackground().GetColor();
927         else
928             nColor = pWindow->GetBackground().GetColor().GetColor();
929     }
930 
931     return nColor;
932 }
933 
934 // XAccessibleExtendedComponent
935 
936 uno::Reference< awt::XFont > SAL_CALL VCLXAccessibleComponent::getFont(  ) throw (uno::RuntimeException)
937 {
938     OExternalLockGuard aGuard( this );
939 
940     uno::Reference< awt::XFont > xFont;
941     Window* pWindow = GetWindow();
942     if ( pWindow )
943     {
944         uno::Reference< awt::XDevice > xDev( pWindow->GetComponentInterface(), uno::UNO_QUERY );
945         if ( xDev.is() )
946         {
947             Font aFont;
948             if ( pWindow->IsControlFont() )
949                 aFont = pWindow->GetControlFont();
950             else
951                 aFont = pWindow->GetFont();
952             VCLXFont* pVCLXFont = new VCLXFont;
953             pVCLXFont->Init( *xDev.get(), aFont );
954             xFont = pVCLXFont;
955         }
956     }
957 
958     return xFont;
959 }
960 
961 ::rtl::OUString SAL_CALL VCLXAccessibleComponent::getTitledBorderText(  ) throw (uno::RuntimeException)
962 {
963     OExternalLockGuard aGuard( this );
964 
965     ::rtl::OUString sRet;
966     if ( GetWindow() )
967         sRet = GetWindow()->GetText();
968 
969     return sRet;
970 }
971 
972 ::rtl::OUString SAL_CALL VCLXAccessibleComponent::getToolTipText(  ) throw (uno::RuntimeException)
973 {
974     OExternalLockGuard aGuard( this );
975 
976     ::rtl::OUString sRet;
977     if ( GetWindow() )
978         sRet = GetWindow()->GetQuickHelpText();
979 
980     return sRet;
981 }
982 
983