1 7 package javax.swing; 8 9 import java.beans.PropertyChangeListener ; 10 import java.beans.PropertyChangeSupport ; 11 import java.beans.PropertyChangeEvent ; 12 import java.util.List ; 13 import java.util.ArrayList ; 14 import java.util.Collections ; 15 16 import java.util.concurrent.*; 17 import java.util.concurrent.locks.*; 18 19 import java.awt.event.*; 20 21 import javax.swing.SwingUtilities ; 22 23 import sun.awt.AppContext; 24 import sun.swing.AccumulativeRunnable; 25 26 208 public abstract class SwingWorker<T, V> implements RunnableFuture<T> { 209 212 private static final int MAX_WORKER_THREADS = 10; 213 214 217 private volatile int progress; 218 219 222 private volatile StateValue state; 223 224 228 private final FutureTask<T> future; 229 230 233 private final PropertyChangeSupport propertyChangeSupport; 234 235 238 private AccumulativeRunnable<V> doProcess; 239 240 243 private AccumulativeRunnable<Integer > doNotifyProgressChange; 244 245 private final AccumulativeRunnable<Runnable > doSubmit = getDoSubmit(); 246 247 251 public enum StateValue { 252 255 PENDING, 256 260 STARTED, 261 262 267 DONE 268 }; 269 270 273 public SwingWorker() { 274 Callable<T> callable = 275 new Callable<T>() { 276 public T call() throws Exception { 277 setState(StateValue.STARTED); 278 return doInBackground(); 279 } 280 }; 281 282 future = new FutureTask<T>(callable) { 283 @Override  284 protected void done() { 285 doneEDT(); 286 setState(StateValue.DONE); 287 } 288 }; 289 290 state = StateValue.PENDING; 291 propertyChangeSupport = new SwingWorkerPropertyChangeSupport(this); 292 doProcess = null; 293 doNotifyProgressChange = null; 294 } 295 296 310 protected abstract T doInBackground() throws Exception ; 311 312 316 public final void run() { 317 future.run(); 318 } 319 320 389 protected final void publish(V... chunks) { 390 synchronized (this) { 391 if (doProcess == null) { 392 doProcess = new AccumulativeRunnable<V>() { 393 @Override  394 public void run(List <V> args) { 395 process(args); 396 } 397 @Override  398 protected void submit() { 399 doSubmit.add(this); 400 } 401 }; 402 } 403 } 404 doProcess.add(chunks); 405 } 406 407 419 protected void process(List <V> chunks) { 420 } 421 422 434 protected void done() { 435 } 436 437 464 protected final void setProgress(int progress) { 465 if (progress < 0 || progress > 100) { 466 throw new IllegalArgumentException ("the value should be from 0 to 100"); 467 } 468 if (this.progress == progress) { 469 return; 470 } 471 int oldProgress = this.progress; 472 this.progress = progress; 473 if (! getPropertyChangeSupport().hasListeners("progress")) { 474 return; 475 } 476 synchronized (this) { 477 if (doNotifyProgressChange == null) { 478 doNotifyProgressChange = 479 new AccumulativeRunnable<Integer >() { 480 @Override  481 public void run(List <Integer > args) { 482 firePropertyChange("progress", 483 args.get(0), 484 args.get(args.size() - 1)); 485 } 486 @Override  487 protected void submit() { 488 doSubmit.add(this); 489 } 490 }; 491 } 492 } 493 doNotifyProgressChange.add(oldProgress, progress); 494 } 495 496 501 public final int getProgress() { 502 return progress; 503 } 504 505 518 public final void execute() { 519 getWorkersExecutorService().execute(this); 520 } 521 522 526 public final boolean cancel(boolean mayInterruptIfRunning) { 527 return future.cancel(mayInterruptIfRunning); 528 } 529 530 533 public final boolean isCancelled() { 534 return future.isCancelled(); 535 } 536 537 540 public final boolean isDone() { 541 return future.isDone(); 542 } 543 544 582 public final T get() throws InterruptedException , ExecutionException { 583 return future.get(); 584 } 585 586 591 public final T get(long timeout, TimeUnit unit) throws InterruptedException , 592 ExecutionException, TimeoutException { 593 return future.get(timeout, unit); 594 } 595 596 598 611 public final void addPropertyChangeListener(PropertyChangeListener listener) { 612 getPropertyChangeSupport().addPropertyChangeListener(listener); 613 } 614 615 629 public final void removePropertyChangeListener(PropertyChangeListener listener) { 630 getPropertyChangeSupport().removePropertyChangeListener(listener); 631 } 632 633 655 public final void firePropertyChange(String propertyName, Object oldValue, 656 Object newValue) { 657 getPropertyChangeSupport().firePropertyChange(propertyName, 658 oldValue, newValue); 659 } 660 661 678 public final PropertyChangeSupport getPropertyChangeSupport() { 679 return propertyChangeSupport; 680 } 681 682 684 689 public final StateValue getState() { 690 694 if (isDone()) { 695 return StateValue.DONE; 696 } else { 697 return state; 698 } 699 } 700 701 705 private void setState(StateValue state) { 706 StateValue old = this.state; 707 this.state = state; 708 firePropertyChange("state", old, state); 709 } 710 711 714 private void doneEDT() { 715 Runnable doDone = 716 new Runnable () { 717 public void run() { 718 done(); 719 } 720 }; 721 if (SwingUtilities.isEventDispatchThread()) { 722 doDone.run(); 723 } else { 724 doSubmit.add(doDone); 725 } 726 } 727 728 729 739 private static synchronized ExecutorService getWorkersExecutorService() { 740 final AppContext appContext = AppContext.getAppContext(); 741 Object obj = appContext.get(SwingWorker .class); 742 if (obj == null) { 743 ThreadFactory threadFactory = 745 new ThreadFactory() { 746 final ThreadFactory defaultFactory = 747 Executors.defaultThreadFactory(); 748 public Thread newThread(final Runnable r) { 749 Thread thread = 750 defaultFactory.newThread(r); 751 thread.setName("SwingWorker-" 752 + thread.getName()); 753 return thread; 754 } 755 }; 756 757 764 obj = new ThreadPoolExecutor(0, MAX_WORKER_THREADS, 765 1L, TimeUnit.SECONDS, 766 new LinkedBlockingQueue<Runnable >(), 767 threadFactory) { 768 769 private final ReentrantLock pauseLock = new ReentrantLock(); 770 private final Condition unpaused = pauseLock.newCondition(); 771 private boolean isPaused = false; 772 private final ReentrantLock executeLock = new ReentrantLock(); 773 774 @Override  775 public void execute(Runnable command) { 776 799 800 executeLock.lock(); 802 try { 803 804 pauseLock.lock(); 805 try { 806 isPaused = true; 807 } finally { 808 pauseLock.unlock(); 809 } 810 811 setCorePoolSize(MAX_WORKER_THREADS); 812 super.execute(command); 813 setCorePoolSize(0); 814 815 pauseLock.lock(); 816 try { 817 isPaused = false; 818 unpaused.signalAll(); 819 } finally { 820 pauseLock.unlock(); 821 } 822 } finally { 823 executeLock.unlock(); 824 } 825 } 826 @Override 827 protected void afterExecute(Runnable r, Throwable t) { 828 super.afterExecute(r, t); 829 pauseLock.lock(); 830 try { 831 while(isPaused) { 832 unpaused.await(); 833 } 834 } catch(InterruptedException ignore) { 835 836 } finally { 837 pauseLock.unlock(); 838 } 839 } 840 }; 841 appContext.put(SwingWorker .class, obj); 842 } 843 return (ExecutorService)obj; 844 } 845 846 private static final Object DO_SUBMIT_KEY = new StringBuilder ("doSubmit"); 847 private static AccumulativeRunnable<Runnable > getDoSubmit() { 848 synchronized (DO_SUBMIT_KEY) { 849 final AppContext appContext = AppContext.getAppContext(); 850 Object doSubmit = appContext.get(DO_SUBMIT_KEY); 851 if (doSubmit == null) { 852 doSubmit = new DoSubmitAccumulativeRunnable(); 853 appContext.put(DO_SUBMIT_KEY, doSubmit); 854 } 855 return (AccumulativeRunnable<Runnable >) doSubmit; 856 } 857 } 858 private static class DoSubmitAccumulativeRunnable 859 extends AccumulativeRunnable<Runnable > implements ActionListener { 860 private final static int DELAY = (int) (1000 / 30); 861 @Override  862 protected void run(List <Runnable > args) { 863 for (Runnable runnable : args) { 864 runnable.run(); 865 } 866 } 867 @Override  868 protected void submit() { 869 Timer timer = new Timer (DELAY, this); 870 timer.setRepeats(false); 871 timer.start(); 872 } 873 public void actionPerformed(ActionEvent event) { 874 run(); 875 } 876 } 877 878 private class SwingWorkerPropertyChangeSupport 879 extends PropertyChangeSupport { 880 SwingWorkerPropertyChangeSupport(Object source) { 881 super(source); 882 } 883 @Override  884 public void firePropertyChange(final PropertyChangeEvent evt) { 885 if (SwingUtilities.isEventDispatchThread()) { 886 super.firePropertyChange(evt); 887 } else { 888 doSubmit.add( 889 new Runnable () { 890 public void run() { 891 SwingWorkerPropertyChangeSupport.this 892 .firePropertyChange(evt); 893 } 894 }); 895 } 896 } 897 } 898 } 899
| Popular Tags
|