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