001    /*
002     * $Id: Level2RadarChooser.java,v 1.7 2012/02/19 17:35:37 davep Exp $
003     *
004     * This file is part of McIDAS-V
005     *
006     * Copyright 2007-2012
007     * Space Science and Engineering Center (SSEC)
008     * University of Wisconsin - Madison
009     * 1225 W. Dayton Street, Madison, WI 53706, USA
010     * https://www.ssec.wisc.edu/mcidas
011     * 
012     * All Rights Reserved
013     * 
014     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015     * some McIDAS-V source code is based on IDV and VisAD source code.  
016     * 
017     * McIDAS-V is free software; you can redistribute it and/or modify
018     * it under the terms of the GNU Lesser Public License as published by
019     * the Free Software Foundation; either version 3 of the License, or
020     * (at your option) any later version.
021     * 
022     * McIDAS-V is distributed in the hope that it will be useful,
023     * but WITHOUT ANY WARRANTY; without even the implied warranty of
024     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025     * GNU Lesser Public License for more details.
026     * 
027     * You should have received a copy of the GNU Lesser Public License
028     * along with this program.  If not, see http://www.gnu.org/licenses.
029     */
030    
031    package edu.wisc.ssec.mcidasv.chooser;
032    
033    
034    import org.w3c.dom.Element;
035    
036    import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
037    
038    import ucar.unidata.data.DataSource;
039    
040    import ucar.unidata.data.DataSourceDescriptor;
041    import ucar.unidata.data.radar.Level2RadarDataSource;
042    
043    import ucar.unidata.idv.*;
044    import ucar.unidata.idv.chooser.IdvChooserManager;
045    import ucar.unidata.idv.control.DisplayControlBase;
046    
047    import ucar.unidata.metdata.*;
048    
049    import ucar.unidata.ui.ChooserPanel;
050    import ucar.unidata.util.FileManager;
051    import ucar.unidata.util.GuiUtils;
052    import ucar.unidata.util.Misc;
053    
054    import ucar.unidata.util.PatternFileFilter;
055    import ucar.unidata.util.PollingInfo;
056    import ucar.unidata.util.TwoFacedObject;
057    import ucar.unidata.xml.XmlResourceCollection;
058    
059    
060    import ucar.unidata.xml.XmlUtil;
061    
062    import java.awt.*;
063    import java.awt.event.*;
064    
065    import java.io.File;
066    
067    import java.util.ArrayList;
068    import java.util.Collections;
069    import java.util.Hashtable;
070    import java.util.Iterator;
071    import java.util.List;
072    import java.util.Map;
073    import java.util.Vector;
074    
075    import javax.swing.*;
076    import javax.swing.event.*;
077    
078    import 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.7 $Date: 2012/02/19 17:35:37 $
093     */
094    public 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