/*
* Copyright (C) 2008-2015 by Holger Arndt
*
* This file is part of the Universal Java Matrix Package (UJMP).
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* UJMP is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* UJMP 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with UJMP; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package org.ujmp.gui.util;
import java.awt.Component;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.JFrame;
import org.ujmp.gui.interfaces.CanBeRepainted;
public class GraphicsExecutor {
private static final int count = Runtime.getRuntime().availableProcessors();
private static final List<Executor> executors = new LinkedList<Executor>();
public static synchronized void shutDown() {
for (Executor ex : executors) {
try {
ex.shutdownNow();
} catch (Exception e) {
}
}
executors.clear();
}
public static synchronized final void scheduleUpdate(CanBeRepainted component) {
while (executors.size() < Runtime.getRuntime().availableProcessors()) {
Executor executor = new Executor();
executors.add(executor);
}
Component c = (Component) component;
while (c != null && !(c instanceof JFrame)) {
c = c.getParent();
}
if (c != null && c.isVisible()) {
Executor executor = getExecutor(component);
executor.sheduleUpdate(component);
}
}
private static Executor getExecutor(CanBeRepainted component) {
return executors.get(Math.abs(component.hashCode()) % count);
}
public static final void setFinished(CanBeRepainted component) {
executors.get(component.hashCode() % count).setFinished(component);
}
}
class UpdateTask implements Runnable {
private static final Logger logger = Logger.getLogger(UpdateTask.class.getName());
private CanBeRepainted component = null;
public UpdateTask(CanBeRepainted component) {
this.component = component;
if (component == null) {
System.out.println("null component");
}
}
public void run() {
try {
GraphicsExecutor.setFinished(component);
component.repaintUI();
((JComponent) component).repaint(500);
} catch (Exception e) {
logger.log(Level.WARNING, "could not repaint ui", e);
}
}
}
class Executor extends ThreadPoolExecutor {
private static final LowPriorityThreadFactory factory = new LowPriorityThreadFactory();
private final Set<CanBeRepainted> waitingTasks = Collections.synchronizedSet(new HashSet<CanBeRepainted>());
public Executor() {
super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
}
public void setFinished(CanBeRepainted component) {
waitingTasks.remove(component);
}
public void sheduleUpdate(CanBeRepainted component) {
if (!waitingTasks.contains(component)) {
waitingTasks.add(component);
UpdateTask task = new UpdateTask(component);
submit(task);
}
}
}
class LowPriorityThreadFactory implements ThreadFactory {
static final AtomicInteger poolNumber = new AtomicInteger(1);
final ThreadGroup group;
final AtomicInteger threadNumber = new AtomicInteger(1);
final String namePrefix;
public LowPriorityThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "UJMPGraphicsExecutorPool-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
t.setDaemon(true);
t.setPriority(Thread.MIN_PRIORITY);
return t;
}
}