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 <svxrectctaccessiblecontext.hxx>
21 #include <com/sun/star/accessibility/AccessibleRole.hpp>
22 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
23 #include <unotools/accessiblestatesethelper.hxx>
24 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
25 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
26 #include <toolkit/helper/convert.hxx>
27 #include <vcl/svapp.hxx>
28 #include <osl/mutex.hxx>
29 #include <tools/debug.hxx>
30 #include <tools/gen.hxx>
31 #include <sal/log.hxx>
32 #include <vcl/settings.hxx>
33 #include <svx/strings.hrc>
34 #include <svx/dlgctrl.hxx>
35 #include <svx/dialmgr.hxx>
36 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
37 #include <unotools/accessiblerelationsethelper.hxx>
39 using namespace ::cppu
;
40 using namespace ::osl
;
41 using namespace ::com::sun::star
;
42 using namespace ::com::sun::star::uno
;
43 using namespace ::com::sun::star::accessibility
;
45 using namespace ::com::sun::star::lang
;
47 #define MAX_NUM_OF_CHILDREN 9
48 #define NOCHILDSELECTED -1
53 struct ChildIndexToPointData
55 const char* pResIdName
;
56 const char* pResIdDescr
;
62 static const ChildIndexToPointData
* IndexToPoint( tools::Long nIndex
)
64 DBG_ASSERT( nIndex
< 9 && nIndex
>= 0, "-IndexToPoint(): invalid child index! You have been warned..." );
66 // corners are counted from left to right and top to bottom
67 static const ChildIndexToPointData pCornerData
[] =
69 { RID_SVXSTR_RECTCTL_ACC_CHLD_LT
, RID_SVXSTR_RECTCTL_ACC_CHLD_LT
, RectPoint::LT
}, // 0
70 { RID_SVXSTR_RECTCTL_ACC_CHLD_MT
, RID_SVXSTR_RECTCTL_ACC_CHLD_MT
, RectPoint::MT
}, // 1
71 { RID_SVXSTR_RECTCTL_ACC_CHLD_RT
, RID_SVXSTR_RECTCTL_ACC_CHLD_RT
, RectPoint::RT
}, // 2
72 { RID_SVXSTR_RECTCTL_ACC_CHLD_LM
, RID_SVXSTR_RECTCTL_ACC_CHLD_LM
, RectPoint::LM
}, // 3
73 { RID_SVXSTR_RECTCTL_ACC_CHLD_MM
, RID_SVXSTR_RECTCTL_ACC_CHLD_MM
, RectPoint::MM
}, // 4
74 { RID_SVXSTR_RECTCTL_ACC_CHLD_RM
, RID_SVXSTR_RECTCTL_ACC_CHLD_RM
, RectPoint::RM
}, // 5
75 { RID_SVXSTR_RECTCTL_ACC_CHLD_LB
, RID_SVXSTR_RECTCTL_ACC_CHLD_LB
, RectPoint::LB
}, // 6
76 { RID_SVXSTR_RECTCTL_ACC_CHLD_MB
, RID_SVXSTR_RECTCTL_ACC_CHLD_MB
, RectPoint::MB
}, // 7
77 { RID_SVXSTR_RECTCTL_ACC_CHLD_RB
, RID_SVXSTR_RECTCTL_ACC_CHLD_RB
, RectPoint::RB
} // 8
80 return pCornerData
+ nIndex
;
84 static tools::Long
PointToIndex( RectPoint ePoint
)
86 tools::Long
nRet( static_cast<tools::Long
>(ePoint
) );
88 // corners are counted from left to right and top to bottom
89 DBG_ASSERT( int(RectPoint::LT
) == 0 && int(RectPoint::MT
) == 1 && int(RectPoint::RT
) == 2 && int(RectPoint::LM
) == 3 && int(RectPoint::MM
) == 4 && int(RectPoint::RM
) == 5 &&
90 int(RectPoint::LB
) == 6 && int(RectPoint::MB
) == 7 && int(RectPoint::RB
) == 8, "*PointToIndex(): unexpected enum value!" );
92 nRet
= static_cast<tools::Long
>(ePoint
);
97 SvxRectCtlAccessibleContext::SvxRectCtlAccessibleContext(SvxRectCtl
* pRepr
)
99 , mnSelectedChild(NOCHILDSELECTED
)
102 ::SolarMutexGuard aSolarGuard
;
103 msName
= SvxResId( RID_SVXSTR_RECTCTL_ACC_CORN_NAME
);
104 msDescription
= SvxResId( RID_SVXSTR_RECTCTL_ACC_CORN_DESCR
);
107 mvChildren
.resize(MAX_NUM_OF_CHILDREN
);
110 SvxRectCtlAccessibleContext::~SvxRectCtlAccessibleContext()
115 IMPLEMENT_FORWARD_XINTERFACE2( SvxRectCtlAccessibleContext
, OAccessibleSelectionHelper
, OAccessibleHelper_Base
)
116 IMPLEMENT_FORWARD_XTYPEPROVIDER2( SvxRectCtlAccessibleContext
, OAccessibleSelectionHelper
, OAccessibleHelper_Base
)
118 Reference
< XAccessible
> SAL_CALL
SvxRectCtlAccessibleContext::getAccessibleAtPoint( const awt::Point
& rPoint
)
120 ::osl::MutexGuard
aGuard( m_aMutex
);
122 Reference
< XAccessible
> xRet
;
124 tools::Long nChild
= mpRepr
? PointToIndex(mpRepr
->GetApproxRPFromPixPt(rPoint
)) : NOCHILDSELECTED
;
126 if (nChild
!= NOCHILDSELECTED
)
127 xRet
= getAccessibleChild( nChild
);
132 // XAccessibleContext
133 sal_Int32 SAL_CALL
SvxRectCtlAccessibleContext::getAccessibleChildCount()
135 ::osl::MutexGuard
aGuard( m_aMutex
);
137 return SvxRectCtl::NO_CHILDREN
;
140 Reference
< XAccessible
> SAL_CALL
SvxRectCtlAccessibleContext::getAccessibleChild( sal_Int32 nIndex
)
142 checkChildIndex( nIndex
);
144 Reference
< XAccessible
> xChild(mvChildren
[ nIndex
]);
147 ::SolarMutexGuard aSolarGuard
;
149 ::osl::MutexGuard
aGuard( m_aMutex
);
151 xChild
= mvChildren
[ nIndex
].get();
153 if (!xChild
.is() && mpRepr
)
155 const ChildIndexToPointData
* p
= IndexToPoint( nIndex
);
156 OUString
aName(SvxResId(p
->pResIdName
));
157 OUString
aDescr(SvxResId(p
->pResIdDescr
));
159 tools::Rectangle
aFocusRect( mpRepr
->CalculateFocusRectangle( p
->ePoint
) );
161 rtl::Reference
<SvxRectCtlChildAccessibleContext
> pChild
= new SvxRectCtlChildAccessibleContext(this, aName
,
162 aDescr
, aFocusRect
, nIndex
);
163 mvChildren
[ nIndex
] = pChild
;
167 if( mnSelectedChild
== nIndex
)
168 pChild
->setStateChecked( true );
175 Reference
< XAccessible
> SAL_CALL
SvxRectCtlAccessibleContext::getAccessibleParent()
177 ::osl::MutexGuard
aGuard( m_aMutex
);
179 return mpRepr
->getAccessibleParent();
180 return uno::Reference
<css::accessibility::XAccessible
>();
183 sal_Int16 SAL_CALL
SvxRectCtlAccessibleContext::getAccessibleRole()
185 return AccessibleRole::PANEL
;
188 OUString SAL_CALL
SvxRectCtlAccessibleContext::getAccessibleDescription()
190 ::osl::MutexGuard
aGuard( m_aMutex
);
191 return msDescription
+ " Please use arrow key to selection.";
194 OUString SAL_CALL
SvxRectCtlAccessibleContext::getAccessibleName()
196 ::osl::MutexGuard
aGuard( m_aMutex
);
200 /** Return empty reference to indicate that the relation set is not
203 Reference
< XAccessibleRelationSet
> SAL_CALL
SvxRectCtlAccessibleContext::getAccessibleRelationSet()
205 ::osl::MutexGuard
aGuard( m_aMutex
);
207 return mpRepr
->get_accessible_relation_set();
208 return uno::Reference
<css::accessibility::XAccessibleRelationSet
>();
211 Reference
< XAccessibleStateSet
> SAL_CALL
SvxRectCtlAccessibleContext::getAccessibleStateSet()
213 ::osl::MutexGuard
aGuard( m_aMutex
);
214 rtl::Reference
<utl::AccessibleStateSetHelper
> pStateSetHelper
= new utl::AccessibleStateSetHelper
;
218 pStateSetHelper
->AddState( AccessibleStateType::ENABLED
);
219 pStateSetHelper
->AddState( AccessibleStateType::FOCUSABLE
);
220 if( mpRepr
->HasFocus() )
221 pStateSetHelper
->AddState( AccessibleStateType::FOCUSED
);
222 pStateSetHelper
->AddState( AccessibleStateType::OPAQUE
);
224 pStateSetHelper
->AddState( AccessibleStateType::SHOWING
);
226 if( mpRepr
->IsVisible() )
227 pStateSetHelper
->AddState( AccessibleStateType::VISIBLE
);
230 pStateSetHelper
->AddState( AccessibleStateType::DEFUNC
);
232 return pStateSetHelper
;
235 void SAL_CALL
SvxRectCtlAccessibleContext::grabFocus()
237 ::SolarMutexGuard aSolarGuard
;
238 ::osl::MutexGuard
aGuard( m_aMutex
);
244 sal_Int32
SvxRectCtlAccessibleContext::getForeground()
246 ::SolarMutexGuard aSolarGuard
;
247 ::osl::MutexGuard
aGuard( m_aMutex
);
249 //see SvxRectCtl::Paint
250 const StyleSettings
& rStyles
= Application::GetSettings().GetStyleSettings();
251 return sal_Int32(rStyles
.GetLabelTextColor());
254 sal_Int32
SvxRectCtlAccessibleContext::getBackground( )
256 ::SolarMutexGuard aSolarGuard
;
257 ::osl::MutexGuard
aGuard( m_aMutex
);
259 //see SvxRectCtl::Paint
260 const StyleSettings
& rStyles
= Application::GetSettings().GetStyleSettings();
261 return sal_Int32(rStyles
.GetDialogColor());
264 // XAccessibleSelection
265 void SvxRectCtlAccessibleContext::implSelect(sal_Int32 nIndex
, bool bSelect
)
267 ::SolarMutexGuard aSolarGuard
;
269 ::osl::MutexGuard
aGuard( m_aMutex
);
271 checkChildIndex( nIndex
);
273 const ChildIndexToPointData
* pData
= IndexToPoint( nIndex
);
275 DBG_ASSERT(pData
, "SvxRectCtlAccessibleContext::selectAccessibleChild(): this is an impossible state! Or at least should be...");
281 // this does all what is needed, including the change of the child's state!
282 mpRepr
->SetActualRP( pData
->ePoint
);
286 SAL_WARN( "svx", "SvxRectCtlAccessibleContext::clearAccessibleSelection() is not possible!" );
291 bool SvxRectCtlAccessibleContext::implIsSelected( sal_Int32 nIndex
)
293 ::osl::MutexGuard
aGuard( m_aMutex
);
295 checkChildIndex( nIndex
);
297 return nIndex
== mnSelectedChild
;
301 void SvxRectCtlAccessibleContext::checkChildIndex( tools::Long nIndex
)
303 if( nIndex
< 0 || nIndex
>= getAccessibleChildCount() )
304 throw lang::IndexOutOfBoundsException();
307 void SvxRectCtlAccessibleContext::FireChildFocus( RectPoint eButton
)
309 ::osl::MutexGuard
aGuard( m_aMutex
);
310 tools::Long nNew
= PointToIndex( eButton
);
311 tools::Long nNumOfChildren
= getAccessibleChildCount();
312 if( nNew
< nNumOfChildren
)
315 mnSelectedChild
= nNew
;
316 if( nNew
!= NOCHILDSELECTED
)
318 if( mvChildren
[ nNew
].is() )
319 mvChildren
[ nNew
]->FireFocusEvent();
325 aNew
<<= AccessibleStateType::FOCUSED
;
326 NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED
, aOld
, aNew
);
330 mnSelectedChild
= NOCHILDSELECTED
;
333 void SvxRectCtlAccessibleContext::selectChild( tools::Long nNew
)
335 ::osl::MutexGuard
aGuard( m_aMutex
);
336 if( nNew
== mnSelectedChild
)
339 tools::Long nNumOfChildren
= getAccessibleChildCount();
340 if( nNew
< nNumOfChildren
)
342 if( mnSelectedChild
!= NOCHILDSELECTED
)
343 { // deselect old selected child if one is selected
344 SvxRectCtlChildAccessibleContext
* pChild
= mvChildren
[ mnSelectedChild
].get();
346 pChild
->setStateChecked( false );
350 mnSelectedChild
= nNew
;
352 if( nNew
!= NOCHILDSELECTED
)
354 if( mvChildren
[ nNew
].is() )
355 mvChildren
[ nNew
]->setStateChecked( true );
359 mnSelectedChild
= NOCHILDSELECTED
;
362 void SvxRectCtlAccessibleContext::selectChild(RectPoint eButton
)
364 // no guard -> is done in next selectChild
365 selectChild(PointToIndex( eButton
));
368 void SAL_CALL
SvxRectCtlAccessibleContext::disposing()
370 ::osl::MutexGuard
aGuard(m_aMutex
);
371 OAccessibleSelectionHelper::disposing();
372 for (auto & rxChild
: mvChildren
)
381 awt::Rectangle
SvxRectCtlAccessibleContext::implGetBounds()
383 ::SolarMutexGuard aSolarGuard
;
384 ::osl::MutexGuard
aGuard( m_aMutex
);
391 Size
aOutSize(mpRepr
->GetOutputSizePixel());
393 aRet
.X
= aOutPos
.X();
394 aRet
.Y
= aOutPos
.Y();
395 aRet
.Width
= aOutSize
.Width();
396 aRet
.Height
= aOutSize
.Height();
402 SvxRectCtlChildAccessibleContext::SvxRectCtlChildAccessibleContext(
403 const Reference
<XAccessible
>& rxParent
,
404 const OUString
& rName
,
405 const OUString
& rDescription
,
406 const tools::Rectangle
& rBoundingBox
,
407 tools::Long nIndexInParent
)
408 : msDescription( rDescription
)
411 , maBoundingBox( rBoundingBox
)
412 , mnIndexInParent( nIndexInParent
)
413 , mbIsChecked( false )
417 SvxRectCtlChildAccessibleContext::~SvxRectCtlChildAccessibleContext()
422 Reference
< XAccessible
> SAL_CALL
SvxRectCtlChildAccessibleContext::getAccessibleAtPoint( const awt::Point
& /*rPoint*/ )
424 return Reference
< XAccessible
>();
427 void SAL_CALL
SvxRectCtlChildAccessibleContext::grabFocus()
431 sal_Int32
SvxRectCtlChildAccessibleContext::getForeground( )
433 ::SolarMutexGuard aSolarGuard
;
434 ::osl::MutexGuard
aGuard( m_aMutex
);
436 //see SvxRectCtl::Paint
437 const StyleSettings
& rStyles
= Application::GetSettings().GetStyleSettings();
438 return sal_Int32(rStyles
.GetLabelTextColor());
441 sal_Int32
SvxRectCtlChildAccessibleContext::getBackground( )
443 ::SolarMutexGuard aSolarGuard
;
444 ::osl::MutexGuard
aGuard( m_aMutex
);
446 //see SvxRectCtl::Paint
447 const StyleSettings
& rStyles
= Application::GetSettings().GetStyleSettings();
448 return sal_Int32(rStyles
.GetDialogColor());
451 // XAccessibleContext
452 sal_Int32 SAL_CALL
SvxRectCtlChildAccessibleContext::getAccessibleChildCount()
457 Reference
< XAccessible
> SAL_CALL
SvxRectCtlChildAccessibleContext::getAccessibleChild( sal_Int32
/*nIndex*/ )
459 throw lang::IndexOutOfBoundsException();
462 Reference
< XAccessible
> SAL_CALL
SvxRectCtlChildAccessibleContext::getAccessibleParent()
467 sal_Int16 SAL_CALL
SvxRectCtlChildAccessibleContext::getAccessibleRole()
469 return AccessibleRole::RADIO_BUTTON
;
472 OUString SAL_CALL
SvxRectCtlChildAccessibleContext::getAccessibleDescription()
474 ::osl::MutexGuard
aGuard( m_aMutex
);
475 return msDescription
;
478 OUString SAL_CALL
SvxRectCtlChildAccessibleContext::getAccessibleName()
480 ::osl::MutexGuard
aGuard( m_aMutex
);
484 /** Return empty reference to indicate that the relation set is not
487 Reference
<XAccessibleRelationSet
> SAL_CALL
SvxRectCtlChildAccessibleContext::getAccessibleRelationSet()
489 rtl::Reference
<utl::AccessibleRelationSetHelper
> pRelationSetHelper
= new utl::AccessibleRelationSetHelper
;
492 uno::Sequence
< uno::Reference
< uno::XInterface
> > aSequence
{ mxParent
};
493 pRelationSetHelper
->AddRelation( css::accessibility::AccessibleRelation( css::accessibility::AccessibleRelationType::MEMBER_OF
, aSequence
) );
496 return pRelationSetHelper
;
499 Reference
< XAccessibleStateSet
> SAL_CALL
SvxRectCtlChildAccessibleContext::getAccessibleStateSet()
501 ::osl::MutexGuard
aGuard( m_aMutex
);
502 rtl::Reference
<utl::AccessibleStateSetHelper
> pStateSetHelper
= new utl::AccessibleStateSetHelper
;
504 if (!rBHelper
.bDisposed
)
508 pStateSetHelper
->AddState( AccessibleStateType::CHECKED
);
511 pStateSetHelper
->AddState( AccessibleStateType::ENABLED
);
512 pStateSetHelper
->AddState( AccessibleStateType::SENSITIVE
);
513 pStateSetHelper
->AddState( AccessibleStateType::OPAQUE
);
514 pStateSetHelper
->AddState( AccessibleStateType::SELECTABLE
);
515 pStateSetHelper
->AddState( AccessibleStateType::SHOWING
);
516 pStateSetHelper
->AddState( AccessibleStateType::VISIBLE
);
519 pStateSetHelper
->AddState( AccessibleStateType::DEFUNC
);
521 return pStateSetHelper
;
525 Any SAL_CALL
SvxRectCtlChildAccessibleContext::getCurrentValue()
528 aRet
<<= ( mbIsChecked
? 1.0 : 0.0 );
532 sal_Bool SAL_CALL
SvxRectCtlChildAccessibleContext::setCurrentValue( const Any
& /*aNumber*/ )
537 Any SAL_CALL
SvxRectCtlChildAccessibleContext::getMaximumValue()
544 Any SAL_CALL
SvxRectCtlChildAccessibleContext::getMinimumValue()
555 sal_Int32
SvxRectCtlChildAccessibleContext::getAccessibleActionCount( )
561 sal_Bool
SvxRectCtlChildAccessibleContext::doAccessibleAction ( sal_Int32 nIndex
)
563 ::osl::MutexGuard
aGuard( m_aMutex
);
565 if ( nIndex
< 0 || nIndex
>= getAccessibleActionCount() )
566 throw IndexOutOfBoundsException();
568 Reference
<XAccessibleSelection
> xSelection( mxParent
, UNO_QUERY
);
570 xSelection
->selectAccessibleChild(mnIndexInParent
);
576 OUString
SvxRectCtlChildAccessibleContext::getAccessibleActionDescription ( sal_Int32 nIndex
)
578 ::osl::MutexGuard
aGuard( m_aMutex
);
580 if ( nIndex
< 0 || nIndex
>= getAccessibleActionCount() )
581 throw IndexOutOfBoundsException();
587 Reference
< XAccessibleKeyBinding
> SvxRectCtlChildAccessibleContext::getAccessibleActionKeyBinding( sal_Int32 nIndex
)
589 ::osl::MutexGuard
aGuard( m_aMutex
);
591 if ( nIndex
< 0 || nIndex
>= getAccessibleActionCount() )
592 throw IndexOutOfBoundsException();
594 return Reference
< XAccessibleKeyBinding
>();
597 void SAL_CALL
SvxRectCtlChildAccessibleContext::disposing()
599 OAccessibleComponentHelper::disposing();
603 awt::Rectangle
SvxRectCtlChildAccessibleContext::implGetBounds( )
605 // no guard necessary, because no one changes maBoundingBox after creating it
606 return AWTRectangle(maBoundingBox
);
609 void SvxRectCtlChildAccessibleContext::setStateChecked( bool bChecked
)
611 if( mbIsChecked
== bChecked
)
614 mbIsChecked
= bChecked
;
618 Any
& rMod
= bChecked
? aNew
: aOld
;
620 //Send the STATE_CHANGED(Focused) event to accessible
621 rMod
<<= AccessibleStateType::FOCUSED
;
622 NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED
, aOld
, aNew
);
624 rMod
<<= AccessibleStateType::CHECKED
;
626 NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED
, aOld
, aNew
);
629 void SvxRectCtlChildAccessibleContext::FireFocusEvent()
633 aNew
<<= AccessibleStateType::FOCUSED
;
634 NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED
, aOld
, aNew
);
637 IMPLEMENT_FORWARD_XINTERFACE2( SvxRectCtlChildAccessibleContext
, OAccessibleComponentHelper
, OAccessibleHelper_Base_3
)
638 IMPLEMENT_FORWARD_XTYPEPROVIDER2( SvxRectCtlChildAccessibleContext
, OAccessibleComponentHelper
, OAccessibleHelper_Base_3
)
640 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */