001 /* 002 * Copyright (C) 2008-2010 by Holger Arndt 003 * 004 * This file is part of the Universal Java Matrix Package (UJMP). 005 * See the NOTICE file distributed with this work for additional 006 * information regarding copyright ownership and licensing. 007 * 008 * UJMP is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation; either version 2 011 * of the License, or (at your option) any later version. 012 * 013 * UJMP is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public 019 * License along with UJMP; if not, write to the 020 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 021 * Boston, MA 02110-1301 USA 022 */ 023 024 package org.ujmp.gui.util; 025 026 import java.awt.Component; 027 import java.awt.Cursor; 028 import java.util.Collections; 029 import java.util.HashSet; 030 import java.util.LinkedList; 031 import java.util.List; 032 import java.util.Set; 033 import java.util.concurrent.LinkedBlockingQueue; 034 import java.util.concurrent.ThreadFactory; 035 import java.util.concurrent.ThreadPoolExecutor; 036 import java.util.concurrent.TimeUnit; 037 import java.util.concurrent.atomic.AtomicInteger; 038 import java.util.logging.Level; 039 import java.util.logging.Logger; 040 041 import javax.swing.JComponent; 042 import javax.swing.JFrame; 043 044 import org.ujmp.gui.interfaces.CanBeRepainted; 045 046 public class GraphicsExecutor { 047 048 private static final int count = Runtime.getRuntime().availableProcessors(); 049 050 private static final List<Executor> executors = new LinkedList<Executor>(); 051 052 public static synchronized void shutDown() { 053 for (Executor ex : executors) { 054 try { 055 ex.shutdownNow(); 056 } catch (Exception e) { 057 } 058 } 059 executors.clear(); 060 } 061 062 public static synchronized final void scheduleUpdate( 063 CanBeRepainted component) { 064 while (executors.size() < Runtime.getRuntime().availableProcessors()) { 065 Executor executor = new Executor(); 066 executors.add(executor); 067 } 068 069 Component c = (Component) component; 070 while (c != null && !(c instanceof JFrame)) { 071 c = c.getParent(); 072 } 073 if (c != null && c.isVisible()) { 074 Executor executor = getExecutor(component); 075 executor.sheduleUpdate(component); 076 } 077 } 078 079 private static Executor getExecutor(CanBeRepainted component) { 080 return executors.get(Math.abs(component.hashCode()) % count); 081 } 082 083 public static final void setFinished(CanBeRepainted component) { 084 executors.get(component.hashCode() % count).setFinished(component); 085 } 086 087 } 088 089 class UpdateTask implements Runnable { 090 091 private static final Logger logger = Logger.getLogger(UpdateTask.class 092 .getName()); 093 094 private CanBeRepainted component = null; 095 096 public UpdateTask(CanBeRepainted component) { 097 this.component = component; 098 if (component == null) { 099 System.out.println("null component"); 100 } 101 } 102 103 public void run() { 104 try { 105 GraphicsExecutor.setFinished(component); 106 ((JComponent) component).setCursor(Cursor 107 .getPredefinedCursor(Cursor.WAIT_CURSOR)); 108 component.repaintUI(); 109 ((JComponent) component).setCursor(Cursor.getDefaultCursor()); 110 ((JComponent) component).repaint(1); 111 112 } catch (Exception e) { 113 logger.log(Level.WARNING, "could not repaint ui", e); 114 } 115 } 116 117 } 118 119 class Executor extends ThreadPoolExecutor { 120 121 private static final LowPriorityThreadFactory factory = new LowPriorityThreadFactory(); 122 123 private final Set<CanBeRepainted> waitingTasks = Collections 124 .synchronizedSet(new HashSet<CanBeRepainted>()); 125 126 public Executor() { 127 super(1, 1, 0L, TimeUnit.MILLISECONDS, 128 new LinkedBlockingQueue<Runnable>(), factory); 129 } 130 131 public void setFinished(CanBeRepainted component) { 132 waitingTasks.remove(component); 133 } 134 135 public void sheduleUpdate(CanBeRepainted component) { 136 if (!waitingTasks.contains(component)) { 137 // System.out.println("schedule update: " + component); 138 waitingTasks.add(component); 139 UpdateTask task = new UpdateTask(component); 140 submit(task); 141 } 142 } 143 } 144 145 class LowPriorityThreadFactory implements ThreadFactory { 146 static final AtomicInteger poolNumber = new AtomicInteger(1); 147 148 final ThreadGroup group; 149 150 final AtomicInteger threadNumber = new AtomicInteger(1); 151 152 final String namePrefix; 153 154 public LowPriorityThreadFactory() { 155 SecurityManager s = System.getSecurityManager(); 156 group = (s != null) ? s.getThreadGroup() : Thread.currentThread() 157 .getThreadGroup(); 158 namePrefix = "GraphicsExecutorPool-"; 159 } 160 161 public Thread newThread(Runnable r) { 162 Thread t = new Thread(group, r, namePrefix 163 + threadNumber.getAndIncrement(), 0); 164 t.setDaemon(true); 165 t.setPriority(Thread.MIN_PRIORITY); 166 return t; 167 } 168 }