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