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