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 #include <svx/AccessibleShape.hxx> 27 #include "svx/DescriptionGenerator.hxx" 28 #include <svx/AccessibleShapeInfo.hxx> 29 #include <com/sun/star/view/XSelectionSupplier.hpp> 30 #include <rtl/uuid.h> 31 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLE_ROLE_HPP_ 32 #include <com/sun/star/accessibility/AccessibleRole.hpp> 33 #endif 34 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLE_STATE_TYPE_HPP_ 35 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 36 #endif 37 #include <com/sun/star/beans/XPropertySet.hpp> 38 #include <com/sun/star/container/XChild.hpp> 39 #include <com/sun/star/drawing/XShapes.hpp> 40 #include <com/sun/star/drawing/XShapeDescriptor.hpp> 41 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 42 #include <com/sun/star/drawing/FillStyle.hpp> 43 #include <com/sun/star/text/XText.hpp> 44 #include <editeng/outlobj.hxx> 45 #include <rtl/ref.hxx> 46 #include <editeng/unoedsrc.hxx> 47 #include <svx/unoshtxt.hxx> 48 #include <svx/svdobj.hxx> 49 #include <svx/svdmodel.hxx> 50 #include "svx/unoapi.hxx" 51 #include <com/sun/star/uno/Exception.hpp> 52 #include <svx/ShapeTypeHandler.hxx> 53 #include <svx/SvxShapeTypes.hxx> 54 55 #ifndef _SVX_ACCESSIBILITY_HRC 56 #include "accessibility.hrc" 57 #endif 58 #include "svx/svdstr.hrc" 59 #include <svx/dialmgr.hxx> 60 #include <vcl/svapp.hxx> 61 #include <unotools/accessiblestatesethelper.hxx> 62 #include <svx/svdview.hxx> 63 #include "AccessibleEmptyEditSource.hxx" 64 65 using namespace ::com::sun::star; 66 using namespace ::com::sun::star::accessibility; 67 using ::com::sun::star::uno::Reference; 68 using ::rtl::OUString; 69 70 namespace accessibility { 71 72 namespace { 73 74 OUString GetOptionalProperty ( 75 const Reference<beans::XPropertySet>& rxSet, 76 const OUString& rsPropertyName) 77 { 78 OUString sValue; 79 80 if (rxSet.is()) 81 { 82 const Reference<beans::XPropertySetInfo> xInfo (rxSet->getPropertySetInfo()); 83 if ( ! xInfo.is() || xInfo->hasPropertyByName(rsPropertyName)) 84 { 85 try 86 { 87 rxSet->getPropertyValue(rsPropertyName) >>= sValue; 88 } 89 catch (beans::UnknownPropertyException&) 90 { 91 // This exception should only be thrown when the property 92 // does not exits (of course) and the XPropertySetInfo is 93 // not available. 94 } 95 } 96 } 97 return sValue; 98 } 99 100 } // end of anonymous namespace 101 102 103 104 105 //===== internal ============================================================ 106 107 AccessibleShape::AccessibleShape ( 108 const AccessibleShapeInfo& rShapeInfo, 109 const AccessibleShapeTreeInfo& rShapeTreeInfo) 110 : AccessibleContextBase (rShapeInfo.mxParent,AccessibleRole::LIST_ITEM), 111 mpChildrenManager(NULL), 112 mxShape (rShapeInfo.mxShape), 113 maShapeTreeInfo (rShapeTreeInfo), 114 mnIndex (rShapeInfo.mnIndex), 115 m_nIndexInParent(-1), 116 mpText (NULL), 117 mpParent (rShapeInfo.mpChildrenManager) 118 { 119 m_pShape = GetSdrObjectFromXShape(mxShape); 120 UpdateNameAndDescription(); 121 } 122 123 124 125 126 AccessibleShape::~AccessibleShape (void) 127 { 128 if (mpChildrenManager != NULL) 129 delete mpChildrenManager; 130 if (mpText != NULL) 131 delete mpText; 132 OSL_TRACE ("~AccessibleShape"); 133 134 // Unregistering from the various broadcasters should be unnecessary 135 // since this destructor would not have been called if one of the 136 // broadcasters would still hold a strong reference to this object. 137 } 138 139 140 141 142 void AccessibleShape::Init (void) 143 { 144 // Update the OPAQUE and SELECTED shape. 145 UpdateStates (); 146 147 // Create a children manager when this shape has children of its own. 148 Reference<drawing::XShapes> xShapes (mxShape, uno::UNO_QUERY); 149 if (xShapes.is() && xShapes->getCount() > 0) 150 mpChildrenManager = new ChildrenManager ( 151 this, xShapes, maShapeTreeInfo, *this); 152 if (mpChildrenManager != NULL) 153 mpChildrenManager->Update(); 154 155 // Register at model as document::XEventListener. 156 if (maShapeTreeInfo.GetModelBroadcaster().is()) 157 maShapeTreeInfo.GetModelBroadcaster()->addEventListener ( 158 static_cast<document::XEventListener*>(this)); 159 160 // Beware! Here we leave the paths of the UNO API and descend into the 161 // depths of the core. Necessary for makeing the edit engine 162 // accessible. 163 Reference<text::XText> xText (mxShape, uno::UNO_QUERY); 164 if (xText.is()) 165 { 166 SdrView* pView = maShapeTreeInfo.GetSdrView (); 167 const Window* pWindow = maShapeTreeInfo.GetWindow (); 168 if (pView != NULL && pWindow != NULL && mxShape.is()) 169 { 170 // #107948# Determine whether shape text is empty 171 SdrObject* pSdrObject = GetSdrObjectFromXShape(mxShape); 172 if( pSdrObject ) 173 { 174 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, pSdrObject ); 175 OutlinerParaObject* pOutlinerParaObject = NULL; 176 177 if( pTextObj ) 178 pOutlinerParaObject = pTextObj->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active 179 180 bool bOwnParaObj = pOutlinerParaObject != NULL; 181 182 if( !pOutlinerParaObject && pSdrObject ) 183 pOutlinerParaObject = pSdrObject->GetOutlinerParaObject(); 184 185 // create AccessibleTextHelper to handle this shape's text 186 if( !pOutlinerParaObject ) 187 { 188 // empty text -> use proxy edit source to delay creation of EditEngine 189 ::std::auto_ptr<SvxEditSource> pEditSource( new AccessibleEmptyEditSource ( *pSdrObject, *pView, *pWindow) ); 190 mpText = new AccessibleTextHelper( pEditSource ); 191 } 192 else 193 { 194 // non-empty text -> use full-fledged edit source right away 195 ::std::auto_ptr<SvxEditSource> pEditSource( new SvxTextEditSource ( *pSdrObject, 0, *pView, *pWindow) ); 196 mpText = new AccessibleTextHelper( pEditSource ); 197 } 198 199 if( bOwnParaObj ) 200 delete pOutlinerParaObject; 201 202 mpText->SetEventSource(this); 203 } 204 } 205 } 206 } 207 208 209 210 211 void AccessibleShape::UpdateStates (void) 212 { 213 ::utl::AccessibleStateSetHelper* pStateSet = 214 static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); 215 if (pStateSet == NULL) 216 return; 217 218 // Set the opaque state for certain shape types when their fill style is 219 // solid. 220 bool bShapeIsOpaque = false; 221 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape)) 222 { 223 case DRAWING_PAGE: 224 case DRAWING_RECTANGLE: 225 case DRAWING_TEXT: 226 { 227 uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY); 228 if (xSet.is()) 229 { 230 try 231 { 232 drawing::FillStyle aFillStyle; 233 bShapeIsOpaque = ( xSet->getPropertyValue (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FillStyle"))) >>= aFillStyle) 234 && aFillStyle == drawing::FillStyle_SOLID; 235 } 236 catch (::com::sun::star::beans::UnknownPropertyException&) 237 { 238 // Ignore. 239 } 240 } 241 } 242 } 243 if (bShapeIsOpaque) 244 pStateSet->AddState (AccessibleStateType::OPAQUE); 245 else 246 pStateSet->RemoveState (AccessibleStateType::OPAQUE); 247 248 // Set the selected state. 249 bool bShapeIsSelected = false; 250 // XXX fix_me this has to be done with an extra interface later on 251 if ( m_pShape && maShapeTreeInfo.GetSdrView() ) 252 { 253 bShapeIsSelected = maShapeTreeInfo.GetSdrView()->IsObjMarked(m_pShape) == sal_True; 254 } 255 256 if (bShapeIsSelected) 257 pStateSet->AddState (AccessibleStateType::SELECTED); 258 else 259 pStateSet->RemoveState (AccessibleStateType::SELECTED); 260 } 261 262 263 264 265 bool AccessibleShape::operator== (const AccessibleShape& rShape) 266 { 267 return this==&rShape; 268 } 269 270 271 272 273 sal_Bool AccessibleShape::SetState (sal_Int16 aState) 274 { 275 sal_Bool bStateHasChanged = sal_False; 276 277 if (aState == AccessibleStateType::FOCUSED && mpText != NULL) 278 { 279 // Offer FOCUSED state to edit engine and detect whether the state 280 // changes. 281 sal_Bool bIsFocused = mpText->HaveFocus (); 282 mpText->SetFocus (sal_True); 283 bStateHasChanged = (bIsFocused != mpText->HaveFocus ()); 284 } 285 else 286 bStateHasChanged = AccessibleContextBase::SetState (aState); 287 288 return bStateHasChanged; 289 } 290 291 292 293 294 sal_Bool AccessibleShape::ResetState (sal_Int16 aState) 295 { 296 sal_Bool bStateHasChanged = sal_False; 297 298 if (aState == AccessibleStateType::FOCUSED && mpText != NULL) 299 { 300 // Try to remove FOCUSED state from the edit engine and detect 301 // whether the state changes. 302 sal_Bool bIsFocused = mpText->HaveFocus (); 303 mpText->SetFocus (sal_False); 304 bStateHasChanged = (bIsFocused != mpText->HaveFocus ()); 305 } 306 else 307 bStateHasChanged = AccessibleContextBase::ResetState (aState); 308 309 return bStateHasChanged; 310 } 311 312 313 314 315 sal_Bool AccessibleShape::GetState (sal_Int16 aState) 316 { 317 if (aState == AccessibleStateType::FOCUSED && mpText != NULL) 318 { 319 // Just delegate the call to the edit engine. The state is not 320 // merged into the state set. 321 return mpText->HaveFocus(); 322 } 323 else 324 return AccessibleContextBase::GetState (aState); 325 } 326 327 328 329 330 //===== XAccessibleContext ================================================== 331 332 /** The children of this shape come from two sources: The children from 333 group or scene shapes and the paragraphs of text. 334 */ 335 sal_Int32 SAL_CALL 336 AccessibleShape::getAccessibleChildCount () 337 throw (::com::sun::star::uno::RuntimeException) 338 { 339 ThrowIfDisposed (); 340 sal_Int32 nChildCount = 0; 341 342 // Add the number of shapes that are children of this shape. 343 if (mpChildrenManager != NULL) 344 nChildCount += mpChildrenManager->GetChildCount (); 345 // Add the number text paragraphs. 346 if (mpText != NULL) 347 nChildCount += mpText->GetChildCount (); 348 349 return nChildCount; 350 } 351 352 353 354 355 /** Forward the request to the shape. Return the requested shape or throw 356 an exception for a wrong index. 357 */ 358 uno::Reference<XAccessible> SAL_CALL 359 AccessibleShape::getAccessibleChild (sal_Int32 nIndex) 360 throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException) 361 { 362 ThrowIfDisposed (); 363 364 uno::Reference<XAccessible> xChild; 365 366 // Depending on the index decide whether to delegate this call to the 367 // children manager or the edit engine. 368 if ((mpChildrenManager != NULL) 369 && (nIndex < mpChildrenManager->GetChildCount())) 370 { 371 xChild = mpChildrenManager->GetChild (nIndex); 372 } 373 else if (mpText != NULL) 374 { 375 sal_Int32 nI = nIndex; 376 if (mpChildrenManager != NULL) 377 nI -= mpChildrenManager->GetChildCount(); 378 xChild = mpText->GetChild (nI); 379 } 380 else 381 throw lang::IndexOutOfBoundsException ( 382 ::rtl::OUString::createFromAscii ("shape has no child with index ") 383 + rtl::OUString::valueOf(nIndex), 384 static_cast<uno::XWeak*>(this)); 385 386 return xChild; 387 } 388 389 390 391 392 /** Return a copy of the state set. 393 Possible states are: 394 ENABLED 395 SHOWING 396 VISIBLE 397 */ 398 uno::Reference<XAccessibleStateSet> SAL_CALL 399 AccessibleShape::getAccessibleStateSet (void) 400 throw (::com::sun::star::uno::RuntimeException) 401 { 402 ::osl::MutexGuard aGuard (maMutex); 403 Reference<XAccessibleStateSet> xStateSet; 404 405 if (rBHelper.bDisposed || mpText == NULL) 406 // Return a minimal state set that only contains the DEFUNC state. 407 xStateSet = AccessibleContextBase::getAccessibleStateSet (); 408 else 409 { 410 ::utl::AccessibleStateSetHelper* pStateSet = 411 static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); 412 413 if (pStateSet != NULL) 414 { 415 // Merge current FOCUSED state from edit engine. 416 if (mpText != NULL) 417 { 418 if (mpText->HaveFocus()) 419 pStateSet->AddState (AccessibleStateType::FOCUSED); 420 else 421 pStateSet->RemoveState (AccessibleStateType::FOCUSED); 422 } 423 424 // Create a copy of the state set that may be modified by the 425 // caller without affecting the current state set. 426 xStateSet = Reference<XAccessibleStateSet>( 427 new ::utl::AccessibleStateSetHelper (*pStateSet)); 428 } 429 } 430 431 return xStateSet; 432 } 433 434 435 436 437 //===== XAccessibleComponent ================================================ 438 439 /** The implementation below is at the moment straightforward. It iterates 440 over all children (and thereby instances all children which have not 441 been already instatiated) until a child covering the specifed point is 442 found. 443 This leaves room for improvement. For instance, first iterate only over 444 the already instantiated children and only if no match is found 445 instantiate the remaining ones. 446 */ 447 uno::Reference<XAccessible > SAL_CALL 448 AccessibleShape::getAccessibleAtPoint ( 449 const awt::Point& aPoint) 450 throw (uno::RuntimeException) 451 { 452 ::osl::MutexGuard aGuard (maMutex); 453 454 sal_Int32 nChildCount = getAccessibleChildCount (); 455 for (sal_Int32 i=0; i<nChildCount; ++i) 456 { 457 Reference<XAccessible> xChild (getAccessibleChild (i)); 458 if (xChild.is()) 459 { 460 Reference<XAccessibleComponent> xChildComponent ( 461 xChild->getAccessibleContext(), uno::UNO_QUERY); 462 if (xChildComponent.is()) 463 { 464 awt::Rectangle aBBox (xChildComponent->getBounds()); 465 if ( (aPoint.X >= aBBox.X) 466 && (aPoint.Y >= aBBox.Y) 467 && (aPoint.X < aBBox.X+aBBox.Width) 468 && (aPoint.Y < aBBox.Y+aBBox.Height) ) 469 return xChild; 470 } 471 } 472 } 473 474 // Have not found a child under the given point. Returning empty 475 // reference to indicate this. 476 return uno::Reference<XAccessible>(); 477 } 478 479 480 481 482 awt::Rectangle SAL_CALL AccessibleShape::getBounds (void) 483 throw (::com::sun::star::uno::RuntimeException) 484 { 485 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 486 ::osl::MutexGuard aGuard (maMutex); 487 488 ThrowIfDisposed (); 489 awt::Rectangle aBoundingBox; 490 if ( mxShape.is() ) 491 { 492 493 static const OUString sBoundRectName ( 494 RTL_CONSTASCII_USTRINGPARAM("BoundRect")); 495 static const OUString sAnchorPositionName ( 496 RTL_CONSTASCII_USTRINGPARAM("AnchorPosition")); 497 498 // Get the shape's bounding box in internal coordinates (in 100th of 499 // mm). Use the property BoundRect. Only if that is not supported ask 500 // the shape for its position and size directly. 501 Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY); 502 Reference<beans::XPropertySetInfo> xSetInfo; 503 bool bFoundBoundRect = false; 504 if (xSet.is()) 505 { 506 xSetInfo = xSet->getPropertySetInfo (); 507 if (xSetInfo.is()) 508 { 509 if (xSetInfo->hasPropertyByName (sBoundRectName)) 510 { 511 try 512 { 513 uno::Any aValue = xSet->getPropertyValue (sBoundRectName); 514 aValue >>= aBoundingBox; 515 bFoundBoundRect = true; 516 } 517 catch (beans::UnknownPropertyException e) 518 { 519 // Handled below (bFoundBoundRect stays false). 520 } 521 } 522 else 523 OSL_TRACE (" no property BoundRect"); 524 } 525 } 526 527 // Fallback when there is no BoundRect Property. 528 if ( ! bFoundBoundRect ) 529 { 530 awt::Point aPosition (mxShape->getPosition()); 531 awt::Size aSize (mxShape->getSize()); 532 aBoundingBox = awt::Rectangle ( 533 aPosition.X, aPosition.Y, 534 aSize.Width, aSize.Height); 535 536 // While BoundRects have absolute positions, the position returned 537 // by XPosition::getPosition is relative. Get the anchor position 538 // (usually not (0,0) for Writer shapes). 539 if (xSetInfo.is()) 540 { 541 if (xSetInfo->hasPropertyByName (sAnchorPositionName)) 542 { 543 uno::Any aPos = xSet->getPropertyValue (sAnchorPositionName); 544 awt::Point aAnchorPosition; 545 aPos >>= aAnchorPosition; 546 aBoundingBox.X += aAnchorPosition.X; 547 aBoundingBox.Y += aAnchorPosition.Y; 548 } 549 } 550 } 551 552 // Transform coordinates from internal to pixel. 553 if (maShapeTreeInfo.GetViewForwarder() == NULL) 554 throw uno::RuntimeException (::rtl::OUString ( 555 RTL_CONSTASCII_USTRINGPARAM( 556 "AccessibleShape has no valid view forwarder")), 557 static_cast<uno::XWeak*>(this)); 558 ::Size aPixelSize = maShapeTreeInfo.GetViewForwarder()->LogicToPixel ( 559 ::Size (aBoundingBox.Width, aBoundingBox.Height)); 560 ::Point aPixelPosition = maShapeTreeInfo.GetViewForwarder()->LogicToPixel ( 561 ::Point (aBoundingBox.X, aBoundingBox.Y)); 562 563 // Clip the shape's bounding box with the bounding box of its parent. 564 Reference<XAccessibleComponent> xParentComponent ( 565 getAccessibleParent(), uno::UNO_QUERY); 566 if (xParentComponent.is()) 567 { 568 // Make the coordinates relative to the parent. 569 awt::Point aParentLocation (xParentComponent->getLocationOnScreen()); 570 int x = aPixelPosition.getX() - aParentLocation.X; 571 int y = aPixelPosition.getY() - aParentLocation.Y; 572 573 /* // The following block is a workarround for bug #99889# (property 574 // BoundRect returnes coordinates relative to document window 575 // instead of absolute coordinates for shapes in Writer). Has to 576 // be removed as soon as bug is fixed. 577 578 // Use a non-null anchor position as flag that the shape is in a 579 // Writer document. 580 if (xSetInfo.is()) 581 if (xSetInfo->hasPropertyByName (sAnchorPositionName)) 582 { 583 uno::Any aPos = xSet->getPropertyValue (sAnchorPositionName); 584 awt::Point aAnchorPosition; 585 aPos >>= aAnchorPosition; 586 if (aAnchorPosition.X > 0) 587 { 588 x = aPixelPosition.getX(); 589 y = aPixelPosition.getY(); 590 } 591 } 592 // End of workarround. 593 */ 594 // Clip with parent (with coordinates relative to itself). 595 ::Rectangle aBBox ( 596 x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight()); 597 awt::Size aParentSize (xParentComponent->getSize()); 598 ::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height); 599 aBBox = aBBox.GetIntersection (aParentBBox); 600 aBoundingBox = awt::Rectangle ( 601 aBBox.getX(), 602 aBBox.getY(), 603 aBBox.getWidth(), 604 aBBox.getHeight()); 605 } 606 else 607 { 608 OSL_TRACE ("parent does not support component"); 609 aBoundingBox = awt::Rectangle ( 610 aPixelPosition.getX(), aPixelPosition.getY(), 611 aPixelSize.getWidth(), aPixelSize.getHeight()); 612 } 613 } 614 615 return aBoundingBox; 616 } 617 618 619 620 621 awt::Point SAL_CALL AccessibleShape::getLocation (void) 622 throw (::com::sun::star::uno::RuntimeException) 623 { 624 ThrowIfDisposed (); 625 awt::Rectangle aBoundingBox (getBounds()); 626 return awt::Point (aBoundingBox.X, aBoundingBox.Y); 627 } 628 629 630 631 632 awt::Point SAL_CALL AccessibleShape::getLocationOnScreen (void) 633 throw (::com::sun::star::uno::RuntimeException) 634 { 635 ThrowIfDisposed (); 636 637 // Get relative position... 638 awt::Point aLocation (getLocation ()); 639 640 // ... and add absolute position of the parent. 641 uno::Reference<XAccessibleComponent> xParentComponent ( 642 getAccessibleParent(), uno::UNO_QUERY); 643 if (xParentComponent.is()) 644 { 645 awt::Point aParentLocation (xParentComponent->getLocationOnScreen()); 646 aLocation.X += aParentLocation.X; 647 aLocation.Y += aParentLocation.Y; 648 } 649 else 650 OSL_TRACE ("getLocation: parent does not support XAccessibleComponent"); 651 return aLocation; 652 } 653 654 655 656 657 awt::Size SAL_CALL AccessibleShape::getSize (void) 658 throw (uno::RuntimeException) 659 { 660 ThrowIfDisposed (); 661 awt::Rectangle aBoundingBox (getBounds()); 662 return awt::Size (aBoundingBox.Width, aBoundingBox.Height); 663 } 664 665 666 667 668 sal_Int32 SAL_CALL AccessibleShape::getForeground (void) 669 throw (::com::sun::star::uno::RuntimeException) 670 { 671 ThrowIfDisposed (); 672 sal_Int32 nColor (0x0ffffffL); 673 674 try 675 { 676 uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY); 677 if (aSet.is()) 678 { 679 uno::Any aColor; 680 aColor = aSet->getPropertyValue (OUString::createFromAscii ("LineColor")); 681 aColor >>= nColor; 682 } 683 } 684 catch (::com::sun::star::beans::UnknownPropertyException) 685 { 686 // Ignore exception and return default color. 687 } 688 return nColor; 689 } 690 691 692 693 694 sal_Int32 SAL_CALL AccessibleShape::getBackground (void) 695 throw (::com::sun::star::uno::RuntimeException) 696 { 697 ThrowIfDisposed (); 698 sal_Int32 nColor (0L); 699 700 try 701 { 702 uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY); 703 if (aSet.is()) 704 { 705 uno::Any aColor; 706 aColor = aSet->getPropertyValue (OUString::createFromAscii ("FillColor")); 707 aColor >>= nColor; 708 } 709 } 710 catch (::com::sun::star::beans::UnknownPropertyException) 711 { 712 // Ignore exception and return default color. 713 } 714 return nColor; 715 } 716 717 718 719 720 //===== XAccessibleEventBroadcaster ========================================= 721 722 void SAL_CALL AccessibleShape::addEventListener ( 723 const Reference<XAccessibleEventListener >& rxListener) 724 throw (uno::RuntimeException) 725 { 726 if (rBHelper.bDisposed || rBHelper.bInDispose) 727 { 728 uno::Reference<uno::XInterface> xThis ( 729 (lang::XComponent *)this, uno::UNO_QUERY); 730 rxListener->disposing (lang::EventObject (xThis)); 731 } 732 else 733 { 734 AccessibleContextBase::addEventListener (rxListener); 735 if (mpText != NULL) 736 mpText->AddEventListener (rxListener); 737 } 738 } 739 740 741 742 743 void SAL_CALL AccessibleShape::removeEventListener ( 744 const Reference<XAccessibleEventListener >& rxListener) 745 throw (uno::RuntimeException) 746 { 747 AccessibleContextBase::removeEventListener (rxListener); 748 if (mpText != NULL) 749 mpText->RemoveEventListener (rxListener); 750 } 751 752 753 754 755 //===== XInterface ========================================================== 756 757 com::sun::star::uno::Any SAL_CALL 758 AccessibleShape::queryInterface (const com::sun::star::uno::Type & rType) 759 throw (::com::sun::star::uno::RuntimeException) 760 { 761 ::com::sun::star::uno::Any aReturn = AccessibleContextBase::queryInterface (rType); 762 if ( ! aReturn.hasValue()) 763 aReturn = ::cppu::queryInterface (rType, 764 static_cast<XAccessibleComponent*>(this), 765 static_cast<XAccessibleExtendedComponent*>(this), 766 static_cast<lang::XEventListener*>(this), 767 static_cast<document::XEventListener*>(this), 768 static_cast<lang::XUnoTunnel*>(this) 769 ); 770 return aReturn; 771 } 772 773 774 775 776 void SAL_CALL 777 AccessibleShape::acquire (void) 778 throw () 779 { 780 AccessibleContextBase::acquire (); 781 } 782 783 784 785 786 void SAL_CALL 787 AccessibleShape::release (void) 788 throw () 789 { 790 AccessibleContextBase::release (); 791 } 792 793 794 795 796 //===== XServiceInfo ======================================================== 797 798 ::rtl::OUString SAL_CALL 799 AccessibleShape::getImplementationName (void) 800 throw (::com::sun::star::uno::RuntimeException) 801 { 802 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleShape")); 803 } 804 805 806 807 808 uno::Sequence<OUString> SAL_CALL 809 AccessibleShape::getSupportedServiceNames (void) 810 throw (::com::sun::star::uno::RuntimeException) 811 { 812 ThrowIfDisposed (); 813 // Get list of supported service names from base class... 814 uno::Sequence<OUString> aServiceNames = 815 AccessibleContextBase::getSupportedServiceNames(); 816 sal_Int32 nCount (aServiceNames.getLength()); 817 818 // ...and add additional names. 819 aServiceNames.realloc (nCount + 1); 820 static const OUString sAdditionalServiceName (RTL_CONSTASCII_USTRINGPARAM( 821 "com.sun.star.drawing.AccessibleShape")); 822 aServiceNames[nCount] = sAdditionalServiceName; 823 824 return aServiceNames; 825 } 826 827 828 829 830 831 //===== XTypeProvider =================================================== 832 833 uno::Sequence<uno::Type> SAL_CALL 834 AccessibleShape::getTypes (void) 835 throw (uno::RuntimeException) 836 { 837 ThrowIfDisposed (); 838 // Get list of types from the context base implementation, ... 839 uno::Sequence<uno::Type> aTypeList (AccessibleContextBase::getTypes()); 840 // ... get list of types from component base implementation, ... 841 uno::Sequence<uno::Type> aComponentTypeList (AccessibleComponentBase::getTypes()); 842 // ... define local types, ... 843 const uno::Type aLangEventListenerType = 844 ::getCppuType((const uno::Reference<lang::XEventListener>*)0); 845 const uno::Type aDocumentEventListenerType = 846 ::getCppuType((const uno::Reference<document::XEventListener>*)0); 847 const uno::Type aUnoTunnelType = 848 ::getCppuType((const uno::Reference<lang::XUnoTunnel>*)0); 849 // const uno::Type aStateSetType = 850 // ::getCppuType((const uno::Reference<XAccessibleStateSet>*)0); 851 852 // ... and merge them all into one list. 853 sal_Int32 nTypeCount (aTypeList.getLength()), 854 nComponentTypeCount (aComponentTypeList.getLength()); 855 int i; 856 857 aTypeList.realloc (nTypeCount + nComponentTypeCount + 3); 858 859 for (i=0; i<nComponentTypeCount; i++) 860 aTypeList[nTypeCount + i] = aComponentTypeList[i]; 861 862 aTypeList[nTypeCount + i++ ] = aLangEventListenerType; 863 aTypeList[nTypeCount + i++ ] = aDocumentEventListenerType; 864 aTypeList[nTypeCount + i ] = aUnoTunnelType; 865 866 return aTypeList; 867 } 868 869 870 871 872 //===== lang::XEventListener ================================================ 873 874 /** Disposing calls are accepted only from the model: Just reset the 875 reference to the model in the shape tree info. Otherwise this object 876 remains functional. 877 */ 878 void SAL_CALL 879 AccessibleShape::disposing (const lang::EventObject& aEvent) 880 throw (uno::RuntimeException) 881 { 882 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 883 ::osl::MutexGuard aGuard (maMutex); 884 885 try 886 { 887 if (aEvent.Source == maShapeTreeInfo.GetModelBroadcaster()) 888 { 889 // Remove reference to model broadcaster to allow it to pass 890 // away. 891 maShapeTreeInfo.SetModelBroadcaster(NULL); 892 } 893 894 } 895 catch (uno::RuntimeException e) 896 { 897 OSL_TRACE ("caught exception while disposing"); 898 } 899 } 900 901 902 903 904 //===== document::XEventListener ============================================ 905 906 void SAL_CALL 907 AccessibleShape::notifyEvent (const document::EventObject& rEventObject) 908 throw (uno::RuntimeException) 909 { 910 static const OUString sShapeModified ( 911 RTL_CONSTASCII_USTRINGPARAM("ShapeModified")); 912 913 // First check if the event is for us. 914 uno::Reference<drawing::XShape> xShape ( 915 rEventObject.Source, uno::UNO_QUERY); 916 if ( xShape.get() == mxShape.get() ) 917 { 918 if (rEventObject.EventName.equals (sShapeModified)) 919 { 920 // Some property of a shape has been modified. Send an event 921 // that indicates a change of the visible data to all listeners. 922 CommitChange ( 923 AccessibleEventId::VISIBLE_DATA_CHANGED, 924 uno::Any(), 925 uno::Any()); 926 927 // Name and Description may have changed. Update the local 928 // values accordingly. 929 UpdateNameAndDescription(); 930 } 931 } 932 } 933 934 935 936 937 //===== lang::XUnoTunnel ================================================ 938 939 const uno::Sequence< sal_Int8 >& 940 AccessibleShape::getUnoTunnelImplementationId() 941 throw() 942 { 943 static uno::Sequence< sal_Int8 >* pSeq = 0; 944 945 if( !pSeq ) 946 { 947 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); 948 949 if( !pSeq ) 950 { 951 static uno::Sequence< sal_Int8 > aSeq( 16 ); 952 rtl_createUuid( (sal_uInt8*) aSeq.getArray(), 0, sal_True ); 953 pSeq = &aSeq; 954 } 955 } 956 957 return( *pSeq ); 958 } 959 960 //------------------------------------------------------------------------------ 961 AccessibleShape* 962 AccessibleShape::getImplementation( const uno::Reference< uno::XInterface >& rxIFace ) 963 throw() 964 { 965 uno::Reference< lang::XUnoTunnel > xTunnel( rxIFace, uno::UNO_QUERY ); 966 AccessibleShape* pReturn = NULL; 967 968 if( xTunnel.is() ) 969 pReturn = reinterpret_cast< AccessibleShape* >( xTunnel->getSomething( getUnoTunnelImplementationId() ) ); 970 971 return( pReturn ); 972 } 973 974 //------------------------------------------------------------------------------ 975 sal_Int64 SAL_CALL 976 AccessibleShape::getSomething( const uno::Sequence< sal_Int8 >& rIdentifier ) 977 throw(uno::RuntimeException) 978 { 979 sal_Int64 nReturn( 0 ); 980 981 if( ( rIdentifier.getLength() == 16 ) && ( 0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(), rIdentifier.getConstArray(), 16 ) ) ) 982 nReturn = reinterpret_cast< sal_Int64 >( this ); 983 984 return( nReturn ); 985 } 986 987 //===== IAccessibleViewForwarderListener ==================================== 988 989 void AccessibleShape::ViewForwarderChanged (ChangeType aChangeType, 990 const IAccessibleViewForwarder* pViewForwarder) 991 { 992 // Inform all listeners that the graphical representation (i.e. size 993 // and/or position) of the shape has changed. 994 CommitChange (AccessibleEventId::VISIBLE_DATA_CHANGED, 995 uno::Any(), 996 uno::Any()); 997 998 // Tell children manager of the modified view forwarder. 999 if (mpChildrenManager != NULL) 1000 mpChildrenManager->ViewForwarderChanged (aChangeType, pViewForwarder); 1001 1002 // update our children that our screen position might have changed 1003 if( mpText ) 1004 mpText->UpdateChildren(); 1005 } 1006 1007 1008 1009 1010 //===== protected internal ================================================== 1011 /// Set this object's name if is different to the current name. 1012 ::rtl::OUString 1013 AccessibleShape::CreateAccessibleBaseName (void) 1014 throw (::com::sun::star::uno::RuntimeException) 1015 { 1016 return ShapeTypeHandler::CreateAccessibleBaseName( mxShape ); 1017 } 1018 1019 1020 ::rtl::OUString 1021 AccessibleShape::CreateAccessibleName (void) 1022 throw (::com::sun::star::uno::RuntimeException) 1023 { 1024 OUString sName (CreateAccessibleBaseName()); 1025 1026 // Append the shape's index to the name to disambiguate between shapes 1027 // of the same type. If such an index where not given to the 1028 // constructor then use the z-order instead. If even that does not exist 1029 // we throw an exception. 1030 long nIndex = mnIndex; 1031 if (nIndex == -1) 1032 { 1033 try 1034 { 1035 uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY); 1036 if (xSet.is()) 1037 { 1038 uno::Any aZOrder (xSet->getPropertyValue (::rtl::OUString::createFromAscii ("ZOrder"))); 1039 aZOrder >>= nIndex; 1040 1041 // Add one to be not zero based. 1042 nIndex += 1; 1043 } 1044 } 1045 catch (beans::UnknownPropertyException) 1046 { 1047 // We throw our own exception that is a bit more informative. 1048 throw uno::RuntimeException (::rtl::OUString ( 1049 RTL_CONSTASCII_USTRINGPARAM("AccessibleShape has invalid index and no ZOrder property")), 1050 static_cast<uno::XWeak*>(this)); 1051 } 1052 1053 } 1054 1055 // Put a space between name and index because of Gnopernicus othewise 1056 // spells the name. 1057 sName += OUString (RTL_CONSTASCII_USTRINGPARAM(" ")) + OUString::valueOf (nIndex); 1058 1059 return sName; 1060 } 1061 1062 1063 1064 1065 ::rtl::OUString 1066 AccessibleShape::CreateAccessibleDescription (void) 1067 throw (::com::sun::star::uno::RuntimeException) 1068 { 1069 DescriptionGenerator aDG (mxShape); 1070 aDG.Initialize (CreateAccessibleBaseName()); 1071 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape)) 1072 { 1073 case DRAWING_3D_CUBE: 1074 case DRAWING_3D_EXTRUDE: 1075 case DRAWING_3D_LATHE: 1076 case DRAWING_3D_SPHERE: 1077 aDG.Add3DProperties (); 1078 break; 1079 1080 case DRAWING_3D_SCENE: 1081 case DRAWING_GROUP: 1082 case DRAWING_PAGE: 1083 // No further information is appended. 1084 break; 1085 1086 case DRAWING_CAPTION: 1087 case DRAWING_CLOSED_BEZIER: 1088 case DRAWING_CLOSED_FREEHAND: 1089 case DRAWING_ELLIPSE: 1090 case DRAWING_POLY_POLYGON: 1091 case DRAWING_POLY_POLYGON_PATH: 1092 case DRAWING_RECTANGLE: 1093 aDG.AddLineProperties (); 1094 aDG.AddFillProperties (); 1095 break; 1096 1097 case DRAWING_CONNECTOR: 1098 case DRAWING_LINE: 1099 case DRAWING_MEASURE: 1100 case DRAWING_OPEN_BEZIER: 1101 case DRAWING_OPEN_FREEHAND: 1102 case DRAWING_POLY_LINE: 1103 case DRAWING_POLY_LINE_PATH: 1104 aDG.AddLineProperties (); 1105 break; 1106 1107 case DRAWING_CONTROL: 1108 aDG.AddProperty (OUString::createFromAscii ("ControlBackground"), 1109 DescriptionGenerator::COLOR, 1110 OUString()); 1111 aDG.AddProperty (OUString::createFromAscii ("ControlBorder"), 1112 DescriptionGenerator::INTEGER, 1113 OUString()); 1114 break; 1115 1116 case DRAWING_TEXT: 1117 aDG.AddTextProperties (); 1118 break; 1119 1120 default: 1121 aDG.Initialize (::rtl::OUString ( 1122 RTL_CONSTASCII_USTRINGPARAM("Unknown accessible shape"))); 1123 uno::Reference<drawing::XShapeDescriptor> xDescriptor (mxShape, uno::UNO_QUERY); 1124 if (xDescriptor.is()) 1125 { 1126 aDG.AppendString (::rtl::OUString (RTL_CONSTASCII_USTRINGPARAM("service name="))); 1127 aDG.AppendString (xDescriptor->getShapeType()); 1128 } 1129 } 1130 1131 return aDG(); 1132 } 1133 1134 1135 1136 1137 uno::Reference< drawing::XShape > AccessibleShape::GetXShape() 1138 { 1139 return( mxShape ); 1140 } 1141 1142 1143 1144 // protected 1145 void AccessibleShape::disposing (void) 1146 { 1147 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); 1148 ::osl::MutexGuard aGuard (maMutex); 1149 1150 // Make sure to send an event that this object looses the focus in the 1151 // case that it has the focus. 1152 ::utl::AccessibleStateSetHelper* pStateSet = 1153 static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); 1154 if (pStateSet != NULL) 1155 pStateSet->RemoveState (AccessibleStateType::FOCUSED); 1156 1157 // Unregister from broadcasters. 1158 Reference<lang::XComponent> xComponent (mxShape, uno::UNO_QUERY); 1159 if (xComponent.is()) 1160 xComponent->removeEventListener (this); 1161 1162 // Unregister from model. 1163 if (maShapeTreeInfo.GetModelBroadcaster().is()) 1164 maShapeTreeInfo.GetModelBroadcaster()->removeEventListener ( 1165 static_cast<document::XEventListener*>(this)); 1166 1167 // Release the child containers. 1168 if (mpChildrenManager != NULL) 1169 { 1170 delete mpChildrenManager; 1171 mpChildrenManager = NULL; 1172 } 1173 if (mpText != NULL) 1174 { 1175 mpText->Dispose(); 1176 delete mpText; 1177 mpText = NULL; 1178 } 1179 1180 // Cleanup. Remove references to objects to allow them to be 1181 // destroyed. 1182 mxShape = NULL; 1183 maShapeTreeInfo = AccessibleShapeTreeInfo(); 1184 1185 // Call base classes. 1186 AccessibleContextBase::dispose (); 1187 } 1188 1189 sal_Int32 SAL_CALL 1190 AccessibleShape::getAccessibleIndexInParent (void) 1191 throw (::com::sun::star::uno::RuntimeException) 1192 { 1193 ThrowIfDisposed (); 1194 // Use a simple but slow solution for now. Optimize later. 1195 1196 sal_Int32 nIndex = m_nIndexInParent; 1197 if ( -1 == nIndex ) 1198 nIndex = AccessibleContextBase::getAccessibleIndexInParent(); 1199 return nIndex; 1200 } 1201 1202 1203 1204 1205 void AccessibleShape::UpdateNameAndDescription (void) 1206 { 1207 // Ignore missing title, name, or description. There are fallbacks for 1208 // them. 1209 try 1210 { 1211 Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY_THROW); 1212 OUString sString; 1213 1214 // Get the accessible name. 1215 sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Title"))); 1216 if (sString.getLength() > 0) 1217 { 1218 SetAccessibleName(sString, AccessibleContextBase::FromShape); 1219 } 1220 else 1221 { 1222 sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Name"))); 1223 if (sString.getLength() > 0) 1224 SetAccessibleName(sString, AccessibleContextBase::FromShape); 1225 } 1226 1227 // Get the accessible description. 1228 sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Description"))); 1229 if (sString.getLength() > 0) 1230 SetAccessibleDescription(sString, AccessibleContextBase::FromShape); 1231 } 1232 catch (uno::RuntimeException&) 1233 { 1234 } 1235 } 1236 1237 1238 1239 1240 } // end of namespace accessibility 1241