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 { 118 vos::OGuard aGuard(Application::GetSolarMutex()); 119 OUString sBoxName( pCellFrm->GetTabBox()->GetName() ); 120 SetName( sBoxName ); 121 122 bIsSelected = IsSelected(); 123 124 //Need not assign the pointer of accessible table object to m_pAccTable, 125 //for it already done in SwAccessibleCell::GetTable(); Former codes: 126 //m_pAccTable= GetTable(); 127 GetTable(); 128 } 129 130 sal_Bool SwAccessibleCell::_InvalidateMyCursorPos() 131 { 132 sal_Bool bNew = IsSelected(); 133 sal_Bool bOld; 134 { 135 vos::OGuard aGuard( aMutex ); 136 bOld = bIsSelected; 137 bIsSelected = bNew; 138 } 139 if( bNew ) 140 { 141 // remember that object as the one that has the caret. This is 142 // neccessary to notify that object if the cursor leaves it. 143 ::vos::ORef < SwAccessibleContext > xThis( this ); 144 GetMap()->SetCursorContext( xThis ); 145 } 146 147 sal_Bool bChanged = bOld != bNew; 148 if( bChanged ) 149 { 150 FireStateChangedEvent( AccessibleStateType::SELECTED, bNew ); 151 if (m_pAccTable) 152 { 153 m_pAccTable->AddSelectionCell(this,bNew); 154 } 155 } 156 return bChanged; 157 } 158 159 sal_Bool SwAccessibleCell::_InvalidateChildrenCursorPos( const SwFrm *pFrm ) 160 { 161 sal_Bool bChanged = sal_False; 162 163 const SwAccessibleChildSList aVisList( GetVisArea(), *pFrm, *GetMap() ); 164 SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); 165 while( aIter != aVisList.end() ) 166 { 167 const SwAccessibleChild& rLower = *aIter; 168 const SwFrm *pLower = rLower.GetSwFrm(); 169 if( pLower ) 170 { 171 if( rLower.IsAccessible( GetMap()->GetShell()->IsPreView() ) ) 172 { 173 ::vos::ORef< SwAccessibleContext > xAccImpl( 174 GetMap()->GetContextImpl( pLower, sal_False ) ); 175 if( xAccImpl.isValid() ) 176 { 177 ASSERT( xAccImpl->GetFrm()->IsCellFrm(), 178 "table child is not a cell frame" ) 179 bChanged = static_cast< SwAccessibleCell *>( 180 xAccImpl.getBodyPtr() )->_InvalidateMyCursorPos(); 181 } 182 else 183 bChanged = sal_True; // If the context is not know we 184 // don't know whether the selection 185 // changed or not. 186 } 187 else 188 { 189 // This is a box with sub rows. 190 bChanged |= _InvalidateChildrenCursorPos( pLower ); 191 } 192 } 193 ++aIter; 194 } 195 196 return bChanged; 197 } 198 199 void SwAccessibleCell::_InvalidateCursorPos() 200 { 201 if (IsSelected()) 202 { 203 const SwAccessibleChild aChild( GetChild( *(GetMap()), 0 ) ); 204 if( aChild.IsValid() && aChild.GetSwFrm() ) 205 { 206 ::vos::ORef < SwAccessibleContext > xChildImpl( GetMap()->GetContextImpl( aChild.GetSwFrm()) ); 207 if(xChildImpl.isValid()) 208 { 209 AccessibleEventObject aEvent; 210 aEvent.EventId = AccessibleEventId::STATE_CHANGED; 211 aEvent.NewValue<<=AccessibleStateType::FOCUSED; 212 xChildImpl->FireAccessibleEvent( aEvent ); 213 } 214 } 215 } 216 217 const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() ); 218 ASSERT( pParent->IsTabFrm(), "parent is not a tab frame" ); 219 const SwTabFrm *pTabFrm = static_cast< const SwTabFrm * >( pParent ); 220 if( pTabFrm->IsFollow() ) 221 pTabFrm = pTabFrm->FindMaster(); 222 223 while( pTabFrm ) 224 { 225 _InvalidateChildrenCursorPos( pTabFrm ); 226 /* 227 sal_Bool bChanged = _InvalidateChildrenCursorPos( pTabFrm ); 228 if( bChanged ) 229 { 230 ::vos::ORef< SwAccessibleContext > xAccImpl( 231 GetMap()->GetContextImpl( pTabFrm, sal_False ) ); 232 if( xAccImpl.isValid() ) 233 { 234 AccessibleEventObject aEvent; 235 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; 236 xAccImpl->FireAccessibleEvent( aEvent ); 237 } 238 } 239 */ 240 pTabFrm = pTabFrm->GetFollow(); 241 } 242 if (m_pAccTable) 243 { 244 m_pAccTable->FireSelectionEvent(); 245 } 246 } 247 248 sal_Bool SwAccessibleCell::HasCursor() 249 { 250 vos::OGuard aGuard( aMutex ); 251 return bIsSelected; 252 } 253 254 SwAccessibleCell::~SwAccessibleCell() 255 { 256 } 257 258 OUString SAL_CALL SwAccessibleCell::getAccessibleDescription (void) 259 throw (uno::RuntimeException) 260 { 261 return GetName(); 262 } 263 264 OUString SAL_CALL SwAccessibleCell::getImplementationName() 265 throw( uno::RuntimeException ) 266 { 267 return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); 268 } 269 270 sal_Bool SAL_CALL SwAccessibleCell::supportsService( 271 const ::rtl::OUString& sTestServiceName) 272 throw (uno::RuntimeException) 273 { 274 return sTestServiceName.equalsAsciiL( sServiceName, 275 sizeof(sServiceName)-1 ) || 276 sTestServiceName.equalsAsciiL( sAccessibleServiceName, 277 sizeof(sAccessibleServiceName)-1 ); 278 } 279 280 uno::Sequence< OUString > SAL_CALL SwAccessibleCell::getSupportedServiceNames() 281 throw( uno::RuntimeException ) 282 { 283 uno::Sequence< OUString > aRet(2); 284 OUString* pArray = aRet.getArray(); 285 pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); 286 pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); 287 return aRet; 288 } 289 290 void SwAccessibleCell::Dispose( sal_Bool bRecursive ) 291 { 292 const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() ); 293 ::vos::ORef< SwAccessibleContext > xAccImpl( 294 GetMap()->GetContextImpl( pParent, sal_False ) ); 295 if( xAccImpl.isValid() ) 296 xAccImpl->DisposeChild( SwAccessibleChild(GetFrm()), bRecursive ); 297 SwAccessibleContext::Dispose( bRecursive ); 298 } 299 300 void SwAccessibleCell::InvalidatePosOrSize( const SwRect& rOldBox ) 301 { 302 const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() ); 303 ::vos::ORef< SwAccessibleContext > xAccImpl( 304 GetMap()->GetContextImpl( pParent, sal_False ) ); 305 if( xAccImpl.isValid() ) 306 xAccImpl->InvalidateChildPosOrSize( SwAccessibleChild(GetFrm()), rOldBox ); 307 SwAccessibleContext::InvalidatePosOrSize( rOldBox ); 308 } 309 310 311 // ===== XAccessibleInterface =========================================== 312 313 uno::Any SwAccessibleCell::queryInterface( const uno::Type& rType ) 314 throw( uno::RuntimeException ) 315 { 316 if (rType == ::getCppuType((const uno::Reference<XAccessibleExtendedAttributes>*)0)) 317 { 318 uno::Any aR; 319 aR <<= uno::Reference<XAccessibleExtendedAttributes>(this); 320 return aR; 321 } 322 323 if (rType == ::getCppuType((const uno::Reference<XAccessibleSelection>*)0)) 324 { 325 uno::Any aR; 326 aR <<= uno::Reference<XAccessibleSelection>(this); 327 return aR; 328 } 329 if ( rType == ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) ) ) 330 { 331 uno::Reference<XAccessibleValue> xValue = this; 332 uno::Any aRet; 333 aRet <<= xValue; 334 return aRet; 335 } 336 else 337 { 338 return SwAccessibleContext::queryInterface( rType ); 339 } 340 } 341 342 //====== XTypeProvider ==================================================== 343 uno::Sequence< uno::Type > SAL_CALL SwAccessibleCell::getTypes() 344 throw(uno::RuntimeException) 345 { 346 uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() ); 347 348 sal_Int32 nIndex = aTypes.getLength(); 349 aTypes.realloc( nIndex + 1 ); 350 351 uno::Type* pTypes = aTypes.getArray(); 352 pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) ); 353 354 return aTypes; 355 } 356 357 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleCell::getImplementationId() 358 throw(uno::RuntimeException) 359 { 360 vos::OGuard aGuard(Application::GetSolarMutex()); 361 static uno::Sequence< sal_Int8 > aId( 16 ); 362 static sal_Bool bInit = sal_False; 363 if(!bInit) 364 { 365 rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); 366 bInit = sal_True; 367 } 368 return aId; 369 } 370 371 // ===== XAccessibleValue =============================================== 372 373 SwFrmFmt* SwAccessibleCell::GetTblBoxFormat() const 374 { 375 DBG_ASSERT( GetFrm() != NULL, "no frame?" ); 376 DBG_ASSERT( GetFrm()->IsCellFrm(), "no cell frame?" ); 377 378 const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() ); 379 return pCellFrm->GetTabBox()->GetFrmFmt(); 380 } 381 382 //Implement TableCell currentValue 383 uno::Any SwAccessibleCell::getCurrentValue( ) 384 throw( uno::RuntimeException ) 385 { 386 vos::OGuard aGuard(Application::GetSolarMutex()); 387 CHECK_FOR_DEFUNC( XAccessibleValue ); 388 389 uno::Any aAny; 390 391 const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() ); 392 const SwStartNode *pSttNd = pCellFrm->GetTabBox()->GetSttNd(); 393 if( pSttNd ) 394 { 395 ::rtl::OUString strRet; 396 SwNodeIndex aCntntIdx( *pSttNd, 0 ); 397 SwCntntNode* pCNd=NULL; 398 for(int nIndex = 0 ; 399 0 != ( pCNd = pSttNd->GetNodes().GoNext( &aCntntIdx ) ) && 400 aCntntIdx.GetIndex() < pSttNd->EndOfSectionIndex(); 401 ++nIndex ) 402 { 403 if(pCNd && pCNd->IsTxtNode()) 404 { 405 if (0 != nIndex) 406 { 407 strRet += ::rtl::OUString::createFromAscii(" "); 408 } 409 strRet +=((SwTxtNode*)pCNd)->GetTxt(); 410 } 411 } 412 aAny <<= strRet; 413 } 414 return aAny; 415 } 416 417 sal_Bool SwAccessibleCell::setCurrentValue( const uno::Any& aNumber ) 418 throw( uno::RuntimeException ) 419 { 420 vos::OGuard aGuard(Application::GetSolarMutex()); 421 CHECK_FOR_DEFUNC( XAccessibleValue ); 422 423 double fValue = 0; 424 sal_Bool bValid = (aNumber >>= fValue); 425 if( bValid ) 426 { 427 SwTblBoxValue aValue( fValue ); 428 GetTblBoxFormat()->SetFmtAttr( aValue ); 429 } 430 return bValid; 431 } 432 433 uno::Any SwAccessibleCell::getMaximumValue( ) 434 throw( uno::RuntimeException ) 435 { 436 uno::Any aAny; 437 aAny <<= DBL_MAX; 438 return aAny; 439 } 440 441 uno::Any SwAccessibleCell::getMinimumValue( ) 442 throw( uno::RuntimeException ) 443 { 444 uno::Any aAny; 445 aAny <<= -DBL_MAX; 446 return aAny; 447 } 448 449 ::rtl::OUString ReplaceOneChar(::rtl::OUString oldOUString, ::rtl::OUString replacedChar, ::rtl::OUString replaceStr) 450 { 451 int iReplace = -1; 452 iReplace = oldOUString.lastIndexOf(replacedChar); 453 if (iReplace > -1) 454 { 455 for(;iReplace>-1;) 456 { 457 oldOUString = oldOUString.replaceAt(iReplace,1, replaceStr); 458 iReplace=oldOUString.lastIndexOf(replacedChar,iReplace); 459 } 460 } 461 return oldOUString; 462 } 463 ::rtl::OUString ReplaceFourChar(::rtl::OUString oldOUString) 464 { 465 oldOUString = ReplaceOneChar(oldOUString,OUString::createFromAscii("\\"),OUString::createFromAscii("\\\\")); 466 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(";"),::rtl::OUString::createFromAscii("\\;")); 467 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii("="),::rtl::OUString::createFromAscii("\\=")); 468 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(","),::rtl::OUString::createFromAscii("\\,")); 469 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(":"),::rtl::OUString::createFromAscii("\\:")); 470 return oldOUString; 471 } 472 473 ::com::sun::star::uno::Any SAL_CALL SwAccessibleCell::getExtendedAttributes() 474 throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException) 475 { 476 ::com::sun::star::uno::Any strRet; 477 SwFrmFmt *pFrmFmt = GetTblBoxFormat(); 478 DBG_ASSERT(pFrmFmt,"Must be Valid"); 479 480 const SwTblBoxFormula& tbl_formula = pFrmFmt->GetTblBoxFormula(); 481 482 ::rtl::OUString strFormula = ReplaceFourChar(tbl_formula.GetFormula()); 483 ::rtl::OUString strFor = ::rtl::OUString::createFromAscii("Formula:"); 484 strFor += strFormula; 485 strFor += ::rtl::OUString::createFromAscii(";") ; 486 strRet <<= strFor; 487 488 return strRet; 489 } 490 491 sal_Int32 SAL_CALL SwAccessibleCell::getBackground() 492 throw (::com::sun::star::uno::RuntimeException) 493 { 494 const SvxBrushItem &rBack = GetFrm()->GetAttrSet()->GetBackground(); 495 sal_uInt32 crBack = rBack.GetColor().GetColor(); 496 497 if (COL_AUTO == crBack) 498 { 499 uno::Reference<XAccessible> xAccDoc = getAccessibleParent(); 500 if (xAccDoc.is()) 501 { 502 uno::Reference<XAccessibleComponent> xCompoentDoc(xAccDoc, uno::UNO_QUERY); 503 if (xCompoentDoc.is()) 504 { 505 crBack = (sal_uInt32)xCompoentDoc->getBackground(); 506 } 507 } 508 } 509 return crBack; 510 } 511 512 //===== XAccessibleSelection ============================================ 513 void SwAccessibleCell::selectAccessibleChild( 514 sal_Int32 nChildIndex ) 515 throw ( lang::IndexOutOfBoundsException, uno::RuntimeException ) 516 { 517 aSelectionHelper.selectAccessibleChild(nChildIndex); 518 } 519 520 sal_Bool SwAccessibleCell::isAccessibleChildSelected( 521 sal_Int32 nChildIndex ) 522 throw ( lang::IndexOutOfBoundsException, uno::RuntimeException ) 523 { 524 return aSelectionHelper.isAccessibleChildSelected(nChildIndex); 525 } 526 527 void SwAccessibleCell::clearAccessibleSelection( ) 528 throw ( uno::RuntimeException ) 529 { 530 aSelectionHelper.clearAccessibleSelection(); 531 } 532 533 void SwAccessibleCell::selectAllAccessibleChildren( ) 534 throw ( uno::RuntimeException ) 535 { 536 aSelectionHelper.selectAllAccessibleChildren(); 537 } 538 539 sal_Int32 SwAccessibleCell::getSelectedAccessibleChildCount( ) 540 throw ( uno::RuntimeException ) 541 { 542 return aSelectionHelper.getSelectedAccessibleChildCount(); 543 } 544 545 uno::Reference<XAccessible> SwAccessibleCell::getSelectedAccessibleChild( 546 sal_Int32 nSelectedChildIndex ) 547 throw ( lang::IndexOutOfBoundsException, uno::RuntimeException) 548 { 549 return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex); 550 } 551 552 void SwAccessibleCell::deselectAccessibleChild( 553 sal_Int32 nSelectedChildIndex ) 554 throw ( lang::IndexOutOfBoundsException, uno::RuntimeException ) 555 { 556 aSelectionHelper.deselectAccessibleChild(nSelectedChildIndex); 557 } 558 559 SwAccessibleTable *SwAccessibleCell::GetTable() 560 { 561 if (!m_pAccTable) 562 { 563 if (!xTableReference.is()) 564 { 565 xTableReference = getAccessibleParent(); 566 #ifdef OSL_DEBUG_LEVEL 567 uno::Reference<XAccessibleContext> xContextTable(xTableReference, uno::UNO_QUERY); 568 OSL_ASSERT(xContextTable.is() && xContextTable->getAccessibleRole() == AccessibleRole::TABLE); 569 #endif 570 //SwAccessibleTable aTable = *(static_cast<SwAccessibleTable *>(xTable.get())); 571 } 572 m_pAccTable = static_cast<SwAccessibleTable *>(xTableReference.get()); 573 } 574 return m_pAccTable; 575 } 576