source: ether_megapoli/trunk/service/implementation/gov2/noaa/pmel/sgt/swing/JGraphicLayout.java @ 192

Last change on this file since 192 was 192, checked in by vmipsl, 13 years ago

Servlet _ Contour en cours _ package gov2

File size: 32.0 KB
Line 
1/*
2 * $Id: JGraphicLayout.java,v 1.24 2003/08/22 23:02:39 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
13package  gov.noaa.pmel.sgt.swing;
14
15import gov.noaa.pmel.sgt.CartesianGraph;
16import gov.noaa.pmel.sgt.Pane;
17import gov.noaa.pmel.sgt.SGLabel;
18import gov.noaa.pmel.sgt.Layer;
19import gov.noaa.pmel.sgt.JPane;
20import gov.noaa.pmel.sgt.AxisTransform;
21import gov.noaa.pmel.sgt.LineCartesianRenderer;
22import gov.noaa.pmel.sgt.Graph;
23import gov.noaa.pmel.sgt.Attribute;
24import gov.noaa.pmel.sgt.LineAttribute;
25import gov.noaa.pmel.sgt.GridAttribute;
26import gov.noaa.pmel.sgt.PlainAxis;
27import gov.noaa.pmel.sgt.TimeAxis;
28import gov.noaa.pmel.sgt.Logo;
29import gov.noaa.pmel.sgt.DataNotFoundException;
30
31import gov.noaa.pmel.util.Domain;
32import gov.noaa.pmel.util.Rectangle2D;
33import gov.noaa.pmel.util.Dimension2D;
34import gov.noaa.pmel.util.Range2D;
35import gov.noaa.pmel.util.TimeRange;
36import gov.noaa.pmel.util.GeoDate;
37import gov.noaa.pmel.util.Units;
38import gov.noaa.pmel.util.SoTRange;
39
40import gov.noaa.pmel.sgt.dm.SGTData;
41import gov.noaa.pmel.sgt.dm.SGTPoint;
42import gov.noaa.pmel.sgt.dm.SGTLine;
43import gov.noaa.pmel.sgt.dm.SGTGrid;
44import gov.noaa.pmel.sgt.dm.Collection;
45import gov.noaa.pmel.sgt.dm.SGTVector;
46
47import gov.noaa.pmel.sgt.swing.prop.SGLabelDialog;
48import gov.noaa.pmel.sgt.swing.prop.TimeAxisDialog;
49import gov.noaa.pmel.sgt.swing.prop.SpaceAxisDialog;
50import gov.noaa.pmel.sgt.swing.prop.LogoDialog;
51
52import java.util.Vector;
53import java.util.Enumeration;
54import java.util.Hashtable;
55import java.net.URL;
56import java.awt.Image;
57import java.awt.Color;
58import java.awt.Rectangle;
59import java.awt.Component;
60import java.awt.Frame;
61import java.awt.Container;
62import java.awt.Dimension;
63import java.awt.event.InputEvent;
64import java.text.DecimalFormat;
65
66import java.beans.PropertyVetoException;
67import java.beans.PropertyChangeSupport;
68import java.beans.PropertyChangeListener;
69import java.beans.VetoableChangeSupport;
70import java.beans.VetoableChangeListener;
71
72/**
73 * <code>JGraphicLayout</code> is a abstract class that provides
74 * the basis for pre-defined layouts using the
75 * <code>CartesianGraph</code> class. <code>JGraphicLayout</code>
76 * extends <code>JPane</code>.
77 *
78 * @author Donald Denbo
79 * @version $Revision: 1.24 $, $Date: 2003/08/22 23:02:39 $
80 * @since 2.0
81 * @see CartesianGraph
82 * @see JPlotLayout
83**/
84public abstract class JGraphicLayout extends JPane {
85  /**
86   * Use X array from <code>SGTData</code>.
87   */
88  public static final int X_AXIS = 1;
89  /**
90   * Use Y array from <code>SGTData</code>.
91   */
92  public static final int Y_AXIS = 2;
93  /**
94   * Use Z array from <code>SGTData</code>.
95   */
96  public static final int Z_AXIS = 3;
97  /** Width of graph in physical units */
98  protected static double XSIZE_ = 6.00;
99  /** Start of X axis in physical units */
100  protected static double XMIN_  = 0.60;
101  /** End of X axis in physical units */
102  protected static double XMAX_  = 5.40;
103  /** Height of graph in physical units */
104  protected static double YSIZE_ = 4.50;
105  /** Start of Y axis in physical units */
106  protected static double YMIN_  = 0.75;
107  /** End of Y axis in physical units */
108  protected static double YMAX_  = 3.30;
109  //
110  /** Height of main title in physical units */
111  protected static double MAIN_TITLE_HEIGHT_ = 0.25;
112  /** Height of axis title in physical units */
113  protected static double TITLE_HEIGHT_ = 0.22;
114  /** Height of axis labels in physical units */
115  protected static double LABEL_HEIGHT_ = 0.18;
116  /** Height of 2nd and 3rd main titles */
117  protected static double WARN_HEIGHT_ = 0.15;
118  /** Height of line or color key labels */
119  protected static double KEY_HEIGHT_ = 0.16;
120  //  protected static double KEY_HEIGHT_ = 0.20;
121  //
122  /** Width of key if in separate pane */
123  protected static double XKEYSIZE_ =  6.00;
124  /** Height of key if in separate pane */
125  protected static double YKEYSIZE_ = 12.00;
126  //
127  /** Main pane color */
128  protected static Color PANE_COLOR = Color.white;
129  /** Key pane color */
130  protected static Color KEYPANE_COLOR = Color.white;
131  //
132  /** Base units of data */
133  protected int base_units_ = Units.NONE;
134  private JGraphicLayout me_;
135  /** Key pane reference */
136  protected JPane keyPane_;
137  /** <code>SGTData</code> storage */
138  protected Vector data_;
139  /** Mapping of data to attributes */
140  protected Hashtable dataAttrMap_ = new Hashtable();
141  /** Identification of graph */
142  protected String ident_;
143  /** Layers are overlayed */
144  protected boolean overlayed_;
145  /** Data is clipped to axes */
146  protected boolean clipping_ = false;
147  /** Optional image */
148  protected Image iconImage_ = null;
149
150  /**
151   * Titles for graph
152   * @link aggregation
153   * @undirected
154   * @label titles
155   */
156  protected SGLabel mainTitle_, title2_, title3_;
157  /** Reference to Mouse event handler */
158  protected SymMouse aSymMouse_;
159  //
160  /** Allow editing of <code>sgt</code> object properties */
161  protected boolean editClasses_ = true;
162  /** Reference to <code>SGLabelDialog</code> */
163  protected SGLabelDialog sg_props_;
164  /** Reference to <code>SpaceAxisDialog</code> */
165  protected SpaceAxisDialog pa_props_;
166  /** Reference to <code>TimeAxisDialog</code> */
167  protected TimeAxisDialog ta_props_;
168  /** Reference to <code>LogoDialog</code> */
169  protected LogoDialog lo_props_;
170  //
171  /** Reference to <code>PropertyChangeSupport</code> */
172  protected PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
173  /** Reference to <code>VetoableChangeSupport</code> */
174  protected VetoableChangeSupport vetos_ = new VetoableChangeSupport(this);
175  /**
176   * Default constructor
177   */
178  public JGraphicLayout() {
179    this("", null, new Dimension(50,50));
180  }
181  /**
182   * <code>JGraphicLayout</code> constructor.
183   *
184   * @param id identifier
185   * @param img icon image
186   * @see JPlotLayout
187   */
188  public JGraphicLayout(String id, Image img) {
189    this(id, img, new Dimension(50,50));
190  }
191  /**
192   * <code>JGraphicLayout</code> constructor.
193   *
194   * @param id identifier
195   * @param img icon image
196   * @param size graph size in device units
197   * @see JPlotLayout
198   */
199  public JGraphicLayout(String id, Image img, Dimension size) {
200    super(id, size);
201    ident_ = id;
202    overlayed_ = true;
203    data_ = new Vector(10);
204    iconImage_ = img;
205    mainTitle_ = null;
206    title2_ = null;
207    title3_ = null;
208    me_ = this;
209    if(aSymMouse_ == null) aSymMouse_ = new SymMouse();
210    addMouseListener(aSymMouse_);
211  }
212  /**
213   * Set the identifier
214   *
215   * @param id layout identifier
216   */
217  public void setId(String id) {
218    ident_ = id;
219  }
220  /**
221   * Get the identifier
222   *
223   * @return layout identifier
224   */
225  public String getId() {
226    return ident_;
227  }
228  /**
229   * Set the plot titles.
230   *
231   * @param title main plot title
232   * @param title2 secondary plot title
233   * @param title3 tertiary plot title
234   */
235  public void setTitles(String title, String title2, String title3) {
236    if(mainTitle_ != null) mainTitle_.setText(title);
237    if(title2_ != null) title2_.setText(title2);
238    if(title3_ != null) title3_.setText(title3);
239  }
240  /**
241   * Set the base units. The base units are set automatically based
242   * on the first <code>SGTData</code> added to the list. Other
243   * <code>SGTData</code> objects added
244   * thereafter will be converted to the standard display units for each
245   * base unit type.  (TEMPERATURE, default units are "degC"; VELOCITY,
246   * default units are "m/s"; DISTANCE, default unis are "m"). NOTE: Presently
247   * the units supported are very limited.
248   *
249   * @see gov.noaa.pmel.util.Units#NONE
250   * @see gov.noaa.pmel.util.Units#TEMPERATURE
251   * @see gov.noaa.pmel.util.Units#VELOCITY
252   * @see gov.noaa.pmel.util.Units#DISTANCE
253   */
254  public void setBaseUnit(int base) {
255    base_units_ = base;
256  }
257  /**
258   * Get the base units
259   *
260   * @return the current base units for the layout
261   */
262  public int getBaseUnit() {
263    return base_units_;
264  }
265  /**
266   * Set flag to overlay the layers.
267   *
268   * @param over if true overlay layers if false stack
269   */
270  public void setOverlayed(boolean over) {
271    overlayed_ = over;
272  }
273  /**
274   * Layer overlay flag.
275   *
276   * @return true if layers will be overlayed
277   */
278  public boolean isOverlayed() {
279    return overlayed_;
280  }
281  /**
282   * Get icon image
283   *
284   * @return icon image
285   */
286  public Image getIconImage() {
287    return iconImage_;
288  }
289  /**
290   * Get KeyPane object
291   *
292   * @return pane
293   */
294  public JPane getKeyPane() {
295    return keyPane_;
296  }
297  /**
298   * Is there a key pane?
299   */
300  public boolean isKeyPane() {
301    return (keyPane_ != null);
302  }
303  /**
304   * Add data to the layout.  Where data is added is dependent on the
305   * specific layout. Additional layers will be created as required.
306   *
307   * @param data data to be added
308   */
309  public void addData(SGTData data) {
310    data_.addElement(data);
311  }
312  /**
313   * Associate <code>SGTData</code> with an
314   * <code>Attribute</code>. The associations are managed by a
315   * <code>Hashtable</code> object.
316   */
317  public void addAttribute(SGTData data, Attribute attr) {
318    dataAttrMap_.put(data, attr);
319  }
320  /**
321   * Find an <code>Attribute</code> given a <code>SGTData</code>
322   * object.
323   */
324  public Attribute getAttribute(SGTData data)
325    throws DataNotFoundException {
326    Attribute attr = (Attribute)dataAttrMap_.get(data);
327    if(attr == null) {
328      throw new DataNotFoundException();
329    }
330    return attr;
331  }
332  /**
333   * Find an <code>Attribute</code> given an id.
334   *
335   * @since 3.0
336   */
337  public Attribute findAttribute(String id) {
338    Attribute attr = null;
339    Enumeration e = dataAttrMap_.elements();
340    while(e.hasMoreElements()) {
341      attr = (Attribute)e.nextElement();
342      if(attr.getId().equals(id)) return attr;
343    }
344    return attr;
345  }
346  /**
347   * Add data to the plot
348   */
349  public abstract void addData(SGTData data, String label);
350  /**
351   * Construct a string that summarizes the location of the data.
352   */
353  public abstract String getLocationSummary(SGTData grid);
354  /**
355   * Find the range of the <code>SGTLine</code> object in the specific
356   * direction.
357   *
358   * @param data SGTLine object
359   * @param dir direction
360   * @see CartesianGraph
361   */
362  public Range2D findRange(SGTLine data, int dir) {
363    int num, i, first=0;
364    double amin=0.0, amax=0.0;
365    double[] values;
366    boolean good = false;
367
368    switch(dir) {
369    case X_AXIS:
370      values = data.getXArray();
371      num = values.length;
372      break;
373    default:
374    case Y_AXIS:
375      values = data.getYArray();
376      num = values.length;
377    }
378    for(i=0; i < num; i++) {
379      if(!Double.isNaN(values[i])) {
380        amin = (double)values[i];
381        amax = (double)values[i];
382        good = true;
383        first = i+1;
384        break;
385      }
386    }
387    if(!good) {
388      return new Range2D(Double.NaN, Double.NaN);
389    } else {
390      for(i=first; i < num; i++) {
391        if(!Double.isNaN(values[i])) {
392          amin = Math.min(amin, (double)values[i]);
393          amax = Math.max(amax, (double)values[i]);
394        }
395      }
396    }
397    return new Range2D(amin, amax);
398  }
399  /**
400   * Find the range of the <code>SGTLine</code> object in the specific
401   * direction.
402   *
403   * @param data SGTLine object
404   * @param dir direction
405   * @return range as an <code>SoTRange</code> object
406   * @see CartesianGraph
407   */
408  public SoTRange findSoTRange(SGTLine line, int dir) {
409    switch(dir) {
410    case X_AXIS:
411      return line.getXRange();
412    case Y_AXIS:
413      return line.getYRange();
414    default:
415      return null;
416    }
417  }
418  /**
419   * Find the range of the <code>SGTVector</code> object in the
420   * specified direction.  Uses the U component to find X, Y ranges.
421   *
422   * @param data the data vector
423   * @param dir the direction
424   * @return range as an <code>SoTRange</code> object
425   */
426  public SoTRange findSoTRange(SGTVector data, int dir) {
427    double[] veclen;
428    int num, i, first = 0;
429    double amin = 0.0, amax = 0.0;
430    boolean good = false;
431
432    switch(dir) {
433    case X_AXIS:
434      return data.getU().getXRange();
435    case Y_AXIS:
436      return data.getU().getYRange();
437    default:
438    case Z_AXIS:
439      double[] ucomp = data.getU().getZArray();
440      double[] vcomp = data.getV().getZArray();
441      veclen = new double[ucomp.length];
442      for(i=0; i < veclen.length; i++) {
443        veclen[i] = Math.sqrt(ucomp[i]*ucomp[i] + vcomp[i]*vcomp[i]);
444      }
445      num = veclen.length;
446    }
447    for(i=0; i < num; i++) {
448      if(!Double.isNaN(veclen[i])) {
449        amin = (double)veclen[i];
450        amax = (double)veclen[i];
451        good = true;
452        first = i+1;
453        break;
454      }
455    }
456    if(!good) {
457      return new SoTRange.Double(Double.NaN, Double.NaN);
458    } else {
459      for(i=first; i < num; i++) {
460        if(!Double.isNaN(veclen[i])) {
461          amin = Math.min(amin, (double)veclen[i]);
462          amax = Math.max(amax, (double)veclen[i]);
463        }
464      }
465    }
466    return new SoTRange.Double(amin, amax);
467  }
468  /**
469   * Find the range of the <code>SGTGrid</code> object in the
470   * specified direction.
471   *
472   * @param data the data grid
473   * @param attr the grid attribute
474   * @param dir the direction
475   * @return range as an <code>SoTRange</code> object
476   */
477  public SoTRange findSoTRange(SGTGrid data, GridAttribute attr, int dir) {
478    int num, onum, i, first=0;
479    double amin=0.0, amax=0.0;
480    GeoDate tmin, tmax;
481    double[] values, orig;
482    GeoDate[] taxis, torig;
483    boolean good = false;
484
485    if(attr.isRaster() &&
486       ((data.isXTime() && (dir == X_AXIS) && !data.hasXEdges()) ||
487            (data.isYTime() && (dir == Y_AXIS) && !data.hasYEdges()))) {
488        torig = data.getTimeArray();
489        onum = torig.length;
490        taxis = new GeoDate[onum+1];
491        taxis[0] = torig[0].subtract(
492                   (torig[1].subtract(torig[0])).divide(2.0));
493        for(i=1; i < onum; i++) {
494          taxis[i] = (torig[i-1].add(torig[i])).divide(2.0);
495        }
496        taxis[onum] = torig[onum-1].add(
497                      (torig[onum-1].subtract(torig[onum-2])).divide(2.0));
498        num = taxis.length;
499        return new SoTRange.Time(taxis[0].getTime(),
500                                 taxis[num-1].getTime());
501    }
502
503    switch(dir) {
504    case X_AXIS:
505      if(attr.isRaster()) {
506        if(data.hasXEdges()) {
507          return data.getXEdgesRange();
508        } else {
509          orig = data.getXArray();
510          onum = orig.length;
511          values = new double[onum+1];
512          values[0] = orig[0]-(orig[1]-orig[0])*0.5;
513          for(i=1; i < onum; i++) {
514            values[i] = (orig[i-1]+orig[i])*0.5;
515          }
516          values[onum] = orig[onum-1]+(orig[onum-1]-orig[onum-2])*0.5;
517          num = values.length;
518        }
519      } else {
520        return data.getXRange();
521      }
522      break;
523    case Y_AXIS:
524      if(attr.isRaster()) {
525        if(data.hasYEdges()) {
526          return data.getYEdgesRange();
527        } else {
528          orig = data.getYArray();
529          onum = orig.length;
530          values = new double[onum+1];
531          values[0] = orig[0]-(orig[1]-orig[0])*0.5;
532          for(i=1; i < onum; i++) {
533            values[i] = (orig[i-1]+orig[i])*0.5;
534          }
535          values[onum] = orig[onum-1]+(orig[onum-1]-orig[onum-2])*0.5;
536          num = values.length;
537        }
538      } else {
539        return data.getYRange();
540      }
541      break;
542    default:
543    case Z_AXIS:
544      values = data.getZArray();
545      num = values.length;
546    }
547    for(i=0; i < num; i++) {
548      if(!Double.isNaN(values[i])) {
549        amin = (double)values[i];
550        amax = (double)values[i];
551        good = true;
552        first = i+1;
553        break;
554      }
555    }
556    if(!good) {
557      return new SoTRange.Double(Double.NaN, Double.NaN);
558    } else {
559      for(i=first; i < num; i++) {
560        if(!Double.isNaN(values[i])) {
561          amin = Math.min(amin, (double)values[i]);
562          amax = Math.max(amax, (double)values[i]);
563        }
564      }
565    }
566    return new SoTRange.Double(amin, amax);
567  }
568  /**
569   * Find the range of the <code>SGTGrid</code> object in the
570   * specified direction.
571   *
572   * @param data the data grid
573   * @param attr the grid attribute
574   * @param dir the direction
575   */
576  public Range2D findRange(SGTGrid data, GridAttribute attr, int dir) {
577    int num, onum, i, first=0;
578    double amin=0.0, amax=0.0;
579    double[] values, orig;
580    boolean good = false;
581
582    switch(dir) {
583    case X_AXIS:
584      if(attr.isRaster()) {
585        if(data.hasXEdges()) {
586          values = data.getXEdges();
587          num = values.length;
588        } else {
589          orig = data.getXArray();
590          onum = orig.length;
591          values = new double[onum+1];
592          values[0] = orig[0]-(orig[1]-orig[0])*0.5;
593          for(i=1; i < onum; i++) {
594            values[i] = (orig[i-1]+orig[i])*0.5;
595          }
596          values[onum] = orig[onum-1]+(orig[onum-1]-orig[onum-2])*0.5;
597          num = values.length;
598        }
599      } else {
600        values = data.getXArray();
601        num = values.length;
602      }
603      break;
604    case Y_AXIS:
605      if(attr.isRaster()) {
606        if(data.hasYEdges()) {
607          values = data.getYEdges();
608          num = values.length;
609        } else {
610          orig = data.getYArray();
611          onum = orig.length;
612          values = new double[onum+1];
613          values[0] = orig[0]-(orig[1]-orig[0])*0.5;
614          for(i=1; i < onum; i++) {
615            values[i] = (orig[i-1]+orig[i])*0.5;
616          }
617          values[onum] = orig[onum-1]+(orig[onum-1]-orig[onum-2])*0.5;
618          num = values.length;
619        }
620      } else {
621        values = data.getYArray();
622        num = values.length;
623      }
624      break;
625    default:
626    case Z_AXIS:
627      values = data.getZArray();
628      num = values.length;
629    }
630    for(i=0; i < num; i++) {
631      if(!Double.isNaN(values[i])) {
632        amin = (double)values[i];
633        amax = (double)values[i];
634        good = true;
635        first = i+1;
636        break;
637      }
638    }
639    if(!good) {
640      return new Range2D(Double.NaN, Double.NaN);
641    } else {
642      for(i=first; i < num; i++) {
643        if(!Double.isNaN(values[i])) {
644          amin = Math.min(amin, (double)values[i]);
645          amax = Math.max(amax, (double)values[i]);
646        }
647      }
648    }
649    return new Range2D(amin, amax);
650  }
651  /**
652   * Find the time range of the <code>SGTLine</code> object.
653   *
654   * @param data SGTLine object
655   * @see CartesianGraph
656   */
657  public TimeRange findTimeRange(SGTLine data) {
658    long taxis[];
659    int num;
660
661    taxis = data.getGeoDateArray().getTime();
662    num = taxis.length;
663    return new TimeRange(taxis[0], taxis[num-1]);
664  }
665  /**
666   * Find the <code>TimeRange</code> of the <code>SGTGrid</code> object.
667   *
668   * @param data the data grid
669   * @param attr the grid attribute
670   * @param dir the direction
671   */
672  public TimeRange findTimeRange(SGTGrid data, GridAttribute attr) {
673    long tmin, tmax;
674    long taxis[], orig[];
675    int num, onum, i;
676
677    if(attr.isRaster() && (data.isXTime() || data.isYTime())) {
678      if(data.hasXEdges() || data.hasYEdges()) {
679        taxis = data.getGeoDateArrayEdges().getTime();
680      } else {
681        orig = data.getGeoDateArray().getTime();
682        onum = orig.length;
683        taxis = new long[onum+1];
684        taxis[0] = orig[0] - (orig[1]-orig[0])/2;
685        for(i=1; i < onum; i++) {
686          taxis[i] = (orig[i-1] + orig[i])/2;
687        }
688        taxis[onum] = orig[onum-1] + (orig[onum-1] - orig[onum-2])/2;
689      }
690    } else {
691      taxis = data.getGeoDateArray().getTime();
692    }
693    num = taxis.length;
694    return new TimeRange(taxis[0], taxis[num-1]);
695  }
696  /**
697   * Set clipping on or off. If clipping is on, clip to the
698   * axes range.
699   *
700   * @param clip true if clipping is on
701   */
702  public void setClipping(boolean clip) {
703    clipping_ = clip;
704  }
705  /**
706   * Returns true if clipping is on.
707   *
708   * @return true if clipping is on
709   */
710  public boolean isClipping() {
711    return clipping_;
712  }
713  /**
714   * Set the axes to the range of the <code>SGTData</code> objects.
715   */
716  abstract public void resetZoom();
717  /**
718   * Set the axes to to range specified by the <code>Domain</code>
719   * object.
720   */
721  abstract public void setRange(Domain domain) throws PropertyVetoException;
722  /**
723   * Get the current <code>Domain</code>
724   */
725  public Domain getRange() {
726    Domain domain = new Domain();
727    Range2D xr = new Range2D();
728    Range2D yr = new Range2D();
729//    TimeRange tr = new TimeRange();
730    Layer layer = getFirstLayer();
731    Graph graph = layer.getGraph();
732    if(graph instanceof CartesianGraph) {
733      CartesianGraph cg = (CartesianGraph)graph;
734      AxisTransform xt = cg.getXTransform();
735      AxisTransform yt = cg.getYTransform();
736      if(xt.isTime()) {
737        domain.setXRange(xt.getTimeRangeU());
738      } else {
739        domain.setXRange(xt.getRangeU());
740      }
741      if(yt.isTime()) {
742        domain.setYRange(yt.getTimeRangeU());
743      } else {
744        domain.setYRange(yt.getRangeU());
745      }
746    }
747    return domain;
748  }
749  /**
750   * Get the zoom bounds in user units
751   */
752  public Domain getZoomBoundsU() {
753    Domain domain = new Domain();
754    Range2D xr = new Range2D();
755    Range2D yr = new Range2D();
756    long start, end;
757
758    Rectangle zoom = getZoomBounds();
759    Layer layer = getFirstLayer();
760    Graph graph = layer.getGraph();
761
762    if(graph instanceof CartesianGraph) {
763      CartesianGraph cg = (CartesianGraph)graph;
764      AxisTransform xt = cg.getXTransform();
765      AxisTransform yt = cg.getYTransform();
766      if(xt.isSpace()) {
767        xr.start = cg.getXPtoU(layer.getXDtoP(zoom.x));
768        xr.end = cg.getXPtoU(layer.getXDtoP(zoom.x + zoom.width));
769        if(xr.start > xr.end) {
770          double temp = xr.start;
771          xr.start = xr.end;
772          xr.end = temp;
773        }
774        domain.setXRange(xr);
775      } else {
776        start = cg.getXPtoLongTime(layer.getXDtoP(zoom.x));
777        end = cg.getXPtoLongTime(layer.getXDtoP(zoom.x + zoom.width));
778        if(start > end) {
779          long tmp = start;
780          start = end;
781          end = tmp;
782        }
783        domain.setXRange(new TimeRange(new GeoDate(start), new GeoDate(end)));
784      }
785      if(yt.isSpace()) {
786        yr.start = cg.getYPtoU(layer.getYDtoP(zoom.y));
787        yr.end = cg.getYPtoU(layer.getYDtoP(zoom.y + zoom.height));
788        if(yr.start > yr.end) {
789          double temp = yr.start;
790          yr.start = yr.end;
791          yr.end = temp;
792        }
793        domain.setYRange(yr);
794      } else {
795        start = cg.getYPtoLongTime(layer.getYDtoP(zoom.y));
796        end = cg.getYPtoLongTime(layer.getYDtoP(zoom.y + zoom.height));
797        if(start > end) {
798          long tmp = start;
799          start = end;
800          end = tmp;
801        }
802        domain.setYRange(new TimeRange(new GeoDate(start), new GeoDate(end)));
803      }
804    }
805    return domain;
806  }
807  /**
808   * return a formated string summarizing the latitude
809   */
810  protected String getLatString(double lat) {
811    if(lat == 0.0) return "Eq";
812    DecimalFormat dfLat = new DecimalFormat("##.##N;##.##S");
813    return dfLat.format(lat);
814  }
815  /**
816   * return a formated string summarizing the longitude
817   */
818  protected String getLonString(double lond) {
819    /* positive west */
820    String str;
821    DecimalFormat dfLon = new DecimalFormat("###.##W;###.##");
822    double lon = (lond + 360.0) % 360.0;
823    dfLon.setNegativeSuffix("E");
824    if(lon > 180.0) {
825      lon = 360.0 - lon;
826    }
827    return dfLon.format(lon);
828  }
829  /**
830   * Return data associated with the plot.
831   *
832   * @return data in a <code>Collection</code>
833   */
834  public Collection getData() {
835    Collection col = new Collection(ident_ + " Data Collection",
836                                    data_.size());
837    for(Enumeration e = data_.elements(); e.hasMoreElements(); ) {
838      col.addElement(e.nextElement());
839    }
840    return col;
841  }
842
843  class SymMouse extends java.awt.event.MouseAdapter  {
844    public void mousePressed(java.awt.event.MouseEvent event) {
845      if(!isMouseEventsEnabled()) return;
846      Object object = event.getSource();
847      if (object == me_)
848        Layout_MousePress(event);
849      else if (object == keyPane_)
850        KeyPane_MousePress(event);
851    }
852
853    public void mouseClicked(java.awt.event.MouseEvent event) {
854      if(!isMouseEventsEnabled()) return;
855      Object object = event.getSource();
856      if (object == me_)
857        Layout_MouseClicked(event);
858      else if (object == keyPane_)
859        KeyPane_MouseClicked(event);
860    }
861
862    public void mouseReleased(java.awt.event.MouseEvent event) {
863      if(!isMouseEventsEnabled()) return;
864      Object object = event.getSource();
865      if (object == me_)
866        Layout_MouseRelease(event);
867    }
868  }
869
870  void Layout_MouseRelease(java.awt.event.MouseEvent event) {
871    //
872    // continue only if button1 is pressed
873    //
874    if((event.getModifiers()&InputEvent.BUTTON1_MASK) == 0) return;
875
876    Rectangle zm = getZoomBounds();
877    if(zm.width <= 1 || zm.height <= 1) return;
878
879    Domain zoom = getZoomBoundsU();
880
881    setClipping(true);
882
883    if(getFirstLayer().getGraph() instanceof CartesianGraph) {
884      try {
885        setRange(zoom);
886      } catch (PropertyVetoException e) {
887        System.out.println("Zoom denied! " + e);
888      }
889    }
890    //    draw();
891  }
892
893  void Layout_MousePress(java.awt.event.MouseEvent event) {
894    if(event.isControlDown()) {
895      resetZoom();
896      setClipping(false);
897      //      draw();
898    }
899  }
900
901  void Layout_MouseClicked(java.awt.event.MouseEvent event) {
902    if(event.isControlDown()) return;
903    Object obj = getSelectedObject();
904    if(obj instanceof LineCartesianRenderer) {
905      LineCartesianRenderer line = (LineCartesianRenderer)obj;
906      LineAttribute attr = line.getLineAttribute();
907      if(attr.getStyle() == LineAttribute.SOLID) {
908        attr.setStyle(LineAttribute.HIGHLIGHT);
909      } else if(attr.getStyle() == LineAttribute.HIGHLIGHT) {
910        attr.setStyle(LineAttribute.SOLID);
911      }
912      //      draw();
913    }
914
915    if(((event.getModifiers()&InputEvent.BUTTON3_MASK) != 0) &&
916       editClasses_) {
917      showProperties(obj);
918    }
919  }
920
921  void KeyPane_MousePress(java.awt.event.MouseEvent event) {
922  }
923
924  void KeyPane_MouseClicked(java.awt.event.MouseEvent event) {
925    if(keyPane_ == null) return;
926    Object obj = keyPane_.getSelectedObject();
927    if(obj instanceof LineCartesianRenderer) {
928      LineCartesianRenderer line = (LineCartesianRenderer)obj;
929      LineAttribute attr = line.getLineAttribute();
930      if(attr.getStyle() == LineAttribute.SOLID) {
931        attr.setStyle(LineAttribute.HIGHLIGHT);
932      } else if(attr.getStyle() == LineAttribute.HIGHLIGHT) {
933        attr.setStyle(LineAttribute.SOLID);
934      }
935      //      draw();
936      //      keyPane_.draw();
937    }
938    if(editClasses_) {
939      showProperties(obj);
940    }
941  }
942  /**
943   * Enable <code>sgt</code> object property editing
944   */
945  public void setEditClasses(boolean b) {
946    editClasses_ = b;
947  }
948  /**
949   * Are <code>sgt</code> objects editable?
950   */
951  public boolean isEditClasses() {
952    return editClasses_;
953  }
954  /**
955   * Determine if the object selected is an SGLabel, PlainAxis, or
956   * TimeAxis. Depending on the answer create the appropriate dialog.
957   */
958  void showProperties(Object obj) {
959    if(obj instanceof SGLabel) {
960      if(sg_props_ == (SGLabelDialog) null) {
961        //
962        // create the SGLabelDialog
963        //
964        sg_props_ = new SGLabelDialog();
965      }
966      sg_props_.setSGLabel((SGLabel) obj, this);
967      if(!sg_props_.isShowing())
968        sg_props_.show();
969    } else if(obj instanceof PlainAxis) {
970      if(pa_props_ == (SpaceAxisDialog) null) {
971        //
972        // create the PlainAxis dialog
973        //
974        pa_props_ = new SpaceAxisDialog();
975      }
976      pa_props_.setSpaceAxis((PlainAxis) obj, this);
977      if(!pa_props_.isShowing())
978        pa_props_.show();
979    } else if(obj instanceof TimeAxis) {
980      if(ta_props_ == (TimeAxisDialog) null) {
981        //
982        // create the TimeAxis Dialog
983        //
984        ta_props_ = new TimeAxisDialog();
985      }
986      ta_props_.setTimeAxis((TimeAxis) obj, this);
987      if(!ta_props_.isShowing())
988        ta_props_.show();
989    } else if (obj instanceof Logo) {
990      if(lo_props_ == (LogoDialog) null) {
991        //
992        // create the LogoProperties dialog
993        //
994        lo_props_ = new LogoDialog();
995      }
996      lo_props_.setLogo((Logo) obj, this);
997      if(!lo_props_.isShowing())
998        lo_props_.show();
999    }
1000  }
1001
1002  private Frame getFrame() {
1003    Container theFrame = this;
1004    do {
1005      theFrame = theFrame.getParent();
1006    } while ((theFrame != null) && !(theFrame instanceof Frame));
1007    if (theFrame == null)
1008      theFrame = new Frame();
1009    return (Frame) theFrame;
1010  }
1011  /**
1012   * Set the clip range for all <code>Layer</code>s.
1013   */
1014  protected void setAllClip(SoTRange xr, SoTRange yr) {
1015    if(yr.isTime()) {
1016      setAllClip(yr.getStart().getLongTime(),
1017                 yr.getEnd().getLongTime(),
1018                 ((SoTRange.Double)xr).start,
1019                 ((SoTRange.Double)xr).end);
1020    } else {
1021      if(xr.isTime()) {
1022        setAllClip(xr.getStart().getLongTime(),
1023                   xr.getEnd().getLongTime(),
1024                   ((SoTRange.Double)yr).start,
1025                   ((SoTRange.Double)yr).end);
1026      } else {
1027        setAllClip(((SoTRange.Double)xr).start,
1028                   ((SoTRange.Double)xr).end,
1029                   ((SoTRange.Double)yr).start,
1030                   ((SoTRange.Double)yr).end);
1031      }
1032    }
1033  }
1034
1035  /**
1036   * Set the clip range for all <code>Layer</code>s.
1037   */
1038  protected void setAllClip(double xmin, double xmax, double ymin, double ymax) {
1039    Layer ly;
1040    Component[] comps = getComponents();
1041    for(int i=0; i < comps.length; i++) {
1042      if(comps[i] instanceof Layer) {
1043        ly = (Layer)comps[i];
1044        ((CartesianGraph)ly.getGraph()).setClip(xmin, xmax, ymin, ymax);
1045      }
1046    }
1047  }
1048  /**
1049   * Set the clip range for all <code>Layer</code>s.
1050   */
1051  protected void setAllClip(GeoDate tmin, GeoDate tmax, double min, double max) {
1052//    System.out.println("setAllClip(" + tmin + ", " + tmax + ", " + min + ", " + max + ")");
1053    setAllClip(tmin.getTime(), tmax.getTime(), min, max);
1054/*    Layer ly;
1055    Component[] comps = getComponents();
1056    for(int i=0; i < comps.length; i++) {
1057      if(comps[i] instanceof Layer) {
1058        ly = (Layer)comps[i];
1059        ((CartesianGraph)ly.getGraph()).setClip(tmin, tmax, min, max);
1060      }
1061    } */
1062  }
1063  /**
1064   * @since 3.0
1065   */
1066  protected void setAllClip(long tmin, long tmax, double min, double max) {
1067//    System.out.println("setAllClip(" + tmin + ", " + tmax + ", " + min + ", " + max + ")");
1068    Layer ly;
1069    Component[] comps = getComponents();
1070    for(int i=0; i < comps.length; i++) {
1071      ly = (Layer)comps[i];
1072      ((CartesianGraph)ly.getGraph()).setClip(tmin, tmax, min, max);
1073    }
1074  }
1075  /**
1076   * Turn on clipping for all <code>Layer</code>s.
1077   */
1078  protected void setAllClipping(boolean clip) {
1079    Layer ly;
1080    Component[] comps = getComponents();
1081    for(int i=0; i < comps.length; i++) {
1082      if(comps[i] instanceof Layer) {
1083        ly = (Layer)comps[i];
1084        ((CartesianGraph)ly.getGraph()).setClipping(clip);
1085      }
1086    }
1087  }
1088  /**
1089   * Get the bounds for the line or color key.
1090   */
1091  public abstract Rectangle2D.Double getKeyBoundsP();
1092  /**
1093   * Set the bounds for the line or color key.
1094   */
1095  public abstract void setKeyBoundsP(Rectangle2D.Double r);
1096  /**
1097   * Get the size of the key layer in physical coordinates.
1098   */
1099  public Dimension2D getKeyLayerSizeP() {
1100    if(keyPane_ != null) {
1101      return keyPane_.getFirstLayer().getSizeP();
1102    }
1103    return null;
1104  }
1105  /**
1106   * Set the size of the key layer in physical coordinates.
1107   */
1108  public void setKeyLayerSizeP(Dimension2D d) {
1109    if(keyPane_ != null) {
1110      keyPane_.getFirstLayer().setSizeP(d);
1111    }
1112  }
1113  public void addVetoableChangeListener(VetoableChangeListener l) {
1114    vetos_.addVetoableChangeListener(l);
1115  }
1116  public void removeVetoableChangeListener(VetoableChangeListener l) {
1117    vetos_.removeVetoableChangeListener(l);
1118  }
1119  public void addPropertyChangeListener(PropertyChangeListener l) {
1120    changes_.addPropertyChangeListener(l);
1121  }
1122  public void removePropertyChangeListener(PropertyChangeListener l) {
1123    changes_.removePropertyChangeListener(l);
1124  }
1125}
Note: See TracBrowser for help on using the repository browser.