source: main/trunk/gli/src/org/greenstone/gatherer/download/DownloadProgressBar.java@ 31720

Last change on this file since 31720 was 31720, checked in by ak19, 7 years ago
  1. GLI's DownloadJobs don't allow pausing and resuming (the button used to work, but didn't ever pause/resume in the background, at least it's been stopping the wget download activity after wget related changes from some years back). Changing the Pause/Resume button in the DownloadProgressBar to the Stop/Stopped button. 2. Added another useful link on InterruptedException to SafeProgress and its documentation.
  • Property svn:keywords set to Author Date Id Revision
File size: 14.4 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.download;
38
39import java.awt.*;
40import java.awt.event.*;
41import javax.swing.*;
42import javax.swing.border.*;
43import org.greenstone.gatherer.Dictionary;
44import org.greenstone.gatherer.Gatherer;
45//import org.greenstone.gatherer.collection.DownloadJob;
46import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
47import org.greenstone.gatherer.util.Utility;
48import org.greenstone.gatherer.gui.*;
49
50public class DownloadProgressBar
51 extends JPanel
52 implements ActionListener {
53
54 private boolean simple = false;
55
56 private Dimension bar_size = new Dimension(520, 25);
57
58 private Dimension MINIMUM_BUTTON_SIZE = new Dimension(100, 25);
59 private Dimension PROGRESS_BAR_SIZE = new Dimension(580,75);
60
61 private int current_action;
62 private int err_count;
63 private int file_count;
64 private int total_count;
65 private int warning_count;
66
67 private JLabel current_status;
68 private JLabel main_status;
69 private JLabel results_status;
70
71 private JPanel center_pane;
72 private JPanel inner_pane;
73
74 private JProgressBar progress;
75
76 private long file_size;
77 private long total_size;
78
79 private String current_url;
80 private String initial_url;
81
82 private DownloadJob owner;
83
84 public JButton stop_start_button;
85 public JButton log_button;
86 public JButton close_button;
87
88 public DownloadProgressBar(DownloadJob owner, String initial_url, boolean simple) {
89 this.owner = owner;
90 this.current_url = null;
91 this.err_count = 0;
92 this.initial_url = initial_url;
93 this.file_count = 0;
94 this.file_size = 0;
95 this.simple = simple;
96 this.total_count = 0;
97 this.total_size = 0;
98 this.warning_count = 0;
99
100 this.setLayout(new BorderLayout());
101 this.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
102
103 this.current_action = DownloadJob.STOPPED;
104
105 inner_pane = new JPanel(new BorderLayout());
106 inner_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
107
108 center_pane = new JPanel(new GridLayout(3,1));
109
110 main_status = new JLabel();
111
112 current_status = new JLabel();
113
114 results_status = new JLabel();
115
116 progress = new JProgressBar();
117 progress.setStringPainted(true);
118 progress.setMinimum(0);
119 progress.setMaximum(0);
120 progress.setEnabled(false);
121 progress.setString(Dictionary.get("Mirroring.DownloadJob.Waiting"));
122 inner_pane.add(progress, BorderLayout.CENTER);
123
124 center_pane.add(main_status);
125 center_pane.add(current_status);
126 center_pane.add(results_status);
127
128 JPanel button_pane = new JPanel();
129
130 // our "pause" button never paused before, it always did a process.destroy() on being pressed.
131 // See http://trac.greenstone.org/browser/trunk/gli/src/org/greenstone/gatherer/download/DownloadJob.java?rev=13594
132 // However, now we additionally ensure that the wget launched by the perl is stopped before
133 // process.destroy(), so at least it cleans up better. I'm therefore changing it to a "Stop" button.
134 stop_start_button = new GLIButton(Dictionary.get("Mirroring.DownloadJob.Stop"),Dictionary.get("Mirroring.DownloadJob.Stop_Tooltip"));
135 stop_start_button.addActionListener(this);
136 stop_start_button.addActionListener(owner);
137 stop_start_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
138 stop_start_button.setMnemonic(KeyEvent.VK_P);
139 stop_start_button.setEnabled(true);
140
141
142 log_button = new GLIButton(Dictionary.get("Mirroring.DownloadJob.Log"),Dictionary.get("Mirroring.DownloadJob.Log_Tooltip"));
143 log_button.addActionListener(owner);
144 log_button.addActionListener(this);
145 log_button.setEnabled(false);
146 log_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
147 log_button.setMnemonic(KeyEvent.VK_L);
148
149
150 close_button = new GLIButton(Dictionary.get("Mirroring.DownloadJob.Close"),Dictionary.get("Mirroring.DownloadJob.Close_Tooltip"));
151 close_button.addActionListener(owner);
152 close_button.addActionListener(this);
153 close_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
154 close_button.setMnemonic(KeyEvent.VK_C);
155 close_button.setEnabled(true);
156
157
158 // Layout - or at least some of it
159
160 inner_pane.add(center_pane, BorderLayout.NORTH);
161
162 button_pane.setLayout(new GridLayout(3,1));
163 button_pane.add(stop_start_button);
164 button_pane.add(log_button);
165 button_pane.add(close_button);
166
167 this.add(inner_pane, BorderLayout.CENTER);
168 this.add(button_pane, BorderLayout.EAST);
169
170 // Make the labels, etc update.
171 refresh();
172 }
173
174 // internally thread-safe
175 public void enableCancelJob(boolean isEnabled) {
176 synchronized(stop_start_button) {
177 stop_start_button.setEnabled(isEnabled);
178 }
179 synchronized(stop_start_button) {
180 close_button.setEnabled(isEnabled);
181 }
182 }
183
184 public void actionPerformed(ActionEvent event) {
185 Object source = event.getSource();
186 if(source == stop_start_button) {
187 // If we are running, stop.
188 if (current_action == DownloadJob.RUNNING) {
189 current_action = DownloadJob.STOPPED;
190 stop_start_button.setText(Dictionary.get("Mirroring.DownloadJob.Stopped"));
191 stop_start_button.setToolTipText(Dictionary.get("Mirroring.DownloadJob.Stopped_Tooltip"));
192
193 progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Stopped"));
194 progress.setIndeterminate(false);
195 stop_start_button.setEnabled(false);
196 }
197 }
198 else if(source == close_button) {
199 // If we are running, stop.
200 if (current_action == DownloadJob.RUNNING) {
201 current_action = DownloadJob.STOPPED;
202 progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Stopped"));
203
204 progress.setIndeterminate(false);
205 }
206 }
207 else if(source == log_button) {
208
209 LogDialog dialog = new LogDialog(owner.getLogDocument());
210 dialog.setVisible(true);
211 dialog = null;
212 }
213
214 refresh();
215 }
216
217 /** This method is called when a new download is begun. The
218 * details of the download are updated and a new JProgressBar
219 * assigned to track the download.
220 * @param url The url String of the file that is being downloaded.
221 */
222 public synchronized void addDownload(String url) {
223 current_url = url;
224 file_size = 0;
225 refresh();
226 }
227
228 /** When the download of the current url is completed, this method
229 * is called to enlighten the DownloadProgressBar of this fact.
230 */
231 public synchronized void downloadComplete() {
232 current_url = null;
233 file_count++;
234 if(total_count < (file_count + err_count + warning_count)) {
235 total_count = (file_count + err_count + warning_count);
236 }
237 progress.setValue(progress.getMaximum());
238 //Dictionary.setText(progress, "Mirroring.DownloadJob.Download_Complete");
239 refresh();
240 }
241
242 public synchronized void downloadFailed() {
243 err_count++;
244 if(total_count < (file_count + err_count + warning_count)) {
245 total_count = (file_count + err_count + warning_count);
246 }
247 refresh();
248 }
249
250 public synchronized void downloadWarning() {
251 warning_count++;
252 if(total_count < (file_count + err_count + warning_count)) {
253 total_count = (file_count + err_count + warning_count);
254 }
255 refresh();
256 }
257
258 // need to make these methods synchronized too, as they modify variables
259 // that other synchronized methods work with. And if any methods that modify
260 // such variables were to remain unsynchronized, can end up with race conditions
261 // http://stackoverflow.com/questions/574240/is-there-an-advantage-to-use-a-synchronized-method-instead-of-a-synchronized-blo
262 // "Not only do synchronized methods not lock the whole class, but they don't lock the whole instance either. Unsynchronized methods in the class may still proceed on the instance."
263 // "Only the syncronized methods are locked. If there are fields you use within synced methods that are accessed by unsynced methods, you can run into race conditions."
264 public synchronized void setTotalDownload(int total_download) {
265 total_count = total_download;
266 refresh();
267 }
268
269 public Dimension getPreferredSize() {
270 return PROGRESS_BAR_SIZE;
271 }
272
273 public synchronized void increaseFileCount() {
274 file_count++;
275 refresh();
276 }
277
278 public synchronized void increaseFileCount(int amount) {
279 file_count += amount;
280 refresh();
281 }
282
283 public synchronized void resetFileCount() {
284 file_count = 0;
285 refresh();
286 }
287
288 /** When a mirroring task is first initiated this function is called
289 * to set initial values for the variables if necessary and to
290 * fiddle visual components such as the tool tip etc.
291 * @param reset A Boolean specifying whether the variables should be
292 * reset to zero.
293 */
294 public synchronized void mirrorBegun(boolean reset, boolean simple) {
295 if(reset) {
296 this.file_count = 0;
297 this.file_size = 0;
298 this.total_count = 0;
299 this.total_size = 0;
300 this.err_count = 0;
301 this.warning_count = 0;
302 }
303 current_action = DownloadJob.RUNNING;
304 stop_start_button.setEnabled(true);
305 log_button.setEnabled(true);
306 if(simple) {
307 progress.setIndeterminate(true);
308 progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Progress"));
309 }
310 }
311
312 /** Once a mirroring task is complete, if the DownloadJob returns from the
313 * native call but the status is still running, then this method
314 * is called to once again tinker with the pretty visual
315 * components.
316 */
317 public synchronized void mirrorComplete() {
318 current_action = DownloadJob.COMPLETE;
319 current_url = null;
320 if(simple) {
321 progress.setIndeterminate(false);
322 }
323 progress.setValue(progress.getMaximum());
324 progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Complete"));
325 current_status.setText(Dictionary.get("Mirroring.DownloadJob.Download_Complete"));
326 // will display "Download Complete" once an OAI download session has finished running
327
328 stop_start_button.setEnabled(false);
329 this.updateUI();
330 }
331
332 /** When called this method updates the DownloadProgressBar to reflect
333 * the amount of the current file downloaded.
334 */
335 public synchronized void updateProgress(long current, long expected) {
336 file_size = file_size + current;
337 if(!progress.isIndeterminate()) {
338 // If current is zero, then this is the 'precall' before the
339 // downloading actually starts.
340 if(current == 0) {
341 // Remove the old progress bar, then deallocate it.
342 inner_pane.remove(progress);
343 progress = null;
344 if(expected == 0) {
345 // We don't have a content length. This bar will go from 0 to 100 only!
346 progress = new JProgressBar(0, 100);
347 }
348 else {
349 // Assign a new progress bar of length expected content length.
350 progress = new JProgressBar(0, (new Long(expected)).intValue());
351 }
352 progress.setEnabled(true);
353 // Add the new progress bar.
354 inner_pane.add(progress, BorderLayout.CENTER);
355 inner_pane.updateUI();
356 }
357 // Otherwise if expected is not zero move the progress bar and
358 // update percent complete.
359 else if (expected != 0) {
360 progress.setValue((new Long(file_size)).intValue());
361 int p_c = (new Double(progress.getPercentComplete() * 100)).intValue();
362 progress.setString(p_c + "%");
363 progress.setStringPainted(true);
364 }
365 // Finally, in the case we have no content length, we'll instead
366 // write the current number of bytes downloaded again.
367 else {
368 progress.setString(file_size + " b");
369 progress.setStringPainted(true);
370 }
371 }
372 refresh();
373 }
374
375 /** Causes the two labels associated with this DownloadProgressBar object to
376 * update, thus reflecting the progression of the download. This
377 * method is called by any of the other public setter methods in this
378 * class.
379 */
380 private void refresh() {
381 // Refresh the contents of main label.
382 String args1[] = new String[1];
383 args1[0] = initial_url.toString();
384 main_status.setText(Dictionary.get("Mirroring.DownloadJob.Downloading", args1));
385
386 if (current_url != null) {
387 // Refresh the current label contents.
388 String args2[] = new String[1];
389 args2[0] = current_url;
390 current_status.setText(Dictionary.get("Mirroring.DownloadJob.Downloading", args2));
391 }
392 else if (current_action == DownloadJob.STOPPED || current_action == DownloadJob.PAUSED) {
393 current_status.setText(Dictionary.get("Mirroring.DownloadJob.Waiting_User"));
394 }
395 else {
396 current_status.setText(Dictionary.get("Mirroring.DownloadJob.Download_Complete"));
397 }
398
399 // Refresh the contents of results label
400 String args3[] = new String[4];
401 args3[0] = file_count + "";
402 args3[1] = total_count + "";
403 args3[2] = warning_count + "";
404 args3[3] = err_count + "";
405 results_status.setText(Dictionary.get("Mirroring.DownloadJob.Status", args3));
406
407 this.updateUI();
408 }
409
410 static final private Dimension DIALOG_SIZE = new Dimension(640,480);
411
412 private class LogDialog
413 extends JDialog {
414
415 public LogDialog(AppendLineOnlyFileDocument document) {
416 super(Gatherer.g_man, Dictionary.get("Mirroring.DownloadJob.Log_Title"));
417 setSize(DIALOG_SIZE);
418 JPanel content_pane = (JPanel) getContentPane();
419 JTextArea text_area = new JTextArea(document);
420 JButton button = new GLIButton(Dictionary.get("General.Close"));
421 // Connection
422 button.addActionListener(new CloseActionListener());
423 // Layout
424 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
425 content_pane.setLayout(new BorderLayout());
426 content_pane.add(new JScrollPane(text_area), BorderLayout.CENTER);
427 content_pane.add(button, BorderLayout.SOUTH);
428 }
429
430 private class CloseActionListener
431 implements ActionListener {
432 public void actionPerformed(ActionEvent event) {
433 LogDialog.this.dispose();
434 }
435 }
436 }
437}
Note: See TracBrowser for help on using the repository browser.