/** *######################################################################### * * 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. } } } } }