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 <cppuhelper/supportsservice.hxx>
30 #include <unotools/accessiblestatesethelper.hxx>
31 #include <vcl/menu.hxx>
35 using namespace ::com::sun::star
;
36 using namespace ::com::sun::star::lang
;
37 using namespace ::com::sun::star::uno
;
38 using namespace ::com::sun::star::accessibility
;
39 using namespace ::comphelper
;
42 // OAccessibleMenuBaseComponent
45 OAccessibleMenuBaseComponent::OAccessibleMenuBaseComponent( Menu
* pMenu
)
55 m_aAccessibleChildren
.assign( m_pMenu
->GetItemCount(), Reference
< XAccessible
>() );
56 m_pMenu
->AddEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
61 OAccessibleMenuBaseComponent::~OAccessibleMenuBaseComponent()
64 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
68 bool OAccessibleMenuBaseComponent::IsEnabled()
74 bool OAccessibleMenuBaseComponent::IsFocused()
80 bool OAccessibleMenuBaseComponent::IsVisible()
86 bool OAccessibleMenuBaseComponent::IsSelected()
92 bool OAccessibleMenuBaseComponent::IsChecked()
98 void OAccessibleMenuBaseComponent::SetStates()
100 m_bEnabled
= IsEnabled();
101 m_bFocused
= IsFocused();
102 m_bVisible
= IsVisible();
103 m_bSelected
= IsSelected();
104 m_bChecked
= IsChecked();
108 void OAccessibleMenuBaseComponent::SetEnabled( bool bEnabled
)
110 if ( m_bEnabled
!= bEnabled
)
112 sal_Int16 nStateType
=AccessibleStateType::ENABLED
;
113 if (IsMenuHideDisabledEntries())
115 nStateType
= AccessibleStateType::VISIBLE
;
117 std::array
<Any
, 2> aOldValue
, aNewValue
;
120 aOldValue
[0] <<= AccessibleStateType::SENSITIVE
;
121 aOldValue
[1] <<= nStateType
;
125 aNewValue
[0] <<= nStateType
;
126 aNewValue
[1] <<= AccessibleStateType::SENSITIVE
;
128 m_bEnabled
= bEnabled
;
129 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[0], aNewValue
[0] );
130 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[1], aNewValue
[1] );
135 void OAccessibleMenuBaseComponent::SetFocused( bool bFocused
)
137 if ( m_bFocused
!= bFocused
)
139 Any aOldValue
, aNewValue
;
141 aOldValue
<<= AccessibleStateType::FOCUSED
;
143 aNewValue
<<= AccessibleStateType::FOCUSED
;
144 m_bFocused
= bFocused
;
145 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
150 void OAccessibleMenuBaseComponent::SetVisible( bool bVisible
)
152 if ( m_bVisible
!= bVisible
)
154 Any aOldValue
, aNewValue
;
156 aOldValue
<<= AccessibleStateType::VISIBLE
;
158 aNewValue
<<= AccessibleStateType::VISIBLE
;
159 m_bVisible
= bVisible
;
160 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
165 void OAccessibleMenuBaseComponent::SetSelected( bool bSelected
)
167 if ( m_bSelected
!= bSelected
)
169 Any aOldValue
, aNewValue
;
171 aOldValue
<<= AccessibleStateType::SELECTED
;
173 aNewValue
<<= AccessibleStateType::SELECTED
;
174 m_bSelected
= bSelected
;
175 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
180 void OAccessibleMenuBaseComponent::SetChecked( bool bChecked
)
182 if ( m_bChecked
!= bChecked
)
184 Any aOldValue
, aNewValue
;
186 aOldValue
<<= AccessibleStateType::CHECKED
;
188 aNewValue
<<= AccessibleStateType::CHECKED
;
189 m_bChecked
= bChecked
;
190 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
195 void OAccessibleMenuBaseComponent::UpdateEnabled( sal_Int32 i
, bool bEnabled
)
197 if ( i
>= 0 && i
< static_cast<sal_Int32
>(m_aAccessibleChildren
.size()) )
199 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
202 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
204 pComp
->SetEnabled( bEnabled
);
210 void OAccessibleMenuBaseComponent::UpdateFocused( sal_Int32 i
, bool bFocused
)
212 if ( i
>= 0 && i
< static_cast<sal_Int32
>(m_aAccessibleChildren
.size()) )
214 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
217 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
219 pComp
->SetFocused( bFocused
);
225 void OAccessibleMenuBaseComponent::UpdateVisible()
227 SetVisible( IsVisible() );
228 for (const Reference
<XAccessible
>& xChild
: m_aAccessibleChildren
)
232 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
234 pComp
->SetVisible( pComp
->IsVisible() );
240 void OAccessibleMenuBaseComponent::UpdateSelected( sal_Int32 i
, bool bSelected
)
242 NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
244 if ( i
>= 0 && i
< static_cast<sal_Int32
>(m_aAccessibleChildren
.size()) )
246 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
249 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
251 pComp
->SetSelected( bSelected
);
257 void OAccessibleMenuBaseComponent::UpdateChecked( sal_Int32 i
, bool bChecked
)
259 if ( i
>= 0 && i
< static_cast<sal_Int32
>(m_aAccessibleChildren
.size()) )
261 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
264 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
266 pComp
->SetChecked( bChecked
);
272 void OAccessibleMenuBaseComponent::UpdateAccessibleName( sal_Int32 i
)
274 if ( i
>= 0 && i
< static_cast<sal_Int32
>(m_aAccessibleChildren
.size()) )
276 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
279 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
281 pComp
->SetAccessibleName( pComp
->GetAccessibleName() );
287 void OAccessibleMenuBaseComponent::UpdateItemText( sal_Int32 i
)
289 if ( i
>= 0 && i
< static_cast<sal_Int32
>(m_aAccessibleChildren
.size()) )
291 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
294 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
296 pComp
->SetItemText( pComp
->GetItemText() );
302 sal_Int32
OAccessibleMenuBaseComponent::GetChildCount() const
304 return m_aAccessibleChildren
.size();
308 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChild( sal_Int32 i
)
310 Reference
< XAccessible
> xChild
= m_aAccessibleChildren
[i
];
315 // create a new child
316 OAccessibleMenuBaseComponent
* pChild
;
318 if ( m_pMenu
->GetItemType( static_cast<sal_uInt16
>(i
) ) == MenuItemType::SEPARATOR
)
320 pChild
= new VCLXAccessibleMenuSeparator( m_pMenu
, static_cast<sal_uInt16
>(i
) );
324 PopupMenu
* pPopupMenu
= m_pMenu
->GetPopupMenu( m_pMenu
->GetItemId( static_cast<sal_uInt16
>(i
) ) );
327 pChild
= new VCLXAccessibleMenu( m_pMenu
, static_cast<sal_uInt16
>(i
), pPopupMenu
);
328 pPopupMenu
->SetAccessible( pChild
);
332 pChild
= new VCLXAccessibleMenuItem( m_pMenu
, static_cast<sal_uInt16
>(i
) );
341 // insert into menu item list
342 m_aAccessibleChildren
[i
] = xChild
;
350 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChildAt( const awt::Point
& rPoint
)
352 Reference
< XAccessible
> xChild
;
353 for ( sal_uInt32 i
= 0, nCount
= getAccessibleChildCount(); i
< nCount
; ++i
)
355 Reference
< XAccessible
> xAcc
= getAccessibleChild( i
);
358 Reference
< XAccessibleComponent
> xComp( xAcc
->getAccessibleContext(), UNO_QUERY
);
361 tools::Rectangle aRect
= VCLRectangle( xComp
->getBounds() );
362 Point aPos
= VCLPoint( rPoint
);
363 if ( aRect
.IsInside( aPos
) )
376 void OAccessibleMenuBaseComponent::InsertChild( sal_Int32 i
)
378 if ( i
> static_cast<sal_Int32
>(m_aAccessibleChildren
.size()) )
379 i
= m_aAccessibleChildren
.size();
383 // insert entry in child list
384 m_aAccessibleChildren
.insert( m_aAccessibleChildren
.begin() + i
, Reference
< XAccessible
>() );
386 // update item position of accessible children
387 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
389 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
392 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
394 pComp
->SetItemPos( static_cast<sal_uInt16
>(j
) );
398 // send accessible child event
399 Reference
< XAccessible
> xChild( GetChild( i
) );
402 Any aOldValue
, aNewValue
;
403 aNewValue
<<= xChild
;
404 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
410 void OAccessibleMenuBaseComponent::RemoveChild( sal_Int32 i
)
412 if ( i
>= 0 && i
< static_cast<sal_Int32
>(m_aAccessibleChildren
.size()) )
414 // keep the accessible of the removed item
415 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
417 // remove entry in child list
418 m_aAccessibleChildren
.erase( m_aAccessibleChildren
.begin() + i
);
420 // update item position of accessible children
421 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
423 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
426 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
428 pComp
->SetItemPos( static_cast<sal_uInt16
>(j
) );
432 // send accessible child event
435 Any aOldValue
, aNewValue
;
436 aOldValue
<<= xChild
;
437 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
439 Reference
< XComponent
> xComponent( xChild
, UNO_QUERY
);
440 if ( xComponent
.is() )
441 xComponent
->dispose();
447 bool OAccessibleMenuBaseComponent::IsHighlighted()
453 bool OAccessibleMenuBaseComponent::IsChildHighlighted()
455 bool bChildHighlighted
= false;
457 for (const Reference
<XAccessible
>& xChild
: m_aAccessibleChildren
)
461 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
462 if ( pComp
&& pComp
->IsHighlighted() )
464 bChildHighlighted
= true;
470 return bChildHighlighted
;
474 void OAccessibleMenuBaseComponent::SelectChild( sal_Int32 i
)
477 if ( getAccessibleRole() == AccessibleRole::MENU
&& !IsPopupMenuOpen() )
480 // highlight the child
482 m_pMenu
->HighlightItem( static_cast<sal_uInt16
>(i
) );
486 void OAccessibleMenuBaseComponent::DeSelectAll()
489 m_pMenu
->DeHighlight();
493 bool OAccessibleMenuBaseComponent::IsChildSelected( sal_Int32 i
)
495 bool bSelected
= false;
497 if ( m_pMenu
&& m_pMenu
->IsHighlighted( static_cast<sal_uInt16
>(i
) ) )
504 void OAccessibleMenuBaseComponent::Click()
509 bool OAccessibleMenuBaseComponent::IsPopupMenuOpen()
515 IMPL_LINK( OAccessibleMenuBaseComponent
, MenuEventListener
, VclMenuEvent
&, rEvent
, void )
517 OSL_ENSURE( rEvent
.GetMenu(), "OAccessibleMenuBaseComponent - Menu?" );
518 ProcessMenuEvent( rEvent
);
522 void OAccessibleMenuBaseComponent::ProcessMenuEvent( const VclMenuEvent
& rVclMenuEvent
)
524 sal_uInt16 nItemPos
= rVclMenuEvent
.GetItemPos();
526 switch ( rVclMenuEvent
.GetId() )
528 case VclEventId::MenuShow
:
529 case VclEventId::MenuHide
:
534 case VclEventId::MenuHighlight
:
537 UpdateFocused( nItemPos
, true );
538 UpdateSelected( nItemPos
, true );
541 case VclEventId::MenuDehighlight
:
543 UpdateFocused( nItemPos
, false );
544 UpdateSelected( nItemPos
, false );
547 case VclEventId::MenuSubmenuActivate
:
551 case VclEventId::MenuSubmenuDeactivate
:
553 UpdateFocused( nItemPos
, true );
556 case VclEventId::MenuEnable
:
558 UpdateEnabled( nItemPos
, true );
561 case VclEventId::MenuDisable
:
563 UpdateEnabled( nItemPos
, false );
566 case VclEventId::MenuSubmenuChanged
:
568 RemoveChild( nItemPos
);
569 InsertChild( nItemPos
);
572 case VclEventId::MenuInsertItem
:
574 InsertChild( nItemPos
);
577 case VclEventId::MenuRemoveItem
:
579 RemoveChild( nItemPos
);
582 case VclEventId::MenuItemTextChanged
:
584 UpdateAccessibleName( nItemPos
);
585 UpdateItemText( nItemPos
);
588 case VclEventId::MenuItemChecked
:
590 UpdateChecked( nItemPos
, true );
593 case VclEventId::MenuItemUnchecked
:
595 UpdateChecked( nItemPos
, false );
598 case VclEventId::ObjectDying
:
602 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
606 // dispose all menu items
607 for (const Reference
<XAccessible
>& i
: m_aAccessibleChildren
)
609 Reference
< XComponent
> xComponent( i
, UNO_QUERY
);
610 if ( xComponent
.is() )
611 xComponent
->dispose();
613 m_aAccessibleChildren
.clear();
628 IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleMenuBaseComponent
, OAccessibleExtendedComponentHelper
, OAccessibleMenuBaseComponent_BASE
)
634 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleMenuBaseComponent
, OAccessibleExtendedComponentHelper
, OAccessibleMenuBaseComponent_BASE
)
640 void OAccessibleMenuBaseComponent::disposing()
642 OAccessibleExtendedComponentHelper::disposing();
646 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
650 // dispose all menu items
651 for (const Reference
<XAccessible
>& i
: m_aAccessibleChildren
)
653 Reference
< XComponent
> xComponent( i
, UNO_QUERY
);
654 if ( xComponent
.is() )
655 xComponent
->dispose();
657 m_aAccessibleChildren
.clear();
665 sal_Bool
OAccessibleMenuBaseComponent::supportsService( const OUString
& rServiceName
)
667 return cppu::supportsService(this, rServiceName
);
674 Reference
< XAccessibleContext
> OAccessibleMenuBaseComponent::getAccessibleContext( )
676 OExternalLockGuard
aGuard( this );
682 // XAccessibleContext
685 Reference
< XAccessibleStateSet
> OAccessibleMenuBaseComponent::getAccessibleStateSet( )
687 OExternalLockGuard
aGuard( this );
689 utl::AccessibleStateSetHelper
* pStateSetHelper
= new utl::AccessibleStateSetHelper
;
690 Reference
< XAccessibleStateSet
> xSet
= pStateSetHelper
;
692 if ( !rBHelper
.bDisposed
&& !rBHelper
.bInDispose
)
694 FillAccessibleStateSet( *pStateSetHelper
);
698 pStateSetHelper
->AddState( AccessibleStateType::DEFUNC
);
705 bool OAccessibleMenuBaseComponent::IsMenuHideDisabledEntries()
710 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */