1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: accessiblemenubasecomponent.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_accessibility.hxx"
34 // includes --------------------------------------------------------------
35 #include <accessibility/standard/accessiblemenubasecomponent.hxx>
36 #include <accessibility/standard/vclxaccessiblemenu.hxx>
37 #include <accessibility/standard/vclxaccessiblemenuitem.hxx>
38 #include <accessibility/standard/vclxaccessiblemenuseparator.hxx>
39 #include <toolkit/helper/externallock.hxx>
40 #include <toolkit/helper/convert.hxx>
42 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
43 #include <com/sun/star/accessibility/AccessibleRole.hpp>
44 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
46 #include <unotools/accessiblestatesethelper.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/window.hxx>
49 #include <vcl/menu.hxx>
50 #include <tools/debug.hxx>
52 using namespace ::com::sun::star
;
53 using namespace ::com::sun::star::lang
;
54 using namespace ::com::sun::star::uno
;
55 using namespace ::com::sun::star::accessibility
;
56 using namespace ::comphelper
;
59 // -----------------------------------------------------------------------------
60 // OAccessibleMenuBaseComponent
61 // -----------------------------------------------------------------------------
63 OAccessibleMenuBaseComponent::OAccessibleMenuBaseComponent( Menu
* pMenu
)
64 :AccessibleExtendedComponentHelper_BASE( new VCLExternalSolarLock() )
66 ,m_bEnabled( sal_False
)
67 ,m_bFocused( sal_False
)
68 ,m_bVisible( sal_False
)
69 ,m_bSelected( sal_False
)
70 ,m_bChecked( sal_False
)
72 m_pExternalLock
= static_cast< VCLExternalSolarLock
* >( getExternalLock() );
76 m_aAccessibleChildren
.assign( m_pMenu
->GetItemCount(), Reference
< XAccessible
>() );
77 m_pMenu
->AddEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
81 // -----------------------------------------------------------------------------
83 OAccessibleMenuBaseComponent::~OAccessibleMenuBaseComponent()
86 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
88 delete m_pExternalLock
;
89 m_pExternalLock
= NULL
;
92 // -----------------------------------------------------------------------------
94 sal_Bool
OAccessibleMenuBaseComponent::IsEnabled()
99 // -----------------------------------------------------------------------------
101 sal_Bool
OAccessibleMenuBaseComponent::IsFocused()
106 // -----------------------------------------------------------------------------
108 sal_Bool
OAccessibleMenuBaseComponent::IsVisible()
113 // -----------------------------------------------------------------------------
115 sal_Bool
OAccessibleMenuBaseComponent::IsSelected()
120 // -----------------------------------------------------------------------------
122 sal_Bool
OAccessibleMenuBaseComponent::IsChecked()
127 // -----------------------------------------------------------------------------
129 void OAccessibleMenuBaseComponent::SetStates()
131 m_bEnabled
= IsEnabled();
132 m_bFocused
= IsFocused();
133 m_bVisible
= IsVisible();
134 m_bSelected
= IsSelected();
135 m_bChecked
= IsChecked();
138 // -----------------------------------------------------------------------------
140 void OAccessibleMenuBaseComponent::SetEnabled( sal_Bool bEnabled
)
142 if ( m_bEnabled
!= bEnabled
)
144 Any aOldValue
[2], aNewValue
[2];
147 aOldValue
[0] <<= AccessibleStateType::SENSITIVE
;
148 aOldValue
[1] <<= AccessibleStateType::ENABLED
;
152 aNewValue
[0] <<= AccessibleStateType::ENABLED
;
153 aNewValue
[1] <<= AccessibleStateType::SENSITIVE
;
155 m_bEnabled
= bEnabled
;
156 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[0], aNewValue
[0] );
157 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[1], aNewValue
[1] );
161 // -----------------------------------------------------------------------------
163 void OAccessibleMenuBaseComponent::SetFocused( sal_Bool bFocused
)
165 if ( m_bFocused
!= bFocused
)
167 Any aOldValue
, aNewValue
;
169 aOldValue
<<= AccessibleStateType::FOCUSED
;
171 aNewValue
<<= AccessibleStateType::FOCUSED
;
172 m_bFocused
= bFocused
;
173 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
177 // -----------------------------------------------------------------------------
179 void OAccessibleMenuBaseComponent::SetVisible( sal_Bool bVisible
)
181 if ( m_bVisible
!= bVisible
)
183 Any aOldValue
, aNewValue
;
185 aOldValue
<<= AccessibleStateType::VISIBLE
;
187 aNewValue
<<= AccessibleStateType::VISIBLE
;
188 m_bVisible
= bVisible
;
189 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
193 // -----------------------------------------------------------------------------
195 void OAccessibleMenuBaseComponent::SetSelected( sal_Bool bSelected
)
197 if ( m_bSelected
!= bSelected
)
199 Any aOldValue
, aNewValue
;
201 aOldValue
<<= AccessibleStateType::SELECTED
;
203 aNewValue
<<= AccessibleStateType::SELECTED
;
204 m_bSelected
= bSelected
;
205 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
209 // -----------------------------------------------------------------------------
211 void OAccessibleMenuBaseComponent::SetChecked( sal_Bool bChecked
)
213 if ( m_bChecked
!= bChecked
)
215 Any aOldValue
, aNewValue
;
217 aOldValue
<<= AccessibleStateType::CHECKED
;
219 aNewValue
<<= AccessibleStateType::CHECKED
;
220 m_bChecked
= bChecked
;
221 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
225 // -----------------------------------------------------------------------------
227 void OAccessibleMenuBaseComponent::UpdateEnabled( sal_Int32 i
, sal_Bool bEnabled
)
229 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
231 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
234 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
236 pComp
->SetEnabled( bEnabled
);
241 // -----------------------------------------------------------------------------
243 void OAccessibleMenuBaseComponent::UpdateFocused( sal_Int32 i
, sal_Bool bFocused
)
245 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
247 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
250 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
252 pComp
->SetFocused( bFocused
);
257 // -----------------------------------------------------------------------------
259 void OAccessibleMenuBaseComponent::UpdateVisible()
261 SetVisible( IsVisible() );
262 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
264 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
267 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
269 pComp
->SetVisible( pComp
->IsVisible() );
274 // -----------------------------------------------------------------------------
276 void OAccessibleMenuBaseComponent::UpdateSelected( sal_Int32 i
, sal_Bool bSelected
)
278 NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
280 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
282 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
285 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
287 pComp
->SetSelected( bSelected
);
292 // -----------------------------------------------------------------------------
294 void OAccessibleMenuBaseComponent::UpdateChecked( sal_Int32 i
, sal_Bool bChecked
)
296 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
298 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
301 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
303 pComp
->SetChecked( bChecked
);
308 // -----------------------------------------------------------------------------
310 void OAccessibleMenuBaseComponent::UpdateAccessibleName( sal_Int32 i
)
312 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
314 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
317 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
319 pComp
->SetAccessibleName( pComp
->GetAccessibleName() );
324 // -----------------------------------------------------------------------------
326 void OAccessibleMenuBaseComponent::UpdateItemText( sal_Int32 i
)
328 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
330 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
333 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
335 pComp
->SetItemText( pComp
->GetItemText() );
340 // -----------------------------------------------------------------------------
342 sal_Int32
OAccessibleMenuBaseComponent::GetChildCount()
344 return m_aAccessibleChildren
.size();
347 // -----------------------------------------------------------------------------
349 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChild( sal_Int32 i
)
351 Reference
< XAccessible
> xChild
= m_aAccessibleChildren
[i
];
356 // create a new child
357 OAccessibleMenuBaseComponent
* pChild
;
359 if ( m_pMenu
->GetItemType( (USHORT
)i
) == MENUITEM_SEPARATOR
)
361 pChild
= new VCLXAccessibleMenuSeparator( m_pMenu
, (sal_uInt16
)i
);
365 PopupMenu
* pPopupMenu
= m_pMenu
->GetPopupMenu( m_pMenu
->GetItemId( (USHORT
)i
) );
368 pChild
= new VCLXAccessibleMenu( m_pMenu
, (sal_uInt16
)i
, pPopupMenu
);
369 pPopupMenu
->SetAccessible( pChild
);
373 pChild
= new VCLXAccessibleMenuItem( m_pMenu
, (sal_uInt16
)i
);
382 // insert into menu item list
383 m_aAccessibleChildren
[i
] = xChild
;
390 // -----------------------------------------------------------------------------
392 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChildAt( const awt::Point
& rPoint
)
394 Reference
< XAccessible
> xChild
;
395 for ( sal_uInt32 i
= 0, nCount
= getAccessibleChildCount(); i
< nCount
; ++i
)
397 Reference
< XAccessible
> xAcc
= getAccessibleChild( i
);
400 Reference
< XAccessibleComponent
> xComp( xAcc
->getAccessibleContext(), UNO_QUERY
);
403 Rectangle aRect
= VCLRectangle( xComp
->getBounds() );
404 Point aPos
= VCLPoint( rPoint
);
405 if ( aRect
.IsInside( aPos
) )
417 // -----------------------------------------------------------------------------
419 void OAccessibleMenuBaseComponent::InsertChild( sal_Int32 i
)
421 if ( i
> (sal_Int32
)m_aAccessibleChildren
.size() )
422 i
= m_aAccessibleChildren
.size();
426 // insert entry in child list
427 m_aAccessibleChildren
.insert( m_aAccessibleChildren
.begin() + i
, Reference
< XAccessible
>() );
429 // update item position of accessible children
430 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
432 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
435 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
437 pComp
->SetItemPos( (sal_uInt16
)j
);
441 // send accessible child event
442 Reference
< XAccessible
> xChild( GetChild( i
) );
445 Any aOldValue
, aNewValue
;
446 aNewValue
<<= xChild
;
447 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
452 // -----------------------------------------------------------------------------
454 void OAccessibleMenuBaseComponent::RemoveChild( sal_Int32 i
)
456 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
458 // keep the accessible of the removed item
459 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
461 // remove entry in child list
462 m_aAccessibleChildren
.erase( m_aAccessibleChildren
.begin() + i
);
464 // update item position of accessible children
465 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
467 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
470 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
472 pComp
->SetItemPos( (sal_uInt16
)j
);
476 // send accessible child event
479 Any aOldValue
, aNewValue
;
480 aOldValue
<<= xChild
;
481 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
483 Reference
< XComponent
> xComponent( xChild
, UNO_QUERY
);
484 if ( xComponent
.is() )
485 xComponent
->dispose();
490 // -----------------------------------------------------------------------------
492 sal_Bool
OAccessibleMenuBaseComponent::IsHighlighted()
497 // -----------------------------------------------------------------------------
499 sal_Bool
OAccessibleMenuBaseComponent::IsChildHighlighted()
501 sal_Bool bChildHighlighted
= sal_False
;
503 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
505 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
508 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
509 if ( pComp
&& pComp
->IsHighlighted() )
511 bChildHighlighted
= sal_True
;
517 return bChildHighlighted
;
520 // -----------------------------------------------------------------------------
522 void OAccessibleMenuBaseComponent::SelectChild( sal_Int32 i
)
525 if ( getAccessibleRole() == AccessibleRole::MENU
&& !IsPopupMenuOpen() )
528 // highlight the child
530 m_pMenu
->HighlightItem( (USHORT
)i
);
533 // -----------------------------------------------------------------------------
535 void OAccessibleMenuBaseComponent::DeSelectAll()
538 m_pMenu
->DeHighlight();
541 // -----------------------------------------------------------------------------
543 sal_Bool
OAccessibleMenuBaseComponent::IsChildSelected( sal_Int32 i
)
545 sal_Bool bSelected
= sal_False
;
547 if ( m_pMenu
&& m_pMenu
->IsHighlighted( (USHORT
)i
) )
548 bSelected
= sal_True
;
553 // -----------------------------------------------------------------------------
555 void OAccessibleMenuBaseComponent::Select()
559 // -----------------------------------------------------------------------------
561 void OAccessibleMenuBaseComponent::DeSelect()
565 // -----------------------------------------------------------------------------
567 void OAccessibleMenuBaseComponent::Click()
571 // -----------------------------------------------------------------------------
573 sal_Bool
OAccessibleMenuBaseComponent::IsPopupMenuOpen()
578 // -----------------------------------------------------------------------------
580 IMPL_LINK( OAccessibleMenuBaseComponent
, MenuEventListener
, VclSimpleEvent
*, pEvent
)
582 DBG_ASSERT( pEvent
&& pEvent
->ISA( VclMenuEvent
), "OAccessibleMenuBaseComponent - Unknown MenuEvent!" );
583 if ( pEvent
&& pEvent
->ISA( VclMenuEvent
) )
585 DBG_ASSERT( ((VclMenuEvent
*)pEvent
)->GetMenu(), "OAccessibleMenuBaseComponent - Menu?" );
586 ProcessMenuEvent( *(VclMenuEvent
*)pEvent
);
591 // -----------------------------------------------------------------------------
593 void OAccessibleMenuBaseComponent::ProcessMenuEvent( const VclMenuEvent
& rVclMenuEvent
)
595 sal_uInt16 nItemPos
= rVclMenuEvent
.GetItemPos();
597 switch ( rVclMenuEvent
.GetId() )
599 case VCLEVENT_MENU_SHOW
:
600 case VCLEVENT_MENU_HIDE
:
605 case VCLEVENT_MENU_HIGHLIGHT
:
607 SetFocused( sal_False
);
608 UpdateFocused( nItemPos
, sal_True
);
609 UpdateSelected( nItemPos
, sal_True
);
612 case VCLEVENT_MENU_DEHIGHLIGHT
:
614 UpdateFocused( nItemPos
, sal_False
);
615 UpdateSelected( nItemPos
, sal_False
);
618 case VCLEVENT_MENU_SUBMENUACTIVATE
:
622 case VCLEVENT_MENU_SUBMENUDEACTIVATE
:
624 UpdateFocused( nItemPos
, sal_True
);
627 case VCLEVENT_MENU_ENABLE
:
629 UpdateEnabled( nItemPos
, sal_True
);
632 case VCLEVENT_MENU_DISABLE
:
634 UpdateEnabled( nItemPos
, sal_False
);
637 case VCLEVENT_MENU_SUBMENUCHANGED
:
639 RemoveChild( nItemPos
);
640 InsertChild( nItemPos
);
643 case VCLEVENT_MENU_INSERTITEM
:
645 InsertChild( nItemPos
);
648 case VCLEVENT_MENU_REMOVEITEM
:
650 RemoveChild( nItemPos
);
653 case VCLEVENT_MENU_ACCESSIBLENAMECHANGED
:
655 UpdateAccessibleName( nItemPos
);
658 case VCLEVENT_MENU_ITEMTEXTCHANGED
:
660 UpdateAccessibleName( nItemPos
);
661 UpdateItemText( nItemPos
);
664 case VCLEVENT_MENU_ITEMCHECKED
:
666 UpdateChecked( nItemPos
, sal_True
);
669 case VCLEVENT_MENU_ITEMUNCHECKED
:
671 UpdateChecked( nItemPos
, sal_False
);
674 case VCLEVENT_OBJECT_DYING
:
678 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
682 // dispose all menu items
683 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
685 Reference
< XComponent
> xComponent( m_aAccessibleChildren
[i
], UNO_QUERY
);
686 if ( xComponent
.is() )
687 xComponent
->dispose();
689 m_aAccessibleChildren
.clear();
700 // -----------------------------------------------------------------------------
702 // -----------------------------------------------------------------------------
704 IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleMenuBaseComponent
, AccessibleExtendedComponentHelper_BASE
, OAccessibleMenuBaseComponent_BASE
)
706 // -----------------------------------------------------------------------------
708 // -----------------------------------------------------------------------------
710 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleMenuBaseComponent
, AccessibleExtendedComponentHelper_BASE
, OAccessibleMenuBaseComponent_BASE
)
712 // -----------------------------------------------------------------------------
714 // -----------------------------------------------------------------------------
716 void OAccessibleMenuBaseComponent::disposing()
718 AccessibleExtendedComponentHelper_BASE::disposing();
722 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
726 // dispose all menu items
727 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
729 Reference
< XComponent
> xComponent( m_aAccessibleChildren
[i
], UNO_QUERY
);
730 if ( xComponent
.is() )
731 xComponent
->dispose();
733 m_aAccessibleChildren
.clear();
737 // -----------------------------------------------------------------------------
739 // -----------------------------------------------------------------------------
741 sal_Bool
OAccessibleMenuBaseComponent::supportsService( const ::rtl::OUString
& rServiceName
) throw (RuntimeException
)
743 Sequence
< ::rtl::OUString
> aNames( getSupportedServiceNames() );
744 const ::rtl::OUString
* pNames
= aNames
.getConstArray();
745 const ::rtl::OUString
* pEnd
= pNames
+ aNames
.getLength();
746 for ( ; pNames
!= pEnd
&& !pNames
->equals( rServiceName
); ++pNames
)
749 return pNames
!= pEnd
;
752 // -----------------------------------------------------------------------------
754 // -----------------------------------------------------------------------------
756 Reference
< XAccessibleContext
> OAccessibleMenuBaseComponent::getAccessibleContext( ) throw (RuntimeException
)
758 OExternalLockGuard
aGuard( this );
763 // -----------------------------------------------------------------------------
764 // XAccessibleContext
765 // -----------------------------------------------------------------------------
767 Reference
< XAccessibleStateSet
> OAccessibleMenuBaseComponent::getAccessibleStateSet( ) throw (RuntimeException
)
769 OExternalLockGuard
aGuard( this );
771 utl::AccessibleStateSetHelper
* pStateSetHelper
= new utl::AccessibleStateSetHelper
;
772 Reference
< XAccessibleStateSet
> xSet
= pStateSetHelper
;
774 if ( !rBHelper
.bDisposed
&& !rBHelper
.bInDispose
)
776 FillAccessibleStateSet( *pStateSetHelper
);
780 pStateSetHelper
->AddState( AccessibleStateType::DEFUNC
);
786 // -----------------------------------------------------------------------------