/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
*
* This library 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.1 of the License, or (at your option) any later version.
* <p/>
* This library 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.
*/
package furbelow;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.swing.CellRendererPane;
import javax.swing.Icon;
import javax.swing.JList;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
/** Provide animation of auto-generated animations. Makes use of the repaint
* tracking structure established by {@link AnimatedIcon}.
*/
public abstract class AbstractAnimatedIcon extends AnimatedIcon {
private static final int DEFAULT_INTERVAL = 1000/24;
private Timer timer;
private int repaintInterval;
private int frame;
private int frameCount;
protected AbstractAnimatedIcon() {
this(0);
}
protected AbstractAnimatedIcon(int frameCount) {
this(frameCount, DEFAULT_INTERVAL);
}
protected AbstractAnimatedIcon(int frameCount, int interval) {
this.frameCount = frameCount;
setFrameInterval(interval);
}
/** Ensure the timer stops running, so it, too can be GC'd. */
protected void finalize() {
timer.stop();
}
/** Setting a frame interval of zero stops automatic animation. */
public void setFrameInterval(int interval) {
repaintInterval = interval;
if (interval != 0) {
if (timer == null) {
timer = new Timer(interval, new AnimationUpdater(this));
timer.setRepeats(true);
}
else {
timer.setDelay(interval);
}
}
else if (timer != null) {
timer.stop();
timer = null;
}
}
public int getFrameInterval() {
return repaintInterval;
}
/** Returns the total number of frames. */
public int getFrameCount() {
return frameCount;
}
/** Advance to the next animation frame. */
public void nextFrame() {
setFrame(getFrame() + 1);
}
/** Set the current animation frame number. */
public void setFrame(int f) {
this.frame = f;
if (frameCount != 0)
frame = frame % frameCount;
repaint();
}
/** Returns the current animation frame number. */
public int getFrame() {
return frame;
}
/** Implement this method to paint the icon. */
protected abstract void paintFrame(Component c, Graphics g, int x, int y);
public abstract int getIconWidth();
public abstract int getIconHeight();
protected synchronized void registerRepaintArea(Component c, int x, int y, int w, int h) {
if (timer != null && !timer.isRunning()) {
timer.start();
}
super.registerRepaintArea(c, x, y, w, h);
}
private static class AnimationUpdater implements ActionListener {
private WeakReference ref;
public AnimationUpdater(AbstractAnimatedIcon icon) {
this.ref = new WeakReference(icon);
}
public void actionPerformed(ActionEvent e) {
AbstractAnimatedIcon icon = (AbstractAnimatedIcon)ref.get();
if (icon != null) {
icon.nextFrame();
}
}
}
}