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    }