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 http://hdfgroup.org/products/hdf-java/doc/Copyright.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;
016
017import hdf.hdf5lib.H5;
018import hdf.hdf5lib.exceptions.HDF5Exception;
019import hdf.object.CompoundDS;
020import hdf.object.Dataset;
021import hdf.object.Datatype;
022import hdf.object.FileFormat;
023import hdf.object.Group;
024import hdf.object.HObject;
025import hdf.object.ScalarDS;
026import hdf.object.h5.H5Datatype;
027import hdf.view.ViewProperties.BITMASK_OP;
028import java.awt.BorderLayout;
029import java.awt.Color;
030import java.awt.Component;
031import java.awt.Cursor;
032import java.awt.Dimension;
033import java.awt.GridLayout;
034import java.awt.Insets;
035import java.awt.Point;
036import java.awt.Toolkit;
037import java.awt.datatransfer.Clipboard;
038import java.awt.datatransfer.DataFlavor;
039import java.awt.datatransfer.StringSelection;
040import java.awt.event.ActionEvent;
041import java.awt.event.ActionListener;
042import java.awt.event.InputEvent;
043import java.awt.event.ItemEvent;
044import java.awt.event.ItemListener;
045import java.awt.event.KeyEvent;
046import java.awt.event.MouseEvent;
047import java.awt.event.MouseListener;
048import java.io.BufferedInputStream;
049import java.io.BufferedReader;
050import java.io.BufferedWriter;
051import java.io.DataOutputStream;
052import java.io.File;
053import java.io.FileInputStream;
054import java.io.FileNotFoundException;
055import java.io.FileOutputStream;
056import java.io.FileReader;
057import java.io.FileWriter;
058import java.io.IOException;
059import java.io.PrintWriter;
060import java.io.StringReader;
061import java.lang.reflect.Array;
062import java.lang.reflect.Constructor;
063import java.math.BigInteger;
064import java.nio.ByteBuffer;
065import java.nio.ByteOrder;
066import java.nio.DoubleBuffer;
067import java.nio.FloatBuffer;
068import java.nio.IntBuffer;
069import java.nio.LongBuffer;
070import java.nio.ShortBuffer;
071import java.text.DecimalFormat;
072import java.text.NumberFormat;
073import java.util.BitSet;
074import java.util.Enumeration;
075import java.util.HashMap;
076import java.util.Iterator;
077import java.util.List;
078import java.util.StringTokenizer;
079import java.util.Vector;
080import javax.swing.BorderFactory;
081import javax.swing.ButtonGroup;
082import javax.swing.CellEditor;
083import javax.swing.JButton;
084import javax.swing.JCheckBoxMenuItem;
085import javax.swing.JComboBox;
086import javax.swing.JComponent;
087import javax.swing.JDialog;
088import javax.swing.JFileChooser;
089import javax.swing.JFrame;
090import javax.swing.JInternalFrame;
091import javax.swing.JLabel;
092import javax.swing.JList;
093import javax.swing.JMenu;
094import javax.swing.JMenuBar;
095import javax.swing.JMenuItem;
096import javax.swing.JOptionPane;
097import javax.swing.JPanel;
098import javax.swing.JPopupMenu;
099import javax.swing.JRadioButton;
100import javax.swing.JScrollPane;
101import javax.swing.JSplitPane;
102import javax.swing.JTable;
103import javax.swing.JTextArea;
104import javax.swing.JTextField;
105import javax.swing.JViewport;
106import javax.swing.KeyStroke;
107import javax.swing.SwingConstants;
108import javax.swing.UIManager;
109import javax.swing.WindowConstants;
110import javax.swing.border.Border;
111import javax.swing.border.CompoundBorder;
112import javax.swing.border.EtchedBorder;
113import javax.swing.border.LineBorder;
114import javax.swing.border.MatteBorder;
115import javax.swing.border.TitledBorder;
116import javax.swing.event.ChangeEvent;
117import javax.swing.event.ListSelectionEvent;
118import javax.swing.table.AbstractTableModel;
119import javax.swing.table.JTableHeader;
120import javax.swing.table.TableCellRenderer;
121import javax.swing.table.TableColumn;
122import javax.swing.tree.DefaultMutableTreeNode;
123import javax.swing.tree.TreeNode;
124
125/**
126 * TableView displays an HDF dataset as a two-dimensional table.
127 */
128public class DefaultTableView extends JInternalFrame implements TableView, ActionListener, MouseListener {
129    private static final long             serialVersionUID = -7452459299532863847L;
130
131    private final static org.slf4j.Logger log              = org.slf4j.LoggerFactory.getLogger(DefaultTableView.class);
132
133    /**
134     * The main HDFView.
135     */
136    private final ViewManager             viewer;
137
138    /**
139     * Numerical data type. B = byte array, S = short array, I = int array, J = long array, F =
140     * float array, and D = double array.
141     */
142    private char                          NT               = ' ';
143
144    /**
145     * The Scalar Dataset.
146     */
147    private Dataset                       dataset;
148
149    /**
150     * The value of the dataset.
151     */
152    private Object                        dataValue;
153
154    /**
155     * The table used to hold the table data.
156     */
157    private JTable                        table;
158
159    /** Label to indicate the current cell location. */
160    private JLabel                        cellLabel;
161
162    /** Text field to display the value of of the current cell. */
163    private JTextArea                     cellValueField;
164
165    private boolean                       isValueChanged;
166
167    private final Toolkit                 toolkit;
168
169    private boolean                       isReadOnly;
170
171    private boolean                       isDisplayTypeChar;
172
173    private boolean                       isDataTransposed;
174
175    private boolean                       isRegRef;
176    private boolean                       isObjRef;
177
178    private final JCheckBoxMenuItem       checkFixedDataLength;
179    private int                           fixedDataLength;
180    private final JCheckBoxMenuItem       checkCustomNotation;
181    private final JCheckBoxMenuItem       checkScientificNotation;
182    private final JCheckBoxMenuItem       checkHex;
183    private final JCheckBoxMenuItem       checkBin;
184
185    // changed to use normalized scientific notation (1 <= coefficient < 10).
186    // private final DecimalFormat scientificFormat = new DecimalFormat("###.#####E0#");
187    private final DecimalFormat           scientificFormat = new DecimalFormat("0.0###E0###");
188    private DecimalFormat                 customFormat     = new DecimalFormat("###.#####");
189    private final NumberFormat            normalFormat     = null;                                                     // NumberFormat.getInstance();
190    private NumberFormat                  numberFormat     = normalFormat;
191    private boolean                       showAsHex        = false, showAsBin = false;
192    private final boolean                 startEditing[]   = { false };
193    private JPopupMenu                    popupMenu;
194
195    private enum ViewType {
196        TABLE, IMAGE, TEXT
197    }
198
199    private ViewType         viewType;
200
201    private JTextField       frameField;
202
203    private long             curFrame                = 0;
204    private long             maxFrame                = 1;
205
206    private Object           fillValue               = null;
207
208    private BitSet           bitmask;
209
210    private BITMASK_OP       bitmaskOP               = BITMASK_OP.EXTRACT;
211
212    private int              binaryOrder;
213
214    private int              indexBase               = 0;
215
216    private static final int FLOAT_BUFFER_SIZE       = 524288;
217
218    private static final int INT_BUFFER_SIZE         = 524288;
219
220    private static final int SHORT_BUFFER_SIZE       = 1048576;
221
222    private static final int LONG_BUFFER_SIZE        = 262144;
223
224    private static final int DOUBLE_BUFFER_SIZE      = 262144;
225
226    private static final int BYTE_BUFFER_SIZE        = 2097152;
227
228    /* the value of the current cell value in editing. */
229    private Object           currentEditingCellValue = null;
230
231    /**
232     * Constructs an TableView.
233     * <p>
234     *
235     * @param theView
236     *            the main HDFView.
237     */
238    public DefaultTableView(ViewManager theView) {
239        this(theView, null);
240    }
241
242    /**
243     * Constructs an TableView.
244     * <p>
245     *
246     * @param theView
247     *            the main HDFView.
248     * @param map
249     *            the properties on how to show the data. The map is used to allow applications to
250     *            pass properties on how to display the data, such as, transposing data, showing
251     *            data as character, applying bitmask, and etc. Predefined keys are listed at
252     *            ViewProperties.DATA_VIEW_KEY.
253     */
254    public DefaultTableView(ViewManager theView, HashMap map) {
255        super();
256
257        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
258        log.trace("DefaultTableView start");
259
260        viewer = theView;
261        toolkit = Toolkit.getDefaultToolkit();
262        isValueChanged = false;
263        isReadOnly = false;
264        isRegRef = false;
265        isObjRef = false;
266        viewType = ViewType.TABLE;
267        fixedDataLength = -1;
268        HObject hobject = null;
269        popupMenu = null;
270        bitmask = null;
271
272        if (ViewProperties.isIndexBase1()) indexBase = 1;
273        log.trace("isIndexBase1() is {}", indexBase);
274
275        checkFixedDataLength = new JCheckBoxMenuItem("Fixed Data Length", false);
276        checkCustomNotation = new JCheckBoxMenuItem("Show Custom Notation", false);
277        checkScientificNotation = new JCheckBoxMenuItem("Show Scientific Notation", false);
278        checkHex = new JCheckBoxMenuItem("Show Hexadecimal", false);
279        checkBin = new JCheckBoxMenuItem("Show Binary", false);
280
281        if (map != null) {
282            hobject = (HObject) map.get(ViewProperties.DATA_VIEW_KEY.OBJECT);
283
284            bitmask = (BitSet) map.get(ViewProperties.DATA_VIEW_KEY.BITMASK);
285            bitmaskOP = (BITMASK_OP) map.get(ViewProperties.DATA_VIEW_KEY.BITMASKOP);
286
287            Boolean b = (Boolean) map.get(ViewProperties.DATA_VIEW_KEY.CHAR);
288            if (b != null) isDisplayTypeChar = b.booleanValue();
289
290            b = (Boolean) map.get(ViewProperties.DATA_VIEW_KEY.TRANSPOSED);
291            if (b != null) isDataTransposed = b.booleanValue();
292
293            b = (Boolean) map.get(ViewProperties.DATA_VIEW_KEY.INDEXBASE1);
294            if (b != null) {
295                if (b.booleanValue())
296                    indexBase = 1;
297                else
298                    indexBase = 0;
299            }
300        }
301        log.trace("isIndexBase={} - isDataTransposed={} - isDisplayTypeChar={}", indexBase, isDataTransposed, isDisplayTypeChar);
302
303        if (hobject == null) hobject = viewer.getTreeView().getCurrentObject();
304
305        if ((hobject == null) || !(hobject instanceof Dataset)) {
306            return;
307        }
308
309        dataset = (Dataset) hobject;
310        isReadOnly = dataset.getFileFormat().isReadOnly();
311        log.trace("dataset({}) isReadOnly={}", dataset, isReadOnly);
312
313        long[] dims = dataset.getDims();
314        long tsize = 1;
315
316        for (int i = 0; i < dims.length; i++)
317            tsize *= dims[i];
318
319        log.trace("dataset size={} Height={} Width={}", tsize, dataset.getHeight(), dataset.getWidth());
320        if (dataset.getHeight() <= 0 || dataset.getWidth() <= 0 || tsize <= 0) {
321            JOptionPane.showMessageDialog(this, "Could not open dataset '" + dataset.getName() + "'. Dataset has dimension of size 0.");
322            return;
323        }
324
325        // cannot edit hdf4 vdata
326        if (dataset.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4))
327                && (dataset instanceof CompoundDS)) {
328            isReadOnly = true;
329        }
330
331        // disable edit feature for szip compression when encode is not enabled
332        if (!isReadOnly) {
333            String compression = dataset.getCompression();
334            if ((compression != null) && compression.startsWith("SZIP")) {
335                if (!compression.endsWith("ENCODE_ENABLED")) {
336                    isReadOnly = true;
337                }
338            }
339        }
340
341        Datatype dtype = dataset.getDatatype();
342        log.trace("dataset dtype.getDatatypeClass()={}", dtype.getDatatypeClass());
343        isDisplayTypeChar = (isDisplayTypeChar && (dtype.getDatatypeSize() == 1 || (dtype.getDatatypeClass() == Datatype.CLASS_ARRAY && dtype
344                .getBasetype().getDatatypeClass() == Datatype.CLASS_CHAR)));
345
346        log.trace("dataset isDisplayTypeChar={} isConvertEnum={}", isDisplayTypeChar, ViewProperties.isConvertEnum());
347        dataset.setEnumConverted(ViewProperties.isConvertEnum());
348
349        // set title & border
350        TitledBorder border = BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.lightGray, 1), indexBase
351                + "-based",
352                TitledBorder.RIGHT, TitledBorder.TOP, this.getFont(), Color.black);
353        ((JPanel) getContentPane()).setBorder(border);
354
355        // create the table and its columnHeader
356        if (dataset instanceof CompoundDS) {
357            isDataTransposed = false; // disable transpose for compound dataset
358            this.setFrameIcon(ViewProperties.getTableIcon());
359            table = createTable((CompoundDS) dataset);
360        }
361        else { /* if (dataset instanceof ScalarDS) */
362            this.setFrameIcon(ViewProperties.getDatasetIcon());
363            table = createTable((ScalarDS) dataset);
364            log.trace("createTable((ScalarDS) dataset) dtype.getDatatypeClass()={}", dtype.getDatatypeClass());
365
366            if (dtype.getDatatypeClass() == Datatype.CLASS_REFERENCE) {
367                table.addMouseListener(this);
368
369                if (dtype.getDatatypeSize() > 8) {
370                    isReadOnly = true;
371                    isRegRef = true;
372                }
373                else
374                    isObjRef = true;
375            }
376            else if ((dtype.getDatatypeClass() == Datatype.CLASS_BITFIELD) || (dtype.getDatatypeClass() == Datatype.CLASS_OPAQUE)) {
377                showAsHex = true;
378                checkHex.setSelected(true);
379                checkScientificNotation.setSelected(false);
380                checkCustomNotation.setSelected(false);
381                checkBin.setSelected(false);
382                showAsBin = false;
383                numberFormat = normalFormat;
384            }
385            log.trace("createTable((ScalarDS) dataset) isRegRef={} isObjRef={} showAsHex={}", isRegRef, isObjRef, showAsHex);
386        }
387
388        if (table == null) {
389            viewer.showStatus("Creating table failed - " + dataset.getName());
390            dataset = null;
391            super.dispose();
392            return;
393        }
394        table.setName("data");
395
396        log.trace("DefaultTableView create ColumnHeader");
397        ColumnHeader columnHeaders = new ColumnHeader(table);
398        columnHeaders.setName("columnHeaders");
399        table.setTableHeader(columnHeaders);
400        table.setCellSelectionEnabled(true);
401        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
402        table.setGridColor(Color.gray);
403
404        // add the table to a scroller
405        JScrollPane scrollingTable = new JScrollPane(table);
406        scrollingTable.getVerticalScrollBar().setUnitIncrement(100);
407        scrollingTable.getHorizontalScrollBar().setUnitIncrement(100);
408
409        // create row headers and add it to the scroller
410        log.trace("DefaultTableView create RowHeader");
411        RowHeader rowHeaders = new RowHeader(table, dataset);
412        rowHeaders.setName("rowHeaders");
413
414        JViewport viewp = new JViewport();
415        viewp.add(rowHeaders);
416        viewp.setPreferredSize(rowHeaders.getPreferredSize());
417        scrollingTable.setRowHeader(viewp);
418
419        cellLabel = new JLabel("");
420        cellLabel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
421        Dimension dim = cellLabel.getPreferredSize();
422        dim.width = 75;
423        cellLabel.setPreferredSize(dim);
424        cellLabel.setHorizontalAlignment(SwingConstants.RIGHT);
425
426        cellValueField = new JTextArea();
427        cellValueField.setLineWrap(true);
428        cellValueField.setWrapStyleWord(true);
429        cellValueField.setEditable(false);
430        cellValueField.setBackground(new Color(255, 255, 240));
431
432        JScrollPane scrollingcellValue = new JScrollPane(cellValueField);
433        scrollingcellValue.getVerticalScrollBar().setUnitIncrement(50);
434        scrollingcellValue.getHorizontalScrollBar().setUnitIncrement(50);
435
436        JPanel valuePane = new JPanel();
437        valuePane.setLayout(new BorderLayout());
438        valuePane.add(cellLabel, BorderLayout.WEST);
439        valuePane.add(scrollingcellValue, BorderLayout.CENTER);
440
441        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, valuePane, scrollingTable);
442        splitPane.setDividerLocation(25);
443        JPanel contentPane = (JPanel) getContentPane();
444        contentPane.add(splitPane);
445
446        StringBuffer sb = new StringBuffer(hobject.getName());
447        sb.append("  at  ");
448        sb.append(hobject.getPath());
449        sb.append("  [");
450        sb.append(dataset.getFileFormat().getName());
451        sb.append("  in  ");
452        sb.append(dataset.getFileFormat().getParent());
453        sb.append("]");
454        setTitle(sb.toString());
455
456        // setup subset information
457        log.trace("DefaultTableView setup subset information");
458        int rank = dataset.getRank();
459        int[] selectedIndex = dataset.getSelectedIndex();
460        long[] count = dataset.getSelectedDims();
461        long[] stride = dataset.getStride();
462        // long[] dims = dataset.getDims();
463        long[] start = dataset.getStartDims();
464        int n = Math.min(3, rank);
465        if (rank > 2) {
466            curFrame = start[selectedIndex[2]] + indexBase;
467            maxFrame = dims[selectedIndex[2]];
468        }
469
470        sb.append(" [ dims");
471        sb.append(selectedIndex[0]);
472        for (int i = 1; i < n; i++) {
473            sb.append("x");
474            sb.append(selectedIndex[i]);
475        }
476        sb.append(", start");
477        sb.append(start[selectedIndex[0]]);
478        for (int i = 1; i < n; i++) {
479            sb.append("x");
480            sb.append(start[selectedIndex[i]]);
481        }
482        sb.append(", count");
483        sb.append(count[selectedIndex[0]]);
484        for (int i = 1; i < n; i++) {
485            sb.append("x");
486            sb.append(count[selectedIndex[i]]);
487        }
488        sb.append(", stride");
489        sb.append(stride[selectedIndex[0]]);
490        for (int i = 1; i < n; i++) {
491            sb.append("x");
492            sb.append(stride[selectedIndex[i]]);
493        }
494        sb.append(" ] ");
495        log.trace("DefaultTableView subset={}", sb.toString());
496
497        setJMenuBar(createMenuBar());
498        viewer.showStatus(sb.toString());
499
500        // set cell height for large fonts
501        int cellRowHeight = table.getFontMetrics(table.getFont()).getHeight();
502        rowHeaders.setRowHeight(cellRowHeight);
503        table.setRowHeight(cellRowHeight);
504
505        // create popup menu for reg. ref.
506        if (isRegRef || isObjRef) popupMenu = createPopupMenu();
507        log.trace("DefaultTableView finish");
508    }
509
510    private JMenuBar createMenuBar ( ) {
511        JMenuBar bar = new JMenuBar();
512        JButton button;
513        boolean isEditable = !isReadOnly;
514        boolean is3D = (dataset.getRank() > 2);
515
516        JMenu menu = new JMenu("Table", false);
517        menu.setMnemonic('T');
518        bar.add(menu);
519
520        JMenuItem item = new JMenuItem("Export Data to Text File");
521        item.addActionListener(this);
522        item.setActionCommand("Save table as text");
523        menu.add(item);
524
525        JMenu exportAsBinaryMenu = new JMenu("Export Data to Binary File");
526        if ((dataset instanceof ScalarDS)) {
527            menu.add(exportAsBinaryMenu);
528        }
529        item = new JMenuItem("Native Order");
530        item.addActionListener(this);
531        item.setActionCommand("Save table as binary Native Order");
532        exportAsBinaryMenu.add(item);
533        item = new JMenuItem("Little Endian");
534        item.addActionListener(this);
535        item.setActionCommand("Save table as binary Little Endian");
536        exportAsBinaryMenu.add(item);
537        item = new JMenuItem("Big Endian");
538        item.addActionListener(this);
539        item.setActionCommand("Save table as binary Big Endian");
540        exportAsBinaryMenu.add(item);
541
542        menu.addSeparator();
543
544        item = new JMenuItem("Import Data from Text File");
545        item.addActionListener(this);
546        item.setActionCommand("Import data from file");
547        item.setEnabled(isEditable);
548        menu.add(item);
549
550        item = checkFixedDataLength;
551        item.addActionListener(this);
552        item.setActionCommand("Fixed data length");
553        if (dataset instanceof ScalarDS) {
554            menu.add(item);
555        }
556
557        JMenu importFromBinaryMenu = new JMenu("Import Data from Binary File");
558        if ((dataset instanceof ScalarDS)) {
559            menu.add(importFromBinaryMenu);
560        }
561        item = new JMenuItem("Native Order");
562        item.addActionListener(this);
563        item.setActionCommand("Order as Native Order");
564        importFromBinaryMenu.add(item);
565        item = new JMenuItem("Little Endian");
566        item.addActionListener(this);
567        item.setActionCommand("Order as Little Endian");
568        importFromBinaryMenu.add(item);
569        item = new JMenuItem("Big Endian");
570        item.addActionListener(this);
571        item.setActionCommand("Order as Big Endian");
572        importFromBinaryMenu.add(item);
573
574        menu.addSeparator();
575
576        item = new JMenuItem("Copy");
577        item.addActionListener(this);
578        item.setActionCommand("Copy data");
579        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), true));
580        menu.add(item);
581
582        item = new JMenuItem("Paste");
583        item.addActionListener(this);
584        item.setActionCommand("Paste data");
585        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), true));
586        item.setEnabled(isEditable);
587        menu.add(item);
588
589        menu.addSeparator();
590
591        item = new JMenuItem("Copy to New Dataset");
592        item.addActionListener(this);
593        item.setActionCommand("Write selection to dataset");
594        item.setEnabled(isEditable && (dataset instanceof ScalarDS));
595        menu.add(item);
596
597        item = new JMenuItem("Save Changes to File");
598        item.addActionListener(this);
599        item.setActionCommand("Save dataset");
600        item.setEnabled(isEditable);
601        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), true));
602        menu.add(item);
603
604        menu.addSeparator();
605
606        item = new JMenuItem("Select All");
607        item.addActionListener(this);
608        item.setActionCommand("Select all data");
609        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), true));
610        menu.add(item);
611
612        menu.addSeparator();
613
614        item = new JMenuItem("Show Lineplot");
615        item.addActionListener(this);
616        item.setActionCommand("Show chart");
617        menu.add(item);
618
619        item = new JMenuItem("Show Statistics");
620        item.addActionListener(this);
621        item.setActionCommand("Show statistics");
622        menu.add(item);
623
624        menu.addSeparator();
625
626        item = new JMenuItem("Math Conversion");
627        item.addActionListener(this);
628        item.setActionCommand("Math conversion");
629        item.setEnabled(isEditable);
630        menu.add(item);
631
632        menu.addSeparator();
633
634        item = checkScientificNotation;
635        item.addActionListener(this);
636        item.setActionCommand("Show scientific notation");
637        if (dataset instanceof ScalarDS) {
638            menu.add(item);
639        }
640
641        item = checkCustomNotation;
642        item.addActionListener(this);
643        item.setActionCommand("Show custom notation");
644        if (dataset instanceof ScalarDS) {
645            menu.add(item);
646        }
647
648        item = new JMenuItem("Create custom notation");
649        item.addActionListener(this);
650        item.setActionCommand("Create custom notation");
651        menu.add(item);
652
653        boolean isInt = (NT == 'B' || NT == 'S' || NT == 'I' || NT == 'J');
654        // this will allow disabling of hex and binary display menu options
655        // boolean isUINT64 = (dataset.getDatatype().isUnsigned() && (NT == 'J'));
656        item = checkHex;
657        item.addActionListener(this);
658        item.setActionCommand("Show hexadecimal");
659        if ((dataset instanceof ScalarDS) && isInt /* && !isUINT64 */) {
660            menu.add(item);
661        }
662
663        item = checkBin;
664        item.addActionListener(this);
665        item.setActionCommand("Show binary");
666        if ((dataset instanceof ScalarDS) && isInt /* && !isUINT64 */) {
667            menu.add(item);
668        }
669
670        menu.addSeparator();
671
672        item = new JMenuItem("Close");
673        item.addActionListener(this);
674        item.setActionCommand("Close");
675        menu.add(item);
676
677        bar.add(new JLabel("     "));
678
679        // add icons to the menubar
680
681        Insets margin = new Insets(0, 2, 0, 2);
682
683        // chart button
684        button = new JButton(ViewProperties.getChartIcon());
685        bar.add(button);
686        button.setToolTipText("Line Plot");
687        button.setMargin(margin);
688        button.addActionListener(this);
689        button.setActionCommand("Show chart");
690
691        if (is3D) {
692            bar.add(new JLabel("     "));
693
694            // first button
695            button = new JButton(ViewProperties.getFirstIcon());
696            bar.add(button);
697            button.setToolTipText("First");
698            button.setMargin(margin);
699            button.setName("firstbutton");
700            button.addActionListener(this);
701            button.setActionCommand("First page");
702
703            // previous button
704            button = new JButton(ViewProperties.getPreviousIcon());
705            bar.add(button);
706            button.setToolTipText("Previous");
707            button.setMargin(margin);
708            button.setName("prevbutton");
709            button.addActionListener(this);
710            button.setActionCommand("Previous page");
711
712            frameField = new JTextField(String.valueOf(curFrame));
713            frameField.setMaximumSize(new Dimension(50, 30));
714            bar.add(frameField);
715            frameField.setMargin(margin);
716            frameField.setName("framenumber");
717            frameField.addActionListener(this);
718            frameField.setActionCommand("Go to frame");
719
720            JLabel tmpField = new JLabel(String.valueOf(maxFrame), SwingConstants.CENTER);
721            tmpField.setMaximumSize(new Dimension(50, 30));
722            bar.add(tmpField);
723
724            // next button
725            button = new JButton(ViewProperties.getNextIcon());
726            bar.add(button);
727            button.setToolTipText("Next");
728            button.setMargin(margin);
729            button.setName("nextbutton");
730            button.addActionListener(this);
731            button.setActionCommand("Next page");
732
733            // last button
734            button = new JButton(ViewProperties.getLastIcon());
735            bar.add(button);
736            button.setToolTipText("Last");
737            button.setMargin(margin);
738            button.setName("lastbutton");
739            button.addActionListener(this);
740            button.setActionCommand("Last page");
741        }
742
743        return bar;
744    }
745
746    @Override
747    public void actionPerformed (ActionEvent e) {
748        try {
749            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
750
751            e.getSource();
752            String cmd = e.getActionCommand();
753            log.trace("DefaultTableView actionPerformed: {}", cmd);
754
755            if (cmd.equals("Close")) {
756                dispose(); // terminate the application
757            }
758            else if (cmd.equals("Save table as text")) {
759                try {
760                    saveAsText();
761                }
762                catch (Exception ex) {
763                    toolkit.beep();
764                    JOptionPane.showMessageDialog((JFrame) viewer, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
765                }
766            }
767            else if (cmd.startsWith("Save table as binary")) {
768                if (cmd.equals("Save table as binary Native Order")) binaryOrder = 1;
769                if (cmd.equals("Save table as binary Little Endian")) binaryOrder = 2;
770                if (cmd.equals("Save table as binary Big Endian")) binaryOrder = 3;
771                try {
772                    saveAsBinary();
773                }
774                catch (Exception ex) {
775                    toolkit.beep();
776                    JOptionPane.showMessageDialog((JFrame) viewer, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
777                }
778            }
779            else if (cmd.equals("Copy data")) {
780                copyData();
781            }
782            else if (cmd.equals("Paste data")) {
783                pasteData();
784            }
785            else if (cmd.equals("Import data from file")) {
786                String currentDir = dataset.getFileFormat().getParent();
787                JFileChooser fchooser = new JFileChooser(currentDir);
788                fchooser.setFileFilter(DefaultFileFilter.getFileFilterText());
789                int returnVal = fchooser.showOpenDialog(this);
790
791                if (returnVal != JFileChooser.APPROVE_OPTION) {
792                    return;
793                }
794
795                File choosedFile = fchooser.getSelectedFile();
796                if (choosedFile == null) {
797                    return;
798                }
799
800                String txtFile = choosedFile.getAbsolutePath();
801                importTextData(txtFile);
802            }
803            else if (cmd.startsWith("Order as")) {
804                if (cmd.equals("Order as Native Order")) binaryOrder = 1;
805                if (cmd.equals("Order as Little Endian")) binaryOrder = 2;
806                if (cmd.equals("Order as Big Endian")) binaryOrder = 3;
807
808                importBinaryData();
809            }
810            else if (cmd.equals("Write selection to dataset")) {
811                JTable jtable = getTable();
812                if ((jtable.getSelectedColumnCount() <= 0) || (jtable.getSelectedRowCount() <= 0)) {
813                    JOptionPane.showMessageDialog(this, "Select table cells to write.", "HDFView", JOptionPane.INFORMATION_MESSAGE);
814                    return;
815                }
816
817                TreeView treeView = viewer.getTreeView();
818                TreeNode node = viewer.getTreeView().findTreeNode(dataset);
819                Group pGroup = (Group) ((DefaultMutableTreeNode) node.getParent()).getUserObject();
820                TreeNode root = dataset.getFileFormat().getRootNode();
821
822                if (root == null) {
823                    return;
824                }
825
826                Vector<Object> list = new Vector<Object>(dataset.getFileFormat().getNumberOfMembers() + 5);
827                DefaultMutableTreeNode theNode = null;
828                Enumeration<?> local_enum = ((DefaultMutableTreeNode) root).depthFirstEnumeration();
829                while (local_enum.hasMoreElements()) {
830                    theNode = (DefaultMutableTreeNode) local_enum.nextElement();
831                    list.add(theNode.getUserObject());
832                }
833
834                NewDatasetDialog dialog = new NewDatasetDialog((JFrame) viewer, pGroup, list, this);
835                dialog.setVisible(true);
836
837                HObject obj = (HObject) dialog.getObject();
838                if (obj != null) {
839                    Group pgroup = dialog.getParentGroup();
840                    try {
841                        treeView.addObject(obj, pgroup);
842                    }
843                    catch (Exception ex) {
844                        log.debug("Write selection to dataset:", ex);
845                    }
846                }
847
848                list.setSize(0);
849            }
850            else if (cmd.equals("Save dataset")) {
851                try {
852                    updateValueInFile();
853                }
854                catch (Exception ex) {
855                    toolkit.beep();
856                    JOptionPane.showMessageDialog((JFrame) viewer, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
857                }
858            }
859            else if (cmd.equals("Select all data")) {
860                try {
861                    selectAll();
862                }
863                catch (Exception ex) {
864                    toolkit.beep();
865                    JOptionPane.showMessageDialog((JFrame) viewer, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
866                }
867            }
868            else if (cmd.equals("Show chart")) {
869                showLineplot();
870            }
871            else if (cmd.equals("First page")) {
872                firstPage();
873            }
874            else if (cmd.equals("Previous page")) {
875                previousPage();
876            }
877            else if (cmd.equals("Next page")) {
878                nextPage();
879            }
880            else if (cmd.equals("Last page")) {
881                lastPage();
882            }
883            else if (cmd.equals("Show statistics")) {
884                try {
885                    Object theData = null;
886                    theData = getSelectedData();
887
888                    if (dataset instanceof CompoundDS) {
889                        int cols = table.getSelectedColumnCount();
890                        if (cols != 1) {
891                            JOptionPane.showMessageDialog(this, "Please select one colunm a time for compound dataset.",
892                                    getTitle(), JOptionPane.ERROR_MESSAGE);
893                            return;
894                        }
895                    }
896                    else if (theData == null) {
897                        theData = dataValue;
898                    }
899
900                    double[] minmax = new double[2];
901                    double[] stat = new double[2];
902                    Tools.findMinMax(theData, minmax, fillValue);
903                    if (Tools.computeStatistics(theData, stat, fillValue) > 0) {
904                        String statistics = "Min                      = " + minmax[0] + "\nMax                      = " + minmax[1]
905                                + "\nMean                     = " + stat[0] + "\nStandard deviation = " + stat[1];
906                        JOptionPane.showMessageDialog(this, statistics, "Statistics", JOptionPane.INFORMATION_MESSAGE);
907                    }
908
909                    theData = null;
910                    System.gc();
911                }
912                catch (Exception ex) {
913                    toolkit.beep();
914                    JOptionPane.showMessageDialog((JFrame) viewer, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
915                }
916            }
917            else if (cmd.equals("Math conversion")) {
918                try {
919                    mathConversion();
920                }
921                catch (Exception ex) {
922                    toolkit.beep();
923                    JOptionPane.showMessageDialog((JFrame) viewer, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
924                }
925            }
926            else if (cmd.startsWith("Go to frame")) {
927                int page = 0;
928                try {
929                    page = Integer.parseInt(frameField.getText().trim()) - indexBase;
930                }
931                catch (Exception ex) {
932                    page = -1;
933                }
934
935                gotoPage(page);
936            }
937            else if (cmd.equals("Show scientific notation")) {
938                if (checkScientificNotation.isSelected()) {
939                    checkCustomNotation.setSelected(false);
940                    numberFormat = scientificFormat;
941                    checkHex.setSelected(false);
942                    checkBin.setSelected(false);
943                    showAsHex = false;
944                    showAsBin = false;
945                }
946                else
947                    numberFormat = normalFormat;
948                this.updateUI();
949            }
950            else if (cmd.equals("Create custom notation")) {
951                String msg = "Create number format by pattern \nINTEGER . FRACTION E EXPONENT\nusing # for optional digits and 0 for required digits"
952                        + "\nwhere, INTEGER: the pattern for the integer part"
953                        + "\n       FRACTION: the pattern for the fractional part"
954                        + "\n       EXPONENT: the pattern for the exponent part"
955                        + "\n\nFor example, "
956                        + "\n\t the normalized scientific notation format is \"#.0###E0##\""
957                        + "\n\t to make the digits required \"0.00000E000\"\n\n";
958                String str = (String) JOptionPane.showInputDialog(this, msg, "Create a custom number format",
959                        JOptionPane.PLAIN_MESSAGE, ViewProperties.getLargeHdfIcon(), null, null);
960                if ((str == null) || (str.length() < 1)) {
961                    return;
962                }
963
964                customFormat.applyPattern(str);
965
966            }
967            else if (cmd.equals("Show custom notation")) {
968                if (checkCustomNotation.isSelected()) {
969                    numberFormat = customFormat;
970                    checkScientificNotation.setSelected(false);
971                    checkHex.setSelected(false);
972                    checkBin.setSelected(false);
973                    showAsHex = false;
974                    showAsBin = false;
975                }
976                else
977                    numberFormat = normalFormat;
978                this.updateUI();
979            }
980            else if (cmd.equals("Show hexadecimal")) {
981                showAsHex = checkHex.isSelected();
982                if (showAsHex) {
983                    checkScientificNotation.setSelected(false);
984                    checkCustomNotation.setSelected(false);
985                    checkBin.setSelected(false);
986                    showAsBin = false;
987                    numberFormat = normalFormat;
988                }
989                this.updateUI();
990            }
991            else if (cmd.equals("Show binary")) {
992                showAsBin = checkBin.isSelected();
993                if (showAsBin) {
994                    checkScientificNotation.setSelected(false);
995                    checkCustomNotation.setSelected(false);
996                    checkHex.setSelected(false);
997                    showAsHex = false;
998                    numberFormat = normalFormat;
999                }
1000                this.updateUI();
1001            }
1002            else if (cmd.equals("Fixed data length")) {
1003                if (!checkFixedDataLength.isSelected()) {
1004                    fixedDataLength = -1;
1005                    this.updateUI();
1006                    return;
1007                }
1008
1009                String str = JOptionPane
1010                        .showInputDialog(
1011                                this,
1012                                "Enter fixed data length when importing text data\n\n"
1013                                        + "For example, for a text string of \"12345678\"\n\t\tenter 2, the data will be 12, 34, 56, 78\n\t\tenter 4, the data will be 1234, 5678\n",
1014                                "");
1015
1016                if ((str == null) || (str.length() < 1)) {
1017                    checkFixedDataLength.setSelected(false);
1018                    return;
1019                }
1020
1021                try {
1022                    fixedDataLength = Integer.parseInt(str);
1023                }
1024                catch (Exception ex) {
1025                    fixedDataLength = -1;
1026                }
1027
1028                if (fixedDataLength < 1) {
1029                    checkFixedDataLength.setSelected(false);
1030                    return;
1031                }
1032            }
1033            else if (cmd.startsWith("Show data as")) {
1034                log.trace("DefaultTableView actionPerformed: {}", cmd);
1035                // show data pointed by reg. ref.
1036                if (cmd.endsWith("table"))
1037                    viewType = ViewType.TABLE;
1038                else if (cmd.endsWith("image"))
1039                    viewType = ViewType.IMAGE;
1040                else
1041                    viewType = ViewType.TABLE;
1042                log.trace("DefaultTableView actionPerformed: Show data as: {}", viewType);
1043
1044                Object theData = getSelectedData();
1045                if (theData == null) {
1046                    toolkit.beep();
1047                    JOptionPane.showMessageDialog(this, "No data selected.", getTitle(), JOptionPane.ERROR_MESSAGE);
1048                    return;
1049
1050                }
1051
1052                int[] selectedRows = table.getSelectedRows();
1053                int[] selectedCols = table.getSelectedColumns();
1054                if (selectedRows == null || selectedRows.length <= 0) {
1055                    log.trace("DefaultTableView actionPerformed: Show data as: selectedRows is empty");
1056                    return;
1057                }
1058                int len = Array.getLength(selectedRows) * Array.getLength(selectedCols);
1059                log.trace("DefaultTableView actionPerformed: Show data as: len={}", len);
1060                for (int i = 0; i < len; i++) {
1061                    if (isRegRef) {
1062                        log.trace("DefaultTableView actionPerformed: Show data[{}] as: isRegRef={}", i, isRegRef);
1063                        showRegRefData((String) Array.get(theData, i));
1064                    }
1065                    else if (isObjRef) {
1066                        log.trace("DefaultTableView actionPerformed: Show data[{}] as: isObjRef={}", i, isObjRef);
1067                        showObjRefData(Array.getLong(theData, i));
1068                    }
1069                }
1070            }
1071        }
1072        finally {
1073            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1074        }
1075    }
1076
1077    // Implementing DataView.
1078    @Override
1079    public HObject getDataObject ( ) {
1080        return dataset;
1081    }
1082
1083    @Override
1084    public void dispose ( ) {
1085        if (isValueChanged && !isReadOnly) {
1086            int op = JOptionPane.showConfirmDialog(this, "\"" + dataset.getName() + "\" has changed.\n"
1087                    + "Do you want to save the changes?", getTitle(), JOptionPane.YES_NO_OPTION);
1088
1089            if (op == JOptionPane.YES_OPTION) {
1090                updateValueInFile();
1091            }
1092            else
1093                dataset.clearData(); // reload data
1094
1095        }
1096
1097        if (dataset instanceof ScalarDS) {
1098            ScalarDS sds = (ScalarDS) dataset;
1099            // reload the data when it is displayed next time
1100            // because the display type (table or image) may be
1101            // different.
1102
1103            if (sds.isImage()) {
1104                sds.clearData();
1105            }
1106
1107            dataValue = null;
1108            table = null;
1109        }
1110
1111        viewer.removeDataView(this);
1112
1113        super.dispose();
1114    }
1115
1116    // Implementing DataObserver.
1117    private void previousPage ( ) {
1118        int rank = dataset.getRank();
1119
1120        if (rank < 3) {
1121            return;
1122        }
1123
1124        long[] start = dataset.getStartDims();
1125        dataset.getDims();
1126        int[] selectedIndex = dataset.getSelectedIndex();
1127        long idx = start[selectedIndex[2]];
1128        if (idx == 0) {
1129            return; // current page is the first page
1130        }
1131
1132        gotoPage(start[selectedIndex[2]] - 1);
1133    }
1134
1135    // Implementing DataObserver.
1136    private void nextPage ( ) {
1137        int rank = dataset.getRank();
1138
1139        if (rank < 3) {
1140            return;
1141        }
1142
1143        long[] start = dataset.getStartDims();
1144        int[] selectedIndex = dataset.getSelectedIndex();
1145        long[] dims = dataset.getDims();
1146        long idx = start[selectedIndex[2]];
1147        if (idx == dims[selectedIndex[2]] - 1) {
1148            return; // current page is the last page
1149        }
1150
1151        gotoPage(start[selectedIndex[2]] + 1);
1152    }
1153
1154    // Implementing DataObserver.
1155    private void firstPage ( ) {
1156        int rank = dataset.getRank();
1157
1158        if (rank < 3) {
1159            return;
1160        }
1161
1162        long[] start = dataset.getStartDims();
1163        int[] selectedIndex = dataset.getSelectedIndex();
1164        dataset.getDims();
1165        long idx = start[selectedIndex[2]];
1166        if (idx == 0) {
1167            return; // current page is the first page
1168        }
1169
1170        gotoPage(0);
1171    }
1172
1173    // Implementing DataObserver.
1174    private void lastPage ( ) {
1175        int rank = dataset.getRank();
1176
1177        if (rank < 3) {
1178            return;
1179        }
1180
1181        long[] start = dataset.getStartDims();
1182        int[] selectedIndex = dataset.getSelectedIndex();
1183        long[] dims = dataset.getDims();
1184        long idx = start[selectedIndex[2]];
1185        if (idx == dims[selectedIndex[2]] - 1) {
1186            return; // current page is the last page
1187        }
1188
1189        gotoPage(dims[selectedIndex[2]] - 1);
1190    }
1191
1192    // Implementing TableObserver.
1193    @Override
1194    public JTable getTable ( ) {
1195        return table;
1196    }
1197
1198    // Implementing TableObserver.
1199    private void showLineplot ( ) {
1200        int[] rows = table.getSelectedRows();
1201        int[] cols = table.getSelectedColumns();
1202
1203        if ((rows == null) || (cols == null) || (rows.length <= 0) || (cols.length <= 0)) {
1204            toolkit.beep();
1205            JOptionPane.showMessageDialog(this, "Select rows/columns to draw line plot.", getTitle(), JOptionPane.ERROR_MESSAGE);
1206            return;
1207        }
1208
1209        int nrow = table.getRowCount();
1210        int ncol = table.getColumnCount();
1211
1212        log.trace("DefaultTableView showLineplot: {} - {}", nrow, ncol);
1213        LineplotOption lpo = new LineplotOption((JFrame) viewer, "Line Plot Options -- " + dataset.getName(), nrow, ncol);
1214        lpo.setVisible(true);
1215
1216        int plotType = lpo.getPlotBy();
1217        if (plotType == LineplotOption.NO_PLOT) {
1218            return;
1219        }
1220
1221        boolean isRowPlot = (plotType == LineplotOption.ROW_PLOT);
1222        int xIndex = lpo.getXindex();
1223
1224        // figure out to plot data by row or by column
1225        // Plot data by rows if all columns are selected and part of
1226        // rows are selected, otherwise plot data by column
1227        double[][] data = null;
1228        int nLines = 0;
1229        String title = "Lineplot - " + dataset.getPath() + dataset.getName();
1230        String[] lineLabels = null;
1231        double[] yRange = { Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY };
1232        double xData[] = null;
1233
1234        if (isRowPlot) {
1235            title += " - by row";
1236            nLines = rows.length;
1237            if (nLines > 10) {
1238                toolkit.beep();
1239                nLines = 10;
1240                JOptionPane.showMessageDialog(this, "More than 10 rows are selected.\n" + "The first 10 rows will be displayed.",
1241                        getTitle(), JOptionPane.WARNING_MESSAGE);
1242            }
1243            lineLabels = new String[nLines];
1244            data = new double[nLines][cols.length];
1245
1246            double value = 0.0;
1247            for (int i = 0; i < nLines; i++) {
1248                lineLabels[i] = String.valueOf(rows[i] + indexBase);
1249                for (int j = 0; j < cols.length; j++) {
1250                    data[i][j] = 0;
1251                    try {
1252                        value = Double.parseDouble(table.getValueAt(rows[i], cols[j]).toString());
1253                        data[i][j] = value;
1254                        yRange[0] = Math.min(yRange[0], value);
1255                        yRange[1] = Math.max(yRange[1], value);
1256                    }
1257                    catch (NumberFormatException ex) {
1258                        log.debug("rows[{}]:", i, ex);
1259                    }
1260                } // for (int j = 0; j < ncols; j++)
1261            } // for (int i = 0; i < rows.length; i++)
1262
1263            if (xIndex >= 0) {
1264                xData = new double[cols.length];
1265                for (int j = 0; j < cols.length; j++) {
1266                    xData[j] = 0;
1267                    try {
1268                        value = Double.parseDouble(table.getValueAt(xIndex, cols[j]).toString());
1269                        xData[j] = value;
1270                    }
1271                    catch (NumberFormatException ex) {
1272                        log.debug("xIndex of {}:", xIndex, ex);
1273                    }
1274                }
1275            }
1276        } // if (isRowPlot)
1277        else {
1278            title += " - by column";
1279            nLines = cols.length;
1280            if (nLines > 10) {
1281                toolkit.beep();
1282                nLines = 10;
1283                JOptionPane.showMessageDialog(this, "More than 10 columns are selected.\n"
1284                        + "The first 10 columns will be displayed.", getTitle(), JOptionPane.WARNING_MESSAGE);
1285            }
1286            lineLabels = new String[nLines];
1287            data = new double[nLines][rows.length];
1288            double value = 0.0;
1289            for (int j = 0; j < nLines; j++) {
1290                lineLabels[j] = table.getColumnName(cols[j] /* + indexBase */);
1291                for (int i = 0; i < rows.length; i++) {
1292                    data[j][i] = 0;
1293                    try {
1294                        value = Double.parseDouble(table.getValueAt(rows[i], cols[j]).toString());
1295                        data[j][i] = value;
1296                        yRange[0] = Math.min(yRange[0], value);
1297                        yRange[1] = Math.max(yRange[1], value);
1298                    }
1299                    catch (NumberFormatException ex) {
1300                        log.debug("cols[{}]:", j, ex);
1301                    }
1302                } // for (int j=0; j<ncols; j++)
1303            } // for (int i=0; i<rows.length; i++)
1304
1305            if (xIndex >= 0) {
1306                xData = new double[rows.length];
1307                for (int j = 0; j < rows.length; j++) {
1308                    xData[j] = 0;
1309                    try {
1310                        value = Double.parseDouble(table.getValueAt(rows[j], xIndex).toString());
1311                        xData[j] = value;
1312                    }
1313                    catch (NumberFormatException ex) {
1314                        log.debug("xIndex of {}:", xIndex, ex);
1315                    }
1316                }
1317            }
1318        } // else
1319
1320        int n = removeInvalidPlotData(data, xData, yRange);
1321        if (n < data[0].length) {
1322            double[][] dataNew = new double[data.length][n];
1323            for (int i = 0; i < data.length; i++)
1324                System.arraycopy(data[i], 0, dataNew[i], 0, n);
1325
1326            data = dataNew;
1327
1328            if (xData != null) {
1329                double[] xDataNew = new double[n];
1330                System.arraycopy(xData, 0, xDataNew, 0, n);
1331                xData = xDataNew;
1332            }
1333        }
1334
1335        // allow to draw a flat line: all values are the same
1336        if (yRange[0] == yRange[1]) {
1337            yRange[1] += 1;
1338            yRange[0] -= 1;
1339        }
1340        else if (yRange[0] > yRange[1]) {
1341            toolkit.beep();
1342            JOptionPane.showMessageDialog(this,
1343                    "Cannot show line plot for the selected data. \n" + "Please check the data range: ("
1344                            + yRange[0] + ", " + yRange[1] + ").", getTitle(), JOptionPane.ERROR_MESSAGE);
1345            data = null;
1346            return;
1347        }
1348        if (xData == null) { // use array index and length for x data range
1349            xData = new double[2];
1350            xData[0] = indexBase; // 1- or zero-based
1351            xData[1] = data[0].length + indexBase - 1; // maximum index
1352        }
1353
1354        Chart cv = new Chart((JFrame) viewer, title, Chart.LINEPLOT, data, xData, yRange);
1355        cv.setLineLabels(lineLabels);
1356
1357        String cname = dataValue.getClass().getName();
1358        char dname = cname.charAt(cname.lastIndexOf("[") + 1);
1359        if ((dname == 'B') || (dname == 'S') || (dname == 'I') || (dname == 'J')) {
1360            cv.setTypeToInteger();
1361        }
1362
1363        cv.setVisible(true);
1364    }
1365
1366    /**
1367     * Remove values of NaN, INF from the array.
1368     *
1369     * @param data
1370     *            the data array
1371     * @param xData
1372     *            the x-axis data points
1373     * @param yRange
1374     *            the range of data values
1375     * @return number of data points in the plot data if successful; otherwise, returns false.
1376     */
1377    private int removeInvalidPlotData (double[][] data, double[] xData, double[] yRange) {
1378        int idx = 0;
1379        boolean hasInvalid = false;
1380
1381        if (data == null || yRange == null) return -1;
1382
1383        yRange[0] = Double.POSITIVE_INFINITY;
1384        yRange[1] = Double.NEGATIVE_INFINITY;
1385
1386        for (int i = 0; i < data[0].length; i++) {
1387            hasInvalid = false;
1388
1389            for (int j = 0; j < data.length; j++) {
1390                hasInvalid = Tools.isNaNINF(data[j][i]);
1391                if (xData != null) hasInvalid = hasInvalid || Tools.isNaNINF(xData[i]);
1392
1393                if (hasInvalid)
1394                    break;
1395                else {
1396                    data[j][idx] = data[j][i];
1397                    if (xData != null) xData[idx] = xData[i];
1398                    yRange[0] = Math.min(yRange[0], data[j][idx]);
1399                    yRange[1] = Math.max(yRange[1], data[j][idx]);
1400                }
1401            }
1402
1403            if (!hasInvalid) idx++;
1404        }
1405
1406        return idx;
1407    }
1408
1409    /**
1410     * Returns the selected data values.
1411     */
1412    @Override
1413    public Object getSelectedData ( ) {
1414        if (dataset instanceof CompoundDS) {
1415            return getSelectedCompoundData();
1416        }
1417        else {
1418            return getSelectedScalarData();
1419        }
1420    }
1421
1422    /**
1423     * Returns the selected data values.
1424     */
1425    private Object getSelectedScalarData ( ) {
1426        Object selectedData = null;
1427
1428        int[] selectedRows = table.getSelectedRows();
1429        int[] selectedCols = table.getSelectedColumns();
1430        if (selectedRows == null || selectedRows.length <= 0 || selectedCols == null || selectedCols.length <= 0) {
1431            return null;
1432        }
1433
1434        int size = selectedCols.length * selectedRows.length;
1435        log.trace("DefaultTableView getSelectedScalarData: {}", size);
1436
1437        // the whole table is selected
1438        if ((table.getColumnCount() == selectedCols.length) && (table.getRowCount() == selectedRows.length)) {
1439            return dataValue;
1440        }
1441
1442        selectedData = null;
1443        if (isRegRef) {
1444            // reg. ref data are stored in strings
1445            selectedData = new String[size];
1446        }
1447        else {
1448            switch (NT) {
1449                case 'B':
1450                    selectedData = new byte[size];
1451                    break;
1452                case 'S':
1453                    selectedData = new short[size];
1454                    break;
1455                case 'I':
1456                    selectedData = new int[size];
1457                    break;
1458                case 'J':
1459                    selectedData = new long[size];
1460                    break;
1461                case 'F':
1462                    selectedData = new float[size];
1463                    break;
1464                case 'D':
1465                    selectedData = new double[size];
1466                    break;
1467                default:
1468                    selectedData = null;
1469                    break;
1470            }
1471        }
1472
1473        if (selectedData == null) {
1474            toolkit.beep();
1475            JOptionPane.showMessageDialog(this, "Unsupported data type.", getTitle(), JOptionPane.ERROR_MESSAGE);
1476            return null;
1477        }
1478        log.trace("DefaultTableView getSelectedScalarData: selectedData is type {}", NT);
1479
1480        table.getSelectedRow();
1481        table.getSelectedColumn();
1482        int w = table.getColumnCount();
1483        log.trace("DefaultTableView getSelectedScalarData: getColumnCount={}", w);
1484        int idx_src = 0;
1485        int idx_dst = 0;
1486        log.trace("DefaultTableView getSelectedScalarData: Rows.length={} Cols.length={}", selectedRows.length, selectedCols.length);
1487        for (int i = 0; i < selectedRows.length; i++) {
1488            for (int j = 0; j < selectedCols.length; j++) {
1489                idx_src = selectedRows[i] * w + selectedCols[j];
1490                log.trace("DefaultTableView getSelectedScalarData[{},{}]: dataValue[{}]={} from r{} and c{}", i, j, idx_src,
1491                        Array.get(dataValue, idx_src), selectedRows[i], selectedCols[j]);
1492                Array.set(selectedData, idx_dst, Array.get(dataValue, idx_src));
1493                log.trace("DefaultTableView getSelectedScalarData[{},{}]: selectedData[{}]={}", i, j, idx_dst,
1494                        Array.get(selectedData, idx_dst));
1495                idx_dst++;
1496            }
1497        }
1498
1499        // this only works for continuous cells
1500        // for (int i = 0; i < rows; i++) {
1501        // idx_src = (r0 + i) * w + c0;
1502        // System.arraycopy(dataValue, idx_src, selectedData, idx_dst, cols);
1503        // idx_dst += cols;
1504        // }
1505
1506        return selectedData;
1507    }
1508
1509    /**
1510     * Returns the selected data values.
1511     */
1512    private Object getSelectedCompoundData ( ) {
1513        Object selectedData = null;
1514
1515        int cols = table.getSelectedColumnCount();
1516        int rows = table.getSelectedRowCount();
1517
1518        if ((cols <= 0) || (rows <= 0)) {
1519            toolkit.beep();
1520            JOptionPane.showMessageDialog(this, "No data is selected.", getTitle(), JOptionPane.ERROR_MESSAGE);
1521            return null;
1522        }
1523
1524        Object colData = null;
1525        try {
1526            colData = ((List<?>) dataset.getData()).get(table.getSelectedColumn());
1527        }
1528        catch (Exception ex) {
1529            log.debug("colData:", ex);
1530            return null;
1531        }
1532
1533        int size = Array.getLength(colData);
1534        String cName = colData.getClass().getName();
1535        int cIndex = cName.lastIndexOf("[");
1536        char nt = ' ';
1537        if (cIndex >= 0) {
1538            nt = cName.charAt(cIndex + 1);
1539        }
1540        log.trace("DefaultTableView getSelectedCompoundData: size={} cName={} nt={}", size, cName, nt);
1541
1542        if (nt == 'B') {
1543            selectedData = new byte[size];
1544        }
1545        else if (nt == 'S') {
1546            selectedData = new short[size];
1547        }
1548        else if (nt == 'I') {
1549            selectedData = new int[size];
1550        }
1551        else if (nt == 'J') {
1552            selectedData = new long[size];
1553        }
1554        else if (nt == 'F') {
1555            selectedData = new float[size];
1556        }
1557        else if (nt == 'D') {
1558            selectedData = new double[size];
1559        }
1560        else {
1561            toolkit.beep();
1562            JOptionPane.showMessageDialog(this, "Unsupported data type.", getTitle(), JOptionPane.ERROR_MESSAGE);
1563            return null;
1564        }
1565        log.trace("DefaultTableView getSelectedCompoundData: selectedData={}", selectedData);
1566
1567        System.arraycopy(colData, 0, selectedData, 0, size);
1568
1569        return selectedData;
1570    }
1571
1572    /**
1573     * Creates a JTable to hold a scalar dataset.
1574     */
1575    private JTable createTable (ScalarDS d) {
1576        JTable theTable = null;
1577        int rows = 0;
1578        int cols = 0;
1579
1580        log.trace("createTable: ScalarDS start");
1581        int rank = d.getRank();
1582        if (rank <= 0) {
1583            try {
1584                d.init();
1585                log.trace("createTable: d.inited");
1586            }
1587            catch (Exception ex) {
1588                JOptionPane.showMessageDialog(this, ex, "createTable:" + getTitle(), JOptionPane.ERROR_MESSAGE);
1589                dataValue = null;
1590                return null;
1591            }
1592
1593            rank = d.getRank();
1594        }
1595        long[] dims = d.getSelectedDims();
1596        log.trace("createTable dims={}", dims);
1597
1598        rows = (int) dims[0];
1599        cols = 1;
1600        if (rank > 1) {
1601            rows = d.getHeight();
1602            cols = d.getWidth();
1603        }
1604
1605        log.trace("createTable: rows={} : cols={}", rows, cols);
1606        dataValue = null;
1607        try {
1608            dataValue = d.getData();
1609            if (dataValue == null) {
1610                JOptionPane.showMessageDialog(this, "No data read", "ScalarDS createTable:" + getTitle(),
1611                        JOptionPane.WARNING_MESSAGE);
1612                return null;
1613            }
1614
1615            log.trace("createTable: dataValue={}", dataValue);
1616            if (Tools.applyBitmask(dataValue, bitmask, bitmaskOP)) {
1617                isReadOnly = true;
1618                String opName = "Bits ";
1619
1620                if (bitmaskOP == ViewProperties.BITMASK_OP.AND) opName = "Bitwise AND ";
1621
1622                JPanel contentpane = (JPanel) getContentPane();
1623                Border border = contentpane.getBorder();
1624
1625                String btitle = ((TitledBorder) border).getTitle();
1626                btitle += ", " + opName + bitmask;
1627                ((TitledBorder) border).setTitle(btitle);
1628            }
1629
1630            d.convertFromUnsignedC();
1631            dataValue = d.getData();
1632
1633            if (Array.getLength(dataValue) <= rows) cols = 1;
1634        }
1635        catch (Throwable ex) {
1636            JOptionPane.showMessageDialog(this, ex, "ScalarDS createTable:" + getTitle(), JOptionPane.ERROR_MESSAGE);
1637            dataValue = null;
1638        }
1639
1640        if (dataValue == null) {
1641            return null;
1642        }
1643
1644        fillValue = d.getFillValue();
1645        log.trace("createTable: fillValue={}", fillValue);
1646
1647        String cName = dataValue.getClass().getName();
1648        int cIndex = cName.lastIndexOf("[");
1649        if (cIndex >= 0) {
1650            NT = cName.charAt(cIndex + 1);
1651        }
1652        log.trace("createTable: cName={} NT={}", cName, NT);
1653
1654        // convert numerical data into char
1655        // only possible cases are byte[] and short[] (converted from unsigned
1656        // byte)
1657        if (isDisplayTypeChar && ((NT == 'B') || (NT == 'S'))) {
1658            int n = Array.getLength(dataValue);
1659            char[] charData = new char[n];
1660            for (int i = 0; i < n; i++) {
1661                if (NT == 'B') {
1662                    charData[i] = (char) Array.getByte(dataValue, i);
1663                }
1664                else if (NT == 'S') {
1665                    charData[i] = (char) Array.getShort(dataValue, i);
1666                }
1667            }
1668
1669            dataValue = charData;
1670        }
1671        else if ((NT == 'B') && dataset.getDatatype().getDatatypeClass() == Datatype.CLASS_ARRAY) {
1672            Datatype baseType = dataset.getDatatype().getBasetype();
1673            if (baseType.getDatatypeClass() == Datatype.CLASS_STRING) {
1674                dataValue = Dataset.byteToString((byte[]) dataValue, baseType.getDatatypeSize());
1675            }
1676        }
1677
1678        final String columnNames[] = new String[cols];
1679        final int rowCount = rows;
1680        final int colCount = cols;
1681        final long[] startArray = dataset.getStartDims();
1682        final long[] strideArray = dataset.getStride();
1683        int[] selectedIndex = dataset.getSelectedIndex();
1684        final int rowStart = (int) startArray[selectedIndex[0]];
1685        final int rowStride = (int) strideArray[selectedIndex[0]];
1686        int start = 0;
1687        int stride = 1;
1688
1689        if (rank > 1) {
1690            start = (int) startArray[selectedIndex[1]];
1691            stride = (int) strideArray[selectedIndex[1]];
1692
1693            for (int i = 0; i < cols; i++) {
1694                columnNames[i] = String.valueOf(start + indexBase + i * stride);
1695            }
1696        }
1697        else {
1698            columnNames[0] = "  ";
1699        }
1700
1701        AbstractTableModel tm = new AbstractTableModel() {
1702            private static final long  serialVersionUID = 254175303655079056L;
1703            private final StringBuffer stringBuffer     = new StringBuffer();
1704            private final Datatype     dtype            = dataset.getDatatype();
1705            private final Datatype     btype            = dtype.getBasetype();
1706            private final int          typeSize         = dtype.getDatatypeSize();
1707            private final boolean      isArray          = (dtype.getDatatypeClass() == Datatype.CLASS_ARRAY);
1708            private final boolean      isStr            = (NT == 'L');
1709            private final boolean      isInt            = (NT == 'B' || NT == 'S' || NT == 'I' || NT == 'J');
1710            private final boolean      isUINT64         = (dtype.isUnsigned() && (NT == 'J'));
1711            private Object             theValue;
1712
1713            boolean                    isNaturalOrder   = (dataset.getRank() == 1 || (dataset.getSelectedIndex()[0] < dataset
1714                                                                .getSelectedIndex()[1]));
1715
1716            @Override
1717            public int getColumnCount ( ) {
1718                return columnNames.length;
1719            }
1720
1721            @Override
1722            public int getRowCount ( ) {
1723                return rowCount;
1724            }
1725
1726            @Override
1727            public String getColumnName (int col) {
1728                return columnNames[col];
1729            }
1730
1731            @Override
1732            public Object getValueAt (int row, int column) {
1733                if (startEditing[0]) return "";
1734                log.trace("ScalarDS:createTable:AbstractTableModel:getValueAt({},{}) start", row, column);
1735                log.trace("ScalarDS:createTable:AbstractTableModel:getValueAt isInt={} isArray={} showAsHex={} showAsBin={}",
1736                        isInt, isArray, showAsHex, showAsBin);
1737
1738                if (isArray) {
1739                    // ARRAY dataset
1740                    log.trace("ScalarDS:createTable:AbstractTableModel:getValueAt({},{}) ARRAY", row, column);
1741
1742                    stringBuffer.setLength(0); // clear the old string
1743
1744                    if (dtype instanceof H5Datatype) {
1745                        // Since variable-length strings have no datatype size,
1746                        // just directly append the data to the string buffer
1747                        if (((H5Datatype) dtype).isVLEN() && dtype.getBasetype().getDatatypeClass() == Datatype.CLASS_STRING) {
1748                            stringBuffer.append(Array.get(dataValue, 0));
1749                            for (int i = 0; i < dtype.getArrayDims()[0]; i++) {
1750                                if (i > 0) stringBuffer.append(", ");
1751                                stringBuffer.append(Array.get(dataValue, i));
1752                            }
1753                            return stringBuffer;
1754                        }
1755                    }
1756
1757                    int arraySize = dtype.getDatatypeSize() / btype.getDatatypeSize();
1758                    log.trace(
1759                            "ScalarDS:createTable:AbstractTableModel:getValueAt ARRAY dataset size={} isDisplayTypeChar={} isUINT64={}",
1760                            arraySize, isDisplayTypeChar, isUINT64);
1761
1762                    int i0 = (row * colCount + column) * arraySize;
1763                    int i1 = i0 + arraySize;
1764
1765                    if (isDisplayTypeChar) {
1766                        for (int i = i0; i < i1; i++) {
1767                            stringBuffer.append(Array.getChar(dataValue, i));
1768                            if (stringBuffer.length() > 0 && i < (i1 - 1)) stringBuffer.append(", ");
1769                        }
1770                    }
1771                    else {
1772                        if (isUINT64) {
1773                            log.trace("ScalarDS:createTable:AbstractTableModel:getValueAt({},{}) ARRAY of unsigned longs", row, column);
1774                            // array of unsigned longs
1775                            for (int i = i0; i < i1; i++) {
1776                                Long l = (Long) Array.get(dataValue, i);
1777                                BigInteger big;
1778                                if (l < 0) {
1779                                    l = (l << 1) >>> 1;
1780                                    BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65
1781                                    BigInteger big2 = new BigInteger(l.toString());
1782                                    big = big1.add(big2);
1783                                }
1784                                else {
1785                                    big = new BigInteger(l.toString());
1786                                }
1787                                if (showAsHex)
1788                                    theValue = Tools.toHexString(big.longValue(), 8);
1789                                else if (showAsBin)
1790                                    theValue = Tools.toBinaryString(big.longValue(), 8);
1791                                else
1792                                    theValue = big.toString(10);
1793
1794                                stringBuffer.append(theValue);
1795                                if (stringBuffer.length() > 0 && i < (i1 - 1)) stringBuffer.append(", ");
1796                            }
1797                        }
1798                        else {
1799                            log.trace("ScalarDS:createTable:AbstractTableModel:getValueAt({},{}) ARRAY not unsigned longs", row, column);
1800                            for (int i = i0; i < i1; i++) {
1801                                theValue = Array.get(dataValue, i);
1802                                log.trace("ScalarDS:createTable:AbstractTableModel:getValueAt({},{}) ARRAY[{}]={}", row, column, i, theValue);
1803                                if (showAsHex)
1804                                    theValue = Tools.toHexString(Long.valueOf(theValue.toString()), typeSize / arraySize);
1805                                else if (showAsBin)
1806                                    theValue = Tools.toBinaryString(Long.valueOf(theValue.toString()), typeSize / arraySize);
1807                                else
1808                                    theValue = theValue.toString();
1809
1810                                stringBuffer.append(theValue);
1811
1812                                if (stringBuffer.length() > 0 && i < (i1 - 1))
1813                                    stringBuffer.append(", ");
1814                            }
1815                        }
1816                    }
1817                    theValue = stringBuffer;
1818                }
1819                else {
1820                    // not an array
1821                    int index = column * rowCount + row;
1822
1823                    if (dataset.getRank() > 1) {
1824                        log.trace(
1825                                "ScalarDS:createTable:AbstractTableModel:getValueAt rank={} isDataTransposed={} isNaturalOrder={}",
1826                                dataset.getRank(), isDataTransposed, isNaturalOrder);
1827                        if (isDataTransposed && isNaturalOrder)
1828                            index = column * rowCount + row;
1829                        else if (!isDataTransposed && !isNaturalOrder)
1830                            // Reshape Data
1831                            index = row * colCount + column;
1832                        else if (isDataTransposed && !isNaturalOrder)
1833                            // Transpose Data
1834                            index = column * rowCount + row;
1835                        else
1836                            index = row * colCount + column;
1837                    }
1838                    log.trace("ScalarDS:createTable:AbstractTableModel:getValueAt index={} isStr={} isUINT64={}", index, isStr,
1839                            isUINT64);
1840
1841                    if (isStr) {
1842                        theValue = Array.get(dataValue, index);
1843                        return theValue;
1844                    }
1845
1846                    if (isUINT64) {
1847                        theValue = Array.get(dataValue, index);
1848                        Long l = (Long) theValue;
1849                        BigInteger big;
1850                        if (l < 0) {
1851                            l = (l << 1) >>> 1;
1852                            BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65
1853                            BigInteger big2 = new BigInteger(l.toString());
1854                            big = big1.add(big2);
1855                        }
1856                        else {
1857                            big = new BigInteger(l.toString());
1858                        }
1859                        if (showAsHex)
1860                            theValue = Tools.toHexString(big.longValue(), 8);// big.toString(16);
1861                        else if (showAsBin)
1862                            theValue = Tools.toBinaryString(big.longValue(), 8);
1863                        else
1864                            theValue = big.toString(10);
1865                    }
1866                    else if (showAsHex && isInt) {
1867                        // show in Hexadecimal
1868                        theValue = Array.get(dataValue, index);
1869                        theValue = Tools.toHexString(Long.valueOf(theValue.toString()), typeSize);
1870                    }
1871                    else if (showAsBin && isInt) {
1872                        theValue = Array.get(dataValue, index);
1873                        theValue = Tools.toBinaryString(Long.valueOf(theValue.toString()), typeSize);
1874                    }
1875                    else if (numberFormat != null) {
1876                        // show in scientific format
1877                        theValue = Array.get(dataValue, index);
1878                        theValue = numberFormat.format(theValue);
1879                    }
1880                    else {
1881                        theValue = Array.get(dataValue, index);
1882                    }
1883                }
1884
1885                log.trace("ScalarDS:createTable:AbstractTableModel:getValueAt finish");
1886                return theValue;
1887            } // getValueAt(int row, int column)
1888        };
1889
1890        theTable = new JTable(tm) {
1891            private static final long serialVersionUID = -145476220959400488L;
1892            private final Datatype    dtype            = dataset.getDatatype();
1893            private final boolean     isArray          = (dtype.getDatatypeClass() == Datatype.CLASS_ARRAY);
1894
1895            @Override
1896            public boolean isCellEditable (int row, int col) {
1897                if (isReadOnly || isDisplayTypeChar || isArray || showAsBin || showAsHex) {
1898                    return false;
1899                }
1900                else {
1901                    return true;
1902                }
1903            }
1904
1905            @Override
1906            public boolean editCellAt (int row, int column, java.util.EventObject e) {
1907                if (!isCellEditable(row, column)) {
1908                    return super.editCellAt(row, column, e);
1909                }
1910
1911                if (e instanceof KeyEvent) {
1912                    KeyEvent ke = (KeyEvent) e;
1913                    if (ke.getID() == KeyEvent.KEY_PRESSED) {
1914                        startEditing[0] = true;
1915                    }
1916                }
1917                else if (e instanceof MouseEvent) {
1918                    MouseEvent me = (MouseEvent) e;
1919                    int mc = me.getClickCount();
1920                    if (mc > 1) {
1921                        currentEditingCellValue = getValueAt(row, column);
1922                    }
1923                }
1924
1925                return super.editCellAt(row, column, e);
1926            }
1927
1928            @Override
1929            public void editingStopped (ChangeEvent e) {
1930                int row = getEditingRow();
1931                int col = getEditingColumn();
1932                super.editingStopped(e);
1933                startEditing[0] = false;
1934
1935                Object source = e.getSource();
1936
1937                if (source instanceof CellEditor) {
1938                    CellEditor editor = (CellEditor) source;
1939                    String cellValue = (String) editor.getCellEditorValue();
1940
1941                    try {
1942                        updateValueInMemory(cellValue, row, col);
1943                    }
1944                    catch (Exception ex) {
1945                        toolkit.beep();
1946                        JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
1947                    }
1948                } // if (source instanceof CellEditor)
1949            }
1950
1951            @Override
1952            public boolean isCellSelected (int row, int column) {
1953                if ((getSelectedRow() == row) && (getSelectedColumn() == column)) {
1954                    cellLabel.setText(String.valueOf(rowStart + indexBase + row * rowStride) + ", " + table.getColumnName(column)
1955                            + "  =  ");
1956
1957                    log.trace("JTable.ScalarDS isCellSelected isRegRef={} isObjRef={}", isRegRef, isObjRef);
1958                    Object val = getValueAt(row, column);
1959                    String strVal = null;
1960
1961                    if (isRegRef) {
1962                        boolean displayValues = ViewProperties.showRegRefValues();
1963                        log.trace("JTable.ScalarDS isCellSelected displayValues={}", displayValues);
1964                        if (displayValues && val != null && ((String) val).compareTo("NULL") != 0) {
1965                            String reg = (String) val;
1966                            boolean isPointSelection = (reg.indexOf('-') <= 0);
1967
1968                            // find the object location
1969                            String oidStr = reg.substring(reg.indexOf('/'), reg.indexOf(' '));
1970                            log.trace("JTable.ScalarDS isCellSelected: isPointSelection={} oidStr={}", isPointSelection, oidStr);
1971
1972                            // decode the region selection
1973                            String regStr = reg.substring(reg.indexOf('{') + 1, reg.indexOf('}'));
1974                            if (regStr == null || regStr.length() <= 0) { // no
1975                                                                          // selection
1976                                strVal = null;
1977                            }
1978                            else {
1979                                reg.substring(reg.indexOf('}') + 1);
1980
1981                                StringTokenizer st = new StringTokenizer(regStr);
1982                                int nSelections = st.countTokens();
1983                                if (nSelections <= 0) { // no selection
1984                                    strVal = null;
1985                                }
1986                                else {
1987                                    log.trace("JTable.ScalarDS isCellSelected: nSelections={}", nSelections);
1988
1989                                    HObject obj = FileFormat.findObject(dataset.getFileFormat(), oidStr);
1990                                    if (obj == null || !(obj instanceof ScalarDS)) { // no
1991                                                                                     // selection
1992                                        strVal = null;
1993                                    }
1994                                    else {
1995                                        ScalarDS dset = (ScalarDS) obj;
1996                                        try {
1997                                            dset.init();
1998                                        }
1999                                        catch (Exception ex) {
2000                                            log.debug("reference dset did not init()", ex);
2001                                        }
2002                                        StringBuffer selectionSB = new StringBuffer();
2003                                        StringBuffer strvalSB = new StringBuffer();
2004
2005                                        int idx = 0;
2006                                        while (st.hasMoreTokens()) {
2007                                            log.trace("JTable.ScalarDS isCellSelected: st.hasMoreTokens() begin");
2008
2009                                            int rank = dset.getRank();
2010                                            long start[] = dset.getStartDims();
2011                                            long count[] = dset.getSelectedDims();
2012                                            // long count[] = new long[rank];
2013
2014                                            // set the selected dimension sizes
2015                                            // based on the region selection
2016                                            // info.
2017                                            String sizeStr = null;
2018                                            String token = st.nextToken();
2019
2020                                            selectionSB.setLength(0);
2021                                            selectionSB.append(token);
2022                                            log.trace("JTable.ScalarDS isCellSelected: selectionSB={}", selectionSB);
2023
2024                                            token = token.replace('(', ' ');
2025                                            token = token.replace(')', ' ');
2026                                            if (isPointSelection) {
2027                                                // point selection
2028                                                String[] tmp = token.split(",");
2029                                                for (int x = 0; x < tmp.length; x++) {
2030                                                    count[x] = 1;
2031                                                    sizeStr = tmp[x].trim();
2032                                                    start[x] = Long.valueOf(sizeStr);
2033                                                    log.trace("JTable.ScalarDS isCellSelected: point sel={}", tmp[x]);
2034                                                }
2035                                            }
2036                                            else {
2037                                                // rectangle selection
2038                                                String startStr = token.substring(0, token.indexOf('-'));
2039                                                String endStr = token.substring(token.indexOf('-') + 1);
2040                                                log.trace("JTable.ScalarDS isCellSelected: rect sel with startStr={} endStr={}",
2041                                                        startStr, endStr);
2042                                                String[] tmp = startStr.split(",");
2043                                                log.trace("JTable.ScalarDS isCellSelected: tmp with length={} rank={}", tmp.length,
2044                                                        rank);
2045                                                for (int x = 0; x < tmp.length; x++) {
2046                                                    sizeStr = tmp[x].trim();
2047                                                    start[x] = Long.valueOf(sizeStr);
2048                                                    log.trace("JTable.ScalarDS isCellSelected: rect start={}", tmp[x]);
2049                                                }
2050                                                tmp = endStr.split(",");
2051                                                for (int x = 0; x < tmp.length; x++) {
2052                                                    sizeStr = tmp[x].trim();
2053                                                    count[x] = Long.valueOf(sizeStr) - start[x] + 1;
2054                                                    log.trace("JTable.ScalarDS isCellSelected: rect end={} count={}", tmp[x],
2055                                                            count[x]);
2056                                                }
2057                                            }
2058                                            log.trace("JTable.ScalarDS isCellSelected: selection inited");
2059
2060                                            Object dbuf = null;
2061                                            try {
2062                                                dbuf = dset.getData();
2063                                            }
2064                                            catch (Exception ex) {
2065                                                JOptionPane.showMessageDialog(this, ex, "Region Reference:" + getTitle(),
2066                                                        JOptionPane.ERROR_MESSAGE);
2067                                            }
2068
2069                                            // Convert dbuf to a displayable
2070                                            // string
2071                                            String cName = dbuf.getClass().getName();
2072                                            int cIndex = cName.lastIndexOf("[");
2073                                            if (cIndex >= 0) {
2074                                                NT = cName.charAt(cIndex + 1);
2075                                            }
2076                                            log.trace("JTable.ScalarDS isCellSelected: cName={} NT={}", cName, NT);
2077
2078                                            if (idx > 0) strvalSB.append(',');
2079
2080                                            // convert numerical data into char
2081                                            // only possible cases are byte[]
2082                                            // and short[] (converted from
2083                                            // unsigned
2084                                            // byte)
2085                                            Datatype dtype = dset.getDatatype();
2086                                            Datatype baseType = dtype.getBasetype();
2087                                            log.trace("JTable.ScalarDS isCellSelected: dtype={} baseType={}",
2088                                                    dtype.getDatatypeDescription(), baseType);
2089                                            if (baseType == null) baseType = dtype;
2090                                            if ((dtype.getDatatypeClass() == Datatype.CLASS_ARRAY && baseType.getDatatypeClass() == Datatype.CLASS_CHAR)
2091                                                    && ((NT == 'B') || (NT == 'S'))) {
2092                                                int n = Array.getLength(dbuf);
2093                                                log.trace("JTable.ScalarDS isCellSelected charData length = {}", n);
2094                                                char[] charData = new char[n];
2095                                                for (int i = 0; i < n; i++) {
2096                                                    if (NT == 'B') {
2097                                                        charData[i] = (char) Array.getByte(dbuf, i);
2098                                                    }
2099                                                    else if (NT == 'S') {
2100                                                        charData[i] = (char) Array.getShort(dbuf, i);
2101                                                    }
2102                                                }
2103
2104                                                strvalSB.append(charData);
2105                                                log.trace("JTable.ScalarDS isCellSelected charData");// =
2106                                                                                                     // {}",
2107                                                                                                     // strvalSB);
2108                                            }
2109                                            else {
2110                                                // numerical values
2111                                                if (dtype.getDatatypeClass() == Datatype.CLASS_ARRAY) dtype = baseType;
2112                                                boolean is_unsigned = dtype.isUnsigned();
2113                                                int n = Array.getLength(dbuf);
2114                                                if (is_unsigned) {
2115                                                    switch (NT) {
2116                                                        case 'B':
2117                                                            byte[] barray = (byte[]) dbuf;
2118                                                            short sValue = barray[0];
2119                                                            if (sValue < 0) {
2120                                                                sValue += 256;
2121                                                            }
2122                                                            strvalSB.append(sValue);
2123                                                            for (int i = 1; i < n; i++) {
2124                                                                strvalSB.append(',');
2125                                                                sValue = barray[i];
2126                                                                if (sValue < 0) {
2127                                                                    sValue += 256;
2128                                                                }
2129                                                                strvalSB.append(sValue);
2130                                                            }
2131                                                            break;
2132                                                        case 'S':
2133                                                            short[] sarray = (short[]) dbuf;
2134                                                            int iValue = sarray[0];
2135                                                            if (iValue < 0) {
2136                                                                iValue += 65536;
2137                                                            }
2138                                                            strvalSB.append(iValue);
2139                                                            for (int i = 1; i < n; i++) {
2140                                                                strvalSB.append(',');
2141                                                                iValue = sarray[i];
2142                                                                if (iValue < 0) {
2143                                                                    iValue += 65536;
2144                                                                }
2145                                                                strvalSB.append(iValue);
2146                                                            }
2147                                                            break;
2148                                                        case 'I':
2149                                                            int[] iarray = (int[]) dbuf;
2150                                                            long lValue = iarray[0];
2151                                                            if (lValue < 0) {
2152                                                                lValue += 4294967296L;
2153                                                            }
2154                                                            strvalSB.append(lValue);
2155                                                            for (int i = 1; i < n; i++) {
2156                                                                strvalSB.append(',');
2157                                                                lValue = iarray[i];
2158                                                                if (lValue < 0) {
2159                                                                    lValue += 4294967296L;
2160                                                                }
2161                                                                strvalSB.append(lValue);
2162                                                            }
2163                                                            break;
2164                                                        case 'J':
2165                                                            long[] larray = (long[]) dbuf;
2166                                                            Long l = (Long) larray[0];
2167                                                            String theValue = Long.toString(l);
2168                                                            if (l < 0) {
2169                                                                l = (l << 1) >>> 1;
2170                                                                BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65
2171                                                                BigInteger big2 = new BigInteger(l.toString());
2172                                                                BigInteger big = big1.add(big2);
2173                                                                theValue = big.toString();
2174                                                            }
2175                                                            strvalSB.append(theValue);
2176                                                            for (int i = 1; i < n; i++) {
2177                                                                strvalSB.append(',');
2178                                                                l = (Long) larray[i];
2179                                                                theValue = Long.toString(l);
2180                                                                if (l < 0) {
2181                                                                    l = (l << 1) >>> 1;
2182                                                                    BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65
2183                                                                    BigInteger big2 = new BigInteger(l.toString());
2184                                                                    BigInteger big = big1.add(big2);
2185                                                                    theValue = big.toString();
2186                                                                }
2187                                                                strvalSB.append(theValue);
2188                                                            }
2189                                                            break;
2190                                                        default:
2191                                                            strvalSB.append(Array.get(dbuf, 0));
2192                                                            for (int i = 1; i < n; i++) {
2193                                                                strvalSB.append(',');
2194                                                                strvalSB.append(Array.get(dbuf, i));
2195                                                            }
2196                                                            break;
2197                                                    }
2198                                                }
2199                                                else {
2200                                                    for (int x = 0; x < n; x++) {
2201                                                        Object theValue = Array.get(dbuf, x);
2202                                                        if (x > 0) strvalSB.append(',');
2203                                                        strvalSB.append(theValue);
2204                                                    }
2205                                                }
2206                                                log.trace("JTable.ScalarDS isCellSelected byteString");// =
2207                                                                                                       // {}",
2208                                                                                                       // strvalSB);
2209                                            }
2210                                            idx++;
2211                                            dset.clearData();
2212                                            log.trace("JTable.ScalarDS isCellSelected: st.hasMoreTokens() end");// strvalSB
2213                                                                                                                // =
2214                                                                                                                // {}",
2215                                                                                                                // strvalSB);
2216                                        } // while (st.hasMoreTokens())
2217                                        strVal = strvalSB.toString();
2218                                        log.trace("JTable.ScalarDS isCellSelected: st.hasMoreTokens() end");// value
2219                                                                                                            // =
2220                                                                                                            // {}",
2221                                                                                                            // strVal);
2222                                    }
2223                                }
2224                            }
2225                        }
2226                        else {
2227                            strVal = null;
2228                        }
2229                    }
2230                    else if (isObjRef) {
2231                        Long ref = (Long) val;
2232                        long oid[] = { ref.longValue() };
2233
2234                        // decode object ID
2235                        try {
2236                            HObject obj = FileFormat.findObject(dataset.getFileFormat(), oid);
2237                            strVal = obj.getFullName();
2238                        }
2239                        catch (Exception ex) {
2240                            strVal = null;
2241                        }
2242                    }
2243
2244                    if (strVal == null && val != null) strVal = val.toString();
2245
2246                    log.trace("JTable.ScalarDS isCellSelected finish");// value
2247                                                                       // =
2248                                                                       // {}",strVal);
2249                    cellValueField.setText(strVal);
2250                }
2251
2252                return super.isCellSelected(row, column);
2253            }
2254        };
2255        theTable.setName("ScalarDS");
2256
2257        log.trace("createTable: ScalarDS finish");
2258        return theTable;
2259    }
2260
2261    /**
2262     * Creates a JTable to hold a compound dataset.
2263     */
2264    private JTable createTable (CompoundDS d) {
2265        JTable theTable = null;
2266        log.trace("createTable: CompoundDS start");
2267
2268        int rank = d.getRank();
2269        if (rank <= 0) {
2270            d.init();
2271        }
2272
2273        long[] startArray = d.getStartDims();
2274        long[] strideArray = d.getStride();
2275        int[] selectedIndex = d.getSelectedIndex();
2276        final int rowStart = (int) startArray[selectedIndex[0]];
2277        final int rowStride = (int) strideArray[selectedIndex[0]];
2278
2279        // use lazy convert for large number of strings
2280        if (d.getHeight() > 10000) {
2281            d.setConvertByteToString(false);
2282        }
2283
2284        dataValue = null;
2285        try {
2286            dataValue = d.getData();
2287        }
2288        catch (Throwable ex) {
2289            log.debug("getData failure: ", ex);
2290            toolkit.beep();
2291            JOptionPane.showMessageDialog(this, ex, "TableView" + getTitle(), JOptionPane.ERROR_MESSAGE);
2292            dataValue = null;
2293        }
2294
2295        if ((dataValue == null) || !(dataValue instanceof List)) {
2296            return null;
2297        }
2298
2299        final int rows = d.getHeight();
2300        int cols = d.getSelectedMemberCount();
2301        String[] columnNames = new String[cols];
2302
2303        int idx = 0;
2304        String[] columnNamesAll = d.getMemberNames();
2305        for (int i = 0; i < columnNamesAll.length; i++) {
2306            if (d.isMemberSelected(i)) {
2307                columnNames[idx] = columnNamesAll[i];
2308                columnNames[idx] = columnNames[idx].replaceAll(CompoundDS.separator, "->");
2309                idx++;
2310            }
2311        }
2312
2313        String[] subColumnNames = columnNames;
2314        int columns = d.getWidth();
2315        if (columns > 1) {
2316            // multi-dimension compound dataset
2317            subColumnNames = new String[columns * columnNames.length];
2318            int halfIdx = columnNames.length / 2;
2319            for (int i = 0; i < columns; i++) {
2320                for (int j = 0; j < columnNames.length; j++) {
2321                    // display column index only once, in the middle of the
2322                    // compound fields
2323                    if (j == halfIdx) {
2324                        // subColumnNames[i * columnNames.length + j] = (i + 1)
2325                        // + "\n " + columnNames[j];
2326                        subColumnNames[i * columnNames.length + j] = (i + indexBase) + "\n " + columnNames[j];
2327                    }
2328                    else {
2329                        subColumnNames[i * columnNames.length + j] = " \n " + columnNames[j];
2330                    }
2331                }
2332            }
2333        }
2334
2335        final String[] allColumnNames = subColumnNames;
2336        AbstractTableModel tm = new AbstractTableModel() {
2337            private static final long serialVersionUID = -2176296469630678304L;
2338            CompoundDS                compound         = (CompoundDS) dataset;
2339            int                       orders[]         = compound.getSelectedMemberOrders();
2340            Datatype                  types[]          = compound.getSelectedMemberTypes();
2341            StringBuffer              stringBuffer     = new StringBuffer();
2342            int                       nFields          = ((List<?>) dataValue).size();
2343            int                       nRows            = getRowCount();
2344            int                       nSubColumns      = (nFields > 0) ? getColumnCount() / nFields : 0;
2345
2346            @Override
2347            public int getColumnCount ( ) {
2348                return allColumnNames.length;
2349            }
2350
2351            @Override
2352            public int getRowCount ( ) {
2353                return rows;
2354            }
2355
2356            @Override
2357            public String getColumnName (int col) {
2358                return allColumnNames[col];
2359            }
2360
2361            @Override
2362            public Object getValueAt (int row, int col) {
2363                if (startEditing[0]) return "";
2364
2365                int fieldIdx = col;
2366                int rowIdx = row;
2367                char CNT = ' ';
2368                boolean CshowAsHex = false;
2369                boolean CshowAsBin = false;
2370                log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt({},{}) start", row, col);
2371
2372                if (nSubColumns > 1) { // multi-dimension compound dataset
2373                    int colIdx = col / nFields;
2374                    fieldIdx = col - colIdx * nFields;
2375                    // BUG 573: rowIdx = row * orders[fieldIdx] + colIdx * nRows
2376                    // * orders[fieldIdx];
2377                    rowIdx = row * orders[fieldIdx] * nSubColumns + colIdx * orders[fieldIdx];
2378                    log.trace(
2379                            "CompoundDS:createTable:AbstractTableModel:getValueAt() row={} orders[{}]={} nSubColumns={} colIdx={}",
2380                            row, fieldIdx, orders[fieldIdx], nSubColumns, colIdx);
2381                }
2382                else {
2383                    rowIdx = row * orders[fieldIdx];
2384                    log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() row={} orders[{}]={}", row, fieldIdx,
2385                            orders[fieldIdx]);
2386                }
2387                log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() fieldIdx={} rowIdx={}", fieldIdx, rowIdx);
2388
2389                Object colValue = ((List<?>) dataValue).get(fieldIdx);
2390                if (colValue == null) {
2391                    return "Null";
2392                }
2393
2394                stringBuffer.setLength(0); // clear the old string
2395                Datatype dtype = types[fieldIdx];
2396                boolean isString = (dtype.getDatatypeClass() == Datatype.CLASS_STRING);
2397                boolean isArray = (dtype.getDatatypeClass() == Datatype.CLASS_ARRAY);
2398                if (isArray) {
2399                    dtype = types[fieldIdx].getBasetype();
2400                    isString = (dtype.getDatatypeClass() == Datatype.CLASS_STRING);
2401                    log.trace("**CompoundDS:createTable:AbstractTableModel:getValueAt(): isArray={} isString={}", isArray, isString);
2402
2403                    if (dtype instanceof H5Datatype) {
2404                        // Since variable-length strings are of type CLASS_STRING, not CLASS_VLEN,
2405                        // the check below cannot determine if the datatype is a variable-length string
2406                        if (((H5Datatype) dtype).isVLEN() && isString) {
2407                            for (int i = 0; i < orders[fieldIdx]; i++) {
2408                                if (i > 0) stringBuffer.append(", ");
2409                                stringBuffer.append(((String[]) colValue)[i]);
2410                            }
2411                            return stringBuffer;
2412                        }
2413                    }
2414                    else if (dtype.getDatatypeClass() == Datatype.CLASS_VLEN) {
2415                        // Only support variable length strings
2416                        if (!(dtype.getBasetype().getDatatypeClass() == Datatype.CLASS_STRING)) {
2417                            int arraylen = (int) types[fieldIdx].getDatatypeSize();
2418                            log.trace("**CompoundDS:createTable:AbstractTableModel:getValueAt(): isArray={} of {} istype={}", isArray, arraylen, dtype);
2419                            String str = new String( "*unsupported*");
2420                            stringBuffer.append(str.trim());
2421                            return stringBuffer;
2422                        }
2423                    }
2424                }
2425                log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt(): isString={} getBasetype()={}", isString, types[fieldIdx].getDatatypeClass());
2426                if (isString && ((colValue instanceof byte[]) || isArray)) {
2427                    // strings
2428                    int strlen = dtype.getDatatypeSize();
2429                    int arraylen = strlen;
2430                    if(isArray) {
2431                        arraylen = types[fieldIdx].getDatatypeSize();
2432                    }
2433                    log.trace("**CompoundDS:createTable:AbstractTableModel:getValueAt(): isArray={} of {} isString={} of {}", isArray, arraylen, isString, strlen);
2434                    int arraycnt = arraylen / strlen;
2435                    for (int loopidx = 0; loopidx < arraycnt; loopidx++) {
2436                        if(isArray && loopidx > 0) {
2437                            stringBuffer.append(", ");
2438                        }
2439                        String str = new String(((byte[]) colValue), rowIdx * strlen + loopidx * strlen, strlen);
2440                        int idx = str.indexOf('\0');
2441                        if (idx > 0) {
2442                            str = str.substring(0, idx);
2443                        }
2444                        stringBuffer.append(str.trim());
2445                    }
2446                }
2447                else if (isArray && dtype.getDatatypeClass() == Datatype.CLASS_COMPOUND) {
2448                    for (int i = 0; i < orders[fieldIdx]; i++) {
2449                        try {
2450                            int tid = dtype.toNative();
2451                            int numberOfMembers = H5.H5Tget_nmembers(tid);
2452                            Object field_data = null;
2453
2454                            try {
2455                                field_data = Array.get(colValue, rowIdx + i);
2456                            }
2457                            catch (Exception ex) {
2458                                log.debug("CompoundDS:createTable:AbstractTableModel:getValueAt(): could not retrieve field_data: ", ex);
2459                            }
2460
2461                            if (i > 0) stringBuffer.append(", ");
2462                            stringBuffer.append("[ ");
2463
2464                            for (int j = 0; j < numberOfMembers; j++) {
2465                                Object theValue = null;
2466
2467                                try {
2468                                    theValue = Array.get(field_data, j);
2469                                    log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() theValue[{}]={}", j, theValue.toString());
2470                                }
2471                                catch (Exception ex) {
2472                                    log.debug("CompoundDS:createTable:AbstractTableModel:getValueAt() member[{}] is unsupported", j, ex);
2473                                    theValue = "*unsupported*";
2474                                }
2475
2476                                if (j > 0) stringBuffer.append(", ");
2477                                stringBuffer.append(theValue);
2478                            }
2479
2480                            stringBuffer.append(" ]");
2481                        }
2482                        catch (Exception ex) {
2483                            log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt(): ", ex);
2484                        }
2485                    }
2486
2487                    return stringBuffer;
2488                }
2489                else {
2490                    // numerical values
2491
2492                    String cName = colValue.getClass().getName();
2493                    int cIndex = cName.lastIndexOf("[");
2494                    if (cIndex >= 0) {
2495                        CNT = cName.charAt(cIndex + 1);
2496                    }
2497                    log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt(): cName={} CNT={}", cName, CNT);
2498
2499                    boolean isUINT64 = false;
2500                    boolean isInt = (CNT == 'B' || CNT == 'S' || CNT == 'I' || CNT == 'J');
2501                    boolean isEnum = dtype.getDatatypeClass() == Datatype.CLASS_ENUM;
2502                    int typeSize = dtype.getDatatypeSize();
2503
2504                    if ((dtype.getDatatypeClass() == Datatype.CLASS_BITFIELD)
2505                            || (dtype.getDatatypeClass() == Datatype.CLASS_OPAQUE)) {
2506                        CshowAsHex = true;
2507                        log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() class={} (BITFIELD or OPAQUE)",
2508                                dtype.getDatatypeClass());
2509                    }
2510                    if (dtype.isUnsigned()) {
2511                        if (cIndex >= 0) {
2512                            isUINT64 = (cName.charAt(cIndex + 1) == 'J');
2513                        }
2514                    }
2515                    log.trace(
2516                            "CompoundDS:createTable:AbstractTableModel:getValueAt() isUINT64={} isInt={} CshowAsHex={} typeSize={}",
2517                            isUINT64, isInt, CshowAsHex, typeSize);
2518
2519                    if (isEnum) {
2520                        String[] outValues = new String[getRowCount() * orders[fieldIdx]];
2521
2522                        if (!dataset.isEnumConverted()) {
2523                            try {
2524                                H5Datatype.convertEnumValueToName(dtype.toNative(), colValue, outValues);
2525                            }
2526                            catch (HDF5Exception ex) {
2527                                log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt(): Could not convert enum values to names: ex");
2528                                return stringBuffer;
2529                            }
2530                        }
2531                        else
2532                            outValues = (String[])colValue;
2533                        for (int i = rowIdx; i < (rowIdx + orders[fieldIdx]); i++) {
2534                            if (i > rowIdx) stringBuffer.append(", ");
2535                            stringBuffer.append(outValues[i]);
2536                        }
2537                    }
2538                    else {
2539                        for (int i = 0; i < orders[fieldIdx]; i++) {
2540                            log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt():for[{}]", i);
2541                            if (isUINT64) {
2542                                Object theValue = Array.get(colValue, rowIdx + i);
2543                                log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() isUINT64 theValue[{}]={}", i,
2544                                        theValue.toString());
2545                                Long l = (Long) theValue;
2546                                BigInteger big;
2547                                if (l < 0) {
2548                                    l = (l << 1) >>> 1;
2549                                    BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65
2550                                    BigInteger big2 = new BigInteger(l.toString());
2551                                    big = big1.add(big2);
2552                                }
2553                                else {
2554                                    big = new BigInteger(l.toString());
2555                                }
2556                                if (showAsHex)
2557                                    theValue = Tools.toHexString(big.longValue(), typeSize);// big.toString(16);
2558                                else if (showAsBin)
2559                                    theValue = Tools.toBinaryString(big.longValue(), typeSize);
2560                                else
2561                                    theValue = big.toString(10);
2562
2563                                if (i > 0) stringBuffer.append(", ");
2564                                stringBuffer.append(theValue);
2565                            }
2566                            else if (CshowAsHex && isInt) {
2567                                char[] hexArray = "0123456789ABCDEF".toCharArray();
2568                                Object theValue = Array.get(colValue, rowIdx * typeSize + typeSize * i);
2569                                log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() CshowAsHex theValue[{}]={}", i,
2570                                        theValue.toString());
2571                                // show in Hexadecimal
2572                                char[] hexChars = new char[2];
2573                                if (i > 0) stringBuffer.append(", ");
2574                                for (int x = 0; x < typeSize; x++) {
2575                                    if (x > 0)
2576                                        theValue = Array.get(colValue, rowIdx * typeSize + typeSize * i + x);
2577                                    int v = (int) ((Byte) theValue) & 0xFF;
2578                                    hexChars[0] = hexArray[v >>> 4];
2579                                    hexChars[1] = hexArray[v & 0x0F];
2580                                    if (x > 0) stringBuffer.append(":");
2581                                    stringBuffer.append(hexChars);
2582                                    log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() hexChars[{}]={}", x, hexChars);
2583                                }
2584                            }
2585                            else if (showAsBin && isInt) {
2586                                Object theValue = Array.get(colValue, rowIdx + typeSize * i);
2587                                log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() showAsBin theValue[{}]={}", i,
2588                                        theValue.toString());
2589                                theValue = Tools.toBinaryString(Long.valueOf(theValue.toString()), typeSize);
2590                                if (i > 0) stringBuffer.append(", ");
2591                                stringBuffer.append(theValue);
2592                            }
2593                            else if (numberFormat != null) {
2594                                // show in scientific format
2595                                Object theValue = Array.get(colValue, rowIdx + i);
2596                                log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() numberFormat theValue[{}]={}", i,
2597                                        theValue.toString());
2598                                theValue = numberFormat.format(theValue);
2599                                if (i > 0) stringBuffer.append(", ");
2600                                stringBuffer.append(theValue);
2601                            }
2602                            else {
2603                                Object theValue = Array.get(colValue, rowIdx + i);
2604                                log.trace("CompoundDS:createTable:AbstractTableModel:getValueAt() theValue[{}]={}", i,
2605                                        theValue.toString());
2606                                if (i > 0) stringBuffer.append(", ");
2607                                stringBuffer.append(theValue);
2608                            }
2609                        }
2610                    } // end of else {
2611                } // end of else {
2612
2613                return stringBuffer;
2614            }
2615        };
2616
2617        theTable = new JTable(tm) {
2618            private static final long serialVersionUID   = 3221288637329958074L;
2619            int                       lastSelectedRow    = -1;
2620            int                       lastSelectedColumn = -1;
2621
2622            @Override
2623            public boolean isCellEditable (int row, int column) {
2624                return !isReadOnly;
2625            }
2626
2627            @Override
2628            public boolean editCellAt (int row, int column, java.util.EventObject e) {
2629                if (!isCellEditable(row, column)) {
2630                    return super.editCellAt(row, column, e);
2631                }
2632
2633                if (e instanceof KeyEvent) {
2634                    KeyEvent ke = (KeyEvent) e;
2635                    if (ke.getID() == KeyEvent.KEY_PRESSED) startEditing[0] = true;
2636                }
2637                else if (e instanceof MouseEvent) {
2638                    MouseEvent me = (MouseEvent) e;
2639                    int mc = me.getClickCount();
2640                    if (mc > 1) {
2641                        currentEditingCellValue = getValueAt(row, column);
2642                    }
2643                }
2644
2645                return super.editCellAt(row, column, e);
2646            }
2647
2648            @Override
2649            public void editingStopped (ChangeEvent e) {
2650                int row = getEditingRow();
2651                int col = getEditingColumn();
2652                super.editingStopped(e);
2653                startEditing[0] = false;
2654
2655                Object source = e.getSource();
2656
2657                if (source instanceof CellEditor) {
2658                    CellEditor editor = (CellEditor) source;
2659                    String cellValue = (String) editor.getCellEditorValue();
2660
2661                    try {
2662                        updateValueInMemory(cellValue, row, col);
2663                    }
2664                    catch (Exception ex) {
2665                        log.debug("updateValueInMemory: ", ex);
2666                        toolkit.beep();
2667                        JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
2668                    }
2669                } // if (source instanceof CellEditor)
2670            }
2671
2672            @Override
2673            public boolean isCellSelected (int row, int column) {
2674                if ((lastSelectedRow == row) && (lastSelectedColumn == column)) {
2675                    return super.isCellSelected(row, column);
2676                }
2677                log.trace("JTable.CompoundDS isCellSelected row={} column={}", row, column);
2678
2679                lastSelectedRow = row;
2680                lastSelectedColumn = column;
2681                if ((getSelectedRow() == row) && (getSelectedColumn() == column)) {
2682                    cellLabel.setText(String.valueOf(rowStart + indexBase + row * rowStride) + ", " + table.getColumnName(column)
2683                            + "  =  ");
2684                    cellValueField.setText(getValueAt(row, column).toString());
2685                }
2686
2687                return super.isCellSelected(row, column);
2688            }
2689        };
2690
2691        if (columns > 1) {
2692            // multi-dimension compound dataset
2693            MultiLineHeaderRenderer renderer = new MultiLineHeaderRenderer(columns, columnNames.length);
2694            Enumeration<?> local_enum = theTable.getColumnModel().getColumns();
2695            while (local_enum.hasMoreElements()) {
2696                ((TableColumn) local_enum.nextElement()).setHeaderRenderer(renderer);
2697            }
2698        }
2699        theTable.setName("CompoundDS");
2700
2701        log.trace("createTable: CompoundDS finish");
2702        return theTable;
2703    } /* createTable */
2704
2705    private void gotoPage (long idx) {
2706        if (dataset.getRank() < 3 || idx == (curFrame - indexBase)) {
2707            return;
2708        }
2709
2710        if (isValueChanged) {
2711            updateValueInFile();
2712        }
2713
2714        long[] start = dataset.getStartDims();
2715        int[] selectedIndex = dataset.getSelectedIndex();
2716        long[] dims = dataset.getDims();
2717
2718        if ((idx < 0) || (idx >= dims[selectedIndex[2]])) {
2719            toolkit.beep();
2720            JOptionPane.showMessageDialog(this, "Frame number must be between" + indexBase + " and "
2721                    + (dims[selectedIndex[2]] - 1 + indexBase), getTitle(), JOptionPane.ERROR_MESSAGE);
2722            return;
2723        }
2724
2725        start[selectedIndex[2]] = idx;
2726        curFrame = idx + indexBase;
2727        dataset.clearData();
2728
2729        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
2730
2731        try {
2732            dataValue = dataset.getData();
2733            if (dataset instanceof ScalarDS) {
2734                ((ScalarDS) dataset).convertFromUnsignedC();
2735                dataValue = dataset.getData();
2736            }
2737        }
2738        catch (Exception ex) {
2739            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
2740            dataValue = null;
2741            JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
2742            return;
2743        }
2744
2745        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
2746
2747        frameField.setText(String.valueOf(curFrame));
2748        updateUI();
2749    }
2750
2751    /** copy data from the spreadsheet to the system clipboard. */
2752    private void copyData ( ) {
2753        StringBuffer sb = new StringBuffer();
2754
2755        int r0 = table.getSelectedRow(); // starting row
2756        int c0 = table.getSelectedColumn(); // starting column
2757
2758        if ((r0 < 0) || (c0 < 0)) {
2759            return;
2760        }
2761
2762        int nr = table.getSelectedRowCount();
2763        int nc = table.getSelectedColumnCount();
2764        int r1 = r0 + nr; // finish row
2765        int c1 = c0 + nc; // finishing column
2766
2767        try {
2768            for (int i = r0; i < r1; i++) {
2769                sb.append(table.getValueAt(i, c0).toString());
2770                for (int j = c0 + 1; j < c1; j++) {
2771                    sb.append("\t");
2772                    sb.append(table.getValueAt(i, j).toString());
2773                }
2774                sb.append("\n");
2775            }
2776        }
2777        catch (java.lang.OutOfMemoryError err) {
2778            toolkit.beep();
2779            JOptionPane.showMessageDialog((JFrame) viewer,
2780                    "Copying data to system clipboard failed. \nUsing \"export/import data\" for copying/pasting large data.",
2781                    getTitle(), JOptionPane.ERROR_MESSAGE);
2782            return;
2783        }
2784
2785        Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
2786        StringSelection contents = new StringSelection(sb.toString());
2787        cb.setContents(contents, null);
2788    }
2789
2790    /** paste data from the system clipboard to the spreadsheet. */
2791    private void pasteData ( ) {
2792        int pasteDataFlag = JOptionPane.showConfirmDialog(this, "Do you want to paste selected data?", this.getTitle(),
2793                JOptionPane.YES_NO_OPTION);
2794        if (pasteDataFlag == JOptionPane.NO_OPTION) {
2795            return;
2796        }
2797
2798        int cols = table.getColumnCount();
2799        int rows = table.getRowCount();
2800        int r0 = table.getSelectedRow();
2801        int c0 = table.getSelectedColumn();
2802
2803        if (c0 < 0) {
2804            c0 = 0;
2805        }
2806        if (r0 < 0) {
2807            r0 = 0;
2808        }
2809        int r = r0;
2810        int c = c0;
2811
2812        Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
2813        // Transferable content = cb.getContents(this);
2814        String line = "";
2815        try {
2816            String s = (String) cb.getData(DataFlavor.stringFlavor);
2817
2818            StringTokenizer st = new StringTokenizer(s, "\n");
2819            // read line by line
2820            while (st.hasMoreTokens() && (r < rows)) {
2821                line = st.nextToken();
2822
2823                if (fixedDataLength < 1) {
2824                    // separate by delimiter
2825                    StringTokenizer lt = new StringTokenizer(line, "\t");
2826                    while (lt.hasMoreTokens() && (c < cols)) {
2827                        try {
2828                            updateValueInMemory(lt.nextToken(), r, c);
2829                        }
2830                        catch (Exception ex) {
2831                            continue;
2832                        }
2833                        c++;
2834                    }
2835                    r = r + 1;
2836                    c = c0;
2837                }
2838                else {
2839                    // the data has fixed length
2840                    int n = line.length();
2841                    String theVal;
2842                    for (int i = 0; i < n; i = i + fixedDataLength) {
2843                        try {
2844                            theVal = line.substring(i, i + fixedDataLength);
2845                            updateValueInMemory(theVal, r, c);
2846                        }
2847                        catch (Exception ex) {
2848                            continue;
2849                        }
2850                        c++;
2851                    }
2852                }
2853            }
2854        }
2855        catch (Throwable ex) {
2856            toolkit.beep();
2857            JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
2858        }
2859
2860        table.updateUI();
2861    }
2862
2863    /**
2864     * import data values from text file.
2865     */
2866    private void importTextData (String fname) {
2867        int pasteDataFlag = JOptionPane.showConfirmDialog(this, "Do you want to paste selected data?", this.getTitle(),
2868                JOptionPane.YES_NO_OPTION);
2869        if (pasteDataFlag == JOptionPane.NO_OPTION) {
2870            return;
2871        }
2872        int cols = table.getColumnCount();
2873        int rows = table.getRowCount();
2874        int r0 = table.getSelectedRow();
2875        int c0 = table.getSelectedColumn();
2876
2877        if (c0 < 0) {
2878            c0 = 0;
2879        }
2880        if (r0 < 0) {
2881            r0 = 0;
2882        }
2883
2884        // start at the first column for compound datasets
2885        if (dataset instanceof CompoundDS) c0 = 0;
2886
2887        BufferedReader in = null;
2888        try {
2889            in = new BufferedReader(new FileReader(fname));
2890        }
2891        catch (FileNotFoundException ex) {
2892            log.debug("import data values from text file {}:", fname, ex);
2893            return;
2894        }
2895
2896        String line = null;
2897        StringTokenizer tokenizer1 = null;
2898
2899        try {
2900            line = in.readLine();
2901        }
2902        catch (IOException ex) {
2903            try {
2904                in.close();
2905            }
2906            catch (IOException ex2) {
2907                log.debug("close text file {}:", fname, ex2);
2908            }
2909            log.debug("read text file {}:", fname, ex);
2910            return;
2911        }
2912
2913        String delName = ViewProperties.getDataDelimiter();
2914        String delimiter = "";
2915
2916        // delimiter must include a tab to be consistent with copy/paste for
2917        // compound fields
2918        if (dataset instanceof CompoundDS)
2919            delimiter = "\t";
2920        else {
2921            if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_TAB)) {
2922                delimiter = "\t";
2923            }
2924            else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_SPACE)) {
2925                delimiter = " " + delimiter;
2926            }
2927            else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_COMMA)) {
2928                delimiter = ",";
2929            }
2930            else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_COLON)) {
2931                delimiter = ":";
2932            }
2933            else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_SEMI_COLON)) {
2934                delimiter = ";";
2935            }
2936        }
2937        String token = null;
2938        int r = r0;
2939        int c = c0;
2940        while ((line != null) && (r < rows)) {
2941            if (fixedDataLength > 0) {
2942                // the data has fixed length
2943                int n = line.length();
2944                String theVal;
2945                for (int i = 0; i < n; i = i + fixedDataLength) {
2946                    try {
2947                        theVal = line.substring(i, i + fixedDataLength);
2948                        updateValueInMemory(theVal, r, c);
2949                    }
2950                    catch (Exception ex) {
2951                        continue;
2952                    }
2953                    c++;
2954                }
2955            }
2956            else {
2957                try {
2958                    tokenizer1 = new StringTokenizer(line, delimiter);
2959                    while (tokenizer1.hasMoreTokens() && (c < cols)) {
2960                        token = tokenizer1.nextToken();
2961                        if (dataset instanceof ScalarDS) {
2962                            StringTokenizer tokenizer2 = new StringTokenizer(token);
2963                            while (tokenizer2.hasMoreTokens() && (c < cols)) {
2964                                updateValueInMemory(tokenizer2.nextToken(), r, c);
2965                                c++;
2966                            }
2967                        }
2968                        else {
2969                            updateValueInMemory(token, r, c);
2970                            c++;
2971                        }
2972                    } // while (tokenizer1.hasMoreTokens() && index < size)
2973                }
2974                catch (Exception ex) {
2975                    JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
2976                    try {
2977                        in.close();
2978                    }
2979                    catch (IOException ex2) {
2980                        log.debug("close text file {}:", fname, ex2);
2981                    }
2982                    return;
2983                }
2984            }
2985
2986            try {
2987                line = in.readLine();
2988            }
2989            catch (IOException ex) {
2990                log.debug("read text file {}:", fname, ex);
2991                line = null;
2992            }
2993            c = 0;
2994            r++;
2995        } // while ((line != null) && (r < rows))
2996
2997        try {
2998            in.close();
2999        }
3000        catch (IOException ex) {
3001            log.debug("close text file {}:", fname, ex);
3002        }
3003
3004        table.updateUI();
3005    }
3006
3007    /**
3008     * import data values from binary file.
3009     */
3010    private void importBinaryData ( ) {
3011        String currentDir = dataset.getFileFormat().getParent();
3012        JFileChooser fchooser = new JFileChooser(currentDir);
3013        fchooser.setFileFilter(DefaultFileFilter.getFileFilterBinary());
3014        int returnVal = fchooser.showOpenDialog(this);
3015
3016        if (returnVal != JFileChooser.APPROVE_OPTION) {
3017            return;
3018        }
3019        File choosedFile = fchooser.getSelectedFile();
3020        if (choosedFile == null) {
3021            return;
3022        }
3023        String fname = choosedFile.getAbsolutePath();
3024
3025        int pasteDataFlag = JOptionPane.showConfirmDialog(this, "Do you want to paste selected data?", this.getTitle(),
3026                JOptionPane.YES_NO_OPTION);
3027        if (pasteDataFlag == JOptionPane.NO_OPTION) {
3028            return;
3029        }
3030
3031        getBinaryDatafromFile(fname);
3032    }
3033
3034    /** Reads data from a binary file into a buffer and updates table. */
3035    private void getBinaryDatafromFile (String fileName) {
3036        String fname = fileName;
3037        FileInputStream inputFile = null;
3038        BufferedInputStream in = null;
3039        ByteBuffer byteBuffer = null;
3040        try {
3041            inputFile = new FileInputStream(fname);
3042            long fileSize = inputFile.getChannel().size();
3043            in = new BufferedInputStream(inputFile);
3044
3045            Object data = dataset.getData();
3046            int datasetSize = Array.getLength(data);
3047            String cname = data.getClass().getName();
3048            char dname = cname.charAt(cname.lastIndexOf("[") + 1);
3049
3050            if (dname == 'B') {
3051                long datasetByteSize = datasetSize;
3052                byteBuffer = ByteBuffer.allocate(BYTE_BUFFER_SIZE);
3053                if (binaryOrder == 1)
3054                    byteBuffer.order(ByteOrder.nativeOrder());
3055                else if (binaryOrder == 2)
3056                    byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
3057                else if (binaryOrder == 3) byteBuffer.order(ByteOrder.BIG_ENDIAN);
3058
3059                int bufferSize = (int) Math.min(fileSize, datasetByteSize);
3060
3061                int remainingSize = bufferSize - (BYTE_BUFFER_SIZE);
3062                int allocValue = 0;
3063                int iterationNumber = 0;
3064                byte[] byteArray = new byte[BYTE_BUFFER_SIZE];
3065                do {
3066                    if (remainingSize <= 0) {
3067                        allocValue = remainingSize + (BYTE_BUFFER_SIZE);
3068                    }
3069                    else {
3070                        allocValue = (BYTE_BUFFER_SIZE);
3071                    }
3072
3073                    in.read(byteBuffer.array(), 0, allocValue);
3074
3075                    byteBuffer.get(byteArray, 0, allocValue);
3076                    System.arraycopy(byteArray, 0, dataValue, (iterationNumber * BYTE_BUFFER_SIZE), allocValue);
3077                    byteBuffer.clear();
3078                    remainingSize = remainingSize - (BYTE_BUFFER_SIZE);
3079                    iterationNumber++;
3080                } while (remainingSize > -(BYTE_BUFFER_SIZE));
3081
3082                isValueChanged = true;
3083            }
3084            else if (dname == 'S') {
3085                long datasetShortSize = datasetSize * 2;
3086                byteBuffer = ByteBuffer.allocate(SHORT_BUFFER_SIZE * 2);
3087                if (binaryOrder == 1)
3088                    byteBuffer.order(ByteOrder.nativeOrder());
3089                else if (binaryOrder == 2)
3090                    byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
3091                else if (binaryOrder == 3) byteBuffer.order(ByteOrder.BIG_ENDIAN);
3092
3093                int bufferSize = (int) Math.min(fileSize, datasetShortSize);
3094                int remainingSize = bufferSize - (SHORT_BUFFER_SIZE * 2);
3095                int allocValue = 0;
3096                int iterationNumber = 0;
3097                ShortBuffer sb = byteBuffer.asShortBuffer();
3098                short[] shortArray = new short[SHORT_BUFFER_SIZE];
3099
3100                do {
3101                    if (remainingSize <= 0) {
3102                        allocValue = remainingSize + (SHORT_BUFFER_SIZE * 2);
3103                    }
3104                    else {
3105                        allocValue = (SHORT_BUFFER_SIZE * 2);
3106                    }
3107                    in.read(byteBuffer.array(), 0, allocValue);
3108                    sb.get(shortArray, 0, allocValue / 2);
3109                    System.arraycopy(shortArray, 0, dataValue, (iterationNumber * SHORT_BUFFER_SIZE), allocValue / 2);
3110                    byteBuffer.clear();
3111                    sb.clear();
3112                    remainingSize = remainingSize - (SHORT_BUFFER_SIZE * 2);
3113                    iterationNumber++;
3114                } while (remainingSize > -(SHORT_BUFFER_SIZE * 2));
3115
3116                isValueChanged = true;
3117            }
3118            else if (dname == 'I') {
3119                long datasetIntSize = datasetSize * 4;
3120                byteBuffer = ByteBuffer.allocate(INT_BUFFER_SIZE * 4);
3121                if (binaryOrder == 1)
3122                    byteBuffer.order(ByteOrder.nativeOrder());
3123                else if (binaryOrder == 2)
3124                    byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
3125                else if (binaryOrder == 3) byteBuffer.order(ByteOrder.BIG_ENDIAN);
3126
3127                int bufferSize = (int) Math.min(fileSize, datasetIntSize);
3128                int remainingSize = bufferSize - (INT_BUFFER_SIZE * 4);
3129                int allocValue = 0;
3130                int iterationNumber = 0;
3131                int[] intArray = new int[INT_BUFFER_SIZE];
3132                byte[] tmpBuf = byteBuffer.array();
3133                IntBuffer ib = byteBuffer.asIntBuffer();
3134
3135                do {
3136                    if (remainingSize <= 0) {
3137                        allocValue = remainingSize + (INT_BUFFER_SIZE * 4);
3138                    }
3139                    else {
3140                        allocValue = (INT_BUFFER_SIZE * 4);
3141                    }
3142                    in.read(tmpBuf, 0, allocValue);
3143                    ib.get(intArray, 0, allocValue / 4);
3144                    System.arraycopy(intArray, 0, dataValue, (iterationNumber * INT_BUFFER_SIZE), allocValue / 4);
3145                    byteBuffer.clear();
3146                    ib.clear();
3147                    remainingSize = remainingSize - (INT_BUFFER_SIZE * 4);
3148                    iterationNumber++;
3149                } while (remainingSize > -(INT_BUFFER_SIZE * 4));
3150
3151                isValueChanged = true;
3152            }
3153            else if (dname == 'J') {
3154                long datasetLongSize = datasetSize * 8;
3155                byteBuffer = ByteBuffer.allocate(LONG_BUFFER_SIZE * 8);
3156
3157                if (binaryOrder == 1)
3158                    byteBuffer.order(ByteOrder.nativeOrder());
3159                else if (binaryOrder == 2)
3160                    byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
3161                else if (binaryOrder == 3) byteBuffer.order(ByteOrder.BIG_ENDIAN);
3162
3163                int bufferSize = (int) Math.min(fileSize, datasetLongSize);
3164                int remainingSize = bufferSize - (LONG_BUFFER_SIZE * 8);
3165                int allocValue = 0;
3166                int iterationNumber = 0;
3167                long[] longArray = new long[LONG_BUFFER_SIZE];
3168                LongBuffer lb = byteBuffer.asLongBuffer();
3169
3170                do {
3171                    if (remainingSize <= 0) {
3172                        allocValue = remainingSize + (LONG_BUFFER_SIZE * 8);
3173                    }
3174                    else {
3175                        allocValue = (LONG_BUFFER_SIZE * 8);
3176                    }
3177
3178                    in.read(byteBuffer.array(), 0, allocValue);
3179                    lb.get(longArray, 0, allocValue / 8);
3180                    System.arraycopy(longArray, 0, dataValue, (iterationNumber * LONG_BUFFER_SIZE), allocValue / 8);
3181                    byteBuffer.clear();
3182                    lb.clear();
3183                    remainingSize = remainingSize - (LONG_BUFFER_SIZE * 8);
3184                    iterationNumber++;
3185                } while (remainingSize > -(LONG_BUFFER_SIZE * 8));
3186
3187                isValueChanged = true;
3188            }
3189            else if (dname == 'F') {
3190                long datasetFloatSize = datasetSize * 4;
3191                byteBuffer = ByteBuffer.allocate(FLOAT_BUFFER_SIZE * 4);
3192                if (binaryOrder == 1)
3193                    byteBuffer.order(ByteOrder.nativeOrder());
3194                else if (binaryOrder == 2)
3195                    byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
3196                else if (binaryOrder == 3) byteBuffer.order(ByteOrder.BIG_ENDIAN);
3197
3198                int bufferSize = (int) Math.min(fileSize, datasetFloatSize);
3199                int remainingSize = bufferSize - (FLOAT_BUFFER_SIZE * 4);
3200                int allocValue = 0;
3201                int iterationNumber = 0;
3202                FloatBuffer fb = byteBuffer.asFloatBuffer();
3203                float[] floatArray = new float[FLOAT_BUFFER_SIZE];
3204                do {
3205                    if (remainingSize <= 0) {
3206                        allocValue = remainingSize + (FLOAT_BUFFER_SIZE * 4);
3207                    }
3208                    else {
3209                        allocValue = (FLOAT_BUFFER_SIZE * 4);
3210                    }
3211
3212                    in.read(byteBuffer.array(), 0, allocValue);
3213                    fb.get(floatArray, 0, allocValue / 4);
3214                    System.arraycopy(floatArray, 0, dataValue, (iterationNumber * FLOAT_BUFFER_SIZE), allocValue / 4);
3215                    byteBuffer.clear();
3216                    fb.clear();
3217                    remainingSize = remainingSize - (FLOAT_BUFFER_SIZE * 4);
3218                    iterationNumber++;
3219                } while (remainingSize > -(FLOAT_BUFFER_SIZE * 4));
3220
3221                isValueChanged = true;
3222            }
3223            else if (dname == 'D') {
3224                long datasetDoubleSize = datasetSize * 8;
3225                byteBuffer = ByteBuffer.allocate(DOUBLE_BUFFER_SIZE * 8);
3226                if (binaryOrder == 1)
3227                    byteBuffer.order(ByteOrder.nativeOrder());
3228                else if (binaryOrder == 2)
3229                    byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
3230                else if (binaryOrder == 3) byteBuffer.order(ByteOrder.BIG_ENDIAN);
3231
3232                int bufferSize = (int) Math.min(fileSize, datasetDoubleSize);
3233                int remainingSize = bufferSize - (DOUBLE_BUFFER_SIZE * 8);
3234                int allocValue = 0;
3235                int iterationNumber = 0;
3236                DoubleBuffer db = byteBuffer.asDoubleBuffer();
3237                double[] doubleArray = new double[DOUBLE_BUFFER_SIZE];
3238
3239                do {
3240                    if (remainingSize <= 0) {
3241                        allocValue = remainingSize + (DOUBLE_BUFFER_SIZE * 8);
3242                    }
3243                    else {
3244                        allocValue = (DOUBLE_BUFFER_SIZE * 8);
3245                    }
3246
3247                    in.read(byteBuffer.array(), 0, allocValue);
3248                    db.get(doubleArray, 0, allocValue / 8);
3249                    System.arraycopy(doubleArray, 0, dataValue, (iterationNumber * DOUBLE_BUFFER_SIZE), allocValue / 8);
3250                    byteBuffer.clear();
3251                    db.clear();
3252                    remainingSize = remainingSize - (DOUBLE_BUFFER_SIZE * 8);
3253                    iterationNumber++;
3254                } while (remainingSize > -(DOUBLE_BUFFER_SIZE * 8));
3255
3256                isValueChanged = true;
3257
3258            }
3259
3260        }
3261        catch (Exception es) {
3262            es.printStackTrace();
3263        }
3264        finally {
3265            try {
3266                in.close();
3267                inputFile.close();
3268            }
3269            catch (IOException ex) {
3270                log.debug("close binary file {}:", fname, ex);
3271            }
3272        }
3273        table.updateUI();
3274    }
3275
3276    /** Save data as text. */
3277    private void saveAsText ( ) throws Exception {
3278        final JFileChooser fchooser = new JFileChooser(dataset.getFile());
3279        fchooser.setFileFilter(DefaultFileFilter.getFileFilterText());
3280        // fchooser.changeToParentDirectory();
3281        fchooser.setDialogTitle("Save Current Data To Text File --- " + dataset.getName());
3282
3283        File choosedFile = new File(dataset.getName() + ".txt");
3284
3285        fchooser.setSelectedFile(choosedFile);
3286        int returnVal = fchooser.showSaveDialog(this);
3287
3288        if (returnVal != JFileChooser.APPROVE_OPTION) {
3289            return;
3290        }
3291
3292        choosedFile = fchooser.getSelectedFile();
3293        if (choosedFile == null) {
3294            return;
3295        }
3296        String fname = choosedFile.getAbsolutePath();
3297        log.trace("DefaultTableView saveAsText: file={}", fname);
3298
3299        // check if the file is in use
3300        List<?> fileList = viewer.getTreeView().getCurrentFiles();
3301        if (fileList != null) {
3302            FileFormat theFile = null;
3303            Iterator<?> iterator = fileList.iterator();
3304            while (iterator.hasNext()) {
3305                theFile = (FileFormat) iterator.next();
3306                if (theFile.getFilePath().equals(fname)) {
3307                    toolkit.beep();
3308                    JOptionPane.showMessageDialog(this, "Unable to save data to file \"" + fname + "\". \nThe file is being used.",
3309                            getTitle(), JOptionPane.ERROR_MESSAGE);
3310                    return;
3311                }
3312            }
3313        }
3314
3315        if (choosedFile.exists()) {
3316            int newFileFlag = JOptionPane.showConfirmDialog(this, "File exists. Do you want to replace it?", this.getTitle(),
3317                    JOptionPane.YES_NO_OPTION);
3318            if (newFileFlag == JOptionPane.NO_OPTION) {
3319                return;
3320            }
3321        }
3322
3323        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(choosedFile)));
3324
3325        String delName = ViewProperties.getDataDelimiter();
3326        String delimiter = "";
3327
3328        // delimiter must include a tab to be consistent with copy/paste for
3329        // compound fields
3330        if (dataset instanceof CompoundDS) delimiter = "\t";
3331
3332        if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_TAB)) {
3333            delimiter = "\t";
3334        }
3335        else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_SPACE)) {
3336            delimiter = " " + delimiter;
3337        }
3338        else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_COMMA)) {
3339            delimiter = "," + delimiter;
3340        }
3341        else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_COLON)) {
3342            delimiter = ":" + delimiter;
3343        }
3344        else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_SEMI_COLON)) {
3345            delimiter = ";" + delimiter;
3346        }
3347
3348        int cols = table.getColumnCount();
3349        int rows = table.getRowCount();
3350
3351        for (int i = 0; i < rows; i++) {
3352            out.print(table.getValueAt(i, 0));
3353            for (int j = 1; j < cols; j++) {
3354                out.print(delimiter);
3355                out.print(table.getValueAt(i, j));
3356            }
3357            out.println();
3358        }
3359
3360        out.flush();
3361        out.close();
3362
3363        viewer.showStatus("Data save to: " + fname);
3364    }
3365
3366    /** Save data as binary. */
3367    private void saveAsBinary ( ) throws Exception {
3368        final JFileChooser fchooser = new JFileChooser(dataset.getFile());
3369        fchooser.setFileFilter(DefaultFileFilter.getFileFilterBinary());
3370        // fchooser.changeToParentDirectory();
3371        fchooser.setDialogTitle("Save Current Data To Binary File --- " + dataset.getName());
3372
3373        File choosedFile = new File(dataset.getName() + ".bin");
3374        fchooser.setSelectedFile(choosedFile);
3375        int returnVal = fchooser.showSaveDialog(this);
3376
3377        if (returnVal != JFileChooser.APPROVE_OPTION) {
3378            return;
3379        }
3380
3381        choosedFile = fchooser.getSelectedFile();
3382        if (choosedFile == null) {
3383            return;
3384        }
3385        String fname = choosedFile.getAbsolutePath();
3386        log.trace("DefaultTableView saveAsBinary: file={}", fname);
3387
3388        // check if the file is in use
3389        List<?> fileList = viewer.getTreeView().getCurrentFiles();
3390        if (fileList != null) {
3391            FileFormat theFile = null;
3392            Iterator<?> iterator = fileList.iterator();
3393            while (iterator.hasNext()) {
3394                theFile = (FileFormat) iterator.next();
3395                if (theFile.getFilePath().equals(fname)) {
3396                    toolkit.beep();
3397                    JOptionPane.showMessageDialog(this, "Unable to save data to file \"" + fname + "\". \nThe file is being used.",
3398                            getTitle(), JOptionPane.ERROR_MESSAGE);
3399                    return;
3400                }
3401            }
3402        }
3403
3404        // check if the file exists
3405        if (choosedFile.exists()) {
3406            int newFileFlag = JOptionPane.showConfirmDialog(this, "File exists. Do you want to replace it?", this.getTitle(),
3407                    JOptionPane.YES_NO_OPTION);
3408            if (newFileFlag == JOptionPane.NO_OPTION) {
3409                return;
3410            }
3411        }
3412
3413        FileOutputStream outputFile = new FileOutputStream(choosedFile);
3414        DataOutputStream out = new DataOutputStream(outputFile);
3415
3416        if (dataset instanceof ScalarDS) {
3417            ((ScalarDS) dataset).convertToUnsignedC();
3418            Object data = dataset.getData();
3419            String cname = data.getClass().getName();
3420            char dname = cname.charAt(cname.lastIndexOf("[") + 1);
3421            ByteBuffer bb = null;
3422
3423            int size = Array.getLength(data);
3424
3425            if (dname == 'B') {
3426                byte[] bdata = new byte[size];
3427                bdata = (byte[]) data;
3428
3429                bb = ByteBuffer.allocate(BYTE_BUFFER_SIZE);
3430                if (binaryOrder == 1)
3431                    bb.order(ByteOrder.nativeOrder());
3432                else if (binaryOrder == 2)
3433                    bb.order(ByteOrder.LITTLE_ENDIAN);
3434                else if (binaryOrder == 3) bb.order(ByteOrder.BIG_ENDIAN);
3435
3436                int remainingSize = size - BYTE_BUFFER_SIZE;
3437                int allocValue = 0;
3438                int iterationNumber = 0;
3439                do {
3440                    if (remainingSize <= 0) {
3441                        allocValue = remainingSize + BYTE_BUFFER_SIZE;
3442                    }
3443                    else {
3444                        allocValue = BYTE_BUFFER_SIZE;
3445                    }
3446                    bb.clear();
3447                    bb.put(bdata, (iterationNumber * BYTE_BUFFER_SIZE), allocValue);
3448                    out.write(bb.array(), 0, allocValue);
3449                    remainingSize = remainingSize - BYTE_BUFFER_SIZE;
3450                    iterationNumber++;
3451                } while (remainingSize > -BYTE_BUFFER_SIZE);
3452
3453                out.flush();
3454                out.close();
3455            }
3456            else if (dname == 'S') {
3457                short[] sdata = new short[size];
3458                sdata = (short[]) data;
3459                bb = ByteBuffer.allocate(SHORT_BUFFER_SIZE * 2);
3460                if (binaryOrder == 1)
3461                    bb.order(ByteOrder.nativeOrder());
3462                else if (binaryOrder == 2)
3463                    bb.order(ByteOrder.LITTLE_ENDIAN);
3464                else if (binaryOrder == 3) bb.order(ByteOrder.BIG_ENDIAN);
3465
3466                ShortBuffer sb = bb.asShortBuffer();
3467                int remainingSize = size - SHORT_BUFFER_SIZE;
3468                int allocValue = 0;
3469                int iterationNumber = 0;
3470                do {
3471                    if (remainingSize <= 0) {
3472                        allocValue = remainingSize + SHORT_BUFFER_SIZE;
3473                    }
3474                    else {
3475                        allocValue = SHORT_BUFFER_SIZE;
3476                    }
3477                    bb.clear();
3478                    sb.clear();
3479                    sb.put(sdata, (iterationNumber * SHORT_BUFFER_SIZE), allocValue);
3480                    out.write(bb.array(), 0, allocValue * 2);
3481                    remainingSize = remainingSize - SHORT_BUFFER_SIZE;
3482                    iterationNumber++;
3483                } while (remainingSize > -SHORT_BUFFER_SIZE);
3484
3485                out.flush();
3486                out.close();
3487            }
3488            else if (dname == 'I') {
3489                int[] idata = new int[size];
3490                idata = (int[]) data;
3491                bb = ByteBuffer.allocate(INT_BUFFER_SIZE * 4);
3492                if (binaryOrder == 1)
3493                    bb.order(ByteOrder.nativeOrder());
3494                else if (binaryOrder == 2)
3495                    bb.order(ByteOrder.LITTLE_ENDIAN);
3496                else if (binaryOrder == 3) bb.order(ByteOrder.BIG_ENDIAN);
3497
3498                IntBuffer ib = bb.asIntBuffer();
3499                int remainingSize = size - INT_BUFFER_SIZE;
3500                int allocValue = 0;
3501                int iterationNumber = 0;
3502                do {
3503                    if (remainingSize <= 0) {
3504                        allocValue = remainingSize + INT_BUFFER_SIZE;
3505                    }
3506                    else {
3507                        allocValue = INT_BUFFER_SIZE;
3508                    }
3509                    bb.clear();
3510                    ib.clear();
3511                    ib.put(idata, (iterationNumber * INT_BUFFER_SIZE), allocValue);
3512                    out.write(bb.array(), 0, allocValue * 4);
3513                    remainingSize = remainingSize - INT_BUFFER_SIZE;
3514                    iterationNumber++;
3515                } while (remainingSize > -INT_BUFFER_SIZE);
3516
3517                out.flush();
3518                out.close();
3519            }
3520            else if (dname == 'J') {
3521                long[] ldata = new long[size];
3522                ldata = (long[]) data;
3523
3524                bb = ByteBuffer.allocate(LONG_BUFFER_SIZE * 8);
3525                if (binaryOrder == 1)
3526                    bb.order(ByteOrder.nativeOrder());
3527                else if (binaryOrder == 2)
3528                    bb.order(ByteOrder.LITTLE_ENDIAN);
3529                else if (binaryOrder == 3) bb.order(ByteOrder.BIG_ENDIAN);
3530
3531                LongBuffer lb = bb.asLongBuffer();
3532                int remainingSize = size - LONG_BUFFER_SIZE;
3533                int allocValue = 0;
3534                int iterationNumber = 0;
3535                do {
3536                    if (remainingSize <= 0) {
3537                        allocValue = remainingSize + LONG_BUFFER_SIZE;
3538                    }
3539                    else {
3540                        allocValue = LONG_BUFFER_SIZE;
3541                    }
3542                    bb.clear();
3543                    lb.clear();
3544                    lb.put(ldata, (iterationNumber * LONG_BUFFER_SIZE), allocValue);
3545                    out.write(bb.array(), 0, allocValue * 8);
3546                    remainingSize = remainingSize - LONG_BUFFER_SIZE;
3547                    iterationNumber++;
3548                } while (remainingSize > -LONG_BUFFER_SIZE);
3549
3550                out.flush();
3551                out.close();
3552            }
3553            else if (dname == 'F') {
3554                float[] fdata = new float[size];
3555                fdata = (float[]) data;
3556
3557                bb = ByteBuffer.allocate(FLOAT_BUFFER_SIZE * 4);
3558                if (binaryOrder == 1)
3559                    bb.order(ByteOrder.nativeOrder());
3560                else if (binaryOrder == 2)
3561                    bb.order(ByteOrder.LITTLE_ENDIAN);
3562                else if (binaryOrder == 3) bb.order(ByteOrder.BIG_ENDIAN);
3563
3564                FloatBuffer fb = bb.asFloatBuffer();
3565                int remainingSize = size - FLOAT_BUFFER_SIZE;
3566                int allocValue = 0;
3567                int iterationNumber = 0;
3568                do {
3569                    if (remainingSize <= 0) {
3570                        allocValue = remainingSize + FLOAT_BUFFER_SIZE;
3571                    }
3572                    else {
3573                        allocValue = FLOAT_BUFFER_SIZE;
3574                    }
3575                    bb.clear();
3576                    fb.clear();
3577                    fb.put(fdata, (iterationNumber * FLOAT_BUFFER_SIZE), allocValue);
3578                    out.write(bb.array(), 0, allocValue * 4);
3579                    remainingSize = remainingSize - FLOAT_BUFFER_SIZE;
3580                    iterationNumber++;
3581                } while (remainingSize > -FLOAT_BUFFER_SIZE);
3582
3583                out.flush();
3584                out.close();
3585            }
3586            else if (dname == 'D') {
3587                double[] ddata = new double[size];
3588                ddata = (double[]) data;
3589
3590                bb = ByteBuffer.allocate(DOUBLE_BUFFER_SIZE * 8);
3591                if (binaryOrder == 1)
3592                    bb.order(ByteOrder.nativeOrder());
3593                else if (binaryOrder == 2)
3594                    bb.order(ByteOrder.LITTLE_ENDIAN);
3595                else if (binaryOrder == 3) bb.order(ByteOrder.BIG_ENDIAN);
3596
3597                DoubleBuffer db = bb.asDoubleBuffer();
3598                int remainingSize = size - DOUBLE_BUFFER_SIZE;
3599                int allocValue = 0;
3600                int iterationNumber = 0;
3601                do {
3602                    if (remainingSize <= 0) {
3603                        allocValue = remainingSize + DOUBLE_BUFFER_SIZE;
3604                    }
3605                    else {
3606                        allocValue = DOUBLE_BUFFER_SIZE;
3607                    }
3608                    bb.clear();
3609                    db.clear();
3610                    db.put(ddata, (iterationNumber * DOUBLE_BUFFER_SIZE), allocValue);
3611                    out.write(bb.array(), 0, allocValue * 8);
3612                    remainingSize = remainingSize - DOUBLE_BUFFER_SIZE;
3613                    iterationNumber++;
3614                } while (remainingSize > -DOUBLE_BUFFER_SIZE);
3615
3616                out.flush();
3617                out.close();
3618            }
3619        }
3620
3621        viewer.showStatus("Data save to: " + fname);
3622    }
3623
3624    /**
3625     * update dataset value in file. The change will go to file.
3626     */
3627    @Override
3628    public void updateValueInFile ( ) {
3629        log.trace("DefaultTableView updateValueInFile enter");
3630        if (isReadOnly || showAsBin || showAsHex) {
3631            return;
3632        }
3633
3634        if (!isValueChanged) {
3635            return;
3636        }
3637
3638        try {
3639            log.trace("DefaultTableView updateValueInFile write");
3640            dataset.write();
3641        }
3642        catch (Exception ex) {
3643            toolkit.beep();
3644            JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
3645            return;
3646        }
3647
3648        isValueChanged = false;
3649        log.trace("DefaultTableView updateValueInFile exit");
3650    }
3651
3652    /**
3653     * Selects all rows, columns, and cells in the table.
3654     */
3655    private void selectAll ( ) throws Exception {
3656        table.selectAll();
3657    }
3658
3659    /**
3660     * Converting selected data based on predefined math functions.
3661     */
3662    private void mathConversion ( ) throws Exception {
3663        if (isReadOnly) {
3664            return;
3665        }
3666
3667        int cols = table.getSelectedColumnCount();
3668        // if (!(dataset instanceof ScalarDS)) return;
3669        if ((dataset instanceof CompoundDS) && (cols > 1)) {
3670            toolkit.beep();
3671            JOptionPane.showMessageDialog(this, "Please select one colunm a time for math conversion for compound dataset.",
3672                    getTitle(), JOptionPane.ERROR_MESSAGE);
3673            return;
3674        }
3675
3676        Object theData = getSelectedData();
3677        if (theData == null) {
3678            toolkit.beep();
3679            JOptionPane.showMessageDialog(this, "No data is selected.", getTitle(), JOptionPane.ERROR_MESSAGE);
3680            return;
3681        }
3682
3683        MathConversionDialog dialog = new MathConversionDialog((JFrame) viewer, theData);
3684        dialog.setVisible(true);
3685
3686        if (dialog.isConverted()) {
3687            if (dataset instanceof CompoundDS) {
3688                Object colData = null;
3689                try {
3690                    colData = ((List<?>) dataset.getData()).get(table.getSelectedColumn());
3691                }
3692                catch (Exception ex) {
3693                    log.debug("colData:", ex);
3694                }
3695
3696                if (colData != null) {
3697                    int size = Array.getLength(theData);
3698                    System.arraycopy(theData, 0, colData, 0, size);
3699                }
3700            }
3701            else {
3702                int rows = table.getSelectedRowCount();
3703                int r0 = table.getSelectedRow();
3704                int c0 = table.getSelectedColumn();
3705                int w = table.getColumnCount();
3706                int idx_src = 0;
3707                int idx_dst = 0;
3708                for (int i = 0; i < rows; i++) {
3709                    idx_dst = (r0 + i) * w + c0;
3710                    System.arraycopy(theData, idx_src, dataValue, idx_dst, cols);
3711                    idx_src += cols;
3712                }
3713            }
3714
3715            theData = null;
3716            System.gc();
3717            table.updateUI();
3718            isValueChanged = true;
3719        }
3720
3721    }
3722
3723    /**
3724     * update cell value in memory. It does not change the dataset value in file.
3725     *
3726     * @param cellValue
3727     *            the string value of input.
3728     * @param row
3729     *            the row of the editing cell.
3730     * @param col
3731     *            the column of the editing cell.
3732     */
3733    private void updateValueInMemory (String cellValue, int row, int col) throws Exception {
3734        log.trace("DefaultTableView updateValueInMemory");
3735        if (currentEditingCellValue != null) {
3736            // data values are the same, no need to change the data
3737            if (currentEditingCellValue.toString().equals(cellValue)) return;
3738        }
3739
3740        if (dataset instanceof ScalarDS) {
3741            updateScalarData(cellValue, row, col);
3742        }
3743        else if (dataset instanceof CompoundDS) {
3744            updateCompoundData(cellValue, row, col);
3745        }
3746    }
3747
3748    /**
3749     * update cell value in memory. It does not change the dataset value in file.
3750     *
3751     * @param cellValue
3752     *            the string value of input.
3753     * @param row
3754     *            the row of the editing cell.
3755     * @param col
3756     *            the column of the editing cell.
3757     */
3758    private void updateScalarData (String cellValue, int row, int col) throws Exception {
3759        if (!(dataset instanceof ScalarDS) || (cellValue == null) || ((cellValue = cellValue.trim()) == null) || showAsBin
3760                || showAsHex) {
3761            return;
3762        }
3763
3764        int i = 0;
3765        if (isDataTransposed) {
3766            i = col * table.getRowCount() + row;
3767        }
3768        else {
3769            i = row * table.getColumnCount() + col;
3770        }
3771        log.trace("DefaultTableView updateScalarData {} NT={}", cellValue, NT);
3772
3773        ScalarDS sds = (ScalarDS) dataset;
3774        boolean isUnsigned = sds.isUnsigned();
3775        String cname = dataset.getOriginalClass().getName();
3776        char dname = cname.charAt(cname.lastIndexOf("[") + 1);
3777        log.trace("updateScalarData isUnsigned={} cname={} dname={}", isUnsigned, cname, dname);
3778
3779        // check data range for unsigned datatype converted sizes!
3780        if (isUnsigned) {
3781            long lvalue = -1;
3782            long maxValue = Long.MAX_VALUE;
3783            if (dname == 'B') {
3784                maxValue = 255;
3785                lvalue = Long.parseLong(cellValue);
3786
3787                if (lvalue < 0) {
3788                    throw new NumberFormatException("Negative value for unsigned integer: " + lvalue);
3789                }
3790
3791                if (lvalue > maxValue) {
3792                    throw new NumberFormatException("Data value is out of range: " + lvalue);
3793                }
3794            }
3795            else if (dname == 'S') {
3796                maxValue = 65535;
3797                lvalue = Long.parseLong(cellValue);
3798
3799                if (lvalue < 0) {
3800                    throw new NumberFormatException("Negative value for unsigned integer: " + lvalue);
3801                }
3802
3803                if (lvalue > maxValue) {
3804                    throw new NumberFormatException("Data value is out of range: " + lvalue);
3805                }
3806            }
3807            else if (dname == 'I') {
3808                maxValue = 4294967295L;
3809                lvalue = Long.parseLong(cellValue);
3810
3811                if (lvalue < 0) {
3812                    throw new NumberFormatException("Negative value for unsigned integer: " + lvalue);
3813                }
3814
3815                if (lvalue > maxValue) {
3816                    throw new NumberFormatException("Data value is out of range: " + lvalue);
3817                }
3818            }
3819            else if (dname == 'J') {
3820                BigInteger Jmax = new BigInteger("18446744073709551615");
3821                BigInteger big = new BigInteger(cellValue);
3822                if (big.compareTo(Jmax) > 0) {
3823                    throw new NumberFormatException("Negative value for unsigned integer: " + cellValue);
3824                }
3825                if (big.compareTo(BigInteger.ZERO) < 0) {
3826                    throw new NumberFormatException("Data value is out of range: " + cellValue);
3827                }
3828            }
3829        }
3830
3831        switch (NT) {
3832            case 'B':
3833                byte bvalue = 0;
3834                bvalue = Byte.parseByte(cellValue);
3835                Array.setByte(dataValue, i, bvalue);
3836                break;
3837            case 'S':
3838                short svalue = 0;
3839                svalue = Short.parseShort(cellValue);
3840                Array.setShort(dataValue, i, svalue);
3841                break;
3842            case 'I':
3843                int ivalue = 0;
3844                ivalue = Integer.parseInt(cellValue);
3845                Array.setInt(dataValue, i, ivalue);
3846                break;
3847            case 'J':
3848                long lvalue = 0;
3849                if (dname == 'J') {
3850                    BigInteger big = new BigInteger(cellValue);
3851                    lvalue = big.longValue();
3852                }
3853                else
3854                    lvalue = Long.parseLong(cellValue);
3855                Array.setLong(dataValue, i, lvalue);
3856                break;
3857            case 'F':
3858                float fvalue = 0;
3859                fvalue = Float.parseFloat(cellValue);
3860                Array.setFloat(dataValue, i, fvalue);
3861                break;
3862            case 'D':
3863                double dvalue = 0;
3864                dvalue = Double.parseDouble(cellValue);
3865                Array.setDouble(dataValue, i, dvalue);
3866                break;
3867            default:
3868                Array.set(dataValue, i, cellValue);
3869                break;
3870        }
3871
3872        isValueChanged = true;
3873    }
3874
3875    private void updateCompoundData (String cellValue, int row, int col) throws Exception {
3876        if (!(dataset instanceof CompoundDS) || (cellValue == null) || ((cellValue = cellValue.trim()) == null)) {
3877            return;
3878        }
3879        log.trace("DefaultTableView updateCompoundData");
3880
3881        CompoundDS compDS = (CompoundDS) dataset;
3882        List<?> cdata = (List<?>) compDS.getData();
3883        int orders[] = compDS.getSelectedMemberOrders();
3884        Datatype types[] = compDS.getSelectedMemberTypes();
3885        int nFields = cdata.size();
3886        int nSubColumns = table.getColumnCount() / nFields;
3887        table.getRowCount();
3888        int column = col;
3889        int offset = 0;
3890        int morder = 1;
3891
3892        if (nSubColumns > 1) { // multi-dimension compound dataset
3893            int colIdx = col / nFields;
3894            column = col - colIdx * nFields;
3895            // //BUG 573: offset = row * orders[column] + colIdx * nRows *
3896            // orders[column];
3897            offset = row * orders[column] * nSubColumns + colIdx * orders[column];
3898        }
3899        else {
3900            offset = row * orders[column];
3901        }
3902        morder = orders[column];
3903
3904        Object mdata = cdata.get(column);
3905
3906        // strings
3907        if (Array.get(mdata, 0) instanceof String) {
3908            Array.set(mdata, offset, cellValue);
3909            isValueChanged = true;
3910            return;
3911        }
3912        else if (types[column].getDatatypeClass() == Datatype.CLASS_STRING) {
3913            // it is string but not converted, still byte array
3914            int strlen = types[column].getDatatypeSize();
3915            offset *= strlen;
3916            byte[] bytes = cellValue.getBytes();
3917            byte[] bData = (byte[]) mdata;
3918            int n = Math.min(strlen, bytes.length);
3919            System.arraycopy(bytes, 0, bData, offset, n);
3920            offset += n;
3921            n = strlen - bytes.length;
3922            // space padding
3923            for (int i = 0; i < n; i++) {
3924                bData[offset + i] = ' ';
3925            }
3926            isValueChanged = true;
3927            return;
3928        }
3929
3930        // Numeric data
3931        char mNT = ' ';
3932        String cName = mdata.getClass().getName();
3933        int cIndex = cName.lastIndexOf("[");
3934        if (cIndex >= 0) {
3935            mNT = cName.charAt(cIndex + 1);
3936        }
3937
3938        StringTokenizer st = new StringTokenizer(cellValue, ",");
3939        if (st.countTokens() < morder) {
3940            toolkit.beep();
3941            JOptionPane.showMessageDialog(this, "Number of data point < " + morder + ".", getTitle(), JOptionPane.ERROR_MESSAGE);
3942            return;
3943        }
3944
3945        String token = "";
3946        isValueChanged = true;
3947        switch (mNT) {
3948            case 'B':
3949                byte bvalue = 0;
3950                for (int i = 0; i < morder; i++) {
3951                    token = st.nextToken().trim();
3952                    bvalue = Byte.parseByte(token);
3953                    Array.setByte(mdata, offset + i, bvalue);
3954                }
3955                break;
3956            case 'S':
3957                short svalue = 0;
3958                for (int i = 0; i < morder; i++) {
3959                    token = st.nextToken().trim();
3960                    svalue = Short.parseShort(token);
3961                    Array.setShort(mdata, offset + i, svalue);
3962                }
3963                break;
3964            case 'I':
3965                int ivalue = 0;
3966                for (int i = 0; i < morder; i++) {
3967                    token = st.nextToken().trim();
3968                    ivalue = Integer.parseInt(token);
3969                    Array.setInt(mdata, offset + i, ivalue);
3970                }
3971                break;
3972            case 'J':
3973                long lvalue = 0;
3974                for (int i = 0; i < morder; i++) {
3975                    token = st.nextToken().trim();
3976                    BigInteger big = new BigInteger(token);
3977                    lvalue = big.longValue();
3978                    // lvalue = Long.parseLong(token);
3979                    Array.setLong(mdata, offset + i, lvalue);
3980                }
3981                break;
3982            case 'F':
3983                float fvalue = 0;
3984                for (int i = 0; i < morder; i++) {
3985                    token = st.nextToken().trim();
3986                    fvalue = Float.parseFloat(token);
3987                    Array.setFloat(mdata, offset + i, fvalue);
3988                }
3989                break;
3990            case 'D':
3991                double dvalue = 0;
3992                for (int i = 0; i < morder; i++) {
3993                    token = st.nextToken().trim();
3994                    dvalue = Double.parseDouble(token);
3995                    Array.setDouble(mdata, offset + i, dvalue);
3996                }
3997                break;
3998            default:
3999                isValueChanged = false;
4000        }
4001    }
4002
4003    private class LineplotOption extends JDialog implements ActionListener, ItemListener {
4004        private static final long serialVersionUID = -3457035832213978906L;
4005        public static final int   NO_PLOT          = -1;
4006        public static final int   ROW_PLOT         = 0;
4007        public static final int   COLUMN_PLOT      = 1;
4008
4009        private int               idx_xaxis        = -1, plotType = -1;
4010        private JRadioButton      rowButton, colButton;
4011        @SuppressWarnings("rawtypes")
4012        private JComboBox         rowBox, colBox;
4013
4014        @SuppressWarnings({ "rawtypes", "unchecked" })
4015        public LineplotOption(JFrame owner, String title, int nrow, int ncol) {
4016            super(owner, title, true);
4017
4018            rowBox = new JComboBox();
4019            rowBox.setEditable(false);
4020            colBox = new JComboBox();
4021            colBox.setEditable(false);
4022
4023            JPanel contentPane = (JPanel) this.getContentPane();
4024            contentPane.setPreferredSize(new Dimension(400, 150));
4025            contentPane.setLayout(new BorderLayout(10, 10));
4026
4027            long[] startArray = dataset.getStartDims();
4028            long[] strideArray = dataset.getStride();
4029            int[] selectedIndex = dataset.getSelectedIndex();
4030            int start = (int) startArray[selectedIndex[0]];
4031            int stride = (int) strideArray[selectedIndex[0]];
4032
4033            rowBox.addItem("array index");
4034            for (int i = 0; i < nrow; i++) {
4035                rowBox.addItem("row " + (start + indexBase + i * stride));
4036            }
4037
4038            colBox.addItem("array index");
4039            for (int i = 0; i < ncol; i++) {
4040                colBox.addItem("column " + table.getColumnName(i));
4041            }
4042
4043            rowButton = new JRadioButton("Row");
4044            colButton = new JRadioButton("Column", true);
4045            rowButton.addItemListener(this);
4046            colButton.addItemListener(this);
4047            ButtonGroup rgroup = new ButtonGroup();
4048            rgroup.add(rowButton);
4049            rgroup.add(colButton);
4050
4051            JPanel p1 = new JPanel();
4052            p1.setLayout(new GridLayout(2, 1, 5, 5));
4053            p1.add(new JLabel(" Series in:", SwingConstants.RIGHT));
4054            p1.add(new JLabel(" For abscissa use:", SwingConstants.RIGHT));
4055
4056            JPanel p2 = new JPanel();
4057            p2.setLayout(new GridLayout(2, 1, 5, 5));
4058            // p2.setBorder(new LineBorder(Color.lightGray));
4059            p2.add(colButton);
4060            p2.add(colBox);
4061
4062            JPanel p3 = new JPanel();
4063            p3.setLayout(new GridLayout(2, 1, 5, 5));
4064            // p3.setBorder(new LineBorder(Color.lightGray));
4065            p3.add(rowButton);
4066            p3.add(rowBox);
4067
4068            JPanel p = new JPanel();
4069            p.setBorder(new LineBorder(Color.lightGray));
4070            p.setLayout(new GridLayout(1, 3, 20, 5));
4071            p.add(p1);
4072            p.add(p2);
4073            p.add(p3);
4074
4075            JPanel bp = new JPanel();
4076
4077            JButton okButton = new JButton("Ok");
4078            okButton.addActionListener(this);
4079            okButton.setActionCommand("Ok");
4080            bp.add(okButton);
4081
4082            JButton cancelButton = new JButton("Cancel");
4083            cancelButton.addActionListener(this);
4084            cancelButton.setActionCommand("Cancel");
4085            bp.add(cancelButton);
4086
4087            contentPane.add(new JLabel(" Select plot options:"), BorderLayout.NORTH);
4088            contentPane.add(p, BorderLayout.CENTER);
4089            contentPane.add(bp, BorderLayout.SOUTH);
4090
4091            colBox.setEnabled(colButton.isSelected());
4092            rowBox.setEnabled(rowButton.isSelected());
4093
4094            Point l = getParent().getLocation();
4095            l.x += 450;
4096            l.y += 200;
4097            setLocation(l);
4098            pack();
4099        }
4100
4101        int getXindex ( ) {
4102            return idx_xaxis;
4103        }
4104
4105        int getPlotBy ( ) {
4106            return plotType;
4107        }
4108
4109        @Override
4110        public void actionPerformed (ActionEvent e) {
4111            e.getSource();
4112            String cmd = e.getActionCommand();
4113
4114            if (cmd.equals("Cancel")) {
4115                plotType = NO_PLOT;
4116                this.dispose(); // terminate the application
4117            }
4118            else if (cmd.equals("Ok")) {
4119                if (colButton.isSelected()) {
4120                    idx_xaxis = colBox.getSelectedIndex() - 1;
4121                    plotType = COLUMN_PLOT;
4122                }
4123                else {
4124                    idx_xaxis = rowBox.getSelectedIndex() - 1;
4125                    plotType = ROW_PLOT;
4126                }
4127
4128                this.dispose(); // terminate the application
4129            }
4130        }
4131
4132        @Override
4133        public void itemStateChanged (ItemEvent e) {
4134            Object source = e.getSource();
4135
4136            if (source.equals(colButton) || source.equals(rowButton)) {
4137                colBox.setEnabled(colButton.isSelected());
4138                rowBox.setEnabled(rowButton.isSelected());
4139            }
4140        }
4141    }
4142
4143    private class ColumnHeader extends JTableHeader {
4144        private static final long serialVersionUID   = -3179653809792147055L;
4145        private int               currentColumnIndex = -1;
4146        private int               lastColumnIndex    = -1;
4147        private JTable            parentTable;
4148
4149        public ColumnHeader(JTable theTable) {
4150            super(theTable.getColumnModel());
4151
4152            parentTable = theTable;
4153            setReorderingAllowed(false);
4154        }
4155
4156        @Override
4157        protected void processMouseMotionEvent (MouseEvent e) {
4158            super.processMouseMotionEvent(e);
4159
4160            if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
4161                // do not do anything, just resize the column
4162                if (getResizingColumn() != null) return;
4163
4164                int colEnd = columnAtPoint(e.getPoint());
4165
4166                if (colEnd < 0) {
4167                    colEnd = 0;
4168                }
4169                if (currentColumnIndex < 0) {
4170                    currentColumnIndex = 0;
4171                }
4172
4173                parentTable.clearSelection();
4174
4175                if (colEnd > currentColumnIndex) {
4176                    parentTable.setColumnSelectionInterval(currentColumnIndex, colEnd);
4177                }
4178                else {
4179                    parentTable.setColumnSelectionInterval(colEnd, currentColumnIndex);
4180                }
4181
4182                parentTable.setRowSelectionInterval(0, parentTable.getRowCount() - 1);
4183            }
4184        }
4185
4186        @Override
4187        protected void processMouseEvent (MouseEvent e) {
4188            super.processMouseEvent(e);
4189
4190            int mouseID = e.getID();
4191
4192            if (mouseID == MouseEvent.MOUSE_CLICKED) {
4193                if (currentColumnIndex < 0) {
4194                    return;
4195                }
4196
4197                if (e.isControlDown()) {
4198                    // select discontinuous columns
4199                    parentTable.addColumnSelectionInterval(currentColumnIndex, currentColumnIndex);
4200                }
4201                else if (e.isShiftDown()) {
4202                    // select continuous columns
4203                    if (lastColumnIndex < 0) {
4204                        parentTable.addColumnSelectionInterval(0, currentColumnIndex);
4205                    }
4206                    else if (lastColumnIndex < currentColumnIndex) {
4207                        parentTable.addColumnSelectionInterval(lastColumnIndex, currentColumnIndex);
4208                    }
4209                    else {
4210                        parentTable.addColumnSelectionInterval(currentColumnIndex, lastColumnIndex);
4211                    }
4212                }
4213                else {
4214                    // clear old selection and set new column selection
4215                    parentTable.clearSelection();
4216                    parentTable.setColumnSelectionInterval(currentColumnIndex, currentColumnIndex);
4217                }
4218
4219                lastColumnIndex = currentColumnIndex;
4220                parentTable.setRowSelectionInterval(0, parentTable.getRowCount() - 1);
4221            }
4222            else if (mouseID == MouseEvent.MOUSE_PRESSED) {
4223                currentColumnIndex = columnAtPoint(e.getPoint());
4224            }
4225        }
4226    } // private class ColumnHeader
4227
4228    /** RowHeader defines the row header component of the Spreadsheet. */
4229    private class RowHeader extends JTable {
4230        private static final long serialVersionUID = -1548007702499873626L;
4231        private int               currentRowIndex  = -1;
4232        private int               lastRowIndex     = -1;
4233        private JTable            parentTable;
4234
4235        public RowHeader(JTable pTable, Dataset dset) {
4236            // Create a JTable with the same number of rows as
4237            // the parent table and one column.
4238            // super( pTable.getRowCount(), 1 );
4239
4240            final long[] startArray = dset.getStartDims();
4241            final long[] strideArray = dset.getStride();
4242            final int[] selectedIndex = dset.getSelectedIndex();
4243            final int start = (int) startArray[selectedIndex[0]];
4244            final int stride = (int) strideArray[selectedIndex[0]];
4245            final int rowCount = pTable.getRowCount();
4246            parentTable = pTable;
4247
4248            AbstractTableModel tm = new AbstractTableModel() {
4249                private static final long serialVersionUID = -8117073107569884677L;
4250
4251                @Override
4252                public int getColumnCount ( ) {
4253                    return 1;
4254                }
4255
4256                @Override
4257                public int getRowCount ( ) {
4258                    return rowCount;
4259                }
4260
4261                @Override
4262                public String getColumnName (int col) {
4263                    return " ";
4264                }
4265
4266                @Override
4267                public Object getValueAt (int row, int column) {
4268                    log.trace("RowHeader:AbstractTableModel:getValueAt");
4269                    return String.valueOf(start + indexBase + row * stride);
4270                }
4271            };
4272
4273            this.setModel(tm);
4274
4275            // Get the only table column.
4276            TableColumn col = getColumnModel().getColumn(0);
4277
4278            // Use the cell renderer in the column.
4279            col.setCellRenderer(new RowHeaderRenderer());
4280        }
4281
4282        /** Overridden to return false since the headers are not editable. */
4283        @Override
4284        public boolean isCellEditable (int row, int col) {
4285            return false;
4286        }
4287
4288        /** This is called when the selection changes in the row headers. */
4289        @Override
4290        public void valueChanged (ListSelectionEvent e) {
4291            if (parentTable == null) {
4292                return;
4293            }
4294
4295            int rows[] = getSelectedRows();
4296            if ((rows == null) || (rows.length == 0)) {
4297                return;
4298            }
4299
4300            parentTable.clearSelection();
4301            parentTable.setRowSelectionInterval(rows[0], rows[rows.length - 1]);
4302            parentTable.setColumnSelectionInterval(0, parentTable.getColumnCount() - 1);
4303        }
4304
4305        @Override
4306        protected void processMouseMotionEvent (MouseEvent e) {
4307            if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
4308                int colEnd = rowAtPoint(e.getPoint());
4309
4310                if (colEnd < 0) {
4311                    colEnd = 0;
4312                }
4313                if (currentRowIndex < 0) {
4314                    currentRowIndex = 0;
4315                }
4316
4317                parentTable.clearSelection();
4318
4319                if (colEnd > currentRowIndex) {
4320                    parentTable.setRowSelectionInterval(currentRowIndex, colEnd);
4321                }
4322                else {
4323                    parentTable.setRowSelectionInterval(colEnd, currentRowIndex);
4324                }
4325
4326                parentTable.setColumnSelectionInterval(0, parentTable.getColumnCount() - 1);
4327            }
4328        }
4329
4330        @Override
4331        protected void processMouseEvent (MouseEvent e) {
4332            int mouseID = e.getID();
4333
4334            if (mouseID == MouseEvent.MOUSE_CLICKED) {
4335                if (currentRowIndex < 0) {
4336                    return;
4337                }
4338
4339                if (e.isControlDown()) {
4340                    // select discontinuous rows
4341                    parentTable.addRowSelectionInterval(currentRowIndex, currentRowIndex);
4342                }
4343                else if (e.isShiftDown()) {
4344                    // select contiguous columns
4345                    if (lastRowIndex < 0) {
4346                        parentTable.addRowSelectionInterval(0, currentRowIndex);
4347                    }
4348                    else if (lastRowIndex < currentRowIndex) {
4349                        parentTable.addRowSelectionInterval(lastRowIndex, currentRowIndex);
4350                    }
4351                    else {
4352                        parentTable.addRowSelectionInterval(currentRowIndex, lastRowIndex);
4353                    }
4354                }
4355                else {
4356                    // clear old selection and set new column selection
4357                    parentTable.clearSelection();
4358                    parentTable.setRowSelectionInterval(currentRowIndex, currentRowIndex);
4359                }
4360
4361                lastRowIndex = currentRowIndex;
4362
4363                parentTable.setColumnSelectionInterval(0, parentTable.getColumnCount() - 1);
4364            }
4365            else if (mouseID == MouseEvent.MOUSE_PRESSED) {
4366                currentRowIndex = rowAtPoint(e.getPoint());
4367            }
4368        }
4369    } // private class RowHeader extends JTable
4370
4371    /**
4372     * RowHeaderRenderer is a custom cell renderer that displays cells as buttons.
4373     */
4374    private class RowHeaderRenderer extends JLabel implements TableCellRenderer {
4375        private static final long serialVersionUID = -8963879626159783226L;
4376
4377        public RowHeaderRenderer( ) {
4378            super();
4379            setHorizontalAlignment(SwingConstants.CENTER);
4380
4381            setOpaque(true);
4382            setBorder(UIManager.getBorder("TableHeader.cellBorder"));
4383            setBackground(Color.lightGray);
4384        }
4385
4386        /** Configures the button for the current cell, and returns it. */
4387        @Override
4388        public Component getTableCellRendererComponent (JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
4389                int column) {
4390            setFont(table.getFont());
4391
4392            if (value != null) {
4393                setText(value.toString());
4394            }
4395
4396            return this;
4397        }
4398    } // private class RowHeaderRenderer extends JLabel implements
4399      // TableCellRenderer
4400
4401    @SuppressWarnings("rawtypes")
4402    private class MultiLineHeaderRenderer extends JList implements TableCellRenderer {
4403        private static final long    serialVersionUID = -3697496960833719169L;
4404        private final CompoundBorder subBorder        = new CompoundBorder(new MatteBorder(1, 0, 1, 0, java.awt.Color.darkGray),
4405                                                              new MatteBorder(1, 0, 1, 0, java.awt.Color.white));
4406        private final CompoundBorder majorBorder      = new CompoundBorder(new MatteBorder(1, 1, 1, 0, java.awt.Color.darkGray),
4407                                                              new MatteBorder(1, 2, 1, 0, java.awt.Color.white));
4408        Vector<String>               lines            = new Vector<String>();
4409        int                          nSubcolumns      = 1;
4410
4411        public MultiLineHeaderRenderer(int majorColumns, int subColumns) {
4412            nSubcolumns = subColumns;
4413            setOpaque(true);
4414            setForeground(UIManager.getColor("TableHeader.foreground"));
4415            setBackground(UIManager.getColor("TableHeader.background"));
4416        }
4417
4418        @Override
4419        public Component getTableCellRendererComponent (JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
4420                int column) {
4421            setFont(table.getFont());
4422            String str = (value == null) ? "" : value.toString();
4423            BufferedReader br = new BufferedReader(new StringReader(str));
4424            String line;
4425
4426            lines.clear();
4427            try {
4428                while ((line = br.readLine()) != null) {
4429                    lines.addElement(line);
4430                }
4431            }
4432            catch (IOException ex) {
4433                log.debug("string read:", ex);
4434            }
4435
4436            if ((column / nSubcolumns) * nSubcolumns == column) {
4437                setBorder(majorBorder);
4438            }
4439            else {
4440                setBorder(subBorder);
4441            }
4442            setListData(lines);
4443
4444            return this;
4445        }
4446    }
4447
4448    // ////////////////////////////////////////////////////////////////////////
4449    // //
4450    // The code below was added to deal with region references //
4451    // Peter Cao, 4/30/2009 //
4452    // //
4453    // ////////////////////////////////////////////////////////////////////////
4454
4455    @Override
4456    public void mouseClicked (MouseEvent e) {
4457        // only deal with reg. ref
4458        if (!(isRegRef || isObjRef)) return;
4459
4460        int eMod = e.getModifiers();
4461
4462        // provide two options here: double click to show data in table, or
4463        // right mouse to choose to show data in table or in image
4464
4465        // right mouse click
4466        if (e.isPopupTrigger()
4467                || (eMod == InputEvent.BUTTON3_MASK)
4468                || (System.getProperty("os.name").startsWith("Mac")
4469                && (eMod == (InputEvent.BUTTON1_MASK
4470                | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())))) {
4471            if (popupMenu != null) {
4472                popupMenu.show((JComponent) e.getSource(), e.getX(), e.getY());
4473            }
4474        }
4475        else if (e.getClickCount() == 2) {
4476            // double click
4477            viewType = ViewType.TABLE;
4478            Object theData = null;
4479            try {
4480                theData = ((Dataset) getDataObject()).getData();
4481            }
4482            catch (Exception ex) {
4483                JOptionPane.showMessageDialog(this, ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE);
4484            }
4485
4486            if (theData == null) {
4487                toolkit.beep();
4488                JOptionPane.showMessageDialog(this, "No data selected.", getTitle(), JOptionPane.ERROR_MESSAGE);
4489                return;
4490
4491            }
4492
4493            int[] selectedRows = table.getSelectedRows();
4494            if (selectedRows == null || selectedRows.length <= 0) {
4495                return;
4496            }
4497            int len = Array.getLength(selectedRows);
4498            for (int i = 0; i < len; i++) {
4499                if (isRegRef)
4500                    showRegRefData((String) Array.get(theData, selectedRows[i]));
4501                else if (isObjRef) showObjRefData(Array.getLong(theData, selectedRows[i]));
4502            }
4503        }
4504    }
4505
4506    @Override
4507    public void mouseEntered (MouseEvent e) {
4508    }
4509
4510    @Override
4511    public void mouseExited (MouseEvent e) {
4512    }
4513
4514    @Override
4515    public void mousePressed (MouseEvent e) {
4516    }
4517
4518    @Override
4519    public void mouseReleased (MouseEvent e) {
4520    }
4521
4522    /** creates a popup menu for a right mouse click on a data object */
4523    private JPopupMenu createPopupMenu ( ) {
4524        JPopupMenu menu = new JPopupMenu();
4525        JMenuItem item;
4526
4527        item = new JMenuItem("Show As Table");
4528        item.setMnemonic(KeyEvent.VK_T);
4529        item.addActionListener(this);
4530        item.setActionCommand("Show data as table");
4531        menu.add(item);
4532
4533        item = new JMenuItem("Show As Image");
4534        item.setMnemonic(KeyEvent.VK_I);
4535        item.addActionListener(this);
4536        item.setActionCommand("Show data as image");
4537        menu.add(item);
4538
4539        // item = new JMenuItem( "Show As Text");
4540        // item.setMnemonic(KeyEvent.VK_I);
4541        // item.addActionListener(this);
4542        // item.setActionCommand("Show data as text");
4543        // menu.add(item);
4544
4545        return menu;
4546    }
4547
4548    /**
4549     * Display data pointed by object references. Data of each object is shown in a separate
4550     * spreadsheet.
4551     *
4552     * @param ref
4553     *            the array of strings that contain the object reference information.
4554     *
4555     */
4556    private void showObjRefData (long ref) {
4557        long[] oid = { ref };
4558        log.trace("DefaultTableView showObjRefData: ref={}", ref);
4559
4560        HObject obj = FileFormat.findObject(dataset.getFileFormat(), oid);
4561        if (obj == null || !(obj instanceof ScalarDS)) return;
4562
4563        ScalarDS dset = (ScalarDS) obj;
4564        ScalarDS dset_copy = null;
4565
4566        // create an instance of the dataset constructor
4567        Constructor<? extends ScalarDS> constructor = null;
4568        Object[] paramObj = null;
4569        Object data = null;
4570
4571        try {
4572            Class[] paramClass = { FileFormat.class, String.class, String.class };
4573            constructor = dset.getClass().getConstructor(paramClass);
4574            paramObj = new Object[] { dset.getFileFormat(), dset.getName(), dset.getPath() };
4575            dset_copy = (ScalarDS) constructor.newInstance(paramObj);
4576            data = dset_copy.getData();
4577        }
4578        catch (Exception ex) {
4579            JOptionPane.showMessageDialog(this, ex, "Object Reference:" + getTitle(), JOptionPane.ERROR_MESSAGE);
4580            data = null;
4581        }
4582
4583        if (data == null) return;
4584
4585        JInternalFrame dataView = null;
4586        HashMap map = new HashMap(1);
4587        map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, dset_copy);
4588        switch (viewType) {
4589            case TEXT:
4590                dataView = new DefaultTextView(viewer, map);
4591                break;
4592            case IMAGE:
4593                dataView = new DefaultImageView(viewer, map);
4594                break;
4595            default:
4596                dataView = new DefaultTableView(viewer, map);
4597                break;
4598        }
4599
4600        if (dataView != null) {
4601            viewer.addDataView((DataView) dataView);
4602        }
4603    }
4604
4605    /**
4606     * Display data pointed by region references. Data of each region is shown in a separate
4607     * spreadsheet. The reg. ref. information is stored in strings of the format below:
4608     * <p />
4609     * <ul>
4610     * <li>For point selections: "file_id:obj_id { <point1> <point2> ...) }", where <point1> is in
4611     * the form of (location_of_dim0, location_of_dim1, ...). For example, 0:800 { (0,1) (2,11)
4612     * (1,0) (2,4) }</li>
4613     * <li>For rectangle selections:
4614     * "file_id:obj_id { <corner coordinates1> <corner coordinates2> ... }", where <corner
4615     * coordinates1> is in the form of (start_corner)-(oposite_corner). For example, 0:800 {
4616     * (0,0)-(0,2) (0,11)-(0,13) (2,0)-(2,2) (2,11)-(2,13) }</li>
4617     * </ul>
4618     *
4619     * @param reg
4620     *            the array of strings that contain the reg. ref information.
4621     *
4622     */
4623    @SuppressWarnings({ "rawtypes", "unchecked" })
4624    private void showRegRefData (String reg) {
4625        boolean isPointSelection = false;
4626
4627        if (reg == null || (reg.length() <= 0) || (reg.compareTo("NULL") == 0)) return;
4628        log.trace("DefaultTableView showRegRefData: reg={}", reg);
4629
4630        isPointSelection = (reg.indexOf('-') <= 0);
4631
4632        // find the object location
4633        String oidStr = reg.substring(reg.indexOf('/'), reg.indexOf(' '));
4634        log.trace("DefaultTableView showRegRefData: isPointSelection={} oidStr={}", isPointSelection, oidStr);
4635
4636        // decode the region selection
4637        String regStr = reg.substring(reg.indexOf('{') + 1, reg.indexOf('}'));
4638        if (regStr == null || regStr.length() <= 0) return; // no selection
4639
4640        reg.substring(reg.indexOf('}') + 1);
4641
4642        StringTokenizer st = new StringTokenizer(regStr);
4643        int nSelections = st.countTokens();
4644        if (nSelections <= 0) return; // no selection
4645        log.trace("DefaultTableView showRegRefData: nSelections={}", nSelections);
4646
4647        HObject obj = FileFormat.findObject(dataset.getFileFormat(), oidStr);
4648        if (obj == null || !(obj instanceof ScalarDS)) return;
4649
4650        ScalarDS dset = (ScalarDS) obj;
4651        ScalarDS dset_copy = null;
4652
4653        // create an instance of the dataset constructor
4654        Constructor<? extends ScalarDS> constructor = null;
4655        Object[] paramObj = null;
4656        try {
4657            @SuppressWarnings("rawtypes")
4658            Class[] paramClass = { FileFormat.class, String.class, String.class };
4659            constructor = dset.getClass().getConstructor(paramClass);
4660            paramObj = new Object[] { dset.getFileFormat(), dset.getName(), dset.getPath() };
4661        }
4662        catch (Exception ex) {
4663            constructor = null;
4664        }
4665
4666        // load each selection into a separate dataset and display it in
4667        // a separate spreadsheet
4668        StringBuffer titleSB = new StringBuffer();
4669        log.trace("DefaultTableView showRegRefData: titleSB created");
4670
4671        while (st.hasMoreTokens()) {
4672            log.trace("DefaultTableView showRegRefData: st.hasMoreTokens() begin");
4673            try {
4674                dset_copy = (ScalarDS) constructor.newInstance(paramObj);
4675            }
4676            catch (Exception ex) {
4677                continue;
4678            }
4679
4680            if (dset_copy == null) continue;
4681
4682            try {
4683                dset_copy.init();
4684            }
4685            catch (Exception ex) {
4686                continue;
4687            }
4688
4689            dset_copy.getRank();
4690            long start[] = dset_copy.getStartDims();
4691            long count[] = dset_copy.getSelectedDims();
4692
4693            // set the selected dimension sizes based on the region selection
4694            // info.
4695            int idx = 0;
4696            String sizeStr = null;
4697            String token = st.nextToken();
4698
4699            titleSB.setLength(0);
4700            titleSB.append(token);
4701            titleSB.append(" at ");
4702            log.trace("DefaultTableView showRegRefData: titleSB={}", titleSB);
4703
4704            token = token.replace('(', ' ');
4705            token = token.replace(')', ' ');
4706            if (isPointSelection) {
4707                // point selection
4708                StringTokenizer tmp = new StringTokenizer(token, ",");
4709                while (tmp.hasMoreTokens()) {
4710                    count[idx] = 1;
4711                    sizeStr = tmp.nextToken().trim();
4712                    start[idx] = Long.valueOf(sizeStr);
4713                    idx++;
4714                }
4715            }
4716            else {
4717                // rectangle selection
4718                String startStr = token.substring(0, token.indexOf('-'));
4719                String endStr = token.substring(token.indexOf('-') + 1);
4720                StringTokenizer tmp = new StringTokenizer(startStr, ",");
4721                while (tmp.hasMoreTokens()) {
4722                    sizeStr = tmp.nextToken().trim();
4723                    start[idx] = Long.valueOf(sizeStr);
4724                    idx++;
4725                }
4726
4727                idx = 0;
4728                tmp = new StringTokenizer(endStr, ",");
4729                while (tmp.hasMoreTokens()) {
4730                    sizeStr = tmp.nextToken().trim();
4731                    count[idx] = Long.valueOf(sizeStr) - start[idx] + 1;
4732                    idx++;
4733                }
4734            }
4735            log.trace("DefaultTableView showRegRefData: selection inited");
4736
4737            try {
4738                dset_copy.getData();
4739            }
4740            catch (Exception ex) {
4741                JOptionPane.showMessageDialog(this, ex, "Region Reference:" + getTitle(), JOptionPane.ERROR_MESSAGE);
4742            }
4743
4744            JInternalFrame dataView = null;
4745            HashMap map = new HashMap(1);
4746            map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, dset_copy);
4747            switch (viewType) {
4748                case TEXT:
4749                    dataView = new DefaultTextView(viewer, map);
4750                    break;
4751                case IMAGE:
4752                    dataView = new DefaultImageView(viewer, map);
4753                    break;
4754                default:
4755                    dataView = new DefaultTableView(viewer, map);
4756                    break;
4757            }
4758
4759            if (dataView != null) {
4760                viewer.addDataView((DataView) dataView);
4761                dataView.setTitle(dataView.getTitle() + "; " + titleSB.toString());
4762            }
4763            log.trace("DefaultTableView showRegRefData: st.hasMoreTokens() end");
4764        } // while (st.hasMoreTokens())
4765    } // private void showRegRefData(String reg)
4766}