home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 November
/
Chip_1998-11_cd.bin
/
tema
/
Cafe
/
Source.bin
/
Animator.java
< prev
next >
Wrap
Text File
|
1998-03-18
|
17KB
|
640 lines
package symantec.itools.multimedia;
import java.awt.Graphics;
import java.awt.MediaTracker;
import java.awt.Canvas;
import java.awt.Image;
import java.awt.Dimension;
import java.net.URL;
import java.util.Vector;
import java.util.Enumeration;
import java.beans.PropertyVetoException;
import java.beans.PropertyChangeListener;
import java.beans.VetoableChangeListener;
import java.beans.PropertyChangeEvent;
// 01/29/97 TWB Integrated changes from Windows
// 05/30/97 RKM Changed symantec.beans references to java.beans
// Moved AnimatorImage class into its own file as the compiler suggested
// 05/31/97 RKM Updated to support Java 1.1
// Made properties bound & constrained
// 07/15/97 CAR marked fields transient as needed
// modified addImage to call the AnimatorImage constructor which takes a Component reference
// 08/27/97 CAR setting repeatMode from false to true will re-start the animation
/**
* This is a simple animation component. <br>
* It creates an animation by displaying a series of images in sequence.
* The programmer can specify the delay between frames in milliseconds.
* The animation can loop for a specific
* number of iterations or can run forever.
*
* @version 1.0, Nov 26, 1996
* @author Symantec
*/
public class Animator extends Canvas implements Runnable, PropertyChangeListener
{
/**
* Constructs a default Animator. The animator defaults to a 500 millisecond delay, and loops forever.
*/
public Animator()
{
delay = 500;
numLoops = 1;
forever = true;
images = new Vector();
currentImage = null;
clearFrame = false;
previewMode = false;
maxWidth = 0;
maxHeight = 0;
vetos = new symantec.itools.beans.VetoableChangeSupport(this);
changes = new symantec.itools.beans.PropertyChangeSupport(this);
changes.addPropertyChangeListener(this);
}
//
// Properties
//
/**
* Sets the delay between animation frames.
* @param i animation delay, in milliseconds
* @see #getDelay
* @exception PropertyVetoException
* if the specified property value is unacceptable
*/
public void setDelay(int newDelay)
throws PropertyVetoException
{
if (delay != newDelay)
{
Integer oldDelayInt = new Integer(delay);
Integer newDelayInt = new Integer(newDelay);
vetos.fireVetoableChange("Delay", oldDelayInt, newDelayInt);
delay = newDelay;
changes.firePropertyChange("Delay", oldDelayInt, newDelayInt);
}
}
/**
* Returns the current delay between animation frames.
* @return current animation delay, in milliseconds
* @see #setDelay
*/
public int getDelay()
{
return delay;
}
/**
* Sets the number of loops to perform when displaying
* the animation set.
* @param i loop count
* @see #getNumLoops
* @exception PropertyVetoException
* if the specified property value is unacceptable
*/
public void setNumLoops(int newNumLoops)
throws PropertyVetoException
{
if (numLoops != newNumLoops)
{
Integer oldNumLoopsInt = new Integer(numLoops);
Integer newNumLoopsInt = new Integer(newNumLoops);
vetos.fireVetoableChange("NumLoops", oldNumLoopsInt, newNumLoopsInt);
numLoops = newNumLoops;
changes.firePropertyChange("NumLoops", oldNumLoopsInt, newNumLoopsInt);
}
}
/**
* Returns the current animation set loop count.
* @return loop count
* @see #setNumLoops
*/
public int getNumLoops()
{
return numLoops;
}
/**
* Sets the repeat mode setting.
* @param b repeat mode, repeats if true
* @see #getRepeatMode
* @exception PropertyVetoException
* if the specified property value is unacceptable
*/
public void setRepeatMode(boolean newRepeatMode)
throws PropertyVetoException
{
if (forever != newRepeatMode)
{
Boolean oldRepeatModeBool = new Boolean(forever);
Boolean newRepeatModeLoopsBool = new Boolean(newRepeatMode);
vetos.fireVetoableChange("RepeatMode", oldRepeatModeBool, newRepeatModeLoopsBool);
forever = newRepeatMode;
changes.firePropertyChange("RepeatMode", oldRepeatModeBool, newRepeatModeLoopsBool);
}
}
/**
* @deprecated
* @see #isRepeatMode
*/
public boolean getRepeatMode()
{
return isRepeatMode();
}
/**
* Returns the current repeat mode setting.
* @return current repeat mode setting, true if repeat forever
* @see #setRepeatMode
*/
public boolean isRepeatMode()
{
return forever;
}
/**
* Sets the image list. Images in this list are displayed in
* sequence to form the animation.
* @param list array of image URLs
* @see #getImageList
* @exception PropertyVetoException
* if the specified property value is unacceptable
*/
public synchronized void setImageList(URL[] newImageList)
throws PropertyVetoException
{
//???RKM??? I'm not comparing the two lists here, should I?
boolean wasAnimating = (displayThread != null);
if (wasAnimating)
stopAnimation();
URL[] oldImageList = getImageList();
vetos.fireVetoableChange("ImageList", oldImageList, newImageList);
currentImage = null;
images = new Vector();
for (int i = 0; i < newImageList.length; ++i)
addImage(newImageList[i]);
changes.firePropertyChange("ImageList", oldImageList, newImageList);
if (wasAnimating || previewMode || !java.beans.Beans.isDesignTime())
{
startAnimation();
}
else if (newImageList.length > 0)
{
currentImage = ((AnimatorImage)images.elementAt(0)).image;
}
repaint();
}
/**
* Returns the image list.
* @return URL list of images
* @see #setImageList
*/
public synchronized URL[] getImageList()
{
URL[] list = new URL[images.size()];
int i = 0;
Enumeration enum = images.elements();
while (enum.hasMoreElements())
{
list[i++] = ((AnimatorImage)enum.nextElement()).url;
}
return list;
}
/**
* Sets whether or not the animation frame area is cleared
* between each frame.
* @param newClearFrame if true, the frame area is cleared between each
* animation frame; if false, the frame area is not cleared.
* @see #getClearFrame
* @exception PropertyVetoException
* if the specified property value is unacceptable
*/
public void setClearFrame(boolean newClearFrame)
throws PropertyVetoException
{
if (clearFrame = newClearFrame)
{
Boolean oldClearFrameBool = new Boolean(clearFrame);
Boolean newClearFrameBool = new Boolean(newClearFrame);
vetos.fireVetoableChange("ClearFrame", oldClearFrameBool, newClearFrameBool);
clearFrame = newClearFrame;
changes.firePropertyChange("ClearFrame", oldClearFrameBool, newClearFrameBool);
}
}
/**
* @deprecated
* @see #isClearFrame
*/
public boolean getClearFrame()
{
return isClearFrame();
}
/**
* Gets the current clear frame setting.
* @return boolean - if true, the frame area is cleared
* between each animation frame; if false, the frame area
* is not cleared.
* @see #setClearFrame
*/
public boolean isClearFrame()
{
return clearFrame;
}
/**
* Sets the preview mode flag. This flag is used by Visual Cafe to
* determine if this component should be run during design time.
* @param newPreviewMode new preview mode
* @see #getPreviewMode
*/
public void setPreviewMode(boolean newPreviewMode)
{
if (previewMode != newPreviewMode)
{
if (java.beans.Beans.isDesignTime())
{
previewMode = newPreviewMode;
if (previewMode && (images.size() > 0))
startAnimation();
else
stopAnimation();
}
}
}
/**
* @deprecated
* @see #setPreviewMode
*/
public boolean getPreviewMode()
{
return isPreviewMode();
}
/**
* Gets the preview mode flag. This flag is used by Visual Cafe to
* determine if this component should be run during design time.
* @see #setPreviewMode
*/
public boolean isPreviewMode()
{
return previewMode;
}
//
// Methods
//
/**
* Adds an image to the animation set.
* @param url URL of the image to add
*/
public synchronized void addImage(URL url)
{
Image image = getToolkit().getImage(url);
boolean loadWait = images.size() == 0 || previewMode || !java.beans.Beans.isDesignTime();
if (loadWait)
{
imageLoadWait(image);
}
images.addElement(new AnimatorImage(url, image, loadWait, this));
}
/**
* Starts the animation.
* @see #stopAnimation
*/
public void startAnimation()
{
if (displayThread == null)
{
displayThread = new Thread(this);
displayThread.start();
}
else
{
try {
displayThread.join();
} catch (InterruptedException e) {}
displayThread = new Thread(this);
displayThread.start();
}
}
/**
* Stops the animation.
* @see #startAnimation
*/
public void stopAnimation()
{
if (displayThread != null)
{
displayThread.stop();
displayThread = null;
}
}
/**
* Body of Animation Thread. This method is called by the Java Virtual Machine
* in response to a call to the start method of this object.
*/
public synchronized void run()
{
for (int i = 0; i < numLoops || forever; ++i)
{
if (images.size() == 0)
{
try
{
wait(delay);
}
catch(InterruptedException e)
{
}
}
else
{
for (int j = 0; j < images.size(); ++j)
{
synchronized(this)
{
try
{
wait(delay);
}
catch(InterruptedException e)
{
}
AnimatorImage ai = (AnimatorImage)images.elementAt(j);
if (!ai.loaded)
{
imageLoadWait(ai.image);
images.setElementAt(new AnimatorImage(ai.url, ai.image, true), j);
}
currentImage = ai.image;
}
repaint();
}
}
}
}
/**
* Paints this component using the given graphics context.
* This is a standard Java AWT method which typically gets called
* by the AWT to handle painting this component. It paints this component
* using the given graphics context. The graphics context clipping region
* is set to the bounding rectangle of this component and its <0,0>
* coordinate is this component's top-left corner.
*
* @param g the graphics context used for painting
* @see java.awt.Component#repaint
* @see #update
*/
public synchronized void paint(Graphics g)
{
if (currentImage != null)
g.drawImage(currentImage, 0, 0, this);
}
/**
* Handles redrawing of this component on the screen.
* This is a standard Java AWT method which gets called by the Java
* AWT (repaint()) to handle repainting this component on the screen.
* The graphics context clipping region is set to the bounding rectangle
* of this component and its <0,0> coordinate is this component's
* top-left corner.
* Typically this method paints the background color to clear the
* component's drawing space, sets graphics context to be the foreground
* color, and then calls paint() to draw the component.
*
* It is overridden here to make clearing the background before painting
* optional. If the clearFrame flag is true the background will be erased
* before painting begins.
*
* @param g the graphics context
* @see java.awt.Component#repaint
* @see #paint
*/
public void update(Graphics g)
{
if (clearFrame)
super.update(g);
else
paint(g);
}
/**
* Returns the recommended dimensions to properly display this component.
* This is a standard Java AWT method which gets called to determine
* the recommended size of this component.
*
* @return If no images have been loaded, a dimension of 10 by 10 is returned.
* If one or more images have been loaded, the largest height and the
* largest width of any image is returned.
*
* @see #minimumSize
*/
public Dimension preferredSize()
{
if (images == null || images.size() == 0)
return new Dimension(10, 10);
return new Dimension(maxWidth, maxHeight);
}
/**
* Returns the minimum dimensions to properly display this component.
* This is a standard Java AWT method which gets called to determine
* the minimum size of this component.
*
* @return If no images have been loaded, a dimension of 10 by 10 is returned.
* If one or more images have been loaded, the largest height and the
* largest width of any image is returned.
*
* @see #preferredSize
*/
public Dimension minimumSize()
{
return preferredSize();
}
/**
* A method of the PropertyChangeListener interface.
* This method is called when a property of this component changes.
* It starts the animation when the Repeat Mode property is set.
* @param the event
* @see java.awt.PropertyChangeListener
*/
public void propertyChange(PropertyChangeEvent evt)
{
String property = evt.getPropertyName();
if(property != null) {
if(property.equalsIgnoreCase("RepeatMode")) {
startAnimation();
}
}
}
/**
* Adds a listener for all event changes.
* @param PropertyChangeListener listener the listener to add.
* @see #removePropertyChangeListener
*/
public void addPropertyChangeListener(PropertyChangeListener listener)
{
changes.addPropertyChangeListener(listener);
}
/**
* Removes a listener for all event changes.
* @param PropertyChangeListener listener the listener to remove.
* @see #addPropertyChangeListener
*/
public void removePropertyChangeListener(PropertyChangeListener listener)
{
changes.removePropertyChangeListener(listener);
}
/**
* Adds a vetoable listener for all event changes.
* @param VetoableChangeListener listener the listener to add.
* @see #removeVetoableChangeListener
*/
public void addVetoableChangeListener(VetoableChangeListener listener)
{
vetos.addVetoableChangeListener(listener);
}
/**
* Removes a vetoable listener for all event changes.
* @param VetoableChangeListener listener the listener to remove.
* @see #addVetoableChangeListener
*/
public void removeVetoableChangeListener(VetoableChangeListener listener)
{
vetos.removeVetoableChangeListener(listener);
}
void imageLoadWait(Image image)
{
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(image, 0);
try
{
tracker.waitForAll();
}
catch(InterruptedException e)
{
}
int size;
if ((size = image.getWidth(this)) > maxWidth)
maxWidth = size;
if ((size = image.getHeight(this)) > maxHeight)
maxHeight = size;
}
/**
* Delay time between images, in milliseconds.
*/
protected int delay;
/**
* Number of times to show the animation sequence.
*/
protected int numLoops;
/**
* Run animation forever. If false, use numLoops.
*/
protected boolean forever;
/**
* Images to be displayed.
*/
protected Vector images;
/**
* Image currently being shown.
*/
transient protected Image currentImage;
/**
* Thread which runs the animation.
*/
transient protected Thread displayThread;
/**
* Dimension of largest image in sequence.
*/
protected int maxWidth, maxHeight;
/**
* Clear frame between each image.
*/
protected boolean clearFrame;
/**
* Preview this component at design time.
*/
protected boolean previewMode;
// Private members
private symantec.itools.beans.VetoableChangeSupport vetos;
private symantec.itools.beans.PropertyChangeSupport changes;
}