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