Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / accessibility / AccessibleShape.cxx
blob6e4891d4f011b1b30dc4e03f388a0280f2dc937a
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 <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"
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 = 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 = GetSdrObjectFromXShape(mxShape);
152 if( !pSdrObject )
153 return;
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) ) );
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) ) );
169 if( pWindow->HasFocus() )
170 mpText->SetFocus();
172 mpText->SetEventSource(this);
176 void AccessibleShape::UpdateStates()
178 ::utl::AccessibleStateSetHelper* pStateSet =
179 static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
180 if (pStateSet == nullptr)
181 return;
183 // Set the opaque state for certain shape types when their fill style is
184 // solid.
185 bool bShapeIsOpaque = false;
186 switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
188 case DRAWING_PAGE:
189 case DRAWING_RECTANGLE:
190 case DRAWING_TEXT:
192 uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
193 if (xSet.is())
197 drawing::FillStyle aFillStyle;
198 bShapeIsOpaque = ( xSet->getPropertyValue ("FillStyle") >>= aFillStyle)
199 && aFillStyle == drawing::FillStyle_SOLID;
201 catch (css::beans::UnknownPropertyException&)
203 // Ignore.
208 if (bShapeIsOpaque)
209 pStateSet->AddState (AccessibleStateType::OPAQUE);
210 else
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);
223 else
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
239 // changes.
240 bool bIsFocused = mpText->HaveFocus ();
241 mpText->SetFocus();
242 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
244 else
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 ());
263 else
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();
278 else
279 return AccessibleContextBase::GetState (aState);
282 // OverWrite the parent's getAccessibleName method
283 OUString SAL_CALL AccessibleShape::getAccessibleName()
285 ThrowIfDisposed ();
286 if (m_pShape && !m_pShape->GetTitle().isEmpty())
287 return CreateAccessibleName() + " " + m_pShape->GetTitle();
288 else
289 return CreateAccessibleName();
292 OUString SAL_CALL AccessibleShape::getAccessibleDescription()
294 ThrowIfDisposed ();
295 if( m_pShape && !m_pShape->GetDescription().isEmpty())
296 return m_pShape->GetDescription() ;
297 else
298 return " ";
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.
305 sal_Int32 SAL_CALL
306 AccessibleShape::getAccessibleChildCount ()
308 if (IsDisposed())
310 return 0;
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 ();
322 return nChildCount;
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)
332 ThrowIfDisposed ();
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);
350 else
351 throw lang::IndexOutOfBoundsException (
352 "shape has no child with index " + OUString::number(nIndex),
353 static_cast<uno::XWeak*>(this));
355 return xChild;
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) };
369 if(aSequence[0])
371 pRelationSet->AddRelation(
372 AccessibleRelation( AccessibleRelationType::DESCRIBED_BY, aSequence ) );
374 return uno::Reference<XAccessibleRelationSet>(pRelationSet);
377 /** Return a copy of the state set.
378 Possible states are:
379 ENABLED
380 SHOWING
381 VISIBLE
383 uno::Reference<XAccessibleStateSet> SAL_CALL
384 AccessibleShape::getAccessibleStateSet()
386 ::osl::MutexGuard aGuard (maMutex);
388 if (IsDisposed())
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());
397 if (!pStateSet)
398 return Reference<XAccessibleStateSet>();
400 // Merge current FOCUSED state from edit engine.
401 if (mpText)
403 if (mpText->HaveFocus())
404 pStateSet->AddState (AccessibleStateType::FOCUSED);
405 else
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();
410 if( xTempAcc.is() )
412 css::uno::Reference<XAccessibleContext>
413 xTempAccContext = xTempAcc->getAccessibleContext();
414 if( xTempAccContext.is() )
416 css::uno::Reference<XAccessibleStateSet> rState =
417 xTempAccContext->getAccessibleStateSet();
418 if (rState.is())
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);
442 return xStateSet;
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
449 found.
450 This leaves room for improvement. For instance, first iterate only over
451 the already instantiated children and only if no match is found
452 instantiate the remaining ones.
454 uno::Reference<XAccessible > SAL_CALL
455 AccessibleShape::getAccessibleAtPoint (
456 const awt::Point& aPoint)
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));
464 if (xChild.is())
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) )
475 return xChild;
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);
491 ThrowIfDisposed ();
492 awt::Rectangle aBoundingBox;
493 if ( mxShape.is() )
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;
505 if (xSet.is())
507 xSetInfo = xSet->getPropertySetInfo ();
508 if (xSetInfo.is())
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).
523 else
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).
540 if (xSetInfo.is())
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 (
580 aBBox.getX(),
581 aBBox.getY(),
582 aBBox.getWidth(),
583 aBBox.getHeight());
585 else
587 SAL_INFO("svx", "parent does not support component");
588 aBoundingBox = awt::Rectangle (
589 aPixelPosition.getX(), aPixelPosition.getY(),
590 aPixelSize.getWidth(), aPixelSize.getHeight());
594 return aBoundingBox;
598 awt::Point SAL_CALL AccessibleShape::getLocation()
600 ThrowIfDisposed ();
601 awt::Rectangle aBoundingBox (getBounds());
602 return awt::Point (aBoundingBox.X, aBoundingBox.Y);
606 awt::Point SAL_CALL AccessibleShape::getLocationOnScreen()
608 ThrowIfDisposed ();
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;
622 else
623 SAL_WARN("svx", "parent does not support XAccessibleComponent");
624 return aLocation;
628 awt::Size SAL_CALL AccessibleShape::getSize()
630 ThrowIfDisposed ();
631 awt::Rectangle aBoundingBox (getBounds());
632 return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
636 sal_Int32 SAL_CALL AccessibleShape::getForeground()
638 ThrowIfDisposed ();
639 sal_Int32 nColor (0x0ffffffL);
643 uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
644 if (aSet.is())
646 uno::Any aColor;
647 aColor = aSet->getPropertyValue ("LineColor");
648 aColor >>= nColor;
651 catch (const css::beans::UnknownPropertyException &)
653 // Ignore exception and return default color.
655 return nColor;
659 sal_Int32 SAL_CALL AccessibleShape::getBackground()
661 ThrowIfDisposed ();
662 Color nColor;
666 uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
667 if (aSet.is())
669 uno::Any aColor;
670 aColor = aSet->getPropertyValue ("FillColor");
671 aColor >>= nColor;
672 aColor = aSet->getPropertyValue ("FillTransparence");
673 short nTrans=0;
674 aColor >>= nTrans;
675 Color crBk(nColor);
676 if (nTrans == 0 )
678 crBk.SetTransparency(0xff);
680 else
682 nTrans = short(256 - nTrans / 100. * 256);
683 crBk.SetTransparency(sal_uInt8(nTrans));
685 nColor = crBk;
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));
705 else
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);
722 // XInterface
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)
738 return aReturn;
742 void SAL_CALL
743 AccessibleShape::acquire()
744 throw ()
746 AccessibleContextBase::acquire ();
750 void SAL_CALL
751 AccessibleShape::release()
752 throw ()
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;
767 if( xAcc.is() )
769 xContext = xAcc->getAccessibleContext();
772 if( xContext.is() )
774 if( xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
776 uno::Reference< css::accessibility::XAccessibleText >
777 xText(xAcc, uno::UNO_QUERY);
778 if( xText.is() )
780 if( xText->getSelectionStart() >= 0 ) return true;
783 else if( xContext->getAccessibleRole() == AccessibleRole::SHAPE )
785 Reference< XAccessibleStateSet > pRState = xContext->getAccessibleStateSet();
786 if( !pRState.is() )
787 return false;
789 uno::Sequence<short> aStates = pRState->getStates();
790 return std::find(aStates.begin(), aStates.end(), AccessibleStateType::SELECTED) != aStates.end();
794 return false;
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++;
815 return nCount;
819 Reference<XAccessible> SAL_CALL AccessibleShape::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
821 if ( nSelectedChildIndex > getSelectedAccessibleChildCount() )
822 throw IndexOutOfBoundsException();
823 sal_Int32 i1, i2;
824 for( i1 = 0, i2 = 0; i1 < getAccessibleChildCount(); i1++ )
825 if( isAccessibleChildSelected(i1) )
827 if( i2 == nSelectedChildIndex )
828 return getAccessibleChild( i1 );
829 i2++;
831 return Reference<XAccessible>();
835 void SAL_CALL AccessibleShape::deselectAccessibleChild( sal_Int32 )
840 // XAccessibleExtendedAttributes
841 uno::Any SAL_CALL AccessibleShape::getExtendedAttributes()
843 uno::Any strRet;
844 OUString style;
845 if( getAccessibleRole() != AccessibleRole::SHAPE ) return strRet;
846 if( m_pShape )
848 style = "style:" + GetStyle();
850 style += ";";
851 strRet <<= style;
852 return strRet;
855 // XServiceInfo
856 OUString SAL_CALL
857 AccessibleShape::getImplementationName()
859 return "AccessibleShape";
863 uno::Sequence<OUString> SAL_CALL
864 AccessibleShape::getSupportedServiceNames()
866 ThrowIfDisposed ();
867 const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleShape" };
868 return comphelper::concatSequences(AccessibleContextBase::getSupportedServiceNames(), vals);
871 // XTypeProvider
872 uno::Sequence<uno::Type> SAL_CALL
873 AccessibleShape::getTypes()
875 ThrowIfDisposed ();
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
893 remains functional.
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
905 // away.
906 maShapeTreeInfo.SetModelBroadcaster(nullptr);
910 catch (uno::RuntimeException const&)
912 TOOLS_WARN_EXCEPTION("svx", "caught exception while disposing");
916 // document::XShapeEventListener
917 void SAL_CALL
918 AccessibleShape::notifyShapeEvent (const document::EventObject& rEventObject)
920 if (rEventObject.EventName != "ShapeModified")
921 return;
923 //Need to update text children when receiving ShapeModified hint when exiting edit mode for text box
924 if (mpText)
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.
930 CommitChange (
931 AccessibleEventId::VISIBLE_DATA_CHANGED,
932 uno::Any(),
933 uno::Any());
935 // Name and Description may have changed. Update the local
936 // values accordingly.
937 UpdateNameAndDescription();
940 // lang::XUnoTunnel
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,
949 uno::Any(),
950 uno::Any());
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
957 if( mpText )
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.
981 OUString nameStr;
982 if (shape->m_pShape)
983 nameStr = shape->m_pShape->GetName();
984 if (nameStr.isEmpty())
986 sName += " ";
988 else
990 sName = nameStr;
993 //If the new produced name if not the same with last,notify name changed
994 //Event
995 if (aAccName != sName && !aAccName.isEmpty())
997 uno::Any aOldValue, aNewValue;
998 aOldValue <<= aAccName;
999 aNewValue <<= sName;
1000 CommitChange(
1001 AccessibleEventId::NAME_CHANGED,
1002 aNewValue,
1003 aOldValue);
1005 aAccName = sName;
1006 return sName;
1009 // protected
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)
1034 mpText->Dispose();
1035 mpText.reset();
1038 // Cleanup. Remove references to objects to allow them to be
1039 // destroyed.
1040 mxShape = nullptr;
1041 maShapeTreeInfo.dispose();
1043 // Call base classes.
1044 AccessibleContextBase::dispose ();
1047 sal_Int32 SAL_CALL
1048 AccessibleShape::getAccessibleIndexInParent()
1050 ThrowIfDisposed ();
1051 // Use a simple but slow solution for now. Optimize later.
1053 sal_Int32 nIndex = m_nIndexInParent;
1054 if ( -1 == nIndex )
1055 nIndex = AccessibleContextBase::getAccessibleIndexInParent();
1056 return nIndex;
1060 void AccessibleShape::UpdateNameAndDescription()
1062 // Ignore missing title, name, or description. There are fallbacks for
1063 // them.
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);
1074 else
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;
1099 case DRAWING_OLE:
1100 nAccessibleRole = AccessibleRole::EMBEDDED_OBJECT ; break;
1102 default:
1103 nAccessibleRole = AccessibleContextBase::getAccessibleRole();
1104 break;
1107 return nAccessibleRole;
1110 namespace {
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);
1120 if(pObj1 && pObj2)
1121 return pObj1->GetOrdNum() < pObj2->GetOrdNum();
1122 else
1123 return false;
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:
1135 // [0] group level
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 );
1139 aRet[0] = 0;
1140 aRet[1] = 0;
1141 aRet[2] = 0;
1143 css::uno::Reference<XAccessible> xParent = getAccessibleParent();
1144 if (!xParent.is())
1146 return aRet;
1148 SdrObject *pObj = GetSdrObjectFromXShape(mxShape);
1151 if(pObj == nullptr )
1153 return aRet;
1156 // Compute object's group level.
1157 sal_Int32 nGroupLevel = 0;
1158 SdrObject * pUper = pObj->getParentSdrObjectFromSdrObject();
1159 while( pUper )
1161 ++nGroupLevel;
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() ) );
1176 return aRet;
1178 if (xParentContext->getAccessibleRole() != AccessibleRole::SHAPE)
1180 return aRet;
1183 SdrObjList *pGrpList = nullptr;
1184 if( pObj->getParentSdrObjectFromSdrObject() )
1185 pGrpList = pObj->getParentSdrObjectFromSdrObject()->GetSubList();
1186 else
1187 return aRet;
1189 std::vector< uno::Reference<drawing::XShape> > vXShapes;
1190 if (pGrpList)
1192 const size_t nObj = pGrpList->GetObjCount();
1193 for(size_t i = 0 ; i < nObj ; ++i)
1195 SdrObject *pSubObj = pGrpList->GetObj(i);
1196 if (pSubObj &&
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
1208 sal_Int32 nPos = 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();
1216 pArray[2] = nPos;
1217 break;
1219 nPos++;
1222 return aRet;
1225 OUString AccessibleShape::getObjectLink( const uno::Any& )
1227 OUString aRet;
1229 SdrObject *pObj = GetSdrObjectFromXShape(mxShape);
1230 if(pObj == nullptr )
1232 return aRet;
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() ) );
1242 return aRet;
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...
1250 return 0;
1253 SvxAccessibleHyperlink* pLink = new SvxAccessibleHyperlink(m_pShape,this);
1254 if (pLink->IsValidHyperlink())
1255 return 1;
1256 else
1257 return 0;
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())
1269 xRet = pLink;
1270 if( !xRet.is() )
1271 throw css::lang::IndexOutOfBoundsException();
1273 return xRet;
1275 sal_Int32 SAL_CALL AccessibleShape::getHyperLinkIndex( sal_Int32 )
1277 return 0;
1279 // XAccessibleText
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);
1286 return aValues;
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;
1303 return aResult;
1305 css::accessibility::TextSegment SAL_CALL AccessibleShape::getTextBeforeIndex( sal_Int32, sal_Int16 )
1307 css::accessibility::TextSegment aResult;
1308 return aResult;
1310 css::accessibility::TextSegment SAL_CALL AccessibleShape::getTextBehindIndex( sal_Int32, sal_Int16 )
1312 css::accessibility::TextSegment aResult;
1313 return 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: */