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