001: package net.xoetrope.awt;
002:
003: import java.io.Reader;
004: import java.util.Enumeration;
005: import java.util.StringTokenizer;
006: import java.util.Vector;
007:
008: import java.awt.Cursor;
009: import java.awt.Point;
010: import java.awt.Polygon;
011: import java.awt.event.MouseEvent;
012: import java.awt.event.MouseMotionListener;
013:
014: import net.xoetrope.xml.XmlElement;
015: import net.xoetrope.xml.XmlSource;
016: import java.util.Hashtable;
017:
018: /**
019: * <p>A widget for displaying an image and associating hotspots at
020: * coordinates specified in an external file</p>
021: * <p>Copyright: Copyright (c) Xoetrope Ltd., 1998-2003<br>
022: * License: see license.txt
023: * @version $Revision: 1.9 $
024: */
025: public class XHotspotImage extends XImage implements
026: MouseMotionListener {
027: protected static Cursor handCursor, defaultCursor;
028: protected Vector hotspots, images;
029: protected Vector names;
030: protected Hashtable disabled;
031:
032: /**
033: * Constructor. Sets cursors and creates the Vector which stores the hotspots.
034: * Adds a new MouseMotionListener to the image
035: */
036: public XHotspotImage() {
037: if (handCursor == null) {
038: handCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
039: defaultCursor = Cursor
040: .getPredefinedCursor(Cursor.DEFAULT_CURSOR);
041: }
042:
043: hotspots = new Vector();
044: images = new Vector();
045: addMouseMotionListener(this );
046: }
047:
048: /**
049: * Move the hotspot from the disabled Hashtable to the main Vector
050: * @param name
051: */
052: public void enableHotspot(String name) {
053: if (disabled != null) {
054: Object o = disabled.remove(name);
055: if (o != null) {
056: names.addElement(name);
057: hotspots.addElement(o);
058: hotspotEnabled(name);
059: }
060: }
061: }
062:
063: /**
064: * Convenience method to inform subclasses when a hotspot has been enabled
065: * @param name the name of the hotspot being enabled.
066: */
067: protected void hotspotEnabled(String name) {
068: }
069:
070: /**
071: * Create a hashtable to store the disabled hotspots and move the disabled
072: * one into it from the main Vector.
073: * @param name the name of the hotspot to be disabled
074: */
075: public void disableHotspot(String name) {
076: if (disabled == null)
077: disabled = new Hashtable();
078:
079: for (int i = 0; i < names.size(); i++) {
080: String temp = (String) names.elementAt(i);
081: if (temp.compareTo(name) == 0) {
082: Object key = names.elementAt(i);
083: Object hotspot = hotspots.elementAt(i);
084: hotspots.removeElementAt(i);
085: names.removeElementAt(i);
086: disabled.put(key, hotspot);
087: hotspotDisabled(name, i);
088: }
089: }
090: }
091:
092: /**
093: * Convenience method to inform subclasses when a hotspot has been disabled
094: * @param name the name of the hotspot being disabled.
095: * @param idx the index of the hotspot being disabled
096: */
097: protected void hotspotDisabled(String name, int idx) {
098: }
099:
100: /**
101: * Get the name of the hotspot in element i of the names vector
102: * @param i The index of the hotspot
103: * @return The Name of the hotspot
104: */
105: public String getName(int i) {
106: if (i != -1)
107: return (String) names.elementAt(i);
108: return null;
109: }
110:
111: /**
112: * Reads the hotspot information from the reader parameter and adds them to
113: * the names and hotspots vectors.
114: * @param r Reader of the file.
115: */
116: public void read(Reader r) {
117: names = new Vector();
118: hotspots = new Vector();
119: XmlElement element = XmlSource.read(r);
120: if ((element == null) || (element.getChildren() == null))
121: return;
122:
123: Enumeration e = element.getChildren().elements();
124: while (e.hasMoreElements()) {
125: XmlElement ele = (XmlElement) e.nextElement();
126: Object name = ele.getAttribute("name");
127: Object image = ele.getAttribute("image");
128: if (name == null)
129: names.addElement("");
130: else
131: names.addElement(ele.getAttribute("name").toString());
132: addHotspot(ele.getAttribute("coords").toString(),
133: image == null ? "" : image.toString());
134: handleElement(ele);
135: }
136: }
137:
138: protected void handleElement(XmlElement ele) {
139:
140: }
141:
142: private int getNextTokenAsInt(StringTokenizer tokenizer) {
143: String s = tokenizer.nextToken().trim();
144: return Integer.parseInt(s);
145: }
146:
147: /**
148: * Creates a polygon and iterates the coordinates in the pts paramater adding
149: * each to the polygon. Adds the polygon to the hotspots Vector
150: * @param pts String containing the points pairs of the polygon.
151: */
152: private void addHotspot(String pts, String image) {
153: Polygon p = new Polygon();
154: StringTokenizer tokenizer = new StringTokenizer(pts, ",");
155: int x0 = getNextTokenAsInt(tokenizer);
156: int y0 = getNextTokenAsInt(tokenizer);
157: p.addPoint(x0, y0);
158:
159: int x, y;
160: while (tokenizer.hasMoreTokens()) {
161: x = getNextTokenAsInt(tokenizer);
162: y = getNextTokenAsInt(tokenizer);
163: p.addPoint(x, y);
164: }
165:
166: // Close the polygon
167: p.addPoint(x0, y0);
168: hotspots.addElement(p);
169: images.addElement(image);
170: }
171:
172: /**
173: * Check the Point p to see if any of the polygons in the hotspots Vector contain
174: * it. If so return the index of the Vector element.
175: * @param p The Point which we are checking
176: * @return The index of the polygon which contains the point or -1 if none of
177: * the polygons contain the Point
178: */
179: public int checkHotspot(Point p) {
180: int numPolygons = hotspots.size();
181: for (int i = 0; i < numPolygons; i++) {
182: Polygon poly = (Polygon) hotspots.elementAt(i);
183:
184: if (poly.contains(p)) {
185: setCursor(handCursor);
186: return i;
187: }
188: }
189: setCursor(defaultCursor);
190: return -1;
191: }
192:
193: /**
194: * Call the checkHotSpot function to change the cursor
195: * @param e MouseEvent
196: */
197: public void mouseMoved(MouseEvent e) {
198: checkHotspot(e.getPoint());
199: }
200:
201: /**
202: * Unused method.
203: * @param e
204: */
205: public void mouseDragged(MouseEvent e) {
206: }
207: }
|