Translator.java revision 14243:2ad92ad4e9a9
1/*
2 * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package com.sun.java.accessibility.util;
28
29import com.sun.java.accessibility.util.internal.*;
30import java.beans.*;
31import java.util.*;
32import java.awt.*;
33import java.awt.event.*;
34// Do not import Swing classes.  This module is intended to work
35// with both Swing and AWT.
36// import javax.swing.*;
37import javax.accessibility.*;
38
39/**
40 * <p>The {@code Translator} class provides a translation to interface
41 * {@link javax.accessibility.Accessible Accessible}
42 * for objects that do not implement interface {@code Accessible}.  Assistive
43 * technologies can use the {@link #getAccessible getAccessible} class method of
44 * {@code Translator} to obtain an object that implements interface {@code Accessible}.
45 * If the object passed in already implements interface {@code Accessible},
46 * {@code getAccessible} merely returns the object.
47 *
48 * <p>An example of how an assistive technology might use the {@code Translator}
49 * class is as follows:
50 *
51 * <PRE>
52 *    Accessible accessible = Translator.getAccessible(someObj);
53 *    // obtain information from the 'accessible' object.
54 * </PRE>
55 *
56 * <P>Note:  This implementation is missing many things and is not a recommended way
57 * to implement accessibility features for a toolkit.  Instead of relying upon this
58 * code, a toolkit's components should implement interface {@code Accessible} directly.
59 */
60public class Translator extends AccessibleContext
61        implements Accessible, AccessibleComponent {
62
63    /** The source object needing translating. */
64    protected Object source;
65
66    /**
67     * Find a translator for this class.  If one doesn't exist for this
68     * class explicitly, try its superclass and so on.
69     *
70     * @param c a Class
71     * @return the {@code Translator} Class for the Class passed in
72     */
73    protected static Class<?> getTranslatorClass(Class<?> c) {
74        Class<?> t = null;
75        if (c == null) {
76            return null;
77        }
78        switch (c.getSimpleName()) {
79            case "Button":
80                t = ButtonTranslator.class;
81                break;
82            case "Checkbox":
83                t = CheckboxTranslator.class;
84                break;
85            case "Label":
86                t = LabelTranslator.class;
87                break;
88            case "List":
89                t = ListTranslator.class;
90                break;
91            case "TextComponent":
92                t = TextComponentTranslator.class;
93                break;
94        }
95        if (t != null) {
96            return t;
97        } else {
98            return getTranslatorClass(c.getSuperclass());
99        }
100    }
101
102    /**
103     * Obtain an object that implements interface {@code Accessible}.  If the object
104     * passed in already implements interface {@code Accessible}, {@code getAccessible}
105     * merely returns the object.
106     *
107     * @param o an Object; if a null is passed in a null is returned
108     * @return an {@code Object}, possibly the {@code Object} passed in, that
109     *     implements the {@code Accessible} interface for the {@code Object}
110     *     which was passed in
111     */
112    public static Accessible getAccessible(Object o) {
113        Accessible a = null;
114
115        if (o == null) {
116            return null;
117        }
118        if (o instanceof Accessible) {
119            a = (Accessible)o;
120        } else {
121            Class<?> translatorClass = getTranslatorClass(o.getClass());
122            if (translatorClass != null) {
123                try {
124                    Translator t = (Translator)translatorClass.newInstance();
125                    t.setSource(o);
126                    a = t;
127                } catch (Exception e) {
128                }
129            }
130        }
131        if (a == null) {
132            a = new Translator(o);
133        }
134        return a;
135    }
136
137    /**
138     * Create a new {@code Translator}.  You must call the {@link #setSource setSource}
139     * method to set the object to be translated after calling this constructor.
140     */
141    public Translator() {
142    }
143
144    /**
145     * Create a new {@code Translator} with the source object o.
146     *
147     * @param o the Component that does not implement interface
148     *     {@link javax.accessibility.Accessible Accessible}
149     */
150    public Translator(Object o) {
151        source = o;
152    }
153
154    /**
155     * Get the source {@code Object} of the {@code Translator}.
156     *
157     * @return the source {@code Object} of the {@code Translator}
158     */
159    public Object getSource() {
160        return source;
161    }
162
163    /**
164     * Set the source object of the {@code Translator}.
165     *
166     * @param o the Component that does not implement interface Accessible
167     */
168    public void setSource(Object o) {
169        source = o;
170    }
171
172    /**
173     * Returns true if this object is the same as the one passed in.
174     *
175     * @param o the {@code Object} to check against
176     * @return true if this is the same object
177     */
178    public boolean equals(Object o) {
179        if (o instanceof Translator) {
180            return java.util.Objects.equals(source, o);
181        } else {
182            return false;
183        }
184    }
185
186    /**
187     * Return hashcode.
188     *
189     * @return hashcode
190     */
191    public int hashCode() {
192        return java.util.Objects.hashCode(source);
193    }
194
195
196// Accessible methods
197
198    /**
199     * Returns this object.
200     */
201    public AccessibleContext getAccessibleContext() {
202        return this;
203    }
204
205// AccessibleContext methods
206
207    /**
208     * Get the accessible name of this object.
209     *
210     * @return the localized name of the object; can be null if this object
211     *     does not have a name
212     */
213    public String getAccessibleName() {
214        if (source instanceof MenuItem) {
215            return ((MenuItem) source).getLabel();
216        } else if (source instanceof Component) {
217            return ((Component) source).getName();
218        } else {
219            return null;
220        }
221    }
222
223    /**
224     * Set the name of this object.
225     */
226    public void setAccessibleName(String s) {
227        if (source instanceof MenuItem) {
228            ((MenuItem) source).setLabel(s);
229        } else if (source instanceof Component) {
230            ((Component) source).setName(s);
231        }
232    }
233
234    /**
235     * Get the accessible description of this object.
236     *
237     * @return the description of the object; can be null if this object does
238     * not have a description
239     */
240    public String getAccessibleDescription() {
241        return null;
242    }
243
244    /**
245     * Set the accessible description of this object.
246     *
247     * @param s the new localized description of the object
248     */
249    public void setAccessibleDescription(String s) {
250    }
251
252    /**
253     * Get the role of this object.
254     *
255     * @return an instance of AccessibleRole describing the role of the object
256     */
257    public AccessibleRole getAccessibleRole() {
258        return AccessibleRole.UNKNOWN;
259    }
260
261
262    /**
263     * Get the state of this object, given an already populated state.
264     * This method is intended for use by subclasses so they don't have
265     * to check for everything.
266     *
267     * @return an instance of {@code AccessibleStateSet}
268     *     containing the current state of the object
269     */
270    public AccessibleStateSet getAccessibleStateSet() {
271        AccessibleStateSet states = new AccessibleStateSet();
272        if (source instanceof Component) {
273            Component c = (Component) source;
274            for (Container p = c.getParent(); p != null; p = p.getParent()) {
275                if (p instanceof Window) {
276                    if (((Window)p).getFocusOwner() == c) {
277                        states.add(AccessibleState.FOCUSED);
278                    }
279                }
280            }
281        }
282        if (isEnabled()) {
283            states.add(AccessibleState.ENABLED);
284        }
285        if (isFocusTraversable()) {
286            states.add(AccessibleState.FOCUSABLE);
287        }
288        if (source instanceof MenuItem) {
289            states.add(AccessibleState.FOCUSABLE);
290        }
291        return states;
292    }
293
294    /**
295     * Get the accessible parent of this object.
296     *
297     * @return the accessible parent of this object; can be null if this
298     *     object does not have an accessible parent
299     */
300    public Accessible getAccessibleParent() {
301        if (accessibleParent != null) {
302            return accessibleParent;
303        } else if (source instanceof Component) {
304            return getAccessible(((Component) source).getParent());
305        } else {
306            return null;
307        }
308    }
309
310    /**
311     * Get the index of this object in its accessible parent.
312     *
313     * @return -1 of this object does not have an accessible parent; otherwise,
314     * the index of the child in its accessible parent
315     */
316    public int getAccessibleIndexInParent() {
317        if (source instanceof Component) {
318            Container parent = ((Component) source).getParent();
319            if (parent != null) {
320                Component ca[] = parent.getComponents();
321                for (int i = 0; i < ca.length; i++) {
322                    if (source.equals(ca[i])) {
323                        return i;
324                    }
325                }
326            }
327        }
328        return -1;
329    }
330
331    /**
332     * Returns the number of accessible children in the object.
333     *
334     * @return the number of accessible children in the object
335     */
336    public int getAccessibleChildrenCount() {
337        if (source instanceof Container) {
338            Component[] children = ((Container) source).getComponents();
339            int count = 0;
340            for (int i = 0; i < children.length; i++) {
341                Accessible a = getAccessible(children[i]);
342                if (a != null) {
343                    count++;
344                }
345            }
346            return count;
347        } else {
348            return 0;
349        }
350    }
351
352    /**
353     * Return the nth accessible child of the object.
354     *
355     * @param i zero-based index of child
356     * @return the nth accessible child of the object
357     */
358    public Accessible getAccessibleChild(int i) {
359        if (source instanceof Container) {
360            Component[] children = ((Container) source).getComponents();
361            int count = 0;
362
363            for (int j = 0; j < children.length; j++) {
364                Accessible a = getAccessible(children[j]);
365                if (a != null) {
366                    if (count == i) {
367                        AccessibleContext ac = a.getAccessibleContext();
368                        if (ac != null) {
369                            ac.setAccessibleParent(this);
370                        }
371                        return a;
372                    } else {
373                        count++;
374                    }
375                }
376            }
377        }
378        return null;
379    }
380
381    /**
382     * Gets the {@code Locale} of the component. If the component does not have a
383     * locale, the locale of its parent is returned.
384     *
385     * @return the {@code Locale} of the object
386     */
387    public Locale getLocale() throws IllegalComponentStateException {
388        if (source instanceof Component) {
389            return ((Component) source).getLocale();
390        } else {
391            return null;
392        }
393    }
394
395    /**
396     * Add a {@code PropertyChangeListener} to the listener list.  The listener
397     * is registered for all properties.
398     */
399    public void addPropertyChangeListener(PropertyChangeListener l) {
400    }
401
402    /**
403     * Remove the {@code PropertyChangeListener} from the listener list.
404     */
405    public void removePropertyChangeListener(PropertyChangeListener l) {
406    }
407
408// AccessibleComponent methods
409
410    /**
411     * Get the background {@code Color} of this object.
412     *
413     * @return if supported, the background {@code Color} of the object;
414     *     otherwise, null
415     *
416     */
417    public Color getBackground() {
418        if (source instanceof Component) { // MenuComponent doesn't do background
419            return ((Component) source).getBackground();
420        } else {
421            return null;
422        }
423    }
424
425    /**
426     * Set the background {@code Color} of this object.
427     *
428     * @param c the new {@code Color} for the background
429     */
430    public void setBackground(Color c) {
431        if (source instanceof Component) { // MenuComponent doesn't do background
432            ((Component) source).setBackground(c);
433        }
434    }
435
436    /**
437     * Get the foreground {@code Color} of this object.
438     *
439     * @return if supported, the foreground {@code Color} of the object; otherwise, null
440     */
441    public Color getForeground() {
442        if (source instanceof Component) { // MenuComponent doesn't do foreground
443            return ((Component) source).getForeground();
444        } else {
445            return null;
446        }
447    }
448
449    /**
450     * Set the foreground {@code Color} of this object.
451     *
452     * @param c the new {@code Color} for the foreground
453     */
454    public void setForeground(Color c) {
455        if (source instanceof Component) { // MenuComponent doesn't do foreground
456            ((Component) source).setForeground(c);
457        }
458    }
459
460    /**
461     * Get the {@code Cursor} of this object.
462     *
463     * @return if supported, the Cursor of the object; otherwise, null
464     */
465    public Cursor getCursor() {
466        if (source instanceof Component) { // MenuComponent doesn't do cursor
467            return ((Component) source).getCursor();
468        } else {
469            return null;
470        }
471    }
472
473    /**
474     * Set the {@code Cursor} of this object.
475     * @param c the new {@code Cursor} for the object
476     */
477    public void setCursor(Cursor c) {
478        if (source instanceof Component) { // MenuComponent doesn't do cursor
479            ((Component) source).setCursor(c);
480        }
481    }
482
483    /**
484     * Get the {@code Font} of this object.
485     *
486     * @return if supported, the {@code Font} for the object; otherwise, null
487     */
488    public Font getFont() {
489        if (source instanceof Component) {
490            return ((Component) source).getFont();
491        } else if (source instanceof MenuComponent) {
492            return ((MenuComponent) source).getFont();
493        } else {
494            return null;
495        }
496    }
497
498    /**
499     * Set the {@code Font} of this object.
500     *
501     * @param f the new {@code Font} for the object
502     */
503    public void setFont(Font f) {
504        if (source instanceof Component) {
505            ((Component) source).setFont(f);
506        } else if (source instanceof MenuComponent) {
507            ((MenuComponent) source).setFont(f);
508        }
509    }
510
511    /**
512     * Get the {@code FontMetrics} of this object.
513     *
514     * @param f the {@code Font}
515     * @return if supported, the {@code FontMetrics} the object; otherwise, null
516     * @see #getFont
517     */
518    public FontMetrics getFontMetrics(Font f) {
519        if (source instanceof Component) {
520            return ((Component) source).getFontMetrics(f);
521        } else {
522            return null;
523        }
524    }
525
526    /**
527     * Determine if the object is enabled.
528     *
529     * @return true if object is enabled; otherwise, false
530     */
531    public boolean isEnabled() {
532        if (source instanceof Component) {
533            return ((Component) source).isEnabled();
534        } else if (source instanceof MenuItem) {
535            return ((MenuItem) source).isEnabled();
536        } else {
537            return true;
538        }
539    }
540
541    /**
542     * Set the enabled state of the object.
543     *
544     * @param b if true, enables this object; otherwise, disables it
545     */
546    public void setEnabled(boolean b) {
547        if (source instanceof Component) {
548            ((Component) source).setEnabled(b);
549        } else if (source instanceof MenuItem) {
550            ((MenuItem) source).setEnabled(b);
551        }
552    }
553
554    /**
555     * Determine if the object is visible.
556     *
557     * @return true if object is visible; otherwise, false
558     */
559    public boolean isVisible() {
560        if (source instanceof Component) {
561            return ((Component) source).isVisible();
562        } else {
563            return false;
564        }
565    }
566
567    /**
568     * Set the visible state of the object.
569     *
570     * @param b if true, shows this object; otherwise, hides it
571     */
572    public void setVisible(boolean b) {
573        if (source instanceof Component) {
574            ((Component) source).setVisible(b);
575        }
576    }
577
578    /**
579     * Determine if the object is showing.  This is determined by checking
580     * the visibility of the object and ancestors of the object.
581     *
582     * @return true if object is showing; otherwise, false
583     */
584    public boolean isShowing() {
585        if (source instanceof Component) {
586            return ((Component) source).isShowing();
587        } else {
588            return false;
589        }
590    }
591
592    /**
593     * Checks whether the specified {@code Point} is within this
594     * object's bounds, where the {@code Point} is relative to the coordinate
595     * system of the object.
596     *
597     * @param p the {@code Point} relative to the coordinate system of the object
598     * @return true if object contains {@code Point}; otherwise false
599     */
600    public boolean contains(Point p) {
601        if (source instanceof Component) {
602            return ((Component) source).contains(p);
603        } else {
604            return false;
605        }
606    }
607
608    /**
609     * Returns the location of the object on the screen.
610     *
611     * @return location of object on screen; can be null if this object
612     *     is not on the screen
613     */
614    public Point getLocationOnScreen() {
615        if (source instanceof Component) {
616            return ((Component) source).getLocationOnScreen();
617        } else {
618            return null;
619        }
620    }
621
622    /**
623     * Returns the location of the object relative to parent.
624     *
625     * @return location of object relative to parent; can be null if
626     *     this object or its parent are not on the screen
627     */
628    public Point getLocation() {
629        if (source instanceof Component) {
630            return ((Component) source).getLocation();
631        } else {
632            return null;
633        }
634    }
635
636    /**
637     * Sets the location of the object relative to parent.
638     */
639    public void setLocation(Point p) {
640        if (source instanceof Component) {
641            ((Component) source).setLocation(p);
642        }
643    }
644
645    /**
646     * Returns the current bounds of this object.
647     *
648     * @return current bounds of object; can be null if this object
649     *     is not on the screen
650     */
651    public Rectangle getBounds() {
652        if (source instanceof Component) {
653            return ((Component) source).getBounds();
654        } else {
655            return null;
656        }
657    }
658
659    /**
660     * Sets the current bounds of this object.
661     */
662    public void setBounds(Rectangle r) {
663        if (source instanceof Component) {
664            ((Component) source).setBounds(r);
665        }
666    }
667
668    /**
669     * Returns the current size of this object.
670     *
671     * @return current size of object; can be null if this object is
672     *     not on the screen
673     */
674    public Dimension getSize() {
675        if (source instanceof Component) {
676            return ((Component) source).getSize();
677        } else {
678            return null;
679        }
680    }
681
682    /**
683     * Sets the current size of this object.
684     */
685    public void setSize(Dimension d) {
686        if (source instanceof Component) {
687            ((Component) source).setSize(d);
688        }
689    }
690
691    /**
692     * Returns the accessible child contained at the local coordinate
693     * Point, if one exists.
694     *
695     * @return the Accessible at the specified location, if it exists
696     */
697    public Accessible getAccessibleAt(Point p) {
698        if (source instanceof Component) {
699            Component c = ((Component) source).getComponentAt(p);
700            if (c != null) {
701                return (getAccessible(c));
702            }
703        }
704        return null;
705    }
706
707    /**
708     * Returns whether this object can accept focus or not.
709     *
710     * @return true if object can accept focus; otherwise false
711     */
712    @SuppressWarnings("deprecation")
713    public boolean isFocusTraversable() {
714        if (source instanceof Component) {
715            return ((Component) source).isFocusTraversable();
716        } else {
717            return false;
718        }
719    }
720
721    /**
722     * Requests focus for this object.
723     */
724    public void requestFocus() {
725        if (source instanceof Component) {
726            ((Component) source).requestFocus();
727        }
728    }
729
730    /**
731     * Adds the specified {@code FocusListener} to receive focus events from
732     * this component.
733     *
734     * @param l the focus listener
735     */
736    public synchronized void addFocusListener(FocusListener l) {
737        if (source instanceof Component) {
738            ((Component) source).addFocusListener(l);
739        }
740    }
741
742    /**
743     * Removes the specified focus listener so it no longer receives focus
744     * events from this component.
745     *
746     * @param l the focus listener; this method performs no function, nor does it
747     *     throw an exception if the listener specified was not previously added
748     *     to this component; if listener is null, no exception is thrown and no
749     *     action is performed.
750     */
751    public synchronized void removeFocusListener(FocusListener l) {
752        if (source instanceof Component) {
753            ((Component) source).removeFocusListener(l);
754        }
755    }
756}
757