/src/net/java/swingfx/waitwithstyle/CancelableProgessAdapter.java

https://code.google.com/p/ascension-log-visualizer/ · Java · 209 lines · 108 code · 18 blank · 83 comment · 27 complexity · f8369d0816e406244954763b006da618 MD5 · raw file

  1. package net.java.swingfx.waitwithstyle;
  2. import java.awt.Cursor;
  3. import java.awt.Rectangle;
  4. import java.awt.event.ActionEvent;
  5. import java.awt.event.ActionListener;
  6. import java.beans.PropertyChangeEvent;
  7. import java.beans.PropertyChangeListener;
  8. import javax.swing.*;
  9. /**
  10. * An InfiniteProgressAdapter that adds a cancel button to a CancelableAdaptee
  11. * (the InfiniteProgressPanel or the PerformanceProgressPanel).
  12. *
  13. * @author Michael Bushe michael@bushe.com
  14. */
  15. public class CancelableProgessAdapter implements InfiniteProgressAdapter {
  16. protected CancelableAdaptee progressPanel;
  17. protected JLabel textLabel;
  18. protected JButton cancelButton;
  19. protected JButton applicationDefaultButton;
  20. private JRootPane rootPane;
  21. /**
  22. * Construct with an adaptee
  23. *
  24. * @param progressPanel
  25. * the adaptee, if null, setAdaptee() can be called later (before
  26. * animation starting) with a non-null value.
  27. */
  28. public CancelableProgessAdapter(
  29. final CancelableAdaptee progressPanel) {
  30. setAdaptee(progressPanel);
  31. }
  32. /**
  33. * Must be called with a non-null before any of the adaptee's calls to
  34. * animationStarting, etc. are called.
  35. *
  36. * @param progressPanel
  37. */
  38. public void setAdaptee(
  39. final CancelableAdaptee progressPanel) {
  40. this.progressPanel = progressPanel;
  41. }
  42. /**
  43. * Adds a cancel listener that will be called back when the the cancel
  44. * button is clicked.
  45. *
  46. * @param listener
  47. * a cancel callback
  48. */
  49. public void addCancelListener(
  50. final ActionListener listener) {
  51. if (cancelButton == null)
  52. cancelButton = createCancelButton();
  53. if (cancelButton != null)
  54. cancelButton.addActionListener(listener);
  55. }
  56. /**
  57. * Eemoves a cancel listener that would have been called back when the the
  58. * cancel button was clicked.
  59. *
  60. * @param listener
  61. * a cancel callback
  62. */
  63. public void removeCancelListener(
  64. final ActionListener listener) {
  65. if (cancelButton != null)
  66. cancelButton.removeActionListener(listener);
  67. }
  68. /**
  69. * Overridable to supply your own button. Overriders should:
  70. * <ul>
  71. * <li>Call progresspanel.stop() on action performed.
  72. * <li>Set the cursor on their button, else the busy cursor will not
  73. * indicate to the user that the button is clickable.
  74. * </ul>
  75. */
  76. protected JButton createCancelButton() {
  77. if (progressPanel instanceof JComponent) {
  78. rootPane = ((JComponent) progressPanel).getRootPane();
  79. if (rootPane != null)
  80. rootPane.addPropertyChangeListener(new PropertyChangeListener() {
  81. public void propertyChange(
  82. final PropertyChangeEvent evt) {
  83. if ("defaultButton".equals(evt.getPropertyName())) {
  84. /*
  85. * Track the default button every time it changes so
  86. * that when the cancel button becomes the default
  87. * button, as it must when the user clicks it, its
  88. * possible to reset the default button back to
  89. * being the button that the application expects it
  90. * to be... Ideally, the cancel button should never
  91. * even get focus as a focus change is not
  92. * transparent to application code. A better scheme
  93. * might be to set cancel button to be not focusable
  94. * and then click the button programmatically as
  95. * appropriate.
  96. */
  97. final JButton oldDefaultButton = (JButton) evt.getOldValue();
  98. if (oldDefaultButton != cancelButton)
  99. applicationDefaultButton = oldDefaultButton;
  100. }
  101. }
  102. });
  103. }
  104. final JButton button = new JButton("Cancel");
  105. button.setCursor(Cursor.getDefaultCursor());
  106. button.addActionListener(new ActionListener() {
  107. public void actionPerformed(
  108. final ActionEvent e) {
  109. progressPanel.stop();
  110. if (rootPane != null) {
  111. if (applicationDefaultButton != null)
  112. rootPane.setDefaultButton(applicationDefaultButton);
  113. applicationDefaultButton = null;
  114. }
  115. }
  116. });
  117. return button;
  118. }
  119. /**
  120. * Called by the CancelableAdaptee (progress panel) when the animation is
  121. * starting. Does nothing by default.
  122. */
  123. public void animationStarting() {}
  124. /**
  125. * Called by the CancelableAdaptee (progress panel) when the animation is
  126. * stopping. Removes the button from the progressPanel by default.
  127. */
  128. public void animationStopping() {
  129. if (cancelButton != null)
  130. SwingUtilities.invokeLater(new Runnable() {
  131. public void run() {
  132. progressPanel.getComponent().remove(cancelButton);
  133. }
  134. });
  135. }
  136. /**
  137. * Called by the CancelableAdaptee (progress panel) when it is finished
  138. * painting itself.
  139. * <p>
  140. * By default, paints the cancelButton if it is not null.
  141. *
  142. * @param maxY
  143. * the lowest (on the screen) Y that the adapteee used - you
  144. * should paint your components before this.
  145. */
  146. public void paintSubComponents(
  147. final double maxY) {
  148. if (cancelButton != null) {
  149. final int buttonWidth = 80;
  150. final Rectangle cancelButtonBoundedRectangle = new Rectangle((progressPanel.getComponent()
  151. .getWidth() / 2 - buttonWidth / 2),
  152. (int) maxY + 10,
  153. 80,
  154. 21);
  155. cancelButton.setBounds(cancelButtonBoundedRectangle);
  156. }
  157. }
  158. /**
  159. * Called by the CancelableAdaptee (progress panel) when the animation's
  160. * ramp up (fade in) is over. Adds the cancel button to the progressPanel by
  161. * default (if not null), via an invokeLater().
  162. */
  163. public void rampUpEnded() {
  164. SwingUtilities.invokeLater(new Runnable() {
  165. public void run() {
  166. if (cancelButton != null)
  167. progressPanel.getComponent().add(cancelButton);
  168. }
  169. });
  170. }
  171. /**
  172. * Called to programmatically click the cancel button. Can be called from
  173. * any thread.
  174. */
  175. public void doCancel() {
  176. final Runnable runner = new Runnable() {
  177. public void run() {
  178. if (cancelButton == null)
  179. // could be called programmatically, easy way to simulate,
  180. // don't care about expense
  181. cancelButton = createCancelButton();
  182. if (cancelButton != null)
  183. cancelButton.doClick();
  184. }
  185. };
  186. if (SwingUtilities.isEventDispatchThread())
  187. runner.run();
  188. else
  189. SwingUtilities.invokeLater(runner);
  190. }
  191. }