blob: 36366df170c7a5a9fbbc50738bbd1e921af45139 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26
27
28package javax.swing;
29
30
31
32import java.io.*;
33import java.awt.BorderLayout;
34import java.awt.Frame;
35import java.awt.Dialog;
36import java.awt.Window;
37import java.awt.Component;
38import java.awt.Container;
39import java.beans.PropertyChangeEvent;
40import java.beans.PropertyChangeListener;
41import java.awt.event.WindowListener;
42import java.awt.event.WindowAdapter;
43import java.awt.event.WindowEvent;
44
45import java.awt.IllegalComponentStateException;
46import java.awt.Point;
47import java.awt.Rectangle;
48import java.text.*;
49import java.util.Locale;
50import javax.accessibility.*;
51import javax.swing.event.*;
52import 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 */
81public class ProgressMonitor extends Object 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 (WindowListener)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)((long)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 if (dialog != null) {
695 return (Accessible)dialog;
696 }
697 return null;
698 }
699
700 /*
701 * Returns the parent AccessibleContext
702 */
703 private AccessibleContext getParentAccessibleContext() {
704 if (dialog != null) {
705 return dialog.getAccessibleContext();
706 }
707 return null;
708 }
709
710 /**
711 * Gets the 0-based index of this object in its accessible parent.
712 *
713 * @return the 0-based index of this object in its parent; -1 if this
714 * object does not have an accessible parent.
715 *
716 * @see #getAccessibleParent
717 * @see #getAccessibleChildrenCount
718 * @see #getAccessibleChild
719 */
720 public int getAccessibleIndexInParent() {
721 if (accessibleJOptionPane != null) {
722 // delegate to the AccessibleJOptionPane
723 return accessibleJOptionPane.getAccessibleIndexInParent();
724 }
725 return -1;
726 }
727
728 /**
729 * Returns the number of accessible children of the object.
730 *
731 * @return the number of accessible children of the object.
732 */
733 public int getAccessibleChildrenCount() {
734 // return the number of children in the JPanel containing
735 // the message, note label and progress bar
736 AccessibleContext ac = getPanelAccessibleContext();
737 if (ac != null) {
738 return ac.getAccessibleChildrenCount();
739 }
740 return 0;
741 }
742
743 /**
744 * Returns the specified Accessible child of the object. The Accessible
745 * children of an Accessible object are zero-based, so the first child
746 * of an Accessible child is at index 0, the second child is at index 1,
747 * and so on.
748 *
749 * @param i zero-based index of child
750 * @return the Accessible child of the object
751 * @see #getAccessibleChildrenCount
752 */
753 public Accessible getAccessibleChild(int i) {
754 // return a child in the JPanel containing the message, note label
755 // and progress bar
756 AccessibleContext ac = getPanelAccessibleContext();
757 if (ac != null) {
758 return ac.getAccessibleChild(i);
759 }
760 return null;
761 }
762
763 /*
764 * Returns the AccessibleContext for the JPanel containing the
765 * message, note label and progress bar
766 */
767 private AccessibleContext getPanelAccessibleContext() {
768 if (myBar != null) {
769 Component c = myBar.getParent();
770 if (c instanceof Accessible) {
771 return ((Accessible)c).getAccessibleContext();
772 }
773 }
774 return null;
775 }
776
777 /**
778 * Gets the locale of the component. If the component does not have a
779 * locale, then the locale of its parent is returned.
780 *
781 * @return this component's locale. If this component does not have
782 * a locale, the locale of its parent is returned.
783 *
784 * @exception IllegalComponentStateException
785 * If the Component does not have its own locale and has not yet been
786 * added to a containment hierarchy such that the locale can be
787 * determined from the containing parent.
788 */
789 public Locale getLocale() throws IllegalComponentStateException {
790 if (accessibleJOptionPane != null) {
791 // delegate to the AccessibleJOptionPane
792 return accessibleJOptionPane.getLocale();
793 }
794 return null;
795 }
796
797 /* ===== end AccessibleContext ===== */
798
799 /**
800 * Gets the AccessibleComponent associated with this object that has a
801 * graphical representation.
802 *
803 * @return AccessibleComponent if supported by object; else return null
804 * @see AccessibleComponent
805 */
806 public AccessibleComponent getAccessibleComponent() {
807 if (accessibleJOptionPane != null) {
808 // delegate to the AccessibleJOptionPane
809 return accessibleJOptionPane.getAccessibleComponent();
810 }
811 return null;
812 }
813
814 /**
815 * Gets the AccessibleValue associated with this object that supports a
816 * Numerical value.
817 *
818 * @return AccessibleValue if supported by object; else return null
819 * @see AccessibleValue
820 */
821 public AccessibleValue getAccessibleValue() {
822 if (myBar != null) {
823 // delegate to the AccessibleJProgressBar
824 return myBar.getAccessibleContext().getAccessibleValue();
825 }
826 return null;
827 }
828
829 /**
830 * Gets the AccessibleText associated with this object presenting
831 * text on the display.
832 *
833 * @return AccessibleText if supported by object; else return null
834 * @see AccessibleText
835 */
836 public AccessibleText getAccessibleText() {
837 if (getNoteLabelAccessibleText() != null) {
838 return this;
839 }
840 return null;
841 }
842
843 /*
844 * Returns the note label AccessibleText
845 */
846 private AccessibleText getNoteLabelAccessibleText() {
847 if (noteLabel != null) {
848 // AccessibleJLabel implements AccessibleText if the
849 // JLabel contains HTML text
850 return noteLabel.getAccessibleContext().getAccessibleText();
851 }
852 return null;
853 }
854
855 /* ===== Begin AccessibleText impl ===== */
856
857 /**
858 * Given a point in local coordinates, return the zero-based index
859 * of the character under that Point. If the point is invalid,
860 * this method returns -1.
861 *
862 * @param p the Point in local coordinates
863 * @return the zero-based index of the character under Point p; if
864 * Point is invalid return -1.
865 */
866 public int getIndexAtPoint(Point p) {
867 AccessibleText at = getNoteLabelAccessibleText();
868 if (at != null && sameWindowAncestor(pane, noteLabel)) {
869 // convert point from the option pane bounds
870 // to the note label bounds.
871 Point noteLabelPoint = SwingUtilities.convertPoint(pane,
872 p,
873 noteLabel);
874 if (noteLabelPoint != null) {
875 return at.getIndexAtPoint(noteLabelPoint);
876 }
877 }
878 return -1;
879 }
880
881 /**
882 * Determines the bounding box of the character at the given
883 * index into the string. The bounds are returned in local
884 * coordinates. If the index is invalid an empty rectangle is returned.
885 *
886 * @param i the index into the String
887 * @return the screen coordinates of the character's bounding box,
888 * if index is invalid return an empty rectangle.
889 */
890 public Rectangle getCharacterBounds(int i) {
891 AccessibleText at = getNoteLabelAccessibleText();
892 if (at != null && sameWindowAncestor(pane, noteLabel)) {
893 // return rectangle in the option pane bounds
894 Rectangle noteLabelRect = at.getCharacterBounds(i);
895 if (noteLabelRect != null) {
896 return SwingUtilities.convertRectangle(noteLabel,
897 noteLabelRect,
898 pane);
899 }
900 }
901 return null;
902 }
903
904 /*
905 * Returns whether source and destination components have the
906 * same window ancestor
907 */
908 private boolean sameWindowAncestor(Component src, Component dest) {
909 if (src == null || dest == null) {
910 return false;
911 }
912 return SwingUtilities.getWindowAncestor(src) ==
913 SwingUtilities.getWindowAncestor(dest);
914 }
915
916 /**
917 * Returns the number of characters (valid indicies)
918 *
919 * @return the number of characters
920 */
921 public int getCharCount() {
922 AccessibleText at = getNoteLabelAccessibleText();
923 if (at != null) { // JLabel contains HTML text
924 return at.getCharCount();
925 }
926 return -1;
927 }
928
929 /**
930 * Returns the zero-based offset of the caret.
931 *
932 * Note: That to the right of the caret will have the same index
933 * value as the offset (the caret is between two characters).
934 * @return the zero-based offset of the caret.
935 */
936 public int getCaretPosition() {
937 AccessibleText at = getNoteLabelAccessibleText();
938 if (at != null) { // JLabel contains HTML text
939 return at.getCaretPosition();
940 }
941 return -1;
942 }
943
944 /**
945 * Returns the String at a given index.
946 *
947 * @param part the CHARACTER, WORD, or SENTENCE to retrieve
948 * @param index an index within the text
949 * @return the letter, word, or sentence
950 */
951 public String getAtIndex(int part, int index) {
952 AccessibleText at = getNoteLabelAccessibleText();
953 if (at != null) { // JLabel contains HTML text
954 return at.getAtIndex(part, index);
955 }
956 return null;
957 }
958
959 /**
960 * Returns the String after a given index.
961 *
962 * @param part the CHARACTER, WORD, or SENTENCE to retrieve
963 * @param index an index within the text
964 * @return the letter, word, or sentence
965 */
966 public String getAfterIndex(int part, int index) {
967 AccessibleText at = getNoteLabelAccessibleText();
968 if (at != null) { // JLabel contains HTML text
969 return at.getAfterIndex(part, index);
970 }
971 return null;
972 }
973
974 /**
975 * Returns the String before a given index.
976 *
977 * @param part the CHARACTER, WORD, or SENTENCE to retrieve
978 * @param index an index within the text
979 * @return the letter, word, or sentence
980 */
981 public String getBeforeIndex(int part, int index) {
982 AccessibleText at = getNoteLabelAccessibleText();
983 if (at != null) { // JLabel contains HTML text
984 return at.getBeforeIndex(part, index);
985 }
986 return null;
987 }
988
989 /**
990 * Returns the AttributeSet for a given character at a given index
991 *
992 * @param i the zero-based index into the text
993 * @return the AttributeSet of the character
994 */
995 public AttributeSet getCharacterAttribute(int i) {
996 AccessibleText at = getNoteLabelAccessibleText();
997 if (at != null) { // JLabel contains HTML text
998 return at.getCharacterAttribute(i);
999 }
1000 return null;
1001 }
1002
1003 /**
1004 * Returns the start offset within the selected text.
1005 * If there is no selection, but there is
1006 * a caret, the start and end offsets will be the same.
1007 *
1008 * @return the index into the text of the start of the selection
1009 */
1010 public int getSelectionStart() {
1011 AccessibleText at = getNoteLabelAccessibleText();
1012 if (at != null) { // JLabel contains HTML text
1013 return at.getSelectionStart();
1014 }
1015 return -1;
1016 }
1017
1018 /**
1019 * Returns the end offset within the selected text.
1020 * If there is no selection, but there is
1021 * a caret, the start and end offsets will be the same.
1022 *
1023 * @return the index into teh text of the end of the selection
1024 */
1025 public int getSelectionEnd() {
1026 AccessibleText at = getNoteLabelAccessibleText();
1027 if (at != null) { // JLabel contains HTML text
1028 return at.getSelectionEnd();
1029 }
1030 return -1;
1031 }
1032
1033 /**
1034 * Returns the portion of the text that is selected.
1035 *
1036 * @return the String portion of the text that is selected
1037 */
1038 public String getSelectedText() {
1039 AccessibleText at = getNoteLabelAccessibleText();
1040 if (at != null) { // JLabel contains HTML text
1041 return at.getSelectedText();
1042 }
1043 return null;
1044 }
1045 /* ===== End AccessibleText impl ===== */
1046 }
1047 // inner class AccessibleProgressMonitor
1048
1049}