001    /*
002     * $Id: HRITChooser.java,v 1.18 2012/02/19 17:35:36 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    import java.awt.Component;
034    import java.awt.Container;
035    import java.awt.event.ActionEvent;
036    import java.awt.event.ActionListener;
037    import java.beans.PropertyChangeEvent;
038    import java.beans.PropertyChangeListener;
039    import java.io.File;
040    import java.util.ArrayList;
041    import java.util.Collections;
042    import java.util.Vector;
043    
044    import javax.swing.JComboBox;
045    import javax.swing.JFileChooser;
046    import javax.swing.JLabel;
047    import javax.swing.JPanel;
048    import javax.swing.filechooser.FileFilter;
049    
050    import org.w3c.dom.Element;
051    
052    import ucar.unidata.idv.chooser.IdvChooserManager;
053    import ucar.unidata.util.GuiUtils;
054    import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
055    
056    public 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    }