xref: /trunk/main/accessibility/source/standard/vclxaccessibletabcontrol.cxx (revision ca62e2c2083b5d0995f1245bad6c2edfb455fbec)
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_accessibility.hxx"
26 #include <accessibility/standard/vclxaccessibletabcontrol.hxx>
27 #include <accessibility/standard/vclxaccessibletabpage.hxx>
28 
29 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
30 #include <com/sun/star/accessibility/AccessibleRole.hpp>
31 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
32 #include <unotools/accessiblestatesethelper.hxx>
33 #include <vcl/tabctrl.hxx>
34 #include <vcl/tabpage.hxx>
35 
36 #include <vector>
37 
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::accessibility;
42 using namespace ::comphelper;
43 
44 
45 //  ----------------------------------------------------
46 //  class VCLXAccessibleTabControl
47 //  ----------------------------------------------------
48 
49 VCLXAccessibleTabControl::VCLXAccessibleTabControl( VCLXWindow* pVCLXWindow )
50     :VCLXAccessibleComponent( pVCLXWindow )
51 {
52     m_pTabControl = static_cast< TabControl* >( GetWindow() );
53 
54     if ( m_pTabControl )
55         m_aAccessibleChildren.assign( m_pTabControl->GetPageCount(), Reference< XAccessible >() );
56 }
57 
58 // -----------------------------------------------------------------------------
59 
60 VCLXAccessibleTabControl::~VCLXAccessibleTabControl()
61 {
62 }
63 
64 // -----------------------------------------------------------------------------
65 
66 void VCLXAccessibleTabControl::UpdateFocused()
67 {
68     for ( sal_uInt32 i = 0; i < m_aAccessibleChildren.size(); ++i )
69     {
70         Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
71         if ( xChild.is() )
72         {
73             VCLXAccessibleTabPage* pVCLXAccessibleTabPage = static_cast< VCLXAccessibleTabPage* >( xChild.get() );
74             if ( pVCLXAccessibleTabPage )
75                 pVCLXAccessibleTabPage->SetFocused( pVCLXAccessibleTabPage->IsFocused() );
76         }
77     }
78 }
79 
80 // -----------------------------------------------------------------------------
81 
82 void VCLXAccessibleTabControl::UpdateSelected( sal_Int32 i, bool bSelected )
83 {
84     // IAccessible2 implementation, 2009
85     //NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
86 
87     if ( i >= 0 && i < (sal_Int32)m_aAccessibleChildren.size() )
88     {
89         Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
90         if ( xChild.is() )
91         {
92             VCLXAccessibleTabPage* pVCLXAccessibleTabPage = static_cast< VCLXAccessibleTabPage* >( xChild.get() );
93             if ( pVCLXAccessibleTabPage )
94                 pVCLXAccessibleTabPage->SetSelected( bSelected );
95         }
96     }
97 }
98 
99 // -----------------------------------------------------------------------------
100 
101 void VCLXAccessibleTabControl::UpdatePageText( sal_Int32 i )
102 {
103     if ( i >= 0 && i < (sal_Int32)m_aAccessibleChildren.size() )
104     {
105         Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
106         if ( xChild.is() )
107         {
108             VCLXAccessibleTabPage* pVCLXAccessibleTabPage = static_cast< VCLXAccessibleTabPage* >( xChild.get() );
109             if ( pVCLXAccessibleTabPage )
110                 pVCLXAccessibleTabPage->SetPageText( pVCLXAccessibleTabPage->GetPageText() );
111         }
112     }
113 }
114 
115 // -----------------------------------------------------------------------------
116 
117 void VCLXAccessibleTabControl::UpdateTabPage( sal_Int32 i, bool bNew )
118 {
119     if ( i >= 0 && i < (sal_Int32)m_aAccessibleChildren.size() )
120     {
121         Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
122         if ( xChild.is() )
123         {
124             VCLXAccessibleTabPage* pVCLXAccessibleTabPage = static_cast< VCLXAccessibleTabPage* >( xChild.get() );
125             if ( pVCLXAccessibleTabPage )
126                 pVCLXAccessibleTabPage->Update( bNew );
127         }
128     }
129 }
130 
131 // -----------------------------------------------------------------------------
132 
133 void VCLXAccessibleTabControl::InsertChild( sal_Int32 i )
134 {
135     if ( i >= 0 && i <= (sal_Int32)m_aAccessibleChildren.size() )
136     {
137         // insert entry in child list
138         m_aAccessibleChildren.insert( m_aAccessibleChildren.begin() + i, Reference< XAccessible >() );
139 
140         // send accessible child event
141         Reference< XAccessible > xChild( getAccessibleChild( i ) );
142         if ( xChild.is() )
143         {
144             Any aOldValue, aNewValue;
145             aNewValue <<= xChild;
146             NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
147         }
148     }
149 }
150 
151 // -----------------------------------------------------------------------------
152 
153 void VCLXAccessibleTabControl::RemoveChild( sal_Int32 i )
154 {
155     if ( i >= 0 && i < (sal_Int32)m_aAccessibleChildren.size() )
156     {
157         // get the accessible of the removed page
158         Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
159 
160         // remove entry in child list
161         m_aAccessibleChildren.erase( m_aAccessibleChildren.begin() + i );
162 
163         // send accessible child event
164         if ( xChild.is() )
165         {
166             Any aOldValue, aNewValue;
167             aOldValue <<= xChild;
168             NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
169 
170             Reference< XComponent > xComponent( xChild, UNO_QUERY );
171             if ( xComponent.is() )
172                 xComponent->dispose();
173         }
174     }
175 }
176 
177 // -----------------------------------------------------------------------------
178 
179 void VCLXAccessibleTabControl::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
180 {
181     switch ( rVclWindowEvent.GetId() )
182     {
183         case VCLEVENT_TABPAGE_ACTIVATE:
184         case VCLEVENT_TABPAGE_DEACTIVATE:
185         {
186             if ( m_pTabControl )
187             {
188                 sal_uInt16 nPageId = (sal_uInt16)(sal_IntPtr) rVclWindowEvent.GetData();
189                 sal_uInt16 nPagePos = m_pTabControl->GetPagePos( nPageId );
190                 UpdateFocused();
191                 UpdateSelected( nPagePos, rVclWindowEvent.GetId() == VCLEVENT_TABPAGE_ACTIVATE );
192             }
193         }
194         break;
195         case VCLEVENT_TABPAGE_PAGETEXTCHANGED:
196         {
197             if ( m_pTabControl )
198             {
199                 sal_uInt16 nPageId = (sal_uInt16)(sal_IntPtr) rVclWindowEvent.GetData();
200                 sal_uInt16 nPagePos = m_pTabControl->GetPagePos( nPageId );
201                 UpdatePageText( nPagePos );
202             }
203         }
204         break;
205         case VCLEVENT_TABPAGE_INSERTED:
206         {
207             if ( m_pTabControl )
208             {
209                 sal_uInt16 nPageId = (sal_uInt16)(sal_IntPtr) rVclWindowEvent.GetData();
210                 sal_uInt16 nPagePos = m_pTabControl->GetPagePos( nPageId );
211                 InsertChild( nPagePos );
212             }
213         }
214         break;
215         case VCLEVENT_TABPAGE_REMOVED:
216         {
217             if ( m_pTabControl )
218             {
219                 sal_uInt16 nPageId = (sal_uInt16)(sal_IntPtr) rVclWindowEvent.GetData();
220                 for ( sal_Int32 i = 0, nCount = getAccessibleChildCount(); i < nCount; ++i )
221                 {
222                     Reference< XAccessible > xChild( getAccessibleChild( i ) );
223                     if ( xChild.is() )
224                     {
225                         VCLXAccessibleTabPage* pVCLXAccessibleTabPage = static_cast< VCLXAccessibleTabPage* >( xChild.get() );
226                         if ( pVCLXAccessibleTabPage && pVCLXAccessibleTabPage->GetPageId() == nPageId )
227                         {
228                             RemoveChild( i );
229                             break;
230                         }
231                     }
232                 }
233             }
234         }
235         break;
236         case VCLEVENT_TABPAGE_REMOVEDALL:
237         {
238             for ( sal_Int32 i = m_aAccessibleChildren.size() - 1; i >= 0; --i )
239                 RemoveChild( i );
240         }
241         break;
242         case VCLEVENT_WINDOW_GETFOCUS:
243         case VCLEVENT_WINDOW_LOSEFOCUS:
244         {
245             UpdateFocused();
246         }
247         break;
248         case VCLEVENT_OBJECT_DYING:
249         {
250             if ( m_pTabControl )
251             {
252                 m_pTabControl = NULL;
253 
254                 // dispose all tab pages
255                 for ( sal_uInt32 i = 0; i < m_aAccessibleChildren.size(); ++i )
256                 {
257                     Reference< XComponent > xComponent( m_aAccessibleChildren[i], UNO_QUERY );
258                     if ( xComponent.is() )
259                         xComponent->dispose();
260                 }
261                 m_aAccessibleChildren.clear();
262             }
263 
264             VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
265         }
266         break;
267         default:
268             VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
269    }
270 }
271 
272 // -----------------------------------------------------------------------------
273 
274 void VCLXAccessibleTabControl::ProcessWindowChildEvent( const VclWindowEvent& rVclWindowEvent )
275 {
276     switch ( rVclWindowEvent.GetId() )
277     {
278         case VCLEVENT_WINDOW_SHOW:
279         case VCLEVENT_WINDOW_HIDE:
280         {
281             if ( m_pTabControl )
282             {
283                 Window* pChild = static_cast< Window* >( rVclWindowEvent.GetData() );
284                 if ( pChild && pChild->GetType() == WINDOW_TABPAGE )
285                 {
286                     for ( sal_Int32 i = 0, nCount = m_pTabControl->GetPageCount(); i < nCount; ++i )
287                     {
288                         sal_uInt16 nPageId = m_pTabControl->GetPageId( (sal_uInt16)i );
289                         TabPage* pTabPage = m_pTabControl->GetTabPage( nPageId );
290                         if ( pTabPage == (TabPage*) pChild )
291                             UpdateTabPage( i, rVclWindowEvent.GetId() == VCLEVENT_WINDOW_SHOW );
292                     }
293                 }
294             }
295         }
296         break;
297         default:
298             VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent );
299     }
300 }
301 
302 
303 // -----------------------------------------------------------------------------
304 
305 void VCLXAccessibleTabControl::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet )
306 {
307     VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
308 
309     if ( m_pTabControl )
310         rStateSet.AddState( AccessibleStateType::FOCUSABLE );
311 }
312 
313 // -----------------------------------------------------------------------------
314 // XInterface
315 // -----------------------------------------------------------------------------
316 
317 IMPLEMENT_FORWARD_XINTERFACE2( VCLXAccessibleTabControl, VCLXAccessibleComponent, VCLXAccessibleTabControl_BASE )
318 
319 // -----------------------------------------------------------------------------
320 // XTypeProvider
321 // -----------------------------------------------------------------------------
322 
323 IMPLEMENT_FORWARD_XTYPEPROVIDER2( VCLXAccessibleTabControl, VCLXAccessibleComponent, VCLXAccessibleTabControl_BASE )
324 
325 // -----------------------------------------------------------------------------
326 // XComponent
327 // -----------------------------------------------------------------------------
328 
329 void VCLXAccessibleTabControl::disposing()
330 {
331     VCLXAccessibleComponent::disposing();
332 
333     if ( m_pTabControl )
334     {
335         m_pTabControl = NULL;
336 
337         // dispose all tab pages
338         for ( sal_uInt32 i = 0; i < m_aAccessibleChildren.size(); ++i )
339         {
340             Reference< XComponent > xComponent( m_aAccessibleChildren[i], UNO_QUERY );
341             if ( xComponent.is() )
342                 xComponent->dispose();
343         }
344         m_aAccessibleChildren.clear();
345     }
346 }
347 
348 // -----------------------------------------------------------------------------
349 // XServiceInfo
350 // -----------------------------------------------------------------------------
351 
352 ::rtl::OUString VCLXAccessibleTabControl::getImplementationName() throw (RuntimeException)
353 {
354     return ::rtl::OUString::createFromAscii( "com.sun.star.comp.toolkit.AccessibleTabControl" );
355 }
356 
357 // -----------------------------------------------------------------------------
358 
359 Sequence< ::rtl::OUString > VCLXAccessibleTabControl::getSupportedServiceNames() throw (RuntimeException)
360 {
361     Sequence< ::rtl::OUString > aNames(1);
362     aNames[0] = ::rtl::OUString::createFromAscii( "com.sun.star.awt.AccessibleTabControl" );
363     return aNames;
364 }
365 
366 // -----------------------------------------------------------------------------
367 // XAccessibleContext
368 // -----------------------------------------------------------------------------
369 
370 sal_Int32 VCLXAccessibleTabControl::getAccessibleChildCount() throw (RuntimeException)
371 {
372     OExternalLockGuard aGuard( this );
373 
374     return m_aAccessibleChildren.size();
375 }
376 
377 // -----------------------------------------------------------------------------
378 
379 Reference< XAccessible > VCLXAccessibleTabControl::getAccessibleChild( sal_Int32 i ) throw (IndexOutOfBoundsException, RuntimeException)
380 {
381     OExternalLockGuard aGuard( this );
382 
383     if ( i < 0 || i >= getAccessibleChildCount() )
384         throw IndexOutOfBoundsException();
385 
386     Reference< XAccessible > xChild = m_aAccessibleChildren[i];
387     if ( !xChild.is() )
388     {
389         if ( m_pTabControl )
390         {
391             sal_uInt16 nPageId = m_pTabControl->GetPageId( (sal_uInt16)i );
392 
393             xChild = new VCLXAccessibleTabPage( m_pTabControl, nPageId );
394 
395             // insert into tab page list
396             m_aAccessibleChildren[i] = xChild;
397         }
398     }
399 
400     return xChild;
401 }
402 
403 // -----------------------------------------------------------------------------
404 
405 sal_Int16 VCLXAccessibleTabControl::getAccessibleRole(  ) throw (RuntimeException)
406 {
407     OExternalLockGuard aGuard( this );
408 
409     return AccessibleRole::PAGE_TAB_LIST;
410 }
411 
412 // -----------------------------------------------------------------------------
413 
414 ::rtl::OUString VCLXAccessibleTabControl::getAccessibleName(  ) throw (RuntimeException)
415 {
416     OExternalLockGuard aGuard( this );
417 
418     return ::rtl::OUString();
419 }
420 
421 // -----------------------------------------------------------------------------
422 // XAccessibleSelection
423 // -----------------------------------------------------------------------------
424 
425 void VCLXAccessibleTabControl::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
426 {
427     OExternalLockGuard aGuard( this );
428 
429     if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() )
430         throw IndexOutOfBoundsException();
431 
432     if ( m_pTabControl )
433         m_pTabControl->SelectTabPage( m_pTabControl->GetPageId( (sal_uInt16)nChildIndex ) );
434 }
435 
436 // -----------------------------------------------------------------------------
437 
438 sal_Bool VCLXAccessibleTabControl::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
439 {
440     OExternalLockGuard aGuard( this );
441 
442     if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() )
443         throw IndexOutOfBoundsException();
444 
445     sal_Bool bSelected = sal_False;
446     if ( m_pTabControl && m_pTabControl->GetCurPageId() == m_pTabControl->GetPageId( (sal_uInt16)nChildIndex ) )
447         bSelected = sal_True;
448 
449     return bSelected;
450 }
451 
452 // -----------------------------------------------------------------------------
453 
454 void VCLXAccessibleTabControl::clearAccessibleSelection(  ) throw (RuntimeException)
455 {
456     // This method makes no sense in a tab control, and so does nothing.
457 }
458 
459 // -----------------------------------------------------------------------------
460 
461 void VCLXAccessibleTabControl::selectAllAccessibleChildren(  ) throw (RuntimeException)
462 {
463     OExternalLockGuard aGuard( this );
464 
465     selectAccessibleChild( 0 );
466 }
467 
468 // -----------------------------------------------------------------------------
469 
470 sal_Int32 VCLXAccessibleTabControl::getSelectedAccessibleChildCount(  ) throw (RuntimeException)
471 {
472     OExternalLockGuard aGuard( this );
473 
474     return 1;
475 }
476 
477 // -----------------------------------------------------------------------------
478 
479 Reference< XAccessible > VCLXAccessibleTabControl::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
480 {
481     OExternalLockGuard aGuard( this );
482 
483     if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() )
484         throw IndexOutOfBoundsException();
485 
486     Reference< XAccessible > xChild;
487 
488     for ( sal_Int32 i = 0, j = 0, nCount = getAccessibleChildCount(); i < nCount; i++ )
489     {
490         if ( isAccessibleChildSelected( i ) && ( j++ == nSelectedChildIndex ) )
491         {
492             xChild = getAccessibleChild( i );
493             break;
494         }
495     }
496 
497     return xChild;
498 }
499 
500 // -----------------------------------------------------------------------------
501 
502 void VCLXAccessibleTabControl::deselectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
503 {
504     OExternalLockGuard aGuard( this );
505 
506     if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() )
507         throw IndexOutOfBoundsException();
508 
509     // This method makes no sense in a tab control, and so does nothing.
510 }
511 
512 // -----------------------------------------------------------------------------
513