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 <standard/accessiblemenubasecomponent.hxx>
21 #include <standard/vclxaccessiblemenu.hxx>
22 #include <standard/vclxaccessiblemenuitem.hxx>
23 #include <standard/vclxaccessiblemenuseparator.hxx>
24 #include <toolkit/helper/vclunohelper.hxx>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 #include <com/sun/star/accessibility/AccessibleRole.hpp>
28 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
29 #include <comphelper/accessiblecontexthelper.hxx>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <o3tl/safeint.hxx>
32 #include <vcl/menu.hxx>
33 #include <vcl/vclevent.hxx>
37 using namespace ::com::sun::star
;
38 using namespace ::com::sun::star::lang
;
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::accessibility
;
41 using namespace ::comphelper
;
44 // OAccessibleMenuBaseComponent
47 OAccessibleMenuBaseComponent::OAccessibleMenuBaseComponent( Menu
* pMenu
)
57 m_aAccessibleChildren
.assign( m_pMenu
->GetItemCount(), rtl::Reference
< OAccessibleMenuItemComponent
>() );
58 m_pMenu
->AddEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
63 OAccessibleMenuBaseComponent::~OAccessibleMenuBaseComponent()
66 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
70 bool OAccessibleMenuBaseComponent::IsEnabled()
76 bool OAccessibleMenuBaseComponent::IsFocused()
82 bool OAccessibleMenuBaseComponent::IsVisible()
88 bool OAccessibleMenuBaseComponent::IsSelected()
94 bool OAccessibleMenuBaseComponent::IsChecked()
100 void OAccessibleMenuBaseComponent::SetStates()
102 m_bEnabled
= IsEnabled();
103 m_bFocused
= IsFocused();
104 m_bVisible
= IsVisible();
105 m_bSelected
= IsSelected();
106 m_bChecked
= IsChecked();
110 void OAccessibleMenuBaseComponent::SetEnabled( bool bEnabled
)
112 if ( m_bEnabled
== bEnabled
)
115 sal_Int64 nStateType
=AccessibleStateType::ENABLED
;
116 if (IsMenuHideDisabledEntries())
118 nStateType
= AccessibleStateType::VISIBLE
;
120 std::array
<Any
, 2> aOldValue
, aNewValue
;
123 aOldValue
[0] <<= AccessibleStateType::SENSITIVE
;
124 aOldValue
[1] <<= nStateType
;
128 aNewValue
[0] <<= nStateType
;
129 aNewValue
[1] <<= AccessibleStateType::SENSITIVE
;
131 m_bEnabled
= bEnabled
;
132 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[0], aNewValue
[0] );
133 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[1], aNewValue
[1] );
137 void OAccessibleMenuBaseComponent::SetFocused( bool bFocused
)
139 if ( m_bFocused
!= bFocused
)
141 Any aOldValue
, aNewValue
;
143 aOldValue
<<= AccessibleStateType::FOCUSED
;
145 aNewValue
<<= AccessibleStateType::FOCUSED
;
146 m_bFocused
= bFocused
;
147 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
152 void OAccessibleMenuBaseComponent::SetVisible( bool bVisible
)
154 if ( m_bVisible
!= bVisible
)
156 Any aOldValue
, aNewValue
;
158 aOldValue
<<= AccessibleStateType::VISIBLE
;
160 aNewValue
<<= AccessibleStateType::VISIBLE
;
161 m_bVisible
= bVisible
;
162 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
167 void OAccessibleMenuBaseComponent::SetSelected( bool bSelected
)
169 if ( m_bSelected
!= bSelected
)
171 Any aOldValue
, aNewValue
;
173 aOldValue
<<= AccessibleStateType::SELECTED
;
175 aNewValue
<<= AccessibleStateType::SELECTED
;
176 m_bSelected
= bSelected
;
177 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
182 void OAccessibleMenuBaseComponent::SetChecked( bool bChecked
)
184 if ( m_bChecked
!= bChecked
)
186 Any aOldValue
, aNewValue
;
188 aOldValue
<<= AccessibleStateType::CHECKED
;
190 aNewValue
<<= AccessibleStateType::CHECKED
;
191 m_bChecked
= bChecked
;
192 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
197 void OAccessibleMenuBaseComponent::UpdateEnabled( sal_Int32 i
, bool bEnabled
)
199 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
201 rtl::Reference
< OAccessibleMenuBaseComponent
> xChild( m_aAccessibleChildren
[i
] );
203 xChild
->SetEnabled( bEnabled
);
208 void OAccessibleMenuBaseComponent::UpdateFocused( sal_Int32 i
, bool bFocused
)
210 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
212 rtl::Reference
< OAccessibleMenuBaseComponent
> xChild( m_aAccessibleChildren
[i
] );
214 xChild
->SetFocused( bFocused
);
219 void OAccessibleMenuBaseComponent::UpdateVisible()
221 SetVisible( IsVisible() );
222 for (const rtl::Reference
<OAccessibleMenuItemComponent
>& xChild
: m_aAccessibleChildren
)
225 xChild
->SetVisible( xChild
->IsVisible() );
230 void OAccessibleMenuBaseComponent::UpdateSelected( sal_Int32 i
, bool bSelected
)
232 NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
234 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
236 rtl::Reference
< OAccessibleMenuBaseComponent
> xChild( m_aAccessibleChildren
[i
] );
238 xChild
->SetSelected( bSelected
);
243 void OAccessibleMenuBaseComponent::UpdateChecked( sal_Int32 i
, bool bChecked
)
245 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
247 rtl::Reference
< OAccessibleMenuBaseComponent
> xChild( m_aAccessibleChildren
[i
] );
249 xChild
->SetChecked( bChecked
);
254 void OAccessibleMenuBaseComponent::UpdateAccessibleName( sal_Int32 i
)
256 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
258 rtl::Reference
< OAccessibleMenuBaseComponent
> xChild( m_aAccessibleChildren
[i
] );
261 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
263 pComp
->SetAccessibleName( pComp
->GetAccessibleName() );
268 void OAccessibleMenuBaseComponent::UpdateItemRole(sal_Int32 i
)
270 if (i
< 0 || o3tl::make_unsigned(i
) >= m_aAccessibleChildren
.size())
273 rtl::Reference
<OAccessibleMenuItemComponent
> xChild(m_aAccessibleChildren
[i
]);
277 xChild
->NotifyAccessibleEvent(AccessibleEventId::ROLE_CHANGED
, Any(), Any());
280 void OAccessibleMenuBaseComponent::UpdateItemText( sal_Int32 i
)
282 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
284 rtl::Reference
< OAccessibleMenuItemComponent
> xChild( m_aAccessibleChildren
[i
] );
286 xChild
->SetItemText( xChild
->GetItemText() );
291 sal_Int64
OAccessibleMenuBaseComponent::GetChildCount() const
293 return m_aAccessibleChildren
.size();
297 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChild( sal_Int64 i
)
299 rtl::Reference
< OAccessibleMenuItemComponent
> xChild
= m_aAccessibleChildren
[i
];
304 // create a new child
305 if ( m_pMenu
->GetItemType( static_cast<sal_uInt16
>(i
) ) == MenuItemType::SEPARATOR
)
307 xChild
= new VCLXAccessibleMenuSeparator(m_pMenu
, static_cast<sal_uInt16
>(i
));
311 PopupMenu
* pPopupMenu
= m_pMenu
->GetPopupMenu( m_pMenu
->GetItemId( static_cast<sal_uInt16
>(i
) ) );
314 xChild
= new VCLXAccessibleMenu(m_pMenu
, static_cast<sal_uInt16
>(i
), pPopupMenu
);
315 pPopupMenu
->SetAccessible(xChild
);
319 xChild
= new VCLXAccessibleMenuItem(m_pMenu
, static_cast<sal_uInt16
>(i
));
326 // insert into menu item list
327 m_aAccessibleChildren
[i
] = xChild
;
335 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChildAt( const awt::Point
& rPoint
)
337 for ( sal_Int64 i
= 0, nCount
= getAccessibleChildCount(); i
< nCount
; ++i
)
339 Reference
< XAccessible
> xAcc
= getAccessibleChild( i
);
342 Reference
< XAccessibleComponent
> xComp( xAcc
->getAccessibleContext(), UNO_QUERY
);
345 tools::Rectangle aRect
= VCLUnoHelper::ConvertToVCLRect(xComp
->getBounds());
346 Point aPos
= VCLUnoHelper::ConvertToVCLPoint(rPoint
);
347 if ( aRect
.Contains( aPos
) )
359 void OAccessibleMenuBaseComponent::InsertChild( sal_Int32 i
)
364 if ( o3tl::make_unsigned(i
) > m_aAccessibleChildren
.size() )
365 i
= m_aAccessibleChildren
.size();
367 // insert entry in child list
368 m_aAccessibleChildren
.insert( m_aAccessibleChildren
.begin() + i
, rtl::Reference
< OAccessibleMenuItemComponent
>() );
370 // update item position of accessible children
371 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
373 rtl::Reference
< OAccessibleMenuItemComponent
> xAcc( m_aAccessibleChildren
[j
] );
375 xAcc
->SetItemPos( static_cast<sal_uInt16
>(j
) );
378 // send accessible child event
379 Reference
< XAccessible
> xChild( GetChild( i
) );
382 Any aOldValue
, aNewValue
;
383 aNewValue
<<= xChild
;
384 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
389 void OAccessibleMenuBaseComponent::RemoveChild( sal_Int32 i
)
391 if ( i
< 0 || o3tl::make_unsigned(i
) >= m_aAccessibleChildren
.size() )
394 // keep the accessible of the removed item
395 rtl::Reference
< OAccessibleMenuItemComponent
> xChild( m_aAccessibleChildren
[i
] );
397 // remove entry in child list
398 m_aAccessibleChildren
.erase( m_aAccessibleChildren
.begin() + i
);
400 // update item position of accessible children
401 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
403 rtl::Reference
< OAccessibleMenuItemComponent
> xAcc( m_aAccessibleChildren
[j
] );
405 xAcc
->SetItemPos( static_cast<sal_uInt16
>(j
) );
408 // send accessible child event
411 Any aOldValue
, aNewValue
;
412 aOldValue
<<= uno::Reference
<XAccessible
>(xChild
);
413 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
420 bool OAccessibleMenuBaseComponent::IsHighlighted()
426 bool OAccessibleMenuBaseComponent::IsChildHighlighted()
428 bool bChildHighlighted
= false;
430 for (const rtl::Reference
<OAccessibleMenuItemComponent
>& xChild
: m_aAccessibleChildren
)
432 if ( xChild
.is() && xChild
->IsHighlighted() )
434 bChildHighlighted
= true;
439 return bChildHighlighted
;
443 void OAccessibleMenuBaseComponent::SelectChild( sal_Int32 i
)
446 if ( getAccessibleRole() == AccessibleRole::MENU
&& !IsPopupMenuOpen() )
449 // highlight the child
451 m_pMenu
->HighlightItem( static_cast<sal_uInt16
>(i
) );
455 void OAccessibleMenuBaseComponent::DeSelectAll()
458 m_pMenu
->DeHighlight();
462 bool OAccessibleMenuBaseComponent::IsChildSelected( sal_Int32 i
)
464 bool bSelected
= false;
466 if ( m_pMenu
&& m_pMenu
->IsHighlighted( static_cast<sal_uInt16
>(i
) ) )
473 void OAccessibleMenuBaseComponent::Click()
478 bool OAccessibleMenuBaseComponent::IsPopupMenuOpen()
484 IMPL_LINK( OAccessibleMenuBaseComponent
, MenuEventListener
, VclMenuEvent
&, rEvent
, void )
486 OSL_ENSURE( rEvent
.GetMenu(), "OAccessibleMenuBaseComponent - Menu?" );
487 ProcessMenuEvent( rEvent
);
491 void OAccessibleMenuBaseComponent::ProcessMenuEvent( const VclMenuEvent
& rVclMenuEvent
)
493 sal_uInt16 nItemPos
= rVclMenuEvent
.GetItemPos();
495 switch ( rVclMenuEvent
.GetId() )
497 case VclEventId::MenuShow
:
498 case VclEventId::MenuHide
:
503 case VclEventId::MenuHighlight
:
506 UpdateFocused( nItemPos
, true );
507 UpdateSelected( nItemPos
, true );
510 case VclEventId::MenuDehighlight
:
512 UpdateFocused( nItemPos
, false );
513 UpdateSelected( nItemPos
, false );
516 case VclEventId::MenuSubmenuActivate
:
520 case VclEventId::MenuSubmenuDeactivate
:
522 UpdateFocused( nItemPos
, true );
525 case VclEventId::MenuEnable
:
527 UpdateEnabled( nItemPos
, true );
530 case VclEventId::MenuDisable
:
532 UpdateEnabled( nItemPos
, false );
535 case VclEventId::MenuSubmenuChanged
:
537 RemoveChild( nItemPos
);
538 InsertChild( nItemPos
);
541 case VclEventId::MenuInsertItem
:
543 InsertChild( nItemPos
);
546 case VclEventId::MenuRemoveItem
:
548 RemoveChild( nItemPos
);
551 case VclEventId::MenuAccessibleNameChanged
:
553 UpdateAccessibleName( nItemPos
);
556 case VclEventId::MenuItemRoleChanged
:
558 UpdateItemRole(nItemPos
);
561 case VclEventId::MenuItemTextChanged
:
563 UpdateAccessibleName( nItemPos
);
564 UpdateItemText( nItemPos
);
567 case VclEventId::MenuItemChecked
:
569 UpdateChecked( nItemPos
, true );
572 case VclEventId::MenuItemUnchecked
:
574 UpdateChecked( nItemPos
, false );
577 case VclEventId::ObjectDying
:
581 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
585 // dispose all menu items
586 for (const rtl::Reference
<OAccessibleMenuItemComponent
>& xComponent
: m_aAccessibleChildren
)
588 if ( xComponent
.is() )
589 xComponent
->dispose();
591 m_aAccessibleChildren
.clear();
606 void OAccessibleMenuBaseComponent::disposing()
608 OAccessibleExtendedComponentHelper::disposing();
613 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
617 // dispose all menu items
618 for (const rtl::Reference
<OAccessibleMenuItemComponent
>& xComponent
: m_aAccessibleChildren
)
620 if ( xComponent
.is() )
621 xComponent
->dispose();
623 m_aAccessibleChildren
.clear();
630 sal_Bool
OAccessibleMenuBaseComponent::supportsService( const OUString
& rServiceName
)
632 return cppu::supportsService(this, rServiceName
);
639 Reference
< XAccessibleContext
> OAccessibleMenuBaseComponent::getAccessibleContext( )
641 OExternalLockGuard
aGuard( this );
647 // XAccessibleContext
650 sal_Int64
OAccessibleMenuBaseComponent::getAccessibleStateSet( )
652 OExternalLockGuard
aGuard( this );
654 sal_Int64 nStateSet
= 0;
656 if ( !rBHelper
.bDisposed
&& !rBHelper
.bInDispose
)
658 FillAccessibleStateSet( nStateSet
);
662 nStateSet
|= AccessibleStateType::DEFUNC
;
669 bool OAccessibleMenuBaseComponent::IsMenuHideDisabledEntries()
674 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */