Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / accessibility / source / standard / accessiblemenubasecomponent.cxx
blobe1ab9e326ebf3fe93f054ef93b3c7d8e5b459701
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 <comphelper/accessiblecontexthelper.hxx>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <o3tl/safeint.hxx>
32 #include <vcl/menu.hxx>
33 #include <vcl/vclevent.hxx>
35 #include <array>
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::lang;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::accessibility;
41 using namespace ::comphelper;
44 // OAccessibleMenuBaseComponent
47 OAccessibleMenuBaseComponent::OAccessibleMenuBaseComponent( Menu* pMenu )
48 :m_pMenu( pMenu )
49 ,m_bEnabled( false )
50 ,m_bFocused( false )
51 ,m_bVisible( false )
52 ,m_bSelected( false )
53 ,m_bChecked( false )
55 if ( m_pMenu )
57 m_aAccessibleChildren.assign( m_pMenu->GetItemCount(), Reference< XAccessible >() );
58 m_pMenu->AddEventListener( LINK( this, OAccessibleMenuBaseComponent, MenuEventListener ) );
63 OAccessibleMenuBaseComponent::~OAccessibleMenuBaseComponent()
65 if ( m_pMenu )
66 m_pMenu->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent, MenuEventListener ) );
70 bool OAccessibleMenuBaseComponent::IsEnabled()
72 return false;
76 bool OAccessibleMenuBaseComponent::IsFocused()
78 return false;
82 bool OAccessibleMenuBaseComponent::IsVisible()
84 return false;
88 bool OAccessibleMenuBaseComponent::IsSelected()
90 return false;
94 bool OAccessibleMenuBaseComponent::IsChecked()
96 return false;
100 void OAccessibleMenuBaseComponent::SetStates()
102 m_bEnabled = IsEnabled();
103 m_bFocused = IsFocused();
104 m_bVisible = IsVisible();
105 m_bSelected = IsSelected();
106 m_bChecked = IsChecked();
110 void OAccessibleMenuBaseComponent::SetEnabled( bool bEnabled )
112 if ( m_bEnabled == bEnabled )
113 return;
115 sal_Int64 nStateType=AccessibleStateType::ENABLED;
116 if (IsMenuHideDisabledEntries())
118 nStateType = AccessibleStateType::VISIBLE;
120 std::array<Any, 2> aOldValue, aNewValue;
121 if ( m_bEnabled )
123 aOldValue[0] <<= AccessibleStateType::SENSITIVE;
124 aOldValue[1] <<= nStateType;
126 else
128 aNewValue[0] <<= nStateType;
129 aNewValue[1] <<= AccessibleStateType::SENSITIVE;
131 m_bEnabled = bEnabled;
132 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue[0], aNewValue[0] );
133 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue[1], aNewValue[1] );
137 void OAccessibleMenuBaseComponent::SetFocused( bool bFocused )
139 if ( m_bFocused != bFocused )
141 Any aOldValue, aNewValue;
142 if ( m_bFocused )
143 aOldValue <<= AccessibleStateType::FOCUSED;
144 else
145 aNewValue <<= AccessibleStateType::FOCUSED;
146 m_bFocused = bFocused;
147 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
152 void OAccessibleMenuBaseComponent::SetVisible( bool bVisible )
154 if ( m_bVisible != bVisible )
156 Any aOldValue, aNewValue;
157 if ( m_bVisible )
158 aOldValue <<= AccessibleStateType::VISIBLE;
159 else
160 aNewValue <<= AccessibleStateType::VISIBLE;
161 m_bVisible = bVisible;
162 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
167 void OAccessibleMenuBaseComponent::SetSelected( bool bSelected )
169 if ( m_bSelected != bSelected )
171 Any aOldValue, aNewValue;
172 if ( m_bSelected )
173 aOldValue <<= AccessibleStateType::SELECTED;
174 else
175 aNewValue <<= AccessibleStateType::SELECTED;
176 m_bSelected = bSelected;
177 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
182 void OAccessibleMenuBaseComponent::SetChecked( bool bChecked )
184 if ( m_bChecked != bChecked )
186 Any aOldValue, aNewValue;
187 if ( m_bChecked )
188 aOldValue <<= AccessibleStateType::CHECKED;
189 else
190 aNewValue <<= AccessibleStateType::CHECKED;
191 m_bChecked = bChecked;
192 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
197 void OAccessibleMenuBaseComponent::UpdateEnabled( sal_Int32 i, bool bEnabled )
199 if ( i >= 0 && o3tl::make_unsigned(i) < m_aAccessibleChildren.size() )
201 Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
202 if ( xChild.is() )
204 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
205 if ( pComp )
206 pComp->SetEnabled( bEnabled );
212 void OAccessibleMenuBaseComponent::UpdateFocused( sal_Int32 i, bool bFocused )
214 if ( i >= 0 && o3tl::make_unsigned(i) < m_aAccessibleChildren.size() )
216 Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
217 if ( xChild.is() )
219 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
220 if ( pComp )
221 pComp->SetFocused( bFocused );
227 void OAccessibleMenuBaseComponent::UpdateVisible()
229 SetVisible( IsVisible() );
230 for (const Reference<XAccessible>& xChild : m_aAccessibleChildren)
232 if ( xChild.is() )
234 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
235 if ( pComp )
236 pComp->SetVisible( pComp->IsVisible() );
242 void OAccessibleMenuBaseComponent::UpdateSelected( sal_Int32 i, bool bSelected )
244 NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
246 if ( i >= 0 && o3tl::make_unsigned(i) < m_aAccessibleChildren.size() )
248 Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
249 if ( xChild.is() )
251 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
252 if ( pComp )
253 pComp->SetSelected( bSelected );
259 void OAccessibleMenuBaseComponent::UpdateChecked( sal_Int32 i, bool bChecked )
261 if ( i >= 0 && o3tl::make_unsigned(i) < m_aAccessibleChildren.size() )
263 Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
264 if ( xChild.is() )
266 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
267 if ( pComp )
268 pComp->SetChecked( bChecked );
274 void OAccessibleMenuBaseComponent::UpdateAccessibleName( sal_Int32 i )
276 if ( i >= 0 && o3tl::make_unsigned(i) < m_aAccessibleChildren.size() )
278 Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
279 if ( xChild.is() )
281 OAccessibleMenuItemComponent* pComp = static_cast< OAccessibleMenuItemComponent* >( xChild.get() );
282 if ( pComp )
283 pComp->SetAccessibleName( pComp->GetAccessibleName() );
289 void OAccessibleMenuBaseComponent::UpdateItemText( sal_Int32 i )
291 if ( i >= 0 && o3tl::make_unsigned(i) < m_aAccessibleChildren.size() )
293 Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
294 if ( xChild.is() )
296 OAccessibleMenuItemComponent* pComp = static_cast< OAccessibleMenuItemComponent* >( xChild.get() );
297 if ( pComp )
298 pComp->SetItemText( pComp->GetItemText() );
304 sal_Int64 OAccessibleMenuBaseComponent::GetChildCount() const
306 return m_aAccessibleChildren.size();
310 Reference< XAccessible > OAccessibleMenuBaseComponent::GetChild( sal_Int64 i )
312 Reference< XAccessible > xChild = m_aAccessibleChildren[i];
313 if ( !xChild.is() )
315 if ( m_pMenu )
317 // create a new child
318 rtl::Reference<OAccessibleMenuBaseComponent> pChild;
320 if ( m_pMenu->GetItemType( static_cast<sal_uInt16>(i) ) == MenuItemType::SEPARATOR )
322 pChild = new VCLXAccessibleMenuSeparator( m_pMenu, static_cast<sal_uInt16>(i) );
324 else
326 PopupMenu* pPopupMenu = m_pMenu->GetPopupMenu( m_pMenu->GetItemId( static_cast<sal_uInt16>(i) ) );
327 if ( pPopupMenu )
329 pChild = new VCLXAccessibleMenu( m_pMenu, static_cast<sal_uInt16>(i), pPopupMenu );
330 pPopupMenu->SetAccessible( pChild );
332 else
334 pChild = new VCLXAccessibleMenuItem( m_pMenu, static_cast<sal_uInt16>(i) );
338 // set states
339 pChild->SetStates();
341 xChild = pChild;
343 // insert into menu item list
344 m_aAccessibleChildren[i] = xChild;
348 return xChild;
352 Reference< XAccessible > OAccessibleMenuBaseComponent::GetChildAt( const awt::Point& rPoint )
354 Reference< XAccessible > xChild;
355 for ( sal_Int64 i = 0, nCount = getAccessibleChildCount(); i < nCount; ++i )
357 Reference< XAccessible > xAcc = getAccessibleChild( i );
358 if ( xAcc.is() )
360 Reference< XAccessibleComponent > xComp( xAcc->getAccessibleContext(), UNO_QUERY );
361 if ( xComp.is() )
363 tools::Rectangle aRect = VCLRectangle( xComp->getBounds() );
364 Point aPos = VCLPoint( rPoint );
365 if ( aRect.Contains( aPos ) )
367 xChild = xAcc;
368 break;
374 return xChild;
378 void OAccessibleMenuBaseComponent::InsertChild( sal_Int32 i )
380 if ( i < 0 )
381 return;
383 if ( o3tl::make_unsigned(i) > m_aAccessibleChildren.size() )
384 i = m_aAccessibleChildren.size();
386 // insert entry in child list
387 m_aAccessibleChildren.insert( m_aAccessibleChildren.begin() + i, Reference< XAccessible >() );
389 // update item position of accessible children
390 for ( sal_uInt32 j = i, nCount = m_aAccessibleChildren.size(); j < nCount; ++j )
392 Reference< XAccessible > xAcc( m_aAccessibleChildren[j] );
393 if ( xAcc.is() )
395 OAccessibleMenuItemComponent* pComp = static_cast< OAccessibleMenuItemComponent* >( xAcc.get() );
396 if ( pComp )
397 pComp->SetItemPos( static_cast<sal_uInt16>(j) );
401 // send accessible child event
402 Reference< XAccessible > xChild( GetChild( i ) );
403 if ( xChild.is() )
405 Any aOldValue, aNewValue;
406 aNewValue <<= xChild;
407 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
412 void OAccessibleMenuBaseComponent::RemoveChild( sal_Int32 i )
414 if ( i < 0 || o3tl::make_unsigned(i) >= m_aAccessibleChildren.size() )
415 return;
417 // keep the accessible of the removed item
418 Reference< XAccessible > xChild( m_aAccessibleChildren[i] );
420 // remove entry in child list
421 m_aAccessibleChildren.erase( m_aAccessibleChildren.begin() + i );
423 // update item position of accessible children
424 for ( sal_uInt32 j = i, nCount = m_aAccessibleChildren.size(); j < nCount; ++j )
426 Reference< XAccessible > xAcc( m_aAccessibleChildren[j] );
427 if ( xAcc.is() )
429 OAccessibleMenuItemComponent* pComp = static_cast< OAccessibleMenuItemComponent* >( xAcc.get() );
430 if ( pComp )
431 pComp->SetItemPos( static_cast<sal_uInt16>(j) );
435 // send accessible child event
436 if ( xChild.is() )
438 Any aOldValue, aNewValue;
439 aOldValue <<= xChild;
440 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
442 Reference< XComponent > xComponent( xChild, UNO_QUERY );
443 if ( xComponent.is() )
444 xComponent->dispose();
449 bool OAccessibleMenuBaseComponent::IsHighlighted()
451 return false;
455 bool OAccessibleMenuBaseComponent::IsChildHighlighted()
457 bool bChildHighlighted = false;
459 for (const Reference<XAccessible>& xChild : m_aAccessibleChildren)
461 if ( xChild.is() )
463 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xChild.get() );
464 if ( pComp && pComp->IsHighlighted() )
466 bChildHighlighted = true;
467 break;
472 return bChildHighlighted;
476 void OAccessibleMenuBaseComponent::SelectChild( sal_Int32 i )
478 // open the menu
479 if ( getAccessibleRole() == AccessibleRole::MENU && !IsPopupMenuOpen() )
480 Click();
482 // highlight the child
483 if ( m_pMenu )
484 m_pMenu->HighlightItem( static_cast<sal_uInt16>(i) );
488 void OAccessibleMenuBaseComponent::DeSelectAll()
490 if ( m_pMenu )
491 m_pMenu->DeHighlight();
495 bool OAccessibleMenuBaseComponent::IsChildSelected( sal_Int32 i )
497 bool bSelected = false;
499 if ( m_pMenu && m_pMenu->IsHighlighted( static_cast<sal_uInt16>(i) ) )
500 bSelected = true;
502 return bSelected;
506 void OAccessibleMenuBaseComponent::Click()
511 bool OAccessibleMenuBaseComponent::IsPopupMenuOpen()
513 return false;
517 IMPL_LINK( OAccessibleMenuBaseComponent, MenuEventListener, VclMenuEvent&, rEvent, void )
519 OSL_ENSURE( rEvent.GetMenu(), "OAccessibleMenuBaseComponent - Menu?" );
520 ProcessMenuEvent( rEvent );
524 void OAccessibleMenuBaseComponent::ProcessMenuEvent( const VclMenuEvent& rVclMenuEvent )
526 sal_uInt16 nItemPos = rVclMenuEvent.GetItemPos();
528 switch ( rVclMenuEvent.GetId() )
530 case VclEventId::MenuShow:
531 case VclEventId::MenuHide:
533 UpdateVisible();
535 break;
536 case VclEventId::MenuHighlight:
538 SetFocused( false );
539 UpdateFocused( nItemPos, true );
540 UpdateSelected( nItemPos, true );
542 break;
543 case VclEventId::MenuDehighlight:
545 UpdateFocused( nItemPos, false );
546 UpdateSelected( nItemPos, false );
548 break;
549 case VclEventId::MenuSubmenuActivate:
552 break;
553 case VclEventId::MenuSubmenuDeactivate:
555 UpdateFocused( nItemPos, true );
557 break;
558 case VclEventId::MenuEnable:
560 UpdateEnabled( nItemPos, true );
562 break;
563 case VclEventId::MenuDisable:
565 UpdateEnabled( nItemPos, false );
567 break;
568 case VclEventId::MenuSubmenuChanged:
570 RemoveChild( nItemPos );
571 InsertChild( nItemPos );
573 break;
574 case VclEventId::MenuInsertItem:
576 InsertChild( nItemPos );
578 break;
579 case VclEventId::MenuRemoveItem:
581 RemoveChild( nItemPos );
583 break;
584 case VclEventId::MenuAccessibleNameChanged:
586 UpdateAccessibleName( nItemPos );
588 break;
589 case VclEventId::MenuItemTextChanged:
591 UpdateAccessibleName( nItemPos );
592 UpdateItemText( nItemPos );
594 break;
595 case VclEventId::MenuItemChecked:
597 UpdateChecked( nItemPos, true );
599 break;
600 case VclEventId::MenuItemUnchecked:
602 UpdateChecked( nItemPos, false );
604 break;
605 case VclEventId::ObjectDying:
607 if ( m_pMenu )
609 m_pMenu->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent, MenuEventListener ) );
611 m_pMenu = nullptr;
613 // dispose all menu items
614 for (const Reference<XAccessible>& i : m_aAccessibleChildren)
616 Reference< XComponent > xComponent( i, UNO_QUERY );
617 if ( xComponent.is() )
618 xComponent->dispose();
620 m_aAccessibleChildren.clear();
623 break;
624 default:
627 break;
632 // XComponent
635 void OAccessibleMenuBaseComponent::disposing()
637 OAccessibleExtendedComponentHelper::disposing();
639 if ( !m_pMenu )
640 return;
642 m_pMenu->RemoveEventListener( LINK( this, OAccessibleMenuBaseComponent, MenuEventListener ) );
644 m_pMenu = nullptr;
646 // dispose all menu items
647 for (const Reference<XAccessible>& i : m_aAccessibleChildren)
649 Reference< XComponent > xComponent( i, UNO_QUERY );
650 if ( xComponent.is() )
651 xComponent->dispose();
653 m_aAccessibleChildren.clear();
657 // XServiceInfo
660 sal_Bool OAccessibleMenuBaseComponent::supportsService( const OUString& rServiceName )
662 return cppu::supportsService(this, rServiceName);
666 // XAccessible
669 Reference< XAccessibleContext > OAccessibleMenuBaseComponent::getAccessibleContext( )
671 OExternalLockGuard aGuard( this );
673 return this;
677 // XAccessibleContext
680 sal_Int64 OAccessibleMenuBaseComponent::getAccessibleStateSet( )
682 OExternalLockGuard aGuard( this );
684 sal_Int64 nStateSet = 0;
686 if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
688 FillAccessibleStateSet( nStateSet );
690 else
692 nStateSet |= AccessibleStateType::DEFUNC;
695 return nStateSet;
699 bool OAccessibleMenuBaseComponent::IsMenuHideDisabledEntries()
701 return false;
704 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */