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/extended/AccessibleGridControl.hxx" 27 #include "accessibility/extended/AccessibleGridControlTable.hxx" 28 #include "accessibility/extended/AccessibleGridControlHeader.hxx" 29 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 30 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp> 31 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp> 32 #include <svtools/accessibletable.hxx> 33 #include <comphelper/types.hxx> 34 #include <toolkit/helper/vclunohelper.hxx> 35 36 // ============================================================================ 37 38 namespace accessibility 39 { 40 41 // ============================================================================ 42 43 using ::rtl::OUString; 44 45 using namespace ::com::sun::star::uno; 46 using namespace ::com::sun::star; 47 using namespace ::com::sun::star::lang; 48 using namespace ::com::sun::star::accessibility; 49 using namespace ::svt; 50 using namespace ::svt::table; 51 52 // ============================================================================ 53 class AccessibleGridControl_Impl 54 { 55 public: 56 /// the XAccessible which created the AccessibleGridControl 57 WeakReference< XAccessible > m_aCreator; 58 59 /** The data table child. */ 60 Reference< 61 ::com::sun::star::accessibility::XAccessible > m_xTable; 62 AccessibleGridControlTable* m_pTable; 63 64 /** The header bar for rows. */ 65 Reference< 66 ::com::sun::star::accessibility::XAccessible > m_xRowHeaderBar; 67 AccessibleGridControlHeader* m_pRowHeaderBar; 68 69 /** The header bar for columns (first row of the table). */ 70 Reference< 71 ::com::sun::star::accessibility::XAccessible > m_xColumnHeaderBar; 72 AccessibleGridControlHeader* m_pColumnHeaderBar; 73 74 /** The table cell child. */ 75 Reference< 76 ::com::sun::star::accessibility::XAccessible > m_xCell; 77 AccessibleGridControlTableCell* m_pCell; 78 }; 79 80 DBG_NAME( AccessibleGridControl ) 81 82 AccessibleGridControl::AccessibleGridControl( 83 const Reference< XAccessible >& _rxParent, const Reference< XAccessible >& _rxCreator, 84 IAccessibleTable& _rTable ) 85 : AccessibleGridControlBase( _rxParent, _rTable, TCTYPE_GRIDCONTROL ) 86 { 87 m_pImpl.reset( new AccessibleGridControl_Impl() ); 88 m_pImpl->m_aCreator = _rxCreator; 89 } 90 91 // ----------------------------------------------------------------------------- 92 AccessibleGridControl::~AccessibleGridControl() 93 { 94 } 95 // ----------------------------------------------------------------------------- 96 97 void SAL_CALL AccessibleGridControl::disposing() 98 { 99 ::osl::MutexGuard aGuard( getOslMutex() ); 100 101 m_pImpl->m_pTable = NULL; 102 m_pImpl->m_pColumnHeaderBar = NULL; 103 m_pImpl->m_pRowHeaderBar = NULL; 104 m_pImpl->m_pCell = NULL; 105 m_pImpl->m_aCreator = Reference< XAccessible >(); 106 107 Reference< XAccessible > xTable = m_pImpl->m_xTable; 108 109 Reference< XComponent > xComp( m_pImpl->m_xTable, UNO_QUERY ); 110 if ( xComp.is() ) 111 { 112 xComp->dispose(); 113 } 114 Reference< XAccessible > xCell = m_pImpl->m_xCell; 115 116 Reference< XComponent > xCellComp( m_pImpl->m_xCell, UNO_QUERY ); 117 if ( xCellComp.is() ) 118 { 119 xCellComp->dispose(); 120 } 121 122 ::comphelper::disposeComponent(m_pImpl->m_xRowHeaderBar); 123 ::comphelper::disposeComponent(m_pImpl->m_xColumnHeaderBar); 124 AccessibleGridControlBase::disposing(); 125 } 126 // ----------------------------------------------------------------------------- 127 128 // XAccessibleContext --------------------------------------------------------- 129 130 sal_Int32 SAL_CALL AccessibleGridControl::getAccessibleChildCount() 131 throw ( uno::RuntimeException ) 132 { 133 TCSolarGuard aSolarGuard; 134 ::osl::MutexGuard aGuard( getOslMutex() ); 135 ensureIsAlive(); 136 return m_aTable.GetAccessibleControlCount(); 137 } 138 // ----------------------------------------------------------------------------- 139 140 Reference< XAccessible > SAL_CALL 141 AccessibleGridControl::getAccessibleChild( sal_Int32 nChildIndex ) 142 throw ( lang::IndexOutOfBoundsException, uno::RuntimeException ) 143 { 144 TCSolarGuard aSolarGuard; 145 ::osl::MutexGuard aGuard( getOslMutex() ); 146 147 if (nChildIndex<0 || nChildIndex>=getAccessibleChildCount()) 148 throw IndexOutOfBoundsException(); 149 150 Reference< XAccessible > xChild; 151 if (isAlive()) 152 { 153 if(nChildIndex == 0 && m_aTable.HasColHeader()) 154 { 155 if(!m_pImpl->m_xColumnHeaderBar.is()) 156 { 157 AccessibleGridControlHeader* pColHeaderBar = new AccessibleGridControlHeader(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_COLUMNHEADERBAR); 158 m_pImpl->m_xColumnHeaderBar = pColHeaderBar; 159 } 160 xChild = m_pImpl->m_xColumnHeaderBar; 161 } 162 else if(m_aTable.HasRowHeader() && (nChildIndex == 1 || nChildIndex == 0)) 163 { 164 if(!m_pImpl->m_xRowHeaderBar.is()) 165 { 166 AccessibleGridControlHeader* pRowHeaderBar = new AccessibleGridControlHeader(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_ROWHEADERBAR); 167 m_pImpl->m_xRowHeaderBar = pRowHeaderBar; 168 } 169 xChild = m_pImpl->m_xRowHeaderBar; 170 } 171 else 172 { 173 if(!m_pImpl->m_xTable.is()) 174 { 175 AccessibleGridControlTable* pTable = new AccessibleGridControlTable(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_TABLE); 176 m_pImpl->m_xTable = pTable; 177 m_pImpl->m_pTable = pTable; 178 } 179 xChild = m_pImpl->m_xTable; 180 } 181 } 182 return xChild; 183 } 184 // ----------------------------------------------------------------------------- 185 186 sal_Int16 SAL_CALL AccessibleGridControl::getAccessibleRole() 187 throw ( uno::RuntimeException ) 188 { 189 ensureIsAlive(); 190 return AccessibleRole::PANEL; 191 } 192 // ----------------------------------------------------------------------------- 193 194 // XAccessibleComponent ------------------------------------------------------- 195 196 Reference< XAccessible > SAL_CALL 197 AccessibleGridControl::getAccessibleAtPoint( const awt::Point& rPoint ) 198 throw ( uno::RuntimeException ) 199 { 200 TCSolarGuard aSolarGuard; 201 ::osl::MutexGuard aGuard( getOslMutex() ); 202 ensureIsAlive(); 203 204 Reference< XAccessible > xChild; 205 sal_Int32 nIndex = 0; 206 if( m_aTable.ConvertPointToControlIndex( nIndex, VCLPoint( rPoint ) ) ) 207 xChild = m_aTable.CreateAccessibleControl( nIndex ); 208 else 209 { 210 // try whether point is in one of the fixed children 211 // (table, header bars, corner control) 212 Point aPoint( VCLPoint( rPoint ) ); 213 for( nIndex = 0; (nIndex < 3) && !xChild.is(); ++nIndex ) 214 { 215 Reference< XAccessible > xCurrChild( implGetFixedChild( nIndex ) ); 216 Reference< XAccessibleComponent > 217 xCurrChildComp( xCurrChild, uno::UNO_QUERY ); 218 219 if( xCurrChildComp.is() && 220 VCLRectangle( xCurrChildComp->getBounds() ).IsInside( aPoint ) ) 221 xChild = xCurrChild; 222 } 223 } 224 return xChild; 225 } 226 // ----------------------------------------------------------------------------- 227 228 void SAL_CALL AccessibleGridControl::grabFocus() 229 throw ( uno::RuntimeException ) 230 { 231 TCSolarGuard aSolarGuard; 232 ::osl::MutexGuard aGuard( getOslMutex() ); 233 ensureIsAlive(); 234 m_aTable.GrabFocus(); 235 } 236 // ----------------------------------------------------------------------------- 237 238 Any SAL_CALL AccessibleGridControl::getAccessibleKeyBinding() 239 throw ( uno::RuntimeException ) 240 { 241 ensureIsAlive(); 242 return Any(); 243 } 244 // ----------------------------------------------------------------------------- 245 246 // XServiceInfo --------------------------------------------------------------- 247 248 OUString SAL_CALL AccessibleGridControl::getImplementationName() 249 throw ( uno::RuntimeException ) 250 { 251 return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.AccessibleGridControl" ) ); 252 } 253 // ----------------------------------------------------------------------------- 254 255 // internal virtual methods --------------------------------------------------- 256 257 Rectangle AccessibleGridControl::implGetBoundingBox() 258 { 259 Window* pParent = m_aTable.GetAccessibleParentWindow(); 260 DBG_ASSERT( pParent, "implGetBoundingBox - missing parent window" ); 261 return m_aTable.GetWindowExtentsRelative( pParent ); 262 } 263 // ----------------------------------------------------------------------------- 264 265 Rectangle AccessibleGridControl::implGetBoundingBoxOnScreen() 266 { 267 return m_aTable.GetWindowExtentsRelative( NULL ); 268 } 269 // internal helper methods ---------------------------------------------------- 270 271 Reference< XAccessible > AccessibleGridControl::implGetTable() 272 { 273 if( !m_pImpl->m_xTable.is() ) 274 { 275 m_pImpl->m_pTable = createAccessibleTable(); 276 m_pImpl->m_xTable = m_pImpl->m_pTable; 277 } 278 return m_pImpl->m_xTable; 279 } 280 // ----------------------------------------------------------------------------- 281 282 Reference< XAccessible > 283 AccessibleGridControl::implGetHeaderBar( AccessibleTableControlObjType eObjType ) 284 { 285 Reference< XAccessible > xRet; 286 Reference< XAccessible >* pxMember = NULL; 287 288 if( eObjType == TCTYPE_ROWHEADERBAR ) 289 pxMember = &m_pImpl->m_xRowHeaderBar; 290 else if( eObjType == TCTYPE_COLUMNHEADERBAR ) 291 pxMember = &m_pImpl->m_xColumnHeaderBar; 292 293 if( pxMember ) 294 { 295 if( !pxMember->is() ) 296 { 297 AccessibleGridControlHeader* pHeaderBar = new AccessibleGridControlHeader( 298 (Reference< XAccessible >)m_pImpl->m_aCreator, m_aTable, eObjType ); 299 300 if ( TCTYPE_COLUMNHEADERBAR == eObjType) 301 m_pImpl->m_pColumnHeaderBar = pHeaderBar; 302 else 303 m_pImpl->m_pRowHeaderBar = pHeaderBar; 304 305 *pxMember = pHeaderBar; 306 } 307 xRet = *pxMember; 308 } 309 return xRet; 310 } 311 // ----------------------------------------------------------------------------- 312 Reference< XAccessible > 313 AccessibleGridControl::implGetFixedChild( sal_Int32 nChildIndex ) 314 { 315 Reference< XAccessible > xRet; 316 switch( nChildIndex ) 317 { 318 case TCINDEX_COLUMNHEADERBAR: 319 xRet = implGetHeaderBar( TCTYPE_COLUMNHEADERBAR ); 320 break; 321 case TCINDEX_ROWHEADERBAR: 322 xRet = implGetHeaderBar( TCTYPE_ROWHEADERBAR ); 323 break; 324 case TCINDEX_TABLE: 325 xRet = implGetTable(); 326 break; 327 } 328 return xRet; 329 } 330 // ----------------------------------------------------------------------------- 331 AccessibleGridControlTable* AccessibleGridControl::createAccessibleTable() 332 { 333 Reference< XAccessible > xCreator = (Reference< XAccessible >)m_pImpl->m_aCreator; 334 DBG_ASSERT( xCreator.is(), "accessibility/extended/AccessibleGirdControl::createAccessibleTable: my creator died - how this?" ); 335 return new AccessibleGridControlTable( xCreator, m_aTable, TCTYPE_TABLE ); 336 } 337 // ----------------------------------------------------------------------------- 338 void AccessibleGridControl::commitCellEvent(sal_Int16 _nEventId,const Any& _rNewValue,const Any& _rOldValue) 339 { 340 sal_Int32 nChildCount = getAccessibleChildCount(); 341 if(nChildCount != 0) 342 { 343 for(sal_Int32 i=0;i<nChildCount;i++) 344 { 345 Reference< XAccessible > xAccessible = getAccessibleChild(i); 346 com::sun::star::uno::Reference< com::sun::star::accessibility::XAccessibleContext > xAccessibleChild = xAccessible->getAccessibleContext(); 347 if(m_pImpl->m_xTable == xAccessible) 348 { 349 std::vector< AccessibleGridControlTableCell* > xCellCont = m_pImpl->m_pTable->getCellVector(); 350 int nIndex = m_aTable.GetCurrentRow()*m_aTable.GetColumnCount()+m_aTable.GetCurrentColumn(); 351 if(!xCellCont.empty() && xCellCont[nIndex]) 352 { 353 m_pImpl->m_pCell = xCellCont[nIndex]; 354 m_pImpl->m_pCell->commitEvent( _nEventId, _rNewValue, _rOldValue ); 355 } 356 } 357 } 358 } 359 else 360 { 361 if ( m_pImpl->m_xTable.is() ) 362 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue); 363 } 364 } 365 void AccessibleGridControl::commitTableEvent(sal_Int16 _nEventId,const Any& _rNewValue,const Any& _rOldValue) 366 { 367 if ( m_pImpl->m_xTable.is() ) 368 { 369 if(_nEventId == AccessibleEventId::ACTIVE_DESCENDANT_CHANGED) 370 { 371 Reference< XAccessible > xChild = m_pImpl->m_pTable->getAccessibleChild(m_aTable.GetCurrentRow()*m_aTable.GetColumnCount()+m_aTable.GetCurrentColumn()); 372 m_pImpl->m_pTable->commitEvent(_nEventId, makeAny(xChild),_rOldValue); 373 } 374 else if(_nEventId == AccessibleEventId::TABLE_MODEL_CHANGED) 375 { 376 AccessibleTableModelChange aChange; 377 if(_rNewValue >>= aChange) 378 { 379 if(aChange.Type == AccessibleTableModelChangeType::DELETE) 380 { 381 std::vector< AccessibleGridControlTableCell* >::iterator m_pCell = m_pImpl->m_pTable->getCellVector().begin(); 382 std::vector< Reference< XAccessible > >::iterator m_xAccessibleVector = m_pImpl->m_pTable->getAccessibleCellVector().begin(); 383 int nColCount = m_aTable.GetColumnCount(); 384 m_pImpl->m_pTable->getCellVector().erase(m_pCell+nColCount*aChange.FirstRow, m_pCell+nColCount*aChange.LastRow ); 385 m_pImpl->m_pTable->getAccessibleCellVector().erase(m_xAccessibleVector+nColCount*aChange.FirstRow, m_xAccessibleVector+nColCount*aChange.LastRow); 386 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue); 387 } 388 else 389 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue); 390 } 391 } 392 else 393 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue); 394 } 395 } 396 // ============================================================================ 397 // = AccessibleGridControlAccess 398 // ============================================================================ 399 DBG_NAME( AccessibleGridControlAccess ) 400 // ----------------------------------------------------------------------------- 401 AccessibleGridControlAccess::AccessibleGridControlAccess( const Reference< XAccessible >& _rxParent, IAccessibleTable& _rTable ) 402 :m_xParent( _rxParent ) 403 ,m_rTable( _rTable ) 404 ,m_pContext( NULL ) 405 { 406 } 407 408 // ----------------------------------------------------------------------------- 409 AccessibleGridControlAccess::~AccessibleGridControlAccess() 410 { 411 } 412 413 // ----------------------------------------------------------------------------- 414 void AccessibleGridControlAccess::dispose() 415 { 416 ::osl::MutexGuard aGuard( m_aMutex ); 417 418 m_pContext = NULL; 419 ::comphelper::disposeComponent( m_xContext ); 420 } 421 422 // ----------------------------------------------------------------------------- 423 Reference< XAccessibleContext > SAL_CALL AccessibleGridControlAccess::getAccessibleContext() throw ( RuntimeException ) 424 { 425 ::osl::MutexGuard aGuard( m_aMutex ); 426 427 DBG_ASSERT( ( m_pContext && m_xContext.is() ) || ( !m_pContext && !m_xContext.is() ), 428 "accessibility/extended/AccessibleGridControlAccess::getAccessibleContext: inconsistency!" ); 429 430 // if the context died meanwhile (we're no listener, so it won't tell us explicitily when this happens), 431 // then reset an re-create. 432 if ( m_pContext && !m_pContext->isAlive() ) 433 m_xContext = m_pContext = NULL; 434 435 if ( !m_xContext.is() ) 436 m_xContext = m_pContext = new AccessibleGridControl( m_xParent, this, m_rTable ); 437 438 return m_xContext; 439 } 440 441 // ----------------------------------------------------------------------------- 442 bool AccessibleGridControlAccess::isContextAlive() const 443 { 444 return ( NULL != m_pContext ) && m_pContext->isAlive(); 445 } 446 447 // ============================================================================ 448 449 } // namespace accessibility 450