001 /* 002 * $Id: FlatFileChooser.java,v 1.12 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 034 import static javax.swing.GroupLayout.DEFAULT_SIZE; 035 import static javax.swing.GroupLayout.Alignment.BASELINE; 036 import static javax.swing.GroupLayout.Alignment.LEADING; 037 import static javax.swing.GroupLayout.Alignment.TRAILING; 038 import static javax.swing.LayoutStyle.ComponentPlacement.RELATED; 039 import static javax.swing.LayoutStyle.ComponentPlacement.UNRELATED; 040 041 import java.awt.Image; 042 import java.awt.MediaTracker; 043 import java.awt.Toolkit; 044 import java.awt.event.ActionEvent; 045 import java.awt.event.ActionListener; 046 import java.awt.event.FocusEvent; 047 import java.awt.event.FocusListener; 048 import java.io.File; 049 import java.io.FileNotFoundException; 050 import java.io.FileReader; 051 import java.io.InputStream; 052 import java.util.ArrayList; 053 import java.util.Hashtable; 054 import java.util.List; 055 056 import javax.swing.GroupLayout; 057 import javax.swing.JButton; 058 import javax.swing.JCheckBox; 059 import javax.swing.JComboBox; 060 import javax.swing.JComponent; 061 import javax.swing.JFileChooser; 062 import javax.swing.JLabel; 063 import javax.swing.JPanel; 064 import javax.swing.JRadioButton; 065 import javax.swing.JTextField; 066 067 import org.w3c.dom.Element; 068 069 import ucar.unidata.idv.IntegratedDataViewer; 070 import ucar.unidata.idv.chooser.IdvChooser; 071 import ucar.unidata.idv.chooser.IdvChooserManager; 072 import ucar.unidata.util.GuiUtils; 073 import ucar.unidata.util.IOUtil; 074 import ucar.unidata.util.Misc; 075 import ucar.unidata.util.TwoFacedObject; 076 import ucar.unidata.xml.XmlUtil; 077 import visad.util.ImageHelper; 078 import edu.wisc.ssec.mcidasv.Constants; 079 import edu.wisc.ssec.mcidasv.data.AxformInfo; 080 import edu.wisc.ssec.mcidasv.data.EnviInfo; 081 import edu.wisc.ssec.mcidasv.data.HeaderInfo; 082 import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 083 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Position; 084 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Prefer; 085 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.TextColor; 086 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Width; 087 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.IconPanel; 088 089 /** 090 * @author SSEC Development Team 091 */ 092 093 public class FlatFileChooser extends IdvChooser implements Constants { 094 095 /** Set default stride to keep dimensions within this */ 096 private int maxDefDim = 1000; 097 098 // Properties associated with the button selector 099 private File dataFile; 100 private JTextField dataFileText = new JTextField(); 101 private JButton dataFileButton = new JButton(); 102 private JLabel dataFileDescription = new JLabel(); 103 private JLabel textDescription = new JLabel(); 104 105 // Dimensions 106 // elements, lines, bands 107 private JTextField textElements = new JTextField(); 108 private JTextField textLines = new JTextField(); 109 private JTextField textBands = new JTextField(); 110 private JTextField textUnit = new JTextField(); 111 private JTextField textStride = new JTextField(); 112 private JCheckBox checkTranspose = new JCheckBox("Transpose elements/lines"); 113 private List bandNames = new ArrayList(); 114 private List bandFiles = new ArrayList(); 115 116 // Navigation 117 // lat/lon files or bounds 118 private JRadioButton radioLatLonFiles = new JRadioButton("Files", true); 119 private JRadioButton radioLatLonBounds = new JRadioButton("Bounds", false); 120 private File latFile, lonFile; 121 private JLabel textLatFile = new JLabel(); 122 private JButton buttonLatFile = new JButton(); 123 private JLabel textLonFile = new JLabel(); 124 private JButton buttonLonFile = new JButton(); 125 private JPanel panelLatLonFiles = new JPanel(); 126 private JTextField textLatUL = new JTextField(); 127 private JTextField textLonUL = new JTextField(); 128 private JTextField textLatLR = new JTextField(); 129 private JTextField textLonLR = new JTextField(); 130 private JPanel panelLatLonBounds = new JPanel(); 131 private JTextField textLatLonScale = new JTextField(); 132 private JCheckBox checkEastPositive = new JCheckBox("East positive"); 133 134 135 // Properties associated with the data file 136 // bytes/pixel, ASCII delimiter, endianness, interleave, offset, missing 137 private JRadioButton radioBinary = new JRadioButton("Binary", true); 138 private JRadioButton radioASCII = new JRadioButton("ASCII", false); 139 private JRadioButton radioImage = new JRadioButton("Image", false); 140 private JRadioButton radioEndianLittle = new JRadioButton("Little", true); 141 private JRadioButton radioEndianBig = new JRadioButton("Big", false); 142 private JComboBox comboByteFormat = new JComboBox(); 143 private JComboBox comboInterleave = new JComboBox(); 144 private JTextField textOffset = new JTextField(); 145 private JPanel panelBinary = new JPanel(); 146 private JTextField textDelimiter = new JTextField(); 147 private JPanel panelASCII = new JPanel(); 148 private JPanel panelImage = new JPanel(); 149 private JTextField textMissing = new JTextField(); 150 151 private List<TwoFacedObject> listByteFormat = Misc.newList(new TwoFacedObject[] { 152 new TwoFacedObject("1-byte unsigned integer", HeaderInfo.kFormat1ByteUInt), 153 new TwoFacedObject("2-byte signed integer", HeaderInfo.kFormat2ByteSInt), 154 new TwoFacedObject("4-byte signed integer", HeaderInfo.kFormat4ByteSInt), 155 new TwoFacedObject("4-byte float", HeaderInfo.kFormat4ByteFloat), 156 new TwoFacedObject("8-byte double", HeaderInfo.kFormat8ByteDouble), 157 new TwoFacedObject("2x8-byte complex number", HeaderInfo.kFormat2x8Byte), 158 new TwoFacedObject("2-byte unsigned integer", HeaderInfo.kFormat2ByteUInt) 159 }); 160 161 private List<TwoFacedObject> listInterleave = Misc.newList( 162 new TwoFacedObject("Sequential", HeaderInfo.kInterleaveSequential), 163 new TwoFacedObject("By line", HeaderInfo.kInterleaveByLine), 164 new TwoFacedObject("By pixel", HeaderInfo.kInterleaveByPixel)); 165 166 private JLabel statusLabel = new JLabel("Status"); 167 168 /** 169 * Super setStatus() takes a second string to enable "simple" mode 170 * which highlights the required component. We don't really care 171 * about that feature, and we don't want getStatusLabel() to 172 * change the label background color. 173 */ 174 @Override 175 public void setStatus(String statusString, String foo) { 176 if (statusString == null) 177 statusString = ""; 178 statusLabel.setText(statusString); 179 } 180 181 /** 182 * Get a handle on the IDV 183 */ 184 protected IntegratedDataViewer idv = getIdv(); 185 186 /** 187 * Create the FileChooser, passing in the manager and the xml element 188 * from choosers.xml 189 * 190 * @param mgr The manager 191 * @param root The xml root 192 * 193 */ 194 public FlatFileChooser(IdvChooserManager mgr, Element root) { 195 super(mgr, root); 196 197 loadButton = McVGuiUtils.makeImageTextButton(ICON_ACCEPT_SMALL, getLoadCommandName()); 198 loadButton.setActionCommand(getLoadCommandName()); 199 loadButton.addActionListener(this); 200 201 dataFileButton = McVGuiUtils.makeImageButton(ICON_OPEN, "Open file"); 202 dataFileButton.addActionListener(new ActionListener(){ 203 public void actionPerformed(ActionEvent e) { 204 dataFile = getDataFile(dataFile); 205 if (dataFile!=null) { 206 dataFileText.setText(dataFile.getAbsolutePath()); 207 inspectDataFile(dataFile); 208 } 209 } 210 }); 211 dataFileText.addActionListener(new ActionListener(){ 212 public void actionPerformed(ActionEvent e) { 213 dataFile = new File(dataFileText.getText()); 214 inspectDataFile(dataFile); 215 } 216 }); 217 dataFileText.addFocusListener(new FocusListener() { 218 public void focusGained(FocusEvent e) {} 219 public void focusLost(FocusEvent e) { 220 dataFile = new File(dataFileText.getText()); 221 inspectDataFile(dataFile); 222 } 223 }); 224 225 radioLatLonFiles.addActionListener(new ActionListener(){ 226 public void actionPerformed(ActionEvent e) { 227 checkSetLatLon(); 228 } 229 }); 230 radioLatLonBounds.addActionListener(new ActionListener(){ 231 public void actionPerformed(ActionEvent e) { 232 checkSetLatLon(); 233 } 234 }); 235 236 buttonLatFile = McVGuiUtils.makeImageButton(ICON_OPEN, "Select latitude file"); 237 buttonLatFile.addActionListener(new ActionListener(){ 238 public void actionPerformed(ActionEvent e) { 239 latFile = getDataFile(latFile); 240 if (latFile!=null) 241 textLatFile.setText(latFile.getName()); 242 } 243 }); 244 buttonLonFile = McVGuiUtils.makeImageButton(ICON_OPEN, "Select longitude file"); 245 buttonLonFile.addActionListener(new ActionListener(){ 246 public void actionPerformed(ActionEvent e) { 247 lonFile = getDataFile(lonFile); 248 if (lonFile!=null) 249 textLonFile.setText(lonFile.getName()); 250 } 251 }); 252 GuiUtils.buttonGroup(radioLatLonFiles, radioLatLonBounds); 253 254 radioBinary.addActionListener(new ActionListener(){ 255 public void actionPerformed(ActionEvent e) { 256 checkSetBinaryASCIIImage(); 257 } 258 }); 259 radioASCII.addActionListener(new ActionListener(){ 260 public void actionPerformed(ActionEvent e) { 261 checkSetBinaryASCIIImage(); 262 } 263 }); 264 radioImage.addActionListener(new ActionListener(){ 265 public void actionPerformed(ActionEvent e) { 266 checkSetBinaryASCIIImage(); 267 } 268 }); 269 GuiUtils.buttonGroup(radioBinary, radioASCII, radioImage); 270 GuiUtils.buttonGroup(radioEndianLittle, radioEndianBig); 271 272 GuiUtils.setListData(comboByteFormat, listByteFormat); 273 GuiUtils.setListData(comboInterleave, listInterleave); 274 275 setHaveData(false); 276 } 277 278 /** 279 * enable/disable widgets for navigation 280 */ 281 private void checkSetLatLon() { 282 boolean isFile = radioLatLonFiles.isSelected(); 283 GuiUtils.enableTree(panelLatLonFiles, isFile); 284 GuiUtils.enableTree(panelLatLonBounds, !isFile); 285 } 286 287 /** 288 * enable/disable widgets for binary/ASCII 289 */ 290 private void checkSetBinaryASCIIImage() { 291 GuiUtils.enableTree(panelBinary, radioBinary.isSelected()); 292 GuiUtils.enableTree(panelASCII, radioASCII.isSelected()); 293 GuiUtils.enableTree(panelImage, radioImage.isSelected()); 294 } 295 296 /** 297 * Set whether the user has made a selection that contains data. 298 * 299 * @param have true to set the haveData property. Enables the 300 * loading button 301 */ 302 public void setHaveData(boolean have) { 303 super.setHaveData(have); 304 updateStatus(); 305 } 306 307 /** 308 * Set the status message appropriately 309 */ 310 protected void updateStatus() { 311 super.updateStatus(); 312 checkSetLatLon(); 313 checkSetBinaryASCIIImage(); 314 if(!getHaveData()) { 315 setStatus("Select a file"); 316 } 317 } 318 319 /** 320 * Inspect the selected data file 321 * Determine if it is a known header file type 322 * 323 * @param thisFile 324 * @throws FileNotFoundException 325 */ 326 private void inspectDataFile(File thisFile) { 327 if (thisFile == null || thisFile.getName()=="") { 328 dataFileDescription.setText(""); 329 setHaveData(false); 330 return; 331 } 332 if (!thisFile.exists()) { 333 dataFileDescription.setText("File does not exist"); 334 setHaveData(false); 335 return; 336 } 337 try { 338 FileReader fr = new FileReader(thisFile); 339 char first80c[] = new char[80]; 340 fr.read(first80c, 0, 80); 341 fr.close(); 342 String first80 = new String(first80c); 343 clearValues(); 344 boolean doStride = false; 345 if (IOUtil.hasSuffix(thisFile.getName(), ".gif") || 346 IOUtil.hasSuffix(thisFile.getName(), ".jpg") || 347 IOUtil.hasSuffix(thisFile.getName(), ".png")) { 348 dataFileDescription.setText("Image file"); 349 processImageFile(thisFile); 350 } 351 else if (IOUtil.hasSuffix(thisFile.getName(), ".xml") || 352 IOUtil.hasSuffix(thisFile.getName(), ".ximg")) { 353 dataFileDescription.setText("XML image header file"); 354 processXmlHeaderFile(thisFile); 355 } 356 else if (first80.indexOf(" Space Science & Engineering Center") >= 0) { 357 dataFileDescription.setText("McIDAS-X AXFORM header file"); 358 processAxformHeaderFile(thisFile); 359 doStride = true; 360 } 361 else if (first80.indexOf("ENVI") >= 0) { 362 dataFileDescription.setText("ENVI header file"); 363 processEnviHeaderFile(thisFile); 364 doStride = true; 365 } 366 else { 367 dataFileDescription.setText("Binary, ASCII or Image data"); 368 processGenericFile(thisFile); 369 doStride = true; 370 } 371 372 // Default the stride 373 int newStride = 1; 374 if (doStride) { 375 String textLinesText = textLines.getText(); 376 String textElementsText = textElements.getText(); 377 if (!(textLinesText.equalsIgnoreCase("") || textElementsText.equalsIgnoreCase(""))) { 378 int myLines = Integer.parseInt(textLinesText); 379 int myElements = Integer.parseInt(textElementsText); 380 if (myLines > maxDefDim || myElements > maxDefDim) { 381 newStride = Math.max((int)Math.ceil((float)myLines/(float)maxDefDim), (int)Math.ceil((float)myElements/(float)maxDefDim)); 382 } 383 } 384 } 385 textStride.setText(Integer.toString(newStride)); 386 387 setHaveData(true); 388 } 389 catch (Exception e) { 390 e.printStackTrace(); 391 } 392 } 393 394 /** 395 * Special processing for a known data type 396 * This deals specifically with AXFORM header files 397 */ 398 private void processAxformHeaderFile(File thisFile) { 399 try { 400 AxformInfo axformInfo = new AxformInfo(thisFile); 401 402 // Set the properties in the GUI 403 textDescription.setText(axformInfo.getParameter(HeaderInfo.DESCRIPTION, "")); 404 textElements.setText((axformInfo.getParameter(HeaderInfo.ELEMENTS, 0)).toString()); 405 textLines.setText((axformInfo.getParameter(HeaderInfo.LINES, 0)).toString()); 406 textUnit.setText((axformInfo.getParameter(HeaderInfo.UNIT, "")).toString()); 407 bandNames = (List)axformInfo.getParameter(HeaderInfo.BANDNAMES, new ArrayList()); 408 bandFiles = (List)axformInfo.getParameter(HeaderInfo.BANDFILES, new ArrayList()); 409 textBands.setText(Integer.toString(bandNames.size())); 410 textOffset.setText((axformInfo.getParameter(HeaderInfo.OFFSET, 0)).toString()); 411 textMissing.setText((axformInfo.getParameter(HeaderInfo.MISSINGVALUE, (float)0)).toString()); 412 413 Integer dataType = (Integer)axformInfo.getParameter(HeaderInfo.DATATYPE, HeaderInfo.kFormatUnknown); 414 Boolean bigEndian = (Boolean)axformInfo.getParameter(HeaderInfo.BIGENDIAN, false); 415 if (dataType==HeaderInfo.kFormatASCII) { 416 radioASCII.setSelected(true); 417 } 418 else if (dataType==HeaderInfo.kFormatImage) { 419 radioImage.setSelected(true); 420 } 421 else { 422 radioBinary.setSelected(true); 423 TwoFacedObject tfo = TwoFacedObject.findId(dataType.intValue(), listByteFormat); 424 if (tfo!=null) 425 comboByteFormat.setSelectedItem(tfo); 426 tfo = TwoFacedObject.findId(HeaderInfo.kInterleaveSequential, listInterleave); 427 if (tfo!=null) 428 comboInterleave.setSelectedItem(tfo); 429 } 430 431 radioEndianLittle.setSelected(!bigEndian.booleanValue()); 432 radioEndianBig.setSelected(bigEndian.booleanValue()); 433 434 List latlonFiles = axformInfo.getParameter(HeaderInfo.NAVFILES, new ArrayList()); 435 if (latlonFiles.size() == 2) { 436 latFile = new File((String)latlonFiles.get(0)); 437 lonFile = new File((String)latlonFiles.get(1)); 438 } 439 440 if (latFile==null || lonFile==null) { 441 radioLatLonBounds.setSelected(true); 442 } 443 else { 444 textLatFile.setText(latFile.getName()); 445 textLonFile.setText(lonFile.getName()); 446 radioLatLonFiles.setSelected(true); 447 } 448 449 textLatLonScale.setText("100"); 450 checkEastPositive.setSelected(true); 451 452 } 453 catch (Exception e) { 454 e.printStackTrace(); 455 } 456 } 457 458 /** 459 * Special processing for a known data type 460 * This deals specifically with ENVI header files 461 */ 462 private void processEnviHeaderFile(File thisFile) { 463 try { 464 EnviInfo enviInfo = new EnviInfo(thisFile); 465 466 // Set the properties in the GUI 467 textDescription.setText(enviInfo.getParameter(HeaderInfo.DESCRIPTION, "")); 468 textElements.setText((enviInfo.getParameter(HeaderInfo.ELEMENTS, 0)).toString()); 469 textLines.setText((enviInfo.getParameter(HeaderInfo.LINES, 0)).toString()); 470 textUnit.setText((enviInfo.getParameter(HeaderInfo.UNIT, "")).toString()); 471 bandNames = (List)enviInfo.getParameter(HeaderInfo.BANDNAMES, new ArrayList()); 472 bandFiles = (List)enviInfo.getParameter(HeaderInfo.BANDFILES, new ArrayList()); 473 textBands.setText(Integer.toString(bandNames.size())); 474 textOffset.setText((enviInfo.getParameter(HeaderInfo.OFFSET, 0)).toString()); 475 textMissing.setText((enviInfo.getParameter(HeaderInfo.MISSINGVALUE, (float)0)).toString()); 476 477 Integer dataType = (Integer)enviInfo.getParameter(HeaderInfo.DATATYPE, HeaderInfo.kFormatUnknown); 478 String interleaveType = (enviInfo.getParameter(HeaderInfo.INTERLEAVE, HeaderInfo.kInterleaveSequential)).toString(); 479 Boolean bigEndian = (Boolean)enviInfo.getParameter(HeaderInfo.BIGENDIAN, false); 480 radioBinary.setSelected(true); 481 TwoFacedObject tfo = TwoFacedObject.findId(dataType.intValue(), listByteFormat); 482 if (tfo!=null) 483 comboByteFormat.setSelectedItem(tfo); 484 tfo = TwoFacedObject.findId(interleaveType, listInterleave); 485 if (tfo!=null) 486 comboInterleave.setSelectedItem(tfo); 487 488 radioEndianLittle.setSelected(!bigEndian.booleanValue()); 489 radioEndianBig.setSelected(bigEndian.booleanValue()); 490 491 // Look for a geo.hdr file that contains Latitude and Longitude bands 492 String parent = thisFile.getParent(); 493 if (parent==null) parent="."; 494 String navFile = thisFile.getName().replace(".hdr", ""); 495 int lastDot = navFile.lastIndexOf("."); 496 if (lastDot >= 0) { 497 navFile = navFile.substring(0, lastDot) + ".geo.hdr"; 498 } 499 navFile = parent + "/" + navFile; 500 EnviInfo navInfo = new EnviInfo(navFile); 501 if (navInfo.isNavHeader()) { 502 latFile = new File(navFile); 503 lonFile = new File(navFile); 504 } 505 506 if (latFile==null || lonFile==null) { 507 radioLatLonBounds.setSelected(true); 508 } 509 else { 510 textLatFile.setText(latFile.getName()); 511 textLonFile.setText(lonFile.getName()); 512 radioLatLonFiles.setSelected(true); 513 } 514 515 textLatLonScale.setText("1"); 516 checkEastPositive.setSelected(false); 517 518 } 519 catch (Exception e) { 520 e.printStackTrace(); 521 } 522 } 523 524 /** 525 * Special processing for a known data type 526 * This deals specifically with XML header files 527 */ 528 private void processXmlHeaderFile(File thisFile) { 529 try { 530 531 String description = ""; 532 int lines = 0; 533 int elements = 0; 534 float missingVal = -1; 535 536 bandFiles = new ArrayList(); 537 bandNames = new ArrayList(); 538 539 Element root = XmlUtil.getRoot(thisFile.getAbsolutePath(), getClass()); 540 if (!root.getTagName().equals("image")) { 541 processGenericFile(thisFile); 542 return; 543 } 544 545 description = XmlUtil.getAttribute(root, "name", (String) null); 546 String url = ""; 547 if (XmlUtil.hasAttribute(root, "url")) { 548 url = XmlUtil.getAttribute(root, "url"); 549 if (description == "") { 550 description = url; 551 } 552 String parent = thisFile.getParent(); 553 if (parent==null) parent="."; 554 url = parent + "/" + url; 555 } 556 else { 557 processGenericFile(thisFile); 558 return; 559 } 560 if (XmlUtil.hasAttribute(root, "ullat")) { 561 radioLatLonBounds.setSelected(true); 562 textLatUL.setText(XmlUtil.getAttribute(root, "ullat")); 563 } 564 if (XmlUtil.hasAttribute(root, "ullon")) { 565 radioLatLonBounds.setSelected(true); 566 textLonUL.setText(XmlUtil.getAttribute(root, "ullon")); 567 } 568 if (XmlUtil.hasAttribute(root, "lrlat")) { 569 radioLatLonBounds.setSelected(true); 570 textLatLR.setText(XmlUtil.getAttribute(root, "lrlat")); 571 } 572 if (XmlUtil.hasAttribute(root, "lrlon")) { 573 radioLatLonBounds.setSelected(true); 574 textLonLR.setText(XmlUtil.getAttribute(root, "lrlon")); 575 } 576 577 // Try to read the referenced image to get lines and elements 578 setStatus("Loading image"); 579 InputStream is = null; 580 is = IOUtil.getInputStream(url, getClass()); 581 byte[] imageContent = IOUtil.readBytes(is); 582 Image image = Toolkit.getDefaultToolkit().createImage(imageContent); 583 MediaTracker tracker = new MediaTracker(this); 584 tracker.addImage(image, 0); 585 try { 586 tracker.waitForAll(); 587 } 588 catch(InterruptedException e) {} 589 ImageHelper ih = new ImageHelper(); 590 image.getWidth(ih); 591 if (ih.badImage) { 592 throw new IllegalStateException("Bad image: " + url); 593 } 594 elements = image.getWidth(ih); 595 lines = image.getHeight(ih); 596 597 // Bands 598 bandFiles.add(url); 599 bandNames.add("XML image file"); 600 601 // Set the properties in the GUI 602 textDescription.setText(description); 603 textElements.setText(Integer.toString(elements)); 604 textLines.setText(Integer.toString(lines)); 605 textBands.setText(Integer.toString(bandNames.size())); 606 607 radioImage.setSelected(true); 608 textMissing.setText(Float.toString(missingVal)); 609 610 textLatLonScale.setText("1"); 611 checkEastPositive.setSelected(false); 612 613 } 614 catch (Exception e) { 615 e.printStackTrace(); 616 } 617 } 618 619 /** 620 * Special processing for a known data type 621 * This deals specifically with XML header files 622 */ 623 private void processImageFile(File thisFile) { 624 try { 625 626 String description = ""; 627 int lines = 0; 628 int elements = 0; 629 float missingVal = -1; 630 631 bandFiles = new ArrayList(); 632 bandNames = new ArrayList(); 633 634 description = thisFile.getName(); 635 String url = thisFile.getAbsolutePath(); 636 637 // Try to read the referenced image to get lines and elements 638 setStatus("Loading image"); 639 InputStream is = null; 640 is = IOUtil.getInputStream(url, getClass()); 641 byte[] imageContent = IOUtil.readBytes(is); 642 Image image = Toolkit.getDefaultToolkit().createImage(imageContent); 643 MediaTracker tracker = new MediaTracker(this); 644 tracker.addImage(image, 0); 645 try { 646 tracker.waitForAll(); 647 } 648 catch(InterruptedException e) {} 649 ImageHelper ih = new ImageHelper(); 650 image.getWidth(ih); 651 if (ih.badImage) { 652 throw new IllegalStateException("Bad image: " + url); 653 } 654 elements = image.getWidth(ih); 655 lines = image.getHeight(ih); 656 657 // Bands 658 bandFiles.add(url); 659 bandNames.add("Image file"); 660 661 // Set the properties in the GUI 662 textDescription.setText(description); 663 textElements.setText(Integer.toString(elements)); 664 textLines.setText(Integer.toString(lines)); 665 textBands.setText(Integer.toString(bandNames.size())); 666 667 radioImage.setSelected(true); 668 textMissing.setText(Float.toString(missingVal)); 669 670 textLatLonScale.setText("1"); 671 checkEastPositive.setSelected(false); 672 673 } 674 catch (Exception e) { 675 e.printStackTrace(); 676 } 677 } 678 679 /** 680 * Special processing for an unknown data type 681 * Can we glean anything about the file by inspecting it more? 682 */ 683 private void processGenericFile(File thisFile) { 684 685 clearValues(); 686 687 // Set appropriate defaults 688 // Bands 689 bandFiles.add(thisFile.getAbsolutePath()); 690 bandNames.add("Flat data"); 691 692 // Set the properties in the GUI 693 textDescription.setText(thisFile.getName()); 694 // textElements.setText(Integer.toString(elements)); 695 // textLines.setText(Integer.toString(lines)); 696 textBands.setText("1"); 697 698 radioBinary.setSelected(true); 699 700 textLatLonScale.setText("1"); 701 checkEastPositive.setSelected(false); 702 703 } 704 705 /** 706 * Clear out any data values presented to the user 707 */ 708 private void clearValues() { 709 textDescription.setText(""); 710 textElements.setText(""); 711 textLines.setText(""); 712 textBands.setText(""); 713 textUnit.setText(""); 714 textStride.setText(""); 715 checkTranspose.setSelected(false); 716 717 textLatFile.setText(""); 718 textLonFile.setText(""); 719 textLatUL.setText(""); 720 textLonUL.setText(""); 721 textLatLR.setText(""); 722 textLonLR.setText(""); 723 724 textLatLonScale.setText(""); 725 checkEastPositive.setSelected(false); 726 727 textOffset.setText(""); 728 textMissing.setText(""); 729 } 730 731 /** 732 * Ask the user for a data file 733 */ 734 private File getDataFile(File thisFile) { 735 JFileChooser fileChooser = new JFileChooser(thisFile); 736 fileChooser.setMultiSelectionEnabled(false); 737 int status = fileChooser.showOpenDialog(null); 738 if (status == JFileChooser.APPROVE_OPTION) { 739 thisFile = fileChooser.getSelectedFile(); 740 } 741 return(thisFile); 742 } 743 744 /** 745 * Get the name of the dataset. 746 * 747 * @return descriptive name of the dataset. 748 */ 749 public String getDatasetName() { 750 return "Data Set Name"; 751 } 752 753 /** 754 * Get the properties from the datasource 755 * 756 * @param ht a Hashtable of properties 757 */ 758 protected void getDataSourceProperties(Hashtable ht) { 759 super.getDataSourceProperties(ht); 760 ht.put("FLAT.NAME", textDescription.getText()); 761 ht.put("FLAT.ELEMENTS", textElements.getText()); 762 ht.put("FLAT.LINES", textLines.getText()); 763 ht.put("FLAT.BANDNAMES", bandNames); 764 ht.put("FLAT.BANDFILES", bandFiles); 765 ht.put("FLAT.UNIT", textUnit.getText()); 766 ht.put("FLAT.STRIDE", textStride.getText()); 767 ht.put("FLAT.TRANSPOSE", checkTranspose.isSelected()); 768 ht.put("FLAT.MISSING", textMissing.getText()); 769 770 // Navigation 771 if (radioLatLonFiles.isSelected()) { 772 ht.put("NAV.TYPE", "FILES"); 773 ht.put("FILE.LAT", latFile.getAbsolutePath()); 774 ht.put("FILE.LON", lonFile.getAbsolutePath()); 775 } 776 else if (radioLatLonBounds.isSelected()) { 777 ht.put("NAV.TYPE", "BOUNDS"); 778 ht.put("BOUNDS.ULLAT", textLatUL.getText()); 779 ht.put("BOUNDS.ULLON", textLonUL.getText()); 780 ht.put("BOUNDS.LRLAT", textLatLR.getText()); 781 ht.put("BOUNDS.LRLON", textLonLR.getText()); 782 } 783 else { 784 ht.put("NAV.TYPE", "UNKNOWN"); 785 } 786 ht.put("NAV.SCALE", textLatLonScale.getText()); 787 ht.put("NAV.EASTPOS", checkEastPositive.isSelected()); 788 789 // Data type 790 if (radioBinary.isSelected()) { 791 TwoFacedObject format = (TwoFacedObject) comboByteFormat.getSelectedItem(); 792 TwoFacedObject interleave = (TwoFacedObject) comboInterleave.getSelectedItem(); 793 ht.put("FORMAT.TYPE", "BINARY"); 794 ht.put("BINARY.FORMAT", format.getId()); 795 ht.put("BINARY.INTERLEAVE", interleave.getId()); 796 ht.put("BINARY.BIGENDIAN", radioEndianBig.isSelected()); 797 ht.put("BINARY.OFFSET", textOffset.getText()); 798 } 799 else if (radioASCII.isSelected()) { 800 ht.put("FORMAT.TYPE", "ASCII"); 801 ht.put("ASCII.DELIMITER", textDelimiter.getText()); 802 } 803 else if (radioImage.isSelected()) { 804 ht.put("FORMAT.TYPE", "IMAGE"); 805 } 806 else { 807 ht.put("FORMAT.TYPE", "UNKNOWN"); 808 } 809 810 } 811 812 /** 813 * User said go, we go. Simply get the list of images 814 * from the imageChooser and create the FILE.FLAT 815 * DataSource 816 * 817 */ 818 public void doLoadInThread() { 819 String definingObject = dataFileText.getText(); 820 String dataType = "FILE.FLAT"; 821 822 Hashtable properties = new Hashtable(); 823 getDataSourceProperties(properties); 824 825 makeDataSource(definingObject, dataType, properties); 826 } 827 828 /** 829 * The dimensions inner panel 830 */ 831 protected JPanel makeDimensionsPanel() { 832 JPanel myPanel = new JPanel(); 833 myPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Dimensions")); 834 835 JLabel elementsLabel = McVGuiUtils.makeLabelRight("Elements:"); 836 McVGuiUtils.setComponentWidth(textElements); 837 838 JLabel linesLabel = McVGuiUtils.makeLabelRight("Lines:"); 839 McVGuiUtils.setComponentWidth(textLines); 840 841 JLabel bandsLabel = McVGuiUtils.makeLabelRight("Bands:"); 842 McVGuiUtils.setComponentWidth(textBands); 843 844 JLabel unitLabel = McVGuiUtils.makeLabelRight("Units:"); 845 McVGuiUtils.setComponentWidth(textUnit); 846 847 JLabel strideLabel = McVGuiUtils.makeLabelRight("Sampling:"); 848 McVGuiUtils.setComponentWidth(textStride); 849 850 // JLabel transposeLabel = McVGuiUtils.makeLabelRight(""); 851 852 GroupLayout layout = new GroupLayout(myPanel); 853 myPanel.setLayout(layout); 854 layout.setHorizontalGroup( 855 layout.createParallelGroup(LEADING) 856 .addGroup(layout.createSequentialGroup() 857 .addContainerGap() 858 .addGroup(layout.createParallelGroup(LEADING) 859 .addGroup(layout.createSequentialGroup() 860 .addComponent(elementsLabel) 861 .addGap(GAP_RELATED) 862 .addComponent(textElements)) 863 .addGroup(layout.createSequentialGroup() 864 .addComponent(linesLabel) 865 .addGap(GAP_RELATED) 866 .addComponent(textLines)) 867 .addGroup(layout.createSequentialGroup() 868 .addComponent(bandsLabel) 869 .addGap(GAP_RELATED) 870 .addComponent(textBands)) 871 .addGroup(layout.createSequentialGroup() 872 .addComponent(unitLabel) 873 .addGap(GAP_RELATED) 874 .addComponent(textUnit)) 875 .addGroup(layout.createSequentialGroup() 876 .addComponent(strideLabel) 877 .addGap(GAP_RELATED) 878 .addComponent(textStride))) 879 .addContainerGap()) 880 ); 881 layout.setVerticalGroup( 882 layout.createParallelGroup(LEADING) 883 .addGroup(TRAILING, layout.createSequentialGroup() 884 .addContainerGap() 885 .addGroup(layout.createParallelGroup(BASELINE) 886 .addComponent(textElements) 887 .addComponent(elementsLabel)) 888 .addPreferredGap(RELATED) 889 .addGroup(layout.createParallelGroup(BASELINE) 890 .addComponent(textLines) 891 .addComponent(linesLabel)) 892 .addPreferredGap(RELATED) 893 .addGroup(layout.createParallelGroup(BASELINE) 894 .addComponent(textBands) 895 .addComponent(bandsLabel)) 896 .addPreferredGap(RELATED) 897 .addGroup(layout.createParallelGroup(BASELINE) 898 .addComponent(textUnit) 899 .addComponent(unitLabel)) 900 .addPreferredGap(RELATED) 901 .addGroup(layout.createParallelGroup(BASELINE) 902 .addComponent(textStride) 903 .addComponent(strideLabel)) 904 .addContainerGap()) 905 ); 906 907 return myPanel; 908 } 909 910 /** 911 * The navigation inner panel 912 */ 913 protected JPanel makeNavigationPanel() { 914 JPanel myPanel = new JPanel(); 915 myPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Navigation")); 916 917 McVGuiUtils.setComponentWidth(textLatFile, Width.DOUBLE); 918 McVGuiUtils.setComponentWidth(textLonFile, Width.DOUBLE); 919 panelLatLonFiles = McVGuiUtils.topBottom( 920 GuiUtils.leftRight(McVGuiUtils.makeLabeledComponent("Latitude:",textLatFile), buttonLatFile), 921 GuiUtils.leftRight(McVGuiUtils.makeLabeledComponent("Longitude:",textLonFile), buttonLonFile), 922 Prefer.NEITHER); 923 924 // Images to make the bounds more clear 925 IconPanel urPanel = new IconPanel("/edu/wisc/ssec/mcidasv/images/upper_right.gif"); 926 IconPanel llPanel = new IconPanel("/edu/wisc/ssec/mcidasv/images/lower_left.gif"); 927 928 McVGuiUtils.setComponentWidth(textLatUL); 929 McVGuiUtils.setComponentWidth(textLonUL); 930 McVGuiUtils.setComponentWidth(textLatLR); 931 McVGuiUtils.setComponentWidth(textLonLR); 932 panelLatLonBounds = McVGuiUtils.topBottom( 933 McVGuiUtils.makeLabeledComponent("UL Lat/Lon:", GuiUtils.leftRight(GuiUtils.hbox(textLatUL, textLonUL), urPanel)), 934 McVGuiUtils.makeLabeledComponent("LR Lat/Lon:", GuiUtils.leftRight(llPanel, GuiUtils.hbox(textLatLR, textLonLR))), 935 Prefer.NEITHER); 936 937 McVGuiUtils.setComponentWidth(radioLatLonFiles); 938 McVGuiUtils.setComponentWidth(radioLatLonBounds); 939 940 JLabel labelScale = McVGuiUtils.makeLabelRight("Scale:"); 941 McVGuiUtils.setComponentWidth(textLatLonScale); 942 943 JPanel panelScaleEastPositive = GuiUtils.hbox(textLatLonScale, checkEastPositive); 944 945 JLabel labelEastPositive = McVGuiUtils.makeLabelRight(""); 946 947 GroupLayout layout = new GroupLayout(myPanel); 948 myPanel.setLayout(layout); 949 layout.setHorizontalGroup( 950 layout.createParallelGroup(LEADING) 951 .addGroup(layout.createSequentialGroup() 952 .addContainerGap() 953 .addGroup(layout.createParallelGroup(LEADING) 954 .addGroup(layout.createSequentialGroup() 955 .addComponent(radioLatLonFiles) 956 .addGap(GAP_RELATED) 957 .addComponent(panelLatLonFiles)) 958 .addGroup(layout.createSequentialGroup() 959 .addComponent(radioLatLonBounds) 960 .addGap(GAP_RELATED) 961 .addComponent(panelLatLonBounds)) 962 .addGroup(layout.createSequentialGroup() 963 .addComponent(labelScale) 964 .addGap(GAP_RELATED) 965 .addComponent(panelScaleEastPositive))) 966 .addContainerGap()) 967 ); 968 layout.setVerticalGroup( 969 layout.createParallelGroup(LEADING) 970 .addGroup(TRAILING, layout.createSequentialGroup() 971 .addContainerGap() 972 .addGroup(layout.createParallelGroup(BASELINE) 973 .addComponent(radioLatLonFiles) 974 .addComponent(panelLatLonFiles)) 975 .addPreferredGap(RELATED) 976 .addGroup(layout.createParallelGroup(BASELINE) 977 .addComponent(radioLatLonBounds) 978 .addComponent(panelLatLonBounds)) 979 .addPreferredGap(RELATED) 980 .addGroup(layout.createParallelGroup(BASELINE) 981 .addComponent(labelScale) 982 .addComponent(panelScaleEastPositive)) 983 .addContainerGap()) 984 ); 985 986 return myPanel; 987 } 988 989 /** 990 * The format inner panel 991 */ 992 protected JPanel makeFormatPanel() { 993 JPanel myPanel = new JPanel(); 994 myPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Format")); 995 996 McVGuiUtils.setComponentWidth(radioBinary); 997 McVGuiUtils.setComponentWidth(radioASCII); 998 McVGuiUtils.setComponentWidth(radioImage); 999 McVGuiUtils.setComponentWidth(radioEndianLittle); 1000 McVGuiUtils.setComponentWidth(radioEndianBig); 1001 1002 McVGuiUtils.setComponentWidth(comboByteFormat, Width.TRIPLE); 1003 McVGuiUtils.setComponentWidth(comboInterleave, Width.DOUBLE); 1004 McVGuiUtils.setComponentWidth(textOffset, Width.HALF); 1005 1006 panelBinary = McVGuiUtils.topBottom( 1007 McVGuiUtils.topBottom( 1008 McVGuiUtils.makeLabeledComponent("Byte format:", comboByteFormat), 1009 McVGuiUtils.makeLabeledComponent("Interleave:", comboInterleave), 1010 Prefer.NEITHER), 1011 McVGuiUtils.topBottom( 1012 McVGuiUtils.makeLabeledComponent("Endian:", GuiUtils.hbox(radioEndianLittle, radioEndianBig, GAP_RELATED)), 1013 McVGuiUtils.makeLabeledComponent("Offset:", McVGuiUtils.makeComponentLabeled(textOffset, "bytes")), 1014 Prefer.NEITHER), 1015 Prefer.NEITHER); 1016 1017 McVGuiUtils.setComponentWidth(textDelimiter, Width.HALF); 1018 panelASCII = McVGuiUtils.makeLabeledComponent("Delimiter:", textDelimiter); 1019 panelImage = new JPanel(); 1020 1021 JLabel missingLabel = McVGuiUtils.makeLabelRight("Missing value:"); 1022 McVGuiUtils.setComponentWidth(textMissing); 1023 JPanel missingPanel = McVGuiUtils.makeComponentLabeled(textMissing, ""); 1024 1025 GroupLayout layout = new GroupLayout(myPanel); 1026 myPanel.setLayout(layout); 1027 layout.setHorizontalGroup( 1028 layout.createParallelGroup(LEADING) 1029 .addGroup(layout.createSequentialGroup() 1030 .addContainerGap() 1031 .addGroup(layout.createParallelGroup(LEADING) 1032 .addGroup(layout.createSequentialGroup() 1033 .addComponent(radioBinary) 1034 .addGap(GAP_RELATED) 1035 .addComponent(panelBinary)) 1036 .addGroup(layout.createSequentialGroup() 1037 .addComponent(radioASCII) 1038 .addGap(GAP_RELATED) 1039 .addComponent(panelASCII)) 1040 .addGroup(layout.createSequentialGroup() 1041 .addComponent(radioImage) 1042 .addGap(GAP_RELATED) 1043 .addComponent(panelImage)) 1044 .addGroup(layout.createSequentialGroup() 1045 .addComponent(missingLabel) 1046 .addGap(GAP_RELATED) 1047 .addComponent(missingPanel))) 1048 .addContainerGap()) 1049 ); 1050 layout.setVerticalGroup( 1051 layout.createParallelGroup(LEADING) 1052 .addGroup(TRAILING, layout.createSequentialGroup() 1053 .addContainerGap() 1054 .addGroup(layout.createParallelGroup(BASELINE) 1055 .addComponent(radioBinary) 1056 .addComponent(panelBinary)) 1057 .addPreferredGap(RELATED) 1058 .addGroup(layout.createParallelGroup(BASELINE) 1059 .addComponent(radioASCII) 1060 .addComponent(panelASCII)) 1061 .addPreferredGap(RELATED) 1062 .addGroup(layout.createParallelGroup(BASELINE) 1063 .addComponent(radioImage) 1064 .addComponent(panelImage)) 1065 .addPreferredGap(RELATED) 1066 .addGroup(layout.createParallelGroup(BASELINE) 1067 .addComponent(missingLabel) 1068 .addComponent(missingPanel)) 1069 .addContainerGap()) 1070 ); 1071 1072 return myPanel; 1073 } 1074 1075 /** 1076 * The main panel properties panel 1077 */ 1078 protected JPanel makePropertiesPanel() { 1079 JPanel thisPanel = new JPanel(); 1080 JPanel topPanel = McVGuiUtils.sideBySide(makeDimensionsPanel(), makeNavigationPanel()); 1081 JPanel bottomPanel = makeFormatPanel(); 1082 return McVGuiUtils.topBottom(topPanel, bottomPanel, Prefer.NEITHER); 1083 } 1084 1085 /** 1086 * @return The gui of this chooser 1087 */ 1088 protected JComponent doMakeContents() { 1089 1090 Element chooserNode = getXmlNode(); 1091 String path = (String) idv.getPreference(PREF_DEFAULTDIR + getId()); 1092 if (path == null) { 1093 path = XmlUtil.getAttribute(chooserNode, "path", (String) null); 1094 } 1095 1096 JPanel myPanel = new JPanel(); 1097 1098 // File 1099 JLabel fileLabel = McVGuiUtils.makeLabelRight("File:"); 1100 McVGuiUtils.setComponentWidth(dataFileText, Width.DOUBLEDOUBLE); 1101 1102 JLabel typeLabel = McVGuiUtils.makeLabelRight("Type:"); 1103 McVGuiUtils.setLabelBold(dataFileDescription, true); 1104 1105 JLabel descriptionLabel = McVGuiUtils.makeLabelRight("Description:"); 1106 McVGuiUtils.setLabelBold(textDescription, true); 1107 1108 JLabel propertiesLabel = McVGuiUtils.makeLabelRight("Properties:"); 1109 JPanel propertiesPanel = makePropertiesPanel(); 1110 1111 JLabel statusLabelLabel = McVGuiUtils.makeLabelRight(""); 1112 McVGuiUtils.setLabelPosition(statusLabel, Position.RIGHT); 1113 McVGuiUtils.setComponentColor(statusLabel, TextColor.STATUS); 1114 1115 JButton helpButton = McVGuiUtils.makeImageButton(ICON_HELP, "Show help"); 1116 helpButton.setActionCommand(GuiUtils.CMD_HELP); 1117 helpButton.addActionListener(this); 1118 1119 McVGuiUtils.setComponentWidth(loadButton, Width.DOUBLE); 1120 1121 GroupLayout layout = new GroupLayout(myPanel); 1122 myPanel.setLayout(layout); 1123 layout.setHorizontalGroup( 1124 layout.createParallelGroup(LEADING) 1125 .addGroup(layout.createSequentialGroup() 1126 .addContainerGap() 1127 .addGroup(layout.createParallelGroup(LEADING) 1128 .addGroup(layout.createSequentialGroup() 1129 .addComponent(fileLabel) 1130 .addGap(GAP_RELATED) 1131 .addComponent(dataFileText) 1132 .addGap(GAP_RELATED) 1133 .addComponent(dataFileButton)) 1134 .addGroup(layout.createSequentialGroup() 1135 .addComponent(typeLabel) 1136 .addGap(GAP_RELATED) 1137 .addComponent(dataFileDescription)) 1138 .addGroup(layout.createSequentialGroup() 1139 .addComponent(descriptionLabel) 1140 .addGap(GAP_RELATED) 1141 .addComponent(textDescription)) 1142 .addGroup(layout.createSequentialGroup() 1143 .addComponent(propertiesLabel) 1144 .addGap(GAP_RELATED) 1145 .addComponent(propertiesPanel)) 1146 .addGroup(TRAILING, layout.createSequentialGroup() 1147 .addComponent(helpButton) 1148 .addPreferredGap(RELATED) 1149 .addComponent(loadButton)) 1150 .addGroup(layout.createSequentialGroup() 1151 .addComponent(statusLabelLabel) 1152 .addGap(GAP_RELATED) 1153 .addComponent(statusLabel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))) 1154 .addContainerGap()) 1155 ); 1156 layout.setVerticalGroup( 1157 layout.createParallelGroup(LEADING) 1158 .addGroup(TRAILING, layout.createSequentialGroup() 1159 .addContainerGap() 1160 .addGroup(layout.createParallelGroup(BASELINE) 1161 .addComponent(dataFileButton) 1162 .addComponent(dataFileText) 1163 .addComponent(fileLabel)) 1164 .addPreferredGap(RELATED) 1165 .addGroup(layout.createParallelGroup(BASELINE) 1166 .addComponent(dataFileDescription) 1167 .addComponent(typeLabel)) 1168 .addPreferredGap(RELATED) 1169 .addGroup(layout.createParallelGroup(BASELINE) 1170 .addComponent(textDescription) 1171 .addComponent(descriptionLabel)) 1172 .addPreferredGap(RELATED) 1173 .addGroup(layout.createParallelGroup(BASELINE) 1174 .addComponent(propertiesPanel) 1175 .addComponent(propertiesLabel)) 1176 .addPreferredGap(RELATED, DEFAULT_SIZE, Short.MAX_VALUE) 1177 .addGroup(layout.createParallelGroup(BASELINE) 1178 .addComponent(statusLabelLabel) 1179 .addComponent(statusLabel)) 1180 .addPreferredGap(UNRELATED) 1181 .addGroup(layout.createParallelGroup(BASELINE) 1182 .addComponent(loadButton) 1183 .addComponent(helpButton)) 1184 .addContainerGap()) 1185 ); 1186 1187 return myPanel; 1188 1189 } 1190 1191 } 1192