/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star::accessibility; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::lang; using namespace ::com::sun::star; using namespace ::comphelper; VCLXAccessibleMenuItem::VCLXAccessibleMenuItem( Menu* pParent, sal_uInt16 nItemPos, Menu* pMenu ) :ImplInheritanceHelper( pParent, nItemPos, pMenu ) { } bool VCLXAccessibleMenuItem::IsFocused() { return IsHighlighted(); } bool VCLXAccessibleMenuItem::IsSelected() { return IsHighlighted(); } bool VCLXAccessibleMenuItem::IsCheckable() { if (!m_pParent) return false; const sal_uInt16 nItemId = m_pParent->GetItemId(m_nItemPos); return m_pParent->IsItemCheckable(nItemId); } bool VCLXAccessibleMenuItem::IsChecked() { bool bChecked = false; if ( m_pParent ) { sal_uInt16 nItemId = m_pParent->GetItemId( m_nItemPos ); if ( m_pParent->IsItemChecked( nItemId ) ) bChecked = true; } return bChecked; } bool VCLXAccessibleMenuItem::IsHighlighted() { bool bHighlighted = false; if ( m_pParent && m_pParent->IsHighlighted( m_nItemPos ) ) bHighlighted = true; return bHighlighted; } void VCLXAccessibleMenuItem::FillAccessibleStateSet( sal_Int64& rStateSet ) { OAccessibleMenuItemComponent::FillAccessibleStateSet( rStateSet ); rStateSet |= AccessibleStateType::FOCUSABLE; if ( IsFocused() ) rStateSet |= AccessibleStateType::FOCUSED; rStateSet |= AccessibleStateType::SELECTABLE; if ( IsSelected() ) rStateSet |= AccessibleStateType::SELECTED; if (IsCheckable()) rStateSet |= AccessibleStateType::CHECKABLE; if ( IsChecked() ) rStateSet |= AccessibleStateType::CHECKED; } // OCommonAccessibleText OUString VCLXAccessibleMenuItem::implGetText() { return m_sItemText; } Locale VCLXAccessibleMenuItem::implGetLocale() { return Application::GetSettings().GetLanguageTag().getLocale(); } void VCLXAccessibleMenuItem::implGetSelection( sal_Int32& nStartIndex, sal_Int32& nEndIndex ) { nStartIndex = 0; nEndIndex = 0; } // XServiceInfo OUString VCLXAccessibleMenuItem::getImplementationName() { return u"com.sun.star.comp.toolkit.AccessibleMenuItem"_ustr; } Sequence< OUString > VCLXAccessibleMenuItem::getSupportedServiceNames() { return { u"com.sun.star.awt.AccessibleMenuItem"_ustr }; } // XAccessibleContext sal_Int16 VCLXAccessibleMenuItem::getAccessibleRole( ) { OExternalLockGuard aGuard( this ); // IA2 CWS. MT: We had the additional roles in UAA for ever, but never used them anywhere. // Looks reasonable, but need to verify in Orca and VoiceOver. sal_Int16 nRole = AccessibleRole::MENU_ITEM; if ( m_pParent ) { sal_uInt16 nItemId = m_pParent->GetItemId( m_nItemPos ); MenuItemBits nItemBits = m_pParent->GetItemBits(nItemId); if( nItemBits & MenuItemBits::RADIOCHECK) nRole = AccessibleRole::RADIO_MENU_ITEM; else if( nItemBits & MenuItemBits::CHECKABLE) nRole = AccessibleRole::CHECK_MENU_ITEM; } return nRole; } // XAccessibleText sal_Int32 VCLXAccessibleMenuItem::getCaretPosition() { return -1; } sal_Bool VCLXAccessibleMenuItem::setCaretPosition( sal_Int32 nIndex ) { OExternalLockGuard aGuard( this ); if ( !implIsValidRange( nIndex, nIndex, m_sItemText.getLength() ) ) throw IndexOutOfBoundsException(); return false; } sal_Unicode VCLXAccessibleMenuItem::getCharacter( sal_Int32 nIndex ) { OExternalLockGuard aGuard( this ); return OCommonAccessibleText::implGetCharacter( implGetText(), nIndex ); } Sequence< PropertyValue > VCLXAccessibleMenuItem::getCharacterAttributes( sal_Int32 nIndex, const Sequence< OUString >& aRequestedAttributes ) { OExternalLockGuard aGuard( this ); if ( !implIsValidIndex( nIndex, m_sItemText.getLength() ) ) throw IndexOutOfBoundsException(); vcl::Font aFont = Application::GetSettings().GetStyleSettings().GetMenuFont(); sal_Int32 nBackColor = getBackground(); sal_Int32 nColor = getForeground(); return CharacterAttributesHelper( aFont, nBackColor, nColor ) .GetCharacterAttributes( aRequestedAttributes ); } awt::Rectangle VCLXAccessibleMenuItem::getCharacterBounds( sal_Int32 nIndex ) { OExternalLockGuard aGuard( this ); if ( !implIsValidIndex( nIndex, m_sItemText.getLength() ) ) throw IndexOutOfBoundsException(); awt::Rectangle aBounds( 0, 0, 0, 0 ); if ( m_pParent ) { sal_uInt16 nItemId = m_pParent->GetItemId( m_nItemPos ); tools::Rectangle aItemRect = m_pParent->GetBoundingRectangle( m_nItemPos ); tools::Rectangle aCharRect = m_pParent->GetCharacterBounds( nItemId, nIndex ); aCharRect.Move( -aItemRect.Left(), -aItemRect.Top() ); aBounds = vcl::unohelper::ConvertToAWTRect(aCharRect); } return aBounds; } sal_Int32 VCLXAccessibleMenuItem::getCharacterCount() { OExternalLockGuard aGuard( this ); return m_sItemText.getLength(); } sal_Int32 VCLXAccessibleMenuItem::getIndexAtPoint( const awt::Point& aPoint ) { OExternalLockGuard aGuard( this ); sal_Int32 nIndex = -1; if ( m_pParent ) { sal_uInt16 nItemId = 0; tools::Rectangle aItemRect = m_pParent->GetBoundingRectangle( m_nItemPos ); Point aPnt(vcl::unohelper::ConvertToVCLPoint(aPoint)); aPnt += aItemRect.TopLeft(); sal_Int32 nI = m_pParent->GetIndexForPoint( aPnt, nItemId ); if ( nI != -1 && m_pParent->GetItemId( m_nItemPos ) == nItemId ) nIndex = nI; } return nIndex; } OUString VCLXAccessibleMenuItem::getSelectedText() { OExternalLockGuard aGuard( this ); return OUString(); } sal_Int32 VCLXAccessibleMenuItem::getSelectionStart() { OExternalLockGuard aGuard( this ); return 0; } sal_Int32 VCLXAccessibleMenuItem::getSelectionEnd() { OExternalLockGuard aGuard( this ); return 0; } sal_Bool VCLXAccessibleMenuItem::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) { OExternalLockGuard aGuard( this ); if ( !implIsValidRange( nStartIndex, nEndIndex, m_sItemText.getLength() ) ) throw IndexOutOfBoundsException(); return false; } OUString VCLXAccessibleMenuItem::getText() { OExternalLockGuard aGuard( this ); return m_sItemText; } OUString VCLXAccessibleMenuItem::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) { OExternalLockGuard aGuard( this ); return OCommonAccessibleText::implGetTextRange( implGetText(), nStartIndex, nEndIndex ); } css::accessibility::TextSegment VCLXAccessibleMenuItem::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) { OExternalLockGuard aGuard( this ); return OCommonAccessibleText::getTextAtIndex( nIndex, aTextType ); } css::accessibility::TextSegment VCLXAccessibleMenuItem::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) { OExternalLockGuard aGuard( this ); return OCommonAccessibleText::getTextBeforeIndex( nIndex, aTextType ); } css::accessibility::TextSegment VCLXAccessibleMenuItem::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) { OExternalLockGuard aGuard( this ); return OCommonAccessibleText::getTextBehindIndex( nIndex, aTextType ); } sal_Bool VCLXAccessibleMenuItem::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) { OExternalLockGuard aGuard( this ); bool bReturn = false; if ( m_pParent ) { vcl::Window* pWindow = m_pParent->GetWindow(); if ( pWindow ) { Reference< datatransfer::clipboard::XClipboard > xClipboard = pWindow->GetClipboard(); if ( xClipboard.is() ) { OUString sText( getTextRange( nStartIndex, nEndIndex ) ); rtl::Reference pDataObj = new vcl::unohelper::TextDataObject( sText ); SolarMutexReleaser aReleaser; xClipboard->setContents( pDataObj, nullptr ); Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( xClipboard, uno::UNO_QUERY ); if( xFlushableClipboard.is() ) xFlushableClipboard->flushClipboard(); bReturn = true; } } } return bReturn; } sal_Bool VCLXAccessibleMenuItem::scrollSubstringTo( sal_Int32, sal_Int32, AccessibleScrollType ) { return false; } // XAccessibleAction sal_Int32 VCLXAccessibleMenuItem::getAccessibleActionCount( ) { return 1; } sal_Bool VCLXAccessibleMenuItem::doAccessibleAction ( sal_Int32 nIndex ) { OExternalLockGuard aGuard( this ); if ( nIndex != 0 ) throw IndexOutOfBoundsException(); Click(); return true; } OUString VCLXAccessibleMenuItem::getAccessibleActionDescription ( sal_Int32 nIndex ) { OExternalLockGuard aGuard( this ); if ( nIndex != 0 ) throw IndexOutOfBoundsException(); return RID_STR_ACC_ACTION_SELECT; } Reference< XAccessibleKeyBinding > VCLXAccessibleMenuItem::getAccessibleActionKeyBinding( sal_Int32 nIndex ) { OExternalLockGuard aGuard( this ); if ( nIndex != 0 ) throw IndexOutOfBoundsException(); rtl::Reference pKeyBindingHelper = new OAccessibleKeyBindingHelper(); if ( m_pParent ) { // create auto mnemonics if (!(m_pParent->GetMenuFlags() & MenuFlags::NoAutoMnemonics)) m_pParent->CreateAutoMnemonics(); // activation key KeyEvent aKeyEvent = m_pParent->GetActivationKey( m_pParent->GetItemId( m_nItemPos ) ); vcl::KeyCode aKeyCode = aKeyEvent.GetKeyCode(); Sequence< awt::KeyStroke > aSeq1 { { 0, // Modifiers static_cast< sal_Int16 >(aKeyCode.GetCode()), aKeyEvent.GetCharCode(), static_cast< sal_Int16 >( aKeyCode.GetFunction()) } }; Reference< XAccessible > xParent( getAccessibleParent() ); if ( xParent.is() ) { Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); if ( xParentContext.is() && xParentContext->getAccessibleRole() == AccessibleRole::MENU_BAR ) aSeq1.getArray()[0].Modifiers |= awt::KeyModifier::MOD2; } pKeyBindingHelper->AddKeyBinding( aSeq1 ); // complete menu activation key sequence Sequence< awt::KeyStroke > aSeq; if ( xParent.is() ) { Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); if ( xParentContext.is() && xParentContext->getAccessibleRole() == AccessibleRole::MENU ) { Reference< XAccessibleAction > xAction( xParentContext, UNO_QUERY ); if ( xAction.is() && xAction->getAccessibleActionCount() > 0 ) { Reference< XAccessibleKeyBinding > xKeyB( xAction->getAccessibleActionKeyBinding( 0 ) ); if ( xKeyB.is() && xKeyB->getAccessibleKeyBindingCount() > 1 ) aSeq = xKeyB->getAccessibleKeyBinding( 1 ); } } } Sequence< awt::KeyStroke > aSeq2 = ::comphelper::concatSequences( aSeq, aSeq1 ); pKeyBindingHelper->AddKeyBinding( aSeq2 ); // accelerator key vcl::KeyCode aAccelKeyCode = m_pParent->GetAccelKey( m_pParent->GetItemId( m_nItemPos ) ); if ( aAccelKeyCode.GetCode() != 0 ) { Sequence< awt::KeyStroke > aSeq3 { { 0, // Modifiers static_cast< sal_Int16 >(aAccelKeyCode.GetCode()), aKeyEvent.GetCharCode(), static_cast< sal_Int16 >(aAccelKeyCode.GetFunction()) } }; if (aAccelKeyCode.GetModifier() != 0) { auto pSeq3 = aSeq3.getArray(); if ( aAccelKeyCode.IsShift() ) pSeq3[0].Modifiers |= awt::KeyModifier::SHIFT; if ( aAccelKeyCode.IsMod1() ) pSeq3[0].Modifiers |= awt::KeyModifier::MOD1; if ( aAccelKeyCode.IsMod2() ) pSeq3[0].Modifiers |= awt::KeyModifier::MOD2; if ( aAccelKeyCode.IsMod3() ) pSeq3[0].Modifiers |= awt::KeyModifier::MOD3; } pKeyBindingHelper->AddKeyBinding( aSeq3 ); } } return pKeyBindingHelper; } // XAccessibleValue Any VCLXAccessibleMenuItem::getCurrentValue( ) { OExternalLockGuard aGuard( this ); Any aValue; if ( IsSelected() ) aValue <<= sal_Int32(1); else aValue <<= sal_Int32(0); return aValue; } sal_Bool VCLXAccessibleMenuItem::setCurrentValue( const Any& aNumber ) { OExternalLockGuard aGuard( this ); bool bReturn = false; sal_Int32 nValue = 0; OSL_VERIFY( aNumber >>= nValue ); if ( nValue <= 0 ) { DeSelect(); bReturn = true; } else if ( nValue >= 1 ) { Select(); bReturn = true; } return bReturn; } Any VCLXAccessibleMenuItem::getMaximumValue( ) { Any aValue; aValue <<= sal_Int32(1); return aValue; } Any VCLXAccessibleMenuItem::getMinimumValue( ) { Any aValue; aValue <<= sal_Int32(0); return aValue; } Any VCLXAccessibleMenuItem::getMinimumIncrement( ) { Any aValue; aValue <<= sal_Int32(1); return aValue; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */