Clover icon

Coverage Report

  1. Project Clover database Mon Sep 2 2024 17:57:51 BST
  2. Package jalview.gui

File ProgressBar.java

 

Coverage histogram

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

Code metrics

32
77
14
1
333
205
34
0.44
5.5
14
2.43

Classes

Class Line # Actions
ProgressBar 46 77 34
0.512195151.2%
 

Contributing tests

This file is covered by 175 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  430 toggle public ProgressBar(JPanel container, JLabel statusBar)
83    {
84  430 if (container == null)
85    {
86  1 throw new NullPointerException();
87    }
88  429 if (!GridLayout.class
89    .isAssignableFrom(container.getLayout().getClass()))
90    {
91  1 throw new IllegalArgumentException("Container must have GridLayout");
92    }
93  428 this.statusPanel = container;
94  428 this.statusBar = statusBar;
95  428 this.progressBars = new Hashtable<>();
96  428 this.progressBarHandlers = new Hashtable<>();
97  428 this.progressBarMessages = new Hashtable<>();
98   
99    }
100   
101    /**
102    * Returns true if any progress bars are still active
103    *
104    * @return
105    */
 
106  15 toggle @Override
107    public boolean operationInProgress()
108    {
109  15 if (progressBars != null && progressBars.size() > 0)
110    {
111  5 return true;
112    }
113  10 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  355 toggle @Override
126    public void setProgressBar(final String message, final long id)
127    {
128  355 SwingUtilities.invokeLater(new Runnable()
129    {
 
130  354 toggle @Override
131    public void run()
132    {
133  354 JPanel progressPanel = progressBars.get(id);
134  354 if (progressPanel != null)
135    {
136    /*
137    * Progress bar is displayed for this id - remove it now, and any handler
138    */
139  177 progressBars.remove(id);
140  177 if (message != null && statusBar != null)
141    {
142  17 statusBar.setText(message);
143    }
144  177 if (progressBarHandlers.containsKey(id))
145    {
146  0 progressBarHandlers.remove(id);
147    }
148  177 removeRow(progressPanel);
149    }
150    else
151    {
152    /*
153    * No progress bar for this id - add one now
154    */
155  177 progressPanel = new JPanel(new BorderLayout(10, 5));
156   
157  177 JProgressBar progressBar = new JProgressBar();
158  177 progressBar.setIndeterminate(true);
159   
160  177 progressPanel.add(new JLabel(message==null ? "" : message), BorderLayout.WEST);
161  177 progressPanel.add(progressBar, BorderLayout.CENTER);
162   
163  177 addRow(progressPanel);
164   
165  177 progressBars.put(id, progressPanel);
166  177 progressBarMessages.put(id, message == null ? "" : message);
167    }
168   
169  354 refreshLayout();
170    }
171    });
172   
173    }
174   
175    /**
176    * Lays out progress bar container hierarchy
177    */
 
178  354 toggle protected void refreshLayout()
179    {
180    /*
181    * lay out progress bar container hierarchy
182    */
183  354 Component root = SwingUtilities.getRoot(statusPanel);
184  354 if (root != null)
185    {
186  303 root.validate();
187    }
188    }
189   
190    /**
191    * Remove one row with a progress bar, in a thread-safe manner
192    *
193    * @param progressPanel
194    */
 
195  177 toggle protected void removeRow(JPanel progressPanel)
196    {
197  177 synchronized (statusPanel)
198    {
199  177 statusPanel.remove(progressPanel);
200  177 GridLayout layout = (GridLayout) statusPanel.getLayout();
201  177 layout.setRows(layout.getRows() - 1);
202  177 statusPanel.remove(progressPanel);
203    }
204    }
205   
206    /**
207    * Add one row with a progress bar, in a thread-safe manner
208    *
209    * @param progressPanel
210    */
 
211  177 toggle protected void addRow(JPanel progressPanel)
212    {
213  177 synchronized (statusPanel)
214    {
215  177 GridLayout layout = (GridLayout) statusPanel.getLayout();
216  177 layout.setRows(layout.getRows() + 1);
217  177 statusPanel.add(progressPanel);
218    }
219    }
220   
221    /**
222    * Add a 'Cancel' handler for the given progress bar id. This should be called
223    * _after_ setProgressBar to have any effect.
224    */
 
225  0 toggle @Override
226    public void registerHandler(final long id,
227    final IProgressIndicatorHandler handler)
228    {
229  0 final IProgressIndicator us = this;
230   
231  0 SwingUtilities.invokeLater(new Runnable()
232    {
 
233  0 toggle @Override
234    public void run()
235    {
236  0 final JPanel progressPanel = progressBars.get(id);
237  0 if (progressPanel == null)
238    {
239  0 jalview.bin.Console.errPrintln(
240    "call setProgressBar before registering the progress bar's handler.");
241  0 return;
242    }
243  0 progressBarHandlers.put(id, handler);
244  0 JButton cancel = new JButton(
245    MessageManager.getString("action.cancel"));
246  0 cancel.addActionListener(new ActionListener()
247    {
248   
 
249  0 toggle @Override
250    public void actionPerformed(ActionEvent e)
251    {
252  0 handler.cancelActivity(id);
253  0 us.setProgressBar(MessageManager
254    .formatMessage("label.cancelled_params", new Object[]
255    { ((JLabel) progressPanel.getComponent(0)).getText() }),
256    id);
257    }
258    });
259  0 progressPanel.add(cancel, BorderLayout.EAST);
260   
261  0 updateCancelHandler(progressPanel, handler);
262    }
263    });
264    }
 
265  0 toggle protected void updateCancelHandler(Container progressPanel, IProgressIndicatorHandler handler)
266    {
267  0 for (Component j:progressPanel.getComponents())
268    {
269  0 if (j instanceof JButton)
270    {
271  0 j.setEnabled(handler.canCancel());
272    }
273    }
274  0 refreshLayout();
275    }
276   
277    /*
278    *
279    */
 
280  0 toggle @Override
281    public JProgressBar getProgressBar(long id)
282    {
283  0 Container progBar = progressBars.get(id);
284  0 if (progBar == null || progBar.getComponentCount() == 0)
285    {
286  0 return null;
287    }
288  0 for (Component component : progBar.getComponents())
289    {
290  0 if (component.getClass().equals(JProgressBar.class))
291    {
292  0 return (JProgressBar) component;
293    }
294    }
295  0 return null;
296    }
297   
 
298  0 toggle @Override
299    public String getMessage(long id)
300    {
301  0 return progressBarMessages.get(id);
302    }
303   
304    /**
305    * change the text shown alongside a progress bar
306    * @param id
307    * @param message
308    */
 
309  0 toggle @Override
310    public void setProgressBarMessage(long id,String message)
311    {
312  0 Container progBar = progressBars.get(id);
313  0 if (progBar == null || progBar.getComponentCount() == 0)
314    {
315  0 return;
316    }
317  0 for (Component component : progBar.getComponents())
318    {
319  0 if (component.getClass().equals(JLabel.class))
320    {
321  0 ((JLabel) component).setText(message);
322  0 IProgressIndicatorHandler handler = progressBarHandlers.get(id);
323  0 if (handler!=null) {
324    // show/hide cancel on message change
325  0 updateCancelHandler(progBar, handler);
326    } else {
327  0 refreshLayout();
328    }
329    }
330    }
331    }
332   
333    }