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 029 package edu.wisc.ssec.mcidasv.chooser; 030 031 032 import static javax.swing.GroupLayout.DEFAULT_SIZE; 033 import static javax.swing.GroupLayout.Alignment.BASELINE; 034 import static javax.swing.GroupLayout.Alignment.LEADING; 035 import static javax.swing.GroupLayout.Alignment.TRAILING; 036 import static javax.swing.LayoutStyle.ComponentPlacement.RELATED; 037 import static javax.swing.LayoutStyle.ComponentPlacement.UNRELATED; 038 039 import java.awt.Image; 040 import java.awt.MediaTracker; 041 import java.awt.Toolkit; 042 import java.awt.event.ActionEvent; 043 import java.awt.event.ActionListener; 044 import java.awt.event.FocusEvent; 045 import java.awt.event.FocusListener; 046 import java.io.File; 047 import java.io.FileNotFoundException; 048 import java.io.FileReader; 049 import java.io.InputStream; 050 import java.util.ArrayList; 051 import java.util.Hashtable; 052 import java.util.List; 053 054 import javax.swing.GroupLayout; 055 import javax.swing.JButton; 056 import javax.swing.JCheckBox; 057 import javax.swing.JComboBox; 058 import javax.swing.JComponent; 059 import javax.swing.JFileChooser; 060 import javax.swing.JLabel; 061 import javax.swing.JPanel; 062 import javax.swing.JRadioButton; 063 import javax.swing.JTextField; 064 065 import org.w3c.dom.Element; 066 067 import ucar.unidata.idv.IntegratedDataViewer; 068 import ucar.unidata.idv.chooser.IdvChooser; 069 import ucar.unidata.idv.chooser.IdvChooserManager; 070 import ucar.unidata.util.GuiUtils; 071 import ucar.unidata.util.IOUtil; 072 import ucar.unidata.util.Misc; 073 import ucar.unidata.util.TwoFacedObject; 074 import ucar.unidata.xml.XmlUtil; 075 import visad.util.ImageHelper; 076 import edu.wisc.ssec.mcidasv.Constants; 077 import edu.wisc.ssec.mcidasv.data.AxformInfo; 078 import edu.wisc.ssec.mcidasv.data.EnviInfo; 079 import edu.wisc.ssec.mcidasv.data.HeaderInfo; 080 import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 081 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Position; 082 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Prefer; 083 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.TextColor; 084 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Width; 085 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.IconPanel; 086 087 /** 088 * @author SSEC Development Team 089 */ 090 091 public class FlatFileChooser extends IdvChooser implements Constants { 092 093 /** Set default stride to keep dimensions within this */ 094 private int maxDefDim = 1000; 095 096 // Properties associated with the button selector 097 private File dataFile; 098 private JTextField dataFileText = new JTextField(); 099 private JButton dataFileButton = new JButton(); 100 private JLabel dataFileDescription = new JLabel(); 101 private JLabel textDescription = new JLabel(); 102 103 // Dimensions 104 // elements, lines, bands 105 private JTextField textElements = new JTextField(); 106 private JTextField textLines = new JTextField(); 107 private JTextField textBands = new JTextField(); 108 private JTextField textUnit = new JTextField(); 109 private JTextField textStride = new JTextField(); 110 private JCheckBox checkTranspose = new JCheckBox("Transpose elements/lines"); 111 private List bandNames = new ArrayList(); 112 private List bandFiles = new ArrayList(); 113 114 // Navigation 115 // lat/lon files or bounds 116 private JRadioButton radioLatLonFiles = new JRadioButton("Files", true); 117 private JRadioButton radioLatLonBounds = new JRadioButton("Bounds", false); 118 private File latFile, lonFile; 119 private JLabel textLatFile = new JLabel(); 120 private JButton buttonLatFile = new JButton(); 121 private JLabel textLonFile = new JLabel(); 122 private JButton buttonLonFile = new JButton(); 123 private JPanel panelLatLonFiles = new JPanel(); 124 private JTextField textLatUL = new JTextField(); 125 private JTextField textLonUL = new JTextField(); 126 private JTextField textLatLR = new JTextField(); 127 private JTextField textLonLR = new JTextField(); 128 private JPanel panelLatLonBounds = new JPanel(); 129 private JTextField textLatLonScale = new JTextField(); 130 private JCheckBox checkEastPositive = new JCheckBox("East positive"); 131 132 133 // Properties associated with the data file 134 // bytes/pixel, ASCII delimiter, endianness, interleave, offset, missing 135 private JRadioButton radioBinary = new JRadioButton("Binary", true); 136 private JRadioButton radioASCII = new JRadioButton("ASCII", false); 137 private JRadioButton radioImage = new JRadioButton("Image", false); 138 private JRadioButton radioEndianLittle = new JRadioButton("Little", true); 139 private JRadioButton radioEndianBig = new JRadioButton("Big", false); 140 private JComboBox comboByteFormat = new JComboBox(); 141 private JComboBox comboInterleave = new JComboBox(); 142 private JTextField textOffset = new JTextField("0"); 143 private JPanel panelBinary = new JPanel(); 144 private JTextField textDelimiter = new JTextField(); 145 private JPanel panelASCII = new JPanel(); 146 private JPanel panelImage = new JPanel(); 147 private JTextField textMissing = new JTextField(); 148 149 private List<TwoFacedObject> listByteFormat = Misc.newList(new TwoFacedObject[] { 150 new TwoFacedObject("1-byte unsigned integer", HeaderInfo.kFormat1ByteUInt), 151 new TwoFacedObject("2-byte signed integer", HeaderInfo.kFormat2ByteSInt), 152 new TwoFacedObject("4-byte signed integer", HeaderInfo.kFormat4ByteSInt), 153 new TwoFacedObject("4-byte float", HeaderInfo.kFormat4ByteFloat), 154 new TwoFacedObject("8-byte double", HeaderInfo.kFormat8ByteDouble), 155 new TwoFacedObject("2x8-byte complex number", HeaderInfo.kFormat2x8Byte), 156 new TwoFacedObject("2-byte unsigned integer", HeaderInfo.kFormat2ByteUInt) 157 }); 158 159 private List<TwoFacedObject> listInterleave = Misc.newList( 160 new TwoFacedObject("Sequential", HeaderInfo.kInterleaveSequential), 161 new TwoFacedObject("By line", HeaderInfo.kInterleaveByLine), 162 new TwoFacedObject("By pixel", HeaderInfo.kInterleaveByPixel)); 163 164 private JLabel statusLabel = new JLabel("Status"); 165 166 /** 167 * Super setStatus() takes a second string to enable "simple" mode 168 * which highlights the required component. We don't really care 169 * about that feature, and we don't want getStatusLabel() to 170 * change the label background color. 171 */ 172 @Override 173 public void setStatus(String statusString, String foo) { 174 if (statusString == null) 175 statusString = ""; 176 statusLabel.setText(statusString); 177 } 178 179 /** 180 * Get a handle on the IDV 181 */ 182 protected IntegratedDataViewer idv = getIdv(); 183 184 /** 185 * Create the FileChooser, passing in the manager and the xml element 186 * from choosers.xml 187 * 188 * @param mgr The manager 189 * @param root The xml root 190 * 191 */ 192 public FlatFileChooser(IdvChooserManager mgr, Element root) { 193 super(mgr, root); 194 195 loadButton = McVGuiUtils.makeImageTextButton(ICON_ACCEPT_SMALL, getLoadCommandName()); 196 loadButton.setActionCommand(getLoadCommandName()); 197 loadButton.addActionListener(this); 198 199 dataFileButton = McVGuiUtils.makeImageButton(ICON_OPEN, "Open file"); 200 dataFileButton.addActionListener(new ActionListener(){ 201 public void actionPerformed(ActionEvent e) { 202 dataFile = getDataFile(dataFile); 203 if (dataFile!=null) { 204 dataFileText.setText(dataFile.getAbsolutePath()); 205 inspectDataFile(dataFile); 206 } 207 } 208 }); 209 dataFileText.addActionListener(new ActionListener(){ 210 public void actionPerformed(ActionEvent e) { 211 dataFile = new File(dataFileText.getText()); 212 inspectDataFile(dataFile); 213 } 214 }); 215 dataFileText.addFocusListener(new FocusListener() { 216 public void focusGained(FocusEvent e) {} 217 public void focusLost(FocusEvent e) { 218 dataFile = new File(dataFileText.getText()); 219 inspectDataFile(dataFile); 220 } 221 }); 222 223 radioLatLonFiles.addActionListener(new ActionListener(){ 224 public void actionPerformed(ActionEvent e) { 225 checkSetLatLon(); 226 } 227 }); 228 radioLatLonBounds.addActionListener(new ActionListener(){ 229 public void actionPerformed(ActionEvent e) { 230 checkSetLatLon(); 231 } 232 }); 233 234 buttonLatFile = McVGuiUtils.makeImageButton(ICON_OPEN, "Select latitude file"); 235 buttonLatFile.addActionListener(new ActionListener(){ 236 public void actionPerformed(ActionEvent e) { 237 latFile = getDataFile(latFile); 238 if (latFile!=null) 239 textLatFile.setText(latFile.getName()); 240 } 241 }); 242 buttonLonFile = McVGuiUtils.makeImageButton(ICON_OPEN, "Select longitude file"); 243 buttonLonFile.addActionListener(new ActionListener(){ 244 public void actionPerformed(ActionEvent e) { 245 lonFile = getDataFile(lonFile); 246 if (lonFile!=null) 247 textLonFile.setText(lonFile.getName()); 248 } 249 }); 250 GuiUtils.buttonGroup(radioLatLonFiles, radioLatLonBounds); 251 252 radioBinary.addActionListener(new ActionListener(){ 253 public void actionPerformed(ActionEvent e) { 254 checkSetBinaryASCIIImage(); 255 } 256 }); 257 radioASCII.addActionListener(new ActionListener(){ 258 public void actionPerformed(ActionEvent e) { 259 checkSetBinaryASCIIImage(); 260 } 261 }); 262 radioImage.addActionListener(new ActionListener(){ 263 public void actionPerformed(ActionEvent e) { 264 checkSetBinaryASCIIImage(); 265 } 266 }); 267 GuiUtils.buttonGroup(radioBinary, radioASCII, radioImage); 268 GuiUtils.buttonGroup(radioEndianLittle, radioEndianBig); 269 270 GuiUtils.setListData(comboByteFormat, listByteFormat); 271 GuiUtils.setListData(comboInterleave, listInterleave); 272 273 setHaveData(false); 274 } 275 276 /** 277 * enable/disable widgets for navigation 278 */ 279 private void checkSetLatLon() { 280 boolean isFile = radioLatLonFiles.isSelected(); 281 GuiUtils.enableTree(panelLatLonFiles, isFile); 282 GuiUtils.enableTree(panelLatLonBounds, !isFile); 283 } 284 285 /** 286 * enable/disable widgets for binary/ASCII 287 */ 288 private void checkSetBinaryASCIIImage() { 289 GuiUtils.enableTree(panelBinary, radioBinary.isSelected()); 290 GuiUtils.enableTree(panelASCII, radioASCII.isSelected()); 291 GuiUtils.enableTree(panelImage, radioImage.isSelected()); 292 } 293 294 /** 295 * Set whether the user has made a selection that contains data. 296 * 297 * @param have true to set the haveData property. Enables the 298 * loading button 299 */ 300 public void setHaveData(boolean have) { 301 super.setHaveData(have); 302 updateStatus(); 303 } 304 305 /** 306 * Set the status message appropriately 307 */ 308 protected void updateStatus() { 309 super.updateStatus(); 310 checkSetLatLon(); 311 checkSetBinaryASCIIImage(); 312 if(!getHaveData()) { 313 setStatus("Select a file"); 314 } 315 } 316 317 /** 318 * Inspect the selected data file 319 * Determine if it is a known header file type 320 * 321 * @param thisFile 322 * @throws FileNotFoundException 323 */ 324 private void inspectDataFile(File thisFile) { 325 if (thisFile == null || thisFile.getName()=="") { 326 dataFileDescription.setText(""); 327 setHaveData(false); 328 return; 329 } 330 if (!thisFile.exists()) { 331 dataFileDescription.setText("File does not exist"); 332 setHaveData(false); 333 return; 334 } 335 try { 336 FileReader fr = new FileReader(thisFile); 337 char first80c[] = new char[80]; 338 fr.read(first80c, 0, 80); 339 fr.close(); 340 String first80 = new String(first80c); 341 clearValues(); 342 boolean doStride = false; 343 if (IOUtil.hasSuffix(thisFile.getName(), ".gif") || 344 IOUtil.hasSuffix(thisFile.getName(), ".jpg") || 345 IOUtil.hasSuffix(thisFile.getName(), ".png")) { 346 dataFileDescription.setText("Image file"); 347 processImageFile(thisFile); 348 } 349 else if (IOUtil.hasSuffix(thisFile.getName(), ".xml") || 350 IOUtil.hasSuffix(thisFile.getName(), ".ximg")) { 351 dataFileDescription.setText("XML image header file"); 352 processXmlHeaderFile(thisFile); 353 } 354 else if (first80.indexOf(" Space Science & Engineering Center") >= 0) { 355 dataFileDescription.setText("McIDAS-X AXFORM header file"); 356 processAxformHeaderFile(thisFile); 357 doStride = true; 358 } 359 else if (first80.indexOf("ENVI") >= 0) { 360 dataFileDescription.setText("ENVI header file"); 361 processEnviHeaderFile(thisFile); 362 doStride = true; 363 } 364 else { 365 dataFileDescription.setText("Binary, ASCII or Image data"); 366 processGenericFile(thisFile); 367 doStride = true; 368 } 369 370 // Default the stride 371 int newStride = 1; 372 if (doStride) { 373 String textLinesText = textLines.getText(); 374 String textElementsText = textElements.getText(); 375 if (!(textLinesText.equalsIgnoreCase("") || textElementsText.equalsIgnoreCase(""))) { 376 int myLines = Integer.parseInt(textLinesText); 377 int myElements = Integer.parseInt(textElementsText); 378 if (myLines > maxDefDim || myElements > maxDefDim) { 379 newStride = Math.max((int)Math.ceil((float)myLines/(float)maxDefDim), (int)Math.ceil((float)myElements/(float)maxDefDim)); 380 } 381 } 382 } 383 textStride.setText(Integer.toString(newStride)); 384 385 setHaveData(true); 386 } 387 catch (Exception e) { 388 e.printStackTrace(); 389 } 390 } 391 392 /** 393 * Special processing for a known data type 394 * This deals specifically with AXFORM header files 395 */ 396 private void processAxformHeaderFile(File thisFile) { 397 try { 398 AxformInfo axformInfo = new AxformInfo(thisFile); 399 400 // Set the properties in the GUI 401 textDescription.setText(axformInfo.getParameter(HeaderInfo.DESCRIPTION, "")); 402 textElements.setText((axformInfo.getParameter(HeaderInfo.ELEMENTS, 0)).toString()); 403 textLines.setText((axformInfo.getParameter(HeaderInfo.LINES, 0)).toString()); 404 textUnit.setText((axformInfo.getParameter(HeaderInfo.UNIT, "")).toString()); 405 bandNames = (List)axformInfo.getParameter(HeaderInfo.BANDNAMES, new ArrayList()); 406 bandFiles = (List)axformInfo.getParameter(HeaderInfo.BANDFILES, new ArrayList()); 407 textBands.setText(Integer.toString(bandNames.size())); 408 textOffset.setText((axformInfo.getParameter(HeaderInfo.OFFSET, 0)).toString()); 409 textMissing.setText((axformInfo.getParameter(HeaderInfo.MISSINGVALUE, (float)0)).toString()); 410 411 Integer dataType = (Integer)axformInfo.getParameter(HeaderInfo.DATATYPE, HeaderInfo.kFormatUnknown); 412 Boolean bigEndian = (Boolean)axformInfo.getParameter(HeaderInfo.BIGENDIAN, false); 413 if (dataType==HeaderInfo.kFormatASCII) { 414 radioASCII.setSelected(true); 415 } 416 else if (dataType==HeaderInfo.kFormatImage) { 417 radioImage.setSelected(true); 418 } 419 else { 420 radioBinary.setSelected(true); 421 TwoFacedObject tfo = TwoFacedObject.findId(dataType.intValue(), listByteFormat); 422 if (tfo!=null) 423 comboByteFormat.setSelectedItem(tfo); 424 tfo = TwoFacedObject.findId(HeaderInfo.kInterleaveSequential, listInterleave); 425 if (tfo!=null) 426 comboInterleave.setSelectedItem(tfo); 427 } 428 429 radioEndianLittle.setSelected(!bigEndian.booleanValue()); 430 radioEndianBig.setSelected(bigEndian.booleanValue()); 431 432 List latlonFiles = axformInfo.getParameter(HeaderInfo.NAVFILES, new ArrayList()); 433 if (latlonFiles.size() == 2) { 434 latFile = new File((String)latlonFiles.get(0)); 435 lonFile = new File((String)latlonFiles.get(1)); 436 } 437 438 if (latFile==null || lonFile==null) { 439 radioLatLonBounds.setSelected(true); 440 } 441 else { 442 textLatFile.setText(latFile.getName()); 443 textLonFile.setText(lonFile.getName()); 444 radioLatLonFiles.setSelected(true); 445 } 446 447 textLatLonScale.setText("100"); 448 checkEastPositive.setSelected(true); 449 450 } 451 catch (Exception e) { 452 e.printStackTrace(); 453 } 454 } 455 456 /** 457 * Special processing for a known data type 458 * This deals specifically with ENVI header files 459 */ 460 private void processEnviHeaderFile(File thisFile) { 461 try { 462 EnviInfo enviInfo = new EnviInfo(thisFile); 463 464 // Set the properties in the GUI 465 textDescription.setText(enviInfo.getParameter(HeaderInfo.DESCRIPTION, "")); 466 textElements.setText((enviInfo.getParameter(HeaderInfo.ELEMENTS, 0)).toString()); 467 textLines.setText((enviInfo.getParameter(HeaderInfo.LINES, 0)).toString()); 468 textUnit.setText((enviInfo.getParameter(HeaderInfo.UNIT, "")).toString()); 469 bandNames = (List)enviInfo.getParameter(HeaderInfo.BANDNAMES, new ArrayList()); 470 bandFiles = (List)enviInfo.getParameter(HeaderInfo.BANDFILES, new ArrayList()); 471 textBands.setText(Integer.toString(bandNames.size())); 472 textOffset.setText((enviInfo.getParameter(HeaderInfo.OFFSET, 0)).toString()); 473 textMissing.setText((enviInfo.getParameter(HeaderInfo.MISSINGVALUE, (float)0)).toString()); 474 475 Integer dataType = (Integer)enviInfo.getParameter(HeaderInfo.DATATYPE, HeaderInfo.kFormatUnknown); 476 String interleaveType = (enviInfo.getParameter(HeaderInfo.INTERLEAVE, HeaderInfo.kInterleaveSequential)).toString(); 477 Boolean bigEndian = (Boolean)enviInfo.getParameter(HeaderInfo.BIGENDIAN, false); 478 radioBinary.setSelected(true); 479 TwoFacedObject tfo = TwoFacedObject.findId(dataType.intValue(), listByteFormat); 480 if (tfo!=null) 481 comboByteFormat.setSelectedItem(tfo); 482 tfo = TwoFacedObject.findId(interleaveType, listInterleave); 483 if (tfo!=null) 484 comboInterleave.setSelectedItem(tfo); 485 486 radioEndianLittle.setSelected(!bigEndian.booleanValue()); 487 radioEndianBig.setSelected(bigEndian.booleanValue()); 488 489 // Look for a geo.hdr file that contains Latitude and Longitude bands 490 String parent = thisFile.getParent(); 491 if (parent==null) parent="."; 492 String navFile = thisFile.getName().replace(".hdr", ""); 493 int lastDot = navFile.lastIndexOf("."); 494 if (lastDot >= 0) { 495 navFile = navFile.substring(0, lastDot) + ".geo.hdr"; 496 } 497 navFile = parent + "/" + navFile; 498 EnviInfo navInfo = new EnviInfo(navFile); 499 if (navInfo.isNavHeader()) { 500 latFile = new File(navFile); 501 lonFile = new File(navFile); 502 } 503 504 if (latFile==null || lonFile==null) { 505 radioLatLonBounds.setSelected(true); 506 } 507 else { 508 textLatFile.setText(latFile.getName()); 509 textLonFile.setText(lonFile.getName()); 510 radioLatLonFiles.setSelected(true); 511 } 512 513 textLatLonScale.setText("1"); 514 checkEastPositive.setSelected(false); 515 516 } 517 catch (Exception e) { 518 e.printStackTrace(); 519 } 520 } 521 522 /** 523 * Special processing for a known data type 524 * This deals specifically with XML header files 525 */ 526 private void processXmlHeaderFile(File thisFile) { 527 try { 528 529 String description = ""; 530 int lines = 0; 531 int elements = 0; 532 float missingVal = -1; 533 534 bandFiles = new ArrayList(); 535 bandNames = new ArrayList(); 536 537 Element root = XmlUtil.getRoot(thisFile.getAbsolutePath(), getClass()); 538 if (!root.getTagName().equals("image")) { 539 processGenericFile(thisFile); 540 return; 541 } 542 543 description = XmlUtil.getAttribute(root, "name", (String) null); 544 String url = ""; 545 if (XmlUtil.hasAttribute(root, "url")) { 546 url = XmlUtil.getAttribute(root, "url"); 547 if (description == "") { 548 description = url; 549 } 550 String parent = thisFile.getParent(); 551 if (parent==null) parent="."; 552 url = parent + "/" + url; 553 } 554 else { 555 processGenericFile(thisFile); 556 return; 557 } 558 if (XmlUtil.hasAttribute(root, "ullat")) { 559 radioLatLonBounds.setSelected(true); 560 textLatUL.setText(XmlUtil.getAttribute(root, "ullat")); 561 } 562 if (XmlUtil.hasAttribute(root, "ullon")) { 563 radioLatLonBounds.setSelected(true); 564 textLonUL.setText(XmlUtil.getAttribute(root, "ullon")); 565 } 566 if (XmlUtil.hasAttribute(root, "lrlat")) { 567 radioLatLonBounds.setSelected(true); 568 textLatLR.setText(XmlUtil.getAttribute(root, "lrlat")); 569 } 570 if (XmlUtil.hasAttribute(root, "lrlon")) { 571 radioLatLonBounds.setSelected(true); 572 textLonLR.setText(XmlUtil.getAttribute(root, "lrlon")); 573 } 574 575 // Try to read the referenced image to get lines and elements 576 setStatus("Loading image"); 577 InputStream is = null; 578 is = IOUtil.getInputStream(url, getClass()); 579 byte[] imageContent = IOUtil.readBytes(is); 580 Image image = Toolkit.getDefaultToolkit().createImage(imageContent); 581 MediaTracker tracker = new MediaTracker(this); 582 tracker.addImage(image, 0); 583 try { 584 tracker.waitForAll(); 585 } 586 catch(InterruptedException e) {} 587 ImageHelper ih = new ImageHelper(); 588 image.getWidth(ih); 589 if (ih.badImage) { 590 throw new IllegalStateException("Bad image: " + url); 591 } 592 elements = image.getWidth(ih); 593 lines = image.getHeight(ih); 594 595 // Bands 596 bandFiles.add(url); 597 bandNames.add("XML image file"); 598 599 // Set the properties in the GUI 600 textDescription.setText(description); 601 textElements.setText(Integer.toString(elements)); 602 textLines.setText(Integer.toString(lines)); 603 textBands.setText(Integer.toString(bandNames.size())); 604 605 radioImage.setSelected(true); 606 textMissing.setText(Float.toString(missingVal)); 607 608 textLatLonScale.setText("1"); 609 checkEastPositive.setSelected(false); 610 611 } 612 catch (Exception e) { 613 e.printStackTrace(); 614 } 615 } 616 617 /** 618 * Special processing for a known data type 619 * This deals specifically with XML header files 620 */ 621 private void processImageFile(File thisFile) { 622 try { 623 624 String description = ""; 625 int lines = 0; 626 int elements = 0; 627 float missingVal = -1; 628 629 bandFiles = new ArrayList(); 630 bandNames = new ArrayList(); 631 632 description = thisFile.getName(); 633 String url = thisFile.getAbsolutePath(); 634 635 // Try to read the referenced image to get lines and elements 636 setStatus("Loading image"); 637 InputStream is = null; 638 is = IOUtil.getInputStream(url, getClass()); 639 byte[] imageContent = IOUtil.readBytes(is); 640 Image image = Toolkit.getDefaultToolkit().createImage(imageContent); 641 MediaTracker tracker = new MediaTracker(this); 642 tracker.addImage(image, 0); 643 try { 644 tracker.waitForAll(); 645 } 646 catch(InterruptedException e) {} 647 ImageHelper ih = new ImageHelper(); 648 image.getWidth(ih); 649 if (ih.badImage) { 650 throw new IllegalStateException("Bad image: " + url); 651 } 652 elements = image.getWidth(ih); 653 lines = image.getHeight(ih); 654 655 // Bands 656 bandFiles.add(url); 657 bandNames.add("Image file"); 658 659 // Set the properties in the GUI 660 textDescription.setText(description); 661 textElements.setText(Integer.toString(elements)); 662 textLines.setText(Integer.toString(lines)); 663 textBands.setText(Integer.toString(bandNames.size())); 664 665 radioImage.setSelected(true); 666 textMissing.setText(Float.toString(missingVal)); 667 668 textLatLonScale.setText("1"); 669 checkEastPositive.setSelected(false); 670 671 } 672 catch (Exception e) { 673 e.printStackTrace(); 674 } 675 } 676 677 /** 678 * Special processing for an unknown data type 679 * Can we glean anything about the file by inspecting it more? 680 */ 681 private void processGenericFile(File thisFile) { 682 683 clearValues(); 684 685 // Set appropriate defaults 686 // Bands 687 bandFiles.clear(); 688 bandFiles.add(thisFile.getAbsolutePath()); 689 bandNames.clear(); 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("0"); 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