1 /* 2 * Copyright (c) 1997, 2014, 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 28 package javax.swing; 29 30 31 32 import java.io.*; 33 import java.awt.BorderLayout; 34 import java.awt.Frame; 35 import java.awt.Dialog; 36 import java.awt.Window; 37 import java.awt.Component; 38 import java.awt.Container; 39 import java.beans.PropertyChangeEvent; 40 import java.beans.PropertyChangeListener; 41 import java.awt.event.WindowListener; 42 import java.awt.event.WindowAdapter; 43 import java.awt.event.WindowEvent; 44 45 import java.awt.IllegalComponentStateException; 46 import java.awt.Point; 47 import java.awt.Rectangle; 48 import java.text.*; 49 import java.util.Locale; 50 import javax.accessibility.*; 51 import javax.swing.event.*; 52 import javax.swing.text.*; 53 54 55 /** A class to monitor the progress of some operation. If it looks 56 * like the operation will take a while, a progress dialog will be popped up. 57 * When the ProgressMonitor is created it is given a numeric range and a 58 * descriptive string. As the operation progresses, call the setProgress method 59 * to indicate how far along the [min,max] range the operation is. 60 * Initially, there is no ProgressDialog. After the first millisToDecideToPopup 61 * milliseconds (default 500) the progress monitor will predict how long 62 * the operation will take. If it is longer than millisToPopup (default 2000, 63 * 2 seconds) a ProgressDialog will be popped up. 64 * <p> 65 * From time to time, when the Dialog box is visible, the progress bar will 66 * be updated when setProgress is called. setProgress won't always update 67 * the progress bar, it will only be done if the amount of progress is 68 * visibly significant. 69 * 70 * <p> 71 * 72 * For further documentation and examples see 73 * <a 74 href="http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html">How to Monitor Progress</a>, 75 * a section in <em>The Java Tutorial.</em> 76 * 77 * @see ProgressMonitorInputStream 78 * @author James Gosling 79 * @author Lynn Monsanto (accessibility) 80 * @since 1.2 81 */ 82 public class ProgressMonitor implements Accessible 83 { 84 private ProgressMonitor root; 85 private JDialog dialog; 86 private JOptionPane pane; 87 private JProgressBar myBar; 88 private JLabel noteLabel; 89 private Component parentComponent; 90 private String note; 91 private Object[] cancelOption = null; 92 private Object message; 93 private long T0; 94 private int millisToDecideToPopup = 500; 95 private int millisToPopup = 2000; 96 private int min; 97 private int max; 98 99 100 /** 101 * Constructs a graphic object that shows progress, typically by filling 102 * in a rectangular bar as the process nears completion. 103 * 104 * @param parentComponent the parent component for the dialog box 105 * @param message a descriptive message that will be shown 106 * to the user to indicate what operation is being monitored. 107 * This does not change as the operation progresses. 108 * See the message parameters to methods in 109 * {@link JOptionPane#message} 110 * for the range of values. 111 * @param note a short note describing the state of the 112 * operation. As the operation progresses, you can call 113 * setNote to change the note displayed. This is used, 114 * for example, in operations that iterate through a 115 * list of files to show the name of the file being processes. 116 * If note is initially null, there will be no note line 117 * in the dialog box and setNote will be ineffective 118 * @param min the lower bound of the range 119 * @param max the upper bound of the range 120 * @see JDialog 121 * @see JOptionPane 122 */ 123 public ProgressMonitor(Component parentComponent, 124 Object message, 125 String note, 126 int min, 127 int max) { 128 this(parentComponent, message, note, min, max, null); 129 } 130 131 132 private ProgressMonitor(Component parentComponent, 133 Object message, 134 String note, 135 int min, 136 int max, 137 ProgressMonitor group) { 138 this.min = min; 139 this.max = max; 140 this.parentComponent = parentComponent; 141 142 cancelOption = new Object[1]; 143 cancelOption[0] = UIManager.getString("OptionPane.cancelButtonText"); 144 145 this.message = message; 146 this.note = note; 147 if (group != null) { 148 root = (group.root != null) ? group.root : group; 149 T0 = root.T0; 150 dialog = root.dialog; 151 } 152 else { 153 T0 = System.currentTimeMillis(); 154 } 155 } 156 157 @SuppressWarnings("serial") // Superclass is not serializable across versions 158 private class ProgressOptionPane extends JOptionPane 159 { 160 ProgressOptionPane(Object messageList) { 161 super(messageList, 162 JOptionPane.INFORMATION_MESSAGE, 163 JOptionPane.DEFAULT_OPTION, 164 null, 165 ProgressMonitor.this.cancelOption, 166 null); 167 } 168 169 170 public int getMaxCharactersPerLineCount() { 171 return 60; 172 } 173 174 175 // Equivalent to JOptionPane.createDialog, 176 // but create a modeless dialog. 177 // This is necessary because the Solaris implementation doesn't 178 // support Dialog.setModal yet. 179 public JDialog createDialog(Component parentComponent, String title) { 180 final JDialog dialog; 181 182 Window window = JOptionPane.getWindowForComponent(parentComponent); 183 if (window instanceof Frame) { 184 dialog = new JDialog((Frame)window, title, false); 185 } else { 186 dialog = new JDialog((Dialog)window, title, false); 187 } 188 if (window instanceof SwingUtilities.SharedOwnerFrame) { 189 WindowListener ownerShutdownListener = 190 SwingUtilities.getSharedOwnerFrameShutdownListener(); 191 dialog.addWindowListener(ownerShutdownListener); 192 } 193 Container contentPane = dialog.getContentPane(); 194 195 contentPane.setLayout(new BorderLayout()); 196 contentPane.add(this, BorderLayout.CENTER); 197 dialog.pack(); 198 dialog.setLocationRelativeTo(parentComponent); 199 dialog.addWindowListener(new WindowAdapter() { 200 boolean gotFocus = false; 201 202 public void windowClosing(WindowEvent we) { 203 setValue(cancelOption[0]); 204 } 205 206 public void windowActivated(WindowEvent we) { 207 // Once window gets focus, set initial focus 208 if (!gotFocus) { 209 selectInitialValue(); 210 gotFocus = true; 211 } 212 } 213 }); 214 215 addPropertyChangeListener(new PropertyChangeListener() { 216 public void propertyChange(PropertyChangeEvent event) { 217 if(dialog.isVisible() && 218 event.getSource() == ProgressOptionPane.this && 219 (event.getPropertyName().equals(VALUE_PROPERTY) || 220 event.getPropertyName().equals(INPUT_VALUE_PROPERTY))){ 221 dialog.setVisible(false); 222 dialog.dispose(); 223 } 224 } 225 }); 226 227 return dialog; 228 } 229 230 ///////////////// 231 // Accessibility support for ProgressOptionPane 232 //////////////// 233 234 /** 235 * Gets the AccessibleContext for the ProgressOptionPane 236 * 237 * @return the AccessibleContext for the ProgressOptionPane 238 * @since 1.5 239 */ 240 public AccessibleContext getAccessibleContext() { 241 return ProgressMonitor.this.getAccessibleContext(); 242 } 243 244 /* 245 * Returns the AccessibleJOptionPane 246 */ 247 private AccessibleContext getAccessibleJOptionPane() { 248 return super.getAccessibleContext(); 249 } 250 } 251 252 253 /** 254 * Indicate the progress of the operation being monitored. 255 * If the specified value is >= the maximum, the progress 256 * monitor is closed. 257 * @param nv an int specifying the current value, between the 258 * maximum and minimum specified for this component 259 * @see #setMinimum 260 * @see #setMaximum 261 * @see #close 262 */ 263 @SuppressWarnings("deprecation") 264 public void setProgress(int nv) { 265 if (nv >= max) { 266 close(); 267 } 268 else { 269 if (myBar != null) { 270 myBar.setValue(nv); 271 } 272 else { 273 long T = System.currentTimeMillis(); 274 long dT = (int)(T-T0); 275 if (dT >= millisToDecideToPopup) { 276 int predictedCompletionTime; 277 if (nv > min) { 278 predictedCompletionTime = (int)(dT * 279 (max - min) / 280 (nv - min)); 281 } 282 else { 283 predictedCompletionTime = millisToPopup; 284 } 285 if (predictedCompletionTime >= millisToPopup) { 286 myBar = new JProgressBar(); 287 myBar.setMinimum(min); 288 myBar.setMaximum(max); 289 myBar.setValue(nv); 290 if (note != null) noteLabel = new JLabel(note); 291 pane = new ProgressOptionPane(new Object[] {message, 292 noteLabel, 293 myBar}); 294 dialog = pane.createDialog(parentComponent, 295 UIManager.getString( 296 "ProgressMonitor.progressText")); 297 dialog.show(); 298 } 299 } 300 } 301 } 302 } 303 304 305 /** 306 * Indicate that the operation is complete. This happens automatically 307 * when the value set by setProgress is >= max, but it may be called 308 * earlier if the operation ends early. 309 */ 310 public void close() { 311 if (dialog != null) { 312 dialog.setVisible(false); 313 dialog.dispose(); 314 dialog = null; 315 pane = null; 316 myBar = null; 317 } 318 } 319 320 321 /** 322 * Returns the minimum value -- the lower end of the progress value. 323 * 324 * @return an int representing the minimum value 325 * @see #setMinimum 326 */ 327 public int getMinimum() { 328 return min; 329 } 330 331 332 /** 333 * Specifies the minimum value. 334 * 335 * @param m an int specifying the minimum value 336 * @see #getMinimum 337 */ 338 public void setMinimum(int m) { 339 if (myBar != null) { 340 myBar.setMinimum(m); 341 } 342 min = m; 343 } 344 345 346 /** 347 * Returns the maximum value -- the higher end of the progress value. 348 * 349 * @return an int representing the maximum value 350 * @see #setMaximum 351 */ 352 public int getMaximum() { 353 return max; 354 } 355 356 357 /** 358 * Specifies the maximum value. 359 * 360 * @param m an int specifying the maximum value 361 * @see #getMaximum 362 */ 363 public void setMaximum(int m) { 364 if (myBar != null) { 365 myBar.setMaximum(m); 366 } 367 max = m; 368 } 369 370 371 /** 372 * Returns true if the user hits the Cancel button in the progress dialog. 373 * 374 * @return true if the user hits the Cancel button in the progress dialog 375 */ 376 public boolean isCanceled() { 377 if (pane == null) return false; 378 Object v = pane.getValue(); 379 return ((v != null) && 380 (cancelOption.length == 1) && 381 (v.equals(cancelOption[0]))); 382 } 383 384 385 /** 386 * Specifies the amount of time to wait before deciding whether or 387 * not to popup a progress monitor. 388 * 389 * @param millisToDecideToPopup an int specifying the time to wait, 390 * in milliseconds 391 * @see #getMillisToDecideToPopup 392 */ 393 public void setMillisToDecideToPopup(int millisToDecideToPopup) { 394 this.millisToDecideToPopup = millisToDecideToPopup; 395 } 396 397 398 /** 399 * Returns the amount of time this object waits before deciding whether 400 * or not to popup a progress monitor. 401 * 402 * @return the amount of time in milliseconds this object waits before 403 * deciding whether or not to popup a progress monitor 404 * @see #setMillisToDecideToPopup 405 */ 406 public int getMillisToDecideToPopup() { 407 return millisToDecideToPopup; 408 } 409 410 411 /** 412 * Specifies the amount of time it will take for the popup to appear. 413 * (If the predicted time remaining is less than this time, the popup 414 * won't be displayed.) 415 * 416 * @param millisToPopup an int specifying the time in milliseconds 417 * @see #getMillisToPopup 418 */ 419 public void setMillisToPopup(int millisToPopup) { 420 this.millisToPopup = millisToPopup; 421 } 422 423 424 /** 425 * Returns the amount of time it will take for the popup to appear. 426 * 427 * @return the amont of time in milliseconds it will take for the 428 * popup to appear 429 * @see #setMillisToPopup 430 */ 431 public int getMillisToPopup() { 432 return millisToPopup; 433 } 434 435 436 /** 437 * Specifies the additional note that is displayed along with the 438 * progress message. Used, for example, to show which file the 439 * is currently being copied during a multiple-file copy. 440 * 441 * @param note a String specifying the note to display 442 * @see #getNote 443 */ 444 public void setNote(String note) { 445 this.note = note; 446 if (noteLabel != null) { 447 noteLabel.setText(note); 448 } 449 } 450 451 452 /** 453 * Specifies the additional note that is displayed along with the 454 * progress message. 455 * 456 * @return a String specifying the note to display 457 * @see #setNote 458 */ 459 public String getNote() { 460 return note; 461 } 462 463 ///////////////// 464 // Accessibility support 465 //////////////// 466 467 /** 468 * The <code>AccessibleContext</code> for the <code>ProgressMonitor</code> 469 * @since 1.5 470 */ 471 protected AccessibleContext accessibleContext = null; 472 473 private AccessibleContext accessibleJOptionPane = null; 474 475 /** 476 * Gets the <code>AccessibleContext</code> for the 477 * <code>ProgressMonitor</code> 478 * 479 * @return the <code>AccessibleContext</code> for the 480 * <code>ProgressMonitor</code> 481 * @since 1.5 482 */ 483 public AccessibleContext getAccessibleContext() { 484 if (accessibleContext == null) { 485 accessibleContext = new AccessibleProgressMonitor(); 486 } 487 if (pane != null && accessibleJOptionPane == null) { 488 // Notify the AccessibleProgressMonitor that the 489 // ProgressOptionPane was created. It is necessary 490 // to poll for ProgressOptionPane creation because 491 // the ProgressMonitor does not have a Component 492 // to add a listener to until the ProgressOptionPane 493 // is created. 494 if (accessibleContext instanceof AccessibleProgressMonitor) { 495 ((AccessibleProgressMonitor)accessibleContext).optionPaneCreated(); 496 } 497 } 498 return accessibleContext; 499 } 500 501 /** 502 * <code>AccessibleProgressMonitor</code> implements accessibility 503 * support for the <code>ProgressMonitor</code> class. 504 * @since 1.5 505 */ 506 protected class AccessibleProgressMonitor extends AccessibleContext 507 implements AccessibleText, ChangeListener, PropertyChangeListener { 508 509 /* 510 * The accessibility hierarchy for ProgressMonitor is a flattened 511 * version of the ProgressOptionPane component hierarchy. 512 * 513 * The ProgressOptionPane component hierarchy is: 514 * JDialog 515 * ProgressOptionPane 516 * JPanel 517 * JPanel 518 * JLabel 519 * JLabel 520 * JProgressBar 521 * 522 * The AccessibleProgessMonitor accessibility hierarchy is: 523 * AccessibleJDialog 524 * AccessibleProgressMonitor 525 * AccessibleJLabel 526 * AccessibleJLabel 527 * AccessibleJProgressBar 528 * 529 * The abstraction presented to assitive technologies by 530 * the AccessibleProgressMonitor is that a dialog contains a 531 * progress monitor with three children: a message, a note 532 * label and a progress bar. 533 */ 534 535 private Object oldModelValue; 536 537 /** 538 * AccessibleProgressMonitor constructor 539 */ 540 protected AccessibleProgressMonitor() { 541 } 542 543 /* 544 * Initializes the AccessibleContext now that the ProgressOptionPane 545 * has been created. Because the ProgressMonitor is not a Component 546 * implementing the Accessible interface, an AccessibleContext 547 * must be synthesized from the ProgressOptionPane and its children. 548 * 549 * For other AWT and Swing classes, the inner class that implements 550 * accessibility for the class extends the inner class that implements 551 * implements accessibility for the super class. AccessibleProgressMonitor 552 * cannot extend AccessibleJOptionPane and must therefore delegate calls 553 * to the AccessibleJOptionPane. 554 */ 555 private void optionPaneCreated() { 556 accessibleJOptionPane = 557 ((ProgressOptionPane)pane).getAccessibleJOptionPane(); 558 559 // add a listener for progress bar ChangeEvents 560 if (myBar != null) { 561 myBar.addChangeListener(this); 562 } 563 564 // add a listener for note label PropertyChangeEvents 565 if (noteLabel != null) { 566 noteLabel.addPropertyChangeListener(this); 567 } 568 } 569 570 /** 571 * Invoked when the target of the listener has changed its state. 572 * 573 * @param e a <code>ChangeEvent</code> object. Must not be null. 574 * @throws NullPointerException if the parameter is null. 575 */ 576 public void stateChanged(ChangeEvent e) { 577 if (e == null) { 578 return; 579 } 580 if (myBar != null) { 581 // the progress bar value changed 582 Object newModelValue = myBar.getValue(); 583 firePropertyChange(ACCESSIBLE_VALUE_PROPERTY, 584 oldModelValue, 585 newModelValue); 586 oldModelValue = newModelValue; 587 } 588 } 589 590 /** 591 * This method gets called when a bound property is changed. 592 * 593 * @param e A <code>PropertyChangeEvent</code> object describing 594 * the event source and the property that has changed. Must not be null. 595 * @throws NullPointerException if the parameter is null. 596 */ 597 public void propertyChange(PropertyChangeEvent e) { 598 if (e.getSource() == noteLabel && e.getPropertyName() == "text") { 599 // the note label text changed 600 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, 0); 601 } 602 } 603 604 /* ===== Begin AccessileContext ===== */ 605 606 /** 607 * Gets the accessibleName property of this object. The accessibleName 608 * property of an object is a localized String that designates the purpose 609 * of the object. For example, the accessibleName property of a label 610 * or button might be the text of the label or button itself. In the 611 * case of an object that doesn't display its name, the accessibleName 612 * should still be set. For example, in the case of a text field used 613 * to enter the name of a city, the accessibleName for the en_US locale 614 * could be 'city.' 615 * 616 * @return the localized name of the object; null if this 617 * object does not have a name 618 * 619 * @see #setAccessibleName 620 */ 621 public String getAccessibleName() { 622 if (accessibleName != null) { // defined in AccessibleContext 623 return accessibleName; 624 } else if (accessibleJOptionPane != null) { 625 // delegate to the AccessibleJOptionPane 626 return accessibleJOptionPane.getAccessibleName(); 627 } 628 return null; 629 } 630 631 /** 632 * Gets the accessibleDescription property of this object. The 633 * accessibleDescription property of this object is a short localized 634 * phrase describing the purpose of the object. For example, in the 635 * case of a 'Cancel' button, the accessibleDescription could be 636 * 'Ignore changes and close dialog box.' 637 * 638 * @return the localized description of the object; null if 639 * this object does not have a description 640 * 641 * @see #setAccessibleDescription 642 */ 643 public String getAccessibleDescription() { 644 if (accessibleDescription != null) { // defined in AccessibleContext 645 return accessibleDescription; 646 } else if (accessibleJOptionPane != null) { 647 // delegate to the AccessibleJOptionPane 648 return accessibleJOptionPane.getAccessibleDescription(); 649 } 650 return null; 651 } 652 653 /** 654 * Gets the role of this object. The role of the object is the generic 655 * purpose or use of the class of this object. For example, the role 656 * of a push button is AccessibleRole.PUSH_BUTTON. The roles in 657 * AccessibleRole are provided so component developers can pick from 658 * a set of predefined roles. This enables assistive technologies to 659 * provide a consistent interface to various tweaked subclasses of 660 * components (e.g., use AccessibleRole.PUSH_BUTTON for all components 661 * that act like a push button) as well as distinguish between subclasses 662 * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes 663 * and AccessibleRole.RADIO_BUTTON for radio buttons). 664 * <p>Note that the AccessibleRole class is also extensible, so 665 * custom component developers can define their own AccessibleRole's 666 * if the set of predefined roles is inadequate. 667 * 668 * @return an instance of AccessibleRole describing the role of the object 669 * @see AccessibleRole 670 */ 671 public AccessibleRole getAccessibleRole() { 672 return AccessibleRole.PROGRESS_MONITOR; 673 } 674 675 /** 676 * Gets the state set of this object. The AccessibleStateSet of an object 677 * is composed of a set of unique AccessibleStates. A change in the 678 * AccessibleStateSet of an object will cause a PropertyChangeEvent to 679 * be fired for the ACCESSIBLE_STATE_PROPERTY property. 680 * 681 * @return an instance of AccessibleStateSet containing the 682 * current state set of the object 683 * @see AccessibleStateSet 684 * @see AccessibleState 685 * @see #addPropertyChangeListener 686 */ 687 public AccessibleStateSet getAccessibleStateSet() { 688 if (accessibleJOptionPane != null) { 689 // delegate to the AccessibleJOptionPane 690 return accessibleJOptionPane.getAccessibleStateSet(); 691 } 692 return null; 693 } 694 695 /** 696 * Gets the Accessible parent of this object. 697 * 698 * @return the Accessible parent of this object; null if this 699 * object does not have an Accessible parent 700 */ 701 public Accessible getAccessibleParent() { 702 return dialog; 703 } 704 705 /* 706 * Returns the parent AccessibleContext 707 */ 708 private AccessibleContext getParentAccessibleContext() { 709 if (dialog != null) { 710 return dialog.getAccessibleContext(); 711 } 712 return null; 713 } 714 715 /** 716 * Gets the 0-based index of this object in its accessible parent. 717 * 718 * @return the 0-based index of this object in its parent; -1 if this 719 * object does not have an accessible parent. 720 * 721 * @see #getAccessibleParent 722 * @see #getAccessibleChildrenCount 723 * @see #getAccessibleChild 724 */ 725 public int getAccessibleIndexInParent() { 726 if (accessibleJOptionPane != null) { 727 // delegate to the AccessibleJOptionPane 728 return accessibleJOptionPane.getAccessibleIndexInParent(); 729 } 730 return -1; 731 } 732 733 /** 734 * Returns the number of accessible children of the object. 735 * 736 * @return the number of accessible children of the object. 737 */ 738 public int getAccessibleChildrenCount() { 739 // return the number of children in the JPanel containing 740 // the message, note label and progress bar 741 AccessibleContext ac = getPanelAccessibleContext(); 742 if (ac != null) { 743 return ac.getAccessibleChildrenCount(); 744 } 745 return 0; 746 } 747 748 /** 749 * Returns the specified Accessible child of the object. The Accessible 750 * children of an Accessible object are zero-based, so the first child 751 * of an Accessible child is at index 0, the second child is at index 1, 752 * and so on. 753 * 754 * @param i zero-based index of child 755 * @return the Accessible child of the object 756 * @see #getAccessibleChildrenCount 757 */ 758 public Accessible getAccessibleChild(int i) { 759 // return a child in the JPanel containing the message, note label 760 // and progress bar 761 AccessibleContext ac = getPanelAccessibleContext(); 762 if (ac != null) { 763 return ac.getAccessibleChild(i); 764 } 765 return null; 766 } 767 768 /* 769 * Returns the AccessibleContext for the JPanel containing the 770 * message, note label and progress bar 771 */ 772 private AccessibleContext getPanelAccessibleContext() { 773 if (myBar != null) { 774 Component c = myBar.getParent(); 775 if (c instanceof Accessible) { 776 return c.getAccessibleContext(); 777 } 778 } 779 return null; 780 } 781 782 /** 783 * Gets the locale of the component. If the component does not have a 784 * locale, then the locale of its parent is returned. 785 * 786 * @return this component's locale. If this component does not have 787 * a locale, the locale of its parent is returned. 788 * 789 * @exception IllegalComponentStateException 790 * If the Component does not have its own locale and has not yet been 791 * added to a containment hierarchy such that the locale can be 792 * determined from the containing parent. 793 */ 794 public Locale getLocale() throws IllegalComponentStateException { 795 if (accessibleJOptionPane != null) { 796 // delegate to the AccessibleJOptionPane 797 return accessibleJOptionPane.getLocale(); 798 } 799 return null; 800 } 801 802 /* ===== end AccessibleContext ===== */ 803 804 /** 805 * Gets the AccessibleComponent associated with this object that has a 806 * graphical representation. 807 * 808 * @return AccessibleComponent if supported by object; else return null 809 * @see AccessibleComponent 810 */ 811 public AccessibleComponent getAccessibleComponent() { 812 if (accessibleJOptionPane != null) { 813 // delegate to the AccessibleJOptionPane 814 return accessibleJOptionPane.getAccessibleComponent(); 815 } 816 return null; 817 } 818 819 /** 820 * Gets the AccessibleValue associated with this object that supports a 821 * Numerical value. 822 * 823 * @return AccessibleValue if supported by object; else return null 824 * @see AccessibleValue 825 */ 826 public AccessibleValue getAccessibleValue() { 827 if (myBar != null) { 828 // delegate to the AccessibleJProgressBar 829 return myBar.getAccessibleContext().getAccessibleValue(); 830 } 831 return null; 832 } 833 834 /** 835 * Gets the AccessibleText associated with this object presenting 836 * text on the display. 837 * 838 * @return AccessibleText if supported by object; else return null 839 * @see AccessibleText 840 */ 841 public AccessibleText getAccessibleText() { 842 if (getNoteLabelAccessibleText() != null) { 843 return this; 844 } 845 return null; 846 } 847 848 /* 849 * Returns the note label AccessibleText 850 */ 851 private AccessibleText getNoteLabelAccessibleText() { 852 if (noteLabel != null) { 853 // AccessibleJLabel implements AccessibleText if the 854 // JLabel contains HTML text 855 return noteLabel.getAccessibleContext().getAccessibleText(); 856 } 857 return null; 858 } 859 860 /* ===== Begin AccessibleText impl ===== */ 861 862 /** 863 * Given a point in local coordinates, return the zero-based index 864 * of the character under that Point. If the point is invalid, 865 * this method returns -1. 866 * 867 * @param p the Point in local coordinates 868 * @return the zero-based index of the character under Point p; if 869 * Point is invalid return -1. 870 */ 871 public int getIndexAtPoint(Point p) { 872 AccessibleText at = getNoteLabelAccessibleText(); 873 if (at != null && sameWindowAncestor(pane, noteLabel)) { 874 // convert point from the option pane bounds 875 // to the note label bounds. 876 Point noteLabelPoint = SwingUtilities.convertPoint(pane, 877 p, 878 noteLabel); 879 if (noteLabelPoint != null) { 880 return at.getIndexAtPoint(noteLabelPoint); 881 } 882 } 883 return -1; 884 } 885 886 /** 887 * Determines the bounding box of the character at the given 888 * index into the string. The bounds are returned in local 889 * coordinates. If the index is invalid an empty rectangle is returned. 890 * 891 * @param i the index into the String 892 * @return the screen coordinates of the character's bounding box, 893 * if index is invalid return an empty rectangle. 894 */ 895 public Rectangle getCharacterBounds(int i) { 896 AccessibleText at = getNoteLabelAccessibleText(); 897 if (at != null && sameWindowAncestor(pane, noteLabel)) { 898 // return rectangle in the option pane bounds 899 Rectangle noteLabelRect = at.getCharacterBounds(i); 900 if (noteLabelRect != null) { 901 return SwingUtilities.convertRectangle(noteLabel, 902 noteLabelRect, 903 pane); 904 } 905 } 906 return null; 907 } 908 909 /* 910 * Returns whether source and destination components have the 911 * same window ancestor 912 */ 913 private boolean sameWindowAncestor(Component src, Component dest) { 914 if (src == null || dest == null) { 915 return false; 916 } 917 return SwingUtilities.getWindowAncestor(src) == 918 SwingUtilities.getWindowAncestor(dest); 919 } 920 921 /** 922 * Returns the number of characters (valid indicies) 923 * 924 * @return the number of characters 925 */ 926 public int getCharCount() { 927 AccessibleText at = getNoteLabelAccessibleText(); 928 if (at != null) { // JLabel contains HTML text 929 return at.getCharCount(); 930 } 931 return -1; 932 } 933 934 /** 935 * Returns the zero-based offset of the caret. 936 * 937 * Note: That to the right of the caret will have the same index 938 * value as the offset (the caret is between two characters). 939 * @return the zero-based offset of the caret. 940 */ 941 public int getCaretPosition() { 942 AccessibleText at = getNoteLabelAccessibleText(); 943 if (at != null) { // JLabel contains HTML text 944 return at.getCaretPosition(); 945 } 946 return -1; 947 } 948 949 /** 950 * Returns the String at a given index. 951 * 952 * @param part the CHARACTER, WORD, or SENTENCE to retrieve 953 * @param index an index within the text 954 * @return the letter, word, or sentence 955 */ 956 public String getAtIndex(int part, int index) { 957 AccessibleText at = getNoteLabelAccessibleText(); 958 if (at != null) { // JLabel contains HTML text 959 return at.getAtIndex(part, index); 960 } 961 return null; 962 } 963 964 /** 965 * Returns the String after a given index. 966 * 967 * @param part the CHARACTER, WORD, or SENTENCE to retrieve 968 * @param index an index within the text 969 * @return the letter, word, or sentence 970 */ 971 public String getAfterIndex(int part, int index) { 972 AccessibleText at = getNoteLabelAccessibleText(); 973 if (at != null) { // JLabel contains HTML text 974 return at.getAfterIndex(part, index); 975 } 976 return null; 977 } 978 979 /** 980 * Returns the String before a given index. 981 * 982 * @param part the CHARACTER, WORD, or SENTENCE to retrieve 983 * @param index an index within the text 984 * @return the letter, word, or sentence 985 */ 986 public String getBeforeIndex(int part, int index) { 987 AccessibleText at = getNoteLabelAccessibleText(); 988 if (at != null) { // JLabel contains HTML text 989 return at.getBeforeIndex(part, index); 990 } 991 return null; 992 } 993 994 /** 995 * Returns the AttributeSet for a given character at a given index 996 * 997 * @param i the zero-based index into the text 998 * @return the AttributeSet of the character 999 */ 1000 public AttributeSet getCharacterAttribute(int i) { 1001 AccessibleText at = getNoteLabelAccessibleText(); 1002 if (at != null) { // JLabel contains HTML text 1003 return at.getCharacterAttribute(i); 1004 } 1005 return null; 1006 } 1007 1008 /** 1009 * Returns the start offset within the selected text. 1010 * If there is no selection, but there is 1011 * a caret, the start and end offsets will be the same. 1012 * 1013 * @return the index into the text of the start of the selection 1014 */ 1015 public int getSelectionStart() { 1016 AccessibleText at = getNoteLabelAccessibleText(); 1017 if (at != null) { // JLabel contains HTML text 1018 return at.getSelectionStart(); 1019 } 1020 return -1; 1021 } 1022 1023 /** 1024 * Returns the end offset within the selected text. 1025 * If there is no selection, but there is 1026 * a caret, the start and end offsets will be the same. 1027 * 1028 * @return the index into the text of the end of the selection 1029 */ 1030 public int getSelectionEnd() { 1031 AccessibleText at = getNoteLabelAccessibleText(); 1032 if (at != null) { // JLabel contains HTML text 1033 return at.getSelectionEnd(); 1034 } 1035 return -1; 1036 } 1037 1038 /** 1039 * Returns the portion of the text that is selected. 1040 * 1041 * @return the String portion of the text that is selected 1042 */ 1043 public String getSelectedText() { 1044 AccessibleText at = getNoteLabelAccessibleText(); 1045 if (at != null) { // JLabel contains HTML text 1046 return at.getSelectedText(); 1047 } 1048 return null; 1049 } 1050 /* ===== End AccessibleText impl ===== */ 1051 } 1052 // inner class AccessibleProgressMonitor 1053 1054 }