001 /* 002 * $Id: AddeRadarChooser.java,v 1.23 2012/02/19 17:35:35 davep 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.chooser.adde; 032 033 import static javax.swing.GroupLayout.DEFAULT_SIZE; 034 import static javax.swing.GroupLayout.PREFERRED_SIZE; 035 import static javax.swing.GroupLayout.Alignment.BASELINE; 036 import static javax.swing.GroupLayout.Alignment.LEADING; 037 import static javax.swing.LayoutStyle.ComponentPlacement.RELATED; 038 039 import java.util.ArrayList; 040 import java.util.Hashtable; 041 import java.util.Iterator; 042 import java.util.List; 043 import java.util.StringTokenizer; 044 045 import javax.swing.GroupLayout; 046 import javax.swing.JComboBox; 047 import javax.swing.JComponent; 048 import javax.swing.JLabel; 049 import javax.swing.JPanel; 050 051 import org.w3c.dom.Element; 052 053 import edu.wisc.ssec.mcidas.AreaDirectory; 054 import edu.wisc.ssec.mcidas.AreaDirectoryList; 055 import edu.wisc.ssec.mcidas.AreaFileException; 056 import edu.wisc.ssec.mcidas.McIDASUtil; 057 058 import ucar.unidata.data.imagery.AddeImageInfo; 059 import ucar.unidata.data.imagery.ImageDataSource; 060 import ucar.unidata.idv.chooser.IdvChooserManager; 061 import ucar.unidata.idv.chooser.adde.AddeServer; 062 import ucar.unidata.metdata.NamedStationTable; 063 import ucar.unidata.util.LogUtil; 064 import ucar.unidata.util.Misc; 065 066 067 import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 068 069 /** 070 * Widget to select NEXRAD radar images from a remote ADDE server 071 * Displays a list of the descriptors (names) of the radar datasets 072 * available for a particular ADDE group on the remote server. 073 * 074 * @author Don Murray 075 */ 076 public class AddeRadarChooser extends AddeImageChooser { 077 078 /** Use to list the stations */ 079 protected static final String VALUE_LIST = "list"; 080 081 /** This is the list of properties that are used in the advanced gui */ 082 private static final String[] RADAR_PROPS = { PROP_UNIT }; 083 084 /** This is the list of labels used for the advanced gui */ 085 private static final String[] RADAR_LABELS = { "Data Type:" }; 086 087 /** Am I currently reading the stations */ 088 private boolean readingStations = false; 089 090 /** handle on the station update task */ 091 private Object readStationTask; 092 093 /** station table */ 094 private List nexradStations; 095 096 097 098 /** 099 * Construct an Adde image selection widget displaying information 100 * for the specified dataset located on the specified server. 101 * 102 * 103 * 104 * @param mgr The chooser manager 105 * @param root The chooser.xml node 106 */ 107 public AddeRadarChooser(IdvChooserManager mgr, Element root) { 108 super(mgr, root); 109 this.nexradStations = 110 getIdv().getResourceManager().findLocationsByType("radar"); 111 } 112 113 /** 114 * get the adde server grup type to use 115 * 116 * @return group type 117 */ 118 protected String getGroupType() { 119 return AddeServer.TYPE_RADAR; 120 } 121 122 /** 123 * Overwrite base class method to return the correct name 124 * (used for labeling, etc.) 125 * 126 * @return data name specific to this selector 127 */ 128 public String getDataName() { 129 return "Radar Data"; 130 } 131 132 @Override public String getDataType() { 133 return "RADAR"; 134 } 135 136 /** 137 * _more_ 138 * 139 * @return _more_ 140 */ 141 public String getDescriptorLabel() { 142 return "Product"; 143 } 144 145 /** 146 * Get the size of the image list 147 * 148 * @return the image list size 149 */ 150 protected int getImageListSize() { 151 return 6; 152 } 153 154 /** 155 * Get a description of the currently selected dataset 156 * 157 * @return the data set description. 158 */ 159 public String getDatasetName() { 160 return getSelectedStation() + " (" + super.getDatasetName() + ")"; 161 } 162 163 /** 164 * Method to call if the server changed. 165 */ 166 protected void connectToServer() { 167 clearStations(); 168 super.connectToServer(); 169 setAvailableStations(); 170 } 171 172 /** 173 * Check if we are ready to read times 174 * 175 * @return true if times can be read 176 */ 177 protected boolean canReadTimes() { 178 return super.canReadTimes() && (getSelectedStation() != null); 179 } 180 181 /** 182 * Get the advanced property names 183 * 184 * @return array of advanced properties 185 */ 186 protected String[] getAdvancedProps() { 187 return RADAR_PROPS; 188 } 189 190 /** 191 * Get the labels for the advanced properties 192 * 193 * @return array of labels 194 */ 195 protected String[] getAdvancedLabels() { 196 return RADAR_LABELS; 197 } 198 199 /** 200 * Update labels, etc. 201 */ 202 protected void updateStatus() { 203 super.updateStatus(); 204 if (getState() != STATE_CONNECTED) { 205 clearStations(); 206 } 207 if (readStationTask!=null) { 208 if(taskOk(readStationTask)) { 209 setStatus("Reading available stations from server"); 210 } else { 211 readStationTask = null; 212 setState(STATE_UNCONNECTED); 213 } 214 } 215 } 216 217 /** 218 * A new station was selected. Update the gui. 219 * 220 * @param stations List of selected stations 221 */ 222 protected void newSelectedStations(List stations) { 223 super.newSelectedStations(stations); 224 descriptorChanged(); 225 } 226 227 /** 228 * Generate a list of radar ids for the id list. 229 */ 230 private void setAvailableStations() { 231 readStationTask = startTask(); 232 clearSelectedStations(); 233 updateStatus(); 234 List stations = readStations(); 235 if(stopTaskAndIsOk(readStationTask)) { 236 readStationTask = null; 237 if (stations != null) { 238 getStationMap().setStations(stations); 239 } else { 240 clearStations(); 241 } 242 updateStatus(); 243 revalidate(); 244 } else { 245 //User pressed cancel 246 setState(STATE_UNCONNECTED); 247 return; 248 } 249 } 250 251 /** 252 * Generate a list of radar ids for the id list. 253 * 254 * @return list of station IDs 255 */ 256 private List readStations() { 257 ArrayList stations = new ArrayList(); 258 try { 259 if ((descriptorNames == null) || (descriptorNames.length == 0)) { 260 return stations; 261 } 262 StringBuffer buff = getGroupUrl(REQ_IMAGEDIR, getGroup()); 263 String descrForIds = descriptorNames[0]; 264 // try to use base reflectivity if it's available. 265 for (int i = 0; i < descriptorNames.length; i++) { 266 if ((descriptorNames[i] != null) 267 && descriptorNames[i].toLowerCase().startsWith( 268 "base")) { 269 descrForIds = descriptorNames[i]; 270 break; 271 } 272 } 273 appendKeyValue(buff, PROP_DESCR, 274 getDescriptorFromSelection(descrForIds)); 275 appendKeyValue(buff, PROP_ID, VALUE_LIST); 276 Hashtable seen = new Hashtable(); 277 AreaDirectoryList dirList = 278 new AreaDirectoryList(buff.toString()); 279 for (Iterator it = dirList.getDirs().iterator(); it.hasNext(); ) { 280 AreaDirectory ad = (AreaDirectory) it.next(); 281 String stationId = 282 McIDASUtil.intBitsToString(ad.getValue(20)).trim(); 283 //Check for uniqueness 284 if (seen.get(stationId) != null) { 285 continue; 286 } 287 seen.put(stationId, stationId); 288 //System.err.println ("id:" + stationId); 289 Object station = findStation(stationId); 290 if (station != null) { 291 stations.add(station); 292 } 293 } 294 } catch (AreaFileException e) { 295 String msg = e.getMessage(); 296 if (msg.toLowerCase().indexOf( 297 "no images meet the selection criteria") >= 0) { 298 LogUtil.userErrorMessage( 299 "No stations could be found on the server"); 300 } else { 301 handleConnectionError(e); 302 } 303 stations = new ArrayList(); 304 setState(STATE_UNCONNECTED); 305 } 306 return stations; 307 } 308 309 /** 310 * Find the station for the given ID 311 * 312 * @param stationId the station ID 313 * 314 * @return the station or null if not found 315 */ 316 private Object findStation(String stationId) { 317 for (int i = 0; i < nexradStations.size(); i++) { 318 NamedStationTable table = 319 (NamedStationTable) nexradStations.get(i); 320 Object station = table.get(stationId); 321 if (station != null) { 322 return station; 323 } 324 } 325 return null; 326 } 327 328 public void doCancel() { 329 readStationTask = null; 330 super.doCancel(); 331 } 332 333 /** 334 * Get the list of properties for the base URL 335 * @return list of properties 336 */ 337 protected String[] getBaseUrlProps() { 338 return new String[] { PROP_DESCR, PROP_ID, PROP_UNIT, PROP_SPAC, 339 PROP_BAND, PROP_USER, PROP_PROJ, }; 340 } 341 342 /** 343 * Overwrite the base class method to return the default property value 344 * for PROP_ID. 345 * 346 * @param prop The property 347 * @param ad The area directory 348 * @param forDisplay Is this to show the end user in the gui. 349 * 350 * @return The value of the property 351 */ 352 protected String getDefaultPropValue(String prop, AreaDirectory ad, 353 boolean forDisplay) { 354 if (prop.equals(PROP_ID)) { 355 return getSelectedStation(); 356 } 357 return super.getDefaultPropValue(prop, ad, forDisplay); 358 } 359 360 /** 361 * Get a description of the properties 362 * 363 * @return a description 364 */ 365 protected String getPropertiesDescription() { 366 StringBuffer buf = new StringBuffer(); 367 if (unitComboBox != null) { 368 buf.append(getAdvancedLabels()[0]); 369 buf.append(" "); 370 buf.append(unitComboBox.getSelectedItem().toString()); 371 } 372 return buf.toString(); 373 } 374 375 /** 376 * get properties 377 * 378 * @param ht properties 379 */ 380 protected void getDataSourceProperties(Hashtable ht) { 381 unitComboBox.setSelectedItem(ALLUNITS); 382 super.getDataSourceProperties(ht); 383 ht.put(ImageDataSource.PROP_IMAGETYPE, ImageDataSource.TYPE_RADAR); 384 } 385 386 /** 387 * Get the time popup widget 388 * 389 * @return a widget for selecing the day 390 */ 391 protected JComponent getExtraTimeComponent() { 392 JPanel filler = new JPanel(); 393 McVGuiUtils.setComponentHeight(filler, new JComboBox()); 394 return filler; 395 } 396 397 /** 398 * Make the UI for this selector. 399 * 400 * @return The gui 401 */ 402 public JComponent doMakeContents() { 403 JPanel myPanel = new JPanel(); 404 405 JLabel stationLabel = McVGuiUtils.makeLabelRight("Station:"); 406 addServerComp(stationLabel); 407 408 JComponent stationPanel = getStationMap(); 409 registerStatusComp("stations", stationPanel); 410 addServerComp(stationPanel); 411 412 JLabel timesLabel = McVGuiUtils.makeLabelRight("Times:"); 413 addDescComp(timesLabel); 414 415 JPanel timesPanel = makeTimesPanel(); 416 timesPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); 417 addDescComp(timesPanel); 418 419 // We need to create this but never show it... AddeImageChooser requires it to be instantiated 420 unitComboBox = new JComboBox(); 421 422 enableWidgets(); 423 424 GroupLayout layout = new GroupLayout(myPanel); 425 myPanel.setLayout(layout); 426 layout.setHorizontalGroup( 427 layout.createParallelGroup(LEADING) 428 .addGroup(layout.createSequentialGroup() 429 .addGroup(layout.createParallelGroup(LEADING) 430 .addGroup(layout.createSequentialGroup() 431 .addComponent(descriptorLabel) 432 .addGap(GAP_RELATED) 433 .addComponent(descriptorComboBox)) 434 .addGroup(layout.createSequentialGroup() 435 .addComponent(stationLabel) 436 .addGap(GAP_RELATED) 437 .addComponent(stationPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)) 438 .addGroup(layout.createSequentialGroup() 439 .addComponent(timesLabel) 440 .addGap(GAP_RELATED) 441 .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)))) 442 ); 443 layout.setVerticalGroup( 444 layout.createParallelGroup(LEADING) 445 .addGroup(layout.createSequentialGroup() 446 .addGroup(layout.createParallelGroup(BASELINE) 447 .addComponent(descriptorLabel) 448 .addComponent(descriptorComboBox)) 449 .addPreferredGap(RELATED) 450 .addGroup(layout.createParallelGroup(LEADING) 451 .addComponent(stationLabel) 452 .addComponent(stationPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)) 453 .addPreferredGap(RELATED) 454 .addGroup(layout.createParallelGroup(LEADING) 455 .addComponent(timesLabel) 456 .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))) 457 ); 458 459 setInnerPanel(myPanel); 460 return super.doMakeContents(true); 461 } 462 463 /** 464 * Get the default value for a key 465 * 466 * @return null for SIZE, else super 467 */ 468 protected String getDefault(String property, String dflt) { 469 if (PROP_SIZE.equals(property)) { 470 return dflt; 471 } 472 return super.getDefault(property, dflt); 473 } 474 475 /** 476 * Make an AddeImageInfo from a URL and an AreaDirectory 477 * 478 * @param dir 479 * AreaDirectory 480 * @param isRelative 481 * true if is relative 482 * @param num 483 * number (for relative images) 484 * 485 * @return corresponding AddeImageInfo 486 */ 487 protected AddeImageInfo makeImageInfo(AreaDirectory dir, 488 boolean isRelative, int num) { 489 AddeImageInfo info = new AddeImageInfo(getAddeServer().getName(), 490 AddeImageInfo.REQ_IMAGEDATA, getGroup(), getDescriptor()); 491 if (isRelative) { 492 info.setDatasetPosition((num == 0) ? 0 : -num); 493 } else { 494 info.setStartDate(dir.getNominalTime()); 495 } 496 setImageInfoProps(info, getMiscKeyProps(), dir); 497 setImageInfoProps(info, getBaseUrlProps(), dir); 498 499 info.setLocateKey(PROP_LINELE); 500 info.setLocateValue("0 0 F"); 501 info.setPlaceValue("ULEFT"); 502 503 String magKey = getPropValue(PROP_MAG, dir); 504 int lmag = 1; 505 int emag = 1; 506 StringTokenizer tok = new StringTokenizer(magKey); 507 lmag = (int) Misc.parseNumber((String) tok.nextElement()); 508 if (tok.hasMoreTokens()) { 509 emag = (int) Misc.parseNumber((String) tok.nextElement()); 510 } else { 511 emag = lmag; 512 } 513 info.setLineMag(lmag); 514 info.setElementMag(emag); 515 516 int lines = dir.getLines(); 517 int elems = dir.getElements(); 518 String sizeKey = getPropValue(PROP_SIZE, dir); 519 tok = new StringTokenizer(sizeKey); 520 String size = (String) tok.nextElement(); 521 if (!size.equalsIgnoreCase("all")) { 522 lines = (int) Misc.parseNumber(size); 523 if (tok.hasMoreTokens()) { 524 elems = (int) Misc.parseNumber((String) tok.nextElement()); 525 } else { 526 elems = lines; 527 } 528 } 529 info.setLines(lines); 530 info.setElements(elems); 531 /* 532 * System.out.println("url = " + info.getURLString().toLowerCase() + 533 * "\n"); 534 */ 535 return info; 536 } 537 }