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