001 /* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2013 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028 029 package edu.wisc.ssec.mcidasv.chooser.adde; 030 031 import static javax.swing.GroupLayout.DEFAULT_SIZE; 032 import static javax.swing.GroupLayout.PREFERRED_SIZE; 033 import static javax.swing.GroupLayout.Alignment.BASELINE; 034 import static javax.swing.GroupLayout.Alignment.LEADING; 035 import static javax.swing.LayoutStyle.ComponentPlacement.RELATED; 036 037 import java.awt.IllegalComponentStateException; 038 import java.awt.Point; 039 import java.awt.event.ActionEvent; 040 import java.awt.event.ActionListener; 041 import java.text.SimpleDateFormat; 042 import java.util.ArrayList; 043 import java.util.Arrays; 044 import java.util.Collections; 045 import java.util.Date; 046 import java.util.Enumeration; 047 import java.util.Hashtable; 048 import java.util.List; 049 import java.util.SortedSet; 050 import java.util.TreeSet; 051 052 import javax.swing.GroupLayout; 053 import javax.swing.JButton; 054 import javax.swing.JComboBox; 055 import javax.swing.JComponent; 056 import javax.swing.JDialog; 057 import javax.swing.JLabel; 058 import javax.swing.JPanel; 059 import javax.swing.ListSelectionModel; 060 061 import org.slf4j.Logger; 062 import org.slf4j.LoggerFactory; 063 import org.w3c.dom.Element; 064 065 import edu.wisc.ssec.mcidas.McIDASUtil; 066 import edu.wisc.ssec.mcidas.adde.AddePointDataReader; 067 import edu.wisc.ssec.mcidas.adde.DataSetInfo; 068 069 import visad.DateTime; 070 import visad.VisADException; 071 072 import ucar.unidata.data.AddeUtil; 073 import ucar.unidata.data.point.AddePointDataSource; 074 import ucar.unidata.idv.chooser.IdvChooserManager; 075 import ucar.unidata.idv.chooser.adde.AddeServer; 076 import ucar.unidata.ui.DateTimePicker; 077 import ucar.unidata.ui.symbol.StationModel; 078 import ucar.unidata.ui.symbol.StationModelManager; 079 import ucar.unidata.util.GuiUtils; 080 import ucar.unidata.util.Misc; 081 import ucar.unidata.util.TwoFacedObject; 082 import ucar.visad.UtcDate; 083 084 import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 085 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Width; 086 087 /** 088 * Selection widget for ADDE point data 089 * 090 * @version $Revision$ $Date$ 091 */ 092 public class AddePointDataChooser extends AddeChooser { 093 094 /** Logging object. Use it! */ 095 private static final Logger logger = LoggerFactory.getLogger(AddePointDataChooser.class); 096 097 /** 098 * Property for the dataset name key. 099 * @see edu.wisc.ssec.mcidasv.chooser.adde.AddeChooser#getDataSetName() 100 */ 101 public static String DATASET_NAME_KEY = "name"; 102 103 /** Property for the data type. */ 104 public static String DATA_TYPE = "ADDE.POINT.V"; 105 106 /** Are we currently reading times */ 107 private Object readTimesTask; 108 109 /** box and label for the relative time */ 110 protected JLabel relTimeIncLabel; 111 protected JComboBox relTimeIncBox; 112 113 /** the relative time increment */ 114 private float relativeTimeIncrement = 1.0f; 115 116 /** archive date */ 117 protected String archiveDay = null; 118 119 /** archive day button and label */ 120 protected JLabel archiveDayLabel; 121 protected JButton archiveDayBtn; 122 123 /** archive date formatter */ 124 private SimpleDateFormat archiveDayFormatter; 125 126 /** station model manager */ 127 private StationModelManager stationModelManager; 128 129 /** allowed descriptor prefix */ 130 protected String descriptorsAllowPrefix = ""; 131 132 protected boolean firstTime = true; 133 protected boolean retry = true; 134 135 /** Possibly ask for times a second time if the first sampling doesn't get any */ 136 private boolean gotObs = false; 137 protected boolean tryWithoutSampling = false; 138 139 /** 140 * Create a chooser for Adde POINT data 141 * 142 * @param mgr The chooser manager 143 * @param root The chooser.xml node 144 */ 145 public AddePointDataChooser(IdvChooserManager mgr, Element root) { 146 super(mgr, root); 147 148 this.stationModelManager = getIdv().getStationModelManager(); 149 150 relTimeIncLabel = new JLabel(" Interval:"); 151 relTimeIncBox = new JComboBox(); 152 relTimeIncBox.setToolTipText("Set the increment between relative times"); 153 relTimeIncBox.addActionListener(new ActionListener() { 154 @Override public void actionPerformed(ActionEvent ae) { 155 JComboBox box = (JComboBox) ae.getSource(); 156 if (GuiUtils.anySelected(box)) { 157 setRelativeTimeIncrement(getRelBoxValue()); 158 } 159 } 160 }); 161 McVGuiUtils.setComponentWidth(relTimeIncBox, Width.ONEHALF); 162 163 descriptorsAllowPrefix = ""; 164 165 archiveDayBtn = GuiUtils.makeImageButton( 166 "/auxdata/ui/icons/calendar_edit.png", this, "getArchiveDay", null, 167 true); 168 archiveDayBtn.setToolTipText("Select a day for archive datasets"); 169 archiveDayLabel = new JLabel("Select day:"); 170 archiveDayFormatter = new SimpleDateFormat(UtcDate.YMD_FORMAT); 171 } 172 173 /** 174 * Do server connection stuff... override this with type-specific methods 175 */ 176 @Override protected void readFromServer() { 177 archiveDay = null; 178 if (archiveDayLabel != null) { 179 archiveDayLabel.setText("Select day:"); 180 } 181 super.readFromServer(); 182 } 183 184 /** 185 * Generate a list of image descriptors for the descriptor list. 186 */ 187 @Override protected void readDescriptors() { 188 try { 189 StringBuffer buff = getGroupUrl(REQ_DATASETINFO, getGroup()); 190 buff.append("&type=").append(getDataType()); 191 DataSetInfo dsinfo = new DataSetInfo(buff.toString()); 192 descriptorTable = dsinfo.getDescriptionTable(); 193 194 // Only show descriptorsAllowPrefix if set 195 for (Enumeration e = descriptorTable.keys(); e.hasMoreElements();) { 196 Object key = e.nextElement(); 197 String str = (String) descriptorTable.get(key); 198 if (!descriptorsAllowPrefix.isEmpty() && str.indexOf(descriptorsAllowPrefix) != 0) 199 descriptorTable.remove(key); 200 } 201 202 String[] names = new String[descriptorTable.size()]; 203 Enumeration enumeration = descriptorTable.keys(); 204 for (int i = 0; enumeration.hasMoreElements(); i++) { 205 Object thisElement = enumeration.nextElement(); 206 names[i] = descriptorTable.get(thisElement).toString() + " - " + thisElement.toString(); 207 } 208 Arrays.sort(names); 209 setDescriptors(names); 210 setState(STATE_CONNECTED); 211 } catch (Exception e) { 212 handleConnectionError(e); 213 } 214 } 215 216 /** 217 * Load in an ADDE point data set based on the 218 * <code>PropertyChangeEvent<code>. 219 * 220 */ 221 @Override public void doLoadInThread() { 222 showWaitCursor(); 223 try { 224 StationModel selectedStationModel = getSelectedStationModel(); 225 String source = getRequestUrl(); 226 227 // make properties Hashtable to hand the station name 228 // to the AddeProfilerDataSource 229 Hashtable ht = new Hashtable(); 230 getDataSourceProperties(ht); 231 ht.put(AddePointDataSource.PROP_STATIONMODELNAME, 232 selectedStationModel.getName()); 233 ht.put(DATASET_NAME_KEY, getDescriptor()); 234 ht.put(DATA_NAME_KEY, getDataName()); 235 if (source.contains(AddeUtil.RELATIVE_TIME)) { 236 ht.put(AddeUtil.NUM_RELATIVE_TIMES, getRelativeTimeIndices()); 237 ht.put(AddeUtil.RELATIVE_TIME_INCREMENT, getRelativeTimeIncrement()); 238 } 239 240 if (getDoAbsoluteTimes()) { 241 ht.put(AddeUtil.ABSOLUTE_TIMES, getSelectedAbsoluteTimes()); 242 } 243 244 makeDataSource(source, DATA_TYPE, ht); 245 saveServerState(); 246 } catch (Exception excp) { 247 logException("Unable to open ADDE point dataset", excp); 248 } 249 showNormalCursor(); 250 } 251 252 /** 253 * Show the archive dialog. This method is not meant to be called but is 254 * public by reason of implementation (or insanity). 255 */ 256 public void getArchiveDay() { 257 final JDialog dialog = GuiUtils.createDialog("Set Archive Day", true); 258 final DateTimePicker dtp = new DateTimePicker((Date) null, false); 259 if (archiveDay != null) { 260 if (archiveDayFormatter == null) { 261 archiveDayFormatter = new SimpleDateFormat(UtcDate.YMD_FORMAT); 262 } 263 Date d = null; 264 try { 265 d = archiveDayFormatter.parse(archiveDay); 266 dtp.setDate(d); 267 } catch (Exception e) { 268 logException("parsing archive day " + archiveDay, e); 269 } 270 } 271 272 ActionListener listener = new ActionListener() { 273 public void actionPerformed(ActionEvent ae) { 274 String cmd = ae.getActionCommand(); 275 if (cmd.equals(GuiUtils.CMD_REMOVE)) { 276 archiveDay = null; 277 archiveDayLabel.setText("Select day:"); 278 setDoAbsoluteTimes(true); 279 descriptorChanged(); 280 } else if (cmd.equals(GuiUtils.CMD_OK)) { 281 try { 282 DateTime dt = new DateTime(dtp.getDate()); 283 String myDay = UtcDate.getYMD(dt); 284 // archiveDayLabel.setText(UtcDate.formatUtcDate(dt, 285 // "MMM dd, yyyy")); 286 archiveDayLabel.setText(myDay); 287 } catch (Exception e) { 288 logger.error("problem while setting archive day label", e); 289 } 290 // System.out.println("archiveDay = " + archiveDay); 291 setDoAbsoluteTimes(true); 292 descriptorChanged(); 293 } 294 dialog.dispose(); 295 } 296 }; 297 298 JPanel buttons = GuiUtils.makeButtons(listener, new String[] { 299 GuiUtils.CMD_OK, GuiUtils.CMD_REMOVE, GuiUtils.CMD_CANCEL }); 300 301 JComponent contents = GuiUtils.topCenterBottom(GuiUtils.inset(GuiUtils 302 .lLabel("Please select a day for this dataset:"), 10), GuiUtils 303 .inset(dtp, 10), buttons); 304 Point p = new Point(200, 200); 305 if (archiveDayBtn != null) { 306 try { 307 p = archiveDayBtn.getLocationOnScreen(); 308 } catch (IllegalComponentStateException ice) { 309 logger.error("archive day button in illegal state", ice); 310 } 311 } 312 dialog.setLocation(p); 313 dialog.getContentPane().add(contents); 314 dialog.pack(); 315 dialog.setVisible(true); 316 } 317 318 /** 319 * Get the selected station model. 320 * 321 * @return StationModel to use: defined by defaultModels list in ctor 322 */ 323 public StationModel getSelectedStationModel() { 324 StationModel returnModel = null; 325 if (isUpperAir()) { 326 returnModel = this.stationModelManager.getStationModel("Observations>Upper Air"); 327 } else if (isSynoptic()) { 328 returnModel = this.stationModelManager.getStationModel("Observations>SYNOP"); 329 } else { 330 returnModel = this.stationModelManager.getStationModel("Observations>METAR"); 331 } 332 return returnModel; 333 } 334 335 /** 336 * Add the interval selector to the component. 337 * @return superclass component with extra stuff 338 */ 339 @Override protected JPanel makeTimesPanel() { 340 JComponent extra1 = getExtraTimeComponentRelative(); 341 GuiUtils.enableTree(extra1, false); 342 JComponent extra2 = getExtraTimeComponentAbsolute(); 343 JPanel timesPanel = super.makeTimesPanel(extra1, extra2); 344 return timesPanel; 345 } 346 347 /** 348 * Get the extra time widget, but built in a different way. 349 * Designed to be put into a GroupLayout 350 * 351 * @return Extra time widget 352 */ 353 protected JComponent getExtraTimeComponentRelative() { 354 TwoFacedObject[] intervals = { 355 new TwoFacedObject("30 minute", .5f), 356 new TwoFacedObject("Hourly", 1f), 357 new TwoFacedObject("Three hourly", 3f), 358 new TwoFacedObject("Six hourly", 6f), 359 new TwoFacedObject("12 hourly", 12f), 360 new TwoFacedObject("24 hourly", 24f) 361 }; 362 363 GuiUtils.setListData(relTimeIncBox, intervals); 364 if (relTimeIncBox.getItemCount()>=2) relTimeIncBox.setSelectedIndex(1); 365 366 return McVGuiUtils.makeLabeledComponent(relTimeIncLabel, relTimeIncBox, McVGuiUtils.Position.LEFT); 367 } 368 369 /** 370 * Get the time popup widget 371 * 372 * @return a widget for selecing the day 373 */ 374 protected JComponent getExtraTimeComponentAbsolute() { 375 return null; 376 // return McVGuiUtils.makeLabeledComponent(archiveDayLabel, archiveDayBtn); 377 } 378 379 /** 380 * Get the value from the relative increment box 381 * 382 * @return the selected value or a default 383 */ 384 protected float getRelBoxValue() { 385 float value = relativeTimeIncrement; 386 if (relTimeIncBox != null) { 387 Object o = relTimeIncBox.getSelectedItem(); 388 if (o != null) { 389 String val = TwoFacedObject.getIdString(o); 390 value = (float) Misc.parseNumber(val); 391 } 392 } 393 return value; 394 } 395 396 /** 397 * Get the string from the relative increment box 398 * 399 * @return the selected string or a default 400 */ 401 public String getRelBoxString() { 402 String value = ""; 403 if (relTimeIncBox != null) { 404 Object o = relTimeIncBox.getSelectedItem(); 405 if (o != null) { 406 value = TwoFacedObject.getIdString(o); 407 } 408 } 409 return value; 410 } 411 412 /** 413 * Get the request URL 414 * 415 * @return the request URL 416 */ 417 public String getRequestUrl() { 418 StringBuffer request = getGroupUrl(REQ_POINTDATA, getGroup()); 419 appendKeyValue(request, PROP_USER, getLastAddedUser()); 420 appendKeyValue(request, PROP_PROJ, getLastAddedProj()); 421 appendKeyValue(request, PROP_DESCR, getDescriptor()); 422 appendRequestSelectClause(request); 423 appendKeyValue(request, PROP_NUM, "ALL"); 424 appendKeyValue(request, PROP_POS, getDoRelativeTimes() ? "ALL" : "0"); 425 return request.toString(); 426 } 427 428 /** 429 * Get the select clause for the adde request specific to this 430 * type of data. 431 * 432 * @param buf The buffer to append to 433 */ 434 protected void appendRequestSelectClause(StringBuffer buf) { 435 StringBuilder selectValue = new StringBuilder(1024); 436 selectValue.append('\''); 437 selectValue.append(getDayTimeSelectString()); 438 //TODO: why is SFCHOURLY explicit here? better way to do it? 439 if ("SFCHOURLY".equalsIgnoreCase(getDescriptor())) { 440 selectValue.append(";type 0"); 441 } 442 selectValue.append(';'); 443 444 if (isUpperAir()){ 445 selectValue.append(AddeUtil.LEVEL); 446 selectValue.append(';'); 447 } 448 selectValue.append(AddeUtil.LATLON_BOX); 449 selectValue.append('\''); 450 appendKeyValue(buf, PROP_SELECT, selectValue.toString()); 451 } 452 453 /** 454 * Check if we are ready to read times 455 * 456 * @return true if times can be read 457 */ 458 protected boolean canReadTimes() { 459 return haveDescriptorSelected(); 460 } 461 462 /** 463 * Enable or disable the GUI widgets based on what has been 464 * selected. 465 */ 466 @Override protected void enableWidgets() { 467 boolean descriptorState = ((getState() == STATE_CONNECTED) 468 && canReadTimes()); 469 470 for (int i = 0; i < compsThatNeedDescriptor.size(); i++) { 471 JComponent comp = (JComponent) compsThatNeedDescriptor.get(i); 472 GuiUtils.enableTree(comp, descriptorState); 473 } 474 475 boolean timesOk = timesOk(); 476 477 // Require times to be selected 478 GuiUtils.enableTree(loadButton, descriptorState && timesOk); 479 480 checkTimesLists(); 481 482 enableAbsoluteTimesList(getDoAbsoluteTimes() && descriptorState); 483 484 getRelativeTimesChooser().setEnabled( !getDoAbsoluteTimes() 485 && descriptorState); 486 487 revalidate(); 488 } 489 490 /** 491 * Do we have times selected. Either we are doing absolute 492 * times and there are some selected in the list. Or we 493 * are doing relative times and we have done a connect to the 494 * server 495 * 496 * @return Do we have times 497 */ 498 public boolean timesOk() { 499 if (getDoAbsoluteTimes() && !haveTimeSelected()) { 500 return false; 501 } 502 return true; 503 } 504 505 /** 506 * Return {@code true} if selected descriptor is for SYNOPTIC data. 507 * 508 * @return {@code true} iff {@link edu.wisc.ssec.mcidasv.chooser.adde.AddePointDataChooser#getDescriptor()} 509 * is {@literal "SYNOP"}. 510 */ 511 protected boolean isSynoptic() { 512 return "SYNOP".equals(getDescriptor()); 513 } 514 515 /** 516 * Return {@code true} if selected descriptor is for upper air. 517 * 518 * @return {@code true} iff {@link edu.wisc.ssec.mcidasv.chooser.adde.AddePointDataChooser#getDescriptor()} 519 * is {@literal "UPPERMAND"}. 520 */ 521 protected boolean isUpperAir() { 522 return "UPPERMAND".equals(getDescriptor()); 523 524 } 525 526 /** 527 * Return {@code true} if selected descriptor is for profiler. 528 * 529 * @return {@code true} iff {@link edu.wisc.ssec.mcidasv.chooser.adde.AddePointDataChooser#getDescriptor()} 530 * is {@literal "PROF"}. 531 */ 532 protected boolean isProfiler() { 533 return "PROF".equals(getDescriptor()); 534 } 535 536 /** 537 * Update the widget with the latest data. 538 * 539 * @throws Exception On badness 540 */ 541 @Override public void handleUpdate() throws Exception { 542 if (getState() != STATE_CONNECTED) { 543 //If not connected then update the server list 544 updateServerList(); 545 } else { 546 //If we are already connected then update the rest of the chooser 547 descriptorChanged(); 548 } 549 updateStatus(); 550 } 551 552 /** 553 * Get the request string for times particular to this chooser 554 * 555 * @return request string 556 */ 557 protected String getTimesRequest() { 558 StringBuffer buf = getGroupUrl(REQ_POINTDATA, getGroup()); 559 appendKeyValue(buf, PROP_USER, getLastAddedUser()); 560 appendKeyValue(buf, PROP_PROJ, getLastAddedProj()); 561 appendKeyValue(buf, PROP_DESCR, getDescriptor()); 562 if (!isUpperAir() && !tryWithoutSampling) { 563 // appendKeyValue(buf, PROP_POS, "0"); 564 appendKeyValue(buf, PROP_POS, "ALL"); 565 appendKeyValue(buf, PROP_SELECT, "'DAY "+getJulianDay()+";LAT 38 42;LON 70 75'"); 566 } 567 else { 568 appendKeyValue(buf, PROP_SELECT, "'DAY "+getJulianDay()+"'"); 569 appendKeyValue(buf, PROP_POS, "ALL"); 570 } 571 if (getDoAbsoluteTimes()) { 572 appendKeyValue(buf, PROP_NUM, "ALL"); 573 } 574 appendKeyValue(buf, PROP_PARAM, "DAY TIME"); 575 return buf.toString(); 576 } 577 578 /** 579 * Get the current Julian day as a String 580 * 581 * @return the current day as a string (yyyyDDD) 582 */ 583 // TODO: This should really be more accessible 584 private String getJulianDay() { 585 String retString = ""; 586 try { 587 DateTime dt = new DateTime(); 588 retString = UtcDate.formatUtcDate(dt, "yyyyDDD"); 589 } catch (VisADException ve) { 590 logger.error("error building julian date", ve); 591 } 592 return retString; 593 } 594 595 /** 596 * This allows derived classes to provide their own name for labeling, etc. 597 * 598 * @return the dataset name 599 */ 600 @Override public String getDataName() { 601 return "Point Data"; 602 } 603 604 /** 605 * _more_ 606 */ 607 @Override public void doCancel() { 608 readTimesTask = null; 609 setState(STATE_UNCONNECTED); 610 super.doCancel(); 611 } 612 613 /** locking mutex */ 614 private final Object MUTEX = new Object(); 615 616 /** 617 * Read the set of image times available for the current server/group/type 618 * This method is a wrapper, setting the wait cursor and wrapping the 619 * call to {@link #readTimesInner()}; in a try/catch block 620 */ 621 @Override public void readTimes() { 622 clearTimesList(); 623 if (!canReadTimes()) { 624 return; 625 } 626 Misc.run(new Runnable() { 627 @Override public void run() { 628 updateStatus(); 629 showWaitCursor(); 630 try { 631 gotObs = false; 632 tryWithoutSampling = false; 633 readTimesInner(); 634 // Try again, this time not sampling by LAT/LON 635 if (!gotObs) { 636 tryWithoutSampling = true; 637 readTimesInner(); 638 } 639 } catch (Exception e) { 640 handleConnectionError(e); 641 } 642 showNormalCursor(); 643 updateStatus(); 644 } 645 }); 646 } 647 648 /** 649 * Set the list of dates/times based on the image selection 650 */ 651 protected void readTimesInner() { 652 SortedSet<DateTime> uniqueTimes = Collections.synchronizedSortedSet(new TreeSet<DateTime>()); 653 654 readTimesTask = startTask(); 655 updateStatus(); 656 Object task = readTimesTask; 657 try { 658 AddePointDataReader apr = new AddePointDataReader(getTimesRequest()); 659 //Make sure no other loads are occurred 660 boolean ok = stopTaskAndIsOk(task); 661 if (!Misc.equals(readTimesTask, task) || !ok) { 662 return; 663 } 664 readTimesTask = null; 665 666 synchronized (MUTEX) { 667 int[][] data = apr.getData(); 668 String[] units = apr.getUnits(); 669 if ( !"CYD".equals(units[0]) || !"HMS".equals(units[1])) { 670 throw new Exception("can't handle date/time units"); 671 } 672 int numObs = data[0].length; 673 //System.out.println("found " + numObs + " obs"); 674 // loop through and find all the unique times 675 try { 676 for (int i = 0; i < numObs; i++) { 677 DateTime dt = 678 new DateTime(McIDASUtil.mcDayTimeToSecs(data[0][i], 679 data[1][i])); 680 uniqueTimes.add(dt); 681 } 682 } catch (Exception e) { 683 logger.error("problem building list of unique times", e); 684 } 685 //System.out.println( 686 // "found " + uniqueTimes.size() + " unique times"); 687 if (getDoAbsoluteTimes()) { 688 if (!uniqueTimes.isEmpty()) { 689 setAbsoluteTimes(new ArrayList<DateTime>(uniqueTimes)); 690 getTimesList().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); 691 } 692 693 // Select the last n hours 694 int selectedIndex = getAbsoluteTimes().size() - 1; 695 int firstIndex = Math.max(0, selectedIndex 696 - getDefaultRelativeTimeIndex()); 697 if (selectedIndex >= 0) 698 setSelectedAbsoluteTime(selectedIndex, firstIndex); 699 } 700 if (numObs>0) { 701 gotObs = true; 702 } 703 } 704 setState(STATE_CONNECTED); 705 } catch (Exception excp) { 706 stopTask(task); 707 readTimesTask = null; 708 handleConnectionError(excp); 709 if (!retry) { 710 return; 711 } 712 try { 713 handleUpdate(); 714 } catch (Exception e) { 715 logger.error("problem handling update", e); 716 } 717 } 718 } 719 720 /** 721 * Show the given error to the user. If it was an Adde exception 722 * that was a bad server error then print out a nice message. 723 * 724 * @param e The exception 725 */ 726 @Override protected void handleConnectionError(Exception e) { 727 retry = false; 728 super.handleConnectionError(e); 729 } 730 731 /** 732 * Are there any times selected. 733 * 734 * @return Any times selected. 735 */ 736 @Override protected boolean haveTimeSelected() { 737 return !getDoAbsoluteTimes() || getHaveAbsoluteTimesSelected(); 738 } 739 740 /** 741 * Create the date time selection string for the "select" clause 742 * of the ADDE URL. 743 * 744 * @return the select day and time strings 745 */ 746 protected String getDayTimeSelectString() { 747 StringBuilder buf = new StringBuilder(1024); 748 if (getDoAbsoluteTimes()) { 749 List times = getSelectedAbsoluteTimes(); 750 751 // no time selection is permitted as a valid choice - 752 // will then use all times today by default. 753 if (times.isEmpty()) { 754 return ""; 755 } 756 757 //check for the "no times available" message 758 if (times.get(0) instanceof String) { 759 return ""; 760 } 761 762 if (archiveDay!=null) { 763 logger.trace("archiveDay: {}", archiveDay); 764 try { 765 Date d = archiveDayFormatter.parse(archiveDay); 766 DateTime dt = new DateTime(d); 767 logger.trace("parsed to: {}", dt.toString()); 768 buf.append("day ").append(UtcDate.getIYD(dt)).append(';'); 769 } catch (Exception e) { 770 logger.error("archiveDay parse error", e); 771 } 772 } 773 else { 774 logger.trace("archiveDay is null!"); 775 } 776 777 buf.append("time "); 778 for (int i = 0; i < times.size(); i++) { 779 DateTime dt = (DateTime) times.get(i); 780 buf.append(UtcDate.getHMS(dt)); 781 if (i != times.size() - 1) { 782 buf.append(','); 783 } 784 } 785 } else { 786 buf.append(AddeUtil.RELATIVE_TIME); 787 } 788 return buf.toString(); 789 } 790 791 /** 792 * Get the data type for this chooser 793 * 794 * @return the type 795 */ 796 @Override public String getDataType() { 797 return "POINT"; 798 } 799 800 /** 801 * Get the increment between times for relative time requests 802 * 803 * @return time increment (hours) 804 */ 805 @Override public float getRelativeTimeIncrement() { 806 return relativeTimeIncrement; 807 } 808 809 /** 810 * Set the increment between times for relative time requests 811 * 812 * @param increment time increment (hours) 813 */ 814 public void setRelativeTimeIncrement(float increment) { 815 relativeTimeIncrement = increment; 816 if (relTimeIncBox != null) { 817 relTimeIncBox.setSelectedItem(relativeTimeIncrement); 818 } 819 } 820 821 /** 822 * Update labels, enable widgets, etc. 823 */ 824 @Override protected void updateStatus() { 825 super.updateStatus(); 826 if (readTimesTask != null) { 827 if (taskOk(readTimesTask)) { 828 setStatus("Reading available times from server"); 829 } 830 } else if (getDoAbsoluteTimes() && !haveTimeSelected()) { 831 setStatus(MSG_TIMES); 832 } 833 enableWidgets(); 834 } 835 836 837 /** 838 * Get the descriptor widget label. 839 * 840 * @return label for the descriptor widget 841 */ 842 @Override public String getDescriptorLabel() { 843 return "Point Type"; 844 } 845 846 /** 847 * get the adde server grup type to use 848 * 849 * @return group type 850 */ 851 @Override protected String getGroupType() { 852 return AddeServer.TYPE_POINT; 853 } 854 855 /** 856 * Make the UI for this selector. 857 * 858 * @return The gui 859 */ 860 @Override public JComponent doMakeContents() { 861 JPanel myPanel = new JPanel(); 862 863 McVGuiUtils.setComponentWidth(descriptorComboBox, Width.DOUBLEDOUBLE); 864 865 JLabel stationLabel = McVGuiUtils.makeLabelRight("Station:"); 866 addServerComp(stationLabel); 867 868 JLabel timesLabel = McVGuiUtils.makeLabelRight("Times:"); 869 addDescComp(timesLabel); 870 871 JPanel timesPanel = makeTimesPanel(); 872 timesPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); 873 addDescComp(timesPanel); 874 875 GroupLayout layout = new GroupLayout(myPanel); 876 myPanel.setLayout(layout); 877 layout.setHorizontalGroup( 878 layout.createParallelGroup(LEADING) 879 .addGroup(layout.createSequentialGroup() 880 .addGroup(layout.createParallelGroup(LEADING) 881 .addGroup(layout.createSequentialGroup() 882 .addComponent(descriptorLabel) 883 .addGap(GAP_RELATED) 884 .addComponent(descriptorComboBox)) 885 .addGroup(layout.createSequentialGroup() 886 .addComponent(timesLabel) 887 .addGap(GAP_RELATED) 888 .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)))) 889 ); 890 layout.setVerticalGroup( 891 layout.createParallelGroup(LEADING) 892 .addGroup(layout.createSequentialGroup() 893 .addGroup(layout.createParallelGroup(BASELINE) 894 .addComponent(descriptorLabel) 895 .addComponent(descriptorComboBox)) 896 .addPreferredGap(RELATED) 897 .addGroup(layout.createParallelGroup(LEADING) 898 .addComponent(timesLabel) 899 .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))) 900 ); 901 902 setInnerPanel(myPanel); 903 return super.doMakeContents(); 904 } 905 906 public JComponent doMakeContents(boolean doesOverride) { 907 if (doesOverride) { 908 return super.doMakeContents(); 909 } else { 910 return doMakeContents(); 911 } 912 } 913 }