xref: /AOO41X/main/vcl/aqua/source/a11y/aqua11yfactory.mm (revision 323de322b8e3c385116436869e4ba6b658fb6405)
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