xref: /trunk/main/vcl/aqua/source/a11y/aqua11yfactory.mm (revision 24784eb80b61bc1709c3e7f636228090e1d3f93c)
1323de322SAndrew Rist/**************************************************************
2cdf0e10cSrcweir *
3323de322SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4323de322SAndrew Rist * or more contributor license agreements.  See the NOTICE file
5323de322SAndrew Rist * distributed with this work for additional information
6323de322SAndrew Rist * regarding copyright ownership.  The ASF licenses this file
7323de322SAndrew Rist * to you under the Apache License, Version 2.0 (the
8323de322SAndrew Rist * "License"); you may not use this file except in compliance
9323de322SAndrew Rist * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir *
11323de322SAndrew Rist *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir *
13323de322SAndrew Rist * Unless required by applicable law or agreed to in writing,
14323de322SAndrew Rist * software distributed under the License is distributed on an
15323de322SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16323de322SAndrew Rist * KIND, either express or implied.  See the License for the
17323de322SAndrew Rist * specific language governing permissions and limitations
18323de322SAndrew Rist * under the License.
19cdf0e10cSrcweir *
20323de322SAndrew Rist *************************************************************/
21323de322SAndrew Rist
22323de322SAndrew 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
152*24784eb8SJohn Bampton        /* #i102033# NSAccessibility does not seem 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
154*24784eb8SJohn Bampton           it crashes by notifying dead objects - which would seemt to be another bug)
155cdf0e10cSrcweir
156cdf0e10cSrcweir           FIXME:
157cdf0e10cSrcweir           Unfortunately this can increase memory consumption drastically until the non transient parent
158*24784eb8SJohn Bampton           is destroyed and 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