001: package abbot.editor.widgets;
002:
003: import java.awt.Component;
004: import java.awt.Graphics;
005: import java.awt.event.ActionEvent;
006: import java.awt.event.ActionListener;
007: import java.lang.ref.WeakReference;
008: import javax.swing.Timer;
009:
010: /** Provide animation of auto-generated animations. Makes use of the repaint
011: * tracking structure established by {@link AnimatedIcon}.
012: */
013: public abstract class AbstractAnimatedIcon extends AnimatedIcon {
014: private static final int DEFAULT_INTERVAL = 1000 / 24;
015:
016: private Timer timer;
017: private int repaintInterval;
018: private int frame;
019: private int frameCount;
020:
021: protected AbstractAnimatedIcon() {
022: this (0);
023: }
024:
025: protected AbstractAnimatedIcon(int frameCount) {
026: this (frameCount, DEFAULT_INTERVAL);
027: }
028:
029: protected AbstractAnimatedIcon(int frameCount, int interval) {
030: this .frameCount = frameCount;
031: setFrameInterval(interval);
032: }
033:
034: /** Ensure the timer stops running, so it, too can be GC'd. */
035: protected void finalize() {
036: timer.stop();
037: }
038:
039: /** Setting a frame interval of zero stops automatic animation. */
040: public void setFrameInterval(int interval) {
041: repaintInterval = interval;
042: if (interval != 0) {
043: if (timer == null) {
044: timer = new Timer(interval, new AnimationUpdater(this ));
045: timer.setRepeats(true);
046: } else {
047: timer.setDelay(interval);
048: }
049: } else if (timer != null) {
050: timer.stop();
051: timer = null;
052: }
053: }
054:
055: public int getFrameInterval() {
056: return repaintInterval;
057: }
058:
059: /** Returns the total number of frames. */
060: public int getFrameCount() {
061: return frameCount;
062: }
063:
064: /** Advance to the next animation frame. */
065: public void nextFrame() {
066: setFrame(getFrame() + 1);
067: }
068:
069: /** Set the current animation frame number. */
070: public void setFrame(int f) {
071: this .frame = f;
072: if (frameCount != 0)
073: frame = frame % frameCount;
074: repaint();
075: }
076:
077: /** Returns the current animation frame number. */
078: public int getFrame() {
079: return frame;
080: }
081:
082: /** Implement this method to paint the icon. */
083: protected abstract void paintFrame(Component c, Graphics g, int x,
084: int y);
085:
086: public abstract int getIconWidth();
087:
088: public abstract int getIconHeight();
089:
090: protected synchronized void registerRepaintArea(Component c, int x,
091: int y, int w, int h) {
092: if (timer != null && !timer.isRunning()) {
093: timer.start();
094: }
095: super .registerRepaintArea(c, x, y, w, h);
096: }
097:
098: private static class AnimationUpdater implements ActionListener {
099: private WeakReference ref;
100:
101: public AnimationUpdater(AbstractAnimatedIcon icon) {
102: this .ref = new WeakReference(icon);
103: }
104:
105: public void actionPerformed(ActionEvent e) {
106: AbstractAnimatedIcon icon = (AbstractAnimatedIcon) ref
107: .get();
108: if (icon != null) {
109: icon.nextFrame();
110: }
111: }
112: }
113: }
|