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