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