1
22 package org.crosswire.common.progress.swing;
23
24 import java.awt.Component;
25 import java.awt.Font;
26 import java.awt.GridBagConstraints;
27 import java.awt.GridBagLayout;
28 import java.awt.GridLayout;
29 import java.io.IOException;
30 import java.io.ObjectInputStream;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36
37 import javax.swing.JButton;
38 import javax.swing.JPanel;
39 import javax.swing.JProgressBar;
40 import javax.swing.SwingUtilities;
41
42 import org.crosswire.common.icu.NumberShaper;
43 import org.crosswire.common.progress.Job;
44 import org.crosswire.common.progress.JobManager;
45 import org.crosswire.common.progress.Progress;
46 import org.crosswire.common.progress.ProgressMode;
47 import org.crosswire.common.progress.WorkEvent;
48 import org.crosswire.common.progress.WorkListener;
49 import org.crosswire.common.swing.ActionFactory;
50 import org.crosswire.common.swing.CWAction;
51 import org.crosswire.common.swing.GuiUtil;
52 import org.crosswire.common.util.Logger;
53
54
62 public class JobsProgressBar extends JPanel implements WorkListener {
63
66 public JobsProgressBar(boolean small) {
67 jobs = new HashMap<Progress, JobData>();
68 positions = new ArrayList<JobData>();
69 shaper = new NumberShaper();
70 actions = new ActionFactory(this);
71
72 if (small) {
73 font = new Font("SansSerif", Font.PLAIN, 10);
75 }
76
77 JobManager.addWorkListener(this);
78
79 Set<Progress> current = JobManager.getJobs();
80 for (Progress job : current) {
81 addJob(job);
82 }
83
84 this.setLayout(new GridLayout(1, 0, 2, 0));
85
86 GuiUtil.applyDefaultOrientation(this);
87 }
88
89
95 public synchronized JButton createCancelButton(Progress job) {
96 CWAction action = actions.addAction("Stop");
97 action.setSmallIcon("toolbarButtonGraphics/general/Stop16.gif");
98 action.setListener(new JobCancelListener(job));
99 return GuiUtil.flatten(new JButton(action));
100 }
101
102
109 public synchronized void workProgressed(final WorkEvent ev) {
110 SwingUtilities.invokeLater(new Runnable() {
111 public void run() {
112 Progress job = ev.getJob();
113
114 if (!jobs.containsKey(job)) {
115 addJob(job);
116 }
117
118 updateJob(job);
119
120 if (job.isFinished()) {
121 removeJob(job);
122 }
123 }
124 });
125 }
126
127
134 public void workStateChanged(WorkEvent ev) {
135 Progress job = (Job) ev.getSource();
136 JobData jobdata = jobs.get(job);
137 jobdata.workStateChanged(ev);
138 }
139
140
143 final synchronized void addJob(Progress job) {
144 ((Job) job).addWorkListener(this);
145
146 int i = findEmptyPosition();
147 log.debug("adding job to panel at " + i + ": " + job.getJobName());
148
149 JProgressBar progress = new JProgressBar();
150 progress.setStringPainted(true);
154 progress.setToolTipText(job.getJobName());
155 progress.setBorder(null);
156 progress.setBackground(getBackground());
157 progress.setForeground(getForeground());
158 if (font != null) {
159 progress.setFont(font);
160 }
161 GuiUtil.applyDefaultOrientation(progress);
162
163
167 JobData jobdata = new JobData(this, job, i, progress);
168 jobs.put(job, jobdata);
169 if (i >= positions.size()) {
170 positions.add(jobdata);
171 } else {
172 positions.set(i, jobdata);
173 }
174
175 this.add(jobdata.getComponent(), i);
176 GuiUtil.refresh(this);
177 GuiUtil.applyDefaultOrientation(this);
178 }
179
180
183 protected synchronized void updateJob(Progress job) {
184 JobData jobdata = jobs.get(job);
185
186 int percent = 99;
188 StringBuilder buf = new StringBuilder(job.getSectionName());
189 if (job.getProgressMode() != ProgressMode.UNKNOWN) {
190 percent = job.getWork();
191 buf.append(": ");
192 buf.append(shaper.shape(Integer.toString(percent)));
193 buf.append('%');
194 }
195 jobdata.getProgress().setString(buf.toString());
196 jobdata.getProgress().setValue(percent);
197 }
198
199
202 protected synchronized void removeJob(Progress job) {
203 ((Job) job).removeWorkListener(this);
204
205 JobData jobdata = jobs.get(job);
206
207 positions.set(jobdata.getIndex(), null);
208 jobs.remove(job);
209 log.debug("removing job from panel: " + jobdata.getJob().getJobName());
210
211 this.remove(jobdata.getComponent());
212 GuiUtil.refresh(this);
213 jobdata.invalidate();
214 }
215
216
219 private int findEmptyPosition() {
220 int i = 0;
221 while (true) {
222 if (i >= positions.size()) {
223 break;
224 }
225
226 if (positions.get(i) == null) {
227 break;
228 }
229
230 i++;
231 }
232
233 return i;
234 }
235
236
243 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
244 actions = new ActionFactory(this);
245 is.defaultReadObject();
246 }
247
248
251 protected transient Map<Progress, JobData> jobs;
252
253
256 private transient List<JobData> positions;
257
258
261 private Font font;
262
263
266 private NumberShaper shaper = new NumberShaper();
267
268
271 private transient ActionFactory actions;
272
273
276 private static final Logger log = Logger.getLogger(JobsProgressBar.class);
277
278
281 private static final long serialVersionUID = 3257563988660663606L;
282
283
286 private static class JobData implements WorkListener {
287
290 JobData(JobsProgressBar bar, Progress job, int index, JProgressBar progress) {
291 this.bar = bar;
292 this.job = job;
293 this.index = index;
294 this.progress = progress;
295 this.comp = decorateProgressBar();
296 }
297
298
301 void invalidate() {
302 job = null;
303 progress = null;
304 index = -1;
305 }
306
307
310 Progress getJob() {
311 return job;
312 }
313
314
317 JProgressBar getProgress() {
318 return progress;
319 }
320
321
324 public Component getComponent() {
325 return comp;
326 }
327
328
331 int getIndex() {
332 return index;
333 }
334
335
342 public void workStateChanged(WorkEvent evt) {
343 if (cancelButton != null) {
344 cancelButton.setEnabled(job.isCancelable());
345 }
346 }
347
348
355 public void workProgressed(WorkEvent ev) {
356 }
358
359
365 private Component decorateProgressBar() {
366 if (!job.isCancelable()) {
367 return progress;
368 }
369
370 JPanel panel = new JPanel(new GridBagLayout());
371 GridBagConstraints gbc = new GridBagConstraints();
372 gbc.gridwidth = 1;
373 gbc.fill = GridBagConstraints.NONE;
374 cancelButton = bar.createCancelButton(job);
375 panel.add(cancelButton, gbc);
376 gbc.weightx = 1.0;
377 gbc.gridwidth = GridBagConstraints.REMAINDER;
378 gbc.fill = GridBagConstraints.HORIZONTAL;
379 panel.add(progress, gbc);
380 GuiUtil.applyDefaultOrientation(panel);
381 return panel;
382 }
383
384 private JobsProgressBar bar;
385 private Progress job;
386 private int index;
387 private JProgressBar progress;
388 private Component comp;
389 private JButton cancelButton;
390 }
391 }
392