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 <extended/accessibletablistboxtable.hxx> 21 #include <extended/AccessibleBrowseBoxTableCell.hxx> 22 #include <extended/AccessibleBrowseBoxCheckBoxCell.hxx> 23 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 24 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 25 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 26 #include <vcl/toolkit/svtabbx.hxx> 27 28 namespace accessibility 29 { 30 31 32 // class AccessibleTabListBoxTable --------------------------------------------- 33 34 using namespace ::com::sun::star::accessibility; 35 using namespace ::com::sun::star::uno; 36 using namespace ::com::sun::star::lang; 37 using namespace ::com::sun::star; 38 39 40 // Ctor() and Dtor() 41 AccessibleTabListBoxTable(const Reference<XAccessible> & rxParent,SvHeaderTabListBox & rBox)42 AccessibleTabListBoxTable::AccessibleTabListBoxTable( const Reference< XAccessible >& rxParent, SvHeaderTabListBox& rBox ) : 43 44 AccessibleBrowseBoxTable( rxParent, rBox ), 45 46 m_pTabListBox ( &rBox ) 47 48 { 49 m_pTabListBox->AddEventListener( LINK( this, AccessibleTabListBoxTable, WindowEventListener ) ); 50 } 51 ~AccessibleTabListBoxTable()52 AccessibleTabListBoxTable::~AccessibleTabListBoxTable() 53 { 54 if ( isAlive() ) 55 { 56 m_pTabListBox = nullptr; 57 58 // increment ref count to prevent double call of Dtor 59 osl_atomic_increment( &m_refCount ); 60 dispose(); 61 } 62 } 63 ProcessWindowEvent(const VclWindowEvent & rVclWindowEvent)64 void AccessibleTabListBoxTable::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) 65 { 66 if ( !isAlive() ) 67 return; 68 69 switch ( VclEventId nEventId = rVclWindowEvent.GetId(); nEventId ) 70 { 71 case VclEventId::ObjectDying : 72 { 73 m_pTabListBox->RemoveEventListener( LINK( this, AccessibleTabListBoxTable, WindowEventListener ) ); 74 m_pTabListBox = nullptr; 75 break; 76 } 77 78 case VclEventId::ControlGetFocus : 79 case VclEventId::ControlLoseFocus : 80 { 81 uno::Any aOldValue, aNewValue; 82 if ( nEventId == VclEventId::ControlGetFocus ) 83 aNewValue <<= AccessibleStateType::FOCUSED; 84 else 85 aOldValue <<= AccessibleStateType::FOCUSED; 86 commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue ); 87 break; 88 } 89 90 case VclEventId::ListboxSelect : 91 { 92 // First send an event that tells the listeners of a 93 // modified selection. The active descendant event is 94 // send after that so that the receiving AT has time to 95 // read the text or name of the active child. 96 commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() ); 97 if ( m_pTabListBox && m_pTabListBox->HasFocus() ) 98 { 99 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() ); 100 if ( pEntry ) 101 { 102 sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry ); 103 sal_uInt16 nCol = m_pTabListBox->GetCurrColumn(); 104 Reference< XAccessible > xChild = 105 m_pTabListBox->CreateAccessibleCell( nRow, nCol ); 106 uno::Any aOldValue, aNewValue; 107 aNewValue <<= xChild; 108 commitEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aNewValue, aOldValue ); 109 } 110 } 111 break; 112 } 113 case VclEventId::WindowGetFocus : 114 { 115 uno::Any aOldValue, aNewValue; 116 aNewValue <<= AccessibleStateType::FOCUSED; 117 commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue ); 118 break; 119 120 } 121 case VclEventId::WindowLoseFocus : 122 { 123 uno::Any aOldValue, aNewValue; 124 aOldValue <<= AccessibleStateType::FOCUSED; 125 commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue ); 126 break; 127 } 128 case VclEventId::ListboxTreeSelect: 129 { 130 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() ); 131 if (pEntry) 132 { 133 sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry ); 134 Reference< XAccessible > xChild = m_pTabListBox->CreateAccessibleCell( nRow, m_pTabListBox->GetCurrColumn() ); 135 TriState eState = TRISTATE_INDET; 136 if ( m_pTabListBox->IsCellCheckBox( nRow, m_pTabListBox->GetCurrColumn(), eState ) ) 137 { 138 AccessibleCheckBoxCell* pCell = static_cast< AccessibleCheckBoxCell* >( xChild.get() ); 139 pCell->commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() ); 140 } 141 else 142 { 143 AccessibleBrowseBoxTableCell* pCell = static_cast< AccessibleBrowseBoxTableCell* >( xChild.get() ); 144 pCell->commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() ); 145 } 146 } 147 } 148 break; 149 case VclEventId::ListboxTreeFocus: 150 { 151 if ( m_pTabListBox && m_pTabListBox->HasFocus() ) 152 { 153 uno::Any aOldValue, aNewValue; 154 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() ); 155 if ( pEntry ) 156 { 157 sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry ); 158 m_xCurChild = m_pTabListBox->CreateAccessibleCell( nRow, m_pTabListBox->GetCurrColumn() ); 159 aNewValue <<= m_xCurChild; 160 commitEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aNewValue ,aOldValue); 161 } 162 else 163 { 164 aNewValue <<= AccessibleStateType::FOCUSED; 165 commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue ,aOldValue); 166 } 167 } 168 } 169 break; 170 171 case VclEventId::CheckboxToggle : 172 { 173 if ( m_pTabListBox && m_pTabListBox->HasFocus() ) 174 { 175 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() ); 176 if ( pEntry ) 177 { 178 sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry ); 179 sal_uInt16 nCol = m_pTabListBox->GetCurrColumn(); 180 TriState eState = TRISTATE_INDET; 181 if ( m_pTabListBox->IsCellCheckBox( nRow, nCol, eState ) ) 182 { 183 Reference< XAccessible > xChild = 184 m_pTabListBox->CreateAccessibleCell( nRow, nCol ); 185 AccessibleCheckBoxCell* pCell = 186 static_cast< AccessibleCheckBoxCell* >( xChild.get() ); 187 pCell->SetChecked( SvHeaderTabListBox::IsItemChecked( pEntry, nCol ) ); 188 } 189 } 190 } 191 break; 192 } 193 194 default: break; 195 } 196 } 197 IMPL_LINK(AccessibleTabListBoxTable,WindowEventListener,VclWindowEvent &,rEvent,void)198 IMPL_LINK( AccessibleTabListBoxTable, WindowEventListener, VclWindowEvent&, rEvent, void ) 199 { 200 OSL_ENSURE( rEvent.GetWindow() && m_pTabListBox, "no event window" ); 201 ProcessWindowEvent( rEvent ); 202 } 203 // helpers -------------------------------------------------------------------- 204 ensureValidIndex(sal_Int32 _nIndex) const205 void AccessibleTabListBoxTable::ensureValidIndex( sal_Int32 _nIndex ) const 206 { 207 if ( ( _nIndex < 0 ) || ( _nIndex >= (implGetRowCount() * implGetColumnCount()) ) ) 208 throw IndexOutOfBoundsException(); 209 } 210 implSelectRow(sal_Int32 _nRow,bool _bSelect)211 void AccessibleTabListBoxTable::implSelectRow( sal_Int32 _nRow, bool _bSelect ) 212 { 213 if ( m_pTabListBox ) 214 m_pTabListBox->Select( m_pTabListBox->GetEntry( _nRow ), _bSelect ); 215 } 216 implGetRowCount() const217 sal_Int32 AccessibleTabListBoxTable::implGetRowCount() const 218 { 219 return m_pTabListBox ? m_pTabListBox->GetEntryCount() : 0; 220 } 221 implGetColumnCount() const222 sal_Int32 AccessibleTabListBoxTable::implGetColumnCount() const 223 { 224 return m_pTabListBox ? m_pTabListBox->GetColumnCount() : 0; 225 } 226 implGetSelRowCount() const227 sal_Int32 AccessibleTabListBoxTable::implGetSelRowCount() const 228 { 229 return m_pTabListBox ? m_pTabListBox->GetSelectionCount() : 0; 230 } 231 implGetSelRow(sal_Int32 nSelRow) const232 sal_Int32 AccessibleTabListBoxTable::implGetSelRow( sal_Int32 nSelRow ) const 233 { 234 if ( m_pTabListBox ) 235 { 236 sal_Int32 nRow = 0; 237 SvTreeListEntry* pEntry = m_pTabListBox->FirstSelected(); 238 while ( pEntry ) 239 { 240 ++nRow; 241 if ( nRow == nSelRow ) 242 return m_pTabListBox->GetEntryPos( pEntry ); 243 pEntry = m_pTabListBox->NextSelected( pEntry ); 244 } 245 } 246 247 return 0; 248 } 249 250 // XInterface & XTypeProvider 251 IMPLEMENT_FORWARD_XINTERFACE2(AccessibleTabListBoxTable,AccessibleBrowseBoxTable,AccessibleTabListBoxTableImplHelper)252 IMPLEMENT_FORWARD_XINTERFACE2(AccessibleTabListBoxTable, AccessibleBrowseBoxTable, AccessibleTabListBoxTableImplHelper) 253 IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleTabListBoxTable, AccessibleBrowseBoxTable, AccessibleTabListBoxTableImplHelper) 254 255 // XServiceInfo 256 257 OUString AccessibleTabListBoxTable::getImplementationName() 258 { 259 return "com.sun.star.comp.svtools.AccessibleTabListBoxTable"; 260 } 261 262 // XAccessibleSelection 263 selectAccessibleChild(sal_Int32 nChildIndex)264 void SAL_CALL AccessibleTabListBoxTable::selectAccessibleChild( sal_Int32 nChildIndex ) 265 { 266 SolarMutexGuard aSolarGuard; 267 ::osl::MutexGuard aGuard( getMutex() ); 268 269 ensureIsAlive(); 270 ensureValidIndex( nChildIndex ); 271 272 implSelectRow( implGetRow( nChildIndex ), true ); 273 } 274 isAccessibleChildSelected(sal_Int32 nChildIndex)275 sal_Bool SAL_CALL AccessibleTabListBoxTable::isAccessibleChildSelected( sal_Int32 nChildIndex ) 276 { 277 SolarMutexGuard aSolarGuard; 278 ::osl::MutexGuard aGuard( getMutex() ); 279 280 ensureIsAlive(); 281 ensureValidIndex( nChildIndex ); 282 283 return m_pTabListBox && m_pTabListBox->IsSelected( m_pTabListBox->GetEntry( implGetRow( nChildIndex ) ) ); 284 } 285 clearAccessibleSelection()286 void SAL_CALL AccessibleTabListBoxTable::clearAccessibleSelection( ) 287 { 288 SolarMutexGuard aSolarGuard; 289 ::osl::MutexGuard aGuard( getMutex() ); 290 291 ensureIsAlive(); 292 293 m_pTabListBox->SetNoSelection(); 294 } 295 selectAllAccessibleChildren()296 void SAL_CALL AccessibleTabListBoxTable::selectAllAccessibleChildren( ) 297 { 298 SolarMutexGuard aSolarGuard; 299 ::osl::MutexGuard aGuard( getMutex() ); 300 301 ensureIsAlive(); 302 303 m_pTabListBox->SelectAll(); 304 } 305 getSelectedAccessibleChildCount()306 sal_Int32 SAL_CALL AccessibleTabListBoxTable::getSelectedAccessibleChildCount( ) 307 { 308 SolarMutexGuard aSolarGuard; 309 ::osl::MutexGuard aGuard( getMutex() ); 310 311 ensureIsAlive(); 312 313 return implGetColumnCount() * implGetSelRowCount(); 314 } 315 getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)316 Reference< XAccessible > SAL_CALL AccessibleTabListBoxTable::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) 317 { 318 SolarMutexGuard aSolarGuard; 319 ::osl::MutexGuard aGuard( getMutex() ); 320 321 ensureIsAlive(); 322 323 sal_Int32 nRows = implGetSelRowCount(); 324 if ( nRows == 0 ) 325 throw IndexOutOfBoundsException(); 326 327 sal_Int32 nRow = implGetSelRow( nSelectedChildIndex % nRows ); 328 sal_Int32 nColumn = nSelectedChildIndex / nRows; 329 return getAccessibleCellAt( nRow, nColumn ); 330 } 331 deselectAccessibleChild(sal_Int32 nSelectedChildIndex)332 void SAL_CALL AccessibleTabListBoxTable::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) 333 { 334 SolarMutexGuard aSolarGuard; 335 ::osl::MutexGuard aGuard( getMutex() ); 336 337 ensureIsAlive(); 338 ensureValidIndex( nSelectedChildIndex ); 339 340 implSelectRow( implGetRow( nSelectedChildIndex ), false ); 341 } 342 343 344 }// namespace accessibility 345 346 347 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 348