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