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