001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2016 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 029package edu.wisc.ssec.mcidasv.control.cyclone; 030 031import java.awt.BorderLayout; 032import java.awt.Dimension; 033import java.awt.Insets; 034import java.awt.event.ActionEvent; 035import java.awt.event.ActionListener; 036import java.util.ArrayList; 037import java.util.Hashtable; 038import java.util.List; 039import java.util.Vector; 040 041import javax.swing.BorderFactory; 042import javax.swing.JButton; 043import javax.swing.JCheckBox; 044import javax.swing.JComponent; 045import javax.swing.JLabel; 046import javax.swing.JList; 047import javax.swing.JPanel; 048import javax.swing.JScrollPane; 049import javax.swing.ListSelectionModel; 050import javax.swing.event.ListSelectionEvent; 051import javax.swing.event.ListSelectionListener; 052 053import ucar.unidata.data.storm.StormDataSource; 054import ucar.unidata.data.storm.StormParam; 055import ucar.unidata.data.storm.StormTrack; 056import ucar.unidata.data.storm.StormTrackPoint; 057import ucar.unidata.data.storm.Way; 058import ucar.unidata.idv.control.chart.LineState; 059import ucar.unidata.idv.control.chart.TimeSeriesChart; 060import ucar.unidata.util.GuiUtils; 061import ucar.unidata.util.Misc; 062import ucar.unidata.util.Range; 063import ucar.unidata.util.TwoFacedObject; 064import visad.DateTime; 065import visad.Real; 066import visad.RealType; 067import visad.Unit; 068 069/** 070 * 071 * @author Unidata Development Team 072 * @version $Revision$ 073 */ 074 075public 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}