/** * */ package org.korsakow.ide.task; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import org.korsakow.domain.task.ITask; import org.korsakow.domain.task.IWorker; import org.korsakow.ide.util.Util; import com.sun.swingx.SwingWorker; public class UIWorker extends SwingWorker<Void, String> implements IWorker, PropertyChangeListener { private volatile Throwable exception = null; private final List<ITask> tasks; public UIWorker() { tasks = new ArrayList<ITask>(); } public UIWorker(ITask task) { this(Util.list(ITask.class, task)); } public UIWorker(List<ITask> tasks) { this.tasks = new ArrayList<ITask>(tasks); // private copy } public void addTask(ITask newTask) { synchronized (tasks) { tasks.add(newTask); } } public void addTasks(List<ITask> newTasks) { synchronized (tasks) { tasks.addAll(newTasks); } } public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { getPropertyChangeSupport().addPropertyChangeListener(propertyName, listener); } protected synchronized void setException(Throwable t) { if (exception == null) exception = t; } public synchronized Throwable getException() { return exception; } @Override public void process(List<String> displayStrings) { System.out.println("Processing task: " + displayStrings.get(0)); } @Override public Void doInBackground() throws Exception { try { int total = 1; int index = 0; int count = 0; boolean done = false; setProgress(0); while (!done) { ITask task = null; synchronized (tasks) { total = tasks.size(); if (index < total) { task = tasks.get(index); ++index; } } if (task == null) { done = true; continue; } task.addPropertyChangeListener(ITask.PROPERTY_PROGRESS, this); task.addPropertyChangeListener(ITask.PROPERTY_DISPLAY_STRING, this); System.out.println("Task: " + task.getTitleString()); firePropertyChange("displayString", null, task.getTitleString()); Thread.sleep(70); // this is a completely unreliable way of giving the publish a chance to run try { task.run(); } catch (InterruptedException e) { done = true; } catch (TaskException e) { done = true; exception = e.getCause(); } task.removePropertyChangeListener(ITask.PROPERTY_DISPLAY_STRING, this); task.removePropertyChangeListener(ITask.PROPERTY_PROGRESS, this); synchronized (tasks) { // lame hack to account for some cases where one task adds more total = tasks.size(); } setProgress(100*++count/total); System.gc(); } } catch (Throwable t) { if (exception == null) exception = t; } return null; } @Override public void done() { } public void waitFor() throws ExecutionException, InterruptedException { get(); } public void propertyChange(PropertyChangeEvent event) { if (event.getPropertyName().equals(ITask.PROPERTY_PROGRESS)) { firePropertyChange(PROPERTY_SUB_PROGRESS, event.getOldValue(), event.getNewValue()); } else if (event.getPropertyName().equals(ITask.PROPERTY_DISPLAY_STRING)) { firePropertyChange(PROPERTY_SUB_DISPLAY_STRING, event.getOldValue(), event.getNewValue()); } } }