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