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