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