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 }