/**
*#########################################################################
*
* A component of the Gatherer application, part of the Greenstone digital
* library suite from the New Zealand Digital Library Project at the
* University of Waikato, New Zealand.
*
*
*
* Author: John Thompson, Greenstone Digital Library, University of Waikato
*
*
*
* Copyright (C) 1999 New Zealand Digital Library Project
*
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*########################################################################
*/
package org.greenstone.gatherer.download;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import org.greenstone.gatherer.*;
/** This class provides access to the functionality of the WGet program, either by calling it via a shell script or by the JNI. It maintains a queue of pending jobs, and the component for showing these tasks to the user.
* @author John Thompson, Greenstone Digital Library, University of Waikato
* @version 2.3
*/
public class DownloadScrollPane
extends Thread {
/** true if verbose debug messages should be displayed, false otherwise. */
private boolean debug = false;
/** true if successfully completed tasks should be automatically removed from the job queue. */
private boolean remove_complete_jobs = true;
private JPanel filler_pane = null;
/** The panel that the task list will be shown in. */
private JPanel list_pane;
/** The job currently underway. */
private DownloadJob job;
/** A scroll pane which will be used to display the list of pending tasks. */
private JScrollPane list_scroll;
/** A queue of download tasks. */
private Vector job_queue;
static final private boolean simple = true;
public DownloadScrollPane() {
job = null;
job_queue = new Vector();
filler_pane = new JPanel();
list_pane = new JPanel();
list_pane.setLayout(new BoxLayout(list_pane, BoxLayout.Y_AXIS));
list_scroll = new JScrollPane(list_pane);
}
public void deleteDownloadJob(DownloadJob delete_me) {
if (delete_me == job) {
try {
// Wait for the job to finish cleaning up, before we can continue cleaning up here.
// But sometimes the job has completed (terminated naturally) and in that case there's
// nothing to wait for.
synchronized(delete_me) {
if (!delete_me.hasSignalledStop()) { // don't wait if DownloadJob.COMPLETED
delete_me.wait();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Close button pressed, get rid of this download's dedicated pane
finishedDownloadJob(delete_me, true);
}
/** To be called when a download job has terminated naturally or was prematurely stopped
* via the close button.
* Gets rid of this download's pane with buttons and progress bar if prematurely stopped. */
protected void finishedDownloadJob(DownloadJob delete_me, boolean removeDisplay) {
if (delete_me.hasSignalledStop()) {
if(removeDisplay) {
list_pane.remove(delete_me.getProgressBar());
list_pane.remove(filler_pane);
}
job_queue.remove(delete_me);
if(job_queue.size() > 0) {
Dimension progress_bar_size = delete_me.getProgressBar().getPreferredSize();
Dimension list_pane_size = list_pane.getSize();
int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);
progress_bar_size = null;
if(height > 0) {
filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
list_pane.add(filler_pane);
}
list_pane_size = null;
}
list_pane.updateUI();
}
else {
DebugStream.println("Somehow we're trying to delete a job that is still running.");
}
}
public synchronized void downloadComplete() {
job.downloadComplete();
}
public synchronized void downloadFailed() {
job.downloadFailed();
}
public synchronized void downloadWarning() {
job.downloadWarning();
}
public JScrollPane getDownloadJobList() {
return list_scroll;
}
public synchronized boolean hasSignalledStop() {
return job.hasSignalledStop();
}
public void newDownloadJob(Download download, String mode, String proxy_url) {
// Create the job and fill in the details from gatherer.config.
DebugStream.println("About to create a new job");
DownloadJob new_job = new DownloadJob(download, Configuration.proxy_pass, Configuration.proxy_user, this, mode, proxy_url);
// Tell it to run as soon as possible
new_job.setState(DownloadJob.RUNNING);
// Add to job_queue job list.
job_queue.add(new_job);
// Now add it to the visual component, job list.
list_pane.remove(filler_pane);
Dimension progress_bar_size = new_job.getProgressBar().getPreferredSize();
Dimension list_pane_size = list_pane.getSize();
int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);
progress_bar_size = null;
list_pane.add(new_job.getProgressBar());
if(height > 0) {
filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
list_pane.add(filler_pane);
}
list_pane_size = null;
//list_pane.setAlignmentX(Component.LEFT_ALIGNMENT);
list_pane.updateUI();
new_job = null; //job = (DownloadJob) job_queue.get(index);
synchronized(this) {
notify(); // Just incase its sleeping.
}
}
public synchronized void updateProgress(long current, long expected) {
job.updateProgress(current, expected);
}
/* There may be times when the download thread is sleeping, but the
* user has indicated that a previously paused job should now begin
* again. The flag within the job will change, so we tell the thread
* to start again.
*/
public void resumeThread() {
synchronized(this) {
notify(); // Just incase its sleeping.
}
}
public void run() {
while(true) {
if(job_queue.size() > 0) {
while(!job_queue.isEmpty()) {
job = (DownloadJob) job_queue.firstElement();
if(job.getState() == DownloadJob.RUNNING) {
DownloadJob delete_me = job;
String jobDisplayString = job.toString();
DebugStream.println("DownloadJob " + jobDisplayString + " Begun.");
System.err.println("DownloadJob " + job.port + " " + job.toString() + " Begun.");
job.callDownload();
// Job is done. Ended naturally, don't get rid of this download's separate display panel
finishedDownloadJob(delete_me, false);
System.err.println("DownloadJob " + jobDisplayString + " complete.");
DebugStream.println("DownloadJob " + jobDisplayString + " complete."); // by this point job is null!
job = null;
delete_me = null;
}
}
try {
synchronized(this) {
DebugStream.println("WGet thread is waiting for DownloadJobs.");
wait();
}
} catch (InterruptedException e) {
// Time to get going again.
}
}
else {
try {
synchronized(this) {
DebugStream.println("WGet thread is waiting for DownloadJobs.");
wait();
}
} catch (InterruptedException e) {
// Time to get going again.
}
}
}
}
}