3 import jalview.util.MessageManager;
5 import java.awt.BorderLayout;
6 import java.awt.Component;
7 import java.awt.GridLayout;
8 import java.awt.event.ActionEvent;
9 import java.awt.event.ActionListener;
10 import java.util.Hashtable;
13 import javax.swing.JButton;
14 import javax.swing.JLabel;
15 import javax.swing.JPanel;
16 import javax.swing.JProgressBar;
17 import javax.swing.SwingUtilities;
20 * A class to manage multiple progress bars embedded in a JPanel.
23 * Refactored from code duplicated in AlignFrame, PCAPanel, WebserviceInfo.
25 public class ProgressBar implements IProgressIndicator
28 * Progress bars in progress, keyed by any arbitrary long value
30 Map<Long, JPanel> progressBars;
33 * Optional handlers for the progress bars
35 Map<Long, IProgressIndicatorHandler> progressBarHandlers;
38 * The panel containing the progress bars - must have GridLayout
40 private JPanel statusPanel;
43 * Optional label where a status update message can be written on completion
46 private JLabel statusBar;
49 * Constructor. Note that the container of the progress bars, and the status
50 * bar to which an optional completion message is written, should be unchanged
51 * for the lifetime of this object for consistent behaviour.
54 * the panel holding the progress bars; must have GridLayout manager
56 * an optional place to write a message when a progress bar is
59 public ProgressBar(JPanel container, JLabel statusBar)
61 if (container == null)
63 throw new NullPointerException();
66 .isAssignableFrom(container.getLayout().getClass()))
68 throw new IllegalArgumentException("Container must have GridLayout");
70 this.statusPanel = container;
71 this.statusBar = statusBar;
72 this.progressBars = new Hashtable<Long, JPanel>();
73 this.progressBarHandlers = new Hashtable<Long, IProgressIndicatorHandler>();
78 * Returns true if any progress bars are still active
83 public boolean operationInProgress()
85 if (progressBars != null && progressBars.size() > 0)
93 * First call for a given id will show the message as a new progress bar. A
94 * second call with the same id will remove it. The 'removal' message is
95 * written to the status bar field (if neither is null).
97 * To avoid progress bars being left orphaned, ensure their removal is
98 * performed in a finally block if there is any risk of an error during
102 public void setProgressBar(String message, long id)
104 Long longId = Long.valueOf(id);
106 JPanel progressPanel = progressBars.get(longId);
107 if (progressPanel != null)
110 * Progress bar is displayed for this id - remove it now, and any handler
112 progressBars.remove(id);
113 if (message != null && statusBar != null)
115 statusBar.setText(message);
117 if (progressBarHandlers.containsKey(longId))
119 progressBarHandlers.remove(longId);
121 removeRow(progressPanel);
126 * No progress bar for this id - add one now
128 progressPanel = new JPanel(new BorderLayout(10, 5));
130 JProgressBar progressBar = new JProgressBar();
131 progressBar.setIndeterminate(true);
133 progressPanel.add(new JLabel(message), BorderLayout.WEST);
134 progressPanel.add(progressBar, BorderLayout.CENTER);
136 addRow(progressPanel);
138 progressBars.put(longId, progressPanel);
145 * Lays out progress bar container hierarchy
147 protected void refreshLayout()
150 * lay out progress bar container hierarchy
152 Component root = SwingUtilities.getRoot(statusPanel);
160 * Remove one row with a progress bar, in a thread-safe manner
162 * @param progressPanel
164 protected void removeRow(JPanel progressPanel)
166 synchronized (statusPanel)
168 statusPanel.remove(progressPanel);
169 GridLayout layout = (GridLayout) statusPanel.getLayout();
170 layout.setRows(layout.getRows() - 1);
171 statusPanel.remove(progressPanel);
176 * Add one row with a progress bar, in a thread-safe manner
178 * @param progressPanel
180 protected void addRow(JPanel progressPanel)
182 synchronized (statusPanel)
184 GridLayout layout = (GridLayout) statusPanel.getLayout();
185 layout.setRows(layout.getRows() + 1);
186 statusPanel.add(progressPanel);
191 * Add a 'Cancel' handler for the given progress bar id. This should be called
192 * _after_ setProgressBar to have any effect.
195 public void registerHandler(final long id,
196 final IProgressIndicatorHandler handler)
198 Long longId = Long.valueOf(id);
199 final JPanel progressPanel = progressBars.get(longId);
200 if (progressPanel == null)
203 .println("call setProgressBar before registering the progress bar's handler.");
208 * Nothing useful to do if not a Cancel handler
210 if (!handler.canCancel())
215 progressBarHandlers.put(longId, handler);
216 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
217 final IProgressIndicator us = this;
218 cancel.addActionListener(new ActionListener()
222 public void actionPerformed(ActionEvent e)
224 handler.cancelActivity(id);
225 us.setProgressBar(MessageManager.formatMessage(
226 "label.cancelled_params", new Object[]
227 { ((JLabel) progressPanel.getComponent(0)).getText() }), id);
230 progressPanel.add(cancel, BorderLayout.EAST);