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    import java.awt.Component;
032    import java.awt.Container;
033    import java.awt.event.ActionEvent;
034    import java.awt.event.ActionListener;
035    import java.beans.PropertyChangeEvent;
036    import java.beans.PropertyChangeListener;
037    import java.io.File;
038    import java.util.ArrayList;
039    import java.util.Collections;
040    import java.util.Vector;
041    
042    import javax.swing.JComboBox;
043    import javax.swing.JFileChooser;
044    import javax.swing.JLabel;
045    import javax.swing.JPanel;
046    import javax.swing.filechooser.FileFilter;
047    
048    import org.w3c.dom.Element;
049    
050    import ucar.unidata.idv.chooser.IdvChooserManager;
051    import ucar.unidata.util.GuiUtils;
052    import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
053    
054    public class HRITChooser extends FileChooser {
055    
056            private static final long serialVersionUID = 1L;
057        
058        private HRITFilter hf = null;
059    
060        private JLabel channelLabel = McVGuiUtils.makeLabelRight("Data Channel:");
061    
062        /**
063         * Create the chooser with the given manager and xml
064         *
065         * @param mgr The manager
066         * @param root The xml
067         *
068         */
069        
070        public HRITChooser(IdvChooserManager mgr, Element root) {
071            super(mgr, root);
072        }
073        
074        /**
075         * Make the file chooser
076         *
077         * @param path   the initial path
078         *
079         * @return  the file chooser
080         */
081        
082        protected JFileChooser doMakeFileChooser(String path) {
083            return new HRITFileChooser(path);
084        }
085        
086        protected Vector<String> getAvailableHRITTypes(String path) {
087            if (path == null) path = ".";
088            
089            ArrayList<String> al = new ArrayList<String>();
090            Vector<String> v = new Vector<String>();
091            File f = new File(path);
092            File [] files = null;
093            if (f.isDirectory()) {
094                    files = f.listFiles(
095                            new java.io.FileFilter() {
096                                    public boolean accept(File f) {
097                                if ((f.getName().endsWith("__")) && (f.getName().matches(".*MSG[2-3].*"))) {
098                                    return true;
099                                } else {
100                                    return false;
101                                }
102                                    }
103                            }
104                    );
105            }
106            if (files != null) {
107                    for (int i = 0; i < files.length; i++) {
108                    String channelStr = files[i].getName().substring(26, 32);
109                    if (channelStr.equals("______")) continue;
110                    channelStr = channelStr.replace("___", "");
111                    if (! al.contains(channelStr)) {
112                            al.add(channelStr);
113                    }
114                    }
115            }
116            Collections.sort(al);
117            for (int i = 0; i < al.size(); i++) {
118                    v.add(al.get(i));
119            }
120            return v;
121        }
122        
123        public class ImageTypeChooser extends JComboBox implements ActionListener, PropertyChangeListener {
124            
125                    private static final long serialVersionUID = 1L;
126                    JFileChooser jfc = null;
127            
128            public ImageTypeChooser(JFileChooser fc, String path) {
129                    jfc = fc;
130                Vector<String> availableTypes = getAvailableHRITTypes(path);
131                if (availableTypes.size() == 1 && availableTypes.get(0) == ".") {
132                    availableTypes.removeAllElements();
133                }
134                reloadComboBox(availableTypes);
135                addActionListener(this);
136                McVGuiUtils.setComponentWidth(this, McVGuiUtils.Width.DOUBLE);
137            }
138            
139            public void actionPerformed(ActionEvent e) {
140                JComboBox cb = (JComboBox) e.getSource();
141                String newFilter = (String) cb.getSelectedItem();
142                HRITFilter hFilter = (HRITFilter) jfc.getFileFilter();
143                hFilter.setExtraFilter(newFilter);
144                jfc.rescanCurrentDirectory();
145            }
146            
147            public void reloadComboBox(Vector<String> v) {
148                    removeAllItems();
149                    if (v != null) {
150                            for (int i = 0; i < v.size(); i++) {
151                                    addItem(v.get(i));
152                            }
153                    }
154                    if (v == null || v.size() == 0) {
155                            setEnabled(false);
156                            channelLabel.setEnabled(false);
157                    }
158                    else {
159                            setEnabled(true);
160                            channelLabel.setEnabled(true);
161                    }
162            }
163            
164            public void propertyChange(PropertyChangeEvent e) {
165                String prop = e.getPropertyName();
166    
167                // If the directory changed, reload the combo box with new image type choices.
168                if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) {
169                    Vector<String> availableTypes = getAvailableHRITTypes(jfc.getCurrentDirectory().getPath());
170                    reloadComboBox(availableTypes);
171                }
172    
173            }
174            
175        }
176        
177        /* HRITFilter */
178        public class HRITFilter extends FileFilter {
179            
180            String extraFilter = null;
181            
182            public HRITFilter(String extraFilter) {
183                    super();
184                    if (extraFilter != null) {
185                            this.extraFilter = extraFilter;
186                    }
187            }
188            
189            // Accept all directories and all HRIT files.
190            public boolean accept(File f) {
191                    
192                if (f.isDirectory()) {
193                    return true;
194                }
195    
196                // XXX TJJ - at present, we are ONLY allowing MSG2 and MSG3 segment data files
197                // through the filter which have already been Wavelet decompressed
198                // (i.e., they end with __ and not C_ )
199                String fileName = f.getName();
200                if ((fileName.endsWith("__")) && (fileName.matches(".*MSG[2-3].*")) && (fileName.length() >= 58)) {
201                    if (extraFilter != null) {
202                            if (fileName.contains(extraFilter)) {
203                                    return true;
204                            } else {
205                                    return false;
206                            }
207                    }
208                } else {
209                    return false;
210                }
211                return false;
212    
213            }
214    
215            // The description of this filter
216            public String getDescription() {
217                return "HRIT Data";
218            }
219            
220            // change the additional filter string
221            public void setExtraFilter(String newFilter) {
222                    if (newFilter != null) {
223                            extraFilter = newFilter;
224                            //seenPatterns.clear();
225                    }
226            }
227            
228        }
229            
230        /**
231         * HRITFileChooser, an extension of JFileChooser
232         *
233         * @author Tommy Jasmin
234         */
235        
236        public class HRITFileChooser extends JFileChooser {
237    
238            /**
239                     * default for serializable class
240                     */
241                    private static final long serialVersionUID = 1L;
242    
243                    /**
244             * Create the file chooser
245             *
246             * @param path   the initial path
247             */
248                    
249            public HRITFileChooser(String path) {
250                super(path);
251                setControlButtonsAreShown(false);
252                setMultiSelectionEnabled(false);
253                setAcceptAllFileFilterUsed(false);
254                processChildren(this);
255            }
256    
257            private void processChildren(Container c) {
258                    Component [] components = c.getComponents();
259                    if (components != null) {
260                            // loop through all components, looking for the JLabel children of 
261                            // components we want to remove
262                            for (int i = 0; i < components.length; i++) {
263                                    if (components[i] instanceof JLabel) {
264                                            String text = ((JLabel) components[i]).getText();
265                                            if (text.equals("File Name:")) {
266                                                    hideChildren((Container) components[i].getParent());
267                                                    continue;
268                                            }
269                                            if (text.equals("Files of Type:")) {
270                                                    hideChildren((Container) components[i].getParent());
271                                                    continue;
272                                            }
273                                    }
274                                    // now check this component for any children
275                                    processChildren((Container) components[i]);
276                            }
277                    }
278            }
279            
280            private void hideChildren(Container c) {
281                    Component [] components = c.getComponents();
282                    for (int i = 0; i < components.length; i++) {
283                            components[i].setVisible(false);
284                    }
285                    c.setVisible(false);
286            }
287    
288            /**
289             * Approve the selection
290             */
291            
292            public void approveSelection() {
293                HRITChooser.this.doLoad();
294            }
295    
296            /**
297             * Cancel the selection
298             */
299            
300            public void cancelSelection() {
301                closeChooser();
302            }
303    
304            /**
305             * Set the selected files
306             *
307             * @param selectedFiles  the selected files
308             */
309            
310            public void setSelectedFiles(File[] selectedFiles) {
311                    String channelStr = null;
312                    String timeStr = null;
313                    if (selectedFiles != null) {
314                            for (int i = 0; i < selectedFiles.length; i++) {
315                                    if (! selectedFiles[i].isDirectory()) {
316                                            if (selectedFiles[i].getName().length() >= 58) {
317                                                    channelStr = selectedFiles[i].getName().substring(26, 32);
318                                                    timeStr = selectedFiles[i].getName().substring(46, 58);
319                                            }
320                                    }
321                            }
322                    }
323                    File curDir = getCurrentDirectory();
324                    File [] fileList = curDir.listFiles();
325                    String tmpChannel = null;
326                    String tmpTime = null;
327                    ArrayList<File> matches = new ArrayList<File>();
328                    for (int i = 0; i < fileList.length; i++) {
329                            if ((fileList[i].getName().endsWith("__")) && 
330                                    (fileList[i].getName().matches(".*MSG[2-3].*")) && 
331                                    (fileList[i].getName().length() >= 58)) {
332                                    tmpChannel = fileList[i].getName().substring(26, 32);
333                                    tmpTime = fileList[i].getName().substring(46, 58);
334                                    if ((tmpChannel.equals(channelStr)) && (tmpTime.equals(timeStr))) {
335                                            matches.add(fileList[i]);
336                                    }
337                            }
338                    }
339                    Collections.sort(matches);
340                    
341                    // make new file array from ArrayList matches
342                    File [] fileSet = new File[matches.size()];
343                    for (int i = 0; i < matches.size(); i++) {
344                            fileSet[i] = (File) matches.get(i);
345                    }
346    
347                    super.setSelectedFiles(fileSet);
348                setHaveData( !((selectedFiles == null)
349                               || (selectedFiles.length == 0)));
350            }
351        }
352    
353        /**
354         * Handle the selection of the set of files
355         *
356         * @param files The files the user chose
357         * @param directory The directory they chose them from
358         * @return True if the file was successful
359         * @throws Exception
360         */
361        
362        protected boolean selectFilesInner(File[] files, File directory)
363                throws Exception {
364            if ((files == null) || (files.length == 0)) {
365                userMessage("Please select a file");
366                return false;
367            }
368            
369            // only allow selection of files that make sense as a "set"
370            // for now, that means all part of single image for a single channel
371            String channelStr = files[0].getName().substring(26, 32);
372            String timeStr = files[0].getName().substring(46, 58);
373            int prvSegment = -1;
374            int curSegment = -1;
375            for (int i = 0; i < files.length; i++) {
376                    try {
377                            curSegment = Integer.parseInt(files[i].getName().substring(40, 42));
378                    } catch (NumberFormatException nfe) {
379                            userMessage("Problem determining image segment number for file: " + files[i].getName());
380                            return false;
381                    }
382                    if (!files[i].getName().substring(26, 32).equals(channelStr)) {
383                            userMessage("Selected data must be for a single channel and time");
384                            return false;
385                    }
386                    if (!files[i].getName().substring(46, 58).equals(timeStr)) {
387                            userMessage("Selected data must be for a single channel and time");
388                            return false;
389                    }
390                    if (prvSegment >= 0) {
391                            if (curSegment != (prvSegment + 1)) {
392                            userMessage("Selected data must be a contiguous set of image segment files");
393                            return false;
394                            }
395                    }
396                    prvSegment = curSegment;
397            }
398            
399            // XXX TJJ - until HRITAdapter can handle the fact that HRV data can 
400            // alter geographic coverage in mid-transmission, we deal with this by
401            // only allowing display of HRV segments one at a time.
402            
403            // commenting out for now - will deal with it in field selector window
404    /*        if (files.length > 1) {
405                    int hrvCount = 0;
406                    for (int i = 0; i < files.length; i++) {
407                            if (files[i].getName().contains("HRV")) {
408                                    hrvCount++;
409                            } 
410                            if (hrvCount > 1) {
411                                    userMessage("At present, HRV data can only be displayed one file at a time");
412                                    return false;
413                            }                       
414                    }
415            }*/
416    
417            return super.selectFilesInner(files, directory);
418        }
419        
420        /**
421         * Get the bottom panel for the chooser
422         * @return the bottom panel
423         */
424        
425        protected JPanel getBottomPanel() {
426            // If we don't have a fileChooser yet, this won't do any good
427            // This happens when Unidata's FileChooser is instantiated
428            // We instantiate ours right after that
429            if (fileChooser == null) {
430                    return null;
431            }
432            
433            ImageTypeChooser itc = new ImageTypeChooser(fileChooser, path);
434            fileChooser.addPropertyChangeListener(itc);
435            JPanel bottomPanel = GuiUtils.left(itc);
436            bottomPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
437            
438            return McVGuiUtils.makeLabeledComponent(channelLabel, itc);
439        }
440        
441        /**
442         * Get the center panel for the chooser
443         * @return the center panel
444         */
445        
446        protected JPanel getCenterPanel() {
447            JPanel centerPanel = super.getCenterPanel();
448            
449            fileChooser.setAcceptAllFileFilterUsed(false);
450          
451            // see what HRIT data is available in this directory,
452            Vector<String> availableTypes = getAvailableHRITTypes(path);
453            String extraFilter = null;
454            if ((availableTypes != null) && (availableTypes.size() > 0)) {
455                    extraFilter = (String) availableTypes.get(0);
456            }
457            
458            hf = new HRITFilter(extraFilter);
459            fileChooser.setFileFilter(hf);
460    
461            return centerPanel;
462        }
463        
464    }