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