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