001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2017 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028 029package edu.wisc.ssec.mcidasv.control; 030 031import static ucar.unidata.util.GuiUtils.hbox; 032import static ucar.unidata.util.GuiUtils.filler; 033import static ucar.unidata.util.GuiUtils.left; 034import static ucar.unidata.util.GuiUtils.topLeft; 035import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.arr; 036 037import java.awt.BorderLayout; 038import java.awt.ComponentOrientation; 039import java.awt.Container; 040import java.awt.Dimension; 041import java.awt.FlowLayout; 042import java.awt.Font; 043import java.beans.PropertyChangeEvent; 044import java.io.File; 045import java.io.FileWriter; 046import java.io.IOException; 047import java.rmi.RemoteException; 048import java.text.SimpleDateFormat; 049import java.util.ArrayList; 050import java.util.Date; 051import java.util.List; 052import java.util.Scanner; 053import java.util.TimeZone; 054 055import javax.swing.Box; 056import javax.swing.ButtonGroup; 057import javax.swing.JButton; 058import javax.swing.JCheckBox; 059import javax.swing.JComboBox; 060import javax.swing.JComponent; 061import javax.swing.JFileChooser; 062import javax.swing.JFrame; 063import javax.swing.JLabel; 064import javax.swing.JOptionPane; 065import javax.swing.JPanel; 066import javax.swing.JRadioButton; 067import javax.swing.JScrollPane; 068import javax.swing.JTextArea; 069import javax.swing.JTextField; 070import javax.swing.SwingUtilities; 071 072import edu.wisc.ssec.mcidasv.McIDASV; 073import edu.wisc.ssec.mcidasv.adt.Data; 074import edu.wisc.ssec.mcidasv.adt.Env; 075import edu.wisc.ssec.mcidasv.adt.Functions; 076import edu.wisc.ssec.mcidasv.adt.History; 077import edu.wisc.ssec.mcidasv.adt.Main; 078import edu.wisc.ssec.mcidasv.adt.ReadIRImage; 079import edu.wisc.ssec.mcidasv.util.WebBrowser; 080 081import org.slf4j.Logger; 082import org.slf4j.LoggerFactory; 083 084import ucar.unidata.data.DataChoice; 085import ucar.unidata.data.DataInstance; 086import ucar.unidata.data.DataSourceImpl; 087import ucar.unidata.data.DataUtil; 088import ucar.unidata.data.grid.GridUtil; 089import ucar.unidata.data.imagery.AddeImageDataSource; 090import ucar.unidata.data.imagery.AddeImageDescriptor; 091import ucar.unidata.data.imagery.ImageDataSource; 092import ucar.unidata.geoloc.LatLonRect; 093import ucar.unidata.idv.DisplayInfo; 094import ucar.unidata.idv.control.DisplayControlImpl; 095import ucar.unidata.ui.LatLonWidget; 096import ucar.unidata.util.GuiUtils; 097import ucar.unidata.util.Misc; 098import ucar.unidata.view.geoloc.NavigatedDisplay; 099import ucar.unidata.xml.XmlObjectStore; 100import ucar.visad.Util; 101import ucar.visad.display.Animation; 102import ucar.visad.display.PointProbe; 103import ucar.visad.display.SelectorDisplayable; 104import ucar.visad.quantities.AirTemperature; 105import visad.CommonUnit; 106import visad.DateTime; 107import visad.DisplayEvent; 108import visad.FieldImpl; 109import visad.FlatField; 110import visad.Real; 111import visad.RealTuple; 112import visad.RealTupleType; 113import visad.Set; 114import visad.VisADException; 115import visad.georef.EarthLocation; 116import visad.georef.EarthLocationTuple; 117import visad.georef.LatLonPoint; 118import visad.util.DataUtility; 119import edu.wisc.ssec.mcidas.AreaDirectory; 120 121/** 122 * Advanced Dvorak Technique Display Control 123 * Algorithm developed at UW Madison/CIMSS to objectively determine tropical 124 * cyclone intensity from geostationary satellite infrared imagery. 125 * 126 * @author Tim Olander 127 */ 128 129public class ADTControl extends DisplayControlImpl { 130 131 private static final Logger logger = LoggerFactory.getLogger(ADTControl.class); 132 133 // Tooltip strings for the various UI buttons and inputs 134 private static final String TOOLTIP_LAND_FLAG_ON = "Apply ADT Land Interaction Rule"; 135 private static final String TOOLTIP_LAND_FLAG_OFF = "Do Not Apply ADT Land Interaction Rule"; 136 private static final String TOOLTIP_MANUAL = "Manually Select Storm Center In Image"; 137 private static final String TOOLTIP_AUTOMATIC = "Select Forecast File For First Guess Below"; 138 private static final String TOOLTIP_HISTORY = "Choose a File to Retain and Store ADT Output Data"; 139 private static final String TOOLTIP_PMW = "Supplement Analysis With Passive Microwave Eye Score"; 140 private static final String TOOLTIP_PENV = "Environmental Mean Sea Level Pressure"; 141 private static final String TOOLTIP_34KT = "34 Knot Wind/Gale Radius"; 142 private static final String TOOLTIP_MSLP_FROM_DVORAK = "Utilize Dvorak Technique to Derive MSLP"; 143 private static final String TOOLTIP_MSLP_FROM_CKZ = "Utilize Coutney/Knaff/Zehr Wind Speed/Presssure Technique"; 144 private static final String TOOLTIP_RMW = "Manually Input Radius of Maximum Wind"; 145 private static final String TOOLTIP_RAW_T = "Manually Define Initial Value for New Storm"; 146 private static final String TOOLTIP_STORM_ID = "Three Character WMO Storm Identfier"; 147 private static final String TOOLTIP_SITE_ID = "Four Character Site Analysis Identifier"; 148 149 public static final String[] SCENE_TYPES = { 150 "Eye", "Pinhole Eye", "Large Eye", "CDO", "Embedded Center", 151 "Irregular CDO", "Curved Band", "Shear" 152 }; 153 154 private static final String[] FORECAST_TYPES = { 155 "ATCF", "DISC", "PACWARN", "GENERIC", "RMSC ICAO", "RMSC WTIO", 156 "TCWC AXAU", "BEST", "HURDAT" 157 }; 158 159 /** _more_ */ 160 private LatLonWidget latLonWidget; 161 162 /** the probe */ 163 private PointProbe probe; 164 165 /** _more_ */ 166 private LatLonPoint probeLocation; 167 168 /** _more_ */ 169 private DataChoice choice; 170 171 /** _more_ */ 172 private static boolean running = false; 173 174 private static boolean runFullADTAnalysis = false; 175 private static boolean GUIFileOverrideTF = false; 176 177 private static boolean GUIOverrideSceneTF; 178 179 private static boolean GUIRunAutoTF; 180 private static boolean GUIOverrideTF; 181 private static boolean GUIATCFOutputTF; 182 private static boolean GUIInitStrengthTF; 183 private static boolean GUILandFlagTF; 184 185 // Default Java boolean value is false - need to initialize if we want true 186 private boolean GUIUseCKZTF = false; 187 private static boolean GUIVmax1or10TF = true; 188 189 private static boolean GUICommentAddTF; 190 private static boolean GUIDeleteTF; 191 private static boolean GUIATCFRecordOutputTF; 192 private static boolean GUIPMWActivateTF; 193 194 // need to determine or provide option 195 private static int GUIDomainID; 196 197 // need to initialize pulldown menu 198 private static int GUIForecastType = 0; 199 200 private static int GUIMWJulianDate; 201 private static int GUIMWHHMMSSTime; 202 private static int GUIStartDate; 203 private static int GUIStartTime; 204 private static int GUIEndDate; 205 private static int GUIEndTime; 206 private static int GUIHistoryListFormat; 207 208 private static double GUIRawTValue; 209 private static double GUIMWScore; 210 private static double GUICKZGaleRadius; 211 private static double GUICKZPenv; 212 private static double GUIRMWSize; 213 private static double GUIUserLatitude; 214 private static double GUIUserLongitude; 215 216 private static String GUIForecastFileName; 217 private String GUIATCFStormID = null; 218 private String GUIATCFSiteID = null; 219 private static String GUIHistoryFileName; 220 private static String GUIHistoryFileListingName; 221 private static String GUICommentString; 222 223 /** _more_ */ 224 private JButton adtBtn; 225 226 private JButton forecastBtn; 227 228 private JButton PMWFileBtn; 229 230 private JRadioButton manButton; 231 232 // Button to relocate probe 233 private JButton moveProbeButton; 234 235 /** _more_ */ 236 private JComboBox<String> forecastTypeBox; 237 238 private JFrame resultFrame; 239 private JTextArea resultArea; 240 private JFrame historyFrame; 241 private JTextArea historyArea; 242 243 private JLabel selectedHistoryFile; 244 245 private JFileChooser historyFileSaveChooser; 246 247 private JFrame overrideSceneFrame; 248 private JLabel overrideSceneCurrentValueLabel; 249 private JComboBox<String> overrideSceneTypeBox; 250 251 // CKZ params will need to be validated before running 252 JTextField ckzPenvTextField = null; 253 JTextField ckz34radiusTextField = null; 254 private static final String DEFAULT_PENV = "1012"; 255 private static final String DEFAULT_RADIUS = "300"; 256 257 private JLabel historyLabel; 258 259 private static String HistoryListOutput; 260 261 private static final String SCENE_TYPE_PREFIX = "Current Scene Type: "; 262 263 JTextField ATCFEntryStormTextField = null; 264 JTextField ATCFEntrySiteTextField = null; 265 266 /** 267 * 268 */ 269 public ADTControl() { 270 super(); 271 } 272 273 @Override public boolean init(DataChoice choice) throws VisADException, 274 RemoteException { 275 logger.info("ADTControl constructor begin..."); 276 277 if (!super.init(choice)) { 278 return false; 279 } 280 this.choice = choice; 281 282 probe = new PointProbe(new RealTuple(RealTupleType.SpatialEarth3DTuple, 283 new double[] { 0.0, 0.0, 0.0 })); 284 285 probe.setVisible(false); 286 probe.setAutoSize(true); 287 probe.addPropertyChangeListener(this); 288 289 probe.setPointSize(getDisplayScale()); 290 addDisplayable(probe, FLAG_COLOR); 291 292 // obtain initial ADT environmental parameters 293 getADTenvParameters(); 294 295 // setup window contents in Controls Window 296 setContents(setupMainWindow()); 297 298 // TJJ Jun 2017 299 // We want to initialize probe to display center if in Manual mode 300 NavigatedDisplay d = getNavigatedDisplay(); 301 if (manButton.isSelected()) { 302 if (d != null) { 303 EarthLocation el = d.getCenterPoint(); 304 logger.debug("Initializing probe location to: {}, {}", el.getLatitude(), el.getLongitude()); 305 probeLocation = el.getLatLonPoint(); 306 probe.setVisible(true); 307 } 308 } 309 updateProbeLocation(); 310 return true; 311 } 312 313 private Container setupMainWindow() { 314 315 /* add Lat/Lon position display text areas */ 316 latLonWidget = new LatLonWidget(GuiUtils.makeActionListener(this, 317 "latLonWidgetChanged", null)); 318 moveProbeButton = new JButton("Move Probe"); 319 // TJJ add a strut and Probe button to the Lat-Lon widget panel 320 latLonWidget.add(Box.createHorizontalStrut(6)); 321 latLonWidget.add(moveProbeButton); 322 moveProbeButton.addActionListener(ae -> { 323 // Validate the manual lat/lon text boxes 324 String validLL = latLonWidget.isValidValues(); 325 if (validLL == null) { 326 // User provided valid lat/lon data, see if it's within 327 // our display bounds. If so, move the probe 328 NavigatedDisplay d = getNavigatedDisplay(); 329 if (manButton.isSelected()) { 330 if (d != null) { 331 EarthLocationTuple elt = null; 332 try { 333 elt = new EarthLocationTuple(latLonWidget.getLat(), latLonWidget.getLon(), Double.NaN); 334 // Make sure the new Earth location is within the bounds of our satellite IR image 335 LatLonRect bounds = d.getLatLonRect(); 336 logger.debug("Bounds min, max Lat: " + bounds.getLatMin() + ", " + bounds.getLatMax()); 337 logger.debug("Bounds min, max Lon: " + bounds.getLonMin() + ", " + bounds.getLonMax()); 338 logger.debug("ELT LatVal, LonVal: " + elt.getLatitude().getValue() + ", " + elt.getLongitude().getValue()); 339 if (bounds.contains(elt.getLatitude().getValue(), elt.getLongitude().getValue())) { 340 probeLocation = elt.getLatLonPoint(); 341 updateProbeLocation(); 342 } else { 343 JOptionPane.showMessageDialog(null, "Location provided is outside image bounds"); 344 } 345 } catch (VisADException | RemoteException ve) { 346 logException(ve); 347 } 348 } 349 } 350 } else { 351 JOptionPane.showMessageDialog(null, validLL); 352 } 353 }); 354 355 /* add Manual or Automated storm centering buttons */ 356 357 manButton = new JRadioButton("Manual"); 358 manButton.setActionCommand("Manual"); 359 manButton.setSelected(true); 360 manButton.setToolTipText(TOOLTIP_MANUAL); 361 JRadioButton autoButton = new JRadioButton("Automated"); 362 autoButton.setActionCommand("Automated"); 363 autoButton.setSelected(false); 364 autoButton.setToolTipText(TOOLTIP_AUTOMATIC); 365 ButtonGroup automangroup = new ButtonGroup(); 366 automangroup.add(manButton); 367 automangroup.add(autoButton); 368 369 /* add forecast file file selector button and file type menu */ 370 JLabel autoStormSelectLabel = new JLabel("AUTOMATED STORM SELECTION"); 371 JLabel manualStormSelectLabel = new JLabel("MANUAL STORM SELECTION"); 372 JLabel forecastSelectLabel = new JLabel("Selected Forecast File: "); 373 374 JLabel forecastLabel = new JLabel("No forecast file selected yet"); 375 376 manButton.addActionListener(ae -> { 377 // enable the manual lat/lon text boxes 378 latLonWidget.getLonField().setEnabled(true); 379 latLonWidget.getLatField().setEnabled(true); 380 autoStormSelectLabel.setEnabled(false); 381 manualStormSelectLabel.setEnabled(true); 382 forecastSelectLabel.setEnabled(false); 383 moveProbeButton.setEnabled(true); 384 forecastBtn.setEnabled(false); 385 forecastTypeBox.setEnabled(false); 386 GUIRunAutoTF = false; 387 }); 388 389 autoButton.addActionListener(ae -> { 390 // disable the manual lat/lon text boxes when in auto mode 391 latLonWidget.getLonField().setEnabled(false); 392 latLonWidget.getLatField().setEnabled(false); 393 autoStormSelectLabel.setEnabled(true); 394 manualStormSelectLabel.setEnabled(false); 395 forecastSelectLabel.setEnabled(true); 396 moveProbeButton.setEnabled(false); 397 forecastBtn.setEnabled(true); 398 forecastTypeBox.setEnabled(true); 399 GUIRunAutoTF = true; 400 System.out.println("running automated ADT!!!\n"); 401 }); 402 403 forecastBtn = new JButton("Select Forecast File"); 404 forecastBtn.setPreferredSize(new Dimension(200,30)); 405 forecastBtn.addActionListener(fbtn -> { 406 GUIForecastFileName = selectForecastFile(); 407 logger.trace("forecast file name={}", GUIForecastFileName); 408 forecastLabel.setText( 409 GUIForecastFileName.substring(GUIForecastFileName.lastIndexOf(File.separatorChar) + 1) 410 ); 411 }); 412 413 forecastTypeBox = new JComboBox<>(FORECAST_TYPES); 414 forecastTypeBox.setSelectedIndex(GUIForecastType); 415 forecastTypeBox.setPreferredSize(new Dimension(150,20)); 416 forecastTypeBox.addActionListener(ame -> { 417 GUIForecastType = forecastTypeBox.getSelectedIndex(); 418 logger.trace("forecast file type={}", GUIForecastType); 419 }); 420 421 forecastTypeBox.setToolTipText("Select Forecast File Type."); 422 autoStormSelectLabel.setEnabled(false); 423 forecastSelectLabel.setEnabled(false); 424 forecastBtn.setEnabled(false); 425 forecastTypeBox.setEnabled(false); 426 427 /* define default history file text field message */ 428 selectedHistoryFile = new JLabel("No history file selected yet"); 429 430 /* add history file selection button */ 431 JButton historyBtn = new JButton("Select History File"); 432 historyBtn.setToolTipText(TOOLTIP_HISTORY); 433 historyBtn.setPreferredSize(new Dimension(200, 30)); 434 historyBtn.addActionListener(hbtn -> { 435 GUIHistoryFileName = selectHistoryFile(); 436 logger.debug("history file name={}", GUIHistoryFileName); 437 438 // TJJ Dec 2017 439 // Do some cursory validation on History file before plowing ahead 440 if (! validHistoryFile(GUIHistoryFileName)) { 441 JOptionPane.showMessageDialog(null, 442 "Your selection does not appear to be a valid ADT History File."); 443 } else { 444 runFullADTAnalysis = true; 445 selectedHistoryFile.setText( 446 GUIHistoryFileName.substring(GUIHistoryFileName.lastIndexOf(File.separatorChar) + 1) 447 ); 448 } 449 }); 450 451 /* add main ADT analysis start button */ 452 adtBtn = new JButton("Run ADT Analysis"); 453 adtBtn.setPreferredSize(new Dimension(250, 50)); 454 adtBtn.addActionListener(ae -> runADTmain()); 455 456 /* add history file list/write button */ 457 JButton listBtn = new JButton("List/Write History File"); 458 listBtn.setPreferredSize(new Dimension(250, 50)); 459 listBtn.addActionListener(ae -> { 460 logger.debug("listing history file name={}", GUIHistoryFileName); 461 try { 462 listHistoryFile(); 463 } catch (NumberFormatException nfe) { 464 JOptionPane.showMessageDialog(null, 465 "Your selection does not appear to be a valid ADT History File."); 466 } 467 }); 468 469 // TJJ Jan 2017 470 // We'll keep the Manual vs. Automated PMW radio button group around 471 // in case code to support automated is added later. For now, only 472 // manual works in this version, so we'll just set the state of the 473 // buttons but not show them. 474 475 JRadioButton PMWManButton = new JRadioButton("Manual"); 476 PMWManButton.setActionCommand("Man"); 477 PMWManButton.setSelected(true); 478 PMWManButton.setEnabled(true); 479 480 JRadioButton PMWAutoButton = new JRadioButton("Automated"); 481 PMWAutoButton.setActionCommand("Auto"); 482 PMWAutoButton.setSelected(false); 483 PMWAutoButton.setEnabled(false); 484 485 /* PMW Manual options */ 486 JLabel pmwManDateLabel = new JLabel("Date:"); 487 JLabel pmwManTimeLabel = new JLabel("Time:"); 488 JLabel pmwManScoreLabel = new JLabel("Score:"); 489 JTextField pmwManDateTextField = new JTextField("1900JAN01", 8); 490 pmwManDateTextField.setToolTipText("YYYYMMMDD"); 491 pmwManDateTextField.addActionListener(ae -> { 492 /* read PMW overpass date */ 493 JTextField src = (JTextField) ae.getSource(); 494 GUIMWJulianDate = 495 Functions.cmonth2julian(src.getText()); 496 GUIMWScore = -99.0; 497 }); 498 JTextField pmwManTimeTextField = new JTextField("000000", 6); 499 pmwManTimeTextField.setToolTipText("HHMMSS"); 500 pmwManTimeTextField.addActionListener(ae -> { 501 /* read PMW overpass time */ 502 JTextField src = (JTextField) ae.getSource(); 503 GUIMWHHMMSSTime = Integer.valueOf(src.getText()); 504 GUIMWScore = -99.0; 505 }); 506 JTextField pmwManScoreTextField = new JTextField("-99.0", 4); 507 pmwManScoreTextField.setToolTipText("Eye Score Value"); 508 pmwManScoreTextField.addActionListener(ae -> { 509 /* read PMW overpass score */ 510 JTextField src = (JTextField) ae.getSource(); 511 GUIMWScore = Double.valueOf(src.getText()); 512 }); 513 pmwManDateTextField.setEnabled(false); 514 pmwManTimeTextField.setEnabled(false); 515 pmwManScoreTextField.setEnabled(false); 516 pmwManDateLabel.setEnabled(false); 517 pmwManTimeLabel.setEnabled(false); 518 pmwManScoreLabel.setEnabled(false); 519 520 ButtonGroup pmwgroup = new ButtonGroup(); 521 pmwgroup.add(PMWAutoButton); 522 pmwgroup.add(PMWManButton); 523 PMWAutoButton.addActionListener(ae -> { 524 /* enter file name */ 525 // Automated - file entry 526 PMWFileBtn.setEnabled(true); 527 pmwManDateTextField.setEnabled(false); 528 pmwManTimeTextField.setEnabled(false); 529 pmwManScoreTextField.setEnabled(false); 530 pmwManDateLabel.setEnabled(false); 531 pmwManTimeLabel.setEnabled(false); 532 pmwManScoreLabel.setEnabled(false); 533 }); 534 PMWManButton.addActionListener(ae -> { 535 /* enter date/time and score manually */ 536 // Maunal entry 537 PMWFileBtn.setEnabled(false); 538 pmwManDateTextField.setEnabled(true); 539 pmwManTimeTextField.setEnabled(true); 540 pmwManScoreTextField.setEnabled(true); 541 pmwManDateLabel.setEnabled(true); 542 pmwManTimeLabel.setEnabled(true); 543 pmwManScoreLabel.setEnabled(true); 544 }); 545 546 /* Add PMW Analysis option buttons and entry fields */ 547 JCheckBox PMWActivateButton = new JCheckBox("Activate"); 548 PMWActivateButton.setActionCommand("PMW"); 549 PMWActivateButton.setSelected(false); 550 PMWActivateButton.setEnabled(true); 551 PMWActivateButton.setToolTipText(TOOLTIP_PMW); 552 PMWActivateButton.addActionListener(ae -> { 553 // if on, turn off and vice versa 554 GUIPMWActivateTF = !GUIPMWActivateTF; 555 PMWManButton.setEnabled(GUIPMWActivateTF); 556 PMWManButton.setSelected(GUIPMWActivateTF); 557 pmwManDateTextField.setEnabled(GUIPMWActivateTF); 558 pmwManTimeTextField.setEnabled(GUIPMWActivateTF); 559 pmwManScoreTextField.setEnabled(GUIPMWActivateTF); 560 pmwManDateLabel.setEnabled(GUIPMWActivateTF); 561 pmwManTimeLabel.setEnabled(GUIPMWActivateTF); 562 pmwManScoreLabel.setEnabled(GUIPMWActivateTF); 563 PMWActivateButton.setSelected(GUIPMWActivateTF); 564 }); 565 566 /* add CKZ option buttons and entry fields */ 567 JLabel ckzPenvLabel = new JLabel("Penv:"); 568 ckzPenvLabel.setEnabled(false); 569 570 JLabel ckz34radiusLabel = new JLabel("34kt Radius:"); 571 ckz34radiusLabel.setEnabled(false); 572 573 ckzPenvTextField = new JTextField(DEFAULT_PENV, 5); 574 ckzPenvTextField.setToolTipText(TOOLTIP_PENV); 575 ckzPenvTextField.addActionListener(ae -> { 576 JTextField src = (JTextField)ae.getSource(); 577 GUICKZPenv = Integer.valueOf(src.getText()); 578 }); 579 ckz34radiusTextField = new JTextField(DEFAULT_RADIUS, 5); 580 ckz34radiusTextField.setToolTipText(TOOLTIP_34KT); 581 ckz34radiusTextField.addActionListener(ae -> { 582 JTextField src = (JTextField)ae.getSource(); 583 GUICKZGaleRadius = Integer.valueOf(src.getText()); 584 }); 585 ckzPenvTextField.setEnabled(false); 586 ckz34radiusTextField.setEnabled(false); 587 588 JRadioButton mslpDvorakButton = new JRadioButton("Dvorak"); 589 mslpDvorakButton.setActionCommand("Dvorak"); 590 mslpDvorakButton.setSelected(true); 591 mslpDvorakButton.setToolTipText(TOOLTIP_MSLP_FROM_DVORAK); 592 JRadioButton mslpCKZButton = new JRadioButton("CKZ"); 593 mslpCKZButton.setActionCommand("CKZ"); 594 mslpCKZButton.setSelected(false); 595 mslpCKZButton.setToolTipText(TOOLTIP_MSLP_FROM_CKZ); 596 ButtonGroup mslpgroup = new ButtonGroup(); 597 mslpgroup.add(mslpDvorakButton); 598 mslpgroup.add(mslpCKZButton); 599 mslpDvorakButton.addActionListener(ae -> { 600 // Dvorak 601 ckzPenvTextField.setEnabled(false); 602 ckz34radiusTextField.setEnabled(false); 603 ckzPenvLabel.setEnabled(false); 604 ckz34radiusLabel.setEnabled(false); 605 mslpDvorakButton.setSelected(true); 606 mslpCKZButton.setSelected(false); 607 GUIUseCKZTF = false; 608 }); 609 mslpCKZButton.addActionListener(ae -> { 610 // CKZ 611 ckzPenvTextField.setEnabled(true); 612 ckz34radiusTextField.setEnabled(true); 613 ckzPenvLabel.setEnabled(true); 614 ckz34radiusLabel.setEnabled(true); 615 mslpDvorakButton.setSelected(false); 616 mslpCKZButton.setSelected(true); 617 GUIUseCKZTF = true; 618 }); 619 620 /* various other keyword options */ 621 /* Initial classification entry -- RAWT */ 622 JLabel RawTLabel = new JLabel("Raw T:"); 623 JTextField RawTTextField = new JTextField("1.0", 4); 624 RawTTextField.setToolTipText(TOOLTIP_RAW_T); 625 RawTTextField.addActionListener(ae -> { 626 JTextField src = (JTextField)ae.getSource(); 627 GUIRawTValue = Double.valueOf(src.getText()); 628 GUIInitStrengthTF = GUIRawTValue >= 1.0; 629 }); 630 631 /* Radius of Max Wind entry -- RMW */ 632 JLabel RMWLabel = new JLabel("RMW:"); 633 JTextField RMWTextField = new JTextField("-99", 4); 634 RMWTextField.setToolTipText(TOOLTIP_RMW); 635 RMWTextField.addActionListener(ae -> { 636 JTextField src = (JTextField)ae.getSource(); 637 GUIRMWSize = Double.valueOf(src.getText()); 638 }); 639 640 /* Override option */ 641 JButton sceneOverrideButton = new JButton("Override Scene Type"); 642 JLabel OverrideLabel = new JLabel(SCENE_TYPE_PREFIX + SCENE_TYPES[Env.OverrideSceneTypeIndex]); 643 sceneOverrideButton.addActionListener(ae -> { 644 overrideSceneFrame.setVisible(true); 645 }); 646 647 /* ATCF Analysis Output Checkbox */ 648 649 JLabel ATCFOutputLabel = new JLabel("ATCF Output:"); 650 JCheckBox ATCFOutputButton = new JCheckBox("Activate"); 651 ATCFOutputButton.setActionCommand("ATCF"); 652 ATCFOutputButton.setSelected(false); 653 ATCFOutputButton.setEnabled(true); 654 655 JLabel ATCFEntryStormLabel = new JLabel("Storm ID:"); 656 ATCFEntryStormTextField = new JTextField("XXX", 8); 657 ATCFEntryStormTextField.setToolTipText(TOOLTIP_STORM_ID); 658 JLabel ATCFEntrySiteLabel = new JLabel("Site ID:"); 659 ATCFEntrySiteTextField = new JTextField("XXXX", 8); 660 ATCFEntrySiteTextField.setToolTipText(TOOLTIP_SITE_ID); 661 ATCFEntryStormLabel.setEnabled(false); 662 ATCFEntryStormTextField.setEnabled(false); 663 ATCFEntrySiteLabel.setEnabled(false); 664 ATCFEntrySiteTextField.setEnabled(false); 665 ATCFEntryStormTextField.addActionListener(ae -> { 666 JTextField src = (JTextField)ae.getSource(); 667 GUIATCFStormID = src.getText(); 668 }); 669 ATCFEntrySiteTextField.addActionListener(ae -> { 670 JTextField src = (JTextField)ae.getSource(); 671 GUIATCFSiteID = src.getText(); 672 }); 673 674 ATCFOutputButton.addActionListener(ae -> { 675 // if on, turn off and vice versa 676 GUIATCFRecordOutputTF = !GUIATCFRecordOutputTF; 677 ATCFEntryStormLabel.setEnabled(GUIATCFRecordOutputTF); 678 ATCFEntryStormTextField.setEnabled(GUIATCFRecordOutputTF); 679 ATCFEntrySiteLabel.setEnabled(GUIATCFRecordOutputTF); 680 ATCFEntrySiteTextField.setEnabled(GUIATCFRecordOutputTF); 681 ATCFOutputButton.setSelected(GUIATCFRecordOutputTF); 682 }); 683 684 /* Land Flag button -- LAND */ 685 JLabel LandFlagLabel = new JLabel("Land Flag:"); 686 JRadioButton LandONButton = new JRadioButton("ON"); 687 LandONButton.setActionCommand("On"); 688 LandONButton.setSelected(true); 689 LandONButton.setToolTipText(TOOLTIP_LAND_FLAG_ON); 690 JRadioButton LandOFFButton = new JRadioButton("OFF"); 691 LandOFFButton.setActionCommand("Off"); 692 LandOFFButton.setSelected(false); 693 LandOFFButton.setToolTipText(TOOLTIP_LAND_FLAG_OFF); 694 ButtonGroup landgroup = new ButtonGroup(); 695 landgroup.add(LandONButton); 696 landgroup.add(LandOFFButton); 697 LandONButton.addActionListener(ae -> { 698 // LAND=YES 699 LandONButton.setSelected(true); 700 LandOFFButton.setSelected(false); 701 GUILandFlagTF = true; 702 }); 703 LandOFFButton.addActionListener(ae -> { 704 // LAND=NO 705 LandONButton.setSelected(false); 706 LandOFFButton.setSelected(true); 707 GUILandFlagTF = false; 708 }); 709 710 /* Wind Speed Vmax output button -- VOUT */ 711 JLabel VOutLabel = new JLabel("VMax:"); 712 JRadioButton V1MinButton = new JRadioButton("One-minute"); 713 V1MinButton.setActionCommand("One"); 714 V1MinButton.setSelected(true); 715 V1MinButton.setToolTipText("Maximum Wind Speed Averaged Over"); 716 JRadioButton V10MinButton = new JRadioButton("Ten-minute"); 717 V10MinButton.setActionCommand("Ten"); 718 V10MinButton.setSelected(false); 719 V10MinButton.setToolTipText("Maximum Wind Speed Averaged Over"); 720 ButtonGroup voutgroup = new ButtonGroup(); 721 voutgroup.add(V1MinButton); 722 voutgroup.add(V10MinButton); 723 V1MinButton.addActionListener(ae -> { 724 // 1-minute winds 725 V1MinButton.setSelected(true); 726 V10MinButton.setSelected(false); 727 GUIVmax1or10TF = true; 728 }); 729 V10MinButton.addActionListener(ae -> { 730 // 10-minute winds 731 V1MinButton.setSelected(false); 732 V10MinButton.setSelected(true); 733 GUIVmax1or10TF = false; 734 }); 735 736 JLabel blankfield = new JLabel(""); 737 738 // TJJ Jan 2018 - interim link to Help for McV 1.7 release 739 JButton helpLinkLabel = new JButton("<html><a href=\"https://www.ssec.wisc.edu\">Help</a></html>"); 740 helpLinkLabel.setToolTipText("Opens ADT Help PDF in your system web browser"); 741 helpLinkLabel.addActionListener(e -> { 742 WebBrowser.browse("https://www.ssec.wisc.edu/mcidas/software/v/resources/adt/McV_ADT_1p7.pdf"); 743 }); 744 745 GuiUtils.tmpInsets = GuiUtils.INSETS_5; 746 JComponent widgets = 747 GuiUtils.formLayout( 748 arr(left(hbox(arr(new JLabel("Storm Center Selection:"), manButton, autoButton), 5)), 749 filler(), 750 left(hbox(arr(manualStormSelectLabel), 10)), 751 filler(), 752 left(hbox(arr(filler(30, 1), latLonWidget))), filler(), 753 left(hbox(arr(autoStormSelectLabel), 10)), filler(), 754 left(hbox(arr(filler(30, 1), forecastBtn, forecastTypeBox, 755 forecastSelectLabel, forecastLabel), 5)), filler(), 756 left(hbox(arr(blankfield))), 757 filler(1, 5), 758 left(hbox(arr(new JLabel("HISTORY FILE INFORMATION")), 10)), filler(), 759 left(hbox(arr(filler(30, 1), historyBtn, new JLabel 760 ("Selected History File: "), selectedHistoryFile), 5)), 761 filler(), 762 left(hbox(arr(blankfield))), 763 filler(1, 5), 764 left(hbox(arr(new JLabel("PMW ANALYSIS")), 10)), filler(), 765 left(hbox(arr(filler(30, 1), PMWActivateButton, 766 pmwManDateLabel, pmwManDateTextField, pmwManTimeLabel, 767 pmwManTimeTextField, pmwManScoreLabel, pmwManScoreTextField), 5)), filler(), 768 left(hbox(arr(blankfield))), 769 filler(1, 5), 770 left(hbox(arr(new JLabel("MISCELLANEOUS OPTIONS")), 10)), filler(), 771 left(hbox(arr(filler(30, 1), new JLabel("MSLP Conversion Method:"), mslpDvorakButton, mslpCKZButton, ckzPenvLabel, ckzPenvTextField, ckz34radiusLabel, ckz34radiusTextField), 5)), filler(), 772 left(hbox(arr(filler(30, 1), sceneOverrideButton, OverrideLabel), 5)), filler(), 773 left(hbox(arr(filler(30, 1), LandFlagLabel, LandONButton, LandOFFButton, filler(20, 1), VOutLabel, V1MinButton, V10MinButton, filler(20, 1), RawTLabel, RawTTextField, RMWLabel, RMWTextField), 5)), filler(), 774 left(hbox(arr(filler(30, 1), ATCFOutputLabel, ATCFOutputButton, ATCFEntryStormLabel, ATCFEntryStormTextField, ATCFEntrySiteLabel, ATCFEntrySiteTextField), 5)), filler(), 775 left(hbox(arr(filler(80, 1), adtBtn, listBtn, helpLinkLabel), 20)), filler())); 776 777 JPanel controls = topLeft(widgets); 778 779 /* set up ADT Bulletin display area */ 780 resultArea = new JTextArea(); 781 resultArea.setEditable(false); 782 783 Font c = new Font("Courier", Font.BOLD, 12); 784 785 resultFrame = new JFrame("ADT Results"); 786 resultFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 787 JScrollPane resultScroller = new JScrollPane(resultArea); 788 resultScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 789 resultFrame.add(resultScroller, BorderLayout.CENTER); 790 resultFrame.setPreferredSize(new Dimension(400, 600)); 791 resultFrame.setFont(c); 792 793 /* set up ADT History File display area */ 794 historyFrame = new JFrame("ADT History File Listing"); 795 Container historyContainer = historyFrame.getContentPane(); 796 historyFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 797 JPanel historyTextPanel = new JPanel(); 798 FlowLayout historyListLayout = new FlowLayout(); 799 historyTextPanel.setLayout(historyListLayout); 800 historyListLayout.setAlignment(FlowLayout.CENTER); 801 802 historyArea = new JTextArea(50,150); 803 historyArea.setEditable(false); 804 JScrollPane historyScroller = new JScrollPane(historyArea); 805 historyScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 806 historyScroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 807 historyScroller.setPreferredSize(new Dimension(1200, 400)); 808 historyArea.setFont(c); 809 810 JPanel historyLabelPanel = new JPanel(); 811 FlowLayout HistoryLabelLayout = new FlowLayout(); 812 historyLabelPanel.setLayout(HistoryLabelLayout); 813 HistoryLabelLayout.setAlignment(FlowLayout.CENTER); 814 historyLabel = new JLabel("No History File Selected"); 815 historyLabel.setPreferredSize(new Dimension(800, 20)); 816 historyLabel.setFont(c); 817 818 /* history file Editing Date Selection window */ 819 JFrame historyDateFrame = new JFrame("History File Editor"); 820 Container historyDateContainer = historyDateFrame.getContentPane(); 821 historyDateFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 822 JPanel historyDatePanel = new JPanel(); 823 FlowLayout DateStartEndLayout = new FlowLayout(); 824 historyDatePanel.setLayout(DateStartEndLayout); 825 DateStartEndLayout.setAlignment(FlowLayout.CENTER); 826 JLabel historyDateStartLabel = new JLabel("Start:"); 827 JLabel historyDateStartDateLabel = new JLabel("Date"); 828 JTextField historyDateStartDateTextField = new JTextField("0000XXX00", 10); 829 JLabel historyDateStartTimeLabel = new JLabel("Time"); 830 JTextField historyDateStartTimeTextField = new JTextField("-1", 8); 831 JLabel historyDateEndLabel = new JLabel("End"); 832 JLabel historyDateEndDateLabel = new JLabel("Date"); 833 JTextField historyDateEndDateTextField = new JTextField("0000XXX00", 10); 834 JLabel historyDateEndTimeLabel = new JLabel("Time"); 835 JTextField historyDateEndTimeTextField = new JTextField("-1", 8); 836 837 JPanel historyButtonPanel = new JPanel(); 838 FlowLayout HistoryButtonLayout = new FlowLayout(); 839 historyButtonPanel.setLayout(HistoryButtonLayout); 840 HistoryButtonLayout.setAlignment(FlowLayout.CENTER); 841 842 JButton historySaveListingBtn = new JButton("Write History"); 843 historySaveListingBtn.setPreferredSize(new Dimension(200, 20)); 844 historySaveListingBtn.addActionListener(ae -> { 845 GUIHistoryFileListingName = selectHistoryFileOutput(); 846 logger.debug("saving history listing file name={}", GUIHistoryFileListingName); 847 GUIHistoryListFormat = -1; 848 }); 849 JButton historyWriteATCFBtn = new JButton("Write ATCF"); 850 historyWriteATCFBtn.setPreferredSize(new Dimension(200, 20)); 851 historyWriteATCFBtn.addActionListener(ae -> { 852 GUIATCFOutputTF = true; 853 GUIHistoryListFormat = 0; 854 logger.debug("calling ATCFFileOutput"); 855 ATCFFileOutput(0); 856 }); 857 historyLabelPanel.add(historyLabel); 858 historyLabelPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); 859 historyTextPanel.add(historyScroller); 860 historyTextPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); 861 862 historyButtonPanel.add(historySaveListingBtn); 863 historyButtonPanel.add(historyWriteATCFBtn); 864 historyButtonPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); 865 historyContainer.add(historyLabelPanel,BorderLayout.NORTH); 866 historyContainer.add(historyTextPanel,BorderLayout.CENTER); 867 historyContainer.add(historyButtonPanel,BorderLayout.SOUTH); 868 869 historyDateStartDateTextField.addActionListener(ae -> { 870 JTextField textField = (JTextField)ae.getSource(); 871 GUIStartDate = Functions.cmonth2julian(textField.getText()); 872 }); 873 historyDateStartTimeTextField.addActionListener(ae -> { 874 JTextField textField = (JTextField)ae.getSource(); 875 GUIStartTime = Integer.valueOf(textField.getText()); 876 }); 877 historyDateEndDateTextField.addActionListener(ae -> { 878 JTextField textField = (JTextField)ae.getSource(); 879 GUIEndDate = Functions.cmonth2julian(textField.getText()); 880 }); 881 historyDateEndTimeTextField.addActionListener(ae -> { 882 JTextField textField = (JTextField)ae.getSource(); 883 GUIEndTime = Integer.valueOf(textField.getText()); 884 }); 885 886 JPanel historyDateButtonPanel = new JPanel(); 887 FlowLayout DateButtonLayout = new FlowLayout(); 888 historyDateButtonPanel.setLayout(DateButtonLayout); 889 DateButtonLayout.setAlignment(FlowLayout.CENTER); 890 JRadioButton historyEditDeleteButton = new JRadioButton("Delete Records"); 891 historyEditDeleteButton.setActionCommand("Delete"); 892 historyEditDeleteButton.setSelected(false); 893 JRadioButton historyEditAddCommentButton = new JRadioButton("Add Comment"); 894 historyEditAddCommentButton.setActionCommand("Comment"); 895 historyEditAddCommentButton.setSelected(false); 896 ButtonGroup editgroup = new ButtonGroup(); 897 editgroup.add(historyEditDeleteButton); 898 editgroup.add(historyEditAddCommentButton); 899 JLabel historyEditAddCommentLabel = new JLabel("Comment:"); 900 JTextField historyEditAddCommentTextField = new JTextField("no comment entered", 25); 901 historyEditAddCommentTextField.setEnabled(false); 902 903 historyEditDeleteButton.addActionListener(ae -> { 904 // history Edit - Delete 905 historyEditDeleteButton.setSelected(true); 906 historyEditAddCommentButton.setSelected(false); 907 historyEditAddCommentLabel.setEnabled(false); 908 historyEditAddCommentTextField.setEnabled(false); 909 GUICommentAddTF = false; 910 GUIDeleteTF = true; 911 }); 912 913 historyEditAddCommentButton.addActionListener(ae -> { 914 // history Edit - Add Comment 915 historyEditDeleteButton.setSelected(false); 916 historyEditAddCommentButton.setSelected(true); 917 historyEditAddCommentLabel.setEnabled(true); 918 historyEditAddCommentTextField.setEnabled(true); 919 GUICommentAddTF = true; 920 GUIDeleteTF = false; 921 }); 922 historyEditAddCommentTextField.addActionListener(ae -> { 923 JTextField src = (JTextField)ae.getSource(); 924 GUICommentString = src.getText(); 925 }); 926 JPanel historyEditInputPanel = new JPanel(); 927 FlowLayout EditInputButtonLayout = new FlowLayout(); 928 historyEditInputPanel.setLayout(EditInputButtonLayout); 929 EditInputButtonLayout.setAlignment(FlowLayout.CENTER); 930 JButton historyEditApplyButton = new JButton("Apply Edits"); 931 historyEditApplyButton.setPreferredSize(new Dimension(150, 20)); 932 historyEditApplyButton.addActionListener(ae -> modifyHistoryFile()); 933 JButton historyEditCancelButton = new JButton("Cancel"); 934 historyEditCancelButton.setPreferredSize(new Dimension(150, 20)); 935 historyEditCancelButton.addActionListener(ae -> historyDateFrame.dispose()); 936 historyDatePanel.add(historyDateStartLabel); 937 historyDatePanel.add(historyDateStartDateLabel); 938 historyDatePanel.add(historyDateStartDateTextField); 939 historyDatePanel.add(historyDateStartTimeLabel); 940 historyDatePanel.add(historyDateStartTimeTextField); 941 historyDatePanel.add(historyDateEndLabel); 942 historyDatePanel.add(historyDateEndDateLabel); 943 historyDatePanel.add(historyDateEndDateTextField); 944 historyDatePanel.add(historyDateEndTimeLabel); 945 historyDatePanel.add(historyDateEndTimeTextField); 946 historyDatePanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); 947 historyDateButtonPanel.add(historyEditDeleteButton); 948 historyDateButtonPanel.add(historyEditAddCommentButton); 949 historyDateButtonPanel.add(historyEditAddCommentLabel); 950 historyDateButtonPanel.add(historyEditAddCommentTextField); 951 historyEditInputPanel.add(historyEditApplyButton); 952 historyEditInputPanel.add(historyEditCancelButton); 953 historyDateContainer.add(historyDatePanel, BorderLayout.NORTH); 954 historyDateContainer.add(historyDateButtonPanel, BorderLayout.CENTER); 955 historyDateContainer.add(historyEditInputPanel, BorderLayout.SOUTH); 956 957 /* set up Scene Type Override Window display window */ 958 overrideSceneFrame = new JFrame("Override Scene Type"); 959 overrideSceneFrame.setSize(new Dimension(400, 300)); 960 Container overrideSceneContainer = overrideSceneFrame.getContentPane(); 961 overrideSceneFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 962 JPanel overrideSceneCurrentPanel = new JPanel(); 963 FlowLayout OverrideSceneCurrentLayout = new FlowLayout(); 964 overrideSceneCurrentPanel.setLayout(OverrideSceneCurrentLayout); 965 OverrideSceneCurrentLayout.setAlignment(FlowLayout.CENTER); 966 JLabel overrideSceneCurrentLabel = new JLabel("Current Scene Type:"); 967 overrideSceneCurrentValueLabel = new JLabel(SCENE_TYPES[Env.OverrideSceneTypeIndex]); 968 JPanel overrideSceneSelectPanel = new JPanel(); 969 FlowLayout OverrideSceneSelectLayout = new FlowLayout(); 970 overrideSceneCurrentPanel.setLayout(OverrideSceneSelectLayout); 971 OverrideSceneSelectLayout.setAlignment(FlowLayout.CENTER); 972 JLabel overrideSceneSelectLabel = new JLabel("Select New Scene Type:"); 973 overrideSceneTypeBox = new JComboBox<>(SCENE_TYPES); 974 overrideSceneTypeBox.setSelectedIndex(Env.OverrideSceneTypeIndex); 975 overrideSceneTypeBox.setPreferredSize(new Dimension(150, 20)); 976 // overrideSceneTypeBox.addActionListener(ame -> Env.OverrideSceneTypeIndex = overrideSceneTypeBox.getSelectedIndex()); 977 JPanel overrideSceneButtonPanel = new JPanel(); 978 FlowLayout OverrideSceneButtonLayout = new FlowLayout(); 979 overrideSceneButtonPanel.setLayout(OverrideSceneButtonLayout); 980 OverrideSceneButtonLayout.setAlignment(FlowLayout.CENTER); 981 JButton overrideSceneAcceptButton = new JButton("Accept New Scene"); 982 overrideSceneAcceptButton.setPreferredSize(new Dimension(190, 20)); 983 overrideSceneAcceptButton.addActionListener(ae -> { 984 // accept new scene selection 985 overrideSceneFrame.setVisible(false); 986 Env.OverrideSceneTypeIndex = overrideSceneTypeBox.getSelectedIndex(); 987 OverrideLabel.setText(SCENE_TYPE_PREFIX + SCENE_TYPES[Env.OverrideSceneTypeIndex]); 988 overrideSceneCurrentValueLabel.setText(SCENE_TYPES[Env.OverrideSceneTypeIndex]); 989 // runADTmain(); 990 }); 991 JButton overrideSceneCancelButton = new JButton("Keep Current Scene"); 992 overrideSceneCancelButton.setPreferredSize(new Dimension(190, 20)); 993 overrideSceneCancelButton.addActionListener(ae -> { 994 overrideSceneFrame.setVisible(false); 995 // runADTmain(); 996 }); 997 overrideSceneCurrentPanel.add(overrideSceneCurrentLabel); 998 overrideSceneCurrentPanel.add(overrideSceneCurrentValueLabel); 999 overrideSceneSelectPanel.add(overrideSceneSelectLabel); 1000 overrideSceneSelectPanel.add(overrideSceneTypeBox); 1001 overrideSceneButtonPanel.add(overrideSceneAcceptButton); 1002 overrideSceneButtonPanel.add(overrideSceneCancelButton); 1003 overrideSceneContainer.add(overrideSceneCurrentPanel, BorderLayout.NORTH); 1004 overrideSceneContainer.add(overrideSceneSelectPanel, BorderLayout.CENTER); 1005 overrideSceneContainer.add(overrideSceneButtonPanel, BorderLayout.SOUTH); 1006 1007 JScrollPane scrollPane = new JScrollPane(controls); 1008 scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 1009 return scrollPane; 1010 } 1011 1012 /** 1013 * Do some cursory checking on validity of selected History file 1014 * @param historyFileName 1015 * @return true is seems ok 1016 */ 1017 1018 private boolean validHistoryFile(String historyFileName) { 1019 boolean seemsOk = true; 1020 1021 History CurrentHistory = new History(); 1022 1023 try { 1024 logger.debug("trying to read history file {}", historyFileName); 1025 CurrentHistory.ReadHistoryFile(historyFileName); 1026 } catch (IOException exception) { 1027 logger.warn("History file %s is not valid", historyFileName); 1028 seemsOk = false; 1029 } 1030 1031 logger.debug("Number of history records: {}", History.HistoryNumberOfRecords()); 1032 if (History.HistoryNumberOfRecords() == 0) seemsOk = false; 1033 return seemsOk; 1034 } 1035 1036 private void runADTmain() { 1037 if (!running) { 1038 running = true; 1039 adtBtn.setEnabled(false); 1040 adtBtn.setText("Running"); 1041 Misc.run(() -> { 1042 runADT(); 1043 ExitADT(); 1044 }); 1045 } 1046 } 1047 1048 private void runADT() { 1049 Main StormADT = new Main(); 1050 String ADTRunOutput; 1051 String ErrorMessage; 1052 1053 if (GUIFileOverrideTF) { 1054 String GUIOverrideFilePath = System.getenv("ODTHOME"); 1055 if (GUIOverrideFilePath == null) { 1056 GUIOverrideFilePath = System.getenv("HOME"); 1057 } 1058 String GUIOverrideFile = GUIOverrideFilePath + "/runadt.nogui.inputs.txt"; 1059 /* GUIFileOverrideCheckBoxToggle(); change toggle back to OFF */ 1060 int RetVal = ReadGUIOverrideInputFile(GUIOverrideFile); 1061 if (RetVal == -1) { 1062 ErrorMessage = String.format("Error reading GUI override file %s\n",GUIOverrideFile); 1063 System.out.println(ErrorMessage); 1064 userMessage(ErrorMessage); 1065 ExitADT(); 1066 return; 1067 } 1068 } 1069 1070 loadADTenvParameters(); 1071 1072 boolean RunAuto = Env.AutoTF; 1073 1074 // In auto mode, make sure a valid forecast file was selected 1075 if (RunAuto) { 1076 if (GUIForecastFileName == null) { 1077 userMessage("A valid forecast file must be selected to use Automated mode."); 1078 ExitADT(); 1079 return; 1080 } 1081 } 1082 1083 /* set storm position either through automated storm selection or by manual choice */ 1084 GetImageDateTime(); 1085 int ReturnVal = StormADT.GetInitialPosition(); // should set up to throw exception instead of return value 1086 if (ReturnVal < 0) { 1087 ErrorMessage = "Error obtaining initial position... exiting ADT\n"; 1088 System.out.println(ErrorMessage); 1089 userMessage(ErrorMessage); 1090 ExitADT(); 1091 } else { 1092 if (RunAuto) { 1093 try { 1094 float CenterLatitude = (float)Env.SelectedLatitude; 1095 float CenterLongitude = (float)Env.SelectedLongitude; 1096 /* System.out.println("pre-ARCHER latitude=%f longitude=%f\n",CenterLatitude,CenterLongitude); */ 1097 GetImageData(CenterLatitude, CenterLongitude); 1098 } catch (Exception exception) { 1099 ErrorMessage = "Error reading IR data pre-ARCHER\n"; 1100 System.out.println(ErrorMessage); 1101 userMessage(ErrorMessage); 1102 ExitADT(); 1103 return; 1104 } 1105 StormADT.GetARCHERPosition(); 1106 } else { 1107 if (probeLocation == null) { 1108 ErrorMessage = "Please select storm center location manually and try again"; 1109 System.out.println(ErrorMessage); 1110 userMessage(ErrorMessage); 1111 ExitADT(); 1112 return; 1113 } else { 1114 Env.SelectedLatitude = probeLocation.getLatitude().getValue(); 1115 Env.SelectedLongitude = probeLocation.getLongitude().getValue(); 1116 } 1117 } 1118 1119 try { 1120 float CenterLatitude = (float) Env.SelectedLatitude; 1121 float CenterLongitude = (float) Env.SelectedLongitude; 1122 /* System.out.println("latitude=%f longitude=%f domain=%d\n",CenterLatitude,CenterLongitude,DomainID); */ 1123 GetImageData(CenterLatitude, CenterLongitude); 1124 } catch (Exception e) { 1125 ErrorMessage = "Error reading IR data in getimagedata()\n"; 1126 logger.error(ErrorMessage.trim(), e); 1127 userMessage(ErrorMessage); 1128 ExitADT(); 1129 return; 1130 } 1131 1132 // TJJ Jun 2017 Just about ready, a few more validation checks and we can run 1133 // If CKZ chosen as MSLP Conversion Method, need to validate Penv and 34kt Radius fields 1134 // This may not be the best place to do this, but it's better than not doing it ;-) 1135 1136 if (GUIUseCKZTF) { 1137 1138 String newPenvStr = ckzPenvTextField.getText(); 1139 boolean badPenv = false; 1140 try { 1141 int newPenv = Integer.valueOf(newPenvStr); 1142 if (newPenv > 0) { 1143 GUICKZPenv = newPenv; 1144 Env.CKZPenv = GUICKZPenv; 1145 } else { 1146 badPenv = true; 1147 } 1148 } catch (NumberFormatException nfe) { 1149 badPenv = true; 1150 } 1151 1152 if (badPenv) { 1153 // Throw up a warning and bail out 1154 showBadIntWarning("Penv", newPenvStr); 1155 return; 1156 } 1157 1158 String newRadiusStr = ckz34radiusTextField.getText(); 1159 boolean badNewRadius = false; 1160 try { 1161 int newRadius = Integer.valueOf(newRadiusStr); 1162 if (newRadius > 0) { 1163 GUICKZGaleRadius = newRadius; 1164 Env.CKZGaleRadius = GUICKZGaleRadius; 1165 } else { 1166 badNewRadius = true; 1167 } 1168 } catch (NumberFormatException nfe) { 1169 badNewRadius = true; 1170 } 1171 1172 if (badNewRadius) { 1173 // Throw up a warning and bail out 1174 showBadIntWarning("Radius", newRadiusStr); 1175 return; 1176 } 1177 1178 } 1179 1180 try { 1181 logger.debug("RUNNING ADT ANALYSIS"); 1182 ADTRunOutput = StormADT.RunADTAnalysis(runFullADTAnalysis,GUIHistoryFileName); 1183 } catch (IOException exception) { 1184 ErrorMessage = "Error with call to StormADT.RunADT()\n"; 1185 logger.error(ErrorMessage.trim(), exception); 1186 userMessage(ErrorMessage); 1187 ExitADT(); 1188 return; 1189 } 1190 if (GUIOverrideSceneTF) { 1191 /* System.out.println("Overriding scene type!!! Scene value=%d\n",InitialSceneTypeValue); */ 1192 overrideSceneCurrentValueLabel.setText(SCENE_TYPES[Env.OverrideSceneTypeIndex]); 1193 overrideSceneFrame.pack(); 1194 overrideSceneFrame.setVisible(true); 1195 ExitADT(); 1196 } else { 1197 logger.debug("done running ADT"); 1198 1199 resultArea.setText(ADTRunOutput); 1200 resultFrame.pack(); 1201 resultFrame.setVisible(true); 1202 1203 // TJJ Dec 2017 1204 // This is in reference to Request #11, Bug #17 from 1205 // http://mcidas.ssec.wisc.edu/inquiry-v/?inquiry=1187 1206 // Since the intent here is to modify the currently active history file by appending 1207 // one record, and since that record insert had been previously commented out below, 1208 // we'll assume this was never working properly in the first place. To prevent the 1209 // current History File from being clobbered, we just won't do the re-write for now, 1210 // since as is, a deep Exception zeros out the file, and the original file should 1211 // at the very least remain unmodified. 1212 1213// if (GUIHistoryFileName != null) { 1214// try { 1215// // int[] InsertRecs = History.InsertHistoryRecord(runFullADTAnalysis,GUIHistoryFileName); 1216// /* System.out.println("*** Modified=%d InsertOverwriteFlag=%d***\n",InsertRecs[0],InsertRecs[1]); */ 1217// int NumRecs = History.WriteHistoryFile(GUIHistoryFileName); 1218// ErrorMessage = String.format("Number of records written to history file: %d\n", NumRecs); 1219// } catch (IOException exception) { 1220// ErrorMessage = String.format("Error writing history file %s\n", GUIHistoryFileName); 1221// } catch (Exception e) { 1222// logger.error("Exception: ", e); 1223// ErrorMessage = String.format("Error writing history file %s\n", GUIHistoryFileName); 1224// } 1225// logger.warn(ErrorMessage.trim()); 1226// userMessage(ErrorMessage); 1227// } 1228 1229 if (GUIATCFRecordOutputTF) { 1230 ATCFFileOutput(-1); 1231 } 1232 1233 ExitADT(); 1234 } 1235 } 1236 } 1237 1238 /** 1239 * Show a warning about a certain parameter needing to be greater than zero. 1240 * 1241 * @param type Parameter name. Cannot be {@code null}. 1242 * @param badValue Erroneous value. Cannot be {@code null}. 1243 */ 1244 private void showBadIntWarning(String type, String badValue) { 1245 String msg = "Invalid %s value: %s\nPlease provide a positive integer."; 1246 JOptionPane.showMessageDialog(null, 1247 String.format(msg, type, badValue)); 1248 ExitADT(); 1249 } 1250 1251 private void ExitADT() { 1252 running = false; 1253 adtBtn.setEnabled(true); 1254 adtBtn.setText("Run Analysis"); 1255 } 1256 1257 /* 1258 * Override for additional local cleanup 1259 * (non-Javadoc) 1260 * @see ucar.unidata.idv.control.DisplayControlImpl#doRemove() 1261 */ 1262 1263 @Override public void doRemove() throws RemoteException, VisADException { 1264 super.doRemove(); 1265 if (resultFrame != null) { 1266 resultFrame.dispose(); 1267 } 1268 if (historyFrame != null) { 1269 historyFrame.dispose(); 1270 } 1271 } 1272 1273 private void listHistoryFile() { 1274 HistoryListOutput = null; 1275 1276 History CurrentHistory = new History(); 1277 1278 // Make sure a valid History File has been selected. At startup, value will be null 1279 if (GUIHistoryFileName == null) { 1280 JOptionPane.showMessageDialog(null, 1281 "Please first select a valid ADT History File."); 1282 return; 1283 } 1284 1285 try { 1286 logger.debug("trying to read history file {}", GUIHistoryFileName); 1287 CurrentHistory.ReadHistoryFile(GUIHistoryFileName); 1288 } catch (IOException exception) { 1289 String ErrorMessage = String.format("History file %s is not found",GUIHistoryFileName); 1290 logger.warn(ErrorMessage); 1291 userMessage(ErrorMessage); 1292 return; 1293 } 1294 1295 logger.debug("Number of history records: {}", History.HistoryNumberOfRecords()); 1296 1297 HistoryListOutput = History.ListHistory(0, -1, "CIMS", "99X"); 1298 historyLabel.setText(GUIHistoryFileName); 1299 historyArea.setText(HistoryListOutput); 1300 historyFrame.pack(); 1301 historyFrame.setVisible(true); 1302 1303 } 1304 1305 private void modifyHistoryFile() { 1306 1307 if (GUIDeleteTF) { 1308 // delete records 1309 int DeleteReturn[] = History.DeleteHistoryRecords(runFullADTAnalysis,GUIHistoryFileName); 1310 logger.debug("deleted {} records... modified {} records", DeleteReturn[1],DeleteReturn[0]); 1311 } else if( GUICommentAddTF) { 1312 // 1313 int CommentAddReturn = History.CommentHistoryRecords(GUICommentString); 1314 logger.debug("added comment to {} records",CommentAddReturn); 1315 } else { 1316 // invalid selection 1317 logger.warn("entered invalid selection!"); 1318 } 1319 1320 try { 1321 int HistoryFileRecords = History.WriteHistoryFile(GUIHistoryFileName); 1322 if (HistoryFileRecords >= 0) { 1323 logger.debug("wrote {} records to '{}'", HistoryFileRecords, GUIHistoryFileName); 1324 } 1325 } catch (IOException exception) { 1326 String ErrorMessage = String.format("error updating history file %s",GUIHistoryFileName); 1327 System.out.println(ErrorMessage); 1328 userMessage(ErrorMessage); 1329 } 1330 } 1331 1332 private String selectHistoryFile() { 1333 1334 String fileNameReturn = null; 1335 1336 JFrame historyFileFrame = new JFrame(); 1337 JFileChooser historyFileChooser = new JFileChooser(); 1338 String historyPath = System.getenv("ODTHISTORY"); 1339 if (historyPath == null) { 1340 historyPath = getLastPath("mcv.adt.lasthistorypath", System.getProperty("user.home")); 1341 } 1342 historyFileChooser.setCurrentDirectory(new File(historyPath)); 1343 historyFileChooser.setDialogTitle("Select ADT History File"); 1344 int returnVal = historyFileChooser.showOpenDialog(historyFileFrame); 1345 if (returnVal == JFileChooser.APPROVE_OPTION) { 1346 File file = historyFileChooser.getSelectedFile(); 1347 fileNameReturn = file.getAbsolutePath(); 1348 setLastPath("mcv.adt.lasthistorypath", file.getPath()); 1349 } 1350 1351 return fileNameReturn; 1352 } 1353 1354 /** 1355 * Returns the path that corresponds to the given McIDAS-V property ID. 1356 * 1357 * @param id ID used to store user's last selected path. 1358 * @param defaultPath Path to use if {@code id} has not been set. 1359 * 1360 * @return Either the {@code String} representation of the last selected 1361 * path, or {@code defaultPath}. 1362 */ 1363 private String getLastPath(String id, String defaultPath) { 1364 McIDASV mcv = (McIDASV)getIdv(); 1365 String path = defaultPath; 1366 if (mcv != null) { 1367 path = mcv.getObjectStore().get(id, defaultPath); 1368 } 1369 return path; 1370 } 1371 1372 /** 1373 * Sets the value of the given McIDAS-V property ID to the specified path. 1374 * 1375 * @param id ID to store. 1376 * @param path Path to associate with {@code id}. 1377 */ 1378 private void setLastPath(String id, String path) { 1379 String okayPath = (path != null) ? path : ""; 1380 McIDASV mcv = (McIDASV)getIdv(); 1381 if (mcv != null) { 1382 XmlObjectStore store = mcv.getObjectStore(); 1383 store.put(id, okayPath); 1384 store.saveIfNeeded(); 1385 } 1386 } 1387 1388 /** 1389 * Write a new ADT History File 1390 * @return true if ok 1391 */ 1392 1393 private String selectHistoryFileOutput() { 1394 1395 File saveFile = null; 1396 String ErrorMessage; 1397 1398 historyFileSaveChooser = new JFileChooser(); 1399 historyFileSaveChooser.setCurrentDirectory(null); 1400 historyFileSaveChooser.setDialogTitle("Save ADT History File"); 1401 int returnVal = historyFileSaveChooser.showSaveDialog(historyFrame); 1402 if (returnVal == JFileChooser.APPROVE_OPTION) { 1403 saveFile = historyFileSaveChooser.getSelectedFile(); 1404 try (FileWriter outFile = new FileWriter(saveFile)) { 1405 outFile.write(HistoryListOutput); 1406 outFile.flush(); 1407 outFile.close(); 1408 ErrorMessage = String.format("success writing history file output file %s\n",saveFile.toString()); 1409 } catch (IOException ex) { 1410 logger.error("problem writing to history file output", ex); 1411 ErrorMessage = String.format("error writing history file output file %s\n",saveFile.toString()); 1412 } 1413 System.out.println(ErrorMessage); 1414 userMessage(ErrorMessage); 1415 } 1416 1417 String saveFilePath = null; 1418 if (saveFile != null) { 1419 saveFilePath = saveFile.getAbsolutePath(); 1420 } 1421 return saveFilePath; 1422 1423 } 1424 1425 /** 1426 * Write out the ATCF file 1427 * @param outputstyle 1428 * @return true if written ok 1429 */ 1430 1431 private boolean ATCFFileOutput(int outputstyle) { 1432 File saveFile = null; 1433 String ATCFOutputFileName; 1434 String ATCFOutputFilePath; 1435 String ATCFFileOutput; 1436 String ATCFMessage; 1437 boolean writefileTF = false; 1438 boolean returnStatus = true; 1439 1440 if (outputstyle == 0) { 1441 // output entire history file in ATCF 1442 historyFileSaveChooser = new JFileChooser(); 1443 historyFileSaveChooser.setCurrentDirectory(null); 1444 historyFileSaveChooser.setDialogTitle("Write ATCF File"); 1445 int returnVal = historyFileSaveChooser.showSaveDialog(historyFrame); 1446 if (returnVal == JFileChooser.APPROVE_OPTION) { 1447 saveFile = historyFileSaveChooser.getSelectedFile(); 1448 writefileTF = true; 1449 } else if (returnVal == JFileChooser.CANCEL_OPTION) { 1450 // User has pressed cancel button 1451 writefileTF = false; 1452 } 1453 logger.debug("saving ATCF history listing file name={} writeTF={}", saveFile, writefileTF); 1454 } else { 1455 1456 GUIATCFStormID = ATCFEntryStormTextField.getText(); 1457 GUIATCFSiteID = ATCFEntrySiteTextField.getText(); 1458 1459 if ((GUIATCFStormID == null) || (GUIATCFSiteID == null)) { 1460 JOptionPane.showMessageDialog(this.getMainPanel(), "Please provide valid Storm and Site IDs for ATCF output."); 1461 return false; 1462 } 1463 1464 // Validate the Storm ID and Site ID inputs 1465 boolean siteStormValid = true; 1466 // Storm must be 3-char 1467 if (GUIATCFStormID.length() != 3) { 1468 siteStormValid = false; 1469 } else { 1470 // It is 3-char, make sure it's DDC (digit-digit-char) 1471 if (! GUIATCFStormID.matches("\\d\\d[A-Z]")) { 1472 siteStormValid = false; 1473 } 1474 } 1475 // Site must be 4-char 1476 if (GUIATCFSiteID.length() != 4) { 1477 siteStormValid = false; 1478 } 1479 1480 if (! siteStormValid) { 1481 JOptionPane.showMessageDialog(null, "Please provide valid Storm and Site IDs for ATCF output."); 1482 return false; 1483 } 1484 1485 // call routine to generate ATCF file name for single analysis record 1486 logger.debug("stormID={} siteID={}", GUIATCFStormID, GUIATCFSiteID); 1487 ATCFOutputFileName = Functions.adt_atcffilename(GUIATCFStormID,GUIATCFSiteID); 1488 logger.debug("atcf output name={}*", ATCFOutputFileName); 1489 ATCFOutputFilePath = System.getenv("ODTOUTPUT"); 1490 if (ATCFOutputFilePath == null) { 1491 ATCFOutputFilePath = System.getenv("HOME"); 1492 } 1493 logger.debug("atcf output path={}*", ATCFOutputFilePath); 1494 saveFile = new File(ATCFOutputFilePath + File.separator + ATCFOutputFileName); 1495 logger.debug("atcf output name={}*", saveFile.toString()); 1496 writefileTF = true; 1497 } 1498 // call routine to output file 1499 logger.info("Site ID: " + GUIATCFSiteID + ", Storm ID: " + GUIATCFStormID); 1500 if ((GUIATCFSiteID == null) || (GUIATCFStormID == null)) { 1501 JOptionPane.showMessageDialog(historyFrame, "You must first activate ATCF output"); 1502 return returnStatus; 1503 } 1504 ATCFFileOutput = History.ListHistory(outputstyle, GUIHistoryListFormat, GUIATCFSiteID, GUIATCFStormID); 1505 if (writefileTF) { 1506 try (FileWriter outFile = new FileWriter(saveFile)) { 1507 outFile.write(ATCFFileOutput); 1508 outFile.flush(); 1509 outFile.close(); 1510 ATCFMessage = String.format("Success writing ATCF file %s",saveFile); 1511 } catch (IOException ex) { 1512 logger.error("problem writing to ATCF file", ex); 1513 ATCFMessage = String.format("Error writing ATCF file %s",saveFile); 1514 } 1515 System.out.println(ATCFMessage); 1516 userMessage(ATCFMessage); 1517 } 1518 return returnStatus; 1519 } 1520 1521 private String selectForecastFile() { 1522 1523 String fileNameReturn = null; 1524 1525 logger.debug("in selectForecastFile"); 1526 JFrame forecastFileFrame = new JFrame(); 1527 JFileChooser forecastFileChooser = new JFileChooser(); 1528 String forecastPath = System.getenv("ODTAUTO"); 1529 if (forecastPath == null) { 1530 forecastPath = getLastPath("mcv.adt.lastforecastpath", System.getProperty("user.home")); 1531 } 1532 logger.debug("forecast path={}", forecastPath); 1533 forecastFileChooser.setCurrentDirectory(new File(forecastPath)); 1534 forecastFileChooser.setDialogTitle("Select ADT Forecast File"); 1535 int returnVal = forecastFileChooser.showOpenDialog(forecastFileFrame); 1536 logger.debug("retVal={}", returnVal); 1537 if (returnVal == JFileChooser.APPROVE_OPTION) { 1538 File file = forecastFileChooser.getSelectedFile(); 1539 fileNameReturn = file.getAbsolutePath(); 1540 setLastPath("mcv.adt.lastforecastpath", file.getPath()); 1541 } else { 1542 logger.error("error with file chooser"); 1543 } 1544 return fileNameReturn; 1545 } 1546 1547 private void getADTenvParameters() { 1548 History.InitCurrent(true); 1549 GUIHistoryFileName = null; 1550 1551 /* load initial ADT Environmental parameters */ 1552 GUIDeleteTF = Env.DeleteTF; 1553 GUIRunAutoTF = Env.AutoTF; 1554 GUIOverrideSceneTF = Env.OverSceneTF; 1555 GUIOverrideTF = Env.OverTF; 1556 GUIATCFOutputTF = Env.ATCFOutputTF; 1557 GUIATCFRecordOutputTF = Env.ATCFRecordOutputTF; 1558 GUIInitStrengthTF = Env.InitStrengthTF; 1559 GUILandFlagTF = Env.LandFlagTF; 1560 GUIUseCKZTF = Env.UseCKZTF; 1561 GUIVmax1or10TF = Env.Vmax1or10TF; 1562 GUICommentAddTF = Env.CommentAddTF; 1563 GUIPMWActivateTF = Env.UsePMWTF; 1564 1565 /* integer values */ 1566 GUIDomainID = Env.DomainID; 1567 GUIForecastType = Env.ForecastFileType; 1568 GUIMWJulianDate = Env.MWJulianDate; 1569 GUIMWHHMMSSTime = Env.MWHHMMSSTime; 1570 GUIStartDate = Env.StartJulianDate; 1571 GUIStartTime = Env.StartHHMMSSTime; 1572 GUIEndDate = Env.EndJulianDate; 1573 GUIEndTime = Env.EndHHMMSSTime; 1574 GUIHistoryListFormat = Env.HistoryListFormat; 1575 /* double values */ 1576 GUIRawTValue = Env.InitRawTValue; 1577 GUIMWScore = Env.MWScore; 1578 GUICKZGaleRadius = Env.CKZGaleRadius; 1579 GUICKZPenv = Env.CKZPenv; 1580 GUIRMWSize = Env.RMWSize; 1581 GUIUserLatitude = Env.SelectedLatitude; 1582 GUIUserLongitude = Env.SelectedLongitude; 1583 1584 GUIForecastFileName = Env.ForecastFileName; // needed? 1585 GUIHistoryFileListingName = Env.ASCIIOutputFileName; // needed? 1586 GUIATCFStormID = Env.StormIDString; 1587 GUIATCFSiteID = Env.ATCFSourceAgcyIDString; 1588 1589 } 1590 1591 private void loadADTenvParameters() { 1592 /* Env GlobalVariables = new Env(); */ 1593 1594 logger.debug("setting env parameters"); 1595 1596 // send ADT Environmental parameters to Env prior to running ADT 1597 // boolean values 1598 Env.DeleteTF = GUIDeleteTF; 1599 Env.AutoTF = GUIRunAutoTF; 1600 Env.OverTF = GUIOverrideTF; 1601 Env.ATCFOutputTF = GUIATCFOutputTF; 1602 Env.ATCFRecordOutputTF = GUIATCFRecordOutputTF; 1603 Env.InitStrengthTF = GUIInitStrengthTF; 1604 Env.LandFlagTF = GUILandFlagTF; 1605 Env.UseCKZTF = GUIUseCKZTF; 1606 Env.Vmax1or10TF = GUIVmax1or10TF; 1607 Env.CommentAddTF = GUICommentAddTF; 1608 Env.OverSceneTF = GUIOverrideSceneTF; 1609 Env.UsePMWTF = GUIPMWActivateTF; 1610 1611 // integer values 1612 Env.DomainID = GUIDomainID; 1613 Env.ForecastFileType = GUIForecastType; 1614 Env.MWJulianDate = GUIMWJulianDate; 1615 Env.MWHHMMSSTime = GUIMWHHMMSSTime; 1616 Env.StartJulianDate = GUIStartDate; 1617 Env.StartHHMMSSTime = GUIStartTime; 1618 Env.EndJulianDate = GUIEndDate; 1619 Env.EndHHMMSSTime = GUIEndTime; 1620 Env.HistoryListFormat = GUIHistoryListFormat; 1621 // double values 1622 Env.InitRawTValue = GUIRawTValue; 1623 Env.MWScore = GUIMWScore; 1624 Env.CKZGaleRadius = GUICKZGaleRadius; 1625 Env.CKZPenv = GUICKZPenv; 1626 Env.RMWSize = GUIRMWSize; 1627 Env.SelectedLatitude = GUIUserLatitude; 1628 Env.SelectedLongitude = GUIUserLongitude; 1629 1630 logger.debug("load forecast file name={}", GUIForecastFileName); 1631 Env.ForecastFileName = GUIForecastFileName; // needed? 1632 Env.ASCIIOutputFileName = GUIHistoryFileListingName; // needed? 1633 Env.StormIDString = GUIATCFStormID; 1634 Env.ATCFSourceAgcyIDString = GUIATCFSiteID; 1635 1636 } 1637 1638 private int ReadGUIOverrideInputFile(String GUIOverrideFile) { 1639 1640 logger.debug("opening file '{}'", GUIOverrideFile); 1641 1642 File GUIDataFile = new File(GUIOverrideFile); 1643 String delims = "[ ]+"; 1644 String line; 1645 int retval = 1; 1646 1647 GUIOverrideTF = false; 1648 GUIOverrideSceneTF = false; 1649 GUICommentString = null; 1650 GUIRunAutoTF = true; 1651 GUIDeleteTF = false; 1652 GUICommentAddTF = false; 1653 GUIStartDate = 1900001; 1654 GUIStartTime = 000000; 1655 GUIEndDate = 1900001; 1656 GUIEndTime = 000000; 1657 GUIUserLatitude = -99.5; 1658 GUIUserLongitude = -999.5; 1659 GUIDomainID = 0; 1660 runFullADTAnalysis = true; 1661 1662 try { 1663 Scanner GUIFile = new Scanner(GUIDataFile); 1664 while (GUIFile.hasNextLine()) { 1665 if ((line = GUIFile.nextLine()).isEmpty()){ 1666 break; 1667 } else { 1668 String[] tokens = line.split(delims); 1669 String IDstring = tokens[0]; 1670 String RecValue = tokens[1]; 1671 /* System.out.println("scanning IDstring=%s\n",IDstring); */ 1672 switch (IDstring) { 1673 case "ATCFOutputTF": 1674 GUIATCFOutputTF = Boolean.valueOf(RecValue); 1675 break; 1676 case "ATCFRecordOutputTF": 1677 GUIATCFRecordOutputTF = Boolean.valueOf(RecValue); 1678 break; 1679 case "InitStrengthTF": 1680 GUIInitStrengthTF = Boolean.valueOf(RecValue); 1681 break; 1682 case "LandFlagTF": 1683 GUILandFlagTF = Boolean.valueOf(RecValue); 1684 break; 1685 case "UseCKZTF": 1686 GUIUseCKZTF = Boolean.valueOf(RecValue); 1687 break; 1688 case "Vmax1or10TF": 1689 GUIVmax1or10TF = Boolean.valueOf(RecValue); 1690 break; 1691 case "UsePMWTF": 1692 GUIPMWActivateTF = Boolean.valueOf(RecValue); 1693 break; 1694 case "ForecastType": 1695 GUIForecastType = Integer.valueOf(RecValue); 1696 break; 1697 case "MWJulianDate": 1698 GUIMWJulianDate = Integer.valueOf(RecValue); 1699 break; 1700 case "MWHHMMSSTime": 1701 GUIMWHHMMSSTime = Integer.valueOf(RecValue); 1702 break; 1703 case "HistoryListFormat": 1704 GUIHistoryListFormat = Integer.valueOf(RecValue); 1705 break; 1706 case "RawTValue": 1707 GUIRawTValue = Double.valueOf(RecValue); 1708 break; 1709 case "MWScore": 1710 GUIMWScore = Double.valueOf(RecValue); 1711 break; 1712 case "CKZGaleRadius": 1713 GUICKZGaleRadius = Double.valueOf(RecValue); 1714 break; 1715 case "CKZPenv": 1716 GUICKZPenv = Double.valueOf(RecValue); 1717 break; 1718 case "RMWSize": 1719 GUIRMWSize = Double.valueOf(RecValue); 1720 break; 1721 case "HistoryFileName": 1722 GUIHistoryFileName = RecValue; 1723 break; 1724 case "ForecastFileName": 1725 GUIForecastFileName = RecValue; 1726 break; 1727 case "HistoryFileListingName": 1728 GUIHistoryFileListingName = RecValue; 1729 break; 1730 case "ATCFStormID": 1731 GUIATCFStormID = RecValue; 1732 break; 1733 case "ATCFSiteID": 1734 GUIATCFSiteID = RecValue; 1735 break; 1736 default: 1737 break; 1738 } 1739 } 1740 } 1741 GUIFile.close(); 1742 } catch (IOException ex) { 1743 retval = -1; 1744 } 1745 return retval; 1746 } 1747 1748 public void latLonWidgetChanged() { 1749 logger.debug("latlonwidgetchanged called"); 1750 try { 1751 logger.debug("latlon widget changed"); 1752 String message = latLonWidget.isValidValues(); 1753 if (message != null) { 1754 userMessage(message); 1755 return; 1756 } 1757 probeLocation = ucar.visad.Util.makeEarthLocation( 1758 latLonWidget.getLat(), latLonWidget.getLon()).getLatLonPoint(); 1759 } catch (Exception e) { 1760 logException("Handling LatLonWidget changed", e); 1761 } 1762 } 1763 1764 protected boolean shouldAddDisplayListener() { 1765 return true; 1766 } 1767 1768 protected boolean shouldAddControlListener() { 1769 return true; 1770 } 1771 1772 protected boolean canHandleEvents() { 1773 if (!getHaveInitialized() || (getMakeWindow() && !getWindowVisible())) { 1774 return false; 1775 } 1776 return isGuiShown(); 1777 } 1778 1779 public void handleDisplayChanged(DisplayEvent event) { 1780 super.handleDisplayChanged(event); 1781 if (canHandleEvents()) { 1782// int id = event.getId(); 1783// // String idstring = event.toString(); 1784// // InputEvent inputEvent = event.getInputEvent(); 1785// // System.out.println("event ID=%d %s\n",id,idstring); 1786// try { 1787// if (id == DisplayEvent.MOUSE_PRESSED_LEFT) { 1788// logger.debug("Manual Position Selection"); 1789// probeLocation = toEarth(event).getLatLonPoint(); 1790// updateProbeLocation(); 1791// } 1792// } catch (Exception e) { 1793// logException("Error selecting position with mouse", e); 1794// } 1795 } 1796 } 1797 1798 /** 1799 * Respond to the probe being dragged. 1800 * 1801 * @param event Event to handle. 1802 */ 1803 @Override public void propertyChange(PropertyChangeEvent event) { 1804 if (canHandleEvents() && SelectorDisplayable.PROPERTY_POSITION.equals(event.getPropertyName())) { 1805 try { 1806 RealTuple position = probe.getPosition(); 1807 double[] loc = position.getValues(); 1808 logger.debug("Manual Position Selection loc={}", loc); 1809 // note: loc[1] is apparently latitude, and loc[0] is longitude! 1810 probeLocation = 1811 makeEarthLocation(loc[1], loc[0], loc[2]).getLatLonPoint(); 1812 SwingUtilities.invokeLater(this::updatePositionWidget); 1813 } catch (VisADException | RemoteException ex) { 1814 logger.error("Error updating probe location", ex); 1815 } 1816 } else { 1817 super.propertyChange(event); 1818 } 1819 } 1820 1821 /** 1822 * Update {@link #latLonWidget} if it exists. 1823 * 1824 * <p>Note: must be called from the event dispatch thread.</p> 1825 */ 1826 private void updatePositionWidget() { 1827 if (latLonWidget != null) { 1828 try { 1829 logger.trace("attempting to update widget! lat={} lon={}", probeLocation.getLatitude(), probeLocation.getLongitude()); 1830 latLonWidget.setLat(getDisplayConventions().formatLatLon(probeLocation.getLatitude().getValue(CommonUnit.degree))); 1831 latLonWidget.setLon(getDisplayConventions().formatLatLon(probeLocation.getLongitude().getValue(CommonUnit.degree))); 1832 } catch (VisADException ex) { 1833 logger.error("Error updating GUI with probe position", ex); 1834 } 1835 } else { 1836 logger.trace("no lat/lon widget to update!"); 1837 } 1838 } 1839 1840 private void updateProbeLocation() { 1841 try { 1842 if (probeLocation == null) { 1843 return; 1844 } 1845 double lon = probeLocation.getLongitude().getValue(CommonUnit.degree); 1846 double lat = probeLocation.getLatitude().getValue(CommonUnit.degree); 1847 probe.setPosition( 1848 new RealTuple(RealTupleType.SpatialEarth3DTuple, new double[] { lon, lat, 0 })); 1849 probe.setVisible(true); 1850 1851 GUIUserLatitude = lat; // added TLO 1852 GUIUserLongitude = lon; // added TLO 1853 logger.debug("set lat/lon from probe at lat={} lon={}", GUIUserLatitude, GUIUserLongitude); 1854 if (latLonWidget != null) { 1855 latLonWidget.setLat(getDisplayConventions().formatLatLon( 1856 probeLocation.getLatitude().getValue(CommonUnit.degree))); 1857 latLonWidget.setLon(getDisplayConventions().formatLatLon( 1858 probeLocation.getLongitude().getValue(CommonUnit.degree))); 1859 } 1860 } catch (Exception e) { 1861 logException("Handling probe changed", e); 1862 } 1863 } 1864 1865 /** 1866 * Set the ProbeLocation property. 1867 * 1868 * @param value New value for ProbeLocation. 1869 */ 1870 public void setProbeLocation(LatLonPoint value) { 1871 probeLocation = value; 1872 } 1873 1874 /** 1875 * Get the ProbeLocation property. 1876 * 1877 * @return The ProbeLocation 1878 */ 1879 public LatLonPoint getProbeLocation() { 1880 return probeLocation; 1881 } 1882 1883 protected FlatField getFlatField(FieldImpl data) 1884 throws VisADException, RemoteException 1885 { 1886 FlatField ff; 1887 if (GridUtil.isSequence(data)) { 1888 ff = (FlatField)data.getSample(0); 1889 } else { 1890 ff = (FlatField)data; 1891 } 1892 return ff; 1893 } 1894 1895 public EarthLocation toEarth(DisplayEvent event) 1896 throws VisADException, RemoteException 1897 { 1898 NavigatedDisplay d = getNavigatedDisplay(); 1899 return (d == null) ? null : d.getEarthLocation(toBox(event)); 1900 } 1901 1902 private void GetImageDateTime() { 1903 1904 RealTuple timeTuple; 1905 Real tt; 1906 DateTime dat; 1907 1908 List infos = getDisplayInfos(); 1909 DisplayInfo displayInfo = (DisplayInfo) infos.get(0); 1910 1911 try { 1912 Animation anime = displayInfo.getViewManager().getAnimation(); 1913 Set timeSet = anime.getSet(); 1914 int pos = anime.getCurrent(); 1915 1916 timeTuple = DataUtility.getSample(timeSet, pos); 1917 tt = (Real) timeTuple.getComponent(0); 1918 dat = new DateTime(tt); 1919 } catch (VisADException e) { 1920 logException("Handling data", e); 1921 return; 1922 } catch (RemoteException f) { 1923 logger.warn("Something went wrong!", f); 1924 return; 1925 } 1926 1927 double curdate = dat.getValue(); 1928 logger.debug("curdate={}",curdate); 1929 1930 Date datevalue = new Date((long)curdate*1000); 1931 1932 SimpleDateFormat dateformat = new SimpleDateFormat("yyyyDDD"); 1933 SimpleDateFormat timeformat = new SimpleDateFormat("HHmmss"); 1934 dateformat.setTimeZone(TimeZone.getTimeZone("GMT")); 1935 timeformat.setTimeZone(TimeZone.getTimeZone("GMT")); 1936 1937 String JulianDate = dateformat.format(datevalue); 1938 String HHMMSSTime = timeformat.format(datevalue); 1939 int ImageDateInt = Integer.valueOf(JulianDate); 1940 int ImageTimeInt = Integer.valueOf(HHMMSSTime); 1941 // System.out.println("image date = %d image time=%d\n",ImageDateInt,ImageTimeInt); */ 1942 1943 Data.IRData_JulianDate = ImageDateInt; 1944 Data.IRData_HHMMSSTime = ImageTimeInt; 1945 1946 logger.debug("IMAGE DATE={} TIME={}", Data.IRData_JulianDate, Data.IRData_HHMMSSTime); 1947 } 1948 1949 private void GetImageData(float CenterLatitude, float CenterLongitude) { 1950 logger.debug("creating ReadIRImage()..."); 1951 1952 // ReadIRImage IRImage = new ReadIRImage(); 1953 1954 FlatField ffield; 1955 int SatelliteID; 1956 int channel; 1957 1958 List sources = new ArrayList(); 1959 1960 logger.debug("entering getimagedata"); 1961 boolean isTemp = false; 1962 choice.getDataSources(sources); 1963 try { 1964 List infos = getDisplayInfos(); 1965 DataInstance de = getDataInstance(); 1966 DisplayInfo displayInfo = (DisplayInfo) infos.get(0); 1967 1968 Animation anime = displayInfo.getViewManager().getAnimation(); 1969 // Set timeSet = anime.getSet(); 1970 int pos = anime.getCurrent(); 1971 ffield = DataUtil.getFlatField(de.getData()); 1972 DataSourceImpl dsi = (DataSourceImpl) sources.get(0); 1973 1974 if (dsi instanceof AddeImageDataSource) { 1975 ImageDataSource dds = (ImageDataSource) sources.get(0); 1976 List imageLists = dds.getImageList(); 1977 1978 AddeImageDescriptor aid = (AddeImageDescriptor) imageLists.get(pos); 1979 AreaDirectory ad = aid.getDirectory(); 1980 SatelliteID = ad.getSensorID(); 1981 int[] bands = ad.getBands(); 1982 channel = bands[0]; 1983 1984 isTemp = Util.isCompatible(ffield, AirTemperature.getRealType()); 1985 } else { 1986 channel = 4; 1987 SatelliteID = 70; 1988 // String name = ffield.getSample(0).getType().prettyString(); 1989 } 1990 } catch (VisADException e) { 1991 logException("Handling data", e); 1992 return; 1993 } catch (RemoteException f) { 1994 logger.warn("Something went wrong!", f); 1995 return; 1996 } 1997 1998 // String shortName = choice.getName(); 1999 2000 Env.UserDefineDomain = 0; // automated 2001 // String sidName = Functions.adt_sattypes(SatelliteID); 2002 2003 logger.debug("SatelliteID={}", SatelliteID); 2004 2005 try { 2006 ReadIRImage.ReadIRDataFile(ffield, 2007 CenterLatitude, 2008 CenterLongitude, 2009 SatelliteID, 2010 channel, 2011 isTemp); 2012 } 2013 catch (Exception ex) { 2014 logger.error("ReadIRImage failed", ex); 2015 } 2016 } 2017}