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 }