1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svx/AccessibleShape.hxx>
21 #include <svx/AccessibleShapeInfo.hxx>
22 #include <com/sun/star/accessibility/AccessibleRole.hpp>
23 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
24 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
25 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/drawing/XShapes.hpp>
28 #include <com/sun/star/document/XShapeEventBroadcaster.hpp>
29 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30 #include <com/sun/star/drawing/FillStyle.hpp>
31 #include <com/sun/star/text/XText.hpp>
32 #include <sal/log.hxx>
33 #include <editeng/unoedsrc.hxx>
34 #include <svx/AccessibleTextHelper.hxx>
35 #include <svx/ChildrenManager.hxx>
36 #include <svx/IAccessibleParent.hxx>
37 #include <svx/IAccessibleViewForwarder.hxx>
38 #include <svx/unoshtxt.hxx>
39 #include <svx/svdobj.hxx>
40 #include <svx/unoapi.hxx>
41 #include <svx/svdpage.hxx>
42 #include <svx/ShapeTypeHandler.hxx>
43 #include <svx/SvxShapeTypes.hxx>
45 #include <vcl/svapp.hxx>
46 #include <unotools/accessiblestatesethelper.hxx>
47 #include <unotools/accessiblerelationsethelper.hxx>
48 #include <svx/svdview.hxx>
49 #include <tools/diagnose_ex.h>
50 #include <cppuhelper/queryinterface.hxx>
51 #include <comphelper/sequence.hxx>
52 #include "AccessibleEmptyEditSource.hxx"
57 using namespace ::com::sun::star
;
58 using namespace ::com::sun::star::accessibility
;
59 using ::com::sun::star::uno::Reference
;
60 using ::com::sun::star::lang::IndexOutOfBoundsException
;
61 using ::com::sun::star::uno::RuntimeException
;
63 namespace accessibility
{
67 OUString
GetOptionalProperty (
68 const Reference
<beans::XPropertySet
>& rxSet
,
69 const OUString
& rsPropertyName
)
75 const Reference
<beans::XPropertySetInfo
> xInfo (rxSet
->getPropertySetInfo());
76 if ( ! xInfo
.is() || xInfo
->hasPropertyByName(rsPropertyName
))
80 rxSet
->getPropertyValue(rsPropertyName
) >>= sValue
;
82 catch (beans::UnknownPropertyException
&)
84 // This exception should only be thrown when the property
85 // does not exits (of course) and the XPropertySetInfo is
93 } // end of anonymous namespace
96 AccessibleShape::AccessibleShape (
97 const AccessibleShapeInfo
& rShapeInfo
,
98 const AccessibleShapeTreeInfo
& rShapeTreeInfo
)
99 : AccessibleContextBase (rShapeInfo
.mxParent
,AccessibleRole::SHAPE
),
100 mxShape (rShapeInfo
.mxShape
),
101 maShapeTreeInfo (rShapeTreeInfo
),
102 m_nIndexInParent(-1),
103 mpParent (rShapeInfo
.mpChildrenManager
)
105 m_pShape
= GetSdrObjectFromXShape(mxShape
);
106 UpdateNameAndDescription();
109 AccessibleShape::~AccessibleShape()
111 mpChildrenManager
.reset();
113 SAL_INFO("svx", "~AccessibleShape");
115 // Unregistering from the various broadcasters should be unnecessary
116 // since this destructor would not have been called if one of the
117 // broadcasters would still hold a strong reference to this object.
120 void AccessibleShape::Init()
122 // Update the OPAQUE and SELECTED shape.
125 // Create a children manager when this shape has children of its own.
126 Reference
<drawing::XShapes
> xShapes (mxShape
, uno::UNO_QUERY
);
127 if (xShapes
.is() && xShapes
->getCount() > 0)
128 mpChildrenManager
.reset( new ChildrenManager (
129 this, xShapes
, maShapeTreeInfo
, *this) );
130 if (mpChildrenManager
!= nullptr)
131 mpChildrenManager
->Update();
133 // Register at model as document::XEventListener.
134 if (mxShape
.is() && maShapeTreeInfo
.GetModelBroadcaster().is())
135 maShapeTreeInfo
.GetModelBroadcaster()->addShapeEventListener(mxShape
,
136 static_cast<document::XShapeEventListener
*>(this));
138 // Beware! Here we leave the paths of the UNO API and descend into the
139 // depths of the core. Necessary for making the edit engine
141 Reference
<text::XText
> xText (mxShape
, uno::UNO_QUERY
);
145 SdrView
* pView
= maShapeTreeInfo
.GetSdrView ();
146 const vcl::Window
* pWindow
= maShapeTreeInfo
.GetWindow ();
147 if (!(pView
!= nullptr && pWindow
!= nullptr && mxShape
.is()))
150 // #107948# Determine whether shape text is empty
151 SdrObject
* pSdrObject
= GetSdrObjectFromXShape(mxShape
);
155 SdrTextObj
* pTextObj
= dynamic_cast<SdrTextObj
*>( pSdrObject
);
156 const bool hasOutlinerParaObject
= (pTextObj
&& pTextObj
->CanCreateEditOutlinerParaObject()) || (pSdrObject
->GetOutlinerParaObject() != nullptr);
158 // create AccessibleTextHelper to handle this shape's text
159 if( !hasOutlinerParaObject
)
161 // empty text -> use proxy edit source to delay creation of EditEngine
162 mpText
.reset( new AccessibleTextHelper( std::make_unique
<AccessibleEmptyEditSource
>(*pSdrObject
, *pView
, *pWindow
) ) );
166 // non-empty text -> use full-fledged edit source right away
167 mpText
.reset( new AccessibleTextHelper( std::make_unique
<SvxTextEditSource
>(*pSdrObject
, nullptr, *pView
, *pWindow
) ) );
169 if( pWindow
->HasFocus() )
172 mpText
->SetEventSource(this);
176 void AccessibleShape::UpdateStates()
178 ::utl::AccessibleStateSetHelper
* pStateSet
=
179 static_cast< ::utl::AccessibleStateSetHelper
*>(mxStateSet
.get());
180 if (pStateSet
== nullptr)
183 // Set the opaque state for certain shape types when their fill style is
185 bool bShapeIsOpaque
= false;
186 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape
))
189 case DRAWING_RECTANGLE
:
192 uno::Reference
<beans::XPropertySet
> xSet (mxShape
, uno::UNO_QUERY
);
197 drawing::FillStyle aFillStyle
;
198 bShapeIsOpaque
= ( xSet
->getPropertyValue ("FillStyle") >>= aFillStyle
)
199 && aFillStyle
== drawing::FillStyle_SOLID
;
201 catch (css::beans::UnknownPropertyException
&)
209 pStateSet
->AddState (AccessibleStateType::OPAQUE
);
211 pStateSet
->RemoveState (AccessibleStateType::OPAQUE
);
213 // Set the selected state.
214 bool bShapeIsSelected
= false;
215 // XXX fix_me this has to be done with an extra interface later on
216 if ( m_pShape
&& maShapeTreeInfo
.GetSdrView() )
218 bShapeIsSelected
= maShapeTreeInfo
.GetSdrView()->IsObjMarked(m_pShape
);
221 if (bShapeIsSelected
)
222 pStateSet
->AddState (AccessibleStateType::SELECTED
);
224 pStateSet
->RemoveState (AccessibleStateType::SELECTED
);
227 OUString
AccessibleShape::GetStyle()
229 return ShapeTypeHandler::CreateAccessibleBaseName( mxShape
);
232 bool AccessibleShape::SetState (sal_Int16 aState
)
234 bool bStateHasChanged
= false;
236 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
238 // Offer FOCUSED state to edit engine and detect whether the state
240 bool bIsFocused
= mpText
->HaveFocus ();
242 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
245 bStateHasChanged
= AccessibleContextBase::SetState (aState
);
247 return bStateHasChanged
;
251 bool AccessibleShape::ResetState (sal_Int16 aState
)
253 bool bStateHasChanged
= false;
255 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
257 // Try to remove FOCUSED state from the edit engine and detect
258 // whether the state changes.
259 bool bIsFocused
= mpText
->HaveFocus ();
260 mpText
->SetFocus (false);
261 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
264 bStateHasChanged
= AccessibleContextBase::ResetState (aState
);
266 return bStateHasChanged
;
270 bool AccessibleShape::GetState (sal_Int16 aState
)
272 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
274 // Just delegate the call to the edit engine. The state is not
275 // merged into the state set.
276 return mpText
->HaveFocus();
279 return AccessibleContextBase::GetState (aState
);
282 // OverWrite the parent's getAccessibleName method
283 OUString SAL_CALL
AccessibleShape::getAccessibleName()
286 if (m_pShape
&& !m_pShape
->GetTitle().isEmpty())
287 return CreateAccessibleName() + " " + m_pShape
->GetTitle();
289 return CreateAccessibleName();
292 OUString SAL_CALL
AccessibleShape::getAccessibleDescription()
295 if( m_pShape
&& !m_pShape
->GetDescription().isEmpty())
296 return m_pShape
->GetDescription() ;
301 // XAccessibleContext
302 /** The children of this shape come from two sources: The children from
303 group or scene shapes and the paragraphs of text.
306 AccessibleShape::getAccessibleChildCount ()
313 sal_Int32 nChildCount
= 0;
315 // Add the number of shapes that are children of this shape.
316 if (mpChildrenManager
!= nullptr)
317 nChildCount
+= mpChildrenManager
->GetChildCount ();
318 // Add the number text paragraphs.
319 if (mpText
!= nullptr)
320 nChildCount
+= mpText
->GetChildCount ();
326 /** Forward the request to the shape. Return the requested shape or throw
327 an exception for a wrong index.
329 uno::Reference
<XAccessible
> SAL_CALL
330 AccessibleShape::getAccessibleChild (sal_Int32 nIndex
)
334 uno::Reference
<XAccessible
> xChild
;
336 // Depending on the index decide whether to delegate this call to the
337 // children manager or the edit engine.
338 if ((mpChildrenManager
!= nullptr)
339 && (nIndex
< mpChildrenManager
->GetChildCount()))
341 xChild
= mpChildrenManager
->GetChild (nIndex
);
343 else if (mpText
!= nullptr)
345 sal_Int32 nI
= nIndex
;
346 if (mpChildrenManager
!= nullptr)
347 nI
-= mpChildrenManager
->GetChildCount();
348 xChild
= mpText
->GetChild (nI
);
351 throw lang::IndexOutOfBoundsException (
352 "shape has no child with index " + OUString::number(nIndex
),
353 static_cast<uno::XWeak
*>(this));
358 uno::Reference
<XAccessibleRelationSet
> SAL_CALL
359 AccessibleShape::getAccessibleRelationSet()
361 ::osl::MutexGuard
aGuard (maMutex
);
362 if (mpParent
== nullptr)
363 return uno::Reference
<XAccessibleRelationSet
>();
365 ::utl::AccessibleRelationSetHelper
* pRelationSet
= new utl::AccessibleRelationSetHelper
;
367 //this mxshape is the captioned shape
368 uno::Sequence
< uno::Reference
< uno::XInterface
> > aSequence
{ mpParent
->GetAccessibleCaption(mxShape
) };
371 pRelationSet
->AddRelation(
372 AccessibleRelation( AccessibleRelationType::DESCRIBED_BY
, aSequence
) );
374 return uno::Reference
<XAccessibleRelationSet
>(pRelationSet
);
377 /** Return a copy of the state set.
383 uno::Reference
<XAccessibleStateSet
> SAL_CALL
384 AccessibleShape::getAccessibleStateSet()
386 ::osl::MutexGuard
aGuard (maMutex
);
390 // Return a minimal state set that only contains the DEFUNC state.
391 return AccessibleContextBase::getAccessibleStateSet ();
394 ::utl::AccessibleStateSetHelper
* pStateSet
=
395 static_cast<::utl::AccessibleStateSetHelper
*>(mxStateSet
.get());
398 return Reference
<XAccessibleStateSet
>();
400 // Merge current FOCUSED state from edit engine.
403 if (mpText
->HaveFocus())
404 pStateSet
->AddState (AccessibleStateType::FOCUSED
);
406 pStateSet
->RemoveState (AccessibleStateType::FOCUSED
);
408 //Just when the document is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
409 css::uno::Reference
<XAccessible
> xTempAcc
= getAccessibleParent();
412 css::uno::Reference
<XAccessibleContext
>
413 xTempAccContext
= xTempAcc
->getAccessibleContext();
414 if( xTempAccContext
.is() )
416 css::uno::Reference
<XAccessibleStateSet
> rState
=
417 xTempAccContext
->getAccessibleStateSet();
420 css::uno::Sequence
<short> aStates
= rState
->getStates();
421 if (std::find(aStates
.begin(), aStates
.end(), AccessibleStateType::EDITABLE
) != aStates
.end())
423 pStateSet
->AddState (AccessibleStateType::EDITABLE
);
424 pStateSet
->AddState (AccessibleStateType::RESIZABLE
);
425 pStateSet
->AddState (AccessibleStateType::MOVEABLE
);
431 // Create a copy of the state set that may be modified by the
432 // caller without affecting the current state set.
433 Reference
<XAccessibleStateSet
> xStateSet(new ::utl::AccessibleStateSetHelper(*pStateSet
));
435 if (mpParent
&& mpParent
->IsDocumentSelAll())
437 ::utl::AccessibleStateSetHelper
* pCopyStateSet
=
438 static_cast<::utl::AccessibleStateSetHelper
*>(xStateSet
.get());
439 pCopyStateSet
->AddState (AccessibleStateType::SELECTED
);
445 // 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 instantiated) until a child covering the specified point is
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
)
458 ::osl::MutexGuard
aGuard (maMutex
);
460 sal_Int32 nChildCount
= getAccessibleChildCount ();
461 for (sal_Int32 i
=0; i
<nChildCount
; ++i
)
463 Reference
<XAccessible
> xChild (getAccessibleChild (i
));
466 Reference
<XAccessibleComponent
> xChildComponent (
467 xChild
->getAccessibleContext(), uno::UNO_QUERY
);
468 if (xChildComponent
.is())
470 awt::Rectangle
aBBox (xChildComponent
->getBounds());
471 if ( (aPoint
.X
>= aBBox
.X
)
472 && (aPoint
.Y
>= aBBox
.Y
)
473 && (aPoint
.X
< aBBox
.X
+aBBox
.Width
)
474 && (aPoint
.Y
< aBBox
.Y
+aBBox
.Height
) )
480 // Have not found a child under the given point. Returning empty
481 // reference to indicate this.
482 return uno::Reference
<XAccessible
>();
486 awt::Rectangle SAL_CALL
AccessibleShape::getBounds()
488 SolarMutexGuard aSolarGuard
;
489 ::osl::MutexGuard
aGuard (maMutex
);
492 awt::Rectangle aBoundingBox
;
496 static const char sBoundRectName
[] = "BoundRect";
497 static const char sAnchorPositionName
[] = "AnchorPosition";
499 // Get the shape's bounding box in internal coordinates (in 100th of
500 // mm). Use the property BoundRect. Only if that is not supported ask
501 // the shape for its position and size directly.
502 Reference
<beans::XPropertySet
> xSet (mxShape
, uno::UNO_QUERY
);
503 Reference
<beans::XPropertySetInfo
> xSetInfo
;
504 bool bFoundBoundRect
= false;
507 xSetInfo
= xSet
->getPropertySetInfo ();
510 if (xSetInfo
->hasPropertyByName (sBoundRectName
))
514 uno::Any aValue
= xSet
->getPropertyValue (sBoundRectName
);
515 aValue
>>= aBoundingBox
;
516 bFoundBoundRect
= true;
518 catch (beans::UnknownPropertyException
const&)
520 // Handled below (bFoundBoundRect stays false).
524 SAL_WARN("svx", "no property BoundRect");
528 // Fallback when there is no BoundRect Property.
529 if ( ! bFoundBoundRect
)
531 awt::Point
aPosition (mxShape
->getPosition());
532 awt::Size
aSize (mxShape
->getSize());
533 aBoundingBox
= awt::Rectangle (
534 aPosition
.X
, aPosition
.Y
,
535 aSize
.Width
, aSize
.Height
);
537 // While BoundRects have absolute positions, the position returned
538 // by XPosition::getPosition is relative. Get the anchor position
539 // (usually not (0,0) for Writer shapes).
542 if (xSetInfo
->hasPropertyByName (sAnchorPositionName
))
544 uno::Any aPos
= xSet
->getPropertyValue (sAnchorPositionName
);
545 awt::Point aAnchorPosition
;
546 aPos
>>= aAnchorPosition
;
547 aBoundingBox
.X
+= aAnchorPosition
.X
;
548 aBoundingBox
.Y
+= aAnchorPosition
.Y
;
553 // Transform coordinates from internal to pixel.
554 if (maShapeTreeInfo
.GetViewForwarder() == nullptr)
555 throw uno::RuntimeException (
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
));
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())
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
;
573 // Clip with parent (with coordinates relative to itself).
574 ::tools::Rectangle
aBBox (
575 x
, y
, x
+ aPixelSize
.getWidth(), y
+ aPixelSize
.getHeight());
576 awt::Size
aParentSize (xParentComponent
->getSize());
577 ::tools::Rectangle
aParentBBox (0,0, aParentSize
.Width
, aParentSize
.Height
);
578 aBBox
= aBBox
.GetIntersection (aParentBBox
);
579 aBoundingBox
= awt::Rectangle (
587 SAL_INFO("svx", "parent does not support component");
588 aBoundingBox
= awt::Rectangle (
589 aPixelPosition
.getX(), aPixelPosition
.getY(),
590 aPixelSize
.getWidth(), aPixelSize
.getHeight());
598 awt::Point SAL_CALL
AccessibleShape::getLocation()
601 awt::Rectangle
aBoundingBox (getBounds());
602 return awt::Point (aBoundingBox
.X
, aBoundingBox
.Y
);
606 awt::Point SAL_CALL
AccessibleShape::getLocationOnScreen()
610 // Get relative position...
611 awt::Point
aLocation (getLocation ());
613 // ... and add absolute position of the parent.
614 uno::Reference
<XAccessibleComponent
> xParentComponent (
615 getAccessibleParent(), uno::UNO_QUERY
);
616 if (xParentComponent
.is())
618 awt::Point
aParentLocation (xParentComponent
->getLocationOnScreen());
619 aLocation
.X
+= aParentLocation
.X
;
620 aLocation
.Y
+= aParentLocation
.Y
;
623 SAL_WARN("svx", "parent does not support XAccessibleComponent");
628 awt::Size SAL_CALL
AccessibleShape::getSize()
631 awt::Rectangle
aBoundingBox (getBounds());
632 return awt::Size (aBoundingBox
.Width
, aBoundingBox
.Height
);
636 sal_Int32 SAL_CALL
AccessibleShape::getForeground()
639 sal_Int32
nColor (0x0ffffffL
);
643 uno::Reference
<beans::XPropertySet
> aSet (mxShape
, uno::UNO_QUERY
);
647 aColor
= aSet
->getPropertyValue ("LineColor");
651 catch (const css::beans::UnknownPropertyException
&)
653 // Ignore exception and return default color.
659 sal_Int32 SAL_CALL
AccessibleShape::getBackground()
666 uno::Reference
<beans::XPropertySet
> aSet (mxShape
, uno::UNO_QUERY
);
670 aColor
= aSet
->getPropertyValue ("FillColor");
672 aColor
= aSet
->getPropertyValue ("FillTransparence");
678 crBk
.SetTransparency(0xff);
682 nTrans
= short(256 - nTrans
/ 100. * 256);
683 crBk
.SetTransparency(sal_uInt8(nTrans
));
688 catch (const css::beans::UnknownPropertyException
&)
690 // Ignore exception and return default color.
692 return sal_Int32(nColor
);
695 // XAccessibleEventBroadcaster
696 void SAL_CALL
AccessibleShape::addAccessibleEventListener (
697 const Reference
<XAccessibleEventListener
>& rxListener
)
699 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
701 uno::Reference
<uno::XInterface
> xThis (
702 static_cast<lang::XComponent
*>(this), uno::UNO_QUERY
);
703 rxListener
->disposing (lang::EventObject (xThis
));
707 AccessibleContextBase::addAccessibleEventListener (rxListener
);
708 if (mpText
!= nullptr)
709 mpText
->AddEventListener (rxListener
);
714 void SAL_CALL
AccessibleShape::removeAccessibleEventListener (
715 const Reference
<XAccessibleEventListener
>& rxListener
)
717 AccessibleContextBase::removeAccessibleEventListener (rxListener
);
718 if (mpText
!= nullptr)
719 mpText
->RemoveEventListener (rxListener
);
723 css::uno::Any SAL_CALL
724 AccessibleShape::queryInterface (const css::uno::Type
& rType
)
726 css::uno::Any aReturn
= AccessibleContextBase::queryInterface (rType
);
727 if ( ! aReturn
.hasValue())
728 aReturn
= ::cppu::queryInterface (rType
,
729 static_cast<XAccessibleComponent
*>(this),
730 static_cast<XAccessibleExtendedComponent
*>(this),
731 static_cast< css::accessibility::XAccessibleSelection
* >(this),
732 static_cast< css::accessibility::XAccessibleExtendedAttributes
* >(this),
733 static_cast<document::XShapeEventListener
*>(this),
734 static_cast<lang::XUnoTunnel
*>(this),
735 static_cast<XAccessibleGroupPosition
*>(this),
736 static_cast<XAccessibleHypertext
*>(this)
743 AccessibleShape::acquire()
746 AccessibleContextBase::acquire ();
751 AccessibleShape::release()
754 AccessibleContextBase::release ();
757 // XAccessibleSelection
758 void SAL_CALL
AccessibleShape::selectAccessibleChild( sal_Int32
)
763 sal_Bool SAL_CALL
AccessibleShape::isAccessibleChildSelected( sal_Int32 nChildIndex
)
765 uno::Reference
<XAccessible
> xAcc
= getAccessibleChild( nChildIndex
);
766 uno::Reference
<XAccessibleContext
> xContext
;
769 xContext
= xAcc
->getAccessibleContext();
774 if( xContext
->getAccessibleRole() == AccessibleRole::PARAGRAPH
)
776 uno::Reference
< css::accessibility::XAccessibleText
>
777 xText(xAcc
, uno::UNO_QUERY
);
780 if( xText
->getSelectionStart() >= 0 ) return true;
783 else if( xContext
->getAccessibleRole() == AccessibleRole::SHAPE
)
785 Reference
< XAccessibleStateSet
> pRState
= xContext
->getAccessibleStateSet();
789 uno::Sequence
<short> aStates
= pRState
->getStates();
790 return std::find(aStates
.begin(), aStates
.end(), AccessibleStateType::SELECTED
) != aStates
.end();
798 void SAL_CALL
AccessibleShape::clearAccessibleSelection( )
803 void SAL_CALL
AccessibleShape::selectAllAccessibleChildren( )
808 sal_Int32 SAL_CALL
AccessibleShape::getSelectedAccessibleChildCount()
810 sal_Int32 nCount
= 0;
811 sal_Int32 TotalCount
= getAccessibleChildCount();
812 for( sal_Int32 i
= 0; i
< TotalCount
; i
++ )
813 if( isAccessibleChildSelected(i
) ) nCount
++;
819 Reference
<XAccessible
> SAL_CALL
AccessibleShape::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex
)
821 if ( nSelectedChildIndex
> getSelectedAccessibleChildCount() )
822 throw IndexOutOfBoundsException();
824 for( i1
= 0, i2
= 0; i1
< getAccessibleChildCount(); i1
++ )
825 if( isAccessibleChildSelected(i1
) )
827 if( i2
== nSelectedChildIndex
)
828 return getAccessibleChild( i1
);
831 return Reference
<XAccessible
>();
835 void SAL_CALL
AccessibleShape::deselectAccessibleChild( sal_Int32
)
840 // XAccessibleExtendedAttributes
841 uno::Any SAL_CALL
AccessibleShape::getExtendedAttributes()
845 if( getAccessibleRole() != AccessibleRole::SHAPE
) return strRet
;
848 style
= "style:" + GetStyle();
857 AccessibleShape::getImplementationName()
859 return "AccessibleShape";
863 uno::Sequence
<OUString
> SAL_CALL
864 AccessibleShape::getSupportedServiceNames()
867 const css::uno::Sequence
<OUString
> vals
{ "com.sun.star.drawing.AccessibleShape" };
868 return comphelper::concatSequences(AccessibleContextBase::getSupportedServiceNames(), vals
);
872 uno::Sequence
<uno::Type
> SAL_CALL
873 AccessibleShape::getTypes()
876 // Get list of types from the context base implementation, ...
877 uno::Sequence
<uno::Type
> aTypeList (AccessibleContextBase::getTypes());
878 // ... get list of types from component base implementation, ...
879 uno::Sequence
<uno::Type
> aComponentTypeList (AccessibleComponentBase::getTypes());
880 // ... define local types
881 uno::Sequence
<uno::Type
> localTypesList
= {
882 cppu::UnoType
<lang::XEventListener
>::get(),
883 cppu::UnoType
<document::XEventListener
>::get(),
884 cppu::UnoType
<lang::XUnoTunnel
>::get()
887 return comphelper::concatSequences(aTypeList
, aComponentTypeList
, localTypesList
);
890 // lang::XEventListener
891 /** Disposing calls are accepted only from the model: Just reset the
892 reference to the model in the shape tree info. Otherwise this object
895 void AccessibleShape::disposing (const lang::EventObject
& aEvent
)
897 SolarMutexGuard aSolarGuard
;
898 ::osl::MutexGuard
aGuard (maMutex
);
902 if (aEvent
.Source
== maShapeTreeInfo
.GetModelBroadcaster())
904 // Remove reference to model broadcaster to allow it to pass
906 maShapeTreeInfo
.SetModelBroadcaster(nullptr);
910 catch (uno::RuntimeException
const&)
912 TOOLS_WARN_EXCEPTION("svx", "caught exception while disposing");
916 // document::XShapeEventListener
918 AccessibleShape::notifyShapeEvent (const document::EventObject
& rEventObject
)
920 if (rEventObject
.EventName
!= "ShapeModified")
923 //Need to update text children when receiving ShapeModified hint when exiting edit mode for text box
925 mpText
->UpdateChildren();
928 // Some property of a shape has been modified. Send an event
929 // that indicates a change of the visible data to all listeners.
931 AccessibleEventId::VISIBLE_DATA_CHANGED
,
935 // Name and Description may have changed. Update the local
936 // values accordingly.
937 UpdateNameAndDescription();
941 UNO3_GETIMPLEMENTATION_IMPL(AccessibleShape
)
943 // IAccessibleViewForwarderListener
944 void AccessibleShape::ViewForwarderChanged()
946 // Inform all listeners that the graphical representation (i.e. size
947 // and/or position) of the shape has changed.
948 CommitChange (AccessibleEventId::VISIBLE_DATA_CHANGED
,
952 // Tell children manager of the modified view forwarder.
953 if (mpChildrenManager
!= nullptr)
954 mpChildrenManager
->ViewForwarderChanged();
956 // update our children that our screen position might have changed
958 mpText
->UpdateChildren();
961 // protected internal
962 // Set this object's name if is different to the current name.
963 OUString
AccessibleShape::CreateAccessibleBaseName()
965 return ShapeTypeHandler::CreateAccessibleBaseName( mxShape
);
969 OUString
AccessibleShape::CreateAccessibleName()
971 return GetFullAccessibleName(this);
974 OUString
AccessibleShape::GetFullAccessibleName (AccessibleShape
*shape
)
976 OUString
sName (shape
->CreateAccessibleBaseName());
977 // Append the shape's index to the name to disambiguate between shapes
978 // of the same type. If such an index where not given to the
979 // constructor then use the z-order instead. If even that does not exist
980 // we throw an exception.
983 nameStr
= shape
->m_pShape
->GetName();
984 if (nameStr
.isEmpty())
993 //If the new produced name if not the same with last,notify name changed
995 if (aAccName
!= sName
&& !aAccName
.isEmpty())
997 uno::Any aOldValue
, aNewValue
;
998 aOldValue
<<= aAccName
;
1001 AccessibleEventId::NAME_CHANGED
,
1010 void AccessibleShape::disposing()
1012 SolarMutexGuard aSolarGuard
;
1013 ::osl::MutexGuard
aGuard (maMutex
);
1015 // Make sure to send an event that this object loses the focus in the
1016 // case that it has the focus.
1017 ::utl::AccessibleStateSetHelper
* pStateSet
=
1018 static_cast< ::utl::AccessibleStateSetHelper
*>(mxStateSet
.get());
1019 if (pStateSet
!= nullptr)
1020 pStateSet
->RemoveState (AccessibleStateType::FOCUSED
);
1022 // Unregister from model.
1023 if (mxShape
.is() && maShapeTreeInfo
.GetModelBroadcaster().is())
1024 maShapeTreeInfo
.GetModelBroadcaster()->removeShapeEventListener(mxShape
,
1025 static_cast<document::XShapeEventListener
*>(this));
1027 // Release the child containers.
1028 if (mpChildrenManager
!= nullptr)
1030 mpChildrenManager
.reset();
1032 if (mpText
!= nullptr)
1038 // Cleanup. Remove references to objects to allow them to be
1041 maShapeTreeInfo
.dispose();
1043 // Call base classes.
1044 AccessibleContextBase::dispose ();
1048 AccessibleShape::getAccessibleIndexInParent()
1051 // Use a simple but slow solution for now. Optimize later.
1053 sal_Int32 nIndex
= m_nIndexInParent
;
1055 nIndex
= AccessibleContextBase::getAccessibleIndexInParent();
1060 void AccessibleShape::UpdateNameAndDescription()
1062 // Ignore missing title, name, or description. There are fallbacks for
1066 Reference
<beans::XPropertySet
> xSet (mxShape
, uno::UNO_QUERY_THROW
);
1068 // Get the accessible name.
1069 OUString sString
= GetOptionalProperty(xSet
, "Title");
1070 if (!sString
.isEmpty())
1072 SetAccessibleName(sString
, AccessibleContextBase::FromShape
);
1076 sString
= GetOptionalProperty(xSet
, "Name");
1077 if (!sString
.isEmpty())
1078 SetAccessibleName(sString
, AccessibleContextBase::FromShape
);
1081 // Get the accessible description.
1082 sString
= GetOptionalProperty(xSet
, "Description");
1083 if (!sString
.isEmpty())
1084 SetAccessibleDescription(sString
, AccessibleContextBase::FromShape
);
1086 catch (uno::RuntimeException
&)
1091 // Return this object's role.
1092 sal_Int16 SAL_CALL
AccessibleShape::getAccessibleRole()
1094 sal_Int16 nAccessibleRole
= AccessibleRole::SHAPE
;
1095 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape
))
1097 case DRAWING_GRAPHIC_OBJECT
:
1098 nAccessibleRole
= AccessibleRole::GRAPHIC
; break;
1100 nAccessibleRole
= AccessibleRole::EMBEDDED_OBJECT
; break;
1103 nAccessibleRole
= AccessibleContextBase::getAccessibleRole();
1107 return nAccessibleRole
;
1112 //sort the drawing objects from up to down, from left to right
1113 struct XShapePosCompareHelper
1115 bool operator() ( const uno::Reference
<drawing::XShape
>& xshape1
,
1116 const uno::Reference
<drawing::XShape
>& xshape2
) const
1118 SdrObject
* pObj1
= GetSdrObjectFromXShape(xshape1
);
1119 SdrObject
* pObj2
= GetSdrObjectFromXShape(xshape2
);
1121 return pObj1
->GetOrdNum() < pObj2
->GetOrdNum();
1128 //end of group position
1130 // XAccessibleGroupPosition
1131 uno::Sequence
< sal_Int32
> SAL_CALL
1132 AccessibleShape::getGroupPosition( const uno::Any
& )
1134 // we will return the:
1136 // [1] similar items counts in the group
1137 // [2] the position of the object in the group
1138 uno::Sequence
< sal_Int32
> aRet( 3 );
1143 css::uno::Reference
<XAccessible
> xParent
= getAccessibleParent();
1148 SdrObject
*pObj
= GetSdrObjectFromXShape(mxShape
);
1151 if(pObj
== nullptr )
1156 // Compute object's group level.
1157 sal_Int32 nGroupLevel
= 0;
1158 SdrObject
* pUper
= pObj
->getParentSdrObjectFromSdrObject();
1162 pUper
= pUper
->getParentSdrObjectFromSdrObject();
1165 css::uno::Reference
<XAccessibleContext
> xParentContext
= xParent
->getAccessibleContext();
1166 if( xParentContext
->getAccessibleRole() == AccessibleRole::DOCUMENT
||
1167 xParentContext
->getAccessibleRole() == AccessibleRole::DOCUMENT_PRESENTATION
||
1168 xParentContext
->getAccessibleRole() == AccessibleRole::DOCUMENT_SPREADSHEET
||
1169 xParentContext
->getAccessibleRole() == AccessibleRole::DOCUMENT_TEXT
)//Document
1171 Reference
< XAccessibleGroupPosition
> xGroupPosition( xParent
,uno::UNO_QUERY
);
1172 if ( xGroupPosition
.is() )
1174 aRet
= xGroupPosition
->getGroupPosition( uno::makeAny( getAccessibleContext() ) );
1178 if (xParentContext
->getAccessibleRole() != AccessibleRole::SHAPE
)
1183 SdrObjList
*pGrpList
= nullptr;
1184 if( pObj
->getParentSdrObjectFromSdrObject() )
1185 pGrpList
= pObj
->getParentSdrObjectFromSdrObject()->GetSubList();
1189 std::vector
< uno::Reference
<drawing::XShape
> > vXShapes
;
1192 const size_t nObj
= pGrpList
->GetObjCount();
1193 for(size_t i
= 0 ; i
< nObj
; ++i
)
1195 SdrObject
*pSubObj
= pGrpList
->GetObj(i
);
1197 xParentContext
->getAccessibleChild(i
)->getAccessibleContext()->getAccessibleRole() != AccessibleRole::GROUP_BOX
)
1199 vXShapes
.push_back( GetXShapeForSdrObject(pSubObj
) );
1204 std::sort( vXShapes
.begin(), vXShapes
.end(), XShapePosCompareHelper() );
1206 //get the index of the selected object in the group
1207 //we start counting position from 1
1209 for ( const auto& rpShape
: vXShapes
)
1211 if ( rpShape
.get() == mxShape
.get() )
1213 sal_Int32
* pArray
= aRet
.getArray();
1214 pArray
[0] = nGroupLevel
;
1215 pArray
[1] = vXShapes
.size();
1225 OUString
AccessibleShape::getObjectLink( const uno::Any
& )
1229 SdrObject
*pObj
= GetSdrObjectFromXShape(mxShape
);
1230 if(pObj
== nullptr )
1234 if (maShapeTreeInfo
.GetDocumentWindow().is())
1236 Reference
< XAccessibleGroupPosition
> xGroupPosition( maShapeTreeInfo
.GetDocumentWindow(), uno::UNO_QUERY
);
1237 if (xGroupPosition
.is())
1239 aRet
= xGroupPosition
->getObjectLink( uno::makeAny( getAccessibleContext() ) );
1245 // XAccessibleHypertext
1246 sal_Int32 SAL_CALL
AccessibleShape::getHyperLinkCount()
1248 // MT: Introduced with IA2 CWS, but SvxAccessibleHyperlink was redundant to svx::AccessibleHyperlink which we introduced meanwhile.
1249 // Code need to be adapted...
1253 SvxAccessibleHyperlink* pLink = new SvxAccessibleHyperlink(m_pShape,this);
1254 if (pLink->IsValidHyperlink())
1260 uno::Reference
< XAccessibleHyperlink
> SAL_CALL
1261 AccessibleShape::getHyperLink( sal_Int32
)
1263 uno::Reference
< XAccessibleHyperlink
> xRet
;
1264 // MT: Introduced with IA2 CWS, but SvxAccessibleHyperlink was redundant to svx::AccessibleHyperlink which we introduced meanwhile.
1265 // Code need to be adapted...
1267 SvxAccessibleHyperlink* pLink = new SvxAccessibleHyperlink(m_pShape,this);
1268 if (pLink->IsValidHyperlink())
1271 throw css::lang::IndexOutOfBoundsException();
1275 sal_Int32 SAL_CALL
AccessibleShape::getHyperLinkIndex( sal_Int32
)
1280 sal_Int32 SAL_CALL
AccessibleShape::getCaretPosition( ){return 0;}
1281 sal_Bool SAL_CALL
AccessibleShape::setCaretPosition( sal_Int32
){return false;}
1282 sal_Unicode SAL_CALL
AccessibleShape::getCharacter( sal_Int32
){return 0;}
1283 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
AccessibleShape::getCharacterAttributes( sal_Int32
, const css::uno::Sequence
< OUString
>& )
1285 uno::Sequence
< css::beans::PropertyValue
> aValues(0);
1288 css::awt::Rectangle SAL_CALL
AccessibleShape::getCharacterBounds( sal_Int32
)
1290 return css::awt::Rectangle(0, 0, 0, 0 );
1292 sal_Int32 SAL_CALL
AccessibleShape::getCharacterCount( ){return 0;}
1293 sal_Int32 SAL_CALL
AccessibleShape::getIndexAtPoint( const css::awt::Point
& ){return 0;}
1294 OUString SAL_CALL
AccessibleShape::getSelectedText( ){return OUString();}
1295 sal_Int32 SAL_CALL
AccessibleShape::getSelectionStart( ){return 0;}
1296 sal_Int32 SAL_CALL
AccessibleShape::getSelectionEnd( ){return 0;}
1297 sal_Bool SAL_CALL
AccessibleShape::setSelection( sal_Int32
, sal_Int32
){return true;}
1298 OUString SAL_CALL
AccessibleShape::getText( ){return OUString();}
1299 OUString SAL_CALL
AccessibleShape::getTextRange( sal_Int32
, sal_Int32
){return OUString();}
1300 css::accessibility::TextSegment SAL_CALL
AccessibleShape::getTextAtIndex( sal_Int32
, sal_Int16
)
1302 css::accessibility::TextSegment aResult
;
1305 css::accessibility::TextSegment SAL_CALL
AccessibleShape::getTextBeforeIndex( sal_Int32
, sal_Int16
)
1307 css::accessibility::TextSegment aResult
;
1310 css::accessibility::TextSegment SAL_CALL
AccessibleShape::getTextBehindIndex( sal_Int32
, sal_Int16
)
1312 css::accessibility::TextSegment aResult
;
1315 sal_Bool SAL_CALL
AccessibleShape::copyText( sal_Int32
, sal_Int32
){return true;}
1316 sal_Bool SAL_CALL
AccessibleShape::scrollSubstringTo( sal_Int32
, sal_Int32
, AccessibleScrollType
){return false;}
1318 } // end of namespace accessibility
1320 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */