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