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 <accessibility/standard/accessiblemenubasecomponent.hxx>
21 #include <accessibility/standard/vclxaccessiblemenu.hxx>
22 #include <accessibility/standard/vclxaccessiblemenuitem.hxx>
23 #include <accessibility/standard/vclxaccessiblemenuseparator.hxx>
24 #include <toolkit/helper/externallock.hxx>
25 #include <toolkit/helper/convert.hxx>
27 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
28 #include <com/sun/star/accessibility/AccessibleRole.hpp>
29 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <unotools/accessiblestatesethelper.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/window.hxx>
34 #include <vcl/menu.hxx>
36 using namespace ::com::sun::star
;
37 using namespace ::com::sun::star::lang
;
38 using namespace ::com::sun::star::uno
;
39 using namespace ::com::sun::star::accessibility
;
40 using namespace ::comphelper
;
44 // OAccessibleMenuBaseComponent
47 OAccessibleMenuBaseComponent::OAccessibleMenuBaseComponent( Menu
* pMenu
)
48 :AccessibleExtendedComponentHelper_BASE( new VCLExternalSolarLock() )
56 m_pExternalLock
= static_cast< VCLExternalSolarLock
* >( getExternalLock() );
60 m_aAccessibleChildren
.assign( m_pMenu
->GetItemCount(), Reference
< XAccessible
>() );
61 m_pMenu
->AddEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
67 OAccessibleMenuBaseComponent::~OAccessibleMenuBaseComponent()
70 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
72 delete m_pExternalLock
;
73 m_pExternalLock
= NULL
;
78 bool OAccessibleMenuBaseComponent::IsEnabled()
85 bool OAccessibleMenuBaseComponent::IsFocused()
92 bool OAccessibleMenuBaseComponent::IsVisible()
99 bool OAccessibleMenuBaseComponent::IsSelected()
106 bool OAccessibleMenuBaseComponent::IsChecked()
113 void OAccessibleMenuBaseComponent::SetStates()
115 m_bEnabled
= IsEnabled();
116 m_bFocused
= IsFocused();
117 m_bVisible
= IsVisible();
118 m_bSelected
= IsSelected();
119 m_bChecked
= IsChecked();
124 void OAccessibleMenuBaseComponent::SetEnabled( bool bEnabled
)
126 if ( m_bEnabled
!= bEnabled
)
128 sal_Int16 nStateType
=AccessibleStateType::ENABLED
;
129 if (IsMenuHideDisabledEntries())
131 nStateType
= AccessibleStateType::VISIBLE
;
133 Any aOldValue
[2], aNewValue
[2];
136 aOldValue
[0] <<= AccessibleStateType::SENSITIVE
;
137 aOldValue
[1] <<= nStateType
;
141 aNewValue
[0] <<= nStateType
;
142 aNewValue
[1] <<= AccessibleStateType::SENSITIVE
;
144 m_bEnabled
= bEnabled
;
145 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[0], aNewValue
[0] );
146 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[1], aNewValue
[1] );
152 void OAccessibleMenuBaseComponent::SetFocused( bool bFocused
)
154 if ( m_bFocused
!= bFocused
)
156 Any aOldValue
, aNewValue
;
158 aOldValue
<<= AccessibleStateType::FOCUSED
;
160 aNewValue
<<= AccessibleStateType::FOCUSED
;
161 m_bFocused
= bFocused
;
162 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
168 void OAccessibleMenuBaseComponent::SetVisible( bool bVisible
)
170 if ( m_bVisible
!= bVisible
)
172 Any aOldValue
, aNewValue
;
174 aOldValue
<<= AccessibleStateType::VISIBLE
;
176 aNewValue
<<= AccessibleStateType::VISIBLE
;
177 m_bVisible
= bVisible
;
178 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
184 void OAccessibleMenuBaseComponent::SetSelected( bool bSelected
)
186 if ( m_bSelected
!= bSelected
)
188 Any aOldValue
, aNewValue
;
190 aOldValue
<<= AccessibleStateType::SELECTED
;
192 aNewValue
<<= AccessibleStateType::SELECTED
;
193 m_bSelected
= bSelected
;
194 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
200 void OAccessibleMenuBaseComponent::SetChecked( bool bChecked
)
202 if ( m_bChecked
!= bChecked
)
204 Any aOldValue
, aNewValue
;
206 aOldValue
<<= AccessibleStateType::CHECKED
;
208 aNewValue
<<= AccessibleStateType::CHECKED
;
209 m_bChecked
= bChecked
;
210 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
216 void OAccessibleMenuBaseComponent::UpdateEnabled( sal_Int32 i
, bool bEnabled
)
218 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
220 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
223 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
225 pComp
->SetEnabled( bEnabled
);
232 void OAccessibleMenuBaseComponent::UpdateFocused( sal_Int32 i
, bool bFocused
)
234 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
236 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
239 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
241 pComp
->SetFocused( bFocused
);
248 void OAccessibleMenuBaseComponent::UpdateVisible()
250 SetVisible( IsVisible() );
251 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
253 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
256 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
258 pComp
->SetVisible( pComp
->IsVisible() );
265 void OAccessibleMenuBaseComponent::UpdateSelected( sal_Int32 i
, bool bSelected
)
267 NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
269 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
271 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
274 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
276 pComp
->SetSelected( bSelected
);
283 void OAccessibleMenuBaseComponent::UpdateChecked( sal_Int32 i
, bool bChecked
)
285 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
287 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
290 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
292 pComp
->SetChecked( bChecked
);
299 void OAccessibleMenuBaseComponent::UpdateAccessibleName( sal_Int32 i
)
301 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
303 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
306 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
308 pComp
->SetAccessibleName( pComp
->GetAccessibleName() );
315 void OAccessibleMenuBaseComponent::UpdateItemText( sal_Int32 i
)
317 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
319 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
322 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
324 pComp
->SetItemText( pComp
->GetItemText() );
331 sal_Int32
OAccessibleMenuBaseComponent::GetChildCount()
333 return m_aAccessibleChildren
.size();
338 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChild( sal_Int32 i
)
340 Reference
< XAccessible
> xChild
= m_aAccessibleChildren
[i
];
345 // create a new child
346 OAccessibleMenuBaseComponent
* pChild
;
348 if ( m_pMenu
->GetItemType( (sal_uInt16
)i
) == MenuItemType::SEPARATOR
)
350 pChild
= new VCLXAccessibleMenuSeparator( m_pMenu
, (sal_uInt16
)i
);
354 PopupMenu
* pPopupMenu
= m_pMenu
->GetPopupMenu( m_pMenu
->GetItemId( (sal_uInt16
)i
) );
357 pChild
= new VCLXAccessibleMenu( m_pMenu
, (sal_uInt16
)i
, pPopupMenu
);
358 pPopupMenu
->SetAccessible( pChild
);
362 pChild
= new VCLXAccessibleMenuItem( m_pMenu
, (sal_uInt16
)i
);
371 // insert into menu item list
372 m_aAccessibleChildren
[i
] = xChild
;
381 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChildAt( const awt::Point
& rPoint
)
383 Reference
< XAccessible
> xChild
;
384 for ( sal_uInt32 i
= 0, nCount
= getAccessibleChildCount(); i
< nCount
; ++i
)
386 Reference
< XAccessible
> xAcc
= getAccessibleChild( i
);
389 Reference
< XAccessibleComponent
> xComp( xAcc
->getAccessibleContext(), UNO_QUERY
);
392 Rectangle aRect
= VCLRectangle( xComp
->getBounds() );
393 Point aPos
= VCLPoint( rPoint
);
394 if ( aRect
.IsInside( aPos
) )
408 void OAccessibleMenuBaseComponent::InsertChild( sal_Int32 i
)
410 if ( i
> (sal_Int32
)m_aAccessibleChildren
.size() )
411 i
= m_aAccessibleChildren
.size();
415 // insert entry in child list
416 m_aAccessibleChildren
.insert( m_aAccessibleChildren
.begin() + i
, Reference
< XAccessible
>() );
418 // update item position of accessible children
419 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
421 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
424 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
426 pComp
->SetItemPos( (sal_uInt16
)j
);
430 // send accessible child event
431 Reference
< XAccessible
> xChild( GetChild( i
) );
434 Any aOldValue
, aNewValue
;
435 aNewValue
<<= xChild
;
436 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
443 void OAccessibleMenuBaseComponent::RemoveChild( sal_Int32 i
)
445 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
447 // keep the accessible of the removed item
448 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
450 // remove entry in child list
451 m_aAccessibleChildren
.erase( m_aAccessibleChildren
.begin() + i
);
453 // update item position of accessible children
454 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
456 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
459 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
461 pComp
->SetItemPos( (sal_uInt16
)j
);
465 // send accessible child event
468 Any aOldValue
, aNewValue
;
469 aOldValue
<<= xChild
;
470 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
472 Reference
< XComponent
> xComponent( xChild
, UNO_QUERY
);
473 if ( xComponent
.is() )
474 xComponent
->dispose();
481 bool OAccessibleMenuBaseComponent::IsHighlighted()
488 bool OAccessibleMenuBaseComponent::IsChildHighlighted()
490 bool bChildHighlighted
= false;
492 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
494 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
497 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
498 if ( pComp
&& pComp
->IsHighlighted() )
500 bChildHighlighted
= true;
506 return bChildHighlighted
;
511 void OAccessibleMenuBaseComponent::SelectChild( sal_Int32 i
)
514 if ( getAccessibleRole() == AccessibleRole::MENU
&& !IsPopupMenuOpen() )
517 // highlight the child
519 m_pMenu
->HighlightItem( (sal_uInt16
)i
);
524 void OAccessibleMenuBaseComponent::DeSelectAll()
527 m_pMenu
->DeHighlight();
532 bool OAccessibleMenuBaseComponent::IsChildSelected( sal_Int32 i
)
534 bool bSelected
= false;
536 if ( m_pMenu
&& m_pMenu
->IsHighlighted( (sal_uInt16
)i
) )
544 void OAccessibleMenuBaseComponent::Select()
550 void OAccessibleMenuBaseComponent::DeSelect()
556 void OAccessibleMenuBaseComponent::Click()
562 bool OAccessibleMenuBaseComponent::IsPopupMenuOpen()
569 IMPL_LINK( OAccessibleMenuBaseComponent
, MenuEventListener
, VclSimpleEvent
*, pEvent
)
571 OSL_ENSURE( pEvent
&& pEvent
->ISA( VclMenuEvent
), "OAccessibleMenuBaseComponent - Unknown MenuEvent!" );
572 if ( pEvent
&& pEvent
->ISA( VclMenuEvent
) )
574 OSL_ENSURE( static_cast<VclMenuEvent
*>(pEvent
)->GetMenu(), "OAccessibleMenuBaseComponent - Menu?" );
575 ProcessMenuEvent( *static_cast<VclMenuEvent
*>(pEvent
) );
582 void OAccessibleMenuBaseComponent::ProcessMenuEvent( const VclMenuEvent
& rVclMenuEvent
)
584 sal_uInt16 nItemPos
= rVclMenuEvent
.GetItemPos();
586 switch ( rVclMenuEvent
.GetId() )
588 case VCLEVENT_MENU_SHOW
:
589 case VCLEVENT_MENU_HIDE
:
594 case VCLEVENT_MENU_HIGHLIGHT
:
597 UpdateFocused( nItemPos
, true );
598 UpdateSelected( nItemPos
, true );
601 case VCLEVENT_MENU_DEHIGHLIGHT
:
603 UpdateFocused( nItemPos
, false );
604 UpdateSelected( nItemPos
, false );
607 case VCLEVENT_MENU_SUBMENUACTIVATE
:
611 case VCLEVENT_MENU_SUBMENUDEACTIVATE
:
613 UpdateFocused( nItemPos
, true );
616 case VCLEVENT_MENU_ENABLE
:
618 UpdateEnabled( nItemPos
, true );
621 case VCLEVENT_MENU_DISABLE
:
623 UpdateEnabled( nItemPos
, false );
626 case VCLEVENT_MENU_SUBMENUCHANGED
:
628 RemoveChild( nItemPos
);
629 InsertChild( nItemPos
);
632 case VCLEVENT_MENU_INSERTITEM
:
634 InsertChild( nItemPos
);
637 case VCLEVENT_MENU_REMOVEITEM
:
639 RemoveChild( nItemPos
);
642 case VCLEVENT_MENU_ACCESSIBLENAMECHANGED
:
644 UpdateAccessibleName( nItemPos
);
647 case VCLEVENT_MENU_ITEMTEXTCHANGED
:
649 UpdateAccessibleName( nItemPos
);
650 UpdateItemText( nItemPos
);
653 case VCLEVENT_MENU_ITEMCHECKED
:
655 UpdateChecked( nItemPos
, true );
658 case VCLEVENT_MENU_ITEMUNCHECKED
:
660 UpdateChecked( nItemPos
, false );
663 case VCLEVENT_OBJECT_DYING
:
667 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
671 // dispose all menu items
672 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
674 Reference
< XComponent
> xComponent( m_aAccessibleChildren
[i
], UNO_QUERY
);
675 if ( xComponent
.is() )
676 xComponent
->dispose();
678 m_aAccessibleChildren
.clear();
693 IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleMenuBaseComponent
, AccessibleExtendedComponentHelper_BASE
, OAccessibleMenuBaseComponent_BASE
)
699 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleMenuBaseComponent
, AccessibleExtendedComponentHelper_BASE
, OAccessibleMenuBaseComponent_BASE
)
705 void OAccessibleMenuBaseComponent::disposing()
707 AccessibleExtendedComponentHelper_BASE::disposing();
711 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
715 // dispose all menu items
716 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
718 Reference
< XComponent
> xComponent( m_aAccessibleChildren
[i
], UNO_QUERY
);
719 if ( xComponent
.is() )
720 xComponent
->dispose();
722 m_aAccessibleChildren
.clear();
730 sal_Bool
OAccessibleMenuBaseComponent::supportsService( const OUString
& rServiceName
) throw (RuntimeException
, std::exception
)
732 return cppu::supportsService(this, rServiceName
);
739 Reference
< XAccessibleContext
> OAccessibleMenuBaseComponent::getAccessibleContext( ) throw (RuntimeException
, std::exception
)
741 OExternalLockGuard
aGuard( this );
747 // XAccessibleContext
750 Reference
< XAccessibleStateSet
> OAccessibleMenuBaseComponent::getAccessibleStateSet( ) throw (RuntimeException
, std::exception
)
752 OExternalLockGuard
aGuard( this );
754 utl::AccessibleStateSetHelper
* pStateSetHelper
= new utl::AccessibleStateSetHelper
;
755 Reference
< XAccessibleStateSet
> xSet
= pStateSetHelper
;
757 if ( !rBHelper
.bDisposed
&& !rBHelper
.bInDispose
)
759 FillAccessibleStateSet( *pStateSetHelper
);
763 pStateSetHelper
->AddState( AccessibleStateType::DEFUNC
);
771 bool OAccessibleMenuBaseComponent::IsMenuHideDisabledEntries()
776 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */