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 package edu.wisc.ssec.mcidasv.chooser; 029 030 import java.awt.BorderLayout; 031 import java.io.File; 032 033 import java.text.ParseException; 034 import java.text.SimpleDateFormat; 035 import java.util.Date; 036 import java.util.Vector; 037 038 import javax.swing.JFileChooser; 039 import javax.swing.JOptionPane; 040 import javax.swing.JPanel; 041 import javax.swing.filechooser.FileFilter; 042 043 import org.slf4j.Logger; 044 import org.slf4j.LoggerFactory; 045 046 import ucar.unidata.idv.chooser.IdvChooserManager; 047 import ucar.unidata.util.StringUtil; 048 049 public class SuomiNPPChooser extends FileChooser { 050 051 private static final long serialVersionUID = 1L; 052 private static final Logger logger = LoggerFactory.getLogger(SuomiNPPChooser.class); 053 private static final long CONSECUTIVE_GRANULE_MAX_GAP_MS = 60000; 054 055 // date formatter for converting Suomi NPP day/time from file name for consecutive granule check 056 private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmSSS"); 057 058 /** 059 * Create the chooser with the given manager and xml 060 * 061 * @param mgr The manager 062 * @param root The xml 063 * 064 */ 065 066 public SuomiNPPChooser(IdvChooserManager mgr, org.w3c.dom.Element root) { 067 super(mgr, root); 068 } 069 070 /** 071 * Make the file chooser 072 * 073 * @param path the initial path 074 * 075 * @return the file chooser 076 */ 077 078 protected JFileChooser doMakeFileChooser(String path) { 079 if (fileChooser == null) { 080 logger.debug("Creating Suomi NPP File Chooser..."); 081 fileChooser = new SuomiNPPFileChooser(path, this); 082 } else { 083 logger.debug("2nd call to doMakeFileChooser, why?"); 084 } 085 return fileChooser; 086 } 087 088 /** 089 * Handle the selection of the set of files 090 * 091 * @param files The files the user chose 092 * @param directory The directory they chose them from 093 * @return True if the file was successful 094 * @throws Exception 095 */ 096 097 protected boolean selectFilesInner(File[] files, File directory) 098 throws Exception { 099 if ((files == null) || (files.length == 0)) { 100 userMessage("Please select a file"); 101 return false; 102 } 103 104 // At present, Suomi NPP chooser only allows selecting sets of consecutive granules 105 boolean granulesAreConsecutive = testConsecutiveGranules(files); 106 if (granulesAreConsecutive) { 107 return super.selectFilesInner(files, directory); 108 } else { 109 // throw up a dialog to tell user the problem 110 JOptionPane.showMessageDialog(this, "When selecting multiple granules, they must be consecutive."); 111 } 112 return false; 113 } 114 115 /** 116 * Test whether a set of files are consecutive Suomi NPP granules, 117 * any sensor. 118 * @param files 119 * @return true if consecutive tests pass for all files 120 */ 121 122 private boolean testConsecutiveGranules(File[] files) { 123 boolean testResult = false; 124 if (files == null) return testResult; 125 // compare start time of current granule with end time of previous 126 // difference should be very small - under a second 127 long prvTime = -1; 128 testResult = true; 129 for (int i = 0; i < files.length; i++) { 130 if ((files[i] != null) && !files[i].isDirectory()) { 131 if (files[i].exists()) { 132 String fileName = files[i].getName(); 133 int dateIndex = fileName.lastIndexOf("_d2") + 2; 134 int timeIndexStart = fileName.lastIndexOf("_t") + 2; 135 int timeIndexEnd = fileName.lastIndexOf("_e") + 2; 136 String dateStr = fileName.substring(dateIndex, dateIndex + 8); 137 String timeStrStart = fileName.substring(timeIndexStart, timeIndexStart + 7); 138 String timeStrEnd = fileName.substring(timeIndexEnd, timeIndexEnd + 7); 139 // sanity check on file name lengths 140 int fnLen = fileName.length(); 141 if ((dateIndex > fnLen) || (timeIndexStart > fnLen) || (timeIndexEnd > fnLen)) { 142 logger.warn("unexpected file name length for: " + fileName); 143 testResult = false; 144 break; 145 } 146 // pull start and end time out of file name 147 Date dS = null; 148 Date dE = null; 149 try { 150 dS = sdf.parse(dateStr + timeStrStart); 151 // due to nature of Suomi NPP file name encoding, we need a special 152 // check here - end time CAN roll over to next day, while day part 153 // does not change. if this happens, we tweak the date string 154 String endDateStr = dateStr; 155 String startHour = timeStrStart.substring(0, 2); 156 String endHour = timeStrEnd.substring(0, 2); 157 if ((startHour.equals("23")) && (endHour.equals("00"))) { 158 // temporarily convert date to integer, increment, convert back 159 int tmpDate = Integer.parseInt(dateStr); 160 tmpDate++; 161 endDateStr = "" + tmpDate; 162 logger.info("Granule time spanning days case handled ok..."); 163 } 164 dE = sdf.parse(endDateStr + timeStrEnd); 165 } catch (ParseException e) { 166 logger.error("Not recognized as valid Suomi NPP file name: " + fileName); 167 testResult = false; 168 break; 169 } 170 long curTime = dS.getTime(); 171 long endTime = dE.getTime(); 172 // only check current with previous 173 if (prvTime > 0) { 174 // make sure time diff does not exceed allowed threshold 175 // consecutive granules should be less than 1 minute apart 176 if ((curTime - prvTime) > CONSECUTIVE_GRANULE_MAX_GAP_MS) { 177 testResult = false; 178 break; 179 } 180 } 181 prvTime = endTime; 182 } 183 } 184 } 185 return testResult; 186 } 187 188 /** 189 * Convert the given array of File objects 190 * to an array of String file names. Only 191 * include the files that actually exist. 192 * 193 * @param files Selected files 194 * @return Selected files as Strings 195 */ 196 197 protected String[] getFileNames(File[] files) { 198 if (files == null) { 199 return (String[]) null; 200 } 201 Vector<String> v = new Vector<String>(); 202 String fileNotExistsError = ""; 203 204 // NOTE: If multiple files are selected, then missing files 205 // are not in the files array. If one file is selected and 206 // it is not there, then it is in the array and file.exists() 207 // is false 208 for (int i = 0; i < files.length; i++) { 209 if ((files[i] != null) && !files[i].isDirectory()) { 210 if ( !files[i].exists()) { 211 fileNotExistsError += "File does not exist: " + files[i] + "\n"; 212 } else { 213 v.add(files[i].toString()); 214 } 215 } 216 } 217 218 if (fileNotExistsError.length() > 0) { 219 userMessage(fileNotExistsError); 220 return null; 221 } 222 223 return v.isEmpty() 224 ? null 225 : StringUtil.listToStringArray(v); 226 } 227 228 /** 229 * Get the bottom panel for the chooser 230 * @return the bottom panel 231 */ 232 233 protected JPanel getBottomPanel() { 234 // No bottom panel at present 235 return null; 236 } 237 238 /** 239 * Get the center panel for the chooser 240 * @return the center panel 241 */ 242 243 protected JPanel getCenterPanel() { 244 JPanel centerPanel = super.getCenterPanel(); 245 246 JPanel jp = new JPanel(new BorderLayout()) { 247 public void paint(java.awt.Graphics g) { 248 FileFilter ff = fileChooser.getFileFilter(); 249 if (! (ff instanceof SuomiNPPFilter)) { 250 fileChooser.setAcceptAllFileFilterUsed(false); 251 fileChooser.setFileFilter(new SuomiNPPFilter()); 252 } 253 super.paint(g); 254 } 255 }; 256 jp.add(centerPanel); 257 258 return jp; 259 } 260 261 }