1*323de322SAndrew Rist/************************************************************** 2cdf0e10cSrcweir * 3*323de322SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*323de322SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*323de322SAndrew Rist * distributed with this work for additional information 6*323de322SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*323de322SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*323de322SAndrew Rist * "License"); you may not use this file except in compliance 9*323de322SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*323de322SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*323de322SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*323de322SAndrew Rist * software distributed under the License is distributed on an 15*323de322SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*323de322SAndrew Rist * KIND, either express or implied. See the License for the 17*323de322SAndrew Rist * specific language governing permissions and limitations 18*323de322SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*323de322SAndrew Rist *************************************************************/ 21*323de322SAndrew Rist 22*323de322SAndrew 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 152cdf0e10cSrcweir /* #i102033# NSAccessibility does not seemt 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 154cdf0e10cSrcweir it crashes by notifying dead objects - which would seemt o be another bug) 155cdf0e10cSrcweir 156cdf0e10cSrcweir FIXME: 157cdf0e10cSrcweir Unfortunately this can increase memory consumption drastically until the non transient parent 158cdf0e10cSrcweir is destroyed an 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