001/*
002 * $Id: TDSRadarChooser.java,v 1.18 2011/03/24 16:06:31 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
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
031package edu.wisc.ssec.mcidasv.chooser;
032
033import static javax.swing.GroupLayout.DEFAULT_SIZE;
034import static javax.swing.GroupLayout.PREFERRED_SIZE;
035import static javax.swing.GroupLayout.Alignment.BASELINE;
036import static javax.swing.GroupLayout.Alignment.LEADING;
037import static javax.swing.GroupLayout.Alignment.TRAILING;
038import static javax.swing.LayoutStyle.ComponentPlacement.RELATED;
039import static javax.swing.LayoutStyle.ComponentPlacement.UNRELATED;
040
041import java.awt.Component;
042import java.awt.event.ActionEvent;
043import java.awt.event.ActionListener;
044import java.awt.event.ItemEvent;
045import java.awt.event.ItemListener;
046import java.io.IOException;
047import java.net.URI;
048import java.util.ArrayList;
049import java.util.Date;
050import java.util.Hashtable;
051import java.util.List;
052import java.util.Vector;
053
054import javax.swing.GroupLayout;
055import javax.swing.JButton;
056import javax.swing.JComboBox;
057import javax.swing.JComponent;
058import javax.swing.JLabel;
059import javax.swing.JPanel;
060import javax.swing.JTabbedPane;
061
062import org.jdom.Document;
063import org.jdom.JDOMException;
064import org.jdom.Namespace;
065import org.jdom.input.SAXBuilder;
066import org.w3c.dom.Element;
067
068import thredds.catalog.XMLEntityResolver;
069import ucar.nc2.thredds.TDSRadarDatasetCollection;
070import ucar.nc2.units.DateUnit;
071import ucar.unidata.data.radar.RadarQuery;
072import ucar.unidata.geoloc.StationImpl;
073import ucar.unidata.idv.chooser.IdvChooserManager;
074import ucar.unidata.idv.chooser.TimesChooser;
075import ucar.unidata.metdata.NamedStation;
076import ucar.unidata.metdata.NamedStationImpl;
077import ucar.unidata.util.DateSelection;
078import ucar.unidata.util.DateUtil;
079import ucar.unidata.util.DatedThing;
080import ucar.unidata.util.GuiUtils;
081import ucar.unidata.util.LogUtil;
082import ucar.unidata.util.Misc;
083import ucar.unidata.util.PreferenceList;
084import ucar.unidata.util.Product;
085import ucar.unidata.util.TwoFacedObject;
086
087import visad.CommonUnit;
088import visad.DateTime;
089
090import edu.wisc.ssec.mcidasv.Constants;
091import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
092import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Position;
093import edu.wisc.ssec.mcidasv.util.McVGuiUtils.TextColor;
094import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Width;
095
096
097/**
098 * Created by IntelliJ IDEA.
099 * User: yuanho
100 * Date: Jan 16, 2008
101 * Time: 11:17:51 AM
102 * To change this template use File | Settings | File Templates.
103 */
104public class TDSRadarChooser extends TimesChooser implements Constants {
105
106    /** The collection */
107    private TDSRadarDatasetCollection collection;
108
109
110    /** The currently selected station */
111    private NamedStation selectedStation;
112
113    /** The currently selected level3 product */
114    private String selectedProduct;
115
116    /** Those urls we connect to */
117    //"http://motherlode.ucar.edu:8080/thredds/radarServer/catalog.xml";
118    private String serverUrl;
119
120    /** Each dataset collection URL */
121    //"http://motherlode.ucar.edu:8080/thredds/radarServer/level2/idd/dataset.xml";
122    //private String collectionUrl;
123
124    /** Component to hold collections */
125    private JComboBox collectionSelector;
126
127    /** Component to hold product list */
128    private JComboBox productComboBox;
129    
130    /** Level 3 panel that can be hidden */
131    private JPanel productPanel;
132    
133    /** components that need a server for activation */
134    private List compsThatNeedServer = new ArrayList();
135
136    /** components that need a server for activation */
137    private List level3CompsThatNeedServer = new ArrayList();
138
139    /** persistent holder for catalog URLS */
140    private PreferenceList urlListHandler;
141
142    /** catalog URL holder */
143    private JComboBox urlBox;
144
145    /** ok flag */
146    private boolean okToDoUrlListEvents = true;
147
148    /** dataset list */
149    private List datasetList;
150
151    /** Command for connecting */
152    protected static final String CMD_CONNECT = "cmd.connect";
153
154    /** _more_          */
155    private boolean isLevel3;
156
157    /** _more_          */
158    public static final String[] level3_ExName = { "NVW", "DPA" };
159
160
161    /**
162     * Create the RadarChooser
163     *
164     * @param mgr The <code>IdvChooserManager</code>
165     * @param root  The xml root that defines this chooser
166     *
167     */
168    public TDSRadarChooser(IdvChooserManager mgr, Element root) {
169        super(mgr, root);
170        
171        loadButton = McVGuiUtils.makeImageTextButton(ICON_ACCEPT_SMALL, getLoadCommandName());
172        loadButton.setActionCommand(getLoadCommandName());
173        loadButton.addActionListener(this);
174        
175        cancelButton = McVGuiUtils.makeImageButton(ICON_CANCEL, "Cancel");
176        cancelButton.setActionCommand(GuiUtils.CMD_CANCEL);
177        cancelButton.addActionListener(this);
178        cancelButton.setEnabled(false);
179        
180    }
181
182
183
184    /**
185     * Handle the update event. Just pass it through to the imageChooser
186     */
187    public void doUpdate() {
188        if ((serverUrl == null) || (datasetList == null)
189                || (datasetList.size() == 0) || (selectedProduct == null)) {
190            if (urlBox != null) {
191                setServer((String) urlBox.getSelectedItem());
192            }
193            return;
194        }
195        Misc.run(this, "stationOrProductChanged");
196    }
197
198
199
200    /**
201     * Update the status of the gui
202     */
203    protected void updateStatus() {
204        super.updateStatus();
205        if (serverUrl == null) {
206            setHaveData(false);
207            setStatus("Please connect to the server");
208        }
209        else if (selectedStation == null) {
210            setHaveData(false);
211            setStatus("Please select a station", "stations");
212        }
213        else if (isLevel3 && (selectedProduct == null)) {
214            setHaveData(false);
215            setStatus("Please select a level 3 product", "products");
216        }
217        else {
218            boolean haveTimesSelected;
219            if (getDoAbsoluteTimes()) {
220                haveTimesSelected = getSelectedAbsoluteTimes().size() > 0;
221            } else {
222                haveTimesSelected = true;
223            }
224            setHaveData(haveTimesSelected);
225            if (haveTimesSelected) {
226                setStatus("Press \"" + CMD_LOAD + "\" to load the selected radar data", "buttons");
227            } else {
228                setStatus("Please select times", "timepanel");
229            }
230        }
231        GuiUtils.enableTree(loadButton, getHaveData());
232    }
233
234
235
236    /**
237     * Handle when there are newly selected stations
238     *
239     * @param stations list of newly selected stations
240     */
241    protected void newSelectedStations(List stations) {
242        super.newSelectedStations(stations);
243        if ((stations == null) || (stations.size() == 0)) {
244            selectedStation = null;
245        } else {
246            NamedStation newStation = (NamedStation) stations.get(0);
247            if (Misc.equals(newStation, selectedStation)) {
248                return;
249            }
250            selectedStation = newStation;
251        }
252        Misc.run(TDSRadarChooser.this, "stationOrProductChanged");
253    }
254
255
256    /** A widget for the list of dataset descriptors */
257
258
259    /** Flag to keep from infinite looping */
260    private boolean ignoreProductChange = false;
261
262    /** Selection label text */
263    protected static final String LABEL_SELECT = " -- Select -- ";
264
265    /**
266     * _more_
267     */
268    protected void productChanged() {
269        stationOrProductChanged();
270        // updateStatus();
271    }
272
273    /**
274     * Reset the descriptor stuff
275     */
276    private void resetProductBox() {
277        ignoreProductChange = true;
278        productComboBox.setSelectedItem(LABEL_SELECT);
279        ignoreProductChange = false;
280    }
281
282    /**
283     * Should we update on first display
284     *
285     * @return true
286     */
287    protected boolean shouldDoUpdateOnFirstDisplay() {
288        return false;
289    }
290
291    /**
292     * Set the server
293     *
294     * @param s the server URL
295     */
296    private void setServer(String s) {
297        datasetList = new ArrayList();
298        serverUrl   = s;
299        try {
300            List collections = getRadarCollections(serverUrl);
301            GuiUtils.setListData(collectionSelector, collections);
302        } catch (Exception e) {
303            GuiUtils.setListData(collectionSelector, new ArrayList());
304        }
305    }
306
307    /**
308     * Set the active collection
309     *
310     * @param s collection URL
311     */
312    private void setCollection(String s) {
313        isLevel3 = false;
314        GuiUtils.enableComponents(level3CompsThatNeedServer, false);
315        productPanel.setVisible(false);
316        GuiUtils.enableComponents(compsThatNeedServer, true);
317        setAbsoluteTimes(new ArrayList());
318        selectedProduct = null;
319        selectedStation = null;
320        Misc.run(this, "initializeCollection", s);
321    }
322
323    /**
324     * _more_
325     *
326     * @param s _more_
327     */
328    private void setLevel3Collection(String s) {
329        isLevel3 = true;
330        GuiUtils.enableComponents(level3CompsThatNeedServer, true);
331        productPanel.setVisible(true);
332        GuiUtils.enableComponents(compsThatNeedServer, true);
333        setAbsoluteTimes(new ArrayList());
334        selectedProduct = null;
335        selectedStation = null;
336        Misc.run(this, "initializeLevel3Collection", s);
337    }
338
339    /**
340     * Add a component that needs to have a valid server
341     *
342     * @param comp  the component
343     *
344     * @return  the component
345     */
346    protected JComponent addServerComp(JComponent comp) {
347        compsThatNeedServer.add(comp);
348        return comp;
349    }
350
351    /**
352     * Add a component that needs to have a valid server
353     *
354     * @param comp  the component
355     *
356     * @return  the component
357     */
358    protected JComponent addLevel3ServerComp(JComponent comp) {
359        level3CompsThatNeedServer.add(comp);
360        return comp;
361    }
362
363    /**
364     * Get  the radar collections for  the given server URL
365     *
366     * @param radarServerURL  server URL
367     *
368     * @return  a map of the collection names to URL
369     */
370    private List getRadarCollections(String radarServerURL) {
371        SAXBuilder        builder;
372        Document          doc  = null;
373        XMLEntityResolver jaxp = new XMLEntityResolver(true);
374        builder = jaxp.getSAXBuilder();
375        List collections = new ArrayList();
376
377        try {
378            doc = builder.build(radarServerURL);
379        } catch (JDOMException e) {
380            userMessage("Invalid catalog");
381            //e.printStackTrace();
382        } catch (IOException e) {
383            userMessage("Unable to open catalog");
384            //e.printStackTrace();
385        }
386
387        org.jdom.Element rootElem    = doc.getRootElement();
388        org.jdom.Element serviceElem = readElements(rootElem, "service");
389        String           uriBase     = serviceElem.getAttributeValue("base");
390        org.jdom.Element dsElem      = readElements(rootElem, "dataset");
391        String           naming      = "catalogRef";
392        Namespace        nss         = rootElem.getNamespace("xlink");
393        List             children    = dsElem.getChildren();
394        for (int j = 0; j < children.size(); j++) {
395            org.jdom.Element child     = (org.jdom.Element) children.get(j);
396            String           childName = child.getName();
397            if (childName.equals(naming)) {
398                //String id   = child.getAttributeValue("ID");
399                String desc    = child.getAttributeValue("title", nss);
400                String urlpath = child.getAttributeValue("href", nss);
401                String[] c = radarServerURL.split(uriBase);  //.replaceFirst("catalog.xml", "");
402                String         ul     = c[0] + uriBase + urlpath;
403                TwoFacedObject twoObj = new TwoFacedObject(desc, ul);
404                collections.add(twoObj);
405                //collections.put(desc, ul);
406            }
407
408        }
409
410        return collections;
411    }
412
413    /**
414     * Read the elements
415     *
416     * @param elem  element
417     * @param eleName element name
418     *
419     * @return an element
420     */
421    public org.jdom.Element readElements(org.jdom.Element elem,
422                                         String eleName) {
423        List children = elem.getChildren();
424        for (int j = 0; j < children.size(); j++) {
425            org.jdom.Element child     = (org.jdom.Element) children.get(j);
426            String           childName = child.getName();
427            if (childName.equals(eleName)) {
428                return child;
429            }
430        }
431        return null;
432    }
433
434    /**
435     * Make the collection.  If there is an error, pop up a user message.
436     *
437     * @param url   URL for the collection
438     */
439    public void initializeCollection(String url) {
440
441        List<NamedStationImpl> stations = new ArrayList<NamedStationImpl>();
442        try {
443            StringBuffer errlog = new StringBuffer();
444            try {
445                collection = TDSRadarDatasetCollection.factory("test", url,
446                        errlog);
447            } catch (Exception exc) {
448                userMessage("Invalid catalog");
449
450                return;
451            }
452            List tdsStations = collection.getRadarStations();
453            for (int i = 0; i < tdsStations.size(); i++) {
454                StationImpl stn = (StationImpl) tdsStations.get(i);
455                // thredds.catalog.query.Location loc = stn.getLocation();
456                //TODO: need better station  need to switch lat lon
457                NamedStationImpl station =
458                    new NamedStationImpl(stn.getName(), stn.getName(),
459                                         stn.getLatitude(),
460                                         stn.getLongitude(),
461                                         stn.getAltitude(), CommonUnit.meter);
462                stations.add(station);
463
464            }
465
466            getStationMap().setStations(stations);
467        } catch (Exception exc) {
468            userMessage("Unable to load stations");
469            return;
470        }
471        urlListHandler.saveState(urlBox);
472    }
473
474    /**
475     * _more_
476     *
477     * @param url _more_
478     */
479    public void initializeLevel3Collection(String url) {
480
481        List<NamedStationImpl> stations = new ArrayList<NamedStationImpl>();
482        List<Product>          products;
483        List<String>           exProducts = new ArrayList<String>();
484
485        for(String ename: level3_ExName){
486            exProducts.add(ename);
487        }
488
489        try {
490            StringBuffer errlog = new StringBuffer();
491            try {
492                collection = TDSRadarDatasetCollection.factory("test", url,
493                        errlog);
494            } catch (Exception exc) {
495                userMessage("Invalid catalog");
496                return;
497            }
498            products = collection.getRadarProducts();
499            List tdsStations = collection.getRadarStations();
500            for (int i = 0; i < tdsStations.size(); i++) {
501                StationImpl stn = (StationImpl) tdsStations.get(i);
502                // thredds.catalog.query.Location loc = stn.getLocation();
503                //TODO: need better station  need to switch lat lon
504                NamedStationImpl station =
505                    new NamedStationImpl(stn.getName(), stn.getName(),
506                                         stn.getLatitude(),
507                                         stn.getLongitude(),
508                                         stn.getAltitude(), CommonUnit.meter);
509                stations.add(station);
510
511            }
512            List<TwoFacedObject> productNames = new ArrayList();
513            for (Product product : products) {
514               // if ( !product.getID().contains("DPA")
515                 //       && !product.getID().contains("NVW")) {
516                if ( !exProducts.contains(product.getID())) {
517                    String lable = product.getName() + " (" + product.getID()
518                                   + ")";
519                    TwoFacedObject twoObj = new TwoFacedObject(lable,
520                                                product.getID());
521                    productNames.add(twoObj);
522                }
523            }
524            GuiUtils.setListData(productComboBox, productNames);
525
526            // GuiUtils.setListData(dataTypeComboBox, dataTypes);
527            getStationMap().setStations(stations);
528        } catch (Exception exc) {
529            userMessage("Unable to load stations");
530            return;
531        }
532        urlListHandler.saveState(urlBox);
533    }
534
535
536    /**
537     * Handle when the user has selected a new station
538     */
539    public void stationOrProductChanged() {
540        Vector times = new Vector();
541        setHaveData(false);
542        if ((!isLevel3 && selectedStation != null) ||
543                (isLevel3 && selectedStation != null && selectedProduct != null)) {
544            List timeSpan = collection.getRadarTimeSpan();
545            Date fromDate =  DateUnit.getStandardOrISO((String) timeSpan.get(0));
546            //Date toDate = DateUnit.getStandardOrISO((String) timeSpan.get(1));
547            Date toDate = new Date(System.currentTimeMillis()
548                                   + DateUtil.daysToMillis(1));
549            //Go back 10 years (or so)
550            //Date fromDate = new Date(System.currentTimeMillis()
551            //                         - DateUtil.daysToMillis(365 * 10));
552            try {
553                showWaitCursor();
554                setAbsoluteTimes(new ArrayList());
555                setStatus("Reading times for station: " + selectedStation,
556                          "");
557                //                LogUtil.message("Reading times for station: "
558                //                                + selectedStation);
559                String pid = null;
560                if(isLevel3)
561                    pid = TwoFacedObject.getIdString(
562                                 productComboBox.getSelectedItem());
563                List allTimes =
564                    collection.getRadarStationTimes(selectedStation.getID(),
565                        pid, fromDate, toDate);
566
567             //   if(allTimes.size() == 0) {
568             //       toDate = new Date(System.currentTimeMillis()
569             //                + DateUtil.daysToMillis(1));
570             //       allTimes =
571             //       collection.getRadarStationTimes(selectedStation.getID(),
572             //           pid, fromDate, toDate);
573             //   }
574
575                for (int timeIdx = 0; timeIdx < allTimes.size(); timeIdx++) {
576                    Object timeObj = allTimes.get(timeIdx);
577                    Date   date;
578                    if (timeObj instanceof Date) {
579                        date = (Date) timeObj;
580                    } else {
581                        date = DateUnit.getStandardOrISO(timeObj.toString());
582                    }
583                    times.add(new DateTime(date));
584                }
585                //                LogUtil.message("");
586                showNormalCursor();
587            } catch (Exception exc) {
588                userMessage("Error reading times for station: "
589                            + selectedStation);
590                //logException("Getting times for station: " + selectedStation,
591                //             exc);
592                setStatus("Select a different collection", "collections");
593                showNormalCursor();
594                return;
595            }
596        }
597        setAbsoluteTimes(times);
598        updateStatus();
599    }
600
601
602
603
604
605    /**
606     * Load the data
607     */
608    public void doLoadInThread() {
609        // to the CDMRadarDataSource
610        Hashtable ht = new Hashtable();
611        if (selectedStation != null) {
612            ht.put(ucar.unidata.data.radar.RadarDataSource.STATION_LOCATION,
613                   selectedStation.getNamedLocation());
614        } else {
615            LogUtil.userMessage("No Station selected");
616        }
617
618        if (isLevel3 && (selectedProduct == null)) {
619
620            LogUtil.userMessage("No Product selected");
621        }
622
623        try {
624            DateSelection dateSelection = new DateSelection();
625            String collectionUrl = TwoFacedObject.getIdString(
626                                       collectionSelector.getSelectedItem());
627            String     pid = null;
628            RadarQuery radarQuery;
629            if (isLevel3) {
630                pid = TwoFacedObject.getIdString(
631                    productComboBox.getSelectedItem());
632                radarQuery = new RadarQuery(collectionUrl,
633                                            selectedStation.getID(), pid,
634                                            dateSelection);
635            } else {
636                radarQuery = new RadarQuery(collectionUrl,
637                                            selectedStation.getID(),
638                                            dateSelection);
639            }
640
641            List urls = new ArrayList();
642
643            if (getDoAbsoluteTimes()) {
644                List times    = new ArrayList();
645                List selected = makeDatedObjects(getSelectedAbsoluteTimes());
646                for (int i = 0; i < selected.size(); i++) {
647                    DatedThing datedThing = (DatedThing) selected.get(i);
648                    Date       date       = datedThing.getDate();
649                    times.add(date);
650                    URI uri = null;
651                    try {
652                        uri = collection.getRadarDatasetURI(
653                            selectedStation.getID(), pid, date);
654                    } catch (Exception excp) {
655                        LogUtil.userMessage("incorrect times selected");
656                        return;
657                    }
658                    urls.add(uri.toString());
659                }
660                if (urls.size() == 0) {
661                    LogUtil.userMessage("No times selected");
662                    return;
663                }
664                dateSelection.setTimes(times);
665            } else {
666                int count = getRelativeTimesList().getSelectedIndex() + 1;
667                if (count == 0) {
668                    LogUtil.userMessage("No relative times selected");
669                    return;
670                }
671                Date toDate = new Date(System.currentTimeMillis()
672                                       + DateUtil.daysToMillis(365 * 100));
673                //Go back 10 years (or so)
674                Date fromDate = new Date(System.currentTimeMillis()
675                                         - DateUtil.daysToMillis(365 * 10));
676
677                dateSelection.setStartFixedTime(fromDate);
678                dateSelection.setEndFixedTime(toDate);
679                dateSelection.setCount(count);
680            }
681            makeDataSource(radarQuery, "FILE.RADAR", ht);
682        } catch (Exception exc) {
683            logException("Loading radar data", exc);
684        }
685    }
686    
687    protected int getNumTimesToSelect() {
688        return 5;
689    }
690    
691    /**
692     * Get the default selected index for the relative times list.
693     *
694     * @return default index
695     */
696    protected int getDefaultRelativeTimeIndex() {
697        return 4;
698    }
699    
700    /**
701     * Check the times lists
702     */
703    protected void checkTimesLists() {
704        super.checkTimesLists();
705        if (timesCardPanelExtra == null) {
706            return;
707        }
708        if (getDoAbsoluteTimes()) {
709            timesCardPanelExtra.show("absolute");
710        } else {
711            timesCardPanelExtra.show("relative");
712        }
713    }
714        
715    /** Card panel to hold extra relative and absolute time components */
716    private GuiUtils.CardLayoutPanel timesCardPanelExtra;
717    
718    /**
719     * Add the interval selector to the component.
720     * @return superclass component with extra stuff
721     */
722    protected JPanel makeTimesPanel() {
723        JComponent extra = getExtraTimeComponent();
724        GuiUtils.enableTree(extra, false);
725        JPanel timesPanel = makeTimesPanel(extra, null);
726        return timesPanel;
727    }
728    
729    /**
730     * Set the relative and absolute extra components
731     */
732    protected JPanel makeTimesPanel(JComponent relativeCard, JComponent absoluteCard) {
733        JPanel timesPanel = super.makeTimesPanel(false,true);
734                
735        // Make a new timesPanel that has extra components tacked on the bottom, inside the tabs
736        Component[] comps = timesPanel.getComponents();
737        if (comps.length==2 && comps[0] instanceof JTabbedPane && comps[1] instanceof JLabel) {         
738            timesCardPanelExtra = new GuiUtils.CardLayoutPanel();
739            if (relativeCard == null) relativeCard = new JPanel();
740            if (absoluteCard == null) absoluteCard = new JPanel();
741            absoluteCard = GuiUtils.hbox(comps[1], GuiUtils.right(absoluteCard));
742            timesCardPanelExtra.add(relativeCard, "relative");
743            timesCardPanelExtra.add(absoluteCard, "absolute");
744            timesPanel = GuiUtils.centerBottom(comps[0], timesCardPanelExtra);
745        }
746        
747        return timesPanel;
748    }
749    
750    /**
751     * Get the time popup widget
752     *
753     * @return  a widget for selecting the day
754     */
755    protected JComponent getExtraTimeComponent() {
756        JPanel filler = new JPanel();
757        McVGuiUtils.setComponentHeight(filler, new JComboBox());
758        return filler;
759    }
760 
761    /**
762     * Make the contents
763     *
764     * @return  the contents
765     */
766    protected JPanel doMakeInnerPanel() {
767        JPanel myPanel = new JPanel();
768
769        JLabel collectionLabel = McVGuiUtils.makeLabelRight("Collection:");
770
771        collectionSelector = new JComboBox();
772        collectionSelector.addItemListener(new ItemListener() {
773            public void itemStateChanged(ItemEvent e) {
774                newSelectedStations(new ArrayList());
775                if (collectionSelector.getSelectedItem() == null) {
776                    return;
777                }
778                String collectionUrl =
779                    TwoFacedObject.getIdString(
780                        collectionSelector.getSelectedItem());
781
782                if (collectionUrl.contains("level3")) {
783                    setLevel3Collection(collectionUrl);
784                } else {
785                    setCollection(collectionUrl);
786                }
787            }
788
789        });
790        addServerComp(collectionLabel);
791        addServerComp(collectionSelector);
792                
793        productComboBox = new JComboBox();
794        productComboBox.addItemListener(new ItemListener() {
795            public void itemStateChanged(ItemEvent e) {
796                if (productComboBox.getSelectedItem() == null) {
797                    return;
798                }
799                selectedProduct =
800                    productComboBox.getSelectedItem().toString();
801                resetProductBox();
802                productChanged();
803            }
804
805        });
806        addLevel3ServerComp(productComboBox);
807                
808        productPanel = McVGuiUtils.makeLabeledComponent("Product:", productComboBox);
809        
810        JLabel stationLabel = McVGuiUtils.makeLabelRight("Station:");
811        addServerComp(stationLabel);
812
813        JComponent stationPanel = getStationMap();
814        registerStatusComp("stations", stationPanel);
815        addServerComp(stationPanel);
816        
817        JLabel timesLabel = McVGuiUtils.makeLabelRight("Times:");
818        addServerComp(timesLabel);
819        
820        JPanel timesPanel = makeTimesPanel();
821        timesPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
822        addServerComp(timesPanel);
823
824        GuiUtils.enableComponents(compsThatNeedServer, false);
825        GuiUtils.enableComponents(level3CompsThatNeedServer, false);
826        productPanel.setVisible(false);
827
828        GroupLayout layout = new GroupLayout(myPanel);
829        myPanel.setLayout(layout);
830        layout.setHorizontalGroup(
831            layout.createParallelGroup(LEADING)
832            .addGroup(layout.createSequentialGroup()
833                .addGroup(layout.createParallelGroup(LEADING)
834                    .addGroup(layout.createSequentialGroup()
835                        .addComponent(collectionLabel)
836                        .addGap(GAP_RELATED)
837                        .addComponent(collectionSelector, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
838                        .addComponent(productPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
839                    .addGroup(layout.createSequentialGroup()
840                        .addComponent(stationLabel)
841                        .addGap(GAP_RELATED)
842                        .addComponent(stationPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
843                    .addGroup(layout.createSequentialGroup()
844                        .addComponent(timesLabel)
845                        .addGap(GAP_RELATED)
846                        .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))))
847        );
848        layout.setVerticalGroup(
849            layout.createParallelGroup(LEADING)
850            .addGroup(layout.createSequentialGroup()
851                .addGroup(layout.createParallelGroup(BASELINE)
852                    .addComponent(collectionLabel)
853                    .addComponent(collectionSelector)
854                    .addComponent(productPanel))
855                .addPreferredGap(RELATED)
856                .addGroup(layout.createParallelGroup(LEADING)
857                    .addComponent(stationLabel)
858                    .addComponent(stationPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
859                .addPreferredGap(RELATED)
860                .addGroup(layout.createParallelGroup(LEADING)
861                    .addComponent(timesLabel)
862                    .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
863                .addPreferredGap(RELATED))
864        );
865        
866        return myPanel;
867    }
868    
869    /**
870     * Make the UI for this selector.
871     * 
872     * Thank you NetBeans for helping with the layout!
873     * 
874     * @return The gui
875     */ 
876    private JPanel innerPanel = doMakeInnerPanel();
877        
878    private JLabel statusLabel = new JLabel("Status");
879
880    @Override
881    public void setStatus(String statusString, String foo) {
882        if (statusString == null)
883            statusString = "";
884        statusLabel.setText(statusString);
885    }
886        
887    protected void setInnerPanel(JPanel newInnerPanel) {
888        innerPanel = newInnerPanel;
889    }
890
891    public JComponent doMakeContents() {
892        JPanel outerPanel = new JPanel();
893
894        JLabel serverLabel = McVGuiUtils.makeLabelRight("Catalog:");                
895
896        //Get the list of catalogs but remove the old catalog.xml entry
897        urlListHandler = getPreferenceList(PREF_TDSRADARSERVER);
898
899        ActionListener catListListener = new ActionListener() {
900            public void actionPerformed(ActionEvent ae) {
901                if ( !okToDoUrlListEvents) {
902                    return;
903                }
904                setServer((String) urlBox.getSelectedItem());
905            }
906        };
907        
908        urlBox = urlListHandler.createComboBox(GuiUtils.CMD_UPDATE, catListListener, true);
909        McVGuiUtils.setComponentWidth(urlBox, Width.DOUBLEDOUBLE);
910        
911        // productComboBox gets created a little too tall--set to same height as urlBox
912        if (productComboBox!=null)
913            McVGuiUtils.setComponentHeight(productComboBox, urlBox);
914                
915        JButton connectButton = McVGuiUtils.makeImageTextButton(ICON_CONNECT_SMALL, "Connect");
916        McVGuiUtils.setComponentWidth(connectButton, Width.DOUBLE);
917        connectButton.setActionCommand(GuiUtils.CMD_UPDATE);
918        connectButton.addActionListener(this);
919                
920        JLabel statusLabelLabel = McVGuiUtils.makeLabelRight("");
921        
922        statusLabel.setText("Status");
923        McVGuiUtils.setLabelPosition(statusLabel, Position.RIGHT);
924        McVGuiUtils.setComponentColor(statusLabel, TextColor.STATUS);
925        
926        JButton helpButton = McVGuiUtils.makeImageButton(ICON_HELP, "Show help");
927        helpButton.setActionCommand(GuiUtils.CMD_HELP);
928        helpButton.addActionListener(this);
929        
930        JButton refreshButton = McVGuiUtils.makeImageButton(ICON_REFRESH, "Refresh");
931        refreshButton.setActionCommand(GuiUtils.CMD_UPDATE);
932        refreshButton.addActionListener(this);
933        
934        McVGuiUtils.setComponentWidth(loadButton, Width.DOUBLE);
935
936        GroupLayout layout = new GroupLayout(outerPanel);
937        outerPanel.setLayout(layout);
938        layout.setHorizontalGroup(
939            layout.createParallelGroup(LEADING)
940            .addGroup(TRAILING, layout.createSequentialGroup()
941                .addGroup(layout.createParallelGroup(TRAILING)
942                    .addGroup(layout.createSequentialGroup()
943                        .addContainerGap()
944                        .addComponent(helpButton)
945                        .addGap(GAP_RELATED)
946                        .addComponent(refreshButton)
947                        .addGap(GAP_RELATED)
948                        .addComponent(cancelButton)
949                        .addPreferredGap(RELATED)
950                        .addComponent(loadButton))
951                        .addGroup(LEADING, layout.createSequentialGroup()
952                        .addContainerGap()
953                        .addGroup(layout.createParallelGroup(LEADING)
954                            .addComponent(innerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
955                            .addGroup(layout.createSequentialGroup()
956                                .addComponent(serverLabel)
957                                .addGap(GAP_RELATED)
958                                .addComponent(urlBox, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
959                                .addGap(GAP_UNRELATED)
960                                .addComponent(connectButton))
961                            .addGroup(layout.createSequentialGroup()
962                                .addComponent(statusLabelLabel)
963                                .addGap(GAP_RELATED)
964                                .addComponent(statusLabel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)))))
965                .addContainerGap())
966        );
967        layout.setVerticalGroup(
968            layout.createParallelGroup(LEADING)
969            .addGroup(layout.createSequentialGroup()
970                .addContainerGap()
971                .addGroup(layout.createParallelGroup(BASELINE)
972                    .addComponent(serverLabel)
973                    .addComponent(urlBox)
974                    .addComponent(connectButton))
975                .addPreferredGap(UNRELATED)
976                .addComponent(innerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
977                .addPreferredGap(UNRELATED)
978                .addGroup(layout.createParallelGroup(BASELINE)
979                    .addComponent(statusLabelLabel)
980                    .addComponent(statusLabel))
981                .addPreferredGap(UNRELATED)
982                .addGroup(layout.createParallelGroup(BASELINE)
983                    .addComponent(loadButton)
984                    .addComponent(cancelButton)
985                    .addComponent(refreshButton)
986                    .addComponent(helpButton))
987                .addContainerGap())
988        );
989    
990        return outerPanel;
991
992    }
993
994}
995