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