001/* 002 * $Id: NPPChooser.java,v 1.10 2011/03/24 16:06:31 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 */ 030package edu.wisc.ssec.mcidasv.chooser; 031 032import edu.wisc.ssec.mcidasv.data.hydra.JPSSUtilities; 033 034import java.awt.Component; 035import java.awt.Container; 036 037import java.io.File; 038import java.io.IOException; 039 040import java.util.ArrayList; 041import java.util.StringTokenizer; 042import java.util.Vector; 043 044import javax.swing.JFileChooser; 045import javax.swing.JLabel; 046import javax.swing.JPanel; 047import javax.swing.filechooser.FileFilter; 048 049import org.slf4j.Logger; 050import org.slf4j.LoggerFactory; 051 052import ucar.nc2.NetcdfFile; 053 054import ucar.unidata.idv.chooser.IdvChooserManager; 055import ucar.unidata.util.StringUtil; 056 057public class NPPChooser extends FileChooser { 058 059 private static final String PRODUCT_SEPARATOR = "-"; 060 private static final String FIELD_SEPARATOR = "_"; 061 062 private static final long serialVersionUID = 1L; 063 private static final Logger logger = LoggerFactory.getLogger(NPPChooser.class); 064 065 private NPPFilter nppf = null; 066 067 /** 068 * Create the chooser with the given manager and xml 069 * 070 * @param mgr The manager 071 * @param root The xml 072 * 073 */ 074 075 public NPPChooser(IdvChooserManager mgr, org.w3c.dom.Element root) { 076 super(mgr, root); 077 } 078 079 /** 080 * Make the file chooser 081 * 082 * @param path the initial path 083 * 084 * @return the file chooser 085 */ 086 087 protected JFileChooser doMakeFileChooser(String path) { 088 return new NPPFileChooser(path); 089 } 090 091 /** 092 * Is this an NPP Product Data file? 093 * 094 * @param f name of file to test 095 * @return 096 */ 097 098 private boolean isNPPFile(File f) { 099 100 // This regular expression matches an NPP Data Product as defined by the 101 // spec in CDFCB-X Volume 1, Page 21 102 String nppRegex = 103 // Product Id, Multiple (ex: VSSTO-GATMO-VSLTO) 104 "(\\w\\w\\w\\w\\w-)*" + 105 // Product Id, Single (ex: VSSTO) 106 "\\w\\w\\w\\w\\w" + FIELD_SEPARATOR + 107 // Spacecraft Id (ex: npp) 108 "\\w\\w\\w" + FIELD_SEPARATOR + 109 // Data Start Date (ex: dYYYYMMDD) 110 "d20[0-3]\\d[0-1]\\d[0-3]\\d" + FIELD_SEPARATOR + 111 // Data Start Time (ex: tHHMMSSS) 112 "t[0-2]\\d[0-5]\\d[0-6]\\d\\d" + FIELD_SEPARATOR + 113 // Data Stop Time (ex: eHHMMSSS) 114 "e[0-2]\\d[0-5]\\d[0-6]\\d\\d" + FIELD_SEPARATOR + 115 // Orbit Number (ex: b00015) 116 "b\\d\\d\\d\\d\\d" + FIELD_SEPARATOR + 117 // Creation Date (ex: cYYYYMMDDHHMMSSSSSSSS) 118 "c20[0-3]\\d[0-1]\\d[0-3]\\d[0-2]\\d[0-5]\\d[0-6]\\d\\d\\d\\d\\d\\d\\d" + FIELD_SEPARATOR + 119 // Origin (ex: navo) 120 "\\w\\w\\w\\w" + FIELD_SEPARATOR + 121 // Domain (ex: ops) 122 "\\w\\w\\w" + 123 // HDF5 suffix 124 ".h5"; 125 126 boolean isNPP = false; 127 128 String fileNameRelative = f.getName(); 129 String fileNameAbsolute = f.getParent() + File.separatorChar + f.getName(); 130 logger.trace("examining filename: " + fileNameRelative); 131 132 // null or empty filename 133 if ((fileNameRelative == null) || (fileNameRelative.equals(""))) return isNPP; 134 135 // see if relative filename matches the NPP regular expression 136 if (fileNameRelative.matches(nppRegex)) { 137 isNPP = true; 138 logger.trace(fileNameRelative + " matches NPP regex"); 139 // don't go any further if file does not match NPP data product regex 140 } else { 141 return isNPP; 142 } 143 144 // make sure a geolocation file is present if it does look like a valid NPP data file! 145 146 // if a geo dataset is embedded in a multi-product file, we can call it good without 147 // having to open any files. Just look for a geo product id in the filename. 148 // HOWEVER - if it's a single-product GEO-only file, disqualify that 149 String prodStr = fileNameRelative.substring(0, fileNameRelative.indexOf(FIELD_SEPARATOR)); 150 StringTokenizer st = new StringTokenizer(prodStr, PRODUCT_SEPARATOR); 151 int numTokens = st.countTokens(); 152 logger.trace("check for embedded GEO, tokenizing: " + prodStr); 153 while (st.hasMoreTokens()) { 154 String singleProd = st.nextToken(); 155 logger.trace("Next token: " + singleProd); 156 for (int i = 0; i < JPSSUtilities.geoProductIDs.length; i++) { 157 if (singleProd.equals(JPSSUtilities.geoProductIDs[i])) { 158 logger.trace("Found embedded GEO: " + singleProd); 159 // if it's a single-product file, disqualify this as a GEO-only file! 160 if (numTokens == 1) { 161 return false; 162 } else { 163 if (numTokens > 1) { 164 return true; 165 } 166 } 167 } 168 } 169 } 170 171 // looks like a standalone product - will have to look for separate geo file 172 // first, create the corresponding GEO loc file name 173 String geoProductID = null; 174 175 boolean noGeo = false; 176 NetcdfFile ncfile = null; 177 try { 178 logger.info("Trying to open file: " + fileNameAbsolute); 179 ncfile = NetcdfFile.open(fileNameAbsolute); 180 ucar.nc2.Attribute a = ncfile.findGlobalAttribute("N_GEO_Ref"); 181 // if no GEO attribute, we can't visualize this NPP data file, don't include it 182 if (a == null) { 183 noGeo = true; 184 } else { 185 logger.info("Value of GEO global attribute: " + a.getStringValue()); 186 // in the newest data from GRAVITE server, attribute is entire file name 187 // if this is detected, no translation/mapping needed 188 if (a.getStringValue().endsWith("h5")) { 189 geoProductID = a.getStringValue(); 190 } else { 191 geoProductID = JPSSUtilities.mapGeoRefToProductID(a.getStringValue()); 192 // we may not have a mapping for every product 193 if (geoProductID == null) noGeo = true; 194 } 195 logger.info("Value of corresponding Product ID: " + geoProductID); 196 } 197 } catch (Exception e) { 198 logger.error("Exception during open file: " + fileNameAbsolute); 199 e.printStackTrace(); 200 } finally { 201 try { 202 ncfile.close(); 203 } catch (IOException ioe) { 204 ioe.printStackTrace(); 205 } 206 } 207 208 // if no geolocation global attribute found, skip this file 209 if (noGeo) { 210 isNPP = false; 211 } else { 212 213 // ok, we know what the geo file is supposed to be, but is it present in this directory? 214 String geoFilename = fileNameAbsolute.substring(0, fileNameAbsolute.lastIndexOf(File.separatorChar) + 1); 215 // check if we have the whole file name or just the prefix 216 if (geoProductID.endsWith("h5")) { 217 geoFilename += geoProductID; 218 } else { 219 geoFilename += geoProductID; 220 geoFilename += fileNameAbsolute.substring(fileNameAbsolute.lastIndexOf(File.separatorChar) + 6); 221 } 222 File geoFile = new File(geoFilename); 223 224 if (geoFile.exists()) { 225 logger.info("GEO file FOUND: " + geoFilename); 226 isNPP = true; 227 } else { 228 logger.info("GEO file NOT found: " + geoFilename); 229 isNPP = false; 230 } 231 232 } 233 234 return isNPP; 235 } 236 237 238 /* NPPFilter */ 239 public class NPPFilter extends FileFilter { 240 241 // maintain an array of "seen" patterns, so we only identify data 242 // once for a particular type and time (instead of for each segment). 243 ArrayList<String> seenPatterns = new ArrayList<String>(); 244 245 String extraFilter = ""; 246 247 public NPPFilter(String extraFilter) { 248 super(); 249 if (extraFilter != null) { 250 this.extraFilter = extraFilter; 251 } 252 } 253 254 // Accept all directories and all NPP files. 255 public boolean accept(File f) { 256 if (f.isDirectory()) { 257 return true; 258 } 259 260 if (isNPPFile(f)) { 261 return true; 262 } else { 263 return false; 264 } 265 266 } 267 268 // The description of this filter 269 public String getDescription() { 270 return "NPP Data"; 271 } 272 273 // change the additional filter string 274 public void setExtraFilter(String newFilter) { 275 if (newFilter != null) { 276 extraFilter = newFilter; 277 seenPatterns.clear(); 278 } 279 } 280 281 } 282 283 /** 284 * An extension of JFileChooser 285 * 286 * @author Tommy Jasmin 287 */ 288 289 public class NPPFileChooser extends JFileChooser { 290 291 /** 292 * default for serializable class 293 */ 294 private static final long serialVersionUID = 1L; 295 296 /** 297 * Create the file chooser 298 * 299 * @param path the initial path 300 */ 301 public NPPFileChooser(String path) { 302 super(path); 303 setControlButtonsAreShown(false); 304 setMultiSelectionEnabled(true); 305 setAcceptAllFileFilterUsed(false); 306 processChildren(this); 307 } 308 309 private void processChildren(Container c) { 310 Component [] components = c.getComponents(); 311 if (components != null) { 312 // loop through all components, looking for the JLabel children of 313 // components we want to remove 314 for (int i = 0; i < components.length; i++) { 315 if (components[i] instanceof JLabel) { 316 String text = ((JLabel) components[i]).getText(); 317 if (text.equals("File Name:")) { 318 hideChildren((Container) components[i].getParent()); 319 continue; 320 } 321 if (text.equals("Files of Type:")) { 322 hideChildren((Container) components[i].getParent()); 323 continue; 324 } 325 } 326 // now check this component for any children 327 processChildren((Container) components[i]); 328 } 329 } 330 } 331 332 private void hideChildren(Container c) { 333 Component [] components = c.getComponents(); 334 for (int i = 0; i < components.length; i++) { 335 components[i].setVisible(false); 336 } 337 c.setVisible(false); 338 } 339 340 /** 341 * Approve the selection 342 */ 343 public void approveSelection() { 344 NPPChooser.this.doLoad(); 345 } 346 347 /** 348 * Cancel the selection 349 */ 350 public void cancelSelection() { 351 closeChooser(); 352 } 353 354 /** 355 * Set the selected files 356 * 357 * @param selectedFiles the selected files 358 */ 359 public void setSelectedFiles(File[] selectedFiles) { 360 super.setSelectedFiles(selectedFiles); 361 setHaveData( !((selectedFiles == null) || (selectedFiles.length == 0))); 362 } 363 } 364 365 /** 366 * Handle the selection of the set of files 367 * 368 * @param files The files the user chose 369 * @param directory The directory they chose them from 370 * @return True if the file was successful 371 * @throws Exception 372 */ 373 374 protected boolean selectFilesInner(File[] files, File directory) 375 throws Exception { 376 if ((files == null) || (files.length == 0)) { 377 userMessage("Please select a file"); 378 return false; 379 } 380 381 return super.selectFilesInner(files, directory); 382 } 383 384 /** 385 * Convert the given array of File objects 386 * to an array of String file names. Only 387 * include the files that actually exist. 388 * 389 * @param files Selected files 390 * @return Selected files as Strings 391 */ 392 393 protected String[] getFileNames(File[] files) { 394 if (files == null) { 395 return (String[]) null; 396 } 397 Vector<String> v = new Vector<String>(); 398 String fileNotExistsError = ""; 399 400 // NOTE: If multiple files are selected, then missing files 401 // are not in the files array. If one file is selected and 402 // it is not there, then it is in the array and file.exists() 403 // is false 404 for (int i = 0; i < files.length; i++) { 405 if ((files[i] != null) && !files[i].isDirectory()) { 406 if ( !files[i].exists()) { 407 fileNotExistsError += "File does not exist: " + files[i] + "\n"; 408 } else { 409 v.add(files[i].toString()); 410 } 411 } 412 } 413 414 if (fileNotExistsError.length() > 0) { 415 userMessage(fileNotExistsError); 416 return null; 417 } 418 419 return v.isEmpty() 420 ? null 421 : StringUtil.listToStringArray(v); 422 } 423 424 /** 425 * Get the bottom panel for the chooser 426 * @return the bottom panel 427 */ 428 429 protected JPanel getBottomPanel() { 430 // No bottom panel at present 431 return null; 432 } 433 434 /** 435 * Get the center panel for the chooser 436 * @return the center panel 437 */ 438 439 protected JPanel getCenterPanel() { 440 JPanel centerPanel = super.getCenterPanel(); 441 442 fileChooser.setAcceptAllFileFilterUsed(false); 443 444 String extraFilter = ""; 445 nppf = new NPPFilter(extraFilter); 446 fileChooser.setFileFilter(nppf); 447 448 return centerPanel; 449 } 450 451}