    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.TableView;
    016
    017import java.lang.reflect.Array;
    018import java.lang.reflect.Constructor;
    019import java.math.BigInteger;
    020import java.util.ArrayList;
    021import java.util.HashMap;
    022import java.util.Iterator;
    023import java.util.LinkedHashSet;
    024import java.util.List;
    025import java.util.Set;
    026import java.util.StringTokenizer;
    027
    028import org.slf4j.Logger;
    029import org.slf4j.LoggerFactory;
    030
    031import org.eclipse.nebula.widgets.nattable.NatTable;
    032import org.eclipse.nebula.widgets.nattable.command.VisualRefreshCommand;
    033import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
    034import org.eclipse.nebula.widgets.nattable.config.EditableRule;
    035import org.eclipse.nebula.widgets.nattable.config.IEditableRule;
    036import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate;
    037import org.eclipse.nebula.widgets.nattable.coordinate.Range;
    038import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
    039import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
    040import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer;
    041import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer;
    042import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
    043import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;
    044import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
    045import org.eclipse.nebula.widgets.nattable.layer.ILayer;
    046import org.eclipse.nebula.widgets.nattable.layer.ILayerListener;
    047import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;
    048import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
    049import org.eclipse.nebula.widgets.nattable.selection.command.SelectCellCommand;
    050import org.eclipse.nebula.widgets.nattable.selection.event.CellSelectionEvent;
    051import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
    052import org.eclipse.swt.SWT;
    053import org.eclipse.swt.custom.ScrolledComposite;
    054import org.eclipse.swt.events.DisposeEvent;
    055import org.eclipse.swt.events.DisposeListener;
    056import org.eclipse.swt.events.SelectionAdapter;
    057import org.eclipse.swt.events.SelectionEvent;
    058import org.eclipse.swt.widgets.Composite;
    059import org.eclipse.swt.widgets.Menu;
    060import org.eclipse.swt.widgets.MenuItem;
    061import org.eclipse.swt.widgets.Shell;
    062
    063import hdf.object.Attribute;
    064import hdf.object.DataFormat;
    065import hdf.object.Dataset;
    066import hdf.object.Datatype;
    067import hdf.object.FileFormat;
    068import hdf.object.HObject;
    069import hdf.object.ScalarDS;
    070import hdf.object.Utils;
    071
    072import hdf.hdf5lib.HDF5Constants;
    073
    074import hdf.object.h5.H5Datatype;
    075import hdf.object.h5.H5File;
    076import hdf.object.h5.H5ScalarAttr;
    077import hdf.object.h5.H5ReferenceType.H5ReferenceData;
    078import hdf.object.h5.H5ReferenceType;
    079
    080import hdf.view.HDFView;
    081import hdf.view.Tools;
    082import hdf.view.ViewProperties;
    083import hdf.view.DataView.DataViewManager;
    084import hdf.view.dialog.InputDialog;
    085
    086/**
    087 * A class to construct a ScalarDS TableView.
    088 */
    089public class DefaultScalarDSTableView extends DefaultBaseTableView implements TableView
    090{
    091    private static final Logger log = LoggerFactory.getLogger(DefaultScalarDSTableView.class);
    092
    093    /**
    094     * Constructs a ScalarDS TableView with no additional data properties.
    095     *
    096     * @param theView
    097     *            the main HDFView.
    098     */
    099    public DefaultScalarDSTableView(DataViewManager theView) {
    100        this(theView, null);
    101    }
    102
    103    /**
    104     * Constructs a ScalarDS TableView with the specified data properties.
    105     *
    106     * @param theView
    107     *            the main HDFView.
    108     *
    109     * @param dataPropertiesMap
    110     *            the properties on how to show the data. The map is used to allow
    111     *            applications to pass properties on how to display the data, such
    112     *            as: transposing data, showing data as characters, applying a
    113     *            bitmask, and etc. Predefined keys are listed at
    114     *            ViewProperties.DATA_VIEW_KEY.
    115     */
    116    @SuppressWarnings("rawtypes")
    117    public DefaultScalarDSTableView(DataViewManager theView, HashMap dataPropertiesMap) {
    118        super(theView, dataPropertiesMap);
    119
    120        if (!shell.isDisposed()) {
    121            if (System.getProperty("os.name").toLowerCase().contains("mac")) {
    122                shell.setImages(ViewProperties.getHdfIcons());
    123            }
    124            else {
    125                shell.setImage(dataObject.getDatatype().isText() ? ViewProperties.getTextIcon() : ViewProperties.getDatasetIcon());
    126            }
    127
    128            shell.addDisposeListener(new DisposeListener() {
    129                @Override
    130                public void widgetDisposed(DisposeEvent e) {
    131                    if (dataObject instanceof ScalarDS) {
    132                        ScalarDS ds = (ScalarDS) dataObject;
    133
    134                        /*
    135                         * Reload the data when it is displayed next time because the display type
    136                         * (table or image) may be different.
    137                         */
    138                        if (ds.isImage()) ds.clearData();
    139                    }
    140                }
    141            });
    142
    143            viewer.addDataView(this);
    144
    145            shell.open();
    146        }
    147    }
    148
    149    @Override
    150    protected void loadData(DataFormat dataObject) throws Exception {
    151        super.loadData(dataObject);
    152
    153        try {
    154            if (Tools.applyBitmask(dataValue, bitmask, bitmaskOP)) {
    155                isReadOnly = true;
    156                String opName = "Bits ";
    157
    158                if (bitmaskOP == ViewProperties.BITMASK_OP.AND)
    159                    opName = "Bitwise AND ";
    160
    161                String title = indexBaseGroup.getText();
    162                title += ", " + opName + bitmask;
    163                indexBaseGroup.setText(title);
    164            }
    165
    166            dataObject.convertFromUnsignedC();
    167
    168            dataValue = dataObject.getData();
    169        }
    170        catch (Exception ex) {
    171            log.debug("loadData(): ", ex);
    172            dataValue = null;
    173            throw ex;
    174        }
    175
    176        if (dataValue == null) {
    177            log.debug("loadData(): data value is null");
    178            throw new RuntimeException("data value is null");
    179        }
    180
    181        fillValue = dataObject.getFillValue();
    182        log.trace("loadData(): fillValue={}", fillValue);
    183
    184        char runtimeTypeClass = Utils.getJavaObjectRuntimeClass(dataValue);
    185        log.trace("loadData(): cName={} runtimeTypeClass={}", dataValue.getClass().getName(), runtimeTypeClass);
    186
    187        /*
    188         * Convert numerical data into character data; only possible cases are byte[]
    189         * and short[] (converted from unsigned byte)
    190         */
    191        if (isDisplayTypeChar && ((runtimeTypeClass == 'B') || (runtimeTypeClass == 'S'))) {
    192            int n = Array.getLength(dataValue);
    193            char[] charData = new char[n];
    194            for (int i = 0; i < n; i++) {
    195                if (runtimeTypeClass == 'B')
    196                    charData[i] = (char) Array.getByte(dataValue, i);
    197                else if (runtimeTypeClass == 'S')
    198                    charData[i] = (char) Array.getShort(dataValue, i);
    199            }
    200
    201            dataValue = charData;
    202        }
    203        else if ((runtimeTypeClass == 'B') && dataObject.getDatatype().isArray()) {
    204            Datatype baseType = dataObject.getDatatype().getDatatypeBase();
    205            if (baseType.isString())
    206                dataValue = Dataset.byteToString((byte[]) dataValue, (int) baseType.getDatatypeSize());
    207        }
    208    }
    209
    210    /**
    211     * Creates the menubar for the Shell.
    212     */
    213    @Override
    214    protected Menu createMenuBar(final Shell theShell) {
    215        Menu baseMenu = super.createMenuBar(theShell);
    216        MenuItem[] baseMenuItems = baseMenu.getItems();
    217        MenuItem item = null;
    218
    219        /*****************************************************************************
    220         *                                                                           *
    221         * Add in a few MenuItems for importing/exporting data from/to binary files. *
    222         *                                                                           *
    223         *****************************************************************************/
    224
    225        MenuItem importExportMenuItem = null;
    226        for (int i = 0; i < baseMenuItems.length; i++)
    227            if (baseMenuItems[i].getText().equals("&Import/Export Data"))
    228                importExportMenuItem = baseMenuItems[i];
    229
    230        if (importExportMenuItem != null) {
    231            Menu importExportMenu = importExportMenuItem.getMenu();
    232            MenuItem[] importExportMenuItems = importExportMenu.getItems();
    233
    234            for (int i = 0; i < importExportMenuItems.length; i++)
    235                if (importExportMenuItems[i].getText().equals("Export Data to"))
    236                    item = importExportMenuItems[i];
    237
    238            if (item != null) {
    239                Menu exportMenu = item.getMenu();
    240
    241                MenuItem exportAsBinaryMenuItem = new MenuItem(exportMenu, SWT.CASCADE);
    242                exportAsBinaryMenuItem.setText("Binary File");
    243
    244                Menu exportAsBinaryMenu = new Menu(exportAsBinaryMenuItem);
    245                exportAsBinaryMenuItem.setMenu(exportAsBinaryMenu);
    246
    247                item = new MenuItem(exportAsBinaryMenu, SWT.PUSH);
    248                item.setText("Native Order");
    249                item.addSelectionListener(new SelectionAdapter() {
    250                    @Override
    251                    public void widgetSelected(SelectionEvent e) {
    252                        binaryOrder = 1;
    253
    254                        try {
    255                            saveAsBinary();
    256                        }
    257                        catch (Exception ex) {
    258                            theShell.getDisplay().beep();
    259                            Tools.showError(theShell, "Export", ex.getMessage());
    260                        }
    261                    }
    262                });
    263
    264                item = new MenuItem(exportAsBinaryMenu, SWT.PUSH);
    265                item.setText("Little Endian");
    266                item.addSelectionListener(new SelectionAdapter() {
    267                    @Override
    268                    public void widgetSelected(SelectionEvent e) {
    269                        binaryOrder = 2;
    270
    271                        try {
    272                            saveAsBinary();
    273                        }
    274                        catch (Exception ex) {
    275                            theShell.getDisplay().beep();
    276                            Tools.showError(theShell, "Export", ex.getMessage());
    277                        }
    278                    }
    279                });
    280
    281                item = new MenuItem(exportAsBinaryMenu, SWT.PUSH);
    282                item.setText("Big Endian");
    283                item.addSelectionListener(new SelectionAdapter() {
    284                    @Override
    285                    public void widgetSelected(SelectionEvent e) {
    286                        binaryOrder = 3;
    287
    288                        try {
    289                            saveAsBinary();
    290                        }
    291                        catch (Exception ex) {
    292                            theShell.getDisplay().beep();
    293                            Tools.showError(theShell, "Export", ex.getMessage());
    294                        }
    295                    }
    296                });
    297            }
    298
    299            item = null;
    300            for (int i = 0; i < importExportMenuItems.length; i++)
    301                if (importExportMenuItems[i].getText().equals("Import Data from"))
    302                    item = importExportMenuItems[i];
    303
    304            if (item != null) {
    305                Menu importMenu = item.getMenu();
    306
    307                MenuItem importAsBinaryMenuItem = new MenuItem(importMenu, SWT.CASCADE);
    308                importAsBinaryMenuItem.setText("Binary File");
    309
    310                Menu importAsBinaryMenu = new Menu(importAsBinaryMenuItem);
    311                importAsBinaryMenuItem.setMenu(importAsBinaryMenu);
    312
    313                item = new MenuItem(importAsBinaryMenu, SWT.PUSH);
    314                item.setText("Native Order");
    315                item.setEnabled(!isReadOnly);
    316                item.addSelectionListener(new SelectionAdapter() {
    317                    @Override
    318                    public void widgetSelected(SelectionEvent e) {
    319                        binaryOrder = 1;
    320
    321                        try {
    322                            importBinaryData();
    323                        }
    324                        catch (Exception ex) {
    325                            Tools.showError(theShell, "Import", ex.getMessage());
    326                        }
    327                    }
    328                });
    329
    330                item = new MenuItem(importAsBinaryMenu, SWT.PUSH);
    331                item.setText("Little Endian");
    332                item.setEnabled(!isReadOnly);
    333                item.addSelectionListener(new SelectionAdapter() {
    334                    @Override
    335                    public void widgetSelected(SelectionEvent e) {
    336                        binaryOrder = 2;
    337
    338                        try {
    339                            importBinaryData();
    340                        }
    341                        catch (Exception ex) {
    342                            Tools.showError(theShell, "Import", ex.getMessage());
    343                        }
    344                    }
    345                });
    346
    347                item = new MenuItem(importAsBinaryMenu, SWT.PUSH);
    348                item.setText("Big Endian");
    349                item.setEnabled(!isReadOnly);
    350                item.addSelectionListener(new SelectionAdapter() {
    351                    @Override
    352                    public void widgetSelected(SelectionEvent e) {
    353                        binaryOrder = 3;
    354
    355                        try {
    356                            importBinaryData();
    357                        }
    358                        catch (Exception ex) {
    359                            Tools.showError(theShell, "Import", ex.getMessage());
    360                        }
    361                    }
    362                });
    363            }
    364
    365            new MenuItem(importExportMenu, SWT.SEPARATOR);
    366
    367            checkFixedDataLength = new MenuItem(importExportMenu, SWT.CHECK);
    368            checkFixedDataLength.setText("Fixed Data Length");
    369            checkFixedDataLength.addSelectionListener(new SelectionAdapter() {
    370                @Override
    371                public void widgetSelected(SelectionEvent e) {
    372                    if (!checkFixedDataLength.getSelection()) {
    373                        fixedDataLength = -1;
    374                        return;
    375                    }
    376
    377                    String str = new InputDialog(theShell, "",
    378                            "Enter fixed data length when importing text data\n\n"
    379                                    + "For example, for a text string of \"12345678\"\n\t\tenter 2,"
    380                                    + "the data will be 12, 34, 56, 78\n\t\tenter 4, the data will be" + "1234, 5678\n")
    381                            .open();
    382
    383                    if ((str == null) || (str.length() < 1)) {
    384                        checkFixedDataLength.setSelection(false);
    385                        return;
    386                    }
    387
    388                    try {
    389                        fixedDataLength = Integer.parseInt(str);
    390                    }
    391                    catch (Exception ex) {
    392                        fixedDataLength = -1;
    393                    }
    394
    395                    if (fixedDataLength < 1) {
    396                        checkFixedDataLength.setSelection(false);
    397                    }
    398                }
    399            });
    400        }
    401
    402        /*****************************************************************************************
    403         *                                                                                       *
    404         * Add a section for changing the way that data is displayed, e.g. as hexadecimal values *
    405         *                                                                                       *
    406         *****************************************************************************************/
    407
    408        MenuItem dataDisplayMenuItem = new MenuItem(baseMenu, SWT.CASCADE);
    409        dataDisplayMenuItem.setText("Data Display");
    410
    411        Menu dataDisplayMenu = new Menu(theShell, SWT.DROP_DOWN);
    412        dataDisplayMenuItem.setMenu(dataDisplayMenu);
    413
    414        checkScientificNotation = new MenuItem(dataDisplayMenu, SWT.CHECK);
    415        checkScientificNotation.setText("Show Scientific Notation");
    416        checkScientificNotation.addSelectionListener(new SelectionAdapter() {
    417            @Override
    418            public void widgetSelected(SelectionEvent e) {
    419                if (checkScientificNotation.getSelection()) {
    420                    if (checkCustomNotation != null)
    421                        checkCustomNotation.setSelection(false);
    422                    if (checkEnum != null)
    423                        checkEnum.setSelection(false);
    424                    if (checkHex != null)
    425                        checkHex.setSelection(false);
    426                    if (checkBin != null)
    427                        checkBin.setSelection(false);
    428
    429                    numberFormat = scientificFormat;
    430                    showAsHex = false;
    431                    showAsBin = false;
    432                }
    433                else {
    434                    numberFormat = normalFormat;
    435                }
    436
    437                updateDataConversionSettings();
    438
    439                dataTable.doCommand(new VisualRefreshCommand());
    440
    441                PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition();
    442                if (lastSelectedCell != null) {
    443                    /*
    444                     * Send down a cell selection event for the current cell to update the cell
    445                     * value labels
    446                     */
    447                    dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition,
    448                            lastSelectedCell.rowPosition, false, false));
    449                }
    450            }
    451        });
    452
    453        checkCustomNotation = new MenuItem(dataDisplayMenu, SWT.CHECK);
    454        checkCustomNotation.setText("Show Custom Notation");
    455        checkCustomNotation.addSelectionListener(new SelectionAdapter() {
    456            @Override
    457            public void widgetSelected(SelectionEvent e) {
    458                if (checkCustomNotation.getSelection()) {
    459                    if (checkScientificNotation != null)
    460                        checkScientificNotation.setSelection(false);
    461                    if (checkEnum != null)
    462                        checkEnum.setSelection(false);
    463                    if (checkHex != null)
    464                        checkHex.setSelection(false);
    465                    if (checkBin != null)
    466                        checkBin.setSelection(false);
    467
    468                    numberFormat = customFormat;
    469                    showAsHex = false;
    470                    showAsBin = false;
    471                }
    472                else {
    473                    numberFormat = normalFormat;
    474                }
    475
    476                updateDataConversionSettings();
    477
    478                dataTable.doCommand(new VisualRefreshCommand());
    479
    480                PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition();
    481                if (lastSelectedCell != null) {
    482                    /*
    483                     * Send down a cell selection event for the current cell to update the cell
    484                     * value labels
    485                     */
    486                    dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition,
    487                            lastSelectedCell.rowPosition, false, false));
    488                }
    489            }
    490        });
    491
    492        item = new MenuItem(dataDisplayMenu, SWT.PUSH);
    493        item.setText("Create custom notation");
    494        item.addSelectionListener(new SelectionAdapter() {
    495            @Override
    496            public void widgetSelected(SelectionEvent e) {
    497                String msg = "Create number format by pattern \nINTEGER . FRACTION E EXPONENT\nusing # for optional digits and 0 for required digits"
    498                        + "\nwhere, INTEGER: the pattern for the integer part"
    499                        + "\n       FRACTION: the pattern for the fractional part"
    500                        + "\n       EXPONENT: the pattern for the exponent part" + "\n\nFor example, "
    501                        + "\n\t the normalized scientific notation format is \"#.0###E0##\""
    502                        + "\n\t to make the digits required \"0.00000E000\"\n\n";
    503
    504                String str = (new InputDialog(theShell, "Create a custom number format", msg, customFormat.toPattern())).open();
    505
    506                if ((str == null) || (str.length() < 1))
    507                    return;
    508
    509                try {
    510                    customFormat.applyPattern(str);
    511                }
    512                catch (Exception ex) {
    513                    log.debug("Invalid custom number notation format: {}:", str, ex);
    514                    Tools.showError(shell, "Create", "Invalid custom notation format " + str);
    515                }
    516            }
    517        });
    518
    519        char runtimeTypeClass = Utils.getJavaObjectRuntimeClass(dataValue);
    520        boolean isInt = (runtimeTypeClass == 'B' || runtimeTypeClass == 'S' || runtimeTypeClass == 'I'
    521                || runtimeTypeClass == 'J');
    522
    523        if (isInt || dataObject.getDatatype().isBitField() || dataObject.getDatatype().isOpaque()) {
    524            checkHex = new MenuItem(dataDisplayMenu, SWT.CHECK);
    525            checkHex.setText("Show Hexadecimal");
    526            checkHex.addSelectionListener(new SelectionAdapter() {
    527                @Override
    528                public void widgetSelected(SelectionEvent e) {
    529                    showAsHex = checkHex.getSelection();
    530                    if (showAsHex) {
    531                        if (checkScientificNotation != null)
    532                            checkScientificNotation.setSelection(false);
    533                        if (checkCustomNotation != null)
    534                            checkCustomNotation.setSelection(false);
    535                        if (checkEnum != null)
    536                            checkEnum.setSelection(false);
    537                        if (checkBin != null)
    538                            checkBin.setSelection(false);
    539
    540                        showAsBin = false;
    541                        numberFormat = normalFormat;
    542                    }
    543
    544                    updateDataConversionSettings();
    545
    546                    dataTable.doCommand(new VisualRefreshCommand());
    547
    548                    PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition();
    549                    if (lastSelectedCell != null) {
    550                        /*
    551                         * Send down a cell selection event for the current cell to update the cell
    552                         * value labels
    553                         */
    554                        dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition,
    555                                lastSelectedCell.rowPosition, false, false));
    556                    }
    557                }
    558            });
    559
    560            checkBin = new MenuItem(dataDisplayMenu, SWT.CHECK);
    561            checkBin.setText("Show Binary");
    562            checkBin.addSelectionListener(new SelectionAdapter() {
    563                @Override
    564                public void widgetSelected(SelectionEvent e) {
    565                    showAsBin = checkBin.getSelection();
    566                    if (showAsBin) {
    567                        if (checkScientificNotation != null)
    568                            checkScientificNotation.setSelection(false);
    569                        if (checkCustomNotation != null)
    570                            checkCustomNotation.setSelection(false);
    571                        if (checkEnum != null)
    572                            checkEnum.setSelection(false);
    573                        if (checkHex != null)
    574                            checkHex.setSelection(false);
    575
    576                        showAsHex = false;
    577                        numberFormat = normalFormat;
    578                    }
    579
    580                    updateDataConversionSettings();
    581
    582                    dataTable.doCommand(new VisualRefreshCommand());
    583
    584                    PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition();
    585                    if (lastSelectedCell != null) {
    586                        /*
    587                         * Send down a cell selection event for the current cell to update the cell
    588                         * value labels
    589                         */
    590                        dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition,
    591                                lastSelectedCell.rowPosition, false, false));
    592                    }
    593                }
    594            });
    595
    596            checkEnum = new MenuItem(dataDisplayMenu, SWT.CHECK);
    597            checkEnum.setText("Show Enum Values");
    598            checkEnum.addSelectionListener(new SelectionAdapter() {
    599                @Override
    600                public void widgetSelected(SelectionEvent e) {
    601                    isEnumConverted = checkEnum.getSelection();
    602                    if (isEnumConverted) {
    603                        if (checkScientificNotation != null)
    604                            checkScientificNotation.setSelection(false);
    605                        if (checkCustomNotation != null)
    606                            checkCustomNotation.setSelection(false);
    607                        if (checkHex != null)
    608                            checkHex.setSelection(false);
    609                        if (checkBin != null)
    610                            checkBin.setSelection(false);
    611
    612                        showAsBin = false;
    613                        showAsHex = false;
    614                        numberFormat = normalFormat;
    615                    }
    616
    617                    updateDataConversionSettings();
    618
    619                    dataTable.doCommand(new VisualRefreshCommand());
    620
    621                    PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition();
    622                    if (lastSelectedCell != null) {
    623                        /*
    624                         * Send down a cell selection event for the current cell to update the cell
    625                         * value labels
    626                         */
    627                        dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition,
    628                                lastSelectedCell.rowPosition, false, false));
    629                    }
    630                }
    631            });
    632        }
    633
    634        return baseMenu;
    635    }
    636
    637    /**
    638     * Creates a NatTable for a Scalar dataset.
    639     *
    640     * @param parent
    641     *            The parent for the NatTable
    642     * @param dataObject
    643     *            The Scalar dataset for the NatTable to display
    644     *
    645     * @return The newly created NatTable
    646     */
    647    @Override
    648    protected NatTable createTable(Composite parent, DataFormat dataObject) {
    649        // Create body layer
    650        try {
    651            dataProvider = DataProviderFactory.getDataProvider(dataObject, dataValue, isDataTransposed);
    652
    653            log.trace("createTable(): rows={} : cols={}", dataProvider.getRowCount(), dataProvider.getColumnCount());
    654
    655            dataLayer = new DataLayer(dataProvider);
    656        }
    657        catch (Exception ex) {
    658            log.debug("createTable(): failed to retrieve DataProvider for table: ", ex);
    659            return null;
    660        }
    661
    662        selectionLayer = new SelectionLayer(dataLayer);
    663        final ViewportLayer viewportLayer = new ViewportLayer(selectionLayer);
    664
    665        dataLayer.setDefaultColumnWidth(80);
    666
    667        // Create the Column Header layer
    668        columnHeaderDataProvider = new ScalarDSColumnHeaderDataProvider(dataObject);
    669        ColumnHeaderLayer columnHeaderLayer = new ColumnHeader(new DataLayer(columnHeaderDataProvider), viewportLayer,
    670                selectionLayer);
    671
    672        // Create the Row Header layer
    673        rowHeaderDataProvider = new RowHeaderDataProvider(dataObject);
    674
    675        // Try to adapt row height to current font
    676        int defaultRowHeight = curFont == null ? 20 : (2 * curFont.getFontData()[0].getHeight());
    677
    678        DataLayer baseLayer = new DataLayer(rowHeaderDataProvider, 40, defaultRowHeight);
    679        RowHeaderLayer rowHeaderLayer = new RowHeader(baseLayer, viewportLayer, selectionLayer);
    680
    681        // Create the Corner Layer
    682        ILayer cornerLayer = new CornerLayer(
    683                new DataLayer(new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider)),
    684                rowHeaderLayer, columnHeaderLayer);
    685
    686        // Create the Grid Layer
    687        GridLayer gridLayer = new EditingGridLayer(viewportLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer);
    688
    689        final NatTable natTable = new NatTable(parent, gridLayer, false);
    690        natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
    691        natTable.addLayerListener(new ScalarDSCellSelectionListener());
    692
    693        // Create popup menu for region or object ref.
    694        if (isStdRef || isRegRef || isObjRef)
    695            natTable.addConfiguration(new RefContextMenu(natTable));
    696
    697        natTable.configure();
    698
    699        return natTable;
    700    }
    701
    702    /**
    703     * Returns the selected data values of the ScalarDS
    704     */
    705    @Override
    706    public Object getSelectedData() {
    707        Object selectedData = null;
    708
    709        // Since NatTable returns the selected row positions as a Set<Range>, convert
    710        // this to an Integer[]
    711        Set<Range> rowPositions = selectionLayer.getSelectedRowPositions();
    712        log.trace("getSelectedData() rowPositions: {}", rowPositions);
    713        Set<Integer> selectedRowPos = new LinkedHashSet<>();
    714        Iterator<Range> i1 = rowPositions.iterator();
    715        while (i1.hasNext())
    716            selectedRowPos.addAll(i1.next().getMembers());
    717
    718        Integer[] selectedRows = selectedRowPos.toArray(new Integer[0]);
    719        int[] selectedCols = selectionLayer.getSelectedColumnPositions();
    720
    721        if (selectedRows == null || selectedRows.length <= 0 || selectedCols == null || selectedCols.length <= 0) {
    722            shell.getDisplay().beep();
    723            Tools.showError(shell, "Select", "No data is selected.");
    724            return null;
    725        }
    726
    727        int size = selectedCols.length * selectedRows.length;
    728        log.trace("getSelectedData() data size: {}", size);
    729
    730        // the whole table is selected
    731        if ((dataTable.getPreferredColumnCount() - 1 == selectedCols.length)
    732                && (dataTable.getPreferredRowCount() - 1 == selectedRows.length))
    733            return dataValue;
    734
    735        if (dataObject.getDatatype().isRef()) {
    736            // ref data are stored in bytes
    737            selectedData = new byte[size * (int)dataObject.getDatatype().getDatatypeSize()];
    738        }
    739        else {
    740            switch (Utils.getJavaObjectRuntimeClass(dataValue)) {
    741            case 'B':
    742                selectedData = new byte[size];
    743                break;
    744            case 'S':
    745                selectedData = new short[size];
    746                break;
    747            case 'I':
    748                selectedData = new int[size];
    749                break;
    750            case 'J':
    751                selectedData = new long[size];
    752                break;
    753            case 'F':
    754                selectedData = new float[size];
    755                break;
    756            case 'D':
    757                selectedData = new double[size];
    758                break;
    759            default:
    760                selectedData = null;
    761                break;
    762            }
    763        }
    764
    765        if (selectedData == null) {
    766            shell.getDisplay().beep();
    767            Tools.showError(shell, "Select", "Unsupported data type.");
    768            return null;
    769        }
    770
    771        log.trace("getSelectedData(): selectedData is type {}", Utils.getJavaObjectRuntimeClass(dataValue));
    772
    773        int w = dataTable.getPreferredColumnCount() - 1;
    774        log.trace("getSelectedData(): getColumnCount={}", w);
    775        int idxSrc = 0;
    776        int idxDst = 0;
    777        log.trace("getSelectedData(): Rows.length={} Cols.length={}", selectedRows.length,
    778                selectedCols.length);
    779        for (int i = 0; i < selectedRows.length; i++) {
    780            for (int j = 0; j < selectedCols.length; j++) {
    781                idxSrc = selectedRows[i] * w + selectedCols[j];
    782                Object dataArrayValue = null;
    783                if (dataValue instanceof ArrayList) {
    784                    dataArrayValue = ((ArrayList)dataValue).get(idxSrc);
    785                    System.arraycopy(dataArrayValue, 0, selectedData, idxDst, (int)dataObject.getDatatype().getDatatypeSize());
    786                }
    787                else {
    788                    dataArrayValue = Array.get(dataValue, idxSrc);
    789                    Array.set(selectedData, idxDst, dataArrayValue);
    790                }
    791                log.trace("getSelectedData()[{},{}]: dataValue[{}]={} from r{} and c{}", i, j,
    792                        idxSrc, dataArrayValue, selectedRows[i], selectedCols[j]);
    793                idxDst++;
    794            }
    795        }
    796
    797        return selectedData;
    798    }
    799
    800    /**
    801     * Returns an IEditableRule that determines whether cells can be edited.
    802     *
    803     * Cells can be edited as long as the dataset is not opened in read-only mode
    804     * and the data is not currently displayed in hexadecimal, binary, or character
    805     * mode.
    806     *
    807     * @param dataObject
    808     *            The dataset for editing
    809     *
    810     * @return a new IEditableRule for the dataset
    811     */
    812    @Override
    813    protected IEditableRule getDataEditingRule(final DataFormat dataObject) {
    814        if (dataObject == null)
    815            return null;
    816
    817        // Only Allow editing if not in read-only mode
    818        return new EditableRule() {
    819            @Override
    820            public boolean isEditable(int columnIndex, int rowIndex) {
    821                /*
    822                 * TODO: Should be able to edit character-displayed types and datasets when
    823                 * displayed as hex/binary.
    824                 */
    825                return !(isReadOnly || isDisplayTypeChar || showAsBin || showAsHex);
    826            }
    827        };
    828    }
    829
    830    /**
    831     * Display data pointed to by object references. Data of each object is shown in
    832     * a separate spreadsheet.
    833     *
    834     * @param refarr
    835     *            the array of bytes that contain the object reference information.
    836     *
    837     */
    838    @Override
    839    @SuppressWarnings({ "rawtypes", "unchecked" })
    840    protected void showObjRefData(byte[] refarr) {
    841        log.trace("showObjRefData(): start: refarr={}", refarr);
    842
    843        if (refarr == null || (refarr.length <= 0) || H5Datatype.zeroArrayCheck(refarr)) {
    844            Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data");
    845            log.debug("showObjRefData(): refarr is null or invalid");
    846            return;
    847        }
    848
    849        String objref = H5Datatype.descReferenceObject(((HObject) dataObject).getFileFormat().getFID(), refarr);
    850        log.trace("showObjRefData(): start: objref={}", objref);
    851
    852        // find the object location
    853        String oidStr = objref.substring(objref.indexOf('/'), objref.indexOf("H5O_TYPE_OBJ_REF")-1);
    854        HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), oidStr);
    855        if (obj == null || !(obj instanceof ScalarDS)) {
    856            Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data");
    857            log.debug("showObjRefData(): obj is null or not a Scalar Dataset");
    858            return;
    859        }
    860
    861        ScalarDS dset = (ScalarDS) obj;
    862        ScalarDS dsetCopy = null;
    863
    864        // create an instance of the dataset constructor
    865        Constructor<? extends ScalarDS> constructor = null;
    866        Object[] paramObj = null;
    867        Object data = null;
    868
    869        try {
    870            Class[] paramClass = { FileFormat.class, String.class, String.class };
    871            constructor = dset.getClass().getConstructor(paramClass);
    872            paramObj = new Object[] { dset.getFileFormat(), dset.getName(), dset.getPath() };
    873            dsetCopy = constructor.newInstance(paramObj);
    874            data = dsetCopy.getData();
    875        }
    876        catch (Exception ex) {
    877            log.debug("showObjRefData(): couldn't show data: ", ex);
    878            Tools.showError(shell, "Select", "Object Reference: " + ex.getMessage());
    879            data = null;
    880        }
    881
    882        if (data == null)
    883            return;
    884
    885        Class<?> theClass = null;
    886        String viewName = null;
    887
    888        switch (viewType) {
    889        case IMAGE:
    890            viewName = HDFView.getListOfImageViews().get(0);
    891            break;
    892        case TABLE:
    893            viewName = (String) HDFView.getListOfTableViews().get(0);
    894            break;
    895        default:
    896            viewName = null;
    897        }
    898
    899        try {
    900            theClass = Class.forName(viewName);
    901        }
    902        catch (Exception ex) {
    903            try {
    904                theClass = ViewProperties.loadExtClass().loadClass(viewName);
    905            }
    906            catch (Exception ex2) {
    907                theClass = null;
    908            }
    909        }
    910
    911        // Use default dataview
    912        if (theClass == null) {
    913            switch (viewType) {
    914            case IMAGE:
    915                viewName = ViewProperties.DEFAULT_IMAGEVIEW_NAME;
    916                break;
    917            case TABLE:
    918                viewName = ViewProperties.DEFAULT_SCALAR_DATASET_TABLEVIEW_NAME;
    919                break;
    920            default:
    921                viewName = null;
    922            }
    923
    924            try {
    925                theClass = Class.forName(viewName);
    926            }
    927            catch (Exception ex) {
    928                log.debug("showObjRefData(): no suitable display class found");
    929                Tools.showError(shell, "Select", "Could not show reference data: no suitable display class found");
    930                return;
    931            }
    932        }
    933
    934        HashMap map = new HashMap(1);
    935        map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, dsetCopy);
    936        Object[] args = { viewer, map };
    937
    938        try {
    939            Tools.newInstance(theClass, args);
    940        }
    941        catch (Exception ex) {
    942            log.debug("showObjRefData(): Could not show reference data: ", ex);
    943            Tools.showError(shell, "Select", "Could not show reference data: " + ex.toString());
    944        }
    945    }
    946
    947    /**
    948     * Display data pointed to by region references. Data of each region is shown in
    949     * a separate spreadsheet.
    950     *
    951     * @param refarr
    952     *            the array of bytes that contain the reg. ref information.
    953     *
    954     */
    955    @Override
    956    @SuppressWarnings({ "rawtypes", "unchecked" })
    957    protected void showRegRefData(byte[] refarr) {
    958        if (refarr == null || (refarr.length <= 0) || H5Datatype.zeroArrayCheck(refarr)) {
    959            Tools.showError(shell, "Select", "Could not show region reference data: invalid or null data");
    960            log.debug("showRegRefData(): refarr is null or invalid");
    961            return;
    962        }
    963
    964        String reg = null;
    965        if (refarr.length == HDF5Constants.H5R_DSET_REG_REF_BUF_SIZE)
    966            reg = H5Datatype.descRegionDataset(((HObject) dataObject).getFileFormat().getFID(), refarr);
    967        else
    968            reg = ((H5ReferenceType)dataObject.getDatatype()).getReferenceRegion(refarr, false);
    969
    970        boolean isPointSelection = (reg.indexOf('-') <= 0);
    971
    972        // find the object location
    973        String oidStr = reg.substring(reg.indexOf('/'), reg.indexOf("REGION_TYPE")-1);
    974
    975        // decode the region selection
    976        String regStr = reg.substring(reg.indexOf('{') + 1, reg.indexOf('}'));
    977        if (regStr == null || regStr.length() <= 0) {
    978            Tools.showError(shell, "Select", "Could not show region reference data: no region selection made.");
    979            log.debug("showRegRefData(): no region selection made");
    980            return; // no selection
    981        }
    982
    983        // TODO: do we need to do something with what's past the closing bracket
    984        // regStr = reg.substring(reg.indexOf('}') + 1);
    985
    986        StringTokenizer st = new StringTokenizer(regStr);
    987        int nSelections = st.countTokens();
    988        if (nSelections <= 0) {
    989            Tools.showError(shell, "Select", "Could not show region reference data: no region selection made.");
    990            log.debug("showRegRefData(): no region selection made");
    991            return; // no selection
    992        }
    993
    994        HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), oidStr);
    995        if (obj == null || !(obj instanceof ScalarDS)) {
    996            Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data");
    997            log.debug("showRegRefData(): obj is null or not a Scalar Dataset");
    998            return;
    999        }
    1000
    1001        ScalarDS dset = (ScalarDS) obj;
    1002        ScalarDS dsetCopy = null;
    1003
    1004        // create an instance of the dataset constructor
    1005        Constructor<? extends ScalarDS> constructor = null;
    1006        Object[] paramObj = null;
    1007        try {
    1008            Class[] paramClass = { FileFormat.class, String.class, String.class };
    1009            constructor = dset.getClass().getConstructor(paramClass);
    1010            paramObj = new Object[] { dset.getFileFormat(), dset.getName(), dset.getPath() };
    1011        }
    1012        catch (Exception ex) {
    1013            log.debug("showRegRefData(): constructor failure: ", ex);
    1014            constructor = null;
    1015        }
    1016
    1017        // load each selection into a separate dataset and display it in
    1018        // a separate spreadsheet
    1019
    1020        while (st.hasMoreTokens()) {
    1021            try {
    1022                dsetCopy = constructor.newInstance(paramObj);
    1023            }
    1024            catch (Exception ex) {
    1025                log.debug("showRegRefData(): constructor newInstance failure: ", ex);
    1026                continue;
    1027            }
    1028
    1029            if (dsetCopy == null) {
    1030                log.debug("showRegRefData(): continue after null dataset copy");
    1031                continue;
    1032            }
    1033
    1034            try {
    1035                dsetCopy.init();
    1036            }
    1037            catch (Exception ex) {
    1038                log.debug("showRegRefData(): continue after copied dataset init failure: ", ex);
    1039                continue;
    1040            }
    1041
    1042            dsetCopy.getRank();
    1043            long[] start = dsetCopy.getStartDims();
    1044            long[] count = dsetCopy.getSelectedDims();
    1045
    1046            // set the selected dimension sizes based on the region selection
    1047            // info.
    1048            int idx = 0;
    1049            String sizeStr = null;
    1050            String token = st.nextToken();
    1051
    1052            token = token.replace('(', ' ');
    1053            token = token.replace(')', ' ');
    1054            if (isPointSelection) {
    1055                // point selection
    1056                StringTokenizer tmp = new StringTokenizer(token, ",");
    1057                while (tmp.hasMoreTokens()) {
    1058                    count[idx] = 1;
    1059                    sizeStr = tmp.nextToken().trim();
    1060                    start[idx] = Long.valueOf(sizeStr);
    1061                    idx++;
    1062                }
    1063            }
    1064            else {
    1065                // rectangle selection
    1066                String startStr = token.substring(0, token.indexOf('-'));
    1067                String endStr = token.substring(token.indexOf('-') + 1);
    1068                StringTokenizer tmp = new StringTokenizer(startStr, ",");
    1069                while (tmp.hasMoreTokens()) {
    1070                    sizeStr = tmp.nextToken().trim();
    1071                    start[idx] = Long.valueOf(sizeStr);
    1072                    idx++;
    1073                }
    1074
    1075                idx = 0;
    1076                tmp = new StringTokenizer(endStr, ",");
    1077                while (tmp.hasMoreTokens()) {
    1078                    sizeStr = tmp.nextToken().trim();
    1079                    count[idx] = Long.valueOf(sizeStr) - start[idx] + 1;
    1080                    idx++;
    1081                }
    1082            }
    1083
    1084            try {
    1085                dsetCopy.getData();
    1086            }
    1087            catch (Exception ex) {
    1088                log.debug("showRegRefData(): getData failure: ", ex);
    1089                Tools.showError(shell, "Select", "Region Reference: " + ex.getMessage());
    1090            }
    1091
    1092            Class<?> theClass = null;
    1093            String viewName = null;
    1094
    1095            switch (viewType) {
    1096            case IMAGE:
    1097                viewName = HDFView.getListOfImageViews().get(0);
    1098                break;
    1099            case TABLE:
    1100                viewName = (String) HDFView.getListOfTableViews().get(0);
    1101                break;
    1102            default:
    1103                viewName = null;
    1104            }
    1105
    1106            try {
    1107                theClass = Class.forName(viewName);
    1108            }
    1109            catch (Exception ex) {
    1110                try {
    1111                    theClass = ViewProperties.loadExtClass().loadClass(viewName);
    1112                }
    1113                catch (Exception ex2) {
    1114                    theClass = null;
    1115                }
    1116            }
    1117
    1118            // Use default dataview
    1119            if (theClass == null) {
    1120                switch (viewType) {
    1121                case IMAGE:
    1122                    viewName = ViewProperties.DEFAULT_IMAGEVIEW_NAME;
    1123                    break;
    1124                case TABLE:
    1125                    viewName = ViewProperties.DEFAULT_SCALAR_DATASET_TABLEVIEW_NAME;
    1126                    break;
    1127                default:
    1128                    viewName = null;
    1129                }
    1130
    1131                try {
    1132                    theClass = Class.forName(viewName);
    1133                }
    1134                catch (Exception ex) {
    1135                    log.debug("showRegRefData(): no suitable display class found");
    1136                    Tools.showError(shell, "Select", "Could not show reference data: no suitable display class found");
    1137                    return;
    1138                }
    1139            }
    1140
    1141            HashMap map = new HashMap(1);
    1142            map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, dsetCopy);
    1143            Object[] args = { viewer, map };
    1144
    1145            try {
    1146                Tools.newInstance(theClass, args);
    1147            }
    1148            catch (Exception ex) {
    1149                log.debug("showRegRefData(): Could not show reference data: ", ex);
    1150                Tools.showError(shell, "Select", "Could not show reference data: " + ex.toString());
    1151            }
    1152        } // (st.hasMoreTokens())
    1153    } // end of showRegRefData()
    1154
    1155    /**
    1156     * Display data pointed to by references. Data of each reference is shown in
    1157     * a separate spreadsheet. The std. ref. information is stored in bytes
    1158     *
    1159     * @param refarr
    1160     *            the array of bytes that contain the std. ref information.
    1161     *
    1162     */
    1163    @Override
    1164    @SuppressWarnings({ "rawtypes", "unchecked" })
    1165    protected void showStdRefData(byte[] refarr) {
    1166        if (refarr == null || H5ReferenceType.zeroArrayCheck(refarr)) {
    1167            Tools.showError(shell, "Select", "Could not show region reference data: invalid or null data");
    1168            log.debug("showStdRefData(): ref is null or invalid");
    1169            return;
    1170        }
    1171
    1172        H5ReferenceType refType = ((H5ReferenceType) dataObject.getDatatype());
    1173        H5ReferenceData refdata = refType.getReferenceData(refarr);
    1174        /* get the filename associated with the reference */
    1175        String reffile = refdata.file_name;
    1176        if ((refdata.ref_type == HDF5Constants.H5R_DATASET_REGION1) ||
    1177                (refdata.ref_type == HDF5Constants.H5R_DATASET_REGION2)) {
    1178            String ref_ptr = refType.getReferenceRegion(refarr, false);
    1179            if ("REGION_TYPE UNKNOWN".equals(refdata.region_type)) {
    1180                String msg = "Reference to " + ref_ptr + " cannot be displayed in a table";
    1181                Tools.showInformation(shell, "Reference", msg);
    1182            }
    1183            else {
    1184                showRegRefData(refarr);
    1185            }
    1186        }
    1187        if (((refdata.ref_type == HDF5Constants.H5R_OBJECT1) && (refdata.obj_type == HDF5Constants.H5O_TYPE_DATASET)) ||
    1188                ((refdata.ref_type == HDF5Constants.H5R_OBJECT2) && (refdata.obj_type == HDF5Constants.H5O_TYPE_DATASET))) {
    1189            String ref_obj = refdata.obj_name;
    1190            showObjStdRefData(ref_obj);
    1191        }
    1192        else if (refdata.ref_type == HDF5Constants.H5R_ATTR) {
    1193            String ref_attr_name = refdata.attr_name;
    1194            String ref_obj_name = refdata.obj_name;
    1195            showAttrStdRefData(ref_obj_name, ref_attr_name);
    1196        }
    1197        else if ("H5O_TYPE_OBJ_REF".equals(refdata.region_type)) {
    1198            String msg = "Reference to " + refdata.obj_name + " cannot be displayed in a table";
    1199            //String ref_ptr = refType.getObjectReferenceName(refarr);
    1200            Tools.showInformation(shell, "Reference", msg);
    1201        }
    1202        else {
    1203            // Other types
    1204        }
    1205    } // end of showStdRefData(byte[] refarr)
    1206
    1207    /**
    1208     * Display data pointed to by object references. Data of each object is shown in
    1209     * a separate spreadsheet.
    1210     *
    1211     * @param ref
    1212     *            the string that contain the object reference information.
    1213     *
    1214     */
    1215    @SuppressWarnings({ "rawtypes", "unchecked" })
    1216    protected void showObjStdRefData(String ref) {
    1217        if (ref == null || (ref.length() <= 0) || (ref.compareTo("NULL") == 0)) {
    1218            Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data");
    1219            log.debug("showObjStdRefData(): ref is null or invalid");
    1220            return;
    1221        }
    1222
    1223        HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), ref);
    1224        if (obj == null || !(obj instanceof ScalarDS)) {
    1225            Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data");
    1226            log.debug("showObjStdRefData(): obj is null or not a Scalar Dataset");
    1227            return;
    1228        }
    1229
    1230        ScalarDS dset = (ScalarDS) obj;
    1231        ScalarDS dsetCopy = null;
    1232
    1233        // create an instance of the dataset constructor
    1234        Constructor<? extends ScalarDS> constructor = null;
    1235        Object[] paramObj = null;
    1236        Object data = null;
    1237
    1238        try {
    1239            Class[] paramClass = { FileFormat.class, String.class, String.class };
    1240            constructor = dset.getClass().getConstructor(paramClass);
    1241            paramObj = new Object[] { dset.getFileFormat(), dset.getName(), dset.getPath() };
    1242            dsetCopy = constructor.newInstance(paramObj);
    1243            data = dsetCopy.getData();
    1244        }
    1245        catch (Exception ex) {
    1246            log.debug("showObjStdRefData(): couldn't show data: ", ex);
    1247            Tools.showError(shell, "Select", "Object Reference: " + ex.getMessage());
    1248            data = null;
    1249        }
    1250
    1251        if (data == null)
    1252            return;
    1253
    1254        Class<?> theClass = null;
    1255        String viewName = null;
    1256
    1257        switch (viewType) {
    1258        case IMAGE:
    1259            viewName = HDFView.getListOfImageViews().get(0);
    1260            break;
    1261        case TABLE:
    1262            viewName = (String) HDFView.getListOfTableViews().get(0);
    1263            break;
    1264        default:
    1265            viewName = null;
    1266        }
    1267
    1268        try {
    1269            theClass = Class.forName(viewName);
    1270        }
    1271        catch (Exception ex) {
    1272            try {
    1273                theClass = ViewProperties.loadExtClass().loadClass(viewName);
    1274            }
    1275            catch (Exception ex2) {
    1276                theClass = null;
    1277            }
    1278        }
    1279
    1280        // Use default dataview
    1281        if (theClass == null) {
    1282            switch (viewType) {
    1283            case IMAGE:
    1284                viewName = ViewProperties.DEFAULT_IMAGEVIEW_NAME;
    1285                break;
    1286            case TABLE:
    1287                viewName = ViewProperties.DEFAULT_SCALAR_DATASET_TABLEVIEW_NAME;
    1288                break;
    1289            default:
    1290                viewName = null;
    1291            }
    1292
    1293            try {
    1294                theClass = Class.forName(viewName);
    1295            }
    1296            catch (Exception ex) {
    1297                log.debug("showObjStdRefData(): no suitable display class found");
    1298                Tools.showError(shell, "Select", "Could not show reference data: no suitable display class found");
    1299                return;
    1300            }
    1301        }
    1302
    1303        HashMap map = new HashMap(1);
    1304        map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, dsetCopy);
    1305        Object[] args = { viewer, map };
    1306
    1307        try {
    1308            Tools.newInstance(theClass, args);
    1309        }
    1310        catch (Exception ex) {
    1311            log.debug("showObjStdRefData(): Could not show reference data: ", ex);
    1312            Tools.showError(shell, "Select", "Could not show reference data: " + ex.toString());
    1313        }
    1314    }
    1315
    1316    /**
    1317     * Display data pointed to by attribute references. Data of each object is shown in
    1318     * a separate spreadsheet.
    1319     *
    1320     * @param ref_obj_name
    1321     *            the string that contain the attribute reference information.
    1322     * @param ref_attr_name
    1323     *            the string that contain the attribute reference information.
    1324     *
    1325     */
    1326    @SuppressWarnings({ "rawtypes", "unchecked" })
    1327    protected void showAttrStdRefData(String ref_obj_name, String ref_attr_name) {
    1328        if (ref_obj_name == null || (ref_obj_name.length() <= 0) || (ref_obj_name.compareTo("NULL") == 0)) {
    1329            log.debug("showAttrStdRefData(): ref_obj_name is null or invalid");
    1330            Tools.showError(shell, "Select", "Could not show attribute reference data: invalid or null object name");
    1331            return;
    1332        }
    1333
    1334        if (ref_attr_name == null || (ref_attr_name.length() <= 0) || (ref_attr_name.compareTo("NULL") == 0)) {
    1335            log.debug("showAttrStdRefData(): ref_attr_name is null or invalid");
    1336            Tools.showError(shell, "Select", "Could not show attribute reference data: invalid or null attribute name");
    1337            return;
    1338        }
    1339
    1340        // find the parent object first
    1341        HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), ref_obj_name);
    1342        if (obj == null) {
    1343            log.debug("showAttrStdRefData(): obj is null");
    1344            Tools.showError(shell, "Select", "Could not show attribute reference data: invalid or null data");
    1345            return;
    1346        }
    1347        List<Attribute> attrs = H5File.getAttribute(obj);
    1348        if ((attrs == null) || (attrs.size() < 1)) {
    1349            log.debug("showAttrStdRefData(): attrs is null");
    1350            Tools.showError(shell, "Select", "Could not show attribute reference data: no attributes found");
    1351            return;
    1352        }
    1353        H5ScalarAttr attr = null;
    1354        H5ScalarAttr attrCopy = null;
    1355        int n = attrs.size();
    1356        for (int i = 0; i < n; i++) {
    1357            attr = (H5ScalarAttr)attrs.get(i);
    1358            if (attr.getAttributeName().equals(ref_attr_name))
    1359                break;
    1360            else
    1361                attr = null;
    1362        }
    1363
    1364        // create an instance of the Attribute constructor
    1365        Constructor<? extends H5ScalarAttr> constructor = null;
    1366        Object[] paramObj = null;
    1367        Object data = null;
    1368
    1369        try {
    1370            Class[] paramClass = { HObject.class, String.class, Datatype.class, long[].class };
    1371            constructor = attr.getClass().getConstructor(paramClass);
    1372            paramObj = new Object[] { obj, attr.getName(), attr.getDatatype(), null };
    1373            attrCopy = constructor.newInstance(paramObj);
    1374            data = attrCopy.getData();
    1375        }
    1376        catch (Exception ex) {
    1377            log.debug("showAttrStdRefData(): couldn't show data: ", ex);
    1378            Tools.showError(shell, "Select", "Attribute Reference: " + ex.getMessage());
    1379            data = null;
    1380        }
    1381
    1382        if (data == null)
    1383            return;
    1384
    1385        Class<?> theClass = null;
    1386        String viewName = null;
    1387
    1388        switch (viewType) {
    1389        case IMAGE:
    1390            viewName = HDFView.getListOfImageViews().get(0);
    1391            break;
    1392        case TABLE:
    1393            viewName = (String) HDFView.getListOfTableViews().get(0);
    1394            break;
    1395        default:
    1396            viewName = null;
    1397        }
    1398
    1399        try {
    1400            theClass = Class.forName(viewName);
    1401        }
    1402        catch (Exception ex) {
    1403            try {
    1404                theClass = ViewProperties.loadExtClass().loadClass(viewName);
    1405            }
    1406            catch (Exception ex2) {
    1407                theClass = null;
    1408            }
    1409        }
    1410
    1411        // Use default dataview
    1412        if (theClass == null) {
    1413            switch (viewType) {
    1414            case IMAGE:
    1415                viewName = ViewProperties.DEFAULT_IMAGEVIEW_NAME;
    1416                break;
    1417            case TABLE:
    1418                viewName = ViewProperties.DEFAULT_SCALAR_DATASET_TABLEVIEW_NAME;
    1419                break;
    1420            default:
    1421                viewName = null;
    1422            }
    1423
    1424            try {
    1425                theClass = Class.forName(viewName);
    1426            }
    1427            catch (Exception ex) {
    1428                log.debug("showAttrStdRefData(): no suitable display class found");
    1429                Tools.showError(shell, "Select", "Could not show reference data: no suitable display class found");
    1430                return;
    1431            }
    1432        }
    1433
    1434        HashMap map = new HashMap(1);
    1435        map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, attrCopy);
    1436        Object[] args = { viewer, map };
    1437
    1438        try {
    1439            Tools.newInstance(theClass, args);
    1440        }
    1441        catch (Exception ex) {
    1442            log.debug("showAttrStdRefData(): Could not show reference data: ", ex);
    1443            Tools.showError(shell, "Select", "Could not show reference data: " + ex.toString());
    1444        }
    1445    }
    1446
    1447    /**
    1448     * Update cell value label and cell value field when a cell is selected
    1449     */
    1450    private class ScalarDSCellSelectionListener implements ILayerListener
    1451    {
    1452        @Override
    1453        public void handleLayerEvent(ILayerEvent e) {
    1454            if (e instanceof CellSelectionEvent) {
    1455                CellSelectionEvent event = (CellSelectionEvent) e;
    1456                Object val = dataTable.getDataValueByPosition(event.getColumnPosition(), event.getRowPosition());
    1457                String strVal = null;
    1458
    1459                String[] columnNames = ((ScalarDSColumnHeaderDataProvider) columnHeaderDataProvider).columnNames;
    1460                int rowStart = ((RowHeaderDataProvider) rowHeaderDataProvider).start;
    1461                int rowStride = ((RowHeaderDataProvider) rowHeaderDataProvider).stride;
    1462
    1463                cellLabel.setText(String.valueOf(
    1464                        rowStart + indexBase + dataTable.getRowIndexByPosition(event.getRowPosition()) * rowStride)
    1465                        + ", " + columnNames[dataTable.getColumnIndexByPosition(event.getColumnPosition())] + "  =  ");
    1466
    1467                if (val == null) {
    1468                    cellValueField.setText("Null");
    1469                    ((ScrolledComposite) cellValueField.getParent()).setMinSize(cellValueField.computeSize(SWT.DEFAULT, SWT.DEFAULT));
    1470                    return;
    1471                }
    1472
    1473                if (isStdRef) {
    1474                    boolean displayValues = ViewProperties.showRegRefValues();
    1475
    1476                    if (displayValues && val != null && !(val instanceof String)) {//((String) val).compareTo("NULL") != 0) {
    1477                        strVal = ((H5ReferenceType) dataObject.getDatatype()).getReferenceRegion((byte[])val, true);
    1478                    }
    1479                }
    1480                else if (isRegRef) {
    1481                    boolean displayValues = ViewProperties.showRegRefValues();
    1482
    1483                    if (displayValues && val != null && ((String) val).compareTo("NULL") != 0) {
    1484                        String reg = (String) val;
    1485                        boolean isPointSelection = (reg.indexOf('-') <= 0);
    1486
    1487                        // find the object location
    1488                        String oidStr = reg.substring(reg.indexOf('/'), reg.indexOf(' '));
    1489
    1490                        // decode the region selection
    1491                        String regStr = reg.substring(reg.indexOf('{') + 1, reg.indexOf('}'));
    1492
    1493                        // no selection
    1494                        if (regStr == null || regStr.length() <= 0) {
    1495                            log.debug("ScalarDSCellSelectionListener:RegRef CellSelected: no selection made");
    1496                            strVal = null;
    1497                        }
    1498                        else {
    1499                            // TODO: do we need to do something with what's past the closing bracket
    1500                            // regStr = reg.substring(reg.indexOf('}') + 1);
    1501
    1502                            StringTokenizer st = new StringTokenizer(regStr);
    1503                            int nSelections = st.countTokens();
    1504                            if (nSelections <= 0) { // no selection
    1505                                strVal = null;
    1506                            }
    1507                            else {
    1508                                HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), oidStr);
    1509                                if (obj == null || !(obj instanceof ScalarDS)) { // no selection
    1510                                    strVal = null;
    1511                                }
    1512                                else {
    1513                                    ScalarDS dset = (ScalarDS) obj;
    1514                                    try {
    1515                                        dset.init();
    1516                                    }
    1517                                    catch (Exception ex) {
    1518                                        log.debug("ScalarDSCellSelectionListener:RegRef CellSelected: reference dset did not init()", ex);
    1519                                    }
    1520                                    StringBuilder strvalSB = new StringBuilder();
    1521
    1522                                    int idx = 0;
    1523                                    while (st.hasMoreTokens()) {
    1524                                        int space_type = dset.getSpaceType();
    1525                                        int rank = dset.getRank();
    1526                                        long[] start = dset.getStartDims();
    1527                                        long[] count = dset.getSelectedDims();
    1528                                        // long count[] = new long[rank];
    1529
    1530                                        // set the selected dimension sizes
    1531                                        // based on the region selection
    1532                                        // info.
    1533                                        String sizeStr = null;
    1534                                        String token = st.nextToken();
    1535
    1536                                        token = token.replace('(', ' ');
    1537                                        token = token.replace(')', ' ');
    1538                                        if (isPointSelection) {
    1539                                            // point selection
    1540                                            String[] tmp = token.split(",");
    1541                                            for (int x = 0; x < tmp.length; x++) {
    1542                                                count[x] = 1;
    1543                                                sizeStr = tmp[x].trim();
    1544                                                start[x] = Long.valueOf(sizeStr);
    1545                                                log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: point sel={}", tmp[x]);
    1546                                            }
    1547                                        }
    1548                                        else {
    1549                                            // rectangle selection
    1550                                            String startStr = token.substring(0, token.indexOf('-'));
    1551                                            String endStr = token.substring(token.indexOf('-') + 1);
    1552                                            log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: rect sel with startStr={} endStr={}",
    1553                                                    startStr, endStr);
    1554                                            String[] tmp = startStr.split(",");
    1555                                            log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: tmp with length={} rank={}",
    1556                                                    tmp.length, rank);
    1557                                            for (int x = 0; x < tmp.length; x++) {
    1558                                                sizeStr = tmp[x].trim();
    1559                                                start[x] = Long.valueOf(sizeStr);
    1560                                                log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: rect start={}",
    1561                                                        tmp[x]);
    1562                                            }
    1563                                            tmp = endStr.split(",");
    1564                                            for (int x = 0; x < tmp.length; x++) {
    1565                                                sizeStr = tmp[x].trim();
    1566                                                count[x] = Long.valueOf(sizeStr) - start[x] + 1;
    1567                                                log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: rect end={} count={}",
    1568                                                        tmp[x], count[x]);
    1569                                            }
    1570                                        }
    1571
    1572                                        Object dbuf = null;
    1573                                        try {
    1574                                            dbuf = dset.getData();
    1575                                        }
    1576                                        catch (Exception ex) {
    1577                                            Tools.showError(shell, "Select", "Region Reference:" +ex.getMessage());
    1578                                        }
    1579
    1580                                        /* Convert dbuf to a displayable string */
    1581                                        char runtimeTypeClass = Utils.getJavaObjectRuntimeClass(dbuf);
    1582                                        log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: cName={} runtimeTypeClass={}",
    1583                                                dbuf.getClass().getName(), runtimeTypeClass);
    1584
    1585                                        if (idx > 0) strvalSB.append(',');
    1586
    1587                                        // convert numerical data into char
    1588                                        // only possible cases are byte[]
    1589                                        // and short[] (converted from
    1590                                        // unsigned byte)
    1591                                        Datatype dtype = dset.getDatatype();
    1592                                        Datatype baseType = dtype.getDatatypeBase();
    1593                                        log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: dtype={} baseType={}",
    1594                                                dtype.getDescription(), baseType);
    1595                                        if (baseType == null)
    1596                                            baseType = dtype;
    1597                                        if ((dtype.isArray() && baseType.isChar())
    1598                                                && ((runtimeTypeClass == 'B') || (runtimeTypeClass == 'S'))) {
    1599                                            int n = Array.getLength(dbuf);
    1600                                            log.trace("ScalarDSCellSelectionListener:RegRef CellSelected charData length = {}", n);
    1601                                            char[] charData = new char[n];
    1602                                            for (int i = 0; i < n; i++) {
    1603                                                if (runtimeTypeClass == 'B') {
    1604                                                    charData[i] = (char) Array.getByte(dbuf, i);
    1605                                                }
    1606                                                else if (runtimeTypeClass == 'S') {
    1607                                                    charData[i] = (char) Array.getShort(dbuf, i);
    1608                                                }
    1609                                            }
    1610
    1611                                            strvalSB.append(charData);
    1612                                        }
    1613                                        else {
    1614                                            // numerical values
    1615                                            boolean isUnsigned = dtype.isUnsigned();
    1616                                            if (dtype.isArray())
    1617                                                isUnsigned = baseType.isUnsigned();
    1618                                            int n = Array.getLength(dbuf);
    1619                                            if (isUnsigned) {
    1620                                                switch (runtimeTypeClass) {
    1621                                                case 'B':
    1622                                                    byte[] barray = (byte[]) dbuf;
    1623                                                    short sValue = barray[0];
    1624                                                    if (sValue < 0) {
    1625                                                        sValue += 256;
    1626                                                    }
    1627                                                    strvalSB.append(sValue);
    1628                                                    for (int i = 1; i < n; i++) {
    1629                                                        strvalSB.append(',');
    1630                                                        sValue = barray[i];
    1631                                                        if (sValue < 0) {
    1632                                                            sValue += 256;
    1633                                                        }
    1634                                                        strvalSB.append(sValue);
    1635                                                    }
    1636                                                    break;
    1637                                                case 'S':
    1638                                                    short[] sarray = (short[]) dbuf;
    1639                                                    int iValue = sarray[0];
    1640                                                    if (iValue < 0) {
    1641                                                        iValue += 65536;
    1642                                                    }
    1643                                                    strvalSB.append(iValue);
    1644                                                    for (int i = 1; i < n; i++) {
    1645                                                        strvalSB.append(',');
    1646                                                        iValue = sarray[i];
    1647                                                        if (iValue < 0) {
    1648                                                            iValue += 65536;
    1649                                                        }
    1650                                                        strvalSB.append(iValue);
    1651                                                    }
    1652                                                    break;
    1653                                                case 'I':
    1654                                                    int[] iarray = (int[]) dbuf;
    1655                                                    long lValue = iarray[0];
    1656                                                    if (lValue < 0) {
    1657                                                        lValue += 4294967296L;
    1658                                                    }
    1659                                                    strvalSB.append(lValue);
    1660                                                    for (int i = 1; i < n; i++) {
    1661                                                        strvalSB.append(',');
    1662                                                        lValue = iarray[i];
    1663                                                        if (lValue < 0) {
    1664                                                            lValue += 4294967296L;
    1665                                                        }
    1666                                                        strvalSB.append(lValue);
    1667                                                    }
    1668                                                    break;
    1669                                                case 'J':
    1670                                                    long[] larray = (long[]) dbuf;
    1671                                                    Long l = larray[0];
    1672                                                    String theValue = Long.toString(l);
    1673                                                    if (l < 0) {
    1674                                                        l = (l << 1) >>> 1;
    1675                                                        BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65
    1676                                                        BigInteger big2 = new BigInteger(l.toString());
    1677                                                        BigInteger big = big1.add(big2);
    1678                                                        theValue = big.toString();
    1679                                                    }
    1680                                                    strvalSB.append(theValue);
    1681                                                    for (int i = 1; i < n; i++) {
    1682                                                        strvalSB.append(',');
    1683                                                        l = larray[i];
    1684                                                        theValue = Long.toString(l);
    1685                                                        if (l < 0) {
    1686                                                            l = (l << 1) >>> 1;
    1687                                                            BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65
    1688                                                            BigInteger big2 = new BigInteger(l.toString());
    1689                                                            BigInteger big = big1.add(big2);
    1690                                                            theValue = big.toString();
    1691                                                        }
    1692                                                        strvalSB.append(theValue);
    1693                                                    }
    1694                                                    break;
    1695                                                default:
    1696                                                    strvalSB.append(Array.get(dbuf, 0));
    1697                                                    for (int i = 1; i < n; i++) {
    1698                                                        strvalSB.append(',');
    1699                                                        strvalSB.append(Array.get(dbuf, i));
    1700                                                    }
    1701                                                    break;
    1702                                                }
    1703                                            }
    1704                                            else {
    1705                                                for (int x = 0; x < n; x++) {
    1706                                                    Object theValue = Array.get(dbuf, x);
    1707                                                    if (x > 0) strvalSB.append(',');
    1708                                                    strvalSB.append(theValue);
    1709                                                }
    1710                                            }
    1711                                        }
    1712                                        idx++;
    1713                                        dset.clearData();
    1714                                    } // (st.hasMoreTokens())
    1715                                    strVal = strvalSB.toString();
    1716                                }
    1717                            }
    1718                        }
    1719                    }
    1720                    else {
    1721                        strVal = null;
    1722                    }
    1723                }
    1724                else if (isObjRef) {
    1725                    if (val != null && ((String) val).compareTo("NULL") != 0) {
    1726                        strVal = (String) val;
    1727                    }
    1728                    else {
    1729                        strVal = null;
    1730                    }
    1731                }
    1732
    1733                if (strVal == null && val != null)
    1734                    strVal = dataDisplayConverter.canonicalToDisplayValue(val).toString();
    1735
    1736                cellValueField.setText(strVal);
    1737                ((ScrolledComposite) cellValueField.getParent()).setMinSize(cellValueField.computeSize(SWT.DEFAULT, SWT.DEFAULT));
    1738            }
    1739        }
    1740    }
    1741
    1742    /**
    1743     * Custom Column Header data provider to set column indices based on Index Base
    1744     * for Scalar Datasets.
    1745     */
    1746    private class ScalarDSColumnHeaderDataProvider implements IDataProvider
    1747    {
    1748        private final String columnNames[];
    1749
    1750        private final int    space_type;
    1751        private final int    rank;
    1752
    1753        private final long[] startArray;
    1754        private final long[] strideArray;
    1755        private final int[]  selectedIndex;
    1756
    1757        private final int    ncols;
    1758
    1759        public ScalarDSColumnHeaderDataProvider(DataFormat theDataObject) {
    1760            space_type = theDataObject.getSpaceType();
    1761            rank = theDataObject.getRank();
    1762
    1763            startArray = theDataObject.getStartDims();
    1764            strideArray = theDataObject.getStride();
    1765            selectedIndex = theDataObject.getSelectedIndex();
    1766
    1767            if (rank > 1) {
    1768                ncols = (int) theDataObject.getWidth();
    1769
    1770                int start = (int) startArray[selectedIndex[1]];
    1771                int stride = (int) strideArray[selectedIndex[1]];
    1772
    1773                columnNames = new String[ncols];
    1774
    1775                for (int i = 0; i < ncols; i++)
    1776                    columnNames[i] = String.valueOf(start + indexBase + i * stride);
    1777            }
    1778            else {
    1779                ncols = 1;
    1780
    1781                columnNames = new String[] { "  " };
    1782            }
    1783        }
    1784
    1785        @Override
    1786        public int getColumnCount() {
    1787            return ncols;
    1788        }
    1789
    1790        @Override
    1791        public int getRowCount() {
    1792            return 1;
    1793        }
    1794
    1795        @Override
    1796        public Object getDataValue(int columnIndex, int rowIndex) {
    1797            return columnNames[columnIndex];
    1798        }
    1799
    1800        @Override
    1801        public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
    1802            // intentional
    1803        }
    1804    }
    1805}