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                     @SuppressWarnings("deprecation")
 125                     Translator t = (Translator)translatorClass.newInstance();
 126                     t.setSource(o);
 127                     a = t;
 128                 } catch (Exception e) {
 129                 }
 130             }
 131         }
 132         if (a == null) {
 133             a = new Translator(o);
 134         }
 135         return a;
 136     }
 137 
 138     /**
 139      * Create a new {@code Translator}.  You must call the {@link #setSource setSource}
 140      * method to set the object to be translated after calling this constructor.
 141      */
 142     public Translator() {
 143     }
 144 
 145     /**
 146      * Create a new {@code Translator} with the source object o.
 147      *
 148      * @param o the Component that does not implement interface
 149      *     {@link javax.accessibility.Accessible Accessible}
 150      */
 151     public Translator(Object o) {
 152         source = o;
 153     }
 154 
 155     /**
 156      * Get the source {@code Object} of the {@code Translator}.
 157      *
 158      * @return the source {@code Object} of the {@code Translator}
 159      */
 160     public Object getSource() {
 161         return source;
 162     }
 163 
 164     /**
 165      * Set the source object of the {@code Translator}.
 166      *
 167      * @param o the Component that does not implement interface Accessible
 168      */
 169     public void setSource(Object o) {
 170         source = o;
 171     }
 172 
 173     /**
 174      * Returns true if this object is the same as the one passed in.
 175      *
 176      * @param o the {@code Object} to check against
 177      * @return true if this is the same object
 178      */
 179     public boolean equals(Object o) {
 180         if (o instanceof Translator) {
 181             return java.util.Objects.equals(source, o);
 182         } else {
 183             return false;
 184         }
 185     }
 186 
 187     /**
 188      * Return hashcode.
 189      *
 190      * @return hashcode
 191      */
 192     public int hashCode() {
 193         return java.util.Objects.hashCode(source);
 194     }
 195 
 196 
 197 // Accessible methods
 198 
 199     /**
 200      * Returns this object.
 201      */
 202     public AccessibleContext getAccessibleContext() {
 203         return this;
 204     }
 205 
 206 // AccessibleContext methods
 207 
 208     /**
 209      * Get the accessible name of this object.
 210      *
 211      * @return the localized name of the object; can be null if this object
 212      *     does not have a name
 213      */
 214     public String getAccessibleName() {
 215         if (source instanceof MenuItem) {
 216             return ((MenuItem) source).getLabel();
 217         } else if (source instanceof Component) {
 218             return ((Component) source).getName();
 219         } else {
 220             return null;
 221         }
 222     }
 223 
 224     /**
 225      * Set the name of this object.
 226      */
 227     public void setAccessibleName(String s) {
 228         if (source instanceof MenuItem) {
 229             ((MenuItem) source).setLabel(s);
 230         } else if (source instanceof Component) {
 231             ((Component) source).setName(s);
 232         }
 233     }
 234 
 235     /**
 236      * Get the accessible description of this object.
 237      *
 238      * @return the description of the object; can be null if this object does
 239      * not have a description
 240      */
 241     public String getAccessibleDescription() {
 242         return null;
 243     }
 244 
 245     /**
 246      * Set the accessible description of this object.
 247      *
 248      * @param s the new localized description of the object
 249      */
 250     public void setAccessibleDescription(String s) {
 251     }
 252 
 253     /**
 254      * Get the role of this object.
 255      *
 256      * @return an instance of AccessibleRole describing the role of the object
 257      */
 258     public AccessibleRole getAccessibleRole() {
 259         return AccessibleRole.UNKNOWN;
 260     }
 261 
 262 
 263     /**
 264      * Get the state of this object, given an already populated state.
 265      * This method is intended for use by subclasses so they don't have
 266      * to check for everything.
 267      *
 268      * @return an instance of {@code AccessibleStateSet}
 269      *     containing the current state of the object
 270      */
 271     public AccessibleStateSet getAccessibleStateSet() {
 272         AccessibleStateSet states = new AccessibleStateSet();
 273         if (source instanceof Component) {
 274             Component c = (Component) source;
 275             for (Container p = c.getParent(); p != null; p = p.getParent()) {
 276                 if (p instanceof Window) {
 277                     if (((Window)p).getFocusOwner() == c) {
 278                         states.add(AccessibleState.FOCUSED);
 279                     }
 280                 }
 281             }
 282         }
 283         if (isEnabled()) {
 284             states.add(AccessibleState.ENABLED);
 285         }
 286         if (isFocusTraversable()) {
 287             states.add(AccessibleState.FOCUSABLE);
 288         }
 289         if (source instanceof MenuItem) {
 290             states.add(AccessibleState.FOCUSABLE);
 291         }
 292         return states;
 293     }
 294 
 295     /**
 296      * Get the accessible parent of this object.
 297      *
 298      * @return the accessible parent of this object; can be null if this
 299      *     object does not have an accessible parent
 300      */
 301     public Accessible getAccessibleParent() {
 302         if (accessibleParent != null) {
 303             return accessibleParent;
 304         } else if (source instanceof Component) {
 305             return getAccessible(((Component) source).getParent());
 306         } else {
 307             return null;
 308         }
 309     }
 310 
 311     /**
 312      * Get the index of this object in its accessible parent.
 313      *
 314      * @return -1 of this object does not have an accessible parent; otherwise,
 315      * the index of the child in its accessible parent
 316      */
 317     public int getAccessibleIndexInParent() {
 318         if (source instanceof Component) {
 319             Container parent = ((Component) source).getParent();
 320             if (parent != null) {
 321                 Component ca[] = parent.getComponents();
 322                 for (int i = 0; i < ca.length; i++) {
 323                     if (source.equals(ca[i])) {
 324                         return i;
 325                     }
 326                 }
 327             }
 328         }
 329         return -1;
 330     }
 331 
 332     /**
 333      * Returns the number of accessible children in the object.
 334      *
 335      * @return the number of accessible children in the object
 336      */
 337     public int getAccessibleChildrenCount() {
 338         if (source instanceof Container) {
 339             Component[] children = ((Container) source).getComponents();
 340             int count = 0;
 341             for (int i = 0; i < children.length; i++) {
 342                 Accessible a = getAccessible(children[i]);
 343                 if (a != null) {
 344                     count++;
 345                 }
 346             }
 347             return count;
 348         } else {
 349             return 0;
 350         }
 351     }
 352 
 353     /**
 354      * Return the nth accessible child of the object.
 355      *
 356      * @param i zero-based index of child
 357      * @return the nth accessible child of the object
 358      */
 359     public Accessible getAccessibleChild(int i) {
 360         if (source instanceof Container) {
 361             Component[] children = ((Container) source).getComponents();
 362             int count = 0;
 363 
 364             for (int j = 0; j < children.length; j++) {
 365                 Accessible a = getAccessible(children[j]);
 366                 if (a != null) {
 367                     if (count == i) {
 368                         AccessibleContext ac = a.getAccessibleContext();
 369                         if (ac != null) {
 370                             ac.setAccessibleParent(this);
 371                         }
 372                         return a;
 373                     } else {
 374                         count++;
 375                     }
 376                 }
 377             }
 378         }
 379         return null;
 380     }
 381 
 382     /**
 383      * Gets the {@code Locale} of the component. If the component does not have a
 384      * locale, the locale of its parent is returned.
 385      *
 386      * @return the {@code Locale} of the object
 387      */
 388     public Locale getLocale() throws IllegalComponentStateException {
 389         if (source instanceof Component) {
 390             return ((Component) source).getLocale();
 391         } else {
 392             return null;
 393         }
 394     }
 395 
 396     /**
 397      * Add a {@code PropertyChangeListener} to the listener list.  The listener
 398      * is registered for all properties.
 399      */
 400     public void addPropertyChangeListener(PropertyChangeListener l) {
 401     }
 402 
 403     /**
 404      * Remove the {@code PropertyChangeListener} from the listener list.
 405      */
 406     public void removePropertyChangeListener(PropertyChangeListener l) {
 407     }
 408 
 409 // AccessibleComponent methods
 410 
 411     /**
 412      * Get the background {@code Color} of this object.
 413      *
 414      * @return if supported, the background {@code Color} of the object;
 415      *     otherwise, null
 416      *
 417      */
 418     public Color getBackground() {
 419         if (source instanceof Component) { // MenuComponent doesn't do background
 420             return ((Component) source).getBackground();
 421         } else {
 422             return null;
 423         }
 424     }
 425 
 426     /**
 427      * Set the background {@code Color} of this object.
 428      *
 429      * @param c the new {@code Color} for the background
 430      */
 431     public void setBackground(Color c) {
 432         if (source instanceof Component) { // MenuComponent doesn't do background
 433             ((Component) source).setBackground(c);
 434         }
 435     }
 436 
 437     /**
 438      * Get the foreground {@code Color} of this object.
 439      *
 440      * @return if supported, the foreground {@code Color} of the object; otherwise, null
 441      */
 442     public Color getForeground() {
 443         if (source instanceof Component) { // MenuComponent doesn't do foreground
 444             return ((Component) source).getForeground();
 445         } else {
 446             return null;
 447         }
 448     }
 449 
 450     /**
 451      * Set the foreground {@code Color} of this object.
 452      *
 453      * @param c the new {@code Color} for the foreground
 454      */
 455     public void setForeground(Color c) {
 456         if (source instanceof Component) { // MenuComponent doesn't do foreground
 457             ((Component) source).setForeground(c);
 458         }
 459     }
 460 
 461     /**
 462      * Get the {@code Cursor} of this object.
 463      *
 464      * @return if supported, the Cursor of the object; otherwise, null
 465      */
 466     public Cursor getCursor() {
 467         if (source instanceof Component) { // MenuComponent doesn't do cursor
 468             return ((Component) source).getCursor();
 469         } else {
 470             return null;
 471         }
 472     }
 473 
 474     /**
 475      * Set the {@code Cursor} of this object.
 476      * @param c the new {@code Cursor} for the object
 477      */
 478     public void setCursor(Cursor c) {
 479         if (source instanceof Component) { // MenuComponent doesn't do cursor
 480             ((Component) source).setCursor(c);
 481         }
 482     }
 483 
 484     /**
 485      * Get the {@code Font} of this object.
 486      *
 487      * @return if supported, the {@code Font} for the object; otherwise, null
 488      */
 489     public Font getFont() {
 490         if (source instanceof Component) {
 491             return ((Component) source).getFont();
 492         } else if (source instanceof MenuComponent) {
 493             return ((MenuComponent) source).getFont();
 494         } else {
 495             return null;
 496         }
 497     }
 498 
 499     /**
 500      * Set the {@code Font} of this object.
 501      *
 502      * @param f the new {@code Font} for the object
 503      */
 504     public void setFont(Font f) {
 505         if (source instanceof Component) {
 506             ((Component) source).setFont(f);
 507         } else if (source instanceof MenuComponent) {
 508             ((MenuComponent) source).setFont(f);
 509         }
 510     }
 511 
 512     /**
 513      * Get the {@code FontMetrics} of this object.
 514      *
 515      * @param f the {@code Font}
 516      * @return if supported, the {@code FontMetrics} the object; otherwise, null
 517      * @see #getFont
 518      */
 519     public FontMetrics getFontMetrics(Font f) {
 520         if (source instanceof Component) {
 521             return ((Component) source).getFontMetrics(f);
 522         } else {
 523             return null;
 524         }
 525     }
 526 
 527     /**
 528      * Determine if the object is enabled.
 529      *
 530      * @return true if object is enabled; otherwise, false
 531      */
 532     public boolean isEnabled() {
 533         if (source instanceof Component) {
 534             return ((Component) source).isEnabled();
 535         } else if (source instanceof MenuItem) {
 536             return ((MenuItem) source).isEnabled();
 537         } else {
 538             return true;
 539         }
 540     }
 541 
 542     /**
 543      * Set the enabled state of the object.
 544      *
 545      * @param b if true, enables this object; otherwise, disables it
 546      */
 547     public void setEnabled(boolean b) {
 548         if (source instanceof Component) {
 549             ((Component) source).setEnabled(b);
 550         } else if (source instanceof MenuItem) {
 551             ((MenuItem) source).setEnabled(b);
 552         }
 553     }
 554 
 555     /**
 556      * Determine if the object is visible.
 557      *
 558      * @return true if object is visible; otherwise, false
 559      */
 560     public boolean isVisible() {
 561         if (source instanceof Component) {
 562             return ((Component) source).isVisible();
 563         } else {
 564             return false;
 565         }
 566     }
 567 
 568     /**
 569      * Set the visible state of the object.
 570      *
 571      * @param b if true, shows this object; otherwise, hides it
 572      */
 573     public void setVisible(boolean b) {
 574         if (source instanceof Component) {
 575             ((Component) source).setVisible(b);
 576         }
 577     }
 578 
 579     /**
 580      * Determine if the object is showing.  This is determined by checking
 581      * the visibility of the object and ancestors of the object.
 582      *
 583      * @return true if object is showing; otherwise, false
 584      */
 585     public boolean isShowing() {
 586         if (source instanceof Component) {
 587             return ((Component) source).isShowing();
 588         } else {
 589             return false;
 590         }
 591     }
 592 
 593     /**
 594      * Checks whether the specified {@code Point} is within this
 595      * object's bounds, where the {@code Point} is relative to the coordinate
 596      * system of the object.
 597      *
 598      * @param p the {@code Point} relative to the coordinate system of the object
 599      * @return true if object contains {@code Point}; otherwise false
 600      */
 601     public boolean contains(Point p) {
 602         if (source instanceof Component) {
 603             return ((Component) source).contains(p);
 604         } else {
 605             return false;
 606         }
 607     }
 608 
 609     /**
 610      * Returns the location of the object on the screen.
 611      *
 612      * @return location of object on screen; can be null if this object
 613      *     is not on the screen
 614      */
 615     public Point getLocationOnScreen() {
 616         if (source instanceof Component) {
 617             return ((Component) source).getLocationOnScreen();
 618         } else {
 619             return null;
 620         }
 621     }
 622 
 623     /**
 624      * Returns the location of the object relative to parent.
 625      *
 626      * @return location of object relative to parent; can be null if
 627      *     this object or its parent are not on the screen
 628      */
 629     public Point getLocation() {
 630         if (source instanceof Component) {
 631             return ((Component) source).getLocation();
 632         } else {
 633             return null;
 634         }
 635     }
 636 
 637     /**
 638      * Sets the location of the object relative to parent.
 639      */
 640     public void setLocation(Point p) {
 641         if (source instanceof Component) {
 642             ((Component) source).setLocation(p);
 643         }
 644     }
 645 
 646     /**
 647      * Returns the current bounds of this object.
 648      *
 649      * @return current bounds of object; can be null if this object
 650      *     is not on the screen
 651      */
 652     public Rectangle getBounds() {
 653         if (source instanceof Component) {
 654             return ((Component) source).getBounds();
 655         } else {
 656             return null;
 657         }
 658     }
 659 
 660     /**
 661      * Sets the current bounds of this object.
 662      */
 663     public void setBounds(Rectangle r) {
 664         if (source instanceof Component) {
 665             ((Component) source).setBounds(r);
 666         }
 667     }
 668 
 669     /**
 670      * Returns the current size of this object.
 671      *
 672      * @return current size of object; can be null if this object is
 673      *     not on the screen
 674      */
 675     public Dimension getSize() {
 676         if (source instanceof Component) {
 677             return ((Component) source).getSize();
 678         } else {
 679             return null;
 680         }
 681     }
 682 
 683     /**
 684      * Sets the current size of this object.
 685      */
 686     public void setSize(Dimension d) {
 687         if (source instanceof Component) {
 688             ((Component) source).setSize(d);
 689         }
 690     }
 691 
 692     /**
 693      * Returns the accessible child contained at the local coordinate
 694      * Point, if one exists.
 695      *
 696      * @return the Accessible at the specified location, if it exists
 697      */
 698     public Accessible getAccessibleAt(Point p) {
 699         if (source instanceof Component) {
 700             Component c = ((Component) source).getComponentAt(p);
 701             if (c != null) {
 702                 return (getAccessible(c));
 703             }
 704         }
 705         return null;
 706     }
 707 
 708     /**
 709      * Returns whether this object can accept focus or not.
 710      *
 711      * @return true if object can accept focus; otherwise false
 712      */
 713     @SuppressWarnings("deprecation")
 714     public boolean isFocusTraversable() {
 715         if (source instanceof Component) {
 716             return ((Component) source).isFocusTraversable();
 717         } else {
 718             return false;
 719         }
 720     }
 721 
 722     /**
 723      * Requests focus for this object.
 724      */
 725     public void requestFocus() {
 726         if (source instanceof Component) {
 727             ((Component) source).requestFocus();
 728         }
 729     }
 730 
 731     /**
 732      * Adds the specified {@code FocusListener} to receive focus events from
 733      * this component.
 734      *
 735      * @param l the focus listener
 736      */
 737     public synchronized void addFocusListener(FocusListener l) {
 738         if (source instanceof Component) {
 739             ((Component) source).addFocusListener(l);
 740         }
 741     }
 742 
 743     /**
 744      * Removes the specified focus listener so it no longer receives focus
 745      * events from this component.
 746      *
 747      * @param l the focus listener; this method performs no function, nor does it
 748      *     throw an exception if the listener specified was not previously added
 749      *     to this component; if listener is null, no exception is thrown and no
 750      *     action is performed.
 751      */
 752     public synchronized void removeFocusListener(FocusListener l) {
 753         if (source instanceof Component) {
 754             ((Component) source).removeFocusListener(l);
 755         }
 756     }
 757 }