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