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