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.Color;
018import java.awt.Component;
019import java.awt.Cursor;
020import java.awt.GridLayout;
021import java.awt.Point;
022import java.awt.Toolkit;
023import java.awt.event.ActionEvent;
024import java.awt.event.ActionListener;
025import java.awt.event.KeyAdapter;
026import java.awt.event.KeyEvent;
027import java.awt.event.MouseAdapter;
028import java.awt.event.MouseEvent;
029import java.io.BufferedInputStream;
030import java.io.BufferedOutputStream;
031import java.io.File;
032import java.io.FileInputStream;
033import java.io.FileOutputStream;
034import java.io.FileNotFoundException;
035import java.io.Serializable;
036import java.lang.reflect.Constructor;
037import java.lang.reflect.Method;
038import java.util.BitSet;
039import java.util.Enumeration;
040import java.util.HashMap;
041import java.util.Iterator;
042import java.util.List;
043import java.util.Vector;
044
045import javax.swing.BorderFactory;
046import javax.swing.ButtonGroup;
047import javax.swing.Icon;
048import javax.swing.JButton;
049import javax.swing.JComboBox;
050import javax.swing.JComponent;
051import javax.swing.JDialog;
052import javax.swing.JFileChooser;
053import javax.swing.JFrame;
054import javax.swing.JInternalFrame;
055import javax.swing.JMenu;
056import javax.swing.JMenuItem;
057import javax.swing.JOptionPane;
058import javax.swing.JPanel;
059import javax.swing.JPopupMenu;
060import javax.swing.JRadioButton;
061import javax.swing.JSeparator;
062import javax.swing.JTree;
063import javax.swing.border.BevelBorder;
064import javax.swing.border.SoftBevelBorder;
065import javax.swing.border.TitledBorder;
066import javax.swing.tree.DefaultMutableTreeNode;
067import javax.swing.tree.DefaultTreeCellRenderer;
068import javax.swing.tree.DefaultTreeModel;
069import javax.swing.tree.MutableTreeNode;
070import javax.swing.tree.TreeNode;
071import javax.swing.tree.TreePath;
072
073import hdf.object.CompoundDS;
074import hdf.object.Dataset;
075import hdf.object.Datatype;
076import hdf.object.FileFormat;
077import hdf.object.Group;
078import hdf.object.HObject;
079import hdf.object.ScalarDS;
080import hdf.view.ViewProperties.DATA_VIEW_KEY;
081
082/**
083 * <p>
084 * TreeView defines APIs for opening files and displaying the file structure in
085 * a tree structure.
086 *
087 * <p>
088 * TreeView uses folders and leaf items to represent groups and data objects in
089 * the file. You can expand or collapse folders to navigate data objects in the
090 * file.
091 *
092 * <p>
093 * From the TreeView, you can open data content or metadata of the selected object.
094 * You can select object(s) to delete or add new objects to the file.
095 */
096public class DefaultTreeView extends JPanel implements TreeView, ActionListener {
097    private static final long            serialVersionUID    = 4092566164712521186L;
098
099    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultTreeView.class);
100
101    /** The owner of this TreeView */
102    private ViewManager                  viewer;
103
104    /**
105     * The super root of tree: all open files start at this root.
106     */
107    private final DefaultMutableTreeNode root;
108
109    /**
110     * The tree which holds file structures.
111     */
112    private final JTree                  tree;
113
114    /** The currently selected tree node. */
115    private DefaultMutableTreeNode       selectedNode = null;
116
117    /** the list of current selected objects */
118    private List<Object>                 objectsToCopy = null;
119
120    private TreePath[]                   currentSelectionsForMove = null;
121
122    /** The currently selected object */
123    private HObject                      selectedObject;
124
125    /** The currently selected file */
126    private FileFormat                   selectedFile;
127
128    /** The current selected TreePath. */
129    private TreePath                     selectedTreePath;
130
131    /** The tree model */
132    private final DefaultTreeModel       treeModel;
133
134    /** A list of currently open files */
135    private List<FileFormat>        fileList = new Vector<>();
136
137    /** A list of editing GUI components */
138    private List<JMenuItem>              editGUIs = new Vector<>();
139
140    /**
141     * The popup menu used to display user choice of actions on data object.
142     */
143    private final JPopupMenu             popupMenu;
144
145    private JMenu                        exportDatasetMenu;
146
147    private JSeparator                   separator;
148
149    private JMenuItem                    addDatasetMenuItem;
150    private JMenuItem                    addTableMenuItem;
151    private JMenuItem                    addDatatypeMenuItem;
152    private JMenuItem                    addLinkMenuItem;
153    private JMenuItem                    setLibVerBoundsItem;
154    private JMenuItem                    changeIndexItem;
155
156    private final Toolkit                toolkit;
157
158    /** Flag to indicate if the dataset is displayed as default */
159    private boolean                      isDefaultDisplay = true;
160
161    /** Flag to indicate if TreeItems are being moved */
162    private boolean                      moveFlag = false;
163
164    private boolean                      isApplyBitmaskOnly  = false;
165
166    private int                          currentIndexType;
167
168    private int                          currentIndexOrder;
169
170    private int                          binaryOrder;
171
172    private String                       currentSearchPhrase = null;
173
174    private enum OBJECT_TYPE {GROUP, DATASET, IMAGE, TABLE, DATATYPE, LINK};
175
176    public DefaultTreeView(ViewManager theView) {
177        viewer = theView;
178
179        root = new DefaultMutableTreeNode() {
180            private static final long serialVersionUID = -6829919815424470510L;
181
182            public boolean isLeaf() {
183                return false;
184            }
185        };
186
187        fileList = new Vector<FileFormat>();
188        toolkit = Toolkit.getDefaultToolkit();
189        editGUIs = new Vector<JMenuItem>();
190        objectsToCopy = null;
191        isDefaultDisplay = true;
192        selectedTreePath = null;
193        selectedNode = null;
194        moveFlag = false;
195        currentSelectionsForMove = null;
196
197        addDatasetMenuItem = new JMenuItem("Dataset", ViewProperties.getDatasetIcon());
198        addDatasetMenuItem.addActionListener(this);
199        addDatasetMenuItem.setActionCommand("Add dataset");
200
201        addTableMenuItem = new JMenuItem("Compound DS", ViewProperties.getTableIcon());
202        addTableMenuItem.addActionListener(this);
203        addTableMenuItem.setActionCommand("Add table");
204
205        addDatatypeMenuItem = new JMenuItem("Datatype", ViewProperties.getDatatypeIcon());
206        addDatatypeMenuItem.addActionListener(this);
207        addDatatypeMenuItem.setActionCommand("Add datatype");
208
209        addLinkMenuItem = new JMenuItem("Link", ViewProperties.getLinkIcon());
210        addLinkMenuItem.addActionListener(this);
211        addLinkMenuItem.setActionCommand("Add link");
212
213        setLibVerBoundsItem = new JMenuItem("Set Lib version bounds");
214        setLibVerBoundsItem.addActionListener(this);
215        setLibVerBoundsItem.setActionCommand("Set Lib version bounds");
216
217        changeIndexItem = new JMenuItem("Change file indexing");
218        changeIndexItem.addActionListener(this);
219        changeIndexItem.setActionCommand("Change file indexing");
220
221        // initialize the tree and root
222        treeModel = new DefaultTreeModel(root);
223        tree = new JTree(treeModel);
224
225        tree.setLargeModel(true);
226        tree.setCellRenderer(new HTreeCellRenderer());
227        tree.addMouseListener(new HTreeMouseAdapter());
228        tree.addKeyListener(new HTreeKeyAdapter());
229        tree.setRootVisible(false);
230        // tree.setShowsRootHandles(true);
231        int rowheight = 23 + (int) ((tree.getFont().getSize() - 12) * 0.5);
232        tree.setRowHeight(rowheight);
233
234        // create the separator
235        separator = new JPopupMenu.Separator();
236
237        // create the popupmenu
238        popupMenu = createPopupMenu();
239
240        // reset the scroll increament
241        // layout GUI component
242        this.setLayout(new BorderLayout());
243        this.add(tree, BorderLayout.CENTER);
244    }
245
246    /** Creates a popup menu for a right mouse click on a data object */
247    private JPopupMenu createPopupMenu() {
248        JPopupMenu menu = new JPopupMenu();
249        JMenuItem item;
250
251        item = new JMenuItem("Open");
252        item.setMnemonic(KeyEvent.VK_O);
253        item.addActionListener(this);
254        item.setActionCommand("Open data");
255        menu.add(item);
256
257        item = new JMenuItem("Open As");
258        item.setMnemonic(KeyEvent.VK_A);
259        item.addActionListener(this);
260        item.setActionCommand("Open data as");
261        menu.add(item);
262
263        menu.addSeparator();
264
265        JMenu newOjbectMenu = new JMenu("New");
266        menu.add(newOjbectMenu);
267        editGUIs.add(newOjbectMenu);
268
269        item = new JMenuItem("Group", ViewProperties.getFoldercloseIcon());
270        item.addActionListener(this);
271        item.setActionCommand("Add group");
272        newOjbectMenu.add(item);
273
274        newOjbectMenu.add(addDatasetMenuItem);
275
276        item = new JMenuItem("Image", ViewProperties.getImageIcon());
277        item.addActionListener(this);
278        item.setActionCommand("Add image");
279        newOjbectMenu.add(item);
280
281        newOjbectMenu.add(addTableMenuItem);
282        newOjbectMenu.add(addDatatypeMenuItem);
283        newOjbectMenu.add(addLinkMenuItem);
284
285        menu.addSeparator();
286
287        item = new JMenuItem("Copy");
288        item.setMnemonic(KeyEvent.VK_C);
289        item.addActionListener(this);
290        item.setActionCommand("Copy object");
291        menu.add(item);
292
293        item = new JMenuItem("Paste");
294        item.setMnemonic(KeyEvent.VK_P);
295        item.addActionListener(this);
296        item.setActionCommand("Paste object");
297        menu.add(item);
298        editGUIs.add(item);
299
300        item = new JMenuItem("Delete");
301        item.setMnemonic(KeyEvent.VK_D);
302        item.addActionListener(this);
303        item.setActionCommand("Cut object");
304        menu.add(item);
305        editGUIs.add(item);
306
307        item = new JMenuItem("Cut");
308        item.setMnemonic(KeyEvent.VK_T);
309        item.addActionListener(this);
310        item.setActionCommand("Move object");
311        menu.add(item);
312        editGUIs.add(item);
313
314        exportDatasetMenu = new JMenu("Export Dataset");
315        menu.add(exportDatasetMenu);
316        item = new JMenuItem("Export Data to Text File");
317        item.addActionListener(this);
318        item.setActionCommand("Save table as text");
319        exportDatasetMenu.add(item);
320
321        item = new JMenuItem("Export Data as Native Order");
322        item.addActionListener(this);
323        item.setActionCommand("Save table as binary Native Order");
324        exportDatasetMenu.add(item);
325        item = new JMenuItem("Export Data as Little Endian");
326        item.addActionListener(this);
327        item.setActionCommand("Save table as binary Little Endian");
328        exportDatasetMenu.add(item);
329        item = new JMenuItem("Export Data as Big Endian");
330        item.addActionListener(this);
331        item.setActionCommand("Save table as binary Big Endian");
332        exportDatasetMenu.add(item);
333
334        menu.addSeparator();
335
336        item = new JMenuItem("Save to");
337        item.setMnemonic(KeyEvent.VK_S);
338        item.addActionListener(this);
339        item.setActionCommand("Save object to file");
340        menu.add(item);
341
342        item = new JMenuItem("Rename");
343        item.setMnemonic(KeyEvent.VK_R);
344        item.addActionListener(this);
345        item.setActionCommand("Rename object");
346        menu.add(item);
347        editGUIs.add(item);
348
349        menu.addSeparator();
350
351        item = new JMenuItem("Show Properties");
352        item.addActionListener(this);
353        item.setActionCommand("Show object properties");
354        menu.add(item);
355
356        item = new JMenuItem("Show Properties As");
357        item.addActionListener(this);
358        item.setActionCommand("Show object properties as");
359        menu.add(item);
360
361        menu.add(changeIndexItem);
362
363        menu.addSeparator();
364
365        item = new JMenuItem("Find");
366        item.setMnemonic(KeyEvent.VK_F);
367        item.addActionListener(this);
368        item.setActionCommand("Find");
369        menu.add(item);
370
371        // item = new JMenuItem( "Find Next");
372        // item.setMnemonic(KeyEvent.VK_N);
373        // item.addActionListener(this);
374        // item.setActionCommand("Find next");
375        // menu.add(item);
376
377        menu.addSeparator();
378
379        item = new JMenuItem("Expand All");
380        item.addActionListener(this);
381        item.setActionCommand("Expand all");
382        menu.add(item);
383        item = new JMenuItem("Collapse All");
384        item.addActionListener(this);
385        item.setActionCommand("Collapse all");
386        menu.add(item);
387
388        menu.addSeparator();
389
390        item = new JMenuItem("Close File");
391        item.setMnemonic(KeyEvent.VK_E);
392        item.addActionListener(this);
393        item.setActionCommand("Close file");
394        menu.add(item);
395
396        item = new JMenuItem("Reload File");
397        // item.setMnemonic(KeyEvent.VK_R);
398        item.addActionListener(this);
399        item.setActionCommand("Reload file");
400        menu.add(item);
401
402        menu.add(separator);
403        menu.add(setLibVerBoundsItem);
404
405        return menu;
406    }
407
408    /** display the popupmenu of data properties */
409    private void showPopupMenu(MouseEvent e) {
410        int x = e.getX();
411        int y = e.getY();
412
413        HObject selectedObject = ((HObject) (selectedNode.getUserObject()));
414        boolean isReadOnly = selectedObject.getFileFormat().isReadOnly();
415        boolean isWritable = !isReadOnly;
416
417        setEnabled(editGUIs, !isReadOnly);
418
419        if (selectedObject instanceof Group) {
420            boolean state = !(((Group) selectedObject).isRoot());
421
422            popupMenu.getComponent(0).setEnabled(false); // "Open" menuitem
423            popupMenu.getComponent(1).setEnabled(false); // "Open as" menuitem
424            popupMenu.getComponent(8).setEnabled(
425                    (selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5)))
426                    && state && isWritable); // "Cut" menuitem
427            popupMenu.getComponent(5).setEnabled(state); // "Copy" menuitem
428            popupMenu.getComponent(6).setEnabled(isWritable); // "Paste" menuitem
429            popupMenu.getComponent(7).setEnabled(state && isWritable); // "Delete" menuitem
430            popupMenu.getComponent(11).setEnabled(state); // "Save to" menuitem
431            popupMenu.getComponent(12).setEnabled(state && isWritable); // "Rename" menuitem
432        }
433        else {
434            popupMenu.getComponent(0).setEnabled(true); // "Open" menuitem
435            popupMenu.getComponent(1).setEnabled(true); // "Open as" menuitem
436            popupMenu.getComponent(8).setEnabled(
437                    (selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5)))
438                    && isWritable); // "Cut" menuitem
439            popupMenu.getComponent(5).setEnabled(true); // "Copy" menuitem
440            popupMenu.getComponent(6).setEnabled(isWritable); // "Paste" menuitem
441            popupMenu.getComponent(7).setEnabled(isWritable); // "Delete" menuitem
442            popupMenu.getComponent(11).setEnabled(true); // "Save to" menuitem
443            popupMenu.getComponent(12).setEnabled(isWritable); // "Rename" menuitem
444        }
445
446                // Adding table is only supported by HDF5
447        if ((selectedFile != null) && selectedFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) {
448            addDatasetMenuItem.setText("Dataset");
449            addTableMenuItem.setVisible(true);
450            addDatatypeMenuItem.setVisible(true);
451            addLinkMenuItem.setVisible(true);
452            boolean state = false;
453            if ((selectedObject instanceof Group)) {
454                state = (((Group) selectedObject).isRoot());
455                separator.setVisible(isWritable && state);
456                setLibVerBoundsItem.setVisible(isWritable && state); // added only if it is HDF5format, iswritable & isroot
457            }
458            else {
459                separator.setVisible(false);
460                setLibVerBoundsItem.setVisible(false);
461            }
462            changeIndexItem.setVisible(state);
463        }
464        else {
465            addDatasetMenuItem.setText("SDS");
466            addTableMenuItem.setVisible(false);
467            addDatatypeMenuItem.setVisible(false);
468            addLinkMenuItem.setVisible(false);
469            separator.setVisible(false);
470            setLibVerBoundsItem.setVisible(false);
471            changeIndexItem.setVisible(false);
472        }
473
474                // Export table is only supported by HDF5
475        if ((selectedObject != null) && selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) {
476            if ((selectedObject instanceof Dataset)) {
477                Dataset dataset = (Dataset) selectedObject;
478                if ((dataset instanceof ScalarDS)) {
479                    exportDatasetMenu.setVisible(true);
480                }
481            }
482            else {
483                exportDatasetMenu.setVisible(false);
484            }
485        }
486        else {
487            exportDatasetMenu.setVisible(false);
488        }
489
490        popupMenu.show((JComponent) e.getSource(), x, y);
491    }
492
493    // Implementing java.io.ActionListener
494    public void actionPerformed(ActionEvent e) {
495        String cmd = e.getActionCommand();
496
497        if (cmd.equals("Close file")) {
498            ((HDFView) viewer).actionPerformed(e);
499        }
500        else if (cmd.equals("Reload file")) {
501            ((HDFView) viewer).actionPerformed(e);
502        }
503        else if (cmd.equals("Add group")) {
504            addGroup();
505        }
506        else if (cmd.equals("Add dataset")) {
507            addDataset();
508        }
509        else if (cmd.equals("Add image")) {
510            addImage();
511        }
512        else if (cmd.equals("Add table")) {
513            addTable();
514        }
515        else if (cmd.equals("Add datatype")) {
516            addDatatype();
517        }
518        else if (cmd.equals("Add link")) {
519            addLink();
520        }
521        else if (cmd.equals("Save table as text")) {
522            binaryOrder = 99;
523            try {
524                saveAsFile();
525            }
526            catch (Exception ex) {
527                toolkit.beep();
528                JOptionPane.showMessageDialog((JFrame) viewer, ex, "Export Dataset", JOptionPane.ERROR_MESSAGE);
529            }
530        }
531        else if (cmd.startsWith("Save table as binary")) {
532            if (cmd.equals("Save table as binary Native Order")) binaryOrder = 1;
533            if (cmd.equals("Save table as binary Little Endian")) binaryOrder = 2;
534            if (cmd.equals("Save table as binary Big Endian")) binaryOrder = 3;
535            try {
536                saveAsFile();
537            }
538            catch (Exception ex) {
539                toolkit.beep();
540                JOptionPane.showMessageDialog((JFrame) viewer, ex, "Export Dataset", JOptionPane.ERROR_MESSAGE);
541            }
542        }
543        else if (cmd.startsWith("Open data")) {
544            if (cmd.equals("Open data")) {
545                isDefaultDisplay = true;
546            }
547            else {
548                isDefaultDisplay = false;
549            }
550
551            try {
552                showDataContent(selectedObject);
553            }
554            catch (Throwable err) {
555                toolkit.beep();
556                JOptionPane.showMessageDialog(this, err, "HDFView", JOptionPane.ERROR_MESSAGE);
557                return;
558            }
559        }
560        else if (cmd.equals("Copy object")) {
561            copyObject();
562        }
563        else if (cmd.equals("Paste object")) {
564            pasteObject();
565        }
566        else if (cmd.equals("Cut object")) {
567            cutObject();
568        }
569        else if (cmd.equals("Move object")) {
570            moveObject();
571        }
572        else if (cmd.equals("Save object to file")) {
573            if (selectedObject == null) {
574                return;
575            }
576
577            if ((selectedObject instanceof Group) && ((Group) selectedObject).isRoot()) {
578                toolkit.beep();
579                JOptionPane.showMessageDialog(this,
580                        "Cannot save the root group.\nUse \"Save As\" from file menu to save the whole file",
581                        "HDFView", JOptionPane.ERROR_MESSAGE);
582                return;
583            }
584
585            String filetype = FileFormat.FILE_TYPE_HDF4;
586            boolean isH5 = selectedObject.getFileFormat().isThisType(
587                    FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
588            if (isH5) {
589                filetype = FileFormat.FILE_TYPE_HDF5;
590            }
591
592            NewFileDialog dialog = new NewFileDialog((JFrame) viewer, selectedObject.getFileFormat().getParent(),
593                    filetype, fileList);
594            // dialog.show();
595
596            if (!dialog.isFileCreated()) {
597                return;
598            }
599
600            String filename = dialog.getFile();
601            FileFormat dstFile = null;
602            try {
603                dstFile = openFile(filename, FileFormat.WRITE);
604            }
605            catch (Exception ex) {
606                toolkit.beep();
607                JOptionPane.showMessageDialog(this, ex.getMessage() + "\n" + filename, "HDFView",
608                        JOptionPane.ERROR_MESSAGE);
609            }
610            List<Object> objList = new Vector<Object>(2);
611            objList.add(selectedObject);
612            pasteObject(objList, dstFile.getRootNode(), dstFile);
613        }
614        else if (cmd.equals("Rename object")) {
615            renameObject();
616        }
617        else if (cmd.startsWith("Show object properties")) {
618            if (cmd.equals("Show object properties")) {
619                isDefaultDisplay = true;
620            }
621            else {
622                isDefaultDisplay = false;
623            }
624
625            try {
626                showMetaData(selectedObject);
627            }
628            catch (Exception ex) {
629                toolkit.beep();
630                JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
631            }
632        }
633        else if (cmd.startsWith("Find")) {
634            if (cmd.equals("Find")) {
635                String findStr = currentSearchPhrase;
636                if (findStr == null) findStr = "";
637
638                findStr = (String) JOptionPane.showInputDialog(this, "Find (e.g. O3Quality, O3*, or *Quality):",
639                        "Find Object by Name", JOptionPane.PLAIN_MESSAGE, null, null, findStr);
640
641                if (findStr != null && findStr.length() > 0) currentSearchPhrase = findStr;
642            }
643
644            find(currentSearchPhrase, selectedTreePath, tree);
645        }
646        else if (cmd.startsWith("Expand all")) {
647            int row = 0;
648            while (row < tree.getRowCount()) {
649                tree.expandRow(row);
650                row++;
651            }
652        }
653        else if (cmd.startsWith("Collapse all")) {
654            int row = tree.getRowCount() - 1;
655            while (row >= 0) {
656                tree.collapseRow(row);
657                row--;
658            }
659        }
660        else if (cmd.startsWith("Set Lib version bounds")) {
661            setLibVersionBounds();
662        }
663        else if (cmd.startsWith("Change file indexing")) {
664            ChangeIndexingDialog dialog = new ChangeIndexingDialog((JFrame) viewer, selectedFile);
665            dialog.setVisible(true);
666            if (dialog.isreloadFile()) {
667                selectedFile.setIndexType(dialog.getIndexType());
668                selectedFile.setIndexOrder(dialog.getIndexOrder());
669                ((HDFView) viewer).reloadFile();
670            }
671        }
672    }
673
674    private void addGroup() {
675        if ((selectedObject == null) || (selectedNode == null)) {
676            return;
677        }
678
679        Group pGroup = null;
680        if (selectedObject instanceof Group) {
681            pGroup = (Group) selectedObject;
682        }
683        else {
684            pGroup = (Group) ((DefaultMutableTreeNode) selectedNode.getParent()).getUserObject();
685        }
686
687        NewGroupDialog dialog = new NewGroupDialog((JFrame) viewer, pGroup,
688                breadthFirstUserObjects(selectedObject.getFileFormat().getRootNode()));
689        dialog.setVisible(true);
690
691        HObject obj = (HObject) dialog.getObject();
692        if (obj == null) {
693            return;
694        }
695
696        Group pgroup = dialog.getParentGroup();
697        try {
698            this.addObject(obj, pgroup);
699        }
700        catch (Exception ex) {
701            toolkit.beep();
702            JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
703            return;
704        }
705    }
706
707    private void addDataset() {
708        if ((selectedObject == null) || (selectedNode == null)) {
709            return;
710        }
711
712        Group pGroup = null;
713        if (selectedObject instanceof Group) {
714            pGroup = (Group) selectedObject;
715        }
716        else {
717            pGroup = (Group) ((DefaultMutableTreeNode) selectedNode.getParent()).getUserObject();
718        }
719
720        NewDatasetDialog dialog = new NewDatasetDialog((JFrame) viewer, pGroup,
721                breadthFirstUserObjects(selectedObject.getFileFormat().getRootNode()));
722        dialog.setVisible(true);
723
724        HObject obj = (HObject) dialog.getObject();
725        if (obj == null) {
726            return;
727        }
728
729        Group pgroup = dialog.getParentGroup();
730        try {
731            addObject(obj, pgroup);
732        }
733        catch (Exception ex) {
734            toolkit.beep();
735            JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
736            return;
737        }
738    }
739
740    private void addImage() {
741        if ((selectedObject == null) || (selectedNode == null)) {
742            return;
743        }
744
745        Group pGroup = null;
746        if (selectedObject instanceof Group) {
747            pGroup = (Group) selectedObject;
748        }
749        else {
750            pGroup = (Group) ((DefaultMutableTreeNode) selectedNode.getParent()).getUserObject();
751        }
752
753        NewImageDialog dialog = new NewImageDialog((JFrame) viewer, pGroup, breadthFirstUserObjects(selectedObject
754                .getFileFormat().getRootNode()));
755        dialog.setVisible(true);
756
757        HObject obj = (HObject) dialog.getObject();
758        if (obj == null) {
759            return;
760        }
761
762        Group pgroup = dialog.getParentGroup();
763        try {
764            this.addObject(obj, pgroup);
765        }
766        catch (Exception ex) {
767            toolkit.beep();
768            JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
769            return;
770        }
771    }
772
773    private void addTable() {
774        if ((selectedObject == null) || (selectedNode == null)) {
775            return;
776        }
777
778        Group pGroup = null;
779        if (selectedObject instanceof Group) {
780            pGroup = (Group) selectedObject;
781        }
782        else {
783            pGroup = (Group) ((DefaultMutableTreeNode) selectedNode.getParent()).getUserObject();
784        }
785
786        NewTableDataDialog dialog = new NewTableDataDialog((JFrame) viewer, pGroup,
787                breadthFirstUserObjects(selectedObject.getFileFormat().getRootNode()));
788        dialog.setVisible(true);
789
790        HObject obj = (HObject) dialog.getObject();
791        if (obj == null) {
792            return;
793        }
794
795        Group pgroup = dialog.getParentGroup();
796        try {
797            addObject(obj, pgroup);
798        }
799        catch (Exception ex) {
800            toolkit.beep();
801            JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
802            return;
803        }
804    }
805
806    private void addDatatype() {
807        if ((selectedObject == null) || (selectedNode == null)) {
808            return;
809        }
810
811        Group pGroup = null;
812        if (selectedObject instanceof Group) {
813            pGroup = (Group) selectedObject;
814        }
815        else {
816            pGroup = (Group) ((DefaultMutableTreeNode) selectedNode.getParent()).getUserObject();
817        }
818
819        NewDatatypeDialog dialog = new NewDatatypeDialog((JFrame) viewer, pGroup,
820                breadthFirstUserObjects(selectedObject.getFileFormat().getRootNode()));
821        dialog.setVisible(true);
822
823        HObject obj = (HObject) dialog.getObject();
824        if (obj == null) {
825            return;
826        }
827
828        Group pgroup = dialog.getParentGroup();
829        try {
830            addObject(obj, pgroup);
831        }
832        catch (Exception ex) {
833            toolkit.beep();
834            JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
835            return;
836        }
837    }
838
839    private void addLink() {
840        if ((selectedObject == null) || (selectedNode == null)) {
841            return;
842        }
843
844        Group pGroup = null;
845        if (selectedObject instanceof Group) {
846            pGroup = (Group) selectedObject;
847        }
848        else {
849            pGroup = (Group) ((DefaultMutableTreeNode) selectedNode.getParent()).getUserObject();
850        }
851
852        NewLinkDialog dialog = new NewLinkDialog((JFrame) viewer, pGroup, breadthFirstUserObjects(selectedObject
853                .getFileFormat().getRootNode()));
854        dialog.setVisible(true);
855
856        HObject obj = (HObject) dialog.getObject();
857        if (obj == null) {
858            return;
859        }
860
861        Group pgroup = dialog.getParentGroup();
862        try {
863            addObject(obj, pgroup);
864        }
865        catch (Exception ex) {
866            toolkit.beep();
867            JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
868            return;
869        }
870    }
871
872    /**
873     * Adds a new data object to the file.
874     *
875     * @param newObject
876     *            the object to add.
877     * @param parentGroup
878     *            the parent group to add the object to.
879     *
880     * @throws Exception if an exception occurs while adding a new data object to the file
881     */
882    public void addObject(HObject newObject, Group parentGroup) throws Exception {
883        if ((newObject == null) || (parentGroup == null)) {
884            return;
885        }
886
887        TreeNode pnode = findTreeNode(parentGroup);
888        TreeNode newnode = null;
889        if (newObject instanceof Group) {
890            newnode = new DefaultMutableTreeNode(newObject) {
891                private static final long serialVersionUID = -8852535261445958398L;
892
893                public boolean isLeaf() {
894                    return false;
895                }
896            };
897        }
898        else {
899            newnode = new DefaultMutableTreeNode(newObject);
900        }
901
902        treeModel.insertNodeInto((DefaultMutableTreeNode) newnode, (DefaultMutableTreeNode) pnode,
903                pnode.getChildCount());
904    }
905
906    /**
907     * Insert an object into the tree.
908     *
909     * @param obj
910     *            the object to insert.
911     * @param pobj
912     *            the parent node.
913     */
914    private void insertNode(TreeNode obj, TreeNode pobj) {
915        if ((obj == null) || (pobj == null)) {
916            return;
917        }
918
919        treeModel.insertNodeInto((DefaultMutableTreeNode) obj, (DefaultMutableTreeNode) pobj, pobj.getChildCount());
920    }
921
922    /** Move selected objects */
923    private void moveObject() {
924        log.trace("moveObject: start");
925        objectsToCopy = getSelectedObjects();
926        moveFlag = true;
927        currentSelectionsForMove = tree.getSelectionPaths();
928    }
929
930    /** Copy selected objects */
931    private void copyObject() {
932        log.trace("copyObject: start");
933        int op = -1;
934        if (moveFlag == true) {
935            String moveMsg = "Do you want to copy all the selected object(s) instead of move?";
936            op = JOptionPane.showConfirmDialog(this, moveMsg, "Copy object", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
937        }
938
939        log.trace("cutObject(): op={}", op);
940        if (op == JOptionPane.NO_OPTION) {
941            return;
942        }
943        moveFlag = false;
944        currentSelectionsForMove = null;
945        objectsToCopy = getSelectedObjects();
946    }
947
948    /** Delete selected objects */
949    private void cutObject() {
950        log.trace("cutObject: start");
951        int op = -1;
952        if (moveFlag == true) {
953            String moveMsg = "Do you want to delete all the selected object(s) instead of move?";
954            op = JOptionPane.showConfirmDialog(this, moveMsg, "Delete object", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
955        }
956
957        log.trace("cutObject(): op={}", op);
958        if (op == JOptionPane.NO_OPTION) {
959            return;
960        }
961        moveFlag = false;
962        currentSelectionsForMove = null;
963        objectsToCopy = getSelectedObjects();
964        removeSelectedObjects();
965    }
966
967    /** Paste selected objects */
968    private void pasteObject() {
969        log.trace("pasteObject(): start");
970        if (moveFlag == true) {
971            log.trace("pasteObject: move");
972            HObject theObj = null;
973            for (int i = 0; i < currentSelectionsForMove.length; i++) {
974                DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelectionsForMove[i].getLastPathComponent());
975                theObj = (HObject) currentNode.getUserObject();
976
977                log.trace("pasteObject(): check if currentSelectionsForMove[{}] is open", i);
978                if (isObjectOpen(theObj)) {
979                    toolkit.beep();
980                    JOptionPane.showMessageDialog(this, "Cannot move the selected object: " + theObj
981                            + "\nThe dataset or dataset in the group is in use."
982                            + "\n\nPlease close the dataset(s) and try again.\n", "HDFView", JOptionPane.ERROR_MESSAGE);
983                    moveFlag = false;
984                    currentSelectionsForMove = null;
985                    objectsToCopy = null;
986                    return;
987                }
988            }
989        }
990
991        TreeNode pitem = selectedNode;
992
993        if ((objectsToCopy == null) || (objectsToCopy.size() <= 0) || (pitem == null)) {
994            return;
995        }
996
997        log.trace("pasteObject(): verify file properties");
998        FileFormat srcFile = ((HObject) objectsToCopy.get(0)).getFileFormat();
999        FileFormat dstFile = getSelectedFile();
1000        FileFormat h5file = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
1001        FileFormat h4file = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4);
1002
1003        if (srcFile == null) {
1004            toolkit.beep();
1005            JOptionPane.showMessageDialog(this, "Source file is null.", "HDFView", JOptionPane.ERROR_MESSAGE);
1006            return;
1007        }
1008        else if (dstFile == null) {
1009            toolkit.beep();
1010            JOptionPane.showMessageDialog(this, "Destination file is null.", "HDFView", JOptionPane.ERROR_MESSAGE);
1011            return;
1012        }
1013        else if (srcFile.isThisType(h4file) && dstFile.isThisType(h5file)) {
1014            toolkit.beep();
1015            JOptionPane.showMessageDialog(this, "Unsupported operation: cannot copy HDF4 object to HDF5 file",
1016                    "HDFView", JOptionPane.ERROR_MESSAGE);
1017            return;
1018        }
1019        else if (srcFile.isThisType(h5file) && dstFile.isThisType(h4file)) {
1020            toolkit.beep();
1021            JOptionPane.showMessageDialog(this, "Unsupported operation: cannot copy HDF5 object to HDF4 file",
1022                    "HDFView", JOptionPane.ERROR_MESSAGE);
1023            return;
1024        }
1025
1026        if (moveFlag == true) {
1027            log.trace("pasteObject(): check if src and dest are different files");
1028            if (srcFile != dstFile) {
1029                toolkit.beep();
1030                JOptionPane.showMessageDialog(this, "Cannot move the selected object to different file", "HDFView",
1031                        JOptionPane.ERROR_MESSAGE);
1032                moveFlag = false;
1033                currentSelectionsForMove = null;
1034                objectsToCopy = null;
1035                return;
1036            }
1037        }
1038
1039        if (pitem.isLeaf()) {
1040            pitem = pitem.getParent();
1041        }
1042
1043        Group pgroup = (Group) ((DefaultMutableTreeNode) pitem).getUserObject();
1044        String fullPath = pgroup.getPath() + pgroup.getName();
1045        if (pgroup.isRoot()) {
1046            fullPath = HObject.separator;
1047        }
1048        log.trace("pasteObject(): fullPath={}",fullPath);
1049
1050        String msg = "";
1051        int msgType = JOptionPane.QUESTION_MESSAGE;
1052        if (srcFile.isThisType(h4file)) {
1053            msg = "WARNING: object can not be deleted after it is copied.\n\n";
1054            msgType = JOptionPane.WARNING_MESSAGE;
1055        }
1056
1057        msg += "Do you want to copy the selected object(s) to \nGroup: " + fullPath + "\nFile: "
1058                + dstFile.getFilePath();
1059
1060        int op = -1;
1061        if (moveFlag == true) {
1062            String moveMsg = "Do you want to move the selected object(s) to \nGroup: " + fullPath + "\nFile: "
1063                    + dstFile.getFilePath();
1064            op = JOptionPane.showConfirmDialog(this, moveMsg, "Move Object", JOptionPane.YES_NO_OPTION, msgType);
1065        }
1066        else {
1067            op = JOptionPane.showConfirmDialog(this, msg, "Copy object", JOptionPane.YES_NO_OPTION, msgType);
1068        }
1069
1070        log.trace("pasteObject(): op={}", op);
1071        if (op == JOptionPane.NO_OPTION) {
1072            return;
1073        }
1074
1075        pasteObject(objectsToCopy, pitem, dstFile);
1076
1077        if (moveFlag == true) {
1078            removeSelectedObjects();
1079            moveFlag = false;
1080            currentSelectionsForMove = null;
1081            objectsToCopy = null;
1082        }
1083        log.trace("pasteObject(): finish");
1084    }
1085
1086    /** Paste selected objects */
1087    private void pasteObject(List<Object> objList, TreeNode pobj, FileFormat dstFile) {
1088        if ((objList == null) || (objList.size() <= 0) || (pobj == null)) return;
1089
1090        FileFormat srcFile = ((HObject) objList.get(0)).getFileFormat();
1091        Group pgroup = (Group) ((DefaultMutableTreeNode) pobj).getUserObject();
1092        log.trace("pasteObject(...): start");
1093
1094        HObject theObj = null;
1095        Iterator<Object> iterator = objList.iterator();
1096        while (iterator.hasNext()) {
1097            theObj = (HObject) iterator.next();
1098
1099            if ((theObj instanceof Group) && ((Group) theObj).isRoot()) {
1100                toolkit.beep();
1101                JOptionPane.showMessageDialog(this, "Unsupported operation: cannot copy the root group", "HDFView",
1102                        JOptionPane.ERROR_MESSAGE);
1103                return;
1104            }
1105
1106            // Check if it creates infinite loop
1107            Group pg = pgroup;
1108            while (!pg.isRoot()) {
1109                if (theObj.equals(pg)) {
1110                    toolkit.beep();
1111                    JOptionPane.showMessageDialog(this, "Unsupported operation: cannot copy a group to itself.",
1112                            "HDFView", JOptionPane.ERROR_MESSAGE);
1113                    return;
1114                }
1115                pg = pg.getParent();
1116            }
1117
1118            try {
1119                log.trace("pasteObject(...): dstFile.copy({}, {}, null)", theObj, pgroup);
1120
1121                TreeNode newObj = null;
1122                if((newObj = srcFile.copy(theObj, pgroup, null)) != null) {
1123                    // Add the node to the tree
1124                    insertNode(newObj, pobj);
1125                }
1126            }
1127            catch (Exception ex) {
1128                toolkit.beep();
1129                JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
1130                // newNode = null;
1131            }
1132        } // while (iterator.hasNext())
1133        log.trace("pasteObject(...): finish");
1134    }
1135
1136    private void renameObject() {
1137        int op = -1;
1138        if (moveFlag == true) {
1139            String moveMsg = "Do you want to rename all the selected object(s) instead of move?";
1140            op = JOptionPane.showConfirmDialog(this, moveMsg, "Rename object", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
1141        }
1142
1143        log.trace("renameObject(): op={}", op);
1144        if (op == JOptionPane.NO_OPTION) {
1145            return;
1146        }
1147        moveFlag = false;
1148        currentSelectionsForMove = null;
1149
1150        if (selectedObject == null) return;
1151
1152        if ((selectedObject instanceof Group) && ((Group) selectedObject).isRoot()) {
1153            toolkit.beep();
1154            JOptionPane.showMessageDialog(this, "Cannot rename the root.", "HDFView", JOptionPane.ERROR_MESSAGE);
1155            return;
1156        }
1157
1158        boolean isH4 = selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4));
1159
1160        if (isH4) {
1161            toolkit.beep();
1162            JOptionPane.showMessageDialog(this, "Cannot rename HDF4 object.", "HDFView", JOptionPane.ERROR_MESSAGE);
1163            return;
1164        }
1165
1166        String oldName = selectedObject.getName();
1167        String newName = (String) JOptionPane.showInputDialog(this, "Rename \"" + oldName + "\" to:", "Rename...",
1168                JOptionPane.INFORMATION_MESSAGE, null, null, oldName);
1169
1170        if (newName == null) return;
1171
1172        newName = newName.trim();
1173        if ((newName == null) || (newName.length() == 0) || newName.equals(oldName)) {
1174            return;
1175        }
1176
1177        try {
1178            selectedObject.setName(newName);
1179        }
1180        catch (Exception ex) {
1181            toolkit.beep();
1182            JOptionPane.showMessageDialog(this, ex.getMessage(), "HDFView", JOptionPane.ERROR_MESSAGE);
1183        }
1184    }
1185
1186    private void removeSelectedObjects() {
1187        FileFormat theFile = getSelectedFile();
1188        if (theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4))) {
1189            toolkit.beep();
1190            JOptionPane.showMessageDialog(this, "Unsupported operation: cannot delete HDF4 object.", "HDFView",
1191                    JOptionPane.ERROR_MESSAGE);
1192            return;
1193        }
1194        log.trace("removeSelectedObjects: start");
1195
1196        TreePath[] currentSelections = tree.getSelectionPaths();
1197
1198        if (moveFlag == true) {
1199            currentSelections = currentSelectionsForMove;
1200        }
1201        if ((currentSelections == null) || (currentSelections.length <= 0)) {
1202            return;
1203        }
1204        if (moveFlag != true) {
1205            int op = JOptionPane.showConfirmDialog(this, "Do you want to remove all the selected object(s) ?",
1206                    "Remove object", JOptionPane.YES_NO_OPTION);
1207
1208            if (op == JOptionPane.NO_OPTION) {
1209                return;
1210            }
1211        }
1212        HObject theObj = null;
1213        for (int i = 0; i < currentSelections.length; i++) {
1214            log.trace("removeSelectedObjects: loop[{}]",i);
1215            DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelections[i].getLastPathComponent());
1216            theObj = (HObject) currentNode.getUserObject();
1217
1218            // cannot delete root
1219            if (theObj instanceof Group) {
1220                Group g = (Group) theObj;
1221                if (g.isRoot()) {
1222                    toolkit.beep();
1223                    JOptionPane.showMessageDialog(this, "Unsupported operation: cannot delete the file root.",
1224                            "HDFView", JOptionPane.ERROR_MESSAGE);
1225                    log.trace("removeSelectedObjects: cannot delete root");
1226                    return;
1227                }
1228            }
1229
1230            if (moveFlag != true) {
1231                if (isObjectOpen(theObj)) {
1232                    toolkit.beep();
1233                    JOptionPane.showMessageDialog(this, "Cannot delete the selected object: " + theObj
1234                            + "\nThe dataset or dataset in the group is in use."
1235                            + "\n\nPlease close the dataset(s) and try again.\n", "HDFView", JOptionPane.ERROR_MESSAGE);
1236                    log.trace("removeSelectedObjects: object in use");
1237                    continue;
1238                }
1239            }
1240
1241            try {
1242                theFile.delete(theObj);
1243            }
1244            catch (Exception ex) {
1245                toolkit.beep();
1246                JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
1247                continue;
1248            }
1249
1250            if (theObj.equals(selectedObject)) {
1251                selectedObject = null;
1252            }
1253
1254            removeNode(currentNode);
1255        } // for (int i=0; i< currentSelections.length; i++) {
1256        log.trace("removeSelectedObjects: finish");
1257    }
1258
1259    private void removeNode(DefaultMutableTreeNode node) {
1260        if (node == null) {
1261            return;
1262        }
1263        log.trace("removeNode: start");
1264
1265        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) (node.getParent());
1266        if (parentNode != null) {
1267            treeModel.removeNodeFromParent(node);
1268
1269            // add the two lines to fix bug in HDFView 1.2. Delete a subgroup and
1270            // then copy the group to another group, the deleted group still exists.
1271            Group pgroup = (Group) parentNode.getUserObject();
1272            pgroup.removeFromMemberList((HObject) node.getUserObject());
1273
1274            if (node.equals(selectedNode)) {
1275                selectedNode = null;
1276                selectedFile = null;
1277            }
1278        } // if (parentNode != null) {
1279        log.trace("removeNode: finish");
1280    }
1281
1282    /**
1283     * Checks if a file is already open.
1284     *
1285     * @param filename the file to query
1286     *
1287     * @return true if the file is open
1288     */
1289    private boolean isFileOpen(String filename) {
1290        boolean isOpen = false;
1291
1292        // Find the file by matching its file name from the list of open files
1293        FileFormat theFile = null;
1294        Iterator<FileFormat> iterator = fileList.iterator();
1295        while (iterator.hasNext()) {
1296            theFile = iterator.next();
1297            if (theFile.getFilePath().equals(filename)) {
1298                isOpen = true;
1299                break;
1300            }
1301        }
1302
1303        return isOpen;
1304    }
1305
1306    /**
1307     * Checks if an object is already open.
1308     */
1309    private boolean isObjectOpen(HObject obj) {
1310        boolean isOpen = false;
1311
1312        if (obj instanceof Group) {
1313            Group g = (Group) obj;
1314            List<?> members = g.getMemberList();
1315            if ((members == null) || (members.size() == 0)) {
1316                isOpen = false;
1317            }
1318            else {
1319                int n = members.size();
1320                for (int i = 0; i < n; i++) {
1321                    HObject theObj = (HObject) members.get(i);
1322                    isOpen = (((HDFView) viewer).getDataView(theObj) != null);
1323                    if (isOpen) {
1324                        break;
1325                    }
1326                }
1327            }
1328        }
1329        else {
1330            return !(((HDFView) viewer).getDataView(obj) == null);
1331        }
1332
1333        return isOpen;
1334    }
1335
1336    /**
1337     * Returns a list of all user objects that traverses the subtree rooted at
1338     * this item in breadth-first order..
1339     *
1340     * @param item
1341     *            the item to start with.
1342     *
1343     * @return list of TreeNodes
1344     */
1345    private final List<Object> breadthFirstUserObjects(TreeNode item) {
1346        if (item == null) return null;
1347
1348        Vector<Object> list = new Vector<Object>();
1349        DefaultMutableTreeNode theItem = null;
1350        Enumeration<?> local_enum = ((DefaultMutableTreeNode) item).breadthFirstEnumeration();
1351        while (local_enum.hasMoreElements()) {
1352            theItem = (DefaultMutableTreeNode) local_enum.nextElement();
1353            list.add(theItem.getUserObject());
1354        }
1355
1356        return list;
1357    }
1358
1359    /**
1360     * Find first object that is matched by name under the specified
1361     * TreeNode.
1362     *
1363     * @param objName
1364     *            -- the object name.
1365     * @return the object if found, otherwise, returns null.
1366     */
1367    private final static HObject find(String objName, TreePath treePath, JTree tree) {
1368        if (objName == null || objName.length() <= 0 || treePath == null) return null;
1369
1370        HObject retObj = null;
1371        boolean isFound = false, isPrefix = false, isSuffix = false, isContain = false;
1372
1373        if (objName.equals("*")) return null;
1374
1375        if (objName.startsWith("*")) {
1376            isSuffix = true;
1377            objName = objName.substring(1, objName.length());
1378        }
1379
1380        if (objName.endsWith("*")) {
1381            isPrefix = true;
1382            objName = objName.substring(0, objName.length() - 1);
1383        }
1384
1385        if (isPrefix && isSuffix) {
1386            isContain = true;
1387            isPrefix = isSuffix = false;
1388        }
1389
1390        if (objName == null || objName.length() <= 0) return null;
1391
1392        DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath.getLastPathComponent();
1393        if (node == null) return null;
1394
1395        HObject obj = null;
1396        String theName = null;
1397        DefaultMutableTreeNode theItem = null;
1398        Enumeration<?> local_enum = node.breadthFirstEnumeration();
1399        while (local_enum.hasMoreElements()) {
1400            theItem = (DefaultMutableTreeNode) local_enum.nextElement();
1401            obj = (HObject) theItem.getUserObject();
1402            if (obj != null && (theName = obj.getName()) != null) {
1403                if (isPrefix)
1404                    isFound = theName.startsWith(objName);
1405                else if (isSuffix)
1406                    isFound = theName.endsWith(objName);
1407                else if (isContain)
1408                    isFound = theName.contains(objName);
1409                else
1410                    isFound = theName.equals(objName);
1411
1412                if (isFound) {
1413                    retObj = obj;
1414                    break;
1415                }
1416            }
1417        }
1418
1419        if (retObj != null) {
1420            TreePath dstPath = getTreePath(treePath, theItem, 0);
1421            tree.setSelectionPath(dstPath);
1422            tree.scrollPathToVisible(dstPath);
1423        }
1424
1425        return retObj;
1426    }
1427
1428    /**
1429     * Get the TreePath from the parent to the target node.
1430     *
1431     * @param parent
1432     *            -- the parent TreePath
1433     * @param node
1434     *            -- the target node
1435     * @param depth
1436     * @return the tree path if target node found, otherwise; returns null;
1437     */
1438    private static TreePath getTreePath(TreePath parent, TreeNode node, int depth) {
1439        if (node == null || parent == null || depth < 0) return null;
1440
1441        TreeNode theNode = (TreeNode) parent.getLastPathComponent();
1442        if (node == theNode) return parent;
1443
1444        if (theNode.getChildCount() >= 0) {
1445            for (Enumeration<?> e = theNode.children(); e.hasMoreElements();) {
1446                TreeNode n = (TreeNode) e.nextElement();
1447                TreePath path = parent.pathByAddingChild(n);
1448                TreePath result = getTreePath(path, node, depth + 1);
1449
1450                if (result != null) {
1451                    return result;
1452                }
1453            }
1454        }
1455
1456        return null;
1457    }
1458
1459    /**
1460     * Save the current file into a new HDF4 file. Since HDF4 does not
1461     * support packing, the source file is copied into the new file with
1462     * the exact same content.
1463     */
1464    private final void saveAsHDF4(FileFormat srcFile) {
1465        if (srcFile == null) {
1466            toolkit.beep();
1467            JOptionPane.showMessageDialog(this, "Select a file to save.", "HDFView", JOptionPane.ERROR_MESSAGE);
1468            return;
1469        }
1470
1471        TreeNode root = srcFile.getRootNode();
1472        if (root == null) {
1473            toolkit.beep();
1474            JOptionPane.showMessageDialog(this, "The file is empty.", "HDFView", JOptionPane.ERROR_MESSAGE);
1475            return;
1476        }
1477
1478        JFrame owner = (viewer == null) ? new JFrame() : (JFrame) viewer;
1479        String currentDir = srcFile.getParent();
1480
1481        if (currentDir != null) {
1482            currentDir += File.separator;
1483        }
1484        else {
1485            currentDir = "";
1486        }
1487
1488        NewFileDialog dialog = new NewFileDialog(owner, currentDir, FileFormat.FILE_TYPE_HDF4, getCurrentFiles());
1489        // dialog.show();
1490
1491        if (!dialog.isFileCreated()) return;
1492
1493        String filename = dialog.getFile();
1494
1495        if(filename == null) return;
1496
1497        // Since cannot pack hdf4, simply copy the whole physical file
1498        int length = 0;
1499        int bsize = 512;
1500        byte[] buffer;
1501        BufferedInputStream bi = null;
1502        BufferedOutputStream bo = null;
1503
1504        try {
1505            bi = new BufferedInputStream(new FileInputStream(srcFile.getFilePath()));
1506        }
1507        catch (Exception ex) {
1508            toolkit.beep();
1509            JOptionPane.showMessageDialog(this, ex.getMessage() + "\n" + filename, "HDFView", JOptionPane.ERROR_MESSAGE);
1510            return;
1511        }
1512
1513        try {
1514            bo = new BufferedOutputStream(new FileOutputStream(filename));
1515        }
1516        catch (Exception ex) {
1517            try {
1518                bi.close();
1519            }
1520            catch (Exception ex2) {
1521                log.debug("Output file force input close:", ex2);
1522            }
1523            toolkit.beep();
1524            JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
1525            return;
1526        }
1527
1528        buffer = new byte[bsize];
1529        try {
1530            length = bi.read(buffer, 0, bsize);
1531        }
1532        catch (Exception ex) {
1533            length = 0;
1534        }
1535        while (length > 0) {
1536            try {
1537                bo.write(buffer, 0, length);
1538                length = bi.read(buffer, 0, bsize);
1539            }
1540            catch (Exception ex) {
1541                length = 0;
1542            }
1543        }
1544
1545        try {
1546            bo.flush();
1547        }
1548        catch (Exception ex) {
1549            log.debug("Output file:", ex);
1550        }
1551        try {
1552            bi.close();
1553        }
1554        catch (Exception ex) {
1555            log.debug("Input file:", ex);
1556        }
1557        try {
1558            bo.close();
1559        }
1560        catch (Exception ex) {
1561            log.debug("Output file:", ex);
1562        }
1563
1564        try {
1565            openFile(filename, FileFormat.WRITE);
1566        }
1567        catch (Exception ex) {
1568            toolkit.beep();
1569            JOptionPane .showMessageDialog(this, ex.getMessage() + "\n" + filename, "HDFView", JOptionPane.ERROR_MESSAGE);
1570        }
1571    }
1572
1573    /**
1574     * Copy the current file into a new HDF5 file. The new file does not include the
1575     * inaccessible objects. Values of reference dataset are not updated in the
1576     * new file.
1577     */
1578    private void saveAsHDF5(FileFormat srcFile) {
1579        if (srcFile == null) {
1580            toolkit.beep();
1581            JOptionPane.showMessageDialog(this, "Select a file to save.", "HDFView", JOptionPane.ERROR_MESSAGE);
1582            return;
1583        }
1584
1585        TreeNode root = srcFile.getRootNode();
1586        if (root == null) {
1587            toolkit.beep();
1588            JOptionPane.showMessageDialog(this, "The file is empty.", "HDFView", JOptionPane.ERROR_MESSAGE);
1589            return;
1590        }
1591
1592        JFrame owner = (viewer == null) ? new JFrame() : (JFrame) viewer;
1593        NewFileDialog dialog = new NewFileDialog(owner, srcFile.getParent(), FileFormat.FILE_TYPE_HDF5,
1594                getCurrentFiles());
1595        // dialog.show();
1596
1597        if (!dialog.isFileCreated()) {
1598            return;
1599        }
1600
1601        String filename = dialog.getFile();
1602
1603        if(filename == null) return;
1604
1605        int n = root.getChildCount();
1606        Vector<Object> objList = new Vector<Object>(n);
1607        DefaultMutableTreeNode node = null;
1608        for (int i = 0; i < n; i++) {
1609            node = (DefaultMutableTreeNode) root.getChildAt(i);
1610            objList.add(node.getUserObject());
1611        }
1612
1613        FileFormat newFile = null;
1614        try {
1615            newFile = openFile(filename, FileFormat.WRITE);
1616        }
1617        catch (Exception ex) {
1618            toolkit.beep();
1619            JOptionPane .showMessageDialog(this, ex.getMessage() + "\n" + filename, "HDFView", JOptionPane.ERROR_MESSAGE);
1620            return;
1621        }
1622
1623        if (newFile == null) return;
1624
1625        TreeNode pnode = newFile.getRootNode();
1626
1627        pasteObject(objList, pnode, newFile);
1628        objList.setSize(0);
1629
1630        Group srcGroup = (Group) ((DefaultMutableTreeNode) root).getUserObject();
1631        Group dstGroup = (Group) ((DefaultMutableTreeNode) newFile.getRootNode()).getUserObject();
1632        Object[] parameter = new Object[2];
1633        Class<?> classHOjbect = null;
1634        Class<?>[] parameterClass = new Class[2];
1635        Method method = null;
1636
1637        // Copy attributes of the root group
1638        try {
1639            parameter[0] = srcGroup;
1640            parameter[1] = dstGroup;
1641            classHOjbect = Class.forName("hdf.object.HObject");
1642            parameterClass[0] = parameterClass[1] = classHOjbect;
1643            method = newFile.getClass().getMethod("copyAttributes", parameterClass);
1644            method.invoke(newFile, parameter);
1645        }
1646        catch (Exception ex) {
1647            toolkit.beep();
1648            JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
1649        }
1650
1651        // Update reference datasets
1652        parameter[0] = srcGroup.getFileFormat();
1653        parameter[1] = newFile;
1654        parameterClass[0] = parameterClass[1] = parameter[0].getClass();
1655        try {
1656            method = newFile.getClass().getMethod("updateReferenceDataset", parameterClass);
1657            method.invoke(newFile, parameter);
1658        }
1659        catch (Exception ex) {
1660            toolkit.beep();
1661            JOptionPane.showMessageDialog(this, ex, "HDFView", JOptionPane.ERROR_MESSAGE);
1662        }
1663    }
1664
1665    /** Save data as file.
1666    *
1667    * @throws Exception if a failure occurred
1668    */
1669    private void saveAsFile() throws Exception {
1670        if (!(selectedObject instanceof Dataset) || (selectedObject == null) || (selectedNode == null)) return;
1671
1672        File chosenFile = null;
1673        Dataset dataset = (Dataset) selectedObject;
1674        final JFileChooser fchooser = new JFileChooser(dataset.getFile());
1675        fchooser.setFileFilter(DefaultFileFilter.getFileFilterText());
1676        // fchooser.changeToParentDirectory();
1677
1678        if(binaryOrder == 99) {
1679            fchooser.setDialogTitle("Save Dataset Data To Text File --- " + dataset.getName());
1680
1681            chosenFile = new File(dataset.getName() + ".txt");
1682        }
1683        else {
1684            fchooser.setDialogTitle("Save Current Data To Binary File --- " + dataset.getName());
1685
1686            chosenFile = new File(dataset.getName() + ".bin");
1687        }
1688
1689        fchooser.setSelectedFile(chosenFile);
1690        int returnVal = fchooser.showSaveDialog(this);
1691
1692        if (returnVal != JFileChooser.APPROVE_OPTION) {
1693            return;
1694        }
1695
1696        chosenFile = fchooser.getSelectedFile();
1697        if (chosenFile == null) {
1698            return;
1699        }
1700        String filename = chosenFile.getAbsolutePath();
1701        if(filename == null) return;
1702
1703        // Check if the file is in use
1704        List<?> fileList = viewer.getTreeView().getCurrentFiles();
1705        if (fileList != null) {
1706            FileFormat theFile = null;
1707            Iterator<?> iterator = fileList.iterator();
1708            while (iterator.hasNext()) {
1709                theFile = (FileFormat) iterator.next();
1710                if (theFile.getFilePath().equals(filename)) {
1711                    toolkit.beep();
1712                    JOptionPane.showMessageDialog(this,
1713                            "Unable to save data to file \"" + filename + "\". \nThe file is being used.",
1714                            "Export Dataset", JOptionPane.ERROR_MESSAGE);
1715                    return;
1716                }
1717            }
1718        }
1719
1720        if (chosenFile.exists()) {
1721            int newFileFlag = JOptionPane.showConfirmDialog(this,
1722                    "File exists. Do you want to replace it ?",
1723                    "Export Dataset", JOptionPane.YES_NO_OPTION);
1724            if (newFileFlag == JOptionPane.NO_OPTION) {
1725                return;
1726            }
1727        }
1728
1729        boolean isH4 = selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4));
1730
1731        if (isH4) {
1732            toolkit.beep();
1733            JOptionPane.showMessageDialog(this, "Cannot export HDF4 object.", "HDFView", JOptionPane.ERROR_MESSAGE);
1734            return;
1735        }
1736
1737        try {
1738            selectedObject.getFileFormat().exportDataset(filename, dataset.getFile(), dataset.getFullName(), binaryOrder);
1739        }
1740        catch (Exception ex) {
1741            toolkit.beep();
1742            JOptionPane.showMessageDialog(this, ex.getMessage(), "HDFView", JOptionPane.ERROR_MESSAGE);
1743        }
1744
1745        viewer.showStatus("Data saved to: " + filename);
1746    }
1747
1748    /** disable/enable GUI components */
1749    private static void setEnabled(List<JMenuItem> list, boolean b) {
1750        Component item = null;
1751        Iterator<JMenuItem> it = list.iterator();
1752        while (it.hasNext()) {
1753            item = it.next();
1754            item.setEnabled(b);
1755        }
1756    }
1757
1758    /**
1759     * Opens a file and retrieves the file structure of the file. It also can be
1760     * used to create a new file by setting the accessID to FileFormat.CREATE.
1761     *
1762     * <p>
1763     * Subclasses must implement this function to take appropriate steps to open
1764     * a file.
1765     * </p>
1766     *
1767     * @param filename
1768     *            the name of the file to open.
1769     * @param accessID
1770     *            identifier for the file access. Valid value of accessID is:
1771     *            <ul>
1772     *            <li>FileFormat.READ --- allow read-only access to file.</li>
1773     *            <li>FileFormat.WRITE --- allow read and write access to file.</li>
1774     *            <li>FileFormat.CREATE --- create a new file.</li>
1775     *            </ul>
1776     *
1777     * @return the FileFormat of this file if successful; otherwise returns
1778     *         null.
1779     *
1780     * @throws Exception if a failure occurred
1781     */
1782    public FileFormat openFile(String filename, int accessID) throws Exception {
1783        log.trace("openFile: {},{}", filename, accessID);
1784        FileFormat fileFormat = null;
1785        MutableTreeNode fileRoot = null;
1786        boolean isNewFile = (FileFormat.OPEN_NEW == (accessID & FileFormat.OPEN_NEW));
1787        if (isNewFile) accessID = accessID - FileFormat.OPEN_NEW;
1788
1789        if (isFileOpen(filename)) {
1790            ((HDFView) viewer).showStatus("File is in use.");
1791            return null;
1792        }
1793
1794        File tmpFile = new File(filename);
1795        if (!tmpFile.exists()) {
1796            throw new FileNotFoundException("File does not exist.");
1797        }
1798
1799        if (!tmpFile.canWrite()) {
1800            accessID = FileFormat.READ;
1801        }
1802
1803        Enumeration<?> keys = FileFormat.getFileFormatKeys();
1804
1805        String theKey = null;
1806        while (keys.hasMoreElements()) {
1807            theKey = (String) keys.nextElement();
1808            if (theKey.equals(FileFormat.FILE_TYPE_HDF4)) {
1809                log.trace("openFile: {} FILE_TYPE_HDF4", filename);
1810                try {
1811                    FileFormat h4format = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4);
1812                    if ((h4format != null) && h4format.isThisType(filename)) {
1813                        fileFormat = h4format.createInstance(filename, accessID);
1814                        break;
1815                    }
1816                }
1817                catch (Throwable err) {
1818                    log.debug("openFile: Error retrieving the file structure of {}: {}", filename, err);
1819                }
1820                continue;
1821            }
1822            else if (theKey.equals(FileFormat.FILE_TYPE_HDF5)) {
1823                log.trace("openFile: {} FILE_TYPE_HDF5", filename);
1824                try {
1825                    FileFormat h5format = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
1826                    if ((h5format != null) && h5format.isThisType(filename)) {
1827                        fileFormat = h5format.createInstance(filename, accessID);
1828                        break;
1829                    }
1830                }
1831                catch (Throwable err) {
1832                    log.debug("openFile: Error retrieving the file structure of {}: {}", filename, err);
1833                }
1834                continue;
1835            }
1836            else {
1837                log.trace("openFile: {} Other", filename);
1838                try {
1839
1840                    FileFormat theformat = FileFormat.getFileFormat(theKey);
1841                    if (theformat.isThisType(filename)) {
1842                        fileFormat = theformat.createInstance(filename, accessID);
1843                        break;
1844                    }
1845                }
1846                catch (Throwable err) {
1847                    log.debug("openFile: Error retrieving the file structure of {}: {}", filename, err);
1848                }
1849            }
1850        }
1851
1852        if (fileFormat == null) throw new java.io.IOException("Unsupported fileformat - " + filename);
1853
1854        ((JFrame) viewer).setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1855        try {
1856            fileFormat.setMaxMembers(ViewProperties.getMaxMembers());
1857            fileFormat.setStartMembers(ViewProperties.getStartMembers());
1858            if (fileFormat.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) {
1859                if(isNewFile) {
1860                    currentIndexType = fileFormat.getIndexType(ViewProperties.getIndexType());
1861                    currentIndexOrder = fileFormat.getIndexOrder(ViewProperties.getIndexOrder());
1862                }
1863                fileFormat.setIndexType(currentIndexType);
1864                fileFormat.setIndexOrder(currentIndexOrder);
1865            }
1866
1867            fileFormat.open();
1868        }
1869        catch (Exception ex) {
1870            log.debug("openFile: FileFormat init and open: {}", ex);
1871            fileFormat = null;
1872        }
1873        finally {
1874            ((JFrame) viewer).setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1875        }
1876
1877        if (fileFormat == null) {
1878            throw new java.io.IOException("openFile: Failed to open file - " + filename);
1879        }
1880        else  {
1881            fileRoot = (MutableTreeNode) fileFormat.getRootNode();
1882
1883            if (fileRoot != null) {
1884                insertNode(fileRoot, root);
1885                /* Expand top level items of root object */
1886                int currentRowCount = tree.getRowCount();
1887                if (currentRowCount > 0) {
1888                    tree.expandRow(tree.getRowCount() - 1);
1889                }
1890
1891                fileList.add(fileFormat);
1892            }
1893        }
1894
1895        return fileFormat;
1896    }
1897
1898    public FileFormat reopenFile(FileFormat fileFormat) throws Exception {
1899        if (fileFormat.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) {
1900            this.currentIndexType = fileFormat.getIndexType(null);
1901            this.currentIndexOrder = fileFormat.getIndexOrder(null);
1902        }
1903        if (fileFormat.isReadOnly())
1904            return openFile(fileFormat.getAbsolutePath(), FileFormat.READ);
1905        else
1906            return openFile(fileFormat.getAbsolutePath(), FileFormat.WRITE);
1907    }
1908
1909    /**
1910     * Close a file
1911     *
1912     * @param file
1913     *            the file to close
1914     *
1915     * @throws Exception if a failure occurred
1916     */
1917    @Override
1918    public void closeFile(FileFormat file) throws Exception {
1919        if (file == null) return;
1920
1921        log.trace("DefaultTreeView:closeFile start");
1922        // Find the file item in the tree and remove it
1923        FileFormat theFile = null;
1924        DefaultMutableTreeNode theNode = null;
1925        Enumeration<?> enumeration = root.children();
1926        while (enumeration.hasMoreElements()) {
1927            theNode = (DefaultMutableTreeNode) enumeration.nextElement();
1928            Group g = (Group) theNode.getUserObject();
1929            theFile = g.getFileFormat();
1930
1931            if (theFile.equals(file)) {
1932                treeModel.removeNodeFromParent(theNode);
1933                try {
1934                    theFile.close();
1935                }
1936                catch (Exception ex) {
1937                    log.debug("DefaultTreeView: closeFile({}): {}:", theFile.getFilePath(), ex);
1938                }
1939                fileList.remove(theFile);
1940                if (theFile.equals(selectedFile)) {
1941                    selectedFile = null;
1942                    selectedNode = null;
1943                }
1944                break;
1945            }
1946        } // while(enumeration.hasMoreElements())
1947        log.trace("DefaultTreeView:closeFile finish");
1948    }
1949
1950    /**
1951     * Save a file
1952     *
1953     * @param file
1954     *            the file to save
1955     *
1956     * @throws Exception if a failure occurred
1957     */
1958    @Override
1959    public void saveFile(FileFormat file) throws Exception {
1960        if (file == null) {
1961            toolkit.beep();
1962            JOptionPane.showMessageDialog(this, "Select a file to save.", "HDFView", JOptionPane.ERROR_MESSAGE);
1963            return;
1964        }
1965
1966        boolean isH4 = file.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4));
1967        boolean isH5 = file.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
1968
1969        if (!(isH4 || isH5)) {
1970            toolkit.beep();
1971            JOptionPane.showMessageDialog(this, "Saving file is not supported for this file type", "HDFView",
1972                    JOptionPane.ERROR_MESSAGE);
1973            return;
1974        }
1975
1976        // Write the change of the data into the file before saving the file
1977        List<?> views = ((HDFView) viewer).getDataViews();
1978        Object theView = null;
1979        TableView tableView = null;
1980        TextView textView = null;
1981        FileFormat theFile = null;
1982        if (views != null) {
1983            int n = views.size();
1984            for (int i = 0; i < n; i++) {
1985                theView = views.get(i);
1986                if (theView instanceof TableView) {
1987                    tableView = (TableView) theView;
1988                    theFile = tableView.getDataObject().getFileFormat();
1989                    if (file.equals(theFile)) {
1990                        tableView.updateValueInFile();
1991                    }
1992                }
1993                else if (theView instanceof TextView) {
1994                    textView = (TextView) theView;
1995                    theFile = textView.getDataObject().getFileFormat();
1996                    if (file.equals(theFile)) {
1997                        textView.updateValueInFile();
1998                    }
1999                }
2000            }
2001        }
2002
2003        if (isH5) {
2004            saveAsHDF5(file);
2005        }
2006        else if (isH4) {
2007            saveAsHDF4(file);
2008        }
2009    }
2010
2011    /**
2012     * Returns the tree node that contains the given data object.
2013     */
2014    @Override
2015    public TreeNode findTreeNode(HObject obj) {
2016        if (obj == null) return null;
2017
2018        TreeNode theFileRoot = obj.getFileFormat().getRootNode();
2019        if (theFileRoot == null)  return null;
2020
2021        DefaultMutableTreeNode theNode = null;
2022        HObject theObj = null;
2023        Enumeration<?> local_enum = ((DefaultMutableTreeNode) theFileRoot).breadthFirstEnumeration();
2024        while(local_enum.hasMoreElements()) {
2025            theNode = (DefaultMutableTreeNode) local_enum.nextElement();
2026            theObj = (HObject) theNode.getUserObject();
2027            if (theObj == null) {
2028                continue;
2029            }
2030
2031            if(theObj.equals(obj)) {
2032                return theNode;
2033            }
2034        }
2035
2036        return null;
2037    }
2038
2039    /**
2040     * Gets the selected file. When multiple files are open, we need to know
2041     * which file is currently selected.
2042     *
2043     * @return the FileFormat of the currently selected file.
2044     */
2045    @Override
2046    public FileFormat getSelectedFile() {
2047        return selectedFile;
2048    }
2049
2050    /**
2051     * Gets a list of selected object in the tree. Obtaining a list of current
2052     * selected objects is necessary for copy/paste/delete objects.
2053     *
2054     * @return a list of selected object in the tree.
2055     */
2056    public List<Object> getSelectedObjects() {
2057        TreePath[] paths = tree.getSelectionPaths();
2058        if ((paths == null) || (paths.length <= 0)) {
2059            return null;
2060        }
2061        log.trace("getSelectedObjects: start");
2062
2063        List<Object> objs = new Vector<Object>(paths.length);
2064        HObject theObject = null, parentObject;
2065        DefaultMutableTreeNode currentNode = null, parentNode = null;
2066        for (int i = 0; i < paths.length; i++) {
2067            currentNode = (DefaultMutableTreeNode) (paths[i].getLastPathComponent());
2068            theObject = (HObject) currentNode.getUserObject();
2069
2070            if (theObject != null) {
2071                log.trace("getSelectedObjects: theObject={}",theObject);
2072                objs.add(theObject);
2073                // removed the group from the selected list if some of its
2074                // members are selected
2075                // to avoid duplicated copy/paste when a group is pasted.
2076                parentNode = (DefaultMutableTreeNode) currentNode.getParent();
2077                parentObject = (HObject) parentNode.getUserObject();
2078                log.trace("getSelectedObjects: parentObject={}",parentObject);
2079                objs.remove(parentObject);
2080            }
2081        }
2082
2083        log.trace("getSelectedObjects: finish");
2084        return objs;
2085    }
2086
2087    /**
2088     * @return the currently selected object in the tree.
2089     */
2090    @Override
2091    public HObject getCurrentObject() {
2092        return selectedObject;
2093    }
2094
2095    /**
2096     * @return the JTree which holds the file structure.
2097     */
2098    @Override
2099    public JTree getTree() {
2100        return tree;
2101    }
2102
2103    /**
2104     * @return the list of currently open files.
2105     */
2106    @Override
2107    public List<FileFormat> getCurrentFiles() {
2108        return fileList;
2109    }
2110
2111    /**
2112     * Display the content of a data object.
2113     *
2114     * @param dataObject
2115     *            the data object
2116     *
2117     * @return the DataView that displays the data content
2118     *
2119     * @throws Exception if a failure occurred
2120     */
2121    @Override
2122    public DataView showDataContent(HObject dataObject) throws Exception {
2123        log.trace("showDataContent({}): start", dataObject.getName());
2124
2125        if ((dataObject == null) || !(dataObject instanceof Dataset)) {
2126            return null; // can only display dataset
2127        }
2128
2129        Dataset d = (Dataset) dataObject;
2130
2131        if (d.getRank() <= 0) d.init();
2132
2133        boolean isText = ((d instanceof ScalarDS) && ((ScalarDS) d).isText());
2134        boolean isImage = ((d instanceof ScalarDS) && ((ScalarDS) d).isImage());
2135        boolean isDisplayTypeChar = false;
2136        boolean isTransposed = false;
2137        boolean isIndexBase1 = ViewProperties.isIndexBase1();
2138        BitSet bitmask = null;
2139        String dataViewName = null;
2140        log.trace("showDataContent: inited");
2141
2142        JInternalFrame theFrame = (JInternalFrame) viewer.getDataView(d);
2143
2144        if (isDefaultDisplay) {
2145
2146            if (theFrame != null) {
2147                theFrame.toFront();
2148                return null;
2149            }
2150
2151            if (isText) {
2152                dataViewName = (String) HDFView.getListOfTextView().get(0);
2153            }
2154            else if (isImage) {
2155                dataViewName = (String) HDFView.getListOfImageView().get(0);
2156            }
2157            else {
2158                dataViewName = (String) HDFView.getListOfTableView().get(0);
2159            }
2160        }
2161        else {
2162            DataOptionDialog dialog = new DataOptionDialog(viewer, d);
2163
2164            dialog.setVisible(true);
2165            if (dialog.isCancelled()) {
2166                return null;
2167            }
2168
2169            isImage = dialog.isImageDisplay();
2170            isDisplayTypeChar = dialog.isDisplayTypeChar();
2171            dataViewName = dialog.getDataViewName();
2172            isTransposed = dialog.isTransposed();
2173            bitmask = dialog.getBitmask();
2174            isIndexBase1 = dialog.isIndexBase1();
2175            isApplyBitmaskOnly = dialog.isApplyBitmaskOnly();
2176        }
2177        log.trace("showDataContent: {}", dataViewName);
2178
2179        // Enables use of JHDF5 in JNLP (Web Start) applications, the system
2180        // class loader with reflection first.
2181        Class<?> theClass = null;
2182        try {
2183            theClass = Class.forName(dataViewName);
2184        }
2185        catch (Exception ex) {
2186            try {
2187                theClass = ViewProperties.loadExtClass().loadClass(dataViewName);
2188            }
2189            catch (Exception ex2) {
2190                theClass = null;
2191            }
2192        }
2193
2194        // Use default dataview
2195        if (theClass == null) {
2196            log.trace("showDataContent: Using default dataview");
2197            if (isText)
2198                dataViewName = "hdf.view.DefaultTextView";
2199            else if (isImage)
2200                dataViewName = "hdf.view.DefaultImageView";
2201            else
2202                dataViewName = "hdf.view.DefaultTableView";
2203            try {
2204                theClass = Class.forName(dataViewName);
2205            }
2206            catch (Exception ex) {
2207                log.debug("Class.forName {} failure: ", dataViewName, ex);
2208            }
2209        }
2210        Object theView = null;
2211        Object[] initargs = { viewer };
2212        HashMap<DATA_VIEW_KEY, Serializable> map = new HashMap<DATA_VIEW_KEY, Serializable>(8);
2213        map.put(ViewProperties.DATA_VIEW_KEY.INDEXBASE1, new Boolean(isIndexBase1));
2214        if (bitmask != null) {
2215            map.put(ViewProperties.DATA_VIEW_KEY.BITMASK, bitmask);
2216            if (isApplyBitmaskOnly) map.put(ViewProperties.DATA_VIEW_KEY.BITMASKOP, ViewProperties.BITMASK_OP.AND);
2217
2218            // Create a copy of the dataset
2219            ScalarDS d_copy = null;
2220            Constructor<? extends Dataset> constructor = null;
2221            Object[] paramObj = null;
2222            try {
2223                Class<?>[] paramClass = { FileFormat.class, String.class, String.class, long[].class };
2224                constructor = d.getClass().getConstructor(paramClass);
2225
2226                paramObj = new Object[] { d.getFileFormat(), d.getName(), d.getPath(), d.getOID() };
2227            }
2228            catch (Exception ex) {
2229                constructor = null;
2230            }
2231
2232            try {
2233                d_copy = (ScalarDS) constructor.newInstance(paramObj);
2234            }
2235            catch (Exception ex) {
2236                d_copy = null;
2237            }
2238            if (d_copy != null) {
2239                try {
2240                    d_copy.init();
2241                    log.trace("showDataContent: d_copy inited");
2242                    int rank = d.getRank();
2243                    System.arraycopy(d.getDims(), 0, d_copy.getDims(), 0, rank);
2244                    System.arraycopy(d.getStartDims(), 0, d_copy.getStartDims(), 0, rank);
2245                    System.arraycopy(d.getSelectedDims(), 0, d_copy.getSelectedDims(), 0, rank);
2246                    System.arraycopy(d.getStride(), 0, d_copy.getStride(), 0, rank);
2247                    System.arraycopy(d.getSelectedIndex(), 0, d_copy.getSelectedIndex(), 0, 3);
2248                }
2249                catch (Throwable ex) {
2250                    ex.printStackTrace();
2251                }
2252
2253                map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, d_copy);
2254            }
2255        }
2256        if (dataViewName.startsWith("hdf.view.DefaultTableView")) {
2257            map.put(ViewProperties.DATA_VIEW_KEY.CHAR, new Boolean(isDisplayTypeChar));
2258            map.put(ViewProperties.DATA_VIEW_KEY.TRANSPOSED, new Boolean(isTransposed));
2259            Object[] tmpargs = { viewer, map };
2260            initargs = tmpargs;
2261        }
2262        else if (dataViewName.startsWith("hdf.view.DefaultImageView")) {
2263            map.put(ViewProperties.DATA_VIEW_KEY.CONVERTBYTE, new Boolean((bitmask != null)));
2264            Object[] tmpargs = { viewer, map };
2265            initargs = tmpargs;
2266        }
2267
2268        try {
2269            ((JFrame) viewer).setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
2270
2271            theView = Tools.newInstance(theClass, initargs);
2272            log.trace("showDataContent: Tools.newInstance");
2273
2274            viewer.addDataView((DataView) theView);
2275        }
2276        catch (Exception ex) {
2277            log.trace("showDataContent: Error instantiating class {}", theClass);
2278        }
2279        finally {
2280            ((JFrame) viewer).setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
2281        }
2282
2283        log.trace("showDataContent({}): finish", dataObject.getName());
2284        return (DataView) theView;
2285    }
2286
2287    /**
2288     * Displays the meta data of a data object.
2289     *
2290     * @param dataObject
2291     *            the data object
2292     *
2293     * @return the MetaDataView that displays the MetaData of the data object
2294     *
2295     * @throws Exception if a failure occurred
2296     */
2297    @Override
2298    public MetaDataView showMetaData(HObject dataObject) throws Exception {
2299        if (dataObject == null) {
2300            return null;
2301        }
2302
2303        List<?> metaDataViewList = HDFView.getListOfMetaDataView();
2304        if ((metaDataViewList == null) || (metaDataViewList.size() <= 0)) {
2305            return null;
2306        }
2307
2308        int n = metaDataViewList.size();
2309        String className = (String) metaDataViewList.get(0);
2310
2311        if (!isDefaultDisplay && (n > 1)) {
2312            className = (String) JOptionPane.showInputDialog(this, "Select MetaDataView", "HDFView",
2313                    JOptionPane.INFORMATION_MESSAGE, null, metaDataViewList.toArray(), className);
2314        }
2315
2316        // Enables use of JHDF5 in JNLP (Web Start) applications, the system
2317        // class loader with reflection first.
2318        Class<?> theClass = null;
2319        try {
2320            theClass = Class.forName(className);
2321        }
2322        catch (Exception ex) {
2323            theClass = ViewProperties.loadExtClass().loadClass(className);
2324        }
2325
2326        Object[] initargs = { viewer };
2327        MetaDataView dataView = (MetaDataView) Tools.newInstance(theClass, initargs);
2328
2329        return dataView;
2330    }
2331
2332    /**
2333     * This class is used to change the default icons for tree nodes.
2334     *
2335     * @see javax.swing.tree.DefaultTreeCellRenderer
2336     */
2337    private class HTreeCellRenderer extends DefaultTreeCellRenderer {
2338        private static final long serialVersionUID = -9030708781106435297L;
2339        private Icon              h4Icon, h4IconR, h5Icon, h5IconR, datasetIcon, imageIcon, tableIcon, textIcon, openFolder, closeFolder,
2340        datasetIconA, imageIconA, tableIconA, textIconA, openFolderA, closeFolderA, datatypeIcon,
2341        datatypeIconA, questionIcon;
2342
2343        private HTreeCellRenderer() {
2344            super();
2345
2346            openFolder = ViewProperties.getFolderopenIcon();
2347            closeFolder = ViewProperties.getFoldercloseIcon();
2348            datasetIcon = ViewProperties.getDatasetIcon();
2349            imageIcon = ViewProperties.getImageIcon();
2350            h4Icon = ViewProperties.getH4Icon();
2351            h4IconR = ViewProperties.getH4IconR();
2352            h5Icon = ViewProperties.getH5Icon();
2353            h5IconR = ViewProperties.getH5IconR();
2354            tableIcon = ViewProperties.getTableIcon();
2355            textIcon = ViewProperties.getTextIcon();
2356
2357            openFolderA = ViewProperties.getFolderopenIconA();
2358            closeFolderA = ViewProperties.getFoldercloseIconA();
2359            datasetIconA = ViewProperties.getDatasetIconA();
2360            imageIconA = ViewProperties.getImageIconA();
2361            tableIconA = ViewProperties.getTableIconA();
2362            textIconA = ViewProperties.getTextIconA();
2363            datatypeIcon = ViewProperties.getDatatypeIcon();
2364            datatypeIconA = ViewProperties.getDatatypeIconA();
2365
2366            questionIcon = ViewProperties.getQuestionIcon();
2367
2368            if (openFolder != null) {
2369                openIcon = openFolder;
2370            }
2371            else {
2372                openFolder = this.openIcon;
2373            }
2374
2375            if (closeFolder != null) {
2376                closedIcon = closeFolder;
2377            }
2378            else {
2379                closeFolder = closedIcon;
2380            }
2381
2382            if (datasetIcon == null) {
2383                datasetIcon = leafIcon;
2384            }
2385            if (imageIcon == null) {
2386                imageIcon = leafIcon;
2387            }
2388            if (tableIcon == null) {
2389                tableIcon = leafIcon;
2390            }
2391            if (textIcon == null) {
2392                textIcon = leafIcon;
2393            }
2394            if (h4Icon == null) {
2395                h4Icon = leafIcon;
2396            }
2397            if (h4IconR == null) {
2398                h4IconR = leafIcon;
2399            }
2400            if (h5Icon == null) {
2401                h5Icon = leafIcon;
2402            }
2403            if (h5IconR == null) {
2404                h5IconR = leafIcon;
2405            }
2406            if (datatypeIcon == null) {
2407                datatypeIcon = leafIcon;
2408            }
2409
2410            if (questionIcon == null) {
2411                questionIcon = leafIcon;
2412            }
2413
2414            if (openFolderA == null) {
2415                openFolderA = openFolder;
2416            }
2417            if (closeFolderA == null) {
2418                closeFolderA = closeFolder;
2419            }
2420            if (datasetIconA == null) {
2421                datasetIconA = datasetIcon;
2422            }
2423            if (imageIconA == null) {
2424                imageIconA = imageIcon;
2425            }
2426            if (tableIconA == null) {
2427                tableIconA = tableIcon;
2428            }
2429            if (textIconA == null) {
2430                textIconA = textIcon;
2431            }
2432            if (datatypeIconA == null) {
2433                datatypeIconA = datatypeIcon;
2434            }
2435        }
2436
2437        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
2438                boolean leaf, int row, boolean hasFocus) {
2439            HObject theObject = (HObject) ((DefaultMutableTreeNode) value).getUserObject();
2440
2441            if (theObject == null)
2442                return super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
2443
2444            boolean hasAttribute = theObject.hasAttribute();
2445
2446            if (theObject instanceof Dataset) {
2447                if (theObject instanceof ScalarDS) {
2448                    ScalarDS sd = (ScalarDS) theObject;
2449                    if (sd.isImage()) {
2450                        if (hasAttribute) {
2451                            leafIcon = imageIconA;
2452                        }
2453                        else {
2454                            leafIcon = imageIcon;
2455                        }
2456                    }
2457                    else if (sd.isText()) {
2458                        if (hasAttribute) {
2459                            leafIcon = textIconA;
2460                        }
2461                        else {
2462                            leafIcon = textIcon;
2463                        }
2464                    }
2465                    else {
2466                        if (hasAttribute) {
2467                            leafIcon = datasetIconA;
2468                        }
2469                        else {
2470                            leafIcon = datasetIcon;
2471                        }
2472
2473                    }
2474                }
2475                else if (theObject instanceof CompoundDS) {
2476                    if (hasAttribute) {
2477                        leafIcon = tableIconA;
2478                    }
2479                    else {
2480                        leafIcon = tableIcon;
2481                    }
2482                }
2483            }
2484            else if (theObject instanceof Group) {
2485                Group g = (Group) theObject;
2486
2487                if (hasAttribute) {
2488                    openIcon = openFolderA;
2489                    closedIcon = closeFolderA;
2490                }
2491                else {
2492                    openIcon = openFolder;
2493                    closedIcon = closeFolder;
2494                }
2495
2496                if (g.isRoot()) {
2497                    if (g.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) {
2498                        if(g.getFileFormat().isReadOnly())
2499                            openIcon = closedIcon = h5IconR;
2500                        else
2501                            openIcon = closedIcon = h5Icon;
2502                    }
2503                    else if (g.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4))) {
2504                        if(g.getFileFormat().isReadOnly())
2505                            openIcon = closedIcon = h4IconR;
2506                        else
2507                            openIcon = closedIcon = h4Icon;
2508                    }
2509                }
2510            }
2511            else if (theObject instanceof Datatype) {
2512                Datatype t = (Datatype) theObject;
2513
2514                if (hasAttribute) {
2515                    leafIcon = datatypeIconA;
2516                }
2517                else {
2518                    leafIcon = datatypeIcon;
2519                }
2520            }
2521
2522            else {
2523                leafIcon = questionIcon;
2524            }
2525
2526            return super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
2527        }
2528    } // private class HTreeCellRenderer
2529
2530    /**
2531     * Handle mouse clicks on data object in the tree view. A right mouse-click
2532     * to show the popup menu for user choice. A double left-mouse-click to
2533     * display the data content. A single left-mouse-click to select the current
2534     * data object.
2535     */
2536    private class HTreeMouseAdapter extends MouseAdapter {
2537        // public void mousePressed(MouseEvent e)
2538        public void mouseReleased(MouseEvent e) {
2539            TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
2540            if (selPath == null) {
2541                return;
2542            }
2543
2544            DefaultMutableTreeNode theNode = (DefaultMutableTreeNode) selPath.getLastPathComponent();
2545            if (!theNode.equals(selectedNode)) {
2546                selectedTreePath = selPath;
2547                selectedNode = theNode;
2548                selectedObject = ((HObject) (selectedNode.getUserObject()));
2549                FileFormat theFile = selectedObject.getFileFormat();
2550                if ((theFile != null) && !theFile.equals(selectedFile)) {
2551                    // a different file is selected, handle only one file a time
2552                    selectedFile = theFile;
2553                    tree.clearSelection();
2554                    tree.setSelectionPath(selPath);
2555                }
2556
2557                viewer.mouseEventFired(e);
2558            }
2559
2560            // ***************************************************************
2561            // Different platforms have different ways to show popups
2562            // if (e.getModifiers() == MouseEvent.BUTTON3_MASK) works for all
2563            // but mac
2564            // mouseReleased() and e.isPopupTrigger() work on windows and mac
2565            // but not unix,
2566            // mouseClicked() and e.isPopupTrigger() work on unix and mac but
2567            // not windows,
2568            // to solve the problem, we use both.
2569            // 7/25/06 bug 517. e.isPopupTrigger does not work on one mouse Mac.
2570            // add (MouseEvent.BUTTON1_MASK|MouseEvent.CTRL_MASK) for MAC
2571            int eMod = e.getModifiers();
2572            if (e.isPopupTrigger()
2573                    || (eMod == MouseEvent.BUTTON3_MASK)
2574                    || (System.getProperty("os.name").startsWith("Mac") && (eMod == (MouseEvent.BUTTON1_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())))) {
2575                int selRow = tree.getRowForLocation(e.getX(), e.getY());
2576
2577                if (!tree.isRowSelected(selRow)) {
2578                    // reselect the node
2579                    tree.clearSelection();
2580                    tree.setSelectionRow(selRow);
2581                }
2582                showPopupMenu(e);
2583            }
2584            // double click to open data content
2585            else if (e.getClickCount() == 2) {
2586                isDefaultDisplay = true;
2587                try {
2588                    showDataContent(selectedObject);
2589                }
2590                catch (Exception ex) {
2591                }
2592            }
2593        } // public void mousePressed(MouseEvent e)
2594    } // private class HTreeMouseAdapter extends MouseAdapter
2595
2596    /**
2597     * Handle key pressed event.
2598     */
2599    private class HTreeKeyAdapter extends KeyAdapter {
2600
2601        @Override
2602        public void keyTyped(KeyEvent e) {
2603        }
2604
2605        @Override
2606        public void keyPressed(KeyEvent e) {
2607        }
2608
2609        @Override
2610        public void keyReleased(KeyEvent e) {
2611            int key = e.getKeyCode();
2612            if (key == KeyEvent.VK_KP_LEFT || key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_KP_UP
2613                    || key == KeyEvent.VK_KP_DOWN || key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT
2614                    || key == KeyEvent.VK_UP || key == KeyEvent.VK_DOWN) {
2615
2616                TreePath selPath = ((JTree) e.getComponent()).getSelectionPath();
2617                if (selPath == null) {
2618                    return;
2619                }
2620
2621                DefaultMutableTreeNode theNode = (DefaultMutableTreeNode) selPath.getLastPathComponent();
2622
2623                if (!theNode.equals(selectedNode)) {
2624                    selectedTreePath = selPath;
2625                    selectedNode = theNode;
2626                    selectedObject = ((HObject) (selectedNode.getUserObject()));
2627                    FileFormat theFile = selectedObject.getFileFormat();
2628                    if ((theFile != null) && !theFile.equals(selectedFile)) {
2629                        // a different file is selected, handle only one file a
2630                        // time
2631                        selectedFile = theFile;
2632                        tree.clearSelection();
2633                        tree.setSelectionPath(selPath);
2634                    }
2635
2636                    ((HDFView) viewer).showMetaData(selectedObject);
2637                }
2638            }
2639        }
2640    }
2641
2642    /**
2643     * ChangeIndexingDialog displays file index options.
2644     */
2645    private class ChangeIndexingDialog extends JDialog implements ActionListener {
2646        private static final long serialVersionUID = 1048114401768228742L;
2647
2648        private JRadioButton checkIndexType;
2649        private JRadioButton checkIndexOrder;
2650        private JRadioButton checkIndexNative;
2651
2652        private boolean reloadFile;
2653
2654        private FileFormat selectedFile;
2655        private int indexType;
2656        private int indexOrder;
2657
2658        /**
2659         * constructs an UserOptionsDialog.
2660         *
2661         * @param view
2662         *            The HDFView.
2663         */
2664        private ChangeIndexingDialog(JFrame view, FileFormat viewSelectedFile) {
2665            super(view, "Index Options", true);
2666
2667            selectedFile = viewSelectedFile;
2668            indexType = selectedFile.getIndexType(null);
2669            indexOrder = selectedFile.getIndexOrder(null);
2670            reloadFile = false;
2671
2672            JPanel contentPane = (JPanel) getContentPane();
2673            contentPane.setLayout(new BorderLayout(8, 8));
2674            contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
2675
2676            JPanel indexP = new JPanel();
2677            TitledBorder tborder = new TitledBorder("Index Options");
2678            tborder.setTitleColor(Color.darkGray);
2679            indexP.setBorder(tborder);
2680            indexP.setLayout(new GridLayout(2, 1, 10, 10));
2681            indexP.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
2682            contentPane.add(indexP);
2683
2684            JPanel pType = new JPanel();
2685            tborder = new TitledBorder("Indexing Type");
2686            tborder.setTitleColor(Color.darkGray);
2687            pType.setBorder(tborder);
2688            pType.setLayout(new GridLayout(1, 2, 8, 8));
2689            checkIndexType = new JRadioButton("By Name", (indexType) == selectedFile.getIndexType("H5_INDEX_NAME"));
2690            checkIndexType.setName("Index by Name");
2691            pType.add(checkIndexType);
2692            JRadioButton checkIndexCreateOrder = new JRadioButton("By Creation Order", (indexType) == selectedFile.getIndexType("H5_INDEX_CRT_ORDER"));
2693            checkIndexCreateOrder.setName("Index by Creation Order");
2694            pType.add(checkIndexCreateOrder);
2695            ButtonGroup bTypegrp = new ButtonGroup();
2696            bTypegrp.add(checkIndexType);
2697            bTypegrp.add(checkIndexCreateOrder);
2698            indexP.add(pType);
2699
2700            JPanel pOrder = new JPanel();
2701            tborder = new TitledBorder("Indexing Order");
2702            tborder.setTitleColor(Color.darkGray);
2703            pOrder.setBorder(tborder);
2704            pOrder.setLayout(new GridLayout(1, 3, 8, 8));
2705            checkIndexOrder = new JRadioButton("Increments", (indexOrder) == selectedFile.getIndexOrder("H5_ITER_INC"));
2706            checkIndexOrder.setName("Index Increments");
2707            pOrder.add(checkIndexOrder);
2708            JRadioButton checkIndexDecrement = new JRadioButton("Decrements", (indexOrder) == selectedFile.getIndexOrder("H5_ITER_DEC"));
2709            checkIndexDecrement.setName("Index Decrements");
2710            pOrder.add(checkIndexDecrement);
2711            checkIndexNative = new JRadioButton("Native", (indexOrder) == selectedFile.getIndexOrder("H5_ITER_NATIVE"));
2712            checkIndexNative.setName("Index Native");
2713            pOrder.add(checkIndexNative);
2714            ButtonGroup bOrdergrp = new ButtonGroup();
2715            bOrdergrp.add(checkIndexOrder);
2716            bOrdergrp.add(checkIndexDecrement);
2717            bOrdergrp.add(checkIndexNative);
2718            indexP.add(pOrder);
2719
2720            JPanel buttonP = new JPanel();
2721            JButton b = new JButton("Reload File");
2722            b.setName("Reload File");
2723            b.setActionCommand("Reload File");
2724            b.addActionListener(this);
2725            buttonP.add(b);
2726            b = new JButton("Cancel");
2727            b.setName("Cancel");
2728            b.setActionCommand("Cancel");
2729            b.addActionListener(this);
2730            buttonP.add(b);
2731
2732            contentPane.add("Center", indexP);
2733            contentPane.add("South", buttonP);
2734
2735            // locate the parent dialog
2736            Point l = getParent().getLocation();
2737            l.x += 250;
2738            l.y += 80;
2739            setLocation(l);
2740            validate();
2741            pack();
2742        }
2743
2744        public void setVisible(boolean b) {
2745            super.setVisible(b);
2746        }
2747
2748        public void actionPerformed(ActionEvent e) {
2749            String cmd = e.getActionCommand();
2750
2751            if (cmd.equals("Reload File")) {
2752                setIndexOptions();
2753                setVisible(false);
2754            }
2755            else if (cmd.equals("Cancel")) {
2756                reloadFile = false;
2757                setVisible(false);
2758            }
2759        }
2760
2761        private void setIndexOptions() {
2762            if (checkIndexType.isSelected())
2763                selectedFile.setIndexType(selectedFile.getIndexType("H5_INDEX_NAME"));
2764            else
2765                selectedFile.setIndexType(selectedFile.getIndexType("H5_INDEX_CRT_ORDER"));
2766            indexType = selectedFile.getIndexType(null);
2767
2768            if (checkIndexOrder.isSelected())
2769                selectedFile.setIndexOrder(selectedFile.getIndexOrder("H5_ITER_INC"));
2770            else if (checkIndexNative.isSelected())
2771                selectedFile.setIndexOrder(selectedFile.getIndexOrder("H5_ITER_NATIVE"));
2772            else
2773                selectedFile.setIndexOrder(selectedFile.getIndexOrder("H5_ITER_DEC"));
2774            indexOrder = selectedFile.getIndexOrder(null);
2775
2776            reloadFile = true;
2777        }
2778
2779        public int getIndexType() {
2780            return indexType;
2781        }
2782
2783        public int getIndexOrder() {
2784            return indexOrder;
2785        }
2786
2787        public boolean isreloadFile() {
2788            return reloadFile;
2789        }
2790    }
2791
2792    @SuppressWarnings("rawtypes")
2793    private void setLibVersionBounds() {
2794        Object[] lowValues = { "Earliest", "Latest" };
2795        Object[] highValues = { "Latest" };
2796        JComboBox lowComboBox = new JComboBox(lowValues);
2797        lowComboBox.setName("earliestversion");
2798        JComboBox highComboBox = new JComboBox(highValues);
2799        highComboBox.setName("latestversion");
2800
2801        Object[] msg = { "Earliest Version:", lowComboBox, "Latest Version:", highComboBox };
2802        Object[] options = { "Ok", "Cancel" };
2803        JOptionPane op = new JOptionPane(msg, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, options);
2804
2805        op.setName("libselect");
2806        JDialog dialog = op.createDialog(this, "Set the library version bounds: ");
2807        dialog.setVisible(true);
2808
2809        String result = null;
2810        try {
2811            result = (String) op.getValue();
2812        }
2813        catch (Exception err) {
2814            // err.printStackTrace();
2815        }
2816
2817        if ((result != null) && (result.equals("Ok"))) {
2818            int low = -1;
2819            int high = 1;
2820            if ((lowComboBox.getSelectedItem()).equals("Earliest"))
2821                low = 0;
2822            else
2823                low = 1;
2824            try {
2825                selectedObject.getFileFormat().setLibBounds(low, high);
2826            }
2827            catch (Throwable err) {
2828                toolkit.beep();
2829                JOptionPane.showMessageDialog(this, err, "Error when setting lib version bounds",
2830                        JOptionPane.ERROR_MESSAGE);
2831                return;
2832            }
2833        }
2834        else
2835            return;
2836    }
2837}