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