001/*****************************************************************************
002 * Copyright by The HDF Group.                                               *
003 * Copyright by the Board of Trustees of the University of Illinois.         *
004 * All rights reserved.                                                      *
005 *                                                                           *
006 * This file is part of the HDF Java Products distribution.                  *
007 * The full copyright notice, including terms governing use, modification,   *
008 * and redistribution, is contained in the file COPYING.                     *
009 * COPYING can be found at the root of the source code distribution tree.    *
010 * If you do not have access to this file, you may request a copy from       *
011 * help@hdfgroup.org.                                                        *
012 ****************************************************************************/
013
014package hdf.view;
015
016import java.awt.BorderLayout;
017import java.awt.Component;
018import java.awt.Dimension;
019import java.awt.Font;
020import java.awt.GridLayout;
021import java.awt.Insets;
022import java.awt.Toolkit;
023import java.awt.datatransfer.DataFlavor;
024import java.awt.datatransfer.Transferable;
025import java.awt.datatransfer.UnsupportedFlavorException;
026import java.awt.dnd.DnDConstants;
027import java.awt.dnd.DropTarget;
028import java.awt.dnd.DropTargetDragEvent;
029import java.awt.dnd.DropTargetDropEvent;
030import java.awt.dnd.DropTargetEvent;
031import java.awt.dnd.DropTargetListener;
032import java.awt.event.ActionEvent;
033import java.awt.event.ActionListener;
034import java.awt.event.KeyEvent;
035import java.io.BufferedInputStream;
036import java.io.BufferedOutputStream;
037import java.io.File;
038import java.io.FileOutputStream;
039import java.io.IOException;
040import java.lang.reflect.Constructor;
041import java.net.URL;
042import java.util.ArrayList;
043import java.util.Enumeration;
044import java.util.Iterator;
045import java.util.List;
046import java.util.Vector;
047
048import javax.swing.ImageIcon;
049import javax.swing.JButton;
050import javax.swing.JComboBox;
051import javax.swing.JComponent;
052import javax.swing.JDesktopPane;
053import javax.swing.JDialog;
054import javax.swing.JFileChooser;
055import javax.swing.JFrame;
056import javax.swing.JInternalFrame;
057import javax.swing.JMenu;
058import javax.swing.JMenuBar;
059import javax.swing.JMenuItem;
060import javax.swing.JOptionPane;
061import javax.swing.JPanel;
062import javax.swing.JScrollPane;
063import javax.swing.JSplitPane;
064import javax.swing.JTabbedPane;
065import javax.swing.JTextArea;
066import javax.swing.JToolBar;
067import javax.swing.KeyStroke;
068import javax.swing.SwingUtilities;
069import javax.swing.UIDefaults;
070import javax.swing.UIManager;
071import javax.swing.event.ChangeEvent;
072import javax.swing.event.ChangeListener;
073
074import hdf.object.Attribute;
075import hdf.object.CompoundDS;
076import hdf.object.Dataset;
077import hdf.object.Datatype;
078import hdf.object.FileFormat;
079import hdf.object.Group;
080import hdf.object.HObject;
081import hdf.object.ScalarDS;
082
083/**
084 * HDFView is the main class of this HDF visual tool. It is used to layout the
085 * graphical components of the hdfview. The major GUI components of the HDFView
086 * include Menubar, Toolbar, TreeView, ContentView, and MessageArea.
087 * <p>
088 * The HDFView is designed in such a way that it does not have direct access to
089 * the HDF library. All the HDF library access is done through HDF objects.
090 * Therefore, the HDFView package depends on the object package but not the
091 * library package. The source code of the view package (hdf.view) should
092 * be compiled with the library package (hdf.hdflib and hdf.hdf5lib).
093 *
094 * @author Peter X. Cao
095 * @version 2.4 9/6/2007
096 */
097
098public class HDFView extends JFrame implements ViewManager, ActionListener, ChangeListener, DropTargetListener {
099    private static final long     serialVersionUID = 2211017444445918998L;
100
101    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(HDFView.class);
102
103    /** a list of tree view implementation. */
104    private static List<String>   treeViews;
105
106    /** a list of image view implementation. */
107    private static List<String>   imageViews;
108
109    /** a list of tree table implementation. */
110    private static List<?>           tableViews;
111
112    /** a list of Text view implementation. */
113    private static List<String>           textViews;
114
115    /** a list of metadata view implementation. */
116    private static List<?>           metaDataViews;
117
118    /** a list of palette view implementation. */
119    private static List<?>           paletteViews;
120
121    /** a list of help view implementation. */
122    private static List<?>           helpViews;
123
124    private static final String   aboutHDFView     = "HDF Viewer, " + "Version " + ViewProperties.VERSION + "\n"
125            + "For " + System.getProperty("os.name") + "\n\n"
126                                                                   + "Copyright " + '\u00a9' + " 2006-2017 The HDF Group.\n"
127            + "All rights reserved.";
128
129    private static final String   JAVA_COMPILER    = "jdk 1.7";
130
131    /** the directory where the HDFView is installed */
132    private String                rootDir;
133
134    /** the current working directory */
135    private String                currentDir;
136
137    /** the current working file */
138    private String                currentFile;
139
140    /** the view properties */
141    private ViewProperties        props;
142
143    /** the list of most recent files */
144    // private Vector recentFiles;
145
146    /** GUI component: the TreeView */
147    private TreeView              treeView;
148
149    /** The offset when a new dataview is added into the main window. */
150    private int                   frameOffset;
151
152    /** GUI component: the panel which is used to display the data content */
153    private final JDesktopPane    contentPane;
154
155    /** GUI component: the text area for showing status message */
156    private final JTextArea       statusArea;
157
158    /** GUI component: the text area for quick attribute view */
159    private final JTextArea       attributeArea;
160
161    /* create tab pane to display attributes and status information */
162    private final JTabbedPane     infoTabbedPane;
163
164    /** the main menu bar */
165    private JMenuBar              menuBar;
166
167    /** GUI component: a list of current data windwos */
168    private final JMenu           windowMenu;
169
170    /** GUI component: file menu on the menubar */
171    private final JMenu           fileMenu;
172
173    /** the string buffer holding the status message */
174    private final StringBuffer    message;
175
176    /** the string buffer holding the metadata information */
177    private final StringBuffer    metadata;
178
179    private final Toolkit         toolkit;
180
181    /** The list of GUI components related to editing */
182    private final List<?>         editGUIs;
183
184    /** The list of GUI components related to HDF5 */
185    private final List<JMenuItem> h5GUIs;
186
187    /** The list of GUI components related to HDF4 */
188    private final List<JMenuItem> h4GUIs;
189
190    /** to add and display url */
191    @SuppressWarnings("rawtypes")
192    private JComboBox             urlBar;
193
194    private UserOptionsDialog     userOptionDialog;
195
196    private Constructor<?>        ctrSrbFileDialog = null;
197
198    private JDialog               srbFileDialog    = null;
199
200    /**
201     * Constructs HDFView with a given root directory, where the HDFView is
202     * installed, and opens the given files in the viewer.
203     *
204     * @param root
205     *            the directory where the HDFView is installed.
206     * @param flist
207     *            a list of files to open.
208     * @param width
209     *            the width of the app in pixels
210     * @param height
211     *            the height of the app in pixels
212     * @param x
213     *            the coord x of the app in pixels
214     * @param y
215     *            the coord y of the app in pixels
216     */
217    @SuppressWarnings("unchecked")
218    public HDFView(String root, List<File> flist, int width, int height, int x, int y) {
219        super("HDFView " + ViewProperties.VERSION);
220        this.setName("hdfview");
221        try {
222            UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
223        }
224        catch(Exception e) { System.out.println("Error setting Java LAF: " + e); }
225
226
227        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
228
229        // set the module class jar files to the class path
230        log.debug("root is {}", root);
231
232        rootDir = root;
233        currentFile = null;
234        frameOffset = 0;
235        userOptionDialog = null;
236        ctrSrbFileDialog = null;
237        toolkit = Toolkit.getDefaultToolkit();
238        ViewProperties.loadIcons();
239        ViewProperties.loadExtClass();
240
241        editGUIs = new Vector<Object>();
242        h4GUIs = new Vector<JMenuItem>();
243        h5GUIs = new Vector<JMenuItem>();
244
245        // load the view properties
246        props = new ViewProperties(rootDir);
247        try {
248            props.load();
249        }
250        catch (Exception ex) {
251            log.debug("Failed to load View Properties from {}", rootDir);
252        }
253
254        // recentFiles = ViewProperties.getMRF();
255        currentDir = ViewProperties.getWorkDir();
256        if (currentDir == null) currentDir = System.getProperty("user.home");
257
258        log.info("Current directory is {}", currentDir);
259
260        treeViews = ViewProperties.getTreeViewList();
261        metaDataViews = ViewProperties.getMetaDataViewList();
262        textViews = ViewProperties.getTextViewList();
263        tableViews = ViewProperties.getTableViewList();
264        imageViews = ViewProperties.getImageViewList();
265        paletteViews = ViewProperties.getPaletteViewList();
266        helpViews = ViewProperties.getHelpViewList();
267
268        // initialize GUI components
269        statusArea = new JTextArea();
270        statusArea.setEditable(false);
271        statusArea.setBackground(new java.awt.Color(240, 240, 240));
272        statusArea.setLineWrap(true);
273        statusArea.setName("status");
274        message = new StringBuffer();
275        metadata = new StringBuffer();
276        showStatus("HDFView root - " + rootDir);
277        showStatus("User property file - " + ViewProperties.getPropertyFile());
278
279        attributeArea = new JTextArea();
280        attributeArea.setEditable(false);
281        attributeArea.setBackground(new java.awt.Color(240, 240, 240));
282        attributeArea.setLineWrap(true);
283        attributeArea.setName("attributes");
284
285        // create tab pane to display attributes and status information
286        infoTabbedPane = new JTabbedPane(JTabbedPane.BOTTOM);
287        infoTabbedPane.addChangeListener(this);
288        infoTabbedPane.setName("tabpane");
289
290        contentPane = new JDesktopPane();
291        contentPane.setName("contentpane");
292        windowMenu = new JMenu("Window");
293        windowMenu.setName("windowmenu");
294        fileMenu = new JMenu("File");
295        fileMenu.setName("filemenu");
296
297        int n = treeViews.size();
298        Class<?> theClass = null;
299        for (int i = 0; i < n; i++) {
300            // Use the first available treeview
301            String className = treeViews.get(i);
302
303            // Enables use of JHDF5 in JNLP (Web Start) applications, the system
304            // class loader with reflection first.
305            try {
306                theClass = Class.forName(className);
307            }
308            catch (Exception ex) {
309                try {
310                    theClass = ViewProperties.loadExtClass().loadClass(className);
311                }
312                catch (Exception ex2) {
313                    theClass = null;
314                }
315            }
316
317            if (theClass != null) break;
318        }
319
320        if (theClass != null) {
321            try {
322                @SuppressWarnings("rawtypes")
323                Class[] paramClass = { Class.forName("hdf.view.ViewManager") };
324                Constructor<?> constructor = theClass.getConstructor(paramClass);
325                Object[] paramObj = { this };
326                treeView = (TreeView) constructor.newInstance(paramObj);
327            }
328            catch (Exception ex) {
329                treeView = null;
330            }
331        }
332
333        // could not load user's treeview, use default treeview.
334        if (treeView == null) treeView = new DefaultTreeView(this);
335
336        createMainWindow(width, height, x, y);
337
338        try {
339            java.awt.Font font = null;
340            String ftype = ViewProperties.getFontType();
341            int fsize = ViewProperties.getFontSize();
342            try {
343                font = new java.awt.Font(ftype, java.awt.Font.PLAIN, fsize);
344            }
345            catch (Exception ex) {
346                font = null;
347            }
348
349            if (font != null)
350                updateFontSize(font);
351
352        }
353        catch (Exception ex) {
354            log.debug("Failed to load Font properties");
355        }
356
357        // need to call pack() before open any file so that
358        // all GUI components will be in place.
359        pack();
360
361        /* add support for drag and drop file */
362        new DropTarget(this, this);
363
364        int nfiles = flist.size();
365
366        log.trace("flist.size() = {}", nfiles);
367        File theFile = null;
368        for (int i = 0; i < nfiles; i++) {
369            theFile = flist.get(i);
370            log.trace("flist[{}] = {}", i, theFile.toString());
371
372            if (theFile.isFile()) {
373                currentDir = theFile.getParentFile().getAbsolutePath();
374                log.trace("file dir is {}", currentFile);
375                currentFile = theFile.getAbsolutePath();
376                log.trace("file is {}", currentFile);
377
378                try {
379                    treeView.openFile(currentFile, FileFormat.WRITE);
380
381                    try {
382                        urlBar.removeItem(currentFile);
383                        urlBar.insertItemAt(currentFile, 0);
384                        urlBar.setSelectedIndex(0);
385                    }
386                    catch (Exception ex2) {
387                        log.info("Failed to update urlBar with {}", currentFile);
388                    }
389                }
390                catch (Exception ex) {
391                    showStatus(ex.toString());
392                }
393            }
394            else {
395                currentDir = theFile.getAbsolutePath();
396            }
397
398            log.info("CurrentDir is {}", currentDir);
399        }
400
401        if (FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4) == null)
402            setEnabled(h4GUIs, false);
403
404        if (FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5) == null) {
405            setEnabled(h5GUIs, false);
406        }
407
408    }
409
410    /**
411     * Set default UI fonts.
412     */
413    private void updateFontSize(Font font) {
414        if (font == null) {
415            return;
416        }
417
418        UIDefaults defaults = UIManager.getLookAndFeelDefaults();
419
420        for (Iterator<?> i = defaults.keySet().iterator(); i.hasNext();) {
421            Object key = i.next();
422            if (defaults.getFont(key) != null) {
423                UIManager.put(key, new javax.swing.plaf.FontUIResource(font));
424            }
425        }
426        SwingUtilities.updateComponentTreeUI(this);
427    }
428
429    /**
430     * Creates and lays out GUI components.
431     *
432     * <pre>
433     * ||=========||=============================||
434     * ||         ||                             ||
435     * ||         ||                             ||
436     * || TreeView||       ContentPane           ||
437     * ||         ||                             ||
438     * ||=========||=============================||
439     * ||            Message Area                ||
440     * ||========================================||
441     * </pre>
442     */
443    @SuppressWarnings({ "unchecked", "rawtypes" })
444    private void createMainWindow(int width, int height, int x, int y) {
445        // create splitpane to separate treeview and the contentpane
446        JScrollPane treeScroller = new JScrollPane((Component) treeView);
447        treeScroller.setName("treescroller");
448        JScrollPane contentScroller = new JScrollPane(contentPane);
449        contentScroller.setName("contentscroller");
450        JSplitPane topSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treeScroller, contentScroller);
451        topSplitPane.setDividerLocation(200);
452        topSplitPane.setName("topsplitpane");
453
454        infoTabbedPane.addTab("Log Info", new JScrollPane(statusArea));
455        infoTabbedPane.addTab("Metadata ", new JScrollPane(attributeArea));
456        infoTabbedPane.setSelectedIndex(1);
457
458        // create splitpane to separate message area and treeview-contentpane
459        topSplitPane.setBorder(null); // refer to Java bug #4131528
460        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topSplitPane, infoTabbedPane);
461        splitPane.setName("splitpane");
462
463        // set the window size
464        // float inset = 0.17f; // for UG only.
465        float inset = 0.04f;
466        Dimension d = toolkit.getScreenSize();
467
468        if (height > 300) {
469            d.height = height;
470        }
471        else {
472            d.height = (int) ((1 - 2 * inset) * d.height);
473        }
474
475        if (width > 300) {
476            d.width = width;
477        }
478        else {
479            d.width = (int) (0.9 * (double) d.height);
480        }
481
482        // TEST
483        if (treeView.getClass().getName().startsWith("ext.erdc")) {
484            topSplitPane.setDividerLocation(500);
485            d.width = (int) (0.9 * toolkit.getScreenSize().width);
486            d.height = (int) (d.width * 0.618);
487        }
488
489        splitPane.setDividerLocation(d.height - 180);
490        this.setLocation(x, y);
491
492        try {
493            this.setIconImage(((ImageIcon) ViewProperties.getHdfIcon()).getImage());
494        }
495        catch (Exception ex) {
496            log.debug("Failed to getImage");
497        }
498
499        this.setJMenuBar(menuBar = createMenuBar());
500        JToolBar toolBar = createToolBar();
501
502        /** create URL address bar */
503        urlBar = new JComboBox(ViewProperties.getMRF());
504        urlBar.setMaximumRowCount(ViewProperties.MAX_RECENT_FILES);
505        urlBar.setEditable(true);
506        urlBar.addActionListener(this);
507        urlBar.setActionCommand("Open file: from file bar");
508        urlBar.setSelectedIndex(-1);
509
510        JPanel urlPane = new JPanel();
511        urlPane.setLayout(new BorderLayout());
512        urlPane.setName("urlpane");
513
514        JButton b = new JButton("Clear Text");
515        b.setActionCommand("Clear current selection");
516        b.setToolTipText("Clear current selection");
517        b.setMargin(new Insets(1, 3, 1, 3));
518        b.addActionListener(this);
519        urlPane.add(b, BorderLayout.EAST);
520
521        b = new JButton("Recent Files");
522        b.addActionListener(this);
523        b.setActionCommand("Popup URL list");
524        b.setToolTipText("List of recent files");
525        b.setMargin(new Insets(1, 3, 1, 3));
526        urlPane.add(b, BorderLayout.WEST);
527
528        urlPane.add(urlBar, BorderLayout.CENTER);
529        JPanel toolPane = new JPanel();
530        toolPane.setLayout(new GridLayout(2, 1, 0, 0));
531        toolPane.add(toolBar);
532        toolPane.add(urlPane);
533        toolPane.setName("toolpane");
534
535        JPanel mainPane = (JPanel) getContentPane();
536        mainPane.setLayout(new BorderLayout());
537        mainPane.add(toolPane, BorderLayout.NORTH);
538        mainPane.add(splitPane, BorderLayout.CENTER);
539        mainPane.setPreferredSize(d);
540        mainPane.setName("mainpane");
541
542        log.info("MainWindow created");
543    }
544
545    private JMenuBar createMenuBar() {
546        JMenuBar mbar = new JMenuBar();
547        mbar.setName("mbar");
548        JMenu menu = null;
549        JMenuItem item;
550
551        // add file menu
552        fileMenu.setMnemonic('f');
553        mbar.add(fileMenu);
554
555        item = new JMenuItem("Open");
556        item.setMnemonic(KeyEvent.VK_O);
557        item.addActionListener(this);
558        item.setActionCommand("Open file");
559        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), true));
560        fileMenu.add(item);
561
562        item = new JMenuItem("Open Read-Only");
563        item.setMnemonic(KeyEvent.VK_R);
564        item.addActionListener(this);
565        item.setActionCommand("Open file read-only");
566        if (!ViewProperties.isReadOnly()) fileMenu.add(item);
567
568        // boolean isSrbSupported = true;
569        // try {
570        // Class.forName("hdf.srb.H5SRB");
571        // Class.forName("hdf.srb.SRBFileDialog");
572        // } catch (Throwable ex) {isSrbSupported = false;}
573        //
574        // if (isSrbSupported) {
575        // item = new JMenuItem( "Open from iRODS");
576        // item.setMnemonic(KeyEvent.VK_S);
577        // item.addActionListener(this);
578        // item.setActionCommand("Open from irods");
579        // fileMenu.add(item);
580        // }
581
582        fileMenu.addSeparator();
583
584        JMenu newFileMenu = new JMenu("New");
585        item = new JMenuItem("HDF4");
586        item.setActionCommand("New HDF4 file");
587        item.setMnemonic(KeyEvent.VK_4);
588        item.addActionListener(this);
589        h4GUIs.add(item);
590        newFileMenu.add(item);
591        item = new JMenuItem("HDF5");
592        item.setActionCommand("New HDF5 file");
593        item.setMnemonic(KeyEvent.VK_5);
594        item.addActionListener(this);
595        h5GUIs.add(item);
596        newFileMenu.add(item);
597        fileMenu.add(newFileMenu);
598
599        fileMenu.addSeparator();
600
601        item = new JMenuItem("Close");
602        item.setMnemonic(KeyEvent.VK_C);
603        item.addActionListener(this);
604        item.setActionCommand("Close file");
605        fileMenu.add(item);
606
607        item = new JMenuItem("Close All");
608        item.setMnemonic(KeyEvent.VK_A);
609        item.addActionListener(this);
610        item.setActionCommand("Close all file");
611        fileMenu.add(item);
612
613        fileMenu.addSeparator();
614
615        item = new JMenuItem("Save");
616        item.setMnemonic(KeyEvent.VK_S);
617        item.addActionListener(this);
618        item.setActionCommand("Save current file");
619        fileMenu.add(item);
620
621        item = new JMenuItem("Save As");
622        item.setMnemonic(KeyEvent.VK_A);
623        item.addActionListener(this);
624        item.setActionCommand("Save current file as");
625        fileMenu.add(item);
626
627        fileMenu.addSeparator();
628
629        item = new JMenuItem("Exit");
630        item.setMnemonic(KeyEvent.VK_X);
631        item.addActionListener(this);
632        item.setActionCommand("Exit");
633        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), true));
634        fileMenu.add(item);
635
636        fileMenu.addSeparator();
637
638        // add window menu
639        windowMenu.setMnemonic('w');
640        mbar.add(windowMenu);
641
642        item = new JMenuItem("Cascade");
643        item.setMnemonic(KeyEvent.VK_C);
644        item.setActionCommand("Cascade all windows");
645        item.addActionListener(this);
646        windowMenu.add(item);
647
648        item = new JMenuItem("Tile");
649        item.setMnemonic(KeyEvent.VK_T);
650        item.setActionCommand("Tile all windows");
651        item.addActionListener(this);
652        windowMenu.add(item);
653
654        windowMenu.addSeparator();
655
656        item = new JMenuItem("Close Window");
657        item.setMnemonic(KeyEvent.VK_W);
658        item.setActionCommand("Close a window");
659        item.addActionListener(this);
660        windowMenu.add(item);
661
662        item = new JMenuItem("Close All");
663        item.setMnemonic(KeyEvent.VK_A);
664        item.setActionCommand("Close all windows");
665        item.addActionListener(this);
666        windowMenu.add(item);
667
668        windowMenu.addSeparator();
669
670        // add tool menu
671        menu = new JMenu("Tools");
672        menu.setMnemonic('T');
673        mbar.add(menu);
674
675        JMenu imageSubmenu = new JMenu("Convert Image To");
676        item = new JMenuItem("HDF4");
677        item.setActionCommand("Convert image file: Image to HDF4");
678        item.addActionListener(this);
679        h4GUIs.add(item);
680        imageSubmenu.add(item);
681        item = new JMenuItem("HDF5");
682        item.setActionCommand("Convert image file: Image to HDF5");
683        item.addActionListener(this);
684        h5GUIs.add(item);
685        imageSubmenu.add(item);
686        menu.add(imageSubmenu);
687
688        menu.addSeparator();
689
690        item = new JMenuItem("User Options");
691        item.setMnemonic(KeyEvent.VK_O);
692        item.setActionCommand("User options");
693        item.addActionListener(this);
694        menu.add(item);
695
696        menu.addSeparator();
697
698        item = new JMenuItem("Register File Format");
699        item.setMnemonic(KeyEvent.VK_R);
700        item.setActionCommand("Register file format");
701        item.addActionListener(this);
702        menu.add(item);
703
704        item = new JMenuItem("Unregister File Format");
705        item.setMnemonic(KeyEvent.VK_U);
706        item.setActionCommand("Unregister file format");
707        item.addActionListener(this);
708        menu.add(item);
709
710        // add help menu
711        menu = new JMenu("Help");
712        menu.setMnemonic('H');
713        mbar.add(menu);
714
715        item = new JMenuItem("User's Guide");
716        item.setMnemonic(KeyEvent.VK_U);
717        item.setActionCommand("Users guide");
718        item.addActionListener(this);
719        menu.add(item);
720
721        menu.addSeparator();
722
723        if ((helpViews != null) && (helpViews.size() > 0)) {
724            int n = helpViews.size();
725            for (int i = 0; i < n; i++) {
726                HelpView theView = (HelpView) helpViews.get(i);
727                item = new JMenuItem(theView.getLabel());
728                item.setActionCommand(theView.getActionCommand());
729                item.addActionListener(this);
730                menu.add(item);
731            }
732            menu.addSeparator();
733        }
734
735        item = new JMenuItem("HDF4 Library Version");
736        item.setMnemonic(KeyEvent.VK_4);
737        item.setActionCommand("HDF4 library");
738        item.addActionListener(this);
739        h4GUIs.add(item);
740        menu.add(item);
741
742        item = new JMenuItem("HDF5 Library Version");
743        item.setMnemonic(KeyEvent.VK_5);
744        item.setActionCommand("HDF5 library");
745        item.addActionListener(this);
746        h5GUIs.add(item);
747        menu.add(item);
748
749        item = new JMenuItem("Java Version");
750        item.setMnemonic(KeyEvent.VK_5);
751        item.setActionCommand("Java version");
752        item.addActionListener(this);
753        menu.add(item);
754
755        menu.addSeparator();
756
757        item = new JMenuItem("Supported File Formats");
758        item.setMnemonic(KeyEvent.VK_L);
759        item.setActionCommand("File format list");
760        item.addActionListener(this);
761        menu.add(item);
762
763        menu.addSeparator();
764
765        item = new JMenuItem("About...");
766        item.setMnemonic(KeyEvent.VK_A);
767        item.setActionCommand("About");
768        item.addActionListener(this);
769        menu.add(item);
770
771        log.info("MenuBar created");
772        return mbar;
773    }
774
775    private JToolBar createToolBar() {
776        JToolBar tbar = new JToolBar();
777        tbar.setFloatable(false);
778        tbar.setName("tbar");
779
780        // open file button
781        JButton button = new JButton(ViewProperties.getFileopenIcon());
782        tbar.add(button);
783        button.setName("Open");
784        button.setToolTipText("Open");
785        button.addActionListener(this);
786        button.setActionCommand("Open file");
787
788        // close file button
789        button = new JButton(ViewProperties.getFilecloseIcon());
790        tbar.add(button);
791        button.setName("Close");
792        button.setToolTipText("Close");
793        button.addActionListener(this);
794        button.setActionCommand("Close file");
795
796        tbar.addSeparator(new Dimension(20, 20));
797
798        // help button
799        button = new JButton(ViewProperties.getHelpIcon());
800        tbar.add(button);
801        button.setName("Help");
802        button.setToolTipText("Help");
803        button.addActionListener(this);
804        button.setActionCommand("Users guide");
805
806        // HDF4 Library Version button
807        button = new JButton(ViewProperties.getH4Icon());
808        tbar.add(button);
809        button.setName("HDF4 library");
810        button.setToolTipText("HDF4 Library Version");
811        button.addActionListener(this);
812        button.setActionCommand("HDF4 library");
813        if (FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4) == null) {
814            button.setEnabled(false);
815        }
816
817        // HDF5 Library Version button
818        button = new JButton(ViewProperties.getH5Icon());
819        tbar.add(button);
820        button.setName("HDF5 library");
821        button.setToolTipText("HDF5 Library Version");
822        button.addActionListener(this);
823        button.setActionCommand("HDF5 library");
824        if (FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5) == null) {
825            button.setEnabled(false);
826        }
827
828        log.info("ToolBar created");
829        return tbar;
830    }
831
832    /**
833     * Bring the window to the front.
834     * <p>
835     *
836     * @param name
837     *            the name of the window to show.
838     */
839    private void showWindow(String name) {
840        int n = contentPane.getComponentCount();
841        if (n <= 0) {
842            return;
843        }
844
845        Component comp = null;
846        JInternalFrame jif = null;
847        for (int i = 0; i < n; i++) {
848            comp = contentPane.getComponent(i);
849            if (!(comp instanceof JInternalFrame)) continue;
850
851            jif = (JInternalFrame) contentPane.getComponent(i);
852
853            if (jif.getName().equals(name)) {
854                jif.toFront();
855                return;
856            }
857        }
858    }
859
860    /** Cascade all windows. */
861    private void cascadeWindow() {
862        int y = 2, x = 2;
863        JInternalFrame jif = null;
864        Component[] clist = contentPane.getComponents();
865
866        if ((clist == null) || (clist.length <= 0)) {
867            return;
868        }
869
870        Dimension d = contentPane.getSize();
871        int w = Math.max(50, d.width - 100);
872        int h = Math.max(50, d.height - 100);
873
874        for (int i = 0; i < clist.length; i++) {
875            jif = (JInternalFrame) clist[i];
876            jif.setBounds(x, y, w, h);
877            contentPane.moveToFront(jif);
878            x += 20;
879            y += 20;
880        }
881    }
882
883    /** Tile all windows. */
884    private void tileWindow() {
885        int y = 0, x = 0, idx = 0;
886        JInternalFrame jif = null;
887        Component[] clist = contentPane.getComponents();
888
889        if ((clist == null) || (clist.length <= 0)) {
890            return;
891        }
892
893        int n = clist.length;
894        int cols = (int) Math.sqrt(n);
895        int rows = (int) Math.ceil((double) n / (double) cols);
896
897        Dimension d = contentPane.getSize();
898        int w = d.width / cols;
899        int h = d.height / rows;
900
901        for (int i = 0; i < rows; i++) {
902            x = 0;
903            for (int j = 0; j < cols; j++) {
904                idx = i * cols + j;
905                if (idx >= n) {
906                    return;
907                }
908
909                jif = (JInternalFrame) clist[idx];
910                jif.setBounds(x, y, w, h);
911                x += w;
912            }
913            y += h;
914        }
915    }
916
917    /** Closes all windows. */
918    private void closeAllWindow() {
919        JInternalFrame jif = null;
920        Component[] clist = contentPane.getComponents();
921
922        if ((clist == null) || (clist.length <= 0)) {
923            return;
924        }
925
926        for (int i = 0; i < clist.length; i++) {
927            jif = (JInternalFrame) clist[i];
928            jif.dispose();
929            jif = null;
930        }
931    }
932
933    /** disable/enable GUI components */
934    private static void setEnabled(List<JMenuItem> list, boolean b) {
935        Component item = null;
936        Iterator<JMenuItem> it = list.iterator();
937        while (it.hasNext()) {
938            item = it.next();
939            item.setEnabled(b);
940        }
941    }
942
943    // To do: Implementing java.io.ActionListener
944    @SuppressWarnings("unchecked")
945    public void actionPerformed(ActionEvent e) {
946        String cmd = e.getActionCommand();
947
948        if (cmd.equals("Exit")) {
949            dispose(); // terminate the application
950        }
951        else if (cmd.startsWith("Open file")) {
952            int fileAccessID = FileFormat.WRITE;
953            String filename = null;
954
955            if (ViewProperties.isReadOnly()) fileAccessID = FileFormat.READ;
956
957            if (cmd.equals("Open file: from file bar")) {
958                filename = (String) urlBar.getSelectedItem();
959                if (filename == null || filename.length() < 1) {
960                    return;
961                }
962
963                // local file
964                if (!(filename.startsWith("http://") || filename.startsWith("ftp://"))) {
965                    File tmpFile = new File(filename);
966
967                    if (!tmpFile.exists()) return;
968
969                    if (tmpFile.isDirectory()) {
970                        currentDir = filename;
971                        filename = openLocalFile();
972                    }
973                }
974            }
975            else if (cmd.equals("Open file read-only")) {
976                fileAccessID = FileFormat.READ;
977                filename = openLocalFile();
978            }
979            else if (cmd.startsWith("Open file://")) {
980                filename = cmd.substring(12);
981            }
982            else {
983                filename = openLocalFile();
984            }
985
986            if (filename == null) {
987                return;
988            }
989
990            if (filename.startsWith("http://") || filename.startsWith("ftp://")) {
991                filename = openRemoteFile(filename);
992            }
993
994            if ((filename == null) || (filename.length() < 1) || filename.equals(currentFile)) {
995                return;
996            }
997
998            currentFile = filename;
999            try {
1000                urlBar.removeItem(filename);
1001                urlBar.insertItemAt(filename, 0);
1002                urlBar.setSelectedIndex(0);
1003            }
1004            catch (Exception ex) {
1005            }
1006
1007            try {
1008                treeView.openFile(filename, fileAccessID + FileFormat.OPEN_NEW);
1009            }
1010            catch (Throwable ex) {
1011                try {
1012                    treeView.openFile(filename, FileFormat.READ);
1013                }
1014                catch (Throwable ex2) {
1015                    String msg = "Failed to open file " + filename + "\n" + ex2;
1016                    toolkit.beep();
1017                    currentFile = null;
1018                    urlBar.setSelectedIndex(-1);
1019                    JOptionPane.showMessageDialog(this, msg, getTitle(), JOptionPane.ERROR_MESSAGE);
1020                }
1021            }
1022        }
1023        else if (cmd.equals("Open from irods")) {
1024            try {
1025                openFromSRB();
1026            }
1027            catch (Exception ex) {
1028                toolkit.beep();
1029                JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
1030            }
1031        }
1032        else if (cmd.startsWith("New HDF")) {
1033            String ftype = FileFormat.FILE_TYPE_HDF5;
1034            if (cmd.equals("New HDF4 file")) {
1035                ftype = FileFormat.FILE_TYPE_HDF4;
1036            }
1037
1038            NewFileDialog dialog = new NewFileDialog(this, currentDir, ftype, treeView.getCurrentFiles());
1039            dialog.setName("newfiledialog");
1040            // dialog.show();
1041
1042            if (!dialog.isFileCreated()) {
1043                return;
1044            }
1045            String filename = dialog.getFile();
1046            if (filename == null) {
1047                return;
1048            }
1049
1050            try {
1051                treeView.openFile(filename, FileFormat.WRITE);
1052                currentFile = filename;
1053                try {
1054                    urlBar.removeItem(filename);
1055                    urlBar.insertItemAt(filename, 0);
1056                    urlBar.setSelectedIndex(0);
1057                }
1058                catch (Exception ex2) {
1059                }
1060            }
1061            catch (Exception ex) {
1062                toolkit.beep();
1063                JOptionPane.showMessageDialog(this, ex.getMessage() + "\n" + filename, getTitle(),
1064                        JOptionPane.ERROR_MESSAGE);
1065            }
1066        }
1067        else if (cmd.equals("Close file")) {
1068            closeFile(treeView.getSelectedFile());
1069        }
1070        else if (cmd.equals("Close all file")) {
1071            closeAllWindow();
1072            List<FileFormat> files = treeView.getCurrentFiles();
1073
1074            while (!files.isEmpty()) {
1075                try {
1076                    treeView.closeFile(files.get(0));
1077                }
1078                catch (Exception ex) {
1079                }
1080            }
1081            currentFile = null;
1082
1083            attributeArea.setText("");
1084        }
1085
1086        else if (cmd.equals("Reload file")) {
1087            reloadFile();
1088        }
1089        else if (cmd.equals("Save current file as")) {
1090            try {
1091                treeView.saveFile(treeView.getSelectedFile());
1092            }
1093            catch (Exception ex) {
1094                toolkit.beep();
1095                JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
1096            }
1097        }
1098        else if (cmd.equals("Save current file")) {
1099            /* save what have been changed in memory into file */
1100            try {
1101                FileFormat file = treeView.getSelectedFile();
1102                List<JInternalFrame> views = getDataViews();
1103                Object theView = null;
1104                TableView tableView = null;
1105                TextView textView = null;
1106                FileFormat theFile = null;
1107                if (views != null) {
1108                    int n = views.size();
1109                    for (int i = 0; i < n; i++) {
1110                        theView = views.get(i);
1111                        if (theView instanceof TableView) {
1112                            tableView = (TableView) theView;
1113                            theFile = tableView.getDataObject().getFileFormat();
1114                            if (file.equals(theFile)) {
1115                                tableView.updateValueInFile();
1116                            }
1117                        }
1118                        else if (theView instanceof TextView) {
1119                            textView = (TextView) theView;
1120                            theFile = textView.getDataObject().getFileFormat();
1121                            if (file.equals(theFile)) {
1122                                textView.updateValueInFile();
1123                            }
1124                        }
1125                    } // for (int i=0; i<n; i++)
1126                } // if (views != null)
1127            }
1128            catch (Exception ex) {
1129                toolkit.beep();
1130                JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
1131            }
1132        }
1133        else if (cmd.equals("Cascade all windows")) {
1134            cascadeWindow();
1135        }
1136        else if (cmd.equals("Tile all windows")) {
1137            tileWindow();
1138        }
1139        else if (cmd.equals("Close a window")) {
1140            JInternalFrame frame = contentPane.getSelectedFrame();
1141
1142            if (frame != null) {
1143                frame.dispose();
1144            }
1145        }
1146        else if (cmd.equals("Close all windows")) {
1147            closeAllWindow();
1148        }
1149        else if (cmd.startsWith("SHOW WINDOW")) {
1150            // a window is selected to be shown at the front
1151            showWindow(cmd);
1152        }
1153        else if (cmd.startsWith("Convert image file:")) {
1154            String typeFrom = null, typeTo = null;
1155
1156            if (cmd.equals("Convert image file: Image to HDF5")) {
1157                typeFrom = Tools.FILE_TYPE_IMAGE;
1158                typeTo = FileFormat.FILE_TYPE_HDF5;
1159            }
1160            else if (cmd.equals("Convert image file: Image to HDF4")) {
1161                typeFrom = Tools.FILE_TYPE_IMAGE;
1162                typeTo = FileFormat.FILE_TYPE_HDF4;
1163            }
1164            else {
1165                return;
1166            }
1167
1168            FileConversionDialog dialog = new FileConversionDialog(this, typeFrom, typeTo, currentDir,
1169                    treeView.getCurrentFiles());
1170            dialog.setVisible(true);
1171
1172            if (dialog.isFileConverted()) {
1173                String filename = dialog.getConvertedFile();
1174                File theFile = new File(filename);
1175
1176                if (!theFile.exists() || !theFile.exists()) {
1177                    return;
1178                }
1179
1180                currentDir = theFile.getParentFile().getAbsolutePath();
1181                currentFile = theFile.getAbsolutePath();
1182
1183                try {
1184                    treeView.openFile(filename, FileFormat.WRITE);
1185                    try {
1186                        urlBar.removeItem(filename);
1187                        urlBar.insertItemAt(filename, 0);
1188                        urlBar.setSelectedIndex(0);
1189                    }
1190                    catch (Exception ex2) {
1191                    }
1192                }
1193                catch (Exception ex) {
1194                    showStatus(ex.toString());
1195                }
1196            }
1197        }
1198        else if (cmd.equals("User options")) {
1199            if (userOptionDialog == null) {
1200                userOptionDialog = new UserOptionsDialog(this, rootDir);
1201            }
1202
1203            userOptionDialog.setVisible(true);
1204
1205            if (userOptionDialog.isWorkDirChanged()) {
1206                currentDir = ViewProperties.getWorkDir();
1207                log.info("Work Dir Changed - CurrentDir is {}", currentDir);
1208            }
1209
1210            if (userOptionDialog.isFontChanged()) {
1211                Font font = null;
1212                try {
1213                    font = new Font(ViewProperties.getFontType(), Font.PLAIN, ViewProperties.getFontSize());
1214                }
1215                catch (Exception ex) {
1216                    font = null;
1217                }
1218
1219                if (font != null) {
1220                    updateFontSize(font);
1221                }
1222            }
1223        }
1224        else if (cmd.equals("Register file format")) {
1225            String msg = "Register a new file format by \nKEY:FILE_FORMAT:FILE_EXTENSION\n"
1226                    + "where, KEY: the unique identifier for the file format"
1227                    + "\n           FILE_FORMAT: the full class name of the file format"
1228                    + "\n           FILE_EXTENSION: the file extension for the file format" + "\n\nFor example, "
1229                    + "\n\t to add NetCDF, \"NetCDF:hdf.object.nc2.NC2File:nc\""
1230                    + "\n\t to add FITS, \"FITS:hdf.object.fits.FitsFile:fits\"\n\n";
1231            String str = (String) JOptionPane.showInputDialog(this, msg, "Register a file format",
1232                    JOptionPane.PLAIN_MESSAGE, ViewProperties.getLargeHdfIcon(), null, null);
1233            if ((str == null) || (str.length() < 1)) {
1234                return;
1235            }
1236
1237            int idx1 = str.indexOf(':');
1238            int idx2 = str.lastIndexOf(':');
1239
1240            if ((idx1 < 0) || (idx2 <= idx1)) {
1241                JOptionPane.showMessageDialog(this, "Failed to register " + str
1242                        + "\n\nMust in the form of KEY:FILE_FORMAT:FILE_EXTENSION", "Register File Format",
1243                        JOptionPane.ERROR_MESSAGE);
1244                return;
1245            }
1246
1247            String key = str.substring(0, idx1);
1248            String className = str.substring(idx1 + 1, idx2);
1249            String extension = str.substring(idx2 + 1);
1250
1251            // check is the file format has been registered or the key is taken.
1252            String theKey = null;
1253            String theClassName = null;
1254            Enumeration<?> local_enum = FileFormat.getFileFormatKeys();
1255            while (local_enum.hasMoreElements()) {
1256                theKey = (String) local_enum.nextElement();
1257                if (theKey.endsWith(key)) {
1258                    JOptionPane.showMessageDialog(this, "Invalid key: " + key + " is taken.", "Register File Format",
1259                            JOptionPane.ERROR_MESSAGE);
1260                    return;
1261                }
1262
1263                theClassName = FileFormat.getFileFormat(theKey).getClass().getName();
1264                if (theClassName.endsWith(className)) {
1265                    JOptionPane.showMessageDialog(this, "The file format has already been registered: " + className,
1266                            "Register File Format", JOptionPane.ERROR_MESSAGE);
1267                    return;
1268                }
1269            }
1270
1271            // enables use of JHDF5 in JNLP (Web Start) applications, the system
1272            // class loader with reflection first.
1273            Class<?> theClass = null;
1274            try {
1275                theClass = Class.forName(className);
1276            }
1277            catch (Exception ex) {
1278                try {
1279                    theClass = ViewProperties.loadExtClass().loadClass(className);
1280                }
1281                catch (Exception ex2) {
1282                    theClass = null;
1283                }
1284            }
1285            if (theClass == null) {
1286                return;
1287            }
1288
1289            try {
1290                Object theObject = theClass.newInstance();
1291                if (theObject instanceof FileFormat) {
1292                    FileFormat.addFileFormat(key, (FileFormat) theObject);
1293                }
1294            }
1295            catch (Throwable ex) {
1296                JOptionPane.showMessageDialog(this, "Failed to register " + str + "\n\n" + ex, "Register File Format",
1297                        JOptionPane.ERROR_MESSAGE);
1298                return;
1299            }
1300
1301            if ((extension != null) && (extension.length() > 0)) {
1302                extension = extension.trim();
1303                String ext = ViewProperties.getFileExtension();
1304                ext += ", " + extension;
1305                ViewProperties.setFileExtension(ext);
1306            }
1307        }
1308        else if (cmd.equals("Unregister file format")) {
1309            Enumeration<Object> keys = FileFormat.getFileFormatKeys();
1310            ArrayList<Object> keylist = new ArrayList<Object>();
1311
1312            while (keys.hasMoreElements()) {
1313                keylist.add((Object)keys.nextElement());
1314            }
1315
1316            String theKey = (String) JOptionPane.showInputDialog(this, "Unregister a file format",
1317                    "Unregister a file format", JOptionPane.WARNING_MESSAGE, ViewProperties.getLargeHdfIcon(),
1318                    keylist.toArray(), null);
1319
1320            if (theKey == null) {
1321                return;
1322            }
1323
1324            FileFormat.removeFileFormat(theKey);
1325        }
1326        else if (cmd.equals("Users guide")) {
1327            String ugPath = ViewProperties.getUsersGuide();
1328
1329            // URL is invalid, use default path.
1330            if (ugPath == null || !ugPath.startsWith("http://")) {
1331                String sep = File.separator;
1332                File tmpFile = new File(ugPath);
1333                if (!(tmpFile.exists())) {
1334                    ugPath = rootDir + sep + "UsersGuide" + sep + "index.html";
1335                    tmpFile = new File(ugPath);
1336                    if (!(tmpFile.exists())) {
1337                        // use the online copy
1338                        ugPath = "http://www.hdfgroup.org/products/java/hdfview/UsersGuide/index.html";
1339                    }
1340                    ViewProperties.setUsersGuide(ugPath);
1341                }
1342            }
1343
1344            try {
1345                Tools.launchBrowser(ugPath);
1346            }
1347            catch (Exception ex) {
1348                JOptionPane.showMessageDialog(this, ex.getMessage(), "HDFView", JOptionPane.ERROR_MESSAGE,
1349                        ViewProperties.getLargeHdfIcon());
1350            }
1351        }
1352        else if (cmd.equals("HDF4 library")) {
1353            FileFormat thefile = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4);
1354            if (thefile == null) {
1355                return;
1356            }
1357
1358            JOptionPane.showMessageDialog(this, thefile.getLibversion(), "HDFView", JOptionPane.PLAIN_MESSAGE,
1359                    ViewProperties.getLargeHdfIcon());
1360        }
1361        else if (cmd.equals("HDF5 library")) {
1362            FileFormat thefile = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
1363            if (thefile == null) {
1364                return;
1365            }
1366
1367            JOptionPane.showMessageDialog(this, thefile.getLibversion(), "HDFView", JOptionPane.PLAIN_MESSAGE,
1368                    ViewProperties.getLargeHdfIcon());
1369        }
1370        else if (cmd.equals("Java version")) {
1371            String info = "Compiled at " + JAVA_COMPILER + "\nRunning at " + System.getProperty("java.version");
1372            JOptionPane.showMessageDialog(this, info, "HDFView", JOptionPane.PLAIN_MESSAGE,
1373                    ViewProperties.getLargeHdfIcon());
1374        }
1375        else if (cmd.equals("File format list")) {
1376            Enumeration<?> formatKeys = FileFormat.getFileFormatKeys();
1377
1378            String str = "\nSupported File Formats: \n";
1379            while (formatKeys.hasMoreElements()) {
1380                str += "    " + formatKeys.nextElement() + "\n";
1381            }
1382            str += "\n";
1383
1384            JOptionPane.showMessageDialog(this, str, "HDFView", JOptionPane.PLAIN_MESSAGE,
1385                    ViewProperties.getLargeHdfIcon());
1386        }
1387        else if (cmd.equals("About")) {
1388            JOptionPane.showMessageDialog(this, aboutHDFView, "HDFView", JOptionPane.PLAIN_MESSAGE,
1389                    ViewProperties.getLargeHdfIcon());
1390        }
1391        else if (cmd.equals("Popup URL list")) {
1392            urlBar.setPopupVisible(true);
1393        }
1394        else if (cmd.equals("Clear current selection")) {
1395            // urlBar.setPopupVisible(true);
1396            urlBar.setSelectedIndex(-1);
1397        }
1398        else {
1399            if ((helpViews == null) || (helpViews.size() <= 0)) {
1400                return;
1401            }
1402
1403            // try if one of the user help information;
1404            int n = helpViews.size();
1405            for (int i = 0; i < n; i++) {
1406                HelpView theView = (HelpView) helpViews.get(i);
1407                if (cmd.equals(theView.getActionCommand())) {
1408                    theView.show();
1409                    break;
1410                }
1411            } // for (int i=0; i<n; i++)
1412        }
1413    }
1414
1415    private void closeFile(FileFormat theFile) {
1416        if (theFile == null) {
1417            toolkit.beep();
1418            JOptionPane.showMessageDialog(this, "Select a file to close", getTitle(), JOptionPane.ERROR_MESSAGE);
1419            return;
1420        }
1421
1422        // close all the data windows of this file
1423        JInternalFrame[] frames = contentPane.getAllFrames();
1424        if (frames != null) {
1425            for (int i = 0; i < frames.length; i++) {
1426                HObject obj = (HObject) (((DataView) frames[i]).getDataObject());
1427                if (obj == null) {
1428                    continue;
1429                }
1430
1431                if (obj.getFileFormat().equals(theFile)) {
1432                    frames[i].dispose();
1433                    frames[i] = null;
1434                }
1435            }
1436        }
1437
1438        String fname = (String) urlBar.getSelectedItem();
1439        if (theFile.getFilePath().equals(fname)) {
1440            currentFile = null;
1441            urlBar.setSelectedIndex(-1);
1442        }
1443
1444        try {
1445            treeView.closeFile(theFile);
1446        }
1447        catch (Exception ex) {
1448        }
1449        theFile = null;
1450        attributeArea.setText("");
1451        System.gc();
1452    }
1453
1454    public void stateChanged(ChangeEvent e) {
1455        Object src = e.getSource();
1456
1457        log.trace("caught change event");
1458        if (src.equals(infoTabbedPane)) {
1459            int idx = infoTabbedPane.getSelectedIndex();
1460            if (idx == 1) {
1461                // meta info pane is selected
1462                attributeArea.setText("");
1463                showMetaData(treeView.getCurrentObject());
1464            }
1465        }
1466    }
1467
1468    public void dragEnter(DropTargetDragEvent evt) {
1469    }
1470
1471    @SuppressWarnings("unchecked")
1472    public void drop(DropTargetDropEvent evt) {
1473        try {
1474            final Transferable tr = evt.getTransferable();
1475
1476            if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
1477                evt.acceptDrop(DnDConstants.ACTION_COPY);
1478
1479                final List<?> fileList = (List<?>) tr.getTransferData(DataFlavor.javaFileListFlavor);
1480                int n = fileList.size();
1481                for (int i = 0; i < n; i++) {
1482                    File file = (File) fileList.get(i);
1483                    if (file.isDirectory()) continue;
1484
1485                    String filename = file.getAbsolutePath();
1486
1487                    currentFile = filename;
1488                    try {
1489                        treeView.openFile(filename, FileFormat.WRITE);
1490                    }
1491                    catch (Throwable ex) {
1492                        try {
1493                            treeView.openFile(filename, FileFormat.READ);
1494                        }
1495                        catch (Throwable ex2) {
1496                            String msg = "Failed to open file " + filename + "\n" + ex2;
1497                            toolkit.beep();
1498                            JOptionPane.showMessageDialog(this, msg, getTitle(), JOptionPane.ERROR_MESSAGE);
1499                            continue;
1500                        }
1501                    }
1502
1503                    try {
1504                        urlBar.removeItem(filename);
1505                        urlBar.insertItemAt(filename, 0);
1506                        urlBar.setSelectedIndex(0);
1507                    }
1508                    catch (Exception ex) {
1509                        log.debug("Unable to update urlBar:", ex);
1510                    }
1511
1512                }
1513                evt.getDropTargetContext().dropComplete(true);
1514            }
1515            else {
1516                evt.rejectDrop();
1517            }
1518        }
1519        catch (final IOException io) {
1520            evt.rejectDrop();
1521        }
1522        catch (final UnsupportedFlavorException ufe) {
1523            evt.rejectDrop();
1524        }
1525    }
1526
1527    public void dragExit(DropTargetEvent evt) {
1528    }
1529
1530    public void dropActionChanged(DropTargetDragEvent evt) {
1531    }
1532
1533    public void dragOver(DropTargetDragEvent dtde) {
1534    }
1535
1536    public void dispose() {
1537        try {
1538            props.save();
1539        }
1540        catch (Exception ex) {
1541        }
1542
1543        try {
1544            closeAllWindow();
1545        }
1546        catch (Exception ex) {
1547        }
1548
1549        // close all open files
1550        try {
1551            List<FileFormat> filelist = treeView.getCurrentFiles();
1552            if ((filelist != null) && (filelist.size() > 0)) {
1553                Object[] files = filelist.toArray();
1554                int n = files.length;
1555                for (int i = 0; i < n; i++) {
1556                    try {
1557                        treeView.closeFile((FileFormat) files[i]);
1558                    }
1559                    catch (Throwable ex) {
1560                        continue;
1561                    }
1562                }
1563            }
1564        }
1565        catch (Exception ex) {
1566        }
1567
1568        try {
1569            super.dispose();
1570        }
1571        catch (Exception ex) {
1572        }
1573
1574        System.exit(0);
1575    }
1576
1577    /** data content is displayed, and add the dataview to the main windows */
1578    public void addDataView(DataView dataView) {
1579        if (dataView == null) {
1580            return;
1581        }
1582        log.trace("addDataView: start");
1583
1584        if (!(dataView instanceof JInternalFrame)) {
1585            toolkit.beep();
1586            JOptionPane.showMessageDialog(this, "Unsupported DataView: the dataview is not a JInternalFrame.",
1587                    getTitle(), JOptionPane.ERROR_MESSAGE);
1588            return;
1589        }
1590
1591        // check if the data content is already displayed
1592        JInternalFrame[] frames = contentPane.getAllFrames();
1593        JInternalFrame theFrame = null;
1594        if (frames != null) {
1595            // test if the data is already displayed
1596            for (int i = 0; i < frames.length; i++) {
1597                if (dataView.equals(frames[i])) {
1598                    theFrame = frames[i];
1599                    break;
1600                }
1601            }
1602        }
1603
1604        if (theFrame != null) {
1605            // Data is already displayed. Just bring the dataview to the front
1606            theFrame.toFront();
1607            try {
1608                theFrame.setSelected(true);
1609            }
1610            catch (java.beans.PropertyVetoException e) {
1611            }
1612
1613            return;
1614        }
1615        log.trace("addDataView: not already displayed");
1616
1617        JInternalFrame frame = (JInternalFrame) dataView;
1618
1619        if (dataView instanceof TableView)
1620            if (((TableView) dataView).getTable() == null)
1621                return;
1622
1623        contentPane.add(frame);
1624        HObject dataObject = null;
1625        try {
1626            dataObject = dataView.getDataObject();
1627        }
1628        catch (Exception ex) {
1629            JOptionPane.showMessageDialog(this, ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE);
1630        }
1631        if (dataObject == null) {
1632            // toolkit.beep();
1633            // JOptionPane
1634            // .showMessageDialog(
1635            // this,
1636            // "Unsupported DataObject: the data object is not supported.",
1637            // getTitle(), JOptionPane.ERROR_MESSAGE);
1638            return;
1639
1640        }
1641        String fullPath = dataObject.getPath() + dataObject.getName();
1642        String cmd = "SHOW WINDOW" + dataObject.getFID() + fullPath;
1643        // make the window to be unique: fid+path
1644        log.trace("addDataView: cmd={}", cmd);
1645
1646        frame.setName(fullPath); // data windows are identified by full path the file
1647        // id
1648        frame.setMaximizable(true);
1649        frame.setClosable(true);
1650        frame.setResizable(true);
1651
1652        JMenuItem item = new JMenuItem(fullPath);
1653        item.setActionCommand(cmd);
1654        item.addActionListener(this);
1655
1656        if (windowMenu.getMenuComponentCount() == 6) {
1657            Component[] menuItems = windowMenu.getMenuComponents();
1658            for (int i = 0; i < 6; i++) {
1659                menuItems[i].setEnabled(true);
1660            }
1661        }
1662
1663        windowMenu.add(item);
1664
1665        frame.setLocation(frameOffset, frameOffset);
1666        if (frameOffset < 60) {
1667            frameOffset += 15;
1668        }
1669        else {
1670            frameOffset = 0;
1671        }
1672
1673        Dimension d = contentPane.getSize();
1674        frame.setSize(d.width - 60, d.height - 60);
1675        log.trace("addDataView: finish");
1676
1677        frame.show();
1678    }
1679
1680    /** data content is closed, and remove the dataview from the main window */
1681    public void removeDataView(DataView dataView) {
1682        if (!(dataView instanceof JInternalFrame)) {
1683            toolkit.beep();
1684            JOptionPane.showMessageDialog(this, "The dataview is not a JInternalFrame.", getTitle(),
1685                    JOptionPane.ERROR_MESSAGE);
1686            return;
1687        }
1688
1689        JInternalFrame frame = (JInternalFrame) dataView;
1690        String name = frame.getName();
1691
1692        int n = windowMenu.getItemCount();
1693        JMenuItem theItem = null;
1694        for (int i = 6; i < n; i++) {
1695            theItem = windowMenu.getItem(i);
1696
1697            if (theItem == null) {
1698                continue;
1699            }
1700
1701            if (theItem.getActionCommand().equals(name)) {
1702                windowMenu.remove(i);
1703                theItem = null;
1704                break;
1705            }
1706        }
1707
1708        if (windowMenu.getMenuComponentCount() == 6) {
1709            Component[] menuItems = windowMenu.getMenuComponents();
1710            for (int i = 0; i < 6; i++) {
1711                menuItems[i].setEnabled(false);
1712            }
1713        }
1714    }
1715
1716    public TreeView getTreeView() {
1717        return treeView;
1718    }
1719
1720    /** Tree mouse event fired */
1721    public void mouseEventFired(java.awt.event.MouseEvent e) {
1722        HObject obj = treeView.getCurrentObject();
1723
1724        if (obj == null) {
1725            return;
1726        }
1727
1728        Object src = e.getSource();
1729        if ((src instanceof JComponent)) {
1730            String filename = obj.getFile();
1731            urlBar.setSelectedItem(filename);
1732
1733            if (infoTabbedPane.getSelectedIndex() == 1) showMetaData(obj);
1734        }
1735    }
1736
1737    public void showMetaData(HObject obj) {
1738        if (obj == null || currentFile == null) return;
1739
1740        log.trace("showMetaData: start");
1741        metadata.setLength(0);
1742        metadata.append(obj.getName());
1743
1744        String oidStr = null;
1745        long[] OID = obj.getOID();
1746        if (OID != null) {
1747            oidStr = String.valueOf(OID[0]);
1748            for (int i = 1; i < OID.length; i++) {
1749                oidStr += ", " + OID[i];
1750            }
1751        }
1752        metadata.append(" (");
1753        metadata.append(oidStr);
1754        metadata.append(")");
1755
1756        if (obj instanceof Group) {
1757            log.trace("showMetaData: instanceof Group");
1758            Group g = (Group) obj;
1759            metadata.append("\n    Group size = ");
1760            metadata.append(g.getMemberList().size());
1761        }
1762        else if (obj instanceof Dataset) {
1763            log.trace("showMetaData: instanceof Dataset");
1764            Dataset d = (Dataset) obj;
1765            if (d.getRank() <= 0) {
1766                d.init();
1767            }
1768            log.trace("showMetaData: inited");
1769
1770            metadata.append("\n    ");
1771            if (d instanceof ScalarDS) {
1772                Datatype dtype = d.getDatatype();
1773                if (dtype != null) metadata.append(dtype.getDatatypeDescription());
1774            }
1775            else if (d instanceof CompoundDS) {
1776                metadata.append("Compound/Vdata");
1777            }
1778            metadata.append(",    ");
1779
1780            long dims[] = d.getDims();
1781
1782            if (dims != null) {
1783                metadata.append(dims[0]);
1784                for (int i = 1; i < dims.length; i++) {
1785                    metadata.append(" x ");
1786                    metadata.append(dims[i]);
1787                }
1788            }
1789        } // else if (obj instanceof Dataset)
1790        else {
1791            log.debug("obj not instanceof Group or Dataset");
1792        }
1793
1794        List<?> attrList = null;
1795        try {
1796            log.trace("showMetaData: getMetadata");
1797            attrList = obj.getMetadata();
1798        }
1799        catch (Exception ex) {
1800            log.debug("getMetadata failure: ", ex);
1801        }
1802
1803        if (attrList == null) {
1804            metadata.append("\n    Number of attributes = 0");
1805        }
1806        else {
1807            int n = attrList.size();
1808            log.trace("showMetaData: append {} attributes", n);
1809            metadata.append("\n    Number of attributes = ");
1810            metadata.append(n);
1811
1812            for (int i = 0; i < n; i++) {
1813                log.trace("showMetaData: append Object[{}]", i);
1814                Object attrObj = attrList.get(i);
1815                if (!(attrObj instanceof Attribute)) {
1816                    continue;
1817                }
1818                Attribute attr = (Attribute) attrObj;
1819                metadata.append("\n        ");
1820                metadata.append(attr.getName());
1821                metadata.append(" = ");
1822                metadata.append(attr.toString(","));
1823                log.trace("showMetaData: append Object[{}]={}", i, attr.getName());
1824            }
1825        }
1826
1827        attributeArea.setText(metadata.toString());
1828        attributeArea.setCaretPosition(0);
1829        log.trace("showMetaData: finish");
1830    }
1831
1832    /**
1833     * Returns DataView contains the specified data object. It is useful to
1834     * avoid redundant display of data object that is opened already.
1835     *
1836     * @param dataObject
1837     *            the whose presence in the main view is to be tested.
1838     * @return DataView contains the specified data object, null if the data
1839     *         object is not displayed.
1840     */
1841    public DataView getDataView(HObject dataObject) {
1842        if (dataObject == null) {
1843            return null;
1844        }
1845
1846        // check if the data content is already displayed
1847        JInternalFrame[] frames = contentPane.getAllFrames();
1848        JInternalFrame theFrame = null;
1849
1850        if (frames == null) {
1851            return null;
1852        }
1853
1854        HObject obj = null;
1855        for (int i = 0; i < frames.length; i++) {
1856            if (!(frames[i] instanceof DataView)) {
1857                continue;
1858            }
1859
1860            obj = (HObject) (((DataView) frames[i]).getDataObject());
1861            if (dataObject.equals(obj)) {
1862                theFrame = frames[i];
1863                break; // data is already displayed
1864            }
1865        }
1866
1867        return (DataView) theFrame;
1868    }
1869
1870    /**
1871     * Returns a list of all open DataViews
1872     *
1873     * @return A list of all open DataViews
1874     */
1875    public List<JInternalFrame> getDataViews() {
1876        // check if the data content is already displayed
1877        JInternalFrame[] frames = contentPane.getAllFrames();
1878
1879        if ((frames == null) || (frames.length <= 0)) {
1880            return null;
1881        }
1882
1883        Vector<JInternalFrame> views = new Vector<JInternalFrame>(frames.length);
1884        for (int i = 0; i < frames.length; i++) {
1885            if (!(frames[i] instanceof DataView)) {
1886                continue;
1887            }
1888            else {
1889                views.add(frames[i]);
1890            }
1891        }
1892
1893        return views;
1894    }
1895
1896    /**
1897     * @return a list of treeview implementations.
1898     */
1899    public static final List<String> getListOfTreeView() {
1900        return treeViews;
1901    }
1902
1903    /**
1904     * @return a list of imageview implementations.
1905     */
1906    public static final List<String> getListOfImageView() {
1907        return imageViews;
1908    }
1909
1910    /**
1911     * @return a list of tableview implementations.
1912     */
1913    public static final List<?> getListOfTableView() {
1914        return tableViews;
1915    }
1916
1917    /**
1918     * @return a list of textview implementations.
1919     */
1920    public static final List<?> getListOfTextView() {
1921        return textViews;
1922    }
1923
1924    /**
1925     * @return a list of metaDataview implementations.
1926     */
1927    public static final List<?> getListOfMetaDataView() {
1928        return metaDataViews;
1929    }
1930
1931    /**
1932     * @return a list of paletteview implementations.
1933     */
1934    public static final List<?> getListOfPaletteView() {
1935        return paletteViews;
1936    }
1937
1938    /**
1939     * Display feedback message.
1940     *
1941     * @param msg
1942     *            the message to display.
1943     */
1944    public void showStatus(String msg) {
1945        message.append(msg);
1946        message.append("\n");
1947        statusArea.setText(message.toString());
1948    }
1949
1950    public void reloadFile() {
1951        int temp_index_type = 0;
1952        int temp_index_order = 0;
1953
1954        FileFormat theFile = treeView.getSelectedFile();
1955        if (theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) {
1956            temp_index_type = theFile.getIndexType(null);
1957            temp_index_order = theFile.getIndexOrder(null);
1958        }
1959        closeFile(theFile);
1960
1961        if (theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) {
1962            theFile.setIndexType(temp_index_type);
1963            theFile.setIndexOrder(temp_index_order);
1964        }
1965        try {
1966            treeView.reopenFile(theFile);
1967        }
1968        catch (Exception ex) {
1969        }
1970    }
1971
1972    /** choose local file */
1973    private String openLocalFile() {
1974        log.info("openLocalFile: CurrentDir is {}", currentDir);
1975        JFileChooser fchooser = new JFileChooser(currentDir);
1976        fchooser.setFileFilter(DefaultFileFilter.getFileFilter());
1977
1978        int returnVal = fchooser.showOpenDialog(this);
1979
1980        if (returnVal != JFileChooser.APPROVE_OPTION) {
1981            return null;
1982        }
1983
1984        File choosedFile = fchooser.getSelectedFile();
1985        if (choosedFile == null) {
1986            return null;
1987        }
1988
1989        if (choosedFile.isDirectory()) {
1990            currentDir = choosedFile.getPath();
1991        }
1992        else {
1993            currentDir = choosedFile.getParent();
1994        }
1995
1996        return choosedFile.getAbsolutePath();
1997    }
1998
1999    /** Load remote file and save it to local temporary directory */
2000    private String openRemoteFile(String urlStr) {
2001        if (urlStr == null)
2002            return null;
2003
2004        String localFile = null;
2005
2006        if(urlStr.startsWith("http://")) {
2007            localFile = urlStr.substring(7);
2008        }
2009        else if (urlStr.startsWith("ftp://")) {
2010            localFile = urlStr.substring(6);
2011        }
2012        else {
2013            return null;
2014        }
2015
2016        localFile = localFile.replace('/', '@');
2017        localFile = localFile.replace('\\', '@');
2018
2019        // Search the local file cache
2020        String tmpDir = System.getProperty("java.io.tmpdir");
2021
2022        File tmpFile = new File(tmpDir);
2023        if (!tmpFile.canWrite()) tmpDir = System.getProperty("user.home");
2024
2025        localFile = tmpDir + File.separator + localFile;
2026
2027        tmpFile = new File(localFile);
2028        if (tmpFile.exists())
2029            return localFile;
2030
2031        URL url = null;
2032
2033        try {
2034            url = new URL(urlStr);
2035        }
2036        catch (Exception ex) {
2037            url = null;
2038            toolkit.beep();
2039            JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
2040            return null;
2041        }
2042
2043        BufferedInputStream in = null;
2044        BufferedOutputStream out = null;
2045
2046        try {
2047            in = new BufferedInputStream(url.openStream());
2048            out = new BufferedOutputStream(new FileOutputStream(tmpFile));
2049        }
2050        catch (Exception ex) {
2051            in = null;
2052            toolkit.beep();
2053            JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
2054            try {
2055                out.close();
2056            }
2057            catch (Exception ex2) {
2058                log.debug("Remote file: ", ex2);
2059            }
2060
2061            return null;
2062        }
2063
2064        setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
2065        byte[] buff = new byte[512]; // set the default buff size to 512
2066        try {
2067            int n = 0;
2068            while ((n = in.read(buff)) > 0) {
2069                out.write(buff, 0, n);
2070            }
2071        }
2072        catch (Exception ex) {
2073            log.debug("Remote file: ", ex);
2074        }
2075
2076        try {
2077            in.close();
2078        }
2079        catch (Exception ex) {
2080            log.debug("Remote file: ", ex);
2081        }
2082
2083        try {
2084            out.close();
2085        }
2086        catch (Exception ex) {
2087            log.debug("Remote file: ", ex);
2088        }
2089
2090        setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
2091
2092        return localFile;
2093    }
2094
2095    /** open file from SRB server */
2096    private void openFromSRB() throws Exception {
2097        if (ctrSrbFileDialog == null) {
2098            Class<?> theClass = null;
2099
2100            try {
2101                theClass = Class.forName("hdf.srb.SRBFileDialog");
2102            }
2103            catch (Exception ex) {
2104                theClass = null;
2105                showStatus(ex.toString());
2106                throw (new ClassNotFoundException("Cannot find SRBFileDialog"));
2107            }
2108
2109            try {
2110                @SuppressWarnings("rawtypes")
2111                Class[] paramClass = { Class.forName("java.awt.Frame") };
2112                ctrSrbFileDialog = theClass.getConstructor(paramClass);
2113            }
2114            catch (Exception ex) {
2115                ctrSrbFileDialog = null;
2116                throw (new InstantiationException("Cannot construct SRBFileDialog"));
2117            }
2118        }
2119
2120        if (srbFileDialog == null) {
2121            try {
2122                Object[] paramObj = { (java.awt.Frame) this };
2123                srbFileDialog = (JDialog) ctrSrbFileDialog.newInstance(paramObj);
2124            }
2125            catch (Exception ex) {
2126                throw ex;
2127            }
2128        }
2129        else {
2130            srbFileDialog.setVisible(true);
2131        }
2132
2133        currentFile = srbFileDialog.getName();
2134    }
2135
2136    /**
2137     * The starting point of this application.
2138     *
2139     * <pre>
2140     * Usage: java(w)
2141     *        -Dhdf.hdf5lib.H5.hdf5lib="your HDF5 library path"
2142     *        -Dhdf.hdflib.HDFLibrary.hdflib="your HDF4 library path"
2143     *        -root "the directory where the HDFView is installed"
2144     *        [filename] "the file to open"
2145     * </pre>
2146     *
2147     * @param args  the command line arguments
2148     */
2149    public static void main(String[] args) {
2150        String rootDir = System.getProperty("hdfview.workdir");
2151        log.trace("main: rootDir = {} ", rootDir);
2152        if(rootDir == null) rootDir = System.getProperty("user.dir");
2153
2154        File tmpFile = null;
2155        int j = args.length;
2156        int W = 0, H = 0, X = 0, Y = 0;
2157
2158        for(int i = 0; i < args.length; i++) {
2159            if ("-root".equalsIgnoreCase(args[i])) {
2160                j--;
2161                try {
2162                    j--;
2163                    tmpFile = new File(args[++i]);
2164
2165                    if(tmpFile.isDirectory()) {
2166                        rootDir = tmpFile.getPath();
2167                    }
2168                    else if(tmpFile.isFile()) {
2169                        rootDir = tmpFile.getParent();
2170                    }
2171                }
2172                catch (Exception ex) {}
2173            }
2174            else if("-g".equalsIgnoreCase(args[i]) || "-geometry".equalsIgnoreCase(args[i])) {
2175                j--;
2176                // -geometry WIDTHxHEIGHT+XOFF+YOFF
2177                try {
2178                    String geom = args[++i];
2179                    j--;
2180
2181                    int idx = 0;
2182                    int idx2 = geom.lastIndexOf('-');
2183                    int idx3 = geom.lastIndexOf('+');
2184
2185                    idx = Math.max(idx2, idx3);
2186                    if(idx > 0) {
2187                        Y = Integer.parseInt(geom.substring(idx + 1));
2188
2189                        if(idx == idx2)
2190                            Y = -Y;
2191
2192                        geom = geom.substring(0, idx);
2193                        idx2 = geom.lastIndexOf('-');
2194                        idx3 = geom.lastIndexOf('+');
2195                        idx = Math.max(idx2, idx3);
2196
2197                        if(idx > 0) {
2198                            X = Integer.parseInt(geom.substring(idx + 1));
2199
2200                            if(idx == idx2)
2201                                X = -X;
2202
2203                            geom = geom.substring(0, idx);
2204                        }
2205                    }
2206
2207                    idx = geom.indexOf('x');
2208
2209                    if(idx > 0) {
2210                        W = Integer.parseInt(geom.substring(0, idx));
2211                        H = Integer.parseInt(geom.substring(idx + 1));
2212                    }
2213
2214                }
2215                catch (Exception ex) {
2216                    ex.printStackTrace();
2217                }
2218            }
2219            else if ("-java.version".equalsIgnoreCase(args[i])) {
2220                String info = "Compiled at " + JAVA_COMPILER + "\nRunning at " + System.getProperty("java.version");
2221                JOptionPane.showMessageDialog(new JFrame(), info, "HDFView", JOptionPane.PLAIN_MESSAGE,
2222                        ViewProperties.getLargeHdfIcon());
2223                System.exit(0);
2224            }
2225        }
2226
2227        Vector<File> flist = new Vector<File>();
2228        tmpFile = null;
2229        if (j >= 0) {
2230            for (int i=args.length-j; i < args.length; i++) {
2231                tmpFile = new File(rootDir, args[i]);
2232                log.trace("main: filelist - file = {} ", tmpFile.getAbsolutePath());
2233                log.trace("main: filelist - add file = {} exists={} isFile={} isDir={}", tmpFile, tmpFile.exists(), tmpFile.isFile(), tmpFile.isDirectory());
2234                if (tmpFile.exists() && (tmpFile.isFile() || tmpFile.isDirectory())) {
2235                    log.trace("main: flist - add file = {}", tmpFile.getAbsolutePath());
2236                    flist.add(new File(tmpFile.getAbsolutePath()));
2237                }
2238            }
2239        }
2240
2241        final Vector<File> the_flist = flist;
2242        final String the_rootDir = rootDir;
2243        final int the_X = X, the_Y = Y, the_W = W, the_H = H;
2244
2245        log.trace("main: flist.size={} - the_rootDir={}", the_flist.size(), the_rootDir);
2246        // Schedule a job for the event-dispatching thread:
2247        // creating and showing this application's GUI.
2248        javax.swing.SwingUtilities.invokeLater(new Runnable() {
2249            public void run() {
2250                HDFView frame = new HDFView(the_rootDir, the_flist, the_W, the_H, the_X, the_Y);
2251                frame.setVisible(true);
2252            }
2253        });
2254    }
2255}