001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2017
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
031
032import org.w3c.dom.Element;
033
034import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
035
036import ucar.unidata.data.DataSource;
037
038import ucar.unidata.data.DataSourceDescriptor;
039import ucar.unidata.data.radar.Level2RadarDataSource;
040
041import ucar.unidata.idv.*;
042import ucar.unidata.idv.chooser.IdvChooserManager;
043import ucar.unidata.idv.control.DisplayControlBase;
044
045import ucar.unidata.metdata.*;
046
047import ucar.unidata.ui.ChooserPanel;
048import ucar.unidata.util.FileManager;
049import ucar.unidata.util.GuiUtils;
050import ucar.unidata.util.Misc;
051
052import ucar.unidata.util.PatternFileFilter;
053import ucar.unidata.util.PollingInfo;
054import ucar.unidata.util.TwoFacedObject;
055import ucar.unidata.xml.XmlResourceCollection;
056
057
058import ucar.unidata.xml.XmlUtil;
059
060import java.awt.*;
061import java.awt.event.*;
062
063import java.io.File;
064
065import java.util.ArrayList;
066import java.util.Collections;
067import java.util.Hashtable;
068import java.util.Iterator;
069import java.util.List;
070import java.util.Map;
071import java.util.Vector;
072
073import javax.swing.*;
074import javax.swing.event.*;
075
076import javax.swing.filechooser.FileFilter;
077
078
079
080/**
081 * A chooser for Level II NEXRAD data. This loads in
082 * files from the file system. Since (right now) the
083 * data does not contain the station we rely on
084 * the heuristic  of looking at the directory path
085 * name to see if it contains a station name.
086 * The user can also specify the station from the GUI
087 *
088 *
089 * @author IDV development team
090 * @version $Revision$Date: 2011/03/24 16:06:31 $
091 */
092public class Level2RadarChooser extends FileChooser {
093
094    /** Holds the predefined list of nexrad stations */
095    private JComboBox stationsCbx;
096
097    /** List of predefined nexrad stations */
098    private List nexradStations;
099
100    /** Label used in the widgets to show an unknown station */
101    private static String UNKNOWN_STATION = "I'm Feeling Lucky";
102
103    /**
104     * The data source id we pass the files to.
105     * This is the oone defined in idv/resources/datasources.xml
106     */
107    private static String DATA_TYPE = "FILE.LEVEL2RADAR";
108
109    /** the type for the CDM radar */
110    private static String CDM_DATA_TYPE = "FILE.RADAR";
111
112    /** checkbox for switching data types */
113    private JCheckBox typeCbx;
114
115    /**
116     * Create the chooser with the given chooser manager
117     * and xml root (from the xml that defines this chooser).
118     *
119     * @param mgr The manager
120     * @param root The xml
121     *
122     */
123    public Level2RadarChooser(IdvChooserManager mgr, Element root) {
124        super(mgr, root);
125    }
126
127    /**
128     * Label for {@link #getDataSourcesComponent()} selector.
129     *
130     * @return {@code String} to use as the label for data sources selector.
131     */
132    protected String getDataSourcesLabel() {
133        return "Station:";
134    }
135
136    /**
137     * Overridden so that McIDAS-V can attempt auto-selecting the default data
138     * source type.
139     */
140    @Override protected JComboBox getDataSourcesComponent() {
141        stationsCbx = new JComboBox();
142        List stations = Misc.newList(UNKNOWN_STATION);
143        stations.addAll(nexradStations = getStations());
144        DisplayControlBase.setStations(stations, stationsCbx, false);
145        return stationsCbx;
146    }
147    
148    /**
149     * Get the tooltip for the load button
150     *
151     * @return The tooltip for the load button
152     */
153    protected String getLoadToolTip() {
154        return "Load the selected Level II radar files";
155    }
156
157    /**
158     * Make the file chooser
159     *
160     * @param path  the initial path
161     *
162     * @return the JFileChooser
163     */
164    protected JFileChooser doMakeFileChooser(String path) {
165        MyFileChooser fileChooser = new Level2RadarFileChooser(this, path);
166        fileChooser.addChoosableFileFilter(new PatternFileFilter(".*\\.raw$", "Raw files"));
167//        fileChooser.setApproveButtonText(ChooserPanel.CMD_LOAD);
168        fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
169        if (path != null) {
170            fileChooser.setCurrentDirectory(new File(path));
171        }
172        return fileChooser;
173    }
174    
175    /**
176     * Process the set of selected files
177     *
178     * @param files Array of files
179     * @param directory The last directory  chosen
180     *
181     * @return true if successful
182     */
183    protected boolean selectFilesInner(File[] files, final File directory) {
184        final Object selected =
185            ((TwoFacedObject) stationsCbx.getSelectedItem()).getId();
186
187        if (selected.equals(UNKNOWN_STATION)
188                && ((typeCbx != null) && !typeCbx.isSelected())) {
189            userMessage("Unknown location of selected files, "
190                        + "please select from list");
191            return false;
192        }
193
194        int recentCnt = getFileCount();
195        if (recentCnt <= 0) {
196            if ((files == null) || (files.length == 0)) {
197                userMessage("Please select one or more files");
198                return false;
199            }
200        }
201        if ((files != null) && (files.length > 0)) {
202            FileManager.addToHistory(files[0]);
203        }
204
205        String[] tmpDataLoc = getFileNames(((recentCnt <= 0)
206                                            ? files
207                                            : null));
208        if (recentCnt <= 0) {
209            if (tmpDataLoc == null) {
210                return false;
211            }
212        }
213
214        final Hashtable properties =
215            Misc.newHashtable(Level2RadarDataSource.STATION_LOCATION,
216                              selected);
217        String pattern = getFilePattern();
218        if ((pattern != null) && (pattern.length() > 0)) {
219            properties.put(DataSource.PROP_FILEPATTERN,
220                           pattern.toLowerCase());
221        } else {
222            pattern = null;
223        }
224
225        if (recentCnt > 0) {
226            properties.put(DataSource.MOST_RECENT, new Integer(recentCnt));
227            tmpDataLoc = new String[] { directory.toString() };
228            PollingInfo pollingInfo = new PollingInfo(directory.toString(),
229                                          60000, pattern, false, false);
230            pollingInfo.setMode(PollingInfo.MODE_COUNT);
231            pollingInfo.setFileCount(recentCnt);
232            properties.put(DataSource.PROP_POLLINFO, pollingInfo);
233        }
234
235        String dataType = ((typeCbx != null) && !typeCbx.isSelected())
236                          ? DATA_TYPE
237                          : CDM_DATA_TYPE;
238        // System.out.println("dataType = " + dataType);
239        makeDataSource(tmpDataLoc, dataType, properties);
240        return true;
241    }
242
243    /**
244     * Read in the nexrad stations from the
245     * idv/resources/nexradstns.xml resource
246     *
247     * @return List of of {@link ucar.unidata.metdata.NamedStation}-s
248     */
249    private List getStations() {
250        if (nexradStations == null) {
251            nexradStations = new Vector();
252            List radarLocations =
253                getIdv().getResourceManager().findLocationsByType("radar");
254            for (int i = 0; i < radarLocations.size(); i++) {
255                NamedStationTable nexrTable =
256                    (NamedStationTable) radarLocations.get(i);
257                nexradStations.addAll(nexrTable.values());
258            }
259            Collections.sort(nexradStations);
260        }
261        return nexradStations;
262    }
263
264    /**
265     * Try to guess at the station of the selected
266     * file based on directory name.
267     *
268     * @param file The selected file
269     */
270    protected void guessAtStation(File file) {
271
272        if ((file == null) || !file.isDirectory()) {
273            return;
274        }
275        if ((nexradStations == null) || nexradStations.isEmpty()) {
276            return;
277        }
278        File tmpFile = file;
279
280        //Walk up the directory tree, looking at the names of each file
281
282        //Use the  dirLevel so we only do the println on the first check.
283        //Though  we could use it to only check one or two directory levels
284        int     dirLevel = 0;
285        boolean found    = false;
286        while ((tmpFile != null) && (found == false)) {
287            String name = tmpFile.getName().toLowerCase();
288            for (Iterator iter =
289                    nexradStations.iterator(); iter.hasNext(); ) {
290                NamedStation station = (NamedStation) iter.next();
291                if (station == null) {
292                    continue;
293                }
294
295                String id = station.getIdentifier();
296                //Do a .equals - perhaps we do want to do the .indexOf check??
297                //Though that might mean some odd matches.
298                if (name.indexOf(id.toLowerCase()) >= 0) {
299                    stationsCbx.setSelectedItem(
300                        DisplayControlBase.createStationTfo(station));
301                    found = true;
302                    break;
303                }
304            }
305            dirLevel++;
306            tmpFile = tmpFile.getParentFile();
307        }
308        if ( !found) {
309            stationsCbx.setSelectedItem(UNKNOWN_STATION);
310        }
311    }
312
313    /**
314     * This class allows us to add in our own functionality
315     * to the file chooser. It has a hook to support the guessing
316     * of the station from the directory name and passes through
317     * to the chooser the select and cancel events
318     *
319     * @author IDV development team
320     */
321    public class Level2RadarFileChooser extends FileChooser.MyFileChooser {
322
323        /** my chooser */
324        Level2RadarChooser myChooser;
325
326        /** Keeps track of the last directory the user chose */
327        File lastDirectory = null;
328
329        /**
330         * Create the special file chooser
331         *
332         *
333         * @param chooser the chooser to relate to
334         * @param path  path to start with
335         */
336        public Level2RadarFileChooser(Level2RadarChooser chooser,
337                                      String path) {
338            super(path);
339            myChooser = chooser;
340        }
341
342        /**
343         * Try to guess at the  station name
344         *
345         * @param file The currently selected dir
346         */
347        public void setCurrentDirectory(File file) {
348            super.setCurrentDirectory(file);
349            if ( !Misc.equals(file, lastDirectory)) {
350                if (myChooser != null) {
351                    myChooser.guessAtStation(file);
352                }
353                lastDirectory = file;
354            }
355        }
356    }
357
358    /**
359     * Get the bottom panel for the chooser
360     * @return the bottom panel
361     */
362    protected JPanel getBottomPanel() {       
363        // do this because the original check is made before the list is inited
364        if (getFileChooser() != null) {
365            guessAtStation(getFileChooser().getCurrentDirectory());
366        }
367        JComponent recentComponent = getRecentFilesComponent();
368        Component [] components = recentComponent.getComponents();
369        if (components != null) {
370                for (int i = 0; i < components.length; i++) {
371                        if (components[i] instanceof JLabel) {
372                                McVGuiUtils.setComponentWidth((JLabel)components[i], McVGuiUtils.Width.SINGLE);
373                                McVGuiUtils.setLabelPosition((JLabel)components[i], McVGuiUtils.Position.RIGHT);
374                        }
375                        else if (components[i] instanceof JComboBox) {
376                                McVGuiUtils.setComponentWidth((JComboBox)components[i], McVGuiUtils.Width.DOUBLE);
377                        }
378                        else if (components[i] instanceof JTextField) {
379                                McVGuiUtils.setComponentWidth((JTextField)components[i], McVGuiUtils.Width.SINGLE);
380                        }
381                }
382                recentComponent = GuiUtils.left(GuiUtils.hbox(components));
383        }
384        return McVGuiUtils.makeLabeledComponent("Times:", recentComponent);
385    }
386    
387}
388