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 <vcl/window.hxx>
47 #include <unotools/accessiblestatesethelper.hxx>
48 #include <unotools/accessiblerelationsethelper.hxx>
49 #include <svx/svdview.hxx>
50 #include <tools/diagnose_ex.h>
51 #include <cppuhelper/queryinterface.hxx>
52 #include <comphelper/sequence.hxx>
53 #include "AccessibleEmptyEditSource.hxx"
58 using namespace ::com::sun::star
;
59 using namespace ::com::sun::star::accessibility
;
60 using ::com::sun::star::uno::Reference
;
61 using ::com::sun::star::lang::IndexOutOfBoundsException
;
62 using ::com::sun::star::uno::RuntimeException
;
64 namespace accessibility
{
68 OUString
GetOptionalProperty (
69 const Reference
<beans::XPropertySet
>& rxSet
,
70 const OUString
& rsPropertyName
)
76 const Reference
<beans::XPropertySetInfo
> xInfo (rxSet
->getPropertySetInfo());
77 if ( ! xInfo
.is() || xInfo
->hasPropertyByName(rsPropertyName
))
81 rxSet
->getPropertyValue(rsPropertyName
) >>= sValue
;
83 catch (beans::UnknownPropertyException
&)
85 // This exception should only be thrown when the property
86 // does not exits (of course) and the XPropertySetInfo is
94 } // end of anonymous namespace
97 AccessibleShape::AccessibleShape (
98 const AccessibleShapeInfo
& rShapeInfo
,
99 const AccessibleShapeTreeInfo
& rShapeTreeInfo
)
100 : AccessibleContextBase (rShapeInfo
.mxParent
,AccessibleRole::SHAPE
),
101 mxShape (rShapeInfo
.mxShape
),
102 maShapeTreeInfo (rShapeTreeInfo
),
103 m_nIndexInParent(-1),
104 mpParent (rShapeInfo
.mpChildrenManager
)
106 m_pShape
= GetSdrObjectFromXShape(mxShape
);
107 UpdateNameAndDescription();
110 AccessibleShape::~AccessibleShape()
112 mpChildrenManager
.reset();
114 SAL_INFO("svx", "~AccessibleShape");
116 // Unregistering from the various broadcasters should be unnecessary
117 // since this destructor would not have been called if one of the
118 // broadcasters would still hold a strong reference to this object.
121 void AccessibleShape::Init()
123 // Update the OPAQUE and SELECTED shape.
126 // Create a children manager when this shape has children of its own.
127 Reference
<drawing::XShapes
> xShapes (mxShape
, uno::UNO_QUERY
);
128 if (xShapes
.is() && xShapes
->getCount() > 0)
129 mpChildrenManager
.reset( new ChildrenManager (
130 this, xShapes
, maShapeTreeInfo
, *this) );
131 if (mpChildrenManager
!= nullptr)
132 mpChildrenManager
->Update();
134 // Register at model as document::XEventListener.
135 if (mxShape
.is() && maShapeTreeInfo
.GetModelBroadcaster().is())
136 maShapeTreeInfo
.GetModelBroadcaster()->addShapeEventListener(mxShape
,
137 static_cast<document::XShapeEventListener
*>(this));
139 // Beware! Here we leave the paths of the UNO API and descend into the
140 // depths of the core. Necessary for making the edit engine
142 Reference
<text::XText
> xText (mxShape
, uno::UNO_QUERY
);
146 SdrView
* pView
= maShapeTreeInfo
.GetSdrView ();
147 const vcl::Window
* pWindow
= maShapeTreeInfo
.GetWindow ();
148 if (!(pView
!= nullptr && pWindow
!= nullptr && mxShape
.is()))
151 // #107948# Determine whether shape text is empty
152 SdrObject
* pSdrObject
= GetSdrObjectFromXShape(mxShape
);
156 SdrTextObj
* pTextObj
= dynamic_cast<SdrTextObj
*>( pSdrObject
);
157 const bool hasOutlinerParaObject
= (pTextObj
&& pTextObj
->CanCreateEditOutlinerParaObject()) || (pSdrObject
->GetOutlinerParaObject() != nullptr);
159 // create AccessibleTextHelper to handle this shape's text
160 if( !hasOutlinerParaObject
)
162 // empty text -> use proxy edit source to delay creation of EditEngine
163 mpText
.reset( new AccessibleTextHelper( std::make_unique
<AccessibleEmptyEditSource
>(*pSdrObject
, *pView
, *pWindow
->GetOutDev()) ) );
167 // non-empty text -> use full-fledged edit source right away
168 mpText
.reset( new AccessibleTextHelper( std::make_unique
<SvxTextEditSource
>(*pSdrObject
, nullptr, *pView
, *pWindow
->GetOutDev()) ) );
170 if( pWindow
->HasFocus() )
173 mpText
->SetEventSource(this);
177 void AccessibleShape::UpdateStates()
179 ::utl::AccessibleStateSetHelper
* pStateSet
=
180 static_cast< ::utl::AccessibleStateSetHelper
*>(mxStateSet
.get());
181 if (pStateSet
== nullptr)
184 // Set the opaque state for certain shape types when their fill style is
186 bool bShapeIsOpaque
= false;
187 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape
))
190 case DRAWING_RECTANGLE
:
193 uno::Reference
<beans::XPropertySet
> xSet (mxShape
, uno::UNO_QUERY
);
198 drawing::FillStyle aFillStyle
;
199 bShapeIsOpaque
= ( xSet
->getPropertyValue ("FillStyle") >>= aFillStyle
)
200 && aFillStyle
== drawing::FillStyle_SOLID
;
202 catch (css::beans::UnknownPropertyException
&)
210 pStateSet
->AddState (AccessibleStateType::OPAQUE
);
212 pStateSet
->RemoveState (AccessibleStateType::OPAQUE
);
214 // Set the selected state.
215 bool bShapeIsSelected
= false;
216 // XXX fix_me this has to be done with an extra interface later on
217 if ( m_pShape
&& maShapeTreeInfo
.GetSdrView() )
219 bShapeIsSelected
= maShapeTreeInfo
.GetSdrView()->IsObjMarked(m_pShape
);
222 if (bShapeIsSelected
)
223 pStateSet
->AddState (AccessibleStateType::SELECTED
);
225 pStateSet
->RemoveState (AccessibleStateType::SELECTED
);
228 OUString
AccessibleShape::GetStyle()
230 return ShapeTypeHandler::CreateAccessibleBaseName( mxShape
);
233 bool AccessibleShape::SetState (sal_Int16 aState
)
235 bool bStateHasChanged
= false;
237 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
239 // Offer FOCUSED state to edit engine and detect whether the state
241 bool bIsFocused
= mpText
->HaveFocus ();
243 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
246 bStateHasChanged
= AccessibleContextBase::SetState (aState
);
248 return bStateHasChanged
;
252 bool AccessibleShape::ResetState (sal_Int16 aState
)
254 bool bStateHasChanged
= false;
256 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
258 // Try to remove FOCUSED state from the edit engine and detect
259 // whether the state changes.
260 bool bIsFocused
= mpText
->HaveFocus ();
261 mpText
->SetFocus (false);
262 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
265 bStateHasChanged
= AccessibleContextBase::ResetState (aState
);
267 return bStateHasChanged
;
271 bool AccessibleShape::GetState (sal_Int16 aState
)
273 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
275 // Just delegate the call to the edit engine. The state is not
276 // merged into the state set.
277 return mpText
->HaveFocus();
280 return AccessibleContextBase::GetState (aState
);
283 // OverWrite the parent's getAccessibleName method
284 OUString SAL_CALL
AccessibleShape::getAccessibleName()
287 if (m_pShape
&& !m_pShape
->GetTitle().isEmpty())
288 return CreateAccessibleName() + " " + m_pShape
->GetTitle();
290 return CreateAccessibleName();
293 OUString SAL_CALL
AccessibleShape::getAccessibleDescription()
296 if( m_pShape
&& !m_pShape
->GetDescription().isEmpty())
297 return m_pShape
->GetDescription() ;
302 // XAccessibleContext
303 /** The children of this shape come from two sources: The children from
304 group or scene shapes and the paragraphs of text.
307 AccessibleShape::getAccessibleChildCount ()
314 sal_Int32 nChildCount
= 0;
316 // Add the number of shapes that are children of this shape.
317 if (mpChildrenManager
!= nullptr)
318 nChildCount
+= mpChildrenManager
->GetChildCount ();
319 // Add the number text paragraphs.
320 if (mpText
!= nullptr)
321 nChildCount
+= mpText
->GetChildCount ();
327 /** Forward the request to the shape. Return the requested shape or throw
328 an exception for a wrong index.
330 uno::Reference
<XAccessible
> SAL_CALL
331 AccessibleShape::getAccessibleChild (sal_Int32 nIndex
)
335 uno::Reference
<XAccessible
> xChild
;
337 // Depending on the index decide whether to delegate this call to the
338 // children manager or the edit engine.
339 if ((mpChildrenManager
!= nullptr)
340 && (nIndex
< mpChildrenManager
->GetChildCount()))
342 xChild
= mpChildrenManager
->GetChild (nIndex
);
344 else if (mpText
!= nullptr)
346 sal_Int32 nI
= nIndex
;
347 if (mpChildrenManager
!= nullptr)
348 nI
-= mpChildrenManager
->GetChildCount();
349 xChild
= mpText
->GetChild (nI
);
352 throw lang::IndexOutOfBoundsException (
353 "shape has no child with index " + OUString::number(nIndex
),
354 static_cast<uno::XWeak
*>(this));
359 uno::Reference
<XAccessibleRelationSet
> SAL_CALL
360 AccessibleShape::getAccessibleRelationSet()
362 ::osl::MutexGuard
aGuard (maMutex
);
363 if (mpParent
== nullptr)
364 return uno::Reference
<XAccessibleRelationSet
>();
366 rtl::Reference
<::utl::AccessibleRelationSetHelper
> pRelationSet
= new utl::AccessibleRelationSetHelper
;
368 //this mxshape is the captioned shape
369 uno::Sequence
< uno::Reference
< uno::XInterface
> > aSequence
{ mpParent
->GetAccessibleCaption(mxShape
) };
372 pRelationSet
->AddRelation(
373 AccessibleRelation( AccessibleRelationType::DESCRIBED_BY
, aSequence
) );
378 /** Return a copy of the state set.
384 uno::Reference
<XAccessibleStateSet
> SAL_CALL
385 AccessibleShape::getAccessibleStateSet()
387 ::osl::MutexGuard
aGuard (maMutex
);
391 // Return a minimal state set that only contains the DEFUNC state.
392 return AccessibleContextBase::getAccessibleStateSet ();
395 ::utl::AccessibleStateSetHelper
* pStateSet
=
396 static_cast<::utl::AccessibleStateSetHelper
*>(mxStateSet
.get());
399 return Reference
<XAccessibleStateSet
>();
401 // Merge current FOCUSED state from edit engine.
404 if (mpText
->HaveFocus())
405 pStateSet
->AddState (AccessibleStateType::FOCUSED
);
407 pStateSet
->RemoveState (AccessibleStateType::FOCUSED
);
409 //Just when the document is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
410 css::uno::Reference
<XAccessible
> xTempAcc
= getAccessibleParent();
413 css::uno::Reference
<XAccessibleContext
>
414 xTempAccContext
= xTempAcc
->getAccessibleContext();
415 if( xTempAccContext
.is() )
417 css::uno::Reference
<XAccessibleStateSet
> rState
=
418 xTempAccContext
->getAccessibleStateSet();
421 css::uno::Sequence
<short> aStates
= rState
->getStates();
422 if (std::find(aStates
.begin(), aStates
.end(), AccessibleStateType::EDITABLE
) != aStates
.end())
424 pStateSet
->AddState (AccessibleStateType::EDITABLE
);
425 pStateSet
->AddState (AccessibleStateType::RESIZABLE
);
426 pStateSet
->AddState (AccessibleStateType::MOVEABLE
);
432 // Create a copy of the state set that may be modified by the
433 // caller without affecting the current state set.
434 Reference
<XAccessibleStateSet
> xStateSet(new ::utl::AccessibleStateSetHelper(*pStateSet
));
436 if (mpParent
&& mpParent
->IsDocumentSelAll())
438 ::utl::AccessibleStateSetHelper
* pCopyStateSet
=
439 static_cast<::utl::AccessibleStateSetHelper
*>(xStateSet
.get());
440 pCopyStateSet
->AddState (AccessibleStateType::SELECTED
);
446 // XAccessibleComponent
447 /** The implementation below is at the moment straightforward. It iterates
448 over all children (and thereby instances all children which have not
449 been already instantiated) until a child covering the specified point is
451 This leaves room for improvement. For instance, first iterate only over
452 the already instantiated children and only if no match is found
453 instantiate the remaining ones.
455 uno::Reference
<XAccessible
> SAL_CALL
456 AccessibleShape::getAccessibleAtPoint (
457 const awt::Point
& aPoint
)
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
));
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
) )
481 // Have not found a child under the given point. Returning empty
482 // reference to indicate this.
483 return uno::Reference
<XAccessible
>();
487 awt::Rectangle SAL_CALL
AccessibleShape::getBounds()
489 SolarMutexGuard aSolarGuard
;
490 ::osl::MutexGuard
aGuard (maMutex
);
493 awt::Rectangle aBoundingBox
;
497 static constexpr OUStringLiteral sBoundRectName
= u
"BoundRect";
498 static constexpr OUStringLiteral sAnchorPositionName
= u
"AnchorPosition";
500 // Get the shape's bounding box in internal coordinates (in 100th of
501 // mm). Use the property BoundRect. Only if that is not supported ask
502 // the shape for its position and size directly.
503 Reference
<beans::XPropertySet
> xSet (mxShape
, uno::UNO_QUERY
);
504 Reference
<beans::XPropertySetInfo
> xSetInfo
;
505 bool bFoundBoundRect
= false;
508 xSetInfo
= xSet
->getPropertySetInfo ();
511 if (xSetInfo
->hasPropertyByName (sBoundRectName
))
515 uno::Any aValue
= xSet
->getPropertyValue (sBoundRectName
);
516 aValue
>>= aBoundingBox
;
517 bFoundBoundRect
= true;
519 catch (beans::UnknownPropertyException
const&)
521 // Handled below (bFoundBoundRect stays false).
525 SAL_WARN("svx", "no property BoundRect");
529 // Fallback when there is no BoundRect Property.
530 if ( ! bFoundBoundRect
)
532 awt::Point
aPosition (mxShape
->getPosition());
533 awt::Size
aSize (mxShape
->getSize());
534 aBoundingBox
= awt::Rectangle (
535 aPosition
.X
, aPosition
.Y
,
536 aSize
.Width
, aSize
.Height
);
538 // While BoundRects have absolute positions, the position returned
539 // by XPosition::getPosition is relative. Get the anchor position
540 // (usually not (0,0) for Writer shapes).
543 if (xSetInfo
->hasPropertyByName (sAnchorPositionName
))
545 uno::Any aPos
= xSet
->getPropertyValue (sAnchorPositionName
);
546 awt::Point aAnchorPosition
;
547 aPos
>>= aAnchorPosition
;
548 aBoundingBox
.X
+= aAnchorPosition
.X
;
549 aBoundingBox
.Y
+= aAnchorPosition
.Y
;
554 // Transform coordinates from internal to pixel.
555 if (maShapeTreeInfo
.GetViewForwarder() == nullptr)
556 throw uno::RuntimeException (
557 "AccessibleShape has no valid view forwarder",
558 static_cast<uno::XWeak
*>(this));
559 ::Size aPixelSize
= maShapeTreeInfo
.GetViewForwarder()->LogicToPixel (
560 ::Size (aBoundingBox
.Width
, aBoundingBox
.Height
));
561 ::Point aPixelPosition
= maShapeTreeInfo
.GetViewForwarder()->LogicToPixel (
562 ::Point (aBoundingBox
.X
, aBoundingBox
.Y
));
564 // Clip the shape's bounding box with the bounding box of its parent.
565 Reference
<XAccessibleComponent
> xParentComponent (
566 getAccessibleParent(), uno::UNO_QUERY
);
567 if (xParentComponent
.is())
569 // Make the coordinates relative to the parent.
570 awt::Point
aParentLocation (xParentComponent
->getLocationOnScreen());
571 int x
= aPixelPosition
.getX() - aParentLocation
.X
;
572 int y
= aPixelPosition
.getY() - aParentLocation
.Y
;
574 // Clip with parent (with coordinates relative to itself).
575 ::tools::Rectangle
aBBox (
576 x
, y
, x
+ aPixelSize
.getWidth(), y
+ aPixelSize
.getHeight());
577 awt::Size
aParentSize (xParentComponent
->getSize());
578 ::tools::Rectangle
aParentBBox (0,0, aParentSize
.Width
, aParentSize
.Height
);
579 aBBox
= aBBox
.GetIntersection (aParentBBox
);
580 aBoundingBox
= awt::Rectangle (
588 SAL_INFO("svx", "parent does not support component");
589 aBoundingBox
= awt::Rectangle (
590 aPixelPosition
.getX(), aPixelPosition
.getY(),
591 aPixelSize
.getWidth(), aPixelSize
.getHeight());
599 awt::Point SAL_CALL
AccessibleShape::getLocation()
602 awt::Rectangle
aBoundingBox (getBounds());
603 return awt::Point (aBoundingBox
.X
, aBoundingBox
.Y
);
607 awt::Point SAL_CALL
AccessibleShape::getLocationOnScreen()
611 // Get relative position...
612 awt::Point
aLocation (getLocation ());
614 // ... and add absolute position of the parent.
615 uno::Reference
<XAccessibleComponent
> xParentComponent (
616 getAccessibleParent(), uno::UNO_QUERY
);
617 if (xParentComponent
.is())
619 awt::Point
aParentLocation (xParentComponent
->getLocationOnScreen());
620 aLocation
.X
+= aParentLocation
.X
;
621 aLocation
.Y
+= aParentLocation
.Y
;
624 SAL_WARN("svx", "parent does not support XAccessibleComponent");
629 awt::Size SAL_CALL
AccessibleShape::getSize()
632 awt::Rectangle
aBoundingBox (getBounds());
633 return awt::Size (aBoundingBox
.Width
, aBoundingBox
.Height
);
637 sal_Int32 SAL_CALL
AccessibleShape::getForeground()
640 sal_Int32
nColor (0x0ffffffL
);
644 uno::Reference
<beans::XPropertySet
> aSet (mxShape
, uno::UNO_QUERY
);
648 aColor
= aSet
->getPropertyValue ("LineColor");
652 catch (const css::beans::UnknownPropertyException
&)
654 // Ignore exception and return default color.
660 sal_Int32 SAL_CALL
AccessibleShape::getBackground()
667 uno::Reference
<beans::XPropertySet
> aSet (mxShape
, uno::UNO_QUERY
);
671 aColor
= aSet
->getPropertyValue ("FillColor");
673 aColor
= aSet
->getPropertyValue ("FillTransparence");
683 nTrans
= short(256 - nTrans
/ 100. * 256);
684 crBk
.SetAlpha(255 - sal_uInt8(nTrans
));
689 catch (const css::beans::UnknownPropertyException
&)
691 // Ignore exception and return default color.
693 return sal_Int32(nColor
);
696 // XAccessibleEventBroadcaster
697 void SAL_CALL
AccessibleShape::addAccessibleEventListener (
698 const Reference
<XAccessibleEventListener
>& rxListener
)
700 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
702 uno::Reference
<uno::XInterface
> xThis (
703 static_cast<lang::XComponent
*>(this), uno::UNO_QUERY
);
704 rxListener
->disposing (lang::EventObject (xThis
));
708 AccessibleContextBase::addAccessibleEventListener (rxListener
);
709 if (mpText
!= nullptr)
710 mpText
->AddEventListener (rxListener
);
715 void SAL_CALL
AccessibleShape::removeAccessibleEventListener (
716 const Reference
<XAccessibleEventListener
>& rxListener
)
718 AccessibleContextBase::removeAccessibleEventListener (rxListener
);
719 if (mpText
!= nullptr)
720 mpText
->RemoveEventListener (rxListener
);
724 css::uno::Any SAL_CALL
725 AccessibleShape::queryInterface (const css::uno::Type
& rType
)
727 css::uno::Any aReturn
= AccessibleContextBase::queryInterface (rType
);
728 if ( ! aReturn
.hasValue())
729 aReturn
= ::cppu::queryInterface (rType
,
730 static_cast<XAccessibleComponent
*>(this),
731 static_cast<XAccessibleExtendedComponent
*>(this),
732 static_cast< css::accessibility::XAccessibleSelection
* >(this),
733 static_cast< css::accessibility::XAccessibleExtendedAttributes
* >(this),
734 static_cast<document::XShapeEventListener
*>(this),
735 static_cast<lang::XUnoTunnel
*>(this),
736 static_cast<XAccessibleGroupPosition
*>(this),
737 static_cast<XAccessibleHypertext
*>(this)
744 AccessibleShape::acquire()
747 AccessibleContextBase::acquire ();
752 AccessibleShape::release()
755 AccessibleContextBase::release ();
758 // XAccessibleSelection
759 void SAL_CALL
AccessibleShape::selectAccessibleChild( sal_Int32
)
764 sal_Bool SAL_CALL
AccessibleShape::isAccessibleChildSelected( sal_Int32 nChildIndex
)
766 uno::Reference
<XAccessible
> xAcc
= getAccessibleChild( nChildIndex
);
767 uno::Reference
<XAccessibleContext
> xContext
;
770 xContext
= xAcc
->getAccessibleContext();
775 if( xContext
->getAccessibleRole() == AccessibleRole::PARAGRAPH
)
777 uno::Reference
< css::accessibility::XAccessibleText
>
778 xText(xAcc
, uno::UNO_QUERY
);
781 if( xText
->getSelectionStart() >= 0 ) return true;
784 else if( xContext
->getAccessibleRole() == AccessibleRole::SHAPE
)
786 Reference
< XAccessibleStateSet
> pRState
= xContext
->getAccessibleStateSet();
790 uno::Sequence
<short> aStates
= pRState
->getStates();
791 return std::find(aStates
.begin(), aStates
.end(), AccessibleStateType::SELECTED
) != aStates
.end();
799 void SAL_CALL
AccessibleShape::clearAccessibleSelection( )
804 void SAL_CALL
AccessibleShape::selectAllAccessibleChildren( )
809 sal_Int32 SAL_CALL
AccessibleShape::getSelectedAccessibleChildCount()
811 sal_Int32 nCount
= 0;
812 sal_Int32 TotalCount
= getAccessibleChildCount();
813 for( sal_Int32 i
= 0; i
< TotalCount
; i
++ )
814 if( isAccessibleChildSelected(i
) ) nCount
++;
820 Reference
<XAccessible
> SAL_CALL
AccessibleShape::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex
)
822 if ( nSelectedChildIndex
> getSelectedAccessibleChildCount() )
823 throw IndexOutOfBoundsException();
825 for( i1
= 0, i2
= 0; i1
< getAccessibleChildCount(); i1
++ )
826 if( isAccessibleChildSelected(i1
) )
828 if( i2
== nSelectedChildIndex
)
829 return getAccessibleChild( i1
);
832 return Reference
<XAccessible
>();
836 void SAL_CALL
AccessibleShape::deselectAccessibleChild( sal_Int32
)
841 // XAccessibleExtendedAttributes
842 uno::Any SAL_CALL
AccessibleShape::getExtendedAttributes()
846 if( getAccessibleRole() != AccessibleRole::SHAPE
) return strRet
;
849 style
= "style:" + GetStyle();
858 AccessibleShape::getImplementationName()
860 return "AccessibleShape";
864 uno::Sequence
<OUString
> SAL_CALL
865 AccessibleShape::getSupportedServiceNames()
868 const css::uno::Sequence
<OUString
> vals
{ "com.sun.star.drawing.AccessibleShape" };
869 return comphelper::concatSequences(AccessibleContextBase::getSupportedServiceNames(), vals
);
873 uno::Sequence
<uno::Type
> SAL_CALL
874 AccessibleShape::getTypes()
877 // Get list of types from the context base implementation, ...
878 uno::Sequence
<uno::Type
> aTypeList (AccessibleContextBase::getTypes());
879 // ... get list of types from component base implementation, ...
880 uno::Sequence
<uno::Type
> aComponentTypeList (AccessibleComponentBase::getTypes());
881 // ... define local types
882 uno::Sequence
<uno::Type
> localTypesList
= {
883 cppu::UnoType
<lang::XEventListener
>::get(),
884 cppu::UnoType
<document::XEventListener
>::get(),
885 cppu::UnoType
<lang::XUnoTunnel
>::get()
888 return comphelper::concatSequences(aTypeList
, aComponentTypeList
, localTypesList
);
891 // lang::XEventListener
892 /** Disposing calls are accepted only from the model: Just reset the
893 reference to the model in the shape tree info. Otherwise this object
896 void AccessibleShape::disposing (const lang::EventObject
& aEvent
)
898 SolarMutexGuard aSolarGuard
;
899 ::osl::MutexGuard
aGuard (maMutex
);
903 if (aEvent
.Source
== maShapeTreeInfo
.GetModelBroadcaster())
905 // Remove reference to model broadcaster to allow it to pass
907 maShapeTreeInfo
.SetModelBroadcaster(nullptr);
911 catch (uno::RuntimeException
const&)
913 TOOLS_WARN_EXCEPTION("svx", "caught exception while disposing");
917 // document::XShapeEventListener
919 AccessibleShape::notifyShapeEvent (const document::EventObject
& rEventObject
)
921 if (rEventObject
.EventName
!= "ShapeModified")
924 //Need to update text children when receiving ShapeModified hint when exiting edit mode for text box
926 mpText
->UpdateChildren();
929 // Some property of a shape has been modified. Send an event
930 // that indicates a change of the visible data to all listeners.
932 AccessibleEventId::VISIBLE_DATA_CHANGED
,
936 // Name and Description may have changed. Update the local
937 // values accordingly.
938 UpdateNameAndDescription();
942 UNO3_GETIMPLEMENTATION_IMPL(AccessibleShape
)
944 // IAccessibleViewForwarderListener
945 void AccessibleShape::ViewForwarderChanged()
947 // Inform all listeners that the graphical representation (i.e. size
948 // and/or position) of the shape has changed.
949 CommitChange (AccessibleEventId::VISIBLE_DATA_CHANGED
,
953 // Tell children manager of the modified view forwarder.
954 if (mpChildrenManager
!= nullptr)
955 mpChildrenManager
->ViewForwarderChanged();
957 // update our children that our screen position might have changed
959 mpText
->UpdateChildren();
962 // protected internal
963 // Set this object's name if is different to the current name.
964 OUString
AccessibleShape::CreateAccessibleBaseName()
966 return ShapeTypeHandler::CreateAccessibleBaseName( mxShape
);
970 OUString
AccessibleShape::CreateAccessibleName()
972 return GetFullAccessibleName(this);
975 OUString
AccessibleShape::GetFullAccessibleName (AccessibleShape
*shape
)
977 OUString
sName (shape
->CreateAccessibleBaseName());
978 // Append the shape's index to the name to disambiguate between shapes
979 // of the same type. If such an index where not given to the
980 // constructor then use the z-order instead. If even that does not exist
981 // we throw an exception.
984 nameStr
= shape
->m_pShape
->GetName();
985 if (nameStr
.isEmpty())
994 //If the new produced name if not the same with last,notify name changed
996 if (aAccName
!= sName
&& !aAccName
.isEmpty())
998 uno::Any aOldValue
, aNewValue
;
999 aOldValue
<<= aAccName
;
1000 aNewValue
<<= sName
;
1002 AccessibleEventId::NAME_CHANGED
,
1011 void AccessibleShape::disposing()
1013 SolarMutexGuard aSolarGuard
;
1014 ::osl::MutexGuard
aGuard (maMutex
);
1016 // Make sure to send an event that this object loses the focus in the
1017 // case that it has the focus.
1018 ::utl::AccessibleStateSetHelper
* pStateSet
=
1019 static_cast< ::utl::AccessibleStateSetHelper
*>(mxStateSet
.get());
1020 if (pStateSet
!= nullptr)
1021 pStateSet
->RemoveState (AccessibleStateType::FOCUSED
);
1023 // Unregister from model.
1024 if (mxShape
.is() && maShapeTreeInfo
.GetModelBroadcaster().is())
1025 maShapeTreeInfo
.GetModelBroadcaster()->removeShapeEventListener(mxShape
,
1026 static_cast<document::XShapeEventListener
*>(this));
1028 // Release the child containers.
1029 if (mpChildrenManager
!= nullptr)
1031 mpChildrenManager
.reset();
1033 if (mpText
!= nullptr)
1039 // Cleanup. Remove references to objects to allow them to be
1042 maShapeTreeInfo
.dispose();
1044 // Call base classes.
1045 AccessibleContextBase::dispose ();
1049 AccessibleShape::getAccessibleIndexInParent()
1052 // Use a simple but slow solution for now. Optimize later.
1054 sal_Int32 nIndex
= m_nIndexInParent
;
1056 nIndex
= AccessibleContextBase::getAccessibleIndexInParent();
1061 void AccessibleShape::UpdateNameAndDescription()
1063 // Ignore missing title, name, or description. There are fallbacks for
1067 Reference
<beans::XPropertySet
> xSet (mxShape
, uno::UNO_QUERY_THROW
);
1069 // Get the accessible name.
1070 OUString sString
= GetOptionalProperty(xSet
, "Title");
1071 if (!sString
.isEmpty())
1073 SetAccessibleName(sString
, AccessibleContextBase::FromShape
);
1077 sString
= GetOptionalProperty(xSet
, "Name");
1078 if (!sString
.isEmpty())
1079 SetAccessibleName(sString
, AccessibleContextBase::FromShape
);
1082 // Get the accessible description.
1083 sString
= GetOptionalProperty(xSet
, "Description");
1084 if (!sString
.isEmpty())
1085 SetAccessibleDescription(sString
, AccessibleContextBase::FromShape
);
1087 catch (uno::RuntimeException
&)
1092 // Return this object's role.
1093 sal_Int16 SAL_CALL
AccessibleShape::getAccessibleRole()
1095 sal_Int16 nAccessibleRole
= AccessibleRole::SHAPE
;
1096 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape
))
1098 case DRAWING_GRAPHIC_OBJECT
:
1099 nAccessibleRole
= AccessibleRole::GRAPHIC
; break;
1101 nAccessibleRole
= AccessibleRole::EMBEDDED_OBJECT
; break;
1104 nAccessibleRole
= AccessibleContextBase::getAccessibleRole();
1108 return nAccessibleRole
;
1113 //sort the drawing objects from up to down, from left to right
1114 struct XShapePosCompareHelper
1116 bool operator() ( const uno::Reference
<drawing::XShape
>& xshape1
,
1117 const uno::Reference
<drawing::XShape
>& xshape2
) const
1119 SdrObject
* pObj1
= GetSdrObjectFromXShape(xshape1
);
1120 SdrObject
* pObj2
= GetSdrObjectFromXShape(xshape2
);
1122 return pObj1
->GetOrdNum() < pObj2
->GetOrdNum();
1129 //end of group position
1131 // XAccessibleGroupPosition
1132 uno::Sequence
< sal_Int32
> SAL_CALL
1133 AccessibleShape::getGroupPosition( const uno::Any
& )
1135 // we will return the:
1137 // [1] similar items counts in the group
1138 // [2] the position of the object in the group
1139 uno::Sequence
< sal_Int32
> aRet( 3 );
1144 css::uno::Reference
<XAccessible
> xParent
= getAccessibleParent();
1149 SdrObject
*pObj
= GetSdrObjectFromXShape(mxShape
);
1152 if(pObj
== nullptr )
1157 // Compute object's group level.
1158 sal_Int32 nGroupLevel
= 0;
1159 SdrObject
* pUper
= pObj
->getParentSdrObjectFromSdrObject();
1163 pUper
= pUper
->getParentSdrObjectFromSdrObject();
1166 css::uno::Reference
<XAccessibleContext
> xParentContext
= xParent
->getAccessibleContext();
1167 if( xParentContext
->getAccessibleRole() == AccessibleRole::DOCUMENT
||
1168 xParentContext
->getAccessibleRole() == AccessibleRole::DOCUMENT_PRESENTATION
||
1169 xParentContext
->getAccessibleRole() == AccessibleRole::DOCUMENT_SPREADSHEET
||
1170 xParentContext
->getAccessibleRole() == AccessibleRole::DOCUMENT_TEXT
)//Document
1172 Reference
< XAccessibleGroupPosition
> xGroupPosition( xParent
,uno::UNO_QUERY
);
1173 if ( xGroupPosition
.is() )
1175 aRet
= xGroupPosition
->getGroupPosition( uno::makeAny( getAccessibleContext() ) );
1179 if (xParentContext
->getAccessibleRole() != AccessibleRole::SHAPE
)
1184 SdrObjList
*pGrpList
= nullptr;
1185 if( pObj
->getParentSdrObjectFromSdrObject() )
1186 pGrpList
= pObj
->getParentSdrObjectFromSdrObject()->GetSubList();
1190 std::vector
< uno::Reference
<drawing::XShape
> > vXShapes
;
1193 const size_t nObj
= pGrpList
->GetObjCount();
1194 for(size_t i
= 0 ; i
< nObj
; ++i
)
1196 SdrObject
*pSubObj
= pGrpList
->GetObj(i
);
1198 xParentContext
->getAccessibleChild(i
)->getAccessibleContext()->getAccessibleRole() != AccessibleRole::GROUP_BOX
)
1200 vXShapes
.push_back( GetXShapeForSdrObject(pSubObj
) );
1205 std::sort( vXShapes
.begin(), vXShapes
.end(), XShapePosCompareHelper() );
1207 //get the index of the selected object in the group
1208 //we start counting position from 1
1210 for ( const auto& rpShape
: vXShapes
)
1212 if ( rpShape
.get() == mxShape
.get() )
1214 sal_Int32
* pArray
= aRet
.getArray();
1215 pArray
[0] = nGroupLevel
;
1216 pArray
[1] = vXShapes
.size();
1226 OUString
AccessibleShape::getObjectLink( const uno::Any
& )
1230 SdrObject
*pObj
= GetSdrObjectFromXShape(mxShape
);
1231 if(pObj
== nullptr )
1235 if (maShapeTreeInfo
.GetDocumentWindow().is())
1237 Reference
< XAccessibleGroupPosition
> xGroupPosition( maShapeTreeInfo
.GetDocumentWindow(), uno::UNO_QUERY
);
1238 if (xGroupPosition
.is())
1240 aRet
= xGroupPosition
->getObjectLink( uno::makeAny( getAccessibleContext() ) );
1246 // XAccessibleHypertext
1247 sal_Int32 SAL_CALL
AccessibleShape::getHyperLinkCount()
1249 // MT: Introduced with IA2 CWS, but SvxAccessibleHyperlink was redundant to svx::AccessibleHyperlink which we introduced meanwhile.
1250 // Code need to be adapted...
1254 SvxAccessibleHyperlink* pLink = new SvxAccessibleHyperlink(m_pShape,this);
1255 if (pLink->IsValidHyperlink())
1261 uno::Reference
< XAccessibleHyperlink
> SAL_CALL
1262 AccessibleShape::getHyperLink( sal_Int32
)
1264 uno::Reference
< XAccessibleHyperlink
> xRet
;
1265 // MT: Introduced with IA2 CWS, but SvxAccessibleHyperlink was redundant to svx::AccessibleHyperlink which we introduced meanwhile.
1266 // Code need to be adapted...
1268 SvxAccessibleHyperlink* pLink = new SvxAccessibleHyperlink(m_pShape,this);
1269 if (pLink->IsValidHyperlink())
1272 throw css::lang::IndexOutOfBoundsException();
1276 sal_Int32 SAL_CALL
AccessibleShape::getHyperLinkIndex( sal_Int32
)
1281 sal_Int32 SAL_CALL
AccessibleShape::getCaretPosition( ){return 0;}
1282 sal_Bool SAL_CALL
AccessibleShape::setCaretPosition( sal_Int32
){return false;}
1283 sal_Unicode SAL_CALL
AccessibleShape::getCharacter( sal_Int32
){return 0;}
1284 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
AccessibleShape::getCharacterAttributes( sal_Int32
, const css::uno::Sequence
< OUString
>& )
1286 uno::Sequence
< css::beans::PropertyValue
> aValues(0);
1289 css::awt::Rectangle SAL_CALL
AccessibleShape::getCharacterBounds( sal_Int32
)
1291 return css::awt::Rectangle(0, 0, 0, 0 );
1293 sal_Int32 SAL_CALL
AccessibleShape::getCharacterCount( ){return 0;}
1294 sal_Int32 SAL_CALL
AccessibleShape::getIndexAtPoint( const css::awt::Point
& ){return 0;}
1295 OUString SAL_CALL
AccessibleShape::getSelectedText( ){return OUString();}
1296 sal_Int32 SAL_CALL
AccessibleShape::getSelectionStart( ){return 0;}
1297 sal_Int32 SAL_CALL
AccessibleShape::getSelectionEnd( ){return 0;}
1298 sal_Bool SAL_CALL
AccessibleShape::setSelection( sal_Int32
, sal_Int32
){return true;}
1299 OUString SAL_CALL
AccessibleShape::getText( ){return OUString();}
1300 OUString SAL_CALL
AccessibleShape::getTextRange( sal_Int32
, sal_Int32
){return OUString();}
1301 css::accessibility::TextSegment SAL_CALL
AccessibleShape::getTextAtIndex( sal_Int32
, sal_Int16
)
1303 css::accessibility::TextSegment aResult
;
1306 css::accessibility::TextSegment SAL_CALL
AccessibleShape::getTextBeforeIndex( sal_Int32
, sal_Int16
)
1308 css::accessibility::TextSegment aResult
;
1311 css::accessibility::TextSegment SAL_CALL
AccessibleShape::getTextBehindIndex( sal_Int32
, sal_Int16
)
1313 css::accessibility::TextSegment aResult
;
1316 sal_Bool SAL_CALL
AccessibleShape::copyText( sal_Int32
, sal_Int32
){return true;}
1317 sal_Bool SAL_CALL
AccessibleShape::scrollSubstringTo( sal_Int32
, sal_Int32
, AccessibleScrollType
){return false;}
1319 } // end of namespace accessibility
1321 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */