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