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