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.Color; 033 import java.awt.Component; 034 import java.awt.Dimension; 035 import java.awt.Font; 036 import java.awt.Insets; 037 import java.awt.event.ActionEvent; 038 import java.awt.event.ActionListener; 039 import java.awt.event.InputEvent; 040 import java.awt.event.KeyEvent; 041 import java.io.FileOutputStream; 042 import java.rmi.RemoteException; 043 import java.util.ArrayList; 044 import java.util.Hashtable; 045 import java.util.List; 046 import java.util.Vector; 047 048 import javax.swing.BorderFactory; 049 import javax.swing.JButton; 050 import javax.swing.JCheckBox; 051 import javax.swing.JComboBox; 052 import javax.swing.JComponent; 053 import javax.swing.JLabel; 054 import javax.swing.JList; 055 import javax.swing.JPanel; 056 import javax.swing.JScrollPane; 057 import javax.swing.JTabbedPane; 058 import javax.swing.JTable; 059 import javax.swing.JTree; 060 import javax.swing.ListSelectionModel; 061 import javax.swing.event.ListSelectionEvent; 062 import javax.swing.event.ListSelectionListener; 063 import javax.swing.table.JTableHeader; 064 import javax.swing.tree.DefaultTreeCellRenderer; 065 066 import org.apache.poi.hssf.usermodel.HSSFCell; 067 import org.apache.poi.hssf.usermodel.HSSFRichTextString; 068 import org.apache.poi.hssf.usermodel.HSSFRow; 069 import org.apache.poi.hssf.usermodel.HSSFSheet; 070 import org.apache.poi.hssf.usermodel.HSSFWorkbook; 071 import org.w3c.dom.Element; 072 073 import ucar.unidata.data.gis.KmlUtil; 074 import ucar.unidata.data.storm.StormInfo; 075 import ucar.unidata.data.storm.StormParam; 076 import ucar.unidata.data.storm.StormTrack; 077 import ucar.unidata.data.storm.StormTrackCollection; 078 import ucar.unidata.data.storm.StormTrackPoint; 079 import ucar.unidata.data.storm.Way; 080 import ucar.unidata.geoloc.LatLonPointImpl; 081 import ucar.unidata.geoloc.LatLonRect; 082 import ucar.unidata.idv.control.ColorTableWidget; 083 import ucar.unidata.idv.control.LayoutModelWidget; 084 import ucar.unidata.idv.flythrough.FlythroughPoint; 085 import ucar.unidata.ui.Command; 086 import ucar.unidata.ui.CommandManager; 087 import ucar.unidata.ui.TableSorter; 088 import ucar.unidata.ui.TreePanel; 089 import ucar.unidata.ui.colortable.ColorTableCanvas; 090 import ucar.unidata.ui.drawing.Glyph; 091 import ucar.unidata.ui.symbol.ShapeSymbol; 092 import ucar.unidata.ui.symbol.StationModel; 093 import ucar.unidata.ui.symbol.StationModelManager; 094 import ucar.unidata.util.ColorTable; 095 import ucar.unidata.util.DateUtil; 096 import ucar.unidata.util.FileManager; 097 import ucar.unidata.util.GuiUtils; 098 import ucar.unidata.util.IOUtil; 099 import ucar.unidata.util.Misc; 100 import ucar.unidata.util.PatternFileFilter; 101 import ucar.unidata.util.Range; 102 import ucar.visad.display.Animation; 103 import ucar.visad.display.CompositeDisplayable; 104 import ucar.visad.display.DisplayMaster; 105 import ucar.visad.display.Displayable; 106 import ucar.visad.display.DisplayableData; 107 import ucar.visad.display.LineDrawing; 108 import visad.CommonUnit; 109 import visad.Data; 110 import visad.DateTime; 111 import visad.DisplayEvent; 112 import visad.Real; 113 import visad.RealType; 114 import visad.Set; 115 import visad.Unit; 116 import visad.VisADException; 117 import visad.georef.EarthLocation; 118 import visad.georef.EarthLocationLite; 119 import visad.georef.LatLonPoint; 120 121 /** 122 * Part of the McV/IDV implementation of AODT 123 * @author Unidata Development Team, McIDAS-V Development Team 124 * @version $Revision$ 125 */ 126 127 public class StormDisplayState { 128 129 /** _more_ */ 130 public static final String PROP_TRACK_TABLE = "prop.track.table"; 131 132 /** _more_ */ 133 private static String ID_OBS_CONE = "id.obs.cone"; 134 135 /** _more_ */ 136 private static String ID_OBS_RINGS = "id.obs.rings"; 137 138 /** _more_ */ 139 private static String ID_OBS_LAYOUTMODEL = "id.obs.layoutmodel"; 140 141 /** _more_ */ 142 private static String ID_FORECAST_CONE = "id.forecast.cone"; 143 144 /** _more_ */ 145 private static String ID_FORECAST_RINGS = "id.forecast.rings"; 146 147 /** _more_ */ 148 private static String ID_FORECAST_COLOR = "id.forecast.color"; 149 150 /** _more_ */ 151 private static String ID_FORECAST_LAYOUTMODEL = "id.forecast.layoutmodel"; 152 153 /** _more_ */ 154 private static String ID_OBS_COLOR = "id.obs.color"; 155 156 /** The array of colors we cycle through */ 157 private static Color[] colors = { Color.RED, Color.PINK, Color.MAGENTA, 158 Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.CYAN, 159 Color.GRAY, Color.LIGHT_GRAY }; 160 161 /** _more_ */ 162 private boolean hasBeenEdited = false; 163 164 /** _more_ */ 165 private boolean colorRangeChanged = false; 166 167 /** _more_ */ 168 private static int[] nextColor = { 0 }; 169 170 /** _more_ */ 171 private JLabel obsColorTableLabel; 172 173 /** _more_ */ 174 private JLabel forecastColorTableLabel; 175 176 /** _more_ */ 177 private List<StormTrackChart> charts = new ArrayList<StormTrackChart>(); 178 179 /** _more_ */ 180 private List<StormTrackTableModel> tableModels = new ArrayList<StormTrackTableModel>(); 181 182 /** _more_ */ 183 private TreePanel tableTreePanel; 184 185 /** _more_ */ 186 private Object MUTEX = new Object(); 187 188 /** _more_ */ 189 private static final Data DUMMY_DATA = new Real(0); 190 191 /** _more_ */ 192 private CompositeDisplayable holder; 193 194 /** _more_ */ 195 private boolean isOnlyChild = false; 196 197 /** _more_ */ 198 private StormInfo stormInfo; 199 200 /** _more_ */ 201 private WayDisplayState forecastState; 202 203 /** _more_ */ 204 private boolean haveLoadedForecasts = false; 205 206 /** _more_ */ 207 private boolean changed = false; 208 209 /** _more_ */ 210 private boolean active = false; 211 212 /** _more_ */ 213 private StormTrackCollection trackCollection; 214 215 /** _more_ */ 216 private StormTrackControl stormTrackControl; 217 218 /** _more_ */ 219 private WayDisplayState obsDisplayState; 220 221 /** _more_ */ 222 private String obsLayoutModelName = "Storm>Hurricane"; 223 224 /** _more_ */ 225 private String obsPointLayoutModelName = "Storm>Forecast Hour"; 226 227 /** _more_ */ 228 private String forecastLayoutModelName = "Storm>Forecast Hour"; 229 230 /** time holder */ 231 private DisplayableData timesHolder = null; 232 233 /** _more_ */ 234 private JComponent mainContents; 235 236 /** _more_ */ 237 private JTabbedPane tabbedPane; 238 239 /** _more_ */ 240 private JComponent originalContents; 241 242 /** _more_ */ 243 private Hashtable params = new Hashtable(); 244 245 /** _more_ */ 246 private static final int FORECAST_TIME_MODE = 0; 247 248 /** _more_ */ 249 private int forecastAnimationMode = FORECAST_TIME_MODE; 250 251 /** _more_ */ 252 private JComboBox timeModeBox; 253 254 /** _more_ */ 255 private Hashtable<Way, WayDisplayState> wayDisplayStateMap = new Hashtable<Way, WayDisplayState>(); 256 257 /** _more_ */ 258 private CommandManager commandManager; 259 260 /** 261 * _more_ 262 */ 263 public StormDisplayState() { 264 } 265 266 /** 267 * _more_ 268 * 269 * @param stormInfo 270 * _more_ 271 * 272 * @throws Exception 273 * _more_ 274 */ 275 public StormDisplayState(StormInfo stormInfo) throws Exception { 276 this.stormInfo = stormInfo; 277 forecastState = new WayDisplayState(this, new Way("forecaststate")); 278 forecastState.getWayState().setVisible(false); 279 forecastState.getConeState().setVisible(true); 280 forecastState.getTrackState().setVisible(true); 281 forecastState.getRingsState().setVisible(true); 282 } 283 284 /** 285 * _more_ 286 * 287 * @return _more_ 288 */ 289 private CommandManager getCommandManager() { 290 if (commandManager == null) { 291 commandManager = new CommandManager(100); 292 } 293 return commandManager; 294 } 295 296 /** 297 * _more_ 298 */ 299 private void checkVisibility() { 300 List<WayDisplayState> wayDisplayStates = getWayDisplayStates(); 301 Color bgcolor = Color.lightGray; 302 303 boolean rowOk = forecastState.getWayState().getVisible(); 304 forecastState.getRingsState().setBackground(rowOk ? null : bgcolor); 305 forecastState.getConeState().setBackground(rowOk ? null : bgcolor); 306 forecastState.getTrackState().setBackground(rowOk ? null : bgcolor); 307 for (WayDisplayState wds : wayDisplayStates) { 308 rowOk = wds.getWayState().getVisible(); 309 if (wds.getWay().isObservation()) { 310 wds.getRingsState().setBackground(rowOk ? null : bgcolor); 311 wds.getConeState().setBackground(rowOk ? null : bgcolor); 312 wds.getTrackState().setBackground(rowOk ? null : bgcolor); 313 } else { 314 rowOk = rowOk && forecastState.getWayState().getVisible(); 315 wds.getWayState().setBackground( 316 forecastState.getWayState().getVisible() ? null 317 : bgcolor); 318 wds.getRingsState() 319 .setBackground( 320 (rowOk && forecastState.getRingsState() 321 .getVisible()) ? null : bgcolor); 322 wds.getConeState() 323 .setBackground( 324 (rowOk && forecastState.getConeState() 325 .getVisible()) ? null : bgcolor); 326 wds.getTrackState() 327 .setBackground( 328 (rowOk && forecastState.getTrackState() 329 .getVisible()) ? null : bgcolor); 330 } 331 } 332 } 333 334 /** 335 * _more_ 336 */ 337 public void colorTableChanged() { 338 try { 339 updateDisplays(); 340 } catch (Exception exc) { 341 stormTrackControl.logException("Changing color table", exc); 342 } 343 } 344 345 /** _more_ */ 346 private int wayCnt = -1; 347 348 /** _more_ */ 349 private StormTrack editedStormTrack; 350 351 /** _more_ */ 352 private StormTrackPoint editedStormTrackPoint; 353 354 /** 355 * _more_ 356 * 357 * @param event 358 * _more_ 359 * 360 * @throws Exception 361 * _more_ 362 */ 363 public void handleEvent(DisplayEvent event) throws Exception { 364 int id = event.getId(); 365 InputEvent inputEvent = event.getInputEvent(); 366 if ((inputEvent instanceof KeyEvent)) { 367 KeyEvent keyEvent = (KeyEvent) inputEvent; 368 if ((keyEvent.getKeyCode() == KeyEvent.VK_Z) 369 && keyEvent.isControlDown()) { 370 getCommandManager().undo(); 371 return; 372 } 373 if ((keyEvent.getKeyCode() == KeyEvent.VK_Y) 374 && keyEvent.isControlDown()) { 375 getCommandManager().redo(); 376 return; 377 } 378 } 379 380 EarthLocation el = stormTrackControl.toEarth(event); 381 LatLonPoint llp = el.getLatLonPoint(); 382 383 if (id == DisplayEvent.MOUSE_PRESSED) { 384 List<StormDisplayState> me = new ArrayList<StormDisplayState>(); 385 me.add(this); 386 387 // System.err.println ("looking"); 388 Real animationTime = null; 389 Animation animation = stormTrackControl.getViewAnimation(); 390 if (animation != null) { 391 animationTime = animation.getAniValue(); 392 } 393 if (animationTime == null) { 394 // System.err.println ("no animation"); 395 return; 396 } 397 Object[] tuple = stormTrackControl.findClosestPoint(el, me, 398 animationTime, 50); 399 if (tuple == null) { 400 // System.err.println ("nothing found"); 401 return; 402 } 403 editedStormTrack = (StormTrack) tuple[0]; 404 editedStormTrackPoint = (StormTrackPoint) tuple[1]; 405 } 406 407 if (id == DisplayEvent.MOUSE_DRAGGED) { 408 if (editedStormTrackPoint == null) { 409 return; 410 } 411 handleMouseDrag(event, el); 412 } 413 414 if (id == DisplayEvent.MOUSE_RELEASED) { 415 editedStormTrackPoint = null; 416 editedStormTrack = null; 417 } 418 } 419 420 /** 421 * Class PointEditCommand _more_ 422 * 423 * 424 * @author IDV Development Team 425 */ 426 private class PointEditCommand extends Command { 427 428 /** _more_ */ 429 StormTrack stormTrack; 430 431 /** _more_ */ 432 List<StormTrackPoint> originalPoints; 433 434 /** _more_ */ 435 List<StormTrackPoint> newPoints; 436 437 /** 438 * _more_ 439 * 440 * @param stormTrack 441 * _more_ 442 * @param originalPoints 443 * _more_ 444 * @param newPoints 445 * _more_ 446 */ 447 public PointEditCommand(StormTrack stormTrack, 448 List<StormTrackPoint> originalPoints, 449 List<StormTrackPoint> newPoints) { 450 this.stormTrack = stormTrack; 451 this.originalPoints = originalPoints; 452 this.newPoints = newPoints; 453 } 454 455 /** 456 * _more_ 457 */ 458 public void redoCommand() { 459 try { 460 stormTrack.setTrackPoints(newPoints); 461 updateDisplays(stormTrack); 462 } catch (Exception exp) { 463 stormTrackControl.logException("undoing edit command", exp); 464 } 465 } 466 467 /** 468 * Undo 469 */ 470 public void undoCommand() { 471 try { 472 stormTrack.setTrackPoints(originalPoints); 473 updateDisplays(stormTrack); 474 } catch (Exception exp) { 475 stormTrackControl.logException("undoing edit command", exp); 476 } 477 } 478 479 } 480 481 /** 482 * _more_ 483 * 484 * @param event 485 * _more_ 486 * @param newPt 487 * _more_ 488 * 489 * @throws Exception 490 * _more_ 491 */ 492 private void handleMouseDrag(DisplayEvent event, EarthLocation newPt) 493 throws Exception { 494 List<StormTrackPoint> points = editedStormTrack.getTrackPoints(); 495 List<StormTrackPoint> originalPoints = new ArrayList<StormTrackPoint>(); 496 for (StormTrackPoint stp : points) { 497 originalPoints.add(new StormTrackPoint(stp)); 498 } 499 500 // if the control key is not down then just move the point 501 int stretchIndex = editedStormTrack.indexOf(editedStormTrackPoint); 502 if (stretchIndex < 0) { 503 // this should never happen 504 throw new IllegalStateException("Cannot find track point"); 505 } 506 507 EarthLocation oldPt = (EarthLocation) points.get(stretchIndex) 508 .getLocation(); 509 510 double deltaY = oldPt.getLatitude().getValue(CommonUnit.degree) 511 - newPt.getLatitude().getValue(CommonUnit.degree); 512 double deltaX = LatLonPointImpl.lonNormal(oldPt.getLongitude() 513 .getValue(CommonUnit.degree)) 514 - LatLonPointImpl.lonNormal(newPt.getLongitude().getValue( 515 CommonUnit.degree)); 516 517 if ((event.getModifiers() & event.CTRL_MASK) != 0) { 518 editedStormTrackPoint.setLocation(newPt); 519 // else do an interpolated stretch 520 int startPts = stretchIndex - 1; 521 int endPts = points.size() - stretchIndex; 522 double percent = 1.0; 523 524 // System.err.println("delta: " + deltaX + " " + deltaY); 525 for (int i = stretchIndex - 1; i >= 0; i--) { 526 percent -= 1.0 / (double) startPts; 527 if (percent <= 0.05) { 528 break; 529 } 530 EarthLocation pt = (EarthLocation) points.get(i).getLocation(); 531 EarthLocation newEl = makePoint(pt.getLatitude().getValue( 532 CommonUnit.degree) 533 - deltaY * percent, LatLonPointImpl.lonNormal(pt 534 .getLongitude().getValue(CommonUnit.degree)) 535 - deltaX * percent); 536 // System.err.println(" " +percent + " " + pt.getLatLonPoint() 537 // + " " + newEl.getLatLonPoint()); 538 points.get(i).setLocation(newEl); 539 } 540 percent = 1.0; 541 for (int i = stretchIndex + 1; i < points.size(); i++) { 542 percent -= 1.0 / (double) endPts; 543 if (percent <= 0.05) { 544 break; 545 } 546 EarthLocation pt = (EarthLocation) points.get(i).getLocation(); 547 EarthLocation newEl = makePoint(pt.getLatitude().getValue( 548 CommonUnit.degree) 549 - deltaY * percent, LatLonPointImpl.lonNormal(pt 550 .getLongitude().getValue(CommonUnit.degree)) 551 - deltaX * percent); 552 points.get(i).setLocation(newEl); 553 } 554 } else if ((event.getModifiers() & event.SHIFT_MASK) != 0) { 555 for (StormTrackPoint stp : points) { 556 EarthLocation pt = (EarthLocation) stp.getLocation(); 557 EarthLocation newEl = makePoint(pt.getLatitude().getValue( 558 CommonUnit.degree) 559 - deltaY, LatLonPointImpl.lonNormal(pt.getLongitude() 560 .getValue(CommonUnit.degree)) 561 - deltaX); 562 stp.setLocation(newEl); 563 } 564 } else { 565 editedStormTrackPoint.setLocation(newPt); 566 } 567 568 getCommandManager().add( 569 new PointEditCommand(editedStormTrack, originalPoints, 570 editedStormTrack.getTrackPoints())); 571 updateDisplays(editedStormTrack); 572 } 573 574 /** 575 * _more_ 576 * 577 * @param latitude 578 * _more_ 579 * @param longitude 580 * _more_ 581 * 582 * @return _more_ 583 * 584 * @throws RemoteException 585 * _more_ 586 * @throws VisADException 587 * _more_ 588 */ 589 protected EarthLocation makePoint(double latitude, double longitude) 590 throws VisADException, RemoteException { 591 Real altReal = new Real(RealType.Altitude, 0); 592 return new EarthLocationLite(new Real(RealType.Latitude, latitude), 593 new Real(RealType.Longitude, longitude), altReal); 594 } 595 596 /** 597 * Check if its ok to show the given way. if we have less than 2 ways total 598 * then always showit 599 * 600 * @param way 601 * _more_ 602 * 603 * @return _more_ 604 */ 605 protected boolean okToShowWay(Way way) { 606 if (wayCnt == -1) { 607 608 List<StormTrack> tracks = trackCollection.getTracks(); 609 Hashtable ways = new Hashtable(); 610 wayCnt = 0; 611 for (StormTrack track : tracks) { 612 if (ways.get(track.getWay()) == null) { 613 wayCnt++; 614 ways.put(track.getWay(), ""); 615 } 616 } 617 } 618 if (wayCnt <= 1) { 619 return true; 620 } 621 return stormTrackControl.okToShowWay(way); 622 } 623 624 /** 625 * _more_ 626 * 627 * @return _more_ 628 */ 629 public LatLonRect getBoundingBox() { 630 if (trackCollection == null) { 631 return null; 632 } 633 double minLon = Double.POSITIVE_INFINITY; 634 double maxLon = Double.NEGATIVE_INFINITY; 635 double minLat = Double.POSITIVE_INFINITY; 636 double maxLat = Double.NEGATIVE_INFINITY; 637 638 boolean didone = false; 639 List<StormTrack> tracks = trackCollection.getTracks(); 640 for (StormTrack track : tracks) { 641 if (!okToShowWay(track.getWay())) { 642 continue; 643 } 644 LatLonRect bbox = track.getBoundingBox(); 645 if (bbox == null) { 646 continue; 647 } 648 minLon = Math.min(minLon, bbox.getLonMin()); 649 maxLon = Math.max(maxLon, bbox.getLonMax()); 650 minLat = Math.min(minLat, bbox.getLatMin()); 651 maxLat = Math.max(maxLat, bbox.getLatMax()); 652 didone = true; 653 } 654 if (!didone) { 655 return null; 656 } 657 return new LatLonRect(new LatLonPointImpl(maxLat, minLon), 658 new LatLonPointImpl(minLat, maxLon)); 659 } 660 661 /** 662 * _more_ 663 * 664 * @param isOnlyChild 665 * _more_ 666 */ 667 protected void setIsOnlyChild(boolean isOnlyChild) { 668 this.isOnlyChild = isOnlyChild; 669 } 670 671 /** 672 * _more_ 673 * 674 * @return _more_ 675 */ 676 public JComponent getContents() { 677 if (mainContents == null) { 678 mainContents = doMakeContents(); 679 } 680 return mainContents; 681 } 682 683 /** 684 * _more_ 685 * 686 * @return _more_ 687 */ 688 protected List<WayDisplayState> getWayDisplayStates() { 689 return (List<WayDisplayState>) Misc.toList(wayDisplayStateMap 690 .elements()); 691 } 692 693 /** 694 * _more_ 695 * 696 * @param way 697 * _more_ 698 * 699 * @return _more_ 700 */ 701 protected WayDisplayState getWayDisplayState(Way way) { 702 WayDisplayState wayState = wayDisplayStateMap.get(way); 703 if (wayState == null) { 704 wayDisplayStateMap.put(way, wayState = new WayDisplayState(this, 705 way)); 706 // "idv.stormtrackcontrol.way.color" 707 if (wayState.getColor() == null) { 708 wayState.setColor(getNextColor(nextColor)); 709 } 710 } 711 return wayState; 712 } 713 714 /** 715 * _more_ 716 */ 717 protected void reload() { 718 if (!active) { 719 return; 720 } 721 deactivate(); 722 loadStorm(); 723 } 724 725 /** 726 * _more_ 727 */ 728 public void loadStorm() { 729 if (active) { 730 return; 731 } 732 active = true; 733 showStorm(); 734 } 735 736 /** 737 * _more_ 738 */ 739 protected void reloadChart() { 740 for (StormTrackChart stormTrackChart : charts) { 741 // stormTrackChart.deactivate(); 742 stormTrackChart.updateChart(); 743 } 744 } 745 746 /** 747 * _more_ 748 * 749 * @return _more_ 750 */ 751 protected StormTrackCollection getTrackCollection() { 752 return trackCollection; 753 } 754 755 /** 756 * _more_ 757 * 758 * @param sm 759 * _more_ 760 */ 761 public void setObsLayoutModel(StationModel sm) { 762 obsLayoutModelName = ((sm == null) ? null : sm.getName()); 763 updateLayoutModel(true); 764 } 765 766 /** 767 * _more_ 768 * 769 * @param sm 770 * _more_ 771 */ 772 public void setObsPointLayoutModel(StationModel sm) { 773 obsPointLayoutModelName = ((sm == null) ? null : sm.getName()); 774 updateLayoutModel(true); 775 } 776 777 /** 778 * _more_ 779 * 780 * @param sm 781 * _more_ 782 */ 783 public void setForecastLayoutModel(StationModel sm) { 784 forecastLayoutModelName = ((sm == null) ? null : sm.getName()); 785 updateLayoutModel(false); 786 } 787 788 /** 789 * _more_ 790 * 791 * @param name 792 * _more_ 793 */ 794 protected void handleChangedStationModel(String name) { 795 if (Misc.equals(obsLayoutModelName, name)) { 796 updateLayoutModel(true); 797 } 798 if (Misc.equals(forecastLayoutModelName, name)) { 799 updateLayoutModel(false); 800 } 801 } 802 803 /** 804 * _more_ 805 * 806 * @param forObs 807 * _more_ 808 */ 809 public void updateLayoutModel(boolean forObs) { 810 List<WayDisplayState> wayDisplayStates = getWayDisplayStates(); 811 try { 812 for (WayDisplayState wds : wayDisplayStates) { 813 if (wds.getWay().isObservation() && !forObs) { 814 continue; 815 } 816 wds.updateLayoutModel(); 817 } 818 } catch (Exception exc) { 819 stormTrackControl.logException("Updating layout models", exc); 820 } 821 } 822 823 /** 824 * _more_ 825 */ 826 public void deactivate() { 827 try { 828 for (StormTrackChart stormTrackChart : charts) { 829 stormTrackChart.deactivate(); 830 } 831 trackCollection = null; 832 active = false; 833 colorRangeChanged = false; 834 stormTrackControl.removeDisplayable(holder); 835 holder = null; 836 if (mainContents != null) { 837 mainContents.removeAll(); 838 mainContents.add(BorderLayout.NORTH, originalContents); 839 List<WayDisplayState> wayDisplayStates = getWayDisplayStates(); 840 for (WayDisplayState wayDisplayState : wayDisplayStates) { 841 wayDisplayState.deactivate(); 842 } 843 mainContents.repaint(1); 844 } 845 stormTrackControl.stormChanged(StormDisplayState.this); 846 847 } catch (Exception exc) { 848 stormTrackControl.logException("Deactivating storm", exc); 849 } 850 } 851 852 /** 853 * _more_ 854 * 855 * @return _more_ 856 */ 857 private JComponent doMakeContents() { 858 JButton loadBtn = new JButton("Load Tracks:"); 859 JLabel topLabel = GuiUtils.cLabel(" " + stormInfo); 860 loadBtn.addActionListener(new ActionListener() { 861 public void actionPerformed(ActionEvent ae) { 862 loadStorm(); 863 } 864 }); 865 866 JComponent top = GuiUtils.hbox(loadBtn, topLabel); 867 originalContents = GuiUtils.inset(top, 5); 868 JComponent contents = GuiUtils.top(originalContents); 869 final int cnt = xcnt++; 870 contents = new JPanel(new BorderLayout()); 871 contents.add(BorderLayout.NORTH, originalContents); 872 return contents; 873 } 874 875 /** _more_ */ 876 static int xcnt = 0; 877 878 /** 879 * _more_ 880 */ 881 public void initDone() { 882 if (getActive()) { 883 showStorm(); 884 } 885 886 } 887 888 /** 889 * _more_ 890 * 891 * @return _more_ 892 */ 893 public boolean getForecastVisible() { 894 // return forecastState.getVisible(); 895 return forecastState.getWayState().getVisible(); 896 } 897 898 /** 899 * _more_ 900 * 901 * @param stormParams 902 * _more_ 903 * @param id 904 * _more_ 905 * 906 * @return _more_ 907 */ 908 private JComponent makeList(List stormParams, final Object id) { 909 if ((stormParams == null) || (stormParams.size() == 0)) { 910 return GuiUtils.filler(2, 10); 911 } 912 final JList list = new JList(new Vector(stormParams)); 913 list.setVisibleRowCount(3); 914 list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 915 list.addListSelectionListener(new ListSelectionListener() { 916 public void valueChanged(ListSelectionEvent e) { 917 List<StormParam> selected = new ArrayList<StormParam>(); 918 selected.addAll(Misc.toList(list.getSelectedValues())); 919 try { 920 params.put(id, selected); 921 updateDisplays(); 922 } catch (Exception exc) { 923 stormTrackControl.logException("setting cones", exc); 924 } 925 926 } 927 }); 928 929 list 930 .setToolTipText("<html>Parameter used for cone<br>Control-click for multiple select</html>"); 931 List selected = (List) params.get(id); 932 if ((selected != null) && (selected.size() > 0)) { 933 int[] indices = new int[selected.size()]; 934 for (int i = 0; i < selected.size(); i++) { 935 indices[i] = stormParams.indexOf(selected.get(i)); 936 } 937 list.setSelectedIndices(indices); 938 } 939 940 JScrollPane sp = new JScrollPane(list); 941 return sp; 942 } 943 944 /** 945 * _more_ 946 * 947 * @param stormParams 948 * _more_ 949 * @param id 950 * _more_ 951 * @param tooltip 952 * _more_ 953 * 954 * @return _more_ 955 */ 956 private JComponent makeBox(List stormParams, final Object id, String tooltip) { 957 if ((stormParams == null) || (stormParams.size() == 0)) { 958 return GuiUtils.filler(2, 10); 959 } 960 final JComboBox box = new JComboBox(new Vector(stormParams)); 961 box.setToolTipText(tooltip); 962 StormParam stormParam = (StormParam) params.get(id); 963 if (stormParam != null) { 964 box.setSelectedItem(stormParam); 965 } 966 box.addActionListener(new ActionListener() { 967 public void actionPerformed(ActionEvent ae) { 968 Object selected = box.getSelectedItem(); 969 if ((selected == null) || (selected instanceof String)) { 970 params.remove(id); 971 } else { 972 params.put(id, selected); 973 } 974 try { 975 colorRangeChanged = false; 976 updateDisplays(); 977 } catch (Exception exc) { 978 stormTrackControl.logException("setting cones", exc); 979 } 980 981 } 982 }); 983 984 return box; 985 } 986 987 /** 988 * _more_ 989 * 990 * @param params 991 * _more_ 992 * 993 * @return _more_ 994 */ 995 private List<StormParam> getDistanceParams(List<StormParam> params) { 996 if ((params == null) || (params.size() == 0)) { 997 return null; 998 } 999 1000 List<StormParam> attrNames = new ArrayList<StormParam>(); 1001 for (StormParam param : params) { 1002 if (Unit.canConvert(param.getUnit(), CommonUnit.meter)) { 1003 1004 attrNames.add(param); 1005 } 1006 1007 } 1008 if (attrNames.size() == 0) { 1009 return null; 1010 } 1011 return attrNames; 1012 } 1013 1014 // RealType fixedtype; 1015 StormParam getFixedParam() { 1016 RealType rtype = RealType.getRealType("Fixed"); 1017 // if (rtype == null) { 1018 // try { 1019 // rtype = new RealType("Fixed"); 1020 // } catch (VisADException e) { 1021 // 1022 // } 1023 // // fixedtype=rtype; 1024 // } 1025 return new StormParam(rtype, false, false); 1026 } 1027 1028 /** 1029 * _more_ 1030 */ 1031 private void initCenterContents() { 1032 1033 if (mainContents == null) { 1034 return; 1035 } 1036 1037 mainContents.removeAll(); 1038 JButton unloadBtn = GuiUtils.makeImageButton( 1039 "/auxdata/ui/icons/Cut16.gif", this, "deactivate"); 1040 unloadBtn.setToolTipText("Remove this storm"); 1041 String label = "Storm: " 1042 + stormInfo.toString() 1043 + " " 1044 + stormInfo.getStartTime().formattedString("yyyy-MM-dd", 1045 DateUtil.TIMEZONE_GMT); 1046 1047 JComponent top = GuiUtils.inset(GuiUtils.leftRight(GuiUtils 1048 .lLabel(label), unloadBtn), new Insets(0, 0, 0, 0)); 1049 1050 List<StormParam> forecastParams = new ArrayList<StormParam>(); 1051 Hashtable seenParams = new Hashtable(); 1052 List<StormParam> obsParams = new ArrayList<StormParam>(); 1053 Hashtable seenWays = new Hashtable(); 1054 for (StormTrack track : trackCollection.getTracks()) { 1055 // if (seenWays.get(track.getWay()) != null) { 1056 // continue; 1057 // } 1058 // seenWays.put(track.getWay(), track.getWay()); 1059 List<StormParam> trackParams = track.getParams(); 1060 if (track.getWay().isObservation()) { 1061 obsParams.addAll(trackParams); 1062 continue; 1063 } 1064 for (StormParam param : trackParams) { 1065 if (seenParams.get(param) != null) { 1066 continue; 1067 } 1068 seenParams.put(param, param); 1069 forecastParams.add(param); 1070 } 1071 } 1072 1073 List<StormParam> forecastRadiusParams = getDistanceParams(forecastParams); 1074 List<StormParam> obsRadiusParams = getDistanceParams(obsParams); 1075 1076 if (obsRadiusParams != null) { 1077 // If its not set then set it 1078 if (params.get(ID_OBS_RINGS) == null) { 1079 params.put(ID_OBS_RINGS, obsRadiusParams.get(0)); 1080 } 1081 if (params.get(ID_OBS_CONE) == null) { 1082 params.put(ID_OBS_CONE, Misc.newList(obsRadiusParams.get(0))); 1083 } 1084 } 1085 if (forecastRadiusParams != null) { 1086 // If its not set then set it 1087 if (params.get(ID_FORECAST_RINGS) == null) { 1088 params.put(ID_FORECAST_RINGS, forecastRadiusParams.get(0)); 1089 } 1090 if (params.get(ID_FORECAST_CONE) == null) { 1091 params.put(ID_FORECAST_CONE, Misc.newList(forecastRadiusParams 1092 .get(0))); 1093 } 1094 } 1095 1096 // Sort them by name 1097 1098 List<Way> ways = Misc.sort(trackCollection.getWayList()); 1099 boolean haveDoneForecast = false; 1100 List<String> colLabels = (List<String>) Misc.newList("", "Show", 1101 "Track"); 1102 if ((forecastRadiusParams != null) || (obsRadiusParams != null)) { 1103 colLabels.add("Rings"); 1104 colLabels.add("Cone"); 1105 } 1106 int numCols = colLabels.size(); 1107 1108 List obsColorParams = new ArrayList(obsParams); 1109 List forecastColorParams = new ArrayList(forecastParams); 1110 obsColorParams.add(0, getFixedParam()); 1111 forecastColorParams.add(0, getFixedParam()); 1112 1113 JComponent obsLayoutComp = new LayoutModelWidget(stormTrackControl, 1114 this, "setObsLayoutModel", getObsLayoutModel(), true); 1115 JComponent obsPointLayoutComp = new LayoutModelWidget( 1116 stormTrackControl, this, "setObsPointLayoutModel", 1117 getObsPointLayoutModel(), true); 1118 JComponent forecastLayoutComp = new LayoutModelWidget( 1119 stormTrackControl, this, "setForecastLayoutModel", 1120 getForecastLayoutModel(), true); 1121 1122 JComponent obsColorByBox = makeBox(obsColorParams, ID_OBS_COLOR, 1123 "Parameter used for coloring observation track"); 1124 JComponent forecastColorByBox = makeBox(forecastColorParams, 1125 ID_FORECAST_COLOR, 1126 "Parameter used for coloring forecast tracks"); 1127 1128 JComponent obsConeComp = ((obsRadiusParams != null) ? makeList( 1129 obsRadiusParams, ID_OBS_CONE) : (JComponent) GuiUtils.filler()); 1130 JComponent obsRingComp = ((obsRadiusParams != null) ? makeBox( 1131 obsRadiusParams, ID_OBS_RINGS, 1132 "Parameter used for observation rings") : (JComponent) GuiUtils 1133 .filler()); 1134 1135 JComponent forecastConeComp = ((forecastRadiusParams != null) ? makeList( 1136 forecastRadiusParams, ID_FORECAST_CONE) 1137 : (JComponent) GuiUtils.filler()); 1138 JComponent forecastRingComp = ((forecastRadiusParams != null) ? makeBox( 1139 forecastRadiusParams, ID_FORECAST_RINGS, 1140 "Parameter used for forecast rings") 1141 : (JComponent) GuiUtils.filler()); 1142 1143 List topComps = new ArrayList(); 1144 1145 timeModeBox = new JComboBox(new Vector(Misc.newList("On", "Off"))); 1146 timeModeBox.setSelectedIndex(forecastAnimationMode); 1147 timeModeBox.addActionListener(new ActionListener() { 1148 public void actionPerformed(ActionEvent ae) { 1149 forecastAnimationMode = timeModeBox.getSelectedIndex(); 1150 try { 1151 // reload(); 1152 updateDisplays(); 1153 } catch (Exception exc) { 1154 stormTrackControl.logException( 1155 "change forecast animation mode", exc); 1156 } 1157 } 1158 }); 1159 timeModeBox.setToolTipText("Animate tracks or show all tracks."); 1160 1161 JComponent forecastModeComp = GuiUtils.inset(GuiUtils.left(GuiUtils 1162 .label("Animation Mode: ", timeModeBox)), 5); 1163 1164 topComps.add(new JLabel("")); 1165 topComps.add(GuiUtils.cLabel("<html><u><i>Observation</i></u></html>")); 1166 topComps.add(GuiUtils.cLabel("<html><u><i>Forecast</i></u></html>")); 1167 1168 topComps.add(GuiUtils.rLabel("Points:")); 1169 topComps.add(obsPointLayoutComp); 1170 topComps.add(forecastLayoutComp); 1171 1172 topComps.add(GuiUtils.rLabel("Animation:")); 1173 topComps.add(obsLayoutComp); 1174 topComps.add(forecastModeComp); // GuiUtils.filler()); 1175 1176 forecastColorTableLabel = new JLabel(" "); 1177 forecastColorTableLabel.setToolTipText("Color table preview"); 1178 obsColorTableLabel = new JLabel(" "); 1179 obsColorTableLabel.setToolTipText("Color table preview"); 1180 1181 topComps.add(GuiUtils.rLabel("Color By:")); 1182 topComps.add(GuiUtils.vbox(obsColorByBox, obsColorTableLabel)); 1183 topComps 1184 .add(GuiUtils.vbox(forecastColorByBox, forecastColorTableLabel)); 1185 1186 if ((forecastRadiusParams != null) || (obsRadiusParams != null)) { 1187 topComps.add(GuiUtils.rLabel("Rings:")); 1188 topComps.add(obsRingComp); 1189 topComps.add(forecastRingComp); 1190 topComps.add(GuiUtils.rLabel("Cone:")); 1191 topComps.add(obsConeComp); 1192 topComps.add(forecastConeComp); 1193 } 1194 1195 GuiUtils.tmpInsets = new Insets(4, 4, 2, 2); 1196 JComponent paramComp = GuiUtils.doLayout(topComps, 3, GuiUtils.WT_N, 1197 GuiUtils.WT_N); 1198 1199 List comps = new ArrayList(); 1200 1201 for (Way way : ways) { 1202 WayDisplayState wds = getWayDisplayState(way); 1203 if (!okToShowWay(wds.getWay())) { 1204 continue; 1205 } 1206 JComponent labelComp = GuiUtils.hbox(wds.getWayState() 1207 .getCheckBox(), new JLabel(" " + way.toString())); 1208 1209 JComponent swatch = GuiUtils.wrap(wds.getColorSwatch()); 1210 if (way.isObservation()) { 1211 // We put the obs in the front of the list 1212 int col = 0; 1213 comps.add(col++, swatch); 1214 comps.add(col++, labelComp); 1215 comps.add(col++, GuiUtils.wrap(wds.getTrackState() 1216 .getCheckBox())); 1217 if (obsRadiusParams != null) { 1218 comps.add(col++, GuiUtils.wrap(wds.getRingsState() 1219 .getCheckBox())); 1220 comps.add(col++, GuiUtils.wrap(wds.getConeState() 1221 .getCheckBox())); 1222 } 1223 1224 } else { 1225 if (!haveDoneForecast) { 1226 1227 // Put the forecast info here 1228 haveDoneForecast = true; 1229 for (int colIdx = 0; colIdx < numCols; colIdx++) { 1230 comps.add(GuiUtils.filler()); 1231 } 1232 1233 comps.add(GuiUtils.filler()); 1234 comps.add(GuiUtils.hbox(forecastState.getWayState() 1235 .getCheckBox(), GuiUtils 1236 .lLabel("<html><u><i>Forecasts:</i></u></html>"))); 1237 comps.add(GuiUtils.wrap(forecastState.getTrackState() 1238 .getCheckBox())); 1239 if (forecastRadiusParams != null) { 1240 comps.add(GuiUtils.wrap(forecastState.getRingsState() 1241 .getCheckBox())); 1242 1243 comps.add(GuiUtils.wrap(forecastState.getConeState() 1244 .getCheckBox())); 1245 } 1246 } 1247 comps.add(swatch); 1248 comps.add(labelComp); 1249 comps.add(GuiUtils.wrap(wds.getTrackState().getCheckBox())); 1250 if (forecastRadiusParams != null) { 1251 comps.add(GuiUtils.wrap(wds.getRingsState().getCheckBox())); 1252 comps.add(GuiUtils.wrap(wds.getConeState().getCheckBox())); 1253 } 1254 } 1255 } 1256 1257 for (int colIdx = 0; colIdx < numCols; colIdx++) { 1258 String s = colLabels.get(colIdx); 1259 if (s.length() > 0) { 1260 comps.add(colIdx, new JLabel("<html><u><i>" + s 1261 + "</i></u></html>")); 1262 } else { 1263 comps.add(colIdx, new JLabel("")); 1264 } 1265 } 1266 1267 GuiUtils.tmpInsets = new Insets(2, 2, 0, 2); 1268 JComponent wayComp = GuiUtils.topLeft(GuiUtils.doLayout(comps, numCols, 1269 GuiUtils.WT_N, GuiUtils.WT_N)); 1270 // Put the list of ways into a scroller if there are lots of them 1271 if (ways.size() > 6) { 1272 int width = 300; 1273 int height = 200; 1274 JScrollPane scroller = GuiUtils.makeScrollPane(wayComp, width, 1275 height); 1276 scroller.setBorder(BorderFactory.createLoweredBevelBorder()); 1277 scroller.setPreferredSize(new Dimension(width, height)); 1278 scroller.setMinimumSize(new Dimension(width, height)); 1279 wayComp = scroller; 1280 } 1281 1282 wayComp = GuiUtils.left(GuiUtils.doLayout(new Component[] { 1283 GuiUtils.left(paramComp), GuiUtils.filler(2, 10), 1284 GuiUtils.left(wayComp) }, 1, GuiUtils.WT_N, GuiUtils.WT_NNY)); 1285 1286 wayComp = GuiUtils.inset(wayComp, new Insets(0, 5, 0, 0)); 1287 // tabbedPane = GuiUtils.getNestedTabbedPane(); 1288 tabbedPane = new JTabbedPane(); 1289 tabbedPane.addTab("Tracks", wayComp); 1290 tabbedPane.addTab("Table", getTrackTable()); 1291 1292 if (charts.size() == 0) { 1293 charts.add(new StormTrackChart(this, "Storm Chart", 1294 StormTrackChart.MODE_FORECASTTIME)); 1295 } 1296 for (StormTrackChart stormTrackChart : charts) { 1297 tabbedPane.addTab(stormTrackChart.getName(), stormTrackChart 1298 .getContents()); 1299 } 1300 1301 JComponent inner = GuiUtils.topCenter(top, tabbedPane); 1302 inner = GuiUtils.inset(inner, 5); 1303 mainContents.add(BorderLayout.CENTER, inner); 1304 mainContents.invalidate(); 1305 mainContents.validate(); 1306 mainContents.repaint(); 1307 1308 checkVisibility(); 1309 } 1310 1311 /** 1312 * Class ParamSelector _more_ 1313 * 1314 * 1315 * @author IDV Development Team 1316 * @version $Revision$ 1317 */ 1318 private static class ParamSelector { 1319 1320 /** _more_ */ 1321 List<StormParam> params; 1322 1323 /** _more_ */ 1324 JList list; 1325 1326 /** 1327 * _more_ 1328 * 1329 * @param types 1330 * _more_ 1331 */ 1332 public ParamSelector(List<StormParam> types) { 1333 } 1334 } 1335 1336 /** 1337 * _more_ 1338 * 1339 * @param time 1340 * _more_ 1341 */ 1342 protected void timeChanged(Real time) { 1343 for (StormTrackChart stormTrackChart : charts) { 1344 stormTrackChart.timeChanged(time); 1345 } 1346 } 1347 1348 /** 1349 * _more_ 1350 * 1351 * @param way 1352 * _more_ 1353 * 1354 * @return _more_ 1355 */ 1356 protected boolean canShowWay(Way way) { 1357 return getWayDisplayState(way).getWayState().getVisible(); 1358 } 1359 1360 /** 1361 * _more_ 1362 * 1363 * @param stormTrackControl 1364 * _more_ 1365 */ 1366 protected void setStormTrackControl(StormTrackControl stormTrackControl) { 1367 this.stormTrackControl = stormTrackControl; 1368 } 1369 1370 /** 1371 * _more_ 1372 */ 1373 protected void showStorm() { 1374 Misc.run(new Runnable() { 1375 public void run() { 1376 DisplayMaster displayMaster = stormTrackControl 1377 .getDisplayMaster(); 1378 boolean wasActive = displayMaster.isActive(); 1379 displayMaster.setDisplayInactive(); 1380 try { 1381 synchronized (MUTEX) { 1382 stormTrackControl.showWaitCursor(); 1383 showStormInner(); 1384 stormTrackControl.stormChanged(StormDisplayState.this); 1385 } 1386 } catch (Exception exc) { 1387 stormTrackControl.logException("Showing storm", exc); 1388 } finally { 1389 stormTrackControl.showNormalCursor(); 1390 if (wasActive) { 1391 try { 1392 // displayMaster.setActive(true); 1393 displayMaster.setDisplayActive(); 1394 } catch (Exception exc) { 1395 } 1396 } 1397 } 1398 1399 } 1400 }); 1401 } 1402 1403 /** 1404 * _more_ 1405 * 1406 * @param displayable 1407 * _more_ 1408 * 1409 * @throws RemoteException 1410 * _more_ 1411 * @throws VisADException 1412 * _more_ 1413 */ 1414 protected void addDisplayable(Displayable displayable) 1415 throws VisADException, RemoteException { 1416 if (holder != null) { 1417 holder.addDisplayable(displayable); 1418 } 1419 } 1420 1421 /** 1422 * _more_ 1423 * 1424 * @return _more_ 1425 */ 1426 protected StormTrackControl getStormTrackControl() { 1427 return stormTrackControl; 1428 } 1429 1430 /** 1431 * _more_ 1432 * 1433 * 1434 * @throws Exception 1435 * _more_ 1436 */ 1437 private void showStormInner() throws Exception { 1438 1439 // Read the tracks if we haven't 1440 long t1 = System.currentTimeMillis(); 1441 if (trackCollection == null) { 1442 if (mainContents != null) { 1443 mainContents.removeAll(); 1444 mainContents.add(GuiUtils.top(GuiUtils.inset(new JLabel( 1445 "Loading Tracks..."), 5))); 1446 mainContents.invalidate(); 1447 mainContents.validate(); 1448 mainContents.repaint(); 1449 } 1450 1451 trackCollection = stormTrackControl.getStormDataSource() 1452 .getTrackCollection(stormInfo, 1453 stormTrackControl.getOkWays(), 1454 stormTrackControl.getObservationWay()); 1455 initCenterContents(); 1456 stormTrackControl 1457 .addDisplayable(holder = new CompositeDisplayable()); 1458 // Add the tracks 1459 for (StormTrack track : trackCollection.getTracks()) { 1460 WayDisplayState wayDisplayState = getWayDisplayState(track 1461 .getWay()); 1462 wayDisplayState.addTrack(track); 1463 } 1464 obsDisplayState = getWayDisplayState(Way.OBSERVATION); 1465 StormTrack obsTrack = trackCollection.getObsTrack(); 1466 1467 List<DateTime> times = new ArrayList<DateTime>(); 1468 if (obsTrack != null) { 1469 times = obsTrack.getTrackTimes(); 1470 } else { 1471 for (StormTrack track : trackCollection.getTracks()) { 1472 times.add(track.getStartTime()); 1473 } 1474 } 1475 if (times.size() > 0) { 1476 times = (List<DateTime>) Misc.sort(Misc.makeUnique(times)); 1477 timesHolder = new LineDrawing("track_time" 1478 + stormInfo.getStormId()); 1479 timesHolder.setManipulable(false); 1480 timesHolder.setVisible(false); 1481 Set timeSet = ucar.visad.Util.makeTimeSet(times); 1482 // System.err.println("time set:" + timeSet); 1483 timesHolder.setData(timeSet); 1484 holder.addDisplayable(timesHolder); 1485 } 1486 } 1487 1488 updateDisplays(); 1489 updateCharts(); 1490 1491 long t2 = System.currentTimeMillis(); 1492 // System.err.println("time:" + (t2 - t1)); 1493 } 1494 1495 /** 1496 * _more_ 1497 * 1498 * @param id 1499 * _more_ 1500 * 1501 * @return _more_ 1502 */ 1503 protected List<StormParam> getParams(Object id) { 1504 List<StormParam> l = (List<StormParam>) params.get(id); 1505 if (l == null) { 1506 l = new ArrayList<StormParam>(); 1507 params.put(id, l); 1508 } 1509 return l; 1510 } 1511 1512 /** 1513 * _more_ 1514 * 1515 * @param way 1516 * _more_ 1517 * 1518 * @return _more_ 1519 */ 1520 protected List<StormParam> getConeParams(WayDisplayState way) { 1521 if (way.getWay().isObservation()) { 1522 return getParams(ID_OBS_CONE); 1523 } 1524 return getParams(ID_FORECAST_CONE); 1525 } 1526 1527 /** 1528 * _more_ 1529 * 1530 * @param way 1531 * _more_ 1532 * 1533 * @return _more_ 1534 */ 1535 protected StormParam getRingsParam(WayDisplayState way) { 1536 if (way.getWay().isObservation()) { 1537 return (StormParam) params.get(ID_OBS_RINGS); 1538 } 1539 return (StormParam) params.get(ID_FORECAST_RINGS); 1540 } 1541 1542 /** 1543 * _more_ 1544 * 1545 * @param way 1546 * _more_ 1547 * 1548 * @return _more_ 1549 */ 1550 protected StormParam getColorParam(WayDisplayState way) { 1551 return getColorParam(way.getWay().isObservation()); 1552 } 1553 1554 /** 1555 * _more_ 1556 * 1557 * @param forObs 1558 * _more_ 1559 * 1560 * @return _more_ 1561 */ 1562 protected StormParam getColorParam(boolean forObs) { 1563 if (forObs) { 1564 StormParam sp = (StormParam) params.get(ID_OBS_COLOR); 1565 if (sp == null) 1566 sp = getFixedParam(); 1567 return sp; 1568 } 1569 return (StormParam) params.get(ID_FORECAST_COLOR); 1570 } 1571 1572 /** 1573 * _more_ 1574 * 1575 * @throws Exception 1576 * _more_ 1577 */ 1578 protected void updateCharts() throws Exception { 1579 if (mainContents == null) { 1580 return; 1581 } 1582 1583 for (StormTrackChart stormTrackChart : charts) { 1584 stormTrackChart.updateChart(); 1585 } 1586 } 1587 1588 /** 1589 * _more_ 1590 * 1591 * @param displayState 1592 * _more_ 1593 * 1594 * @throws Exception 1595 * _more_ 1596 */ 1597 protected void displayStateChanged(DisplayState displayState) 1598 throws Exception { 1599 updateDisplays(); 1600 checkVisibility(); 1601 } 1602 1603 /** 1604 * _more_ 1605 * 1606 * @param track 1607 * _more_ 1608 * 1609 * @throws Exception 1610 * _more_ 1611 */ 1612 protected void updateDisplays(StormTrack track) throws Exception { 1613 Way way = track.getWay(); 1614 WayDisplayState wds = wayDisplayStateMap.get(way); 1615 if (wds != null) { 1616 wds.updateDisplay(true); 1617 for (StormTrackTableModel trackModel : tableModels) { 1618 if (trackModel.getStormTrack().equals(track)) { 1619 trackModel.fireTableStructureChanged(); 1620 Component comp = (Component) track 1621 .getTemporaryProperty(PROP_TRACK_TABLE); 1622 track.setIsEdited(true); 1623 if (comp != null) { 1624 tableTreePanel.show(comp); 1625 tableTreePanel.showPath(comp); 1626 } 1627 break; 1628 } 1629 } 1630 } 1631 } 1632 1633 /** 1634 * _more_ 1635 * 1636 * @throws Exception 1637 * _more_ 1638 */ 1639 protected void updateDisplays() throws Exception { 1640 updateDisplays(false); 1641 } 1642 1643 // sstretch protected void updateDisplays() throws Exception { 1644 1645 /** 1646 * _more_ 1647 * 1648 * @param force 1649 * _more_ 1650 * 1651 * @throws Exception 1652 * _more_ 1653 */ 1654 1655 protected void updateDisplays(boolean force) throws Exception { 1656 DisplayMaster displayMaster = stormTrackControl.getDisplayMaster(); 1657 boolean wasActive = displayMaster.isActive(); 1658 displayMaster.setDisplayInactive(); 1659 try { 1660 List<WayDisplayState> wayDisplayStates = getWayDisplayStates(); 1661 for (WayDisplayState wds : wayDisplayStates) { 1662 if (!okToShowWay(wds.getWay())) { 1663 continue; 1664 } 1665 wds.updateDisplay(force); 1666 } 1667 } finally { 1668 if (wasActive) { 1669 try { 1670 // displayMaster.setActive(true); 1671 displayMaster.setDisplayActive(); 1672 } catch (Exception exc) { 1673 } 1674 } 1675 } 1676 1677 if (obsColorTableLabel != null) { 1678 ColorTable ct = null; 1679 1680 ct = getColorTable(getColorParam(true)); 1681 obsColorTableLabel.setIcon(((ct != null) ? ColorTableCanvas 1682 .getIcon(ct) : null)); 1683 1684 obsColorTableLabel.setToolTipText(getColorTableToolTip(true)); 1685 1686 } 1687 1688 if (forecastColorTableLabel != null) { 1689 ColorTable ct = null; 1690 1691 ct = getColorTable(getColorParam(false)); 1692 forecastColorTableLabel.setIcon(((ct != null) ? ColorTableCanvas 1693 .getIcon(ct) : null)); 1694 1695 forecastColorTableLabel.setToolTipText(getColorTableToolTip(false)); 1696 } 1697 1698 } 1699 1700 /** 1701 * _more_ 1702 * 1703 * @param forObs 1704 * _more_ 1705 * 1706 * @return _more_ 1707 */ 1708 protected String getColorTableToolTip(boolean forObs) { 1709 StormParam param = getColorParam(forObs); 1710 if (param == null) { 1711 return "Color table preview"; 1712 } 1713 Range range = getStormTrackControl().getIdv().getParamDefaultsEditor() 1714 .getParamRange(param.getName()); 1715 if (range == null) { 1716 return "Color table preview"; 1717 } 1718 1719 Unit displayUnit = getStormTrackControl().getIdv() 1720 .getParamDefaultsEditor().getParamDisplayUnit(param.getName()); 1721 1722 String unit = ((displayUnit != null) ? "[" + displayUnit + "]" : ""); 1723 return "Range: " + range.getMin() + unit + " - " + range.getMax() 1724 + unit; 1725 } 1726 1727 /** 1728 * _more_ 1729 * 1730 * @param param 1731 * _more_ 1732 * 1733 * @return _more_ 1734 */ 1735 protected ColorTable getColorTable(StormParam param) { 1736 if (param == null) { 1737 1738 return null; 1739 } else if (param.getName().equalsIgnoreCase("Fixed")) { 1740 try { 1741 getStormTrackControl().getColorTableWidget(new Range(1.0, 1.0)); 1742 } catch (VisADException r) { 1743 } catch (RemoteException s) { 1744 } 1745 return null; 1746 } 1747 1748 Range range = getStormTrackControl().getIdv().getParamDefaultsEditor() 1749 .getParamRange(param.getName()); 1750 if (range == null) { 1751 range = new Range(1.0, 100.0); 1752 } 1753 1754 ColorTableWidget ctw = null; 1755 try { 1756 if (colorRangeChanged) { 1757 range = getStormTrackControl().getRangeForColorTable(); 1758 } 1759 ctw = getStormTrackControl().getColorTableWidget(range); 1760 } catch (VisADException r) { 1761 } catch (RemoteException s) { 1762 } 1763 ColorTable ct = ctw.getColorTable(); 1764 // getStormTrackControl().getIdv().getParamDefaultsEditor() 1765 // .getParamColorTable(param.getName(), false); 1766 if (ct == null) { 1767 ct = getStormTrackControl().getColorTable(); 1768 } 1769 // ct.setRange(range); 1770 1771 return ct; 1772 } 1773 1774 /** 1775 * _more_ 1776 * 1777 * @return _more_ 1778 */ 1779 protected StationModel getObsLayoutModel() { 1780 if ((obsLayoutModelName == null) || obsLayoutModelName.equals("none")) { 1781 return null; 1782 } 1783 1784 StationModelManager smm = stormTrackControl.getControlContext() 1785 .getStationModelManager(); 1786 return smm.getStationModel(obsLayoutModelName); 1787 /* 1788 * StationModel model = new StationModel("TrackLocation"); ShapeSymbol 1789 * shapeSymbol = new ShapeSymbol(0, 0); 1790 * shapeSymbol.setShape(ucar.visad.ShapeUtility.HURRICANE); 1791 * shapeSymbol.setScale(2.0f); shapeSymbol.bounds = new 1792 * java.awt.Rectangle(-15, -15, 30, 30); 1793 * shapeSymbol.setRectPoint(Glyph.PT_MM); 1794 * shapeSymbol.setForeground(null); model.addSymbol(shapeSymbol); return 1795 * model; 1796 */ 1797 } 1798 1799 /** 1800 * _more_ 1801 * 1802 * @return _more_ 1803 */ 1804 protected StationModel getObsPointLayoutModel() { 1805 if ((obsPointLayoutModelName == null) 1806 || obsPointLayoutModelName.equals("none")) { 1807 return null; 1808 } 1809 1810 StationModelManager smm = stormTrackControl.getControlContext() 1811 .getStationModelManager(); 1812 return smm.getStationModel(obsPointLayoutModelName); 1813 /* 1814 * StationModel model = new StationModel("TrackLocation"); ShapeSymbol 1815 * shapeSymbol = new ShapeSymbol(0, 0); 1816 * shapeSymbol.setShape(ucar.visad.ShapeUtility.HURRICANE); 1817 * shapeSymbol.setScale(2.0f); shapeSymbol.bounds = new 1818 * java.awt.Rectangle(-15, -15, 30, 30); 1819 * shapeSymbol.setRectPoint(Glyph.PT_MM); 1820 * shapeSymbol.setForeground(null); model.addSymbol(shapeSymbol); return 1821 * model; 1822 */ 1823 } 1824 1825 /** 1826 * _more_ 1827 * 1828 * @return _more_ 1829 */ 1830 protected StationModel getForecastLayoutModel() { 1831 if ((forecastLayoutModelName == null) 1832 || forecastLayoutModelName.equals("none")) { 1833 return null; 1834 } 1835 StationModelManager smm = stormTrackControl.getControlContext() 1836 .getStationModelManager(); 1837 StationModel sm = smm.getStationModel(forecastLayoutModelName); 1838 if (sm != null) { 1839 return sm; 1840 } 1841 StationModel model = new StationModel("TrackLocation"); 1842 ShapeSymbol shapeSymbol = new ShapeSymbol(0, 0); 1843 shapeSymbol.setScale(0.3f); 1844 shapeSymbol.setShape(ucar.visad.ShapeUtility.CIRCLE); 1845 shapeSymbol.bounds = new java.awt.Rectangle(-15, -15, 30, 30); 1846 shapeSymbol.setRectPoint(Glyph.PT_MM); 1847 model.addSymbol(shapeSymbol); 1848 return model; 1849 } 1850 1851 // ucar.visad.Util.makeTimeField(List<Data> ranges, List times) 1852 1853 /** 1854 * Animation animation = stormTrackControl.getViewAnimation(); if (animation 1855 * == null) { return; } List<StormTrack> visibleTracks = new 1856 * ArrayList<StormTrack>(); Real currentAnimationTime = 1857 * animation.getAniValue(); if (currentAnimationTime == null || 1858 * currentAnimationTime.isMissing()) { return; } Iterate way display states 1859 * boolean visible = false; if(wds.shouldShowTrack() && 1860 * wds.hasTrackDisplay()) { FieldImpl field = 1861 * (FieldImplt)wds.getTrackDisplay().getData() if(field==null) continue; Set 1862 * timeSet = GridUtil.getTimeSet(); if(timeSet == null) continue; if 1863 * (timeSet.getLength() == 1) { visible = true; } else { //Else work the 1864 * visad magic float timeValueFloat = (float) currentAnimationTime.getValue( 1865 * timeSet.getSetUnits()[0]); // System.err.println("multiple times:" + 1866 * timeValueFloat); float[][] value = { { timeValueFloat } }; int[] index = 1867 * timeSet.valueToIndex(value); // System.err.println("index:" + index[0]); 1868 * visible = (index[0] >= 0); } if(visible) { //Find the closest track in 1869 * wds in time visibleTracks.add(..); } } 1870 * 1871 * 1872 * Now search in space 1873 * 1874 * @param stormTrackChart 1875 * _more_ 1876 */ 1877 1878 /** 1879 * _more_ 1880 * 1881 * @param stormTrackChart 1882 * _more_ 1883 */ 1884 protected void removeChart(StormTrackChart stormTrackChart) { 1885 charts.remove(stormTrackChart); 1886 tabbedPane.remove(stormTrackChart.getContents()); 1887 } 1888 1889 /** 1890 * _more_ 1891 */ 1892 public void addForecastTimeChart() { 1893 addForecastChart(StormTrackChart.MODE_FORECASTTIME); 1894 } 1895 1896 /** 1897 * _more_ 1898 */ 1899 public void addForecastHourChart() { 1900 addForecastChart(StormTrackChart.MODE_FORECASTHOUR); 1901 } 1902 1903 /** 1904 * _more_ 1905 * 1906 * @param mode 1907 * _more_ 1908 */ 1909 public void addForecastChart(int mode) { 1910 String chartName = GuiUtils.getInput("Please enter a chart name", 1911 "Chart Name: ", "Storm Chart"); 1912 if (chartName == null) { 1913 return; 1914 } 1915 StormTrackChart stormTrackChart = new StormTrackChart(this, chartName, 1916 mode); 1917 charts.add(stormTrackChart); 1918 tabbedPane.addTab(stormTrackChart.getName(), stormTrackChart 1919 .getContents()); 1920 stormTrackChart.updateChart(); 1921 1922 } 1923 1924 /** 1925 * _more_ 1926 * 1927 * @return _more_ 1928 */ 1929 public List<StormParam> getStormChartParams() { 1930 Hashtable<String, Boolean> s1 = stormTrackControl.getOkParams(); 1931 List<StormParam> allParams = stormTrackControl.getTrackParams(); 1932 List<StormParam> params = new ArrayList(); 1933 for (StormParam sp : allParams) { 1934 Boolean v = s1.get(sp.getName()); 1935 if ((v != null) && v.booleanValue()) { 1936 params.add(sp); 1937 } 1938 } 1939 return params; 1940 // return stormTrackControl.getChartParamFromSelector(); 1941 } 1942 1943 /** 1944 * _more_ 1945 * 1946 * @return _more_ 1947 */ 1948 private JComponent getTrackTable() { 1949 final Font boldFont = new Font("Dialog", Font.BOLD, 10); 1950 final Font plainFont = new Font("Dialog", Font.PLAIN, 10); 1951 tableTreePanel = new TreePanel(true, 150) { 1952 public DefaultTreeCellRenderer doMakeTreeCellRenderer() { 1953 return new DefaultTreeCellRenderer() { 1954 public Component getTreeCellRendererComponent( 1955 JTree theTree, Object value, boolean sel, 1956 boolean expanded, boolean leaf, int row, 1957 boolean hasFocus) { 1958 super.getTreeCellRendererComponent(theTree, value, sel, 1959 expanded, leaf, row, hasFocus); 1960 if (!(value instanceof TreePanel.MyTreeNode)) { 1961 return this; 1962 } 1963 TreePanel.MyTreeNode node = (TreePanel.MyTreeNode) value; 1964 StormTrack track = (StormTrack) node.getObject(); 1965 if (track.getIsEdited()) { 1966 this.setFont(boldFont); 1967 this.setForeground(Color.red); 1968 } else { 1969 this.setFont(plainFont); 1970 this.setForeground(Color.black); 1971 } 1972 return this; 1973 } 1974 }; 1975 } 1976 }; 1977 1978 int width = 400; 1979 int height = 400; 1980 for (StormTrack track : trackCollection.getTracks()) { 1981 final StormTrack theTrack = track; 1982 StormTrackTableModel tableModel = new StormTrackTableModel(this, 1983 track); 1984 tableModels.add(tableModel); 1985 TableSorter sorter = new TableSorter(tableModel); 1986 JTable trackTable = new JTable(sorter); 1987 JTableHeader header = trackTable.getTableHeader(); 1988 header.setToolTipText("Click to sort"); 1989 sorter.setTableHeader(trackTable.getTableHeader()); 1990 1991 JScrollPane scroller = GuiUtils.makeScrollPane(trackTable, width, 1992 height); 1993 scroller.setBorder(BorderFactory.createLoweredBevelBorder()); 1994 JComponent contents = scroller; 1995 if (!track.getWay().isObservation()) { 1996 contents = GuiUtils.topCenter(GuiUtils.left(GuiUtils.inset( 1997 new JLabel(track.getStartTime().toString()), 5)), 1998 contents); 1999 } 2000 2001 track.putTemporaryProperty(PROP_TRACK_TABLE, contents); 2002 2003 JButton flythroughBtn = GuiUtils.makeButton("Fly through", this, 2004 "flythroughTrack", track); 2005 contents = GuiUtils.centerBottom(contents, GuiUtils 2006 .right(flythroughBtn)); 2007 tableTreePanel.addComponent(contents, track.getWay().toString(), 2008 track.getStartTime().toString(), null, track); 2009 } 2010 2011 return tableTreePanel; 2012 } 2013 2014 /** 2015 * _more_ 2016 * 2017 * @param track 2018 * _more_ 2019 */ 2020 public void flythroughTrack(StormTrack track) { 2021 try { 2022 List<FlythroughPoint> points = new ArrayList<FlythroughPoint>(); 2023 for (StormTrackPoint stp : track.getTrackPoints()) { 2024 EarthLocation newLoc = makePoint(stp.getLocation() 2025 .getLatitude().getValue(CommonUnit.degree), stp 2026 .getLocation().getLongitude().getValue( 2027 CommonUnit.degree)); 2028 points.add(new FlythroughPoint(newLoc, stp.getTime())); 2029 } 2030 stormTrackControl.getMapViewManager().flythrough(points); 2031 } catch (Exception exc) { 2032 stormTrackControl.logException("Doing flythrough", exc); 2033 } 2034 } 2035 2036 /** _more_ */ 2037 public static final PatternFileFilter FILTER_DAT = new PatternFileFilter( 2038 ".+\\.dat", "Diamond Format (*.dat)", ".dat"); 2039 2040 /** _more_ */ 2041 JCheckBox obsCbx = new JCheckBox("Observation", true); 2042 2043 /** _more_ */ 2044 JCheckBox forecastCbx = new JCheckBox("Forecast", true); 2045 2046 /** _more_ */ 2047 JCheckBox mostRecentCbx = new JCheckBox("Most Recent Forecasts", false); 2048 2049 /** _more_ */ 2050 JCheckBox editedCbx = new JCheckBox("Edited Tracks", false); 2051 2052 /** 2053 * _more_ 2054 */ 2055 public void writeToDataFile() { 2056 try { 2057 JComponent accessory = GuiUtils.top(GuiUtils.vbox(obsCbx, 2058 forecastCbx, mostRecentCbx, editedCbx)); 2059 2060 String filename = FileManager.getWriteFile(Misc.newList( 2061 FileManager.FILTER_XLS, FILTER_DAT), 2062 FileManager.SUFFIX_XLS, accessory); 2063 if (filename == null) { 2064 return; 2065 } 2066 2067 List<StormTrack> tracksToWrite = new ArrayList<StormTrack>(); 2068 List<Way> waysToUse = new ArrayList<Way>(); 2069 Hashtable<Way, List> trackMap = new Hashtable<Way, List>(); 2070 for (StormTrack track : trackCollection.getTracks()) { 2071 List tracks = trackMap.get(track.getWay()); 2072 if (tracks == null) { 2073 tracks = new ArrayList(); 2074 trackMap.put(track.getWay(), tracks); 2075 waysToUse.add(track.getWay()); 2076 } 2077 tracks.add(track); 2078 if (editedCbx.isSelected()) { 2079 if (track.getIsEdited()) { 2080 tracksToWrite.add(track); 2081 } 2082 } else { 2083 if (track.getWay().isObservation()) { 2084 if (obsCbx.isSelected()) { 2085 tracksToWrite.add(track); 2086 } 2087 } else { 2088 if (forecastCbx.isSelected()) { 2089 tracksToWrite.add(track); 2090 } 2091 2092 } 2093 } 2094 2095 } 2096 2097 if (filename.endsWith(".dat")) { 2098 StringBuffer sb = StormTrack.toDiamond7(tracksToWrite, 2099 stormInfo.getStormId()); 2100 IOUtil.writeFile(filename, sb.toString()); 2101 return; 2102 } 2103 2104 Hashtable sheetNames = new Hashtable(); 2105 HSSFWorkbook wb = new HSSFWorkbook(); 2106 StormTrack obsTrack = trackCollection.getObsTrack(); 2107 // Write the obs track first 2108 if ((obsTrack != null) && obsCbx.isSelected()) { 2109 write(wb, obsTrack, sheetNames); 2110 } 2111 if (forecastCbx.isSelected()) { 2112 waysToUse = Misc.sort(waysToUse); 2113 for (Way way : waysToUse) { 2114 if (way.isObservation()) { 2115 continue; 2116 } 2117 List<StormTrack> tracks = (List<StormTrack>) Misc 2118 .sort(trackMap.get(way)); 2119 if (mostRecentCbx.isSelected()) { 2120 write(wb, tracks.get(tracks.size() - 1), sheetNames); 2121 } else { 2122 for (StormTrack track : tracks) { 2123 write(wb, track, sheetNames); 2124 } 2125 } 2126 } 2127 } 2128 FileOutputStream fileOut = new FileOutputStream(filename); 2129 wb.write(fileOut); 2130 fileOut.close(); 2131 } catch (Exception exc) { 2132 stormTrackControl.logException("Writing spreadsheet", exc); 2133 } 2134 } 2135 2136 /** 2137 * _more_ 2138 * 2139 * @param wb 2140 * _more_ 2141 * @param track 2142 * _more_ 2143 * @param sheetNames 2144 * _more_ 2145 */ 2146 protected void write(HSSFWorkbook wb, StormTrack track, Hashtable sheetNames) { 2147 int cnt = 0; 2148 String dateString = track.getStartTime().formattedString( 2149 "yyyy-MM-dd hhmm", DateUtil.TIMEZONE_GMT); 2150 String sheetName = track.getWay() + " - " + dateString; 2151 if (sheetName.length() > 30) { 2152 sheetName = sheetName.substring(0, 29); 2153 } 2154 // The sheet name length is limited 2155 while (sheetNames.get(sheetName) != null) { 2156 sheetName = (cnt++) + " " + sheetName; 2157 if (sheetName.length() > 30) { 2158 sheetName = sheetName.substring(0, 29); 2159 } 2160 } 2161 sheetNames.put(sheetName, sheetName); 2162 HSSFSheet sheet = wb.createSheet(sheetName); 2163 2164 int rowCnt = 0; 2165 List<StormParam> params = track.getParams(); 2166 HSSFCell cell; 2167 HSSFRow row; 2168 2169 for (StormTrackPoint stp : track.getTrackPoints()) { 2170 if (rowCnt == 0) { 2171 row = sheet.createRow((short) rowCnt++); 2172 row.createCell(0).setCellValue(new HSSFRichTextString("Time")); 2173 row.createCell(1).setCellValue(new HSSFRichTextString("Latitude")); 2174 row.createCell(2).setCellValue(new HSSFRichTextString("Longitude")); 2175 for (int colIdx = 0; colIdx < params.size(); colIdx++) { 2176 row.createCell((colIdx + 3)).setCellValue(new HSSFRichTextString( 2177 params.get(colIdx).toString())); 2178 } 2179 } 2180 row = sheet.createRow((short) rowCnt++); 2181 row.createCell(0).setCellValue(new HSSFRichTextString(stp.getTime().toString())); 2182 row.createCell(1).setCellValue( 2183 stp.getLocation().getLatitude().getValue()); 2184 row.createCell(2).setCellValue( 2185 stp.getLocation().getLongitude().getValue()); 2186 for (int colIdx = 0; colIdx < params.size(); colIdx++) { 2187 Real r = stp.getAttribute(params.get(colIdx)); 2188 cell = row.createCell((colIdx + 3)); 2189 cell.setCellValue(r.getValue()); 2190 } 2191 } 2192 } 2193 2194 /** 2195 * _more_ 2196 * 2197 * @param docNode 2198 * _more_ 2199 * @param state 2200 * _more_ 2201 * @param doObs 2202 * _more_ 2203 * @param doForecast 2204 * _more_ 2205 * @param mostRecent 2206 * _more_ 2207 * 2208 * @throws RemoteException 2209 * _more_ 2210 * @throws VisADException 2211 * _more_ 2212 */ 2213 public void writeToKml(Element docNode, Hashtable state, boolean doObs, 2214 boolean doForecast, boolean mostRecent) throws VisADException, 2215 RemoteException { 2216 try { 2217 List<Way> waysToUse = new ArrayList<Way>(); 2218 Hashtable<Way, List> trackMap = new Hashtable<Way, List>(); 2219 for (StormTrack track : trackCollection.getTracks()) { 2220 List tracks = trackMap.get(track.getWay()); 2221 if (tracks == null) { 2222 tracks = new ArrayList(); 2223 trackMap.put(track.getWay(), tracks); 2224 waysToUse.add(track.getWay()); 2225 } 2226 tracks.add(track); 2227 } 2228 2229 Element topFolder = KmlUtil.folder(docNode, "Storm: " 2230 + stormInfo.toString() 2231 + " " 2232 + stormInfo.getStartTime().formattedString("yyyy-MM-dd", 2233 DateUtil.TIMEZONE_GMT)); 2234 StormTrack obsTrack = trackCollection.getObsTrack(); 2235 // Write the obs track first 2236 if ((obsTrack != null) && doObs) { 2237 Element obsFolder = KmlUtil.folder(topFolder, "Observation"); 2238 stormTrackControl.writeToGE(docNode, state, obsFolder, 2239 obsTrack, getWayDisplayState(obsTrack.getWay()) 2240 .getColor()); 2241 } 2242 if (doForecast) { 2243 waysToUse = Misc.sort(waysToUse); 2244 for (Way way : waysToUse) { 2245 if (way.isObservation()) { 2246 continue; 2247 } 2248 Element wayNode = KmlUtil.folder(topFolder, 2249 stormTrackControl.getWayName() + ": " + way); 2250 List<StormTrack> tracks = (List<StormTrack>) Misc 2251 .sort(trackMap.get(way)); 2252 if (mostRecent) { 2253 StormTrack recent = tracks.get(tracks.size() - 1); 2254 stormTrackControl.writeToGE(docNode, state, wayNode, 2255 recent, getWayDisplayState(recent.getWay()) 2256 .getColor()); 2257 } else { 2258 for (StormTrack track : tracks) { 2259 stormTrackControl.writeToGE(docNode, state, 2260 wayNode, track, getWayDisplayState( 2261 track.getWay()).getColor()); 2262 2263 } 2264 } 2265 } 2266 } 2267 2268 } catch (Exception exc) { 2269 stormTrackControl.logException("Writing KML", exc); 2270 } 2271 } 2272 2273 /** 2274 * Set the StormInfo property. 2275 * 2276 * @param value 2277 * The new value for StormInfo 2278 */ 2279 public void setStormInfo(StormInfo value) { 2280 stormInfo = value; 2281 } 2282 2283 /** 2284 * Get the StormInfo property. 2285 * 2286 * @return The StormInfo 2287 */ 2288 public StormInfo getStormInfo() { 2289 return stormInfo; 2290 } 2291 2292 /** 2293 * Set the Changed property. 2294 * 2295 * @param value 2296 * The new value for Changed 2297 */ 2298 public void setChanged(boolean value) { 2299 changed = value; 2300 } 2301 2302 /** 2303 * Get the Changed property. 2304 * 2305 * @return The Changed 2306 */ 2307 public boolean getChanged() { 2308 return changed; 2309 } 2310 2311 /** 2312 * Set the Active property. 2313 * 2314 * @param value 2315 * The new value for Active 2316 */ 2317 public void setActive(boolean value) { 2318 active = value; 2319 } 2320 2321 /** 2322 * Get the Active property. 2323 * 2324 * @return The Active 2325 */ 2326 public boolean getActive() { 2327 return active; 2328 } 2329 2330 /** 2331 * Set the WayDisplayStateMap property. 2332 * 2333 * @param value 2334 * The new value for WayDisplayStateMap 2335 */ 2336 public void setWayDisplayStateMap(Hashtable<Way, WayDisplayState> value) { 2337 wayDisplayStateMap = value; 2338 } 2339 2340 /** 2341 * Get the WayDisplayStateMap property. 2342 * 2343 * @return The WayDisplayStateMap 2344 */ 2345 public Hashtable<Way, WayDisplayState> getWayDisplayStateMap() { 2346 return wayDisplayStateMap; 2347 } 2348 2349 /** 2350 * Set the ForecastState property. 2351 * 2352 * @param value 2353 * The new value for ForecastState 2354 */ 2355 public void setForecastState(WayDisplayState value) { 2356 forecastState = value; 2357 } 2358 2359 /** 2360 * Get the ForecastState property. 2361 * 2362 * @return The ForecastState 2363 */ 2364 public WayDisplayState getObservationState() { 2365 return obsDisplayState; 2366 } 2367 2368 /** 2369 * Set the ForecastState property. 2370 * 2371 * @param value 2372 * The new value for ForecastState 2373 */ 2374 public void setObservationState(WayDisplayState value) { 2375 obsDisplayState = value; 2376 } 2377 2378 /** 2379 * Get the ForecastState property. 2380 * 2381 * @return The ForecastState 2382 */ 2383 public WayDisplayState getForecastState() { 2384 return forecastState; 2385 } 2386 2387 /** 2388 * Cycle through the color list. 2389 * 2390 * 2391 * @param nextColor 2392 * _more_ 2393 * @return The next color in the list 2394 */ 2395 public static Color getNextColor(int[] nextColor) { 2396 if (nextColor[0] >= colors.length) { 2397 nextColor[0] = 0; 2398 } 2399 return colors[nextColor[0]++]; 2400 } 2401 2402 /** 2403 * Set the Charts property. 2404 * 2405 * @param value 2406 * The new value for Charts 2407 */ 2408 public void setCharts(List<StormTrackChart> value) { 2409 charts = value; 2410 } 2411 2412 /** 2413 * Get the Charts property. 2414 * 2415 * @return The Charts 2416 */ 2417 public List<StormTrackChart> getCharts() { 2418 return charts; 2419 } 2420 2421 /** 2422 * Set the Params property. 2423 * 2424 * @param value 2425 * The new value for Params 2426 */ 2427 public void setParams(Hashtable value) { 2428 params = value; 2429 } 2430 2431 /** 2432 * Get the Params property. 2433 * 2434 * @return The Params 2435 */ 2436 public Hashtable getParams() { 2437 return params; 2438 } 2439 2440 /** 2441 * Set the ObsLayoutModelName property. 2442 * 2443 * @param value 2444 * The new value for ObsLayoutModelName 2445 */ 2446 public void setObsLayoutModelName(String value) { 2447 obsLayoutModelName = value; 2448 } 2449 2450 /** 2451 * Get the ObsLayoutModelName property. 2452 * 2453 * @return The ObsLayoutModelName 2454 */ 2455 public String getObsLayoutModelName() { 2456 return obsLayoutModelName; 2457 } 2458 2459 /** 2460 * Set the ObsLayoutModelName property. 2461 * 2462 * @param value 2463 * The new value for ObsLayoutModelName 2464 */ 2465 public void setObsPointLayoutModelName(String value) { 2466 obsPointLayoutModelName = value; 2467 } 2468 2469 /** 2470 * Get the ObsLayoutModelName property. 2471 * 2472 * @return The ObsLayoutModelName 2473 */ 2474 public String getObsPointLayoutModelName() { 2475 return obsPointLayoutModelName; 2476 } 2477 2478 /** 2479 * Set the ForecastLayoutModelName property. 2480 * 2481 * @param value 2482 * The new value for ForecastLayoutModelName 2483 */ 2484 public void setForecastLayoutModelName(String value) { 2485 forecastLayoutModelName = value; 2486 } 2487 2488 /** 2489 * Get the ForecastLayoutModelName property. 2490 * 2491 * @return The ForecastLayoutModelName 2492 */ 2493 public String getForecastLayoutModelName() { 2494 return forecastLayoutModelName; 2495 } 2496 2497 /** 2498 * _more_ 2499 * 2500 * @return _more_ 2501 */ 2502 public int getForecastAnimationMode() { 2503 return forecastAnimationMode; 2504 } 2505 2506 /** 2507 * _more_ 2508 * 2509 * @param value 2510 * _more_ 2511 */ 2512 public void setForecastAnimationMode(int value) { 2513 forecastAnimationMode = value; 2514 } 2515 2516 /** 2517 * _more_ 2518 */ 2519 public void markHasBeenEdited() { 2520 hasBeenEdited = true; 2521 } 2522 2523 public void colorRangeChanged() { 2524 DisplayMaster displayMaster = stormTrackControl.getDisplayMaster(); 2525 colorRangeChanged = true; 2526 displayMaster.setDisplayInactive(); 2527 try { 2528 stormTrackControl.stormChanged(StormDisplayState.this); 2529 updateDisplays(); 2530 } catch (Exception exc) { 2531 stormTrackControl.logException("Changing color table", exc); 2532 } 2533 2534 } 2535 2536 /** 2537 * _more_ 2538 */ 2539 public boolean isColorRangeChanged() { 2540 return colorRangeChanged; 2541 } 2542 }