2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.util.MessageManager;
25 import java.awt.BorderLayout;
26 import java.awt.Component;
27 import java.awt.GridLayout;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.util.Hashtable;
33 import javax.swing.JButton;
34 import javax.swing.JLabel;
35 import javax.swing.JPanel;
36 import javax.swing.JProgressBar;
37 import javax.swing.SwingUtilities;
40 * A class to manage multiple progress bars embedded in a JPanel.
43 * Refactored from code duplicated in AlignFrame, PCAPanel, WebserviceInfo.
45 public class ProgressBar implements IProgressIndicator
48 * Progress bars in progress, keyed by any arbitrary long value
50 Map<Long, JPanel> progressBars;
53 * Optional handlers for the progress bars
55 Map<Long, IProgressIndicatorHandler> progressBarHandlers;
58 * The panel containing the progress bars - must have GridLayout
60 private JPanel statusPanel;
63 * Optional label where a status update message can be written on completion
66 private JLabel statusBar;
69 * Constructor. Note that the container of the progress bars, and the status
70 * bar to which an optional completion message is written, should be unchanged
71 * for the lifetime of this object for consistent behaviour.
74 * the panel holding the progress bars; must have GridLayout manager
76 * an optional place to write a message when a progress bar is
79 public ProgressBar(JPanel container, JLabel statusBar)
81 if (container == null)
83 throw new NullPointerException();
86 .isAssignableFrom(container.getLayout().getClass()))
88 throw new IllegalArgumentException("Container must have GridLayout");
90 this.statusPanel = container;
91 this.statusBar = statusBar;
92 this.progressBars = new Hashtable<>();
93 this.progressBarHandlers = new Hashtable<>();
98 * Returns true if any progress bars are still active
103 public boolean operationInProgress()
105 if (progressBars != null && progressBars.size() > 0)
113 * First call for a given id will show the message as a new progress bar. A
114 * second call with the same id will remove it. The 'removal' message is
115 * written to the status bar field (if neither is null).
117 * To avoid progress bars being left orphaned, ensure their removal is
118 * performed in a finally block if there is any risk of an error during
122 public void setProgressBar(final String message, final long id)
124 SwingUtilities.invokeLater(new Runnable()
129 if (progressBars.containsKey(id))
132 * Progress bar is displayed for this id - remove it now, and any handler
134 removeProgressBar(id);
135 if (message != null && statusBar != null)
137 statusBar.setText(message);
143 * No progress bar for this id - add one now
145 addProgressBar(id, message);
153 * Add a progress bar for the given id if it doesn't exist displaying the
154 * provided message. Subsequent calls do nothing.
157 * progress bar identifier
162 public void addProgressBar(final long id, final String message)
164 if (progressBars.containsKey(id))
166 JPanel progressPanel = new JPanel(new BorderLayout(10, 5));
167 progressBars.put(id, progressPanel);
169 JProgressBar progressBar = new JProgressBar();
170 progressBar.setIndeterminate(true);
171 progressPanel.add(new JLabel(message), BorderLayout.WEST);
172 progressPanel.add(progressBar, BorderLayout.CENTER);
173 addRow(progressPanel);
176 if (SwingUtilities.isEventDispatchThread())
179 SwingUtilities.invokeLater(r);
183 * Remove a progress bar for the given id if it exists. Subsequent calls do
187 * id of the progress bar to be removed
190 public void removeProgressBar(final long id)
192 JPanel progressPanel = progressBars.remove(id);
193 if (progressPanel == null)
195 progressBarHandlers.remove(id);
197 removeRow(progressPanel);
200 if (SwingUtilities.isEventDispatchThread())
203 SwingUtilities.invokeLater(r);
207 * Lays out progress bar container hierarchy
209 protected void refreshLayout()
212 * lay out progress bar container hierarchy
214 Component root = SwingUtilities.getRoot(statusPanel);
222 * Remove one row with a progress bar, in a thread-safe manner
224 * @param progressPanel
226 protected void removeRow(JPanel progressPanel)
228 synchronized (statusPanel)
230 statusPanel.remove(progressPanel);
231 GridLayout layout = (GridLayout) statusPanel.getLayout();
232 layout.setRows(layout.getRows() - 1);
233 statusPanel.remove(progressPanel);
238 * Add one row with a progress bar, in a thread-safe manner
240 * @param progressPanel
242 protected void addRow(JPanel progressPanel)
244 synchronized (statusPanel)
246 GridLayout layout = (GridLayout) statusPanel.getLayout();
247 layout.setRows(layout.getRows() + 1);
248 statusPanel.add(progressPanel);
253 * Add a 'Cancel' handler for the given progress bar id. This should be called
254 * _after_ setProgressBar to have any effect.
257 public void registerHandler(final long id,
258 final IProgressIndicatorHandler handler)
260 final IProgressIndicator us = this;
262 SwingUtilities.invokeLater(new Runnable()
267 final JPanel progressPanel = progressBars.get(id);
268 if (progressPanel == null)
271 "call setProgressBar before registering the progress bar's handler.");
276 * Nothing useful to do if not a Cancel handler
278 if (!handler.canCancel())
283 progressBarHandlers.put(id, handler);
284 JButton cancel = new JButton(
285 MessageManager.getString("action.cancel"));
286 cancel.addActionListener(new ActionListener()
290 public void actionPerformed(ActionEvent e)
292 handler.cancelActivity(id);
293 us.setProgressBar(MessageManager
294 .formatMessage("label.cancelled_params", new Object[]
295 { ((JLabel) progressPanel.getComponent(0)).getText() }),
299 progressPanel.add(cancel, BorderLayout.EAST);