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_sw.hxx" 26 27 28 #include <vos/mutex.hxx> 29 #include <com/sun/star/accessibility/AccessibleRole.hpp> 30 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 31 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 32 #include <unotools/accessiblestatesethelper.hxx> 33 #include <rtl/uuid.h> 34 #include <vcl/svapp.hxx> 35 #include <cellfrm.hxx> 36 #include <tabfrm.hxx> 37 #include <swtable.hxx> 38 #include "crsrsh.hxx" 39 #include "viscrs.hxx" 40 #include <accfrmobj.hxx> 41 #include <accfrmobjslist.hxx> 42 #include "frmfmt.hxx" 43 #include "cellatr.hxx" 44 #include "accmap.hxx" 45 #include <acccell.hxx> 46 47 #ifndef _STLP_CFLOAT 48 #include <cfloat> 49 #endif 50 51 #include <limits.h> 52 53 #include <ndtxt.hxx> 54 #include <editeng/brshitem.hxx> 55 #include <swatrset.hxx> 56 #include <frmatr.hxx> 57 #include "acctable.hxx" 58 59 using namespace ::com::sun::star; 60 using namespace ::com::sun::star::accessibility; 61 using ::rtl::OUString; 62 using namespace sw::access; 63 64 const sal_Char sServiceName[] = "com.sun.star.table.AccessibleCellView"; 65 const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleCellView"; 66 67 sal_Bool SwAccessibleCell::IsSelected() 68 { 69 sal_Bool bRet = sal_False; 70 71 DBG_ASSERT( GetMap(), "no map?" ); 72 const ViewShell *pVSh = GetMap()->GetShell(); 73 DBG_ASSERT( pVSh, "no shell?" ); 74 if( pVSh->ISA( SwCrsrShell ) ) 75 { 76 const SwCrsrShell *pCSh = static_cast< const SwCrsrShell * >( pVSh ); 77 if( pCSh->IsTableMode() ) 78 { 79 const SwCellFrm *pCFrm = 80 static_cast< const SwCellFrm * >( GetFrm() ); 81 SwTableBox *pBox = 82 const_cast< SwTableBox *>( pCFrm->GetTabBox() ); //SVPtrArr! 83 bRet = pCSh->GetTableCrsr()->GetBoxes().Seek_Entry( pBox ); 84 } 85 } 86 87 return bRet; 88 } 89 90 void SwAccessibleCell::GetStates( ::utl::AccessibleStateSetHelper& rStateSet ) 91 { 92 SwAccessibleContext::GetStates( rStateSet ); 93 94 // SELECTABLE 95 const ViewShell *pVSh = GetMap()->GetShell(); 96 DBG_ASSERT( pVSh, "no shell?" ); 97 if( pVSh->ISA( SwCrsrShell ) ) 98 rStateSet.AddState( AccessibleStateType::SELECTABLE ); 99 //Solution:Add resizable state to table cell. 100 rStateSet.AddState( AccessibleStateType::RESIZABLE ); 101 102 // SELECTED 103 if( IsSelected() ) 104 { 105 rStateSet.AddState( AccessibleStateType::SELECTED ); 106 ASSERT( bIsSelected, "bSelected out of sync" ); 107 ::vos::ORef < SwAccessibleContext > xThis( this ); 108 GetMap()->SetCursorContext( xThis ); 109 } 110 } 111 112 SwAccessibleCell::SwAccessibleCell( SwAccessibleMap *pInitMap, 113 const SwCellFrm *pCellFrm ) 114 : SwAccessibleContext( pInitMap, AccessibleRole::TABLE_CELL, pCellFrm ) 115 , aSelectionHelper( *this ) 116 , bIsSelected( sal_False ) 117 , m_xTableReference( NULL ) 118 , m_pAccTable( NULL ) 119 { 120 vos::OGuard aGuard( Application::GetSolarMutex() ); 121 OUString sBoxName( pCellFrm->GetTabBox()->GetName() ); 122 SetName( sBoxName ); 123 124 bIsSelected = IsSelected(); 125 126 m_xTableReference = getAccessibleParent(); 127 #if OSL_DEBUG_LEVEL > 1 128 uno::Reference< XAccessibleContext > xContextTable( m_xTableReference, uno::UNO_QUERY ); 129 OSL_ASSERT( xContextTable.is() && xContextTable->getAccessibleRole() == AccessibleRole::TABLE ); 130 #endif 131 m_pAccTable = static_cast< SwAccessibleTable * >( m_xTableReference.get() ); 132 } 133 134 sal_Bool SwAccessibleCell::_InvalidateMyCursorPos() 135 { 136 sal_Bool bNew = IsSelected(); 137 sal_Bool bOld; 138 { 139 vos::OGuard aGuard( aMutex ); 140 bOld = bIsSelected; 141 bIsSelected = bNew; 142 } 143 if( bNew ) 144 { 145 // remember that object as the one that has the caret. This is 146 // neccessary to notify that object if the cursor leaves it. 147 ::vos::ORef < SwAccessibleContext > xThis( this ); 148 GetMap()->SetCursorContext( xThis ); 149 } 150 151 sal_Bool bChanged = bOld != bNew; 152 if( bChanged ) 153 { 154 FireStateChangedEvent( AccessibleStateType::SELECTED, bNew ); 155 if (m_pAccTable) 156 { 157 m_pAccTable->AddSelectionCell(this,bNew); 158 } 159 } 160 return bChanged; 161 } 162 163 sal_Bool SwAccessibleCell::_InvalidateChildrenCursorPos( const SwFrm *pFrm ) 164 { 165 sal_Bool bChanged = sal_False; 166 167 const SwAccessibleChildSList aVisList( GetVisArea(), *pFrm, *GetMap() ); 168 SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); 169 while( aIter != aVisList.end() ) 170 { 171 const SwAccessibleChild& rLower = *aIter; 172 const SwFrm *pLower = rLower.GetSwFrm(); 173 if( pLower ) 174 { 175 if( rLower.IsAccessible( GetMap()->GetShell()->IsPreView() ) ) 176 { 177 ::vos::ORef< SwAccessibleContext > xAccImpl( 178 GetMap()->GetContextImpl( pLower, sal_False ) ); 179 if( xAccImpl.isValid() ) 180 { 181 ASSERT( xAccImpl->GetFrm()->IsCellFrm(), 182 "table child is not a cell frame" ) 183 bChanged = static_cast< SwAccessibleCell *>( 184 xAccImpl.getBodyPtr() )->_InvalidateMyCursorPos(); 185 } 186 else 187 bChanged = sal_True; // If the context is not know we 188 // don't know whether the selection 189 // changed or not. 190 } 191 else 192 { 193 // This is a box with sub rows. 194 bChanged |= _InvalidateChildrenCursorPos( pLower ); 195 } 196 } 197 ++aIter; 198 } 199 200 return bChanged; 201 } 202 203 void SwAccessibleCell::_InvalidateCursorPos() 204 { 205 if (IsSelected()) 206 { 207 const SwAccessibleChild aChild( GetChild( *(GetMap()), 0 ) ); 208 if( aChild.IsValid() && aChild.GetSwFrm() ) 209 { 210 ::vos::ORef < SwAccessibleContext > xChildImpl( GetMap()->GetContextImpl( aChild.GetSwFrm()) ); 211 if(xChildImpl.isValid()) 212 { 213 AccessibleEventObject aEvent; 214 aEvent.EventId = AccessibleEventId::STATE_CHANGED; 215 aEvent.NewValue<<=AccessibleStateType::FOCUSED; 216 xChildImpl->FireAccessibleEvent( aEvent ); 217 } 218 } 219 } 220 221 const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() ); 222 ASSERT( pParent->IsTabFrm(), "parent is not a tab frame" ); 223 const SwTabFrm *pTabFrm = static_cast< const SwTabFrm * >( pParent ); 224 if( pTabFrm->IsFollow() ) 225 pTabFrm = pTabFrm->FindMaster(); 226 227 while( pTabFrm ) 228 { 229 _InvalidateChildrenCursorPos( pTabFrm ); 230 /* 231 sal_Bool bChanged = _InvalidateChildrenCursorPos( pTabFrm ); 232 if( bChanged ) 233 { 234 ::vos::ORef< SwAccessibleContext > xAccImpl( 235 GetMap()->GetContextImpl( pTabFrm, sal_False ) ); 236 if( xAccImpl.isValid() ) 237 { 238 AccessibleEventObject aEvent; 239 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; 240 xAccImpl->FireAccessibleEvent( aEvent ); 241 } 242 } 243 */ 244 pTabFrm = pTabFrm->GetFollow(); 245 } 246 if (m_pAccTable) 247 { 248 m_pAccTable->FireSelectionEvent(); 249 } 250 } 251 252 sal_Bool SwAccessibleCell::HasCursor() 253 { 254 vos::OGuard aGuard( aMutex ); 255 return bIsSelected; 256 } 257 258 SwAccessibleCell::~SwAccessibleCell() 259 { 260 } 261 262 OUString SAL_CALL SwAccessibleCell::getAccessibleDescription (void) 263 throw (uno::RuntimeException) 264 { 265 return GetName(); 266 } 267 268 OUString SAL_CALL SwAccessibleCell::getImplementationName() 269 throw( uno::RuntimeException ) 270 { 271 return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); 272 } 273 274 sal_Bool SAL_CALL SwAccessibleCell::supportsService( 275 const ::rtl::OUString& sTestServiceName) 276 throw (uno::RuntimeException) 277 { 278 return sTestServiceName.equalsAsciiL( sServiceName, 279 sizeof(sServiceName)-1 ) || 280 sTestServiceName.equalsAsciiL( sAccessibleServiceName, 281 sizeof(sAccessibleServiceName)-1 ); 282 } 283 284 uno::Sequence< OUString > SAL_CALL SwAccessibleCell::getSupportedServiceNames() 285 throw( uno::RuntimeException ) 286 { 287 uno::Sequence< OUString > aRet(2); 288 OUString* pArray = aRet.getArray(); 289 pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); 290 pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); 291 return aRet; 292 } 293 294 void SwAccessibleCell::Dispose( sal_Bool bRecursive ) 295 { 296 const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() ); 297 ::vos::ORef< SwAccessibleContext > xAccImpl( 298 GetMap()->GetContextImpl( pParent, sal_False ) ); 299 if( xAccImpl.isValid() ) 300 xAccImpl->DisposeChild( SwAccessibleChild(GetFrm()), bRecursive ); 301 SwAccessibleContext::Dispose( bRecursive ); 302 } 303 304 void SwAccessibleCell::InvalidatePosOrSize( const SwRect& rOldBox ) 305 { 306 const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() ); 307 ::vos::ORef< SwAccessibleContext > xAccImpl( 308 GetMap()->GetContextImpl( pParent, sal_False ) ); 309 if( xAccImpl.isValid() ) 310 xAccImpl->InvalidateChildPosOrSize( SwAccessibleChild(GetFrm()), rOldBox ); 311 SwAccessibleContext::InvalidatePosOrSize( rOldBox ); 312 } 313 314 315 // ===== XAccessibleInterface =========================================== 316 317 uno::Any SwAccessibleCell::queryInterface( const uno::Type& rType ) 318 throw( uno::RuntimeException ) 319 { 320 if (rType == ::getCppuType((const uno::Reference<XAccessibleExtendedAttributes>*)0)) 321 { 322 uno::Any aR; 323 aR <<= uno::Reference<XAccessibleExtendedAttributes>(this); 324 return aR; 325 } 326 327 if (rType == ::getCppuType((const uno::Reference<XAccessibleSelection>*)0)) 328 { 329 uno::Any aR; 330 aR <<= uno::Reference<XAccessibleSelection>(this); 331 return aR; 332 } 333 if ( rType == ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) ) ) 334 { 335 uno::Reference<XAccessibleValue> xValue = this; 336 uno::Any aRet; 337 aRet <<= xValue; 338 return aRet; 339 } 340 else 341 { 342 return SwAccessibleContext::queryInterface( rType ); 343 } 344 } 345 346 //====== XTypeProvider ==================================================== 347 uno::Sequence< uno::Type > SAL_CALL SwAccessibleCell::getTypes() 348 throw(uno::RuntimeException) 349 { 350 uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() ); 351 352 sal_Int32 nIndex = aTypes.getLength(); 353 aTypes.realloc( nIndex + 1 ); 354 355 uno::Type* pTypes = aTypes.getArray(); 356 pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) ); 357 358 return aTypes; 359 } 360 361 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleCell::getImplementationId() 362 throw(uno::RuntimeException) 363 { 364 vos::OGuard aGuard(Application::GetSolarMutex()); 365 static uno::Sequence< sal_Int8 > aId( 16 ); 366 static sal_Bool bInit = sal_False; 367 if(!bInit) 368 { 369 rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); 370 bInit = sal_True; 371 } 372 return aId; 373 } 374 375 // ===== XAccessibleValue =============================================== 376 377 SwFrmFmt* SwAccessibleCell::GetTblBoxFormat() const 378 { 379 DBG_ASSERT( GetFrm() != NULL, "no frame?" ); 380 DBG_ASSERT( GetFrm()->IsCellFrm(), "no cell frame?" ); 381 382 const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() ); 383 return pCellFrm->GetTabBox()->GetFrmFmt(); 384 } 385 386 //Implement TableCell currentValue 387 uno::Any SwAccessibleCell::getCurrentValue( ) 388 throw( uno::RuntimeException ) 389 { 390 vos::OGuard aGuard(Application::GetSolarMutex()); 391 CHECK_FOR_DEFUNC( XAccessibleValue ); 392 393 uno::Any aAny; 394 395 const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() ); 396 const SwStartNode *pSttNd = pCellFrm->GetTabBox()->GetSttNd(); 397 if( pSttNd ) 398 { 399 ::rtl::OUString strRet; 400 SwNodeIndex aCntntIdx( *pSttNd, 0 ); 401 SwCntntNode* pCNd=NULL; 402 for(int nIndex = 0 ; 403 0 != ( pCNd = pSttNd->GetNodes().GoNext( &aCntntIdx ) ) && 404 aCntntIdx.GetIndex() < pSttNd->EndOfSectionIndex(); 405 ++nIndex ) 406 { 407 if(pCNd && pCNd->IsTxtNode()) 408 { 409 if (0 != nIndex) 410 { 411 strRet += ::rtl::OUString::createFromAscii(" "); 412 } 413 strRet +=((SwTxtNode*)pCNd)->GetTxt(); 414 } 415 } 416 aAny <<= strRet; 417 } 418 return aAny; 419 } 420 421 sal_Bool SwAccessibleCell::setCurrentValue( const uno::Any& aNumber ) 422 throw( uno::RuntimeException ) 423 { 424 vos::OGuard aGuard(Application::GetSolarMutex()); 425 CHECK_FOR_DEFUNC( XAccessibleValue ); 426 427 double fValue = 0; 428 sal_Bool bValid = (aNumber >>= fValue); 429 if( bValid ) 430 { 431 SwTblBoxValue aValue( fValue ); 432 GetTblBoxFormat()->SetFmtAttr( aValue ); 433 } 434 return bValid; 435 } 436 437 uno::Any SwAccessibleCell::getMaximumValue( ) 438 throw( uno::RuntimeException ) 439 { 440 uno::Any aAny; 441 aAny <<= DBL_MAX; 442 return aAny; 443 } 444 445 uno::Any SwAccessibleCell::getMinimumValue( ) 446 throw( uno::RuntimeException ) 447 { 448 uno::Any aAny; 449 aAny <<= -DBL_MAX; 450 return aAny; 451 } 452 453 ::rtl::OUString ReplaceOneChar(::rtl::OUString oldOUString, ::rtl::OUString replacedChar, ::rtl::OUString replaceStr) 454 { 455 int iReplace = -1; 456 iReplace = oldOUString.lastIndexOf(replacedChar); 457 if (iReplace > -1) 458 { 459 for(;iReplace>-1;) 460 { 461 oldOUString = oldOUString.replaceAt(iReplace,1, replaceStr); 462 iReplace=oldOUString.lastIndexOf(replacedChar,iReplace); 463 } 464 } 465 return oldOUString; 466 } 467 ::rtl::OUString ReplaceFourChar(::rtl::OUString oldOUString) 468 { 469 oldOUString = ReplaceOneChar(oldOUString,OUString::createFromAscii("\\"),OUString::createFromAscii("\\\\")); 470 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(";"),::rtl::OUString::createFromAscii("\\;")); 471 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii("="),::rtl::OUString::createFromAscii("\\=")); 472 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(","),::rtl::OUString::createFromAscii("\\,")); 473 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(":"),::rtl::OUString::createFromAscii("\\:")); 474 return oldOUString; 475 } 476 477 ::com::sun::star::uno::Any SAL_CALL SwAccessibleCell::getExtendedAttributes() 478 throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException) 479 { 480 ::com::sun::star::uno::Any strRet; 481 SwFrmFmt *pFrmFmt = GetTblBoxFormat(); 482 DBG_ASSERT(pFrmFmt,"Must be Valid"); 483 484 const SwTblBoxFormula& tbl_formula = pFrmFmt->GetTblBoxFormula(); 485 486 ::rtl::OUString strFormula = ReplaceFourChar(tbl_formula.GetFormula()); 487 ::rtl::OUString strFor = ::rtl::OUString::createFromAscii("Formula:"); 488 strFor += strFormula; 489 strFor += ::rtl::OUString::createFromAscii(";") ; 490 strRet <<= strFor; 491 492 return strRet; 493 } 494 495 sal_Int32 SAL_CALL SwAccessibleCell::getBackground() 496 throw (::com::sun::star::uno::RuntimeException) 497 { 498 const SvxBrushItem &rBack = GetFrm()->GetAttrSet()->GetBackground(); 499 sal_uInt32 crBack = rBack.GetColor().GetColor(); 500 501 if (COL_AUTO == crBack) 502 { 503 uno::Reference<XAccessible> xAccDoc = getAccessibleParent(); 504 if (xAccDoc.is()) 505 { 506 uno::Reference<XAccessibleComponent> xCompoentDoc(xAccDoc, uno::UNO_QUERY); 507 if (xCompoentDoc.is()) 508 { 509 crBack = (sal_uInt32)xCompoentDoc->getBackground(); 510 } 511 } 512 } 513 return crBack; 514 } 515 516 //===== XAccessibleSelection ============================================ 517 void SwAccessibleCell::selectAccessibleChild( 518 sal_Int32 nChildIndex ) 519 throw ( lang::IndexOutOfBoundsException, uno::RuntimeException ) 520 { 521 aSelectionHelper.selectAccessibleChild(nChildIndex); 522 } 523 524 sal_Bool SwAccessibleCell::isAccessibleChildSelected( 525 sal_Int32 nChildIndex ) 526 throw ( lang::IndexOutOfBoundsException, uno::RuntimeException ) 527 { 528 return aSelectionHelper.isAccessibleChildSelected(nChildIndex); 529 } 530 531 void SwAccessibleCell::clearAccessibleSelection( ) 532 throw ( uno::RuntimeException ) 533 { 534 aSelectionHelper.clearAccessibleSelection(); 535 } 536 537 void SwAccessibleCell::selectAllAccessibleChildren( ) 538 throw ( uno::RuntimeException ) 539 { 540 aSelectionHelper.selectAllAccessibleChildren(); 541 } 542 543 sal_Int32 SwAccessibleCell::getSelectedAccessibleChildCount( ) 544 throw ( uno::RuntimeException ) 545 { 546 return aSelectionHelper.getSelectedAccessibleChildCount(); 547 } 548 549 uno::Reference<XAccessible> SwAccessibleCell::getSelectedAccessibleChild( 550 sal_Int32 nSelectedChildIndex ) 551 throw ( lang::IndexOutOfBoundsException, uno::RuntimeException) 552 { 553 return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex); 554 } 555 556 void SwAccessibleCell::deselectAccessibleChild( 557 sal_Int32 nSelectedChildIndex ) 558 throw ( lang::IndexOutOfBoundsException, uno::RuntimeException ) 559 { 560 aSelectionHelper.deselectAccessibleChild(nSelectedChildIndex); 561 } 562 563