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