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 <com/sun/star/accessibility/AccessibleRole.hpp>
21 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
22 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
23 #include <com/sun/star/accessibility/IllegalAccessibleComponentStateException.hpp>
24 #include <com/sun/star/lang/DisposedException.hpp>
25 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
26 #include <unotools/accessiblestatesethelper.hxx>
27 #include <cppuhelper/supportsservice.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/settings.hxx>
30 #include <o3tl/safeint.hxx>
31 #include <osl/mutex.hxx>
32 #include <tools/gen.hxx>
33 #include <svtools/colorcfg.hxx>
34 #include <comphelper/accessibleeventnotifier.hxx>
35 #include <svx/sdrpaintwindow.hxx>
37 #include <svx/ShapeTypeHandler.hxx>
38 #include <svx/AccessibleShapeInfo.hxx>
39 #include <GraphCtlAccessibleContext.hxx>
40 #include <svx/graphctl.hxx>
41 #include <svx/strings.hrc>
42 #include <svx/svdpage.hxx>
43 #include <svx/dialmgr.hxx>
44 #include <svx/sdrhittesthelper.hxx>
47 using namespace ::cppu
;
48 using namespace ::osl
;
49 using namespace ::accessibility
;
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::uno
;
52 using namespace ::com::sun::star::drawing
;
53 using namespace ::com::sun::star::lang
;
54 using namespace ::com::sun::star::accessibility
;
57 /** initialize this component and set default values */
58 SvxGraphCtrlAccessibleContext::SvxGraphCtrlAccessibleContext(
61 SvxGraphCtrlAccessibleContext_Base( m_aMutex
),
69 if (mpControl
!= nullptr)
71 mpModel
= mpControl
->GetSdrModel();
72 if (mpModel
!= nullptr)
73 mpPage
= mpModel
->GetPage( 0 );
74 mpView
= mpControl
->GetSdrView();
76 if( mpModel
== nullptr || mpPage
== nullptr || mpView
== nullptr )
79 // Set all the pointers to NULL just in case they are used as
88 ::SolarMutexGuard aSolarGuard
;
89 msName
= SvxResId( RID_SVXSTR_GRAPHCTRL_ACC_NAME
);
90 msDescription
= SvxResId( RID_SVXSTR_GRAPHCTRL_ACC_DESCRIPTION
);
93 maTreeInfo
.SetSdrView( mpView
);
94 maTreeInfo
.SetDevice(&mpControl
->GetDrawingArea()->get_ref_device());
95 maTreeInfo
.SetViewForwarder( this );
99 /** on destruction, this component is disposed and all dispose listeners
100 are called, except if this component was already disposed */
101 SvxGraphCtrlAccessibleContext::~SvxGraphCtrlAccessibleContext()
107 /** returns the XAccessible interface for a given SdrObject.
108 Multiple calls for the same SdrObject return the same XAccessible.
110 Reference
< XAccessible
> SvxGraphCtrlAccessibleContext::getAccessible( const SdrObject
* pObj
)
112 Reference
<XAccessible
> xAccessibleShape
;
116 // see if we already created an XAccessible for the given SdrObject
117 ShapesMapType::const_iterator iter
= mxShapes
.find( pObj
);
119 if( iter
!= mxShapes
.end() )
121 // if we already have one, return it
122 xAccessibleShape
= (*iter
).second
.get();
126 // create a new one and remember in our internal map
127 Reference
< XShape
> xShape( Reference
< XShape
>::query( const_cast<SdrObject
*>(pObj
)->getUnoShape() ) );
129 css::uno::Reference
<css::accessibility::XAccessible
> xParent(getAccessibleParent());
130 AccessibleShapeInfo
aShapeInfo (xShape
,xParent
);
131 // Create accessible object that corresponds to the descriptor's shape.
132 rtl::Reference
<AccessibleShape
> pAcc(ShapeTypeHandler::Instance().CreateAccessibleObject(
133 aShapeInfo
, maTreeInfo
));
134 xAccessibleShape
= pAcc
.get();
139 mxShapes
[pObj
] = pAcc
;
141 // Create event and inform listeners of the object creation.
142 CommitChange( AccessibleEventId::CHILD
, makeAny( xAccessibleShape
), makeAny( Reference
<XAccessible
>() ) );
146 return xAccessibleShape
;
150 Reference
< XAccessibleContext
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleContext()
155 // XAccessibleComponent
156 sal_Bool SAL_CALL
SvxGraphCtrlAccessibleContext::containsPoint( const awt::Point
& rPoint
)
158 // no guard -> done in getSize()
159 awt::Size
aSize (getSize());
160 return (rPoint
.X
>= 0)
161 && (rPoint
.X
< aSize
.Width
)
163 && (rPoint
.Y
< aSize
.Height
);
167 Reference
< XAccessible
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleAtPoint( const awt::Point
& rPoint
)
169 ::osl::MutexGuard
aGuard( m_aMutex
);
171 Reference
< XAccessible
> xAccessible
;
175 throw DisposedException();
178 Point
aPnt( rPoint
.X
, rPoint
.Y
);
179 aPnt
= mpControl
->GetDrawingArea()->get_ref_device().PixelToLogic(aPnt
);
181 SdrObject
* pObj
= nullptr;
183 if(mpView
&& mpView
->GetSdrPageView())
185 pObj
= SdrObjListPrimitiveHit(*mpPage
, aPnt
, 1, *mpView
->GetSdrPageView(), nullptr, false);
189 xAccessible
= getAccessible( pObj
);
194 awt::Rectangle SAL_CALL
SvxGraphCtrlAccessibleContext::getBounds()
196 const SolarMutexGuard aSolarGuard
;
198 if (nullptr == mpControl
)
199 throw DisposedException();
202 const Size
aOutSize( mpControl
->GetOutputSizePixel() );
205 aRet
.X
= aOutPos
.X();
206 aRet
.Y
= aOutPos
.Y();
207 aRet
.Width
= aOutSize
.Width();
208 aRet
.Height
= aOutSize
.Height();
213 awt::Point SAL_CALL
SvxGraphCtrlAccessibleContext::getLocation()
215 const SolarMutexGuard aSolarGuard
;
217 if (nullptr == mpControl
)
218 throw DisposedException();
220 const awt::Rectangle
aRect( getBounds() );
229 awt::Point SAL_CALL
SvxGraphCtrlAccessibleContext::getLocationOnScreen()
231 const SolarMutexGuard aSolarGuard
;
233 if (nullptr == mpControl
)
234 throw DisposedException();
236 awt::Point
aScreenLoc(0, 0);
238 auto xParent(getAccessibleParent());
241 css::uno::Reference
<css::accessibility::XAccessibleContext
> xParentContext(xParent
->getAccessibleContext());
242 css::uno::Reference
<css::accessibility::XAccessibleComponent
> xParentComponent(xParentContext
, css::uno::UNO_QUERY
);
243 OSL_ENSURE( xParentComponent
.is(), "ValueSetAcc::getLocationOnScreen: no parent component!" );
244 if ( xParentComponent
.is() )
246 awt::Point
aParentScreenLoc( xParentComponent
->getLocationOnScreen() );
247 awt::Point
aOwnRelativeLoc( getLocation() );
248 aScreenLoc
.X
= aParentScreenLoc
.X
+ aOwnRelativeLoc
.X
;
249 aScreenLoc
.Y
= aParentScreenLoc
.Y
+ aOwnRelativeLoc
.Y
;
256 awt::Size SAL_CALL
SvxGraphCtrlAccessibleContext::getSize()
258 const SolarMutexGuard aSolarGuard
;
260 if (nullptr == mpControl
)
261 throw DisposedException();
263 const awt::Rectangle
aRect( getBounds() );
266 aRet
.Width
= aRect
.Width
;
267 aRet
.Height
= aRect
.Height
;
272 // XAccessibleContext
273 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleChildCount()
275 ::SolarMutexGuard aGuard
;
277 if( nullptr == mpPage
)
278 throw DisposedException();
280 return mpPage
->GetObjCount();
284 /** returns the SdrObject at index nIndex from the model of this graph */
285 SdrObject
* SvxGraphCtrlAccessibleContext::getSdrObject( sal_Int32 nIndex
)
287 ::SolarMutexGuard aGuard
;
289 if( nullptr == mpPage
)
290 throw DisposedException();
292 if( (nIndex
< 0) || ( o3tl::make_unsigned(nIndex
) >= mpPage
->GetObjCount() ) )
293 throw lang::IndexOutOfBoundsException();
295 return mpPage
->GetObj( nIndex
);
299 /** sends an AccessibleEventObject to all added XAccessibleEventListeners */
300 void SvxGraphCtrlAccessibleContext::CommitChange (
302 const uno::Any
& rNewValue
,
303 const uno::Any
& rOldValue
)
305 AccessibleEventObject
aEvent (
306 static_cast<uno::XWeak
*>(this),
312 comphelper::AccessibleEventNotifier::addEvent( mnClientId
, aEvent
);
315 Reference
< XAccessible
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleChild( sal_Int32 nIndex
)
317 ::SolarMutexGuard aGuard
;
319 return getAccessible( getSdrObject( nIndex
) );
322 Reference
< XAccessible
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleParent()
324 ::SolarMutexGuard aGuard
;
326 if( nullptr == mpControl
)
327 throw DisposedException();
329 return mpControl
->GetDrawingArea()->get_accessible_parent();
332 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleIndexInParent()
334 ::SolarMutexGuard aGuard
;
335 // Use a simple but slow solution for now. Optimize later.
337 // Iterate over all the parent's children and search for this object.
338 css::uno::Reference
<css::accessibility::XAccessible
> xParent(getAccessibleParent());
341 Reference
< XAccessibleContext
> xParentContext( xParent
->getAccessibleContext() );
342 if( xParentContext
.is() )
344 sal_Int32 nChildCount
= xParentContext
->getAccessibleChildCount();
345 for( sal_Int32 i
= 0 ; i
< nChildCount
; ++i
)
347 Reference
< XAccessible
> xChild( xParentContext
->getAccessibleChild( i
) );
350 Reference
< XAccessibleContext
> xChildContext
= xChild
->getAccessibleContext();
351 if( xChildContext
== static_cast<XAccessibleContext
*>(this) )
358 // Return -1 to indicate that this object's parent does not know about the
364 sal_Int16 SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleRole()
366 return AccessibleRole::PANEL
;
370 OUString SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleDescription()
372 ::SolarMutexGuard aGuard
;
373 return msDescription
;
377 OUString SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleName()
379 ::SolarMutexGuard aGuard
;
384 /** Return empty reference to indicate that the relation set is not
387 Reference
< XAccessibleRelationSet
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleRelationSet()
389 return Reference
< XAccessibleRelationSet
>();
393 Reference
< XAccessibleStateSet
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleStateSet()
395 ::SolarMutexGuard aGuard
;
397 utl::AccessibleStateSetHelper
* pStateSetHelper
= new utl::AccessibleStateSetHelper
;
399 if ( rBHelper
.bDisposed
|| mbDisposed
)
401 pStateSetHelper
->AddState( AccessibleStateType::DEFUNC
);
405 pStateSetHelper
->AddState( AccessibleStateType::FOCUSABLE
);
406 if( mpControl
->HasFocus() )
407 pStateSetHelper
->AddState( AccessibleStateType::FOCUSED
);
408 pStateSetHelper
->AddState( AccessibleStateType::OPAQUE
);
409 pStateSetHelper
->AddState( AccessibleStateType::SHOWING
);
410 pStateSetHelper
->AddState( AccessibleStateType::VISIBLE
);
413 return pStateSetHelper
;
417 lang::Locale SAL_CALL
SvxGraphCtrlAccessibleContext::getLocale()
419 ::SolarMutexGuard aGuard
;
421 css::uno::Reference
<css::accessibility::XAccessible
> xParent(getAccessibleParent());
424 Reference
< XAccessibleContext
> xParentContext( xParent
->getAccessibleContext() );
425 if( xParentContext
.is() )
426 return xParentContext
->getLocale();
429 // No parent. Therefore throw exception to indicate this cluelessness.
430 throw IllegalAccessibleComponentStateException();
433 // XAccessibleEventListener
434 void SAL_CALL
SvxGraphCtrlAccessibleContext::addAccessibleEventListener( const Reference
< XAccessibleEventListener
>& xListener
)
438 ::SolarMutexGuard aGuard
;
440 mnClientId
= comphelper::AccessibleEventNotifier::registerClient( );
441 comphelper::AccessibleEventNotifier::addEventListener( mnClientId
, xListener
);
446 void SAL_CALL
SvxGraphCtrlAccessibleContext::removeAccessibleEventListener( const Reference
< XAccessibleEventListener
>& xListener
)
451 ::SolarMutexGuard aGuard
;
453 sal_Int32 nListenerCount
= comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, xListener
);
454 if ( !nListenerCount
)
456 // no listeners anymore
457 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
458 // and at least to us not firing any events anymore, in case somebody calls
459 // NotifyAccessibleEvent, again
460 comphelper::AccessibleEventNotifier::revokeClient( mnClientId
);
465 void SAL_CALL
SvxGraphCtrlAccessibleContext::grabFocus()
467 ::SolarMutexGuard aGuard
;
469 if( nullptr == mpControl
)
470 throw DisposedException();
472 mpControl
->GrabFocus();
475 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getForeground()
477 svtools::ColorConfig aColorConfig
;
478 Color nColor
= aColorConfig
.GetColorValue( svtools::FONTCOLOR
).nColor
;
479 return static_cast<sal_Int32
>(nColor
);
482 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getBackground()
484 Color nColor
= Application::GetSettings().GetStyleSettings().GetWindowColor();
485 return static_cast<sal_Int32
>(nColor
);
489 OUString SAL_CALL
SvxGraphCtrlAccessibleContext::getImplementationName()
491 return "com.sun.star.comp.ui.SvxGraphCtrlAccessibleContext";
494 sal_Bool SAL_CALL
SvxGraphCtrlAccessibleContext::supportsService( const OUString
& sServiceName
)
496 return cppu::supportsService(this, sServiceName
);
499 Sequence
< OUString
> SAL_CALL
SvxGraphCtrlAccessibleContext::getSupportedServiceNames()
501 return { "com.sun.star.accessibility.Accessible",
502 "com.sun.star.accessibility.AccessibleContext",
503 "com.sun.star.drawing.AccessibleGraphControl" };
507 Sequence
<sal_Int8
> SAL_CALL
SvxGraphCtrlAccessibleContext::getImplementationId()
509 return css::uno::Sequence
<sal_Int8
>();
513 OUString
SvxGraphCtrlAccessibleContext::getServiceName()
515 return "com.sun.star.accessibility.AccessibleContext";
518 // XAccessibleSelection
519 void SAL_CALL
SvxGraphCtrlAccessibleContext::selectAccessibleChild( sal_Int32 nIndex
)
521 ::SolarMutexGuard aGuard
;
523 if( nullptr == mpView
)
524 throw DisposedException();
526 SdrObject
* pObj
= getSdrObject( nIndex
);
529 mpView
->MarkObj( pObj
, mpView
->GetSdrPageView());
533 sal_Bool SAL_CALL
SvxGraphCtrlAccessibleContext::isAccessibleChildSelected( sal_Int32 nIndex
)
535 ::SolarMutexGuard aGuard
;
537 if( nullptr == mpView
)
538 throw DisposedException();
540 return mpView
->IsObjMarked( getSdrObject( nIndex
) );
544 void SAL_CALL
SvxGraphCtrlAccessibleContext::clearAccessibleSelection()
546 ::SolarMutexGuard aGuard
;
548 if( nullptr == mpView
)
549 throw DisposedException();
551 mpView
->UnmarkAllObj();
555 void SAL_CALL
SvxGraphCtrlAccessibleContext::selectAllAccessibleChildren()
557 ::SolarMutexGuard aGuard
;
559 if( nullptr == mpView
)
560 throw DisposedException();
562 mpView
->MarkAllObj();
566 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getSelectedAccessibleChildCount()
568 ::SolarMutexGuard aGuard
;
570 if( nullptr == mpView
)
571 throw DisposedException();
573 const SdrMarkList
& rList
= mpView
->GetMarkedObjectList();
574 return static_cast<sal_Int32
>(rList
.GetMarkCount());
578 Reference
< XAccessible
> SAL_CALL
SvxGraphCtrlAccessibleContext::getSelectedAccessibleChild( sal_Int32 nIndex
)
580 ::SolarMutexGuard aGuard
;
582 checkChildIndexOnSelection( nIndex
);
584 Reference
< XAccessible
> xAccessible
;
586 const SdrMarkList
& rList
= mpView
->GetMarkedObjectList();
587 SdrObject
* pObj
= rList
.GetMark(static_cast<size_t>(nIndex
))->GetMarkedSdrObj();
589 xAccessible
= getAccessible( pObj
);
595 void SAL_CALL
SvxGraphCtrlAccessibleContext::deselectAccessibleChild( sal_Int32 nIndex
)
597 ::SolarMutexGuard aGuard
;
599 checkChildIndexOnSelection( nIndex
);
604 const SdrMarkList
& rList
= mpView
->GetMarkedObjectList();
606 SdrObject
* pObj
= getSdrObject( nIndex
);
610 SdrMarkList
aRefList( rList
);
612 SdrPageView
* pPV
= mpView
->GetSdrPageView();
613 mpView
->UnmarkAllObj( pPV
);
615 const size_t nCount
= aRefList
.GetMarkCount();
616 for( size_t nMark
= 0; nMark
< nCount
; ++nMark
)
618 if( aRefList
.GetMark(nMark
)->GetMarkedSdrObj() != pObj
)
619 mpView
->MarkObj( aRefList
.GetMark(nMark
)->GetMarkedSdrObj(), pPV
);
624 void SvxGraphCtrlAccessibleContext::checkChildIndexOnSelection( tools::Long nIndex
)
626 if( nIndex
< 0 || nIndex
>= getSelectedAccessibleChildCount() )
627 throw lang::IndexOutOfBoundsException();
631 /** Replace the model, page, and view pointers by the ones provided
632 (explicitly and implicitly).
634 void SvxGraphCtrlAccessibleContext::setModelAndView (
638 ::SolarMutexGuard aGuard
;
641 if (mpModel
!= nullptr)
642 mpPage
= mpModel
->GetPage( 0 );
645 if (mpModel
== nullptr || mpPage
== nullptr || mpView
== nullptr)
649 // Set all the pointers to NULL just in case they are used as
656 maTreeInfo
.SetSdrView (mpView
);
660 void SAL_CALL
SvxGraphCtrlAccessibleContext::disposing()
662 ::SolarMutexGuard aGuard
;
669 mpControl
= nullptr; // object dies with representation
674 for (const auto& rEntry
: mxShapes
)
676 rtl::Reference
<XAccessible
> pAcc(rEntry
.second
.get());
677 Reference
< XComponent
> xComp( pAcc
.get(), UNO_QUERY
);
685 // Send a disposing to all listeners.
688 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId
, *this );
693 void SvxGraphCtrlAccessibleContext::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
695 if (rHint
.GetId() == SfxHintId::ThisIsAnSdrHint
)
697 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>( &rHint
);
698 switch( pSdrHint
->GetKind() )
700 case SdrHintKind::ObjectChange
:
702 ShapesMapType::iterator iter
= mxShapes
.find( pSdrHint
->GetObject() );
704 if( iter
!= mxShapes
.end() )
706 // if we already have one, return it
707 rtl::Reference
<AccessibleShape
> pShape((*iter
).second
);
710 pShape
->CommitChange( AccessibleEventId::VISIBLE_DATA_CHANGED
, uno::Any(), uno::Any() );
715 case SdrHintKind::ObjectInserted
:
716 CommitChange( AccessibleEventId::CHILD
, makeAny( getAccessible( pSdrHint
->GetObject() ) ) , uno::Any());
718 case SdrHintKind::ObjectRemoved
:
719 CommitChange( AccessibleEventId::CHILD
, uno::Any(), makeAny( getAccessible( pSdrHint
->GetObject() ) ) );
721 case SdrHintKind::ModelCleared
:
730 // Has our SdDrawDocument just died?
731 if(rHint
.GetId() == SfxHintId::Dying
)
738 // IAccessibleViewforwarder
739 tools::Rectangle
SvxGraphCtrlAccessibleContext::GetVisibleArea() const
741 tools::Rectangle aVisArea
;
743 if( mpView
&& mpView
->PaintWindowCount())
745 SdrPaintWindow
* pPaintWindow
= mpView
->GetPaintWindow(0);
746 aVisArea
= pPaintWindow
->GetVisibleArea();
752 Point
SvxGraphCtrlAccessibleContext::LogicToPixel (const Point
& rPoint
) const
756 return mpControl
->GetDrawingArea()->get_ref_device().LogicToPixel (rPoint
) + mpControl
->GetPositionInDialog();
764 Size
SvxGraphCtrlAccessibleContext::LogicToPixel (const Size
& rSize
) const
767 return mpControl
->GetDrawingArea()->get_ref_device().LogicToPixel(rSize
);
772 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */