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 <vcl/window.hxx>
31 #include <o3tl/safeint.hxx>
32 #include <osl/mutex.hxx>
33 #include <tools/gen.hxx>
34 #include <svtools/colorcfg.hxx>
35 #include <comphelper/accessibleeventnotifier.hxx>
36 #include <svx/sdrpaintwindow.hxx>
38 #include <svx/ShapeTypeHandler.hxx>
39 #include <svx/AccessibleShapeInfo.hxx>
40 #include <GraphCtlAccessibleContext.hxx>
41 #include <svx/graphctl.hxx>
42 #include <svx/strings.hrc>
43 #include <svx/svdpage.hxx>
44 #include <svx/dialmgr.hxx>
45 #include <svx/sdrhittesthelper.hxx>
48 using namespace ::cppu
;
49 using namespace ::osl
;
50 using namespace ::accessibility
;
51 using namespace ::com::sun::star
;
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::drawing
;
54 using namespace ::com::sun::star::lang
;
55 using namespace ::com::sun::star::accessibility
;
58 /** initialize this component and set default values */
59 SvxGraphCtrlAccessibleContext::SvxGraphCtrlAccessibleContext(
62 SvxGraphCtrlAccessibleContext_Base( m_aMutex
),
70 if (mpControl
!= nullptr)
72 mpModel
= mpControl
->GetSdrModel();
73 if (mpModel
!= nullptr)
74 mpPage
= mpModel
->GetPage( 0 );
75 mpView
= mpControl
->GetSdrView();
77 if( mpModel
== nullptr || mpPage
== nullptr || mpView
== nullptr )
80 // Set all the pointers to NULL just in case they are used as
89 ::SolarMutexGuard aSolarGuard
;
90 msName
= SvxResId( RID_SVXSTR_GRAPHCTRL_ACC_NAME
);
91 msDescription
= SvxResId( RID_SVXSTR_GRAPHCTRL_ACC_DESCRIPTION
);
94 maTreeInfo
.SetSdrView( mpView
);
95 maTreeInfo
.SetWindow(mpControl
->GetDrawingArea()->get_ref_device().GetOwnerWindow());
96 maTreeInfo
.SetViewForwarder( this );
100 /** on destruction, this component is disposed and all dispose listeners
101 are called, except if this component was already disposed */
102 SvxGraphCtrlAccessibleContext::~SvxGraphCtrlAccessibleContext()
108 /** returns the XAccessible interface for a given SdrObject.
109 Multiple calls for the same SdrObject return the same XAccessible.
111 Reference
< XAccessible
> SvxGraphCtrlAccessibleContext::getAccessible( const SdrObject
* pObj
)
113 Reference
<XAccessible
> xAccessibleShape
;
117 // see if we already created an XAccessible for the given SdrObject
118 ShapesMapType::const_iterator iter
= mxShapes
.find( pObj
);
120 if( iter
!= mxShapes
.end() )
122 // if we already have one, return it
123 xAccessibleShape
= (*iter
).second
.get();
127 // create a new one and remember in our internal map
128 Reference
< XShape
> xShape( Reference
< XShape
>::query( const_cast<SdrObject
*>(pObj
)->getUnoShape() ) );
130 css::uno::Reference
<css::accessibility::XAccessible
> xParent(getAccessibleParent());
131 AccessibleShapeInfo
aShapeInfo (xShape
,xParent
);
132 // Create accessible object that corresponds to the descriptor's shape.
133 rtl::Reference
<AccessibleShape
> pAcc(ShapeTypeHandler::Instance().CreateAccessibleObject(
134 aShapeInfo
, maTreeInfo
));
135 xAccessibleShape
= pAcc
.get();
140 mxShapes
[pObj
] = pAcc
;
142 // Create event and inform listeners of the object creation.
143 CommitChange( AccessibleEventId::CHILD
, makeAny( xAccessibleShape
), makeAny( Reference
<XAccessible
>() ) );
147 return xAccessibleShape
;
151 Reference
< XAccessibleContext
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleContext()
156 // XAccessibleComponent
157 sal_Bool SAL_CALL
SvxGraphCtrlAccessibleContext::containsPoint( const awt::Point
& rPoint
)
159 // no guard -> done in getSize()
160 awt::Size
aSize (getSize());
161 return (rPoint
.X
>= 0)
162 && (rPoint
.X
< aSize
.Width
)
164 && (rPoint
.Y
< aSize
.Height
);
168 Reference
< XAccessible
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleAtPoint( const awt::Point
& rPoint
)
170 ::osl::MutexGuard
aGuard( m_aMutex
);
172 Reference
< XAccessible
> xAccessible
;
176 throw DisposedException();
179 Point
aPnt( rPoint
.X
, rPoint
.Y
);
180 aPnt
= mpControl
->GetDrawingArea()->get_ref_device().PixelToLogic(aPnt
);
182 SdrObject
* pObj
= nullptr;
184 if(mpView
&& mpView
->GetSdrPageView())
186 pObj
= SdrObjListPrimitiveHit(*mpPage
, aPnt
, 1, *mpView
->GetSdrPageView(), nullptr, false);
190 xAccessible
= getAccessible( pObj
);
195 awt::Rectangle SAL_CALL
SvxGraphCtrlAccessibleContext::getBounds()
197 const SolarMutexGuard aSolarGuard
;
199 if (nullptr == mpControl
)
200 throw DisposedException();
203 const Size
aOutSize( mpControl
->GetOutputSizePixel() );
206 aRet
.X
= aOutPos
.X();
207 aRet
.Y
= aOutPos
.Y();
208 aRet
.Width
= aOutSize
.Width();
209 aRet
.Height
= aOutSize
.Height();
214 awt::Point SAL_CALL
SvxGraphCtrlAccessibleContext::getLocation()
216 const SolarMutexGuard aSolarGuard
;
218 if (nullptr == mpControl
)
219 throw DisposedException();
221 const awt::Rectangle
aRect( getBounds() );
230 awt::Point SAL_CALL
SvxGraphCtrlAccessibleContext::getLocationOnScreen()
232 const SolarMutexGuard aSolarGuard
;
234 if (nullptr == mpControl
)
235 throw DisposedException();
237 awt::Point
aScreenLoc(0, 0);
239 auto xParent(getAccessibleParent());
242 css::uno::Reference
<css::accessibility::XAccessibleContext
> xParentContext(xParent
->getAccessibleContext());
243 css::uno::Reference
<css::accessibility::XAccessibleComponent
> xParentComponent(xParentContext
, css::uno::UNO_QUERY
);
244 OSL_ENSURE( xParentComponent
.is(), "ValueSetAcc::getLocationOnScreen: no parent component!" );
245 if ( xParentComponent
.is() )
247 awt::Point
aParentScreenLoc( xParentComponent
->getLocationOnScreen() );
248 awt::Point
aOwnRelativeLoc( getLocation() );
249 aScreenLoc
.X
= aParentScreenLoc
.X
+ aOwnRelativeLoc
.X
;
250 aScreenLoc
.Y
= aParentScreenLoc
.Y
+ aOwnRelativeLoc
.Y
;
257 awt::Size SAL_CALL
SvxGraphCtrlAccessibleContext::getSize()
259 const SolarMutexGuard aSolarGuard
;
261 if (nullptr == mpControl
)
262 throw DisposedException();
264 const awt::Rectangle
aRect( getBounds() );
267 aRet
.Width
= aRect
.Width
;
268 aRet
.Height
= aRect
.Height
;
273 // XAccessibleContext
274 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleChildCount()
276 ::SolarMutexGuard aGuard
;
278 if( nullptr == mpPage
)
279 throw DisposedException();
281 return mpPage
->GetObjCount();
285 /** returns the SdrObject at index nIndex from the model of this graph */
286 SdrObject
* SvxGraphCtrlAccessibleContext::getSdrObject( sal_Int32 nIndex
)
288 ::SolarMutexGuard aGuard
;
290 if( nullptr == mpPage
)
291 throw DisposedException();
293 if( (nIndex
< 0) || ( o3tl::make_unsigned(nIndex
) >= mpPage
->GetObjCount() ) )
294 throw lang::IndexOutOfBoundsException();
296 return mpPage
->GetObj( nIndex
);
300 /** sends an AccessibleEventObject to all added XAccessibleEventListeners */
301 void SvxGraphCtrlAccessibleContext::CommitChange (
303 const uno::Any
& rNewValue
,
304 const uno::Any
& rOldValue
)
306 AccessibleEventObject
aEvent (
307 static_cast<uno::XWeak
*>(this),
313 comphelper::AccessibleEventNotifier::addEvent( mnClientId
, aEvent
);
316 Reference
< XAccessible
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleChild( sal_Int32 nIndex
)
318 ::SolarMutexGuard aGuard
;
320 return getAccessible( getSdrObject( nIndex
) );
323 Reference
< XAccessible
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleParent()
325 ::SolarMutexGuard aGuard
;
327 if( nullptr == mpControl
)
328 throw DisposedException();
330 return mpControl
->GetDrawingArea()->get_accessible_parent();
333 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleIndexInParent()
335 ::SolarMutexGuard aGuard
;
336 // Use a simple but slow solution for now. Optimize later.
338 // Iterate over all the parent's children and search for this object.
339 css::uno::Reference
<css::accessibility::XAccessible
> xParent(getAccessibleParent());
342 Reference
< XAccessibleContext
> xParentContext( xParent
->getAccessibleContext() );
343 if( xParentContext
.is() )
345 sal_Int32 nChildCount
= xParentContext
->getAccessibleChildCount();
346 for( sal_Int32 i
= 0 ; i
< nChildCount
; ++i
)
348 Reference
< XAccessible
> xChild( xParentContext
->getAccessibleChild( i
) );
351 Reference
< XAccessibleContext
> xChildContext
= xChild
->getAccessibleContext();
352 if( xChildContext
== static_cast<XAccessibleContext
*>(this) )
359 // Return -1 to indicate that this object's parent does not know about the
365 sal_Int16 SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleRole()
367 return AccessibleRole::PANEL
;
371 OUString SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleDescription()
373 ::SolarMutexGuard aGuard
;
374 return msDescription
;
378 OUString SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleName()
380 ::SolarMutexGuard aGuard
;
385 /** Return empty reference to indicate that the relation set is not
388 Reference
< XAccessibleRelationSet
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleRelationSet()
390 return Reference
< XAccessibleRelationSet
>();
394 Reference
< XAccessibleStateSet
> SAL_CALL
SvxGraphCtrlAccessibleContext::getAccessibleStateSet()
396 ::SolarMutexGuard aGuard
;
398 rtl::Reference
<utl::AccessibleStateSetHelper
> pStateSetHelper
= new utl::AccessibleStateSetHelper
;
400 if ( rBHelper
.bDisposed
|| mbDisposed
)
402 pStateSetHelper
->AddState( AccessibleStateType::DEFUNC
);
406 pStateSetHelper
->AddState( AccessibleStateType::FOCUSABLE
);
407 if( mpControl
->HasFocus() )
408 pStateSetHelper
->AddState( AccessibleStateType::FOCUSED
);
409 pStateSetHelper
->AddState( AccessibleStateType::OPAQUE
);
410 pStateSetHelper
->AddState( AccessibleStateType::SHOWING
);
411 pStateSetHelper
->AddState( AccessibleStateType::VISIBLE
);
414 return pStateSetHelper
;
418 lang::Locale SAL_CALL
SvxGraphCtrlAccessibleContext::getLocale()
420 ::SolarMutexGuard aGuard
;
422 css::uno::Reference
<css::accessibility::XAccessible
> xParent(getAccessibleParent());
425 Reference
< XAccessibleContext
> xParentContext( xParent
->getAccessibleContext() );
426 if( xParentContext
.is() )
427 return xParentContext
->getLocale();
430 // No parent. Therefore throw exception to indicate this cluelessness.
431 throw IllegalAccessibleComponentStateException();
434 // XAccessibleEventListener
435 void SAL_CALL
SvxGraphCtrlAccessibleContext::addAccessibleEventListener( const Reference
< XAccessibleEventListener
>& xListener
)
439 ::SolarMutexGuard aGuard
;
441 mnClientId
= comphelper::AccessibleEventNotifier::registerClient( );
442 comphelper::AccessibleEventNotifier::addEventListener( mnClientId
, xListener
);
447 void SAL_CALL
SvxGraphCtrlAccessibleContext::removeAccessibleEventListener( const Reference
< XAccessibleEventListener
>& xListener
)
452 ::SolarMutexGuard aGuard
;
454 sal_Int32 nListenerCount
= comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, xListener
);
455 if ( !nListenerCount
)
457 // no listeners anymore
458 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
459 // and at least to us not firing any events anymore, in case somebody calls
460 // NotifyAccessibleEvent, again
461 comphelper::AccessibleEventNotifier::revokeClient( mnClientId
);
466 void SAL_CALL
SvxGraphCtrlAccessibleContext::grabFocus()
468 ::SolarMutexGuard aGuard
;
470 if( nullptr == mpControl
)
471 throw DisposedException();
473 mpControl
->GrabFocus();
476 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getForeground()
478 svtools::ColorConfig aColorConfig
;
479 Color nColor
= aColorConfig
.GetColorValue( svtools::FONTCOLOR
).nColor
;
480 return static_cast<sal_Int32
>(nColor
);
483 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getBackground()
485 Color nColor
= Application::GetSettings().GetStyleSettings().GetWindowColor();
486 return static_cast<sal_Int32
>(nColor
);
490 OUString SAL_CALL
SvxGraphCtrlAccessibleContext::getImplementationName()
492 return "com.sun.star.comp.ui.SvxGraphCtrlAccessibleContext";
495 sal_Bool SAL_CALL
SvxGraphCtrlAccessibleContext::supportsService( const OUString
& sServiceName
)
497 return cppu::supportsService(this, sServiceName
);
500 Sequence
< OUString
> SAL_CALL
SvxGraphCtrlAccessibleContext::getSupportedServiceNames()
502 return { "com.sun.star.accessibility.Accessible",
503 "com.sun.star.accessibility.AccessibleContext",
504 "com.sun.star.drawing.AccessibleGraphControl" };
508 Sequence
<sal_Int8
> SAL_CALL
SvxGraphCtrlAccessibleContext::getImplementationId()
510 return css::uno::Sequence
<sal_Int8
>();
514 OUString
SvxGraphCtrlAccessibleContext::getServiceName()
516 return "com.sun.star.accessibility.AccessibleContext";
519 // XAccessibleSelection
520 void SAL_CALL
SvxGraphCtrlAccessibleContext::selectAccessibleChild( sal_Int32 nIndex
)
522 ::SolarMutexGuard aGuard
;
524 if( nullptr == mpView
)
525 throw DisposedException();
527 SdrObject
* pObj
= getSdrObject( nIndex
);
530 mpView
->MarkObj( pObj
, mpView
->GetSdrPageView());
534 sal_Bool SAL_CALL
SvxGraphCtrlAccessibleContext::isAccessibleChildSelected( sal_Int32 nIndex
)
536 ::SolarMutexGuard aGuard
;
538 if( nullptr == mpView
)
539 throw DisposedException();
541 return mpView
->IsObjMarked( getSdrObject( nIndex
) );
545 void SAL_CALL
SvxGraphCtrlAccessibleContext::clearAccessibleSelection()
547 ::SolarMutexGuard aGuard
;
549 if( nullptr == mpView
)
550 throw DisposedException();
552 mpView
->UnmarkAllObj();
556 void SAL_CALL
SvxGraphCtrlAccessibleContext::selectAllAccessibleChildren()
558 ::SolarMutexGuard aGuard
;
560 if( nullptr == mpView
)
561 throw DisposedException();
563 mpView
->MarkAllObj();
567 sal_Int32 SAL_CALL
SvxGraphCtrlAccessibleContext::getSelectedAccessibleChildCount()
569 ::SolarMutexGuard aGuard
;
571 if( nullptr == mpView
)
572 throw DisposedException();
574 const SdrMarkList
& rList
= mpView
->GetMarkedObjectList();
575 return static_cast<sal_Int32
>(rList
.GetMarkCount());
579 Reference
< XAccessible
> SAL_CALL
SvxGraphCtrlAccessibleContext::getSelectedAccessibleChild( sal_Int32 nIndex
)
581 ::SolarMutexGuard aGuard
;
583 checkChildIndexOnSelection( nIndex
);
585 Reference
< XAccessible
> xAccessible
;
587 const SdrMarkList
& rList
= mpView
->GetMarkedObjectList();
588 SdrObject
* pObj
= rList
.GetMark(static_cast<size_t>(nIndex
))->GetMarkedSdrObj();
590 xAccessible
= getAccessible( pObj
);
596 void SAL_CALL
SvxGraphCtrlAccessibleContext::deselectAccessibleChild( sal_Int32 nIndex
)
598 ::SolarMutexGuard aGuard
;
600 checkChildIndexOnSelection( nIndex
);
605 const SdrMarkList
& rList
= mpView
->GetMarkedObjectList();
607 SdrObject
* pObj
= getSdrObject( nIndex
);
611 SdrMarkList
aRefList( rList
);
613 SdrPageView
* pPV
= mpView
->GetSdrPageView();
614 mpView
->UnmarkAllObj( pPV
);
616 const size_t nCount
= aRefList
.GetMarkCount();
617 for( size_t nMark
= 0; nMark
< nCount
; ++nMark
)
619 if( aRefList
.GetMark(nMark
)->GetMarkedSdrObj() != pObj
)
620 mpView
->MarkObj( aRefList
.GetMark(nMark
)->GetMarkedSdrObj(), pPV
);
625 void SvxGraphCtrlAccessibleContext::checkChildIndexOnSelection( tools::Long nIndex
)
627 if( nIndex
< 0 || nIndex
>= getSelectedAccessibleChildCount() )
628 throw lang::IndexOutOfBoundsException();
632 /** Replace the model, page, and view pointers by the ones provided
633 (explicitly and implicitly).
635 void SvxGraphCtrlAccessibleContext::setModelAndView (
639 ::SolarMutexGuard aGuard
;
642 if (mpModel
!= nullptr)
643 mpPage
= mpModel
->GetPage( 0 );
646 if (mpModel
== nullptr || mpPage
== nullptr || mpView
== nullptr)
650 // Set all the pointers to NULL just in case they are used as
657 maTreeInfo
.SetSdrView (mpView
);
661 void SAL_CALL
SvxGraphCtrlAccessibleContext::disposing()
663 ::SolarMutexGuard aGuard
;
670 mpControl
= nullptr; // object dies with representation
675 for (const auto& rEntry
: mxShapes
)
677 rtl::Reference
<XAccessible
> pAcc(rEntry
.second
);
678 Reference
< XComponent
> xComp( pAcc
.get(), UNO_QUERY
);
686 // Send a disposing to all listeners.
689 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId
, *this );
694 void SvxGraphCtrlAccessibleContext::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
696 if (rHint
.GetId() == SfxHintId::ThisIsAnSdrHint
)
698 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>( &rHint
);
699 switch( pSdrHint
->GetKind() )
701 case SdrHintKind::ObjectChange
:
703 ShapesMapType::iterator iter
= mxShapes
.find( pSdrHint
->GetObject() );
705 if( iter
!= mxShapes
.end() )
707 // if we already have one, return it
708 rtl::Reference
<AccessibleShape
> pShape((*iter
).second
);
711 pShape
->CommitChange( AccessibleEventId::VISIBLE_DATA_CHANGED
, uno::Any(), uno::Any() );
716 case SdrHintKind::ObjectInserted
:
717 CommitChange( AccessibleEventId::CHILD
, makeAny( getAccessible( pSdrHint
->GetObject() ) ) , uno::Any());
719 case SdrHintKind::ObjectRemoved
:
720 CommitChange( AccessibleEventId::CHILD
, uno::Any(), makeAny( getAccessible( pSdrHint
->GetObject() ) ) );
722 case SdrHintKind::ModelCleared
:
731 // Has our SdDrawDocument just died?
732 if(rHint
.GetId() == SfxHintId::Dying
)
739 // IAccessibleViewforwarder
740 tools::Rectangle
SvxGraphCtrlAccessibleContext::GetVisibleArea() const
742 tools::Rectangle aVisArea
;
744 if( mpView
&& mpView
->PaintWindowCount())
746 SdrPaintWindow
* pPaintWindow
= mpView
->GetPaintWindow(0);
747 aVisArea
= pPaintWindow
->GetVisibleArea();
753 Point
SvxGraphCtrlAccessibleContext::LogicToPixel (const Point
& rPoint
) const
757 return mpControl
->GetDrawingArea()->get_ref_device().LogicToPixel (rPoint
) + mpControl
->GetPositionInDialog();
765 Size
SvxGraphCtrlAccessibleContext::LogicToPixel (const Size
& rSize
) const
768 return mpControl
->GetDrawingArea()->get_ref_device().LogicToPixel(rSize
);
773 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */