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