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 
  27 package com.sun.java.accessibility.util;
  28 
  29 import com.sun.java.accessibility.util.internal.*;
  30 import java.beans.*;
  31 import java.util.*;
  32 import java.awt.*;
  33 import 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.*;
  37 import 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  */
  60 public 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 }