LibreOffice Module accessibility (master) 1
accessiblelistbox.cxx
Go to the documentation of this file.
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
24#include <com/sun/star/accessibility/AccessibleEventId.hpp>
25#include <com/sun/star/accessibility/AccessibleRole.hpp>
26#include <com/sun/star/accessibility/AccessibleStateType.hpp>
27#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30
31
32namespace accessibility
33{
34
35
36 // class AccessibleListBox -----------------------------------------------------
37
38 using namespace ::com::sun::star::accessibility;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star;
42
43
44 // Ctor() and Dtor()
45
47
48 ImplInheritanceHelper( _rListBox.GetWindowPeer() ),
49 m_xParent( _xParent )
50 {
51 }
52
54 {
55 if ( isAlive() )
56 {
57 // increment ref count to prevent double call of Dtor
58 osl_atomic_increment( &m_refCount );
59 dispose();
60 }
61 }
62
64 {
65 if ( !isAlive() )
66 return;
67
68 switch ( rVclWindowEvent.GetId() )
69 {
70 case VclEventId::CheckboxToggle :
71 {
72 if ( !getListBox() || !getListBox()->HasFocus() )
73 {
74 return;
75 }
76 AccessibleListBoxEntry* pCurOpEntry = GetCurEventEntry(rVclWindowEvent);
77 if(!pCurOpEntry)
78 {
79 return ;
80 }
81 uno::Any aValue;
82 aValue <<= AccessibleStateType::CHECKED;
83
84 if ( getListBox()->GetCheckButtonState( pCurOpEntry->GetSvLBoxEntry() ) == SvButtonState::Checked )
85 {
86 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aValue );
87 }
88 else
89 {
90 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aValue,uno::Any() );
91 }
92 break;
93 }
94
95 case VclEventId::ListboxSelect :
96 {
97 OSL_FAIL("Debug: Treelist shouldn't use VclEventId::ListboxSelect");
98 break;
99 }
100
101 case VclEventId::ListboxTreeSelect:
102 {
103 if ( getListBox() && getListBox()->HasFocus() )
104 {
105 AccessibleListBoxEntry* pEntry =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
106 if (pEntry)
107 {
108 pEntry->NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
109 }
110 }
111 }
112 break;
113 case VclEventId::ListboxTreeFocus:
114 {
116 if( pBox && pBox->HasFocus() )
117 {
118 uno::Any aNewValue;
119 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
120 if ( pEntry )
121 {
122 AccessibleListBoxEntry* pEntryFocus =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
123 if (pEntryFocus && pEntryFocus->GetSvLBoxEntry() == pEntry)
124 {
125 aNewValue <<= m_xFocusedChild;
126 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), aNewValue );
127 return ;
128 }
129
130 uno::Any aOldValue;
131 aOldValue <<= m_xFocusedChild;
132
134
135 aNewValue <<= m_xFocusedChild;
136 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldValue, aNewValue );
137 }
138 else
139 {
140 aNewValue <<= AccessibleStateType::FOCUSED;
141 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aNewValue );
142 }
143 }
144 }
145 break;
146 case VclEventId::ListboxItemRemoved:
147 {
148 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
149 if ( pEntry )
150 {
151 RemoveChildEntries(pEntry);
152 }
153 else
154 {
155 // NULL means Clear()
156 for (auto const& entry : m_mapEntry)
157 {
158 uno::Any aNewValue;
159 uno::Any aOldValue;
160 aOldValue <<= uno::Reference<XAccessible>(entry.second);
161 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
162 }
163 for (auto const& entry : m_mapEntry)
164 { // release references ...
165 entry.second->dispose();
166 }
167 m_mapEntry.clear();
168 }
169 }
170 break;
171
172 // #i92103#
173 case VclEventId::ItemExpanded :
174 case VclEventId::ItemCollapsed :
175 {
176 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
177 if ( pEntry )
178 {
179 Reference<XAccessible> const xChild(implGetAccessible(*pEntry));
180 const short nAccEvent =
181 ( rVclWindowEvent.GetId() == VclEventId::ItemExpanded )
182 ? AccessibleEventId::LISTBOX_ENTRY_EXPANDED
183 : AccessibleEventId::LISTBOX_ENTRY_COLLAPSED;
184 uno::Any aListBoxEntry;
185 aListBoxEntry <<= xChild;
186 NotifyAccessibleEvent( nAccEvent, Any(), aListBoxEntry );
187 if ( getListBox() && getListBox()->HasFocus() )
188 {
189 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), aListBoxEntry );
190 }
191 }
192 }
193 break;
194 default:
195 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
196 }
197 }
198
200 {
201 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
202 if ( !pEntry )
203 pEntry = getListBox()->GetCurEntry();
204
205 AccessibleListBoxEntry* pEntryFocus =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
206 if (pEntryFocus && pEntry && pEntry != pEntryFocus->GetSvLBoxEntry())
207 {
208 AccessibleListBoxEntry *const pAccCurOptionEntry = implGetAccessible(*pEntry).get();
209 uno::Any aNewValue;
210 aNewValue <<= uno::Reference<XAccessible>(pAccCurOptionEntry);
211 NotifyAccessibleEvent( AccessibleEventId::CHILD, uno::Any(), aNewValue );//Add
212
213 return pAccCurOptionEntry;
214 }
215 else
216 {
217 return pEntryFocus;
218 }
219 }
220
222 {
223 MAP_ENTRY::iterator mi = m_mapEntry.find(pEntry);
224 if ( mi != m_mapEntry.end() )
225 {
226 uno::Any aNewValue;
227 uno::Any aOldValue;
228 aOldValue <<= uno::Reference<XAccessible>(mi->second);
229 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
230
231 m_mapEntry.erase(mi);
232 }
233
235 SvTreeListEntry* pEntryChild = pBox->FirstChild(pEntry);
236 while (pEntryChild)
237 {
238 RemoveChildEntries(pEntryChild);
239 pEntryChild = pEntryChild->NextSibling();
240 }
241 }
242
243
245 {
246 switch ( rVclWindowEvent.GetId() )
247 {
248 case VclEventId::WindowShow:
249 case VclEventId::WindowHide:
250 {
251 }
252 break;
253 default:
254 {
255 VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent );
256 }
257 break;
258 }
259 }
260
261
262 // XComponent
263
265 {
266 ::osl::MutexGuard aGuard( m_aMutex );
267
268 m_mapEntry.clear();
269 VCLXAccessibleComponent::disposing();
270 m_xParent = nullptr;
271 }
272
273 // XServiceInfo
274
276 {
277 return "com.sun.star.comp.svtools.AccessibleTreeListBox";
278 }
279
281 {
282 return {"com.sun.star.accessibility.AccessibleContext",
283 "com.sun.star.accessibility.AccessibleComponent",
284 "com.sun.star.awt.AccessibleTreeListBox"};
285 }
286
287 sal_Bool SAL_CALL AccessibleListBox::supportsService( const OUString& _rServiceName )
288 {
289 return cppu::supportsService(this, _rServiceName);
290 }
291
292 // XAccessible
293
295 {
296 ensureAlive();
297 return this;
298 }
299
300 // XAccessibleContext
301
303 {
305
306 sal_Int32 nCount = 0;
307 VclPtr<SvTreeListBox> pSvTreeListBox = getListBox();
308 if ( pSvTreeListBox )
309 nCount = pSvTreeListBox->GetLevelChildCount( nullptr );
310
311 return nCount;
312 }
313
315 {
317
318 SvTreeListEntry* pEntry = getListBox()->GetEntry(i);
319 if ( !pEntry )
320 throw IndexOutOfBoundsException();
321
322 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
323 //return new AccessibleListBoxEntry( *getListBox(), pEntry, this );
324 //return new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
325 return implGetAccessible(*pEntry);
326 }
327
329 {
330 ::osl::MutexGuard aGuard( m_aMutex );
331
332 ensureAlive();
333 return m_xParent;
334 }
335
337 {
338 sal_Int32 nCase = 0;
339 SvTreeListEntry* pEntry = getListBox()->GetEntry(0);
340 if ( pEntry )
341 {
342 if( pEntry->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry) > 0 )
343 {
344 nCase = 1;
345 return nCase;
346 }
347 }
348
349 bool bHasButtons = (getListBox()->GetStyle() & WB_HASBUTTONS)!=0;
350 if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN) )
351 {
352 if( bHasButtons )
353 nCase = 1;
354 }
355 else
356 {
357 if( bHasButtons )
358 nCase = 2;
359 else
360 nCase = 3;
361 }
362 return nCase;
363 }
364
366 {
368
369 //o is: return AccessibleRole::TREE;
370 bool bHasButtons = (getListBox()->GetStyle() & WB_HASBUTTONS)!=0;
371 if(!bHasButtons && (getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN))
372 return AccessibleRole::LIST;
373 else
374 if (GetRoleType() == 0)
375 return AccessibleRole::LIST;
376 else
377 return AccessibleRole::TREE;
378 }
379
381 {
383
384 return getListBox()->GetAccessibleDescription();
385 }
386
388 {
390
391 return getListBox()->GetAccessibleName();
392 }
393
394 // XAccessibleSelection
395
396 void SAL_CALL AccessibleListBox::selectAccessibleChild( sal_Int64 nChildIndex )
397 {
399
400 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
401 if ( !pEntry )
402 throw IndexOutOfBoundsException();
403
404 getListBox()->Select( pEntry );
405 }
406
408 {
410
411 if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
412 throw IndexOutOfBoundsException();
413
414 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
415 if ( !pEntry )
416 throw IndexOutOfBoundsException();
417
418 return getListBox()->IsSelected( pEntry );
419 }
420
422 {
424
425 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
426 for ( sal_Int32 i = 0; i < nCount; ++i )
427 {
428 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
429 if ( getListBox()->IsSelected( pEntry ) )
430 getListBox()->Select( pEntry, false );
431 }
432 }
433
435 {
437
438 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
439 for ( sal_Int32 i = 0; i < nCount; ++i )
440 {
441 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
442 if ( !getListBox()->IsSelected( pEntry ) )
443 getListBox()->Select( pEntry );
444 }
445 }
446
448 {
450
451 return getListBox()->GetSelectionCount();
452 }
453
455 {
457
458 if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() )
459 throw IndexOutOfBoundsException();
460
462 sal_Int64 nSelCount= 0;
463 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
464 for ( sal_Int32 i = 0; i < nCount; ++i )
465 {
466 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
467 if ( getListBox()->IsSelected( pEntry ) )
468 ++nSelCount;
469
470 if ( nSelCount == ( nSelectedChildIndex + 1 ) )
471 {
472 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
473 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
474 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
475 xChild = implGetAccessible(*pEntry).get();
476 break;
477 }
478 }
479
480 return xChild;
481 }
482
483 void SAL_CALL AccessibleListBox::deselectAccessibleChild( sal_Int64 nSelectedChildIndex )
484 {
486
487 SvTreeListEntry* pEntry = getListBox()->GetEntry( nSelectedChildIndex );
488 if ( !pEntry )
489 throw IndexOutOfBoundsException();
490
491 getListBox()->Select( pEntry, false );
492 }
493
494 void AccessibleListBox::FillAccessibleStateSet( sal_Int64& rStateSet )
495 {
496 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
497 if ( getListBox() && isAlive() )
498 {
499 rStateSet |= AccessibleStateType::FOCUSABLE;
500 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
501 if ( getListBox()->GetSelectionMode() == SelectionMode::Multiple )
502 rStateSet |= AccessibleStateType::MULTI_SELECTABLE;
503 }
504 }
505
507 {
509 auto const it = m_mapEntry.find(&rEntry);
510 if (it != m_mapEntry.end())
511 {
512 pAccessible = it->second;
513 }
514 else
515 {
516 pAccessible = new AccessibleListBoxEntry(*getListBox(), rEntry, *this);
517 m_mapEntry.emplace(&rEntry, pAccessible);
518 }
519 assert(pAccessible.is());
520 return pAccessible;
521 }
522
524 {
525 return GetAs< SvTreeListBox >();
526 }
527
528}// namespace accessibility
529
530
531/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SvTreeListEntry * NextSibling() const
bool HasChildrenOnDemand() const
VclEventId GetId() const
void * GetData() const
the class AccessibleListBoxEntry represents the class for an accessible object of a listbox entry
void NotifyAccessibleEvent(sal_Int16 _nEventId, const css::uno::Any &_aOldValue, const css::uno::Any &_aNewValue)
rtl::Reference< AccessibleListBoxEntry > implGetAccessible(SvTreeListEntry &rEntry)
virtual void FillAccessibleStateSet(sal_Int64 &rStateSet) override
virtual void SAL_CALL disposing() override
this function is called upon disposing the component
void SAL_CALL selectAllAccessibleChildren() override
void SAL_CALL deselectAccessibleChild(sal_Int64 nSelectedChildIndex) override
void SAL_CALL selectAccessibleChild(sal_Int64 nChildIndex) override
virtual OUString SAL_CALL getAccessibleDescription() override
virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext() override
AccessibleListBox(SvTreeListBox const &_rListBox, const css::uno::Reference< css::accessibility::XAccessible > &_xParent)
OAccessibleBase needs a valid view.
virtual void ProcessWindowChildEvent(const VclWindowEvent &rVclWindowEvent) override
virtual sal_Int16 SAL_CALL getAccessibleRole() override
VclPtr< SvTreeListBox > getListBox() const
virtual void ProcessWindowEvent(const VclWindowEvent &rVclWindowEvent) override
void RemoveChildEntries(SvTreeListEntry *)
virtual OUString SAL_CALL getImplementationName() override
void SAL_CALL clearAccessibleSelection() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
virtual OUString SAL_CALL getAccessibleName() override
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild(sal_Int64 i) override
virtual sal_Int64 SAL_CALL getAccessibleChildCount() override
accessibility::AccessibleListBoxEntry * GetCurEventEntry(const VclWindowEvent &rVclWindowEvent)
css::uno::Reference< css::accessibility::XAccessible > m_xFocusedChild
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override
sal_Bool SAL_CALL isAccessibleChildSelected(sal_Int64 nChildIndex) override
css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild(sal_Int64 nSelectedChildIndex) override
sal_Int64 SAL_CALL getSelectedAccessibleChildCount() override
css::uno::Reference< css::accessibility::XAccessible > m_xParent
int nCount
ULONG m_refCount
std::mutex m_aMutex
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
void dispose()
bool isAlive()
unsigned char sal_Bool
WinBits const WB_HASBUTTONS