    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 files COPYING and Copyright.html. *
    009 * COPYING can be found at the root of the source code distribution tree.    *
    010 * Or, see https://support.hdfgroup.org/products/licenses.html               *
    011 * If you do not have access to either file, you may request a copy from     *
    012 * help@hdfgroup.org.                                                        *
    013 ****************************************************************************/
    014
    015package hdf.view;
    016
    017import java.io.BufferedInputStream;
    018import java.io.BufferedOutputStream;
    019import java.io.File;
    020import java.io.FileOutputStream;
    021import java.net.URL;
    022import java.util.ArrayList;
    023import java.util.Arrays;
    024import java.util.Enumeration;
    025import java.util.Iterator;
    026import java.util.List;
    027import java.util.Vector;
    028
    029import org.eclipse.jface.preference.PreferenceManager;
    030import org.eclipse.swt.SWT;
    031import org.eclipse.swt.custom.SashForm;
    032import org.eclipse.swt.custom.ScrolledComposite;
    033import org.eclipse.swt.dnd.DND;
    034import org.eclipse.swt.dnd.DropTarget;
    035import org.eclipse.swt.dnd.DropTargetEvent;
    036import org.eclipse.swt.dnd.DropTargetListener;
    037import org.eclipse.swt.dnd.FileTransfer;
    038import org.eclipse.swt.dnd.Transfer;
    039import org.eclipse.swt.events.DisposeEvent;
    040import org.eclipse.swt.events.DisposeListener;
    041import org.eclipse.swt.events.KeyAdapter;
    042import org.eclipse.swt.events.KeyEvent;
    043import org.eclipse.swt.events.SelectionAdapter;
    044import org.eclipse.swt.events.SelectionEvent;
    045import org.eclipse.swt.graphics.Font;
    046import org.eclipse.swt.graphics.Image;
    047import org.eclipse.swt.graphics.Point;
    048import org.eclipse.swt.graphics.Rectangle;
    049import org.eclipse.swt.layout.FillLayout;
    050import org.eclipse.swt.layout.GridData;
    051import org.eclipse.swt.layout.GridLayout;
    052import org.eclipse.swt.layout.RowLayout;
    053import org.eclipse.swt.widgets.Button;
    054import org.eclipse.swt.widgets.Combo;
    055import org.eclipse.swt.widgets.Composite;
    056import org.eclipse.swt.widgets.Control;
    057import org.eclipse.swt.widgets.Dialog;
    058import org.eclipse.swt.widgets.Display;
    059import org.eclipse.swt.widgets.Event;
    060import org.eclipse.swt.widgets.FileDialog;
    061import org.eclipse.swt.widgets.Label;
    062import org.eclipse.swt.widgets.Listener;
    063import org.eclipse.swt.widgets.Menu;
    064import org.eclipse.swt.widgets.MenuItem;
    065import org.eclipse.swt.widgets.Monitor;
    066import org.eclipse.swt.widgets.Shell;
    067import org.eclipse.swt.widgets.Text;
    068import org.eclipse.swt.widgets.ToolBar;
    069import org.eclipse.swt.widgets.ToolItem;
    070
    071import hdf.HDFVersions;
    072import hdf.object.FileFormat;
    073import hdf.object.HObject;
    074import hdf.view.ViewProperties.DataViewType;
    075import hdf.view.HelpView.HelpView;
    076import hdf.view.MetaDataView.MetaDataView;
    077import hdf.view.TableView.TableView;
    078import hdf.view.TreeView.DefaultTreeView;
    079import hdf.view.TreeView.TreeView;
    080import hdf.view.dialog.ImageConversionDialog;
    081import hdf.view.dialog.InputDialog;
    082import hdf.view.dialog.UserOptionsDialog;
    083import hdf.view.dialog.UserOptionsGeneralPage;
    084import hdf.view.dialog.UserOptionsHDFPage;
    085import hdf.view.dialog.UserOptionsNode;
    086
    087
    088/**
    089 * HDFView is the main class of this HDF visual tool. It is used to layout the
    090 * graphical components of the hdfview. The major GUI components of the HDFView
    091 * include Menubar, Toolbar, TreeView, ContentView, and MessageArea.
    092 * <p>
    093 * The HDFView is designed in such a way that it does not have direct access to
    094 * the HDF library. All the HDF library access is done through HDF objects.
    095 * Therefore, the HDFView package depends on the object package but not the
    096 * library package. The source code of the view package (hdf.view) should
    097 * be compiled with the library package (hdf.hdflib and hdf.hdf5lib).
    098 *
    099 * @author Jordan T. Henderson
    100 * @version 2.4 //2015
    101 */
    102public class HDFView implements ViewManager {
    103
    104    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(HDFView.class);
    105
    106    private static Display             display;
    107    private static Shell               mainWindow;
    108
    109    /* Determines whether HDFView is being executed for GUI testing */
    110    private boolean                    isTesting = false;
    111
    112    /* The directory where HDFView is installed */
    113    private String                     rootDir;
    114
    115    /* The current working directory */
    116    private String                     currentDir;
    117
    118    /* The current working file */
    119    private String                     currentFile = null;
    120
    121    /* The view properties */
    122    private ViewProperties             props;
    123
    124    /* A list of tree view implementations. */
    125    private static List<String>        treeViews;
    126
    127    /* A list of image view implementations. */
    128    private static List<String>        imageViews;
    129
    130    /* A list of tree table implementations. */
    131    private static List<?>             tableViews;
    132
    133    /* A list of metadata view implementations. */
    134    private static List<?>             metaDataViews;
    135
    136    /* A list of palette view implementations. */
    137    private static List<?>             paletteViews;
    138
    139    /* A list of help view implementations. */
    140    private static List<?>             helpViews;
    141
    142    /* The list of GUI components related to HDF4 */
    143    private final List<MenuItem>       h4GUIs = new Vector<>();
    144
    145    /* The list of GUI components related to HDF5 */
    146    private final List<MenuItem>       h5GUIs = new Vector<>();
    147
    148    /* The list of GUI components related to editing */
    149    //private final List<?>            editGUIs;
    150
    151    /* GUI component: the TreeView */
    152    private TreeView                   treeView = null;
    153
    154    private static final String        HDF4_VERSION = HDFVersions.HDF4_VERSION;
    155    private static final String        HDF5_VERSION = HDFVersions.HDF5_VERSION;
    156    private static final String        HDFVIEW_VERSION = HDFVersions.HDFVIEW_VERSION;
    157    private static final String        HDFVIEW_USERSGUIDE_URL = "https://support.hdfgroup.org/products/java/hdfview/index.html";
    158    private static final String        JAVA_COMPILER = "jdk 1.7";
    159    private static final String        JAVA_VER_INFO = "Compiled at " + JAVA_COMPILER + "\nRunning at " + System.getProperty("java.version");
    160
    161    private static final String        aboutHDFView = "HDF Viewer, " + "Version " + ViewProperties.VERSION + "\n"
    162            + "For " + System.getProperty("os.name") + "\n\n"
    163            + "Copyright " + '\u00a9' + " 2006-2017 The HDF Group.\n"
    164            + "All rights reserved.";
    165
    166    /* GUI component: The toolbar for open, close, help and hdf4 and hdf5 library information */
    167    private ToolBar                    toolBar;
    168
    169    /* GUI component: The text area for showing status messages */
    170    private Text                       status;
    171
    172    /* GUI component: The area for quick general view */
    173    private ScrolledComposite          generalArea;
    174
    175    /* GUI component: To add and display URLs */
    176    private Combo                      url_bar;
    177
    178    private Button                     recentFilesButton;
    179    private Button                     clearTextButton;
    180
    181    /* GUI component: A list of current data windows */
    182    private Menu                       windowMenu;
    183
    184    /* GUI component: File menu on the menubar */
    185    //private final Menu               fileMenu;
    186
    187    /* The font to be used for display text on all Controls */
    188    private Font                       currentFont;
    189
    190    private UserOptionsDialog          userOptionDialog;
    191
    192    /**
    193     * Constructs HDFView with a given root directory, where the HDFView is
    194     * installed, and opens the given files in the viewer.
    195     *
    196     * @param root
    197     *            the directory where the HDFView is installed.
    198     */
    199    public HDFView(String root) {
    200        log.debug("Root is {}", root);
    201
    202        if (display == null || display.isDisposed()) display = new Display();
    203
    204        rootDir = root;
    205
    206        //editGUIs = new Vector<Object>();
    207
    208        props = new ViewProperties(rootDir);
    209        try {
    210            props.load();
    211        }
    212        catch (Exception ex) {
    213            log.debug("Failed to load View Properties from {}", rootDir);
    214        }
    215
    216        ViewProperties.loadIcons();
    217
    218        currentDir = ViewProperties.getWorkDir();
    219        if (currentDir == null) currentDir = System.getProperty("user.home");
    220
    221        log.info("Current directory is {}", currentDir);
    222
    223        try {
    224            currentFont = new Font(
    225                    display,
    226                    ViewProperties.getFontType(),
    227                    ViewProperties.getFontSize(),
    228                    SWT.NORMAL);
    229        }
    230        catch (Exception ex) {
    231            currentFont = null;
    232        }
    233
    234        treeViews = ViewProperties.getTreeViewList();
    235        metaDataViews = ViewProperties.getMetaDataViewList();
    236        tableViews = ViewProperties.getTableViewList();
    237        imageViews = ViewProperties.getImageViewList();
    238        paletteViews = ViewProperties.getPaletteViewList();
    239        helpViews = ViewProperties.getHelpViewList();
    240
    241        log.debug("Constructor exit");
    242    }
    243
    244
    245    /**
    246     * Creates HDFView with a given size, and opens the given files in the viewer.
    247     *
    248     * @param flist
    249     *            a list of files to open.
    250     * @param width
    251     *            the width of the app in pixels
    252     * @param height
    253     *            the height of the app in pixels
    254     * @param x
    255     *            the coord x of the app in pixels
    256     * @param y
    257     *            the coord y of the app in pixels
    258     *
    259     * @return
    260     *            the newly-created HDFView Shell
    261     */
    262    public Shell openMainWindow(List<File> flist, int width, int height, int x, int y) {
    263        log.debug("openMainWindow enter");
    264
    265        // Initialize all GUI components
    266        mainWindow = createMainWindow();
    267
    268        try {
    269            Font font = null;
    270            String fType = ViewProperties.getFontType();
    271            int fSize = ViewProperties.getFontSize();
    272
    273            try {
    274                font = new Font(display, fType, fSize, SWT.NORMAL);
    275            }
    276            catch (Exception ex) {
    277                font = null;
    278            }
    279
    280            if (font != null)
    281                updateFont(font);
    282        }
    283        catch (Exception ex) {
    284            log.debug("Failed to load Font properties");
    285        }
    286
    287        // Make sure all GUI components are in place before
    288        // opening any files
    289        mainWindow.pack();
    290
    291        int nfiles = flist.size();
    292        File theFile = null;
    293        for (int i = 0; i < nfiles; i++) {
    294            theFile = flist.get(i);
    295
    296            if (theFile.isFile()) {
    297                currentDir = theFile.getParentFile().getAbsolutePath();
    298                currentFile = theFile.getAbsolutePath();
    299
    300                try {
    301                    treeView.openFile(currentFile, FileFormat.WRITE);
    302
    303                    try {
    304                        url_bar.remove(currentFile);
    305                    }
    306                    catch (Exception ex) {}
    307
    308                    url_bar.add(currentFile, 0);
    309                    url_bar.select(0);
    310                }
    311                catch (Exception ex) {
    312                    showStatus(ex.toString());
    313                }
    314            }
    315            else {
    316                currentDir = theFile.getAbsolutePath();
    317            }
    318
    319            log.info("CurrentDir is {}", currentDir);
    320        }
    321
    322        if (FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4) == null)
    323            setEnabled(h4GUIs, false);
    324
    325        if (FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5) == null)
    326            setEnabled(h5GUIs, false);
    327
    328        // Set size of main window
    329        // float inset = 0.17f; // for UG only.
    330        float inset = 0.04f;
    331        Point winDim = new Point(width, height);
    332
    333        // If given height and width are too small, adjust accordingly
    334        if (height <= 300) {
    335            winDim.y = (int) ((1 - 2 * inset) * mainWindow.getSize().y);
    336        }
    337
    338        if (width <= 300) {
    339            winDim.x = (int) (0.9 * mainWindow.getSize().y);
    340        }
    341
    342        mainWindow.setLocation(x, y);
    343        mainWindow.setSize(winDim.x + 200, winDim.y);
    344
    345        // Display the window
    346        mainWindow.open();
    347        log.debug("openMainWindow exit");
    348        return mainWindow;
    349    }
    350
    351    public void runMainWindow() {
    352        log.debug("runMainWindow enter");
    353
    354        while(!mainWindow.isDisposed()) {
    355            // ===================================================
    356            // Wrap each event dispatch in an exception handler
    357            // so that if any event causes an exception it does
    358            // not break the main UI loop
    359            // ===================================================
    360            try {
    361                if (!display.readAndDispatch()) {
    362                    display.sleep();
    363                }
    364            }
    365            catch (Exception e) {
    366                e.printStackTrace();
    367            }
    368        }
    369
    370        if (!isTesting) display.dispose();
    371        log.debug("runMainWindow exit");
    372    }
    373
    374    /**
    375     * Creates and lays out GUI components.
    376     *
    377     * <pre>
    378     * ||=========||=============================||
    379     * ||         ||                             ||
    380     * ||         ||                             ||
    381     * || TreeView||       ContentPane           ||
    382     * ||         ||                             ||
    383     * ||=========||=============================||
    384     * ||            Message Area                ||
    385     * ||========================================||
    386     * </pre>
    387     */
    388    private Shell createMainWindow() {
    389        // Create a new display window
    390        final Shell shell = new Shell(display);
    391        shell.setImage(ViewProperties.getHdfIcon());
    392        shell.setFont(currentFont);
    393        shell.setText("HDFView " + HDFVIEW_VERSION);
    394        shell.setLayout(new GridLayout(3, false));
    395        shell.addDisposeListener(new DisposeListener() {
    396            @Override
    397            public void widgetDisposed(DisposeEvent e) {
    398                ViewProperties.setRecentFiles(new Vector<>(Arrays.asList(url_bar.getItems())));
    399
    400                try {
    401                    props.save();
    402                }
    403                catch (Exception ex) {}
    404
    405                closeAllWindows();
    406
    407                // Close all open files
    408                try {
    409                    List<FileFormat> filelist = treeView.getCurrentFiles();
    410
    411                    if((filelist != null) && (filelist.size() > 0)) {
    412                        Object[] files = filelist.toArray();
    413
    414                        for (int i = 0; i < files.length; i++) {
    415                            try {
    416                                treeView.closeFile((FileFormat) files[i]);
    417                            }
    418                            catch (Throwable ex) {
    419                                continue;
    420                            }
    421                        }
    422                    }
    423                }
    424                catch (Exception ex) {}
    425
    426                if (currentFont != null) currentFont.dispose();
    427            }
    428        });
    429
    430        createMenuBar(shell);
    431        createToolbar(shell);
    432        createUrlToolbar(shell);
    433        createContentArea(shell);
    434
    435        log.info("Main Window created");
    436
    437        return shell;
    438    }
    439
    440    private void createMenuBar(final Shell shell) {
    441        Menu menu = new Menu(shell, SWT.BAR);
    442        shell.setMenuBar(menu);
    443
    444        MenuItem menuItem = new MenuItem(menu, SWT.CASCADE);
    445        menuItem.setText("&File");
    446
    447        Menu fileMenu = new Menu(menuItem);
    448        menuItem.setMenu(fileMenu);
    449
    450        MenuItem item = new MenuItem(fileMenu, SWT.PUSH);
    451        item.setText("&Open\tCtrl-O");
    452        item.setAccelerator(SWT.MOD1 + 'O');
    453        item.addSelectionListener(new SelectionAdapter() {
    454            @Override
    455            public void widgetSelected(SelectionEvent e) {
    456                openLocalFile(null, -1);
    457            }
    458        });
    459
    460        item = new MenuItem(fileMenu, SWT.CASCADE);
    461        item.setText("Open As");
    462
    463        Menu openAsMenu = new Menu(item);
    464        item.setMenu(openAsMenu);
    465
    466        item = new MenuItem(openAsMenu, SWT.PUSH);
    467        item.setText("Read-Only");
    468        item.addSelectionListener(new SelectionAdapter() {
    469            @Override
    470            public void widgetSelected(SelectionEvent e) {
    471                openLocalFile(null, FileFormat.READ);
    472            }
    473        });
    474
    475        item = new MenuItem(openAsMenu, SWT.PUSH);
    476        item.setText("Read/Write");
    477        item.addSelectionListener(new SelectionAdapter() {
    478            @Override
    479            public void widgetSelected(SelectionEvent e) {
    480                openLocalFile(null, FileFormat.WRITE);
    481            }
    482        });
    483
    484        new MenuItem(fileMenu, SWT.SEPARATOR);
    485
    486        MenuItem fileNewMenu = new MenuItem(fileMenu, SWT.CASCADE);
    487        fileNewMenu.setText("New");
    488
    489        Menu newMenu = new Menu(fileNewMenu);
    490        fileNewMenu.setMenu(newMenu);
    491
    492        item = new MenuItem(newMenu, SWT.PUSH);
    493        item.setText("HDF&4");
    494        h4GUIs.add(item);
    495        item.addSelectionListener(new SelectionAdapter() {
    496            @Override
    497            public void widgetSelected(SelectionEvent e) {
    498                if (currentDir != null) {
    499                    currentDir += File.separator;
    500                }
    501                else {
    502                    currentDir = "";
    503                }
    504
    505                String filename = null;
    506
    507                if (!isTesting) {
    508                    FileDialog fChooser = new FileDialog(shell, SWT.SAVE);
    509                    fChooser.setFileName(Tools.checkNewFile(currentDir, ".hdf").getName());
    510
    511                    DefaultFileFilter filter = DefaultFileFilter.getFileFilterHDF4();
    512                    fChooser.setFilterExtensions(new String[] {filter.getExtensions()});
    513                    fChooser.setFilterNames(new String[] {filter.getDescription()});
    514                    fChooser.setFilterIndex(0);
    515
    516                    filename = fChooser.open();
    517                }
    518                else {
    519                    // Prepend test file directory to filename
    520                    filename = currentDir.concat(new InputDialog(mainWindow, "Enter a file name", "").open());
    521                }
    522
    523                if(filename == null) return;
    524
    525                try {
    526                    log.trace("HDFView create hdf4 file");
    527                    FileFormat theFile = Tools.createNewFile(filename, currentDir,
    528                            FileFormat.FILE_TYPE_HDF4, getTreeView().getCurrentFiles());
    529
    530                    if (theFile == null) return;
    531
    532                    currentDir = theFile.getParent();
    533                }
    534                catch (Exception ex) {
    535                    Tools.showError(mainWindow, "New", ex.getMessage());
    536                    return;
    537                }
    538
    539                try {
    540                    treeView.openFile(filename, FileFormat.WRITE);
    541                    currentFile = filename;
    542
    543                    try {
    544                        url_bar.remove(filename);
    545                    }
    546                    catch (Exception ex) {}
    547
    548                    url_bar.add(filename, 0);
    549                    url_bar.select(0);
    550                }
    551                catch (Exception ex) {
    552                    display.beep();
    553                    Tools.showError(mainWindow, "New", ex.getMessage() + "\n" + filename);
    554                }
    555            }
    556        });
    557
    558        item = new MenuItem(newMenu, SWT.PUSH);
    559        item.setText("HDF&5");
    560        h5GUIs.add(item);
    561        item.addSelectionListener(new SelectionAdapter() {
    562            @Override
    563            public void widgetSelected(SelectionEvent e) {
    564                if (currentDir != null) {
    565                    currentDir += File.separator;
    566                }
    567                else {
    568                    currentDir = "";
    569                }
    570
    571                String filename = null;
    572
    573                if (!isTesting) {
    574                    FileDialog fChooser = new FileDialog(shell, SWT.SAVE);
    575                    fChooser.setFileName(Tools.checkNewFile(currentDir, ".h5").getName());
    576
    577                    DefaultFileFilter filter = DefaultFileFilter.getFileFilterHDF5();
    578                    fChooser.setFilterExtensions(new String[] {filter.getExtensions()});
    579                    fChooser.setFilterNames(new String[] {filter.getDescription()});
    580                    fChooser.setFilterIndex(0);
    581
    582                    filename = fChooser.open();
    583                }
    584                else {
    585                    // Prepend test file directory to filename
    586                    filename = currentDir.concat(new InputDialog(mainWindow, "Enter a file name", "").open());
    587                }
    588
    589                if(filename == null) return;
    590
    591                try {
    592                    log.trace("HDFView create hdf5 file");
    593                    FileFormat theFile = Tools.createNewFile(filename, currentDir,
    594                            FileFormat.FILE_TYPE_HDF5, getTreeView().getCurrentFiles());
    595
    596                    if (theFile == null) return;
    597
    598                    currentDir = theFile.getParent();
    599                }
    600                catch (Exception ex) {
    601                    Tools.showError(mainWindow, "New", ex.getMessage());
    602                    return;
    603                }
    604
    605                try {
    606                    treeView.openFile(filename, FileFormat.WRITE);
    607                    currentFile = filename;
    608
    609                    try {
    610                        url_bar.remove(filename);
    611                    }
    612                    catch (Exception ex) {}
    613
    614                    url_bar.add(filename, 0);
    615                    url_bar.select(0);
    616                }
    617                catch (Exception ex) {
    618                    display.beep();
    619                    Tools.showError(mainWindow, "New", ex.getMessage() + "\n" + filename);
    620                }
    621            }
    622        });
    623
    624        new MenuItem(fileMenu, SWT.SEPARATOR);
    625
    626        item = new MenuItem(fileMenu, SWT.PUSH);
    627        item.setText("&Close");
    628        item.addSelectionListener(new SelectionAdapter() {
    629            @Override
    630            public void widgetSelected(SelectionEvent e) {
    631                closeFile(treeView.getSelectedFile());
    632            }
    633        });
    634
    635        item = new MenuItem(fileMenu, SWT.PUSH);
    636        item.setText("Close &All");
    637        item.addSelectionListener(new SelectionAdapter() {
    638            @Override
    639            public void widgetSelected(SelectionEvent e) {
    640                closeAllWindows();
    641
    642                List<FileFormat> files = treeView.getCurrentFiles();
    643                while (!files.isEmpty()) {
    644                    try {
    645                        treeView.closeFile(files.get(0));
    646                    }
    647                    catch (Exception ex) {}
    648                }
    649
    650                currentFile = null;
    651
    652                for (Control control : generalArea.getChildren()) control.dispose();
    653                generalArea.setContent(null);
    654
    655                url_bar.setText("");
    656            }
    657        });
    658
    659        new MenuItem(fileMenu, SWT.SEPARATOR);
    660
    661        item = new MenuItem(fileMenu, SWT.PUSH);
    662        item.setText("&Save");
    663        item.addSelectionListener(new SelectionAdapter() {
    664            @Override
    665            public void widgetSelected(SelectionEvent e) {
    666                if (treeView.getCurrentFiles().size() <= 0) {
    667                    Tools.showError(mainWindow, "Save", "No files currently open.");
    668                    return;
    669                }
    670
    671                if (treeView.getSelectedFile() == null) {
    672                    Tools.showError(mainWindow, "Save", "No files currently selected.");
    673                    return;
    674                }
    675
    676                // Save what has been changed in memory into file
    677                writeDataToFile(treeView.getSelectedFile());
    678            }
    679        });
    680
    681        item = new MenuItem(fileMenu, SWT.PUSH);
    682        item.setText("S&ave As");
    683        item.addSelectionListener(new SelectionAdapter() {
    684            @Override
    685            public void widgetSelected(SelectionEvent e) {
    686                if (treeView.getCurrentFiles().size() <= 0) {
    687                    Tools.showError(mainWindow, "Save", "No files currently open.");
    688                    return;
    689                }
    690
    691                if (treeView.getSelectedFile() == null) {
    692                    Tools.showError(mainWindow, "Save", "No files currently selected.");
    693                    return;
    694                }
    695
    696                try {
    697                    treeView.saveFile(treeView.getSelectedFile());
    698                }
    699                catch (Exception ex) {
    700                    display.beep();
    701                    Tools.showError(mainWindow, "Save", ex.getMessage());
    702                }
    703            }
    704        });
    705
    706        new MenuItem(fileMenu, SWT.SEPARATOR);
    707
    708        item = new MenuItem(fileMenu, SWT.PUSH);
    709        item.setText("E&xit\tCtrl-Q");
    710        item.setAccelerator(SWT.MOD1 + 'Q');
    711        item.addSelectionListener(new SelectionAdapter() {
    712            @Override
    713            public void widgetSelected(SelectionEvent e) {
    714                mainWindow.dispose();
    715            }
    716        });
    717
    718        menuItem = new MenuItem(menu, SWT.CASCADE);
    719        menuItem.setText("&Window");
    720
    721        windowMenu = new Menu(menuItem);
    722        menuItem.setMenu(windowMenu);
    723
    724        item = new MenuItem(windowMenu, SWT.PUSH);
    725        item.setText("&Cascade");
    726        item.addSelectionListener(new SelectionAdapter() {
    727            @Override
    728            public void widgetSelected(SelectionEvent e) {
    729                cascadeWindows();
    730            }
    731        });
    732
    733        item = new MenuItem(windowMenu, SWT.PUSH);
    734        item.setText("&Tile");
    735        item.addSelectionListener(new SelectionAdapter() {
    736            @Override
    737            public void widgetSelected(SelectionEvent e) {
    738                tileWindows();
    739            }
    740        });
    741
    742        new MenuItem(windowMenu, SWT.SEPARATOR);
    743
    744        item = new MenuItem(windowMenu, SWT.PUSH);
    745        item.setText("Close &All");
    746        item.addSelectionListener(new SelectionAdapter() {
    747            @Override
    748            public void widgetSelected(SelectionEvent e) {
    749                closeAllWindows();
    750            }
    751        });
    752
    753        new MenuItem(windowMenu, SWT.SEPARATOR);
    754
    755        menuItem = new MenuItem(menu, SWT.CASCADE);
    756        menuItem.setText("&Tools");
    757
    758        Menu toolsMenu = new Menu(menuItem);
    759        menuItem.setMenu(toolsMenu);
    760
    761        MenuItem convertMenuItem = new MenuItem(toolsMenu, SWT.CASCADE);
    762        convertMenuItem.setText("Convert Image To");
    763
    764        Menu convertMenu = new Menu(convertMenuItem);
    765        convertMenuItem.setMenu(convertMenu);
    766
    767        item = new MenuItem(convertMenu, SWT.PUSH);
    768        item.setText("HDF4");
    769        item.addSelectionListener(new SelectionAdapter() {
    770            @Override
    771            public void widgetSelected(SelectionEvent e) {
    772                convertFile(Tools.FILE_TYPE_IMAGE, FileFormat.FILE_TYPE_HDF4);
    773            }
    774        });
    775        h4GUIs.add(item);
    776
    777        item = new MenuItem(convertMenu, SWT.PUSH);
    778        item.setText("HDF5");
    779        item.addSelectionListener(new SelectionAdapter() {
    780            @Override
    781            public void widgetSelected(SelectionEvent e) {
    782                convertFile(Tools.FILE_TYPE_IMAGE, FileFormat.FILE_TYPE_HDF5);
    783            }
    784        });
    785        h5GUIs.add(item);
    786
    787        new MenuItem(toolsMenu, SWT.SEPARATOR);
    788
    789        item = new MenuItem(toolsMenu, SWT.PUSH);
    790        item.setText("User &Options");
    791        item.addSelectionListener(new SelectionAdapter() {
    792            @Override
    793            public void widgetSelected(SelectionEvent e) {
    794                // Create the preference manager
    795                PreferenceManager mgr = new PreferenceManager();
    796
    797                // Create the nodes
    798                UserOptionsNode one = new UserOptionsNode("general", new UserOptionsGeneralPage());
    799                UserOptionsNode two = new UserOptionsNode("hdf", new UserOptionsHDFPage());
    800
    801                /*
    802                 * TODO: Disabled until module loading is supported
    803                 */
    804                /*
    805                 * UserOptionsNode three = new UserOptionsNode("modules", new UserOptionsViewModulesPage());
    806                 */
    807
    808                // Add the nodes
    809                mgr.addToRoot(one);
    810                mgr.addToRoot(two);
    811
    812                /*
    813                 * TODO: Disabled until module loading is supported
    814                 */
    815                /* mgr.addToRoot(three); */
    816
    817                // Create the preferences dialog
    818                userOptionDialog = new UserOptionsDialog(shell, mgr, rootDir);
    819
    820                // Set the preference store
    821                userOptionDialog.setPreferenceStore(props);
    822                userOptionDialog.create();
    823
    824                // Open the dialog
    825                userOptionDialog.open();
    826
    827                //if (userOptionDialog.isWorkDirChanged())
    828                currentDir = ViewProperties.getWorkDir();
    829
    830                //if (userOptionDialog.isFontChanged()) {
    831                Font font = null;
    832
    833                try {
    834                    font = new Font(display, ViewProperties.getFontType(), ViewProperties.getFontSize(), SWT.NORMAL);
    835                }
    836                catch (Exception ex) {
    837                    font = null;
    838                }
    839
    840                updateFont(font);
    841                //}
    842            }
    843        });
    844
    845        new MenuItem(toolsMenu, SWT.SEPARATOR);
    846
    847        item = new MenuItem(toolsMenu, SWT.PUSH);
    848        item.setText("&Register File Format");
    849        item.addSelectionListener(new SelectionAdapter() {
    850            @Override
    851            public void widgetSelected(SelectionEvent e) {
    852                registerFileFormat();
    853            }
    854        });
    855
    856        item = new MenuItem(toolsMenu, SWT.PUSH);
    857        item.setText("&Unregister File Format");
    858        item.addSelectionListener(new SelectionAdapter() {
    859            @Override
    860            public void widgetSelected(SelectionEvent e) {
    861                unregisterFileFormat();
    862            }
    863        });
    864
    865        menuItem = new MenuItem(menu, SWT.CASCADE);
    866        menuItem.setText("&Help");
    867
    868        Menu helpMenu = new Menu(menuItem);
    869        menuItem.setMenu(helpMenu);
    870
    871        item = new MenuItem(helpMenu, SWT.PUSH);
    872        item.setText("&User's Guide");
    873        item.addSelectionListener(new SelectionAdapter() {
    874            @Override
    875            public void widgetSelected(SelectionEvent e) {
    876                org.eclipse.swt.program.Program.launch(HDFVIEW_USERSGUIDE_URL);
    877            }
    878        });
    879
    880        if ((helpViews != null) && (helpViews.size() > 0)) {
    881            int n = helpViews.size();
    882            for (int i = 0; i < n; i++) {
    883                HelpView theView = (HelpView) helpViews.get(i);
    884                item = new MenuItem(helpMenu, SWT.PUSH);
    885                item.setText(theView.getLabel());
    886                //item.setActionCommand(theView.getActionCommand());
    887            }
    888        }
    889
    890        new MenuItem(helpMenu, SWT.SEPARATOR);
    891
    892        item = new MenuItem(helpMenu, SWT.PUSH);
    893        item.setText("HDF&4 Library Version");
    894        h4GUIs.add(item);
    895        item.addSelectionListener(new SelectionAdapter() {
    896            @Override
    897            public void widgetSelected(SelectionEvent e) {
    898                new LibraryVersionDialog(shell, FileFormat.FILE_TYPE_HDF4).open();
    899            }
    900        });
    901
    902        item = new MenuItem(helpMenu, SWT.PUSH);
    903        item.setText("HDF&5 Library Version");
    904        h5GUIs.add(item);
    905        item.addSelectionListener(new SelectionAdapter() {
    906            @Override
    907            public void widgetSelected(SelectionEvent e) {
    908                new LibraryVersionDialog(shell, FileFormat.FILE_TYPE_HDF5).open();
    909            }
    910        });
    911
    912        item = new MenuItem(helpMenu, SWT.PUSH);
    913        item.setText("&Java Version");
    914        item.addSelectionListener(new SelectionAdapter() {
    915            @Override
    916            public void widgetSelected(SelectionEvent e) {
    917                new JavaVersionDialog(mainWindow).open();
    918            }
    919        });
    920
    921        new MenuItem(helpMenu, SWT.SEPARATOR);
    922
    923        item = new MenuItem(helpMenu, SWT.PUSH);
    924        item.setText("Supported Fi&le Formats");
    925        item.addSelectionListener(new SelectionAdapter() {
    926            @Override
    927            public void widgetSelected(SelectionEvent e) {
    928                new SupportedFileFormatsDialog(mainWindow).open();
    929            }
    930        });
    931
    932        new MenuItem(helpMenu, SWT.SEPARATOR);
    933
    934        item = new MenuItem(helpMenu, SWT.PUSH);
    935        item.setText("&About...");
    936        item.addSelectionListener(new SelectionAdapter() {
    937            @Override
    938            public void widgetSelected(SelectionEvent e) {
    939                new AboutDialog(mainWindow).open();
    940            }
    941        });
    942
    943        setEnabled(Arrays.asList(windowMenu.getItems()), false);
    944
    945        log.info("Menubar created");
    946    }
    947
    948    private void createToolbar(final Shell shell) {
    949        toolBar = new ToolBar(shell, SWT.HORIZONTAL | SWT.RIGHT);
    950        toolBar.setFont(Display.getCurrent().getSystemFont());
    951        toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
    952
    953        ToolItem openItem = new ToolItem(toolBar, SWT.PUSH);
    954        openItem.setToolTipText("Open");
    955        openItem.setImage(ViewProperties.getFileopenIcon());
    956        openItem.addSelectionListener(new SelectionAdapter() {
    957            @Override
    958            public void widgetSelected(SelectionEvent e) {
    959                openLocalFile(null, -1);
    960            }
    961        });
    962
    963        new ToolItem(toolBar, SWT.SEPARATOR).setWidth(4);
    964
    965        ToolItem closeItem = new ToolItem(toolBar, SWT.PUSH);
    966        closeItem.setImage(ViewProperties.getFilecloseIcon());
    967        closeItem.setToolTipText("Close");
    968        closeItem.addSelectionListener(new SelectionAdapter() {
    969            @Override
    970            public void widgetSelected(SelectionEvent e) {
    971                closeFile(treeView.getSelectedFile());
    972            }
    973        });
    974
    975        new ToolItem(toolBar, SWT.SEPARATOR).setWidth(20);
    976
    977        ToolItem helpItem = new ToolItem(toolBar, SWT.PUSH);
    978        helpItem.setImage(ViewProperties.getHelpIcon());
    979        helpItem.setToolTipText("Help");
    980        helpItem.addSelectionListener(new SelectionAdapter() {
    981            @Override
    982            public void widgetSelected(SelectionEvent e) {
    983                String ugPath = ViewProperties.getUsersGuide();
    984
    985                if(ugPath == null || !ugPath.startsWith("http://")) {
    986                    String sep = File.separator;
    987                    File tmpFile = new File(ugPath);
    988
    989                    if(!(tmpFile.exists())) {
    990                        ugPath = rootDir + sep + "UsersGuide" + sep + "index.html";
    991                        tmpFile = new File(ugPath);
    992
    993                        if(!(tmpFile.exists())) {
    994                            ugPath = HDFVIEW_USERSGUIDE_URL;
    995                        }
    996
    997                        ViewProperties.setUsersGuide(ugPath);
    998                    }
    999                }
    1000
    1001                try {
    1002                    org.eclipse.swt.program.Program.launch(ugPath);
    1003                }
    1004                catch (Exception ex) {
    1005                    Tools.showError(shell, "Help", ex.getMessage());
    1006                }
    1007            }
    1008        });
    1009
    1010        new ToolItem(toolBar, SWT.SEPARATOR).setWidth(4);
    1011
    1012        ToolItem hdf4Item = new ToolItem(toolBar, SWT.PUSH);
    1013        hdf4Item.setImage(ViewProperties.getH4Icon());
    1014        hdf4Item.setToolTipText("HDF4 Library Version");
    1015        hdf4Item.addSelectionListener(new SelectionAdapter() {
    1016            @Override
    1017            public void widgetSelected(SelectionEvent e) {
    1018                new LibraryVersionDialog(shell, FileFormat.FILE_TYPE_HDF4).open();
    1019            }
    1020        });
    1021
    1022        if(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4) == null) {
    1023            hdf4Item.setEnabled(false);
    1024        }
    1025
    1026        new ToolItem(toolBar, SWT.SEPARATOR).setWidth(4);
    1027
    1028        ToolItem hdf5Item = new ToolItem(toolBar, SWT.PUSH);
    1029        hdf5Item.setImage(ViewProperties.getH5Icon());
    1030        hdf5Item.setToolTipText("HDF5 Library Version");
    1031        hdf5Item.addSelectionListener(new SelectionAdapter() {
    1032            @Override
    1033            public void widgetSelected(SelectionEvent e) {
    1034                new LibraryVersionDialog(shell, FileFormat.FILE_TYPE_HDF5).open();
    1035            }
    1036        });
    1037
    1038        if(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5) == null) {
    1039            hdf5Item.setEnabled(false);
    1040        }
    1041
    1042        // Make the toolbar as wide as the window and as
    1043        // tall as the buttons
    1044        toolBar.setSize(shell.getClientArea().width, openItem.getBounds().height);
    1045        toolBar.setLocation(0, 0);
    1046
    1047        log.info("Toolbar created");
    1048    }
    1049
    1050    private void createUrlToolbar(final Shell shell) {
    1051        // Recent Files button
    1052        recentFilesButton = new Button(shell, SWT.PUSH);
    1053        recentFilesButton.setFont(currentFont);
    1054        recentFilesButton.setText("Recent Files");
    1055        recentFilesButton.setToolTipText("List of recent files");
    1056        recentFilesButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
    1057        recentFilesButton.addSelectionListener(new SelectionAdapter() {
    1058            @Override
    1059            public void widgetSelected(SelectionEvent e) {
    1060                url_bar.setListVisible(true);
    1061            }
    1062        });
    1063
    1064        // Recent files combo box
    1065        url_bar = new Combo(shell, SWT.BORDER | SWT.SINGLE);
    1066        url_bar.setFont(currentFont);
    1067        url_bar.setItems(ViewProperties.getMRF().toArray(new String[0]));
    1068        url_bar.setVisibleItemCount(ViewProperties.MAX_RECENT_FILES);
    1069        url_bar.deselectAll();
    1070        url_bar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    1071        url_bar.addKeyListener(new KeyAdapter() {
    1072            @Override
    1073            public void keyPressed(KeyEvent e) {
    1074                if(e.keyCode == SWT.CR) {
    1075                    String filename = url_bar.getText();
    1076                    if (filename == null || filename.length() < 1 || filename.equals(currentFile)) {
    1077                        return;
    1078                    }
    1079
    1080                    if (!(filename.startsWith("http://") || filename.startsWith("https://") || filename.startsWith("ftp://"))) {
    1081                        openLocalFile(filename, -1);
    1082                    }
    1083                    else {
    1084                        String remoteFile = openRemoteFile(filename);
    1085
    1086                        if (remoteFile != null) openLocalFile(remoteFile, -1);
    1087                    }
    1088                }
    1089            }
    1090        });
    1091        url_bar.addSelectionListener(new SelectionAdapter() {
    1092            @Override
    1093            public void widgetSelected(SelectionEvent e) {
    1094                String filename = url_bar.getText();
    1095                if (filename == null || filename.length() < 1 || filename.equals(currentFile)) {
    1096                    return;
    1097                }
    1098
    1099                if (!(filename.startsWith("http://") || filename.startsWith("https://") || filename.startsWith("ftp://"))) {
    1100                    openLocalFile(filename, -1);
    1101                }
    1102                else {
    1103                    String remoteFile = openRemoteFile(filename);
    1104
    1105                    if (remoteFile != null) openLocalFile(remoteFile, -1);
    1106                }
    1107            }
    1108        });
    1109
    1110        clearTextButton = new Button(shell, SWT.PUSH);
    1111        clearTextButton.setToolTipText("Clear current selection");
    1112        clearTextButton.setFont(currentFont);
    1113        clearTextButton.setText("Clear Text");
    1114        clearTextButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
    1115        clearTextButton.addSelectionListener(new SelectionAdapter() {
    1116            @Override
    1117            public void widgetSelected(SelectionEvent e) {
    1118                url_bar.setText("");
    1119                url_bar.deselectAll();
    1120            }
    1121        });
    1122
    1123        log.info("URL Toolbar created");
    1124    }
    1125
    1126    private void createContentArea(final Shell shell) {
    1127        SashForm content = new SashForm(shell, SWT.VERTICAL);
    1128        content.setSashWidth(10);
    1129        content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
    1130
    1131        // Add Data content area and Status Area to main window
    1132        Composite container = new Composite(content, SWT.NONE);
    1133        container.setLayout(new FillLayout());
    1134
    1135        Composite statusArea = new Composite(content, SWT.NONE);
    1136        statusArea.setLayout(new FillLayout(SWT.HORIZONTAL));
    1137
    1138        final SashForm contentArea = new SashForm(container, SWT.HORIZONTAL);
    1139        contentArea.setSashWidth(10);
    1140
    1141        // Add TreeView and DataView to content area pane
    1142        ScrolledComposite treeArea = new ScrolledComposite(contentArea, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
    1143        treeArea.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
    1144        treeArea.setExpandHorizontal(true);
    1145        treeArea.setExpandVertical(true);
    1146
    1147        generalArea = new ScrolledComposite(contentArea, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
    1148        generalArea.setExpandHorizontal(true);
    1149        generalArea.setExpandVertical(true);
    1150        generalArea.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW));
    1151        generalArea.setMinHeight(contentArea.getSize().y - 2);
    1152
    1153        // Create status area for displaying messages and metadata
    1154        status = new Text(statusArea, SWT.V_SCROLL | SWT.MULTI | SWT.BORDER);
    1155        status.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW));
    1156        status.setEditable(false);
    1157        status.setFont(currentFont);
    1158
    1159        contentArea.addListener(SWT.Resize, new Listener() {
    1160            @Override
    1161            public void handleEvent(Event arg0) {
    1162                generalArea.setMinHeight(contentArea.getSize().y - 2);
    1163            }
    1164        });
    1165
    1166        // Add drag and drop support for opening files
    1167        DropTarget target = new DropTarget(treeArea, DND.DROP_COPY);
    1168        final FileTransfer fileTransfer = FileTransfer.getInstance();
    1169        target.setTransfer(new Transfer[] { fileTransfer });
    1170        target.addDropListener(new DropTargetListener() {
    1171            @Override
    1172            public void dragEnter(DropTargetEvent e) {
    1173                e.detail = DND.DROP_COPY;
    1174            }
    1175            @Override
    1176            public void dragOver(DropTargetEvent e) {}
    1177            @Override
    1178            public void dragOperationChanged(DropTargetEvent e) { }
    1179            @Override
    1180            public void dragLeave(DropTargetEvent e) {}
    1181            @Override
    1182            public void dropAccept(DropTargetEvent e) {}
    1183            @Override
    1184            public void drop(DropTargetEvent e) {
    1185                if (fileTransfer.isSupportedType(e.currentDataType)) {
    1186                    String[] files = (String[]) e.data;
    1187                    for (int i = 0; i < files.length; i++) {
    1188                        openLocalFile(files[i], -1);
    1189                    }
    1190                }
    1191            }
    1192        });
    1193
    1194        showStatus("HDFView root - " + rootDir);
    1195        showStatus("User property file - " + ViewProperties.getPropertyFile());
    1196
    1197        content.setWeights(new int[] { 9, 1 });
    1198        contentArea.setWeights(new int[] { 1, 3 });
    1199
    1200        log.trace("createContentArea(): load TreeView");
    1201
    1202        DataViewFactory treeViewFactory = DataViewFactoryProducer.getFactory(DataViewType.TREEVIEW);
    1203        if (treeViewFactory == null) {
    1204            log.debug("createContentArea(): TreeView Factory is null");
    1205            return;
    1206        }
    1207
    1208        try {
    1209            treeView = treeViewFactory.getTreeView(treeArea, this);
    1210
    1211            if (treeView == null) {
    1212                log.debug("createContentArea(): error occurred while instantiating TreeView class");
    1213                this.showStatus("Error occurred while instantiating TreeView class - see log for more info");
    1214                return;
    1215            }
    1216        }
    1217        catch (ClassNotFoundException ex) {
    1218            log.debug("createContentArea(): no suitable TreeView class found");
    1219            this.showStatus("Unable to find suitable TreeView class");
    1220            return;
    1221        }
    1222
    1223        treeArea.setContent(treeView.getTree());
    1224
    1225        log.info("Content Area created");
    1226    }
    1227
    1228    /**
    1229     * @return a list of treeview implementations.
    1230     */
    1231    public static final List<String> getListOfTreeViews() {
    1232        return treeViews;
    1233    }
    1234
    1235    /**
    1236     * @return a list of imageview implementations.
    1237     */
    1238    public static final List<String> getListOfImageViews() {
    1239        return imageViews;
    1240    }
    1241
    1242    /**
    1243     * @return a list of tableview implementations.
    1244     */
    1245    public static final List<?> getListOfTableViews() {
    1246        return tableViews;
    1247    }
    1248
    1249    /**
    1250     * @return a list of metaDataview implementations.
    1251     */
    1252    public static final List<?> getListOfMetaDataViews() {
    1253        return metaDataViews;
    1254    }
    1255
    1256    /**
    1257     * @return a list of paletteview implementations.
    1258     */
    1259    public static final List<?> getListOfPaletteViews() {
    1260        return paletteViews;
    1261    }
    1262
    1263    @Override
    1264    public TreeView getTreeView() {
    1265        return treeView;
    1266    }
    1267
    1268    public Combo getUrlBar() {
    1269        return url_bar;
    1270    }
    1271
    1272    /**
    1273     * Display feedback message.
    1274     *
    1275     * @param msg
    1276     *            the message to display.
    1277     */
    1278    @Override
    1279    public void showStatus(String msg) {
    1280        if (status == null) {
    1281            log.debug("showStatus(): status area is null");
    1282            return;
    1283        }
    1284
    1285        status.append(msg);
    1286        status.append("\n");
    1287    }
    1288
    1289    public void showMetaData(final HObject obj) {
    1290        for (Control control : generalArea.getChildren()) control.dispose();
    1291        generalArea.setContent(null);
    1292
    1293        if (obj == null) return;
    1294
    1295        log.trace("showMetaData(): start");
    1296
    1297        DataViewFactory metaDataViewFactory = DataViewFactoryProducer.getFactory(DataViewType.METADATA);
    1298        if (metaDataViewFactory == null) return;
    1299
    1300        MetaDataView theView;
    1301        try {
    1302            theView = metaDataViewFactory.getMetaDataView(generalArea, this, obj);
    1303
    1304            if (theView == null) {
    1305                log.debug("showMetaData(): error occurred while instantiating MetaDataView class");
    1306                this.showStatus("Error occurred while instantiating MetaDataView class - see log for more info");
    1307                return;
    1308            }
    1309        }
    1310        catch (ClassNotFoundException ex) {
    1311            log.debug("showMetaData(): no suitable MetaDataView class found");
    1312            this.showStatus("Unable to find suitable MetaDataView class");
    1313            return;
    1314        }
    1315
    1316        // String viewName = (String) HDFView.getListOfMetaDataViews().get(0);
    1317        //
    1318        // try {
    1319        // Class<?> theClass = Class.forName(viewName);
    1320        // if ("hdf.view.DefaultMetaDataView".equals(viewName)) {
    1321        // Object[] initargs = { generalArea, this, obj };
    1322        // Tools.newInstance(theClass, initargs);
    1323        // }
    1324        // else {
    1325        // Object[] initargs = { this, obj };
    1326        // Tools.newInstance(theClass, initargs);
    1327        // }
    1328        // }
    1329        // catch (Exception ex) {
    1330        // this.showStatus(ex.toString());
    1331        // }
    1332
    1333        log.trace("showMetaData(): finish");
    1334    }
    1335
    1336    public void closeFile(FileFormat theFile) {
    1337        if (theFile == null) {
    1338            display.beep();
    1339            Tools.showError(mainWindow, "Close", "Select a file to close");
    1340            return;
    1341        }
    1342
    1343        // Close all the data windows of this file
    1344        Shell[] views = display.getShells();
    1345        if (views != null) {
    1346            for (int i = 0; i < views.length; i++) {
    1347                Object shellData = views[i].getData();
    1348
    1349                if (!(shellData instanceof DataView)) continue;
    1350
    1351                if ((DataView) shellData != null) {
    1352                    HObject obj = ((DataView) shellData).getDataObject();
    1353
    1354                    if (obj == null || obj.getFileFormat() == null) continue;
    1355
    1356                    if (obj.getFileFormat().equals(theFile)) {
    1357                        views[i].dispose();
    1358                        views[i] = null;
    1359                    }
    1360                }
    1361            }
    1362        }
    1363
    1364        int index = url_bar.getSelectionIndex();
    1365        if (index >= 0) {
    1366            String fName = url_bar.getItem(url_bar.getSelectionIndex());
    1367            if (theFile.getFilePath().equals(fName)) {
    1368                currentFile = null;
    1369                url_bar.setText("");
    1370            }
    1371        }
    1372
    1373        try {
    1374            treeView.closeFile(theFile);
    1375        }
    1376        catch (Exception ex) {}
    1377
    1378        theFile = null;
    1379
    1380        for (Control control : generalArea.getChildren()) control.dispose();
    1381        generalArea.setContent(null);
    1382
    1383        System.gc();
    1384    }
    1385
    1386    /**
    1387     * Write the change of data to the given file.
    1388     *
    1389     * @param theFile
    1390     *           The file to be updated.
    1391     */
    1392    public void writeDataToFile(FileFormat theFile) {
    1393        try {
    1394            Shell[] openShells = display.getShells();
    1395
    1396            if (openShells != null) {
    1397                for (int i = 0; i < openShells.length; i++) {
    1398                    DataView theView = (DataView) openShells[i].getData();
    1399
    1400                    if (theView instanceof TableView) {
    1401                        TableView tableView = (TableView) theView;
    1402                        FileFormat file = tableView.getDataObject().getFileFormat();
    1403                        if (file.equals(theFile)) tableView.updateValueInFile();
    1404                    }
    1405                }
    1406            }
    1407        }
    1408        catch (Exception ex) {
    1409            display.beep();
    1410            Tools.showError(mainWindow, "Save", ex.getMessage());
    1411        }
    1412    }
    1413
    1414    @Override
    1415    public void addDataView(DataView dataView) {
    1416        if (dataView == null || dataView instanceof MetaDataView) {
    1417            return;
    1418        }
    1419
    1420        // Check if the data content is already displayed
    1421        Shell[] shellList = display.getShells();
    1422        if (shellList != null) {
    1423            for (int i = 0; i < shellList.length; i++) {
    1424                if (dataView.equals(shellList[i].getData())
    1425                        && shellList[i].isVisible()) {
    1426                    showWindow(shellList[i]);
    1427                    return;
    1428                }
    1429            }
    1430        }
    1431
    1432        // First window being added
    1433        if (shellList.length == 2) {
    1434            setEnabled(Arrays.asList(windowMenu.getItems()), true);
    1435        }
    1436
    1437        HObject obj = dataView.getDataObject();
    1438        String fullPath = ((obj.getPath() == null) ? "" : obj.getPath())
    1439                + ((obj.getName() == null) ? "" : obj.getName());
    1440
    1441        MenuItem item = new MenuItem(windowMenu, SWT.PUSH);
    1442        item.setText(fullPath);
    1443        item.addSelectionListener(new SelectionAdapter() {
    1444            @Override
    1445            public void widgetSelected(SelectionEvent e) {
    1446                Shell[] sList = display.getShells();
    1447
    1448                for (int i = 0; i < sList.length; i++) {
    1449                    DataView view = (DataView) sList[i].getData();
    1450
    1451                    if (view != null) {
    1452                        HObject obj = view.getDataObject();
    1453
    1454                        if (obj.getFullName().equals(((MenuItem) e.widget).getText())) {
    1455                            showWindow(sList[i]);
    1456                        }
    1457                    }
    1458                }
    1459            }
    1460        });
    1461
    1462        mainWindow.setCursor(null);
    1463    }
    1464
    1465    @Override
    1466    public void removeDataView(DataView dataView) {
    1467        if (mainWindow.isDisposed()) return;
    1468
    1469        HObject obj = dataView.getDataObject();
    1470        if (obj == null) return;
    1471
    1472        MenuItem[] items = windowMenu.getItems();
    1473        for (int i = 0; i < items.length; i++) {
    1474            if(items[i].getText().equals(obj.getFullName())) {
    1475                items[i].dispose();
    1476            }
    1477        }
    1478
    1479        // Last window being closed
    1480        if (display.getShells().length == 2) {
    1481            for (MenuItem item : windowMenu.getItems()) item.setEnabled(false);
    1482        }
    1483    }
    1484
    1485    @Override
    1486    public DataView getDataView(HObject dataObject) {
    1487        Shell[] openShells = display.getShells();
    1488        DataView view = null;
    1489        HObject currentObj = null;
    1490        FileFormat currentFile = null;
    1491
    1492        for (int i = 0; i < openShells.length; i++) {
    1493            view = (DataView) openShells[i].getData();
    1494
    1495            if (view != null) {
    1496                currentObj = view.getDataObject();
    1497                if (currentObj == null) continue;
    1498
    1499                currentFile = currentObj.getFileFormat();
    1500
    1501                if (currentObj.equals(dataObject) && currentFile.equals(dataObject.getFileFormat()))
    1502                    return view;
    1503            }
    1504        }
    1505
    1506        return null;
    1507    }
    1508
    1509    /**
    1510     * Set the testing state that determines if HDFView
    1511     * is being executed for GUI testing.
    1512     *
    1513     * @param testing
    1514     *           Provides SWTBot native dialog compatibility
    1515     *           workarounds if set to true.
    1516     */
    1517    public void setTestState(boolean testing) {
    1518        isTesting = testing;
    1519        currentDir = rootDir;
    1520    }
    1521
    1522    public boolean getTestState() {
    1523        return isTesting;
    1524    }
    1525
    1526    /**
    1527     * Set default UI fonts.
    1528     */
    1529    private void updateFont(Font font) {
    1530        if (currentFont != null) currentFont.dispose();
    1531
    1532        currentFont = font;
    1533
    1534        mainWindow.setFont(font);
    1535        recentFilesButton.setFont(font);
    1536        url_bar.setFont(font);
    1537        clearTextButton.setFont(font);
    1538        status.setFont(font);
    1539
    1540        // On certain platforms the url_bar items don't update their size after
    1541        // a font change. Removing and replacing them fixes this.
    1542        for (String item : url_bar.getItems()) {
    1543            url_bar.remove(item);
    1544            url_bar.add(item);
    1545        }
    1546
    1547        if (treeView.getSelectedFile() != null) {
    1548            url_bar.select(0);
    1549        }
    1550
    1551        ((DefaultTreeView) treeView).updateFont(font);
    1552
    1553        mainWindow.layout();
    1554    }
    1555
    1556    /**
    1557     * Bring window to the front.
    1558     * <p>
    1559     *
    1560     * @param name
    1561     *               the name of the window to show.
    1562     */
    1563    private void showWindow(final Shell shell) {
    1564        shell.getDisplay().asyncExec(new Runnable() {
    1565            @Override
    1566            public void run() {
    1567                shell.forceActive();
    1568            }
    1569        });
    1570    }
    1571
    1572    /**
    1573     * Cascade all windows.
    1574     */
    1575    private void cascadeWindows() {
    1576        Shell[] sList = display.getShells();
    1577
    1578        // Return if main window (shell) is the only open shell
    1579        if (sList.length <= 1) return;
    1580
    1581        int x = 2, y = 2;
    1582        Shell shell = null;
    1583
    1584        Rectangle bounds = Display.getCurrent().getPrimaryMonitor().getClientArea();
    1585        int w = Math.max(50, bounds.width - 100);
    1586        int h = Math.max(50, bounds.height - 100);
    1587
    1588        x = bounds.x;
    1589        y = bounds.y;
    1590
    1591        for (int i = 0; i < sList.length; i++) {
    1592            shell = sList[i];
    1593            shell.setBounds(x, y, w, h);
    1594            shell.setActive();
    1595            x += 20;
    1596            y += 20;
    1597        }
    1598    }
    1599
    1600    /**
    1601     * Tile all windows.
    1602     */
    1603    private void tileWindows() {
    1604        Shell[] sList = display.getShells();
    1605
    1606        // Return if main window (shell) is the only open shell
    1607        if (sList.length <= 1) return;
    1608
    1609        int x = 0, y = 0, idx = 0;
    1610        Shell shell = null;
    1611
    1612        int n = sList.length;
    1613        int cols = (int) Math.sqrt(n);
    1614        int rows = (int) Math.ceil((double) n / (double) cols);
    1615
    1616        Rectangle bounds = Display.getCurrent().getPrimaryMonitor().getClientArea();
    1617        int w = bounds.width / cols;
    1618        int h = bounds.height / rows;
    1619
    1620        y = bounds.y;
    1621        for (int i = 0; i < rows; i++) {
    1622            x = bounds.x;
    1623
    1624            for (int j = 0; j < cols; j++) {
    1625                idx = i * cols + j;
    1626                if (idx >= n)
    1627                    return;
    1628
    1629                shell = sList[idx];
    1630                shell.setBounds(x, y, w, h);
    1631                shell.setActive();
    1632                x += w;
    1633            }
    1634
    1635            y += h;
    1636        }
    1637    }
    1638
    1639    /**
    1640     * Closes all windows.
    1641     */
    1642    private void closeAllWindows() {
    1643        Shell[] sList = display.getShells();
    1644
    1645        for (int i = 0; i < sList.length; i++) {
    1646            if (sList[i].equals(mainWindow)) continue;
    1647            sList[i].dispose();
    1648        }
    1649    }
    1650
    1651    /* Enable and disable GUI components */
    1652    private static void setEnabled(List<MenuItem> list, boolean b) {
    1653        Iterator<MenuItem> it = list.iterator();
    1654
    1655        while (it.hasNext())
    1656            it.next().setEnabled(b);
    1657    }
    1658
    1659    /** Open local file */
    1660    private void openLocalFile(String filename, int fileAccessID) {
    1661        log.trace("openLocalFile {},{}",filename, fileAccessID);
    1662
    1663        /*
    1664         * If given a specific access mode, use it without changing it. If not given a
    1665         * specific access mode, check the current status of the "is read only" property
    1666         * to determine how to open the file. This is to allow one time overrides of the
    1667         * default file access mode when opening a file.
    1668         */
    1669        int accessMode = fileAccessID;
    1670        if (accessMode < 0) {
    1671            if (ViewProperties.isReadOnly())
    1672                accessMode = FileFormat.READ;
    1673            else
    1674                accessMode = FileFormat.WRITE;
    1675        }
    1676
    1677        String[] selectedFilenames = null;
    1678        File[] chosenFiles = null;
    1679
    1680        if (filename != null) {
    1681            File file = new File(filename);
    1682            if(!file.exists()) {
    1683                Tools.showError(mainWindow, "Open", "File " + filename + " does not exist.");
    1684                return;
    1685            }
    1686
    1687            if(file.isDirectory()) {
    1688                currentDir = filename;
    1689                openLocalFile(null, -1);
    1690            }
    1691            else {
    1692                currentFile = filename;
    1693            }
    1694
    1695            try {
    1696                url_bar.remove(filename);
    1697            }
    1698            catch (Exception ex) {}
    1699
    1700            url_bar.add(filename, 0);
    1701            url_bar.select(0);
    1702
    1703            try {
    1704                treeView.openFile(filename, accessMode);
    1705            }
    1706            catch (Throwable ex) {
    1707                try {
    1708                    treeView.openFile(filename, FileFormat.READ);
    1709                }
    1710                catch (Throwable ex2) {
    1711                    display.beep();
    1712                    url_bar.deselectAll();
    1713                    Tools.showError(mainWindow, "Open", "Failed to open file " + filename + "\n" + ex2);
    1714                    currentFile = null;
    1715                }
    1716            }
    1717        }
    1718        else {
    1719            if (!isTesting) {
    1720                log.trace("openLocalFile filename is null");
    1721                FileDialog fChooser = new FileDialog(mainWindow, SWT.OPEN | SWT.MULTI);
    1722                fChooser.setText(mainWindow.getText() + " - Open File " + ((accessMode == FileFormat.READ) ? "Read-only" : "Read/Write"));
    1723                fChooser.setFilterPath(currentDir);
    1724
    1725                DefaultFileFilter filter = DefaultFileFilter.getFileFilter();
    1726                fChooser.setFilterExtensions(new String[] {"*.*", filter.getExtensions()});
    1727                fChooser.setFilterNames(new String[] {"All Files", filter.getDescription()});
    1728                fChooser.setFilterIndex(1);
    1729
    1730                fChooser.open();
    1731
    1732                selectedFilenames = fChooser.getFileNames();
    1733                if(selectedFilenames.length <= 0) return;
    1734
    1735                chosenFiles = new File[selectedFilenames.length];
    1736                for(int i = 0; i < chosenFiles.length; i++) {
    1737                    log.trace("openLocalFile selectedFilenames[{}]: {}",i,selectedFilenames[i]);
    1738                    chosenFiles[i] = new File(fChooser.getFilterPath() + File.separator + selectedFilenames[i]);
    1739
    1740                    if(!chosenFiles[i].exists()) {
    1741                        Tools.showError(mainWindow, "Open", "File " + chosenFiles[i].getName() + " does not exist.");
    1742                        continue;
    1743                    }
    1744
    1745                    if (chosenFiles[i].isDirectory()) {
    1746                        currentDir = chosenFiles[i].getPath();
    1747                    }
    1748                    else {
    1749                        currentDir = chosenFiles[i].getParent();
    1750                    }
    1751
    1752                    try {
    1753                        url_bar.remove(chosenFiles[i].getAbsolutePath());
    1754                    }
    1755                    catch (Exception ex) {}
    1756
    1757                    url_bar.add(chosenFiles[i].getAbsolutePath(), 0);
    1758                    url_bar.select(0);
    1759
    1760                    log.trace("openLocalFile treeView.openFile(chosenFiles[{}]: {}",i,chosenFiles[i].getAbsolutePath());
    1761                    try {
    1762                        treeView.openFile(chosenFiles[i].getAbsolutePath(), accessMode + FileFormat.OPEN_NEW);
    1763                    }
    1764                    catch (Throwable ex) {
    1765                        try {
    1766                            treeView.openFile(chosenFiles[i].getAbsolutePath(), FileFormat.READ);
    1767                        }
    1768                        catch (Throwable ex2) {
    1769                            display.beep();
    1770                            url_bar.deselectAll();
    1771                            Tools.showError(mainWindow, "Open", "Failed to open file " + selectedFilenames[i] + "\n" + ex2);
    1772                            currentFile = null;
    1773                        }
    1774                    }
    1775                }
    1776
    1777                currentFile = chosenFiles[0].getAbsolutePath();
    1778            }
    1779            else {
    1780                // Prepend test file directory to filename
    1781                String fName = currentDir + File.separator + new InputDialog(mainWindow, "Enter a file name", "").open();
    1782
    1783                File chosenFile = new File(fName);
    1784
    1785                if(!chosenFile.exists()) {
    1786                    Tools.showError(mainWindow, "Open", "File " + chosenFile.getName() + " does not exist.");
    1787                    return;
    1788                }
    1789
    1790                if (chosenFile.isDirectory()) {
    1791                    currentDir = chosenFile.getPath();
    1792                }
    1793                else {
    1794                    currentDir = chosenFile.getParent();
    1795                }
    1796
    1797                try {
    1798                    url_bar.remove(chosenFile.getAbsolutePath());
    1799                }
    1800                catch (Exception ex) {}
    1801
    1802                url_bar.add(chosenFile.getAbsolutePath(), 0);
    1803                url_bar.select(0);
    1804
    1805                log.trace("openLocalFile treeView.openFile(chosenFile[{}]: {}",chosenFile.getAbsolutePath());
    1806                try {
    1807                    treeView.openFile(chosenFile.getAbsolutePath(), accessMode + FileFormat.OPEN_NEW);
    1808                }
    1809                catch (Throwable ex) {
    1810                    try {
    1811                        treeView.openFile(chosenFile.getAbsolutePath(), FileFormat.READ);
    1812                    }
    1813                    catch (Throwable ex2) {
    1814                        display.beep();
    1815                        url_bar.deselectAll();
    1816                        Tools.showError(mainWindow, "Open", "Failed to open file " + chosenFile + "\n" + ex2);
    1817                        currentFile = null;
    1818                    }
    1819                }
    1820
    1821                currentFile = chosenFile.getAbsolutePath();
    1822            }
    1823        }
    1824    }
    1825
    1826    /** Load remote file and save it to local temporary directory */
    1827    private String openRemoteFile(String urlStr) {
    1828        if (urlStr == null)
    1829            return null;
    1830
    1831        String localFile = null;
    1832
    1833        if(urlStr.startsWith("http://")) {
    1834            localFile = urlStr.substring(7);
    1835        }
    1836        else if (urlStr.startsWith("https://")) {
    1837            localFile = urlStr.substring(8);
    1838        }
    1839        else if (urlStr.startsWith("ftp://")) {
    1840            localFile = urlStr.substring(6);
    1841        }
    1842        else {
    1843            return null;
    1844        }
    1845
    1846        localFile = localFile.replace('/', '@');
    1847        localFile = localFile.replace('\\', '@');
    1848
    1849        // Search the local file cache
    1850        String tmpDir = System.getProperty("java.io.tmpdir");
    1851
    1852        File tmpFile = new File(tmpDir);
    1853        if (!tmpFile.canWrite()) tmpDir = System.getProperty("user.home");
    1854
    1855        localFile = tmpDir + File.separator + localFile;
    1856
    1857        tmpFile = new File(localFile);
    1858        if (tmpFile.exists())
    1859            return localFile;
    1860
    1861        URL url = null;
    1862
    1863        try {
    1864            url = new URL(urlStr);
    1865        }
    1866        catch (Exception ex) {
    1867            url = null;
    1868            display.beep();
    1869            Tools.showError(mainWindow, "Open", ex.getMessage());
    1870            return null;
    1871        }
    1872
    1873        BufferedInputStream in = null;
    1874        BufferedOutputStream out = null;
    1875
    1876        try {
    1877            in = new BufferedInputStream(url.openStream());
    1878            out = new BufferedOutputStream(new FileOutputStream(tmpFile));
    1879        }
    1880        catch (Exception ex) {
    1881            in = null;
    1882            display.beep();
    1883            Tools.showError(mainWindow, "Open", ex.getMessage());
    1884
    1885            try {
    1886                out.close();
    1887            }
    1888            catch (Exception ex2) {
    1889                log.debug("Remote file: ", ex2);
    1890            }
    1891
    1892            return null;
    1893        }
    1894
    1895        mainWindow.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT));
    1896        byte[] buff = new byte[512]; // set default buffer size to 512
    1897        try {
    1898            int n = 0;
    1899            while ((n = in.read(buff)) > 0) {
    1900                out.write(buff, 0, n);
    1901            }
    1902        }
    1903        catch (Exception ex) {
    1904            log.debug("Remote file: ", ex);
    1905        }
    1906
    1907        try {
    1908            in.close();
    1909        }
    1910        catch (Exception ex) {
    1911            log.debug("Remote file: ", ex);
    1912        }
    1913
    1914        try {
    1915            out.close();
    1916        }
    1917        catch (Exception ex) {
    1918            log.debug("Remote file: ", ex);
    1919        }
    1920
    1921        mainWindow.setCursor(null);
    1922
    1923        return localFile;
    1924    }
    1925
    1926    private void convertFile(String typeFrom, String typeTo) {
    1927        ImageConversionDialog dialog = new ImageConversionDialog(mainWindow, typeFrom, typeTo,
    1928                currentDir, treeView.getCurrentFiles());
    1929        dialog.open();
    1930
    1931        if (dialog.isFileConverted()) {
    1932            String filename = dialog.getConvertedFile();
    1933            File theFile = new File(filename);
    1934
    1935            if (!theFile.exists()) return;
    1936
    1937            currentDir = theFile.getParentFile().getAbsolutePath();
    1938            currentFile = theFile.getAbsolutePath();
    1939
    1940            try {
    1941                treeView.openFile(filename, FileFormat.WRITE);
    1942
    1943                try {
    1944                    url_bar.remove(filename);
    1945                }
    1946                catch (Exception ex) {}
    1947
    1948                url_bar.add(filename, 0);
    1949                url_bar.select(0);
    1950            }
    1951            catch (Exception ex) {
    1952                showStatus(ex.toString());
    1953            }
    1954        }
    1955    }
    1956
    1957    private void registerFileFormat() {
    1958        String msg = "Register a new file format by \nKEY:FILE_FORMAT:FILE_EXTENSION\n"
    1959                + "where, KEY: the unique identifier for the file format"
    1960                + "\n           FILE_FORMAT: the full class name of the file format"
    1961                + "\n           FILE_EXTENSION: the file extension for the file format" + "\n\nFor example, "
    1962                + "\n\t to add NetCDF, \"NetCDF:hdf.object.nc2.NC2File:nc\""
    1963                + "\n\t to add FITS, \"FITS:hdf.object.fits.FitsFile:fits\"\n\n";
    1964
    1965        // TODO:Add custom HDFLarge icon to dialog
    1966        InputDialog dialog = new InputDialog(mainWindow, "Register a file format", msg, SWT.ICON_INFORMATION);
    1967
    1968        String str = dialog.open();
    1969
    1970        if ((str == null) || (str.length() < 1)) return;
    1971
    1972        int idx1 = str.indexOf(':');
    1973        int idx2 = str.lastIndexOf(':');
    1974
    1975        if ((idx1 < 0) || (idx2 <= idx1)) {
    1976            Tools.showError(mainWindow, "Register File Format", "Failed to register " + str
    1977                    + "\n\nMust in the form of KEY:FILE_FORMAT:FILE_EXTENSION");
    1978            return;
    1979        }
    1980
    1981        String key = str.substring(0, idx1);
    1982        String className = str.substring(idx1 + 1, idx2);
    1983        String extension = str.substring(idx2 + 1);
    1984
    1985        // Check if the file format has been registered or the key is taken.
    1986        String theKey = null;
    1987        String theClassName = null;
    1988        Enumeration<?> local_enum = FileFormat.getFileFormatKeys();
    1989        while (local_enum.hasMoreElements()) {
    1990            theKey = (String) local_enum.nextElement();
    1991            if (theKey.endsWith(key)) {
    1992                Tools.showError(mainWindow, "Register File Format", "Invalid key: " + key + " is taken.");
    1993                return;
    1994            }
    1995
    1996            theClassName = FileFormat.getFileFormat(theKey).getClass().getName();
    1997            if (theClassName.endsWith(className)) {
    1998                Tools.showError(mainWindow, "Register File Format", "The file format has already been registered: " + className);
    1999                return;
    2000            }
    2001        }
    2002
    2003        // Enables use of JHDF5 in JNLP (Web Start) applications, the system
    2004        // class loader with reflection first.
    2005        Class<?> theClass = null;
    2006        try {
    2007            theClass = Class.forName(className);
    2008        }
    2009        catch (Exception ex) {
    2010            try {
    2011                theClass = ViewProperties.loadExtClass().loadClass(className);
    2012            }
    2013            catch (Exception ex2) {
    2014                theClass = null;
    2015            }
    2016        }
    2017
    2018        if (theClass == null) {
    2019            return;
    2020        }
    2021
    2022        try {
    2023            Object theObject = theClass.newInstance();
    2024            if (theObject instanceof FileFormat) {
    2025                FileFormat.addFileFormat(key, (FileFormat) theObject);
    2026            }
    2027        }
    2028        catch (Throwable ex) {
    2029            Tools.showError(mainWindow, "Register File Format", "Failed to register " + str + "\n\n" + ex);
    2030            return;
    2031        }
    2032
    2033        if ((extension != null) && (extension.length() > 0)) {
    2034            extension = extension.trim();
    2035            String ext = ViewProperties.getFileExtension();
    2036            ext += ", " + extension;
    2037            ViewProperties.setFileExtension(ext);
    2038        }
    2039    }
    2040
    2041    private void unregisterFileFormat() {
    2042        Enumeration<?> keys = FileFormat.getFileFormatKeys();
    2043        ArrayList<Object> keyList = new ArrayList<>();
    2044
    2045        while (keys.hasMoreElements())
    2046            keyList.add(keys.nextElement());
    2047
    2048        String theKey = new UnregisterFileFormatDialog(mainWindow, SWT.NONE, keyList).open();
    2049
    2050        if (theKey == null) return;
    2051
    2052        FileFormat.removeFileFormat(theKey);
    2053    }
    2054
    2055    private class LibraryVersionDialog extends Dialog {
    2056        private String message;
    2057
    2058        public LibraryVersionDialog(Shell parent, String libType) {
    2059            super(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
    2060
    2061            if(libType == FileFormat.FILE_TYPE_HDF4)
    2062                setMessage("HDF " + HDF4_VERSION);
    2063            else if (libType == FileFormat.FILE_TYPE_HDF5)
    2064                setMessage("HDF5 " + HDF5_VERSION);
    2065        }
    2066
    2067        public void setMessage(String message) {
    2068            this.message = message;
    2069        }
    2070
    2071        public void open() {
    2072            Shell dialog = new Shell(getParent(), getStyle());
    2073            dialog.setFont(currentFont);
    2074            dialog.setText("HDF Library Version");
    2075
    2076            createContents(dialog);
    2077
    2078            dialog.pack();
    2079
    2080            Point computedSize = dialog.computeSize(SWT.DEFAULT, SWT.DEFAULT);
    2081            dialog.setSize(computedSize.x + 50, computedSize.y + 50);
    2082
    2083            // Center the window relative to the main HDFView window
    2084            Point winCenter = new Point(
    2085                    mainWindow.getBounds().x + (mainWindow.getBounds().width / 2),
    2086                    mainWindow.getBounds().y + (mainWindow.getBounds().height / 2));
    2087
    2088            dialog.setLocation(winCenter.x - (dialog.getSize().x / 2), winCenter.y - (dialog.getSize().y / 2));
    2089
    2090            dialog.open();
    2091
    2092            Display display = getParent().getDisplay();
    2093            while (!dialog.isDisposed()) {
    2094                if (!display.readAndDispatch()) {
    2095                    display.sleep();
    2096                }
    2097            }
    2098        }
    2099
    2100        private void createContents(final Shell shell) {
    2101            shell.setLayout(new GridLayout(2, false));
    2102
    2103            Image HDFImage = ViewProperties.getLargeHdfIcon();
    2104
    2105            Label imageLabel = new Label(shell, SWT.CENTER);
    2106            imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    2107            imageLabel.setImage(HDFImage);
    2108
    2109            Label versionLabel = new Label(shell, SWT.CENTER);
    2110            versionLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
    2111            versionLabel.setFont(currentFont);
    2112            versionLabel.setText(message);
    2113
    2114            // Draw HDF Icon and Version string
    2115            Composite buttonComposite = new Composite(shell, SWT.NONE);
    2116            buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
    2117            RowLayout buttonLayout = new RowLayout();
    2118            buttonLayout.center = true;
    2119            buttonLayout.justify = true;
    2120            buttonLayout.type = SWT.HORIZONTAL;
    2121            buttonComposite.setLayout(buttonLayout);
    2122
    2123            Button okButton = new Button(buttonComposite, SWT.PUSH);
    2124            okButton.setFont(currentFont);
    2125            okButton.setText("   &OK   ");
    2126            shell.setDefaultButton(okButton);
    2127            okButton.addSelectionListener(new SelectionAdapter() {
    2128                @Override
    2129                public void widgetSelected(SelectionEvent e) {
    2130                    shell.dispose();
    2131                }
    2132            });
    2133        }
    2134    }
    2135
    2136    private class JavaVersionDialog extends Dialog {
    2137        public JavaVersionDialog(Shell parent) {
    2138            super(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
    2139        }
    2140
    2141        public void open() {
    2142            final Shell dialog = new Shell(getParent(), getStyle());
    2143            dialog.setFont(currentFont);
    2144            dialog.setText("HDFView Java Version");
    2145            dialog.setLayout(new GridLayout(2, false));
    2146
    2147            Image HDFImage = ViewProperties.getLargeHdfIcon();
    2148
    2149            Label imageLabel = new Label(dialog, SWT.CENTER);
    2150            imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    2151            imageLabel.setImage(HDFImage);
    2152
    2153            Label versionLabel = new Label(dialog, SWT.CENTER);
    2154            versionLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
    2155            versionLabel.setFont(currentFont);
    2156            versionLabel.setText(JAVA_VER_INFO);
    2157
    2158            Composite buttonComposite = new Composite(dialog, SWT.NONE);
    2159            buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
    2160            RowLayout buttonLayout = new RowLayout();
    2161            buttonLayout.center = true;
    2162            buttonLayout.justify = true;
    2163            buttonLayout.type = SWT.HORIZONTAL;
    2164            buttonComposite.setLayout(buttonLayout);
    2165
    2166            Button okButton = new Button(buttonComposite, SWT.PUSH);
    2167            okButton.setFont(currentFont);
    2168            okButton.setText("   &OK   ");
    2169            dialog.setDefaultButton(okButton);
    2170            okButton.addSelectionListener(new SelectionAdapter() {
    2171                @Override
    2172                public void widgetSelected(SelectionEvent e) {
    2173                    dialog.dispose();
    2174                }
    2175            });
    2176
    2177            dialog.pack();
    2178
    2179            Point computedSize = dialog.computeSize(SWT.DEFAULT, SWT.DEFAULT);
    2180            dialog.setSize(computedSize.x + 50, computedSize.y + 50);
    2181
    2182            // Center the window relative to the main HDFView window
    2183            Point winCenter = new Point(
    2184                    mainWindow.getBounds().x + (mainWindow.getBounds().width / 2),
    2185                    mainWindow.getBounds().y + (mainWindow.getBounds().height / 2));
    2186
    2187            dialog.setLocation(winCenter.x - (dialog.getSize().x / 2), winCenter.y - (dialog.getSize().y / 2));
    2188
    2189            dialog.open();
    2190
    2191            Display display = getParent().getDisplay();
    2192            while (!dialog.isDisposed()) {
    2193                if (!display.readAndDispatch()) {
    2194                    display.sleep();
    2195                }
    2196            }
    2197        }
    2198    }
    2199
    2200    private class SupportedFileFormatsDialog extends Dialog {
    2201        public SupportedFileFormatsDialog(Shell parent) {
    2202            super(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
    2203        }
    2204
    2205        public void open() {
    2206            final Shell dialog = new Shell(getParent(), getStyle());
    2207            dialog.setFont(currentFont);
    2208            dialog.setText("Supported File Formats");
    2209            dialog.setLayout(new GridLayout(2, false));
    2210
    2211            Enumeration<?> formatKeys = FileFormat.getFileFormatKeys();
    2212
    2213            String formats = "\nSupported File Formats: \n";
    2214            while (formatKeys.hasMoreElements()) {
    2215                formats += "    " + formatKeys.nextElement() + "\n";
    2216            }
    2217            formats += "\n";
    2218
    2219            Image HDFImage = ViewProperties.getLargeHdfIcon();
    2220
    2221            Label imageLabel = new Label(dialog, SWT.CENTER);
    2222            imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    2223            imageLabel.setImage(HDFImage);
    2224
    2225            Label formatsLabel = new Label(dialog, SWT.LEFT);
    2226            formatsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
    2227            formatsLabel.setFont(currentFont);
    2228            formatsLabel.setText(formats);
    2229
    2230            Composite buttonComposite = new Composite(dialog, SWT.NONE);
    2231            buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
    2232            RowLayout buttonLayout = new RowLayout();
    2233            buttonLayout.center = true;
    2234            buttonLayout.justify = true;
    2235            buttonLayout.type = SWT.HORIZONTAL;
    2236            buttonComposite.setLayout(buttonLayout);
    2237
    2238            Button okButton = new Button(buttonComposite, SWT.PUSH);
    2239            okButton.setFont(currentFont);
    2240            okButton.setText("   &OK   ");
    2241            dialog.setDefaultButton(okButton);
    2242            okButton.addSelectionListener(new SelectionAdapter() {
    2243                @Override
    2244                public void widgetSelected(SelectionEvent e) {
    2245                    dialog.dispose();
    2246                }
    2247            });
    2248
    2249            dialog.pack();
    2250
    2251            Point computedSize = dialog.computeSize(SWT.DEFAULT, SWT.DEFAULT);
    2252            dialog.setSize(computedSize.x + 50, computedSize.y + 50);
    2253
    2254            // Center the window relative to the main HDFView window
    2255            Point winCenter = new Point(
    2256                    mainWindow.getBounds().x + (mainWindow.getBounds().width / 2),
    2257                    mainWindow.getBounds().y + (mainWindow.getBounds().height / 2));
    2258
    2259            dialog.setLocation(winCenter.x - (dialog.getSize().x / 2), winCenter.y - (dialog.getSize().y / 2));
    2260
    2261            dialog.open();
    2262
    2263            Display display = getParent().getDisplay();
    2264            while (!dialog.isDisposed()) {
    2265                if (!display.readAndDispatch()) {
    2266                    display.sleep();
    2267                }
    2268            }
    2269        }
    2270    }
    2271
    2272    private class AboutDialog extends Dialog {
    2273        public AboutDialog(Shell parent) {
    2274            super(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
    2275        }
    2276
    2277        public void open() {
    2278            final Shell dialog = new Shell(getParent(), getStyle());
    2279            dialog.setFont(currentFont);
    2280            dialog.setText("About HDFView");
    2281            dialog.setLayout(new GridLayout(2, false));
    2282
    2283            Image HDFImage = ViewProperties.getLargeHdfIcon();
    2284
    2285            Label imageLabel = new Label(dialog, SWT.CENTER);
    2286            imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    2287            imageLabel.setImage(HDFImage);
    2288
    2289            Label aboutLabel = new Label(dialog, SWT.LEFT);
    2290            aboutLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
    2291            aboutLabel.setFont(currentFont);
    2292            aboutLabel.setText(aboutHDFView);
    2293
    2294            Composite buttonComposite = new Composite(dialog, SWT.NONE);
    2295            buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
    2296            RowLayout buttonLayout = new RowLayout();
    2297            buttonLayout.center = true;
    2298            buttonLayout.justify = true;
    2299            buttonLayout.type = SWT.HORIZONTAL;
    2300            buttonComposite.setLayout(buttonLayout);
    2301
    2302            Button okButton = new Button(buttonComposite, SWT.PUSH);
    2303            okButton.setFont(currentFont);
    2304            okButton.setText("   &OK   ");
    2305            dialog.setDefaultButton(okButton);
    2306            okButton.addSelectionListener(new SelectionAdapter() {
    2307                @Override
    2308                public void widgetSelected(SelectionEvent e) {
    2309                    dialog.dispose();
    2310                }
    2311            });
    2312
    2313            dialog.pack();
    2314
    2315            Point computedSize = dialog.computeSize(SWT.DEFAULT, SWT.DEFAULT);
    2316            dialog.setSize(computedSize.x + 50, computedSize.y + 50);
    2317
    2318            // Center the window relative to the main HDFView window
    2319            Point winCenter = new Point(
    2320                    mainWindow.getBounds().x + (mainWindow.getBounds().width / 2),
    2321                    mainWindow.getBounds().y + (mainWindow.getBounds().height / 2));
    2322
    2323            dialog.setLocation(winCenter.x - (dialog.getSize().x / 2), winCenter.y - (dialog.getSize().y / 2));
    2324
    2325            dialog.open();
    2326
    2327            Display display = getParent().getDisplay();
    2328            while (!dialog.isDisposed()) {
    2329                if (!display.readAndDispatch()) {
    2330                    display.sleep();
    2331                }
    2332            }
    2333        }
    2334    }
    2335
    2336    private class UnregisterFileFormatDialog extends Dialog {
    2337
    2338        private List<Object> keyList;
    2339        private String formatChoice = null;
    2340
    2341        public UnregisterFileFormatDialog(Shell parent, int style, List<Object> keyList) {
    2342            super(parent, style);
    2343
    2344            this.keyList = keyList;
    2345        }
    2346
    2347        public String open() {
    2348            Shell parent = getParent();
    2349            final Shell shell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
    2350            shell.setFont(currentFont);
    2351            shell.setText("Unregister a file format");
    2352            shell.setLayout(new GridLayout(2, false));
    2353
    2354            Image HDFImage = ViewProperties.getLargeHdfIcon();
    2355
    2356            Label imageLabel = new Label(shell, SWT.CENTER);
    2357            imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    2358            imageLabel.setImage(HDFImage);
    2359
    2360
    2361            final Combo formatChoiceCombo = new Combo(shell, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY);
    2362            formatChoiceCombo.setFont(currentFont);
    2363            formatChoiceCombo.setItems(keyList.toArray(new String[0]));
    2364            formatChoiceCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
    2365            formatChoiceCombo.select(0);
    2366            formatChoiceCombo.addSelectionListener(new SelectionAdapter() {
    2367                @Override
    2368                public void widgetSelected(SelectionEvent e) {
    2369                    formatChoice = formatChoiceCombo.getItem(formatChoiceCombo.getSelectionIndex());
    2370                }
    2371            });
    2372
    2373            Composite buttonComposite = new Composite(shell, SWT.NONE);
    2374            buttonComposite.setLayout(new GridLayout(2, true));
    2375            buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
    2376
    2377            Button okButton = new Button(buttonComposite, SWT.PUSH);
    2378            okButton.setFont(currentFont);
    2379            okButton.setText("   &OK   ");
    2380            okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
    2381            okButton.addSelectionListener(new SelectionAdapter() {
    2382                @Override
    2383                public void widgetSelected(SelectionEvent e) {
    2384                    shell.dispose();
    2385                }
    2386            });
    2387
    2388            Button cancelButton = new Button(buttonComposite, SWT.PUSH);
    2389            cancelButton.setFont(currentFont);
    2390            cancelButton.setText(" &Cancel ");
    2391            cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false));
    2392            cancelButton.addSelectionListener(new SelectionAdapter() {
    2393                @Override
    2394                public void widgetSelected(SelectionEvent e) {
    2395                    shell.dispose();
    2396                }
    2397            });
    2398
    2399            shell.pack();
    2400
    2401            Point computedSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
    2402            shell.setSize(computedSize.x + 50, computedSize.y + 50);
    2403
    2404            Rectangle parentBounds = parent.getBounds();
    2405            Point shellSize = shell.getSize();
    2406            shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
    2407                    (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
    2408
    2409            shell.open();
    2410
    2411            Display display = parent.getDisplay();
    2412            while(!shell.isDisposed()) {
    2413                if (!display.readAndDispatch())
    2414                    display.sleep();
    2415            }
    2416
    2417            return formatChoice;
    2418        }
    2419    }
    2420
    2421    /**
    2422     * The starting point of this application.
    2423     *
    2424     * <pre>
    2425     * Usage: java(w)
    2426     *        -Dhdf.hdf5lib.H5.hdf5lib="your HDF5 library path"
    2427     *        -Dhdf.hdflib.HDFLibrary.hdflib="your HDF4 library path"
    2428     *        -root "the directory where the HDFView is installed"
    2429     *        [filename] "the file to open"
    2430     * </pre>
    2431     *
    2432     * @param args  the command line arguments
    2433     */
    2434    public static void main(String[] args) {
    2435        if (display == null || display.isDisposed()) display = new Display();
    2436
    2437        String rootDir = System.getProperty("hdfview.workdir");
    2438        log.trace("main: rootDir = {} ", rootDir);
    2439        if(rootDir == null)
    2440            rootDir = System.getProperty("user.dir");
    2441
    2442        File tmpFile = null;
    2443        Monitor primaryMonitor = display.getPrimaryMonitor();
    2444        Point margin = new Point(primaryMonitor.getBounds().width,
    2445                primaryMonitor.getBounds().height);
    2446
    2447        int j = args.length;
    2448        int W = margin.x / 2;
    2449        int H = margin.y;
    2450        int X = 0;
    2451        int Y = 0;
    2452
    2453        for(int i = 0; i < args.length; i++) {
    2454            if ("-root".equalsIgnoreCase(args[i])) {
    2455                j--;
    2456                try {
    2457                    j--;
    2458                    tmpFile = new File(args[++i]);
    2459
    2460                    if(tmpFile.isDirectory())
    2461                        rootDir = tmpFile.getPath();
    2462                    else if(tmpFile.isFile())
    2463                        rootDir = tmpFile.getParent();
    2464                }
    2465                catch (Exception ex) {}
    2466            }
    2467            else if("-g".equalsIgnoreCase(args[i]) || "-geometry".equalsIgnoreCase(args[i])) {
    2468                j--;
    2469                // -geometry WIDTHxHEIGHT+XOFF+YOFF
    2470                try {
    2471                    String geom = args[++i];
    2472                    j--;
    2473
    2474                    int idx = 0;
    2475                    int idx2 = geom.lastIndexOf('-');
    2476                    int idx3 = geom.lastIndexOf('+');
    2477
    2478                    idx = Math.max(idx2, idx3);
    2479                    if(idx > 0) {
    2480                        Y = Integer.parseInt(geom.substring(idx + 1));
    2481
    2482                        if(idx == idx2)
    2483                            Y = -Y;
    2484
    2485                        geom = geom.substring(0, idx);
    2486                        idx2 = geom.lastIndexOf('-');
    2487                        idx3 = geom.lastIndexOf('+');
    2488                        idx = Math.max(idx2, idx3);
    2489
    2490                        if(idx > 0) {
    2491                            X = Integer.parseInt(geom.substring(idx + 1));
    2492
    2493                            if(idx == idx2)
    2494                                X = -X;
    2495
    2496                            geom = geom.substring(0, idx);
    2497                        }
    2498                    }
    2499
    2500                    idx = geom.indexOf('x');
    2501
    2502                    if(idx > 0) {
    2503                        W = Integer.parseInt(geom.substring(0, idx));
    2504                        H = Integer.parseInt(geom.substring(idx + 1));
    2505                    }
    2506
    2507                }
    2508                catch (Exception ex) {
    2509                    ex.printStackTrace();
    2510                }
    2511            }
    2512            else if("-java.version".equalsIgnoreCase(args[i])) {
    2513                /* Set icon to ViewProperties.getLargeHdfIcon() */
    2514                Tools.showInformation(mainWindow, "Java Version", JAVA_VER_INFO);
    2515                System.exit(0);
    2516            }
    2517        }
    2518
    2519        Vector<File> fList = new Vector<>();
    2520        tmpFile = null;
    2521
    2522        if(j >= 0) {
    2523            for(int i = args.length - j; i < args.length; i++) {
    2524                tmpFile = new File(args[i]);
    2525                if(!tmpFile.isAbsolute())
    2526                    tmpFile = new File(rootDir, args[i]);
    2527                log.trace("main: filelist - file = {} ", tmpFile.getAbsolutePath());
    2528                log.trace("main: filelist - add file = {} exists={} isFile={} isDir={}", tmpFile, tmpFile.exists(), tmpFile.isFile(), tmpFile.isDirectory());
    2529                if(tmpFile.exists() && (tmpFile.isFile() || tmpFile.isDirectory())) {
    2530                    log.trace("main: flist - add file = {}", tmpFile.getAbsolutePath());
    2531                    fList.add(new File(tmpFile.getAbsolutePath()));
    2532                }
    2533            }
    2534        }
    2535
    2536        final Vector<File> the_fList = fList;
    2537        final String the_rootDir = rootDir;
    2538        final int the_X = X, the_Y = Y, the_W = W, the_H = H;
    2539
    2540        display.syncExec(new Runnable() {
    2541            @Override
    2542            public void run() {
    2543                HDFView app = new HDFView(the_rootDir);
    2544
    2545                // TODO: Look for a better solution to native dialog problem
    2546                app.setTestState(false);
    2547
    2548                app.openMainWindow(the_fList, the_W, the_H, the_X, the_Y);
    2549                app.runMainWindow();
    2550            }
    2551        });
    2552    }
    2553}