PageRenderTime 35ms CodeModel.GetById 21ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

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