Update ooo320-m1
[ooovba.git] / svx / source / accessibility / AccessibleShape.cxx
blob14ec72bfb3c42eb1e3d669afe2f23e16d49c7f62
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: AccessibleShape.cxx,v $
10 * $Revision: 1.54 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include <svx/AccessibleShape.hxx>
34 #include "DescriptionGenerator.hxx"
35 #include <svx/AccessibleShapeInfo.hxx>
36 #include <com/sun/star/view/XSelectionSupplier.hpp>
37 #include <rtl/uuid.h>
38 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLE_ROLE_HPP_
39 #include <com/sun/star/accessibility/AccessibleRole.hpp>
40 #endif
41 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLE_STATE_TYPE_HPP_
42 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
43 #endif
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/container/XChild.hpp>
46 #include <com/sun/star/drawing/XShapes.hpp>
47 #include <com/sun/star/drawing/XShapeDescriptor.hpp>
48 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
49 #include <com/sun/star/drawing/FillStyle.hpp>
50 #include <com/sun/star/text/XText.hpp>
51 #include <svx/outlobj.hxx>
52 #include <rtl/ref.hxx>
53 #include <svx/unoedsrc.hxx>
54 #include <svx/unoshtxt.hxx>
55 #include <svx/svdobj.hxx>
56 #include <svx/svdmodel.hxx>
57 #include "unoapi.hxx"
58 #include <com/sun/star/uno/Exception.hpp>
59 #include <svx/ShapeTypeHandler.hxx>
60 #include <svx/SvxShapeTypes.hxx>
62 #ifndef _SVX_ACCESSIBILITY_HRC
63 #include "accessibility.hrc"
64 #endif
65 #include "svdstr.hrc"
66 #include <svx/dialmgr.hxx>
67 #include <vcl/svapp.hxx>
68 #include <unotools/accessiblestatesethelper.hxx>
69 #include <svx/svdview.hxx>
70 #include "AccessibleEmptyEditSource.hxx"
72 using namespace ::com::sun::star;
73 using namespace ::com::sun::star::accessibility;
74 using ::com::sun::star::uno::Reference;
75 using ::rtl::OUString;
77 namespace accessibility {
79 namespace {
81 OUString GetOptionalProperty (
82 const Reference<beans::XPropertySet>& rxSet,
83 const OUString& rsPropertyName)
85 OUString sValue;
87 if (rxSet.is())
89 const Reference<beans::XPropertySetInfo> xInfo (rxSet->getPropertySetInfo());
90 if ( ! xInfo.is() || xInfo->hasPropertyByName(rsPropertyName))
92 try
94 rxSet->getPropertyValue(rsPropertyName) >>= sValue;
96 catch (beans::UnknownPropertyException&)
98 // This exception should only be thrown when the property
99 // does not exits (of course) and the XPropertySetInfo is
100 // not available.
104 return sValue;
107 } // end of anonymous namespace
112 //===== internal ============================================================
114 AccessibleShape::AccessibleShape (
115 const AccessibleShapeInfo& rShapeInfo,
116 const AccessibleShapeTreeInfo& rShapeTreeInfo)
117 : AccessibleContextBase (rShapeInfo.mxParent,AccessibleRole::LIST_ITEM),
118 mpChildrenManager(NULL),
119 mxShape (rShapeInfo.mxShape),
120 maShapeTreeInfo (rShapeTreeInfo),
121 mnIndex (rShapeInfo.mnIndex),
122 m_nIndexInParent(-1),
123 mpText (NULL),
124 mpParent (rShapeInfo.mpChildrenManager)
126 m_pShape = GetSdrObjectFromXShape(mxShape);
127 UpdateNameAndDescription();
133 AccessibleShape::~AccessibleShape (void)
135 if (mpChildrenManager != NULL)
136 delete mpChildrenManager;
137 if (mpText != NULL)
138 delete mpText;
139 OSL_TRACE ("~AccessibleShape");
141 // Unregistering from the various broadcasters should be unnecessary
142 // since this destructor would not have been called if one of the
143 // broadcasters would still hold a strong reference to this object.
149 void AccessibleShape::Init (void)
151 // Update the OPAQUE and SELECTED shape.
152 UpdateStates ();
154 // Create a children manager when this shape has children of its own.
155 Reference<drawing::XShapes> xShapes (mxShape, uno::UNO_QUERY);
156 if (xShapes.is() && xShapes->getCount() > 0)
157 mpChildrenManager = new ChildrenManager (
158 this, xShapes, maShapeTreeInfo, *this);
159 if (mpChildrenManager != NULL)
160 mpChildrenManager->Update();
162 // Register at model as document::XEventListener.
163 if (maShapeTreeInfo.GetModelBroadcaster().is())
164 maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
165 static_cast<document::XEventListener*>(this));
167 // Beware! Here we leave the paths of the UNO API and descend into the
168 // depths of the core. Necessary for makeing the edit engine
169 // accessible.
170 Reference<text::XText> xText (mxShape, uno::UNO_QUERY);
171 if (xText.is())
173 SdrView* pView = maShapeTreeInfo.GetSdrView ();
174 const Window* pWindow = maShapeTreeInfo.GetWindow ();
175 if (pView != NULL && pWindow != NULL && mxShape.is())
177 // #107948# Determine whether shape text is empty
178 SdrObject* pSdrObject = GetSdrObjectFromXShape(mxShape);
179 if( pSdrObject )
181 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, pSdrObject );
182 OutlinerParaObject* pOutlinerParaObject = NULL;
184 if( pTextObj )
185 pOutlinerParaObject = pTextObj->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active
187 bool bOwnParaObj = pOutlinerParaObject != NULL;
189 if( !pOutlinerParaObject && pSdrObject )
190 pOutlinerParaObject = pSdrObject->GetOutlinerParaObject();
192 // create AccessibleTextHelper to handle this shape's text
193 if( !pOutlinerParaObject )
195 // empty text -> use proxy edit source to delay creation of EditEngine
196 ::std::auto_ptr<SvxEditSource> pEditSource( new AccessibleEmptyEditSource ( *pSdrObject, *pView, *pWindow) );
197 mpText = new AccessibleTextHelper( pEditSource );
199 else
201 // non-empty text -> use full-fledged edit source right away
202 ::std::auto_ptr<SvxEditSource> pEditSource( new SvxTextEditSource ( *pSdrObject, 0, *pView, *pWindow) );
203 mpText = new AccessibleTextHelper( pEditSource );
206 if( bOwnParaObj )
207 delete pOutlinerParaObject;
209 mpText->SetEventSource(this);
218 void AccessibleShape::UpdateStates (void)
220 ::utl::AccessibleStateSetHelper* pStateSet =
221 static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
222 if (pStateSet == NULL)
223 return;
225 // Set the opaque state for certain shape types when their fill style is
226 // solid.
227 bool bShapeIsOpaque = false;
228 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
230 case DRAWING_PAGE:
231 case DRAWING_RECTANGLE:
232 case DRAWING_TEXT:
234 uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
235 if (xSet.is())
239 drawing::FillStyle aFillStyle;
240 bShapeIsOpaque = ( xSet->getPropertyValue (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FillStyle"))) >>= aFillStyle)
241 && aFillStyle == drawing::FillStyle_SOLID;
243 catch (::com::sun::star::beans::UnknownPropertyException&)
245 // Ignore.
250 if (bShapeIsOpaque)
251 pStateSet->AddState (AccessibleStateType::OPAQUE);
252 else
253 pStateSet->RemoveState (AccessibleStateType::OPAQUE);
255 // Set the selected state.
256 bool bShapeIsSelected = false;
257 // XXX fix_me this has to be done with an extra interface later on
258 if ( m_pShape && maShapeTreeInfo.GetSdrView() )
260 bShapeIsSelected = maShapeTreeInfo.GetSdrView()->IsObjMarked(m_pShape) == TRUE;
263 if (bShapeIsSelected)
264 pStateSet->AddState (AccessibleStateType::SELECTED);
265 else
266 pStateSet->RemoveState (AccessibleStateType::SELECTED);
272 bool AccessibleShape::operator== (const AccessibleShape& rShape)
274 return this==&rShape;
280 sal_Bool AccessibleShape::SetState (sal_Int16 aState)
282 sal_Bool bStateHasChanged = sal_False;
284 if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
286 // Offer FOCUSED state to edit engine and detect whether the state
287 // changes.
288 sal_Bool bIsFocused = mpText->HaveFocus ();
289 mpText->SetFocus (sal_True);
290 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
292 else
293 bStateHasChanged = AccessibleContextBase::SetState (aState);
295 return bStateHasChanged;
301 sal_Bool AccessibleShape::ResetState (sal_Int16 aState)
303 sal_Bool bStateHasChanged = sal_False;
305 if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
307 // Try to remove FOCUSED state from the edit engine and detect
308 // whether the state changes.
309 sal_Bool bIsFocused = mpText->HaveFocus ();
310 mpText->SetFocus (sal_False);
311 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
313 else
314 bStateHasChanged = AccessibleContextBase::ResetState (aState);
316 return bStateHasChanged;
322 sal_Bool AccessibleShape::GetState (sal_Int16 aState)
324 if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
326 // Just delegate the call to the edit engine. The state is not
327 // merged into the state set.
328 return mpText->HaveFocus();
330 else
331 return AccessibleContextBase::GetState (aState);
337 //===== XAccessibleContext ==================================================
339 /** The children of this shape come from two sources: The children from
340 group or scene shapes and the paragraphs of text.
342 sal_Int32 SAL_CALL
343 AccessibleShape::getAccessibleChildCount ()
344 throw (::com::sun::star::uno::RuntimeException)
346 ThrowIfDisposed ();
347 sal_Int32 nChildCount = 0;
349 // Add the number of shapes that are children of this shape.
350 if (mpChildrenManager != NULL)
351 nChildCount += mpChildrenManager->GetChildCount ();
352 // Add the number text paragraphs.
353 if (mpText != NULL)
354 nChildCount += mpText->GetChildCount ();
356 return nChildCount;
362 /** Forward the request to the shape. Return the requested shape or throw
363 an exception for a wrong index.
365 uno::Reference<XAccessible> SAL_CALL
366 AccessibleShape::getAccessibleChild (sal_Int32 nIndex)
367 throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
369 ThrowIfDisposed ();
371 uno::Reference<XAccessible> xChild;
373 // Depending on the index decide whether to delegate this call to the
374 // children manager or the edit engine.
375 if ((mpChildrenManager != NULL)
376 && (nIndex < mpChildrenManager->GetChildCount()))
378 xChild = mpChildrenManager->GetChild (nIndex);
380 else if (mpText != NULL)
382 sal_Int32 nI = nIndex;
383 if (mpChildrenManager != NULL)
384 nI -= mpChildrenManager->GetChildCount();
385 xChild = mpText->GetChild (nI);
387 else
388 throw lang::IndexOutOfBoundsException (
389 ::rtl::OUString::createFromAscii ("shape has no child with index ")
390 + rtl::OUString::valueOf(nIndex),
391 static_cast<uno::XWeak*>(this));
393 return xChild;
399 /** Return a copy of the state set.
400 Possible states are:
401 ENABLED
402 SHOWING
403 VISIBLE
405 uno::Reference<XAccessibleStateSet> SAL_CALL
406 AccessibleShape::getAccessibleStateSet (void)
407 throw (::com::sun::star::uno::RuntimeException)
409 ::osl::MutexGuard aGuard (maMutex);
410 Reference<XAccessibleStateSet> xStateSet;
412 if (rBHelper.bDisposed || mpText == NULL)
413 // Return a minimal state set that only contains the DEFUNC state.
414 xStateSet = AccessibleContextBase::getAccessibleStateSet ();
415 else
417 ::utl::AccessibleStateSetHelper* pStateSet =
418 static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
420 if (pStateSet != NULL)
422 // Merge current FOCUSED state from edit engine.
423 if (mpText != NULL)
425 if (mpText->HaveFocus())
426 pStateSet->AddState (AccessibleStateType::FOCUSED);
427 else
428 pStateSet->RemoveState (AccessibleStateType::FOCUSED);
431 // Create a copy of the state set that may be modified by the
432 // caller without affecting the current state set.
433 xStateSet = Reference<XAccessibleStateSet>(
434 new ::utl::AccessibleStateSetHelper (*pStateSet));
438 return xStateSet;
444 //===== XAccessibleComponent ================================================
446 /** The implementation below is at the moment straightforward. It iterates
447 over all children (and thereby instances all children which have not
448 been already instatiated) until a child covering the specifed point is
449 found.
450 This leaves room for improvement. For instance, first iterate only over
451 the already instantiated children and only if no match is found
452 instantiate the remaining ones.
454 uno::Reference<XAccessible > SAL_CALL
455 AccessibleShape::getAccessibleAtPoint (
456 const awt::Point& aPoint)
457 throw (uno::RuntimeException)
459 ::osl::MutexGuard aGuard (maMutex);
461 sal_Int32 nChildCount = getAccessibleChildCount ();
462 for (sal_Int32 i=0; i<nChildCount; ++i)
464 Reference<XAccessible> xChild (getAccessibleChild (i));
465 if (xChild.is())
467 Reference<XAccessibleComponent> xChildComponent (
468 xChild->getAccessibleContext(), uno::UNO_QUERY);
469 if (xChildComponent.is())
471 awt::Rectangle aBBox (xChildComponent->getBounds());
472 if ( (aPoint.X >= aBBox.X)
473 && (aPoint.Y >= aBBox.Y)
474 && (aPoint.X < aBBox.X+aBBox.Width)
475 && (aPoint.Y < aBBox.Y+aBBox.Height) )
476 return xChild;
481 // Have not found a child under the given point. Returning empty
482 // reference to indicate this.
483 return uno::Reference<XAccessible>();
489 awt::Rectangle SAL_CALL AccessibleShape::getBounds (void)
490 throw (::com::sun::star::uno::RuntimeException)
492 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
493 ::osl::MutexGuard aGuard (maMutex);
495 ThrowIfDisposed ();
496 awt::Rectangle aBoundingBox;
497 if ( mxShape.is() )
500 static const OUString sBoundRectName (
501 RTL_CONSTASCII_USTRINGPARAM("BoundRect"));
502 static const OUString sAnchorPositionName (
503 RTL_CONSTASCII_USTRINGPARAM("AnchorPosition"));
505 // Get the shape's bounding box in internal coordinates (in 100th of
506 // mm). Use the property BoundRect. Only if that is not supported ask
507 // the shape for its position and size directly.
508 Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
509 Reference<beans::XPropertySetInfo> xSetInfo;
510 bool bFoundBoundRect = false;
511 if (xSet.is())
513 xSetInfo = xSet->getPropertySetInfo ();
514 if (xSetInfo.is())
516 if (xSetInfo->hasPropertyByName (sBoundRectName))
520 uno::Any aValue = xSet->getPropertyValue (sBoundRectName);
521 aValue >>= aBoundingBox;
522 bFoundBoundRect = true;
524 catch (beans::UnknownPropertyException e)
526 // Handled below (bFoundBoundRect stays false).
529 else
530 OSL_TRACE (" no property BoundRect");
534 // Fallback when there is no BoundRect Property.
535 if ( ! bFoundBoundRect )
537 awt::Point aPosition (mxShape->getPosition());
538 awt::Size aSize (mxShape->getSize());
539 aBoundingBox = awt::Rectangle (
540 aPosition.X, aPosition.Y,
541 aSize.Width, aSize.Height);
543 // While BoundRects have absolute positions, the position returned
544 // by XPosition::getPosition is relative. Get the anchor position
545 // (usually not (0,0) for Writer shapes).
546 if (xSetInfo.is())
548 if (xSetInfo->hasPropertyByName (sAnchorPositionName))
550 uno::Any aPos = xSet->getPropertyValue (sAnchorPositionName);
551 awt::Point aAnchorPosition;
552 aPos >>= aAnchorPosition;
553 aBoundingBox.X += aAnchorPosition.X;
554 aBoundingBox.Y += aAnchorPosition.Y;
559 // Transform coordinates from internal to pixel.
560 if (maShapeTreeInfo.GetViewForwarder() == NULL)
561 throw uno::RuntimeException (::rtl::OUString (
562 RTL_CONSTASCII_USTRINGPARAM(
563 "AccessibleShape has no valid view forwarder")),
564 static_cast<uno::XWeak*>(this));
565 ::Size aPixelSize = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
566 ::Size (aBoundingBox.Width, aBoundingBox.Height));
567 ::Point aPixelPosition = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
568 ::Point (aBoundingBox.X, aBoundingBox.Y));
570 // Clip the shape's bounding box with the bounding box of its parent.
571 Reference<XAccessibleComponent> xParentComponent (
572 getAccessibleParent(), uno::UNO_QUERY);
573 if (xParentComponent.is())
575 // Make the coordinates relative to the parent.
576 awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
577 int x = aPixelPosition.getX() - aParentLocation.X;
578 int y = aPixelPosition.getY() - aParentLocation.Y;
580 /* // The following block is a workarround for bug #99889# (property
581 // BoundRect returnes coordinates relative to document window
582 // instead of absolute coordinates for shapes in Writer). Has to
583 // be removed as soon as bug is fixed.
585 // Use a non-null anchor position as flag that the shape is in a
586 // Writer document.
587 if (xSetInfo.is())
588 if (xSetInfo->hasPropertyByName (sAnchorPositionName))
590 uno::Any aPos = xSet->getPropertyValue (sAnchorPositionName);
591 awt::Point aAnchorPosition;
592 aPos >>= aAnchorPosition;
593 if (aAnchorPosition.X > 0)
595 x = aPixelPosition.getX();
596 y = aPixelPosition.getY();
599 // End of workarround.
601 // Clip with parent (with coordinates relative to itself).
602 ::Rectangle aBBox (
603 x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
604 awt::Size aParentSize (xParentComponent->getSize());
605 ::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
606 aBBox = aBBox.GetIntersection (aParentBBox);
607 aBoundingBox = awt::Rectangle (
608 aBBox.getX(),
609 aBBox.getY(),
610 aBBox.getWidth(),
611 aBBox.getHeight());
613 else
615 OSL_TRACE ("parent does not support component");
616 aBoundingBox = awt::Rectangle (
617 aPixelPosition.getX(), aPixelPosition.getY(),
618 aPixelSize.getWidth(), aPixelSize.getHeight());
622 return aBoundingBox;
628 awt::Point SAL_CALL AccessibleShape::getLocation (void)
629 throw (::com::sun::star::uno::RuntimeException)
631 ThrowIfDisposed ();
632 awt::Rectangle aBoundingBox (getBounds());
633 return awt::Point (aBoundingBox.X, aBoundingBox.Y);
639 awt::Point SAL_CALL AccessibleShape::getLocationOnScreen (void)
640 throw (::com::sun::star::uno::RuntimeException)
642 ThrowIfDisposed ();
644 // Get relative position...
645 awt::Point aLocation (getLocation ());
647 // ... and add absolute position of the parent.
648 uno::Reference<XAccessibleComponent> xParentComponent (
649 getAccessibleParent(), uno::UNO_QUERY);
650 if (xParentComponent.is())
652 awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
653 aLocation.X += aParentLocation.X;
654 aLocation.Y += aParentLocation.Y;
656 else
657 OSL_TRACE ("getLocation: parent does not support XAccessibleComponent");
658 return aLocation;
664 awt::Size SAL_CALL AccessibleShape::getSize (void)
665 throw (uno::RuntimeException)
667 ThrowIfDisposed ();
668 awt::Rectangle aBoundingBox (getBounds());
669 return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
675 sal_Int32 SAL_CALL AccessibleShape::getForeground (void)
676 throw (::com::sun::star::uno::RuntimeException)
678 ThrowIfDisposed ();
679 sal_Int32 nColor (0x0ffffffL);
683 uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
684 if (aSet.is())
686 uno::Any aColor;
687 aColor = aSet->getPropertyValue (OUString::createFromAscii ("LineColor"));
688 aColor >>= nColor;
691 catch (::com::sun::star::beans::UnknownPropertyException)
693 // Ignore exception and return default color.
695 return nColor;
701 sal_Int32 SAL_CALL AccessibleShape::getBackground (void)
702 throw (::com::sun::star::uno::RuntimeException)
704 ThrowIfDisposed ();
705 sal_Int32 nColor (0L);
709 uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
710 if (aSet.is())
712 uno::Any aColor;
713 aColor = aSet->getPropertyValue (OUString::createFromAscii ("FillColor"));
714 aColor >>= nColor;
717 catch (::com::sun::star::beans::UnknownPropertyException)
719 // Ignore exception and return default color.
721 return nColor;
727 //===== XAccessibleEventBroadcaster =========================================
729 void SAL_CALL AccessibleShape::addEventListener (
730 const Reference<XAccessibleEventListener >& rxListener)
731 throw (uno::RuntimeException)
733 if (rBHelper.bDisposed || rBHelper.bInDispose)
735 uno::Reference<uno::XInterface> xThis (
736 (lang::XComponent *)this, uno::UNO_QUERY);
737 rxListener->disposing (lang::EventObject (xThis));
739 else
741 AccessibleContextBase::addEventListener (rxListener);
742 if (mpText != NULL)
743 mpText->AddEventListener (rxListener);
750 void SAL_CALL AccessibleShape::removeEventListener (
751 const Reference<XAccessibleEventListener >& rxListener)
752 throw (uno::RuntimeException)
754 AccessibleContextBase::removeEventListener (rxListener);
755 if (mpText != NULL)
756 mpText->RemoveEventListener (rxListener);
762 //===== XInterface ==========================================================
764 com::sun::star::uno::Any SAL_CALL
765 AccessibleShape::queryInterface (const com::sun::star::uno::Type & rType)
766 throw (::com::sun::star::uno::RuntimeException)
768 ::com::sun::star::uno::Any aReturn = AccessibleContextBase::queryInterface (rType);
769 if ( ! aReturn.hasValue())
770 aReturn = ::cppu::queryInterface (rType,
771 static_cast<XAccessibleComponent*>(this),
772 static_cast<XAccessibleExtendedComponent*>(this),
773 static_cast<lang::XEventListener*>(this),
774 static_cast<document::XEventListener*>(this),
775 static_cast<lang::XUnoTunnel*>(this)
777 return aReturn;
783 void SAL_CALL
784 AccessibleShape::acquire (void)
785 throw ()
787 AccessibleContextBase::acquire ();
793 void SAL_CALL
794 AccessibleShape::release (void)
795 throw ()
797 AccessibleContextBase::release ();
803 //===== XServiceInfo ========================================================
805 ::rtl::OUString SAL_CALL
806 AccessibleShape::getImplementationName (void)
807 throw (::com::sun::star::uno::RuntimeException)
809 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleShape"));
815 uno::Sequence<OUString> SAL_CALL
816 AccessibleShape::getSupportedServiceNames (void)
817 throw (::com::sun::star::uno::RuntimeException)
819 ThrowIfDisposed ();
820 // Get list of supported service names from base class...
821 uno::Sequence<OUString> aServiceNames =
822 AccessibleContextBase::getSupportedServiceNames();
823 sal_Int32 nCount (aServiceNames.getLength());
825 // ...and add additional names.
826 aServiceNames.realloc (nCount + 1);
827 static const OUString sAdditionalServiceName (RTL_CONSTASCII_USTRINGPARAM(
828 "com.sun.star.drawing.AccessibleShape"));
829 aServiceNames[nCount] = sAdditionalServiceName;
831 return aServiceNames;
838 //===== XTypeProvider ===================================================
840 uno::Sequence<uno::Type> SAL_CALL
841 AccessibleShape::getTypes (void)
842 throw (uno::RuntimeException)
844 ThrowIfDisposed ();
845 // Get list of types from the context base implementation, ...
846 uno::Sequence<uno::Type> aTypeList (AccessibleContextBase::getTypes());
847 // ... get list of types from component base implementation, ...
848 uno::Sequence<uno::Type> aComponentTypeList (AccessibleComponentBase::getTypes());
849 // ... define local types, ...
850 const uno::Type aLangEventListenerType =
851 ::getCppuType((const uno::Reference<lang::XEventListener>*)0);
852 const uno::Type aDocumentEventListenerType =
853 ::getCppuType((const uno::Reference<document::XEventListener>*)0);
854 const uno::Type aUnoTunnelType =
855 ::getCppuType((const uno::Reference<lang::XUnoTunnel>*)0);
856 // const uno::Type aStateSetType =
857 // ::getCppuType((const uno::Reference<XAccessibleStateSet>*)0);
859 // ... and merge them all into one list.
860 sal_Int32 nTypeCount (aTypeList.getLength()),
861 nComponentTypeCount (aComponentTypeList.getLength());
862 int i;
864 aTypeList.realloc (nTypeCount + nComponentTypeCount + 3);
866 for (i=0; i<nComponentTypeCount; i++)
867 aTypeList[nTypeCount + i] = aComponentTypeList[i];
869 aTypeList[nTypeCount + i++ ] = aLangEventListenerType;
870 aTypeList[nTypeCount + i++ ] = aDocumentEventListenerType;
871 aTypeList[nTypeCount + i ] = aUnoTunnelType;
873 return aTypeList;
879 //===== lang::XEventListener ================================================
881 /** Disposing calls are accepted only from the model: Just reset the
882 reference to the model in the shape tree info. Otherwise this object
883 remains functional.
885 void SAL_CALL
886 AccessibleShape::disposing (const lang::EventObject& aEvent)
887 throw (uno::RuntimeException)
889 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
890 ::osl::MutexGuard aGuard (maMutex);
894 if (aEvent.Source == maShapeTreeInfo.GetModelBroadcaster())
896 // Remove reference to model broadcaster to allow it to pass
897 // away.
898 maShapeTreeInfo.SetModelBroadcaster(NULL);
902 catch (uno::RuntimeException e)
904 OSL_TRACE ("caught exception while disposing");
911 //===== document::XEventListener ============================================
913 void SAL_CALL
914 AccessibleShape::notifyEvent (const document::EventObject& rEventObject)
915 throw (uno::RuntimeException)
917 static const OUString sShapeModified (
918 RTL_CONSTASCII_USTRINGPARAM("ShapeModified"));
920 // First check if the event is for us.
921 uno::Reference<drawing::XShape> xShape (
922 rEventObject.Source, uno::UNO_QUERY);
923 if ( xShape.get() == mxShape.get() )
925 if (rEventObject.EventName.equals (sShapeModified))
927 // Some property of a shape has been modified. Send an event
928 // that indicates a change of the visible data to all listeners.
929 CommitChange (
930 AccessibleEventId::VISIBLE_DATA_CHANGED,
931 uno::Any(),
932 uno::Any());
934 // Name and Description may have changed. Update the local
935 // values accordingly.
936 UpdateNameAndDescription();
944 //===== lang::XUnoTunnel ================================================
946 const uno::Sequence< sal_Int8 >&
947 AccessibleShape::getUnoTunnelImplementationId()
948 throw()
950 static uno::Sequence< sal_Int8 >* pSeq = 0;
952 if( !pSeq )
954 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
956 if( !pSeq )
958 static uno::Sequence< sal_Int8 > aSeq( 16 );
959 rtl_createUuid( (sal_uInt8*) aSeq.getArray(), 0, sal_True );
960 pSeq = &aSeq;
964 return( *pSeq );
967 //------------------------------------------------------------------------------
968 AccessibleShape*
969 AccessibleShape::getImplementation( const uno::Reference< uno::XInterface >& rxIFace )
970 throw()
972 uno::Reference< lang::XUnoTunnel > xTunnel( rxIFace, uno::UNO_QUERY );
973 AccessibleShape* pReturn = NULL;
975 if( xTunnel.is() )
976 pReturn = reinterpret_cast< AccessibleShape* >( xTunnel->getSomething( getUnoTunnelImplementationId() ) );
978 return( pReturn );
981 //------------------------------------------------------------------------------
982 sal_Int64 SAL_CALL
983 AccessibleShape::getSomething( const uno::Sequence< sal_Int8 >& rIdentifier )
984 throw(uno::RuntimeException)
986 sal_Int64 nReturn( 0 );
988 if( ( rIdentifier.getLength() == 16 ) && ( 0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(), rIdentifier.getConstArray(), 16 ) ) )
989 nReturn = reinterpret_cast< sal_Int64 >( this );
991 return( nReturn );
994 //===== IAccessibleViewForwarderListener ====================================
996 void AccessibleShape::ViewForwarderChanged (ChangeType aChangeType,
997 const IAccessibleViewForwarder* pViewForwarder)
999 // Inform all listeners that the graphical representation (i.e. size
1000 // and/or position) of the shape has changed.
1001 CommitChange (AccessibleEventId::VISIBLE_DATA_CHANGED,
1002 uno::Any(),
1003 uno::Any());
1005 // Tell children manager of the modified view forwarder.
1006 if (mpChildrenManager != NULL)
1007 mpChildrenManager->ViewForwarderChanged (aChangeType, pViewForwarder);
1009 // update our children that our screen position might have changed
1010 if( mpText )
1011 mpText->UpdateChildren();
1017 //===== protected internal ==================================================
1018 /// Set this object's name if is different to the current name.
1019 ::rtl::OUString
1020 AccessibleShape::CreateAccessibleBaseName (void)
1021 throw (::com::sun::star::uno::RuntimeException)
1023 return ShapeTypeHandler::CreateAccessibleBaseName( mxShape );
1027 ::rtl::OUString
1028 AccessibleShape::CreateAccessibleName (void)
1029 throw (::com::sun::star::uno::RuntimeException)
1031 OUString sName (CreateAccessibleBaseName());
1033 // Append the shape's index to the name to disambiguate between shapes
1034 // of the same type. If such an index where not given to the
1035 // constructor then use the z-order instead. If even that does not exist
1036 // we throw an exception.
1037 long nIndex = mnIndex;
1038 if (nIndex == -1)
1042 uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
1043 if (xSet.is())
1045 uno::Any aZOrder (xSet->getPropertyValue (::rtl::OUString::createFromAscii ("ZOrder")));
1046 aZOrder >>= nIndex;
1048 // Add one to be not zero based.
1049 nIndex += 1;
1052 catch (beans::UnknownPropertyException)
1054 // We throw our own exception that is a bit more informative.
1055 throw uno::RuntimeException (::rtl::OUString (
1056 RTL_CONSTASCII_USTRINGPARAM("AccessibleShape has invalid index and no ZOrder property")),
1057 static_cast<uno::XWeak*>(this));
1062 // Put a space between name and index because of Gnopernicus othewise
1063 // spells the name.
1064 sName += OUString (RTL_CONSTASCII_USTRINGPARAM(" ")) + OUString::valueOf (nIndex);
1066 return sName;
1072 ::rtl::OUString
1073 AccessibleShape::CreateAccessibleDescription (void)
1074 throw (::com::sun::star::uno::RuntimeException)
1076 DescriptionGenerator aDG (mxShape);
1077 aDG.Initialize (CreateAccessibleBaseName());
1078 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
1080 case DRAWING_3D_CUBE:
1081 case DRAWING_3D_EXTRUDE:
1082 case DRAWING_3D_LATHE:
1083 case DRAWING_3D_SPHERE:
1084 aDG.Add3DProperties ();
1085 break;
1087 case DRAWING_3D_SCENE:
1088 case DRAWING_GROUP:
1089 case DRAWING_PAGE:
1090 // No further information is appended.
1091 break;
1093 case DRAWING_CAPTION:
1094 case DRAWING_CLOSED_BEZIER:
1095 case DRAWING_CLOSED_FREEHAND:
1096 case DRAWING_ELLIPSE:
1097 case DRAWING_POLY_POLYGON:
1098 case DRAWING_POLY_POLYGON_PATH:
1099 case DRAWING_RECTANGLE:
1100 aDG.AddLineProperties ();
1101 aDG.AddFillProperties ();
1102 break;
1104 case DRAWING_CONNECTOR:
1105 case DRAWING_LINE:
1106 case DRAWING_MEASURE:
1107 case DRAWING_OPEN_BEZIER:
1108 case DRAWING_OPEN_FREEHAND:
1109 case DRAWING_POLY_LINE:
1110 case DRAWING_POLY_LINE_PATH:
1111 aDG.AddLineProperties ();
1112 break;
1114 case DRAWING_CONTROL:
1115 aDG.AddProperty (OUString::createFromAscii ("ControlBackground"),
1116 DescriptionGenerator::COLOR,
1117 OUString());
1118 aDG.AddProperty (OUString::createFromAscii ("ControlBorder"),
1119 DescriptionGenerator::INTEGER,
1120 OUString());
1121 break;
1123 case DRAWING_TEXT:
1124 aDG.AddTextProperties ();
1125 break;
1127 default:
1128 aDG.Initialize (::rtl::OUString (
1129 RTL_CONSTASCII_USTRINGPARAM("Unknown accessible shape")));
1130 uno::Reference<drawing::XShapeDescriptor> xDescriptor (mxShape, uno::UNO_QUERY);
1131 if (xDescriptor.is())
1133 aDG.AppendString (::rtl::OUString (RTL_CONSTASCII_USTRINGPARAM("service name=")));
1134 aDG.AppendString (xDescriptor->getShapeType());
1138 return aDG();
1144 uno::Reference< drawing::XShape > AccessibleShape::GetXShape()
1146 return( mxShape );
1151 // protected
1152 void AccessibleShape::disposing (void)
1154 ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
1155 ::osl::MutexGuard aGuard (maMutex);
1157 // Make sure to send an event that this object looses the focus in the
1158 // case that it has the focus.
1159 ::utl::AccessibleStateSetHelper* pStateSet =
1160 static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
1161 if (pStateSet != NULL)
1162 pStateSet->RemoveState (AccessibleStateType::FOCUSED);
1164 // Unregister from broadcasters.
1165 Reference<lang::XComponent> xComponent (mxShape, uno::UNO_QUERY);
1166 if (xComponent.is())
1167 xComponent->removeEventListener (this);
1169 // Unregister from model.
1170 if (maShapeTreeInfo.GetModelBroadcaster().is())
1171 maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
1172 static_cast<document::XEventListener*>(this));
1174 // Release the child containers.
1175 if (mpChildrenManager != NULL)
1177 delete mpChildrenManager;
1178 mpChildrenManager = NULL;
1180 if (mpText != NULL)
1182 mpText->Dispose();
1183 delete mpText;
1184 mpText = NULL;
1187 // Cleanup. Remove references to objects to allow them to be
1188 // destroyed.
1189 mxShape = NULL;
1190 maShapeTreeInfo = AccessibleShapeTreeInfo();
1192 // Call base classes.
1193 AccessibleContextBase::dispose ();
1196 sal_Int32 SAL_CALL
1197 AccessibleShape::getAccessibleIndexInParent (void)
1198 throw (::com::sun::star::uno::RuntimeException)
1200 ThrowIfDisposed ();
1201 // Use a simple but slow solution for now. Optimize later.
1203 sal_Int32 nIndex = m_nIndexInParent;
1204 if ( -1 == nIndex )
1205 nIndex = AccessibleContextBase::getAccessibleIndexInParent();
1206 return nIndex;
1212 void AccessibleShape::UpdateNameAndDescription (void)
1214 // Ignore missing title, name, or description. There are fallbacks for
1215 // them.
1218 Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY_THROW);
1219 OUString sString;
1221 // Get the accessible name.
1222 sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Title")));
1223 if (sString.getLength() > 0)
1225 SetAccessibleName(sString, AccessibleContextBase::FromShape);
1227 else
1229 sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Name")));
1230 if (sString.getLength() > 0)
1231 SetAccessibleName(sString, AccessibleContextBase::FromShape);
1234 // Get the accessible description.
1235 sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Description")));
1236 if (sString.getLength() > 0)
1237 SetAccessibleDescription(sString, AccessibleContextBase::FromShape);
1239 catch (uno::RuntimeException&)
1247 } // end of namespace accessibility