001 /* 002 * $Id: SuomiNPPChooser.java,v 1.3 2012/03/29 20:44:30 tommyj 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 package edu.wisc.ssec.mcidasv.chooser; 031 032 import java.awt.Component; 033 import java.awt.Container; 034 035 import java.io.File; 036 037 import java.text.ParseException; 038 import java.text.SimpleDateFormat; 039 import java.util.Date; 040 import java.util.Vector; 041 042 import javax.swing.JFileChooser; 043 import javax.swing.JLabel; 044 import javax.swing.JOptionPane; 045 import javax.swing.JPanel; 046 047 import org.slf4j.Logger; 048 import org.slf4j.LoggerFactory; 049 050 import ucar.unidata.idv.chooser.IdvChooserManager; 051 import ucar.unidata.util.StringUtil; 052 053 public class SuomiNPPChooser extends FileChooser { 054 055 private static final long serialVersionUID = 1L; 056 private static final Logger logger = LoggerFactory.getLogger(SuomiNPPChooser.class); 057 private static final long CONSECUTIVE_GRANULE_TIME_GAP_MS = 1000; 058 059 // date formatter for converting Suomi NPP day/time from file name for consecutive granule check 060 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmSSS"); 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 SuomiNPPChooser(IdvChooserManager mgr, org.w3c.dom.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 if (fileChooser == null) { 084 logger.trace("Creating Suomi NPP File Chooser..."); 085 fileChooser = new SuomiNPPFileChooser(path); 086 } else { 087 logger.trace("2nd call to doMakeFileChooser, why?"); 088 } 089 return fileChooser; 090 } 091 092 /** 093 * An extension of JFileChooser 094 * 095 * @author Tommy Jasmin 096 */ 097 098 public class SuomiNPPFileChooser extends JFileChooser { 099 100 /** 101 * default for serializable class 102 */ 103 private static final long serialVersionUID = 1L; 104 105 /** 106 * Create the file chooser 107 * 108 * @param path the initial path 109 */ 110 public SuomiNPPFileChooser(String path) { 111 super(path); 112 setControlButtonsAreShown(false); 113 setMultiSelectionEnabled(true); 114 setAcceptAllFileFilterUsed(false); 115 processChildren(this); 116 } 117 118 private void processChildren(Container c) { 119 Component [] components = c.getComponents(); 120 if (components != null) { 121 // loop through all components, looking for the JLabel children of 122 // components we want to remove 123 for (int i = 0; i < components.length; i++) { 124 if (components[i] instanceof JLabel) { 125 String text = ((JLabel) components[i]).getText(); 126 if (text.equals("File Name:")) { 127 hideChildren((Container) components[i].getParent()); 128 continue; 129 } 130 if (text.equals("Files of Type:")) { 131 hideChildren((Container) components[i].getParent()); 132 continue; 133 } 134 } 135 // now check this component for any children 136 processChildren((Container) components[i]); 137 } 138 } 139 } 140 141 private void hideChildren(Container c) { 142 Component [] components = c.getComponents(); 143 for (int i = 0; i < components.length; i++) { 144 components[i].setVisible(false); 145 } 146 c.setVisible(false); 147 } 148 149 /** 150 * Approve the selection 151 */ 152 public void approveSelection() { 153 SuomiNPPChooser.this.doLoad(); 154 } 155 156 /** 157 * Cancel the selection 158 */ 159 public void cancelSelection() { 160 closeChooser(); 161 } 162 163 /** 164 * Set the selected files 165 * 166 * @param selectedFiles the selected files 167 */ 168 public void setSelectedFiles(File[] selectedFiles) { 169 super.setSelectedFiles(selectedFiles); 170 setHaveData( !((selectedFiles == null) || (selectedFiles.length == 0))); 171 } 172 } 173 174 /** 175 * Handle the selection of the set of files 176 * 177 * @param files The files the user chose 178 * @param directory The directory they chose them from 179 * @return True if the file was successful 180 * @throws Exception 181 */ 182 183 protected boolean selectFilesInner(File[] files, File directory) 184 throws Exception { 185 if ((files == null) || (files.length == 0)) { 186 userMessage("Please select a file"); 187 return false; 188 } 189 190 // At present, Suomi NPP chooser only allows selecting sets of consecutive granules 191 boolean granulesAreConsecutive = testConsecutiveGranules(files); 192 if (granulesAreConsecutive) { 193 return super.selectFilesInner(files, directory); 194 } else { 195 // throw up a dialog to tell user the problem 196 JOptionPane.showMessageDialog(this, "When selecting multiple granules, they must be consecutive."); 197 } 198 return false; 199 } 200 201 /** 202 * Test whether a set of files are consecutive Suomi NPP granules, 203 * any sensor. 204 * @param files 205 * @return true if consecutive tests pass for all files 206 */ 207 208 private boolean testConsecutiveGranules(File[] files) { 209 boolean testResult = false; 210 if (files == null) return testResult; 211 // compare start time of current granule with end time of previous 212 // difference should be very small - under a second 213 long prvTime = -1; 214 testResult = true; 215 for (int i = 0; i < files.length; i++) { 216 if ((files[i] != null) && !files[i].isDirectory()) { 217 if (files[i].exists()) { 218 String fileName = files[i].getName(); 219 int dateIndex = fileName.lastIndexOf("_d2") + 2; 220 int timeIndexStart = fileName.lastIndexOf("_t") + 2; 221 int timeIndexEnd = fileName.lastIndexOf("_e") + 2; 222 String dateStr = fileName.substring(dateIndex, dateIndex + 8); 223 String timeStrStart = fileName.substring(timeIndexStart, timeIndexStart + 7); 224 String timeStrEnd = fileName.substring(timeIndexEnd, timeIndexEnd + 7); 225 // sanity check on file name lengths 226 int fnLen = fileName.length(); 227 if ((dateIndex > fnLen) || (timeIndexStart > fnLen) || (timeIndexEnd > fnLen)) { 228 logger.warn("unexpected file name length for: " + fileName); 229 testResult = false; 230 break; 231 } 232 // pull start and end time out of file name 233 Date dS = null; 234 Date dE = null; 235 try { 236 dS = sdf.parse(dateStr + timeStrStart); 237 dE = sdf.parse(dateStr + timeStrEnd); 238 } catch (ParseException e) { 239 logger.error("Not recognized as valid Suomi NPP file name: " + fileName); 240 testResult = false; 241 break; 242 } 243 long curTime = dS.getTime(); 244 long endTime = dE.getTime(); 245 // only check current with previous 246 if (prvTime > 0) { 247 // make sure time diff does not exceed allowed threshold 248 // consecutive granules should be less than 1 second apart 249 if ((curTime - prvTime) > CONSECUTIVE_GRANULE_TIME_GAP_MS) { 250 testResult = false; 251 break; 252 } 253 } 254 prvTime = endTime; 255 } 256 } 257 } 258 return testResult; 259 } 260 261 /** 262 * Convert the given array of File objects 263 * to an array of String file names. Only 264 * include the files that actually exist. 265 * 266 * @param files Selected files 267 * @return Selected files as Strings 268 */ 269 270 protected String[] getFileNames(File[] files) { 271 if (files == null) { 272 return (String[]) null; 273 } 274 Vector<String> v = new Vector<String>(); 275 String fileNotExistsError = ""; 276 277 // NOTE: If multiple files are selected, then missing files 278 // are not in the files array. If one file is selected and 279 // it is not there, then it is in the array and file.exists() 280 // is false 281 for (int i = 0; i < files.length; i++) { 282 if ((files[i] != null) && !files[i].isDirectory()) { 283 if ( !files[i].exists()) { 284 fileNotExistsError += "File does not exist: " + files[i] + "\n"; 285 } else { 286 v.add(files[i].toString()); 287 } 288 } 289 } 290 291 if (fileNotExistsError.length() > 0) { 292 userMessage(fileNotExistsError); 293 return null; 294 } 295 296 return v.isEmpty() 297 ? null 298 : StringUtil.listToStringArray(v); 299 } 300 301 /** 302 * Get the bottom panel for the chooser 303 * @return the bottom panel 304 */ 305 306 protected JPanel getBottomPanel() { 307 // No bottom panel at present 308 return null; 309 } 310 311 /** 312 * Get the center panel for the chooser 313 * @return the center panel 314 */ 315 316 protected JPanel getCenterPanel() { 317 JPanel centerPanel = super.getCenterPanel(); 318 319 fileChooser.setAcceptAllFileFilterUsed(false); 320 fileChooser.setFileFilter(new SuomiNPPFilter()); 321 322 return centerPanel; 323 } 324 325 }