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}