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