001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2024
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 https://www.gnu.org/licenses/.
027 */
028
029package edu.wisc.ssec.mcidasv.chooser;
030
031
032import ucar.unidata.beans.NonVetoableProperty;
033import ucar.unidata.beans.Property;
034import ucar.unidata.beans.PropertySet;
035import ucar.unidata.data.sounding.CMASoundingAdapter;
036import ucar.unidata.data.sounding.NetcdfSoundingAdapter;
037import ucar.unidata.data.sounding.SoundingAdapter;
038
039
040import ucar.unidata.util.FileManager;
041
042import ucar.unidata.util.GuiUtils;
043import ucar.unidata.util.LogUtil;
044import ucar.unidata.util.Misc;
045import ucar.unidata.util.PatternFileFilter;
046
047
048
049import java.awt.Component;
050import java.awt.Insets;
051import java.awt.event.ActionEvent;
052import java.awt.event.ActionListener;
053import java.awt.event.WindowAdapter;
054import java.awt.event.WindowEvent;
055import java.awt.event.WindowListener;
056
057import java.beans.*;
058
059import java.io.File;
060
061import javax.swing.BorderFactory;
062import javax.swing.JButton;
063import javax.swing.JFrame;
064import javax.swing.JOptionPane;
065import javax.swing.JPanel;
066import javax.swing.JTextField;
067
068
069/**
070 * A browser for finding netCDF upper air files.
071 *
072 * @author Unidata development team
073 * @version $Revision$
074 */
075public class SoundingFileBrowser {
076
077    /** PatternFileFilter for upper air netCDF files */
078    public static final PatternFileFilter FILTER_NC =
079        new PatternFileFilter(".*ua\\.nc$,Upperair.*\\.nc$",
080                              "netCDF Upper Air files (*ua.nc)");
081
082    /** PatternFileFilter for CMA upper air files */
083    public static final PatternFileFilter FILTER_CMA_UA =
084        new PatternFileFilter(".*\\.ta$", "CMA Upper Air files (*.ta)");
085
086    /** property for the sounding adapter */
087    private Property soundingAdapterProperty;
088
089    /** property set */
090    private PropertySet propertySet;
091
092    /** selected file input */
093    protected JTextField selectedFileDisplay;
094
095    /** flag for file changes */
096    private boolean ignoreChangingFile = false;
097
098    /** frame for the browse */
099    private static JFrame frame = null;
100
101    /** frame contents */
102    private JPanel contents;
103
104    /**
105     * Construct an object for selecting sounding files starting at
106     * the current directory
107     */
108    SoundingFileBrowser() {
109        this(".");
110    }
111
112    /**
113     * Construct an object for selecting sounding files starting at
114     * the specified directory.
115     *
116     * @param  directoryName   starting directory to search for files.
117     */
118    SoundingFileBrowser(String directoryName) {
119
120        // set up the properties
121        propertySet = new PropertySet();
122
123        propertySet.addProperty(soundingAdapterProperty =
124            new NonVetoableProperty(this, "soundingAdapter"));
125
126        File selectedFile = new File(directoryName);
127
128
129        selectedFileDisplay = new JTextField(30);
130        selectedFileDisplay.addActionListener(new ActionListener() {
131            public void actionPerformed(ActionEvent ae) {
132                checkNewFile(new File(selectedFileDisplay.getText().trim()));
133            }
134        });
135        GuiUtils.setNoFill();
136        GuiUtils.tmpInsets = new Insets(0, 2, 0, 2);
137        contents = GuiUtils.doLayout(new Component[] { selectedFileDisplay,
138                fileSelectionButton() }, 2, GuiUtils.WT_N, GuiUtils.WT_N);
139    }
140
141
142    /**
143     * Create a file selection button
144     * @return the file selection button
145     */
146    private JButton fileSelectionButton() {
147        JButton fileSelectButton = new JButton("Select File...");
148        fileSelectButton.addActionListener(new ActionListener() {
149            public void actionPerformed(ActionEvent e) {
150                //Read the file - don't include the "include all" file filter.
151                String file =
152                    FileManager.getReadFile("Select Upper Air File",
153                                            Misc.newList(FILTER_NC,
154                                                FILTER_CMA_UA));
155                if (file == null) {
156                    return;
157                }
158                checkNewFile(new File(file));
159            }
160        });
161
162        return fileSelectButton;
163    }
164
165    /**
166     * Check the status of the file.
167     *
168     * @param selectedFile   file to use for checking
169     */
170    protected void checkNewFile(File selectedFile) {
171        if (ignoreChangingFile) {
172            return;
173        }
174        if ( !selectedFile.exists()) {
175            LogUtil.userMessage("File does not exist:" + selectedFile);
176            return;
177        }
178        SoundingAdapter adapter = null;
179        try {
180            adapter = new NetcdfSoundingAdapter(selectedFile);
181        } catch (IllegalArgumentException ill) {
182            System.out.println(ill.getMessage());
183            try {
184                adapter = new CMASoundingAdapter(selectedFile);
185            } catch (Exception exc) {
186                LogUtil.logException("Reading sounding:" + selectedFile, exc);
187                return;
188            }
189        } catch (Exception exc) {
190            LogUtil.logException("Reading sounding:" + selectedFile, exc);
191            return;
192        }
193        if (adapter.getSoundingTimes() != null) {
194            try {
195                soundingAdapterProperty.setValueAndNotifyListeners(adapter);
196                ignoreChangingFile = true;
197                selectedFileDisplay.setText(selectedFile.getPath());
198                ignoreChangingFile = false;
199            } catch (PropertyVetoException excpt) {
200                LogUtil.logException("New sounding dataset was vetoed: ",
201                                     excpt);
202            }
203        } else {
204            LogUtil.userMessage("Unable to read data from file "
205                                + selectedFile);
206        }
207    }
208
209
210    /**
211     * Get the contents of this browser.
212     *
213     * @return browser contents
214     */
215    public JPanel getContents() {
216        return contents;
217    }
218
219    /**
220     * Get the SoundingAdapter property
221     *
222     * @return the SoundingAdapter property
223     */
224    protected Property getSoundingAdapterProperty() {
225        return soundingAdapterProperty;
226    }
227
228    /**
229     * Get the SoundingAdapter associated with this browser
230     * @return the associated SoundingAdapter
231     */
232    public SoundingAdapter getSoundingAdapter() {
233        return (SoundingAdapter) soundingAdapterProperty.getValue();
234    }
235
236    /**
237     * Adds a property change listener.
238     *
239     * @param listener          The property change listener.
240     */
241    public void addPropertyChangeListener(PropertyChangeListener listener) {
242        propertySet.addPropertyChangeListener(listener);
243    }
244
245    /**
246     * Removes a property change listener.
247     *
248     * @param listener          The property change listener.
249     */
250    public void removePropertyChangeListener(
251            PropertyChangeListener listener) {
252        propertySet.removePropertyChangeListener(listener);
253    }
254
255    /**
256     * Adds a property change listener for a named property.
257     *
258     * @param name              The name of the property.
259     * @param listener          The property change listener.
260     */
261    public void addPropertyChangeListener(String name,
262                                          PropertyChangeListener listener) {
263        propertySet.addPropertyChangeListener(name, listener);
264    }
265
266    /**
267     * Removes a property change listener for a named property.
268     *
269     * @param name              The name of the property.
270     * @param listener          The property change listener.
271     */
272    public void removePropertyChangeListener(
273            String name, PropertyChangeListener listener) {
274        propertySet.removePropertyChangeListener(name, listener);
275    }
276
277    /**
278     * Test routine.
279     *
280     * @param args  name of file or directory if supplied
281     */
282    public static void main(String[] args) {
283
284        frame = new JFrame("Sounding Browser Test");
285
286        frame.addWindowListener(new WindowAdapter() {
287            public void windowClosing(WindowEvent e) {
288                System.exit(0);
289            }
290        });
291
292        SoundingFileBrowser ncfb = new SoundingFileBrowser((args.length > 0)
293                ? args[0]
294                : "/var/data/ldm/decoded");
295
296        frame.getContentPane().add(ncfb.getContents());
297        frame.pack();
298        frame.setVisible(true);
299    }
300}
301