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