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 }