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
;
43 // -----------------------------------------------------------------------------
44 // OAccessibleMenuBaseComponent
45 // -----------------------------------------------------------------------------
47 OAccessibleMenuBaseComponent::OAccessibleMenuBaseComponent( Menu
* pMenu
)
48 :AccessibleExtendedComponentHelper_BASE( new VCLExternalSolarLock() )
50 ,m_bEnabled( sal_False
)
51 ,m_bFocused( sal_False
)
52 ,m_bVisible( sal_False
)
53 ,m_bSelected( sal_False
)
54 ,m_bChecked( sal_False
)
56 m_pExternalLock
= static_cast< VCLExternalSolarLock
* >( getExternalLock() );
60 m_aAccessibleChildren
.assign( m_pMenu
->GetItemCount(), Reference
< XAccessible
>() );
61 m_pMenu
->AddEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
65 // -----------------------------------------------------------------------------
67 OAccessibleMenuBaseComponent::~OAccessibleMenuBaseComponent()
70 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
72 delete m_pExternalLock
;
73 m_pExternalLock
= NULL
;
76 // -----------------------------------------------------------------------------
78 sal_Bool
OAccessibleMenuBaseComponent::IsEnabled()
83 // -----------------------------------------------------------------------------
85 sal_Bool
OAccessibleMenuBaseComponent::IsFocused()
90 // -----------------------------------------------------------------------------
92 sal_Bool
OAccessibleMenuBaseComponent::IsVisible()
97 // -----------------------------------------------------------------------------
99 sal_Bool
OAccessibleMenuBaseComponent::IsSelected()
104 // -----------------------------------------------------------------------------
106 sal_Bool
OAccessibleMenuBaseComponent::IsChecked()
111 // -----------------------------------------------------------------------------
113 void OAccessibleMenuBaseComponent::SetStates()
115 m_bEnabled
= IsEnabled();
116 m_bFocused
= IsFocused();
117 m_bVisible
= IsVisible();
118 m_bSelected
= IsSelected();
119 m_bChecked
= IsChecked();
122 // -----------------------------------------------------------------------------
124 void OAccessibleMenuBaseComponent::SetEnabled( sal_Bool bEnabled
)
126 if ( m_bEnabled
!= bEnabled
)
128 Any aOldValue
[2], aNewValue
[2];
131 aOldValue
[0] <<= AccessibleStateType::SENSITIVE
;
132 aOldValue
[1] <<= AccessibleStateType::ENABLED
;
136 aNewValue
[0] <<= AccessibleStateType::ENABLED
;
137 aNewValue
[1] <<= AccessibleStateType::SENSITIVE
;
139 m_bEnabled
= bEnabled
;
140 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[0], aNewValue
[0] );
141 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[1], aNewValue
[1] );
145 // -----------------------------------------------------------------------------
147 void OAccessibleMenuBaseComponent::SetFocused( sal_Bool bFocused
)
149 if ( m_bFocused
!= bFocused
)
151 Any aOldValue
, aNewValue
;
153 aOldValue
<<= AccessibleStateType::FOCUSED
;
155 aNewValue
<<= AccessibleStateType::FOCUSED
;
156 m_bFocused
= bFocused
;
157 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
161 // -----------------------------------------------------------------------------
163 void OAccessibleMenuBaseComponent::SetVisible( sal_Bool bVisible
)
165 if ( m_bVisible
!= bVisible
)
167 Any aOldValue
, aNewValue
;
169 aOldValue
<<= AccessibleStateType::VISIBLE
;
171 aNewValue
<<= AccessibleStateType::VISIBLE
;
172 m_bVisible
= bVisible
;
173 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
177 // -----------------------------------------------------------------------------
179 void OAccessibleMenuBaseComponent::SetSelected( sal_Bool bSelected
)
181 if ( m_bSelected
!= bSelected
)
183 Any aOldValue
, aNewValue
;
185 aOldValue
<<= AccessibleStateType::SELECTED
;
187 aNewValue
<<= AccessibleStateType::SELECTED
;
188 m_bSelected
= bSelected
;
189 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
193 // -----------------------------------------------------------------------------
195 void OAccessibleMenuBaseComponent::SetChecked( sal_Bool bChecked
)
197 if ( m_bChecked
!= bChecked
)
199 Any aOldValue
, aNewValue
;
201 aOldValue
<<= AccessibleStateType::CHECKED
;
203 aNewValue
<<= AccessibleStateType::CHECKED
;
204 m_bChecked
= bChecked
;
205 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
209 // -----------------------------------------------------------------------------
211 void OAccessibleMenuBaseComponent::UpdateEnabled( sal_Int32 i
, sal_Bool bEnabled
)
213 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
215 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
218 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
220 pComp
->SetEnabled( bEnabled
);
225 // -----------------------------------------------------------------------------
227 void OAccessibleMenuBaseComponent::UpdateFocused( sal_Int32 i
, sal_Bool bFocused
)
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
->SetFocused( bFocused
);
241 // -----------------------------------------------------------------------------
243 void OAccessibleMenuBaseComponent::UpdateVisible()
245 SetVisible( IsVisible() );
246 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
248 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
251 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
253 pComp
->SetVisible( pComp
->IsVisible() );
258 // -----------------------------------------------------------------------------
260 void OAccessibleMenuBaseComponent::UpdateSelected( sal_Int32 i
, sal_Bool bSelected
)
262 NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
264 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
266 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
269 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
271 pComp
->SetSelected( bSelected
);
276 // -----------------------------------------------------------------------------
278 void OAccessibleMenuBaseComponent::UpdateChecked( sal_Int32 i
, sal_Bool bChecked
)
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
->SetChecked( bChecked
);
292 // -----------------------------------------------------------------------------
294 void OAccessibleMenuBaseComponent::UpdateAccessibleName( sal_Int32 i
)
296 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
298 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
301 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xChild
.get() );
303 pComp
->SetAccessibleName( pComp
->GetAccessibleName() );
308 // -----------------------------------------------------------------------------
310 void OAccessibleMenuBaseComponent::UpdateItemText( 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
->SetItemText( pComp
->GetItemText() );
324 // -----------------------------------------------------------------------------
326 sal_Int32
OAccessibleMenuBaseComponent::GetChildCount()
328 return m_aAccessibleChildren
.size();
331 // -----------------------------------------------------------------------------
333 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChild( sal_Int32 i
)
335 Reference
< XAccessible
> xChild
= m_aAccessibleChildren
[i
];
340 // create a new child
341 OAccessibleMenuBaseComponent
* pChild
;
343 if ( m_pMenu
->GetItemType( (sal_uInt16
)i
) == MENUITEM_SEPARATOR
)
345 pChild
= new VCLXAccessibleMenuSeparator( m_pMenu
, (sal_uInt16
)i
);
349 PopupMenu
* pPopupMenu
= m_pMenu
->GetPopupMenu( m_pMenu
->GetItemId( (sal_uInt16
)i
) );
352 pChild
= new VCLXAccessibleMenu( m_pMenu
, (sal_uInt16
)i
, pPopupMenu
);
353 pPopupMenu
->SetAccessible( pChild
);
357 pChild
= new VCLXAccessibleMenuItem( m_pMenu
, (sal_uInt16
)i
);
366 // insert into menu item list
367 m_aAccessibleChildren
[i
] = xChild
;
374 // -----------------------------------------------------------------------------
376 Reference
< XAccessible
> OAccessibleMenuBaseComponent::GetChildAt( const awt::Point
& rPoint
)
378 Reference
< XAccessible
> xChild
;
379 for ( sal_uInt32 i
= 0, nCount
= getAccessibleChildCount(); i
< nCount
; ++i
)
381 Reference
< XAccessible
> xAcc
= getAccessibleChild( i
);
384 Reference
< XAccessibleComponent
> xComp( xAcc
->getAccessibleContext(), UNO_QUERY
);
387 Rectangle aRect
= VCLRectangle( xComp
->getBounds() );
388 Point aPos
= VCLPoint( rPoint
);
389 if ( aRect
.IsInside( aPos
) )
401 // -----------------------------------------------------------------------------
403 void OAccessibleMenuBaseComponent::InsertChild( sal_Int32 i
)
405 if ( i
> (sal_Int32
)m_aAccessibleChildren
.size() )
406 i
= m_aAccessibleChildren
.size();
410 // insert entry in child list
411 m_aAccessibleChildren
.insert( m_aAccessibleChildren
.begin() + i
, Reference
< XAccessible
>() );
413 // update item position of accessible children
414 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
416 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
419 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
421 pComp
->SetItemPos( (sal_uInt16
)j
);
425 // send accessible child event
426 Reference
< XAccessible
> xChild( GetChild( i
) );
429 Any aOldValue
, aNewValue
;
430 aNewValue
<<= xChild
;
431 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
436 // -----------------------------------------------------------------------------
438 void OAccessibleMenuBaseComponent::RemoveChild( sal_Int32 i
)
440 if ( i
>= 0 && i
< (sal_Int32
)m_aAccessibleChildren
.size() )
442 // keep the accessible of the removed item
443 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
445 // remove entry in child list
446 m_aAccessibleChildren
.erase( m_aAccessibleChildren
.begin() + i
);
448 // update item position of accessible children
449 for ( sal_uInt32 j
= i
, nCount
= m_aAccessibleChildren
.size(); j
< nCount
; ++j
)
451 Reference
< XAccessible
> xAcc( m_aAccessibleChildren
[j
] );
454 OAccessibleMenuItemComponent
* pComp
= static_cast< OAccessibleMenuItemComponent
* >( xAcc
.get() );
456 pComp
->SetItemPos( (sal_uInt16
)j
);
460 // send accessible child event
463 Any aOldValue
, aNewValue
;
464 aOldValue
<<= xChild
;
465 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
467 Reference
< XComponent
> xComponent( xChild
, UNO_QUERY
);
468 if ( xComponent
.is() )
469 xComponent
->dispose();
474 // -----------------------------------------------------------------------------
476 sal_Bool
OAccessibleMenuBaseComponent::IsHighlighted()
481 // -----------------------------------------------------------------------------
483 sal_Bool
OAccessibleMenuBaseComponent::IsChildHighlighted()
485 sal_Bool bChildHighlighted
= sal_False
;
487 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
489 Reference
< XAccessible
> xChild( m_aAccessibleChildren
[i
] );
492 OAccessibleMenuBaseComponent
* pComp
= static_cast< OAccessibleMenuBaseComponent
* >( xChild
.get() );
493 if ( pComp
&& pComp
->IsHighlighted() )
495 bChildHighlighted
= sal_True
;
501 return bChildHighlighted
;
504 // -----------------------------------------------------------------------------
506 void OAccessibleMenuBaseComponent::SelectChild( sal_Int32 i
)
509 if ( getAccessibleRole() == AccessibleRole::MENU
&& !IsPopupMenuOpen() )
512 // highlight the child
514 m_pMenu
->HighlightItem( (sal_uInt16
)i
);
517 // -----------------------------------------------------------------------------
519 void OAccessibleMenuBaseComponent::DeSelectAll()
522 m_pMenu
->DeHighlight();
525 // -----------------------------------------------------------------------------
527 sal_Bool
OAccessibleMenuBaseComponent::IsChildSelected( sal_Int32 i
)
529 sal_Bool bSelected
= sal_False
;
531 if ( m_pMenu
&& m_pMenu
->IsHighlighted( (sal_uInt16
)i
) )
532 bSelected
= sal_True
;
537 // -----------------------------------------------------------------------------
539 void OAccessibleMenuBaseComponent::Select()
543 // -----------------------------------------------------------------------------
545 void OAccessibleMenuBaseComponent::DeSelect()
549 // -----------------------------------------------------------------------------
551 void OAccessibleMenuBaseComponent::Click()
555 // -----------------------------------------------------------------------------
557 sal_Bool
OAccessibleMenuBaseComponent::IsPopupMenuOpen()
562 // -----------------------------------------------------------------------------
564 IMPL_LINK( OAccessibleMenuBaseComponent
, MenuEventListener
, VclSimpleEvent
*, pEvent
)
566 OSL_ENSURE( pEvent
&& pEvent
->ISA( VclMenuEvent
), "OAccessibleMenuBaseComponent - Unknown MenuEvent!" );
567 if ( pEvent
&& pEvent
->ISA( VclMenuEvent
) )
569 OSL_ENSURE( ((VclMenuEvent
*)pEvent
)->GetMenu(), "OAccessibleMenuBaseComponent - Menu?" );
570 ProcessMenuEvent( *(VclMenuEvent
*)pEvent
);
575 // -----------------------------------------------------------------------------
577 void OAccessibleMenuBaseComponent::ProcessMenuEvent( const VclMenuEvent
& rVclMenuEvent
)
579 sal_uInt16 nItemPos
= rVclMenuEvent
.GetItemPos();
581 switch ( rVclMenuEvent
.GetId() )
583 case VCLEVENT_MENU_SHOW
:
584 case VCLEVENT_MENU_HIDE
:
589 case VCLEVENT_MENU_HIGHLIGHT
:
591 SetFocused( sal_False
);
592 UpdateFocused( nItemPos
, sal_True
);
593 UpdateSelected( nItemPos
, sal_True
);
596 case VCLEVENT_MENU_DEHIGHLIGHT
:
598 UpdateFocused( nItemPos
, sal_False
);
599 UpdateSelected( nItemPos
, sal_False
);
602 case VCLEVENT_MENU_SUBMENUACTIVATE
:
606 case VCLEVENT_MENU_SUBMENUDEACTIVATE
:
608 UpdateFocused( nItemPos
, sal_True
);
611 case VCLEVENT_MENU_ENABLE
:
613 UpdateEnabled( nItemPos
, sal_True
);
616 case VCLEVENT_MENU_DISABLE
:
618 UpdateEnabled( nItemPos
, sal_False
);
621 case VCLEVENT_MENU_SUBMENUCHANGED
:
623 RemoveChild( nItemPos
);
624 InsertChild( nItemPos
);
627 case VCLEVENT_MENU_INSERTITEM
:
629 InsertChild( nItemPos
);
632 case VCLEVENT_MENU_REMOVEITEM
:
634 RemoveChild( nItemPos
);
637 case VCLEVENT_MENU_ACCESSIBLENAMECHANGED
:
639 UpdateAccessibleName( nItemPos
);
642 case VCLEVENT_MENU_ITEMTEXTCHANGED
:
644 UpdateAccessibleName( nItemPos
);
645 UpdateItemText( nItemPos
);
648 case VCLEVENT_MENU_ITEMCHECKED
:
650 UpdateChecked( nItemPos
, sal_True
);
653 case VCLEVENT_MENU_ITEMUNCHECKED
:
655 UpdateChecked( nItemPos
, sal_False
);
658 case VCLEVENT_OBJECT_DYING
:
662 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
666 // dispose all menu items
667 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
669 Reference
< XComponent
> xComponent( m_aAccessibleChildren
[i
], UNO_QUERY
);
670 if ( xComponent
.is() )
671 xComponent
->dispose();
673 m_aAccessibleChildren
.clear();
684 // -----------------------------------------------------------------------------
686 // -----------------------------------------------------------------------------
688 IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleMenuBaseComponent
, AccessibleExtendedComponentHelper_BASE
, OAccessibleMenuBaseComponent_BASE
)
690 // -----------------------------------------------------------------------------
692 // -----------------------------------------------------------------------------
694 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleMenuBaseComponent
, AccessibleExtendedComponentHelper_BASE
, OAccessibleMenuBaseComponent_BASE
)
696 // -----------------------------------------------------------------------------
698 // -----------------------------------------------------------------------------
700 void OAccessibleMenuBaseComponent::disposing()
702 AccessibleExtendedComponentHelper_BASE::disposing();
706 m_pMenu
->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent
, MenuEventListener
) );
710 // dispose all menu items
711 for ( sal_uInt32 i
= 0; i
< m_aAccessibleChildren
.size(); ++i
)
713 Reference
< XComponent
> xComponent( m_aAccessibleChildren
[i
], UNO_QUERY
);
714 if ( xComponent
.is() )
715 xComponent
->dispose();
717 m_aAccessibleChildren
.clear();
721 // -----------------------------------------------------------------------------
723 // -----------------------------------------------------------------------------
725 sal_Bool
OAccessibleMenuBaseComponent::supportsService( const OUString
& rServiceName
) throw (RuntimeException
)
727 return cppu::supportsService(this, rServiceName
);
730 // -----------------------------------------------------------------------------
732 // -----------------------------------------------------------------------------
734 Reference
< XAccessibleContext
> OAccessibleMenuBaseComponent::getAccessibleContext( ) throw (RuntimeException
)
736 OExternalLockGuard
aGuard( this );
741 // -----------------------------------------------------------------------------
742 // XAccessibleContext
743 // -----------------------------------------------------------------------------
745 Reference
< XAccessibleStateSet
> OAccessibleMenuBaseComponent::getAccessibleStateSet( ) throw (RuntimeException
)
747 OExternalLockGuard
aGuard( this );
749 utl::AccessibleStateSetHelper
* pStateSetHelper
= new utl::AccessibleStateSetHelper
;
750 Reference
< XAccessibleStateSet
> xSet
= pStateSetHelper
;
752 if ( !rBHelper
.bDisposed
&& !rBHelper
.bInDispose
)
754 FillAccessibleStateSet( *pStateSetHelper
);
758 pStateSetHelper
->AddState( AccessibleStateType::DEFUNC
);
764 // -----------------------------------------------------------------------------
766 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */