001 /*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2013
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 *
010 * All Rights Reserved
011 *
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.
014 *
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 *
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023 * GNU Lesser Public License for more details.
024 *
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program. If not, see http://www.gnu.org/licenses.
027 */
028
029 package edu.wisc.ssec.mcidasv.control.cyclone;
030
031 import java.awt.BorderLayout;
032 import java.awt.Dimension;
033 import java.awt.Insets;
034 import java.awt.event.ActionEvent;
035 import java.awt.event.ActionListener;
036 import java.util.ArrayList;
037 import java.util.Hashtable;
038 import java.util.List;
039 import java.util.Vector;
040
041 import javax.swing.BorderFactory;
042 import javax.swing.JButton;
043 import javax.swing.JCheckBox;
044 import javax.swing.JComponent;
045 import javax.swing.JLabel;
046 import javax.swing.JList;
047 import javax.swing.JPanel;
048 import javax.swing.JScrollPane;
049 import javax.swing.ListSelectionModel;
050 import javax.swing.event.ListSelectionEvent;
051 import javax.swing.event.ListSelectionListener;
052
053 import ucar.unidata.data.storm.StormDataSource;
054 import ucar.unidata.data.storm.StormParam;
055 import ucar.unidata.data.storm.StormTrack;
056 import ucar.unidata.data.storm.StormTrackPoint;
057 import ucar.unidata.data.storm.Way;
058 import ucar.unidata.idv.control.chart.LineState;
059 import ucar.unidata.idv.control.chart.TimeSeriesChart;
060 import ucar.unidata.util.GuiUtils;
061 import ucar.unidata.util.Misc;
062 import ucar.unidata.util.Range;
063 import ucar.unidata.util.TwoFacedObject;
064 import visad.DateTime;
065 import visad.Real;
066 import visad.RealType;
067 import visad.Unit;
068
069 /**
070 *
071 * @author Unidata Development Team
072 * @version $Revision$
073 */
074
075 public class StormTrackChart {
076
077 /** _more_ */
078 public static final int MODE_FORECASTTIME = 0;
079
080 /** _more_ */
081 public static final int MODE_FORECASTHOUR = 1;
082
083 /** _more_ */
084 private StormDisplayState stormDisplayState;
085
086 /** _more_ */
087 private int mode;
088
089 /** _more_ */
090 private TimeSeriesChart timeSeries;
091
092 /** _more_ */
093 private JPanel chartLeft;
094
095 /** _more_ */
096 private JPanel chartTop;
097
098 /** _more_ */
099 private boolean madeChart = false;
100
101 /** _more_ */
102 private List<DateTime> forecastTimes;
103
104 /** _more_ */
105 private List<Integer> forecastHours;
106
107 /** _more_ */
108 private List<StormParam> chartParams = new ArrayList<StormParam>();
109
110 /** _more_ */
111 private List<Way> chartWays = new ArrayList();
112
113 /** _more_ */
114 private boolean chartDifference = false;
115
116 /** _more_ */
117 private JList chartTimeBox;
118
119 /** _more_ */
120 private boolean ignoreChartTimeChanges = false;
121
122 /** _more_ */
123 private JComponent contents;
124
125 /** _more_ */
126 private String name;
127
128 /**
129 * _more_
130 */
131 public StormTrackChart() {
132 }
133
134 /**
135 * _more_
136 *
137 * @param stormDisplayState
138 * _more_
139 * @param name
140 * _more_
141 *
142 */
143 public StormTrackChart(StormDisplayState stormDisplayState, String name) {
144 this(stormDisplayState, name, MODE_FORECASTTIME);
145 }
146
147 /**
148 * _more_
149 *
150 * @param stormDisplayState
151 * _more_
152 * @param name
153 * _more_
154 * @param mode
155 * _more_
156 */
157 public StormTrackChart(StormDisplayState stormDisplayState, String name,
158 int mode) {
159 this.stormDisplayState = stormDisplayState;
160 this.name = name;
161 this.mode = mode;
162 }
163
164 /**
165 * _more_
166 *
167 * @return _more_
168 */
169 protected boolean isHourly() {
170 return mode == MODE_FORECASTHOUR;
171 }
172
173 /**
174 * _more_
175 */
176 public void deactivate() {
177 madeChart = false;
178 contents = null;
179 }
180
181 /**
182 * _more_
183 *
184 * @return _more_
185 */
186 protected JComponent getContents() {
187 if (contents == null) {
188 contents = doMakeContents();
189 }
190 return contents;
191 }
192
193 /**
194 * _more_
195 *
196 * @return _more_
197 */
198 private JComponent doMakeContents() {
199 chartTop = new JPanel(new BorderLayout());
200 chartLeft = new JPanel(new BorderLayout());
201 JComponent chartComp = GuiUtils.leftCenter(chartLeft, GuiUtils
202 .topCenter(chartTop, getChart().getContents()));
203 return chartComp;
204 }
205
206 /**
207 * Get the chart
208 *
209 * @return The chart_
210 */
211 public TimeSeriesChart getChart() {
212 if (timeSeries == null) {
213 timeSeries = new TimeSeriesChart(stormDisplayState
214 .getStormTrackControl(), "Track Charts") {
215 protected void makeInitialChart() {
216 }
217 };
218 // TODO make this work:
219 // timeSeries.setAlwaysShowFirstChart(false);
220 timeSeries.showAnimationTime(true);
221 timeSeries.setDateFormat("MM/dd HH:mm z");
222 }
223 return timeSeries;
224 }
225
226 /**
227 * _more_
228 *
229 * @param time
230 * _more_
231 */
232 protected void timeChanged(Real time) {
233 getChart().timeChanged();
234 }
235
236 /**
237 * _more_
238 *
239 * @return _more_
240 */
241 private List<DateTime> findForecastTimes() {
242 List<DateTime> forecastTimes = new ArrayList<DateTime>();
243 Hashtable seenForecastTime = new Hashtable();
244 for (StormTrack track : stormDisplayState.getTrackCollection()
245 .getTracks()) {
246 if (track.getWay().isObservation()) {
247 continue;
248 }
249 if (!chartWays.contains(track.getWay())) {
250 continue;
251 }
252 DateTime dttm = track.getStartTime();
253 if (seenForecastTime.get(dttm) == null) {
254 seenForecastTime.put(dttm, dttm);
255 forecastTimes.add(dttm);
256 }
257 }
258 return (List<DateTime>) Misc.sort(forecastTimes);
259 }
260
261 /**
262 * _more_
263 *
264 * @return _more_
265 */
266 private List<Integer> findForecastHours() {
267 List<Integer> forecastHours = new ArrayList<Integer>();
268 Hashtable seenForecastHour = new Hashtable();
269 Hashtable seen = new Hashtable();
270 for (StormTrack track : stormDisplayState.getTrackCollection()
271 .getTracks()) {
272 if (track.getWay().isObservation()) {
273 continue;
274 }
275 if (!chartWays.contains(track.getWay())) {
276 continue;
277 }
278 for (StormTrackPoint stormTrackPoint : track.getTrackPoints()) {
279 Integer forecastHour = new Integer(stormTrackPoint
280 .getForecastHour());
281 if (seenForecastHour.get(forecastHour) == null) {
282 seenForecastHour.put(forecastHour, forecastHour);
283 forecastHours.add(forecastHour);
284 }
285 }
286 }
287 return (List<Integer>) Misc.sort(forecastHours);
288 }
289
290 /**
291 * _more_
292 */
293 protected void createChart() {
294
295 if (madeChart) {
296 return;
297 }
298 madeChart = true;
299 final JCheckBox chartDiffCbx = new JCheckBox("Use Difference",
300 chartDifference);
301 chartDiffCbx.addActionListener(new ActionListener() {
302 public void actionPerformed(ActionEvent ae) {
303 chartDifference = chartDiffCbx.isSelected();
304 updateChart();
305 }
306 });
307
308 chartTimeBox = new JList();
309 chartTimeBox.setVisibleRowCount(3);
310 chartTimeBox
311 .setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
312 chartTimeBox.addListSelectionListener(new ListSelectionListener() {
313 public void valueChanged(ListSelectionEvent e) {
314 if (ignoreChartTimeChanges) {
315 return;
316 }
317
318 updateChart();
319 }
320 });
321
322 List<StormParam> params = getStormTrackParams();
323
324 Insets inset = new Insets(3, 7, 7, 0);
325 List chartComps = new ArrayList();
326
327 List<Way> ways = Misc.sort(stormDisplayState.getTrackCollection()
328 .getWayList());
329 List wayComps = new ArrayList();
330 for (Way way : ways) {
331 final Way theWay = way;
332 if (way.isObservation() && !chartWays.contains(way)) {
333 chartWays.add(way);
334 }
335 final JCheckBox cbx = new JCheckBox(way.toString(), chartWays
336 .contains(theWay));
337 cbx.addActionListener(new ActionListener() {
338 public void actionPerformed(ActionEvent ae) {
339 if (cbx.isSelected()) {
340 addChartWay(theWay);
341 } else {
342 removeChartWay(theWay);
343 }
344 }
345 });
346 if (!way.isObservation()) {
347 wayComps.add(cbx);
348 } else {
349 wayComps.add(0, cbx);
350 }
351 }
352
353 chartComps.add(new JLabel(stormDisplayState.getStormTrackControl()
354 .getWaysName()
355 + ":"));
356 JComponent chartWayComp = GuiUtils.vbox(wayComps);
357 if (wayComps.size() > 6) {
358 chartWayComp = makeScroller(chartWayComp, 100, 150);
359 }
360 chartComps.add(GuiUtils.inset(chartWayComp, inset));
361 chartComps.add(GuiUtils.lLabel((isHourly() ? "Forecast Hour:"
362 : "Forecast Time:")));
363 JScrollPane sp = new JScrollPane(chartTimeBox);
364 chartComps.add(GuiUtils.inset(sp, inset));
365
366 List paramComps = new ArrayList();
367 for (StormParam param : params) {
368 // if (param.getIsChartParam() == false) {
369 // continue;
370 // }
371 final StormParam theParam = param;
372 boolean useChartParam = chartParams.contains(theParam);
373 final JCheckBox cbx = new JCheckBox(param.toString(), useChartParam);
374 cbx.addActionListener(new ActionListener() {
375 public void actionPerformed(ActionEvent ae) {
376 if (cbx.isSelected()) {
377 addChartParam(theParam);
378 } else {
379 removeChartParam(theParam);
380 }
381 }
382 });
383 paramComps.add(cbx);
384 }
385 chartComps.add(new JLabel("Parameters:"));
386 JComponent paramComp = GuiUtils.vbox(paramComps);
387 if (paramComps.size() > 6) {
388 paramComp = makeScroller(paramComp, 100, 150);
389 }
390 chartComps.add(GuiUtils.inset(paramComp, inset));
391 chartComps.add(chartDiffCbx);
392
393 JButton removeBtn = GuiUtils.makeButton("Remove Chart", this,
394 "removeChart");
395 chartComps.add(GuiUtils.filler(5, 10));
396 chartComps.add(removeBtn);
397
398 // JComponent top = GuiUtils.left(GuiUtils.hbox(
399 // GuiUtils.label("Forecast Time: ", chartTimeBox),
400 // chartDiffCbx));
401 // top = GuiUtils.inset(top,5);
402 // chartTop.add(BorderLayout.NORTH, top);
403 JComponent left = GuiUtils.doLayout(chartComps, 1, GuiUtils.WT_N,
404 new double[] { 0, 1, 0, 1, 0 });
405 chartLeft.add(BorderLayout.CENTER, GuiUtils.inset(left, 5));
406
407 chartLeft.invalidate();
408 chartLeft.validate();
409 chartLeft.repaint();
410
411 }
412
413 /**
414 * _more_
415 *
416 * @return _more_
417 */
418 protected List getStormTrackParams() {
419 // Get the types from the first forecast track
420 List<StormParam> params = stormDisplayState.getStormChartParams();
421 if ((params == null) || (params.size() == 0)) {
422 for (StormTrack track : stormDisplayState.getTrackCollection()
423 .getTracks()) {
424 if (track == null) {
425 continue;
426 }
427 if (!track.isObservation()) {
428 params = track.getParams();
429 break;
430 }
431 }
432
433 // If we didn't get any from the forecast track use the obs track
434 if (params.size() == 0) {
435 StormTrack obsTrack = stormDisplayState.getTrackCollection()
436 .getObsTrack();
437 if (obsTrack != null) {
438 params = obsTrack.getParams();
439 }
440 }
441 }
442 return params;
443
444 }
445
446 /**
447 * _more_
448 */
449 public void removeChart() {
450 if (GuiUtils.askOkCancel("Remove Chart",
451 "Do you want to remove this chart?")) {
452 stormDisplayState.removeChart(this);
453
454 }
455
456 }
457
458 /**
459 * _more_
460 *
461 * @param comp
462 * _more_
463 * @param width
464 * _more_
465 * @param height
466 * _more_
467 *
468 * @return _more_
469 */
470 JScrollPane makeScroller(JComponent comp, int width, int height) {
471 JScrollPane scroller = GuiUtils.makeScrollPane(comp, width, height);
472 scroller.setBorder(BorderFactory.createLoweredBevelBorder());
473 scroller.setPreferredSize(new Dimension(width, height));
474 scroller.setMinimumSize(new Dimension(width, height));
475 return scroller;
476 }
477
478 /**
479 * _more_
480 *
481 * @param stormTrack
482 * _more_
483 * @param param
484 * _more_
485 *
486 * @return _more_
487 */
488 protected LineState makeLine(StormTrack stormTrack, StormParam param) {
489 List<Real> values = new ArrayList<Real>();
490 List<DateTime> times = stormTrack.getTrackTimes();
491 List<StormTrackPoint> trackPoints = stormTrack.getTrackPoints();
492 double min = 0;
493 double max = 0;
494 Unit unit = null;
495 for (int pointIdx = 0; pointIdx < times.size(); pointIdx++) {
496 Real value = trackPoints.get(pointIdx).getAttribute(param);
497 if (value == null) {
498 continue;
499 }
500 if (unit == null) {
501 unit = ((RealType) value.getType()).getDefaultUnit();
502 }
503 values.add(value);
504 double dvalue = value.getValue();
505 // System.err.print(","+dvalue);
506 if ((pointIdx == 0) || (dvalue > max)) {
507 max = dvalue;
508 }
509 if ((pointIdx == 0) || (dvalue < min)) {
510 min = dvalue;
511 }
512 }
513 if (values.size() == 0) {
514 return null;
515 }
516 // System.err.println("");
517 String paramLabel = param.toString();
518 String label = stormTrack.getWay().toString(); // +":" + paramLabel;
519 LineState lineState = new LineState();
520 lineState.setRangeIncludesZero(true);
521 if (stormTrack.getWay().isObservation()) {
522 lineState.setWidth(2);
523 } else {
524 lineState.setWidth(1);
525 }
526 lineState.setRange(new Range(min, max));
527 lineState.setChartName(paramLabel);
528 lineState.setAxisLabel("[" + unit + "]");
529
530 // System.err.println (param + " " +
531 // StormDataSource.TYPE_STORMCATEGORY);
532 if (Misc.equals(param, StormDataSource.PARAM_STORMCATEGORY)) {
533 // lineState.setShape(LineState.LINETYPE_BAR);
534 lineState.setLineType(LineState.LINETYPE_BAR);
535 lineState.setLineType(LineState.LINETYPE_AREA);
536 } else {
537 lineState.setLineType(LineState.LINETYPE_SHAPES_AND_LINES);
538 lineState.setShape(LineState.SHAPE_LARGEPOINT);
539 }
540
541 lineState.setColor(stormDisplayState.getWayDisplayState(
542 stormTrack.getWay()).getColor());
543 lineState.setName(label);
544 lineState.setTrack(times, values);
545 return lineState;
546
547 }
548
549 /**
550 * _more_
551 *
552 *
553 * @param param
554 * _more_
555 */
556 private void removeChartParam(StormParam param) {
557 while (chartParams.contains(param)) {
558 chartParams.remove(param);
559 }
560 updateChart();
561 }
562
563 /**
564 * _more_
565 *
566 *
567 * @param param
568 * _more_
569 */
570 private void addChartParam(StormParam param) {
571 if (!chartParams.contains(param)) {
572 chartParams.add(param);
573 }
574 updateChart();
575 }
576
577 /**
578 * _more_
579 *
580 * @param way
581 * _more_
582 */
583 private void removeChartWay(Way way) {
584 while (chartWays.contains(way)) {
585 chartWays.remove(way);
586 }
587 updateChart();
588 }
589
590 /**
591 * _more_
592 *
593 * @param way
594 * _more_
595 */
596 private void addChartWay(Way way) {
597 if (!chartWays.contains(way)) {
598 chartWays.add(way);
599 }
600 updateChart();
601 }
602
603 /**
604 * _more_
605 */
606 private void getSelectedTimes() {
607 if (isHourly()) {
608 Object[] selects = chartTimeBox.getSelectedValues();
609 if (forecastHours == null) {
610 forecastHours = new ArrayList();
611 }
612 for (int i = 0; i < selects.length; i++) {
613 Object select = selects[i];
614 TwoFacedObject tfo = (TwoFacedObject) select;
615 Integer hour = (Integer) tfo.getId();
616 forecastHours.add(hour);
617 }
618
619 } else {
620 forecastTimes = (List<DateTime>) Misc.toList(chartTimeBox
621 .getSelectedValues());
622
623 }
624 }
625
626 /**
627 * _more_
628 */
629 protected void updateChart() {
630
631 try {
632 if (!madeChart) {
633 createChart();
634 }
635 ignoreChartTimeChanges = true;
636
637 if (isHourly()) {
638 List<Integer> fHours = findForecastHours();
639 List<TwoFacedObject> tfos = new ArrayList<TwoFacedObject>();
640 for (Integer i : fHours) {
641 tfos.add(new TwoFacedObject(i + "H", i));
642 }
643
644 Object[] selected = chartTimeBox.getSelectedValues();
645 chartTimeBox.setListData(new Vector(tfos));
646 GuiUtils.setSelectedItems(chartTimeBox, Misc.toList(selected));
647
648 if ((selected == null) && (tfos.size() > 0)) {
649 TwoFacedObject selected0 = tfos.get(0);
650 forecastHours.add((Integer) selected0.getId());
651 }
652
653 // chartTimeBox.setSelectedItem(selected);
654 } else {
655 List<DateTime> fTimes = findForecastTimes();
656
657 Object[] selected = chartTimeBox.getSelectedValues();
658
659 chartTimeBox.setListData(new Vector(fTimes));
660 GuiUtils.setSelectedItems(chartTimeBox, Misc.toList(selected));
661
662 if ((selected == null) && (fTimes.size() > 0)) {
663 DateTime dt0 = fTimes.get(0);
664 forecastTimes.add(dt0);
665 }
666
667 // chartTimeBox.setSelectedItem(forecastTime);
668 }
669 ignoreChartTimeChanges = false;
670 getSelectedTimes();
671 chartTimeBox.repaint();
672 Hashtable<Way, List> wayToTracks = new Hashtable<Way, List>();
673 for (Way way : chartWays) {
674 wayToTracks.put(way, new ArrayList<Way>());
675 }
676
677 List<StormTrack> tracksToUse = new ArrayList<StormTrack>();
678 for (StormTrack track : stormDisplayState.getTrackCollection()
679 .getTracks()) {
680 List trackList = wayToTracks.get(track.getWay());
681 if (trackList == null) {
682 continue;
683 }
684 if (track.getWay().isObservation()) {
685 tracksToUse.add(track);
686 } else {
687 trackList.add(track);
688 }
689 }
690
691 StormTrack obsTrack = stormDisplayState.getTrackCollection()
692 .getObsTrack();
693
694 if (isHourly()) {
695 for (Way way : chartWays) {
696 List<StormTrack> tracksFromWay = wayToTracks.get(way);
697
698 for (Integer fHour : forecastHours) {
699 List<StormTrackPoint> points = new ArrayList<StormTrackPoint>();
700 for (StormTrack track : tracksFromWay) {
701 StormTrackPoint stp = track
702 .findPointWithForecastHour(fHour.intValue());
703 if (stp != null) {
704 // TODO: What time do we use???
705 points.add(stp);
706 }
707
708 }
709 if (points.size() > 0) {
710 points = (List<StormTrackPoint>) Misc.sort(points);
711 tracksToUse.add(new StormTrack(stormDisplayState
712 .getStormInfo(), way, points, null));
713 }
714 }
715 }
716
717 } else {
718 for (Way way : chartWays) {
719 List<StormTrack> tracksFromWay = wayToTracks.get(way);
720 for (StormTrack track : tracksFromWay) {
721 for (DateTime fTime : forecastTimes) {
722 if (Misc.equals(fTime, track.getStartTime())) {
723 tracksToUse.add(track);
724 }
725 }
726 }
727 }
728 }
729
730 List<LineState> lines = new ArrayList<LineState>();
731
732 for (StormParam param : chartParams) {
733 Hashtable seenWays = new Hashtable();
734 List<LineState> linesForParam = new ArrayList<LineState>();
735 for (StormTrack track : tracksToUse) {
736 LineState lineState = null;
737 if (chartDifference && param.getCanDoDifference()) {
738 if (track.getWay().isObservation()) {
739 continue;
740 }
741 track = StormDataSource.difference(obsTrack, track,
742 param);
743 if (track != null) {
744 lineState = makeLine(track, param);
745 }
746 } else {
747 lineState = makeLine(track, param);
748 }
749 if (lineState == null) {
750 continue;
751 }
752 // Only add it if there are values
753 if (lineState.getRange().getMin() == lineState.getRange()
754 .getMin()) {
755 if (seenWays.get(track.getWay()) != null) {
756 lineState.setVisibleInLegend(false);
757 } else {
758 seenWays.put(track.getWay(), "");
759 }
760
761 linesForParam.add(lineState);
762 }
763 }
764 double max = Double.NEGATIVE_INFINITY;
765 double min = Double.POSITIVE_INFINITY;
766 ;
767 for (LineState lineState : linesForParam) {
768 Range r = lineState.getRange();
769 min = Math.min(min, r.getMin());
770 max = Math.max(max, r.getMax());
771 }
772 // System.err.println(param + " min/max:" + min + "/" + max);
773 boolean first = true;
774 for (LineState lineState : linesForParam) {
775 lineState.setAxisVisible(first);
776 first = false;
777 lineState.setRange(new Range(min, max));
778 }
779 lines.addAll(linesForParam);
780 }
781 getChart().setTracks(lines);
782 } catch (Exception exc) {
783 stormDisplayState.getStormTrackControl().logException(
784 "Updating chart", exc);
785 }
786
787 }
788
789 /**
790 * Set the ChartParams property.
791 *
792 * @param value
793 * The new value for ChartParams
794 */
795 public void setChartParams(List<StormParam> value) {
796 chartParams = value;
797 }
798
799 /**
800 * Get the ChartParams property.
801 *
802 * @return The ChartParams
803 */
804 public List<StormParam> getChartParams() {
805 return chartParams;
806 }
807
808 /**
809 * Set the ChartWays property.
810 *
811 * @param value
812 * The new value for ChartWays
813 */
814 public void setChartWays(List<Way> value) {
815 chartWays = value;
816 }
817
818 /**
819 * Get the ChartWays property.
820 *
821 * @return The ChartWays
822 */
823 public List<Way> getChartWays() {
824 return chartWays;
825 }
826
827 /**
828 * Set the ChartForecastTime property.
829 *
830 * @param value
831 * The new value for ChartForecastTime
832 */
833 public void setForecastTime(DateTime value) {
834 forecastTimes = (List<DateTime>) Misc.newList(value);
835 }
836
837 /**
838 * _more_
839 *
840 * @param value
841 * _more_
842 */
843 public void setForecastTimes(List<DateTime> value) {
844 forecastTimes = value;
845 }
846
847 /**
848 * _more_
849 *
850 * @return _more_
851 */
852 public List<DateTime> getForecastTimes() {
853 return forecastTimes;
854 }
855
856 /**
857 * Set the ChartDifference property.
858 *
859 * @param value
860 * The new value for ChartDifference
861 */
862 public void setChartDifference(boolean value) {
863 chartDifference = value;
864 }
865
866 /**
867 * Get the ChartDifference property.
868 *
869 * @return The ChartDifference
870 */
871 public boolean getChartDifference() {
872 return chartDifference;
873 }
874
875 /**
876 * Set the Name property.
877 *
878 * @param value
879 * The new value for Name
880 */
881 public void setName(String value) {
882 name = value;
883 }
884
885 /**
886 * Get the Name property.
887 *
888 * @return The Name
889 */
890 public String getName() {
891 return name;
892 }
893
894 /**
895 * Set the StormDisplayState property.
896 *
897 * @param value
898 * The new value for StormDisplayState
899 */
900 public void setStormDisplayState(StormDisplayState value) {
901 stormDisplayState = value;
902 }
903
904 /**
905 * Get the StormDisplayState property.
906 *
907 * @return The StormDisplayState
908 */
909 public StormDisplayState getStormDisplayState() {
910 return stormDisplayState;
911 }
912
913 /**
914 * Set the Mode property.
915 *
916 * @param value
917 * The new value for Mode
918 */
919 public void setMode(int value) {
920 mode = value;
921 }
922
923 /**
924 * Get the Mode property.
925 *
926 * @return The Mode
927 */
928 public int getMode() {
929 return mode;
930 }
931
932 /**
933 * Set the ForecastHour property.
934 *
935 * @param value
936 * The new value for ForecastHour
937 */
938 public void setForecastHour(int value) {
939 forecastHours = (List<Integer>) Misc.newList(new Integer(value));
940 }
941
942 /**
943 * _more_
944 *
945 * @param value
946 * _more_
947 */
948 public void setForecastHours(List<Integer> value) {
949 forecastHours = value;
950 }
951
952 /**
953 * _more_
954 *
955 * @return _more_
956 */
957 public List<Integer> getForecastHours() {
958 return forecastHours;
959 }
960 }