sd: keep a non-owning pointer to the OverridingShell
[LibreOffice.git] / svx / source / accessibility / AccessibleShape.cxx
blob7f3eb9986fe6b172e6adee19a0afc30f2ebc8a7c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/accessiblerelationsethelper.hxx>
48 #include <svx/svdview.hxx>
49 #include <comphelper/diagnose_ex.hxx>
50 #include <cppuhelper/queryinterface.hxx>
51 #include <comphelper/sequence.hxx>
52 #include "AccessibleEmptyEditSource.hxx"
54 #include <algorithm>
55 #include <memory>
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 {
65 namespace {
67 OUString GetOptionalProperty (
68 const Reference<beans::XPropertySet>& rxSet,
69 const OUString& rsPropertyName)
71 OUString sValue;
73 if (rxSet.is())
75 const Reference<beans::XPropertySetInfo> xInfo (rxSet->getPropertySetInfo());
76 if ( ! xInfo.is() || xInfo->hasPropertyByName(rsPropertyName))
78 try
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
86 // not available.
90 return sValue;
93 } // end of anonymous namespace
95 // internal
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 = SdrObject::getSdrObjectFromXShape(mxShape);
106 UpdateNameAndDescription();
109 AccessibleShape::~AccessibleShape()
111 mpChildrenManager.reset();
112 mpText.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.
123 UpdateStates ();
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
140 // accessible.
141 Reference<text::XText> xText (mxShape, uno::UNO_QUERY);
142 if (!xText.is())
143 return;
145 SdrView* pView = maShapeTreeInfo.GetSdrView ();
146 const vcl::Window* pWindow = maShapeTreeInfo.GetWindow ();
147 if (!(pView != nullptr && pWindow != nullptr && mxShape.is()))
148 return;
150 // #107948# Determine whether shape text is empty
151 SdrObject* pSdrObject = SdrObject::getSdrObjectFromXShape(mxShape);
152 if( !pSdrObject )
153 return;
155 SdrTextObj* pTextObj = DynCastSdrTextObj( 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->GetOutDev()) ) );
164 else
166 // non-empty text -> use full-fledged edit source right away
167 mpText.reset( new AccessibleTextHelper( std::make_unique<SvxTextEditSource >(*pSdrObject, nullptr, *pView, *pWindow->GetOutDev()) ) );
169 if( pWindow->HasFocus() )
170 mpText->SetFocus();
172 mpText->SetEventSource(this);
176 void AccessibleShape::UpdateStates()
178 // Set the opaque state for certain shape types when their fill style is
179 // solid.
180 bool bShapeIsOpaque = false;
181 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
183 case DRAWING_PAGE:
184 case DRAWING_RECTANGLE:
185 case DRAWING_TEXT:
187 uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
188 if (xSet.is())
192 drawing::FillStyle aFillStyle;
193 bShapeIsOpaque = ( xSet->getPropertyValue (u"FillStyle"_ustr) >>= aFillStyle)
194 && aFillStyle == drawing::FillStyle_SOLID;
196 catch (css::beans::UnknownPropertyException&)
198 // Ignore.
203 if (bShapeIsOpaque)
204 mnStateSet |= AccessibleStateType::OPAQUE;
205 else
206 mnStateSet &= ~AccessibleStateType::OPAQUE;
208 // Set the selected state.
209 bool bShapeIsSelected = false;
210 // XXX fix_me this has to be done with an extra interface later on
211 if ( m_pShape && maShapeTreeInfo.GetSdrView() )
213 bShapeIsSelected = maShapeTreeInfo.GetSdrView()->IsObjMarked(m_pShape);
216 if (bShapeIsSelected)
217 mnStateSet |= AccessibleStateType::SELECTED;
218 else
219 mnStateSet &= ~AccessibleStateType::SELECTED;
222 OUString AccessibleShape::GetStyle() const
224 return ShapeTypeHandler::CreateAccessibleBaseName( mxShape );
227 bool AccessibleShape::SetState (sal_Int64 aState)
229 bool bStateHasChanged = false;
231 if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
233 // Offer FOCUSED state to edit engine and detect whether the state
234 // changes.
235 bool bIsFocused = mpText->HaveFocus ();
236 mpText->SetFocus();
237 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
239 else
240 bStateHasChanged = AccessibleContextBase::SetState (aState);
242 return bStateHasChanged;
246 bool AccessibleShape::ResetState (sal_Int64 aState)
248 bool bStateHasChanged = false;
250 if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
252 // Try to remove FOCUSED state from the edit engine and detect
253 // whether the state changes.
254 bool bIsFocused = mpText->HaveFocus ();
255 mpText->SetFocus (false);
256 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
258 else
259 bStateHasChanged = AccessibleContextBase::ResetState (aState);
261 return bStateHasChanged;
265 bool AccessibleShape::GetState (sal_Int64 aState)
267 if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
269 // Just delegate the call to the edit engine. The state is not
270 // merged into the state set.
271 return mpText->HaveFocus();
273 else
274 return AccessibleContextBase::GetState (aState);
277 // OverWrite the parent's getAccessibleName method
278 OUString SAL_CALL AccessibleShape::getAccessibleName()
280 ThrowIfDisposed ();
281 if (m_pShape && !m_pShape->GetTitle().isEmpty())
282 return CreateAccessibleName() + " " + m_pShape->GetTitle();
283 else
284 return CreateAccessibleName();
287 OUString SAL_CALL AccessibleShape::getAccessibleDescription()
289 ThrowIfDisposed ();
290 if( m_pShape && !m_pShape->GetDescription().isEmpty())
291 return m_pShape->GetDescription() ;
292 else
293 return u" "_ustr;
296 // XAccessibleContext
297 /** The children of this shape come from two sources: The children from
298 group or scene shapes and the paragraphs of text.
300 sal_Int64 SAL_CALL
301 AccessibleShape::getAccessibleChildCount ()
303 if (IsDisposed())
305 return 0;
308 sal_Int64 nChildCount = 0;
310 // Add the number of shapes that are children of this shape.
311 if (mpChildrenManager != nullptr)
312 nChildCount += mpChildrenManager->GetChildCount ();
313 // Add the number text paragraphs.
314 if (mpText != nullptr)
315 nChildCount += mpText->GetChildCount ();
317 return nChildCount;
321 /** Forward the request to the shape. Return the requested shape or throw
322 an exception for a wrong index.
324 uno::Reference<XAccessible> SAL_CALL
325 AccessibleShape::getAccessibleChild (sal_Int64 nIndex)
327 ThrowIfDisposed ();
329 uno::Reference<XAccessible> xChild;
331 // Depending on the index decide whether to delegate this call to the
332 // children manager or the edit engine.
333 if ((mpChildrenManager != nullptr)
334 && (nIndex < mpChildrenManager->GetChildCount()))
336 xChild = mpChildrenManager->GetChild (nIndex);
338 else if (mpText != nullptr)
340 sal_Int64 nI = nIndex;
341 if (mpChildrenManager != nullptr)
342 nI -= mpChildrenManager->GetChildCount();
343 xChild = mpText->GetChild (nI);
345 else
346 throw lang::IndexOutOfBoundsException (
347 "shape has no child with index " + OUString::number(nIndex),
348 getXWeak());
350 return xChild;
353 uno::Reference<XAccessibleRelationSet> SAL_CALL
354 AccessibleShape::getAccessibleRelationSet()
356 ::osl::MutexGuard aGuard (m_aMutex);
357 if (mpParent == nullptr)
358 return uno::Reference<XAccessibleRelationSet>();
360 rtl::Reference<::utl::AccessibleRelationSetHelper> pRelationSet = new utl::AccessibleRelationSetHelper;
362 //this mxshape is the captioned shape
363 uno::Sequence<uno::Reference<css::accessibility::XAccessible>> aSequence { mpParent->GetAccessibleCaption(mxShape) };
364 if(aSequence[0])
366 pRelationSet->AddRelation(
367 AccessibleRelation(AccessibleRelationType_DESCRIBED_BY, aSequence));
369 return pRelationSet;
372 /** Return a copy of the state set.
373 Possible states are:
374 ENABLED
375 SHOWING
376 VISIBLE
378 sal_Int64 SAL_CALL
379 AccessibleShape::getAccessibleStateSet()
381 ::osl::MutexGuard aGuard (m_aMutex);
383 if (IsDisposed())
385 // Return a minimal state set that only contains the DEFUNC state.
386 return AccessibleContextBase::getAccessibleStateSet ();
389 // Merge current FOCUSED state from edit engine.
390 if (mpText)
392 if (mpText->HaveFocus())
393 mnStateSet |= AccessibleStateType::FOCUSED;
394 else
395 mnStateSet &= ~AccessibleStateType::FOCUSED;
397 //Just when the document is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
398 css::uno::Reference<XAccessible> xTempAcc = getAccessibleParent();
399 if( xTempAcc.is() )
401 css::uno::Reference<XAccessibleContext>
402 xTempAccContext = xTempAcc->getAccessibleContext();
403 if( xTempAccContext.is() )
405 sal_Int64 nState = xTempAccContext->getAccessibleStateSet();
406 if (nState & AccessibleStateType::EDITABLE)
408 mnStateSet |= AccessibleStateType::EDITABLE;
409 mnStateSet |= AccessibleStateType::RESIZABLE;
410 mnStateSet |= AccessibleStateType::MOVEABLE;
415 sal_Int64 nRetStateSet = mnStateSet;
417 if (mpParent && mpParent->IsDocumentSelAll())
419 nRetStateSet |= AccessibleStateType::SELECTED;
422 return nRetStateSet;
425 // XAccessibleComponent
426 /** The implementation below is at the moment straightforward. It iterates
427 over all children (and thereby instances all children which have not
428 been already instantiated) until a child covering the specified point is
429 found.
430 This leaves room for improvement. For instance, first iterate only over
431 the already instantiated children and only if no match is found
432 instantiate the remaining ones.
434 uno::Reference<XAccessible > SAL_CALL
435 AccessibleShape::getAccessibleAtPoint (
436 const awt::Point& aPoint)
438 ::osl::MutexGuard aGuard (m_aMutex);
440 sal_Int64 nChildCount = getAccessibleChildCount ();
441 for (sal_Int64 i = 0; i < nChildCount; ++i)
443 Reference<XAccessible> xChild (getAccessibleChild (i));
444 if (xChild.is())
446 Reference<XAccessibleComponent> xChildComponent (
447 xChild->getAccessibleContext(), uno::UNO_QUERY);
448 if (xChildComponent.is())
450 awt::Rectangle aBBox (xChildComponent->getBounds());
451 if ( (aPoint.X >= aBBox.X)
452 && (aPoint.Y >= aBBox.Y)
453 && (aPoint.X < aBBox.X+aBBox.Width)
454 && (aPoint.Y < aBBox.Y+aBBox.Height) )
455 return xChild;
460 // Have not found a child under the given point. Returning empty
461 // reference to indicate this.
462 return uno::Reference<XAccessible>();
466 awt::Rectangle SAL_CALL AccessibleShape::getBounds()
468 SolarMutexGuard aSolarGuard;
469 ::osl::MutexGuard aGuard (m_aMutex);
471 ThrowIfDisposed ();
472 awt::Rectangle aBoundingBox;
473 if ( mxShape.is() )
476 static constexpr OUString sBoundRectName = u"BoundRect"_ustr;
477 static constexpr OUString sAnchorPositionName = u"AnchorPosition"_ustr;
479 // Get the shape's bounding box in internal coordinates (in 100th of
480 // mm). Use the property BoundRect. Only if that is not supported ask
481 // the shape for its position and size directly.
482 Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
483 Reference<beans::XPropertySetInfo> xSetInfo;
484 bool bFoundBoundRect = false;
485 if (xSet.is())
487 xSetInfo = xSet->getPropertySetInfo ();
488 if (xSetInfo.is())
490 if (xSetInfo->hasPropertyByName (sBoundRectName))
494 uno::Any aValue = xSet->getPropertyValue (sBoundRectName);
495 aValue >>= aBoundingBox;
496 bFoundBoundRect = true;
498 catch (beans::UnknownPropertyException const&)
500 // Handled below (bFoundBoundRect stays false).
503 else
504 SAL_WARN("svx", "no property BoundRect");
508 // Fallback when there is no BoundRect Property.
509 if ( ! bFoundBoundRect )
511 awt::Point aPosition (mxShape->getPosition());
512 awt::Size aSize (mxShape->getSize());
513 aBoundingBox = awt::Rectangle (
514 aPosition.X, aPosition.Y,
515 aSize.Width, aSize.Height);
517 // While BoundRects have absolute positions, the position returned
518 // by XPosition::getPosition is relative. Get the anchor position
519 // (usually not (0,0) for Writer shapes).
520 if (xSetInfo.is())
522 if (xSetInfo->hasPropertyByName (sAnchorPositionName))
524 uno::Any aPos = xSet->getPropertyValue (sAnchorPositionName);
525 awt::Point aAnchorPosition;
526 aPos >>= aAnchorPosition;
527 aBoundingBox.X += aAnchorPosition.X;
528 aBoundingBox.Y += aAnchorPosition.Y;
533 // Transform coordinates from internal to pixel.
534 if (maShapeTreeInfo.GetViewForwarder() == nullptr)
535 throw uno::RuntimeException (
536 u"AccessibleShape has no valid view forwarder"_ustr,
537 getXWeak());
538 ::Size aPixelSize = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
539 ::Size (aBoundingBox.Width, aBoundingBox.Height));
540 ::Point aPixelPosition = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
541 ::Point (aBoundingBox.X, aBoundingBox.Y));
543 // Clip the shape's bounding box with the bounding box of its parent.
544 Reference<XAccessibleComponent> xParentComponent (
545 getAccessibleParent(), uno::UNO_QUERY);
546 if (xParentComponent.is())
548 // Make the coordinates relative to the parent.
549 awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
550 int x = aPixelPosition.getX() - aParentLocation.X;
551 int y = aPixelPosition.getY() - aParentLocation.Y;
553 // Clip with parent (with coordinates relative to itself).
554 ::tools::Rectangle aBBox (
555 x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
556 awt::Size aParentSize (xParentComponent->getSize());
557 ::tools::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
558 aBBox = aBBox.GetIntersection (aParentBBox);
559 aBoundingBox = awt::Rectangle (
560 aBBox.Left(),
561 aBBox.Top(),
562 aBBox.getOpenWidth(),
563 aBBox.getOpenHeight());
565 else
567 SAL_INFO("svx", "parent does not support component");
568 aBoundingBox = awt::Rectangle (
569 aPixelPosition.getX(), aPixelPosition.getY(),
570 aPixelSize.getWidth(), aPixelSize.getHeight());
574 return aBoundingBox;
578 awt::Point SAL_CALL AccessibleShape::getLocation()
580 ThrowIfDisposed ();
581 awt::Rectangle aBoundingBox (getBounds());
582 return awt::Point (aBoundingBox.X, aBoundingBox.Y);
586 awt::Point SAL_CALL AccessibleShape::getLocationOnScreen()
588 ThrowIfDisposed ();
590 // Get relative position...
591 awt::Point aLocation (getLocation ());
593 // ... and add absolute position of the parent.
594 uno::Reference<XAccessibleComponent> xParentComponent (
595 getAccessibleParent(), uno::UNO_QUERY);
596 if (xParentComponent.is())
598 awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
599 aLocation.X += aParentLocation.X;
600 aLocation.Y += aParentLocation.Y;
602 else
603 SAL_WARN("svx", "parent does not support XAccessibleComponent");
604 return aLocation;
608 awt::Size SAL_CALL AccessibleShape::getSize()
610 ThrowIfDisposed ();
611 awt::Rectangle aBoundingBox (getBounds());
612 return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
616 sal_Int32 SAL_CALL AccessibleShape::getForeground()
618 ThrowIfDisposed ();
619 sal_Int32 nColor (0x0ffffffL);
623 uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
624 if (aSet.is())
626 uno::Any aColor;
627 aColor = aSet->getPropertyValue (u"LineColor"_ustr);
628 aColor >>= nColor;
631 catch (const css::beans::UnknownPropertyException &)
633 // Ignore exception and return default color.
635 return nColor;
639 sal_Int32 SAL_CALL AccessibleShape::getBackground()
641 ThrowIfDisposed ();
642 Color nColor;
646 uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
647 if (aSet.is())
649 uno::Any aColor;
650 aColor = aSet->getPropertyValue (u"FillColor"_ustr);
651 aColor >>= nColor;
652 aColor = aSet->getPropertyValue (u"FillTransparence"_ustr);
653 short nTrans=0;
654 aColor >>= nTrans;
655 Color crBk(nColor);
656 if (nTrans == 0 )
658 crBk.SetAlpha(0);
660 else
662 nTrans = short(256 - nTrans / 100. * 256);
663 crBk.SetAlpha(255 - sal_uInt8(nTrans));
665 nColor = crBk;
668 catch (const css::beans::UnknownPropertyException &)
670 // Ignore exception and return default color.
672 return sal_Int32(nColor);
675 // XAccessibleEventBroadcaster
676 void SAL_CALL AccessibleShape::addAccessibleEventListener (
677 const Reference<XAccessibleEventListener >& rxListener)
679 if (rBHelper.bDisposed || rBHelper.bInDispose)
681 uno::Reference<uno::XInterface> xThis (
682 static_cast<lang::XComponent *>(this), uno::UNO_QUERY);
683 rxListener->disposing (lang::EventObject (xThis));
685 else
687 AccessibleContextBase::addAccessibleEventListener (rxListener);
688 if (mpText != nullptr)
689 mpText->AddEventListener (rxListener);
694 void SAL_CALL AccessibleShape::removeAccessibleEventListener (
695 const Reference<XAccessibleEventListener >& rxListener)
697 AccessibleContextBase::removeAccessibleEventListener (rxListener);
698 if (mpText != nullptr)
699 mpText->RemoveEventListener (rxListener);
702 // XInterface
703 css::uno::Any SAL_CALL
704 AccessibleShape::queryInterface (const css::uno::Type & rType)
706 css::uno::Any aReturn = AccessibleContextBase::queryInterface (rType);
707 if ( ! aReturn.hasValue())
708 aReturn = ::cppu::queryInterface (rType,
709 static_cast<XAccessibleComponent*>(this),
710 static_cast<XAccessibleExtendedComponent*>(this),
711 static_cast< css::accessibility::XAccessibleSelection* >(this),
712 static_cast< css::accessibility::XAccessibleExtendedAttributes* >(this),
713 static_cast<document::XShapeEventListener*>(this),
714 static_cast<lang::XUnoTunnel*>(this),
715 static_cast<XAccessibleGroupPosition*>(this),
716 static_cast<XAccessibleHypertext*>(this)
718 return aReturn;
722 void SAL_CALL
723 AccessibleShape::acquire()
724 noexcept
726 AccessibleContextBase::acquire ();
730 void SAL_CALL
731 AccessibleShape::release()
732 noexcept
734 AccessibleContextBase::release ();
737 // XAccessibleSelection
738 void SAL_CALL AccessibleShape::selectAccessibleChild( sal_Int64 )
743 sal_Bool SAL_CALL AccessibleShape::isAccessibleChildSelected( sal_Int64 nChildIndex )
745 uno::Reference<XAccessible> xAcc = getAccessibleChild( nChildIndex );
746 uno::Reference<XAccessibleContext> xContext;
747 if( xAcc.is() )
749 xContext = xAcc->getAccessibleContext();
752 if( xContext.is() )
754 if( xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
756 uno::Reference< css::accessibility::XAccessibleText >
757 xText(xAcc, uno::UNO_QUERY);
758 if( xText.is() )
760 if( xText->getSelectionStart() >= 0 ) return true;
763 else if( xContext->getAccessibleRole() == AccessibleRole::SHAPE )
765 sal_Int64 pRState = xContext->getAccessibleStateSet();
767 return bool(pRState & AccessibleStateType::SELECTED);
771 return false;
775 void SAL_CALL AccessibleShape::clearAccessibleSelection( )
780 void SAL_CALL AccessibleShape::selectAllAccessibleChildren( )
785 sal_Int64 SAL_CALL AccessibleShape::getSelectedAccessibleChildCount()
787 sal_Int64 nCount = 0;
788 sal_Int64 TotalCount = getAccessibleChildCount();
789 for( sal_Int64 i = 0; i < TotalCount; i++ )
790 if( isAccessibleChildSelected(i) ) nCount++;
792 return nCount;
796 Reference<XAccessible> SAL_CALL AccessibleShape::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
798 if ( nSelectedChildIndex > getSelectedAccessibleChildCount() )
799 throw IndexOutOfBoundsException();
800 for (sal_Int64 i1 = 0, i2 = 0; i1 < getAccessibleChildCount(); i1++)
801 if( isAccessibleChildSelected(i1) )
803 if( i2 == nSelectedChildIndex )
804 return getAccessibleChild( i1 );
805 i2++;
807 return Reference<XAccessible>();
811 void SAL_CALL AccessibleShape::deselectAccessibleChild( sal_Int64 )
816 // XAccessibleExtendedAttributes
817 uno::Any SAL_CALL AccessibleShape::getExtendedAttributes()
819 uno::Any strRet;
820 OUString style;
821 if( getAccessibleRole() != AccessibleRole::SHAPE ) return strRet;
822 if( m_pShape )
824 style = "style:" + GetStyle();
826 style += ";";
827 strRet <<= style;
828 return strRet;
831 // XServiceInfo
832 OUString SAL_CALL
833 AccessibleShape::getImplementationName()
835 return u"AccessibleShape"_ustr;
839 uno::Sequence<OUString> SAL_CALL
840 AccessibleShape::getSupportedServiceNames()
842 ThrowIfDisposed ();
843 const css::uno::Sequence<OUString> vals { u"com.sun.star.drawing.AccessibleShape"_ustr };
844 return comphelper::concatSequences(AccessibleContextBase::getSupportedServiceNames(), vals);
847 // XTypeProvider
848 uno::Sequence<uno::Type> SAL_CALL
849 AccessibleShape::getTypes()
851 ThrowIfDisposed ();
852 // Get list of types from the context base implementation, ...
853 uno::Sequence<uno::Type> aTypeList (AccessibleContextBase::getTypes());
854 // ... get list of types from component base implementation, ...
855 uno::Sequence<uno::Type> aComponentTypeList (AccessibleComponentBase::getTypes());
856 // ... define local types
857 uno::Sequence<uno::Type> localTypesList = {
858 cppu::UnoType<lang::XEventListener>::get(),
859 cppu::UnoType<document::XEventListener>::get(),
860 cppu::UnoType<lang::XUnoTunnel>::get()
863 return comphelper::concatSequences(aTypeList, aComponentTypeList, localTypesList);
866 // lang::XEventListener
867 /** Disposing calls are accepted only from the model: Just reset the
868 reference to the model in the shape tree info. Otherwise this object
869 remains functional.
871 void AccessibleShape::disposing (const lang::EventObject& aEvent)
873 SolarMutexGuard aSolarGuard;
874 ::osl::MutexGuard aGuard (m_aMutex);
878 if (aEvent.Source == maShapeTreeInfo.GetModelBroadcaster())
880 // Remove reference to model broadcaster to allow it to pass
881 // away.
882 maShapeTreeInfo.SetModelBroadcaster(nullptr);
886 catch (uno::RuntimeException const&)
888 TOOLS_WARN_EXCEPTION("svx", "caught exception while disposing");
890 mpChildrenManager.reset();
891 mxShape.clear();
892 maShapeTreeInfo.dispose();
893 mpText.reset();
896 // document::XShapeEventListener
897 void SAL_CALL
898 AccessibleShape::notifyShapeEvent (const document::EventObject& rEventObject)
900 if (rEventObject.EventName != "ShapeModified")
901 return;
903 //Need to update text children when receiving ShapeModified hint when exiting edit mode for text box
904 if (mpText)
905 mpText->UpdateChildren();
908 // Some property of a shape has been modified. Send an event
909 // that indicates a change of the visible data to all listeners.
910 CommitChange (
911 AccessibleEventId::VISIBLE_DATA_CHANGED,
912 uno::Any(),
913 uno::Any(), -1);
915 // Name and Description may have changed. Update the local
916 // values accordingly.
917 UpdateNameAndDescription();
920 // lang::XUnoTunnel
921 UNO3_GETIMPLEMENTATION_IMPL(AccessibleShape)
923 // IAccessibleViewForwarderListener
924 void AccessibleShape::ViewForwarderChanged()
926 // Inform all listeners that the graphical representation (i.e. size
927 // and/or position) of the shape has changed.
928 CommitChange (AccessibleEventId::VISIBLE_DATA_CHANGED,
929 uno::Any(),
930 uno::Any(), -1);
932 // Tell children manager of the modified view forwarder.
933 if (mpChildrenManager != nullptr)
934 mpChildrenManager->ViewForwarderChanged();
936 // update our children that our screen position might have changed
937 if( mpText )
938 mpText->UpdateChildren();
941 // protected internal
942 // Set this object's name if is different to the current name.
943 OUString AccessibleShape::CreateAccessibleBaseName()
945 return ShapeTypeHandler::CreateAccessibleBaseName( mxShape );
949 OUString AccessibleShape::CreateAccessibleName()
951 return GetFullAccessibleName(this);
954 OUString AccessibleShape::GetFullAccessibleName (AccessibleShape *shape)
956 OUString sName (shape->CreateAccessibleBaseName());
957 // Append the shape's index to the name to disambiguate between shapes
958 // of the same type. If such an index where not given to the
959 // constructor then use the z-order instead. If even that does not exist
960 // we throw an exception.
961 OUString nameStr;
962 if (shape->m_pShape)
963 nameStr = shape->m_pShape->GetName();
964 if (nameStr.isEmpty())
966 sName += " ";
968 else
970 sName = nameStr;
973 //If the new produced name if not the same with last,notify name changed
974 //Event
975 if (aAccName != sName && !aAccName.isEmpty())
977 uno::Any aOldValue, aNewValue;
978 aOldValue <<= aAccName;
979 aNewValue <<= sName;
980 CommitChange(
981 AccessibleEventId::NAME_CHANGED,
982 aNewValue,
983 aOldValue, -1);
985 aAccName = sName;
986 return sName;
989 // protected
990 void AccessibleShape::disposing()
992 SolarMutexGuard aSolarGuard;
993 ::osl::MutexGuard aGuard (m_aMutex);
995 // Make sure to send an event that this object loses the focus in the
996 // case that it has the focus.
997 mnStateSet &= ~AccessibleStateType::FOCUSED;
999 // Unregister from model.
1000 if (mxShape.is() && maShapeTreeInfo.GetModelBroadcaster().is())
1001 maShapeTreeInfo.GetModelBroadcaster()->removeShapeEventListener(mxShape,
1002 static_cast<document::XShapeEventListener*>(this));
1004 // Release the child containers.
1005 if (mpChildrenManager != nullptr)
1007 mpChildrenManager.reset();
1009 if (mpText != nullptr)
1011 mpText->Dispose();
1012 mpText.reset();
1015 // Cleanup. Remove references to objects to allow them to be
1016 // destroyed.
1017 mxShape = nullptr;
1018 maShapeTreeInfo.dispose();
1020 // Call base classes.
1021 AccessibleContextBase::disposing();
1024 sal_Int64 SAL_CALL
1025 AccessibleShape::getAccessibleIndexInParent()
1027 ThrowIfDisposed ();
1028 // Use a simple but slow solution for now. Optimize later.
1030 sal_Int64 nIndex = m_nIndexInParent;
1031 if ( -1 == nIndex )
1032 nIndex = AccessibleContextBase::getAccessibleIndexInParent();
1033 return nIndex;
1037 void AccessibleShape::UpdateNameAndDescription()
1039 // Ignore missing title, name, or description. There are fallbacks for
1040 // them.
1043 Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY_THROW);
1045 // Get the accessible name.
1046 OUString sString = GetOptionalProperty(xSet, u"Title"_ustr);
1047 if (!sString.isEmpty())
1049 SetAccessibleName(sString, AccessibleContextBase::FromShape);
1051 else
1053 sString = GetOptionalProperty(xSet, u"Name"_ustr);
1054 if (!sString.isEmpty())
1055 SetAccessibleName(sString, AccessibleContextBase::FromShape);
1058 // Get the accessible description.
1059 sString = GetOptionalProperty(xSet, u"Description"_ustr);
1060 if (!sString.isEmpty())
1061 SetAccessibleDescription(sString, AccessibleContextBase::FromShape);
1063 catch (uno::RuntimeException&)
1068 // Return this object's role.
1069 sal_Int16 SAL_CALL AccessibleShape::getAccessibleRole()
1071 sal_Int16 nAccessibleRole = AccessibleRole::SHAPE ;
1072 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
1074 case DRAWING_GRAPHIC_OBJECT:
1075 nAccessibleRole = AccessibleRole::GRAPHIC ; break;
1076 case DRAWING_OLE:
1077 nAccessibleRole = AccessibleRole::EMBEDDED_OBJECT ; break;
1079 default:
1080 nAccessibleRole = AccessibleContextBase::getAccessibleRole();
1081 break;
1084 return nAccessibleRole;
1087 namespace {
1089 //sort the drawing objects from up to down, from left to right
1090 struct XShapePosCompareHelper
1092 bool operator() ( const uno::Reference<drawing::XShape>& xshape1,
1093 const uno::Reference<drawing::XShape>& xshape2 ) const
1095 SdrObject* pObj1 = SdrObject::getSdrObjectFromXShape(xshape1);
1096 SdrObject* pObj2 = SdrObject::getSdrObjectFromXShape(xshape2);
1097 if(pObj1 && pObj2)
1098 return pObj1->GetOrdNum() < pObj2->GetOrdNum();
1099 else
1100 return false;
1105 //end of group position
1107 // XAccessibleGroupPosition
1108 uno::Sequence< sal_Int32 > SAL_CALL
1109 AccessibleShape::getGroupPosition( const uno::Any& )
1111 // we will return the:
1112 // [0] group level
1113 // [1] similar items counts in the group
1114 // [2] the position of the object in the group
1115 uno::Sequence< sal_Int32 > aRet{ 0, 0, 0 };
1117 css::uno::Reference<XAccessible> xParent = getAccessibleParent();
1118 if (!xParent.is())
1120 return aRet;
1122 SdrObject *pObj = SdrObject::getSdrObjectFromXShape(mxShape);
1125 if(pObj == nullptr )
1127 return aRet;
1130 // Compute object's group level.
1131 sal_Int32 nGroupLevel = 0;
1132 SdrObject * pUper = pObj->getParentSdrObjectFromSdrObject();
1133 while( pUper )
1135 ++nGroupLevel;
1136 pUper = pUper->getParentSdrObjectFromSdrObject();
1139 css::uno::Reference<XAccessibleContext> xParentContext = xParent->getAccessibleContext();
1140 if( xParentContext->getAccessibleRole() == AccessibleRole::DOCUMENT ||
1141 xParentContext->getAccessibleRole() == AccessibleRole::DOCUMENT_PRESENTATION ||
1142 xParentContext->getAccessibleRole() == AccessibleRole::DOCUMENT_SPREADSHEET ||
1143 xParentContext->getAccessibleRole() == AccessibleRole::DOCUMENT_TEXT )//Document
1145 Reference< XAccessibleGroupPosition > xGroupPosition( xParent,uno::UNO_QUERY );
1146 if ( xGroupPosition.is() )
1148 aRet = xGroupPosition->getGroupPosition( uno::Any( getAccessibleContext() ) );
1150 return aRet;
1152 if (xParentContext->getAccessibleRole() != AccessibleRole::SHAPE)
1154 return aRet;
1157 SdrObjList *pGrpList = nullptr;
1158 if( pObj->getParentSdrObjectFromSdrObject() )
1159 pGrpList = pObj->getParentSdrObjectFromSdrObject()->GetSubList();
1160 else
1161 return aRet;
1163 std::vector< uno::Reference<drawing::XShape> > vXShapes;
1164 if (pGrpList)
1166 const size_t nObj = pGrpList->GetObjCount();
1167 for(size_t i = 0 ; i < nObj ; ++i)
1169 SdrObject *pSubObj = pGrpList->GetObj(i);
1170 if (pSubObj &&
1171 xParentContext->getAccessibleChild(i)->getAccessibleContext()->getAccessibleRole() != AccessibleRole::GROUP_BOX)
1173 vXShapes.push_back( GetXShapeForSdrObject(pSubObj) );
1178 std::sort( vXShapes.begin(), vXShapes.end(), XShapePosCompareHelper() );
1180 //get the index of the selected object in the group
1181 //we start counting position from 1
1182 sal_Int32 nPos = 1;
1183 for ( const auto& rpShape : vXShapes )
1185 if ( rpShape.get() == mxShape.get() )
1187 sal_Int32* pArray = aRet.getArray();
1188 pArray[0] = nGroupLevel;
1189 pArray[1] = vXShapes.size();
1190 pArray[2] = nPos;
1191 break;
1193 nPos++;
1196 return aRet;
1199 OUString AccessibleShape::getObjectLink( const uno::Any& )
1201 OUString aRet;
1203 SdrObject *pObj = SdrObject::getSdrObjectFromXShape(mxShape);
1204 if(pObj == nullptr )
1206 return aRet;
1208 if (maShapeTreeInfo.GetDocumentWindow().is())
1210 Reference< XAccessibleGroupPosition > xGroupPosition( maShapeTreeInfo.GetDocumentWindow(), uno::UNO_QUERY );
1211 if (xGroupPosition.is())
1213 aRet = xGroupPosition->getObjectLink( uno::Any( getAccessibleContext() ) );
1216 return aRet;
1219 // XAccessibleHypertext
1220 sal_Int32 SAL_CALL AccessibleShape::getHyperLinkCount()
1222 // MT: Introduced with IA2 CWS, but SvxAccessibleHyperlink was redundant to svx::AccessibleHyperlink which we introduced meanwhile.
1223 // Code need to be adapted...
1224 return 0;
1227 SvxAccessibleHyperlink* pLink = new SvxAccessibleHyperlink(m_pShape,this);
1228 if (pLink->IsValidHyperlink())
1229 return 1;
1230 else
1231 return 0;
1234 uno::Reference< XAccessibleHyperlink > SAL_CALL
1235 AccessibleShape::getHyperLink( sal_Int32 )
1237 uno::Reference< XAccessibleHyperlink > xRet;
1238 // MT: Introduced with IA2 CWS, but SvxAccessibleHyperlink was redundant to svx::AccessibleHyperlink which we introduced meanwhile.
1239 // Code need to be adapted...
1241 SvxAccessibleHyperlink* pLink = new SvxAccessibleHyperlink(m_pShape,this);
1242 if (pLink->IsValidHyperlink())
1243 xRet = pLink;
1244 if( !xRet.is() )
1245 throw css::lang::IndexOutOfBoundsException();
1247 return xRet;
1249 sal_Int32 SAL_CALL AccessibleShape::getHyperLinkIndex( sal_Int32 )
1251 return 0;
1253 // XAccessibleText
1254 sal_Int32 SAL_CALL AccessibleShape::getCaretPosition( ){return 0;}
1255 sal_Bool SAL_CALL AccessibleShape::setCaretPosition( sal_Int32 ){return false;}
1256 sal_Unicode SAL_CALL AccessibleShape::getCharacter( sal_Int32 ){return 0;}
1257 css::uno::Sequence< css::beans::PropertyValue > SAL_CALL AccessibleShape::getCharacterAttributes( sal_Int32, const css::uno::Sequence< OUString >& )
1259 uno::Sequence< css::beans::PropertyValue > aValues(0);
1260 return aValues;
1262 css::awt::Rectangle SAL_CALL AccessibleShape::getCharacterBounds( sal_Int32 )
1264 return css::awt::Rectangle(0, 0, 0, 0 );
1266 sal_Int32 SAL_CALL AccessibleShape::getCharacterCount( ){return 0;}
1267 sal_Int32 SAL_CALL AccessibleShape::getIndexAtPoint( const css::awt::Point& ){return 0;}
1268 OUString SAL_CALL AccessibleShape::getSelectedText( ){return OUString();}
1269 sal_Int32 SAL_CALL AccessibleShape::getSelectionStart( ){return 0;}
1270 sal_Int32 SAL_CALL AccessibleShape::getSelectionEnd( ){return 0;}
1271 sal_Bool SAL_CALL AccessibleShape::setSelection( sal_Int32, sal_Int32 ){return true;}
1272 OUString SAL_CALL AccessibleShape::getText( ){return OUString();}
1273 OUString SAL_CALL AccessibleShape::getTextRange( sal_Int32, sal_Int32 ){return OUString();}
1274 css::accessibility::TextSegment SAL_CALL AccessibleShape::getTextAtIndex( sal_Int32, sal_Int16 )
1276 css::accessibility::TextSegment aResult;
1277 return aResult;
1279 css::accessibility::TextSegment SAL_CALL AccessibleShape::getTextBeforeIndex( sal_Int32, sal_Int16 )
1281 css::accessibility::TextSegment aResult;
1282 return aResult;
1284 css::accessibility::TextSegment SAL_CALL AccessibleShape::getTextBehindIndex( sal_Int32, sal_Int16 )
1286 css::accessibility::TextSegment aResult;
1287 return aResult;
1289 sal_Bool SAL_CALL AccessibleShape::copyText( sal_Int32, sal_Int32 ){return true;}
1290 sal_Bool SAL_CALL AccessibleShape::scrollSubstringTo( sal_Int32, sal_Int32, AccessibleScrollType ){return false;}
1292 } // end of namespace accessibility
1294 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */