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/convert.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(), Reference
< XAccessible
>() );
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 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
204 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
206 pComp
->SetEnabled( bEnabled
);
212 void OAccessibleMenuBaseComponent::UpdateFocused( sal_Int32 i
, bool bFocused
)
214 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
216 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
219 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
221 pComp
->SetFocused( bFocused
);
227 void OAccessibleMenuBaseComponent::UpdateVisible()
229 SetVisible( IsVisible() );
230 for (const Reference
<XAccessible
>& xChild
: m_aAccessibleChildren
)
234 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
236 pComp
->SetVisible( pComp
->IsVisible() );
242 void OAccessibleMenuBaseComponent::UpdateSelected( sal_Int32 i
, bool bSelected
)
244 NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
246 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
248 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
251 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
253 pComp
->SetSelected( bSelected
);
259 void OAccessibleMenuBaseComponent::UpdateChecked( sal_Int32 i
, bool bChecked
)
261 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
263 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
266 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
268 pComp
->SetChecked( bChecked
);
274 void OAccessibleMenuBaseComponent::UpdateAccessibleName( sal_Int32 i
)
276 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
278 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
281 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
283 pComp
->SetAccessibleName( pComp
->GetAccessibleName() );
289 void OAccessibleMenuBaseComponent::UpdateItemText( sal_Int32 i
)
291 if ( i
>= 0 && o3tl::make_unsigned(i
) < m_aAccessibleChildren
.size() )
293 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
296 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
298 pComp
->SetItemText( pComp
->GetItemText() );
304 sal_Int64
OAccessibleMenuBaseComponent::GetChildCount() const
306 return m_aAccessibleChildren
.size();
310 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChild( sal_Int64 i
)
312 Reference
< XAccessible
> xChild
= m_aAccessibleChildren
[i
];
317 // create a new child
318 rtl::Reference
<OAccessibleMenuBaseComponent
> pChild
;
320 if ( m_pMenu
->GetItemType( static_cast<sal_uInt16
>(i
) ) == MenuItemType::SEPARATOR
)
322 pChild
= new VCLXAccessibleMenuSeparator( m_pMenu
, static_cast<sal_uInt16
>(i
) );
326 PopupMenu
* pPopupMenu
= m_pMenu
->GetPopupMenu( m_pMenu
->GetItemId( static_cast<sal_uInt16
>(i
) ) );
329 pChild
= new VCLXAccessibleMenu( m_pMenu
, static_cast<sal_uInt16
>(i
), pPopupMenu
);
330 pPopupMenu
->SetAccessible( pChild
);
334 pChild
= new VCLXAccessibleMenuItem( m_pMenu
, static_cast<sal_uInt16
>(i
) );
343 // insert into menu item list
344 m_aAccessibleChildren
[i
] = xChild
;
352 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChildAt( const awt::Point
& rPoint
)
354 Reference
< XAccessible
> xChild
;
355 for ( sal_Int64 i
= 0, nCount
= getAccessibleChildCount(); i
< nCount
; ++i
)
357 Reference
< XAccessible
> xAcc
= getAccessibleChild( i
);
360 Reference
< XAccessibleComponent
> xComp( xAcc
->getAccessibleContext(), UNO_QUERY
);
363 tools::Rectangle aRect
= VCLRectangle( xComp
->getBounds() );
364 Point aPos
= VCLPoint( rPoint
);
365 if ( aRect
.Contains( aPos
) )
378 void OAccessibleMenuBaseComponent::InsertChild( sal_Int32 i
)
383 if ( o3tl::make_unsigned(i
) > m_aAccessibleChildren
.size() )
384 i
= m_aAccessibleChildren
.size();
386 // insert entry in child list
387 m_aAccessibleChildren
.insert( m_aAccessibleChildren
.begin() + i
, Reference
< XAccessible
>() );
389 // update item position of accessible children
390 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
392 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
395 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
397 pComp
->SetItemPos( static_cast<sal_uInt16
>(j
) );
401 // send accessible child event
402 Reference
< XAccessible
> xChild( GetChild( i
) );
405 Any aOldValue
, aNewValue
;
406 aNewValue
<<= xChild
;
407 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
412 void OAccessibleMenuBaseComponent::RemoveChild( sal_Int32 i
)
414 if ( i
< 0 || o3tl::make_unsigned(i
) >= m_aAccessibleChildren
.size() )
417 // keep the accessible of the removed item
418 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
420 // remove entry in child list
421 m_aAccessibleChildren
.erase( m_aAccessibleChildren
.begin() + i
);
423 // update item position of accessible children
424 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
426 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
429 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
431 pComp
->SetItemPos( static_cast<sal_uInt16
>(j
) );
435 // send accessible child event
438 Any aOldValue
, aNewValue
;
439 aOldValue
<<= xChild
;
440 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
442 Reference
< XComponent
> xComponent( xChild
, UNO_QUERY
);
443 if ( xComponent
.is() )
444 xComponent
->dispose();
449 bool OAccessibleMenuBaseComponent::IsHighlighted()
455 bool OAccessibleMenuBaseComponent::IsChildHighlighted()
457 bool bChildHighlighted
= false;
459 for (const Reference
<XAccessible
>& xChild
: m_aAccessibleChildren
)
463 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
464 if ( pComp
&& pComp
->IsHighlighted() )
466 bChildHighlighted
= true;
472 return bChildHighlighted
;
476 void OAccessibleMenuBaseComponent::SelectChild( sal_Int32 i
)
479 if ( getAccessibleRole() == AccessibleRole::MENU
&& !IsPopupMenuOpen() )
482 // highlight the child
484 m_pMenu
->HighlightItem( static_cast<sal_uInt16
>(i
) );
488 void OAccessibleMenuBaseComponent::DeSelectAll()
491 m_pMenu
->DeHighlight();
495 bool OAccessibleMenuBaseComponent::IsChildSelected( sal_Int32 i
)
497 bool bSelected
= false;
499 if ( m_pMenu
&& m_pMenu
->IsHighlighted( static_cast<sal_uInt16
>(i
) ) )
506 void OAccessibleMenuBaseComponent::Click()
511 bool OAccessibleMenuBaseComponent::IsPopupMenuOpen()
517 IMPL_LINK( OAccessibleMenuBaseComponent
, MenuEventListener
, VclMenuEvent
&, rEvent
, void )
519 OSL_ENSURE( rEvent
.GetMenu(), "OAccessibleMenuBaseComponent - Menu?" );
520 ProcessMenuEvent( rEvent
);
524 void OAccessibleMenuBaseComponent::ProcessMenuEvent( const VclMenuEvent
& rVclMenuEvent
)
526 sal_uInt16 nItemPos
= rVclMenuEvent
.GetItemPos();
528 switch ( rVclMenuEvent
.GetId() )
530 case VclEventId::MenuShow
:
531 case VclEventId::MenuHide
:
536 case VclEventId::MenuHighlight
:
539 UpdateFocused( nItemPos
, true );
540 UpdateSelected( nItemPos
, true );
543 case VclEventId::MenuDehighlight
:
545 UpdateFocused( nItemPos
, false );
546 UpdateSelected( nItemPos
, false );
549 case VclEventId::MenuSubmenuActivate
:
553 case VclEventId::MenuSubmenuDeactivate
:
555 UpdateFocused( nItemPos
, true );
558 case VclEventId::MenuEnable
:
560 UpdateEnabled( nItemPos
, true );
563 case VclEventId::MenuDisable
:
565 UpdateEnabled( nItemPos
, false );
568 case VclEventId::MenuSubmenuChanged
:
570 RemoveChild( nItemPos
);
571 InsertChild( nItemPos
);
574 case VclEventId::MenuInsertItem
:
576 InsertChild( nItemPos
);
579 case VclEventId::MenuRemoveItem
:
581 RemoveChild( nItemPos
);
584 case VclEventId::MenuAccessibleNameChanged
:
586 UpdateAccessibleName( nItemPos
);
589 case VclEventId::MenuItemTextChanged
:
591 UpdateAccessibleName( nItemPos
);
592 UpdateItemText( nItemPos
);
595 case VclEventId::MenuItemChecked
:
597 UpdateChecked( nItemPos
, true );
600 case VclEventId::MenuItemUnchecked
:
602 UpdateChecked( nItemPos
, false );
605 case VclEventId::ObjectDying
:
609 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
613 // dispose all menu items
614 for (const Reference
<XAccessible
>& i
: m_aAccessibleChildren
)
616 Reference
< XComponent
> xComponent( i
, UNO_QUERY
);
617 if ( xComponent
.is() )
618 xComponent
->dispose();
620 m_aAccessibleChildren
.clear();
635 void OAccessibleMenuBaseComponent::disposing()
637 OAccessibleExtendedComponentHelper::disposing();
642 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
646 // dispose all menu items
647 for (const Reference
<XAccessible
>& i
: m_aAccessibleChildren
)
649 Reference
< XComponent
> xComponent( i
, UNO_QUERY
);
650 if ( xComponent
.is() )
651 xComponent
->dispose();
653 m_aAccessibleChildren
.clear();
660 sal_Bool
OAccessibleMenuBaseComponent::supportsService( const OUString
& rServiceName
)
662 return cppu::supportsService(this, rServiceName
);
669 Reference
< XAccessibleContext
> OAccessibleMenuBaseComponent::getAccessibleContext( )
671 OExternalLockGuard
aGuard( this );
677 // XAccessibleContext
680 sal_Int64
OAccessibleMenuBaseComponent::getAccessibleStateSet( )
682 OExternalLockGuard
aGuard( this );
684 sal_Int64 nStateSet
= 0;
686 if ( !rBHelper
.bDisposed
&& !rBHelper
.bInDispose
)
688 FillAccessibleStateSet( nStateSet
);
692 nStateSet
|= AccessibleStateType::DEFUNC
;
699 bool OAccessibleMenuBaseComponent::IsMenuHideDisabledEntries()
704 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */