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 }