001    /*
002     * Copyright 2002-2007 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.richclient.application.statusbar.support;
017    
018    import java.awt.BorderLayout;
019    import java.awt.Dimension;
020    import java.awt.Insets;
021    import java.awt.event.ActionEvent;
022    import java.awt.event.ActionListener;
023    
024    import javax.swing.BorderFactory;
025    import javax.swing.Icon;
026    import javax.swing.JButton;
027    import javax.swing.JComponent;
028    import javax.swing.JPanel;
029    import javax.swing.JProgressBar;
030    import javax.swing.UIManager;
031    import javax.swing.border.BevelBorder;
032    import javax.swing.border.Border;
033    
034    import org.springframework.richclient.application.ApplicationServicesLocator;
035    import org.springframework.richclient.factory.AbstractControlFactory;
036    import org.springframework.richclient.image.IconSource;
037    import org.springframework.richclient.progress.ProgressMonitor;
038    import org.springframework.util.StringUtils;
039    
040    /**
041     * <code>ProgressMonitor</code> implementation that handles its own controls:
042     * <ul>
043     * <li>a <code>JProgressBar</code> to show the progress to the user</li>
044     * <li>optionally a <code>JButton</code> to allow the user to cancel the
045     * current task</li>
046     * </ul>
047     * <p>
048     * Initally the progress bar and button are hidden, and shown when a task is
049     * running longer than the <code>delayProgress</code> property (default is 500
050     * ms).
051     *
052     * @author Peter De Bruycker
053     */
054    public class StatusBarProgressMonitor extends AbstractControlFactory implements
055                    ProgressMonitor {
056    
057            /** Progress bar creation is delayed by this ms */
058            public static final int DEFAULT_DELAY_PROGRESS = 500;
059    
060            public static final int UNKNOWN = -1;
061    
062            private JButton cancelButton;
063    
064            private boolean cancelEnabled = true;
065    
066            private Icon cancelIcon;
067    
068            private JPanel control;
069    
070            private boolean isCanceled;
071    
072            private JProgressBar progressBar;
073    
074            private long startTime;
075    
076            private String taskName;
077    
078            private int delayProgress = DEFAULT_DELAY_PROGRESS;
079    
080            protected JButton createCancelButton() {
081                    JButton cancelButton = new JButton();
082                    cancelButton.setBorderPainted(false);
083                    cancelButton.setIcon(getCancelIcon());
084                    cancelButton.setMargin(new Insets(0, 0, 0, 0));
085    
086                    return cancelButton;
087            }
088    
089            protected JComponent createControl() {
090                    control = new JPanel(new BorderLayout());
091    
092                    cancelButton = createCancelButton();
093                    cancelButton.addActionListener(new ActionListener() {
094                            public void actionPerformed(ActionEvent e) {
095                                    logger.info("Requesting task cancellation...");
096                                    setCanceled(true);
097                            }
098                    });
099                    progressBar = createProgressBar();
100    
101                    control.add(progressBar);
102                    control.add(cancelButton, BorderLayout.LINE_END);
103    
104            Border bevelBorder = BorderFactory.createBevelBorder(BevelBorder.LOWERED, UIManager
105                    .getColor("controlHighlight"), UIManager.getColor("controlShadow"));
106            Border emptyBorder = BorderFactory.createEmptyBorder(1, 3, 1, 3);
107            control.setBorder(BorderFactory.createCompoundBorder(bevelBorder, emptyBorder));
108    
109                    // initially hide the control
110                    hideProgress();
111    
112                    return control;
113            }
114    
115            protected JProgressBar createProgressBar() {
116                    JProgressBar progressBar = new JProgressBar();
117                    progressBar.setPreferredSize(new Dimension(200, 17));
118                    progressBar.setStringPainted(true);
119    
120                    return progressBar;
121            }
122    
123            public void done() {
124                    startTime = 0;
125                    if (progressBar != null) {
126                            progressBar.setValue(progressBar.getMaximum());
127                            progressBar.setString("");
128                    }
129                    hideProgress();
130            }
131    
132            public Icon getCancelIcon() {
133                    if (cancelIcon == null) {
134                            cancelIcon = ((IconSource) ApplicationServicesLocator.services()
135                                            .getService(IconSource.class)).getIcon("cancel.icon");
136                    }
137    
138                    return cancelIcon;
139            }
140    
141            protected JProgressBar getProgressBar() {
142                    return progressBar;
143            }
144    
145            private void hideButton() {
146                    cancelButton.setEnabled(cancelEnabled);
147                    cancelButton.setVisible(false);
148            }
149    
150            protected void hideProgress() {
151                    if (progressBar.isVisible()) {
152                            progressBar.setVisible(false);
153                            cancelButton.setVisible(false);
154                    }
155            }
156    
157            public boolean isCanceled() {
158                    return isCanceled;
159            }
160    
161            public void setCanceled(boolean b) {
162                    isCanceled = b;
163                    cancelButton.setEnabled(!b);
164            }
165    
166            public void setCancelEnabled(boolean enabled) {
167                    cancelEnabled = enabled;
168                    if (progressBar.isVisible() && !cancelButton.isVisible() && enabled) {
169                            showButton();
170                    } else {
171                            hideButton();
172                    }
173            }
174    
175            public void setCancelIcon(Icon icon) {
176                    cancelIcon = icon;
177                    if (cancelButton != null) {
178                            cancelButton.setIcon(icon);
179                    }
180            }
181    
182            private void showButton() {
183                    cancelButton.setEnabled(cancelEnabled);
184                    cancelButton.setVisible(true);
185            }
186    
187            private void showProgress() {
188                    if (!progressBar.isVisible()) {
189                            if (cancelEnabled) {
190                                    showButton();
191                            }
192                            progressBar.setVisible(true);
193                    }
194            }
195    
196            public void subTaskStarted(String name) {
197                    String text;
198                    if (name.length() == 0) {
199                            text = name;
200                    } else {
201                            if (StringUtils.hasText(taskName)) {
202                                    text = taskName + " - " + name;
203                            } else {
204                                    text = name;
205                            }
206                    }
207                    progressBar.setString(text);
208            }
209    
210            public void taskStarted(String name, int totalWork) {
211                    startTime = System.currentTimeMillis();
212                    isCanceled = false;
213                    if (totalWork == UNKNOWN) {
214                            progressBar.setIndeterminate(true);
215                    } else {
216                            progressBar.setIndeterminate(false);
217                            progressBar.setMaximum(totalWork);
218                            progressBar.setValue(0);
219                    }
220                    taskName = name;
221                    progressBar.setString(taskName);
222                    showProgress();
223            }
224    
225            public void worked(int work) {
226                    if (!progressBar.isVisible()) {
227                            if ((System.currentTimeMillis() - startTime) > delayProgress) {
228                                    control.setVisible(true);
229                            }
230                    }
231                    progressBar.setValue((int) work);
232    
233                    if (progressBar.isStringPainted()) {
234                            progressBar.setString(((int) work) + "%");
235                    }
236            }
237    
238            public void setDelayProgress(int delayProgress) {
239                    this.delayProgress = delayProgress;
240            }
241    }