1 | /* |
---|
2 | * $Id: Layer.java,v 1.25 2003/09/03 22:50:51 dwd Exp $ |
---|
3 | * |
---|
4 | * This software is provided by NOAA for full, free and open release. It is |
---|
5 | * understood by the recipient/user that NOAA assumes no liability for any |
---|
6 | * errors contained in the code. Although this software is released without |
---|
7 | * conditions or restrictions in its use, it is expected that appropriate |
---|
8 | * credit be given to its author and to the National Oceanic and Atmospheric |
---|
9 | * Administration should the software be included by the recipient as an |
---|
10 | * element in other product development. |
---|
11 | */ |
---|
12 | |
---|
13 | package gov.noaa.pmel.sgt; |
---|
14 | |
---|
15 | import gov.noaa.pmel.sgt.dm.Collection; |
---|
16 | import gov.noaa.pmel.sgt.dm.SGTData; |
---|
17 | |
---|
18 | import gov.noaa.pmel.sgt.swing.Draggable; |
---|
19 | |
---|
20 | import gov.noaa.pmel.util.Dimension2D; |
---|
21 | import gov.noaa.pmel.util.Rectangle2D; |
---|
22 | import gov.noaa.pmel.util.Debug; |
---|
23 | |
---|
24 | import java.util.Vector; |
---|
25 | import java.util.Enumeration; |
---|
26 | import java.util.Iterator; |
---|
27 | import java.awt.*; |
---|
28 | |
---|
29 | // jdk1.2 |
---|
30 | //import java.awt.geom.Rectangle2D; |
---|
31 | |
---|
32 | /** |
---|
33 | * A <code>Layer</code> contains a single <code>Graph</code> object |
---|
34 | * and multiple <code>LayerChild</code> objects. |
---|
35 | * There can be many <code>Layer</code> objects associated with each |
---|
36 | * <code>Pane</code> object and |
---|
37 | * the <code>Layer</code> objects can share <code>Transform</code> |
---|
38 | * and <code>Axis</code> objects, but are not |
---|
39 | * required to. The <code>Layer</code> is also where keys |
---|
40 | * related to <code>Color</code>, Vectors, and |
---|
41 | * Lines are attached. The can be at most one key of each type attached to a |
---|
42 | * <code>Layer</code>. |
---|
43 | * <p> |
---|
44 | * The <code>Layer</code> object transforms physical coordinates |
---|
45 | * to device coordinates. All objects that attach to a |
---|
46 | * <code>Layer</code> use physical coordinates. |
---|
47 | * The exception to this is the <code>Graph</code> object |
---|
48 | * (and its children), since these objects transform user |
---|
49 | * coordinates to physical coordinates. |
---|
50 | * <p> |
---|
51 | * The following is a simple example of using the <code>Pane</code>, |
---|
52 | * <code>Layer</code>, and <code>SGLabel</code> objects |
---|
53 | * together. In this example, the <code>Pane</code> and |
---|
54 | * <code>Layer</code> objects are created such that, |
---|
55 | * in the absence of any resizing, 100 pixels is equal to 1.0 |
---|
56 | * physical units. Two labels are created, the first contains |
---|
57 | * the current time and is located in the bottom left of |
---|
58 | * the <code>Layer</code>. The second label is a title that is |
---|
59 | * positioned near the top and centered. |
---|
60 | * <pre> |
---|
61 | * Pane pane; |
---|
62 | * Layer layer; |
---|
63 | * SGLabel title; |
---|
64 | * SGLabel label; |
---|
65 | * GeoDate stime; |
---|
66 | * ... |
---|
67 | * // |
---|
68 | * // Instantiate Pane, Layer, and GeoDate objects. |
---|
69 | * // |
---|
70 | * pane = new Pane("test pane", new Dimension(400, 300)); |
---|
71 | * pane.setLayout(new StackedLayout()); |
---|
72 | * layer = new Layer("Test Layer", new Dimension2D(4.0, 3.0)); |
---|
73 | * stime = new GeoDate(); |
---|
74 | * // |
---|
75 | * // Instatiate an SGLabel object as label, set its text to the |
---|
76 | * // current time and position it near the lower-left corner |
---|
77 | * // of the layer. |
---|
78 | * // |
---|
79 | * label = new SGLabel("test", stime.toString(), new Point2D.Double(0.05, 0.05)); |
---|
80 | * // |
---|
81 | * // Set properties for label. |
---|
82 | * // |
---|
83 | * label.setAlign(SGLabel.BOTTOM, SGLabel.LEFT); |
---|
84 | * label.setColor(Color.magenta); |
---|
85 | * label.setHeightP(0.15); |
---|
86 | * label.setFont(new Font("Dialog", Font.PLAIN, 10)); |
---|
87 | * // |
---|
88 | * // Add label to layer. |
---|
89 | * // |
---|
90 | * layer.addChild(label); |
---|
91 | * // |
---|
92 | * // Instatiate an SGLabel object as title, set its text and position |
---|
93 | * // it near the top of the layer and centered. Set the properties |
---|
94 | * // for title. |
---|
95 | * // |
---|
96 | * title = new SGLabel("title", "SciGraph Test!", new Point2D.Double(2.125, 2.9)); |
---|
97 | * title.setAlign(SGLabel.TOP, SGLabel.CENTER); |
---|
98 | * title.setHeightP(0.25); |
---|
99 | * title.setFont(new Font("Helvetica", Font.BOLD, 14)); |
---|
100 | * // |
---|
101 | * // Add title to layer and add layer to pane. |
---|
102 | * // |
---|
103 | * layer.addChild(title); |
---|
104 | * pane.add(layer); |
---|
105 | * </pre> |
---|
106 | * |
---|
107 | * @author Donald Denbo |
---|
108 | * @version $Revision: 1.25 $, $Date: 2003/09/03 22:50:51 $ |
---|
109 | * @since 1.0 |
---|
110 | * @see Pane |
---|
111 | * @see Graph |
---|
112 | * @see ColorKey |
---|
113 | * @see SGLabel |
---|
114 | * @see LineKey |
---|
115 | * @see gov.noaa.pmel.util.GeoDate |
---|
116 | **/ |
---|
117 | public class Layer extends Component implements Cloneable, LayerControl { |
---|
118 | private String ident_; |
---|
119 | /**@shapeType AggregationLink |
---|
120 | * @clientCardinality 1 |
---|
121 | * @label graph*/ |
---|
122 | private Graph graph_; |
---|
123 | /**@shapeType AggregationLink |
---|
124 | @associates <b>LayerChild</b> |
---|
125 | @supplierCardinality 0..* |
---|
126 | * @undirected |
---|
127 | * @label children */ |
---|
128 | private Vector children_; |
---|
129 | private double pWidth_; |
---|
130 | private double pHeight_; |
---|
131 | private double ax_; |
---|
132 | private double ay_; |
---|
133 | private int xoff_; |
---|
134 | private int yoff_; |
---|
135 | private double xoff2_; |
---|
136 | private double yoff2_; |
---|
137 | protected AbstractPane pane_; |
---|
138 | |
---|
139 | private void computeScale() { |
---|
140 | Dimension d; |
---|
141 | boolean hasG2 = getGraphics() instanceof Graphics2D; |
---|
142 | // compute xoff and yoff as double then truncate to int |
---|
143 | Rectangle pbnds = pane_.getBounds(); |
---|
144 | Rectangle bnds = getBounds(); |
---|
145 | if(pane_.isPrinter()) { |
---|
146 | ax_ = 72; // java2 is in 1/72 of an inch |
---|
147 | ay_ = ax_; |
---|
148 | xoff2_ = (bnds.width - ax_*pWidth_)/2.0 + bnds.x; |
---|
149 | yoff2_ = bnds.height - (bnds.height - ay_*pHeight_)/2.0 + bnds.y; |
---|
150 | } else { |
---|
151 | // not printer |
---|
152 | ax_ = (double)bnds.width/pWidth_; |
---|
153 | ay_ = (double)bnds.height/pHeight_; |
---|
154 | if(ax_ > ay_) { |
---|
155 | ax_ = ay_; |
---|
156 | } else if(ay_ > ax_) { |
---|
157 | ay_ = ax_; |
---|
158 | } |
---|
159 | xoff2_ = (bnds.width - ax_*pWidth_)/2.0 + bnds.x - pbnds.x; |
---|
160 | yoff2_ = bnds.height - (bnds.height - ay_*pHeight_)/2.0 + bnds.y - pbnds.y; |
---|
161 | } |
---|
162 | xoff_ = (int)xoff2_; |
---|
163 | yoff_ = (int)yoff2_; |
---|
164 | if(Debug.DEBUG && pane_.isPrinter()) { |
---|
165 | System.out.println("Layer.computeScale["+getId()+"] printer = " + pane_.isPrinter()); |
---|
166 | System.out.println(" xd(min) = " + getXPtoD(0.0)); |
---|
167 | System.out.println(" xd(max) = " + getXPtoD(pWidth_)); |
---|
168 | System.out.println(" yd(min) = " + getYPtoD(0.0)); |
---|
169 | System.out.println(" yd(max) = " + getYPtoD(pHeight_)); |
---|
170 | } |
---|
171 | } |
---|
172 | /** |
---|
173 | * Set the size of the <code>Layer</code> in device units. |
---|
174 | * |
---|
175 | * @param sze dimension of the <code>Layer</code> |
---|
176 | */ |
---|
177 | public void setSize(Dimension sze) { |
---|
178 | super.setSize(sze); |
---|
179 | computeScale(); |
---|
180 | modified("Layer: setSize(Dimension)"); |
---|
181 | } |
---|
182 | /** |
---|
183 | * Set the size of the <code>Layer</code> in device units. |
---|
184 | * |
---|
185 | * @param w width of the <code>Layer</code> |
---|
186 | * @param h height of the <code>Layer</code> |
---|
187 | */ |
---|
188 | public void setSize(int w, int h) { |
---|
189 | super.setSize(w, h); |
---|
190 | computeScale(); |
---|
191 | modified("Layer: setSize(int,int)"); |
---|
192 | } |
---|
193 | /** |
---|
194 | * Set the location of the <code>Layer</code> in device units. |
---|
195 | * |
---|
196 | * @param pt location of the <code>Layer</code> |
---|
197 | */ |
---|
198 | public void setLocation(Point pt) { |
---|
199 | super.setLocation(pt); |
---|
200 | computeScale(); |
---|
201 | modified("Layer: setLocation(Point)"); |
---|
202 | } |
---|
203 | /** |
---|
204 | * Set the location of the <code>Layer</code> in device units. |
---|
205 | * |
---|
206 | * @param x horizontal location of the <code>Layer</code> |
---|
207 | * @param y vertical location of the <code>Layer</code> |
---|
208 | */ |
---|
209 | public void setLocation(int x, int y) { |
---|
210 | super.setLocation(x, y); |
---|
211 | computeScale(); |
---|
212 | modified("Layer: setLocation(int,int)"); |
---|
213 | } |
---|
214 | /** |
---|
215 | * Set the bounds of the <code>Layer</code> in device units. |
---|
216 | * |
---|
217 | * @param x horizontal location of the <code>Layer</code> |
---|
218 | * @param y vertical location of the <code>Layer</code> |
---|
219 | * @param w width of the <code>Layer</code> |
---|
220 | * @param h height of the <code>Layer</code> |
---|
221 | */ |
---|
222 | public void setBounds(int x, int y, int w, int h) { |
---|
223 | super.setBounds(x, y, w, h); |
---|
224 | computeScale(); |
---|
225 | // System.out.println("Layer.setBounds(" + x + ", " + y + ", " + |
---|
226 | // w + ", " + h + ")"); |
---|
227 | modified("Layer: setBounds(int,int,int,int)"); |
---|
228 | } |
---|
229 | /** |
---|
230 | * Set the bounds of the <code>Layer</code> in device units. |
---|
231 | * |
---|
232 | * @param bnds bounds of the <code>Layer</code> |
---|
233 | */ |
---|
234 | public void setBounds(Rectangle bnds) { |
---|
235 | super.setBounds(bnds); |
---|
236 | computeScale(); |
---|
237 | modified("Layer: setBounds(Rectangle)"); |
---|
238 | } |
---|
239 | /** |
---|
240 | * Transform physical units to device for x coordinate. |
---|
241 | * |
---|
242 | * @param xp x physical coordinate |
---|
243 | * @return x device coordinate |
---|
244 | * @since 2.0 |
---|
245 | */ |
---|
246 | public int getXPtoD(double xp) { |
---|
247 | return (int)(ax_*xp) + xoff_; |
---|
248 | } |
---|
249 | /** |
---|
250 | * Transform physcial units to device for y coordinate. |
---|
251 | * |
---|
252 | * @param yp y physical coordinate |
---|
253 | * @return y device coordinate |
---|
254 | * @since 2.0 |
---|
255 | */ |
---|
256 | public int getYPtoD(double yp) { |
---|
257 | return yoff_ - (int)(ay_*yp); |
---|
258 | } |
---|
259 | /** |
---|
260 | * Transform physical units to device for x coordinate. |
---|
261 | * |
---|
262 | * @param xp x physical coordinate |
---|
263 | * @return x device coordinate |
---|
264 | * @since 3.0 |
---|
265 | */ |
---|
266 | public double getXPtoD2(double xp) { |
---|
267 | return ax_*xp + xoff2_; |
---|
268 | } |
---|
269 | /** |
---|
270 | * Transform physcial units to device for y coordinate. |
---|
271 | * |
---|
272 | * @param yp y physical coordinate |
---|
273 | * @return y device coordinate |
---|
274 | * @since 3.0 |
---|
275 | */ |
---|
276 | public double getYPtoD2(double yp) { |
---|
277 | return yoff2_ - ay_*yp; |
---|
278 | } |
---|
279 | protected double getXSlope() { |
---|
280 | return ax_; |
---|
281 | } |
---|
282 | protected double getYSlope() { |
---|
283 | return ay_; |
---|
284 | } |
---|
285 | protected double getXOffset() { |
---|
286 | return xoff2_; |
---|
287 | } |
---|
288 | protected double getYOffset() { |
---|
289 | return yoff2_; |
---|
290 | } |
---|
291 | /** |
---|
292 | * Transform device units to physical for the x direction. |
---|
293 | * |
---|
294 | * @param xd device x coordinate |
---|
295 | * |
---|
296 | * @return physical x coordinate |
---|
297 | */ |
---|
298 | public double getXDtoP(int xd) { |
---|
299 | return (double)(xd - xoff2_)/ax_; |
---|
300 | } |
---|
301 | /** |
---|
302 | * Transform device units to physical for the y direction. |
---|
303 | * |
---|
304 | * @param yd device y coordinate |
---|
305 | * |
---|
306 | * @return physical y coordinate |
---|
307 | */ |
---|
308 | public double getYDtoP(int yd) { |
---|
309 | return (double)(yoff2_ - yd)/ay_; |
---|
310 | } |
---|
311 | /** |
---|
312 | * Create a <code>Layer</code> object. |
---|
313 | * The <code>Layer</code> is created with a default |
---|
314 | * width and height equal to 1.0. |
---|
315 | * |
---|
316 | * @param id identifier for Layer |
---|
317 | **/ |
---|
318 | public Layer(String id) { |
---|
319 | this(id, new Dimension2D(1.0, 1.0)); |
---|
320 | } |
---|
321 | /** |
---|
322 | * Create a <code>Layer</code> object. |
---|
323 | * The <code>Layer</code> is created with the specified |
---|
324 | * dimensions and identifier. |
---|
325 | * |
---|
326 | * @param id identifier for Layer |
---|
327 | * @param psize The physical dimensions of the Layer |
---|
328 | **/ |
---|
329 | public Layer(String id,Dimension2D psize) { |
---|
330 | ident_ = id; |
---|
331 | pWidth_ = psize.width; |
---|
332 | pHeight_ = psize.height; |
---|
333 | children_ = new Vector(5,5); |
---|
334 | } |
---|
335 | /** |
---|
336 | * Default constructor for <code>Layer</code>. |
---|
337 | * The <code>Layer</code> is created with an |
---|
338 | * empty identifier and a width and height equal to 1.0f. |
---|
339 | **/ |
---|
340 | public Layer() { |
---|
341 | this(""); |
---|
342 | } |
---|
343 | /** |
---|
344 | * Copy the <code>Layer</code> and its attached classes. |
---|
345 | * |
---|
346 | * @return copy |
---|
347 | */ |
---|
348 | public Layer copy() { |
---|
349 | Layer newLayer; |
---|
350 | try { |
---|
351 | newLayer = (Layer)clone(); |
---|
352 | } catch (CloneNotSupportedException e) { |
---|
353 | newLayer = new Layer(ident_, new Dimension2D(pWidth_, pHeight_)); |
---|
354 | } |
---|
355 | // |
---|
356 | // copy children |
---|
357 | // |
---|
358 | newLayer.children_ = new Vector(5,5); |
---|
359 | // |
---|
360 | if(!children_.isEmpty()) { |
---|
361 | LayerChild newChild; |
---|
362 | for(Enumeration it = children_.elements(); it.hasMoreElements();) { |
---|
363 | newChild = ((LayerChild)it.nextElement()).copy(); |
---|
364 | newLayer.addChild(newChild); |
---|
365 | } |
---|
366 | } |
---|
367 | // |
---|
368 | // copy Graph |
---|
369 | // |
---|
370 | if(graph_ != (Graph) null) { |
---|
371 | Graph newGraph = graph_.copy(); |
---|
372 | newLayer.setGraph(newGraph); |
---|
373 | } |
---|
374 | return newLayer; |
---|
375 | } |
---|
376 | /** |
---|
377 | * Draw the Layer and its attached classes. |
---|
378 | * |
---|
379 | * @param g graphics context |
---|
380 | * @exception PaneNotFoundException if a pane object is not found |
---|
381 | **/ |
---|
382 | public void draw(Graphics g) throws PaneNotFoundException { |
---|
383 | if(pane_ == null) throw new PaneNotFoundException(); |
---|
384 | computeScale(); |
---|
385 | |
---|
386 | if(false) { |
---|
387 | System.out.println("\nLayer.draw(g): " + ident_); |
---|
388 | System.out.println(" layer.getBounds(" + ident_ + ") = " + getBounds()); |
---|
389 | System.out.println(" layer.getBoundsP(" + ident_ + ") = " + getBoundsP()); |
---|
390 | System.out.println(" pane.getBounds(" + pane_.getId() + ") = " + pane_.getBounds()); |
---|
391 | } |
---|
392 | /* int x0, y0, x1, y1; |
---|
393 | x0 = getXPtoD(0.0f); |
---|
394 | y0 = getYPtoD(0.0f); |
---|
395 | Rectangle2D.Double psize_ = getBoundsP(); |
---|
396 | x1 = getXPtoD(psize_.width); |
---|
397 | y1 = getYPtoD(psize_.height); |
---|
398 | g.setColor(Color.blue); |
---|
399 | g.drawRect(x0,y1,x1-x0-1,y0-y1-1); */ |
---|
400 | // System.out.println("Layer.draw(g): " + ident_ + ", [" + ax_ + ", " + ay_ + "], [" + |
---|
401 | // xoff2_ + ", " + yoff2_ + "]"); |
---|
402 | |
---|
403 | // |
---|
404 | // draw Graph |
---|
405 | // |
---|
406 | if(graph_ != (Graph) null) graph_.draw(g); |
---|
407 | // |
---|
408 | // draw children |
---|
409 | // |
---|
410 | if(!children_.isEmpty()) { |
---|
411 | LayerChild child; |
---|
412 | for(Enumeration it = children_.elements(); it.hasMoreElements();) { |
---|
413 | child = (LayerChild)it.nextElement(); |
---|
414 | if(!(child instanceof Draggable)) { |
---|
415 | try { |
---|
416 | child.draw(g); |
---|
417 | } catch(LayerNotFoundException e) { |
---|
418 | } |
---|
419 | } |
---|
420 | } |
---|
421 | } |
---|
422 | } |
---|
423 | |
---|
424 | public void drawDraggableItems(Graphics g) throws PaneNotFoundException { |
---|
425 | if(pane_ == null) throw new PaneNotFoundException(); |
---|
426 | // |
---|
427 | // draw draggable items |
---|
428 | // |
---|
429 | if(!children_.isEmpty()) { |
---|
430 | LayerChild child; |
---|
431 | for(Enumeration it = children_.elements(); it.hasMoreElements();) { |
---|
432 | child = (LayerChild)it.nextElement(); |
---|
433 | if(child instanceof Draggable) { |
---|
434 | try { |
---|
435 | child.draw(g); |
---|
436 | } catch(LayerNotFoundException e) { |
---|
437 | } |
---|
438 | } |
---|
439 | } |
---|
440 | } |
---|
441 | } |
---|
442 | /** |
---|
443 | * Associate a graph with the layer. Only one graph or its children may be attached to a |
---|
444 | * layer. Multiple graphs are created by using multiple layers. |
---|
445 | * |
---|
446 | * @param gr graph |
---|
447 | * @return True if attachment was succesful |
---|
448 | * @see Graph |
---|
449 | **/ |
---|
450 | public boolean setGraph(Graph gr) { |
---|
451 | graph_ = gr; |
---|
452 | graph_.setLayer(this); |
---|
453 | modified("Layer: setGraph()"); |
---|
454 | return true; |
---|
455 | } |
---|
456 | /** |
---|
457 | * Get the <code>Graph</code> attached to the layer. |
---|
458 | * |
---|
459 | * @return Reference to the <code>Graph</code>. |
---|
460 | **/ |
---|
461 | public Graph getGraph() { |
---|
462 | return graph_; |
---|
463 | } |
---|
464 | /** |
---|
465 | * Add a <code>LayerChild</code> to the <code>Layer</code>. |
---|
466 | * Each <code>Layer</code> can contain as many children as needed. |
---|
467 | * |
---|
468 | * @param child A <code>LayerChild</code> |
---|
469 | * @see SGLabel |
---|
470 | * @see LineKey |
---|
471 | * @see ColorKey |
---|
472 | * @see Ruler |
---|
473 | **/ |
---|
474 | public void addChild(LayerChild child) { |
---|
475 | child.setLayer(this); |
---|
476 | children_.addElement(child); |
---|
477 | modified("Layer: addChild()"); |
---|
478 | } |
---|
479 | /** |
---|
480 | * Remove a <code>LayerChild</code> object from the <code>Layer</code>. |
---|
481 | * |
---|
482 | * @param child A <code>ChildLayer</code> object associated with the <code>Layer</code> |
---|
483 | * @exception ChildNotFoundException The child is not associated with the <code>Layer</code> |
---|
484 | * @see SGLabel |
---|
485 | * @see LineKey |
---|
486 | * @see ColorKey |
---|
487 | * @see Ruler |
---|
488 | **/ |
---|
489 | public void removeChild(LayerChild child) throws ChildNotFoundException { |
---|
490 | if(!children_.isEmpty()) { |
---|
491 | LayerChild chld; |
---|
492 | boolean found = false; |
---|
493 | for(Enumeration it = children_.elements(); it.hasMoreElements();) { |
---|
494 | chld = (LayerChild)it.nextElement(); |
---|
495 | if(chld.equals(child)) { |
---|
496 | children_.removeElement(child); |
---|
497 | found = true; |
---|
498 | modified("Layer: removeChild(LayerChild)"); |
---|
499 | } |
---|
500 | } |
---|
501 | if(!found) throw new ChildNotFoundException(); |
---|
502 | } else { |
---|
503 | throw new ChildNotFoundException(); |
---|
504 | } |
---|
505 | } |
---|
506 | /** |
---|
507 | * Remove a <code>LayerChild</code> object from the <code>Layer</code>. |
---|
508 | * |
---|
509 | * @param labid An identifier for a <code>LayerChild</code> associated with the <code>Layer</code> |
---|
510 | * @exception ChildNotFoundException The child is not associated with the <code>Layer</code> |
---|
511 | * @see SGLabel |
---|
512 | * @see LineKey |
---|
513 | * @see ColorKey |
---|
514 | * @see Ruler |
---|
515 | **/ |
---|
516 | public void removeChild(String labid) throws ChildNotFoundException { |
---|
517 | if(!children_.isEmpty()) { |
---|
518 | boolean found = false; |
---|
519 | LayerChild child; |
---|
520 | for(Enumeration it = children_.elements(); it.hasMoreElements();) { |
---|
521 | child = (LayerChild)it.nextElement(); |
---|
522 | if(child.getId().equals(labid)) { |
---|
523 | children_.removeElement(child); |
---|
524 | found = true; |
---|
525 | modified("Layer: removeChild(String)"); |
---|
526 | } |
---|
527 | } |
---|
528 | if(!found) throw new ChildNotFoundException(); |
---|
529 | } else { |
---|
530 | throw new ChildNotFoundException(); |
---|
531 | } |
---|
532 | } |
---|
533 | |
---|
534 | /** |
---|
535 | * Find <code>LayerChild</code> in <code>Layer</code>. |
---|
536 | * @param id LayerChild identifier |
---|
537 | * @return LayerChild |
---|
538 | * @since 3.0 |
---|
539 | */ |
---|
540 | public LayerChild findChild(String id) { |
---|
541 | LayerChild child = null; |
---|
542 | for(Enumeration it=children_.elements(); it.hasMoreElements();) { |
---|
543 | child = (LayerChild)it.nextElement(); |
---|
544 | if(child.getId().equals(id)) return child; |
---|
545 | } |
---|
546 | return null; |
---|
547 | } |
---|
548 | /** |
---|
549 | * Tests if a <code>LayerChild</code> is attached to the |
---|
550 | * <code>Layer</code>. |
---|
551 | * |
---|
552 | * @param child LayerChild to test |
---|
553 | * @return true if attached to Layer |
---|
554 | * @since 2.0 |
---|
555 | */ |
---|
556 | public boolean isChildAttached(LayerChild child) { |
---|
557 | boolean found = false; |
---|
558 | if(!children_.isEmpty()) { |
---|
559 | LayerChild chld; |
---|
560 | for(Enumeration it = children_.elements(); it.hasMoreElements();) { |
---|
561 | chld = (LayerChild)it.nextElement(); |
---|
562 | if(chld.equals(child)) { |
---|
563 | children_.removeElement(child); |
---|
564 | found = true; |
---|
565 | break; |
---|
566 | } |
---|
567 | } |
---|
568 | } |
---|
569 | return found; |
---|
570 | } |
---|
571 | /** |
---|
572 | * Remove all <code>LayerChild</code> objects from the <code>Layer</code>. |
---|
573 | */ |
---|
574 | public void removeAllChildren() { |
---|
575 | children_.removeAllElements(); |
---|
576 | modified("Layer: removeAllChildren()"); |
---|
577 | } |
---|
578 | /** |
---|
579 | * Get a child associated with the <code>Layer</code>. |
---|
580 | * |
---|
581 | * @param labid A <code>LayerChild</code> object identifier |
---|
582 | * @return layerChild with id |
---|
583 | * @exception ChildNotFoundException The child is not associated with the <code>Layer</code> |
---|
584 | * @see SGLabel |
---|
585 | * @see LineKey |
---|
586 | * @see ColorKey |
---|
587 | * @see Ruler |
---|
588 | **/ |
---|
589 | public LayerChild getChild(String labid) throws ChildNotFoundException { |
---|
590 | if(!children_.isEmpty()) { |
---|
591 | LayerChild child; |
---|
592 | for(Enumeration it = children_.elements(); it.hasMoreElements();) { |
---|
593 | child = (LayerChild)it.nextElement(); |
---|
594 | if(child.getId() == labid) return child; |
---|
595 | } |
---|
596 | throw new ChildNotFoundException(); |
---|
597 | } else { |
---|
598 | throw new ChildNotFoundException(); |
---|
599 | } |
---|
600 | } |
---|
601 | /** |
---|
602 | * Create a <code>Enumeration</code> for the |
---|
603 | * <code>LayerChild</code>'s associated with the <code>Layer</code>. |
---|
604 | * |
---|
605 | * @return <code>Enumeration</code> for the <code>LayerChild</code> objects. |
---|
606 | * @see Enumeration |
---|
607 | * @see SGLabel |
---|
608 | * @see LineKey |
---|
609 | * @see ColorKey |
---|
610 | * @see Ruler |
---|
611 | **/ |
---|
612 | public Enumeration childElements() { |
---|
613 | return children_.elements(); |
---|
614 | } |
---|
615 | |
---|
616 | /** |
---|
617 | * @since 3.0 |
---|
618 | */ |
---|
619 | public Iterator childIterator() { |
---|
620 | return children_.iterator(); |
---|
621 | } |
---|
622 | |
---|
623 | /** |
---|
624 | * @since 3.0 |
---|
625 | */ |
---|
626 | public LayerChild[] getChildren() { |
---|
627 | LayerChild[] childs = new LayerChild[0]; |
---|
628 | childs = (LayerChild[])children_.toArray(childs); |
---|
629 | return childs; |
---|
630 | } |
---|
631 | /** |
---|
632 | * Set the size of the <code>Layer</code> in physical coordinates. |
---|
633 | * |
---|
634 | * @param psize The physical size of the <code>Layer</code>. |
---|
635 | **/ |
---|
636 | public void setSizeP(Dimension2D psize) { |
---|
637 | pWidth_ = psize.width; |
---|
638 | pHeight_ = psize.height; |
---|
639 | computeScale(); |
---|
640 | modified("Layer: setSizeP()"); |
---|
641 | } |
---|
642 | /** |
---|
643 | * Get the <code>Layer</code> size in physical coordinates. |
---|
644 | * This returns the physical coordinate size |
---|
645 | * of the <code>Layer</code>. |
---|
646 | * |
---|
647 | * @return A <code>Dimension2D</code> containing the physical size of the <code>Layer</code>. |
---|
648 | * @see Dimension2D |
---|
649 | **/ |
---|
650 | public Dimension2D getSizeP() { |
---|
651 | return new Dimension2D(pWidth_, pHeight_); |
---|
652 | } |
---|
653 | /** |
---|
654 | * Get the <code>Layer</code> bounds in physical coordinates. |
---|
655 | * The origin of the bounding rectangle, |
---|
656 | * for a <code>Layer</code>, is always (0,0). |
---|
657 | * |
---|
658 | * @return A <code>Rectangle2D.Double</code> containing the physical bounds of the <code>Layer</code>. |
---|
659 | * @see java.awt.geom.Rectangle2D.Double |
---|
660 | **/ |
---|
661 | public Rectangle2D.Double getBoundsP() { |
---|
662 | return new Rectangle2D.Double(0.0, 0.0, |
---|
663 | pWidth_, pHeight_); |
---|
664 | } |
---|
665 | /** |
---|
666 | * Get the <code>Layer</code> identifier. |
---|
667 | * |
---|
668 | * @return The identifier. |
---|
669 | **/ |
---|
670 | public String getId() { |
---|
671 | return ident_; |
---|
672 | } |
---|
673 | /** |
---|
674 | * Set the <code>Layer</code> identifier. |
---|
675 | * |
---|
676 | * @param id identifier |
---|
677 | **/ |
---|
678 | public void setId(String id) { |
---|
679 | ident_ = id; |
---|
680 | } |
---|
681 | /** |
---|
682 | * Set the <code>Pane</code> the <code>Layer</code> is associated with. |
---|
683 | * This method is called by <code>Pane</code> when the |
---|
684 | * <code>Pane.add</code> method is exectued. |
---|
685 | * |
---|
686 | * @param p The <code>Pane</code> |
---|
687 | **/ |
---|
688 | public void setPane(AbstractPane p) { |
---|
689 | pane_ = p; |
---|
690 | computeScale(); |
---|
691 | modified("Layer: setPane()"); |
---|
692 | } |
---|
693 | /** |
---|
694 | * Get the <code>Pane</code> the <code>Layer</code> is associated |
---|
695 | * with. |
---|
696 | * |
---|
697 | * @return Refence to the <code>Pane</code> |
---|
698 | **/ |
---|
699 | public AbstractPane getPane() { |
---|
700 | return pane_; |
---|
701 | } |
---|
702 | /** |
---|
703 | * Used internally by sgt. |
---|
704 | * @param mess message |
---|
705 | * @since 2.0 |
---|
706 | */ |
---|
707 | public void modified(String mess) { |
---|
708 | if(pane_ != null) { |
---|
709 | // if(Debug.EVENT) System.out.println("Layer: modified(" + mess + ")"); |
---|
710 | pane_.setModified(true, mess); |
---|
711 | } |
---|
712 | } |
---|
713 | /** |
---|
714 | * Find object associated with a MOUSE_DOWN event. The getObjectAt method |
---|
715 | * scans through all the objects associated with the layer to find one |
---|
716 | * whose bounding box contains the mouse location. |
---|
717 | * |
---|
718 | * This method should not be called by a user. |
---|
719 | * |
---|
720 | * @param pt device coordinates |
---|
721 | * @param check if true requires that object isSelectable |
---|
722 | * @return object at location |
---|
723 | **/ |
---|
724 | public Object getObjectAt(int x, int y, boolean check) { |
---|
725 | return getObjectAt(new Point(x, y), check); |
---|
726 | } |
---|
727 | /** |
---|
728 | * Find object associated with a MOUSE_DOWN event. The getObjectAt method |
---|
729 | * scans through all the objects associated with the layer to find one |
---|
730 | * whose bounding box contains the mouse location. |
---|
731 | * |
---|
732 | * This method should not be called by a user. |
---|
733 | * |
---|
734 | * @param pt device coordinates |
---|
735 | * @return object at location |
---|
736 | **/ |
---|
737 | public Object getObjectAt(int x,int y) { |
---|
738 | return getObjectAt(new Point(x, y), true); |
---|
739 | } |
---|
740 | /** |
---|
741 | * Find object associated with a MOUSE_DOWN event. The getObjectAt method |
---|
742 | * scans through all the objects associated with the layer to find one |
---|
743 | * whose bounding box contains the mouse location. |
---|
744 | * |
---|
745 | * This method should not be called by a user. |
---|
746 | * |
---|
747 | * @param pt device coordinates |
---|
748 | * @param check if true requires that object isSelectable |
---|
749 | * @return object at location |
---|
750 | **/ |
---|
751 | public Object getObjectAt(Point pt, boolean check) { |
---|
752 | Rectangle bnds; |
---|
753 | Object obj; |
---|
754 | if(!children_.isEmpty()) { |
---|
755 | LayerChild child; |
---|
756 | for(Enumeration it = children_.elements(); it.hasMoreElements();) { |
---|
757 | child = (LayerChild)it.nextElement(); |
---|
758 | bnds = child.getBounds(); |
---|
759 | if(bnds.contains(pt) && (!check || child.isSelectable()) && |
---|
760 | child.isVisible()) { |
---|
761 | if(child instanceof LineKey) { |
---|
762 | return ((LineKey)child).getObjectAt(pt); |
---|
763 | } else if(child instanceof PointCollectionKey) { |
---|
764 | return ((PointCollectionKey)child).getObjectAt(pt); |
---|
765 | } else if(child instanceof VectorKey) { |
---|
766 | return ((VectorKey)child).getObjectAt(pt); |
---|
767 | } else { |
---|
768 | return child; |
---|
769 | } |
---|
770 | } |
---|
771 | } |
---|
772 | } |
---|
773 | if(graph_ != null) { |
---|
774 | obj = graph_.getObjectAt(pt); |
---|
775 | if(obj != null) return obj; |
---|
776 | } |
---|
777 | return (Object) null; |
---|
778 | } |
---|
779 | |
---|
780 | /** |
---|
781 | * Find objects associated with a MOUSE_DOWN event. The getObjecstAt method |
---|
782 | * scans through all the objects associated with the layer to find those |
---|
783 | * whose bounding box contains the mouse location. |
---|
784 | * |
---|
785 | * This method should not be called by a user. |
---|
786 | * |
---|
787 | * @param x mouse coordinate |
---|
788 | * @param y mouse coordinate |
---|
789 | * @param check if selectable |
---|
790 | * @return object array |
---|
791 | * @since 3.0 |
---|
792 | */ |
---|
793 | public Object[] getObjectsAt(int x, int y, boolean check) { |
---|
794 | Point pt = new Point(x, y); |
---|
795 | Vector obList = new Vector(); |
---|
796 | Object obj = null; |
---|
797 | Rectangle bnds; |
---|
798 | if(!children_.isEmpty()) { |
---|
799 | LayerChild child; |
---|
800 | for(Enumeration it = children_.elements(); it.hasMoreElements();) { |
---|
801 | child = (LayerChild)it.nextElement(); |
---|
802 | bnds = child.getBounds(); |
---|
803 | if(bnds.contains(pt) && (!check || child.isSelectable()) && |
---|
804 | child.isVisible()) { |
---|
805 | if(child instanceof LineKey) { |
---|
806 | obj = ((LineKey)child).getObjectAt(pt); |
---|
807 | if(obj != null) obList.add(obj); |
---|
808 | } else if(child instanceof PointCollectionKey) { |
---|
809 | obj = ((PointCollectionKey)child).getObjectAt(pt); |
---|
810 | if(obj != null) obList.add(obj); |
---|
811 | } else if(child instanceof VectorKey) { |
---|
812 | obj = ((VectorKey)child).getObjectAt(pt); |
---|
813 | if(obj != null) obList.add(obj); |
---|
814 | } else { |
---|
815 | if(child != null) obList.add(child); |
---|
816 | } |
---|
817 | } |
---|
818 | } |
---|
819 | } |
---|
820 | if(graph_ != null) { |
---|
821 | obj = graph_.getObjectAt(pt); |
---|
822 | if(obj != null) obList.add(obj); |
---|
823 | } |
---|
824 | |
---|
825 | return obList.toArray(); |
---|
826 | } |
---|
827 | /** |
---|
828 | * Get a <code>String</code> representation of the |
---|
829 | * <code>Layer</code>. |
---|
830 | * |
---|
831 | * @return <code>String</code> representation |
---|
832 | */ |
---|
833 | public String toString() { |
---|
834 | String name = getClass().getName(); |
---|
835 | return name.substring(name.lastIndexOf(".")+1) + ": " + ident_; |
---|
836 | } |
---|
837 | /** |
---|
838 | * Checks to see if a data id matches that data attached to the |
---|
839 | * <code>Graph</code>. |
---|
840 | * @param id data identifier |
---|
841 | * @return true if data is in layer |
---|
842 | * @since 2.0 |
---|
843 | */ |
---|
844 | public boolean isDataInLayer(String id) { |
---|
845 | if(graph_ instanceof CartesianGraph) { |
---|
846 | CartesianRenderer cr = ((CartesianGraph)graph_).getRenderer(); |
---|
847 | if(cr instanceof LineCartesianRenderer) { |
---|
848 | if(((LineCartesianRenderer)cr).hasCollection()) { |
---|
849 | Collection co = ((LineCartesianRenderer)cr).getCollection(); |
---|
850 | for(Enumeration it = co.elements(); it.hasMoreElements();) { |
---|
851 | if(((SGTData)it.nextElement()).getId().equals(id)) return true; |
---|
852 | } |
---|
853 | } else { |
---|
854 | return ((LineCartesianRenderer)cr).getLine().getId().equals(id); |
---|
855 | } |
---|
856 | } else if(cr instanceof GridCartesianRenderer) { |
---|
857 | return ((GridCartesianRenderer)cr).getGrid().getId().equals(id); |
---|
858 | } else if(cr instanceof PointCartesianRenderer) { |
---|
859 | if(((PointCartesianRenderer)cr).hasCollection()) { |
---|
860 | Collection co = ((PointCartesianRenderer)cr).getCollection(); |
---|
861 | for(Enumeration it = co.elements(); it.hasMoreElements();) { |
---|
862 | if(((SGTData)it.nextElement()).getId().equals(id)) return true; |
---|
863 | } |
---|
864 | } else { |
---|
865 | return ((PointCartesianRenderer)cr).getPoint().getId().equals(id); |
---|
866 | } |
---|
867 | } |
---|
868 | } |
---|
869 | return false; |
---|
870 | } |
---|
871 | } |
---|