package net.xoetrope.swing;
import java.io.Reader;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.XmlSource;
/**
* <p>A widget for displaying an image and associating hotspots at
* coordinates specified in an external file</p>
* <p>Copyright: Copyright (c) Xoetrope Ltd., 1998-2003<br>
* License: see license.txt
* @version 1.0
*/
public class XHotspotImage extends XImage implements MouseMotionListener
{
/**
* The default pointer - the hand cursor
*/
protected static Cursor handCursor;
/**
* The default cursor
*/
protected static Cursor defaultCursor;
/**
* The hotspots
*/
protected Vector hotspots;
/**
* The hotspot names
*/
protected Vector names;
/**
* Constructor. Sets cursors and creates the Vector which stores the hotspots.
* Adds a new MouseMotionListener to the image
*/
public XHotspotImage()
{
if ( handCursor == null ) {
handCursor = Cursor.getPredefinedCursor( Cursor.HAND_CURSOR );
defaultCursor = Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR );
}
hotspots = new Vector();
addMouseMotionListener( this );
}
/**
* Get the name of the hotspot in element i of the names vector
* @param i The index of the hotspot
* @return The Name of the hotspot
*/
public String getName( int i )
{
if ( i != -1 )
return ( String )names.elementAt( i );
return null;
}
/**
* Reads the hotspot information from the reader parameter and adds them to
* the names and hotspots vectors.
* @param r Reader of the file.
*/
public void read( Reader r )
{
names = new Vector();
hotspots = new Vector();
XmlElement element = XmlSource.read( r );
Enumeration e = element.getChildren().elements();
while ( e.hasMoreElements() ) {
XmlElement ele = ( XmlElement )e.nextElement();
if ( ele.getName().compareTo( "area" ) == 0 ) {
Object name = ele.getAttribute( "name" );
if (name == null)
names.addElement("");
else
names.addElement( ele.getAttribute( "name" ));
addHotspot( ele.getAttribute( "coords" ));
}
else
addCustomHotspot( ele );
}
}
/**
* Add a hotspot which is not defined as an 'area'
* @param ele the xml element containg the definition of the hotspot.
*/
protected void addCustomHotspot( XmlElement ele )
{
}
/**
* Parses the next element of a tokenised string into an integer
* @param tokenizer the tokenised string
* @return the parsed token
*/
private int getNextTokenAsInt( StringTokenizer tokenizer )
{
String s = tokenizer.nextToken().trim();
return Integer.parseInt( s );
}
/**
* Creates a polygon and iterates the coordinates in the pts paramater adding
* each to the polygon. Adds the polygon to the hotspots Vector
* @param pts String containing the points pairs of the polygon.
*/
private void addHotspot( String pts )
{
Polygon p = new Polygon();
StringTokenizer tokenizer = new StringTokenizer( pts, "," );
int x0 = getNextTokenAsInt( tokenizer );
int y0 = getNextTokenAsInt( tokenizer );
p.addPoint( x0, y0 );
int x, y;
while ( tokenizer.hasMoreTokens() ) {
x = getNextTokenAsInt( tokenizer );
y = getNextTokenAsInt( tokenizer );
p.addPoint( x, y );
}
// Close the polygon
p.addPoint( x0, y0 );
hotspots.addElement( p );
}
/**
* Check the Point p to see if any of the polygons in the hotspots Vector contain
* it. If so return the index of the Vector element.
* @param p The Point which we are checking
* @return The index of the polygon which contains the point or -1 if none of
* the polygons contain the Point
*/
public int checkHotspot( Point p )
{
int numPolygons = hotspots.size();
for ( int i = 0; i < numPolygons; i++ ) {
Polygon poly = ( Polygon )hotspots.elementAt( i );
if ( poly.contains( p ) ) {
setCursor( handCursor );
return i;
}
}
setCursor( defaultCursor );
return -1;
}
/**
* Call the checkHotSpot function to change the cursor
* @param e MouseEvent
*/
public void mouseMoved( MouseEvent e )
{
checkHotspot( e.getPoint() );
}
/**
* Unused method.
* @param e -
*/
public void mouseDragged( MouseEvent e )
{
}
}