1 /* 2 * Copyright (c) 1997, 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 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="https://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 */ ProgressMonitor(Component parentComponent, Object message, String note, int min, int max)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 ProgressMonitor(Component parentComponent, Object message, String note, int min, int max, ProgressMonitor group)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 { ProgressOptionPane(Object messageList)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 getMaxCharactersPerLineCount()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. createDialog(Component parentComponent, String title)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 */ getAccessibleContext()240 public AccessibleContext getAccessibleContext() { 241 return ProgressMonitor.this.getAccessibleContext(); 242 } 243 244 /* 245 * Returns the AccessibleJOptionPane 246 */ getAccessibleJOptionPane()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") setProgress(int nv)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 */ close()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 */ getMinimum()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 */ setMinimum(int m)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 */ getMaximum()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 */ setMaximum(int m)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 or closes 373 * the progress dialog. 374 * 375 * @return true if the user hits the Cancel button or closes 376 * the progress dialog 377 */ isCanceled()378 public boolean isCanceled() { 379 if (pane == null) { 380 return false; 381 } 382 383 Object v = pane.getValue(); 384 if (v == null) { 385 return false; 386 } 387 388 return (((cancelOption.length == 1) && v.equals(cancelOption[0])) || 389 v.equals(Integer.valueOf(JOptionPane.CLOSED_OPTION))); 390 } 391 392 393 /** 394 * Specifies the amount of time to wait before deciding whether or 395 * not to popup a progress monitor. 396 * 397 * @param millisToDecideToPopup an int specifying the time to wait, 398 * in milliseconds 399 * @see #getMillisToDecideToPopup 400 */ setMillisToDecideToPopup(int millisToDecideToPopup)401 public void setMillisToDecideToPopup(int millisToDecideToPopup) { 402 this.millisToDecideToPopup = millisToDecideToPopup; 403 } 404 405 406 /** 407 * Returns the amount of time this object waits before deciding whether 408 * or not to popup a progress monitor. 409 * 410 * @return the amount of time in milliseconds this object waits before 411 * deciding whether or not to popup a progress monitor 412 * @see #setMillisToDecideToPopup 413 */ getMillisToDecideToPopup()414 public int getMillisToDecideToPopup() { 415 return millisToDecideToPopup; 416 } 417 418 419 /** 420 * Specifies the amount of time it will take for the popup to appear. 421 * (If the predicted time remaining is less than this time, the popup 422 * won't be displayed.) 423 * 424 * @param millisToPopup an int specifying the time in milliseconds 425 * @see #getMillisToPopup 426 */ setMillisToPopup(int millisToPopup)427 public void setMillisToPopup(int millisToPopup) { 428 this.millisToPopup = millisToPopup; 429 } 430 431 432 /** 433 * Returns the amount of time it will take for the popup to appear. 434 * 435 * @return the amont of time in milliseconds it will take for the 436 * popup to appear 437 * @see #setMillisToPopup 438 */ getMillisToPopup()439 public int getMillisToPopup() { 440 return millisToPopup; 441 } 442 443 444 /** 445 * Specifies the additional note that is displayed along with the 446 * progress message. Used, for example, to show which file the 447 * is currently being copied during a multiple-file copy. 448 * 449 * @param note a String specifying the note to display 450 * @see #getNote 451 */ setNote(String note)452 public void setNote(String note) { 453 this.note = note; 454 if (noteLabel != null) { 455 noteLabel.setText(note); 456 } 457 } 458 459 460 /** 461 * Specifies the additional note that is displayed along with the 462 * progress message. 463 * 464 * @return a String specifying the note to display 465 * @see #setNote 466 */ getNote()467 public String getNote() { 468 return note; 469 } 470 471 ///////////////// 472 // Accessibility support 473 //////////////// 474 475 /** 476 * The <code>AccessibleContext</code> for the <code>ProgressMonitor</code> 477 * @since 1.5 478 */ 479 protected AccessibleContext accessibleContext = null; 480 481 private AccessibleContext accessibleJOptionPane = null; 482 483 /** 484 * Gets the <code>AccessibleContext</code> for the 485 * <code>ProgressMonitor</code> 486 * 487 * @return the <code>AccessibleContext</code> for the 488 * <code>ProgressMonitor</code> 489 * @since 1.5 490 */ getAccessibleContext()491 public AccessibleContext getAccessibleContext() { 492 if (accessibleContext == null) { 493 accessibleContext = new AccessibleProgressMonitor(); 494 } 495 if (pane != null && accessibleJOptionPane == null) { 496 // Notify the AccessibleProgressMonitor that the 497 // ProgressOptionPane was created. It is necessary 498 // to poll for ProgressOptionPane creation because 499 // the ProgressMonitor does not have a Component 500 // to add a listener to until the ProgressOptionPane 501 // is created. 502 if (accessibleContext instanceof AccessibleProgressMonitor) { 503 ((AccessibleProgressMonitor)accessibleContext).optionPaneCreated(); 504 } 505 } 506 return accessibleContext; 507 } 508 509 /** 510 * <code>AccessibleProgressMonitor</code> implements accessibility 511 * support for the <code>ProgressMonitor</code> class. 512 * @since 1.5 513 */ 514 protected class AccessibleProgressMonitor extends AccessibleContext 515 implements AccessibleText, ChangeListener, PropertyChangeListener { 516 517 /* 518 * The accessibility hierarchy for ProgressMonitor is a flattened 519 * version of the ProgressOptionPane component hierarchy. 520 * 521 * The ProgressOptionPane component hierarchy is: 522 * JDialog 523 * ProgressOptionPane 524 * JPanel 525 * JPanel 526 * JLabel 527 * JLabel 528 * JProgressBar 529 * 530 * The AccessibleProgessMonitor accessibility hierarchy is: 531 * AccessibleJDialog 532 * AccessibleProgressMonitor 533 * AccessibleJLabel 534 * AccessibleJLabel 535 * AccessibleJProgressBar 536 * 537 * The abstraction presented to assitive technologies by 538 * the AccessibleProgressMonitor is that a dialog contains a 539 * progress monitor with three children: a message, a note 540 * label and a progress bar. 541 */ 542 543 private Object oldModelValue; 544 545 /** 546 * AccessibleProgressMonitor constructor 547 */ AccessibleProgressMonitor()548 protected AccessibleProgressMonitor() { 549 } 550 551 /* 552 * Initializes the AccessibleContext now that the ProgressOptionPane 553 * has been created. Because the ProgressMonitor is not a Component 554 * implementing the Accessible interface, an AccessibleContext 555 * must be synthesized from the ProgressOptionPane and its children. 556 * 557 * For other AWT and Swing classes, the inner class that implements 558 * accessibility for the class extends the inner class that implements 559 * implements accessibility for the super class. AccessibleProgressMonitor 560 * cannot extend AccessibleJOptionPane and must therefore delegate calls 561 * to the AccessibleJOptionPane. 562 */ optionPaneCreated()563 private void optionPaneCreated() { 564 accessibleJOptionPane = 565 ((ProgressOptionPane)pane).getAccessibleJOptionPane(); 566 567 // add a listener for progress bar ChangeEvents 568 if (myBar != null) { 569 myBar.addChangeListener(this); 570 } 571 572 // add a listener for note label PropertyChangeEvents 573 if (noteLabel != null) { 574 noteLabel.addPropertyChangeListener(this); 575 } 576 } 577 578 /** 579 * Invoked when the target of the listener has changed its state. 580 * 581 * @param e a <code>ChangeEvent</code> object. Must not be null. 582 * @throws NullPointerException if the parameter is null. 583 */ stateChanged(ChangeEvent e)584 public void stateChanged(ChangeEvent e) { 585 if (e == null) { 586 return; 587 } 588 if (myBar != null) { 589 // the progress bar value changed 590 Object newModelValue = myBar.getValue(); 591 firePropertyChange(ACCESSIBLE_VALUE_PROPERTY, 592 oldModelValue, 593 newModelValue); 594 oldModelValue = newModelValue; 595 } 596 } 597 598 /** 599 * This method gets called when a bound property is changed. 600 * 601 * @param e A <code>PropertyChangeEvent</code> object describing 602 * the event source and the property that has changed. Must not be null. 603 * @throws NullPointerException if the parameter is null. 604 */ propertyChange(PropertyChangeEvent e)605 public void propertyChange(PropertyChangeEvent e) { 606 if (e.getSource() == noteLabel && e.getPropertyName() == "text") { 607 // the note label text changed 608 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, 0); 609 } 610 } 611 612 /* ===== Begin AccessileContext ===== */ 613 614 /** 615 * Gets the accessibleName property of this object. The accessibleName 616 * property of an object is a localized String that designates the purpose 617 * of the object. For example, the accessibleName property of a label 618 * or button might be the text of the label or button itself. In the 619 * case of an object that doesn't display its name, the accessibleName 620 * should still be set. For example, in the case of a text field used 621 * to enter the name of a city, the accessibleName for the en_US locale 622 * could be 'city.' 623 * 624 * @return the localized name of the object; null if this 625 * object does not have a name 626 * 627 * @see #setAccessibleName 628 */ getAccessibleName()629 public String getAccessibleName() { 630 if (accessibleName != null) { // defined in AccessibleContext 631 return accessibleName; 632 } else if (accessibleJOptionPane != null) { 633 // delegate to the AccessibleJOptionPane 634 return accessibleJOptionPane.getAccessibleName(); 635 } 636 return null; 637 } 638 639 /** 640 * Gets the accessibleDescription property of this object. The 641 * accessibleDescription property of this object is a short localized 642 * phrase describing the purpose of the object. For example, in the 643 * case of a 'Cancel' button, the accessibleDescription could be 644 * 'Ignore changes and close dialog box.' 645 * 646 * @return the localized description of the object; null if 647 * this object does not have a description 648 * 649 * @see #setAccessibleDescription 650 */ getAccessibleDescription()651 public String getAccessibleDescription() { 652 if (accessibleDescription != null) { // defined in AccessibleContext 653 return accessibleDescription; 654 } else if (accessibleJOptionPane != null) { 655 // delegate to the AccessibleJOptionPane 656 return accessibleJOptionPane.getAccessibleDescription(); 657 } 658 return null; 659 } 660 661 /** 662 * Gets the role of this object. The role of the object is the generic 663 * purpose or use of the class of this object. For example, the role 664 * of a push button is AccessibleRole.PUSH_BUTTON. The roles in 665 * AccessibleRole are provided so component developers can pick from 666 * a set of predefined roles. This enables assistive technologies to 667 * provide a consistent interface to various tweaked subclasses of 668 * components (e.g., use AccessibleRole.PUSH_BUTTON for all components 669 * that act like a push button) as well as distinguish between subclasses 670 * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes 671 * and AccessibleRole.RADIO_BUTTON for radio buttons). 672 * <p>Note that the AccessibleRole class is also extensible, so 673 * custom component developers can define their own AccessibleRole's 674 * if the set of predefined roles is inadequate. 675 * 676 * @return an instance of AccessibleRole describing the role of the object 677 * @see AccessibleRole 678 */ getAccessibleRole()679 public AccessibleRole getAccessibleRole() { 680 return AccessibleRole.PROGRESS_MONITOR; 681 } 682 683 /** 684 * Gets the state set of this object. The AccessibleStateSet of an object 685 * is composed of a set of unique AccessibleStates. A change in the 686 * AccessibleStateSet of an object will cause a PropertyChangeEvent to 687 * be fired for the ACCESSIBLE_STATE_PROPERTY property. 688 * 689 * @return an instance of AccessibleStateSet containing the 690 * current state set of the object 691 * @see AccessibleStateSet 692 * @see AccessibleState 693 * @see #addPropertyChangeListener 694 */ getAccessibleStateSet()695 public AccessibleStateSet getAccessibleStateSet() { 696 if (accessibleJOptionPane != null) { 697 // delegate to the AccessibleJOptionPane 698 return accessibleJOptionPane.getAccessibleStateSet(); 699 } 700 return null; 701 } 702 703 /** 704 * Gets the Accessible parent of this object. 705 * 706 * @return the Accessible parent of this object; null if this 707 * object does not have an Accessible parent 708 */ getAccessibleParent()709 public Accessible getAccessibleParent() { 710 return dialog; 711 } 712 713 /* 714 * Returns the parent AccessibleContext 715 */ getParentAccessibleContext()716 private AccessibleContext getParentAccessibleContext() { 717 if (dialog != null) { 718 return dialog.getAccessibleContext(); 719 } 720 return null; 721 } 722 723 /** 724 * Gets the 0-based index of this object in its accessible parent. 725 * 726 * @return the 0-based index of this object in its parent; -1 if this 727 * object does not have an accessible parent. 728 * 729 * @see #getAccessibleParent 730 * @see #getAccessibleChildrenCount 731 * @see #getAccessibleChild 732 */ getAccessibleIndexInParent()733 public int getAccessibleIndexInParent() { 734 if (accessibleJOptionPane != null) { 735 // delegate to the AccessibleJOptionPane 736 return accessibleJOptionPane.getAccessibleIndexInParent(); 737 } 738 return -1; 739 } 740 741 /** 742 * Returns the number of accessible children of the object. 743 * 744 * @return the number of accessible children of the object. 745 */ getAccessibleChildrenCount()746 public int getAccessibleChildrenCount() { 747 // return the number of children in the JPanel containing 748 // the message, note label and progress bar 749 AccessibleContext ac = getPanelAccessibleContext(); 750 if (ac != null) { 751 return ac.getAccessibleChildrenCount(); 752 } 753 return 0; 754 } 755 756 /** 757 * Returns the specified Accessible child of the object. The Accessible 758 * children of an Accessible object are zero-based, so the first child 759 * of an Accessible child is at index 0, the second child is at index 1, 760 * and so on. 761 * 762 * @param i zero-based index of child 763 * @return the Accessible child of the object 764 * @see #getAccessibleChildrenCount 765 */ getAccessibleChild(int i)766 public Accessible getAccessibleChild(int i) { 767 // return a child in the JPanel containing the message, note label 768 // and progress bar 769 AccessibleContext ac = getPanelAccessibleContext(); 770 if (ac != null) { 771 return ac.getAccessibleChild(i); 772 } 773 return null; 774 } 775 776 /* 777 * Returns the AccessibleContext for the JPanel containing the 778 * message, note label and progress bar 779 */ getPanelAccessibleContext()780 private AccessibleContext getPanelAccessibleContext() { 781 if (myBar != null) { 782 Component c = myBar.getParent(); 783 if (c instanceof Accessible) { 784 return c.getAccessibleContext(); 785 } 786 } 787 return null; 788 } 789 790 /** 791 * Gets the locale of the component. If the component does not have a 792 * locale, then the locale of its parent is returned. 793 * 794 * @return this component's locale. If this component does not have 795 * a locale, the locale of its parent is returned. 796 * 797 * @exception IllegalComponentStateException 798 * If the Component does not have its own locale and has not yet been 799 * added to a containment hierarchy such that the locale can be 800 * determined from the containing parent. 801 */ getLocale()802 public Locale getLocale() throws IllegalComponentStateException { 803 if (accessibleJOptionPane != null) { 804 // delegate to the AccessibleJOptionPane 805 return accessibleJOptionPane.getLocale(); 806 } 807 return null; 808 } 809 810 /* ===== end AccessibleContext ===== */ 811 812 /** 813 * Gets the AccessibleComponent associated with this object that has a 814 * graphical representation. 815 * 816 * @return AccessibleComponent if supported by object; else return null 817 * @see AccessibleComponent 818 */ getAccessibleComponent()819 public AccessibleComponent getAccessibleComponent() { 820 if (accessibleJOptionPane != null) { 821 // delegate to the AccessibleJOptionPane 822 return accessibleJOptionPane.getAccessibleComponent(); 823 } 824 return null; 825 } 826 827 /** 828 * Gets the AccessibleValue associated with this object that supports a 829 * Numerical value. 830 * 831 * @return AccessibleValue if supported by object; else return null 832 * @see AccessibleValue 833 */ getAccessibleValue()834 public AccessibleValue getAccessibleValue() { 835 if (myBar != null) { 836 // delegate to the AccessibleJProgressBar 837 return myBar.getAccessibleContext().getAccessibleValue(); 838 } 839 return null; 840 } 841 842 /** 843 * Gets the AccessibleText associated with this object presenting 844 * text on the display. 845 * 846 * @return AccessibleText if supported by object; else return null 847 * @see AccessibleText 848 */ getAccessibleText()849 public AccessibleText getAccessibleText() { 850 if (getNoteLabelAccessibleText() != null) { 851 return this; 852 } 853 return null; 854 } 855 856 /* 857 * Returns the note label AccessibleText 858 */ getNoteLabelAccessibleText()859 private AccessibleText getNoteLabelAccessibleText() { 860 if (noteLabel != null) { 861 // AccessibleJLabel implements AccessibleText if the 862 // JLabel contains HTML text 863 return noteLabel.getAccessibleContext().getAccessibleText(); 864 } 865 return null; 866 } 867 868 /* ===== Begin AccessibleText impl ===== */ 869 870 /** 871 * Given a point in local coordinates, return the zero-based index 872 * of the character under that Point. If the point is invalid, 873 * this method returns -1. 874 * 875 * @param p the Point in local coordinates 876 * @return the zero-based index of the character under Point p; if 877 * Point is invalid return -1. 878 */ getIndexAtPoint(Point p)879 public int getIndexAtPoint(Point p) { 880 AccessibleText at = getNoteLabelAccessibleText(); 881 if (at != null && sameWindowAncestor(pane, noteLabel)) { 882 // convert point from the option pane bounds 883 // to the note label bounds. 884 Point noteLabelPoint = SwingUtilities.convertPoint(pane, 885 p, 886 noteLabel); 887 if (noteLabelPoint != null) { 888 return at.getIndexAtPoint(noteLabelPoint); 889 } 890 } 891 return -1; 892 } 893 894 /** 895 * Determines the bounding box of the character at the given 896 * index into the string. The bounds are returned in local 897 * coordinates. If the index is invalid an empty rectangle is returned. 898 * 899 * @param i the index into the String 900 * @return the screen coordinates of the character's bounding box, 901 * if index is invalid return an empty rectangle. 902 */ getCharacterBounds(int i)903 public Rectangle getCharacterBounds(int i) { 904 AccessibleText at = getNoteLabelAccessibleText(); 905 if (at != null && sameWindowAncestor(pane, noteLabel)) { 906 // return rectangle in the option pane bounds 907 Rectangle noteLabelRect = at.getCharacterBounds(i); 908 if (noteLabelRect != null) { 909 return SwingUtilities.convertRectangle(noteLabel, 910 noteLabelRect, 911 pane); 912 } 913 } 914 return null; 915 } 916 917 /* 918 * Returns whether source and destination components have the 919 * same window ancestor 920 */ sameWindowAncestor(Component src, Component dest)921 private boolean sameWindowAncestor(Component src, Component dest) { 922 if (src == null || dest == null) { 923 return false; 924 } 925 return SwingUtilities.getWindowAncestor(src) == 926 SwingUtilities.getWindowAncestor(dest); 927 } 928 929 /** 930 * Returns the number of characters (valid indicies) 931 * 932 * @return the number of characters 933 */ getCharCount()934 public int getCharCount() { 935 AccessibleText at = getNoteLabelAccessibleText(); 936 if (at != null) { // JLabel contains HTML text 937 return at.getCharCount(); 938 } 939 return -1; 940 } 941 942 /** 943 * Returns the zero-based offset of the caret. 944 * 945 * Note: That to the right of the caret will have the same index 946 * value as the offset (the caret is between two characters). 947 * @return the zero-based offset of the caret. 948 */ getCaretPosition()949 public int getCaretPosition() { 950 AccessibleText at = getNoteLabelAccessibleText(); 951 if (at != null) { // JLabel contains HTML text 952 return at.getCaretPosition(); 953 } 954 return -1; 955 } 956 957 /** 958 * Returns the String at a given index. 959 * 960 * @param part the CHARACTER, WORD, or SENTENCE to retrieve 961 * @param index an index within the text 962 * @return the letter, word, or sentence 963 */ getAtIndex(int part, int index)964 public String getAtIndex(int part, int index) { 965 AccessibleText at = getNoteLabelAccessibleText(); 966 if (at != null) { // JLabel contains HTML text 967 return at.getAtIndex(part, index); 968 } 969 return null; 970 } 971 972 /** 973 * Returns the String after a given index. 974 * 975 * @param part the CHARACTER, WORD, or SENTENCE to retrieve 976 * @param index an index within the text 977 * @return the letter, word, or sentence 978 */ getAfterIndex(int part, int index)979 public String getAfterIndex(int part, int index) { 980 AccessibleText at = getNoteLabelAccessibleText(); 981 if (at != null) { // JLabel contains HTML text 982 return at.getAfterIndex(part, index); 983 } 984 return null; 985 } 986 987 /** 988 * Returns the String before a given index. 989 * 990 * @param part the CHARACTER, WORD, or SENTENCE to retrieve 991 * @param index an index within the text 992 * @return the letter, word, or sentence 993 */ getBeforeIndex(int part, int index)994 public String getBeforeIndex(int part, int index) { 995 AccessibleText at = getNoteLabelAccessibleText(); 996 if (at != null) { // JLabel contains HTML text 997 return at.getBeforeIndex(part, index); 998 } 999 return null; 1000 } 1001 1002 /** 1003 * Returns the AttributeSet for a given character at a given index 1004 * 1005 * @param i the zero-based index into the text 1006 * @return the AttributeSet of the character 1007 */ getCharacterAttribute(int i)1008 public AttributeSet getCharacterAttribute(int i) { 1009 AccessibleText at = getNoteLabelAccessibleText(); 1010 if (at != null) { // JLabel contains HTML text 1011 return at.getCharacterAttribute(i); 1012 } 1013 return null; 1014 } 1015 1016 /** 1017 * Returns the start offset within the selected text. 1018 * If there is no selection, but there is 1019 * a caret, the start and end offsets will be the same. 1020 * 1021 * @return the index into the text of the start of the selection 1022 */ getSelectionStart()1023 public int getSelectionStart() { 1024 AccessibleText at = getNoteLabelAccessibleText(); 1025 if (at != null) { // JLabel contains HTML text 1026 return at.getSelectionStart(); 1027 } 1028 return -1; 1029 } 1030 1031 /** 1032 * Returns the end offset within the selected text. 1033 * If there is no selection, but there is 1034 * a caret, the start and end offsets will be the same. 1035 * 1036 * @return the index into the text of the end of the selection 1037 */ getSelectionEnd()1038 public int getSelectionEnd() { 1039 AccessibleText at = getNoteLabelAccessibleText(); 1040 if (at != null) { // JLabel contains HTML text 1041 return at.getSelectionEnd(); 1042 } 1043 return -1; 1044 } 1045 1046 /** 1047 * Returns the portion of the text that is selected. 1048 * 1049 * @return the String portion of the text that is selected 1050 */ getSelectedText()1051 public String getSelectedText() { 1052 AccessibleText at = getNoteLabelAccessibleText(); 1053 if (at != null) { // JLabel contains HTML text 1054 return at.getSelectedText(); 1055 } 1056 return null; 1057 } 1058 /* ===== End AccessibleText impl ===== */ 1059 } 1060 // inner class AccessibleProgressMonitor 1061 1062 } 1063