KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > html > Map


1 /*
2  * @(#)Map.java 1.8 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.text.html;
8
9 import java.awt.Polygon JavaDoc;
10 import java.awt.Rectangle JavaDoc;
11 import java.util.StringTokenizer JavaDoc;
12 import java.util.Vector JavaDoc;
13 import javax.swing.text.AttributeSet JavaDoc;
14
15 /**
16  * Map is used to represent a map element that is part of an HTML document.
17  * Once a Map has been created, and any number of areas have been added,
18  * you can test if a point falls inside the map via the contains method.
19  *
20  * @author Scott Violet
21  * @version 1.8 12/19/03
22  */

23 class Map {
24     /** Name of the Map. */
25     private String JavaDoc name;
26     /** An array of AttributeSets. */
27     private Vector JavaDoc areaAttributes;
28     /** An array of RegionContainments, will slowly grow to match the
29      * length of areaAttributes as needed. */

30     private Vector JavaDoc areas;
31
32     public Map() {
33     }
34
35     public Map(String JavaDoc name) {
36     this.name = name;
37     }
38
39     /**
40      * Returns the name of the Map.
41      */

42     public String JavaDoc getName() {
43     return name;
44     }
45
46     /**
47      * Defines a region of the Map, based on the passed in AttributeSet.
48      */

49     public void addArea(AttributeSet JavaDoc as) {
50     if (as == null) {
51         return;
52     }
53     if (areaAttributes == null) {
54         areaAttributes = new Vector JavaDoc(2);
55     }
56     areaAttributes.addElement(as.copyAttributes());
57     }
58
59     /**
60      * Removes the previously created area.
61      */

62     public void removeArea(AttributeSet JavaDoc as) {
63     if (as != null && areaAttributes != null) {
64         int numAreas = (areas != null) ? areas.size() : 0;
65         for (int counter = areaAttributes.size() - 1; counter >= 0;
66          counter--) {
67         if (((AttributeSet JavaDoc)areaAttributes.elementAt(counter)).
68             isEqual(as)){
69             areaAttributes.removeElementAt(counter);
70             if (counter < numAreas) {
71             areas.removeElementAt(counter);
72             }
73         }
74         }
75     }
76     }
77
78     /**
79      * Returns the AttributeSets representing the differet areas of the Map.
80      */

81     public AttributeSet JavaDoc[] getAreas() {
82     int numAttributes = (areaAttributes != null) ? areaAttributes.size() :
83                         0;
84     if (numAttributes != 0) {
85         AttributeSet JavaDoc[] retValue = new AttributeSet JavaDoc[numAttributes];
86
87         areaAttributes.copyInto(retValue);
88         return retValue;
89     }
90     return null;
91     }
92
93     /**
94      * Returns the AttributeSet that contains the passed in location,
95      * <code>x</code>, <code>y</code>. <code>width</code>, <code>height</code>
96      * gives the size of the region the map is defined over. If a matching
97      * area is found, the AttribueSet for it is returned.
98      */

99     public AttributeSet JavaDoc getArea(int x, int y, int width, int height) {
100     int numAttributes = (areaAttributes != null) ?
101                              areaAttributes.size() : 0;
102
103     if (numAttributes > 0) {
104         int numAreas = (areas != null) ? areas.size() : 0;
105
106         if (areas == null) {
107         areas = new Vector JavaDoc(numAttributes);
108         }
109         for (int counter = 0; counter < numAttributes; counter++) {
110         if (counter >= numAreas) {
111             areas.addElement(createRegionContainment
112                 ((AttributeSet JavaDoc)areaAttributes.elementAt(counter)));
113         }
114         RegionContainment rc = (RegionContainment)areas.
115                                              elementAt(counter);
116         if (rc != null && rc.contains(x, y, width, height)) {
117             return (AttributeSet JavaDoc)areaAttributes.elementAt(counter);
118         }
119         }
120     }
121     return null;
122     }
123
124     /**
125      * Creates and returns an instance of RegionContainment that can be
126      * used to test if a particular point lies inside a region.
127      */

128     protected RegionContainment createRegionContainment
129                               (AttributeSet JavaDoc attributes) {
130     Object JavaDoc shape = attributes.getAttribute(HTML.Attribute.SHAPE);
131
132     if (shape == null) {
133         shape = "rect";
134     }
135     if (shape instanceof String JavaDoc) {
136         String JavaDoc shapeString = ((String JavaDoc)shape).toLowerCase();
137         RegionContainment rc = null;
138
139         try {
140         if (shapeString.equals("rect")) {
141             rc = new RectangleRegionContainment(attributes);
142         }
143         else if (shapeString.equals("circle")) {
144             rc = new CircleRegionContainment(attributes);
145         }
146         else if (shapeString.equals("poly")) {
147             rc = new PolygonRegionContainment(attributes);
148         }
149         else if (shapeString.equals("default")) {
150             rc = DefaultRegionContainment.sharedInstance();
151         }
152         } catch (RuntimeException JavaDoc re) {
153         // Something wrong with attributes.
154
rc = null;
155         }
156         return rc;
157     }
158     return null;
159     }
160
161     /**
162      * Creates and returns an array of integers from the String
163      * <code>stringCoords</code>. If one of the values represents a
164      * % the returned value with be negative. If a parse error results
165      * from trying to parse one of the numbers null is returned.
166      */

167     static protected int[] extractCoords(Object JavaDoc stringCoords) {
168     if (stringCoords == null || !(stringCoords instanceof String JavaDoc)) {
169         return null;
170     }
171
172     StringTokenizer JavaDoc st = new StringTokenizer JavaDoc((String JavaDoc)stringCoords,
173                             ", \t\n\r");
174     int[] retValue = null;
175     int numCoords = 0;
176
177     while(st.hasMoreElements()) {
178         String JavaDoc token = st.nextToken();
179         int scale;
180
181         if (token.endsWith("%")) {
182         scale = -1;
183         token = token.substring(0, token.length() - 1);
184         }
185         else {
186         scale = 1;
187         }
188         try {
189         int intValue = Integer.parseInt(token);
190
191         if (retValue == null) {
192             retValue = new int[4];
193         }
194         else if(numCoords == retValue.length) {
195             int[] temp = new int[retValue.length * 2];
196
197             System.arraycopy(retValue, 0, temp, 0, retValue.length);
198             retValue = temp;
199         }
200         retValue[numCoords++] = intValue * scale;
201         } catch (NumberFormatException JavaDoc nfe) {
202         return null;
203         }
204     }
205     if (numCoords > 0 && numCoords != retValue.length) {
206         int[] temp = new int[numCoords];
207
208         System.arraycopy(retValue, 0, temp, 0, numCoords);
209         retValue = temp;
210     }
211     return retValue;
212     }
213
214
215     /**
216      * Defines the interface used for to check if a point is inside a
217      * region.
218      */

219     interface RegionContainment {
220     /**
221      * Returns true if the location <code>x</code>, <code>y</code>
222      * falls inside the region defined in the receiver.
223      * <code>width</code>, <code>height</code> is the size of
224      * the enclosing region.
225      */

226     public boolean contains(int x, int y, int width, int height);
227     }
228
229
230     /**
231      * Used to test for containment in a rectangular region.
232      */

233     static class RectangleRegionContainment implements RegionContainment {
234     /** Will be non-null if one of the values is a percent, and any value
235      * that is non null indicates it is a percent
236      * (order is x, y, width, height). */

237     float[] percents;
238     /** Last value of width passed in. */
239     int lastWidth;
240     /** Last value of height passed in. */
241     int lastHeight;
242         /** Top left. */
243         int x0;
244         int y0;
245         /** Bottom right. */
246         int x1;
247         int y1;
248
249     public RectangleRegionContainment(AttributeSet JavaDoc as) {
250         int[] coords = Map.extractCoords(as.getAttribute(HTML.
251                                Attribute.COORDS));
252
253         percents = null;
254         if (coords == null || coords.length != 4) {
255         throw new RuntimeException JavaDoc("Unable to parse rectangular area");
256         }
257         else {
258         x0 = coords[0];
259         y0 = coords[1];
260         x1 = coords[2];
261         y1 = coords[3];
262         if (x0 < 0 || y0 < 0 || x1 < 0 || y1 < 0) {
263             percents = new float[4];
264             lastWidth = lastHeight = -1;
265             for (int counter = 0; counter < 4; counter++) {
266             if (coords[counter] < 0) {
267                 percents[counter] = Math.abs
268                         (coords[counter]) / 100.0f;
269             }
270             else {
271                 percents[counter] = -1.0f;
272             }
273             }
274         }
275         }
276     }
277
278     public boolean contains(int x, int y, int width, int height) {
279         if (percents == null) {
280         return contains(x, y);
281         }
282         if (lastWidth != width || lastHeight != height) {
283         lastWidth = width;
284         lastHeight = height;
285         if (percents[0] != -1.0f) {
286             x0 = (int)(percents[0] * width);
287         }
288         if (percents[1] != -1.0f) {
289             y0 = (int)(percents[1] * height);
290         }
291         if (percents[2] != -1.0f) {
292             x1 = (int)(percents[2] * width);
293         }
294         if (percents[3] != -1.0f) {
295             y1 = (int)(percents[3] * height);
296         }
297         }
298         return contains(x, y);
299     }
300
301         public boolean contains(int x, int y) {
302             return ((x >= x0 && x <= x1) &&
303                     (y >= y0 && y <= y1));
304         }
305     }
306
307
308     /**
309      * Used to test for containment in a polygon region.
310      */

311     static class PolygonRegionContainment extends Polygon JavaDoc implements
312              RegionContainment {
313     /** If any value is a percent there will be an entry here for the
314      * percent value. Use percentIndex to find out the index for it. */

315     float[] percentValues;
316     int[] percentIndexs;
317     /** Last value of width passed in. */
318     int lastWidth;
319     /** Last value of height passed in. */
320     int lastHeight;
321
322     public PolygonRegionContainment(AttributeSet JavaDoc as) {
323         int[] coords = Map.extractCoords(as.getAttribute(HTML.Attribute.
324                                 COORDS));
325
326         if (coords == null || coords.length == 0 ||
327         coords.length % 2 != 0) {
328         throw new RuntimeException JavaDoc("Unable to parse polygon area");
329         }
330         else {
331         int numPercents = 0;
332
333         lastWidth = lastHeight = -1;
334         for (int counter = coords.length - 1; counter >= 0;
335              counter--) {
336             if (coords[counter] < 0) {
337             numPercents++;
338             }
339         }
340
341         if (numPercents > 0) {
342             percentIndexs = new int[numPercents];
343             percentValues = new float[numPercents];
344             for (int counter = coords.length - 1, pCounter = 0;
345              counter >= 0; counter--) {
346             if (coords[counter] < 0) {
347                 percentValues[pCounter] = coords[counter] /
348                                       -100.0f;
349                 percentIndexs[pCounter] = counter;
350                 pCounter++;
351             }
352             }
353         }
354         else {
355             percentIndexs = null;
356             percentValues = null;
357         }
358         npoints = coords.length / 2;
359         xpoints = new int[npoints];
360         ypoints = new int[npoints];
361         
362         for (int counter = 0; counter < npoints; counter++) {
363             xpoints[counter] = coords[counter + counter];
364             ypoints[counter] = coords[counter + counter + 1];
365         }
366         }
367     }
368
369     public boolean contains(int x, int y, int width, int height) {
370         if (percentValues == null || (lastWidth == width &&
371                       lastHeight == height)) {
372         return contains(x, y);
373         }
374         // Force the bounding box to be recalced.
375
bounds = null;
376         lastWidth = width;
377         lastHeight = height;
378         float fWidth = (float)width;
379         float fHeight = (float)height;
380         for (int counter = percentValues.length - 1; counter >= 0;
381          counter--) {
382         if (percentIndexs[counter] % 2 == 0) {
383             // x
384
xpoints[percentIndexs[counter] / 2] =
385                 (int)(percentValues[counter] * fWidth);
386         }
387         else {
388             // y
389
ypoints[percentIndexs[counter] / 2] =
390                 (int)(percentValues[counter] * fHeight);
391         }
392         }
393         return contains(x, y);
394     }
395     }
396
397
398     /**
399      * Used to test for containment in a circular region.
400      */

401     static class CircleRegionContainment implements RegionContainment {
402     /** X origin of the circle. */
403     int x;
404     /** Y origin of the circle. */
405     int y;
406     /** Radius of the circle. */
407     int radiusSquared;
408     /** Non-null indicates one of the values represents a percent. */
409     float[] percentValues;
410     /** Last value of width passed in. */
411     int lastWidth;
412     /** Last value of height passed in. */
413     int lastHeight;
414
415     public CircleRegionContainment(AttributeSet JavaDoc as) {
416         int[] coords = Map.extractCoords(as.getAttribute(HTML.Attribute.
417                                 COORDS));
418
419         if (coords == null || coords.length != 3) {
420         throw new RuntimeException JavaDoc("Unable to parse circular area");
421         }
422         x = coords[0];
423         y = coords[1];
424         radiusSquared = coords[2] * coords[2];
425         if (coords[0] < 0 || coords[1] < 0 || coords[2] < 0) {
426         lastWidth = lastHeight = -1;
427         percentValues = new float[3];
428         for (int counter = 0; counter < 3; counter++) {
429             if (coords[counter] < 0) {
430             percentValues[counter] = coords[counter] /
431                                      -100.0f;
432             }
433             else {
434             percentValues[counter] = -1.0f;
435             }
436         }
437         }
438         else {
439         percentValues = null;
440         }
441     }
442
443     public boolean contains(int x, int y, int width, int height) {
444         if (percentValues != null && (lastWidth != width ||
445                       lastHeight != height)) {
446         int newRad = Math.min(width, height) / 2;
447
448         lastWidth = width;
449         lastHeight = height;
450         if (percentValues[0] != -1.0f) {
451             this.x = (int)(percentValues[0] * width);
452         }
453         if (percentValues[1] != -1.0f) {
454             this.y = (int)(percentValues[1] * height);
455         }
456         if (percentValues[2] != -1.0f) {
457             radiusSquared = (int)(percentValues[2] *
458                    Math.min(width, height));
459             radiusSquared *= radiusSquared;
460         }
461         }
462         return (((x - this.x) * (x - this.x) +
463              (y - this.y) * (y - this.y)) <= radiusSquared);
464     }
465     }
466
467
468     /**
469      * An implementation that will return true if the x, y location is
470      * inside a rectangle defined by origin 0, 0, and width equal to
471      * width passed in, and height equal to height passed in.
472      */

473     static class DefaultRegionContainment implements RegionContainment {
474     /** A global shared instance. */
475     static DefaultRegionContainment si = null;
476
477     public static DefaultRegionContainment sharedInstance() {
478         if (si == null) {
479         si = new DefaultRegionContainment();
480         }
481         return si;
482     }
483
484     public boolean contains(int x, int y, int width, int height) {
485         return (x <= width && x >= 0 && y >= 0 && y <= width);
486     }
487     }
488 }
489
Popular Tags