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_svx.hxx" 26 27 #include <accessiblecell.hxx> 28 29 #include "svx/DescriptionGenerator.hxx" 30 31 #include <com/sun/star/accessibility/AccessibleRole.hpp> 32 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 33 34 #include <vcl/svapp.hxx> 35 36 #include <unotools/accessiblestatesethelper.hxx> 37 38 #include <editeng/outlobj.hxx> 39 #include <svx/unoshtxt.hxx> 40 #include <svx/svdotext.hxx> 41 42 using ::rtl::OUString; 43 using namespace ::sdr::table; 44 using namespace ::com::sun::star; 45 using namespace ::com::sun::star::uno; 46 using namespace ::com::sun::star::accessibility; 47 using namespace ::com::sun::star::lang; 48 using namespace ::com::sun::star::container; 49 50 namespace accessibility { 51 52 // -------------------------------------------------------------------- 53 // AccessibleCell 54 // -------------------------------------------------------------------- 55 56 AccessibleCell::AccessibleCell( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible>& rxParent, const sdr::table::CellRef& rCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo ) 57 : AccessibleCellBase( rxParent, AccessibleRole::TABLE_CELL ) 58 , maShapeTreeInfo( rShapeTreeInfo ) 59 , mnIndexInParent( nIndex ) 60 , mpText( NULL ) 61 , mxCell( rCell ) 62 { 63 } 64 65 // -------------------------------------------------------------------- 66 67 AccessibleCell::~AccessibleCell (void) 68 { 69 DBG_ASSERT( mpText == 0, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" ); 70 } 71 72 // -------------------------------------------------------------------- 73 74 void AccessibleCell::Init (void) 75 { 76 SdrView* pView = maShapeTreeInfo.GetSdrView(); 77 const Window* pWindow = maShapeTreeInfo.GetWindow (); 78 if( (pView != NULL) && (pWindow != NULL) && mxCell.is()) 79 { 80 OutlinerParaObject* pOutlinerParaObject = mxCell->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active 81 82 bool bOwnParaObject = pOutlinerParaObject != 0; 83 84 if( !pOutlinerParaObject ) 85 pOutlinerParaObject = mxCell->GetOutlinerParaObject(); 86 87 // create AccessibleTextHelper to handle this shape's text 88 if( pOutlinerParaObject ) 89 { 90 // non-empty text -> use full-fledged edit source right away 91 ::std::auto_ptr<SvxEditSource> pEditSource( new SvxTextEditSource( mxCell->GetObject(), mxCell.get(), *pView, *pWindow) ); 92 mpText = new AccessibleTextHelper( pEditSource ); 93 mpText->SetEventSource(this); 94 } 95 96 if( bOwnParaObject) 97 delete pOutlinerParaObject; 98 } 99 } 100 101 // -------------------------------------------------------------------- 102 103 sal_Bool AccessibleCell::SetState (sal_Int16 aState) 104 { 105 sal_Bool bStateHasChanged = sal_False; 106 107 if (aState == AccessibleStateType::FOCUSED && mpText != NULL) 108 { 109 // Offer FOCUSED state to edit engine and detect whether the state 110 // changes. 111 sal_Bool bIsFocused = mpText->HaveFocus (); 112 mpText->SetFocus (sal_True); 113 bStateHasChanged = (bIsFocused != mpText->HaveFocus ()); 114 } 115 else 116 bStateHasChanged = AccessibleContextBase::SetState (aState); 117 118 return bStateHasChanged; 119 } 120 121 // -------------------------------------------------------------------- 122 123 sal_Bool AccessibleCell::ResetState (sal_Int16 aState) 124 { 125 sal_Bool bStateHasChanged = sal_False; 126 127 if (aState == AccessibleStateType::FOCUSED && mpText != NULL) 128 { 129 // Try to remove FOCUSED state from the edit engine and detect 130 // whether the state changes. 131 sal_Bool bIsFocused = mpText->HaveFocus (); 132 mpText->SetFocus (sal_False); 133 bStateHasChanged = (bIsFocused != mpText->HaveFocus ()); 134 } 135 else 136 bStateHasChanged = AccessibleContextBase::ResetState (aState); 137 138 return bStateHasChanged; 139 } 140 141 // -------------------------------------------------------------------- 142 143 sal_Bool AccessibleCell::GetState (sal_Int16 aState) 144 { 145 if (aState == AccessibleStateType::FOCUSED && mpText != NULL) 146 { 147 // Just delegate the call to the edit engine. The state is not 148 // merged into the state set. 149 return mpText->HaveFocus(); 150 } 151 else 152 return AccessibleContextBase::GetState (aState); 153 } 154 155 //----------------------------------------------------------------------------- 156 157 bool AccessibleCell::operator== (const AccessibleCell& rAccessibleCell) 158 { 159 return this == &rAccessibleCell; 160 } 161 162 //----------------------------------------------------------------------------- 163 // XInterface 164 //----------------------------------------------------------------------------- 165 166 Any SAL_CALL AccessibleCell::queryInterface( const Type& aType ) throw (RuntimeException) 167 { 168 return AccessibleCellBase::queryInterface( aType ); 169 } 170 171 //----------------------------------------------------------------------------- 172 173 void SAL_CALL AccessibleCell::acquire( ) throw () 174 { 175 AccessibleCellBase::acquire(); 176 } 177 178 //----------------------------------------------------------------------------- 179 180 void SAL_CALL AccessibleCell::release( ) throw () 181 { 182 AccessibleCellBase::release(); 183 } 184 185 // -------------------------------------------------------------------- 186 // XAccessibleContext 187 // -------------------------------------------------------------------- 188 189 /** The children of this cell come from the paragraphs of text. 190 */ 191 sal_Int32 SAL_CALL AccessibleCell::getAccessibleChildCount() throw (::com::sun::star::uno::RuntimeException) 192 { 193 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 194 ThrowIfDisposed (); 195 return mpText != NULL ? mpText->GetChildCount () : 0; 196 } 197 198 // -------------------------------------------------------------------- 199 200 /** Forward the request to the shape. Return the requested shape or throw 201 an exception for a wrong index. 202 */ 203 Reference<XAccessible> SAL_CALL AccessibleCell::getAccessibleChild (sal_Int32 nIndex) throw (IndexOutOfBoundsException, RuntimeException) 204 { 205 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 206 ThrowIfDisposed (); 207 208 // todo: does GetChild throw IndexOutOfBoundsException? 209 return mpText->GetChild (nIndex); 210 } 211 212 // -------------------------------------------------------------------- 213 214 /** Return a copy of the state set. 215 Possible states are: 216 ENABLED 217 SHOWING 218 VISIBLE 219 */ 220 Reference<XAccessibleStateSet> SAL_CALL AccessibleCell::getAccessibleStateSet (void) throw (RuntimeException) 221 { 222 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 223 ::osl::MutexGuard aGuard (maMutex); 224 Reference<XAccessibleStateSet> xStateSet; 225 226 if (rBHelper.bDisposed || mpText == NULL) 227 { 228 // Return a minimal state set that only contains the DEFUNC state. 229 xStateSet = AccessibleContextBase::getAccessibleStateSet (); 230 } 231 else 232 { 233 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); 234 235 if(pStateSet) 236 { 237 // Merge current FOCUSED state from edit engine. 238 if (mpText != NULL) 239 { 240 if (mpText->HaveFocus()) 241 pStateSet->AddState (AccessibleStateType::FOCUSED); 242 else 243 pStateSet->RemoveState (AccessibleStateType::FOCUSED); 244 } 245 246 // Create a copy of the state set that may be modified by the 247 // caller without affecting the current state set. 248 xStateSet = Reference<XAccessibleStateSet>(new ::utl::AccessibleStateSetHelper (*pStateSet)); 249 } 250 } 251 252 return xStateSet; 253 } 254 255 // -------------------------------------------------------------------- 256 // XAccessibleComponent 257 // -------------------------------------------------------------------- 258 259 sal_Bool SAL_CALL AccessibleCell::containsPoint( const ::com::sun::star::awt::Point& aPoint) throw (::com::sun::star::uno::RuntimeException) 260 { 261 return AccessibleComponentBase::containsPoint( aPoint ); 262 } 263 264 /** The implementation below is at the moment straightforward. It iterates 265 over all children (and thereby instances all children which have not 266 been already instatiated) until a child covering the specifed point is 267 found. 268 This leaves room for improvement. For instance, first iterate only over 269 the already instantiated children and only if no match is found 270 instantiate the remaining ones. 271 */ 272 Reference<XAccessible > SAL_CALL AccessibleCell::getAccessibleAtPoint ( const ::com::sun::star::awt::Point& aPoint) throw(RuntimeException) 273 { 274 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 275 ::osl::MutexGuard aGuard (maMutex); 276 277 sal_Int32 nChildCount = getAccessibleChildCount (); 278 for (sal_Int32 i=0; i<nChildCount; ++i) 279 { 280 Reference<XAccessible> xChild (getAccessibleChild (i)); 281 if (xChild.is()) 282 { 283 Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY); 284 if (xChildComponent.is()) 285 { 286 awt::Rectangle aBBox (xChildComponent->getBounds()); 287 if ( (aPoint.X >= aBBox.X) 288 && (aPoint.Y >= aBBox.Y) 289 && (aPoint.X < aBBox.X+aBBox.Width) 290 && (aPoint.Y < aBBox.Y+aBBox.Height) ) 291 return xChild; 292 } 293 } 294 } 295 296 // Have not found a child under the given point. Returning empty 297 // reference to indicate this. 298 return uno::Reference<XAccessible>(); 299 } 300 301 // -------------------------------------------------------------------- 302 303 ::com::sun::star::awt::Rectangle SAL_CALL AccessibleCell::getBounds(void) throw(RuntimeException) 304 { 305 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 306 ::osl::MutexGuard aGuard (maMutex); 307 308 ThrowIfDisposed (); 309 ::com::sun::star::awt::Rectangle aBoundingBox; 310 if( mxCell.is() ) 311 { 312 // Get the cell's bounding box in internal coordinates (in 100th of mm) 313 const ::Rectangle aCellRect( mxCell->getCellRect() ); 314 315 // Transform coordinates from internal to pixel. 316 if (maShapeTreeInfo.GetViewForwarder() == NULL) 317 throw uno::RuntimeException (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleCell has no valid view forwarder")),static_cast<uno::XWeak*>(this)); 318 319 ::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) ); 320 ::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() )); 321 322 // Clip the shape's bounding box with the bounding box of its parent. 323 Reference<XAccessibleComponent> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY); 324 if (xParentComponent.is()) 325 { 326 // Make the coordinates relative to the parent. 327 awt::Point aParentLocation (xParentComponent->getLocationOnScreen()); 328 int x = aPixelPosition.getX() - aParentLocation.X; 329 int y = aPixelPosition.getY() - aParentLocation.Y; 330 331 // Clip with parent (with coordinates relative to itself). 332 ::Rectangle aBBox ( x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight()); 333 awt::Size aParentSize (xParentComponent->getSize()); 334 ::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height); 335 aBBox = aBBox.GetIntersection (aParentBBox); 336 aBoundingBox = awt::Rectangle ( aBBox.getX(), aBBox.getY(), aBBox.getWidth(), aBBox.getHeight()); 337 } 338 else 339 { 340 OSL_TRACE ("parent does not support component"); 341 aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight()); 342 } 343 } 344 345 return aBoundingBox; 346 } 347 348 // -------------------------------------------------------------------- 349 350 ::com::sun::star::awt::Point SAL_CALL AccessibleCell::getLocation(void) throw (RuntimeException) 351 { 352 ThrowIfDisposed (); 353 ::com::sun::star::awt::Rectangle aBoundingBox(getBounds()); 354 return ::com::sun::star::awt::Point(aBoundingBox.X, aBoundingBox.Y); 355 } 356 357 // -------------------------------------------------------------------- 358 359 ::com::sun::star::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen(void) throw(RuntimeException) 360 { 361 ThrowIfDisposed (); 362 363 // Get relative position... 364 ::com::sun::star::awt::Point aLocation(getLocation ()); 365 366 // ... and add absolute position of the parent. 367 Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY); 368 if(xParentComponent.is()) 369 { 370 ::com::sun::star::awt::Point aParentLocation(xParentComponent->getLocationOnScreen()); 371 aLocation.X += aParentLocation.X; 372 aLocation.Y += aParentLocation.Y; 373 } 374 else 375 { 376 OSL_TRACE ("getLocation: parent does not support XAccessibleComponent"); 377 } 378 379 return aLocation; 380 } 381 382 // -------------------------------------------------------------------- 383 384 awt::Size SAL_CALL AccessibleCell::getSize (void) throw (RuntimeException) 385 { 386 ThrowIfDisposed (); 387 awt::Rectangle aBoundingBox (getBounds()); 388 return awt::Size (aBoundingBox.Width, aBoundingBox.Height); 389 } 390 391 // -------------------------------------------------------------------- 392 393 void SAL_CALL AccessibleCell::addFocusListener ( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFocusListener >& xListener) throw (::com::sun::star::uno::RuntimeException) 394 { 395 AccessibleComponentBase::addFocusListener( xListener ); 396 } 397 398 // -------------------------------------------------------------------- 399 400 void SAL_CALL AccessibleCell::removeFocusListener (const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFocusListener >& xListener ) throw (::com::sun::star::uno::RuntimeException) 401 { 402 AccessibleComponentBase::removeFocusListener( xListener ); 403 } 404 405 // -------------------------------------------------------------------- 406 407 void SAL_CALL AccessibleCell::grabFocus (void) throw (::com::sun::star::uno::RuntimeException) 408 { 409 AccessibleComponentBase::grabFocus(); 410 } 411 412 // -------------------------------------------------------------------- 413 414 sal_Int32 SAL_CALL AccessibleCell::getForeground(void) throw (RuntimeException) 415 { 416 ThrowIfDisposed (); 417 sal_Int32 nColor (0x0ffffffL); 418 419 // todo 420 return nColor; 421 } 422 423 // -------------------------------------------------------------------- 424 425 sal_Int32 SAL_CALL AccessibleCell::getBackground (void) throw (RuntimeException) 426 { 427 ThrowIfDisposed (); 428 sal_Int32 nColor (0L); 429 430 // todo 431 return nColor; 432 } 433 434 // -------------------------------------------------------------------- 435 // XAccessibleExtendedComponent 436 // -------------------------------------------------------------------- 437 438 ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFont > SAL_CALL AccessibleCell::getFont (void) throw (::com::sun::star::uno::RuntimeException) 439 { 440 //todo 441 return AccessibleComponentBase::getFont(); 442 } 443 444 // -------------------------------------------------------------------- 445 446 ::rtl::OUString SAL_CALL AccessibleCell::getTitledBorderText (void) throw (::com::sun::star::uno::RuntimeException) 447 { 448 return AccessibleComponentBase::getTitledBorderText(); 449 } 450 451 // -------------------------------------------------------------------- 452 453 ::rtl::OUString SAL_CALL AccessibleCell::getToolTipText (void) throw (::com::sun::star::uno::RuntimeException) 454 { 455 return AccessibleComponentBase::getToolTipText(); 456 } 457 458 // -------------------------------------------------------------------- 459 // XAccessibleEventBroadcaster 460 // -------------------------------------------------------------------- 461 462 void SAL_CALL AccessibleCell::addEventListener( const Reference<XAccessibleEventListener >& rxListener) throw (RuntimeException) 463 { 464 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 465 ::osl::MutexGuard aGuard (maMutex); 466 if (rBHelper.bDisposed || rBHelper.bInDispose) 467 { 468 Reference<XInterface> xSource( static_cast<XComponent *>(this) ); 469 lang::EventObject aEventObj(xSource); 470 rxListener->disposing(aEventObj); 471 } 472 else 473 { 474 AccessibleContextBase::addEventListener (rxListener); 475 if (mpText != NULL) 476 mpText->AddEventListener (rxListener); 477 } 478 } 479 480 // -------------------------------------------------------------------- 481 482 void SAL_CALL AccessibleCell::removeEventListener( const Reference<XAccessibleEventListener >& rxListener) throw (RuntimeException) 483 { 484 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 485 AccessibleContextBase::removeEventListener(rxListener); 486 if (mpText != NULL) 487 mpText->RemoveEventListener (rxListener); 488 } 489 490 // -------------------------------------------------------------------- 491 // XServiceInfo 492 // -------------------------------------------------------------------- 493 494 OUString SAL_CALL AccessibleCell::getImplementationName(void) throw (RuntimeException) 495 { 496 return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleCell")); 497 } 498 499 // -------------------------------------------------------------------- 500 501 Sequence<OUString> SAL_CALL AccessibleCell::getSupportedServiceNames(void) throw (RuntimeException) 502 { 503 ThrowIfDisposed (); 504 505 // Get list of supported service names from base class... 506 uno::Sequence<OUString> aServiceNames = AccessibleContextBase::getSupportedServiceNames(); 507 sal_Int32 nCount (aServiceNames.getLength()); 508 509 // ...and add additional names. 510 aServiceNames.realloc (nCount + 1); 511 static const OUString sAdditionalServiceName (RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.AccessibleCell")); 512 aServiceNames[nCount] = sAdditionalServiceName; 513 514 return aServiceNames; 515 } 516 517 // -------------------------------------------------------------------- 518 // IAccessibleViewForwarderListener 519 // -------------------------------------------------------------------- 520 521 void AccessibleCell::ViewForwarderChanged (ChangeType /*aChangeType*/, const IAccessibleViewForwarder* /*pViewForwarder*/) 522 { 523 // Inform all listeners that the graphical representation (i.e. size 524 // and/or position) of the shape has changed. 525 CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any()); 526 527 // update our children that our screen position might have changed 528 if( mpText ) 529 mpText->UpdateChildren(); 530 } 531 532 // -------------------------------------------------------------------- 533 // protected 534 // -------------------------------------------------------------------- 535 536 void AccessibleCell::disposing (void) 537 { 538 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 539 ::osl::MutexGuard aGuard (maMutex); 540 541 // Make sure to send an event that this object looses the focus in the 542 // case that it has the focus. 543 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); 544 if (pStateSet != NULL) 545 pStateSet->RemoveState(AccessibleStateType::FOCUSED); 546 547 if (mpText != NULL) 548 { 549 mpText->Dispose(); 550 delete mpText; 551 mpText = NULL; 552 } 553 554 // Cleanup. Remove references to objects to allow them to be 555 // destroyed. 556 mxCell.clear(); 557 maShapeTreeInfo = AccessibleShapeTreeInfo(); 558 559 // Call base classes. 560 AccessibleContextBase::dispose (); 561 } 562 563 sal_Int32 SAL_CALL AccessibleCell::getAccessibleIndexInParent (void) throw (RuntimeException) 564 { 565 ThrowIfDisposed (); 566 return mnIndexInParent; 567 } 568 569 ::rtl::OUString SAL_CALL AccessibleCell::getAccessibleName (void) throw (::com::sun::star::uno::RuntimeException) 570 { 571 ThrowIfDisposed (); 572 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 573 574 if( mxCell.is() ) 575 return mxCell->getName(); 576 577 return AccessibleCellBase::getAccessibleName(); 578 } 579 580 } // end of namespace accessibility 581