Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.gui

File ProgressBar.java

 

Coverage histogram

../../img/srcFileCovDistChart6.png
37% of files have more coverage

Code metrics

38
91
16
1
370
229
39
0.43
5.69
16
2.44

Classes

Class Line # Actions
ProgressBar 46 91 39
0.544827654.5%
 

Contributing tests

This file is covered by 198 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package jalview.gui;
22   
23    import jalview.util.MessageManager;
24   
25    import java.awt.BorderLayout;
26    import java.awt.Component;
27    import java.awt.Container;
28    import java.awt.GridLayout;
29    import java.awt.event.ActionEvent;
30    import java.awt.event.ActionListener;
31    import java.util.Hashtable;
32    import java.util.Map;
33   
34    import javax.swing.JButton;
35    import javax.swing.JLabel;
36    import javax.swing.JPanel;
37    import javax.swing.JProgressBar;
38    import javax.swing.SwingUtilities;
39   
40    /**
41    * A class to manage multiple progress bars embedded in a JPanel.
42    */
43    /*
44    * Refactored from code duplicated in AlignFrame, PCAPanel, WebserviceInfo.
45    */
 
46    public class ProgressBar implements IProgressIndicator
47    {
48    /*
49    * Progress bars in progress, keyed by any arbitrary long value
50    */
51    Map<Long, JPanel> progressBars;
52   
53    Map<Long, String> progressBarMessages;
54   
55    /*
56    * Optional handlers for the progress bars
57    */
58    Map<Long, IProgressIndicatorHandler> progressBarHandlers;
59   
60    /*
61    * The panel containing the progress bars - must have GridLayout
62    */
63    private JPanel statusPanel;
64   
65    /*
66    * Optional label where a status update message can be written on completion
67    * of progress
68    */
69    private JLabel statusBar;
70   
71    /**
72    * Constructor. Note that the container of the progress bars, and the status
73    * bar to which an optional completion message is written, should be unchanged
74    * for the lifetime of this object for consistent behaviour.
75    *
76    * @param container
77    * the panel holding the progress bars; must have GridLayout manager
78    * @param statusBar
79    * an optional place to write a message when a progress bar is
80    * removed
81    */
 
82  497 toggle public ProgressBar(JPanel container, JLabel statusBar)
83    {
84  497 if (container == null)
85    {
86  1 throw new NullPointerException();
87    }
88  496 if (!GridLayout.class
89    .isAssignableFrom(container.getLayout().getClass()))
90    {
91  1 throw new IllegalArgumentException("Container must have GridLayout");
92    }
93  495 this.statusPanel = container;
94  495 this.statusBar = statusBar;
95  495 this.progressBars = new Hashtable<>();
96  495 this.progressBarHandlers = new Hashtable<>();
97  495 this.progressBarMessages = new Hashtable<>();
98   
99    }
100   
101    /**
102    * Returns true if any progress bars are still active
103    *
104    * @return
105    */
 
106  41 toggle @Override
107    public boolean operationInProgress()
108    {
109  41 if (progressBars != null && progressBars.size() > 0)
110    {
111  18 return true;
112    }
113  23 return false;
114    }
115   
116    /**
117    * First call for a given id will show the message as a new progress bar. A
118    * second call with the same id will remove it. The 'removal' message is
119    * written to the status bar field (if neither is null).
120    *
121    * To avoid progress bars being left orphaned, ensure their removal is
122    * performed in a finally block if there is any risk of an error during
123    * execution.
124    */
 
125  661 toggle @Override
126    public void setProgressBar(final String message, final long id)
127    {
128  661 SwingUtilities.invokeLater(new Runnable()
129    {
 
130  661 toggle @Override
131    public void run()
132    {
133  661 if (progressBars.containsKey(id))
134    {
135    /*
136    * Progress bar is displayed for this id - remove it now, and any handler
137    */
138  330 removeProgressBar(id);
139  330 if (message != null && statusBar != null)
140    {
141  17 statusBar.setText(message);
142    }
143    }
144    else
145    {
146    /*
147    * No progress bar for this id - add one now
148    */
149  331 addProgressBar(id, message);
150    }
151    }
152    });
153   
154    }
155   
156    /**
157    * Add a progress bar for the given id if it doesn't exist displaying the
158    * provided message. Subsequent calls do nothing.
159    *
160    * @param id
161    * progress bar identifier
162    * @param message
163    * displayed message
164    */
 
165  331 toggle @Override
166    public void addProgressBar(final long id, final String message)
167    {
168  331 if (progressBars.containsKey(id))
169  0 return;
170  331 JPanel progressPanel = new JPanel(new BorderLayout(10, 5));
171  331 progressBars.put(id, progressPanel);
172  331 progressBarMessages.put(id, message == null ? "" : message);
173  331 Runnable r = () -> {
174  331 JProgressBar progressBar = new JProgressBar();
175  331 progressBar.setIndeterminate(true);
176  331 progressPanel.add(new JLabel(message==null ? "" : message), BorderLayout.WEST);
177  331 progressPanel.add(progressBar, BorderLayout.CENTER);
178  331 addRow(progressPanel);
179  331 refreshLayout();
180    };
181  331 if (SwingUtilities.isEventDispatchThread())
182  331 r.run();
183    else
184  0 SwingUtilities.invokeLater(r);
185    }
186   
187    /**
188    * Remove a progress bar for the given id if it exists. Subsequent calls do
189    * nothing.
190    *
191    * @param id
192    * id of the progress bar to be removed
193    */
 
194  330 toggle @Override
195    public void removeProgressBar(final long id)
196    {
197  330 JPanel progressPanel = progressBars.remove(id);
198  330 progressBarMessages.remove(id);
199  330 if (progressPanel == null)
200  0 return;
201  330 progressBarHandlers.remove(id);
202  330 Runnable r = () -> {
203  330 removeRow(progressPanel);
204  330 refreshLayout();
205    };
206  330 if (SwingUtilities.isEventDispatchThread())
207  330 r.run();
208    else
209  0 SwingUtilities.invokeLater(r);
210    }
211   
212    /**
213    * Lays out progress bar container hierarchy
214    */
 
215  661 toggle protected void refreshLayout()
216    {
217    /*
218    * lay out progress bar container hierarchy
219    */
220  661 Component root = SwingUtilities.getRoot(statusPanel);
221  661 if (root != null)
222    {
223  584 root.validate();
224    }
225    }
226   
227    /**
228    * Remove one row with a progress bar, in a thread-safe manner
229    *
230    * @param progressPanel
231    */
 
232  330 toggle protected void removeRow(JPanel progressPanel)
233    {
234  330 synchronized (statusPanel)
235    {
236  330 statusPanel.remove(progressPanel);
237  330 GridLayout layout = (GridLayout) statusPanel.getLayout();
238  330 layout.setRows(layout.getRows() - 1);
239  330 statusPanel.remove(progressPanel);
240    }
241    }
242   
243    /**
244    * Add one row with a progress bar, in a thread-safe manner
245    *
246    * @param progressPanel
247    */
 
248  331 toggle protected void addRow(JPanel progressPanel)
249    {
250  331 synchronized (statusPanel)
251    {
252  331 GridLayout layout = (GridLayout) statusPanel.getLayout();
253  331 layout.setRows(layout.getRows() + 1);
254  331 statusPanel.add(progressPanel);
255    }
256    }
257   
258    /**
259    * Add a 'Cancel' handler for the given progress bar id. This should be called
260    * _after_ setProgressBar to have any effect.
261    */
 
262  0 toggle @Override
263    public void registerHandler(final long id,
264    final IProgressIndicatorHandler handler)
265    {
266  0 final IProgressIndicator us = this;
267   
268  0 SwingUtilities.invokeLater(new Runnable()
269    {
 
270  0 toggle @Override
271    public void run()
272    {
273  0 final JPanel progressPanel = progressBars.get(id);
274  0 if (progressPanel == null)
275    {
276  0 jalview.bin.Console.errPrintln(
277    "call setProgressBar before registering the progress bar's handler.");
278  0 return;
279    }
280  0 progressBarHandlers.put(id, handler);
281  0 JButton cancel = new JButton(
282    MessageManager.getString("action.cancel"));
283  0 cancel.addActionListener(new ActionListener()
284    {
285   
 
286  0 toggle @Override
287    public void actionPerformed(ActionEvent e)
288    {
289  0 handler.cancelActivity(id);
290  0 us.setProgressBar(MessageManager
291    .formatMessage("label.cancelled_params", new Object[]
292    { ((JLabel) progressPanel.getComponent(0)).getText() }),
293    id);
294    }
295    });
296  0 progressPanel.add(cancel, BorderLayout.EAST);
297   
298  0 updateCancelHandler(progressPanel, handler);
299    }
300    });
301    }
 
302  0 toggle protected void updateCancelHandler(Container progressPanel, IProgressIndicatorHandler handler)
303    {
304  0 for (Component j:progressPanel.getComponents())
305    {
306  0 if (j instanceof JButton)
307    {
308  0 j.setEnabled(handler.canCancel());
309    }
310    }
311  0 refreshLayout();
312    }
313   
314    /*
315    *
316    */
 
317  0 toggle @Override
318    public JProgressBar getProgressBar(long id)
319    {
320  0 Container progBar = progressBars.get(id);
321  0 if (progBar == null || progBar.getComponentCount() == 0)
322    {
323  0 return null;
324    }
325  0 for (Component component : progBar.getComponents())
326    {
327  0 if (component.getClass().equals(JProgressBar.class))
328    {
329  0 return (JProgressBar) component;
330    }
331    }
332  0 return null;
333    }
334   
 
335  0 toggle @Override
336    public String getMessage(long id)
337    {
338  0 return progressBarMessages.get(id);
339    }
340   
341    /**
342    * change the text shown alongside a progress bar
343    * @param id
344    * @param message
345    */
 
346  0 toggle @Override
347    public void setProgressBarMessage(long id,String message)
348    {
349  0 Container progBar = progressBars.get(id);
350  0 if (progBar == null || progBar.getComponentCount() == 0)
351    {
352  0 return;
353    }
354  0 for (Component component : progBar.getComponents())
355    {
356  0 if (component.getClass().equals(JLabel.class))
357    {
358  0 ((JLabel) component).setText(message);
359  0 IProgressIndicatorHandler handler = progressBarHandlers.get(id);
360  0 if (handler!=null) {
361    // show/hide cancel on message change
362  0 updateCancelHandler(progBar, handler);
363    } else {
364  0 refreshLayout();
365    }
366    }
367    }
368    }
369   
370    }