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