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 { 132 TCSolarGuard aSolarGuard; 133 ::osl::MutexGuard aGuard( getOslMutex() ); 134 ensureIsAlive(); 135 return m_aTable.GetAccessibleControlCount(); 136 } 137 // ----------------------------------------------------------------------------- 138 139 Reference< XAccessible > SAL_CALL 140 AccessibleGridControl::getAccessibleChild( sal_Int32 nChildIndex ) 141 { 142 TCSolarGuard aSolarGuard; 143 ::osl::MutexGuard aGuard( getOslMutex() ); 144 145 if (nChildIndex<0 || nChildIndex>=getAccessibleChildCount()) 146 throw IndexOutOfBoundsException(); 147 148 Reference< XAccessible > xChild; 149 if (isAlive()) 150 { 151 if(nChildIndex == 0 && m_aTable.HasColHeader()) 152 { 153 if(!m_pImpl->m_xColumnHeaderBar.is()) 154 { 155 AccessibleGridControlHeader* pColHeaderBar = new AccessibleGridControlHeader(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_COLUMNHEADERBAR); 156 m_pImpl->m_xColumnHeaderBar = pColHeaderBar; 157 } 158 xChild = m_pImpl->m_xColumnHeaderBar; 159 } 160 else if(m_aTable.HasRowHeader() && (nChildIndex == 1 || nChildIndex == 0)) 161 { 162 if(!m_pImpl->m_xRowHeaderBar.is()) 163 { 164 AccessibleGridControlHeader* pRowHeaderBar = new AccessibleGridControlHeader(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_ROWHEADERBAR); 165 m_pImpl->m_xRowHeaderBar = pRowHeaderBar; 166 } 167 xChild = m_pImpl->m_xRowHeaderBar; 168 } 169 else 170 { 171 if(!m_pImpl->m_xTable.is()) 172 { 173 AccessibleGridControlTable* pTable = new AccessibleGridControlTable(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_TABLE); 174 m_pImpl->m_xTable = pTable; 175 m_pImpl->m_pTable = pTable; 176 } 177 xChild = m_pImpl->m_xTable; 178 } 179 } 180 return xChild; 181 } 182 // ----------------------------------------------------------------------------- 183 184 sal_Int16 SAL_CALL AccessibleGridControl::getAccessibleRole() 185 { 186 ensureIsAlive(); 187 return AccessibleRole::PANEL; 188 } 189 // ----------------------------------------------------------------------------- 190 191 // XAccessibleComponent ------------------------------------------------------- 192 193 Reference< XAccessible > SAL_CALL 194 AccessibleGridControl::getAccessibleAtPoint( const awt::Point& rPoint ) 195 { 196 TCSolarGuard aSolarGuard; 197 ::osl::MutexGuard aGuard( getOslMutex() ); 198 ensureIsAlive(); 199 200 Reference< XAccessible > xChild; 201 sal_Int32 nIndex = 0; 202 if( m_aTable.ConvertPointToControlIndex( nIndex, VCLPoint( rPoint ) ) ) 203 xChild = m_aTable.CreateAccessibleControl( nIndex ); 204 else 205 { 206 // try whether point is in one of the fixed children 207 // (table, header bars, corner control) 208 Point aPoint( VCLPoint( rPoint ) ); 209 for( nIndex = 0; (nIndex < 3) && !xChild.is(); ++nIndex ) 210 { 211 Reference< XAccessible > xCurrChild( implGetFixedChild( nIndex ) ); 212 Reference< XAccessibleComponent > 213 xCurrChildComp( xCurrChild, uno::UNO_QUERY ); 214 215 if( xCurrChildComp.is() && 216 VCLRectangle( xCurrChildComp->getBounds() ).IsInside( aPoint ) ) 217 xChild = xCurrChild; 218 } 219 } 220 return xChild; 221 } 222 // ----------------------------------------------------------------------------- 223 224 void SAL_CALL AccessibleGridControl::grabFocus() 225 { 226 TCSolarGuard aSolarGuard; 227 ::osl::MutexGuard aGuard( getOslMutex() ); 228 ensureIsAlive(); 229 m_aTable.GrabFocus(); 230 } 231 // ----------------------------------------------------------------------------- 232 233 Any SAL_CALL AccessibleGridControl::getAccessibleKeyBinding() 234 { 235 ensureIsAlive(); 236 return Any(); 237 } 238 // ----------------------------------------------------------------------------- 239 240 // XServiceInfo --------------------------------------------------------------- 241 242 OUString SAL_CALL AccessibleGridControl::getImplementationName() 243 { 244 return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.AccessibleGridControl" ) ); 245 } 246 // ----------------------------------------------------------------------------- 247 248 // internal virtual methods --------------------------------------------------- 249 250 Rectangle AccessibleGridControl::implGetBoundingBox() 251 { 252 Window* pParent = m_aTable.GetAccessibleParentWindow(); 253 DBG_ASSERT( pParent, "implGetBoundingBox - missing parent window" ); 254 return m_aTable.GetWindowExtentsRelative( pParent ); 255 } 256 // ----------------------------------------------------------------------------- 257 258 Rectangle AccessibleGridControl::implGetBoundingBoxOnScreen() 259 { 260 return m_aTable.GetWindowExtentsRelative( NULL ); 261 } 262 // internal helper methods ---------------------------------------------------- 263 264 Reference< XAccessible > AccessibleGridControl::implGetTable() 265 { 266 if( !m_pImpl->m_xTable.is() ) 267 { 268 m_pImpl->m_pTable = createAccessibleTable(); 269 m_pImpl->m_xTable = m_pImpl->m_pTable; 270 } 271 return m_pImpl->m_xTable; 272 } 273 // ----------------------------------------------------------------------------- 274 275 Reference< XAccessible > 276 AccessibleGridControl::implGetHeaderBar( AccessibleTableControlObjType eObjType ) 277 { 278 Reference< XAccessible > xRet; 279 Reference< XAccessible >* pxMember = NULL; 280 281 if( eObjType == TCTYPE_ROWHEADERBAR ) 282 pxMember = &m_pImpl->m_xRowHeaderBar; 283 else if( eObjType == TCTYPE_COLUMNHEADERBAR ) 284 pxMember = &m_pImpl->m_xColumnHeaderBar; 285 286 if( pxMember ) 287 { 288 if( !pxMember->is() ) 289 { 290 AccessibleGridControlHeader* pHeaderBar = new AccessibleGridControlHeader( 291 (Reference< XAccessible >)m_pImpl->m_aCreator, m_aTable, eObjType ); 292 293 if ( TCTYPE_COLUMNHEADERBAR == eObjType) 294 m_pImpl->m_pColumnHeaderBar = pHeaderBar; 295 else 296 m_pImpl->m_pRowHeaderBar = pHeaderBar; 297 298 *pxMember = pHeaderBar; 299 } 300 xRet = *pxMember; 301 } 302 return xRet; 303 } 304 // ----------------------------------------------------------------------------- 305 Reference< XAccessible > 306 AccessibleGridControl::implGetFixedChild( sal_Int32 nChildIndex ) 307 { 308 Reference< XAccessible > xRet; 309 switch( nChildIndex ) 310 { 311 case TCINDEX_COLUMNHEADERBAR: 312 xRet = implGetHeaderBar( TCTYPE_COLUMNHEADERBAR ); 313 break; 314 case TCINDEX_ROWHEADERBAR: 315 xRet = implGetHeaderBar( TCTYPE_ROWHEADERBAR ); 316 break; 317 case TCINDEX_TABLE: 318 xRet = implGetTable(); 319 break; 320 } 321 return xRet; 322 } 323 // ----------------------------------------------------------------------------- 324 AccessibleGridControlTable* AccessibleGridControl::createAccessibleTable() 325 { 326 Reference< XAccessible > xCreator = (Reference< XAccessible >)m_pImpl->m_aCreator; 327 DBG_ASSERT( xCreator.is(), "accessibility/extended/AccessibleGirdControl::createAccessibleTable: my creator died - how this?" ); 328 return new AccessibleGridControlTable( xCreator, m_aTable, TCTYPE_TABLE ); 329 } 330 // ----------------------------------------------------------------------------- 331 void AccessibleGridControl::commitCellEvent(sal_Int16 _nEventId,const Any& _rNewValue,const Any& _rOldValue) 332 { 333 sal_Int32 nChildCount = getAccessibleChildCount(); 334 if(nChildCount != 0) 335 { 336 for(sal_Int32 i=0;i<nChildCount;i++) 337 { 338 Reference< XAccessible > xAccessible = getAccessibleChild(i); 339 com::sun::star::uno::Reference< com::sun::star::accessibility::XAccessibleContext > xAccessibleChild = xAccessible->getAccessibleContext(); 340 if(m_pImpl->m_xTable == xAccessible) 341 { 342 std::vector< AccessibleGridControlTableCell* > xCellCont = m_pImpl->m_pTable->getCellVector(); 343 int nIndex = m_aTable.GetCurrentRow()*m_aTable.GetColumnCount()+m_aTable.GetCurrentColumn(); 344 if(!xCellCont.empty() && xCellCont[nIndex]) 345 { 346 m_pImpl->m_pCell = xCellCont[nIndex]; 347 m_pImpl->m_pCell->commitEvent( _nEventId, _rNewValue, _rOldValue ); 348 } 349 } 350 } 351 } 352 else 353 { 354 if ( m_pImpl->m_xTable.is() ) 355 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue); 356 } 357 } 358 void AccessibleGridControl::commitTableEvent(sal_Int16 _nEventId,const Any& _rNewValue,const Any& _rOldValue) 359 { 360 if ( m_pImpl->m_xTable.is() ) 361 { 362 if(_nEventId == AccessibleEventId::ACTIVE_DESCENDANT_CHANGED) 363 { 364 Reference< XAccessible > xChild = m_pImpl->m_pTable->getAccessibleChild(m_aTable.GetCurrentRow()*m_aTable.GetColumnCount()+m_aTable.GetCurrentColumn()); 365 m_pImpl->m_pTable->commitEvent(_nEventId, makeAny(xChild),_rOldValue); 366 } 367 else if(_nEventId == AccessibleEventId::TABLE_MODEL_CHANGED) 368 { 369 AccessibleTableModelChange aChange; 370 if(_rNewValue >>= aChange) 371 { 372 if(aChange.Type == AccessibleTableModelChangeType::DELETE) 373 { 374 std::vector< AccessibleGridControlTableCell* >::iterator m_pCell = m_pImpl->m_pTable->getCellVector().begin(); 375 std::vector< Reference< XAccessible > >::iterator m_xAccessibleVector = m_pImpl->m_pTable->getAccessibleCellVector().begin(); 376 int nColCount = m_aTable.GetColumnCount(); 377 m_pImpl->m_pTable->getCellVector().erase(m_pCell+nColCount*aChange.FirstRow, m_pCell+nColCount*aChange.LastRow ); 378 m_pImpl->m_pTable->getAccessibleCellVector().erase(m_xAccessibleVector+nColCount*aChange.FirstRow, m_xAccessibleVector+nColCount*aChange.LastRow); 379 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue); 380 } 381 else 382 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue); 383 } 384 } 385 else 386 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue); 387 } 388 } 389 // ============================================================================ 390 // = AccessibleGridControlAccess 391 // ============================================================================ 392 DBG_NAME( AccessibleGridControlAccess ) 393 // ----------------------------------------------------------------------------- 394 AccessibleGridControlAccess::AccessibleGridControlAccess( const Reference< XAccessible >& _rxParent, IAccessibleTable& _rTable ) 395 :m_xParent( _rxParent ) 396 ,m_rTable( _rTable ) 397 ,m_pContext( NULL ) 398 { 399 } 400 401 // ----------------------------------------------------------------------------- 402 AccessibleGridControlAccess::~AccessibleGridControlAccess() 403 { 404 } 405 406 // ----------------------------------------------------------------------------- 407 void AccessibleGridControlAccess::dispose() 408 { 409 ::osl::MutexGuard aGuard( m_aMutex ); 410 411 m_pContext = NULL; 412 ::comphelper::disposeComponent( m_xContext ); 413 } 414 415 // ----------------------------------------------------------------------------- 416 Reference< XAccessibleContext > SAL_CALL AccessibleGridControlAccess::getAccessibleContext() 417 { 418 ::osl::MutexGuard aGuard( m_aMutex ); 419 420 DBG_ASSERT( ( m_pContext && m_xContext.is() ) || ( !m_pContext && !m_xContext.is() ), 421 "accessibility/extended/AccessibleGridControlAccess::getAccessibleContext: inconsistency!" ); 422 423 // if the context died meanwhile (we're no listener, so it won't tell us explicitly when this happens), 424 // then reset an re-create. 425 if ( m_pContext && !m_pContext->isAlive() ) 426 m_xContext = m_pContext = NULL; 427 428 if ( !m_xContext.is() ) 429 m_xContext = m_pContext = new AccessibleGridControl( m_xParent, this, m_rTable ); 430 431 return m_xContext; 432 } 433 434 // ----------------------------------------------------------------------------- 435 bool AccessibleGridControlAccess::isContextAlive() const 436 { 437 return ( NULL != m_pContext ) && m_pContext->isAlive(); 438 } 439 440 // ============================================================================ 441 442 } // namespace accessibility 443