Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / accessibility / source / standard / accessiblemenubasecomponent.cxx
blob5431efd0d112f3ed896d7a235600cf248366363f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
33 #include <array>
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 )
46 :m_pMenu( pMenu )
47 ,m_bEnabled( false )
48 ,m_bFocused( false )
49 ,m_bVisible( false )
50 ,m_bSelected( false )
51 ,m_bChecked( false )
53 if ( m_pMenu )
55 m_aAccessibleChildren.assign( m_pMenu->GetItemCount(), Reference< XAccessible >() );
56 m_pMenu->AddEventListener( LINK( this, OAccessibleMenuBaseComponent, MenuEventListener ) );
61 OAccessibleMenuBaseComponent::~OAccessibleMenuBaseComponent()
63 if ( m_pMenu )
64 m_pMenu->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent, MenuEventListener ) );
68 bool OAccessibleMenuBaseComponent::IsEnabled()
70 return false;
74 bool OAccessibleMenuBaseComponent::IsFocused()
76 return false;
80 bool OAccessibleMenuBaseComponent::IsVisible()
82 return false;
86 bool OAccessibleMenuBaseComponent::IsSelected()
88 return false;
92 bool OAccessibleMenuBaseComponent::IsChecked()
94 return false;
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;
118 if ( m_bEnabled )
120 aOldValue[0] <<= AccessibleStateType::SENSITIVE;
121 aOldValue[1] <<= nStateType;
123 else
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;
140 if ( m_bFocused )
141 aOldValue <<= AccessibleStateType::FOCUSED;
142 else
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;
155 if ( m_bVisible )
156 aOldValue <<= AccessibleStateType::VISIBLE;
157 else
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;
170 if ( m_bSelected )
171 aOldValue <<= AccessibleStateType::SELECTED;
172 else
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;
185 if ( m_bChecked )
186 aOldValue <<= AccessibleStateType::CHECKED;
187 else
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] );
200 if ( xChild.is() )
202 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
203 if ( pComp )
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] );
215 if ( xChild.is() )
217 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
218 if ( pComp )
219 pComp->SetFocused( bFocused );
225 void OAccessibleMenuBaseComponent::UpdateVisible()
227 SetVisible( IsVisible() );
228 for (const Reference<XAccessible>& xChild : m_aAccessibleChildren)
230 if ( xChild.is() )
232 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
233 if ( pComp )
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] );
247 if ( xChild.is() )
249 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
250 if ( pComp )
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] );
262 if ( xChild.is() )
264 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
265 if ( pComp )
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] );
277 if ( xChild.is() )
279 OAccessibleMenuItemComponent* pComp = static_cast< OAccessibleMenuItemComponent* >( xChild.get() );
280 if ( pComp )
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] );
292 if ( xChild.is() )
294 OAccessibleMenuItemComponent* pComp = static_cast< OAccessibleMenuItemComponent* >( xChild.get() );
295 if ( pComp )
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];
311 if ( !xChild.is() )
313 if ( m_pMenu )
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) );
322 else
324 PopupMenu* pPopupMenu = m_pMenu->GetPopupMenu( m_pMenu->GetItemId( static_cast<sal_uInt16>(i) ) );
325 if ( pPopupMenu )
327 pChild = new VCLXAccessibleMenu( m_pMenu, static_cast<sal_uInt16>(i), pPopupMenu );
328 pPopupMenu->SetAccessible( pChild );
330 else
332 pChild = new VCLXAccessibleMenuItem( m_pMenu, static_cast<sal_uInt16>(i) );
336 // set states
337 pChild->SetStates();
339 xChild = pChild;
341 // insert into menu item list
342 m_aAccessibleChildren[i] = xChild;
346 return 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 );
356 if ( xAcc.is() )
358 Reference< XAccessibleComponent > xComp( xAcc->getAccessibleContext(), UNO_QUERY );
359 if ( xComp.is() )
361 tools::Rectangle aRect = VCLRectangle( xComp->getBounds() );
362 Point aPos = VCLPoint( rPoint );
363 if ( aRect.IsInside( aPos ) )
365 xChild = xAcc;
366 break;
372 return xChild;
376 void OAccessibleMenuBaseComponent::InsertChild( sal_Int32 i )
378 if ( i > static_cast<sal_Int32>(m_aAccessibleChildren.size()) )
379 i = m_aAccessibleChildren.size();
381 if ( i >= 0 )
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] );
390 if ( xAcc.is() )
392 OAccessibleMenuItemComponent* pComp = static_cast< OAccessibleMenuItemComponent* >( xAcc.get() );
393 if ( pComp )
394 pComp->SetItemPos( static_cast<sal_uInt16>(j) );
398 // send accessible child event
399 Reference< XAccessible > xChild( GetChild( i ) );
400 if ( xChild.is() )
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] );
424 if ( xAcc.is() )
426 OAccessibleMenuItemComponent* pComp = static_cast< OAccessibleMenuItemComponent* >( xAcc.get() );
427 if ( pComp )
428 pComp->SetItemPos( static_cast<sal_uInt16>(j) );
432 // send accessible child event
433 if ( xChild.is() )
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()
449 return false;
453 bool OAccessibleMenuBaseComponent::IsChildHighlighted()
455 bool bChildHighlighted = false;
457 for (const Reference<XAccessible>& xChild : m_aAccessibleChildren)
459 if ( xChild.is() )
461 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
462 if ( pComp && pComp->IsHighlighted() )
464 bChildHighlighted = true;
465 break;
470 return bChildHighlighted;
474 void OAccessibleMenuBaseComponent::SelectChild( sal_Int32 i )
476 // open the menu
477 if ( getAccessibleRole() == AccessibleRole::MENU && !IsPopupMenuOpen() )
478 Click();
480 // highlight the child
481 if ( m_pMenu )
482 m_pMenu->HighlightItem( static_cast<sal_uInt16>(i) );
486 void OAccessibleMenuBaseComponent::DeSelectAll()
488 if ( m_pMenu )
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) ) )
498 bSelected = true;
500 return bSelected;
504 void OAccessibleMenuBaseComponent::Click()
509 bool OAccessibleMenuBaseComponent::IsPopupMenuOpen()
511 return false;
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:
531 UpdateVisible();
533 break;
534 case VclEventId::MenuHighlight:
536 SetFocused( false );
537 UpdateFocused( nItemPos, true );
538 UpdateSelected( nItemPos, true );
540 break;
541 case VclEventId::MenuDehighlight:
543 UpdateFocused( nItemPos, false );
544 UpdateSelected( nItemPos, false );
546 break;
547 case VclEventId::MenuSubmenuActivate:
550 break;
551 case VclEventId::MenuSubmenuDeactivate:
553 UpdateFocused( nItemPos, true );
555 break;
556 case VclEventId::MenuEnable:
558 UpdateEnabled( nItemPos, true );
560 break;
561 case VclEventId::MenuDisable:
563 UpdateEnabled( nItemPos, false );
565 break;
566 case VclEventId::MenuSubmenuChanged:
568 RemoveChild( nItemPos );
569 InsertChild( nItemPos );
571 break;
572 case VclEventId::MenuInsertItem:
574 InsertChild( nItemPos );
576 break;
577 case VclEventId::MenuRemoveItem:
579 RemoveChild( nItemPos );
581 break;
582 case VclEventId::MenuItemTextChanged:
584 UpdateAccessibleName( nItemPos );
585 UpdateItemText( nItemPos );
587 break;
588 case VclEventId::MenuItemChecked:
590 UpdateChecked( nItemPos, true );
592 break;
593 case VclEventId::MenuItemUnchecked:
595 UpdateChecked( nItemPos, false );
597 break;
598 case VclEventId::ObjectDying:
600 if ( m_pMenu )
602 m_pMenu->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent, MenuEventListener ) );
604 m_pMenu = nullptr;
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();
616 break;
617 default:
620 break;
625 // XInterface
628 IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleMenuBaseComponent, OAccessibleExtendedComponentHelper, OAccessibleMenuBaseComponent_BASE )
631 // XTypeProvider
634 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleMenuBaseComponent, OAccessibleExtendedComponentHelper, OAccessibleMenuBaseComponent_BASE )
637 // XComponent
640 void OAccessibleMenuBaseComponent::disposing()
642 OAccessibleExtendedComponentHelper::disposing();
644 if ( m_pMenu )
646 m_pMenu->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent, MenuEventListener ) );
648 m_pMenu = nullptr;
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();
662 // XServiceInfo
665 sal_Bool OAccessibleMenuBaseComponent::supportsService( const OUString& rServiceName )
667 return cppu::supportsService(this, rServiceName);
671 // XAccessible
674 Reference< XAccessibleContext > OAccessibleMenuBaseComponent::getAccessibleContext( )
676 OExternalLockGuard aGuard( this );
678 return 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 );
696 else
698 pStateSetHelper->AddState( AccessibleStateType::DEFUNC );
701 return xSet;
705 bool OAccessibleMenuBaseComponent::IsMenuHideDisabledEntries()
707 return false;
710 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */