1323de322SAndrew Rist/************************************************************** 2cdf0e10cSrcweir * 3323de322SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4323de322SAndrew Rist * or more contributor license agreements. See the NOTICE file 5323de322SAndrew Rist * distributed with this work for additional information 6323de322SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7323de322SAndrew Rist * to you under the Apache License, Version 2.0 (the 8323de322SAndrew Rist * "License"); you may not use this file except in compliance 9323de322SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11323de322SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13323de322SAndrew Rist * Unless required by applicable law or agreed to in writing, 14323de322SAndrew Rist * software distributed under the License is distributed on an 15323de322SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16323de322SAndrew Rist * KIND, either express or implied. See the License for the 17323de322SAndrew Rist * specific language governing permissions and limitations 18323de322SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20323de322SAndrew Rist *************************************************************/ 21323de322SAndrew Rist 22323de322SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir// MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir#include "precompiled_vcl.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir#include "aqua/salinst.h" 28cdf0e10cSrcweir#include "aqua/aqua11yfactory.h" 29cdf0e10cSrcweir#include "aqua/aqua11yfocustracker.hxx" 30cdf0e10cSrcweir 31cdf0e10cSrcweir#include "aqua11yfocuslistener.hxx" 32cdf0e10cSrcweir#include "aqua11yrolehelper.h" 33cdf0e10cSrcweir#include "aqua11ywrapperbutton.h" 34cdf0e10cSrcweir#include "aqua11ywrapperstatictext.h" 35cdf0e10cSrcweir#include "aqua11ywrappertextarea.h" 36cdf0e10cSrcweir#include "aqua11ywrappercheckbox.h" 37cdf0e10cSrcweir#include "aqua11ywrappercombobox.h" 38cdf0e10cSrcweir#include "aqua11ywrappergroup.h" 39cdf0e10cSrcweir#include "aqua11ywrapperlist.h" 40cdf0e10cSrcweir#include "aqua11ywrapperradiobutton.h" 41cdf0e10cSrcweir#include "aqua11ywrapperradiogroup.h" 42cdf0e10cSrcweir#include "aqua11ywrapperrow.h" 43cdf0e10cSrcweir#include "aqua11ywrapperscrollarea.h" 44cdf0e10cSrcweir#include "aqua11ywrapperscrollbar.h" 45cdf0e10cSrcweir#include "aqua11ywrappersplitter.h" 46cdf0e10cSrcweir#include "aqua11ywrappertabgroup.h" 47cdf0e10cSrcweir#include "aqua11ywrappertoolbar.h" 48cdf0e10cSrcweir#include "aqua11ytablewrapper.h" 49cdf0e10cSrcweir 50cdf0e10cSrcweir#include <com/sun/star/accessibility/AccessibleStateType.hpp> 51cdf0e10cSrcweir 52cdf0e10cSrcweirusing namespace ::com::sun::star::accessibility; 53cdf0e10cSrcweirusing namespace ::com::sun::star::uno; 54cdf0e10cSrcweir 55cdf0e10cSrcweirstatic bool enabled = false; 56cdf0e10cSrcweir 57cdf0e10cSrcweir@implementation AquaA11yFactory : NSObject 58cdf0e10cSrcweir 59cdf0e10cSrcweir#pragma mark - 60cdf0e10cSrcweir#pragma mark Wrapper Repository 61cdf0e10cSrcweir 62cdf0e10cSrcweir+(NSMutableDictionary *)allWrapper { 63cdf0e10cSrcweir static NSMutableDictionary * mdAllWrapper = nil; 64cdf0e10cSrcweir if ( mdAllWrapper == nil ) { 65cdf0e10cSrcweir mdAllWrapper = [ [ [ NSMutableDictionary alloc ] init ] retain ]; 66cdf0e10cSrcweir // initialize keyboard focus tracker 67cdf0e10cSrcweir rtl::Reference< AquaA11yFocusListener > listener( AquaA11yFocusListener::get() ); 68cdf0e10cSrcweir AquaA11yFocusTracker::get().setFocusListener(listener.get()); 69cdf0e10cSrcweir enabled = true; 70cdf0e10cSrcweir } 71cdf0e10cSrcweir return mdAllWrapper; 72cdf0e10cSrcweir} 73cdf0e10cSrcweir 74cdf0e10cSrcweir+(NSValue *)keyForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext { 75cdf0e10cSrcweir return [ NSValue valueWithPointer: rxAccessibleContext.get() ]; 76cdf0e10cSrcweir} 77cdf0e10cSrcweir 78cdf0e10cSrcweir+(NSValue *)keyForAccessibleContextAsRadioGroup: (Reference < XAccessibleContext >) rxAccessibleContext { 79cdf0e10cSrcweir return [ NSValue valueWithPointer: ( rxAccessibleContext.get() + 2 ) ]; 80cdf0e10cSrcweir} 81cdf0e10cSrcweir 82cdf0e10cSrcweir+(AquaA11yWrapper *)wrapperForAccessible: (Reference < XAccessible >) rxAccessible { 83cdf0e10cSrcweir if ( rxAccessible.is() ) { 84cdf0e10cSrcweir Reference< XAccessibleContext > xAccessibleContext = rxAccessible->getAccessibleContext(); 85cdf0e10cSrcweir if( xAccessibleContext.is() ) { 86cdf0e10cSrcweir return [ AquaA11yFactory wrapperForAccessibleContext: xAccessibleContext ]; 87cdf0e10cSrcweir } 88cdf0e10cSrcweir } 89cdf0e10cSrcweir return nil; 90cdf0e10cSrcweir} 91cdf0e10cSrcweir 92cdf0e10cSrcweir+(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext { 93cdf0e10cSrcweir return [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: YES asRadioGroup: NO ]; 94cdf0e10cSrcweir} 95cdf0e10cSrcweir 96cdf0e10cSrcweir+(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext createIfNotExists:(BOOL) bCreate { 97cdf0e10cSrcweir return [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: bCreate asRadioGroup: NO ]; 98cdf0e10cSrcweir} 99cdf0e10cSrcweir 100cdf0e10cSrcweir+(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext createIfNotExists:(BOOL) bCreate asRadioGroup:(BOOL) asRadioGroup{ 101cdf0e10cSrcweir NSMutableDictionary * dAllWrapper = [ AquaA11yFactory allWrapper ]; 102cdf0e10cSrcweir NSValue * nKey = nil; 103cdf0e10cSrcweir if ( asRadioGroup ) { 104cdf0e10cSrcweir nKey = [ AquaA11yFactory keyForAccessibleContextAsRadioGroup: rxAccessibleContext ]; 105cdf0e10cSrcweir } else { 106cdf0e10cSrcweir nKey = [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ]; 107cdf0e10cSrcweir } 108cdf0e10cSrcweir AquaA11yWrapper * aWrapper = (AquaA11yWrapper *) [ dAllWrapper objectForKey: nKey ]; 109cdf0e10cSrcweir if ( aWrapper != nil ) { 110cdf0e10cSrcweir [ aWrapper retain ]; 111cdf0e10cSrcweir } else if ( bCreate ) { 112cdf0e10cSrcweir NSString * nativeRole = [ AquaA11yRoleHelper getNativeRoleFrom: rxAccessibleContext.get() ]; 113cdf0e10cSrcweir // TODO: reflection 114cdf0e10cSrcweir if ( [ nativeRole isEqualToString: NSAccessibilityButtonRole ] ) { 115cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperButton alloc ] initWithAccessibleContext: rxAccessibleContext ]; 116cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityTextAreaRole ] ) { 117cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperTextArea alloc ] initWithAccessibleContext: rxAccessibleContext ]; 118cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityStaticTextRole ] ) { 119cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperStaticText alloc ] initWithAccessibleContext: rxAccessibleContext ]; 120cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityComboBoxRole ] ) { 121cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperComboBox alloc ] initWithAccessibleContext: rxAccessibleContext ]; 122cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityGroupRole ] ) { 123cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperGroup alloc ] initWithAccessibleContext: rxAccessibleContext ]; 124cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityToolbarRole ] ) { 125cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperToolbar alloc ] initWithAccessibleContext: rxAccessibleContext ]; 126cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityScrollAreaRole ] ) { 127cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperScrollArea alloc ] initWithAccessibleContext: rxAccessibleContext ]; 128cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityTabGroupRole ] ) { 129cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperTabGroup alloc ] initWithAccessibleContext: rxAccessibleContext ]; 130cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityScrollBarRole ] ) { 131cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperScrollBar alloc ] initWithAccessibleContext: rxAccessibleContext ]; 132cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityCheckBoxRole ] ) { 133cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperCheckBox alloc ] initWithAccessibleContext: rxAccessibleContext ]; 134cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityRadioGroupRole ] ) { 135cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperRadioGroup alloc ] initWithAccessibleContext: rxAccessibleContext ]; 136cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityRadioButtonRole ] ) { 137cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperRadioButton alloc ] initWithAccessibleContext: rxAccessibleContext ]; 138cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityRowRole ] ) { 139cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperRow alloc ] initWithAccessibleContext: rxAccessibleContext ]; 140cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityListRole ] ) { 141cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperList alloc ] initWithAccessibleContext: rxAccessibleContext ]; 142cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilitySplitterRole ] ) { 143cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapperSplitter alloc ] initWithAccessibleContext: rxAccessibleContext ]; 144cdf0e10cSrcweir } else if ( [ nativeRole isEqualToString: NSAccessibilityTableRole ] ) { 145cdf0e10cSrcweir aWrapper = [ [ AquaA11yTableWrapper alloc ] initWithAccessibleContext: rxAccessibleContext ]; 146cdf0e10cSrcweir } else { 147cdf0e10cSrcweir aWrapper = [ [ AquaA11yWrapper alloc ] initWithAccessibleContext: rxAccessibleContext ]; 148cdf0e10cSrcweir } 149cdf0e10cSrcweir [ nativeRole release ]; 150cdf0e10cSrcweir [ aWrapper setActsAsRadioGroup: asRadioGroup ]; 151cdf0e10cSrcweir #if 0 152*24784eb8SJohn Bampton /* #i102033# NSAccessibility does not seem to know an equivalent for transient children. 153cdf0e10cSrcweir That means we need to cache this, else e.g. tree list boxes are not accessible (moreover 154*24784eb8SJohn Bampton it crashes by notifying dead objects - which would seemt to be another bug) 155cdf0e10cSrcweir 156cdf0e10cSrcweir FIXME: 157cdf0e10cSrcweir Unfortunately this can increase memory consumption drastically until the non transient parent 158*24784eb8SJohn Bampton is destroyed and finally all the transients are released. 159cdf0e10cSrcweir */ 160cdf0e10cSrcweir if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) ) 161cdf0e10cSrcweir #endif 162cdf0e10cSrcweir { 163cdf0e10cSrcweir [ dAllWrapper setObject: aWrapper forKey: nKey ]; 164cdf0e10cSrcweir } 165cdf0e10cSrcweir } 166cdf0e10cSrcweir return aWrapper; 167cdf0e10cSrcweir} 168cdf0e10cSrcweir 169cdf0e10cSrcweir+(void)insertIntoWrapperRepository: (NSView *) viewElement forAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext { 170cdf0e10cSrcweir NSMutableDictionary * dAllWrapper = [ AquaA11yFactory allWrapper ]; 171cdf0e10cSrcweir [ dAllWrapper setObject: viewElement forKey: [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ] ]; 172cdf0e10cSrcweir} 173cdf0e10cSrcweir 174cdf0e10cSrcweir+(void)removeFromWrapperRepositoryFor: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext { 175cdf0e10cSrcweir // TODO: when RADIO_BUTTON search for associated RadioGroup-wrapper and delete that as well 176cdf0e10cSrcweir AquaA11yWrapper * theWrapper = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: NO ]; 177cdf0e10cSrcweir if ( theWrapper != nil ) { 178cdf0e10cSrcweir [ [ AquaA11yFactory allWrapper ] removeObjectForKey: [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ] ]; 179cdf0e10cSrcweir [ theWrapper release ]; 180cdf0e10cSrcweir } 181cdf0e10cSrcweir} 182cdf0e10cSrcweir 183cdf0e10cSrcweir+(void)registerView: (NSView *) theView { 184cdf0e10cSrcweir if ( enabled && [ theView isKindOfClass: [ AquaA11yWrapper class ] ] ) { 185cdf0e10cSrcweir // insertIntoWrapperRepository gets called from SalFrameView itself to bootstrap the bridge initially 186cdf0e10cSrcweir [ (AquaA11yWrapper *) theView accessibleContext ]; 187cdf0e10cSrcweir } 188cdf0e10cSrcweir} 189cdf0e10cSrcweir 190cdf0e10cSrcweir+(void)revokeView: (NSView *) theView { 191cdf0e10cSrcweir if ( enabled && [ theView isKindOfClass: [ AquaA11yWrapper class ] ] ) { 192cdf0e10cSrcweir [ AquaA11yFactory removeFromWrapperRepositoryFor: [ (AquaA11yWrapper *) theView accessibleContext ] ]; 193cdf0e10cSrcweir } 194cdf0e10cSrcweir} 195cdf0e10cSrcweir 196cdf0e10cSrcweir@end 197